1. 动态图和静态图的区别?自动微分是什么?
一文详解pytorch的“动态图”与“自动微分”技术 - 知乎
2. 教程
https://pytorch.apachecn.org/#/docs/1.7/043
loss = (prediction - labels).sum()
loss.backward() # backward pass
当我们在误差张量上调用.backward()
时,开始反向传播。 然后,Autograd 会为每个模型参数计算梯度并将其存储在参数的.grad
属性中。
optim.step() #gradient descent
调用.step()
启动梯度下降。 优化器通过.grad
中存储的梯度来调整每个参数。
a = torch.tensor([2., 3.], requires_grad=True)
external_grad = torch.tensor([1., 1.])
loss.backward(gradient=external_grad)
# gradient是与loss形状相同的张量,它表示loss相对于本身的梯度,都是1
2. 若loss 是标量:
loss.sum().backward()
概念:有向无环图。像一棵倒立的数。下面是输入张量,根是输出张量。
问题1:什么是动态图?
每次 .backward()
调用之后, 自动构建新图。因此可以向python一样断点调试等。
即使只有一个输入张量具有 requires_grad=True
,操作的输出张量也将需要梯度。
.requires_grad = False : 冻结参数, 用于微调模型。
torch.no_grad() 中的上下文管理器可以冻结参数。
x = torch.tensor([1], requires_grad=True)
with torch.no_grad():
y = x * 2
y.requires_grad # False
@torch.no_grad()
def doubler(x):
return x * 2
z = doubler(x)
z.requires_grad # False
定义网络:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 自定义的层
# self.层名 = ...
def forward(self, x):
# 操作
return x
net = Net()
print(net)
只需要定义forward
函数,就可以使用autograd
为您自动定义backward
函数(计算梯度
模型的可学习参数由net.parameters()
返回
torch.nn
仅支持小批量,不支持单个样本的输入。
例如,nn.Conv2d
将采用(b,c,h,w)
的 4D 张量。
如果只有一个样本,只需使用input.unsqueeze(0)
添加一个假批量尺寸(1,c,h,w)
。
损失函数:nn.MSELoss
CV: torchvision
包有:torchvision.datasets和torch.utils.data.DataLoader。
GPU上训练
定义新的 Autograd 函数
可以通过定义torch.autograd.Function
的子类并实现forward
和backward
函数来轻松定义自己的 Autograd 运算符。 然后,我们可以通过构造实例并像调用函数一样调用新的 Autograd 运算符,并传递包含输入数据的张量。
class LegendrePolynomial3(torch.autograd.Function):
"""
We can implement our own custom autograd Functions by subclassing
torch.autograd.Function and implementing the forward and backward passes
which operate on Tensors.
"""
@staticmethod
def forward(ctx, input):
"""
In the forward pass we receive a Tensor containing the input and return
a Tensor containing the output. ctx is a context object that can be used
to stash information for backward computation. You can cache arbitrary
objects for use in the backward pass using the ctx.save_for_backward method.
"""
ctx.save_for_backward(input)
return 0.5 * (5 * input ** 3 - 3 * input)
@staticmethod
def backward(ctx, grad_output):
"""
In the backward pass we receive a Tensor containing the gradient of the loss
with respect to the output, and we need to compute the gradient of the loss
with respect to the input.
"""
input, = ctx.saved_tensors
return grad_output * 1.5 * (5 * input ** 2 - 1)
使用:
P3 = LegendrePolynomial3.apply
y_pred = a + b * P3(c + d * x)
可以使用常规的 Python 流控制来实现循环(如for),并且可以通过在定义forward时简单地多次重复使用相同的参数来实现权重共享
TensorDataset是一个数据集包装张量。 通过定义索引的长度和方式,这也为我们提供了沿张量的第一维进行迭代,索引和切片的方法。
from torch.utils.data import TensorDataset
train_ds = TensorDataset(x_train, y_train)
xb,yb = train_ds[i*bs : i*bs+bs]
DataLoader
负责批量管理, DataLoader
使迭代迭代变得更加容易。
from torch.utils.data import DataLoader
train_dl = DataLoader(train_ds, batch_size=bs)
for xb,yb in train_dl:
pred = model(xb)
# 验证集
valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)
总是在训练之前调用model.train()
,并在推理之前调用model.eval()
,因为诸如nn.BatchNorm2d
和nn.Dropout
之类的层会使用它们,以确保这些不同阶段的行为正确。
model.eval()
with torch.no_grad():
valid_loss = sum(loss_func(model(xb), yb) for xb, yb in valid_dl)
def loss_batch(model, loss_func, xb, yb, opt=None):
loss = loss_func(model(xb), yb)
if opt is not None:
loss.backward()
opt.step()
opt.zero_grad()
return loss.item(), len(xb)
import numpy as np
def fit(epochs, model, loss_func, opt, train_dl, valid_dl):
for epoch in range(epochs):
model.train()
for xb, yb in train_dl:
loss_batch(model, loss_func, xb, yb, opt)
model.eval()
with torch.no_grad():
losses, nums = zip(
*[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
)
val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)
print(epoch, val_loss)
def get_data(train_ds, valid_ds, bs):
return (
DataLoader(train_ds, batch_size=bs, shuffle=True),
DataLoader(valid_ds, batch_size=bs * 2),
)
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(epochs, model, loss_func, opt, train_dl, valid_dl)
Sequential
对象以顺序方式运行其中包含的每个模块
从给定的函数定义自定义层, 然后在使用Sequential
定义网络时可以使用该层。
1. Conv2d
CLASS torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)
dilation: Default: 1
2. MaxPool2d
CLASS torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)