В CNN каждый новый фильтр имеет разные веса для каждого входного канала, или одинаковые веса каждого фильтра используются для входных каналов?


28

Насколько я понимаю, сверточный слой сверточной нейронной сети имеет четыре измерения: input_channels, filter_height, filter_width, number_of_filters. Кроме того, я понимаю, что каждый новый фильтр просто замыкается на ВСЕ входные каналы (или карты возможностей / активации из предыдущего слоя).

ОДНАКО, на рисунке ниже из CS231 показан каждый фильтр (красного цвета), применяемый к ОДНОМУ КАНАЛУ, а не один и тот же фильтр, используемый для разных каналов. Кажется, это указывает на то, что для КАЖДОГО канала есть отдельный фильтр (в данном случае я предполагаю, что это три цветовых канала входного изображения, но то же самое применимо ко всем входным каналам).

Это сбивает с толку - есть ли разные уникальные фильтры для каждого входного канала?

введите описание изображения здесь

Источник: http://cs231n.github.io/convolutional-networks/

Приведенное выше изображение кажется противоречивым отрывку из «Основ глубокого обучения» О'рейли :

«... фильтры работают не только с одной картой объектов. Они работают со всем объемом карт объектов, созданных на определенном слое ... В результате карты объектов должны работать с объемами, не только области "

... Кроме того, я понимаю, что эти изображения , показанные ниже, показывают, что один и тот же фильтр просто свернут по всем трем входным каналам (что противоречит тому, что показано на рисунке CS231 выше):

введите описание изображения здесь

введите описание изображения здесь


Ответы:


13

В сверточной нейронной сети существует ли уникальный фильтр для каждого входного канала или же все новые фильтры используются во всех входных каналах?

Первый. Фактически для каждой комбинации входного канала / выходного канала определено отдельное ядро.

Обычно для архитектуры CNN в одном фильтре, как описано в вашем number_of_filtersпараметре, имеется одно двумерное ядро ​​на входной канал. Существуют input_channels * number_of_filtersнаборы весов, каждый из которых описывает ядро ​​свертки. Таким образом, диаграммы, показывающие один набор весов на входной канал для каждого фильтра, верны. Первая диаграмма также ясно показывает, что результаты применения этих ядер объединяются путем суммирования их и добавления смещения для каждого выходного канала.

Это также можно рассматривать как использование трехмерной свертки для каждого выходного канала, которая имеет ту же глубину, что и вход. Это то, что показывает ваша вторая диаграмма, а также то, что многие библиотеки будут делать внутри. Математически это тот же результат (при условии, что глубины точно совпадают), хотя тип слоя обычно помечается как «Conv2D» или подобный. Точно так же, если ваш тип ввода по своей сути трехмерный, такой как вокселы или видео, вы можете использовать слой «Conv3D», но внутри он вполне может быть реализован как свертка 4D.


спасибо за это объяснение. Похоже, каждый фильтр имеет несколько input_channelsверсий с разным весом . Есть ли у вас «официальный» источник, подтверждающий это понимание?
Райан Чейз

@RyanChase: Да, это правильно. Я бы просто указал вам на курс Эндрю Нг по CNN - начиная с того, как будет обрабатываться цветное изображение: coursera.org/learn/convolutional-neural-networks/lecture/ctQZz/…
Нил Слэйтер

Я хотел бы отметить, что в этом источнике ( cs231n.github.io/convolutional-networks ) фильтры (веса или kernesl) являются объемами (то есть 3-мерными), и у них есть то же 3-е измерение, которое имеет одно из входных объем. Кроме того, как (по крайней мере) сейчас указано в этом источнике, тома были разрезаны по 3-му измерению, чтобы лучше визуализировать применение фильтра к входному объему. Я не думаю, что, в общем, «для каждой комбинации входного канала / выходного канала определено отдельное ядро». правильно.
nbro

Обратите внимание, что фильтры (или ядра) являются весами, которые необходимо изучить (т.е. они не являются фиксированными, но на самом деле они являются параметрами CNN). Возможно, что они (то есть срезы фильтра) в конце одинаковы для 3-го измерения.
nbro

