機(jī)器學(xué)習(xí)當(dāng)中的數(shù)學(xué)---微分學(xué)部分

機(jī)器學(xué)習(xí)當(dāng)中的數(shù)學(xué)---微分學(xué)部分

關(guān)于無窮小的物理學(xué)遐想

我認(rèn)為無窮小還是很不好理解的,于是我想到了物理學(xué)上的另外一個類比,也就是牛頓的經(jīng)典力學(xué)和愛因斯坦的相對論。
無窮小的自然語言解釋是,當(dāng)自變量x趨向于0的時候,函數(shù)\lim_{x\rightarrow 0} f(x)=0。但是不同函數(shù)趨于0的速度是不同的,最典型的就是指數(shù)型的函數(shù)比如x^n(n>1)就要比x趨于0的速度要快很多,因此x^nx的高階無窮小,記作x^n=\mathcal{O}(x),相應(yīng)的其他函數(shù)的類比也是一樣的。

無窮小與無窮小的比較

如果一個無窮小是另外一個無窮小的高階無窮小,那么兩者之比就是0。
其實(shí)兩個無窮小可以認(rèn)為是兩個維度或者說兩個世界的東西,實(shí)際上算術(shù)上的差距并沒有可比性,就好像我們在牛頓經(jīng)典力學(xué)時空觀下,我們的運(yùn)動其實(shí)是相對于光速的極限下是靜止不動的一樣,這里也就是相當(dāng)于那個xx^n的比較一樣,x^n要比x小得太多太多太多了,以至于x^nx這個無窮小看來看來也是0。正如光速比我們快得太多太多太多了,實(shí)際上那個x^nx,光與我們已經(jīng)不是同一個維度下的東西了,我們無法理解光在那種速度下會發(fā)生什么事。而同階無窮小,就像光與其他電磁波一樣,雖然它們快得難以被我們理解,但他們是同樣地快,或者說他們的速度的差別是可以被測量,被常數(shù)化的,所以其實(shí)是相同的級別。

當(dāng)x較小的時候
\lim _{x\rightarrow 0}(\lim _{m\rightarrow \infty}\dfrac{1-x^{m+1}}{1-x})=\lim _{x\rightarrow 0}\dfrac{1}{1-x}

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
%matplotlib inline

import seaborn as sns
plt.style.use('ggplot')
x=np.linspace(0,20,9)
y=2*x**2+2*x+1
new_x=[i for i in x if x.tolist().index(i)%2==0]
new_y=2*np.array(new_x)**2+2*np.array(new_x)+1

在做任何事情前,一定要明白為什么這么做。這也是為什么學(xué)習(xí)機(jī)器學(xué)習(xí)要從學(xué)習(xí)高等數(shù)學(xué)開始,這點(diǎn)很重要。
因?yàn)闄C(jī)器學(xué)習(xí)本質(zhì)上是一個逼近的問題,我們現(xiàn)在可以回到歐幾里得時代,發(fā)現(xiàn)圓的測量可能沒有工具借助,幾乎是不可能的,但是聰明的哲學(xué)家或者說研究者,他們通過對圓進(jìn)行外接和內(nèi)接,通過求圓內(nèi)部和外部的多邊形的面積,如果不斷增加邊的數(shù)量,那么外接和內(nèi)接多邊形就可以不斷逼近圓,最終三者的面積的極限就是相等的,進(jìn)而求出圓的面積

fig=plt.figure(figsize=(8,8))
ax=fig.add_subplot(1,1,1)
circle1=plt.Circle((0.5, 0.5), 0.2, color='k', fill=False)
ax.add_artist(circle1)
<matplotlib.patches.Circle at 0x1a1738b3c8>
import matplotlib.pyplot as plt
from matplotlib.patches import CirclePolygon

circle = CirclePolygon((0, 0), radius = 0.75, fc = 'y')
plt.gca().add_patch(circle)

verts = circle.get_path().vertices
trans = circle.get_patch_transform()
points = trans.transform(verts)
# print(points)

plt.plot(points[:,0],points[:,1])
plt.axis('scaled')
plt.show()
線性逼近圓

機(jī)器學(xué)習(xí)當(dāng)中的逼近

低階的線性逼近

plt.plot(x.tolist(),y.tolist())
plt.plot(new_x, new_y, 'b-o') 
plt.xlim(0,20)
plt.ylim(0,1000)
plt.show()
線性逼近曲線
fig=plt.figure(figsize=(16,8))
x_s=np.linspace(1,10000,1000)
y_s=np.sin(2*np.pi*x_s)
x_s_new=np.array([i for i in x_s if x_s.tolist().index(i)%20 == 0])
y_s_new=np.sin(2*np.pi*x_s_new)
plt.plot(x_s, y_s)
plt.plot(x_s_new, y_s_new,'b--o')
[<matplotlib.lines.Line2D at 0x1a17821908>]
線性逼近正弦函數(shù)

從上面看到,都是用一些局部的線性函數(shù)去逼近一些復(fù)雜的函數(shù),這樣子我們就可以用簡單的函數(shù)去近似出復(fù)雜的函數(shù),可以想到,如果點(diǎn)足夠多的話可以無限逼近。線性方程在該點(diǎn)的值與該復(fù)雜函數(shù)在該點(diǎn)的值是一致的。

f(x_{0}+\Delta)=f(x_{0})+\Delta\dfrac{df(x_{0})}{dx}+\mathcal{O}(\Delta)

這里的\mathcal{O}(\Delta)\Delta的高階無窮小,\Delta也就是dx,相當(dāng)于橫坐標(biāo)差,當(dāng)x\rightarrow0的時候,因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=%5Cmathcal%7BO%7D(%5CDelta)" alt="\mathcal{O}(\Delta)" mathimg="1">是\Delta的高階無窮小,因此趨于0的速度要快于前面的線性方程部分,因此\lim_{x\rightarrow0}f(x_0+\Delta)=\lim_{x\rightarrow0}(f(x_0)+\Delta\dfrac{df(x_0)}{dx})。
也就是復(fù)雜函數(shù)和線性方程逼近于x_0的這個極限是相同的,\mathcal{O}(\Delta)在非趨近的情況下是個誤差項(xiàng)

高階的線性逼近

上面的是低階的線性逼近,這里的“低階”意思是指只有次數(shù)為1的導(dǎo)數(shù),我們可以想到后面的導(dǎo)數(shù)部分\dfrac{df(x_0)}{dx}又可以展開,所以\Delta\dfrac{df(x_0)}{dx}=\Delta(f^{'}(x_0)+\Delta\dfrac{df^{'}(x_0)}{dx})=\Delta f^{'}(x_0)+\Delta^{2}\dfrac{df^{'}(x_0)}{dx}+\mathcal{O}(\Delta^{2})
進(jìn)行進(jìn)一步的展開,這里進(jìn)行二階的泰勒展開后誤差為\Delta^{2}的高階無窮小,如果是n階展開的話就是n階無窮小

多元函數(shù)的逼近

from mpl_toolkits import mplot3d

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
def f(x, y):
    return x ** 2 + y ** 2
x = np.linspace(-6, 6, 30)
y = np.linspace(-6, 6, 30)

X, Y = np.meshgrid(x, y)
# print(X)

Z = f(X, Y)
Z.shape
(30, 30)
fig = plt.figure()
ax = plt.axes(projection='3d')

ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
                cmap='viridis', edgecolor='none')
plt.show()
多元函數(shù)

多元函數(shù)

偏導(dǎo)數(shù)

其實(shí)偏導(dǎo)數(shù)就是,對于一個多元函數(shù),比如說二元函數(shù)f(x,y)其沿著坐標(biāo)軸方向上的導(dǎo)數(shù)即為偏導(dǎo)數(shù),沿著x方向上的為x的偏導(dǎo)數(shù),在y方向?yàn)閥的偏導(dǎo)數(shù)。表示為:
\partial f_x(x, y)=\dfrac{\partial f(x, y)}{\partial x}=\lim_{\Delta x\rightarrow0}\dfrac{f(x+\Delta x, y)}{\Delta x}
\partial f_y(x, y)=\dfrac{\partial f(x, y)}{\partial y}=\lim_{\Delta y\rightarrow0}\dfrac{f(x, y+\Delta y)}{\Delta y}

以上是沿著x軸和y軸方向上的偏導(dǎo)數(shù),如果是沿著任意一個方向v=(a, b)的話,在該方向上該多元函數(shù)的導(dǎo)數(shù)為\nabla f_v(x, y)=\lim_{\Delta \rightarrow 0}\dfrac{f(x+a·\Delta, y+b·\Delta)-f(x, y)}{\Delta} a·\Delta
b·\Delta可以認(rèn)為是\Delta在x軸和y軸方向的一個投影,從x和y的方向上進(jìn)行逼近。

線性逼近

同樣的,類似于一元復(fù)雜函數(shù)可以通過一個線性函數(shù)來不斷逼近,多元函數(shù)也可以用一個線性方程來不斷逼近

