李哥深度学习代码复盘--回归实战(上)

回归实战--新冠预测:用前两天的人数与相关数据预测第三天的人数。

本次复盘包括基础部分和优化部分。

基础部分:代码实现需要pytorch,numpy,matplotlib,time和csv几个库,其中pytorch用于构建,训练和部署深度学习模型(张量,梯度计算等),numpy用于数据预处理,matplotlib用于可视化,time用于记录时间,csv用于读写csv文件以加载或保存数据。

1.数据处理

class CovidDataset(Dataset):
    def __init__(self, file_path, mode="train"):   
    #该函数接收文件路径与模式两个参数,若mode无指定值,则默认以训练模式进行
        with open(file_path, "r") as f:
        #以只读模式打开file_path路径下的文件,并将其赋值给变量f
            ori_data = list(csv.reader(f))
            #从文件对象f中读取csv格式的数据,并将其转换为列表
            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]
            #将csv_data中非5倍数的索引加入索引列表
            data = torch.tensor(csv_data[indices, :-1])
            #选择索引列表指定的所有行,以及每行除最后一列以外的所有列,转换为张量
            self.y = torch.tensor(csv_data[indices, -1])
            #提取最后一列转换为张量(最后一列为结果)
        elif mode == "val":     #验证集
            indices = [i for i in range(len(csv_data)) if i % 5 == 0]
            #将csv_data中为5倍数的索引加入索引列表
            data = torch.tensor(csv_data[indices, :-1])
            self.y = torch.tensor(csv_data[indices, -1])
        else:          #测试集
            indices = [i for i in range(len(csv_data))]   #测试集需放入所有数据
            data = torch.tensor(csv_data[indices])        #将数据转换为张量

        self.data = (data - data.mean(dim=0, keepdim=True))/data.std(dim=0, keepdim=True)
        #标准化处理,mean计算平均值,std计算标准差,dim=0代表沿样本维度,keepdim=True保证输出保持原有维度
        self.mode = mode         #将传入的mode参数存储为实例属性,便于传递运用

    def __getitem__(self, idx):      #该函数接收索引参数
        if self.mode != "test":      #判断是否为测试集,否返回数据和y,是则返回数据
            return self.data[idx].float(), self.y[idx].float()
        else:
            return self.data[idx].float()

    def __len__(self):       #该函数返回样本数量
        return len(self.data)


train_file = "covid.train.csv"        #训练数据集的csv文件路径
test_file = "covid.test.csv"          #测试数据集的csv文件路径

train_dataset = CovidDataset(train_file, "train")    #创建训练数据集实例(使用train_file路径下的文件作为输入,并设置模式为train,以下类似)
val_dataset = CovidDataset(train_file, "val")        #创建验证数据集实例
test_dataset = CovidDataset(test_file, "test")       #创建测试数据集实例

上段代码定义了一个数据集类,并在类中定义了初始化、获取项目和长度三个函数用于处理数据。初始化函数读取csv文件,根据传入的mode参数决定加载相应数据集并进行标准化;获取项目函数在判断是否为测试集后决定返回特征和标签或仅特征;长度函数则返回数据集中样本数量。

2.构建模型

class MyModel(nn.Module):
    def __init__(self, inDim):          #初始化函数,接收输入特征维度
        super(MyModel, self).__init__()     #调用父类nn.Module的构造函数
        #定义模型结构
        self.fc1 = nn.Linear(inDim, 64)     #定义一个全连接层,将输入的特征维度inDim映射到64维输出
        self.relu1 = nn.ReLU()     #定义激活函数层
        self.fc2 = nn.Linear(64, 1)     #定义一个全连接层,将64维输入映射到1维输出

    def forward(self, x):    #模型前向过程
        x = self.fc1(x)     #经过第一个全连接层
        x = self.relu1(x)     #经过激活函数层
        x = self.fc2(x)    #经过第二个全连接层

        if len(x.size()) > 1:     #检查输出是否有额外的维度,有则移除
            return x.squeeze(1)
        return x

device = "cuda" if torch.cuda.is_available() else "cpu"     
#用于检查是否有可用的NVIDIA GPU,并根据结果选择将张量和模型分配到GPU还是CPU上运行

model = MyModel(inDim=93).to(device)     #创建模型实例,并将其分配到相应设备

