Proceso de cálculo del gradiente de pytorch.

1. Conocimientos básicos:

  1. De manera similar a las operaciones básicas en numpy, la función de pytorch es introducir GPU para acelerar las operaciones y agregar una interfaz gráfica, que es adecuada para operaciones de big data, especialmente el aprendizaje profundo.
  2. El gradiente es similar a la derivación: encuentra el mejor camino para el descenso del gradiente.
  3. Además de realizar operaciones de álgebra lineal, el tensor también puede calcular gradientes.

       Tensor es una matriz de n dimensiones en pytorch. Podemos construir un gráfico de retropropagación especificando el parámetro reuqires_grad=True para calcular los gradientes. En pytorch, generalmente se le llama gráfico de cálculo dinámico (DCG), es decir, gráfico de cálculo dinámico. Tres configuraciones requieren el cálculo automático de gradientes:

# 三种设置需要自动计算梯度的方式。
import torch
import numpy as np

# 方式一
x = torch.randn(2,2, requires_grad=True)

# 方式二
x = torch.autograd.Variable(torch.Tensor([2,3]), requires_grad=True)

#方式三
x = torch.tensor([2,3], requires_grad=True, dtype=torch.float64)

# 方式四
x = np.array([1,2,3] ,dtype=np.float64)
x = torch.from_numpy(x)
x.requires_grad = True
# 或者 x.requires_grad_(True)

2. Dé un ejemplo para ilustrar el proceso de cálculo del gradiente.

1) Primero crea la variable tensorial

# Create tensors.
import torch
x = torch.tensor(3.) # 数字
w = torch.tensor(4., requires_grad=True) # 数字
b = torch.tensor(5., requires_grad=True) # 数字
x, w, b

输出结果:
(tensor(3.), tensor(4., requiere_grad=True), tensor(5., requiere_grad=True))

2) Introduce la expresión y=w*x+b, y es tensor.

# Arithmetic operations
y = w * x + b
y

Resultado de salida:
tensor(17., grad_fn=<AddBackward0>)

3) Llame al método back() para derivar la derivada de la función y, es decir, encuentre el gradiente.

# Compute derivatives
y.backward()
#相当于函数变为 y = 3 * w + b

#求梯度:
# Display gradients
print('dy/dx:', x.grad)
print('dy/dw:', w.grad)
print('dy/db:', b.grad)

Resultado:
dy/dx: Ninguno
dy/dw: tensor(3.)
dy / db:tensor(1.)

Explicación: Para y = x * w + b, porque x es una constante 3, para y = 3 * w + b, la derivada parcial de y con respecto a x dy/dx=0, y la derivada parcial de y con respecto a x a w dy/dw = 3, Encuentre la derivada parcial de y con respecto a b dy/db=1.

3. Ejemplo 2 para ilustrar el proceso de cálculo del gradiente.

La mayoría de las funciones proporcionadas por Pytorch en términos de gradientes están diseñadas para redes neuronales. Las definiciones y explicaciones dadas en los documentos oficiales son relativamente abstractas. Lo siguiente se combinará con ejemplos para resumir mi comprensión de la función hacia atrás de cálculo de gradiente en Pytorch.

1) Construcción de red neuronal simple

Primero nos fijamos en una red neuronal muy simple.

Supongamos que x1 y x2 son las capas intermedias de la red neuronal, y es nuestra capa de salida, Y es el valor real y L es la pérdida. w1 y w2 son pesos correspondientes a x1 y x2.
La cifra anterior se expresa como una fórmula matemática:

  • x2=w1∗x1
  • y=w2∗x2
  • L=Y-y

Por lo general, usaremos el tensor de PyTorch para representar x1, w1, w2, x2, y. L también se puede representar mediante un tensor (las dimensiones pueden ser diferentes a las de otros tensores).
Entre ellos, llamamos al tensor que debemos configurar nosotros mismos (es decir, no calcular a través de otros tensores) como tensor de hoja. Por ejemplo, x1, w1 y w2 son los llamados tensores de hoja.
En pytorch, expresamos el modelo anterior.

import torch
import numpy as np
 
x1 = torch.from_numpy( 2*np.ones((2, 2), dtype=np.float32) )
x1.requires_grad_(True)   #设置该tensor可被记录操作用于梯度计算
w1 = torch.from_numpy( 5*np.ones((2, 2), dtype=np.float32) )
w1.requires_grad_(True)
print("x1 =", x1)
print("w1 =", w1)
 
x2 = x1 * w1
w2 = torch.from_numpy( 6*np.ones((2,2), dtype=np.float32) )
w2.requires_grad_(True)
print("x2 =", x2)
print("w2 =", w2)
 
y = x2 * w2
Y = torch.from_numpy( 10*np.ones((2,2), dtype=np.float32) )
print("y =", y)
print("Y =", Y)
 
L = Y - y

 Resultado de salida:

x1 = tensor([[2., 2.],
        [2., 2.]], require_grad=True)
w1 = tensor([[5., 5.],
        [5., 5.]], requiere_grad=True)
x2 = tensor([[10 ., 10.],
        [10., 10.]], grad_fn=<MulBackward0>)
w2 = tensor([[6., 6 .],
        [6., 6.]], requiere_grad=True)
y = tensor([[60., 60.],         [10., 10.]]) Y = tensor([[10., 10.],
        [60., 60.]], grad_fn=<MulBackward0>)

Nota sobre el código anterior:

  1. Establecer require_grad de un tensor en True guardará si el tensor registra todas las operaciones para calcular gradientes. Puede especificar directamente el atributo require_grad = True al crear el tensor, o puede usar la función x.requires_grad_(True).
  2. Al tensor obtenido mediante la operación (no el tensor creado por usted mismo) se le asignará automáticamente el atributo grad_fn. Esta propiedad representa la función de gradiente.

