YOLO raw and combined heads
YOLO26 and RawLTRB
- YOLO26 with explicit RawLTRB regression in grid-cell units; detection by default.
- One to three explicitly mapped box/score head pairs; every input has one role.
- INT8 or BF16; each pair has matching precision and spatial geometry.
- Logical trailing HWC axes, rank 3–6. Extra leading dimensions must be one. This is batch one, not arbitrary batched/time-axis decoding.
- Four logical coordinate channels; 1–256 logical score channels/classes.
- Positive spatial extents up to 32,767, at most 1,048,576 cells per head.
- Model/original image extents 1–1,048,576; output capacity 1–65,536.
- Explicit Identity or Sigmoid score activation. Detection threshold
[0,1); NMS threshold[0,1]. Zero score threshold is an inclusive numerical cutoff, not a default sentinel. YOLO26 skips NMS at zero and applies it at positive thresholds; ordinary YOLO NMS remains active at zero. Unsupported profiles fail at preparation. - No FP16/FP32 input. Pose and segmentation are explicit tasks.
Dense single-class BF16 scores
A physical dense or padded BF16 score tensor with one logical class and one anchor uses the single-class scanner. It reads only that class, skips the unnecessary class reduction, and advances by the validated physical pixel stride. It does not read padding or cache input values between executions.
The prepared sortable-key cutoff is evaluated as an exact raw-word interval;
signed zeros, subnormals, infinities and NaN encodings retain their existing
admission behavior. Identity or Sigmoid is selected once per head, with the
same float expression and final finite/threshold checks. Logical cell order,
class index zero, selection and output clearing are unchanged. Objectness,
combined heads and family-specific scanners keep their existing routes. See
scanning.h (A65/boxdecode/detail/scanning.h),
bf16_cutoff.h (A65/boxdecode/detail/bf16_cutoff.h), and
exhaustive and guarded tests (A65/boxdecode/tests/dense_single_test.inc).
Packed single-class BF16 scores
For one logical BF16 class and one anchor without objectness, the packed scanner reads the low and high bytes of channel zero directly. Every admitted C tile has one real channel in this case, including odd C tiles and tiles larger than the logical channel count. Row runs preserve logical cell order across partial spatial tiles; padding never contributes a score.
This route needs no per-cell class reduction, key/class scratch, or second
emission scan. It retains the packed scanner's explicit mapping of both signed
zeros to positive zero, the exact prepared cutoff, configured activation and
final score checks. Geometry, selection, ties and output clearing are unchanged.
See scanning.h (A65/boxdecode/detail/scanning.h) and
exhaustive/guarded single-class tests (A65/boxdecode/tests/dense_single_test.inc).
Packed BF16 class-stripe rejection
The single-anchor packed scanner can reject a BF16 class stripe before
reconstructing its words when every logical high byte is provably below the
prepared score cutoff. For cutoff_high = cutoff >> 8, the negative-byte bound
is max(0x81u, 0x100u - cutoff_high): a raw high byte at or above this bound has
a complemented sortable high byte strictly below cutoff_high, regardless of
its low byte. The 0x80 bucket, which includes negative zero and small negative
subnormals, is never rejected by this shortcut.
Inactive tail lanes are masked out of the test. Any stripe not rejected by the
bound retains the ordinary key reduction, full-word reconstruction and score
checks. The cutoff comes from the configured activation's actual float results;
this test neither approximates sigmoid nor changes the exact threshold or
first-class tie rule. See
scanning.h (A65/boxdecode/detail/scanning.h) and
boundary tests (A65/boxdecode/tests/blocked_scan_test.inc).
For INT8 tensors containing only full C16 stripes, the signed maximum is
compared directly with the prepared raw cutoff. The +128 sortable key is
formed only for admitted stripes: adding
128 to both operands preserves the comparison, including admit-all -128
and reject-all 128 cutoffs. Surviving stripes keep the same key update,
first-class tie behavior. Tensors with partial stripes retain their existing
key comparison and padding masks. See
cutoff and guarded-route tests (A65/boxdecode/tests/int8_cutoff_test.inc).
The packed scanner clears its per-cell best keys on every call. For a positive
cutoff, every class index that can be emitted is written when that cell first
replaces its zero key, so unused class-index scratch need not be cleared. A zero
cutoff still clears default class indices because an untouched zero key can
be admitted. This affects scratch initialization only: unused output rows and
mask pixels retain the full zeroing contract on every call. See
context-reuse/minimum-key tests (A65/boxdecode/tests/blocked_scan_test.inc).
For full-stripe INT8/BF16 tensors (both logical channels and channel-tile size
are multiples of 16), the streaming scanner binds the class-scratch data
pointer once per head. Context creation sizes this storage; scanning and
candidate emission never resize it. Partial-stripe tensors retain their
existing vector access. Both paths keep the same conditional clearing, strict
best-key updates and first-class ties. See
scanning.h (A65/boxdecode/detail/scanning.h).
Partial INT8 heads whose physical channel tiles contain a single active lane
in their final C16 stripe select a singleton-capable scanner once per head.
For that stripe, the signed byte supplies the key directly and the class is
the stripe's first channel; no class reduction or first-index search is needed.
The cutoff and strict best-key update are unchanged, including key zero and
earlier-class ties. Heads without such a stripe use the direct partial scanner;
BF16 and full-stripe policies are unchanged. Full channel tiles and the final
partial channel tile are both considered, including when the logical channel
count is smaller than the channel tile. See the
guarded policy tests (A65/boxdecode/tests/int8_cutoff_test.inc).
Standard YOLOv5
BoxDecodeYoloV5V1, recipe-derived raw encoding and sigmoid activation; fixed anchors. Segmentation adds explicit coefficients and a basis tensor; arbitrary anchors are not supported.- Exactly three combined inputs, with
Head::combined(port)in P3/P4/P5 order. Ports may be permuted, but each is mapped exactly once. Head order selects the anchor/stride level, not the input port number. - Trailing HWC, rank 3–6 with singleton outer axes; logical C is
3 * (num_classes + 5). Each anchor contains raw x/y/w/h logits, objectness, then class logits. Input is not decoded boxes or post-sigmoid probabilities. - Model width/height must be multiples of 32; head dimensions are exactly model dimensions divided by 8, 16 and 32. Common spatial/image/capacity bounds above also apply. Preparation validates this three-level profile explicitly.
- INT8/BF16 only. At most 256 classes if any head is INT8; otherwise at most 336. Integer quantization is explicit per input. FP16/FP32 inputs are rejected.
- Dense physical channels must be padded to a multiple of 16, at most 1,024.
Compact
Contiguousworks only when logical C already satisfies that alignment.MlaCBlockedsupports combined heads; its C tile must be a multiple of 16, at most 1,024, for both precisions. Partial tiles are accounted for in storage. - Fixed standard anchor pairs: P3
(10,13), (16,30), (33,23); P4(30,61), (62,45), (59,119); P5(116,90), (156,198), (373,326). - Decode uses
(2*sigmoid(txy)-0.5+cell)*stridefor centers and(2*sigmoid(twh))²*anchorfor sizes. Confidence issigmoid(objectness)*sigmoid(best_class_logit).
YOLOv5 preparation fragment
This constructs the same plan type for a 640×640, 80-class BF16 model. Logical C is 255; each pixel reserves 256 physical channels. All six shape axes are explicit. The returned plan reports required buffer sizes; allocation, binding and execution follow the BoxDecode call, with three inputs.
#include <simaai/kernels/ops/boxdecode.h>
#include <array>
simaai::kernels::Result<simaai::kernels::ops::boxdecode::Plan>
prepare_yolov5() {
namespace k = simaai::kernels;
namespace b = k::ops::boxdecode;
constexpr int K = 16;
auto head = [](int hw) {
const std::int64_t pixel = 256 * 2;
const std::int64_t row = hw * pixel, frame = hw * row;
return k::TensorSpec{{1,1,1,hw,hw,255}, k::DType::BFloat16,
k::Strided{{frame,frame,frame,row,pixel,2}}};
};
std::array inputs{head(80), head(40), head(20)};
std::array outputs{
k::TensorSpec{{K,4}, k::DType::Int32},
k::TensorSpec{{K}, k::DType::Float32},
k::TensorSpec{{K}, k::DType::Int32},
k::TensorSpec{{1}, k::DType::Int32}};
b::Params params;
params.heads = {b::Head::combined(0), b::Head::combined(1),
b::Head::combined(2)};
params.model_input_size = {.width = 640, .height = 640};
params.original_image_size = {.width = 640, .height = 640};
params.num_classes = 80;
params.max_detections = K;
params.detection_threshold = 0.5f;
params.nms_iou_threshold = 0.5f;
// Sigmoid is derived from the YOLOv5 raw recipe.
params.profile = b::Profile::YoloV5V1;
return b::check_inference({inputs, outputs, params});
}
See the common BoxDecode contract for errors, memory, outputs and qualification.
Background objectness rejection
The combined YOLO5/YOLO7 scanner reads the three anchors' objectness values for a cell before reading class values. If their exact raw-domain maximum is below the prepared objectness cutoff, the whole cell is rejected. Otherwise the counted anchor loop retains its per-anchor threshold, activation, finite check, class argmax and final score product. This is not a product-threshold approximation, and it does not change tied candidate order.
For packed inputs, objectness addresses advance through bounded physical row
runs. Channel metadata is reused at each run boundary, including partial spatial
tiles, instead of reconstructing the same metadata for every anchor and cell.
Logical row/cell/anchor encounter order remains unchanged. Dense input keeps its
ordinary element stride. See
scanner implementation (A65/boxdecode/detail/scanning.h) and
independent boundary tests (A65/boxdecode/tests/background_gate_test.inc).
Separate YOLOX objectness
YOLOX prepares an address reader for its extra_input objectness tensor,
independently of the class-score reader. Execution uses that tensor's dtype,
quantization and tile geometry. The existing within-head dtype agreement still
applies; objectness layout and INT8 quantization parameters may differ from
those of the class scores.
Prepared pixel/channel metadata replaces repeated packed-coordinate divisions.
No objectness values are cached: each call reads the current binding.
Early rejection keeps the existing activation and score-product rules. With
identity activation, positive objectness below detection_threshold can still
produce an accepted product when the class score exceeds one. It must not be
rejected using the sigmoid-only bound. See the
objectness tests (A65/boxdecode/tests/yolox_objectness_test.inc).
Blocked INT8 score reductions
The eligible packed full-C16 blocked scanner retains its local best score as
a signed raw INT8 value. The initial value -128 corresponds exactly to the
previous sortable key zero. Admission compares against the prepared raw cutoff;
a strict improvement updates the class, preserving the first equal-score class.
When every raw value is -128, class zero remains the default, including the
minimum-cutoff case. Activation and final threshold checks are unchanged.
This policy does not alter the partial-C16 scanner.
See packed_scan.h (A65/boxdecode/detail/packed_scan.h) and the
blocked scanner tests (A65/boxdecode/tests/blocked_scan_test.inc).