Как именно вы рассчитываете градиенты для фильтров в сверточной нейронной сети? - PullRequest
0 голосов
/ 14 мая 2019

Из нескольких статей я узнал, что для вычисления градиентов для фильтров нужно просто свернуть входной объем в качестве входного значения и матрицу ошибок в качестве ядра.После этого вы просто вычитаете вес фильтра по градиентам (умноженным на скорость обучения).Я реализовал этот процесс, но он не работает.

Я даже пытался выполнить процесс обратного распространения с ручкой и бумагой, но рассчитанные мной градиенты не улучшают работу фильтров.Итак, я неправильно понимаю весь процесс?

Редактировать: я приведу пример моего понимания обратного распространения в CNN и проблемы с ним.

Рассмотрим рандомизированную входную матрицу для сверточного слоя:

1, 0, 1

0, 0, 1

1, 0, 0

И рандомизированная весовая матрица:

1, 0

0, 1

Выход будет (применяется активатор ReLU):

1, 1

0, 0

Цель для этого слоя - матрица 2x2, заполненная нулями.Таким образом, мы знаем, что матрица весов также должна быть заполнена нулями.

Ошибка:

-1, -1

0, 0

При применении процесса, как указано выше, градиенты:

-1, -1

1, 0

Итак, новая матрица весов:

2, 1

-1, 1

Это никуда не денется.Если я повторю процесс, веса фильтра просто перейдут к чрезвычайно высоким значениям.Значит, я где-то допустил ошибку.Так что же я делаю не так?

1 Ответ

0 голосов
/ 22 мая 2019

Я приведу вам полный пример, не буду коротким, но, надеюсь, вы его получите. Для простоты я опускаю как функции смещения, так и функции активации, но как только вы их получите, достаточно просто добавить их. Помните, что обратное распространение по сути то же самое в CNN, как и в простом MLP, но вместо умножения у вас будут свертки. Итак, вот мой образец:

Введите:

.7 -.3 -.7 .5
.9 -.5 -.2 .9
-.1 .8 -.3 -.5
0 .2 -.1 .6

Ядро:

.1 -.3
-.5 .7

Выполнение сверточного выхода (Результат 1-го сверточного слоя и ввод для 2-го сверточного слоя):

.32 .27 -.59
.99 -.52 -.55
-.45 .64 .13

L2 Ядро:

-.5 .1
.3 .9

Активация L2:

.73 .29
.37 -.63

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

-.07 .15
-.09 .02

Это всегда будет тот же размер, что и ваша активация перед выравниванием слоя. Теперь, чтобы вычислить дельту ядра для текущего L2, вы свяжете активацию L1 с вышеуказанной дельтой. Я не буду записывать это снова, но результат будет:

.17 .02
-.05 .13

Обновление ядра выполняется как L2.Kernel - = LR * ROT180 (dL2.K), что означает, что вы сначала поворачиваете вышеуказанную матрицу 2x2, а затем обновляете ядро. Вот для нашего игрушечного примера получается:

-.51 .11
.3  .9

Теперь, чтобы вычислить дельту для первого сверточного слоя, напомним, что в MLP у вас было следующее: current_delta * current_weight_matrix. Ну, в слое Conv, у вас почти тоже самое. Вы должны свернуть исходное Ядро (до обновления) слоя L2 с вашей дельтой для текущего слоя. Но эта свертка будет полной сверткой. Результат оказывается:

.04 -.08 .02
.02 -.13 .14
-.03 -.08 .01

С этим вы перейдете к 1-му сверточному слою и свернете исходный ввод с этой дельтой 3x3:

.16 .03
-.09 .16

И обновите ядро ​​L1 так же, как указано выше:

.08 -.29
-.5 .68

Тогда вы можете начать с подачи вперед. Вышеуказанные вычисления были округлены до 2 десятичных знаков, и для расчета новых значений в ядре использовалась скорость обучения .1

TLDR:

  • Вы получите дельта

  • Вы вычисляете следующую дельту, которая будет использоваться для следующего слоя как: FullConvolution (Li.Input, delta)

  • Вычисление дельты ядра, которая используется для обновления ядра: Convolution (Li.W, delta)

  • Перейти на следующий слой и повторить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...