手写数字识别网
写一个数字,看两层卷积、两层池化怎么一层层把它变成答案
此刻
从左到右:输入 → 卷积 1 → 池化 1 → 卷积 2 → 池化 2 → 全连接 → 输出。颜色越深,那一格越活跃。灰线是真实连接:卷积每格只连上一层一小块,全连接 256 格全连 32 个节点、32 连 10左键拖动旋转,右键拖动或按住 Shift 拖动平移,滚轮缩放;触屏单指转、双指移和捏合;方向键平移,0 复位鼠标移到任何一张图上,看那个点连着上一层的哪一小块
怎么做
- 卷积:小窗口找花纹8 个 5×5 的小窗口各自滑过输入,得到 8 张「哪里有这种花纹」的图
- 池化:缩小一半,只留最亮的2×2 里取最大,位置稍微挪一点也不怕
- 再卷积、再池化,最后全连接投票第二层卷积把第一层的 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 输出自动对账。