PyTorch入门学习:9-Softmax Classifier

9 Softmax Classifier

1 Introduction

Design 10 outputs using Sigmoid? 如果直接使用之前的模型,每个输出对应相应类别的概率,那么会造成最终输出不满足分布的特点。 因此,需要对输出进行处理,使得每个类别对应的输出满足以下条件:

  1. 为解决这个问题,将最后一层Sigmoid换为Softmax层。

2 Softmax Layer

  • Softmax函数 使用指数操作来保证每个输出大于0,用比例来确保符合分布规律。
  • An example simple example

3 Loss Function - Cross Entropy

loss function Cross Entropy Loss Function:

  • 不难看出损失只对标签为一的一项有效,假设为1,若,则损失无限大,反之,损失为0。这是对其合理性的简单阐释。
1
2
3
4
5
6
7
# numpy 示例
import numpy as np
y = np.array([1, 0, 0])
z = np.array([0.2, 0.1, -0.1])
y_pred = np.exp(z) / np.exp(z).sum()
loss = -np.sum(y * np.log(y_pred))
print(loss)

Cross Entropy Loss in PyTorch

  • 注意: 如图,在PyTorch中,CrossEntropyLoss已经包含了Softmax层,因此在使用时不需要手动添加Softmax层。另外,使用One-Hot编码表示标签,需要使用LongTensor类型。
1
2
3
4
5
6
7
# torch示例
import torch
y = torch.LongTensor([0])
z = torch.Tensor([[0.2, 0.1, -0.1]])
criterion = torch.nn.CrossEntropyLoss()
loss = criterion(z, y)
print(loss)

4 MNIST Dataset

4.1 数字图像

数字图像是指由像素点组成的二维图像,每个像素点都有一个数值来表示其颜色或灰度值。灰度图像是指每个像素点只有一个数值(单通道(channel)),而不是RGB三通道的数值。 h - 高度 | w - 宽度 | c - 通道 在PIL(Python Imaging Library)和opencv中,图像张量是的三维张量,分别对应高度、宽度和通道数。但在PyTorch中,图像张量是的三维张量,分别对应通道数、高度和宽度。这是为了更高效地进行计算。(?)

MNIST数据集中的样本是28x28的灰度图像,每个像素值在(从0~255映射到)之间。其中,数值大的颜色深。

4.2 Import and Prepare Dataset

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
# import
import torch
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
# 1. prepare dataset
batch_size = 64
# Convert the PIL Image to Tensor
# ToTensor()将PIL Image或numpy.ndarray转换为FloatTensor
# Normalize()将Tensor归一化到[-1,1]
# 公式:output = (input - mean(0.1307)) / std(0.3081)
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
# 读取样本时,transform会自动将图像转换为Tensor
train_dataset = datasets.MNIST(
root='../dataset/mnist',
train=True,
transform=transform,
download=True)
train_loader = DataLoader(
train_dataset,
batch_size=batch_size,
shuffle=True)

test_dataset = datasets.MNIST(
root='../dataset/mnist',
train=False,
transform=transform,
download=True)
test_loader = DataLoader(
test_dataset,
batch_size=batch_size,
shuffle=False)

4.3 Design Model

Design Model

  • x=x.view(-1, 28*28)中的-1表示自动计算该维度的大小,这里是将的图像展开为的向量。
  • 这次使用的激活函数为更常用的relu函数。relu函数的定义为: 它的作用是将小于0的数值置为0,大于0的数值保持不变。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.l1 = torch.nn.Linear(784, 512)
self.l2 = torch.nn.Linear(512, 256)
self.l3 = torch.nn.Linear(256, 128)
self.l4 = torch.nn.Linear(128, 64)
self.l5 = torch.nn.Linear(64, 10)

def forward(self, x):
x = x.view(-1, 28*28)
x = F.relu(self.l1(x))
x = F.relu(self.l2(x))
x = F.relu(self.l3(x))
x = F.relu(self.l4(x))
x = self.l5(x)
return x

model = Net()
criterion = torch.nn.CrossEntropyLoss()
# momentum 量项,用于加速收敛
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

关于动(冲)量的设置 传统梯度下降: 带Momentum的梯度下降: 其中: 是当前时刻的速度 是动量系数(通常设为0.9左右) 是学习率 是当前梯度 作用:

  • 加速收敛:在一致的方向上积累速度,加快收敛
  • 减少震荡:平滑路径,减少在局部最小值附近的震荡
  • 穿越鞍点:帮助模型更快地穿越梯度较小的区域

4.4 Train and 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
# 将训练过程封装为函数
def train(epoch):
running_loss = 0.0
for batch_idx, data in enumerate(train_loader, 0):
inputs, target = data
optimizer.zero_grad()

# forward + backward + update
outputs = model(inputs)
loss = criterion(outputs, target)
loss.backward()
optimizer.step()

running_loss += loss.item()
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
# torch.no_grad() 上下文管理器,用于在测试时禁用梯度计算
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = model(images)
# 取输出中概率最大的类别作为预测结果
_, predicted = torch.max(outputs.data, dim=1)
# 由于batch的原因,要对labels取size(0)
total += labels.size(0)
# 结果形如[1 0 0 1 0 0 0 1...],求和即正确预测的数量
correct += (predicted == labels).sum().item()
print('Accuracy on test set: %d %%' % (100 * correct / total))

if __name__ == '__main__':
for epoch in range(10):
train(epoch)
test()

为什么准确率不太高? 目前使用的是全连接层,而加入特征提取算法能够提取图像的高层特征,在图像识别任务中更有效。 一些人工特征提取算法:FFT、wavelet等 自动特征提取算法:卷积神经网络(CNN)等

5 Exercise

5.1 Cross Entropy Loss vs NLLLoss

  • What are the differences between CrossEntropyLoss and NLLLoss?
  • Reading the document:
  • Try to know why:
    • CrossEntropyLoss <===> LogSoftmax + NLLLoss

5.2 Classifier Implementation


PyTorch入门学习:9-Softmax Classifier
https://eleco.top/2026/02/25/learn-torch-9-Softmax-Classifier/
作者
Eleco
发布于
2026年2月25日
许可协议