【PyTorch基础教程12】图像多分类问题(学不会来打我啊)

网友投稿 1104 2022-05-30

学习总结

(1)本次图像多分类中的最后一层网络不需要加激活,因为在最后的torch.nn.CrossEntropyLoss已经包括了激活函数softmax。这里注意softmax的dim参数问题,如下面这个是(3,2)的一个变量,dim = 0 实际上是对第一维的3个变量进行对数化,而dim = 1是对第二维进行操作。

a = torch.Tensor([[1,1],[2,2],[3,3]]) a.size() Out[89]: torch.Size([3, 2]) b = torch.nn.Softmax(dim=0)(a) b Out[91]: tensor([[0.0900, 0.0900], [0.2447, 0.2447], [0.6652, 0.6652]]) b = torch.nn.Softmax(dim=1)(a) b Out[93]: tensor([[0.5000, 0.5000], [0.5000, 0.5000], [0.5000, 0.5000]])

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

(2)本次pytorch在读图像时,将PIL图像(现在都用Pillow了)转为Tensor,神经网络一般希望input比较小,最好在-1到1之间,最好符合正态分布。三种主流图像处理库的比较:

文章目录

学习总结

一、多分类问题

二、分布和API

三、交叉熵代码实践

四、代码实践

Reference

一、多分类问题

注意验证/测试的流程基本与训练过程大体一致,不同点在于:

需要预先设置torch.no_grad,以及将model调至eval模式

不需要将优化器的梯度置零

不需要将loss反向回传到网络

不需要更新optimizer

二、分布和API

法一:把每一个类别的确定看作是一个二分类问题。利用交叉熵。

为了解决抑制问题,就不要输出每个类别的概率,且满足每个概率大于0和概率之和为1的条件。(二分类我们输出的是分布,求出一个然后用1减去即可,多分类虽然也可以这样,但是最后1减去其他所有概率的计算,还需要构建计算图有点麻烦)。

之前二分类中的交叉熵的两项中只能有一项为0.

(1)NLLLoss函数计算如下红色框:

【PyTorch基础教程12】图像多分类问题(学不会来打我啊)

(2)可以直接使用torch.nn.CrossEntropyLoss(将下列红框计算纳入)。注意右侧是由类别生成独热编码向量。

交叉熵,最后一层网络不需要激活,因为在最后的Torch.nn.CrossEntropyLoss已经包括了激活函数softmax。

(1)交叉熵手写版本

import numpy as np y = np.array([1, 0, 0]) z = np.array([0.2, 0.1, -0.1]) y_predict = np.exp(z) / np.exp(z).sum() loss = (- y * np.log(y_predict)).sum() print(loss) # 0.9729189131256584

1

2

3

4

5

6

7

(2)交叉熵pytorch栗子

交叉熵损失和NLL损失的区别(读文档):

https://pytorch.org/doc s/stable/nn.html#crossentropyloss

https://pytorch.org/docs/stable/nn.html#nllloss

搞懂为啥:CrossEntropyLoss <==> LogSoftmax + NLLLoss

三、交叉熵代码实践

前面是sigmoid,后面是softmax(使得概率大于0,概率值和为1)。 两点注意。

# -*- coding: utf-8 -*- """ Created on Mon Oct 18 22:48:55 2021 @author: 86493 """ # 用CrossEntropyLoss计算交叉熵 import torch # 注意1:设定的第0个分类 y = torch.LongTensor([0]) z = torch.Tensor([[0.2, 0.1, -0.1]]) # 注意2:CrossEntropyLoss criterion = torch.nn.CrossEntropyLoss() loss = criterion(z, y) print(loss.item()) # 0.9729189276695251 # 举栗子:mini-batch:batch_size = 3 import torch criterion = torch.nn.CrossEntropyLoss() # 三个样本 Y = torch.LongTensor([2, 0, 1]) # 第一个样本比较吻合,loss会较小 Y_pred1 = torch.Tensor([[0.1, 0.2, 0.9], # 2 该层为原始的线性层的输出 [1.1, 0.1, 0.2], # 0 [0.2, 2.1, 0.1]])# 1 # 第二个样本差的比较远,loss较大 Y_pred2 = torch.Tensor([[0.8, 0.2, 0.3], # 2 [0.2, 0.3, 0.5], # 0 [0.2, 0.2, 0.5]])# 1 l1 = criterion(Y_pred1, Y) l2 = criterion(Y_pred2, Y) print("Batch Loss1 = ", l1.data, "\nBatch Loss2 =", l2.data) # Batch Loss1 = tensor(0.4966) # Batch Loss2 = tensor(1.2389)

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

四、代码实践

(1)pytorch在读图像时,将PIL图像(现在都用Pillow了)转为Tensor,神经网络希望input比较小,最好在-1到1之间,最好符合正态分布。

三种主流图像处理库的比较:

(2)transforms.Normalize,转为标准正态分布即是一种映射到(0, 1)函数。  Pixel  norm  =  Pixel  origin  −  mean   std  \text { Pixel }_{\text {norm }}=\frac{\text { Pixel }_{\text {origin }}-\text { mean }}{\text { std }}  Pixel norm  = std  Pixel origin  − mean

(3)激活层改用relu,最后一层不用加,因为交叉熵损失函数里面已经包括了。

