Общие причины nans во время обучения

Я заметил, что частым явлением во время тренировки является NANs вводится.

часто кажется, что он вводится весами во внутренних продуктах / полностью связанных или сверточных слоях.

это происходит потому, что вычисление градиента взрывается? Или это из-за инициализации веса (если да, то почему инициализация веса имеет этот эффект)? Или это, вероятно, вызвано характером входных данных?

в главный вопрос здесь просто:какова наиболее распространенная причина для NANs, происходящих во время обучения? а во-вторых, каковы некоторые методы борьбы с этим (и почему они работают)?

4 ответов


хороший вопрос.
Я сталкивался с этим явлением несколько раз. Вот мои наблюдения:--35-->


градиент взорвать

причина: большие градиенты выбивают процесс обучения из колеи.

что вас ждет: глядя на журнал выполнения, вы должны посмотреть на значения потерь за итерацию. Вы заметите, что потеря начинает расти значительно от итерации к итерации, в конце концов, потеря будет слишком большой, чтобы быть представленной переменной с плавающей запятой, и она станет nan.

что делать: уменьшить base_lr (в решатель.prototxt) на порядок (по крайней мере). Если у вас есть несколько слоев потери, вы должны проверить журнал, чтобы увидеть, какой слой отвечает за градиент взорвать и уменьшить loss_weight (в train_val.prototxt) для этого конкретного слоя, а не общей base_lr.


плохая политика скорости обучения и params

причина: caffe не удается вычислить допустимую скорость обучения и получает 'inf' или 'nan' вместо этого эта недопустимая скорость умножает все обновления и, таким образом, аннулирует все параметры.

что вас ждет: глядя на журнал выполнения, вы должны видеть, что сама скорость обучения становится 'nan', для пример:

... sgd_solver.cpp:106] Iteration 0, lr = -nan

что делать: исправить все параметры, влияющие на скорость обучения в .
Например, если вы используете lr_policy: "poly" и вы забыли определить max_iter параметр, вы в конечном итоге с lr = nan...
Дополнительные сведения о скорости обучения в caffe см. В разделе этой теме.


неисправная функция потери

причина: иногда вычисления потерь в слоях потерь вызывает nans, чтобы появиться. Например, кормление InfogainLoss слой с ненормализованными значениями, используя пользовательский слой потерь с ошибками и т. д.

что вас ждет: глядя на журнал выполнения, вы, вероятно, не заметите ничего необычного: потеря постепенно уменьшается, и внезапно nan появляется.

что делать: посмотрите, можете ли вы воспроизвести ошибку, добавьте распечатка на слой потерь и отладка ошибки.

например: однажды я использовал потерю, которая нормализовала штраф по частоте появления метки в пакете. Так уж получилось, что если одна из обучающих меток вообще не появилась в партии-потери вычисляются произведенные nans. В этом случае работы с достаточно большими партиями (относительно количества меток в наборе) было достаточно, чтобы избежать этой ошибки.


неисправен ввод

причина: у вас есть вклад с nan в нем!

что вас ждет: как только процесс обучения "попадает", этот неисправный вход-выход становится nan. Глядя на журнал выполнения, вы, вероятно, не заметите ничего необычного: потеря постепенно уменьшается, и внезапно nan появляется.

что делать: повторно создайте входные наборы данных (lmdb/leveldn/hdf5...) убедитесь, что вы не имейте плохие файлы изображений в вашем наборе обучения/проверки. Для отладки вы можете построить простую сеть, которая читает входной слой, имеет фиктивную потерю поверх него и проходит через все входы: если один из них неисправен, эта фиктивная сеть также должна производить nan.


шаг больше, чем размер ядра в "Pooling" пласт

по какой-то причине, выбирая stride>kernel_size для объединения результатов может с nans. Например:

layer {
  name: "faulty_pooling"
  type: "Pooling"
  bottom: "x"
  top: "y"
  pooling_param {
    pool: AVE
    stride: 5
    kernel: 3
  }
}

результаты nans в y.


нестабильность в "BatchNorm"

сообщалось, что под некоторыми настройками "BatchNorm" слой может выводить nans из-за численных неустойчивостей.
Это вопрос воспитывался в bvlc / caffe и PR #5136 пытается исправить это.


недавно я узнал о debug_info флаг: задание debug_info: true на 'solver.prototxt' сделает печать caffe для регистрации больше отладки информация (включая значения градиента и значения активации) во время обучения: эта информация может помощь в обнаружении градиентных взрывов и других проблем в учебном процессе.


в моем случае причиной была не установка смещения в слоях свертки/деконволюции.

устранение: добавьте к параметрам слоя свертки следующее.

bias_filler { тип: "константа" значение: 0 }


этот ответ не вызывает nans, но скорее предлагает способ помочь отладить его. Вы можете иметь этот слой python:

class checkFiniteLayer(caffe.Layer):
  def setup(self, bottom, top):
    self.prefix = self.param_str
  def reshape(self, bottom, top):
    pass
  def forward(self, bottom, top):
    for i in xrange(len(bottom)):
      isbad = np.sum(1-np.isfinite(bottom[i].data[...]))
      if isbad>0:
        raise Exception("checkFiniteLayer: %s forward pass bottom %d has %.2f%% non-finite elements" %
                        (self.prefix,i,100*float(isbad)/bottom[i].count))
  def backward(self, top, propagate_down, bottom):
    for i in xrange(len(top)):
      if not propagate_down[i]:
        continue
      isf = np.sum(1-np.isfinite(top[i].diff[...]))
        if isf>0:
          raise Exception("checkFiniteLayer: %s backward pass top %d has %.2f%% non-finite elements" %
                          (self.prefix,i,100*float(isf)/top[i].count))

добавление этого слоя в ваш train_val.prototxt в определенные моменты вы подозреваете, может вызвать проблемы:

layer {
  type: "Python"
  name: "check_loss"
  bottom: "fc2"
  top: "fc2"  # "in-place" layer
  python_param {
    module: "/path/to/python/file/check_finite_layer.py" # must be in $PYTHONPATH
    layer: "checkFiniteLayer"
    param_str: "prefix-check_loss" # string for printouts
  }
}

Я пытался построить разреженный автоэнкодер и несколько слоев в нем, чтобы вызвать разреженности. Запустив сеть, я наткнулся на НАН. При удалении некоторых слоев (в моем случае мне действительно пришлось удалить 1) я обнаружил, что NaN исчез. Итак, я думаю, что слишком большая разреженность может привести и к NaN (возможно, были вызваны некоторые вычисления 0/0!?)