'Machine Learning/National Language Processing'에 해당하는 글 16건

언어 모델


언어 모델(Language Model) 은 단어 순서나 문장이 적합한지를 판단하고 확률을 할당한다. 


  • 통계 기반 언어 모델(SLM: Statistical Languagel Model) : n-gram
  • 인공신경망 기반 언어 모델 : Perceptron, 피드 포워드 신경망 언어 모델 (NNLM: Neural Network Language Model), GPT, Bert


현재는 GPT 나 Bert 같은 인공신경망 기반의 언어 모델이 주로 쓰이나 n-gram 도 꾸준히 자연어 처리에 사용된다.



카운터 기반의 통계적 접근


카운터 기반의 통계학적 언어 모델(SLM) 은 문서에서 이전 단어와 다음 단어의 출현 수를 계산한다. An adorable little boy 가 문서에서 100번 등장하고 다음에 is 가 30번 등장했다면, An adorable little boy 다음에 is 가 나타날 확률은 다음과 같이 나타낼 수 있다.


P(is|An adorable little boy) = count(An adorable little boy is) / count(An adorable little boy) = 30%


카운터에 기반한 확률은 코퍼스 데이터에 위 문장이 존재하지 않는다면 확률은 0 이 되므로 희소 문제(sparsity problem)가 발생하는 단점이 있지만 n-gram 이나 스무딩, 백오프 같은 일반화(generalization) 기법을 사용하여 희소 문제를 완화할 수 있다.



N-gram 언어 모델


코퍼스에서 긴 문장의 확률을 구하려 할 때 발생하는 희소 문제에서, 긴 문장을 줄이면 희소 문제 발생률을 낮출 수 있다. N-gram 은  N  개의 연속적인 단어 나열을 의미한다. "An adorable little boy is spreading smiles" 문장으로 n-gram 을 만들어 보면 아래와 같이 나눌 수 있다.


  • unigrams (N : 1)  an, adorable, little, boy, is, spreading, smiles
  • bigrams (N : 2) an adorable, adorable little, little boy, boy is, is spreading, spreading smiles
  • trigrams (N : 3) an adorable little, adorable little boy, little boy is, boy is spreading, is spreading smiles
  • 4-grams (N : 4) an adorable little boy, adorable little boy is, little boy is spreading, boy is spreading smiles
  • ...


예를 들어 'An adorable little boy is spreading _____' 처럼 spreading 다음의 단어를 예측하고 싶을 때 4-gram 을 사용하면 밑줄을 포함한 앞 단어들의 카운팅 작업을 하게 되며,  다음과 같은 식으로 표현할 수 있다.


P(w|boy is spreading) = count(boy is spreading w) / count(boy is spreading)


boy is spreading 이 문서에서 1,000번 등장하고, boy is spreading 다음에 insults가 500번, smiles 가 200번 등장했다면, insults 의 확률이 50% 로 높은 확률을 가지게 된다. 전체 문장을 고려한 언어 모델보다 카운터는 늘릴 수 있지만, 정확도가 떨어질 수 있다는 것을 알았다.


N-gram 의 n 을 어떻게 설정하느냐에 따라 카운터/성능/정확도가 달라질 수 있다. 

- n 이 커질수록, 카운트 수는 적어지고, 모델 사이즈가 커진다.

- n 이 작을수록, 카운트 수는 많아지지만, 정확도가 현실의 확률분포와 멀어진다. 


언어나 코퍼스에 따라 달라지겠지만 펄플렉서티 지표에 의하면, 일반적으로 가장 효율적인 n 은 4 로 측정되고 있다.


펄플렉서티(PPL: perplexity) 는 언어 모델의 성능을 평가하기 위한 내부 평가 지표로 perplexity(헷갈림) 의 수치가 낮을수록 성능이 좋음을 나타낸다.




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

조건부 확률이란 주어진 사건(B)이 일어났다는 가정 하에 다른 한 사건(A)이 일어날 확률(P or Pr)을 뜻하며, P(A|B)로 표기한다. 이 때 사건 A가 발생할 확률은 B에 따라 달라진다.


