Caffe2 - C++ API
A deep learning, cross platform ML framework
clip_op.cc
1 #include "caffe2/operators/clip_op.h"
2 #include "caffe2/utils/eigen_utils.h"
3 
4 namespace caffe2 {
5 
6 template <>
7 bool ClipOp<float, CPUContext>::RunOnDevice() {
8  auto& X = Input(0);
9 
10  auto* Y = Output(0, X.sizes(), at::dtype<float>());
11  EigenVectorMap<float>(Y->template mutable_data<float>(), Y->numel()) =
12  ConstEigenVectorMap<float>(X.data<float>(), X.numel())
13  .cwiseMax(min_)
14  .cwiseMin(max_);
15  return true;
16 }
17 
18 template <>
19 bool ClipGradientOp<float, CPUContext>::RunOnDevice() {
20  auto& Y = Input(0);
21  auto& dY = Input(1);
22 
23  CAFFE_ENFORCE_GE(Y.numel(), 0);
24  CAFFE_ENFORCE_EQ(dY.numel(), Y.numel());
25  auto* dX = Output(0, Y.sizes(), at::dtype<float>());
26  const float* Ydata = Y.data<float>();
27  const float* dYdata = dY.data<float>();
28  float* dXdata = dX->template mutable_data<float>();
29  for (int i = 0; i < Y.numel(); ++i) {
30  dXdata[i] = dYdata[i] * (Ydata[i] > min_ && Ydata[i] < max_);
31  }
32  return true;
33 }
34 
35 REGISTER_CPU_OPERATOR(Clip, ClipOp<float, CPUContext>);
36 REGISTER_CPU_GRADIENT_OPERATOR(ClipGradient, ClipGradientOp<float, CPUContext>);
37 
38 OPERATOR_SCHEMA(Clip)
39  .NumInputs(1)
40  .NumOutputs(1)
41  .AllowInplace({{0, 0}})
42  .IdenticalTypeAndShape()
43  .SetDoc(R"DOC(
44 This operator limits the given input within an interval. The interval is
45 specified by the `min` and `max` arguments. They default to
46 *numeric_limits::lowest()* and *numeric_limits::max()* respectively. The
47 clipping operation can be done in an in-place fashion by using the same output
48 blob as the input blob.
49 
50 Github Links:
51 
52 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/clip_op.cc
53 
54 <details>
55 
56 <summary> <b>Example</b> </summary>
57 
58 **Code**
59 
60 ```
61 workspace.ResetWorkspace()
62 
63 op = core.CreateOperator(
64  "Clip",
65  ["X"],
66  ["Y"],
67  min=20.0,
68  max=60.0
69 
70 )
71 
72 workspace.FeedBlob("X", (np.random.randint(100, size=(5,5))).astype(np.float32))
73 print("X:", workspace.FetchBlob("X"))
74 workspace.RunOperatorOnce(op)
75 print("Y:", workspace.FetchBlob("Y"))
76 
77 ```
78 
79 **Result**
80 
81 ```
82 X: [[45. 16. 59. 99. 48.]
83  [12. 44. 46. 82. 28.]
84  [ 1. 91. 18. 9. 71.]
85  [24. 37. 61. 12. 81.]
86  [36. 38. 30. 84. 40.]]
87 Y: [[45. 20. 59. 60. 48.]
88  [20. 44. 46. 60. 28.]
89  [20. 60. 20. 20. 60.]
90  [24. 37. 60. 20. 60.]
91  [36. 38. 30. 60. 40.]]
92 ```
93 
94 </details>
95 
96 )DOC")
97  .Arg(
98  "min",
99  "*(type: float)* Minimum value, under which element is "
100  "replaced by min (default=*numeric_limits::lowest()*).")
101  .Arg(
102  "max",
103  "*(type: float)* Maximum value, under which element is "
104  "replaced by max (default=*numeric_limits::max()*).")
105  .Input(
106  0,
107  "X",
108  "*(Tensor`<float>`)* Input tensor within range "
109  "[*numeric_limits::lowest()*, *numeric_limits::max()*].")
110  .Output(
111  0,
112  "Y",
113  "*(Tensor`<float>`)* Output tensor clipped within range [`min`, `max`].")
114  .InheritOnnxSchema();
115 
116 GRADIENT_OPERATOR_SCHEMA(ClipGradient)
117  .NumInputs(2)
118  .NumOutputs(1)
119  .AllowInplace({{1, 0}});
120 
121 class GetClipGradient : public GradientMakerBase {
122  using GradientMakerBase::GradientMakerBase;
123  vector<OperatorDef> GetGradientDefs() override {
124  return SingleGradientDef(
125  "ClipGradient", "",
126  vector<string>{O(0), GO(0)},
127  vector<string>{GI(0)});
128  }
129 };
130 REGISTER_GRADIENT(Clip, GetClipGradient);
131 } // namespace caffe2
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13