用法
1. 前向传播outputs = model(inputs)
步骤:定义模型函数 -> 实例化模型 -> 定义输入 -> 前向传播计算输出
import torch
import torch.nn as nn
# 定义一个简单的线性模型
class SimpleModel(nn.Module):
def __init__(self):
super(SimpleModel, self).__init__()
self.linear = nn.Linear(10, 1)
def forward(self, x):
return self.linear(x)
# 创建模型实例
model = SimpleModel()
# 生成一些随机输入
inputs = torch.randn(32, 10) # 32个样本,每个样本有10个特征
# 前向传播计算输出
outputs = model(inputs)
2. 计算损失loss = criterion(outputs, targets)
步骤:定义损失函数 -> 定义目标/标签 -> 计算损失
# 定义损失函数
criterion = nn.MSELoss()
# 生成一些目标数据
targets = torch.randn(32, 1) # 32个样本,每个样本有1个目标值
# 计算损失
loss = criterion(outputs, targets)
3. 清零梯度optimizer.zero_grad()
在每个训练步骤中,需要进行以下几个步骤:
- 前向传播:计算损失函数,这一步将产生模型的预测值。
- 反向传播:计算损失函数相对于模型参数的梯度。
- 参数更新:使用优化器更新模型参数。
每次调用 loss.backward()
时,计算得到的梯度会被累积到已经存在的梯度上。如果不在每个训练步骤开始时清除这些梯度,会导致梯度的累积,从而影响模型参数的更新。
optimizer.zero_grad()
就是在每个训练步骤开始时清除之前的梯度,确保每次更新时梯度只来自当前的反向传播。在每个训练步骤开始时调用,确保反向传播计算的梯度只来自当前批次的数据,避免梯度累积影响模型训练。
4. 反向传播loss.backward()
反向传播是计算神经网络梯度的一种方法。通过反向传播,神经网络可以基于损失函数的梯度来更新参数,使得模型的预测结果更加准确。
在PyTorch中,每次进行张量操作时,都会动态构建一个计算图,这个计算图跟踪所有操作以及它们之间的依赖关系。调用loss.backward()
时,PyTorch会遍历这个计算图,从输出(损失)到输入(模型参数),计算每个参数的梯度,并将这些梯度存储在每个参数的.grad
属性中。
5. 更新参数optimizer.step()
在调用loss.backward()
之后,模型参数的.grad
属性中已经存储了损失函数相对于这些参数的梯度。optimizer.step()
则使用这些梯度来更新模型参数,这一步是通过优化器的算法(如随机梯度下降SGD、Adam、RMSprop等)来完成的,不同优化器在step()
中使用不同的算法来更新参数。
例子
例1:定义一个训练函数
def train(epoch):
RMSE = 0
cost_all = 0
for step, (batch_x, batch_mask_x, batch_y) in enumerate(loader):
batch_x = batch_x.type(torch.FloatTensor).cuda()
batch_mask_x = batch_mask_x.type(torch.FloatTensor).cuda()
# rec为实例化的模型
decoder = rec(batch_x) # 前向传播,计算预测值,会自动执行模型定义函数里的forward
loss, rmse = rec.loss(decoder=decoder, input=batch_x, optimizer=optimer, mask_input=batch_mask_x) # 计算损失
optimer.zero_grad() # 清零梯度
loss.backward() # 反向传播计算梯度
optimer.step() # 更新参数
cost_all += loss
RMSE += rmse
# detach()
RMSE = np.sqrt(RMSE.detach().cpu().numpy() / (train_mask_r == 1).sum())
print('epoch:', epoch, 'train RMSE:', RMSE)
可以看出训练五步走:前向传播 -> 计算损失 -> 清零梯度 -> 反向传播计算梯度 -> 更新参数
例2:训练多个Epoch
num_epochs = 10
for epoch in range(num_epochs):
for inputs, targets in dataloader:
# 前向传播
outputs = model(inputs)
# 计算损失
loss = criterion(outputs, targets)
# 清零梯度
optimizer.zero_grad()
# 反向传播计算梯度
loss.backward()
# 更新参数
optimizer.step()
print(f"Epoch {epoch+1}/{num_epochs}, Loss: {loss.item()}")