by museonghwang

문서 단어 행렬(Document-Term Matrix, DTM) 개념 이해

|

  1. 문서 단어 행렬(Document-Term Matrix, DTM) 개념
  2. 문서 단어 행렬(DTM)의 표현
  3. 문서 단어 행렬(DTM)의 한계점
    • 3.1 희소 행렬 표현(Sparse Matrix Representation)
    • 3.2 단순 빈도수 기반 단어 표현

카운트 기반의 단어 표현방법 중 하나인 문서 단어 행렬(DTM)의 개념에 대해 알아보겠습니다.



1. 문서 단어 행렬(Document-Term Matrix, DTM) 개념

문서 단어 행렬(Document-Term Maxtrix, DTM)다수의 문서 데이터(=Corpus)에서 등장한 모든 단어의 출현 빈도수(frequency)를 행렬로 표현한 것 입니다. 행과 열을 반대로 선택하면 TDM 이라고 부르기도 합니다. 즉, DTM은 각 문서 데이터에 대한 Bag of Words(BoW)를 행렬로 만든 것으로 생각 할 수 있으며, BoW와 다른 표현 방법이 아니라 BoW 표현을 다수의 문서에 대해서 행렬로 표현하고 부르는 용어 입니다.

DTM은 국소 표현(Local Representation) 또는 이산 표현(Discrete Representation)의 일종으로 카운트 기반의 단어 표현방법입니다.


2. 문서 단어 행렬(DTM)의 표현

DTM 예시를 들어보겠습니다. 예를 들어 4개의 문서가 있다고 하겠습니다.

  1. 문서 1 : 먹고 싶은 사과
  2. 문서 2 : 먹고 싶은 바나나
  3. 문서 3 : 길고 노란 바나나 바나나
  4. 문서 4 : 저는 과일이 좋아요


문서 내 띄어쓰기를 기준으로 토큰화(tokenization)한다고 가정하겠습니다. 토큰화는 문장을 여러 단위의 덩어리로 쪼개는 작업이라 생각하시면 됩니다. 문서별 단어의 출현 빈도수를 행렬로 표현하면 아래 표와 같습니다.

- 과일이 길고 노란 먹고 바나나 사과 싶은 저는 좋아요
문서1 0 0 0 1 0 1 1 0 0
문서2 0 0 0 1 1 0 1 0 0
문서3 0 1 1 0 2 0 0 0 0
문서4 1 0 0 0 0 0 0 1 1


image


각 문서에서 등장한 단어의 빈도를 행렬의 값으로 표기 합니다. 문서 단어 행렬(DTM)은 문서들을 서로 비교할 수 있도록 수치화할 수 있다는 점에서 의의를 갖습니다. 만약 필요에 따라서는 형태소 분석기로 단어 토큰화를 수행하고, 불용어에 해당되는 조사들 또한 제거하여 더 정제된 DTM을 만들 수도 있을 것입니다.


3. 문서 단어 행렬(DTM)의 한계점

DTM은 매우 간단하고 구현하기도 쉽지만, 본질적으로 가지는 몇 가지 한계들이 있습니다.


3.1 희소 행렬 표현(Sparse Matrix Representation)

원-핫 벡터는 단어 집합의 크기가 벡터의 차원이 되고 대부분의 값이 0이 되는 벡터로, 공간적 낭비와 계산 리소스를 증가시킬 수 있다는 점에서 단점을 가지는데, DTM도 마찬가지입니다. DTM희소 벡터(sparse vector) 또는 희소 행렬 표현(Sparse Matrix Representation) 문제 로 인해 높은 계산 복잡도와 저장공간 낭비 문제 가 있습니다. 희소 행렬 표현이란 대부분의 값이 0으로 표현된 행렬 을 말합니다. 희소 행렬 표현으로 인한 문제점을 알아보겠습니다.

  1. 높은 계산 복잡도
    • DTM은 문서 개수와 문서 내 모든 단어 집합의 크기만큼의 차원을 갖습니다.
    • 즉, 문서 데이터가(=row 개수) 방대해질수록 단어 집합의 크기(=column 개수)는 기하급수적으로 증가하기 때문에, DTM은 수만, 수십만 이상의 차원을 가질 수 있습니다.
    • 차원의 개수가 커진 만큼 계산의 복잡도는 증가하기 때문에 리소스 낭비를 유발합니다.
  2. 저장공간 낭비
    • DTM은 대부분의 column이 0인 행렬 표현방식임에도 불구하고, 단어 집합의 크기만큼 차원을 갖기 때문에 저장공간의 낭비를 유발합니다.
    • 이러한 행렬을 희소 행렬 표현이라고 부르는데, 불필요하게 많은 차원의 행렬을 사용하기 때문에 저장공간의 낭비를 유발합니다.


이러한 이유로 전처리를 통해 단어 집합의 크기를 줄이는 일은 BoW 표현을 사용하는 모델에서 중요할 수 있습니다. 구두점, 빈도수가 낮은 단어, 불용어를 제거하고, 어간이나 표제어 추출을 통해 단어를 정규화하여 단어 집합의 크기를 줄이는 텍스트 전처리 방법을 사용할 수 있습니다.


3.2 단순 빈도수 기반 단어 표현

DTM은 문서 데이터에서 단어의 빈도수만 고려하기 때문에 중요 단어와 불필요한 단어를 구분하기 어렵다는 한계가 있습니다. 예를 들어 문장에서 어떤 의미를 갖지 않지만 여러 문서에서 공통적으로 빈출 되는 단어가 있는데, 바로 불용어(stop word)입니다. 영어에 대해서 DTM을 만들었을 때, 불용어인 the는 어떤 문서이든 자주 등장할 수 밖에 없습니다. 그런데 유사한 문서인지 비교하고 싶은 문서1, 문서2, 문서3에서 동일하게 the가 빈도수가 높다고 해서 이 문서들이 유사한 문서라고 판단해서는 안 됩니다.

각 문서에는 중요한 단어와 불필요한 단어들이 혼재되어 있습니다. 불용어(stopwords)와 같은 단어들은 빈도수가 높더라도 자연어 처리에 있어 의미를 갖지 못하는 단어입니다. 그럼 문서에서 의미있는 단어를 추출하기 위해서는 어떻게 해야 할까요? 문서에서 단어의 출현빈도뿐만 아니라 단어의 중요도까지 고려하는 방법 이 있습니다. 즉, 문서에서 중요한 단어는 높은 가중치를 부여하고, 덜 중요한 단어는 낮은 가중치를 부여하는 방법 입니다. 이러한 방법을 적용한 것이 TF-IDF(Term Frequency-Inverse Document Frequency) 입니다.

Read more

BoW(Bag of Words) 개념 및 실습

|

  1. Bag of Words 개념
  2. Bag of Words 특징
  3. Bag of Words 생성 절차
  4. Bag of Words 실습(1) - 한국어 BoW 만들기
  5. Bag of Words 실습(2) - CountVectorizer 클래스로 BoW 만들기
  6. Bag of Words 실습(2) - 불용어를 제거한 BoW 만들기
    • 6.1 사용자가 직접 정의한 불용어 사용
    • 6.2 CountVectorizer에서 제공하는 자체 불용어 사용
    • 6.3 NLTK에서 지원하는 불용어 사용

카운트 기반의 단어 표현 방법인 Bag of Words(BoW) 개념과 생성 방법을 알아보겠습니다.



1. Bag of Words 개념

BoW(Bag of Words) 는 단어를 수치화하는 방법 중 하나로, 문서 내 단어들의 순서와 의미는 고려하지 않고 오직 출현 빈도(frequency)만 고려하여 단어를 표현하는 방법 입니다.

BoW는 국소 표현방법(Local Representation) 또는 이산 표현방법(Discrete Representation)의 일종으로 카운트 기반의 단어 표현방법(Count-based Word Representation)이라고 부릅니다.


2. Bag of Words 특징

BoW어떤 단어들이 몇 회 나왔는지는 파악할 수 있지만, 단어들이 어떤 순서로 구성되었는지는 파악할 수 없다는 특징 이 있습니다. Bag of Words를 직역하면 말 그대로 단어들의 가방 을 의미합니다. 가방에 문장의 단어들을 넣고 흔든다면, 단어의 순서는 무의미해집니다. 즉, 단어의 순서는 무시하고, 오직 단어의 빈도수에만 집중하는 방법 입니다.

