新冠人数预测回归任务项目学习

一、引入一些必要库

import pylab as plt
import torch
from torch.utils.data import DataLoader, Dataset
import csv
import pandas as pd
import numpy as np
import torch.nn as nn
import torch.optim as optim
import time
import os

以上的库是这个项目需要用到的库。

二、生成数据集

class CovidDataset(Dataset):

    def __init__(self, file_path, mode):
        with open(file_path, "r") as f:
            csv_data = list(csv.reader(f))
            data = np.array(csv_data[1:])

            if mode == "train" :
                indices = [i for i in range(len(data)) if i%5 != 0]
            elif mode == "val" :
                indices = [i for i in range(len(data)) if i%5 == 0]

            if mode == "test":
                x = data[:,1:].astype(float)
            else:
                x = data[indices, 1:-1].astype(float)
                y = data[indices, -1].astype(float)
                self.y = torch.tensor(y)
            x = torch.tensor(x)
            self.x = x-x.mean(dim=0,keepdim = True)/x.std(dim=0,keepdim = True)
            self.mode = mode

    def __getitem__(self, index):
        if self.mode == "test":
            return self.x[index].float()
        else:
            return self.x[index].float(),self.y[index].float()

    def __len__(self):
        return len(self.x)

        

这里可以看到,CovidDataset的构建函数首先将数据文件以读的方式打开,以csv_data的形式保存,之后调用np.array将读出的list形式的数据以矩阵的形式存放。

然后根据模型的模式进行取数据,这里取5的倍数做为验证集,其余部分作为训练集,随即将data的数据进行切片,调用astype将数组转为float类型后,调用tensor将所需数据转为张量。

对x进行标准化后,储存mode方便之后调用。

之后的两个类非常简单,__getitem__返回给定的index下标下x对应下标位置的float值,__len__返回x的长度。

三、设立模型

