2025년, 코딩은 선택이 아닌 필수!

2025년 모든 학교에서 코딩이 시작 됩니다. 먼저 준비하는 사람만이 기술을 선도해 갑니다~

머신러닝/12. 딥러닝챗봇

[딥러닝챗봇]임베딩

파아란기쁨1 2022. 6. 17. 10:43
반응형

1.임베딩이란?

컴퓨터는 자연어를 직접 처리할 수 없고 수치연산만 가능하기 때문에 자연어를 숫자나 벡터형태로 변환을 해야 합니다.

이런 일련과정을 자연어 처리 분야에서는 임베딩(embedding)이라고 합니다.

즉, 임베딩은 단어나 문장을 수치화해 벡터공간으로 표현하는 과정을 의미합니다.

 

2. 단어 임베딩

단어임베딩은 말뭉치에서 각각의 단어를 벡터로 변환하는 기법을 의미합니다.

토크나이징을 통해 추출된 토큰들을 어떻게 단어 임베딩하는지 알아 보겠습니다.

 

2.1 원-핫 인코딩

원-핫 인코딩(one-hot encoding)은 단어를 숫자 벡터로 변환하는 가장 기본적인 방법입니다. 명칭에서도 알 수 있듯이 요소들 중 단 하나의 값만 1이고 나머지 요소값은 0인 인코딩을 의미합니다.(단 하나의 값만 1이기 때문에 희소(Sparse) 벡터라고도 합니다.)

 

원-핫 인코딩을 하기 위해서는 단어집합이라 불리는 사전을 먼저 만들어야 합니다.

다음의 예를 보겠습니다.

 

코랩에서 konlpy 에러시 다음과 같이 설치

%%bash
apt-get update
apt-get install g++ openjdk-8-jdk python-dev python3-dev
pip3 install JPype1
pip3 install konlpy

 

from konlpy.tag import Komoran
import numpy as np

komoran = Komoran()
text = "오늘 날씨는 구름이 많아요."

#명사만 추출
nouns=komoran.nouns(text)
print(nouns)

#단어 사전 구축 및 단어별 인덱스 부여
dics={}
for word in nouns:
  if word not in dics.keys():
    dics[word]=len(dics)

print(dics)

#원-핫 인코딩
nb_classes=len(dics) #원핫 인코딩 벡터의 차원의 크기를 결정
targets=list(dics.values()) #딕셔너리 타입을 리스트 형태로 변환 이때 value 값만 추출
one_hot_targets=np.eye(nb_classes)[targets] #넘파이의 eye 함수를 이용하여 원핫 벡터를 만들자.
print(one_hot_targets)

출력결과를 살펴보면 다음과 같다.

원핫인코딩한 결과 오늘: 0, 날씨: 1, 구름: 2 와 같이 숫자로 변환 후 원핫벡터 생성하면 위와 같이 나타난다.

 

이 때 원-핫 벡터의 경우 단순히 단어의 순서에 의한 인덱스 값을 기반으로 인코딩 된 값이기 때문에 단어의 의미나 유사한 단어의 관계를 담고 있지 않다.

또한 단어 사전의 크기가 커짐에 따라 원-핫 벡터의 차원도 커지는데 이때 메모리 낭비와 계산의 복잡도가 커진다.

 

2.2 희소표현과 분산표현

위에서 원-핫 인코딩을 하면 단어의 인덱스 요소만 1이고 나머지 요소는 모두 0으로 표현되는 희소벡터이다. 이러한 희소벡터를 희소표현이라 부른다.

이러한 희소표현은 자연어 처리를 잘 하기 위해서는 기본 토큰이 되는 단어의 의미와 주변 단어 간의 관계가 단어 임베딩에 표현 되어야 하는데 이러한 처리를 할 수가 없다.

이를 해결하기 위해 분산표현이 고안 되었는데~

분산표현은 한 단어의 정보가 특정 차원에 표현되지 않고 여러 차원에 분산되어 표현된다.

예) 오늘 : 희소표현[1,0,0],분산표현[-0.233,0.692,0.103]

이렇게 표현되면 더이상 희소희자 않고 신경망에서는 분산표현을 학습하는 과정에서 임베딩 벡터의 모든 차원에 의미 있는 데이터를 고르게 밀집 시킨다.

이 때문에 희소표현과는 다르게 벡터 차원의 압축이 가능해 지며 이렇게 차원에 데이터를 밀집 시킬 수 있어 밀집표현이라고도 한다.

 

이러한 분산표현 방식은 다음과 같은 2가지 장점을 갖게 된다.

1. 임베딩 벡터의 차원을 데이터 손실을 최소화 하면서 압축할 수 있다.

2. 임베딩 벡터에는 단어의 의미,주변 단어간의 관계등 많은 정보가 내포되어 있다. 예를 들면 '남자'와 '남성'이라는 단어를 보면 희소표현에서는 단순히 남자와 남성의 요솟값에 불과하다. 하지만 분산표현에서는 벡터 공간상에서 유사한 의미를 갖는 단어들은 비슷한 위치에 분포 되기 때문에 남자와 남성은 매우 가까운 위치에 있게 된다.

 

2.3 Word2Vec

