最近我们被客户要求撰写关于GARCH的研究报告,包括一些图形和统计输出。本文考虑一些ARCH(p)过程,例如ARCH(1)。
其中
梯度下降算法是深度学习中使用非常广泛的优化算法,也是众多机器学习算法中最常用的优化方法。几乎当前每一个先进的(state-of-the-art)机器学习库或者深度学习库都会包括梯度下降算法的不同变种实现。但是,它们就像一个黑盒优化器,很难得到它们优缺点的实际解释。
首先介绍梯度下降算法的三种框架,然后介绍它们存在的问题和挑战,接着介绍如何进行改进来解决存在的问题即算法的优化。
一、梯度下降算法三大框架
-
批量梯度下降(Batch gradient descent)
旨在每次使用全量的训练集样本来更新模型参数,即:θ=θ−η⋅∇θJ(θ)
伪码如下:
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function,data,params)
params = params - learning_rate * params_grad
nb_epochs是用户输入的最大迭代次数。使用全量的训练集样本计算损失函数loss_function的梯度params_grad,然后使用学习速率learning_rate朝着梯度相反方向去更新模型的每一个参数params。
批量梯度下降每次学习都使用整个训练集,因此其优点在于每次更新都会朝着正确的方向进行,最后能够保证收敛于极值点(凸函数收敛于全局极值点,非凸函数可能会收敛于局部极值点,属于凸理论的问题了),但是其缺点在于每次学习时间过长,并且如果训练集很大以至于需要消耗大量的内存,并且全量梯度下降不能进行在线模型参数更新。
-
随机梯度下降(Stochastic gradient descent)
旨在每次从训练集中随机选择一个样本来进行学习,即:θ=θ−η⋅∇θJ(θ;xi;yi)
伪码如下:
for i in range(nb_epochs):
np.random.shuffle(data)
for example in data:
params_grad = evaluate_gradient(loss_functon,example,params)
params = params - learning_rate * params_grad
批量梯度下降算法每次都会使用全部训练样本,因此这些计算是冗余的,因为每次都使用完全相同的样本集。而随机梯度下降算法每次只随机选择一个样本来更新模型参数,因此每次的学习是非常快速的,并且可以进行在线更新。
我们可以对不同的参数方案和他们如何快速优化有一个直观的认识:特别观察一下SGD,红色的那条线,从图中可以看出SGD实际上是所有方法中最慢的一个,所以在实际中很少应用它,我们可以使用更好的方案。
二、Challenges
虽然梯度下降算法效果很好,并广泛使用,但是也存在着问题和挑战需要解决:
1. 选择一个合理的学习速率很难。如果学习速率过小,则会导致收敛速度很慢;如果学习速率过大,那么就会阻碍收敛,即在极值点附近会震荡。
学习速率调整(又称学习速率调度,Learning rate schedules),在每次更新过程中,改变学习速率,如退火。一般使用某种事先设定的策略或者在每次迭代中衰减一个较小的阈值。无论哪种调整方法,都需要事先进行固定设置,这便无法自适应每次学习的数据集特点。
2.模型所有的参数每次更新都是使用相同的学习速率。如果数据特征是稀疏的或者每个特征有着不同的取值统计特征与空间,那么便不能在每次更新中每个参数使用相同的学习速率,那些很少出现的特征应该使用一个相对较大的学习速率。
3.对于非凸目标函数,容易陷入那些次优的局部极值点中,如在神经网路中。那么如何避免呢。而更严重的问题不是局部极值点,而是鞍点。
三、梯度下降优化算法
-
Momentum
如果把要优化的目标函数看成山谷的话,可以把要优化的参数看成滚下山的石头,参数随机化为一个随机数可以看做在山谷的某个位置以0速度开始往下滚。目标函数的梯度可以看做给石头施加的力,由力学定律知:F=m∗a,所以梯度与石头下滚的加速度成正比。因而,梯度直接影响速度,速度的累加得到石头的位置,对这个物理过程进行建模,可以得到参数更新过程为
# Momentum update
v = momentum * v - learning_rate * dx # integrate velocity
x += v # integrate position
代码中v指代速度,其计算过程中有一个超参数momentum,称为动量(momentum)。虽然名字为动量,其物理意义更接近于摩擦,其可以降低速度值,降低了系统的动能,防止石头在山谷的最底部不能停止情况的发生。如果没有momentum * v,那么小球就永远都不会停下了,会在平面上滚动,不会有能量的损失,损失函数就很难最小化。动量的取值范围通常为[0.5, 0.9, 0.95, 0.99],一种常见的做法是在迭代开始时将其设为0.5,在一定的迭代次数(epoch)后,将其值更新为0.99。
加上动量项就像从山顶滚下一个球,球往下滚的时候累积了前面的动量(动量不断增加),因此速度变得越来越快,直到到达终点。同理,在更新模型参数时,对于那些当前的梯度方向与上一次梯度方向相同的参数,那么进行加强,即这些方向上更快了;对于那些当前的梯度方向与上一次梯度方向不同的参数,那么进行削减,即这些方向上减慢了。即在陡峭的方向上削弱这些动荡,在一致的浅的方向激励此过程。因此可以获得更快的收敛速度与减少振荡。
有一个高斯白噪声 .
> for(t in 3:n){ + sigma2\[t\]=w+a1\*epsilon\[t-1\]^2+a2\*epsilon\[t-2\]^2 + epsilon\[t\]=eta\[t\]*sqrt(sigma2\[t\]) + }
(红线是条件方差过程)。
> acf(epsilon,lag=50,lwd=2)
可下载资源
如果是一个ARCH(),那么就是一个AR(1)过程。所以第一个想法是考虑回归,就像我们对AR(1)所做的那样
> summary(lm(Y~X1,data=db))
这里有一些明显的自相关。但由于我们的向量不能被认为是高斯分布的,使用最小二乘法也许不是最好的策略。实际上,如果我们的序列不是高斯分布的,它仍然是有条件的高斯分布的,因为我们假设是高斯(强)白噪声。
然后,似然函数是
而对数似然函数为
而一个自然的想法是定义
代码简单地说就是
> OPT=optim(par= + coefficients(lm(Y~X1,data=db)),fn=loglik)
由于参数必须是正数,我们在此假定它们可以写成一些实数的指数。观察一下,这些值更接近于用来生成我们的时间序列的值。
随时关注您喜欢的主题
如果我们使用R函数来估计这些参数,我们会得到
> summary(garch(epsilon,c(0,1))) ...
所以的置信区间是
coef\[2,1\]+ + c(-1.96,1.96)*coef\[2,2\]
实际上,由于我们的主要兴趣是这个参数,所以有可能使用轮廓似然方法。
> OPT=optimize(function(x) -proflik(x), interval=c(0,2)) objective-qchisq(.95,df=1) > abline(h=t,col="red")
当然,所有这些技术都可以扩展到高阶ARCH过程。例如,如果我们假设有一个ARCH(2)时间序列
其中
有一个高斯(强)白噪声 .对数似然性仍然是
而我们可以定义
上面的代码可以被修改,以考虑到这个额外的部分。
optim(par= + coefficients(lm(Y~X1+X2,data=db)),fn=loglik)
我们也可以考虑一些广义的ARCH过程,例如GARCH(1,1)。
其中
同样,可以使用最大似然技术。实际上,我们也可以用Fisher-Scoring算法编码,因为(在一个非常普遍的情况下
这里 . 使用标准的梯度下降算法,我们可以得到以下对GARCH过程的估计。
> while(sum(G^2)>1e-12){ + s2=rep(theta\[1\],n) + for (i in 2:n){s2\[i\]=theta\[1\]+theta\[2\]\*X\[(i-1)\]^2+theta\[3\]\*s2\[(i-1)\]}
这里有趣的一点是,我们也得出了(渐进的)方差
>sqrt(diag(solve(H))
可下载资源
关于作者
Kaizong Ye是拓端研究室(TRL)的研究员。Kaizong Ye是拓端研究室(TRL)的研究员。在此对他对本文所作的贡献表示诚挚感谢,他在上海财经大学完成了统计学专业的硕士学位,专注人工智能领域。擅长Python.Matlab仿真、视觉处理、神经网络、数据分析。
本文借鉴了作者最近为《R语言数据分析挖掘必知必会 》课堂做的准备。
非常感谢您阅读本文,如需帮助请联系我们!