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 more