Skip to content

Commit 7786b0a

Browse files
committed
Update to latest version of HF Transformers (Fixes Sumandora#4)
I hope this didn't break backwards compatibility in ways beyond what I can test. Anyways, lots of new stuff in HF Transformers, which make this quite a lot harder than it was before. I'm not sure if I can continue supporting this, if it this goes on. Perhaps they should think of a canonical way of doing this...
1 parent adba4d7 commit 7786b0a

3 files changed

Lines changed: 70 additions & 36 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.pt

compute_refusal_dir.py

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
1-
import jaxtyping
2-
31
import random
42

53
import torch
6-
from transformers import AutoTokenizer, AutoModelForCausalLM, TextStreamer, BitsAndBytesConfig
7-
8-
import einops
4+
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
95

106
from tqdm import tqdm
117

128
torch.inference_mode()
139

14-
MODEL_ID = "stabilityai/stablelm-2-zephyr-1_6b"
15-
#MODEL_ID = "Qwen/Qwen1.5-1.8B-Chat"
16-
#MODEL_ID = "Qwen/Qwen-1_8B-chat"
17-
#MODEL_ID = "google/gemma-1.1-2b-it"
18-
#MODEL_ID = "google/gemma-1.1-7b-it"
19-
#MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct"
20-
21-
model = AutoModelForCausalLM.from_pretrained(MODEL_ID, trust_remote_code=True, torch_dtype=torch.float16, quantization_config=BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16))
10+
MODEL_ID = "tiiuae/Falcon3-1B-Instruct"
11+
# MODEL_ID = "Qwen/Qwen3-1.7B"
12+
# MODEL_ID = "stabilityai/stablelm-2-zephyr-1_6b"
13+
# MODEL_ID = "Qwen/Qwen1.5-1.8B-Chat"
14+
# MODEL_ID = "Qwen/Qwen-1_8B-chat"
15+
# MODEL_ID = "google/gemma-1.1-2b-it"
16+
# MODEL_ID = "google/gemma-1.1-7b-it"
17+
# MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct"
18+
19+
model = AutoModelForCausalLM.from_pretrained(MODEL_ID,
20+
trust_remote_code=True,
21+
dtype=torch.float16,
22+
device_map="cuda",
23+
quantization_config=BitsAndBytesConfig(load_in_4bit=True,
24+
bnb_4bit_compute_dtype=torch.float16))
2225
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
2326

2427
# settings:
@@ -39,18 +42,26 @@
3942
harmless_instructions = random.sample(harmless, instructions)
4043

