用法 

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()

在每个训练步骤中,需要进行以下几个步骤:

  1. 前向传播:计算损失函数,这一步将产生模型的预测值。
  2. 反向传播:计算损失函数相对于模型参数的梯度。
  3. 参数更新:使用优化器更新模型参数。

每次调用 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()}")
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