ディープラーニングのお勉強体験記”30:番外編「XP」の各sin波コード”(リカレントニューラルネットワーク”RNN”を中心にバックプロパゲーション”BPTT”を数式を使って理解したい!)
「ゼロから作るDeep Learning 2 ―自然言語処理編」のRNNコード、P216、第5章「5.5.3 RNNLMの学習コード」から作ったWindows XPの各sin波コード
前回「Windows xp」でAnacondaを使えるようにしたと紹介しました。でもって、ここではそこで動く「sin波学習コード」紹介します。わざわざ紹介する内容でもないかもしれませんが、、、、、、
「Jupyter Notebook」を使うということと(普段は「Jupyter Lab」を使ってます)、コードの先頭部分に「%matplotlib inline」を追加する、グラフの表示部分をちょっと書き換えるだけ(1波形1コマンドラインにする)と、簡単ですから、、、、、
でもまあ、一応書かせてもらいます!(簡単なことでも、それなりに苦労はしていますので)
目次
1:xp用のRNNのSIN波コード
# 完成版 Windows xp用 RNNコード
# ゼロから作る Deep Learning2のP216、第5章「5.5.3 RNNLMの学習コード」でコード全体が見えるようにできるだけ「import」を外した
# プログラムの動作検証用にSINカーブを学習させるため変更したコード
# coding: utf-8
# import sys
# sys.path.append('C:\\kojin\\資料\\AI関連\\ゼロから作る Deep Learning\\ゼロから作る Deep Learning2\\deep-learning-from-scratch-2-master\\')
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
# from common.optimizer import SGD
# from dataset import ptb # このimportを有効にするには上記パス設定「sys.path.append('C:\\kojin\\AI関連\\・・・」が必要!
# from simple_rnnlm import SimpleRnnlm
np.random.seed(seed=255) # 発生する乱数を固定する(255)
# ハイパーパラメータの設定
batch_size = 10
time_size = 10 # Truncated BPTTの展開する時間サイズ
n_in = 1 # 入力層のニューロン数
n_mid = 45 # 中間層のニューロン数
n_out = 1 # 出力層のニューロン数
# できるだけオリジナルのコードに変更を加えないため、既存の変数に代入する
vocab_size = n_out
wordvec_size = n_in
hidden_size = n_mid
lr = 0.008
max_epoch = 301
# 学習データの読み込み
## -------------------学習用データ------------------------------------
# -- 訓練データの作成 --
sin_x = np.linspace(-2*np.pi, 2*np.pi, 101) # -2πから2πまで
sin_y = np.sin(sin_x) # sin関数 predict用で使用する(なんかバグがある、predict部分で再宣言必要)
sin_y_noise = np.sin(sin_x) + 0.05*np.random.randn(len(sin_x)) # sin関数に乱数でノイズを加える
x_data = sin_y_noise.reshape(-1, 1)
t_data = sin_y_noise.reshape(-1, 1)
#------------------------------------------------------------------------------------------------
xs = x_data[:-1] # 入力
ts = t_data[1:] # 出力(教師ラベル)
data_size = len(xs)
#///////////////////RNNに対応した「time_size」行列の学習用データを作成 開始部分/////////////////////////
x_time = np.empty((data_size - time_size, time_size, wordvec_size), dtype='f')
t_time = np.empty((data_size - time_size, time_size, vocab_size), dtype='f')
for i in range(data_size - time_size):
for j in range(time_size):
x_time[i, j, :] = xs[i + j]
t_time[i, j, :] = ts[i + j]
#///////////////////RNNに対応した「time_size」行列の学習用データを作成 終了部分/////////////////////////
# 学習時に使用する変数
# max_iters = data_size // (batch_size * time_size)
max_iters = data_size // batch_size # SIN波学習のデータ量として、「time_size」で割ってしまうと足りなくなる
time_idx = 0
total_loss = 0
loss_count = 0
ppl_list = []
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# できるだけimportを外すため、classをコピペした箇所の「開始」部分
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# GPUを定義しておく(コードのどこかでこの定義を参照しているらしいけど、PCにNVIDIA無いので、下記定義をするだけ)
GPU = False
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# optimizer.py の抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
class SGD:
'''
確率的勾配降下法(Stochastic Gradient Descent)
'''
def __init__(self, lr=0.01):
self.lr = lr
def update(self, params, grads):
for i in range(len(params)):
params[i] -= self.lr * grads[i]
# ---------------------------------------------------------------------------------------------------------------------------
# optimizer.py の抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# time_layers.py の抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
class TimeAffine:
def __init__(self, W, b):
self.params = [W, b]
self.grads = [np.zeros_like(W), np.zeros_like(b)]
self.x = None
def forward(self, x):
N, T, D = x.shape
W, b = self.params
rx = x.reshape(N*T, -1)
out = np.dot(rx, W) + b
self.x = x
return out.reshape(N, T, -1)
def backward(self, dout):
x = self.x
N, T, D = x.shape
W, b = self.params
dout = dout.reshape(N*T, -1)
rx = x.reshape(N*T, -1)
db = np.sum(dout, axis=0)
dW = np.dot(rx.T, dout)
dx = np.dot(dout, W.T)
dx = dx.reshape(*x.shape)
self.grads[0][...] = dW
self.grads[1][...] = db
return dx
class RNN:
def __init__(self, Wx, Wh, b):
self.params = [Wx, Wh, b]
self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]
self.cache = None
def forward(self, x, h_prev):
Wx, Wh, b = self.params
t = np.dot(h_prev, Wh) + np.dot(x, Wx) + b
h_next = np.tanh(t)
self.cache = (x, h_prev, h_next)
return h_next
def backward(self, dh_next):
Wx, Wh, b = self.params
x, h_prev, h_next = self.cache
dt = dh_next * (1 - h_next ** 2)
db = np.sum(dt, axis=0)
dWh = np.dot(h_prev.T, dt)
dh_prev = np.dot(dt, Wh.T)
dWx = np.dot(x.T, dt)
dx = np.dot(dt, Wx.T)
self.grads[0][...] = dWx
self.grads[1][...] = dWh
self.grads[2][...] = db
return dx, dh_prev
class TimeRNN:
def __init__(self, Wx, Wh, b, stateful=False):
self.params = [Wx, Wh, b]
self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]
self.layers = None
self.h, self.dh = None, None
self.stateful = stateful
def forward(self, xs):
Wx, Wh, b = self.params
N, T, D = xs.shape
D, H = Wx.shape
self.layers = []
hs = np.empty((N, T, H), dtype='f')
if not self.stateful or self.h is None:
self.h = np.zeros((N, H), dtype='f')
for t in range(T):
layer = RNN(*self.params)
self.h = layer.forward(xs[:, t, :], self.h)
hs[:, t, :] = self.h
self.layers.append(layer)
return hs
def backward(self, dhs):
Wx, Wh, b = self.params
N, T, H = dhs.shape
D, H = Wx.shape
dxs = np.empty((N, T, D), dtype='f')
dh = 0
grads = [0, 0, 0]
for t in reversed(range(T)):
layer = self.layers[t]
dx, dh = layer.backward(dhs[:, t, :] + dh)
dxs[:, t, :] = dx
for i, grad in enumerate(layer.grads):
grads[i] += grad
for i, grad in enumerate(grads):
self.grads[i][...] = grad
self.dh = dh
return dxs
def set_state(self, h):
self.h = h
def reset_state(self):
self.h = None
class TimeOutputWithLoss:
# このコードは「class TimeSoftmaxWithLoss」の代わりに実装する
def __init__(self):
self.cache = None
def forward(self, xs, ts):
N, T, D = xs.shape # ここでDは1
# RNNのタイプに合わせて「#1」か「#2」を選択する
# # ------------------RNN many to many start---------------#1
# loss = 0.5 * np.sum((xs - ts)**2) #1
# loss /= N # 1データ分での誤差 #1
# # -------------------RNN many to many end----------------#1
# ------------------RNN many to one start----------------#2
loss = 0.5 * np.sum((xs[:, T-1, :] - ts[:, T-1, :])**2) #2
loss /= N # 1データ分での誤差 #2
# -------------------RNN many to one end-----------------#2
self.cache = (ts, xs, (N, T, D))
return loss
def backward(self, dout=1):
ts, xs, (N, T, D) = self.cache
# RNNのタイプに合わせて「#1」か「#2」を選択する
# # ------------------RNN many to many start---------------#1
# dout = xs - ts #1
# dout /= N #1
# # -------------------RNN many to many end----------------#1
# ------------------RNN many to one start----------------#2
dout = np.zeros([N, T, D], dtype='float') #2
dout[:, T-1, :] = xs[:, T-1, :] - ts[:, T-1, :] #2
# -------------------RNN many to one end-----------------#2
return dout
# ---------------------------------------------------------------------------------------------------------------------------
# time_layers.py の抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# simple_rnnlm.py の抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
class SimpleRnnlm:
def __init__(self, vocab_size, wordvec_size, hidden_size):
V, D, H = vocab_size, wordvec_size, hidden_size
rn = np.random.randn
# 重みの初期化
# embed_W = (rn(V, D) / 100).astype('f') # embedingレイヤは無効にする
rnn_Wx = (rn(D, H) / np.sqrt(D)).astype('f')
rnn_Wh = (rn(H, H) / np.sqrt(H)).astype('f')
rnn_b = np.zeros(H).astype('f')
affine_W = (rn(H, V) / np.sqrt(H)).astype('f')
affine_b = np.zeros(V).astype('f')
# レイヤの生成
self.layers = [
# TimeEmbedding(embed_W), # embedingレイヤは無効にする
TimeRNN(rnn_Wx, rnn_Wh, rnn_b, stateful=True),
TimeAffine(affine_W, affine_b)
# Simple_TimeAffine(affine_W, affine_b)
]
# self.loss_layer = TimeSoftmaxWithLoss() # TimeSoftmaxWithLossレイヤは無効にする
self.loss_layer = TimeOutputWithLoss()
self.rnn_layer = self.layers[0] # 「TimeEmbedding」を外したので「TimeRNN」を「self.rnn_layer」にするため「self.layers[1]」を「self.layers[0]」にした
# すべての重みと勾配をリストにまとめる
self.params, self.grads = [], []
for layer in self.layers:
self.params += layer.params
self.grads += layer.grads
#------オリジナルコードに予測(predict)が無いので、LSTMのコードから持ってくる------
def predict(self, xs):
for layer in self.layers:
xs = layer.forward(xs)
return xs
def forward(self, xs, ts):
for layer in self.layers:
xs = layer.forward(xs)
loss = self.loss_layer.forward(xs, ts)
return loss
def backward(self, dout=1):
dout = self.loss_layer.backward(dout)
for layer in reversed(self.layers):
dout = layer.backward(dout)
return dout
def reset_state(self):
self.rnn_layer.reset_state()
# ---------------------------------------------------------------------------------------------------------------------------
# simple_rnnlm.py の抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# できるだけimportを外すため、classをコピペした箇所の「終了」部分
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# モデルの生成
model = SimpleRnnlm(vocab_size, wordvec_size, hidden_size)
optimizer = SGD(lr)
# ミニバッチの各サンプルの読み込み開始位置を計算
# jump = (corpus_size - 1) // batch_size
# offset = [i * jump for i in range(batch_size)]
for epoch in range(max_epoch):
#---「common」の「trainer.py」から「class Trainer」よりデータをシャッフルする部分を抜粋---
time_idx = 0 # インデックス追加部分
# シャッフル
idx = np.random.permutation(np.arange(data_size - time_size))
x_shuffle = x_time[idx, ]
t_shuffle = t_time[idx, ]
#-----------------------------------------------------------------------------------
# /////////////////////////////////////////////////////////////////////////////////////////////////////////
for iter in range(max_iters - 1):
# ミニバッチの取得
batch_x = np.empty((batch_size, time_size, wordvec_size), dtype='f')
batch_t = np.empty((batch_size, time_size, vocab_size), dtype='f')
for i in range(batch_size):
batch_x[i, :, :] = x_shuffle[time_idx + i, ]
batch_t[i, :, :] = t_shuffle[time_idx + i, ]
time_idx += batch_size
# /////////////////////////////////////////////////////////////////////////////////////////////////////////
# 勾配を求め、パラメータを更新
loss = model.forward(batch_x, batch_t)
model.backward()
optimizer.update(model.params, model.grads)
total_loss += loss
loss_count += 1
# エポックごとにパープレキシティの評価 「パープレキシティ」はここでは「ロス」として扱う
# ppl = np.exp(total_loss / loss_count)
ppl = total_loss
# print('| epoch %d | perplexity %.2f'
# % (epoch+1, ppl))
ppl_list.append(float(ppl))
total_loss, loss_count = 0, 0
#----------------予測部分開始-------------------------------------
# -- 予測 --
# 順伝播 RNN層
# x_predict = xs[:]
x_predict = sin_y.reshape(-1, 1) # x_predictのデータ構造をsin_yと同じにしている
x_predict.fill(0.0)
sin_y = np.sin(sin_x) # sin関数 なぜかここで再定義しないとsinデータを読み込まない
for i in range(time_size):
x_predict[i, ] = sin_y[i, ] # 「x_predict」の最初の「time_size」分SIN波データを組み込む
# y_predict = np.empty((batch_size, wordvec_size, vocab_size), dtype='f')
y_predict = np.empty((batch_size, time_size, vocab_size), dtype='f')
pred_batch_x = np.empty((batch_size, time_size, wordvec_size), dtype='f')
# batch_x = np.empty((batch_size, time_size, wordvec_size), dtype='f')
# 「batch_size」 ありきでコードが組まれているので、入力データを「batch_size」分、重複させて作る
for j in range(data_size - time_size + 1):
for t in range(time_size):
for i in range(batch_size):
pred_batch_x[i, t, :] = x_predict[j + t, ] # データは時系列に作成、「batch_size」分、重複させている
y_predict = model.predict(pred_batch_x)
x_predict[j + time_size, :] = y_predict[0, time_size-1, 0]
#-----------------予測部分終了------------------------------------
# グラフの描画 誤差の表示部分
x = np.arange(len(ppl_list))
plt.plot(x, ppl_list, color='c', label='train')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()
# グラフの描画 学習結果の波形パターンの一致度合いを表示
td = ts.reshape(-1)
x_pre = x_predict[:-1]
x = np.arange(len(td))
# x = np.arange(len(x_predict))
# plt.plot(x, td, x_predict, label='train')
plt.plot(x, td, color='b', label='target')
plt.plot(x, x_pre, color='r', label='predict')
plt.xlabel('epochs')
plt.ylabel('sin(x)')
plt.show()
実行結果は
です。
2:xp用のLSTMのSIN波コード
# 完成版 Windows xp用 LSTMコード
# ゼロから作る Deep Learning2のP216、第5章「5.5.3 RNNLMの学習コード」でコード全体が見えるようにできるだけ「import」を外した
# プログラムの動作検証用にSINカーブを学習させるため変更したコード
# coding: utf-8
# import sys
# sys.path.append('C:\\kojin\\資料\\AI関連\\ゼロから作る Deep Learning\\ゼロから作る Deep Learning2\\deep-learning-from-scratch-2-master\\')
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
# from common.optimizer import SGD
# from dataset import ptb # このimportを有効にするには上記パス設定「sys.path.append('C:\\kojin\\AI関連\\・・・」が必要!
# from simple_rnnlm import SimpleRnnlm
np.random.seed(seed=773) # 発生する乱数を固定する(773 326 512 138)
# ハイパーパラメータの設定
batch_size = 10
time_size = 10 # Truncated BPTTの展開する時間サイズ
n_in = 1 # 入力層のニューロン数
n_mid = 45 # 中間層のニューロン数
n_out = 1 # 出力層のニューロン数
# できるだけオリジナルのコードに変更を加えないため、既存の変数に代入する
vocab_size = n_out
wordvec_size = n_in
hidden_size = n_mid
lr = 0.008
max_epoch = 301
# 学習データの読み込み
## -------------------学習用データ------------------------------------
# -- 訓練データの作成 --
sin_x = np.linspace(-2*np.pi, 2*np.pi, 101) # -2πから2πまで
sin_y = np.sin(sin_x) # sin関数 predict用で使用する(なんかバグがある、predict部分で再宣言必要)
sin_y_noise = np.sin(sin_x) + 0.05*np.random.randn(len(sin_x)) # sin関数に乱数でノイズを加える
x_data = sin_y_noise.reshape(-1, 1)
t_data = sin_y_noise.reshape(-1, 1)
#------------------------------------------------------------------------------------------------
xs = x_data[:-1] # 入力
ts = t_data[1:] # 出力(教師ラベル)
data_size = len(xs)
#///////////////////RNNに対応した「time_size」行列の学習用データを作成 開始部分/////////////////////////
x_time = np.empty((data_size - time_size, time_size, wordvec_size), dtype='f')
t_time = np.empty((data_size - time_size, time_size, vocab_size), dtype='f')
for i in range(data_size - time_size):
for j in range(time_size):
x_time[i, j, :] = xs[i + j]
t_time[i, j, :] = ts[i + j]
#///////////////////RNNに対応した「time_size」行列の学習用データを作成 終了部分/////////////////////////
# 学習時に使用する変数
# max_iters = data_size // (batch_size * time_size)
max_iters = data_size // batch_size # SIN波学習のデータ量として、「time_size」で割ってしまうと足りなくなる
time_idx = 0
total_loss = 0
loss_count = 0
ppl_list = []
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# できるだけimportを外すため、classをコピペした箇所の「開始」部分
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# GPUを定義しておく(コードのどこかでこの定義を参照しているらしいけど、PCにNVIDIA無いので、下記定義をするだけ)
GPU = False
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# optimizer.py の抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
class SGD:
'''
確率的勾配降下法(Stochastic Gradient Descent)
'''
def __init__(self, lr=0.01):
self.lr = lr
def update(self, params, grads):
for i in range(len(params)):
params[i] -= self.lr * grads[i]
# ---------------------------------------------------------------------------------------------------------------------------
# optimizer.py の抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# functions.py の全部抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# ---------------------------------------------------------------------------------------------------------------------------
# functions.py の全部抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# time_layers.py の抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
class TimeAffine:
def __init__(self, W, b):
self.params = [W, b]
self.grads = [np.zeros_like(W), np.zeros_like(b)]
self.x = None
def forward(self, x):
N, T, D = x.shape
W, b = self.params
rx = x.reshape(N*T, -1)
out = np.dot(rx, W) + b
self.x = x
return out.reshape(N, T, -1)
def backward(self, dout):
x = self.x
N, T, D = x.shape
W, b = self.params
dout = dout.reshape(N*T, -1)
rx = x.reshape(N*T, -1)
db = np.sum(dout, axis=0)
dW = np.dot(rx.T, dout)
dx = np.dot(dout, W.T)
dx = dx.reshape(*x.shape)
self.grads[0][...] = dW
self.grads[1][...] = db
return dx
class LSTM:
def __init__(self, Wx, Wh, b):
'''
Parameters
----------
Wx: 入力`x`用の重みパラーメタ(4つ分の重みをまとめる)
Wh: 隠れ状態`h`用の重みパラメータ(4つ分の重みをまとめる)
b: バイアス(4つ分のバイアスをまとめる)
'''
self.params = [Wx, Wh, b]
self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]
self.cache = None
def forward(self, x, h_prev, c_prev):
Wx, Wh, b = self.params
N, H = h_prev.shape
A = np.dot(x, Wx) + np.dot(h_prev, Wh) + b
f = A[:, :H]
g = A[:, H:2*H]
i = A[:, 2*H:3*H]
o = A[:, 3*H:]
f = sigmoid(f)
g = np.tanh(g)
i = sigmoid(i)
o = sigmoid(o)
c_next = f * c_prev + g * i
h_next = o * np.tanh(c_next)
self.cache = (x, h_prev, c_prev, i, f, g, o, c_next)
return h_next, c_next
def backward(self, dh_next, dc_next):
Wx, Wh, b = self.params
x, h_prev, c_prev, i, f, g, o, c_next = self.cache
tanh_c_next = np.tanh(c_next)
ds = dc_next + (dh_next * o) * (1 - tanh_c_next ** 2)
dc_prev = ds * f
di = ds * g
df = ds * c_prev
do = dh_next * tanh_c_next
dg = ds * i
di *= i * (1 - i)
df *= f * (1 - f)
do *= o * (1 - o)
dg *= (1 - g ** 2)
dA = np.hstack((df, dg, di, do))
dWh = np.dot(h_prev.T, dA)
dWx = np.dot(x.T, dA)
db = dA.sum(axis=0)
self.grads[0][...] = dWx
self.grads[1][...] = dWh
self.grads[2][...] = db
dx = np.dot(dA, Wx.T)
dh_prev = np.dot(dA, Wh.T)
return dx, dh_prev, dc_prev
class TimeLSTM:
def __init__(self, Wx, Wh, b, stateful=False):
self.params = [Wx, Wh, b]
self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]
self.layers = None
self.h, self.c = None, None
self.dh = None
self.stateful = stateful
def forward(self, xs):
Wx, Wh, b = self.params
N, T, D = xs.shape
H = Wh.shape[0]
self.layers = []
hs = np.empty((N, T, H), dtype='f')
if not self.stateful or self.h is None:
self.h = np.zeros((N, H), dtype='f')
if not self.stateful or self.c is None:
self.c = np.zeros((N, H), dtype='f')
for t in range(T):
layer = LSTM(*self.params)
self.h, self.c = layer.forward(xs[:, t, :], self.h, self.c)
hs[:, t, :] = self.h
self.layers.append(layer)
return hs
def backward(self, dhs):
Wx, Wh, b = self.params
N, T, H = dhs.shape
D = Wx.shape[0]
dxs = np.empty((N, T, D), dtype='f')
dh, dc = 0, 0
grads = [0, 0, 0]
for t in reversed(range(T)):
layer = self.layers[t]
dx, dh, dc = layer.backward(dhs[:, t, :] + dh, dc)
dxs[:, t, :] = dx
for i, grad in enumerate(layer.grads):
grads[i] += grad
for i, grad in enumerate(grads):
self.grads[i][...] = grad
self.dh = dh
return dxs
def set_state(self, h, c=None):
self.h, self.c = h, c
def reset_state(self):
self.h, self.c = None, None
class TimeOutputWithLoss:
# このコードは「class TimeSoftmaxWithLoss」の代わりに実装する
def __init__(self):
self.cache = None
def forward(self, xs, ts):
N, T, D = xs.shape # ここでDは1
# RNNのタイプに合わせて「#1」か「#2」を選択する
# # ------------------RNN many to many start---------------#1
# loss = 0.5 * np.sum((xs - ts)**2) #1
# loss /= N # 1データ分での誤差 #1
# # -------------------RNN many to many end----------------#1
# ------------------RNN many to one start----------------#2
loss = 0.5 * np.sum((xs[:, T-1, :] - ts[:, T-1, :])**2) #2
loss /= N # 1データ分での誤差 #2
# -------------------RNN many to one end-----------------#2
self.cache = (ts, xs, (N, T, D))
return loss
def backward(self, dout=1):
ts, xs, (N, T, D) = self.cache
# RNNのタイプに合わせて「#1」か「#2」を選択する
# # ------------------RNN many to many start---------------#1
# dout = xs - ts #1
# dout /= N #1
# # -------------------RNN many to many end----------------#1
# ------------------RNN many to one start----------------#2
dout = np.zeros([N, T, D], dtype='float') #2
dout[:, T-1, :] = xs[:, T-1, :] - ts[:, T-1, :] #2
# -------------------RNN many to one end-----------------#2
return dout
# ---------------------------------------------------------------------------------------------------------------------------
# time_layers.py の抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# simple_rnnlm.py の抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
class SimpleRnnlm:
def __init__(self, vocab_size=10000, wordvec_size=100, hidden_size=100):
V, D, H = vocab_size, wordvec_size, hidden_size
rn = np.random.randn
# 重みの初期化
# embed_W = (rn(V, D) / 100).astype('f') # embedingレイヤは無効にする
lstm_Wx = (rn(D, 4 * H) / np.sqrt(D)).astype('f')
lstm_Wh = (rn(H, 4 * H) / np.sqrt(H)).astype('f')
lstm_b = np.zeros(4 * H).astype('f')
affine_W = (rn(H, V) / np.sqrt(H)).astype('f')
affine_b = np.zeros(V).astype('f')
# レイヤの生成
self.layers = [
# TimeEmbedding(embed_W), # embedingレイヤは無効にする
TimeLSTM(lstm_Wx, lstm_Wh, lstm_b, stateful=True),
TimeAffine(affine_W, affine_b)
]
# self.loss_layer = TimeSoftmaxWithLoss() # TimeSoftmaxWithLossレイヤは無効にする
self.loss_layer = TimeOutputWithLoss()
self.lstm_layer = self.layers[0] # 「TimeEmbedding」を外したので「TimeLSTM」を「self.lstm_layer」にするため「self.layers[1]」を「self.layers[0]」にした
# 「rnn」を「lstm」に書き換え
# すべての重みと勾配をリストにまとめる
self.params, self.grads = [], []
for layer in self.layers:
self.params += layer.params
self.grads += layer.grads
#------オリジナルコードに予測(predict)が無いので、LSTMのコードから持ってくる------
def predict(self, xs):
for layer in self.layers:
xs = layer.forward(xs)
return xs
def forward(self, xs, ts):
for layer in self.layers:
xs = layer.forward(xs)
loss = self.loss_layer.forward(xs, ts)
return loss
def backward(self, dout=1):
dout = self.loss_layer.backward(dout)
for layer in reversed(self.layers):
dout = layer.backward(dout)
return dout
def reset_state(self):
self.lstm_layer.reset_state() # 「rnn」を「lstm」に書き換え
# ---------------------------------------------------------------------------------------------------------------------------
# simple_rnnlm.py の抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# できるだけimportを外すため、classをコピペした箇所の「終了」部分
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# モデルの生成
model = SimpleRnnlm(vocab_size, wordvec_size, hidden_size)
optimizer = SGD(lr)
# ミニバッチの各サンプルの読み込み開始位置を計算
# jump = (corpus_size - 1) // batch_size
# offset = [i * jump for i in range(batch_size)]
for epoch in range(max_epoch):
#---「common」の「trainer.py」から「class Trainer」よりデータをシャッフルする部分を抜粋---
time_idx = 0 # インデックス追加部分
# シャッフル
idx = np.random.permutation(np.arange(data_size - time_size))
x_shuffle = x_time[idx, ]
t_shuffle = t_time[idx, ]
#-----------------------------------------------------------------------------------
# /////////////////////////////////////////////////////////////////////////////////////////////////////////
for iter in range(max_iters - 1):
# ミニバッチの取得
batch_x = np.empty((batch_size, time_size, wordvec_size), dtype='f')
batch_t = np.empty((batch_size, time_size, vocab_size), dtype='f')
for i in range(batch_size):
batch_x[i, :, :] = x_shuffle[time_idx + i, ]
batch_t[i, :, :] = t_shuffle[time_idx + i, ]
time_idx += batch_size
# /////////////////////////////////////////////////////////////////////////////////////////////////////////
# 勾配を求め、パラメータを更新
loss = model.forward(batch_x, batch_t)
model.backward()
optimizer.update(model.params, model.grads)
total_loss += loss
loss_count += 1
# エポックごとにパープレキシティの評価 「パープレキシティ」はここでは「ロス」として扱う
# ppl = np.exp(total_loss / loss_count)
ppl = total_loss
# print('| epoch %d | perplexity %.2f'
# % (epoch+1, ppl))
ppl_list.append(float(ppl))
total_loss, loss_count = 0, 0
#----------------予測部分開始-------------------------------------
# -- 予測 --
# 順伝播 RNN層
# x_predict = xs[:]
x_predict = sin_y.reshape(-1, 1) # x_predictのデータ構造をsin_yと同じにしている
x_predict.fill(0.0)
sin_y = np.sin(sin_x) # sin関数 なぜかここで再定義しないとsinデータを読み込まない
for i in range(time_size):
x_predict[i, ] = sin_y[i, ] # 「x_predict」の最初の「time_size」分SIN波データを組み込む
y_predict = np.empty((batch_size, time_size, vocab_size), dtype='f')
pred_batch_x = np.empty((batch_size, time_size, wordvec_size), dtype='f')
# batch_x = np.empty((batch_size, time_size, wordvec_size), dtype='f')
# 「batch_size」 ありきでコードが組まれているので、入力データを「batch_size」分、重複させて作る
for j in range(data_size - time_size + 1):
for t in range(time_size):
for i in range(batch_size):
pred_batch_x[i, t, :] = x_predict[j + t, ] # データは時系列に作成、「batch_size」分、重複させている
y_predict = model.predict(pred_batch_x)
x_predict[j + time_size, :] = y_predict[0, time_size-1, 0]
#-----------------予測部分終了------------------------------------
# グラフの描画 誤差の表示部分
x = np.arange(len(ppl_list))
plt.plot(x, ppl_list, color='c', label='train')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()
# グラフの描画 学習結果の波形パターンの一致度合いを表示
td = ts.reshape(-1)
x_pre = x_predict[:-1]
x = np.arange(len(td))
# x = np.arange(len(x_predict))
# plt.plot(x, td, x_predict, label='train')
plt.plot(x, td, color='b', label='target')
plt.plot(x, x_pre, color='r', label='predict')
plt.xlabel('epochs')
plt.ylabel('sin(x)')
plt.show()
実行結果は
です。
3:xp用のGRUのSIN波コード
# 完成版 Windows xp用 GRUコード
# ゼロから作る Deep Learning2のP216、第5章「5.5.3 RNNLMの学習コード」でコード全体が見えるようにできるだけ「import」を外した
# プログラムの動作検証用にSINカーブを学習させるため変更したコード
# coding: utf-8
# import sys
# sys.path.append('C:\\kojin\\資料\\AI関連\\ゼロから作る Deep Learning\\ゼロから作る Deep Learning2\\deep-learning-from-scratch-2-master\\')
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
# from common.optimizer import SGD
# from dataset import ptb # このimportを有効にするには上記パス設定「sys.path.append('C:\\kojin\\AI関連\\・・・」が必要!
# from simple_rnnlm import SimpleRnnlm
np.random.seed(seed=7724) # 発生する乱数を固定する(7724)
# ハイパーパラメータの設定
batch_size = 10
time_size = 10 # Truncated BPTTの展開する時間サイズ
n_in = 1 # 入力層のニューロン数
n_mid = 45 # 中間層のニューロン数
n_out = 1 # 出力層のニューロン数
# できるだけオリジナルのコードに変更を加えないため、既存の変数に代入する
vocab_size = n_out
wordvec_size = n_in
hidden_size = n_mid
lr = 0.005
max_epoch = 501
# 学習データの読み込み
## -------------------学習用データ------------------------------------
# -- 訓練データの作成 --
sin_x = np.linspace(-2*np.pi, 2*np.pi, 101) # -2πから2πまで
sin_y = np.sin(sin_x) # sin関数 predict用で使用する(なんかバグがある、predict部分で再宣言必要)
sin_y_noise = np.sin(sin_x) + 0.05*np.random.randn(len(sin_x)) # sin関数に乱数でノイズを加える
x_data = sin_y_noise.reshape(-1, 1)
t_data = sin_y_noise.reshape(-1, 1)
#------------------------------------------------------------------------------------------------
xs = x_data[:-1] # 入力
ts = t_data[1:] # 出力(教師ラベル)
data_size = len(xs)
#///////////////////RNNに対応した「time_size」行列の学習用データを作成 開始部分/////////////////////////
x_time = np.empty((data_size - time_size, time_size, wordvec_size), dtype='f')
t_time = np.empty((data_size - time_size, time_size, vocab_size), dtype='f')
for i in range(data_size - time_size):
for j in range(time_size):
x_time[i, j, :] = xs[i + j]
t_time[i, j, :] = ts[i + j]
#///////////////////RNNに対応した「time_size」行列の学習用データを作成 終了部分/////////////////////////
# 学習時に使用する変数
# max_iters = data_size // (batch_size * time_size)
max_iters = data_size // batch_size # SIN波学習のデータ量として、「time_size」で割ってしまうと足りなくなる
time_idx = 0
total_loss = 0
loss_count = 0
ppl_list = []
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# できるだけimportを外すため、classをコピペした箇所の「開始」部分
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# GPUを定義しておく(コードのどこかでこの定義を参照しているらしいけど、PCにNVIDIA無いので、下記定義をするだけ)
GPU = False
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# optimizer.py の抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
class SGD:
'''
確率的勾配降下法(Stochastic Gradient Descent)
'''
def __init__(self, lr=0.01):
self.lr = lr
def update(self, params, grads):
for i in range(len(params)):
params[i] -= self.lr * grads[i]
# ---------------------------------------------------------------------------------------------------------------------------
# optimizer.py の抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# functions.py の全部抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# ---------------------------------------------------------------------------------------------------------------------------
# functions.py の全部抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# time_layers.py の抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
class TimeAffine:
def __init__(self, W, b):
self.params = [W, b]
self.grads = [np.zeros_like(W), np.zeros_like(b)]
self.x = None
def forward(self, x):
N, T, D = x.shape
W, b = self.params
rx = x.reshape(N*T, -1)
out = np.dot(rx, W) + b
self.x = x
return out.reshape(N, T, -1)
def backward(self, dout):
x = self.x
N, T, D = x.shape
W, b = self.params
dout = dout.reshape(N*T, -1)
rx = x.reshape(N*T, -1)
db = np.sum(dout, axis=0)
dW = np.dot(rx.T, dout)
dx = np.dot(dout, W.T)
dx = dx.reshape(*x.shape)
self.grads[0][...] = dW
self.grads[1][...] = db
return dx
class GRU:
def __init__(self, Wx, Wh, b):
'''
Parameters
----------
Wx: 入力`x`用の重みパラーメタ(3つ分の重みをまとめる)
Wh: 隠れ状態`h`用の重みパラメータ(3つ分の重みをまとめる)
b: バイアス(3つ分のバイアスをまとめる)
'''
self.params = [Wx, Wh, b]
self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]
self.cache = None
def forward(self, x, h_prev):
Wx, Wh, b = self.params
H = Wh.shape[0]
Wxz, Wxr, Wxh = Wx[:, :H], Wx[:, H:2 * H], Wx[:, 2 * H:]
Whz, Whr, Whh = Wh[:, :H], Wh[:, H:2 * H], Wh[:, 2 * H:]
bz, br, bh = b[:H], b[H:2 * H], b[2 * H:]
z = sigmoid(np.dot(x, Wxz) + np.dot(h_prev, Whz) + bz)
r = sigmoid(np.dot(x, Wxr) + np.dot(h_prev, Whr) + br)
h_hat = np.tanh(np.dot(x, Wxh) + np.dot(r*h_prev, Whh) + bh)
h_next = (1-z) * h_prev + z * h_hat
self.cache = (x, h_prev, z, r, h_hat)
return h_next
def backward(self, dh_next):
Wx, Wh, b = self.params
H = Wh.shape[0]
Wxz, Wxr, Wxh = Wx[:, :H], Wx[:, H:2 * H], Wx[:, 2 * H:]
Whz, Whr, Whh = Wh[:, :H], Wh[:, H:2 * H], Wh[:, 2 * H:]
x, h_prev, z, r, h_hat = self.cache
dh_hat =dh_next * z
dh_prev = dh_next * (1-z)
# tanh
dt = dh_hat * (1 - h_hat ** 2)
dbh = np.sum(dt, axis=0)
dWhh = np.dot((r * h_prev).T, dt)
dhr = np.dot(dt, Whh.T)
dWxh = np.dot(x.T, dt)
dx = np.dot(dt, Wxh.T)
dh_prev += r * dhr
# update gate(z)
dz = dh_next * h_hat - dh_next * h_prev
dt = dz * z * (1-z)
dbz = np.sum(dt, axis=0)
dWhz = np.dot(h_prev.T, dt)
dh_prev += np.dot(dt, Whz.T)
dWxz = np.dot(x.T, dt)
dx += np.dot(dt, Wxz.T)
# rest gate(r)
dr = dhr * h_prev
dt = dr * r * (1-r)
dbr = np.sum(dt, axis=0)
dWhr = np.dot(h_prev.T, dt)
dh_prev += np.dot(dt, Whr.T)
dWxr = np.dot(x.T, dt)
dx += np.dot(dt, Wxr.T)
self.dWx = np.hstack((dWxz, dWxr, dWxh))
self.dWh = np.hstack((dWhz, dWhr, dWhh))
self.db = np.hstack((dbz, dbr, dbh))
self.grads[0][...] = self.dWx
self.grads[1][...] = self.dWh
self.grads[2][...] = self.db
return dx, dh_prev
class TimeGRU:
def __init__(self, Wx, Wh, b, stateful=False):
self.params = [Wx, Wh, b]
self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]
self.layers = None
self.h, self.dh = None, None
self.stateful = stateful
def forward(self, xs):
Wx, Wh, b = self.params
N, T, D = xs.shape
H = Wh.shape[0]
self.layers = []
hs = np.empty((N, T, H), dtype='f')
if not self.stateful or self.h is None:
self.h = np.zeros((N, H), dtype='f')
for t in range(T):
layer = GRU(*self.params)
self.h = layer.forward(xs[:, t, :], self.h)
hs[:, t, :] = self.h
self.layers.append(layer)
return hs
def backward(self, dhs):
Wx, Wh, b = self.params
N, T, H = dhs.shape
D = Wx.shape[0]
dxs = np.empty((N, T, D), dtype='f')
dh = 0
grads = [0, 0, 0]
for t in reversed(range(T)):
layer = self.layers[t]
dx, dh = layer.backward(dhs[:, t, :] + dh)
dxs[:, t, :] = dx
for i, grad in enumerate(layer.grads):
grads[i] += grad
for i, grad in enumerate(grads):
self.grads[i][...] = grad
self.dh = dh
return dxs
def set_state(self, h):
self.h = h
def reset_state(self):
self.h = None
class TimeOutputWithLoss:
# このコードは「class TimeSoftmaxWithLoss」の代わりに実装する
def __init__(self):
self.cache = None
def forward(self, xs, ts):
N, T, D = xs.shape # ここでDは1
# RNNのタイプに合わせて「#1」か「#2」を選択する
# # ------------------RNN many to many start---------------#1
# loss = 0.5 * np.sum((xs - ts)**2) #1
# loss /= N # 1データ分での誤差 #1
# # -------------------RNN many to many end----------------#1
# ------------------RNN many to one start----------------#2
loss = 0.5 * np.sum((xs[:, T-1, :] - ts[:, T-1, :])**2) #2
loss /= N # 1データ分での誤差 #2
# -------------------RNN many to one end-----------------#2
self.cache = (ts, xs, (N, T, D))
return loss
def backward(self, dout=1):
ts, xs, (N, T, D) = self.cache
# RNNのタイプに合わせて「#1」か「#2」を選択する
# # ------------------RNN many to many start---------------#1
# dout = xs - ts #1
# dout /= N #1
# # -------------------RNN many to many end----------------#1
# ------------------RNN many to one start----------------#2
dout = np.zeros([N, T, D], dtype='float') #2
dout[:, T-1, :] = xs[:, T-1, :] - ts[:, T-1, :] #2
# -------------------RNN many to one end-----------------#2
return dout
# ---------------------------------------------------------------------------------------------------------------------------
# time_layers.py の抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# simple_rnnlm.py の抜粋「開始」部分
# ---------------------------------------------------------------------------------------------------------------------------
class SimpleRnnlm:
def __init__(self, vocab_size=10000, wordvec_size=100, hidden_size=100):
V, D, H = vocab_size, wordvec_size, hidden_size
rn = np.random.randn
# 重みの初期化
# embed_W = (rn(V, D) / 100).astype('f') # embedingレイヤは無効にする
gru_Wx = (rn(D, 3 * H) / np.sqrt(D)).astype('f') # 「lstm」を「gru」に書き換えつつ、「4」を「3」にした
gru_Wh = (rn(H, 3 * H) / np.sqrt(H)).astype('f') # 「lstm」を「gru」に書き換えつつ、「4」を「3」にした
gru_b = np.zeros(3 * H).astype('f') # 「lstm」を「gru」に書き換えつつ、「4」を「3」にした
affine_W = (rn(H, V) / np.sqrt(H)).astype('f')
affine_b = np.zeros(V).astype('f')
# レイヤの生成 # 「TimeLSTM」を「TimeGRU」に書き換え
self.layers = [
# TimeEmbedding(embed_W), # embedingレイヤは無効にする
TimeGRU(gru_Wx, gru_Wh,gru_b, stateful=True),
TimeAffine(affine_W, affine_b)
]
# self.loss_layer = TimeSoftmaxWithLoss() # TimeSoftmaxWithLossレイヤは無効にする
self.loss_layer = TimeOutputWithLoss()
self.gru_layer = self.layers[0] # 「TimeEmbedding」を外したので「TimeGRU」を「self.gru_layer」にするため「self.layers[1]」を「self.layers[0]」にした
# 「rnn」を「gru」に書き換え
# すべての重みと勾配をリストにまとめる
self.params, self.grads = [], []
for layer in self.layers:
self.params += layer.params
self.grads += layer.grads
#------オリジナルコードに予測(predict)が無いので、LSTMのコードから持ってくる------
def predict(self, xs):
for layer in self.layers:
xs = layer.forward(xs)
return xs
def forward(self, xs, ts):
for layer in self.layers:
xs = layer.forward(xs)
loss = self.loss_layer.forward(xs, ts)
return loss
def backward(self, dout=1):
dout = self.loss_layer.backward(dout)
for layer in reversed(self.layers):
dout = layer.backward(dout)
return dout
def reset_state(self):
self.gru_layer.reset_state() # 「rnn」を「gru」に書き換え
# ---------------------------------------------------------------------------------------------------------------------------
# simple_rnnlm.py の抜粋「終了」部分
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# できるだけimportを外すため、classをコピペした箇所の「終了」部分
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# モデルの生成
model = SimpleRnnlm(vocab_size, wordvec_size, hidden_size)
optimizer = SGD(lr)
# ミニバッチの各サンプルの読み込み開始位置を計算
# jump = (corpus_size - 1) // batch_size
# offset = [i * jump for i in range(batch_size)]
for epoch in range(max_epoch):
#---「common」の「trainer.py」から「class Trainer」よりデータをシャッフルする部分を抜粋---
time_idx = 0 # インデックス追加部分
# シャッフル
idx = np.random.permutation(np.arange(data_size - time_size))
x_shuffle = x_time[idx, ]
t_shuffle = t_time[idx, ]
#-----------------------------------------------------------------------------------
# /////////////////////////////////////////////////////////////////////////////////////////////////////////
for iter in range(max_iters - 1):
# ミニバッチの取得
batch_x = np.empty((batch_size, time_size, wordvec_size), dtype='f')
batch_t = np.empty((batch_size, time_size, vocab_size), dtype='f')
for i in range(batch_size):
batch_x[i, :, :] = x_shuffle[time_idx + i, ]
batch_t[i, :, :] = t_shuffle[time_idx + i, ]
time_idx += batch_size
# /////////////////////////////////////////////////////////////////////////////////////////////////////////
# 勾配を求め、パラメータを更新
loss = model.forward(batch_x, batch_t)
model.backward()
optimizer.update(model.params, model.grads)
total_loss += loss
loss_count += 1
# エポックごとにパープレキシティの評価 「パープレキシティ」はここでは「ロス」として扱う
# ppl = np.exp(total_loss / loss_count)
ppl = total_loss
# print('| epoch %d | perplexity %.2f'
# % (epoch+1, ppl))
ppl_list.append(float(ppl))
total_loss, loss_count = 0, 0
#----------------予測部分開始-------------------------------------
# -- 予測 --
# 順伝播 RNN層
# x_predict = xs[:]
x_predict = sin_y.reshape(-1, 1) # x_predictのデータ構造をsin_yと同じにしている
x_predict.fill(0.0)
sin_y = np.sin(sin_x) # sin関数 なぜかここで再定義しないとsinデータを読み込まない
for i in range(time_size):
x_predict[i, ] = sin_y[i, ] # 「x_predict」の最初の「time_size」分SIN波データを組み込む
y_predict = np.empty((batch_size, time_size, vocab_size), dtype='f')
pred_batch_x = np.empty((batch_size, time_size, wordvec_size), dtype='f')
# batch_x = np.empty((batch_size, time_size, wordvec_size), dtype='f')
# 「batch_size」 ありきでコードが組まれているので、入力データを「batch_size」分、重複させて作る
for j in range(data_size - time_size + 1):
for t in range(time_size):
for i in range(batch_size):
pred_batch_x[i, t, :] = x_predict[j + t, ] # データは時系列に作成、「batch_size」分、重複させている
y_predict = model.predict(pred_batch_x)
x_predict[j + time_size, :] = y_predict[0, time_size-1, 0]
#-----------------予測部分終了------------------------------------
# グラフの描画 誤差の表示部分
x = np.arange(len(ppl_list))
plt.plot(x, ppl_list, color='c', label='train')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()
# グラフの描画 学習結果の波形パターンの一致度合いを表示
td = ts.reshape(-1)
x_pre = x_predict[:-1]
x = np.arange(len(td))
# x = np.arange(len(x_predict))
# plt.plot(x, td, x_predict, label='train')
plt.plot(x, td, color='b', label='target')
plt.plot(x, x_pre, color='r', label='predict')
plt.xlabel('epochs')
plt.ylabel('sin(x)')
plt.show() 実行結果は
です。
以上です。



コメント
コメントを投稿