@@ -1364,5 +1364,157 @@ class simd
13641364#endif
13651365 scalar_add_vectors (x, y, n, j);
13661366 }
1367+
1368+ // Scalar fallback for scale_vector
1369+ inline static void scalar_scale_vector (double * y, const double scale, size_t n, size_t start = 0 ) noexcept
1370+ {
1371+ for (size_t j = start; j < n; ++j)
1372+ {
1373+ y[j] *= scale;
1374+ }
1375+ }
1376+
1377+ // Vector-scalar multiplication (y *= scale)
1378+ inline static void scale_vector (double * y, const double scale, size_t n) noexcept
1379+ {
1380+ MYODDWEB_PROFILE_FUNCTION (" simd" );
1381+ size_t j = 0 ;
1382+ #ifdef SIMD_AVX2_ENABLED
1383+ __m256d vec_scale = _mm256_set1_pd (scale);
1384+ for (; j + 3 < n; j += 4 )
1385+ {
1386+ __m256d vec_y = _mm256_loadu_pd (y + j);
1387+ vec_y = _mm256_mul_pd (vec_y, vec_scale);
1388+ _mm256_storeu_pd (y + j, vec_y);
1389+ }
1390+ #endif
1391+ scalar_scale_vector (y, scale, n, j);
1392+ }
1393+
1394+ // Scalar fallback for sgd_step
1395+ inline static void scalar_sgd_step (
1396+ double * values,
1397+ double * grads,
1398+ double * velocities,
1399+ const double * decays,
1400+ double momentum,
1401+ double lr,
1402+ double clipping_scale,
1403+ bool is_bias,
1404+ size_t n,
1405+ size_t start = 0 ) noexcept
1406+ {
1407+ for (size_t i = start; i < n; ++i)
1408+ {
1409+ double grad = grads[i] * clipping_scale;
1410+ if (!is_bias && decays != nullptr && decays[i] > 0.0 )
1411+ {
1412+ grad += decays[i] * values[i];
1413+ }
1414+ double v = momentum * velocities[i] + grad;
1415+ values[i] -= lr * v;
1416+ velocities[i] = v;
1417+ grads[i] = grad;
1418+ }
1419+ }
1420+
1421+ // Vectorized SGD step
1422+ inline static void sgd_step (
1423+ double * values,
1424+ double * grads,
1425+ double * velocities,
1426+ const double * decays,
1427+ double momentum,
1428+ double lr,
1429+ double clipping_scale,
1430+ bool is_bias,
1431+ size_t n) noexcept
1432+ {
1433+ MYODDWEB_PROFILE_FUNCTION (" simd" );
1434+ size_t j = 0 ;
1435+ #ifdef SIMD_AVX2_ENABLED
1436+ __m256d vec_clip = _mm256_set1_pd (clipping_scale);
1437+ __m256d vec_momentum = _mm256_set1_pd (momentum);
1438+ __m256d vec_lr = _mm256_set1_pd (lr);
1439+
1440+ for (; j + 3 < n; j += 4 )
1441+ {
1442+ __m256d g = _mm256_loadu_pd (&grads[j]);
1443+ __m256d cur_w = _mm256_loadu_pd (&values[j]);
1444+ __m256d cur_v = _mm256_loadu_pd (&velocities[j]);
1445+
1446+ __m256d grad = _mm256_mul_pd (g, vec_clip);
1447+
1448+ if (!is_bias && decays != nullptr )
1449+ {
1450+ __m256d d = _mm256_loadu_pd (&decays[j]);
1451+ #ifdef SIMD_FMA_ENABLED
1452+ grad = _mm256_fmadd_pd (d, cur_w, grad);
1453+ #else
1454+ grad = _mm256_add_pd (grad, _mm256_mul_pd (d, cur_w));
1455+ #endif
1456+ }
1457+
1458+ #ifdef SIMD_FMA_ENABLED
1459+ __m256d next_v = _mm256_fmadd_pd (vec_momentum, cur_v, grad);
1460+ #else
1461+ __m256d next_v = _mm256_add_pd (_mm256_mul_pd (vec_momentum, cur_v), grad);
1462+ #endif
1463+
1464+ __m256d next_w = _mm256_sub_pd (cur_w, _mm256_mul_pd (vec_lr, next_v));
1465+
1466+ _mm256_storeu_pd (&velocities[j], next_v);
1467+ _mm256_storeu_pd (&values[j], next_w);
1468+ _mm256_storeu_pd (&grads[j], grad);
1469+ }
1470+ #endif
1471+ scalar_sgd_step (values, grads, velocities, decays, momentum, lr, clipping_scale, is_bias, n, j);
1472+ }
1473+
1474+ // Scalar fallback for none_step
1475+ inline static void scalar_none_step (
1476+ double * values,
1477+ double * grads,
1478+ double lr,
1479+ double clipping_scale,
1480+ size_t n,
1481+ size_t start = 0 ) noexcept
1482+ {
1483+ for (size_t i = start; i < n; ++i)
1484+ {
1485+ double grad = grads[i] * clipping_scale;
1486+ values[i] -= lr * grad;
1487+ grads[i] = grad;
1488+ }
1489+ }
1490+
1491+ // Vectorized None step (plain SGD without momentum)
1492+ inline static void none_step (
1493+ double * values,
1494+ double * grads,
1495+ double lr,
1496+ double clipping_scale,
1497+ size_t n) noexcept
1498+ {
1499+ MYODDWEB_PROFILE_FUNCTION (" simd" );
1500+ size_t j = 0 ;
1501+ #ifdef SIMD_AVX2_ENABLED
1502+ __m256d vec_clip = _mm256_set1_pd (clipping_scale);
1503+ __m256d vec_lr = _mm256_set1_pd (lr);
1504+
1505+ for (; j + 3 < n; j += 4 )
1506+ {
1507+ __m256d g = _mm256_loadu_pd (&grads[j]);
1508+ __m256d cur_w = _mm256_loadu_pd (&values[j]);
1509+
1510+ __m256d grad = _mm256_mul_pd (g, vec_clip);
1511+ __m256d next_w = _mm256_sub_pd (cur_w, _mm256_mul_pd (vec_lr, grad));
1512+
1513+ _mm256_storeu_pd (&values[j], next_w);
1514+ _mm256_storeu_pd (&grads[j], grad);
1515+ }
1516+ #endif
1517+ scalar_none_step (values, grads, lr, clipping_scale, n, j);
1518+ }
13671519};
13681520} // namespace myoddweb::nn
0 commit comments