2) Cálculo del gradiente de propagación hacia atrás.

Una vez completado el cálculo de propagación hacia adelante anterior, queremos calcular el gradiente de propagación hacia atrás (BP). El principio básico es la regla de la cadena de derivación. La derivación de la red anterior es:

dL/dx1 = -1*w2*w1 = -30 (formato tensor)

dL/dw1=-1*w2*x1=-12 (formato tensor)

dL/dw2= -1*x2 =-10 (formato tensor)

PyTorch proporciona la función hacia atrás para calcular gradientes. El proceso de solución se convierte en: 

L.backward(torch.ones(2, 2, dtype=torch.float))
print(x1.grad) # 查看L对于x1的梯度
print(w1.grad) # L对于w1的梯度
print(w2.grad)

La función forward() se ejecuta para el último Tensor L, y se calculará el gradiente del Tensor de hoja que participó en la operación y generó el Tensor actual. Su valor de gradiente se almacenará en el atributo .grad del tensor de hoja.
Por ejemplo, en la red anterior, x1, w1 y w2 son los llamados tensores de hoja.

Resultado de salida:

tensor([[-30., -30.],
        [-30., -30.]])
tensor([ [-12., -12.],
        [-12., -12.]])
tensor([[-10., -10. ],
        [-10., -10.]])

1. Explicación de los parámetros de gradiente de la función hacia atrás.

gradiente se explica oscuramente en la documentación oficial de PyTorch. Entiendo que este parámetro representa la derivada del tensor de salida de la red (se supone que es L) con respecto al tensor que actualmente llama a la función back() (se supone que es Y ) Es decir gradiente=∂L∂Ygradiente=∂L∂Y.
(1) Por ejemplo, si el tensor de salida de mi modelo mencionado anteriormente es L, y el tensor que actualmente llama hacia atrás también es L, entonces el gradiente se expresa como ∂L∂L=1 ∂L∂L=1, es decir, un tensor cuyos elementos son todos 1. La dimensión del gradiente debe ser la misma que la dimensión del tensor que llama a la función back(). . Eso esL.backward(torch.ones(2, 2, dtype=torch.float)).
(2) Para otro ejemplo, supongamos que no conocemos la representación funcional de L con respecto a y, pero conocemos el gradiente de L con respecto a y (es decir, ∂L∂y=− 1∂L∂y=−1) Cuando , podemos llamar a la función hacia atrás en una posición específica, como el nodo intermedio y, y completar el proceso de gradiente de cálculo inverso mediante y.backward(-1 * torch.ones(2, 2, dtype=torch.float)). Un diseño de este tipo puede calcular el valor del gradiente en una ubicación específica mediante la regla de la cadena.
(3) Para el caso en el que L es un escalar (constante), no se pueden especificar parámetros y el parámetro predeterminado es torch.tensor(1). Para los casos en los que L es superior a 1 dimensión, el primer parámetro de forward() debe especificarse explícitamente.

2. Otros puntos a tener en cuenta sobre la función hacia atrás

(1) De forma predeterminada, el tensor obtenido mediante la misma operación solo puede ejecutarse hacia atrás() una vez. Si desea volver a realizar la ejecución hacia atrás (), debe calcular nuevamente el Tesnor obtenido.
(2) Cuando se obtienen varios tensores de la misma operación del tensor fuente, el método al revés () de los tensores obtenidos mediante estas operaciones agregará valores numéricos al atributo grad del tensor fuente. .
Por ejemplo, en el ejemplo anterior, suponiendo que hay otro tensor L2 obtenido operando en x1, el resultado del gradiente se acumulará en x1.grad después de ejecutar L2.backward().

print("x1.grad =",x1.grad) # 原来x1的梯度 
L2 = x1 * x1
L2.backward(torch.ones(2, 2, dtype=torch.float))
print("x1.grad =", x1.grad) # 计算L2的backward后梯度结果将累加到x1.grad中
x1.grad = tensor([[-26., -26.],
        [-26., -26.]])
x1.grad = tensor([[-22., -22.],
        [-22., -22.]])

 (3) Solo los tensores de hoja (creados por usted mismo y no calculados a través de otros tensores) pueden calcular gradientes. De lo contrario, después de ejecutar L.backwar() para x1 que no es hoja, x1.grad será Ninguno. Al definir nodos de hoja, tenga en cuenta que deben crearse directamente con antorcha y no pueden calcularse mediante tensor. Por ejemplo, cambie la definición de x1 en el ejemplo a x1 = 2 * torch.ones(2, 2, requires_grad=True, dtype=torch.float) . De hecho, ya realizó el cálculo del tensor, x1 ya no será una hoja y torch.ones() en la expresión es la hoja.

Referencia:Función hacia atrás de cálculo de gradiente de aprendizaje de Pytorch - Yabei Fries - Blog Park

3.Ejemplos

import torch
a = torch.tensor([2., 3.], requires_grad=True)    
b = a + 3
c = b * b * 3
out = c.mean()
out.backward(retain_graph=True)
a.grad

Salida de resultados:

tensor([15., 18.])

Derivación de gradiente:

 

Resumir:

Note1:Enpytorch, solo los números de punto flotante tienen gradientes< a i=4 >, por lo que en el método anterior, el tipo d del tensor se especifica como tipo torch.float32, torch.float64, o con un punto decimal durante la inicialización.

Supongo que te gusta

Origin blog.csdn.net/qimo601/article/details/123849789
Recomendado
Clasificación