torch 训练相关

Pytorch 使用 GPU

  1. 设备转换

    2 things must be on GPU: model, tensors, 处于同设备(CPU 或 GPU)的数据才能够互相运算,否则需要转换到同一设备

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # For nvidia GPU
    cuda_device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    # For arm-based Apple M1's GPU
    device = torch.device("mps" if torch.backends.mps.is_available() else "cpu")

    cpu_device = torch.device("cpu")

    # use case
    model = model.to(cuda_device)
    tensor = tensor.to(device)
    model = model.to(cpu_device)

    Logistic Regression - Deep Learning Wizard

  2. torch.cuda()tensor.to(torch.device("cuda")) 区别

    Early versions of pytorch had .cuda() and .cpu() methods to move tensors and models from cpu to gpu and back. However, this made code writing a bit cumbersome. Later versions introduced .to() that basically takes care of everything in an elegant way:

    python - PyTorch: What is the difference between tensor.cuda() and tensor.to(torch.device("cuda:0"))? - Stack Overflow

    推荐使用新版的 tensor.to(torch.device("cuda"))

注意:tensor.to() 执行的不是 inplace 操作,因此需要赋值;module.to() 执行的是 inplace 操作。

tensor 在 cpu 与 gpu 之间

  1. 想要修改模型参数,然后继续使用:

    1. 将其从 gpu 拷贝一份,使用: .cpu().detach() 返回 tensor 形式 或 .cpu().detach().numpy() 返回 numpy 形式
    2. 然后,对 tensor 或者 numpy 进行修改 最后,将 CPU 中修改的 tensor(numpy 需要转换为 tensor)拷贝到 gpu 中去:.cuda() 或 .to(device=torch.device('gpu'))

    即使 copy.deepcopy 了 tensor, tensor 也是在 gpu 中的,需要转到 cpu

    Copy PyTorch Model using deepcopy() and state_dict() - Knowledge Transfer Pytorch 的 12 个坑 - 知乎

model.train() 和 model.eval()

model.train(): 在使用 pytorch 构建神经网络的时候,训练过程中会在程序上方添加一句 model.train(),作用是启用 batch normalization 和 drop out。

model.eval(): 测试过程中会使用 model.eval(),这时神经网络会沿用 batch normalization 的值,并不使用 drop out。

如果模型中有 BN 层 (Batch Normalization)和 Dropout,需要在训练时添加 model.train(),在测试时添加 model.eval()。其中 model.train()是保证 BN 层用每一批数据的均值和方差,而 model.eval() 是保证 BN 用全部训练数据的均值和方差;而对于 Dropout,model.train()是随机取一部分网络连接来训练更新参数,而 model.eval() 是利用到了所有网络连接。

如果没有 BN 层 (Batch Normalization)和 Dropout 这两种层,就不用写了。

python - What does model.train() do in PyTorch? - Stack Overflow [PyTorch 学习笔记] 7.3 使用 GPU 训练模型 - 知乎

小知识

  1. Loss.item()

    The .item() method extracts the loss’s value as a Python float, so that you can do some operations, such as sum and average operations.

    .item() moves the data to CPU. It converts or extracts the loss’s value as a Python float. and the plain python float number can only live on the CPU.

    What is loss.item() - autograd - PyTorch Forums

  2. In Pytorch, when dataset = cifar, the type(dataset.targets) is list

    注意 pytorch 读取 MNIST 读出来的 dataset.targets 是 Tensor,但是读取 CIFAR10 读取出来的不是 Tensor,而是 list. 统一训练的时候,注意判断

  3. Time

    CPU 跑 MNIST 多分类逻辑回归: 6 min 左右 GPU 跑 MNIST 多分类逻辑回归: 1min30 min 左右

  4. accuracy

    1. a binary classification model using logistic regression on MNIST can converges to 98% accuracy
    2. a multi-class classification model using logistic regression on MNIST can converges to 92% accuracy

    参考: python - Logistic Regression implementation with MNIST - not converging? - Stack Overflow

复制创建独立新模型

The PyTorch model 是可变对象,因此直接赋值是浅拷贝,需要使用 `copy.deepcopy()` 或者 `model.state_dict()` 来进行深拷贝。

1
2
import copy
modelB = copy.deepcopy(modelA)
[Copy PyTorch Model using deepcopy() and state_dict() - Knowledge Transfer](https://androidkt.com/copy-pytorch-model-using-deepcopy-and-state_dict/)

numpy 和 torch 的 矩阵乘

两个矩阵相乘: np.dot(A,B) 或者 np.matmul(A, B) 多个矩阵相乘: 每两个使用 dot 或者 matmul 或直接使用 @ 符号 对应元素相乘: np.multiply 或者 *

torch.mul() 是对应元素相乘(可广播),torch.mm() 是矩阵相乘 torch.mul() 和 torch.mm() 区别_mob604756f6df2a 的技术博客_51CTO 博客

jupyter notebook 缓存问题

  1. 在外部更改了调用的函数的代码,但是它依然使用旧的缓存的代码,解决方法:

    Put in the following two cells at the beggining of your code and it will automatically reload any new version of your code:

    1
    2
    %load_ext autoreload
    %autoreload 2

    python - Ipython notebook caching issue - Stack Overflow

交叉熵

交叉熵预测结果的概率矩阵,求预测概率最大的值,可以使用的函数:

1
2
torch.max(input, dim, keepdim=False) 返回 (max, max_indices)
torch.argmax(input, dim, keepdim=False) 返回 max_indices

常见形式:

1
2
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)

