Cunt1257 commited on
Commit
6ee9587
·
verified ·
1 Parent(s): 0f39a61

Upload 14 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,9 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ asserts/main-fig.png filter=lfs diff=lfs merge=lfs -text
37
+ asserts/table-1.png filter=lfs diff=lfs merge=lfs -text
38
+ asserts/table-2.png filter=lfs diff=lfs merge=lfs -text
39
+ asserts/table-3.png filter=lfs diff=lfs merge=lfs -text
40
+ asserts/table-4.png filter=lfs diff=lfs merge=lfs -text
41
+ asserts/table-5.png filter=lfs diff=lfs merge=lfs -text
asserts/main-fig.png ADDED

Git LFS Details

  • SHA256: d18549c5e7af06fbdee067441f7cb0f258d821a42a597e0639076b7eb68d6b2e
  • Pointer size: 131 Bytes
  • Size of remote file: 260 kB
asserts/table-1.png ADDED

Git LFS Details

  • SHA256: 87f8df9aa8f68122f81a2fd896c7be9946734ec2837cec5316c3e4dacc47381a
  • Pointer size: 131 Bytes
  • Size of remote file: 735 kB
asserts/table-2.png ADDED

Git LFS Details

  • SHA256: ea15e32f196d2e60b9da0be18d5b80f81d865f269f0976f8c633287dd39424d2
  • Pointer size: 131 Bytes
  • Size of remote file: 389 kB
asserts/table-3.png ADDED

Git LFS Details

  • SHA256: 1d41c92527f6ac8d10972ac71bf3c8875281df581a8bb9684609a4e26848e384
  • Pointer size: 131 Bytes
  • Size of remote file: 887 kB
asserts/table-4.png ADDED

Git LFS Details

  • SHA256: dd6dc9167ed636751fa1d01a205d5a01983bc78d51beda783aeec2fc788bc5bd
  • Pointer size: 131 Bytes
  • Size of remote file: 415 kB
asserts/table-5.png ADDED

Git LFS Details

  • SHA256: a19686f4be52ad3094f093b026e89fbbfe250bf19761dd1e7dd0cf0523a54526
  • Pointer size: 131 Bytes
  • Size of remote file: 435 kB
llama2-7b-w2a16/config.yaml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ model: model_zoo/Llama-2-7b-hf
2
+ wbits: 2
3
+ abits: 16
4
+ epochs: 60
5
+ use_bfloat16: true
6
+ eval_ppl: true
7
+ quant_mode: lora_only # [fp16,slider,lora_only] slider is for W4A4, lora_only is for WXA16.
8
+ batch_size: 3
9
+ low_memory: true
10
+ nsamples: 128 # the num pf calibration data
11
+ calib_dataset: wikitext2
12
+ test_datasets: wikitext2,c4
13
+
14
+ # group layer
15
+ num_layer: 4 # middle sliding window size
16
+ sliding_layer: 2 # middle sliding stride
17
+ fill_window_size: 4 # progressive sliding size
18
+
19
+
20
+ # lora
21
+ lora_rank: 4 # lora rank
22
+ use_lora: true # 默认
23
+
24
+
25
+ # instraSliding
26
+ quant_rate: 0.5
27
+
28
+
29
+ # target generation and loss
30
+ inference_batch_size: 12 # the batchsize in get training data
31
+ fp16_act: false # use fp_act to reduce cpu memory
32
+
33
+
34
+ # optimizer
35
+ scale_lr: 0.00 #learn scaling学习率
36
+ lora_lr: 0.0005 # lora 学习率
37
+ lwc_lr: 0.01 # lwc学习率
38
+ warmup_ratio: 0.0 # warnup占总训练iter的比例,范围:[0.0,1.0]
39
+ wd: 0.0
llama2-7b-w4a4/config.yaml ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ model: model_zoo/Llama-2-7b-hf
2
+ wbits: 4
3
+ abits: 4
4
+ epochs: 20
5
+ use_bfloat16: true
6
+ eval_ppl: true
7
+ quant_mode: slider # [fp16,slider,lora_only] slider is for W4A4, lora_only is for WXA16.
8
+ batch_size: 3
9
+ low_memory: true
10
+ nsamples: 128 # the num pf calibration data
11
+ calib_dataset: wikitext2
12
+ test_datasets: wikitext2,c4
13
+
14
+ load_rotate_model_path: ./rotate_models/llama2-7B-rotate.pth # Load the rotated FP16 model; if the file does not exist, a rotated model will be generated at the specified path. Applies only to weight-activation quantization.
15
+
16
+
17
+ # group layer
18
+ num_layer: 4 # middle sliding window size
19
+ sliding_layer: 2 # middle sliding stride
20
+
21
+
22
+
23
+
24
+
25
+
26
+ # lora
27
+ lora_rank: 4 # lora rank
28
+ use_lora: true # 默认
29
+
30
+
31
+ # instraSliding
32
+ quant_step: 2
33
+ quant_rate: 0.5
34
+
35
+
36
+ # target generation and loss
37
+ inference_batch_size: 12 # the batchsize in get training data
38
+ fp16_act: false # use fp_act to reduce cpu memory
39
+
40
+
41
+ # optimizer
42
+ scale_lr: 0.001 #learn scaling学习率
43
+ lora_lr: 0.0001 # lora 学习率
44
+ lwc_lr: 0.01 # lwc学习率
45
+ warmup_ratio: 0.0 # warnup占总训练iter的比例,范围:[0.0,1.0]
46
+ wd: 0.0
models/LMClass.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import transformers
2
+ import torch
3
+ from .models_utils import BaseLM
4
+ from transformers import AutoTokenizer, AutoConfig, AutoModelForCausalLM
5
+ import torch.nn.functional as F
6
+ import torch
7
+ from tqdm import tqdm
8
+ import pdb
9
+
10
+
11
+ class LMClass(BaseLM):
12
+ def __init__(self, args,model_name=None):
13
+
14
+ super().__init__()
15
+
16
+ self.args = args
17
+ self._device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
18
+ if model_name is not None:
19
+ self.model_name = model_name
20
+ else:
21
+ self.model_name = args.model
22
+ self.batch_size_per_gpu = args.batch_size
23
+
24
+ self.model_config = self.model_name
25
+ config = AutoConfig.from_pretrained(
26
+ self.model_name, attn_implementation=args.attn_implementation,trust_remote_code=True
27
+ )
28
+
29
+ self.tokenizer = AutoTokenizer.from_pretrained(self.model_name, use_fast=False,legacy=False)
30
+ torch_dtype = torch.bfloat16 if args.use_bfloat16 is True else torch.float16
31
+
32
+ self.model = AutoModelForCausalLM.from_pretrained(self.model_name, config=config, device_map='cpu',torch_dtype=torch_dtype, trust_remote_code=True)
33
+
34
+ self.seqlen = self.model.config.max_position_embeddings
35
+ self.model.eval()
36
+ self.vocab_size = self.tokenizer.vocab_size
37
+ print("vocab size: ", self.vocab_size)
38
+
39
+ @property
40
+ def eot_token(self) -> str:
41
+ return self.tokenizer.eos_token
42
+
43
+ @property
44
+ def eot_token_id(self):
45
+ # we use EOT because end of *text* is more accurate for what we're doing than end of *sentence*
46
+ return self.tokenizer.eos_token_id
47
+
48
+ @property
49
+ def max_length(self):
50
+ try:
51
+ return self.gpt2.config.n_ctx
52
+ except AttributeError:
53
+ # gptneoconfig doesn't have n_ctx apparently
54
+ return self.model.config.max_position_embeddings
55
+
56
+ @property
57
+ def max_gen_toks(self):
58
+ print("max_gen_toks fn")
59
+ return 256
60
+
61
+ @property
62
+ def batch_size(self):
63
+ # TODO: fix multi-gpu
64
+ return self.batch_size_per_gpu # * gpus
65
+
66
+ @property
67
+ def device(self):
68
+ # TODO: fix multi-gpu
69
+ return self._device
70
+
71
+ def tok_encode(self, string: str):
72
+ return self.tokenizer.encode(string, add_special_tokens=False)
73
+
74
+ def tok_encode_batch(self, strings):
75
+ return self.tokenizer(
76
+ strings,
77
+ padding=True,
78
+ add_special_tokens=False,
79
+ return_tensors="pt",
80
+ )
81
+
82
+ def tok_decode(self, tokens):
83
+ return self.tokenizer.batch_decode(tokens, skip_special_tokens=True)
84
+
85
+ def _model_call(self, inps):
86
+ """
87
+ inps: a torch tensor of shape [batch, sequence]
88
+ the size of sequence may vary from call to call
89
+ returns: a torch tensor of shape [batch, sequence, vocab] with the
90
+ logits returned from the model
91
+ """
92
+ with torch.no_grad():
93
+
94
+ return self.model(inps)["logits"]
95
+
96
+ def model_batched_set(self, inps):
97
+ dataset_logits = []
98
+ for batch in inps:
99
+ multi_logits = F.log_softmax(
100
+ self._model_call(batch), dim=-1
101
+ ).cpu() # [batch, padding_length, vocab]
102
+ dataset_logits.append(multi_logits)
103
+ return dataset_logits
104
+
105
+ def _model_generate(self, context, max_length, eos_token_id):
106
+ return self.model.generate(
107
+ context, max_length=max_length, eos_token_id=eos_token_id, do_sample=False
108
+ )
models/hadamard_utils.py ADDED
The diff for this file is too large to render. See raw diff
 
