本文介绍了如何使用 PyTorch 构建“基于公里数和速度对自行车保养周期预测”的模型,并运用网格搜索方法进行超参数调优。通过实际代码示例,阐述了数据准备、模型定义、训练过程以及超参数搜索的具体实现,同时展示了如何可视化训练损失和验证损失曲线来理解和掌握相关技术。
一、引言
在深度学习领域,构建一个准确且高效的模型不仅依赖于合适的算法和架构,还需要对模型的超参数进行精细调优。超参数是在训练过程之前需要手动设置的参数,如学习率、训练轮数等,它们的选择直接影响模型的性能。本文将使用 PyTorch 库构建一个简单的线性回归模型,并通过网格搜索方法寻找最优的超参数组合。
二、环境准备
为了运行本文中的代码,你需要安装以下 Python 库:
-
torch:用于构建和训练深度学习模型。 -
numpy:用于数据处理和数值计算。 -
matplotlib:用于可视化训练过程中的损失曲线。
你可以使用以下命令进行安装:
pip install torch numpy matplotlib
三、代码实现
3.1 数据准备
首先,我们需要准备训练数据和验证数据。在这个例子中,我们使用 numpy 生成一些示例数据,并将其转换为 torch.Tensor 类型。然后,将数据划分为训练集和验证集,并使用 DataLoader 进行批量加载。
import numpy as np
import torch
from torch.utils.data import DataLoader, TensorDataset
def prepare_data():
"""
准备数据,包括生成数据、转换为 Tensor 类型和划分训练集、验证集
:return: 训练集和验证集的数据加载器
"""
X = np.array(
[[25.0, 20.0], [24.8, 20.3], [25.5, 20.0], [23.0, 20.8], [28.5, 20], [23.0, 23.8], [25.0, 21.0], [24.8, 21.3],
[25.5, 21.0], [23.0, 21.8], [28.5, 21.0], [23.0, 24.8], [25.5, 21.0], [23.0, 21.8], [28.5, 21.0], [23.0, 24.8]])
y = np.array([12.5, 11.8, 11.8, 16.0, 12.8, 17.0, 12.5, 11.8, 11.8, 16.0, 12.8, 17.2, 11.8, 16.0, 12.8, 17.1])
X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32)
train_size = int(0.8 * len(X))
X_train, X_val = X[:train_size], X[train_size:]
y_train, y_val = y[:train_size], y[train_size:]
train_dataset = TensorDataset(X_train, y_train)
val_dataset = TensorDataset(X_val, y_val)
train_loader = DataLoader(train_dataset, batch_size=4, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=4, shuffle=False)
return train_loader, val_loader
3.2 模型定义
接下来,我们定义一个简单的线性回归模型 SimpleRegressor,它包含一个线性层。
import torch.nn as nn
class SimpleRegressor(nn.Module):
"""
简单的线性回归模型
"""
def __init__(self, input_size, output_size):
super(SimpleRegressor, self).__init__()
self.fc = nn.Linear(input_size, output_size)
def forward(self, x):
return self.fc(x)
3.3 训练和评估函数
定义一个 train_model 函数,用于训练模型并记录训练损失和验证损失。
import torch.optim as optim
def train_model(model, train_loader, val_loader, lr, epochs):
"""
训练模型并记录训练损失和验证损失
:param model: 模型实例
:param train_loader: 训练集数据加载器
:param val_loader: 验证集数据加载器
:param lr: 学习率
:param epochs: 训练轮数
:return: 训练损失列表和验证损失列表
"""
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=lr)
train_losses = []
val_losses = []
for epoch in range(epochs):
model.train()
train_loss = 0
for inputs, labels in train_loader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs.squeeze(), labels)
loss.backward()
optimizer.step()
train_loss += loss.item()
train_loss /= len(train_loader)
train_losses.append(train_loss)
model.eval()
val_loss = 0
with torch.no_grad():
for inputs, labels in val_loader:
outputs = model(inputs)
loss = criterion(outputs.squeeze(), labels)
val_loss += loss.item()
val_loss /= len(val_loader)
val_losses.append(val_loss)
print(f'Epoch {epoch + 1}/{epochs}, Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f}')
return train_losses, val_losses
3.4 超参数调优
使用网格搜索方法进行超参数调优,尝试不同的学习率和训练轮数组合,并选择验证损失最小的组合作为最优超参数。
import itertools
import matplotlib.pyplot as plt
def hyperparameter_tuning(train_loader, val_loader, learning_rates, epochs_list):
"""
超参数调优,使用网格搜索方法
:param train_loader: 训练集数据加载器
:param val_loader: 验证集数据加载器
:param learning_rates: 学习率列表
:param epochs_list: 训练轮数列表
:return: 最佳学习率、最佳训练轮数和最佳验证损失
"""
best_val_loss = float('inf')
best_lr = None
best_epochs = None
param_combinations = list(itertools.product(learning_rates, epochs_list))
fig, axes = plt.subplots(len(learning_rates), len(epochs_list), figsize=(15, 10))
for i, (lr, epochs) in enumerate(param_combinations):
row = i // len(epochs_list)
col = i % len(epochs_list)
print(f'\nTraining with lr={lr}, epochs={epochs}')
model = SimpleRegressor(2, 1)
train_losses, val_losses = train_model(model, train_loader, val_loader, lr, epochs)
final_val_loss = val_losses[-1]
if final_val_loss < best_val_loss:
best_val_loss = final_val_loss
best_lr = lr
best_epochs = epochs
print(f"final_val_loss:{final_val_loss},best_val_loss:{best_val_loss}")
axes[row, col].plot(train_losses, label='Train Loss')
axes[row, col].plot(val_losses, label='Validation Loss')
axes[row, col].set_title(f'lr={lr}, epochs={epochs}')
axes[row, col].set_xlabel('Epoch')
axes[row, col].set_ylabel('Loss')
axes[row, col].legend()
plt.tight_layout()
plt.savefig('loss_curves.png')
return best_lr, best_epochs, best_val_loss
3.5 主程序
在主程序中,调用上述函数完成数据准备、超参数调优,并输出最佳超参数和对应的验证损失。
if __name__ == "__main__":
train_loader, val_loader = prepare_data()
learning_rates = [0.001, 0.005, 0.01, 0.1]
epochs_list = [10, 20, 30]
best_lr, best_epochs, best_val_loss = hyperparameter_tuning(train_loader, val_loader, learning_rates, epochs_list)
print(f'\nBest hyperparameters: lr={best_lr}, epochs={best_epochs}, Best validation loss: {best_val_loss:.4f}')
四、结果分析
运行上述代码后,会生成一个 loss_curves.png 文件,其中包含了不同超参数组合下的训练损失曲线和验证损失曲线。通过观察这些曲线,我们可以直观地了解不同超参数对模型性能的影响。同时,代码会输出最佳的学习率、训练轮数和对应的验证损失,帮助我们选择最优的超参数组合。
4.1 输出loss曲线图
loss曲线
4.2 控制台日志输出
Best hyperparameters: lr=0.001, epochs=30, Best validation loss: 2.5039
五、总结
本文通过一个简单的线性回归模型示例,展示了如何使用 PyTorch 进行模型构建、训练和超参数调优。网格搜索是一种简单有效的超参数调优方法,但在实际应用中,可能需要根据具体问题和数据集的特点选择更合适的调优方法,如随机搜索、贝叶斯优化等。希望本文能为读者在深度学习模型的超参数调优方面提供一些帮助。








网友评论