use model_io::ResidentIndex;
use crate::real_forward_layout::DTYPE_RAW_FP16;
use crate::real_forward_types::RealForwardError;
use crate::vision::shape::VisionShape;
pub(crate) const BLOCK_ROLES: [&str; 12] = [
"ln1_w", "ln1_b", "qkv_w", "qkv_b", "proj_w", "proj_b", "ln2_w", "ln2_b", "fc1_w", "fc1_b",
"fc2_w", "fc2_b",
];
#[derive(Debug, Clone, Copy)]
pub(crate) enum Role {
Ln1W = 0,
Ln1B = 1,
QkvW = 2,
QkvB = 3,
ProjW = 4,
ProjB = 5,
Ln2W = 6,
Ln2B = 7,
Fc1W = 8,
Fc1B = 9,
Fc2W = 10,
Fc2B = 11,
}
#[derive(Debug, Clone)]
pub(crate) struct BlockRoles {
pub(crate) offsets: [u64; 12],
}
impl BlockRoles {
pub(crate) fn at(&self, role: Role) -> u64 {
self.offsets[role as usize]
}
}
#[derive(Debug, Clone)]
pub(crate) struct VisionResident {
pub(crate) patch_w: u64,
pub(crate) patch_b: u64,
pub(crate) merger_norm_w: u64,
pub(crate) merger_norm_b: u64,
pub(crate) merger_fc1_w: u64,
pub(crate) merger_fc1_b: u64,
pub(crate) merger_fc2_w: u64,
pub(crate) merger_fc2_b: u64,
pub(crate) pos_embed_host: usize,
pub(crate) deepstack_mergers: Vec<DeepstackMergerWeights>,
}
#[derive(Debug, Clone)]
pub(crate) struct DeepstackMergerWeights {
pub(crate) norm_w: u64,
pub(crate) norm_b: u64,
pub(crate) fc1_w: u64,
pub(crate) fc1_b: u64,
pub(crate) fc2_w: u64,
pub(crate) fc2_b: u64,
}
fn fp16_view(
index: &ResidentIndex,
name: &str,
expect_elems: usize,
) -> Result<u64, RealForwardError> {
let e = index
.entries
.get(name)
.ok_or_else(|| RealForwardError::MissingTensor(name.to_string()))?;
if e.dtype != DTYPE_RAW_FP16 {
return Err(RealForwardError::Unsupported(format!(
"vision tensor {name} carries dtype {}, but the tower's kernels bind FP16 (tag {}); \
a same-width BF16 tensor would be read as a different number rather than refused",
e.dtype, DTYPE_RAW_FP16
)));
}
if e.size_bytes as usize != expect_elems * 2 {
return Err(RealForwardError::Unsupported(format!(
"vision tensor {name}: {} bytes does not match expected FP16 [{expect_elems}]",
e.size_bytes
)));
}
Ok(e.file_offset - index.header.index_size)
}
pub(crate) use crate::real_forward_layout::VISION_PREFIX;
pub(crate) const DEEPSTACK_MERGER_PREFIX: &str = "deepstack_merger_list.";
impl VisionResident {
pub(crate) fn resolve(
index: &ResidentIndex,
shape: &VisionShape,
) -> Result<Self, RealForwardError> {
let h = shape.hidden;
let m = shape.merger_input();
let name = |tail: &str| format!("{VISION_PREFIX}{tail}");
let patch_w = fp16_view(index, &name("patch_embed.proj.weight"), h * shape.patch_dim)?;
let patch_b = fp16_view(index, &name("patch_embed.proj.bias"), h)?;
let pos_entry = index
.entries
.get(&name("pos_embed.weight"))
.ok_or_else(|| RealForwardError::MissingTensor(name("pos_embed.weight")))?;
let _ = fp16_view(index, &name("pos_embed.weight"), shape.pos_rows * h)?;
let pos_embed_host = (pos_entry.file_offset - index.header.index_size) as usize;
Ok(Self {
patch_w,
patch_b,
merger_norm_w: fp16_view(index, &name("merger.norm.weight"), h)?,
merger_norm_b: fp16_view(index, &name("merger.norm.bias"), h)?,
merger_fc1_w: fp16_view(index, &name("merger.linear_fc1.weight"), m * m)?,
merger_fc1_b: fp16_view(index, &name("merger.linear_fc1.bias"), m)?,
merger_fc2_w: fp16_view(
index,
&name("merger.linear_fc2.weight"),
shape.out_hidden * m,
)?,
merger_fc2_b: fp16_view(index, &name("merger.linear_fc2.bias"), shape.out_hidden)?,
pos_embed_host,
deepstack_mergers: Self::resolve_deepstack(index, shape, m)?,
})
}
fn resolve_deepstack(
index: &ResidentIndex,
shape: &VisionShape,
m: usize,
) -> Result<Vec<DeepstackMergerWeights>, RealForwardError> {
let name =
|k: usize, tail: &str| format!("{VISION_PREFIX}{DEEPSTACK_MERGER_PREFIX}{k}.{tail}");
let mut mergers = Vec::with_capacity(shape.deepstack.len());
for k in 0..shape.deepstack.len() {
mergers.push(DeepstackMergerWeights {
norm_w: fp16_view(index, &name(k, "norm.weight"), m)?,
norm_b: fp16_view(index, &name(k, "norm.bias"), m)?,
fc1_w: fp16_view(index, &name(k, "linear_fc1.weight"), m * m)?,
fc1_b: fp16_view(index, &name(k, "linear_fc1.bias"), m)?,
fc2_w: fp16_view(index, &name(k, "linear_fc2.weight"), shape.out_hidden * m)?,
fc2_b: fp16_view(index, &name(k, "linear_fc2.bias"), shape.out_hidden)?,
});
}
Ok(mergers)
}
}
pub(crate) fn role_size(role: &str, shape: &VisionShape) -> Option<u64> {
let h = shape.hidden as u64;
let inter = shape.intermediate as u64;
let elems = match role {
"ln1_w" | "ln1_b" | "ln2_w" | "ln2_b" | "proj_b" | "fc2_b" => h,
"qkv_w" => 3 * h * h,
"qkv_b" => 3 * h,
"proj_w" => h * h,
"fc1_w" => inter * h,
"fc1_b" => inter,
"fc2_w" => h * inter,
_ => return None,
};
Some(elems * 2)
}
pub(crate) fn resolve_block_roles(
entry: &model_io::ExpertEntry,
block: usize,
stride: u64,
shape: &VisionShape,
) -> Result<BlockRoles, RealForwardError> {
let mut offsets = [0u64; 12];
for (i, role) in BLOCK_ROLES.iter().enumerate() {
let sub = entry.sub_tensors.get(*role).ok_or_else(|| {
RealForwardError::MissingTensor(format!(
"vision block {block} is missing the sub-tensor {role}"
))
})?;
if sub.dtype != "fp16" {
return Err(RealForwardError::Unsupported(format!(
"vision block {block} role {role} carries dtype {:?}, but the tower's kernels \
bind FP16; a same-width type would be read as a different number",
sub.dtype
)));
}
if let Some(expected) = role_size(role, shape) {
if sub.size != expected {
return Err(RealForwardError::Unsupported(format!(
"vision block {block} role {role} size {} does not match expected size {expected}",
sub.size
)));
}
}
if sub.offset % 4 != 0 {
return Err(RealForwardError::Unsupported(format!(
"vision block {block} role {role} sits at blob offset {}, which is not 4-byte \
aligned; Metal cannot bind a buffer there",
sub.offset
)));
}
if sub.offset + sub.size > stride {
return Err(RealForwardError::Unsupported(format!(
"vision block {block} role {role} spans {}..{} of a {stride}-byte blob",
sub.offset,
sub.offset + sub.size
)));
}
offsets[i] = sub.offset;
}
Ok(BlockRoles { offsets })
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeMap;
fn test_shape() -> VisionShape {
VisionShape {
depth: 1,
hidden: 16,
intermediate: 32,
heads: 2,
head_dim: 8,
merge: 2,
out_hidden: 16,
patch_dim: 16,
pos_rows: 16,
pos_side: 4,
patch_size: 16,
deepstack: Vec::new(),
}
}
fn make_entry_with_sub(role: &str, size: u64) -> model_io::ExpertEntry {
let shape = test_shape();
let mut sub_tensors = BTreeMap::new();
let mut offset = 0u64;
for &r in &BLOCK_ROLES {
let r_size = if r == role {
size
} else {
role_size(r, &shape).unwrap()
};
sub_tensors.insert(
r.to_string(),
model_io::SubTensorEntry {
offset,
size: r_size,
dtype: "fp16".to_string(),
},
);
offset += r_size;
}
model_io::ExpertEntry {
expert: 0,
offset: 0,
size: offset,
sub_tensors,
}
}
#[test]
fn block_roles_validates_exact_sizes() {
let shape = test_shape();
let entry = make_entry_with_sub("ln1_w", role_size("ln1_w", &shape).unwrap());
assert!(resolve_block_roles(&entry, 0, 100_000, &shape).is_ok());
}
#[test]
fn block_role_wrong_size_is_refused() {
let shape = test_shape();
let wrong_size = role_size("ln1_w", &shape).unwrap() + 2;
let entry = make_entry_with_sub("ln1_w", wrong_size);
let err = resolve_block_roles(&entry, 0, 100_000, &shape).expect_err("wrong size");
match err {
RealForwardError::Unsupported(msg) => {
assert!(
msg.contains("role ln1_w size 34 does not match expected size 32"),
"msg: {msg}"
);
}
other => panic!("expected Unsupported error, got {other:?}"),
}
}
}