main.cpp 13.1 KB
Newer Older
Paul's avatar
Paul committed
1
2
#include "argument_parser.hpp"
#include "command.hpp"
Paul's avatar
Paul committed
3
#include "verify.hpp"
Paul's avatar
Paul committed
4
#include "perf.hpp"
5
#include "models.hpp"
Paul's avatar
Paul committed
6

Paul's avatar
Paul committed
7
8
9
#include <migraphx/tf.hpp>
#include <migraphx/onnx.hpp>
#include <migraphx/stringutils.hpp>
10
11
#include <migraphx/load_save.hpp>
#include <migraphx/json.hpp>
Paul's avatar
Paul committed
12

13
14
15
#include <migraphx/dead_code_elimination.hpp>
#include <migraphx/eliminate_identity.hpp>
#include <migraphx/eliminate_pad.hpp>
16
17
#include <migraphx/generate.hpp>
#include <migraphx/pass_manager.hpp>
18
#include <migraphx/propagate_constant.hpp>
19
#include <migraphx/quantization.hpp>
20
#include <migraphx/register_op.hpp>
21
#include <migraphx/rewrite_batchnorm.hpp>
22
23
24
#include <migraphx/simplify_algebra.hpp>
#include <migraphx/simplify_reshapes.hpp>

25
26
#include <fstream>

