Buomsoo Kim

케라스와 함께하는 쉬운 딥러닝 (15) - 순환형 신경망(RNN) 기초

|

순환형 신경망 1 - RNN 구조 기초

Objective: RNN의 기본적인 구조를 이해하고 케라스로 이를 구현해본다

MLP나 CNN와 같은 feedforward net과는 달리, RNN은 순차형(sequential) 데이터를 모델링하는데 최적화된 구조라고 할 수 있다. 데이터가 입력되는 순서가 중요한 역할을 하는 순차형 정보를 수월하게 처리하기 위해 RNN은 이전 상태(state)를 기록하고 이를 다음 셀에서 활용할 수 있는 독특한 구조를 가지고 있다.

그러므로, RNN을 효과적으로 활용하기 위해서는 이러한 상태(state)들 간의 순서(sequence)라는 컨셉을 이해하는 것이 필수적이다.


RNN 모델 입력 데이터

가장 기본적인 형태의 RNN 셀에 입력되는 텐서의 모양은 (batch_size, timesteps, input_dim)와 같다.

  • batch_size: 경사하강법(stochastic gradient descent)으로 모델이 학습될 때 한 번에 고려되는 데이터 인스턴스의 갯수. RNN 셀을 생성할 때에는 설정되지 않고 주로 모델을 fitting하는 과정에서 설정된다.
  • timesteps: 인풋 시퀀스의 갯수
  • input_dim: 각 인풋 시퀀스의 차원(dimensionality). feedforward net에서 입력 feature의 차원 수와 비슷한 역할을 한다고 볼 수 있다.
# RNN 입력 데이터 예시
x = np.array([[
             [1,    # => input_dim 1
              2,    # => input_dim 2 
              3],   # => input_dim 3     # => timestep 1                            
             [4, 5, 6]                   # => timestep 2
             ],                                  # => batch 1
             [[7, 8, 9], [10, 11, 12]],          # => batch 2
             [[13, 14, 15], [16, 17, 18]]        # => batch 3
             ])

print('(Batch size, timesteps, input_dim) = ',x.shape)
(Batch size, timesteps, input_dim) =  (3, 2, 3)

SimpleRNN

SimpleRNN은 가장 기본적인 형태의 RNN 셀로, 입력 텐서에는 최소 2개의 파라미터(timesteps, input_dim)을 설정을 해주어야 한다

# rnn = SimpleRNN(50)(Input(shape = (10,))) => error
# rnn = SimpleRNN(50)(Input(shape = (10, 30, 40))) => error
rnn = SimpleRNN(50)(Input(shape = (10, 30)))

return_sequences 파라미터를 따로 설정해 주지 않으면 False로 디폴트 값이 설정되며, 이 경우에는 출력 값이 셀의 갯수(number of cells)와 동일하다. 즉, 셀 하나당 하나의 스칼라(scalar) 값이 반환된다.

rnn = SimpleRNN(50)(Input(shape = (10, 30)))
print(rnn.shape)
(?, 50)

만약 return_sequences 파라미터를 True로 설정해 주면 출력 값은 (timesteps X Num_cells)가 되며 timesteps은 입력 텐서의 모양에 따라 결정된다.

rnn = SimpleRNN(50, return_sequences = True)(Input(shape = (10, 30)))
print(rnn.shape)
(?, ?, 50)

좀더 자세히 예시를 통해 살펴보자

  • return_sequences == False 인 경우
rnn = SimpleRNN(50, return_sequences = False, return_state = True)(Input(shape = (10, 30)))
print(rnn[0].shape)         # shape of output
print(rnn[1].shape)         # shape of last state
(?, 50)
(?, 50)
  • return_sequences == True 인 경우
rnn = SimpleRNN(50, return_sequences = True, return_state = True)(Input(shape = (10, 30)))
print(rnn[0].shape)         # shape of output
print(rnn[1].shape)         # shape of last state
(?, ?, 50)
(?, 50)

