Try   HackMD

嘗試理解LSTM和CNN的結合

參考資料

前景提要

發現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

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包裝成

model.add(TimeDistributed(...)) model.add(LSTM(...)) model.add(Dense(...))

CNN LSTM Model

上述已經清楚表達了CNN和LSTM要怎麼處理了,我們現在將他合起來八~
有兩種分法:

  1. 寫完整的CNN之後包進TimeDistributed
# 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(...))
  1. 在寫CNN時每一層都包在TimeDistributed裡面
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(...))