Low level support for ONNX files. This package is useful if you want to investigate ONNX files in detail or create new tools to read or write ONNX files. It is not useful if you just want to load an ONNX file into your favorite machine learning library or run inference. For the former, search for ONNX loading support in the library. For the latter you can use ONNXRunTime.jl.
The ONNX.jl package has roughly the same purpose as this package. The fundamental difference is that ONNXLowLevel has no dependencies apart from ProtoBuf whereas ONNX supports saving and loading graphs with a tape representation and can run inference on some of the ONNX operations.
Both packages export the ProtoBuf generated structs but differ slightly in their additional convenience constructors and functions.
using Pkg
Pkg.add("ONNXLowLevel")
The ONNX format is defined by the onnx.proto3
file, which defines ProtoBuf messages and their meanings. These are
automatically converted into structs, and an ONNX file corresponds to
nested structs with a ModelProto
at the top.
An ONNX file can be loaded into a ModelProto
with either of these
methods:
load(filename::AbstractString)
load(io::IO)
load(data::Vector{UInt8})
Correspondingly a ModelProto
can be saved with
save(filename::AbstractString, model::ModelProto)
save(io::IO, model::ModelProto)
save(model::ModelProto)
The contents of an ONNX file or a ModelProto
can be interactively
explored with a text user interface tool:
@explore filename
@explore model
All ONNX structs, such as ModelProto
, have keyword argument
constructors, where omitted fields are set to empty or neutral values.
The struct docstring lists all fields, which can also be found in
onnx.proto3
.
Some structs and fields have names which do not match Julia's naming
rules. Those can be accessed with the var"X"
syntax, such as
var"TensorShapeProto.Dimension"
or value_info.var"#type"
.
Some of the frequently used and complicated to construct ONNX structs have additional convenience constructors and accessors to convert them back to common Julia types.
AttributeProto(name, value)
AttributeProto(name => value)
Construct an AttributeProto with the given name
and a value
, which
can be a Float64
, Int64
, String
, TensorProto
, GraphProto
,
SparseTensorProto
, or TypeProto
. Additionally it can be a Vector
of the aforementioned types, and also generalizes to all subtypes of
AbstractFloat
, Integer
, AbstractString
, and AbstractVector
.
AttributeProto.(dict::AbstractDict)
A Dict
of name, value pairs can be converted to a
Vector{AttributeProto}
by broadcasting the constructor.
get_attribute(attribute::AttributeProto)
Convert an AttributeProto
to a Pair
of name => value
.
get_attributes(attributes::Vector{<:AttributeProto})
Convert a Vector
of AttributeProto
to a Dict
.
get_attributes(attributes::Vector{<:AttributeProto}; dicttype)
Convert a Vector
of AttributeProto
to a dictionary of specific
dicttype
.
ValueInfoProto(name::AbstractString, type::DataType,
dims::Vector{<:Any})
Construct a ValueInfoProto
with the given name
for a tensor. The
type
can be Int64
, UInt64
, Int32
, UInt32
, Int16
, UInt16
,
Int8
, UInt8
, Float64
, Float32
, Float16
, ComplexF64
, or
ComplexF32
. Each element of dims
can be either an integer or a
string, where the former is the size of the dimension and the latter
is a symbolic name for the dimension, which can be set dynamically.
See a later section for support of four bit integer, 8 bit float, and bfloat16 types.
name, type, dims = get_value_info(value_info::ValueInfoProto;
params_as_zero = false)
Extract name
, type
, and dims
from a ValueInfoProto
. If
params_as_zero
is true
, return dims
as an all integer vector
where dynamic dimensions are set to zero.
ONNX tensors are stored in row-major format, which is contrary to
Julia's native column-major. This means that conversion between a
Julia Array
and an ONNX TensorProto
either needs to reverse the
dimensions or transpose the data. ONNXLowLevel chooses the former
option since transposing the data is relatively expensive and it is
easy to convert to the latter option with permutedims(x, ndims(x):-1:1)
.
TensorProto(name::AbstractString, x::AbstractArray)
Create a TensorProto
with the given name
. The data x
can have
any shape and an element type of either Int64
, UInt64
, Int32
,
UInt32
, Int16
, UInt16
, Int8
, UInt8
, Float64
, Float32
,
Float16
, ComplexF64
, ComplexF32
, Bool
, or String
.
See a later section for support of four bit integer, 8 bit float, and bfloat16 element types.
TensorProto(x::AbstractArray)
Like above but name
is set to the empty string.
get_tensor(tensor::TensorProto)
Convert a TensorProto
to a Julia Array
.
The ONNX format includes a number of data types which are not natively
supported by Julia: BFLOAT16
, FLOAT8E4M3FN
, FLOAT8E4M3FNUZ
,
FLOAT8E5M2
, FLOAT8E5M2FNUZ
, INT4
, and UINT4
.
Neither of these are currently supported by ONNXLowLevel. The plan is
to support BFLOAT16
as an extension for the BFloat16s
package. The
other data types may get minimal support within this package.