test_runner.py 7.12 KB
Newer Older
1
import os, sys
Shucai Xiao's avatar
Shucai Xiao committed
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
import numpy as np
import argparse
import onnx
from onnx import numpy_helper
import migraphx


def parse_args():
    parser = argparse.ArgumentParser(description="MIGraphX test runner")
    parser.add_argument('test_dir',
                        type=str,
                        metavar='test_loc',
                        help='folder where the test is stored')
    parser.add_argument('--target',
                        type=str,
                        default='gpu',
                        help='Specify where the tests execute (ref, gpu)')
    args = parser.parse_args()

    return args


def get_sub_folders(dir_name):
    dir_contents = os.listdir(dir_name)
    folders = []
    for item in dir_contents:
        tmp_item = dir_name + '/' + item
        if os.path.isdir(tmp_item):
            folders.append(item)
    folders.sort()

    return folders


def get_test_cases(dir_name):
    return get_sub_folders(dir_name)


def get_model_name(dir_name):
    dir_contents = os.listdir(dir_name)
    for item in dir_contents:
        file_name = dir_name + '/' + item
        if os.path.isfile(file_name) and file_name.endswith('.onnx'):
            return item

    return ''


def read_pb_file(filename):
    with open(filename, 'rb') as pfile:
        data_str = pfile.read()
        tensor = onnx.TensorProto()
        tensor.ParseFromString(data_str)
        np_array = numpy_helper.to_array(tensor)

57
    return tensor.name, np_array
Shucai Xiao's avatar
Shucai Xiao committed
58
59


60
def wrapup_inputs(io_folder, param_names):
Shucai Xiao's avatar
Shucai Xiao committed
61
    param_map = {}
62
63
64
65
66
67
68
69
70
    for i in range(len(param_names)):
        file_name = io_folder + '/input_' + str(i) + '.pb'
        name, data = read_pb_file(file_name)
        param_map[name] = data

    for name in param_names:
        if not name in param_map.keys():
            print("Input {} does not exist!".format(name))
            sys.exit()
Shucai Xiao's avatar
Shucai Xiao committed
71
72
73
74
75

    return param_map


def read_outputs(io_folder, out_num):
76
    outputs = {}
Shucai Xiao's avatar
Shucai Xiao committed
77
78
    for i in range(out_num):
        file_name = io_folder + '/output_' + str(i) + '.pb'
79
80
        name, data = read_pb_file(file_name)
        outputs[name] = data
Shucai Xiao's avatar
Shucai Xiao committed
81
82
83
84

    return outputs


85
86
87
88
89
90
91
92
93
94
95
96
97
def model_parameter_names(model_file_name):
    with open(model_file_name, 'rb') as pfile:
        data_str = pfile.read()
        model_proto = onnx.ModelProto()
        model_proto.ParseFromString(data_str)
        init_names = set([(i.name) for i in model_proto.graph.initializer])
        param_names = []
        for input in model_proto.graph.input:
            if input.name not in init_names:
                param_names.append(input.name)

        return param_names

Shucai Xiao's avatar
Shucai Xiao committed
98

99
100
101
102
103
104
105
106
107
def model_output_names(model_file_name):
    with open(model_file_name, 'rb') as pfile:
        data_str = pfile.read()
        model_proto = onnx.ModelProto()
        model_proto.ParseFromString(data_str)
        output_names = [out.name for out in model_proto.graph.output]

        return output_names

Shucai Xiao's avatar
Shucai Xiao committed
108

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def get_input_shapes(sample_case, param_names):
    param_shape_map = {}
    for i in range(len(param_names)):
        file_name = sample_case + '/input_' + str(i) + '.pb'
        name, data = read_pb_file(file_name)
        param_shape_map[name] = list(data.shape)
        print("{}: {}".format(name, data.shape))

    for name in param_names:
        if not name in param_shape_map.keys():
            print("Input {} does not exist!".format(name))
            sys.exit()

    return param_shape_map


