NeuroWhAI의 잡블로그

[Keras] LSTM으로 영화 리뷰의 평점 예측하기 - imdb 본문

개발 및 공부/라이브러리&프레임워크

[Keras] LSTM으로 영화 리뷰의 평점 예측하기 - imdb

NeuroWhAI 2018. 3. 9. 20:35


※ 이 글은 '코딩셰프의 3분 딥러닝 케라스맛'이라는 책을 보고 실습한걸 기록한 글입니다.


imdb는 리뷰 문장의 단어들을 출현빈도순으로 정렬해서 정수로 변환시킨 시퀀스를 x로 하고
평가의 긍정적, 부정적 여부를 1, 0으로 라벨링한 데이터셋 입니다.
그러니까 예를 들어 x는 [31, 3, 55, 123, 4, 99, 4443, 3423] 이렇게 생겼고
y는 1(긍정적) 이렇게 되어있습니다.
목표는 x를 가지고 y를 예측하는 것입니다.

코드:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#-*- coding: utf-8 -*-
 
import numpy as np
import keras
from keras import layers, models, datasets
from keras import backend as K
from keras.utils import np_utils
from keras.preprocessing import sequence
import matplotlib.pyplot as plt
from sklearn import model_selection, metrics
from sklearn.preprocessing import MinMaxScaler
import os
 
class Data:
    def __init__(self, max_features=20000, maxlen=80):
        (x_train, y_train), (x_test, y_test) = datasets.imdb.load_data(
            num_words=max_features)
        x_train = sequence.pad_sequences(x_train, maxlen=maxlen)
        x_test = sequence.pad_sequences(x_test, maxlen=maxlen)
        self.x_train, self.y_train = x_train, y_train
        self.x_test, self.y_test = x_test, y_test
 
class RNN_LSTM(models.Model):
    def __init__(self, max_features, maxlen):
        x = layers.Input((maxlen,))
        h = layers.Embedding(max_features, 128)(x)
        h = layers.LSTM(128, dropout=0.2, recurrent_dropout=0.2)(h)
        y = layers.Dense(1, activation='sigmoid')(h)
        super().__init__(x, y)
 
        self.compile(loss='binary_crossentropy',
            optimizer='adam', metrics=['accuracy'])
 
class Machine:
    def __init__(self, max_features=20000, maxlen=80):
        self.data = Data(max_features, maxlen)
        self.model = RNN_LSTM(max_features, maxlen)
 
    def run(self, epochs=3, batch_size=32):
        data = self.data
        model = self.model
 
        print('Training stage')
        model.fit(data.x_train, data.y_train,
            batch_size=batch_size, epochs=epochs,
            validation_data=(data.x_test, data.y_test),
            verbose=2)
 
        loss, acc = model.evaluate(data.x_test, data.y_test,
            batch_size=batch_size, verbose=2)
 
        print('Test performance: accuracy={0}, loss={1}'.format(acc, loss))
 
def main():
    m = Machine()
    m.run()
 
if __name__ == '__main__':
    main()
cs

결과:
Training stage
Train on 25000 samples, validate on 25000 samples
Epoch 1/3
 - 244s - loss: 0.4633 - acc: 0.7804 - val_loss: 0.3842 - val_acc: 0.8332
Epoch 2/3
 - 239s - loss: 0.2992 - acc: 0.8786 - val_loss: 0.3751 - val_acc: 0.8355
Epoch 3/3
 - 244s - loss: 0.2177 - acc: 0.9156 - val_loss: 0.4489 - val_acc: 0.8286
Test performance: accuracy=0.82856, loss=0.44894479445934293

책에서 왜 3 에포크만 돌렸는지 모르겠지만 검증 정확도가 83%에서 안오르는거 보면 3 에포크만 돌려도 충분한 것 같습니다.


코드 설명입니다.

datasets.imdb.load_data로 imdb 데이터셋을 불러오고 있는데 num_words를 설정해주면
출현빈도가 많은 단어순으로 num_words개의 단어 종류만 불러오고 그 외엔 oov_char값으로 바꿔버립니다.

preprocessing.sequence.pad_sequences는 시퀀스들의 길이를 똑같게 맞추는 역할을 합니다.
maxlen을 설정하지 않으면 가장 길이가 긴 시퀀스의 길이에 맞춰집니다.
기본적으로 시퀀스의 앞에 0을 넣어 길이를 맞춰주며
길이가 maxlen보다 크면 앞에서부터 잘리게 됩니다.

layers.Embedding은 0~(input_dim-1)까지의 정수가 든, 길이 input_length의 시퀀스의 각 값을
output_dim개의 값으로 변환해줍니다.
그러니까 input_length=10, output_dim=64일때 입력으로 (32, 10)의 데이터를 주면 (32, 10, 64)로 변환해줍니다.
이 예제에서는 0~19999 범위의 정수들을 128개의 값으로 임베딩해주게 됩니다.
왜 이런걸 하느냐하면 수학적인건 잘 모르지만 모델에 너무 큰 수 하나를 넣는거보단 작은 여러개의 값으로 대응시켜 사용하는게 더 효과적이기 때문일겁니다.
그리고 이 레이어는 모델의 첫번째에만 위치할 수 있다고 합니다.

layers.LSTM은 이름대로 LSTM 레이어입니다.
recurrent_dropout으로 되먹임되는 상태(Recurrent State)에도 드롭아웃을 적용할 수 있다고 합니다.

그리고 라벨이 0 또는 1 뿐이므로 loss 함수는 binary_crossentropy를 사용했습니다.

설명 끝!





Comments