ARTICLE DETAIL

资讯详情

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

HCIA-AI V4.0 备考 实验1

HCIA-AI V4.0 备考 实验1 实验 1 复盘从 0 实现全连接神经网络HCIA-AI V4.0 实验手册 第 5–16 页思考题 1、2 完整解答零、3 分钟速览一句话说清这个实验用手写数字图片MNIST当题目用纯 NumPy 搭一个有 4 个隐藏层的神经网络让它自己学出看图认数字的本事最后在 10000 张没见过的图上考到约 96.7 分。必须记住的 6 个数字事项数字为什么重要输入神经元78428×28 的图片拉平隐藏层结构100, 100, 100, 1004 个隐藏层每层 100 个神经元输出神经元10数字 0 到 9训练集 / 测试集60000 / 10000 张训练用前者考试用后者初始 loss约 2.3026 −ln(1/10)代表十个类别瞎猜最终测试准确率约 96.5%–96.7%四种优化器都能达到两道思考题一句话概括思考题 1 是怎么让训练更好——改学习率、换策略看 loss 曲线。思考题 2 是怎么知道训练好不好——加测试模块看测试准确率。一个管优化一个管验证。一、这个实验在做什么1.1 神经网络认数字的四步基本功一次训练术语叫一次迭代就是这四步循环取一小批图片128 张 ↓ 前向传播算出现在网络认为每张图是什么数字 → 得到预测 ↓ 计算损失预测和正确答案差多少 → 得到 loss ↓ 反向传播算出每个权重该往哪个方向调 → 得到梯度 ↓ 更新参数按优化器的规则调整权重 → 参数变好一点重复 1000 次loss 从 2.3 降到 0.1 左右网络就学会了。1.2 手册里的整体流程原图数据加载 → 构建模型 → 初始化超参数 → 计算损失 ↓ ↓ 停止训练 ← 迭代训练 ← 更新参数 ← 计算梯度1.3 数据从哪来原始数据是 4 个压缩文件程序第一次运行时会自动把它们解析成内存数组文件内容数量train-images-idx3-ubyte.gz训练图片60000 张train-labels-idx1-ubyte.gz训练答案60000 个t10k-images-idx3-ubyte.gz测试图片10000 张t10k-labels-idx1-ubyte.gz测试答案10000 个解析过程做了两件事归一化像素值从 0–255 缩放到 0–1dataset[key] / 255.0。不缩放的话数值太大训练不动。标签转 one-hot把数字 3 变成[0,0,0,1,0,0,0,0,0,0]np.eye(10)[X]这样才能和 Softmax 的输出做交叉熵。解析结果会缓存成mnist.pkl以后每次运行直接读它启动秒开。二、代码结构8 个文件各管什么文件一句话说明关键内容train_mnist.py总指挥实验入口训练循环、打印 loss、画图load_mnist.py数据搬运工load_mnist()、gz 解析、one-hot 转换multi_layer_net.py网络本体predict前向、loss损失、gradient反向、accuracy准确率layers.py网络的一砖一瓦Affine全连接、Relu、SoftmaxWithLossfunctions.py数学公式relu、sigmoid、softmax、cross_entropy_errorgradient.py数值微分用来验证反向传播算得对不对optimizer.py四种参数更新法SGD、Momentum、AdaGrad、Adamutil.py小工具smooth_curve把抖动的曲线画平滑四个优化器的区别考试常考优化器默认学习率核心思想SGD0.01最朴素沿梯度反方向走所有参数共用一个固定步长Momentum0.01加惯性像滚雪球抑制左右震荡AdaGrad0.01每个参数自适应历史梯度越大步长越小Adam0.001动量 自适应学习率还带偏差修正三、考试时的操作流程解压代码包进入能看到train_mnist.py的那一层文件夹。在这个文件夹里打开命令行点文件夹上方的地址栏输入cmd回车手册第 8 页的官方做法。确认位置输入cd回车打印出来的路径应该就是这个文件夹。确认环境输入python -c import numpy, matplotlib; print(ok)看到ok就对了。运行python train_mnist.py。第一次运行会先打印Converting ...和Creating pickle file ...这是正常的。训练完会弹出一张 loss 曲线图截图保存。思考题 1、2 都是在这个train_mnist.py上改代码改完按Ctrl S保存回命令行重新运行。四、实验结果主实验配置4 个优化器各自训练一个784-100-100-100-100-10的网络batch_size128迭代 1000 次。训练过程中每 100 次迭代打印的 lossiterationSGDMomentumAdaGradAdam02.37422.35901.87452.20811001.38280.31710.10960.22692000.68140.23930.12520.18443000.52680.21520.11730.20704000.42000.16200.07080.11695000.38400.14250.06710.13836000.38860.17230.06970.12427000.37700.17120.08820.09308000.20800.08440.04000.04529000.35660.12510.04830.0391训练结束后在 10000 张测试集上的准确率优化器测试集准确率SGD0.9183Momentum0.9636AdaGrad0.9673Adam0.9672结论SGD 在山谷地形上来回震荡下降最慢Momentum 靠惯性加速AdaGrad 和 Adam 因为能自适应调整步长前 100 次迭代就已经冲到 loss 0.1 左右收敛最快。最终 AdaGrad、Adam、Momentum 都能达到 96% 以上。五、思考题 1 复盘5.1 题目代码中如何修改学习率请使用不同的学习率设置策略观察 loss 曲线。5.2 怎么改三种层次由浅入深改法一改一个固定学习率。找到优化器定义那几行把参数填进括号optimizers[SGD]SGD(lr0.1)# 原来是 SGD()默认 lr0.01改法二一次对比多个学习率。把四行优化器定义替换成optimizers[lr0.001]SGD(lr0.001)optimizers[lr0.01]SGD(lr0.01)optimizers[lr0.1]SGD(lr0.1)optimizers[lr1.0]SGD(lr1.0)同时要把画图那行的markers字典的键改成一样的名字否则会报KeyError或者干脆把markermarkers[key]改成markero一劳永逸。改法三做学习率策略衰减。这个不用改优化器类只要在训练循环里每次迭代前给optimizer.lr重新赋值。找到for key in optimizers.keys():那一行在它下面第一句插入ifkeySGD:optimizers[key].lr0.5*(0.99**i)# 指数衰减i就是当前的迭代次数。想换成别的策略只换0.5 * (0.99 ** i)这个公式策略公式常数不衰减0.5步进衰减每 250 次减半0.5 * (0.5 ** (i // 250))指数衰减0.5 * (0.99 ** i)余弦退火0.5 * 0.5 * (1 np.cos(np.pi * i / max_iterations))5.3 实验结果第一组只换固定学习率优化器固定为 SGD初始权重和采样顺序都相同唯一变量是学习率学习率最后 100 次迭代平均 loss测试集 loss测试集准确率0.0011.54021.47960.61290.010.29870.30570.91230.10.06380.13480.95620.50.04310.13080.96011.02.29562.30210.1135第二组换学习率策略初始学习率都是 1.0也就是第一组里那种会发散的值学习率策略最后 100 次迭代平均 loss测试集准确率常数 1.0不衰减2.29560.1135步进衰减每 250 次减半0.29420.8976指数衰减1.0 × 0.995^i0.22000.9331指数衰减1.0 × 0.99^i0.31060.91255.4 结论建议背下来学习率是优化器的构造参数写法是SGD(lr0.1)训练途中也可以直接给optimizer.lr赋值用来实现动态衰减。学习率太小0.0011000 次迭代后 loss 还有 1.54模型根本没走到最优点测试准确率只有 61%属于欠拟合。学习率太大1.0loss 冲上去以后卡在 2.30 再也不降测试准确率只有 11%。看到 2.30 这个数就要反应过来它是十个类别瞎猜的水平−ln(1/10) 2.3026说明参数已经彻底崩了、发散了。合适的学习率在 0.1 到 0.5 之间loss 能降到 0.05 以下测试准确率 95% 以上。衰减策略的价值同样从 1.0 起步不衰减就发散加上衰减就都能收敛。其中步进衰减前 350 次迭代 loss 一直平在 2.3因为前 250 次学习率还是 1.0指数衰减下降更平滑。说明先用大学习率快速下降、再用小学习率精细收敛比全程固定学习率更稳。六、思考题 2 复盘6.1 题目请在代码中加入测试模块输出不同阶段测试准确率。题目有三个考点加入原来没有、不同阶段不能只在最后算一次、测试准确率要用测试集算。6.2 怎么改核心就是加一行找到训练循环里打印 loss 的那一段把它从ifi%1000:print(iteration:str(i))forkeyinoptimizers.keys():lossnetworks[key].loss(x_batch,t_batch)print(key:str(loss))改成ifi%1000:print(iteration:str(i))forkeyinoptimizers.keys():lossnetworks[key].loss(x_batch,t_batch)accnetworks[key].accuracy(x_test,t_test)# 新增print(key loss:str(loss) 测试准确率:str(acc))# 改新增的实质内容就是一句话networks[key].accuracy(x_test, t_test)。放在if i % 100 0:里面就实现了每 100 次迭代评估一次i 取值 0、100、200 …… 900正好是题目说的不同阶段。6.3 为什么这么写原理accuracy方法已经在multi_layer_net.py里写好了不用自己实现defaccuracy(self,x,t):yself.predict(x)# 前向传播得到每张图属于 0~9 的概率ynp.argmax(y,axis1)# 取概率最大的那个位置 预测的数字ift.ndim!1:tnp.argmax(t,axis1)# 把 one-hot 答案变回数字accuracynp.sum(yt)/float(x.shape[0])# 数对的张数 ÷ 总张数returnaccuracy最关键的一点评估只做前向传播既不调用gradient()也不调用optimizer.update()所以它不会改变模型的任何一个参数——相当于拿当前模型去做一次模拟考。6.4 实验结果测试集10000 张准确率随迭代的变化用手册默认的四个优化器跑出来的真实数据iterationSGDMomentumAdaGradAdam00.13580.10330.28010.14821000.65690.90040.92630.91142000.81300.92970.94040.93973000.86030.94060.95000.94674000.87650.94070.95210.95345000.89010.94910.95960.94956000.89460.95700.95740.95597000.90820.95620.96270.96298000.91190.95460.96370.96329000.90840.95490.96510.9634同一时刻训练集和测试集的对比iteration 900优化器训练集2000 张测试集10000 张差距SGD0.90050.9084−0.0079Momentum0.96500.95490.0101AdaGrad0.97300.96510.0079Adam0.96800.96340.00466.5 结论建议背下来训练刚开始时四个优化器的测试准确率都只有 10%–28%因为参数还是随机初始化的十个类别等于瞎猜。到第 100 次迭代AdaGrad 已经到 92.6%Momentum 和 Adam 都在 90% 以上而 SGD 只有 65.7%说明自适应学习率和动量确实收敛更快。到 400 次迭代以后陆续进入平台期最终 AdaGrad 96.51%、Adam 96.34%、Momentum 95.49%、SGD 90.84%。训练集准确率和测试集准确率始终只差 0.5%–1%两条曲线几乎重合说明没有过拟合泛化能力正常。这道题的实际意义只盯着训练 loss 是看不出模型好坏的必须用没见过的测试集来评估。有了阶段准确率还能看出模型什么时候收敛——比如 Adam 在第 700 次迭代之后测试准确率基本不涨了继续训练只是浪费时间可以据此提前停止训练。6.6 补充实验过拟合长什么样如果只从训练集里取300 张样本来训练其余设置不变结果会变成数据集准确率训练集300 张模型见过1.0000测试集10000 张没见过0.8170训练准确率很快冲到 100%测试准确率却卡在 81.7% 不动两条曲线明显分离这就是典型的过拟合网络有约 11 万个参数却只喂了 300 个样本模型把训练样本背了下来没有学到能推广的规律。这也正是思考题 2 那个训练集 vs 测试集对比的意义所在。七、两道思考题的关系一句话点透思考题 1思考题 2关心什么训练过程本身怎么下降得更快更稳训练结果好坏模型是不是真的学会了改的地方优化器的lr参数训练循环里新增评估代码看的指标loss 曲线测试集 accuracy一句话结论学习率过小欠拟合、过大发散配合衰减策略最好必须用没见过的测试集评估才能判断泛化能力一个管调参一个管验收。八、易错点清单改代码时缩进不对 → 报IndentationError。解决办法不要从零打字复制上一行再改缩进自动就对了。打成中文标点→ 报语法错误。切英文输入法再打标点。markers字典的键和optimizers的键不一致 → 报KeyError。改完忘记Ctrl S保存 → 重跑还是老结果。plt.savefig()写在plt.show()后面 → 存的图是空的因为show()会阻塞、后面那句执行不到。顺序必须是先savefig再show。跑实验时命令行站的目录不对 → 报cant open file train_mnist.py。用地址栏输入cmd的办法重新打开。提示python 不是内部或外部命令→ 机器上没装 Python 或没加进环境变量用 Anaconda 安装并勾选加入 PATH。提示No module named numpy→ 缺库执行pip install numpy matplotlib。第一次运行很慢并打印一堆Converting ...→ 正常那是在解析数据、生成mnist.pkl。加了测试模块以后变慢 → 正常。测试集有 10000 张每评估一次都要做一次前向传播间隔从 100 改成 200 就快一半。答题时用x_batch当测试集 → 算出来的是训练准确率不合题意。accuracy(t_test, x_test)参数顺序写反 → 报维度错误正确顺序是数据在前、标签在后。把评估代码写在训练循环外面 → 只能得到最后一个阶段的结果不满足不同阶段。九、过程问答记录大白话版这一节是我准备实验的过程中自己问出来的问题按提问的先后顺序排。答案全部用大白话写尽量不绕弯子。Q1 这个实验到底在干啥说白了就是教电脑认手写数字。先给它 6 万张写着 0 到 9 的手写图片让它自己看、自己学。学完之后再拿 1 万张它没见过的图片考它看能认对多少张。我们这个程序最后能认对大约 96.7%也就是 1 万张里错 300 多张。而且全程不许用现成的工具包比如 PyTorch 那种全部用最基础的数学库 NumPy 一笔一画写出来。所以叫从 0 实现。要交的东西就三样一张图四种算法的对比曲线、两道思考题的答案、一份实验报告。Q2 考试机上没有 Codex那终端从哪开不用背命令用鼠标点两下就有先打开装着代码的那个文件夹里面能看到train_mnist.py。用鼠标点一下文件夹最上面那条长长的地址栏点完里面的字会变蓝。接着用键盘敲三个字母cmd按回车。啪一下弹出一个黑窗口。这个黑窗口已经站在你刚才那个文件夹里了你不用告诉它路怎么走。这招不是我编的是华为手册里写着的原话“单击文件夹上方的导航栏然后输入以下命令并回车 → cmd”。Q3 你之前教我的命令考试时能照着敲吗不能得换一套。我之前是拿 Codex 里的 PowerShell 教你的。考试时从地址栏敲cmd打开的那个黑窗口叫命令提示符两个东西说话方式不一样。怎么分辨看前面有没有PS两个字母。有PS就是 PowerShell没有就是 cmd。你想干啥PowerShell 这么说cmd 这么说看自己在哪个文件夹pwdcd后面啥都别加看文件夹里有啥dirdir换个文件夹cd 路径cd /d 路径防止中文乱码$env:PYTHONIOENCODINGutf-8set PYTHONIOENCODINGutf-8清屏clearcls最容易踩的坑在 cmd 里敲pwd它会说不认识这个命令。这时候你敲cd效果一样。Q4 思考题 1 是让我加载现成代码还是自己改自己改。华为给你的就那 8 个文件思考题是留给你动手的压根没有参考答案代码这回事。我凭什么这么肯定两件事。第一翻手册1.3 节思考题下面就只有两行题目一个字代码都没给。第二把参考代码文件夹里那两个网页从头到尾搜了一遍“学习率”“learning_rate”optimizer这几个词一次都没出现过而且那两个文件一个是 MindSpore 版的、一个是老式线性回归的本来就不是这个实验的代码。所以流程就是把华为给的train_mnist.py跑起来 → 在上面改 → 保存 → 再跑一遍看结果。Q5 学习率到底改哪一行改这种行optimizers[SGD]SGD()往括号里填东西就是了optimizers[SGD]SGD(lr0.1)括号里空着不写程序就用默认值 0.01。四个算法的默认值是SGD、Momentum、AdaGrad 都是 0.01Adam 是 0.001。Adam 天生小十倍因为它自己会把步子放大。想一次比好几个学习率就把那四行换成optimizers[lr0.001]SGD(lr0.001)optimizers[lr0.01]SGD(lr0.01)optimizers[lr0.1]SGD(lr0.1)optimizers[lr1.0]SGD(lr1.0)改完会报错说找不到lr0.001这个名字。因为下面画图的地方有个小本本叫 markers上面记的还是老名字。要么把那个小本本上的名字也改一遍要么干脆把markermarkers[key]这句改成markero一了百了。Q6 学习率设置策略是啥意思意思是别老用一个固定的数让这个数一路变。为啥要变打个比方下山的时候一开始离山顶远可以迈大步快到谷底了还迈大步一下就冲过头了得改成小碎步。学习率就是这个步子大小。怎么让它变不用动优化器本身的代码只要在训练循环里每次都给它改一下ifkeySGD:optimizers[key].lr0.5*(0.99**i)# 每走一步就缩小一点i是走到第几步了。叫什么怎么写一直不变0.5每 250 步砍一半0.5 * (0.5 ** (i // 250))每步少一点点0.5 * (0.99 ** i)慢慢滑到 0像滑梯0.5 * 0.5 * (1 np.cos(np.pi * i / max_iterations))Q7 思考题 2 说的加测试模块具体加啥就加一行。找到训练循环里打印 loss 的那段ifi%1000:print(iteration:str(i))forkeyinoptimizers.keys():lossnetworks[key].loss(x_batch,t_batch)print(key:str(loss))改成ifi%1000:print(iteration:str(i))forkeyinoptimizers.keys():lossnetworks[key].loss(x_batch,t_batch)accnetworks[key].accuracy(x_test,t_test)# 加的print(key loss:str(loss) 测试准确率:str(acc))# 改的真正加的就一句话networks[key].accuracy(x_test, t_test)。意思就是拿现在这个模型去考那 1 万张它没见过的图片告诉我考了多少分。为什么要加在if i % 100 0:里面因为这句话的意思是每 100 步做一次。i 取 0、100、200 …… 900正好做 10 次这就是题目要的不同阶段。还有个好消息这个accuracy函数人家早就写好了就在multi_layer_net.py里躺着你不用自己写。Q8 为啥非得用测试集拿训练集考不行吗不行。训练集是它做过的题当然考得好。就跟考试前把答案背下来一样分数看着高其实啥也没学会。原来那个程序打印的 loss 也是这个毛病——用的是刚刚训练过的那 128 张图。要真想看它会不会认数字就得拿它没见过的那 1 万张来考。而且这两条线训练集得分、测试集得分的差距本身就有用两条线贴在一起 → 挺好是真学会了两条线裂开一大截 → 那是死记硬背。比如只给它 300 张图练手训练集能考 100 分测试集只有 81.7 分。Q9 我基本没碰过代码让我加代码心里发慌咋办那你得先知道一件事你不需要会写代码只要会改代码。整个实验你要做的动作只有三种改个数字把0.01改成0.1加一行字删一行字。这跟你用 Word 改字、加行、删行一模一样。唯一的区别是必须用记事本那种纯文本的编辑器记事本、IDLE、PyCharm、VS Code 都行千万别用 Word——Word 会偷偷加格式一存代码就废了。顺便说一句.py文件其实就是个文本文件跟.txt没区别别被后缀名吓到。建议按这个顺序练先只改一个数字确认改一下 → 保存 → 重新跑这条路走得通再练加一行再练删一行。这三样练熟思考题 2 对你来说就是重复动作而已。Q10 加的那一行缩进老是弄不对怎么搞缩进就是行首的那几个空格。Python 全靠它判断哪几行是一伙的所以不能乱来。只要记住一条新加的那行左边要跟它正上方那行对齐。但千万别用眼睛数空格一数准错。可靠的招是鼠标点上一行左边那个行号整行会变蓝按Ctrl C复制按一下↓键光标跳到下一行行首按Ctrl V粘贴——现在有两行一模一样的空格绝对对齐了再把新那行里不要的字删掉。用这个办法永远不会报缩进错误。还有一点标点必须是英文的。冒号打:别打引号打别打。用中文标点程序直接报错。Q11 程序报错了一堆红字看不懂咋办别慌只看最后两行就够了。比如这一段File train_mnist.py, line 71 acc networks[key].accuracy(x_test, t_test) ^ IndentationError: unexpected indent倒数第二行告诉你出事的是哪一行还把那一行原文抄给你看这里是第 71 行。最后一行告诉你错在哪。常见的几个词记住就行报错里出现这个词啥意思怎么办IndentationError开头的空格没对齐把整行删了用复制上一行再改的办法重做SyntaxError: invalid character你打了中文标点换成英文标点NameError用了一个不认识的名字多半是单词拼错了KeyError小本本markers里没这个名markers 的键和 optimizers 的键对不上了改的办法就一句话光标点到那行按Ctrl Z一直撤销退回到没改的时候重来一遍。Q12 画出来的图怎么存成文件在plt.legend()和plt.show()中间插一句plt.savefig(loss.png)顺序千万别反plt.show()会把程序卡住等你把图窗关掉它才往下走。所以写在它后面的句子根本轮不到执行你只会得到一个空文件。图窗弹出来也不影响关掉它程序就继续往下跑了。截图交作业也行存成文件更保险。Q13 手一抖把文件改坏了怎么办两个办法第一编辑器还开着光标点到乱的地方Ctrl Z一直撤销能退回原样。第二已经存坏了跟我说一声。我这边有你文件的完整内容一句话就能给你恢复。所以放心改这个实验的代码改坏了没有任何损失。
返回列表