| | | |

Introdução a PINNs

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

2.6 Diferenciação automática

Diferenciação automática é um conjunto de técnicas para a computação de derivadas numéricas em um programa de computador. Explora-se o fato de que um programa computacional executa uma sequência de operações aritméticas e funções elementares, podendo-se computar a derivada por aplicações da regra da cadeia.

PyTorch computa o gradiente (derivada) de uma função f:n a partir de seu grafo computacional. Os gradientes são computados por retropropagação. Por exemplo, para a computação do gradiente

𝒙f(𝒙0)=dfd𝒙|𝒙=𝒙0, (2.79)

primeiramente, propaga-se a entrada 𝒙0 pela função computacional f, obtendo-se y0=f(𝒙0). Então, o gradiente é computado por retropropagação.

Exemplo 2.6.1.

Seja f(x)=sen(πx) e vamos computar

f(0)=dfdx|x=0 (2.80)

por diferenciação automática.

Refer to caption
Figura 2.14: Grafo computacional da diferenciação automática de f(x)=sen(πx).

A Figura 2.14 mostra o grafo computacional da função f(x)=sen(πx). A entrada x é propagada formando o grafo de propagação. Ao grafo de propagação, folhas são adicionadas contendo as derivadas de cada operação. Para a computação do gradiente, adicionamos uma variável fictícia z=y e, então, o gradiente dy/dx=dz/dx é computado por retropropagação. A retropropagação é feita da seguinte forma

dydx|x=x0=dzdx|x=x0 (2.81)
=dzdu|x=x0dudx|x=x0 (2.82)
=dzdy|x=x0dydu|x=x0dudx|x=x0 (2.83)
=1πcos(πx0)=πcos(πx0). (2.84)
Refer to caption
Figura 2.15: Comparação entre as diferenciações analítica (f) e automática (autograd).

O Código 13 contém uma implementação PyTorch da diferenciação automática da função f(x)=sen(πx) para x(0,1/4,1/2,3/4,1). Observe que para a computação do gradiente, a entrada x deve ser marcada com o atributo requires_grad=True. O comando y.backward() computa o gradiente de y em relação a x. O argumento gradient=ones_like(y) é usado para especificar o vetor de gradientes iniciais para a retropropagação. Este é o dz/dy neste exemplo aqui. O gradiente dy/dx é armazenado no atributo x.grad. Ainda, a Figura 2.15 mostra a comparação entre as diferenciações analítica (f) e automática (autograd). Observemos que os resultados são idênticos, com diferenças da ordem de 107, que é a precisão numérica do PyTorch141414Por padrão, o PyTorch usa pontos flutuantes de 32-bits, com precisão aproximada de 107..

Código 13: ex_autograd.py
1from torch import tensor, sin, pi, ones_like
2
3# entrada
4x = tensor([0.,0.25,0.5,0.75,1.])
5x = x.reshape(-1, 1)
6x.requires_grad_(True)
7
8# propagação
9y = sin(pi * x)
10
11# retropropagação (cálculo do gradiente)
12y.backward(gradient=ones_like(y))
13
14# print gradiente
15print('dydx =', x.grad)
dydx = tensor([[ 3.1416e+00],
[ 2.2214e+00],
[-1.3732e-07],
[-2.2214e+00],
[-3.1416e+00]])

O grafo computacional da retropopagação pode ser recuperado no PyTorch com o seguinte código (Código LABEL:cod:ex_mlp_autograd_graph).

Código 14: ex_autograd.py (continuação)
1def print_backward_graph(node, depth=0, seen=None):
2 seen = set() if seen is None else seen
3 if node is None or node in seen:
4 return
5 seen.add(node)
6 print(" " * depth + type(node).__name__)
7 for parent, _ in node.next_functions:
8 print_backward_graph(parent, depth + 1, seen)
9
10print_backward_graph(y.grad_fn)
SinBackward0
MulBackward0
AccumulateGrad

Observemos que a computação do gradiente de primeira ordem também acaba por construir um novo grafo. Este, por sua vez, pode ser usado para a computação da diferenciação automática de segunda ordem, i.e. para a derivação de segunda ordem.

Exemplo 2.6.2.

Vamos computar a segunda derivada da função f(x)=sen(πx) por diferenciação automática. O primeiro passo é propagar a entrada x pela função f, obtendo-se y=f(x). Em seguida, computamos o gradiente de primeira ordem dy/dx por retropropagação. O gradiente de segunda ordem d2y/dx2 é computado propagando-se o gradiente de primeira ordem dy/dx pelo grafo computacional da retropropagação, obtendo-se d2y/dx2.

Refer to caption
Figura 2.16: Comparação entre as diferenciações analítica (f, f′′) e automática (dydx, d2ydx2).

O Código 15 contém uma implementação PyTorch da diferenciação automática de segunda ordem dessa função para x(0,1/4,1/2,3/4,1). A Figura 2.16 mostra a comparação entre as diferenciações analítica (f, f′′) e automática (dydx, d2ydx2). Observemos que os resultados são idênticos, com diferenças na ordem da precisão computacional do PyTorch, que é da ordem de 107. Verifique!

