25 #include "onnx_model.hpp"
26 #include <casadi/core/graph_builder_internal.hpp>
35 int CASADI_GRAPHMODEL_ONNX_EXPORT
38 plugin->name =
"onnx";
40 plugin->version = CASADI_VERSION;
51 "ONNX backend for GraphModel: protobuf metadata, symbolic import and export.\n";
56 {
OT_STRING,
"Real type for exported tensors: 'double' (default) or 'float'"}}
69 for (
auto&& op : opts) {
70 if (op.first ==
"casadi_real") set_casadi_real(op.second.to_string());
75 casadi_assert(
model_.ParseFromArray(data.data(),
static_cast<int>(data.size())),
76 "Failed to parse ONNX model from memory");
81 casadi_assert(
has_model_,
"No ONNX model loaded.");
83 casadi_assert(
model_.SerializeToString(&s),
"Failed to serialize ONNX model");
84 return std::vector<uint8_t>(s.begin(), s.end());
88 static Node io_node(
const onnx::ValueInfoProto& vi,
const std::string& io) {
92 const onnx::TypeProto::Tensor& tt = vi.type().tensor_type();
94 const onnx::TensorShapeProto& sh = tt.shape();
95 for (
int k = 0; k < sh.dim_size(); ++k) {
96 const auto& d = sh.dim(k);
97 if (d.has_dim_value()) {
98 n.
dimension.push_back(
static_cast<casadi_int
>(d.dim_value()));
102 n.
dim_params.push_back(d.has_dim_param() ? d.dim_param() :
"");
110 const onnx::GraphProto& g =
model_.graph();
113 std::set<std::string> init_names;
114 for (
int i = 0; i < g.initializer_size(); ++i) init_names.insert(g.initializer(i).name());
116 for (
int i = 0; i < g.input_size(); ++i)
117 if (!init_names.count(g.input(i).name())) gb.
add_node(
io_node(g.input(i),
"input"));
118 for (
int i = 0; i < g.output_size(); ++i) gb.
add_node(
io_node(g.output(i),
"output"));
125 if (
model_.producer_name() ==
"CasADi")
return f;
126 std::vector<MX> inputs, args, outputs;
129 std::map<std::string, int> in_rank;
130 for (
const auto& in :
model_.graph().input())
131 in_rank[in.name()] = in.type().tensor_type().shape().dim_size();
132 for (casadi_int i = 0; i < f.
n_in(); ++i) {
134 if (in_rank[f.
name_in(i)] < 2) {
136 args.push_back(inputs.back());
139 args.push_back(inputs.back().T());
142 f.
call(args, outputs,
true);
143 for (casadi_int i = 0; i < f.
n_out(); ++i) {
144 const auto& shape =
model_.graph().output(i).type().tensor_type().shape();
145 outputs[i] = shape.dim_size() == 1 ? vec(outputs[i]) : outputs[i].T();
151 auto it = opts.find(
"casadi_real");
152 if (it != opts.end()) set_casadi_real(it->second.to_string());
const std::vector< std::string > & name_in() const
Get the names of all inputs, in order.
const Sparsity & sparsity_in(casadi_int ind) const
Get the sparsity pattern of an input, by index or name.
casadi_int n_out() const
Get the number of function outputs.
casadi_int n_in() const
Get the number of function inputs.
void call(const std::vector< DM > &arg, std::vector< DM > &res, bool always_inline=false, bool never_inline=false) const
Evaluate with a list or a dict of arguments; the result has the same form.
const std::vector< std::string > & name_out() const
Get the names of all outputs, in order.
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
Internal class for GraphBuilder.
void clear_nodes()
Drop all tensor descriptors (called by a backend before re-filling)
void add_node(const Node &n)
Append a tensor descriptor (called by a backend during fill_metadata)
const std::map< std::string, casadi_int > & dim_bindings() const
Base interface for format-specific graph-model backends.
static const Options options_
Options.
const std::vector< uint8_t > & model_data() const
Raw model bytes.
virtual void init(const Dict &opts)
Initialize.
std::vector< uint8_t > export_symbolic(const Function &f, const Dict &opts) override
Serialize a CasADi Function as model bytes (symbolic export; mutates the backend's engine)
static const std::string meta_doc
Documentation.
static const Options options_
Options.
Function create(const std::string &name)
Create a CasADi Function from the loaded ONNX graph.
void load_bytes(const std::vector< uint8_t > &data)
Load a graph from serialized ONNX bytes.
static GraphModelInternal * creator(const std::vector< uint8_t > &model_data)
Plugin factory.
std::vector< uint8_t > save_bytes() const
Serialize the loaded graph/model to ONNX bytes.
onnx::ModelProto model_
ONNX model protocol buffer.
Function import_symbolic(const GraphBuilderInternal &gb, const std::string &name) override
Rebuild the graph as a CasADi Function (symbolic import; mutates the backend's engine)
void init(const Dict &opts) override
Initialize.
bool has_model_
Whether a model has been loaded.
void load(const Function &f)
Load a CasADi Function and convert to the ONNX representation.
Onnx(const std::vector< uint8_t > &model_data)
void set_dimension(const std::string &name, casadi_int dim)
Set dimension for a symbolic variable.
void fill_metadata(GraphBuilderInternal &gb) const override
Populate a builder's Node metadata from the parsed model.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
Sparsity T() const
Transposed pattern.
std::string onnx_dtype_name(casadi_int t)
Human-readable name of an ONNX element-type enum (1=FLOAT, 11=DOUBLE, 7=INT64, ......
static Node io_node(const onnx::ValueInfoProto &vi, const std::string &io)
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
int CASADI_GRAPHMODEL_ONNX_EXPORT casadi_register_graphmodel_onnx(GraphModelInternal::Plugin *plugin)
void CASADI_GRAPHMODEL_ONNX_EXPORT casadi_load_graphmodel_onnx()
Metadata for one graph tensor (graph input or output)
std::vector< casadi_int > dimension
Declared shape, -1 for dynamic dimensions.
std::string name
Tensor name.
std::string io
"input" or "output"
std::string dtype
Element type name (FLOAT, INT64, ...)
std::vector< std::string > dim_params
Symbolic name per axis ("" if static)