벡터화
워드 임베딩
Word2Vec
임베딩 벡터 시각화
FastText
Glove
$ mkdir -p ~/aiffel/word_embedding
4(Q). Out of Vocabulary?
A. 단어장에 없는 단어가 등장하여 대처할 수 없는 난감한 문제
Document
1 : you know I want your love
2 : I like you
3 : what should I do
What is Term Frequency?
단어들의 원-핫 벡터 합 / 문장 단어 개수
와 같음Why Term Frequency?
What is IDF?
1 : 강아지, 고양이, 강아지
2 : 애교, 고양이
3 : 컴퓨터, 노트북
⬇️
강아지 : 1번
고양이 : 2번
애교 : 3번
컴퓨터 : 4번
노트북 : 5번
+추가 전처리 : 정수가 큰 숫자 제거 등을 할 수도 있음
⬇️
각 단어를 V차원 벡터로 표현
강아지 : [1, 0, 0, 0, 0]
고양이 : [0, 1, 0, 0, 0]
애교 : [0, 0, 1, 0, 0]
컴퓨터 : [0, 0, 0, 1, 0]
노트북 : [0, 0, 0, 0, 1]
$ pip install konlpy
import re
from konlpy.tag import Okt
from collections import Counter
text = "임금님 귀는 당나귀 귀! 임금님 귀는 당나귀 귀! 실컷~ 소리치고 나니 속이 확 뚫려 살 것 같았어."
text
정규 표현식으로 특수문자 제거
[^ㄱ-ㅎㅏ-ㅣ가-힣 ]
reg = re.compile("[^ㄱ-ㅎㅏ-ㅣ가-힣 ]")
text = reg.sub('', text)
print(text)
okt=Okt()
tokens = okt.morphs(text)
print(tokens)
['임금님', '귀', '는', '당나귀', '귀', '임금님', '귀', '는', '당나귀', '귀', '실컷', '소리', '치고', '나니', '속이', '확', '뚫려', '살', '것', '같았어']
Counter
서브클래스로 빈도수 카운트vocab = Counter(tokens)
print(vocab)
Counter({
'귀': 4,
'임금님': 2,
'는': 2,
'당나귀': 2,
'실컷': 1,
'소리': 1,
'치고': 1,
'나니': 1,
'속이': 1,
'확': 1,
'뚫려': 1,
'살': 1,
'것': 1,
'같았어': 1
})
most_common()
vocab_size = 5
vocab = vocab.most_common(vocab_size)
print(vocab)
word2idx={word[0] : index+1 for index, word in enumerate(vocab)}
print(word2idx)
최종 단어장 :
word2idx
one_hot_encoding
def one_hot_encoding(word, word2index):
one_hot_vector = [0]*(len(word2index))
index = word2index[word]
one_hot_vector[index-1] = 1
return one_hot_vector
임금님
단어 원-핫 벡터 보기one_hot_encoding("임금님", word2idx)
Tokenizer
: 단어장을 만듦to_categorical
: 원-핫 인코딩 도구from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.utils import to_categorical
text = [['강아지', '고양이', '강아지'],['애교', '고양이'], ['컴퓨터', '노트북']]
text
t = Tokenizer()
t.fit_on_texts(text)
print(t.word_index)
vocab_size
+1
을 하는 이유 : 0번 단어가 특별 토큰으로 추가되는 경우가 많기 때문(0번은 패딩 토큰으로 주로 사용)vocab_size = len(t.word_index) + 1
현재 vocab_size는 6
sub_text = ['강아지', '고양이', '강아지', '컴퓨터']
encoded = t.texts_to_sequences([sub_text])
print(encoded)
to_categorical()
one_hot = to_categorical(encoded, num_classes = vocab_size)
print(one_hot)
결과 : 각 단어가 단어장 크기(6)인 6차원 벡터로 변환됨
빅데이터: 큰 용량의 역습 – 차원의 저주 (Curse of dimensionality)
// [둥근,빨간,단맛,신맛]
사과 : [0.8, 0.7, 0.7, 0.1] // 0.8만큼 둥글고, 0.7만큼 빨갛고, 0.7만큼 달고, 0.1만큼 신 것은 사과다
바나나: [0.1, 0.0, 0.8. 0.0] // 0.1만큼 둥글고, 0.0만큼 빨갛고, 0.8만큼 달고, 0.0만큼 신 것은 바나나다
귤 : [0.7, 0.5, 0.6, 0.5] // 0.7만큼 둥글고, 0.5만큼 빨갛고, 0.6만큼 달고, 0.5만큼 신 것은 귤이다
Q. 임베딩 벡터 값이 얻어지는 방식
A. 신경망 모델이 단어 의미와 문맥을 자동으로 학습해 벡터 값이 조정됨
(답안): 훈련 데이터로부터 Language Model을 학습하는 과정에서 자동으로 얻어짐
NPLM(Neural Probabilistic Language Model)
Word2Vec
그 이후, FastText 나 GloVe 등의 임베딩 방법 추가 제안
Q.
박찬호 - 야구 + 축구
결과는?
A. 호나우두/Noun
What is Encoding?
What is One Hot Encoding?
One Hot Encoding doesn't have similarity
every distances is same to each other
cosine similarity also 0 since angle is 90 degree
Embedding
Word2Vec
Word2Vec data generation(skipgram)
- "king brave man"
- "queen beautiful woman"
Word2Vec deep learning model input and target
Word2Vec training
hidden layer is the word2Vec
Word2Vec is hidden layer after train
because input is one hot encoding, hidden layer works as lookup table
Word2Vec gives similarity in vector representation
강아지
, 애교
, 귀여운
: 의미적으로 비슷한 단어들이 비슷한 벡터로 표현됨"I like natural language processing."
m
-> 주변 단어 개수는 2m
윈도우 크기가 1일 때, 하나의 샘플 문장에 대한 데이터셋 생성 과정((주변 단어의 셋), 중심 단어)
- ((like), I), ((I, natural), like), ((like, language), natural), ((natural, processing), language), ((language), processing)
- 각각의 단어가 원-핫 인코딩됨 ➡️ 원-핫 벡터가 됨
- 원-핫 벡터가 ➡️ CBoW or Skip-gram 입력이 됨
Word2Vec은 은닉층이 1개이기 때문에 얕은 신경망 학습이라고 봐야함!
출력층 벡터
와 중심 단어의 원-핫 벡터
손실을 최소화하는 방식으로 학습정리
- 주변 단어를 통해 중간 단어 예측
- 한계
- OOV
- Polysemy
- 문맥 파악 어려움
CBoW와의 차이점
- 중심 단어로부터 주변 단어 예측
- 은닉층에서 다수 벡터의 덧셈, 평균을 구하는 부분이 없음
공통점
- 가중치 행렬 행 또는 열에서 임베딩 벡터를 얻음
대부분의 Word2Vec은 SGNS(Skip-Gram with Negative Sampling) 사용
기존 다중 클래스 분류 문제 ➡️ sigmode 함수를 사용하는 이진 분류 문제
출력층에서 softmax 함수를 통과한 V차원 벡터
, V차원 주변 단어 원-핫 벡터
의 오차를 구함"Thou shalt not make a machine in the likeness of a human mind"
레이블 지정
거짓 데이터셋 생성 관정
중심 단어 및 주변 단어 내적 + 출력층 시그모이드 함수를 통과 = 1 or 0 레이블로부터 오차 구하기 및 역전파 수행
gensim
: 토픽 모델링 NLP 패키지NLTK
제공 코퍼스$ pip install nltk
$ pip install gensim
NLTK
내장 코퍼스 다운로드import nltk
nltk.download('abc')
nltk.download('punkt')
corpus
변수에 저장from nltk.corpus import abc
corpus = abc.sents()
print(corpus[:3])
[['PM', 'denies', 'knowledge', 'of', 'AWB', 'kickbacks', 'The', 'Prime', 'Minister', 'has', 'denied', 'he', 'knew', 'AWB', 'was', 'paying', 'kickbacks', 'to', 'Iraq', 'despite', 'writing', 'to', 'the', 'wheat', 'exporter', 'asking', 'to', 'be', 'kept', 'fully', 'informed', 'on', 'Iraq', 'wheat', 'sales', '.'], ['Letters', 'from', 'John', 'Howard', 'and', 'Deputy', 'Prime', 'Minister', 'Mark', 'Vaile', 'to', 'AWB', 'have', 'been', 'released', 'by', 'the', 'Cole', 'inquiry', 'into', 'the', 'oil', 'for', 'food', 'program', '.'], ['In', 'one', 'of', 'the', 'letters', 'Mr', 'Howard', 'asks', 'AWB', 'managing', 'director', 'Andrew', 'Lindberg', 'to', 'remain', 'in', 'close', 'contact', 'with', 'the', 'Government', 'on', 'Iraq', 'wheat', 'sales', '.']]
print('코퍼스의 크기 :',len(corpus))
vector size
: 학습 후 임베딩 벡터 차원window
: context window 크기min_count
: 단어 최소 빈도수 제한workers
: 학습 프로세스 수sg
: 0(CBoW), 1(Skip-gram)from gensim.models import Word2Vec
model = Word2Vec(sentences = corpus, vector_size = 100, window = 5, min_count = 5, workers = 4, sg = 0)
print("모델 학습 완료!")
model.wv.most_similar
model_result = model.wv.most_similar("man")
print(model_result)
[('woman', 0.9233373999595642), ('skull', 0.911032497882843), ('Bang', 0.9056490063667297), ('asteroid', 0.9051957130432129), ('third', 0.9020178318023682), ('baby', 0.8993921279907227), ('dog', 0.8985978364944458), ('bought', 0.8975234031677246), ('rally', 0.8912491798400879), ('disc', 0.8888981342315674)]
from gensim.models import KeyedVectors
model.wv.save_word2vec_format('~/aiffel/word_embedding/w2v')
loaded_model = KeyedVectors.load_word2vec_format("~/aiffel/word_embedding/w2v")
print("모델 load 완료!")
model_result = loaded_model.most_similar("man")
print(model_result)
[('woman', 0.9233373999595642), ('skull', 0.911032497882843), ('Bang', 0.9056490063667297), ('asteroid', 0.9051957130432129), ('third', 0.9020178318023682), ('baby', 0.8993921279907227), ('dog', 0.8985978364944458), ('bought', 0.8975234031677246), ('rally', 0.8912491798400879), ('disc', 0.8888981342315674)]
overacting
➡️ KeyErrorloaded_model.most_similar('overacting')
memory
의 오타인 memorry
loaded_model.most_similar('memorry')
w2v
모델(저장한 모델)을 이용해 벡터값 지정 파일 및 메타 파일 얻기$ python -m gensim.scripts.word2vec2tensor --input ~/aiffel/word_embedding/w2v --output ~/aiffel/word_embedding/w2v
Load
클릭 > w2v_tensor.tsv, w2v_metadata.tsv 업로드
Search
버튼 or 그래프 포인트로 원하는 단어 선택 > neighbors로 이웃 개수 지정
COSINE
or EUCLIDEAN
으로 거리 측정 메트릭 지정Word2Vec vs FastText
- Word2Vec : 단어를 더 이상 깨질 수 없는 단위로 구분
- FastText : 단어 내부의 내부 단어(subwords) 학습
n-gram
<pa, par, art, rti, tia, ial, al>
+ 기존 단어에 <>를 붙인 <partial>
실제 사용 시에는 n의 최솟값 및 최댓값 범위 설정 가능
gensim
패키지 디폴트 값 : 3, 6이렇게 생성된 단어들 각각에 대한 Word2Vec을 수행함
partial = <pa + par + art + rti + ita + ial + al> + <par + arti + rtia + tial + ial> + <part + ...중략... + <partial>
오타에 robust하기 떄문에, 단어장에 단어가 없어도 n-gram이 다른 단어에 있다면 ➡️ 벡터값을 구할 수 있음
FastText 학습
from gensim.models import FastText
fasttext_model = FastText(corpus, window=5, min_count=5, workers=4, sg=1)
print("FastText 학습 완료!")
overacting
과 코사인 유사도가 높은 단어 보기fasttext_model.wv.most_similar('overacting')
memoryy
fasttext_model.wv.most_similar('memoryy')
유사 단어로 memory 출력
음절 단위 FastText
텐서플로우
트라이그램 벡터 구성<텐서, 텐서플, 서플로, 플로우, 로우>, <텐서플로우>
자소 단위 FastText
<ㅌㅔ,ㅌㅔㄴ,ㅔㄴㅅ,ㄴㅅㅓ,ㅅㅓ_, ...중략... >
단어-문서행렬(Word-Document Matrix), 단어-문맥행렬(window based co-occurrence matrix) 등의 입력 데이터에 특이값 분해 수행 ➡️ 차원수 축소로 계산 효율성 UP
truncated SVD 사용
Q. 행렬 A에 대해 특이값 분해 변형인 thin SVD, compact SVD, Truncated SVD을 사용했을 경우 중 행렬 A 복구가 가능한 특이값 분해는?
A. Thin SVD, Compact SVD(Truncated SVD의 경우에는 근사 복원까지만 가능함)
한계점 2가지
- 차원 축소의 재사용 불가 : 새 단어 추가시 DTM을 다시 만들어 다시 차원 축소를 해야함
- 단어 벡터간 유사도 계산 측면 : Word2Vec보다 성능 떨어짐
즉, 카운트 기반 및 예측 기반 방식을 모두 사용해 Word2Vec보다 나은 임베딩 방법인 Glove
제안
Example corpus(윈도우 크기 1)
- I like deep learning.
- I like NLP.
- I enjoy flying.
"중심 단어 벡터, 주변 단어 벡터 내적 ➡️ 전체 코퍼스의 동시 등장 빈도 로그값이 되도록 한다."
- 전체 코퍼스에서의
동시 등장 빈도 로그값
,중심 단어 벡터 - 주변 단어 벡터 내적값
최소화할 수 있도록 두 벡터 값을 학습
GloVe word vector
- Common Crawl (42B tokens, 1.9M vocab, uncased, 300d vectors, 1.75 GB download)
- Common Crawl (840B tokens, 2.2M vocab, cased, 300d vectors, 2.03 GB download)
- Wikipedia 2014 + Gigaword 5 (6B tokens, 400K vocab, uncased, 300d vectors, 822 MB download)
- Twitter (2B tweets, 27B tokens, 1.2M vocab, uncased, 200d vectors, 1.42 GB download)
import gensim.downloader as api
glove_model = api.load("glove-wiki-gigaword-50")
glove_model.most_similar("dog")
glove_model.most_similar('overacting')
glove_model.most_similar('memoryy')
GloVe 역시 OOV 문제가 있음