챗봇의 경우 많은 단어를 처리 하면서 단어 간 유사도롤 계산 할 수 있어야 좋은 성능을 낼 수 있는데 원-핫 인코딩 기법은 처리 할 수가 없다. 따라서 분산표현 방식을 사용할 것인데 대표적인 모델로 Word2Vec 가 있다.

 

Word2Vec 은 2013년 구글에서 발표했고 가장 많이 사용하고 있는 단어 임베딩 모델이다.

Word2Vec은 CBOW(continuous bag og words)와 skip-gram 두가지 모델로 제안되었다.

 

CBOW 모델은 맥락이라 표현된느 주변 단어들을 이용해 타깃 단어를 예측하는 신경망 모델이다. 신경망의 입력을 주변단어들로 구성하고 출력을 타깃 단어로 설정해 학습된 가중치 데이터를 임베딩 벡터로 활용한다. skip-gram 모델은 CBOW모델과 반대로 하나의 타깃 단어를 이용해 주변 단어를 예측하는 모델이다.

 

CBOW 모델

오늘 _ 는 구름이 많아요

주변단어로 타깃단어 예측

skip-gram

_ 날씨는 _ 이 많아요

주변단어 예측

 

 

windosw size=2 인경우 주변 단어를 앞뒤 단어 2개까지 모델 학습을 위해 사용한다.

  • 예문 : "The fat cat sat on the mat"

파이썬을 이용해 Word2vec을 실습하기 전에 한국어 말뭉치를 수집하자.

github.com/e9t/nsmc 에서 다운로드 할 수 있다.

 

from gensim.models import Word2Vec
from konlpy.tag import Komoran
import time

#네이버 영화 리뷰 읽어옴
def read_review_data(filename):
  print(filename)
  data=[]
  with open(filename,'r') as f:
    data = [line.split('\t') for line in f.read().splitlines()]
    data = data[1:] #헤더 제거
    #for word in line:
    #  data.append(word.split())
  return data

#학습시간 측정
start = time.time()

#리뷰파일 읽어오기
print('1) 말뭉치 데이터 읽기 시작')
review_data = read_review_data('rating.txt')
print(len(review_data)) #리뷰데이터 전체 개수
print('1) 말뭉치 데이터 읽기 완료',time.time()-start)

#문장 단위로 명사만 추출해 학습 입력 데이터로 만듦
print('2) 형태소에서 명사만 추출시작')
komoran = Komoran()
docs=[komoran.nouns(sentence[1]) for sentence in review_data]
print('2) 형태소에서 명사만 추출 완료',time.time()-start)

#Word2Vec 모델 학습
print('3) Word2Vec 모델학습시작')
model = Word2Vec(sentences=docs,size=200,window=4,hs=1,min_count=2,sg=1)
print('3) Word2Vec 모델학습 완료',time.time()-start)

#모델저장
print('4) 학습된 모델 저장 시작')
model.save('nvmc.model')
print('4) 학습된 모델 저장 완료',time.time()-start)

#학습된 말뭉치 수, 코퍼스 내 전체 단어수
print('corpus_count : ',model.corpus_count)
print('corpus_total_words : ',model.corpus_total_words)

다운 받은 파일로 실행 했을때 'utf-8' codec can't decode bytes in position 1048574-1048575: unexpected end of data' 에러 발생해서 텍스트 파일을 살펴 보니 마지막 부분이 잘못 되어 있었음

마지막 부분 삭제 후 재 저장후 업로드 후에 정상 실행 됨

129935 개의 명사를 추출했고 68만개 정도의 단어 임베딩을 처리할 수 있는 Word2Vec 모델을 학습하였다.

모델이 생성 된것을 확인 할 수 있다.

 

이제 생성된 Word2Vec 모델 파일을 읽어와서 실제로 단어 임베딩된 값과 벡터 공간상의 유사한 단어들을 확인하는 예제를 살펴 보자.

from gensim.models import Word2Vec

#모델로딩
model = Word2Vec.load('nvmc.model')
print('corpus_total_words : ',model.corpus_total_words)

#'사랑'이란 단어로 생성한 단어 임베딩 벡터
print('사랑 : ',model.wv['사랑'])

#단어 유사도 계산
print("일요일 = 월요일 \t", model.wv.similarity(w1='일요일',w2='월요일'))
print("안성기 = 배우 \t", model.wv.similarity(w1='안성기',w2='배우'))
print("대기업 = 삼성 \t", model.wv.similarity(w1='대기업',w2='삼성'))
print("일요일 != 삼성 \t", model.wv.similarity(w1='일요일',w2='삼성'))
print("히어로 != 삼성 \t", model.wv.similarity(w1='히어로',w2='삼성'))

#가장 유사한 단어 추출
print(model.wv.most_similar("안성기",topn=3))
print(model.wv.most_similar("시리즈",topn=3))

 

 

 

 

[참고]

한빛미디어 - 처음 배우는 딥러닝 챗봇

https://github.com/keiraydev/chatbot

 

GitHub - keiraydev/chatbot: 한빛미디어 처음 배우는 딥러닝 챗봇

한빛미디어 처음 배우는 딥러닝 챗봇. Contribute to keiraydev/chatbot development by creating an account on GitHub.

github.com

 

 

반응형