ใน CNN ตัวกรองใหม่แต่ละตัวมีน้ำหนักแตกต่างกันสำหรับแต่ละช่องสัญญาณหรือมีน้ำหนักเท่ากันของตัวกรองแต่ละตัวที่ใช้ในช่องสัญญาณอินพุตหรือไม่


28

ความเข้าใจของฉันคือชั้นของเครือข่ายประสาทเทียมแบบ Convolutional มีสี่มิติคือ input_channels, filter_height, filter_width, number_of_filters ยิ่งไปกว่านั้นฉันเข้าใจว่าตัวกรองใหม่แต่ละตัวมีความซับซ้อนมากกว่า input_channels ทั้งหมด (หรือคุณสมบัติ / แผนที่เปิดใช้งานจากเลเยอร์ก่อนหน้า)

อย่างไรก็ตามกราฟิกด้านล่างจาก CS231 จะแสดงตัวกรองแต่ละตัว (สีแดง) ที่ใช้กับช่องเดี่ยวแทนที่จะใช้ตัวกรองเดียวกันที่ใช้ข้ามช่องสัญญาณ ดูเหมือนว่านี่จะบ่งบอกว่ามีตัวกรองแยกต่างหากสำหรับช่อง EACH (ในกรณีนี้ฉันสมมติว่าเป็นช่องสามสีของภาพที่ป้อน แต่สิ่งเดียวกันจะใช้กับช่องสัญญาณทั้งหมด)

นี่คือความสับสน - มีตัวกรองที่ไม่ซ้ำกันที่แตกต่างกันสำหรับแต่ละช่องสัญญาณเข้าหรือไม่?

enter image description here

ที่มา: http://cs231n.github.io/convolutional-networks/

ภาพด้านบนดูเหมือนจะขัดแย้งกับข้อความที่ตัดตอนมาจาก"พื้นฐานการเรียนรู้ลึก"ของ O'reilly :

"... ตัวกรองไม่เพียงทำงานบนแผนที่คุณลักษณะเดียวเท่านั้นพวกเขาทำงานบนไดรฟ์ข้อมูลแผนที่ทั้งหมดที่สร้างขึ้นในเลเยอร์เฉพาะ ... ด้วยเหตุนี้คุณสมบัติแผนที่จะต้องสามารถทำงานได้มากกว่าโวลุ่ม ไม่ใช่แค่พื้นที่ "

... นอกจากนี้มันเป็นความเข้าใจของฉันที่ภาพด้านล่างนี้แสดงให้เห็นว่าตัวกรองTHE SAMEนั้นได้รับการโน้มน้าวใจเหนือช่องสัญญาณอินพุตทั้งสาม (ขัดแย้งกับสิ่งที่แสดงในกราฟิก CS231 ด้านบน):

enter image description here

enter image description here


คำตอบ:


13

ในโครงข่ายประสาทเทียมที่มีเอกลักษณ์ตัวกรองสำหรับแต่ละช่องสัญญาณหรือมีตัวกรองใหม่เหมือนกันที่ใช้ในทุกช่องสัญญาณเข้าหรือไม่?

อดีต. ในความเป็นจริงมีเคอร์เนลแยกต่างหากที่กำหนดไว้สำหรับแต่ละช่องสัญญาณเข้า / รวมช่องสัญญาณออก

โดยทั่วไปแล้วสำหรับสถาปัตยกรรม CNN ในตัวกรองเดียวตามที่คุณอธิบายไว้ number_of_filtersพารามิเตอร์จะมีเคอร์เนล 2D หนึ่งตัวต่อหนึ่งช่องสัญญาณอินพุต มีinput_channels * number_of_filtersชุดตุ้มน้ำหนักซึ่งแต่ละชุดอธิบายเคอร์เนล convolution ดังนั้นแผนภาพที่แสดงน้ำหนักหนึ่งชุดต่อหนึ่งช่องสัญญาณสำหรับตัวกรองแต่ละตัวนั้นถูกต้อง แผนภาพแรกยังแสดงให้เห็นชัดเจนว่าผลลัพธ์ของการใช้เมล็ดเหล่านั้นถูกรวมเข้าด้วยกันโดยการรวมเข้าด้วยกันและเพิ่มอคติสำหรับแต่ละช่องสัญญาณ