f(x+\Delta_x, y+\Delta_y)=f(x, y)+L_x·\Delta_x+L_y·\Delta_y+\mathcal{O}(|\Delta_x|+|\Delta_y|)

偏導(dǎo)數(shù)與梯度的關(guān)系

我們上面說過,偏導(dǎo)數(shù)是多元函數(shù)f(x, y)對于x軸和y軸方向上的導(dǎo)數(shù),但是很多時候我們并不是只限定在x軸和y軸方向上求導(dǎo)數(shù),比如v方向,v=(a, b),那么在v方向上的導(dǎo)數(shù)不叫偏導(dǎo)數(shù),叫梯度,梯度也是在該點(diǎn)處下降最快的方向。
我們將某點(diǎn)(x, y)x軸的偏導(dǎo)數(shù)和y軸的偏導(dǎo)數(shù)組成一個向量,表示為\Delta f(x, y)=(f_x, f_y)^T(備注:T表示為列向量的意思)
那么在該點(diǎn)(x, y)朝著某個方向v=(a, b)最快下降方向也就是梯度方向,表示為
\Delta f_v(x, y)=v·\Delta f(x, y)=a·f_x+b·f_y=a·\partial f_x(x,y)+b·\partial f_y(x,y)

關(guān)于導(dǎo)數(shù)為什么是下降最快的方向

import seaborn as sns
# def f(x):
#     return np.sin(2*np.pi * x)

# x_d=np.linspace(0, 1000, 500)

# y_d=f(x_d)

# x_p=x_d[250]
# y_p=np.sin(2*np.pi * x_p)
# f_der=2*np.pi*np.cos(2*np.pi*x_p)#get the derivatives
# print(f_der)
# tangent_line=y_p+f_der*(x_d-x_p)
# plt.plot(x_d,y_d,'-b',x_p, y_p, 'om', x_d, tangent_line,'--r')
# # plt.plot(x_d,y_d)
# plt.xticks(color='w')
# plt.yticks(color='w')
# plt.ylim(-1,1)
# plt.show()
def f(x): # sample function
    return x*np.sin(np.power(x,2))

# evaluation of the function
x = np.linspace(-2,4,150)
y = f(x)

a = 1.4
h = 0.1
fprime = (f(a+h)-f(a))/h # derivative
tan = f(a)+fprime*(x-a)  # tangent
larger_tan = f(a)+ -5*(x-a)  # larger tangent
print(fprime)
# plot of the function and the tangent
plt.plot(x,y,'b',a,f(a),'om',x,tan,'--r',x,larger_tan, '-g')
plt.xticks(color='white')
plt.yticks(color='white')
plt.show()
-1.2818633377155364
導(dǎo)數(shù)是最快下降方向

關(guān)于這個問題,我的理解是這樣的,在圖上那個紅點(diǎn)處,紅色虛線是切線,綠色是絕對值大于切線斜率絕對值的線,我們想象成一個點(diǎn)在曲線上快速運(yùn)動,它不能越軌,否則該點(diǎn)就不算是曲線上的點(diǎn)了,這樣的話,每個點(diǎn)在曲線上面的最大下降方向只能是切線方向,如果比切線下降更快,如綠色線,接下來這個點(diǎn)繼續(xù)往綠色方向運(yùn)動,哪怕一點(diǎn)點(diǎn),都是飛出圖上藍(lán)色的軌道外了,也就不算是曲線上的點(diǎn)了。所以在某一點(diǎn)處,切線方向一定是下降最快的方向

梯度下降法和牛頓法

簡而言之,梯度下降法就是多元函數(shù)的線性逼近,而牛頓法相當(dāng)于是多元函數(shù)泰勒展開后的n階逼近。(不太明白的可以參考一元函數(shù)的線性逼近和n階逼近)

先修知識 泰勒展開

泰勒展開是關(guān)于某個復(fù)雜函數(shù)f(x)在a點(diǎn)處的展開表達(dá)式,對于一個無限可微分函數(shù)f(x),其在真實(shí)點(diǎn)a處的泰勒展開式為f(x)=f(a)+f'(a)(x-a)+\dfrac{1}{2}f"(a)(x-a)^2+……+\dfrac{1}{n}f^{(n)}(x-a)^n

梯度下降法

J(\theta_0+\Delta_\theta)=J(\theta_0)+\Delta^{T}_\theta\nabla J(\theta_0)+|\mathcal{O}(\Delta_\theta)|