이번 포스팅에서는 RNN의 상태(sequence)와 순서(sequence)의 개념에 대해서 알아보고, 기본적인 RNN 셀(SimpleRNN)을 케라스를 통해 어떻게 생성하고 설정하는 지에 대해서 알아보았다. 다음 포스팅에서는 보다 진보된 형태의 RNN 구조에 대해서 알아보자.

전체 코드

본 실습의 전체 코드는 여기에서 열람하실 수 있습니다!

케라스와 함께하는 쉬운 딥러닝 (14) - 다양한 CNN 구조

|

합성곱 신경망 8 - 다양한 CNN 구조

Objective: 케라스로 다양한 CNN 모델을 만들어 본다.

지난 포스팅에서 케라스로 문장 분류를 위한 2-D CNN 모형을 IMDB MOVIE REVIEW SENTIMENT 데이터를 활용하여 만들어 보았으며, 간단한 1-D CONVOLUTION (TEMPORAL CONVOLUTION)보다 개량된 정확도인 86.6%의 test accuracy를 기록하였다.

이번 포스팅에는 문장 분류를 위한 CNN의 학습 과정을 개선시키고 안정화할 수 있는 여러 가지 방법을 탐구해 보자.

IMDB 데이터 셋 불러오기

IMDB 영화 리뷰 감성분류 데이터 셋(IMDB Movie Revies Sentiment Classification Dataset)은 총 50,000 개의 긍정/혹은 부정으로 레이블링된 데이터 인스턴스(즉, 50,000개의 영화 리뷰)로 이루어져 있으며, 케라스 패키지 내에 processing이 다 끝난 형태로 포함되어 있다.

리뷰 데이터를 불러올 때 주요 파라미터는 아래와 같다

  • num_features: 빈도 순으로 상위 몇 개의 단어를 포함시킬 것인가를 결정
  • sequence_length: 각 문장의 최대 길이(특정 문장이 sequence_length보다 길면 자르고, sequence_length보다 짧으면 빈 부분을 0으로 채운다)를 결정
  • embedding_dimension: 각 단어를 표현하는 벡터 공간의 크기(즉, 각 단어의 vector representation의 dimensionality)
import numpy as np
import matplotlib.pyplot as plt

from keras.datasets import imdb
from keras.preprocessing.sequence import pad_sequences

num_features = 3000
sequence_length = 300
embedding_dimension = 100

(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words = num_features)

X_train = pad_sequences(X_train, maxlen = sequence_length)
X_test = pad_sequences(X_test, maxlen = sequence_length)

print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
(25000, 300), (25000, 300), (25000,), (25000,)

2-D CNN WITH DIFFERENT SETTINGS

지난번 포스팅의 마지막 모델과 비슷한 구조를 갖고 있지만 Dropout과 Batch Normalization 등 MLP모델을 안정화시키는 데 활용한 기법들을 CNN 구조에도 동일하게 활용해 본다.


자신이 만든 CNN 모델이 제대로 작동하지 않고 지나치게 낮은 training/test accuracy를 보인다면, 이러한 기법들을 조합하여 성능을 높일 수도 있다.

from keras.models import Model
from keras.layers import concatenate, Input

filter_sizes = [3, 4, 5]

# 합성곱 연산을 적용하는 함수를 따로 생성. 이렇게 만들어 놓으면 convolution 레이어가 여러개더라도 편리하게 적용할 수 있다.
def convolution()
    inn = Input(shape = (sequence_length, embedding_dimension, 1))
    convolutions = []
    # we conduct three convolutions & poolings then concatenate them.
    for fs in filter_sizes:
        conv = Conv2D(filters = 100, kernel_size = (fs, embedding_dimension), strides = 1, padding = "valid")(inn)
        nonlinearity = Activation('relu')(conv)
        maxpool = MaxPooling2D(pool_size = (sequence_length - fs + 1, 1), padding = "valid")(nonlinearity)
        convolutions.append(maxpool)

    outt = concatenate(convolutions)
    model = Model(inputs = inn, outputs = outt)

    return model

