微信登录

超参数调优 - 手动调优 - 调整学习率等

PyTorch 超参数调优 - 手动调优 - 调整学习率等

在深度学习的世界里,训练一个高效且准确的模型并非易事。除了精心设计模型架构外,超参数的选择也起着至关重要的作用。超参数是在训练过程开始之前就需要设置的参数,它们不能通过模型从数据中学习得到,而是需要人为地进行调整。在众多超参数中,学习率、批量大小和迭代次数等是最为关键的几个。本文将聚焦于 PyTorch 中这些超参数的手动调优,尤其是学习率的调整,为大家提供一些实用的技巧和方法。

超参数简介

在深入探讨调优方法之前,我们先来了解一下几个重要的超参数:
| 超参数 | 含义 | 影响 |
| —- | —- | —- |
| 学习率(Learning Rate) | 控制模型参数更新的步长,即每次迭代时参数更新的幅度 | 过大可能导致模型无法收敛,过小则会使训练速度过慢 |
| 批量大小(Batch Size) | 每次迭代时用于计算梯度的样本数量 | 较大的批量可以使梯度估计更准确,但可能会增加内存需求;较小的批量可以增加随机性,有助于跳出局部最优解 |
| 迭代次数(Epoch) | 整个数据集被模型训练的次数 | 次数过少可能导致模型欠拟合,次数过多则可能导致过拟合 |

手动调优学习率

固定学习率

固定学习率是最简单的设置方法,即在整个训练过程中学习率保持不变。以下是一个使用固定学习率的 PyTorch 示例代码:

  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. # 定义一个简单的线性模型
  5. model = nn.Linear(10, 1)
  6. # 定义损失函数
  7. criterion = nn.MSELoss()
  8. # 定义优化器,设置固定学习率为 0.01
  9. optimizer = optim.SGD(model.parameters(), lr=0.01)
  10. # 模拟训练数据
  11. inputs = torch.randn(100, 10)
  12. labels = torch.randn(100, 1)
  13. # 训练模型
  14. for epoch in range(100):
  15. optimizer.zero_grad()
  16. outputs = model(inputs)
  17. loss = criterion(outputs, labels)
  18. loss.backward()
  19. optimizer.step()
  20. print(f'Epoch {epoch+1}, Loss: {loss.item()}')

在这个例子中,我们使用随机梯度下降(SGD)优化器,将学习率固定为 0.01。固定学习率的优点是简单易懂,但缺点是在训练过程中无法根据模型的表现进行调整,可能会导致训练效果不佳。

学习率衰减

学习率衰减是一种常见的调优方法,它在训练初期使用较大的学习率,以便快速收敛到最优解附近;在训练后期,逐渐减小学习率,以避免错过最优解。PyTorch 提供了多种学习率衰减策略,如 StepLRExponentialLR 等。以下是使用 StepLR 的示例代码:

  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. from torch.optim.lr_scheduler import StepLR
  5. # 定义一个简单的线性模型
  6. model = nn.Linear(10, 1)
  7. # 定义损失函数
  8. criterion = nn.MSELoss()
  9. # 定义优化器,设置初始学习率为 0.1
  10. optimizer = optim.SGD(model.parameters(), lr=0.1)
  11. # 定义学习率调度器,每 10 个 epoch 学习率乘以 0.1
  12. scheduler = StepLR(optimizer, step_size=10, gamma=0.1)
  13. # 模拟训练数据
  14. inputs = torch.randn(100, 10)
  15. labels = torch.randn(100, 1)
  16. # 训练模型
  17. for epoch in range(100):
  18. optimizer.zero_grad()
  19. outputs = model(inputs)
  20. loss = criterion(outputs, labels)
  21. loss.backward()
  22. optimizer.step()
  23. # 更新学习率
  24. scheduler.step()
  25. print(f'Epoch {epoch+1}, Loss: {loss.item()}, LR: {optimizer.param_groups[0]["lr"]}')

在这个例子中,我们使用 StepLR 调度器,每 10 个 epoch 将学习率乘以 0.1。这样可以在训练过程中逐渐减小学习率,提高模型的收敛效果。

手动调整学习率

除了使用学习率调度器,我们还可以手动调整学习率。以下是一个手动调整学习率的示例代码:

  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. # 定义一个简单的线性模型
  5. model = nn.Linear(10, 1)
  6. # 定义损失函数
  7. criterion = nn.MSELoss()
  8. # 定义优化器,设置初始学习率为 0.1
  9. optimizer = optim.SGD(model.parameters(), lr=0.1)
  10. # 模拟训练数据
  11. inputs = torch.randn(100, 10)
  12. labels = torch.randn(100, 1)
  13. # 训练模型
  14. for epoch in range(100):
  15. optimizer.zero_grad()
  16. outputs = model(inputs)
  17. loss = criterion(outputs, labels)
  18. loss.backward()
  19. optimizer.step()
  20. # 手动调整学习率
  21. if (epoch + 1) % 20 == 0:
  22. for param_group in optimizer.param_groups:
  23. param_group['lr'] *= 0.1
  24. print(f'Epoch {epoch+1}, Loss: {loss.item()}, LR: {optimizer.param_groups[0]["lr"]}')

在这个例子中,我们每隔 20 个 epoch 将学习率乘以 0.1。手动调整学习率可以根据模型的实际表现进行灵活调整,但需要更多的人工干预。

批量大小和迭代次数的调整

除了学习率,批量大小和迭代次数也会对模型的训练效果产生重要影响。一般来说,较大的批量大小可以使梯度估计更准确,但可能会增加内存需求;较小的批量大小可以增加随机性,有助于跳出局部最优解。迭代次数则需要根据数据集的大小和模型的复杂度进行调整,避免过拟合和欠拟合。

以下是一个调整批量大小和迭代次数的示例代码:

  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. from torch.utils.data import DataLoader, TensorDataset
  5. # 定义一个简单的线性模型
  6. model = nn.Linear(10, 1)
  7. # 定义损失函数
  8. criterion = nn.MSELoss()
  9. # 定义优化器,设置学习率为 0.01
  10. optimizer = optim.SGD(model.parameters(), lr=0.01)
  11. # 模拟训练数据
  12. inputs = torch.randn(100, 10)
  13. labels = torch.randn(100, 1)
  14. # 创建数据集和数据加载器
  15. dataset = TensorDataset(inputs, labels)
  16. # 设置批量大小为 10
  17. dataloader = DataLoader(dataset, batch_size=10, shuffle=True)
  18. # 设置迭代次数为 20
  19. num_epochs = 20
  20. # 训练模型
  21. for epoch in range(num_epochs):
  22. running_loss = 0.0
  23. for i, (inputs_batch, labels_batch) in enumerate(dataloader):
  24. optimizer.zero_grad()
  25. outputs = model(inputs_batch)
  26. loss = criterion(outputs, labels_batch)
  27. loss.backward()
  28. optimizer.step()
  29. running_loss += loss.item()
  30. print(f'Epoch {epoch+1}, Loss: {running_loss / len(dataloader)}')

在这个例子中,我们将批量大小设置为 10,迭代次数设置为 20。通过调整批量大小和迭代次数,可以找到最优的训练参数。

总结

手动调优超参数是一个需要耐心和经验的过程。在调整学习率时,可以尝试固定学习率、学习率衰减和手动调整等方法;在调整批量大小和迭代次数时,需要根据数据集的大小和模型的复杂度进行权衡。通过不断地尝试和调整,我们可以找到最优的超参数组合,提高模型的训练效果和性能。希望本文的内容对大家在 PyTorch 超参数调优方面有所帮助。