@nbro: Да, вы можете реализовать двухмерную свертку на нескольких 2D-срезах в виде одной трехмерной свертки с глубиной ядра, равной количеству каналов. Математически это идентично моему описанию. Вы также можете просмотреть его как укороченную полностью подключенную сеть прямой связи с общими весами (многие из которых равны нулю). Этот ответ фокусируется на том, как выглядит 2D-фильтры, потому что OP спрашивает о том, как расположены 2D-фильтры. На самом деле они могут быть организованы в более крупное трехмерное ядро, но они по-прежнему применяются в качестве двумерных ядер, используя «трюк», который эквивалентен трехмерной свертке.
Нил Слэйтер

12

Следующая картинка, которую вы использовали в своем вопросе, очень точно описывает происходящее. Помните, что каждый элемент трехмерного фильтра (серый куб) состоит из разных значений ( 3x3x3=27значений). Таким образом, три разных 2D-фильтра размера 3x3могут быть объединены, чтобы сформировать этот один 3D-фильтр размера 3x3x3.

convnet2D

3x3x3RGB - фрагмент из картины умножает поэлементно с помощью 3D - фильтра (показано серого цвета). В этом случае фильтр имеет 3x3x3=27весовые коэффициенты. Когда эти веса умножаются по элементам, а затем суммируются, это дает одно значение.


Итак, есть ли отдельный фильтр для каждого входного канала?

ДА , количество 2D-фильтров равно количеству входных каналов в изображении. Однако полезно, если вы считаете, что для входных матриц с более чем одним каналом существует только один 3D-фильтр (как показано на рисунке выше).


Тогда почему это называется 2D-сверткой (если фильтр 3D и входная матрица 3D)?

Это двумерная свертка, потому что шаги фильтра идут только по размерам высоты и ширины ( НЕ глубина), и, следовательно, выходные данные, полученные этой сверткой, также являются двумерной матрицей. Количество направлений движения фильтра определяет размеры свертки.

Примечание. Если вы развиваете свое понимание, визуализируя один 3D-фильтр вместо нескольких 2D-фильтров (по одному для каждого слоя), то вам будет легко понять сложные архитектуры CNN, такие как Resnet, InceptionV3 и т. Д.


это хорошее объяснение, но более конкретно вопрос, который я пытаюсь понять, состоит в том, являются ли фильтры, которые работают на каждом входном канале, копиями одинаковых или совершенно разных весов. На самом деле это не показано на изображении, и на самом деле для меня это изображение предполагает, что к каждому каналу применяются одинаковые веса (так как они имеют одинаковый цвет) ... В ответе @neil slater, звучит как каждый Фильтр фактически имеет количество input_channelsверсий с разным весом. Если это также ваше понимание, есть ли «официальный» источник, подтверждающий это?
Райан Чейз

Да, действительно, это тоже мое понимание. Для меня это было ясно, когда я пытался представить, что этот серый куб состоит из 27 различных значений веса. Это означает, что есть 3 разных 2D фильтра, а не один и тот же 2D фильтр, применяемый к каждому входному слою.
Мохсин Бухари

Я не смог найти никакого официального источника, подтверждающего это. Однако, когда я пытался обернуть голову вокруг этой же концепции, я создал фиктивный входной и весовой фильтры в Tensorflow и наблюдал результат. Я был доволен этим. Если я найду какой-либо официальный объяснение. Я отредактирую свой ответ выше.
Мохсин Бухари

Если вы следуете пути Tensorflow. Вы можете напечатать свой весовой фильтр после показа своего фиктивного слоя CNN входного образца.
Мохсин Бухари

@Moshsin Bukhari Я обязательно попробую изучить фильтры в TensorFlow. Хотели бы вы поделиться своим кодом для изучения того, что содержится в фильтрах? Вы можете напечатать значения фильтра, например, на каждом шаге в сети?
Райан Чейз

3

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

Пусть пример будет следующим (по отношению к 1 сверточному слою):

  • входной тензор 9х9х5, т.е. 5 входных каналов, поэтому input_channels=5
  • размер фильтра / ядра 4x4 и шаг 1
  • выходной тензор 6х6х56, т.е. 56 выходных каналов, поэтому output_channels=56
  • тип заполнения - «VALID» (т.е. без заполнения)

