从一条曲线谈损失函数优化方法

损失函数也叫目标函数,他是衡量预测值和实际值的相似程度的指标。我们希望预测值和真实值尽量接近,就需要估计一系列参数来拟合,这个参数集使得误差越小就说明这个算法还不错。一个损失函数有可能存在多个局部最小点,我们就需要至少找到在局部地区的最小值。

找到生成最小值的一组参数的算法被称为优化算法。我们发现随着算法复杂度的增加,则算法倾向于更高效地逼近最小值。我们将在这篇文章中讨论以下算法:

  • 随机梯度下降法(批次、随机、mini-batch)
  • 动量算法(物理里面的动量含义)
  • RMSProp
  • Adam 算法

随机梯度下降法

随便找一本书介绍 SGD,都会出现这个公式


image

θ是你试图找到最小化 J 的参数,这里的 J 称为目标函数,α叫做学习率。目标函数的来龙去脉可以参考之前的文章。我们先假设θ取一个值,然后不停的修正这个值,从而使得最小化J。可以假设θ是一个山坡上一个点,而最后的导数部分是该点的坡度;学习率就是一个摩擦系数,学习率大就说明摩擦越小。

算法说明

随机梯度下降法:
1、初始化参数(θ,学习率)
2、计算每个θ处的梯度
3、更新参数
4、重复步骤 2 和 3,直到代价值稳定

随便举个例子:
下面是一个目标函数和他的导数


image

用 python 实现这两个曲线


import numpy as np
import matplotlib.pyplot as plt

def minimaFunction(theta):
    return np.cos(3*np.pi*theta)/theta

def minimaFunctionDerivative(theta):
    const1 = 3*np.pi
    const2 = const1*theta
    return -(const1*np.sin(const2)/theta)-np.cos(const2)/theta**2
#从0.1-2.1,步长0.01
theta = np.arange(.1,2.1,.01)
Jtheta = minimaFunction(theta)
dJtheta = minimaFunctionDerivative(theta)

plt.plot(theta,Jtheta,'m--',label = r'$J(\theta)$')
plt.plot(theta,dJtheta/30,'g-',label = r'$dJ(\theta)/30$')
plt.legend()

axes = plt.gca()

plt.ylabel(r'$J(\theta),dJ(\theta)/30$')
plt.xlabel(r'$\theta$')
plt.title(r'$J(\theta),dJ(\theta)/30 $ vs $\theta$')

plt.show()
image

图中虚线有3处局部最低点,在靠近0附件是全局最小的。
使用下面的程序模拟逐步找到最小值

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

#给定参数逐步找到最优值
def optimize(iterations, oF, dOF,params,learningRate):
    oParams = [params]
    #喜欢次数
    for i in range(iterations):
        # 计算参数的导数
        dParams = dOF(params)
        # 更新参数值
        params = params-learningRate*dParams
        # 参数追加到数组,方便演示
        oParams.append(params)
    return np.array(oParams)

#损失函数
def minimaFunction(theta):
    return np.cos(3*np.pi*theta)/theta
#损失函数导数
def minimaFunctionDerivative(theta):
    const1 = 3*np.pi
    const2 = const1*theta
    return -(const1*np.sin(const2)/theta)-np.cos(const2)/theta**2
#基本参数设定
theta = .6
iterations=45
learningRate = .0007
optimizedParameters = optimize(iterations,\
                               minimaFunction,\
                               minimaFunctionDerivative,\
                               theta,\
                               learningRate)

#  plt 绘制损失函数曲线
thetaR = np.arange(.1,2.1,.01)
Jtheta = minimaFunction(thetaR)

# 在损失函数上绘制参数点
JOptiTheta = minimaFunction(optimizedParameters)

# 创建动画
fig, ax = plt.subplots()
line, = ax.plot(thetaR,Jtheta,'m-')
axes = plt.gca()
axes.set_ylim([-4,6])#y 周范围
axes.set_xlim([0,2])#x周范围

# 构建动画参数
Writer = animation.writers['ffmpeg']
writer = Writer(fps=15, metadata=dict(artist='Me'), bitrate=1800)

# 动画动作
def animate(i):
    line, = ax.plot(optimizedParameters[i],JOptiTheta[i],'or')  # update the data
    plt.title(r'Updating $\theta$ through SGD $\theta$ = %f J($\theta$) = %f' %(optimizedParameters[i],JOptiTheta[i]))
    return line,

