Replacing onnxruntime’s protobuf usage with onnx-light#
onnxruntime (ORT) is written against the protobuf implementation of
onnx. Besides the message types (ModelProto,
TensorProto, …), ORT calls the protobuf
message API (ParseFromArray, SerializeToArray, ByteSizeLong, …)
and the protobuf I/O streams (google::protobuf::io::ZeroCopyInputStream,
FileInputStream, FileOutputStream, …).
onnx-light is protobuf-free: its message classes do not expose these
methods. This page documents, method by method, how to replace every protobuf
/ onnx C++ construct that onnxruntime relies on with its onnx-light
equivalent. It is the reference used by the onnxruntime_USE_ONNX_LIGHT
build option.
Detecting the backend at compile time#
When onnxruntime is configured with -Donnxruntime_USE_ONNX_LIGHT=ON the
build defines the preprocessor macro ORT_USE_ONNX_LIGHT for every
translation unit (add_compile_definitions(ORT_USE_ONNX_LIGHT)). Code that
must behave differently between the two backends branches on that macro:
#if defined(ORT_USE_ONNX_LIGHT)
// onnx-light native API
#else
// protobuf API
#endif
The onnx-light drop-in header <onnx/onnx_pb.h> also defines
ONNX_LIGHT_NAMESPACE (the upstream onnx package does not), which can be
used as a header-only fallback detector.
The message (de)serialization API#
onnx-light message classes expose the following native API (declared by the
SERIALIZATION_METHOD() macro in onnx_light/onnx_proto/stream_class.h):
onnx-light method |
Meaning |
|---|---|
|
Parse the message from a byte buffer (returns |
|
Parse the message from a |
|
Serialize the message into a |
|
Compute the serialized-size split (proto / small / big data). |
|
Total serialized size in bytes ( |
Every protobuf message method used by onnxruntime maps onto that native API:
protobuf ( |
onnx-light replacement |
|---|---|
|
|
|
|
|
|
|
read the descriptor into a |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note
onnx-light has no 2 GB message-size limit and lets exceptions propagate
instead of returning false (see the design notes).
The wrappers above return true on success so onnxruntime’s bool
call sites keep working unchanged.
A ready-made onnxruntime helper#
To keep the two backends in a single place, onnxruntime ships a header-only
adapter, include/onnxruntime/core/graph/onnx_proto_serialize.h, exposing
templated free functions in namespace onnxruntime::proto_io. Each function
compiles to the protobuf call or the onnx-light call depending on
ORT_USE_ONNX_LIGHT:
Helper |
Replaces |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <google/protobuf/io/zero_copy_stream_impl.h>
google::protobuf::io::IstreamInputStream zci(&istream);
bool ok = model_proto.ParseFromZeroCopyStream(&zci) && istream.eof();
auto n = model_proto.ByteSizeLong();
model_proto.SerializeToArray(buffer, n);
#include "core/graph/onnx_proto_serialize.h"
bool ok = onnxruntime::proto_io::ParseFromIStream(model_proto, istream);
auto n = onnxruntime::proto_io::ByteSize(model_proto);
onnxruntime::proto_io::SerializeToArray(model_proto, buffer, n);
The google::protobuf symbols still referenced by onnxruntime#
A few onnxruntime files reference the google::protobuf namespace for
non-serialization purposes. onnx-light provides drop-in equivalents in
onnx_light/onnx_proto/google_protobuf_compat.h (pulled in automatically by
the <onnx/onnx_pb.h> compatibility header):
protobuf symbol |
onnx-light shim |
|---|---|
|
alias of |
|
alias of |
|
alias of |
|
forwards to |
|
no-op (onnx-light has no global protobuf state) |
|
alias of |
|
alias of |
|
alias of |
|
alias of |
|
alias of |
|
alias of |
Every class in google_protobuf_compat.h is now a pure using alias to a
concrete onnx-light class. The ZeroCopy stream interface
(Next / BackUp / ByteCount and, for output streams, Flush) is
implemented directly on the onnx-light BinaryStream / BinaryWriteStream
hierarchy in stream.h / stream.cc, so the compat header carries no
implementation of its own.
Version guards#
Blocks guarded by GOOGLE_PROTOBUF_VERSION must also exclude the onnx-light
build, because the macro is undefined there (and would evaluate to 0). The
protobuf-arena helpers RepeatedPtrField::ClearedCount /
ReleaseCleared have no onnx-light counterpart and are simply skipped
(onnx-light stores repeated fields in std::vector and frees them on
Clear()):
#if !defined(ORT_USE_ONNX_LIGHT) && GOOGLE_PROTOBUF_VERSION < 5026000
// protobuf-only cleared-object reclamation
#endif
onnxruntime files converted#
The core library (always built) has been converted to route through
onnxruntime::proto_io or to guard protobuf-only code:
core/graph/model.cc— istream / file-descriptor load and save,ByteSizeLong,SerializeToArray,ParseFromArray.core/graph/graph.cc—ClearedCount/ReleaseClearedguards.core/session/inference_session.cc—ParseFromArray,ByteSizeLong.core/session/provider_bridge_ort.cc—ModelProto/FunctionProtoSerializeToString/SerializeToOstream/ParseFromString/SerializeAsStringbridge methods.core/framework/graph_partitioner.cc—ByteSizeLong,SerializeToArray,SerializeToOstream, file-descriptor save.core/framework/debug_node_inputs_outputs_utils.cc—SerializeToFileDescriptor,SerializeAsString.core/framework/allocation_planner.cc—ByteSizeLong.
The same substitution (include core/graph/onnx_proto_serialize.h and call
the matching proto_io helper) applies to the optional components that are
only built on demand and therefore not covered by the default build:
execution providers —
providers/tensorrt,providers/nv_tensorrt_rtx,providers/openvino,providers/cann,providers/migraphx,providers/vitisai(SerializeToString/ParseFromString/SerializeAsStringused in abool/ return context).training —
orttraining/...(ParseFromArray/SerializeToZeroCopyStream).tests —
test/onnx,test/framework,test/fuzzing(model load / save helpers).
See also#
How to replace onnx by onnx-light — the general onnx → onnx-light migration guide.
Linking onnx-light in C++ — the exported CMake targets.