metrale_model_layers/layers/glm_vit/
rope.rs1use super::GlmVit;
14
15pub fn block_major_position_ids(grid_h: usize, grid_w: usize, merge: usize) -> Vec<(u32, u32)> {
20 let m = merge.max(1);
21 let (bh, bw) = (grid_h / m, grid_w / m);
22 let mut ids = Vec::with_capacity(bh * bw * m * m);
23 for a in 0..bh {
24 for c in 0..bw {
25 for b in 0..m {
26 for d in 0..m {
27 ids.push(((a * m + b) as u32, (c * m + d) as u32));
28 }
29 }
30 }
31 }
32 ids
33}
34
35pub fn build_axial_rope_tables(
42 ids: &[(u32, u32)],
43 inv_freq: &[f32],
44 head_dim: usize,
45) -> (Vec<f32>, Vec<f32>) {
46 let half = head_dim / 2;
47 let n_freq = inv_freq.len();
48 let mut cos = vec![0.0f32; ids.len() * head_dim];
49 let mut sin = vec![0.0f32; ids.len() * head_dim];
50 for (t, &(h_id, w_id)) in ids.iter().enumerate() {
51 for d in 0..half {
52 let angle = if d < n_freq {
54 h_id as f32 * inv_freq[d]
55 } else {
56 w_id as f32 * inv_freq[d - n_freq]
57 };
58 let (s, c) = angle.sin_cos();
59 cos[t * head_dim + d] = c;
60 cos[t * head_dim + half + d] = c;
61 sin[t * head_dim + d] = s;
62 sin[t * head_dim + half + d] = s;
63 }
64 }
65 (cos, sin)
66}
67
68impl GlmVit {
69 pub(super) fn upload_rope_tables(
71 &self,
72 grid_h: usize,
73 grid_w: usize,
74 cos_dst: metrale_gpu_runtime::gpu::DevicePtr,
75 sin_dst: metrale_gpu_runtime::gpu::DevicePtr,
76 gpu: &dyn metrale_gpu_runtime::gpu::GpuBackend,
77 stream: u64,
78 ) -> anyhow::Result<()> {
79 let ids = block_major_position_ids(grid_h, grid_w, self.spatial_merge_size);
80 let (cos, sin) = build_axial_rope_tables(&ids, &self.rope_inv_freq, self.head_dim);
81 gpu.copy_h2d_async(&to_bf16_bytes(&cos), cos_dst, stream)?;
82 gpu.copy_h2d_async(&to_bf16_bytes(&sin), sin_dst, stream)?;
83 Ok(())
84 }
85}
86
87pub(super) fn to_bf16_bytes(v: &[f32]) -> Vec<u8> {
89 let mut out = Vec::with_capacity(v.len() * 2);
90 for &x in v {
91 let bits = x.to_bits();
92 let lsb = (bits >> 16) & 1;
93 let rounded = bits.wrapping_add(0x7fff + lsb);
94 out.extend_from_slice(&((rounded >> 16) as u16).to_le_bytes());
95 }
96 out
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
106 fn position_ids_are_block_major_not_raster() {
107 let ids = block_major_position_ids(4, 4, 2);
108 assert_eq!(ids.len(), 16);
109 assert_eq!(&ids[0..4], &[(0, 0), (0, 1), (1, 0), (1, 1)]);
110 assert_eq!(&ids[4..8], &[(0, 2), (0, 3), (1, 2), (1, 3)]);
111 assert_eq!(&ids[8..12], &[(2, 0), (2, 1), (3, 0), (3, 1)]);
112 assert_ne!(ids[2], (0, 2));
113 }
114
115 #[test]
118 fn position_ids_handle_a_non_square_grid() {
119 let ids = block_major_position_ids(26, 46, 2);
120 assert_eq!(ids.len(), 26 * 46);
121 assert_eq!(ids[0], (0, 0));
122 assert_eq!(ids[23 * 4 - 1], (1, 45));
123 assert_eq!(*ids.last().unwrap(), (25, 45));
124 let mut seen: Vec<(u32, u32)> = ids.clone();
125 seen.sort_unstable();
126 seen.dedup();
127 assert_eq!(seen.len(), ids.len(), "block-major must be a permutation");
128 }
129
130 #[test]
133 fn axial_tables_duplicate_the_half_row() {
134 let head_dim = 8;
135 let inv_freq = vec![1.0f32, 0.5];
136 let ids = [(3u32, 5u32)];
137 let (cos, sin) = build_axial_rope_tables(&ids, &inv_freq, head_dim);
138 let expect: [f32; 4] = [3.0 * 1.0, 3.0 * 0.5, 5.0 * 1.0, 5.0 * 0.5];
139 for (d, &angle) in expect.iter().enumerate() {
140 assert!((cos[d] - angle.cos()).abs() < 1e-6, "cos[{d}]");
141 assert!((sin[d] - angle.sin()).abs() < 1e-6, "sin[{d}]");
142 assert_eq!(cos[d], cos[head_dim / 2 + d]);
143 assert_eq!(sin[d], sin[head_dim / 2 + d]);
144 }
145 }
146
147 #[test]
149 fn the_origin_token_is_an_identity_rotation() {
150 let inv_freq: Vec<f32> = (0..16)
151 .map(|k| 10_000f32.powf(-2.0 * k as f32 / 32.0))
152 .collect();
153 let ids = block_major_position_ids(32, 32, 2);
154 let (cos, sin) = build_axial_rope_tables(&ids, &inv_freq, 64);
155 for d in 0..64 {
156 assert_eq!(cos[d], 1.0);
157 assert_eq!(sin[d], 0.0);
158 }
159 }
160
161 #[test]
162 fn bf16_conversion_rounds_to_nearest_even() {
163 assert_eq!(to_bf16_bytes(&[1.0]), 0x3f80u16.to_le_bytes().to_vec());
164 let halfway = f32::from_bits(0x3f80_8000);
166 assert_eq!(to_bf16_bytes(&[halfway]), 0x3f80u16.to_le_bytes().to_vec());
167 let above = f32::from_bits(0x3f80_8001);
168 assert_eq!(to_bf16_bytes(&[above]), 0x3f81u16.to_le_bytes().to_vec());
169 }
170}