每次(在CPU上)更改pytorch CNN损失的解决方法


介绍

执行CNN程序时,有很多部分取决于随机数,并且每次执行时输出结果都会改变。因此,对我而言,可能很难完全复制该论文(如果它在小数点后两位左右)。一个认真解决这个问题的故事。

单击此处以在gpu

上的

验证环境

macOS High Sierra 10.13.6
python 3.5.5
pytorch 0.4.0
火炬视觉0.2.1

验证

运行该程序3次,并比较结果(因为它很长,所以省略了)。
https://github.com/chatflip/qiita_code/blob/master/deterministic/not_deterministic1.py

终奌站

1
~/qiita_code/deterministic$ python not_deterministic1.py

not_deterministic1.py

1
2
3
4
5
                                    1回目           2回目            3回目
Train Epoch: 1 [0/60000 (0%)]   Loss: 2.304123  Loss: 2.300169  Loss: 2.294914
Train Epoch: 1 [64/60000 (0%)]  Loss: 2.306989  Loss: 2.302103  Loss: 2.290142
Train Epoch: 1 [128/60000 (0%)] Loss: 2.319033  Loss: 2.294176  Loss: 2.300677
Train Epoch: 1 [192/60000 (0%)] Loss: 2.305209  Loss: 2.313074  Loss: 2.310522

每次执行时,

损失都有不同的值。 not_deterministic1.py使用许多随机数。基本上,如果您固定随机数的种子,则无论您执行多少次,它都将是相同的值。使用随机数的地方如下(可能还有其他地方……)

  • 加载的图像的变形(例如Transforms.RandomCrop)
  • 数据集改组(例如DataLoader shuffle=True)
  • 初始网络权重(例如,Nn。Conv2d。权重)

捕获pytorch / torchvision库以修复这些随机数的种子。

加载的图像变形

torchvision.transforms中使用的随机数在python标准库中是随机的。
因此,使用random.seed()修复种子。

transforms.RandomCrop 的随机部分
https://github.com/pytorch/vision/blob/v0.2.1/torchvision/transforms/transforms.py#L399
transforms.RandomHorizo??ntalFlip的随机部分
https://github.com/pytorch/vision/blob/v0.2.1/torchvision/transforms/transforms.py#L447
python标准库随机
https://docs.python.jp/3.5/library/random.html

数据集洗牌

如果

DataLoader的shuffle参数设置为True,则将在函数中调用RandomSampler。
在RandomSampler内部,torch.randperm会随机播放数据集。
可以使用torch.manual_seed()设置torch.randperm的随机种子。

随机抽样创建操作列在[随机抽样]和...
(https://pytorch.org/docs/0.4.0/torch.html#random-sampling)
https://pytorch.org/docs/0.4.0/torch.html?highlight=randperm#creation-ops

Dataloader shuffle = True
https://github.com/pytorch/pytorch/blob/v0.4.0/torch/utils/data/dataloader.py#L434
RandomSampler的随机数部分
https://github.com/pytorch/pytorch/blob/v0.4.0/torch/utils/data/sampler.py#L51
torch.manual_seed
https://pytorch.org/docs/0.4.0/torch.html?highlight=randperm#torch.manual_seed

网络的初始值

声明

nn.Conv2d时,nn.Parameter()存储在self.weight中,并使用torch.Tensor的uniform_(统一随机数)进行初始化。
也可以使用torch.manual_seed()进行设置。

nn.ConvNd重量设置
https://github.com/pytorch/pytorch/blob/v0.4.0/torch/nn/modules/conv.py#L31
https://github.com/pytorch/pytorch/blob/v0.4.0/torch/nn/modules/conv.py#L45

重新验证

根据上述内容执行程序(not_deterministic2.py)

终奌站

1
~/qiita_code/deterministic$ python not_deterministic2.py --num_workers=0

not_deterministic2.py

1
2
3
4
5
                                    1回目           2回目            3回目
Train Epoch: 1 [0/60000 (0%)]   Loss: 2.283671  Loss: 2.283671  Loss: 2.283671
Train Epoch: 1 [64/60000 (0%)]  Loss: 2.313809  Loss: 2.313809  Loss: 2.313809
Train Epoch: 1 [128/60000 (0%)] Loss: 2.318310  Loss: 2.318310  Loss: 2.318310
Train Epoch: 1 [192/60000 (0%)] Loss: 2.315323  Loss: 2.315323  Loss: 2.315323

结果相同。但是num_worker