Численные методы оптимизации в машинном обучении: от теории к реализации

Углубленный курс по математическим основам и программной реализации алгоритмов обучения. Слушатели изучат строгий вывод методов оптимизации, анализ их сходимости и специфику работы с вычислительными ошибками в современных ML-системах.

1. Основы численного анализа, компьютерная арифметика и природа ошибок вычислений

Основы численного анализа, компьютерная арифметика и природа ошибок вычислений

Представьте, что вы обучаете глубокую нейронную сеть в течение нескольких недель на дорогостоящем кластере GPU. На миллионной итерации градиент внезапно превращается в NaN (Not a Number), или веса модели застывают, хотя функция потерь еще далека от минимума. Часто причина кроется не в архитектуре сети или плохих данных, а в фундаментальном ограничении вычислительной техники: компьютеры не умеют работать с вещественными числами. Они работают лишь с их дискретными аппроксимациями. В мире численной оптимизации разница между математическим идеалом и машинной реальностью — это не просто погрешность, а фактор, определяющий сходимость алгоритма и стабильность всей системы.

Анатомия машинного числа: стандарт IEEE 754

Математическая прямая непрерывна и бесконечна. Память компьютера конечна и дискретна. Чтобы представить число в цифровом виде, мы используем стандарт IEEE 754, который определяет формат чисел с плавающей точкой (floating-point).

Любое число в этой системе представляется в виде:

