[Pytorch 3.2 autograd] resumo do autograd

Link de nota: link de autograd O
seguinte é o conteúdo da nota
3.2 Autograd
torch.autograd é um conjunto de motor de derivação automática especialmente desenvolvido para a conveniência dos cálculos do usuário, que pode construir automaticamente um gráfico de cálculo de acordo com o processo de entrada e propagação direta, e realizar a propagação de volta.
3.2 .1 Variável
de importação futura print_function
import torch as t
from torch.autograd import Variável como V
“” "--------------------" " "

Para criar a variável do tensor, você precisa especificar a derivada

a = V (t.ones (3, 4), requer_grad = Verdadeiro)
a
“” "--------------------" ""
b = V (t. zeros (3,4))
b
“” "--------------------" ""

O uso de funções é consistente com o Tensor

c = a + b

c = a.add (b)
c
“” "--------------------" ""
d = c.sum ()
d.backward () # 反向传播
“” "--------------------" ""

Preste atenção na diferença entre os dois

O primeiro se torna tensor após obter dados e calcula a soma do tensor para obter o float

Este último ainda é variável após o cálculo da soma

c.data.sum (), c.sum ()
“” "--------------------" ""
a.grad
“” "----- --------------- "" "

Embora não seja especificado que C requer orientação, C depende de A e A requer orientação

Portanto, o atributo requirements_grad de c será automaticamente definido como verdadeiro

a.requires_grad, b.requires_grad, c.requires_grad, d.requires_grad
“” "--------------------" ""

A variável criada pelo usuário pertence ao nó folha, e o grad_fn correspondente é nenhum

a.is_leaf, b.is_leaf, c.is_leaf, d.is_leaf
"" "--------------------" ""
# c.grad é nenhum, c é não Leaf node, seu gradiente é usado para calcular o gradiente de A
# Embora c.requeires_grad = True, ele será liberado imediatamente após o cálculo do gradiente
c.grad é Nenhum
A diferença entre derivação manual e Atograd
de importação futura print_function
import tocch as t
de torch.autograd import Variável como V

def f (x):
“” “计算 y” ""
y = x ** 2 * t.exp (x)
retorna y

def gradf (x):
“手动 求 导”
dx = x * 2 t.exp (x) + x ** 2 t.exp (x)
return dx
“” "------------ -------- "" "
x = V (t.randn (3,4), requer_grad = Verdadeiro)
y = f (x)
y
“ ”" ------------ -------- "" "
y.backward (t.ones (y.size ())) # grad_variable 形状 与 Y 一致
x.grad
“ ”" ------------ -------- "" "

A fórmula calculada por autograd é a mesma que o resultado do cálculo manual

gradf (x)
autograd 的 细节:
from future import print_function
import tocch as t
from torch.autograd import Variable as V

x = V (t.ones (1))
b = V (t.rand (1), requer_grad = Verdadeiro)
w = V (t.rand (1), requer_grad = Verdadeiro)
y = w * x # 等价 于y = w.mul (x)
z = y + b # 等价 于 z = y.add (b)
“” "--------------------" " "
x.requires_grad, b.requires_grad, w.requires_grad
“ ”" -------------------- "" "

Embora y.requires_grad não seja especificado como True, porque y depende de w que precisa ser guiado

Portanto, y.requires_grad é True

y.requires_grad
“” "--------------------" ""
x.is_leaf, w.is_leaf, b.is_leaf, y.is_leaf, z.is_leaf
“” "--------------------" ""

next_functions salva a entrada de grad_fn, que é uma tupla, e os elementos da tupla também são Function

O primeiro é y, que é a saída da multiplicação (mul), então a função retropropagação correspondente y.grad_fn é MulBackward

O segundo é b, é um nó folha, criado pelo usuário, grad_fn é Nenhum, mas há

z.grad_fn.next_functions
“” "--------------------" ""

O grad_fn da variável corresponde à função na figura

z.grad_fn.next_functions [0] [0] == y.grad_fn
“” "--------------------" ""

O grad_fn do nó folha é Nenhum

