python實(shí)現(xiàn)梯度下降算法的實(shí)例詳解
python版本選擇
這里選的python版本是2.7,因?yàn)槲抑坝胮ython3試了幾次,發(fā)現(xiàn)在畫3d圖的時(shí)候會(huì)報(bào)錯(cuò),所以改用了2.7。
數(shù)據(jù)集選擇
數(shù)據(jù)集我選了一個(gè)包含兩個(gè)變量,三個(gè)參數(shù)的數(shù)據(jù)集,這樣可以畫出3d圖形對(duì)結(jié)果進(jìn)行驗(yàn)證。
部分函數(shù)總結(jié)
symbols()函數(shù):首先要安裝sympy庫(kù)才可以使用。用法:
>>> x1 = symbols('x2')
>>> x1 + 1
x2 + 1
在這個(gè)例子中,x1和x2是不一樣的,x2代表的是一個(gè)函數(shù)的變量,而x1代表的是python中的一個(gè)變量,它可以表示函數(shù)的變量,也可以表示其他的任何量,它替代x2進(jìn)行函數(shù)的計(jì)算。實(shí)際使用的時(shí)候我們可以將x1,x2都命名為x,但是我們要知道他們倆的區(qū)別。
再看看這個(gè)例子:
>>> x = symbols('x')
>>> expr = x + 1
>>> x = 2
>>> print(expr)
x + 1
作為python變量的x被2這個(gè)數(shù)值覆蓋了,所以它現(xiàn)在不再表示函數(shù)變量x,而expr依然是函數(shù)變量x+1的別名,所以結(jié)果依然是x+1。
subs()函數(shù):既然普通的方法無(wú)法為函數(shù)變量賦值,那就肯定有函數(shù)來(lái)實(shí)現(xiàn)這個(gè)功能,用法:
>>> (1 + x*y).subs(x, pi)#一個(gè)參數(shù)時(shí)的用法
pi*y + 1
>>> (1 + x*y).subs({x:pi, y:2})#多個(gè)參數(shù)時(shí)的用法
1 + 2*pi
diff()函數(shù):求偏導(dǎo)數(shù),用法:result=diff(fun,x),這個(gè)就是求fun函數(shù)對(duì)x變量的偏導(dǎo)數(shù),結(jié)果result也是一個(gè)變量,需要賦值才能得到準(zhǔn)確結(jié)果。
代碼實(shí)現(xiàn):
from __future__ import division
from sympy import symbols, diff, expand
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
data = {'x1': [100, 50, 100, 100, 50, 80, 75, 65, 90, 90],
'x2': [4, 3, 4, 2, 2, 2, 3, 4, 3, 2],
'y': [9.3, 4.8, 8.9, 6.5, 4.2, 6.2, 7.4, 6.0, 7.6, 6.1]}#初始化數(shù)據(jù)集
theta0, theta1, theta2 = symbols('theta0 theta1 theta2', real=True) # y=theta0+theta1*x1+theta2*x2,定義參數(shù)
costfuc = 0 * theta0
for i in range(10):
costfuc += (theta0 + theta1 * data['x1'][i] + theta2 * data['x2'][i] - data['y'][i]) ** 2
costfuc /= 20#初始化代價(jià)函數(shù)
dtheta0 = diff(costfuc, theta0)
dtheta1 = diff(costfuc, theta1)
dtheta2 = diff(costfuc, theta2)
rtheta0 = 1
rtheta1 = 1
rtheta2 = 1#為參數(shù)賦初始值
costvalue = costfuc.subs({theta0: rtheta0, theta1: rtheta1, theta2: rtheta2})
newcostvalue = 0#用cost的值的變化程度來(lái)判斷是否已經(jīng)到最小值了
count = 0
alpha = 0.0001#設(shè)置學(xué)習(xí)率,一定要設(shè)置的比較小,否則無(wú)法到達(dá)最小值
while (costvalue - newcostvalue > 0.00001 or newcostvalue - costvalue > 0.00001) and count < 1000:
count += 1
costvalue = newcostvalue
rtheta0 = rtheta0 - alpha * dtheta0.subs({theta0: rtheta0, theta1: rtheta1, theta2: rtheta2})
rtheta1 = rtheta1 - alpha * dtheta1.subs({theta0: rtheta0, theta1: rtheta1, theta2: rtheta2})
rtheta2 = rtheta2 - alpha * dtheta2.subs({theta0: rtheta0, theta1: rtheta1, theta2: rtheta2})
newcostvalue = costfuc.subs({theta0: rtheta0, theta1: rtheta1, theta2: rtheta2})
rtheta0 = round(rtheta0, 4)
rtheta1 = round(rtheta1, 4)
rtheta2 = round(rtheta2, 4)#給結(jié)果保留4位小數(shù),防止數(shù)值溢出
print(rtheta0, rtheta1, rtheta2)
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(data['x1'], data['x2'], data['y']) # 繪制散點(diǎn)圖
xx = np.arange(20, 100, 1)
yy = np.arange(1, 5, 0.05)
X, Y = np.meshgrid(xx, yy)
Z = X * rtheta1 + Y * rtheta2 + rtheta0
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.get_cmap('rainbow'))
plt.show()#繪制3d圖進(jìn)行驗(yàn)證
結(jié)果:


實(shí)例擴(kuò)展:
'''
梯度下降算法
Batch Gradient Descent
Stochastic Gradient Descent SGD
'''
__author__ = 'epleone'
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import sys
# 使用隨機(jī)數(shù)種子, 讓每次的隨機(jī)數(shù)生成相同,方便調(diào)試
# np.random.seed(111111111)
class GradientDescent(object):
eps = 1.0e-8
max_iter = 1000000 # 暫時(shí)不需要
dim = 1
func_args = [2.1, 2.7] # [w_0, .., w_dim, b]
def __init__(self, func_arg=None, N=1000):
self.data_num = N
if func_arg is not None:
self.FuncArgs = func_arg
self._getData()
def _getData(self):
x = 20 * (np.random.rand(self.data_num, self.dim) - 0.5)
b_1 = np.ones((self.data_num, 1), dtype=np.float)
# x = np.concatenate((x, b_1), axis=1)
self.x = np.concatenate((x, b_1), axis=1)
def func(self, x):
# noise太大的話, 梯度下降法失去作用
noise = 0.01 * np.random.randn(self.data_num) + 0
w = np.array(self.func_args)
# y1 = w * self.x[0, ] # 直接相乘
y = np.dot(self.x, w) # 矩陣乘法
y += noise
return y
@property
def FuncArgs(self):
return self.func_args
@FuncArgs.setter
def FuncArgs(self, args):
if not isinstance(args, list):
raise Exception(
'args is not list, it should be like [w_0, ..., w_dim, b]')
if len(args) == 0:
raise Exception('args is empty list!!')
if len(args) == 1:
args.append(0.0)
self.func_args = args
self.dim = len(args) - 1
self._getData()
@property
def EPS(self):
return self.eps
@EPS.setter
def EPS(self, value):
if not isinstance(value, float) and not isinstance(value, int):
raise Exception("The type of eps should be an float number")
self.eps = value
def plotFunc(self):
# 一維畫圖
if self.dim == 1:
# x = np.sort(self.x, axis=0)
x = self.x
y = self.func(x)
fig, ax = plt.subplots()
ax.plot(x, y, 'o')
ax.set(xlabel='x ', ylabel='y', title='Loss Curve')
ax.grid()
plt.show()
# 二維畫圖
if self.dim == 2:
# x = np.sort(self.x, axis=0)
x = self.x
y = self.func(x)
xs = x[:, 0]
ys = x[:, 1]
zs = y
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(xs, ys, zs, c='r', marker='o')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()
else:
# plt.axis('off')
plt.text(
0.5,
0.5,
"The dimension(x.dim > 2) \n is too high to draw",
size=17,
rotation=0.,
ha="center",
va="center",
bbox=dict(
boxstyle="round",
ec=(1., 0.5, 0.5),
fc=(1., 0.8, 0.8), ))
plt.draw()
plt.show()
# print('The dimension(x.dim > 2) is too high to draw')
# 梯度下降法只能求解凸函數(shù)
def _gradient_descent(self, bs, lr, epoch):
x = self.x
# shuffle數(shù)據(jù)集沒(méi)有必要
# np.random.shuffle(x)
y = self.func(x)
w = np.ones((self.dim + 1, 1), dtype=float)
for e in range(epoch):
print('epoch:' + str(e), end=',')
# 批量梯度下降,bs為1時(shí) 等價(jià)單樣本梯度下降
for i in range(0, self.data_num, bs):
y_ = np.dot(x[i:i + bs], w)
loss = y_ - y[i:i + bs].reshape(-1, 1)
d = loss * x[i:i + bs]
d = d.sum(axis=0) / bs
d = lr * d
d.shape = (-1, 1)
w = w - d
y_ = np.dot(self.x, w)
loss_ = abs((y_ - y).sum())
print('\tLoss = ' + str(loss_))
print('擬合的結(jié)果為:', end=',')
print(sum(w.tolist(), []))
print()
if loss_ < self.eps:
print('The Gradient Descent algorithm has converged!!\n')
break
pass
def __call__(self, bs=1, lr=0.1, epoch=10):
if sys.version_info < (3, 4):
raise RuntimeError('At least Python 3.4 is required')
if not isinstance(bs, int) or not isinstance(epoch, int):
raise Exception(
"The type of BatchSize/Epoch should be an integer number")
self._gradient_descent(bs, lr, epoch)
pass
pass
if __name__ == "__main__":
if sys.version_info < (3, 4):
raise RuntimeError('At least Python 3.4 is required')
gd = GradientDescent([1.2, 1.4, 2.1, 4.5, 2.1])
# gd = GradientDescent([1.2, 1.4, 2.1])
print("要擬合的參數(shù)結(jié)果是: ")
print(gd.FuncArgs)
print("===================\n\n")
# gd.EPS = 0.0
gd.plotFunc()
gd(10, 0.01)
print("Finished!")
到此這篇關(guān)于python實(shí)現(xiàn)梯度下降算法的實(shí)例詳解的文章就介紹到這了,更多相關(guān)教你用python實(shí)現(xiàn)梯度下降算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
快速排序的算法思想及Python版快速排序的實(shí)現(xiàn)示例
快速排序算法來(lái)源于分治法的思想策略,這里我們將來(lái)為大家簡(jiǎn)單解析一下快速排序的算法思想及Python版快速排序的實(shí)現(xiàn)示例:2016-07-07
python3顯式變量類型typing的實(shí)現(xiàn)
這篇文章主要介紹了python3顯式變量類型typing的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Pycharm+Flask零基礎(chǔ)項(xiàng)目搭建入門的實(shí)現(xiàn)
本文主要介紹了Pycharm+Flask零基礎(chǔ)項(xiàng)目搭建入門的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
用Python中的__slots__緩存資源以節(jié)省內(nèi)存開(kāi)銷的方法
這篇文章主要介紹了用Python中的__slots__通過(guò)緩存資源的方式以節(jié)省內(nèi)存開(kāi)銷的方法,且示例代碼非常簡(jiǎn)單,需要的朋友可以參考下2015-04-04
Python web框架(django,flask)實(shí)現(xiàn)mysql數(shù)據(jù)庫(kù)讀寫分離的示例
這篇文章主要介紹了Python web框架(django,flask)實(shí)現(xiàn)mysql數(shù)據(jù)庫(kù)讀寫分離的示例,幫助大家更好的理解和學(xué)習(xí)python,感興趣的朋友可以了解下2020-11-11
pip/anaconda修改鏡像源,加快python模塊安裝速度的操作
這篇文章主要介紹了pip/anaconda修改鏡像源,加快python模塊安裝速度的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03
快速進(jìn)修Python指南之網(wǎng)絡(luò)編程及并發(fā)編程
這篇文章主要為大家介紹了Java開(kāi)發(fā)者如何快速進(jìn)修Python指南之網(wǎng)絡(luò)編程及并發(fā)編程實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12

