はじめに
前回はRNNのモデルについて調べました。
今回からChatGPTに聞いたコードを勉強していき、RNNを実装できるようにしていきたいと思います。
RNNのコードについて勉強してみた
コード
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# RNNセルの定義
class SimpleRNNCell:
def __init__(self, input_size, hidden_size):
self.input_size = input_size
self.hidden_size = hidden_size
# 重み行列の初期化
self.Wx = np.random.randn(hidden_size, input_size)
self.Wh = np.random.randn(hidden_size, hidden_size)
self.b = np.zeros((hidden_size, 1))
def forward(self, x, h_prev):
# 順伝播
self.x = x
self.h_prev = h_prev
self.a = np.dot(self.Wx, x) + np.dot(self.Wh, h_prev) + self.b
self.h = np.tanh(self.a)
return self.h
def backward(self, dh_next):
# 逆伝播
da = dh_next * (1 - np.tanh(self.a)**2)
self.db = np.sum(da, axis=1, keepdims=True)
self.dWh = np.dot(da, self.h_prev.T)
self.dWx = np.dot(da, self.x.T)
self.dx = np.dot(self.Wh.T, da)
self.dh_prev = np.dot(self.Wx.T, da)
return self.dx, self.dh_prev
def update_parameters(self, learning_rate):
# 重みの更新
self.Wx -= learning_rate * self.dWx
self.Wh -= learning_rate * self.dWh
self.b -= learning_rate * self.db
# サンプルデータの生成
seq_length = 5
input_size = 10
hidden_size = input_size
fig = plt.figure()
# 入力データ (shape: (input_size, seq_length))
X = np.random.randn(input_size, seq_length)
print(X)
ax1 = fig.add_subplot(3, 1, 1)
ax1.plot(range(len(X)), X, marker="o")
ax1.set_ylabel("input")
# 目標出力 (仮の値)
y = np.random.randn(hidden_size, 1)
print(y)
ax2 = fig.add_subplot(3, 1, 2)
ax2.plot(range(len(y)), y, label="original")
ax2.set_ylabel("output")
# 初期隠れ状態 (shape: (hidden_size, 1))
h0 = np.zeros((hidden_size, 1))
# RNNセルの作成
rnn_cell = SimpleRNNCell(seq_length, hidden_size)
# 順伝播
h_t = h0
epochs = 100
loss_list = []
for epoch in range(epochs):
for t in range(input_size):
x_t = X[t, :].reshape(-1, 1)
h_t = rnn_cell.forward(x_t, h_t)
# 仮の損失関数 (例: 平均二乗誤差)
loss = np.mean((h_t - y)**2)
loss_list.append(loss)
# 逆伝播
dh_next = 2 * (h_t - y) # 仮の勾配
dx, dh_prev = rnn_cell.backward(dh_next)
# 重みの更新
learning_rate = 0.01
rnn_cell.update_parameters(learning_rate)
print(loss)
ax2.plot(range(len(y)), h_t, marker="o", label="predict")
ax2.legend(loc="upper left")
ax3 = fig.add_subplot(3, 1, 3)
ax3.plot(range(epochs)[1:], loss_list[1:], marker="o")
ax3.set_ylabel("loss")
ax3.set_yscale('log')
x_t = X[-1, :].reshape(-1, 1)
pred = rnn_cell.forward(x_t, h_t)[-1]
調べてみた
RNNの順伝播と逆伝播のイメージを作ってみた
今回はRNNの順伝播と逆伝播について調べていきたいと思います。
RNNを調べて、私が理解した範囲で図化しました。
各時間毎にこれまでのニューラルネットワークと変わりませんが、隠れ層が次の時間のニューラルネットワークのインプットにもなるのかなと思います。
隠れ層にも重みが与えられ、インプットデータと隠れ層の重み(Wx)と隠れ層同士の重み(Wh)を最適化していくことがRNNの目的になるのかなと思います。
該当コードを調べてみた
まずは該当箇所のコード
# 順伝播
h_t = h0
epochs = 100
loss_list = []
for epoch in range(epochs):
for t in range(input_size):
x_t = X[t, :].reshape(-1, 1)
h_t = rnn_cell.forward(x_t, h_t)
# 仮の損失関数 (例: 平均二乗誤差)
loss = np.mean((h_t - y)**2)
loss_list.append(loss)
# 逆伝播
dh_next = 2 * (h_t - y) # 仮の勾配
dx, dh_prev = rnn_cell.backward(dh_next)
# 重みの更新
learning_rate = 0.01
rnn_cell.update_parameters(learning_rate)
print(loss)
RNNに限らずニューラルネットワークの順伝播と逆伝播はこちらの記事とこちらの記事で勉強しました。
RNNの特徴のコード
RNNの特徴としては入力層と隠れ層を何度も使いまわしているというところでしょうか
for t in range(input_size):
x_t = X[t, :].reshape(-1, 1)
h_t = rnn_cell.forward(x_t, h_t)
の部分です。
x_tは入力層ですが、X[t, :]のtがループで1行ずつずれていくことが分かります。つまり、時系列データの時間を少しずつずらしていくということになると思われます。
一方、h_tもx_tを入力して、隠れ層に自分自身h_tを使って隠れ層を更新しています。これを行うことで時系列毎で隠れ層を共有、更新を行っているのだと思います。
それ以外の順伝播と逆伝播はこれまでのニューラルネットワークと同じですね。
コメント