我是CNN的新手,正在通过食物分类来学习它。以下是我的代码。在数据集部分,我将训练数据集和验证数据集从numpy转换为张量。此时,张量的形状为([9866, 128, 128, 3]
)。由于通道3需要在第一个索引位置,所以我使用了“transpose”方法来更改索引。然后,我使用“Data.TensorDataset”将训练数据和训练标签组合在一起,使用“Data.DataLoader”的原因是我需要批处理大小来加速训练过程。
我的训练集准确率达到了68%,我想提高它。我在网上搜索后发现,可能需要添加归一化处理。但我只找到了如下方式
transform = transforms.Compose([ transforms.ToTensor(), # range [0, 255] -> [0.0,1.0] ])
我对如何将其与“Data.DataLoader”结合使用感到困惑。我知道还有另一种方式可以将训练数据从numpy转换为dataloader,具体如下,这里是链接
train_transform = transforms.Compose([ transforms.ToPILImage(), transforms.RandomHorizontalFlip(), transforms.RandomRotation(15), transforms.ToTensor(), ])test_transform = transforms.Compose([ transforms.ToPILImage(), transforms.ToTensor(),])class ImgDataset(Dataset): def __init__(self, x, y=None, transform=None): self.x = x self.y = y if y is not None: self.y = torch.LongTensor(y) self.transform = transform def __len__(self): return len(self.x) def __getitem__(self, index): X = self.x[index] if self.transform is not None: X = self.transform(X) if self.y is not None: Y = self.y[index] return X, Y else: return Xtrain_set = ImgDataset(train_x, train_y, train_transform)val_set = ImgDataset(val_x, val_y, test_transform)train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True)val_loader = DataLoader(val_set, batch_size=batch_size, shuffle=False)
我的方法可能有些傻,但我还是想尝试,任何帮助都将不胜感激。我希望我解释得清楚,提前感谢。
如果需要,这里是完整的代码:
回答:
对模型输入(无论是训练集、验证集还是测试集)执行的数据归一化取决于您的训练数据统计信息。更具体地说,它对应于训练集中使用的图像的逐通道均值和标准偏差。
torchvision.transforms.Normalize
您可以使用torchvision
的transforms.Normalize
来实现。它是一个非常简单的函数,但很多人似乎难以理解它,或者没有阅读其文档…
torchvision.transforms.Normalize(mean, std, inplace=False)
使用均值和标准偏差对张量图像进行归一化。此变换不支持PIL图像。给定mean
:(mean[1]
, …,mean[n]
) 和std
:(std[1]
, …,std[n]
),对于n
个通道,此变换将归一化输入torch.*Tensor
的每个通道,即output[channel] = (input[channel] - mean[channel]) / std[channel]
您可以认为这两个参数'mean'
和'std'
的命名不够准确,确实有些误导。这可以解释为什么它被如此频繁地误用(今天也是如此)。
它不过是逐通道位移-缩放操作符。
变换的误用
我经常看到这种类型的归一化设置。
T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
为了澄清,上述设置不会执行以下两件事:
-
它不会将您的输入归一化到
[0, 1]
。 -
它不会标准化您的输入(即不会使
mean=0
,std=1
)
所描述的变换将值从[0, 1]
映射到[-1, 1]
(因为(x - .5) / .5 = 2x - 1
)。
>>> x = torch.tensor([0., .5, 1.]).reshape(1, 3, 1, 1)tensor([0.0, 0.5, 1.0])>>> t = T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))>>> t(x).flatten()tensor([-1., 0., 1.])
如何正确使用transforms.Normalize
在您的案例中,您不应该使用.5
作为mean
和std
参数。这没有任何意义。如果您在之前使用了T.ToTensor
,您实际上是在将值映射到[-1, 1]
…
相反,您应该使用实际数据集的mean
和std
来初始化变换,即您直接从数据集中测量得到的均值和标准偏差。
例如,对于Imagenet,统计数据是:[0.485, 0.456, 0.406]
和[0.229, 0.224, 0.225]
,分别为均值和标准偏差。您应该这样做:
>>> t = T.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
已导入torchvision.transforms
为T