十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

TensorFlow全连接网络八股流程:MNIST与Fashion-MNIST实战详解

TensorFlow全连接网络八股流程:MNIST与Fashion-MNIST实战详解 这段时间有不少朋友问我学 TensorFlow 应该从哪开始我每次的答案都一样——先把 MNIST 和 Fashion-MNIST 用全连接网络完整跑一遍。网上讲这两个数据集的教程一抓一大把但大多要么只贴一段能跑的代码要么一上来就讲卷积、残差、注意力把初学者直接劝退。这篇笔记不一样我想从“神经网络八股”的角度把一套固定的搭模型流程拆开揉碎讲清楚加载数据、预处理、建模型、编译、训练、评估、预测每一步怎么来为什么这么来哪些地方容易踩坑。老实说我当时刚刚接触这个领域的时候对“八股”两个字挺排斥的总觉得写代码不应该被条条框框限制。等到实际写了几个项目才明白所谓八股其实是官方教程和社区沉淀下来的一套稳定的、可以直接复用的最佳实践尤其对于新手来说先照着标准流程走通一遍比埋头造轮子重要得多。这套流程适合谁适合刚学完 Python 基础、想入门深度学习但不知道从哪个项目下手的人也适合已经在用 PyTorch 但想快速体验 TensorFlow 的开发者。不需要你有 GPU纯 CPU 也能跑只是慢一点而已。我会把两个数据集分开讲因为它们看起来长得像实际训起来差别不小。文章里出现的代码我都用 TensorFlow 2.x 写过和验证过你可以直接复制到 Jupyter Notebook 里逐段执行。1. 先搞清楚“神经网络八股”到底在说哪几块1.1 为什么叫“八股”古代科举写文章有固定格式叫八股文。深度学习中神经网络项目的代码组织也逐渐形成了一套几乎固定的套路被不少人戏称为“神经网络八股”。这不是贬义恰恰说明这套流程经过大量实践检验已经足够稳定和通用。在你对网络结构设计、训练技巧还不够熟悉的时候先沿用这套固定流程能把注意力集中在更核心的问题上比如数据怎么处理、网络该怎么调。TensorFlow/Keras 出现之后这套八股被进一步简化了。一个最典型的分类任务代码骨架是这样的导入模块、读取数据集、预处理、定义模型结构、调用 compile 指定优化器和损失函数、调用 fit 训练模型、调用 evaluate 或 predict 验证结果。就这么几件事几乎覆盖了 80% 的入门级任务。你把这套流程搞明白后面再学卷积、循环、Transformer也只是在“模型结构”这一栏里换东西其他环节依然是同一套骨架。1.2 两个数据集的定位MNIST 与 Fashion-MNISTMNIST 是手写数字识别数据集6 万张训练图片、1 万张测试图片每张都是 28×28 的灰度图内容是从 0 到 9 的单个手写数字。它太经典了经典到很多框架的官方文档都用它当第一个案例。Fashion-MNIST 是后来推出的替代数据集图像尺寸、样本数量、类别数量跟 MNIST 完全一样但内容换成了 10 类服装物品T 恤、裤子、套头衫、连衣裙、外套、凉鞋、衬衫、运动鞋、包、短靴。很多人把 Fashion-MNIST 口语化成“衣裤识别分类”严格来说不太准确它的类别远不止“衣”和“裤”只是其中两类而已。但标题里这么说也无可厚非毕竟在非专业场景下大家一看这个说法就知道是针对服装图像的分类任务。需要特别强调的是Fashion-MNIST 的难度明显高于 MNIST。手写数字的笔画结构差异很大模型很容易抓住关键特征而服装图像里T 恤和衬衫、外套和连衣裙之间的界限有时候连人眼都容易看错所以它更适合用来检验一个模型真正学到了什么而不是靠数据集本身简单而显得“效果很好”。2. 环境准备TensorFlow 版本、硬件与安装那些容易翻车的细节2.1 安装命令与版本选择我建议直接安装 TensorFlow 2.x 的最新稳定版。以 2024 年底到 2025 年这段时间为例稳定版本已经到 2.18、2.19 了。安装命令很简单pip install tensorflow如果是在国内网络环境下pip 默认源偶尔会很慢建议临时换一个镜像源pip install tensorflow -i https://pypi.tuna.tsinghua.edu.cn/simple有 NVIDIA 显卡的话可以安装 GPU 版本但 TensorFlow 2.x 里 CPU 版和 GPU 版的 pip 包已经不再分开了直接pip install tensorflow之后只要 CUDA、cuDNN 环境匹配TensorFlow 会自动调用 GPU。不过 GPU 相关的环境配置很容易翻车初学者如果暂时没有条件先用 CPU 跑这两个数据集完全没问题。我这个项目就是在普通笔记本的 CPU 上完成的一个 epoch 也就是几十秒到一两分钟完全等得起。2.2 验证环境是否装好装完以后别急着写代码先在命令行或者 Notebook 里验证一下import tensorflow as tf print(tf.__version__) print(tf.config.list_physical_devices(GPU))第一条命令会打印版本号第二条命令会列出可用的 GPU 设备。如果返回的是空列表说明目前跑的是 CPU 版本如果能看到类似physical_device_desc: device: 0, name: NVIDIA GeForce ...这样的输出说明 GPU 已经被识别到了。实际用的过程中TensorFlow 会在控制台打印一大堆莫名其妙的日志建议在导入之前加两行代码把日志级别调低import os os.environ[TF_CPP_MIN_LOG_LEVEL] 2这样能过滤掉大部分 INFO 和 WARNING。之后为了让实验结果可以复现我通常会在代码最前面固定随机种子import numpy as np import random as python_random python_random.seed(42) np.random.seed(42) tf.random.set_seed(42)这个细节很关键尤其是在后面调参的时候如果每次运行结果都不一样你很难判断准确率的提升到底来自你的改动还是运气。2.3 安装过程中的几个常见问题Windows 缺少 VC 运行库在 Windows 上如果导入 TensorFlow 时报错找不到msvcp140.dll或类似文件去微软官网装一个 Visual C Redistributable 即可。Python 版本太新或太旧TensorFlow 2.18 对 Python 3.9 到 3.12 支持比较好如果用的是 Python 3.13某些版本会出现兼容性问题。Anaconda 环境冲突老编码习惯不太好的人会直接在 base 环境里安装很容易把已有的 NumPy、Pandas 版本搞坏。建议新建一个独立环境比如conda create -n tf python3.11然后在这个环境里安装。3. 数据准备加载、形状、归一化与 one-hot3.1 用 Keras 自带接口加载数据TensorFlow 的 Keras 模块把 MNIST 和 Fashion-MNIST 都封装好了两行代码就能加载from tensorflow.keras import datasets # 加载 MNIST (x_train, y_train), (x_test, y_test) datasets.mnist.load_data() # 加载 Fashion-MNIST用这一行替换上面就行 # (x_train, y_train), (x_test, y_test) datasets.fashion_mnist.load_data()第一次运行的时候代码会自动把数据压缩包下载到~/.keras/datasets/目录。下载过程偶尔会很慢如果等太久可以直接从网上下载对应的mnist.npz或fashion-mnist.npz文件手动放到那个缓存目录下面再重新执行加载代码。加载之后的x_train形状是(60000, 28, 28)x_test形状是(10000, 28, 28)里面的每个元素是 0 到 255 之间的整数表示灰度值。y_train和y_test是一维数组存放 0 到 9 的类别标签。3.2 归一化不是可选项而是必选项我会在拿到数据之后立刻做归一化x_train x_train.astype(float32) / 255.0 x_test x_test.astype(float32) / 255.0为什么必须归一化因为后续的网络层计算中输入值和权重做矩阵乘法如果输入范围是 0~255经过累加之后数值会比较大梯度下降算法在这种尺度下收敛很慢甚至可能因为梯度爆炸出现 NaN 的 loss。把所有像素压缩到 0~1 之间相当于把不同特征的尺度拉齐梯度更新过程会平稳很多。3.3 标签要不要 one-hot这是新手特别容易困惑的一个点。很多旧教程会把标签转成 one-hot 编码也就是把标签 3 变成[0,0,0,1,0,0,0,0,0,0]。这么做的原因是为了配合categorical_crossentropy这个损失函数。但实际上TensorFlow/Keras 提供了一个更省事的接口叫sparse_categorical_crossentropy可以之间接收整数标签不需要额外转换。也就是说标签保持整数用losssparse_categorical_crossentropy标签转 one-hot用losscategorical_crossentropy两种方式效果完全等价。既然使用sparse可以少写一行代码后面我都默认使用整数标签版本。3.4 MNIST 与 Fashion-MNIST 差异对比下面这张表能帮你直观感受两个数据集的差别对比项MNISTFashion-MNIST图像尺寸28×28 灰度28×28 灰度训练集规模6000060000测试集规模1000010000类别数1010类别内容手写数字 0-9T恤、裤子、套头衫、连衣裙、外套、凉鞋、衬衫、运动鞋、包、短靴类间差异较大笔画清晰较小部分类别边界模糊全连接网络水平约 97%~98%约 88%~90%Fashion-MNIST 的存在意义就是给“MNIST 太简单、模型容易过拟合却不自知”的问题打补丁。你在 MNIST 上随便搭个两层全连接验证准确率可能就 97% 了容易产生一种“我已经懂深度学习”的错觉。把同样的模型搬到 Fashion-MNIST 上准确率会掉到 90% 以下这个时候你才真正开始体会什么叫调参、什么叫过拟合。4. 搭建全连接网络的核心代码套路4.1 Sequential 模型与 Dense 层用 Keras 搭全连接网络推荐直接使用Sequential。这个名字本身很形象一层接一层按顺序往下排。这是最简单也最不容易出错的模型容器。核心代码长这样from tensorflow.keras import layers, models model models.Sequential([ layers.Flatten(input_shape(28, 28)), layers.Dense(128, activationrelu), layers.Dense(10, activationsoftmax) ])先说Flatten。前面的数据形状是(28, 28)的二维矩阵但全连接层的输入要求是一维向量Flatten的作用就是把这 784 个像素值按顺序拉平变成一个长度为 784 的向量。这一步几乎没有任何计算量只是为了调整数据形状。有的教程喜欢在数据预处理阶段reshape(-1, 784)效果一样但结构上不如Flatten直观。接着是两个Dense层。Dense(128, activationrelu)表示一个有 128 个神经元的全连接层每个神经元接收上一层的全部 784 个输出做一次线性变换后过 ReLU 激活函数。Dense(10, activationsoftmax)是输出层有 10 个神经元对应 10 个类别最后通过 softmax 变成 10 个概率值哪个位置的概率最大模型就认为图片属于哪个类。4.2 中间层的节点数为什么选 128用 128 而不是 64 或 256没有严格的数学依据更多是一个经验取值。784 维的输入压缩到 128 维再映射到 10 维这个信息瓶颈设置得比较适中。如果你把中间层改成 32模型表达能力会下降准确率大概率变差改成 512准确率可能小幅提升但计算量和参数量会明显增加而且在小数据集上容易过拟合。我建议就把 128 作为默认值等整条流程跑通了再回头调这个数字对比效果。要真正理解这个参数的影响最好看一眼model.summary()的输出model.summary()它会打印每一层的输出形状和参数量。以这个模型为例第一层 Dense 的参数量是 784×128 128 100480其中 784×128 是权重矩阵128 是偏置向量。第二层 Dense 的参数量是 128×10 10 1290。整个模型的参数量约 10 万。这个数字对深度学习来说非常小所以训练起来非常快。4.3 激活函数与 bias 的作用很多初学者会问神经网络里的 biases 到底是什么其实它就是线性变换y Wx b里的那个b。如果只有Wx那么无论网络怎么堆层决策边界都只能过原点表达能力会弱很多。b的存在让神经元可以在输入特征全为 0 的时候依然有非零输出相当于给模型多了一个可学习的偏移量。在 Keras 里Dense 层默认就会自动添加 bias不需要手动设置。隐藏层用 ReLU输出层用 softmax这是八股里约定俗成的黄金组合。ReLU 的计算方式是max(0, x)小于 0 的部分直接清零大于 0 的部分保持不变。它比传统的 sigmoid 好在两点计算简单求导也简单而且能有效缓解深层网络中的梯度消失问题。softmax 则是一个归一化指数函数它把 10 个原始得分转换成 10 个非负且和为 1 的概率值。因为每个样本只能属于一个类别所以输出层用 softmax 天然契合多分类任务。损失函数选择sparse_categorical_crossentropy也有讲究。交叉熵衡量的是模型预测概率分布与真实标签分布之间的距离预测越离谱loss 越大梯度更新方向也就越明确。相比之下回归任务常用的均方误差 MSE 在分类任务上收敛慢并不适合。5. 训练环节compile、fit、验证集与日志解读5.1 compile给模型配齐损失函数、优化器和指标模型结构定义好之后先不急着训练需要调用compile把训练三要素配置好优化器、损失函数、评估指标。这是我的标准写法model.compile(optimizeradam, losssparse_categorical_crossentropy, metrics[accuracy])optimizeradam是当前最常用的优化器。Adam 是一种自适应学习率算法它会根据每个参数的历史梯度动态调整学习率所以对大范围任务都适用几乎不需要手动调节学习率。如果你想试试最原始的随机梯度下降可以改成optimizersgd但通常会发现收敛速度慢不少。第一次跑八股流程直接用 Adam 就行。metrics[accuracy]表示在训练和验证过程中除了计算 loss还要计算分类准确率。准确率是根据预测概率取最大类别后与真实标签比较得到的百分比直观易懂非常适合作为监控指标。5.2 fit喂数据、定迭代次数编译完成之后调用fit开始训练history model.fit(x_train, y_train, batch_size32, epochs10, validation_split0.2)这里解释一下三个最关键的参数。batch_size32表示每次从训练集中随机抽取 32 张图片做一次梯度计算。为什么不一次性把所有 6 万张图都算完再更新梯度因为计算量太大内存也扛不住而且全量梯度下降容易陷入局部最优。每次取一小批数据计算梯度虽然方向有噪声但更新速度快整体收敛反而更好。32 是目前最常用的默认值显卡显存不够就调到 16显存充足也可以试 64、128。epochs10表示把整个训练集完整过 10 遍。MNIST 很简单10 轮足够看到明显效果如果想追求更高准确率可以增加到 20 甚至 30 轮。但注意轮数不是越多越好后半程训练集 loss 可能继续下降验证集准确率却不升反降这就是过拟合的信号。validation_split0.2表示从训练集末尾拿出 20% 的数据作为验证集剩余 80% 用于训练。验证集在每一轮结束后都会被评估一次用于监控模型在没见过的数据上的表现。如果不想从训练集里切也可以直接把测试集作为验证集validation_data(x_test, y_test)。但更严谨的做法是留出验证集测试集最后再用形成三次数据集训练集、验证集、测试集。不过作为入门项目直接在fit里切一个验证集就够了。5.3 训练日志怎么看fit执行过程中每一轮会打印一行日志包含当前轮次、训练 loss、训练准确率、验证 loss、验证准确率。第一次跑出来的日志可能类似这样Epoch 1/10 1500/1500 [] - 3s 2ms/step - loss: 0.3421 - accuracy: 0.9045 - val_loss: 0.1886 - val_accuracy: 0.9456 Epoch 2/10 1500/1500 [] - 3s 2ms/step - loss: 0.1563 - accuracy: 0.9543 - val_loss: 0.1342 - val_accuracy: 0.9601第一轮的训练准确率能到 90%说明模型在两三层网络、纯 CPU 训练的情况下就已经具备了基本识别能力。随着 epoch 增加训练 loss 应该逐步下降训练准确率和验证准确率应该同步上升。到了第 10 轮左右训练准确率一般能到 98% 以上验证准确率在 97% 左右MNIST 这个任务基本就算跑通了。如果把history存了下来后续还可以画 loss 曲线和准确率曲线直观看到训练状态。这是非常实用的诊断手段import matplotlib.pyplot as plt plt.plot(history.history[loss], labeltrain_loss) plt.plot(history.history[val_loss], labelval_loss) plt.legend() plt.show()如果训练 loss 一路下降而验证 loss 在某个 epoch 之后开始回升恭喜你看到了教科书级的过拟合现象。这时候就可以考虑加 Dropout、加正则化、减小网络规模或者设置EarlyStopping回调。6. 推理预测与结果可视化从概率到眼见为实6.1 用 predict 和 argmax 拿到预测类别模型训练完之后要验证它的真实水平标准做法是调用evaluate在测试集上计算 loss 和准确率test_loss, test_acc model.evaluate(x_test, y_test, verbose0) print(ftest accuracy: {test_acc:.4f})evaluate和predict的区别在于evaluate需要提供真实标签计算预测值与标签之间的损失并给出指标predict则只负责拿输入图片推概率不关心标签。想看一下模型对具体某张图的判断用predict非常直观import numpy as np # 取前 10 张测试图片 sample_images x_test[:10] sample_labels y_test[:10] predictions model.predict(sample_images) predicted_classes np.argmax(predictions, axis1) for i in range(10): print(f真实标签: {sample_labels[i]}, 预测标签: {predicted_classes[i]}, 置信度: {np.max(predictions[i]):.4f})predictions的形状是(10, 10)每一行代表模型对一张图片在 10 个类别上的概率预测。np.argmax沿着 axis1 取最大值的位置得到的就是预测类别编号。6.2 把预测结果画出来光看数字不过瘾我习惯把测试集前几张图片原图、真实标签和预测标签一起画出来。用 matplotlib 就能快速实现class_names [T恤, 裤子, 套头衫, 连衣裙, 外套, 凉鞋, 衬衫, 运动鞋, 包, 短靴] plt.figure(figsize(10, 5)) for i in range(10): plt.subplot(2, 5, i 1) plt.imshow(x_test[i], cmapgray) plt.title(f真实:{class_names[y_test[i]]}\n预测:{class_names[predicted_classes[i]]}) plt.axis(off) plt.tight_layout() plt.show()如果要在 MNIST 上运行只需要把class_names换成数字字符串列表[0,1,2,3,4,5,6,7,8,9]。真正跑完这两套数据之后你会发现一个有意思的现象MNIST 上几乎每张图都预测得很准偶尔才有一两个错的Fashion-MNIST 上则很容易看到衬衫被预测成 T 恤、外套被预测成连衣裙这类错误。这不是模型弱而是类别之间的视觉差异本来就小。意识到这一点你对“模型准确率为什么提不上去”的理解会深刻很多。6.3 保存模型别让训练白跑训练好的模型如果不保存关掉 Notebook 之后一切归零。所以最后一步通常是把模型存下来之后加载复用model.save(mnist_model.h5) # 加载 from tensorflow.keras import models as km loaded_model km.load_model(mnist_model.h5)Keras 的save接口会把模型结构、权重、优化器状态全部打包保存。下次直接加载省去了重新训练的时间。7. 实测过程中的常见坑下载失败、API 变更、不收敛与过拟合7.1 数据自动下载失败怎么办load_data()第一次运行时会自动下载数据但如果网络环境不稳定很容易卡在下载阶段甚至报超时。我的建议是不要跟网络较劲直接手动下载对应的.npz文件放到~/.keras/datasets/目录下。TensorFlow 在加载时会首先检查缓存目录文件存在就直接读取。网上也有一些类似指南会提到“设代理”但在我自己的经验里最稳妥的方案就是换个稳定的网络环境或者手动下载文件绕开自动下载这一步。7.2 TF 2.x 的 API 变化很多人写的教程是基于 TensorFlow 1.x里面会有tf.Session()、tf.placeholder、tf.nn.softmax之类的陈旧写法。如果你照着敲在 2.x 环境里基本跑不通。现在写 TensorFlow 2.x 的代码只需要记住一个原则能用tf.keras的地方就尽量用tf.keras。比如tf.keras.layers.Dense、tf.keras.models.Sequential、tf.keras.datasets.mnist。不要在同一个项目里混用keras和tf.keras否则很容易出现版本不一致带来的诡异报错。如果你装了全新环境直接from tensorflow import keras就好。7.3 损失变成 NaN 或不收敛训练日志里如果出现loss: nan那基本可以确定是数值溢出。最常见的三个原因数据没有归一化、学习率过大、激活函数和输出层搭配不当。解决办法从简单到复杂检查归一化确保像素除以 255检查优化器默认参数如果手动设置了过大的学习率调回默认值实在不行把模型换成更简单的结构逐层排查。还有种情况是 loss 一直不降训练准确率像心电图一样乱跳。这大概率是batch_size选得太小或者学习率不合适。把batch_size调到 32 或 64通常能缓解。7.4 过拟合训练集好、验证集差在 MNIST 上全连接网络其实不太容易过拟合因为任务简单且数据量相对够。但 Fashion-MNIST 上出现过拟合的可能性大很多。我在实验时就见过训练准确率 97%验证准确率只有 89% 的情况。缓解手段很多入门阶段最有效的是加 Dropout 层model models.Sequential([ layers.Flatten(input_shape(28, 28)), layers.Dense(128, activationrelu), layers.Dropout(0.2), layers.Dense(10, activationsoftmax) ])Dropout 的作用是每次训练时随机让一部分神经元的输出置零强迫网络不依赖个别节点从而增强泛化能力。0.2表示 20% 的输出会被随机丢弃。这个值不是越大越好太大反而会欠拟合。另一个有效的做法是加 EarlyStopping。训练到验证集 loss 不再下降时自动停止省时间又防过拟合from tensorflow.keras.callbacks import EarlyStopping early_stop EarlyStopping(monitorval_loss, patience3, restore_best_weightsTrue) history model.fit(x_train, y_train, batch_size32, epochs50, validation_split0.2, callbacks[early_stop])就算设置 50 个 epoch因为早停机制的存在模型通常只跑十几轮就会停下来并恢复到验证集最优的那一轮权重。8. 从八股到活学活用换成卷积网络、调参与样本偏差的思考8.1 CNN 改造的入门方向全连接网络只是用来熟悉流程的起步工具它在图像任务上有个天然缺陷把二维图像拉平成向量之后像素之间的空间位置关系就丢失了。比如“笔画的左上角”和“笔画的右下角”原本有结构关系但拉平成一个 784 维向量后这些位置信息变成了一堆互不相干的坐标。这也是为什么在 Fashion-MNIST 上全连接网络的准确率始终上不了 95%。想把准确率再往上提一个台阶最简单的方式是换成卷积神经网络CNN。改造后的模型大概长这样model models.Sequential([ layers.Conv2D(32, (3, 3), activationrelu, input_shape(28, 28, 1)), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activationrelu), layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(128, activationrelu), layers.Dropout(0.2), layers.Dense(10, activationsoftmax) ])注意CNN 的输入维度是(高度, 宽度, 通道数)。灰度图只有一个通道所以需要把数据形状从(60000, 28, 28)变成(60000, 28, 28, 1)x_train_cnn x_train.reshape(-1, 28, 28, 1) x_test_cnn x_test.reshape(-1, 28, 28, 1)其他训练流程完全不用动。我自己跑下来CNN 在 MNIST 上可以轻松到 99% 以上在 Fashion-MNIST 上能到 92%~93%。提升幅度明显这也能让你直观感受到网络结构对性能的影响到底有多大。8.2 调参的优先级和方向如果你想把结果再往上刷优先调这几个方向中间层神经元数量、隐藏层数量、batch_size、Dropout 数值、学习率。一次只改一个变量记录准确率变化这是最标准的实验习惯。我在实验过程中发现Fashion-MNIST 上把隐藏层从一层加到两层准确率往往有小幅提升隐藏层节点从 128 调到 256提升不明显但训练时间几乎翻倍。这在学校练手阶段属于效率不高的改动。另外一个容易忽略的细节是模型最后预测时往往会把图片里的细纹理忽略掉。想验证这一点可以把测试集里预测错误的图片打印出来盯着看几秒。你会发现很多错误其实人眼也容易犯错比如衬衫和 T 恤、外套和连衣裙这说明模型已经学到了真实可用的特征不是瞎猜。8.3 框架选择的个人看法最近几年 PyTorch 在研究社区里的声量确实很大很多新的论文代码都用 PyTorch 实现包括最新的图神经网络、扩散模型等。但 TensorFlow 在工业部署和移动端推理方面仍然有一席之地比如 TensorFlow Lite、TensorFlow Serving生态非常成熟。2024 年来看选哪个框架更多取决于你周围团队的习惯和目标场景。但就入门来说我不建议在这上面纠结太久八股流程才是更值得吃透的东西。你把这套标准流程练熟了换成 PyTorch 也只需要学习 API 差异底层思路是共通的。根据我个人的经验把两个数据集、两套框架都完整跑一遍比迷信任何单个框架的“屠榜”技巧都有用。这篇笔记写到最后我还是想多说一句代码能跑通只是第一步真正有价值的动作是把两个数据集的训练日志并排放在一起去看那些数字背后的含义。MNIST 上随便搭的模型就能跑出很高准确率它适合让你建立自信Fashion-MNIST 才会逼着你思考模型为什么犯错、数据里有什么样的分布偏见、过拟合什么时候出现。把这些想明白了以后再见到任何新数据集你都知道该从哪下手也就能更从容地面对那套固定的八股流程了。
返回列表