# 여러가지 기법이 추가된 2D CNN 모델을 만들고 학습시키기 위한 함수
def imdb_cnn_4():
    
    model = Sequential()
    model.add(Embedding(input_dim = 3000, output_dim = embedding_dimension, input_length = sequence_length))
    model.add(Reshape((sequence_length, embedding_dimension, 1), input_shape = (sequence_length, embedding_dimension)))
    model.add(Dropout(0.5))
    # call convolution method defined above
    model.add(convolution())
    
    model.add(Flatten())
    model.add(Dense(10))
    model.add(BatchNormalization())
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    model.add(Dense(10))
    model.add(Activation('relu'))
    model.add(BatchNormalization())
    model.add(Dropout(0.5))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))

    adam = optimizers.Adam(lr = 0.001)

    model.compile(loss='binary_crossentropy', optimizer=adam , metrics=['accuracy'])
    
    return model

model = imdb_cnn_4()

모델을 학습시키고 검증해 보자

history = model.fit(X_train, y_train, batch_size = 50, epochs = 100, validation_split = 0.2, verbose = 0)

plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.legend(['training', 'validation'], loc = 'upper left')
plt.show()


results = model.evaluate(X_test, y_test)
print('Test accuracy: ', results[1])

검증 정확도 86.8%로 지난번 모델과 비슷한 정확도를 보이지만 성능을 높이기 위해 여러 기법들을 활용할 수 있다는 점을 유의하자. 지금도 딥 러닝 모델의 학습을 위한 새로운 기법들이 꾸준히 제안되고 있다.

Test accuracy:  0.86876

전체 코드

본 실습의 전체 코드는 여기에서 열람하실 수 있습니다!

Using Dark Theme in Google Colaboratory

|

Using Dark Theme in Google Colaboratory

Recently, it was annoucned via the Google Colab twitter that the dark theme is supported in Colaboratory.

This was a great news for me who sometimes spent hours a day writing codes to process and analyze data with colaboratory.

If you haven’t tried it, try using it after reading this short article. It is so EASY and makes your eyes much less tiresome.

1. Default (light) theme in Colaboratory

By default, the light theme is applied when you create a new colab file like below.

But sometimes, working with a bright screen for a long time makes you much fatigued.

2. Converting to dark theme

1. Open “Preferences”

Click [Preferences] under [Tools] to manage your preferences.

2. Change your theme

Change the theme to “dark.” It will be set to “light” by default and you can always come back and change to the default seting of “light.”

3. Start coding with less burden on your eyes!

Now come back to the colab file and you will see that the cells and background are changed into dark colors.

As noted, you can always bounce back to the default (light) mode same way. And as always, thank you for reading and enjoy coding!

케라스와 함께하는 쉬운 딥러닝 (13) - 다양한 CNN 구조

|

합성곱 신경망 7 - 다양한 CNN 구조

Objective: 케라스로 다양한 CNN 모델을 만들어 본다.

지난 포스팅에서 케라스로 문장 분류를 위한 간단한 CNN 모형을 만들어 보았다.

NLP 계의 MNIST라고 할 수 있을 정도로 자주 활용되는 텍스트 데이터인 IMDB MOVIE REVIEW SENTIMENT 데이터를 활용하였으며, 간단한 1-D CONVOLUTION (TEMPORAL CONVOLUTION)을 적용하여 85% 정도의 검증 정확도를 기록하였다.

이번 포스팅에는 문장 분류를 위한 CNN의 학습 과정을 개선시키고 안정화할 수 있는 여러 가지 방법을 탐구해 보자.

IMDB 데이터 셋 불러오기

