
教程人工智能机器学习深度学习【免费下载链接】AI-For-Beginners12 Weeks, 24 Lessons, AI for All!项目地址https://gitcode.com/GitHub_Trending/ai/AI-For-Beginners点击查看免费下载本篇文章围绕 AI-For-Beginners 第 4 课《搭建自己的神经网络框架》配套实验展开核心任务是使用课程中从零手写的神经网络框架解决 MNIST 手写数字的 10 分类问题并对比 1 层、2 层与 3 层感知机的效果。读者完成本文的实验后将掌握Linear、Softmax、CrossEntropyLoss、Tanh、Net等模块化层的实现原理理解前向传播、反向传播、随机梯度下降SGD在真实分类任务中的完整调用链并能独立回答激活函数是否影响性能网络层数如何选择训练中权重如何变化等关键问题。实验背景从课程框架走向真实分类任务在课程正文 README.md 中我们学习了将单层感知机扩展为灵活框架的方法支持多类分类、回归问题以及非线性可分的类别分离。课程配套笔记 OwnFramework.ipynb 逐步实现了完整的模块化框架——每一层都是一个带forward方法的 Python 类可组合成任意深度的网络。本实验lab/README.md则要求把这套框架从玩具级的二维二分类示例迁移到 MNIST 手写数字识别这一经典的多分类真实任务上分别用 1 层、2 层和 3 层感知机求解并回答四个研究性问题。实验起点笔记为 MyFW_MNIST.ipynb。实验准备加载与拆分 MNIST 数据集实验数据为 MNIST 手写数字集合。启动笔记中直接下载并解压数据!rm *.pkl !wget https://raw.githubusercontent.com/microsoft/AI-For-Beginners/main/data/mnist.pkl.gz !gzip -d mnist.pkl.gz离线替代方案该数据集同样已经存放在本仓库的 data/mnist.pkl.gz 目录中可以直接复制使用无需联网。随后用pickle载入并取出训练集的特征与标签import pickle with open(mnist.pkl,rb) as f: MNIST pickle.load(f) labels MNIST[Train][Labels] data MNIST[Train][Features]可以通过data.shape确认数据形状MNIST 每张图片为 28×28 的灰度像素展平后每行特征向量长度为 784标签为 0~9 共 10 类。接下来使用 Scikit-Learn 将数据拆分为训练集与测试集80% / 20%from sklearn.model_selection import train_test_split features_train, features_test, labels_train, labels_test train_test_split(data, labels, test_size0.2) print(fTrain samples: {len(features_train)}, test samples: {len(features_test)})复用框架把课程代码搬进实验实验的第 1 条指令是把课程中的框架代码粘贴到本笔记中更好的做法是放进一个独立的 Python 模块。也就是说本实验完全复用 OwnFramework.ipynb 中构建的框架无需引入任何深度学习库。下面逐一回顾这些核心组件——它们是本实验的全部武器。Linear 线性层线性层完成z W·x b的计算。权重W使用np.random.normal(0, 1/sqrt(nin))初始化方差按输入维度缩放避免深层网络梯度消失偏置b初始化为零。完整实现含反向传播与参数更新如下class Linear: def __init__(self,nin,nout): self.W np.random.normal(0, 1.0/np.sqrt(nin), (nout, nin)) self.b np.zeros((1,nout)) self.dW np.zeros_like(self.W) self.db np.zeros_like(self.b) def forward(self, x): self.xx return np.dot(x, self.W.T) self.b def backward(self, dz): dx np.dot(dz, self.W) dW np.dot(dz.T, self.x) db dz.sum(axis0) self.dW dW self.db db return dx def update(self,lr): self.W - lr*self.dW self.b - lr*self.db注意所有计算都针对整个 minibatch 进行而非单条样本。dx、dW、db的维度分别为minibatch×nout、nout×nin、nout对应公式∂z/∂W x∂z/∂b 1Δx Δz × WΔW Δz × xΔb Δz这正是反向传播时误差沿计算图向输入方向回传的落点。Softmax把输出变成概率网络的原始输出可以是任意实数需要经过softmax归一化为各类别的概率分布class Softmax: def forward(self,z): self.z z zmax z.max(axis1,keepdimsTrue) expz np.exp(z-zmax) Z expz.sum(axis1,keepdimsTrue) return expz / Z def backward(self,dp): p self.forward(self.z) pdp p * dp return pdp - p * pdp.sum(axis1, keepdimsTrue)实现中用zmax做数值稳定性处理减去每行最大值再取指数避免exp溢出。softmax 输出可解释为类别集合上的概率分布q σ(z_c) p̂(c|x)每一行概率之和恰为 1。下图展示了带 softmax 输出的 MNIST 分类网络架构——输入 784 维像素向量输出 10 类概率CrossEntropyLoss交叉熵损失层分类任务的损失是 logistic 损失的推广——交叉熵损失用于度量网络输出概率分布与 one-hot 期望分布之间的差异。当网络对真实类别给出的概率为 1 时损失为 0概率越接近 0 损失越大可趋向无穷class CrossEntropyLoss: def forward(self,p,y): self.p p self.y y p_of_y p[np.arange(len(y)), y] log_prob np.log(p_of_y) return -log_prob.mean() # average over all input samples def backward(self,loss): dlog_softmax np.zeros_like(self.p) dlog_softmax[np.arange(len(self.y)), self.y] - 1.0/len(self.y) return dlog_softmax / self.pforward中p[np.arange(len(y)), y]按每个样本的真实类别取出对应概率取对数后求负平均。重要约定损失函数必须对整个数据集或 minibatch 返回一个标量因此用.mean()聚合所有样本的损失。backward实现了 log-softmax 与交叉熵合并后的解析梯度从而可以跨过 softmax 层直接把误差回传到线性层。Net层容器与训练循环Net类将各层堆叠为列表forward按序执行、backward逆序回传、update只更新带update方法的层如Linear而Softmax、Tanh这类无参数层自动跳过class Net: def __init__(self): self.layers [] def add(self,l): self.layers.append(l) def forward(self,x): for l in self.layers: x l.forward(x) return x def backward(self,z): for l in self.layers[::-1]: z l.backward(z) return z def update(self,lr): for l in self.layers: if update in l.__dir__(): l.update(lr)一次完整 epoch 的训练循环SGDminibatch size4学习率 lr如下def train_epoch(net, train_x, train_labels, lossCrossEntropyLoss(), batch_size4, lr0.1): for i in range(0,len(train_x),batch_size): xb train_x[i:ibatch_size] yb train_labels[i:ibatch_size] p net.forward(xb) # forward pass l loss.forward(p,yb) dp loss.backward(l) # backward pass dx net.backward(dp) net.update(lr)每个训练回合由两部分组成前向传播对给定 minibatch 计算损失值与反向传播把误差沿计算图分配回模型参数。整个过程可用计算图直观表示Tanh层间非线性激活课程强调了一个关键点在线性层之间必须插入非线性激活函数如tanh。因为线性函数的复合仍是线性函数若不加非线性多个线性层叠加的表示能力与单层完全相同。Tanh层实现如下其反向传播利用了tanh 1 - tanh²class Tanh: def forward(self,x): y np.tanh(x) self.y y return y def backward(self,dy): return (1.0-self.y**2)*dy加入非线性后多层感知机的数学形式为z₁ W₁×x b₁z₂ W₂×α(z₁) b₂f σ(z₂)其中α是非线性激活函数、σ是 softmax、参数集θ ⟨W₁, b₁, W₂, b₂⟩。利用链式法则各层权重的梯度可写成∂L/∂W₂ (∂L/∂σ)(∂σ/∂z₂)(∂z₂/∂W₂)∂L/∂W₁ (∂L/∂σ)(∂σ/∂z₂)(∂z₂/∂α)(∂α/∂z₁)(∂z₁/∂W₁)注意所有表达式最左侧的因子完全相同——这正是误差可以从损失出发、沿计算图逐层向前回传backprop的数学基础也是我们能在Net中逆序遍历层列表完成反向传播的原因。完成实验1、2、3 层感知机的 MNIST 训练实验笔记 MyFW_MNIST.ipynb 给出的操作步骤为将课程框架代码粘贴进笔记或独立 Python 模块定义并训练单层感知机训练过程中持续观察训练与验证准确率判断是否发生过拟合必要时调整层参数以提升准确率对2 层、3 层感知机重复以上步骤并在层间尝试不同的激活函数回答下方研究性问题。以两层网络为例用Net组合框架组件即可完成定义net Net() net.add(Linear(784, 64)) # MNIST 输入 784 维 net.add(Tanh()) # 层间非线性激活 net.add(Linear(64, 10)) # 输出 10 类 net.add(Softmax()) loss CrossEntropyLoss()对于单层版本只需去掉中间Tanh与第二层Linear让Linear(784,10)直接接Softmax()三层版本则再叠加一组Linear Tanh。之后反复调用train_epoch训练若干 epoch并用类似get_loss_acc的辅助函数统计def get_loss_acc(x,y,lossCrossEntropyLoss()): p net.forward(x) l loss.forward(p,y) pred np.argmax(p,axis1) acc (predy).mean() return l,accnp.argmax(p,axis1)取每行概率最大的下标作为预测类别与真实标签比较得到准确率。可分别在训练集与测试集上调用同时监控loss与acc。实验讨论四个研究性问题的分析框架完成训练后需要针对实验原文提出的问题给出自己的观察结论。这里提供分析思路与判断依据实际结论请以你自己训练得到的数据为准。激活函数是否影响网络性能会。这正是课程引入Tanh的原因。若无激活函数多层线性层的复合依然是线性变换网络退化为一层的能力见 OwnFramework.ipynb 第 45 个 cell 的说明。在 MNIST 上对比同一深度、仅更换层间激活如tanh与relu风格的自定义非线性的网络可以观察到收敛速度与最终准确率的差异。建议固定层数与隐藏单元数仅改变激活函数做对照实验。这个任务是否需要 2 层或 3 层网络MNIST 数据集类别较多且存在大量书写变形单层线性分类器线性可分限制通常只能达到约 90% 左右的准确率加入一层隐藏单元后网络具备拟合非线性决策边界的能力准确率会明显提升。理论依据是足够多神经元的双层模型可以分类任意凸集三层模型几乎可以分类任意集合见 OwnFramework.ipynb 第 47 个 cell。你可以记录三种深度下的最终准确率与训练耗时判断继续加深是否带来收益。训练中遇到了哪些困难层数增加后尤为明显随着层数增加梯度需要经过更多层的链式乘法回传容易出现梯度消失浅层权重更新缓慢甚至停滞问题。观察各层权重的更新幅度可以发现深层与浅层的不均衡。此外更深的网络更容易过拟合训练损失很低但验证损失远高于训练损失、甚至随训练继续而上升——因为模型开始记忆训练样本而丢失了对数据整体规律的把握。课程中的train_and_plot工具记录每个 epoch 的训练/验证准确率并绘制曲线正是用于捕捉这类现象的。过拟合的直观对比如下图中x表示训练数据、o表示验证数据左侧单层线性模型较好拟合了数据本质右侧复杂模型对训练数据拟合完美但对其他数据的验证误差非常高。权重在训练中如何变化可以按实验原文建议绘制每个 epoch 权重的最大绝对值max abs weight随 epoch 的变化曲线。一般观察训练初期权重幅度随梯度更新快速增长随后逐渐趋于平稳如果出现幅度持续异常增大尤其配合验证损失反弹通常意味着过拟合或学习率过大。实现上只需在每个 epoch 结束后遍历net.layers中带W属性的层记录np.max(np.abs(l.W))即可。该曲线能帮你直观理解学习率与权重正则化可类比 L2 正则思想的关系。课程要点回顾与后续延伸本实验直接复用了课程结论可作为实验结果的解释依据见 OwnFramework.ipynb 的 Takeaways容量与过拟合参数少的简单模型不易过拟合复杂的多层模型容易过拟合需持续监控验证误差是否在进一步训练中回升数据需求越复杂的模型需要越多训练数据缓解过拟合的两条路径简化模型或增加训练数据量偏差-方差权衡需要在模型能力与数据量、过拟合与欠拟合之间取得折中没有万能配方层数与参数规模没有标准答案最可靠的方式是像本实验一样动手对比。完成本实验后建议回到课程主笔记 OwnFramework.ipynb 复习训练循环与反向传播的逐步推导再结合本实验的 MNIST 结果即可把自研框架 真实分类任务这一完整链路彻底吃透。赞分享教程人工智能机器学习深度学习【免费下载链接】AI-For-Beginners12 Weeks, 24 Lessons, AI for All!项目地址https://gitcode.com/GitHub_Trending/ai/AI-For-Beginners点击查看免费下载相关推荐用自研神经网络框架完成 MNIST 手写数字分类AI-For-Beginners 多层感知机实验全解析用自研神经网络框架完成 MNIST 手写数字分类AI For Beginners 多层感知机实验全解析 本篇技术指南围绕 AI For Beginners 课教程人工智能机器学习深度学习AI for Beginners 实验指南用自研神经网络框架完成 MNIST 手写数字分类AI for Beginners 实验指南用自研神经网络框架完成 MNIST 手写数字分类 本篇技术指南围绕 AI for Beginners 课程12 周教程人工智能机器学习深度学习用自研神经网络框架完成 MNIST 手写数字分类AI-For-Beginners 自建框架实验实战指南用自研神经网络框架完成 MNIST 手写数字分类AI For Beginners 自建框架实验实战指南 本篇技术指南围绕 AI For Beginners 课教程人工智能机器学习深度学习上一篇FFmpeg-Kit终极指南跨平台多媒体处理的革命性解决方案下一篇Smithbox游戏修改工具完整教程从入门到精通创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考