Processing math: 100%
본문 바로가기

자연어처리

어텐션(Attention) (1)

1. 어텐션(Attention)


1.1 RNN에 기반한 Seq2Seq의 문제점

■ RNN에 기반한 Encoder-Decoder 구조의 Seq2Seq 모델은 Encoder가 시계열 데이터를 인코딩한 후, 그 정보를 고정 길이 벡터  h에 담아 Decoder에 전달한다. 

■ Decoder는 이 벡터를 바탕으로 정답(또는 타깃)과의 비교를 통해 예측 결과를 평가하고, 이를 바탕으로 Loss를 계산하여 학습을 수행하는 구조이다.

■ 이렇게 RNN에 기반한 Seq2Seq구조에는 두 가지 주요한 문제점이 있으며, 각각 Encoder와 Decoder에 관련되어 있다.

■ 먼저, RNN에 기반한 Decoder의 문제점은 고질적 문제인 기울기 소실 문제이다.

■ Encoder의 문제점은 은닉 상태와 관련이 있다.

■ Encoder에서 생성하는 은닉 상태는 고정 길이 벡터라서 입력 문장(시퀀스)이 길어도, 항상 동일한 길이(크기)의 벡터가 된다. 즉, 고정된 크기의 벡터에 입력 시퀀스의 정보를 압축하기 때문에 문장이 길어질수록 중요한 정보가 누락될 가능성이 크다.

■ 예를 들어, 기계 번역에서는 입력 문장이 길어질수록 번역 품질이 저하되는 문제가 발생한다. 이러한 Seq2Seq의 한계를 개선하기 위해 나온 기법이 Attention 메커니즘이다. 

■ 어텐션은 Seq2Seq 구조에서 출력 시퀀스를 예측하는 매 시점(time step)마다 Encoder의 입력 시퀀스를 참고하되, 예측할 출력 단어와 관련이 큰 단어에 '집중'해서 참고하는 방법으로, 입력 시퀀스가 길어지더라도 출력 시퀀스의 정확도가 떨어지는 것을 보정할 수 있다.


1.2 어텐션 아이디어

■ 사람이 글을 읽을 때는 보통 왼쪽에서 오른쪽으로 읽어나가며, 복잡하고 어려운 글은 중간중간 멈추고 어떤 단어와 어떤 단어가 문장 안에서 연결되는지 단어들 사이의 관계를 생각하거나 찾아보곤 한다.

■ 어텐션은 이러한 이해 과정을 모방한 개념이다. 즉, 문장 내에서 단어와 단어 사이의 관계를 파악하여, 맥락과 관련이 깊은 단어와 그렇지 않은 단어를 파악함으로써,

관련이 깊은 단어는 맥락에 더 많이 반영하고, 관련이 적은 단어는 적게 반영하는, 주변의 단어들의 관계에 따라 전체적인 맥락을 이해하려는 과정을 모방한 연산이 어텐션이다. 


1.3 Query, Key, Value

먼저 key-value하면 떠올릴 수 있는 것은 파이썬의 딕셔너리이다. 딕셔너리는 key-value 쌍으로 구성되며, key를 통해서 맵핑된 value를 찾아내는 특징이 있다.

사실 쿼리, 키, 값이라는 용어는 정보 검색 분야에서 유래한 용어이다. 

■ 우리가 검색창에 어떤 내용을 검색할 때, 입력하는 검색어를 '쿼리(query)'라고 한다.

■ 사용자가 query(검색어)를 입력하면 검색 엔진은 수많은 문서 중에서 query(검색어)와 관련 있는 문서를 찾게 된다.

■ 이때, query(검색어)와 관련이 있는지 계산하기 위해 문서가 가진 특징을 이용하는데, 문서가 가진 특징을 '키(key)'라고 한다. key(문서가 가진 특징)는 문서의 제목, 본문, 저자명 등의 요소들이 될 수 있다.