image


3. Bag of Words 생성 절차

BoW를 만드는 과정은 두 가지의 절차로 생성됩니다.

  1. 문서 내 단어별로 고유의 정수 인덱스를 할당하여 단어 집합(Vocabulary) 생성
  2. 각 단어별 인덱스에 단어 토큰의 출현 빈도를 저장한 BoW 벡터 생성


4. Bag of Words 실습(1) - 한국어 BoW 만들기

한국어 예제를 통해서 BoW에 대해서 이해해보도록 하겠습니다. 우선 문서1이 다음과 같이 작성되어있다고 가정하겠습니다.

문서1 : 정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다.


문서1에 대해서 BoW를 만들어보겠습니다. 아래의 함수는 입력된 문서에 대해서 단어 집합(vocaburary)을 만들어 각 단어에 정수 인덱스를 할당하고, BoW를 만듭니다.

# pip install konlpy
from konlpy.tag import Okt

okt = Okt()

def build_bag_of_words(document):
    # 온점 제거 및 형태소 분석
    document = document.replace('.', '')
    tokenized_document = okt.morphs(document)
    print('tokenized_document :', tokenized_document)

    # 단어별 고유의 정수 인덱스를 할당할 단어 집합(Vocabulary)
    word_to_index = {}
    # 단어별 인덱스에 단어의 출현빈도를 저장할 BoW 벡터
    bow = []

    for word in tokenized_document:
        # 처음 출현한 단어인 경우(=단어 집합에 미존재)
        if word not in word_to_index.keys():
            # 단어가 등장한 순서를 정수 인덱스로 부여
            word_to_index[word] = len(word_to_index)
            # 처음 등장한 단어이므로 BoW에 전부 기본값 1을 넣는다.
            bow.insert(len(word_to_index) - 1, 1)
        
        # 출현 이력이 있는 단어의 경우
        else:
            # 재등장하는 단어의 인덱스
            index = word_to_index.get(word)
            # 재등장한 단어는 해당하는 인덱스의 위치에 1을 더한다.
            bow[index] = bow[index] + 1
    
    return word_to_index, bow


해당 함수에 문서1을 입력으로 넣어보겠습니다.

doc1 = "정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다."

vocab, bow = build_bag_of_words(doc1)

print('vocabulary :', vocab)
print('bag of words vector :', bow)
[output]
tokenized_document : ['정부', '가', '발표', '하는', '물가상승률', '과', '소비자', '가', '느끼는', '물가상승률', '은', '다르다']
vocabulary : {'정부': 0, '가': 1, '발표': 2, '하는': 3, '물가상승률': 4, '과': 5, '소비자': 6, '느끼는': 7, '은': 8, '다르다': 9}
bag of words vector : [1, 2, 1, 1, 2, 1, 1, 1, 1, 1]


문서1에 대해 온점 제거 및 형태소 분석을 한 결과는 첫번째 출력, 문서1에 각 단어에 대해서 인덱스를 부여한 결과는 두번째 출력, 문서1의 BoW는 세번째 출력 결과입니다.

세번째 출력 결과를 보면, 인덱스 4에 해당하는 물가상승률은 두 번 언급되었기 때문에 인덱스 4에 해당하는 값이 2입니다. 만약, 한국어에서 불용어에 해당되는 조사들 또한 제거한다면 더 정제된 BoW를 만들 수도 있습니다.


다음은 문서2가 다음과 같이 작성되어있다고 가정하겠습니다.

문서2 : 소비자는 주로 소비하는 상품을 기준으로 물가상승률을 느낀다.


위 함수에 문서2를 입력으로 넣어보겠습니다.

doc2 = '소비자는 주로 소비하는 상품을 기준으로 물가상승률을 느낀다.'

vocab, bow = build_bag_of_words(doc2)

print('vocabulary :', vocab)
print('bag of words vector :', bow)
[output]
tokenized_document : ['소비자', '는', '주로', '소비', '하는', '상품', '을', '기준', '으로', '물가상승률', '을', '느낀다']
vocabulary : {'소비자': 0, '는': 1, '주로': 2, '소비': 3, '하는': 4, '상품': 5, '을': 6, '기준': 7, '으로': 8, '물가상승률': 9, '느낀다': 10}
bag of words vector : [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1]


문서1과 문서2를 합쳐서 문서 3이라고 명명하고, BoW를 만들 수도 있습니다.

문서2 : 정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다. 소비자는 주로 소비하는 상품을 기준으로 물가상승률을 느낀다.


doc3 = doc1 + ' ' + doc2
print('doc3 :', doc3)

vocab, bow = build_bag_of_words(doc3)
print('\nvocabulary :', vocab)
print('bag of words vector :', bow)
[output]
doc3 : 정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다. 소비자는 주로 소비하는 상품을 기준으로 물가상승률을 느낀다.

tokenized_document : ['정부', '가', '발표', '하는', '물가상승률', '과', '소비자', '가', '느끼는', '물가상승률', '은', '다르다', '소비자', '는', '주로', '소비', '하는', '상품', '을', '기준', '으로', '물가상승률', '을', '느낀다']
vocabulary : {'정부': 0, '가': 1, '발표': 2, '하는': 3, '물가상승률': 4, '과': 5, '소비자': 6, '느끼는': 7, '은': 8, '다르다': 9, '는': 10, '주로': 11, '소비': 12, '상품': 13, '을': 14, '기준': 15, '으로': 16, '느낀다': 17}
bag of words vector : [1, 2, 1, 2, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1]


문서3의 단어 집합은 문서1과 문서2의 단어들을 모두 포함하고 있는 것들을 볼 수 있습니다. BoW는 종종 여러 문서의 단어 집합을 합친 뒤에, 해당 단어 집합에 대한 각 문서의 BoW를 구하기도 합니다. 가령, 문서3에 대한 단어 집합을 기준으로 문서1, 문서2의 BoW를 만든다고 한다면 결과는 아래와 같습니다.

