AI深度学习系列(2):亲手搭第一个网络
简单说:第一个神经网络别自己发明,抄一个最小版本跑通,再逐个改参数看变化。我搭的两层网络总共六十行代码,第一次报了七个错。改学习率比改网络结构见效快得多。
ai深度学习系列2来了。第一篇讲概念(想补课的搜"AI深度学习是什么,看完这篇你就能跟人聊明白"),后台就有读者催更:道理都懂了,手痒,想真的搭一个出来。这篇就是我搭第一个网络的完整流水账——从抄代码、报错、修错、到跑通后做的三组小实验。
丑话说前面:这篇没有高深内容。
它的价值恰恰在于足够笨。网上不缺教程,缺的是把"从报错到跑通"这段狼狈过程原样记录下来的参考。新手最怕的不是难,是以为只有自己卡住。
任务和弹药:六十行代码搭个什么
原子答案:任务是从零搭一个两层全连接网络,识别手写数字(MNIST数据集),只用PyTorch的基础张量运算,不调用现成的nn.Sequential堆模块。整个网络连注释六十行,训练五分钟能出结果。
为什么选这个任务?三个理由。数据集是现成的,六万张28乘28像素的灰度图,不用自己找数据;任务目标简单,把图片分成十类(数字0到9),做对做错一眼可判;最关键的是——它麻雀虽小,前向传播、损失函数、反向传播、参数更新四件套一个不少,改动任何一处都有肉眼可见的反馈。
环境方面我用的老笔记本,CPU跑,没显卡。这个任务模型小,CPU完全够用,一轮训练约四十秒。框架选PyTorch不选TensorFlow纯属个人偏好,TensorFlow搭同样的东西也可以,PyTorch官方教程的60分钟入门那篇我是对照着抄的。数据集MNIST的原始出处是Yann LeCun的页面,现在一般直接用框架内置的下载接口,省事。
网络结构画出来就一行字:784个输入(28乘28展开)→128个神经元(ReLU激活)→10个输出。
就这么点东西。
第一晚的七个报错,逐个复盘
原子答案:七个错里五个是形状对不上,两个是数据类型问题,没有一个是"数学不会"。新手阶段的深度学习代码报错,九成是张量形状和类型这类工程细节,不是智商问题。
挨个列出来,你可能全都会撞上:
第一个错,矩阵维度不匹配。输入忘了把图片展开成一维向量,直接把形状为64乘28乘28的张量喂给了期待784维输入的层。报错信息最后一行写着expected input size匹配失败。修法一行代码:reshape成64乘784。
第二个错,CrossEntropyLoss重复套softmax。我在网络最后一层手贱加了softmax,而这个损失函数内部自带一遍。模型死活不收敛,损失在2.3附近横盘——这个数字我记到现在,log(10)约等于2.3,等于模型在瞎猜。删掉那行softmax,损失立刻开始掉。
第三个和第四个错是复制粘贴手滑:一个把学习率的0.1敲成了01(Python里这是合法的整数1,不报错但训练飞了),一个变量名写错大小写。第五个是忘了zero_grad,梯度累积导致训练曲线抖成心电图。第六个,DataLoader的num_workers参数在Windows上报错,这是个老坑,Windows下多进程加载数据得套main保护。第七个纯属玄学,Anaconda环境冲突,pandas和numpy版本打架,重开了一个干净环境了事。
老实讲,第一个晚上我就卡在这七个错上,进度为零,气得下楼跑了两圈。回来重读报错信息,发现每个错的最后一行其实都把答案写脸上了。深度学习新手的报错,读最后三行,够了。
ai深度学习系列2实战:跑通之后改参数比看十篇教程涨知识
原子答案:网络跑通后我做三组对照实验:调学习率、调隐藏层宽度、调训练轮数,每组只动一个变量。实验一晚上做完,结论是学习率对结果影响最大,隐藏层从128加到512提升微弱。
基础配置下(学习率0.1、隐藏层128个神经元、跑5轮),测试集准确率约97.1%。然后开始瞎改。先说三组实验的数据:
| 改动项 | 原值 | 改后 | 测试准确率 | 我的判断 |
|---|---|---|---|---|
| 学习率 | 0.1 | 0.5 | 跌到约89%,损失剧烈震荡 | 步子太大,直接崩 |
| 学习率 | 0.1 | 0.01 | 约96.5%,收敛变慢 | 稳但慢,不划算 |
| 隐藏层宽度 | 128 | 512 | 约97.3%,提升0.2个点 | 收益太薄,不值当 |
| 训练轮数 | 5 | 15 | 约97.6%,但训练耗时三倍 | 边际递减明显 |
| 批大小 | 64 | 16 | 约97.2%,训练变慢 | 小任务上无感 |
这张表最扎心的发现是隐藏层那行。参数翻了四倍,准确率才涨0.2个点。当时我对着屏幕愣了几秒,第一次直观理解了什么叫"模型容量不是越大越好"——任务太简单,大网络杀鸡用牛刀,牛刀还贵。
学习率0.5那组最有戏剧性。损失曲线像坐过山车,忽上忽下,最后稳定在一个很差的水平。这个画面比任何教材里"学习率过大会导致震荡"那句话都生动。看一百遍定义,不如亲手把损失曲线抖一次。
这次实战教会我的三件事
原子答案:一,形状错误是新手第一大坑,打印张量形状的习惯能救命;二,损失值卡在2.3这种"奇怪的平台期"往往藏着逻辑错误而非超参数问题;三,实验记录必须当场写,事隔三天全忘。
第一件事展开说说。我现在的习惯是每次数据进网络前都print一下shape,几十行的脚本里塞了七八个print。看着蠢,救过我无数次。深度学习代码的bug大多不报语法错误,形状悄悄错了照样能跑,结果就是不对,这种沉默的错最耗时。新手怎么避坑,我踩过的那些入口级陷阱都记在AI入门学习的五大误区里,这篇算是它的代码版续集。
第二件事,那个2.3的教训后来被我用上了。同事的模型损失一直卡在某个值不动,我瞄了一眼数字就问:是不是损失函数和输出层重复处理了?他查了十分钟,果然。这种"数字指纹"的直觉只能从自己的坑里长出来。
第三件事是我的实验记录本。三组实验当晚全靠随手记在一个文本文件里,包括每次改动的准确率和耗时。上周翻回去看,如果没有那份记录,0.2个点的提升差异我绝对记不准。写下来,比记住靠谱。
如果这个系列的第一篇你还没看过,建议先补:AI深度学习是什么?一个例子讲透底层原理,概念和实操配着消化最快。
话说回来,搭完这个网络我有三天没碰深度学习。原因是膨胀——觉得全连接网络不过如此,直接去抄了个ResNet,然后被批归一化层和残差连接的组合按在地上摩擦了整晚。冷静下来才明白,六十行的两层网络和工业级的残差网络之间,隔着的是几百个我这种夜晚。
下一步的台阶怎么上,路线我规划过一版,按"先动手再补原理"的顺序排:人工智能AI技术学习顺序。慢就是快,这话是我被ResNet毒打之后才真信的。
常见问题
完全零基础能直接照这篇搭吗?
需要先会一点Python,能看懂函数、循环和列表就行,大概两周的入门量。数学不设门槛,这个网络用到的求导知识看不懂也不影响跑通,回头补得上。
没有显卡怎么办?
这个任务不需要。CPU跑一轮约四十秒,五轮三分多钟,完全可以接受。真到了要训大模型的阶段,用云端免费算力顶上,具体白嫖姿势我写过一篇实操记录,搜AI云计算跑机器学习就能找到。
为什么要手写网络而不用现成库?
练手阶段的手写是有价值的重复劳动——你会在报错里被迫理解每一行在干嘛。跑通之后就该用高级接口了,工程里没人手写这些。学习的顺序和干活的习惯,得分开对待。
准确率97%算什么水平?
对MNIST这个任务来说只是及格线。人类准确率约99.7%,卷积网络能到99%以上。但第一个网络的97%比数字本身重要,它证明整条链路在你手里是通的。
ai深度学习系列2到这里收尾。下一篇打算写卷积:同样的手写数字任务,换CNN能再涨两个点,改动量其实只有十几行。第一个网络的代码和实验记录我都留着,需要参考的可以照文中的结构自己敲一遍——敲一遍,你就懂了这整篇文章在说什么。觉得有用的话,转给那个总说"想学深度学习但不知从哪下手"的朋友,这篇就是给他准备的起跑线。