1. 梯度下降法简介
1-1
以下是定义了一个损失函数以后,参数theta对应的损失函数J的值对应的示例图,我们需要找到使得损失函数值J取得最小值对应的theta(这里是二维平面,也就是我们的参数只有一个)
在直线方程中,导数代表斜率
在曲线方程中,导数代表切线斜率
导数代表theta单位变化时,J相应的变化
1-2
1-3
η太小,会减慢收敛学习速度
1-4
η太大,甚至导致不收敛
1-5
其他注意事项
-
并不是所有函数都有唯一的极值点
1-6
解决方案:
- 多次运行,随机化初始点
- 梯度下降法的初始点也是一个超参数
1-7
2 梯度下降法模拟
2.1 实现
import numpy as np
import matplotlib.pyplot as plt
# 简单模拟一个损失函数
plot_x = np.linspace(-1,6,141)
plot_y = (plot_x-2.5)**2-1
# 绘制我们模拟的损失函数
plt.plot(plot_x,plot_y)
2.1-1
def dJ(theta):
"""损失函数的导数"""
return 2*(theta-2.5)
def J(theta):
"""损失函数"""
try:
return (theta-2.5)**2-1
except:
return float('inf')
def gradient_descent(initial_theta,eta,n_iters = 1e4,epsilon=1e-8):
"""
梯度下降法封装
initial_theta:初始化的theta值
eta:学习率η
n_iters: 最大循环次数
epsilon: 精度
"""
theta = initial_theta
# theta_history 保存theta的变化值
theta_history.append(initial_theta)
i_iters = 0
while i_iters<n_iters:
"""
如果theta两次变化之间的损失函数值的变化小于我们定义的精度
则可以说明我们已经找到了最低的损失函数值和对应的theta
如果循环次数超过了我们设置的循环次数,
则说明可能由于η设置的过大导致无止境的循环
"""
gradient = dJ(theta)
last_theta = theta
theta = theta - eta * gradient
theta_history.append(theta)
if (abs(J(theta)-J(last_theta)) < epsilon):
break
i_iters += 1
def plot_theta_history():
plt.plot(plot_x,J(plot_x))
plt.plot(np.array(theta_history),J(np.array(theta_history)),color='r',marker='+')
print("the size of theta_history is %d"%len(theta_history))
2.2 使用不同η学习率测试并观察我们的梯度下降法的结果
eta = 0.1
theta_history = []
gradient_descent(0.,eta)
plot_theta_history()
2.2-1
eta = 0.01
theta_history = []
gradient_descent(0.,eta)
plot_theta_history()
2.2-2
eta = 0.001
theta_history = []
gradient_descent(0.,eta)
plot_theta_history()
2.2-3
eta = 0.8
theta_history = []
gradient_descent(0.,eta)
plot_theta_history()
2.2-4
可以发现,只要η不超过一个限度,我们编写的函数都可以在有限次数之后找到最优解,并且η越小,学习的次数越多
下面来看一下,如果eta取较大值1.1,会出现什么情况
eta = 1.1
theta_history = []
gradient_descent(0.,eta)
# 数据量太大会报错
# plot_theta_history()
print