NLP & DL
- ํน์ ๋ชฉ์ ์ด ์๋, ๋ฒ์ฉ์ (์ผ๋ฐ์ )์ผ๋ก ์ฐ์ผ Word Embedding์ ๋ง๋ ๋ค.
-
embedding์ ๋ฐฉ๋ฒ
- ๋ฐ๋ผ์ ๋ฌธ์ฅ ์ ๋จ์ด์ ๋งฅ๋ฝ(์๋ฏธ)๋ฅผ ํ์ ํ ์ค ์๋ค.
- ์ฆ, semantic ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ค.
-
์ฐธ๊ณ :
- ๋ถํฌ ๊ฐ์ค:
- ๊ฐ์ ๋ฌธ๋งฅ์ ๋จ์ด, ์ฆ ๋น์ทํ ์์น์ ๋์ค๋ ๋จ์ด๋ ๋น์ทํ ์๋ฏธ๋ฅผ ๊ฐ์ง๋ค. ๋ฐ๋ผ์ ์ด๋ค ๊ธ์์ ๋น์ทํ ์์น์ ์กด์ฌํ๋ ๋จ์ด๋ ๋จ์ด ๊ฐ์ ์ ์ฌ๋๊ฐ ๋๋ค๊ณ ํ๋จ.
๋น๋ ๊ธฐ๋ฐ์ ๋ฌธ์ ์์นํ ํ์ต ๊ธฐ๋ฐ์ ๋ฌธ์ ์์นํ ์นด์ดํธ ๊ธฐ๋ฐ ๋ฐฉ๋ฒ ์์ธก ๋ฐฉ๋ฒ ๋น ๋ฅด๋ค ๋จ์ด๋ค์ ๋ณต์กํ ํน์ง๊น์ง ์ ํ์ ํ ์ ์๋ค. Bag of word(BOW), TF-IDF ํ์ฉํ SVD ๋ฑ Word Embedding / Word2Vec
Word2Vec
Word2Vec | Word Embedding |
---|---|
ํน์ ๋ชฉ์ ์ด ์๋ ๋ฒ์ฉ์ ์ธ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ๋๋ค. - ๋ฐฉ๋ํ ์์ ์๋ฌด๋ฌธ์๋ ์ฝํผ์ค๋ฅผ ํ์ตํ์ฌ ๋จ์ด๋ค์ด ์ด๋ค ๊ด๊ณ๋ฅผ ๊ฐ๋๋ก ๋ฒกํฐํ(์์นํ)ํ๋ ๊ธฐ์ ์ด๋ค. - ๋ฐ๋ผ์ ๋จ์ด๋ค์ ์๋ฏธ๊ฐ ๋ฒ์ฉ์ ์ด๋ค. |
classification ๋ฑ์ ํน์ ๋ชฉ์ ์ ๋ฌ์ฑํ๊ธฐ ์ํด ๊ทธ๋๋ง๋ค ํ์ตํ๋ ๋ฐฉ์. - ๋จ์ด๋ค์ด ํน์ ๋ชฉ์ ์ ๋ง๊ฒ ๋ฒกํฐํ๋๋ค. |
์ฌํ์ ์ผ๋ก ๊ฒฐ์ ๋๋ Word Embedding ๊ณผ ๋ฌ๋ฆฌ ์ฌ์ ์ ํ์ตํ์ฌ ๋จ์ด์ ๋งฅ๋ฝ์ ์ฐธ์กฐํ ๋ฒกํฐํ๋ฅผ ์งํํ๋ค. - ๋ถํฌ๊ฐ์ค ์ด๋ก ์ฌ์ฉ: ''์ฃผ๋ณ ๋จ์ด๋ค์ ์ฐธ์กฐํ๋ ๋ฑ ๋จ์ด๋ค์ ๋ถํฌ๋ฅผ ํตํด ํด๋น ๋จ์ด์ ์๋ฏธ๋ฅผ ํ์ ํ๋ค'', ๋ ๋ป๋จ์ด์ - ์ฃผ๋ณ ๋จ์ด(๋งฅ๋ฝ:context)๋ฅผ ์ฐธ์กฐํ์ฌ ํด๋น ๋จ์ด๋ฅผ ์์นํํ๋ค. ๊ทธ๋ฌ๋ฉด ํด๋น ๋จ์ด๋ ์ธ์ ๋จ์ด๋ค๊ณผ ๊ด๊ณ๊ฐ ๋งบ์ด์ง๊ณ ์ธ์ ๋จ์ด๋ค ๊ฐ์๋ ๋จ์ด ๋ฒกํฐ์ ์ ์ฌ๋๊ฐ ๋๋ค. |
Word Embedding ๋ฒกํฐ๋ ์ฌํ์ ์ผ๋ก ๊ฒฐ์ ๋๊ณ , ํน์ ๋ชฉ์ ์ ์ฉ๋์ ํ์ ๋๋ค. |
๋ฐฉ๋ฒ: continuous back of word (CBOW ), Skip-gram |
-
๋ํ์ ์ธ Word2Vec >
CBOW Skip-Gram ๋ฌธ์ฅ์ ๋จ์ด๋ก ์ ์ฒ๋ฆฌํ๋ค. ๋ฌธ์ฅ์ ๋จ์ด๋ก ์ ์ฒ๋ฆฌํ๋ค. ์์นํํ๊ณ ์ถ์ ๋จ์ด๊ฐ output ๋๋๋ก
๋คํธ์ํฌ ๊ตฌ์ฑ์ฃผ๋ณ ๋จ์ด๋ฅผ
* ์์:
input
ex: (input) alic, bit ๋ฑ ์ฌ๋ฌ ๊ฐ ... โ
hidden layer โ
(output) hurt
๋ฐ๋ผ์: hidden layer = ์ค๊ฐ์ถ๋ ฅ.CBOW ๋ฅผ ๊ฑฐ๊พธ๋ก ํ ๊ฒ.
- input 1๊ฐ ,
- output ์ฌ๋ฌ ๊ฐ
* ์์:
(input) hurt โ
hidden layer โ
(output) alic, bit ๋ฑ ์ฌ๋ฌ ๊ฐ ...
- AE ๋ฐฐ์ธ ๋, ๋ชจ๋ธ ์ ์ฒด ํ์ต ์ํจ ํ,
autoencoding ๋ถ๋ฌธ๋ง ๋ฐ๋ก ๋นผ์
๋ชฉ์ ์ ๋ง๊ฒ ๋๋ฆฐ ๊ฒ์ฒ๋ผ
Skip-Gram๋ ๊ทธ๋ ๊ฒ ์งํํจ.์ฆ, ์ฌ๋ฌ ๊ฐ๋ก ํ ๊ฐ ์์ธก ์ฆ, ํ ๊ฐ๋ก ์ฌ๋ฌ ๊ฐ ์์ธก
-
์๋ฆฌ >
์๋ฅผ ๋ค์ด
- (input) hurt๋ฅผ one-hot encodingํด์ hurt์ ์์น(index) ๋ฅผ ํ์ ํ ํ,
- (output) alic๋ฅผ ๋ฃ์์ ๋ hurt์ ์์น(index)๋ฅผ ์ฐพ๋๋ก ํจ
- ์์ธก ์, ๋ ํธ๋ฆฌํ ๊ฑด Skip-Gram.
- ๋จ์ด ํ๋๋ง ๋ฃ์ผ๋ฉด output์ด ๋์ค๋ฏ๋ก
- ๋จ์ >
-
๋์์ด์์ด๋ฅผ ์ ๋๋ก ํ์ ํ์ง ๋ชปํ๋ค.
- ์ค์ word2vec์ ์์น๋ฅผ ๊ณ์ฐํ ๋ ๊ฐ๊น์ด ๊ฑฐ๋ฆฌ์ ์๋ ๊ฐ๋ค์ ํ๊ท ์ผ๋ก ๊ณ์ฐํ๊ธฐ ๋๋ฌธ์
- ํด๊ฒฐ๋ฐฉ๋ฒ:
ELMo
- embedding ํ ๋, ๋ฌธ๋งฅ์ ๋ฐ๋ผ ๊ฐ๋ณ์ ์ผ๋ก vector๋ฅผ ๋ง๋ ๋ค. ์ฆ, ๋งฅ๋ฝํ๋ ๋จ์ด ์๋ฒ ๋ฉ
-
์ถ๋ ฅ์ธต์ 'softmax'๋ฅผ ์ฌ์ฉํด์ ๊ณ์ฐ๋์ด ๋ง๋ค.
- softmax๋ฅผ ์ฌ์ฉํ๋ ์ด์ : one-hot ์ธ์ฝ๋ฉ ์ํด์
- ๊ทธ๋ฐ๋ฐ softmax๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ์ ์ฒด ๋จ์ด๋ฅผ 0~1์ฌ์ด์ ๊ฐ์ผ๋ก ํํํ๊ธฐ ์ํด ์ ๋ถ ๊ณ์ฐ์ ์งํํ๋๋ฐ, ์ด๋ ์ ์ฒด ๋จ์ด๊ฐ 3๋ง ๊ฐ ๋ฑ์ง๊ฐ ๋์ด๊ฐ๋ ์ ๋๋ก ํฐ vocab์ผ ๋ ๊ณ์ฐ๋์ด ๋ง๋ค.
-
ํด๊ฒฐ ๋ฐฉ๋ฒ:
Skip-Gram Negative Sampling(SGNS)
- SGNS๋ sigmoid ์ฌ์ฉ
-
OOV(Out Of Vocbulary)
-
ํด๊ฒฐ๋ฐฉ๋ฒ:
FastText
- ๋น๋์๊ฐ ์ ์ ๋จ์ด์ ๋ํด์๋ OOV ๋ฌธ์ ์ ํด๊ฒฐ ๊ฐ๋ฅ์ฑ์ด ๋๋ค
-
-
๋ฌธ์ ์ ์ฒด์ ๋ํด์ ๊ณ ๋ ค ๋ชปํ๋ค.
-
ํด๊ฒฐ๋ฐฉ๋ฒ:
GloVe
- ๋น๋๊ธฐ๋ฐ(TF-IDF) + ํ์ต๊ธฐ๋ฐ(Embedding) ๋ฐฉ๋ฒ ํผ์ฉ
- TF-IDF: ๋ฌธ์ ์ ์ฒด์ ๋ํ ํต๊ณ๋ฅผ ์ฌ์ฉํ์ง๋ง, ๋จ์ด๋ณ ์๋ฏธ๋ ๊ณ ๋ คํ์ง ๋ชปํ๋ค๋ ๋จ์ ๊ณผ Word2Vec: ์ฃผ๋ณ ๋จ์ด๋ง์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ฌธ์ ์ ์ฒด์ ๋ํด์๋ ๊ณ ๋ คํ์ง ๋ชปํ๋ค.
-
-
CODE
- SGNS + CNN
- ์์ค alice in wonderland์ ์ฌ์ฉ๋ ๋จ์ด๋ค์ 2์ฐจ์ feature๋ก vectorํ ํ๋ค.
-
๊ทธ๋ฆผ์ผ๋ก ๋จผ์ ๋ณด๊ธฐ:
๋คํธ์ํฌ์๋ center๊ฐ ๋ฃ์
- x๊ฐ์ธ 7์ input ํ์ ๋ output์ด y๊ฐ์ผ๋ก 8์ด ๋์ฌ ๋์ ๋คํธ์ํฌ๋ค.
- 2๊ฐ ๋ด๋ฐ์ผ๋ก ์ค์์ ๋์ latent layer๋ฅผ ์ ์ฒด ํ์ต ํ ๋ฐ๋ก ๋นผ๋ด๊ณ ,
- ์ด๋ ๋์จ x์ขํ์ y์ขํ๋ก 2D์์ plt์ ๊ทธ๋ฆผ์ผ๋ก ๋ํ๋ด๋ฉด, ๋งฅ๋ฝ ์ ๊ฐ๊น์ด ์๋ฏธ๋ฅผ ๊ฐ์ง ๋จ์ด๋ค๋ผ๋ฆฌ ๋ญ์ณ์ ธ ์์์ ํ์ธํ ์ ์๋ค.
code
STEP 1
-
ํจํค์ง ๋ถ๋ฌ์ค๊ธฐ
from sklearn.model_selection import train_test_split from sklearn.preprocessing import OneHotEncoder import matplotlib.pyplot as plt import nltk import numpy as np import pandas as pd from nltk.corpus import stopwords from nltk.stem import WordNetLemmatizer import string from nltk import pos_tag from nltk.stem import PorterStemmer import collections from tensorflow.keras.layers import Input, Dense, Dropout from tensorflow.keras.models import Model
-
์ ์ฒ๋ฆฌ
def preprocessing(text): # ํ line(sentence)๊ฐ ์ ๋ ฅ๋จ # step1. ํน๋ฌธ ์ ๊ฑฐ text2 = "".join([" " if ch in string.punctuation else ch for ch in text]) # for ch in text: ํ sentence์์ ํ๋์ character๋ฅผ ๋ณด๊ณ , string.punctuation:[!@#$% ๋ฑ]์ ๊ณต๋ฐฑ์ฒ๋ฆฌ('')=์ ๊ฑฐ ํจ tokens = nltk.word_tokenize(text2) tokens = [word.lower() for word in tokens] # ์ ์ ๊ฑฐ์์ ์ด์๋จ์ ๊ฒ๋ค๋ง .lower() = ์๋ฌธ์๋ก ๋ฐ๊ฟ์ word์ ๋ฃ์ด์ค # step2. ๋ถ์ฉ์ด ์ฒ๋ฆฌ(์ ๊ฑฐ) stopwds = stopwords.words('english') tokens = [token for token in tokens if token not in stopwds] # stopword์ ์๋ ๊ฒ๋ง token ๋ณ์์ ์ ์ฅ # step3. ๋จ์ด์ ์ฒ ์๊ฐ 3๊ฐ ์ด์์ธ ๊ฒ๋ง ์ ์ฅ tokens = [word for word in tokens if len(word)>=3] # step4. stemmer: ์ด๊ฐ(prefix) ์ถ์ถ(์ด๋ฏธ(surffix) ์ ๊ฑฐ) ex: goes -> go / going -> go stemmer = PorterStemmer() tokens = [stemmer.stem(word) for word in tokens] # step5. ๋จ์ด์ ํ์ฌ ํ๊น (tagging) tagged_corpus = pos_tag(tokens) # ex: (alic, NNP), (love, VB) Noun_tags = ['NN','NNP','NNPS','NNS'] Verb_tags = ['VB','VBD','VBG','VBN','VBP','VBZ'] # ๋จ์ด์ ์ํ(ํ์ ์ด,Lemma)์ ํ์ํ๋ค ## ํ์ ์ด(Lemma)๋ ํ๊ธ๋ก๋ 'ํ์ ์ด' ๋๋ '๊ธฐ๋ณธ ์ฌ์ ํ ๋จ์ด' ์ ๋์ ์๋ฏธ. ๋์ฌ์ ํ์ฉ์ฌ์ ํ์ฉํ (surfacial form) ์ ๋ถ์ ## ์ฐธ๊ณ : https://wikidocs.net/21707 ## ๊ฑ ํ์ฉ์ฌ/๋์ฌ๋ฅผ ์ฌ์ ํ ๋จ์ด๋ก ๋ง๋ค์๋ค ์๊ฐํ๊ธฐ.... # ex: belives -> (stemmer)believe(๋ฏฟ๋ค) // belives -> (lemmatizer)belief(๋ฏฟ์) # (cooking, N) -> cooking / (cooking, V) -> cook ## ํ๊ตญ์ด ์์: """ lemmatize ํจ์๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ๋์ด์ฐ๊ธฐ๊ฐ ์ง์ผ์ง ๋จ์ด๊ฐ ์ ๋ ฅ๋์์ ๋ Komoran ์ ์ด์ฉํ์ฌ ํํ์ ๋ถ์์ ํ ๋ค, VV ๋ VA ํ๊ทธ๋ฅผ ๊ฐ์ง ๋จ์ด์ '-๋ค'๋ฅผ ๋ถ์ ๋๋ค. ๋จ, '์ฌ๊ณ ์ถ๋ค' ์ ๊ฐ์ ๋ณตํฉ ์ฉ์ธ๋ '์ฌ๋ค' ๋ก ๋ณต์๋ฉ๋๋ค. ์ถ์ฒ: https://lovit.github.io/nlp/2019/01/22/trained_kor_lemmatizer/ """ lemmatizer = WordNetLemmatizer() # ํ์ฌ์ ๋ฐ๋ผ ๋จ์ด์ lemma๊ฐ ๋ฌ๋ผ์ง๋ค # (cooking, N) -> cooking / (cooking, V) -> cook def prat_lemmatize(token,tag): if tag in Noun_tags: return lemmatizer.lemmatize(token,'n') elif tag in Verb_tags: return lemmatizer.lemmatize(token,'v') else: return lemmatizer.lemmatize(token,'n') pre_proc_text = " ".join([prat_lemmatize(token,tag) for token,tag in tagged_corpus]) return pre_proc_text
-
์์ค alice in wonderland๋ฅผ ์ฝ์ด์จ๋ค.
lines = [] fin = open("./dataset/alice_in_wonderland.txt", "r") for line in fin: if len(line) == 0: continue # ์์ค txt๋ด ์ํฐ ์์ ๊ธฐ lines.append(preprocessing(line)) fin.close()
-
๋จ์ด๋ค์ด ์ฌ์ฉ๋ ํ์๋ฅผ ์นด์ดํธ ํ๋ค.
counter = collections.Counter() for line in lines: for word in nltk.word_tokenize(line): counter[word.lower()] += 1
-
์ฌ์ ์ ๊ตฌ์ถํ๋ค.
- ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋ ๋จ์ด๋ฅผ 1๋ฒ์ผ๋ก ์์ํด์ ๋ฒํธ๋ฅผ ๋ถ์ฌํ๋ค.
word2idx = {w:(i+1) for i,(w,_) in enumerate(counter.most_common())} # ex: [(apple:50), (cat: 43), ...] idx2word = {v:k for k,v in word2idx.items()} # ex: [(50: apple), (43: cat), ...]
-
Trigram์ผ๋ก ํ์ต ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ค.
xs = [] # ์ ๋ ฅ ๋ฐ์ดํฐ ys = [] # ์ถ๋ ฅ ๋ฐ์ดํฐ for line in lines: # ์ฌ์ ์ ๋ถ์ฌ๋ ๋ฒํธ๋ก ๋จ์ด๋ค์ ํ์ํ๋ค. ## ๊ฐ ๋ฌธ์ฅ์ tokenizeํด์ ์๋ฌธ์๋ก ๋ฐ๊พธ๊ณ word2idx๋ก ๋ณํ embedding = [word2idx[w.lower()] for w in nltk.word_tokenize(line)] # word2idx: value๊ฐ์ธ index๋ฒํธ๊ฐ ๋์ด # Trigram์ผ๋ก ์ฃผ๋ณ ๋จ์ด๋ค์ ๋ฌถ๋๋ค. ## .trigrams(=3)๋งํผ ๋์ด์ ์ฐ์๋ ๋ฌธ์ฅ์ผ๋ก ๋ฌถ๊ธฐ ex: triples = [(1,2,3), (3,5,3), ...] triples = list(nltk.trigrams(embedding)) # ์ผ์ชฝ ๋จ์ด, ์ค๊ฐ ๋จ์ด, ์ค๋ฅธ์ชฝ ๋จ์ด๋ก ๋ถ๋ฆฌํ๋ค. w_lefts = [x[0] for x in triples] # [1, 2, ...8] w_centers = [x[1] for x in triples] # [2, 8, ...13] w_rights = [x[2] for x in triples] # [8, 13, ...7] # ์ ๋ ฅ (xs) ์ถ๋ ฅ (xy) # --------- ----------- # 1. ์ค๊ฐ ๋จ์ด --> ์ผ์ชฝ ๋จ์ด # 2. ์ค๊ฐ ๋จ์ด --> ์ค๋ฅธ์ชฝ ๋จ์ด xs.extend(w_centers) ys.extend(w_lefts) xs.extend(w_centers) ys.extend(w_rights)
-
ํ์ต ๋ฐ์ดํฐ๋ฅผ one-hot ํํ๋ก ๋ฐ๊พธ๊ณ , ํ์ต์ฉ๊ณผ ์ํ์ฉ์ผ๋ก ๋ถ๋ฆฌํ๋ค.
vocab_size = len(word2idx) + 1 # ์ฌ์ ์ ํฌ๊ธฐ # vocab_size = 1787 # + 1 ํด์ค์ผ ๋ฐ์ ohe ํ ๋, vocab ๋๊น์ง ์ ๋ถ๋ฅผ ohe ํ ์ ์์ ohe = OneHotEncoder(categories = [range(vocab_size)]) # ohe = OneHotEncoder(categories=[range(0, 1787)]) X = ohe.fit_transform(np.array(xs).reshape(-1, 1)).todense() # .todense = .toarray()์ ๋์ผํจ: ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์ด ํํ๋ก ๋ณํ Y = ohe.fit_transform(np.array(ys).reshape(-1, 1)).todense()
X.shape = (13868, 1787) / y.shape = (13868, 1787)
STEP 2. ํ์ต์ฉ/์ํ์ฉ data๋ก ๋ถ๋ฆฌ
Xtrain, Xtest, Ytrain, Ytest, xstr, xsts = train_test_split(X, Y, xs, test_size=0.2)
# xs๋ฅผ ์ด ์ด์ ? => ๋ค์์ ๊ฐ๊น์ด ๋จ์ด๋ผ๋ฆฌ ๊ทธ๋ฆผ(plt) ๊ทธ๋ฆด ๋ ์ฐ๋ ค๊ณ
shape ์ฐธ๊ณ >
np.array(xs).shape
Out[19]: (13868,)np.array(xstr).shape
Out[20]: (11094,)np.array(xsts).shape
Out[21]: (2774,)np.array(Xtrain).shape
Out[22]: (11094, 1787)np.array(Xtest).shape
Out[23]: (2774, 1787)np.array(Ytrain).shape
Out[24]: (11094, 1787)np.array(Ytest).shape
Out[25]: (2774, 1787)
-
๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ์์ฑํ๋ค.
BATCH_SIZE = 128 NUM_EPOCHS = 20 input_layer = Input(shape = (Xtrain.shape[1],), name="input") # shape = batch(None) ๋นผ๊ณ y feature์ shape๋ง ๋ฃ์ด์ฃผ๋ฉด ๋จ first_layer = Dense(300, activation='relu', name = "first")(input_layer) first_dropout = Dropout(0.5, name="firstdout")(first_layer) second_layer = Dense(2, activation='relu', name="second")(first_dropout) third_layer = Dense(300,activation='relu', name="third")(second_layer) third_dropout = Dropout(0.5,name="thirdout")(third_layer) fourth_layer = Dense(Ytrain.shape[1], activation='softmax', name = "fourth")(third_dropout) # Ytrain.shape[1] = Xtrain์ shape๊ณผ ๋์ผํด์ผ ํจ # activation='softmax': one-hot์ด ์ถ๋ ฅ๋๊ธฐ ๋๋ฌธ์ softmax์ฌ์ผ ํจ model = Model(input_layer, fourth_layer) model.compile(optimizer = "rmsprop", loss="categorical_crossentropy")
loss="
categorical_crossentropy
": ๋ง์ฝ one-hot์ด ์๋๋ผ, ์ซ์(vocab์ index)๊ฐ ์ถ๋ ฅ๋๋ค๋ฉด, loss="sparse_categorical_crossentropy
"
-
ํ์ต
hist = model.fit(Xtrain, Ytrain, batch_size=BATCH_SIZE, epochs=NUM_EPOCHS, validation_data = (Xtest, Ytest))
-
Loss history๋ฅผ ๊ทธ๋ฆฐ๋ค
plt.plot(hist.history['loss'], label='Train loss') plt.plot(hist.history['val_loss'], label = 'Test loss') plt.legend() plt.title("Loss history") plt.xlabel("epoch") plt.ylabel("loss") plt.show()
STEP3. ๋จ์ด๋ค๋ผ๋ฆฌ์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ทธ๋ฆผ์ผ๋ก ๋ํ๋ด๋ code
-
Word2Vec ์์น ํ์ธ
# Extracting Encoder section of the Model for prediction of latent variables # ํ์ต์ด ์๋ฃ๋ ํ ์ค๊ฐ(hidden layer)์ ๊ฒฐ๊ณผ ํ์ธ: = Word2Vec layerํ์ธ. # (word2vec: word๋ฅผ vec(์์น)๋ก ํํ. ์ ๋ฒ ์์ ์์ w์ ๊ฐ์ '.get_weight()'ํด์ ํ์ธํ์ ๋์ ๊ฐ์ด ๋์ฌ ๋ฏ) encoder = Model(input_layer, second_layer) # Predicting latent variables with extracted Encoder model reduced_X = encoder.predict(Xtest) # Xtest ๋ฃ์ ๊ฒ์ฒ๋ผ ์์์ ๋จ์ด๋ฅผ ์ ๋ ฅํ๋ฉด reduced_X = ํด๋น ๋จ์ด์ Word2Vecํํ๋ก ์ถ๋ ฅ๋จ # ์ํ ๋ฐ์ดํฐ์ ๋จ์ด๋ค์ ๋ํ 2์ฐจ์ latent feature(word2vec ๋ง๋๋ layer)์ธ reduced_X๋ฅผ ๋ฐ์ดํฐ ํ๋ ์(ํ)์ผ๋ก ์ ๋ฆฌํ๋ค. final_pdframe = pd.DataFrame(reduced _X) final_pdframe.columns = ["xaxis","yaxis"] final_pdframe["word_indx"] = xsts # test ์ฉ์ด๋ฏ๋ก train/test split ํ ๋ ๊ฐ์ด ๋๋ด๋ xstr, xsts ์ค y๊ฐ์ธ xsts ์ฌ์ฉ final_pdframe["word"] = final_pdframe["word_indx"].map(idx2word) # index๋ฅผ word๋ก ๋ณํํจ # ๋ฐ์ดํฐ ํ๋ ์์์ 100๊ฐ๋ฅผ ์ํ๋งํ๋ค. rows = final_pdframe.sample(n = 100) labels = list(rows["word"]) xvals = list(rows["xaxis"]) yvals = list(rows["yaxis"])
[final_pdframe] > Out[26]: xaxis yaxis word_indx word 0 0.301799 0.000000 25 take 1 0.590210 0.810300 468 pick 2 0.672298 0.000000 1 say 3 0.408792 0.520896 9 know 4 0.387678 0.605502 30 much ... ... ... ... 2769 1.309759 0.851837 27 mock 2770 0.000000 0.423953 622 master 2771 0.196061 0.299570 83 good 2772 0.000000 0.024289 1516 deserv 2773 0.470771 0.550808 497 plan
[2774 rows x 4 columns]
-
์ํ๋ง๋ 100๊ฐ ๋จ์ด๋ฅผ 2์ฐจ์ ๊ณต๊ฐ์์ ๋ฐฐ์น
- ๊ฑฐ๋ฆฌ๊ฐ ๊ฐ๊น์ด ๋จ์ด๋ค์ ์๋ก ๊ด๋ จ์ด ๋์ ๊ฒ
plt.figure(figsize=(15, 15)) for i, label in enumerate(labels): x = xvals[i] y = yvals[i] plt.scatter(x, y) plt.annotate(label,xy=(x, y), xytext=(5, 2), textcoords='offset points', ha='right', va='bottom', fontsize=15) plt.xlabel("Dimension 1") plt.ylabel("Dimension 2") plt.show()
Skip-Gram Negative Sampling
(SGNS)
-
Skip-Gram์ softmax๋ฅผ ํ์ฉํ๊ธฐ ๋๋ฌธ์ ๊ณ์ฐ๋์ด ๋ง๋ค๋ ๋จ์ ์ sigmoid ์ฌ์ฉํ์ฌ ๋ณด์ํจ
- ๊ฐ์ด 0~1์ฌ์ด ๊ฐ์ด ์๋๋ผ, 0 ์๋๋ฉด 1์ธ ์ด์ง ๋ถ๋ฅ๋ก ๋์ด
- ๋ฐ๋ผ์ ๊ณ์ฐ๋ ๊ฐ์
-
๋ฐฉ๋ฒ:
Skip-Gram Negative Sampling
:- n-gram์ผ๋ก ์ ํํ ๋จ์ด ์์๋ label = 1์ ๋ถ์ฌํ๊ณ , ๋๋คํ๊ฒ ์ ํํ ๋จ์ด ์์๋ label = 0์ ๋ถ์ฌํด์ ์ด์ง ๋ถ๋ฅ
N-gram์ผ๋ก ์ ํํ ๋จ์ด ์์ ์๋ก ์ฐ๊ด๋ ๋จ์ด๋ก ์ธ์๋จ
- 2๊ฐ์ input์ ๊ฐ๊ฐ์ input, target ๊ฐ ์ ๋ ฅ
- ๊ฐ๊ฐ vector ๊ฐ ๊ณ์ฐ
- ๋ ๊ฐ concat(or dot or add)
- sigmoid ๊ณ์ฐํ์ฌ
- label(0 or 1) ๊ฐ์ด ๋์ค๊ฒ
- ํ์ต์ด ์๋ฃ๋ ํ์๋ ์๋์ ์ผ์ชฝ ๋คํธ์ํฌ์ ํน์ ๋จ์ด๋ฅผ ์ ๋ ฅํ๋ฉด, ๊ทธ ๋จ์ด์ ๋ํ word vector๋ฅผ ์ป์ ์ ์๋ค.
skip-gram๊ณผ skip-Gram Negative Sampling ์ฐจ์ด
Skip-Gram |
Skip-Gram Negative Sampling |
---|---|
input 1๊ฐ input: input data output: target data |
input 2๊ฐ input[1] : input data input[2] : target data output: label |
label ็ก | label ๆ: 1 or 0์ผ๋ก ์ด๋ฃจ์ด์ ธ ์์(์ด์ง๋ถ๋ฅ) n-gram์ผ๋ก ์ ํํ ๋จ์ด ์์๋ label = 1 ๋๋คํ๊ฒ ์ ํํ ๋จ์ด ์์๋ label = 0 |
์ถ๋ ฅ์ธต: softmax ์ฌ์ฉํ์ฌ 0~1์ฌ์ด์ ๊ฐ loss='categorical_crossentropy' ๋ฐ๋ผ์ argmax() ํจ |
์ถ๋ ฅ์ธต: sigmoid ์ฌ์ฉํ์ฌ ์ด์ง๋ถ๋ฅ loss="binary_crossentropy" |
๊ฑฐ๋ฆฌ ์ฐ์ฐ(cosine ๋ฑ)์ ํ์ง ์๋๋ค. latent layer์์ ๋ฒกํฐ ์ฐ์ฐ์ ํตํด ๋์จ x,y ์ขํ๋ก ๊ทธ๋ฆผ์ ๊ทธ๋ฆฌ๋๊ฐ ํด์ ๋งฅ๋ฝ ์ ๋น์ทํ ์๋ฏธ๋ฅผ ๊ฐ์ง ๋จ์ด๋ค์ ์ฐพ์๋ผ ์ ์๋ค. |
๊ฑฐ๋ฆฌ ์ฐ์ฐ์ ํ ์ ์๋ค. ๋ ๊ฐ์ input ๊ฐ์์ ๋์จ vector ๊ฐ์ ํ๋๋ก ํฉ์น ๋ dot ํจ์๋ฅผ ์ฐ๋ฉด ๊ฑฐ๋ฆฌ ์ฐ์ฐ์ ํ๋ ๊ฒ๊ณผ ๊ฐ๋ค. ์ด๋ cosine ๊ฑฐ๋ฆฌ ํจ์๋ฅผ ์ธ ์๋ ์๋ค. ๊ทธ๋ฐ๋ฐ, concate ์ด๋ add ํจ์๋ฅผ ์ฐ๋ฉด ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ ๋ชปํ๋ค. |
SGNS์ Embedding ํ์ฉ
- raw data ์ ์ฒ๋ฆฌ
- Trigram์ผ๋ก ํ์ตํ data ์์ฑ
-
๊ธ์ (1), ๋ถ์ (0) data ์์ฑ:SGNS์ฉ ํ์ต ๋ฐ์ดํฐ๋ฅผ ์์ฑ
rand_word = np.random.randint(1, len(word2idx), len(xs)) x_pos = np.vstack([xs, ys]).T x_neg = np.vstack([xs, rand_word]).T y_pos = np.ones(x_pos.shape[0]).reshape(-1,1) y_neg = np.zeros(x_neg.shape[0]).reshape(-1,1)
x_total = np.vstack([x_pos, x_neg]) y_total = np.vstack([y_pos, y_neg]) X = np.hstack([x_total, y_total]) np.random.shuffle(X)
- SGNS ๋ชจ๋ธ ๋น๋
embedding
,dot
,reshape
,sigmoid
,binary_crossentropy
๋ฑ- SGNS ๋ชจ๋ธ ํ์ต
- SGNS์ Embedding ๋ชจ๋ธ ๋ง๋ค๊ณ , ๊ทธ ๋ชจ๋ธ์ ๊ฐ์ค์น(w)๋ง ๋ฐ๋ก ๋นผ์ ์ ์ฅํจ
- ์ฌ๊ธฐ๊น์ง๊ฐ ๋ฒ์ฉ ๋ชฉ์ ์ SGNS์ Embedding์ ๋ง๋ ์ ์ฐจ.
- ์๋๋ถํด ๋ถํน์ word data์ SGNS๋ก ํ์ตํ Embedding ๊ธฐ๋ฒ์ ์ ์ฉํด๋ณด๋ ๊ฒ์
- raw data๋ก train/test data split
- ํ์ฉํ CNN ๋ชจ๋ธ ๋น๋(complie ๊น์ง)
- CNN ๋ชจ๋ธ ํ์ต ์ ์ SGNS์ Embedding์ ๊ฐ์ค์น(w) load(๋ถ๋ฌ์ค๊ธฐ)
- CNN ๋ชจ๋ธ fit ํ ๋, SKNS์์ ํ์ตํ W๋ฅผ ์ ์ฉ:
model.layers[1].set_weights(We)
- plt ๊ทธ๋ฆฌ๊ฑฐ๋ ์ฑ๋ฅ ํ์ธ
-
์ฑ๋ฅ ํ์ธ:
y_pred = model.predict(x_test) y_pred = np.where(y_pred > 0.5, 1, 0) print ("Test accuracy:", accuracy_score(y_test, y_pred))
-
Google's trained Word2Vec model:
- SGNS ๋ฐฉ์
- Pre-trained ๋ฐฉ์
- ๋ฌธ์ โ Vectorํ(์์นํ) โ ์ผ๋ฐ DL๋ก ๋ฐ๋ก ํ์ต ๊ฐ๋ฅ
์์ฉ ๋ฐ ๋ฐ์ ์ ์์ด ๊ถ๊ธํ ์
-
Word2Vec์ code ไธญ ๋น๋์์ผ๋ก index๋ฅผ ๋ถ์ฌํ์๋ค.
word2idx = {w:(i+1) for i,(w,_) in enumerate(counter.most_common())}
-
๊ทธ๋ฐ๋ฐ ๋ฐ๋ก ๋ค์, trigram์ผ๋ก ํ์ต ๋ฐ์ดํฐ๋ฅผ ๊ตฌ์ฑํ ๋
embedding = [word2idx[w.lower()] for w in nltk.word_tokenize(line)]
์ ๋ง ๋จ์ํ word2idx๋ฅผ ๋จ์ด ์ฐพ๋ ์ฉ๋๋ก๋ง ์ผ๋ค.
triples = list(nltk.trigrams(embedding))
-
๋ง์ฝ, ์ embedding์ sort ํด์ idx number๋ฅผ ์ฌ์ ๋ ฌํ๊ฑฐ๋, pre-processing ๋จ๊ณ์ embedding์ ๋ฃ๋๋ค.
๊ทธ๋ฆฌ๊ณ CNN, LSTM ๋ชจ๋ธ์ ๋๋ฆฐ๋ค๋ฉด, ๋น๋๊ฐ ๋น์ทํ ๋จ์ด๋ค๋ผ๋ฆฌ ๋ฌถ์ผ ๊ฒ์ด๋ค.
๊ทธ๋ผ ๋จ์ด์ ์ค์๋ ์์ผ๋ก ๊ฑฐ๋ฆฌ๋ฅผ ์ธก์ ํ ํ ๋ฐ, ๊ทธ๋ผ index number 1์ธ ๋จ์ด๋ฅผ ์ฐพ๊ณ , ๊ทธ ๋จ์ด์ ๋ค๋ฅธ ๋จ์ด ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํด ํน์ ์ ์ ๊ตฌ๊ฐ ์ด์ธ์ ๊ฒ๋ค์ ๋ฐ๋ก ๋ชจ์๋๋ค๋ฉด?
-
์๋ฅผ ๋ค์ด ๊ฐ์ฅ ๋ง์ด ๋์จ ๋จ์ด happy์ ๋ค๋ฅธ ๋จ์ด๋ค ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ์ธก์ ํ๊ณ , 0.5 ์ดํ์ ์ฝ์ฌ์ธ ์ ์ฌ๋์ธ ๊ฒ๋ค์ ๋ฐ๋ก ๋นผ์ Another_vocab์ ๋ชจ์๋๋ค. ๊ธฐ์กด vocab์ ๊ฒ๋ค์ ํด๋น Document, Sentence์ ํต์ฌ keyword ๋ค์ผ ๊ฑฐ๊ณ , ์ฃผ์ธ๊ณต๋ค์ด๊ฒ ์ง(๊ฒฝ์ฐ์ ๋ฐ๋ผ์ ํ์๊ฐ ์๋ ๋จ์ด์ผ์๋ ์๊ฒ ๋ค.)
์ด๋ ๊ฒ ๋ค๋ฅธ ๋ฌธ์๋ ์ด๋ฌํ process๋ฅผ ์งํํด Anothervocab2๋ฅผ ๋ง๋ ๋ค.
๊ทธ ๋ค์ Anothervocab์ Anothervocab_2์ cosine ์ ์ฌ๋๋ฅผ ๋ค์ ๊ตฌํด axis๋ก ํตํฉํ์ ๋์ ์ ์ฌ๋๋ ํด๋น ๋ฌธ์ ์ฌ์ด์ ๊ฒน์น๋ ๋จ์ด๋ค ์์น๊ฒ ์ง.
- ์ด๊ฑธ 100๋ ์น ์ ๋ฌธ data์ ๋ ๋ณ๋ก ์ ์ฉํ๋ค๋ฉด, 1988๋ ์ ๋ฌธ๊ณผ 2020๋ ์ ๋ฌธ์ด ์ ์ฌ๋๊ฐ ๋์ ๋, 1988๋ ๋ฐ 2020๋ ์ ๊ตญ๋ฏผ๋ค์ ๊ด์ฌ์ฌ๊ฐ ์ผ์นํ๋ค๊ณ ๋ณผ ์ ์์ง ์์๊น?
-
์ฐธ๊ณ :
์๋ง์ถ์ด ํํธ, blog.naver.com/chunjein
์ฝ๋ ์ถ์ฒ: ํฌ๋ฆฌ์๋ ๋ฐ๋ธ์ฌ ์ธ. 2019.01.31. ์์ฐ์ด ์ฒ๋ฆฌ ์ฟก๋ถ with ํ์ด์ฌ [ํ์ด์ฌ์ผ๋ก NLP๋ฅผ ๊ตฌํํ๋ 60์ฌ ๊ฐ์ง ๋ ์ํผ]. ์์ด์ฝ