นี้สามารถยังถูกมองว่าเป็นใช้บิด 3D สำหรับแต่ละช่องเอาท์พุทที่เกิดขึ้นจะมีความลึกเช่นเดียวกับการป้อนข้อมูล นี่คือสิ่งที่แผนภาพที่สองของคุณแสดงและสิ่งที่ห้องสมุดหลายแห่งจะทำภายใน ในทางคณิตศาสตร์นี่เป็นผลลัพธ์เดียวกัน (หากความลึกตรงกับ) แม้ว่าประเภทเลเยอร์จะมีป้ายกำกับว่า "Conv2D" หรือคล้ายกัน ในทำนองเดียวกันถ้าประเภทอินพุตของคุณเป็น 3D โดยเนื้อแท้เช่น voxels หรือวิดีโอคุณอาจใช้เลเยอร์ "Conv3D" แต่ภายในนั้นสามารถนำไปใช้ในรูปแบบการแปลง 4D ได้


ขอบคุณสำหรับคำอธิบายนี้ มันเสียงเหมือนตัวกรองแต่ละตัวจริงมีจำนวนinput_channelsรุ่นที่มีน้ำหนักที่แตกต่าง คุณมีแหล่ง "เป็นทางการ" ที่ยืนยันความเข้าใจนี้หรือไม่?
Ryan Chase

@RyanChase: ใช่ถูกต้อง ฉันจะชี้ให้คุณดูหลักสูตรของ CNNs ของ Andrew Ng - เริ่มต้นที่นี่ด้วยวิธีการประมวลผลภาพสี: coursera.org/learn/convolutional-neural-networks/lecture/ctQZz/
Neil Slater

ฉันต้องการทราบว่าในแหล่งนั้น ( cs231n.github.io/convolutional-networks ) ตัวกรอง (น้ำหนักหรือ kernesl) เป็นไดรฟ์ข้อมูล (เช่น 3 มิติ) และพวกเขามีมิติที่ 3 เดียวกันมีหนึ่งในอินพุต ปริมาณ นอกจากนี้ตามที่ระบุไว้ในแหล่งที่มาอย่างน้อยตอนนี้ไดรฟ์ข้อมูลได้ถูกแบ่งออกเป็นส่วน ๆ ในส่วนที่สามเพื่อให้เห็นภาพที่ชัดเจนยิ่งขึ้นเกี่ยวกับการประยุกต์ใช้ตัวกรองกับปริมาณอินพุต ฉันไม่คิดว่าโดยทั่วไปแล้ว "มีเคอร์เนลแยกต่างหากที่กำหนดไว้สำหรับแต่ละช่องสัญญาณเข้า / ช่องสัญญาณออกรวมกัน" ถูกต้อง.
nbro

โปรดทราบว่าตัวกรอง (หรือเมล็ด) เป็นน้ำหนักที่ต้องเรียนรู้ (เช่นตัวกรองไม่ได้ถูกแก้ไข แต่จริง ๆ แล้วเป็นพารามิเตอร์ของ CNN) อาจเป็นได้ว่าพวกเขาเป็น (เช่นชิ้นส่วนของตัวกรอง) ในตอนท้ายเหมือนกันในมิติที่ 3
nbro

@nbro: ใช่คุณสามารถใช้การโน้มน้าวใจแบบ 2 มิติกับ 2D หลาย ๆ ชิ้นในรูปแบบการสนทนา 3 มิติเดียวโดยมีความลึกของเคอร์เนลเท่ากับจำนวนช่อง ศาสตร์นี้เหมือนกับคำอธิบายของฉัน คุณยังสามารถดูได้ว่าเป็นเครือข่ายฟีดไปข้างหน้าที่ถูกตัดทอนอย่างสมบูรณ์ซึ่งมีน้ำหนักที่ใช้ร่วมกัน (ซึ่งส่วนใหญ่เป็นศูนย์) คำตอบนี้มุ่งเน้นไปที่มุมมองของตัวกรอง 2D คือเนื่องจาก OP ถามเกี่ยวกับวิธีการจัดเรียงตัวกรอง 2D ในความเป็นจริงพวกเขาอาจถูกจัดเรียงเป็นเคอร์เนล 3D ที่มีขนาดใหญ่ขึ้น แต่พวกเขายังคงถูกนำมาใช้เป็นเมล็ด 2 มิติโดยใช้ "เคล็ดลับ" ที่การบิด 3D นั้นเทียบเท่ากัน
Neil Slater