Мы отмечаем, что:

  • поскольку на входе имеется 5 каналов, размер фильтра становится 4x4x5, то есть имеется 5 отдельных уникальных 2D-фильтров размером 4x4 (т.е. каждый имеет 16 весов); для свертки на входе размера 9x9x5 фильтр становится трехмерным и должен иметь размер 4x4x5
  • поэтому: для каждого входного канала существует отдельный 2D-фильтр с 16 различными весами каждый. Другими словами, количество 2D-фильтров соответствует количеству входных каналов.
  • поскольку имеется 56 выходных каналов, должно быть 56 трехмерных фильтров W0, W1, ..., W55 размером 4x4x5 (см. на графике CS231 есть 2 трехмерных фильтра W0, W1 для учета двух выходных данных). каналы), где 3-е измерение размера 5 представляет ссылку на 5 входных каналов (см. в графике CS231 каждый 3D-фильтр W0, W1 имеет 3-е измерение 3, которое соответствует 3 входным каналам)
  • следовательно: количество 3D-фильтров равно количеству выходных каналов

Этот сверточный слой, таким образом, содержит:

56 трехмерных фильтров размером 4x4x5 (= 80 различных весов каждый) для учета 56 выходных каналов, где каждый имеет значение для 3-го измерения 5, чтобы соответствовать 5 входным каналам. Всего есть

number_of_filters=input_channel*output_channels=5*56=280

2D-фильтры размером 4х4 (т.е. всего 280х16 различных весов).


0

Есть только ограничение в 2D. Зачем?

Представьте себе полностью связанный слой.

Это было бы ужасно огромно, каждый нейрон был бы подключен к 1000x1000x3 входным нейронам. Но мы знаем, что обработка близлежащего пикселя имеет смысл, поэтому мы ограничиваемся небольшой 2D-окрестностью, поэтому каждый нейрон связан только с 3x3 рядом нейронов в 2D. Мы не знаем ничего о каналах, поэтому подключаемся ко всем каналам.

Тем не менее, было бы слишком много весов. Но из-за неизменности перевода, фильтр, работающий хорошо в одной области, наиболее вероятно полезен в другой области. Поэтому мы используем один и тот же набор весов в 2D. Опять же, нет такой переводной инвариантности между каналами, поэтому там нет такого ограничения.


0

Обратитесь к разделу «Локальное подключение» в http://cs231n.github.io/convolutional-networks/ и слайд 7-18.

Гиперпараметр «Receptive Field» фильтра определяется только высотой и шириной, поскольку глубина определяется глубиной предыдущего слоя.

Обратите внимание, что «Степень подключения по оси глубины всегда равна ГЛУБИНЕ входного объема» или ГЛУБИНА карты активации (в случае более поздних слоев).

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

ОБРАТИТЕ ВНИМАНИЕ, что Сверточная Сеть изучает все параметры фильтра (включая измерение глубины), и они составляют "h w input_layer_depth + 1 (bias)".


0

Я рекомендую главу 2.2.1 моей магистерской диссертации в качестве ответа. Чтобы добавить к оставшимся ответам:

Керас твой друг, чтобы понять, что происходит:

from keras.models import Sequential
from keras.layers import Conv2D

model = Sequential()
model.add(Conv2D(32, input_shape=(28, 28, 3),
          kernel_size=(5, 5),
          padding='same',
          use_bias=False))
model.add(Conv2D(17, (3, 3), padding='same', use_bias=False))
model.add(Conv2D(13, (3, 3), padding='same', use_bias=False))
model.add(Conv2D(7, (3, 3), padding='same', use_bias=False))
model.compile(loss='categorical_crossentropy', optimizer='adam')

print(model.summary())

дает

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 28, 28, 32)        2400      
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 28, 28, 17)        4896      
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 28, 28, 13)        1989      
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 28, 28, 7)         819       
=================================================================
Total params: 10,104

Попробуйте сформулировать ваши варианты. Что это будет означать для параметров, если что-то еще будет иметь место?

Подсказка: 2400знак равно32(355)

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

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


0

Просто чтобы сделать две детали абсолютно ясными:

Скажи у тебя есть N 2D входные каналы собираются N2D выходные каналы. Общее количество 2D3×3 Вес фильтра на самом деле N2, Но как это влияет на трехмерную свертку, т. Е. Если каждый входной канал вносит один 2D-слой в каждый выходной канал, то каждый выходной канал изначально состоит изN 2D слои, как они объединены?

Как правило, это скрыто почти во всех публикациях, которые я видел, но ключевой концепцией является N2 2D выходные каналы чередуются друг с другом, образуя Nвыходные каналы, такие как перетасованные колоды, перед суммированием. Это все логично, когда вы понимаете, что вдоль размеров канала свертки (что никогда не иллюстрируется) у вас фактически есть полностью связанный слой! Каждый входной 2D канал умножается на уникальный3×3фильтр, дает вклад 2D выходного слоя в один выходной канал. После объединения каждый выходной слой является комбинацией каждого входного слоя×уникальный фильтр. Это все для всего вклада.

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


0

Для тех, кто пытается понять, как вычисляются свертки, вот полезный фрагмент кода в Pytorch:

batch_size = 1
height = 3 
width = 3
conv1_in_channels = 2
conv1_out_channels = 2
conv2_out_channels = 2
kernel_size = 2
# (N, C_in, H, W) is shape of all tensors. (batch_size, channels, height, width)
input = torch.Tensor(np.arange(0, batch_size*height*width*in_channels).reshape(batch_size, in_channels, height, width))
conv1 = nn.Conv2d(in_channels, conv1_out_channels, kernel_size, bias=False) # no bias to make calculations easier
# set the weights of the convolutions to make the convolutions easier to follow
nn.init.constant_(conv1.weight[0][0], 0.25)
nn.init.constant_(conv1.weight[0][1], 0.5)
nn.init.constant_(conv1.weight[1][0], 1) 
nn.init.constant_(conv1.weight[1][1], 2) 
out1 = conv1(input) # compute the convolution

conv2 = nn.Conv2d(conv1_out_channels, conv2_out_channels, kernel_size, bias=False)
nn.init.constant_(conv2.weight[0][0], 0.25)
nn.init.constant_(conv2.weight[0][1], 0.5)
nn.init.constant_(conv2.weight[1][0], 1) 
nn.init.constant_(conv2.weight[1][1], 2) 
out2 = conv2(out1) # compute the convolution

for tensor, name in zip([input, conv1.weight, out1, conv2.weight, out2], ['input', 'conv1', 'out1', 'conv2', 'out2']):
    print('{}: {}'.format(name, tensor))
    print('{} shape: {}'.format(name, tensor.shape))

Запуск этого дает следующий вывод:

input: tensor([[[[ 0.,  1.,  2.],
          [ 3.,  4.,  5.],
          [ 6.,  7.,  8.]],

         [[ 9., 10., 11.],
          [12., 13., 14.],
          [15., 16., 17.]]]])
input shape: torch.Size([1, 2, 3, 3])
conv1: Parameter containing:
tensor([[[[0.2500, 0.2500],
          [0.2500, 0.2500]],

         [[0.5000, 0.5000],
          [0.5000, 0.5000]]],


        [[[1.0000, 1.0000],
          [1.0000, 1.0000]],

         [[2.0000, 2.0000],
          [2.0000, 2.0000]]]], requires_grad=True)
conv1 shape: torch.Size([2, 2, 2, 2])
out1: tensor([[[[ 24.,  27.],
          [ 33.,  36.]],

         [[ 96., 108.],
          [132., 144.]]]], grad_fn=<MkldnnConvolutionBackward>)
out1 shape: torch.Size([1, 2, 2, 2])
conv2: Parameter containing:
tensor([[[[0.2500, 0.2500],
          [0.2500, 0.2500]],

         [[0.5000, 0.5000],
          [0.5000, 0.5000]]],


        [[[1.0000, 1.0000],
          [1.0000, 1.0000]],

         [[2.0000, 2.0000],
          [2.0000, 2.0000]]]], requires_grad=True)
conv2 shape: torch.Size([2, 2, 2, 2])
out2: tensor([[[[ 270.]],

         [[1080.]]]], grad_fn=<MkldnnConvolutionBackward>)
out2 shape: torch.Size([1, 2, 1, 1])

Обратите внимание на то, как каждый канал свертки суммирует все выходные сигналы предыдущих каналов.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.