[기계 번역] 이중 언어 데이터에서의 단어 임베딩 (Bilingual Word Embeddings from Non-Parallel Document Data)

Posted by 적분 ∫2tdt=t²+c
2018.11.30 18:19 그냥 공부

서론

기계 번역은 (사실은 꽤 오래전부터지만) 최근 엄청나게 떠오르고 있는 Hot한 연구 분야입니다. 특히 몇년전 Google이 Google 번역에 딥러닝을 도입하고, 네이버가 파파고를 출시하면서 외국어 공부가 필요없는 세상이 다가오는 것처럼 보이기도 합니다. 기계 번역 분야는 정말 미래가 기대되는 연구 분야라고 할 수 있겠습니다.

딥러닝을 통한 기계 번역 기술의 비약적인 발전에는 단어 임베딩(Word Embedding)이라는 뿌리가 있습니다. 단어 임베딩 기법에 대해서는 예전에 Gaussian LDA를 소개하면서 잠깐 언급한 적이 있습니다. 단어 임베딩이란 각각의 단어를 숫자로 표현하는데, 그 때 그 숫자들이 단어의 의미를 반영할 수 있도록 하는 것이라고 한 줄 요약할 수 있겠지요.

결국 컴퓨터는 모든 데이터를 숫자로 처리하고, 딥러닝과 같은 복잡한 인공신경망도 숫자(입력 신호의 강도)만을 입력받을 수 있으니, 자연언어처리에 딥러닝을 적용하기 위해서는 각 단어들을 적절하게 숫자로 바꿔주는게 필수적입니다. Word Embedding이 중요한 이유라고 할 수 있죠.


언어 중립적인 단어 임베딩의 가능성

기존의 Word2Vec과 같은 기법은 한 언어에 대해서만 단어 임베딩을 진행하는 기법이었습니다. 영어 텍스트를 가지고 학습을 진행한다면 Word2Vec은 텍스트 내의 단어들 간의 관계를 학습하여 Girl-Boy, Woman-Man 등의 관계를 파악할 수 있게 해줍니다. Word2Vec을 통해 각 단어들의 적절하게 숫자로 변환되었으니, 의미가 유사한 단어들은 좌표 상으로도 비슷한 위치에 존재할 것이고, 이를 통해서 다양한 자연언어처리 기법(텍스트 분류, 감성 분석, 개체명 인식, 질문 답변 등등)을 사용할 수가 있습니다.


다만 위와 같이 영어에 대해서 Word Embedding을 사용하고, 그 결과를 바탕으로 감성 분석 모델을 학습했다면, 그 모델은 영어에 대해서만 사용할 수 있습니다. 만약 한국어에 대해서 감성 분석 모델을 학습하고 싶다면, 다시 한국어 텍스트를 모으고, Word2Vec을 돌리고, 그 결과를 바탕으로 한국어 감성 모델을 학습해야하죠.

그런데 곰곰히 생각해보면, 단어 임베딩의 결과로 나타나는 숫자들이 실제 단어의 의미를 반영한다면, 언어에 독립적인 값을 가질 겁니다. (정확히는 단어가 가리키는 어떤 개념을 값으로 가지겠죠.) 예를 들어 덥다-춥다라는 개념 간의 관계는 언어에 상관없이 반의어일 겁니다. 이 개념들 간의 관계는 대부분 언어와는 독립적인 것이고, 각각의 언어들은 이 개념을 다른 어휘로 표현할 뿐이라는 겁니다. 즉, 단어 임베딩의 값은 중립적인 중간 언어(Interlingual)가 될 수 있다는 얘기죠.


우리가 적절한 형태의 중간 언어 임베딩을 구할 수 있다면, 이 임베딩으로 감성 분석 모델(을 비롯한 여러 가지 자연언어처리 모델)을 학습하고, 각각의 개별언어를 중간 언어의 임베딩으로 바꾸어서 이 모델에 넣는 것만으로 감성 분석을 실시할 수 있습니다. 언어 독립적인 감성 분석 모델을 학습할 수 있으니, 개별 언어에 대한 감성 분석 모델을 굳이 만들 필요가 없어집니다. 기계 번역도 아주 간단해지죠. A언어에서 중간 언어로 encoding을 하고, 중간 언어에서 B언어로 decoding해줌으로써 번역을 실시하는게 가능해집니다.


