use rayon::prelude::*;
use super::Decoder;
use crate::norm::NormOp;
impl Decoder {
pub(crate) fn pre_norm_residual(
&self,
norm: &NormOp,
hidden: &mut [f32],
rows: usize,
) -> Vec<f32> {
let hidden_dim = self.config.hidden_dim;
debug_assert_eq!(hidden.len(), rows * hidden_dim);
let eps = self.config.rms_norm_eps;
let normed: Vec<f32> = if rows > 1 {
hidden
.par_chunks(hidden_dim)
.map(|row| norm.apply(row, eps))
.flatten()
.collect()
} else {
hidden
.chunks(hidden_dim)
.flat_map(|row| norm.apply(row, eps))
.collect()
};
crate::normed_residual::adopt(hidden, &normed, self.config.normed_residual_scale);
normed
}
}
#[cfg(test)]
mod tests {
#[test]
fn no_host_body_norms_the_stream_by_hand() {
const BODIES: [(&str, &str); 4] = [
("decoder.rs", include_str!("../decoder.rs")),
("decoder/ffn_block.rs", include_str!("ffn_block.rs")),
("decoder/attn_block.rs", include_str!("attn_block.rs")),
(
"decoder/recurrent_block.rs",
include_str!("recurrent_block.rs"),
),
];
for (name, src) in BODIES {
let flat: String = src.chars().filter(|c| !c.is_whitespace()).collect();
assert!(
!flat.contains(".norm_weight.apply("),
"{name} norms the residual stream by hand; call `Decoder::pre_norm_residual` \
so the architectures whose residual IS that norm's output \
(`crate::normed_residual`) are served there too"
);
}
}
}