| #include "caffe2/opt/backend_transformer_base.h" | 
 | #include "caffe2/onnx/onnx_exporter.h" | 
 | #include "caffe2/utils/proto_utils.h" | 
 |  | 
 | namespace caffe2 { | 
 |  | 
 | // Populate 'net_pos' argument for any ops that don't already have it. 'net_pos' | 
 | // we populate here starts after the max 'net_pos' value we encountered. | 
 | void BackendTransformerBase::annotateOpIndex(NetDef* net) { | 
 |   // find the max net_pos that we have so far. | 
 |   int i = -1; | 
 |   for (const auto& op : net->op()) { | 
 |     ArgumentHelper helper(op); | 
 |     int old_index = helper.GetSingleArgument(op, kNetPos, -1); | 
 |     i = std::max(i, old_index); | 
 |   } | 
 |  | 
 |   // populate net_pos for any op that doesn't already have it. | 
 |   for (auto& op : *(net->mutable_op())) { | 
 |     if (!ArgumentHelper::HasArgument(op, kNetPos)) { | 
 |       AddArgument(kNetPos, ++i, &op); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | std::string BackendTransformerBase::getModelId(const NetDef& net) { | 
 |   static std::atomic<size_t> seq_id{0}; | 
 |   std::string model_id; | 
 |   for (const auto& arg : net.arg()) { | 
 |     if (arg.name() == kModelId) { | 
 |       if (arg.has_s()) { | 
 |         model_id = arg.s(); | 
 |       } else if (arg.has_i()) { | 
 |         model_id = c10::to_string(arg.i()); | 
 |       } | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   if (model_id.empty()) { | 
 |     model_id = "unnamed_" + c10::to_string(seq_id++); | 
 |   } | 
 |   return model_id; | 
 | } | 
 |  | 
 | TensorProto wrapShapeInfoIntoTensorProto( | 
 |     const std::string& name, | 
 |     const ShapeInfo& shape_info) { | 
 |   TensorProto t; | 
 |   t.set_name(name); | 
 |   t.set_data_type(shape_info.shape.data_type()); | 
 |   for (const auto i : shape_info.shape.dims()) { | 
 |     t.add_dims(i); | 
 |   } | 
 |   for (const auto& dimType : shape_info.getDimType()) { | 
 |     t.add_int32_data(static_cast<int32_t>(dimType)); | 
 |   } | 
 |   return t; | 
 | } | 
 |  | 
 | QTensorProto wrapShapeInfoIntoQTensorProto( | 
 |     const std::string& name, | 
 |     const ShapeInfo& shape_info) { | 
 |   QTensorProto t; | 
 |   CAFFE_ENFORCE( | 
 |       shape_info.is_quantized == true, | 
 |       "Only quantized shapeinfo can be extracted into QTensor!"); | 
 |   t.set_name(name); | 
 |   t.set_data_type(shape_info.shape.data_type()); | 
 |   t.set_axis(shape_info.q_info.axis); | 
 |   t.set_is_multiparam(true); | 
 |   for (const auto i : shape_info.q_info.scale) { | 
 |     t.add_scales(i); | 
 |   } | 
 |   t.set_scale(1.0); | 
 |   for (const auto i : shape_info.q_info.offset) { | 
 |     t.add_biases(i); | 
 |   } | 
 |   t.set_bias(0.0); | 
 |   // precision and is_signed is not used in onnxifi workflow, but it is required | 
 |   // field | 
 |   t.set_precision(0); | 
 |   // NOLINTNEXTLINE(modernize-use-bool-literals) | 
 |   t.set_is_signed(0); | 
 |   for (const auto i : shape_info.shape.dims()) { | 
 |     t.add_dims(i); | 
 |   } | 
 |   for (const auto& dimType : shape_info.getDimType()) { | 
 |     t.add_data(static_cast<int32_t>(dimType)); | 
 |   } | 
 |   return t; | 
 | } | 
 |  | 
 | ShapeInfoMap BackendTransformerBase::ssaRewriteAndMapNames( | 
 |     Workspace* ws, | 
 |     NetDef* pred_net, | 
 |     const ShapeInfoMap& input_shape_hints) { | 
 |   input_mapping_ = onnx::SsaRewrite(nullptr, pred_net); | 
 |   // Annote the ops with net position | 
 |   annotateOpIndex(pred_net); | 
 |  | 
 |   // Since we are going to create a mapped workspace, we need to make sure that | 
 |   // the parent workspace has the mapped blob names. If the blobs don't exist | 
 |   // (usually such blobs are input tensor names), we exclude them from mapping. | 
 |   std::vector<std::string> exclude_mapping; | 
 |   for (const auto& kv : input_mapping_) { | 
 |     if (!ws->HasBlob(kv.second)) { | 
 |       exclude_mapping.emplace_back(kv.first); | 
 |     } | 
 |   } | 
 |   for (const auto& i : exclude_mapping) { | 
 |     input_mapping_.erase(i); | 
 |   } | 
 |  | 
 |   ShapeInfoMap shape_hints_mapped; | 
 |   for (const auto& kv : input_shape_hints) { | 
 |     shape_hints_mapped.emplace(kv.first, kv.second); | 
 |   } | 
 |   return shape_hints_mapped; | 
 | } | 
 |  | 
 | ShapeInfoMap BackendTransformerBase::inferShapes( | 
 |     Workspace* ws, | 
 |     NetDef* pred_net, | 
 |     const ShapeInfoMap& shape_hints_mapped, | 
 |     const BoundShapeSpec& spec) { | 
 |   ShapeInfoMap shape_map; | 
 |  | 
 |   // Populate shapes from workplace | 
 |   const std::vector<std::string> ws_blobs = ws->Blobs(); | 
 |   for (const auto& s : ws_blobs) { | 
 |     auto shape_info = getShapeInfoFromBlob(ws->GetBlob(s)); | 
 |     if (shape_info.dimTypeIsSet()) { | 
 |       shape_map.emplace(s, shape_info); | 
 |     } | 
 |   } | 
 |   for (const auto& s : shape_hints_mapped) { | 
 |     shape_map.insert(s); | 
 |   } | 
 |   auto eng = BoundShapeInferencerRegistry()->Create("C10", spec); | 
 |   eng->InferBoundShapeAndType(*pred_net, shape_map, ws); | 
 |   const auto& out_map = eng->shape_info(); | 
 |   shape_map.clear(); | 
 |   for (const auto& kv : out_map) { | 
 |     shape_map.emplace( | 
 |         std::piecewise_construct, | 
 |         std::forward_as_tuple(kv.first), | 
 |         std::forward_as_tuple( | 
 |             kv.second.getDimType(), | 
 |             kv.second.shape, | 
 |             kv.second.is_quantized, | 
 |             kv.second.q_info)); | 
 |   } | 
 |   return shape_map; | 
 | } | 
 |  | 
 | void BackendTransformerBase::addShapeToNet( | 
 |     NetDef& shape_net, | 
 |     const ShapeInfoMap& shape_hints) const { | 
 |   auto* shape_arg = shape_net.add_arg(); | 
 |   auto* qshape_arg = shape_net.add_arg(); | 
 |   shape_arg->set_name("shape_info"); | 
 |   qshape_arg->set_name("qshape_info"); | 
 |   for (const auto& kv : shape_hints) { | 
 |     if (!kv.second.is_quantized) { | 
 |       auto t = wrapShapeInfoIntoTensorProto(kv.first, kv.second); | 
 |       shape_arg->mutable_tensors()->Add()->CopyFrom(t); | 
 |     } else { | 
 |       auto t = wrapShapeInfoIntoQTensorProto(kv.first, kv.second); | 
 |       qshape_arg->mutable_qtensors()->Add()->CopyFrom(t); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void BackendTransformerBase::dumpNet( | 
 |     const NetDef& pred_net, | 
 |     const ShapeInfoMap& shape_hints, | 
 |     const std::string& fname) const { | 
 |   NetDef shape_net(pred_net); | 
 |   addShapeToNet(shape_net, shape_hints); | 
 |   WriteProtoToTextFile(shape_net, fname, false); | 
 | } | 
 | } // namespace caffe2 |