12

ภาพต่อไปนี้ที่คุณใช้ในคำถามของคุณอธิบายอย่างถูกต้องว่าเกิดอะไรขึ้น โปรดจำไว้ว่าแต่ละองค์ประกอบของตัวกรอง 3D (ลูกบาศก์สีเทา) ประกอบด้วยค่า ( 3x3x3=27ค่า) ต่างกัน ดังนั้นตัวกรอง 2Dขนาดแตกต่างกันสามตัว3x3สามารถต่อกันเพื่อสร้างขนาดตัวกรองสามมิติ3x3x3นี้

convnet2D

3x3x3ก้อน RGB จากภาพจะถูกคูณelementwiseโดยกรอง 3D (แสดงเป็นสีเทา) ในกรณีนี้ตัวกรองมี3x3x3=27น้ำหนัก เมื่อตุ้มน้ำหนักเหล่านี้ถูกคูณด้วยองค์ประกอบที่ชาญฉลาดแล้วนำมารวมกันมันจะให้ค่าเดียว


ดังนั้นจะมีตัวกรองแยกต่างหากสำหรับแต่ละช่องสัญญาณเข้าหรือไม่

ใช่มีตัวกรอง 2Dจำนวนมากเท่ากับจำนวนช่องสัญญาณเข้าในภาพ อย่างไรก็ตามมันช่วยถ้าคุณคิดว่าสำหรับเมทริกซ์อินพุตที่มีมากกว่าหนึ่งช่องจะมีตัวกรองสามมิติเพียงตัวเดียวเดียว (ดังที่แสดงในภาพด้านบน)


แล้วทำไมจึงเรียกว่าการโน้มน้าวแบบ 2 มิติ (หากตัวกรองเป็น 3D และเมทริกซ์อินพุตเป็น 3D)

นี่คือการบิดแบบ 2D เนื่องจากความก้าวหน้าของฟิลเตอร์เป็นไปตามขนาดความสูงและความกว้างเท่านั้น ( ไม่ใช่ความลึก) ดังนั้นผลลัพธ์ที่เกิดจากการบิดนี้จึงเป็นเมทริกซ์แบบ 2D จำนวนทิศทางการเคลื่อนที่ของฟิลเตอร์กำหนดขนาดของการบิด

หมายเหตุ: หากคุณสร้างความเข้าใจด้วยการแสดงฟิลเตอร์3D ตัวเดียวแทนตัวกรอง2Dหลายตัว (หนึ่งตัวสำหรับแต่ละเลเยอร์) จากนั้นคุณจะมีเวลาทำความเข้าใจกับสถาปัตยกรรม CNN ขั้นสูงเช่น Resnet, InceptionV3 เป็นต้น


นี่เป็นคำอธิบายที่ดี แต่โดยเฉพาะอย่างยิ่งคำถามที่ฉันพยายามเข้าใจคือตัวกรองที่ทำงานในแต่ละช่องสัญญาณเป็นสำเนาของน้ำหนักเดียวกันหรือน้ำหนักแตกต่างกันโดยสิ้นเชิง นี่ไม่ได้แสดงในภาพและอันที่จริงสำหรับฉันแล้วภาพประเภทนั้นแสดงให้เห็นว่ามันมีน้ำหนักแบบเดียวกันกับแต่ละช่อง (เนื่องจากสีเดียวกัน) ... ... ต่อคำตอบของผู้ตำหนินี้ ตัวกรองมีจำนวนinput_channelsเวอร์ชันที่มีน้ำหนักแตกต่างกัน หากนี่เป็นความเข้าใจของคุณมีแหล่ง "ทางการ" ยืนยันสิ่งนี้หรือไม่
Ryan Chase