梯度下降法相當(dāng)于是對函數(shù)J(\theta)\theta_0這點(diǎn)的線性逼近

梯度下降法并不能告訴我們極小值點(diǎn)在哪,但是可以告訴我們在\theta_0這一點(diǎn)下降最快的方向在哪里。然后我們可以以一定的下降速率去更新已有的\theta值。這個下降速率就是學(xué)習(xí)率,類似于一個人在完全黑暗之中在山谷里面摸索最低點(diǎn)谷底,那么學(xué)習(xí)率就像是這個人的步伐,可以一腳邁一大步,但是很容易邁過頭;同樣,也可以一腳邁一小步,但收斂速度會很慢。
\theta_n=\theta_{n-1}-\eta·\nabla J(\theta_{n-1})

對于一個數(shù)據(jù)集X來說,其梯度就是所有單個樣本的梯度之和
J_X(\theta)=\sum_{i=1}^{n}\nabla J_{x_1}(\theta)=\nabla J_{x_1}(\theta)+ \nabla J_{x_2}(\theta)+\nabla J_{x_3}(\theta)+……+\nabla J_{x_n}(\theta)
其中x_{i}是指樣本i,i從1到n代表X所有的每個樣本,而\nabla J_{x_i}(\theta)則代表樣本i的梯度

梯度下降根據(jù)對總體樣本的選取不同計(jì)算出選取樣本的梯度,以此樣本計(jì)算出來的梯度作為參數(shù)更新的方向,直到梯度為0的時候即為到達(dá)最優(yōu)點(diǎn)。三種不同的計(jì)算梯度方式:

  1. 全量梯度下降法

這種方法就是計(jì)算所有樣本的梯度之和,以此作為參數(shù)更新的方向

  1. 隨機(jī)梯度下降法

這種方法是每次只計(jì)算一個樣本的梯度,以此作為參數(shù)更新的方向,一般配合學(xué)習(xí)率逐漸降低的方法,有和全量梯度相似的收斂速度,好處是可以跳出局部最優(yōu)點(diǎn),有可能找到全局最優(yōu)點(diǎn)

  1. 小批量隨機(jī)梯度下降法

這種方法也是隨機(jī)抽取樣本,不同的是,每次計(jì)算梯度是以每個小樣本的梯度之和作為更新方向,比起隨機(jī)梯度下降法來說好處是更加容易收斂,受單個樣本波動性更小。

def plot_saddle(x, y):
    return x**2 - y**2
from mpl_toolkits import mplot3d
from mpl_toolkits.mplot3d import Axes3D
Z2=plot_saddle(X, Y)
fig = plt.figure()
ax = plt.axes(projection='3d')

ax.plot_surface(X, Y, Z2, rstride=1, cstride=1,
                cmap='viridis', edgecolor='none')
plt.show()
馬鞍
plt.contour(X, Y, Z2, 20, cmap='RdGy');
馬鞍對應(yīng)的等勢面
fig = plt.figure()
ax = plt.axes(projection='3d')

ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
                cmap='viridis', edgecolor='none')
plt.show()
山谷
plt.contour(X, Y, Z, 20, cmap='RdGy');
山谷對應(yīng)的等勢面

如何閱讀等高線圖:

  1. 等高線越密集的地方,說明其斜度越大。
  2. 等高線包圍的一圈又一圈可能是valley,可能是mountain,需要通過等高線的密集變化來看出。
  3. 從上面可以看出來,對于低谷來說,其兩側(cè)的等高線由外向內(nèi)梯度越來越小,對于山谷則剛好相反,其梯度越來越大,參考再上面一副圖的左右兩邊,鞍形的左右兩邊就各是一座山峰,中間等高線變緩的就是鞍部。

牛頓法

首先要明白牛頓法是做什么的,它是要找到f(x)=0時候的x值

牛頓法與初始點(diǎn)的選取很有關(guān)系,如果初始點(diǎn)所對應(yīng)的切線斜率為0的話,那么接下來的x值就無法更新。牛頓法的好處是,比起一階的梯度下降,其收斂速度會更快。

參考鏈接:https://blog.paperspace.com/intro-to-optimization-momentum-rmsprop-adam/

\dfrac{\partial f(x)}{\partial x_i \partial x_ij}
這個二階導(dǎo)數(shù)是多個變量的求導(dǎo)組合,其形式如下:

