Caffe2 - C++ API
A deep learning, cross platform ML framework
locally_connected_op.cc
1 #include "caffe2/operators/locally_connected_op.h"
2 
3 #include <functional>
4 #include <vector>
5 
6 #include "caffe2/operators/locally_connected_op_impl.h"
7 
8 namespace caffe2 {
9 
10 namespace {
11 
12 constexpr char kLCDoc[] = R"DOC(
13 Note that other parameters, such as the stride and
14 kernel size, or the pads' sizes in each direction are not necessary for input
15 because they are provided by the ConvPoolOpBase operator. Various dimension
16 checks are done implicitly, and the sizes are specified in the Input docs for
17 this operator. As is expected, the filter is locally connected with a subset of
18 the image and the bias is added; this is done throughout the image data and the
19 output is computed. As a side note on the implementation layout:
20 locally_connected_op_impl.h is the templated implementation of the
21 locally_connected_op.h file, which is why they are separate files.
22 )DOC";
23 
24 std::function<void(OpSchema&)> LCDocGenerator(const char* dim) {
25  return [dim](OpSchema& schema) {
26  string doc = R"DOC(
27 The locally connected operator consumes an input vector, a {dim}filter blob
28 and a bias blob and computes the output. {lc_doc})DOC";
29  c10::ReplaceAll(doc, "{dim}", dim);
30  c10::ReplaceAll(doc, "{lc_doc}", kLCDoc);
31  schema.SetDoc(doc);
32  schema.Input(
33  1,
34  "filter",
35  "The filter blob that will be used in the locally connected op; "
36  "has size (YH * YW * M x C x kH x kW) if order == NCHW else "
37  "(YH * YW * M * KH * KW * C), where YH and YW are the height "
38  "and width of the output image, C is the number of channels, and kH "
39  "and kW are the height and width of the kernel.");
40  schema.Input(
41  2,
42  "bias",
43  "The 1D bias blob that is added through the locally connected op; "
44  "has size (YH * YW * M).");
45  schema.Output(
46  0,
47  "Y",
48  "Output data blob that contains the result of the locally connected op."
49  "The output dimensions are functions of the kernel size, stride size, "
50  "and pad lengths."
51  "");
52  };
53 }
54 
55 } // namespace
56 
57 REGISTER_CPU_OPERATOR(LC, LocallyConnectedOp<float, CPUContext>);
58 
59 OPERATOR_SCHEMA(LC)
60  .NumInputs(2, 3)
61  .NumOutputs(1)
62  .TensorInferenceFunction(ConvPoolOpBase<CPUContext>::TensorInferenceForLC)
63  .FillUsing(LCDocGenerator(""));
64 
65 REGISTER_CPU_OPERATOR(LC1D, LocallyConnectedOp<float, CPUContext>);
66 
67 OPERATOR_SCHEMA(LC1D)
68  .NumInputs(2, 3)
69  .NumOutputs(1)
70  .TensorInferenceFunction(ConvPoolOpBase<CPUContext>::TensorInferenceForLC)
71  .FillUsing(LCDocGenerator("1D "));
72 
73 REGISTER_CPU_OPERATOR(LC2D, LocallyConnectedOp<float, CPUContext>);
74 
75 OPERATOR_SCHEMA(LC2D)
76  .NumInputs(2, 3)
77  .NumOutputs(1)
78  .TensorInferenceFunction(ConvPoolOpBase<CPUContext>::TensorInferenceForLC)
79  .FillUsing(LCDocGenerator("2D "));
80 
81 REGISTER_CPU_OPERATOR(LC3D, LocallyConnectedOp<float, CPUContext>);
82 
83 OPERATOR_SCHEMA(LC3D)
84  .NumInputs(2, 3)
85  .NumOutputs(1)
86  .TensorInferenceFunction(ConvPoolOpBase<CPUContext>::TensorInferenceForLC)
87  .FillUsing(LCDocGenerator("3D "));
88 
89 REGISTER_CPU_OPERATOR(
90  LCGradient,
91  LocallyConnectedGradientOp<float, CPUContext>);
92 
93 OPERATOR_SCHEMA(LCGradient).NumInputs(2, 3).NumOutputs(1, 3);
94 
95 REGISTER_CPU_OPERATOR(
96  LC1DGradient,
97  LocallyConnectedGradientOp<float, CPUContext>);
98 
99 OPERATOR_SCHEMA(LC1DGradient).NumInputs(2, 3).NumOutputs(1, 3);
100 
101 REGISTER_CPU_OPERATOR(
102  LC2DGradient,
103  LocallyConnectedGradientOp<float, CPUContext>);
104 
105 OPERATOR_SCHEMA(LC2DGradient).NumInputs(2, 3).NumOutputs(1, 3);
106 
107 REGISTER_CPU_OPERATOR(
108  LC3DGradient,
109  LocallyConnectedGradientOp<float, CPUContext>);
110 
111 OPERATOR_SCHEMA(LC3DGradient).NumInputs(2, 3).NumOutputs(1, 3);
112 
113 namespace {
114 
115 class GetLocallyConnectedGradient : public GradientMakerBase {
116  using GradientMakerBase::GradientMakerBase;
117 
118  std::vector<OperatorDef> GetGradientDefs() override {
119  CAFFE_ENFORCE(def_.input_size() == 3 || def_.input_size() == 2);
120  ArgumentHelper argsHelper(def_);
121  const bool compute_dX =
122  !argsHelper.GetSingleArgument<bool>("no_gradient_to_input", 0);
123 
124  if (def_.input_size() == 3) {
125  if (compute_dX) {
126  return SingleGradientDef(
127  def_.type() + "Gradient",
128  "",
129  std::vector<string>{I(0), I(1), GO(0)},
130  std::vector<string>{GI(1), GI(2), GI(0)});
131  } else {
132  return SingleGradientDef(
133  def_.type() + "Gradient",
134  "",
135  std::vector<string>{I(0), I(1), GO(0)},
136  std::vector<string>{GI(1), GI(2)});
137  }
138  } else {
139  if (compute_dX) {
140  return SingleGradientDef(
141  def_.type() + "Gradient",
142  "",
143  std::vector<string>{I(0), I(1), GO(0)},
144  std::vector<string>{GI(1), GI(0)},
145  std::vector<Argument>{MakeArgument<int>("no_bias", 1)});
146  } else {
147  return SingleGradientDef(
148  def_.type() + "Gradient",
149  "",
150  std::vector<string>{I(0), I(1), GO(0)},
151  std::vector<string>{GI(1)},
152  std::vector<Argument>{MakeArgument<int>("no_bias", 1)});
153  }
154  }
155  }
156 };
157 
158 } // namespace
159 
160 REGISTER_GRADIENT(LC, GetLocallyConnectedGradient);
161 REGISTER_GRADIENT(LC1D, GetLocallyConnectedGradient);
162 REGISTER_GRADIENT(LC2D, GetLocallyConnectedGradient);
163 REGISTER_GRADIENT(LC3D, GetLocallyConnectedGradient);
164 
165 } // namespace caffe2
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13