第 3 章:神经网络如何学习

第 3 章:神经网络如何学习

在第二章中,我们详细了解了神经网络的静态结构:由神经元组成的层,以及连接它们的权重和偏置。现在,我们将进入整个教程最核心的部分:神经网络是如何从数据中"学习"的?

这个学习过程是一个动态的、不断调整自身参数以求更佳预测的过程。我们将通过四个关键概念来揭示这个秘密:

  1. 前向传播 (Forward Propagation):数据如何通过网络产生一个预测?
  2. 损失函数 (Loss Function):如何量化这个预测的"好坏"?
  3. 梯度下降 (Gradient Descent):如何根据"好坏"程度,找到参数优化的方向?
  4. 反向传播 (Backpropagation):如何高效地在整个网络中执行这个优化?

让我们从第一步开始。

3.1 前向传播:从输入到输出

前向传播,顾名思义,是信息在神经网络中 从前向后 传递的过程。它描述了当给定一个输入样本时,网络是如何一步步进行计算,并最终在输出层得到一个预测值的完整流程。

这个过程非常直观,就是将我们在第二章学到的所有知识串联起来。

前向传播的步骤

我们以一个简单的、用于二元分类的网络为例。假设它有一个输入层、一个隐藏层和一个输出层。

在这里插入图片描述

图 3.1: 前向传播流程示意图。数据从输入层(绿色)开始,流经隐藏层(蓝色),最终到达输出层(红色)产生预测值。

对于一个输入样本 X,其前向传播的计算流程如下:

  1. 输入层 -> 隐藏层

    • 首先,隐藏层的每一个神经元都会接收来自输入层所有神经元的信号。
    • 对于隐藏层中的 第 j 个神经元,它会计算一个加权和 z_j,这和我们在感知器中学到的一样:
      z j = ( ∑ i ( x i ⋅ w i j ) ) + b j z_j = (\sum_{i} (x_i \cdot w_{ij})) + b_j zj=(i(xiwij))+bj
      其中,x_i 是第 i 个输入,w_ij 是从输入层第 i 个神经元到隐藏层第 j 个神经元的权重,b_j 是隐藏层第 j 个神经元的偏置。
    • 然后,将这个加权和 z_j 通过一个激活函数(比如我们学过的 ReLU 或 Sigmoid)处理,得到该神经元的输出 a_j
      a j = Activation ( z j ) a_j = \text{Activation}(z_j) aj=Activation(zj)
    • 对隐藏层中的所有神经元重复这个过程,我们就得到了整个隐藏层的输出 A_hidden
  2. 隐藏层 -> 输出层

    • 现在,隐藏层的输出 A_hidden 成为了输出层的输入。
    • 输出层的计算过程与隐藏层完全相同。假设我们的输出层只有一个神经元(用于二元分类),它的计算过程是:
      • 计算加权和 z_output
        z output = ( ∑ j ( a j ⋅ w j , output ) ) + b output z_{\text{output}} = (\sum_{j} (a_j \cdot w_{j,\text{output}})) + b_{\text{output}} zoutput=(j(ajwj,output))+boutput
      • 应用激活函数得到最终预测 y_pred
        y pred = Activation output ( z output ) y_{\text{pred}} = \text{Activation}_{\text{output}}(z_{\text{output}}) ypred=Activationoutput(zoutput)
        (对于二元分类,这里的激活函数通常是 Sigmoid)

至此,一次完整的前向传播就完成了。 我们从一个原始输入 X 开始,通过网络中预设的权重和偏置,一步步计算,最终得到了一个预测结果 y_pred

值得注意的是,在网络未经训练时,由于权重和偏置都是随机初始化的,这个 y_pred 几乎肯定是错误的。

那么,我们如何知道它"错得有多离谱"?又该如何利用这个"错误"来指导网络调整参数,让下一次的预测更准一些呢?

这便是我们下一节要讨论的 损失函数

3.2 损失函数:衡量预测的"错误"程度

损失函数(Loss Function),有时也被称为 成本函数(Cost Function)目标函数(Objective Function),是神经网络学习过程中的"导航员"和"裁判"。

它的作用非常明确:用一个具体的数值来量化模型的预测值(y_pred)与真实值(y_true)之间的差距。

