ops

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package ops provides ONNX operator implementations with a common Operator interface and a registry for looking up operators by type.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrIncompatibleShapes indicates that the input tensors have shapes
	// that cannot be broadcast together.
	ErrIncompatibleShapes = errors.New("ops: incompatible shapes")

	// ErrInvalidInputCount indicates that an operator received the wrong
	// number of input tensors.
	ErrInvalidInputCount = errors.New("ops: invalid input count")

	// ErrOperatorNotFound indicates that a registry lookup failed because
	// no operator is registered under the requested op type string.
	ErrOperatorNotFound = errors.New("ops: operator not found")

	// ErrOperatorExists indicates that a registration was rejected because
	// an operator is already registered under the given op type string.
	ErrOperatorExists = errors.New("ops: operator already registered")

	// ErrEmptyOpType indicates that a registry operation was called with
	// an empty op type string.
	ErrEmptyOpType = errors.New("ops: empty op type")

	// ErrNilOperator indicates that a registration was called with a nil
	// operator implementation.
	ErrNilOperator = errors.New("ops: nil operator")
)

Sentinel errors returned by operator implementations and the registry.

ActivePool is the package-level reference to the tensor pool used by operators that allocate raw []float32 scratch buffers (Conv's im2col + gemm scratch, ConvLeakyRelu likewise). The engine stores its pool here before the execution loop; operators read it via Load.

It is an atomic.Pointer so concurrent Run() calls on different engines (or different tests with t.Parallel) do not race on the global. When nil, operators fall back to fresh heap allocation.

View Source
var ActiveWorkerPool atomic.Pointer[WorkerPool]

ActiveWorkerPool is the package-level reference to the current WorkerPool used by fanout sites. The engine stores its pool here at the start of Run (via atomic.Pointer.Store) and clears it at the end (Shutdown drains workers; Store(nil) is best-effort hand-off).

Operators read it via Load — when nil, they fall back to either the legacy budget-based goroutine spawn or a fully sequential execution (per-site policy).

Functions

func DequantizeQ8_0

func DequantizeQ8_0(src []byte, dst []float32, count int)

DequantizeQ8_0 reverses QuantizeQ8_0: it writes count fp32 weights into dst by reading numBlocks Q8_0 blocks from src. dst must have capacity for at least count elements; src must hold at least ceil(count/32) blocks. Bytes past the live element count in the final block are ignored.

This routine is provided for tests and tools (sidecar loaders); the fast inference path fuses dequantisation into the GEMM kernel.

func ForceRegister

func ForceRegister(opType string, op Operator) error

ForceRegister stores an operator implementation unconditionally, allowing it to overwrite an existing registration. It validates that opType is non-empty and op is non-nil.

func Im2col

func Im2col(pool *tensor.Pool, data []float32, channels, height, width, kH, kW, padTop, padLeft, padBottom, padRight, strideH, strideW, dilationH, dilationW int) []float32

Im2col is an exported wrapper around the internal im2col function, making the im2col transformation available to other packages (e.g., the GPU provider) without duplicating the implementation.

func List

func List() []string

List returns a sorted slice of all registered op type strings. The returned slice is a copy and safe to mutate.

func MustRegister

func MustRegister(opType string, op Operator)

MustRegister calls Register and panics if the registration fails. It is the exported counterpart of mustRegister and is intended for use in init() functions of sibling sub-packages (ops/winograd, ops/q8, the graph fusion packages) that need to add operators at program start.

The no-panic rule that governs the rest of this module applies to runtime control flow. Registration is a one-shot program-startup operation; a duplicate or nil registration there is always a programmer error and there is no caller to return the failure to.

func QuantizeQ8_0

func QuantizeQ8_0(src []float32) []byte

QuantizeQ8_0 quantizes the fp32 slice src into a packed Q8_0 byte stream. The returned slice has length ceil(len(src)/32) * 36.

Per-block quantization:

  • amax := max(|src[k]|) for k in block
  • s := amax / 127.0 (s == 0 if the block is all zeros)
  • q[i] := round(src[i] / s) clamped to [-127, 127]

Tail handling: if len(src) is not a multiple of 32, the last block pads its int8 region with zeros and uses the scale derived from only the live elements. The 32-element block size is chosen to match llama.cpp; smaller blocks would tighten the per-block dynamic range at the cost of more scale storage.

func QuantizeWeightRows

func QuantizeWeightRows(weights []float32, outChannels, innerSize int) (blocks []byte, blocksPerRow int)

QuantizeWeightRows packs an outChannels × innerSize fp32 weight matrix (e.g. a Conv weight reshaped to [outC, inC*kH*kW]) into a contiguous Q8_0 byte stream where each output channel occupies a fixed row stride of blocksPerRow * q8BlockBytes bytes. This is the layout the kernel expects on its A side.

Returned blocksPerRow == ceil(innerSize / 32).

func Register

func Register(opType string, op Operator) error

Register stores an operator implementation keyed by its ONNX op type string (e.g., "Add", "Mul", "LeakyRelu", "Clip"). It returns an error if the opType is empty, op is nil, or an operator is already registered under that opType.

func Transpose

func Transpose(pool *tensor.Pool, data []float32, rows, cols int) []float32

Transpose is an exported wrapper around the internal transpose function, making the row-major matrix transposition available to other packages (e.g., the GPU provider) without duplicating the implementation.

func Unregister

func Unregister(opType string) error

Unregister removes the operator registered under opType. It returns an error if opType is empty or no operator is registered under that name.

Types

type AddOp

type AddOp struct{}

AddOp implements the ONNX Add operator. It computes the elementwise sum of two input tensors with broadcasting support.

func (AddOp) Execute

func (AddOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute validates that exactly 2 inputs are provided, then delegates to broadcastBinaryOp with addition as the elementwise function.

type AveragePoolOp

type AveragePoolOp struct{}

AveragePoolOp implements the ONNX AveragePool operator for 2D NCHW inputs. It supports configurable kernel_shape, strides, pads and the count_include_pad flag. ceil_mode is supported for both 0 (floor, the default) and 1 (ceil) output-size rounding; dilations are assumed 1 (the default — the F5DCTNet v1/v1s trunks only emit plain 2x2/s2 downsample pools).

Why this op exists in a "minimal CNN runtime": the v1 and v1s F5DCTNet trunks downsample with AveragePool (the v1ss trunk replaced it with strided convolution). Running the v44 v1/v1s ensemble members in pure Go therefore requires this operator.

func (AveragePoolOp) Execute

func (AveragePoolOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute pools each (batch, channel) plane independently. The window sum is taken over the in-bounds elements of the kernel footprint; the divisor is the full kernel area when count_include_pad=1 and the in-bounds element count otherwise (matching the ONNX spec).

type BatchNormalizationOp

type BatchNormalizationOp struct{}

BatchNormalizationOp implements the ONNX BatchNormalization operator in inference mode (test mode):

y = (x - mean) / sqrt(var + epsilon) * scale + bias

Inputs (positional, all 1-D length C except x):

  • x: [N, C, ...spatial...]
  • scale: [C]
  • bias: [C]
  • mean: [C]
  • var: [C]

The channel axis is fixed at index 1 (NCHW layout). For ranks > 2 the remaining trailing dims are treated as spatial. For rank-2 input [N, C] the operator degenerates to a per-element affine transform.

Only the data output (output 0) is produced — the optional auxiliary outputs (running mean / running var) used during training do not exist in inference graphs we care about.

func (BatchNormalizationOp) Execute

func (BatchNormalizationOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute reads epsilon, validates the input shapes, precomputes a per-channel multiplier and offset, and applies the affine transform in a single sweep over the input data.

type CastOp

type CastOp struct{}

CastOp implements the ONNX Cast operator. The runtime tensor type is Float32 in every internal kernel, so Cast is functionally a no-op when the requested target type is also a real-valued type (Float32 / Float16 / Float64) and is otherwise a value-by-value coercion to the integer target type.

Because the operator's job is to bridge ONNX-declared graph types to the Float32 runtime, the implementation does not change the bit pattern of the underlying float32 buffer — it simply returns a tensor aliasing the input data with the same shape. Models that rely on Cast to perform integer truncation (e.g. Cast(float → int32) → downstream Reshape that uses the int32 buffer as an index list) are not supported here; that workload is rare in inference graphs and every observed F5 / Real-ESRGAN model uses Cast only to bridge an integer-typed graph input into the float32 compute domain.

Attribute contract: the ONNX `to` attribute carries the target DataType as an int. CastOp records the value purely so future ops that introspect the cast can reason about it; the Execute method itself is type-agnostic.

func (CastOp) Execute

func (CastOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute validates that exactly one input is supplied and returns a shape-equivalent tensor backed by the same float32 data. The `to` attribute is read for diagnostic purposes; it is not used to alter the runtime tensor type because every kernel downstream consumes float32.

type ClipOp

type ClipOp struct{}

ClipOp implements the ONNX Clip operator (opset 11+). It clamps each element of the input tensor between optional min and max scalar bounds provided as tensor inputs.

func (ClipOp) Execute

func (op ClipOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute clamps the input tensor values. It accepts 1 to 3 inputs: (input, [min], [max]). Min and max are optional scalar tensors.

type ConcatFusedTailOp

type ConcatFusedTailOp struct{}

ConcatFusedTailOp is the runtime counterpart of the graph.ApplyConcatWriteFusion pass. It implements a fused (Conv-variant → Concat) tail pattern where the producer Conv writes its output directly into the tail slice of the joint Concat output buffer, eliminating both the producer's standalone output materialisation and the corresponding memcpy that an unfused Concat would perform on that tail slice.

Input layout (set by the fusion pass):

[prefix_0, prefix_1, ..., prefix_{P-1}, x, w, bias_or_nil, slope?]

where P = "prefix_count" attribute, the prefix_i are the original Concat inputs other than the last, and the trailing inputs are the producer Conv's inputs in their canonical positions (slope is present only when producer_op == "ConvPRelu"). Bias may be nil for two-input Convs.

Attribute contract:

axis           int    — Concat axis; always 1 in the production graphs but
                        carried through so the op is self-describing.
prefix_count   int    — Number of prefix inputs (0 ≤ P ≤ len(inputs)-2).
producer_op    string — "Conv", "ConvLeakyRelu", or "ConvPRelu". Tells the
                        runtime which underlying kernel to dispatch.
strides, pads, dilations — Conv attributes, forwarded from the producer.
alpha          float  — LeakyReLU slope; required when producer_op =="ConvLeakyRelu".

The op allocates the joint output tensor of shape [N, sum(prefix_C)+producer_C, H, W] from the supplied allocator, copies each prefix input into its slice with the same block-copy strategy ConcatOp uses, then dispatches the producer Conv kernel via a custom allocator that returns a "view tensor" backed by the tail slice of the joint buffer. The Conv kernel's writes therefore land directly in the joint output, avoiding the separate output buffer and the Concat memcpy.

Batch fallback: when batch != 1, the per-batch tail slice of the joint NCHW buffer is non-contiguous (strides interleave the prefix and producer regions) and the view-tensor trick would corrupt the layout. The op falls back to running the producer to a fresh tensor and copying like a normal Concat. The production SR pipeline always uses batch == 1, so this fallback is a correctness safety net rather than a hot path.

func (ConcatFusedTailOp) Execute

func (ConcatFusedTailOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute runs the fused Concat-tail op. See the type doc for input and attribute conventions.

type ConcatOp

type ConcatOp struct{}

ConcatOp implements the ONNX Concat operator. It concatenates variadic input tensors along the specified axis using block-copy memory transfers.

func (ConcatOp) Execute

func (ConcatOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute validates inputs and the axis attribute, then concatenates all input tensors along the resolved axis dimension.

type ConvLeakyReluOp

type ConvLeakyReluOp struct{}

ConvLeakyReluOp is the fused Conv → LeakyReLU operator. It performs the same im2col + GEMM as ConvOp, but the gemmTransposedB write fuses the per-output-channel bias add AND the LeakyReLU activation into one pass — eliminating the intermediate output materialisation that an unfused Conv → LeakyReLU pair would incur.

In Real-ESRGAN the Conv layer is followed almost universally by LeakyReLU (279 of the 351 Conv outputs feed directly into LeakyRelu), so the savings compound at the model level.

Attribute contract (read from the merged Conv + LeakyRelu attributes produced by the graph fusion pass):

strides:    int[2]   — Conv stride; defaults to [1, 1]
pads:       int[4]   — Conv pads (top, left, bottom, right); defaults to zeros
dilations:  int[2]   — Conv dilations; defaults to [1, 1]
alpha:      float32  — LeakyReLU slope for negative values; defaults to 0.01

Inputs are the same as Conv: [x, w, bias?].

func (ConvLeakyReluOp) Execute

func (ConvLeakyReluOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute runs the fused Conv + LeakyReLU. The implementation mirrors ConvOp.Execute but calls gemmTransposedB with leaky=true and the supplied alpha so the kernel writes the activated values directly.

type ConvOp

type ConvOp struct{}

ConvOp implements the ONNX Conv operator using im2col matrix unrolling followed by GEMM. It supports 2D convolution with configurable strides, padding, and dilations for NCHW layout.

func (ConvOp) Execute

func (ConvOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute validates inputs, reads convolution attributes with defaults, and performs im2col + GEMM convolution independently per batch sample. Internal im2col, transpose, and gemm buffers are drawn from the package-level ActivePool when available, eliminating per-Execute heap allocations for these temporaries.

type ConvPReluOp

type ConvPReluOp struct{}

ConvPReluOp is the fused Conv → PReLU operator. It performs the same im2col + GEMM as ConvOp, but the gemmTransposedBPReLU write fuses the per-output-channel bias add AND the per-output-channel PReLU activation into one pass — eliminating the intermediate output materialisation that an unfused Conv → PReLU pair would incur.

In realesr-general-x4v3, 33 of the 34 Conv layers feed directly into a per-channel PReLU; collapsing those pairs is the dominant v3-specific speed win because every elimination removes one full read+write pass over the activation tensor.

Attribute contract (read from the Conv attributes carried over by the graph fusion pass; the PReLU op carries no attributes of its own):

strides:    int[2]   — Conv stride; defaults to [1, 1]
pads:       int[4]   — Conv pads (top, left, bottom, right); defaults to zeros
dilations:  int[2]   — Conv dilations; defaults to [1, 1]

Inputs: [x, w, bias_or_nil, slope]. Bias is optional (3-input Conv passes a non-nil tensor; 2-input Conv passes nil at index 2). Slope is the PReLU slope tensor and must be either a scalar (1 element, broadcast across all channels) or per-channel-broadcastable using the same logic as PReluOp ([C], [C, 1, 1], [1, C, 1, 1], …).

func (ConvPReluOp) Execute

func (ConvPReluOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute runs the fused Conv + PReLU. The implementation mirrors ConvOp.Execute but expands the slope tensor into a per-output-channel []float32 once per call and dispatches gemmTransposedBPReLU to write the activated values directly.

type DepthToSpaceOp

type DepthToSpaceOp struct{}

DepthToSpaceOp implements the ONNX DepthToSpace operator. It rearranges data from the depth (channel) dimension into spatial blocks, producing an output tensor of shape [N, C/(r*r), H*r, W*r] from an input of shape [N, C, H, W] and a blocksize attribute r.

Two modes are supported:

  • "DCR" (depth-column-row): the legacy default for opset < 13. The channel axis is interpreted as (blocksize, blocksize, C_out).
  • "CRD" (column-row-depth): the default for opset >= 13. The channel axis is interpreted as (C_out, blocksize, blocksize).

We default to "DCR" to match the ONNX spec defaults; callers running opset >= 13 models that omit the attribute (which is rare since the node is usually exported with mode set explicitly) should configure it at the model-import layer.

func (DepthToSpaceOp) Execute

func (DepthToSpaceOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute reads the blocksize and mode attributes, validates the input shape, and writes the rearranged output via direct flat-index iteration over the source tensor.

type DropoutOp

type DropoutOp struct{}

DropoutOp implements the ONNX Dropout operator. In an inference-only runtime Dropout is the identity function: it returns a copy of the input tensor regardless of the ratio attribute / input or the training_mode flag.

ONNX changed Dropout's signature across opsets:

  • opset < 12: 1 input (data), `ratio` is an attribute.
  • opset >= 12: up to 3 inputs (data, ratio, training_mode) and a `seed` attribute.

Both forms produce one or two outputs (data, mask). Because we never materialise the boolean mask in inference, this implementation emits only the data output and ignores ratio / training_mode entirely.

func (DropoutOp) Execute

func (DropoutOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute returns a single-tensor slice carrying a fresh copy of the first input.

type EqualOp

type EqualOp struct{}

EqualOp implements the ONNX Equal operator. For each pair of broadcasted elements it emits 1.0 when the inputs match and 0.0 otherwise. ONNX defines the output as bool, but the runtime is float32-only so the boolean is encoded as 1.0/0.0 in a float32 tensor — downstream Cast and arithmetic ops treat the encoding transparently.

func (EqualOp) Execute

func (EqualOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute compares the two input tensors element-wise (with NumPy-style broadcasting) and returns a tensor whose entries are 1.0 where the inputs are equal and 0.0 elsewhere.

type FlattenOp

type FlattenOp struct{}

FlattenOp implements the ONNX Flatten operator. It reshapes the input tensor into a 2-D tensor whose first dimension is the product of all input dims with index < axis and whose second dimension is the product of the remaining dims.

The axis attribute defaults to 1. Negative values count from the end: axis = -1 is equivalent to rank - 1. The row-major data layout is preserved verbatim — Flatten is a metadata-only operation in row-major storage.

func (FlattenOp) Execute

func (FlattenOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute computes the 2-D output shape from the axis attribute and returns a tensor backed by a copy of the input data.

type GemmOp

type GemmOp struct{}

GemmOp implements the ONNX Gemm operator (General Matrix Multiply):

Y = alpha * A^* @ B^* + beta * C

where A^* = A^T when transA == 1 (otherwise A), and likewise for B. C is an optional bias tensor that is broadcast over [M, N] following ONNX/NumPy rules.

Attributes (all optional):

  • alpha float, default 1.0
  • beta float, default 1.0
  • transA int, default 0
  • transB int, default 0

The matmul work is delegated to the package-internal gemm() helper in gemm.go which selects a SIMD or scalar kernel via build tags. This operator wrapper is responsible only for transposition (when requested), the alpha/beta scaling, and the broadcast bias add.

func (GemmOp) Execute

func (GemmOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute performs the GEMM and returns the [M, N] result.

type GlobalAveragePoolOp

type GlobalAveragePoolOp struct{}

GlobalAveragePoolOp implements the ONNX GlobalAveragePool operator. Given an input of shape [N, C, D1, D2, ...] it computes the mean over the spatial dims (everything from axis 2 onward), producing an output of shape [N, C, 1, 1, ...] with the spatial axes preserved as size-1 dims (matching the ONNX spec, which keeps rank rather than squeezing).

func (GlobalAveragePoolOp) Execute

func (GlobalAveragePoolOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute returns a tensor of the same rank as the input where every spatial dim is collapsed to length 1 and the value is the mean over that channel's spatial elements.

type LeakyReluOp

type LeakyReluOp struct{}

LeakyReluOp implements the ONNX LeakyRelu operator. For each element, it outputs x if x >= 0, otherwise alpha * x. The alpha attribute defaults to 0.01 when absent.

func (LeakyReluOp) Execute

func (op LeakyReluOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute applies the leaky ReLU activation to the single input tensor.

type MulAddOp

type MulAddOp struct{}

MulAddOp is the fused Mul + Add operator. It computes

y = (a * b) + c

in a single pass over the output, eliminating the intermediate elementwise tensor that an unfused Mul → Add pair would materialise.

Inputs are exactly three tensors [a, b, c] in this order. The graph fusion pass canonicalises the input ordering so the kernel can assume the operand arrangement above (Mul is commutative, Add is commutative — the fusion picks an ordering and this op trusts it).

Broadcasting follows ONNX/NumPy rules and matches the shape semantics of an unfused Mul + Add: the Mul intermediate has shape broadcast(a, b), and the final output has shape broadcast(broadcast(a, b), c). The fast-path covers the common Real-ESRGAN residual-scaling shape pattern where one of {a, b} is a scalar (shape [1]) or a per-channel vector ([1, C, 1, 1]) and c shares the same N-dimensional shape as the other Mul operand.

func (MulAddOp) Execute

func (MulAddOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute runs the fused Mul + Add. It dispatches to a single-pass kernel for the equal-shape and scalar-broadcast fast paths, and falls back to the generic broadcastBinaryOp pair (with a small scratch tensor) for anything more exotic. Even the slow path only materialises the intermediate via the standard broadcast helper, so numerical results match Mul + Add bit-for-bit on the slow path and to within ~1e-7 on the fast paths (the FMA reordering is identical to what conv_leaky_relu does).

type MulOp

type MulOp struct{}

MulOp implements the ONNX Mul operator. It computes the elementwise product of two input tensors with broadcasting support.

func (MulOp) Execute

func (MulOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute validates that exactly 2 inputs are provided, then delegates to broadcastBinaryOp with multiplication as the elementwise function.

type Operator

type Operator interface {
	Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)
}

Operator defines the execution interface for a single ONNX operator. Each implementation is a stateless struct that validates inputs, performs computation, and returns exactly one output tensor on success.

The alloc parameter controls how output tensors are allocated. Passing tensor.New uses heap allocation; passing a pool-backed allocator reuses buffers. A nil alloc falls back to defaultAlloc (tensor.New).

func Get

func Get(opType string) (Operator, error)

Get returns the registered operator for the given ONNX op type string. It returns an error wrapping ErrOperatorNotFound if no operator is registered under that name.

type PReluOp

type PReluOp struct{}

PReluOp implements the ONNX PRelu operator. For each element, it outputs x when x >= 0, otherwise slope * x. The slope is supplied as a runtime input tensor (input[1]) and is broadcast against the data input across the channel dimension.

This implementation accepts any slope tensor that is unidirectionally broadcastable to a per-channel layout: a single scalar, a 1-D [C], or any rank-N shape whose product is C with all non-channel dimensions equal to 1 (e.g., [C, 1, 1] or [1, C, 1, 1] — both appear in realesr-general-x4v3 exports). Anything else is rejected with an error wrapping ErrIncompatibleShapes.

func (PReluOp) Execute

func (PReluOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute applies the PReLU activation, broadcasting the per-channel slope over the input tensor and writing into a freshly allocated output.

type ReduceMeanOp

type ReduceMeanOp struct{}

ReduceMeanOp implements the ONNX ReduceMean operator. It computes the arithmetic mean of the input tensor across the named axes.

Axis source has shifted between opset versions:

  • opset <= 17: `axes` is an int attribute list.
  • opset >= 18: `axes` is supplied as the (optional) second input tensor, with float32 entries (the runtime is float32-only).

This implementation accepts both forms with the second-input form taking precedence when present, matching the pattern in unsqueeze.go.

Attributes:

  • axes ints, optional (opset <= 17)
  • keepdims int, default 1
  • noop_with_empty_axes int, default 0 (only relevant when axes is empty)

When axes is absent (and not provided as an input), ONNX reduces over every axis, producing a scalar — unless `noop_with_empty_axes == 1` (opset >= 18), in which case the input is returned unchanged.

func (ReduceMeanOp) Execute

func (ReduceMeanOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute resolves axes, computes the output shape, and writes the per-output-cell mean into the output tensor.

type ReluOp

type ReluOp struct{}

ReluOp implements the ONNX Relu operator. For each element it computes y = max(0, x). This is a stateless, attribute-free, single-input elementwise activation.

func (ReluOp) Execute

func (ReluOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute applies the rectified linear activation to the single input tensor and returns a new tensor of the same shape.

type ReshapeOp

type ReshapeOp struct{}

ReshapeOp implements the ONNX Reshape operator. It returns a tensor with a new shape but the same underlying float32 data, copied verbatim.

The shape input is a 1-D tensor (stored as float32 in the runtime; values are taken as their integer truncation). A value of -1 in the shape means "infer this dimension from the remaining elements". A value of 0 in the shape means "copy the corresponding dimension from the input" when the allowzero attribute is absent or 0; when allowzero is 1, a 0 is taken literally (which in practice yields an empty tensor and is not exercised by inference workloads in this codebase).

func (ReshapeOp) Execute

func (ReshapeOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute computes the new shape from the shape input, validates that the product of the new shape matches the input element count, and returns a tensor with the new shape backed by a fresh copy of the input data.

type ResizeOp

type ResizeOp struct{}

ResizeOp implements the ONNX Resize operator (opset 11+). It supports bilinear and nearest neighbor interpolation with configurable coordinate transformation modes (asymmetric, half_pixel, align_corners).

func (ResizeOp) Execute

func (ResizeOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute validates inputs, resolves output dimensions from scales or sizes, and performs the selected interpolation independently per (N, C) slice.

type SigmoidOp

type SigmoidOp struct{}

SigmoidOp implements the ONNX Sigmoid operator. For each element it computes 1 / (1 + exp(-x)).

Performance: SPAN issues 18 Sigmoid ops per Run, each over a feature map of up to 256K elements. The naive math.Exp path costs ~30 ns per element on M-series. We replace it with a 1024-entry lookup table over [-8, 8] with linear interpolation, which is ~5× faster (~6 ns per element) and within 5e-5 max abs error vs the true sigmoid — well below the precision relevant to image SR (sigmoid output is element-wise multiplied with a feature map, so any error <1e-3 is imperceptible after pipeline-end u8 quantization).

func (SigmoidOp) Execute

func (SigmoidOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute applies the sigmoid activation to the single input tensor.

type SqueezeOp

type SqueezeOp struct{}

SqueezeOp implements the ONNX Squeeze operator. It removes dimensions of size 1. When axes is supplied, only those positions are squeezed (and each must reference a size-1 dim). When axes is absent, every size-1 dimension is removed.

Like Unsqueeze, the axes specification moved from an attribute (opset <= 12) to a second input tensor (opset 13+). This implementation accepts either form: it checks input slot 1 first, then the `axes` attribute.

Underlying data is unchanged; only shape metadata shrinks.

func (SqueezeOp) Execute

func (SqueezeOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute resolves the axes list, removes the named dimensions, and returns a tensor whose data is a copy of the input.

type SubOp

type SubOp struct{}

SubOp implements the ONNX Sub operator. It computes the elementwise difference of two input tensors with NumPy-style broadcasting support.

func (SubOp) Execute

func (SubOp) Execute(inputs []*tensor.Tensor, _ map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute validates that exactly 2 inputs are provided, then delegates to broadcastBinaryOp with subtraction as the elementwise function.

type TransposeOp

type TransposeOp struct{}

TransposeOp implements the ONNX Transpose operator. It permutes the dimensions of the input tensor according to the perm attribute. When perm is absent or empty, the dimensions are reversed (matching the ONNX spec default).

Unlike Reshape, Transpose changes the row-major element order, so data must be physically copied to the new layout. The implementation walks every output element, derives its multi-dimensional index from the output strides, maps that index back through perm to the input coordinate, and reads from the input data at the computed offset.

func (TransposeOp) Execute

func (TransposeOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute returns the transposed tensor.

type UnsqueezeOp

type UnsqueezeOp struct{}

UnsqueezeOp implements the ONNX Unsqueeze operator. It inserts dimensions of size 1 at the positions named by `axes`. Negative axes are interpreted relative to the rank of the OUTPUT (post-unsqueeze) tensor.

The axes specification moved from an attribute (opset <= 12) to a second input tensor (opset 13+). This implementation accepts either form: when a second input is present its float32 data is interpreted as the axes list; otherwise the `axes` attribute is consulted.

The underlying data layout is unchanged — only the shape metadata grows.

func (UnsqueezeOp) Execute

func (UnsqueezeOp) Execute(inputs []*tensor.Tensor, attributes map[string]*onnx.Attribute, alloc tensor.Allocator) ([]*tensor.Tensor, error)

Execute resolves the axes list, computes the output shape, and returns a tensor that shares the input element ordering.

type WorkerPool

type WorkerPool struct {
	// contains filtered or unexported fields
}

WorkerPool is a per-Engine-Run helper-goroutine budget. It is created at the start of Engine.Run, lives for the duration of a single inference call, and is shut down at the end of Run. Fanout sites (Winograd cells, GEMM M-split, Conv im2col fanout) submit work items to the pool; the pool's worker count caps how many helper goroutines may be in flight at once across the whole Run.

Design history: an earlier iteration kept a fixed roster of long-lived worker goroutines parked on a shared channel between work items, hoping to amortise goroutine spawn cost over a Run. On the M-series target it regressed end-to-end at every benchmarked SR shape — channel send/receive per Submit added ~0.5–1µs that swamped the cheap `go fn()` it replaced. The current design keeps the per-Run *budget* (a counted-token slice of the global concurrency limit, see ops/concurrency.go) but lets Submit ad-hoc-spawn a goroutine per work item. Worker spawn cost is paid once per fanout item, not once per Run, but the budget acquisition that used to happen per fanout-site now happens once per Run — eliminating the pthread_cond churn from the old fairHelperCount + tryAcquireWorkers pattern that profiles flagged as 91% of CPU time.

Reentrancy: each Run() creates its own pool, so concurrent Run() calls (different engines, or pipeline tile workers) do not share a pool. The package-level ActiveWorkerPool atomic.Pointer carries "the current pool" for fanout sites to discover. When two Runs race on the global, last-writer-wins is correctness-safe because pools are interchangeable from a work-execution standpoint — any live pool dispatches submitted work correctly.

Sizing: NewWorkerPool tries to acquire up to `requested` tokens from the global workerBudget (capped at GOMAXPROCS-1). The count actually acquired becomes the pool's worker count. This shares the budget across concurrent Runs: when 4 tile workers each call Run simultaneously, each gets ~NumCPU/4 helpers, keeping the OS-thread total bounded by NumCPU. Single-Run mode gets the full budget.

func NewWorkerPool

func NewWorkerPool(requested int) *WorkerPool

NewWorkerPool spawns up to `requested` long-lived workers, bounded by what is currently free in the global workerBudget. Returns a pool that may have fewer workers than requested if the budget was partially saturated by a sibling Run.

`requested` of 0 or below produces a 0-worker pool: every Submit runs synchronously in the caller. This is the safe fallback for single-thread mode (GOMAXPROCS<=1).

The caller is responsible for WorkerPool.Shutdown — typically via `defer pool.Shutdown()` immediately after construction. Shutdown releases the workerBudget tokens.

func (*WorkerPool) Shutdown

func (p *WorkerPool) Shutdown()

Shutdown returns the pool's tokens to the global workerBudget and marks the pool as no longer dispatching. Idempotent — safe to call multiple times (only the first call releases tokens). Typically invoked via `defer pool.Shutdown()` from Engine.Run.

IMPORTANT: callers must wait on their own WaitGroups before calling Shutdown. Submit does not track in-flight goroutines, so Shutdown has no way to wait for them; the fanout-site idiom is:

for i := 0; i < n-1; i++ {
    wg.Add(1)
    pool.Submit(func() { defer wg.Done(); ... })
}
// run last chunk in caller
doWork(...)
wg.Wait() // waits for the helpers' wg.Done

and Shutdown happens later, at end of Run, when no fanout site has outstanding helpers.

func (*WorkerPool) Submit

func (p *WorkerPool) Submit(fn func())

Submit dispatches fn as a helper goroutine, or runs it inline when the pool has no spare budget. Specifically:

  • p == nil, p.workers == 0 (single-thread mode or fully-saturated budget), or Shutdown already called: fn runs synchronously in the calling goroutine.
  • Otherwise: a fresh goroutine is spawned to run fn, returning immediately to the caller.

The caller is responsible for synchronising completion via its own WaitGroup (Submit does not track in-flight work). The cap on concurrent helpers is enforced not by Submit itself but by the fanout-site idiom of asking for at most p.Workers() helpers.

func (*WorkerPool) Workers

func (p *WorkerPool) Workers() int

Workers returns the number of worker goroutines this pool was constructed with. Useful for fanout-site sizing decisions: "split the work across (Workers + 1) chunks, with the calling goroutine taking the last chunk in-line."

Returns 0 for a nil pool, signalling "fall back to sequential".

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL