【深度学习笔记】回归模型-新冠人数预测
·
一个最简单的神经网络通常包括4部分
1.data:一般输入是文件地址,或者数据内容,输出是一个存储了数据x,y的数据结构,torch中一般用dataloader来装载
2.model:定义自己的模型,输入x,输出预测值
3.hyperpara:除模型外的超参,包括学习率,优化器,损失函数等
4.训练流程
训练集,测试集,验证集
将训练集拆分成训练集和验证机,训练集中进行训练,验证集中不进行训练,这样可以对自己的模型进行验证,拆分过程要随机均布
训练流程=训练+验证
batchsize
不能一次取全部,也不能只取一个
要分批来取
一个轮次=所有数据都看一遍 1epoch=see all the batches once
sgd:随机梯度下降
随机:随机取一批数据
梯度下降:通过梯度下降来更新模型
项目:新冠疫情感染人数预测
源代码
独热编码:一种分类形式
数据是用dataset数据集这个类表示,包含三个函数:init,getitem,len
init 初始化:通过文件路径来读取数据x,y
getitem:给定一个下标,返回一个数据
len:求数据长度
模型包含两个函数:init,forward
init:初始化一个函数模型
forward:让数据通过函数模型
超参:如batch_size
import torch
import matplotlib.pyplot as plt #画图
import numpy as np #矩阵相关
import csv #处理csv文件
import pandas #也是csv文件,更高级
import torch.nn as nn
from torch import optim
import time
from torch.utils.data import Dataset,DataLoader #继承官方的类
class CovidDataset(Dataset):
#init 初始化:通过文件路径来读取数据x,y
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) #不要第一行和第一列,将字符型数据转换成浮点型
#逢5取1,不推荐
if mode=="train":
indices=[i for i in range(len(csv_data)) if i%5!=0] #2700行进行循环,对5取余筛选进新列表
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))]
self.X=torch.tensor(csv_data[indices,:93]) #左闭右开,0~92列,共93列,因为csv_data已经去掉了一列
if mode!="test":
self.Y= torch.tensor(csv_data[indices,-1]) #Y取最后一列
#标准化,x减去均值除以方差,消除量纲影响
self.X=(self.X-self.X.mean(dim=0,keepdim=True))/self.X.std(dim=0,keepdim=True) #dim=0表示行,1表示列
self.mode=mode
pass
#给一个下标,返回指定的值
def __getitem__(self, item):
if self.mode=="test":
return self.X[item].float()
else:
return self.X[item].float(),self.Y[item].float()
def __len__(self):
return len(self.X)
train_file=r"C:\Users\86130\Desktop\深度学习\covid\covid.train.csv"
# for x,y in train_set:
# print(x,y)
class myModel(nn.Module):
def __init__(self,inDim):#indim试输入维度
super(myModel,self).__init__()
self.fc1=nn.Linear(inDim,128)
self.relu1=nn.ReLU()
self.fc2=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) #如果维度大于1,就去掉第二个维度
return x
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=99999999999999999
for epoch in range(epochs): #发枪指令,模型训练的开始
model.train()
train_loss=0.0 #浮点形式
for x,y in train_loader:
x,y=x.to(device),y.to(device)
y_pred=model(x)
bat_loss=loss(y_pred,y)
bat_loss.backward()
optimizer.step()
optimizer.zero_grad()
train_loss+=bat_loss.cpu().item()
plt_train_loss.append(train_loss/train_loader.__len__())
model.eval()
start_time=time.time()
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_bat_loss=loss(val_pred_y,val_y)
val_loss+=val_bat_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:%.6f"%\
(epoch,epochs,time.time()-start_time,plt_train_loss[-1],plt_val_loss[-1]))
plt.plot(plt_train_loss)
plt.plot(plt_val_loss)
plt.title("loss")
plt.legend(["train","val"])
plt.show()
def evaluate(model_path,test_loader,rel_path,device):
model=torch.load(model_path).to(device) #加载最好的模型到设备上
rel=[] #记录预测结果
model.eval()
with torch.no_grad():
for x in test_loader:
x=x.to(device)
pred=model(x)
rel.append(pred.cpu().item())
with open(rel_path,"w",newline="") as f:
csv_writer=csv.writer(f)
csv_writer.writerow(["id","tested_positived"])
for i,pred in enumerate(rel): #同时得到第几个和第几个的结果
csv_writer.writerow([str(i),str(pred)])
print("结果保存到了{}".format(rel_path))
batch_size=16
train_set=CovidDataset(train_file,"train")
val_set=CovidDataset(train_file,"val")
test_set=CovidDataset(train_file,"test")
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=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_save/best_model.pth"
rel_path="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)
1. 导入依赖库
1import torch
2import matplotlib.pyplot as plt #画图
3import numpy as np #矩阵相关
4import csv #处理csv文件
5import pandas #也是csv文件,更高级
6import torch.nn as nn
7from torch import optim
8import time
9from torch.utils.data import Dataset,DataLoader #继承官方的类
torch: PyTorch 深度学习框架的核心库。matplotlib.pyplot: 用于绘制训练损失曲线等图表。numpy: 提供强大的多维数组对象和数学运算函数,常用于数据预处理。csv: 用于读写 CSV (逗号分隔值) 格式的文件,这里是数据集的格式。pandas: 一个强大的数据分析库,虽然在这段代码中被导入了但并未使用,通常比原生csv库更方便。torch.nn: 包含神经网络层和损失函数的模块。torch.optim: 包含各种优化算法(如 SGD, Adam)的模块。time: 用于记录单个 epoch 的训练耗时。torch.utils.data.Dataset, DataLoader: PyTorch 提供的工具,用于方便地构建和加载数据集。
2. 自定义数据集 CovidDataset
1class CovidDataset(Dataset):
2 #init 初始化:通过文件路径来读取数据x,y
3 def __init__(self,file_path,mode): #初始化
4 with open(file_path,"r") as f:
5 ori_data=list(csv.reader(f))
6 csv_data=np.array(ori_data)[1:,1:].astype(float) #不要第一行和第一列,将字符型数据转换成浮点型
7 #逢5取1,不推荐
8 if mode=="train":
9 indices=[i for i in range(len(csv_data)) if i%5!=0] #2700行进行循环,对5取余筛选进新列表
10 elif mode=="val":
11 indices = [i for i in range(len(csv_data)) if i % 5 == 0]
12 elif mode=="test":
13 indices = [i for i in range(len(csv_data))]
14 self.X=torch.tensor(csv_data[indices,:93]) #左闭右开,0~92列,共93列,因为csv_data已经去掉了一列
15 if mode!="test":
16 self.Y= torch.tensor(csv_data[indices,-1]) #Y取最后一列
17 #标准化,x减去均值除以方差,消除量纲影响
18 self.X=(self.X-self.X.mean(dim=0,keepdim=True))/self.X.std(dim=0,keepdim=True) #dim=0表示行,1表示列
19 self.mode=mode
20 pass
- 功能: 继承自
torch.utils.data.Dataset,用于封装您的原始数据,使其能被DataLoader有效利用。 __init__函数:with open(file_path,"r") as f: 打开指定路径的 CSV 文件。ori_data=list(csv.reader(f)): 读取所有行并存为列表。csv_data=np.array(ori_data)[1:,1:].astype(float): 转换为 NumPy 数组,并切片去除第一行(通常是标题)和第一列(可能是ID),然后将所有数据转为float类型。- 数据划分: 根据
mode参数 ("train","val","test"),通过i % 5的余数来划分数据。例如,训练集取余数非0的行(占 4/5),验证集取余数为0的行(占 1/5)。这是一种简单的数据划分方法。 self.X=torch.tensor(...): 将处理好的特征数据转换为 PyTorch 张量。if mode!="test": self.Y=...: 只有在非测试模式下才加载标签 Y(最后一列)。self.X=(self.X-...)/...: 标准化 (Normalization)。这是关键的预处理步骤,它将每个特征的分布调整为均值为0,标准差为1,有助于模型更快、更稳定地收敛。self.mode=mode: 保存模式,以便__getitem__方法知道如何返回数据。
1 #给一个下标,返回指定的值
2 def __getitem__(self, item):
3 if self.mode=="test":
4 return self.X[item].float()
5 else:
6 return self.X[item].float(),self.Y[item].float()
7 def __len__(self):
8 return len(self.X)
__getitem__函数: 当我们用索引访问数据集时(如dataset[5]),这个方法会被调用。它根据mode返回一个样本的特征,或者特征和标签的元组。__len__函数: 返回数据集的总长度,DataLoader会用到这个信息。
3. 自定义模型 myModel
1class myModel(nn.Module):
2 def __init__(self,inDim):#indim试输入维度
3 super(myModel,self).__init__()
4 self.fc1=nn.Linear(inDim,128)
5 self.relu1=nn.ReLU()
6 self.fc2=nn.Linear(128,1)
7 def forward(self,x):
8 x=self.fc1(x)
9 x=self.relu1(x)
10 x=self.fc2(x)
11
12 if len(x.size())>1:
13 x=x.squeeze(1) #如果维度大于1,就去掉第二个维度
14 return x
- 功能: 定义了一个简单的两层全连接(线性)神经网络。
__init__函数:super(myModel,self).__init__(): 调用父类nn.Module的构造函数,这是 PyTorch 模型的标准写法。self.fc1=nn.Linear(inDim,128): 定义第一个线性层,将inDim维的输入映射到 128 维。self.relu1=nn.ReLU(): 定义 ReLU 激活函数,增加模型的非线性。self.fc2=nn.Linear(128,1): 定义第二个线性层,将 128 维映射到 1 维输出,用于回归任务。
forward函数: 定义了数据x通过网络的前向传播过程。它依次经过线性层1、ReLU激活、线性层2。最后的squeeze(1)是为了确保输出的形状是[batch_size]而不是[batch_size, 1],方便后续计算损失。
4. 训练与验证函数 train_val
1def train_val(model,train_loader,val_loader,lr,optimizer,device,epochs,save_path):
2 model=model.to(device)
3 plt_train_loss=[]
4 plt_val_loss=[]
5 min_val_loss=99999999999999999
- 功能: 执行模型的训练和验证流程。
- 初始化: 将模型移到指定设备(CPU/GPU),准备存储损失的列表,以及一个记录最小验证损失的变量。
1 for epoch in range(epochs): #发枪指令,模型训练的开始
2 model.train()
3 train_loss=0.0 #浮点形式
4 for x,y in train_loader:
5 x,y=x.to(device),y.to(device)
6 y_pred=model(x)
7 bat_loss=loss(y_pred,y)
8 bat_loss.backward()
9 optimizer.step()
10 optimizer.zero_grad()
11 train_loss+=bat_loss.cpu().item()
12 plt_train_loss.append(train_loss/train_loader.__len__())
- 训练循环:
model.train(): 设置模型为训练模式。for x,y in train_loader: 遍历训练数据加载器,每次获取一个批次的数据。x,y=x.to(device),y.to(device): 将数据移到计算设备。y_pred=model(x): 前向传播,得到预测值。bat_loss=loss(y_pred,y): 计算该批次的损失。bat_loss.backward(): 反向传播,计算梯度。optimizer.step(): 根据梯度更新模型参数。optimizer.zero_grad(): 清零梯度,防止累积。train_loss+=bat_loss.cpu().item(): 累加当前批次的损失值(转换为 Python 数值)。plt_train_loss.append(...): 计算并存储本 epoch 的平均训练损失。
1 model.eval()
2 start_time=time.time()
3 val_loss=0.0
4 with torch.no_grad():
5 for val_x,val_y in val_loader:
6 val_x,val_y=val_x.to(device),val_y.to(device)
7 val_pred_y=model(val_x)
8 val_bat_loss=loss(val_pred_y,val_y)
9 val_loss+=val_bat_loss.cpu().item() # <-- 关键修复点
10 plt_val_loss.append(val_loss/val_loader.__len__())
- 验证循环:
model.eval(): 设置模型为评估模式。with torch.no_grad(): 关闭梯度计算,节约内存。for val_x,val_y in val_loader: 遍历验证数据加载器。- 关键:
val_loss+=val_bat_loss.cpu().item(),这里将张量转换为 Python 数值,确保val_loss是一个数字,这是代码能运行的关键。 plt_val_loss.append(...): 计算并存储本 epoch 的平均验证损失。
1 #保存
2 if val_loss<min_val_loss:
3 min_val_loss=val_loss
4 torch.save(model,save_path)
5 print("[%03d/%03d] %2.2f sec(s) train_loss:%.6f val_loss:%.6f"%\
6 (epoch,epochs,time.time()-start_time,plt_train_loss[-1],plt_val_loss[-1]))
- 模型保存: 如果当前 epoch 的验证损失是历史最低,就保存模型。
- 日志打印: 输出训练进度和损失信息。
1 plt.plot(plt_train_loss)
2 plt.plot(plt_val_loss)
3 plt.title("loss")
4 plt.legend(["train","val"])
5 plt.show()
- 绘图: 训练结束后,绘制训练和验证损失曲线。
5. 评估与预测函数 evaluate
1def evaluate(model_path,test_loader,rel_path,device):
2 model=torch.load(model_path).to(device) #加载最好的模型到设备上
3 rel=[] #记录预测结果
4 model.eval()
5 with torch.no_grad():
6 for x in test_loader:
7 x=x.to(device)
8 pred=model(x)
9 rel.append(pred.cpu().item())
- 功能: 加载训练好的模型,对测试集进行预测。
torch.load(model_path): 从文件加载已保存的模型。for x in test_loader: 遍历测试数据(无标签)。pred=model(x): 得到预测结果。rel.append(pred.cpu().item()): 将预测值转换为 Python 数值并存储。
1 with open(rel_path,"w",newline="") as f:
2 csv_writer=csv.writer(f)
3 csv_writer.writerow(["id","tested_positived"])
4 for i,pred in enumerate(rel): #同时得到第几个和第几个的结果
5 csv_writer.writerow([str(i),str(pred)])
6 print("结果保存到了{}".format(rel_path))
- 写入CSV: 将预测结果按要求的格式写入 CSV 文件,用于提交。
6. 主程序入口
1# ... (创建数据集、加载器、模型、优化器等) ...
2train_val(model,train_loader,val_loader,lr,optimizer,device,epochs,save_path)
3evaluate(save_path,test_loader,rel_path,device)
- 首先,初始化所有必要的组件。
- 然后,调用
train_val函数进行模型训练和验证。 - 最后,调用
evaluate函数加载最佳模型,对测试集进行预测并生成提交文件。
一些提升模型效率的手段
1.正则化:loss=loss+w*w
w是模型参数
作用,让模型曲线更加平滑,防止过拟合
让w更小
2.取出相关系数比较大的列
3.pca主成分分析
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)