はじめに
ディープラーニングによく使われている最適化手法がどのような動作をするのか気になったので、ライトコードさんの記事を参考に試してみました。
環境
WSL
ubuntu 22.04
python3.10.6
jupyter
コード
%matplotlib inline
%matplotlib widget
from torch import optim
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np
import torch
#各データの格納リスト
classes = ['SGD', 'Momentum', 'Adagrad', 'RMSprop', 'Adadelta', 'Adam']
x_list = {}
f_list = {}
optimizers = {}
#各種optimizer毎に関数の最適化を行う
for key in classes:
x_list[key] = np.empty((0, 2))
f_list[key] = np.empty((0))
#更新パラメータ(x, y)の初期値
init = [-3., -2.]
x = torch.tensor(init, requires_grad=True)
params = [x]
#学習率
lr = 1
#各optimizerの定義
optimizers['SGD'] = optim.SGD(params, lr=0.001)
optimizers['Momentum'] = optim.SGD(params, lr=0.001, momentum=0.5)
optimizers['Adagrad'] = optim.Adagrad(params, lr)
optimizers['RMSprop'] = optim.RMSprop(params, lr=0.01)
optimizers['Adadelta'] = optim.Adadelta(params, lr)
optimizers['Adam'] = optim.Adam(params, lr)
#関数定義(ビール関数)
f = lambda x: (1.5 - x[0] + x[0]*x[1])**2 + (2.25 - x[0] + x[0]*x[1]**2)**2 + (2.625 - x[0] + x[0]*x[1]**3)**2
#関数の出力に対して勾配を求め、optimizerで更新を繰り返す
for i in range(1000):
optimizers[key].zero_grad()
out = f(x)
out.backward()
optimizers[key].step()
x_list[key] = np.vstack([x_list[key],np.array([x.detach().numpy()])])
f_list[key] = np.append(f_list[key],np.array([out.detach().numpy()]), axis = 0)
#グリッドの計算
xmin, xmax= -5, 5
ymin, ymax= -5, 5
xstep = (xmax - xmin)/50
ystep = (ymax - ymin)/50
x_grid, y_grid = np.meshgrid(np.arange(xmin, xmax + xstep, xstep), np.arange(ymin, ymax + ystep, ystep))
z = f([x_grid,y_grid])
#グラフの出力
fig = plt.figure(figsize=(10, 7))
i = 1
for key in classes:
ax = fig.add_subplot(2, int(len(classes)/2), i, projection='3d')
ax.set_title(key, fontsize=8)
ax.set_xlabel('x', fontsize=8)
ax.set_ylabel('y', fontsize=8)
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)
ax.view_init(elev=50, azim=-10)
ax.plot(init[0], init[1], 'x') #初期位置
ax.plot(3, 0.5, '+') #ゴール(ビール関数)
)
ax.plot(x_list[key][:,0],x_list[key][:,1],f_list[key][:],"ro-", ms=1)
ax.plot_surface(x_grid, y_grid, z, cmap='jet',norm=LogNorm(), alpha = 0.5)
i += 1
結果
検証に最適化のテスト関数であるBeale関数を使用しました。
xマークが初期値、
+マークがゴールになります。
関数のハイパーパラメータによって結果は変わるので、
各手法にどんな傾向があるのか観察することができました。
ほかにも様々な最適化手法があるので、試してみるのも面白いです。
参考文献