Trong CNN, mỗi bộ lọc mới có các trọng số khác nhau cho từng kênh đầu vào hay là các trọng số giống nhau của từng bộ lọc được sử dụng trên các kênh đầu vào?


28

Hiểu biết của tôi là lớp tích chập của mạng nơ ron tích chập có bốn chiều: input_channels, filter_height, filter_ rắc, number_of_filters. Hơn nữa, theo hiểu biết của tôi, mỗi bộ lọc mới chỉ bị chia nhỏ trên TẤT CẢ các input_channels (hoặc bản đồ tính năng / kích hoạt từ lớp trước).

TUY NHIÊN, đồ họa bên dưới từ CS231 cho thấy mỗi bộ lọc (màu đỏ) đang được áp dụng cho KÊNH SINGLE, thay vì cùng một bộ lọc được sử dụng trên các kênh. Điều này dường như chỉ ra rằng có một bộ lọc riêng cho kênh EACH (trong trường hợp này tôi giả sử chúng là ba kênh màu của một hình ảnh đầu vào, nhưng điều tương tự sẽ áp dụng cho tất cả các kênh đầu vào).

Điều này gây nhầm lẫn - có một bộ lọc duy nhất khác nhau cho mỗi kênh đầu vào không?

nhập mô tả hình ảnh ở đây

Nguồn: http://cs231n.github.io/convolutional-networks/

Hình ảnh trên có vẻ mâu thuẫn với một trích đoạn trong cuốn "Những nguyên tắc cơ bản của việc học sâu" của O'reilly :

"... các bộ lọc không chỉ hoạt động trên một bản đồ tính năng duy nhất. Chúng hoạt động trên toàn bộ khối lượng bản đồ tính năng đã được tạo ở một lớp cụ thể ... Do đó, bản đồ tính năng phải có thể hoạt động theo khối lượng, không chỉ các khu vực "

... Ngoài ra, theo hiểu biết của tôi, những hình ảnh dưới đây đang chỉ ra bộ lọc CÙNG chỉ được tích hợp trên cả ba kênh đầu vào (trái ngược với những gì được hiển thị trong đồ họa CS231 ở trên):

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


Câu trả lời:


13

Trong mạng nơ ron tích chập, có một bộ lọc duy nhất cho mỗi kênh đầu vào hoặc là cùng một bộ lọc mới được sử dụng trên tất cả các kênh đầu vào?

Các cựu. Trong thực tế, có một hạt nhân riêng được xác định cho mỗi kết hợp kênh đầu vào / kênh đầu ra.

Thông thường đối với kiến ​​trúc CNN, trong một bộ lọc như được mô tả bởi number_of_filterstham số của bạn , có một nhân 2D trên mỗi kênh đầu vào. Có input_channels * number_of_filterscác bộ trọng số, mỗi bộ mô tả một hạt nhân chập. Vì vậy, các sơ đồ hiển thị một bộ trọng số cho mỗi kênh đầu vào cho mỗi bộ lọc là chính xác. Sơ đồ đầu tiên cũng cho thấy rõ rằng kết quả của việc áp dụng các hạt nhân đó được kết hợp bằng cách tổng hợp chúng và thêm độ lệch cho mỗi kênh đầu ra.

Điều này cũng có thể được xem như là sử dụng tích chập 3D cho mỗi kênh đầu ra, điều này xảy ra có cùng độ sâu với đầu vào. Đó là những gì sơ đồ thứ hai của bạn đang hiển thị, và cũng là những gì nhiều thư viện sẽ làm trong nội bộ. Về mặt toán học, đây là kết quả tương tự (với điều kiện độ sâu khớp chính xác), mặc dù loại lớp thường được dán nhãn là "Conv2D" hoặc tương tự. Tương tự nếu loại đầu vào của bạn vốn là 3D, chẳng hạn như voxels hoặc video, thì bạn có thể sử dụng lớp "Conv3D", nhưng bên trong nó có thể được triển khai dưới dạng tích chập 4D.


cảm ơn vì lời giải thích này Có vẻ như mỗi bộ lọc thực sự có số lượng input_channelsphiên bản với trọng lượng khác nhau . Bạn có nguồn "chính thức" xác nhận sự hiểu biết này không?
Ryan Chase

