下降方法與梯度下降

《Convex Optimization》

在介紹下降方法之前,我們需要先看一些預(yù)備的知識(shí)啃洋。

預(yù)備知識(shí)

我們假設(shè)目標(biāo)函數(shù)在下水平集S上是強(qiáng)凸的欢嘿,這是指存在m > 0,使得
\nabla^2 f(x) \succeq mI
對(duì)于任意x成立揩局。
注意毫玖,這個(gè)廣義不等式,是指\nabla^2 f(x) - mI半正定凌盯,即付枫,\nabla^2 f(x)的最小特征值大于等于m
對(duì)于x, y\in S驰怎,我們有廣義泰勒展開:
f(y)=f(x)+\nabla^{T}(y-x)+\frac{1}{2}(y-x)^{T}\nabla^{2}f(z)(y-x)
z \in [x,y]
利用強(qiáng)凸性假設(shè)阐滩,可以推得不等式(同時(shí)可知,S是有界的):
f(y) \ge f(x) + \nabla f(x)^{T}(y-x) + \frac{m}{2}\|y-x\|_2^2
通過县忌,不等式右邊是關(guān)于y的二次凸函數(shù)掂榔,令其關(guān)于y的導(dǎo)數(shù)等于零,可以得到該二次函數(shù)的最優(yōu)解\widetilde{y} = x-(1/m)\nabla f(x)症杏,所以
f(y) \ge f(x) - \frac{1}{2m}\|\nabla f(x)\|_2^2
x^*f(x)的全局最優(yōu)解装获,p^*=f(x^*),因?yàn)樯鲜霾坏仁綄?duì)于任意y都成立厉颤,所以:
p^* \ge f(x) - \frac{1}{2m} \|\nabla f(x)\|_2^2
由此可見穴豫,任何梯度足夠小的點(diǎn)都是近似最優(yōu)解。由于走芋,
\|\nabla f(x)\|_2 \le (2m\epsilon)^{1/2} \Rightarrow f(x) - p^* \le \epsilon
我們可以將其解釋為次優(yōu)性條件绩郎。
因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=S" alt="S" mathimg="1">有界,而\nabla^2 f(x)的最大特征值是xS上的連續(xù)函數(shù)翁逞,所以它在S上有界,即存在常數(shù)M使得:
\nabla^2 f(x) \preceq MI
關(guān)于Hessian矩陣的這個(gè)上界溉仑,意味著挖函,對(duì)任意的x, y \in S:
f(y) \le f(x) + \nabla f(x)^T(y-x) + \frac{M}{2} \|y-x\|_2^2
同樣,可以得到:
p^* \le f(x) - \frac{1}{2M} \|\nabla f(x)\|_2^2
注意:
mI \preceq \nabla^2 f(x) \preceq MI
\kappa = M/m為矩陣\nabla^2 f(x)的條件數(shù)的上界。通常怨喘,\kappa越薪蚧(越接近1),梯度下降收斂的越快必怜。這個(gè)條件會(huì)在收斂性分析中反復(fù)用到肉拓。

下降方法

由凸性知:\nabla f(x^{(k)})^T (y-x^{(k)}) \ge 0意味著f(y) \ge f(x^{(k)}),因此一個(gè)下降方法中的搜索方向必須滿足:
\nabla f(x^{(k)})^T \Delta x^{(k)} < 0
我們并沒有限定下降方向\Delta x必須為逆梯度方向梳庆,事實(shí)上這種選擇也僅僅是局部最優(yōu)的策略暖途。
所以算法是如此的:

下降方法

停止準(zhǔn)則通常根據(jù)次優(yōu)性條件,采用
\|\nabla f(x)\| \le \eta
膏执,其中
\eta
是小正數(shù)驻售。

梯度下降方法的算法如下:

梯度下降

精確直線搜索

精確直線搜索需要我們求解下面的單元的優(yōu)化問題:
t = argmin_{s \ge 0} f(x+s \Delta x)
因?yàn)閱栴}是一元的,所以相對(duì)來說比較簡(jiǎn)單更米,可以通過一定的方法來求解該問題欺栗,特殊情況下,可以用解析方法來確定其最優(yōu)解征峦。

收斂性分析

在收斂性分析的時(shí)候迟几,我們選擇\Delta x := -\nabla f(x)
我們定義:\widetilde{f}(t)=f(x-t\nabla f(x))栏笆,同時(shí)类腮,我們只考慮滿足x-t\nabla f(x) \in St。通過預(yù)備知識(shí)竖伯,我們?nèi)菀椎玫较旅娴囊粋€(gè)上界:

上界

