Caffe2 - C++ API
A deep learning, cross platform ML framework
softplus_op.cc
1 #include "caffe2/operators/softplus_op.h"
2 
3 #include "caffe2/utils/eigen_utils.h"
4 #include "caffe2/utils/math.h"
5 
6 namespace caffe2 {
7 
8 template <>
9 bool SoftplusOp<float, CPUContext>::RunOnDevice() {
10  auto& X = Input(0);
11 
12  auto* Y = Output(0, X.sizes(), at::dtype<float>());
13 
14  EigenVectorMap<float>(Y->template mutable_data<float>(), X.numel()) =
15  (ConstEigenVectorMap<float>(X.data<float>(), X.numel()).array().exp() +
16  1.0f)
17  .log();
18  return true;
19 }
20 
21 template <>
22 bool SoftplusGradientOp<float, CPUContext>::RunOnDevice() {
23  auto& Y = Input(0);
24  auto& dY = Input(1);
25 
26  DCHECK_EQ(dY.numel(), Y.numel());
27  auto* dX = Output(0, Y.sizes(), at::dtype<float>());
28 
29  const float* Ydata = Y.data<float>();
30  const float* dYdata = dY.data<float>();
31  float* dXdata = dX->template mutable_data<float>();
32  EigenVectorArrayMap<float> dXvec(dXdata, dX->numel());
33  ConstEigenVectorArrayMap<float> Yvec(Ydata, Y.numel());
34  ConstEigenVectorArrayMap<float> dYvec(dYdata, dY.numel());
35  dXvec = dYvec * (1.0 - (-Yvec).exp());
36  return true;
37 }
38 
39 REGISTER_CPU_OPERATOR(Softplus, SoftplusOp<float, CPUContext>);
40 REGISTER_CPU_OPERATOR(SoftplusGradient, SoftplusGradientOp<float, CPUContext>);
41 
42 // Input: X, output: Y
43 OPERATOR_SCHEMA(Softplus)
44  .NumInputs(1)
45  .NumOutputs(1)
46  .AllowInplace({{0, 0}})
47  .IdenticalTypeAndShape()
48  .SetDoc(R"DOC(
49 Softplus takes one input data tensor $X$ and produces one output data tensor $Y,$ where the softplus function, $y = ln(e^x + 1)$, is applied to $X$ elementwise.
50 
51 Github Links:
52 
53 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/softplus_op.h
54 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/softplus_op.cc
55 
56 
57 <details>
58 
59 <summary> <b>Example</b> </summary>
60 
61 **Code**
62 
63 ```
64 
65 workspace.ResetWorkspace()
66 
67 op = core.CreateOperator(
68  "Softplus",
69  ["X"],
70  ["Y"],
71 )
72 
73 workspace.FeedBlob("X", np.random.randn(3, 3).astype(np.float32))
74 print("X:\n", workspace.FetchBlob("X"), "\n")
75 
76 workspace.RunOperatorOnce(op)
77 print("Y:\n", workspace.FetchBlob("Y"))
78 
79 ```
80 
81 **Result**
82 
83 ```
84 
85 X:
86  [[-0.5380011 0.65190786 0.55673236]
87  [-0.16272168 0.5451048 0.30880353]
88  [-0.76606876 -0.6238556 -0.40444514]]
89 
90 Y:
91  [[0.4598992 1.0713093 1.0097669 ]
92  [0.61509246 1.0023911 0.8594219 ]
93  [0.38174385 0.42909983 0.5112337 ]]
94 
95 ```
96 
97 </details>
98 
99 )DOC")
100  .Input(0, "X", "Input data blob to be operated on.")
101  .Output(0, "Y", "Output data blob with same shape as input.")
102  .InheritOnnxSchema();
103 
104 // Input: Y, dY, output: dX
105 OPERATOR_SCHEMA(SoftplusGradient)
106  .NumInputs(2)
107  .NumOutputs(1)
108  .AllowInplace({{1, 0}});
109 
111  using GradientMakerBase::GradientMakerBase;
112  vector<OperatorDef> GetGradientDefs() override {
113  return SingleGradientDef(
114  "SoftplusGradient",
115  "",
116  vector<string>{O(0), GO(0)},
117  vector<string>{GI(0)});
118  }
119 };
120 REGISTER_GRADIENT(Softplus, GetSoftplusGradient);
121 
122 } // namespace caffe2
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13
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 ...