makepad/libs/ai/models/beats/src/weights.rs
Admin 6ba1b9425c libs: ai hub/models/cuda, speech, chat_ui
Squash of 54 work commits (Sep 1–12):
  6251f7c  ai-hub: body domain — live pose packets ride the realtime session
  ea50c77  chat_ui: the feed's session gets its profile brief back
  f51b5f3  ai-body: the crate for the native SAM 3D Body port, with its weights reader
  8211ae6  ai-body: the MHR rig and the pose head's parameter decoding, oracle-exact
  9e343a8  ai-body: the DINOv3 ViT-H+/16 backbone, crop and ray conditioning; Metal gains rope-half and affine layer norm
  69d842c  ai-body: the promptable pose decoder and its refinement loop, oracle-matched on Metal
  66e5e2f  ai-hub: SAM 3D Body runs natively — `sam3dbody` on the body domain, oracle-matched end to end
  a634198  ai-hub: the body-native commit carried a peer's in-flight hub hunks; put them back where they were
  9ff44e8  ai-hub: the body-native wiring, this time only the lane's hunks
  6a1c16b  ai-body: third-party notices — what the port is implemented after, and what it is not
  d78411a  ai-body: the per-step work moves to the GPU
  b22259b  ai-body: the context stays on the GPU; only the pose token leaves the loop
  346f31f  ai-body: flash attention for the head-dim-64 blocks
  45b5b98  ai-body: the crop size is a runtime knob, and the loop reports where its time goes
  4be6d19  ai-body: the test modules import the grid constants they still use
  7598346  ai-body: tensor-core GEMMs for the backbone, and the rig's correctives only where they count
  a9ce596  ai-body: the crop warp runs across cores
  8964ba6  ai-body: an FP8 backbone mode, off by default, measured against the oracle
  a2aaa8f  ai-body: the FP8 bias rides a column-broadcast add on the device
  d53c77d  metal: a device-resident ViT stack, and the body backbone rides it
  d006d0a  metal: resident f32 linears keep their weight on the device
  525ba1c  metal: a device-resident two-way decoder layer, and the body decoder rides it
  c9e6d88  ai-body: the hands pass — hand crops, the hand decoder, the hand-mode rig and the wrist fusion
  62dff26  ai-body: the mask prompt — a person's segmentation mask conditions the body pass
  a648cf8  ai-hub: body session options — hands, detect, persons=N
  8c568df  ai-hub: drop the SAM 3D Body reference worker backend
  7ff875a  ai-hub: keep a peer's in-flight beats/notes/local work out of the body commits
  31e5faa  ai-hub: local model runner, licence acknowledgements, a shared install panel; Beat This!, Basic Pitch and the Salamander drum-kit entries
  b94bc58  ai-services: the wire, the app port and the panel state — one conversation, many apps
  2acb798  ai-services: wire v2 — endpoints, receiver-side caps, result disposition
  8ae0ffb  ai-services: the engine core — registry, router and conversation, tested against a scripted model
  2308736  ai-services: the real models behind the engine feature — local through the hub, Claude, and none
  c3f631d  livepipe: one reusable pipe from a camera to a fleet node and back
  ff62db3  ai libs: the runtime env-var cleanup — precision is a per-caller policy, not an environment side channel
  04a94ef  realtime: one service-log line when a live session opens and one when it closes
  0ecb81c  ai models: the model-crates env-var cleanup — 172 research knobs gone, the unset default is the code
  4ca36c1  ai hub + services: the assistant's model comes from wherever it is resident — the fleet chat box, with tools, then the local weights
  432121e  aichat engine + wm: launch, then use — the assistant continues in the same turn once the app it started is on the bus
  7a5bf69  ai-hub registry: the Salamander drumkit samples come from the makepad.nl mirror — the GitHub repo only carries the .sfz files
  102ffc5  ai-services: messages on the bus — a manifest declares topics, the engine subscribes on a tool's behalf or by ToolResult.subscribe, a service publishes Message frames, an idle conversation wakes on a message as an event turn under rate laws; the WM bus forwards the new frames; every app that matches the wire gets its arm
  a837792  hub + flow: a whitespace-only chat completion is retried once and then fails instead of passing as an answer; a flow's model is a fleet model id unless it names a weight file on disk; chat models show under the text domain in /v1/models
  bc6c620  hub + flow: what the chat review found — the in-process route retries an empty completion too, a node says whether its prefill opened thinking so a brief-mode answer is never discarded, a preferred model falls back to normal election when no node has it, discovery keeps looking for the preferred model until patience runs out
  75c3441  hub: the PRO 6000 serves image as well as chat and text
  ad5e98b  hub registry: flux2-dev's VRAM estimate is its measured peak, 30 GB
  c7241e0  hub: a node that evicted every resident releases its cached allocator pool before refusing a load or publishing usable VRAM
  30575f0  flow: route generation by request workload
  1be1e21  ai-hub: gate downloads by disk capacity and recover fleet admission
  df6b394  filesystem_watcher, bounded_http, ai services: live and tool prerequisites
  79ebdb9  ai-hub: add a native Pixal3D image-to-3D backend
  0ba0d74  ai-hub: propagate typed refusals under reject queue policy
  cc6c872  Speed up H3 conditioning and video decoding
  e512059  Fix Qwen vision residency and generated material colors
  2864f68  ai-hub http client: bound every plain TCP connect to 3 s per address
  3d93229  ai: CUDA is a Linux/Windows-only dependency; the hub library defaults to llm + stt

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:40:31 +02:00