IMDB 영화 리뷰 감성분류 데이터 셋(IMDB Movie Revies Sentiment Classification Dataset)은 총 50,000 개의 긍정/혹은 부정으로 레이블링된 데이터 인스턴스(즉, 50,000개의 영화 리뷰)로 이루어져 있으며, 케라스 패키지 내에 processing이 다 끝난 형태로 포함되어 있다.

리뷰 데이터를 불러올 때 주요 파라미터는 아래와 같다

  • num_features: 빈도 순으로 상위 몇 개의 단어를 포함시킬 것인가를 결정
  • sequence_length: 각 문장의 최대 길이(특정 문장이 sequence_length보다 길면 자르고, sequence_length보다 짧으면 빈 부분을 0으로 채운다)를 결정
  • embedding_dimension: 각 단어를 표현하는 벡터 공간의 크기(즉, 각 단어의 vector representation의 dimensionality)
import numpy as np
import matplotlib.pyplot as plt

from keras.datasets import imdb
from keras.preprocessing.sequence import pad_sequences

num_features = 3000
sequence_length = 300
embedding_dimension = 100

(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words = num_features)

X_train = pad_sequences(X_train, maxlen = sequence_length)
X_test = pad_sequences(X_test, maxlen = sequence_length)

print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
(25000, 300), (25000, 300), (25000,), (25000,)

2-D CONVOLUTION & POOLING

앞서 언급했듯이, 지난번 포스팅에서는 1-D convolution (temporal convolution)을 활용하였다. 이번에는 NLP 과업에서는 자주 활용되지 않지만 이미지 데이터 처리에 자주 활용되는 2-D CONVOLUTION을 적용해 보자.

Reshape을 활용해 embedding layer를 4차원으로 전환해 2차원 합성곱 연산을 가능케 한다.

from keras.layers import Reshape, Conv2D, GlobalMaxPooling2D
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras import optimizers

def imdb_cnn_2():
    model = Sequential()

    model.add(Embedding(input_dim = 3000, output_dim = embedding_dimension, input_length = sequence_length))
    model.add(Reshape((sequence_length, embedding_dimension, 1), input_shape = (sequence_length, embedding_dimension)))
    model.add(Conv2D(filters = 50, kernel_size = (5, embedding_dimension), strides = (1,1), padding = 'valid'))
    model.add(GlobalMaxPooling2D())

    model.add(Dense(10))
    model.add(Activation('relu'))
    model.add(Dropout(0.3))
    model.add(Dense(10))
    model.add(Activation('relu'))
    model.add(Dropout(0.3))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))

    adam = optimizers.Adam(lr = 0.001)

    model.compile(loss='binary_crossentropy', optimizer=adam , metrics=['accuracy'])

    return model

model = imdb_cnn_2()

2차원 합성곱 연산 후에 GlobalMaxPooling2D 레이어를 이어 붙였다(flatten 필요 없음).

history = model.fit(X_train, y_train, batch_size = 50, epochs = 100, validation_split = 0.2, verbose = 0)

plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.legend(['training', 'validation'], loc = 'upper left')
plt.show()


검증 정확도로 모델을 검증해 보자.

results = model.evaluate(X_test, y_test)
print('Test accuracy: ', results[1])
Test accuracy:  0.86628

검증 정확도 86.6%로 지난번에 활용하였던 간단한 모델에 비해서 미묘하게 정확도는 상승하였다.

DIFFERENT FILTER SIZES

지금까지 우리가 구현해온 CONVOLUTION 연산은 한 번에 필터의 사이즈를 하나만 적용하였다. 그렇지만 Kim 2014 논문에서는 하나의 레이어에 여러 개의 크기의 합성곱 필터를 적용한 결과를 이어 붙여 따라 붙는 레이어를 완성하였다.


이번에는 이와 유사하게, 필터 크기를 3, 4, 5로 다양화하고 max pooling을 적용한 결과를 concatenate해 다양한 time window로 학습을 해보자

