test_runner.py 8.03 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
    data_array = []
    name_array = []
64
65
66
67
    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
68
69
70
71
72
73
74
75
76
77
        data_array.append(data)
        if name:
            name_array.append(name)

    if len(name_array) < len(data_array):
        param_map = {}
        for i in range(len(param_names)):
            param_map[param_names[i]] = data_array[i]

        return param_map
78
79
80
81
82

    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
83
84
85
86

    return param_map


87
88
89
90
91
def read_outputs(io_folder, out_names):
    outputs = []
    data_array = []
    name_array = []
    for i in range(len(out_names)):
Shucai Xiao's avatar
Shucai Xiao committed
92
        file_name = io_folder + '/output_' + str(i) + '.pb'
93
        name, data = read_pb_file(file_name)
94
95
96
97
98
99
100
101
102
103
        data_array.append(data)
        if name:
            name_array.append(name)

    if len(name_array) < len(data_array):
        return data_array

    for name in out_names:
        index = name_array.index(name)
        outputs.append(data_array[index])
Shucai Xiao's avatar
Shucai Xiao committed
104
105
106
107

    return outputs


108
109
110
111
112
113
114
115
116
117
118
119
120
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
121

122
123
124
125
126
127
128
129
130
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
131

132
133
def get_input_shapes(sample_case, param_names):
    param_shape_map = {}
134
135
    name_array = []
    shape_array = []
136
137
138
    for i in range(len(param_names)):
        file_name = sample_case + '/input_' + str(i) + '.pb'
        name, data = read_pb_file(file_name)
139
        param_shape_map[name] = data.shape
140
141
142
143
144
145
146
147
148
149
        shape_array.append(data.shape)
        if name:
            name_array.append(name)

    if len(name_array) < len(shape_array):
        param_shape_map = {}
        for i in range(len(param_names)):
            param_shape_map[param_names[i]] = shape_array[i]

        return param_shape_map
150
151
152
153
154
155
156
157
158

    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
159
160
161
162
def run_one_case(model, param_map):
    # convert np array to model argument
    pp = {}
    for key, val in param_map.items():
163
        #print("input: {} = {}".format(key, val))
Shucai Xiao's avatar
Shucai Xiao committed
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
        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):
Shucai Xiao's avatar
Shucai Xiao committed
187
            print("\nOutput {} is incorrect ...".format(i))
Shucai Xiao's avatar
Shucai Xiao committed
188
            print("Expected value: \n{}".format(gold_outputs[i]))
Shucai Xiao's avatar
Shucai Xiao committed
189
190
            print("......")
            print("Actual value: \n{}\n".format(outputs[i]))
Shucai Xiao's avatar
Shucai Xiao committed
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
            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
221
222
223
224
225
226
227
228
229
230
231

    # get param names
    param_names = model_parameter_names(model_path_name)

    # 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)
232
233
    for name, dims in param_shapes.items():
        print("Input: {}, shape: {}".format(name, dims))
234
    print()
235

Shucai Xiao's avatar
Shucai Xiao committed
236
    # read and compile model
237
    model = migraphx.parse_onnx(model_path_name, map_input_dims=param_shapes)
Shucai Xiao's avatar
Shucai Xiao committed
238
239
240
241
242
243
244
245
246
247
    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)
248
        gold_outputs = read_outputs(io_folder, output_names)
Shucai Xiao's avatar
Shucai Xiao committed
249
250
251
252
253
254
255
256
257
258
259

        # 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)
260
261
262
        # 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
263
264

        # check output correctness
265
        ret = check_correctness(gold_outputs, output_data)
Shucai Xiao's avatar
Shucai Xiao committed
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
        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()