非線形な関数のグラフ。リカレントニューラルネットワークを使用してカオスの香りがする 出力を生成します。
マイナス100からプラス100までの1000ステップで変化する時系列データを、隠れ層サイズが[10,20,30]のLSTMを1つ使ったモデルに入力し、シーケンス長の値を変更して出力がどのように変化するかをプロットします。
LSTMでは、各時刻での計算は独立して行われるのではなく、ある時刻の入力をモデルに入れてその出力を生成し、その出力をまた同じ入力として使用するというプロセスがシーケンスの長さ分繰り返されます。
具体的には、各時刻での計算は次の手順で行われます:
時刻tでの入力をLSTMモデルに渡し、時刻tでの出力を生成します。
次の時刻であるt+1での入力として、時刻tでの出力を再度モデルに渡し、時刻t+1での出力を生成します。
各時刻でこのプロセスを繰り返し、シーケンスの長さ分だけ計算を行います。
シーケンスの長さが1の場合、それは単なる時刻tにおける単一の入力です。この場合、LSTMモデルは過去の情報を考慮せず、現在の入力だけを使用して出力を計算します。これは、通常の単一の隠れ層を持つニューラルネットワークと同等です。
一方、シーケンスの長さが5の場合、それは過去の5つの時刻にわたる情報を含む入力と見なすことができます。この場合、隠れ層が 5つ のニューラルネットワークのような計算になります。そのため、一つのLSTM層は、過去の複数の時刻にわたる情報をキャプチャすることができると考えることができます。
ニューラルネットワークの1つの層の計算は 入力と重み行列の積 (線形変換) にシグモイド関数(非線形)を乗ずることで計算されます。シグモイド関数に含まれる指数関数の項により、ニューラルネットワークは非線形の関数となります。
リカレントニューラルネットワークでは、同じパラメーターの重み行列が複数の時間ステップに渡って再利用されるわけではありません。各時間ステップで異なるパラメーターの重み行列での計算が行われます。
各シーケンス長と隠れ層のサイズの組み合わせに対して、12枚のグラフがプロットされます。それぞれのグラフには、3つの異なる隠れ層サイズに対応する出力結果がプロットされます。
多様な形状の出力となります。シーケンス長が大きくなるとグラフ形状がより複雑になっていきます。
このコードでは、各シーケンス長と隠れ層のサイズの組み合わせに対して、12枚のグラフがプロットされます。それぞれのグラフには、3つの異なる隠れ層サイズに対応する出力結果がプロットされます。
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import LSTM, Dense
class SimpleLSTMNetwork:
def __init__(self, input_size, output_size, hidden_size):
self.input_size = input_size
self.output_size = output_size
self.hidden_size = hidden_size
# LSTM層を含むモデルの作成
self.model = Sequential([
LSTM(hidden_size, input_shape=(None, input_size)),
Dense(output_size)
])
# モデルのコンパイル
self.model.compile(loss='mse', optimizer='adam')
def forward(self, X):
# モデルに入力を与えて予測を取得
prediction = self.model.predict(X)
return prediction
def generate_time_series(start, end, num_steps):
# マイナス100からプラス100までの1000ステップで変化する時系列データの生成
time_series = np.linspace(start, end, num_steps)
return time_series.reshape(-1, 1)
def plot_lstm_output_grid(sequence_lengths, time_series, hidden_sizes):
fig, axes = plt.subplots(4, 3, figsize=(15, 10))
axes = axes.flatten()
for i, sequence_length in enumerate(sequence_lengths):
for j, hidden_size in enumerate(hidden_sizes):
# ニューラルネットワークの生成
network = SimpleLSTMNetwork(input_size=1, output_size=1, hidden_size=hidden_size)
# 入力データの生成
X_values = []
for k in range(len(time_series) - sequence_length):
X_values.append(time_series[k:k+sequence_length])
X_values = np.array(X_values)
X_values = np.expand_dims(X_values, axis=-1)
# フォワードパスでYの値を計算
Y_values = network.forward(X_values)
# グラフでプロット
axes[i].plot(Y_values.squeeze(), label=f'Hidden Size: {hidden_size}')
axes[i].set_xlabel('Step')
axes[i].set_ylabel('Y')
axes[i].set_title(f'Sequence Length: {sequence_length}')
axes[i].grid(True)
axes[i].legend()
plt.tight_layout()
plt.show()
# マイナス100からプラス100までの1000ステップで変化する時系列データの生成
time_series = generate_time_series(-100, 100, 1000)
# 検証するシーケンス長のリスト
sequence_lengths = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60]
# 比較する隠れ層のサイズのリスト
hidden_sizes = [10, 20, 30]
# シーケンス長と隠れ層のサイズの組み合わせによる出力の比較をプロット
plot_lstm_output_grid(sequence_lengths, time_series, hidden_sizes)
シンプルで見やすい12枚のグラフを表示します。それぞれのグラフは異なるシーケンス長を持ち、そのシーケンス長による出力の変化が可視化されます。
12枚のグラフを3×4のタイル状に配置して表示します。それぞれのグラフは異なるシーケンス長を持ち、そのシーケンス長による出力の変化が可視化されます。
ニューラルネットワークの生成
network = SimpleLSTMNetwork(input_size=1, output_size=1, hidden_size=10)
hidden_sizeを設定できます。
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import LSTM, Dense
class SimpleLSTMNetwork:
def __init__(self, input_size, output_size, hidden_size):
self.input_size = input_size
self.output_size = output_size
self.hidden_size = hidden_size
# LSTM層を含むモデルの作成
self.model = Sequential([
LSTM(hidden_size, input_shape=(None, input_size)),
Dense(output_size)
])
# モデルのコンパイル
self.model.compile(loss='mse', optimizer='adam')
def forward(self, X):
# モデルに入力を与えて予測を取得
prediction = self.model.predict(X)
return prediction
def generate_time_series(start, end, num_steps):
# マイナス100からプラス100までの1000ステップで変化する時系列データの生成
time_series = np.linspace(start, end, num_steps)
return time_series.reshape(-1, 1)
def plot_lstm_output_grid(sequence_lengths, time_series):
fig, axes = plt.subplots(3, 4, figsize=(15, 10))
axes = axes.flatten()
for i, sequence_length in enumerate(sequence_lengths):
# ニューラルネットワークの生成
network = SimpleLSTMNetwork(input_size=1, output_size=1, hidden_size=10)
# 入力データの生成
X_values = []
for j in range(len(time_series) - sequence_length):
X_values.append(time_series[j:j+sequence_length])
X_values = np.array(X_values)
X_values = np.expand_dims(X_values, axis=-1)
# フォワードパスでYの値を計算
Y_values = network.forward(X_values)
# グラフでプロット
axes[i].plot(Y_values.squeeze(), label=f'Sequence Length: {sequence_length}')
axes[i].set_xlabel('Step')
axes[i].set_ylabel('Y')
axes[i].set_title(f'Sequence Length: {sequence_length}')
axes[i].grid(True)
axes[i].legend()
plt.tight_layout()
plt.show()
# マイナス100からプラス100までの1000ステップで変化する時系列データの生成
time_series = generate_time_series(-100, 100, 1000)
# 検証するシーケンス長のリスト
sequence_lengths = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60]
# シーケンス長の変化による出力の変化を3×4のタイル状にプロット
plot_lstm_output_grid(sequence_lengths, time_series)