ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

猫狗识别毕设实战:基于TensorFlow的CNN图像分类全流程解析

猫狗识别毕设实战:基于TensorFlow的CNN图像分类全流程解析 毕设选到“猫狗识别”这个题目很多人第一反应是网上找个代码直接跑。但真正动手才发现数据集下载慢、环境装不上、训练时报错、准确率上不去、到了答辩时候连卷积层为什么这样设计都说不清楚。这篇文章不打算只贴一段代码让你复制而是把从数据集准备、模型搭建、训练调参到预测验证的完整链路讲清楚。你会看到每一步为什么这么做遇到报错怎么排查以及答辩时老师最常问的几个点怎么回答。这篇文章更适合“想真正跑通并理解原理”的读者。如果你是零基础开始做毕设或者正准备用 TensorFlow CNN 完成图像二分类接下来这套方法可以直接用到你的项目里。1. 猫狗识别在毕设中的真实定位与常见坑猫狗识别是典型的图像二分类问题输入一张图片模型输出它是猫还是狗。毕设选这个题目有天然优势数据集成熟、任务直观、可视化效果好而且 CNN 在这个任务上的表现足够支撑一篇合格的本科论文。但它也有几个容易被低估的坑。第一个坑是数据集。很多人以为数据集拿到就能直接训练实际上 Kaggle 的 Dogs vs Cats 原始数据集需要科学下载而且下载下来是一堆散乱的 jpg没有划分训练集和验证集文件名还带着序号。如果直接拿去训练验证集和训练集会混在一起最终准确率虚高答辩时一被追问就露馅。正确做法是把图片按类别放入train/cat、train/dog、validation/cat、validation/dog这样的目录结构后面用ImageDataGenerator或image_dataset_from_directory读取时才会自动打标签。第二个坑是版本兼容。TensorFlow 的 API 更新很快tf.keras.preprocessing.image.ImageDataGenerator在新版本里已经标记为 deprecated而网上大量老教程还在用model.fit_generator()。如果你装的是 TensorFlow 2.18老代码大概率会报错或者出现一堆警告。解决办法是统一使用model.fit()以及优先使用flow_from_directory最新推荐的数据读取方式。第三个坑是训练时间。CNN 在 CPU 上跑会很慢很多人因为训练太慢直接放弃。后面会给出两种方案一是用 Google Colab 免费 GPU二是调整模型参数减少计算量让模型在普通笔记本上也能在合理时间内训练完。明确了这些坑后面的步骤你就知道每一步是在解决什么问题了。2. CNN 核心概念30分钟能听懂的原理CNN 的英文全称是 Convolutional Neural Network中文叫卷积神经网络。它专门用来处理图像这类网格状数据核心思路是让模型自动学习图像中不同层级的特征。2.1 为什么全连接网络不适合图像如果把一张 100x100 的彩色图片直接拉平会得到 30000 个像素值全连接层的每个神经元都要和这 30000 个值全连接参数量爆炸而且丢失了像素之间的空间关系。猫的耳朵在图片左上角、狗的眼睛在右上角这种“位置信息”对全连接网络来说完全感知不到。CNN 通过卷积操作保留图像的空间结构用滑动窗口的方式在整张图上提取局部特征。一个卷积核就像一个小放大镜每次只看图像的一个小区域然后移动到下一个区域。这个特点叫作“局部连接”和“参数共享”。2.2 卷积层、池化层、全连接层分别做什么一个典型的 CNN 分类模型由三类层堆叠而成**卷积层Conv2D**负责提取特征。每个卷积核会把一个小窗口内的像素做加权求和得到一个特征图。第一层卷积提取的是边缘、颜色等低级特征更深层的卷积会把低级特征组合成耳朵、眼睛、毛发纹理等高级特征。**池化层MaxPooling2D**负责压缩特征图尺寸。它把每个小区域内的最大值保留下来丢掉其他信息。这样做能减少计算量同时让模型对微小的位置变化不那么敏感。可以理解为我们只需要知道“这块区域有耳朵”不需要知道“耳朵具体偏了几像素”。**全连接层Dense**负责分类决策。经过多次卷积和池化后特征图被展平成一维向量然后经过若干全连接层最终用 Softmax 输出两个类别的概率。2.3 激活函数为什么重要卷积层和全连接层本质上是线性运算如果不加激活函数不管堆多少层模型表达能力都有限。ReLU 函数的表达式是f(x) max(0, x)计算简单、能缓解梯度消失问题是目前 CNN 的主流选择。最后一层分类用 Softmax它会输出“是猫的概率”和“是狗的概率”两者加起来等于 1。下面这张表可以帮助你快速记忆各层的作用层类型核心作用输出变化典型参数Conv2D提取局部特征通道数增加filters, kernel_size, activationMaxPooling2D压缩尺寸、保留主要特征宽高减半pool_sizeFlatten展平为一维向量变成 1D无Dense特征组合与分类输出类别数units, activation理解到这里后面写代码时就清楚每一行在干什么了。3. 环境准备TensorFlow 安装与版本兼容这是最容易让人崩溃的环节。不同 TensorFlow 版本在不同系统上的安装差异很大下面给出一个比较稳妥的安装方案。3.1 判断环境类型先确认你的操作系统和 Python 版本。打开命令行工具执行python --version pip --version然后确认是否已经安装了 TensorFlowpip show tensorflow如果输出版本号说明已经装过了如果提示WARNING: Package(s) not found说明需要安装。3.2 安装 TensorFlow 稳定版这里推荐的安装命令是pip install tensorflow这条命令会安装当前最新的稳定版。如果你需要指定版本可以这样写pip install tensorflow2.18需要注意TensorFlow 2.18 属于较新的版本。如果你的电脑是 Windows 且没有 NVIDIA 显卡建议直接安装 CPU 版默认的 tensorflow 包就包含 CPU 支持不需要额外安装 CUDA 和 cuDNN。如果你的显卡是 NVIDIA 且已经配置好 CUDA可以安装pip install tensorflow[and-cuda]这个选项会在安装 TensorFlow 的同时配置 GPU 运行所需环境。没有 NVIDIA 显卡也没有关系猫狗识别这个任务用 CPU 也能训练只是时间会长一些。安装完成后验证一下import tensorflow as tf print(tf.__version__) print(GPU Available:, tf.config.list_physical_devices(GPU))如果你是从零开始做毕设我建议直接使用 Google Colab。它自带 TensorFlow 环境还能免费使用 GPU省去本地环境配置的麻烦。打开 Google Colab 后在代码框执行import tensorflow as tf print(tf.__version__)Colab 会自动选择运行环境如果显示 GPU 不可用可以通过菜单“修改 - 笔记本设置 - 硬件加速器”里把硬件加速器切换为 GPU然后重启运行时。3.3 版本兼容提醒网上很多教程是基于 TensorFlow 2.4 或者 2.10 写的里面的部分 API 在 2.18 里已经变了。最典型的是这两个model.fit_generator()在 TensorFlow 2.3 之后不再推荐使用统一用model.fit()。tf.keras.preprocessing.image.ImageDataGenerator在 2.18 中会提示 deprecated建议用tf.keras.utils.image_dataset_from_directory。建议新项目直接使用image_dataset_from_directory读取数据它在性能和代码简洁性上都更好。但考虑到很多毕设参考资料还是基于ImageDataGenerator写的如果你网上下载的代码是这种写法改用model.fit()就能消除大部分报错。4. 猫狗数据集获取与预处理4.1 数据集来源猫狗识别最常用的数据集是 Kaggle 的 Dogs vs Cats 数据集包含 25000 张猫和狗的图片其中猫 12500 张狗 12500 张。获取方式有两种第一种从 Kaggle 官网下载https://www.kaggle.com/c/dogs-vs-cats/data下载前需要注册 Kaggle 账号并且接受竞赛规则。下载完成后会得到一个压缩包解压后有train和test1两个目录。第二种如果你不想注册 Kaggle可以从 Microsoft 官网下载早期公开的猫狗数据集https://www.microsoft.com/en-us/download/details.aspx?id54765这个数据集也是 25000 张文件名类似cat.1.jpg、dog.1.jpg。为了和 Kaggle 保持一致建议按照下面的方式重新组织目录。4.2 数据集目录结构不管从哪里下载最关键的一步是把数据整理成 Kerasimage_dataset_from_directory支持的目录结构dataset/ ├── train/ │ ├── cat/ │ │ ├── cat.1.jpg │ │ ├── cat.2.jpg │ │ └── ... │ └── dog/ │ ├── dog.1.jpg │ ├── dog.2.jpg │ └── ... └── validation/ ├── cat/ │ └── ... └── dog/ └── ...为什么要分成 train 和 validation因为我们需要在训练过程中不断评估模型在没见过的图片上的表现如果只用训练集模型“记住”了图片准确率再高也没有实际意义。验证集的作用是模拟“新图片”用来决定什么时候停止训练、模型有没有过拟合。建议从原始数据中每类取 1000 张作为训练集、100 张作为验证集。这样数据量适中在 CPU 上也能在几十分钟到两三个小时内完成训练。你可以使用下面的 Python 脚本来自动划分# 文件路径split_dataset.py import os import shutil import random # 原始数据集解压后的路径 source_dir downloads/train # 目标目录 target_dir dataset train_cat_dir os.path.join(target_dir, train, cat) train_dog_dir os.path.join(target_dir, train, dog) val_cat_dir os.path.join(target_dir, validation, cat) val_dog_dir os.path.join(target_dir, validation, dog) for d in [train_cat_dir, train_dog_dir, val_cat_dir, val_dog_dir]: os.makedirs(d, exist_okTrue) cat_files [f for f in os.listdir(source_dir) if f.startswith(cat)] dog_files [f for f in os.listdir(source_dir) if f.startswith(dog)] random.seed(42) random.shuffle(cat_files) random.shuffle(dog_files) # 每类取 1100 张1000 张训练100 张验证 for f in cat_files[:1000]: shutil.copy(os.path.join(source_dir, f), os.path.join(train_cat_dir, f)) for f in dog_files[:1000]: shutil.copy(os.path.join(source_dir, f), os.path.join(train_dog_dir, f)) for f in cat_files[1000:1100]: shutil.copy(os.path.join(source_dir, f), os.path.join(val_cat_dir, f)) for f in dog_files[1000:1100]: shutil.copy(os.path.join(source_dir, f), os.path.join(val_dog_dir, f)) print(数据集划分完成)执行python split_dataset.py4.3 图片读取和预处理使用image_dataset_from_directory读取数据# 文件路径data_loader.py import tensorflow as tf from tensorflow.keras.utils import image_dataset_from_directory IMG_SIZE (128, 128) BATCH_SIZE 32 train_ds image_dataset_from_directory( dataset/train, validation_split0.2, subsettraining, seed123, image_sizeIMG_SIZE, batch_sizeBATCH_SIZE, label_modebinary ) val_ds image_dataset_from_directory( dataset/validation, validation_split0.2, subsetvalidation, seed123, image_sizeIMG_SIZE, batch_sizeBATCH_SIZE, label_modebinary ) # 归一化到 [0, 1]提升训练稳定性 normalization_layer tf.keras.layers.Rescaling(1./255) train_ds train_ds.map(lambda x, y: (normalization_layer(x), y)) val_ds val_ds.map(lambda x, y: (normalization_layer(x), y)) for images, labels in train_ds.take(1): print(images.shape, labels.shape)这里有几个新手容易搞混的地方label_modebinary表示标签不是 One-Hot 编码而是 0 或 1最后一层只需要一个神经元 Sigmoid 激活函数。如果你的label_modecategorical最后一层就要改成两个神经元 Softmax。两种写法都能完成任务但不要混用。validation_split0.2的作用是从训练目录里自动抽 20% 作为验证集。这意味着你其实不需要手动创建 validation 目录只要训练目录足够大就行。不过手动分目录的方式更直观也方便控制数据量两者选择一种即可。执行完之后应该能看到Found 1600 files belonging to 2 classes. Found 400 files belonging to 2 classes.如果你的输出里只有 “Found 0 files”说明目录结构或路径有问题检查 dataset 目录下的子目录是否存在以及图片是否真的在对应目录中。5. CNN 模型构建与完整代码模型结构直接决定训练效果。我们使用一个经典的小型 CNN 结构三组卷积 池化然后展平、全连接、输出二分类概率。5.1 模型定义# 文件路径model.py import tensorflow as tf from tensorflow.keras import layers, models def build_cnn_model(): model models.Sequential([ # 第一组卷积块提取低级特征 layers.Conv2D(16, (3, 3), activationrelu, input_shape(128, 128, 3)), layers.MaxPooling2D(2, 2), # 第二组卷积块组合中级特征 layers.Conv2D(32, (3, 3), activationrelu), layers.MaxPooling2D(2, 2), # 第三组卷积块提取高级特征 layers.Conv2D(64, (3, 3), activationrelu), layers.MaxPooling2D(2, 2), # 展平后全连接输出二分类概率 layers.Flatten(), layers.Dense(128, activationrelu), layers.Dropout(0.5), layers.Dense(1, activationsigmoid) ]) return model model build_cnn_model() model.summary()这段代码定义了一个三层卷积的 CNN 模型。为什么使用 (3, 3) 卷积核因为 3x3 是目前应用最广的卷积核尺寸计算量小堆叠两层 3x3 的感受野相当于一层 5x5但参数量更少。为什么卷积核数量从 16 增加到 32、64因为浅层提取的是基础特征通道数不需要太多越往深层特征越抽象、越丰富通道数需要增加这样才能表达足够复杂的信息。为什么在全连接层后面加 Dropout(0.5)因为全连接层的参数量大很容易过拟合——也就是在训练集上准确率很高但测试集上明显下降。Dropout 会在训练时随机丢弃 50% 的神经元相当于每个 batch 都在训练一个稍有不同的网络能有效缓解过拟合。5.2 编译模型# 文件路径train.py model.compile( optimizeradam, lossbinary_crossentropy, metrics[accuracy] )因为label_modebinary且最后一层是 Sigmoid所以损失函数用binary_crossentropy二分类交叉熵。优化器选 Adam 是当前最稳妥的默认选择它自适应学习率不需要手动调整太多参数。如果你的标签是 One-Hot 编码并且最后一层用了 Softmax这里就需要改成categorical_crossentropy。5.3 数据增强直接训练 1000 张图容易过拟合因为模型看到的数据变化太少。数据增强可以在训练时对图片随机做旋转、翻转、缩放等变换相当于“凭空创造”更多训练样本。# 文件路径train.py from tensorflow.keras import layers data_augmentation tf.keras.Sequential([ layers.RandomFlip(horizontal), layers.RandomRotation(0.1), layers.RandomZoom(0.1), ]) train_ds train_ds.map(lambda x, y: (data_augmentation(x, trainingTrue), y))为什么要设计trainingTrue因为数据增强只在训练阶段使用验证和预测时不做任何随机变换。如果验证时也做增强验证集结果就没有参考价值了。6. 模型训练与评估训练是整个流程中最花时间的一步也是最容易出问题的一步。6.1 开始训练# 文件路径train.py from tensorflow.keras.callbacks import EarlyStopping history model.fit( train_ds, validation_dataval_ds, epochs30, callbacks[EarlyStopping(patience3, restore_best_weightsTrue)] )加了EarlyStopping会在验证集准确率连续 3 个 epoch 不再提升时自动停止训练并恢复验证集表现最好的那组权重。这样既省时间又能避免训练后期过拟合。在 Colab 的 GPU 环境下上面这套配置128x1281000 张训练图大概 5 到 10 分钟就能训练完。在 CPU 环境下可能需要 30 到 60 分钟视电脑配置而定。如果训练时间太长可以把IMG_SIZE改为(64, 64)全部代码中的input_shape也要同步改为(64, 64, 3)准确率会有小幅下降但速度会明显提升。6.2 查看训练效果训练完成后用 Matplotlib 画出准确率和损失曲线# 文件路径plot_history.py import matplotlib.pyplot as plt def plot_history(history): acc history.history[accuracy] val_acc history.history[val_accuracy] loss history.history[loss] val_loss history.history[val_loss] epochs_range range(1, len(acc) 1) plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.plot(epochs_range, acc, labelTraining Accuracy) plt.plot(epochs_range, val_acc, labelValidation Accuracy) plt.legend() plt.title(Training and Validation Accuracy) plt.subplot(1, 2, 2) plt.plot(epochs_range, loss, labelTraining Loss) plt.plot(epochs_range, val_loss, labelValidation Loss) plt.legend() plt.title(Training and Validation Loss) plt.savefig(training_history.png) plt.show() plot_history(history)如何判断模型是否正常看两条曲线如果训练准确率和验证准确率都在上升说明模型在正常学习。如果训练准确率接近 1.0但验证准确率停滞在 70% 左右说明过拟合了需要增加 Dropout、数据增强或者减少模型参数量。如果训练准确率和验证准确率都很低比如 50% 左右说明模型没有学到有效特征可能是学习率不合适或者数据有问题标签打错了。在猫狗识别这个任务上用本文的模型结构加上数据增强验证准确率达到 85% 到 92% 是比较正常的水平。如果数据集很小几百张图准确率可能只能到 80% 左右这属于正常现象不用焦虑。6.3 保存模型训练结束后保存模型后面预测时直接加载model.save(cat_dog_classifier.h5)这个文件包含了模型结构和权重预测时不需要再重新构建网络。7. 单张图片预测实战训练完成后最后一步是拿一张新图片做预测。这是毕设最核心的演示环节也是答辩时一定要展示的功能。7.1 加载模型进行预测# 文件路径predict.py import tensorflow as tf import numpy as np from tensorflow.keras.preprocessing import image model tf.keras.models.load_model(cat_dog_classifier.h5) def predict_image(img_path): img image.load_img(img_path, target_size(128, 128)) img_array image.img_to_array(img) img_array np.expand_dims(img_array, axis0) img_array img_array / 255.0 pred model.predict(img_array, verbose0)[0][0] if pred 0.5: label 狗 confidence pred else: label 猫 confidence 1 - pred print(f图片: {img_path}) print(f预测结果: {label}) print(f置信度: {confidence:.2%}) return label, confidence predict_image(test_imgs/cat_test.jpg) predict_image(test_imgs/dog_test.jpg)注意预测时做了两个关键操作一是target_size(128, 128)和训练时的图片尺寸保持一致。如果训练用 128x128预测就必须用 128x128否则输入尺寸不匹配会直接报错。二是img_array / 255.0把像素值归一化到 0 到 1 之间因为模型是在归一化后的数据上训练的。如果遗漏这一步预测结果会非常差而且往往完全看不出原因。7.2 输出结果解释如果输出结果是图片: test_imgs/cat_test.jpg 预测结果: 猫 置信度: 96.50%说明模型成功识别出了图片中的动物。这里pred 0.5的判断方式是二分类 Sigmoid 的标准用法。如果模型输出的值是 0.8说明模型有 80% 的把握认为是狗如果输出 0.2说明模型有 80% 的把握认为是猫。8. 猫狗识别常见问题与排查方法模型跑不起来、准确率上不去、报错看不懂这三个问题是毕设过程中出现频率最高的。我把常见问题整理成一张表建议收藏备用。问题现象可能原因排查方式解决方案训练时报FileNotFoundError数据路径不对或目录结构不规范打印当前路径检查train/cat目录是否存在重新按第 4.2 节的目录结构整理数据集训练时报InvalidArgumentError: logits and labels must have the same shape标签模式和输出层不匹配检查label_mode和Dense层参数label_modebinary时最后一层使用Dense(1, activationsigmoid)model.fit_generator报错或提示 deprecatedTensorFlow 版本太高pip show tensorflow查看版本改用model.fit()删除steps_per_epoch等旧参数验证准确率低只有 50% 左右图片未归一化、标签错乱、模型结构有误检查数据加载代码是否做了1/255增加Rescaling(1./255)或在 map 中除以 255训练和验证准确率都高但预测新图准确率低预测时预处理步骤和训练不一致对比训练时IMG_SIZE和Rescaling预测时使用相同的图片尺寸和归一化方式训练速度特别慢使用了 CPU 且图片尺寸大、卷积核多查看任务管理器 CPU 占用率改用 Colab GPU或把IMG_SIZE缩小到(64, 64)减少卷积核数量内存不足 OOMBatch size 过大或图片尺寸过大查看错误日志是否为ResourceExhaustedError调小BATCH_SIZE如从 32 改到 16 或 89. 猫狗识别实战最佳实践与答辩建议9.1 工程层面的最佳实践从工程角度有几个实操经验很值得在项目中使用。第一固定随机种子。数据增强和数据划分都有随机性为了让实验结果可复现在代码开头加上import random import numpy as np import tensorflow as tf random.seed(42) np.random.seed(42) tf.random.set_seed(42)这样每次训练的结果不会相差太大论文里的实验数据也更可信。第二训练过程中把中间结果保存下来。除了保存最终的cat_dog_classifier.h5建议再保存一份带时间戳的备份model.save(fcat_dog_classifier_{epochs}_epochs.h5)这样如果后期想复现某个实验不至于把之前的结果覆盖掉。第三日志输出要规范。训练结束后把最终准确率打印出来方便论文里直接引用loss, acc model.evaluate(val_ds, verbose0) print(f验证集损失: {loss:.4f}) print(f验证集准确率: {acc:.4f})9.2 答辩时老师常问的问题这个项目做完了并不是终点答辩时老师大概率会针对几个点追问问题一为什么用卷积神经网络不用其他模型可以这样回答全连接网络直接处理图片会造成参数过多并丢失空间信息CNN 通过局部连接、权值共享和池化操作能够以更少的参数自动提取图像特征与循环神经网络相比图像不存在明显的序列时序依赖CNN 在图像特征提取上更高效。近年来的 Vision Transformer 在图像领域也很强但它的训练需要更大规模的数据在中小数据集的猫狗识别任务上CNN 的性价比更高。问题二准确率达到多少算合格需要结合数据集规模说明。数据量少、模型简单准确率 80% 是正常水平数据量大、调优充分90% 以上已经很好。如果准确率接近 100%反倒要怀疑数据泄露或者过拟合。建议在论文中展示训练集和验证集的曲线图让老师看到你已经分析了过拟合问题。问题三如果让你继续改进你会怎么做常见思路有四种使用迁移学习把 VGG16、ResNet50 预训练模型的权重作为初始权重只训练最后几层可以显著提升准确率和训练速度增加数据增强策略比如随机亮度、对比度、剪切变换使用 BatchNormalization 层加速收敛采用 K 折交叉验证获得更稳定的评估结果。问题四为什么最后一层用 Sigmoid 而不是 Softmax二分类问题有两种等价写法一种是用一个神经元加 Sigmoid输出 0 到 1 之间的概率大于 0.5 判为正类另一种是用两个神经元加 Softmax输出两个类别的概率分布。两种写法效果基本一致但 Sigmoid binary_crossentropy在二分类场景下更简洁算是分类问题的业界常见做法。9.3 如果你的 GPU 不可用如果调试环境没有 GPU建议优先使用 Google Colab 的免费 GPU。进入 Colab 后通过菜单“修改 - 笔记本设置 - 硬件加速器”选择 GPU然后验证import tensorflow as tf print(tf.config.list_physical_devices(GPU))输出里出现GPU设备信息后就可以直接运行上面的训练代码。需要注意的是Colab 免费版在长时间闲置后可能会断开建议把model.save()写进训练脚本边训练边保存避免白跑。10. 后续进阶方向如果你已经跑通了猫狗识别接下来有几个值得深入的方向。第一个方向是迁移学习。使用 TensorFlow Hub 加载 MobileNetV2 或 EfficientNet 的预训练模型替换掉自己训练的卷积层。代码量不大准确率却往往更高而且训练速度更快是论文里很常见的实验对比方案。第二个方向是分类扩展到多分类。把猫狗二分类扩展到猫、狗、鸟、兔子四分类需要修改数据集目录结构、最后一层神经元数量和损失函数。这个改动能帮你更好地理解 CNN 模型的“可扩展性”。第三个方向是可视化卷积层。把卷积层输出的特征图可视化看看模型到底学到了什么。这一步做出来后论文里可以截图展示答辩会增加不少说服力。第四个方向是探索 Vision TransformerViT。从 ChatGPT、大语言模型到 CV 领域的 Transformer 化图像分类现在已经不是 CNN 一家独大。但理解 CNN 仍然是掌握这些新模型的基础因为卷积的特征提取思想对很多后续模型仍然有借鉴意义。跑通 CNN 之后再去看 ViT、Attention 机制会有一种豁然开朗的感觉。猫狗识别这个题目本身不复杂但它串起了数据预处理、模型设计、训练调参、预测部署的完整流程。把这个流程跑通你收获的不仅是一个能用的模型还有一套处理图像分类问题的方法论。这套方法论放到其他分类任务上换套数据、调一下参数就能复用到新场景。如果你能看到这里说明你已经准备好动手了。下一步建议不要急着改代码先按文章顺序把环境装好、数据集整理好把第 5 节的模型训练代码完整跑一遍然后再逐步调整参数观察准确率的变化。跑通一次完整流程比反复看一百篇文章都管用。
返回列表