李宏毅深度学习作业一_2020_pytorch实现

一、作业一说明:

  • 目的

根据前9个小时的数据,预测出第十个小时 PM2.5 的数值

  • 方法
    线性回归

  • 数据:

使用丰原站的观测记录,分成 train.csv 跟 test.csv,train.csv是丰原站每个月的前 20 天所有数据。test.csv 则是从丰原站剩下的资料中取样出来。
train.csv: 每个月前 20 天的完整数据。
test.csv : 从剩下的数据当中取样出连续的 10 小时为一笔,前九小时的所有观测数据当作 feature,第十小时的 PM2.5 当作 answer。一共取出 240 笔不重复的 test_data,请根据 feature 预测这 240 笔的 PM2.5。
Data 含有 18 项观测数据 AMB_TEMP, CH4, CO, NHMC, NO, NO2, NOx, O3, PM10, PM2.5, RAINFALL, RH, SO2, THC, WD_HR, WIND_DIREC, WIND_SPEED, WS_HR。
train.csv和test.csv百度云链接:
链接:https://pan.baidu.com/s/1BtoxnoS66wq06POYt5BoAQ
提取码:p33s

二、思路与代码实现

导入需要的库并读取文件
涉及到简单的切片和补缺值,应该都会。

import numpy as np
import pandas as pd
import torch
from torch.utils.data import DataLoader,Dataset

#数据地址,记得改成自己的
path = r'E:/MLdataset/hw1/train.csv'

#读取文件
with open(path,encoding="big5") as t:
    train_data = pd.read_csv(t)

#数据清理,保留需要的列,缺值用0补
data = train_data.iloc[:,3:]
data[data == 'NR'] = 0
raw_data = data.to_numpy()

如下图,一个小时有18项观测数据,9个小时就是18×9=162个数据,给每个数据分配一个权重w,再加上偏置b,就是一个线性回归的过程。

在这里插入图片描述

为了方便处理,如图所示,我们将18×9的表格拉直为1×162的矩阵,用它与162×1的权重矩阵w相乘,就得到1×1的label(其实还要加上偏置b,详见后面)。这就是我们的一个训练数据。接下来我们从所给的train.csv找出所有的训练数据。
在这里插入图片描述
观察train.csv的格式,见下图,发现其按一天为一组数据,第二天的数据竖直接在第一天的后面。
在这里插入图片描述
这样的结构不方便我们提取出训练数据和label,稍微处理一下。我们将2014.01.02的数据整体移到与2014.01.01水平的位置,连接起来,2014.01.03及往后的数据依此这样处理。原始数据就由竖条变为横长条形状,如下图。
在这里插入图片描述

#将raw_data的数据由竖直变水平连接
month_data = {}  #建立了month_data字典,将每个月的数据分别储存
for month in range(12):  #12个月
    sample = np.empty([18,480])  #有18个数据指标,一天24h,一个月的数据有前20天的,所以20*24=480
    for day in range(20):  #20天
        #切片赋值,举个例子,month=0,day=1时,sample[:,24:48] = raw_data[18:36,:],就是把raw_data的18——36行移到sample的24——24列,及将2014.01.02的数据移到2014.01.01的过程。
        sample[:,day*24:(day+1)*24] = raw_data[18*(20*month + day):18*(20*month + day +1),:]
    month_data[month] = sample #赋值存储,键为月份,值为18*480的数据表

接下来就从变形好的数据中提取我们想要的训练数据和label。
可以看到,一个月有20天的数据,一天有24个小时,共480个小时,一个小时有18个指标,所以得到的是18×480的矩阵。每连续的10个小时可以作为一组训练数据,前九个小时的data作为输入,第十个小时的PM2.5作为label。在一个月20天的480个小时,就能有471条这样的数据产生。12个月就有12×471条数据。

在这里插入图片描述
如前面说的,我们将一个data展开成162*1,再将一个月471个data拼在一起。

