| | | |

Introdução a PINNs

Ajude a manter o site livre, gratuito e sem propagandas. Colabore!

2.2 Treinamento por retro-propagação

Em revisão

Embora o algoritmo de treinamento perceptron seja eficiente para problemas de classificação linearmente separáveis, ele não é aplicável a problemas mais gerais. Para isso, vamos introduzir o problema de treinamento de um perceptron como um problema de otimização. A ideia é definir uma função de perda que quantifique o erro entre as saídas estimadas pelo modelo e as saídas esperadas. E, então, minimizar essa função de perda em relação aos parâmetros do modelo.

Ao longo da seção, vamos considerar o modelo de perceptron

y~=η(𝒙;𝜽=(𝒘,b))=φ(𝒘𝒙+b)z, (2.28)

com função de ativação φ:, sendo os vetores de entrada 𝒙 e dos pesos 𝒘 de tamanho nin. A pré-ativação do neurônio é denotada por z:=𝒘𝒙+b.

Fornecido um conjunto de treinamento {(𝒙(s),y(s))}s=0ns, com ns amostras, o objetivo é calcular os parâmetros 𝜽=(𝒘,b) que minimizam a função de perda erro quadrático médio (EQM)

ε(𝒘,b):=1nss=1ns(y~(s)y(s))2 (2.29)
=1nss=1nsε(s)(𝒘,b) (2.30)

onde y~(s)=η(𝒙(s);𝜽) é o valor estimado pelo modelo e y(s) é o valor esperado da s-ésima amostra. Nesta escolha, a função de perda para a s-ésima amostra é

ε(s):=(y~(s)y(s))2. (2.31)

Ou seja, o treinamento consiste em resolver o seguinte problema de otimização

argmin(𝒘,b)ε(𝒘,b) (2.32)

Neste contexto, o método que escolhemos para resolver (2.32) é chamado de otimizador. Na sequência, vamos estudar que otimizadores baseados em gradientes da função de perda podem ser aplicados de forma eficiente para o treinamento de perceptrons.

2.2.1 Método do gradiente descendente

O método do gradiente descendente (GD) é um dos métodos mais simples de otimização baseados em gradiente. É um método de declive, em que os parâmetros do modelo são atualizados na direção e sentido oposto ao gradiente da função de perda.

Aplicado ao nosso modelo de perceptron consiste no seguinte algoritmo:

  1. 1.

    (𝒘,b) aproximação inicial.

  2. 2.

    Para e1,,ne:

    1. (a)

      (𝒘,b)(𝒘,b)lrε(𝒘,b)

onde, escolhemos o número de épocas ne, a taxa de aprendizagem444A taxa de aprendizagem é usualmente escolhida como um valor pequeno 0<lr<1. lr (do inglês, learning rate). Sendo o gradiente definido por

ε(𝒘,b):=(εw1,,εwnin,εb). (2.33)

O cálculo do gradiente para os pesos 𝒘 pode ser feito como segue555Aqui, há um abuso de linguagem ao não se observar as dimensões dos operandos matriciais.

ε𝒘=𝒘[1nss=1nsε(s)] (2.34)
=1nss=1nsε(s)y~(s)y~(s)𝒘 (2.35)
=1nss=1nsε(s)y~(s)y~(s)z(s)z(s)𝒘 (2.36)

Observando que

ε(s)y~(s)=2(y~(s)y(s)), (2.37)
y~(s)z(s)=f(z(s)), (2.38)
z(s)𝒘=𝒙(s), (2.39)

obtemos

ε𝒘=1nss=1ns2(y~(s)y(s))f(z(s))𝒙(s) (2.40)

Analogamente, segue o cálculo do gradiente para o bias b:

εb=1nss=1nsε(s)y~(s)y~(s)z(s)z(s)b (2.41)
=1nss=1ns2(y~(s)y(s))f(z(s))1 (2.42)
Refer to caption
Figura 2.3: Fluxograma de uma época de treinamento.