자연어 처리에서 조건부 확률은 언어 모델에서 적합한 단어를 추론하는데 사용될 수 있다. 예를 들어 "나는 학교에 (     )." 라는 문장에서 괄호 안에 어떤 단어가 들어가는 것이 가장 확률이 높은지 등을 파악할 때 사용될 수 있다.


조건부 확률에 나타나는 사건과의 상관 관계를 수식으로 표현하면 다음과 같다.


P(B) = B 사건이 발생할 확률

P(A) = A 사건이 발생할 확률

P(A∩B) = P(A,B) = P(A)P(B|A) = B 와 A 사건이 모두 발생할 확률

P(A|B) = P(A∩B)/P(B) = B 사건이 발생하고 A 사건이 발생할 확률

P(A,B,C,D) = P(A)P(B|A)P(C|A,B)P(D|A,B,C) = D, C, B, A 사건이 모두 발생할 확률 (조건부 확률의 연쇄법칙)

P(x1,x2,x3...xn) = P(x1)P(x2|x1)P(x3|x1,x2)...P(xn|x1...xn-1)



예제1)


전체 중고차 중 70% 가 에어컨이 있고,

전체 중고차 중 40% 가 CD 플레이어가 있다.

전체 중고차 중 90% 가 둘 중 하나 이상을 가지고 있다.

에어컨이 없는 중고차 중 CD 플레이어도 없을 확률은?

에어컨이 없는 중고차 P(B) 중 CD 플레이어도 없는 중고차 P(A) 의 확률 P(A|B)


---------------------------------------------------------------------


공식 P(A|B) = P(A,B)/P(B)

P(B) = 에어컨이 없을 확률 = 0.3

P(A,B) = 둘다 없는 확률 = 0.1

P(A|B) = P(A,B)/P(B) = 0.1 / 0.3 = 1/3


예제2)


"An adorable little boy is spreading smiles" 문장의 확률은?

(문장의 확률은 이전 단어로부터 다음 단어가 등장할 확률들의 곱으로 구성된다.)


---------------------------------------------------------------------


공식 P(x1,x2,x3...xn) = P(x1)P(x2|x1)P(x3|x1,x2)...P(xn|x1...xn-1)

P(An adorable little boy is spreading smiles) =

P(An)×

P(adorable|An)×

P(little|An adorable)×

P(boy|An adorable little)×

P(is|An adorable little boy)×

P(spreading|An adorable little boy is)×

P(smiles|An adorable little boy is spreading)




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

x와 y로 분리된 데이터에 대해 테스트 데이터를 분리할 수 있어야 한다.



사이킷런으로 분리


import numpy as np
from sklearn.model_selection import train_test_split
 
X, y = np.arange(10).reshape((52)), range(5)
 
print(X)
'''
[[0 1]
 [2 3]
 [4 5]
 [6 7]
 [8 9]]
'''
 
print(list(y))
# [0, 1, 2, 3, 4]
 
# test 데이터 비율을 20% 로 설정
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234)
 
print(X_test)  # [[8 9]]
print(y_test)  # [4]
cs



수동으로 분리


import numpy as np
 
X, y = np.arange(0,24).reshape((12,2)), range(12)
 
print(X)
'''
[[ 0  1]
 [ 2  3]
 [ 4  5]
 [ 6  7]
 [ 8  9]
 [10 11]
 [12 13]
 [14 15]
 [16 17]
 [18 19]
 [20 21]
 [22 23]]
'''
 
print(list(y))
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
 
# test 데이터 비율을 20%로 설정
n_train = int(len(X) * 0.8)  # 9
n_test = int(len(X) - n_train)  # 3
 
# train 데이터와 test 데이터 모두를 퍼센트로 구분할 경우 데이터가 누락될 수 있으므로,
# train 데이터나 test 데이터 중 하나만 선택하여 나머지와 함께 계산한다.
# 아래 예는 n_train 을 선택
X_test = X[n_train:] 
y_test = y[n_train:]
X_train = X[:n_train]
y_train = y[:n_train]
 
print(X_test)
print(list(y_test))
'''
[[18 19]
 [20 21]
 [22 23]]
[9, 10, 11]
'''
cs




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