對(duì)上述不等式倆邊同時(shí)關(guān)于t求最小存哲,左邊等于\widetilde{f}(t_{exact}),右邊是一個(gè)簡(jiǎn)單的二次型函數(shù)七婴,其最小解為t=1/M祟偷,因此我們有:
f(x^{+}) = \widetilde{f}(t_{exact}) \le f(x) - \frac{1}{M} \|\nabla(f(x))\|_2^2
從該式倆邊同時(shí)減去p^*,我們得到
f(x^+)-p^* \le f(x) - p^* - \frac{1}{M} \|\nabla f(x)\|_2^2
\|\nabla f(x)\|_2^2 \ge 2m(f(x)-p^*)打厘,可以斷定:
f(x^+) -p ^* \le (1-m/M)(f(x)-p^*)
重復(fù)進(jìn)行修肠,可以看出,
f(x^+) -p ^* \le (1-m/M)^{k}(f(x)-p^*)
收斂性分析到這為止户盯,更多內(nèi)容翻看凸優(yōu)化嵌施。

回溯直線搜索

回溯直線搜索,不要求每次都減少最多莽鸭,只是要求減少足夠量就可以了吗伤。其算法如下:

在這里插入圖片描述

回溯搜索從單位步長(zhǎng)開始,按比例逐漸減少硫眨,直到滿足停止條件
f(x+t\Delta x) \le f(x) + \alpha t \nabla f(x)^T \Delta x
足淆。

在這里插入圖片描述

最后的結(jié)果
t
滿足
t \ge min\{1, \beta t_0 \}

在實(shí)際計(jì)算中,我們首先用\betat直到x+t\Delta x \in dom f巧号,然后才開始檢驗(yàn)停止準(zhǔn)則是否成立族奢。

參數(shù)\alpha的正常取值在0.01 和 0.3 之間表示我們可以接受的f的減少量在基于線性外推預(yù)測(cè)的減少量的1\%1\%之間。參數(shù)\beta的正常取值在 0.1(對(duì)應(yīng)非常粗糙的搜索)和 0.8(對(duì)應(yīng)于不太粗糙的搜索)之間丹鸿。

收斂性分析

我們先證明越走,只要0 \le t \le 1/M,就能滿足回溯停止條件:
\widetilde{f}(t) \le f(x) - \alpha t \|\nabla f(x)\|
首先靠欢,注意到:
0 \le t \le 1/M \Rightarrow -t + \frac{Mt^2}{2} \le -t/2
由于\alpha < 1/2(這也是為什么我們限定\alpha < 1/2的原因)廊敌,所以可以得到:

在這里插入圖片描述

因此,回溯直線搜索將終止于
t=1
或者
t\ge \beta/M
掺涛。故:
f(x^+) \le f(x) - \min \{\alpha, (\beta \alpha / M) \} \|\nabla f(x)\|_2^2

倆邊減去
p^*
庭敦,再結(jié)合
\|\nabla f(x)\|_2^2 \ge 2m(f(x)-p^*)
可導(dǎo)出:
f(x^+)-p^* \le (1-\min \{2m\alpha, 2 \beta \alpha m/M \})^{k}(f(x) - p^*)

數(shù)值試驗(yàn)

f(x)=\frac{1}{2}(x_1^2+\gamma x_2^2)

我們選取初始點(diǎn)為(\gamma, 1),\gamma=10

下圖是精確直線搜索:

精確直線搜索

下圖是回溯直線搜索,\alpha=0.4, \beta=0.7可以看出來薪缆,每一次的震蕩的幅度比上面的要大一些秧廉。

在這里插入圖片描述

f(x)=e^{x_1+3x_2-0.3}+e^{x_1-3_x2-0.3}+e^{-x_1-0.1}

下面采用的是回溯直線搜索,\alpha=0.4,\beta=0.7,初始點(diǎn)為(7,3)

回溯直線搜索

初始點(diǎn)為(-7, -3)

回溯直線搜索

\alpha=0.2,\beta=0.7

回溯直線搜索

代碼

import numpy as np

