Python MNIST Pytorch中验证错误意外增加

Python MNIST Pytorch中验证错误意外增加,python,deep-learning,pytorch,mnist,Python,Deep Learning,Pytorch,Mnist,我对整个领域有点陌生,因此决定研究MNIST数据集。我几乎修改了源代码的全部内容,只有一个重要的变化:数据加载。我不想在Torchvision中使用预加载的数据集。所以我用了 我通过从Dataset继承并创建一个新的dataloader从CSV文件加载数据。 以下是相关代码: mean = 33.318421449829934 sd = 78.56749081851163 # mean = 0.1307 # sd = 0.3081 import numpy as np from torch.ut

我对整个领域有点陌生,因此决定研究MNIST数据集。我几乎修改了源代码的全部内容,只有一个重要的变化:数据加载。我不想在Torchvision中使用预加载的数据集。所以我用了

我通过从Dataset继承并创建一个新的dataloader从CSV文件加载数据。 以下是相关代码:

mean = 33.318421449829934
sd = 78.56749081851163
# mean = 0.1307
# sd = 0.3081
import numpy as np
from torch.utils.data import Dataset, DataLoader

class dataset(Dataset):
    def __init__(self, csv, transform=None):
        data = pd.read_csv(csv, header=None)
        self.X = np.array(data.iloc[:, 1:]).reshape(-1, 28, 28, 1).astype('float32')
        self.Y = np.array(data.iloc[:, 0])

        del data
        self.transform = transform

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

    def __getitem__(self, idx):
        item = self.X[idx]
        label = self.Y[idx]

        if self.transform:
            item = self.transform(item)

        return (item, label)

import torchvision.transforms as transforms
trainData = dataset('mnist_train.csv', transform=transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((mean,), (sd,))
]))
testData = dataset('mnist_test.csv', transform=transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((mean,), (sd,))
]))

train_loader = DataLoader(dataset=trainData,
                         batch_size=10, 
                         shuffle=True,
                         )
test_loader = DataLoader(dataset=testData, 
                        batch_size=10, 
                        shuffle=True,
                        )
然而,这段代码给了我一个你在图中看到的非常奇怪的训练错误图,以及一个11%的最终验证错误,因为它将所有内容都分类为“7”。

我成功地跟踪了问题,直到我如何规范化数据,以及如果我使用示例代码(0.1307和0.3081)中给出的值进行转换。规范化,以及将数据读取为“uint8”类型,它工作得非常好。 请注意,在这两种情况下提供的数据差异非常小。在0到1之间的值上按0.1307和0.3081标准化与在0到255之间的值上按33.31和78.56标准化具有相同的效果。这些值甚至基本相同(黑色像素在第一种情况下对应于-0.4241,在第二种情况下对应于-0.4242)

如果你想在IPython笔记本上清楚地看到这个问题,请查看


我无法理解是什么导致了这两种略有不同的数据加载方式在行为上的巨大差异。非常感谢您的帮助。

长话短说:您需要将
item=self.X[idx]
更改为
item=self.X[idx].copy()

长话短说:
T.ToTensor()
运行,它返回一个张量,该张量为numpy数组的内存别名
dataset.X
。和
T.Normalize()
,因此每次提取样本时,都要减去
mean
,然后除以
std
,从而导致数据集降级


编辑:关于为什么它在原始MNIST装载机中工作,兔子洞甚至更深。
MNIST
中的关键一行是将图像放入实例中。该操作声称仅在缓冲区不连续的情况下进行复制(在我们的例子中是这样),但在下,它检查缓冲区是否是跨步的(实际上是跨步的),从而复制缓冲区。幸运的是,默认的torchvision管道包含一个副本,因此
T.Normalize()
的就地操作不会损坏
MNIST
实例的内存
自我数据。

0.1307和0.3081是在MNIST数据集上计算的平均值和标准偏差。在标准化中,通常使用数据集的平均值和标准值。我不认为你可以使用任何一组值。我已经计算了像素强度的平均值和标准偏差,它们分别对应于33.31和78.56,当你在0到255的范围内看它时,我不确定我是否理解这个解释-如果你在做了这件事之后减去平均值,除以标准偏差,它应该没有效果,不是吗?(因为平均值为零,标准偏差为1)如果每次计算平均值和标准偏差(对于每张图像),情况就是这样。但是这个值在脚本开始时是硬编码的(大概是MNIST数据集的全局平均值和方差),所以每次减去33.318。。。除以78.56749<代码>标准化(平均值,标准值)
适用于预先计算的
平均值
标准值
,如果我理解正确,则不适用。在这两种情况下,数据集都会退化,但由于第一种情况下的值更大(33和78比0.13和0.30),退化程度更高,值开始发散。@nobody_nowhere no,原始实现涉及复制样本,因此就地
torchivision.transform
操作不会损坏原始。请参阅我的更新回复以获得更深入的解释。我将与torchvision就这一行为提出一个问题。@Jatentaki为了澄清,我指的是IPython笔记本中两个案例之间的区别。一个是我加载类型为“float32”的值(结果为黑色0-白色255),将值除以数据集的标准值和平均值(33和78),另一个是我加载类型为“uint8”的值(结果为黑色0-白色1),并将值除以此表示中的标准值和平均值(0.13和0.30)。