赞
踩
要找到某个函数的最小值,就是沿着该函数的梯度的负方向寻找。若寻找某函数最大值,则沿着梯度方向找。
那么梯度下降数学表示:
梯度上升数学表示:
上述某函数可以理解成最小二乘问题(线性回归和非线性)的损失函数,均方误差损失表示为:
对于凸函数可以使用最小二乘法求解最优点,过程是求关于w的导数,使导数等于0即可
对于梯度下降法则需要迭代N次,每次将wi带入上式中求得wi值下的导数,然后求得wi+1的值
上图是梯度下降求解过程,假设求解一个线性回归问题,目标函数是均方误差最小,数学公式表示为:
用矩阵表示为:
则梯度的负方向寻找最小点,p0是开始位置,w0可以使初始值1的矩阵,则将w0带入导数方程求得w0导数,那么根据梯度下降法
首先生成随机样本:
- x = np.arange(0, 100, 1)
- y = x * 11.8 - np.random.standard_normal(100) * 100
使用梯度下降法求解结果如下图
第一张图表示样本分布,第二张(右上)表示使用梯度下降法求解拟合直线,第三张(左下)表示随着迭代次数增加模型损失逐渐下降直至平稳,第四张图表示参数的学习效果,随着迭代次数增加参数学习逐渐稳定。
- 迭代 1 损失:18659840.76439424,weight参数:[[1.0539232487566108, 4.578364388994817]]
- 迭代 2 损失:9004152.836684883,weight参数:[[1.0901282014628215, 6.981505910781841]]
- 迭代 3 损失:4649307.430631565,weight参数:[[1.1144339831409158, 8.5953966993742]]
- 迭代 4 损失:2685213.4523903765,weight参数:[[1.13074857483731, 9.679246133912951]]
- 迭代 5 损失:1799380.5932514765,weight参数:[[1.1416964803735679, 10.407132849392006]]
- 迭代 6 损失:1399858.0328088128,weight参数:[[1.1490402518776508, 10.89596376971111]]
- 迭代 7 损失:1219667.972099556,weight参数:[[1.1539635759490037, 11.22425070567449]]
- 迭代 8 损失:1138399.8251730944,weight参数:[[1.157261387354931, 11.44472025576014]]
- 迭代 9 损失:1101746.7947403109,weight参数:[[1.1594675447067935, 11.59278230490871]]
- 迭代 10 损失:1085215.783217484,weight参数:[[1.1609405742996355, 11.692217259740454]]
迭代10轮,直线方程可以表达为y = 11.692217259740454* x +1.1609405742996355和样本生成方程即(y = x * 11.8 - np.random.standard_normal(100) * 100)比较接近了
python实现代码如下
- # @Time : 2020/6/16 19:42
- # @Author : 大太阳小白
- # @Software: PyCharm
- """
- 通过程序理解如何使用梯度下降求解
- 1、首先程序定义一个样本集,用来代替真实数据的分布
- 2、计算模型误差,使用均方误差
- 3、利用均方误差求导,解出关于待定参数w的导数
- 4、目标函数是误差最小,则关于w的方程求w下降最快方向使目标函数下降最快
- 5、定义w初始位置,带入导数方程,求得关于初始位置w的导数
- 6、w根据w位置导数移动lamda倍步长,得到新的w1点,带入导数方程求w1导数,如此迭代
- 7、当满足一定迭代限制或是误差限制时停止迭代,求得w值
- """
- import numpy as np
- import matplotlib.pyplot as plt
-
-
- def create_sample_set():
- """
- 生成样本数据集
- :return:
- """
- x = np.arange(0, 100, 1)
- y = x * 11.8 - np.random.standard_normal(100) * 100
- return x, y
-
-
- def loss(weight, x, y):
- """
- 损失函数使用均方误差
- :param weight:权重
- :param x:
- :param y:
- :return:
- """
- return (x * weight - y).T * (x * weight - y)
-
-
- def gradient(weight, x, y):
- """
- 基于损失函数求关于w的导数
- :param weight:
- :param x:
- :param y:
- :return:
- """
- return x.T * (x * weight - y)
-
-
- def gradient_descent(x, y, max_iter=10, learning_rate=0.001):
- """
- 梯度下降求解
- :param x:
- :param y:
- :param max_iter:
- :param learning_rate:
- :return:
- """
- m, n = np.shape(x)
- weight = np.mat(np.ones((n, 1)))
- loss_arr = []
- weight_arr = np.zeros((max_iter,n))
- for i in range(max_iter):
- g = gradient(weight, x, y)
- weight = weight - learning_rate * g
- error = loss(weight, x, y).T.tolist()[0][0]
- loss_arr.append(error)
- weight_arr[i, :] = weight.T
- print("迭代 {} 损失:{},weight参数:{}".format(i + 1, error, weight.T.tolist()))
-
- return weight,loss_arr,weight_arr
-
-
- if __name__ == '__main__':
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
- features, labels = create_sample_set()
- X = np.ones((2, 100))
- X[1] = np.mat(features)
- X = X.T
- Y = labels.reshape(100, 1)
- weights,loss_array,weights_array = gradient_descent(X, Y, learning_rate=0.000001)
- # 绘制曲线
- fig = plt.figure()
-
- ax1 = fig.add_subplot(2, 2, 1)
- ax1.set_title("样本数据分布" )
- ax1.scatter(features, labels)
- ax2 = fig.add_subplot(2, 2, 2)
- ax2.set_title("梯度下降拟合效果" )
- ax2.scatter(features, labels)
- ax2.plot(features, (X * weights).T.tolist()[0])
- ax3 = fig.add_subplot(2, 2, 3)
- ax3.set_title("随着迭代次数增加loss走势")
- ax3.plot(range(len(loss_array)), loss_array)
- ax4 = fig.add_subplot(2, 2, 4)
- ax4.set_title("随着迭代数增加学习的参数逐渐稳定")
- ax4.plot(np.array(weights_array))
-
-
- plt.show()
模型使用的学习率很小,可以尝试加大学习率(会出现问题),这个时候可以考虑对样本数据进行标准化。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。