Skip to content

Commit 996245f

Browse files
committed
8.16
1 parent 6f81d2a commit 996245f

39 files changed

+6704
-0
lines changed

docs/deep_dive/mrt.rst

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
2+
***********
3+
MRT summary
4+
***********
5+
6+
.. contents::
7+
8+
Introduce
9+
=========
10+
11+
MRT, short for **Model Representation Tool**, aims to convert floating model into a deterministi
12+
c and non-data-overflow network. MRT links the off-chain AI developer community to the on-chain e
13+
cosystem, from Off-chain deep learning to MRT transformations, and then uploading to Cortex Block
14+
chain for on-chain deterministic inference.
15+
16+
As the above CVM Runtime section points out, the model that goes
17+
under MRT transformation can be accepted by CVM Runtime, which
18+
we called it on-chain model. MRT propose approaches to transform
19+
floating model to on-chain model, mainly include:
20+
21+
- do transformation from floating to full integer with minimum
22+
accuracy drop.
23+
- certify the process data to be non-flow over INT32.
24+
25+
Application
26+
===========
27+
28+
Quantization steps
29+
------------------
30+
31+
The main quantization procedure is:
32+
33+
Model Load >>> Preparation >>> [Optional] Model Split >>>
34+
35+
Calibration >>> Quantization >>> [Optional] Model Merge >>> Compilation to CVM,
36+
37+
The execution steps of main.py include prepare, calibrate, quantize, evaluate, and mrt_compile.
38+
Each step will generate a corresponding intermediate file. You can set the start from that step
39+
ccording to the parameter COMMON.START_AFTER of the configuration file,
40+
and use the corresponding intermediate file.
41+
42+
prepare(calibrate, quantize, evaluate, mrt_compile): According to the COMMON and PREPARE(CALIBRATE, QUANTIZE, EVALUATE, MRT_COMPILE) parameters of the configuration file, load the corresponding
43+
model file, call the corresponding function, and save the file generated by the operation to the
44+
model directory. If the split parameter is not empty,
45+
you need to split the model into top and base after prepare, and merge the models after quantize.
46+
47+
Instructions for use
48+
--------------------
49+
50+
Quantization by executing the following code snippet:
51+
52+
.. code-block::
53+
54+
python main.py config/file/path
55+
56+
The sample configure file is located at ``python/mrt/model_zoo/config.example.ini`` (`config.example.ini <https://github.com/CortexFoundation/cvm-runtime/blob/master/python/mrt/model_zoo/config.example.ini>`_),
57+
and the configure file is located at ``tests/mrt/model_zoo/`` (`model_zoo <https://github.com/CortexFoundation/cvm-runtime/tree/wlt/tests/mrt/model_zoo>`_).
58+
59+
Note
60+
====
61+
62+
Before executing python main.py yaml_file, save the trained model json file and params file to ~/mrt_model/, and the quantized related files are stored in this directory.
63+
About the yaml file, the default value of PREPARE.INPUTSHAPE is [-1, 3, 224, 224], before quantization, you need to set this value to the size of the value input by the model

