mDenseOn-ONNX / scripts /quantize.py
algoprog's picture
mDenseOn exported to ONNX: float32 (exact) and an 8-bit build, with the scripts that made them
dc2a503 verified
Raw History Blame Contribute Delete
2.11 kB
# The 8-bit build: the layers' weights through ONNX Runtime's MatMulNBits (8 bits, blocks of 32, symmetric), and the
# 256k-word table as int8 rows with one float32 scale each, looked up and scaled back with Gather -> Cast -> Mul
# (standard operators). Activations and arithmetic stay float32. Needs ONNX Runtime 1.23+ to run.
# pip install onnx onnxruntime
# python quantize.py onnx/model.onnx onnx/model_q8.onnx
import sys
import numpy as np
import onnx
from onnx import TensorProto, helper, numpy_helper
from onnxruntime.quantization.matmul_nbits_quantizer import DefaultWeightOnlyQuantConfig, MatMulNBitsQuantizer
src, dst = sys.argv[1], sys.argv[2]
m = onnx.load(src)
q = MatMulNBitsQuantizer(m, algo_config=DefaultWeightOnlyQuantConfig(block_size=32, is_symmetric=True, bits=8, op_types_to_quantize=('MatMul',), quant_axes=(('MatMul', 0),)))
q.process()
m = q.model.model
g = m.graph
inits = {i.name: i for i in g.initializer}
node = next(n for n in g.node if n.op_type == 'Gather' and n.input[0] in inits and len(inits[n.input[0]].dims) == 2 and inits[n.input[0]].dims[0] > 100000)
table = numpy_helper.to_array(inits[node.input[0]]).astype(np.float32)
scale = np.maximum(np.abs(table).max(axis=1, keepdims=True), 1e-12) / 127.0
rows = np.clip(np.rint(table / scale), -127, 127).astype(np.int8)
name, ids, out = node.input[0], node.input[1], node.output[0]
g.initializer.remove(inits[name])
g.initializer.extend([numpy_helper.from_array(rows, name + '_int8'), numpy_helper.from_array(scale.astype(np.float32), name + '_scale')])
at = list(g.node).index(node)
g.node.remove(node)
for i, n in enumerate([
helper.make_node('Gather', [name + '_int8', ids], [out + '_q'], axis=0, name='table_gather_int8'),
helper.make_node('Cast', [out + '_q'], [out + '_f'], to=TensorProto.FLOAT, name='table_cast'),
helper.make_node('Gather', [name + '_scale', ids], [out + '_s'], axis=0, name='table_gather_scale'),
helper.make_node('Mul', [out + '_f', out + '_s'], [out], name='table_dequantize'),
]):
g.node.insert(at + i, n)
onnx.checker.check_model(m)
onnx.save(m, dst)
print('saved', dst)