Caffe2 - C++ API
A deep learning, cross platform ML framework
relu_op.cc
1 #include "caffe2/operators/relu_op.h"
2 
3 #include "caffe2/utils/math.h"
4 
5 namespace caffe2 {
6 
7 template <>
8 bool ReluOp<float, CPUContext>::RunOnDevice() {
9  auto& X = Input(0);
10  auto* Y = Output(0);
11  Y->ResizeLike(X);
12 
13 #ifdef CAFFE2_USE_ACCELERATE
14  const float zero = 0.0f;
15  vDSP_vthres(X.data<float>(), 1, &zero, Y->mutable_data<float>(), 1, X.size());
16 #else
17  EigenVectorMap<float>(Y->mutable_data<float>(), X.size()) =
18  ConstEigenVectorMap<float>(X.data<float>(), X.size()).cwiseMax(0.f);
19 #endif
20  /* Naive implementation
21  const float* Xdata = X.data<float>();
22  float* Ydata = Y->mutable_data<float>();
23  for (int i = 0; i < X.size(); ++i) {
24  Ydata[i] = std::max(Xdata[i], 0.f);
25  }
26  */
27  return true;
28 }
29 
30 template <>
31 bool ReluGradientOp<float, CPUContext>::RunOnDevice() {
32  auto& Y = Input(0);
33  auto& dY = Input(1);
34  auto* dX = Output(0);
35  CAFFE_ENFORCE_EQ(dY.size(), Y.size());
36  dX->ResizeLike(Y);
37 
38  const float* Ydata = Y.data<float>();
39  const float* dYdata = dY.data<float>();
40  float* dXdata = dX->mutable_data<float>();
41  // TODO: proper vectorization with Eigen
42  EigenVectorArrayMap<float> dXvec(dXdata, dX->size());
43  ConstEigenVectorArrayMap<float> Yvec(Ydata, Y.size());
44  ConstEigenVectorArrayMap<float> dYvec(dYdata, dY.size());
45  dXvec = dYvec * Yvec.cwiseSign();
46  /* Previous implementation
47  for (int i = 0; i < Y.size(); ++i) {
48  dXdata[i] = Ydata[i] > 0 ? dYdata[i] : 0;
49  }
50  */
51  return true;
52 }
53 
54 namespace {
55 OpSchema::Cost CostInferenceForRelu(
56  const OperatorDef& def,
57  const vector<TensorShape>& in) {
58  struct OpSchema::Cost cost = PointwiseCostInference<0>(def, in);
59  cost.params_bytes = 0;
60  return cost;
61 }
62 } // namespace
63 
64 REGISTER_CPU_OPERATOR(Relu, ReluOp<float, CPUContext>);
65 REGISTER_CPU_OPERATOR(ReluGradient, ReluGradientOp<float, CPUContext>);
66 
67 // Input: X, output: Y
68 OPERATOR_SCHEMA(Relu)
69  .NumInputs(1)
70  .NumOutputs(1)
71  .AllowInplace({{0, 0}})
72  .CostInferenceFunction(CostInferenceForRelu)
73  .IdenticalTypeAndShape()
74  .SetDoc(R"DOC(
75 Relu takes one input data (Tensor<T>) and produces one output data
76 (Tensor<T>) where the rectified linear function, y = max(0, x), is applied to
77 the tensor elementwise.
78 )DOC")
79  .Input(0, "X", "1D input tensor")
80  .Output(0, "Y", "1D input tensor")
81  .InheritOnnxSchema("Relu");
82 
83 // Input: Y, dY, output: dX
84 OPERATOR_SCHEMA(ReluGradient)
85  .NumInputs(2)
86  .NumOutputs(1)
87  .AllowInplace({{1, 0}})
88  .SetDoc(R"DOC(
89 ReluGradient takes both Y and dY and uses this to update dX according to the
90 chain rule and derivatives of the rectified linear function.
91 )DOC");
92 
93 class GetReluGradient : public GradientMakerBase {
94  using GradientMakerBase::GradientMakerBase;
95  vector<OperatorDef> GetGradientDefs() override {
96  return SingleGradientDef(
97  def_.type() + "Gradient",
98  "",
99  vector<string>{O(0), GO(0)},
100  vector<string>{GI(0)});
101  }
102 };
103 REGISTER_GRADIENT(Relu, GetReluGradient);
104 REGISTER_GRADIENT(ReluFp16, GetReluGradient);
105 
106 } // namespace caffe2
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
static vector< OperatorDef > SingleGradientDef(const Args &...args)
a helper function to allow one to create one single operator def, which is usually the case for many ...