Две регрессионные модели могут показать одинаковый MSE на одном и том же тестовом наборе и всё равно давать противоположные ответы на вопрос, можно ли доверять прогнозу. Разница вскроется только тогда, когда понадобится интервал предсказания или вероятность превысить порог.
Причина в устройстве метрики. MSE считает квадрат отклонения прогноза от истинного значения, то есть смотрит только на условное среднее. Дисперсия шума, форма распределения ошибок, интервалы и вероятности в неё не входят. Метрика отвечает, насколько точно угадана точка, и молчит о том, насколько прогноз информативен как распределение.
Gaussian NLL (negative log-likelihood для гауссова распределения) закрывает этот пробел: модель предсказывает два числа на каждое наблюдение, среднее μ и дисперсию σ², точнее её логарифм. Функция потерь собирается из двух конкурирующих частей: fit term штрафует за промах по среднему, honesty term штрафует за раздутую неопределённость. В итоге появляются калиброванные интервалы и вероятности вместо бинарного «да/нет», а цена этой честности - несколько новых подводных камней при обучении.
Почему MSE вводит в заблуждение: скрытые допущения
Формально MSE выглядит так: L = (1/N) * Σ(y_i - f(x_i))², где f(x) - прогноз модели. Всё дальнейшее следует из одного вопроса: при каких допущениях о данных эта функция становится статистически правильной целью обучения.
Что именно оптимизирует MSE: условное среднее и неявная гомоскедастичность
Пусть сигнал описывается моделью y = μ(x) + ε, где шум ε нормален с нулевым средним и постоянной дисперсией σ². Логарифм правдоподобия выборки:
log L = -N/2 * log(2πσ²) - (1 / (2σ²)) * Σ(y_i - f(x_i))²
Первое слагаемое от f не зависит, второе убывает ровно тогда, когда убывает сумма квадратов. Значит, минимизация MSE и максимизация правдоподобия при таких допущениях дают одну и ту же оценку. Вот только допущений здесь два: гауссово распределение шума и постоянная дисперсия шума, то есть гомоскедастичность. Второе почти никогда не выполняется на реальных сигналах. Волатильность в финансовых рядах приходит кластерами: спокойные недели сменяются серией резких движений. Уровень шума сенсора зависит от режима работы, температуры и загрузки. Спрос на товар шумит сильнее в праздники, чем в обычные дни.
Когда дисперсия меняется от точки к точке, корректная функция потерь взвешивает остатки обратно пропорционально дисперсии: (y - μ)² / σ²(x). Невзвешенная MSE этого не делает, поэтому модель распределяет ёмкость неравномерно: шумные участки дают большой вклад в лосс, и всё внимание уходит туда, тогда как на тихих участках прогноз остаётся грубым без всякого штрафа. Природа квадратичных потерь и причины их особой роли подробно разобраны в материале про среднее арифметическое и квадратичные потери.
Отдельная проблема: даже идеально найденное условное среднее E[y|x] мало что говорит о данных. Условное распределение может быть несимметричным или двугорбым, и тогда среднее попадает в промежуток между двумя реальными режимами, где наблюдений почти нет.
Две модели с одинаковым MSE: как это возможно
Самое наглядное следствие: MSE вообще не видит σ. Формула метрики зависит только от μ, поэтому две модели с одинаковыми прогнозами среднего и разными оценками дисперсии получат ровно одинаковый MSE. Пусть обе выдали в одной точке 5.0, но первая с σ = 0.1, а вторая с σ = 2.0. Метрика одинаковая, а смысл противоположный: первая утверждает, что значение почти наверняка лежит в диапазоне 4.8-5.2, вторая разводит руками и называет диапазон 1-9.
Дальше интереснее. Сконструируем простой пример. Сигнал на отрезке x ∈ [0, 1]: y = sin(2πx) плюс шум, дисперсия которого растёт слева направо, от σ = 0.05 в начале до σ = 0.4 в конце. Модель A выучила и форму кривой, и профиль шума: её μ близко к истине всюду, а σ повторяет рост. Модель B чуть смещает μ в тихой левой части, где остатки визуально заметны, зато попадает точнее в правой шумной зоне. Суммарный квадрат ошибок у них можно подобрать одинаковым, а вот вероятностные прогнозы окажутся противоположными: A уверена там, где сигнал чистый, B рисует узкий интервал на шумном участке.
Для метрики это неразличимо. Для задачи, где по прогнозу принимают решение, разница принципиальная. Если система планирует закупку по верхней границе интервала, ошибка в профиле σ искажает план сильнее, чем небольшая разница в среднем.
Как Gaussian NLL исправляет ситуацию
Gaussian NLL обучает модель предсказывать параметры условного распределения. Для каждой точки выходной слой отдаёт два числа: μ и log σ². Лосс:
L = (1/N) * Σ[ 0.5 * log(σ_i²) + (y_i - μ_i)² / (2σ_i²) ]
Константа 0.5 * log(2π) опущена, на градиенты она не влияет. Модель сама решает, где заявить узкое распределение, а где широкое, и платит за оба решения.
Fit term и honesty term: два конкурирующих члена лосса
Разберём по частям.
- Fit term:
(y - μ)² / (2σ²). Квадратичная ошибка, поделённая на дисперсию. Промах в тихой точке, где σ мала, стоит дорого; тот же промах там, где шум объективно велик, обходится дешевле. - Honesty term:
0.5 * log(σ²). Логарифмический штраф за заявленную неопределённость. Раздувая σ, от него не спрятаться: чем шире распределение, тем больше этот член.
Равновесие находится аналитически. Возьмём одну точку с остатком r = y - μ и продифференцируем лосс по σ²: 1/(2σ²) - r²/(2σ⁴) = 0, откуда σ² = r². Оптимум для отдельного наблюдения достигается при σ, равной модулю остатка. Посмотрим, как это выглядит в числах при остатке r = 10:
| σ | fit term | honesty term | сумма |
|---|---|---|---|
| 1 | 50.0 | 0.0 | 50.0 |
| 3 | 5.6 | 1.10 | 6.7 |
| 10 | 0.5 | 2.30 | 2.80 |
| 30 | 0.06 | 3.40 | 3.46 |
Минимум попадает ровно на σ = 10. Логика такая: fit term падает квадратично, honesty term растёт логарифмически, поэтому у модели есть пространство для манёвра, но не бесконечное. Дальнейшее расширение σ уже повышает лосс, и это удерживает оценку неопределённости от расползания. Аналогия простая: модель платит логарифмический налог за заявленную неуверенность и получает квадратичный штраф за промах. Обмануть баланс между двумя платежами не получится, если шум действительно гауссов.
Почему предсказывают log σ, а не σ
- Положительность по построению. σ = exp(log σ) всегда больше нуля, ветка с отрицательной дисперсией исчезает из пространства поиска.
- Устойчивость градиента. Производная лосса по log σ² равна
0.5 * (1 - r²/σ²): при σ, стремящейся к нулю, она не улетает в бесконечность так, как производная по самой σ. - Масштабная симметрия. Одинаковые относительные изменения σ дают одинаковые сдвиги log σ, поэтому шаг обучения работает одинаково и на σ = 0.01, и на σ = 100.
- Удобный клиппинг. Ограничить log σ диапазоном [-5, 5] просто, и это держит σ примерно в границах от 0.007 до 148.
Во многих фреймворках на выходе получается логарифм дисперсии, а не стандартного отклонения. Разница только в множителе: log σ² = 2 log σ. Например, torch.nn.GaussianNLLLoss в PyTorch принимает на вход именно дисперсию, а torch.distributions.Normal ждёт уже σ в параметре scale. Перепутать легко, поэтому стоит один раз проверить, что именно возвращает голова модели.
Практические подводные камни Gaussian NLL
Ловушка оптимизации: как модель «объясняет» ошибки завышенной σ
Из таблицы выше видно неприятное свойство: расширить σ выгодно почти всегда, когда остаток велик. На одном выбросе с остатком 10 рост σ с 1 до 10 снижает fit term с 50 до 0.5, а honesty term добавляет всего 2.3. Если σ предсказывается отдельно для каждой точки, модель может поднять её только на проблемных наблюдениях и почти бесплатно срезать лосс.
Когда это статистически честно, а когда нет? Если остаток порождён настоящим шумом, высокая σ там и должна быть. Ловушка начинается в трёх случаях:
- Модель может уменьшить систематическую ошибку (смещение из-за недообученности), но расширение σ дешевле. NLL не различает aleatoric и epistemic неопределённость.
- В данных есть выбросы и тяжёлые хвосты. Нормальное распределение с одной σ плохо описывает такие точки, и обучение начинает гонку за ними.
- Выборка маленькая, и оценка σ держится на нескольких наблюдениях.
Практические ответы на это:
- Робастные распределения вместо нормального: NLL для распределения Стьюдента с настраиваемой степенью свободы прямо моделирует тяжёлые хвосты и не заставляет σ раздуваться.
- Смеси гауссовых компонент (mixture density network). Несколько пар μ и σ описывают и выбросы, и многомодальные условные распределения.
- Detach-приём: убрать σ из-под градиента в fit term, чтобы модель не могла придушить сложные примеры завышенной дисперсией. Параметр σ тогда учится только по honesty term и не подменяет собой качество среднего.
- Отдельная метрика на μ. Смотреть на MAE или MSE по среднему прогнозу параллельно с NLL: если μ деградирует, а лосс падает за счёт σ, вы поймали ловушку.
Клиппинг диапазона σ и другие меры стабилизации
- Клиппинг log σ в фиксированный коридор, например [-5, 5]. Это спасает от взрыва градиентов и от нулевой дисперсии, которая превращает деление в inf.
- Малый epsilon в знаменателе. В torch.nn.GaussianNLLLoss параметр eps по умолчанию равен 1e-6 и подстраховывает дисперсию от нуля.
- Инициализация около нуля. Смещение головы для log σ² ставят в ноль, чтобы стартовать с σ = 1 и не ломать первые шаги обучения.
- Разогрев на MSE. Первые эпохи обучают только μ, а σ зафиксирована или её вклад ослаблен; полный NLL включают позже. Так модель сначала находит форму сигнала, а потом учится оценивать шум.
- Мониторинг. Гистограмма предсказанных σ, доля точек на границах клиппинга, кривые fit и honesty отдельно. Если honesty term доминирует, модель торгует качеством среднего за счёт дисперсии.
- Проверка калибровки. Предсказанную σ нужно сверять с фактическим разбросом остатков на валидации; типичные ошибки чтения таких проверок, включая доверительные интервалы и p-value, разобраны в материале про 10 статистических ловушек.
Худший сценарий, к которому приводит пренебрежение клиппингом: σ уходит в потолок на большой части выборки, интервалы становятся шириной от нуля до бесконечности. Формально модель не врёт, интервалы даже покрывают истину. Практическая ценность такого прогноза нулевая.
Что даёт вероятностный подход на практике
Три вещи, которые нельзя получить из точечной оценки: интервалы с проверяемым покрытием, вероятности для пороговых решений и ранжирование точек по неопределённости.
Корректные интервалы предсказания вместо точечных оценок
Интервал строится из двух параметров: [μ - z * σ, μ + z * σ]. Для уровня 95% z ≈ 1.96, для 68% z = 1. Модель с честной σ даёт интервалы, покрытие которых на отложенной выборке близко к номинальному.
Покрытие (PICP, prediction interval coverage probability) считается просто: доля истинных значений, попавших в интервал. Рядом смотрят среднюю ширину интервала (MPIW). Хорошая модель увеличивает покрытие без раздувания ширины; модель, которая просто растянула интервалы, выигрывает в покрытии и проигрывает в ширине. Ещё полезны NLL на тесте и CRPS: обе метрики оценивают всё распределение, а не отдельную точку.
Для визуального контроля строят веерную диаграмму: средняя линия плюс полосы 50% и 90%. У хорошо обученной модели истинные значения выходят за границы 90% полосы примерно в одном случае из десяти.
Вероятности для пороговых решений: от «да/нет» к оценке риска
Допустим, линия контроля качества считает деталь бракованной, если измеренный параметр превышает порог T = 1.0. Модель с гауссовым выходом даёт вероятность P(y > T) = 1 - Φ((T - μ)/σ), где Φ - функция распределения стандартной нормали.
Возьмём две детали с одинаковым прогнозом среднего μ = 0.9. Первая предсказана с σ = 0.05: z = (1.0 - 0.9)/0.05 = 2, P(y > 1.0) ≈ 2.3%. Вторая с σ = 0.5: z = 0.2, P(y > 1.0) ≈ 42%. Среднее одинаковое, а решения противоположные: первую можно пропустить, вторую стоит отправить на повторное измерение. Классический детектор с бинарным выходом в такой ситуации вернул бы одну и ту же метку для обеих.
Дальше подключается экономика. Если ложный пропуск дефекта стоит дороже лишней остановки конвейера, порог вероятности сдвигают вниз, и наоборот. Вероятностная модель позволяет выбирать порог под стоимость ошибок, а не подгонять его вслепую.
Ранжирование по σ закрывает ещё две задачи: обнаружение аномалий (высокая предсказанная дисперсия отмечает точки, не похожие на обучающую выборку) и активное обучение (размечать в первую очередь примеры с наибольшей неопределённостью). Типичные прикладные сценарии: планирование запасов по интервалам спроса, оценка риска в финансах, контроль сенсорных показаний, прогноз энергопотребления.
Когда MSE всё ещё уместен
Отказываться от MSE стоит не всегда. Он остаётся разумным выбором в нескольких ситуациях.
- Дисперсия шума действительно постоянна и известна из физики процесса: лабораторный сенсор в стабильном режиме, калиброванное измерение с паспортной погрешностью.
- Задача требует только точечного прогноза, а цена ошибки симметрична в обе стороны. Если интервалы и вероятности никто не использует, NLL добавит сложности без пользы.
- Данных мало. Оценка σ на нескольких десятках наблюдений ненадёжна, и предсказанные интервалы будут плохо откалиброваны. На малых выборках проще честно признать ограничение.
- Распределение ошибок сильно отличается от гауссова, а времени на смеси и робастные лоссы нет. Здесь помогает квантильная регрессия (pinball loss): интервалы строятся без допущений о форме распределения.
- MSE нужен как базовая линия. Сравнивать новую вероятностную модель удобнее с простым бейзлайном, а не только с предыдущей нейросетью.
MSE не плохой. Он оптимизирует конкретную цель, условное среднее, и делает это корректно. Проблема возникает, когда от него ждут ответов про неопределённость, которых в него не заложено.
Как внедрить Gaussian NLL в свой пайплайн
Схема перехода укладывается в несколько шагов: у модели появляется вторая голова на выходе, функция потерь меняется на NLL, набор метрик расширяется.
- Выходной слой возвращает два тензора: μ и log σ².
- Функция потерь считает
0.5 * (log σ² + (y - μ)² / σ²)и усредняет по батчу. - log σ² клиппится, σ инициализируется около единицы, первые эпохи можно обучать только на MSE.
- На валидации отслеживаются NLL, покрытие интервалов, ширина интервалов и отдельно MAE по μ.
import torch
import torch.nn as nn
class GaussianHead(nn.Module):
def __init__(self, features: int):
super().__init__()
self.mu = nn.Linear(features, 1)
self.log_var = nn.Linear(features, 1)
nn.init.zeros_(self.log_var.weight)
nn.init.zeros_(self.log_var.bias)
def forward(self, h):
mu = self.mu(h)
log_var = torch.clamp(self.log_var(h), min=-5.0, max=5.0)
return mu, log_var
head = GaussianHead(128)
criterion = nn.GaussianNLLLoss(eps=1e-6)
mu, log_var = head(h)
loss = criterion(mu, target, torch.exp(log_var))
Тот же лосс вручную, если нужно обойтись без встроенной функции фреймворка:
loss = 0.5 * (log_var + (target - mu) ** 2 / torch.exp(log_var)).mean()
Для негауссовых шумов подойдут другие распределения: NLL для Стьюдента при тяжёлых хвостах, смеси гауссиан при многомодальности, квантильный лосс, когда интервалы нужны без параметрических допущений. Переход редко проходит гладко с первого раза: метрики скачут, σ упирается в границы клиппинга, приходится подбирать разогрев. В таких итерациях выигрывает не самый свежий инструмент, а дисциплина в мониторинге и готовность возвращаться к базовой линии, о чём подробно говорится в разборе пяти уроков за восемь лет в ML.
Минимальный чек-лист перед выкаткой такой модели в прод: интервалы покрывают истину с заявленной частотой, ширина интервалов меняется по данным, а не стоит на границах клиппинга, fit и honesty сбалансированы, качество среднего прогноза не хуже, чем у MSE-бейзлайна. Если хотя бы один пункт провален, вероятностная надстройка пока не готова к принятию решений.