#动画
ani = animation.FuncAnimation(fig, animate, np.arange(1, iterations),
                              interval=1, blit=True)
#保存
ani.save('sgd1.mp4', writer=writer)
image

如果我们的学习率很大,我们可以自己调参数进行测试,会发现红点数据有可能冲到另外一个坡度,形成震荡。把参数跳到0.01就可以发现这个现象。

动量 SGD

用户想要使用非常大的学习速率来快速学习感兴趣的参数。不幸的是,当代价函数波动较大时,这可能导致不稳定,之前的视频学习参数过大,基本就没什么点可以看到。
动量 SGD 试图使用过去的梯度预测学习率来解决这个问题


image

γ 和 ν 值允许用户对 dJ(θ) 的前一个值和当前值进行加权来确定新的θ值。人们通常选择γ和ν的值来创建指数加权移动平均值,如下所示:
image
β参数的最佳选择是 0.9。选择一个等于 1-1/t 的β值可以让用户更愿意考虑νdw 的最新 t 值。这种简单的改变可以使优化过程产生显著的结果!我们现在可以使用更大的学习率,并在尽可能短的时间内收敛!
#给定参数逐步找到最优值
def optimize(iterations, oF, dOF,params,learningRate,beta):
    oParams = [params]
    vdw=0.0
    #喜欢次数
    for i in range(iterations):
        # 计算参数的导数
        dParams = dOF(params)
        # 应用公式求得 vdw
        vdw = vdw*beta+(1.0-beta)*dParams
        # 更新参数值
        params = params-learningRate*vdw
        # 参数追加到数组,方便演示
        oParams.append(params)
    return np.array(oParams)
image

RMSProp

精益求精,我们继续看看如何再优化。
RMS prop 试图通过观察关于每个参数的函数梯度的相对大小,来改善动量函数。因此,我们可以取每个梯度平方的加权指数移动平均值,并按比例归一化梯度下降函数。具有较大梯度的参数的 sdw 值将变得比具有较小梯度的参数大得多,从而使代价函数平滑下降到最小值。可以在下面的等式中看到:


image

这里的 epsilon 是为数值稳定性而添加的,可以取 10e-7。我理解的意思是防止除以0吧。
既然公式给出了,我们就继续用代码来实现

def optimize(iterations, oF, dOF,params,learningRate,beta):
    oParams = [params]
    sdw=0.0
    eps = 10**(-7)
    #喜欢次数
    for i in range(iterations):
        # 计算参数的导数
        dParams = dOF(params)
        # 应用公式求得 sdw
        sdw = sdw*beta+(1.0-beta)*dParams**2
        # 更新参数值
        params = params-learningRate*dParams/(sdw**.5+eps)
        # 参数追加到数组,方便演示
        oParams.append(params)
    return np.array(oParams)
image

看来效果越来越好了。

Adam 算法

我们是否可以做得更好?结合上面动量和RMSProp结合成一种算法,以获得两全其美的效果。公式如下:


image

其中贝塔有2个参数,分别可以设置为0.9和0.999,贝塔的 t 次方,t 表示迭代次数(需要+1)


#给定参数逐步找到最优值
def optimize(iterations, oF, dOF,params,learningRate,beta1,beta2):
    oParams = [params]
    sdm=0.0
    vdm=0.0
    vdwCorr = 0.0
    sdwCorr = 0.0
    eps = 10**(-7)
    #喜欢次数
    for i in range(iterations):
        # 计算参数的导数
        dParams = dOF(params)
        # 应用公式求得
        vdm=vdm*beta1+(1-beta1)*dParams
        sdm=sdm*beta2+(1-beta1)*dParams**2

        vdwCorr=vdm/(1.0-beta1**(i+1))
        sdwCorr=sdm/(1.0-beta2**(i+1))

        # 更新参数值
        params = params-learningRate*vdwCorr/(sdwCorr**.5+eps)

        # 参数追加到数组,方便演示
        oParams.append(params)
    return np.array(oParams)

学习率修改为0.3,也能比较好的工作。


image

当然,针对多维也是一样操作,需要考虑导数的时候各个维度,参数也需要对应出现。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容