梯度下降法(Gradient Descent,GD)是一种常用的求解
无约束最优化问题
的方法,在最优化、统计学以及机器学习等领域有着广泛的应用。
梯度下降法的基本思想:梯度下降法(Gradient Descent) – 现代机器学习的血液
我们所要优化的函数必须是一个
连续可微
的函数,可微,既可微分,意思是在函数的任意定义域上导数存在。如果导数存在且是连续函数,则原函数是连续可微的。
例子:
d ( x 2 ) d x = 2 x d ( 5 − x ) d x = − 2 ( 5 − x ) \frac{d(x^2)}{dx} = 2x \\ \frac{d(5-x)}{dx} = -2(5-x) dxd(x2)=2xdxd(5−x)=−2(5−x)
多元连续可微函数求微分的例子:
∂ ∂ x ( x 2 y 2 ) = 2 x y 2 ∂ ∂ y ( − 2 y 5 + z 2 ) = − 10 y 4 ∂ ∂ x 2 [ 0.55 − ( 5 x 1 + 2 x 2 − 12 x 3 ) ] = − 2 \frac{\partial}{\partial x}(x^2y^2) = 2xy^2 \\ \frac{\partial}{\partial y}(-2y^5 + z^2) = -10y^4 \\ \frac{\partial }{\partial x_2}[0.55 - (5x_1 + 2x_2 - 12x_3)] = -2 ∂x∂(x2y2)=2xy2∂y∂(−2y5+z2)=−10y4∂x2∂[0.55−(5x1+2x2−12x3)]=−2
以二元函数 z = f ( x , y ) z=f(x,y) z=f(x,y) 为例,假设其对每个变量都具有连续的一阶偏导数 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z 和 ∂ z ∂ y \frac{\partial z}{\partial y} ∂y∂z,则这两个偏导数构成的向量 [ ∂ z ∂ x , ∂ z ∂ y ] [\frac{\partial z}{\partial x}, \frac{\partial z}{\partial y}] [∂x∂z,∂y∂z] ,即为该二元函数的梯度向量,一般记作 ∇ f ( x , y ) \nabla f(x,y) ∇f(x,y),其中 ∇ \nabla ∇ 读作“Nabla”。
例子:
J ( Θ ) = 0.55 − ( 5 θ 1 + 2 θ 2 − 12 θ 3 ) ∇ J ( Θ ) = [ ∂ J ∂ θ 1 , ∂ J ∂ θ 2 , ∂ J ∂ θ 3 ] = [ − 5 , − 2 , 12 ] J(\Theta) = 0.55 - (5\theta_1 + 2\theta_2 - 12\theta_3) \\ \nabla J(\Theta) = [\frac{\partial J}{\partial \theta_1},\frac{\partial J}{\partial \theta_2},\frac{\partial J}{\partial \theta_3}]=[-5,-2,12] J(Θ)=0.55−(5θ1+2θ2−12θ3)∇J(Θ)=[∂θ1∂J,∂θ2∂J,∂θ3∂J]=[−5,−2,12]
梯度的意义:
从几何意义来讲,梯度的方向表示的是函数增加最快的方向,这正是我们下山要找的“最陡峭的方向”的反方向!因此后面要讲到的迭代公式中,梯度前面的符号为“-”,代表梯度方向的反方向。
更多请参考:深入浅出–梯度下降法及其实现
问题描述:
求函数 f ( X ) = f ( x 1 , x 2 ) = 1 3 x 1 2 + 1 2 x 2 2 f(X) = f(x_1, x_2) = \frac{1}{3}x_1^2 + \frac{1}{2}x_2^2 f(X)=f(x1,x2)=31x12+21x22 的极小值点。
解:设初始点为 X 1 = ( 3 , 2 ) X_1 = (3,2) X1=(3,2),学习率为 α \alpha α。
初始点处的梯度为 ∇ f ( X 1 ) = ( 2 3 × 3 , 2 2 × 2 ) = ( 2 , 2 ) \nabla f(X_1) = (\frac{2}{3} \times 3, \frac{2}{2} \times 2) = (2,2) ∇f(X1)=(32×3,22×2)=(2,2)
因此更新迭代公式带入原函数中,得:
f ( X 2 ) = f ( X 1 − α ∇ f ( X 1 ) ) = 10 3 α 2 − 8 α + 5 f(X_2) = f(X_1 - \alpha\nabla f(X_1)) = \frac{10}{3}\alpha^2 - 8\alpha + 5 f(X2)=f(X1−α∇f(X1))=310α2−8α+5
此时, α 1 ∗ = 6 5 \alpha_1^* = \frac{6}{5} α1∗=56时,为函数极小点。
因此, X 2 = X 1 − a 1 ∗ = ( 3 5 , − 2 5 ) X_2 = X_1 - a_1^*=(\frac{3}{5},-\frac{2}{5}) X2=X1−a1∗=(53,−52),一次迭代结束。
然后,再将 X 2 X_2 X2作为初始点,重复上面的迭代步骤,
得到: X 3 = ( 3 5 2 , 2 5 2 ) X_3 = (\frac{3}{5^2}, \frac{2}{5^2}) X3=(523,522)
根据规律显然可知: X k = ( 3 5 k − 1 , ( − 1 ) k − 1 2 5 k − 1 ) X_k = (\frac{3}{5^{k-1}},(-1)^{k-1}\frac{2}{5^{k-1}}) Xk=(5k−13,(−1)k−15k−12)
例中目标函数 f ( X ) f(X) f(X)是三维空间中的椭圆抛物面,其投影至二维空间上的等高线是一簇椭圆(如下图所示)。 f ( X ) f(X) f(X)的极小点就是这簇椭圆的中心 X ∗ = ( 0 , 0 ) X^*=(0,0) X∗=(0,0)。我们求得的迭代公式 { X k } \{X_k\} {Xk}是逐渐趋近于 X ∗ X^* X∗的
求解函数:
z = 2 ( x − 1 ) 2 + y 2 z = 2(x-1)^2 + y^2 z=2(x−1)2+y2
可求出其梯度为:
( ∂ z ∂ x , ∂ z ∂ y ) = ( 4 x − 4 , 2 y ) (\frac{\partial z}{\partial x},\frac{\partial z}{\partial y}) = (4x-4,2y) (∂x∂z,∂y∂z)=(4x−4,2y)
1. 初始设定
给出初始位置 ( x i , y i ) , i = 0 (x_i,y_i),i=0 (xi,yi),i=0 与 学习率 α = 0.1 \alpha=0.1 α=0.1
2. 计算位移量
( Δ x i , Δ y i ) = − α ( ∂ z ∂ x , ∂ z ∂ y ) = − α ( 4 x i − 4 , 2 y i ) (\Delta x_i,\Delta y_i)= -\alpha(\frac{\partial z}{\partial x},\frac{\partial z}{\partial y}) = -\alpha(4x_i-4,2y_i) (Δxi,Δyi)=−α(∂x∂z,∂y∂z)=−α(4xi−4,2yi)
这个位移量可以看作是通过小步长来找出局部最小值
3. 更新位置
当 i = 0时,将当前位置 ( x 0 , y 0 ) = ( 3 , 2 ) (x_0,y_0)=(3,2) (x0,y0)=(3,2) 与当前计算得到的位移偏移量 ( − 0.8 , − 0.4 ) (-0.8,-0.4) (−0.8,−0.4) 相加得到 ( 2.2 , 1.6 ) (2.2,1.6) (2.2,1.6)
即, ( x i + 1 , y i + 1 ) = ( x i , y i ) + ( Δ x i , Δ y i ) (x_{i+1},y_{i+1}) = (x_i,y_i)+(\Delta x_i,\Delta y_i) (xi+1,yi+1)=(xi,yi)+(Δxi,Δyi)
4. 反复执行2和3的操作
反复执行2和3的操作30次后,得到坐标 ( x 30 , y 30 ) (x_{30},y_{30}) (x30,y30) 的值
由此可以得出,函数 z z z 在 (1,0) 处取得最小值 0
实验环境
Anaconda + python3.6 + jupyter
1. 导入所需库
# 导入所需库
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import math
from mpl_toolkits.mplot3d import Axes3D
import warnings
2. 函数定义
# 原函数
def Z(x,y):
return 2*(x-1)**2 + y**2
# x方向上的梯度
def dx(x):
return 4*x-4
# y方向上的梯度
def dy(y):
return 2*y
3. 赋初值
# 初始值
X = x_0 = 3
Y = y_0 = 2
# 学习率
alpha = 0.1
4. 定义数据保存列表
# 保存梯度下降所经过的点
globalX = [x_0]
globalY = [y_0]
globalZ = [Z(x_0,y_0)]
5. 重复迭代30次
# 迭代30次
for i in range(30):
temX = X - alpha * dx(X)
temY = Y - alpha * dy(Y)
temZ = Z(temX, temY)
# X,Y 重新赋值
X = temX
Y = temY
# 将新值存储起来
globalX.append(temX)
globalY.append(temY)
globalZ.append(temZ)
6. 打印结果
# 打印结果
print(u"最终结果为:(x,y,z)=(%.5f, %.5f, %.5f)" % (X, Y, Z(X,Y)))
print(u"迭代过程中取值")
num = len(globalX)
for i in range(num):
print(u"x%d=%.5f, y%d=%.5f, z%d=%.5f" % (i,globalX[i],i,globalY[i],i,globalZ[i]))
可见,函数 z = 2 ( x − 1 ) 2 + y 2 z = 2(x-1)^2 + y^2 z=2(x−1)2+y2 在 (1,0) 处取得最小值 0,结果跟excel分析的结果一致
7. 绘制过程图
%matplotlib inline
axisX = np.arange(-4,4,0.2)
axisY = np.arange(-4,4,0.2)
axisX, axisY = np.meshgrid(axisX, axisY) # 生成xv、yv,将axisX、axisY变成n*m的矩阵,方便后面绘图
valueZ = np.array(list(map(lambda t : Z(t[0],t[1]),zip(axisX.flatten(),axisY.flatten()))))
valueZ.shape = axisX.shape # 1600的Z图还原成原来的(40,40)
%matplotlib inline
#作图
fig = plt.figure(facecolor='w',figsize=(12,8))
ax = Axes3D(fig)
ax.plot_surface(axisX,axisY,valueZ,rstride=1,cstride=1,cmap=plt.cm.jet)
ax.plot(globalX,globalY,globalZ,'ko-')
ax.set_title(u'$ z=2×(x-1)^2 + y^2 $')
ax.set_xlabel(u'x')
ax.set_ylabel(u'y')
ax.set_zlabel('z')
plt.show()