99namespace flag_gems {
1010using namespace triton_jit ;
1111
12- void rotary_embedding_inplace (
13- at::Tensor& q, // [batch_size, seq_len, q_heads, head_dim] or [num_tokens, q_heads, head_dim]
14- at::Tensor& k, // [batch_size, seq_len, k_heads, head_dim] or [num_tokens, k_heads, head_dim]
12+ void check_rotary_embedding_inputs (
13+ const at::Tensor& q, // [batch_size, seq_len, q_heads, head_dim] or [num_tokens, q_heads, head_dim]
14+ const at::Tensor& k, // [batch_size, seq_len, k_heads, head_dim] or [num_tokens, k_heads, head_dim]
1515 const at::Tensor& cos, // [max_seq_len, head_dim // 2]
1616 const at::Tensor& sin, // [max_seq_len, head_dim // 2]
17- std::optional<at::Tensor> position_ids, // None or [..., seq_len]
18- bool rotary_interleaved) { // default false
19-
17+ const std::optional<at::Tensor>& position_ids) { // None or [..., seq_len]
18+ // 1. Check that q and k have the same head dimension
2019 TORCH_CHECK (k.size (-1 ) == q.size (-1 ),
2120 " q and k must have the same last dimension, got " ,
2221 q.sizes (),
2322 " and " ,
2423 k.sizes ());
24+
25+ // 2. Check that cos and sin have the same last dimension
2526 TORCH_CHECK (cos.size (-1 ) == sin.size (-1 ),
2627 " cos and sin must have the same last dimension, got " ,
2728 cos.sizes (),
2829 " and " ,
2930 sin.sizes ());
31+
32+ // 3. Check that cos/sin dimension matches q/k head_dim // 2
3033 TORCH_CHECK (cos.size (-1 ) * 2 == q.size (-1 ),
3134 " cos/sin dim must be half of q/k dim, got " ,
3235 cos.sizes (),
3336 " and " ,
3437 q.sizes ());
3538
36- TORCH_CHECK (cos.stride (-1 ) == 1 , " cos must be contiguous at the last dimension" );
37- TORCH_CHECK (sin.stride (-1 ) == 1 , " sin must be contiguous at the last dimension" );
39+ // 4. Check that cos and sin are contiguous at the last dimension
40+ TORCH_CHECK (cos.stride (-1 ) == 1 ,
41+ " cos must be contiguous at the last dimension, got stride " ,
42+ cos.stride (-1 ));
43+ TORCH_CHECK (sin.stride (-1 ) == 1 ,
44+ " sin must be contiguous at the last dimension, got stride " ,
45+ sin.stride (-1 ));
3846
3947 auto q_sizes = q.sizes ();
4048 auto k_sizes = k.sizes ();
41- std::optional<int64_t > seq_len;
4249
50+ // 5. Check that q and k have the same number of dimensions
4351 TORCH_CHECK (q_sizes.size () == k_sizes.size (),
4452 " q and k must have the same number of dimensions, got " ,
4553 q_sizes.size (),
4654 " and " ,
4755 k_sizes.size ());
4856
57+ // 6. Check that all dimensions except the last two match between q and k
4958 for (int i = 0 ; i < q_sizes.size () - 2 ; ++i) {
5059 TORCH_CHECK (q_sizes[i] == k_sizes[i],
51- " q and k must have the same shape before the last two dims, got " ,
52- q_sizes,
60+ " Mismatch in q and k shape at dim " ,
61+ i,
62+ " : got " ,
63+ q_sizes[i],
5364 " and " ,
54- k_sizes);
65+ k_sizes[i] );
5566 }
5667
68+ // 7. If position_ids is not provided, q must have 4 dimensions
5769 if (!position_ids.has_value ()) {
5870 TORCH_CHECK (q_sizes.size () == 4 ,
5971 " q must have 4 dimensions if position_ids is not provided, got " ,
6072 q_sizes.size ());
61- seq_len = q_sizes[1 ];
62-
63- } else { // default case
73+ } else {
6474 auto pos_sizes = position_ids.value ().sizes ();
75+
76+ // 8. Check that position_ids has the same number of dims as q.shape[:-2]
6577 TORCH_CHECK (pos_sizes.size () == q_sizes.size () - 2 ,
6678 " position_ids must have the same number of dims as q.shape[:-2], got " ,
6779 pos_sizes.size (),
6880 " and " ,
6981 q_sizes.size () - 2 );
7082
83+ // 9. Check that position_ids shape matches q.shape[:-2] on each dimension
7184 for (int i = 0 ; i < pos_sizes.size (); ++i) {
7285 TORCH_CHECK (pos_sizes[i] == q_sizes[i],
7386 " Mismatch in position_ids and q shape at dim " ,
@@ -77,7 +90,28 @@ void rotary_embedding_inplace(
7790 " and " ,
7891 q_sizes[i]);
7992 }
93+ }
94+ }
95+
96+ void rotary_embedding_inplace (
97+ at::Tensor& q, // [batch_size, seq_len, q_heads, head_dim] or [num_tokens, q_heads, head_dim]
98+ at::Tensor& k, // [batch_size, seq_len, k_heads, head_dim] or [num_tokens, k_heads, head_dim]
99+ const at::Tensor& cos, // [max_seq_len, head_dim // 2]
100+ const at::Tensor& sin, // [max_seq_len, head_dim // 2]
101+ std::optional<at::Tensor> position_ids, // None or [..., seq_len]
102+ bool rotary_interleaved) { // default false
103+
104+ check_rotary_embedding_inputs (q, k, cos, sin, position_ids);
105+
106+ auto q_sizes = q.sizes ();
107+ auto k_sizes = k.sizes ();
108+ std::optional<int64_t > seq_len;
109+
110+ if (!position_ids.has_value ()) {
111+ seq_len = q_sizes[1 ];
80112
113+ } else { // default case
114+ auto pos_sizes = position_ids.value ().sizes ();
81115 position_ids = position_ids.value ().view ({-1 }); // flatten the position_ids tensor
82116 seq_len = std::nullopt ;
83117 }
@@ -166,67 +200,18 @@ std::tuple<at::Tensor, at::Tensor> rotary_embedding(const at::Tensor& q,
166200 const at::Tensor& sin,
167201 std::optional<at::Tensor> position_ids,
168202 bool rotary_interleaved) {
169- TORCH_CHECK (k.size (-1 ) == q.size (-1 ),
170- " q and k must have the same last dimension, got " ,
171- q.sizes (),
172- " and " ,
173- k.sizes ());
174- TORCH_CHECK (cos.size (-1 ) == sin.size (-1 ),
175- " cos and sin must have the same last dimension, got " ,
176- cos.sizes (),
177- " and " ,
178- sin.sizes ());
179- TORCH_CHECK (cos.size (-1 ) * 2 == q.size (-1 ),
180- " cos/sin dim must be half of q/k dim, got " ,
181- cos.sizes (),
182- " and " ,
183- q.sizes ());
184-
185- TORCH_CHECK (cos.stride (-1 ) == 1 , " cos must be contiguous at the last dimension" );
186- TORCH_CHECK (sin.stride (-1 ) == 1 , " sin must be contiguous at the last dimension" );
203+ // Check inputs
204+ check_rotary_embedding_inputs (q, k, cos, sin, position_ids);
187205
188206 auto q_sizes = q.sizes ();
189207 auto k_sizes = k.sizes ();
190208 std::optional<int64_t > seq_len;
191209
192- TORCH_CHECK (q_sizes.size () == k_sizes.size (),
193- " q and k must have the same number of dimensions, got " ,
194- q_sizes.size (),
195- " and " ,
196- k_sizes.size ());
197-
198- for (int i = 0 ; i < q_sizes.size () - 2 ; ++i) {
199- TORCH_CHECK (q_sizes[i] == k_sizes[i],
200- " q and k must have the same shape before the last two dims, got " ,
201- q_sizes,
202- " and " ,
203- k_sizes);
204- }
205-
206210 if (!position_ids.has_value ()) {
207- TORCH_CHECK (q_sizes.size () == 4 ,
208- " q must have 4 dimensions if position_ids is not provided, got " ,
209- q_sizes.size ());
210211 seq_len = q_sizes[1 ];
211212
212213 } else { // default case
213214 auto pos_sizes = position_ids.value ().sizes ();
214- TORCH_CHECK (pos_sizes.size () == q_sizes.size () - 2 ,
215- " position_ids must have the same number of dims as q.shape[:-2], got " ,
216- pos_sizes.size (),
217- " and " ,
218- q_sizes.size () - 2 );
219-
220- for (int i = 0 ; i < pos_sizes.size (); ++i) {
221- TORCH_CHECK (pos_sizes[i] == q_sizes[i],
222- " Mismatch in position_ids and q shape at dim " ,
223- i,
224- " : got " ,
225- pos_sizes[i],
226- " and " ,
227- q_sizes[i]);
228- }
229-
230215 position_ids = position_ids.value ().view ({-1 }); // flatten the position_ids tensor
231216 seq_len = std::nullopt ;
232217 }
0 commit comments