models/int_llama_layer.py ADDED
@@ -0,0 +1,627 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ from typing import Optional, Tuple, List
4
+ from quantize.int_linear import QuantLinear
5
+ from quantize.int_matmul import QuantMatMul
6
+ import torch.nn.functional as F
7
+ from quantize.slider_norm import SliderLlamaRMSNorm
8
+ from quantize.slider_norm import RMSN
9
+ from collections import OrderedDict
10
+ import math
11
+ from transformers.models.llama.modeling_llama import LlamaRotaryEmbedding,apply_rotary_pos_emb,LlamaRMSNorm,repeat_kv
12
+ from transformers.models.llama.configuration_llama import LlamaConfig
13
+ from transformers.activations import ACT2FN
14
+ import copy
15
+ from models.transformation import *
16
+
17
+ from transformers.models.qwen3_moe.modeling_qwen3_moe import Qwen3MoeSparseMoeBlock
18
+
19
+
20
+ from quantize.int_linear_lora import LoRAQuantLinear
21
+
22
+ from models.hadamard_utils import random_hadamard_matrix
23
+
24
+ from quantize.utils import cleanup_memory
25
+
26
+ class QuantLlamaMLP(nn.Module):
27
+ def __init__(
28
+ self,
29
+ org_module: nn.Module,
30
+ hidden_act: str,
31
+ args=None,
32
+ use_lora=False,
33
+ lora_attr=None,
34
+ ):
35
+ super().__init__()
36
+ self.lora_attr = lora_attr
37
+ self.merged_down = False
38
+
39
+ self.args = args
40
+ if use_lora:
41
+ self.gate_proj = LoRAQuantLinear(
42
+ org_module.gate_proj,
43
+ args.weight_quant_params,
44
+ args.act_quant_params,
45
+ r=args.lora_rank,
46
+ lora_attr=self.lora_attr
47
+ )
48
+ self.down_proj = LoRAQuantLinear(
49
+ org_module.down_proj,
50
+ args.weight_quant_params,
51
+ args.act_quant_params,
52
+ r=args.lora_rank,
53
+ lora_attr=self.lora_attr
54
+ )
55
+ self.up_proj = LoRAQuantLinear(
56
+ org_module.up_proj,
57
+ args.weight_quant_params,
58
+ args.act_quant_params,
59
+ r=args.lora_rank,
60
+ lora_attr=self.lora_attr
61
+ )
62
+ else:
63
+ self.gate_proj = QuantLinear(
64
+ org_module.gate_proj,
65
+ args.weight_quant_params,
66
+ args.act_quant_params,
67
+ )
68
+ self.down_proj = QuantLinear(
69
+ org_module.down_proj,
70
+ args.weight_quant_params,
71
+ args.act_quant_params,
72
+ )
73
+ self.up_proj = QuantLinear(
74
+ org_module.up_proj, args.weight_quant_params, args.act_quant_params
75
+ )
76
+ self.act_fn = ACT2FN[hidden_act]
77
+
78
+
79
+
80
+
81
+ def forward(self, x):
82
+
83
+ return self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
84
+
85
+ def get_quant_moe_mlp(org_module: nn.Module,args,config,use_lora,lora_attr):
86
+ if args.quant_gate is True or args.update_gate is True:
87
+ if use_lora:
88
+ weight_quant_params = copy.deepcopy(args.weight_quant_params)
89
+ act_quant_params = copy.deepcopy(args.act_quant_params)
90
+
91
+ if args.update_gate is True:
92
+ weight_quant_params["n_bits"] = 16
93
+ act_quant_params["n_bits"] = 16
94
+
95
+ org_module.gate = LoRAQuantLinear(
96
+ org_module.gate,
97
+ weight_quant_params,
98
+ act_quant_params,
99
+ r=args.lora_rank,
100
+ lora_attr=lora_attr
101
+ )
102
+ else:
103
+ org_module.gate = QuantLinear(
104
+ org_module.gate,
105
+ args.weight_quant_params,
106
+ args.act_quant_params,
107
+ )
108
+
109
+
110
+ for i in range(len(org_module.experts)):
111
+ ori_mlp = org_module.experts[i]
112
+ org_module.experts[i] = QuantLlamaMLP(
113
+ org_module=ori_mlp,
114
+ hidden_act=config.hidden_act,
115
+ args=args,
116
+ use_lora=use_lora,
117
+ lora_attr=lora_attr
118
+ )
119
+ return org_module
120
+
121
+
122
+ class QuantLlamaAttention(nn.Module):
123
+ """Multi-headed attention from 'Attention Is All You Need' paper"""
124
+
125
+ def __init__(self,
126
+ org_module: nn.Module,
127
+ config: LlamaConfig,
128
+ args=None,
129
+ use_lora=False,
130
+ lora_attr=None,
131
+ layer_id = None,
132
+ ):
133
+ super().__init__()
134
+ self.config = config
135
+ self.hidden_size = config.hidden_size
136
+ self.num_heads = config.num_attention_heads
137
+ # self.head_dim = self.hidden_size // self.num_heads
138
+ self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
139
+ self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
140
+ self.num_key_value_heads = config.num_key_value_heads
141
+ self.max_position_embeddings = config.max_position_embeddings
142
+ self.lora_attr = lora_attr
143
+ self.merge_v = False
144
+ self.layer_idx = layer_id
145
+ self.scaling = self.head_dim**-0.5
146
+ self.add_norm_model_list = ["qwen3" ,"qwen3_moe"]
147
+
148
+
149
+ if config.model_type in self.add_norm_model_list :
150
+ self.q_norm = copy.deepcopy(org_module.q_norm)
151
+ self.k_norm = copy.deepcopy(org_module.k_norm)
152
+
153
+ self.merged_vo = False
154
+
155
+ self.args = args
156
+ if (self.head_dim * self.num_heads) != self.hidden_size and self.config.model_type not in self.add_norm_model_list:
157
+ raise ValueError(
158
+ f"hidden_size must be divisible by num_heads (got `hidden_size`: {self.hidden_size}"
159
+ f" and `num_heads`: {self.num_heads})."
160
+ )
161
+
162
+ # self.rotary_emb = copy.deepcopy(org_module.rotary_emb)
163
+ self.rotary_emb = LlamaRotaryEmbedding(self.config)
164
+
165
+ if use_lora:
166
+ self.k_proj = LoRAQuantLinear(
167
+ org_module.k_proj,
168
+ args.weight_quant_params,
169
+ args.act_quant_params,
170
+ disable_input_quant=False,
171
+ r=args.lora_rank,
172
+ lora_attr=self.lora_attr
173
+ )
174
+ self.v_proj = LoRAQuantLinear(
175
+ org_module.v_proj,
176
+ args.weight_quant_params,
177
+ args.act_quant_params,
178
+ disable_input_quant=False,
179
+ r=args.lora_rank,
180
+ lora_attr=self.lora_attr
181
+ )
182
+ self.q_proj = LoRAQuantLinear(
183
+ org_module.q_proj,
184
+ args.weight_quant_params,
185
+ args.act_quant_params,
186
+ disable_input_quant=False,
187
+ r=args.lora_rank,
188
+ lora_attr=self.lora_attr
189
+ )
190
+ self.o_proj = LoRAQuantLinear(
191
+ org_module.o_proj,
192
+ args.weight_quant_params,
193
+ args.act_quant_params,
194
+ r=args.lora_rank,
195
+ lora_attr=self.lora_attr
196
+ )
197
+ else:
198
+ self.k_proj = QuantLinear(
199
+ org_module.k_proj,
200
+ args.weight_quant_params,
201
+ args.act_quant_params,
202
+ disable_input_quant=False,
203
+ )
204
+ self.v_proj = QuantLinear(
205
+ org_module.v_proj,
206
+ args.weight_quant_params,
207
+ args.act_quant_params,
208
+ disable_input_quant=False,
209
+ )
210
+ self.q_proj = QuantLinear(
211
+ org_module.q_proj,
212
+ args.weight_quant_params,
213
+ args.act_quant_params,
214
+ disable_input_quant=False,
215
+ )
216
+ self.o_proj = QuantLinear(
217
+ org_module.o_proj, args.weight_quant_params, args.act_quant_params
218
+ )
219
+
220
+ self.qkt_matmul = QuantMatMul(
221
+ args.q_quant_params, args.k_quant_params, matmul_func=torch.matmul
222
+ )
223
+ self.pv_matmul = QuantMatMul(
224
+ args.p_quant_params, args.v_quant_params, matmul_func=torch.matmul
225
+ )
226
+
227
+ self.use_weight_quant = False
228
+ self.use_act_quant = False
229
+
230
+
231
+
232
+
233
+ def _shape(self, tensor: torch.Tensor, seq_len: int, bsz: int):
234
+ return tensor.view(bsz, seq_len, self.num_heads, self.head_dim).transpose(1, 2).contiguous()
235
+
236
+ def forward(
237
+ self,
238
+ hidden_states: torch.Tensor,
239
+ attention_mask: Optional[torch.Tensor] = None,
240
+ position_ids: Optional[torch.LongTensor] = None,
241
+ past_key_value: Optional[Tuple[torch.Tensor]] = None,
242
+ output_attentions: bool = False,
243
+ use_cache: bool = False,
244
+ cache_position: Optional[torch.LongTensor] = None,
245
+ position_embeddings: Tuple[torch.Tensor, torch.Tensor] = None,
246
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
247
+ bsz, q_len, _ = hidden_states.size()
248
+
249
+ input_shape = hidden_states.shape[:-1]
250
+ hidden_shape = (*input_shape, -1, self.head_dim)
251
+
252
+ if self.config.model_type in self.add_norm_model_list:
253
+ # import ipdb;ipdb.set_trace()
254
+ query_states = self.q_norm(self.q_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
255
+ key_states = self.k_norm(self.k_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
256
+ else:
257
+ query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
258
+ key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
259
+
260
+ value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
261
+
262
+
263
+
264
+ kv_seq_len = key_states.shape[-2]
265
+
266
+ if past_key_value is not None:
267
+ # kv_seq_len += past_key_value[0].shape[-2]
268
+ if self.layer_idx is None:
269
+ raise ValueError(
270
+ f"The cache structure has changed since version v4.36. If you are using {self.__class__.__name__} "
271
+ "for auto-regressive decoding with k/v caching, please make sure to initialize the attention class "
272
+ "with a layer index."
273
+ )
274
+ kv_seq_len += past_key_value.get_usable_length(kv_seq_len, self.layer_idx)
275
+
276
+ cos, sin = position_embeddings
277
+ query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
278
+
279
+
280
+
281
+ # [bsz, nh, t, hd]
282
+
283
+ if past_key_value is not None:
284
+ # sin and cos are specific to RoPE models; cache_position needed for the static cache
285
+ cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
286
+ key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
287
+
288
+ key_states = repeat_kv(key_states, self.num_key_value_groups)
289
+ value_states = repeat_kv(value_states, self.num_key_value_groups)
290
+
291
+
292
+
293
+ query_states = self.qkt_matmul.quant_x1(query_states) # dont quant q
294
+ key_states = self.qkt_matmul.quant_x2(key_states)
295
+ attn_weights = self.qkt_matmul(query_states, key_states.transpose(2, 3)) * self.scaling
296
+
297
+
298
+ if attention_mask is not None:
299
+ causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
300
+ attn_weights = attn_weights + causal_mask
301
+ attn_weights = torch.max(attn_weights, torch.tensor(torch.finfo(attn_weights.dtype).min))
302
+
303
+ attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query_states.dtype)
304
+ attn_weights = self.pv_matmul.quant_x1(attn_weights) # dont quant p
305
+ value_states = self.pv_matmul.quant_x2(value_states)
306
+ attn_output = self.pv_matmul(attn_weights, value_states)
307
+
308
+
309
+ attn_output = attn_output.transpose(1, 2).contiguous()
310
+ attn_output = attn_output.reshape(*input_shape, -1).contiguous()
311
+
312
+
313
+ attn_output = self.o_proj(attn_output)
314
+
315
+ if not output_attentions:
316
+ attn_weights = None
317
+
318
+ return attn_output, attn_weights, past_key_value
319
+
320
+
321
+
322
+
323
+ class QuantLlamaDecoderLayer(nn.Module):
324
+ def __init__(self,
325
+ config: LlamaConfig,
326
+ ori_layer,
327
+ layer_id,
328
+ args,
329
+ quant_mode="fp16",
330
+ use_lora=False,
331
+ lora_attr=None,
332
+ ):
333
+ super().__init__()
334
+ self.use_lora = use_lora
335
+ self.hidden_size = config.hidden_size
336
+ self.lora_attr = lora_attr
337
+
338
+ self.self_attn = QuantLlamaAttention(
339
+ org_module=ori_layer.self_attn,
340
+ config=config,
341
+ args=args,
342
+ use_lora=self.use_lora,
343
+ lora_attr=self.lora_attr,
344
+ layer_id = layer_id,
345
+ )
346
+ if isinstance(ori_layer.mlp, Qwen3MoeSparseMoeBlock):
347
+ self.mlp = get_quant_moe_mlp(
348
+ org_module=ori_layer.mlp,
349
+ args=args,
350
+ config=config,
351
+ use_lora=self.use_lora,
352
+ lora_attr=self.lora_attr
353
+ )
354
+ else:
355
+ self.mlp = QuantLlamaMLP(
356
+ org_module=ori_layer.mlp,
357
+ hidden_act=config.hidden_act,
358
+ args=args,
359
+ use_lora=self.use_lora,
360
+ lora_attr=self.lora_attr
361
+ )
362
+
363
+ self.input_layernorm = SliderLlamaRMSNorm(ori_layer.input_layernorm,eps=ori_layer.input_layernorm.variance_epsilon)
364
+ self.post_attention_layernorm = SliderLlamaRMSNorm(ori_layer.post_attention_layernorm,eps=ori_layer.post_attention_layernorm.variance_epsilon)
365
+ self.eval_mode = False
366
+ self.quant_mode = quant_mode
367
+
368
+ assert self.quant_mode in ["slider","lora_only","fp16"],"only supprot quant_mode in [slider,fp16]"
369
+ self.finished_quant = False
370
+ self.revocer_act = False
371
+
372
+ self.layer_id = layer_id
373
+
374
+ self.massive_act_loc_mask = None
375
+ self.modify_massive_act = False
376
+ self.args = args
377
+ self.Q_merged = False
378
+
379
+ self.update_quant_mode(self.quant_mode,args)
380
+
381
+
382
+
383
+ def update_quant_mode(self,new_mode,args=None):
384
+ self.quant_mode = new_mode
385
+ support_list = ["weight_merge","slider","lora_only","fp16"]
386
+ assert self.quant_mode in support_list,f"only supprot quant_mode in {support_list}"
387
+
388
+ if self.quant_mode == "fp16":
389
+ self.set_quant_state(weight_quant=False,act_quant=False,quant_rate=args.quant_rate)
390
+ for name, module in self.named_modules():
391
+ # if isinstance(module, QuantLinear):
392
+ if hasattr(module,"use_temporary_parameter"):
393
+ module.use_temporary_parameter=False
394
+ self.clear_temp_variable()
395
+ elif self.quant_mode == "weight_merge":
396
+ self.set_quant_state(weight_quant=False,act_quant=bool(args.abits<16),quant_rate=args.quant_rate)
397
+ # import ipdb;ipdb.set_trace()
398
+ if self.finished_quant is False:
399
+ # import ipdb;ipdb.set_trace()
400
+ if args.quant_mode_layer_list[self.layer_id] in ["slider"]:
401
+ self.smooth_inplace()
402
+ with torch.no_grad():
403
+ for name, module in self.named_modules():
404
+ if hasattr(module,"use_temporary_parameter"):
405
+ module.use_temporary_parameter=False
406
+ if isinstance(module, LoRAQuantLinear):
407
+ module.merged = True
408
+ # import ipdb;ipdb.set_trace()
409
+
410
+ if args.lora_rank > 0 :
411
+ for i in range(module.lora_iter_num):
412
+ if args.export_model_path and args.export_model_mode =="fp16":
413
+ module.weight = module.weight + module.lora_B[i] @ module.lora_A[i] * module.scaling
414
+ else:
415
+ module.weight = module.weight_quantizer(module.weight + module.lora_B[i] @ module.lora_A[i] * module.scaling)
416
+ else:
417
+ module.weight = module.weight_quantizer(module.weight)
418
+ elif isinstance(module, QuantLinear):
419
+ if args.export_model_path and args.export_model_mode =="fp16":
420
+ module.weight = module.weight
421
+ else:
422
+ module.weight = module.weight_quantizer(module.weight)
423
+ # module.use_temporary_parameter=False
424
+ else:
425
+ pass
426
+ self.finished_quant = True
427
+ self.clear_temp_variable()
428
+ else:
429
+ self.set_quant_state(weight_quant=True,act_quant=bool(args.abits<16),quant_rate=args.quant_rate)
430
+ self.clear_temp_variable()
431
+
432
+ def update_quant_parms(self,weight_quant_params):
433
+ for name, module in self.named_modules():
434
+ if isinstance(module, QuantLinear):
435
+ module.update_quant_parms(weight_quant_params)
436
+
437
+
438
+ def forward(
439
+ self,
440
+ hidden_states: torch.Tensor,
441
+ attention_mask: Optional[torch.Tensor] = None,
442
+ position_ids: Optional[torch.LongTensor] = None,
443
+ past_key_value: Optional[Tuple[torch.Tensor]] = None,
444
+ output_attentions: Optional[bool] = False,
445
+ use_cache: Optional[bool] = False,
446
+ cache_position: Optional[torch.LongTensor] = None,
447
+ position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
448
+ output_router_logits = False,
449
+ ) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
450
+ """
451
+ Args:
452
+ hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, embed_dim)`
453
+ attention_mask (`torch.FloatTensor`, *optional*): attention mask of size
454
+ `(batch, 1, tgt_len, src_len)` where padding elements are indicated by very large negative values.
455
+ output_attentions (`bool`, *optional*):
456
+ Whether or not to return the attentions tensors of all attention layers. See `attentions` under
457
+ returned tensors for more detail.
458
+ use_cache (`bool`, *optional*):
459
+ If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding
460
+ (see `past_key_values`).
461
+ past_key_value (`Tuple(torch.FloatTensor)`, *optional*): cached past key and value projection states
462
+ """
463
+
464
+
465
+
466
+ if not (self.quant_mode in ["fp16","weight_merge","lora_only"]):
467
+ if self.quant_mode in ["slider"]:
468
+ self.smooth_and_quant_temporary()
469
+ else:
470
+ raise NotImplementedError("only supprot quant_mode in [slider,lora_only,weight_merge,fp16]")
471
+
472
+
473
+ residual = hidden_states
474
+
475
+ hidden_states = self.input_layernorm(hidden_states)
476
+
477
+
478
+ # Self Attention
479
+ hidden_states, self_attn_weights, present_key_value = self.self_attn(
480
+ hidden_states=hidden_states,
481
+ attention_mask=attention_mask,
482
+ position_ids=position_ids,
483
+ past_key_value=past_key_value,
484
+ output_attentions=output_attentions,
485
+ use_cache=use_cache,
486
+ cache_position=cache_position,
487
+ position_embeddings=position_embeddings,
488
+
489
+ )
490
+ hidden_states = residual + hidden_states
491
+
492
+ # Fully Connected
493
+ residual = hidden_states
494
+ hidden_states = self.post_attention_layernorm(hidden_states)
495
+
496
+
497
+ hidden_states = self.mlp(hidden_states)
498
+
499
+ if isinstance(hidden_states, tuple):
500
+ hidden_states, router_logits = hidden_states
501
+ else:
502
+ router_logits = None
503
+
504
+ hidden_states = residual + hidden_states
505
+
506
+ outputs = (hidden_states,)
507
+
508
+ if output_attentions:
509
+ outputs += (self_attn_weights,)
510
+
511
+ if use_cache:
512
+ outputs += (present_key_value,)
513
+
514
+ if self.eval_mode:
515
+ self.clear_temp_variable()
516
+
517
+ if output_attentions:
518
+ outputs += (self_attn_weights,)
519
+
520
+ if output_router_logits:
521
+ outputs += (router_logits,)
522
+ return outputs
523
+
524
+ def set_quant_state(self, weight_quant: bool = False, act_quant: bool = False, quant_rate:float = 1.0):
525
+ # setting weight quantization here does not affect actual forward pass
526
+ self.use_weight_quant = weight_quant
527
+ self.use_act_quant = act_quant
528
+ self.quant_rate = quant_rate
529
+ names = []
530
+ for name, m in self.named_modules():
531
+ if isinstance(m, (QuantLinear, QuantMatMul)):
532
+ names.append(name)
533
+ m.set_quant_state(weight_quant, act_quant, quant_rate)
534
+
535
+ def smooth_and_quant_temporary(self):
536
+ with torch.no_grad():
537
+ for name, module in self.named_parameters():
538
+ if "smooth_scale" in name:
539
+ module.data = truncate_number(module)
540
+
541
+
542
+
543
+ smooth_ln_fcs_temporary(self.input_layernorm,[self.self_attn.q_proj, self.self_attn.k_proj, self.self_attn.v_proj],
544
+ self.qkv_smooth_scale,self.qkv_smooth_shift)
545
+ smooth_ln_fcs_temporary(self.post_attention_layernorm,[self.mlp.up_proj,self.mlp.gate_proj],
546
+ self.fc1_smooth_scale,self.fc1_smooth_shift)
547
+ smooth_fc_fc_temporary(self.self_attn.v_proj,self.self_attn.o_proj,
548
+ self.out_smooth_scale, self.out_smooth_shift,num_key_value_groups=self.self_attn.num_key_value_groups,head_dim=self.self_attn.head_dim,args=self.args)
549
+ smooth_q_k_temporary(self.self_attn.q_proj, self.self_attn.k_proj,
550
+ self.qkt_smooth_scale,num_key_value_groups=self.self_attn.num_key_value_groups,head_dim=self.self_attn.head_dim,args=self.args)
551
+ if self.args.use_down_scale is True:
552
+ smooth_fc_fc_temporary(self.mlp.up_proj,self.mlp.down_proj,
553
+ self.fc2_smooth_scale,self.fc2_smooth_shift)
554
+ else:
555
+ self.mlp.down_proj.temp_weight = self.mlp.down_proj.weight
556
+
557
+
558
+ # quant
559
+ for name, module in self.named_modules():
560
+ if isinstance(module, QuantLinear):
561
+ if hasattr(module, "temp_weight"):
562
+ module.temp_weight = module.temp_weight
563
+ else:
564
+ module.temp_weight = module.weight
565
+ if not hasattr(module, "temp_bias"):
566
+ module.temp_bias = module.bias
567
+ module.use_temporary_parameter=True
568
+
569
+ def clear_temp_variable(self):
570
+ for name, module in self.named_modules():
571
+ if hasattr(module,"temp_weight"):
572
+ del module.temp_weight
573
+ if hasattr(module,"temp_bias"):
574
+ del module.temp_bias
575
+
576
+
577
+ @torch.no_grad()
578
+ def smooth_inplace(self):
579
+ if self.let:
580
+ for name, module in self.named_parameters():
581
+ if "smooth_scale" in name:
582
+ module.data = truncate_number(module)
583
+ smooth_ln_fcs_inplace(self.input_layernorm,[self.self_attn.q_proj, self.self_attn.k_proj, self.self_attn.v_proj],
584
+ self.qkv_smooth_scale,self.qkv_smooth_shift)
585
+ smooth_ln_fcs_inplace(self.post_attention_layernorm,[self.mlp.up_proj,self.mlp.gate_proj],
586
+ self.fc1_smooth_scale,self.fc1_smooth_shift)
587
+ smooth_fc_fc_inplace(self.self_attn.v_proj,self.self_attn.o_proj,
588
+ self.out_smooth_scale, self.out_smooth_shift,self.self_attn.num_key_value_groups,head_dim=self.self_attn.head_dim,args=self.args)
589
+ smooth_q_k_inplace(self.self_attn.q_proj, self.self_attn.k_proj,
590
+ self.qkt_smooth_scale,self.self_attn.num_key_value_groups,head_dim=self.self_attn.head_dim,args=self.args)
591
+ if self.args.use_down_scale is True:
592
+ smooth_fc_fc_inplace(self.mlp.up_proj,self.mlp.down_proj,
593
+ self.fc2_smooth_scale,self.fc2_smooth_shift)
594
+
595
+ def get_slider_parameters(self, use_list=["scale"]):
596
+ params = []
597
+ for n, m in self.named_parameters():
598
+ if any(n.find(t) > -1 for t in use_list):
599
+ params.append(m)
600
+ return iter(params)
601
+
602
+ def get_lwc_parameters(self):
603
+ params = []
604
+ for n, m in self.named_parameters():
605
+ if n.find('bound_factor') > -1:
606
+ params.append(m)
607
+ return iter(params)
608
+
609
+ def slider_parameters(self, use_list=["scale"]):
610
+ params = []
611
+ for n, m in self.named_parameters():
612
+ if n.find('bound_factor') > -1 or any(n.find(t) > -1 for t in use_list):
613
+ params.append(m)
614
+ return iter(params)
615
+
616
+ def slider_state_dict(self, destination=None, prefix='', keep_vars=False):
617
+ if destination is None:
618
+ destination = OrderedDict()
619
+ for name, param in self.named_parameters():
620
+ if name.find('smooth') > -1 or name.find('bound_factor') > -1:
621
+ destination[prefix + name] = param if keep_vars else param.detach()
622
+ return destination
623
+
624
+ def register_scales_and_zeros(self):
625
+ for name, module in self.named_modules():
626
+ if isinstance(module, QuantLinear):
627
+ module.weight_quantizer.register_scales_and_zeros()
models/models_utils.py ADDED
@@ -0,0 +1,534 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import abc
2
+ import torch
3
+ import json
4
+ import hashlib
5
+ import collections
6
+ from tqdm import tqdm
7
+ from typing import Iterable
8
+ from abc import abstractmethod
9
+ from torch import nn
10
+ import transformers
11
+ import torch.nn.functional as F
12
+
13
+ class TruncateFunction(torch.autograd.Function):
14
+ @staticmethod
15
+ def forward(ctx, input, threshold):
16
+ truncated_tensor = input.clone()
17
+ truncated_tensor[truncated_tensor.abs() < threshold] = truncated_tensor[truncated_tensor.abs() < threshold].sign() * threshold
18
+ return truncated_tensor
19
+
20
+
21
+ @staticmethod
22
+ def backward(ctx, grad_output):
23
+ grad_input = grad_output.clone()
24
+ return grad_input, None
25
+
26
+ def truncate_number(number, threshold=1e-3):
27
+ # clamping scale to avoid overflow in the AMP training
28
+ return TruncateFunction.apply(number, threshold)
29
+
30
+ def find_layers(module, layers=[nn.Conv2d, nn.Linear, transformers.Conv1D], name=""):
31
+ if type(module) in layers:
32
+ return {name: module}
33
+ res = {}
34
+ for name1, child in module.named_children():
35
+ res.update(
36
+ find_layers(
37
+ child, layers=layers, name=name + "." + name1 if name != "" else name1
38
+ )
39
+ )
40
+ return res
41
+
42
+
43
+ class CacheHook:
44
+ def __init__(self, cachinglm):
45
+ if cachinglm is None:
46
+ self.dbdict = None
47
+ return
48
+
49
+ self.dbdict = cachinglm.dbdict
50
+
51
+ def add_partial(self, attr, req, res):
52
+ if self.dbdict is None:
53
+ return
54
+ hsh = hash_args(attr, req)
55
+ self.dbdict[hsh] = res
56
+
57
+
58
+ class LM(abc.ABC):
59
+ def __init__(self):
60
+ self.cache_hook = CacheHook(None)
61
+
62
+ @abstractmethod
63
+ def loglikelihood(self, requests):
64
+ """Compute log-likelihood of generating a continuation from a context.
65
+ Downstream tasks should attempt to use loglikelihood instead of other
66
+ LM calls whenever possible.
67
+
68
+ :param requests: list
69
+ A list of pairs (context, continuation)
70
+ context: str
71
+ Context string. Implementations of LM must be able to handle an
72
+ empty context string.
73
+ continuation: str
74
+ The continuation over which log likelihood will be calculated. If
75
+ there is a word boundary, the space should be in the continuation.
76
+ For example, context="hello" continuation=" world" is correct.
77
+ :return: list
78
+ A list of pairs (logprob, isgreedy)
79
+ logprob: float
80
+ The log probability of `continuation`
81
+ isgreedy:
82
+ Whether `continuation` would be generated by greedy sampling from `context`
83
+ """
84
+ pass
85
+
86
+ @abstractmethod
87
+ def loglikelihood_rolling(self, requests):
88
+ """Compute full log-likelihood of a string, with no truncation, for perplexity computation
89
+ - We will use the full max context length of the model.
90
+ - For inputs that exceed the max context length, we divide the tokenized string into chunks of up to
91
+ the max context length.
92
+ - IMPORTANT: Each document's loglikelihood/perplexity is computed *separately*, unlike other implementations
93
+ which may simply concatenate multiple documents together.
94
+ - IMPORTANT: We maximize the amount of context for each prediction. Specifically, for inputs that we break into
95
+ multiple chunks, the last input will still a full-sized context.
96
+ Example:
97
+ Input tokens: [ 0 1 2 3 4 5 6 7 8 9 ]
98
+ Prefix: EOT
99
+ Max context length: 4
100
+ Resulting input/prediction pairs:
101
+
102
+ INPUT: EOT 0 1 2
103
+ PRED: 0 1 2 3
104
+
105
+ INPUT: 3 4 5 6
106
+ PRED: 4 5 6 7
107
+
108
+ INPUT: 5 6 7 8
109
+ PRED: 8 9
110
+
111
+ Observe that:
112
+ 1. Each token is predicted exactly once
113
+ 2. For the last pair, we provide the full context, but only score the last two tokens
114
+
115
+ :param requests: list
116
+ A list of strings
117
+ string: str
118
+ String for which we are computing per-toke loglikelihood
119
+ :return: list
120
+ A list of pairs (logprob, isgreedy)
121
+ logprob: float
122
+ The log probability of `continuation`
123
+ isgreedy:
124
+ Whether `continuation` would be generated by greedy sampling from `context`
125
+ """
126
+ pass
127
+
128
+ # TODO: Add an optional max length
129
+ @abstractmethod
130
+ def greedy_until(self, requests):
131
+ """Generate greedily until a stopping sequence
132
+
133
+ :param requests: list
134
+ A list of pairs (context, until)
135
+ context: str
136
+ Context string
137
+ until: [str]
138
+ The string sequences to generate until. These string sequences
139
+ may each span across multiple tokens, or may be part of one token.
140
+ :return: list
141
+ A list of strings continuation
142
+ continuation: str
143
+ The generated continuation.
144
+ """
145
+ pass
146
+
147
+ @classmethod
148
+ def create_from_arg_string(cls, additional_config=None):
149
+ additional_config = {} if additional_config is None else additional_config
150
+ args = {k: v for k, v in additional_config.items() if v is not None}
151
+ return cls(**args)
152
+
153
+ def set_cache_hook(self, cache_hook):
154
+ self.cache_hook = cache_hook
155
+
156
+
157
+ class BaseLM(LM):
158
+ @property
159
+ @abstractmethod
160
+ def eot_token_id(self):
161
+ pass
162
+
163
+ @property
164
+ @abstractmethod
165
+ def max_length(self):
166
+ pass
167
+
168
+ @property
169
+ @abstractmethod
170
+ def max_gen_toks(self):
171
+ pass
172
+
173
+ @property
174
+ @abstractmethod
175
+ def batch_size(self):
176
+ pass
177
+
178
+ @property
179
+ @abstractmethod
180
+ def device(self):
181
+ pass
182
+
183
+ @abstractmethod
184
+ def tok_encode(self, string: str):
185
+ pass
186
+
187
+ @abstractmethod
188
+ def tok_decode(self, tokens: Iterable[int]):
189
+ pass
190
+
191
+ @abstractmethod
192
+ def _model_generate(self, context, max_length, eos_token_id):
193
+ pass
194
+
195
+ @abstractmethod
196
+ def _model_call(self, inps):
197
+ """
198
+ inps: a torch tensor of shape [batch, sequence]
199
+ the size of sequence may vary from call to call
200
+
201
+ returns: a torch tensor of shape [batch, sequence, vocab] with the
202
+ logits returned from the model
203
+ """
204
+ pass
205
+
206
+ # subclass must implement properties vocab_size, eot_token_id, max_gen_toks, batch_size, device, max_length.
207
+ # TODO: enforce this somehow
208
+
209
+ def loglikelihood(self, requests):
210
+ new_reqs = []
211
+ for context, continuation in requests:
212
+ if context == "":
213
+ # end of text as context
214
+ context_enc = [self.eot_token_id]
215
+ else:
216
+ context_enc = self.tok_encode(context)
217
+
218
+ continuation_enc = self.tok_encode(continuation)
219
+ new_reqs.append(((context, continuation), context_enc, continuation_enc))
220
+
221
+ return self._loglikelihood_tokens(new_reqs)
222
+
223
+ def loglikelihood_rolling(self, requests):
224
+ # TODO: Implement caching once we've confirmed the perplexity implementation
225
+ # TODO: automatic batch size detection for vectorization
226
+
227
+ loglikelihoods = []
228
+ for (string,) in tqdm(requests):
229
+ rolling_token_windows = list(
230
+ map(
231
+ make_disjoint_window,
232
+ get_rolling_token_windows(
233
+ token_list=self.tok_encode(string),
234
+ prefix_token=self.eot_token_id,
235
+ max_seq_len=self.max_length,
236
+ context_len=1,
237
+ ),
238
+ )
239
+ )
240
+
241
+ rolling_token_windows = [(None,) + x for x in rolling_token_windows]
242
+
243
+ # TODO: extract out this call so it only gets called once and also somehow figure out partial caching for
244
+ # that
245
+ string_nll = self._loglikelihood_tokens(
246
+ rolling_token_windows, disable_tqdm=True
247
+ )
248
+
249
+ # discard is_greedy
250
+ string_nll = [x[0] for x in string_nll]
251
+
252
+ string_nll = sum(string_nll)
253
+ loglikelihoods.append(string_nll)
254
+
255
+ return loglikelihoods
256
+
257
+ def _loglikelihood_tokens(self, requests, disable_tqdm=False):
258
+ # TODO: implement some kind of efficient-request-middleware that lumps together requests with the same context
259
+ res = []
260
+ dataset_inps = []
261
+
262
+ def _collate(x):
263
+ # the negative sign on len(toks) sorts descending - this has a few advantages:
264
+ # - time estimates will always be over not underestimates, which is more useful for planning
265
+ # - to know the size of a batch when going through the list, you know the first one is always the batch
266
+ # padded context length. this is useful to simplify the batching logic and more importantly to make
267
+ # automatic adaptive batches much much easier to implement
268
+ # - any OOMs will happen right away rather than near the end
269
+
270
+ toks = x[1] + x[2]
271
+ return -len(toks), tuple(toks)
272
+
273
+ # TODO: automatic (variable) batch size detection for vectorization
274
+ re_ord = Reorderer(requests, _collate)
275
+ for chunk in chunks(
276
+ tqdm(re_ord.get_reordered(), disable=disable_tqdm), self.batch_size
277
+ ):
278
+ inps = []
279
+ cont_toks_list = []
280
+ inplens = []
281
+
282
+ padding_length = None
283
+
284
+ # because vectorizing is annoying, we first convert each (context, continuation) pair to padded
285
+ # tensors, then we pack them together into a batch, call the model, and then pick it all apart
286
+ # again because vectorizing is annoying
287
+
288
+ for _, context_enc, continuation_enc in chunk:
289
+ # sanity check
290
+ assert len(context_enc) > 0
291
+ assert len(continuation_enc) > 0
292
+ assert len(continuation_enc) <= self.max_length
293
+
294
+ # how this all works:
295
+ # CTX CONT
296
+ # inp 0 1 2 3|4 5 6 7 8 9 <- last token is deleted by inp[:, :-1]
297
+ # gpt2 \ \
298
+ # logits 1 2 3|4 5 6 7 8 9 <- the ctx half gets tossed out by the
299
+ # cont_toks 4 5 6 7 8 9 [:, -len(continuation_enc):, :self.vocab_size] slice
300
+
301
+ # when too long to fit in context, truncate from the left
302
+ inp = torch.tensor(
303
+ (context_enc + continuation_enc)[-(self.max_length + 1) :][:-1],
304
+ dtype=torch.long,
305
+ ).to(self.device)
306
+ (inplen,) = inp.shape
307
+
308
+ cont = continuation_enc
309
+
310
+ # since in _collate we make sure length is descending, the longest is always the first one.
311
+ padding_length = (
312
+ padding_length if padding_length is not None else inplen
313
+ )
314
+
315
+ # pad length from seq to padding_length
316
+ inp = torch.cat(
317
+ [
318
+ inp, # [seq]
319
+ torch.zeros(padding_length - inplen, dtype=torch.long).to(
320
+ inp.device
321
+ ), # [padding_length - seq]
322
+ ],
323
+ dim=0,
324
+ )
325
+
326
+ inps.append(inp.unsqueeze(0)) # [1, padding_length]
327
+ cont_toks_list.append(cont)
328
+ inplens.append(inplen)
329
+ # import pdb; pdb.set_trace()
330
+ batched_inps = torch.cat(inps, dim=0).to(
331
+ self.device
332
+ ) # [batch, padding_length
333
+
334
+ # self.model = self.model.to(self.device)
335
+ multi_logits = F.log_softmax(
336
+ self._model_call(batched_inps), dim=-1
337
+ ).cpu() # [batch, padding_length, vocab]
338
+
339
+
340
+ for (cache_key, _, _), logits, inp, inplen, cont_toks in zip(
341
+ chunk, multi_logits, inps, inplens, cont_toks_list
342
+ ):
343
+
344
+ # Slice to original seq length
345
+ contlen = len(cont_toks)
346
+ logits = logits[inplen - contlen : inplen].unsqueeze(
347
+ 0
348
+ ) # [1, seq, vocab]
349
+
350
+ # Check if per-token argmax is exactly equal to continuation
351
+ greedy_tokens = logits.argmax(dim=-1)
352
+ cont_toks = torch.tensor(cont_toks, dtype=torch.long).unsqueeze(
353
+ 0
354
+ ) # [1, seq]
355
+ # import pdb; pdb.set_trace()
356
+ max_equal = (greedy_tokens == cont_toks).all()
357
+
358
+ # Obtain log-probs at the corresponding continuation token indices
359
+ # last_token_slice = logits[:, -1, :].squeeze(0).tolist()
360
+ logits = torch.gather(logits, 2, cont_toks.unsqueeze(-1)).squeeze(
361
+ -1
362
+ ) # [1, seq]
363
+
364
+ # Answer: (log prob, is-exact-match)
365
+ answer = (float(logits.sum()), bool(max_equal))
366
+
367
+ # partial caching
368
+ if cache_key is not None:
369
+ self.cache_hook.add_partial("loglikelihood", cache_key, answer)
370
+ res.append(answer)
371
+
372
+ return re_ord.get_original(res)
373
+
374
+ def greedy_until(self, requests):
375
+ print("greedy utils in base...")
376
+ # TODO: implement fully general `until` that handles until that are
377
+ # multiple tokens or that span multiple tokens correctly
378
+
379
+ # TODO: extract to TokenizedLM?
380
+ res = []
381
+
382
+ def _collate(x):
383
+ toks = self.tok_encode(x[0])
384
+ return len(toks), x[0]
385
+
386
+ re_ord = Reorderer(requests, _collate)
387
+
388
+ for context, until in tqdm(re_ord.get_reordered()):
389
+ if isinstance(until, str):
390
+ until = [until]
391
+
392
+ (primary_until,) = self.tok_encode(until[0])
393
+
394
+ context_enc = torch.tensor(
395
+ [self.tok_encode(context)[self.max_gen_toks - self.max_length :]]
396
+ ).to(self.device)
397
+
398
+ cont = self._model_generate(
399
+ context_enc, context_enc.shape[1] + self.max_gen_toks, primary_until
400
+ )
401
+
402
+ s = self.tok_decode(cont[0].tolist()[context_enc.shape[1] :])
403
+
404
+ for term in until:
405
+ s = s.split(term)[0]
406
+
407
+ # partial caching
408
+ self.cache_hook.add_partial("greedy_until", (context, until), s)
409
+
410
+ res.append(s)
411
+
412
+ return re_ord.get_original(res)
413
+
414
+
415
+ def make_disjoint_window(pair):
416
+ """Takes output from get_rolling_token_windows and makes the context not overlap with the continuation"""
417
+ a, b = pair
418
+ return a[: len(a) - (len(b) - 1)], b
419
+
420
+
421
+ def hash_args(attr, args):
422
+ dat = json.dumps([attr] + list(args))
423
+ return hashlib.sha256(dat.encode("utf-8")).hexdigest()
424
+
425
+
426
+ def simple_parse_args_string(args_string):
427
+ """
428
+ Parses something like
429
+ args1=val1,arg2=val2
430
+ Into a dictionary
431
+ """
432
+ args_string = args_string.strip()
433
+ if not args_string:
434
+ return {}
435
+ arg_list = args_string.split(",")
436
+ args_dict = {}
437
+ for arg in arg_list:
438
+ k, v = arg.split("=")
439
+ args_dict[k] = v
440
+ return args_dict
441
+
442
+
443
+ def get_rolling_token_windows(token_list, prefix_token, max_seq_len, context_len):
444
+ """
445
+ - context_len allows for a rolling window context, allowing each prediction window to potentially
446
+ condition on some context
447
+
448
+ :param token_list: list
449
+ List of tokens to be PREDICTED
450
+ :param max_seq_len: int
451
+ max_seq_len of model (or max_seq_len we want to use)
452
+ :param context_len: int
453
+ Amount of desired token context for prediction. Needs to be at least 1.
454
+ :param prefix_token: token
455
+ Dummy token like <eos> so the first token has something to condition on
456
+ :return: generator
457
+ Generator of tuples
458
+ (input_tokens, pred_tokens)
459
+ Note: Score only the last len(pred_tokens) logits of the LM
460
+ """
461
+ assert 1 <= context_len <= max_seq_len
462
+ if not token_list:
463
+ return
464
+ # +1 offset, going from input->preds
465
+ pred_len = max_seq_len - context_len + 1
466
+ predicted = 0
467
+
468
+ # Special handling for first window: predict all tokens
469
+ first_seq_len = min(max_seq_len, len(token_list))
470
+ yield ([prefix_token] + token_list[: first_seq_len - 1], token_list[:first_seq_len])
471
+ predicted += first_seq_len
472
+
473
+ while predicted < len(token_list):
474
+ window_pred_len = min(len(token_list) - predicted, pred_len)
475
+ window_end = predicted + window_pred_len
476
+
477
+ yield (
478
+ token_list[window_end - max_seq_len - 1 : window_end - 1],
479
+ token_list[window_end - window_pred_len : window_end],
480
+ )
481
+ predicted += window_pred_len
482
+
483
+
484
+ class Reorderer:
485
+ def __init__(self, arr, fn):
486
+ self.size = len(arr)
487
+ arr = list(enumerate(arr))
488
+ arr = group(arr, lambda x: fn(x[1]))
489
+ arr = [([y[0] for y in x], x[0][1]) for x in arr]
490
+ arr.sort(key=lambda x: fn(x[1]))
491
+
492
+ self.arr = arr
493
+
494
+ def get_reordered(self):
495
+ return [x[1] for x in self.arr]
496
+
497
+ def get_original(self, newarr):
498
+ res = [None] * self.size
499
+ cov = [False] * self.size
500
+
501
+ for (inds, _), v in zip(self.arr, newarr):
502
+ for ind in inds:
503
+ res[ind] = v
504
+ cov[ind] = True
505
+
506
+ assert all(cov)
507
+
508
+ return res
509
+
510
+
511
+ def join_iters(iters):
512
+ for iter in iters:
513
+ yield from iter
514
+
515
+
516
+ def chunks(iter, n):
517
+ arr = []
518
+ for x in iter:
519
+ arr.append(x)
520
+ if len(arr) == n:
521
+ yield arr
522
+ arr = []
523
+
524
+ if arr:
525
+ yield arr
526
+
527
+
528
+ def group(arr, fn):
529
+ res = collections.defaultdict(list)
530
+
531
+ for ob in arr:
532
+ res[fn(ob)].append(ob)
533
+
534
+ return list(res.values())
models/rotation_utils.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import typing
3
+ from quantize import utils
4
+ import transformers
5
+ import tqdm, math
6
+ from models.hadamard_utils import random_hadamard_matrix
7
+ from dataclasses import dataclass
8
+
9
+ OPT_MODEL = transformers.models.opt.modeling_opt.OPTForCausalLM
10
+ OPT_LAYER = transformers.models.opt.modeling_opt.OPTDecoderLayer
11
+ LLAMA_MODEL = transformers.models.llama.modeling_llama.LlamaForCausalLM
12
+ LLAMA_LAYER = transformers.models.llama.modeling_llama.LlamaDecoderLayer
13
+ QWEN_MODEL = transformers.models.qwen2.modeling_qwen2.Qwen2ForCausalLM
14
+ QWEN_LATER = transformers.models.qwen2.modeling_qwen2.Qwen2DecoderLayer
15
+
16
+
17
+ DEV = torch.device('cuda:0') if torch.cuda.is_available() else torch.device('cpu')
18
+
19
+ class RMSN(torch.nn.Module):
20
+ """
21
+ This class implements the Root Mean Square Normalization (RMSN) layer.
22
+ We use the implementation from LLAMARMSNorm here:
23
+ https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py#L75
24
+ """
25
+
26
+ def __init__(self, mean_dim: int,ori_norm, eps=1e-5):
27
+ super().__init__()
28
+ self.eps = eps
29
+ self.mean_dim = mean_dim
30
+ if ori_norm:
31
+ self.weight = torch.nn.Parameter(torch.ones_like(ori_norm.weight))
32
+ if hasattr(ori_norm,"bias") and ori_norm.bias is not None:
33
+ self.bias = torch.nn.Parameter(torch.zeros_like(ori_norm.bias))
34
+ else:
35
+ self.weight = torch.nn.Parameter(torch.ones(1))
36
+ self.bias = None
37
+
38
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
39
+ input_dtype = x.dtype
40
+ if x.dtype == torch.float16:
41
+ x = x.to(torch.float32)
42
+ variance = x.pow(2).mean(-1, keepdim=True)
43
+ x = x * torch.rsqrt(variance + self.eps)
44
+ return (self.weight * x).to(input_dtype)
45
+
46
+
47
+
48
+ def replace_modules(
49
+ root: torch.nn.Module,
50
+ type_to_replace,
51
+ new_module_factory,
52
+ replace_layers: bool,
53
+ ) -> None:
54
+ """Replace modules of given type using the supplied module factory.
55
+
56
+ Perform a depth-first search of a module hierarchy starting at root
57
+ and replace all instances of type_to_replace with modules created by
58
+ new_module_factory. Children of replaced modules are not processed.
59
+
60
+ Args:
61
+ root: the root of the module hierarchy where modules should be replaced
62
+ type_to_replace: a type instances of which will be replaced
63
+ new_module_factory: a function that given a module that should be replaced
64
+ produces a module to replace it with.
65
+ """
66
+ for name, module in root.named_children():
67
+ new_module = None
68
+ if isinstance(module, type_to_replace):
69
+ if replace_layers: # layernorm_fusion.replace_layers case where transformer layers are replaced
70
+ new_module = new_module_factory(module, int(name))
71
+ else: # layernorm_fusion.fuse_modules case where layernorms are fused
72
+ new_module = new_module_factory(module)
73
+ elif len(list(module.children())) > 0:
74
+ replace_modules(module, type_to_replace, new_module_factory, replace_layers)
75
+
76
+ if new_module is not None:
77
+ setattr(root, name, new_module)
78
+
79
+ def get_model_type(model):
80
+ if isinstance(model, OPT_MODEL):
81
+ model_type = OPT_MODEL
82
+ elif isinstance(model, LLAMA_MODEL):
83
+ model_type = LLAMA_MODEL
84
+ elif isinstance(model, QWEN_MODEL):
85
+ model_type = QWEN_MODEL
86
+ else:
87
+ raise ValueError(f'Unknown model type {model}')
88
+ return model_type
89
+
90
+
91
+ def model_type_extractor(model):
92
+ if isinstance(model, LLAMA_MODEL):
93
+ return LLAMA_MODEL
94
+ elif isinstance(model, QWEN_MODEL):
95
+ return QWEN_MODEL
96
+ elif isinstance(model, OPT_MODEL):
97
+ return OPT_MODEL
98
+ else:
99
+ raise ValueError(f'Unknown model type {model}')
100
+
101
+ def get_embeddings(model, model_type) -> list[torch.nn.Module]:
102
+ if model_type == LLAMA_MODEL or model_type == QWEN_MODEL :
103
+ return [model.model.embed_tokens]
104
+ elif model_type == OPT_MODEL:
105
+ return [model.model.decoder.embed_tokens, model.model.decoder.embed_positions]
106
+ else:
107
+ raise ValueError(f'Unknown model type {model_type}')
108
+
109
+
110
+ def get_transformer_layers(model, model_type):
111
+ if model_type == LLAMA_MODEL or model_type == QWEN_MODEL:
112
+ return [layer for layer in model.model.layers]
113
+ elif model_type == OPT_MODEL:
114
+ return [layer for layer in model.model.decoder.layers]
115
+ else:
116
+ raise ValueError(f'Unknown model type {model_type}')
117
+
118
+
119
+ def get_lm_head(model, model_type):
120
+ if model_type == LLAMA_MODEL or model_type == QWEN_MODEL:
121
+ return model.lm_head
122
+ elif model_type == OPT_MODEL:
123
+ return model.lm_head
124
+ else:
125
+ raise ValueError(f'Unknown model type {model_type}')
126
+
127
+
128
+
129
+
130
+ def get_pre_head_layernorm(model, model_type):
131
+ if model_type == LLAMA_MODEL or model_type == QWEN_MODEL :
132
+ pre_head_layernorm = model.model.norm
133
+ assert isinstance(pre_head_layernorm,
134
+ (transformers.models.llama.modeling_llama.LlamaRMSNorm,transformers.models.qwen2.modeling_qwen2.Qwen2RMSNorm))
135
+ elif model_type == OPT_MODEL:
136
+ pre_head_layernorm = model.model.decoder.final_layer_norm
137
+ assert pre_head_layernorm is not None
138
+ else:
139
+ raise ValueError(f'Unknown model type {model_type}')
140
+ return pre_head_layernorm
141
+
142
+ def fuse_ln_linear(layernorm: torch.nn.Module, linear_layers: typing.Iterable[torch.nn.Linear]) -> None:
143
+ """
144
+ fuse the linear operations in Layernorm into the adjacent linear blocks.
145
+ """
146
+ for linear in linear_layers:
147
+ linear_dtype = linear.weight.dtype
148
+
149
+ # Calculating new weight and bias
150
+ W_ = linear.weight.data.double()
151
+ linear.weight.data = (W_ * layernorm.weight.double()).to(linear_dtype)
152
+
153
+ if hasattr(layernorm, 'bias'):
154
+ if linear.bias is None:
155
+ linear.bias = torch.nn.Parameter(torch.zeros(linear.out_features, dtype=torch.float64))
156
+ linear.bias.data = linear.bias.data.double() + torch.matmul(W_, layernorm.bias.double())
157
+ linear.bias.data = linear.bias.data.to(linear_dtype)
158
+
159
+ def bake_mean_into_linear(linear: torch.nn.Linear) -> None:
160
+ """
161
+ This function takes a linear layer and subtracts the means from the
162
+ weights and biases. This will result in the linear layer performing
163
+ the mean substitution which is usually done inside layernorm.
164
+ """
165
+ linear_dtype = linear.weight.dtype
166
+ W_ = linear.weight.data.double()
167
+ linear.weight.data = W_ - W_.mean(dim=-2, keepdim=True)
168
+ linear.weight.data = linear.weight.data.to(linear_dtype)
169
+ if linear.bias is not None:
170
+ b_ = linear.bias.data.double()
171
+ linear.bias.data = b_ - b_.mean()
172
+ linear.bias.data = linear.bias.data.to(linear_dtype)
173
+
174
+
175
+
176
+ def fuse_layer_norms(model):
177
+
178
+ model_type = get_model_type(model)
179
+
180
+ kwargs = {'model': model, 'model_type': model_type}
181
+
182
+ # Embedding fusion
183
+ for W in get_embeddings(**kwargs):
184
+ W_ = W.weight.data.double()
185
+ W.weight.data = (W_ - W_.mean(dim=-1, keepdim=True)).to(W.weight.data.dtype)
186
+
187
+ layers = get_transformer_layers(**kwargs)
188
+
189
+ # Fuse the linear operations in Layernorm into the adjacent linear blocks.
190
+ for layer in layers:
191
+
192
+ # fuse the input layernorms into the linear layers
193
+ if model_type == LLAMA_MODEL or model_type == QWEN_MODEL :
194
+ fuse_ln_linear(layer.post_attention_layernorm, [layer.mlp.up_proj, layer.mlp.gate_proj])
195
+ fuse_ln_linear(layer.input_layernorm, [layer.self_attn.q_proj, layer.self_attn.k_proj, layer.self_attn.v_proj])
196
+ elif model_type == OPT_MODEL:
197
+ fuse_ln_linear(layer.self_attn_layer_norm, [layer.self_attn.q_proj, layer.self_attn.k_proj, layer.self_attn.v_proj])
198
+ fuse_ln_linear(layer.final_layer_norm, [layer.fc1])
199
+ else:
200
+ raise ValueError(f'Unknown model type {model_type}')
201
+
202
+
203
+
204
+ if model_type == OPT_MODEL:
205
+ bake_mean_into_linear(layer.self_attn.out_proj)
206
+ bake_mean_into_linear(layer.fc2)
207
+
208
+
209
+ fuse_ln_linear(get_pre_head_layernorm(**kwargs), [get_lm_head(**kwargs)])
210
+
211
+ model_type2_NORM = {
212
+ LLAMA_MODEL: transformers.models.llama.modeling_llama.LlamaRMSNorm,
213
+ QWEN_MODEL: transformers.models.qwen2.modeling_qwen2.Qwen2RMSNorm,
214
+ OPT_MODEL: torch.nn.LayerNorm
215
+ }
216
+
217
+ replace_modules(
218
+ model,
219
+ model_type2_NORM[model_type],
220
+ lambda ori_norm: RMSN(model.config.hidden_size,ori_norm),
221
+ replace_layers=False,
222
+ )
223
+
224
+
225
+
226
+ def get_orthogonal_matrix(size, mode, device=DEV):
227
+ return random_hadamard_matrix(size, device)
228
+
229
+
230
+ def rotate_embeddings(model, Q: torch.Tensor) -> None:
231
+ # Rotate the embeddings.
232
+ model_type = model_type_extractor(model)
233
+ for W in get_embeddings(model, model_type):
234
+ dtype = W.weight.data.dtype
235
+ W_ = W.weight.data.to(device=DEV, dtype=torch.float64)
236
+ W.weight.data = torch.matmul(W_, Q).to(device="cpu", dtype=dtype)
237
+
238
+
239
+ def rotate_attention_inputs(layer, Q, model_type) -> None:
240
+ # Rotate the WQ, WK and WV matrices of the self-attention layer.
241
+ for W in [layer.self_attn.q_proj, layer.self_attn.k_proj, layer.self_attn.v_proj]:
242
+ dtype = W.weight.dtype
243
+ W_ = W.weight.to(device=DEV, dtype=torch.float64)
244
+ W.weight.data = torch.matmul(W_, Q).to(device="cpu", dtype=dtype)
245
+
246
+ def rotate_attention_output(layer, Q, model_type) -> None:
247
+ # Rotate output matrix of the self-attention layer.
248
+ if model_type == LLAMA_MODEL or model_type == QWEN_MODEL:
249
+ W = layer.self_attn.o_proj
250
+ elif model_type == OPT_MODEL:
251
+ W = layer.self_attn.out_proj
252
+ else:
253
+ raise ValueError(f'Unknown model type {model_type}')
254
+
255
+ dtype = W.weight.data.dtype
256
+ W_ = W.weight.data.to(device=DEV, dtype=torch.float64)
257
+ W.weight.data = torch.matmul(Q.T, W_).to(device="cpu", dtype=dtype)
258
+ if W.bias is not None:
259
+ b = W.bias.data.to(device=DEV, dtype=torch.float64)
260
+ W.bias.data = torch.matmul(Q.T, b).to(device="cpu", dtype=dtype)
261
+
262
+ def rotate_mlp_input(layer, Q, model_type):
263
+ # Rotate the MLP input weights.
264
+ if model_type == LLAMA_MODEL or model_type == QWEN_MODEL:
265
+ mlp_inputs = [layer.mlp.up_proj, layer.mlp.gate_proj]
266
+ elif model_type == OPT_MODEL:
267
+ mlp_inputs = [layer.fc1]
268
+ else:
269
+ raise ValueError(f'Unknown model type {model_type}')
270
+ for W in mlp_inputs:
271
+ dtype = W.weight.dtype
272
+ W_ = W.weight.data.to(device=DEV, dtype=torch.float64)
273
+ W.weight.data = torch.matmul(W_, Q).to(device="cpu", dtype=dtype)
274
+
275
+ def rotate_mlp_output(layer, Q, model_type,add_online_rotate=True):
276
+ # Rotate the MLP output weights and bias.
277
+ if model_type == LLAMA_MODEL or model_type == QWEN_MODEL:
278
+ W = layer.mlp.down_proj
279
+ elif model_type == OPT_MODEL:
280
+ W = layer.fc2
281
+ else:
282
+ raise ValueError(f'Unknown model type {model_type}')
283
+ dtype = W.weight.data.dtype
284
+ W_ = W.weight.data.to(device=DEV, dtype=torch.float64)
285
+ W.weight.data = torch.matmul(Q.T, W_).to(device="cpu", dtype=dtype)
286
+ if W.bias is not None:
287
+ b = W.bias.data.to(device=DEV, dtype=torch.float64)
288
+ W.bias.data = torch.matmul(Q.T, b).to(device="cpu", dtype=dtype)
289
+
290
+
291
+
292
+ def rotate_head(model, Q: torch.Tensor) -> None:
293
+ # Rotate the head.
294
+ W = get_lm_head(model, model_type=model_type_extractor(model))
295
+ dtype = W.weight.data.dtype
296
+ W_ = W.weight.data.to(device=DEV, dtype=torch.float64)
297
+ W.weight.data = torch.matmul(W_, Q).to(device="cpu", dtype=dtype)
298
+
299
+ @torch.inference_mode()
300
+ def rotate_model(model, args,add_online_rotate=True):
301
+ Q = get_orthogonal_matrix(model.config.hidden_size,
302
+ args.rotate_mode)
303
+ config = model.config
304
+ num_heads = config.num_attention_heads
305
+ model_dim = config.hidden_size
306
+ head_dim = model_dim // num_heads
307
+
308
+
309
+ model_type = model_type_extractor(model)
310
+ rotate_embeddings(model, Q)
311
+ rotate_head(model, Q)
312
+ utils.cleanup_memory()
313
+ layers = get_transformer_layers(model, model_type=model_type)
314
+ for idx, layer in enumerate(tqdm.tqdm(layers, unit="layer", desc="Rotating")):
315
+ rotate_attention_inputs(layers[idx], Q, model_type)
316
+ rotate_attention_output(layers[idx], Q, model_type)
317
+ rotate_mlp_input(layers[idx], Q, model_type)
318
+ rotate_mlp_output(layers[idx], Q, model_type,add_online_rotate)
319
+
320
+
321
+
322
+ def get_rotate_model(model,save_path):
323
+ @dataclass
324
+ class parm():
325
+ rotate_mode:str
326
+ save_qmodel_path:str
327
+ fp32_had:bool
328
+ args = parm("hadamard",save_path,False)
329
+ model.to("cpu")
330
+ model.eval()
331
+ fuse_layer_norms(model)
332
+ rotate_model(model, args,add_online_rotate=False)
333
+ save_dict = {}
334
+ save_dict["model"] = model.state_dict()
335
+ torch.save(save_dict, args.save_qmodel_path)
336
+ return save_dict
models/transformation.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+
4
+
5
+
6
+ class TruncateFunction(torch.autograd.Function):
7
+ @staticmethod
8
+ def forward(ctx, input, threshold):
9
+ ctx.save_for_backward(input)
10
+ ctx.threshold = threshold
11
+ truncated_tensor = input.clone()
12
+ truncated_tensor = torch.where(truncated_tensor.abs() < threshold, truncated_tensor.sign() * threshold, truncated_tensor)
13
+ return truncated_tensor
14
+
15
+ @staticmethod
16
+ def backward(ctx, grad_output):
17
+ input, = ctx.saved_tensors
18
+ threshold = ctx.threshold
19
+ grad_input = grad_output.clone()
20
+ grad_input[input.abs() < threshold] = 0
21
+ return grad_input, None
22
+
23
+ def truncate_number(number, threshold=1e-2):
24
+ # avoid overflow with AMP training
25
+ return TruncateFunction.apply(number, threshold)
26
+
27
+
28
+
29
+ def smooth_ln_fcs_temporary(ln, fcs, scales,shifts,weight_in_cpu=False):
30
+ ln.use_temporary_parameter = True
31
+ if weight_in_cpu is True:
32
+ ln.weight = ln.weight.to(scales.device)
33
+ for fc in fcs:
34
+ fc.weight = fc.weight.to(scales.device)
35
+
36
+
37
+ if not isinstance(fcs, list):
38
+ fcs = [fcs]
39
+ if hasattr(ln, 'bias') and ln.bias is not None:
40
+ ln.temp_bias = (ln.bias - shifts) / scales
41
+ else:
42
+ ln.temp_bias = (-1*shifts) / scales
43
+
44
+ ln.temp_weight = ln.weight / scales
45
+
46
+ for fc in fcs:
47
+ fc.use_temporary_parameter = True
48
+ if hasattr(fc, 'bias') and fc.bias is not None:
49
+ fc.temp_bias = fc.bias + torch.matmul(fc.weight,shifts)
50
+ else:
51
+ fc.temp_bias = torch.matmul(fc.weight,shifts)
52
+ fc.temp_weight = fc.weight * scales.view(1,-1)
53
+
54
+ if weight_in_cpu is True:
55
+ ln.weight = ln.weight.cpu()
56
+ for fc in fcs:
57
+ fc.weight = fc.weight.cpu()
58
+
59
+
60
+ def smooth_ln_fcs_inplace(ln, fcs, scales,shifts):
61
+ ln.use_temporary_parameter = False
62
+ if not isinstance(fcs, list):
63
+ fcs = [fcs]
64
+ if hasattr(ln, 'bias') and ln.bias is not None:
65
+ ln.bias.sub_(shifts)
66
+ ln.bias.div_(scales)
67
+ else:
68
+ del ln.bias
69
+ ln.register_buffer('bias',(-1*shifts)/scales)
70
+
71
+ ln.weight.div_(scales)
72
+ for fc in fcs:
73
+ fc.use_temporary_parameter = False
74
+ if hasattr(fc, 'bias') and fc.bias is not None:
75
+ fc.bias.add_(fc.weight@shifts)
76
+ else:
77
+ del fc.bias
78
+ # import ipdb;ipdb.set_trace()
79
+ fc.register_buffer('bias',fc.weight@shifts)
80
+ fc.weight.mul_(scales.view(1,-1))
81
+
82
+
83
+
84
+ def smooth_fc_fc_temporary(fc1, fc2, scales,shifts=None,num_key_value_groups=1,head_dim=128,weight_in_cpu=False,args=None):
85
+ # only support for v_proj and out_proh now.
86
+ fc1.use_temporary_parameter = True
87
+ fc2.use_temporary_parameter = True
88
+ if weight_in_cpu is True:
89
+ fc1.weight = fc1.weight.to(scales.device)
90
+ fc2.weight = fc2.weight.to(scales.device)
91
+
92
+ # import ipdb;ipdb.set_trace()
93
+ if num_key_value_groups > 1:
94
+ # import ipdb;ipdb.set_trace()
95
+ if args.gqa_scales == "copy":
96
+ kv_scales = scales
97
+ kv_shift = shifts
98
+ scales = scales.view(-1,head_dim).repeat_interleave(num_key_value_groups,dim=0).view(-1)
99
+ shifts = shifts.view(-1,head_dim).repeat_interleave(num_key_value_groups,dim=0).view(-1)
100
+ elif args.gqa_scales == "mean":
101
+ kv_scales = scales.view(-1,num_key_value_groups,head_dim).mean(dim=1).view(-1)
102
+ kv_shift = shifts.view(-1,num_key_value_groups,head_dim).mean(dim=1).view(-1)
103
+ else:
104
+ raise NotImplementedError("Only implemented copy and mean for gqa")
105
+ else:
106
+ kv_scales = scales
107
+ kv_shift = shifts
108
+
109
+ if hasattr(fc1, 'temp_weight'):
110
+ fc1.temp_bias = fc1.temp_bias - kv_shift
111
+ fc1.temp_bias = fc1.temp_bias/kv_scales.view(-1)
112
+ fc1.temp_weight = fc1.temp_weight/kv_scales.view(-1,1)
113
+ else:
114
+ fc1.temp_bias = fc1.bias/kv_scales.view(-1)
115
+ fc1.temp_weight = fc1.weight/kv_scales.view(-1,1)
116
+
117
+ if hasattr(fc2, 'bias') and fc2.bias is not None:
118
+ fc2.temp_bias = fc2.bias + fc2.weight@shifts
119
+ else:
120
+ fc2.temp_bias = fc2.weight@shifts
121
+ fc2.temp_weight = fc2.weight * scales.view(1,-1)
122
+
123
+
124
+ if weight_in_cpu is True:
125
+ fc1.weight = fc1.weight.cpu()
126
+ fc2.weight = fc2.weight.cpu()
127
+
128
+ def smooth_fc_fc_inplace(fc1, fc2, scales,shifts=None,num_key_value_groups=1,head_dim=128,args=None):
129
+ # only support for v_proj and out_proh now.
130
+ fc1.use_temporary_parameter = False
131
+ fc2.use_temporary_parameter = False
132
+
133
+ if num_key_value_groups > 1:
134
+ # import ipdb;ipdb.set_trace()
135
+ if args.gqa_scales == "copy":
136
+ kv_scales = scales
137
+ kv_shift = shifts
138
+ scales = scales.view(-1,head_dim).repeat_interleave(num_key_value_groups,dim=0).view(-1)
139
+ shifts = shifts.view(-1,head_dim).repeat_interleave(num_key_value_groups,dim=0).view(-1)
140
+ elif args.gqa_scales == "mean":
141
+ kv_scales = scales.view(-1,num_key_value_groups,head_dim).mean(dim=1).view(-1)
142
+ kv_shift = shifts.view(-1,num_key_value_groups,head_dim).mean(dim=1).view(-1)
143
+ else:
144
+ raise NotImplementedError("Only implemented copy and mean for gqa")
145
+ else:
146
+ kv_scales = scales
147
+ kv_shift = shifts
148
+
149
+
150
+ fc1.bias.sub_(kv_shift)
151
+ fc1.bias.div_(kv_scales.view(-1))
152
+ fc1.weight.div_(kv_scales.view(-1,1))
153
+
154
+
155
+ if hasattr(fc2, 'bias') and fc2.bias is not None:
156
+ fc2.bias.add_(fc2.weight@shifts)
157
+ else:
158
+ del fc2.bias
159
+ fc2.register_buffer('bias',fc2.weight@shifts)
160
+ fc2.weight.mul_(scales.view(1,-1))
161
+
162
+
163
+
164
+ def smooth_q_k_temporary(q_proj, k_proj,scales,num_key_value_groups=1,head_dim=128,weight_in_cpu=False,args=None):
165
+ q_proj.use_temporary_parameter = True
166
+ k_proj.use_temporary_parameter = True
167
+
168
+ if weight_in_cpu is True:
169
+ q_proj.weight = q_proj.weight.to(scales.device)
170
+ k_proj.weight = k_proj.weight.to(scales.device)
171
+
172
+ if num_key_value_groups > 1:
173
+ # import ipdb;ipdb.set_trace()
174
+ if args.gqa_scales == "copy":
175
+ kv_scales = scales
176
+ scales = scales.view(-1,head_dim).repeat_interleave(num_key_value_groups,dim=0).view(-1)
177
+ elif args.gqa_scales == "mean":
178
+ kv_scales = scales.view(-1,num_key_value_groups,head_dim).mean(dim=1).view(-1)
179
+ else:
180
+ raise NotImplementedError("Only implemented copy and mean for gqa")
181
+ else:
182
+ kv_scales = scales
183
+
184
+ q_proj.temp_weight = q_proj.temp_weight/scales.view(-1,1)
185
+ q_proj.temp_bias = q_proj.temp_bias/scales.view(-1)
186
+
187
+ k_proj.temp_weight = k_proj.temp_weight*kv_scales.view(-1,1)
188
+ k_proj.temp_bias = k_proj.temp_bias*kv_scales.view(-1)
189
+
190
+ if weight_in_cpu is True:
191
+ q_proj.weight = q_proj.weight.cpu()
192
+ k_proj.weight = k_proj.weight.cpu()
193
+
194
+
195
+ def smooth_q_k_inplace(q_proj, k_proj, scales,num_key_value_groups=1,head_dim=128,args=None):
196
+ q_proj.use_temporary_parameter = False
197
+ k_proj.use_temporary_parameter = False
198
+
199
+ if num_key_value_groups > 1:
200
+ # import ipdb;ipdb.set_trace()
201
+ if args.gqa_scales == "copy":
202
+ kv_scales = scales
203
+ scales = scales.view(-1,head_dim).repeat_interleave(num_key_value_groups,dim=0).view(-1)
204
+ elif args.gqa_scales == "mean":
205
+ kv_scales = scales.view(-1,num_key_value_groups,head_dim).mean(dim=1).view(-1)
206
+ else:
207
+ raise NotImplementedError("Only implemented copy and mean for gqa")
208
+ else:
209
+ kv_scales = scales
210
+
211
+ q_proj.weight.div_(scales.view(-1,1))
212
+ q_proj.bias.div_(scales.view(-1))
213
+ k_proj.weight.mul_(kv_scales.view(-1,1))
214
+ k_proj.bias.mul_(kv_scales.view(-1))