Запишите процесс устранения неполадок Нэн в обучении полуточному усилителю в PyTorch.

Согласно онлайн-учебнику, в обучении усилителя половинной точности есть проблемы с наном, которые представляют собой не что иное, как следующие типы:

  • При расчете убытка возникает ситуация деления на 0
  • Потери слишком велики, и они оцениваются как inf с половинной точностью.
  • Если в параметрах сети есть nan, то в результате операции также будет выведено nan (это скорее явление, чем причина. Появление nan в сети должно быть связано с появлением nan или inf ранее)

Но в целом есть три типа:

  • Операционные ошибки, такие как x/0 при расчете убытков, вызывающие ошибки
  • Числовое переполнение, результат операции выходит за пределы представления, например, вес и ввод в норме, а результат операции Nan или Inf. Например, если потеря слишком велика, она фактически превышает диапазон представления и становится инф.
  • Проблема с градиентом, возможно проблема с возвратом градиента (не знаю)

0. Заключение

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

Но Нэн появляется в этой статье из-за float16, потому что максимальное значение, поддерживаемое float16, равно 65504, а моя модель включает матричное умножение (фактически операция q@k в трансформаторе). Среди них a∈[-38,40], b∈[-39,40] и умножение матриц a@b=c, c∈[-61408,inf]. Поскольку максимальное значение после операции матричного умножения a и b превышает максимальное представление float16, что приводит к появлению inf, поэтому окончательный результат появляется Nan.

1. Грубое позиционирование

Процесс обучения можно представить в виде следующего процесса:
вставьте сюда описание изображения

1.1 Привязка к эпохе

Во-первых, видно, что потери на выходе в эпоху 4 в норме, а это означает, что процесс обучения 0~498iter в epoch4 нормальный, тогда проблема может появиться в 501 iter эпохи 4 499iter и epoch0~499iter.

1.2 найти его

Теперь нам нужно настроить таргетинг на конкретный итератор.

Об этом можно судить по методу дихотомии.В модели отладки 100, 300 и 499 итеров в эпоху = 5 раундов соответственно проверяют, являются ли потери нормальными, и так далее, чтобы найти конкретный итер.

У меня между iter161~162 эпохи = 5, потеря нормальна, когда iter = 161, и потеря Nan, когда iter = 162. Iter по-прежнему следует процессу, показанному на рисунке выше.Можно видеть, что проблема заключается не в чем ином, как в вычислении градиента и обновлении веса, когда iter=161, а также в прямой операции и расчете потерь, когда iter=162, в этих четырех местах.

1.3 Поиск конкретных шагов

При отладке сделайте паузу непосредственно перед прямой операцией эпохи = 5 и iter = 162.

Сначала посмотрите, в норме ли вес:

# 在iter=162的模型推理之前,检查权重是否存在异常值,比如Nan或inf
if epoch == 5:
    if i == 162:
        print(epoch, i)

        class bcolors:
            HEADER = '\033[95m'
            OKBLUE = '\033[94m'
            OKGREEN = '\033[92m'
            WARNING = '\033[93m'
            FAIL = '\033[91m'
            ENDC = '\033[0m'
            BOLD = '\033[1m'
            UNDERLINE = '\033[4m'

        # print grad check
        v_n = []
        v_v = []
        v_g = []
        for name, parameter in model.named_parameters():
            v_n.append(name)
            v_v.append(parameter.detach().cpu().numpy() if parameter is not None else [0])
            v_g.append(parameter.grad.detach().cpu().numpy() if parameter.grad is not None else [0])
        for j in range(len(v_n)):
            if np.isnan(np.max(v_v[j]).item() - np.min(v_v[j]).item()) or np.isnan(
                    np.max(v_g[j]).item() - np.min(v_g[j]).item()):
                color = bcolors.FAIL + '*'
            else:
                color = bcolors.OKGREEN + ' '
            print('%svalue %s: %.3e ~ %.3e' % (color, v_n[j], np.min(v_v[j]).item(), np.max(v_v[j]).item()))
            print('%sgrad  %s: %.3e ~ %.3e' % (color, v_n[j], np.min(v_g[j]).item(), np.max(v_g[j]).item()))

outputs = model(images)

В ходе проверки доказано, что с весом проблем нет, поэтому проблема ограничивается прямыми рассуждениями и расчетом потерь iter=162.

Проверьте ввод и вывод
с помощью кода:

print(images.mean())	# 检查输入,正常
outputs = model(images)
print(outputs .mean())	# 检查输出,Nan

Отсюда мы знаем ситуацию: вес модели нормальный, вход модели нормальный, а выход модели Нан

2. Точное позиционирование

Здесь это легко сделать.С помощью pycharm мы шаг за шагом отлаживаем ввод и вывод каждой модели в модели, чтобы увидеть, какая часть модели появляется Nan или Inf, и, наконец, найти строку кода:

attn = (q @ k.transpose(-2, -1)) * self.scale

Этот код предназначен для реализации матричного умножения q и k, диапазоны их значений:

тензор макс (приблизительное значение) мин (приблизительное значение)
д 38 -37
к 40 -38
внимание инф -61408

Отсюда видно, что это простая проблема вычисления, и очень распространенная проблема - числовое переполнение.Учитывая, что я использую float16 половинной точности, максимальное значение при запросе равно 65504, поэтому весьма вероятно, что максимальное значение имеет переполнен. Для проверки мы можем преобразовать q и k в double (float64) перед вычислением, и мы можем обнаружить, что результат вычисления нормальный, и тип тоже float64. Это показывает, что это вызвано числовым переполнением.
вставьте сюда описание изображения

3. Решения

Теперь известно, что моя причина - числовое переполнение.Один из способов - перехватить: установить inf или nan как константу, и я нормализую q и k до [-1,1] перед операцией, что гарантирует, что результат операции будет не быть слишком большим (нет причин, это безмозглая операция, и ее не рекомендуется изучать).

Supongo que te gusta

Origin blog.csdn.net/qq_40243750/article/details/128207067
Recomendado
Clasificación