4144
harmful_toks = [
42-
tokenizer.apply_chat_template(conversation=[{"role": "user", "content": insn}], add_generation_prompt=True,
45+
tokenizer.apply_chat_template(conversation=[{"role": "user", "content": insn}],
46+
add_generation_prompt=True,
4347
return_tensors="pt") for insn in harmful_instructions]
4448
harmless_toks = [
45-
tokenizer.apply_chat_template(conversation=[{"role": "user", "content": insn}], add_generation_prompt=True,
49+
tokenizer.apply_chat_template(conversation=[{"role": "user", "content": insn}],
50+
add_generation_prompt=True,
4651
return_tensors="pt") for insn in harmless_instructions]
4752

4853
max_its = instructions*2
4954
bar = tqdm(total=max_its)
5055

56+
5157
def generate(toks):
5258
bar.update(n=1)
53-
return model.generate(toks.to(model.device), use_cache=False, max_new_tokens=1, return_dict_in_generate=True, output_hidden_states=True)
59+
return model.generate(toks.to(model.device),
60+
use_cache=False,
61+
max_new_tokens=1,
62+
return_dict_in_generate=True,
63+
output_hidden_states=True)
64+
5465

5566
harmful_outputs = [generate(toks) for toks in harmful_toks]
5667
harmless_outputs = [generate(toks) for toks in harmless_toks]

inference.py

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,50 @@
1-
from typing import Optional, Tuple
2-
31
import einops
42
import jaxtyping
53
import torch
64
import torch.nn as nn
5+
from typing import Optional, Tuple
76
from transformers import AutoTokenizer, AutoModelForCausalLM, TextStreamer, BitsAndBytesConfig
7+
from inspect import signature
88

99
torch.inference_mode()
1010

11-
torch.set_default_device("cpu")
12-
13-
MODEL_ID = "stabilityai/stablelm-2-zephyr-1_6b"
14-
#MODEL_ID = "Qwen/Qwen1.5-1.8B-Chat"
15-
#MODEL_ID = "Qwen/Qwen-1_8B-chat"
16-
#MODEL_ID = "google/gemma-1.1-2b-it"
17-
#MODEL_ID = "google/gemma-1.1-7b-it"
18-
#MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct"
19-
20-
model = AutoModelForCausalLM.from_pretrained(MODEL_ID, trust_remote_code=True, device_map="cuda", quantization_config=BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16))
11+
MODEL_ID = "tiiuae/Falcon3-1B-Instruct"
12+
# MODEL_ID = "Qwen/Qwen3-1.7B"
13+
# MODEL_ID = "stabilityai/stablelm-2-zephyr-1_6b"
14+
# MODEL_ID = "Qwen/Qwen1.5-1.8B-Chat"
15+
# MODEL_ID = "Qwen/Qwen-1_8B-chat"
16+
# MODEL_ID = "google/gemma-1.1-2b-it"
17+
# MODEL_ID = "google/gemma-1.1-7b-it"
18+
# MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct"
19+
20+
model = AutoModelForCausalLM.from_pretrained(MODEL_ID,
21+
trust_remote_code=True,
22+
dtype=torch.float16,
23+
device_map="cuda",
24+
quantization_config=BitsAndBytesConfig(load_in_4bit=True,
25+
bnb_4bit_compute_dtype=torch.float16))
2126
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
2227

2328
refusal_dir = torch.load(MODEL_ID.replace("/", "_") + "_refusal_dir.pt")
2429

2530

2631
def direction_ablation_hook(activation: jaxtyping.Float[torch.Tensor, "... d_act"],
2732
direction: jaxtyping.Float[torch.Tensor, "d_act"]):
28-
proj = einops.einsum(activation, direction.view(-1, 1), '... d_act, d_act single -> ... single') * direction
33+
proj = einops.einsum(activation, direction.view(-1, 1),
34+
'... d_act, d_act single -> ... single') * direction
2935
return activation - proj
3036

3137

38+
# Some model developers thought it was stupid to pass a tuple of tuple of tuples around (rightfully so), but unfortunately now we have a divide
39+
sig = signature(model.model.layers[0].forward)
40+
simple = sig.return_annotation == torch.Tensor
41+
42+
3243
class AblationDecoderLayer(nn.Module):
44+
def __init__(self):
45+
super().__init__()
46+
self.attention_type = "full_attention"
47+
3348
def forward(
3449
self,
3550
hidden_states: torch.Tensor,
@@ -40,24 +55,32 @@ def forward(
4055
use_cache: Optional[bool] = False,
4156
cache_position: Optional[torch.LongTensor] = None,
4257
**kwargs,
43-
) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
58+
):
4459
assert not output_attentions
4560

46-
ablated = direction_ablation_hook(hidden_states, refusal_dir.to(hidden_states.device)).to(hidden_states.device)
61+
ablated = direction_ablation_hook(hidden_states, refusal_dir.to(
62+
hidden_states.device)).to(hidden_states.device)
63+
64+
if simple:
65+
return ablated
4766

4867
outputs = (ablated,)
4968

5069
if use_cache:
5170
outputs += (past_key_value,)
5271

53-
# noinspection PyTypeChecker
5472
return outputs
5573

5674

57-
for idx in reversed(range(len(model.model.layers))): # for qwen 1 this needs to be changed to model.transformer.h
75+
# for qwen 1 this needs to be changed to model.transformer.h
76+
for idx in reversed(range(len(model.model.layers))):
5877
model.model.layers.insert(idx, AblationDecoderLayer())
5978

60-
conversation=[]
79+
# bruh
80+
if hasattr(model, "config") and hasattr(model.config, "num_hidden_layers"):
81+
model.config.num_hidden_layers *= 2
82+
83+
conversation = []
6184

6285
streamer = TextStreamer(tokenizer)
6386

@@ -66,10 +89,9 @@ def forward(
6689
prompt = input()
6790
conversation.append({"role": "user", "content": prompt})
6891
toks = tokenizer.apply_chat_template(conversation=conversation,
69-
add_generation_prompt=True, return_tensors="pt")
92+
add_generation_prompt=True, return_tensors="pt")
7093

7194
gen = model.generate(toks.to(model.device), streamer=streamer, max_new_tokens=1337)
7295

7396
decoded = tokenizer.batch_decode(gen[0][len(toks[0]):], skip_special_tokens=True)
7497
conversation.append({"role": "assistant", "content": "".join(decoded)})
75-

0 commit comments

Comments
 (0)