Привет, это моя первая статья на Хабре. И я хочу рассказать вам о проблеме, на решение которой когда-то давно у меня ушло довольно много времени.
Часто бывает, что при обучении (или тестировании) модели нейронной сети (NN) функция потерь (loss) возвращает значение NaN (Not a Number). Это приводит к тому, что фаза обучения «срывается». Обычно неясно, почему это происходит. Я расскажу вам о возможных причинах и рекомендациях по решению этой проблемы.
Взрыв градиента
Существует две основные проблемы с градиентами на этапе обучения: исчезновение (vanishing) и взрыв (explosion) градиент. Первая описана в этих статьях:[1] [2]. Вторая будет рассмотрена здесь. Напомню, что при обратном распространении ошибки оптимизатор распространяет градиенты от последнего слоя к первому (хорошо описано в книге Тарика Рашида «Создаем нейронную сеть»). С помощью глубокой NN значения градиентов можно значительно увеличить (или уменьшить). Поэтому абсолютные значения становятся inf или NaN. Итак, есть несколько рекомендаций:
-
Уменьшите начальную скорость обучения или/и используйте планировщик скорости обучения.
-
Нормирование градиентов (clip)

# loss.backprop() torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm= C) # optimizer.step()
Этот метод позволяет ограничить градиенты в диапазоне [-C..C].
3. Измените архитектуру текущей модели (количество слоев, голов, нейронов и т.д.) или используйте другую модель.
Конкретный слой в архитектуре
Некоторые слои могут выдавать NaN для определенных входных данных. Например, слой нормализации использует деление на норму вектора x

Но что, если заданный вектор x равен нулю, тогда и его норма. Это приводит к делению на ноль, следовательно, . Очевидное решение — добавить небольшое ненулевое число (например, 10e-7) в знаменатель.

В популярных фреймворках слои нормализации (обычно) уже используют это небольшое число, но лучше убедиться в этом, чтобы избежать такого случая.
Производная от определенного слоя
Оптимизатор вычисляет производные функций потерь и слоев NN при обратном распространении. Рассмотрим слой standard-deviation-pooling, описанный здесь. Стандартное отклонение некоторого вектора x:

Давайте продифференцируем эту функцию по х:

Поэтому нам нужно нарушить уравнение (*). Самое простое решение — добавить к небольшое число
.
Функция потерь возвращает NaN
Давайте разберемся с средней абсолютной ошибкой (mean absolute error — MAE).

Итак, как показано выше, если любое из предсказанных моделью значений равно целевому значению y^, производная функции потерь возвращает NaN. Вы можете заметить, что этот случай довольно редкий, но я думаю, что он все равно заслуживает вашего внимания
Заключение
Мы рассмотрели несколько случаев, когда функция потерь становится NaN. В вашем пайплайне обучения вы можете проверять выход NN, градиенты и значение функции потерь, являются ли они NaN. Это позволит вашему алгоритму прервать цикл обучения и исправить ошибку.
ссылка на оригинал статьи https://habr.com/ru/articles/900460/
Добавить комментарий