MLP — Multilayer Perceptron — Conceito básico

Francke Peixoto
7 min readJul 4, 2020

--

📌 Uma rede MLP, é uma rede totalmente conectada,(fully connected network | feedforward network).

O entendimento dessa rede, nos ajuda a obter informações sobre os motivos adjacentes nos modelos avançados de Deep Learning. As MLPs são usadas comumente em problemas de regressão simples. No entanto, as MLPs não são ideais para o processamento de padrões com dados sequenciais e multidimensionais.

🙄 Uma MLP se esforça para lembrar de padrões em dados sequenciais, por conta disso, requer um número “grande” de parâmetros para processar dados multidimensionais.

Para dados sequenciais, as RNNs são as queridinhas porque seus padrões permitem que a rede descubra dependência no 🧠 histórico dos dados, o que é bem útil para previsões. Para dados, como imagens e vídeos, as CNNs se destacam na extração de mapas de recursos para classificação, segmentação, dentre outras tarefas.
Em alguns casos, uma CNN na forma de Conv1D/1D também é usada para redes com dados de entrada sequenciais. No entanto, na maioria dos modelos de Deep Learning, MLP, CNN ou RNN são combinadas para aproveitar o máximo de cada.

MLP,CNN e RNN não fazem tudo…
Muito de seu sucesso vem de identificar seu objetivo e a boa escolha de alguns parâmetros, tais como:

Loss function, Optimizer e Regularizer
Também, temos os dados de fora do ambiente de treinamento. O papel do Regularizer é garantir que o modelo treinado generalize para novos dados.

Dataset MNIST

Suponha que nosso objetivo seja criar uma rede para identificar números com base em dígitos manuscritos. Por exemplo, quando a entrada para a rede é uma imagem de um número 8, a previsão correspondente também deve ser 8.
🤷🏻‍♂️ Esse é um trabalho básico de classificação com redes neurais.

O dataset do National Institute of Standards and Technology, ou MNIST, é considerado como o Olá Mundo! dos datasets de Deep Learning.
Antes de dissecarmos o modelo MLP, é essencial entender o dataset MNIST. Ele é usado para explicar e validar muitas teorias da deep learning, porque as 70.000 imagens que ele contêm são pequenas, mas suficientemente ricas em informações;

O MNIST é uma coleção de dígitos que variam de 0 a 9. Ele possui um conjunto de treinamento de 60.000 imagens e 10.000 testes classificados em categorias.

Para usarmos o dataset MNIST no tensorflow é simples.

In [1]:

#carregar dataset mnist
import numpy as np
from tensorflow.keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step

O método mnist.load_data() é conveniente, pois não há necessidade de carregar todas as 70.000 imagens e suas labels.

Antes de entrarmos no classificador MLP, é essencial ter em mente que, embora os dados do MNIST consistam em tensores bidimensionais, eles devem ser remodelados, dependendo do tipo de camada de entrada.

Uma imagem em escala de cinza 3x3 é remodelada para as camadas de entradas MLP,CNN e RNN:

As labels estão no formato de dígitos, de 0 a 9.

In [2]:

num_labels = len(np.unique(y_train))
print("total de labels:\t{}".format(num_labels))
print("labels:\t\t\t{0}".format(np.unique(y_train)))
total de labels: 10
labels: [0 1 2 3 4 5 6 7 8 9]

⚠️ Essa representação não é adequada para a camada de previsão que gera probabilidade por classe.

O formato mais indicado é o one-hot, um vetor 10-dimensional como todos os valores 0, exceto o índice da classe.

Por exemplo, se a label for 4, o vetor equivalente é [0,0,0,0, 1 ,0,0,0,0,0].

Em Deep Learning, os dados são armazenados em tensor. O termo tensor se aplica a um tensor escalar (tensor 0D), vetor (tensor 1D), matriz (tensor bidimensional) e tensor multidimensional.

In [3]:

#converter em one-hot
from tensorflow.keras.utils import to_categorical
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

Nosso modelo é uma MLP, portanto, seus inputs devem ser um tensor 1D. como tal, x_train e x_test devem ser transformados em [60.000, 2828] e [10.000, 2828],

No numpy, o size de -1 significa permitir que a library calcule a dimensão correta, No caso x_train, é 60.000.

In [4]:

# Assumindo que nossa imagem é quadrada.
image_size = x_train.shape[1]
input_size = image_size * image_size

print("x_train:\t{}".format(x_train.shape))
print("x_test:\t\t{}\n".format(x_test.shape))

print('Redimensionar e normalizar.\n')x_train = np.reshape(x_train, [-1, input_size])
x_train = x_train.astype('float32') / 255
x_test = np.reshape(x_test, [-1, input_size])
x_test = x_test.astype('float32') / 255
print("x_train:\t{}".format(x_train.shape))
print("x_test:\t\t{}".format(x_test.shape))
x_train: (60000, 28, 28)
x_test: (10000, 28, 28)
Redimensionar e normalizar.x_train: (60000, 784)
x_test: (10000, 784)

Construindo o modelo

Nosso modelo é composto por três layers MLP em uma camada Densa. A primeira e a segunda, são idênticas, seguidas por uma função de ativação Rectified Linear Unit ( ReLU ) e Dropout.

In [5]:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation, Dropout
# Parâmetros
batch_size = 128 # É o tamanho da amostra de entradas a serem processadas em cada etapa de treinamento. //epocas
hidden_units = 256
dropout = 0.45
# Nossa MLP com ReLU e Dropout
model = Sequential()
model.add(Dense(hidden_units, input_dim=input_size))
model.add(Activation('relu'))
model.add(Dropout(dropout))
model.add(Dense(hidden_units))
model.add(Activation('relu'))
model.add(Dropout(dropout))
model.add(Dense(num_labels))

