10

Я работаю над репликацией нейронной сети. Я пытаюсь понять, как работают стандартные типы слоев. В частности, у меня возникли проблемы с поиском описания того, как ведут себя слои поперечной нормализации на обратном пути.Алгоритм обратного прополнения через уровень локализации локального отклика (LRN)

Поскольку нормализация уровня не имеет параметров, я мог предположить два возможных варианта:

  1. градиенты ошибок из следующего (т.е. позже) слоя передаются в обратном направлении, не делая ничего для них.

  2. Градиенты ошибки нормализуются так же, как активация нормализуется по каналам в прямом проходе.

Я не могу придумать причину, по которой вы делали бы один над другим, основываясь на любой интуиции, поэтому я хотел бы помочь в этом.

EDIT1:

слой представляет собой стандартный слой CAFFE, как описано здесь http://caffe.berkeleyvision.org/tutorial/layers.html (см 'Локальная Нормирование отклика (LRN)').

Реализация слоя в прямом проходе описана в разделе 3.3 статьи alexNet: http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf

EDIT2:

Я считаю, что вперед и алгоритмы обратных частот описаны как в библиотеке Факела здесь: https://github.com/soumith/cudnn.torch/blob/master/SpatialCrossMapLRN.lua

и в библиотеке Caffe здесь: https://github.com/BVLC/caffe/blob/master/src/caffe/layers/lrn_layer.cpp

Пожалуйста, может кто знаком ни с/оба этих перевода метод для этапа обратного прохода в простой английский?

+0

Можете ли вы ссылаться на ссылку о «слоях нормализации поперечной канавки»? Google только раскрывает документ arxiv, который, похоже, говорит о многом другом. Это вряд ли похоже на стандартный тип слоя. – IVlad

+0

Добавлены ссылки @IVlad. – user1488804

ответ

3

Он использует правило цепи для распространения градиента назад через локальный уровень нормализации отклика. Он несколько похож на слой нелинейности в этом смысле (который также не имеет обучаемых параметров сам по себе, но влияет на градиенты, идущие назад).

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

Во-первых, на переднем проходе они кэшировать так называемую шкалу, которая вычисляется (с точки зрения AlexNet бумаги см формулу из раздела 3.3), как:

scale_i = k + alpha/n * sum(a_j^2) 

Здесь и далее sum является сумма индексируется j и идет от max(0, i - n/2) к min(N, i + n/2)

(обратите внимание, что в документе они не нормализуются на n, поэтому я предполагаю, что это то, что Caffe делает иначе, чем AlexNet). Первой проход затем вычисляется как b_i = a_i + scale_i^-beta.

Для обратной передачи ошибки предположим, что ошибка, исходящая от следующего уровня, равна be_i, а ошибка, которую нам нужно вычислить, - ae_i. Тогда ae_i вычисляется как:

ae_i = scale_i^-b * be_i - (2 * alpha * beta/n) * a_i * sum(be_j * b_j/scale_j) 

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

  1. Когда вы вычисляете слагаемые для суммы, выделите массив размером N + n - 1 и нанесите его на n/2 нулями на каждом конце. Таким образом, вы можете вычислить сумму от i - n/2 до i + n/2, не заботясь о том, чтобы идти ниже нуля и выше N.

  2. Вам не нужно пересчитывать sum на каждой итерации, вместо того, чтобы вычислять слагаемые заранее (a_j^2 для переднего прохода, be_j * b_j/scale_j для обратного прохода), а затем вычислить sum для i = 0, а затем для каждого подряд i просто добавьте addend[i + n/2] и вычтите addend[i - n/2 - 1], он даст вам значение суммы для нового значения i в постоянное время.

+1

не должен ли это быть 'b_i = a_i * scale_i^-beta'? –

-1

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

-1

У меня есть альтернативная формулировка назад, и я не знаю, если это эквивалентно Caffe лет:

So Caffe является:

ae_i = scale_i^-b * be_i - (2 * alpha * beta/n) * a_i * sum(be_j * b_j/scale_j) 

дифференцирования оригинального выражения

b_i = a_i/(scale_i^-b) 

Я получаю

ae_i = scale_i^-b * be_i - (2 * alpha * beta/n) * a_i * be_i*sum(ae_j)/scale_i^(-b-1)