miopen_target.cpp 7.92 KB
Newer Older
Paul's avatar
Paul committed
1
2
#include <rtg/miopen/miopen_target.hpp>
#include <rtg/manage_ptr.hpp>
Paul's avatar
Paul committed
3
4
#include <rtg/instruction.hpp>
#include <rtg/operators.hpp>
Paul's avatar
Paul committed
5
6
7

#include <miopen/miopen.h>

Paul's avatar
Paul committed
8
9
namespace rtg {
namespace miopen {
Paul's avatar
Paul committed
10

Paul's avatar
Paul committed
11
12
13
14
15
16
17
18
19
20
struct hip_allocate
{
    std::string name() const { return "hip::allocate"; }
    shape compute_shape(std::vector<shape> inputs) const
    {
        check_shapes{inputs}.has(1);
        return inputs.front();
    }
    argument compute(shape output_shape, std::vector<argument>) const
    {
Paul's avatar
Paul committed
21
        char* data = nullptr;
Paul's avatar
Paul committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
        // TODO: Check return status
        hipMalloc(&data, output_shape.bytes());
        return {output_shape, data};
    }
};

struct hip_free
{
    std::string name() const { return "hip::free"; }
    shape compute_shape(std::vector<shape> inputs) const
    {
        check_shapes{inputs}.has(1);
        return {};
    }
Paul's avatar
Paul committed
36
    argument compute(shape, std::vector<argument> args) const
Paul's avatar
Paul committed
37
38
39
40
41
42
43
    {
        // TODO: Check return status
        hipFree(args.front().data());
        return {};
    }
};

Paul's avatar
Paul committed
44
using miopen_handle     = RTG_MANAGE_PTR(miopenHandle_t, miopenDestroy);
Paul's avatar
Paul committed
45
using tensor_descriptor = RTG_MANAGE_PTR(miopenTensorDescriptor_t, miopenDestroyTensorDescriptor);
Paul's avatar
Paul committed
46
47
48
49
using convolution_descriptor = RTG_MANAGE_PTR(miopenConvolutionDescriptor_t,
                                              miopenDestroyConvolutionDescriptor);
using activation_descriptor  = RTG_MANAGE_PTR(miopenActivationDescriptor_t,
                                             miopenDestroyActivationDescriptor);
Paul's avatar
Paul committed
50

Paul's avatar
Paul committed
51
template <class Result, class F, class... Ts>
Paul's avatar
Paul committed
52
53
54
Result make_obj(F f, Ts... xs)
{
    typename Result::pointer x = nullptr;
Paul's avatar
Paul committed
55
    auto status                = f(&x, xs...);
Paul's avatar
Paul committed
56
    Result r{x};
Paul's avatar
Paul committed
57
    if(status != miopenStatusSuccess)
Paul's avatar
Paul committed
58
59
60
61
62
63
64
65
66
67
68
        RTG_THROW("MIOpen call failed");
    return r;
}

tensor_descriptor make_tensor(const rtg::shape& s)
{
    auto t = make_obj<tensor_descriptor>(&miopenCreateTensorDescriptor);
    // Convert to ints
    std::vector<int> lens(s.lens().begin(), s.lens().end());
    std::vector<int> strides(s.strides().begin(), s.strides().end());
    miopenDataType_t d;
Paul's avatar
Paul committed
69
70
71
72
    if(s.type() == shape::float_type)
        d = miopenFloat;
    else
        RTG_THROW("Unsupported type");
Paul's avatar
Paul committed
73
74
75
76
77
78
79
    miopenSetTensorDescriptor(t.get(), d, s.lens().size(), lens.data(), strides.data());
    return t;
}

convolution_descriptor make_conv(const rtg::convolution& op)
{
    auto c = make_obj<convolution_descriptor>(&miopenCreateConvolutionDescriptor);
Paul's avatar
Paul committed
80
81
82
83
84
85
86
87
    miopenInitConvolutionDescriptor(c.get(),
                                    miopenConvolution,
                                    op.padding[0],
                                    op.padding[1],
                                    op.stride[0],
                                    op.stride[1],
                                    op.dilation[0],
                                    op.dilation[1]);
Paul's avatar
Paul committed
88
89
90
    return c;
}

Paul's avatar
Paul committed
91
92
93
94
95
96
97
activation_descriptor make_relu()
{
    auto ad = make_obj<activation_descriptor>(&miopenCreateActivationDescriptor);
    miopenSetActivationDescriptor(ad.get(), miopenActivationRELU, 0, 0, 0);
    return ad;
}

Paul's avatar
Paul committed
98
99
100
struct miopen_convolution
{
    convolution op;
Paul's avatar
Paul committed
101
    shared<convolution_descriptor> cd;
Paul's avatar
Paul committed
102
103