@RyanChase: Đúng vậy. Tôi sẽ chỉ cho bạn biết khóa học của Andrew Ng trên CNNs - bắt đầu từ đây với cách xử lý hình ảnh màu: coursera.org/learn/convolutional-neural-networks/lecture/ctQZz/ tựa
Neil Slater

Tôi muốn lưu ý rằng, trong nguồn đó ( cs231n.github.io/convolutional-networks ), các bộ lọc (trọng số hoặc kernesl) là các khối (tức là 3 chiều) và chúng có cùng chiều thứ 3 có một trong các đầu vào âm lượng. Hơn nữa, như hiện tại (ít nhất) đã được nêu trong nguồn đó, các khối lượng đã được cắt ngang qua chiều thứ 3 để trực quan hóa ứng dụng của bộ lọc vào âm lượng đầu vào tốt hơn. Tôi không nghĩ rằng, nói chung, "có một hạt nhân riêng được xác định cho mỗi kết hợp kênh đầu vào / kênh đầu ra." đúng.
nbro

Lưu ý rằng các bộ lọc (hoặc hạt nhân) là các trọng số cần phải học (nghĩa là chúng không cố định, nhưng chúng thực sự là các tham số của CNN). Có thể là chúng (tức là các lát của bộ lọc), ở cuối, giống nhau trên chiều thứ 3.
nbro

@nbro: Có, bạn có thể triển khai tích chập 2D trên nhiều lát 2D dưới dạng tích chập 3D đơn lẻ với độ sâu hạt nhân giống như số kênh. Về mặt toán học, điều này giống hệt với mô tả của tôi. Bạn cũng có thể xem nó như một mạng chuyển tiếp nguồn cấp dữ liệu được kết nối đầy đủ với các trọng số được chia sẻ (nhiều trong số đó là 0). Câu trả lời này tập trung vào chế độ xem của các bộ lọc 2D là gì, bởi vì OP đang hỏi về cách sắp xếp các bộ lọc 2D. Thực tế chúng có thể được sắp xếp thành một hạt nhân 3D lớn hơn, nhưng chúng vẫn được áp dụng như các hạt nhân 2D bằng cách sử dụng "thủ thuật" mà phép tích chập 3D là tương đương.
Neil Slater

12

Hình ảnh sau đây mà bạn sử dụng trong câu hỏi của mình, mô tả rất chính xác những gì đang xảy ra. Hãy nhớ rằng mỗi phần tử của bộ lọc 3D (khối màu xám) được tạo thành từ một giá trị ( 3x3x3=27giá trị) khác nhau . Vì vậy, ba bộ lọc kích thước 2D khác nhau 3x3có thể được ghép nối để tạo thành một bộ lọc kích thước 3D này3x3x3 .

kết nối

Đoạn 3x3x3RGB từ hình ảnh được nhân lên theo từng phần tử bằng bộ lọc 3D (hiển thị màu xám). Trong trường hợp này, bộ lọc có 3x3x3=27trọng lượng. Khi các trọng số này được nhân lên thành phần tử khôn ngoan và sau đó được tính tổng, nó mang lại một giá trị.


Vì vậy, có một bộ lọc riêng cho mỗi kênh đầu vào?

, có nhiều bộ lọc 2D như số lượng kênh đầu vào trong hình ảnh. Tuy nhiên , sẽ hữu ích nếu bạn nghĩ rằng đối với các ma trận đầu vào có nhiều hơn một kênh, chỉ có một bộ lọc 3D (như trong hình trên).


Vậy thì tại sao cái này được gọi là tích chập 2D (nếu bộ lọc là 3D và ma trận đầu vào là 3D)?

Đây là tích chập 2D vì các bước của bộ lọc chỉ dọc theo kích thước chiều cao và chiều rộng ( KHÔNG phải độ sâu) và do đó, đầu ra được tạo bởi tích chập này cũng là một ma trận 2D. Số lượng hướng di chuyển của bộ lọc xác định kích thước của tích chập.

Lưu ý: Nếu bạn xây dựng sự hiểu biết của mình bằng cách trực quan hóa một bộ lọc 3D thay vì nhiều bộ lọc 2D (một cho mỗi lớp), thì bạn sẽ dễ dàng hiểu được các kiến ​​trúc CNN nâng cao như Resnet, InceptionV3, v.v.


