Home [Chatbot] Chapter4 워드 임베딩
Post
Cancel

[Chatbot] Chapter4 워드 임베딩

임베딩

  • 자연어를 숫자나 벡터 형태로 변환할 필요가 있음
  • 임베딩이란 단어나 문장을 수치화해 벡터 공간으로 표현하는 과정
  • 말뭉치 의미에 따라 벡터화하므로 문법 정보를 포함
  • 문장 임베딩 / 단어 임베딩

단어 임베딩

  • 말뭉치에서 각각의 단어를 벡터로 변환하는 기법

1. 원-핫 인코딩

  • 단 하나의 값만 1이고, 나머지는 0 -> 희소벡터
  • 단어 집합을 먼저 만들어야 함
  • 고유한 인덱스 번호를 부여함
  • 인덱스 번호가 원-핫 인코딩에서 1의 값을 갖는 위치가 됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from konlpy.tag import Komoran
import numpy as np

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

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

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

# 원-핫 인코딩
nb_classes = len(dics)
targets = list(dics.values())
one_hot = np.eye(nb_classes)[targets] # np.eye() : 단위 행렬
print(one_hot)
1
2
3
4
5
['오늘', '날씨', '구름']
{'오늘': 0, '날씨': 1, '구름': 2}
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

2. 희소 표현과 분산 표현

  • 원-핫 인코딩은 희소 벡터(희소 행렬)에 해당
  • 단어가 희소 벡터로 표현되는 방식을 희소 표현이라고 함
  • 각 차원이 독립적인 정보를 갖고 있지만, 단어 사전 크기가 커질수록 메모리 낭비와 계산 복잡도 증가
  • 단어 간 연관성이 없음


  • 희소표현의 단점을 해결하기 위해 단어 간 유사성을 잘 표현하고 공간을 절약하는 분산 표현 방법 등장
  • 분산 표현이란 한 단어의 정보가 특정 차원에 표현되지 않고, 여러 차원에 분산되어 표현된다는 뜻
  • 데이터 손실을 최소화 하면서 벡터 차원이 압축됨
  • 임베딩 벡터에는 단어 의미, 주변 단어 간의 관계 등 많은 정보가 내포되어 일반화 능력이 뛰어남
  • 벡터 공간 상에서 유사한 의미를 갖는 단어들은 비슷한 위치에 분포됨

3. Word2Vec

  • 신경망 기반 단어 임베딩의 대표적인 방법
  • 단어 임베딩 모델
  • CBOWskip-gram 두 가지 모델로 제안됨
  • CBOW : 주변 단어를 이용해 타깃 단어를 예측
  • skip-gram : 타깃 단어를 이용해 주변 단어들을 예측
  • 윈도우 : 앞뒤로 몇 개의 단어까지 확인할지의 범위
  • Word2Vec의 단어 임베딩은 해당 단어를 밀집 벡터로 표현하여 학습을 통해 의미상 비슷한 단어들을 비슷한 벡터 공간에 위치
  • 의미에 따라 방향성을 가짐
1
2
3
from gensim.models import Word2Vec
from konlpy.tag import Komoran
import time
1
2
3
4
5
6
# 네이버 영화 리뷰 데이터
def read_review(filename):
    with open(filename, 'r') as f:
        data = [line.split('\t') for line in f.read().splitlines()]
        data = data[1:] # header 제거
    return data
1
2
3
4
# 리뷰 파일 읽어오기
df = read_review('C:/Users/USER/Desktop/ratings.txt')

print(len(df)) # 데이터 개수
1
2
200000
16.601213693618774
1
2
# 데이터 확인
df[0]
1
['8112052', '어릴때보고 지금다시봐도 재밌어요ㅋㅋ', '1']
1
2
3
4
5
# 문장 단위로 명사만 추출해 학습 입력 데이터로 만듦
komoran = Komoran()

docs = [komoran.nouns(sentence[1]) for sentence in df]
print(docs)

[[‘때’], [‘디자인’, ‘학생’, ‘외국’, ‘디자이너’, ‘전통’, ‘발전’, ‘문화’, ‘산업’, ‘사실’, ‘우리나라’, ‘시절’, ‘끝’, ‘열정’, ‘노라’, ‘노’, ‘전통’, ‘사람’, ‘꿈’, ‘수’, ‘것’, ‘감사’], [‘폴리스’, ‘스토리’, ‘시리즈’, ‘뉴’, ‘최고’], [‘연기’, ‘것’, ‘라고’, ‘생각’, ‘몰입’, ‘영’, ‘화지’], [‘안개’, ‘밤하늘’, ‘초승달’, ‘영화’], … , [], [‘완전’, ‘사이코’, ‘영화’, ‘마지막’, ‘영화’, ‘질’], [‘라따뚜이’, ‘스머프’], [‘포’, ‘풍’, ‘저그’, ‘가나’, ‘신다영’, ‘차영’, ‘차영’, ‘차’]]

  • sentences : 모델 학습에 필요한 문장 데이터
  • size : 단어 임베딩 벡터의 차원(크기)
  • window : 주변 단어 윈도우의 크기
  • hs : 0(0이 아닌 경우 음수 샘플링 사용), 1(모델 학습에 softmax 사용)
  • min_count : 단어 최소 빈도수 제한(빈도수 이하 단어들은 학습하지 않음)
  • sg : 0(CBOW모델), 1(skip-gram 모델)
1
2
# Word2Vec 모델 학습
model = Word2Vec(sentences=docs, size=200, window=4, hs=1, min_count=2, sg=1)
1
2
3
4
5
6
# 모델 저장
model.save('nvmc.model')

