| #pragma once |
| |
| #include "caffe2/onnx/backend_rep.h" |
| #include "caffe2/onnx/device.h" |
| #include "caffe2/onnx/helper.h" |
| #include "caffe2/proto/caffe2_pb.h" |
| #include "onnx/onnx_pb.h" |
| |
| #include <functional> |
| #include <string> |
| #include <unordered_map> |
| #include <unordered_set> |
| |
| constexpr int kKnownOpsetVersion = 9; |
| |
| namespace caffe2 { |
| namespace onnx { |
| |
| using ::ONNX_NAMESPACE::AttributeProto; |
| using ::ONNX_NAMESPACE::GraphProto; |
| using ::ONNX_NAMESPACE::ModelProto; |
| using ::ONNX_NAMESPACE::NodeProto; |
| using ::ONNX_NAMESPACE::TensorProto; |
| using ::ONNX_NAMESPACE::ValueInfoProto; |
| |
| using ValueInfoMap = std::unordered_map<std::string, ValueInfoProto>; |
| |
| class TORCH_API ConversionContext { |
| public: |
| ConversionContext(const ValueInfoMap& value_infos, int opset_version) |
| : value_infos_(value_infos), opset_version_(opset_version) {} |
| const ValueInfoMap& value_infos() const { |
| return value_infos_; |
| } |
| int opset_version() const { |
| return opset_version_; |
| } |
| |
| private: |
| const ValueInfoMap& value_infos_; |
| const int opset_version_; |
| }; |
| |
| // \brief This struct holds the converted ops after the onnx->c2 conversion. |
| // Notice that for RNN ops, it may create ops in init_net. Hence we have the |
| // `init_ops` field. |
| struct TORCH_API Caffe2Ops { |
| ::google::protobuf::RepeatedPtrField<caffe2::OperatorDef> init_ops; |
| ::google::protobuf::RepeatedPtrField<caffe2::OperatorDef> ops; |
| ::google::protobuf::RepeatedPtrField<std::string> interface_blobs; |
| }; |
| |
| // A convenient class to query attributes of a NodeProto. Note that the |
| // NodeProto can not be modified during the query of OnnxAttributes object |
| class TORCH_API OnnxAttributes { |
| public: |
| OnnxAttributes(const NodeProto& node); |
| |
| bool HasAttribute(const std::string& key) const { |
| return onnx_attrs_.count(key); |
| } |
| |
| AttributeProto* AddRewrittenAttribute(const std::string& key) { |
| auto tmp = rewritten_onnx_attrs_.emplace(key, AttributeProto()); |
| auto& attr = tmp.first->second; |
| attr.set_name(key); |
| return &attr; |
| } |
| |
| ::google::protobuf::RepeatedPtrField<caffe2::Argument> OnnxAttrToCaffe2Arg( |
| std::function<std::string(const std::string&)> mapper) const; |
| |
| // Get attribute given attribute name, specialied on data type T. Note that |
| // the return value is copied |
| template <typename T> |
| T get(const std::string& key) const; |
| |
| template <typename T> |
| T get(const std::string& key, const T& default_value) const { |
| if (onnx_attrs_.count(key)) { |
| return get<T>(key); |
| } else { |
| return default_value; |
| } |
| } |
| |
| const AttributeProto* remove(const std::string& key) { |
| const AttributeProto* result = nullptr; |
| auto iter = onnx_attrs_.find(key); |
| if (iter != onnx_attrs_.end()) { |
| result = iter->second; |
| onnx_attrs_.erase(iter); |
| } |
| return result; |
| } |
| |
| private: |
| std::unordered_map<std::string, const AttributeProto*> onnx_attrs_; |
| std::unordered_map<std::string, AttributeProto> rewritten_onnx_attrs_; |
| }; |
| |
| template <> |
| int64_t OnnxAttributes::get(const std::string& key) const; |
| template <> |
| float OnnxAttributes::get(const std::string& key) const; |
| |
| template <> |
| ::google::protobuf::RepeatedPtrField<std::string> OnnxAttributes::get( |
| const std::string& key) const; |
| |
| template <> |
| ::google::protobuf::RepeatedField<::google::protobuf::int64> |
| OnnxAttributes::get(const std::string& key) const; |
| |
| template <> |
| ::google::protobuf::RepeatedField<float> OnnxAttributes::get( |
| const std::string& key) const; |
| |
| template <> |
| const TensorProto* OnnxAttributes::get(const std::string& key) const; |
| |
| // convenient class for onnx node |
| struct TORCH_API OnnxNode { |
| OnnxNode(const NodeProto& node_in) : node(node_in), attributes(node_in) {} |
| |
| const NodeProto& node; |
| |
| OnnxAttributes attributes; |
| }; |
| |
| class TORCH_API Caffe2Backend { |
| public: |
| // Since we still have this Python-C++ hybrid flow, we will need to take the |
| // DummyName generator from Python as a pointer. In this case, Python env owns |
| // the DummyName object and we don't need to keep track of its life time in |
| // C++. Therefore in this case, we use a null dtor to prevent C++ shared_ptr |
| // from releasing the object |
| Caffe2Backend(DummyName* dummy = nullptr) { |
| if (dummy) { |
| dummy_ = std::shared_ptr<DummyName>(dummy, [](DummyName*) {}); |
| } else { |
| dummy_ = std::make_shared<DummyName>(); |
| } |
| } |
| |
| Caffe2BackendRep* Prepare( |
| const std::string& onnx_model_str, |
| const std::string& device, |
| const std::vector<Caffe2Ops>& extras); |
| |
| bool SupportOp(const std::string tyep) const; |
| |
| Caffe2Ops ConvertNode( |
| const std::string& node_str, |
| const ConversionContext& ctx); |
| |
| void BuildTensorFillingOp( |
| caffe2::OperatorDef* c2_op, |
| const TensorProto& onnx_tensor, |
| const std::string& output_name = "", |
| const std::string& shape_name = ""); |
| |
| private: |
| using SpecialOpConverter = |
| Caffe2Ops (Caffe2Backend::*)(OnnxNode*, const ConversionContext&); |
| |
| void OnnxToCaffe2( |
| caffe2::NetDef* init_net, |
| caffe2::NetDef* pred_net, |
| const ModelProto& onnx_model, |
| const std::string& device, |
| int opset_version, |
| bool include_initializers, |
| const std::vector<Caffe2Ops>& extras); |
| |
| void CheckOpSchemaArguments( |
| const caffe2::OpSchema& schema, |
| const caffe2::OperatorDef& op); |
| |
| Caffe2Ops OnnxNodeToCaffe2Ops( |
| const ModelProto& init_model, |
| const ModelProto& pred_model, |
| const ConversionContext& ctx, |
| OnnxNode* onnx_node); |
| |
| std::unordered_set<std::string> AllNamesInGraph(const GraphProto& graph); |
| |
| Caffe2Ops CommonOnnxNodeToCaffe2Ops( |
| OnnxNode* onnx_node, |
| const ConversionContext& ctx); |
| |
| Caffe2Ops CreateArgMaxMin(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateCast(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateConstant(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateConstantOfShape( |
| OnnxNode* onnx_node, |
| const ConversionContext& ctx); |
| |
| Caffe2Ops CreateConvPoolOpBase( |
| OnnxNode* onnx_node, |
| const ConversionContext& ctx); |
| |
| Caffe2Ops CreatePadPool(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateReshape(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateGather(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateGemm(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreatePad(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateConcat(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateLogSoftmax(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateSlice(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| std::string PreprocessSliceIndexTensor( |
| OnnxNode* onnx_node, |
| Caffe2Ops& ret, |
| std::string indices_tensor, |
| std::string axes_tensor, |
| std::string rank_tensor, |
| std::string zero_tensor, |
| std::string one_tensor, |
| int default_value); |
| |
| Caffe2Ops CreateDynamicSlice( |
| OnnxNode* onnx_node, |
| const ConversionContext& ctx); |
| |
| Caffe2Ops CreateSplit(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateReciprocal(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateRandomNormal( |
| OnnxNode* onnx_node, |
| const ConversionContext& ctx); |
| |
| Caffe2Ops CreateWhereOp(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateNonZeroOp(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateMultinomialOp( |
| OnnxNode* onnx_node, |
| const ConversionContext& ctx); |
| |
| Caffe2Ops CreateBatchNormalization( |
| OnnxNode* onnx_node, |
| const ConversionContext& ctx); |
| |
| Caffe2Ops CreateMatMul(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateUpsample(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateDropout(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| Caffe2Ops CreateLRN(OnnxNode* onnx_node, const ConversionContext& ctx); |
| |
| // LUT related getters |
| const std::unordered_map<std::string, std::string>& get_renamed_operators() |
| const; |
| const std::unordered_set<std::string>& get_rnn_operators() const; |
| const std::unordered_map<std::string, int>& get_broken_operators() const; |
| const std::unordered_map<std::string, std::string>& get_renamed_attrs() const; |
| const std:: |
| unordered_map<std::string, std::unordered_map<std::string, std::string>>& |
| get_per_op_renamed_attrs() const; |
| const std::unordered_map<std::string, Caffe2Backend::SpecialOpConverter>& |
| get_special_operators() const; |
| |
| // Dummy name generator |
| std::shared_ptr<DummyName> dummy_; |
| }; |
| |
| } // namespace onnx |
| } // namespace caffe2 |