tests/deprecated/test_V3.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import unittest
2+
import logging
3+
import os
4+
from os import path
5+
import sys
6+
import json
7+
8+
from mrt.utils import log_init
9+
from mrt.V3.execute import run
10+
from mrt.V3.utils import merge_cfg, override_cfg_args, get_logger
11+
from mrt.V3.evaluate import get_evaluation_info
12+
13+
log_init()
14+
yaml_files = set()
15+
results = {}
16+
base_dir = path.join(path.dirname(path.realpath(__file__)), "..", "..")
17+
18+
def _multi_validate(
19+
messages, base_func, data_iter, *comp_funcs,
20+
iter_num=10, logger=logging.getLogger(""), batch_size=16):
21+
log_str = "Iteration: {:3d} | " + base_func.__name__ + ": {} | "
22+
for func in comp_funcs:
23+
log_str += func.__name__ + ": {} | "
24+
log_str += "Total Sample: {:5d}"
25+
total = 0
26+
27+
for i in range(iter_num):
28+
data, label = data_iter()
29+
base_acc = base_func(data, label)
30+
comp_acc = [func(data, label) for func in comp_funcs]
31+
total += batch_size
32+
33+
msg = log_str.format(i, base_acc, *comp_acc, total)
34+
logger.info(msg)
35+
messages.append(msg)
36+
37+
def output_results():
38+
rfile_path = path.join(base_dir, "docs", "mrt", "V3_results.rst")
39+
cur_results = {}
40+
with open(rfile_path, "r") as f:
41+
for line in f:
42+
if not line.startswith("**") or ":" not in line:
43+
continue
44+
_, model_name, result = line.split("**")
45+
result = result[1:]
46+
cur_results[model_name] = result
47+
for model_name, result in results.items():
48+
cur_results[model_name] = result
49+
lines = [
50+
"",
51+
"************************",
52+
"MRT Quantization Results",
53+
"************************",
54+
"",
55+
".. _mrt_quantization_results:",
56+
"",
57+
]
58+
for model_name, result in cur_results.items():
59+
line = "**{0}**:{1}".format(model_name,result)
60+
lines.append(line)
61+
lines.append("")
62+
lines.append("")
63+
lines = [line+"\n" for line in lines]
64+
with open(rfile_path, "w") as f:
65+
f.writelines(lines)
66+
67+
def register_test_case(yaml_file_name):
68+
yaml_dir = path.join(base_dir, "tests", "mrt", "model_zoo")
69+
yaml_file_name_ext = "{}.yaml".format(yaml_file_name)
70+
yaml_file = path.join(yaml_dir, yaml_file_name_ext)
71+
72+
if yaml_file in yaml_files:
73+
raise RuntimeError(
74+
"test case: {} already registered.".format(yaml_file))
75+
yaml_files.add(yaml_file)
76+
77+
def test_func(self):
78+
base_cfg = merge_cfg(yaml_file)
79+
80+
# test preparation, calibration, quantization
81+
argv = [
82+
"--common.run_evaluate", "False",
83+
"--common.run_compile", "False",
84+
]
85+
cfg = override_cfg_args(base_cfg, argv)
86+
run(cfg)
87+
88+
# test evaluation
89+
evalfunc, data_iter_func, quantfunc = get_evaluation_info(
90+
cfg.COMMON, cfg.EVALUATE)
91+
logger = get_logger(cfg.COMMON.VERBOSITY)
92+
messages = []
93+
with self.assertRaises(StopIteration):
94+
_multi_validate(
95+
messages, evalfunc, data_iter_func, quantfunc,
96+
iter_num=cfg.EVALUATE.ITER_NUM, logger=logger,
97+
batch_size=cfg.EVALUATE.BATCH)
98+
results[yaml_file_name] = messages[-1]
99+
output_results()
100+
101+
# test compilation
102+
argv = [
103+
"--common.run_evaluate", "False",
104+
"--common.run_compile", "True",
105+
"--common.start_after", "quantize",
106+
]
107+
cfg = override_cfg_args(base_cfg, argv)
108+
run(cfg)
109+
110+
def wrapper(cls):
111+
func_name = "test_case_{}".format(yaml_file_name)
112+
setattr(cls, func_name, test_func)
113+
return cls
114+
115+
return wrapper
116+
117+
118+
# @register_test_case("alexnet")
119+
# @register_test_case("densenet161")
120+
# @register_test_case("mobilenet1_0")
121+
# @register_test_case("mobilenetv2_1.0")
122+
# @register_test_case("resnet18_v1")
123+
# @register_test_case("resnet18_v1b_0.89")
124+
# @register_test_case("resnet50_v1")
125+
# @register_test_case("resnet50_v2")
126+
# @register_test_case("shufflenet_v1")
127+
# @register_test_case("squeezenet1.0")
128+
# @register_test_case("tf_inception_v3")
129+
# @register_test_case("vgg19")
130+
# @register_test_case("cifar_resnet20_v1")
131+
# @register_test_case("mnist")
132+
# @register_test_case("qd10_resnetv1_20")
133+
# @register_test_case("quickdraw")
134+
# @register_test_case("ssd")
135+
# @register_test_case("ssd_512_mobilenet1.0_voc")
136+
# @register_test_case("trec")
137+
# @register_test_case("yolo3_darknet53_voc")
138+
# @register_test_case("yolo3_mobilenet1.0_voc")
139+
class TestV3(unittest.TestCase):
140+
pass
141+
142+
if __name__ == "__main__":
143+
unittest.main()

