python+numpy+matplotalib實現(xiàn)梯度下降法
這個階段一直在做和梯度一類算法相關的東西,索性在這兒做個匯總:
一、算法論述
梯度下降法(gradient descent)別名最速下降法(曾經我以為這是兩個不同的算法-.-),是用來求解無約束最優(yōu)化問題的一種常用算法。下面以求解線性回歸為題來敘述:
設:一般的線性回歸方程(擬合函數(shù))為:(其中
的值為1)

則
這一組向量參數(shù)選擇的好與壞就需要一個機制來評估,據(jù)此我們提出了其損失函數(shù)為(選擇均方誤差):

我們現(xiàn)在的目的就是使得損失函數(shù)
取得最小值,即目標函數(shù)為:

如果
的值取到了0,意味著我們構造出了極好的擬合函數(shù),也即選擇出了最好的
值,但這基本是達不到的,我們只能使得其無限的接近于0,當滿足一定精度時停止迭代。
那么問題來了如何調整
使得
取得的值越來越小呢?方法很多,此處以梯度下降法為例:
分為兩步:(1)初始化
的值。
(2)改變
的值,使得
按梯度下降的方向減少。
值的更新使用如下的方式來完成:


其中
為步長因子,這里我們取定值,但注意如果
取得過小會導致收斂速度過慢,
過大則損失函數(shù)可能不會收斂,甚至逐漸變大,可以在下述的代碼中修改
的值來進行驗證。后面我會再寫一篇關于隨機梯度下降法的文章,其實與梯度下降法最大的不同就在于一個求和符號。
二、代碼實現(xiàn)
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from matplotlib import style
#構造數(shù)據(jù)
def get_data(sample_num=10000):
"""
擬合函數(shù)為
y = 5*x1 + 7*x2
:return:
"""
x1 = np.linspace(0, 9, sample_num)
x2 = np.linspace(4, 13, sample_num)
x = np.concatenate(([x1], [x2]), axis=0).T
y = np.dot(x, np.array([5, 7]).T)
return x, y
#梯度下降法
def GD(samples, y, step_size=0.01, max_iter_count=1000):
"""
:param samples: 樣本
:param y: 結果value
:param step_size: 每一接迭代的步長
:param max_iter_count: 最大的迭代次數(shù)
:param batch_size: 隨機選取的相對于總樣本的大小
:return:
"""
#確定樣本數(shù)量以及變量的個數(shù)初始化theta值
m, var = samples.shape
theta = np.zeros(2)
y = y.flatten()
#進入循環(huán)內
print(samples)
loss = 1
iter_count = 0
iter_list=[]
loss_list=[]
theta1=[]
theta2=[]
#當損失精度大于0.01且迭代此時小于最大迭代次數(shù)時,進行
while loss > 0.001 and iter_count < max_iter_count:
loss = 0
#梯度計算
theta1.append(theta[0])
theta2.append(theta[1])
for i in range(m):
h = np.dot(theta,samples[i].T)
#更新theta的值,需要的參量有:步長,梯度
for j in range(len(theta)):
theta[j] = theta[j] - step_size*(1/m)*(h - y[i])*samples[i,j]
#計算總體的損失精度,等于各個樣本損失精度之和
for i in range(m):
h = np.dot(theta.T, samples[i])
#每組樣本點損失的精度
every_loss = (1/(var*m))*np.power((h - y[i]), 2)
loss = loss + every_loss
print("iter_count: ", iter_count, "the loss:", loss)
iter_list.append(iter_count)
loss_list.append(loss)
iter_count += 1
plt.plot(iter_list,loss_list)
plt.xlabel("iter")
plt.ylabel("loss")
plt.show()
return theta1,theta2,theta,loss_list
def painter3D(theta1,theta2,loss):
style.use('ggplot')
fig = plt.figure()
ax1 = fig.add_subplot(111, projection='3d')
x,y,z = theta1,theta2,loss
ax1.plot_wireframe(x,y,z, rstride=5, cstride=5)
ax1.set_xlabel("theta1")
ax1.set_ylabel("theta2")
ax1.set_zlabel("loss")
plt.show()
def predict(x, theta):
y = np.dot(theta, x.T)
return y
if __name__ == '__main__':
samples, y = get_data()
theta1,theta2,theta,loss_list = GD(samples, y)
print(theta) # 會很接近[5, 7]
painter3D(theta1,theta2,loss_list)
predict_y = predict(theta, [7,8])
print(predict_y)
三、繪制的圖像如下:
迭代次數(shù)與損失精度間的關系圖如下:步長為0.01

變量
、
與損失函數(shù)loss之間的關系:(從初始化之后會一步步收斂到loss滿足精度,之后
、
會變的穩(wěn)定下來)

下面我們來看一副當步長因子變大后的圖像:步長因子為0.5(很明顯其收斂速度變緩了)


當步長因子設置為1.8左右時,其損失值已經開始震蕩


以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
caffe的python接口之手寫數(shù)字識別mnist實例
這篇文章主要為大家介紹了caffe的python接口之手寫數(shù)字識別mnist實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06
Python?range函數(shù)生成一系列連續(xù)整數(shù)的內部機制解析
這篇文章主要為大家介紹了Python?range函數(shù)生成一系列連續(xù)整數(shù)的內部機制解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
Python StringIO模塊實現(xiàn)在內存緩沖區(qū)中讀寫數(shù)據(jù)
這篇文章主要介紹了Python StringIO模塊實現(xiàn)在內存緩沖區(qū)中讀寫數(shù)據(jù),本文講解了使用實例、StringIO類中的方法、文件操作和字符串操作示例等內容,需要的朋友可以參考下2015-04-04
Windows中安裝使用Virtualenv來創(chuàng)建獨立Python環(huán)境
有時我們的程序中需要調用不同版本的Python包和模塊,那么借助Virtualenv的虛擬環(huán)境就可以幫助我們隔離使用,接下來我們就來看一下在Windows中安裝使用Virtualenv來創(chuàng)建獨立Python環(huán)境的方法2016-05-05