这个差距,我们称之为"损失"(Loss)或"误差"(Error)。

  • 损失值越大,说明模型的预测越不准确,离真实答案"越远"。
  • 损失值越小,说明模型的预测越精准,离真实答案"越近"。

因此,整个神经网络训练的 最终目标,就是通过调整权重和偏置,来 最小化这个损失函数的值

选择哪种损失函数取决于我们正在处理的任务类型。下面我们介绍两种最常见的场景。

场景一:回归问题(Regression)

在回归任务中,我们的目标是预测一个连续的数值,比如房价、气温或者股票价格。对于这类问题,最常用的损失函数是 均方误差(Mean Squared Error, MSE)

工作原理:MSE 计算的是所有样本的"预测值与真实值之差的平方"的平均值。

在这里插入图片描述

图 3.2: 均方误差(MSE)的可视化。它计算的是每个数据点(蓝点)到模型预测线(红线)的垂直距离(绿色虚线,即残差)的平方的平均值。(来源: Neuromatch Academy)

数学公式(假设我们有 n 个样本):
L MSE = 1 n ∑ i = 1 n ( y true ( i ) − y pred ( i ) ) 2 L_{\text{MSE}} = \frac{1}{n} \sum_{i=1}^{n} (y_{\text{true}}^{(i)} - y_{\text{pred}}^{(i)})^2 LMSE=n1i=1n(ytrue(i)ypred(i))2

  • 我们先计算每个样本的预测值和真实值之差 (y_true - y_pred)
  • 然后将这个差值平方,这有两个好处:1) 保证结果是正数;2) 对较大的误差给予更重的"惩罚"。
  • 最后将所有样本的平方误差加起来,求一个平均值。

场景二:分类问题(Classification)

在分类任务中,我们的目标是预测一个离散的类别标签,例如判断一封邮件是否为垃圾邮件(二元分类),或者识别一张图片中的动物是猫、狗还是鸟(多元分类)。

对于分类问题,最强大的损失函数是 交叉熵损失(Cross-Entropy Loss)

工作原理:它的核心思想是:对于正确的预测,我们给予较小的"惩罚"(损失);对于错误的预测,我们给予巨大的"惩罚"。

在这里插入图片描述

图 3.3: 不同损失函数在二元分类中的对比(当真实标签为1时)。交叉熵损失(绿色实线)显示,当模型对正确类别的预测概率接近1时,损失趋近于0;而当预测概率接近0时,损失会急剧增加,给予错误的预测巨大的惩罚。(来源: Wikimedia Commons)

对于最常见的 二元分类(Binary Classification),其交叉熵损失(也称为 BCE Loss)公式如下:

L BCE = − 1 n ∑ i = 1 n [ y true ( i ) log ⁡ ( y pred ( i ) ) + ( 1 − y true ( i ) ) log ⁡ ( 1 − y pred ( i ) ) ] L_{\text{BCE}} = - \frac{1}{n} \sum_{i=1}^{n} \left[ y_{\text{true}}^{(i)} \log(y_{\text{pred}}^{(i)}) + (1 - y_{\text{true}}^{(i)}) \log(1 - y_{\text{pred}}^{(i)}) \right] LBCE=n1i=1n[ytrue(i)log(ypred(i))+(1ytrue(i))log(1ypred(i))]

让我们来理解一下这个公式:

  • 如果真实标签 y_true 是 1:公式简化为 -log(y_pred)
    • 如果我们的预测 y_pred 也很接近 1(比如 0.99),那么 log(y_pred) 接近 0,损失就很小。
    • 如果我们的预测 y_pred 离谱地接近 0(比如 0.01),那么 log(y_pred) 会趋近于负无穷,损失就会变得非常大。
  • 如果真实标签 y_true 是 0:公式简化为 -log(1 - y_pred)
    • 如果我们的预测 y_pred 也很接近 0(比如 0.01),那么 1 - y_pred 接近 1,log(1-y_pred) 接近 0,损失就很小。
    • 如果我们的预测 y_pred 离谱地接近 1(比如 0.99),那么 1 - y_pred 接近 0,log(1-y_pred) 会趋近于负无穷,损失就会变得非常大。

