.. _sec_mlp_scratch: Implementação de Perceptrons Multicamadas do Zero ================================================= Agora que caracterizamos perceptrons multicamadas (MLPs) matematicamente, vamos tentar implementar um nós mesmos. Para comparar com nossos resultados anteriores alcançado com regressão *softmax* (:numref:`sec_softmax_scratch`), vamos continuar a trabalhar com o conjunto de dados de classificação de imagens Fashion-MNIST (:numref:`sec_fashion_mnist`). .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python from mxnet import gluon, np, npx from d2l import mxnet as d2l npx.set_np() batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) .. raw:: html
.. raw:: html
.. code:: python import torch from torch import nn from d2l import torch as d2l batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) .. raw:: html
.. raw:: html
.. code:: python import tensorflow as tf from d2l import tensorflow as d2l batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) .. raw:: html
.. raw:: html
Inicializando os Parâmetros do Modelo ------------------------------------- Lembre-se de que o Fashion-MNIST contém 10 classes, e que cada imagem consiste em uma graded :math:`28 \times 28 = 784` de valores de pixel em tons de cinza. Novamente, vamos desconsiderar a estrutura espacial entre os pixels por enquanto, então podemos pensar nisso simplesmente como um conjunto de dados de classificação com 784 características de entrada e 10 classes. Para começar, iremos implementar um MLP com uma camada oculta e 256 unidades ocultas. Observe que podemos considerar essas duas quantidades como hiperparâmetros. Normalmente, escolhemos larguras de camada em potências de 2, que tendem a ser computacionalmente eficientes porque de como a memória é alocada e endereçada no hardware. Novamente, iremos representar nossos parâmetros com vários tensores. Observe que *para cada camada*, devemos acompanhar uma matriz de ponderação e um vetor de polarização. Como sempre, alocamos memória para os gradientes da perda com relação a esses parâmetros. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python num_inputs, num_outputs, num_hiddens = 784, 10, 256 W1 = np.random.normal(scale=0.01, size=(num_inputs, num_hiddens)) b1 = np.zeros(num_hiddens) W2 = np.random.normal(scale=0.01, size=(num_hiddens, num_outputs)) b2 = np.zeros(num_outputs) params = [W1, b1, W2, b2] for param in params: param.attach_grad() .. raw:: html
.. raw:: html
.. code:: python num_inputs, num_outputs, num_hiddens = 784, 10, 256 W1 = nn.Parameter(torch.randn( num_inputs, num_hiddens, requires_grad=True) * 0.01) b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True)) W2 = nn.Parameter(torch.randn( num_hiddens, num_outputs, requires_grad=True) * 0.01) b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True)) params = [W1, b1, W2, b2] .. raw:: html
.. raw:: html
.. code:: python num_inputs, num_outputs, num_hiddens = 784, 10, 256 W1 = tf.Variable(tf.random.normal( shape=(num_inputs, num_hiddens), mean=0, stddev=0.01)) b1 = tf.Variable(tf.zeros(num_hiddens)) W2 = tf.Variable(tf.random.normal( shape=(num_hiddens, num_outputs), mean=0, stddev=0.01)) b2 = tf.Variable(tf.random.normal([num_outputs], stddev=.01)) params = [W1, b1, W2, b2] .. raw:: html
.. raw:: html
Função de Ativação ------------------ Para ter certeza de que sabemos como tudo funciona, iremos implementar a ativação ReLU nós mesmos usar a função máxima em vez de invocar a função embutida ``relu`` diretamente. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python def relu(X): return np.maximum(X, 0) .. raw:: html
.. raw:: html
.. code:: python def relu(X): a = torch.zeros_like(X) return torch.max(X, a) .. raw:: html
.. raw:: html
.. code:: python def relu(X): return tf.math.maximum(X, 0) .. raw:: html
.. raw:: html
Modelo ------ Porque estamos desconsiderando a estrutura espacial, nós ``remodelamos`` cada imagem bidimensional em um vetor plano de comprimento ``num_inputs``. Finalmente, nós implementamos nosso modelo com apenas algumas linhas de código. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python def net(X): X = X.reshape((-1, num_inputs)) H = relu(np.dot(X, W1) + b1) return np.dot(H, W2) + b2 .. raw:: html
.. raw:: html
.. code:: python def net(X): X = X.reshape((-1, num_inputs)) H = relu(X@W1 + b1) # Here '@' stands for matrix multiplication return (H@W2 + b2) .. raw:: html
.. raw:: html
.. code:: python def net(X): X = tf.reshape(X, (-1, num_inputs)) H = relu(tf.matmul(X, W1) + b1) return tf.matmul(H, W2) + b2 .. raw:: html
.. raw:: html
Função de Perda --------------- Para garantir estabilidade numérica, e porque já implementamos a função\* softmax\* do zero (:numref:`sec_softmax_scratch`), alavancamos a função integrada de APIs de alto nível para calcular o *softmax* e a perda de entropia cruzada. Lembre-se de nossa discussão anterior sobre essas complexidades em :numref:`subsec_softmax-implementation-revisited`. Nós encorajamos o leitor interessado a examinar o código-fonte para a função de perda para aprofundar seu conhecimento dos detalhes de implementação. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python loss = gluon.loss.SoftmaxCrossEntropyLoss() .. raw:: html
.. raw:: html
.. code:: python loss = nn.CrossEntropyLoss() .. raw:: html
.. raw:: html
.. code:: python def loss(y_hat, y): return tf.losses.sparse_categorical_crossentropy( y, y_hat, from_logits=True) .. raw:: html
.. raw:: html
Trainamento ----------- Felizmente, o loop de treinamento para MLPs é exatamente igual à regressão *softmax*. Aproveitando o pacote ``d2l`` novamente, chamamos a função ``train_ch3`` (ver :numref:`sec_softmax_scratch`), definindo o número de épocas para 10 e a taxa de aprendizagem para 0,1. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python num_epochs, lr = 10, 0.1 d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, lambda batch_size: d2l.sgd(params, lr, batch_size)) .. figure:: output_mlp-scratch_106d07_63_0.svg .. raw:: html
.. raw:: html
.. code:: python num_epochs, lr = 10, 0.1 updater = torch.optim.SGD(params, lr=lr) d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater) .. figure:: output_mlp-scratch_106d07_66_0.svg .. raw:: html
.. raw:: html
.. code:: python num_epochs, lr = 10, 0.1 updater = d2l.Updater([W1, W2, b1, b2], lr) d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater) .. figure:: output_mlp-scratch_106d07_69_0.svg .. raw:: html
.. raw:: html
Para avaliar o modelo aprendido, nós aplicamos em alguns dados de teste. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python d2l.predict_ch3(net, test_iter) .. figure:: output_mlp-scratch_106d07_75_0.svg .. raw:: html
.. raw:: html
.. code:: python d2l.predict_ch3(net, test_iter) .. figure:: output_mlp-scratch_106d07_78_0.svg .. raw:: html
.. raw:: html
.. code:: python d2l.predict_ch3(net, test_iter) .. figure:: output_mlp-scratch_106d07_81_0.svg .. raw:: html
.. raw:: html
Resumo ------ - Vimos que implementar um MLP simples é fácil, mesmo quando feito manualmente. - No entanto, com um grande número de camadas, implementar MLPs do zero ainda pode ser complicado (por exemplo, nomear e controlar os parâmetros do nosso modelo). Exercícios ---------- 1. Altere o valor do hiperparâmetro ``num_hiddens`` e veja como esse hiperparâmetro influencia seus resultados. Determine o melhor valor deste hiperparâmetro, mantendo todos os outros constantes. 2. Experimente adicionar uma camada oculta adicional para ver como isso afeta os resultados. 3. Como mudar a taxa de aprendizado altera seus resultados? Corrigindo a arquitetura do modelo e outros hiperparâmetros (incluindo o número de épocas), qual taxa de aprendizado oferece os melhores resultados? 4. Qual é o melhor resultado que você pode obter otimizando todos os hiperparâmetros (taxa de aprendizagem, número de épocas, número de camadas ocultas, número de unidades ocultas por camada) em conjunto? 5. Descreva por que é muito mais difícil lidar com vários hiperparâmetros. 6. Qual é a estratégia mais inteligente que você pode imaginar para estruturar uma pesquisa em vários hiperparâmetros? .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
.. raw:: html