    std::string name() const { return "miopen::convolution"; }
Paul's avatar
Paul committed
104
105
    shape compute_shape(std::vector<shape> inputs) const
    {
Paul's avatar
Paul committed
106
        check_shapes{inputs}.has(4);
Paul's avatar
Paul committed
107
        return op.compute_shape({inputs.at(1), inputs.at(2)});
Paul's avatar
Paul committed
108
109
110
111
112
113
114
    }
    argument compute(shape output_shape, std::vector<argument> args) const
    {
        auto x_desc = make_tensor(args[1].get_shape());
        auto w_desc = make_tensor(args[2].get_shape());
        auto y_desc = make_tensor(output_shape);

Paul's avatar
Paul committed
115
        float alpha = 1, beta = 0;
Paul's avatar
Paul committed
116
117
        int algo_count;
        miopenConvAlgoPerf_t perf;
118
        miopenFindConvolutionForwardAlgorithm(args[0].implicit(),
Paul's avatar
Paul committed
119
                                              x_desc.get(),
120
                                              args[1].implicit(),
Paul's avatar
Paul committed
121
                                              w_desc.get(),
122
                                              args[2].implicit(),
Paul's avatar
Paul committed
123
                                              cd.get(),
Paul's avatar
Paul committed
124
                                              y_desc.get(),
125
                                              args[3].implicit(),
Paul's avatar
Paul committed
126
127
128
                                              1,
                                              &algo_count,
                                              &perf,
Paul's avatar
Paul committed
129
130
                                              nullptr,
                                              0,
Paul's avatar
Paul committed
131
                                              false);
132
        miopenConvolutionForward(args[0].implicit(),
Paul's avatar
Paul committed
133
                                 &alpha,
Paul's avatar
Paul committed
134
                                 x_desc.get(),
135
                                 args[1].implicit(),
Paul's avatar
Paul committed
136
                                 w_desc.get(),
137
                                 args[2].implicit(),
Paul's avatar
Paul committed
138
139
140
                                 cd.get(),
                                 perf.fwd_algo,
                                 &beta,
Paul's avatar
Paul committed
141
                                 y_desc.get(),
142
                                 args[3].implicit(),
Paul's avatar
Paul committed
143
144
145
146
147
148
149
150
151
152
                                 nullptr,
                                 0);
        return args[3];
    }
};

struct miopen_relu
{
    shared<activation_descriptor> ad;
    std::string name() const { return "miopen::relu"; }
Paul's avatar
Paul committed
153
    shape compute_shape(std::vector<shape> inputs) const
Paul's avatar
Paul committed
154
    {
Paul's avatar
Paul committed
155
156
        check_shapes{inputs}.has(3);
        return inputs.at(1);
Paul's avatar
Paul committed
157
158
159
160
161
162
163
    }

    argument compute(shape output_shape, std::vector<argument> args) const
    {
        float alpha = 1, beta = 0;
        auto x_desc = make_tensor(args[1].get_shape());
        auto y_desc = make_tensor(output_shape);
164
        miopenActivationForward(args[0].implicit(),
Paul's avatar
Paul committed
165
166
167
                                ad.get(),
                                &alpha,
                                x_desc.get(),
168
                                args[1].implicit(),
Paul's avatar
Paul committed
169
170
                                &beta,
                                y_desc.get(),
171
                                args[2].implicit());
Paul's avatar
Paul committed
172
173

        return args[2];
Paul's avatar
Paul committed
174
175
176
    }
};

Paul's avatar
Paul committed
177
178
struct miopen_apply
{
Paul's avatar
Paul committed
179
180
    program* prog = nullptr;
    instruction_ref handle{};
Paul's avatar
Paul committed
181
182
183

    void apply()
    {
Paul's avatar
Paul committed
184
        handle = prog->add_parameter("handle", shape{shape::any_type});
Paul's avatar
Paul committed
185
186
187
188
        for(auto it = prog->begin(); it != prog->end(); it++)
        {
            if(it->op.name() == "convolution")
            {
Paul's avatar
Paul committed
189
                apply_convolution(it);
Paul's avatar
Paul committed
190
191
192
            }
            else if(it->op.name() == "activation")
            {
Paul's avatar
Paul committed
193
194
195
196
197
                apply_activation(it);
            }
        }
    }

Paul's avatar
Paul committed
198
199
    instruction_ref insert_allocation(instruction_ref ins, const shape& s)
    {
Paul's avatar
Paul committed
200
        if(ins == --prog->end())
Paul's avatar
Paul committed
201
202
203
204
205
        {
            return prog->add_parameter("output", s);
        }
        else
        {
Paul's avatar
Paul committed
206
            auto is     = prog->add_outline(s);
Paul's avatar
Paul committed
207
208
209
210
211
212
            auto result = prog->insert_instruction(ins, hip_allocate{}, is);
            prog->insert_instruction(++ins, hip_free{}, result);
            return result;
        }
    }

Paul's avatar
Paul committed
213
214
    void apply_convolution(instruction_ref ins)
    {
Paul's avatar
Paul committed
215
216
        auto&& op   = any_cast<convolution>(ins->op);
        auto cd     = make_conv(op);
Paul's avatar
Paul committed
217
218
        auto output = insert_allocation(ins, ins->result);

Paul's avatar
Paul committed
219
220
221
222
223
224
        prog->replace_instruction(ins,
                                  miopen_convolution{op, std::move(cd)},
                                  handle,
                                  ins->arguments.at(0),
                                  ins->arguments.at(1),
                                  output);
Paul's avatar
Paul committed
225
226
    }

Paul's avatar
Paul committed
227
    void apply_activation(instruction_ref ins)
Paul's avatar
Paul committed
228
229
    {
        auto&& op = any_cast<activation>(ins->op);
Paul's avatar
Paul committed
230
231
        auto ad   = make_relu();
        if(op.mode == "relu")
Paul's avatar
Paul committed
232
233
        {
            auto output = insert_allocation(ins, ins->result);
Paul's avatar
Paul committed
234
235
            prog->replace_instruction(
                ins, miopen_relu{std::move(ad)}, handle, ins->arguments.at(0), output);
Paul's avatar
Paul committed
236
237
        }
    }
Paul's avatar
Paul committed
238
239
};

Paul's avatar
Paul committed
240
std::string miopen_target::name() const { return "miopen"; }
Paul's avatar
Paul committed
241

Paul's avatar
Paul committed
242
void miopen_target::apply(program& p) const { miopen_apply{&p}.apply(); }
Paul's avatar
Paul committed
243
244
245
246

} // namespace miopen

} // namespace rtg