.. _sec_nin:
Mạng trong mạng (Nin)
=====================
LeNet, AlexNet và VGG đều chia sẻ một mẫu thiết kế chung: trích xuất các
tính năng khai thác cấu trúc *không gian* thông qua một chuỗi các lớp
phức tạp và tập hợp và sau đó xử lý các biểu diễn thông qua các lớp được
kết nối hoàn toàn. Những cải tiến trên LeNet của AlexNet và VGG chủ yếu
nằm ở cách các mạng sau này mở rộng và làm sâu sắc thêm hai mô-đun này.
Ngoài ra, người ta có thể tưởng tượng sử dụng các lớp được kết nối hoàn
toàn trước đó trong quá trình này. Tuy nhiên, việc sử dụng bất cẩn các
lớp dày đặc có thể từ bỏ cấu trúc không gian của biểu diễn hoàn toàn,
*mạng trong mạng* (\* NiN\*) khối cung cấp một giải pháp thay thế. Chúng
được đề xuất dựa trên một cái nhìn sâu sắc rất đơn giản: sử dụng MLP
trên các kênh cho mỗi pixel riêng biệt :cite:`Lin.Chen.Yan.2013`.
NiN Blocks
----------
Nhớ lại rằng các đầu vào và đầu ra của các lớp phức tạp bao gồm các hàng
chục bốn chiều với các trục tương ứng với ví dụ, kênh, chiều cao và
chiều rộng. Cũng nhớ lại rằng các đầu vào và đầu ra của các lớp được kết
nối hoàn toàn thường là các hàng chục hai chiều tương ứng với ví dụ và
tính năng. Ý tưởng đằng sau Nin là áp dụng một lớp được kết nối hoàn
toàn tại mỗi vị trí pixel (cho mỗi chiều cao và chiều rộng). Nếu chúng
ta buộc trọng lượng trên mỗi vị trí không gian, chúng ta có thể nghĩ đây
là một lớp ghép :math:`1\times 1` (như được mô tả trong
:numref:`sec_channels`) hoặc như một lớp được kết nối hoàn toàn hoạt
động độc lập trên mỗi vị trí pixel. Một cách khác để xem điều này là
nghĩ về từng phần tử trong chiều không gian (chiều cao và chiều rộng)
tương đương với một ví dụ và một kênh tương đương với một đối tượng.
:numref:`fig_nin` minh họa sự khác biệt về cấu trúc chính giữa VGG và
Nin, và các khối của chúng. Khối Nin bao gồm một lớp phức tạp tiếp theo
là hai lớp ghép :math:`1\times 1` hoạt động như các lớp được kết nối
hoàn toàn trên mỗi pixel với các kích hoạt ReLU. Hình dạng cửa sổ phức
tạp của lớp đầu tiên thường được đặt bởi người dùng. Các hình dạng cửa
sổ tiếp theo được cố định thành :math:`1 \times 1`.
.. _fig_nin:
.. figure:: ../img/nin.svg
:width: 600px
Comparing architectures of VGG and NiN, and their blocks.
.. raw:: html
.. raw:: html
.. code:: python
from mxnet import np, npx
from mxnet.gluon import nn
from d2l import mxnet as d2l
npx.set_np()
def nin_block(num_channels, kernel_size, strides, padding):
blk = nn.Sequential()
blk.add(nn.Conv2D(num_channels, kernel_size, strides, padding,
activation='relu'),
nn.Conv2D(num_channels, kernel_size=1, activation='relu'),
nn.Conv2D(num_channels, kernel_size=1, activation='relu'))
return blk
.. raw:: html
.. raw:: html
.. code:: python
import torch
from torch import nn
from d2l import torch as d2l
def nin_block(in_channels, out_channels, kernel_size, strides, padding):
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU())
.. raw:: html
.. raw:: html
.. code:: python
import tensorflow as tf
from d2l import tensorflow as d2l
def nin_block(num_channels, kernel_size, strides, padding):
return tf.keras.models.Sequential([
tf.keras.layers.Conv2D(num_channels, kernel_size, strides=strides,
padding=padding, activation='relu'),
tf.keras.layers.Conv2D(num_channels, kernel_size=1,
activation='relu'),
tf.keras.layers.Conv2D(num_channels, kernel_size=1,
activation='relu')])
.. raw:: html
.. raw:: html
Mô hình NiN
-----------
Mạng Nin ban đầu được đề xuất ngay sau AlexNet và rõ ràng rút ra một số
cảm hứng. Nin sử dụng các lớp phức tạp với hình dạng cửa sổ
:math:`11\times 11`, :math:`5\times 5`, và :math:`3\times 3`, và các số
kênh đầu ra tương ứng giống như trong AlexNet. Mỗi khối Nin được theo
sau bởi một lớp tổng hợp tối đa với một sải chân là 2 và một hình dạng
cửa sổ là :math:`3\times 3`.
Một điểm khác biệt đáng kể giữa Nin và AlexNet là Nin tránh hoàn toàn
các lớp được kết nối hoàn toàn. Thay vào đó, Nin sử dụng một khối Nin
với một số kênh đầu ra bằng số lớp nhãn, tiếp theo là một lớp tổng hợp
trung bình *global*, mang lại một vectơ của logits. Một ưu điểm của
thiết kế của Nin là nó làm giảm đáng kể số lượng các thông số mô hình
cần thiết. Tuy nhiên, trong thực tế, thiết kế này đôi khi đòi hỏi thời
gian đào tạo mô hình tăng lên.
.. raw:: html
.. raw:: html
.. code:: python
net = nn.Sequential()
net.add(nin_block(96, kernel_size=11, strides=4, padding=0),
nn.MaxPool2D(pool_size=3, strides=2),
nin_block(256, kernel_size=5, strides=1, padding=2),
nn.MaxPool2D(pool_size=3, strides=2),
nin_block(384, kernel_size=3, strides=1, padding=1),
nn.MaxPool2D(pool_size=3, strides=2),
nn.Dropout(0.5),
# There are 10 label classes
nin_block(10, kernel_size=3, strides=1, padding=1),
# The global average pooling layer automatically sets the window shape
# to the height and width of the input
nn.GlobalAvgPool2D(),
# Transform the four-dimensional output into two-dimensional output
# with a shape of (batch size, 10)
nn.Flatten())
.. raw:: html
.. raw:: html
.. code:: python
net = nn.Sequential(
nin_block(1, 96, kernel_size=11, strides=4, padding=0),
nn.MaxPool2d(3, stride=2),
nin_block(96, 256, kernel_size=5, strides=1, padding=2),
nn.MaxPool2d(3, stride=2),
nin_block(256, 384, kernel_size=3, strides=1, padding=1),
nn.MaxPool2d(3, stride=2),
nn.Dropout(0.5),
# There are 10 label classes
nin_block(384, 10, kernel_size=3, strides=1, padding=1),
nn.AdaptiveAvgPool2d((1, 1)),
# Transform the four-dimensional output into two-dimensional output with a
# shape of (batch size, 10)
nn.Flatten())
.. raw:: html
.. raw:: html
.. code:: python
def net():
return tf.keras.models.Sequential([
nin_block(96, kernel_size=11, strides=4, padding='valid'),
tf.keras.layers.MaxPool2D(pool_size=3, strides=2),
nin_block(256, kernel_size=5, strides=1, padding='same'),
tf.keras.layers.MaxPool2D(pool_size=3, strides=2),
nin_block(384, kernel_size=3, strides=1, padding='same'),
tf.keras.layers.MaxPool2D(pool_size=3, strides=2),
tf.keras.layers.Dropout(0.5),
# There are 10 label classes
nin_block(10, kernel_size=3, strides=1, padding='same'),
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Reshape((1, 1, 10)),
# Transform the four-dimensional output into two-dimensional output
# with a shape of (batch size, 10)
tf.keras.layers.Flatten(),
])
.. raw:: html
.. raw:: html
Chúng ta tạo ra một ví dụ dữ liệu để xem hình dạng đầu ra của mỗi block.
.. raw:: html
.. raw:: html
.. code:: python
X = np.random.uniform(size=(1, 1, 224, 224))
net.initialize()
for layer in net:
X = layer(X)
print(layer.name, 'output shape:\t', X.shape)
.. parsed-literal::
:class: output
sequential1 output shape: (1, 96, 54, 54)
pool0 output shape: (1, 96, 26, 26)
sequential2 output shape: (1, 256, 26, 26)
pool1 output shape: (1, 256, 12, 12)
sequential3 output shape: (1, 384, 12, 12)
pool2 output shape: (1, 384, 5, 5)
dropout0 output shape: (1, 384, 5, 5)
sequential4 output shape: (1, 10, 5, 5)
pool3 output shape: (1, 10, 1, 1)
flatten0 output shape: (1, 10)
.. raw:: html
.. raw:: html
.. code:: python
X = torch.rand(size=(1, 1, 224, 224))
for layer in net:
X = layer(X)
print(layer.__class__.__name__,'output shape:\t', X.shape)
.. parsed-literal::
:class: output
Sequential output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Sequential output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Sequential output shape: torch.Size([1, 384, 12, 12])
MaxPool2d output shape: torch.Size([1, 384, 5, 5])
Dropout output shape: torch.Size([1, 384, 5, 5])
Sequential output shape: torch.Size([1, 10, 5, 5])
AdaptiveAvgPool2d output shape: torch.Size([1, 10, 1, 1])
Flatten output shape: torch.Size([1, 10])
.. raw:: html
.. raw:: html
.. code:: python
X = tf.random.uniform((1, 224, 224, 1))
for layer in net().layers:
X = layer(X)
print(layer.__class__.__name__,'output shape:\t', X.shape)
.. parsed-literal::
:class: output
Sequential output shape: (1, 54, 54, 96)
MaxPooling2D output shape: (1, 26, 26, 96)
Sequential output shape: (1, 26, 26, 256)
MaxPooling2D output shape: (1, 12, 12, 256)
Sequential output shape: (1, 12, 12, 384)
MaxPooling2D output shape: (1, 5, 5, 384)
Dropout output shape: (1, 5, 5, 384)
Sequential output shape: (1, 5, 5, 10)
GlobalAveragePooling2D output shape: (1, 10)
Reshape output shape: (1, 1, 1, 10)
Flatten output shape: (1, 10)
.. raw:: html
.. raw:: html
Đào tạo
-------
Như trước đây chúng ta sử dụng Fashion-MNIST để đào tạo mô hình. Đào tạo
của Nin tương tự như cho AlexNet và VGG.
.. raw:: html
.. raw:: html
.. code:: python
lr, num_epochs, batch_size = 0.1, 10, 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
.. parsed-literal::
:class: output
loss 1.843, train acc 0.316, test acc 0.568
2926.6 examples/sec on gpu(0)
.. figure:: output_nin_8ad4f3_39_1.svg
.. raw:: html
.. raw:: html
.. code:: python
lr, num_epochs, batch_size = 0.1, 10, 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
.. parsed-literal::
:class: output
loss 0.381, train acc 0.858, test acc 0.863
3160.4 examples/sec on cuda:0
.. figure:: output_nin_8ad4f3_42_1.svg
.. raw:: html
.. raw:: html
.. code:: python
lr, num_epochs, batch_size = 0.1, 10, 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
.. parsed-literal::
:class: output
loss 0.336, train acc 0.874, test acc 0.876
3264.0 examples/sec on /GPU:0
.. parsed-literal::
:class: output
.. figure:: output_nin_8ad4f3_45_2.svg
.. raw:: html
.. raw:: html
Tóm tắt
-------
- Nin sử dụng các khối bao gồm một lớp phức tạp và nhiều lớp ghép
:math:`1\times 1`. Điều này có thể được sử dụng trong ngăn xếp phức
tạp để cho phép tính phi tuyến trên mỗi pixel hơn.
- Nin loại bỏ các lớp được kết nối hoàn toàn và thay thế chúng bằng
tổng hợp trung bình toàn cầu (tức là tổng hợp tất cả các vị trí) sau
khi giảm số lượng kênh xuống số lượng đầu ra mong muốn (ví dụ: 10 cho
Fashion-MNIST).
- Loại bỏ các lớp được kết nối hoàn toàn làm giảm quá mức. Nin có ít
tham số hơn đáng kể.
- Thiết kế Nin ảnh hưởng đến nhiều thiết kế CNN tiếp theo.
Bài tập
-------
1. Điều chỉnh các siêu tham số để cải thiện độ chính xác phân loại.
2. Tại sao có hai lớp ghép :math:`1\times 1` trong khối Nin? Loại bỏ một
trong số chúng, sau đó quan sát và phân tích các hiện tượng thử
nghiệm.
3. Tính toán mức sử dụng tài nguyên cho Nin.
1. Số lượng tham số là bao nhiêu?
2. Số lượng tính toán là bao nhiêu?
3. Dung lượng bộ nhớ cần thiết trong quá trình đào tạo là bao nhiêu?
4. Dung lượng bộ nhớ cần thiết trong quá trình dự đoán là bao nhiêu?
4. Những vấn đề có thể xảy ra với việc giảm đại diện
:math:`384 \times 5 \times 5` thành đại diện
:math:`10 \times 5 \times 5` trong một bước là gì?
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html