use fuel_ir::Shape;
use fuel_ir::error::Result;
use fuel_tensor::{lazy::Tensor, lazy::WeightStorage};
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq)]
pub struct MimiTransformerConfig {
pub d_model: usize,
pub num_heads: usize,
pub num_layers: usize,
pub dim_feedforward: usize,
pub max_period: f32,
pub conv_layout: bool,
pub layer_norm_eps: f64,
}
impl MimiTransformerConfig {
pub fn mimi_v0_1() -> Self {
Self {
d_model: 512,
num_heads: 8,
num_layers: 8,
dim_feedforward: 2048,
max_period: 10_000.0,
conv_layout: true,
layer_norm_eps: 1e-5,
}
}
pub fn head_dim(&self) -> usize {
self.d_model / self.num_heads
}
}
#[derive(Debug, Clone)]
pub struct LayerNormWeights {
pub gain: Arc<[f32]>,
pub bias: Arc<[f32]>,
}
#[derive(Debug, Clone)]
pub struct MimiAttentionWeights {
pub q_proj: WeightStorage,
pub k_proj: WeightStorage,
pub v_proj: WeightStorage,
pub o_proj: WeightStorage,
}
#[derive(Debug, Clone)]
pub struct MimiMlpWeights {
pub fc1: WeightStorage,
pub fc2: WeightStorage,
}
#[derive(Debug, Clone)]
pub struct MimiTransformerLayerWeights {
pub norm1: LayerNormWeights,
pub norm2: LayerNormWeights,
pub attn: MimiAttentionWeights,
pub mlp: MimiMlpWeights,
pub layer_scale_1: Arc<[f32]>,
pub layer_scale_2: Arc<[f32]>,
}
#[derive(Debug, Clone)]
pub struct MimiTransformerWeights {
pub layers: Vec<MimiTransformerLayerWeights>,
}
#[derive(Debug, Clone)]
pub struct ProjectedTransformerWeights {
pub transformer: MimiTransformerWeights,
pub input_proj: Option<WeightStorage>,
pub output_projs: Vec<(Option<WeightStorage>, usize)>,
}
#[derive(Debug, Clone)]
pub struct ProjectedTransformerModel {
pub config: MimiTransformerConfig,
pub input_dim: usize,
pub weights: ProjectedTransformerWeights,
}
impl ProjectedTransformerModel {
pub fn forward(&self, xs: &Tensor) -> Result<Vec<Tensor>> {
let cfg = &self.config;
let dims = xs.shape();
let dims = dims.dims();
assert_eq!(dims.len(), 3, "ProjectedTransformer expects rank 3 input");
let xs = if cfg.conv_layout {
xs.permute([0, 2, 1_usize])?
} else {
xs.clone()
};
let h = match &self.weights.input_proj {
None => xs,
Some(w) => w.apply_linear(&xs, self.input_dim, cfg.d_model)?,
};
let in_dims = h.shape();
let in_dims = in_dims.dims();
let b = in_dims[0];
let t = in_dims[1];
let head_dim = cfg.head_dim();
let (cos, sin) = build_rope_tables(&h, t, head_dim, cfg.max_period);
let causal_mask = Tensor::additive_causal_mask_like(&h, t);
let mut hidden = h;
for layer in &self.weights.transformer.layers {
hidden = apply_layer(&hidden, layer, &cos, &sin, &causal_mask, cfg, b, t)?;
}
let mut outs = Vec::with_capacity(self.weights.output_projs.len());
for (proj, out_dim) in &self.weights.output_projs {
let y = match proj {
None => hidden.clone(),
Some(w) => w.apply_linear(&hidden, cfg.d_model, *out_dim)?,
};
let y = if cfg.conv_layout {
y.permute([0, 2, 1_usize])?
} else {
y
};
outs.push(y);
}
Ok(outs)
}
}
fn apply_layer(
x: &Tensor,
w: &MimiTransformerLayerWeights,
cos: &Tensor,
sin: &Tensor,
causal_mask: &Tensor,
cfg: &MimiTransformerConfig,
b: usize,
t: usize,
) -> Result<Tensor> {
let n1 = x.layer_norm_affine(
Arc::clone(&w.norm1.gain),
Arc::clone(&w.norm1.bias),
cfg.layer_norm_eps,
)?;
let attn = apply_attention(&n1, &w.attn, cos, sin, causal_mask, cfg, b, t)?;
let scaled = apply_per_channel_scale(&attn, &w.layer_scale_1, cfg.d_model)?;
let after_attn = x.add(&scaled)?;
let n2 = after_attn.layer_norm_affine(
Arc::clone(&w.norm2.gain),
Arc::clone(&w.norm2.bias),
cfg.layer_norm_eps,
)?;
let mlp = apply_mlp(&n2, &w.mlp, cfg)?;
let scaled_mlp = apply_per_channel_scale(&mlp, &w.layer_scale_2, cfg.d_model)?;
after_attn.add(&scaled_mlp)
}
fn apply_attention(
x: &Tensor,
w: &MimiAttentionWeights,
cos: &Tensor,
sin: &Tensor,
causal_mask: &Tensor,
cfg: &MimiTransformerConfig,
b: usize,
t: usize,
) -> Result<Tensor> {
let d = cfg.d_model;
let heads = cfg.num_heads;
let head_dim = cfg.head_dim();
let scale = 1.0_f64 / (head_dim as f64).sqrt();
let q = w
.q_proj
.apply_linear(x, d, d)?
.split_heads(heads, head_dim)?;
let k = w
.k_proj
.apply_linear(x, d, d)?
.split_heads(heads, head_dim)?;
let v = w
.v_proj
.apply_linear(x, d, d)?
.split_heads(heads, head_dim)?;
let q = apply_rope_interleaved(&q, cos, sin, b, heads, t, head_dim)?;
let k = apply_rope_interleaved(&k, cos, sin, b, heads, t, head_dim)?;
let batch = b * heads;
let q3 = q.reshape(Shape::from_dims(&[batch, t, head_dim]))?;
let k3 = k.reshape(Shape::from_dims(&[batch, t, head_dim]))?;
let v3 = v.reshape(Shape::from_dims(&[batch, t, head_dim]))?;
let kt = k3.permute([0, 2, 1_usize])?;
let scores = q3.matmul(&kt)?.mul_scalar(scale);
let mask = causal_mask
.reshape(Shape::from_dims(&[1, t, t]))?
.broadcast_to(Shape::from_dims(&[batch, t, t]))?;
let scores = scores.add(&mask)?;
let probs = scores.softmax_last_dim()?;
let ctx = probs
.matmul(&v3)?
.reshape(Shape::from_dims(&[b, heads, t, head_dim]))?
.merge_heads()?;
let _ = d;
w.o_proj.apply_linear(&ctx, d, d)
}
fn apply_mlp(x: &Tensor, w: &MimiMlpWeights, cfg: &MimiTransformerConfig) -> Result<Tensor> {
let hidden = cfg.dim_feedforward;
let d = cfg.d_model;
let h = w.fc1.apply_linear(x, d, hidden)?.gelu();
w.fc2.apply_linear(&h, hidden, d)
}
fn apply_per_channel_scale(x: &Tensor, scale: &Arc<[f32]>, hidden: usize) -> Result<Tensor> {
let dims_v = x.shape().dims().to_vec();
let mut shape = vec![1_usize; dims_v.len()];
shape[dims_v.len() - 1] = hidden;
let s = x
.const_f32_like(Arc::clone(scale), Shape::from_dims(&[hidden]))?
.reshape(Shape::from_dims(&shape))?
.broadcast_to(Shape::from_dims(&dims_v))?;
x.mul(&s)
}
fn build_rope_tables(
anchor: &Tensor,
t: usize,
head_dim: usize,
max_period: f32,
) -> (Tensor, Tensor) {
let half = head_dim / 2;
let mut cos_v = Vec::with_capacity(t * half);
let mut sin_v = Vec::with_capacity(t * half);
for pos in 0..t {
for i in 0..half {
let freq = 1.0_f32 / max_period.powf((2 * i) as f32 / head_dim as f32);
let theta = (pos as f32) * freq;
cos_v.push(theta.cos());
sin_v.push(theta.sin());
}
}
let cos = anchor
.const_f32_like(Arc::from(cos_v), Shape::from_dims(&[t, half]))
.expect("mimi rope: t*half pushes against shape [t, half] -- same two values");
let sin = anchor
.const_f32_like(Arc::from(sin_v), Shape::from_dims(&[t, half]))
.expect("mimi rope: t*half pushes against shape [t, half] -- same two values");
(cos, sin)
}
fn apply_rope_interleaved(
x: &Tensor,
cos: &Tensor,
sin: &Tensor,
b: usize,
heads: usize,
t: usize,
head_dim: usize,
) -> Result<Tensor> {
let half = head_dim / 2;
let x_pairs = x.reshape(Shape::from_dims(&[b, heads, t, half, 2]))?;
let x_even = x_pairs
.narrow(4_usize, 0, 1)?
.reshape(Shape::from_dims(&[b, heads, t, half]))?;
let x_odd = x_pairs
.narrow(4_usize, 1, 1)?
.reshape(Shape::from_dims(&[b, heads, t, half]))?;
let cos_b = cos
.reshape(Shape::from_dims(&[1, 1, t, half]))?
.broadcast_to(Shape::from_dims(&[b, heads, t, half]))?;
let sin_b = sin
.reshape(Shape::from_dims(&[1, 1, t, half]))?
.broadcast_to(Shape::from_dims(&[b, heads, t, half]))?;
let new_even = x_even.mul(&cos_b)?.sub(&x_odd.mul(&sin_b)?)?;
let new_odd = x_even.mul(&sin_b)?.add(&x_odd.mul(&cos_b)?)?;
let stacked = Tensor::stack(&[&new_even, &new_odd], 4_usize)?;
stacked.reshape(Shape::from_dims(&[b, heads, t, head_dim]))
}
impl ProjectedTransformerWeights {
pub fn load_from_mmapped(
st: &fuel_loaders::safetensors::MmapedSafetensors,
prefix: &str,
cfg: &MimiTransformerConfig,
input_dim: usize,
output_dims: &[usize],
) -> Result<Self> {
use fuel_tensor::{lazy::load_tensor_as_f32, lazy::load_transposed_matrix_preserve_dtype};
let d = cfg.d_model;
let mut layers: Vec<MimiTransformerLayerWeights> = Vec::with_capacity(cfg.num_layers);
for i in 0..cfg.num_layers {
let p = format!("{prefix}.layers.{i}");
let n1_g = load_tensor_as_f32(st, &format!("{p}.input_layernorm.weight"))?;
let n1_b = load_tensor_as_f32(st, &format!("{p}.input_layernorm.bias"))?;
let n2_g = load_tensor_as_f32(st, &format!("{p}.post_attention_layernorm.weight"))?;
let n2_b = load_tensor_as_f32(st, &format!("{p}.post_attention_layernorm.bias"))?;
if n1_g.len() != d || n1_b.len() != d || n2_g.len() != d || n2_b.len() != d {
fuel_ir::bail!(
"{p} LN sizes: input_g {} input_b {} post_g {} post_b {} expected {d}",
n1_g.len(),
n1_b.len(),
n2_g.len(),
n2_b.len(),
);
}
let q_proj = load_transposed_matrix_preserve_dtype(
st,
&format!("{p}.self_attn.q_proj.weight"),
d,
d,
)?;
let k_proj = load_transposed_matrix_preserve_dtype(
st,
&format!("{p}.self_attn.k_proj.weight"),
d,
d,
)?;
let v_proj = load_transposed_matrix_preserve_dtype(
st,
&format!("{p}.self_attn.v_proj.weight"),
d,
d,
)?;
let o_proj = load_transposed_matrix_preserve_dtype(
st,
&format!("{p}.self_attn.o_proj.weight"),
d,
d,
)?;
let fc1 = load_transposed_matrix_preserve_dtype(
st,
&format!("{p}.mlp.fc1.weight"),
cfg.dim_feedforward,
d,
)?;
let fc2 = load_transposed_matrix_preserve_dtype(
st,
&format!("{p}.mlp.fc2.weight"),
d,
cfg.dim_feedforward,
)?;
let ls1 = load_tensor_as_f32(st, &format!("{p}.self_attn_layer_scale.scale"))?;
let ls2 = load_tensor_as_f32(st, &format!("{p}.mlp_layer_scale.scale"))?;
if ls1.len() != d || ls2.len() != d {
fuel_ir::bail!(
"{p} layer_scale sizes: ls1 {} ls2 {} expected {d}",
ls1.len(),
ls2.len(),
);
}
layers.push(MimiTransformerLayerWeights {
norm1: LayerNormWeights {
gain: Arc::from(n1_g),
bias: Arc::from(n1_b),
},
norm2: LayerNormWeights {
gain: Arc::from(n2_g),
bias: Arc::from(n2_b),
},
attn: MimiAttentionWeights {
q_proj,
k_proj,
v_proj,
o_proj,
},
mlp: MimiMlpWeights { fc1, fc2 },
layer_scale_1: Arc::from(ls1),
layer_scale_2: Arc::from(ls2),
});
}
let input_proj = if input_dim == d {
None
} else {
let w = load_transposed_matrix_preserve_dtype(
st,
&format!("{prefix}.input_proj.weight"),
d,
input_dim,
)?;
Some(w)
};
let mut output_projs: Vec<(Option<WeightStorage>, usize)> =
Vec::with_capacity(output_dims.len());
for (i, &od) in output_dims.iter().enumerate() {
let proj = if od == d {
None
} else {
let w = load_transposed_matrix_preserve_dtype(
st,
&format!("{prefix}.output_projs.{i}.weight"),
od,
d,
)?;
Some(w)
};
output_projs.push((proj, od));
}
Ok(ProjectedTransformerWeights {
transformer: MimiTransformerWeights { layers },
input_proj,
output_projs,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use fuel_tensor::Device;
fn rng_seed(seed: u32) -> impl FnMut() -> f32 {
let mut s = seed;
move || {
s = s.wrapping_mul(1103515245).wrapping_add(12345);
((s >> 16) as u16 as f32 / 65535.0 - 0.5) * 0.05
}
}
fn vec_of(n: usize, nb: &mut dyn FnMut() -> f32) -> Arc<[f32]> {
Arc::from((0..n).map(|_| nb()).collect::<Vec<_>>())
}
fn ws(n: usize, nb: &mut dyn FnMut() -> f32) -> WeightStorage {
WeightStorage::F32(vec_of(n, nb))
}
fn ln_w(c: usize) -> LayerNormWeights {
LayerNormWeights {
gain: Arc::from(vec![1.0_f32; c]),
bias: Arc::from(vec![0.0_f32; c]),
}
}
fn tiny_cfg() -> MimiTransformerConfig {
MimiTransformerConfig {
d_model: 8,
num_heads: 2,
num_layers: 2,
dim_feedforward: 16,
max_period: 10_000.0,
conv_layout: true,
layer_norm_eps: 1e-5,
}
}
fn build_layer(
d: usize,
ff: usize,
nb: &mut dyn FnMut() -> f32,
) -> MimiTransformerLayerWeights {
MimiTransformerLayerWeights {
norm1: ln_w(d),
norm2: ln_w(d),
attn: MimiAttentionWeights {
q_proj: ws(d * d, nb),
k_proj: ws(d * d, nb),
v_proj: ws(d * d, nb),
o_proj: ws(d * d, nb),
},
mlp: MimiMlpWeights {
fc1: ws(d * ff, nb),
fc2: ws(ff * d, nb),
},
layer_scale_1: vec_of(d, nb),
layer_scale_2: vec_of(d, nb),
}
}
fn tiny_model(input_dim: usize, output_dims: Vec<usize>) -> ProjectedTransformerModel {
let cfg = tiny_cfg();
let mut nb = rng_seed(2026);
let d = cfg.d_model;
let ff = cfg.dim_feedforward;
let transformer = MimiTransformerWeights {
layers: (0..cfg.num_layers)
.map(|_| build_layer(d, ff, &mut nb))
.collect(),
};
let input_proj = if input_dim == d {
None
} else {
Some(ws(input_dim * d, &mut nb))
};
let output_projs: Vec<_> = output_dims
.iter()
.map(|&od| {
let proj = if od == d {
None
} else {
Some(ws(d * od, &mut nb))
};
(proj, od)
})
.collect();
ProjectedTransformerModel {
config: cfg,
input_dim,
weights: ProjectedTransformerWeights {
transformer,
input_proj,
output_projs,
},
}
}
#[test]
fn forward_returns_one_per_output_dim() {
let d = 8;
let model = tiny_model(d, vec![d]);
let xs = Tensor::from_f32(
(0..(1 * d * 5))
.map(|i| (i as f32) * 0.01)
.collect::<Vec<_>>(),
Shape::from_dims(&[1, d, 5]),
&Device::cpu(),
)
.unwrap();
let outs = model.forward(&xs).unwrap();
assert_eq!(outs.len(), 1);
assert_eq!(outs[0].shape().dims(), &[1, d, 5]);
for &v in &outs[0].realize_f32() {
assert!(v.is_finite());
}
}
#[test]
fn forward_with_different_input_dim_uses_input_proj() {
let input_dim = 4;
let d = 8;
let model = tiny_model(input_dim, vec![d]);
let xs = Tensor::from_f32(
(0..(1 * input_dim * 5))
.map(|i| (i as f32) * 0.01)
.collect::<Vec<_>>(),
Shape::from_dims(&[1, input_dim, 5]),
&Device::cpu(),
)
.unwrap();
let outs = model.forward(&xs).unwrap();
assert_eq!(outs[0].shape().dims(), &[1, d, 5]);
}
#[test]
fn forward_multiple_output_projections() {
let d = 8;
let model = tiny_model(d, vec![d, 4]);
let xs = Tensor::from_f32(
(0..(1 * d * 5))
.map(|i| (i as f32) * 0.01)
.collect::<Vec<_>>(),
Shape::from_dims(&[1, d, 5]),
&Device::cpu(),
)
.unwrap();
let outs = model.forward(&xs).unwrap();
assert_eq!(outs.len(), 2);
assert_eq!(outs[0].shape().dims(), &[1, d, 5]);
assert_eq!(outs[1].shape().dims(), &[1, 4, 5]);
}
#[test]
fn rope_zero_position_is_identity() {
let b = 1;
let h = 2;
let t = 1;
let d = 4;
let x_data: Vec<f32> = (0..(b * h * t * d))
.map(|i| (i as f32 + 1.0) * 0.1)
.collect();
let x = Tensor::from_f32(
x_data.clone(),
Shape::from_dims(&[b, h, t, d]),
&Device::cpu(),
)
.unwrap();
let (cos, sin) = build_rope_tables(&x, t, d, 10_000.0);
let out = apply_rope_interleaved(&x, &cos, &sin, b, h, t, d).unwrap();
let out_data = out.realize_f32();
for (a, b) in x_data.iter().zip(out_data.iter()) {
assert!(
(a - b).abs() < 1e-6,
"RoPE at pos=0 should be identity: {a} vs {b}"
);
}
}
#[test]
#[allow(clippy::needless_range_loop)]
fn causal_mask_enforces_position() {
let d = 8;
let model = tiny_model(d, vec![d]);
let t = 4;
let xs_a = Tensor::from_f32(
(0..(1 * d * t))
.map(|i| (i as f32) * 0.01)
.collect::<Vec<_>>(),
Shape::from_dims(&[1, d, t]),
&Device::cpu(),
)
.unwrap();
let mut data_b: Vec<f32> = (0..(1 * d * t)).map(|i| (i as f32) * 0.01).collect();
for c in 0..d {
data_b[c * t + (t - 1)] = 9.0; }
let xs_b = Tensor::from_f32(data_b, Shape::from_dims(&[1, d, t]), &Device::cpu()).unwrap();
let oa = model.forward(&xs_a).unwrap();
let ob = model.forward(&xs_b).unwrap();
let da = oa[0].realize_f32();
let db = ob[0].realize_f32();
let mut max_pos_diff = vec![0.0_f32; t];
for c in 0..d {
for pos in 0..t {
let i = c * t + pos;
let d_pos = (da[i] - db[i]).abs();
if d_pos > max_pos_diff[pos] {
max_pos_diff[pos] = d_pos;
}
}
}
for pos in 0..(t - 1) {
assert!(
max_pos_diff[pos] < 1e-5,
"causal mask violated at pos {pos}: max_diff = {}",
max_pos_diff[pos]
);
}
assert!(
max_pos_diff[t - 1] > 1e-6,
"last-pos output should respond to last-token input change"
);
}
#[test]
fn preset_mimi_v0_1() {
let p = MimiTransformerConfig::mimi_v0_1();
assert_eq!(p.d_model, 512);
assert_eq!(p.num_heads, 8);
assert_eq!(p.num_layers, 8);
assert_eq!(p.head_dim(), 64);
}
}