Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_ConvTranspose.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_CONVTRANSPOSE_HXX
2#define TMVA_SOFIE_ROPERATOR_CONVTRANSPOSE_HXX
3
5#include <TMVA/ROperator.hxx>
6#include <TMVA/RModel.hxx>
7
8#include <memory>
9#include <sstream>
10#include <algorithm>
11#include <stdexcept>
12#include <vector>
13#include <cassert>
14
16
17/*! \brief Transposed Convolution operator
18 *
19 * Inference code generation for a transposed convolution layer.
20 * See the <a href="https://github.com/onnx/onnx/blob/main/docs/Operators.md#convtranspose">ONNX documentation</a> for
21 * details about the transposed conv layer.
22 */
23template <typename T>
25private:
26 std::string fAttrAutopad;
27 std::vector<size_t> fAttrDilations;
28 size_t fAttrGroup;
29 std::vector<size_t> fAttrKernelShape;
30 std::vector<size_t> fAttrOutputPadding;
31 std::vector<size_t> fAttrOutputShape;
32 std::vector<size_t> fAttrPads;
33 std::vector<size_t> fAttrStrides;
34
35 std::string fNX;
36 std::string fNW;
37 std::string fNB;
38 std::string fNBroadcastedB;
39 std::string fNY;
40
41 std::string fConvK;
42 std::string fImcol;
43
44 std::vector<size_t> fShapeX;
45 std::vector<size_t> fShapeW;
46 std::vector<size_t> fShapeB;
47 std::vector<size_t> fShapeY;
48
49 std::string fType;
50
51 size_t fDim; // dimension of the convolution
52
53public:
54 /*! Default constructor of ROperator_ConvTranspose */
56
57 /*! \brief Constructor of ROperator_ConvTranspose from the attributes
58 *
59 * \param autopad padding
60 * \param dilations dilations of the kernel
61 * \param group number of groups
62 * \param kernelShape shape of the kernel
63 * \param outputPadding padding of the output
64 * \param outputShape shape of the output
65 * \param pads padding of the input
66 * \param strides strides
67 * \param nameX name of the input
68 * \param nameW name of the weight
69 * \param nameB name of the bias
70 * \param nameY name of the output
71 */
72 ROperator_ConvTranspose(std::string autopad, std::vector<size_t> dilations, size_t group,
73 std::vector<size_t> kernelShape, std::vector<size_t> outputPadding,
74 std::vector<size_t> outputShape, std::vector<size_t> pads, std::vector<size_t> strides,
75 std::string nameX, std::string nameW, std::string nameB, std::string nameY)
77 fAttrDilations(dilations),
82 fAttrPads(pads),
83 fAttrStrides(strides),
84 fNX(UTILITY::Clean_name(nameX)),
85 fNW(UTILITY::Clean_name(nameW)),
86 fNB(UTILITY::Clean_name(nameB)),
87 fNY(UTILITY::Clean_name(nameY))
88 {
91 if (!fNB.empty()) {
92 fInputTensorNames.emplace_back(fNB);
93 }
94
95 if (std::is_same<T, float>::value) {
96 fType = "float";
97 } else {
98 throw std::runtime_error("TMVA SOFIE Encountered unsupported type parsing a Conv operator");
99 }
100 }
101
102 /*! \brief Infers the type of the output tensor
103 * \param input type of the input tensors
104 */
105 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override
106 {
107 ETensorType out = input[0];
108 return {out};
109 }
110
111 /*! \brief Infers the shape of the input tensors
112 * \param input shape of the input tensors
113 */
114 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> /*input*/) override;
115
116 /*! \brief Initialize the model
117 * \param model Model
118 */
119 void Initialize(RModel &) override;
120
121 /*! \brief Generate code for initializing the op
122 */
123 std::string GenerateInitCode() override;
124
125 /*! \brief Generate the inference code
126 * \param opName name of the operator
127 */
128 std::string Generate(std::string opName) override;
129
130 /*! \brief Returns the blas routines needed to compile the generated code
131 */
132 std::vector<std::string> GetBlasRoutines() override { return {std::string("Gemm"), std::string("Axpy")}; }
133};
134
135template <typename T>
136auto ROperator_ConvTranspose<T>::ShapeInference(std::vector<std::vector<size_t>> input)
137 -> std::vector<std::vector<size_t>>
138{
139 const std::vector<size_t> &inputShape = input[0];
140 const std::vector<size_t> &weightShape = input[1];
141 size_t size = inputShape.size();
142 // Dimension of the conv transpose op
143 fDim = size - 2;
144 // Number of groups
145 if (fAttrGroup == 0)
146 fAttrGroup = 1;
147 if (fAttrStrides.empty()) {
148 fAttrStrides = std::vector<size_t>(fDim, 1);
149 }
150 if (fAttrDilations.empty()) {
151 fAttrDilations = std::vector<size_t>(fDim, 1);
152 }
153 // The shape of the kernel is kw for 1d image, kh x Kw for 2d images and kd x kh x kw for a 3d image
154 if (fAttrKernelShape.empty()) {
155 fAttrKernelShape.resize(fDim);
156 for (size_t i = 0; i < fDim; i++)
157 fAttrKernelShape[i] = fShapeW[i + 2] + (fAttrDilations[i] - 1) * (fShapeW[i + 2] - 1);
158 }
159 if (fAttrOutputPadding.empty())
160 fAttrOutputPadding = std::vector<size_t>(fDim, 0);
161
162 // The Shape of the output is batch_size x out_channel x out_w for a 1d image,
163 // batch_size x out_channel x out_h x out_w for a 2d image and
164 // batch_size x out_channel x out_d x out_h x out_w for a 3d image
165 // where out_channel = weight_shape[1] * group
166 std::vector<size_t> outShape(size);
167 outShape[0] = inputShape[0];
168 outShape[1] = weightShape[1] * fAttrGroup;
169
170 // Generate the padding
171 if (fAttrPads.empty()) {
172 fAttrPads = std::vector<size_t>(2 * fDim, 0);
173
174 if (fAttrAutopad != "NOTSET") {
175 throw std::runtime_error("ConvTranspose with padding SAME_UPPER or SMAE_LOWER not supported");
176 }
177 }
178 if (fAttrOutputShape.empty()) {
179 fAttrOutputShape.resize(fDim);
180 for (size_t i = 0; i < fDim; i++) {
181 size_t j = i + 2;
182 fAttrOutputShape[i] = fAttrStrides[i] * (inputShape[j] - 1) + fAttrKernelShape[i] + fAttrOutputPadding[i] -
183 fAttrPads[i] - fAttrPads[fDim + i];
184 }
185 } else {
186 // The shape of the output is explicitly set
187 fAttrPads = std::vector<size_t>(2 * fDim, 0);
188 for (size_t i = 0; i < fDim; ++i) {
189 size_t input_shape = inputShape[i + 2];
190 size_t output_shape = fAttrOutputShape[i];
191 size_t kernel_shape = weightShape[i + 2];
192
193 size_t stride = fAttrStrides[i];
194 size_t dilation = fAttrDilations[i];
195 size_t output_padding = fAttrOutputPadding[i];
196
197 size_t effective_kernel_shape = (kernel_shape - 1) * dilation + 1;
199
201 throw std::runtime_error("ConvTranspose: explicitly set output_shape is too large for "
202 "the given input and kernel shapes.");
203 }
204
206
207 fAttrPads[i + fDim] = total_padding / 2;
208 fAttrPads[i] = total_padding - fAttrPads[i + fDim];
209 }
210 }
211
212 for (size_t i = 0; i < fDim; i++)
213 outShape[i + 2] = fAttrOutputShape[i];
214 std::vector<std::vector<size_t>> ret({outShape});
215 return ret;
216}
217
218template <typename T>
220{
221
222 fUseSession = model.UseSession();
223 if (!model.CheckIfTensorAlreadyExist(fNX)) {
224 throw std::runtime_error("TMVA SOFIE Conv Transpose op Input Tensor " + fNX + " is not found in model");
225 }
226 fShapeX = model.GetTensorShape(fNX);
227 if (fShapeX.size() < 3 || fShapeX.size() > 5) {
228 std::cout << fNX << " : " << ConvertShapeToString(fShapeX) << std::endl;
229 throw std::runtime_error("TMVA SOFIE Conv Transpose Op input data tensor" + fNX +
230 " is not of 3,4 or 5 dimensions");
231 }
232 fDim = fShapeX.size() - 2;
233 if (!model.CheckIfTensorAlreadyExist(fNW)) {
234 throw std::runtime_error("TMVA SOFIE Conv op Input weight Tensor " + fNW + " is not found in model");
235 }
236 fShapeW = model.GetTensorShape(fNW);
237 if (fShapeW.size() < 3 || fShapeW.size() > 5) {
238 std::cout << fNW << " : " << ConvertShapeToString(fShapeW) << std::endl;
239 throw std::runtime_error("TMVA SOFIE Conv Transpose Op input weight tensor" + fNW +
240 " is not of 3,4 or 5 dimensions");
241 }
242 fShapeY = ShapeInference({fShapeX, fShapeW})[0];
243
244 model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY);
245 if (fNB != "") {
246 if (!model.CheckIfTensorAlreadyExist(fNB)) {
247 throw std::runtime_error("TMVA SOFIE ConvTrans op Input Tensor " + fNB + " is not found in model");
248 }
249 fShapeB = model.GetTensorShape(fNB);
250 if (fShapeB.size() < 1)
251 throw std::runtime_error("TMVA SOFIE ConvTrans op: Bias Tensor has empty shape");
252
253 size_t bsize = ConvertShapeToLength(fShapeB);
254 size_t ysize = ConvertShapeToLength(fShapeY);
255 // broadcasting is needed if first stride of B is not same of Y
256 bool broadcast_needed = (bsize != ysize);
257 // Broadcast the bias B
258 if (broadcast_needed) {
259 // we assume bias tensor size is equal to number of filters that is the second dimension in
260 // the output tensor
261 if (bsize != fShapeY[1])
262 throw std::runtime_error("TMVA SOFIE ConvTrans op: Bias Tensor has wrong shape: " +
263 ConvertShapeToString(fShapeB));
264
265 auto original_data = model.GetInitializedTensorData(fNB);
266
267 if (fType != "float")
268 throw std::runtime_error(
269 "TMVA SOFIE ConvTrans op: Broadcasting for non-float type tensors is not supported");
270 // here the acual broadcasting
271 if (!fUseSession) {
272 // Broadcast B from M to N x M x Od x Oh x Ow
273 std::shared_ptr<void> new_data_ptr(
274 UTILITY::BroadcastConvBias<float>(static_cast<float *>(original_data.get()), bsize, fShapeY),
275 std::default_delete<float[]>());
276
277 model.UpdateInitializedTensor(fNB, model.GetTensorType(fNB), fShapeY, new_data_ptr);
278 fShapeB = model.GetTensorShape(fNB);
279 fNBroadcastedB = fNB; // use same name
280 } else {
281 // In case of session add broadcasting code in Session constructor and in GenerateInitCode
282 // we need to add a new intermediate tensor for broadcasted bias tensor
283 fNBroadcastedB = "Broadcasted" + fNB;
284 model.AddIntermediateTensor(fNBroadcastedB, model.GetTensorType(fNB), fShapeY);
285 }
286 } else {
287 // bias tensor is already correct shape, no need to broadcast
288 if (fShapeY != fShapeB)
289 throw std::runtime_error("TMVA SOFIE ConvTrans op: Broadcasting is not needed but bias has wrong shape" +
290 ConvertShapeToString(fShapeB));
291 fNBroadcastedB = fNB;
292 }
293 }
294
295 size_t kernelSize = 1;
296 size_t inputSize = 1;
297 for (size_t i = 0; i < fDim; i++) {
298 inputSize *= fShapeX[2 + i];
299 kernelSize *= fAttrKernelShape[i];
300 }
301
302 std::vector<size_t> shape1 = {fShapeW[0], fShapeW[1], kernelSize};
303 std::vector<size_t> shape2 = {fShapeW[1], kernelSize, inputSize};
304 model.AddIntermediateTensor(fNX + "_f", ConvertStringToType(fType), shape1);
305 model.AddIntermediateTensor(fNX + "_xcol", ConvertStringToType(fType), shape2);
306 fConvK = fNX + "_f";
307 fImcol = fNX + "_xcol";
308 fOutputTensorNames.emplace_back(fConvK);
309 fOutputTensorNames.emplace_back(fImcol);
310
311 // register the inference helper functions used by the generated code
312 // (only the <3D case is supported, which uses col2im)
313 model.AddNeededHelperFunction("col2im");
314 if (!fNB.empty())
315 model.AddNeededHelperFunction("BroadcastConvBias");
316}
317
318template <typename T>
320{
321 std::stringstream out;
322 // generate initialization code for broadcasting of bias tensor
323 size_t bsize = ConvertShapeToLength(fShapeB);
324 size_t ysize = ConvertShapeToLength(fShapeY);
325 if (bsize != ysize && !fNBroadcastedB.empty()) {
326 // include a separate scope to avoid defining unique operator temp variables
327 out << SP << "{\n";
328 out << SP << SP << "float * data = UTILITY::BroadcastConvBias<float>(tensor_" << fNB << ", " << bsize << ", "
329 << ConvertShapeToString(fShapeY) << ");\n";
330 out << SP << SP << "std::copy(data, data + " << ConvertShapeToLength(fShapeY) << ", tensor_" << fNBroadcastedB
331 << ");\n";
332 out << SP << SP << "delete[] data;\n";
333 out << SP << "}\n";
334 }
335 return out.str();
336}
337
338template <typename T>
340{
341 OpName = "op_" + OpName;
342
343 if (fShapeX.empty() || fShapeW.empty() || (fNB != "" && fShapeB.empty()) || fShapeY.empty()) {
344 throw std::runtime_error("TMVA SOFIE Conv Op called to Generate without being initialized first");
345 }
346
347 std::stringstream out;
348
349 size_t bsize = fShapeX[0];
350 size_t kDepth = (fDim > 2) ? fShapeW[2] : 1; // kernel depth
351 size_t kHeight = (fDim > 1) ? fShapeW[fDim] : 1; // kernel height
352 size_t kWidth = fShapeW[fDim + 1]; // kernel width
353
354 size_t iDepth = (fDim > 2) ? fShapeX[2] : 1; // input depth
355 size_t iHeight = (fDim > 1) ? fShapeX[fDim] : 1; // input height
356 size_t iWidth = fShapeX[fDim + 1]; // input width
357
358 size_t oDepth = (fDim > 2) ? fShapeY[2] : 1; // output depth
359 size_t oHeight = (fDim > 1) ? fShapeY[fDim] : 1; // ouput height
360 size_t oWidth = fShapeY[fDim + 1]; // output width
361
362 out << "\n//---- operator ConvTranspose " << OpName << "\n";
363
364 // create first matrix with convolution kernels
365 if (!fUseSession) {
366 size_t kernelSize = fAttrKernelShape[0];
367 if (fDim > 1)
368 kernelSize *= fAttrKernelShape[1];
369 out << SP << fType << " tensor_" << fNX << "_f[" << fShapeW[0] * fShapeW[1] * kernelSize << "] = {0};\n";
370 }
371
372 // vectorize the (dilated)convolution kernels into a matrix
373 // The shape of the kernel is W for 1d image, H x W for 2d image and D x H x W
374 // for 3d image
375 size_t id = (fDim > 2) ? fDim - 3 : 2;
376 size_t ih = (fDim > 1) ? fDim - 2 : 1;
377 size_t iw = fDim - 1;
378 size_t wstrideDil = fAttrDilations[iw];
379 size_t hstride = kWidth;
380 size_t hstrideDil = fAttrKernelShape[iw];
381 if (fDim > 1)
382 hstrideDil *= fAttrDilations[ih];
383 // stride dilated in the height
384 size_t dstride = kHeight * kWidth;
385 size_t dstrideDil = fAttrKernelShape[iw];
386 if (fDim > 1)
387 dstrideDil *= fAttrKernelShape[ih];
388 if (fDim > 2)
389 dstrideDil *= fAttrDilations[id];
390 size_t icstride = kHeight * kWidth * kDepth;
391 size_t icstrideDil = 1;
392 for (size_t i = 0; i < fDim; i++)
393 icstrideDil *= fAttrKernelShape[i];
394 size_t ocstride = fShapeW[1] * icstride;
395 size_t ocstrideDil = fShapeW[1] * icstrideDil;
396
397 // The shape of f is [M/group, kHeight x kWidth]
398 out << SP << "for (std::size_t ic = 0; ic < " << fShapeW[0] << "; ic++) {\n";
399 out << SP << SP << "for (std::size_t oc = 0; oc < " << fShapeW[1] << "; oc++) {\n";
400 // out << SP << SP << SP << "size_t kIndex = 0;\n"; // filter index
401 if (fDim > 2)
402 out << SP << SP << SP << "for (std::size_t kd = 0; kd < " << kDepth << "; kd++) {\n";
403 if (fDim > 1)
404 out << SP << SP << SP << "for (std::size_t kh = 0; kh < " << kHeight << "; kh++) {\n";
405 out << SP << SP << SP << SP << "for (std::size_t kw = 0; kw < " << kWidth << "; kw++) {\n";
406
407 out << SP << SP << SP << SP << SP << "tensor_" << fNX << "_f[ic * " << ocstrideDil << " + oc * " << icstrideDil;
408 if (fDim > 2)
409 out << " + kd * " << dstrideDil;
410 if (fDim > 1)
411 out << " + kh * " << hstrideDil;
412 out << " + kw * " << wstrideDil << " ] = tensor_" << fNW << "[ic * " << ocstride << " + oc * " << icstride;
413
414 if (fDim > 2)
415 out << " + kd * " << dstride;
416 if (fDim > 1)
417 out << " + kh * " << hstride;
418 out << " + kw ];\n";
419
420 // here we rotate the input kernel tranforming 0,1,2,...N-1 in N-1,N-2,...,2,1,0
421 // out << " + " << icstride -1 << " - kIndex ];\n"; // tranform 1,2,3,4 in 4,3,2,1
422 // out << SP << SP << SP << SP << SP << "kIndex++;\n"; // update input filter index
423
424 out << SP << SP << SP << SP << "}\n";
425 if (fDim > 1)
426 out << SP << SP << SP << "}\n";
427 if (fDim > 2)
428 out << SP << SP << SP << "}\n";
429
430 out << SP << SP << "}\n";
431 out << SP << "}\n";
432
433 out << SP << "char " << OpName << "_transA = 'N';\n";
434 out << SP << "char " << OpName << "_transB = 'T';\n";
435 out << SP << "int " << OpName << "_m = " << iHeight * iWidth * iDepth << ";\n";
436 out << SP << "int " << OpName << "_n = " << icstrideDil * fShapeW[1] << ";\n"; // output channels * filters
437 out << SP << "int " << OpName << "_k = " << fShapeW[0] << ";\n"; // input channels
438 out << SP << "float " << OpName << "_alpha = 1.0;\n";
439 out << SP << "float " << OpName << "_beta = 0.0;\n";
440
441 if (!fUseSession) {
442 out << SP << fType << " tensor_" << fNX << "_xcol[" << fShapeW[0] * icstrideDil * oDepth * oHeight * oWidth
443 << "] = {0};\n";
444 }
445
446 // Loop on batch size
447 out << SP << "for (size_t n = 0; n < " << bsize << "; n++) {\n";
448
449 // IM2COL: Unroll the input tensor
450 // order input data as (e.g. kernel 2x2) and (xa,ya) is channel 1 and (xb,yb) is channel 2
451 // (xa1,..,xak,ya1,..yak)(xb1,...,xbk,yb1,..,ybk)
452 // (xa2,...xak+1,ya1,...yak)(......)
453 // trick for speed is using caffe im2col and output a matrix which contains filtered values as rows.
454 // By doing this one has consecutive memory reads and writes
455 // Resulting matrix op_xcol is (output channels * filter_h * filter_w , output_h * output_w)
456
457 if (fAttrGroup == 1) {
458 out << SP << SP << "size_t x_offset = n * " << fShapeX[1] * iDepth * iHeight * iWidth << ";\n";
459 out << SP << SP << "size_t out_offset = n * " << fShapeY[1] * oDepth * oHeight * oWidth << ";\n";
460
461 // DO BLAS before:
462 // BLAS
463 out << SP << SP << "BLAS::sgemm_(&" << OpName << "_transA, &" << OpName << "_transB, &" << OpName << "_m, &"
464 << OpName << "_n, &" << OpName << "_k, &" << OpName << "_alpha, "
465 << "tensor_" << fNX << " + x_offset, &" << OpName
466 << "_m,\n"; // use m if op_xcol is not transpose , otherwise k
467 out << SP << SP << SP << "tensor_" << fNX << "_f, &" << OpName << "_n, &" << OpName << "_beta, tensor_" << fNX
468 << "_xcol, &" << OpName << "_m);\n";
469
470 // when using im2col - resulting matrix is transposed, is (input_c * filter_h * filter_w, output_h *
471 // output_w)
472 // before using col2im I need to transpose matrix
473 if (fDim < 3) {
474 out << SP << SP << "UTILITY::col2im<float>(tensor_" << fNX
475 << "_xcol,"
476 // channels, height, width, kernel_h, kernel_w, pad_h_begin, pad_h_end, pad_w_begin, pad_w_end,
477 // stride_h, stride_w, dilation_h, dilation_w,
478 << fShapeY[1] << "," << oHeight << "," << oWidth << ",";
479 if (fDim == 1)
480 out << "1, " << fAttrKernelShape[0] << ",0,0," << fAttrPads[0] << "," << fAttrPads[1] << ",1,"
481 << fAttrStrides[0] << ",1," << fAttrDilations[0];
482 else // dim ==2
483 out << fAttrKernelShape[0] << "," << fAttrKernelShape[1] << "," << fAttrPads[0] << "," << fAttrPads[2]
484 << "," << fAttrPads[1] << "," << fAttrPads[3] << "," << fAttrStrides[0] << "," << fAttrStrides[1] << ","
485 << fAttrDilations[0] << "," << fAttrDilations[1];
486 out << ", tensor_" << fNY << " + out_offset);\n\n ";
487 } else {
488 // 3d : needs a col2im for 3d
489 throw std::runtime_error("TMVA SOFIE 3D Conv Transpose not yet supported");
490 out << SP << SP << "UTILITY::Im2col_3d<float>(tensor_" << fNX
491 << " + x_offset,"
492 // channels, d, h, w, k_d, k_h, k_w, pad_d_begin, pad_d_end, pad_h_begin, pad_h_end,
493 // pad_w_begin, pad_w_end, stride_d, stride_h, stride_w, dilation_d, dilation_h, dilation_w,
494 //
495 << fShapeX[1] << "," << oDepth << "," << oHeight << "," << oWidth << "," << fAttrKernelShape[0] << ","
496 << fAttrKernelShape[1] << "," << fAttrKernelShape[2] << "," << fAttrPads[0] << "," << fAttrPads[3] << ","
497 << fAttrPads[1] << "," << fAttrPads[4] << "," << fAttrPads[2] << "," << fAttrPads[5] << ","
498 << fAttrStrides[0] << "," << fAttrStrides[1] << "," << fAttrStrides[2] << "," << fAttrDilations[0] << ","
499 << fAttrDilations[1] << "," << fAttrDilations[2] << ",tensor_" << fNX << "_xcol);\n\n ";
500 }
501 // // BLAS
502 // out << SP << SP << "BLAS::sgemm_(&" << OpName << "_transA, &" << OpName << "_transB, &" << OpName << "_m, &"
503 // << OpName << "_n, &" << OpName << "_k, &" << OpName << "_alpha, tensor_" << fNX << "_xcol, &" << OpName
504 // << "_m,\n"; // use m if op_xcol is not transpose , otherwise k
505 // out << SP << SP << SP <<"tensor_" << fNX << "_f, &" << OpName << "_k, &" << OpName << "_beta, tensor_" << fNY
506 // << " + out_offset, &" << OpName << "_m);\n";
507 } else {
508 // case of group transposed convolution
509 // Unroll (IM2COL) the input tensor- make loop on groups and repeat operations (IM2COL + GEMM for each
510 // group)
511 out << SP << SP << "for (size_t g = 0; g < " << fAttrGroup << "; g++) {\n";
512 out << SP << SP << "size_t x_offset = n * " << fShapeX[1] * iHeight * iWidth << " + g * "
513 << fShapeX[1] * iHeight * iWidth / fAttrGroup << ";\n ";
514 out << SP << SP << "size_t out_offset = n * " << fShapeY[1] * oHeight * oWidth << " + g * "
515 << fShapeY[1] * oHeight * oWidth / fAttrGroup << ";\n ";
516
517 // do BLAS here (LM: probably need an offset for op_f the kernels)
518 out << SP << SP << "BLAS::sgemm_(&" << OpName << "_transA, &" << OpName << "_transB, &" << OpName << "_m, &"
519 << OpName << "_n, &" << OpName << "_k, &" << OpName << "_alpha, "
520 << "tensor_" << fNX << " + x_offset, &" << OpName
521 << "_m,\n"; // use m if op_xcol is not transpose , otherwise k
522 out << SP << SP << SP << "tensor_" << fNX << "_f, &" << OpName << "_n, &" << OpName << "_beta, tensor_" << fNX
523 << "_xcol , &" << OpName << "_m);\n";
524
525 if (fDim < 3) {
526 out << SP << SP << "UTILITY::col2im<float>(tensor_" << fNX
527 << "_xcol,"
528 // channels, height, width, kernel_h, kernel_w, pad_h_begin, pad_h_end, pad_w_begin, pad_w_end,
529 // stride_h, stride_w, dilation_h, dilation_w,
530 << fShapeY[1] << "," << oHeight << "," << oWidth << ",";
531 if (fDim == 1)
532 out << "1, " << fAttrKernelShape[0] << ",0,0," << fAttrPads[0] << "," << fAttrPads[1] << ",1,"
533 << fAttrStrides[0] << ",1," << fAttrDilations[0];
534 else // dim ==2
535 out << fAttrKernelShape[0] << "," << fAttrKernelShape[1] << "," << fAttrPads[0] << "," << fAttrPads[2]
536 << "," << fAttrPads[1] << "," << fAttrPads[3] << "," << fAttrStrides[0] << "," << fAttrStrides[1] << ","
537 << fAttrDilations[0] << "," << fAttrDilations[1];
538 out << ", tensor_" << fNY << " + out_offset);\n\n ";
539 } else {
540 // 3d im2col
541 throw std::runtime_error("TMVA SOFIE 3D Conv Transpose not yet supported");
542
543 out << SP << SP << "UTILITY::Im2col_3d<float>(tensor_" << fNX
544 << " + x_offset,"
545 // channels, d, h, w, k_d, k_h, k_w, pad_d_begin, pad_d_end, pad_h_begin, pad_h_end,
546 // pad_w_begin, pad_w_end, stride_d, stride_h, stride_w, dilation_d, dilation_h, dilation_w,
547 //
548 << fShapeX[1] << "," << oDepth << "," << oHeight << "," << oWidth << "," << fAttrKernelShape[0] << ","
549 << fAttrKernelShape[1] << "," << fAttrKernelShape[2] << "," << fAttrPads[0] << "," << fAttrPads[3] << ","
550 << fAttrPads[1] << "," << fAttrPads[4] << "," << fAttrPads[2] << "," << fAttrPads[5] << ","
551 << fAttrStrides[0] << "," << fAttrStrides[1] << "," << fAttrStrides[2] << "," << fAttrDilations[0] << ","
552 << fAttrDilations[1] << "," << fAttrDilations[2] << "," << "tensor_" << fNX << "_xcol);\n\n ";
553 }
554
555 // // BLAS
556 // // offset g must be g * k * n
557 // out << SP << SP << SP << "size_t offset_f = g * " << fShapeW[0] * fShapeW[1] * icstrideDil / fAttrGroup <<
558 // ";\n"; out << SP << SP << "BLAS::sgemm_(&" << OpName << "_transA, &" << OpName << "_transB, &" << OpName <<
559 // "_m, &"
560 // << OpName << "_n, &" << OpName << "_k, &" << OpName << "_alpha, tensor_" << fNX << "_xcol, &" << OpName
561 // << "_m,\n"; // use m if op_xcol is not transpose , otherwise k
562 // out << SP << SP << SP << "tensor_" << fNX << "_f + offset_f, &" << OpName << "_k, &" << OpName << "_beta,
563 // tensor_" << fNY
564 // << " + out_offset"
565 // << ", &" << OpName << "_m);\n";
566
567 out << SP << SP << "}\n"; // end of group loop
568 }
569
570 out << SP << "}\n"; // end of batch size loop
571
572 if (fNBroadcastedB != "") {
573 out << SP << "int " << OpName << "_size = " << fShapeY[0] * fShapeY[1] * oDepth * oHeight * oWidth << ";\n";
574 out << SP << "float " << OpName << "_gamma = 1.0;\n";
575 out << SP << "int " << OpName << "_incx = 1;\n";
576 out << SP << "int " << OpName << "_incy = 1;\n";
577
578 out << SP << "BLAS::saxpy_(&" << OpName << "_size, &" << OpName << "_gamma, tensor_" << fNBroadcastedB << ", &"
579 << OpName << "_incx, tensor_" << fNY << ", &" << OpName << "_incy);\n";
580 }
581
582 return out.str();
583}
584
585} // namespace TMVA::Experimental::SOFIE
586
587#endif
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
std::vector< std::string > GetBlasRoutines() override
Returns the blas routines needed to compile the generated code.
ROperator_ConvTranspose(std::string autopad, std::vector< size_t > dilations, size_t group, std::vector< size_t > kernelShape, std::vector< size_t > outputPadding, std::vector< size_t > outputShape, std::vector< size_t > pads, std::vector< size_t > strides, std::string nameX, std::string nameW, std::string nameB, std::string nameY)
Constructor of ROperator_ConvTranspose from the attributes.
void Initialize(RModel &) override
Initialize the model.
ROperator_ConvTranspose()
Default constructor of ROperator_ConvTranspose.
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input) override
Infers the type of the output tensor.
std::string GenerateInitCode() override
Generate code for initializing the op.
std::string Generate(std::string opName) override
Generate the inference code.
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > >) override
Infers the shape of the input tensors.
std::vector< std::string_view > fInputTensorNames
Definition ROperator.hxx:50
std::vector< std::string_view > fOutputTensorNames
Definition ROperator.hxx:51
std::size_t ConvertShapeToLength(const std::vector< size_t > &shape)
ETensorType ConvertStringToType(std::string type)
std::string ConvertShapeToString(const std::vector< size_t > &shape)