1 #include "caffe2/operators/conv_op.h" 2 #include "caffe2/operators/conv_op_impl.h" 3 #include "caffe2/operators/conv_pool_op_base.h" 7 std::vector<TensorShape> TensorInferenceForConvGradient(
8 const OperatorDef& def,
9 const std::vector<TensorShape>& in) {
10 CAFFE_ENFORCE_EQ(in.size(), 3,
"ConvGradient requires 3 inputs");
12 if (in[0].unknown_shape()) {
13 std::vector<TensorShape> out(1);
14 out[0].set_unknown_shape(
true);
17 ArgumentHelper helper(def);
18 const auto no_bias = helper.GetSingleArgument<
int>(
"no_bias", 0);
19 const auto n_outputs = def.output_size();
20 vector<TensorShape> out(n_outputs);
25 vector<int64_t> bias_shape = {in[1].dims(0)};
26 out[1] = CreateTensorShape(bias_shape, in[1].data_type());
29 if (n_outputs == 3 || (no_bias && n_outputs == 2)) {
31 out[out.size() - 1] = in[0];
37 OpSchema::Cost CostInferenceForConvGradient(
38 const OperatorDef& def,
39 const vector<TensorShape>& inputs) {
40 CAFFE_ENFORCE_EQ(inputs.size(), 3,
"ConvGradient requires 3 inputs");
41 ArgumentHelper helper(def);
43 StringToStorageOrder(helper.GetSingleArgument<
string>(
"order",
"NCHW"));
44 const auto no_bias = helper.GetSingleArgument<
int>(
"no_bias", 0);
45 const auto n_outputs = def.output_size();
47 const auto& outputs = TensorInferenceForConvGradient(def, inputs);
48 const auto& X = inputs[0];
49 const auto& filter = inputs[1];
50 const auto& dY = inputs[2];
51 const auto N = X.dims(0);
52 const auto M = filter.dims(0);
54 (order == StorageOrder::NCHW ? X.dims(1) : X.dims(X.dims_size() - 1));
55 const auto output_image_size =
56 (order == StorageOrder::NCHW
58 : nElemBetweenDim(dY, 1, dY.dims_size() - 1));
60 (order == StorageOrder::NCHW
61 ? nElemFromDim(filter, 2)
62 : nElemBetweenDim(filter, 1, filter.dims_size() - 1));
64 struct OpSchema::Cost c;
65 c.flops = N * 2 *
M * kernel_elem *
C * output_image_size;
67 c.flops += N * (
M * output_image_size);
69 if (n_outputs == 3 || (no_bias && n_outputs == 2)) {
70 c.flops += N * 2 *
M * kernel_elem *
C * output_image_size;
73 c.bytes_read = (nElemFromDim(X) + nElemFromDim(filter) + nElemFromDim(dY)) *
76 for (
auto i = 0; i < n_outputs; i++) {
77 c.bytes_written += nElemFromDim(outputs[i]) *
sizeof(float);
79 c.params_bytes = nElemFromDim(filter) *
sizeof(float);
84 REGISTER_CPU_OPERATOR(ConvGradient, ConvGradientOp<float, CPUContext>);
85 OPERATOR_SCHEMA(ConvGradient)
88 .TensorInferenceFunction(TensorInferenceForConvGradient)
89 .CostInferenceFunction(CostInferenceForConvGradient);
91 REGISTER_CPU_OPERATOR(Conv1DGradient, ConvGradientOp<float, CPUContext>);
92 OPERATOR_SCHEMA(Conv1DGradient).NumInputs(2, 3).NumOutputs(1, 3);
94 REGISTER_CPU_OPERATOR(Conv2DGradient, ConvGradientOp<float, CPUContext>);
95 OPERATOR_SCHEMA(Conv2DGradient).NumInputs(2, 3).NumOutputs(1, 3);
97 REGISTER_CPU_OPERATOR(Conv3DGradient, ConvGradientOp<float, CPUContext>);
98 OPERATOR_SCHEMA(Conv3DGradient).NumInputs(2, 3).NumOutputs(1, 3);
101 using GradientMakerBase::GradientMakerBase;
102 vector<OperatorDef> GetGradientDefs()
override {
103 CAFFE_ENFORCE(def_.input_size() == 3 || def_.input_size() == 2);
107 auto compute_dX = !argsHelper.GetSingleArgument<
bool>(
"no_gradient_to_input", 0);
109 if (def_.input_size() == 3) {
112 def_.type() +
"Gradient",
114 vector<string>{I(0), I(1), GO(0)},
115 vector<string>{GI(1), GI(2), GI(0)});
118 def_.type() +
"Gradient",
120 vector<string>{I(0), I(1), GO(0)},
121 vector<string>{GI(1), GI(2)});
126 def_.type() +
"Gradient",
128 vector<string>{I(0), I(1), GO(0)},
129 vector<string>{GI(1), GI(0)},
130 vector<Argument>{MakeArgument<int>(
"no_bias", 1)});
133 def_.type() +
"Gradient",
135 vector<string>{I(0), I(1), GO(0)},
136 vector<string>{GI(1)},
137 vector<Argument>{MakeArgument<int>(
"no_bias", 1)});
A helper class to index into arguments.
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 ...