Paul's avatar
Paul committed
27
28
29
30
31
32
namespace migraphx {
namespace driver {
inline namespace MIGRAPHX_INLINE_NS {

struct loader
{
33
    std::string model;
Paul's avatar
Paul committed
34
    std::string file;
Paul's avatar
Paul committed
35
    std::string file_type;
36
37
38
39
40
    unsigned batch              = 1;
    bool is_nhwc                = true;
    unsigned trim               = 0;
    bool optimize               = false;
    bool skip_unknown_operators = false;
41
42
43
    bool brief                  = false;
    std::string output_type;
    std::string output;
Paul's avatar
Paul committed
44
45
46

    void parse(argument_parser& ap)
    {
Paul's avatar
Paul committed
47
        ap(file, {}, ap.metavar("<input file>"));
48
        ap(model, {"--model"}, ap.help("Load model"), ap.type("resnet50|inceptionv3|alexnet"));
Paul's avatar
Paul committed
49
50
        ap(file_type, {"--onnx"}, ap.help("Load as onnx"), ap.set_value("onnx"));
        ap(file_type, {"--tf"}, ap.help("Load as tensorflow"), ap.set_value("tf"));
51
52
        ap(file_type, {"--migraphx"}, ap.help("Load as MIGraphX"), ap.set_value("migraphx"));
        ap(file_type, {"--migraphx-json"}, ap.help("Load as MIGraphX JSON"), ap.set_value("json"));
53
        ap(batch, {"--batch"}, ap.help("Set batch size for model"));
Paul's avatar
Paul committed
54
        ap(is_nhwc, {"--nhwc"}, ap.help("Treat tensorflow format as nhwc"), ap.set_value(true));
55
56
57
58
        ap(skip_unknown_operators,
           {"--skip-unknown-operators"},
           ap.help("Skip unknown operators when parsing and continue to parse."),
           ap.set_value(true));
Paul's avatar
Paul committed
59
        ap(is_nhwc, {"--nchw"}, ap.help("Treat tensorflow format as nchw"), ap.set_value(false));
Paul's avatar
Paul committed
60
        ap(trim, {"--trim", "-t"}, ap.help("Trim instructions from the end"));
61
        ap(optimize, {"--optimize", "-O"}, ap.help("Optimize when reading"), ap.set_value(true));
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
        ap(output_type,
           {"--graphviz", "-g"},
           ap.help("Print out a graphviz representation."),
           ap.set_value("graphviz"));
        ap(brief, {"--brief"}, ap.help("Make the output brief."), ap.set_value(true));
        ap(output_type,
           {"--cpp"},
           ap.help("Print out the program as cpp program."),
           ap.set_value("cpp"));
        ap(output_type, {"--json"}, ap.help("Print out program as json."), ap.set_value("json"));
        ap(output_type,
           {"--text"},
           ap.help("Print out program in text format."),
           ap.set_value("text"));
        ap(output_type,
           {"--binary"},
           ap.help("Print out program in binary format."),
           ap.set_value("binary"));
        ap(output, {"--output", "-o"}, ap.help("Output to file."));
Paul's avatar
Paul committed
81
82
    }

Paul's avatar
Paul committed
83
    program load()
Paul's avatar
Paul committed
84
85
    {
        program p;
86
        if(model.empty())
Paul's avatar
Paul committed
87
        {
88
89
90
91
92
93
            if(file_type.empty())
            {
                if(ends_with(file, ".onnx"))
                    file_type = "onnx";
                else if(ends_with(file, ".pb"))
                    file_type = "tf";
94
95
96
97
                else if(ends_with(file, ".json"))
                    file_type = "json";
                else
                    file_type = "migraphx";
98
99
100
            }
            std::cout << "Reading: " << file << std::endl;
            if(file_type == "onnx")
101
102
103
104
105
106
107
            {
                onnx_options options;
                options.default_dim_value      = batch;
                options.skip_unknown_operators = skip_unknown_operators;
                options.print_program_on_error = true;
                p                              = parse_onnx(file, options);
            }
108
            else if(file_type == "tf")
109
            {
110
                p = parse_tf(file, tf_options{is_nhwc, batch});
111
            }
112
113
114
115
116
117
118
119
120
121
            else if(file_type == "json")
            {
                file_options options;
                options.format = "json";
                p              = migraphx::load(file, options);
            }
            else if(file_type == "migraphx")
            {
                p = migraphx::load(file);
            }
122
123
124
125
126
127
128
129
130
131
132
        }
        else
        {
            if(model == "resnet50")
                p = resnet50(batch);
            else if(model == "inceptionv3")
                p = inceptionv3(batch);
            else if(model == "alexnet")
                p = alexnet(batch);
            else
                MIGRAPHX_THROW("Unknown model: " + model);
Paul's avatar
Paul committed
133
        }
Paul's avatar
Paul committed
134
        if(trim > 0)
Paul's avatar
Paul committed
135
        {
Paul's avatar
Paul committed
136
            auto last = std::prev(p.end(), trim);
Paul's avatar
Paul committed
137
138
            p.remove_instructions(last, p.end());
        }
Paul's avatar
Paul committed
139
140
141
        if(optimize)
            migraphx::run_passes(p,
                                 {
142
                                     migraphx::rewrite_batchnorm{},
Paul's avatar
Paul committed
143
144
145
146
147
148
149
150
151
152
153
                                     migraphx::eliminate_identity{},
                                     migraphx::dead_code_elimination{},
                                     migraphx::simplify_algebra{},
                                     migraphx::dead_code_elimination{},
                                     migraphx::simplify_reshapes{},
                                     migraphx::dead_code_elimination{},
                                     migraphx::propagate_constant{},
                                     migraphx::dead_code_elimination{},
                                     migraphx::eliminate_pad{},
                                     migraphx::dead_code_elimination{},
                                 });
Paul's avatar
Paul committed
154
155
        return p;
    }
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
186
187
188
189
190
191

    static void write(std::ostream& os, const std::vector<char>& buffer)
    {
        os.write(buffer.data(), buffer.size());
    }

    void save(const program& p)
    {
        auto* os = &std::cout;
        std::ofstream fs;
        if(not output.empty())
        {
            fs.open(output);
            os = &fs;
        }

        std::string type = output_type;
        if(type.empty())
        {
            if(output.empty())
                type = "text";
            else
                type = "binary";
        }

        if(type == "cpp")
            p.print_cpp(*os);
        else if(type == "graphviz")
            p.print_graph(*os, brief);
        else if(type == "text")
            *os << p << std::endl;
        else if(type == "json")
            *os << to_json_string(p.to_value()) << std::endl;
        else if(type == "binary")
            write(*os, save_buffer(p));
    }
Paul's avatar
Paul committed
192
193
};

194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
struct program_params
{
    std::vector<std::string> fill0{};
    std::vector<std::string> fill1{};
    void parse(argument_parser& ap)
    {
        ap(fill0, {"--fill0"}, ap.help("Fill parameter with 0s"), ap.append());
        ap(fill1, {"--fill1"}, ap.help("Fill parameter with 1s"), ap.append());
    }

    auto generate(const program& p, bool use_gpu)
    {
        program::parameter_map m;
        for(auto&& s : fill0)
            m[s] = fill_argument(p.get_parameter_shape(s), 0);
        for(auto&& s : fill1)
            m[s] = fill_argument(p.get_parameter_shape(s), 1);
        fill_param_map(m, p, use_gpu);
        return m;
    }
};

Paul's avatar
Paul committed
216
217
struct compiler
{
218
219
    static const int q_fp16 = 1;
    static const int q_int8 = 2;
Paul's avatar
Paul committed
220
    loader l;
221
    program_params parameters;
222
223
224
    bool gpu          = true;
    bool offload_copy = false;
    int quantize      = 0;
225

kahmed10's avatar
kahmed10 committed
226
    std::vector<std::string> fill0;
Paul's avatar
Paul committed
227
    std::vector<std::string> fill1;
Paul's avatar
Paul committed
228
229
    void parse(argument_parser& ap)
    {
Paul's avatar
Paul committed
230
        l.parse(ap);
231
        parameters.parse(ap);
Paul's avatar
Paul committed
232
233
        ap(gpu, {"--gpu"}, ap.help("Compile on the gpu"), ap.set_value(true));
        ap(gpu, {"--cpu"}, ap.help("Compile on the cpu"), ap.set_value(false));
234
235
236
        ap(offload_copy,
           {"--enable-offload-copy"},
           ap.help("Enable implicit offload copying"),
237
           ap.set_value(true));
238
239
        ap(quantize, {"--fp16"}, ap.help("Quantize for fp16"), ap.set_value(q_fp16));
        ap(quantize, {"--int8"}, ap.help("Quantize for int8"), ap.set_value(q_int8));
Paul's avatar
Paul committed
240
241
    }

242
    auto params(const program& p, bool use_gpu = true)
Paul's avatar
Paul committed
243
    {
244
        return parameters.generate(p, use_gpu && gpu && !offload_copy);
Paul's avatar
Paul committed
245
    }
246
247
248
249

    program compile()
    {
        auto p = l.load();
250
251
252
        // Dont compile if its already been compiled
        if(p.is_compiled())
            return p;
253
254
255
256
257
258
259
260
261
        auto t = get_target(gpu);
        if(quantize == q_fp16)
        {
            quantize_fp16(p);
        }
        else if(quantize == q_int8)
        {
            quantize_int8(p, t, {params(p, false)});
        }
262
263
264
        compile_options options;
        options.offload_copy = offload_copy;
        p.compile(t, options);
265
        l.save(p);
266
267
        return p;
    }
Paul's avatar
Paul committed
268
269
};

Paul's avatar
Paul committed
270
271
272
struct read : command<read>
{
    loader l;
273
    void parse(argument_parser& ap) { l.parse(ap); }
Paul's avatar
Paul committed
274
275
276
277

    void run()
    {
        auto p = l.load();
278
        l.save(p);
Paul's avatar
Paul committed
279
280
281
    }
};

Paul's avatar
Paul committed
282
283
284
285
286
287
288
289
struct params : command<params>
{
    loader l;
    void parse(argument_parser& ap) { l.parse(ap); }

    void run()
    {
        auto p = l.load();
Paul's avatar
Paul committed
290
        for(auto&& param : p.get_parameter_shapes())
Paul's avatar
Paul committed
291
292
293
294
            std::cout << param.first << ": " << param.second << std::endl;
    }
};

Paul's avatar
Paul committed
295
296
297
struct verify : command<verify>
{
    loader l;
298
    program_params parameters;
Paul's avatar
Paul committed
299
    double tolerance     = 80;
Paul's avatar
Paul committed
300
    bool per_instruction = false;
Paul's avatar
Paul committed
301
    bool reduce          = false;
302
    bool offload_copy    = false;
Paul's avatar
Paul committed
303
304
    void parse(argument_parser& ap)
    {
Paul's avatar
Paul committed
305
        l.parse(ap);
306
        parameters.parse(ap);
307
308
309
310
        ap(offload_copy,
           {"--enable-offload-copy"},
           ap.help("Enable implicit offload copying"),
           ap.set_value(true));
Paul's avatar
Paul committed
311
312
        ap(tolerance, {"--tolerance"}, ap.help("Tolerance for errors"));
        ap(per_instruction,
Paul's avatar
Paul committed
313
314
315
316
           {"-i", "--per-instruction"},
           ap.help("Verify each instruction"),
           ap.set_value(true));
        ap(reduce, {"-r", "--reduce"}, ap.help("Reduce program and verify"), ap.set_value(true));
Paul's avatar
Paul committed
317
318
319
320
321
    }

    void run()
    {
        auto p = l.load();
322
        l.save(p);
Paul's avatar
Paul committed
323
324
        std::cout << p << std::endl;

325
326
327
        compile_options options;
        options.offload_copy = offload_copy;

328
329
        auto m = parameters.generate(p, false);

Paul's avatar
Paul committed
330
331
        if(per_instruction)
        {
332
            verify_instructions(p, options, tolerance);
Paul's avatar
Paul committed
333
334
335
        }
        else if(reduce)
        {
336
            verify_reduced_program(p, options, m, tolerance);
Paul's avatar
Paul committed
337
338
339
        }
        else
        {
340
            verify_program(l.file, p, options, m, tolerance);
Paul's avatar
Paul committed
341
342
343
344
        }
    }
};

Paul's avatar
Paul committed
345
346
347
struct compile : command<compile>
{
    compiler c;
Paul's avatar
Paul committed
348
    void parse(argument_parser& ap) { c.parse(ap); }
Paul's avatar
Paul committed
349
350
351
352

    void run()
    {
        std::cout << "Compiling ... " << std::endl;
353
        c.compile();
Paul's avatar
Paul committed
354
355
356
357
358
359
    }
};

struct run_cmd : command<run_cmd>
{
    compiler c;
Paul's avatar
Paul committed
360
    void parse(argument_parser& ap) { c.parse(ap); }
Paul's avatar
Paul committed
361
362
363
364
365
366
367

    void run()
    {
        std::cout << "Compiling ... " << std::endl;
        auto p = c.compile();
        std::cout << "Allocating params ... " << std::endl;
        auto m = c.params(p);
Paul's avatar
Paul committed
368
        p.eval(m);
Paul's avatar
Paul committed
369
370
371
372
        std::cout << p << std::endl;
    }
};

Paul's avatar
Paul committed
373
374
375
376
struct perf : command<perf>
{
    compiler c;
    unsigned n = 100;
Paul's avatar
Paul committed
377
378
    void parse(argument_parser& ap)
    {
Paul's avatar
Paul committed
379
380
381
382
383
384
385
386
387
388
389
390
391
        c.parse(ap);
        ap(n, {"--iterations", "-n"}, ap.help("Number of iterations to run for perf report"));
    }

    void run()
    {
        std::cout << "Compiling ... " << std::endl;
        auto p = c.compile();
        std::cout << "Allocating params ... " << std::endl;
        auto m = c.params(p);
        std::cout << "Running performance report ... " << std::endl;
        p.perf_report(std::cout, n, m);
    }
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
};

struct op : command<op>
{
    bool show_ops = false;
    void parse(argument_parser& ap)
    {
        ap(show_ops,
           {"--list", "-l"},
           ap.help("List all the operators of MIGraphX"),
           ap.set_value(true));
    }
    void run() const
    {
        if(show_ops)
        {
            for(const auto& name : get_operators())
                std::cout << name << std::endl;
        }
    }
Paul's avatar
Paul committed
412
413
};

Paul's avatar
Paul committed
414
415
416
417
418
struct main_command
{
    static std::string get_command_help()
    {
        std::string result = "Commands:\n";
Paul's avatar
Paul committed
419
420
421
422
        return std::accumulate(get_commands().begin(),
                               get_commands().end(),
                               result,
                               [](auto r, auto&& p) { return r + "    " + p.first + "\n"; });
Paul's avatar
Paul committed
423
    }
Paul's avatar
Paul committed
424
    void parse(argument_parser& ap)
Paul's avatar
Paul committed
425
    {
Paul's avatar
Paul committed
426
        ap(nullptr, {"-h", "--help"}, ap.help("Show help"), ap.show_help(get_command_help()));
Paul's avatar
Paul committed
427
428
429
430
431
    }

    void run() {}
};

Paul's avatar
Paul committed
432
433
434
435
} // namespace MIGRAPHX_INLINE_NS
} // namespace driver
} // namespace migraphx

Paul's avatar
Paul committed
436
using namespace migraphx::driver; // NOLINT
Paul's avatar
Paul committed
437
438
int main(int argc, const char* argv[])
{
Paul's avatar
Paul committed
439
    std::vector<std::string> args(argv + 1, argv + argc);
Paul's avatar
Paul committed
440
    if(args.empty())
Paul's avatar
Paul committed
441
        return 0;
Paul's avatar
Paul committed
442
    auto&& m = get_commands();
Paul's avatar
Paul committed
443
    auto cmd = args.front();
Paul's avatar
Paul committed
444
    if(m.count(cmd) > 0)
Paul's avatar
Paul committed
445
    {
Paul's avatar
Paul committed
446
        m.at(cmd)({args.begin() + 1, args.end()});
Paul's avatar
Paul committed
447
    }
Paul's avatar
Paul committed
448
    else
Paul's avatar
Paul committed
449
    {
Paul's avatar
Paul committed
450
        run_command<main_command>(args);
Paul's avatar
Paul committed
451
452
453
    }
    return 0;
}