■ 검색 엔진은 query(검색어)와 각 문서의 key(문서 특징) 사이의 관련성을 계산해서 query(검색어)와 관련 깊은 key(문서 특징)를 가진 문서를 찾아 관련도순으로 정렬해서 사용자에게 제공한다.

■ 이때, 사용자에게 제공되는 '문서'가 바로 '값(value)'이다. 즉, 사용자가 검색하여 원하는 결과는 어떤 특정한 value라고 할 수 있다. 

■ 예를 들어, '나는 오늘 블로그 정리를 끝냈다.'라는 문장이 있을 때, '블로그'와 관련된 단어를 찾고자 한다고 해보자. 그렇다면, 이 경우 검색어인 쿼리는 '블로그'이다.

■ 그리고 query(블로그)와 관련이 있는 단어를 찾을 때 key는 문장 속 각 단어들이 key에 해당된다.

- key는 ['나는', '오늘', '블로그', '정리를', '끝냈다']가 된다고 하자.

query(블로그)와 관련이 있는 key를 찾은 경우, 그 key에 연결된 value를 반환하게 된다.

- 이때 value가 단어의 의미를 수치화하여 나타낸 key(문장 속의 각 단어)의 토큰 임베딩 벡터라고 하자.

■ 만약, '블로그'라는 query로  ['나는', '오늘', '블로그', '정리를', '끝냈다']라는 key 묶음에서 query(블로그)와 관련된 key를 찾았다면, 예를 들어 query(블로그)와 높은 관련성을 가지는 key가 '블로그', '정리를', '끝냈다'라고 했을 때

■ 이러한 관련성 계산을 통해 계산된 결과가 이 key들('블로그', '정리를', '끝냈다')에 맵핑된 각각의 value(이 예에서는 임베딩 벡터)가 적절히 섞인 값이 된다면 '블로그', '정리를', '끝냈다'라는 결과는 마치 사람이 단어를 재해석하는 과정을 모방한 것이라고 볼 수 있다.

■ 왜냐하면, value가 적절히 섞인 값이라는 것은, 결국 여러 주변 단어들의 의미가 잘 어우러진 표현이라고 할 수 있으며, 이는 사람이 단어를 재해석하여 얻은 의미와 같다고 볼 수 있기 때문이다.

■ 위의 예시 내용을 key-value 개념을 바탕으로 쿼리, 키, 값에 대한 전체적인 프레임을 그림으로 표현하면 다음과 같다.

Query, Key, Value 프레임


1.4 Attention Mechanism

- 사용자가 원하는 어떤 값을 어텐션 값(Attention Value)이라고 하겠다. 

■ 어텐션 값을 얻는 과정에서는 위의 블로그 예시처럼 쿼리, 키, 값이 사용된다. 이런 과정을 다음과 같이 어텐션 함수로 표현할 수 있다. Attention(Query, Key, Value) = Attention Value

■ 어텐션 값을 구하는 과정은 위의 예시에서 설명한 것처럼, 먼저 쿼리에 대해서 모든 키와의 유사도를 각각 계산한 뒤, 계산한 유사도를 키에 대응되는 각각의 값에 반영한다. 그리고 이렇게 유사도가 반영된 값들을 모두 더한 결과가 어텐션 값이 된다. 이러한 어텐션의 메커니즘을 그림으로 나타내면 다음과 같다.

Attention Mechanism

"쿼리에 대해서 모든 키와의 유사도를 각각 계산"하는 것은, 쿼리가 각 키와 얼마나 관련성이 있는지 측정하는 것이므로, 쿼리와 키를 통해 '어떤 것이 중요한 정보인지'를 수치화하는 단계로 볼 수 있으며,

- "계산한 유사도를 키에 대응되는 각각의 값에 반영"하는 것은, 수치화한 정보를 키에 반영하여 쿼리가 어떤 정보에 집중(Attention)해야 하는지를 알려주는 것이라고 할 수 있다. 