class GradDescent:
    """
    梯度下降方法
    """
    def __init__(self, f, x):
        assert hasattr(f, "__call__"), \
            "Invalid function {0}".format(f)
        self.__f = f
        self.x = x
        self.y = self.__f(x)
        self.__process = [(self.x, self.y)]

    @property
    def process(self):
        """獲得梯度下降過程"""
        return self.__process

    def grad1(self, update_x, error=1e-5):
        """精確收縮算法
        update_x: 用來更新x的函數(shù)拣帽,這個(gè)我們沒辦法在這里給出
        error: 梯度的誤差限疼电,默認(rèn)為1e-5
        """
        assert hasattr(update_x, "__call__"), \
            "Invalid function {0}".format(update_x)
        error = error if error > 0 else 1e-5
        while True:
            x = update_x(self.x)
            if (x - self.x) @ (x - self.x) < error:
                break
            else:
                self.x = x
                self.y = self.__f(self.x)
                self.__process.append((self.x, self.y))

    def grad2(self, gradient, alpha, beta, error=1e-5):
        """回溯直線收縮算法
        gradient: 梯度需要給出
        alpha: 下降的期望值 (0, 0.5)
        beta:每次更新的倍率 (0, 1)
        error: 梯度的誤差限,默認(rèn)為1e-5
        """
        assert hasattr(gradient, "__call__"), \
            "Invalid gradient"
        assert 0 < alpha < 0.5, \
            "alpha should between (0, 0.5), but receive {0}".format(alpha)
        assert 0 < beta < 1, \
            "beta should between (0, 1), but receive {0}".format(beta)
        error = error if error > 0 else 1e-5
        def search_t(alpha, beta):
            t = 1
            t_old = 1
            grad = -gradient(self.x)
            grad_module = grad @ grad
            while True:
                newx = self.x + t * grad
                newy = self.__f(newx)
                if newy < self.y - alpha * t * grad_module:
                    return t_old
                else:
                    t_old = t
                    t = t_old * beta
        while True:
            t = search_t(alpha, beta)
            x = self.x - t * gradient(self.x)
            if (t * gradient(self.x)) @ (t * gradient(self.x)) < error:
                break
            else:
                self.x = x
                self.y = self.__f(self.x)
                self.__process.append((self.x, self.y))



r = 10.

def f(x):
    vec = np.array([1., r], dtype=float)
    return 0.5 * (x ** 2) @ vec

def f2(x):
    x0 = x[0]
    x1 = x[1]
    return np.exp(x0+3*x1-0.1) \
            + np.exp(x0-3*x1-0.3) \
            + np.exp(-x0-0.1)
def gradient2(x):
    x0 = x[0]
    x1 = x[1]
    grad1 = np.exp(x0+3*x1-0.1) \
            + np.exp(x0-3*x1-0.3) \
            - np.exp(-x0-0.1)
    grad2 = 3 * np.exp(x0+3*x1-0.1) \
            -3 * np.exp(x0-3*x1-0.3)
    return np.array([grad1, grad2])


def update(x):
    t = -(x[0] ** 2 + r ** 2 * x[1] ** 2) \
            / (x[0] ** 2 + r ** 3 * x[1] ** 2)
    x0 = x[0] + t * x[0]
    x1 = x[1] + t * x[1] * r
    return np.array([x0, x1])

def gradient(x):
    diag_martix = np.diag([1., r])
    return x @ diag_martix

x_prime = np.array([7, 3.], dtype=float)
ggg = GradDescent(f2, x_prime)
#ggg.grad1(update)
ggg.grad2(gradient2, alpha=0.2, beta=0.7)
process = ggg.process
import matplotlib.pyplot as plt
import matplotlib.path as mpath
fig, ax = plt.subplots(figsize=(10, 6))
w1 = 4
w2 = 10
Y, X = np.mgrid[-w1:w1:300j, -w2:w2:300j]
U = X
V = r * Y
ax.streamplot(X, Y, U, V)
process_x = list(zip(*process))[0]
print(process_x)
path = mpath.Path(process_x)
x0, x1 = zip(*process_x)
ax.set_xlim(-8, 8)
ax.set_ylim(-4, 4)
ax.plot(x0, x1, "go-")
plt.show()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末减拭,一起剝皮案震驚了整個(gè)濱河市蔽豺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拧粪,老刑警劉巖修陡,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異可霎,居然都是意外死亡魄鸦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門癣朗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拾因,“玉大人,你說我怎么就攤上這事旷余【罴牵” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵正卧,是天一觀的道長(zhǎng)蠢熄。 經(jīng)常有香客問我,道長(zhǎng)炉旷,這世上最難降的妖魔是什么护赊? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任惠遏,我火速辦了婚禮砾跃,結(jié)果婚禮上骏啰,老公的妹妹穿的比我還像新娘。我一直安慰自己抽高,他們只是感情好判耕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著翘骂,像睡著了一般壁熄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碳竟,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天草丧,我揣著相機(jī)與錄音,去河邊找鬼莹桅。 笑死昌执,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的诈泼。 我是一名探鬼主播懂拾,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼铐达!你這毒婦竟也來了岖赋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瓮孙,失蹤者是張志新(化名)和其女友劉穎唐断,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杭抠,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脸甘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了祈争。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斤程。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖菩混,靈堂內(nèi)的尸體忽然破棺而出忿墅,到底是詐尸還是另有隱情沮峡,我是刑警寧澤邢疙,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏椭员。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一莺禁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至扛吞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荆责,已是汗流浹背滥比。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留做院,地道東北人盲泛。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像键耕,于是被迫代替她去往敵國(guó)和親寺滚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353