pub struct PerBlockAffine { /* private fields */ }Expand description
Quantization parameters for per-block affine quantization.
The tensor is divided into fixed-size contiguous blocks along axis. Each
block carries its own scale (and optionally zero_point). Partial
trailing blocks are permitted; see the spec for padding rules.
The dequantization formula for element q with block index b is:
s = scale[b] (widened to float32 if float16/bfloat16)
z = zero_point[b] (0 if symmetric)
x_real = s * (q - z)§Wire format
Total descriptor length: 24 bytes (including the 4-byte header).
| Offset | Field | Type |
|---|---|---|
| 4 | axis | uint32 LE |
| 8 | block_size | uint32 LE |
| 12 | scale_buffer_index | uint32 LE |
| 16 | zero_point_buffer_index | uint32 LE (0xFFFFFFFF if symmetric) |
| 20 | scale_type_tag | uint8 (0x01, 0x02, or 0x03) |
| 21 | _reserved | uint8[3] (must be 0x00) |
§Design notes
PartialEq, Eq, and Hash are all derived because this struct contains
no floating-point fields.
Copy because the struct is ≤ 24 bytes with no Drop glue.
§Examples
use hurray_core::{ElementType, PerBlockAffine};
let q = PerBlockAffine::new_symmetric(0, 32, 1, ElementType::Float32).unwrap();
assert!(q.is_symmetric());
assert_eq!(q.block_size(), 32);
assert_eq!(q.scale_type(), ElementType::Float32);Implementations§
Source§impl PerBlockAffine
impl PerBlockAffine
Sourcepub fn new_asymmetric(
axis: u32,
block_size: u32,
scale_buffer_index: u32,
zero_point_buffer_index: u32,
scale_type: ElementType,
) -> Result<Self>
pub fn new_asymmetric( axis: u32, block_size: u32, scale_buffer_index: u32, zero_point_buffer_index: u32, scale_type: ElementType, ) -> Result<Self>
Creates an asymmetric PerBlockAffine descriptor.
§Errors
Error::InvalidBlockSize—block_sizeis not a power of two or is less than2.Error::InvalidQuantization—scale_typeis not one ofFloat16,BFloat16, orFloat32.
§Examples
use hurray_core::{ElementType, PerBlockAffine};
let q = PerBlockAffine::new_asymmetric(0, 64, 1, 2, ElementType::Float16).unwrap();
assert!(!q.is_symmetric());
assert_eq!(q.zero_point_buffer_index(), Some(2));Sourcepub fn new_symmetric(
axis: u32,
block_size: u32,
scale_buffer_index: u32,
scale_type: ElementType,
) -> Result<Self>
pub fn new_symmetric( axis: u32, block_size: u32, scale_buffer_index: u32, scale_type: ElementType, ) -> Result<Self>
Creates a symmetric PerBlockAffine descriptor.
In symmetric mode the zero-point array is implicit (all zeros); no zero-point buffer entry is required.
§Errors
Error::InvalidBlockSize—block_sizeis not a power of two or is less than2.Error::InvalidQuantization—scale_typeis not one ofFloat16,BFloat16, orFloat32.
§Examples
use hurray_core::{ElementType, PerBlockAffine};
let q = PerBlockAffine::new_symmetric(0, 128, 1, ElementType::BFloat16).unwrap();
assert!(q.is_symmetric());
assert_eq!(q.zero_point_buffer_index(), None);Sourcepub fn is_symmetric(&self) -> bool
pub fn is_symmetric(&self) -> bool
Returns true if this descriptor uses symmetric quantization (no zero point).
§Examples
use hurray_core::{ElementType, PerBlockAffine};
assert!(PerBlockAffine::new_symmetric(0, 32, 1, ElementType::Float32)
.unwrap()
.is_symmetric());Sourcepub fn axis(&self) -> u32
pub fn axis(&self) -> u32
Returns the quantization axis index.
§Examples
use hurray_core::{ElementType, PerBlockAffine};
let q = PerBlockAffine::new_symmetric(2, 32, 1, ElementType::Float32).unwrap();
assert_eq!(q.axis(), 2);Sourcepub fn block_size(&self) -> u32
pub fn block_size(&self) -> u32
Returns the number of logical elements per block along axis.
§Examples
use hurray_core::{ElementType, PerBlockAffine};
let q = PerBlockAffine::new_symmetric(0, 64, 1, ElementType::Float32).unwrap();
assert_eq!(q.block_size(), 64);Sourcepub fn scale_buffer_index(&self) -> u32
pub fn scale_buffer_index(&self) -> u32
Returns the buffer table index of the per-block scale array.
§Examples
use hurray_core::{ElementType, PerBlockAffine};
let q = PerBlockAffine::new_symmetric(0, 32, 3, ElementType::Float32).unwrap();
assert_eq!(q.scale_buffer_index(), 3);Sourcepub fn zero_point_buffer_index(&self) -> Option<u32>
pub fn zero_point_buffer_index(&self) -> Option<u32>
Returns the buffer table index of the per-block zero-point array, or
None if this descriptor is symmetric.
None maps to the wire sentinel 0xFFFFFFFF.
§Examples
use hurray_core::{ElementType, PerBlockAffine};
let asym = PerBlockAffine::new_asymmetric(0, 32, 1, 2, ElementType::Float32).unwrap();
assert_eq!(asym.zero_point_buffer_index(), Some(2));
let sym = PerBlockAffine::new_symmetric(0, 32, 1, ElementType::Float32).unwrap();
assert_eq!(sym.zero_point_buffer_index(), None);Sourcepub fn scale_type(&self) -> ElementType
pub fn scale_type(&self) -> ElementType
Returns the element type used for scale values.
§Examples
use hurray_core::{ElementType, PerBlockAffine};
let q = PerBlockAffine::new_symmetric(0, 32, 1, ElementType::Float16).unwrap();
assert_eq!(q.scale_type(), ElementType::Float16);Sourcepub fn num_blocks_per_axis(&self, shape_axis: u64) -> u64
pub fn num_blocks_per_axis(&self, shape_axis: u64) -> u64
Computes the number of blocks along axis for a given shape_axis size.
Uses ceil(shape_axis / block_size).
Returns 0 when shape_axis == 0 per the ADR-007 empty-axis carve-out:
an empty quantization axis produces zero blocks and zero-byte parameter buffers.
§Examples
use hurray_core::{ElementType, PerBlockAffine};
let q = PerBlockAffine::new_symmetric(0, 32, 1, ElementType::Float32).unwrap();
assert_eq!(q.num_blocks_per_axis(64), 2);
assert_eq!(q.num_blocks_per_axis(65), 3); // partial trailing block
assert_eq!(q.num_blocks_per_axis(0), 0); // ADR-007 empty-axis carve-outSourcepub fn validate_against_shape_axis(&self, shape_axis: u64) -> Result<()>
pub fn validate_against_shape_axis(&self, shape_axis: u64) -> Result<()>
Validates this descriptor against the resolved shape_axis size.
Rejects if shape_axis is the DYNAMIC sentinel (u64::MAX), or if
shape_axis > 0 and block_size > shape_axis.
Does not check shape_axis == 0 (ADR-007 carve-out: the upper-bound
check is waived for empty axes).
§Errors
Error::QuantizationShapeMismatch—shape_axisis the DYNAMIC sentinel, orshape_axis > 0andblock_size > shape_axis.
§Examples
use hurray_core::{ElementType, PerBlockAffine, DYNAMIC};
let q = PerBlockAffine::new_symmetric(0, 32, 1, ElementType::Float32).unwrap();
assert!(q.validate_against_shape_axis(64).is_ok());
assert!(q.validate_against_shape_axis(32).is_ok());
assert!(q.validate_against_shape_axis(0).is_ok()); // ADR-007: waived
assert!(q.validate_against_shape_axis(16).is_err()); // block_size > shape_axis
assert!(q.validate_against_shape_axis(DYNAMIC).is_err()); // dynamic dimensionSourcepub fn valid_storage_types() -> &'static [ElementType]
pub fn valid_storage_types() -> &'static [ElementType]
Returns the set of storage ElementTypes that are valid for this scheme.
Per docs/spec/quantization/per-block-affine.md § Valid Storage Types.
WHY &'static [ElementType]: no allocation per call (design decision #5).
§Examples
use hurray_core::{ElementType, PerBlockAffine};
assert!(PerBlockAffine::valid_storage_types().contains(&ElementType::Int8));
assert!(PerBlockAffine::valid_storage_types().contains(&ElementType::Int4));
assert!(!PerBlockAffine::valid_storage_types().contains(&ElementType::Int16));Trait Implementations§
Source§impl Clone for PerBlockAffine
impl Clone for PerBlockAffine
Source§fn clone(&self) -> PerBlockAffine
fn clone(&self) -> PerBlockAffine
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for PerBlockAffine
Source§impl Debug for PerBlockAffine
impl Debug for PerBlockAffine
impl Eq for PerBlockAffine
Source§impl Hash for PerBlockAffine
impl Hash for PerBlockAffine
Source§impl PartialEq for PerBlockAffine
impl PartialEq for PerBlockAffine
Source§fn eq(&self, other: &PerBlockAffine) -> bool
fn eq(&self, other: &PerBlockAffine) -> bool
self and other values to be equal, and is used by ==.