美文网首页
机器学习(李宏毅)作业1-pytorch实现

机器学习(李宏毅)作业1-pytorch实现

作者: Houtasu | 来源:发表于2021-02-03 11:17 被阅读0次

    最近又双叒开始学习机器学习了,这次看了些pytorch的教程,
    把上次用只用numpy的用pytorch实现一遍。
    这里推荐一个gitbook:Dive-into-DL-PyTorch
    和一个视频教程《PyTorch深度学习实践》完结合集
    题目和基本思路请参考上篇作业一
    本篇仅讲代码实现。
    首先导入相关的包,没啥好说的。

    import numpy as np
    import pandas as pd
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    
    print(torch.__version__)
    torch.set_default_tensor_type(torch.FloatTensor)
    
    data = pd.read_csv('../Datasets/weather/train.csv', encoding='big5')
    

    用pandas读取数据,注意编码为big5。

    data.rename(columns={'日期':'date', '測站': 'station', '測項': 'feature'}, inplace=True)
    

    先把中文重命名,中文选择很不方便。

    data['date'] = pd.to_datetime(data['date'])
    

    把第一列时间转为datetime对象,以调用pandas时间相关的方法。
    现在就要开始构造训练数据了。


    题目的要求是用前9个小时的数据预测第10个小时的pm2.5值,
    那么就要依次取9个小时的数据整理为一行,把第10个小时的pm值取出来作为标签。
    但是需要注意的是给我们的数据集中是取的每个月的前20天的数据,
    第20天的后9个小时的数据是没有标签值的,所以不能作为训练数据。
    那么每一个月有20*24-9=471个样本。
    data['month'] = data.date.dt.month
    data1 = data.groupby(['month','feature']).apply(reshape_feature)
    

    因为数据在月之间是不连续的,所以只能每个月分开处理。
    但是在pandas中,我们可以直接按照月分组并应用apply函数。
    直接调用dt.month获取每个datetime对象的月份。
    然后又因为一个月的数据是的(20天*18特征)*24小时,我们需要把同样的特征追加到一行,
    变为18特征*(24小时*20天)
    在上面分组的时候是['month','feature']一起分组的,
    所以每一个applay传入的数据就是一个月中同一个特征的数据,那么直接转为numpy后reshape(-1)就拼接完成了。
    要注意的是天的前后顺序一定要对。

    def reshape_feature(df):
        df['day'] = data.date.dt.day
        df.sort_values('day', inplace=True)
        df.drop(['date', 'station', 'feature', 'day', 'month'], inplace=True, axis=1)
        df = df.to_numpy()
        return df.reshape(-1)
    

    得到的数据就是图中的样子,一个二维索引,一共12月*18特征行,每行24小时*20天
    再然后就可以用二维切片data1.loc[i][:, j+9]取出所有特征9个小时的数据,再reshape即可得到训练数据
    train_data = []
    for i in range(1, 13):
        x = np.vstack(data1.loc[i])
        train_data.append(np.array([x[:,j:j+9].reshape(-1) for j in range(20*24-9)]))
    
    train_data = np.array(train_data)
    train_data = train_data.reshape((-1, 162))
    

    循环结束后train_data是一个包含12个(471*162)array的列表。
    把这个列表转为array后再用reshape转为(5652*162)的array。
    到这一步也只是构造出我们需要的特征,还需要填充空值和数据标准化。
    把这个array转为dataframe。

    train_data = pd.DataFrame(train_data)
    train_data.replace('NR', 0, inplace=True)
    train_data = train_data.astype('float')
    train_data.fillna(0, inplace=True)
    

    把NR替换为0,把整个dataframe转为float类型,再填充0值。



    然后做标准化处理

    train_data = train_data.apply(lambda x: (x - x.mean()) / x.std())
    train_data = train_data.values
    

    现在得到了最终的训练数据。
    接下来我们取出这些训练数据对于的labels。
    labels = data1.loc[:, 'PM2.5'].copy()
    
    labels = np.vstack(labels)
    labels = labels[:, 9:]
    labels = labels.reshape(-1)
    

    labels就是原数据中的PM2.5值,从data1中取出的是(12个月,24小时*20天)的数据。
    然后前9个小时的数据得到第10个pm值,所以用切片选取第10个开始的pm值。
    再用reshape把12个月拼接在一起得到最终的标签数据。
    经过这么多处理后,终于得到训练样本了。。。
    把这些数据转为tensor,接下来正式进入pytorch的部分。

    train_data = torch.tensor(train_data.astype('float'), dtype=torch.float)
    labels = torch.tensor(labels.astype('float'), dtype=torch.float).view(-1, 1)
    
    train_data, valid_data = train_data[:5500], train_data[5500:]
    labels, valid_labels = labels[:5500], labels[5500:]
    

    由于没有给我们测试数据,所以直接从训练集中截取一小部分来作为测试集。

    batch_size = 128
    dataset = torch.utils.data.TensorDataset(train_data, labels)
    train_iter = torch.utils.data.DataLoader(dataset, batch_size, shuffle=True)
    

    把数据转为dataloader

    class LinearNet(nn.Module):
        def __init__(self, n_feature):
            super(LinearNet, self).__init__()
            self.linear1 = nn.Linear(n_feature, 1)
    #         self.linear2 = nn.Linear(64, 16)
    #         self.linear3 = nn.Linear(16, 1)
            
        def forward(self, x):
    #         x = F.relu(self.linear1(x))
    #         x = F.relu(self.linear2(x))
            return self.linear1(x)
    

    定义线性模型

    def train(epoch):
        total_loss, num = 0, 0
        for X,Y in train_iter:
            optim.zero_grad()
            
            out = net(X)
            l = loss(out, Y)
            l.backward()
            optim.step()
            
            total_loss += l.item()*X.shape[0]
            num += X.shape[0]
        if epoch % 30 == 29:
            print(f'epoch: {epoch + 1}, loss: {total_loss / num :.4f}')
    

    定义训练函数

    net = LinearNet(train_data.shape[1])
    loss = nn.MSELoss()
    optim = torch.optim.Adam(net.parameters(), lr=0.01)
    

    实例化模型,损失函数,优化器,开始train

    for i in range(300):
        train(i)
    

    在测试集上看下损失

    with torch.no_grad():
        print(torch.sum(torch.pow((net(valid_data) - valid_labels), 2))/len(valid_data))
    tensor(28.9964)
    

    把测试集上的预测值和实际值做下对比

    with torch.no_grad():
        for x,y in zip(net(valid_data), valid_labels):
            print(round(x.item(),2), y.item())
    

    可以看出有些差的少,但大部分还是相差有点大的。
    一个是模型比较简单,二个是样本较少。
    本篇也主要是介绍如何生成样本和简单的pytorch的使用,至于如何提升准确度现在还不会。
    以后学到了再优化模型。
    pytorch部分实在没啥好讲的,已经封装的很成熟了,只需要按照固定的套路去调接口就好了。
    其实这里最复杂的是前面的特征提取部分,
    如何把原始数据转化为我们的训练样本比后面调用pytorch要难很多,
    在上篇中使用了大量的循环,有的甚至是三层for循环,
    本篇则使用了大量了pandas和numpy技巧,比如groupby后apply,reshape(-1)拼接数据等。
    这样在数据处理部分只用了一个for循环,甚至那里用多重索引的apply后可以一个循环都不用。
    这些技巧可以提升代码的可读性,也不用手动实现最基础的部分。

    相关文章

      网友评论

          本文标题:机器学习(李宏毅)作业1-pytorch实现

          本文链接:https://www.haomeiwen.com/subject/hrlytltx.html