對于兩個變量的情況:
H(x)=\begin{bmatrix} \dfrac{\partial f(x)}{\partial^2 x_1}, \dfrac{\partial f(x)}{\partial x_1 \partial x_2}\\ \dfrac{\partial f(x)}{\partial x_2 \partial x_1}, \dfrac{\partial f(x)}{\partial^2 x_2} \end{bmatrix}
這里的第一行代表先對x_1進(jìn)行求導(dǎo),再依次對x_1,x_2進(jìn)行二階求導(dǎo),同理第二行也是一樣的對x_2進(jìn)行相同的操作。
對于多個變量則有:

H(x)=\begin{bmatrix} \dfrac{\partial f(x)}{\partial^2 x_1}, \dfrac{\partial f(x)}{\partial x_1 \partial x_2}, \dfrac{\partial f(x)}{\partial x_1 \partial x_3}, \dfrac{\partial f(x)}{\partial x_1 \partial x_4}, ……, \dfrac{\partial f(x)}{\partial x_1 \partial x_n}\\ \dfrac{\partial f(x)}{\partial x_2 \partial x_1}, \dfrac{\partial f(x)}{\partial^2 x_2}, \dfrac{\partial f(x)}{\partial x_2 \partial x_3}, \dfrac{\partial f(x)}{\partial x_2 \partial x_4}, ……, \dfrac{\partial f(x)}{\partial x_2 \partial x_n}\\ \dfrac{\partial f(x)}{\partial x_3 \partial x_1}, \dfrac{\partial f(x)}{\partial x_3 \partial x_2}, \dfrac{\partial f(x)}{\partial^2 x_3}, \dfrac{\partial f(x)}{\partial x_3 \partial x_4}, ……, \dfrac{\partial f(x)}{\partial x_3 \partial x_n}\\ \dfrac{\partial f(x)}{\partial x_4 \partial x_1}, \dfrac{\partial f(x)}{\partial x_4 \partial x_2}, \dfrac{\partial f(x)}{\partial x_4 \partial x_3}, \dfrac{\partial f(x)}{\partial^2 x_4}, ……, \dfrac{\partial f(x)}{\partial x_4 \partial x_n}\\ ……, ……, ……, ……, ……, ……\\ \dfrac{\partial f(x)}{\partial x_n \partial x_1}, \dfrac{\partial f(x)}{\partial x_n \partial x_2}, \dfrac{\partial f(x)}{\partial x_n \partial x_3}, \dfrac{\partial f(x)}{\partial x_n \partial x_4}, ……, \dfrac{\partial f(x)}{\partial^2 x_n} \end{bmatrix}

牛頓法一個很好地彌補(bǔ)了一階的梯度下降的缺點(diǎn),一階的梯度下降只能知道當(dāng)前函數(shù)值是下降還是上升以及斜率的絕對值,但并不知道當(dāng)前下降的快慢,也就是不知道目前是否已經(jīng)越來越陡還是越來越緩,而二階導(dǎo)數(shù)可以彌補(bǔ)這個問題

打個比方,就好像如果我們只有一階的信息,那么我們能知道身處現(xiàn)在的位置,往哪個方向上是下降的,而且下降得最快,但我們并不知道接下來越來越緩還是越來越陡

牛頓法對多元函數(shù)的二階求導(dǎo)

def newton_func(x):
    return x**2 + 2 * x -3
fig=plt.figure()
x_r=np.linspace(-5,1, 600)
y_r= newton_func(x_r)
x_rp=-3
y_rp=0
x_rp2=1
y_rp2=0

plt.plot(x_r, y_r, 'r--', x_rp, y_rp, 'om',x_rp2, y_rp2,'om')
plt.text(x_rp+0.2, y_rp+0.5, 'a') 
plt.text(x_rp2+0.1, y_rp2+0.5, 'b')
plt.hlines(y=0,xmin=-5,xmax=1)
plt.xticks(color='w')
plt.yticks(color='w')
(array([-6., -4., -2.,  0.,  2.,  4.,  6.,  8., 10., 12., 14.]),
 <a list of 11 Text yticklabel objects>)
函數(shù)與x軸的交點(diǎn)

比如在這里有個函數(shù)f(x)=x^2+2x-3,那么牛頓法的目的就是要求出f(x)等于0的時候的x值,也就是a點(diǎn)和b點(diǎn)的對應(yīng)的x(在圖中就是-3和-1)



x_rp3=-4.8
y_rp3=newton_func(x_rp3)
h = 0.1
fprime = (newton_func(x_rp3+h)-newton_func(x_rp3))/h # derivative
xrange=np.linspace(-5, -3, 600)
tan = newton_func(x_rp3)+fprime*(xrange-x_rp3)  # tangent
# larger_tan = f(x_rp3)+ -5*(x-x_rp3)  # larger tangent
plt.plot(x_r, y_r, 'r--', x_rp, y_rp, 'om',x_rp2, y_rp2,'om',x_rp3, y_rp3,'om', xrange, tan, 'g--')

