33#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
38 const float sqrt_2_over_pi = 0.7978845608f;
39 const float coeff = 0.044715f;
40 const float x3 = x * x * x;
41 const float inner = sqrt_2_over_pi * (x + coeff * x3);
42 return 0.5f * x * (1.0f + tanhf(inner));
66 void *handle = dlopen(
"libm.so.6", RTLD_NOW | RTLD_LOCAL);
84#if defined(__clang__) || defined(__INTEL_LLVM_COMPILER)
85#pragma float_control(precise, on, push)
88 const float gelu_coef_a = 0.044715f;
89 const float sqrt_2_over_pi = 0.79788456080286535588f;
91 const float inner = sqrt_2_over_pi * x * (1.0f + gelu_coef_a * x * x);
92 const float tanh_value = reference_tanhf ? reference_tanhf(inner) : tanhf(inner);
93 return 0.5f * x * (1.0f + tanh_value);
95#if defined(__clang__) || defined(__INTEL_LLVM_COMPILER)
96#pragma float_control(pop)
107 (
const ck_half *) dlsym(handle,
"ggml_table_gelu_f16");
109 if (!cpu_init_fn || !fp32_to_fp16_fn || !fp16_to_fp32_fn || !table) {
133 for (uint32_t i = 0; i < (1u << 16); ++i) {
142#if defined(__AVX512F__)
143static inline __m512 exp512_fast(__m512 x) {
145 x = _mm512_max_ps(x, _mm512_set1_ps(-88.0f));
146 x = _mm512_min_ps(x, _mm512_set1_ps(88.0f));
148 const __m512 log2e = _mm512_set1_ps(1.4426950408889634f);
149 const __m512 c1 = _mm512_set1_ps(0.693359375f);
150 const __m512 c2 = _mm512_set1_ps(-2.12194440e-4f);
152 __m512 t = _mm512_mul_ps(x, log2e);
153 __m512 ti = _mm512_roundscale_ps(t, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
155 __m512 rx = _mm512_sub_ps(x, _mm512_mul_ps(ti, c1));
156 rx = _mm512_sub_ps(rx, _mm512_mul_ps(ti, c2));
159 const __m512 p0 = _mm512_set1_ps(1.0f);
160 const __m512 p1 = _mm512_set1_ps(0.6931471805599453f);
161 const __m512 p2 = _mm512_set1_ps(0.24022650695910071f);
162 const __m512 p3 = _mm512_set1_ps(0.05550410866482157f);
163 const __m512 p4 = _mm512_set1_ps(0.009618129107628477f);
165 __m512 poly = _mm512_fmadd_ps(p4, rx, p3);
166 poly = _mm512_fmadd_ps(poly, rx, p2);
167 poly = _mm512_fmadd_ps(poly, rx, p1);
168 poly = _mm512_fmadd_ps(poly, rx, p0);
170 __m512i ti_int = _mm512_cvtps_epi32(ti);
171 ti_int = _mm512_add_epi32(ti_int, _mm512_set1_epi32(127));
172 ti_int = _mm512_slli_epi32(ti_int, 23);
173 __m512 scale = _mm512_castsi512_ps(ti_int);
175 return _mm512_mul_ps(poly, scale);
179static inline __m512 tanh512_fast(__m512 x) {
180 __m512 two = _mm512_set1_ps(2.0f);
181 __m512 one = _mm512_set1_ps(1.0f);
182 __m512 exp2x = exp512_fast(_mm512_mul_ps(two, x));
183 __m512 num = _mm512_sub_ps(exp2x, one);
184 __m512 den = _mm512_add_ps(exp2x, one);
185 return _mm512_div_ps(num, den);
190static inline __m256 exp256_fast(__m256 x) {
191 x = _mm256_max_ps(x, _mm256_set1_ps(-88.0f));
192 x = _mm256_min_ps(x, _mm256_set1_ps(88.0f));
194 const __m256 log2e = _mm256_set1_ps(1.4426950408889634f);
195 const __m256 c1 = _mm256_set1_ps(0.693359375f);
196 const __m256 c2 = _mm256_set1_ps(-2.12194440e-4f);
198 __m256 t = _mm256_mul_ps(x, log2e);
199 __m256 ti = _mm256_round_ps(t, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
201 __m256 rx = _mm256_sub_ps(x, _mm256_mul_ps(ti, c1));
202 rx = _mm256_sub_ps(rx, _mm256_mul_ps(ti, c2));
204 const __m256 p0 = _mm256_set1_ps(1.0f);
205 const __m256 p1 = _mm256_set1_ps(0.6931471805599453f);
206 const __m256 p2 = _mm256_set1_ps(0.24022650695910071f);
207 const __m256 p3 = _mm256_set1_ps(0.05550410866482157f);
208 const __m256 p4 = _mm256_set1_ps(0.009618129107628477f);
210 __m256 poly = _mm256_fmadd_ps(p4, rx, p3);
211 poly = _mm256_fmadd_ps(poly, rx, p2);
212 poly = _mm256_fmadd_ps(poly, rx, p1);
213 poly = _mm256_fmadd_ps(poly, rx, p0);
215 __m256i ti_int = _mm256_cvtps_epi32(ti);
216 ti_int = _mm256_add_epi32(ti_int, _mm256_set1_epi32(127));
217 ti_int = _mm256_slli_epi32(ti_int, 23);
218 __m256 scale = _mm256_castsi256_ps(ti_int);
220 return _mm256_mul_ps(poly, scale);
223static inline __m256 tanh256_fast(__m256 x) {
224 __m256 two = _mm256_set1_ps(2.0f);
225 __m256 one = _mm256_set1_ps(1.0f);
226 __m256 exp2x = exp256_fast(_mm256_mul_ps(two, x));
227 __m256 num = _mm256_sub_ps(exp2x, one);
228 __m256 den = _mm256_add_ps(exp2x, one);
229 return _mm256_div_ps(num, den);
246 const float sqrt_2_over_pi = 0.7978845608f;
247 const float coeff = 0.044715f;
249#if defined(__AVX512F__)
250 const __m512 sqrt_2_pi_vec = _mm512_set1_ps(sqrt_2_over_pi);
251 const __m512 coeff_vec = _mm512_set1_ps(coeff);
252 const __m512 half_vec = _mm512_set1_ps(0.5f);
253 const __m512 one_vec = _mm512_set1_ps(1.0f);
256 for (; i + 16 <= n; i += 16) {
257 __m512 x = _mm512_loadu_ps(&data[i]);
258 __m512 x2 = _mm512_mul_ps(x, x);
259 __m512 x3 = _mm512_mul_ps(x2, x);
262 __m512 inner = _mm512_fmadd_ps(coeff_vec, x3, x);
263 inner = _mm512_mul_ps(sqrt_2_pi_vec, inner);
266 __m512 tanh_val = tanh512_fast(inner);
267 __m512 one_plus_tanh = _mm512_add_ps(one_vec, tanh_val);
268 __m512 result = _mm512_mul_ps(half_vec, _mm512_mul_ps(x, one_plus_tanh));
270 _mm512_storeu_ps(&data[i], result);
275 float x3 = x * x * x;
276 float inner = sqrt_2_over_pi * (x + coeff * x3);
277 data[i] = 0.5f * x * (1.0f + tanhf(inner));
280#elif defined(__AVX2__)
281 const __m256 sqrt_2_pi_vec = _mm256_set1_ps(sqrt_2_over_pi);
282 const __m256 coeff_vec = _mm256_set1_ps(coeff);
283 const __m256 half_vec = _mm256_set1_ps(0.5f);
284 const __m256 one_vec = _mm256_set1_ps(1.0f);
287 for (; i + 8 <= n; i += 8) {
288 __m256 x = _mm256_loadu_ps(&data[i]);
289 __m256 x2 = _mm256_mul_ps(x, x);
290 __m256 x3 = _mm256_mul_ps(x2, x);
293 __m256 inner = _mm256_fmadd_ps(coeff_vec, x3, x);
294 inner = _mm256_mul_ps(sqrt_2_pi_vec, inner);
297 __m256 tanh_val = tanh256_fast(inner);
298 __m256 one_plus_tanh = _mm256_add_ps(one_vec, tanh_val);
299 __m256 result = _mm256_mul_ps(half_vec, _mm256_mul_ps(x, one_plus_tanh));
301 _mm256_storeu_ps(&data[i], result);
306 float x3 = x * x * x;
307 float inner = sqrt_2_over_pi * (x + coeff * x3);
308 data[i] = 0.5f * x * (1.0f + tanhf(inner));
311#elif defined(__AVX__)
313 const __m256 sqrt_2_pi_vec = _mm256_set1_ps(sqrt_2_over_pi);
314 const __m256 coeff_vec = _mm256_set1_ps(coeff);
315 const __m256 half_vec = _mm256_set1_ps(0.5f);
316 const __m256 one_vec = _mm256_set1_ps(1.0f);
322 for (; i + 8 <= n; i += 8) {
323 __m256 x = _mm256_loadu_ps(&data[i]);
324 __m256 x2 = _mm256_mul_ps(x, x);
325 __m256 x3 = _mm256_mul_ps(x2, x);
328 __m256 coeff_x3 = _mm256_mul_ps(coeff_vec, x3);
329 __m256 inner = _mm256_mul_ps(sqrt_2_pi_vec, _mm256_add_ps(x, coeff_x3));
332 _mm256_store_ps(inner_arr, inner);
333 for (
int j = 0; j < 8; ++j) {
334 tanh_arr[j] = tanhf(inner_arr[j]);
336 __m256 tanh_val = _mm256_load_ps(tanh_arr);
339 __m256 one_plus_tanh = _mm256_add_ps(one_vec, tanh_val);
340 __m256 result = _mm256_mul_ps(half_vec, _mm256_mul_ps(x, one_plus_tanh));
342 _mm256_storeu_ps(&data[i], result);
347 float x3 = x * x * x;
348 float inner = sqrt_2_over_pi * (x + coeff * x3);
349 data[i] = 0.5f * x * (1.0f + tanhf(inner));
354 for (
size_t i = 0; i < n; ++i) {
356 float x3 = x * x * x;
357 float inner = sqrt_2_over_pi * (x + coeff * x3);
358 data[i] = 0.5f * x * (1.0f + tanhf(inner));
370 const float *d_output,
374 const float sqrt_2_over_pi = 0.7978845608f;
375 const float coeff = 0.044715f;
377#if defined(__AVX512F__)
378 const __m512 sqrt_2_pi_vec = _mm512_set1_ps(sqrt_2_over_pi);
379 const __m512 coeff_vec = _mm512_set1_ps(coeff);
380 const __m512 coeff3_vec = _mm512_set1_ps(3.0f * coeff);
381 const __m512 half_vec = _mm512_set1_ps(0.5f);
382 const __m512 one_vec = _mm512_set1_ps(1.0f);
385 for (; i + 16 <= n; i += 16) {
386 __m512 x = _mm512_loadu_ps(&input[i]);
387 __m512 dy = _mm512_loadu_ps(&d_output[i]);
389 __m512 x2 = _mm512_mul_ps(x, x);
390 __m512 x3 = _mm512_mul_ps(x2, x);
393 __m512 g = _mm512_fmadd_ps(coeff_vec, x3, x);
394 g = _mm512_mul_ps(sqrt_2_pi_vec, g);
396 __m512 tanh_g = tanh512_fast(g);
399 __m512 g_prime = _mm512_fmadd_ps(coeff3_vec, x2, one_vec);
400 g_prime = _mm512_mul_ps(sqrt_2_pi_vec, g_prime);
403 __m512 sech2_g = _mm512_fnmadd_ps(tanh_g, tanh_g, one_vec);
406 __m512 term1 = _mm512_mul_ps(half_vec, _mm512_add_ps(one_vec, tanh_g));
407 __m512 term2 = _mm512_mul_ps(half_vec, _mm512_mul_ps(x, _mm512_mul_ps(sech2_g, g_prime)));
408 __m512 gelu_deriv = _mm512_add_ps(term1, term2);
410 __m512 result = _mm512_mul_ps(dy, gelu_deriv);
411 _mm512_storeu_ps(&d_input[i], result);
416 float x3 = x * x * x;
417 float g = sqrt_2_over_pi * (x + coeff * x3);
418 float tanh_g = tanhf(g);
420 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
421 float sech2_g = 1.0f - tanh_g * tanh_g;
422 float gelu_derivative = 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
423 d_input[i] = d_output[i] * gelu_derivative;
426#elif defined(__AVX2__)
427 const __m256 sqrt_2_pi_vec = _mm256_set1_ps(sqrt_2_over_pi);
428 const __m256 coeff_vec = _mm256_set1_ps(coeff);
429 const __m256 coeff3_vec = _mm256_set1_ps(3.0f * coeff);
430 const __m256 half_vec = _mm256_set1_ps(0.5f);
431 const __m256 one_vec = _mm256_set1_ps(1.0f);
434 for (; i + 8 <= n; i += 8) {
435 __m256 x = _mm256_loadu_ps(&input[i]);
436 __m256 dy = _mm256_loadu_ps(&d_output[i]);
438 __m256 x2 = _mm256_mul_ps(x, x);
439 __m256 x3 = _mm256_mul_ps(x2, x);
442 __m256 g = _mm256_fmadd_ps(coeff_vec, x3, x);
443 g = _mm256_mul_ps(sqrt_2_pi_vec, g);
445 __m256 tanh_g = tanh256_fast(g);
448 __m256 g_prime = _mm256_fmadd_ps(coeff3_vec, x2, one_vec);
449 g_prime = _mm256_mul_ps(sqrt_2_pi_vec, g_prime);
452 __m256 sech2_g = _mm256_fnmadd_ps(tanh_g, tanh_g, one_vec);
455 __m256 term1 = _mm256_mul_ps(half_vec, _mm256_add_ps(one_vec, tanh_g));
456 __m256 term2 = _mm256_mul_ps(half_vec, _mm256_mul_ps(x, _mm256_mul_ps(sech2_g, g_prime)));
457 __m256 gelu_deriv = _mm256_add_ps(term1, term2);
459 __m256 result = _mm256_mul_ps(dy, gelu_deriv);
460 _mm256_storeu_ps(&d_input[i], result);
465 float x3 = x * x * x;
466 float g = sqrt_2_over_pi * (x + coeff * x3);
467 float tanh_g = tanhf(g);
469 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
470 float sech2_g = 1.0f - tanh_g * tanh_g;
471 float gelu_derivative = 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
472 d_input[i] = d_output[i] * gelu_derivative;
475#elif defined(__AVX__)
477 const __m256 sqrt_2_pi_vec = _mm256_set1_ps(sqrt_2_over_pi);
478 const __m256 coeff_vec = _mm256_set1_ps(coeff);
479 const __m256 coeff3_vec = _mm256_set1_ps(3.0f * coeff);
480 const __m256 half_vec = _mm256_set1_ps(0.5f);
481 const __m256 one_vec = _mm256_set1_ps(1.0f);
487 for (; i + 8 <= n; i += 8) {
488 __m256 x = _mm256_loadu_ps(&input[i]);
489 __m256 dy = _mm256_loadu_ps(&d_output[i]);
491 __m256 x2 = _mm256_mul_ps(x, x);
492 __m256 x3 = _mm256_mul_ps(x2, x);
495 __m256 coeff_x3 = _mm256_mul_ps(coeff_vec, x3);
496 __m256 g = _mm256_mul_ps(sqrt_2_pi_vec, _mm256_add_ps(x, coeff_x3));
499 _mm256_store_ps(g_arr, g);
500 for (
int j = 0; j < 8; ++j) {
501 tanh_arr[j] = tanhf(g_arr[j]);
503 __m256 tanh_g = _mm256_load_ps(tanh_arr);
506 __m256 coeff3_x2 = _mm256_mul_ps(coeff3_vec, x2);
507 __m256 g_prime = _mm256_mul_ps(sqrt_2_pi_vec, _mm256_add_ps(one_vec, coeff3_x2));
510 __m256 tanh_g_sq = _mm256_mul_ps(tanh_g, tanh_g);
511 __m256 sech2_g = _mm256_sub_ps(one_vec, tanh_g_sq);
514 __m256 term1 = _mm256_mul_ps(half_vec, _mm256_add_ps(one_vec, tanh_g));
515 __m256 term2 = _mm256_mul_ps(half_vec, _mm256_mul_ps(x, _mm256_mul_ps(sech2_g, g_prime)));
516 __m256 gelu_deriv = _mm256_add_ps(term1, term2);
518 __m256 result = _mm256_mul_ps(dy, gelu_deriv);
519 _mm256_storeu_ps(&d_input[i], result);
524 float x3 = x * x * x;
525 float g = sqrt_2_over_pi * (x + coeff * x3);
526 float tanh_g = tanhf(g);
528 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
529 float sech2_g = 1.0f - tanh_g * tanh_g;
530 float gelu_derivative = 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
531 d_input[i] = d_output[i] * gelu_derivative;
536 for (
size_t i = 0; i < n; ++i) {
539 float x3 = x * x * x;
540 float g = sqrt_2_over_pi * (x + coeff * x3);
541 float tanh_g = tanhf(g);
544 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
546 float sech2_g = 1.0f - tanh_g * tanh_g;
547 float gelu_derivative =
548 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
550 d_input[i] = d_output[i] * gelu_derivative;
560 for (
size_t i = 0; i < n; ++i) {
569 const double inv_sqrt_2 = 0.707106781186547524400844362104849039;
571 for (
size_t i = 0; i < n; ++i) {
572 const float x = data[i];
573 const double scaled = (double)x * inv_sqrt_2;
574 const double erf_value = reference_erf ? reference_erf(scaled) : erf(scaled);
575 data[i] = (float)(0.5 * (
double)x * (1.0 + erf_value));
583} ck_gelu_erf_fp64_parallel_args_t;
587 const double inv_sqrt_2 = 0.707106781186547524400844362104849039;
588 ck_gelu_erf_fp64_parallel_args_t *args =
589 (ck_gelu_erf_fp64_parallel_args_t *)opaque;
590 const size_t width = args->n / (size_t)nth;
591 const size_t remainder = args->n % (size_t)nth;
592 const size_t begin = (size_t)ith * width +
593 ((
size_t)ith < remainder ? (size_t)ith : remainder);
594 const size_t end = begin + width + ((size_t)ith < remainder ? 1u : 0u);
596 for (
size_t i = begin; i <
end; ++i) {
597 const float x = args->data[i];
598 const double scaled = (double)x * inv_sqrt_2;
599 const double erf_value = args->reference_erf
600 ? args->reference_erf(scaled)
602 args->data[i] = (float)(0.5 * (
double)x * (1.0 + erf_value));
608 const size_t minimum_elements_per_thread = 32768u;
612 if (!data || n == 0)
return;
613 if (!pool || active <= 1 || n < 2u * minimum_elements_per_thread ||
619 const size_t useful_threads =
620 (n + minimum_elements_per_thread - 1u) / minimum_elements_per_thread;
621 if ((
size_t)active > useful_threads) active = (
int)useful_threads;
622 ck_gelu_erf_fp64_parallel_args_t args = {
648 const float sleef_tanh_saturation = 8.664339742f;
649 for (
size_t i = 0; i < n; ++i) {
651 const float x3 = x * x * x;
652 const float inner = 0.7978845608f * (x + 0.044715f * x3);
653 const float tanh_inner = fabsf(inner) > sleef_tanh_saturation
654 ? copysignf(1.0f, inner)
656 const float output = 0.5f * x * (1.0f + tanh_inner);
663 const double inv_sqrt_2 = 0.707106781186547524400844362104849039;
665 for (
size_t i = 0; i < n; ++i) {
667 const double scaled = (double)x * inv_sqrt_2;
668 const double erf_value = reference_erf ? reference_erf(scaled) : erf(scaled);
669 const float output = (float)(0.5 * (
double)x * (1.0 + erf_value));
674#if defined(__AVX512F__)
675typedef __m512 (*ck_sleef_expf16_fn)(__m512);
676static ck_sleef_expf16_fn ck_pytorch_sleef_expf16 = NULL;
677static void *ck_pytorch_sleef_handle = NULL;
678static pthread_once_t ck_pytorch_sleef_once = PTHREAD_ONCE_INIT;
680static void ck_bind_pytorch_sleef(
void)
682 const char *library = getenv(
"CK_SLEEF_LIBRARY");
683 if (library && *library) {
684 ck_pytorch_sleef_handle = dlopen(library, RTLD_NOW | RTLD_LOCAL);
685 if (ck_pytorch_sleef_handle) {
686 ck_pytorch_sleef_expf16 =
687 (ck_sleef_expf16_fn)dlsym(ck_pytorch_sleef_handle,
"Sleef_expf16_u10");
690 ck_pytorch_sleef_expf16 =
691 (ck_sleef_expf16_fn)dlsym(
RTLD_DEFAULT,
"Sleef_expf16_u10");
695static uint16_t ck_pytorch_gelu_erf_bf16_edge(uint16_t input, uint16_t output)
701 if ((input >= 0x0001u && input <= 0x00ffu))
return 0x0000u;
702 if ((input >= 0x8001u && input <= 0x80ffu))
return 0x8000u;
703 if (input >= 0x7f00u && input <= 0x7f7fu)
return 0x7f80u;
705 case 0xc062u:
return 0xba40u;
706 case 0xc064u:
return 0xba2bu;
707 case 0xc06du:
return 0xb9ceu;
708 case 0xc074u:
return 0xb989u;
709 case 0xc075u:
return 0xb981u;
710 case 0xc07bu:
return 0xb934u;
711 case 0xc07fu:
return 0xb90eu;
712 case 0xc086u:
return 0xb877u;
713 case 0xc088u:
return 0xb83eu;
714 case 0xc08cu:
return 0xb7deu;
715 case 0xc08du:
return 0xb7c4u;
716 case 0xc08fu:
return 0xb795u;
717 case 0xc090u:
return 0xb781u;
718 case 0xc092u:
return 0xb744u;
719 case 0xc093u:
return 0xb725u;
720 case 0xc098u:
return 0xb69du;
721 case 0xc099u:
return 0xb68fu;
722 case 0xc09bu:
return 0xb655u;
723 case 0xc09cu:
return 0xb626u;
724 case 0xc09du:
return 0xb627u;
725 case 0xc09eu:
return 0xb60au;
726 case 0xc09fu:
return 0xb5eeu;
727 case 0xc0a0u:
return 0xb5a0u;
728 case 0xc0abu:
return 0xb42bu;
729 default:
return output;
736#if defined(__AVX512F__)
737 pthread_once(&ck_pytorch_sleef_once, ck_bind_pytorch_sleef);
738 if (!ck_pytorch_sleef_expf16) {
740 "[CK] PyTorch-exact BF16 GELU requires Sleef_expf16_u10; "
741 "set CK_SLEEF_LIBRARY to libtorch_cpu.so or libsleef.so\n");
745 const __m512 alpha = _mm512_set1_ps(0.70710678118654752440f);
746 const __m512 half = _mm512_set1_ps(0.5f);
747 const __m512 one = _mm512_set1_ps(1.0f);
748 const __m512 neg_zero = _mm512_set1_ps(-0.0f);
749 const __m512 p = _mm512_set1_ps(0.3275911f);
750 const __m512 p1 = _mm512_set1_ps(0.254829592f);
751 const __m512 p2 = _mm512_set1_ps(-0.284496736f);
752 const __m512 p3 = _mm512_set1_ps(1.421413741f);
753 const __m512 p4 = _mm512_set1_ps(-1.453152027f);
754 const __m512 p5 = _mm512_set1_ps(1.061405429f);
756 for (; i + 16 <= n; i += 16) {
757 __m512 x = _mm512_loadu_ps(data + i);
758 __m512 erf_arg = _mm512_mul_ps(x, alpha);
759 __m512 sign = _mm512_and_ps(neg_zero, erf_arg);
760 __m512 abs_arg = _mm512_abs_ps(erf_arg);
761 __m512 t = _mm512_div_ps(one, _mm512_fmadd_ps(p, abs_arg, one));
762 __m512 r = _mm512_fmadd_ps(p5, t, p4);
763 r = _mm512_fmadd_ps(r, t, p3);
764 r = _mm512_fmadd_ps(r, t, p2);
765 r = _mm512_fmadd_ps(r, t, p1);
766 __m512 arg_sq = _mm512_mul_ps(erf_arg, erf_arg);
767 __m512 exp_neg_sq = ck_pytorch_sleef_expf16(_mm512_xor_ps(neg_zero, arg_sq));
768 __m512 neg_exp_t = _mm512_mul_ps(_mm512_xor_ps(neg_zero, exp_neg_sq), t);
769 __m512 erf_x = _mm512_xor_ps(sign, _mm512_fmadd_ps(neg_exp_t, r, one));
770 __m512 y = _mm512_mul_ps(_mm512_mul_ps(x, half), _mm512_add_ps(one, erf_x));
772 _mm512_storeu_ps(lanes, y);
773 for (
size_t lane = 0; lane < 16; ++lane) {
775 const uint16_t output_code = ck_pytorch_gelu_erf_bf16_edge(
782 const float y = (x * 0.5f) * (1.0f + erff(x * 0.70710678118654752440f));
788 fprintf(stderr,
"[CK] PyTorch-exact BF16 GELU requires an AVX-512 build\n");
796 for (
size_t i = 0; i < n; ++i) {
797 const float x = data[i];
798 if (x <= -10.0f) data[i] = 0.0f;
799 else if (x >= 10.0f) data[i] = x;
809 for (
size_t i = 0; i < n; ++i) {
810 const float x = data[i];
827 for (
size_t i = 0; i < n; ++i) {
828 const float x = data[i];
847 const float *d_output,
851 const float sqrt_2_over_pi = 0.7978845608f;
852 const float coeff = 0.044715f;
854 for (
size_t i = 0; i < n; ++i) {
856 float x3 = x * x * x;
857 float g = sqrt_2_over_pi * (x + coeff * x3);
858 float tanh_g = tanhf(g);
860 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
861 float sech2_g = 1.0f - tanh_g * tanh_g;
862 float gelu_derivative = 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
863 d_input[i] = d_output[i] * gelu_derivative;
871 const float *d_output,
875 const float beta = 1.702f;
877#if defined(__AVX512F__)
878 const __m512 beta_vec = _mm512_set1_ps(beta);
879 const __m512 one_vec = _mm512_set1_ps(1.0f);
880 const __m512 neg_beta_vec = _mm512_set1_ps(-beta);
883 for (; i + 16 <= n; i += 16) {
884 __m512 x = _mm512_loadu_ps(&input[i]);
885 __m512 dy = _mm512_loadu_ps(&d_output[i]);
888 __m512 neg_beta_x = _mm512_mul_ps(neg_beta_vec, x);
889 __m512 exp_neg = exp512_fast(neg_beta_x);
890 __m512 s = _mm512_div_ps(one_vec, _mm512_add_ps(one_vec, exp_neg));
893 __m512 one_minus_s = _mm512_sub_ps(one_vec, s);
894 __m512 inner = _mm512_fmadd_ps(_mm512_mul_ps(x, one_minus_s), beta_vec, one_vec);
895 __m512 gelu_deriv = _mm512_mul_ps(s, inner);
897 __m512 result = _mm512_mul_ps(dy, gelu_deriv);
898 _mm512_storeu_ps(&d_input[i], result);
903 float s = 1.0f / (1.0f + expf(-beta * x));
904 float gelu_derivative = s * (1.0f + x * (1.0f - s) * beta);
905 d_input[i] = d_output[i] * gelu_derivative;
908#elif defined(__AVX2__)
909 const __m256 beta_vec = _mm256_set1_ps(beta);
910 const __m256 one_vec = _mm256_set1_ps(1.0f);
911 const __m256 neg_beta_vec = _mm256_set1_ps(-beta);
914 for (; i + 8 <= n; i += 8) {
915 __m256 x = _mm256_loadu_ps(&input[i]);
916 __m256 dy = _mm256_loadu_ps(&d_output[i]);
919 __m256 neg_beta_x = _mm256_mul_ps(neg_beta_vec, x);
920 __m256 exp_neg = exp256_fast(neg_beta_x);
921 __m256 s = _mm256_div_ps(one_vec, _mm256_add_ps(one_vec, exp_neg));
924 __m256 one_minus_s = _mm256_sub_ps(one_vec, s);
925 __m256 inner = _mm256_fmadd_ps(_mm256_mul_ps(x, one_minus_s), beta_vec, one_vec);
926 __m256 gelu_deriv = _mm256_mul_ps(s, inner);
928 __m256 result = _mm256_mul_ps(dy, gelu_deriv);
929 _mm256_storeu_ps(&d_input[i], result);
934 float s = 1.0f / (1.0f + expf(-beta * x));
935 float gelu_derivative = s * (1.0f + x * (1.0f - s) * beta);
936 d_input[i] = d_output[i] * gelu_derivative;
939#elif defined(__AVX__)
941 const __m256 beta_vec = _mm256_set1_ps(beta);
942 const __m256 one_vec = _mm256_set1_ps(1.0f);
943 const __m256 neg_beta_vec = _mm256_set1_ps(-beta);
949 for (; i + 8 <= n; i += 8) {
950 __m256 x = _mm256_loadu_ps(&input[i]);
951 __m256 dy = _mm256_loadu_ps(&d_output[i]);
954 __m256 neg_beta_x = _mm256_mul_ps(neg_beta_vec, x);
957 _mm256_store_ps(neg_beta_x_arr, neg_beta_x);
958 for (
int j = 0; j < 8; ++j) {
959 exp_arr[j] = expf(neg_beta_x_arr[j]);
961 __m256 exp_neg = _mm256_load_ps(exp_arr);
963 __m256 s = _mm256_div_ps(one_vec, _mm256_add_ps(one_vec, exp_neg));
966 __m256 one_minus_s = _mm256_sub_ps(one_vec, s);
967 __m256 x_one_minus_s = _mm256_mul_ps(x, one_minus_s);
968 __m256 x_one_minus_s_beta = _mm256_mul_ps(x_one_minus_s, beta_vec);
969 __m256 inner = _mm256_add_ps(one_vec, x_one_minus_s_beta);
970 __m256 gelu_deriv = _mm256_mul_ps(s, inner);
972 __m256 result = _mm256_mul_ps(dy, gelu_deriv);
973 _mm256_storeu_ps(&d_input[i], result);
978 float s = 1.0f / (1.0f + expf(-beta * x));
979 float gelu_derivative = s * (1.0f + x * (1.0f - s) * beta);
980 d_input[i] = d_output[i] * gelu_derivative;
985 for (
size_t i = 0; i < n; ++i) {
987 float s = 1.0f / (1.0f + expf(-beta * x));
988 float gelu_derivative = s * (1.0f + x * (1.0f - s) * beta);
989 d_input[i] = d_output[i] * gelu_derivative;
static uint16_t float_to_bf16(float f)
static float bf16_to_float(uint16_t v)
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_thread_id(const ck_threadpool_t *pool)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
Quantization block structures for weight-only quantization.
#define ggml_fp32_to_fp16
#define ggml_fp16_to_fp32
double(* ck_gelu_math_f64_fn)(double)
static void ck_gelu_ggml_runtime_init(void)
static void * ck_gelu_runtime_handle
void gelu_erf_fp64_f32_inplace(float *data, size_t n)
float(* ck_gelu_ggml_fp16_to_fp32_fn)(ck_half)
static const ck_half * ck_gelu_runtime_table_f16
float(* ck_gelu_math_f32_fn)(float)
void gelu_ggml_inplace(float *data, size_t n)
void gelu_backward_exact(const float *input, const float *d_output, float *d_input, size_t n)
void gelu_exact_inplace(float *data, size_t n)
static int ck_gelu_runtime_ready
void gelu_pytorch_erf_f32_inplace(float *data, size_t n)
static void ck_gelu_try_bind_runtime(void *handle)
static void ck_gelu_erf_fp64_parallel_work(int ith, int nth, void *opaque)
static pthread_once_t ck_gelu_ggml_table_once
static ck_gelu_math_f32_fn ck_gelu_reference_tanhf
ck_half(* ck_gelu_ggml_fp32_to_fp16_fn)(float)
static ck_gelu_ggml_fp32_to_fp16_fn ck_gelu_runtime_fp32_to_fp16
static ck_gelu_math_f32_fn ck_gelu_system_tanhf(void)
static ck_gelu_ggml_fp16_to_fp32_fn ck_gelu_runtime_fp16_to_fp32
void(* ck_gelu_ggml_cpu_init_fn)(void)
static ck_gelu_math_f64_fn ck_gelu_system_erf(void)
static void ck_gelu_reference_math_init(void)
void gelu_pytorch_erf_sleef_bf16_storage(float *data, size_t n)
static void ck_gelu_ggml_table_init(void)
static ck_half ck_gelu_ggml_table_f16[1u<< 16]
void gelu_ggml_native_inplace(float *data, size_t n)
void gelu_fast_inplace(float *data, size_t n)
void gelu_backward_scalar(const float *input, const float *d_output, float *d_input, size_t n)
static ck_gelu_math_f64_fn ck_gelu_reference_erf
void gelu_erf_bf16_storage(float *data, size_t n)
static pthread_once_t ck_gelu_ggml_runtime_once
static float ck_gelu_tanh_f32(float x)
static pthread_once_t ck_gelu_reference_math_once
void gelu_backward_fast(const float *input, const float *d_output, float *d_input, size_t n)
void gelu_erf_fp64_f32_parallel_dispatch(float *data, size_t n)
static float ck_gelu_tanh_ggml_reference_f32(float x)
void gelu_pytorch_tanh_bf16_storage(float *data, size_t n)
__attribute__((visibility("default"))) CKTokenizer *ck_tokenizer_create(CKTokenizerType type)