Shucai Xiao's avatar
Shucai Xiao committed
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
def run_one_case(model, param_map):
    # convert np array to model argument
    pp = {}
    for key, val in param_map.items():
        print("input = {}".format(val))
        pp[key] = migraphx.argument(val)

    # run the model
    model_outputs = model.run(param_map)

    # convert argument to np array
    outputs = []
    for output in model_outputs:
        outputs.append(np.array(output))

    return outputs


def check_correctness(gold_outputs, outputs, rtol=1e-3, atol=1e-3):
    if len(gold_outputs) != len(outputs):
        print("Number of outputs {} is not equal to expected number {}".format(
            len(outputs), len(gold_outputs)))
        return False

    out_num = len(gold_outputs)
    ret = True
    for i in range(out_num):
        if not np.allclose(gold_outputs[i], outputs[i], rtol, atol):
            print("Output {} is incorrect ...".format(i))
            print("Expected value: \n{}".format(gold_outputs[i]))
            print("Actual value: \n{}".format(outputs[i]))
            ret = False

    return ret


def tune_input_shape(model, input_data):
    param_shapes = model.get_parameter_shapes()
    input_shapes = {}
    for name, s in param_shapes.items():
        assert name in input_data
        data_shape = list(input_data[name].shape)
        if not np.array_equal(data_shape, s.lens()):
            input_shapes[name] = data_shape

    return input_shapes


def main():
    args = parse_args()
    test_loc = args.test_dir
    target = args.target

    test_name = os.path.basename(os.path.normpath(test_loc))

    print("Running test \"{}\" on target \"{}\" ...\n".format(
        test_name, target))

    # get model full path
    model_name = get_model_name(test_loc)
    model_path_name = test_loc + '/' + model_name
186
187
188
189
190
191
192
193
194
195
196
197
198

    # get param names
    param_names = model_parameter_names(model_path_name)
    print("param_name = {}".format(param_names))

    # get output names
    output_names = model_output_names(model_path_name)

    # get test cases
    cases = get_test_cases(test_loc)
    sample_case = test_loc + '/' + cases[0]
    param_shapes = get_input_shapes(sample_case, param_names)

Shucai Xiao's avatar
Shucai Xiao committed
199
    # read and compile model
200
201
    model = migraphx.parse_onnx(model_path_name, map_input_dims=param_shapes)
    # param_names = model.get_parameter_names()
Shucai Xiao's avatar
Shucai Xiao committed
202
203
204
205
206
207
208
209
210
211
    output_shapes = model.get_output_shapes()

    model.compile(migraphx.get_target(target))

    # get test cases
    case_num = len(cases)
    correct_num = 0
    for case_name in cases:
        io_folder = test_loc + '/' + case_name
        input_data = wrapup_inputs(io_folder, param_names)
212
        gold_outputs = read_outputs(io_folder, len(output_shapes))
Shucai Xiao's avatar
Shucai Xiao committed
213
214
215
216
217
218
219
220
221
222
223

        # if input shape is different from model shape, reload and recompile
        # model
        input_shapes = tune_input_shape(model, input_data)
        if not len(input_shapes) == 0:
            model = migraphx.parse_onnx(model_path_name,
                                        map_input_dims=input_shapes)
            model.compile(migraphx.get_target(target))

        # run the model and return outputs
        output_data = run_one_case(model, input_data)
224
225
226
        gold_output_data = []
        for i in range(len((output_data))):
            gold_output_data.append(gold_outputs[output_names[i]])
Shucai Xiao's avatar
Shucai Xiao committed
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

        # check output correctness
        ret = check_correctness(gold_output_data, output_data)
        if ret:
            correct_num += 1

        output_str = "PASSED" if ret else "FAILED"
        print("\tCase {}: {}".format(case_name, output_str))

    print("\nTest \"{}\" has {} cases:".format(test_name, case_num))
    print("\t Passed: {}".format(correct_num))
    print("\t Failed: {}".format(case_num - correct_num))
    if case_num > correct_num:
        error_num = case_num - correct_num
        raise ValueError(str(error_num) + " cases failed!")


if __name__ == "__main__":
    main()