# 嘗試理解LSTM和CNN的結合
[TOC]
## 參考資料
* [Machine Learning Mastery](https://machinelearningmastery.com/cnn-long-short-term-memory-networks/)
## 前景提要
發現LSTM其實並沒有想像中的效果,在學弟的提議下發現了不少人在識別圖片/影片時都會使用CNN+LSTM的技術,因此嘗試寫寫看
## CNN LSTM Architecture
CNN+LSTMs當初是用來希望可以解決下述等問題:
* 預測連續圖片(=影片)的結果
* 類似猜劇情之類的東西
* 生成連續圖片(=影片)的文字描述
我們也可以將可處理的問題,整理成三種類型:
1. Activity Recognition: 產生a sequence of images的文本形容
2. Image Descritipn: 產生對於單一圖片的文本形容
3. Video Descritipn: 產生對於連續圖片的文本形容
而CNN+LSTM也可以稱為LRCN (long-term recurrent convolutional network),意旨在LSTM前面接上一CNN。
因為該模型是要生成對圖像的文字描述,所以關鍵就是我們需要一個已經train好的CNN,而該CNN是訓練來分類圖片現在我們可以將它用來提取描述所需要的說明
```
此處將CNN用來當作圖片的encoder,並且使用用來分類的CNN的最後一層的hidden layer來當作input 給RNN
[出處](https://arxiv.org/abs/1411.4555)
```
該架構也可以用來處理自然語言的相關處理,使用CNN做為特徵提取氣,並使用LSTM來處理一段聲音和文字類型的input data
講了這麼多,簡而言之,該架構適用於下述的情況:
1. 與空間有關的話:
* 2D strucutre or pixels in an image
* 1D structure of words in as sentence, paragraph, or ducument
2. 與時間有關的話:
* order of images in a video
* words in text
* require the generation of output with temporal structure such as words in a texual description
## Implement CNN LSTM in Keras
直接使用Keras裡面的CNN和LSTM,並將CNN放在一層的LSTM前面
文章中建議我們可以將該架構直接想成兩個子部分:
1. CNN: 提取特徵工具人
2. LSTM: 嘗試解釋按照時間序的特徵
### CNN
這邊的CNN先假設input為2D的圖片,因此使用了2D-CNN
且在此範例當中input為10\*10 pixel images with 1 channel
``` python=
cnn = Sequential()
cnn.add(Conv2D(1, (2,2), activation='relu', padding='same', input_shape=(10,10,1)))
cnn.add(MaxPooling2D(pool_size=(2, 2)))
cnn.add(Flatten())
```
### LSTM
CNN一次只能處理一張圖片,但我們現在需要處理是一連串的圖片,所以我們在這使用處理時序性的的LSTM
CNN可以使用已經訓練好的模型(像是VGG)來提取圖片裡面的特徵。也可以來自LSTM的backprpogation error來訓練CNN

而在CNN+LSTM的架構當中,我們會希望CNN處理單筆資料,LSTM處理時序性資料。所以我們要想辦法允許CNN一次只收一張圖片,並且依照連續的時間段傳送給LSTM。
如果想要達成上述的效果,我們可以使用TimeDistributed layer將做好的CNN包裝起來,把模型加進該layer就可以。因為該layer的用意就是將同時輸出的data包裝成
``` python=
model.add(TimeDistributed(...))
model.add(LSTM(...))
model.add(Dense(...))
```
### CNN LSTM Model
上述已經清楚表達了CNN和LSTM要怎麼處理了,我們現在將他合起來八~
有兩種分法:
1. 寫完整的CNN之後包進TimeDistributed
``` python=
# define CNN model
cnn = Sequential()
cnn.add(Conv2D(...))
cnn.add(MaxPooling2D(...))
cnn.add(Flatten())
# define LSTM model
model = Sequential()
model.add(TimeDistributed(cnn, ...))
model.add(LSTM(..))
model.add(Dense(...))
```
2. 在寫CNN時每一層都包在TimeDistributed裡面
``` python=
model = Sequential()
# define CNN model
model.add(TimeDistributed(Conv2D(...))
model.add(TimeDistributed(MaxPooling2D(...)))
model.add(TimeDistributed(Flatten()))
# define LSTM model
model.add(LSTM(...))
model.add(Dense(...))
```