일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- c
- hackthissite
- webhacking
- hackerschool
- 경제
- 러닝 스칼라
- Scala
- php
- Javascript
- c++
- Web
- backend
- 파이썬
- ChatGPT
- 인공지능
- deep learning
- Linux
- 러닝스칼라
- flask
- mysql
- BOF 원정대
- 딥러닝
- 웹해킹
- BOF
- 챗GPT
- 백엔드
- Shellcode
- 리눅스
- Python
- hacking
- Today
- Total
jam 블로그
Deep learning natural language processing nlp 1 본문
자연어 처리(Natural Language Processing, NLP)
스터디 용으로 Deep Learning from Scratch 2 책을 참고로 정리한 것입니다.
Word Embedding에 대해서 알아봅니다.
- 시소러스를 활용한 기법
- 통계 기반 기법
- 추론 기반 기법(word2vec)
- Latent semantic analysis
- Brown clustering
- Glove
- fastText
- Gensim
위와 같이 다양하게 있으며, 해당 책에서는 볼드로 된 3가지를 설명합니다.
시소러스
유의어 사전으로, '뜻이 같은 단어(동의어)'나 '뜻이 비슷한 단어(유의어)'가 한 그룹으로 분류
자연어 처리에 이용되는 시소러스는 단어 사이의 '상위, 하위' 또는 '전체, 부분' 과 같이 관계를 정의해둔 형식으로 사용합니다.
- WordNet
시소러스 종류 중 하나로 '단어 네트워크'를 이용할 수 있습니다. 또한 단어 사이의 유사도를 구할 수 있습니다.
Python library에서는 NLTK가 있습니다.
from nltk.corpus import wordnet
print(wordnet.synsets('car'))
'''
[Synset('car.n.01'), Synset('car.n.02'), Synset('car.n.03'), Synset('car.n.04'), Synset('cable_car.n.01')]
위와 같이 결과가 나오며, 'car' 단어로 'n' 명사의 그룹의 서로 다른 동의어 그룹이 5개가 있다는 뜻입니다.
'''
car = wordnet.synset('car.n.01')
print(car.definition())
'''
a motor vehicle with four wheels; usually propelled by an internal combustion engine
여기서 나오는 문자은 동의어 그룹의 의미를 뜻하며, 컴퓨터 보다는 사람이 이해 할 때 쓰입니다.
'''
car = wordnet.synset('car.n.01')
novel = wordnet.synset('novel.n.01')
dog = wordnet.synset('dog.n.01')
motorcycle = wordnet.synset('motorcycle.n.01')
print(car.path_similarity(novel))
print(car.path_similarity(dog))
print(car.path_similarity(motorcycle))
'''
0.05555555555555555
0.07692307692307693
0.3333333333333333
car 단어와 novel, dog, motorcycle 셋 단어의 유사도를 구한 것이며 다른 두 단어에 비해 motorcycle이 높은 것을 확인 할 수 있습니다.
'''
시소러스의 단점으로는
- 새로운 단어가 생겨날 수록 사람이 레이블링 하는데에 있어서 갱신이 어렵기 때문에 시대 변화에 대응하기 어렵습니다.
- 위에 얘기했다시피 사람의 손을 거쳐야 하기 때문에 비용이 큽니다.
- 단어의 쓰임새에 따라 뜻이 달라지는 미묘한 차이를 표현할 수 없습니다.
통계 기반 기법
시소러스의 문제가 있어서 나왔습니다. 여기서는 말뭉치 Corpus를 이용합니다.
다음은 매우 작은 텍스트를 사용하여 전처리 Preprocessing을 진행합니다.
text = 'You say goodbye and I say hello.' # 말뭉치
text = text.lower() # 전부 소문자로 변경
text = text.replace('.', ' .') # 마침표를 한칸 띄우는걸로 교체
words = text.split(' ') # 띄어쓰기 기준으로 분할
print(words)
'''
['you', 'say', 'goodbye', 'and', 'i', 'say', 'hello', '.']
정규식을 사용하여 분할 할 수 도 있습니다.
'''
word_to_id = {}
id_to_word = {}
for word in words:
if word not in word_to_id:
new_id = len(word_to_id)
word_to_id[word] = new_id
id_to_word[new_id] = word
print(word_to_id)
print(id_to_word)
'''
{'you': 0, 'say': 1, 'goodbye': 2, 'and': 3, 'i': 4, 'hello': 5, '.': 6}
{0: 'you', 1: 'say', 2: 'goodbye', 3: 'and', 4: 'i', 5: 'hello', 6: '.'}
'''
import numpy as np
corpus = [word_to_id[w] for w in words]
corpus = np.array(corpus)
print(corpus)
'''
[0 1 2 3 4 1 5 6]
문장을 id 값으로 전처리한 상태입니다.
'''
- 분산 표현 : 단어의 의미를 정확하게 파악할 수 잇는 벡터 표현
- 분포 가설 : 단어의 의미는 주변 단어에 의해 형성된다.
분포 가설의 주요 핵심은 단어 자체의 의미보다는 주변 단어 즉, 맥락이 의미를 형성한다 입니다. - 통계 기반 : 주변에 어떤 단어가 몇 번이나 등장하는지를 세어 집계하는 방법
- 동시발생 행렬 : 모든 단어에 대해 동시 발생하는 단어를 표로 정리
import numpy as np
def create_co_matrix(corpus, vocab_size, window_size=1):
corpus_size= len(corpus)
co_matrix = np.zeros((vocab_size, vocab_size), dtype=np.int32)
for idx, word_id in enumerate(corpus):
for i in range(1, window_size + 1):
left_idx = idx - i
right_idx = idx + i
if left_idx >= 0:
left_word_id = corpus[left_idx]
co_matrix[word_id, left_word_id] += 1
if right_idx < corpus_size:
right_word_id = corpus[right_idx]
co_matrix[word_id, right_word_id] += 1
return co_matrix
각 단어들의 벡터 사이의 유사도 측정 방식
- 벡터의 내적
- 유클리드 거리
- 코사인 유사도
코사인 유사도는 다음과 같습니다.
예를 들어 두 벡터 $ x = (x_1, x_2, x_3, \cdots , x_n), y = (y_1, y_2, y_3, \cdots , y_n) $
$$
similarity(x, y) = \frac{x \cdot y}{|x||y|}
$$
식은 부자에는 벡터의 내적이, 분모에는 각 벡터의 노름(norm) 입니다. 여기서 노름은 L2 norm 이며, 벡터의 각 원소를 제곱해 더한 후 다시 제곱근을 구해 계산합니다.
def cos_similarity(x, y, eps=1e-8):
nx = x / (np.sqrt(np.sum(x**2)) + eps)
ny = y / (np.sqrt(np.sum(y**2)) + eps)
return np.dot(nx, ny)
import numpy as np
import sys
def preprocess(text):
text = text.lower()
text = text.replace('.',' .')
words = text.split(" ")
word_to_id = {}
id_to_word = {}
for word in words:
if word not in word_to_id:
new_id = len(word_to_id)
word_to_id[word] = new_id
id_to_word[new_id] = word
corpus = np.array([word_to_id[w] for w in words])
return corpus, word_to_id, id_to_word
def create_co_matrix(corpus, vocab_size, window_size=1):
corpus_size= len(corpus)
co_matrix = np.zeros((vocab_size, vocab_size), dtype=np.int32)
for idx, word_id in enumerate(corpus):
for i in range(1, window_size + 1):
left_idx = idx - i
right_idx = idx + i
if left_idx >= 0:
left_word_id = corpus[left_idx]
co_matrix[word_id, left_word_id] += 1
if right_idx < corpus_size:
right_word_id = corpus[right_idx]
co_matrix[word_id, right_word_id] += 1
return co_matrix
def most_similar(query, word_to_id, id_to_word, word_matrix, top=5):
if query not in word_to_id:
print("%s(을)를 찾을 수 없습니다." % query)
return
print('\n[query] ' + query)
query_id = word_to_id[query]
query_vec = word_matrix[query_id]
vocab_size = len(id_to_word)
similarity = np.zeros(vocab_size)
for i in range(vocab_size):
similarity[i] = cos_similarity(word_matrix[i], query_vec)
count = 0
for i in (-1 * similarity).argsort():
if id_to_word[i] == query:
continue
print(' %s: %s' % (id_to_word[i], similarity[i]))
count += 1
if count >= top:
return
def cos_similarity(x, y):
nx = x/np.sqrt(np.sum(x**2))
ny = y/np.sqrt(np.sum(y**2))
return np.dot(nx, ny)
text = 'You say goodbye and I say hello.'
corpus, word_to_id, id_to_word = preprocess(text)
vocab_size = len(word_to_id)
C = create_co_matrix(corpus, vocab_size)
most_similar('you', word_to_id, id_to_word, C, top=5)
'''
goodbye: 0.7071067811865475
i: 0.7071067811865475
hello: 0.7071067811865475
say: 0.0
and: 0.0
'''
위에서 단어를 벡터로 표현한 것을 좀 더 개선해 봅시다.
점별 상호정보량(Pointwise Mutual Information)이라는 척도를 사용합니다.
PMI,는 확률 변수 $ x, y $에 대해 다음 식으로 정의됩니다.
$$
PMI(x, y) = log_2\frac{P(x, y)}{P(x)P(y)}
$$
위 식은 $P(x)$는 $x$가 일어날 확률, $P(y)$는 $y$가 일어날 확률, $P(x, y)$는 $x, y$가 동시에 일어날 확률을 뜻하며, 높을 수록 관련성이 높습니다.
이 공식을 위에서 만들었던 동시발생 행렬 C로 변경하면 다음과 같습니다.
$$
PMI(x, y) = log_2\frac{P(x, y)}{P(x)P(y)} = log_2\frac{\frac{C(x, y)}{N}}{\frac{C(x)}{N}\frac{C(y)}{N}} = log_2\frac{C(x,y)\cdot N}{C(x)C(y)}
$$
단점은 동시 발생 횟수가 0이면 $ log_2 0 = -\infty$ 되기에 양의 상호정보량 (PPMI) $PPMI(x, y) = max(0, PMI(x,y,))$
차원감소(Dimensionality reduction) : 노이즈를 줄이면서 최대한 중요한 정보를 유지하는게 핵심
특잇값분해(Singular Value Decomposition, SVD) : 임의의 행렬 X를 U, S, V라는 세 행렬의 곱으로 분해하며, U, V는 직교행렬, S는 대각행렬입니다.
S 행렬에서 대각 성분에는 특잇값(Singular value)가 큰 순서로 나열되어 있으며, 중요하지 않는 부분을 줄여서 차원 감소를 시행합니다.
'인공지능' 카테고리의 다른 글
DIALOGPT : Large-Scale Generative Pre-training for Conversational Response Generation (0) | 2020.03.31 |
---|---|
Extreme Language Model Compression with Optimal Subwords and Shared Projections (0) | 2019.12.18 |
Deep learning one hot encoding (0) | 2019.10.20 |
Artificial Neural Network 2 (0) | 2019.10.20 |
Artificial Neural Network 1 (0) | 2019.10.20 |