metrale_model_layers/layers/ngram_embed/
table.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-25: One n-gram lookup table on device: BF16 as shipped,
4//! FP8-quantized at load, or NVMe-backed by a bounded row cache.
5//!
6//! Owner: model-layers (n-gram embedding).
7//! Invariants: none beyond the types.
8
9use anyhow::Result;
10use metrale_gpu_runtime::gpu::GpuBackend;
11
12use crate::weight_map::{DenseWeight, Fp8DenseWeight};
13
14/// 2026-09-25: One n-gram lookup table. `Fp8` holds E4M3 rows with a
15/// per-row f32 scale, which the gather (`batched_embed_fp8`) applies.
16pub enum NgramTable {
17    Bf16(DenseWeight),
18    Fp8(Fp8DenseWeight),
19    /// 2026-09-25: NVMe-backed: a bounded set of rows is resident in a
20    /// GPU-addressable arena. The host maps row ids to arena slots
21    /// (`NgramRowCache::resolve`) and the same gather kernels read the arena
22    /// by slot.
23    #[cfg(feature = "cuda")]
24    Cached(Box<metrale_storage::NgramRowCache>),
25}
26
27impl NgramTable {
28    /// 2026-09-25: Quantize a BF16 table to FP8 on the GPU with
29    /// `quantize_bf16_to_fp8`. `w` is not freed.
30    pub fn quantize_bf16(
31        w: &DenseWeight,
32        rows: usize,
33        dim: usize,
34        gpu: &dyn GpuBackend,
35        stream: u64,
36    ) -> Result<Self> {
37        let k = gpu.kernel("gemv_fp8w", "quantize_bf16_to_fp8")?;
38        Ok(Self::Fp8(crate::weight_map::quantize_to_fp8(
39            w, rows, dim, gpu, k, stream,
40        )?))
41    }
42}