1. Autogrado: diferenciación automática
El núcleo de todas las redes neuronales en PyTorch es el autograd
paquete. Primero presentamos brevemente este paquete y luego entrenamos nuestra primera red neuronal.
autograd
El paquete proporciona una diferenciación automática para todas las operaciones en el tensor. Es un marco definido en tiempo de ejecución, lo que significa que la propagación hacia atrás se define de acuerdo con la forma en que se ejecuta el código, y cada iteración puede ser diferente.
A continuación, usamos algunos ejemplos simples para ver este paquete:
Tensor
torch.Tensor
Es la clase principal del paquete. Si establece su propiedad .requires_grad
en Verdadero, comenzará a rastrear todas las operaciones en él. Después de completar el cálculo, puede llamar .backward()
y calcular automáticamente todos los gradientes. El gradiente de este tensor se acumulará en el .grad
atributo.
Para evitar que un tensor rastree el historial, puede llamar para .detach()
separarlo del historial de cálculos y evitar que se rastreen cálculos futuros.
Para evitar el seguimiento del historial (y el uso de la memoria), también puede usar torch.no_grad () para envolver el bloque de código: esto puede ser particularmente útil al evaluar el modelo, porque el modelo puede tener requires_grad = True
parámetros entrenables, pero no necesitamos gradientes.
Hay otra clase que es muy importante para la implementación de autogrado-Función.
El tensor y la función están conectados entre sí y construyen un gráfico acíclico para construir un proceso de cálculo completo. Cada tensor tiene un .grad_fn
atributo que se refiere a la función del tensor creado (excepto los tensores creados por el usuario, que grad_fn
son None
).
Si desea calcular la derivada, puede llamarla en Tensor .backward()
. Si el tensor es un escalar (es decir, contiene datos de un elemento), no necesita backward()
especificar ningún parámetro, pero si tiene más elementos, necesita especificar un parámetro de gradiente, que es un tensor de forma coincidente.
import torch
Cree un tensor y configúrelo requires_grad = True
para realizar un seguimiento de su cálculo
x = torch.ones(2, 2, requires_grad=True)
print(x)
输出:
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
Realizar operaciones sobre tensores:
y = x + 2
print(y)
输出:
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward0>)
Debido a que y es creado por una operación, tiene grad_fn y x es creado por el usuario, por lo que su grad_fn es None.
print(y.grad_fn)
print(x.grad_fn)
输出:
<AddBackward0 object at 0x000001E020B794A8>
None
Realice la operación en y
z = y * y * 3
out = z.mean()
print(z, out)
输出:
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward1>)
.requires_grad_(...)
Cambie el requires_grad
logotipo del Tensor existente en su lugar . Si no se proporciona, el indicador de entrada tiene el valor predeterminado Falso.
a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
输出:
False
True
<SumBackward0 object at 0x000001E020B79FD0>
Gradientes
Ahora realicemos la propagación hacia atrás, que es out.backward()
equivalente a ejecutarout.backward(torch.tensor(1.))
out.backward()
Genere el gradiente d (out) / dx de out ax:
print(x.grad)
输出:
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
Veamos ahora un ejemplo de producto vectorial jacobiano:
x = torch.randn(3, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
print(y)
输出:
tensor([ 384.5854, -13.6405, -1049.2870], grad_fn=<MulBackward0>)
Ahora, en este caso, y ya no es un escalar. torch.autograd
No es posible calcular directamente el determinante jacobiano completo, pero si solo queremos el producto vectorial jacobiano, solo necesitamos pasar el vector hacia atrás como parámetro:
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)
print(x.grad)
输出:
tensor([5.1200e+01, 5.1200e+02, 5.1200e-02])
También puede usar el código torch.no_grad () y usar .requires_grad = True en el tensor para dejar de usar el historial de seguimiento.
print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad():
print((x ** 2).requires_grad)
输出:
True
True
False