18 const int num_heads = dim / head_dim;
19 for (
int row = 0; row < rows; ++row) {
20 float *row_ptr = x + (size_t)row * (
size_t)dim;
21 for (
int head = 0; head < num_heads; ++head) {
22 float *head_ptr = row_ptr + (size_t)head * (
size_t)head_dim;
24 for (
int col = 0; col < head_dim; ++col) {
25 sum_sq += (double)(head_ptr[col] * head_ptr[col]);
27 const float norm = sqrtf((
float)sum_sq);
28 const float inv_norm = 1.0f / fmaxf(norm, eps);
29 for (
int col = 0; col < head_dim; ++col) {
30 head_ptr[col] *= inv_norm;
48 const ck_recurrent_qk_l2_args_t *args =
49 (
const ck_recurrent_qk_l2_args_t *)opaque;
50 const int heads_per_row = args->q_heads + args->k_heads;
51 for (
int job = begin; job <
end; ++job) {
52 const int row = job / heads_per_row;
53 const int local_head = job - row * heads_per_row;
55 if (local_head < args->q_heads) {
57 ((size_t)row * (
size_t)args->q_heads +
58 (size_t)local_head) * (size_t)args->head_dim;
61 ((size_t)row * (
size_t)args->k_heads +
62 (size_t)(local_head - args->q_heads)) *
63 (
size_t)args->head_dim;
67 for (
int col = 0; col < args->head_dim; ++col) {
68 sum_sq += (double)(head_ptr[col] * head_ptr[col]);
70 const float norm = sqrtf((
float)sum_sq);
71 const float inv_norm = 1.0f / fmaxf(norm, args->eps);
72 for (
int col = 0; col < args->head_dim; ++col) {
73 head_ptr[col] *= inv_norm;
85 if (!d_out || !x || !d_x || rows <= 0 || dim <= 0 || head_dim <= 0) {
88 const int num_heads = dim / head_dim;
89 if (num_heads <= 0 || num_heads * head_dim != dim) {
93 for (
int row = 0; row < rows; ++row) {
94 const float *d_row = d_out + (size_t) row * (
size_t) dim;
95 const float *x_row = x + (size_t) row * (
size_t) dim;
96 float *dx_row = d_x + (size_t) row * (
size_t) dim;
97 for (
int head = 0; head < num_heads; ++head) {
98 const float *d_head = d_row + (size_t) head * (
size_t) head_dim;
99 const float *x_head = x_row + (size_t) head * (
size_t) head_dim;
100 float *dx_head = dx_row + (size_t) head * (
size_t) head_dim;
104 for (
int col = 0; col < head_dim; ++col) {
105 sum_sq += (double) (x_head[col] * x_head[col]);
106 dot += (double) (d_head[col] * x_head[col]);
108 const float norm = sqrtf((
float) sum_sq);
109 const float inv_norm = 1.0f / fmaxf(norm, eps);
111 for (
int col = 0; col < head_dim; ++col) {
112 dx_head[col] = d_head[col] / eps;
116 const float proj_scale = inv_norm * inv_norm * inv_norm * (float) dot;
117 for (
int col = 0; col < head_dim; ++col) {
118 dx_head[col] = inv_norm * d_head[col] - proj_scale * x_head[col];
131 if (!q || !k || rows <= 0 || q_dim <= 0 || k_dim <= 0 ||
132 head_dim <= 0 || q_dim % head_dim != 0 || k_dim % head_dim != 0) {
135 const int q_heads = q_dim / head_dim;
136 const int k_heads = k_dim / head_dim;
137 if (q_heads > INT_MAX - k_heads) {
140 const int heads_per_row = q_heads + k_heads;
141 if (rows > INT_MAX / heads_per_row) {
145 ck_recurrent_qk_l2_args_t args = {
146 q, k, q_heads, k_heads, head_dim, eps,
148 const int jobs = rows * heads_per_row;
149 const size_t elements = (size_t)jobs * (
size_t)head_dim;
150 const size_t minimum_elements_per_thread = 32768u;
151 const uintptr_t q_begin = (uintptr_t)q;
152 const uintptr_t q_end = q_begin +
153 (size_t)rows * (
size_t)q_dim *
sizeof(float);
154 const uintptr_t k_begin = (uintptr_t)k;
155 const uintptr_t k_end = k_begin +
156 (size_t)rows * (
size_t)k_dim *
sizeof(float);
157 const int ranges_overlap = q_begin < k_end && k_begin < q_end;
158 if (ranges_overlap || elements < 2u * minimum_elements_per_thread) {
166 size_t useful_threads =
167 (elements + minimum_elements_per_thread - 1u) /
168 minimum_elements_per_thread;
169 if ((
size_t)active > useful_threads) {
170 active = (int)useful_threads;
178 pool, active, 0, jobs, 8,
201 enum { ilp_factor = 4, num_levels = 4, vector_width = 8 };
202 const int vector_count = dim / vector_width;
203 const int cascade_count = vector_count / ilp_factor;
204 const int level_power =
208 const int level_step = 1 << level_power;
209 const int level_mask = level_step - 1;
210 __m256 acc[num_levels][ilp_factor];
211 for (
int level = 0; level < num_levels; ++level) {
212 for (
int lane = 0; lane < ilp_factor; ++lane) {
213 acc[level][lane] = _mm256_setzero_ps();
218 while (group + level_step <= cascade_count) {
219 for (
int offset = 0; offset < level_step; ++offset, ++group) {
220 for (
int lane = 0; lane < ilp_factor; ++lane) {
221 const int vector_index = group * ilp_factor + lane;
222 const __m256 value = _mm256_loadu_ps(
223 x + vector_index * vector_width);
224 const __m256 square = _mm256_mul_ps(value, value);
225 acc[0][lane] = _mm256_add_ps(acc[0][lane], square);
228 for (
int level = 1; level < num_levels; ++level) {
229 for (
int lane = 0; lane < ilp_factor; ++lane) {
231 _mm256_add_ps(acc[level][lane], acc[level - 1][lane]);
232 acc[level - 1][lane] = _mm256_setzero_ps();
234 const int mask = level_mask << (level * level_power);
235 if ((group &
mask) != 0) {
240 for (; group < cascade_count; ++group) {
241 for (
int lane = 0; lane < ilp_factor; ++lane) {
242 const int vector_index = group * ilp_factor + lane;
243 const __m256 value = _mm256_loadu_ps(
244 x + vector_index * vector_width);
245 const __m256 square = _mm256_mul_ps(value, value);
246 acc[0][lane] = _mm256_add_ps(acc[0][lane], square);
249 for (
int level = 1; level < num_levels; ++level) {
250 for (
int lane = 0; lane < ilp_factor; ++lane) {
252 _mm256_add_ps(acc[0][lane], acc[level][lane]);
256 int vector_index = cascade_count * ilp_factor;
257 for (; vector_index < vector_count; ++vector_index) {
258 const __m256 value = _mm256_loadu_ps(
259 x + vector_index * vector_width);
260 const __m256 square = _mm256_mul_ps(value, value);
261 acc[0][0] = _mm256_add_ps(acc[0][0], square);
263 for (
int lane = 1; lane < ilp_factor; ++lane) {
264 acc[0][0] = _mm256_add_ps(acc[0][0], acc[0][lane]);
267 _Alignas(32)
float lanes[8];
268 _mm256_store_ps(lanes, acc[0][0]);
269 volatile float sum = 0.0f;
270 for (
int lane = 0; lane < 8; ++lane) {
271 sum = sum + lanes[lane];
273 for (
int d = vector_count * vector_width; d < dim; ++d) {
274 sum = sum + x[d] * x[d];
279 volatile float sum = 0.0f;
280 for (
int d = 0; d < dim; ++d) {
281 sum = sum + x[d] * x[d];
292 if (!x || rows <= 0 || dim <= 0 || head_dim <= 0 ||
293 dim % head_dim != 0) {
296 const int num_heads = dim / head_dim;
297 for (
int row = 0; row < rows; ++row) {
298 float *row_ptr = x + (size_t)row * (
size_t)dim;
299 for (
int head = 0; head < num_heads; ++head) {
300 float *head_ptr = row_ptr + (size_t)head * (
size_t)head_dim;
303 const float inverse = 1.0f / sqrtf(sum + eps);
304#if defined(__AVX512F__)
305 const __m512 inv = _mm512_set1_ps(inverse);
307 for (; d + 16 <= head_dim; d += 16) {
310 _mm512_mul_ps(_mm512_loadu_ps(head_ptr + d), inv));
312 for (; d < head_dim; ++d) {
313 head_ptr[d] = head_ptr[d] * inverse;
315#elif defined(__AVX2__)
316 const __m256 inv = _mm256_set1_ps(inverse);
318 for (; d + 8 <= head_dim; d += 8) {
321 _mm256_mul_ps(_mm256_loadu_ps(head_ptr + d), inv));
323 for (; d < head_dim; ++d) {
324 head_ptr[d] = head_ptr[d] * inverse;
327 for (
int d = 0; d < head_dim; ++d) {
328 head_ptr[d] = head_ptr[d] * inverse;
351 __m256 streams[4] = {
352 _mm256_setzero_ps(), _mm256_setzero_ps(),
353 _mm256_setzero_ps(), _mm256_setzero_ps()
356 for (; d + 32 <= dim; d += 32) {
357 for (
int stream = 0; stream < 4; ++stream) {
358 _Alignas(32)
float lanes[8];
359 const __m256 values = _mm256_loadu_ps(x + d + stream * 8);
360 _mm256_store_ps(lanes, _mm256_mul_ps(values, values));
361 for (
int lane = 0; lane < 8; ++lane) {
366 _mm256_add_ps(streams[stream], _mm256_load_ps(lanes));
369 __m256 reduced = _mm256_add_ps(streams[0], streams[1]);
370 reduced = _mm256_add_ps(reduced, streams[2]);
371 reduced = _mm256_add_ps(reduced, streams[3]);
372 _Alignas(32)
float lanes[8];
373 _mm256_store_ps(lanes, reduced);
374 volatile float sum = 0.0f;
375 for (
int lane = 0; lane < 8; ++lane) {
376 sum = sum + lanes[lane];
378 for (; d < dim; ++d) {
387 volatile float sum = 0.0f;
388 for (
int d = 0; d < dim; ++d) {
403 if (!x || rows <= 0 || dim <= 0 || head_dim <= 0 ||
404 dim % head_dim != 0) {
407 const int num_heads = dim / head_dim;
408 if (expanded_heads <= 0 || expanded_heads % num_heads != 0) {
411 const int heads_per_group = expanded_heads / num_heads;
412 const int total_heads = rows * expanded_heads;
413 const int vector_limit = (total_heads / 32) * 32;
414 for (
int row = 0; row < rows; ++row) {
415 float *row_ptr = x + (size_t)row * (
size_t)dim;
416 for (
int head = 0; head < num_heads; ++head) {
418 row_ptr + (size_t)head * (
size_t)head_dim;
422 const float denominator =
431 const int flat_head =
432 (row * expanded_heads) + head * heads_per_group;
434 if (flat_head < vector_limit) {
447 for (
int col = 0; col < head_dim; ++col) {
void recurrent_qk_l2_norm_backward(const float *d_q_out, const float *d_k_out, const float *q, const float *k, float *d_q, float *d_k, int rows, int q_dim, int k_dim, int head_dim, float eps)