문제는 이 중간 언어의 임베딩을 어떻게 구하느냐겠죠. 여러 가지 기법들이 제시되고 있는데 본 포스팅에서는 다음 논문의 내용을 바탕으로 그 기법들에 대해 살펴보도록 하겠습니다.

Vulić, I., & Moens, M. F. (2015). Bilingual word embeddings from non-parallel document-aligned data applied to bilingual lexicon induction. In Proceedings of the 53rd Annual Meeting of the Association for Computational Linguistics and the 7th International Joint Conference on Natural Language Processing (Volume 2: Short Papers) (Vol. 2, pp. 719-725).


Duong, L., Kanayama, H., Ma, T., Bird, S., & Cohn, T. (2016). Learning crosslingual word embeddings without bilingual corpora. arXiv preprint arXiv:1606.09403.


기존의 방법들

가장 대표적인 기존 방법은 선형 변환(Linear Transform)입니다. Girl-Boy, Woman-Man 같이 개념들 사이의 관계는 어떤 언어에서나 유사할 것입니다. 다만 Word Embedding 기법의 특성 상 코드를 돌릴때마다 각 단어의 임베딩 벡터값은 제멋대로 바뀝니다. (처음 돌렸을때는 Girl을 [0.1, 0.3, -0.4]에 임베딩했는데, 지금 다시 돌려보니 [0.5, -0.2, 0.3]에 임베딩하는 것처럼) 다만 벡터값들은 계속 바뀌어도 단어 들 간의 관계(수학적으로는 각도로 표현됩니다)는 그대로 유지되는게 특징입니다.

단어 임베딩을 학습할 때 마다 각 점의 위치는 매번 바뀝니다. 오직 유지되는 건 점들 간의 각도입니다.

투명 필름에 위 그림이 그려져있다고 상상해보시면 쉽습니다. 오른쪽, 왼쪽 좌표계의 점(Girl, Boy)들 위치는 다릅니다. 하지만 Girl과 Boy 사이의 각도는 유지되므로, 오른쪽 좌표계를 살포시 들어서 잘 돌리고 움직이다 보면 왼쪽 좌표계랑 Girl과 Boy가 같은 위치에 가도록 맞출 수 있을 겁니다. (이 때 맞추는 기준점을 pivot point라고 합니다.) 이렇게 좌표계를 회전시키고 이동시키고 확대시키고 축소시키는 변환들을 모두 통틀어 선형 변환이라고 합니다. 즉 선형 변환을 통해서 서로 다른 단어 임베딩 결과를 합치시킬 수 있습니다.


이는 꼭 같은 언어에 국한되지 않습니다. 양쪽 다 충분히 큰 (같은 도메인 내의) 텍스트를 학습한 경우 Girl-Boy와 같이 주요 개념들 사이의 각도는 언어에 관계없이 거의 유사하게 됩니다. 따라서 한 언어를 기준으로 잡고, 다른 언어의 단어 임베딩 결과를 선형 변환시킴으로써 두 단어의 임베딩을 같은 공간에 위치시킬 수 있습니다.


이 방법의 한계는 pivot point로 삼을 단어 목록이 필요하다는 것입니다. 위의 예시에서는 Girl과 Girl을 일치시키면 됐지만, 서로 다른 언어 사이에서는 Girl-여자애처럼 무엇을 일치시켜야하는지 미리 알고 있어야 올바른 선형 변환이 가능하기 때문이죠. 즉 단어 사전이 필요하다는 건 큰 약점 중의 하나가 되겠습니다.

그리고 실제로 두 언어 간의 단어 임베딩 결과가 선형 변환만으로 완벽하게 일치하기 어려운 경우가 많습니다. 따라서 선형변환만으로는 오차가 커질 수 있기에, 어느 정도 한계가 있는 방법이라고 할 수 있습니다.


더 좋은 방법은 애초에 두 언어의 임베딩을 따로 구한뒤 선형변환으로 힘들게 합치지 말고, 처음부터 두 언어를 같이 넣고 임베딩을 구하는 것이겠죠. 이런 아이디어를 바탕으로 다음과 같은 방법들이 제시됩니다.