Regularization

Uma rede neural tem a tendência de memoriza seus dados de treinamento, especialmente se contiver capacidade mais que suficiente. Nesse caso, a rede falha catastroficamente quando submetida aos dados de teste.

Este é o caso clássico de que a rede falha em generalizar (Overfitting / Underfitting). Para evitar essa tendência o modelousa uma camada regulatória. O Dropout.

A ideia do Dropout é simples. Dada uma taxa de descarte ( em nosso modelo, definimos = 0,45) a camada remove aleatoriamente essa fração de unidades.

Por exemplo, se a primeira camada tiver 256 unidades, depois que o Dropout(0,45) for aplicado, apenas (1–0,45) * 255 = 140 unidades participarão da próxima camada.

O Dropout torna as redes neurais mais robustas para dados de entrada imprevistos, porque a rede é treinada para prever corretamente, mesmo que algumas unidades estejam ausentes.

⚠️ O Dropout só participa da “brincadeira” 🤷🏻‍♂️ durante o treinamento.

Activation

A camada de saída possui 10 unidades, seguida por uma função de ativação softmax. As 10 unidades correspondem as 10 possíveis labels, classes ou categorias.

A activation do softmax pode ser expressada matematicamente , conforme a seguinte equação:

In [6]:

model.add(Activation('softmax'))model.summary()Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 256) 200960
_________________________________________________________________
activation (Activation) (None, 256) 0
_________________________________________________________________
dropout (Dropout) (None, 256) 0
_________________________________________________________________
dense_1 (Dense) (None, 256) 65792
_________________________________________________________________
activation_1 (Activation) (None, 256) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 256) 0
_________________________________________________________________
dense_2 (Dense) (None, 10) 2570
_________________________________________________________________
activation_2 (Activation) (None, 10) 0
=================================================================
Total params: 269,322
Trainable params: 269,322
Non-trainable params: 0
_________________________________________________________________

Optimization

O objetivo do Optimization é minimizar a função de perda. A idéia é que, se a perda for reduzida para um nível aceitável, o modelo indiretamente aprendeu a função que mapeia os inputs para os outputs.

Métricas de desempenho são usadas para determinar se seu modelo aprendeu.

In [8]:

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
  • Categorical_crossentropy, é usada para one-hot
  • Accuracy é uma boa métrica para tarefas de classificação.
  • Adam é um algoritmo de otimização que pode ser usado em vez do procedimento clássico de descida de gradiente estocástico

📌 Dado nosso conjunto de treinamento, a escolha da loss function, o optimizer e o regularizer, podemos iniciar o treinamento de nosso modelo.

In [9]:

model.fit(x_train, y_train, epochs=20, batch_size=batch_size)Epoch 1/20
469/469 [==============================] - 3s 6ms/step - loss: 0.4236 - accuracy: 0.8709
Epoch 2/20
469/469 [==============================] - 3s 6ms/step - loss: 0.1947 - accuracy: 0.9413
Epoch 3/20
469/469 [==============================] - 3s 6ms/step - loss: 0.1536 - accuracy: 0.9539
Epoch 4/20
469/469 [==============================] - 3s 6ms/step - loss: 0.1294 - accuracy: 0.9609
Epoch 5/20
469/469 [==============================] - 3s 5ms/step - loss: 0.1161 - accuracy: 0.9644
Epoch 6/20
469/469 [==============================] - 3s 6ms/step - loss: 0.1028 - accuracy: 0.9679
Epoch 7/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0946 - accuracy: 0.9707
Epoch 8/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0866 - accuracy: 0.9732
Epoch 9/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0817 - accuracy: 0.9748
Epoch 10/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0788 - accuracy: 0.9755
Epoch 11/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0744 - accuracy: 0.9772
Epoch 12/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0668 - accuracy: 0.9784
Epoch 13/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0672 - accuracy: 0.9784
Epoch 14/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0643 - accuracy: 0.9796
Epoch 15/20
469/469 [==============================] - 3s 5ms/step - loss: 0.0625 - accuracy: 0.9803
Epoch 16/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0618 - accuracy: 0.9804
Epoch 17/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0585 - accuracy: 0.9816
Epoch 18/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0567 - accuracy: 0.9819
Epoch 19/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0579 - accuracy: 0.9812
Epoch 20/20
469/469 [==============================] - 3s 6ms/step - loss: 0.0530 - accuracy: 0.9830

Out[9]:

<tensorflow.python.keras.callbacks.History at 0x7fcee046a410>

Evaluation

Nesse ponto, nosso modelo classificador de dígitos MNIST está completo. Sua avaliação de desempenho será o próximo passo para determinar se o modelo treinado apresentará uma solução sub-ótima.

In [10]:

print("Validar o modelo em nosso dataset de teste:\n")
_, acc = model.evaluate(x_test,
y_test,
batch_size=batch_size,
verbose=0)
print("\nAccuracy: %.1f%%\n" % (100.0 * acc))
Validar o modelo em nosso dataset de teste:
Accuracy: 98.2%

Conclusão

Mesmo com uma accuracy de 98%, há uma necessidade de melhorar em nossa rede.

No próximo artigo, criaremos um modelo baseado em CNN.

Saber muito não lhe torna inteligente. A inteligência se traduz na forma que você recolhe, julga, maneja e, sobretudo, onde e como aplica esta informação. (Carl Sagan)

Referências

--

--

Francke Peixoto

Software Engineer | Data Engineer | Data & Analytics Enthusiastic | Machine Learning | Azure | Fullstack Developer | Systems Analist | .Net — Acta, non verba