Caffe2 - C++ API
A deep learning, cross platform ML framework
backend.h
1 #pragma once
2 
3 #include "caffe2/onnx/backend_rep.h"
4 #include "caffe2/onnx/device.h"
5 #include "caffe2/onnx/helper.h"
6 #include "caffe2/proto/caffe2_pb.h"
7 #include "onnx/onnx_pb.h"
8 
9 #include <functional>
10 #include <string>
11 #include <unordered_map>
12 #include <unordered_set>
13 
14 constexpr int kKnownOpsetVersion = 9;
15 
16 namespace caffe2 {
17 namespace onnx {
18 
19 using ::ONNX_NAMESPACE::AttributeProto;
20 using ::ONNX_NAMESPACE::GraphProto;
21 using ::ONNX_NAMESPACE::ModelProto;
22 using ::ONNX_NAMESPACE::NodeProto;
23 using ::ONNX_NAMESPACE::TensorProto;
24 using ::ONNX_NAMESPACE::ValueInfoProto;
25 
26 using ValueInfoMap = std::unordered_map<std::string, ValueInfoProto>;
27 
28 class CAFFE2_API ConversionContext {
29  public:
30  ConversionContext(const ValueInfoMap& value_infos, int opset_version)
31  : value_infos_(value_infos), opset_version_(opset_version) {}
32  const ValueInfoMap& value_infos() const {
33  return value_infos_;
34  }
35  int opset_version() const {
36  return opset_version_;
37  }
38 
39  private:
40  const ValueInfoMap& value_infos_;
41  const int opset_version_;
42 };
43 
44 // \brief This struct holds the converted ops after the onnx->c2 conversion.
45 // Notice that for RNN ops, it may create ops in init_net. Hence we have the
46 // `init_ops` field.
47 struct CAFFE2_API Caffe2Ops {
48  ::google::protobuf::RepeatedPtrField<caffe2::OperatorDef> init_ops;
49  ::google::protobuf::RepeatedPtrField<caffe2::OperatorDef> ops;
50  ::google::protobuf::RepeatedPtrField<std::string> interface_blobs;
51 };
52 
53 // A convenient class to query attributes of a NodeProto. Note that the
54 // NodeProto can not be modified during the query of OnnxAttributes object
55 class CAFFE2_API OnnxAttributes {
56  public:
57  OnnxAttributes(const NodeProto& node);
58 
59  bool HasAttribute(const std::string& key) const {
60  return onnx_attrs_.count(key);
61  }
62 
63  AttributeProto* AddRewrittenAttribute(const std::string& key) {
64  auto tmp = rewritten_onnx_attrs_.emplace(key, AttributeProto());
65  auto& attr = tmp.first->second;
66  attr.set_name(key);
67  return &attr;
68  }
69 
70  ::google::protobuf::RepeatedPtrField<caffe2::Argument> OnnxAttrToCaffe2Arg(
71  std::function<std::string(const std::string&)> mapper) const;
72 
73  // Get attribute given attribute name, specialied on data type T. Note that
74  // the return value is copied
75  template <typename T>
76  T get(const std::string& key) const;
77 
78  template <typename T>
79  T get(const std::string& key, const T& default_value) const {
80  if (onnx_attrs_.count(key)) {
81  return get<T>(key);
82  } else {
83  return default_value;
84  }
85  }
86 
87  const AttributeProto* remove(const std::string& key) {
88  const AttributeProto* result = nullptr;
89  auto iter = onnx_attrs_.find(key);
90  if (iter != onnx_attrs_.end()) {
91  result = iter->second;
92  onnx_attrs_.erase(iter);
93  }
94  return result;
95  }
96 
97  private:
98  std::unordered_map<std::string, const AttributeProto*> onnx_attrs_;
99  std::unordered_map<std::string, AttributeProto> rewritten_onnx_attrs_;
100 };
101 
102 template <>
103 int64_t OnnxAttributes::get(const std::string& key) const;
104 template <>
105 float OnnxAttributes::get(const std::string& key) const;
106 
107 template <>
108 ::google::protobuf::RepeatedPtrField<std::string> OnnxAttributes::get(
109  const std::string& key) const;
110 
111 template <>
112 ::google::protobuf::RepeatedField<::google::protobuf::int64>
113 OnnxAttributes::get(const std::string& key) const;
114 
115 template <>
116 ::google::protobuf::RepeatedField<float>
117 OnnxAttributes::get(const std::string& key) const;
118 
119 template <>
120 const TensorProto* OnnxAttributes::get(const std::string& key) const;
121 
122 // convenient class for onnx node
123 struct CAFFE2_API OnnxNode {
124  OnnxNode(const NodeProto& node_in) : node(node_in), attributes(node_in) {}
125 
126  const NodeProto& node;
127 
128  OnnxAttributes attributes;
129 };
130 
131 class CAFFE2_API Caffe2Backend {
132  public:
133  // Since we still have this Python-C++ hybrid flow, we will need to take the
134  // DummyName generator from Python as a pointer. In this case, Python env owns
135  // the DummyName object and we don't need to keep track of its life time in
136  // C++. Therefore in this case, we use a null dtor to prevent C++ shared_ptr
137  // from releasing the object
138  Caffe2Backend(DummyName* dummy = nullptr) {
139  if (dummy) {
140  dummy_ = std::shared_ptr<DummyName>(dummy, [](DummyName *){});
141  } else {
142  dummy_ = std::make_shared<DummyName>();
143  }
144  }
145 
146  Caffe2BackendRep* Prepare(
147  const std::string& onnx_model_str,
148  const std::string& device,
149  const std::vector<Caffe2Ops>& extras);
150 
151  bool SupportOp(const std::string tyep) const;
152 
153  Caffe2Ops ConvertNode(
154  const std::string& node_str,
155  const ConversionContext& ctx);
156 
157  void BuildTensorFillingOp(
158  caffe2::OperatorDef* c2_op,
159  const TensorProto& onnx_tensor,
160  const std::string& output_name = "",
161  const std::string& shape_name = "");
162 
163  private:
164  using SpecialOpConverter =
166 
167  void OnnxToCaffe2(
168  caffe2::NetDef* init_net,
169  caffe2::NetDef* pred_net,
170  const ModelProto& onnx_model,
171  const std::string& device,
172  int opset_version,
173  bool include_initializers,
174  const std::vector<Caffe2Ops>& extras);
175 
176  void CheckOpSchemaArguments(const caffe2::OpSchema& schema, const caffe2::OperatorDef& op);
177 
178  Caffe2Ops OnnxNodeToCaffe2Ops(
179  const ModelProto& init_model,
180  const ModelProto& pred_model,
181  const ConversionContext& ctx,
182  OnnxNode* onnx_node);
183 
184  std::unordered_set<std::string> AllNamesInGraph(const GraphProto& graph);
185 
186  Caffe2Ops CommonOnnxNodeToCaffe2Ops(
187  OnnxNode* onnx_node,
188  const ConversionContext& ctx);
189 
190  Caffe2Ops CreateArgMaxMin(OnnxNode* onnx_node, const ConversionContext& ctx);
191 
192  Caffe2Ops CreateCast(OnnxNode* onnx_node, const ConversionContext& ctx);
193 
194  Caffe2Ops CreateConstant(OnnxNode* onnx_node, const ConversionContext& ctx);
195 
196  Caffe2Ops CreateConstantOfShape(
197  OnnxNode* onnx_node,
198  const ConversionContext& ctx);
199 
200  Caffe2Ops CreateConvPoolOpBase(
201  OnnxNode* onnx_node,
202  const ConversionContext& ctx);
203 
204  Caffe2Ops CreatePadPool(OnnxNode* onnx_node, const ConversionContext& ctx);
205 
206  Caffe2Ops CreateReshape(OnnxNode* onnx_node, const ConversionContext& ctx);
207 
208  Caffe2Ops CreateGather(OnnxNode* onnx_node, const ConversionContext& ctx);
209 
210  Caffe2Ops CreateGemm(OnnxNode* onnx_node, const ConversionContext& ctx);
211 
212  Caffe2Ops CreatePad(OnnxNode* onnx_node, const ConversionContext& ctx);
213 
214  Caffe2Ops CreateConcat(OnnxNode* onnx_node, const ConversionContext& ctx);
215 
216  Caffe2Ops CreateLogSoftmax(OnnxNode* onnx_node, const ConversionContext& ctx);
217 
218  Caffe2Ops CreateSlice(OnnxNode* onnx_node, const ConversionContext& ctx);
219 
220  std::string PreprocessSliceIndexTensor(OnnxNode* onnx_node,
221  Caffe2Ops& ret,
222  std::string indices_tensor,
223  std::string axes_tensor,
224  std::string rank_tensor,
225  std::string zero_tensor,
226  std::string one_tensor,
227  int default_value);
228 
229  Caffe2Ops CreateDynamicSlice(OnnxNode* onnx_node, const ConversionContext& ctx);
230 
231  Caffe2Ops CreateSplit(OnnxNode* onnx_node, const ConversionContext& ctx);
232 
233  Caffe2Ops CreateReciprocal(OnnxNode* onnx_node, const ConversionContext& ctx);
234 
235  Caffe2Ops CreateRandomNormal(
236  OnnxNode* onnx_node,
237  const ConversionContext& ctx);
238 
239  Caffe2Ops CreateBatchNormalization(
240  OnnxNode* onnx_node,
241  const ConversionContext& ctx);
242 
243  Caffe2Ops CreateMatMul(OnnxNode* onnx_node, const ConversionContext& ctx);
244 
245  Caffe2Ops CreateUpsample(OnnxNode* onnx_node, const ConversionContext& ctx);
246 
247  Caffe2Ops CreateDropout(OnnxNode* onnx_node, const ConversionContext& ctx);
248 
249  Caffe2Ops CreateLRN(OnnxNode* onnx_node, const ConversionContext& ctx);
250 
251  // LUT related getters
252  const std::unordered_map<std::string, std::string>& get_renamed_operators()
253  const;
254  const std::unordered_set<std::string>& get_rnn_operators() const;
255  const std::unordered_map<std::string, int>& get_broken_operators() const;
256  const std::unordered_map<std::string, std::string>& get_renamed_attrs() const;
257  const std::
258  unordered_map<std::string, std::unordered_map<std::string, std::string>>&
259  get_per_op_renamed_attrs() const;
260  const std::unordered_map<std::string, Caffe2Backend::SpecialOpConverter>&
261  get_special_operators() const;
262 
263  // Dummy name generator
264  std::shared_ptr<DummyName> dummy_;
265 };
266 
267 } // namespace onnx
268 } // namespace caffe2
A class to record the schema of an op.
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13