Observemos cada época consiste de duas etapas (consultemos a Figura 2.3):

  1. a)

    Propagação

    A etapa de propagação na amostragem, avaliação e cálculo da função de perda. A amostragem é a escolha (ou construção) das amostras de treinamento que serão utilizadas para a atualização dos parâmetros do modelo. A avaliação é o cálculo dos valores estimados 𝒚~ (saída do modelo) para as amostras escolhidas. O cálculo da função de perda é feito com base nos valores estimados.

  2. b)

    Retro-propagação

    A etapa de retro-propagação consiste no cálculo do gradiente da função de perda e na atualização dos parâmetros do modelo. O cálculo do gradiente é feito por um processo de acumulação do gradiente da função de perda para cada amostra utilizada na etapa de propagação. A atualização dos parâmetros é feita com base nos gradientes calculados.

Aplicação

Na Subseção 2.1.1, treinamos um perceptron para o problema de classificação do e-lógico. A função de ativação f(x)=sign(x) não é adequada para a aplicação do método GD, pois f(x)0 para x0. Alternativamente, podemos utilizar a função tangente hiperbólica como função de ativação

φ(x)=tanh(x) (2.43)

que é diferenciável com derivada

φ(x)=1tanh2(x). (2.44)
Refer to caption
Figura 2.4: Função tangente hiperbólica e sua derivada.

O Código 3 contém uma implementação do treinamento de um perceptron para o problema de classificação do e-lógico utilizando o método GD. Verifique!

Código 3: perceptron_gd.py
1import torch
2
3# modelo
4
5class Perceptron(torch.nn.Module):
6 def __init__(self):
7 super().__init__()
8 self.linear = torch.nn.Linear(2,1)
9
10 def forward(self, x):
11 z = self.linear(x)
12 y = torch.tanh(z)
13 return y
14
15model = Perceptron()
16
17# treinamento
18
19## optimizador
20optim = torch.optim.SGD(model.parameters(), lr=0.5)
21
22## função erro
23loss_fun = torch.nn.MSELoss()
24
25## dados de treinamento
26X_train = torch.tensor([[1., 1.],
27 [1., -1.],
28 [-1., 1.],
29 [-1., -1.]])
30y_train = torch.tensor([1., -1., -1., -1.]).reshape(-1,1)
31
32print("\nDados de treinamento")
33print("X_train =")
34print(X_train)
35print("y_train = ")
36print(y_train)
37
38## num max épocas
39nepochs = 100
40tol = 5e-2
41
42for epoch in range(nepochs):
43
44 # forward
45 y_est = model(X_train)
46
47 # erro
48 loss = loss_fun(y_est, y_train)
49
50 print(f'{epoch}: {loss.item():.4e}')
51
52 # critério de parada
53 if (loss.item() < tol):
54 break
55
56 # backward
57 optim.zero_grad()
58 loss.backward()
59 optim.step()
60
61
62# verificação
63y = model(X_train)
64print(f'y_est = {y}')

Retro-propagação

O termo retro-propagação é usado para enfatizar que o cálculo do gradiente da função de perda é feito de forma retroativa, ou seja, a partir da saída do modelo e voltando-se para os parâmetros do modelo. A Figura 2.5 ilustra o processo de retro-propagação aplicado ao treinamento de um perceptron. Observemos que a inferência do modelo pode ser esquematizada como uma árvore. No cálculo da pré-ativação z=𝒘𝒙+b, o gradiente z/𝜽=z/(𝒘,b) pode ser calculado diretamente e armazenado como uma folha da árvore. Em seguida, a saída da rede é calculada como y~=φ(z), e o gradiente y~/z também pode ser calculado e armazenado como uma folha da árvore. Por fim, a função de perda é calculada e o gradiente ε/y~ calculado e armazenado como uma folha da árvore. Terminada a etapa de propagação (inferência do modelo), as folhas da árvore contém todos os fatores necessários para o cálculo do gradiente da função de perda em relação aos parâmetros do modelo, lembrando que, por meio da regra da cadeia, temos

ε𝜽=εy~y~zz𝜽. (2.45)

Com isso, o cálculo do gradiente da função de perda em relação aos parâmetros pode ser feito por um processo de acumulação, um somatório de produtos de gradientes. No próximo capítulo, vamos explorar mais detalhadamente o processo de retro-propagação como uma aplicação de diferenciação automática.

Refer to caption
Figura 2.5: Fluxograma do método de retro-propagação aplicado ao treinamento de um perceptron.

2.2.2 Método do gradiente estocástico