Quando w.grad_fn, x.grad_fn
calcula o gradiente de w, o valor de x ($ {\ parcial y \ over \ parcial w} = x $) é usado. Esses valores serão salvos como um buffer no futuro O processo será apagado automaticamente após o cálculo do gradiente. Para poder retropropagar várias vezes, você precisa especificar retém_graph para reter esses buffers.
de importação futura print_function import tocch
as t
from torch.autograd import Variável as V

Use reter_grafo para salvar o buffer

z.backward (reter_graph = True)
w.grad
“” "--------------------" ""

Múltipla propagação de retorno, acúmulo de gradiente, que é o significado do logotipo AccumulateGrad em w

z.backward ()
w.grad
PyTorch usa um gráfico dinâmico. Seu gráfico de cálculo é criado do zero sempre que é propagado para frente, para que possa usar instruções de controle Python (como for, if, etc.) para criar cálculos com base em requisitos Figura. Isso é muito útil no campo do processamento de linguagem natural, significa que você não precisa construir todos os caminhos de gráfico possíveis com antecedência, o gráfico é construído em tempo de execução.
de importação futura print_function import tocch
as t
from torch.autograd import Variável as V

def abs (x):
if x.data [0]> 0: return x
else: return -x

x = t.ones (1, requer_grad = Verdadeiro)
y = abs (x)
y.backward ()
x.grad
“” "--------------------" ""
x = -1 * t.ones (1)
x = x.requires_grad_ ()
y = abs (x)
y.backward ()
x.grad
“” "------------- ------- "" "
def f (x):
resultado = 1
para ii em x:
se ii.item ()> 0: resultado = ii * resultado
retornar resultado
x = t.arange (-2.0,4.0 , requer_grad = Verdadeiro)

y = f (x) # y = x [3] * x [4] * x [5]
y.backward ()
x.grad
“” "---------------- ---- "" "
Às vezes, podemos não querer autograd para diferenciar tensor. Considerando que a derivação precisa armazenar em cache muitas estruturas intermediárias e adicionar sobrecarga de memória / vídeo, então podemos desligar a derivação automática. Para cenários que não exigem retropropagação (como inferência, ou seja, ao testar inferência), desligar a derivação automática pode atingir um certo grau de melhoria de velocidade e economizar cerca de metade da memória de vídeo, porque não precisa alocar espaço para calcular o gradiente.
x = t.ones (1, requer_grad = Verdadeiro)
w = t.rand (1, requer_grad = Verdadeiro)
y = x * w

y depende de w e w.requires_grad = True

x.requires_grad, w.requires_grad, y.requires_grad
“” "--------------------" ""
com t.no_grad ():
x = t.ones ( 1)
w = t.rand (1, requer_grad = Verdadeiro)
y = x * w

y depende de w e x. Embora w.requires_grad = True, o requirements_grad de y ainda é falso

x.requires_grad, w.requires_grad, y.requires_grad
“” "--------------------" ""

Equivalente a t.no_grad ()

t.set_grad_enabled (False)
x = t.ones (1)
w = t.rand (1, requires_grad = True)
y = x * w

y depende de w e x. Embora w.requires_grad = True, o requirements_grad de y ainda é falso

x.requires_grad, w.requires_grad, y.requires_grad

No processo de retropropagação, a derivada do nó não folha é apagada após a conclusão do cálculo. Se você deseja visualizar o gradiente dessas variáveis, existem dois métodos:
use a função autograd.grad.
Use o gancho
autograd.grad e os métodos hook são ferramentas muito poderosas. Para um uso mais detalhado, consulte a documentação oficial da API. Aqui está um exemplo para ilustrar o uso básico. O método do gancho é recomendado, mas no uso real, você deve tentar evitar a modificação do valor do grad.
x = t.ones (3, requer_grad = Verdadeiro)
w = t.rand (3, requer_grad = Verdadeiro)
y = x * w

y depende de w e w.requires_grad = True

z = y.sum ()
x.requires_grad, w.requires_grad, y.requires_grad
“” "--------------------" ""

