25 #include "onnx_function_impl.hpp"
26 #include "graph_builder_internal.hpp"
27 #include "casadi_misc.hpp"
40 std::vector<std::string> ret;
51 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
52 std::mutex OnnxFunction::mutex_solvers_;
62 {
OT_STRING,
"Execution provider for the ONNX runtime backend"}},
64 {
OT_DICT,
"Sizes for symbolic/dynamic tensor dimensions (name -> size)"}},
66 {
OT_DICT,
"Explicit shapes for inputs (name -> shape), overriding the model's"}},
68 {
OT_DICT,
"Baked-in input values (name -> value); these inputs are not exposed"}},
70 {
OT_STRING,
"Symbolic dimension naming the forward seed count [nfwd]"}},
72 {
OT_STRING,
"Symbolic dimension naming the adjoint seed count [nadj]"}}
78 case 1:
return "FLOAT";
case 2:
return "UINT8";
case 3:
return "INT8";
79 case 4:
return "UINT16";
case 5:
return "INT16";
case 6:
return "INT32";
80 case 7:
return "INT64";
case 8:
return "STRING";
case 9:
return "BOOL";
81 case 10:
return "FLOAT16";
case 11:
return "DOUBLE";
case 12:
return "UINT32";
82 case 13:
return "UINT64";
case 16:
return "BFLOAT16";
83 default:
return "TYPE" +
str(t);
88 static const std::map<std::string, casadi_int> m = {
89 {
"FLOAT", 1}, {
"UINT8", 2}, {
"INT8", 3}, {
"UINT16", 4}, {
"INT16", 5},
90 {
"INT32", 6}, {
"INT64", 7}, {
"STRING", 8}, {
"BOOL", 9}, {
"FLOAT16", 10},
91 {
"DOUBLE", 11}, {
"UINT32", 12}, {
"UINT64", 13}, {
"BFLOAT16", 16}};
92 auto it = m.find(name);
93 return it != m.end() ? it->second : 0;
98 const std::vector<std::string>& req) {
99 if (req.empty())
return all;
100 std::vector<OnnxTensorInfo> sel;
101 for (
const std::string& name : req) {
104 if (t.name == name) { sel.push_back(t); found =
true;
break; }
105 casadi_assert(found,
"ONNX tensor '" + name +
"' not found in model");
111 const std::vector<std::string>& inputs,
112 const std::vector<std::string>& outputs)
118 std::vector<OnnxTensorInfo> all_out;
126 if (n.io ==
"input") {
130 all_out.push_back(t);
144 const std::vector<OnnxTensorInfo>& v) {
145 std::vector<std::string> names;
146 std::vector<std::vector<casadi_int>> shapes;
147 std::vector<casadi_int> elem_types, numels;
149 names.push_back(t.name);
150 shapes.push_back(t.shape);
151 elem_types.push_back(t.elem_type);
152 numels.push_back(t.numel);
154 s.
pack(d +
"::names", names);
155 s.
pack(d +
"::shapes", shapes);
156 s.
pack(d +
"::elem_types", elem_types);
157 s.
pack(d +
"::numels", numels);
160 std::vector<OnnxTensorInfo>& v) {
161 std::vector<std::string> names;
162 std::vector<std::vector<casadi_int>> shapes;
163 std::vector<casadi_int> elem_types, numels;
164 s.
unpack(d +
"::names", names);
165 s.
unpack(d +
"::shapes", shapes);
166 s.
unpack(d +
"::elem_types", elem_types);
167 s.
unpack(d +
"::numels", numels);
169 for (
size_t k = 0; k < names.size(); ++k)
170 v.push_back(
OnnxTensorInfo{names[k], shapes[k], elem_types[k], numels[k]});
187 s.
pack(
"OnnxFunction::model_inputs",
189 s.
pack(
"OnnxFunction::model_outputs",
199 s.
unpack(
"OnnxFunction::model_data", bytes);
206 std::vector<std::string> mi, mo;
207 s.
unpack(
"OnnxFunction::model_inputs", mi);
209 s.
unpack(
"OnnxFunction::model_outputs", mo);
221 for (
auto&& op : opts) {
222 if (op.first ==
"fwd_dim")
fwd_dim_ = op.second.to_string();
223 else if (op.first ==
"adj_dim")
adj_dim_ = op.second.to_string();
226 std::vector<OnnxTensorInfo> exposed;
239 for (casadi_int j = 0; j < static_cast<casadi_int>(
in_.size()); ++j)
240 if (
in_[j].name == t.name) { src = j;
break; }
243 casadi_assert(
static_cast<casadi_int
>(bv->second.size()) == t.numel,
244 "Baked value for '" + t.name +
"' has " +
str(bv->second.size())
245 +
" elements, expected " +
str(t.numel));
247 for (
double v : bv->second)
in_val_.push_back(v);
260 casadi_int numel = 1;
261 for (casadi_int d : shape) numel *= d;
266 const std::vector<std::string>& inames,
const std::vector<std::string>& onames,
267 const std::vector<Sparsity>& in_sp,
const std::vector<Sparsity>& out_sp,
268 const Dict& dim_bind,
const Dict& opts)
const {
270 std::vector<std::string> cin, con;
271 for (
const std::string& nm : inames)
if (
model_inputs_.count(nm)) cin.push_back(nm);
272 for (
const std::string& nm : onames)
if (
model_outputs_.count(nm)) con.push_back(nm);
274 if (!dim_bind.empty()) o[
"dim_bindings"] = dim_bind;
277 std::map<std::string, MX> m;
278 std::vector<MX> args(inames.size());
279 for (
size_t i = 0; i < inames.size(); ++i) {
280 args[i] =
MX::sym(inames[i], in_sp[i]);
281 m[inames[i]] = args[i];
284 for (
const std::string& nm : cin) gin.push_back(m[nm]);
285 std::vector<MX> gout = g(gin);
286 std::map<std::string, MX> mo;
287 for (
size_t k = 0; k < con.size(); ++k) mo[con[k]] = gout[k];
288 std::vector<MX> outs(onames.size());
289 for (
size_t j = 0; j < onames.size(); ++j) {
290 auto it = mo.find(onames[j]);
291 outs[j] = it != mo.end() ? it->second :
MX::zeros(out_sp[j]);
294 auto it = opts.find(
"derivative_of");
295 if (it != opts.end()) wopts[
"derivative_of"] = it->second;
296 return Function(name, args, outs, inames, onames, wopts);
301 if (
in_.empty() ||
out_.empty())
return false;
303 bool any_in =
false, any_out =
false;
304 for (
size_t i = 0; i <
in_.size(); ++i) {
309 for (
size_t j = 0; j <
out_.size(); ++j) {
314 return any_in && any_out;
318 const std::vector<std::string>& inames,
319 const std::vector<std::string>& onames,
320 const Dict& opts)
const {
321 std::vector<Sparsity> isp, osp;
338 if (
in_.empty() ||
out_.empty())
return false;
340 bool any_in =
false, any_out =
false;
341 for (
size_t i = 0; i <
in_.size(); ++i) {
346 for (
size_t j = 0; j <
out_.size(); ++j) {
351 return any_in && any_out;
355 const std::vector<std::string>& inames,
356 const std::vector<std::string>& onames,
357 const Dict& opts)
const {
358 std::vector<Sparsity> isp, osp;
375 if (
in_.empty() ||
out_.empty())
return false;
377 for (
size_t j = 0; j <
out_.size(); ++j) {
379 for (
size_t i = 0; i <
in_.size(); ++i) {
389 const std::vector<std::string>& inames,
390 const std::vector<std::string>& onames,
391 const Dict& opts)
const {
392 std::vector<Sparsity> isp, osp;
407 const std::vector<std::string>& inputs,
408 const std::vector<std::string>& outputs,
414 const std::vector<uint8_t>& model_data,
415 const std::vector<std::string>& inputs,
416 const std::vector<std::string>& outputs,
422 for (
auto&& op : opts) {
423 if (op.first ==
"dim_bindings") {
424 for (
auto&& d :
static_cast<Dict>(op.second)) bi->
dim_bindings_[d.first] = d.second;
425 }
else if (op.first ==
"input_shapes") {
426 for (
auto&& d :
static_cast<Dict>(op.second))
428 }
else if (op.first ==
"input_values") {
429 for (
auto&& d :
static_cast<Dict>(op.second))
432 fopts[op.first] = op.second;
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
Internal class for Function.
std::string diff_prefix(const std::string &prefix) const
Determine prefix for differentiated functions.
void init(const Dict &opts) override
Initialize.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
static const Options options_
Options.
void serialize_type(SerializingStream &s) const override
Serialize type information.
static Function create(FunctionInternal *node)
Create from node.
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
static MX zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
Internal class for GraphBuilder.
std::map< std::string, std::vector< double > > input_values_
const std::vector< Node > & node_list() const
std::vector< casadi_int > resolved_shape(const Node &n) const
std::map< std::string, casadi_int > dim_bindings_
Pending configuration carried into create()
std::map< std::string, std::vector< casadi_int > > input_shapes_
std::vector< uint8_t > model_data_
A mutable, format-neutral interface to a computational-graph model.
GraphBuilderInternal * get() const
Function get_forward(casadi_int nfwd, const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Return function that calculates forward derivatives.
static Sparsity tensor_sparsity(const std::vector< casadi_int > &shape)
Map an ONNX N-D shape to a 2-D CasADi sparsity (rank<=2 direct, rank>2 flattened column)
std::string fwd_dim_
Symbolic dimensions naming the forward/adjoint seed counts (bound in get_forward/reverse)
static const std::string infix_
static std::map< std::string, Plugin > solvers_
Plugin registry.
Function get_jacobian(const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Return Jacobian of all input elements with respect to all output elements.
Function wrap_derivative(const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const std::vector< Sparsity > &in_sp, const std::vector< Sparsity > &out_sp, const Dict &dim_bind, const Dict &opts) const
std::set< std::string > model_outputs_
Function get_reverse(casadi_int nadj, const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Return function that calculates adjoint derivatives.
std::vector< casadi_int > in_src_
Per all_in_ entry: exposed-arg index (>=0), -2 baked value, or -1 unwired (default)
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
std::vector< OnnxTensorInfo > in_
Metadata for the exposed inputs/outputs (the selection)
bool has_jacobian() const override
Return Jacobian of all input elements with respect to all output elements.
void serialize_type(SerializingStream &s) const override
Serialize type information.
std::map< std::string, std::vector< double > > input_values_
Baked input values: input name -> value; such inputs are not exposed as Function inputs.
bool diff_out(casadi_int i) const
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into a plugin instance (dispatches on the plugin name)
void build_io_map()
Compute the per-model-input feed map: in_src_ (arg index / -2 baked / -1 default) + in_val_.
bool has_forward(casadi_int nfwd) const override
Return function that calculates forward derivatives.
static Function create(const std::string &solver, const std::string &name, const GraphBuilderInternal *gb, const std::vector< std::string > &inputs, const std::vector< std::string > &outputs, const Dict &opts)
Plugin factory.
static const Options options_
Options.
static std::string meta_doc
Documentation string.
std::vector< OnnxTensorInfo > out_
std::vector< OnnxTensorInfo > all_in_
Metadata for every model input (a runtime backend must feed all of them)
std::vector< uint8_t > model_data_
Serialized ONNX model.
static Function from_model_data(const std::string &solver, const std::string &name, const std::vector< uint8_t > &model_data, const std::vector< std::string > &inputs, const std::vector< std::string > &outputs, const Dict &opts)
Freeze a function from raw model bytes: stage a transient GraphBuilder, then create()
std::set< std::string > model_inputs_
Names of every input/output tensor in the model (for derivative detection)
bool diff_in(casadi_int i) const
True if input/output index is differentiable (is_diff_in/out, default true)
OnnxFunction(const std::string &name, const GraphBuilderInternal *gb, const std::vector< std::string > &inputs, const std::vector< std::string > &outputs)
Construct by freezing a snapshot of a builder's metadata + config (exposed selection)
std::vector< double > in_val_
Baked input values, flat over all_in_ (numel each; placeholder block when not baked)
bool has_reverse(casadi_int nadj) const override
Return function that calculates adjoint derivatives.
void init(const Dict &opts) override
Initialize.
static bool has_plugin(const std::string &pname, bool verbose=false)
Check if a plugin is available or can be loaded.
void serialize_type(SerializingStream &s) const
Serialize type information.
static Plugin & getPlugin(const std::string &pname)
Load and get the creator function.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
virtual const char * plugin_name() const=0
static Plugin load_plugin(const std::string &pname, bool register_plugin=true, bool needs_lock=true)
Load a plugin dynamically.
Base class for FunctionInternal and LinsolInternal.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
casadi_int size1() const
Get the number of rows.
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern *.
casadi_int size2() const
Get the number of columns.
std::string onnxbackend_doc(const std::string &solver)
Get documentation for an ONNX runtime backend.
void load_onnxbackend(const std::string &solver)
Load an ONNX runtime backend.
bool has_onnxbackend(const std::string &solver)
Check if a given ONNX runtime backend is available.
std::vector< std::string > onnxbackend_solvers()
List available ONNX runtime backends.
std::string onnx_dtype_name(casadi_int t)
Human-readable name of an ONNX element-type enum (1=FLOAT, 11=DOUBLE, 7=INT64, ......
casadi_int onnx_dtype_enum(const std::string &name)
ONNX element-type enum for a human-readable name (inverse of onnx_dtype_name; 0 if unknown)
static std::vector< OnnxTensorInfo > select_tensors(const std::vector< OnnxTensorInfo > &all, const std::vector< std::string > &req)
static void unpack_tensors(DeserializingStream &s, const std::string &d, std::vector< OnnxTensorInfo > &v)
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
bool any(const std::vector< bool > &v)
Check if any arguments are true.
bool all(const std::vector< bool > &v)
Check if all arguments are true.
static void pack_tensors(SerializingStream &s, const std::string &d, const std::vector< OnnxTensorInfo > &v)
Metadata for one graph tensor (graph input or output)
Metadata for a single ONNX tensor (input or output); shape is resolved by the builder.
casadi_int elem_type
ONNX element type enum (1=float, 11=double, 7=int64)
std::vector< casadi_int > shape
Resolved shape (dynamic dims bound or set to 1)
std::string name
ONNX tensor name.
casadi_int numel
Number of elements in the resolved shape.