Sequence to Sequence 모형
기본적인 뉴럴 네트워크는 함수 $f(x)$를 근사하는 것이라고 보면 된다. 입력을 원하는 출력으로 매핑하는 것이다. 예컨대 입력이 이미지라면 입력 이미지가 개인지 새인지 하는 것을 출력하는 함수를 뉴럴 네트워크로 근사하는 것이다. 그런데 생각해보면 함수에 입력하는 변수의 크기는 정해져 있다. 즉 $f(x)$ 함수는 $x$에 대한 함수이지 $x$와 $y$에 대한 함수로 확장할 수는 없는 것이다. 이게 왜 문제가 될까?
문장을 번역한다고 할 때 입력이 되는 문장의 길이는 그때그때 다를 것이다. 단어가 열 개일 수도 있고 스무 개일 수도 있다. 따라서 영어 문장을 입력으로 받아 한국어 문장을 출력하는 함수는 가변 길이 입력에 대해 적용할 수 있어야 한다. 어떻게 해야 할까?
Recurrent Neural Network는 이를 Recursion과 상태(state)를 도입하는 방법으로 해결했다. RNN은 다음과 같은 함수이다:
\[ h_t = f(x_t, h_{t - 1}) \]
여기서 $h_t$는 $t$ 시점의 상태이고 $x_t$는 $t$ 시점의 입력이다. 즉 $t$ 시점의 상태는 이전 시점 $t-1$의 상태와 현재 입력에 의해 결정되는 것이다. 즉 단어 1, 단어 2, 단어 3에 대해서 RNN은 다음과 같이 작동한다:
\[ h_1 = f(\text{단어 1}, h_0) \\ h_2 = f(\text{단어 2}, h_1) \\ h_3 = f(\text{단어 3}, h_2) \\ (h_0 = \mathbf{0}) \]
즉 마지막 상태 $h_3$는 모든 입력 단어 1, 단어 2, 단어 3을 RNN이 "보고 난" 이후 결정되는 것이다. 따라서 $h_3$는 입력에 모두에 대한 정보를 (상태의 크기가 충분하다고 하면) 갖게 된다.
자, 이제 이런 함수로 어떻게 문장을 번역할 수 있을까?
위와 같은 RNN에 영어 문장을 입력했다고 해보자. 그렇다면 영어 문장을 입력으로 받은 RNN의 최종 상태 $h_t$는 영어 문장에 대한 충분한 정보를 갖고 있을 것이다. 이런 RNN을 입력을 특정한 상태 벡터로 인코딩한다고 해서 인코더라고 부른다. 이제 인코더가 인코딩한 상태 $h_t$를 인코딩된 벡터를 복원하는 디코더에 입력한다. 디코더 RNN이 인코더가 인코딩한 영어 문장을 한국어 문장으로 디코딩하는 것이다. 디코딩은 언어 모델이라는 방식에 기반한다. 잠깐 언어 모델이 무엇인지 설명해보자면 다음과 같다.
문장을 단어의 시퀀스로 보면 단어들에 기반해서 문장에 확률을 부여할 수 있다. 예를 들어 뉴럴넷은 위대하다라는 문장이 있다고 하자. 그렇다면,
\[ P(\text{뉴럴넷}, \text{은}, \text{위대}, \text{하다}) \]
위와 같은 확률을 생각할 수 있다. 재미있는 것은 위의 확률을 다음과 같이 분해할 수 있다는 것이다.
\[ P(\text{뉴럴넷})P(\text{은}|\text{뉴럴넷})P(\text{위대}|\text{뉴럴넷}, \text{은})P(\text{하다}|\text{뉴럴넷}, \text{은}, \text{위대}) \]
이 구조를 잘 보면 이전 단어들에 대한 다음 단어의 조건부 확률을 구하는 방식으로 전체 문장의 확률을 계산할 수 있다는 의미라는 것을 알 수 있다. 이를 디코더에 어떻게 적용할 수 있을까? 인코딩된 상태 $h_t$에 대해서 다음 한국어 단어의 확률을 계산하는 RNN을 학습시키면 상태 $h_t$에 대해 가장 확률이 높은 한국어 문장을 생성할 수 있다는 것이다. 이 문장이 곧 입력 영어 문장에 대한 번역 한국어 문장이 된다.
가변 길이 문장을 제한된 크기의 상태로 인코딩한다는 것이 사실상 불가능하기 때문에 실제로 사용되는 모형에서는 주의(Attention) 같은 메커니즘을 도입한다. 하지만 입력 문장을 어떤 상태로 인코딩해서, 인코딩된 상태를 다시 디코딩하는 방식으로 동작한다는 작동 방식은 기본적으로 동일하다. 인코더-디코더가 이런 식으로 연결된 모델을 Sequence to Sequence 모델이라고 부르며 GNMT는 사실상 이 모델을 충분히 크고 정교하게 만든 것이라고 볼 수 있다.
Sequence to Sequence (출처: https://www.tensorflow.org)
Google’s AI translation tool seems to have invented its own secret internal language
그렇다면 위의 글에서 뉴럴넷이 내부 언어를 만들어냈다는 것의 의미는 무엇일까? 구글은 최근 GNMT를 단순히 영어-한국어 같은 두 언어 페어 사이의 번역 대신 하나의 모델로 영어, 일본어, 한국어 등 다양한 언어 사이의 번역이 가능하도록 확장했다. 논문은 [[https://arxiv.org/abs/1611.04558]]에 있다. 어떻게 했냐면 인코더에 입력을 주면서 어떤 언어로 번역해야 할지를 같이 입력으로 준 것이다. 예를 들면 "<영어로> 뉴럴넷은 위대하다"라고 입력한 것이다. 그랬더니 다양한 언어 사이의 번역이 가능해졌다. 단순하지 않은가? 뉴럴넷 연구자인 Andrej Karpathy도 이 아이디어가 당황스러웠던 모양이다.
(출처: https://twitter.com/karpathy/status/798806811360960512)
이런 식으로 뉴럴넷을 학습시켰더니 놀랍게도 일본어를 영어로 번역하는 방법을 학습하고, 영어를 한국어로 번역하는 방법을 학습했더니 일본어를 한국어로 번역하는 방법은 학습하지 않았는데도 번역할 수 있게 된 것이다. 대체 어떻게?
정확히 어떤 일이 벌어지고 있는지는 알기 어렵다. 하지만 몇가지 분석을 통해 벌어지고 있는 일을 추측해볼 수는 있다. 아마도 뉴럴넷은 구체적인 언어와는 별개로 의미가 유사하다면 유사한 방식으로 문장을 인코딩하는 것일 수 있다. 즉 일본어 문장 A의 의미를 $a$로 인코딩한 다음 $a$를 통해 영어로 번역하고, 영어 문장 A의 의미를 $a$로 인코딩한 다음 한국어로 번역한다면, 일본어 문장 A가 들어오면 스위치를 영어 대신 한국어로 바꾸어도 여전히 의미를 $a$로 인코딩한 다음 한국어로 번역할 수 있는 것이다. 그렇게 뉴럴넷은 아마도 언어에 공통된 내적 언어를 학습한 것일 수 있다.
그렇지만 반드시 이런 현상만 일어나는 것은 아니고 예컨대 포르투갈어 -> 영어, 영어 -> 스페인어에 대해서 학습된 모델이 포르투갈어 -> 스페인어에 대해선 다른 방식으로 인코딩하는 현상도 관찰되었다. 대체 뉴럴넷이 무슨 일을 하고 있는지 종잡을 수는 없다. 그렇지만 뭔가 희한한 일이 일어나고 있다는 건 분명해 보인다.
또 다양한 언어에 대해 학습시켰기 때문에 이런 것도 가능하다.
늘 잘 되는 건 아니라지만 입력 언어를 섞어도 번역을 해낼 수 있다는 것이다. 하다가 생각이 났는지 다음과 같은 장난(?)도 했다.
<일본어로> 혹은 <한국어로> 대신 0.3<일본어로> + 0.7<한국어로>라고 입력해서 번역 결과를 출력한 것이다. 저자들은 일본어와 한국어를 섞은 중간 언어가 튀어나오길 기대했으나 그렇지는 않아서 아쉽다(?)고 말하고 있다. 그렇지만 뭔가 뉘앙스의 차이는 있는 것 같고 그게 일본어와 한국어를 섞는 과정에서 발생한 것일 수도 있다.