onnx-light-cpu#

Highly optimized CPU kernels for onnx-light.

It implements ONNX operators with SIMD-accelerated kernels that dispatch at runtime to the best available instruction set (AVX-512, AVX2, AVX, SSE2, or a scalar fallback). The optimal implementation is selected once through CPUID-based CPU feature detection and cached, so the dispatch overhead is paid only once.

The kernels can be used directly from C++ or installed into onnx-light’s shared C++ kernel dispatch table so any ONNX model using a supported operator runs the optimized kernel when evaluated through a ReferenceEvaluator. See Getting Started to install the package and run your first model, the Standalone C++ inference page for a complete standalone C++ inference program, the ByOp page for the list of operators provided by this repository, the Examples gallery for runnable examples, the Benchmarks gallery for performance comparisons against other back-ends, and the Processor performance for a profile of the current host.

Registering the optimized kernels#

Registration installs every shipped onnx-light-cpu kernel into onnx-light’s shared CPU dispatch table. It is process-wide, so call it once before creating the evaluators or runtime sessions that should use the accelerated implementations.

Build with the onnx-light integration enabled, then call onnx_light_cpu.register_kernels() before constructing the evaluator:

from onnx_light.onnx.reference import ReferenceEvaluator
from onnx_light_cpu import register_kernels

register_kernels()
session = ReferenceEvaluator(model)
outputs = session.run(None, feeds)

To override an operator for one evaluator only, leave the shared table unchanged and register a Python kernel on that session:

import numpy as np
from onnx_light.onnx.reference import ReferenceEvaluator

session = ReferenceEvaluator(model)
session.register_custom_kernel("", "Abs", lambda node, x: np.abs(x))
outputs = session.run(None, feeds)

Other evaluators keep their existing Abs implementation.

The Python entry point is available in builds configured with ONNX_LIGHT_CPU_WITH_ONNX_LIGHT=ON.

Link onnx_light_cpu::lib_onnx_light_cpu_kernels and register the kernels before constructing an onnx-light runtime session:

#include <onnx_light_cpu/kernels/register_kernels.h>

int main() {
  onnx_light_cpu::RegisterAllKernels();

  // RuntimeSession and ReferenceEvaluator now resolve supported
  // CPU operators to the onnx-light-cpu implementations.
}

The native integration is built with -DONNX_LIGHT_CPU_WITH_ONNX_LIGHT=ON.

To override an operator for one C++ runtime context only, register its callback on that context before the session’s first Run:

#include <onnx_core/runtime/kernels/kernel_context.h>
#include <onnx_core/runtime/memory/simple_tensor.h>
#include <onnx_core/runtime/runtime_context.h>
#include <onnx_core/runtime/runtime_session.h>

#include <cmath>
#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <vector>

namespace rt = ONNX_LIGHT_NAMESPACE::core::runtime;

void RegisterAbsForSession(rt::RuntimeContext &context) {
  context.RegisterCustomKernel(
      "", "Abs", [](const ONNX_LIGHT_NAMESPACE::NodeProto &node,
                     rt::RuntimeContext &context) {
        const rt::Tensor &input = context.Get(node.input(0));
        if (input.data_type != static_cast<std::int32_t>(rt::DataType::FLOAT)) {
          throw std::invalid_argument("This example Abs kernel requires FLOAT input.");
        }
        std::vector<float> output(static_cast<std::size_t>(input.element_count()));
        for (std::size_t i = 0; i < output.size(); ++i) {
          output[i] = std::fabs(input.AsFloat()[i]);
        }
        context.Set(node.output(0),
                    rt::Tensor::FromFloat(node.output(0), input.shape, output));
      });
}

rt::RuntimeContext context(rt::KernelContext(rt::DefaultOpset(18)));
RegisterAbsForSession(context);
rt::RuntimeSession session(context.GetExecutionPlan(graph));
session.Run(context);

RuntimeSession caches resolved kernels on its first run, so register the callback before then. Other contexts continue to use their existing Abs implementation.

The shipped-kernel Python and C++ entry points above update the same shared C++ KernelDispatchTable. See Registering kernels for per-session overrides, kernel-usage inspection, custom registrations, and troubleshooting when two builds link different copies of lib_onnx_core.