본문 바로가기
----------책----------/밑바닥부터 시작하는 딥러닝2

CHAPTER2 - 자연어와 단어의 분산 표현

by 탶선 2020. 1. 31.
반응형

 

 

2.1 자연어 처리(NLP - Natural Language Processing)

- 자연어(natural language) : 인간의 언어

- 자연어 처리 - '자연어를 처리하는 분야

- '인간의 말을 컴퓨터에게 인해시키기 위한 기술(분야)'

2.1.1 단어의 의미

- 단어 : 의미의 최소 단위

2.2 시소러스 - 유의어 사전

- 사람이 직접 단어의 의미를 정의하는 방식

- 뜻이 같은 단어(동의어)나 뜻이 비슷한 단어(유의어) 를 한 그룹으로 분류한 사전

ex) car = auto / automobile / machine / motorcar

- 모든 단어에 대한 유의어 집합을 이용하여 단어들의 관계를 그래프로 표현 및 단어 사이의 연결 정의 가능

 ->  단어 사이의 연관성 학습 가능

문제점

- 사람의 수작업으로 레이블링

 -> 즉각적인 시대 변화에 대응 불가능

 -> 인적비용

 -> 단어사이의 미묘한 차이 표현 불가

2.3 통계 기반 기법

말뭉치(corpus) 사용

말뭉치 - 자연어 처리, 애플리케이션을 염두에 두고 수집된 데이터

전처리 - 텍스트 데이터를 단어로 분할하고 그 분할된 단어들을 단어 ID 목록으로 변환

text = 'You say goodbye and I say hello.'    

text = text.lower()    # 모든 문자 소문자로
text = text.replace('.', ' .')    # '.' 를 ' .' 로 변환
text

words = text.split(' ')    # 문장의 모든 단어를 분할
words

lower() 메서드 - 문장 첫머리의 대문자로 시작하는 단어와 소문자 단어를 똑같이 취급하기 위해

replace('.' , ' .') - 문장 끝의 마침표 고려 -> re.split() 정규표현식 메서드 사용하여 가능

word_to_id = {}                  #딕셔너리 생성
id_to_word = {}                  #딕셔너리 생성

for word in words:              # words 반복해서 word에 저장
    if word not in word_to_id:  # word가 word_to_id 안에 없으면
        new_id = len(word_to_id) # new_id에 word_to_id의 길이를 저장(1,)
        word_to_id[word] = new_id# word_to_id[word]에 번호 저장
        id_to_word[new_id] = word# id_to_workd[new_id]에 단어 저장

id_to_word[1]
word_to_id['hello']

2.3.2 단어의 분산 표현

단어를 벡터로 표현 - 분산 표현(deistributional representation)

  • 단어의 의미를 정확하게 파악 가능한 벡터 표현
  • 단어끼리의 관련성 파악 용이
  • 정량화 용이

2.3.3 분포 가설(distributional hpothesis) - '단어의 의미는 주변 단어에 의해 형성된다'

  • 단어 자체에는 의미가 없으며, 그 단어가 사용된 context가 의미를 형성
  • context - 특정 단어를 중심에 둔 주변단어
  • context의 크기(window size) - 주변 단어를 n개 포함하는 크기

2.3.4 동시발생 행렬(co-occurrence matrix)

모든 해당 단어를 표현한 벡터 - 동시발생 행렬

2.3.5 벡터 간 유사도

코사인 유사도(Cosine similarity) - 단어 벡터의 유사도 측정시 자주 사용됨

  • 분자 - 벡터의 내적
  • 분모 - 벡터의 norm( 벡터의 크기)

import numpy as np

def cos_similarity(x,y,eps = 1e-8):            # division zero 오류 방지 위한 eps
    nx = x / (np.sqrt(np.sum( x ** 2)) + eps)
    ny = y / (np.sqrt(np.sum( y ** 2)) + eps)
    return np.dot(nx,ny)

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

text = 'You say goodbye ane 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)
c0 = C[word_to_id['you']]
c1 = C[word_to_id['i']]
print(cos_similarity(c0,c1))

2.4 통계 기반 기법 개선하기

2.4.1 상호정보량(mutual information)

점별 상호 정보량 PMI (Pointwise Mutual Information)

  • 단어가 단독으로 출연한 횟수 고려
  • 두 단어의 동시발생 횟수가 0이면 $log_{2}0 = -\infty $
    • 양의 상호정보량 PPMI (Positive PMI) 사용

  • C(x),C(y) - 각 x,y 단어의 등장 횟수
  • N - 말뭉치에 포함된 단어 수

 

PPMI 문제점

  • 말뭉치의 어휘 수 증가 -> 각 단어 벡터의 차원 수 증가
  • 벡터의 원소 대부분이 0 -> 각 원소의 중요도가 낮다
  • 노이즈에 약하고 견고하지 못하다

PPMI 문제의 해결법

  • 벡터의 차원 감소

def ppmi(C, verbose = False, eps = 1e-8):
    M = np.zeros_like(C, dtype=np.float32)
    N = np.sum(C)
    S = np.sum(C, axis=0)
    total = C.shape[0] * C.shape[1]
    cnt = 0
    
    for i in range(C.shape[0]):
        for j in range(C.shape[1]):
            pmi = np.log2(C[i,j] * N / (S[j]*S[i]) + eps)
            M[i,j] = max(0,pmi)
            
            if verbose:
                cnt += 1
                if cnt % (total//100) == 0:
                    print('%.1f%% 완료' %(100*cnt/total))
    return M

 

 

 

2.4.2 차원 감소(dimensionality reduction)

벡터의 차원을 줄이는 방법(중요한 정보는 유지하며)

  • 희소벡터/행렬 (원소 대부분이 0인 벡터/행렬) 에서 중요한 축을 찾아내어 더 적은 차원으로 표현

 

SVD(Singular Value Decomposition) - 특잇값(해당 축의 중요도) 분해

임의의 행렬 X를 세 행렬(U,S,V)의 곱으로 분해(흰 부분은 원소가 0)

행렬 S에서 특잇값이 작다면 중요도가 낮다 -> 행렬 U에서 여분의 열벡터를 깎아 원래의 행렬로 근사

 

 

### 본 게시물은 밑바닥부터 시작하는 딥러닝 2를 읽고 정리한 노트입니다. ###

 

반응형

댓글