Optimization Algorithm
Алгоритм оптимизации обновляет веса модели, чтобы минимизировать функцию потерь во время обучения. Рассматриваются градиентный спуск, моментум, Adam, AdamW, Muon и примеры кода.
Алгоритм оптимизации, или оптимизатор, — это правило, по которому в процессе обучения изменяются параметры модели, чтобы уменьшить ее функцию потерь. В глубоком обучении оптимизатор получает градиент функции потерь по каждому весу модели, вычисленный с помощью обратного распространения ошибки, и решает, насколько и в каком направлении изменить каждый вес. Вместе с скоростью обучения оптимизатор определяет скорость сходимости обучения, его стабильность, потребление памяти и зачастую то, насколько хорошо итоговая модель обобщает данные.
Как работают оптимизаторы#
Почти каждый оптимизатор глубокого обучения — это разновидность градиентного спуска: вычислить градиент g функции потерь на мини-пакете, а затем сделать небольшой шаг в противоположном направлении: w ← w − η·g. Оптимизаторы отличаются тем, как обрабатывают g перед шагом. Методы с моментумом усредняют градиенты во времени, чтобы ускорить движение в устойчивых направлениях. Адаптивные методы делят шаг каждого параметра на текущую оценку величины его градиента. Muon ортогонализует обновление всей матрицы весов целиком. Методы второго порядка также учитывают кривизну, благодаря чему каждый шаг точнее, но вычисляется намного дороже. Методы, которым градиент не нужен, например эволюционные алгоритмы и случайный поиск, оптимизируют модель, перебирая варианты и оставляя лучший:
Правило обновления особенно важно, когда поверхность функции потерь плохо обусловлена и в одних направлениях изгибается резко, а в других — плавно. Разница хорошо видна, если запустить три оптимизатора из одной точки в узкой долине:
import torch
# A long, narrow valley: f(w) = w1^2 + 50 * w2^2, with its minimum at (0, 0)
scale = torch.tensor([1.0, 50.0])
optimizers = {
"SGD": lambda p: torch.optim.SGD(p, lr=0.015),
"SGD + momentum": lambda p: torch.optim.SGD(p, lr=0.015, momentum=0.9),
"Adam": lambda p: torch.optim.Adam(p, lr=0.1),
}
for name, make_optimizer in optimizers.items():
w = torch.tensor([5.0, 1.0], requires_grad=True)
optimizer = make_optimizer([w])
# Same loss and starting point for every optimizer; only the update rule differs
for step in range(100):
loss = (scale * w**2).sum()
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"{name:15s} f(w) after 100 steps: {(scale * w**2).sum().item():.6f}")Обычный SGD останавливается на значении 0.056531, потому что крутое направление w2 ограничивает скорость обучения: при любом значении выше 0.02 параметр w2 на каждом шаге уходит слишком далеко, а при 0.021 значение функции потерь за 100 шагов поднимается примерно до 9,5 миллиарда. Из-за этого ограничения прогресс вдоль пологого направления w1 идет медленно. Моментум достигает 0.000216, набирая скорость вдоль w1, а Adam достигает 0.001953, задавая отдельный размер шага для каждой координаты.
Распространенные алгоритмы оптимизации#
- Стохастический градиентный спуск (SGD): Делает шаг против градиента мини-пакета. С моментумом 0.9 он использовался для обучения большинства известных сверточных сетей и хранит одно дополнительное значение для каждого параметра.
- AdaGrad и RMSProp: Масштабируют шаг каждого параметра с учетом истории квадратов его градиентов. AdaGrad делит шаг на корень из их текущей суммы, которая только растет, поэтому шаги уменьшаются на протяжении всего обучения. Вместо этого RMSProp использует экспоненциально затухающее среднее, благодаря чему размеры шагов остаются адаптивными.
- Adam: Сочетает моментум с масштабированием в стиле RMSProp и корректирует оба скользящих среднего значения с учетом их нулевого начального состояния. Значения по умолчанию — скорость обучения 0.001, β1 = 0.9 и β2 = 0.999 — подходят для множества задач.
- AdamW: Adam с разделенным затуханием весов, которое непосредственно уменьшает веса, а не делает это через адаптивное масштабирование градиента. Это стандартный оптимизатор для трансформеров и больших языковых моделей (LLMs).
- Muon: Ортогонализует обновление моментума каждой двумерной матрицы весов с помощью итераций Ньютона — Шульца и хранит один буфер состояния на параметр. Moonshot AI масштабировала его для предварительного обучения LLM.
- L-BFGS: Квазиньютоновский метод, который строит оценку кривизны по недавним градиентам. Он сходится за небольшое число шагов на гладких задачах с полным пакетом, но шумные градиенты мини-пакетов делают его неподходящим для больших сетей.
В пакете оптимизаторов PyTorch реализованы все эти методы, включая torch.optim.Muon, а также планировщики скорости обучения, совместимые с любым из них.
Оптимизатор и смежные понятия#
- Функция потерь: Целевая величина, которую минимизирует оптимизатор, например перекрестная энтропия для классификации или среднеквадратичная ошибка для регрессии.
- Планировщик скорости обучения: Регулирует размер шага η в ходе обучения, используя разогрев, ступенчатое снижение или косинусный отжиг, и работает поверх любого оптимизатора.
- Подбор гиперпараметров: Внешний поиск по настройкам, таким как оптимизатор, скорость обучения и размер пакета, где каждый вариант требует полного или частичного запуска обучения. Для этого используют методы без градиента, например байесовскую оптимизацию и эволюционный поиск, поскольку оценку на валидации нельзя дифференцировать по таким вариантам, как оптимизатор.
Выбор оптимизатора#
Оптимизатор и скорость обучения выбираются вместе, поскольку каждый оптимизатор работает в своем диапазоне: SGD с моментумом обычно запускают со значением от 0.01 до 0.1, а оптимизаторы семейства Adam — примерно с 0.001. Обучение Ultralytics YOLO автоматически выбирает подходящий вариант: по умолчанию optimizer="auto" игнорирует lr0 и выбирает AdamW со скоростью обучения, рассчитанной с учетом количества классов, для запусков длительностью до 10 000 итераций; при более длинном расписании выбирается MuSGD — гибрид SGD и Muon, использованный для обучения опубликованных контрольных точек YOLO26. Если указать оптимизатор по имени, начинает действовать lr0:
from ultralytics import YOLO
# Загрузи предварительно обученную модель YOLO26n
model = YOLO("yolo26n.pt")
# Явно выбери SGD; lr0 применяется, только если оптимизатор не равен "auto"
results = model.train(data="coco8.yaml", epochs=5, optimizer="SGD", lr0=0.01)При использовании optimizer="SGD" тренер также включает моментум Нестерова, задавая коэффициентом аргумент momentum, значение которого по умолчанию равно 0.937.