tests/deprecated/test_alexnet.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import gluon_zoo as gz
2+
import mxnet as mx
3+
from mxnet import ndarray as nd
4+
from mxnet import gluon
5+
6+
import sym_pass as spass
7+
import dataset as ds
8+
import sym_calib as calib
9+
import sim_quant_helper as sim
10+
import utils
11+
import mrt as _mrt
12+
13+
gz.save_model("alexnet")
14+
15+
16+
def load_fname(version, suffix=None, with_ext=False):
17+
suffix = "."+suffix if suffix is not None else ""
18+
prefix = "./data/alexnet%s%s" % (version, suffix)
19+
return utils.extend_fname(prefix, with_ext=with_ext)
20+
21+
batch_size = 700
22+
input_size = 224
23+
inputs_ext = { 'data': {
24+
'shape': (batch_size, 3, input_size, input_size)
25+
}}
26+
inputs = [mx.sym.var(n) for n in inputs_ext]
27+
# ctx = mx.gpu(2)
28+
ctx = [mx.gpu(int(i)) for i in "1,2,3,4,5,6,7".split(',') if i.strip()]
29+
30+
utils.log_init()
31+
32+
data_iter = ds.load_imagenet_rec(batch_size, input_size)
33+
def data_iter_func():
34+
data = data_iter.next()
35+
return data.data[0], data.label[0]
36+
data, _ = data_iter_func()
37+
38+
sym_file, param_file = load_fname("")
39+
net1 = utils.load_model(sym_file, param_file, inputs, ctx=ctx)
40+
acc_top1 = mx.metric.Accuracy()
41+
acc_top5 = mx.metric.TopKAccuracy(5)
42+
acc_top1.reset()
43+
acc_top5.reset()
44+
def alexnet(data, label):
45+
data = gluon.utils.split_and_load(data, ctx_list=ctx, batch_axis=0, even_split=False)
46+
res = [net1.forward(d) for d in data]
47+
res = nd.concatenate(res)
48+
acc_top1.update(label, res)
49+
_, top1 = acc_top1.get()
50+
acc_top5.update(label, res)
51+
_, top5 = acc_top5.get()
52+
return "top1={:6.2%} top5={:6.2%}".format(top1, top5)
53+
54+
# sym, params = mx.sym.load(sym_file), nd.load(param_file)
55+
# sym, params = spass.sym_quant_prepare(sym, params, inputs_ext)
56+
# qsym, qparams, precs, _ = calib.sym_simulate(sym, params, inputs_ext, data, ctx)
57+
# qsym, qparams = calib.sym_realize(qsym, qparams, inputs_ext, precs, "cvm")
58+
# dump_sym, dump_params, dump_ext = load_fname("", "sym.quantize", True)
59+
# sim.save_ext(dump_ext, inputs_ext)
60+
# nd.save(dump_params, qparams)
61+
# open(dump_sym, "w").write(qsym.tojson())
62+
63+
dump_sym, dump_params, dump_ext = load_fname("", "sym.quantize", True)
64+
sym, params = mx.sym.load(dump_sym), nd.load(dump_params)
65+
(inputs_ext,) = sim.load_ext(dump_ext)
66+
if True:
67+
_mrt.std_dump(sym, params, inputs_ext, data, "alexnet",
68+
is_mxnet=True)
69+
exit()
70+
inputs = [mx.sym.var(n) for n in inputs_ext]
71+
net2 = utils.load_model(dump_sym, dump_params, inputs, ctx=ctx)
72+
qacc_top1 = mx.metric.Accuracy()
73+
qacc_top5 = mx.metric.TopKAccuracy(5)
74+
qacc_top1.reset()
75+
qacc_top5.reset()
76+
def cvm_quantize(data, label):
77+
data = sim.load_real_data(data, 'data', inputs_ext)
78+
data = gluon.utils.split_and_load(data, ctx_list=ctx, batch_axis=0, even_split=False)
79+
res = [net2.forward(d) for d in data]
80+
res = nd.concatenate(res)
81+
qacc_top1.update(label, res)
82+
_, top1 = qacc_top1.get()
83+
qacc_top5.update(label, res)
84+
_, top5 = qacc_top5.get()
85+
return "top1={:6.2%} top5={:6.2%}".format(top1, top5)
86+
87+
utils.multi_validate(alexnet, data_iter_func,
88+
cvm_quantize,
89+
iter_num=1000000)
90+
# utils.multi_eval_accuracy(alexnet, data_iter_func,
91+
# cvm_quantize,
92+
# iter_num=10000)

