一 梯度下降法原理
梯度下降(Gradient Descent, GD),是一种基于搜索的最优化方法。梯度下降(Gradient Descent, GD)优化算法,其作用是用来对原始模型的损失函数进行优化,以便寻找到最优的参数,使得损失函数的值最小。
机器学习就是需找一种函数f(x)并进行优化, 且这种函数能够做预测、分类、生成等工作。而梯度下降是目前机器学习、深度学习解决最优化问题的算法中,最核心、应用最广的方法。说白了,梯度就是向量,是多元函数的导数,梯度指向误差值增加最快的方向,导数为0(梯度为0向量)的点,就是优化问题的解。
梯度下降法,从理论上来讲,只能得到局部最优解,而不能得到全局最优解,可以尝试用过以下方法解决即:首先随机产生多个初始参数集,即多组参数集合;然后分别对每个初始参数集使用梯度下降法,直到函数值收敛于某个值;最后从这些值中找出最小值,这个找到的最小值被当作函数的最小值。当然这种方式不一定能找到全局最优解,但是起码能找到较好的。
对多元线性回归的损失函数进行求导,在真实数据中效果比较差,这是因为数据的规模不一样,因此在梯度下降之前需要使用归一化。
数据归一化
from sklearn.preprocessing import StandardScaler
standardScaler = StandardScaler()
standardScaler.fit(X_train)
X_train_std = standardScaler.transform(X_train)
lin_reg3 = LinearRegression()
lin_reg3.fit_gd(X_train_std, y_train)
X_test_std = standardScaler.transform(X_test)
lin_reg2.score(X_test, y_test)
二 代码实现
python中有两种常见求导的方法,一种是使用Scipy库中的derivative方法,另一种就Sympy库中的diff方法。
import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import derivative
def lossFunction(x):
return (x-2.5)**2-1
import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import derivative
def lossFunction(x):
return (x-2.5)**2-1
# 在-1到6的范围内构建140个点
plot_x = np.linspace(-1,6,141)
# plot_y 是对应的损失函数值
plot_y = lossFunction(plot_x)
plt.plot(plot_x,plot_y)
plt.show()
算法:计算损失函数J在当前点的对应导数
输入:当前数据点theta
输出:点在损失函数上的导数
def dLF(theta):
return derivative(lossFunction, theta, dx=1e-6)
theta = 0.0
eta = 0.1
epsilon = 1e-6
while True:
# 每一轮循环后,要求当前这个点的梯度是多少
gradient = dLF(theta)
last_theta = theta
# 移动点,沿梯度的反方向移动步长eta
theta = theta - eta * gradient
# 判断theta是否达到最小值
# 因为梯度在不断下降,因此新theta的损失函数在不断减小
# 看差值是否达到了要求
if(abs(lossFunction(theta) - lossFunction(last_theta)) < epsilon):
break
print(theta)
print(lossFunction(theta))
创建一个用于存放所有点位置的列表,然后将其在图上绘制出
def gradient_descent(initial_theta, eta, epsilon=1e-6):
theta = initial_theta
theta_history.append(theta)
while True:
# 每一轮循环后,要求当前这个点的梯度是多少
gradient = dLF(theta)
last_theta = theta
# 移动点,沿梯度的反方向移动步长eta
theta = theta - eta * gradient
theta_history.append(theta)
# 判断theta是否达到损失函数最小值的位置
if(abs(lossFunction(theta) - lossFunction(last_theta)) < epsilon):
break
def plot_theta_history():
plt.plot(plot_x,plot_y)
plt.plot(np.array(theta_history), lossFunction(np.array(theta_history)), color='red', marker='o')
plt.show()
调整学习率
eta=0.1
theta_history = []
gradient_descent(0., eta)
plot_theta_history()
print("梯度下降查找次数:",len(theta_history))
在刚开始时移动比较大,因为学习率是一定的,再乘上梯度本身数值大(比较陡),后来梯度数值小(平缓)所以移动的比较小。且经历了34次查找。
使用使用学习率0.01/0.9进行观察
学习率过小,收敛学习速度变慢,使得算法的效率降低;学习率过大又会导致不收敛
参考:https://mp.weixin.qq.com/s/nI9IBa4ccfg0xqyn0tbRPA
https://mp.weixin.qq.com/s/nI9IBa4ccfg0xqyn0tbRPA