这正是我们想要的:预测越有信心且越正确,损失越小;预测越有信心但越错误,损失就越大。


现在,我们有了一个明确的目标(最小化损失函数),也知道了如何衡量我们距离这个目标有多远。

接下来的问题是:我们应该 如何 调整那成千上万的权重和偏置,才能让这个损失值降低呢?我们是应该把某个权重调高一点,还是调低一点?调多少才合适?

明确的目标(最小化损失函数),也知道了如何衡量我们距离这个目标有多远。

接下来的问题是:我们应该 如何 调整那成千上万的权重和偏置,才能让这个损失值降低呢?我们是应该把某个权重调高一点,还是调低一点?调多少才合适?

这就是下一节 “梯度下降” 将要为我们解答的问题。

3.3 梯度下降:找到最小化损失的路径

现在,我们站在了问题的核心:我们有了一个可以量化错误的损失函数,我们如何系统地调整网络中成千上万的参数(权重 w 和偏置 b),来让损失值变得越来越小呢?

暴力尝试显然是行不通的。我们需要一个聪明且高效的策略。这个策略就是 梯度下降(Gradient Descent)

一个下山的类比

为了理解梯度下降,想象一个非常生动的场景:

你正置身于一座连绵起伏的山脉中,四周一片浓雾,你看不清山谷的最低点在哪里。你的任务是尽快到达山谷的底部。你该怎么办?

一个非常直观的策略是:环顾四周,找到脚下最陡峭的下坡方向,然后朝着这个方向迈出一步。 到达新位置后,你再次重复这个过程:环顾四周,找到新的最陡峭的下坡方向,再迈出一步。只要你坚持这么做,最终你将一步步地走到山谷的最低点。

这就是梯度下降算法的全部直觉。在这个类比中:

  • 山脉的地形:就是我们的 损失函数。这是一个由所有网络参数(权重和偏置)决定的复杂、高维度的"地形"。
  • 你在山上的位置:由当前网络的 所有参数值 决定。
  • 你的海拔高度:就是当前参数所对应的 损失值
  • 我们的目标:找到这片地形的 最低点(Global Minimum),也就是损失函数的最小值。
  • 最陡峭的下坡方向:这就是 梯度(Gradient) 的反方向。

在这里插入图片描述

图 3.4: 梯度下降的可视化。在这个损失函数的"地形"上,无论从哪个点开始(红点),梯度下降算法都会引导参数沿着最陡峭的下坡路径前进,最终到达一个局部或全局的最低点。

核心概念:梯度与学习率

梯度下降算法的核心由两个概念组成:

  1. 梯度(Gradient, ∇)
    在数学上,梯度是一个向量,它指向函数值 增长最快 的方向。换句话说,梯度就是函数在当前位置的 最陡峭的上坡方向

    那么,最陡峭的 下坡方向 自然就是梯度的 反方向-∇)。

    在神经网络中,这个"函数"就是我们的损失函数 L。梯度 ∇L 就是损失函数 L 对所有参数(w_1, w_2, ..., b_1, b_2, ...)求偏导数后组成的向量。这个向量告诉我们,在当前的位置,如何微调每一个参数,才能让损失值上升得最快。而我们只需要沿着它的反方向更新参数,就能最高效地降低损失。

  2. 学习率(Learning Rate, α)
    找到了下山的方向后,我们还需要决定 每一步该迈多大。这个步长,就是 学习率。它是一个超参数(需要我们手动设定的值),用来控制每次参数更新的幅度。

    • 学习率太小:我们会像个谨小慎微的婴儿一样,每次只挪动一小步。虽然方向是对的,但下山速度会非常非常慢,训练过程会极其漫长。
    • 学习率太大:我们可能会因为步子迈得太大而"冲过头",直接越过了山谷的最低点,甚至可能跳到了对面的山坡上,导致损失值不降反升,永远无法收敛到最低点。

    因此,选择一个合适的学习率是训练神经网络中最关键的环节之一。

梯度下降的更新规则

结合梯度和学习率,我们就得到了梯度下降的参数更新规则。对于网络中的任何一个参数 θ(它可以是任何权重 w 或偏置 b),其更新过程如下:

