Keras搭建ANN多分类模型实现鸢尾花数据集分类实战

发布时间:2026/10/20 5:03:12
Keras搭建ANN多分类模型实现鸢尾花数据集分类实战 我第一次把鸢尾花数据集喂给Keras时其实并没有想得那么复杂加载数据、定义网络、跑几个epoch、看准确率。真正跑通后才发现多分类任务里那些看似不起眼的细节——标签怎么编码、输出层该用几个神经元、损失函数选哪个——才是决定模型能不能学起来的关键。这篇文章就把我完整复现“Keras搭建ANN多分类任务进行鸢尾花数据集分类”的过程拆开讲从数据形态、网络设计和代码实现一路写到运行中的坑适合刚学完Python、准备动手做第一个神经网络项目的朋友直接照着敲。1. 鸢尾花数据集为什么适合作为ANN多分类的入门项目很多教程推荐鸢尾花分类但我更想强调的不是“它简单”而是它刚好能覆盖一个多分类模型从数据到评估的所有环节没有任何一个环节是白给的。鸢尾花数据集包含150条样本每条样本有4个数值特征花萼长度、花萼宽度、花瓣长度、花瓣宽度标签是三类鸢尾花。数据集本身干净不需要做图像缩放、文本清洗这类额外处理初学者可以把全部注意力放在模型本身。1.1 分类问题的最小闭环特征、标签与类别映射一个监督学习问题要成立至少要满足三点有可区分样本的特征、有明确标注的类别、有足够的样本去拟合特征和类别之间的关系。鸢尾花数据集恰好是一个“最小但完整”的载体特征维度刚好合适既不稀疏到让模型无从下手也不冗余到掩盖信号。我第一次跑这个任务时犯过一个认知错误——把“分类”等同于“回归”直接让模型输出一个数值当作类别编号。这样做的结果是模型表现很不稳定因为类别之间并没有天然的大小关系。类别0、类别1、类别2只是编号不代表类别1“等于”类别0加一。多分类的正确打开方式是把输出层设计成类别数的维度让模型为每个类别分别给一个“得分”最后在这些得分里选择最大者作为预测结果。1.2 多分类和回归或二分类的本质差异在哪表面上看多分类只是把二分类的输出从1个神经元换成n个神经元但实际训练过程中差异很大。二分类常用sigmoid配合binary_crossentropy模型只需要判断“是或不是”多分类用softmax配合categorical_crossentropy模型必须学会在多个类别之间做权衡输出的是一个概率分布。还有一点容易被忽略鸢尾花数据集本身类别完全均衡50条样本一类所以直接观察测试准确率就很有参考意义。如果换到非均衡数据集准确率可能失真比如某个类别占了90%模型全部猜这个类也有90%准确率。因此做多分类任务时我通常会额外看每个类别的精确率、召回率而不是只看总体准确率。1.3 为什么不用MNIST或CIFAR作为第一个任务MNIST和CIFAR都是经典数据集但它们一方面数据量更大、训练时间更长另一方面它们天然带有空间结构处理图像时至少要引入卷积、池化这些概念。新手很容易把“没调通网络结构”和“没理解数据流”混在一起出了问题不知道是前处理错了还是模型错了。鸢尾花的优势是特征已经是向量形式可以直接进入全连接层把问题收敛到“全连接网络本身怎么设计、怎么调优”这件事上。等我跑通这个流程后再迁移到图像分类就只需要在输入端增加图像预处理和特征提取层后面的训练、评估逻辑几乎还是同一套。所以我一直认为鸢尾花不是一个“玩具”而是一个能帮你把神经网络基本功练扎实的起点。2. 搭建网络前的模型设计维度、激活函数与损失函数很多人拿到数据集后第一件事就是直接写代码我建议先花五分钟把模型结构在纸上画出来。Keras的语法足够友好但语法友好不等于不需要设计恰恰因为写代码门槛低你更要清楚每个数字、每个参数到底在做什么。2.1 输入层维度和标签编码方式的选择鸢尾花每条样本有4个特征所以输入层第一个Dense层的input_dim参数是4。这一点看似简单却有初学者在这里踩坑如果用Keras的Input层那么需要显式指定shape(4,)而不是(4, 1)。(4,)表示一维向量长度4(4, 1)表示4行1列的二维矩阵两者含义完全不同。后续接Dense层时(4, 1)通常也能跑但语义上很奇怪容易在模型summary阶段产生困惑。标签部分更需要认真处理。如果直接用整数标签[0, 1, 2]喂给模型配合sparse_categorical_crossentropy也可以Keras支持这种写法。但如果你想把“多分类概率输出”理解得更透彻我建议先用to_categorical把标签转换成one-hot编码例如2变成[0, 0, 1]。这样输出层的3个神经元就分别对应三个类别的预测置信度你也能直接看到模型在“不确定”时的表现。2.2 隐藏层设计里的常见约定与我的经验值对于只需要处理4个特征的鸢尾花任务两层全连接其实已经足够第一层用8个或16个神经元激活函数选ReLU第二层用3个神经元激活函数选softmax。注意隐藏层增加后模型通常会拟合得更好但也更容易在小数据集上过拟合。150条样本的鸢尾花数据集如果用一个“32-64-3”这样的网络训练集准确率可以冲到很高测试集却不一定比小网络好。我在实际复现时偏好“16-8-3”这样的窄网络而不是一味加宽。原因很简单鸢尾花的特征维度只有4特征内部关系没那么复杂过宽的隐藏层反而给了模型太多自由度去记住训练样本。这里要区分两个概念参数量太大和样本量不匹配会让模型失去泛化能力窄网络虽然听起来不“高级”但在这个任务上往往更稳。2.3 softmax与categorical_crossentropy搭配的底层逻辑softmax做的事情是对一组数字做归一化让它们变成和为1的概率。假设输出层得到原始分数[2.0, 1.0, 0.1]softmax会把它变成类似[0.66, 0.24, 0.10]的结果。它和categorical_crossentropy组合在一起时损失函数会对“真实类别对应的预测概率”取负对数。如果真实类别是第0类预测概率是0.66那么损失大约是-log(0.66)0.41如果模型预测概率只有0.1损失就会变得很大从而推动更新。这里有个很实际的问题为什么不能用均方误差MSE来做多分类理论上可以但实践中收敛慢且效果差。交叉熵能把预测概率和真实分布的差异放大梯度更明显。对于多分类任务几乎默认用categorical_crossentropy或sparse_categorical_crossentropy。理解了这一层就不会在编译模型时随便换损失函数然后抱怨模型不收敛了。3. Keras实现鸢尾花多分类的完整过程下面给出我跑通的一份完整代码。代码不是最精简的版本因为我有意加入了数据划分、标准化和训练历史记录这些才是实战中真正需要的组成部分。3.1 环境准备与数据加载的细节我的环境是Python 3.8以上配合TensorFlow。Keras现在作为TensorFlow的高层API来使用引入方式为from tensorflow import keras这一点和早期独立Keras包略有不同。如果你在搜索资料时看到一些老代码写from keras ...也不要慌逻辑基本一致但新项目我建议统一使用tf.keras。加载数据直接用Keras内置的数据集接口会返回(train_data, train_labels), (test_data, test_labels)结构。这里有个容易忽略的细节内置接口在首次运行时需要下载数据如果你网络不稳定下载会卡住。稳妥的办法是确保你有网络连接或者从本地方便的位置把数据文件准备好再通过指定路径的方式加载。3.2 构建Sequential模型并完成编译以下是我常用的模型定义方式import numpy as np from tensorflow import keras from tensorflow.keras import layers from tensorflow.keras.utils import to_categorical # 省略数据加载部分这里直接展示模型构建 model keras.Sequential([ layers.Dense(16, activationrelu, input_shape(4,)), layers.Dense(8, activationrelu), layers.Dense(3, activationsoftmax) ]) model.compile( optimizeradam, losscategorical_crossentropy, metrics[accuracy] ) model.summary()Dense层的第一个参数是神经元数量第二个参数是激活函数input_shape只在第一层填写。model.summary()会打印每一层的输出形状和参数量我建议每次构建后都看一眼确认维度衔接无误。编译阶段里optimizer选择Adam是因为它在大部分问题上收敛稳定不需要太多手动调节。学习率默认是0.001对鸢尾花数据集来说足够。如果你想观察不同优化器的影响可以把它换成SGD但需要适当调大epoch数量因为SGD本身更“钝”。3.3 训练、评估与预测的关键代码数据划分和标准化我放在训练之前from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) y_train_onehot to_categorical(y_train, num_classes3) y_test_onehot to_categorical(y_test, num_classes3) history model.fit( X_train, y_train_onehot, validation_data(X_test, y_test_onehot), epochs100, batch_size8, verbose1 )StandardScaler会让特征变成均值0、方差1这对神经网络训练很有帮助。原始鸢尾花特征范围没有夸张到需要归一化但实践中我几乎总是先标准化因为后续换数据集时这是通用流程。训练时设置了validation_data每一轮结束后模型都会在测试集上算一次准确率这样我能直观看到训练过程中是否过拟合。预测阶段我这样写predictions model.predict(X_test) pred_classes np.argmax(a, axis1) if a else []这里需要强调model.predict返回的是每个类别的概率矩阵不是直接返回类别编号。要得到类别结果必须用np.argmax在最后一个维度上取最大值的位置。很多新手第一次看到预测结果“形状对不上”就是因为忘了这一步。4. 运行结果分析、常见坑与调参方向模型跑完不是终点把结果看懂才是。下面我从数值表现、复现性、损失曲线三个方面讲一讲实际运行后你会看到什么以及几个反复出现的坑。4.1 从准确率看模型的判断力在我重复多次的实验中一个16-8-3结构的小网络经过100个epoch训练测试集准确率通常在95%以上有时能达到100%。但这里我需要提醒一句鸢尾花数据集很小测试集往往只有30条样本一个样本被分错准确率就下降约3.3个百分点。所以95%和100%之间的差距可能只是“一条样本”的区别不要因为一次跑出100%就认为模型彻底学会了特征。为了看得更细我会输出分类报告from sklearn.metrics import classification_report print(classification_report(y_test, pred_classes, target_names[setosa, versicolor, virginica]))实际输出会出现每类一个precision、recall和f1-score。鸢尾花数据集里有一类通常是setosa很好分另外两类偶尔会有混淆。如果你发现某个类别的召回率特别低问题可能不是模型结构而是特征在边界处本身就存在重叠。4.2 数据顺序、随机种子与复现性神经网络训练里有个隐藏不确定性权重初始化、数据打乱顺序、数据划分方式都受随机数影响。Keras默认每次运行都可能产生不同结果这不是bug而是机制。为了做实验对比我会在开头固定全局随机种子import random import numpy as np import tensorflow as tf random.seed(42) np.random.seed(42) tf.random.set_seed(42)但即使设了种子在GPU上有时仍不能做到完全复现因为某些底层算子是非确定性的。对鸢尾花这种小任务来说你更该关注的是“平均效果”而不是每次都要一模一样。一个反常识的观察是不固定随机种子时多次运行准确率会在一个小区间内抖动这是正常的如果有人只用一次运行结果说某个模型比另一个模型好我基本不会信。4.3 损失曲线不下降时的排查路径训练时如果发现验证集准确率一直上不去我建议按这个顺序排查先说数据确认标签编码正确特别是one-hot后真实类别对应的位置是否对再看学习率把learning rate调小一个量级比如从0.001降到0.0001看损失是否开始缓慢下降最后看网络结构确认输出层的神经元数量等于类别数且最后一层激活函数是softmax。还有一个很容易踩的坑activation参数拼错。比如写activtionrelu会直接报错但如果写成linear模型也能跑起来因为线性激活本质上是没有压缩此时多分类输出会变得很奇怪。每次构建模型后跑一下model.predict看看输出是否是一个形状正确、每行加起来接近1的概率分布就能快速确认网络尾部是否正确。另外epoch数量也需要控制。鸢尾花数据量少训练100次已经足够有时候到第50个epoch后验证集损失就在原地震荡。继续训练不会让模型变得更差但也不会更好反而可能开始记住训练集里的噪声。保存最佳模型权重的ModelCheckpoint回调在这个任务里就能派上用场。5. 从鸢尾花任务迁移到其他多分类任务的通用思路跑通一个数据集的意义在于你能把同一套方法论迁移到新任务上。下面这些点不是鸢尾花专属而是从这个小任务里得到的可迁移经验。5.1 神经元数量和层数如何影响结果鸢尾花任务告诉我模型容量要和数据复杂度匹配。特征维度是4、样本量是150时16-8-3的小网络已经能逼近这个任务的性能上限继续加大到128-64-3训练集损失会更低但验证集没有明显提升甚至不稳定。换成分类目标更复杂的任务比如文本多分类或更宽泛的图像分类就需要在深度上做文章比如增加隐层或在图像任务上引入卷积层。判断模型容量是否合适的直观方法是画训练集和验证集的准确率曲线如果训练集准确率远高于验证集说明过拟合常见对策是减少神经元、增加Dropout、增大正则化如果两者都低说明欠拟合模型容量不足需要增大容量或增加特征工程。这一步其实每个项目都适用。5.2 如果换成一个类别更多的数据集需要改什么假设你要做一个10个类别的分类任务改动逻辑依然是模式化的。第一输入维度改成数据的特征数量第二输出层神经元数从3改成10第三标签编码时to_categorical的num_classes参数改成10第四损失函数仍然用categorical_crossentropy。除了这些结构性改动之外你还要关注每类样本是否足够以及是否需要做类别平衡处理。在实际项目中多分类任务比鸢尾花复杂的地方主要在于两点。第一特征不一定是数值向量文本、图像、音频都需要先转成向量或张量第二类别之间的关系可能不是互斥的。如果一个样本可以同时属于多个类别那就不是多分类问题而是多标签问题输出层的设计、损失函数选择都会随之改变。这些概念在动手前分清楚会少走很多弯路。5.3 我唯一保留的“小习惯”可视化历史记录训练完成的history对象里保存了每个epoch的loss和accuracy。我建议把这个对象存成Python文件或直接读取出来画曲线而不要只盯着控制台末尾那个最终准确率。一个简单的绘图逻辑是横轴是epoch纵轴是验证损失一条曲线画训练损失一条画验证损失。如果两条曲线出现明显分离而且验证损失开始上升这往往就是停下来的信号。我自己在多次跑鸢尾花任务时发现验证损失常常在第40到60个epoch之间出现一个最低点之后开始缓慢回升训练损失却还在下降。这就是典型的过拟合信号。如果使用EarlyStopping回调就可以让模型在验证损失不再改善时自动停止训练同时把最优权重恢复回来。对于后续更换更大的数据集这个习惯能直接帮你节省大量时间。最后再分享一个小技巧在模型编译之后、训练之前可以先拿一批测试数据做一次model.predict观察输出概率的形状。如果这一步正确那么后面训练出的模型大概率不会出现维度或编码错误。很多看似“玄学”的训练问题其实在正式“开工”之前就能被这一步提前暴露。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询