■ 어텐션 개념에서 쿼리와 키의 유사도는 어떤 것이 중요한 정보인지 알려주는 점수로 유사도라는 단어 대신 어텐션 스코어(Attention Score)라고도 부른다.

■ 쿼리와 키는 벡터 혹은 행렬로 나타낼 수 있으며, 이러한 쿼리와 키의 유사도(=어텐션 스코어)를 구하는 방법(위의 어텐션 메커니즘 그림에서 Function에 해당)으로는

- 루옹 어텐션(Luong Attention)이라고도 불리는 닷-프로덕트 어텐션 (Dot-Product Attention)

- 바다나우 어텐션(Bahadanau Attention)이라고도 불리는 애디티브 어텐션(Additive Attention)이 있다. 

■ 계산한 어텐션 스코어는 비교를 위해 총합이 1이 되도록 소프트맥스 함수가 적용된다. 소프트맥스 함수를 통해 얻게 되는 분포를  Attention Distribution 또는 Attention weight라고 부른다. 

■ 즉, 어텐션 스코어를 소프트맥스 함수로 정규화한 결과가 어텐션 가중치이다. 

■ 최종적으로 Query와 Key로부터 얻어진 어텐션 가중치를 이용하여 Value의 가중 합(weighted sum)을 통해 Attention Value가 출력된다.

■ 이러한 어텐션 메커니즘을 Seq2Seq 구조에 적용시키는 것이다.

■ Seq2Seq 구조는 Encoder-Decoder로 구성되며, Decoder에서 최종 출력이 이루어진다. 그리고 최종 출력을 위해 사용되는 것은 입력 정보를 압축한 Hidden State이다. 그러므로 Query를 Decoder의 Hidden State로 생각할 수 있다.

■ 일반적인 Seq2Seq 구조의 문제점은 1.1의 내용처럼 Encoder가 Decoder에 전달하는 은닉 상태는 고정 길이 벡터라서 입력 문장(시퀀스)이 길어도, 항상 동일한 길이(크기)의 벡터가 된다. 즉, 고정된 크기의 벡터에 입력 시퀀스의 정보를 압축하기 때문에 문장이 길어질수록 최종 출력을 하는 Decoder에 전달할 중요한 정보가 누락될 가능성이 크다는 것이었다. 

■ 그러므로 Key는 각 시점(time step)별 입력 시퀀스를 압축한 Encoder의 모든 시점(또는 일부 시점)의 Hidden State가 되어야 한다. 

■ Encoder의 모든 시점(또는 일부 시점)의 Hidden State Vector를 모두 이용한다는 것은 Encoder의 모든 시점의 Hidden State를 Decoder에 전달할 하나의 고정 길이 벡터로 만들지 않고, Encoder의 각 시점별 Hidden State를 사용하는 것이며, 각 시점별 Hidden State에는 입력 시퀀스 길이에 비례한 정보가 인코딩되며, Decoder의 Hidden State에서 이를 참고할 수 있는 구조가 되기 때문이다.

■ 정리하면, Seq2Seq에서 Query는 t 시점의 Decoder의 은닉 상태, Key는 모든 시점(또는 일부 시점)의 Encoder의 은닉 상태이며, 이 Query와 Key를 이용해 어텐션 스코어를 계산한 다음,

계산한 어텐션 스코어를 가중치로 변환시키기 위해 소프트맥스 함수에 통과시켜 총합이 1이며, 0.0 ~ 1.0 사이의 값을 가지는 어텐션 가중치를 얻는다.

■ 이 어텐션 가중치는 Value와 가중 합을 하여 어텐션 값을 얻기 위해 사용된다. 여기서 Value도 모든 시점(또는 일부 시점)의 Encoder의 은닉 상태가 되어야 한다.

■ 그 이유는, 실제로 가져와서 사용하고 싶은 정보는 입력 시퀀스의 각 부분에 대한 정보이기 때문이다. 그러므로 Seq2Seq 구조에서 어텐션 값(Attention Value)는 Context Vector라고 할 수 있다.