优化是一个我们尝试为深度学习模型找到最佳参数集的过程。优化器生成新的参数值,并使用某个标准来评估它们,以确定最佳选项。作为神经网络架构的重要组成部分,优化器有助于确定最佳权重、偏差或其他将产生所需输出的超参数。
PyTorch 中有许多种类的优化器,每种都有其优缺点。它们包括 Adagrad、Adam、RMSProp 等。
在之前的教程中,我们实现了优化器更新权重和偏差的所有必要步骤。在这里,您将了解一些 PyTorch 包,这些包可以使优化器的实现更加容易。特别是,您将学习
- 如何使用 PyTorch 中的一些包来实现优化器。
- 如何从 PyTorch 的 'nn' 包中导入线性类和损失函数。
- 如何使用 PyTorch 的 'optim' 包实现随机梯度下降和 Adam(最常用的优化器)。
- 如何自定义模型的权重和偏差。
请注意,我们将在 PyTorch 系列的后续教程中使用相同的实现步骤。
通过我的《用PyTorch进行深度学习》一书来启动你的项目。它提供了包含可用代码的自学教程。
让我们开始吧。

使用 PyTorch 中的优化器。
图片来源:Jean-Daniel Calame。部分权利保留。
概述
本教程分为五个部分:
- 准备数据
- 构建模型和损失函数
- 使用随机梯度下降训练模型
- 使用 Adam 优化器训练模型
- 绘制图表
准备数据
让我们开始导入本教程中将使用的库。
1 2 3 4 |
import matplotlib.pyplot as plt import numpy as np import torch from torch.utils.data import Dataset, DataLoader |
我们将使用自定义数据类。数据是一条具有斜率和截距分别为 -5 和 1 的从 -5 到 5 的值。此外,我们将添加与 x
相同的值的噪声,并训练模型来估计这条线。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 创建我们的数据集类 class Build_Data(Dataset): # 构造函数 def __init__(self): self.x = torch.arange(-5, 5, 0.1).view(-1, 1) self.func = -5 * self.x + 1 self.y = self.func + 0.4 * torch.randn(self.x.size()) self.len = self.x.shape[0] # 获取数据 def __getitem__(self, index): return self.x[index], self.y[index] # 获取数据长度 def __len__(self): return self.len |
现在,我们使用它来创建我们的数据集对象并绘制数据。
1 2 3 4 5 6 7 8 9 10 11 |
# 创建数据集对象 data_set = Build_Data() # 绘制和可视化数据点 plt.plot(data_set.x.numpy(), data_set.y.numpy(), 'b+', label = 'y') plt.plot(data_set.x.numpy(), data_set.func.numpy(), 'r', label = 'func') plt.xlabel('x') plt.ylabel('y') plt.legend() plt.grid('True', color='y') plt.show() |