O grad do nó não folha é apagado automaticamente após o cálculo, y.grad é Nenhum

z.backward ()
(x.grad, w.grad, y.grad)
“” "--------------------" ""

O primeiro método: use grad para obter o gradiente da variável intermediária

x = t.ones (3, requer_grad = Verdadeiro)
w = t.rand (3, requer_grad = Verdadeiro)
y = x * w
z = y.sum ()

O gradiente de z a y, chamando implicitamente para trás ()

t.autograd.grad (z, y)
“” "--------------------" ""

O segundo método: use o gancho

Gancho é uma função, a entrada é gradiente, não deve haver valor de retorno

def variable_hook (grad):
print ('gradiente de y:', grad)

x = t.ones (3, requer_grad = Verdadeiro)
w = t.rand (3, requer_grad = Verdadeiro)
y = x * w

Gancho de registro

hook_handle = y.register_hook (variable_hook)
z = y.sum ()
z.backward ()

A menos que você precise usar o gancho todas as vezes, lembre-se de remover o gancho depois de usá-lo

hook_handle.remove ()
“” "--------------------" ""

O significado do atributo grad na variável e o parâmetro grad_variables da função backward
x = t.arange (0,3, require_grad = True)
y = x 2 + x * 2
z = y.sum ()
z.backward () # reverso de z Para propagar
x.grad
"" "--------------------" ""
x = t.arange (0,3, requer_grad = Verdadeiro)
y = x
2 + x * 2
z = y.sum ()
y_gradient = t.Tensor ([1,1,1]) # dz / dy
y.backward (y_gradient)
# Propagação para trás de y x.grad
usa variável para implementar regressão linear
importar tocha como t
% matplotlib inline
de matplotlib importar pyplot como plt
de IPython importar exibir
importar numpy como np
“” "--------------------" ""

Defina a semente do número aleatório, de modo que a seguinte saída seja consistente quando executado em computadores diferentes

t.manual_seed (1000)
def get_fake_data (batch_size = 8):
'' 'Gerar dados aleatórios: y = x * 2 + 3, mais algum ruído' ''
x = t.rand (batch_size, 1) * 5
y = x * 2 + 3 + t.randn (batch_size, 1)
retorna x, y
“” "--------------------" ""

Vamos ver como é a distribuição xy

x, y = get_fake_data ()
plt.scatter (x.squeeze (). numpy (), y.squeeze (). numpy ())
“” "---------------- ---- "" "

Parâmetros de inicialização aleatórios

w = t.rand (1,1, requer_grad = Verdadeiro)
b = t.zeros (1,1, requer_grad = Verdadeiro)
perdas = np.zeros (500)

lr = 0,005 # taxa de aprendizagem

para ii no intervalo (500):
x, y = get_fake_data (batch_size = 32)

# forward:计算loss
y_pred = x.mm(w) + b.expand_as(y)
loss = 0.5 * (y_pred - y) ** 2
loss = loss.sum()
losses[ii] = loss.item()

# backward:手动计算梯度
loss.backward()

# 更新参数
w.data.sub_(lr * w.grad.data)
b.data.sub_(lr * b.grad.data)

# 梯度清零
w.grad.data.zero_()
b.grad.data.zero_()

if ii%50 ==0:
    # 画图
    display.clear_output(wait=True)
    x = t.arange(0, 6).view(-1, 1)
	x = t.tensor(x, dtype=t.float32)  # 要注意格式
    y = x.mm(w.data) + b.data.expand_as(x)
    plt.plot(x.numpy(), y.numpy()) # predicted
    
    x2, y2 = get_fake_data(batch_size=20) 
    plt.scatter(x2.numpy(), y2.numpy()) # true data
    
    plt.xlim(0,5)
    plt.ylim(0,13)   
    plt.show()
    plt.pause(0.5)

print (w.item (), b.item ())
“” "--------------------" ""
plt.plot (perdas)
plt.ylim ( 5,50)

Acho que você gosta

Origin blog.csdn.net/Leomn_J/article/details/113122576
Recomendado
Clasificación