Когда обучение не идет. Loss is NaN. Причины и решения
Привет, это моя первая статья на Хабре. И я хочу рассказать вам о проблеме, на решение которой когда-то давно у меня ушло довольно много времени.
Часто бывает, что при обучении (или тестировании) модели нейронной сети (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 равен нулю, тогда и его норма. Это приводит к делению на ноль, следовательно,
В популярных фреймворках слои нормализации (обычно) уже используют это небольшое число, но лучше убедиться в этом, чтобы избежать такого случая.
Производная от определенного слоя
Оптимизатор вычисляет производные функций потерь и слоев NN при обратном распространении. Рассмотрим слой standard-deviation-pooling, описанный здесь. Стандартное отклонение некоторого вектора x:
Давайте продифференцируем эту функцию по х:
Поэтому нам нужно нарушить уравнение (*). Самое простое решение - добавить к
Функция потерь возвращает NaN
Давайте разберемся с средней абсолютной ошибкой (mean absolute error - MAE).
Итак, как показано выше, если любое из предсказанных моделью значений
Заключение
Мы рассмотрели несколько случаев, когда функция потерь становится NaN. В вашем пайплайне обучения вы можете проверять выход NN, градиенты и значение функции потерь, являются ли они NaN. Это позволит вашему алгоритму прервать цикл обучения и исправить ошибку.