SMAUG
Simulating Machine Learning Applications on gem5-Aladdin
convolution_op.h
1 #ifndef _OPERATORS_CONVOLUTION_OP_H_
2 #define _OPERATORS_CONVOLUTION_OP_H_
3 
4 #include <string>
5 
6 #include "smaug/core/backend.h"
7 #include "smaug/core/operator.h"
8 #include "smaug/core/workspace.h"
9 #include "smaug/core/types.pb.h"
10 #include "smaug/operators/common.h"
11 #include "smaug/operators/fused_activation_op.h"
12 
13 namespace smaug {
14 
23 template <typename Backend>
24 class ConvolutionOp : public FusedActivationOp {
25  public:
26  ConvolutionOp(const std::string& name, Workspace* workspace)
27  : FusedActivationOp(name, OpType::Convolution3d, workspace),
28  weightRows(0), weightCols(0), numOfmaps(0), rowStride(0),
29  colStride(0), paddingType(UnknownPadding),
30  weightsName(name + "/kernels"), sampling({ NoSampling, 1 }) {
31  inputs.resize(kNumInputs, nullptr);
32  outputs.resize(kNumOutputs, nullptr);
33  }
34 
35  void setWeightDims(int _weightRows, int _weightCols, int _numOfmaps) {
36  weightRows = _weightRows;
37  weightCols = _weightCols;
38  numOfmaps = _numOfmaps;
39  }
40 
41  void setStride(int _rowStride, int _colStride) {
42  rowStride = _rowStride;
43  colStride = _colStride;
44  }
45 
46  void setPadding(PaddingType padding) {
47  paddingType = padding;
48  }
49 
50  bool validate() override {
51  return (weightRows > 0 && weightCols > 0 && numOfmaps > 0 &&
52  rowStride > 0 && colStride > 0 &&
53  paddingType != UnknownPadding && Operator::validate());
54  }
55 
56  virtual TensorShape inferOutputShape() const {
57  Tensor* input = getInput(Inputs);
58  assert(input && "Unable to get input for convolution op!");
59  DataLayout layout = input->getShape().getLayout();
60  bool isNCHW = (layout == DataLayout::NCHW);
61  int rowIdx = isNCHW ? 2 : 1;
62  int colIdx = isNCHW ? 3 : 2;
63  int outputRows = computeOutputDim(
64  input->dim(rowIdx), weightRows, rowStride, paddingType);
65  int outputCols = computeOutputDim(
66  input->dim(colIdx), weightCols, colStride, paddingType);
67  if (isNCHW) {
68  return TensorShape({ 1, numOfmaps, outputRows, outputCols },
69  layout,
70  Backend::Alignment);
71  } else {
72  return TensorShape({ 1, outputRows, outputCols, numOfmaps },
73  layout,
74  Backend::Alignment);
75  }
76  }
77 
78  virtual TensorShape inferWeightsShape() const {
79  Tensor* input = getInput(Inputs);
80  DataLayout layout = input->getShape().getLayout();
81  bool isNCHW = (layout == DataLayout::NCHW);
82  int channelsIdx = isNCHW ? 1 : 3;
83  int inputChannels = input->dim(channelsIdx);
84  if (isNCHW) {
85  return TensorShape(
86  { numOfmaps, inputChannels, weightRows, weightCols },
87  layout, Backend::Alignment);
88  } else {
89  return TensorShape(
90  { numOfmaps, weightRows, weightCols, inputChannels },
91  layout, Backend::Alignment);
92  }
93  }
94 
99  if (inputs.at(Kernels) != nullptr)
100  return;
101  TensorShape shape = inferWeightsShape();
102  Tensor* kernels = new Tensor(weightsName, shape);
103  workspace->addTensor(kernels);
104  inputs[Kernels] = kernels;
105  }
106 
107  void createOutputTensors() {
108  if (outputs.at(Outputs) != nullptr)
109  return;
110  TensorShape shape = inferOutputShape();
111  Tensor* output = new Tensor(name, shape);
112  workspace->addTensor(output);
113  outputs.at(Outputs) = output;
114  }
115 
116  void createAllTensors() override {
118  createOutputTensors();
119  }
120 
121  int getNumOfmaps() const { return numOfmaps; }
122 
123  void run() override {}
124 
125  int getNumParameters() const override {
126  return inputs.at(Kernels)->getShape().size();
127  }
128 
129  std::vector<TensorBase*> getParameterizableInputs() override {
130  return { inputs[Kernels] };
131  }
132 
133  int getRowStride() const { return rowStride; }
134  int getColStride() const { return colStride; }
135  int getWeightRows() const { return weightRows; }
136  int getWeightCols() const { return weightCols; }
137  PaddingType getPadding() const { return paddingType; }
138 
143  std::vector<int> getInputPadding() const {
144  std::vector<int> inputPadding(4);
145  int totalRowPad = (paddingType == SamePadding) ? weightRows - 1 : 0;
146  int totalColPad = (paddingType == SamePadding) ? weightCols - 1 : 0;
147  inputPadding[0] = FRAC_CEIL(totalRowPad, 2);
148  inputPadding[1] = totalRowPad - inputPadding[0];
149  inputPadding[2] = FRAC_CEIL(totalColPad, 2);
150  inputPadding[3] = totalColPad - inputPadding[2];
151  return inputPadding;
152  }
153 
154  bool isSamplingSupported() const override { return true; }
155  void setSamplingInfo(const SamplingInfo& _sampling) override {
156  sampling = _sampling;
157  }
158 
159  protected:
160  int computeOutputDim(int inputDim,
161  int weightDim,
162  int stride,
163  PaddingType pad) const {
164  int padding = (pad == SamePadding ? (weightDim - 1) : 0);
165  return computeOutputDim(inputDim, weightDim, stride, padding);
166  }
167  int computeOutputDim(int inputDim,
168  int weightDim,
169  int stride,
170  int padding) const {
171  return (inputDim - weightDim + padding) / stride + 1;
172  }
173 
174  public:
175  enum { Inputs, Kernels, kNumInputs };
176  enum { Outputs, kNumOutputs };
177 
178  protected:
179  int weightRows;
180  int weightCols;
181  int numOfmaps;
182  int rowStride;
183  int colStride;
184  PaddingType paddingType;
185  std::string weightsName;
186  SamplingInfo sampling;
187 };
188 
189 REGISTER_SPECIAL_OP(ConvolutionOp, ReferenceBackend);
190 
191 } // namespace smaug
192 
193 #endif
smaug::Tensor
Tensor represents a single multi-dimensional array of data.
Definition: tensor.h:344
_SamplingInfo
Simulation sampling information maintained by the Operator and passed to the accelerated kernel.
Definition: common.h:262
FRAC_CEIL
#define FRAC_CEIL(A, B)
Implements the ceiling function of A/B.
Definition: common.h:505
smaug::TensorShape
TensorShape describes the shape of a Tensor.
Definition: tensor.h:35
smaug::ConvolutionOp::getInputPadding
std::vector< int > getInputPadding() const
Compute padding sizes on the row/column boundaries of the input feature map.
Definition: convolution_op.h:143
smaug
The smaug namespace is the parent namespace of all C++ code in SMAUG.
Definition: backend.cpp:38
common.h
Utilities for writing and invoking Aladdin kernels from Operators.
smaug::ConvolutionOp::createWeightsTensors
void createWeightsTensors()
Create placeholder tensors for weights, assuming any data layout is okay.
Definition: convolution_op.h:98
smaug::Operator::validate
virtual bool validate()
Returns true if the parameters/tensors of this operator are all valid.
Definition: operator.h:47