20#if defined(__AVX2__) || defined(__AVX__) || defined(__AVX512F__)
33} ck_train_gemm_args_t;
35#if defined(__AVX__) && !defined(__AVX512F__)
36static inline float ck_train_hsum256_ps(__m256 v) {
37 __m128 lo = _mm256_castps256_ps128(v);
38 __m128 hi = _mm256_extractf128_ps(v, 1);
39 __m128 sum128 = _mm_add_ps(lo, hi);
40 __m128 shuf = _mm_movehdup_ps(sum128);
41 __m128 sums = _mm_add_ps(sum128, shuf);
42 shuf = _mm_movehl_ps(shuf, sums);
43 sums = _mm_add_ss(sums, shuf);
44 return _mm_cvtss_f32(sums);
56 if (!A || !B || !
C || row_start >= row_end || N <= 0 || K <= 0) {
60 for (
int i = row_start; i < row_end; ++i) {
61 const float *a_row = A + (size_t)i * (
size_t)K;
62 float *c_row =
C + (size_t)i * (
size_t)N;
63 for (
int j = 0; j < N; ++j) {
64 const float *b_row = B + (size_t)j * (
size_t)K;
65 float sum = bias ? bias[j] : 0.0f;
66#if defined(__AVX512F__)
67 __m512 acc = _mm512_setzero_ps();
69 for (; k <= K - 16; k += 16) {
70 __m512 a_vec = _mm512_loadu_ps(a_row + k);
71 __m512 b_vec = _mm512_loadu_ps(b_row + k);
72 acc = _mm512_fmadd_ps(a_vec, b_vec, acc);
74 sum += _mm512_reduce_add_ps(acc);
76 sum += a_row[k] * b_row[k];
78#elif defined(__AVX2__)
79 __m256 acc = _mm256_setzero_ps();
81 for (; k <= K - 8; k += 8) {
82 __m256 a_vec = _mm256_loadu_ps(a_row + k);
83 __m256 b_vec = _mm256_loadu_ps(b_row + k);
85 acc = _mm256_fmadd_ps(a_vec, b_vec, acc);
87 acc = _mm256_add_ps(acc, _mm256_mul_ps(a_vec, b_vec));
90 sum += ck_train_hsum256_ps(acc);
92 sum += a_row[k] * b_row[k];
95 for (
int k = 0; k < K; ++k) {
96 sum += a_row[k] * b_row[k];
106 if (nth <= 1 || work_items == 0 || min_chunk == 0) {
109 size_t active = (work_items + min_chunk - 1u) / min_chunk;
113 if (active > (
size_t)nth) {
114 active = (size_t)nth;
120 ck_train_gemm_args_t *a = (ck_train_gemm_args_t *)argp;
121 if (!a || a->M <= 0 || a->N <= 0 || a->K <= 0) {
127 int dn = (a->N + nth - 1) / nth;
136 const int n_chunk = n1 - n0;
141 const float *B_chunk = a->B + (size_t)n0 * (
size_t)a->K;
142 const float *bias_chunk = a->bias ? (a->bias + n0) : NULL;
143 float *C_chunk = a->C + n0;
150 int dm = (a->M + nth - 1) / nth;
159 const int m_chunk = m1 - m0;
174 if (!A || !B || !
C || M <= 0 || N <= 0 || K <= 0) {
182 const size_t work = (size_t)M * (
size_t)N * (size_t)K;
183 if (!pool || nth <= 1 || work < (
size_t)131072) {
189 int active_nth = nth;
192 const int cols_per_worker = (N + nth - 1) / nth;
193 if (cols_per_worker >= 256 && K >= 512 && work >= (
size_t)2097152) {
202 if (active_nth > nth) {
205 if (active_nth <= 1) {
211 ck_train_gemm_args_t args = {
234} ck_train_gemm_nn_args_t;
244} ck_train_gemm_tn_args_t;
247 const float *d_output;
251} ck_train_bias_reduce_args_t;
254 const float *d_output;
260} ck_train_outer_t1_args_t;
263 const float *d_output;
272} ck_train_gemm_backward_args_t;
282 if (!A || !B || !
C || row_start >= row_end || N <= 0 || K <= 0) {
286 for (
int i = row_start; i < row_end; ++i) {
287 const float *a_row = A + (size_t)i * (
size_t)K;
288 float *c_row =
C + (size_t)i * (
size_t)N;
289#if defined(__AVX512F__)
291 for (; j <= N - 16; j += 16) {
292 __m512 sum = bias ? _mm512_loadu_ps(bias + j) : _mm512_setzero_ps();
293 for (
int k = 0; k < K; ++k) {
294 __m512 av = _mm512_set1_ps(a_row[k]);
295 __m512 bv = _mm512_loadu_ps(B + (
size_t)k * (
size_t)N + (
size_t)j);
296 sum = _mm512_fmadd_ps(av, bv, sum);
298 _mm512_storeu_ps(c_row + j, sum);
301 float sum = bias ? bias[j] : 0.0f;
302 for (
int k = 0; k < K; ++k) {
303 sum += a_row[k] * B[(size_t)k * (
size_t)N + (size_t)j];
307#elif defined(__AVX2__)
309 for (; j <= N - 8; j += 8) {
310 __m256 sum = bias ? _mm256_loadu_ps(bias + j) : _mm256_setzero_ps();
311 for (
int k = 0; k < K; ++k) {
312 __m256 av = _mm256_set1_ps(a_row[k]);
313 __m256 bv = _mm256_loadu_ps(B + (
size_t)k * (
size_t)N + (
size_t)j);
315 sum = _mm256_fmadd_ps(av, bv, sum);
317 sum = _mm256_add_ps(sum, _mm256_mul_ps(av, bv));
320 _mm256_storeu_ps(c_row + j, sum);
323 float sum = bias ? bias[j] : 0.0f;
324 for (
int k = 0; k < K; ++k) {
325 sum += a_row[k] * B[(size_t)k * (
size_t)N + (size_t)j];
330 for (
int j = 0; j < N; ++j) {
331 float sum = bias ? bias[j] : 0.0f;
332 for (
int k = 0; k < K; ++k) {
333 sum += a_row[k] * B[(size_t)k * (
size_t)N + (size_t)j];
350 if (!A || !B || !
C || row_start >= row_end || M <= 0 || N <= 0 || K <= 0) {
354 for (
int i = row_start; i < row_end; ++i) {
355 float *c_row =
C + (size_t)i * (
size_t)N;
356#if defined(__AVX512F__)
358 for (; j <= N - 16; j += 16) {
359 __m512 sum = bias ? _mm512_loadu_ps(bias + j) : _mm512_setzero_ps();
360 for (
int k = 0; k < K; ++k) {
361 __m512 av = _mm512_set1_ps(A[(
size_t)k * (
size_t)M + (
size_t)i]);
362 __m512 bv = _mm512_loadu_ps(B + (
size_t)k * (
size_t)N + (
size_t)j);
363 sum = _mm512_fmadd_ps(av, bv, sum);
365 _mm512_storeu_ps(c_row + j, sum);
368 float sum = bias ? bias[j] : 0.0f;
369 for (
int k = 0; k < K; ++k) {
370 sum += A[(size_t)k * (
size_t)M + (size_t)i] *
371 B[(
size_t)k * (size_t)N + (
size_t)j];
375#elif defined(__AVX2__)
377 for (; j <= N - 8; j += 8) {
378 __m256 sum = bias ? _mm256_loadu_ps(bias + j) : _mm256_setzero_ps();
379 for (
int k = 0; k < K; ++k) {
380 __m256 av = _mm256_set1_ps(A[(
size_t)k * (
size_t)M + (
size_t)i]);
381 __m256 bv = _mm256_loadu_ps(B + (
size_t)k * (
size_t)N + (
size_t)j);
383 sum = _mm256_fmadd_ps(av, bv, sum);
385 sum = _mm256_add_ps(sum, _mm256_mul_ps(av, bv));
388 _mm256_storeu_ps(c_row + j, sum);
391 float sum = bias ? bias[j] : 0.0f;
392 for (
int k = 0; k < K; ++k) {
393 sum += A[(size_t)k * (
size_t)M + (size_t)i] *
394 B[(
size_t)k * (size_t)N + (
size_t)j];
399 for (
int j = 0; j < N; ++j) {
400 float sum = bias ? bias[j] : 0.0f;
401 for (
int k = 0; k < K; ++k) {
402 sum += A[(size_t)k * (
size_t)M + (size_t)i] *
403 B[(
size_t)k * (size_t)N + (
size_t)j];
417 if (!d_output || !d_bias || T <= 0 || out_start >= out_end || aligned_out <= 0) {
421 for (
int out_idx = out_start; out_idx < out_end; ++out_idx) {
422 float bias_grad = 0.0f;
423 for (
int t = 0; t < T; ++t) {
424 bias_grad += d_output[(size_t)t * (
size_t)aligned_out + (size_t)out_idx];
426 d_bias[out_idx] += bias_grad;
437 if (!d_output || !input || !d_W || out_start >= out_end || aligned_in <= 0) {
441 for (
int out_idx = out_start; out_idx < out_end; ++out_idx) {
442 float g = d_output[out_idx];
446 float *dw_row = d_W + (size_t)out_idx * (
size_t)aligned_in;
447 for (
int j = 0; j < aligned_in; ++j) {
448 dw_row[j] = g * input[j];
470 ck_train_gemm_nn_args_t *a = (ck_train_gemm_nn_args_t *)argp;
471 if (!a || a->M <= 0 || a->N <= 0 || a->K <= 0) {
476 int dn = (a->N + nth - 1) / nth;
487 for (; j <= n1 - 8; j += 8) {
488 __m256 sum = a->bias ? _mm256_loadu_ps(a->bias + j) : _mm256_setzero_ps();
489 for (
int k = 0; k < a->K; ++k) {
490 __m256 av = _mm256_set1_ps(a->A[k]);
491 __m256 bv = _mm256_loadu_ps(a->B + (
size_t)k * (
size_t)a->N + (
size_t)j);
493 sum = _mm256_fmadd_ps(av, bv, sum);
495 sum = _mm256_add_ps(sum, _mm256_mul_ps(av, bv));
498 _mm256_storeu_ps(a->C + j, sum);
500 for (; j < n1; ++j) {
501 float sum = a->bias ? a->bias[j] : 0.0f;
502 for (
int k = 0; k < a->K; ++k) {
503 sum += a->A[k] * a->B[(size_t)k * (
size_t)a->N + (size_t)j];
508 for (
int j = n0; j < n1; ++j) {
509 float sum = a->bias ? a->bias[j] : 0.0f;
510 for (
int k = 0; k < a->K; ++k) {
511 sum += a->A[k] * a->B[(size_t)k * (
size_t)a->N + (size_t)j];
519 int dm = (a->M + nth - 1) / nth;
529 const int m_chunk = m1 - m0;
538 ck_train_outer_t1_args_t *a = (ck_train_outer_t1_args_t *)argp;
539 if (!a || a->aligned_in <= 0 || a->aligned_out <= 0) {
543 int dn = (a->aligned_out + nth - 1) / nth;
546 if (n0 >= a->aligned_out) {
549 if (n1 > a->aligned_out) {
557 ck_train_gemm_backward_args_t *a = (ck_train_gemm_backward_args_t *)argp;
558 if (!a || !a->d_output || !a->input || !a->W || !a->d_input || !a->d_W ||
559 a->T <= 0 || a->aligned_in <= 0 || a->aligned_out <= 0) {
563 int dt = (a->T + nth - 1) / nth;
581 int dn = (a->aligned_out + nth - 1) / nth;
584 if (n1 > a->aligned_out) {
620 if (!d_output || !input || !W || !d_input || !d_W) {
623 if (T <= 0 || aligned_in <= 0 || aligned_out <= 0) {
629 if (num_threads > 0 && num_threads < nth) {
633 if (!pool || nth <= 1) {
641 gemm_nn_simd(d_output, W, NULL, d_input, 1, aligned_in, aligned_out);
643 const size_t outer_work = (size_t)aligned_out * (
size_t)aligned_in;
644 if (aligned_out < nth * 2 || aligned_in < 64 || outer_work < (
size_t)524288) {
648 ck_train_outer_t1_args_t t1_args = {
649 .d_output = d_output,
653 .aligned_in = aligned_in,
654 .aligned_out = aligned_out,
656 if (active_outer <= 1) {
665 const size_t nn_work = (size_t)T * (
size_t)aligned_in * (size_t)aligned_out;
666 const size_t tn_work = (size_t)aligned_out * (
size_t)aligned_in * (size_t)T;
667 if ((T < 2 && aligned_out < nth * 2) || (nn_work < (size_t)131072 && tn_work < (
size_t)131072)) {
672 ck_train_gemm_backward_args_t bw_args = {
673 .d_output = d_output,
680 .aligned_in = aligned_in,
681 .aligned_out = aligned_out,
684 const size_t bw_rows = (size_t)aligned_out > (
size_t)T ? (size_t)aligned_out : (size_t)T;
686 if (active_bw <= 1) {
709 if (!d_output || !input || !W || !d_input || !d_W) {
712 if (T <= 0 || aligned_in <= 0 || aligned_out <= 0) {
718 if (num_threads > 0 && num_threads < nth) {
722 if (!pool || nth <= 1) {
728 const size_t nn_work = (size_t)aligned_in * (
size_t)aligned_out;
729 if (aligned_in >= nth * 32 && nn_work >= (
size_t)131072) {
731 ck_train_gemm_nn_args_t nn_args = {
741 if (active_nn <= 1) {
742 gemm_nn_simd(d_output, W, NULL, d_input, 1, aligned_in, aligned_out);
747 gemm_nn_simd(d_output, W, NULL, d_input, 1, aligned_in, aligned_out);
750 const size_t outer_work = (size_t)aligned_out * (
size_t)aligned_in;
751 if (aligned_out >= nth && outer_work >= (
size_t)131072) {
753 ck_train_outer_t1_args_t t1_args = {
754 .d_output = d_output,
758 .aligned_in = aligned_in,
759 .aligned_out = aligned_out,
761 if (active_outer <= 1) {
772 const size_t nn_work = (size_t)T * (
size_t)aligned_in * (size_t)aligned_out;
773 const size_t tn_work = (size_t)aligned_out * (
size_t)aligned_in * (size_t)T;
774 if ((T < nth && aligned_out < nth) || (nn_work < (size_t)131072 && tn_work < (
size_t)131072)) {
779 ck_train_gemm_backward_args_t bw_args = {
780 .d_output = d_output,
787 .aligned_in = aligned_in,
788 .aligned_out = aligned_out,
791 const size_t bw_rows = (size_t)aligned_out > (
size_t)T ? (size_t)aligned_out : (size_t)T;
793 if (active_bw <= 1) {
static void ck_train_bias_reduce_compute_range(const float *d_output, float *d_bias, int T, int out_start, int out_end, int aligned_out)
static void ck_train_gemm_tn_compute_rows(const float *A, const float *B, const float *bias, float *C, int row_start, int row_end, int M, int N, int K)
static void ck_train_outer_t1_compute_range(const float *d_output, const float *input, float *d_W, float *d_b, int out_start, int out_end, int aligned_in)
static void ck_train_gemm_backward_serial(const float *d_output, const float *input, const float *W, float *d_input, float *d_W, float *d_b, int T, int aligned_in, int aligned_out)
void gemm_blocked_serial_train_parallel_dispatch(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
void gemm_backward_f32_train_parallel_dispatch_v2(const float *d_output, const float *input, const float *W, float *d_input, float *d_W, float *d_b, int T, int aligned_in, int aligned_out, int num_threads)
static int ck_train_pick_active_threads(int nth, size_t work_items, size_t min_chunk)
static void ck_train_gemm_nn_work(int ith, int nth, void *argp)
static void ck_train_gemm_nt_compute_rows(const float *A, const float *B, const float *bias, float *C, int row_start, int row_end, int N, int K)
static void ck_train_gemm_nn_compute_rows(const float *A, const float *B, const float *bias, float *C, int row_start, int row_end, int N, int K)
static void ck_train_gemm_backward_work(int ith, int nth, void *argp)
static void ck_train_gemm_work(int ith, int nth, void *argp)
static void ck_train_outer_t1_work(int ith, int nth, void *argp)
void gemm_backward_f32_train_parallel_dispatch(const float *d_output, const float *input, const float *W, float *d_input, float *d_W, float *d_b, int T, int aligned_in, int aligned_out, int num_threads)
Persistent pthread thread pool for CK-Engine inference.
void ck_threadpool_dispatch_n(ck_threadpool_t *pool, int active_threads, ck_work_fn_t fn, void *args)
ck_threadpool_t * ck_threadpool_global(void)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
void gemm_nn_simd(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
void gemm_blocked_serial(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)