微分学的核心思想是用熟悉且简单的函数对复杂函数进行局部逼近。
常用作逼近的简单函数包括:
极限的表达方式:
自然语言:当 x x x趋向于 a a a时, f ( x ) f(x) f(x)的极限是 L L L。
数学符号:
lim x → a f ( x ) = L \lim\limits_{x \to a}f(x)=L x→alimf(x)=L
标准语言:对于任意的 ϵ > 0 \epsilon \gt 0 ϵ>0,存在一个 δ > 0 \delta \gt 0 δ>0,对于任意的 x ∈ ( a + δ , a + δ ) x \in\ (a+\delta ,a+\delta ) x∈ (a+δ,a+δ),均有 ∣ f ( x ) − L ∣ < ϵ \vert f(x)-L\vert \lt \epsilon ∣f(x)−L∣<ϵ。
无穷小:一般把趋于零的极限成为无穷小。
无穷小阶数:趋于零的速度越快的无穷小,其阶数越高。比如: x n , x → 0 x^n,x \to\ 0 xn,x→ 0趋于零的速度还快的无穷小记为 o ( x n ) o(x^n) o(xn)。
两边夹定理:如果 f ( x ) < g ( x ) < h ( x ) f(x) \lt g(x) \lt h(x) f(x)<g(x)<h(x),而且这三个函数都在 a a a处有极限,那么则有:
lim x → a f ( x ) ≤ lim x → a g ( x ) ≤ lim x → a h ( x ) \lim \limits_{x\to\ a}f(x) \le \lim \limits_{x\to\ a}g(x) \le \lim \limits_{x\to\ a}h(x) x→ alimf(x)≤x→ alimg(x)≤x→ alimh(x)
重要极限(两边夹定理应用):
三角函数
lim x → 0 sin ( x ) x = 1 \lim \limits_{x \to\ 0} \frac{\sin(x)}{x} =1 x→ 0limxsin(x)=1
自然对数底数
lim n → ∞ ( 1 + 1 n ) n = e \lim \limits_{n \to\ \infty}\left(1+\frac{1}{n}\right)^n =e n→ ∞lim(1+n1)n=e
指数函数
lim x → 0 e x − 1 x = 1 \lim \limits_{x \to\ 0} \frac{e^x-1}{x} =1 x→ 0limxex−1=1
微分学的核心思想就是逼近。
一阶导数:
f ´ ( x ) = lim Δ → 0 f ( Δ x + x ) − f ( x ) Δ x f^´(x)=\lim \limits_{\Delta \to\ 0}\frac{f(\Delta x+x)-f(x)}{\Delta x} f´(x)=Δ→ 0limΔxf(Δx+x)−f(x)
对函数进行线性逼近:
假设函数 f ( x ) f(x) f(x)是一个可微函数, x 0 x_0 x0是定义域中的一个点,那么则有:
f ( x 0 + Δ x ) = f ( x 0 ) + Δ ⋅ d f ( x 0 ) d x + o ( Δ ) f(x_0+\Delta x)=f(x_0)+\Delta ·\frac{df(x_0)}{dx}+o(\Delta) f(x0+Δx)=f(x0)+Δ⋅dxdf(x0)+o(Δ)
注:现在数学符号常用如下记号:
d x = Δ d f ( x 0 ) = f ( x 0 + Δ x ) − f ( x 0 ) + o ( Δ ) dx=\Delta \\[2ex] df(x_0)=f(x_0+\Delta x)-f(x_0)+o(\Delta) dx=Δdf(x0)=f(x0+Δx)−f(x0)+o(Δ)
故上面的微分公式可以写成:
d f ( x 0 ) = f ( x 0 ) d x ⋅ d x df(x_0)=\frac{f(x_0)}{dx}·dx df(x0)=dxf(x0)⋅dx
常见函数的导数:
多项式函数:
d x n d x = n ⋅ x n − 1 \frac{dx^n}{dx}=n·x^{n-1} dxdxn=n⋅xn−1
三角函数:
d sin ( x ) d x = cos ( x ) \frac{d\sin(x)}{dx}=\cos(x) dxdsin(x)=cos(x)
指数函数:
d e x d x = e x \frac{de^x}{dx}=e^x dxdex=ex
一元微分学的顶峰:Taylor级数(对函数进行高阶逼近)
Taylor级数(对函数进行高阶逼近)
如果一个函数 f ( x ) f(x) f(x)是 n n n阶可微函数,那么则有:
f ( x 0 + Δ x ) = f ( x 0 ) + f ( 1 ) ( x 0 ) ⋅ Δ x + 1 2 f ( 2 ) ( x ) ⋅ Δ x 2 + . . . + 1 n ! f ( n ) ( x 0 ) Δ x n + o ( Δ x n ) f(x_0+\Delta x)=f(x_0)+f^{(1)}(x_0)·\Delta x+\frac{1}{2}f^{(2)}(x)·\Delta x^2+...+\frac{1}{n!}f^{(n)}(x_0)\Delta x^n+o(\Delta x^n) f(x0+Δx)=f(x0)+f(1)(x0)⋅Δx+21f(2)(x)⋅Δx2+...+n!1f(n)(x0)Δxn+o(Δxn)
函数 f ( x ) f(x) f(x)的 n n n阶Taylor级数就是与 f ( x ) f(x) f(x)拥有相同前 n n n阶导数的 n n n阶多项式。
当 n = 2 n=2 n=2时,Taylor级数就成为一个二次逼近:
对于2阶可微函数 f ( x ) f(x) f(x):
f ( x 0 + Δ x ) = f ( x 0 ) + f ( 1 ) ( x 0 ) ⋅ Δ x + 1 2 f ( 2 ) ( x ) ⋅ Δ x 2 + o ( Δ x 2 ) f(x_0+\Delta x)=f(x_0)+f^{(1)}(x_0)·\Delta x+\frac{1}{2}f^{(2)}(x)·\Delta x^2+o(\Delta x^2) f(x0+Δx)=f(x0)+f(1)(x0)⋅Δx+21f(2)(x)⋅Δx2+o(Δx2)
而这构成了牛顿法的基础。
对于一个二元函数 f ( x , y ) f(x,y) f(x,y),偏导数定义为:
∂ x f ( x , y ) = ∂ ∂ x f ( x , y ) = lim Δ x → 0 f ( x + Δ x , y ) − f ( x , y ) Δ x ∂ y f ( x , y ) = ∂ ∂ y f ( x , y ) = lim Δ y → 0 f ( x + Δ y , y ) − f ( x , y ) Δ y \partial_xf(x,y)=\frac{\partial}{\partial x}f(x,y)=\lim\limits_{\Delta_x \to\ 0}\frac{f(x+\Delta_x,y)-f(x,y)}{\Delta_x} \\[3ex] \partial_yf(x,y)=\frac{\partial}{\partial y}f(x,y)=\lim\limits_{\Delta_y \to\ 0}\frac{f(x+\Delta_y,y)-f(x,y)}{\Delta_y} ∂xf(x,y)=∂x∂f(x,y)=Δx→ 0limΔxf(x+Δx,y)−f(x,y)∂yf(x,y)=∂y∂f(x,y)=Δy→ 0limΔyf(x+Δy,y)−f(x,y)
沿着方向 v = ( a , b ) v=(a,b) v=(a,b)的方向导数为:
∇ v f ( x , y ) = lim Δ → 0 f ( x + Δ ⋅ a , y + Δ ⋅ b ) − f ( x , y ) Δ \nabla_vf(x,y)=\lim\limits_{\Delta \to\ 0}\frac{f(x+\Delta·a,y+\Delta·b)-f(x,y)}{\Delta} ∇vf(x,y)=Δ→ 0limΔf(x+Δ⋅a,y+Δ⋅b)−f(x,y)
偏导数:沿着坐标轴方向的方向导数。
多元可微函数,一个二元函数 f ( x , y ) f(x,y) f(x,y)一阶可微,如果存在 L x , L y L_x,L_y Lx,Ly使得:
f ( x + Δ x , y + Δ y ) = f ( x , y ) + L x ⋅ Δ x + L y ⋅ Δ y + o ( ∣ Δ x ∣ + ∣ Δ y ∣ ) f(x+\Delta x,y+\Delta y)=f(x,y)+L_x·\Delta_x+L_y·\Delta_y+o(\vert\Delta_x\vert+\vert\Delta_y\vert) f(x+Δx,y+Δy)=f(x,y)+Lx⋅Δx+Ly⋅Δy+o(∣Δx∣+∣Δy∣)
梯度(以二元函数为例)
对于可微函数 f ( x , y ) f(x,y) f(x,y),梯度的定义为:
∇ f ( x , y ) = ( ∂ x f , ∂ y f ) T \nabla f(x,y)=(\partial_xf,\partial_yf)^T ∇f(x,y)=(∂xf,∂yf)T
梯度的代数意义:其任意方向的偏导数可以由梯度来表示,如果 v = ( a , b ) v=(a,b) v=(a,b),则有:
∇ v f ( x , y ) = v ⋅ ∇ f ( x , y ) = a ∂ x f ( x , y ) + b ∂ y f ( x , y ) \nabla_v f(x,y)=v·\nabla f(x,y)=a\partial_xf(x,y)+b\partial_yf(x,y) ∇vf(x,y)=v⋅∇f(x,y)=a∂xf(x,y)+b∂yf(x,y)
梯度的几何意义:梯度方向是函数增长最快的方向
如果 J ( θ ) J(\theta) J(θ)是一个多元函数,在 θ 0 \theta_0 θ0点附近对于 J ( θ ) J(\theta) J(θ)做线性逼近:
J ( θ 0 + Δ θ ) = J ( θ 0 ) + Δ θ T ⋅ ∇ J ( θ 0 ) + o ( ∣ Δ θ ∣ ) J(\theta_0+\Delta_\theta)=J(\theta_0)+\Delta^T_\theta·\nabla J(\theta_0)+o(\vert\Delta_\theta\vert) J(θ0+Δθ)=J(θ0)+ΔθT⋅∇J(θ0)+o(∣Δθ∣)
上述线性逼近不能告诉我们极值点在上面地方,只能告诉我们极值点在什么方向。所以只能选取一个比较”小“的学习率 η \eta η来沿着这个方向走下去,并且得到梯度下降法的序列:
θ n = θ n − 1 − η n − 1 ∇ J ( θ n − 1 ) \theta_n=\theta_{n-1}-\eta_{n-1}\nabla J(\theta_{n-1}) θn=θn−1−ηn−1∇J(θn−1)
梯度下降法:对函数进行一阶逼近寻找函数下降最快的方向。 如同人下山一样,直至获得一个局部或者全局(损失函数是凸函数)最小值。
牛顿法:对函数进行二阶逼近,并且直接估计函数的极小值点。
f ( θ 0 + Δ θ ) = f ( θ 0 ) + Δ θ T ⋅ ∇ f ( θ 0 ) + 1 2 Δ θ T H f ( θ 0 ) Δ θ + o ( ∣ Δ θ ∣ 2 ) f(\theta_0+\Delta_\theta)=f(\theta_0)+\Delta^T_\theta·\nabla f(\theta_0)+\frac{1}{2}\Delta^T_\theta H f(\theta_0)\Delta_\theta+o(\vert\Delta_\theta\vert^2) f(θ0+Δθ)=f(θ0)+ΔθT⋅∇f(θ0)+21ΔθTHf(θ0)Δθ+o(∣Δθ∣2)
于是关于 Δ θ \Delta_\theta Δθ的梯度为:
Δ θ T ⋅ ∇ f ( θ 0 ) + H f ( θ 0 ) Δ θ + o ( ∣ Δ θ ∣ ) \Delta^T_\theta·\nabla f(\theta_0)+H f(\theta_0)\Delta_\theta+o(\vert\Delta_\theta\vert^) ΔθT⋅∇f(θ0)+Hf(θ0)Δθ+o(∣Δθ∣)
零点近似值为:
Δ θ = H f ( θ 0 ) − 1 ⋅ ∇ f ( θ ) \Delta_\theta=Hf(\theta_0)^{-1}·\nabla f(\theta) Δθ=Hf(θ0)−1⋅∇f(θ)
梯度计算
在机器学习和统计参数估计问题中目标函数经常是求和函数的形式:
J x ( θ ) = ∑ i J x i ( θ ) \begin{align} &J_x(\theta)=\sum\limits_iJ_{x_i}(\theta) \\[2ex] \end{align} Jx(θ)=i∑Jxi(θ)
其中每一个函数 J x i ( θ ) J_{x_i}(\theta) Jxi(θ)都对应一个样本 x i x_i xi。当样本量极大时,梯度的计算就会变得非常耗时耗力。
学习率选择
学习率选择过小会导致算法收敛很慢,学习率选择过大容易导致算法不收敛。
Q:为何沿着梯度负方向就是最速下降,即函数下降的速度最快?
在某个要优化的函数 f ( x ) f(x) f(x),在x点处沿方向 v v v 进行移动,到达 f ( x + v ) f(x+v) f(x+v) ,图示表示了移动过程:
上图显示了从A点,移动到B点的过程。那么 v v v 方向是什么的时候,局部下降的最快呢?
换成数学语言来说就是, f ( x + v ) − f ( x ) f(x+v)-f(x) f(x+v)−f(x)的值在 v v v是什么的时候,达到最大!
对 f ( x + v ) f(x+v) f(x+v)在 x x x处进行Taylor一阶展开有:
f ( x + v ) ≈ f ( x ) + ∇ f ( x ) T v f ( x ) − f ( x + v ) ≈ − ∇ f ( x ) T v f(x+v) \approx f(x)+\nabla f(x)^Tv \\[2ex] f(x)-f(x+v) \approx-\nabla f(x)^Tv f(x+v)≈f(x)+∇f(x)Tvf(x)−f(x+v)≈−∇f(x)Tv
则 f ( x + v ) − f ( x ) = d f ( x ) v f(x+v)-f(x)=d f(x)v f(x+v)−f(x)=df(x)v,可以得出: d f ( x ) v d f(x)v df(x)v 为函数值的变化量,注意的是 d f ( x ) d f(x) df(x) 和 v v v 均为向量, d f ( x ) v d f(x)v df(x)v 也就是两个向量进行点积,而向量进行点积的最大值,也就是两者共线的时候,也就是说 v v v 的方向和 d f ( x ) d f(x) df(x) 方向相同的时候,点积值最大,这个点积值也代表了从A点到B点的上升量。而 d f ( x ) df(x) df(x)正是代表函数值在 x x x处的梯度。所以梯度方向是函数局部上升最快的方向,也就证明了梯度的负方向是局部下降最快的方向。
随机梯度下降法主要是为了解决第一个问题:梯度计算。
梯度下降法分为三种类型:
需要在整个数据集上计算所有的梯度,所以批梯度下降法的速度会很慢,同时,批梯度下降法无法处理超出内存容量限制的数据集。批梯度下降法同样也不能在线更新模型,即在运行的过程中,不能增加新的样本。
# 批梯度下降法
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function, data, params)
params = params - learning_rate * params_grad
随机梯度下降法(SGD- stochastic gradient descent)
每次梯度计算只使用一个样本
#随机梯度下降法
for i in range(nb_epochs):
np.random.shuffle(data)
for example in data:
params_grad = evaluate_gradient(loss_function, example, params)
params = params - learning_rate * params_grad
小批量随机梯度下降法(mini batch SGD)
每次梯度计算使用一个小批量样本
# 小批量随机梯度下降法
for i in range(nb_epochs):
np.random.shuffle(data)
for batch in get_batches(data, batch_size=50):
params_grad = evaluate_gradient(loss_function, batch, params)
params = params - learning_rate * params_grad
随机梯度下降法的主要困难在于第二个问题:学习率的选择。
Q:为什么不适用牛顿法?
1.牛顿法要求计算目标函数的二阶导数(Hessian Matrix),在高维特征情形下这个矩阵非常巨大,计算和存储都成问题。
2.在使用小批量情形下,牛顿法对于二阶导数的估计噪声太大。
3.在目标函数非凸时,牛顿法更容易收敛到鞍点甚至最大值。
梯度下降法在狭长的隧道型函数上表现不佳,如下图所示:
动量法每次更新都吸收一部分上次更新的余势:
v t = γ v t − 1 + η ∇ θ J ( θ ) θ t = θ t − 1 − v t \begin{align} &v_t=\gamma v_{t-1}+\eta\nabla_\theta J(\theta) \\[2ex] &\theta_t=\theta_{t-1}-v_t \end{align} vt=γvt−1+η∇θJ(θ)θt=θt−1−vt
这样主体方向的更新就得了更大的保留,从而效果被不断放大。
物理上就像是推一个很重的铁球下山,因为铁球保持了下降主体方向的动量,所以在隧道上沿两侧震荡次数会越来越少。
动量法的问题:
从山顶推下的铁球会越滚越快,以至于到了山底停不下来。
我们希望算法聪明一点,可以在达到底部之前就自己刹车了。利用主体下降方向提供的先见之明,预判自己下一步的位置,并到预判位置计算梯度。
v t = γ v t − 1 + η ∇ θ J ( θ − γ v t − 1 ) θ = θ − v t \begin{align} &v_t=\gamma v_{t-1}+\eta\nabla_\theta J(\theta-\gamma v_{t-1}) \\[2ex] &\theta=\theta-v_t \end{align} vt=γvt−1+η∇θJ(θ−γvt−1)θ=θ−vt
动量法首先计算当前的梯度值(图3中的小的蓝色向量),然后在更新的累积梯度(大的蓝色向量)方向上前进一大步,Nesterov加速梯度下降法NAG首先在先前累积梯度(棕色的向量)方向上前进一大步,计算梯度值,然后做一个修正(绿色的向量)。这个具有预见性的更新防止我们前进得太快,同时增强了算法的响应能力,这一点在很多的任务中对于RNN的性能提升有着重要的意义。
梯度下降法在每一步对每一个参数使用相同的学习率,这种一刀切的做法不能有效利用每一个数据集自身的特点。
Adagrad是一种基自动调整学习率的方法:
为了实现对于更新频繁的参数使用较小的学习率, Adagrad对每个参数历史上的每次更新进行叠加,并以此来做下一次更新的惩罚。
梯度:
g t , i = ∇ θ J ( θ i ) g_{t,i}=\nabla_\theta J(\theta_i) gt,i=∇θJ(θi)
梯度历史矩阵: G t G_t Gt为对角矩阵,其中 G t , i i = ∑ k g k , i 2 G_{t,ii}=\sum_k g^2_{k,i} Gt,ii=∑kgk,i2
参数更新:
θ t + 1 , i = θ t , i − η G t , i i + ϵ ⋅ g t , i \theta_{t+1,i}=\theta_{t,i}-\frac{\eta}{\sqrt{G_{t,ii}+\epsilon}}·g_{t,i} θt+1,i=θt,i−Gt,ii+ϵη⋅gt,i
Adagrad的一个主要缺点是它在分母中累加梯度的平方:由于没增加一个正项,在整个训练过程中,累加的和会持续增长。这会导致学习率变小以至于最终变得无限小,在学习率无限小时,Adagrad算法将无法取得额外的信息。
Adagrad的问题:随着训练的进行,学习速率快速单调递减
在Adadelta中,无需存储先前的 w w w个平方梯度,而是将梯度的平方递归地表示成所有历史梯度平方的均值。
定义平均:
E [ g 2 ] t = γ E [ g 2 ] t − 1 + ( 1 − γ ) g t 2 E[g^2]_t=\gamma E[g^2]_{t-1}+(1-\gamma)g^2_t E[g2]t=γE[g2]t−1+(1−γ)gt2
参数更新方式:
θ t + 1 , i = θ t , i − η E [ g 2 ] t , i i + ϵ ⋅ g t , i \theta_{t+1,i}=\theta_{t,i}-\frac{\eta}{\sqrt{E[g^2]_{t,ii}+\epsilon}}·g_{t,i} θt+1,i=θt,i−E[g2]t,ii+ϵη⋅gt,i
Adadelta以及一般梯度下降法的另一个问题在于:梯度与参数的单位不匹配
Adadelta使用参数更新的移动平均来取代学习率 η \eta η,于是参数更新法则为:
θ t + 1 , i = θ t , i − E [ Δ θ ] t − 1 E [ g 2 ] t , i i + ϵ ⋅ g t , i \theta_{t+1,i}=\theta_{t,i}-\frac{\sqrt{E[\Delta_\theta]_{t-1}}}{\sqrt{E[g^2]_{t,ii}+\epsilon}}·g_{t,i} θt+1,i=θt,i−E[g2]t,ii+ϵE[Δθ]t−1⋅gt,i
如果把Adadelta里面梯度的平方和看成梯度的二阶矩,那么梯度自身的求和就是一阶矩。
Adam算法在Adadelta的二阶矩基础上又引入了一阶矩,而一阶矩,其实就类似于动量法里的动量
m t = β 1 m t − 1 + ( 1 − β 1 ) g t v t = β 2 m t − 1 + ( 1 − β 2 ) g t 2 \begin{align} m_t=\beta_1m_{t-1}+(1-\beta_1)g_t \\[2ex] v_t=\beta_2m_{t-1}+(1-\beta_2)g^2_t \end{align} mt=β1mt−1+(1−β1)gtvt=β2mt−1+(1−β2)gt2
参数更新法则:
θ t + 1 = θ t − η v ^ t + ϵ m ^ t \theta_{t+1}=\theta_{t}-\frac{\eta}{\sqrt{\hat v_t}+\epsilon}\hat m_t θt+1=θt−v^t+ϵηm^t
注:实际操作中 v t v_t vt和 m t m_t mt采取更好的无偏估计,来避免前几次更新时数据不足的问题。
本文仅作为个人学习记录使用, 不用于商业用途, 谢谢您的理解合作。