Upload 4 files
Browse files- utils/__init__.py +3 -0
- utils/datautils.py +189 -0
- utils/export.py +37 -0
- utils/modelutils.py +83 -0
utils/__init__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from .modelutils import DEV, find_layers, gen_conditions, torch_snr_error
|
2 |
+
from .datautils import set_seed, get_wikitext2, get_ptb, get_c4, get_ptb_new, get_c4_new, get_loaders
|
3 |
+
from .export import export_quant_table
|
utils/datautils.py
ADDED
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import torch
|
3 |
+
|
4 |
+
|
5 |
+
def set_seed(seed):
|
6 |
+
np.random.seed(seed)
|
7 |
+
torch.random.manual_seed(seed)
|
8 |
+
|
9 |
+
|
10 |
+
def get_wikitext2(nsamples, seed, seqlen, model):
|
11 |
+
from datasets import load_dataset
|
12 |
+
traindata = load_dataset('wikitext', 'wikitext-2-raw-v1', split='train')
|
13 |
+
testdata = load_dataset('wikitext', 'wikitext-2-raw-v1', split='test')
|
14 |
+
|
15 |
+
from transformers import AutoTokenizer
|
16 |
+
try:
|
17 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=False)
|
18 |
+
except:
|
19 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=True)
|
20 |
+
trainenc = tokenizer("\n\n".join(traindata['text']), return_tensors='pt')
|
21 |
+
testenc = tokenizer("\n\n".join(testdata['text']), return_tensors='pt')
|
22 |
+
|
23 |
+
import random
|
24 |
+
random.seed(seed)
|
25 |
+
trainloader = []
|
26 |
+
for _ in range(nsamples):
|
27 |
+
i = random.randint(0, trainenc.input_ids.shape[1] - seqlen - 1)
|
28 |
+
j = i + seqlen
|
29 |
+
inp = trainenc.input_ids[:, i:j]
|
30 |
+
tar = inp.clone()
|
31 |
+
tar[:, :-1] = -100
|
32 |
+
trainloader.append((inp, tar))
|
33 |
+
return trainloader, testenc
|
34 |
+
|
35 |
+
|
36 |
+
def get_ptb(nsamples, seed, seqlen, model):
|
37 |
+
from datasets import load_dataset
|
38 |
+
traindata = load_dataset('ptb_text_only', 'penn_treebank', split='train')
|
39 |
+
valdata = load_dataset('ptb_text_only', 'penn_treebank', split='validation')
|
40 |
+
|
41 |
+
from transformers import AutoTokenizer
|
42 |
+
try:
|
43 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=False)
|
44 |
+
except:
|
45 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=True)
|
46 |
+
trainenc = tokenizer("\n\n".join(traindata['sentence']), return_tensors='pt')
|
47 |
+
testenc = tokenizer("\n\n".join(valdata['sentence']), return_tensors='pt')
|
48 |
+
|
49 |
+
import random
|
50 |
+
random.seed(seed)
|
51 |
+
trainloader = []
|
52 |
+
for _ in range(nsamples):
|
53 |
+
i = random.randint(0, trainenc.input_ids.shape[1] - seqlen - 1)
|
54 |
+
j = i + seqlen
|
55 |
+
inp = trainenc.input_ids[:, i:j]
|
56 |
+
tar = inp.clone()
|
57 |
+
tar[:, :-1] = -100
|
58 |
+
trainloader.append((inp, tar))
|
59 |
+
return trainloader, testenc
|
60 |
+
|
61 |
+
|
62 |
+
def get_c4(nsamples, seed, seqlen, model):
|
63 |
+
from datasets import load_dataset
|
64 |
+
traindata = load_dataset('allenai/c4', 'allenai--c4', data_files={'train': 'en/c4-train.00000-of-01024.json.gz'}, split='train', use_auth_token=False)
|
65 |
+
valdata = load_dataset('allenai/c4', 'allenai--c4', data_files={'validation': 'en/c4-validation.00000-of-00008.json.gz'}, split='validation', use_auth_token=False)
|
66 |
+
|
67 |
+
from transformers import AutoTokenizer
|
68 |
+
try:
|
69 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=False)
|
70 |
+
except:
|
71 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=True)
|
72 |
+
|
73 |
+
import random
|
74 |
+
random.seed(seed)
|
75 |
+
trainloader = []
|
76 |
+
for _ in range(nsamples):
|
77 |
+
while True:
|
78 |
+
i = random.randint(0, len(traindata) - 1)
|
79 |
+
trainenc = tokenizer(traindata[i]['text'], return_tensors='pt')
|
80 |
+
if trainenc.input_ids.shape[1] >= seqlen:
|
81 |
+
break
|
82 |
+
i = random.randint(0, trainenc.input_ids.shape[1] - seqlen - 1)
|
83 |
+
j = i + seqlen
|
84 |
+
inp = trainenc.input_ids[:, i:j]
|
85 |
+
tar = inp.clone()
|
86 |
+
tar[:, :-1] = -100
|
87 |
+
trainloader.append((inp, tar))
|
88 |
+
|
89 |
+
import random
|
90 |
+
random.seed(0)
|
91 |
+
valenc = []
|
92 |
+
for _ in range(256):
|
93 |
+
while True:
|
94 |
+
i = random.randint(0, len(valdata) - 1)
|
95 |
+
tmp = tokenizer(valdata[i]['text'], return_tensors='pt')
|
96 |
+
if tmp.input_ids.shape[1] >= seqlen:
|
97 |
+
break
|
98 |
+
i = random.randint(0, tmp.input_ids.shape[1] - seqlen - 1)
|
99 |
+
j = i + seqlen
|
100 |
+
valenc.append(tmp.input_ids[:, i:j])
|
101 |
+
valenc = torch.hstack(valenc)
|
102 |
+
|
103 |
+
class TokenizerWrapper:
|
104 |
+
|
105 |
+
def __init__(self, input_ids):
|
106 |
+
self.input_ids = input_ids
|
107 |
+
|
108 |
+
valenc = TokenizerWrapper(valenc)
|
109 |
+
|
110 |
+
return trainloader, valenc
|
111 |
+
|
112 |
+
|
113 |
+
def get_ptb_new(nsamples, seed, seqlen, model):
|
114 |
+
from datasets import load_dataset
|
115 |
+
traindata = load_dataset('ptb_text_only', 'penn_treebank', split='train')
|
116 |
+
testdata = load_dataset('ptb_text_only', 'penn_treebank', split='test')
|
117 |
+
|
118 |
+
from transformers import AutoTokenizer
|
119 |
+
try:
|
120 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=False)
|
121 |
+
except:
|
122 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=True)
|
123 |
+
trainenc = tokenizer(" ".join(traindata['sentence']), return_tensors='pt')
|
124 |
+
testenc = tokenizer(" ".join(testdata['sentence']), return_tensors='pt')
|
125 |
+
|
126 |
+
import random
|
127 |
+
random.seed(seed)
|
128 |
+
trainloader = []
|
129 |
+
for _ in range(nsamples):
|
130 |
+
i = random.randint(0, trainenc.input_ids.shape[1] - seqlen - 1)
|
131 |
+
j = i + seqlen
|
132 |
+
inp = trainenc.input_ids[:, i:j]
|
133 |
+
tar = inp.clone()
|
134 |
+
tar[:, :-1] = -100
|
135 |
+
trainloader.append((inp, tar))
|
136 |
+
return trainloader, testenc
|
137 |
+
|
138 |
+
|
139 |
+
def get_c4_new(nsamples, seed, seqlen, model):
|
140 |
+
from datasets import load_dataset
|
141 |
+
traindata = load_dataset('allenai/c4', 'allenai--c4', data_files={'train': 'en/c4-train.00000-of-01024.json.gz'}, split='train')
|
142 |
+
valdata = load_dataset('allenai/c4', 'allenai--c4', data_files={'validation': 'en/c4-validation.00000-of-00008.json.gz'}, split='validation')
|
143 |
+
|
144 |
+
from transformers import AutoTokenizer
|
145 |
+
try:
|
146 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=False)
|
147 |
+
except:
|
148 |
+
tokenizer = AutoTokenizer.from_pretrained(model, use_fast=True)
|
149 |
+
|
150 |
+
import random
|
151 |
+
random.seed(seed)
|
152 |
+
trainloader = []
|
153 |
+
for _ in range(nsamples):
|
154 |
+
while True:
|
155 |
+
i = random.randint(0, len(traindata) - 1)
|
156 |
+
trainenc = tokenizer(traindata[i]['text'], return_tensors='pt')
|
157 |
+
if trainenc.input_ids.shape[1] >= seqlen:
|
158 |
+
break
|
159 |
+
i = random.randint(0, trainenc.input_ids.shape[1] - seqlen - 1)
|
160 |
+
j = i + seqlen
|
161 |
+
inp = trainenc.input_ids[:, i:j]
|
162 |
+
tar = inp.clone()
|
163 |
+
tar[:, :-1] = -100
|
164 |
+
trainloader.append((inp, tar))
|
165 |
+
|
166 |
+
valenc = tokenizer(' '.join(valdata[:1100]['text']), return_tensors='pt')
|
167 |
+
valenc = valenc.input_ids[:, :(256 * seqlen)]
|
168 |
+
|
169 |
+
class TokenizerWrapper:
|
170 |
+
|
171 |
+
def __init__(self, input_ids):
|
172 |
+
self.input_ids = input_ids
|
173 |
+
|
174 |
+
valenc = TokenizerWrapper(valenc)
|
175 |
+
|
176 |
+
return trainloader, valenc
|
177 |
+
|
178 |
+
|
179 |
+
def get_loaders(name, nsamples=128, seed=0, seqlen=2048, model=''):
|
180 |
+
if 'wikitext2' in name:
|
181 |
+
return get_wikitext2(nsamples, seed, seqlen, model)
|
182 |
+
if 'ptb' in name:
|
183 |
+
if 'new' in name:
|
184 |
+
return get_ptb_new(nsamples, seed, seqlen, model)
|
185 |
+
return get_ptb(nsamples, seed, seqlen, model)
|
186 |
+
if 'c4' in name:
|
187 |
+
if 'new' in name:
|
188 |
+
return get_c4_new(nsamples, seed, seqlen, model)
|
189 |
+
return get_c4(nsamples, seed, seqlen, model)
|
utils/export.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import toml
|
3 |
+
import os
|
4 |
+
|
5 |
+
|
6 |
+
def export_quant_table(quantizers: dict, quant_dir: str, format: str = 'toml'):
|
7 |
+
|
8 |
+
table = {}
|
9 |
+
|
10 |
+
def save_tensor(name: str, tensor):
|
11 |
+
np.save(os.path.join(quant_dir, name), tensor.numpy())
|
12 |
+
return '{}.npy'.format(name)
|
13 |
+
|
14 |
+
for key, value in quantizers.items():
|
15 |
+
quantizer = value[0]
|
16 |
+
|
17 |
+
dump = dict()
|
18 |
+
|
19 |
+
sym = quantizer.sym
|
20 |
+
if not sym:
|
21 |
+
dump['zero'] = save_tensor(name=key + '.zero', tensor=value[2])
|
22 |
+
dump['scale'] = save_tensor(name=key + '.scale', tensor=value[1])
|
23 |
+
dump['wbits'] = value[4]
|
24 |
+
dump['groupsize'] = value[5]
|
25 |
+
if value[5] > 0:
|
26 |
+
dump['group_ids'] = save_tensor(name=key + '.group_ids', tensor=value[3])
|
27 |
+
|
28 |
+
dump['sym'] = sym
|
29 |
+
dump['perchannel'] = quantizer.perchannel
|
30 |
+
|
31 |
+
table[key] = dump
|
32 |
+
|
33 |
+
if not os.path.exists(quant_dir):
|
34 |
+
os.mkdir(quant_dir)
|
35 |
+
|
36 |
+
with open(os.path.join(quant_dir, 'quant.toml'), 'w') as f:
|
37 |
+
toml.dump(table, f)
|
utils/modelutils.py
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import torch.nn as nn
|
3 |
+
|
4 |
+
DEV = torch.device('cuda:0')
|
5 |
+
|
6 |
+
|
7 |
+
def find_layers(module, layers=[nn.Conv2d, nn.Linear], name=''):
|
8 |
+
if type(module) in layers:
|
9 |
+
return {name: module}
|
10 |
+
res = {}
|
11 |
+
for name1, child in module.named_children():
|
12 |
+
res.update(find_layers(child, layers=layers, name=name + '.' + name1 if name != '' else name1))
|
13 |
+
return res
|
14 |
+
|
15 |
+
|
16 |
+
def gen_conditions(_wbits, _groupsize):
|
17 |
+
wbits = _wbits
|
18 |
+
groupsize = _groupsize
|
19 |
+
conditions = []
|
20 |
+
while True:
|
21 |
+
if wbits >= 8:
|
22 |
+
if groupsize == -1 or groupsize == 32:
|
23 |
+
break
|
24 |
+
|
25 |
+
if groupsize > 32:
|
26 |
+
groupsize /= 2
|
27 |
+
else:
|
28 |
+
wbits *= 2
|
29 |
+
groupsize = _groupsize
|
30 |
+
|
31 |
+
conditions.append((int(wbits), int(groupsize)))
|
32 |
+
return conditions
|
33 |
+
|
34 |
+
|
35 |
+
# copy from https://github.com/openppl-public/ppq/blob/master/ppq/quantization/measure/norm.py
|
36 |
+
def torch_snr_error(y_pred: torch.Tensor, y_real: torch.Tensor, reduction: str = 'mean') -> torch.Tensor:
|
37 |
+
"""
|
38 |
+
Compute SNR between y_pred(tensor) and y_real(tensor)
|
39 |
+
|
40 |
+
SNR can be calcualted as following equation:
|
41 |
+
|
42 |
+
SNR(pred, real) = (pred - real) ^ 2 / (real) ^ 2
|
43 |
+
|
44 |
+
if x and y are matrixs, SNR error over matrix should be the mean value of SNR error over all elements.
|
45 |
+
|
46 |
+
SNR(pred, real) = mean((pred - real) ^ 2 / (real) ^ 2)
|
47 |
+
Args:
|
48 |
+
y_pred (torch.Tensor): _description_
|
49 |
+
y_real (torch.Tensor): _description_
|
50 |
+
reduction (str, optional): _description_. Defaults to 'mean'.
|
51 |
+
Raises:
|
52 |
+
ValueError: _description_
|
53 |
+
ValueError: _description_
|
54 |
+
Returns:
|
55 |
+
torch.Tensor: _description_
|
56 |
+
"""
|
57 |
+
y_pred = y_pred.type(torch.float32)
|
58 |
+
y_real = y_real.type(torch.float32)
|
59 |
+
|
60 |
+
if y_pred.shape != y_real.shape:
|
61 |
+
raise ValueError(f'Can not compute snr loss for tensors with different shape. '
|
62 |
+
f'({y_pred.shape} and {y_real.shape})')
|
63 |
+
reduction = str(reduction).lower()
|
64 |
+
|
65 |
+
if y_pred.ndim == 1:
|
66 |
+
y_pred = y_pred.unsqueeze(0)
|
67 |
+
y_real = y_real.unsqueeze(0)
|
68 |
+
|
69 |
+
y_pred = y_pred.flatten(start_dim=1)
|
70 |
+
y_real = y_real.flatten(start_dim=1)
|
71 |
+
|
72 |
+
noise_power = torch.pow(y_pred - y_real, 2).sum(dim=-1)
|
73 |
+
signal_power = torch.pow(y_real, 2).sum(dim=-1)
|
74 |
+
snr = (noise_power) / (signal_power + 1e-7)
|
75 |
+
|
76 |
+
if reduction == 'mean':
|
77 |
+
return torch.mean(snr)
|
78 |
+
elif reduction == 'sum':
|
79 |
+
return torch.sum(snr)
|
80 |
+
elif reduction == 'none':
|
81 |
+
return snr
|
82 |
+
else:
|
83 |
+
raise ValueError(f'Unsupported reduction method.')
|