θ new = θ old − α ⋅ ∇ θ L \theta_{\text{new}} = \theta_{\text{old}} - \alpha \cdot \nabla_{\theta}L θnew=θoldαθL

这个公式的含义是:

  1. 计算损失函数 L 在当前参数 θ_old 处的梯度 ∇_θ L
  2. 将梯度乘以学习率 α,得到本次更新的步长。
  3. 从旧的参数值 θ_old 中减去这个步长,得到新的参数值 θ_new

通过在整个训练数据集上反复迭代这个过程(即,对于每个样本或每个批次的样本,都计算梯度并更新一次参数),网络中的所有参数都会被逐步推向能使总损失最小化的最优值。

但是,这里又出现了一个巨大的挑战:一个现代神经网络的参数动辄成千上万,甚至数百万、数十亿。我们该如何高效地计算出损失函数对这每一个参数的梯度呢?

这就要引出神经网络优化中的最后一块,也是最神奇的一块拼图——反向传播。我们将在下一节详细探讨它。

3.4 反向传播:高效的梯度计算引擎

**反向传播(Backpropagation, BP)**是迄今为止训练神经网络最成功的算法。可以说,没有反向传播,就没有深度学习的今天。它解决的正是上一节末尾提出的那个核心挑战:如何在一个具有数百万甚至数十亿参数的复杂网络中,快速、高效地计算出损失函数对每一个参数的梯度。

它的基本思想非常优雅,完全建立在微积分的 链式法则(Chain Rule) 之上。

直观理解:责任的层层回溯

让我们先抛开复杂的数学公式,用一个直观的方式来理解反向传播。

在前向传播中,信息从输入层流向输出层,最终产生一个预测,并计算出总损失。现在,想象一下,这个最终的损失(误差)是一个"责任",我们需要将这个"总责任"公平且准确地分配回网络中的每一个参数(权重和偏置),看看它们各自对这个最终的错误贡献了多少"力量"。

反向传播做的就是这件事:它将损失 L 这个"总责任",从网络的 输出层开始,一层一层地向后传递,直到输入层。

  1. 输出层:在输出层,我们可以直接计算出损失对该层参数(权重和偏置)的梯度。这相对简单,因为它们离损失函数最近。
  2. 倒数第二层:这一层的参数并没有直接影响最终的损失,而是通过影响了输出层的输出来间接影响损失。那么,这一层某个参数的"责任"有多大呢?根据链式法则,它的大小等于:(它对输出层的影响) x (输出层对最终损失的影响)。由于后者我们已经在第一步算出来了,我们只需要计算前者,就能得到当前层参数的梯度。
  3. 继续向后:这个逻辑可以一直向后传递。任何一层参数的梯度,都可以通过它对下一层的影响,乘以【下一层已经计算出的梯度】来得到。

在这里插入图片描述

图 3.5: 反向传播中的梯度(或误差信号 δ)流动示意图。误差从最后一层(右侧)产生,并利用链式法则逐层向后传递,计算出每一层参数所应承担的"责任"。

就这样,误差信号像涟漪一样从后向前传播,每经过一层,我们就利用链式法则计算出该层参数的梯度。当这个过程到达输入层时,我们就已经拥有了网络中所有参数的梯度。

反向传播的两个阶段

因此,一次完整的参数更新(即梯度下降的一步)实际上包含两个阶段:

  1. 前向传播(Forward Pass)

    • 将一批训练数据输入网络。
    • 从输入层开始,逐层计算,直到输出层得到预测值。
    • 根据预测值和真实值,计算出这一批数据的总损失。
    • 在这个过程中,每一层的计算结果(比如加权和 z 和激活值 a)都需要被缓存下来,因为它们在反向传播阶段需要被用到。
  2. 反向传播(Backward Pass)

    • 从最终的损失开始,计算损失函数对输出层参数的梯度。
    • 利用链式法则,逐层向后计算每一层参数的梯度,直到输入层。
    • 这个过程会用到前向传播中缓存的中间值。

当反向传播完成后,我们就得到了所有参数的梯度。此时,我们就可以使用上一节学到的梯度下降更新规则,来更新所有的权重和偏置了:

θ new = θ old − α ⋅ ∇ θ L \theta_{\text{new}} = \theta_{\text{old}} - \alpha \cdot \nabla_{\theta}L θnew=θoldαθL