class myModel(nn.Module):


    def __init__(self,indim):
        super(myModel,self).__init__()
        self.fc1 = nn.Linear(indim,256)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(256,16)
        self.fc3 = nn.Linear(16,1)

    def forward(self,x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        x = self.relu(x)
        x = self.fc3(x)

        if len(x.size())>1:
            x = x.squeeze(dim=1)

        return x

myModel就是此次训练过程中所使用的模型,继承自nn.Module,我将整个模型分为了三层,每层之间使用nn.Linear全连接,并使用ReLU作为激活函数。当模型的维数大于1时,为了与方便与y运算,所以使用squeeze将x的维数降为一维。之后若向模型中传入参数,将会直接进入forward执行。

四、调整参数

config = {
    "lr" : 0.0001,
    "momentum" : 0.9,
    "epochs" : 1000,
    "save_path" : "model/model.pth",
    "rel_path" : "model/rel.csv",
    "dim" : 93
}
#所要用到的参数,放入了config

train_file = "./covid.train.csv"
test_file = "./covid.test.csv"
#训练集和测试集来自不同的文件

# device = "cuda" if torch.cuda.is_available() else "cpu"
device = "cpu"
#MX250显卡性能过差,实际运行速度不如cpu,因此将模型改为在cpu上运行

train_data = CovidDataset(train_file, "train")
val_data = CovidDataset(train_file, "val")
test_data = CovidDataset(test_file, "test")
#通过刚才的函数来创建不同的数据集

train_loader = DataLoader(train_data, batch_size=16,shuffle=True)
val_loader = DataLoader(val_data, batch_size=16,shuffle=True)
test_loader = DataLoader(test_data, batch_size=1,shuffle=False)
#以数据集为数据集,一批次为16,来创建loader
#test这里一批次为1,且不能打乱顺序

model = myModel(config["dim"])

loss = mseloss
#loss用自己创建的mseloss函数

optimizer = optim.SGD(model.parameters(),lr=config["lr"],momentum=config["momentum"])
#调用优化器,学习率和步长

if not os.path.exists(os.path.dirname(config["save_path"])):
    os.makedirs(os.path.dirname(config["save_path"]))
#若存储文件位置不存在则创建

五、进行训练

def train_val(model, train_loader, val_loader, device, epochs, optimizer, loss, save_path):

    model = model.to(device)

    plt_train_loss = []
    plt_val_loss = []
    min_val_loss = 1e15

    for epoch in range(epochs):
        start_time = time.time()
        model.train()
        train_loss = 0.0
        val_loss = 0.0

        for batch_x, batch_y in train_loader:
            x, target = batch_x.to(device), batch_y.to(device)
            pred = model(x)

            train_bat_loss = loss(pred,target,model)
            train_bat_loss.backward()
            optimizer.step()
            optimizer.zero_grad()
            train_loss += train_bat_loss.detach().cpu().item()

        plt_train_loss.append(train_loss/len(train_loader.dataset))

        model.eval()

        with torch.no_grad():
            for batch_x, batch_y in val_loader:
                val_x, val_target = batch_x.to(device), batch_y.to(device)
                val_pred = model(val_x)
                val_bat_loss = loss(val_pred,val_target,model)
                val_loss += val_bat_loss.cpu().item()
        plt_val_loss.append(val_loss/len(val_loader.dataset))
        if val_loss < min_val_loss:
            torch.save(model, save_path)
            min_val_loss = val_loss

这就是整个模型的训练过程,需要传入模型、训练数据、验证数据、训练设备、轮数、优化器和存储位置。

第一步是将model放入所设的装置上,这里因为显卡性能原因选择cpu。

plt_train_loss = []
plt_val_loss = []
min_val_loss = 1e15

用两个列表分别存放验证集和训练集的loss值,并给min_val_loss赋一个足够大的整数,以此来记录更小值。

        start_time = time.time()
        model.train()
        train_loss = 0.0
        val_loss = 0.0

每个epoch的开始记录开始时间,以计算模型每个轮次的运行时间。

随后将模型置为train模型并设置两个浮点型变量记录loss值。

        for batch_x, batch_y in train_loader:
            x, target = batch_x.to(device), batch_y.to(device)
            pred = model(x)

            train_bat_loss = loss(pred,target,model)
            train_bat_loss.backward()
            optimizer.step()
            optimizer.zero_grad()
            train_loss += train_bat_loss.detach().cpu().item()

每次取一组数据来进行操作,并用pred来记录模型通过前向传播的预测值。

train_bat_loss记算loss后,进行反向传播以此进行梯度的计算。

调用optimizer.step()通过之前设置的步长和学习率对模型进行优化,然后调用zero_grad()将模型的梯度置零,防止梯度累积。

之后,train_loss记录每个批次下的loss的累加,每个批次的数据首先分离出loss后,置于cpu,再调用item将张量转为标量再加给train_loss。

        with torch.no_grad():
            for batch_x, batch_y in val_loader:
                val_x, val_target = batch_x.to(device), batch_y.to(device)
                val_pred = model(val_x)
                val_bat_loss = loss(val_pred,val_target,model)
                val_loss += val_bat_loss.detach().cpu().item()

先用model.eval()设置模型为评估模式,之后和训练模式类似,因为验证集不需要来进行反向传播,因此不需要计算梯度和优化代码。

七、储存结果

def evaluate(save_path ,device, test_loader, rel_path):
    model = torch.load(save_path).to(device)
    rel = []
    model.eval()

    with torch.no_grad():
        for x in test_loader:
            pred = model(x.to(device))
            rel.append(pred.cpu().item())

    print(rel)

    with open(rel_path,"w") as f:
        csv_writer = csv.writer(f)
        csv_writer.writerow(["id","tested_positive"])
        for i in range(len(rel)):
            csv_writer.writerow([str(i),str(rel[i])])
        print("file has been saved in "+rel_path)

将预测值以csv的格式写入设定好的路径中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值