# 학습된 말뭉치 수, 코퍼스 내 전체 단어 수
print('Corpus Count : ', model.corpus_count)
print('Corpus Total Words : ', model.corpus_total_words)
1
2
Corpus Count :  200000
Corpus Total Words :  1076896
  • 생성된 Word2Vec 모델 파일을 읽어와 실제로 단어 임베딩된 값과 벡터 공간상의 유사한 단어들을 확인
  • 모델을 학습할 때 설정한 size 하이퍼 파라미터만큼 단어 임베딩 벡터 차원 크기가 결정됨
1
2
3
4
5
6
7
8
from gensim.models import Word2Vec

# 모델 Load
model = Word2Vec.load('C:/Users/USER/DEsktop/nvmc.model')
print('Corpus Total Words : ', model.corpus_total_words)

# '사랑'이란 단어로 생성한 단어 임베딩 벡터
print('사랑 : ', model.wv['사랑'])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Corpus Total Words :  1076896
사랑 :  [ 0.2227722   0.1308166   0.08151697 -0.00723978  0.1509527  -0.17004585
  0.00840013 -0.24441956 -0.05909146 -0.32303146  0.20456505  0.10809675
 -0.21612184  0.12213039 -0.2770207   0.36656973 -0.03511506  0.10880087
  0.13776775  0.31425217  0.07093788 -0.7185554   0.04259297  0.2376082
 -0.208063    0.13211462 -0.03724234  0.02722316  0.07514791 -0.27001786
 -0.23673943 -0.17043753  0.02996521 -0.38769338 -0.09036228  0.02401703
 -0.3292917   0.03673863 -0.04922774 -0.08874141  0.03007849  0.06135811
 -0.07596387 -0.04033265  0.06983635 -0.38826323  0.20073384 -0.05464417
 -0.10595287 -0.5796523  -0.05407318  0.29334214  0.2141849   0.41522568
  0.07912885  0.01122359 -0.12547943 -0.00231675 -0.3267134   0.2877619
  0.16116454 -0.21542566 -0.41063762  0.22273563  0.21536423  0.10391748
  0.03492094 -0.19002524 -0.10164113  0.25943926 -0.16068009  0.25366557
  0.454409   -0.3734297  -0.09503052 -0.26337305  0.34260222  0.0769483
  0.00761063  0.20098941 -0.11015863  0.11118354  0.2174199  -0.3101217
 -0.15321808  0.13931583 -0.21131535 -0.02318534 -0.24914366 -0.04109119
  0.20606434 -0.14733765 -0.07012182  0.13595167  0.04622768  0.03905148
  0.3059347   0.06472304 -0.18995579 -0.01818325  0.224217    0.07424644
 -0.00889122  0.11835817 -0.19035396  0.40523288 -0.12524752 -0.13002639
 -0.15092425 -0.10893856  0.29592112  0.07804067  0.20202179  0.11090574
  0.15539663  0.03717353  0.24275263 -0.08569314  0.01766842  0.18161453
  0.10276432 -0.05299881 -0.29103062 -0.4771171  -0.02455863  0.01338391
 -0.32010657  0.03955708  0.14547229  0.2595661  -0.11052402  0.39415357
  0.08931098 -0.01431458 -0.32451844  0.17857271  0.07541731 -0.00650155
 -0.11848965  0.01609575 -0.08603881 -0.04149693  0.03645035 -0.05666835
 -0.07202139 -0.18846987 -0.24218947 -0.3949567   0.03041222  0.05754517
 -0.29034385  0.00902974 -0.04125157  0.09509075  0.01274497  0.19624521
  0.14817744  0.07644425  0.08671382 -0.1484946  -0.09740651  0.10697261
  0.10393514  0.05566448  0.36025733  0.02718131  0.2962365  -0.14780426
 -0.14059404  0.04043877  0.07470571 -0.35633612 -0.12186905 -0.13941354
 -0.21965097 -0.31130323  0.00828137 -0.30511114 -0.10194412 -0.32275373
 -0.16599934  0.20533356  0.154536    0.06954142  0.2107928   0.11868656
 -0.23086867 -0.06221215  0.02079245  0.18074818  0.13077524  0.19574514
  0.3585105  -0.11109409 -0.18274142 -0.12309188 -0.0230147  -0.19104394
 -0.33430696  0.11674774]
  • model.wv.similarity() : 두 단어 간의 유사도 계산
  • 유사도가 1에 가까울수록 두 단어는 동일한 의미이거나 문법적으로 관계되어 있을 확률이 높음
1
2
3
4
5
6
# 단어 유사도 계산
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='삼성'))
1
2
3
4
5
일요일 = 월요일	 0.6660608
안성기 = 배우	 0.5478904
대기업 = 삼성	 0.6032991
일요일 != 삼성	 0.28772512
히어로 != 삼성	 0.15809911
  • model.wv.most_similar() : 인자로 사용한 단어와 가장 유사한 단어를 리스트로 반환
1
2
3
# 가장 유사한 단어 추출
print(model.wv.most_similar('안성기', topn=5))
print(model.wv.most_similar('시리즈', topn=5))
1
2
[('씨야', 0.7167593836784363), ('장미희', 0.7130054235458374), ('김갑수', 0.7110061049461365), ('정려원', 0.7079552412033081), ('이은우', 0.7010425329208374)]
[('캐리비안의 해적', 0.6419076323509216), ('X맨', 0.631088137626648), ('러시아워', 0.6305814981460571), ('번외', 0.6276097297668457), ('잭 라이언', 0.6275084614753723)]
This post is licensed under CC BY 4.0 by the author.