DAY5 回归代码详解
model:待训练的模型、train_loader:训练数据加载器、val_loader:验证数据加载器、lr:学习率、optimizer:优化器、device:运行设备(CPU或GPU)、epochs:训练轮次、save_path:模型存储路径。清除当前轴,绘制训练和验证损失曲线,设置标题和图例,暂停一小段时间以更新图形。这个类的作用是数据加载与处理,数据加载csv.reader(f),csv.
Track:正则化(防止过拟合)
现在是代码详解:
class CovidDataset(Dataset):
def __init__(self, file_path, mode):
with open(file_path,'r') as f:
ori_data = list(csv.reader(f))
csv_data = np.array(ori_data)[1:, 1:].astype(float)
if mode == 'train':
indices = [i for i in range(len(csv_data)) if i % 5 != 0]
elif mode == 'val':
indices = [i for i in range(len(csv_data)) if i % 5 == 0]
elif mode == 'test':
indices = [i for i in range(len(csv_data))]
x = torch.tensor(csv_data[indices, :93])
if mode != "test":
self.y = torch.tensor(csv_data[indices, -1])
self.x = (x - x.mean(dim=0,keepdim=True)) / x.std(dim=0,keepdim=True)
self.mode = mode
pass
def __getitem__(self,item):
if self.mode == 'test':
return self.x[item].float()
return self.x[item].float(),self.y[item].float()
def __len__(self):
return len(self.x)
这个类的作用是数据加载与处理,数据加载csv.reader(f),csv.data保存的数据是清洗过的,因为零行零列是没有价值的,同时进行数据转换,将字符串通过astype转为浮点数。
数据集的划分:一般可以将训练集分为训练集和验证集两部分,这里是4:1的比例(通过indices存储),注意数据要是随机的,也就是shuffle为True。特征提取和标签提取也很简单,该数据集中前93列是特征,最后一列是标签。
X的计算公式也很简单:(x - 均值) / 标准差,构造出一个正态分布。
getitem函数的作用:区别训练/验证模式与测试模式
len函数的作用:返回数据集的大小
class myModel(torch.nn.Module):
def __init__(self, inDim):
super(myModel, self).__init__()
self.fc1 = torch.nn.Linear(inDim, 128)
self.relu1 = torch.nn.ReLU()
self.fc2 = torch.nn.Linear(128, 1)
def forward(self, x):
x = self.fc1(x)
x = self.relu1(x)
x = self.fc2(x)
if len(x.size()) > 1:
x = x.squeeze(1)
return x
自主定义的简易神经网络模型。第一步要调用父类初始化,和JAVA的继承很像。第二步定义网络层,这是一个全连接网络,输入维度为indim,输出维度为128,激活函数采用的是relu。前向传播方法就是如此:输入通过、激活函数、输入再通过、激活函数……维度调整、返回输出。
def train_val(model, train_loader, val_loader, lr, optimizer, device, epochs, save_path):
model = model.to(device)
plt_train_loss = []
plt_val_loss = []
min_val_loss = np.inf
# 创建保存模型的目录
save_dir = os.path.dirname(save_path)
if save_dir and not os.path.exists(save_dir):
os.makedirs(save_dir)
# 初始化绘图
plt.ion() # 开启交互模式
fig, ax = plt.subplots()
for epoch in range(epochs):
model.train()
start_time = time.time()
train_loss = 0.0
for x, y in train_loader:
x, y = x.to(device), y.to(device)
y_pred = model(x)
batch_loss = loss(y_pred, y)
batch_loss.backward()
optimizer.step()
optimizer.zero_grad()
train_loss += batch_loss.cpu().item()
plt_train_loss.append(train_loss/train_loader.__len__())
model.eval()
val_loss = 0.0
with torch.no_grad():
for val_x, val_y in val_loader:
val_x, val_y = val_x.to(device), val_y.to(device)
val_pred_y = model(val_x)
val_batch_loss = loss(val_pred_y, val_y)
val_loss += val_batch_loss.cpu().item()
plt_val_loss.append(val_loss / val_loader.__len__())
if val_loss < min_val_loss:
min_val_loss = val_loss
torch.save(model, save_path)
print("[%03d/%03d] %2.2f sec(s) train_loss: %6f val_loss: %06f" %
(epoch, epochs, time.time()- start_time, plt_train_loss[-1], plt_val_loss[-1]))
# 更新绘图
ax.clear() # 清除当前轴
ax.plot(plt_train_loss)
ax.plot(plt_val_loss)
ax.set_title("loss")
ax.legend(["train", "val"])
plt.pause(0.1) # 暂停一小段时间以更新图形
plt.ioff() # 关闭交互模式
plt.show() # 显示最终图形
这是训练与可视化模块。
先介绍运用的参数:model、data、hyperparam※
model:待训练的模型、train_loader:训练数据加载器、val_loader:验证数据加载器、lr:学习率、optimizer:优化器、device:运行设备(CPU或GPU)、epochs:训练轮次、save_path:模型存储路径
第一步:初始化操作。model = model.to(device)将模型迁移到指定设备,能用GPU就用,不能用就CPU。损失记录:plt_train_loss和plt_val_loss记录了训练和验证的损失。min_val_loss用于记录最小验证损失。
第二步:开始训练:model.train(),并且记录训练时间start_time=time.time()
- 遍历训练数据加载器
- 将数据移至指定设备
- 前向传播:pred_y = model(x)
- 计算损失:batch_loss = loss(pred_y, y)
- 反向传播:batch_loss.backward()
- 更新参数:optimizer.step()
- 清零梯度:optimizer.zero_grad()
- 累加损失:train_loss += batch_loss.cpu().item()
- 记录损失:plt_train_loss.append(train_loss/train_loader.__len__())
第三步:开始验证。设置评估模式model.eval(),关闭梯度计算with torch.no_grad()并开始。
- 遍历验证数据加载器
- 将数据移至指定设备
- 前向传播:val_y_pred = model(val_x)
- 计算损失:val_batch_loss = loss(val_y_pred, val_y)
- 累加损失:val_loss += val_batch_loss.cpu().item()
- 记录验证损失:plt_val_loss.append(val_loss / val_loader.__len__())
如果当前验证损失小于最小验证损失,则保存模型,也就是目前我们得到的最优模型。清除当前轴,绘制训练和验证损失曲线,设置标题和图例,暂停一小段时间以更新图形。关闭 Matplotlib 交互模式,显示最终图形。
train_file = r"covid.train.csv"
test_file = r"covid.test.csv"
train_set = CovidDataset(train_file, 'train')
val_set = CovidDataset(train_file, 'val')
test_set = CovidDataset(test_file, 'test')
batch_size = 16
train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(val_set, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_set, batch_size=1, shuffle=False)
loss = torch.nn.MSELoss()
epochs = 20
lr = 0.001
device = "cuda" if torch.cuda.is_available() else "cpu"
print(device)
data_dim = 93
model = myModel(data_dim).to(device)
save_path = "model_save1/bestmodel.pth"
rel_path = "model_save1/pred.csv"
optimizer = optim.SGD(params=model.parameters(), lr=lr, momentum=0.9)
train_val(model, train_loader, val_loader, lr, optimizer, device, epochs, save_path)
evaluate(save_path, test_loader, rel_path, device)
这是主程序,也就是所有超参的体现和函数调用。
最值得讲的部分:
优化器初始化:optimizer = optim.SGD(params=model.parameters(), lr=lr, momentum=0.9
使用随机梯度下降(SGD)优化器,学习率为 lr,动量为 0.9。
动量:
加速收敛 :通过累积梯度方向,加快模型训练速度
避免局部最小值 :利用惯性帮助参数冲过小的能量壁垒
减少震荡 :平滑参数更新过程,提高训练稳定性
更多推荐


所有评论(0)