Где:

  • — знаковый бит (0 для положительных, 1 для отрицательных).
  • — мантисса (дробная часть), определяющая точность числа.
  • — основание системы счисления (в компьютерах ).
  • — экспонента (порядок), определяющая диапазон числа.
  • В машинном обучении мы чаще всего сталкиваемся с форматами float32 (Single Precision) и float64 (Double Precision), а в последнее время — с float16 и bfloat16 для ускорения обучения нейросетей.

    | Формат | Биты (S+E+M) | Значащие десятичные цифры | Диапазон (прибл.) | | :--- | :--- | :--- | :--- | | float16 | 1 + 5 + 10 | ~3.3 | | | bfloat16| 1 + 8 + 7 | ~2.1 | | | float32 | 1 + 8 + 23 | ~7.2 | | | float64 | 1 + 11 + 52 | ~15.9 | |

    Обратите внимание на bfloat16 (Brain Floating Point). У него такая же экспонента, как у float32, но гораздо более короткая мантисса. Это позволяет сохранять широкий динамический диапазон (важно для градиентов), жертвуя точностью отдельных значений.

    Машинный эпсилон и относительная точность

    Ключевым понятием численного анализа является машинный эпсилон ( или ). Это наименьшее положительное число, такое что:

    Для float32 , для float64 . Это означает, что если вы пытаетесь прибавить к единице число, которое меньше , результат в компьютерной логике останется равным . В контексте оптимизации это ставит предел точности, с которой мы можем найти минимум функции.

    Источники и классификация ошибок

    Ошибки в численных методах неизбежны, но их можно и нужно контролировать. Мы разделяем их на три основных типа:

  • Неустранимая ошибка (Inherent Error): Ошибка во входных данных (шум в датасете, погрешность измерений датчиков). Алгоритм оптимизации не может её исправить, он лишь переносит её на результат.
  • Ошибка метода (Truncation Error): Возникает из-за замены бесконечного процесса конечным. Например, когда мы заменяем бесконечный ряд Тейлора первыми двумя слагаемыми для вычисления градиента или когда останавливаем итерационный процесс оптимизации по достижении порога точности.
  • Ошибка округления (Rounding Error): Следствие использования формата IEEE 754. Каждая арифметическая операция порождает микроскопическую ошибку, которая может накапливаться.
  • Потеря значимости (Catastrophic Cancellation)

    Самый опасный вид ошибки округления в оптимизации — это вычитание двух близких по величине чисел. Рассмотрим вычисление производной через конечные разности:

    Математически, чем меньше , тем точнее результат. Однако численно, если слишком мало, значения и становятся почти идентичными. При их вычитании старшие разряды мантиссы обнуляются, и в результате остаются только случайные «хвосты» — ошибки округления, которые затем делятся на крошечное , превращаясь в гигантский шум.

    Исчезновение и взрыв градиентов (Underflow & Overflow)

    В глубоком обучении мы часто перемножаем длинные последовательности чисел (например, при обратном распространении ошибки через множество слоев).

  • Если среднее значение весов и градиентов , то произведение стремится к нулю быстрее, чем его может зафиксировать формат (Underflow). Градиент становится нулем, обучение останавливается.
  • Если , произведение уходит в бесконечность (Overflow), вызывая NaN.
  • Обусловленность задач и устойчивость алгоритмов

    Почему одни функции оптимизируются легко, а другие заставляют алгоритм «блуждать»? Ответ кроется в понятии обусловленности.

    Число обусловленности (Condition Number) задачи характеризует чувствительность решения к малым изменениям входных данных. Для функции относительное число обусловленности определяется как:

    Если велико, задача называется плохо обусловленной. В контексте минимизации квадратичной формы число обусловленности матрицы (отношение максимального собственного значения к минимальному, ) напрямую определяет скорость сходимости градиентного спуска.

    Представьте узкий и длинный овраг. Если вы находитесь на его склоне, градиент направлен почти перпендикулярно дну оврага, а не к его глобальному минимуму. Это классический пример плохой обусловленности ландшафта потерь.

    Численная устойчивость

    Алгоритм называется численно устойчивым, если ошибки округления, возникающие в процессе вычислений, не растут экспоненциально. Рассмотрим задачу вычисления Softmax, которая повсеместно используется в классификации:

    Если среди есть большое положительное число (например, ), то вызовет Overflow. Однако математически Softmax инвариантен к сдвигу: . Устойчивая реализация выбирает :

    Теперь самый большой показатель экспоненты равен 0 (), и переполнение невозможно. Это простейший пример того, как знание компьютерной арифметики меняет код.

    Прямой и обратный анализ ошибок

    Как понять, насколько можно доверять результату работы алгоритма? Существует два подхода:

  • Прямой анализ (Forward Error Analysis): Мы пытаемся оценить разность между истинным значением и вычисленным . Это сложно, так как ошибка зависит от каждого шага вычислений.
  • Обратный анализ (Backward Error Analysis): Метод, популяризированный Джеймсом Уилкинсоном. Мы предполагаем, что вычисленный результат является точным решением для слегка измененных входных данных . Если сопоставимо с погрешностью входных данных, алгоритм считается идеальным с точки зрения точности.
  • В машинном обучении мы часто полагаемся на то, что стохастическая природа алгоритмов (например, SGD) сама по себе является регуляризатором, «прощающим» ошибки округления. Однако при переходе к вычислениям с низкой точностью (Quantization до 4 или 8 бит) понимание этих механизмов становится критическим.

    Практические аспекты реализации

    Перевод математики в код требует внимания к деталям, которые опускаются в учебниках по анализу.

    Суммирование длинных последовательностей

    При обучении на больших базах данных мы часто вычисляем среднее значение градиента или функции потерь. Простое суммирование при больших приводит к накоплению ошибки. Если текущая сумма уже очень велика, а очередное слагаемое мало, то может оказаться меньше, чем , и просто «исчезнуть».

    Для решения этой проблемы используется алгоритм суммирования Кэхэна (Kahan Summation). Он вводит дополнительную переменную для компенсации накопленной ошибки:

    Этот метод позволяет достичь точности, близкой к float64, используя только float32.

    Логарифмическое пространство

    Многие вероятностные модели (например, наивный Байес или скрытые марковские модели) требуют перемножения множества малых вероятностей . Это гарантированно ведет к Underflow. Стандартный прием — переход в логарифмическое пространство:

    Вместо вероятностей мы храним их логарифмы (log-probs), что превращает умножение в сложение и расширяет диапазон представимых значений. При необходимости вернуться к сумме вероятностей (например, для нормализации) используется трюк Log-Sum-Exp:

    Численное дифференцирование и его ловушки

    Хотя в современном ML доминирует автоматическое дифференцирование (Autograd), понимание численного дифференцирования необходимо для проверки корректности градиентов (Gradient Checking).

    Мы уже упоминали проблему вычитания близких чисел. Чтобы минимизировать ошибку, вместо односторонней разности используют центральную разность:

    Ошибка этой аппроксимации имеет порядок , в то время как у односторонней — . Однако существует еще более элегантный метод — дифференцирование с использованием комплексного шага (Complex Step Differentiation):

    Здесь — мнимая единица. Этот метод не страдает от потери значимости при вычитании, так как вычитание в нем вообще не используется. Мы можем брать и получать точность производной вплоть до машинного эпсилона. Это работает для функций, которые можно аналитически продолжить в комплексную плоскость.

    Арифметика в тензорных вычислениях

    Современные библиотеки (PyTorch, JAX, TensorFlow) оптимизируют вычисления на уровне ядер CUDA. Важно понимать, что порядок операций в коде может не совпадать с порядком в математике. Из-за неассоциативности плавающей точки результаты на GPU и CPU могут незначительно различаться.

    В задачах оптимизации это может привести к тому, что на одной архитектуре алгоритм сойдется за 100 итераций, а на другой — за 105 или вовсе застрянет. Это не баг, а свойство численных методов. Для обеспечения воспроизводимости часто приходится фиксировать не только seed генератора случайных чисел, но и использовать детерминированные алгоритмы сверток и суммирования, что может замедлить обучение.

    Границы точности и критерии остановки

    Когда мы реализуем алгоритм оптимизации, нам нужно решить, когда прекратить итерации. Типичные условия:

  • Норма градиента стала мала: .
  • Изменение функции потерь стало незначительным: .
  • Изменение вектора параметров стало мало: .
  • Здесь — порог (tolerance). Выбор напрямую зависит от машинного эпсилона. Если вы установите для float32, алгоритм никогда не остановится по этому критерию, так как шум округления будет всегда больше этого порога. Разумный выбор для первого порядка оптимизации обычно лежит в пределах для одинарной точности.

    Понимание природы чисел в компьютере превращает «магию» настройки нейросетей в инженерную дисциплину. Каждый раз, когда вы видите странное поведение модели, спрашивайте себя: не пытаюсь ли я вычесть два слишком близких числа? Не вылетел ли я за пределы динамического диапазона? Обусловлена ли моя матрица весов? Ответы на эти вопросы часто лежат в фундаментах численного анализа, заложенных еще до появления первого транзистора.