上段代码定义了一个继承自nn.Module的模型类,该模型由两层全连接层和一层ReLU激活函数构成。同时定义了初始化函数和前向传播函数。

3.训练和验证

batchsize = 16      #定义批次大小
train_loader = DataLoader(train_dataset, batch_size=batchsize, shuffle=True)
#创建用于训练的数据加载器,以下类似
val_loader = DataLoader(val_dataset, batch_size=batchsize, shuffle=True)

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 = 999999999999      #初始化最小验证损失

    for epoch in range(epochs):     #开始训练
        train_loss = 0.0            #初始化训练损失
        val_loss = 0.0              #初始化验证损失
        start_time = time.time()    #记录当前轮次开始时间

        model.train()     #模型调为训练模式
        for batch_x, batch_y in train_loader:      #遍历每个批次
            x, target = batch_x.to(device), batch_y.to(device)    #将数据分配到相应设备上
            pred = model(x)      #前向传播(和model.forward(x)效果一致)
            train_bat_loss = loss(pred, target)    #利用预测值和目标值计算损失
            train_bat_loss.backward()     #反向传播计算梯度
            optimizer.step()     #更新模型
            optimizer.zero_grad()            #梯度清零
            train_loss += train_bat_loss.cpu().item()      #张量转换为数值,每轮损失叠加

        plt_train_loss.append(train_loss / train_loader.__len__())
        #将当前轮次的平均训练损失添加到列表中
        
        model.eval()      #模型调为验证模式
        with torch.no_grad():    #禁用梯度计算,验证或评估时不需要计算梯度
            for batch_x, batch_y in val_loader:
                x, target = batch_x.to(device), batch_y.to(device)
                pred = model(x)
                val_bat_loss = loss(pred, target)
                val_loss += val_bat_loss.cpu().item()

        plt_val_loss.append(val_loss / val_loader.__len__())

        if val_loss < min_val_loss:
        #若验证损失小于最小验证损失,则保存对应模型与路径,并替换原最小验证损失
            torch.save(model, save_path)
            min_val_loss = val_loss

        print("[%03d/%03d] %2.2f sec(s) Trainloss: %.6f valloss: %.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 graph")         #折线图标题
    plt.legend(["train", "val"])    #折线图图例
    plt.show()     #显示绘制的折线图

该函数接收模型,训练数据加载器,验证数据加载器,设备,轮次,优化器,损失计算函数等参数,利用数据对构建的模型进行训练和验证。

4.得出测试结果并保存

test_loader = DataLoader(test_dataset, batch_size=1, shuffle=False)    #测试集不能打乱

def evaluate(sava_path, test_loader, device, rel_path):    
    model = torch.load(sava_path).to(device)    #加载模型并分配到相应设备上
    rel = []    #定义列表,用于存放预测结果
    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", newline='') as f:    
    #以写模式打开rel_path路径下的文件,并将其赋值给f,newline=''用于避免出现新的空行,可视情况进行修改
        csvWriter = csv.writer(f)     #创建csv写入对象
        csvWriter.writerow(["id", "tested_positive"])    #写入首行信息
        for i, value in enumerate(rel):     #遍历rel列表,逐行写入
            csvWriter.writerow([str(i), str(value)])
    print("文件已经保存到"+rel_path)       #或 "文件已经保存到{}".format(rel_path)

该函数接收模型路径,测试数据加载器,设备与结果文件路径四个参数,用于加载已经训练好的模型对测试数据集进行预测,并保存预测结果。

5.相应配置以及调用

config = {
    "lr": 0.001,      #学习率
    "epochs": 20,       #轮次数
    "momentum": 0.9,    #动量
    "save_path": "covidpre/best_model.pth",   #模型保存路径
    "rel_path": "pred.csv"     #预测结果保存路径
}

loss = nn.MSELoss()     #均方误差损失函数

optimizer = optim.SGD(model.parameters(), lr=config["lr"], momentum=config["momentum"])
#优化器,optim.SGD是pytorch中实现随机梯度下降优化算法的类

train_val(model, train_loader, val_loader, device, config["epochs"], optimizer, loss, config["save_path"])       #调用训练验证函数

evaluate(config["save_path"], test_loader, device, config["rel_path"])   #调用预测函数

以上部分为一个完整的模型训练预测过程,其所得结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值