-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathquantize.py
More file actions
73 lines (56 loc) · 2.36 KB
/
Copy pathquantize.py
File metadata and controls
73 lines (56 loc) · 2.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import sys
import torch
import copy
import math
import random as rand
import time
import csv
class Quantizer(object):
def __init__(self, roundMeth):
self.roundMeth = roundMeth
def log(self, line):
with open('quant.csv', 'a') as csvfile:
writer = csv.writer(csvfile, delimiter=',')
writer.writerow(line)
def quantize_inputs(self, inputs, bitWidth, loc=None):
if isinstance(inputs, torch.Tensor):
tmp = inputs.clone()
else:
raise TypeError
scaleMat, scaleFac = self.scale(tmp, bitWidth)
scaleMat.mul_(pow(2, -scaleFac))
return scaleMat, scaleFac
def scale(self, scaled, bitWidth):
if ((torch.max(scaled) == 0) and (torch.min(scaled) == 0)):
return scaled.round(), 0
val = 1 << (bitWidth-1)
maxVal = (val - 1) + 0.5
minVal = (-val) - 0.5
# check if values are outside representable range (minVal -> maxVal)
if (torch.max(scaled).item() == float("inf") or torch.min(scaled).item() == float("-inf") or 0):
raise ValueError
if self.roundMeth == 'Simple':
scaled, sf = self.simpleRound(scaled, maxVal, minVal)
elif self.roundMeth == 'Stochastic':
scaled, sf = self.stochRound(scaled, maxVal, minVal)
else:
raise ValueError("Rounding method should be one of 'Simple' or 'Stochastic'")
return scaled, sf
def findSfAndScale(self, scaled, maxVal, minVal):
rangeBest = min(abs(maxVal/torch.max(scaled)), abs(minVal/torch.min(scaled)))
# floor returns int value closest to zero
# on the way up, dont want to over estimate
# on they way down, dont want to underestimate
sf = math.floor(math.log2(rangeBest))
scaled.mul_(pow(2, sf))
return scaled, sf
def stochRound(self, scaled, maxVal, minVal):
scaled, sf = self.findSfAndScale(scaled, maxVal, minVal)
# add values in rand -0.5 -> 0.5 to potentially tip rounding in a certain direction
mod = torch.FloatTensor(scaled.size()).cuda(scaled.device)
mod.uniform_(-0.5, 0.5)
scaled.add_(mod)
return scaled.round(), sf
def simpleRound(self, scaled, maxVal, minVal):
scaled, sf = self.findSfAndScale(scaled, maxVal, minVal)
return scaled.round(), sf