110 float lr,
float lambda,
111 float beta1 = 0.9f,
float beta2 = 0.999f,
float eps = 1e-8f) noexcept
117 const float beta1_t = 1.0f - Sleef_powf_u10(beta1, (
float)t);
118 const float beta2_t = 1.0f - Sleef_powf_u10(beta2, (
float)t);
119 const float inv_beta1_t = 1.0f / beta1_t;
120 const float inv_beta2_t = 1.0f / beta2_t;
122#if defined(__AVX512F__)
123 __m512 beta1_v = _mm512_set1_ps(beta1);
124 __m512 one_minus_beta1 = _mm512_set1_ps(1.0f - beta1);
125 __m512 beta2_v = _mm512_set1_ps(beta2);
126 __m512 one_minus_beta2 = _mm512_set1_ps(1.0f - beta2);
127 __m512 inv_beta1_t_v = _mm512_set1_ps(inv_beta1_t);
128 __m512 inv_beta2_t_v = _mm512_set1_ps(inv_beta2_t);
129 __m512 lr_v = _mm512_set1_ps(lr);
130 __m512 eps_v = _mm512_set1_ps(eps);
131 __m512 decay_v = _mm512_set1_ps(1.0f - lr * lambda);
134 size_t simd_end = n - r;
135#pragma omp parallel for schedule(static) if(n >= 4096 && !omp_in_parallel())
136 for (ptrdiff_t i=0; i < (ptrdiff_t)simd_end; i += 16)
138 __m512 g = _mm512_loadu_ps(&grad[i]);
139 __m512 m_old = _mm512_loadu_ps(&m[i]);
140 __m512 v_old = _mm512_loadu_ps(&v[i]);
142 __m512 m_new = _mm512_fmadd_ps(beta1_v, m_old, _mm512_mul_ps(one_minus_beta1, g));
143 __m512 v_new = _mm512_fmadd_ps(beta2_v, v_old, _mm512_mul_ps(one_minus_beta2, _mm512_mul_ps(g, g)));
145 __m512 m_hat = _mm512_mul_ps(m_new, inv_beta1_t_v);
146 __m512 v_hat = _mm512_mul_ps(v_new, inv_beta2_t_v);
148 __m512 denom = _mm512_add_ps(_mm512_sqrt_ps(v_hat), eps_v);
149 __m512 step = _mm512_div_ps(_mm512_mul_ps(lr_v, m_hat), denom);
151 __m512 w_old = _mm512_loadu_ps(&w[i]);
154 __m512 w_new = _mm512_sub_ps(_mm512_mul_ps(w_old, decay_v), step);
156 _mm512_storeu_ps(&w[i], w_new);
157 _mm512_storeu_ps(&m[i], m_new);
158 _mm512_storeu_ps(&v[i], v_new);
160#elif defined(__AVX2__) || defined(__AVX__)
161 __m256 beta1_v = _mm256_set1_ps(beta1);
162 __m256 one_minus_beta1 = _mm256_set1_ps(1.0f - beta1);
163 __m256 beta2_v = _mm256_set1_ps(beta2);
164 __m256 one_minus_beta2 = _mm256_set1_ps(1.0f - beta2);
165 __m256 inv_beta1_t_v = _mm256_set1_ps(inv_beta1_t);
166 __m256 inv_beta2_t_v = _mm256_set1_ps(inv_beta2_t);
167 __m256 lr_v = _mm256_set1_ps(lr);
168 __m256 eps_v = _mm256_set1_ps(eps);
169 __m256 decay_v = _mm256_set1_ps(1.0f - lr * lambda);
172 size_t simd_end = n - r;
173#pragma omp parallel for schedule(static) if(n >= 4096 && !omp_in_parallel())
174 for (ptrdiff_t i=0; i < (ptrdiff_t)simd_end; i += 8)
176 __m256 g = _mm256_loadu_ps(&grad[i]);
177 __m256 m_old = _mm256_loadu_ps(&m[i]);
178 __m256 v_old = _mm256_loadu_ps(&v[i]);
181 __m256 m_new = _mm256_fmadd_ps(beta1_v, m_old, _mm256_mul_ps(one_minus_beta1, g));
182 __m256 v_new = _mm256_fmadd_ps(beta2_v, v_old, _mm256_mul_ps(one_minus_beta2, _mm256_mul_ps(g, g)));
184 __m256 m_new = _mm256_add_ps(_mm256_mul_ps(beta1_v, m_old), _mm256_mul_ps(one_minus_beta1, g));
185 __m256 v_new = _mm256_add_ps(_mm256_mul_ps(beta2_v, v_old), _mm256_mul_ps(one_minus_beta2, _mm256_mul_ps(g, g)));
188 __m256 m_hat = _mm256_mul_ps(m_new, inv_beta1_t_v);
189 __m256 v_hat = _mm256_mul_ps(v_new, inv_beta2_t_v);
191 __m256 denom = _mm256_add_ps(_mm256_sqrt_ps(v_hat), eps_v);
192 __m256 step = _mm256_div_ps(_mm256_mul_ps(lr_v, m_hat), denom);
194 __m256 w_old = _mm256_loadu_ps(&w[i]);
195 __m256 w_new = _mm256_sub_ps(_mm256_mul_ps(w_old, decay_v), step);
197 _mm256_storeu_ps(&w[i], w_new);
198 _mm256_storeu_ps(&m[i], m_new);
199 _mm256_storeu_ps(&v[i], v_new);
201#elif defined(__SSE__) || defined(_M_AMD64) || defined(_M_X64)
202 __m128 beta1_v = _mm_set1_ps(beta1);
203 __m128 one_minus_beta1 = _mm_set1_ps(1.0f - beta1);
204 __m128 beta2_v = _mm_set1_ps(beta2);
205 __m128 one_minus_beta2 = _mm_set1_ps(1.0f - beta2);
206 __m128 inv_beta1_t_v = _mm_set1_ps(inv_beta1_t);
207 __m128 inv_beta2_t_v = _mm_set1_ps(inv_beta2_t);
208 __m128 lr_v = _mm_set1_ps(lr);
209 __m128 eps_v = _mm_set1_ps(eps);
210 __m128 decay_v = _mm_set1_ps(1.0f - lr * lambda);
213 size_t simd_end = n - r;
214#pragma omp parallel for schedule(static) if(n >= 4096 && !omp_in_parallel())
215 for (ptrdiff_t i=0; i < (ptrdiff_t)simd_end; i += 4)
217 __m128 g = _mm_loadu_ps(&grad[i]);
218 __m128 m_old = _mm_loadu_ps(&m[i]);
219 __m128 v_old = _mm_loadu_ps(&v[i]);
222 __m128 m_new = _mm_fmadd_ps(beta1_v, m_old, _mm_mul_ps(one_minus_beta1, g));
223 __m128 v_new = _mm_fmadd_ps(beta2_v, v_old, _mm_mul_ps(one_minus_beta2, _mm_mul_ps(g, g)));
225 __m128 m_new = _mm_add_ps(_mm_mul_ps(beta1_v, m_old), _mm_mul_ps(one_minus_beta1, g));
226 __m128 v_new = _mm_add_ps(_mm_mul_ps(beta2_v, v_old), _mm_mul_ps(one_minus_beta2, _mm_mul_ps(g, g)));
229 __m128 m_hat = _mm_mul_ps(m_new, inv_beta1_t_v);
230 __m128 v_hat = _mm_mul_ps(v_new, inv_beta2_t_v);
232 __m128 denom = _mm_add_ps(_mm_sqrt_ps(v_hat), eps_v);
233 __m128 step = _mm_div_ps(_mm_mul_ps(lr_v, m_hat), denom);
235 __m128 w_old = _mm_loadu_ps(&w[i]);
236 __m128 w_new = _mm_sub_ps(_mm_mul_ps(w_old, decay_v), step);
238 _mm_storeu_ps(&w[i], w_new);
239 _mm_storeu_ps(&m[i], m_new);
240 _mm_storeu_ps(&v[i], v_new);
244 float decay = 1.0f - lr * lambda;
245#if !defined(__AVX512F__) && !defined(__AVX2__) && !defined(__AVX__) && !defined(__SSE__) && !defined(_M_AMD64) && !defined(_M_X64)
246 #pragma omp parallel for schedule(static) if(n >= 4096 && !omp_in_parallel())
248 for (ptrdiff_t i=simd_end; i < (ptrdiff_t)n; ++i)
251 m[i] = beta1 * m[i] + (1.0f - beta1) * g;
252 v[i] = beta2 * v[i] + (1.0f - beta2) * g * g;
254 float m_hat = m[i] * inv_beta1_t;
255 float v_hat = v[i] * inv_beta2_t;
257 w[i] = w[i] * decay - lr * m_hat / (Sleef_sqrtf_u05(v_hat) + eps);
299 float beta1 = 0.9f,
float beta2 = 0.999f,
float eps = 1e-8f) noexcept
301 const float beta1_t = 1.0f - Sleef_powf_u10(beta1, (
float)t);
302 const float beta2_t = 1.0f - Sleef_powf_u10(beta2, (
float)t);
303 const float inv_beta1_t = 1.0f / beta1_t;
304 const float inv_beta2_t = 1.0f / beta2_t;
306#if defined(__AVX512F__)
307 __m512 beta1_v = _mm512_set1_ps(beta1);
308 __m512 one_minus_beta1 = _mm512_set1_ps(1.0f - beta1);
309 __m512 beta2_v = _mm512_set1_ps(beta2);
310 __m512 one_minus_beta2 = _mm512_set1_ps(1.0f - beta2);
311 __m512 inv_beta1_t_v = _mm512_set1_ps(inv_beta1_t);
312 __m512 inv_beta2_t_v = _mm512_set1_ps(inv_beta2_t);
313 __m512 lr_v = _mm512_set1_ps(lr);
314 __m512 eps_v = _mm512_set1_ps(eps);
317 size_t simd_end = n - r;
318#pragma omp parallel for schedule(static) if(n >= 4096 && !omp_in_parallel())
319 for (ptrdiff_t i=0; i < (ptrdiff_t)simd_end; i += 16)
321 __m512 g = _mm512_loadu_ps(&grad[i]);
322 __m512 m_old = _mm512_loadu_ps(&m[i]);
323 __m512 v_old = _mm512_loadu_ps(&v[i]);
325 __m512 m_new = _mm512_fmadd_ps(beta1_v, m_old, _mm512_mul_ps(one_minus_beta1, g));
326 __m512 v_new = _mm512_fmadd_ps(beta2_v, v_old, _mm512_mul_ps(one_minus_beta2, _mm512_mul_ps(g, g)));
328 __m512 m_hat = _mm512_mul_ps(m_new, inv_beta1_t_v);
329 __m512 v_hat = _mm512_mul_ps(v_new, inv_beta2_t_v);
331 __m512 denom = _mm512_add_ps(_mm512_sqrt_ps(v_hat), eps_v);
332 __m512 step = _mm512_div_ps(_mm512_mul_ps(lr_v, m_hat), denom);
334 __m512 w_old = _mm512_loadu_ps(&w[i]);
335 __m512 w_new = _mm512_sub_ps(w_old, step);
337 _mm512_storeu_ps(&w[i], w_new);
338 _mm512_storeu_ps(&m[i], m_new);
339 _mm512_storeu_ps(&v[i], v_new);
341#elif defined(__AVX2__) || defined(__AVX__)
342 __m256 beta1_v = _mm256_set1_ps(beta1);
343 __m256 one_minus_beta1 = _mm256_set1_ps(1.0f - beta1);
344 __m256 beta2_v = _mm256_set1_ps(beta2);
345 __m256 one_minus_beta2 = _mm256_set1_ps(1.0f - beta2);
346 __m256 inv_beta1_t_v = _mm256_set1_ps(inv_beta1_t);
347 __m256 inv_beta2_t_v = _mm256_set1_ps(inv_beta2_t);
348 __m256 lr_v = _mm256_set1_ps(lr);
349 __m256 eps_v = _mm256_set1_ps(eps);
352 size_t simd_end = n - r;
353#pragma omp parallel for schedule(static) if(n >= 4096 && !omp_in_parallel())
354 for (ptrdiff_t i=0; i < (ptrdiff_t)simd_end; i += 8)
356 __m256 g = _mm256_loadu_ps(&grad[i]);
357 __m256 m_old = _mm256_loadu_ps(&m[i]);
358 __m256 v_old = _mm256_loadu_ps(&v[i]);
361 __m256 m_new = _mm256_fmadd_ps(beta1_v, m_old, _mm256_mul_ps(one_minus_beta1, g));
362 __m256 v_new = _mm256_fmadd_ps(beta2_v, v_old, _mm256_mul_ps(one_minus_beta2, _mm256_mul_ps(g, g)));
364 __m256 m_new = _mm256_add_ps(_mm256_mul_ps(beta1_v, m_old), _mm256_mul_ps(one_minus_beta1, g));
365 __m256 v_new = _mm256_add_ps(_mm256_mul_ps(beta2_v, v_old), _mm256_mul_ps(one_minus_beta2, _mm256_mul_ps(g, g)));
368 __m256 m_hat = _mm256_mul_ps(m_new, inv_beta1_t_v);
369 __m256 v_hat = _mm256_mul_ps(v_new, inv_beta2_t_v);
371 __m256 denom = _mm256_add_ps(_mm256_sqrt_ps(v_hat), eps_v);
372 __m256 step = _mm256_div_ps(_mm256_mul_ps(lr_v, m_hat), denom);
374 __m256 w_old = _mm256_loadu_ps(&w[i]);
375 __m256 w_new = _mm256_sub_ps(w_old, step);
377 _mm256_storeu_ps(&w[i], w_new);
378 _mm256_storeu_ps(&m[i], m_new);
379 _mm256_storeu_ps(&v[i], v_new);
381#elif defined(__SSE__) || defined(_M_AMD64) || defined(_M_X64)
382 __m128 beta1_v = _mm_set1_ps(beta1);
383 __m128 one_minus_beta1 = _mm_set1_ps(1.0f - beta1);
384 __m128 beta2_v = _mm_set1_ps(beta2);
385 __m128 one_minus_beta2 = _mm_set1_ps(1.0f - beta2);
386 __m128 inv_beta1_t_v = _mm_set1_ps(inv_beta1_t);
387 __m128 inv_beta2_t_v = _mm_set1_ps(inv_beta2_t);
388 __m128 lr_v = _mm_set1_ps(lr);
389 __m128 eps_v = _mm_set1_ps(eps);
392 size_t simd_end = n - r;
393#pragma omp parallel for schedule(static) if(n >= 4096 && !omp_in_parallel())
394 for (ptrdiff_t i=0; i < (ptrdiff_t)simd_end; i += 4)
396 __m128 g = _mm_loadu_ps(&grad[i]);
397 __m128 m_old = _mm_loadu_ps(&m[i]);
398 __m128 v_old = _mm_loadu_ps(&v[i]);
401 __m128 m_new = _mm_fmadd_ps(beta1_v, m_old, _mm_mul_ps(one_minus_beta1, g));
402 __m128 v_new = _mm_fmadd_ps(beta2_v, v_old, _mm_mul_ps(one_minus_beta2, _mm_mul_ps(g, g)));
404 __m128 m_new = _mm_add_ps(_mm_mul_ps(beta1_v, m_old), _mm_mul_ps(one_minus_beta1, g));
405 __m128 v_new = _mm_add_ps(_mm_mul_ps(beta2_v, v_old), _mm_mul_ps(one_minus_beta2, _mm_mul_ps(g, g)));
408 __m128 m_hat = _mm_mul_ps(m_new, inv_beta1_t_v);
409 __m128 v_hat = _mm_mul_ps(v_new, inv_beta2_t_v);
411 __m128 denom = _mm_add_ps(_mm_sqrt_ps(v_hat), eps_v);
412 __m128 step = _mm_div_ps(_mm_mul_ps(lr_v, m_hat), denom);
414 __m128 w_old = _mm_loadu_ps(&w[i]);
415 __m128 w_new = _mm_sub_ps(w_old, step);
417 _mm_storeu_ps(&w[i], w_new);
418 _mm_storeu_ps(&m[i], m_new);
419 _mm_storeu_ps(&v[i], v_new);
422#if !defined(__AVX512F__) && !defined(__AVX2__) && !defined(__AVX__) && !defined(__SSE__) && !defined(_M_AMD64) && !defined(_M_X64)
423 #pragma omp parallel for schedule(static) if(n >= 4096 && !omp_in_parallel())
425 for (ptrdiff_t i=simd_end; i < (ptrdiff_t)n; ++i)
428 m[i] = beta1 * m[i] + (1.0f - beta1) * g;
429 v[i] = beta2 * v[i] + (1.0f - beta2) * g * g;
431 float m_hat = m[i] * inv_beta1_t;
432 float v_hat = v[i] * inv_beta2_t;
434 w[i] -= lr * m_hat / (Sleef_sqrtf_u05(v_hat) + eps);