(4)_, predicted = torch.max(outputs.data, dim = 1)求出每一行(样本)的最大值的下标,dim = 1即行的维度;返回最大值和最大值所在的下标。

# -*- coding: utf-8 -*- """ Created on Mon Oct 18 19:25:46 2021 @author: 86493 """ import torch from torchvision import transforms from torchvision import datasets from torch.utils.data import DataLoader # 使用relu激活函数 import torch.nn.functional as F import torch.optim as optim import torch.nn as nn import matplotlib.pyplot as plt losslst = [] batch_size = 64 transform = transforms.Compose([ # 将PIL图片转为Tensor transforms.ToTensor(), # 归一化,分别为均值和标准差 transforms.Normalize((0.1307, ), (0.3081, )) ]) # 训练集数据 train_dataset = datasets.MNIST(root = '../dataset/mnist/', train = True, download = True, transform = transform) train_loader = DataLoader(train_dataset, shuffle = True, batch_size = batch_size) # 测试集数据 test_dataset = datasets.MNIST(root = '../dataset/mnist/', train = False, download = True, transform = transform) test_loader = DataLoader(test_dataset, shuffle = False, batch_size = batch_size) # 模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.l1 = nn.Linear(784, 512) self.l2 = nn.Linear(512, 256) self.l3 = nn.Linear(256, 128) self.l4 = nn.Linear(128, 64) self.l5 = nn.Linear(64, 10) def forward(self, x): # -1位置会自动算出N,即变成(N, 784)矩阵 x = x.view(-1, 784) x = F.relu(self.l1(x)) x = F.relu(self.l2(x)) x = F.relu(self.l3(x)) x = F.relu(self.l4(x)) # 注意最后一层不用加上relu,因为交叉熵已经含有softmax return self.l5(x) model = Net() # 交叉熵作为loss criterion = torch.nn.CrossEntropyLoss() # 优化器SGD加上冲量以优化训练过程 optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum = 0.5) def train(epoch): running_loss = 0.0 for batch_idx, data in enumerate(train_loader, 0): # 1.准备数据 inputs, labels = data # data为元组 # 2.向前传递 outputs = model(inputs) loss = criterion(outputs, labels) losslst.append(loss) # print(losslst,"+++++++++++++") # 3.反向传播 optimizer.zero_grad() loss.backward() # 4.更新参数 optimizer.step() # 记得取loss值用item(),否则会构建计算图 running_loss += loss.item() losslst.append(loss.item()) # 每300个batch打印一次 if batch_idx % 300 == 299: print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300)) running_loss = 0.0 def test(): correct = 0 total = 0 # 加上with这句后面就不会产生计算图 with torch.no_grad(): for data in test_loader: images, labels = data outputs = model(images) # 求出每一行(样本)的最大值的下标,dim = 1即行的维度 # 返回最大值和最大值所在的下标 _, predicted = torch.max(outputs.data, dim = 1) # label矩阵为N × 1 total += labels.size(0) # 猜对的数量,后面算准确率 correct += (predicted == labels).sum().item() print('Accuracy on test set: %d %%' % (100 * correct / total)) # print("losslst的长度为:", len(losslst)) if __name__ == '__main__': for epoch in range(10): # if epoch % 10 == 9: # 每10个输出一次 train(epoch) test()

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

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

代码打印的loss值:

[1, 300] loss: 2.216 [1, 600] loss: 0.872 [1, 900] loss: 0.423 Accuracy on test set: 89 % [2, 300] loss: 0.333 [2, 600] loss: 0.272 [2, 900] loss: 0.232 Accuracy on test set: 93 % [3, 300] loss: 0.189 [3, 600] loss: 0.176 [3, 900] loss: 0.160 Accuracy on test set: 95 % [4, 300] loss: 0.135 [4, 600] loss: 0.127 [4, 900] loss: 0.121 Accuracy on test set: 95 % [5, 300] loss: 0.104 [5, 600] loss: 0.096 [5, 900] loss: 0.097 Accuracy on test set: 96 % [6, 300] loss: 0.080 [6, 600] loss: 0.071 [6, 900] loss: 0.083 Accuracy on test set: 97 % [7, 300] loss: 0.062 [7, 600] loss: 0.062 [7, 900] loss: 0.062 Accuracy on test set: 97 % [8, 300] loss: 0.050 [8, 600] loss: 0.052 [8, 900] loss: 0.053 Accuracy on test set: 97 % [9, 300] loss: 0.034 [9, 600] loss: 0.045 [9, 900] loss: 0.043 Accuracy on test set: 97 % [10, 300] loss: 0.032 [10, 600] loss: 0.032 [10, 900] loss: 0.036 Accuracy on test set: 97 %

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

Reference

(1)pytorch中with torch.no_grad()

(2)https://www.bilibili.com/video/BV1Y7411d7Ys?p=9

(3)pytorch学习(五)—图像的加载/读取方式

(4)解决Python报错:RuntimeError: Can’t call numpy() on Variable that requires grad. Use var.detach().numpy()

pytorch 网络

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:天兔(Lepus 3.8)数据库监控系统部署
下一篇:包含 15 个很棒的示例的终极 Wget 下载指南
相关文章