26 #include "onnx_model.hpp"
31 Sparsity Onnx::input_pattern(
const onnx::GraphProto& graph,
const std::string& name)
const {
32 for (
int i = 0; i < graph.sparse_initializer_size(); ++i) {
33 if (graph.sparse_initializer(i).values().name() == name) {
34 return sparse_tensor_to_dm(graph.sparse_initializer(i)).
sparsity();
41 casadi_int default_value) {
42 for (
int a = 0; a < node.attribute_size(); ++a) {
43 if (node.attribute(a).name() == name)
return node.attribute(a).i();
49 double default_value) {
50 for (
int a = 0; a < node.attribute_size(); ++a) {
51 if (node.attribute(a).name() == name)
return node.attribute(a).f();
57 for (
int a = 0; a < node.attribute_size(); ++a) {
58 if (node.attribute(a).name() == name)
return node.attribute(a).s();
64 const std::string& name) {
65 for (
int a = 0; a < node.attribute_size(); ++a) {
66 if (node.attribute(a).name() == name)
return &node.attribute(a).g();
75 uout() <<
"Set dimension override: " << name <<
" = " << dim << std::endl;
79 casadi_int Onnx::get_dimension(
80 const onnx::TensorShapeProto& shape,
int idx)
const {
81 if (idx >= shape.dim_size())
return 1;
82 const auto& dim = shape.dim(idx);
84 if (dim.has_dim_value())
return static_cast<casadi_int
>(dim.dim_value());
86 if (dim.has_dim_param()) {
87 std::string param_name = dim.dim_param();
90 "Symbolic dimension '" + param_name +
"' not specified. " +
91 "Call set_dimension(\"" + param_name +
"\", value) before create().");
100 static bool load_raw(
DM& dm, casadi_int n,
const onnx::TensorProto& tensor,
101 const char* type_name) {
102 if (!(tensor.has_raw_data() && tensor.raw_data().size() > 0))
return false;
103 const std::string& raw = tensor.raw_data();
104 casadi_assert(raw.size() ==
static_cast<size_t>(n) *
sizeof(
T),
105 std::string(
"Raw data size mismatch for ") + type_name);
106 const T* p =
reinterpret_cast<const T*
>(raw.data());
107 for (casadi_int i = 0; i < n; ++i) dm(i) = static_cast<double>(p[i]);
111 DM Onnx::tensor_to_dm(
const onnx::TensorProto& tensor)
const {
112 std::vector<casadi_int> dims;
113 for (
int i = 0; i < tensor.dims_size(); ++i) {
114 dims.push_back(
static_cast<casadi_int
>(tensor.dims(i)));
118 uout() <<
" tensor_to_dm: dims_size=" << tensor.dims_size()
119 <<
", double_data_size=" << tensor.double_data_size()
120 <<
", raw_data_size=" << tensor.raw_data().size()
121 <<
", data_type=" << tensor.data_type();
122 if (dims.size() > 0) {
123 uout() <<
", dims[0]=" << dims[0];
129 casadi_int rows = dims.size() > 0 ? dims[0] : 1;
130 casadi_int cols = dims.size() > 1 ? dims[1] : 1;
131 if (dims.size() > 2) {
132 casadi_warning(
"ONNX tensor has " + std::to_string(dims.size()) +
133 " dimensions, flattening to 2D");
135 for (
size_t i = 1; i < dims.size(); ++i) {
142 if (dims.size() == 2) std::swap(rows, cols);
146 onnx::TensorProto::DataType dtype =
147 static_cast<onnx::TensorProto::DataType
>(tensor.data_type());
149 casadi_int n = rows * cols;
151 case onnx::TensorProto::DOUBLE: {
152 if (!load_raw<double>(dm, n, tensor,
"DOUBLE")) {
153 casadi_assert(tensor.double_data_size() == n,
"Tensor data size mismatch for DOUBLE");
154 for (casadi_int i = 0; i < n; ++i) dm(i) = tensor.double_data(i);
159 case onnx::TensorProto::FLOAT: {
160 if (!load_raw<float>(dm, n, tensor,
"FLOAT")) {
161 casadi_assert(tensor.float_data_size() == n,
"Tensor data size mismatch for FLOAT");
162 for (casadi_int i = 0; i < n; ++i) dm(i) = static_cast<double>(tensor.float_data(i));
167 case onnx::TensorProto::INT32: {
168 if (!load_raw<int32_t>(dm, n, tensor,
"INT32")) {
169 casadi_assert(tensor.int32_data_size() == n,
"Tensor data size mismatch for INT32");
170 for (casadi_int i = 0; i < n; ++i) dm(i) = static_cast<double>(tensor.int32_data(i));
175 case onnx::TensorProto::INT64: {
176 if (!load_raw<int64_t>(dm, n, tensor,
"INT64")) {
177 casadi_assert(tensor.int64_data_size() == n,
"Tensor data size mismatch for INT64");
178 for (casadi_int i = 0; i < n; ++i) dm(i) = static_cast<double>(tensor.int64_data(i));
183 case onnx::TensorProto::BOOL: {
185 if (tensor.int32_data_size() > 0) {
186 casadi_assert(tensor.int32_data_size() == n,
"Tensor data size mismatch for BOOL");
187 for (casadi_int i = 0; i < n; ++i) dm(i) = tensor.int32_data(i) ? 1.0 : 0.0;
188 }
else if (tensor.has_raw_data() && tensor.raw_data().size() > 0) {
189 const std::string& raw = tensor.raw_data();
190 casadi_assert(raw.size() ==
static_cast<size_t>(n),
"Raw data size mismatch for BOOL");
191 for (casadi_int i = 0; i < n; ++i) dm(i) = raw[i] ? 1.0 : 0.0;
193 casadi_error(
"BOOL tensor has neither int32_data nor raw_data");
199 casadi_error(
"Unsupported ONNX tensor data type: " + std::to_string(dtype) +
200 ". Supported types: DOUBLE(11), FLOAT(1), INT32(6), INT64(7), BOOL(9)");
206 DM Onnx::sparse_tensor_to_dm(
const onnx::SparseTensorProto& st)
const {
208 casadi_int nrow = st.dims_size() > 0 ?
static_cast<casadi_int
>(st.dims(0)) : 1;
209 casadi_int ncol = st.dims_size() > 1 ?
static_cast<casadi_int
>(st.dims(1)) : 1;
210 for (
int i = 2; i < st.dims_size(); ++i) ncol *=
static_cast<casadi_int
>(st.dims(i));
213 std::vector<double> values = tensor_to_dm(st.values()).
nonzeros();
214 casadi_int nnz =
static_cast<casadi_int
>(values.size());
217 const onnx::TensorProto& it = st.indices();
218 std::vector<int64_t> flat;
219 if (it.int64_data_size() > 0) {
220 flat.assign(it.int64_data().begin(), it.int64_data().end());
221 }
else if (it.has_raw_data() && !it.raw_data().empty()) {
222 const std::string& raw = it.raw_data();
223 const int64_t* p =
reinterpret_cast<const int64_t*
>(raw.data());
224 flat.assign(p, p + raw.size() /
sizeof(int64_t));
227 const bool coord = it.dims_size() == 2 && it.dims(1) == 2;
228 casadi_assert(
static_cast<casadi_int
>(flat.size()) == (coord ? 2 * nnz : nnz),
229 "Sparse tensor indices/values size mismatch");
231 std::vector<casadi_int> rows(nnz), cols(nnz);
232 for (casadi_int k = 0; k < nnz; ++k) {
234 rows[k] =
static_cast<casadi_int
>(flat[2 * k]);
235 cols[k] =
static_cast<casadi_int
>(flat[2 * k + 1]);
237 casadi_int lin =
static_cast<casadi_int
>(flat[k]);
238 rows[k] = lin / ncol;
239 cols[k] = lin % ncol;
bool verbose_
Verbose – for debugging.
std::vector< Scalar > & nonzeros()
Matrix< Scalar > T() const
Transpose the matrix.
const Sparsity & sparsity() const
Const access the sparsity - reference to data member.
static Matrix< double > triplet(const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, const Matrix< double > &d)
Construct a sparse matrix from triplet form.
std::map< std::string, casadi_int > dimension_overrides_
Dimension overrides for symbolic dimensions.
void set_dimension(const std::string &name, casadi_int dim)
Set dimension for a symbolic variable.
double get_float_attribute(const onnx::NodeProto &node, const std::string &name, double default_value)
Read a float node attribute by name, or default_value if absent.
const onnx::GraphProto * get_graph_attribute(const onnx::NodeProto &node, const std::string &name)
Read a subgraph (GraphProto) node attribute by name, or nullptr if absent.
casadi_int get_int_attribute(const onnx::NodeProto &node, const std::string &name, casadi_int default_value)
Read an integer node attribute by name, or default_value if absent.
std::string get_string_attribute(const onnx::NodeProto &node, const std::string &name)
Read a string node attribute by name, or "" if absent.
static bool load_raw(DM &dm, casadi_int n, const onnx::TensorProto &tensor, const char *type_name)