【问题标题】:I get a tensor of 600 values instead of 3 values for mean and std of train_loader in PyTorch我得到一个 600 个值的张量,而不是 PyTorch 中 train_loader 的均值和标准的 3 个值
【发布时间】:2020-10-14 22:33:52
【问题描述】:

我正在尝试规范化我的图像数据,为此我需要找到 train_loader 的均值和标准。

mean = 0.0
std = 0.0
nb_samples = 0.0
for data in train_loader:
    images, landmarks = data["image"], data["landmarks"]
    batch_samples = images.size(0)
    images_data = images.view(batch_samples, images.size(1), -1)
    mean +=  torch.Tensor.float(images_data).mean(2).sum(0)
    std += torch.Tensor.float(images_data).std(2).sum(0)
    ###mean += images_data.mean(2).sum(0)
    ###std += images_data.std(2).sum(0)
    nb_samples += batch_samples

mean /= nb_samples
std /= nb_samples

这里的mean和std都是一个torch.Size([600])

当我在数据加载器上尝试(几乎)相同的代码时,它按预期工作:

# code from https://discuss.pytorch.org/t/about-normalization-using-pre-trained-vgg16-networks/23560/6?u=mona_jalal
mean = 0.0
std = 0.0
nb_samples = 0.0
for data in dataloader:
    images, landmarks = data["image"], data["landmarks"]
    batch_samples = images.size(0)

    images_data = images.view(batch_samples, images.size(1), -1)
    mean += images_data.mean(2).sum(0)
    std += images_data.std(2).sum(0)
    nb_samples += batch_samples

mean /= nb_samples
std /= nb_samples

我得到了: mean is: tensor([0.4192, 0.4195, 0.4195], dtype=torch.float64), std is: tensor([0.1182, 0.1184, 0.1186], dtype=torch.float64)

所以我的数据加载器是:

class MothLandmarksDataset(Dataset):
    """Face Landmarks dataset."""

    def __init__(self, csv_file, root_dir, transform=None):
        """
        Args:
            csv_file (string): Path to the csv file with annotations.
            root_dir (string): Directory with all the images.
            transform (callable, optional): Optional transform to be applied
                on a sample.
        """
        self.landmarks_frame = pd.read_csv(csv_file)
        self.root_dir = root_dir
        self.transform = transform

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

    def __getitem__(self, idx):
        if torch.is_tensor(idx):
            idx = idx.tolist()

        img_name = os.path.join(self.root_dir, self.landmarks_frame.iloc[idx, 0])
        image = io.imread(img_name)
        landmarks = self.landmarks_frame.iloc[idx, 1:]
        landmarks = np.array([landmarks])
        landmarks = landmarks.astype('float').reshape(-1, 2)
        sample = {'image': image, 'landmarks': landmarks}

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

        return sample

transformed_dataset = MothLandmarksDataset(csv_file='moth_gt.csv',
                                           root_dir='.',
                                           transform=transforms.Compose(
                                               [
                                               Rescale(256),
                                               RandomCrop(224),
                                               
                                               ToTensor()      
                                               ]
                                                                        )
                                           )



dataloader = DataLoader(transformed_dataset, batch_size=3,
                        shuffle=True, num_workers=4)

而 train_loader 是:

# Device configuration
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
seed = 42
np.random.seed(seed)
torch.manual_seed(seed)

# split the dataset into validation and test sets
len_valid_set = int(0.1*len(dataset))
len_train_set = len(dataset) - len_valid_set

print("The length of Train set is {}".format(len_train_set))
print("The length of Test set is {}".format(len_valid_set))

train_dataset , valid_dataset,  = torch.utils.data.random_split(dataset , [len_train_set, len_valid_set])

# shuffle and batch the datasets
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=8, shuffle=True, num_workers=4)
test_loader = torch.utils.data.DataLoader(valid_dataset, batch_size=8, shuffle=True, num_workers=4)

如果需要更多信息,请告诉我。

我基本上需要为 train_loader 的平均值获取 3 个值,为 train_loader 的 std 的 3 个值用作 Normalize 的参数。

循环内dataloader中的images_data是torch.Size([3, 3, 50176]),train_loader中的images_data是torch.Size([8, 600, 2400])

【问题讨论】:

    标签: python pytorch mean normalization dataloader


    【解决方案1】:

    首先,您的均值和标准 ([600]) 得到的奇怪形状并不令人惊讶,这是由于您的数据具有形状 [8, 600, 800, 3]。基本上,通道维度是此处的最后一个维度,因此当您尝试使用扁平化图像时

    # (N, 600, 800, 3) -> [view] -> (N, 600, 2400 = 800*3)
    images_data = images.view(batch_samples, images.size(1), -1)
    

    您实际上执行了一个奇怪的操作,将图像的宽度和通道尺寸融合在一起,现在是[8, 600, 2400]。因此,应用

    # (8, 600, 2400) -> [mean(2)] -> (8, 600) -> [sum(0)] -> (600) 
    data.mean(2).sum(0)
    

    创建一个大小为[600] 的张量,这正是你得到的。

    有两个非常简单的解决方案: 要么您从permuting 维度开始,以使第二维度成为通道一:

    batch_samples = images.size(0)
    # (N, H, W, C) -> (N, C, H, W)
    reordered = images.permute(0, 3, 1, 2)
    # flatten image into (N, C, H*W)
    images_data = reordered.view(batch_samples, reordered.size(1), -1)
    # mean is now (C) = (3)
    mean += images_data.mean(2).sum(0)
    

    或者您更改应用mean 和sum 的轴

     batch_samples = images.size(0)
    # flatten image into (N, H*W, C), careful this is not what you did
    images_data = images.view(batch_samples, -1, images.size(1))
    # mean is now (C) = (3)
    mean += images_data.mean(1).sum(0)
    

    最后,为什么dataloader和trainloader的行为不同?好吧,我认为这是因为一个使用dataset,而另一个使用transformedDataset。在 TransformedDataset 中,您应用 toTensortransform 将 PIL 图像投射到火炬张量中,我认为 pytorch 足够聪明,可以在此操作期间置换您的尺寸(并将通道放入第二个维度)。换句话说,您的两个数据集不会产生格式相同的图像,它们的不同之处在于轴的排列。

    【讨论】:

      猜你喜欢
      • 2018-01-21
      • 2021-12-30
      • 2021-03-10
      • 1970-01-01
      • 1970-01-01
      • 2020-11-17
      • 1970-01-01
      • 2020-04-13
      • 2019-09-04
      相关资源
      最近更新 更多