단어 사전은 없지만 병렬 코퍼스는 있다

Vulić, I.와 Moens, M. F.는 Word2Vec Skip-gram Negative Sampling을 응용하여 단어 사전이 없이도, 문헌 단위로 정렬된 병렬 코퍼스만 가지고 이중 언어 사이의 단어 임베딩이 가능함을 보였습니다. 문헌 단위로 정렬되었다는 말의 의미는 S언어로 된 문헌 D1_s가 있고, 이 문헌이 T언어로 번역된 D1_t가 있는 것을 말합니다. 이렇게 짝을 이룬 문헌쌍이 무수히 많을 경우, 다음과 같이 간단한 방법으로 Bilingual Word Embedding이 가능합니다.
  1. 모든 문헌쌍에 대하여(i는 문헌쌍의 일련번호) 다음을 반복한다
  2. S언어로 된 문헌 Di_s와 T언어로 된 문헌 Di_t의 모든 단어들을 가져온다.
  3. 2에서 가져온 단어들을 합쳐서 마구 뒤섞어 문헌 Di_u를 만든다. (즉 Di_u에는 Di_s, Di_t의 단어들이 무작위로 섞여 있을 겁니다.)
  4. Di_u를 Word2vec SGNS의 입력으로 넣어 임베딩을 학습한다. (이때 context window 크기를 충분히 크게 주는게 포인트)
마구 뒤섞는게 조금 어이 없어 보이기도 하겠지만, 사실 이 방법은 굉장히 간단하면서도 현명한 해결책입니다. 이론적으로 두 언어 사이의 단어 임베딩을 학습하기 위해서는 S언어의 단어 Vs와 이에 대응하는 T언어의 단어 Vt가 같은 context에 들어가도록 해야합니다. 그렇지만 우리에게 주어진 것은 오직 S언어와 T언어 사이에 대응하는 문헌쌍만 있을뿐, 더 자세한 정보는 없는 상황이지요. 따라서 S언어의 문헌과 T언어의 문헌을 합쳐서 마구 섞고, context window를 충분히 크게 주면 단어 Vs에 대응하는 Vt가 context 안에 들어갈 확률이 높아집니다.

그리고 이런 문헌쌍의 수가 충분히 많다면 Word2Vec은 여기에서 단어들 간의 관계를 충분히 학습해낼 수 있습니다. 간단한 방법이지만, Bilingual Lexicon Induction(어휘사전 추론 문제)에서 평균 58%의 성능을 보이며 기존 방법들을 앞지른 기법입니다. 논문에서는 에스파냐어-영어, 이탈리아어-영어, 독일어-영어를 가지고 실험했는데, dimension은 200~300, context window는 16~48일때 좋은 성능을 보인것을 확인되었습니다.

병렬 코퍼스는 없지만 단어 사전은 있다

이번에는 거꾸로 병렬 코퍼스는 없지만, 단어 사전은 가지고 있는 경우입니다. 사실 병렬 코퍼스보다는 단어 사전 쪽이 데이터를 구하기가 더 쉽습니다. Duong은 병렬 코퍼스는 없고 하나의 언어로만 된 코퍼스들만 가지고 있는 경우, 단어 사전을 활용하여 두 언어를 한 공간에 Word Embedding하는 기법을 제안했습니다.

복잡해보이는 수식이지만 α=1인 경우 Word2Vec의 Negative Sampling과 동일한 목적함수입니다. 가운데 추가된 (1-α)로 시작하는 항이 이 논문의 아이디어인데요, 말로 풀어쓰자면, 단어의 i의 context로 i 주변의 단어들뿐만 아니라, 어휘사전에서 i와 대응하는 외국어 어휘도 context로 고려하겠다는 겁니다. Vulic의 경우 외국어 어휘를 context에 포함하기 위하여 병렬 코퍼스를 합쳐서 마구 섞었다면, 여기서는 단어 사전에서 어휘를 찾아서 그걸 context에 넣어준 것이라고 할 수 있겠습니다.


