케라스 어텐션 메커니즘(Keras Attention Mechanism) (LSTM)

머신러닝과 딥러닝 · 2020. 1. 8. 20:57

어텐션 모델

어텐션의 기본 아이디어는

디코더에서 출력 단어를 예측하는 매 시점(time step)마다,

인코더에서의 전체 입력 문장을 다시 한 번 참고한다는 점이다.

 

단, 전체 입력 문장을 전부 다 동일한 비율로 참고하는 것이 아니라,
해당 시점에서 예측해야할 단어와 연관이 있는 입력 단어 부분을

 

좀 더 집중(attention)해서 보게 된다.

 

딥러닝 모델이 벡터 Sequence 중에서 가장 중요한 벡터에 집중하도록 하는 모델이라 할 수 있다.

어텐션 모델의 Output은 중요한 벡터를 위주로 나타나기 때문에 Sequence의 중요한 부분에 집중한다고 볼 수 있다.

 

 

어텐션 모델은 개념적으로 아래와 같이 동작한다.

  1. 입력으로 들어온 벡터들의 중요도/유사도를, 현재 state를 고려하여 구한다.
  2. 각각의 중요도를, 총 합이 1이 되는 상대값으로 바꾼다(소프트맥스 함수).
  3. 상대값 중요도를 가중치로 보고, Sequence에 있는 벡터들을 가중치합한다.

 

Attention LSTM 예제

import tensorflow as tf
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

TIME_STEPS = 20
INPUT_DIM  = 2

def attention_3d_block(inputs):
    
    # inputs.shape = (batch_size, time_steps, input_dim)
    input_dim = int(inputs.shape[2])
    
    a = tf.keras.layers.Permute((2, 1))(inputs) # same transpose
    #a = tf.keras.layers.Reshape((input_dim, TIME_STEPS))(a) 
    # this line is not useful. It's just to know which dimension is what.
    a = tf.keras.layers.Dense(TIME_STEPS, activation='softmax')(a)
    
    a_probs = tf.keras.layers.Permute((2, 1), name='attention_vec')(a)
    
    output_attention_mul  = tf.keras.layers.multiply([inputs, a_probs])
    #output_attention_mul = merge([inputs, a_probs], name='attention_mul', mode='mul')
    return output_attention_mul

def model_attention_applied_after_lstm():
    
    inputs        = tf.keras.Input(shape=(TIME_STEPS, INPUT_DIM,))
    lstm_units    = 32
    
    lstm_out      = tf.keras.layers.LSTM(lstm_units, return_sequences=True)(inputs)
    
    attention_mul = attention_3d_block(lstm_out)
    attention_mul = tf.keras.layers.Flatten()(attention_mul)
    
    output        = tf.keras.layers.Dense(1, activation='sigmoid')(attention_mul)
    
    model         = tf.keras.Model(inputs=[inputs], outputs=output)
    
    return model

def model_attention_applied_before_lstm():
    
    inputs        = tf.keras.Input(shape=(TIME_STEPS, INPUT_DIM,))
    
    attention_mul = attention_3d_block(inputs)
    
    lstm_units    = 32
    
    attention_mul = tf.keras.layers.LSTM(lstm_units, return_sequences=False)(attention_mul)    
    output        = tf.keras.layers.Dense(1, activation='sigmoid')(attention_mul)
    
    model         = tf.keras.Model(inputs=[inputs], outputs=output)
    
    return model

def get_data_recurrent(n, time_steps, input_dim, attention_column=10):

    x = np.random.standard_normal(size=(n, time_steps, input_dim))
    y = np.random.randint(low=0, high=2, size=(n, 1))

    x[:, attention_column, :] = np.tile(y, input_dim)

    return x, y

model_attetion_applied_after_lstm()의 모델 구조는 다음과 같다.

여기서 tf.kears.layers.Permute()는 transpose과 비슷한 역할을 한다.

 

Input Matrix를 transpose()하는 이유는

 

각각의 Sequence의 벡터 $ y_{i} $에 $ W_{y}$ 행렬을 내적한 값을 더하는 것을 Dense layer로 구현하기 위해서이다.

 

왼쪽 : model_attention_applied_before_lstm 오른쪽 : model_attention_applied_after_lstm

데이터를 생성하고 모델을 만든다.

모델에서 attention_vec의 출력을 보기 위해서 activation_model을 만든다.

train_x, train_y = get_data_recurrent(300000, TIME_STEPS, INPUT_DIM)

#modelman = model_attention_applied_before_lstm()
modelman = model_attention_applied_after_lstm()
modelman.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

modelman.fit([train_x], train_y, epochs=1, batch_size=128, validation_split=0.1)

layer_outputs    = [layer.output for layer in modelman.layers if layer.name == 'attention_vec']
activation_model = tf.keras.models.Model(inputs=modelman.input, outputs=layer_outputs)

attention_vector를 출력해본다.

attention_vectors = []
for i in range(50):
    test_x, test_y = get_data_recurrent(1, TIME_STEPS, INPUT_DIM)

    predict_output   = activation_model.predict(test_x)
    #print(predict_output.shape)
    dols = np.mean(predict_output, axis=2).squeeze()
    #print(dols,"DOLS",dols.shape)
    
    assert (np.sum(dols) - 1.0) < 1e-5
    #attention_vectors.append
    attention_vectors.append(dols)

attention_vector_final = np.mean(np.array(attention_vectors), axis=0)

pd.DataFrame(attention_vector_final, columns=['attention (%)']).plot.bar()

 

왼쪽 : model_attention_applied_before_lstm 오른쪽 : model_attention_applied_after_lstm

10번 인덱스의 가중치 값이 가장 높다.

 

 

RNN의 Long-Term Dependency 해결

Long-Term Dependency(장기 의존성)

제공된 데이터와 배워야 할 정보의 입력 차이(Gap)가 큰 경우 두 정보의 문맥을 연결하기 어려운 현상.

이를 해결하기 위한 방법들은 다음과 같다.

 

LSTM(Long Short Term Memory Network) 등을 활용하여 해결할 수 있다.

 

Attention Mechanism을 이용하면 Sequence가 길더라도 그 중에서 중요한 벡터에 집중할 수 있으므로, Long-Term Dependency를 해결할 수 있음.

 

 

 

https://github.com/philipperemy/keras-attention-mechanism

 

philipperemy/keras-attention-mechanism

Attention mechanism Implementation for Keras. Contribute to philipperemy/keras-attention-mechanism development by creating an account on GitHub.

github.com

https://github.com/BD-SEARCH/MLtutorial/wiki/Attention-Network

 

BD-SEARCH/MLtutorial

Machine Learning 개념 정리! Wiki 참고. Contribute to BD-SEARCH/MLtutorial development by creating an account on GitHub.

github.com

https://wikidocs.net/22893

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net