overview.rst 4.35 KB
Newer Older
Paul's avatar
Paul committed
1
2
3
4
5
6
7
8
Overview
========

MIGraph provides an optimized execution engine for deep learning neural networks.

Building a program
------------------

Paul's avatar
Paul committed
9
A program consists of a set of instructions to be executed when calling `eval <migraph::program::eval>`. Each instruction has an associated `operation <migraph::operation>` which represents the computation to be performed by the instruction.
Paul's avatar
Paul committed
10
11
12
13
14
15
16
17

We can start by building a simple program to add two numbers together::

    program p;
    instruction_ref one = p.add_literal(1);
    instruction_ref two = p.add_literal(2);
    p.add_instruction(add{}, one, two);

Paul's avatar
Paul committed
18
The `add_literal <migraph::program::add_literal>` function will add an instruction to the program to store a literal number. The `instruction_ref <migraph::instruction_ref>` is a reference to the instruction in the program, which can be used to compose the output of the instruction with another instruction.
Paul's avatar
Paul committed
19

Paul's avatar
Paul committed
20
After creating the literals, we then create the instruction to add the numbers together. This is done by using the `add{} <migraph::add>` operation class along with the `instruction_ref <migraph::instruction_ref>` for the input arguments of the instruction.
Paul's avatar
Paul committed
21

Paul's avatar
Paul committed
22
Finally, we can run this `program <migraph::program>` by compiling it for the cpu and then running it with `eval <migraph::program::eval>`::
Paul's avatar
Paul committed
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

    p.compile(cpu::target{});
    argument result = p.eval({});

The easiest way to see the result is to print it::

    std::cout << result;

Which will print ``3``.

We can also compile the program for the gpu as well.

Adding parameters
-----------------

Paul's avatar
Paul committed
38
Of course, this program will always produce the same value which is quite uninteresting. Instead, we want to pass an input to a program and compute a value based on the input. This can be done with a parameter. For example, we can modify the program to take an input ``x``::
Paul's avatar
Paul committed
39
40
41
42
43
44
45

    program p;
    instruction_ref x = p.add_parameter("x", {shape::int64_type});
    instruction_ref two = p.add_literal(2);
    p.add_instruction(add{}, one, two);
    p.compile(cpu::target{});

Paul's avatar
Paul committed
46
This adds a parameter of type ``int64``, and compiles it for the ``cpu``. To run the program, we need to pass the parameter to it when we call `eval <migraph::program::eval>`::
Paul's avatar
Paul committed
47
48
49
50
51
52
53
54

    argument result = p.eval({
        {"x", literal{1}.get_argument()}
    });
    std::cout << result;

This will print ``3``.

Paul's avatar
Paul committed
55
A parameter is given as an `argument <migraph::argument>`. In this case, the simplest way of creating an `argument <migraph::argument>` is from a `literal <migraph::literal>`.
Paul's avatar
Paul committed
56
57
58
59

Tensor data
-----------

Paul's avatar
Paul committed
60
In this example we are just creating numbers, but the `shape <migraph::shape>` class can describe multi-dimensional tensors. For example, we can build a simple network with convolution and relu::
Paul's avatar
Paul committed
61
62
63
64
65
66
67

    program p;
    instruction_ref input = p.add_parameter("x", shape{shape::float_type, {1, 3, 32, 32}});
    instruction_ref weights = p.add_parameter("w", shape{shape::float_type, {1, 3, 5, 5}});
    instruction_ref conv = p.add_instruction(convolution{}, input, weights);
    p.add_instruction(activation{"relu"}, conv);

Paul's avatar
Paul committed
68
Here we create two parameters for both the ``input`` and ``weights``. In the previous examples, we just created simple literals, however, most programs will take data from already allocated buffers(usually on the GPU). In this case, we can create `argument <migraph::argument>` objects directly from the pointers to the buffers::
Paul's avatar
Paul committed
69
70
71
72
73
74
75
76
77
78
79

    // Compile the program
    p.compile(gpu::target{});
    // Allocated buffers by the user
    float* input = ...;
    float* weights = ...;
    // Create the arguments
    argument input_arg{shape{shape::float_type, {1, 3, 32, 32}}, input};
    argument weights_arg{shape{shape::float_type, {1, 3, 32, 32}}, weights};
    p.eval({{"x", input_arg}, {"w", weights_arg}})

Paul's avatar
Paul committed
80
An `argument <migraph::argument>` can handle memory buffers from either the GPU or the CPU, but when running the `program <migraph::program>`, buffers should be allocated for the corresponding target. That is, when compiling for the CPU, the buffers should be allocated on the CPU, and when compiling for the GPU the buffers should be allocated on the GPU.
Paul's avatar
Paul committed
81
82
83
84

Importing from onnx
-------------------

Paul's avatar
Paul committed
85
A `program <migraph::program>` can be built directly from an onnx file, which makes it easier to use neural networks directly from other frameworks. In this case, there is an ``parse_onnx`` function::
Paul's avatar
Paul committed
86
87
88

    program p = parse_onnx("model.onnx");
    p.compile(gpu::target{});
Paul's avatar
Paul committed
89