# 深度學習 04:RNN/LSTM
###### tags: `Deep Learning`
RNN:

LSTM:

<br>
RNN正向傳播公式:
<font size=5>$$h_{t} = tanh(h_{t-1}W_h+X_tW_x+b)$$</font>
RNN 為下圖左邊的,右邊是為了理解展開後的圖

```python=
tf.keras.layers.RNN(
cell, return_sequences=False, return_state=False, go_backwards=False,
stateful=False, unroll=False, time_major=False, **kwargs
)
```
[tf.keras.layers.RNN](https://www.tensorflow.org/api_docs/python/tf/keras/layers/RNN) 內輸入的參數是 cell,是一個 class,不是 units,不可帶數字。
[tf.keras.layers.SimpleRNNCell](https://www.tensorflow.org/api_docs/python/tf/keras/layers/SimpleRNNCell)\[tf.keras.layers.LSTMCell](https://www.tensorflow.org/api_docs/python/tf/keras/layers/SimpleRNNCell) 為 cell 的一種,參數是 units,代表隱藏層神經元數量。
更新權重是一個 batch 平均 然後一起更新。
---
## 預測時間序列
<font color="#f00">**RNN 的 input_shape 通常是 [批次大小, 時間維度, 特徵維度]**</font>

---
### 預測一個值
1. **Baseline**

```python=
np.random.seed(42)
tf.random.set_seed(42)
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=[50, 1]),
keras.layers.Dense(1)
])
model.compile(loss="mse", optimizer="adam")
history = model.fit(X_train, y_train, epochs=20,
validation_data=(X_valid, y_valid))
```
MSE = 0.02
2. **簡單 RNN**

```python=
model = keras.models.Sequential([
keras.layers.SimpleRNN(1, input_shape=[None, 1])
])
```
MSE = 0.014
一共 $W_h$、$W_x$、$b$ 三個參數。
3. **深層 RNN**

```python=
model = keras.models.Sequential([
keras.layers.SimpleRNN(20, return_sequences=True, input_shape=[None, 1]),
keras.layers.SimpleRNN(20),
keras.layers.Dense(1)
])
```
MSE = 0.003
**return_sequences=True** 代表輸出一個 3D array(包含所有時間維度的輸出),若無此參數,將只會輸出一個 2D array(只包含最終時間維度的輸出)。
---
### 預測多個值
1. **循環預測**

將訓練好的深層 RNN 模型預測下一個值,再將那個值加到輸入,並再利用這個模型預測接下來的值,以此類推。
```python=
series = generate_time_series(1, n_steps + 10)
X_new, Y_new = series[:, :n_steps], series[:, n_steps:]
X = X_new
for step_ahead in range(10):
y_pred_one = model.predict(X[:, step_ahead:])[:, np.newaxis, :]
X = np.concatenate([X, y_pred_one], axis=1)
Y_pred = X[:, n_steps:]
```
MSE = 0.029
因為誤差可能會累積,所以預測下個時間特徵通常比循環預測來得準確。
2. **訓練 RNN 同時預測多個值**

在最後一個時間特徵預測接下來十個值。
```python=
model = keras.models.Sequential([
keras.layers.SimpleRNN(20, return_sequences=True, input_shape=[None, 1]),
keras.layers.SimpleRNN(20),
keras.layers.Dense(10)
])
```
MSE = 0.008
3. **Seq to seq**

與其在最後一步預測接下來的十個值,不如在每一步預測接下來的十個值,也就是將 seq-to-vec RNN 轉換成 seq-to-seq RNN($x_0$ -> $y_1$~$y_{11}$ 以此類推)。
```python=
model = keras.models.Sequential([
keras.layers.SimpleRNN(20, return_sequences=True, input_shape=[None, 1]),
keras.layers.SimpleRNN(20, return_sequences=True),
keras.layers.TimeDistributed(keras.layers.Dense(10))
])
```
MSE = 0.006
要將此模型轉換成 seq-to-seq RNN 必須在 Dense 外面包一層 TimeDistributed 層,並在每個時步執行它,它可以將 shape 從 **[批次大小, 時間維度, 輸入維度] 轉換成 [批次大小 x 時間維度, 輸入維度],再經由 Dense 轉回 **[批次大小, 時間維度, 輸入維度]**,雖然 Dense 也能吃 **[批次大小, 時間維度, 輸入維度]**,但如果用 TimeDistributed 層,它只會輸出最後一個時步的十個值。
4. **Conv1D 處理序列**
雖然 LSTM/GRU 比 RNN 能處理更多的序列,然仍難以在 100 個時步以上的序列學習長期模式,如音訊、長句子等。

跟 Seq to seq 不同的是,Seq to seq 是每一個時步預測後十個值,而 Conv1D 是每四個時步組成一個核來預測後十個值。
```python=
model = keras.models.Sequential([
keras.layers.Conv1D(filters=20, kernel_size=4, strides=2, padding="valid",
input_shape=[None, 1]),
keras.layers.GRU(20, return_sequences=True),
keras.layers.GRU(20, return_sequences=True),
keras.layers.TimeDistributed(keras.layers.Dense(10))
])
```
MSE = 0.006
---
1. 精通機器學習,使用 Scikit-Learn, Keras 與 Tensorflow-Aurelien Greon
2. Deep Learning:用 Python 進行深度學習的基礎理論實作 - 齋藤康毅
3. [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/)