1
2
outputs = model(images)
predicted = outputs.argmax(dim=1)

nn.Parameter 初始化在 GPU 设备上

[Undesirable behaviour] Allocating a nn.Parameter on gpu inside a nn.Module makes it not to be enlisted as network parameter · Issue #20089 · pytorch/pytorch

softmax 和 sigmoid

激活函数 sigmoid softmax
分类 一般用于二值分类,可以但不建议用于多值分类,准确率低 可以用于二值以及多值分类
使用注意 分类不明确的,概率性的,使用 sigmoid 分类互斥,可以明确输出是哪个类别的使用 softmax
交叉熵 BCE: binary cross-entropy categorical cross-entropy

machine learning - Sigmoid activation for multi-class classification? - Stack Overflow

machine learning - How does Sigmoid activation work in multi-class classification problems - Data Science Stack Exchange

torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean'): weight 是 sigmoid 预测的类别概率,If given, has to be a Tensor of size nbatch: [batch_size, number_class],(需要梯度,float 类别) 'reduction='mean': the sum of the output will be divided by the number of elements in the output.

nn.BCEWithLogitsLoss() 封装了 sigmoid 所以直接把模型的输入传进去即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
input = torch.randn(3, requires_grad=True)
target = torch.empty(3).random_(2)

sigmoid = nn.Sigmoid()
bce_loss = nn.BCELoss()
bce_logits_loss = nn.BCEWithLogitsLoss()

#with class probabilities
probabilities=sigmoid(input)
output = bce_loss(probabilities, target)
output.backward()

print(output.item()) #0.4326

#with logits
output = bce_logits_loss(input, target)
output.backward()

How is Pytorch’s binary_cross_entropy_with_logits function related to sigmoid and binary_cross_entropy | by Yang Zhang | Medium

Difference between BCELoss and BCEWithLogitsLoss in PyTorch - Knowledge Transfer

soft targets vs hard target

soft targets 就是 softmax 得出的各类的概率 一般使用 soft target 的 loss function

hard target 包含的信息量(信息熵)很低, soft target 包含的信息量大,拥有不同类之间关系的信息(比如同时分类驴和马的时候,尽管某张图片是马,但是 soft target 就不会像 hard target 那样只有马的 index 处的值为 1,其余为 0,而是在驴的部分也会有概率。)

MNIST softmax logistic regression 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Model: "sequential"
mathjax: true
---Layer (type) Output Shape Param #
mathjax: true
---flatten (Flatten) (None, 784) 0
mathjax: true
---dense (Dense) (None, 10) 7850
---
Total params: 7,850
Trainable params: 7,850
Non-trainable params: 0
mathjax: true
---```

parameters: `784*10 weights + 10 biases at output nodes = 7850`

每张图像的输出都是一个大小为 10 的向量,该向量的每个元素都指示了该图像属于某个具体标签(0 到 9)的概率。为图像预测得到的标签即为概率最高的标签。

[Feed-forward and convolutional neural networks](https://uudav.nl/practicals/04_deep_learning/practical_04_answers.html)

## 多分类/二分类

对 crossentropy 输出的概率,求最大的值及其索引: `_, preds = torch.max(outputs, 1)`

At this point, we need to determine the index corresponding to the maximum score in the out tensor. We can do that using the max function in PyTorch, which outputs the maximum value in a tensor as well as the indices where that maximum value occurred.

## [conv neural network - ValueError: Target size (torch.Size([16])) must be the same as input size (torch.Size([16, 1])) - Stack Overflow](https://stackoverflow.com/questions/57798033/valueerror-target-size-torch-size16-must-be-the-same-as-input-size-torch)

pytorch 二分类 using BCEWithLogitsLoss, output neuron = 1, `preds.squeeze(dim=-1).float()`

### 二分类测试

sigmoid 二分类,测试准确度时,注意预测概率是 [0,1],所以将其与 0.5 进行比较
`predicted = (model(image) > 0.5).float().squeeze(dim=-1)`

softmax 二分类,测试准确度时,注意预测概率是 [-inf,inf],所以需要将其与 0 比较
`predicted = (model(image) > 0).float().squeeze(dim=-1)`

[Accuracy not changing after second training epoch - PyTorch Forums](https://discuss.pytorch.org/t/accuracy-not-changing-after-second-training-epoch/80405/3)

# accuracy 先稳定上升,然后一直降低

学习率过大/batch size 过小,可以对学习率降低 1-2 个量级试试
[训练网络时为什么会出现 loss 逐渐增大的情况? - 知乎](https://www.zhihu.com/question/60510992)02

## 准确率先升后降,再升

采用 warm up + Cosine Anneal:

[训练神经网络 Loss 先降后升? - 简书](https://www.jianshu.com/p/c8583867677e)
[base model 第七弹:warm up、consine 衰减 、标签平滑、apex、梯度累加 - 知乎](https://zhuanlan.zhihu.com/p/148487894)

[使用余弦退火逃离局部最优点——快照集成(Snapshot Ensembles)在 Keras 上的应用 - 知乎](https://zhuanlan.zhihu.com/p/93648558)

[Pytorch:几行代码轻松实现 Warm up + Cosine Anneal LR\_我是大黄同学呀的博客-CSDN 博客\_pytorch warmup 实现](https://blog.csdn.net/qq_36560894/article/details/114004799)

[调节学习率 - 知乎](https://zhuanlan.zhihu.com/p/136183319)