데이터 과학 Data Science/자연어처리 NLP

[nlp] Glove 써보기 (세상에서 제일 쉬운 설명)

허니비 honeybee 2023. 1. 21. 00:31

* 이 글은 태생이 문과생인 글쓴이 본인을 이해시키기 위해 초등학생도 이해할 수 있는 쉬운 언어로 바꾸어 작성했습니다. 혹시라도 틀린 부분이 있다면 저보다 멋지신 많은 디지털 노마드님들의 조언 또는 지적 감사히 받겠습니다 

 

 

 

 

오늘은 단어를 벡터화하는 임베딩 방법론 중 하나인 Glove 에 대해 알아보겠다. 

 

 

1. 등장 배경 (word2vec 너 좀 별로다)

 

우선 Glove 는 Word2vec, Fasttext 와 함께 임베딩 방법론의 삼대장으로 자주 거론되는 라이브러리라고 한다. 세 가지 방법론은 각기 다르나 핵심적인 원리는 비슷하다.  임베딩 방식의 이 nlp 방법론들을 공부하는 사람이라면, "CBOW" 와 "skip-gram" 정도는 들어봤을 것이다. CBOW 는 어떤 문장의 중심 단어를 보고 주변 단어를 예측하는 방법이고, skip-gram 은 반대로 주변 단어를 보고 중심 단어를 예측하는 방법이다. 

 

예를 들어, 

 

" 녹차 초콜릿 프라푸치노" (글쓴이의 최애 메뉴) 라는 단어를 학습시키면,

 

CBOW 의 경우

 

__ 초콜릿 ________

 

의 방식으로 학습을, skip- gram 의 경우

 

녹차 ____ 프라푸치노 

 

 

의 방식으로 학습을 진행하게 된다. 이 과정으로 학습할 말뭉치 전체를 돌면서, 쉽게 설명하자면 "어떤 단어 앞뒤에 어떤 단어가 많이 왔는가" 를 학습하고, 함께 출현한 빈도가 높은 단어들을 "비슷한 단어" 취급을 한다는 방법론을 쓴다고 이해하면 되겠다. 

 

그러니까 저런 말뭉치들을 다양하게 학습시키면, 임베딩 방식의 학습법은 기본적으로 "녹차" 와 "초콜릿" 과 "프라푸치노" 를 비슷한 단어라고 학습하게 된다. 

 

그런데 말이지.. Word2Vec 은 기본적으로 임베딩 벡터가 윈도우 크기 내에서만 학습을 진행한다. 이게 무슨 말이냐면 학습을 하는 탐색 범위가 엄청 좁다는거다. 이해를 위해 글쓴이의 개발새발 그림을 첨부하겠다 

 

그림을 보자 (...) 왼쪽은 Word2vec 이 문서를 학습하는 방법이다. 지정된 window의 크기만큼을 고려하여 문서를 학습하고, 또 그 다음 단어로 넘어가 학습하고.. 이 방법을 이용한다. 그렇기 때문에 탐색 범위도 좁고 시간도 엄청 오래 걸린다. 반면Glove 는 한 번 학습에서 문서를 처음부터 끝까지 돌며 학습하고, 그 다음 학습때도 마찬가지다. 그래서 말뭉치의 전체적인 통계 정보를 학습할 수 있다는 엄청난 장점이 있다 

 

좌: Word2Vec 학습법 / 우: Glove 학습법

 

 

 

 

2. 구현 원리 

 

다른 분들 블로그 가서 보세요! 

엄청난 수식들과 함수들... 

 

 

 

3. 그래서 장단점 

 

 

따라서 출현 빈도가 적은 단어에 대해 부정확해지는 단점을 보완할 수 있다. (왜냐면 학습 범위가 전체니까! ) 또 앞서 언급했듯 학습 시간이 빠르다! 이전에는 각 단어별로 좁은 탐지 범위 내에서 학습하고, 다음 단어의 다음 범위를 학습하는 방법을 썼는데, 이 방법은 전체 코퍼스에 대해 단어별로 학습을 진행하기 때문이다. 

 

 

 

 

4. 이제 한 번 써볼까? 

 

 

그러면 이제 한번 Glove 를 써보도록 하겠다. 다른 분들의 블로그를 보니까 사전학습 모델을 많이 쓰는 것 같던데, 기본적으로 당연히 코퍼스는 많을수록 좋고 사전학습은 많이 되면 좋으나, 특수한 상황에 놓인 nlp 를 할 때는 우리의 데이터를 가지고 훈련을 시켜야 한다.. 필자는 지난 시간에 이어 계속 사용하던 카페 메뉴 데이터를 가지고 학습시켜 보도록 하겠다. 

 

필자는 카페 메뉴 데이터 500여개를 가지고 학습시켰다. 1번의 예제에서 살펴본 것 처럼 어떤 메뉴명이나 어떤 메뉴명의 요소 단어를 입력했을 때 어떤 단어가 가장 유사한지 알고 싶다.

 

 

 