단 단어 사전을 이용할 때는 동음이의어, 유의어 등이 문제가 됩니다. 예를 들어 한국어 단어 사전의 경우 '눈'에 eye와 snow가 모두 들어가 있을 겁니다. 이 경우 한국어 단어 '눈'이 등장했을 경우 이에 대응하는 외국어 단어 무엇을 context에 넣어야할지 고민이 됩니다. 무책임한 해결책은 랜덤으로 아무 단어나 넣는 것이겠지만 (이 경우에도 어느 정도 성능이 나오긴 합니다), 더 좋은 것은 맥락에 알맞는 외국어 어휘를 고르는 것입니다. Duong은 EM 알고리즘의 아이디어를 활용하여, O를 최대화하는 외국어 단어를 고르고, 그 때의 오차를 줄이는 학습 과정을 추가함으로써 적절한 외국어 단어를 고를 수 있게 하였습니다.


여기에 추가적으로 in 공간의 벡터만 사용하는 것이 아니라, in-공간의 벡터와 out-공간의 벡터를 모두 활용하여 유사도를 계산하는 것으로 성능을 더욱 끌어올렸습니다. 최종적으로 BLI 실험 결과 에스파냐어-영어, 이탈리아어-영어, 독일어-영어 평균 76%의 성능을 기록하였습니다.


2016년에 나온 Duong의 기법이 Vulic의 기법을 앞질렀지만, 사실 두 방법은 어느 하나가 다른 방법보다 뛰어나고, 다른 하나는 뒤떨어졌다고 말할 수 있는 관계가 아닙니다. 오히려 가용한 데이터에 따라 둘 중 하나를 골라 사용할 수 있는 상보적인 관계에 놓여있다고 볼 수 있겠습니다.


나도 실험해볼거야!

재미있어보이는 논문들이라 열심히 읽고 나서 실험해보고 싶어졌습니다. 다행히 저도 문헌 단위로 정렬된 병렬 코퍼스가 있어서, Vulic의 방법을 구현해보기로 했습니다. 단 아예 똑같이 구현하지는 않았고, 양쪽 언어의 문헌쌍을 합칠때 S언어와 T언어 각각의 context는 유지되도록 하고, 서로 다른 언어간 context window만 섞이도록 구현했습니다.

데이터는 라틴어 성경-한국어 성경이고, 정렬 단위는 완전 문헌은 아니고 장과 절입니다. 약 3만 쌍 단위를 형태소 분석, lemmatization하여 불용어 제거하고 입력 데이터로 사용했습니다.

Dimension = 200, windowSize = 4, crossWindowSize = 5, negativeSamples = 10로 설정하고 총 100 epochs(샘플 데이터가 워낙 작아서...)를 돌렸어요.


라틴어 단어의 경우 총 5536개, 한국어 단어의 경우 총 5630개가 나와 전체 Vocab의 Size는 11166개입니다. 다음은 몇개의 샘플을 입력으로 넣었을때 가장 유사한 단어(라틴어, 한국어 가릴것 없이) 상위 5개를 출력한 결과입니다.


deus*dico*Abraham*omnis*
하느님말하다아브라함모든
dominus*aio*Isaac*모두
주님말씀하다사악universus*
ergo*

사라

그리고
그분loquor*Lazarum*오다

임신하다Cain*nos*nubo*
concipio*카인우리장가들다
Liam*Abel*noster*시집가다
sterilis*아벨저희혼인하다
Onan*곱절deus*iunior*
pario*septuplum*하느님Maala*


*표가 붙어있는게 라틴어 단어이고, 굵게 처리된 것이 올바른 번역입니다. 보시다시피 라틴어 단어와 한국어 단어가 결과에 섞여나오는데, 상위권에 라틴어에 대응하는 한국어 단어(혹은 그 반대)가 등장하는 것을 볼 수 있습니다. 정렬 단위가 문헌보다 좀더 작은 장/절 단위라서 성능이 잘 나오는것 같네요.


의외로 쉽게 라틴어-한국어 사이의 단어 임베딩 결과를 얻어냈는데, 이를 바탕으로 라틴어 사전의 표제어들을 보충할 수도 있을 것 같고, 다양한 방면에 써먹기 좋을것 같습니다.

이 댓글을 비밀 댓글로