在这里插入图片描述
12个月就是12×471条data,data为(12×471,18×9),即(5652,162)。每个data的lable只有一个值,所以label为(12×471,1),即(5652,1)
在这里插入图片描述

x = np.empty([12*471,18*9],dtype=float)#初始化训练data
y = np.empty([12*471,1],dtype=float)#初始化label

for month in range(12):
    for day in range(20):
        for hour in range(24):
            if hour > 14 and day == 19:
                continue
            x[month*471 + day*24 + hour,:] = month_data[month][:,day*24 + hour : day*24 + hour + 9].reshape(1,-1)
            y[month*471 + day*24 +hour,0] = month_data[month][9,day*24 + hour + 9]

这里要加上一个标准化。比较简单粗暴,直接上代码了。

mean_x = np.mean(x,axis = 0)  #求x均值,列
std_x = np.std(x,axis = 0)    #求标准差,列
for i in range(len(x)):
    for j in range(len(x[0])):
        if std_x[j] != 0:
            x[i][j] = (x[i][j]-mean_x[j])/std_x[j] #减均值后除标准差

记得前面说的偏置b吧。这里有个技巧,在X的第一列前中添加一个全为1的列,在w的第一行添加一行,当作b。X就变成了(5652,163),W变为(163,1),可以做矩阵乘法。
在这里插入图片描述
添加列的过程一行代码就搞定:

x = np.concatenate((np.ones([12 * 471, 1]), x), axis = 1).astype(float)#添加一个全1列

至此,数据准备的过程就结束了。x就是处理好的data,y是处理好的label。
下面使用一下pytorch的DataLoader,Dataset两个类实现一下生成和载入数据集。这两个类的具体使用方法,等后面有时间写一篇专门的博客后,再给链接。

#建立自己的类
class Pm_Dataset(Dataset):
    def __init__(self,x,y):
        #初始化一些属性
        self.x_data = torch.from_numpy(x[:])
        self.y_data = torch.from_numpy(y[:])
        self.x_data = self.x_data.float()
        self.y_data = self.y_data.float()
        self.len = x.shape[0]

    #使用Dataset必须定义的两个函数__getitem__()和__len__()
    def __getitem__(self,index):
        return self.x_data[index],self.y_data[index]

    def __len__(self):
        return self.len

#实例化
dataset = Pm_Dataset(x,y)

#载入数据集
train_loader = DataLoader(dataset=dataset,
                        batch_size=500,
                        shuffle=True,
                        num_workers=0)

下面就是训练优化的过程,使用的pytorch框架后,就比较简单。pytorch的使用可以看我总结的相关博客:
https://blog.csdn.net/zhanglw882/category_10561359.html

#建立训练模型
class Model(torch.nn.Module):#继承自torch.nn.Module
    def __init__(self):
        super(Model,self).__init__()
        #线性层
        self.linear = torch.nn.Linear(18*9+1,1)

    #前馈
    def forward(self,x):
        in_size = x.size(0)
        x = x.view(in_size, -1)
        y_pred = self.linear(x)
        return y_pred

#实例化
model = Model()

#损失计算
criterion = torch.nn.MSELoss(reduction='mean')
#优化方法
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)

#训练
for epoch in range(100):
    for i,data in enumerate(train_loader,0):
        inputs,labels = data
        #前馈
        y_pred = model(inputs)
        #损失
        loss = criterion(y_pred,labels)
        #梯度归零
        optimizer.zero_grad()
        print(epoch,i,loss.item())
        #反馈
        loss.backward()
        #优化
        optimizer.step()

torch.save(model.state_dict(),"Linear.pth")#保存训练模型权重

至此,训练过程的代码已经写完,得到的模型保存在了Linear.pth中,就能用于进行test。test过程就是将测试数据用使用训练好的模型权重进行运算,得出label,保存即可。
训练过程完整代码如下:

#李宏毅作业1_pytorch实现,系统windows

