原理
梯度下降法也是一种继最小二乘法后求解最优解的技术之一,在机器学习和深度学习上的应用也十分广泛。
最小二乘法对于模型并不复杂的情况来说,可以一步到位的求出最优解,这是它的优势也是劣势。因为对于模型稍微复杂点,就无法在理论和公式上给出一步到位的解。这时就需要梯度下降法来迭代地求出最优解。当然求出的也有可能是局部最优解。
代码演示
首先进行一维函数的代码演示:下图是一个关于x的二次函数,找出最优解,使得y最小。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
#构建一维图像
def one_dimension_image(x):
return 0.5*(x-2)**2
#构建一维图像的导数
def one_derivate(x):
return 0.5*2*(x-2)
Gtadient_Descent_X = []#存放梯度下降的X坐标
Gtadient_Descent_Y = []#存放梯度下降的Y坐标
x_current = 8 #X初始值
y_current = one_dimension_image(x_current)
Gtadient_Descent_X.append(x_current)
Gtadient_Descent_Y.append(y_current)
learning_rate = 1.5
iter_num = 0 #迭代次数
f_change = x_current #变换值初始化为X的初始值
while f_change >= 1e-10 and iter_num < 100:
x_now = x_current-learning_rate*one_derivate(x_current)
y_now = one_dimension_image(x_now)
f_change = np.abs(y_current-y_now)
x_current = x_now
y_current = y_now
iter_num += 1
Gtadient_Descent_X.append(x_current)
Gtadient_Descent_Y.append(y_current)
#构建数据集
X_data = np.arange(-4,8,0.05)
Y_data = np.array(list(map(lambda t:one_dimension_image(t),X_data)))
plt.figure(facecolor='w')
plt.plot(X_data,Y_data,'r-',linewidth = 2)
plt.plot(Gtadient_Descent_X,Gtadient_Descent_Y,'bo--',linewidth=2)
plt.title('函数$y=0.5*(x-2)^2$\n学习率为%.3f,最终解为:{%.5f,%.5f},迭代次数为%d'%(learning_rate,x_current,y_current,iter_num))
plt.show()
下面进行二维函数的代码演示,与一维不同的是,这次函数的自变量有两个,一个x1,另一个x2.
import matplotlib as mpl
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
#构建二维图像
def two_dimension_image(x1,x2):
return 0.6*(x1+x2)**2-x1*x2
#构建二维图像的偏导数x1
def two_derivate_x1(x1,x2):
return 0.6*2*(x1+x2)-x2
#构建二维图像的偏导数x2
def two_derivate_x2(x1,x2):
return 0.6*2*(x1+x2)-x1
Gtadient_Descent_X1 = []#存放梯度下降的X1坐标
Gtadient_Descent_X2 = []#存放梯度下降的X2坐标
Gtadient_Descent_F = []#存放梯度下降的F坐标
x1_current = 8 #X1初始值
x2_current = 4 #X2初始值
f_current = two_dimension_image(x1_current,x2_current) #Y初始值
Gtadient_Descent_X1.append(x1_current)
Gtadient_Descent_X2.append(x2_current)
Gtadient_Descent_F.append(f_current)
learning_rate = 0.5
iter_num = 0 #迭代次数
f_change1 = x1_current #变换值初始化为X1的初始值
f_change2 = x2_current #变换值初始化为X2的初始值
while np.abs(f_change1) >= 1e-10 and np.abs(f_change2) >= 1e-10 and iter_num < 500:
x1_now = x1_current-learning_rate*two_derivate_x1(x1_current,x2_current)
x2_now = x2_current-learning_rate*two_derivate_x2(x1_current,x2_current)
f_now = two_dimension_image(x1_now,x2_now)
f_change1 =x1_current-x1_now
f_change2 = x2_current-x2_now
x1_current = x1_now
x2_current = x2_now
f_current = f_now
iter_num += 1
Gtadient_Descent_X1.append(x1_current)
Gtadient_Descent_X2.append(x2_current)
Gtadient_Descent_F.append(f_current)
x1_data = np.arange(-5,5,0.2)
x2_data = np.arange(-5,5,0.2)
x1_data,x2_data = np.meshgrid(x1_data,x2_data)
Y = np.array(list(map(lambda t:two_dimension_image(t[0],t[1]),zip(x1_data.flatten(),x2_data.flatten()))))
Y.shape = x1_data.shape
fig = plt.figure(facecolor='w')
ax = Axes3D(fig)
ax.plot_surface(x1_data,x2_data,Y,rstride = 1,cstride = 1,cmap = plt.cm.jet)
ax.plot(Gtadient_Descent_X1, Gtadient_Descent_X2, Gtadient_Descent_F,'bo--')
ax.set_title('函数$0.6*(x1+x2)^2-x1*x2$,最优解为{%.5f,%.5f,%.5f}\n迭代次数为%d'%(x1_current,x2_current,f_current,iter_num))
plt.show()
部分代码解释
- numpy.meshgrid()——生成网格点坐标矩阵
输入参数x和y是列向量,输出的X和Y是坐标矩阵。
比如输入的x是(3,)的,y是(4,)的,那么输出的X矩阵和Y矩阵就是(3,4)。即总共产生了12*12个点。
x = np.array([0, 1,])
y = np.array([0, 1,2])
X, Y = np.meshgrid(x, y)
print(X)
print(Y)
[[0 1]
[0 1]
[0 1]]
[[0 0]
[1 1]
[2 2]]
- numpy.ndarray.flatten——返回一个折叠成一维的数组
该函数只能适用于numpy对象,即array或者mat,普通的list列表是不行的。
x = np.array([[1,2],[3,4],[5,6]])
a = np.mat([[1,2,3],[4,5,6]])
print(x.flatten())
print(a.flatten())
[1 2 3 4 5 6]
[[1 2 3 4 5 6]]
- plt.figure(facecolor=‘w’)——创建自定义图像
figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True)
num:图像编号或名称,数字为编号 ,字符串为名称
figsize:指定figure的宽和高,单位为英寸,如(4,3);
dpi参数指定绘图对象的分辨率,即每英寸多少个像素,缺省值为80 1英寸等于2.5cm,A4纸是 21*30cm的纸张
facecolor:背景颜色
edgecolor:边框颜色
frameon:是否显示边框
- Axes3D(fig)——用于绘制三维图像,将figure变为3d
ax.plot_surface(X, Y, Z,
rstride=1, # rstride(row)指定行的跨度
cstride=1, # cstride(column)指定列的跨度
cmap=plt.get_cmap(‘rainbow’)) # 设置颜色映射