Pytorch - 这是使用 pytorch.data.Dataset 加载大数据集并对其进行线性回归训练的正确方法吗

Posted

技术标签:

【中文标题】Pytorch - 这是使用 pytorch.data.Dataset 加载大数据集并对其进行线性回归训练的正确方法吗【英文标题】:Pytorch - is this the right way to load a big dataset using pytorch.data.Dataset and train it for Linear Regression 【发布时间】:2019-05-23 13:17:29 【问题描述】:

我是 PyTorch 的新手,目前正在使用 historical weather dataset,并且已经构建了 PyTorch DataLoader 迭代器并将数据成功拆分到训练集和测试集。

我想对此数据运行一个简单的线性回归模型来预测列["Temperature (C)"]。我没有做任何特征工程,而只是使用所有浮点 dtypes 作为特征。

在运行模型时(只是一个带有偏差 True-Linear Regression 的全连接层),我发现前 2 批左右的损失有所减少,然后损失在 (100 +- 25) 附近波动。当我对特征进行归一化时,第一批的损失减少了,但波动在200 +- 25左右。

据我所知,我知道一旦对特征进行归一化,SGD 就有更高的机会更快地收敛。但是基础损失存在差异,即。没有特征归一化 ~ 100,有特征归一化/缩放 ~ 200.

我觉得我在某处实现了一些错误,但没有任何线索可以弄清楚我搞砸了什么或者这是否是正常行为。

[更新] 这就是我的 loss function plot 在下降过程中的样子。但我注意到损失的变化太大了。我错了吗 ? Loss vs number of iterations plot x 轴 - 100 个批量大小的迭代次数; y 轴 - 损失

这是我的代码

import pandas as pd
import numpy as np
import torch
from torch.utils.data import DataLoader, Dataset, random_split
from sklearn.preprocessing import StandardScaler

import torch
import torch.nn as nn
from torch.autograd import Variable
from torch.optim import SGD

class LinearRegression(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(LinearRegression, self).__init__()
        self.fc1 = nn.Linear(input_dim, output_dim)

    def forward(self, x):
        output = self.fc1(x)
        return output

class LoaderWeather(Dataset):
    def __init__(self, file_path, transform=None):
        self.file_path = file_path
        self.transform = transform
        # self.scaler = StandardScaler()

        self.data = pd.read_csv(self.file_path)
        self.data = self.data.loc[:, self.data.dtypes == np.float64]

        self.outputs = self.data["Temperature (C)"]
        self.inputs = self.data.drop(["Apparent Temperature (C)", "Temperature (C)"], axis=1)

        self.outputs = np.array(self.outputs).reshape(-1,1)
        self.inputs = np.array(self.inputs)

        # self.inputs = self.scaler.fit_transform(np.array(self.inputs))

        #Normalize data
        # self.means = self.inputs.mean(axis=1).reshape(-1,1)
        # self.stds = self.inputs.std(axis=1).reshape(-1,1)
        # self.inputs = (self.inputs - self.means)/self.stds

    def __getitem__(self, idx):
        return self.inputs[idx], self.outputs[idx]

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

def train_epoch(epoch, train_loader, regression_model, criterion, optimizer):

        print(epoch)
        train_loader = iter(train_loader)
        #Convert to tensors
        for iteration, (inputs, outputs) in enumerate(train_loader):
            # inputs,outputs = train_loader.next()


            inputs = Variable(torch.tensor(inputs).type(torch.FloatTensor))
            outputs = Variable(torch.tensor(outputs).type(torch.FloatTensor))

            #Clear the gradients w.r.t the parameters
            optimizer.zero_grad()

            #Forward pass
            predicted = regression_model(inputs) 

            #Calculate loss
            loss = criterion(predicted, outputs)

            #Backpropogate gradient of loss
            loss.backward()

            #Perform one step of gradient descent
            optimizer.step()

            #Verbosity
            if iteration % 100 == 0:
                print("epochs :, loss : , iteration: ,".format(epoch, loss, iteration))

        return regression_model, loss


def main():

 ############################################   
    #Hyper parameters
    batch_size=100
    n_iters = 20000
    learning_rate=0.0000001
#############################################

    weather_data = LoaderWeather("data/weatherHistory.csv")

    n = len(weather_data)
    n_train = int(0.8 * len(weather_data))
    n_test = n - n_train

    train, test = random_split(weather_data, lengths=[n_train, n_test])



    train_loader = DataLoader(train, batch_size=batch_size, shuffle=True, num_workers=4)
    test_loader = DataLoader(test, batch_size=batch_size, num_workers=4)



    input_dim = 6
    output_dim = 1

    regression_model = LinearRegression(input_dim, output_dim)
    criterion = nn.MSELoss()

    optimizer = SGD(regression_model.parameters(), lr=learning_rate)


    no_of_batches = np.floor(n/batch_size)

    print(no_of_batches)
    epochs = int(n_iters/no_of_batches)

    print("Total epochs : ".format(epochs))

    for epoch in range(epochs):
        regression_model, loss = train_epoch(epoch, train_loader, regression_model, criterion, optimizer)


    print(regression_model, loss)   
    print(regression_model.parameters())
if __name__ == '__main__':
    main()

任何帮助将不胜感激。另外,请让我知道我的训练方式是否良好或这里有什么根本错误。

谢谢

【问题讨论】:

【参考方案1】:

绘制梯度的范数可能很有用(使用线性 reg 这应该不会太难)。如果梯度很小,那么误差的方差是由于随机效应造成的,而如果范数不小,则可能存在一些编程错误。一旦达到收敛区域,一些减少方差的常见技巧是降低学习率(参见https://www.tensorflow.org/api_docs/python/tf/train/exponential_decay),或增加批量大小。这完全取决于您想要达到的准确度。

【讨论】:

以上是关于Pytorch - 这是使用 pytorch.data.Dataset 加载大数据集并对其进行线性回归训练的正确方法吗的主要内容,如果未能解决你的问题,请参考以下文章

大家好,这是香港科技大学PyTorch四日速成教程

Pytorch:图像标签

Pytorch 使用了太多资源

Pytorch 几何:张量大小有问题

Pytorch 卷积网络内存使用详情

Github | PyTorch 中文手册