目录
老饼讲解:一步一步上手深度学习

【例子】训练一个MLP--类别识别

作者 : 老饼 发表日期 : 2025-10-15 17:32:17 更新日期 : 2026-05-20 12:29:10
老饼讲解-简单易懂,干货满满,爽过嗦螺!


好了,这节我们又试试用MLP来实现类别的预测。

类别预测和数值预测可以当成一家人,只需要在数值预测上套一个softmax就可以转为类别预测了。

说干就干,开始!

一、MLP神经网络代码例子-类别预测

为了方便学习,我们使用简单点的数据。

如下所示,是样本的输入,是样本的类别,下面是具体数据以及平面上的展示:

类别预测-样本数据

好了,这也是个简单的例子,我们就简单的用4个隐神经元去拟合它就好了。

对于二分类,我们可以用一个输出,然后输出层使用sigmoid函数,让它输出"属于类别1"的概率。但是为了通用性,这里我们让它拥有两个输出,然后输出层使用softmax函数,让它"属于类别0、属于类别1"的概率。进一步地,使用交叉熵损失函数来训练模型就可以了。

好了,具体代码示例如下:

# 本代码用于展示:训练一个MLP用于类别预测
# 本代码来自《老饼讲解-深度学习》www.bbblearn.com
import torch
import matplotlib.pyplot as plt 
torch.manual_seed(99)
# -----计算网络输出:前馈式计算------
def forward(w1,b1,w2,b2,x):                                   
    return w2@torch.tanh(w1@x+b1)+b2

# -----训练数据----------------------                                  
x = torch.tensor([[2.5, 1.3, 6.2, 1.3, 5.4, 6 ,4.3, 8.2]                                            
                ,[-1.2,2.5,3.6,4,3.4,2.3,7.2,3.9]])                    # 样本的输入数据    
y = torch.tensor([1,1,0,1,0,0,0,0])                                    # 样本的标签
#-----------训练模型-----------------                                  
in_num  = x.shape[0]                                                   # 输入个数
out_num = 2                                                            # 输出个数
hn      = 4                                                            # 隐节点个数
w1  = torch.randn([hn,in_num],requires_grad=True)                      # 初始化输入层到隐层的权重w1
b1  = torch.randn([hn,1],requires_grad=True)                           # 初始化隐层的阈值b1
w2  = torch.randn([out_num,hn],requires_grad=True)                     # 初始化隐层到输出层的权重w2
b2  = torch.randn([out_num,1],requires_grad=True)                      # 初始化输出层的阈值b2
lr = 0.1                                                               # 学习率
loss   = torch.nn.CrossEntropyLoss()                                   # 定义损失函数为交叉熵损失函数
for i in range(20000):                                                 # 训练10000步
    py = forward(w1,b1,w2,b2,x)                                        # 计算网络的输出
    L  = loss(py.T, y)                                                 # 计算损失函数       
    L.backward()                                                       # 用损失函数更新模型参数的梯度
    w1.data=w1.data-lr*w1.grad                                         # 更新模型系数w1
    b1.data=b1.data-lr*b1.grad                                         # 更新模型系数b1
    w2.data=w2.data-lr*w2.grad                                         # 更新模型系数w2
    b2.data=b2.data-lr*b2.grad                                         # 更新模型系数b2
    w1.grad.zero_()                                                    # 清空w1梯度,以便下次backward
    b1.grad.zero_()                                                    # 清空b1梯度,以便下次backward
    w2.grad.zero_()                                                    # 清空w2梯度,以便下次backward
    b2.grad.zero_()                                                    # 清空b2梯度,以便下次backward
    # ----计算错误率----                                                                  
    p_labels = torch.argmax(py,dim=0)                                  # 模型的预测类别
    err_rate = (p_labels!=y).sum()/p_labels.numel()                    # 错误率
    print(f'第{i}轮错误率:' ,(err_rate).numpy()*100,'%')                # 打印错误率
    if(err_rate<=0.01):                                                # 检查退出条件
        break   											                       
# -------打印模型训练结果----------                                    
print('----模型训练结果---')                                           # 打印标题    
print('错误率:' ,(err_rate).numpy()*100,'%')                           # 打印错误率          
# 绘制预测结果                                                         
colors = ['red','b']                                                   # 定义0,1类样本的颜色为red,blue
true_color   = [ colors[i] for i in y]                                 # 各个样本真实对应的颜色  
pred_color = [ colors[i] for i in p_labels]                            # 各个样本预测对应的颜色 
plt.scatter(x[0],x[1],c=true_color,s=20)                               # 绘制真实样本
plt.scatter(x[0],x[1],marker='o',c='none',edgecolors=pred_color,s=80)  # 绘制预测样本
plt.legend(['true label','predict label'])                             # 显示图例
plt.show()                                                             # 显示画布

print("\n模型参数:")                                                   # 打印模型参数
print('w1:',w1)                                                        # 打印w1
print('b1:',b1)                                                        # 打印b1
print('w2:',w2)                                                        # 打印w2
print('b2:',b2)                                                        # 打印b2

运行结果如下:

模型的拟合效果

模型的训练结果

可以看到,训练好的MLP已经能很好的识别样本的类别的。

二、代码解说

其实代码与"MLP用于数值预测"里的代码基本是一样的,但我们还是简单讲解一下吧~

1.1. 数据与参数初始化

从第10行开始看,这里就是数据的生成以及变量、参数的初始化。代码片段1

第10-13行,直接手敲输入数据,没什么好说的。

第15-17行,设置了输入层、隐层、输出层的神经元个数。这里设为2个输出,是因为有两个类别,0和1。

第18-21行,参数的初始化,这里我们简单的使用randn将它们正态分布随机初始化。

1.2. 模型训练

好了,下面是模型训练的代码了。代码片段2

第22行设置了学习率。

第23行初始化了损失函数,这里我们用了交叉熵损失函数。

第24行开始循环迭代训练,最多训练2万步。

第26、27、28行计算模型的预测值,并计算损失函数,然后将损失值进行backward,以此更新参数的梯度。这里需要注意的是,25行的forward函数是我们第7行定义的用于计算模型输出的函数,这里我们的输出值并没有softmax,这是因为pytorch的交叉熵函数torch.nn.CrossEntropyLoss是包含了softmax的。所以我们模型只需输出判别值就可以了,CrossEntropyLoss会进行softmax后再计算交叉熵。

第28-35就是更新参数并清空梯度了。

第37-41行,将模型的判别值转换为模型的类别标签,然后计算预测类别与真实类别的错误率,如果错误率已经很低,就退出训练。

1.3.模型训练结果

第42-58行展示了我们的训练结果。代码片段3

第43、44行打印错误率。

第45-52行,画出真实类别与预测类别。

最后,54-58行打印模型的参数,w1,b1,w2,b2等。

好了,解说完了,其实也没什么好解说的,毕竟都是我们之前学过的知识。

总结

好了,这节我们具体地看了一下,如何用MLP来做类别预测,包括它的具体代码和效果。其实类别预测与数值预测没有多大区别,就只是有多少个类别就用多少个输出,然后输出层套上了softmax,最后用交叉熵作为损失函数进行训练就可以了。



图标 评论
添加评论