这个 “前向计算 -> 反向求导 -> 更新参数” 的循环,就是神经网络训练的核心。这个循环会不断地重复,成千上万次,直到损失函数的值收敛到一个足够小的范围,我们的网络也就"学会"了如何处理这类任务。

至此,我们已经完整地解构了神经网络学习的四大核心组件。在下一章,我们将把这些理论知识应用到实践中,使用 PyTorch 这个强大的深度学习框架,来亲手搭建和训练我们的第一个神经网络。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/912054.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/912054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RocketMQ 消息长轮询

文章目录 问题所在:消费者如何高效地获取消息?解决方案:长轮询 (Long Polling - “等待与观察”模式)长轮询 vs. 短轮询(可视化对比)为什么这个机制对 RocketMQ 这么好?关键的配置参数 让我们用一个简单易懂…

TensorFlow Serving学习笔记3: 组件调用关系

一、整体架构 TensorFlow Serving 采用模块化设计,核心组件包括: Servables:可服务对象(如模型、查找表)Managers:管理 Servable 生命周期(加载/卸载)Loaders:负责 Ser…

视图、索引介绍

目录 1、视图 1.1、什么是视图 1.2、创建视图 1.3、使用视图 1.4、修改视图 1.5、删除视图 1.6、视图的优点 2、MySQL存储结构 2.1、MySQL中的页 3、索引 3.1、索引的数据结构 3.2、B树 和 B树 3.3、B树在MySQL索引中的应用 3.4、索引分类 1、视图 1.1、什么是视…

QT6(46)5.2 QStringListModel 和 QListView :列表的模型与视图的界面搭建与源代码实现

(154)理论讲解 : 例题程序的界面搭建 : (155)以下开始完善代码 ,先准备要给 model 的源数据,一些字符串 : 给出该头文件,以全面展示其内容: #i…

C++设计模式(GOF-23)——03 C++观察者模式(Observer / Event、发布-订阅模式、事件模式)

文章目录 一、观察者模式概述二、传统代码 vs 观察者模式对比1. 传统实现(紧耦合)2. 观察者模式实现(松耦合) 三、Mermaid 类图说明四、核心设计要点1. 接口分层设计2. 通知机制实现3. 扩展性验证 五、应用场景与注意事项适用场景…

海外 AI 部署:中国出海企业如何选择稳定、安全的云 GPU 基础设施?

2025年,中国 AI 企业在模型训练、产品落地和创新应用上不断刷新人们的认知。DeepSeek-R1、Qwen3 等国产大模型密集亮相,国内大模型产业热潮持续升温。与此同时,一个现实的问题也在被越来越多企业关注:模型虽然训练得起&#xff0c…

AI绘画工具实测:Stable Diffusion本地部署指

对于想要深度体验AI绘画的创作者来说,本地部署Stable Diffusion能带来更自由的创作空间。本文将详细介绍Windows系统下的部署流程,帮助你在个人电脑上搭建专业的AI绘画环境。 硬件准备与基础环境配置 部署前需确认电脑配置:建议NVIDIA显卡&…

macOS - 快速上手使用 YOLO

