手写数字识别网

写一个数字,看两层卷积、两层池化怎么一层层把它变成答案

此刻
从左到右:输入 → 卷积 1 → 池化 1 → 卷积 2 → 池化 2 → 全连接 → 输出。颜色越深,那一格越活跃。灰线是真实连接:卷积每格只连上一层一小块,全连接 256 格全连 32 个节点、32 连 10左键拖动旋转,右键拖动或按住 Shift 拖动平移,滚轮缩放;触屏单指转、双指移和捏合;方向键平移,0 复位鼠标移到任何一张图上,看那个点连着上一层的哪一小块

怎么做

  1. 卷积:小窗口找花纹8 个 5×5 的小窗口各自滑过输入,得到 8 张「哪里有这种花纹」的图
  2. 池化:缩小一半,只留最亮的2×2 里取最大,位置稍微挪一点也不怕
  3. 再卷积、再池化,最后全连接投票第二层卷积把第一层的 8 张图合起来看更大的花纹;最后 256 个数投票给 10 个数字

会骗你

  • 它只见过居中的、白底黑字的手写体写到角落、写得太小,或者画个别的东西,它照样给你一个数字和一个把握
  • 把握高不等于对画一个 7 和 1 之间的东西,它可能 90% 把握地认错;把握只是它自己的感觉
  • 每个点只看一小块鼠标移上去就知道:任何一格只连着上一层 5×5 那一小块,整体是一层层拼出来的

卷积找花纹、池化缩小、全连接投票;每一格只看上一层的一小块,答案是一层层拼出来的,把握高不等于对。

文字版:手写数字识别网在做什么

这一页你可以直接用鼠标写一个数字,看一个小型卷积网络怎样一层层把它认出来:输入 → 卷积 → 池化 → 卷积 → 池化 → 全连接 → 十个数字的得分。模型是用 PyTorch 真实训练出来的,页面加载时会自动和原始输出对账。

画面上正在发生什么

第一层卷积用 8 个 5×5 的小窗口各自滑过你写的数字,得到 8 张「哪里有这种花纹」的图——有的对横线敏感,有的对某个方向的笔画敏感。池化层在每个 2×2 的小块里只留最亮的那个,图缩小一半,好处是你的笔画稍微挪动一点,结果也不会变。

把鼠标移到任何一张图上,会画出它连着上一层的哪一小块。这一点很重要:卷积层里每一格只看上一层的一小块,不是全看。最后 256 个数全连到 32 个节点、再连到 10 个输出,黄线标出的是这次判断中投票最重的路径。

什么时候它会骗你

  • 它只见过居中、白底黑字的手写体。把数字写到角落、写得特别小,或者干脆画个别的东西,它照样给你一个数字和一个把握。模型没有「这不是数字」这个选项——训练时就没人教过它。
  • 把握 100% 不等于对。画一个介于 7 和 1 之间的形状,它可能非常自信地认错。输出的那个百分比是 Softmax 归一化的结果,反映的是十个选项里哪个相对最像,不是「我有多大概率是对的」。
  • 测试准确率 98.4% 说的是那套测试数据。换成别人的笔迹、不同的笔画粗细、不同的预处理方式,准确率都会变。任何一个准确率数字都只对它所在的那批数据负责。

常见问题

池化层到底有什么用?
三个作用:缩小特征图从而减少计算量;扩大后续层的感受野;带来一定的平移不变性——目标稍微挪动,最大值往往仍在同一个池化窗口里。代价是丢失精确位置信息,所以需要逐像素定位的任务(如分割)会谨慎使用。
为什么卷积网络比全连接网络更适合图像?
全连接把图像拉平成一长串数,相邻像素的空间关系立刻丢失,而且参数量巨大。卷积保留二维结构,通过局部连接和权重共享把参数量降低几个数量级,同时把「同一个花纹在哪里都算同一个花纹」这条先验写进了结构里。
模型说「把握 100%」是什么意思?
那只是 Softmax 输出的最大值接近 1,表示在给定的十个选项中这一个的得分远高于其余。它不是校准过的概率,也不包含「这可能不是数字」这种可能性。要得到可信的置信度需要额外做概率校准,或者引入拒识机制。

本页模型由 work/train_mnist.py 用 PyTorch 训练导出,98.4% 为该模型在 MNIST 测试集上的准确率;页面加载时与 PyTorch 输出自动对账。

作者与维护:覃秉丰 · 关于覃秉丰 · 引用本页讲解

继续学习