Pytorch多分类

二分类 后,通过学习 nn.CrossEntropyLoss()softmax()argmax() ,我尝试实现了下多分类模型基本工作流程。本博文主要用于整理个人的知识框架,希望也能帮到大家。如有不足,欢迎留言。🙏

运行环境:https://colab.google/

数据准备

准备数据集

1
2
3
4
5
6
7
import torch
import matplotlib.pyplot as plt

from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split

X_blob, y_blob = make_blobs(n_samples = 1000, n_features = 2, centers = 4, cluster_std = 1.5, random_state = 666)

make_blobs

make_blobs 是 Scikit-learn 中用于生成聚类算法测试数据的函数。它能够生成多类别的高斯分布数据集,用于模拟聚类算法的数据集。

n_samples:生成的样本总数,即生成的数据点个数;

n_features:生成的样本的特征数,即维度;

centers:生成的类别数,或者说簇的个数,即数据点围绕几个中心点分布;

random_state:随机数种子,用于控制生成的数据集的随机性,相同的随机数种子会生成相同的数据集;

cluster_std:用于生成聚类数据集时设置聚类的标准差,决定了数据点在每个聚类中的分布紧密程度。标准差越小,数据点越靠近聚类中心,聚类之间的距离越小。

1
2
3
# 数据类型处理
X_blob = torch.from_numpy(X_blob).type(torch.float)
y_blob = torch.from_numpy(y_blob).type(torch.LongTensor) # LongTensor是一个int64数据类型的值

划分数据集

1
X_blob_train, X_blob_test, y_blob_train, y_blob_test = train_test_split(X_blob, y_blob, test_size = 0.2, random_state = 888)

可视化

1
2
3
4
5
6
plt.figure(figsize = (10, 7))

plt.scatter(x = X_blob[:,0], y = X_blob[:,1], c = y_blob, cmap = plt.cm.RdYlBu)

device = "cuda" if torch.cuda.is_available() else "cpu"
-->如下图

picture1

建立模型

模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from torch import nn

class BlobModel(nn.Module):
# hidden_units参数表示隐藏层中神经元的数量,默认值为8。
# 这个参数决定了神经网络的复杂度和性能。
# 隐藏层中的神经元数量越多,神经网络就越复杂,可以学习更复杂的模式和特征。
def __init__(self, input_features, output_features, hidden_units = 8):
super().__init__()
self.linear_layer_stack = nn.Sequential(
nn.Linear(in_features = input_features, out_features = hidden_units),
nn.ReLU(),
nn.Linear(in_features = hidden_units, out_features = output_features),
)

def forward(self, x):
return self.linear_layer_stack(x)

hidden_units

def _init_(self, input_features, output_features, hidden_units = 8):

hidden_units相当于一个中介,进行模型内部的变量传递。

这个参数决定了神经网络的复杂度和性能,隐藏层中的神经元数量越多,神经网络就越复杂,可以学习更复杂的模式和特征。

self.linear_layer_stack = nn.Sequential()

将多个nn.Linear() 和 ReLU() 封装在函数内部。省去return时的嵌套处理

声明模型对象

1
2
3
4
5
6
# 模型和数据,都要保证设备的一致性
model_multiclass = BlobModel(input_features = 2, output_features = 4).to(device)

torch.manual_seed(666)
epochs = 500
X_blob_train, y_blob_train, X_blob_test, y_blob_test = X_blob_train.to(device), y_blob_train.to(device), X_blob_test.to(device), y_blob_test.to(device)

损失函数和优化器

1
2
3
4
5
# 损失函数
loss_fn = nn.CrossEntropyLoss() # 适用于分类的损失

#SGD优化器
optimizer = torch.optim.SGD(model_multiclass.parameters(), lr = 0.1)

nn.CrossEntropyLoss()

nn.CrossEntropyLoss() 是PyTorch中用于计算交叉熵损失的函数。[^1]

通常用于训练分类模型时,计算预测类别概率与真实类别标签之间的差异。

H(p, q) 值越小,交叉熵也越小,q与p更为接近。

如下图所示:[^2]

image-20240213161744549

训练模型

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
for epoch in range(epochs):

model_multiclass.train()

# 1. forward
y_logits = model_multiclass(X_blob_train)
y_pred = torch.softmax(y_logits, dim = 1).argmax(dim = 1) # softmax、argmax

# 2.
loss = loss_fn(y_logits, y_blob_train)
acc = accuracy_fn(y_true = y_blob_train, y_pred = y_pred)

# 3
optimizer.zero_grad()

# 4
loss.backward()

# 5
optimizer.step()

model_multiclass.eval()

with torch.inference_mode():
test_logits = model_multiclass(X_blob_test)
test_pred = torch.softmax(test_logits, dim = 1).argmax(dim = 1)
test_loss = loss_fn(test_logits, y_blob_test)
test_acc = accuracy_fn(y_true = y_blob_test, y_pred = test_pred)

print(f"Epoch:{epoch} | Loss:{loss:.4f}, ACC:{acc:.2f}% | Test Loss:{test_loss:.4f}, Test acc:{test_acc:.2f}%")

softmax

Softmax 函数是一种常用的激活函数,通常用于神经网络模型中的多类别分类任务;

它将一个包含数字的向量转换为概率向量,其中每个值的概率与向量中每个值的相对大小成比例。该函数将返回一个 位于范围(0, 1)内 包含概率值的张量 y_pred_probs,其中每一行的和都为 1。

在这个例子中,y_logits 是模型的输出,dim = 1 表示在第二个维度上进行 softmax 计算。

softmax 与 sigmoid 的区别

1 输入不同:

​ sigmoid 应用于二分类,输入的是一维数值;而 softmax 应用于多分类,输入的是二维数组

2 输出不同

​ sigmoid 输出一维数组,且数组元素位于 0 ~ 1 范围内;

​ softmax 输出二维数组,数组元素位于 0 ~ 1 范围内,元素含义表示 每个类别的概率,且每行和为1

argmax

函数用于返回 张量中指定维度上的最大值的索引 (即哪一类)

1
2
3
4
5
6
7
8
9
-->
Epoch:492 | Loss:0.2597, ACC:86.25% | Test Loss:0.2141, Test acc:91.00%
Epoch:493 | Loss:0.2592, ACC:87.50% | Test Loss:0.2080, Test acc:92.50%
Epoch:494 | Loss:0.2593, ACC:86.12% | Test Loss:0.2136, Test acc:91.50%
Epoch:495 | Loss:0.2589, ACC:87.50% | Test Loss:0.2078, Test acc:92.50%
Epoch:496 | Loss:0.2589, ACC:86.50% | Test Loss:0.2132, Test acc:91.50%
Epoch:497 | Loss:0.2585, ACC:87.38% | Test Loss:0.2077, Test acc:92.50%
Epoch:498 | Loss:0.2585, ACC:86.62% | Test Loss:0.2128, Test acc:91.50%
Epoch:499 | Loss:0.2582, ACC:87.38% | Test Loss:0.2075, Test acc:92.50%

发现 Test acc 达到最高后会下降

学习率太高,步子迈的太大,在最高值附近来回跳

注意:

​ 这里不是过拟合,过拟合是指,模型在训练数据上表现良好,但在测试的数据上表现不佳。过拟合可能会导致模型无法泛化到新的数据集上,因为模型在训练数据集上学习到了噪声而不是信号。

reference

[^1]: 维基百科 交叉熵 相关
[^2]: https://zhuanlan.zhihu.com/p/98785902 以及 评论区 杨子江 解答


评论