O método do gradiente descentente estocástico (GDE666SGD, do inglês, Stochastic Gradient Descent Method) é um variação do método GD. A ideia é atualizar os parâmetros do modelo com base no gradiente do erro de cada amostra (ou um subconjunto de amostras777Nest caso, é conhecido como batch-SGD.). A estocasticidade é obtida da randomização com que as amostras são escolhidas a cada época. O algoritmos consiste no seguinte:

  1. 1.

    𝒘, b aproximações inicial.

  2. 2.

    Para e1,,ne:

    1. 1.1.

      Para srandom(1,,ns):

      (𝒘,b)(𝒘,b)lrε(s)(𝒘,b) (2.46)

Aplicação

O Código 4 é uma implementação do treinamento de um perceptron para o problema de classificação do e-lógico utilizando o método GDE. Verifique!

Código 4: perceptron_gde.py
1import torch
2
3# modelo
4
5class Perceptron(torch.nn.Module):
6 def __init__(self):
7 super().__init__()
8 self.linear = torch.nn.Linear(2,1)
9
10 def forward(self, x):
11 z = self.linear(x)
12 y = torch.tanh(z)
13 return y
14
15model = Perceptron()
16
17# treinamento
18
19# optimizador
20optim = torch.optim.SGD(model.parameters(), lr=0.5)
21
22# função erro
23loss_fun = torch.nn.MSELoss()
24
25# dados de treinamento
26X_train = torch.tensor([[1., 1.],
27 [1., -1.],
28 [-1., 1.],
29 [-1., -1.]])
30y_train = torch.tensor([1., -1., -1., -1.]).reshape(-1,1)
31
32# num de amostras
33ns = y_train.size(0)
34
35print("\nDados de treinamento")
36print("X_train =")
37print(X_train)
38print("y_train = ")
39print(y_train)
40
41# num max épocas
42nepochs = 100
43tol = 5e-2
44
45for epoch in range(nepochs):
46
47 model.train()
48 for s in torch.randperm(ns):
49 # propagação
50 y_est_s = model(X_train[s:s+1,:])
51
52 # função de perda da amostra
53 loss_s = (y_est_s - y_train[s])**2
54
55 # retro-propagação
56 optim.zero_grad()
57 loss_s.backward()
58 optim.step()
59
60 # critério de parada
61 model.eval()
62 y_val = model(X_train)
63
64 loss_val = loss_fun(y_val, y_train)
65 print(f'{epoch}: {loss_val.item():.4e}')
66
67 if (loss_val.item() < tol):
68 break
69
70# verificação
71print(f'y = {y_val}')

2.2.3 Exercícios

E. 2.2.1.

Faça um estudo de convergência para comparar o algoritmo de treinamento perceptron, com o algoritmo de treinamento por retro-propagação utilizando o método GD e o método GDE. Para isso, utilize o problema de classificação do e-lógico.

E. 2.2.2.

No E.2.1.5 foi verificado que não é possível criar um perceptron para emular a operação lógica xor e o algoritmo de treinamento perceptron acaba convergindo para uma saída nula. O que ocorre se tentarmos treinar um perceptron para emular a operação lógica xor utilizando o método GD e o método GDE? As saídas estimadas convergem para algum valor? Justifique sua resposta.

E. 2.2.3.

Crie um perceptron que se ajuste ao seguinte conjunto de dados de entrada e saída.

s x(s) y(s)
1 0.5 1.2
2 1.0 2.1
3 1.5 2.6
4 2.0 3.6
E. 2.2.4.

Nos Código 3 e Código 4, substitua o trecho de código

1optim.zero_grad()
2loss_s.backward()
3optim.step()

por uma implementação manual, em que os gradientes sejam calculados explicitamente e os parâmetros atualizados manualmente.

E. 2.2.5.

Adicione ao método GD um método de busca linear para a escolha da taxa de aprendizagem lr em cada época.


Envie seu comentário

Aproveito para agradecer a todas/os que de forma assídua ou esporádica contribuem enviando correções, sugestões e críticas!

Opcional. Preencha seu nome para que eu possa lhe contatar.
Opcional. Preencha seu e-mail para que eu possa lhe contatar.
As informações preenchidas são enviadas por e-mail para o desenvolvedor do site e tratadas de forma privada. Consulte a política de uso de dados para mais informações.

Licença Creative Commons
Este texto é disponibilizado nos termos da Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional. Ícones e elementos gráficos podem estar sujeitos a condições adicionais.

Pedro H A Konzen
| | | |