본문 바로가기
FullStack/50. ML

[BOOK] 처음 배우는 딥러닝 챗봇 #2 임베딩

by nakanara 2023. 1. 25.
반응형

임베딩

컴퓨터는 자연어를 직접적으로 처리할 수가 없으며, 수치 연산만 가능하기 때문에 자연어를 숫자나 벡터 형태로 변환 필요. 이런 과정을 자연어 처리 분야에서는 임베딩(embedding)이라고

  • 임베딩: 단어나 문장을 수치화해 벡터 공간으로 표현하는 과정

임베딩은 말뭉치의 의미에 따라 벡터화하기 때문에 문법적 정보 포함, 임베딩 품질에 따른 결과 차이가 큼

임베딩에는 문장 임베딩과 단어 임베딩 존재하며, 문장 임베딩은 전체 문장을 벡터로 관리, 단어 임베딩은 개별 단어를 벡터로 표현

  • 문장 임베딩: 문맥적 의미를 지니는 장점, 품질이 좋음, 상용 시스템에 많이 사용, 학습 비용 큼
  • 단어 임베딩: 동음이의어 대한 구별 하지 않음, 의미가 다르더라도 단어의 형태가 같다면 동일한 값으로 취급, 학습 방법 간단

단어 임베딩

원-핫 인코딩

원-핫 인코딩(one-hot encoding)은 숫자를 벡터로 변환하는 기본적인 방법, 개발 단어의 요소가 하나의 고유 값을 가짐, 전체 요소 중 단 하나의 값만 1이기 때문에 희소(sparse) 벡터

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()) # 사전을 리스트 유형으로 변경
one_hot_targets = np.eye(nb_classes)[targets] # eye함수를 이용하여 단위 행렬 구조로 생성
print(one_hot_targets)

원-핫 인코딩의 경우 간단한 구현 방법에 비해 좋은 성능을 가지기 때문에 많이 사용하지만, 단어의 의미나 관계 정보를 가지고 있지 않습니다. 또한 단어 사전의 크기가 커짐에 따라 벡터도 함께 증가하는데, 이점에서 메모리 낭비와 계산의 복잡도가 증가

희소 표현과 분산 표현

원-핫 인코딩은 표현하고자 하는 단어의 인덱스 요소만 1이고 나머지 요소는 모두 0으로 표현하는 희소 벡터(= 희소 행렬)입니다. 이처럼 단어가 희소 벡터로 표현되는 방법을 희소 표현(Sparse Representation)이라고 부름, 희소 표현은 각각의 차원이 독립적인 정보를 지니고 있어 사람이 이해하기에 직관적인 장점은 있지만, 단어 사전의 크기가 커질수록 메모리 낭비와 계산 복잡도가 커지는 단점, 단어 간 연관성이 전혀 없어 의미를 담을 수 없음

작연어 처리를 위해 기본 토큰이 되는 단어의 의미와 주변 단어 간의 관계가 단어 임베딩에 표현되어야 하지만, 희소 표현의 경우 불가능하여, 단어 간의 유사성을 표현하면서 벡트 공간을 절약할 수 있는 방법으로 분산 표현(Distributed Representation) 탄생

분산 표현은 한 단어의 정보가 특정 차원에 표현되지 않고, 여러 차원에 분산되어 표현하여 붙여진 이름
분산 표현() = 데이터를 최대한 밀집시킬 수 있어서 밀집 표현(Dense Representation)이라고 부르며, 밀집 표현으로 만들어진 벡터를 밀집 벡터(Dense Vector)

분산 표현의 장점

  • 임베딩 벡터의 차원을 데이터 손실을 최소화하면서 압축
  • 단어의 의미, 주반 단어 간의 관계 등 많은 정보가 내포되어 있어 일반화 능력이 뛰어남

Woord2Vec

신경망 기반 단어 임베딩의 대표적인 방법인 Word2Vec모델

Word2Vec는 2013년 구글에서 발표하였으며, 가장 많이 사용하고 있는 단어 임베딩 모델, Word2Vec 모델은 CBOW(Continuous Bag Of Word)와 skip-gram 두 가지 모델

  • CBOW모델

맥락(Content word)라 표현되는 주변 단어들을 이용해 타깃 단어를 예층하는 신경망 모델, 신경망의 입력을 주변 단어들로 구성하고 출력을 타깃 단어로 설정해 학습된 가장치 데이터를 임베딩 벡터로 활용

  • skip-gram 모델

CBOW 모델과 반대로 하나의 타깃 단어를 이용해 주변 단어들을 예층하는 신경망 모델, skip-gram모델이 CBOW모델에 비해 예측해야 하는 맥락이 많음, 단어 분산 표현력이 우수해 cBOW 모델에 비해 임베딩 품질 우수

말뭉치 데이터는 양이 많기 때문에 모델을 학습하는 데 시간이 다소 걸림, Word2Vec을 사용할 때마다 오랜 시간 모델 학습을 진행할 수 없으므로 각 단어의 임베딩 벡터가 설정된 모델을 파일로 저장

Wotd2Vec 모델을 텐서플로나 케라스의 신경망 라이브러리를 이용하여 구현할 수 있지만, Word2Vec를 사용할 수 있는 오픈소스 라이브러리인 Gensim 패키지를 사용하여 테스트 진행

# Word2Vec 모델 학습 예제
from gensim.models import Word2Vec
from konlpy.tag import Komoran
import time

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

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

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

# 문장 단위로 명사만 추출하여 학습 입력 데이터 생성
komoran = Komoran()
docs = [komoran.nouns(sentence[1]) for sentence in review_data]

# Word2Vec 모델 학습

# sentences: Word2Vec 모델 학습에 필요한 문장 데이터 
# size: 단어 임베딩 벡터 크기
# window: 주변 단어 윈도우 크기
# hs: 0(0이 아닌 경우 음수 샘플링 사용), 1(모델 학습에 softmax 사용)
# min_count: 단어 최소 빈도 수 제한(설정된 min_count 빈도 수 이하의 단어는 학습하지 않음)
# sg: 0(CBOW 모델), 1(skip-gram 모델)
# workers: 동시 처리할 작업 수
model = Word2Vec(sentences= docs, size=200, window=4, hs=1, min_count=2, sg=1) 

# 모델 저장
model.save('nvmc.model')

# 학습된 말뭉치 수, 코퍼스 내 전체 단어 수

print("corpus_count: ", model.corpus_count)
print("corpus_total_words: ", model.corpus_total_words)
# 학습된 모델을 활용하여 데이터 추출

from gensim.models import Word2Vec

# 모델 로딩
model = Word2Vec.load('nvmc.model')

# '사랑' 이란 단어로 생성한 단어 임베딩 벡터 확인
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.mv.most_similar("안성기", topn=5))
print(model.mv.most_similar("시리즈", topn=5))

참고

반응형