đây là một lời giải thích tốt, nhưng cụ thể hơn là câu hỏi tôi đang cố gắng hiểu là liệu các bộ lọc hoạt động trên mỗi kênh đầu vào có phải là bản sao của cùng một trọng lượng hay các trọng số hoàn toàn khác nhau hay không. Điều này thực sự không được hiển thị trong hình ảnh và trên thực tế đối với tôi, loại hình ảnh đó cho thấy rằng đó là cùng một trọng số được áp dụng cho mỗi kênh (vì cùng màu của chúng) ... Câu trả lời của mỗi người chơi @ @ilil, nghe có vẻ giống nhau bộ lọc thực sự có số lượng input_channelsphiên bản với các trọng lượng khác nhau . Nếu đây cũng là sự hiểu biết của bạn, có nguồn "chính thức" nào xác nhận điều này không?
Ryan Chase

Vâng, thực sự, đó cũng là sự hiểu biết của tôi. Đối với tôi, điều đó là rõ ràng khi tôi cố gắng nghĩ rằng khối màu xám đó bao gồm 27 giá trị trọng lượng khác nhau. Điều này có nghĩa là có 3 bộ lọc 2D khác nhau thay vì cùng một bộ lọc 2D được áp dụng cho mỗi lớp đầu vào.
Mohsin Bukhari

Tôi không thể tìm thấy bất kỳ nguồn chính thức để xác nhận điều này. Tuy nhiên, khi tôi đang cố gắng xoay quanh khái niệm tương tự này, tôi đã tạo ra một bộ lọc đầu vào và trọng lượng giả trong Tensorflow và quan sát đầu ra. Tôi hài lòng với điều đó. Nếu tôi tìm thấy bất kỳ lời giải thích chính thức . Tôi sẽ chỉnh sửa câu trả lời của tôi ở trên.
Mohsin Bukhari

Nếu bạn đi theo con đường Tensorflow. Bạn có thể in bộ lọc trọng lượng của mình sau khi hiển thị mẫu CNN giả của bạn một mẫu đầu vào.
Mohsin Bukhari

@Moshsin Bukhari Tôi chắc chắn sẽ cố gắng khám phá các bộ lọc trong TensorFlow. Bạn có sẵn sàng chia sẻ mã của mình về cách bạn đã tìm hiểu về những gì có trong bộ lọc không? Bạn có thể in các giá trị của bộ lọc ở mỗi bước trong mạng không?
Ryan Chase

3

Tôi đang theo dõi các câu trả lời ở trên với một ví dụ cụ thể với hy vọng sẽ làm rõ hơn cách thức tích chập hoạt động đối với các kênh đầu vào và đầu ra và các trọng số, tương ứng:

Đặt ví dụ như sau (wrt đến 1 lớp chập):

  • tenx đầu vào là 9x9x5, tức là 5 kênh đầu vào, vì vậy input_channels=5
  • kích thước bộ lọc / nhân là 4 x 4 và sải chân là 1
  • tenx đầu ra là 6x6x56, tức là 56 kênh đầu ra, vì vậy output_channels=56
  • loại đệm là 'GIÁ TRỊ' (nghĩa là không có đệm)

Chúng tôi chú ý điều đó:

  • do đầu vào có 5 kênh, kích thước bộ lọc trở thành 4 x 4, tức là có 5 bộ lọc 2D riêng biệt, có kích thước 4 x 4 (tức là mỗi bộ lọc có 16 trọng số); để kết hợp với đầu vào có kích thước 9x9x5, bộ lọc trở thành 3D và phải có kích thước 4x4x5
  • do đó: đối với mỗi kênh đầu vào, tồn tại một bộ lọc 2D riêng biệt với 16 trọng số khác nhau. Nói cách khác, số lượng bộ lọc 2D khớp với số lượng kênh đầu vào
  • vì có 56 kênh đầu ra, phải có 56 bộ lọc 3 chiều W0, W1, ..., W55 có kích thước 4x4x5 (xem trong đồ họa CS231 có 2 bộ lọc 3 chiều W0, W1 để tính đến 2 đầu ra các kênh), trong đó chiều thứ 3 của kích thước 5 thể hiện liên kết đến 5 kênh đầu vào (xem trong đồ họa CS231 mỗi bộ lọc 3D W0, W1 có chiều thứ 3 3, khớp với 3 kênh đầu vào)
  • do đó: số lượng bộ lọc 3D bằng với số lượng kênh đầu ra

