해당 내용은 "딥 러닝을 이용한 자연어 처리 입문" 서적을 토대로 공부한 내용을 개인적으로 보기 편하게 정리해놓은 것입니다.
- 필요 라이브러리
tensorflow, keras, scikit-learn, gensim, NLTK, KoNLTK, Pandas, Numpy, Matplotlib
- 자연어 : 일상생활의 언어
- 자연어처리 : 일상생활의 언어를 컴퓨터가 처리할 수 있도록 하는 일 (ex. 음성인식, 내용 요약, 번역 etc..)
- EDA(Exploratory Data Analysis, 탐색석 데이터 분석)
- 데이터 내 값의 분포, 변수 간 관계, 결측값 존재 유무 등을 파악하는 과정
- Pandas profiling
- 방대한 양의 데이터를 탐색(개요, 변수, 상세확인으로 구성)
- 코퍼스
- 조사나 연구목적에 의해서 특정 도메인으로부터 수집된 텍스트 집합(txt, csv, xml 등)
- 머신러닝 워크플로우
출처: here
- 텍스트 전처리 : 용도에 맞게 텍스트를 사전에 처리하는 작업
토큰의 기준은 데이터의 용도에 따라 사용자가 직접 정의
nltk에는 영어 코퍼스를 토큰화 할 수 있는 도구를 제공 (ex. word_tokenize, wordPunctTokenizer ...)
-
토큰화 고려사항
- 구두점이나 특수 문자를 단순 제외하면 안된다.
- 줄임말과 단어 내에 띄어쓰기가 있는 경우, 토큰화는 접어를 펼치는 작업도 포함한다. (I'm -> I am)
-
한국어 토큰화의 어려움
- 한국어는 교착어이다.
- 한국어는 영어보다 띄어쓰기가 잘 지켜지지 않는다.
토큰화 과정에서 각 단어가 어떤 품사로 쓰였는지 구분하는 과정. NLTK는 Penn Treebank Pos Tags 기준에 의해 품사태깅.
약자 | 이름 |
---|---|
PRP | 인칭대명사 |
VBP | 동사 |
RB | 부사 |
VBG | 현재부사 |
IN | 전치사 |
NNP | 고유명사 |
NNS | 복수명사 |
CC | 접속사 |
DT | 관사 |
- KoNLPy (한국어 자연어처리)
okt, 한나눔, 꼬꼬마 etc..
사실은 형태소 단위로 토큰화 (영어는 단어 토큰화)
- morphs : 형태소 추출
- pos : 품사 태깅
- nouns : 명사 추출
okt 형태소 분석기와, 꼬꼬마 형태소 분석기의 결과는 다르다
사용하고자하는 용도에 맞게 판단하고 알맞은 현태소 분석기를 사용하자
- 정제(cleaning) : 갖고있는 코퍼스로부터 노이즈 데이터를 제거
- 정규화(Normalization) : 표현 방법이 다른 단어들을 통합시켜 같은 단어로 만들어줌
정제와 정규화는 적당한 합의점을 잡고 합의점에 도달할 때까지 지속적으로 진행한다.
- 단계
- 규칙에 기반한 표기가 다른 단어들의 통합 (ex. 어간 추출, 표제어 추출)
- 대,소문자 통합 (ex. Automobile - automobile, But US - us)
- 불필요한 단어의 제거
- 등장 빈도가 적은 단어
- 길이가 짧은 단어(영어권에서는 효과가 좋다.)
- 정규표현식
- 표제어 추출 (Lemmatization): 코퍼스의 단어들로부터 기본 사전형 단어를 찾아나감.
- am, are, is -> be
- 형태학적 parsing (어간과 접사를 분리)
어간 : 단어의 의미를 담고있는 핵심저긴 부분(cats -> cat)
접사 : 단어에 추가적인 의미를 주는 부분(cats -> -s) - 어간 추출 (Stemming): 눈으로 보았을 때, 서로 다른 단어들이지만 같은 의미를 갖고있는 단어들을 하나의 단어로 일반화.
- 단순 규칙에 의거한 추출( 경과 단어가 사전에 존재하지 않을 수 있다.)
- ex. Porter Algorithm ..
- 표제어 추출 VS 어간 추출
- 표제어 추출
- 문맥 고려
- 수행 시 해당 단어의 품사정보를 보존 (=POS 태그를 보존)
- 어간 추출
- 품사정보 보존 X
- 사전에 존재하지 않는 단어가 출력될 수 있음.
- 표제어 추출
- 예시
표제어 추출 | 어간 추출 | |
---|---|---|
am | be | am |
the going | the going | the go |
having | have | hav |
- 한국어에서의 어간 추출
- 5언 9품사
언 | 품사 |
---|---|
체언 | 명사, 대명사, 수사 |
수식언 | 관형사, 부사 |
관계언 | 조사 |
독립언 | 감탄사 |
용언 | 동사, 형용사 |
-
활용 : 용언의 어간이 어미를 갖는 일
- 어간 : 원칙적으로 모양이 변하지 않는 부분
- 어미 : 어간뒤에 붙어 용도에따라 변하는 부분
- 규칙활용 : 어간이 어미를 취할 때 어간의 모습이 일정
- 불규칙 활용 : 어간이 어미를 취할 때 어간의 모습이 변하거나 어미가 특수한 어미일 경우
불규칙 활용의 경우, 좀 더 복잡한 규칙이 필요하다.
-
불용어(StopWord)
- 자주 등장해도 분석에 큰 도움이 없는 단어로 NLTK에서는 불용어 패키지로 특정 단어들을 정의
- I, my, me, over ...
-
NLTK를 통한 불용어 제거
from nltk.corpus import stopwords
stop_words = set(stopwords. words('english'))
- 한국어에서 불용어 제거
- 사용자가 직접 불용어 사전을 만들어 사용
- 대표적 불용어 사전 : here
- 정규 표현식을 이용한 토큰화
from nltk.tokenize import RegexpToknizer
- 문자열을 기준으로 토큰화
tokenizer = RegexpToknizer("[\n]+")
I'm Mr.Ji! -> ['I','m','Mr','Ji']
- 공백을 기준으로 토큰화
tokenizer - RegexpTokenizer("[\s]+", gaps = True) // 다음 정규표현식을 토큰화의 기준으로 쓰겠다.
I'm Mr.Ji! -> ['I'm', 'Mr.Ji!']
단어의 빈도수를 기준으로 정렬한 후, 각각에 해당하는 Index의 원소에 1을 대입.
빈수가 높으면, 낮은 Index를 부여. 이 때, 특정 횟수 이하의 숫자는 제거(cleaning작업)
문장의 매핑 과정 중 Index Dict에 존재하지 않는 단어가 존재하면, key는 'OOV'로, Value는 len+1로 추가한다.
-
sent_tokenize -> 문장 단위로 토큰화 진행
-
word_tokenize -> 단어 단위로 토큰화 진행
-
케라스의 텍스트 전처리
from tensorflow.keras.processing.text import Tokenizer
tokenizer = Toknizer()
tokenizer.fit_on_texts(sentence) // 빈도수를 기준으로 단어집합 생성
tokenizer.word_index // 빈도수에 따른 index 부여 Dict
tokenizer.word_count // 단어와 빈고수 Dict
tokenizer.text_to_sequences(sentence) // Mapping된 배열
Q. 빈도수를 기준으로 상위 5개만 뽑아내려면?
vocab_size = 5
tokenizer = Tokenizer(num_words = vocab_size + 1) // +1인 이유는 0번 Index를 Padding을 위한 공간으로 사용하기 위해
tokenizer.fit_on_texts(sentence)
Q. ;OOV를 쓰고 싶다면?
vocab_size = 5
tokenizer = Tokenizer(num_words = vocab_size + 2, oob_token = 'OOV') // 'OOV'의 Index는 1로 자동 설정
from tensorflow.keras.processing.sequence import pad_sequences
padded = pad_sequences(encoded) // 기본적으로 앞에 0을 padding
Q. 뒤에 0을 padding하고 싶다면?
padded = pad_sequences(encoded, padding = 'post')
Q. Padding의 길이를 설정하려면?
padded = pad_sequences(encoded, padding = 'post', maxlen = 5)
Q. 0이 아닌 다른 값으로 padding하려면?
last_value = len(tokenizer.word_index) + 1
padded = pad_sequences(encoded, padding = 'post', value = last_value)
- 원 핫 인코딩
단어 집합 : 서로 다른 단어들의 집합 (ex. book, books)
- 각 단어에 고유한 인덱스를 부여. (정수 인코딩)
- 표현하고 싶은 단어의 인덱스의 위치에 1을 부여하고, 다른 위치에는 0을 부여.
from tensorflow.keras.utils import to_categorical
- 한계
- 단어의 갯수가 늘어날수록, 벡터의 크기는 계속 커진다. ( = 벡터의 차원이 계속 능어난다.)
- 단어의 유사도를 표현하지 못한다.
- 보완 방법
- 카운트기반 벡터화(LSA, HAL etc..)
- 예측기반 벡터화(NNLM, RNNLM, Word2Vec, FastText etc..)
- 두 개를 합한 벡터화(Glove etc..)
단어 시퀀스에 확률을 할당하는 모델
- 통계를 이용하는 방법
- 인공 신경망을 이용하는 방법.(GPT, BERT etc..)
최근에는 통계를 이용한 모델보다는 인공 신경망을 이용한 모델이 더 발전 대부분 [앞단어]를 통해 [뒷단어]를 예측
- 목적
- 기계 번역
- 오타 교정
- 음성 인식
- 조건부 확률 : A라는 사거니 일어났을 때, B라는 사건이 일어날 확률
By Chain Rule..
Generalize..
문장에 대한 확률에도 조건부 확률을 적용
-
카운트 기반의 접근
- 오늘 일찍 일어났어야' 다음 '했는데'가 나올 확률은?
P(했는데|오늘, 일찍, 일어났어야) = count(오늘 일찍 일어났어야 했는데) / count(오늘 일찍 일어났어야) = 30번 / 100번 = 30%
-
카운트 기반 접근의 한계 (희소문제, Sparsity problem)
- 현실에서의 확률 분포로 근사하는 언어모델을 만들기 위해서는 방대한 양의 코퍼스 데이터가 필요하다.
- 즉, 희소문제 : 충분한 데이터를 관측하지 못하여 언어를 정확히 모델링하지 못하는 문제
-
해결법
N-gram, 스무딩, 백오프 etc..
인공 신경망 기반 언어 모델
카운트에 기반한 통계적 접근 + 이전에 등장한 모든 단어 대신, 일부 단어만 고려 (N-gram의 N을 의미)
SLM | N-gram |
---|---|
P(했는데|오늘 일찍 일어났어야) | P(했는데|했어야) |
- N-gram 장점
- SLM의 코퍼스에 문장이나 단어가 없는 경우 해소
- SLM의 문장이 길어질 때 코퍼스에 문장이 없는 경우 해소
- N-gram
갖고있는 코퍼스에서 n개의 단어 뭉치로 끊어 이를 하나의 토큰으로 간주.
- 'I am a good boy'
set | |
---|---|
unigrams | I, am, a, good, boy |
bigrams | I am, am a, a good, good boy |
trigrams | I amd a, am a good, a good boy |
4- grams | I am a good, am a good boy |
- I am a good W
In 3-gram, P{W|a good) = count(a good W) / count(a good)
- N-gram 언어 모델의 한계
전체 문장을 고려한 언어 모델보다는 성능이 떨어진다.
- 희소문제
SLM보다 count될 확률이 높아질 뿐, 희소문제는 여전히 존재.
- n 선택에서의 trade off(교환)
성능 | count | 모델 SIZE | |
---|---|---|---|
n이 증가 | 향상 | 감소 | 증가 |
n이 감소 | 하락 | 증가 | 감소 |
n은 최대 5를 넘어서면 안된다!
-
적용 분야에 맞는 코퍼스 수집
- 마케팅 분야 vs 의료 분야의 확률 분포는 다르다.
- 원하는 도메인의 코퍼스를 활용하여 언어모델 개발
-
인공신경망을 이용한 언어모델. (Neural Network Based Language Model)
- N-gram 언어 모델보다 대체적으로 성능이 우수한 인공신경망 기반 언어모델 사용 증가.
-
한국에서의 언어모델
- 어순이 중요하지 않다.
오늘 나는 기분이 좋다.
나는 오늘 기분이 좋다.
오늘 기분이 좋다.
기분이 나는 좋다.- 한국어는 교착어이다.
나 : 나는, 나를, 나의, 나에게, 나로써
토큰화를 통해 접사나 조사 등을 분리해야 한다.
- 한국어는 띄어쓰기가 제대로 지켜지지 않는다
띄어쓰기를제대로하지않아도의미전달이가능하다.
-
외부평가 : 모델의 외부에서 모델에 대한 평가를 진행. (모델의 성능비교 등)
-
내부평가 : 모델의 내부에서 모델 자체가 모델에 대한 평가를 진행. (Perplexity 등)
-
언어모델의 평가 방법 : PPL
By Chain Rule..
If Bigram
- 분기계수(Branching Factor)
- PPL은 선택가능한 경우의 수를 의미하는 분기계수이다.
- PPL이 낮으면 성능이 더 좋다. 단, 사람이 느끼기에 좋은 언어모델은 아닐 수 있다.
- 두 모델에 대해 PPL로 비교할 때, 같은 도메인에 동일한 테스트케이스를 사용해야 한다.
페이스북 AI연구팀이 공개한 자료에 따르면, 대부분 기존 언어모델보다 인공신경망 모델의 PPL이 더 낮다(= 성능이 우수하다).
-
DTM(Document-Term-Matrix)
- 다수의 문서에서 등장하는 각 단어의 빈도수만을 원소로 갖는 행렬
- 한계
- 희소 표현 (Sparse representation)
- 공간적 낭비와 계산 리소스를 증가킨다.
- 빈도수 기반 접근
- 문서(문장) 자체의 유사도를 판단할 수 없음 ex/ 나는 너를 좋아해, 나는 너를 안 좋아해
- 희소 표현 (Sparse representation)
-
TF-IDF(Term Frequency-Inverse Document Frequency)
- DTM에 단어의 중요도(가중치)를 포함해 계산한 행렬
- TF : 특정 문서에서 특정 단어의 등장 횟수
- DF : 전체 corpus에서 특정 단어가 등장한 문서의 개수
- idf : DF에 반비례하는 수
idf 계산 중 log를 사용하는 이유 : 문서n의 개수에 따라 한없이 커지는 idf값을 조정하기위해
-
TF-IDF가 항상 DTM보다 좋은 결과를 내지는 않는다.
-
토픽 모델링
- 문서 집합 사이의 추상적인 주제를 발견하기위한 통계적 모델
- LSA vs LDA
- LSA : Latent Semantic Analysis (잠재 의미 분석)
- using SVD
- 한계 : 새로운 데이터가 들어오면 처음부터 다시 계산해야함
- LDA : Latent Dirichlet Analysis (잠재 디리클레 분석)
- 가정: 문서는 topic의 혼합, 데이터가 주어지면 문서 생성과정의 역추적
- LSA : Latent Semantic Analysis (잠재 의미 분석)
자연어를 컴퓨터가 이해하기 쉬운 벡터 형식으로 변환하는 작업(Word2Vec, Glove)
-
희소 표현(Sparse Representation)
- 표현식의 대부분의 값이 0
- 자원 낭비
- ex. 원 핫 인코딩, DTM
-
밀집 표현(Dense Representation)
- 단어를 정해진 크기로 표현
- 밀집 표현을 통한 단어 표현을 __워드 임베딩(Word Embedding)__이라함
- 워드 임베딩을 표현을 통한 결과를 __임베딩 벡터(Embedding Vector)__라 함
-
Word2Vec
-
'비슷한 위치에서 등장하는 단어들은 비슷한 관계를 가진다'
-
Projection Layer를 통해 학습, activation layer X
-
대부분 Skip-gram이 CBOW보다 성능이 좋음
-
CBOW(Continuous Bag Of Words)
- 주변에 위치한 단어(context word)로 중심 단어(center word) 예측
- context word들의 Projection Layer 연산 결과(=output vector)의 평균값을 사용
- 몇개의 주변 단어를 볼것인지 윈도우(window)를 통해 결정
- window size = n -> context word size = 2n (앞 n개, 뒤 n개)
-
Skip-gram
- 중심단어(center word)를 통해 주변 단어(contecxt layer)를 예측
- output vector가 하나만 나오므로 평균을 계산할 필요가 없음
-
NNLM과의 차이점
- NNLM은 이전 단어만 활용하여 단어를 예측(Word2Vec은 이전 단어와 이후 단어를 모두 사용)
- NNLM은 input layer - hidden layer - projection layer - output layer(Word2Vec은 input layer - projection layer - output layer)
-