Caffe2 - C++ API
A deep learning, cross platform ML framework
relu_op.cc
1 #include "caffe2/operators/relu_op.h"
2 
3 #include <algorithm>
4 #include <functional>
5 #include <string>
6 
7 #include "caffe2/utils/eigen_utils.h"
8 
9 namespace caffe2 {
10 
11 template <>
12 template <typename T>
13 bool ReluFunctor<CPUContext>::
14 operator()(const int N, const T* X, T* Y, CPUContext* /* context */) const {
15  EigenVectorMap<T>(Y, N) = ConstEigenVectorMap<float>(X, N).cwiseMax(T(0));
16  return true;
17 }
18 
19 #ifdef CAFFE2_USE_ACCELERATE
20 
21 template <>
22 template <>
23 bool ReluFunctor<CPUContext>::operator()<float>(
24  const int N,
25  const float* X,
26  float* Y,
27  CPUContext* /* context */) const {
28  const float zero = 0.0f;
29  vDSP_vthres(X, 1, &zero, Y, 1, N);
30  return true;
31 }
32 
33 #endif // CAFFE2_USE_ACCELERATE
34 
35 template <>
36 template <typename T>
37 bool ReluGradientFunctor<CPUContext>::Forward(
38  const std::vector<int>& Y_dims,
39  const std::vector<int>& /* dY_dims */,
40  const T* Y,
41  const T* dY,
42  T* dX,
43  CPUContext* /* context */) const {
44  const int size = std::accumulate(
45  Y_dims.cbegin(), Y_dims.cend(), 1, std::multiplies<int>());
46  EigenVectorArrayMap<T>(dX, size) =
47  (ConstEigenVectorArrayMap<T>(Y, size) > T(0))
48  .select(ConstEigenVectorArrayMap<T>(dY, size), T(0));
49  return true;
50 }
51 
52 namespace {
53 
54 OpSchema::Cost CostInferenceForRelu(
55  const OperatorDef& def,
56  const vector<TensorShape>& in) {
57  struct OpSchema::Cost cost = PointwiseCostInference<0>(def, in);
58  cost.params_bytes = 0;
59  return cost;
60 }
61 
62 } // namespace
63 
64 REGISTER_CPU_OPERATOR(
65  Relu,
66  UnaryElementwiseOp<
67  TensorTypes<float>,
68  CPUContext,
69  ReluFunctor<CPUContext>>);
70 REGISTER_CPU_GRADIENT_OPERATOR(
71  ReluGradient,
72  BinaryElementwiseOp<
73  TensorTypes<float>,
74  CPUContext,
75  ReluGradientFunctor<CPUContext>>);
76 
77 // Input: X, output: Y
78 OPERATOR_SCHEMA(Relu)
79  .NumInputs(1)
80  .NumOutputs(1)
81  .AllowInplace({{0, 0}})
82  .CostInferenceFunction(CostInferenceForRelu)
83  .IdenticalTypeAndShape()
84  .SetDoc(R"DOC(
85 Applies rectified linear unit operation to the input data element-wise. The Relu operation takes one input $X$, produces one output $Y$, and is defined as:
86 
87 $$Y = max(0,X)$$
88 
89 Github Links:
90 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/relu_op.h
91 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/relu_op.cc
92 
93 <details>
94 
95 <summary> <b>Example</b> </summary>
96 
97 **Code**
98 
99 ```
100 workspace.ResetWorkspace()
101 
102 op = core.CreateOperator(
103  "Relu",
104  ["X"],
105  ["Y"]
106  )
107 
108 workspace.FeedBlob("X", np.random.randn(4, 4).astype(np.float32)) // NCHW
109 print("X:\n", workspace.FetchBlob("X"), "\n")
110 
111 workspace.RunOperatorOnce(op)
112 print("Y:\n", workspace.FetchBlob("Y"))
113 
114 ```
115 
116 **Result**
117 
118 ```
119 
120 X:
121  [[-1.4655551 0.64575136 0.7921748 0.4150579 ]
122  [ 0.41085166 -0.2837964 0.9881425 -1.9300346 ]
123  [ 0.39705405 0.44639114 0.9940703 0.2926532 ]
124  [-0.6726489 0.01330667 1.101319 0.33858967]]
125 
126 Y:
127  [[0. 0.64575136 0.7921748 0.4150579 ]
128  [0.41085166 0. 0.9881425 0. ]
129  [0.39705405 0.44639114 0.9940703 0.2926532 ]
130  [0. 0.01330667 1.101319 0.33858967]]
131 
132 ```
133 
134 </details>
135 
136 
137 )DOC")
138  .Input(0, "X", "1D input tensor")
139  .Output(0, "Y", "1D output tensor with same shape as input")
140  .InheritOnnxSchema();
141 
142 // Input: Y, dY, output: dX
143 GRADIENT_OPERATOR_SCHEMA(ReluGradient)
144  .NumInputs(2)
145  .NumOutputs(1)
146  .AllowInplace({{1, 0}})
147  .SetDoc(R"DOC(
148 ReluGradient takes both Y and dY and uses this to update dX according to the
149 chain rule and derivatives of the rectified linear function.
150 )DOC");
151 
152 namespace {
153 
154 class GetReluGradient : public GradientMakerBase {
155  using GradientMakerBase::GradientMakerBase;
156  std::vector<OperatorDef> GetGradientDefs() override {
157  return SingleGradientDef(
158  def_.type() + "Gradient",
159  "",
160  std::vector<std::string>{O(0), GO(0)},
161  std::vector<std::string>{GI(0)});
162  }
163 };
164 
165 } // namespace
166 
167 REGISTER_GRADIENT(Relu, GetReluGradient);
168 
169 } // namespace caffe2
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13
Definition: OpClasses.h:2