来自自定义数据集对象的数据
总而言之,以下是创建图表的完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import matplotlib.pyplot as plt import numpy as np import torch from torch.utils.data import Dataset, DataLoader # 创建我们的数据集类 class Build_Data(Dataset): # 构造函数 def __init__(self): self.x = torch.arange(-5, 5, 0.1).view(-1, 1) self.func = -5 * self.x + 1 self.y = self.func + 0.4 * torch.randn(self.x.size()) self.len = self.x.shape[0] # 获取数据 def __getitem__(self, index): return self.x[index], self.y[index] # 获取数据长度 def __len__(self): return self.len # 创建数据集对象 data_set = Build_Data() # 绘制和可视化数据点 plt.plot(data_set.x.numpy(), data_set.y.numpy(), 'b+', label = 'y') plt.plot(data_set.x.numpy(), data_set.func.numpy(), 'r', label = 'func') plt.xlabel('x') plt.ylabel('y') plt.legend() plt.grid('True', color='y') plt.show() |
构建模型和损失函数
在之前的教程中,我们为线性回归模型和损失函数创建了一些函数。PyTorch 只需几行代码即可实现这一点。以下是我们如何从 PyTorch 的 nn
包导入内置线性回归模型及其损失准则。
1 2 |
model = torch.nn.Linear(1, 1) criterion = torch.nn.MSELoss() |
模型参数在创建时是随机化的。我们可以通过以下方式验证这一点
1 2 |
... print(list(model.parameters())) |
它会打印:
1 2 3 |
[参数包含 tensor([[-5.2178]], requires_grad=True), Parameter containing tensor([-5.5367], requires_grad=True)] |
虽然 PyTorch 会随机初始化模型参数,但我们也可以自定义它们以使用自己的参数。我们可以按如下方式设置我们的权重和偏差。请注意,在实际应用中我们很少需要这样做。
1 2 3 |
... model.state_dict()['weight'][0] = -10 model.state_dict()['bias'][0] = -20 |
在开始训练之前,让我们创建一个 DataLoader
对象将数据集加载到管道中。
1 2 3 |
... # 创建 Dataloader 对象 trainloader = DataLoader(dataset = data_set, batch_size=1) |
想开始使用PyTorch进行深度学习吗?
立即参加我的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
使用随机梯度下降训练模型
要使用我们选择的优化器,我们可以从 PyTorch 导入 optim
包。它包含了几个最先进的参数优化算法,这些算法只需一行代码即可实现。例如,随机梯度下降 (SGD) 可按如下方式提供。
1 2 3 |
... # 定义优化器 optimizer = torch.optim.SGD(model.parameters(), lr=0.01) |
作为输入,我们向构造函数提供了 model.parameters()
来指定要优化的内容。我们还定义了步长或学习率 (lr
)。
为了帮助以后可视化优化器的进度,我们创建一个空列表来存储损失,并让我们的模型训练 20 个 epoch。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
... loss_SGD = [] n_iter = 20 for i in range(n_iter): for x, y in trainloader: # 正向传播中进行预测 y_hat = model(x) # 计算原始数据点和预测数据点之间的损失 loss = criterion(y_hat, y) # 将损失存储到列表中 loss_SGD.append(loss.item()) # 每次迭代后清零梯度 optimizer.zero_grad() # 反向传播以计算损失相对于可学习参数的梯度 loss.backward() # 每次迭代后更新参数 optimizer.step() |
在上面,我们将数据样本馈送到模型进行预测并计算损失。梯度在反向传播期间计算,并优化参数。虽然在之前的会话中我们使用了额外的代码行来更新参数和清零梯度,但 PyTorch 提供了优化器中的 zero_grad()
和 step()
方法来使过程简洁。
您可以增加上面 DataLoader
对象中的 batch_size
参数以进行小批量梯度下降。
总而言之,完整的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
import matplotlib.pyplot as plt import numpy as np import torch from torch.utils.data import Dataset, DataLoader # 创建我们的数据集类 class Build_Data(Dataset): # 构造函数 def __init__(self): self.x = torch.arange(-5, 5, 0.1).view(-1, 1) self.func = -5 * self.x + 1 self.y = self.func + 0.4 * torch.randn(self.x.size()) self.len = self.x.shape[0] # 获取数据 def __getitem__(self, index): return self.x[index], self.y[index] # 获取数据长度 def __len__(self): return self.len # 创建数据集对象 data_set = Build_Data() model = torch.nn.Linear(1, 1) criterion = torch.nn.MSELoss() # 创建 Dataloader 对象 trainloader = DataLoader(dataset = data_set, batch_size=1) # 定义优化器 optimizer = torch.optim.SGD(model.parameters(), lr=0.01) loss_SGD = [] n_iter = 20 for i in range(n_iter): for x, y in trainloader: # 正向传播中进行预测 y_hat = model(x) # 计算原始数据点和预测数据点之间的损失 loss = criterion(y_hat, y) # 将损失存储到列表中 loss_SGD.append(loss.item()) # 每次迭代后清零梯度 optimizer.zero_grad() # 反向传播以计算损失相对于可学习参数的梯度 loss.backward() # 每次迭代后更新参数 optimizer.step() |
使用 Adam 优化器训练模型
Adam 是训练深度学习模型最常用的优化器之一。当您拥有大量训练数据时,它速度快且效率很高。Adam 是一个具有动量的优化器,当模型复杂时(在大多数深度学习情况下),它的性能可能优于 SGD。
在 PyTorch 中,将上面的 SGD 优化器替换为 Adam 优化器非常简单。虽然所有其他步骤都相同,但我们只需要将 SGD()
方法替换为 Adam()
来实现该算法。
1 2 3 |
... # 定义优化器 optimizer = torch.optim.Adam(model.parameters(), lr=0.01) |
同样,我们将定义迭代次数和一个空列表来存储模型损失。然后我们可以运行训练。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
... loss_Adam = [] n_iter = 20 for i in range(n_iter): for x, y in trainloader: # 正向传播中进行预测 y_hat = model(x) # 计算原始数据点和预测数据点之间的损失 loss = criterion(y_hat, y) # 将损失存储到列表中 loss_Adam.append(loss.item()) # 每次迭代后清零梯度 optimizer.zero_grad() # 反向传播以计算损失相对于可学习参数的梯度 loss.backward() # 每次迭代后更新参数 optimizer.step() |
将所有内容放在一起,完整的代码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
import matplotlib.pyplot as plt import numpy as np import torch from torch.utils.data import Dataset, DataLoader # 创建我们的数据集类 class Build_Data(Dataset): # 构造函数 def __init__(self): self.x = torch.arange(-5, 5, 0.1).view(-1, 1) self.func = -5 * self.x + 1 self.y = self.func + 0.4 * torch.randn(self.x.size()) self.len = self.x.shape[0] # 获取数据 def __getitem__(self, index): return self.x[index], self.y[index] # 获取数据长度 def __len__(self): return self.len # 创建数据集对象 data_set = Build_Data() model = torch.nn.Linear(1, 1) criterion = torch.nn.MSELoss() # 创建 Dataloader 对象 trainloader = DataLoader(dataset = data_set, batch_size=1) # 定义优化器 optimizer = torch.optim.Adam(model.parameters(), lr=0.01) loss_Adam = [] n_iter = 20 for i in range(n_iter): for x, y in trainloader: # 正向传播中进行预测 y_hat = model(x) # 计算原始数据点和预测数据点之间的损失 loss = criterion(y_hat, y) # 将损失存储到列表中 loss_Adam.append(loss.item()) # 每次迭代后清零梯度 optimizer.zero_grad() # 反向传播以计算损失相对于可学习参数的梯度 loss.backward() # 每次迭代后更新参数 optimizer.step() |
绘制图表
我们已成功实现了用于模型训练的 SGD 和 Adam 优化器。让我们可视化模型损失在训练过程中在两种算法中的下降情况,这些损失存储在列表 loss_SGD
和 loss_Adam
中
1 2 3 4 5 6 7 |
... plt.plot(loss_SGD,label = "随机梯度下降") plt.plot(loss_Adam,label = "Adam 优化器") plt.xlabel('epoch') plt.ylabel('成本/总损失') plt.legend() plt.show() |
您可以看到,在上面的示例中,SGD 比 Adam 收敛得更快。这是因为我们正在训练一个线性回归模型,其中 Adam 提供的算法是过度的。
将所有内容放在一起,完整的代码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
import matplotlib.pyplot as plt import numpy as np import torch from torch.utils.data import Dataset, DataLoader # 创建我们的数据集类 class Build_Data(Dataset): # 构造函数 def __init__(self): self.x = torch.arange(-5, 5, 0.1).view(-1, 1) self.func = -5 * self.x + 1 self.y = self.func + 0.4 * torch.randn(self.x.size()) self.len = self.x.shape[0] # 获取数据 def __getitem__(self, index): return self.x[index], self.y[index] # 获取数据长度 def __len__(self): return self.len # 创建数据集对象 data_set = Build_Data() model = torch.nn.Linear(1, 1) criterion = torch.nn.MSELoss() # 创建 Dataloader 对象 trainloader = DataLoader(dataset = data_set, batch_size=1) # 定义优化器 optimizer = torch.optim.Adam(model.parameters(), lr=0.01) loss_SGD = [] n_iter = 20 for i in range(n_iter): for x, y in trainloader: # 正向传播中进行预测 y_hat = model(x) # 计算原始数据点和预测数据点之间的损失 loss = criterion(y_hat, y) # 将损失存储到列表中 loss_SGD.append(loss.item()) # 每次迭代后清零梯度 optimizer.zero_grad() # 反向传播以计算损失相对于可学习参数的梯度 loss.backward() # 每次迭代后更新参数 optimizer.step() model = torch.nn.Linear(1, 1) loss_Adam = [] for i in range(n_iter): for x, y in trainloader: # 正向传播中进行预测 y_hat = model(x) # 计算原始数据点和预测数据点之间的损失 loss = criterion(y_hat, y) # 将损失存储到列表中 loss_Adam.append(loss.item()) # 每次迭代后清零梯度 optimizer.zero_grad() # 反向传播以计算损失相对于可学习参数的梯度 loss.backward() # 每次迭代后更新参数 optimizer.step() plt.plot(loss_SGD,label = "随机梯度下降") plt.plot(loss_Adam,label = "Adam 优化器") plt.xlabel('epoch') plt.ylabel('成本/总损失') plt.legend() plt.show() |
总结
在本教程中,您使用 PyTorch 的一些内置包实现了优化算法。特别是,您学习了
- 如何使用 PyTorch 中的一些包来实现优化器。
- 如何从 PyTorch 的
nn
包中导入线性类和损失函数。 - 如何使用 PyTorch 的
optim
包实现随机梯度下降和 Adam(最常用的优化器)。 - 如何自定义模型的权重和偏差。
代码中有个错误——只在两个循环中使用了 1 个优化器 (Adam)。
在完整列表中没有这一行
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
因此,最终的图表——看起来不像上面的图片