이를 위해서는 모델을 생성하기 위해 지금까지 사용해왔던 Sequential API가 아닌 Functional API를 사용하여야 한다. Functional API에 대한 자세한 설명은 여기.

from keras.models import Model
from keras.layers import concatenate, Input

filter_sizes = [3, 4, 5]

# 합성곱 연산을 적용하는 함수를 따로 생성. 이렇게 만들어 놓으면 convolution 레이어가 여러개더라도 편리하게 적용할 수 있다.
def convolution()
    inn = Input(shape = (sequence_length, embedding_dimension, 1))
    convolutions = []
    # we conduct three convolutions & poolings then concatenate them.
    for fs in filter_sizes:
        conv = Conv2D(filters = 100, kernel_size = (fs, embedding_dimension), strides = 1, padding = "valid")(inn)
        nonlinearity = Activation('relu')(conv)
        maxpool = MaxPooling2D(pool_size = (sequence_length - fs + 1, 1), padding = "valid")(nonlinearity)
        convolutions.append(maxpool)

    outt = concatenate(convolutions)
    model = Model(inputs = inn, outputs = outt)

    return model

  def imdb_cnn_3():

      model = Sequential()
      model.add(Embedding(input_dim = 3000, output_dim = embedding_dimension, input_length = sequence_length))
      model.add(Reshape((sequence_length, embedding_dimension, 1), input_shape = (sequence_length, embedding_dimension)))

      # call convolution method defined above
      model.add(convolution())

      model.add(Flatten())
      model.add(Dense(10))
      model.add(Activation('relu'))
      model.add(Dropout(0.3))
      model.add(Dense(10))
      model.add(Activation('relu'))
      model.add(Dropout(0.3))
      model.add(Dense(1))
      model.add(Activation('sigmoid'))

      adam = optimizers.Adam(lr = 0.001)

      model.compile(loss='binary_crossentropy', optimizer=adam , metrics=['accuracy'])

      return model

model = imdb_cnn_3()

모델을 학습시키고 검증해 보자

history = model.fit(X_train, y_train, batch_size = 50, epochs = 100, validation_split = 0.2, verbose = 0)

plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.legend(['training', 'validation'], loc = 'upper left')
plt.show()


results = model.evaluate(X_test, y_test)
print('Test accuracy: ', results[1])

검증 정확도 87.2%로 기본 모델(baseline model)에 비해 2% 가량 상승하였다.

Test accuracy:  0.87284

전체 코드

본 실습의 전체 코드는 여기에서 열람하실 수 있습니다!

케라스와 함께하는 쉬운 딥러닝 (12) - 다양한 CNN 구조

|

합성곱 신경망 6 - 다양한 CNN 구조

Objective: 케라스로 다양한 CNN 모델을 만들어 본다.

지난 포스팅에서 케라스로 deep CNN 모델을 만들어 보고 mnist 데이터 셋에서의 검증 정확도를 99% 이상으로 끌어올리는 데 성공하였다.

CNN 모델은 mnist와 같이 이미지 형태의 데이터에 흔히 사용되는 것으로 알려져 있지만, 음성, 영상, 텍스트 형태의 비정형 데이터의 분석에도 자주 활용되고 있다.

이번 포스팅에는 텍스트 데이터인 imdb 데이터를 CNN 구조를 적용한 네트워크를 활용해 분석을 해보자.

문장 분류를 위한 합성곱 신경망(CNN for Sentence Classification)

Kim 2014 논문 이후로 NLP 과업을 위해 CNN이 자주 활용되고 있으며, 최근에는 순환형 신경망(RNN)이 과도한 연산량 등으로 인해 비판을 받으면서 CNN이 더욱 떠오르고 있다