Código 15: ex_autograd_d2f1d.py
1from torch import tensor, sin, pi, ones_like
2from torch.autograd import grad
3
4# entrada
5x = tensor([0.,0.25,0.5,0.75,1.])
6x = x.reshape(-1, 1)
7x.requires_grad_(True)
8
9# propagação
10y = sin(pi * x)
11
12# retropropagação y (gradiente de primeira ordem)
13dydx = grad(y, x, grad_outputs=ones_like(y),
14 create_graph=True)[0]
15
16# propagação dydx (gradiente de segunda ordem)
17d2ydx2 = grad(dydx, x, grad_outputs=ones_like(dydx),
18 create_graph=True)[0]
19
20# print gradiente
21print('d2ydx2 =', d2ydx2)
d2ydx2 = tensor([[-0.0000e+00],
[-6.9789e+00],
[-9.8696e+00],
[-6.9789e+00],
[ 8.6283e-07]], grad_fn=<MulBackward0>)

2.6.1 Autograd MLP

Os conceitos de diferenciação automática (autograd) são diretamente estendidos para redes do tipo Perceptron Multicamadas (MLP, do inglês, Multilayer Perceptron). Uma MLP é uma composição de funções definidas por parâmetros (pesos e biases). Seu treinamento ocorre em duas etapas151515Para mais detalhes, consulte a Subseção LABEL:cap_rede_feedforward_sec_modelo:ssec:treinamento.:

  1. 1.

    Propagação (forward): os dados de entrada são propagados para todas as funções da rede, produzindo a saída estimada.

  2. 2.

    Retropropagação (backward): a computação do gradiente do erro161616Medida da diferença entre o valor estimado e o valor esperado. em relação aos parâmetros da rede é realizado coletando as derivadas (gradientes) das funções da rede. Pela regra da cadeia, essa coleta é feita a partir da camada de saída em direção a camada de entrada da rede.

No seguinte exemplo, exploramos o fato de MLPs serem aproximadoras universais e avaliamos as aproximações das derivadas de primeira e segunda ordem de uma MLP na aproximação de uma função.

Exemplo 2.6.3.

Na Subseção 2.5.2, criamos uma MLP para aproximar a função f(x)=sen(πx) para x[1,1]. Aqui, vamos computar as derivadas de primeira e segunda ordem da MLP por diferenciação automática e comparar com as derivadas analíticas da função f(x)=sen(πx), que são

f(x)=πcos(πx), (2.85)
f′′(x)=π2sen(πx). (2.86)
Refer to caption
Figura 2.17: Comparação da diferenciação automática da MLP com a derivada analítica f(x)=πcos(πx).

Antes de computarmos os gradientes da MLP, voltemos ao Código 11 para adicionarmos uma linha de código ao final do treinamento da MLP, que armazena o modelo treinado em um arquivo. A linha de código é

1torch.save(model, 'modelo.pt')

Armazenado o modelo treinado, podemos carregá-lo em outro código para computarmos os gradientes de primeira e segunda ordem da MLP. O Código 16 contém uma implementação PyTorch da diferenciação automática da MLP para alguns valores de x[1,1]. A Figura 2.17 mostra a comparação entre os gradientes analíticos e automáticos de primeira e segunda ordem da MLP. Observemos que as aproximações das derivadas são boas, mas dependem da qualidade da aproximação da função pela MLP e as diferenças aumentam com a ordem da derivada. Verifique!

Código 16: mlp_autograd_apfun1d.py
1import torch
2
3# modelo treinado
4model = torch.load('model.pt',
5 weights_only=False).to('cpu')
6
7# autograd MLP
8X = torch.tensor([-1.,-0.5,0.,0.5,1.]).reshape(-1,1)
9X.requires_grad = True
10
11Y = model(X)
12
13# gradiente de primeira ordem
14DYDX = torch.autograd.grad(
15 Y, X,
16 grad_outputs=torch.ones_like(Y),
17 create_graph=True)[0]
18
19# gradiente de segunda ordem
20D2YDX2 = torch.autograd.grad(
21 DYDX, X,
22 grad_outputs=torch.ones_like(DYDX))[0]

2.6.2 Exercícios

E. 2.6.1.

Por diferenciação automática, compute o gradiente (a derivada) das seguintes funções:

  1. a)

    g(x)=cos2(x) para valores x[0,2π].

  2. b)

    f(x)=x22x+1 para valores x[2,2].

  3. c)

    h(x)=ln(x1) para valores x(1,2].

  4. d)

    u(t)=et2sen(t) para valores t[π,π].

Em cada caso, monte os grafos computacionais da propagação e da retropropagação na computação dos gradientes. Compare os valores computados com os valores esperados.

E. 2.6.2.

Para cada função no E.2.6.1, crie uma MLP para aproximar a função e, por diferenciação automática, compute as derivadas de primeira e segunda ordem. Compare os valores computados com os valores esperados.

E. 2.6.3.

Por diferenciação automática, compute os gradientes das seguintes funções:

  1. a)

    f(x,y)=x2+y2 para valores (x,y)[1,1]2.

  2. b)

    g(x,y)=exsen(xy) para valores (x,y)(1,2)×(0,π).

Em cada caso, monte os grafos computacionais da propagação e da retropropagação na computação dos gradientes. Compare os valores computados com os valores esperados.

E. 2.6.4.

Para cada função no E.2.6.3, crie uma MLP para aproximar a função e compute as derivadas /x, /y, 2/x2, 2/xy e 2/y2 pela MLP. Compare os valores computados com os valores esperados.

E. 2.6.5.

Para cada função no E.2.6.3, crie uma MLP para aproximar a função e compute o laplacino Δ=(2/x2+2/y2) pela MLP. Compare os valores computados com os valores esperados.


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
| | | |