以 MNIST 举例,

  • train_dataset.data 获得 feature/image 的 tensor, 其 shape 为 torch.Size([60000, 28, 28])
  • train_dataset.targets 获得 label 的 tensor,其 shape 为 torch.Size([60000])
  • train_dataset[0] 获得二元组(image, label)表示第一条记录
  • train_dataset[0][0]train_dataset[0][1] 分别为第一条数据的 image 和 label 对应的 tensor

数据集独立同分布

MINST 数据独立同分布和非独立同分布的代码:

MNIST dataset distributed as IID & Non-IID | Kaggle

MNIST 数据集中各类别数目与比例:Class percentages in MNIST dataset from paper: A Minimal Subset of Features Using Feature Selection for Handwritten Digit Recognition

Normalize dataset

归一化的目的就是使得预处理的数据被限定在一定的范围内(比如 [0,1] 或者 [-1,1]),从而消除奇异样本数据导致的不良影响。

奇异样本数据是指相对于其他输入样本特别大或特别小的样本矢量(即特征向量)

例如:age 特征一般范围 [0, 100], 工资特征一般范围:[2000, 6000], 那么采用梯度下降法训练过程中,寻找最优解的梯度下降过程中,路径就有可能被工资特征的影响所主导,从而导致收敛过程缓慢,甚至收敛效果不好。

例如下图损失函数的等高线,未归一化的特征会导致损失函数的等高线变成椭圆形状,从而导致梯度下降法收敛过程缓慢,甚至收敛效果不好。

unnormalized_data

归一化之后,损失函数的等高线变成圆形,从而导致梯度下降法收敛过程更加平缓,收敛速度加快。 Normalized Data

数据归一化效果:收敛过程更加平缓,收敛速度加快

常见数据集 mean std:

MNIST: mean, std = (0.1307,), (0.3081,) FashionMNIST: mean, std = (0.2861,), (0.3528,) CIFAR10: mean, std = (0.4914, 0.4822, 0.4465), (0.2470, 0.243, 0.261)

例子:

1
2
3
4
5
trans = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.4914, 0.4822, 0.4465),
(0.2470, 0.243, 0.261)),
])
  1. torch.ToTensor() 将图片转换为 FloatTensor

    Converts a PIL Image or numpy.ndarray (H x W x C) in the range [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0], 将所有数除以 255,将数据归一化到 [0,1]

  2. torch.flatten

    transforms.Lambda(torch.flatten) 将数据集 flatten 成一维

    ToTensor — Torchvision main documentation

  3. transforms.Normalize

    对应 channel 的数据,均值和标准差,运算如下:x = (x - mean) / std 经过 transforms.Normalize 数据不一定服从正态分布,结果也不一定都处于 [-1,1] 之间

    Normalize: 减去均值,除以标准差只是将数据进行标准化处理,并不会改变原始数据的分布。每一个 channels 上所有 batch 的数据服从均值为 0,标准差为 1。

    1. 我用 PyTorch 复现了 LeNet-5 神经网络(MNIST 手写数据集篇)!-阿里云开发者社区
    2. 机器学习笔记:为什么要对数据进行归一化处理? - 不说话的汤姆猫 - 博客园
    3. 如何理解归一化(normalization)? - 知乎
    4. pytorch 中归一化 transforms.Normalize 的真正计算过程 - 知乎

Torch 分割数据集 sampler vs subset vs random_split

  1. 如果一直不停使用一个数据集,且需要根据特征使用数据集的不同部分,则使用 sampler

    为了避免重复性创建数据集,只针对一个数据集做后续的处理的话,可以采用 sampler,而不必采用 subset. You can define a custom sampler for the dataset loader avoiding recreating the dataset (just creating a new loader for each different sampling).

  2. 定制化获取数据集的子集,后续只用该子集 / 只使用大数据集的一部分子集训练

    直接根据原始数据集创建一个 subset 子集即可。

    python - Taking subsets of a pytorch dataset - Stack Overflow

    参考:Pytorch 继承 Subset 类完成自定义数据拆分 - 编程宝库

    动态变化权重的采样器, [feature request] [PyTorch] Dynamic Samplers. · Issue #7359 · pytorch/pytorch

  3. 联邦学习中服务端对数据集进行分割,然后分发给 client 从而模拟 local model training with the share of data。

    可以采用 `random_split

    random_split(dataset, lengths) works directly on the dataset.

    Two input arguments:

    1. The first argument is the dataset.
    2. The second is a tuple of lengths.

    returns two Datasets with non-overlapping indices, which were drawn randomly based on the passed lengths, while SubsetRandomSampler accepts the indices directly.

    If we want to split our dataset into 2 parts, we will provide a tuple with 2 numbers. These numbers are the sizes of the corresponding datasets after the split.

    1
    train_dataset, val_dataset = random_split(dataset, (6000, 899))

    It's important to note that in federated learning, both random_split and sampler can be used together, but their roles are slightly different.

    1. random_split is typically used on the server side to divide the global dataset into subsets for clients

    2. while sampler is used on the client side to control the data sampling strategy during local training

  4. 数据集本地分份,然后使用

    train_dataset 读取了数据集的 dataset 对象。

    1. [不推荐] 将 tensor split 成 K 个 tensor,

      torch.tensor_split(train_dataset.data, K_partitions, dim=0)

    2. [推荐] 通过 reshape 或者 view 来改变 tensor 的视图

      train_dataset.data.reshape((K_partitions, len(train_dataset)//K_partitions, -1))

Change label in dataset

推荐如下方式,将标签等于 4 的标签设为 0,将标签等于 9 的标签设为 1 train_dataset.targets[dataset.targets == 4] = 0 train_dataset.targets[dataset.targets == 9] = 1

注意对训练集和测试集都要改变 Change labels in Data Loader - vision - PyTorch Forums