tests/deprecated/test_byr.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import transformer as tfm
2+
3+
import sym_pass as spass
4+
import sym_utils as sutils
5+
from sym_utils import topo_visit_transformer
6+
import mxnet as mx
7+
import nnvm
8+
import numpy as np
9+
from ut_base import *
10+
11+
class TestFuseMultiplyInputs(TfmTest):
12+
def test_fmi(self):
13+
d1 = mx.sym.var('d1', shape=(2, 3))
14+
d2 = mx.sym.var('d2', shape=(2, 4))
15+
d3 = mx.sym.var('d3', shape=(2, 3))
16+
op = mx.sym.concat(d1, d2, d3)
17+
sym = transfer_multiple_inputs(op, {})
18+
19+
data = mx.sym.var('data', shape=(20,))
20+
s1 = mx.sym.slice(data, begin=(0,), end=(6,))
21+
r1 = mx.sym.reshape(s1, shape=(2, 3))
22+
s2 = mx.sym.slice(data, begin=(6,), end=(14,))
23+
r2 = mx.sym.reshape(s2, shape=(2, 4))
24+
s3 = mx.sym.slice(data, begin=(14,), end=(20,))
25+
r3 = mx.sym.reshape(s3, shape=(2, 3))
26+
des = mx.sym.concat(r1, r2, r3)
27+
28+
self._assert_equal(sym, des)
29+
30+
@tfm.N.register_nm("fmi")
31+
def transfer_multiple_inputs(sym, params):
32+
infer_shapes = tfm.infer_shape(sym, params)
33+
dim_sum, dim_per, dims = 0, {}, {}
34+
def _sum_input(node, params, **kwargs):
35+
name = node.attr('name')
36+
nonlocal dim_sum, dim_per, dims
37+
if sutils.is_inputs(node, params):
38+
dims[name] = infer_shapes[name][0]
39+
dot = np.product(dims[name])
40+
dim_per[name] = dot
41+
dim_sum += dot
42+
topo_visit_transformer(sym, params, _sum_input)
43+
data_sum = mx.sym.var('data', shape=(dim_sum,))
44+
first, last = 0, 0
45+
def _change_node(op, params, graph, **kwargs):
46+
name = op.attr('name')
47+
if sutils.is_inputs(op, params):
48+
nonlocal first, last
49+
last = first + dim_per[name]
50+
op = mx.sym.slice(data_sum, name=tfm.N.n('slice'),
51+
begin=(first,), end=(last,))
52+
op = mx.sym.reshape(op, name=tfm.N.n('reshape'),
53+
shape=dims[name])
54+
first = last
55+
return op
56+
sym, params = topo_visit_transformer(sym, params, _change_node)
57+
return sym
58+

tests/deprecated/test_check_graph.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import mxnet as mx
2+
import sym_utils as sutils
3+
import sym_pass as spass
4+
import logging
5+
import utils
6+
import json
7+
from mxnet import ndarray as nd
8+
9+
version = "v3"
10+
11+
def load_fname(version, suffix=None, with_ext=False):
12+
suffix = "."+suffix if suffix is not None else ""
13+
fname = "./data/tf_inception%s%s"%(version, suffix)
14+
return utils.extend_fname(fname, with_ext)
15+
16+
17+
utils.log_init()
18+
logger = logging.getLogger("log.test.check_graph")
19+
sym, prm = load_fname(version)
20+
symbol, params = mx.sym.load(sym), nd.load(prm)
21+
22+
23+
symbol, params = sutils.check_graph(symbol, params, logger)
24+
symbol, params = spass.fuse_transpose(symbol, params, logger)
25+
fsym, _ = load_fname("vt2")
26+
with open(fsym, "w") as f:
27+
f.write(symbol.tojson())

0 commit comments

Comments
 (0)