一个最简单的神经网络通常包括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主成分分析

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