Standard library · Machine learning

onnx

Reading and running ONNX models with no outside dependency.

import onnx
On this page
  1. Types
  2. Functions

ONNX is a common format for machine learning models: export a model you trained in PyTorch or TensorFlow to .onnx and read it in Salam with LoadOnnx. Run runs the graph over the input tensors.

So that it works without an outside file, the example below builds a small model with encoding/protobuf; in practice nothing but LoadOnnx and Run is needed.

Types

Attr

struct Attr
One node attribute, such as alpha.
NameTypeDescription
namestr = ""The name.
kindint = 0The value kind in the ONNX format: 1 float, 2 integer, 3 string, 4 tensor, 6 and 7 lists.
ff64 = 0The float value.
ii64 = 0The integer value.
sstr = ""The string value.
ttensor.TensorThe tensor value.
floatsVectorThe float list.
intsVectorThe integer list.
onnx-Run.salam
import onnx
import tensor
import compress
import encoding.protobuf
import archive
import os

func submessage(b &: compress.ByteBuf, field: int, message: compress.ByteBuf):
    protobuf.WriteTag(b, field, protobuf.WT_LEN)
    protobuf.WriteLenPrefixedBytes(b, message.data, compress.BufLen(message))
end

func text(b &: compress.ByteBuf, field: int, value: str):
    protobuf.WriteTag(b, field, protobuf.WT_LEN)
    protobuf.WriteLenPrefixedStr(b, value)
end

func number(b &: compress.ByteBuf, field: int, value: i64):
    protobuf.WriteTag(b, field, protobuf.WT_VARINT)
    protobuf.WriteVarint(b, value as u64)
end

func node(b &: compress.ByteBuf, op: str, input1: str, input2: str, output: str):
    text(b, 1, input1)
    if input2 != "":
        text(b, 1, input2)
    end
    text(b, 2, output)
    text(b, 4, op)
end

func model(m &: compress.ByteBuf):
    mut graph := compress.NewByteBuf()
    mut mul := compress.NewByteBuf()
    node(mul, "Mul", "x", "w", "h")
    submessage(graph, 1, mul)
    mut relu := compress.NewByteBuf()
    node(relu, "LeakyRelu", "h", "", "y")
    mut alpha := compress.NewByteBuf()
    text(alpha, 1, "alpha")
    number(alpha, 20, 1)
    protobuf.WriteTag(alpha, 2, protobuf.WT_FIXED32)
    protobuf.WriteFloat(alpha, 0.1)
    submessage(relu, 5, alpha)
    submessage(graph, 1, relu)
    mut weight := compress.NewByteBuf()
    number(weight, 1, 3)
    number(weight, 2, 1)
    mut payload := compress.NewByteBuf()
    each factor in [2.0, 2.0, 2.0]:
        protobuf.WriteFloat(payload, factor)
    end
    submessage(weight, 4, payload)
    text(weight, 8, "w")
    submessage(graph, 5, weight)
    mut input_x := compress.NewByteBuf()
    text(input_x, 1, "x")
    submessage(graph, 11, input_x)
    mut output_y := compress.NewByteBuf()
    text(output_y, 1, "y")
    submessage(graph, 12, output_y)
    number(m, 1, 8)
    submessage(m, 7, graph)
end

func main:
    mut buffer := compress.NewByteBuf()
    model(buffer)
    mut good := false
    mut m := onnx.ParseOnnx(buffer.data, compress.BufLen(buffer), good)
    println good, m.ok, m.ir_version, m.nodes.len(), m.inits.len(), m.init_names.get(0)
    mut relu := m.nodes.get(1)
    println relu.op, relu.inputs.get(0), relu.outputs.get(0), relu.attr_index("alpha")
    println (relu.attr_float("alpha", 0.0) * 100.0 + 0.5) as int, relu.attr_int("axis", -1)
    attr := relu.attrs.get(0)
    println attr.name, attr.kind
    println m.feed_names().len(), m.inputs.get(0), m.outputs.get(0)

    mut shape := tensor.Shape2(1, 3)
    mut x := tensor.Full(shape, -1.5)
    x.set_at(2, 4.0)
    mut inputs := Vector {} as Vector<tensor.Tensor>
    inputs.push(x)
    mut outputs := onnx.Run(m, inputs, good)
    mut y := outputs.get(0)
    println good, (y.at(0) * 100.0 - 0.5) as int, y.at(2)

    path := os.TempDir() + "/salam_tiny_en.onnx"
    _ := archive.WriteBinaryFileBuf(path, buffer)
    mut m2 := onnx.LoadOnnx(path, good)
    println good, m2.nodes.len()
    m2.free()
    m.free()
    compress.BufFree(buffer)
end
Outputtrue true 8 2 1 w LeakyRelu h y 0 10 -1 alpha 1 1 x y true -30 8 true 2

free

func free()
Frees the attribute.

The example for this item is shown with the ones above: onnx-Run.salam

Node

struct Node
One graph node: one operator with named inputs and outputs.
NameTypeDescription
opstr = ""The operator name, such as Gemm or Relu.
namestr = ""The node name.
inputsVectorThe names of the inputs.
outputsVectorThe names of the outputs.
attrsVectorThe attributes.

The example for this item is shown with the ones above: onnx-Run.salam

attr_index

func attr_index(name: str): int
The index of the attribute with this name; -1 when there is none.

The example for this item is shown with the ones above: onnx-Run.salam

attr_int

func attr_int(name: str, dflt: i64): i64
An integer attribute, or the default value.

The example for this item is shown with the ones above: onnx-Run.salam

attr_float

func attr_float(name: str, dflt: f64): f64
A float attribute, or the default value.

The example for this item is shown with the ones above: onnx-Run.salam

free

func free()
Frees the node.

The example for this item is shown with the ones above: onnx-Run.salam

Model

struct Model
A parsed ONNX model.
NameTypeDescription
inputsVectorThe names of the graph inputs.
outputsVectorThe names of the outputs.
nodesVectorThe nodes, in the order they run.
init_namesVectorThe names of the fixed weights.
initsVectorThe fixed weights.
ir_versioni64 = 0The IR version in the file.
errorstr = ""The error message.
okbool = falseIt was read correctly.

The example for this item is shown with the ones above: onnx-Run.salam

feed_names

func feed_names(): Vector<str>
The inputs you have to supply, meaning the inputs that are not fixed weights; pass them to Run in that order.

The example for this item is shown with the ones above: onnx-Run.salam

free

func free()
Frees the model.

The example for this item is shown with the ones above: onnx-Run.salam

Functions

ParseOnnx

func ParseOnnx(p: void*, n: int, ok &: bool): Model
Reads the model from bytes in memory.

The example for this item is shown with the ones above: onnx-Run.salam

LoadOnnx

func LoadOnnx(path: str, ok &: bool): Model
Reads the model from a .onnx file.

The example for this item is shown with the ones above: onnx-Run.salam

Run

func Run(model &: Model, inputs &: Vector<tensor.Tensor>, ok &: bool): Vector<tensor.Tensor>
Runs the model over the inputs and returns the outputs in the order of the graph outputs; the usual operators are supported, among them Gemm, MatMul, Add, Mul, Relu, LeakyRelu, Softmax and Transpose.

The example for this item is shown with the ones above: onnx-Run.salam