查看全课大纲(第 27 / 93 节)
- 1.计算机视觉概述
- 2.计算机视觉应用场景
- 3.困难与挑战
- 4.开源库介绍
- 5.图像显示与存储
- 6.CLAHE
- 7.腐蚀膨胀与开闭运算
- 8.滤波与边缘填充
- 9.各种滤波
- 10.图像金字塔
- 11.傅里叶变换
- 12.短时傅里叶变换与小波变换
- 13.颜色特征与颜色直方图
- 14.几何特征_边缘
- 15.几何特征-角点与斑点
- 16.局部特征-SIFT特征描述子
- 17.局部特征-SURF特征描述子
- 18.局部特征-ORB特征描述子
- 19.其他特征描述子
- 20.传统图像分割技术
- 21.GraphCut
- 22.GrabCut
- 23.人脸检测的传统方法
- 24.行人检测的传统方法HOG+SVM
- 25.行人检测DPM
- 26.人工神经网络的架构
- 27.目标函数与梯度下降
- 28.误差反向传播
- 29.可手算的神经网络
- 30.改进目标函数与克服梯度消散
- 31.神经网络之传统神经网络与深度网络的差异
- 32.各种梯度下降算法
- 33.如何选择合适的梯度下降算法
- 34.避免过适应
- 35.CNN的架构
- 36.CNN的误差反向传播_卷积层
- 37.CNN的误差反向传播_池化层
- 38.分类所用的数据集
- 39.Alexnet详解
- 40.VGG详解
- 41.GoogLeNet_v1
- 42.BatchNormalization
- 43.GoogLeNet_v3v4
- 44.ResNet
- 45.ResNeXt
- 46.CNN设计准则
- 47.图像检索与推土机距离
- 48.基于颜色相似性
- 49.基于形状相似性
- 50.基于纹理相似性
- 51.基于局部特征相似性
- 52.DL的二值哈希编码
- 53.高维空间中检索KDTree
- 54.高维空间中检索LSH
- 55.目标识别任务综述
- 56.RCNN
- 57.SPP-Net
- 58.Fast R-CNN
- 59.Faster R-CNN
- 60.R-CNN系列模型回顾
- 61.R-FCN的设计思路
- 62.R-FCN的实现
- 63.YOLOv1
- 64.YOLOv2_9000
- 65.YOLOv3
- 66.图像分割应用场景与数据集
- 67.上采样的实现方式
- 68.FCN网络架构的由来
- 69.FCN构建细节
- 70.DeepLabv1
- 71.CRF
- 72.DeepLabv2
- 73.DeepLabv3
- 74.特定的医学影像分割任务
- 75.U-Net
- 76.3D U-Net
- 77.V-Net
- 78.DenseNet
- 79.病理切片分析任务及数据集
- 80.病理切片分析
- 81.图说任务及其传统处理方法
- 82.深度语言模型与RNN
- 83.LSTM及其变种
- 84.NIC模型
- 85.SAT模型
- 86.图说的性能指标
- 87.判别模型与生成模型
- 88.KL散度与JS散度
- 89.VAE
- 90.GAN的基本原理
- 91.DCGAN与CGAN
- 92.Wasserstein GAN
- 93.SRGAN
目标函数与梯度下降
小象实战讲义 · 基于深度学习的计算机视觉
在上一节,我们学习了人工神经元和前馈神经网络的基本结构。一个网络由输入层、隐藏层和输出层构成,数据在其中单向流动。然而,仅仅有网络结构是不够的,我们还需要一种方法来“教会”这个网络完成特定的任务,比如正确分类一张图片。本节课,我们将引入神经网络学习的核心驱动力:目标函数,并学习如何通过梯度下降这一经典优化算法,来寻找使目标函数最小化的网络参数(权重)。这是理解后续所有深度学习模型训练过程的基础。
💡 核心导读
- 目标函数的定义:理解如何通过期望输出与实际输出的差异来定义一个可量化的“损失”,即目标函数(或损失函数)。
- 梯度下降的原理:学习为什么不能直接求解偏导数为零,以及梯度下降如何通过“迭代”的方式在复杂的参数空间中寻找最优解。
- 学习率的重要性:掌握学习率这一超参数如何影响训练过程的收敛性、速度和稳定性。
- 目标函数的可导性要求:了解为什么激活函数(如Sigmoid)需要处处可导,这与梯度下降算法的可行性息息相关。
从网络输出到目标函数
我们回顾一下前馈神经网络的结构。对于一个输入样本,网络会经过层层计算,最终在输出层产生一个实际输出向量 z = (z1, z2, ..., zc),其中 c 是输出层神经元的个数。同时,对于这个输入样本,我们有一个已知的、正确的期望输出(或称标签)向量 t = (t1, t2, ..., tc)。
一个训练良好的网络,其实际输出 z 应该尽可能地接近期望输出 t。如何量化这个“接近”的程度呢?最直观的方法之一就是计算它们之间的误差。一个经典且广泛使用的度量是均方误差(MSE)。
对于一个单个样本,其目标函数(损失)J 可以定义为所有输出分量误差平方和的一半:
这里,k 遍历输出层的每一个神经元。
(t_k - z_k)是第k个输出分量的误差。- 平方操作
(t_k - z_k)^2有两个作用:第一,将所有误差转为非负值;第二,放大了较大误差的影响。 - 前面的系数
1/2是一个为了后续求导方便的约定,求导时平方项会产生一个因子2,与1/2相乘后恰好为1,简化了表达式。
注意:上面的公式是针对一个训练样本的损失。在实际训练中,我们通常使用一批(Batch)或多个样本。完整的损失函数应该是所有样本损失的平均或总和。例如,对于
N个样本,损失函数可写为: 为了推导和讲解的清晰,我们通常先分析单个样本的情况,其原理可以自然地推广到批量训练。
我们的目标变得非常明确:调整神经网络中所有的连接权重(参数),使得这个目标函数 J 的值达到最小。当 J 最小时,意味着网络在整个训练集上的平均输出误差最小,此时网络对训练样本的拟合最好;但要注意,训练误差最小并不必然意味着对未见数据的预测(泛化)能力最强,这正是后续要讨论的过拟合问题。
德尔塔(Delta)学习规则:权重的迭代调整
那么,如何调整权重 w 来最小化 J 呢?一个朴素的想法是:如果某个权重增大导致误差增大,那就减小它;反之则增大它。这种思想体现在一个早期的监督学习规则——德尔塔学习规则中。
德尔塔规则给出了单个神经元(或感知机)权重调整量 Δw 的公式:
让我们拆解这个公式:
Δw_{ij}: 从神经元j到神经元i的连接权重的改变量。η(Eta): 学习率。这是一个非常重要的超参数,它控制了每次权重更新的“步长”。步长太大可能导致震荡甚至发散;步长太小则学习速度过慢。(d_i - y_i): 误差信号。d_i是神经元i的期望输出,y_i是其实际输出。这个差值直接反映了当前输出的错误程度。x_j: 输入信号。即来自前一层神经元j的输出(对于输入层就是原始输入)。这意味着权重的调整幅度也与输入的强度有关。
德尔塔规则的意义:它确立了权重调整的三个核心依据:1) 误差的大小和方向;2) 学习率控制的步长;3) 输入信号的强度。这为后续更复杂的梯度下降算法提供了直观的理解基础。
然而,德尔塔规则主要适用于单层网络或线性可分问题。对于具有多层非线性隐藏层的神经网络,我们需要一个更强大、更通用的优化方法。
梯度下降:在山坡上蒙眼下山
对于复杂的多层神经网络,其目标函数 J(w) 是所有权重参数 w 的高维非线性函数。直接对 J(w) 求偏导数并令其等于零来求解最优权重,在绝大多数情况下是行不通的。原因如下:
- 方程过于复杂:
J(w)的表达式涉及多层嵌套的非线性函数,其偏导数方程组可能没有解析解,或者求解极其困难。 - 存在多个极值点:非线性函数往往有多个局部极小值点。即使能解出偏导数为零的点,我们也无法区分哪个是全局最小值(最优解),哪个是局部最小值(次优解)。
因此,我们采用一种迭代优化的方法——梯度下降法。
我们可以把目标函数 J(w) 想象成一个多维空间中的“地形图”。假设只有两个权重参数 w1 和 w2,那么 J(w1, w2) 就构成了一个三维曲面。曲面上有的地方高(J 值大,误差大),有的地方低(J 值小,误差小)。我们的目标就是找到这个曲面上的最低点(谷底)。
梯度下降的过程,可以类比为一个被蒙住眼睛的人如何从山坡上走到谷底:
- 探查最陡的方向(计算梯度):人用脚感受脚下山坡哪个方向最陡峭。在数学上,函数在某一点最陡峭的上升方向就是该点的梯度(Gradient)。梯度是一个向量,其方向指向函数值增长最快的方向,其大小表示增长的速率。对于目标函数
J(w),其梯度记为∇J(w)。 - 向相反方向迈步(沿负梯度方向更新):既然要下山(最小化
J),我们就应该朝着与梯度相反的方向,即负梯度方向前进。这是函数值下降最快的方向。权重的更新公式为: 其中η就是学习率。 - 决定步长(选择学习率
η):这一步是迈一大步还是一小步?这就是学习率的作用。- 学习率太大:好比巨人一步跨过一个山头,可能直接从当前山谷迈到了对面更高的山坡上,导致损失值不降反增,训练过程震荡甚至发散。
- 学习率太小:好比蚂蚁下山,每一步都迈得极小,虽然方向正确,但走到谷底需要极其漫长的时间,训练速度过慢。 因此,选择一个合适的学习率是训练成功的关键之一,通常需要根据经验或通过一些自适应算法来确定。
- 重复直到“平地”(迭代收敛):重复步骤1-3。每次更新后,我们都在新的位置计算梯度,并继续沿负梯度方向移动。直到梯度变得非常小(接近零),意味着我们来到了一个“平地”(临界点),此时目标函数值不再显著下降,算法收敛。当然,这个比喻还有一个前提:下山路上不能有“悬崖”,即目标函数必须处处可导,否则“探坡度”这一步就无从做起。
这个过程可以用以下代码概念来示意(注意,这是为了说明流程的伪代码,并非真实训练循环):
# 梯度下降伪代码示意
初始化网络权重 w
设置学习率 η
设置最大迭代次数或收敛阈值
for epoch in range(最大迭代次数):
# 前向传播:计算当前权重下的网络输出和损失 J
predictions = forward_pass(w, training_data)
loss = compute_loss(predictions, labels)
# 反向传播:计算损失 J 关于所有权重 w 的梯度 ∇J(w)
gradients = compute_gradients(w, training_data, labels) # 这涉及到后续要学的反向传播算法
# 梯度下降更新:沿负梯度方向更新权重
w = w - η * gradients
# 检查是否收敛(例如,梯度范数小于某个阈值,或损失不再下降)
if converged(gradients, loss):
break目标函数的可导性要求:不能有“悬崖”
在“蒙眼下山”的比喻中,我们最后提到“可不能有悬崖”。这对应到数学上,就是要求我们的目标函数 J(w) 必须是处处可导的,至少在我们搜索的路径上是可导的。
为什么?因为梯度下降法依赖于计算梯度 ∇J(w)。如果函数在某点不可导(比如有个“悬崖”或“尖刺”),那么在该点梯度就没有定义,算法就无法决定下一步该往哪里走。
在神经网络中,目标函数 J(w) 的可导性主要取决于激活函数。回顾神经元输出公式:输出 = f(加权和 + 偏置),其中 f 就是激活函数。J(w) 的计算链条中包含了这个激活函数。
因此,为了能够使用梯度下降法,我们选择的激活函数必须是可导的。这正是早期神经网络普遍使用 Sigmoid 函数 f(x) = 1 / (1 + e^{-x}) 或 tanh 函数的重要原因之一。它们在定义域内是平滑且处处可导的。
例如,Sigmoid 函数的导数有一个很好的性质:f'(x) = f(x) * (1 - f(x)),这在其后续的反向传播计算中非常方便。
思考:如果使用一个不可导的函数(比如阶跃函数)作为激活函数,梯度下降法就会失效。这也是为什么在深度学习时代,尽管 ReLU (Rectified Linear Unit) 函数在
x=0处不可导,但在实践中我们通常将其在该点的导数定义为 0 或 1,从而使其能够应用于基于梯度的优化。
📝 动手练一练
- 概念辨析:梯度下降法中,为什么我们选择沿负梯度方向更新参数,而不是正梯度方向或其他随机方向?如果学习率设置得过大,可能会导致哪两种典型问题?
👉 点击查看参考答案
- 选择负梯度方向的原因:梯度方向是函数值增长最快的方向。为了最小化目标函数(损失函数),我们自然需要朝函数值减少最快的方向移动,即梯度的反方向,也就是负梯度方向。这是在当前点附近下降最快的方向。
- 学习率过大的问题:
- 震荡(Oscillation):参数更新步长太大,可能会在最优解附近来回跳跃,无法稳定收敛。
- 发散(Divergence):步长极大时,一次更新可能使损失值暴增,从当前的“山谷”跳到另一个更高的“山坡”,导致训练完全失败,损失值趋于无穷大。
- 手算理解:假设一个极其简单的“网络”,只有一个参数
w,其目标函数定义为J(w) = (w - 5)^2。显然,当w = 5时,J取得最小值 0。- a) 计算
J(w)在w = 0处的梯度∇J(0)。 - b) 设学习率
η = 0.1,使用梯度下降公式w_new = w_old - η * ∇J(w_old),计算从初始点w0 = 0开始,经过一次更新后的w1。 - c) 计算
w1处的函数值J(w1),并与J(0)比较,是否下降了?
- a) 计算
👉 点击查看参考答案
a) 首先求
J(w)的导数(对于单变量就是梯度):J(w) = (w-5)^2∇J(w) = dJ/dw = 2*(w-5)在w=0处:∇J(0) = 2*(0-5) = -10b) 应用梯度下降更新:
w1 = w0 - η * ∇J(w0) = 0 - 0.1 * (-10) = 1c) 计算函数值:
J(0) = (0-5)^2 = 25J(1) = (1-5)^2 = 16显然,J(1) = 16 < J(0) = 25,经过一次梯度下降更新,目标函数值确实下降了,参数w从 0 向最优值 5 靠近了一步。
本章小结
本节我们建立了神经网络学习的核心优化框架。我们首先定义了衡量网络性能的目标函数(损失函数),通常采用均方误差等形式。然后,我们指出了直接优化该函数的困难性,从而引入了梯度下降这一迭代优化算法。
梯度下降法通过计算目标函数关于参数的梯度,并沿负梯度方向以一定的学习率更新参数,逐步逼近函数的最小值点。学习率的选择至关重要,需要在收敛速度和稳定性之间取得平衡。同时,为了能够计算梯度,整个网络(特别是激活函数)构成的函数必须是可导的。
今天训练深度网络时,几乎不会再使用这种“朴素”的批量梯度下降,而是使用它的变体:小批量随机梯度下降(mini-batch SGD)、带动量的 SGD、以及 Adam 等自适应方法。但它们的更新骨架仍然是本节这条 ,区别只在于“用多少样本估梯度”“要不要记住历史方向”“每个参数是否用不同的步长”。把这条骨架理解透,后续的优化器就只是在这上面做加法。
📋 行动清单
- 理解目标函数的意义:能够说出为什么需要目标函数,以及均方误差是如何衡量网络输出误差的。
- 掌握梯度下降的比喻与步骤:能够用自己的话复述“蒙眼下山”的比喻,并说明梯度、负梯度、学习率在其中的作用。
- 认识学习率的影响:明确学习率过大或过小分别会导致什么问题,理解其作为关键超参数的地位。
—— 小象教研组