ใช่แล้วนั่นเป็นความเข้าใจของฉันเช่นกัน สำหรับฉันนั่นชัดเจนเมื่อฉันพยายามคิดลูกบาศก์สีเทานั้นให้ประกอบด้วย 27 ค่าน้ำหนักที่แตกต่างกัน ซึ่งหมายความว่ามีตัวกรอง 2D ที่แตกต่างกัน 3 ตัวแทนที่จะเป็นตัวกรอง 2D เดียวกันที่ใช้กับแต่ละเลเยอร์อินพุต
Mohsin Bukhari

ฉันไม่พบแหล่งที่มาอย่างเป็นทางการสำหรับการยืนยันสิ่งนี้ อย่างไรก็ตามเมื่อฉันพยายามล้อมรอบแนวคิดเดียวกันนี้ฉันได้สร้างตัวกรองอินพุตและตัวกรองน้ำหนักใน Tensorflow และสังเกตผลลัพธ์ ฉันพอใจกับสิ่งนั้น หากฉันพบคำอธิบายอย่างเป็นทางการใด ๆ ฉันจะแก้ไขคำตอบของฉันด้านบน
Mohsin Bukhari

ถ้าคุณทำตามเส้นทาง Tensorflow คุณสามารถพิมพ์ตัวกรองน้ำหนักของคุณหลังจากที่แสดงตัวอย่างอินพุทของชั้น CNN
Mohsin Bukhari

@Moshsin Bukhari แน่นอนฉันจะพยายามสำรวจตัวกรองภายใน TensorFlow คุณยินดีที่จะแบ่งปันรหัสของคุณเกี่ยวกับวิธีการเกี่ยวกับการสำรวจสิ่งที่มีอยู่ในตัวกรองหรือไม่ คุณสามารถพิมพ์ค่าของตัวกรองในแต่ละขั้นตอนในเครือข่ายได้หรือไม่?
Ryan Chase

3

ฉันกำลังติดตามคำตอบข้างต้นด้วยตัวอย่างที่เป็นรูปธรรมด้วยความหวังที่จะอธิบายให้ชัดเจนยิ่งขึ้นว่าการทำงานของคอนโวลูชั่นนั้นเกี่ยวข้องกับอินพุตและเอาท์พุตและน้ำหนักอย่างไรตามลำดับ:

ให้ตัวอย่างเป็นดังนี้ (wrt to 1 convolutional layer):

  • เทนเซอร์อินพุทคือ 9x9x5, นั่นคือ 5 อินพุตอินพุทดังนั้น input_channels=5
  • ขนาดตัวกรอง / เคอร์เนลคือ 4x4 และก้าวย่างคือ 1
  • เทนเซอร์เอาท์พุทคือ 6x6x56 เช่น 56 ช่องสัญญาณออกดังนั้น output_channels=56
  • ชนิดของช่องว่างภายในคือ 'VALID' (เช่นไม่มีช่องว่างภายใน)

เราทราบว่า:

  • เนื่องจากอินพุตมี 5 ช่องมิติของตัวกรองจะกลายเป็น 4x4x5 นั่นคือมีตัวกรอง 2D ที่แยกจากกัน 5 ตัวซึ่งเป็นเอกลักษณ์ของ 4x4 ขนาด 4x4 (แต่ละตัวมีน้ำหนัก 16) เพื่อให้มั่นใจในการป้อนข้อมูลขนาด 9x9x5 ตัวกรองจะกลายเป็น 3 มิติและต้องมีขนาด 4x4x5
  • ดังนั้น: สำหรับแต่ละช่องสัญญาณมีตัวกรอง 2D ที่แตกต่างกันที่มีน้ำหนักต่างกัน 16 ตัว กล่าวอีกนัยหนึ่งจำนวนตัวกรอง 2D จะตรงกับจำนวนช่องสัญญาณเข้า
  • เนื่องจากมีช่องสัญญาณออก 56 ช่องจึงต้องมีตัวกรอง 3 มิติ W0, W1, ... , W55 ขนาด 4x4x5 (cf. ในกราฟิก CS231 มี 56 ตัวกรองมี 3 ตัวกรอง 3 มิติ W0, W1 สำหรับ 2 เอาต์พุต แชนเนล) โดยที่มิติที่ 3 ขนาด 5 แสดงลิงก์ไปยัง 5 ช่องสัญญาณ (เปรียบเทียบในกราฟิก CS231 แต่ละฟิลเตอร์ 3D W0, W1 มีมิติที่ 3 3 ซึ่งตรงกับ 3 ช่องสัญญาณเข้า)
  • ดังนั้น: จำนวนตัวกรอง 3D เท่ากับจำนวนช่องสัญญาณขาออก