4.1 필요 라이브러리 import 

 

fasttext 를 쓸 때는 따로 토큰화를 안 해줘도 알아서 자기가 했으나 얘는 따로 해줘야 한다. 한국어 형태소 분석기인 Konlpy 를 이용해서 먼저 토큰화해주자. 

pip install glove_python_binary
pip install konlpy

from glove import Corpus, Glove
from konlpy.tag import Okt

 

 

이 때! 단어를 토큰화한다는건 이런 뜻이다.. 

 

"녹차 초콜릿 프라푸치노"  -> ["녹차", "초콜릿", "프라푸치노"] 

 

기계는 전자와 같은str 형태로 입력시키면 단 한 건의 학습도 안 해 준 채로 빠꾸를 먹일 것이다.. 형태소 단위나 음절 단위나 뭐 상황에 따라 괜찮은 단위로 잘 잘라서 리스트 형태로 담아서 넣어주자

 

 

4.2. 토큰화 

 

 

제거할 불용어를 리스트에 담아주고 포문을 돌려서 불용어를 제거한 뒤 토큰화를 해 주면 된다. 나의 예제 데이터에는 쓸모없는 (only).. 같은게 들어있어서 저 아이들을 제거하고 토큰화했다

# 불용어 정의
stopwords = ['(only)', "인분"]


# 형태소 분석기 OKT를 사용한 토큰화 작업 (다소 시간 소요)
okt = Okt()

tokenized_data = []
for i in df['MENU_FULL_NM']:
    tokenized_sentence = okt.morphs(i, stem=True) # 토큰화
    stopwords_removed_sentence = [word for word in tokenized_sentence if not word in stopwords] # 불용어 제거
    tokenized_data.append(stopwords_removed_sentence)

 

토큰화를 하면 이런식으로 나온다 

 

아 다시 보니까 & 같은 특수문자도 빼주는게 좋겠다. 제대로 토큰화 된 것들도 있고 아닌 것들도 눈에 보인다. 

 

 

 

 

틀린 것들을 보니까 주로 스위트, 프라페와 같이 영어인데 한국어로 쓰여진 것들인 것 같다. 

 

 

4.3. Corpus 생성

 

말뭉치를 생성하자. 나의 학습 데이터는 매우 작기 때문에 저렇게 했는데, 학습 데이터가 문장이라면 window 를 100 단위로 늘려도 될 것 같다

 

# corpus 생성
corpus = Corpus()
corpus.fit(tokenized_data, window=10)

 

 

 

4.4. 학습

 

 

no_components 파라미터는 를, learning_rate 파라미터는 를 뜻한다.  

 

fit 앞쪽에 매직메서드 %time 을 붙이면 학습시키는데 걸린 시간을 볼 수 있다. 생략해도 됨. 근데 필자는 1초가 걸려서 약간 민망했다. 

# model
glove = Glove(no_components=100, learning_rate=0.05) 

%time glove.fit(corpus.matrix, epochs=50, no_threads=4, verbose=False)   
glove.add_dictionary(corpus.dictionary)

 

 

 

 

 

 

4.5 유사한 단어 찾기

 

 

most_similar 메서드를 쓰면 비슷한 단어를 찾아준다. 

 

흐음.. 기대하던 성능보다 훨씬 떨어지는건 아니지만 아직 뭔가 말뭉치가 적어서 그런지 불용어 제거가 덜 되어 그런건지 만족스럽진 않은 결과가 나와줬다. 비슷하긴 한데 저게 과연 최선일까? 하는 단어들. 나는 아메리카노를 치면 "카페라떼" 라던가, "버블티" 라던가가 반환될것을 기대했는데, 아무래도 단어 단위 학습이었기 때문에 이 방법은 한계가 있었던 듯 하다. 

 

print(glove.most_similar("아메리카노"))

[('월넛', 0.34037335247101097), ('소', 0.32296872365935664), ('아몬드', 0.2771482643417035), ('이다', 0.2542079146708588)]

print(glove.most_similar("라떼"))

[('버블', 0.5284820655650415), ('(', 0.5077608382037931), ('크림', 0.5077576053444117)]

print(glove.most_similar("녹차"))

[('토스트', 0.32370878549981585), ('생강', 0.2800209826023582), ('카츠', 0.27208754828746967), ('미니', 0.2498923434252674)]

 

 

 

 

참고자료

 

다른 분을 보니까 이걸로 k-means  써서 비슷한 문장끼리 묶는 실습도 하신 듯!

https://jxnjxn.tistory.com/49

 

[NLP] 단어부터 문장까지 GloVe Embedding / Clustering

[NLP] 단어부터 문장까지 GloVe Embedding 하기 / Clustering 까지 워드 임베딩 방법론 중 하나인 GloVe에 대해서 직접 임베딩하는 과정을 알아보겠습니다. 단어 단위로 임베딩하고 문장 단위의 임베딩으로

jxnjxn.tistory.com

 

 

728x90
반응형