Skip to content

Commit 267b2c9

Browse files
committed
kernels: degree-4 minimax exp in the sigmoid/tanh fast-exp helpers
fast_exp_sigmoid_{sse,avx,avx512,neon} used a truncated cubic Taylor (1 + r + r^2/2 + r^3/6, ~6e-4 relative error) while the standalone fast_exp uses a degree-4 minimax (~3e-6). Through the ~60 stacked SiLU activations of a YOLOv8-class backbone that bias compounds enough to shift detection confidences visibly: FastSAM-s top-1 conf came out 0.75 under yscv vs 0.93 under onnxruntime on an identical input. One extra FMA per lane upgrades all four variants to the same minimax coefficients as fast_exp; throughput change is negligible.
1 parent 9279702 commit 267b2c9

1 file changed

Lines changed: 29 additions & 13 deletions

File tree

  • crates/yscv-kernels/src/ops/simd

crates/yscv-kernels/src/ops/simd/exp.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,14 @@ pub(crate) unsafe fn fast_exp_sigmoid_sse(x: __m128) -> __m128 {
152152
let n_f = _mm_cvtepi32_ps(n_i);
153153
let r = _mm_sub_ps(x, _mm_mul_ps(n_f, _mm_set1_ps(std::f32::consts::LN_2)));
154154

155-
let mut poly = _mm_add_ps(_mm_set1_ps(0.5), _mm_mul_ps(r, _mm_set1_ps(1.0 / 6.0)));
156-
poly = _mm_add_ps(_mm_set1_ps(1.0), _mm_mul_ps(r, poly));
157-
poly = _mm_add_ps(_mm_set1_ps(1.0), _mm_mul_ps(r, poly));
155+
// minimax deg-4 — точность сигмоиды важна для conf-логитов (см. NEON)
156+
let mut poly = _mm_add_ps(
157+
_mm_set1_ps(0.167_781_98),
158+
_mm_mul_ps(r, _mm_set1_ps(0.041_894_704)),
159+
);
160+
poly = _mm_add_ps(_mm_set1_ps(0.499_990_85), _mm_mul_ps(r, poly));
161+
poly = _mm_add_ps(_mm_set1_ps(0.999_971_3), _mm_mul_ps(r, poly));
162+
poly = _mm_add_ps(_mm_set1_ps(1.000_000_1), _mm_mul_ps(r, poly));
158163

159164
let pow2n = {
160165
#[cfg(target_arch = "x86")]
@@ -261,12 +266,14 @@ pub(crate) unsafe fn fast_exp_sigmoid_avx(x: __m256) -> __m256 {
261266
_mm256_mul_ps(n_f, _mm256_set1_ps(std::f32::consts::LN_2)),
262267
);
263268

269+
// minimax deg-4 — точность сигмоиды важна для conf-логитов (см. NEON)
264270
let mut poly = _mm256_add_ps(
265-
_mm256_set1_ps(0.5),
266-
_mm256_mul_ps(r, _mm256_set1_ps(1.0 / 6.0)),
271+
_mm256_set1_ps(0.167_781_98),
272+
_mm256_mul_ps(r, _mm256_set1_ps(0.041_894_704)),
267273
);
268-
poly = _mm256_add_ps(_mm256_set1_ps(1.0), _mm256_mul_ps(r, poly));
269-
poly = _mm256_add_ps(_mm256_set1_ps(1.0), _mm256_mul_ps(r, poly));
274+
poly = _mm256_add_ps(_mm256_set1_ps(0.499_990_85), _mm256_mul_ps(r, poly));
275+
poly = _mm256_add_ps(_mm256_set1_ps(0.999_971_3), _mm256_mul_ps(r, poly));
276+
poly = _mm256_add_ps(_mm256_set1_ps(1.000_000_1), _mm256_mul_ps(r, poly));
270277

271278
let pow2n = {
272279
#[cfg(target_arch = "x86")]
@@ -355,9 +362,15 @@ pub(crate) unsafe fn fast_exp_sigmoid_avx512(x: __m512) -> __m512 {
355362
_mm512_mul_ps(n_f, _mm512_set1_ps(std::f32::consts::LN_2)),
356363
);
357364

358-
let mut poly = _mm512_fmadd_ps(r, _mm512_set1_ps(1.0 / 6.0), _mm512_set1_ps(0.5));
359-
poly = _mm512_fmadd_ps(r, poly, _mm512_set1_ps(1.0));
360-
poly = _mm512_fmadd_ps(r, poly, _mm512_set1_ps(1.0));
365+
// minimax deg-4 — точность сигмоиды важна для conf-логитов (см. NEON)
366+
let mut poly = _mm512_fmadd_ps(
367+
r,
368+
_mm512_set1_ps(0.041_894_704),
369+
_mm512_set1_ps(0.167_781_98),
370+
);
371+
poly = _mm512_fmadd_ps(r, poly, _mm512_set1_ps(0.499_990_85));
372+
poly = _mm512_fmadd_ps(r, poly, _mm512_set1_ps(0.999_971_3));
373+
poly = _mm512_fmadd_ps(r, poly, _mm512_set1_ps(1.000_000_1));
361374

362375
_mm512_scalef_ps(poly, n_f)
363376
}
@@ -425,9 +438,12 @@ pub(crate) unsafe fn fast_exp_sigmoid_neon(x: float32x4_t) -> float32x4_t {
425438
vmulq_f32(vcvtq_f32_s32(n_i), vdupq_n_f32(std::f32::consts::LN_2)),
426439
);
427440
let pow2n = vreinterpretq_f32_s32(vshlq_n_s32::<23>(vaddq_s32(n_i, vdupq_n_s32(127))));
428-
let p = vfmaq_f32(vdupq_n_f32(0.5), r, vdupq_n_f32(1.0 / 6.0));
429-
let p = vfmaq_f32(vdupq_n_f32(1.0), r, p);
430-
vmulq_f32(vfmaq_f32(vdupq_n_f32(1.0), r, p), pow2n)
441+
// minimax deg-4 (как fast_exp_neon): обрезанный кубический Тейлор давал
442+
// ~6e-4 отн. ошибки, что заметно копится через десятки SiLU-слоёв
443+
let p = vfmaq_f32(vdupq_n_f32(0.167_781_98), r, vdupq_n_f32(0.041_894_704));
444+
let p = vfmaq_f32(vdupq_n_f32(0.499_990_85), r, p);
445+
let p = vfmaq_f32(vdupq_n_f32(0.999_971_3), r, p);
446+
vmulq_f32(vfmaq_f32(vdupq_n_f32(1.000_000_1), r, p), pow2n)
431447
}
432448

433449
// ===========================================================================

0 commit comments

Comments
 (0)