Lớp chập đó do đó chứa:

56 bộ lọc 3 chiều có kích thước 4x4x5 (= 80 trọng lượng khác nhau cho mỗi kênh) để tính đến 56 kênh đầu ra trong đó mỗi kênh có giá trị cho chiều thứ 3 là 5 để khớp với 5 kênh đầu vào. Tổng cộng có

number_of_filters=input_channel*output_channels=5*56=280

Bộ lọc 2D có kích thước 4 x 4 (tức là tổng cộng 280x16 trọng lượng khác nhau).


0

Chỉ có hạn chế trong 2D. Tại sao?

Hãy tưởng tượng một lớp được kết nối đầy đủ.

Nó cực kỳ to lớn, mỗi nơ-ron sẽ được kết nối với các nơ-ron đầu vào có thể 1000x1000x3. Nhưng chúng ta biết rằng việc xử lý pixel gần đó có ý nghĩa, do đó chúng ta giới hạn bản thân trong một vùng lân cận 2D nhỏ, vì vậy mỗi nơ-ron chỉ được kết nối với một 3x3 gần các nơ-ron trong 2D. Chúng tôi không biết điều đó về các kênh, vì vậy chúng tôi kết nối với tất cả các kênh.

Tuy nhiên, sẽ có quá nhiều trọng lượng. Nhưng do tính bất biến dịch, bộ lọc hoạt động tốt ở một khu vực có lẽ hữu ích nhất ở một khu vực khác. Vì vậy, chúng tôi sử dụng cùng một tập các trọng số trên 2D. Một lần nữa, không có sự dịch chuyển như vậy giữa các kênh, vì vậy không có hạn chế nào như vậy.


0

Tham khảo phần "Kết nối cục bộ" trong http://cs231n.github.io/convolutional-networks/ và slide 7-18.

Siêu tham số "Trường tiếp nhận" của bộ lọc chỉ được xác định theo chiều cao và chiều rộng, vì độ sâu được cố định theo độ sâu của lớp trước.

LƯU Ý rằng "Phạm vi kết nối dọc theo trục độ sâu luôn bằng DEPTH của âm lượng đầu vào" -hoặc- DEPTH của bản đồ kích hoạt (trong trường hợp các lớp sau).

Theo trực giác, điều này phải là do thực tế là dữ liệu kênh hình ảnh được xen kẽ, không phải là phẳng. Bằng cách này, áp dụng bộ lọc có thể đạt được chỉ bằng cách nhân vectơ cột.

LƯU Ý rằng Mạng Convolutional tìm hiểu tất cả các tham số bộ lọc (bao gồm cả kích thước độ sâu) và chúng có tổng "h w input_layer_depth + 1 (bias)".


0

Tôi đề nghị chương 2.2.1 của luận án thạc sĩ của tôi như là một câu trả lời. Để thêm vào các câu trả lời còn lại:

Keras là bạn của bạn để hiểu những gì xảy ra:

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

cho

_________________________________________________________________
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

Cố gắng hình thành các lựa chọn của bạn. Điều đó có nghĩa gì cho các tham số nếu có trường hợp khác?

2400=32(355)

Cách tiếp cận này cũng giúp bạn với các loại lớp khác, không chỉ các lớp chập.

Cũng xin lưu ý rằng bạn có thể tự do triển khai các giải pháp khác nhau, có thể có số lượng tham số khác.


0

Chỉ cần làm cho hai chi tiết hoàn toàn rõ ràng:

NN3×3N2N

N2N3×3×

Cách dễ nhất để thuyết phục bản thân về điều này là tưởng tượng những gì xảy ra trong các tình huống khác và thấy rằng tính toán trở nên suy biến - nghĩa là, nếu bạn không xen kẽ và kết hợp lại các kết quả, thì các đầu ra khác nhau sẽ không thực sự làm gì cả - chúng 'd có tác dụng tương tự như một đầu ra duy nhất với các trọng số kết hợp.


0

Đối với bất kỳ ai đang cố gắng hiểu cách tính toán kết quả, đây là đoạn mã hữu ích trong 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))

Chạy này cho đầu ra sau:

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

Lưu ý cách mỗi kênh của tổng tích chập trên tất cả các đầu ra kênh trước đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.