Caffe2 - C++ API
A deep learning, cross platform ML framework
expand_squeeze_dims_op.cc
1 #include "caffe2/operators/expand_squeeze_dims_op.h"
2 
3 namespace caffe2 {
4 REGISTER_CPU_OPERATOR(ExpandDims, ExpandDimsOp<CPUContext>);
5 REGISTER_CPU_OPERATOR(Squeeze, SqueezeOp<CPUContext>);
6 
7 OPERATOR_SCHEMA(ExpandDims)
8  .NumInputs(1)
9  .NumOutputs(1)
10  .AllowInplace({{0, 0}})
11  .TensorInferenceFunction([](const OperatorDef& def,
12  const vector<TensorShape>& in) {
13  ArgumentHelper helper(def);
14  auto dims = helper.template GetRepeatedArgument<int>("dims");
15  auto originalSize = dims.size();
16  CAFFE_ENFORCE(originalSize > 0, "Parameter `dims` must be provided.");
17 
18  std::sort(dims.begin(), dims.end());
19  dims.erase(std::unique(dims.begin(), dims.end()), dims.end());
20  if (dims.size() < originalSize) {
21  LOG(WARNING) << "Parameter `dims` has repeated dimensions.";
22  }
23 
24  CAFFE_ENFORCE(dims.front() >= 0, "Dimension ids must be non-negative.");
25  CAFFE_ENFORCE_GE(
26  in[0].dims_size() + dims.size(),
27  dims.back() + 1,
28  "Input needs at least ",
29  (1 + dims.back() - dims.size()),
30  " dimensions given `dims`.");
31 
32  vector<TensorShape> out(1);
33 
34  int cur_pos = 0;
35  int idx = 0;
36  for (const auto new_dim : dims) {
37  for (int i = cur_pos; i < new_dim; i++) {
38  out[0].add_dims(in[0].dims(idx++));
39  }
40  out[0].add_dims(1);
41  cur_pos = new_dim + 1;
42  }
43  for (; idx < in[0].dims_size(); idx++) {
44  out[0].add_dims(in[0].dims(idx));
45  }
46  out[0].set_data_type(in[0].data_type());
47  return out;
48  })
49  .SetDoc(R"DOC(
50 The *ExpandDims* op inserts single-dimensional entries into the shape of the input tensor *data,* and produces a single output tensor *expanded*. The op also takes an argument *dims* with a list of dimensions for where to add the single dimensional entries. If the same blob is provided as input and output, the operation is copy-free. This is the exact inverse operation of *Squeeze*.
51 
52 Github Links:
53 
54 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/expand_squeeze_dims_op.h
55 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/expand_squeeze_dims_op.cc
56 
57 
58 <details>
59 
60 <summary> <b>Example</b> </summary>
61 
62 **Code**
63 
64 ```
65 
66 workspace.ResetWorkspace()
67 
68 op = core.CreateOperator(
69  "ExpandDims",
70  ["data"],
71  ["expanded"],
72  dims=[0,1],
73 )
74 
75 workspace.FeedBlob("data", np.zeros((100,100)).astype(np.float32))
76 print("data.shape:", workspace.FetchBlob("data").shape)
77 
78 workspace.RunOperatorOnce(op)
79 print("expanded.shape:", workspace.FetchBlob("expanded").shape)
80 
81 ```
82 
83 **Result**
84 
85 ```
86 
87 data.shape: (100, 100)
88 expanded.shape: (1, 1, 100, 100)
89 
90 ```
91 
92 </details>
93 
94 
95 
96 )DOC")
97  .Input(0, "data", "Input tensor of data to be operated on.")
98  .Output(0, "expanded", "Reshaped tensor with same data as input.")
99  .Arg(
100  "dims",
101  "*(type: [int])* List of dimensions of *data* to add single dimensional entry.")
102  .InheritOnnxSchema();
103 
104 OPERATOR_SCHEMA(Squeeze)
105  .NumInputs(1)
106  .NumOutputs(1)
107  .AllowInplace({{0, 0}})
108  .SetDoc(R"DOC(
109 The *Squeeze* op removes single-dimensional entries from the shape of the input tensor *data,* and produces a single output tensor *squeezed*. The op also takes an argument *dims* with a list of dimensions to squeeze. If the same blob is provided as input and output, the operation is copy-free. This is the exact inverse operation of *ExpandDims* given the same *dims* argument.
110 
111 Github Links:
112 
113 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/expand_squeeze_dims_op.h
114 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/expand_squeeze_dims_op.cc
115 
116 
117 <details>
118 
119 <summary> <b>Example</b> </summary>
120 
121 **Code**
122 
123 ```
124 
125 workspace.ResetWorkspace()
126 
127 op = core.CreateOperator(
128  "Squeeze",
129  ["data"],
130  ["squeezed"],
131  dims=[0,1],
132 )
133 
134 workspace.FeedBlob("data", np.zeros((1,1,100,100)).astype(np.float32))
135 print("data.shape:", workspace.FetchBlob("data").shape)
136 
137 workspace.RunOperatorOnce(op)
138 print("squeezed.shape:", workspace.FetchBlob("squeezed").shape)
139 
140 ```
142 **Result**
143 
144 ```
145 
146 data.shape: (1, 1, 100, 100)
147 squeezed.shape: (100, 100)
148 
149 ```
150 
151 </details>
152 
153 )DOC")
154  .Input(0, "data", "Input tensor of data to be operated on.")
155  .Output(0, "squeezed", "Reshaped tensor with same data as input.")
156  .Arg("dims", "*(type: [int])* List of dimensions of *data* to squeeze out.")
157  .TensorInferenceFunction([](const OperatorDef& def,
158  const vector<TensorShape>& in) {
159  ArgumentHelper helper(def);
160  auto dims = helper.template GetRepeatedArgument<int>("dims");
161  auto originalSize = dims.size();
162  std::sort(dims.begin(), dims.end());
163  dims.erase(std::unique(dims.begin(), dims.end()), dims.end());
164  if (dims.size() < originalSize) {
165  LOG(WARNING) << "Parameter `dims` has repeated dimensions.";
166  }
167  CAFFE_ENFORCE(dims.front() >= 0, "Dimension ids must be non-negative.");
168 
169  vector<TensorShape> out(1);
170  std::vector<int> newDims =
171  SqueezeOp<CPUContext>::ComputeDims(GetDimsVector(in[0]), dims);
172  out[0] = CreateTensorShape(newDims, in[0].data_type());
173  return out;
174  })
175  .InheritOnnxSchema();
176 
177 class GetSqueezeGradient : public GradientMakerBase {
178  using GradientMakerBase::GradientMakerBase;
179  vector<OperatorDef> GetGradientDefs() override {
180  return SingleGradientDef(
181  "ExpandDims", "", vector<string>{GO(0)}, vector<string>{GI(0)});
182  }
183 };
184 REGISTER_GRADIENT(Squeeze, GetSqueezeGradient);
185 
187  using GradientMakerBase::GradientMakerBase;
188  vector<OperatorDef> GetGradientDefs() override {
189  return SingleGradientDef(
190  "Squeeze", "", vector<string>{GO(0)}, vector<string>{GI(0)});
191  }
192 };
193 REGISTER_GRADIENT(ExpandDims, GetExpandDimsGradient);
194 }
A helper class to index into arguments.
Definition: proto_utils.h:200
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 ...