この記事の例では、参照用に勾配降下アルゴリズムを実装するためのpythonの特定のコードを共有しています。具体的な内容は次のとおりです。
前書き
この記事では、pythonを使用して勾配降下アルゴリズムを実装し、y = Wx + bの線形回帰をサポートします
現在、バッチ勾配アルゴリズムと確率勾配降下アルゴリズムをサポートしています(bs = 1)
また、入力特徴ベクトルのx次元が3未満の画像の視覚化もサポートします。
コードにはpythonバージョン3.4が必要です
コード
'''
勾配降下アルゴリズム
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
# ランダム番号シードを使用して、ランダム番号の生成を毎回同じにします。これは、デバッグに便利です。
# np.random.seed(111111111)classGradientDescent(object):
eps =1.0e-8
max_iter =1000000 #今のところ必要ありません
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 =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]')iflen(args)==0:
raise Exception('args is empty list!!')iflen(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')
# 勾配降下法は凸関数のみを解くことができます
def _gradient_descent(self, bs, lr, epoch):
x = self.x
# シャッフルデータセットは必要ありません
# np.random.shuffle(x)
y = self.func(x)
w = np.ones((self.dim +1,1), dtype=float)for e inrange(epoch):print('epoch:'+str(e), end=',')
# バッチ勾配降下、bsが1の場合、同等の単一サンプル勾配降下
for i inrange(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('フィッティングの結果は:', 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("適合させるパラメータの結果は次のとおりです。: ")print(gd.FuncArgs)print("===================\n\n")
# gd.EPS =0.0
gd.plotFunc()gd(10,0.01)print("Finished!")
以上が本稿の内容ですので、皆様のご勉強に役立てていただければ幸いです。
Recommended Posts