.. _sec_nin: Network in Network (NiN) ======================== LeNet, AlexNet e VGG compartilham um padrão de design comum: extrair recursos que exploram a estrutura *espacial* por meio de uma sequência de camadas de convolução e agrupamento e, em seguida, pós-processar as representações por meio de camadas totalmente conectadas. As melhorias no LeNet por AlexNet e VGG residem principalmente em como essas redes posteriores ampliam e aprofundam esses dois módulos. Alternativamente, pode-se imaginar o uso de camadas totalmente conectadas no início do processo. No entanto, um uso descuidado de camadas densas pode desistir da estrutura espacial da representação inteiramente, Os blocos *rede em rede* (*NiN*) oferecem uma alternativa. Eles foram propostos com base em uma visão muito simples: para usar um MLP nos canais para cada pixel separadamente :cite:`Lin.Chen.Yan.2013`. Blocos NiN ---------- Lembre-se de que as entradas e saídas das camadas convolucionais consistem em tensores quadridimensionais com eixos correspondendo ao exemplo, canal, altura e largura. Lembre-se também de que as entradas e saídas de camadas totalmente conectadas são tipicamente tensores bidimensionais correspondentes ao exemplo e ao recurso. A ideia por trás do NiN é aplicar uma camada totalmente conectada em cada localização de pixel (para cada altura e largura). Se amarrarmos os pesos em cada localização espacial, poderíamos pensar nisso como uma camada convolucional :math:`1 \times 1` (conforme descrito em :numref:`sec_channels`) ou como uma camada totalmente conectada agindo de forma independente em cada localização de pixel. Outra maneira de ver isso é pensar em cada elemento na dimensão espacial (altura e largura) como equivalente a um exemplo e um canal como equivalente a um recurso. :numref:`fig_nin` ilustra as principais diferenças estruturais entre VGG e NiN, e seus blocos. O bloco NiN consiste em uma camada convolucional seguido por duas camadas convolucionais :math:`1 \times 1` que atuam como camadas totalmente conectadas por pixel com ativações ReLU. A forma da janela de convolução da primeira camada é normalmente definida pelo usuário. As formas de janela subsequentes são fixadas em :math:`1 \times 1`. .. _fig_nin: .. figure:: ../img/nin.svg :width: 600px Comparando arquiteturas de VGG e NiN, e seus blocos. .. raw:: html
mxnetpytorchtensorflow
.. 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
Modelo NiN ---------- A rede NiN original foi proposta logo após AlexNet e claramente tira alguma inspiração. NiN usa camadas convolucionais com formas de janela de :math:`11\times 11`, :math:`5\times 5` e :math:`3\times 3`, e os números correspondentes de canais de saída são iguais aos do AlexNet. Cada bloco NiN é seguido por uma camada de *pooling* máxima com um passo de 2 e uma forma de janela de :math:`3\times 3`. Uma diferença significativa entre NiN e AlexNet é que o NiN evita camadas totalmente conectadas. Em vez disso, NiN usa um bloco NiN com um número de canais de saída igual ao número de classes de rótulo, seguido por uma camada de *pooling* média global, produzindo um vetor de logits. Uma vantagem do design da NiN é que reduz o número de parâmetros de modelo necessários. No entanto, na prática, esse design às vezes requer aumento do tempo de treinamento do modelo. .. raw:: html
mxnetpytorchtensorflow
.. 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), # Há 3 classes de rótulos nin_block(10, kernel_size=3, strides=1, padding=1), # A camada de pool de média global define automaticamente a forma da janela # à altura e largura da entrada nn.GlobalAvgPool2D(), # Transforme a saída quadridimensional em saída bidimensional com uma forma de (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), # Há 3 classes de rótulos nin_block(384, 10, kernel_size=3, strides=1, padding=1), nn.AdaptiveAvgPool2d((1, 1)), # Transforme a saída quadridimensional em saída bidimensional com uma forma de (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), # Há 10 classes de rótulos nin_block(10, kernel_size=3, strides=1, padding='same'), tf.keras.layers.GlobalAveragePooling2D(), tf.keras.layers.Reshape((1, 1, 10)), # Transforme a saída quadridimensional em saída bidimensional com uma forma de (batch size, 10) tf.keras.layers.Flatten(), ]) .. raw:: html
.. raw:: html
Criamos um exemplo de dados para ver a forma de saída de cada bloco. .. raw:: html
mxnetpytorchtensorflow
.. 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
Treinamento ----------- Como antes, usamos o Fashion-MNIST para treinar a modelo. O treinamento de NiN é semelhante ao de AlexNet e VGG. .. raw:: html
mxnetpytorchtensorflow
.. 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.601, train acc 0.766, test acc 0.778 2890.1 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.359, train acc 0.865, test acc 0.860 3201.6 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.354, train acc 0.869, test acc 0.874 3453.2 examples/sec on /GPU:0 .. parsed-literal:: :class: output .. figure:: output_nin_8ad4f3_45_2.svg .. raw:: html
.. raw:: html
Sumário ------- - NiN usa blocos que consistem em uma camada convolucional e várias camadas convolucionais :math:`1\times 1`. Isso pode ser usado dentro da pilha convolucional para permitir mais não linearidade por pixel. - NiN remove as camadas totalmente conectadas e as substitui pelo agrupamento médio global (ou seja, somando todos os locais) depois de reduzir o número de canais para o número desejado de saídas (por exemplo, 10 para Fashion-MNIST). - A remoção das camadas totalmente conectadas reduz o ajuste excessivo. NiN tem muito menos parâmetros. - O design NiN influenciou muitos designs subsequentes da CNN. Exercícios ---------- 1. Ajuste os hiperparâmetros para melhorar a precisão da classificação. 2. Por que existem duas camadas convolucionais :math:`1\times 1` no bloco NiN? Remova um deles e então observe e analise os fenômenos experimentais. 3. Calcule o uso de recursos para NiN. 1. Qual é o número de parâmetros? 2. Qual é a quantidade de computação? 3. Qual é a quantidade de memória necessária durante o treinamento? 4. Qual é a quantidade de memória necessária durante a previsão? 4. Quais são os possíveis problemas com a redução da representação :math:`384 \times 5 \times 5` para uma representação :math:`10 \times 5 \times 5` em uma etapa? .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
`Discussão `__ .. raw:: html
.. raw:: html
`Discussão `__ .. raw:: html
.. raw:: html
`Discussão `__ .. raw:: html
.. raw:: html
.. raw:: html