#导入相关库
import numpy as np
import pandas as pd
import torch
from torch.utils.data import DataLoader,Dataset

#数据地址,记得改成自己的
path = r'E:/MLdataset/hw1/train.csv'

#读取文件
with open(path,encoding="big5") as t:
    train_data = pd.read_csv(t)

#数据清理,保留需要的列,缺值用0补
data = train_data.iloc[:,3:]
data[data == 'NR'] = 0
raw_data = data.to_numpy()

#数据处理,变为自己想要的形式

#将raw_data的数据由竖直变水平连接
month_data = {}  #建立了month_data字典,将每个月的数据分别储存
for month in range(12):  #12个月
    sample = np.empty([18,480])  #有18个数据指标,一天24h,一个月的数据有前20天的,所以20*24=480
    for day in range(20):  #20天
        #切片赋值,举个例子,month=0,day=1时,sample[:,24:48] = raw_data[18:36,:],就是把raw_data的18——36行移到sample的24——24列,及将2014.01.02的数据移到2014.01.01的过程。
        sample[:,day*24:(day+1)*24] = raw_data[18*(20*month + day):18*(20*month + day +1),:]
    month_data[month] = sample #赋值存储,键为月份,值为18*480的数据表

x = np.empty([12*471,18*9],dtype=float)#初始化训练data
y = np.empty([12*471,1],dtype=float)#初始化label

for month in range(12):          #12个月
    for day in range(20):        #20天
        for hour in range(24):   #24小时
            if hour > 14 and day == 19: #第20天,hour=15的时候,不执行后面的代码,进入下次循环
                continue
            x[month*471 + day*24 + hour,:] = month_data[month][:,day*24 + hour : day*24 + hour + 9].reshape(1,-1)
            y[month*471 + day*24 +hour,0] = month_data[month][9,day*24 + hour + 9]

mean_x = np.mean(x,axis = 0)  #求x均值,列
std_x = np.std(x,axis = 0)    #求标准差,列
for i in range(len(x)):
    for j in range(len(x[0])):
        if std_x[j] != 0:
            x[i][j] = (x[i][j]-mean_x[j])/std_x[j] #减均值后除标准差

x = np.concatenate((np.ones([12 * 471, 1]), x), axis = 1).astype(float)#添加一个全1列

#建立自己的类
class Pm_Dataset(Dataset):
    def __init__(self,x,y):
        #初始化一些属性
        self.x_data = torch.from_numpy(x[:])
        self.y_data = torch.from_numpy(y[:])
        self.x_data = self.x_data.float()
        self.y_data = self.y_data.float()
        self.len = x.shape[0]

    #使用Dataset必须定义的两个函数__getitem__()和__len__()
    def __getitem__(self,index):
        return self.x_data[index],self.y_data[index]

    def __len__(self):
        return self.len

#实例化
dataset = Pm_Dataset(x,y)

#载入数据集
train_loader = DataLoader(dataset=dataset,
                        batch_size=500,
                        shuffle=True,
                        num_workers=0)
#建立训练模型
class Model(torch.nn.Module):#继承自torch.nn.Module
    def __init__(self):
        super(Model,self).__init__()
        #线性层
        self.linear = torch.nn.Linear(18*9+1,1)

    #前馈
    def forward(self,x):
        in_size = x.size(0)
        x = x.view(in_size, -1)
        y_pred = self.linear(x)
        return y_pred

#实例化
model = Model()

#损失计算
criterion = torch.nn.MSELoss(reduction='mean')
#优化方法
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)

#训练
for epoch in range(100):
    for i,data in enumerate(train_loader,0):
        inputs,labels = data
        #前馈
        y_pred = model(inputs)
        #损失
        loss = criterion(y_pred,labels)
        #梯度归零
        optimizer.zero_grad()
        print(epoch,i,loss.item())
        #反馈
        loss.backward()
        #优化
        optimizer.step()

torch.save(model.state_dict(),"Linear.pth")#保存训练模型权重
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值