ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于Python+TensorFlow 2.3实现花卉识别系统:从数据到实时演示

基于Python+TensorFlow 2.3实现花卉识别系统:从数据到实时演示 简介基于Python与TensorFlow 2.3开发的花卉识别系统是一份可直接运行的高分期末大作业项目面向高校学生、课程设计者及TensorFlow初学者解决从图像数据集处理到模型训练、界面展示的全流程搭建问题也适合K12阶段的综合实践拓展。项目整体识别率约97%功能完善且界面简洁适合快速部署用于答辩或实验演示。资源包共27个文件压缩后约239.31MB包含数据拆分与读取、模型训练与测试、窗口界面等Python代码已训练好的h5模型权重、花卉数据集说明、PNG/JPG示例图片、XML工程配置和readme文档结构清晰便于按需查阅和二次修改。目前已有251人学习下载下载后即可获得完整源码、模型文件、数据说明与使用文档省去环境调试和代码补全的时间尤其适合需要短时间完成期末项目或课程设计的学习者。1. 基于PythonTensorFlow 2.3实现花卉识别系统期末大作业最怕的不是代码期末大作业做花卉识别最常见的交法是用Keras搭个CNN跑通ImageNet上预训练的模型再把准确率截图贴到报告里。但真正到答辩时老师一个问题就能问住为什么用TensorFlow 2.3而不是直接上最新版你的模型在验证集上有95%换一批照片还能不能有90%如果只交一个训练好的model.h5你的大作业就只是一堆权重不叫系统。基于pythontensorflow2.3实现花卉识别系统意味着你要把数据读取、模型训练、效果评估、预测接口四个部分串成一条可复现的流水线同时还要能说清楚每个参数为什么这么设。很多同学卡在环境配置和版本兼容上一晚上都在装库、降版本最后代码还没跑起来。这篇文章我按自己实际做过的路径从数据准备讲到避坑末尾再给你一套能现场演示的实时识别脚本照着做一遍期末答辩的底气会完全不一样。2. 选型与数据准备TensorFlow 2.3的生态位和从文件夹到tf.data的数据管线2.1 为什么是TensorFlow 2.3版本选择其实是给“能跑”上保险选TensorFlow 2.3而不是2.10、2.15不是因为它新而是因为它和很多学校机房、老笔记本CPU的兼容性正好卡在“装得上、跑得动”的位置。TensorFlow 2.3使用tf.keras作为标准接口支持Python 3.7-3.8对CUDA 10.1自带匹配不需要额外去配一堆环境变量和编译工具链。对于期末作业这种交付时间紧、一台机器可能要跑多人程序的任务稳定比尝鲜重要得多。从代码写法来看2.3和2.4、2.5的差异极小但如果你装的是2.10以上会遇到Python 3.11的兼容问题、tf.compat.v1被进一步精简的问题。所以我给的建议是如果你的机器能装好2.3就锁死版本如果因为系统原因已经装了新版也千万别每个API都按最新文档改用tf.keras统一入口基本不会翻车。至于python环境配置我一般用Anaconda建独立环境避免和系统自带的Python冲突conda create -n flower python3.8 conda activate flower pip install tensorflow2.3.0这里指定python3.8是因为TensorFlow 2.3对3.8支持最顺pip install会自动拉取numpy、scipy等依赖不需要手动装一堆库。装完可以用一行代码验一下import tensorflow as tf print(tf.__version__)如果输出了2.3.0环境就通了。如果报DLL load failed多半是缺少Visual C运行库装一下就好。这一环没做好后面所有代码都跑不了所以版本锁定不是洁癖是给你自己省时间。2.2 数据集的目录结构设计与image_dataset_from_directory做花卉识别数据集最常见的来源是Oxford 102 Flowers、Baidu爬图或者老师给的照片集。无论哪种统一目录格式是第一步。标准做法是把图片按类别文件夹放好训练集和验证集分开或者用一个根目录的train代码里再按比例切分。推荐目录结构flower_data/ train/ rose/xxxx1.jpg rose/xxxx2.jpg sunflower/xx1.jpg tulip/yy1.jpg daisy/zz1.jpg dandelion/aa1.jpg在TensorFlow 2.3里最省事的读取方式是tf.keras.preprocessing.image_dataset_from_directory它可以根据文件夹名自动生成标签不需要自己写解析函数。示例代码import tensorflow as tf train_ds tf.keras.preprocessing.image_dataset_from_directory( flower_data/train, validation_split0.2, subsettraining, seed42, image_size(224, 224), batch_size32, label_modecategorical ) val_ds tf.keras.preprocessing.image_dataset_from_directory( flower_data/train, validation_split0.2, subsetvalidation, seed42, image_size(224, 224), batch_size32, label_modecategorical )这段代码把根目录下的子文件夹名作为类别自动按20%切出验证集图片统一缩放到224×224每个batch装32张。label_modecategorical表示标签是one-hot编码对应模型的输出层用softmax如果改成label_modesparse模型输出层就用SparseCategoricalCrossentropy两者不能混用。很多同学在这里翻车训练时用categoricalloss却写sparse导致维度不匹配报错信息在自定义训练循环里被吞掉非常难定位。切分时加了seed42是为了保证每次运行切出来的验证集是同一批图片答辩时两次训练结果才能对比。validation_split设在0.2是因为数据量本身不大验证集太小则指标波动大太大则训练数据不足。如果你手里的图片本身已经分成train和val两个目录就可以去掉validation_split参数直接对两个目录各自调用一次读取函数。2.3 数据增强的必调参数让模型在看“多样本”的同时不学歪期末数据集通常只有几千张直接训练很容易过拟合。TensorFlow 2.3自带的增强层可以直接塞进模型作为第一层训练时会随机变换预测时自动关闭这点比老的ImageDataGenerator方便很多。参考配置data_augmentation tf.keras.Sequential([ tf.keras.layers.RandomFlip(horizontal), tf.keras.layers.RandomRotation(0.05), tf.keras.layers.RandomZoom(0.1), ])参数解释RandomFlip(horizontal)是随机左右翻转花卉照片里花的方向是任意的水平翻转不改变语义RandomRotation(0.05)表示最大旋转5度这个值很小是怕花瓣的纹理方向成为虚假特征RandomZoom(0.1)表示最多随机缩放10%模拟拍摄距离的变化。注意不要加RandomFlip(vertical)因为真实照片里的花很少倒着长过度增强会让模型学到不该有的不变性反而降低真实场景的识别率。增强层放在模型里还是数据流水线里都行。我一般放在模型第一层这样训练和预测的预处理可以统一。但要注意如果把增强层放进Sequential在model.summary()里它也会被算成一层答辩时老师问起来你要能说清楚那不是卷积层。增强效果需要可视化验证不能只凭感觉调参。用matplotlib抽样看一批增强后的图片import matplotlib.pyplot as plt for images, labels in train_ds.take(1): plt.figure(figsize(10, 10)) for i in range(9): ax plt.subplot(3, 3, i 1) plt.imshow(images[i].numpy().astype(uint8)) plt.title(train_ds.class_names[tf.argmax(labels[i])]) plt.axis(off) plt.show()这段代码取出一个batch的第一张图画成3×3网格。如果看到花瓣扭曲、背景变形到不自然说明增强参数太大了要回调。如果增强后的图和原图几乎一样说明增强力度不够起不到防过拟合作用。理想状态是图片仍然看得出是花但角度、缩放、明暗有细微变化。2.4 从文件夹到流水线cache、prefetch和shuffle的玄学直接用image_dataset_from_directory返回的Dataset在每次epoch都会重新读硬盘训练一慢就容易让人误以为是模型问题。加上三行代码能让数据读取和训练计算重叠train_ds train_ds.cache().shuffle(1000).prefetch(buffer_sizetf.data.AUTOTUNE) val_ds val_ds.cache().prefetch(buffer_sizetf.data.AUTOTUNE)cache()把第一个epoch读入的图片缓存在内存里后续epoch不再读盘但如果内存不够可以传cache(filename./cache.tfdata)缓存到本地文件。shuffle(1000)让每个batch里的图片顺序打乱避免模型看到同一个类别的所有照片后连续更新权重这个buffer越大随机性越强但也越占内存。prefetch(buffer_sizetf.data.AUTOTUNE)让数据准备和模型计算并行CPU在GPU/加速器干活时提前准备下一批数据。这套组合是TensorFlow数据管线的基本功答辩时说“我用Dataset API来消除IO瓶颈”比只会一句“用了数据增强”要加分不少。3. 搭建卷积模型手写CNN还是迁移学习期末作业该怎么选3.1 手写CNN的层设计与参数量手算如果老师要求体现“自己写的模型”可以设计一个轻量CNN三层卷积池化全局平均池化全连接层。参考代码model tf.keras.Sequential([ data_augmentation, tf.keras.layers.Conv2D(32, (3, 3), activationrelu, input_shape(224, 224, 3)), tf.keras.layers.MaxPooling2D(2, 2), tf.keras.layers.Conv2D(64, (3, 3), activationrelu), tf.keras.layers.MaxPooling2D(2, 2), tf.keras.layers.Conv2D(128, (3, 3), activationrelu), tf.keras.layers.GlobalAveragePooling2D(), tf.keras.layers.Dense(num_classes, activationsoftmax) ])Conv2D的参数量计算公式是卷积核尺寸×输入通道数×输出通道数再加上每个输出通道一个bias。第一个Conv2D的参数量是3×3×3×3232896第二个是3×3×32×646418496第三个是3×3×64×12812873856。总参数量不到10万CPU上也能很快跑完一轮。注意这里用了GlobalAveragePooling2D而不是Flatten因为Flatten会把最后一个卷积层的输出展开成上万维向量GlobalAveragePooling2D把每个通道的值做平均参数量骤减过拟合风险也小很多。这个结构的感受野变化很重要原图224×224经过两次池化后变成56×56再经过第三次卷积时每个卷积核只能看到局部花瓣纹理。如果你的花类别差别主要在整体形状比如向日葵和雏菊建议把第二层或第三层的卷积核改成5×5感受野更大如果差别在纹理比如玫瑰和牡丹3×3就够。这个调法没有绝对正确答案拿验证集准确率说话就行。3.2 迁移学习MobileNetV2是最省心的特征提取器期末作业普遍想拿高分手写CNN准确率到不了90%很正常因为数据量不够。更好的方案是迁移学习用tensorflow.keras.applications.MobileNetV2作为特征提取器base_model tf.keras.applications.MobileNetV2( input_shape(224, 224, 3), include_topFalse, weightsimagenet ) base_model.trainable False model tf.keras.Sequential([ data_augmentation, base_model, tf.keras.layers.GlobalAveragePooling2D(), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(num_classes, activationsoftmax) ])冻结base_model后整个模型只有顶层Dense的几千个参数在训练用CPU也能在几分钟内跑完几十轮。参数解释include_topFalse去掉MobileNetV2自带的1000类分类头只保留卷积特征提取部分weightsimagenet加载在ImageNet上预训练的权重第一次运行会自动下载约14MB的文件到~/.keras/models如果在无网络的实验环境跑需要提前下载好权重并把路径传进来比如weightsmobilenet_v2_weights.h5。Dropout(0.2)是防止全连接层过拟合但不要设太大否则验证loss会下不去。这里有个关键操作base_model.trainable False之后model.summary()中base_model部分的trainable参数是0。如果你在训练中后期又解冻base_modeltrainableTrue学习率必须调小到1e-5左右否则预训练权重会被破坏准确率会瞬间跳水。期末作业不建议解冻冻结训练已经能拿到比手写CNN高很多的准确率。3.3 优化器、学习率与callbacks让训练过程有后悔药compile和fit的配置直接决定了训练能不能收敛以及中途崩了有没有后悔药。常用的配置model.compile( optimizertf.keras.optimizers.Adam(learning_rate0.001), losscategorical_crossentropy, metrics[accuracy] ) callbacks [ tf.keras.callbacks.EarlyStopping(patience10, restore_best_weightsTrue), tf.keras.callbacks.ModelCheckpoint( flower_model.h5, save_best_onlyTrue, monitorval_accuracy, save_weights_onlyFalse) ] history model.fit( train_ds, validation_dataval_ds, epochs50, callbackscallbacks, verbose1 )Adam(learning_rate0.001)是默认值对大多数任务够用。如果你发现loss前几个epoch不降或者震荡把learning_rate改成0.0003如果下降得特别慢可以升到0.003但很快会过拟合。EarlyStopping(patience10, restore_best_weightsTrue)指连续10个epoch验证指标不提升就停止同时把模型权重恢复到验证指标最好的那个epoch这个restore_best_weights能避免训练到后期过拟合了但你手里存的还是最优模型。ModelCheckpoint的save_best_onlyTrue只保存验证集准确率最高的模型save_weights_onlyFalse保存完整模型结构和权重这样之后加载时不需要重新定义模型结构。很多教程只保存权重再加载时还得复制一遍GoogleNet那种前向结构期末演示时特别容易漏层白白浪费时间。训练完成后看一眼historyprint(max(history.history[val_accuracy]))最高验证准确率是答辩时最重要的硬指标。如果这个值低于期望优先检查是不是数据增强太强了其次把epoch数加大最后再考虑换模型。3.4 两个方案的适用边界验证集准确率与答辩话术手写CNN适合“老师要求不能只用预训练模型”的场景或者你调的参数量明显小于MobileNetV2能体现出“我懂网络设计”。迁移学习适合追求高准确率、演示效果好的场景。我一般会两个都做先用MobileNetV2跑出90%以上的准确率作为主交付再把手写CNN的准确率报告放在附录里说明“自己实现的轻量网络能达到多少预训练特征提取后能提升多少”这样两个维度都展现了。答辩时如果老师问“为什么选MobileNetV2”可以说它用深度可分离卷积计算量比ResNet50小一个数量级0.5-1M参数量在CPU上也能跑实时内置在Keras里不需要额外安装。这个回答就够扎实了。4. 训练过程与评估准确率之外还要看哪些曲线4.1 把整个流程组装成可复跑的训练脚本期末作业交付的是一份能从头跑到尾的代码不是一堆jupyter cell。我建议把所有步骤封装成一个带main的脚本数据读取、增强、模型定义、训练、评估依次执行。这样换一台电脑也能一键复现。下面是一个骨架import tensorflow as tf from tensorflow import keras def build_model(num_classes): base_model tf.keras.applications.MobileNetV2( input_shape(224, 224, 3), include_topFalse, weightsimagenet ) base_model.trainable False model keras.Sequential([ keras.layers.RandomFlip(horizontal), keras.layers.RandomRotation(0.05), base_model, keras.layers.GlobalAveragePooling2D(), keras.layers.Dropout(0.2), keras.layers.Dense(num_classes, activationsoftmax) ]) return model if __name__ __main__: train_ds tf.keras.preprocessing.image_dataset_from_directory(...) val_ds tf.keras.preprocessing.image_dataset_from_directory(...) train_ds train_ds.cache().shuffle(1000).prefetch(tf.data.AUTOTUNE) val_ds val_ds.cache().prefetch(tf.data.AUTOTUNE) model build_model(num_classes5) model.compile(...) history model.fit(...) _, acc model.evaluate(val_ds) print(val_accuracy:, acc)这里把数据读取的参数用省略号代替实际填写和上一章的代码一致。注意main块里要固定seedTensorFlow 2.3里可以加tf.random.set_seed(42)数据集切分也传了seed42这样重复运行的结果在数值上可复现答辩时不同次运行结果不会差得离谱。4.2 混淆矩阵看清模型是把“玫瑰”错认成“月季”还是“郁金香”只看准确率看不出模型细粒度上的错误。花卉种类之间有相似性比如玫瑰和月季、向日葵和雏菊老师很可能追问“哪两类容易混淆”。用混淆矩阵来说话import numpy as np from sklearn.metrics import confusion_matrix y_true [] y_pred [] for images, labels in val_ds: preds model.predict(images) y_pred.extend(np.argmax(preds, axis1)) y_true.extend(np.argmax(labels.numpy() if hasattr(labels, numpy) else labels, axis1)) cm confusion_matrix(y_true, y_pred) print(cm)model.predict(images)返回每个样本的各类别概率np.argmax取最大概率的类作为预测结果。混淆矩阵的行是真实类别列是预测类别对角线越高越好。如果发现玫瑰被频繁认成月季说明这两类在224×224分辨率下差异太小可以针对性收集更多玫瑰特写或者把image_size调整到(256,256)再试一次。这个分析过程期末答辩时讲出来非常加分。4.3 单张图片预测与结果反推到类名训练完总要给人演示“上传一张图片输出是哪类花”。单张图片预测代码需要处理batch维度from tensorflow.keras.preprocessing import image img image.load_img(test_rose.jpg, target_size(224, 224)) img_array image.img_to_array(img) img_array tf.expand_dims(img_array, 0) # 增加batch维度 preds model.predict(img_array) class_names train_ds.class_names predicted_index tf.argmax(preds[0]).numpy() print(Predicted:, class_names[predicted_index], Confidence:, preds[0][predicted_index])这里有个常见坑image.load_img会返回PIL图像image.img_to_array转换为numpy数组但维度是(224,224,3)没有batch维必须用tf.expand_dims扩成(1,224,224,3)否则model.predict()会报维度错误或者把每个像素当成一个样本。另外train_ds.class_names的顺序是文件名的字母排序和训练时Dataset内部生成的标签索引一一对应不能自己手工写死列表。4.4 模型导出与加载h5和SavedModel的实际差异model.save(flower_model.h5)保存为h5文件一个文件包含结构、权重和优化器状态tf.keras.models.load_model(flower_model.h5)可以直接加载。TensorFlow 2.3还支持SavedModel目录格式model.save(saved_model, save_formattf)SavedModel是一个目录包含assets、variables和saved_model.pb在部署到TensorFlow Serving时是标准格式。但期末作业演示时h5单文件更省事复制到U盘也好管理。注意如果你在ModelCheckpoint里设置save_weights_onlyFalse保存的就是完整模型如果只保存了权重h5文件里只有model.set_weights能用的内容加载时必须先用同一个类定义重建模型结构。我习惯在训练后用model.save(final_model.h5)再单独存一份避免和checkpoint文件混淆。5. 避坑与常见问题TensorFlow 2.3下最容易翻车的5个点5.1 现象训练时OutOfMemory程序直接崩溃原因image_dataset_from_directory默认把图片全部加载并解码如果图片分辨率高、batch size大、同时开了shuffle buffer显存或内存瞬间被打满。TensorFlow 2.3的tf.data如果显存OOM会在训练第一个epoch就报错而不是中途。解决把image_size调小到(160, 160)或(128, 128)batch size从32降到16或8给shuffle的buffer降到500cache()改为cache(./cache.tfdata)把缓存写到磁盘而不是内存。如果用的是GPU显存还可以在代码开头加一句gpus tf.config.experimental.list_physical_devices(GPU) if gpus: tf.config.experimental.set_memory_growth(gpus[0], True)set_memory_growth(True)让显存按需增长而不是一开始就占用全部显存这样和其他程序共存时不容易崩。这一点在很多教程里都不会提但实训室里一台机器多人用的情况是救命的。5.2 现象Loss一开始正常某几个epoch后变成NaN原因学习率太大导致梯度爆炸或者数值不稳定的标签问题比如label_modecategorical却使用了sparse_categorical_crossentropy标签维度错误在反向传播时产生异常梯。更隐蔽的原因是数据增强里的RandomZoom(0.1)如果配合某些插值算法可能把像素值推到超出[0,1]范围模型输入不再归一化数值震荡。解决先检查模型输出层和loss是否匹配再把learning_rate降到0.0001最后确认数据流水线里没有自己加的归一化层和增强层冲突。如果数据增强引入异常可以去掉RandomZoom只保留RandomFlip再试。修复后加一个早停callback如果loss在验证集上连续3轮都是NaN直接终止训练避免浪费一晚上。5.3 现象训练集准确率98%验证集只有70%原因典型的过拟合模型记住了训练集图片的纹理、背景、甚至EXIF信息没有学到花卉的通用特征。常见触发点数据增强力度不够、模型参数量过大、训练轮数太多。解决先增加增强强度RandomFlip加RandomRotation(0.1)再加RandomContrast(0.1)让背景和光影变化成为干扰然后把Dropout从0.2提高到0.5如果还不行就用迁移学习的手写CNN替换全连接层或者换用更小的模型。我一般会先看训练曲线训练准确率一直升高、验证准确率升到某个点后掉头向下基本就是过拟合早停后的模型权重已经是最好状态但数据增强还是太弱需要重新调参后再训练。5.4 现象代码运行时报“Failed to find a matching index for file”或者路径找不到原因数据集路径里有中文或空格或者用了OneDrive、Dropbox这类同步文件夹文件被占锁或者路径变成超链接。TensorFlow 2.3在Windows下对中文路径支持很差文件名含中文时image_dataset_from_directory会直接读不到。解决把整个项目放到纯英文路径下比如D:\flower_project\flower_data文件名也全部改成小写英文字母和下划线如果必须用中文名可以在代码里用tf.io.gfile.glob自定义文件列表但代价是要自己写标签映射。期末机房通常有还原系统提前确认项目路径不要放在桌面或文档这种同步目录里。5.5 现象模型加载后预测结果全部是某一类或者预测出来的类名和标签对不上原因加载模型时类名顺序不一致。image_dataset_from_directory的类名顺序是文件夹名的字母排序和你训练后打印的class_names一样但如果你在另一个脚本里单独构建了Dataset类名顺序可能变了模型输出索引和真实类名就错位了。解决训练完把class_names保存成文本文件with open(class_names.txt, w) as f: for name in train_ds.class_names: f.write(name \n)预测时读取这个文件而不是重新猜测with open(class_names.txt) as f: class_names [line.strip() for line in f]另外加载模型后先用一张训练集中的图片自测一下确认输出和原标签一致再拿出去演示。这个小动作能阻止90%的现场翻车。6. 把系统做得像样用OpenCV摄像头识别和批量Top-5输出6.1 摄像头实时识别脚本让答辩演示从“PPT模型”变成“活系统”期末答辩现场最常见的演示是把一张测试图拖进程序然后回车出结果。如果你想更出彩可以加一个摄像头实时识别拿手机或笔记本摄像头对着花实时显示类别和置信度。这里用OpenCV读取摄像头帧再做预处理传给模型import cv2 import tensorflow as tf model tf.keras.models.load_model(final_model.h5) class_names [line.strip() for line in open(class_names.txt)] cap cv2.VideoCapture(0) while True: ret, frame cap.read() if not ret: break img cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img cv2.resize(img, (224, 224)) img_array tf.expand_dims(img.astype(float32) / 255.0, 0) preds model.predict(img_array, verbose0)[0] idx tf.argmax(preds).numpy() label f{class_names[idx]} {preds[idx]*100:.1f}% cv2.putText(frame, label, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2) cv2.imshow(Flower Recognition, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这里注意推理预处理TensorFlow 2.3的image_dataset_from_directory会自动把图片归一化到[0,1]但OpenCV读出来是0-255的整数所以手动除以255.0。如果你在模型层里加了Rescaling层则不需要再除255直接把原始像素传到模型里即可。我习惯在自己的代码里保持“数据读取和预处理逻辑一致”这个原则训练时怎么喂预测时就怎么喂。摄像头帧率不需要太高predict通常几十毫秒一次足够应付答辩演示了。6.2 批量测试与Top-5输出用一张照片的置信度分布说服评委除了“认出来是哪类”还要能解释“为什么敢说这是玫瑰”。一个实用技巧是输出Top-5置信度让评委看到模型并没有在瞎猜import os import numpy as np import tensorflow as tf model tf.keras.models.load_model(final_model.h5) class_names [line.strip() for line in open(class_names.txt)] for img_name in os.listdir(test_images): if not img_name.lower().endswith((.jpg, .jpeg, .png)): continue img tf.keras.preprocessing.image.load_img( os.path.join(test_images, img_name), target_size(224, 224) ) arr tf.keras.preprocessing.image.img_to_array(img) preds model.predict(tf.expand_dims(arr, 0), verbose0)[0] top5_idx np.argsort(preds)[::-1][:5] print(img_name) for i in top5_idx: print(f {class_names[i]}: {preds[i]*100:.2f}%)np.argsort(preds)[::-1]把概率从高到低排序取前5个类名。如果Top-1置信度不高比如60%但Top-2是另一种相似花说明模型对这类照片没有十足把握演示时你可以说“这是因为这张图的拍摄角度偏了花瓣纹理不清晰模型给出了一组候选”。这个说法比强行报“95%”要诚实老师也不会继续追问。我现在的习惯是所有原型demo都默认带一个test_images文件夹里面放几张没参与训练的网络图片每次跑完训练就在里面批量验证一遍把结果保存为txt再截图放进报告。这比只贴一条model.evaluate准确率更能说明系统的鲁棒性。做期末大作业最怕的不是模型不收敛而是演示时拿不出一个“活”的东西。摄像头脚本和Top-5输出这两个小功能加起来不超过100行却能让你的系统从“能跑”变成“能用”。希望这份笔记能帮到你从今天开始动手把数据、训练、避坑、演示串成一条完整的流水线。本文还有配套的精品资源点击获取
返回列表