seq2seq 이란 입력된 시퀀스로부터 다른 도메인의 시퀀스를 출력하는 다양한 분야에서 사용되는 모델 이다.

machine translation, chatbot, summarization, Speech Recognition, image captioning 등등 다양한 자연어 처리에서 쓰인다.


encoder, decoder, generator로 이루어져 있는 일종의 autoencoder 로,

수식1

에서의 **P(Y X;Θ)** 를 최대로 하는 모델 파라미터를 찾도록 학습한 후

수식2

와 같이, 사후 확률을 최대로 하는 Y를 찾아낸다.


Encoder

  • 여러 개의 vector(주어진 소스 문장)를 입력으로 받아, 문장을 함축하는 문장 embedding vector로 만들어냄
    • 즉, P(z X)를 모델링하고, 주어 문장을 Manifold를 따라 차원축소하여, 해당 domain의 latent space의 하나의 점에 투영함.
  • machine translation을 위한 문장 embedding vector를 만들기 위해서는 feature를 최대한 많이 간직해야 함
    • 이것이 다른 text classification과 다른 점
  • 수식으로 나타내기

수식3

  • [;]는 concatenate 를 의미


Decoder

  • CNNLM (conditional neural network language model)

수식4

  • (위 수식을 참조)기존 RNNLM의 수식에서 조건부 확률 변수 부분에 X가 추가되었다.
    • encoder의 결과인 문장 embedding vector와, 이전 time step까지 번역하여 생성한 단어들에 기반하여 현재 time step의 단어를 생성한다

수식5


Generator

  • decoder에서 각 time-stamp 별로 결과 벡터 Ht를 받아 softmax를 계산하여, 각 타깃 언어의 단어별 확률을 반환하는 작업 수행
    • generator의 결과값은 각 단어가 나타난 확률 (이산 확률 분포)

주의점

  • 문장의 길이가 Y = m 일 떄 마지막 반환되는 단어 Ym은 EOS(end of sentence) 토큰이 되어 계산의 종료를 나타냄
    • 즉, 이론상 decoder의 입력으로 들어가지 않음

수식6


한계점

  1. 장기 기억력
  • Neural Network Model이 차원 축소를 통해 데이터를 압축하는데 좋은 성능을 가졌지만, 무한하게 정보를 압축하는 건 불가능
    • 문장 or time-stamp 가 길어질수록 압축 성능이 떨어짐
  1. 구조 정보의 부재
  • 대부분 RNN등의 neural network가 알아서 구조를 이해해준다는 생각에, 문장의 구조 정보보다는 sequence data로 다루는 경향이 있음
    • but, 정말 그럴까?
  1. chatbot 또는 QA봇에서의 활용
  • seq2seq에서는 새롭게 추가되는 정보를 담을 수 없기에, 발전된 구조가 필요
    • 일반적인 대화에서 대답은 질문에 비해 새로운 문맥이 추가되는 경우가 많기 때문


attention

attention이란, query와 비슷한 key를 찾아서 그 value를 얻는 과정이다. (python의 dictionary 느낌 )


def key_value_find(query):
  weights = []

  for key in dic.keys():
    weights += [is_same(key, query)]

  weight_sum = sum(weights)
  for i,w in enumerate(weights):
    weights[i] = weights[i]/weight_sum

  answer = 0

  for weight, value in zip(weights, dic.values()):
    answer += weight * value

  return answer



def is_same(key, query):
  if key == query:
    return 1.
  else:
    return .0


이 때, is_same 말고 cosine 유사도를 반환하는 함수(ex. how_similar)를 이용해도 좋을 것이다.

아래와 같이 수정해보자 !


def key_value_find(query):
  weights = []

  for key in dic.keys():
    weights += [how_similary(key, query)] # cosign similarity 를 채워넣음

  weights = softmax(weights) # 모든 weight 를 구한 후 softmax 계산
  answer = 0

  for weight, value in zip(weights, dic.values()):
    answer += weight * value

  return answer


이를 응용하여 seq2seq에 적용하면 아래와 같다.

attention

attention2

기존 seq2seq은 encoder와 decoder라는 두개의 RNN으로 이루어져 있었으며,

encoder의 결과(문장 embedding vector)의 정보를 decoder의 hidden state에 전달하여 decoder는 이로부터 문장을 만들어내야 했다.

따라서 hidden state만으로는 문장의 모든 정보를 완벽하게 전달하기 어려웠다.


그래서 decoder의 time-stamp마다,

현재 decoder의 hidden state에 따라 필요한 encoder의 정보에 접근하여 정보를 끌어다 쓰겠다는 것!

이 때 선형 변환을 통해 decoder의 현재 상태에 따라 필요한 query를 만들어내고,encoder의 key 값들과 비교하여 weighted sum을 한다.

이러한 선형 변환을 배우는 것 자체가 attention이다. attention을 적용하면, 문장이 길어지더라도 성능이 크게 하락하지 않는다.


즉, attention을 통해 decoder는 encoder에 query를 날리고, 이를 잘 해야 좋은 정답을 얻을 수 있다.

마찬가지로 neural network도 query를 만들어내는 훈련인 셈이다.


Reference