百度云建网站,微信电脑网页版,沈阳中讯国际网站建设,网站服务器如何维护深度学习与优化算法原理
优化函数与深度学习
在一个深度学习问题中#xff0c;通常需要预先定义一个损失函数。有了损失函数以后#xff0c;使用优化算法试图将其最小化。
在优化中#xff0c;这样的损失函数通常被称作优化问题的目标函数#xff08;objective function…深度学习与优化算法原理
优化函数与深度学习
在一个深度学习问题中通常需要预先定义一个损失函数。有了损失函数以后使用优化算法试图将其最小化。
在优化中这样的损失函数通常被称作优化问题的目标函数objective function。
依据惯例优化算法通常只考虑最小化目标函数。其实任何最大化问题都可以很容易地转化为最小化问题只需令目标函数的相反数为新的目标函数即可。
虽然优化为深度学习提供了最小化损失函数的方法但本质上优化与深度学习的目标是有区别的。
训练误差和泛化误差是不同的
优化算法的目标函数通常是一个基于训练数据集的损失函数优化的目标在于降低训练误差。而深度学习的目标在于降低泛化误差。为了降低泛化误差除了使用优化算法降低训练误差以外还需要注意应对过拟合。
深度学习优化的问题
深度学习中绝大多数目标函数都很复杂。因此很多优化问题并不存在解析解而需要使用基于数值方法的优化算法找到近似解即数值解。为了求得最小化目标函数的数值解我们将通过优化算法有限次迭代模型参数来尽可能降低损失函数的值。
常见的优化在深度学习中的挑战有局部最小值和鞍点等。
局部最小值
对于目标函数f(x)f(x)f(x)如果f(x)f(x)f(x)在xxx上的值比在xxx邻近的其他点的值更小那么f(x)f(x)f(x)可能是一个局部最小值local minimum。如果f(x)f(x)f(x)在xxx上的值是目标函数在整个定义域上的最小值那么f(x)f(x)f(x)是全局最小值global minimum。
举个例子给定函数
f(x)x⋅cos(πx),−1.0≤x≤2.0,f(x) x \cdot \text{cos}(\pi x), \qquad -1.0 \leq x \leq 2.0, f(x)x⋅cos(πx),−1.0≤x≤2.0,
我们可以大致找出该函数的局部最小值和全局最小值的位置。需要注意的是图中箭头所指示的只是大致位置。 %matplotlib inline
import sys
sys.path.append(..)
from mpl_toolkits import mplot3d # 三维画图
from matplotlib import pyplot as plt
import numpy as npdef f(x):return x * np.cos(np.pi * x)def set_figsize(figsize(3.5, 2.5)):use_svg_display()# 设置图的尺寸plt.rcParams[figure.figsize] figsize
set_figsize((4.5, 2.5))
x np.arange(-1.0, 2.0, 0.1)
fig, plt.plot(x, f(x))
fig.axes.annotate(local minimum, xy(-0.3, -0.25), xytext(-0.77, -1.0),arrowpropsdict(arrowstyle-))
fig.axes.annotate(global minimum, xy(1.1, -0.95), xytext(0.6, 0.8),arrowpropsdict(arrowstyle-))
plt.xlabel(x)
plt.ylabel(f(x));深度学习模型的目标函数可能有若干局部最优值。当一个优化问题的数值解在局部最优解附近时
由于目标函数有关解的梯度接近或变成零最终迭代求得的数值解可能只令目标函数局部最小化而非全局最小化
鞍点
梯度接近或变成零可能是由于当前解在局部最优解附近造成的另一种可能性是当前解在鞍点saddle point附近。
例如给定函数
f(x)x3,f(x) x^3,f(x)x3,
我们可以找出该函数的鞍点位置。
x np.arange(-2.0, 2.0, 0.1)
fig, plt.plot(x, x**3)
fig.axes.annotate(saddle point, xy(0, -0.2), xytext(-0.52, -5.0),arrowpropsdict(arrowstyle-))
plt.xlabel(x)
plt.ylabel(f(x));又例如下面这个定义在二维空间的函数的例子
f(x,y)x2−y2.f(x, y) x^2 - y^2.f(x,y)x2−y2.
我们可以找出该函数的鞍点位置。
x, y np.mgrid[-1: 1: 31j, -1: 1: 31j]
z x**2 - y**2ax plt.figure().add_subplot(111, projection3d)
ax.plot_wireframe(x, y, z, **{rstride: 2, cstride: 2})
ax.plot([0], [0], [0], rx)
ticks [-1, 0, 1]
plt.xticks(ticks)
plt.yticks(ticks)
ax.set_zticks(ticks)
plt.xlabel(x)
plt.ylabel(y);该函数看起来像一个马鞍而鞍点恰好是马鞍上可坐区域的中心在图的鞍点位置目标函数在xxx轴方向上是局部最小值但在yyy轴方向上是局部最大值。
假设一个函数的输入为kkk维向量输出为标量那么它的海森矩阵Hessian matrix有kkk个特征值。该函数在梯度为0的位置上可能是局部最小值、局部最大值或者鞍点。
当函数的海森矩阵在梯度为零的位置上的特征值全为正时该函数得到局部最小值。当函数的海森矩阵在梯度为零的位置上的特征值全为负时该函数得到局部最大值。当函数的海森矩阵在梯度为零的位置上的特征值有正有负时该函数得到鞍点。
随机矩阵理论告诉我们对于一个大的高斯随机矩阵来说任一特征值是正或者是负的概率都是0.5。那么以上第一种情况的概率为 0.5k0.5^k0.5k。由于深度学习模型参数通常都是高维的kkk很大目标函数的鞍点通常比局部最小值更常见。
在深度学习中虽然找到目标函数的全局最优解很难但这并非是必要的。
梯度下降和随机梯度下降
虽然梯度下降在深度学习中很少被直接使用但理解梯度的意义以及沿着梯度反方向更新自变量可能降低目标函数值的原因是学习后续优化算法的基础。
一维梯度下降
先以简单的一维梯度下降为例。
假设连续可导的函数f:R→Rf: \mathbb{R} \rightarrow \mathbb{R}f:R→R的输入和输出都是标量给定绝对值足够小的数ϵ\epsilonϵ
根据泰勒展开公式我们得到以下的近似
f(xϵ)≈f(x)ϵf′(x).f(x \epsilon) \approx f(x) \epsilon f(x) .f(xϵ)≈f(x)ϵf′(x).
这里f′(x)f(x)f′(x)是函数fff在xxx处的梯度。一维函数的梯度是一个标量也称导数。
接下来找到一个常数η0\eta 0η0使得∣ηf′(x)∣\left|\eta f(x)\right|∣ηf′(x)∣足够小那么可以将ϵ\epsilonϵ替换为−ηf′(x)-\eta f(x)−ηf′(x)并得到
f(x−ηf′(x))≈f(x)−ηf′(x)2.f(x - \eta f(x)) \approx f(x) - \eta f(x)^2.f(x−ηf′(x))≈f(x)−ηf′(x)2.
如果导数f′(x)≠0f(x) \neq 0f′(x)0那么ηf′(x)20\eta f(x)^20ηf′(x)20所以
f(x−ηf′(x))≲f(x).f(x - \eta f(x)) \lesssim f(x).f(x−ηf′(x))≲f(x).
这意味着如果通过
x←x−ηf′(x)x \leftarrow x - \eta f(x)x←x−ηf′(x)
来迭代xxx函数f(x)f(x)f(x)的值可能会降低。因此在梯度下降中我们先选取一个初始值xxx和常数η0\eta 0η0然后不断通过上式来迭代xxx直到达到停止条件例如f′(x)2f(x)^2f′(x)2的值已足够小或迭代次数已达到某个值。
下面以目标函数f(x)x2f(x)x^2f(x)x2为例来看一看梯度下降是如何工作的。虽然很明显最小化f(x)f(x)f(x)的解为x0x0x0这里依然使用这个简单函数来观察xxx是如何被迭代的。
%matplotlib inline
import numpy as np
import torch
import math
import sys
sys.path.append(..) def gd(eta):x 10results [x]for i in range(10):x - eta * 2 * x # f(x) x * x的导数为f(x) 2 * xresults.append(x)print(epoch 10, x:, x)return resultsres gd(0.2)使用x10x10x10作为初始值并设η0.2\eta0.2η0.2。使用梯度下降对xxx迭代10次可见最终xxx的值较接近最优解。
绘制出自变量xxx的迭代轨迹
def show_trace(res):n max(abs(min(res)), abs(max(res)), 10)f_line np.arange(-n, n, 0.1)set_figsize()plt.plot(f_line, [x * x for x in f_line])plt.plot(res, [x * x for x in res], -o)plt.xlabel(x)plt.ylabel(f(x))show_trace(res)学习率
上述梯度下降算法中的正数η\etaη通常叫作学习率。这是一个超参数需要人工设定。如果使用过小的学习率会导致xxx更新缓慢从而需要更多的迭代才能得到较好的解。
下面展示使用学习率η0.05\eta0.05η0.05时自变量xxx的迭代轨迹
show_trace(gd(0.05))如果使用过大的学习率∣ηf′(x)∣\left|\eta f(x)\right|∣ηf′(x)∣可能会过大从而使前面提到的一阶泰勒展开公式不再成立这时我们无法保证迭代xxx会降低f(x)f(x)f(x)的值。
举个例子当设学习率η1.1\eta1.1η1.1时可以看到xxx不断越过overshoot最优解x0x0x0并逐渐发散。
show_trace(gd(1.1))维度增加多维梯度下降
在了解了一维梯度下降之后我们再考虑一种更广义的情况
目标函数的输入为向量输出为标量。
假设目标函数f:Rd→Rf: \mathbb{R}^d \rightarrow \mathbb{R}f:Rd→R的输入是一个ddd维向量x[x1,x2,…,xd]⊤\boldsymbol{x} [x_1, x_2, \ldots, x_d]^\topx[x1,x2,…,xd]⊤。目标函数f(x)f(\boldsymbol{x})f(x)有关x\boldsymbol{x}x的梯度是一个由ddd个偏导数组成的向量
∇xf(x)[∂f(x)∂x1,∂f(x)∂x2,…,∂f(x)∂xd]⊤.\nabla_{\boldsymbol{x}} f(\boldsymbol{x}) \bigg[\frac{\partial f(\boldsymbol{x})}{\partial x_1}, \frac{\partial f(\boldsymbol{x})}{\partial x_2}, \ldots, \frac{\partial f(\boldsymbol{x})}{\partial x_d}\bigg]^\top.∇xf(x)[∂x1∂f(x),∂x2∂f(x),…,∂xd∂f(x)]⊤.
为表示简洁我们用∇f(x)\nabla f(\boldsymbol{x})∇f(x)代替∇xf(x)\nabla_{\boldsymbol{x}} f(\boldsymbol{x})∇xf(x)。梯度中每个偏导数元素∂f(x)/∂xi\partial f(\boldsymbol{x})/\partial x_i∂f(x)/∂xi代表着fff在x\boldsymbol{x}x有关输入xix_ixi的变化率。为了测量fff沿着单位向量u\boldsymbol{u}u即∣u∣1|\boldsymbol{u}|1∣u∣1方向上的变化率在多元微积分中我们定义fff在x\boldsymbol{x}x上沿着u\boldsymbol{u}u方向的方向导数为
Duf(x)limh→0f(xhu)−f(x)h.\text{D}_{\boldsymbol{u}} f(\boldsymbol{x}) \lim_{h \rightarrow 0} \frac{f(\boldsymbol{x} h_ \boldsymbol{u}) - f(\boldsymbol{x})}{h}.Duf(x)h→0limhf(xhu)−f(x).
依据方向导数性质以上方向导数可以改写为
Duf(x)∇f(x)⋅u(向量相乘)\text{D}_{\boldsymbol{u}} f(\boldsymbol{x}) \nabla f(\boldsymbol{x}) \cdot \boldsymbol{u}(向量相乘)Duf(x)∇f(x)⋅u(向量相乘)
方向导数Duf(x)\text{D}_{\boldsymbol{u}} f(\boldsymbol{x})Duf(x)给出了fff在x\boldsymbol{x}x上沿着所有可能方向的变化率。为了最小化fff我们希望找到fff能被降低最快的方向。因此我们可以通过单位向量u\boldsymbol{u}u来最小化方向导数Duf(x)\text{D}_{\boldsymbol{u}} f(\boldsymbol{x})Duf(x)。
由于Duf(x)∣∇f(x)∣⋅∣u∣⋅cos(θ)∣∇f(x)∣⋅cos(θ)\text{D}_{\boldsymbol{u}} f(\boldsymbol{x}) |\nabla f(\boldsymbol{x})| \cdot |\boldsymbol{u}| \cdot \text{cos} (\theta) |\nabla f(\boldsymbol{x})| \cdot \text{cos} (\theta)Duf(x)∣∇f(x)∣⋅∣u∣⋅cos(θ)∣∇f(x)∣⋅cos(θ) 其中θ\thetaθ为梯度∇f(x)\nabla f(\boldsymbol{x})∇f(x)和单位向量u\boldsymbol{u}u之间的夹角当θπ\theta \piθπ时cos(θ)\text{cos}(\theta)cos(θ)取得最小值−1-1−1。因此当u\boldsymbol{u}u在梯度方向∇f(x)\nabla f(\boldsymbol{x})∇f(x)的相反方向时方向导数Duf(x)\text{D}_{\boldsymbol{u}} f(\boldsymbol{x})Duf(x)被最小化。因此我们可能通过梯度下降算法来不断降低目标函数fff的值
x←x−η∇f(x).\boldsymbol{x} \leftarrow \boldsymbol{x} - \eta \nabla f(\boldsymbol{x}).x←x−η∇f(x).
同样其中η\etaη取正数称作学习率。
下面我们构造一个目标函数
输入为二维向量x[x1,x2]⊤\boldsymbol{x} [x_1, x_2]^\topx[x1,x2]⊤输出为标量f(x)x122x22f(\boldsymbol{x})x_1^22x_2^2f(x)x122x22。
那么梯度∇f(x)[2x1,4x2]⊤\nabla f(\boldsymbol{x}) [2x_1, 4x_2]^\top∇f(x)[2x1,4x2]⊤。我们将观察梯度下降从初始位置[−5,−2][-5,-2][−5,−2]开始对自变量x\boldsymbol{x}x的迭代轨迹。
先定义两个辅助函数第一个函数使用给定的自变量更新函数从初始位置[−5,−2][-5,-2][−5,−2]开始迭代自变量x\boldsymbol{x}x共20次第二个函数对自变量x\boldsymbol{x}x的迭代轨迹进行可视化。
def train_2d(trainer): x1, x2, s1, s2 -5, -2, 0, 0 # s1和s2是自变量状态本章后续几节会使用results [(x1, x2)]for i in range(20):x1, x2, s1, s2 trainer(x1, x2, s1, s2)results.append((x1, x2))print(epoch %d, x1 %f, x2 %f % (i 1, x1, x2))return resultsdef show_trace_2d(f, results): plt.plot(*zip(*results), -o, color#ff7f0e)x1, x2 np.meshgrid(np.arange(-5.5, 1.0, 0.1), np.arange(-3.0, 1.0, 0.1))plt.contour(x1, x2, f(x1, x2), colors#1f77b4)plt.xlabel(x1)plt.ylabel(x2)然后观察学习率为0.10.1时自变量的迭代轨迹。使用梯度下降对自变量xx迭代20次后可见最终xx的值较接近最优解[0,0][0,0]。
eta 0.1def f_2d(x1, x2): # 目标函数return x1 ** 2 2 * x2 ** 2def gd_2d(x1, x2, s1, s2):return (x1 - eta * 2 * x1, x2 - eta * 4 * x2, 0, 0)show_trace_2d(f_2d, train_2d(gd_2d))随机梯度下降
在深度学习里目标函数通常是训练数据集中有关各个样本的损失函数的平均。设fi(x)f_i(\boldsymbol{x})fi(x)是有关索引为iii的训练数据样本的损失函数nnn是训练数据样本数x\boldsymbol{x}x是模型的参数向量那么目标函数定义为
f(x)1n∑i1nfi(x).f(\boldsymbol{x}) \frac{1}{n} \sum_{i 1}^n f_i(\boldsymbol{x}).f(x)n1i1∑nfi(x).
目标函数在x\boldsymbol{x}x处的梯度计算为
∇f(x)1n∑i1n∇fi(x).\nabla f(\boldsymbol{x}) \frac{1}{n} \sum_{i 1}^n \nabla f_i(\boldsymbol{x}).∇f(x)n1i1∑n∇fi(x).
如果使用梯度下降每次自变量迭代的计算开销为O(n)\mathcal{O}(n)O(n)它随着nnn线性增长。因此当训练数据样本数很大时梯度下降每次迭代的计算开销很高。
随机梯度下降stochastic gradient descentSGD减少了每次迭代的计算开销。在随机梯度下降的每次迭代中我们随机均匀采样的一个样本索引i∈1,…,ni\in{1,\ldots,n}i∈1,…,n并计算梯度∇fi(x)\nabla f_i(\boldsymbol{x})∇fi(x)来迭代x\boldsymbol{x}x
x←x−η∇fi(x).\boldsymbol{x} \leftarrow \boldsymbol{x} - \eta \nabla f_i(\boldsymbol{x}).x←x−η∇fi(x).
这里η\etaη同样是学习率。可以看到每次迭代的计算开销从梯度下降的O(n)\mathcal{O}(n)O(n)降到了常数O(1)\mathcal{O}(1)O(1)。值得强调的是随机梯度∇fi(x)\nabla f_i(\boldsymbol{x})∇fi(x)是对梯度∇f(x)\nabla f(\boldsymbol{x})∇f(x)的无偏估计
Ei∇fi(x)1n∑i1n∇fi(x)∇f(x).E_i \nabla f_i(\boldsymbol{x}) \frac{1}{n} \sum_{i 1}^n \nabla f_i(\boldsymbol{x}) \nabla f(\boldsymbol{x}).Ei∇fi(x)n1i1∑n∇fi(x)∇f(x).
这意味着平均来说随机梯度是对梯度的一个良好的估计。
下面我们通过在梯度中添加均值为0的随机噪声来模拟随机梯度下降以此来比较它与梯度下降的区别。
def sgd_2d(x1, x2, s1, s2):return (x1 - eta * (2 * x1 np.random.normal(0.1)),x2 - eta * (4 * x2 np.random.normal(0.1)), 0, 0)show_trace_2d(f_2d, train_2d(sgd_2d))随机梯度下降中自变量的迭代轨迹相对于梯度下降中的来说更为曲折。这是由于实验所添加的噪声使模拟的随机梯度的准确度下降。在实际中这些噪声通常指训练数据集中的无意义的干扰。