文章目录 一、关于 yolo二、安装三、命令行使用官方示例yolo cfgyolo predict 四、Python 调用results 数据 一、关于 yolo YOLO(YOLO(You Only Look Once)是一种流行的物体检测和图像分割模型,由华盛顿大学的约瑟夫-雷德蒙(Jose…

<script setup> 语法糖

下面&#xff0c;我们来系统的梳理关于 Vue 3 <script setup> 语法糖 的基本知识点&#xff1a; 一、<script setup> 核心概念 1.1 什么是 <script setup>&#xff1f; <script setup> 是 Vue 3 中 Composition API 的编译时语法糖&#xff0c;它通过…

MYSQL-InnoDB逻辑存储结构 详解

InnoDB逻辑存储结构 段—区—页—行 表空间&#xff1a; 默认情况下InnoDB有一个共享表空间ibdata1&#xff0c;所有数据放入这个表空间&#xff0c;如果开启了innodb_file_per_table&#xff08;默认ON&#xff09;&#xff0c;每张表都可以放到一个单独的表空间&#xff0…

[特殊字符] Python 批量合并 Word 表格中重复单元格教程(收货记录案例实战)

在日常办公中&#xff0c;Word 表格中常出现重复的“供应商名称”或“物料编码”&#xff0c;会导致表格冗余且视觉混乱。这时候&#xff0c;用 Python 自动合并重复单元格可以大幅提升表格专业度和可读性。本篇给大家演示如何用 python-docx 实现该功能。 ✅ 功能概览 自动读取…

从零构建Node.js服务托管前端项目

下面是一个完整的指南&#xff0c;教你如何从零开始构建一个Node.js服务来托管前端项目&#xff0c;并代理API请求到其他服务器。 1. 项目初始化 # 创建项目目录 mkdir node-proxy-server cd node-proxy-server# 初始化npm项目 npm init -y# 安装必要依赖 npm install expres…

Lynx vs React Native vs Flutter 全面对比:三大跨端框架实测分析

一文看懂三大热门跨端技术的历史渊源、架构机制、开发体验、包体积对比与性能评估。 我陪你用实测数据带你理性选型&#xff0c;不踩坑&#xff0c;不盲信。 1. 框架简介&#xff1a;它们是谁&#xff1f;来自哪里&#xff1f;干嘛用&#xff1f; 框架名称所属公司发布时间初衷…

CKESC的ROCK 180A-H 无人机电调:100V 高压冗余设计与安全保护解析

一、核心技术参数与性能指标 电压范围&#xff1a;支持 12~26S 锂电&#xff08;适配 110V 高压系统&#xff09;电流特性&#xff1a; 持续工作电流&#xff1a;90A&#xff08;特定散热条件&#xff09;瞬时耐流&#xff08;1 秒&#xff09;&#xff1a;220A&#xff0c;3 …

优化 ArcPy 脚本性能

使用并行处理 如果硬件条件允许&#xff0c;可以使用 Python 的并行处理模块&#xff08;如 multiprocessing&#xff09;来同时处理多个小任务。这样可以充分利用多核处理器的优势&#xff0c;提高脚本的执行效率。 import multiprocessing def process_raster(raster):arcpy…

Windows下CMake通过鸿蒙SDK交叉编译三方库

前言 华为鸿蒙官方的文章CMake构建工程配置HarmonyOS编译工具链 中介绍了在Linux平台下如何使用CMake来配置鸿蒙的交叉编译环境&#xff0c;编译输出在Harmony中使用的第三方so库以及测试demo。 本文主要是在Windows下实现同样的操作。由于平台差异的原因&#xff0c;有些细节…

从C学C++(6)——构造函数和析构函数

从C学C(6)——构造函数和析构函数 若无特殊说明&#xff0c;本博客所执行的C标准均为C11. 构造函数与析构函数 构造函数定义 构造函数是特殊的成员函数&#xff0c;当创建类类型的新对象&#xff0c;系统自动会调用构造函数构造函数是为了保证对象的每个数据成员都被正确初…

清理 Windows C 盘该注意什么

C 盘空间不足会严重影响系统性能。 清理 C 盘文件时&#xff0c;首要原则是安全。错误地删除系统文件会导致 Windows 无法启动。下面我将按照 从最安全、最推荐到需要谨慎操作的顺序&#xff0c;为你详细列出可以清理的文件和文件夹&#xff0c;并提供操作方法。 第一梯队&…

Python Selenium 滚动到特定元素

文章目录 Python Selenium 滚动到特定元素⚙️ **1. 使用 scrollIntoView() 方法&#xff08;最推荐&#xff09;**&#x1f5b1;️ **2. 结合 ActionChains 移动鼠标&#xff08;模拟用户行为&#xff09;**&#x1f9e9; **3. 使用坐标计算滚动&#xff08;精确控制像素&…

你写的 Express 接口 404,可能是被“动态路由”吃掉了

本文首发在我的个人博客&#xff1a;你写的 Express 接口 404&#xff0c;可能是被“动态路由”吃掉了 前情提要 最近参与公司的一个项目前端 React&#xff0c;后端用的 Express。目前我就做一些功能的新增或者修改。 对于 Express &#xff0c;本人没有公司项目实战经验&…