임베딩
- 자연어를 숫자나 벡터 형태로 변환할 필요가 있음
- 임베딩이란 단어나 문장을 수치화해 벡터 공간으로 표현하는 과정
- 말뭉치 의미에 따라 벡터화하므로 문법 정보를 포함
- 문장 임베딩 / 단어 임베딩
단어 임베딩
- 말뭉치에서 각각의 단어를 벡터로 변환하는 기법
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
- 신경망 기반 단어 임베딩의 대표적인 방법
- 단어 임베딩 모델
CBOW
와 skip-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
| ['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)]
|