1 #include "elementwise_linear_op.h" 6 bool ElementwiseLinearOp<float, CPUContext>::RunOnDevice(){
7 const auto& X = Input(0);
8 const auto& a = Input(1);
9 const auto& b = Input(2);
11 const auto canonical_axis = X.canonical_axis_index(axis_);
12 const int N = X.size_to_dim(canonical_axis);
13 const int D = X.size_from_dim(canonical_axis);
15 CAFFE_ENFORCE_EQ(a.dim(), 1, a.dim());
16 CAFFE_ENFORCE_EQ(a.size(0), D, a.dim());
17 CAFFE_ENFORCE_EQ(b.dim(), 1, b.dim());
18 CAFFE_ENFORCE_EQ(b.size(0), D, b.dim());
20 auto* Y = Output(0, X.sizes(), at::dtype<float>());
22 const float* X_data = X.data<
float>();
23 const float* a_data = a.data<
float>();
24 const float* b_data = b.data<
float>();
25 float* Y_data = Y->template mutable_data<float>();
28 for (
int n = 0; n < N; ++n) {
29 for (
int d = 0; d < D; ++d) {
30 Y_data[p] = X_data[p] * a_data[d] + b_data[d];
38 bool ElementwiseLinearGradientOp<float, CPUContext>::RunOnDevice(){
39 const auto& g_o = Input(0);
40 const auto& X = Input(1);
41 const auto& a = Input(2);
43 const auto canonical_axis = X.canonical_axis_index(axis_);
44 const int N = X.size_to_dim(canonical_axis);
45 const int D = X.size_from_dim(canonical_axis);
47 CAFFE_ENFORCE_EQ(a.dim(), 1, a.dim());
48 CAFFE_ENFORCE_EQ(a.size(0), D, a.dim());
50 auto* g_X = Output(0, X.sizes(), at::dtype<float>());
51 auto* g_a = Output(1, a.sizes(), at::dtype<float>());
52 auto* g_b = Output(2, a.sizes(), at::dtype<float>());
54 const float* g_o_data = g_o.data<
float>();
55 const float* X_data = X.data<
float>();
56 const float* a_data = a.data<
float>();
57 float* g_X_data = g_X->template mutable_data<float>();
58 float* g_a_data = g_a->template mutable_data<float>();
59 float* g_b_data = g_b->template mutable_data<float>();
61 math::Set<float, CPUContext>(g_a->numel(), 0.f, g_a_data, &context_);
62 math::Set<float, CPUContext>(g_b->numel(), 0.f, g_b_data, &context_);
65 for (
int n = 0; n < N; ++n) {
66 for (
int d = 0; d < D; ++d) {
67 g_X_data[p] = g_o_data[p] * a_data[d];
68 g_a_data[d] += g_o_data[p] * X_data[p];
69 g_b_data[d] += g_o_data[p];
76 REGISTER_CPU_OPERATOR(
78 ElementwiseLinearOp<float, CPUContext>);
79 REGISTER_CPU_OPERATOR(
80 ElementwiseLinearGradient,
81 ElementwiseLinearGradientOp<float, CPUContext>);
83 OPERATOR_SCHEMA(ElementwiseLinear)
87 This op computes the elementwise linear combination of a batch of input vectors with a weight vector and bias vector. As input, the op takes an input tensor $X$ of shape $NxD$, a weight vector $w$ of length $D$, and a bias vector $b$ of length $D$. Here, $N$ represents the batch size and $D$ represents the length of the feature vectors. The output, $Y$, is a tensor of shape $NxD$ and is calculated as 89 $$Y_{ij} = X_{ij}w_j + b_j \ for \ i\in{N}, j\in{D}$$ 92 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/elementwise_linear_op.h 93 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/elementwise_linear_op.cc 97 <summary> <b>Example</b> </summary> 103 workspace.ResetWorkspace() 105 op = core.CreateOperator( 112 X = np.array([[1,2,3,4,5],[6,8,9,16,10]]) 116 w = np.array([1,1/2.,1/3.,1/4.,1/5.]) 120 b = np.array([1.,1.,1.,1.,1.]) 124 // Feed X & w & b into workspace 125 workspace.FeedBlob("X", X.astype(np.float32)) 126 workspace.FeedBlob("w", w.astype(np.float32)) 127 workspace.FeedBlob("b", b.astype(np.float32)) 130 workspace.RunOperatorOnce(op) 133 print("Y:\n", workspace.FetchBlob("Y")) 145 [1. 0.5 0.33333333 0.25 0.2] 160 "2D input tensor of size $NxD$. This input represents the input data to be operated on.")
164 "1D scaling factors, or weights, of size $D$. This input contains the weights that will be multiplied by the data.")
168 "1D biases of size $D$. This input contains the biases that will be added to the products of the weights and data.")
172 "2D output tensor of size $NxD$. Calculated as described above.")
175 "*(type: int; default: 1)* Describes the axis of the inputs; defaults to one because the 0th axis most likely describes the batch size.")
176 .InheritOnnxSchema();
178 OPERATOR_SCHEMA(ElementwiseLinearGradient)
183 using GradientMakerBase::GradientMakerBase;
184 vector<OperatorDef> GetGradientDefs()
override {
186 "ElementwiseLinearGradient",
188 vector<string>{GO(0), I(0), I(1)},
189 vector<string>{GI(0), GI(1), GI(2)});
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 ...