문서3 단어 집합에 대한 문서1 BoW : [1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
문서3 단어 집합에 대한 문서2 BoW : [0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1]


문서3 단어 집합에서 물가상승률이라는 단어는 인덱스가 4에 해당됩니다. 물가상승률이라는 단어는 문서1에서는 2회 등장하며, 문서2에서는 1회 등장하였기 때문에 두 BoW의 인덱스 4의 값은 각각 2와 1이 되는 것을 볼 수 있습니다.

BoW각 단어가 등장한 횟수를 수치화하는 텍스트 표현 방법 이므로 주로 어떤 단어가 얼마나 등장했는지를 기준으로 문서가 어떤 성격의 문서인지를 판단하는 작업에 쓰입니다. 즉, 분류 문제나 여러 문서 간의 유사도를 구하는 문제에 주로 쓰입니다. 가령, ‘달리기’, ‘체력’, ‘근력’과 같은 단어가 자주 등장하면 해당 문서를 체육 관련 문서로 분류할 수 있을 것이며, ‘미분’, ‘방정식’, ‘부등식’과 같은 단어가 자주 등장한다면 수학 관련 문서로 분류할 수 있습니다.


5. Bag of Words 실습(2) - CountVectorizer 클래스로 BoW 만들기

사이킷런에서는 단어의 빈도를 Count하여 Vector로 만드는 CountVectorizer 클래스를 지원합니다. 이를 이용하면 영어에 대해서는 손쉽게 BoW를 만들 수 있습니다.

from sklearn.feature_extraction.text import CountVectorizer

corpus = ['you know I want your love. because I love you.']
vector = CountVectorizer()

# 코퍼스로부터 각 단어의 빈도수를 기록
print('bag of words vector :', vector.fit_transform(corpus).toarray()) 

# 각 단어의 인덱스가 어떻게 부여되었는지를 출력
print('vocabulary :', vector.vocabulary_)
[output]
bag of words vector : [[1 1 2 1 2 1]]
vocabulary : {'you': 4, 'know': 1, 'want': 3, 'your': 5, 'love': 2, 'because': 0}


예제 문장에서 you와 love는 두 번씩 언급되었으므로 각각 인덱스 2와 인덱스 4에서 2의 값을 가지며, 그 외의 값에서는 1의 값을 가지는 것을 볼 수 있습니다. 주의할 것은 CountVectorizer단지 띄어쓰기만을 기준으로 단어를 자르는 낮은 수준의 토큰화를 진행하고 BoW를 만든다는 점 입니다. 이는 영어의 경우 띄어쓰기만으로 토큰화가 수행되기 때문에 문제가 없지만 한국어에 CountVectorizer를 적용하면, 조사 등의 이유로 제대로 BoW가 만들어지지 않음을 의미 합니다.

예를 들어, ‘정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다.’ 라는 문장을 CountVectorizer를 사용하여 BoW로 만들 경우, CountVectorizer는 ‘물가상승률’이라는 단어를 인식하지 못 합니다. CountVectorizer는 띄어쓰기를 기준으로 분리한 뒤에 ‘물가상승률과’와 ‘물가상승률은’으로 조사를 포함해서 하나의 단어로 판단하기 때문에 서로 다른 두 단어로 인식 합니다.


6. Bag of Words 실습(2) - 불용어를 제거한 BoW 만들기

BoW 를 사용한다는 것은 그 문서에서 각 단어가 얼마나 자주 등장했는지를 보겠다는 것 입니다. 그리고 각 단어에 대한 빈도수를 수치화 하겠다는 것 은 결국 텍스트 내에서 어떤 단어들이 중요한지를 보고싶다는 의미를 함축 하고 있습니다. 불용어는 자연어 처리에서 별로 의미를 갖지 않는 단어들입니다. 그렇다면 BoW를 만들때 불용어를 제거하는 일은 자연어 처리의 정확도를 높이기 위해서 선택할 수 있는 전처리 기법입니다.

영어의 BoW를 만들기 위해 사용하는 CountVectorizer는 불용어를 지정하면, 불용어는 제외하고 BoW를 만들 수 있도록 불용어 제거 기능을 지원하고 있습니다.

from sklearn.feature_extraction.text import CountVectorizer
from nltk.corpus import stopwords


6.1 사용자가 직접 정의한 불용어 사용

text = ["Family is not an important thing. It's everything."]
vect = CountVectorizer(stop_words=["the", "a", "an", "is", "not"])

print('bag of words vector :', vect.fit_transform(text).toarray())
print('vocabulary :', vect.vocabulary_)
[output]
bag of words vector : [[1 1 1 1 1]]
vocabulary : {'family': 1, 'important': 2, 'thing': 4, 'it': 3, 'everything': 0}


6.2 CountVectorizer에서 제공하는 자체 불용어 사용

text = ["Family is not an important thing. It's everything."]
vect = CountVectorizer(stop_words="english")

print('bag of words vector :', vect.fit_transform(text).toarray())
print('vocabulary :', vect.vocabulary_)
[output]
bag of words vector : [[1 1 1]]
vocabulary : {'family': 0, 'important': 1, 'thing': 2}


6.3 NLTK에서 지원하는 불용어 사용

import nltk
# nltk.download('stopwords')

text = ["Family is not an important thing. It's everything."]
stop_words = stopwords.words("english")
vect = CountVectorizer(stop_words=stop_words)

print('bag of words vector :', vect.fit_transform(text).toarray()) 
print('vocabulary :', vect.vocabulary_)
[output]
bag of words vector : [[1 1 1 1]]
vocabulary : {'family': 1, 'important': 2, 'thing': 3, 'everything': 0}

Read more

단어의 표현 방법(Vectorization)

|

텍스트를 컴퓨터가 이해하고, 효율적으로 처리하게 하기 위해서는 컴퓨터가 이해할 수 있도록 텍스트를 적절히 숫자로 변환해야 합니다. 자연어 처리에서 텍스트를 수치적으로 표현하는 방법으로는 여러가지 방법이 있습니다. 왜냐하면 단어를 표현하는 방법에 따라서 자연어 처리의 성능이 크게 달라지기 때문입니다.

텍스트를 수치적으로 표현하면, 통계적인 접근 방법을 통해 여러 문서로 이루어진 텍스트 데이터가 있을 때 어떤 단어가 특정 문서 내에서 얼마나 중요한 것인지를 나타내거나, 문서의 핵심어 추출, 검색 엔진에서 검색 결과의 순위 결정, 문서들 간의 유사도를 구하는 등의 용도로 사용할 수 있습니다.



1. 단어의 표현 방법

단어의 표현 방법 은 크게 두 가지가 있습니다.

  1. 국소 표현(Local Representation) 방법
    • 이산 표현 (Discrete Representation)
    • 국소 표현 방법은 해당 단어 그 자체만 보고, 각 단어에 특정값(숫자)을 맵핑하여 단어를 표현하는 방법
    • 예를 들어 puppy(강아지), cute(귀여운), lovely(사랑스러운)라는 단어가 있을 때, 각 단어에 1번, 2번, 3번 같이 숫자를 맵핑(mapping)하여 부여한다면 이는 국소 표현 방법에 해당
  2. 분산 표현(Distributed Representation) 방법
    • 연속 표현 (Continuous Representation)
    • 분산 표현 방법은 단어를 표현하기위해 주변을 참고하여 단어를 표현하는 방법
    • 예를 들어 puppy(강아지), cute(귀여운), lovely(사랑스러운)라는 단어가 있을 때, puppy(강아지)라는 단어 근처에는 주로 cute(귀여운), lovely(사랑스러운)이라는 단어가 자주 등장하므로, puppy라는 단어는 cute, lovely한 느낌이다로 단어를 정의한다면 이는 분산 표현 방법에 해당


이렇게 되면 이 두 방법의 차이는 국소 표현 방법 은 단어의 의미나 뉘앙스를 표현할 수 없지만, 분산 표현 방법은 단어의 뉘앙스를 표현할 수 있게 됩니다.

image


One-hot Vector, N-gram, Bag of Words국소 표현(Local Representation) 에 속합니다. 특히 Bag of Words는 단어의 빈도수를 카운트(Count)하여 단어를 수치화하는 단어 표현 방법이며, 그의 확장인 DTM, 그리고 이러한 빈도수 기반 단어 표현에 단어의 중요도에 따른 가중치를 줄 수 있는 TF-IDF 등이 있습니다.

워드 임베딩연속 표현(Continuous Representation) 에 속하면서, 예측(prediction)을 기반으로 단어의 뉘앙스를 표현하는 워드투벡터(Word2Vec) 와 그의 확장인 패스트텍스트(FastText) 가 있고, 예측과 카운트라는 두 가지 방법이 모두 사용된 글로브(GloVe) 방법 등이 존재합니다.


2. 국소 표현(Local Representation)

단어를 표현하는 가장 기본적인 방법은 원-핫 인코딩(one-hot encoding) 방식 이며, 대표적인 Local Representation 방법 입니다. 원-핫 인코딩은 전체 단어 집합의 크기(중복은 카운트하지 않은 단어들의 집합)를 벡터의 차원으로 가지며, 각 단어에 고유한 정수 인덱스를 부여하고, 해당 인덱스의 원소는 1, 나머지 원소는 0을 가지는 벡터로 만듭니다.

image


  • 장점
    • 방법 자체가 매우 간단하고 이해하기 쉬움
  • 단점
    • 단어 벡터가 단어의 의미나 특성을 전혀 표현할 수 없으므로, 단어 벡터 간 유의미한 유사도를 구할 수 없다는 한계가 존재
    • 단어의 벡터의 크기가 매우 크고, 값이 희소(sparse). 즉 실제 사용하는 값은 1이 되는 값 하나 뿐이므로 매우 비효율적


이 문제를 해결하기 위해 벡터의 크기가 작으면서도 벡터의 단어의 의미를 표현할 수 있는 방법 들이 제안되었습니다. 이러한 방법들은 분포 가설(Distributed hypothesis)을 기반 으로 합니다.


3. 분산 표현(Distributed Representation)

분포 가설이란 “같은 문맥의 단어, 즉 비슷한 위치에 나오는 단어는 비슷한 의미를 가진다.”라는 개념으로, 분포 가설을 기반으로 하는 벡터의 크기가 작으면서도 단어의 의미를 표현할 수 있는 방법은 크게 두 가지 방법으로 나뉩니다.

  • 카운트 기반(count-base) 방법
    • 특정 문맥 안에서 단어들이 동시에 등장하는 횟수를 직접 세는 방법
    • 기본적으로 동시 출현 행렬(Co-occurence Matrix)을 만들고 그 행렬들을 변형하는 방식을 사용
  • 예측(predictive) 방법
    • 신경망 등을 통해 문맥 안의 단어들을 예측하는 방법
    • 신경망 구조 혹은 어떠한 모델을 사용해 특정 문맥에서 어떤 단어가 나올지를 예측하면서 단어를 벡터로 만드는 방식을 사용
      • Word2vec
      • NNLM(Nenural Netwrok Language Model)
      • RNNLM(Recurrent Neural Netwrok Language Model)


4. 워드 임베딩(Word Embedding)

워드 임베딩(Word Embedding)(벡터 공간(Vector)으로 + 끼워넣는다(embed))은 단어를 벡터로 표현하는 방법 으로, 연속 표현(Continuous Representation) 에 속하며, 단어를 밀집 표현으로 변환 합니다.

image


희소 표현, 밀집 표현, 그리고 워드 임베딩에 대한 용어 정리를 하겠습니다.


4.1 희소 표현(Sparse Representation)

데이터를 벡터 또는 행렬을 기반으로 수치화하여 표현할 때 극히 일부의 인덱스만 특정 값으로 표현하고, 대부분의 나머지 인덱스는 의미 없는 값으로 표현하는 방법, 즉 값의 대부분이 0으로 표현되는 방법희소 표현(sparse representation) 이라고 합니다. 원-핫 벡터는 전체 단어 집합의 크기를 갖는 벡터에서 표현할 단어의 인덱스만 1로 나타내고, 나머지는 모두 0으로 표현하는 기법으로 희소 벡터(sparse vector) 입니다.

희소 벡터의 문제점은 단어의 개수가 늘어나면 벡터의 차원이 한없이 커져 고차원의 벡터가 되어 불필요한 벡터 공간의 낭비를 유발한다는 점 입니다. 예를 들어 단어가 10,000개 있고 인덱스가 0부터 시작하면서 ‘you’이라는 단어의 인덱스가 3였다면 원 핫 벡터는 다음과 같이 표현되며, 이때 1 뒤의 0의 수는 9996개 입니다.

[you = [0, 0, 1, 0, 0, …, 0]]

image


이러한 희소 벡터 표현은 공간적 낭비를 유발 합니다. 더불어, 카운트 기반의 단어 표현기법 중 하나인 단어문서행렬(Document Term Matrix, DTM) 역시 희소표현을 사용합니다. 이러한 원-핫 인코딩, 카운트 기반 단어 표현기법은 단어의 의미를 반영하지 못합니다. 왜냐하면 단어의 의미는 고려하지 않고 단순히 어떤 단어가 문서에서 몇 번 등장했는지만 고려하기 때문입니다.


4.2 밀집 표현(Dense Representation)

밀집 표현(dense representation) 은 희소 표현과 반대되는 단어표현 방법으로써 텍스트를 실숫값으로 구성하고, 벡터의 차원을 단어 집합의 크기로 상정하지 않고 사용자가 설정한 차원의 벡터로 표현합니다. 희소 표현에서는 단어 집합의 크기만큼 벡터 또는 행렬의 차원이 결정되고, 표현할 단어만 1이 아닌 정수로, 나머지는 0으로 표현했습니다. 반면, 밀집 표현 은 사용자가 임의로 설정한 차원에서, 단순히 0 또는 1의 값만으로 데이터를 표현하는 것이 아닌 실숫값으로 표현합니다.

앞서 활용한 예시에서, 벡터는 단어의 인덱스를 제외한 단어 집합의 크기만큼 0의 값을 가졌습니다. 사용자가 벡터의 크기를 64로 설정했다면, 밀집 표현으로 해당 단어를 표현하면 다음과 같이 64차원을 갖는 벡터 형태로 나타낼 수 있습니다.

[Apple = [0.4, 0.7, …, -0.1]]

image


이 경우 벡터의 차원의 크기를 줄이고(조밀해짐) 실숫값을 밀집하여 표현했다고 해서 밀집 벡터(Dense Vector) 라고 부릅니다.


4.3 워드 임베딩(Word Embedding)

워드 임베딩(Word Embedding) 이란 단어를 밀집 벡터(dense vector)의 형태로 표현하는 기법입니다. 여기서 임베딩을 통해 얻은 결과인 밀집 터를 임베딩 벡터(Embedding Vector) 라고 부릅니다. 워드 임베딩 방법론으로는 LSA, Word2Vec, Glove, FastText, ELMO 등이 있습니다.

- 원-핫 벡터 임베딩 벡터
차원 고차원(단어 집합의 크기) 저차원
다른 표현 희소 벡터의 일종 밀집 벡터의 일종
표현 방법 수동 훈련 데이터로부터 학습함
값의 타입 1과 0 실수


5. Vectorization

결국 텍스트를 컴퓨터가 이해하고, 효율적으로 처리하게 하기 위해서는 컴퓨터가 이해할 수 있도록 텍스트를 적절히 숫자로 변환해야 하며, 이를 Vectorization 이라 지칭할 수 있습니다. 상황별 Vectorization을 정리하겠습니다.

  1. 벡터화에 신경망을 사용하지 않을 경우
    • 단어에 대한 벡터 표현 방법 : 원-핫 인코딩
    • 문서에 대한 벡터 표현 방법 : Document Term Matrix(DTM), TF-IDF
  2. 벡터화에 신경망을 사용하는 경우 (2008 ~ 2018)
    • 단어에 대한 벡터 표현 방법 : 워드 임베딩(Word2Vec, GloVe, FastText, Embedding layer)
    • 문서에 대한 벡터 표현 방법 : Doc2Vec, Sent2Vec
  3. 문맥을 고려한 벡터 표현 방법 (2018 - present)
    • ELMo, BERT
    • Pretrained Language Model의 시대

Read more

인공 신경망 언어 모델(NNLM)과 RNN 언어 모델(RNNLM)

|

  1. 기존 N-gram 언어 모델의 한계
  2. 단어의 의미적 유사성
  3. 피드 포워드 신경망 언어 모델(Neural Network Language Model, NNLM)
  4. NNLM의 이점 : 희소 문제(sparsity problem) 해결
  5. NNLM의 한계점 : 고정된 길이의 입력(Fixed-length input)
  6. RNN 언어 모델(Recurrent Neural Network Language Model, RNNLM)



1. 기존 N-gram 언어 모델의 한계

언어 모델(Language Model, LM) 이란 언어라는 현상을 모델링하고자 단어 시퀀스(문장)에 확률을 할당(assign)하는 모델 입니다. 이때 언어 모델의 전통적인 접근 방법인 통계적 언어 모델(Statistical Language Model, SLM)카운트에 기반하여 이전 단어로부터 다음 단어에 대한 확률을 계산 합니다.

다음은 이전 단어들로부터 다음 단어를 예측하는 SLM 기반(N-gram)의 언어 모델링(Language Modeling) 의 예를 보여줍니다.

# 다음 단어 예측하기
An adorable little boy is spreading ____


n-gram 언어 모델은 언어 모델링에 바로 앞 n-1 개의 단어를 참고합니다. 4-gram 언어 모델이라고 가정했을때, 모델은 바로 앞 3개의 단어만 참고하며 더 앞의 단어들은 무시합니다. 이후 훈련 코퍼스에서 (n-1)-gram 을 카운트한 것을 분모로, n-gram 을 카운트한 것을 분자로 하여 다음 단어가 등장 확률을 예측합니다.

image


하지만 SLM 기반의 언어 모델충분한 데이터를 관측하지 못하여 언어를 정확히 모델링하지 못하는 문제 가 있는데 이를 희소 문제(sparsity problem) 라고 합니다.

예를 들어 훈련 코퍼스에 ‘boy is spreading smiles’ 라는 단어 시퀀스가 존재하지 않으면 n-gram 언어 모델에서 해당 단어 시퀀스의 확률 $P (smiles \mid boy\ is\ spreading)$ 는 0이 됩니다. 이는 언어 모델이 판단하기에 ‘boy is spreading’ 다음에는 ‘smiles’ 이란 단어가 나올 수 없다는 의미이지만, 해당 단어 시퀀스는 현실에서 존재 가능한 시퀀스이므로 적절한 모델링이 아닙니다.


2. 단어의 의미적 유사성

희소 문제는 기계가 단어의 의미적 유사성을 알 수 있다면 해결할 수 있는 문제 입니다. 예를 들어, 저는 최근 ‘톺아보다’라는 생소한 단어를 배웠고, ‘톺아보다’가 ‘샅샅이 살펴보다’와 유사한 의미임을 학습했습니다. 그리고 ‘발표 자료를 살펴보다’라는 표현 대신 ‘발표 자료를 톺아보다’라는 표현을 써봤습니다. 저는 ‘발표 자료를 톺아보다’라는 예문을 어디서 읽은 적은 없지만 두 단어가 유사함을 학습 하였으므로 단어를 대신 선택하여 자연어 생성을 할 수 있었습니다.

기계도 마찬가지입니다. ‘발표 자료를 살펴보다’라는 단어 시퀀스는 존재하지만, ‘발표 자료를 톺아보다’라는 단어 시퀀스는 존재하지 않는 코퍼스를 학습한 언어 모델이 있다고 가정해본다면, 언어 모델은 아래 선택지에서 다음 단어를 예측해야 합니다.

[𝑃(톺아보다 발표\ 자료를)]
[𝑃(냠냠하다 발표\ 자료를)]


저는 ‘살펴보다’와 ‘톺아보다’의 유사성을 학습하였고 이를 근거로 두 선택지 중에서 ‘톺아보다’가 더 맞는 선택이라고 판단할 수 있습니다. 하지만 n-gram 언어 모델은 ‘발표 자료를’ 다음에 ‘톺아보다’가 나올 확률 $P (톺아보다 \mid 발표\ 자료를)$ 를 0으로 연산합니다. n-gram 언어 모델은 ‘살펴보다’와 ‘톺아보다’의 단어의 유사도를 알 수 없으므로 예측에 고려할 수 없습니다.

만약 언어 모델 또한 단어의 의미적 유사성을 학습할 수 있도록 설계 한다면, 훈련 코퍼스에 없는 단어 시퀀스에 대한 예측이라도 유사한 단어가 사용된 단어 시퀀스를 참고하여 보다 정확한 예측 을 할 수 있습니다. 그리고 이러한 아이디어를 반영한 언어 모델이 신경망 언어 모델 NNLM 입니다. 그리고 이 아이디어는 단어 벡터 간 유사도를 구할 수 있는 벡터를 얻어내는 워드 임베딩(word embedding) 의 아이디어이기도 합니다.


즉, 인공 신경망 언어 모델(NNLM)은 희소문제(sparsity problem)를 Word Embedding 으로 해결 하였습니다.

image


3. 피드 포워드 신경망 언어 모델(Neural Network Language Model, NNLM)

NNLM 이 언어 모델링을 학습하는 과정(훈련 과정에서 단어의 유사도를 학습)을 살펴보겠습니다.


예를 들어 훈련 코퍼스‘what will the fat cat sit on’ 과 같은 문장이 있다고 했을때, 언어 모델은 주어진 단어 시퀀스로부터 다음 단어를 예측합니다. 훈련 과정에서는 ‘what will the fat cat’ 이라는 단어 시퀀스가 입력으로 주어지면, 다음 단어 ‘sit’ 을 예측하는 방식으로 훈련됩니다. 즉 NNLM은 $n$ 개의 이전 단어들로부터 $n+1$ 단어를 예측하는 모델입니다. 신경망의 입력(기계가 단어를 인식)은 원-핫 인코딩 을 사용하여 얻은 원-핫 벡터 로 하고, 다음과 같은 예문을 훈련한다 해보겠습니다.

image


원-핫 벡터 들은 훈련을 위한 NNLM의 입력이면서 예측을 위한 레이블이 됩니다. 위 그림은 ‘what will the fat cat’를 입력을 받아서 ‘sit’을 예측하는 일은 기계에게 what, will, the, fat, cat의 원-핫 벡터를 입력받아 sit의 원-핫 벡터를 예측하는 문제입니다. 즉, NNLM 은 n-gram 언어 모델처럼 다음 단어를 예측할 때, 앞의 모든 단어를 참고하는 것이 아니라 정해진 개수의 단어만을 참고 합니다. 이때 이 범위를 윈도우(window) 라고 하기도 하는데, 여기서 윈도우의 크기인 n은 4입니다.

image


NNLM의 구조 를 보면 다음과 같습니다. NNLM은 다음 그림과 같이 총 4개의 층(layer)으로 이루어진 인공 신경망 입니다. 입력층(input layer) 을 보면 앞에서 윈도우의 크기는 4로 정하였으므로 입력은 4개의 단어 ‘will, the, fat, cat’의 원-핫 벡터입니다. 출력층(output layer) 을 보면 모델이 예측해야하는 정답에 해당되는 단어 ‘sit’의 원-핫 벡터는 모델이 예측한 값의 오차를 구하기 위해 레이블로서 사용됩니다. 그리고 오차로부터 손실 함수를 사용하여 인공 신경망이 학습을 하게 됩니다.

image


4개의 원-핫 벡터를 입력 받은 NNLM 은 다음층인 투사층(projection layer) 을 지나게 됩니다. 인공 신경망에서 입력층과 출력층 사이의 층은 보통 은닉층이라고 부르는데, 여기서 투사층이라고 명명한 이 층은 일반 은닉층과 다르게 가중치 행렬과의 곱셈은 이루어지지만 활성화 함수가 존재하지 않습니다. 입력층(Input layer)투사층(Projection layer) 사이의 연산을 생각해보면, 각각의 원-핫 벡터는 가중치 행렬과 곱해져서 투사층을 형성 할 것입니다.

image


투사층의 크기 를 $M$ 으로 설정하면, $V$ 차원의 원-핫벡터인 각 입력 단어 들은 투사층에서 $V × M$ 크기의 가중치 행렬 과 곱해져 $M$ 차원의 벡터를 얻습니다. 여기서 $V$ 는 단어 집합의 크기 를 의미합니다. 만약 원-핫 벡터의 차원 $V$ 가 7이고, $M$ 이 5라면 가중치 행렬 $W$ 는 $7 × 5$ 행렬이 됩니다.

각 단어의 원-핫 벡터와 가중치 $W$ 행렬의 곱이 어떻게 이루어지는지 보겠습니다. 위 그림에서는 각 원-핫 벡터를 $x$ 로 표기하였습니다. 원-핫 벡터의 특성으로 인해 $i$ 번째 인덱스에 1이라는 값을 가지고 그 외의 0의 값을 가지는 원-핫 벡터와 가중치 $W$ 행렬의 곱은 사실 $W$ 행렬의 $i$ 번째 행을 그대로 읽어오는 것과(lookup) 동일 합니다. 그래서 이 작업을 룩업 테이블(lookup table) 이라고 합니다.

image


룩업 테이블(lookup table) 후에는 $V$ 차원을 가지는 원-핫 벡터는 $M$ 차원의 벡터로 맵핑 됩니다. 위 그림에서 단어 ‘fat’ 을 의미하는 원-핫 벡터를 $x_{fat}$ 으로 표현했고, 테이블 룩업 과정을 거친 후의 단어 벡터는 $e_{fat}$ 으로 표현했습니다. 이 벡터들은 초기에는 랜덤한 값을 가지지만 학습 과정에서 값이 계속 변경 되는데 이 단어 벡터를 임베딩 벡터(embedding vector) 라고 합니다.

Projection Layer 는 신경망 그림으로 해석한다면 다음과 같습니다. 단, Weight Matrix는 존재하지만 Bias는 사용하지 않으며, 활성화 함수도 사용하지 않습니다.

image


즉, 각 단어를 의미하는 원-핫 벡터가 lookup table을 거치면 임베딩 벡터(embedding vector)로 변경되고, 투사층(Projection Layer)에서 모두 concatenate 됩니다. 여기서 concatenate란 벡터를 단순히 나열하는 것을 의미하는데, 예를 들어 5차원 벡터 4개를 concatenate하면 20차원 벡터가 됩니다. 벡터의 concatenate 는 딥러닝 연산에서 정보를 모두 사용한다는 의미로 두 개 이상의 정보(벡터)를 함께 사용하고자 할 때 쓰는 연산 입니다.

image


정리하면 lookup table으로 차원이 축소된 각 단어 벡터들이 모두 연결되면 Projection Layer의 결과물입니다. $x$ 를 각 단어의 원-핫 벡터, NNLM이 예측하고자 하는 단어가 문장에서 $t$ 번째 단어라고 하고, 윈도우의 크기를 $n$, 룩업 테이블을 의미하는 함수를 $lookup$, 세미콜론(;)을 연결 기호로 하였을 때 투사층을 식으로 표현하면 아래와 같습니다.

[p^{layer}(투사층) = (lookup(x_{t-n}),\ …;\ lookup(x_{t-2});\ lookup(x_{t-1}))
=(e_{t-n};\ …;\ e_{t-2};\ e_{t-1})]


일반적인 은닉층이 활성화 함수를 사용하는 비선형층(nonlinear layer)인 것과는 달리 투사층은 활성화 함수가 존재하지 않는 선형층(linear layer) 이라는 점이 다소 생소하지만, 이 다음은 다시 은닉층을 사용하는 일반적인 피드 포워드 신경망과 동일합니다.

image


투사층의 결과는 $h$ 의 크기를 가지는 은닉층을 지납니다. 이때의 가중치와 편향을 $W_h$ 와 $b_h$ 라고 하고, 은닉층의 활성화 함수를 하이퍼볼릭탄젠트 함수라고 하였을 때, 은닉층을 식으로 표현하면 아래와 같습니다.

[h^{layer}(은닉층) = tanh(W_h p^{layer} + b_h)]


image


은닉층의 출력은 $V$ 의 크기를 가지는 출력층으로 향합니다. 출력층에서는 활성화 함수로 소프트맥스(softmax) 함수를 사용하는데, $V$ 차원의 벡터는 소프트맥스 함수를 지나면서 벡터의 각 원소는 0과 1사이의 실수값을 가지며 총 합은 1이 되는 상태로 바뀝니다. 이 벡터를 NNLM 의 예측값이라는 의미에서 $\hat{y}$ 라고 할 때, 이를 식으로 표현하면 아래와 같습니다.

[\hat{y}(출력층) = softmax(W_y h^{layer} + b_y)]


벡터 $\hat{y}$ 의 각 차원 안에서의 값이 의미하는 것은 이와 같습니다. $\hat{y}$ 의 $j$ 번째 인덱스가 가진 0과 1사이의 값은 $j$ 번째 단어가 다음 단어일 확률을 나타냅니다. 그리고 $\hat{y}$ 는 실제값. 즉, 실제 정답에 해당되는 단어인 원-핫 벡터의 값에 가까워져야 합니다. 실제값에 해당되는 다음 단어를 $y$ 라고 했을 때, 이 두 벡터가 가까워지게 하기위해서 NNLM 는 손실 함수로 크로스 엔트로피(cross-entropy) 함수를 사용합니다. 해당 문제는 단어 집합의 모든 단어라는 $V$ 개의 선택지 중 정답인 ‘sit’을 예측해야하는 다중 클래스 분류 문제입니다. 그리고 역전파가 이루어지면 모든 가중치 행렬들이 학습되는데, 여기에는 투사층에서의 가중치 행렬도 포함되므로 임베딩 벡터값 또한 학습됩니다.


4. NNLM의 이점 : 희소 문제(sparsity problem) 해결

만약 충분한 훈련 데이터가 있다는 가정 하에 NNLM 의 핵심은, 투사층의 가중치 행렬 $W$ 의 각 행은 각 단어와 맵핑되는 밀집 벡터(Dense Vector) 이므로, 충분한 양의 훈련 코퍼스를 학습한다면 결과적으로 수많은 문장에서 유사한 목적으로 사용되는 단어들은 결국 유사한 임베딩 벡터값을 얻게된다는 것 입니다. 이렇게 되면 훈련이 끝난 후 다음 단어를 예측하는 과정에서 훈련 코퍼스에서 없던 단어 시퀀스라 하더라도 다음 단어를 선택할 수 있습니다. 만약 a cute dog를 학습했다면, a cute cat이 훈련 데이터에 없더라도 a cute cat을 생성 가능합니다.

결과적으로 NNLM은 단어를 표현하기 위해 임베딩 벡터를 사용하므로서 단어의 유사도를 계산할 수 있게되었으며, 이를 통해 희소 문제(sparsity problem)를 해결 하였습니다. 단어 간 유사도를 구할 수 있는 임베딩 벡터의 아이디어는 Word2Vec, FastText, GloVe 등으로 발전되어서 딥 러닝 자연어 처리 모델에서는 필수적으로 사용되는 방법이 되었습니다.


5. NNLM의 한계점 : 고정된 길이의 입력(Fixed-length input)

하지만 NNLM 의 한계점 또한 존재합니다. 즉 NNLM 은 희소 문제(sparsity problem)를 해결했지만 n-gram 언어 모델과 마찬가지로 다음 단어를 예측하기 위해 모든 이전 단어를 참고하는 것이 아닌, 정해진 $n$ 개의 단어만을 참고 할 수 있습니다. 즉, 입력의 길이가 고정된다는 단점 이 있습니다.

이 한계를 극복할 수 있는 언어 모델이 있는데, 바로 RNN(Recurrent Neural Network) 을 사용한 RNN 언어 모델(Recurrent Neural Network Language Model, RNNLM) 입니다.


6. RNN 언어 모델(Recurrent Neural Network Language Model, RNNLM)

RNNLM(Recurrent Neural Network Language Model) 은 RNN으로 만든 언어 모델입니다.


n-gram 언어 모델과 NNLM고정된 개수의 단어만을 입력으로 받아야한다는 단점 이 있었습니다. 하지만 시점(time step)이라는 개념이 도입된 RNN으로 언어 모델을 만들면 입력의 길이를 고정하지 않을 수 있습니다.

예를 들어 훈련 코퍼스에 ‘what will the fat cat sit on’ 과 같은 문장이 있다고 해보겠습니다. 언어 모델은 주어진 단어 시퀀스로부터 다음 단어를 예측하는 모델입니다. 아래의 그림은 RNNLM 이 어떻게 이전 시점의 단어들과 현재 시점의 단어로 다음 단어를 예측하는지를 보여줍니다.

image


RNNLM기본적으로 예측 과정에서 이전 시점의 출력을 현재 시점의 입력으로 합니다. RNNLM은 what을 입력받으면, will을 예측하고 이 will은 다음 시점의 입력이 되어 the를 예측합니다. 그리고 이 또한 다시 다음 시점의 입력이 됩니다. 결과적으로 네번째 시점에서 cat은 앞서 나온 what, will, the, fat이라는 시퀀스로 인해 결정된 단어입니다. 사실 이 과정은 훈련이 끝난 모델의 테스트 과정 동안(실제 사용할 때) 의 이야기입니다.

훈련 과정에서는 이전 시점의 예측 결과를 다음 시점의 입력으로 넣으면서 예측하는 것이 아니라, what will the fat cat sit on라는 훈련 샘플이 있다면, what will the fat cat sit 시퀀스를 모델의 입력으로 넣으면, will the fat cat sit on를 예측하도록 훈련됩니다. will, the, fat, cat, sit, on는 각 시점의 레이블입니다. 이러한 RNN 훈련 기법을 교사 강요(teacher forcing) 라고 합니다.


교사 강요(teacher forcing) 란, 테스트 과정에서 $t$ 시점의 출력이 $t+1$ 시점의 입력으로 사용되는 RNN 모델을 훈련시킬 때 사용하는 훈련 기법 입니다.

훈련할 때 교사 강요를 사용 할 경우, 모델이 $t$ 시점에서 예측한 값을 $t+1$ 시점에 입력으로 사용하지 않고, $t$ 시점의 레이블. 즉, 실제 알고있는 정답을 $t+1$ 시점의 입력으로 사용합니다. 물론, 훈련 과정에서도 이전 시점의 출력을 다음 시점의 입력으로 사용하면서 훈련 시킬 수도 있지만 이는 한 번 잘못 예측하면 뒤에서의 예측까지 영향을 미쳐 훈련 시간이 느려지게 되므로, 교사 강요를 사용하여 RNN을 좀 더 빠르고 효과적으로 훈련시킬 수 있습니다.

image


훈련 과정 동안 출력층에서 사용하는 활성화 함수는 소프트맥스 함수입니다. 그리고 모델이 예측한 값과 실제 레이블과의 오차를 계산하기 위해서 손실 함수로 크로스 엔트로피 함수를 사용합니다.

image


RNNLM의 구조에서 우선 입력층(input layer) 을 보겠습니다. RNNLM의 현 시점(timestep)은 4로 가정합니다. 그래서 4번째 입력 단어인 fat의 원-핫 벡터가 입력 이 됩니다.

출력층(output layer) 을 보면, 모델이 예측해야하는 정답에 해당되는 단어 cat의 원-핫 벡터 는 출력층에서 모델이 예측한 값의 오차를 구하기 위해 사용될 예정입니다. 그리고 이 오차로부터 손실 함수를 사용해 인공 신경망이 학습을 하게 됩니다. 조금 더 구체적으로 살펴보겠습니다.

image


현 시점의 입력 단어의 원-핫 벡터 $x_t$ 를 입력 받은 RNNLM은 우선 임베딩층(embedding layer)을 지납니다. 이 임베딩층은 임베딩 벡터를 얻는 투사층(projection layer)입니다. 단어 집합의 크기가 $V$ 일 때, 임베딩 벡터의 크기를 $M$ 으로 설정하면, 각 입력 단어들은 임베딩층에서 $V × M$ 크기의 임베딩 행렬과 곱해집니다. 만약 원-핫 벡터의 차원이 7이고, M이 5라면 임베딩 행렬은 7 × 5 행렬이 됩니다. 그리고 이 임베딩 행렬은 역전파 과정에서 다른 가중치들과 함께 학습됩니다.

[e_t(임베딩층) = lookup(x_t)]


이 임베딩 벡터는 은닉층에서 이전 시점의 은닉 상태인 $h_{t-1}$ 과 함께 다음의 연산을 하여 현재 시점의 은닉 상태 $h_t$ 를 계산하게 됩니다.

[h_t(은닉층) = tanh(W_x e_t + W_h h_{t-1} + b)]


출력층에서는 활성화 함수로 소프트맥스(softmax) 함수를 사용하는데, $V$ 차원의 벡터는 소프트맥스 함수를 지나면서 각 원소는 0과 1사이의 실수값을 가지며 총 합은 1이 되는 상태로 바뀝니다. 이렇게 나온 벡터를 RNNLM의 $t$ 시점의 예측값이라는 의미에서 $\hat{y_t}$ 라고 합시다. 이를 식으로 표현하면 아래와 같습니다.

[\hat{y_t}(은닉층) = softmax(W_y h_t + b)]


벡터 $\hat{y_t}$ 의 각 차원 안에서의 값이 의미하는 것은 이와 같습니다. $\hat{y_t}$ 의 $j$ 번째 인덱스가 가진 0과 1사이의 값은 $j$ 번째 단어가 다음 단어일 확률을 나타냅니다. 그리고 $\hat{y_t}$ 는 실제값. 즉, 실제 정답에 해당되는 단어인 원-핫 벡터의 값에 가까워져야 합니다. 실제값에 해당되는 다음 단어를 $y$ 라고 했을 때, 이 두 벡터가 가까워지게 하기위해서 RNNLM는 손실 함수로 cross-entropy 함수를 사용합니다. 그리고 역전파가 이루어지면서 가중치 행렬들이 학습되는데, 이 과정에서 임베딩 벡터값들도 학습이 됩니다.

룩업 테이블의 대상이 되는 테이블인 임베딩 행렬을 $E$ 라고 하였을 때, 결과적으로 RNNLM에서 학습 과정에서 학습되는 가중치 행렬은 다음의 $E$, $W_x$, $W_h$, $W_y$ 4개 입니다.

Read more

언어 모델(Language Model, LM)

|

  1. 언어 모델(Language Model)이란?
    • 1.1 전체 단어 시퀀스의 확률
    • 1.2 이전 단어들이 주어졌을 때 다음 단어의 등장 확률
  2. 언어 모델의 간단한 직관
  3. 통계적 언어 모델(Statistical Language Model, SLM)
  4. N-gram 언어 모델(N-gram Language Model)
  5. Sparsity Problem



언어 모델(Language Model, LM) 은 언어라는 현상을 모델링하고자 단어 시퀀스(문장)에 확률을 할당(assign)하는 모델 입니다.

언어 모델을 만드는 방법은 크게는 통계를 이용한 방법 과 인공 신경망을 이용한 방법 으로 구분할 수 있습니다. 최근에는 통계를 이용한 방법보다는 인공 신경망을 이용한 방법이 더 좋은 성능을 보여주고 있습니다.


1. 언어 모델(Language Model)이란?

언어 모델(Language Model, LM) 은 단어 시퀀스에 확률을 할당(assign) 하는 일을 하는 모델 입니다. 이를 조금 풀어서 쓰면, 언어 모델은 가장 자연스러운 단어 시퀀스를 찾아내는 모델 로, 단어 시퀀스에 확률을 할당하는 이유는 Language Model을 통해 더 그럴듯한 문장을 선택할 수 있기 때문입니다.

가장 보편적으로 사용되는 방법은 언어 모델이 이전 단어들이 주어졌을 때 다음 단어를 예측하는 모델, 또는 주어진 양쪽의 단어들로부터 가운데 비어있는 단어를 예측하는 언어 모델 등이 있습니다. 자연어 처리에서 단어 시퀀스에 확률을 할당하는 일이 왜 필요한지 살펴보겠습니다.

image


기계 번역(Machine Translation) 에서 언어 모델은 두 문장을 비교하여 좌측의 문장의 확률이 더 높다고 판단하고, 음성 인식(Speech Recognition) 에서 언어 모델은 두 문장을 비교하여 우측의 문장의 확률이 더 높다고 판단하며, 오타 교정(Spell Correction) 에서는 언어 모델은 두 문장을 비교하여 좌측의 문장의 확률이 더 높다고 판단합니다. 즉 언어 모델은 단어 시퀀스에 확률을 할당하여, 확률을 통해 보다 적절한 문장을 판단 합니다.

Languae Model은 어떤 문장이 가장 그럴듯한지를 판단하며, 일반적으로 주어진 단어 시퀀스 다음에 어떤 단어가 등장할 지 예측하는 것이므로 이를 조건부 확률로 표현해보겠습니다.


1.1 전체 단어 시퀀스의 확률

하나의 단어를 $𝑤$, 단어 시퀀스를 대문자 $𝑊$ 라고 한다면, $𝑛$ 개의 단어가 등장하는 단어 시퀀스 $𝑊$ 의 확률은 다음과 같습니다. 즉 $𝑛$ 개의 단어가 동시에 등장할 확률 입니다.

[𝑃(𝑊) = 𝑃(𝑤_1,𝑤_2,𝑤_3,𝑤_4,𝑤_5,…,𝑤_𝑛)]


1.2 이전 단어들이 주어졌을 때 다음 단어의 등장 확률

다음 단어 등장 확률을 식으로 표현해보겠습니다. $𝑛‐1$ 개의 단어가 나열된 상태에서 $𝑛$ 번째 단어의 확률은 다음과 같습니다.

[𝑃(𝑤_𝑛 𝑤_1,…,𝑤_{𝑛−1})]


다섯번째 단어의 등장 확률은 다음과 같이 표현할 수 있습니다.

[𝑃 (𝑤_5 𝑤_1, 𝑤_2, 𝑤_3, 𝑤_4)]


전체 단어 시퀀스 $𝑊$ 의 확률은 모든 단어가 예측되고 나서야 알 수 있으므로, 이를 일반화하면 전체 단어 시퀀스의 확률은 다음과 같습니다.

[𝑃(𝑊) = 𝑃(𝑤_1,𝑤_2,𝑤_3,𝑤_4,𝑤_5,…𝑤_𝑛) = ∏^n_{i=1}𝑃(𝑤_𝑖 𝑤_1,…,𝑤_{𝑖−1})]


문장 ‘its water is so transparent’ 의 확률 $𝑃 (its\ water\ is\ so\ transparent)$ 를 식으로 표현해봅시다.

각 단어는 문맥이라는 관계로 인해 이전 단어의 영향을 받아 나온 단어 입니다. 그리고 모든 단어로부터 하나의 문장이 완성 됩니다. 그렇기 때문에 문장의 확률을 구하고자 조건부 확률을 사용하겠습니다. 앞서 언급한 조건부 확률의 일반화 식을 문장의 확률 관점에서 다시 적어보면 문장의 확률각 단어들이 이전 단어가 주어졌을 때 다음 단어로 등장할 확률의 곱으로 구성 됩니다.

image


문장의 확률을 구하기 위해서 다음 단어에 대한 예측 확률들을 곱합니다.


2. 언어 모델의 간단한 직관

비행기를 타려고 공항에 갔는데 지각을 하는 바람에 비행기를 [?] 라는 문장이 있습니다. ‘비행기를’ 다음에 어떤 단어가 오게 될지 사람은 쉽게 ‘놓쳤다’ 라고 예상할 수 있습니다. 우리 지식에 기반하여 나올 수 있는 여러 단어들을 후보에 놓고 놓쳤다는 단어가 나올 확률이 가장 높다고 판단하였기 때문입니다.

그렇다면 기계에게 위 문장을 주고, ‘비행기를’ 다음에 나올 단어를 예측해보라고 한다면 과연 어떻게 최대한 정확히 예측할 수 있을까요? 기계도 비슷합니다. 앞에 어떤 단어들이 나왔는지 고려하여 후보가 될 수 있는 여러 단어들에 대해서 확률을 예측해보고 가장 높은 확률을 가진 단어를 선택 합니다.


3. 통계적 언어 모델(Statistical Language Model, SLM)

문장의 확률을 구하기 위해서 다음 단어에 대한 예측 확률을 모두 곱한다는 것은 알았습니다. 언어 모델의 전통적인 접근 방법통계적 언어 모델(Statistical Language Model, SLM)카운트에 기반하여 이전 단어로부터 다음 단어에 대한 확률을 계산 합니다. 즉, 통계적 방법중 카운트 기반 접근의 핵심 아이디어는 “훈련 데이터에서 단순 카운트하고 나누는 것은 어떨까?” 입니다.

image


확률은 위와 같습니다. 예를 들어 기계가 학습한 코퍼스 데이터에서 its water is so transparent that 가 100번 등장했는데 그 다음에 the 가 등장한 경우는 30번이라고 합시다. 이 경우 $P(the|its\ water\ is\ so\ transparent\ that)$ 는 30%입니다.

하지만 훈련 데이터가 정말 방대하지 않은 이상 제대로 카운트할 수 있는 경우가 거의 없습니다.

image


SLM의 한계는 훈련 코퍼스에 확률을 계산하고 싶은 문장이나 단어가 없을 수 있다는 점 입니다. 확률을 계산하고 싶은 문장이 길어질수록 갖고있는 코퍼스에서 그 문장이 존재하지 않을 가능성이 높으며, 다시 말하면 카운트할 수 없을 가능성이 높습니다.

그런데 다음과 같이 참고하는 단어들을 줄이면 카운트를 할 수 있을 가능성을 높일 수 있습니다.

[𝑃(is An\ adorable\ little\ boy)≈ 𝑃(is boy)]


가령, An adorable little boy 가 나왔을 때 is 가 나올 확률을 그냥 boy 가 나왔을 때 is 가 나올 확률로 생각해본다면, 갖고있는 코퍼스에 An adorable little boy is 가 있을 가능성 보다는 boy is 라는 더 짧은 단어 시퀀스가 존재할 가능성이 더 높습니다. 조금 지나친 일반화로 느껴진다면 아래와 같이 little boy 가 나왔을 때 is 가 나올 확률로 생각하는 것도 대안입니다.

[𝑃(is An\ adorable\ little\ boy)≈ 𝑃(is little\ boy)]


즉, 앞에서는 An adorable little boy 가 나왔을 때 is 가 나올 확률을 구하기 위해서는 An adorable little boy 가 나온 횟수와 An adorable little boy is 가 나온 횟수를 카운트해야만 했지만, 이제는 단어의 확률을 구하고자 기준 단어의 앞 단어를 전부 포함해서 카운트하는 것이 아니라, 앞 단어 중 임의의 개수만 포함해서 카운트하여 근사하자는 것 입니다. 이렇게 하면 갖고 있는 코퍼스에서 해당 단어의 시퀀스를 카운트할 확률이 높아집니다.


4. N-gram 언어 모델(N-gram Language Model)

n-gram 언어 모델 은 여전히 카운트에 기반한 통계적 접근을 사용하고 있으므로 SLM의 일종 입니다. 다만, 앞서 배운 언어 모델과는 달리 이전에 등장한 모든 단어를 고려하는 것이 아니라 일부 단어만 고려하는 접근 방법을 사용 합니다. 이때 일부 단어를 몇 개 보느냐를 결정 하는데 이것이 n-gram에서의 n 이 가지는 의미입니다. 예를 들어서 문장 “An adorable little boy is spreading smiles” 이 있을 때, 각 $n$ 에 대해서 n-gram 을 전부 구해보면 다음과 같습니다.

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


정리하면 n-gramn개의 연속적인 단어 나열을 의미 하고 n은 사용자가 정하는 값이며, 이전 단어들이 주어졌을때 다음 단어의 등장 확률의 추정을 앞의 n-1개의 단어에만 의존 합니다.

image


하지만 n-gram은 앞의 단어 몇 개만 보다 보니 의도하고 싶은 대로 문장을 끝맺음하지 못하는 경우가 생긴다는 점 입니다. 문장을 읽다 보면 앞 부분과 뒷부분의 문맥이 전혀 연결 안 되는 경우도 생길 수 있습니다. 예를 들어 $n=2$ 이면 Bigram Language Model 이라고 하며 오직 이전 단어 하나만 고려하여 카운트하여 확률 추정하게됩니다. 즉, n을 선택하는 n-gram trade-off 문제 가 있습니다.

  • n을 크게 선택
    • 실제 훈련 코퍼스에서 해당 n-gram을 카운트할 수 있는 확률은 적어지므로 희소 문제는 점점 심각해집니다.
    • 모델 사이즈가 커진다는 문제점도 있습니다. 기본적으로 코퍼스의 모든 n-gram에 대해서 카운트를 해야 하기 때문.
  • n을 작게 선택
    • 훈련 코퍼스에서 카운트는 잘 되겠지만 근사의 정확도는 현실의 확률분포와 멀어집니다.


결론만 말하자면 n이 작으면 얼토당토 않는 문장이 되버리지만 n이 크면 카운트하기가 어려워 지므로 적절한 n을 선택해야하며, 전체 문장을 고려한 언어 모델보다는 정확도가 떨어질 수밖에 없습니다.


5. Sparsity Problem

언어 모델실생활에서 사용되는 언어의 확률 분포를 근사 모델링 합니다. 실제로 정확하게 알아볼 방법은 없겠지만 현실에서도 An adorable little boy 가 나왔을 때 is 가 나올 확률이라는 것이 존재합니다. 기계에게 많은 코퍼스를 훈련시켜서 언어 모델을 통해 현실에서의 확률 분포를 근사하는 것이 언어 모델의 목표 입니다. 그런데 카운트 기반 또는 N-gram 으로 접근하려고 한다면 갖고있는 코퍼스(corpus). 즉, 다시 말해 통계적 언어 모델(Statistical Language Model, SLM)에서 기계가 훈련하는 데이터는 정말 방대한 양이 필요 합니다.

image


Sparsity Problem 문제를 완화하는 방법으로 스무딩이나 백오프와 같은 여러가지 일반화(generalization) 기법이 존재하지만, 희소 문제에 대한 근본적인 해결책은 되지 못하였습니다. 결국 이러한 한계로 인해 언어 모델의 트렌드는 통계적 언어 모델에서 인공 신경망 언어 모델(NNLM) 로 넘어가게 됩니다.

Read more