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