梯度下降
概念
梯度是一个向量,表示函数在某一点处的方向导数,函数在这点沿着该方向变化最快。
由此可知,当函数是一维函数时,梯度就是导数。
一维梯度下降
程序:使用梯度下降求解方程 y=x2−2x+1y=x2−2x+1 的最小值。
观察学习率对梯度下降的影响。
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False
import numpy as np
%matplotlib tk
# 给定一个初始值(是什么不重要),然后根据梯度来对该值(x)进行调整。使得
# x的值令y值最小。
# 定义原函数
def f(x):
return x ** 2 - 2 * x + 1
# 定义导函数(梯度函数)
def gradient(x):
return 2 * x - 2
# 定义一个列表,来保存x的更新轨迹。
x_list = []
# 定义一个列表,来保存y的更新轨迹。
y_list = []
# 定义学习率。
eta = 0.1
# 定义x的初始值。
x = 10
# 进行循环迭代,在循环中,不管根据x的梯度值更新x,使得更新后的x值,令y值更小。
for i in range(10):
# 将x与y值加入到轨迹列表中。
x_list.append(x)
y_list.append(f(x))
# 对自变量x进行调整。(根据梯度)
x = x - eta * gradient(x)
# display(x_list)
# display(y_list)
# 绘制图像
x = np.arange(-9, 11, 0.1)
y = f(x)
plt.plot(x, y)
# 画出x,y点的移动轨迹。
plt.plot(x_list, y_list, "ro--")
# title等方法中,也同样支持latex语法。
plt.title("函数$y=x^{2} -2x + 1$")
二维梯度下降
程序:使用梯度下降求解方程 y=0.2(x1+x2)2−0.3x1x2+0.4y=0.2(x1+x2)2−0.3x1x2+0.4 的最小值。
from mpl_toolkits.mplot3d import Axes3D
# 定义原函数
def f(x1, x2):
return 0.2 * (x1 + x2) ** 2 - 0.3 * x1 * x2 + 0.4
# 定义梯度函数(导函数)
def gradient_x1(x1, x2):
return 0.4 * (x1 + x2) - 0.3 * x2
def gradient_x2(x1, x2):
return 0.4 * (x1 + x2) - 0.3 * x1
# 定义学习率
eta = 1.5
# 定义x1,x2与y的轨迹列表。
x1_list = []
x2_list = []
y_list = []
# 定义初始位置
x1, x2 = 4.5, 4.5
for i in range(50):
# 轨迹列表加入相应的轨迹
x1_list.append(x1)
x2_list.append(x2)
y_list.append(f(x1, x2))
x1 = x1 - eta * gradient_x1(x1, x2)
x2 = x2 - eta * gradient_x2(x1, x2)
# display(x1_list)
# display(x2_list)
# display(y_list)
X1 = np.arange(-5, 5, 0.1)
X2 = np.arange(-5, 5, 0.1)
# 网状结构。
# X1看做一个列向量,会沿着行进行扩展。扩展的行数与X2元素的个数相同。
# X2看做一个行向量,会沿着列进行扩展。扩展的列数与X1元素的个数相同。
# 返回扩展之后的X1与X2。(经过扩展之后,X1与X2的形状是相同的。)
# meshgrid扩展的目的:经过扩展之后,我们就可以获得任意X1与X2中元素的组合。(例如Ptyhon zip)
X1, X2 = np.meshgrid(X1, X2)
Y = f(X1, X2)
fig = plt.figure()
# 创建3D绘图对象,在参数(figure)上进行绘图。
ax = Axes3D(fig)
# 绘制曲面图。
ax.plot_surface(X1, X2, Y, rstride=5, cstride=5, cmap="rainbow")
ax.plot(x1_list, x2_list, y_list, "bo--")