지도 학습(Supervised Learning) 에서 질문과 그에 적합한 답을 기계에 학습시킬 때, 데이터로부터 질문(x)과 답(y)을 구분해 학습시켜야 한다. 



zip 함수로 분리


q_a = [['질문1'1], ['질문2'2], ['질문3'3]]
x, y = zip(*q_a)
 
# x = ('질문1', '질문2', '질문3')
# y = (1, 2, 3)
cs



DataFrame 으로 분리


import pandas as pd
 
data = [['질문1'1], ['질문2'2], ['질문3'3]]
columns = ['질문컬럼''답변컬럼']
 
df = pd.DataFrame(data, columns=columns)
= df['질문컬럼']
= df['답변컬럼']
print(df)
print(x)
print(y)
 
"""
  질문컬럼  답변컬럼
0  질문1     1
1  질문2     2
2  질문3     3
0    질문1
1    질문2
2    질문3
Name: 질문컬럼, dtype: object
0    1
1    2
2    3
Name: 답변컬럼, dtype: int64
"""
cs



Numpy 로 분리


import numpy as np
 
arr = np.arange(0,16).reshape(4,4)
"""
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
"""
 
res = arr[:, :2
"""
[[ 0  1]
 [ 4  5]
 [ 8  9]
 [12 13]]
"""
 
res = arr[:, 3]
# [ 3  7 11 15]
cs




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

원-핫 인코딩은 문자를 숫자로 바꾸는 기법 중 가장 기본적인 방법으로, 서로 다른 단어들의 집합(vocabulary)을 벡터의 차원으로 만들어 인덱스를 부여하고, 표현하고 싶은 단어의 인덱스에 1, 나머지는 0을 부여하는 벡터 표현 방식이다. 


원-핫 인코딩 순서

  1. 문서나 문장에서 중복 단어 제거.
  2. 각 단어에 고유 인덱스 부여.(정수 인코딩)
  3. 표현할 단어에 인덱스 1 부여, 나머지 0 부여.


from konlpy.tag import Okt
 
okt = Okt()
token = okt.morphs("이것이 원 핫 인코딩이다")
 
word2index = {}
for voca in token:
    if voca not in word2index.keys():
        word2index[voca] = len(word2index)
print(word2index)  
# {'이': 0, '것': 1, '원': 2, '핫': 3, '인코딩': 4, '이다': 5}
 
def onehot_encoding(word, dic):
    onehot_vector = [0* (len(dic))
    index = dic[word]
    onehot_vector[index] = 1
    return onehot_vector
 
print(onehot_encoding("인코딩", word2index)) 
# 원-핫 인코딩 [0, 0, 0, 0, 1, 0]
cs



Keras 원-핫 인코딩


from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.utils import to_categorical
 
text = "나랑 점심 먹으러 갈래 점심 메뉴는 햄버거 갈래 갈래 햄버거 최고야"
 
= Tokenizer()
t.fit_on_texts([text])
print(t.word_index)
# {'갈래': 1, '점심': 2, '햄버거': 3, '나랑': 4, '먹으러': 5, '메뉴는': 6, '최고야': 7}
 
sub_text = "점심 먹으러 갈래 메뉴는 햄버거 최고야"
encoded = t.texts_to_sequences([sub_text])[0]
print(encoded)
# [2, 5, 1, 6, 3, 7]
 
one_hot = to_categorical(encoded)
print(one_hot)
 
'''
[[0. 0. 1. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 1. 0. 0.]
 [0. 1. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 1. 0.]
 [0. 0. 0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 1.]]
'''
cs


원-핫 인코딩은 저장 공간 측면에서 비효율적이며 단어간 유사도를 표현할 수 없는 한계가 있지만, 다음 기법들로 다차원 공간에 유사도를 표현할 수 있다.

  • 카운트 기반의 벡터화 방법 : LSA, HAL
  • 예측 기반의 벡터화 방법 : NNLM, RNNLM, Word2Vec, FastText
  • 카운트와 예측 기반의 벡터화 방법 : GloVe




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,