Google Colaboratoryを使ったRNNの動作確認その2（2022年3月30日）

# 1. はじめに
　YOLO・CNNといったニューラルネットワークを使った機械学習を勉強中の者です。この手のコモディティ化以前のテクノロジーの学習で障害となるのは、プラットフォームやソフトウェアライブラリ等がどんどんアップデートされているので、ほんのちょっと前に書かれた記事であっても、書かれた通りに動かすことができないという点です（筆者も度々遭遇して難儀しています）。
　つい昨晩、RNNに挑戦したところ、やはり参考にさせて頂いたサイト記事の通りには実行できず、いろいろとネット上を調べまわった結果、何とか動かすことができましたので、自分用の備忘録を兼ねて記録しておきたいと思います。その第2弾です。
# 2. 参考にさせて頂いたサイト記事
今度こそわかるぞRNN, LSTM編
https://qiita.com/kazukiii/items/df809d6cd5d7d1f57be3
更新日 2019年05月05日
# 3. テスト用データの作成プログラム
　今回もGoogle Chrome上でGoogle Colaboratoryを使います。
　オリジナルの記事では、乱数によりノイズを乗せたサインカーブをテストデータとして用い、それをRNNで学習させています。
## 3.0 ノイズ入りサインカーブ
　まずは、今回の動作確認に使用するノイズ入りサインカーブを作成するプログラムコードを入力し、試しに実行します。
```
import pandas as pd
import numpy as np
import math
import random
import matplotlib.pyplot as plt
import seaborn as sns

 # サイクルあたりのステップ数
steps_per_cycle = 80
 # 生成するサイクル数
number_of_cycles = 50

df = pd.DataFrame(np.arange(steps_per_cycle * number_of_cycles + 1),
 columns=["t"])
 # 一様乱数でノイズを発生させたsin波を生成
df["sin_t"] = df.t.apply(lambda x: math.sin(x * (2 * math.pi / 
 steps_per_cycle)+ random.uniform(-0.1, +0.1) ))

 # 2サイクルだけ抽出してプロット
df[["sin_t"]].head(steps_per_cycle * 2).plot()

 # 画像を保存
plt.savefig('sinecurveWithNoise.png')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2565347/8e84906a-85c8-8e0a-898f-9012028ba143.png)
　わかりやすくするために、オリジナルの記事より大きめのノイズを与えています。直感的にノイズの入ったサインカーブであることがわかるかと思います。
## 3.1 トレーニングデータ・テストデータの作成プログラム
　続いて、RNNプログラムに入力するデータを作成するプログラムです。30ステップを入力し、31ステップ目を推定するように、トレーニングデータとテストデータを作成するプログラムを入力し、実行します。サインカーブなので、ノイズの無いサインカーブが真値（正解）となります。
```
def _load_data(data, n_prev=30):  
    docX, docY = [], []

    for i in range(len(data) - n_prev):
        docX.append(data.iloc[i:i + n_prev].values)
        docY.append(data.iloc[i + n_prev].values)
    alsX = np.array(docX)
    alsY = np.array(docY)

    return alsX, alsY

def train_test_split(df, test_size=0.1, n_prev=30):  
    ntrn = round(len(df) * (1 - test_size))
    ntrn = int(ntrn)
    X_train, y_train = _load_data(df.iloc[0:ntrn], n_prev)
    X_test, y_test = _load_data(df.iloc[ntrn:], n_prev)

    return (X_train, y_train), (X_test, y_test)

(X_train, y_train), (X_test, y_test) = train_test_split(df[["sin_t"]])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2565347/3e9ea67e-8d1c-bd7c-4cab-94152fa7a70d.png)
# 4. 推論用RNNプログラムの実装と学習
## 4.1 トレーニング用プログラム
　次のコードを入力し実行すると学習が行われます。
```
from keras.models import Sequential  
from keras.layers.core import Dense, Activation  
from keras.layers.recurrent import LSTM

 # パラメータ
in_out_neurons = 1
hidden_neurons = 300
length_of_sequences = 30

model = Sequential()  
model.add(LSTM(hidden_neurons, batch_input_shape=(None, length_of_sequences, 
 in_out_neurons), return_sequences=False))  
model.add(Dense(in_out_neurons))  
model.add(Activation("linear"))  
model.compile(loss="mean_squared_error", optimizer="rmsprop")
model.fit(X_train, y_train, batch_size=600, epochs=15, validation_split=0.05)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2565347/cd7a0f2f-b247-87c9-4fe4-120156c78d61.png)
　GPU無しで2分程度です。
## 4.1 推論用プログラム
　次のコードで推論を実行し、真値データと比較します。
```
 # 予測
predicted = model.predict(X_test)

 # 描写
dataf =  pd.DataFrame(predicted[:200])
dataf.columns = ["predict"]
dataf["input"] = y_test[:200]
dataf.plot()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2565347/697e6f85-746e-1b43-2abc-3bacafdd480a.png)
　振幅がやや少ないですが、概ね推定に成功していると言えます。
# 5. おわりに
　オリジナル記事からの変更箇所は、modelのfitメソッドにおけるエポックの変数名です（nb_epoch → epochs）。オリジナル記事を書いて下さったkazukiiiさんに感謝致します。