plt.text(x_rp+0.2, y_rp+0.5, 'a') 
plt.text(x_rp2+0.1, y_rp2+0.5, 'b')
plt.text(x_rp3+0.1, y_rp3+0.5, 'c')
plt.hlines(y=0,xmin=-5,xmax=1)
plt.vlines(x=x_rp3,ymin=-4, ymax=12,linestyles='dashed',color='blue')
plt.xticks(color='w')
plt.yticks(color='w')
(array([-6., -4., -2.,  0.,  2.,  4.,  6.,  8., 10., 12., 14.]),
 <a list of 11 Text yticklabel objects>)
過曲線的某一點(diǎn)做切線不斷接近x軸交點(diǎn)

牛頓法就是通過不斷更新某個點(diǎn)的切線與x軸相交的點(diǎn),從而不斷逼近f(x)=0時候的x值

x_2=x_1-\dfrac{f(x_1)}{f'(x_1)}
x_3=x_2-\dfrac{f(x_2)}{f'(x_2)}
x_4=x_3-\dfrac{f(x_3)}{f'(x_3)}
x_5=x_4-\dfrac{f(x_4)}{f'(x_4)}
x_6=x_5-\dfrac{f(x_5)}{f'(x_5)}

比如我們選c點(diǎn)(x1, y1)作為起始點(diǎn),做切線,跟x軸會有交點(diǎn),這個時候這個交點(diǎn)對應(yīng)的x在曲線上面的點(diǎn)為x2,這個時候x2比x1接近了a點(diǎn),繼續(xù)做(x2, y2)的切線,重復(fù)以上的步驟,直到找到xn對應(yīng)的f(x_n)無限接近于0,x_n無限接近于a點(diǎn)的橫坐標(biāo),這就是牛頓法。而在求損失函數(shù)的時候我們想要找到一階導(dǎo)數(shù)為0的\theta,用的函數(shù)是一階導(dǎo)數(shù),而對應(yīng)的切線斜率則是二階導(dǎo)數(shù)

關(guān)于梯度下降法和牛頓法的直觀區(qū)別

關(guān)于梯度下降法,我認(rèn)為一個直觀的解釋就是,像是下山的時候總是在每走一步就看一下周圍,朝著下降最快的方向進(jìn)行更新,直到梯度為0,那么\theta_{n-1}就不再更新,因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=%5Ctheta_n%3D%5Ctheta_%7Bn-1%7D-%5Ceta%C2%B7%5Cnabla%20J(%5Ctheta_%7Bn-1%7D)%3D%5Ctheta_%7Bn-1%7D-0%3D%5Ctheta_%7Bn-1%7D" alt="\theta_n=\theta_{n-1}-\eta·\nabla J(\theta_{n-1})=\theta_{n-1}-0=\theta_{n-1}" mathimg="1">。
對于牛頓法,它的目標(biāo)則不一樣,它是通過二階梯度HJ(\theta )來不斷以當(dāng)前點(diǎn)x以及梯度J(\theta)來計(jì)算出當(dāng)前點(diǎn)的切線與x軸的交點(diǎn),這個交點(diǎn)越來越逼近于極小值點(diǎn),直到梯度J(\theta)無限接近于0,更新的方式是\theta_n=\theta_{n-1}-\nabla J(\theta)·H^{-1}J(\theta)。在這個過程中,二階梯度HJ(\theta )其實(shí)可以描繪出一階梯度的變化,也就是山的斜率是越來越陡還是越來越緩,從而相應(yīng)地去調(diào)節(jié)學(xué)習(xí)率(每次的更新的步伐大?。?,而一階梯度相對于二階梯度,它只能告訴我們現(xiàn)在是下山還是上山,這個坡的斜率是多少(有多陡),而并不能告訴我們是越來越緩,還是越來越陡,自然也就無法自適應(yīng)學(xué)習(xí)率了。

為什么機(jī)器學(xué)習(xí)中不多使用牛頓法

主要是因?yàn)榕nD法要求二階導(dǎo)數(shù),而對于多個變量來說,求二階導(dǎo)數(shù)是一個交叉組合的形式,比如對于兩個變量\theta_1, \theta_2其函數(shù)J(\theta_1, \theta_2)的二階梯度是一個4\times4的矩陣,而n個則是n\times n,對于有多個特征的情況下,這種計(jì)算是指數(shù)型地增長

動量法

參考鏈接:https://towardsdatascience.com/stochastic-gradient-descent-with-momentum-a84097641a5d
動量法的出現(xiàn)其實(shí)是因?yàn)閿?shù)據(jù)點(diǎn)有很多噪音,我們希望能夠讓權(quán)重在通過這些數(shù)據(jù)點(diǎn)計(jì)算出損失函數(shù)梯度下降的時候能夠把握好大方向,而減少噪聲對梯度更新方向的干擾。

動量法的梯度更新方式如下:
v_t=\beta·v_{t-1}+(1-\beta)·S_{t}
t代表在數(shù)據(jù)點(diǎn)t的時候,v_{t-1}代表對前面的t-1個數(shù)據(jù)點(diǎn)進(jìn)行動量法更新后的序列,S_{t}是原始的數(shù)據(jù)點(diǎn),相當(dāng)于每次更新的時候都會保留之前的余勢,這樣可以減少單個數(shù)據(jù)點(diǎn)的噪聲的影響。

def cos(x):
    return np.cos(x)
np.random.randn()
y_noi
array([-2.49084187, -2.44073906, -2.35054648, -2.22411117, -2.06682606,
       -1.88539995, -1.68757134, -1.48177834, -1.27679879, -1.08137583,
       -0.90384497, -0.75177856, -0.63166279, -0.54862105, -0.50619538,
       -0.50619538, -0.54862105, -0.63166279, -0.75177856, -0.90384497,
       -1.08137583, -1.27679879, -1.48177834, -1.68757134, -1.88539995,
       -2.06682606, -2.22411117, -2.35054648, -2.44073906, -2.49084187])
x_noi=np.linspace(-3, 3, 500)
y_noi=cos(x_noi) + np.random.randn(len(x_noi))*0.2
plt.plot(x_noi, y_noi, 'om', x_noi,cos(x_noi),'-r')
plt.legend(['a','b'])
<matplotlib.legend.Legend at 0x1a15698390>
移動平均1

計(jì)算前面原始序列的加和

y_t = 0
s_t=[]
for i in range(len(y_noi)):
    y_t = y_t + y_noi[i]
    s_t.append(y_t)

計(jì)算平均后的序列

v_t = 0
v_new = []
for i in range(len(y_noi)):
    v_t = 0.9 * v_t + (1 - 0.9) * y_noi[i]
    v_new.append(v_t)

def plot_beta(beta):
    v_t = 0
    v_new = []
    for i in range(len(y_noi)):
        v_t = beta * v_t + (1 - beta) * y_noi[i]
        v_new.append(v_t)
    return v_new
plt.figure(figsize=(10, 5))
x_noi=np.linspace(-3, 3, 500)
y_noi=cos(x_noi) + np.random.randn(len(x_noi))*0.2
plt.plot(x_noi, y_noi, 'om', x_noi,cos(x_noi),'-r')
plt.plot(x_noi,plot_beta(0.5), color='green', marker='o', linewidth=2)
plt.plot(x_noi,plot_beta(0.9), color='blue', marker='o', linewidth=2)
plt.plot(x_noi,plot_beta(0.98), color='yellow', marker='o', linewidth=2)
plt.legend(['point', 'original function', 'beta=0.5', 'beta=0.9', 'beta=0.98'], loc='upper right')
plt.show()

移動平均2

如圖是對不同beta進(jìn)行求和的結(jié)果,動量法在每次更新梯度的的時候都有兩部分組成,一個是前面的余量,也就是\beta·v_t,beta從直覺上來說可以認(rèn)為是在計(jì)算梯度更新的時候?qū)η懊鏀?shù)據(jù)點(diǎn)的余勢的權(quán)重,而1-\beta則是對當(dāng)前數(shù)據(jù)點(diǎn)的權(quán)重,因此減少了單個數(shù)據(jù)點(diǎn)對梯度更新方向的波動的影響,變得更加穩(wěn)健,從上面可以看出來,隨著\beta值越來越大,曲線越來越光滑,但是會有偏移。

在損失函數(shù)的更新公式當(dāng)中表現(xiàn)為:
\nu_{t}=\gamma·\nu_{t-1}+\eta·\nabla J(\theta)
\theta_{t}=\theta_{t-1}-\nu_t

總體上看,既保留了前面數(shù)據(jù)點(diǎn)的余勢(也就是它們的梯度,包括方向和大?。?,另外一方面也有當(dāng)前點(diǎn)的梯度。由這兩部分組成。物理上看像是推動一個很重的鐵球下山,因?yàn)殍F球保持了下山的方向,所以鐵球向左右兩側(cè)的振蕩會越來越少,兩側(cè)就是非函數(shù)方向,也就是噪聲。

Nesterov accelerated gradient(動量法的改進(jìn)算法)

動量法的問題在于隨著后面的不斷疊加,余勢會越來越大,那么我們希望當(dāng)損失函數(shù)的梯度\nabla J(\theta)接近于0的時候,能夠減小學(xué)習(xí)率。要做到這一點(diǎn),我們可以通過使用下一步的損失函數(shù)梯度。公式如下:
v_t=\gamma·v_{t-1}+\eta·\nabla_{\theta}J(\theta_{t-1}-\gamma v_{t-1})

\theta_{t}=\theta_{t-1}-\eta_{t}
這樣可以提早預(yù)知下一步的梯度,從而盡早進(jìn)行剎車,也就是減小步伐,減小學(xué)習(xí)率。

Adagrad算法

Adagrad是一種自動調(diào)整學(xué)習(xí)率的辦法,這種調(diào)整包括對于每一步的學(xué)習(xí)率,以及不同參數(shù)的學(xué)習(xí)率都不同:

  1. 隨著模型的訓(xùn)練,學(xué)習(xí)率會逐漸衰減。
  2. 對于更新參數(shù)比較頻繁的變量,學(xué)習(xí)率會比較大。
  3. 對于更新參數(shù)比較緩慢的變量,學(xué)習(xí)率比較小。

實(shí)現(xiàn)原理

這里實(shí)現(xiàn)原理主要是從歷史上的更新梯度疊加組合成一個歷史梯度的矩陣,并取對角線上面的組合值作為下一次更新的懲罰參數(shù)。
梯度:
g_{t,i}=\nabla J(\theta_{i})
梯度歷史矩陣:
G_{t}為對角矩陣,上面的元素G_{t, ii}=\sum_{k}g^{2}_{k,i}
參數(shù)更新:
\theta_{t+1,i}=\theta_{t,i}-\dfrac{\eta}{\sqrt{G_{t, ii}+\epsilon}}\nabla J(\theta_t)

在這里i是代表第幾個特征,t是代表第t次更新,對角矩陣上面的元素是前面到現(xiàn)在的梯度的疊加,如果疊加越多,相應(yīng)學(xué)習(xí)率就會越小,更新也會放慢

AdaDelta(Adagrad的改進(jìn)算法)

AdaDelta解決了Adagrad學(xué)習(xí)率衰減過快的問題,因?yàn)榉帜敢恢倍际乔懊娴睦奂?,AdaDelta則是將分母從前面的歷史梯度的全部累加改成了歷史的移動平均值。
E[g^2]_{t}=\gamma E[g^2]_{t-1}+(1-\gamma) g^2_{t}
\theta_{t+1,i}=\theta_{t,i}-\dfrac{\eta}{\sqrt{E[g^2]_{t,ii}+\epsilon}}g_{t,i}
同時之前說的Adagrad和其他梯度算法沒有解決一個問題是參數(shù)的單位和梯度的單位并不是一致的,因此AdaDelta進(jìn)一步把學(xué)習(xí)率\mu改成了前面的參數(shù)更新的移動平均值。更新后結(jié)果如下:
\theta_{t+1,i}=\theta_{t,i}-\dfrac{\sqrt{E[\Delta \theta]_{t-1}}}{\sqrt{E[g^2]_{t,ii}+\epsilon}}g_{t,i}

Adam(基于AdaDelta進(jìn)行改進(jìn)的算法)

AdaDelta是對二階矩(也就是下面的g^2梯度的平方求移動平均值),而Adam則是更進(jìn)一步,對g_{t,i}也進(jìn)行一階的求移動平均值。更新公式如下:
m_t=\beta_{1}m_{t-1}+(1-\beta_{1})g_{t,i}
\nu_t=\beta_{2}\nu_{t-1}+(1-\beta_{2})g^2_{t,i}
\theta_{t}=\theta_{t-1}-\dfrac{\eta}{\sqrt{\nu_{t}+\epsilon}}m_t

結(jié)論

究竟如何選擇算法呢?
? 動量法與Nesterov的改進(jìn)方法著重解決目標(biāo)函數(shù)圖像崎嶇的問題
? Adagrad與Adadelta主要解決學(xué)習(xí)率更新的問題
? Adam集中了前述兩種做法的主要優(yōu)點(diǎn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容