660 lines
22 KiB
Rust

//! Strict Beat This! Lightning-checkpoint loader.
//!
//! The upstream `.ckpt` is read directly. A complete name/shape census runs
//! before allocation; inference never accepts a partial or architecture-mixed
//! state dict. Torch linear dimensions are re-declared in ggml `[in,out]`
//! order, BatchNorm is folded into affine scale/bias, and convolution kernels
//! are reordered once for the graph's compact manual-im2col layout.
use crate::config::*;
use makepad_ai_common::quant::f32_to_f16_rn;
use makepad_ai_common::{
ggml_pad, BufferUsage, Context, DiffusionError, InitParams, Result, Tensor, TensorDesc,
TensorId, TensorLayout, TensorType, GGML_MEM_ALIGN,
};
use makepad_ai_loader::formats::torch_pth::PthStateDict;
use std::collections::{BTreeMap, BTreeSet};
use std::path::{Path, PathBuf};
pub const DEFAULT_GRAPH_EXTRA_BYTES: usize = 16 << 20;
pub fn f16_weights_enabled() -> bool {
!matches!(
std::env::var("MAKEPAD_BEATS_F16").as_deref(),
Ok("0") | Ok("false")
)
}
pub fn f16_weights_requested() -> bool {
matches!(
std::env::var("MAKEPAD_BEATS_F16").as_deref(),
Ok("1") | Ok("true")
)
}
#[derive(Clone, Debug)]
pub struct CheckpointCensus {
pub config: BeatsConfig,
pub tensors: BTreeMap<String, Vec<usize>>,
}
pub fn checkpoint_census(path: impl AsRef<Path>) -> Result<CheckpointCensus> {
let path = path.as_ref();
let state = PthStateDict::load(path).map_err(|error| {
DiffusionError::model(format!("beats checkpoint {}: {error}", path.display()))
})?;
validate_census(&state)
}
pub struct BeatsWeights {
pub ctx: Context,
pub ids: BTreeMap<String, TensorId>,
pub path: PathBuf,
pub config: BeatsConfig,
}
impl BeatsWeights {
pub fn load(path: impl AsRef<Path>) -> Result<Self> {
Self::load_with_options(path, DEFAULT_GRAPH_EXTRA_BYTES, f16_weights_enabled())
}
pub fn load_with_options(
path: impl AsRef<Path>,
extra_bytes: usize,
f16: bool,
) -> Result<Self> {
let path = path.as_ref().to_path_buf();
let mut state = PthStateDict::load(&path).map_err(|error| {
DiffusionError::model(format!("beats checkpoint {}: {error}", path.display()))
})?;
let census = validate_census(&state)?;
let plan = weight_plan(census.config);
let total = plan_total_bytes(&plan, f16, extra_bytes)?;
let mut ctx = Context::new(InitParams {
mem_size: total,
mem_buffer: None,
no_alloc: false,
});
let mut ids = BTreeMap::new();
for item in &plan {
let ty = item.dtype(f16);
let id = ctx
.new_named_tensor(
item.name.clone(),
ty,
item.extents.len(),
&item.extents,
BufferUsage::Weights,
)
.map_err(DiffusionError::model)?;
let values = item.source.gather(&mut state)?;
if values.len() != item.elements() {
return Err(DiffusionError::model(format!(
"beats weight '{}' expected {} floats, checkpoint produced {}",
item.name,
item.elements(),
values.len()
)));
}
if ty == TensorType::F16 {
let half: Vec<u16> = values.into_iter().map(f32_to_f16_rn).collect();
ctx.write_tensor_data(id, bytes_u16(&half))
.map_err(DiffusionError::model)?;
} else {
ctx.write_tensor_data(id, bytes_f32(&values))
.map_err(DiffusionError::model)?;
}
ids.insert(item.name.clone(), id);
}
Ok(Self {
ctx,
ids,
path,
config: census.config,
})
}
}
fn validate_census(state: &PthStateDict) -> Result<CheckpointCensus> {
let linear_shape = state
.shape("model.frontend.linear.weight")
.map_err(|error| DiffusionError::model(format!("beats checkpoint: {error}")))?;
let config = match linear_shape.as_slice() {
[512, FRONTEND_FEATURES] => BeatsConfig::FINAL,
[128, FRONTEND_FEATURES] => BeatsConfig::SMALL,
other => {
return Err(DiffusionError::model(format!(
"beats checkpoint has unsupported frontend.linear.weight shape {other:?}"
)))
}
};
let expected = expected_census(config);
let actual_names: BTreeSet<String> = state.names().cloned().collect();
let expected_names: BTreeSet<String> = expected.keys().cloned().collect();
let missing: Vec<_> = expected_names.difference(&actual_names).cloned().collect();
let unexpected: Vec<_> = actual_names.difference(&expected_names).cloned().collect();
if !missing.is_empty() || !unexpected.is_empty() {
return Err(DiffusionError::model(format!(
"beats checkpoint tensor census failed: missing={missing:?}, unexpected={unexpected:?}"
)));
}
for (name, wanted) in &expected {
let got = state
.shape(name)
.map_err(|error| DiffusionError::model(format!("beats checkpoint: {error}")))?;
if &got != wanted {
return Err(DiffusionError::model(format!(
"beats checkpoint tensor '{name}' has shape {got:?}, expected {wanted:?}"
)));
}
}
Ok(CheckpointCensus {
config,
tensors: expected,
})
}
fn expected_census(config: BeatsConfig) -> BTreeMap<String, Vec<usize>> {
fn add(out: &mut BTreeMap<String, Vec<usize>>, name: String, shape: &[usize]) {
out.insert(name, shape.to_vec());
}
fn batch_norm(
out: &mut BTreeMap<String, Vec<usize>>,
prefix: &str,
channels: usize,
) {
for part in ["weight", "bias", "running_mean", "running_var"] {
add(out, format!("{prefix}.{part}"), &[channels]);
}
add(out, format!("{prefix}.num_batches_tracked"), &[]);
}
let mut out = BTreeMap::new();
batch_norm(&mut out, "model.frontend.stem.bn1d", MEL_BINS);
add(
&mut out,
"model.frontend.stem.conv2d.weight".into(),
&[STEM_DIM, 1, 4, 3],
);
batch_norm(&mut out, "model.frontend.stem.bn2d", STEM_DIM);
for block in 0..STEM_BLOCKS {
let dim = STEM_CHANNELS[block];
let next = STEM_CHANNELS[block + 1];
let root = format!("model.frontend.blocks.{block}");
for (attn_tag, ff_tag) in [("attnF", "ffF"), ("attnT", "ffT")] {
let attn = format!("{root}.partial.{attn_tag}");
let heads = dim / HEAD_DIM;
add(&mut out, format!("{attn}.norm.gamma"), &[dim]);
add(&mut out, format!("{attn}.to_qkv.weight"), &[dim * 3, dim]);
add(&mut out, format!("{attn}.to_gates.weight"), &[heads, dim]);
add(&mut out, format!("{attn}.to_gates.bias"), &[heads]);
add(&mut out, format!("{attn}.to_out.0.weight"), &[dim, dim]);
add(&mut out, format!("{attn}.rotary_embed.freqs"), &[HEAD_DIM / 2]);
let ff = format!("{root}.partial.{ff_tag}.net");
add(&mut out, format!("{ff}.0.gamma"), &[dim]);
add(&mut out, format!("{ff}.1.weight"), &[dim * FF_MULT, dim]);
add(&mut out, format!("{ff}.1.bias"), &[dim * FF_MULT]);
add(&mut out, format!("{ff}.4.weight"), &[dim, dim * FF_MULT]);
add(&mut out, format!("{ff}.4.bias"), &[dim]);
}
add(&mut out, format!("{root}.conv2d.weight"), &[next, dim, 2, 3]);
batch_norm(&mut out, &format!("{root}.norm"), next);
}
add(
&mut out,
"model.frontend.linear.weight".into(),
&[config.transformer_dim, FRONTEND_FEATURES],
);
add(
&mut out,
"model.frontend.linear.bias".into(),
&[config.transformer_dim],
);
for layer in 0..MAIN_LAYERS {
let dim = config.transformer_dim;
let heads = config.heads();
let root = format!("model.transformer_blocks.layers.{layer}");
add(&mut out, format!("{root}.0.norm.gamma"), &[dim]);
add(&mut out, format!("{root}.0.to_qkv.weight"), &[dim * 3, dim]);
add(&mut out, format!("{root}.0.to_gates.weight"), &[heads, dim]);
add(&mut out, format!("{root}.0.to_gates.bias"), &[heads]);
add(&mut out, format!("{root}.0.to_out.0.weight"), &[dim, dim]);
add(&mut out, format!("{root}.0.rotary_embed.freqs"), &[HEAD_DIM / 2]);
add(&mut out, format!("{root}.1.net.0.gamma"), &[dim]);
add(&mut out, format!("{root}.1.net.1.weight"), &[dim * FF_MULT, dim]);
add(&mut out, format!("{root}.1.net.1.bias"), &[dim * FF_MULT]);
add(&mut out, format!("{root}.1.net.4.weight"), &[dim, dim * FF_MULT]);
add(&mut out, format!("{root}.1.net.4.bias"), &[dim]);
}
add(
&mut out,
"model.transformer_blocks.norm.gamma".into(),
&[config.transformer_dim],
);
add(
&mut out,
"model.task_heads.beat_downbeat_lin.weight".into(),
&[2, config.transformer_dim],
);
add(
&mut out,
"model.task_heads.beat_downbeat_lin.bias".into(),
&[2],
);
out
}
#[derive(Clone, Debug)]
enum Source {
Whole(String),
BatchNorm { prefix: String, channels: usize, bias: bool },
Conv {
name: String,
out_channels: usize,
in_channels: usize,
kernel_h: usize,
kernel_w: usize,
},
}
impl Source {
fn gather(&self, state: &mut PthStateDict) -> Result<Vec<f32>> {
match self {
Source::Whole(name) => read(state, name),
Source::BatchNorm {
prefix,
channels,
bias,
} => {
let gamma = read(state, &format!("{prefix}.weight"))?;
let beta = read(state, &format!("{prefix}.bias"))?;
let mean = read(state, &format!("{prefix}.running_mean"))?;
let variance = read(state, &format!("{prefix}.running_var"))?;
let mut out = Vec::with_capacity(*channels);
for channel in 0..*channels {
let scale = gamma[channel] / (variance[channel] + BATCH_NORM_EPS).sqrt();
out.push(if *bias {
beta[channel] - mean[channel] * scale
} else {
scale
});
}
Ok(out)
}
Source::Conv {
name,
out_channels,
in_channels,
kernel_h,
kernel_w,
} => {
let source = read(state, name)?;
let kernel = in_channels * kernel_h * kernel_w;
let mut out = Vec::with_capacity(source.len());
// Torch is [out,in,ky,kx]. The graph forms patches in
// [ky,kx,in] order (in fastest), cutting patch nodes from
// in*kh*kw to kh*kw. Reorder once at load.
for oc in 0..*out_channels {
for ky in 0..*kernel_h {
for kx in 0..*kernel_w {
for ic in 0..*in_channels {
let at = oc * kernel
+ ic * kernel_h * kernel_w
+ ky * kernel_w
+ kx;
out.push(source[at]);
}
}
}
}
Ok(out)
}
}
}
}
fn read(state: &mut PthStateDict, name: &str) -> Result<Vec<f32>> {
state.f32(name).map_err(|error| {
DiffusionError::model(format!("beats checkpoint tensor '{name}': {error}"))
})
}
#[derive(Clone, Debug)]
struct PlanItem {
name: String,
extents: Vec<i64>,
source: Source,
matmul: bool,
}
impl PlanItem {
fn elements(&self) -> usize {
self.extents.iter().product::<i64>() as usize
}
fn dtype(&self, f16: bool) -> TensorType {
if f16 && self.matmul {
TensorType::F16
} else {
TensorType::F32
}
}
}
fn item(name: impl Into<String>, extents: &[usize], source: Source) -> PlanItem {
PlanItem {
name: name.into(),
extents: extents.iter().map(|&value| value as i64).collect(),
source,
matmul: false,
}
}
fn mat(name: impl Into<String>, extents: &[usize], source: Source) -> PlanItem {
let mut item = item(name, extents, source);
item.matmul = true;
item
}
pub(crate) const INPUT_BN_SCALE: &str = "stem.input_bn.scale";
pub(crate) const INPUT_BN_BIAS: &str = "stem.input_bn.bias";
pub(crate) const STEM_CONV: &str = "stem.conv";
pub(crate) const STEM_BN_SCALE: &str = "stem.bn.scale";
pub(crate) const STEM_BN_BIAS: &str = "stem.bn.bias";
pub(crate) const FRONT_LINEAR_W: &str = "frontend.linear.weight";
pub(crate) const FRONT_LINEAR_B: &str = "frontend.linear.bias";
pub(crate) const FINAL_NORM: &str = "main.final_norm.gamma";
pub(crate) const HEAD_W: &str = "head.weight";
pub(crate) const HEAD_B: &str = "head.bias";
pub(crate) fn block_conv(block: usize) -> String {
format!("front{block}.conv")
}
pub(crate) fn block_bn(block: usize, part: &str) -> String {
format!("front{block}.bn.{part}")
}
pub(crate) fn transformer_name(prefix: &str, part: &str) -> String {
format!("{prefix}.{part}")
}
fn add_bn(
plan: &mut Vec<PlanItem>,
graph_prefix: &str,
checkpoint_prefix: &str,
channels: usize,
rank3: bool,
) {
let shape = if rank3 {
vec![channels, 1, 1]
} else {
vec![channels]
};
plan.push(item(
format!("{graph_prefix}.scale"),
&shape,
Source::BatchNorm {
prefix: checkpoint_prefix.into(),
channels,
bias: false,
},
));
plan.push(item(
format!("{graph_prefix}.bias"),
&shape,
Source::BatchNorm {
prefix: checkpoint_prefix.into(),
channels,
bias: true,
},
));
}
fn add_transformer(
plan: &mut Vec<PlanItem>,
graph_prefix: &str,
attn_prefix: &str,
ff_prefix: &str,
dim: usize,
) {
let heads = dim / HEAD_DIM;
plan.push(item(
transformer_name(graph_prefix, "attn.gamma"),
&[dim],
Source::Whole(format!("{attn_prefix}.norm.gamma")),
));
plan.push(mat(
transformer_name(graph_prefix, "attn.qkv"),
&[dim, dim * 3],
Source::Whole(format!("{attn_prefix}.to_qkv.weight")),
));
plan.push(mat(
transformer_name(graph_prefix, "attn.gates_w"),
&[dim, heads],
Source::Whole(format!("{attn_prefix}.to_gates.weight")),
));
plan.push(item(
transformer_name(graph_prefix, "attn.gates_b"),
&[heads],
Source::Whole(format!("{attn_prefix}.to_gates.bias")),
));
plan.push(mat(
transformer_name(graph_prefix, "attn.out"),
&[dim, dim],
Source::Whole(format!("{attn_prefix}.to_out.0.weight")),
));
plan.push(item(
transformer_name(graph_prefix, "ff.gamma"),
&[dim],
Source::Whole(format!("{ff_prefix}.net.0.gamma")),
));
plan.push(mat(
transformer_name(graph_prefix, "ff.w1"),
&[dim, dim * FF_MULT],
Source::Whole(format!("{ff_prefix}.net.1.weight")),
));
plan.push(item(
transformer_name(graph_prefix, "ff.b1"),
&[dim * FF_MULT],
Source::Whole(format!("{ff_prefix}.net.1.bias")),
));
plan.push(mat(
transformer_name(graph_prefix, "ff.w2"),
&[dim * FF_MULT, dim],
Source::Whole(format!("{ff_prefix}.net.4.weight")),
));
plan.push(item(
transformer_name(graph_prefix, "ff.b2"),
&[dim],
Source::Whole(format!("{ff_prefix}.net.4.bias")),
));
}
fn weight_plan(config: BeatsConfig) -> Vec<PlanItem> {
let mut plan = Vec::new();
add_bn(
&mut plan,
"stem.input_bn",
"model.frontend.stem.bn1d",
MEL_BINS,
false,
);
plan.push(mat(
STEM_CONV,
&[1 * 4 * 3, STEM_DIM],
Source::Conv {
name: "model.frontend.stem.conv2d.weight".into(),
out_channels: STEM_DIM,
in_channels: 1,
kernel_h: 4,
kernel_w: 3,
},
));
add_bn(
&mut plan,
"stem.bn",
"model.frontend.stem.bn2d",
STEM_DIM,
true,
);
for block in 0..STEM_BLOCKS {
let dim = STEM_CHANNELS[block];
let next = STEM_CHANNELS[block + 1];
let checkpoint = format!("model.frontend.blocks.{block}");
add_transformer(
&mut plan,
&format!("front{block}.freq"),
&format!("{checkpoint}.partial.attnF"),
&format!("{checkpoint}.partial.ffF"),
dim,
);
add_transformer(
&mut plan,
&format!("front{block}.time"),
&format!("{checkpoint}.partial.attnT"),
&format!("{checkpoint}.partial.ffT"),
dim,
);
plan.push(mat(
block_conv(block),
&[dim * 2 * 3, next],
Source::Conv {
name: format!("{checkpoint}.conv2d.weight"),
out_channels: next,
in_channels: dim,
kernel_h: 2,
kernel_w: 3,
},
));
add_bn(
&mut plan,
&format!("front{block}.bn"),
&format!("{checkpoint}.norm"),
next,
true,
);
}
plan.push(mat(
FRONT_LINEAR_W,
&[FRONTEND_FEATURES, config.transformer_dim],
Source::Whole("model.frontend.linear.weight".into()),
));
plan.push(item(
FRONT_LINEAR_B,
&[config.transformer_dim],
Source::Whole("model.frontend.linear.bias".into()),
));
for layer in 0..MAIN_LAYERS {
let checkpoint = format!("model.transformer_blocks.layers.{layer}");
add_transformer(
&mut plan,
&format!("main{layer}"),
&format!("{checkpoint}.0"),
&format!("{checkpoint}.1"),
config.transformer_dim,
);
}
plan.push(item(
FINAL_NORM,
&[config.transformer_dim],
Source::Whole("model.transformer_blocks.norm.gamma".into()),
));
plan.push(mat(
HEAD_W,
&[config.transformer_dim, 2],
Source::Whole("model.task_heads.beat_downbeat_lin.weight".into()),
));
plan.push(item(
HEAD_B,
&[2],
Source::Whole("model.task_heads.beat_downbeat_lin.bias".into()),
));
plan
}
fn plan_total_bytes(plan: &[PlanItem], f16: bool, extra: usize) -> Result<usize> {
let mut total = 0usize;
for item in plan {
let ty = item.dtype(f16);
let layout = TensorLayout::for_ggml(ty, &item.extents).map_err(DiffusionError::model)?;
let bytes = Tensor::from_desc(0, TensorDesc::new(ty, layout, BufferUsage::Weights)).nbytes();
total = ggml_pad(total, GGML_MEM_ALIGN)
.checked_add(bytes)
.ok_or_else(|| DiffusionError::model("beats weight arena overflow"))?;
}
ggml_pad(total, GGML_MEM_ALIGN)
.checked_add(extra)
.ok_or_else(|| DiffusionError::model("beats context arena overflow"))
}
fn bytes_f32(values: &[f32]) -> &[u8] {
unsafe { std::slice::from_raw_parts(values.as_ptr().cast(), values.len() * 4) }
}
fn bytes_u16(values: &[u16]) -> &[u8] {
unsafe { std::slice::from_raw_parts(values.as_ptr().cast(), values.len() * 2) }
}
#[cfg(test)]
mod tests {
use super::*;
const WEIGHTS: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../../../local/models/weights/beat_this"
);
fn census_if_present(name: &str, want: BeatsConfig) {
let path = Path::new(WEIGHTS).join(name);
if !path.is_file() {
eprintln!("beats census: SKIP, {} is not seeded", path.display());
return;
}
let census = checkpoint_census(&path).unwrap();
assert_eq!(census.config, want);
assert_eq!(census.tensors.len(), 166);
assert_eq!(
census.tensors["model.frontend.stem.conv2d.weight"],
vec![32, 1, 4, 3]
);
assert_eq!(
census.tensors["model.frontend.blocks.2.conv2d.weight"],
vec![256, 128, 2, 3]
);
assert_eq!(
census.tensors["model.frontend.linear.weight"],
vec![want.transformer_dim, 1024]
);
assert_eq!(
census.tensors["model.transformer_blocks.layers.5.0.to_qkv.weight"],
vec![want.transformer_dim * 3, want.transformer_dim]
);
assert_eq!(
census.tensors["model.task_heads.beat_downbeat_lin.weight"],
vec![2, want.transformer_dim]
);
}
#[test]
fn final0_tensor_census_is_exact() {
census_if_present("final0.ckpt", BeatsConfig::FINAL);
}
#[test]
fn small0_tensor_census_is_exact() {
census_if_present("small0.ckpt", BeatsConfig::SMALL);
}
#[test]
fn plans_cover_both_model_widths() {
for config in [BeatsConfig::FINAL, BeatsConfig::SMALL] {
let plan = weight_plan(config);
let names: BTreeSet<_> = plan.iter().map(|item| &item.name).collect();
assert_eq!(names.len(), plan.len());
let head = plan.iter().find(|item| item.name == HEAD_W).unwrap();
assert_eq!(head.extents, vec![config.transformer_dim as i64, 2]);
}
}
}