Kim 2014가 제안한 모델의 대략적인 구조는 아래와 같다


  • 학습 데이터는 각 문장 내에 있는 단어의 embedding vector를 구해 만들어진다(행렬에서 하나의 단어가 하나의 행을 차지)
  • 합성곱 연산은 단어 단위(행 단위)로 이루어진다
  • 결과로는 각 문장을 긍정(1) 혹은 부정(0) 으로 분류한다.


IMDB 데이터 셋 불러오기

IMDB 영화 리뷰 감성분류 데이터 셋(IMDB Movie Revies Sentiment Classification Dataset)은 총 50,000 개의 긍정/혹은 부정으로 레이블링된 데이터 인스턴스(즉, 50,000개의 영화 리뷰)로 이루어져 있으며, 케라스 패키지 내에 processing이 다 끝난 형태로 포함되어 있다.

리뷰 데이터를 불러올 때 주요 파라미터는 아래와 같다

  • num_features: 빈도 순으로 상위 몇 개의 단어를 포함시킬 것인가를 결정
  • sequence_length: 각 문장의 최대 길이(특정 문장이 sequence_length보다 길면 자르고, sequence_length보다 짧으면 빈 부분을 0으로 채운다)를 결정
  • embedding_dimension: 각 단어를 표현하는 벡터 공간의 크기(즉, 각 단어의 vector representation의 dimensionality)
import numpy as np
import matplotlib.pyplot as plt

from keras.datasets import imdb
from keras.preprocessing.sequence import pad_sequences

num_features = 3000
sequence_length = 300
embedding_dimension = 100

(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words = num_features)

X_train = pad_sequences(X_train, maxlen = sequence_length)
X_test = pad_sequences(X_test, maxlen = sequence_length)

print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
(25000, 300), (25000, 300), (25000,), (25000,)

모델 생성하기

가장 기본적인 형태의 1-D convolution (temporal convolution)을 구현해 보자. 이는 2차원 형태(2-D)의 데이터에 적용 가능하다.

from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Conv1D, MaxPooling1D, Embedding, Flatten
from keras import optimizers
def imdb_cnn():
    model = Sequential()

    # use Embedding layer to create vector representation of each word => it is fine-tuned every iteration
    model.add(Embedding(input_dim = 3000, output_dim = embedding_dimension, input_length = sequence_length))
    model.add(Conv1D(filters = 50, kernel_size = 5, strides = 1, padding = 'valid'))
    model.add(MaxPooling1D(2, padding = 'valid'))

    model.add(Flatten())

    model.add(Dense(10))
    model.add(Activation('relu'))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))

    adam = optimizers.Adam(lr = 0.001)

    model.compile(loss='binary_crossentropy', optimizer=adam , metrics=['accuracy'])

    return model

model = imdb_cnn()

보통 위와 같이 Conv1D 레이어에 MaxPooling1D 레이어를 이어 사용한다. 모델 학습은 이미지 데이터와 똑같다.

history = model.fit(X_train, y_train, batch_size = 50, epochs = 100, validation_split = 0.2, verbose = 0)

plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.legend(['training', 'validation'], loc = 'upper left')
plt.show()

모델의 학습은 잘 이루어져 학습 오차는 아래와 같이 0으로 수렴하는 것을 볼 수 있다. 하지만 validation error는 0.85 내외를 왔다갔다 하다가 60 에포크 이상에서 갑자기 떨어져 과적합(overfitting)의 신호를 보인다.


검증 정확도로 모델을 검증해 보자.

results = model.evaluate(X_test, y_test)
print('Test accuracy: ', results[1])
Test accuracy:  0.8556

검증 정확도 85%로 간단한 모델을 활용하고 오래 학습시키지 않았음에도 불구하고 나쁘지 않은 결과를 보여준다. 이제 다음 포스팅에서는 이번 포스팅에서 적용해본 바닐라 모델에서 나아가, 조금 더 복잡한 CNN 모델을 NLP 과업에 적용해 보자.

전체 코드

본 실습의 전체 코드는 여기에서 열람하실 수 있습니다!