เลเยอร์ convolutional นั้นมี:

56 3-dimensional filters of size 4x4x5 (= 80 different weights each) to account for the 56 output channels where each has a value for the 3rd dimension of 5 to match the 5 input channels. In total there are

number_of_filters=input_channel*output_channels=5*56=280

2D filters of size 4x4 (i.e. 280x16 different weights in total).


0

There are only restriction in 2D. Why?

Imagine a fully connected layer.

It'd be awfully huge, each neuron would be connected to maybe 1000x1000x3 inputs neurons. But we know that processing nearby pixel makes sense, therefore we limit ourselves to a small 2D-neighborhood, so each neuron is connected to only a 3x3 near neurons in 2D. We don't know such a thing about channels, so we connect to all channels.

Still, there would be too many weights. But because of the translation invariance, a filter working well in one area is most probably useful in a different area. So we use the same set of weights across 2D. Again, there's no such translation invariance between channels, so there's no such restriction there.


0

Refer to "Local Connectivity" section in http://cs231n.github.io/convolutional-networks/ and slide 7-18.

"Receptive Field" hyperparameter of filter is defined by height & width only, as depth is fixed by preceding layer's depth.

NOTE that "The extent of the connectivity along the depth axis is always equal to the DEPTH of the input volume" -or- DEPTH of activation map (in case of later layers).

Intuitively, this must be due to the fact that image channels data are interleaved, not planar. This way, applying filter can be achieved simply by column vectors multiplication.

NOTE that Convolutional Network learns all the filter parameters (including the depth dimension) and they are total "hwinput_layer_depth + 1 (bias)".


0

I recommend chapter 2.2.1 of my masters thesis as an answer. To add to the remaining answers:

Keras is your friend to understand what happens:

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())

gives

_________________________________________________________________
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

Try to formulate your options. What would that mean for the parameters if something else would be the case?

Hint: 2400=32(355)

This approach also helps you with other layer types, not only convolutional layers.

Please also note that you are free to implement different solutions, that might have other numbers of parameters.


0

Just to make two details absolutely clear:

Say you have N 2D input channels going to N 2D output channels. The total number of 2D 3×3 filter weights is actually N2. But how is the 3D convolution affected, i.e., if every input channel contributes one 2D layer to every output channel, then each output channel is composed initially of N 2D layers, how are they combined?

This tends to be glossed over in almost every publication I've seen, but the key concept is the N2 2D output channels are interleaved with each other to form the N output channels, like shuffled card decks, before being summed together. This is all logical when you realize that along the channel dimensions of a convolution (which is never illustrated), you actually have a fully connected layer! Every input 2D channel, multiplied by a unique 3×3 filter, yields a 2D output layer contribution to a single output channel. Once combined, every output layer is a combination of every input layer × a unique filter. It's an all to all contribution.

The easiest way to convince yourself of this is to imagine what happens in other scenarios and see that the computation becomes degenerate - that is, if you don't interleave and recombine the results, then the different outputs wouldn't actually do anything - they'd have the same effect as a single output with combined weights.


0

For anyone trying to understand how convolutions are calculated, here is a useful code snippet in 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))

Running this gives the following output:

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])

Notice how the each channel of the convolution sums over all previous channels outputs.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.