사전 훈련된 단어 임베딩 이용하기
5장에서 뒤에 단어 임베딩을 학습하는 CBOW 모델에 대해 간략하게 공부할 예정이지만, 실질적으로 우리가 새로운 단어 임베딩 학습 알고리즘을 만들 일은 거의 없기 때문에, 기존에 잘 만들어진 단어 임베딩을 가져와 모델에 적용하는 방법에 대해 알아볼 것입니다.
인터넷에 무료로 공개되어있는 다양한 단어 임베딩 중, 스탠포드 대학교의 GloVe 임베딩을 이용해보겠습니다.
GloVe 임베딩 다운받기
Google Colab에서 단어 임베딩 파일 로드하기
Colab을 기준으로 설명하겠습니다. 우선, annoy 라이브러리를 설치해줍니다. annoy 라이브러리는 Approximate Nearest Neighbors Oh Yeah 의 줄임말로, 공간 내에서 가장 가까운 벡터를 찾는 알고리즘입니다. 실제로 spotify 에서 음악을 추천할 때 활용되어지는 라이브러리 입니다.
!pip install annoy
Python
복사
아래 코드와 같이, PreTrainedEmbeddings를 정의해줍니다.
import numpy as np
from annoy import AnnoyIndex
class PreTrainedEmbeddings(object):
def __init__(self, word_to_index, word_vectors):
self.word_to_index = word_to_index
self.word_vectors = word_vectors
self.index_to_word = {v: k for k, v in self.word_to_index.items()}
self.index = AnnoyIndex(len(word_vectors[0]), metric = 'euclidean')
for _, i in self.word_to_index.items():
self.index.add_item(i, self.word_vectors[i])
self.index.build(50)
# 단어를 입력하면 단어 임베딩 값(행렬값)을 출력
def get_embedding(self, word):
return self.word_vectors[self.word_to_index[word]]
# 벡터를 입력하면 가장 가까운 벡터를 하나 찾음
def get_closest_to_vector(self, vector, n=1):
nn_indices = self.index.get_nns_by_vector(vector, n)
return [self.index_to_word[neighbor]
for neighbor in nn_indices]
# 단어 3개를 입력하면, word1, word2와 동일한 관계를 갖는 word3의 단어쌍 word4를 찾아서 출력
def compute_and_print_analogy(self, word1, word2, word3):
vec1 = self.get_embedding(word1)
vec2 = self.get_embedding(word2)
vec3 = self.get_embedding(word3)
spatial_relationship = vec2 - vec1
vec4 = vec3 + spatial_relationship
closest_words = self.get_closest_to_vector(vec4, n=4)
existing_words = set([word1, word2, word3])
closest_words = [word for word in closest_words
if word not in existing_words]
if len(closest_words) == 0:
print("계산된 벡터와 가장 가까운 이웃을 찾을 수 없습니다!")
return
for word4 in closest_words:
print("{} : {} :: {} : {}".format(word1, word2, word3, word4))
@classmethod
def from_embeddings_file(cls, embedding_file):
word_to_index = {}
word_vectors = []
with open(embedding_file) as fp:
for line in fp.readlines():
line = line.split(" ")
word = line[0]
vec = np.array([float(x) for x in line[1:]])
word_to_index[word] = len(word_to_index)
word_vectors.append(vec)
return cls(word_to_index, word_vectors)
Python
복사
이제, 다운로드한 GloVe 파일을 이용해 학습을 진행하면 잘 훈련된 단어 임베딩을 우리도 사용할 수 있습니다.
embeddings = PreTrainedEmbeddings.from_embeddings_file(file_name)
Python
복사
몇 가지 재미있는 예시를 살펴보겠습니다.
compute_and_print_analogy 메서드를 통해 3가지 단어를 입력했을 때 word1, word2의 관계와 동일한 관계를 갖는 word3의 쌍, word4를 출력해볼 수 있습니다.
embeddings.compute_and_print_analogy('man', 'he', 'woman')
>>> output
man : he :: woman : she
embeddings.compute_and_print_analogy('fly', 'plane', 'sail')
>>> output
fly : plane :: sail : ship
embeddings.compute_and_print_analogy('cat', 'kitten', 'dog')
>>> output
cat : kitten :: dog : puppy
embeddings.compute_and_print_analogy('blue','color', 'dog')
>>> output
blue : color :: dog : pets
embeddings.compute_and_print_analogy('food', 'delicious', 'cat')
>>> output
food : delicious :: cat : adorable
Python
복사
위 예시에서 man을 he라고 한다면 woman은 she라고 한다는 것을 잘 파악하고 있습니다.
blue가 color에 포함된다는 관계를 잘 이해하고 dog가 pets에 포함된다고 출력하는 것도 볼 수 있습니다.
food가 delicious하다고 할 때, cat은 adorable하다고 하며, 수식 관계도 잘 파악하고 있음을 알 수 있습니다.
물론 프로그램이 이 단어들의 의미와 관계를 모두 알고 이러한 결과를 내는 것은 아닙니다. 학습 과정에서 단어들이 자주 같이 등장할 수록 단어끼리의 유사도가 높다고 판단하며 임베딩 벡터 공간 내에서 유사한 의미를 갖도록(가까운 거리를 갖도록) 단어들을 배치합니다. 데이터를 통해 학습하면서 단어 벡터간의 거리를 계속 조정하여 데이터들을 가장 잘 나타내는 위치에 두게 되고, 이를 바탕으로 단어 간의 관계를 출력하게 됩니다.
그러나, 이러한 임베딩을 사용할 때는 주의해야 하는 부분이 하나 있습니다. 인터넷이나 문서화된 글들을 학습데이터로 활용하기 때문에, 인터넷 글 등에 포함되어 있는 전반적인 언어사용자들의 고정관념이나 편견이 임베딩 과정에 반영되어 나타날 수 있습니다. 아래의 예시처럼 학습 데이터속 편견에 의해 나타나는 man-doctor / woman-nurse 와 같은 편향성에 유의해야 합니다.
embeddings.compute_and_print_analogy('man', 'doctor', 'woman')
>>> output
man : doctor :: woman : nurse
man : doctor :: woman : pregnant
Python
복사
이러한 편향성을 어떻게 제거해야 할 것인가 역시 NLP 분야가 떠오르면서 함께 주목받고 있는 흥미로운 연구 분야 중 하나입니다.
이전 글 읽기
다음 글 읽기