본문 바로가기
Study (Data Science)/NLP

전처리, 분산표현, 임베딩, 토큰화

by 콜라찡 2023. 2. 14.
  • 자연어 (Natural) : 인류의 언어. 200가지의 언어 중 40가지 정도가 문자를 가짐.
    • 문맥 의존 언어 (context sensitive language)
    • parsing이 어려움. 문맥, 현실세계의 이해를 필요로 할 때가 많아 단순 파싱이 되지 않음.
    • 착한 영희 친구를 parsing 하여 다 떨어뜨리면, 영희가 착한건가 친구가 착한건가..
    • She drove down the street in her car. 그녀는 그녀의 차를 타고 길을 운전한건가, 차안에 있는 길을 운전한건가.
  • 인공어 (Artificial) : 프로그래밍 언어. C언어, 파스칼 등등. 
    • 문맥 자유 언어 (context free language)
    • parsing이 너무 잘됨. 문맥이 자유로우니 그냥 나누면 끝.

1. 전처리

자연어의 Noise들

  1. 불완전한 문자으로 구성된 대화인 경우
    • 카톡할 때 완벽하게 한 문장을 보내지 않고 끊어 여러번 보내는 경우
  2. 문장의 길이가 너무 길거나 짧은 경우
    • ㅜㅜ,ㅋㅋ 너무 짧아 의미가 없거나, 사용빈도가 높은 리액션들은 언어 모델을 왜곡시키므로 보통 제외함.
    • 행운의 편지처럼 너무 긴 문장은 현재 내용과 관련이 없을 수 있음.
  3. 채팅 데이터에서 문장 시간 간격이 너무 긴 경우
    • 말의 텀이 너무 길면 연속된 대화라고 보기 힘듬. 작년에 보냈는데, 올해 대답하는 경우.
  4. 바람직하지 않은 문장 사용
    • 욕, 오타가 많으면 제외하는 것이 좋음.

 

 

그래서 깔끔한 기사나 책을 데이터로 쓰는데,, 그럼 우리가 궁극적으로 만나는 noise 들은?

  1. 문장부호
    • Hi, my name is John. ("Hi," "my", ..., "John." 으로 분리됨)
    • 문장부호 양 옆으로 blank를 추가해두고, 밑에서 특수문자를 지우도록 처리함.
    • text = text.replace(p, " " + p + " ")
  2. 대소문자
    • First, open the first chapter. (First와 first를 다른 단어로 인식)
    • 소문자나 대문자로 다 일괄 바꿈
    •  .lower()
  3. 특수문자
    • He is a ten-year-old boy. (ten-year-old를 한 단어로 인식) 
    • 정규표현식 re로 조건문 제시하여 없앰. (regex = regular expression)
    • sentence = re.sub("([^a-zA-Z.,?!)", " ", sentence)
 
# From The Project Gutenberg
# (https://www.gutenberg.org/files/2397/2397-h/2397-h.htm)

corpus = \
"""
In the days that followed I learned to spell in this uncomprehending way a great many words, among them pin, hat, cup and a few verbs like sit, stand and walk. 
But my teacher had been with me several weeks before I understood that everything has a name.
One day, we walked down the path to the well-house, attracted by the fragrance of the honeysuckle with which it was covered. 
Some one was drawing water and my teacher placed my hand under the spout. 
As the cool stream gushed over one hand she spelled into the other the word water, first slowly, then rapidly. 
I stood still, my whole attention fixed upon the motions of her fingers. 
Suddenly I felt a misty consciousness as of something forgotten—a thrill of returning thought; and somehow the mystery of language was revealed to me. 
I knew then that "w-a-t-e-r" meant the wonderful cool something that was flowing over my hand. 
That living word awakened my soul, gave it light, hope, joy, set it free! 
There were barriers still, it is true, but barriers that could in time be swept away.
""" 

def cleaning_text(text, punc, regex):
    # 노이즈 유형 (1) 문장부호 공백추가
    for p in punc:
        text = text.replace(p, " " + p + " ")

    # 노이즈 유형 (2), (3) 소문자화 및 특수문자 제거
    text = re.sub(regex, " ", text).lower()

    return text

print(cleaning_text(corpus, [".", ",", "!", "?"], "([^a-zA-Z0-9.,?!\n])"))
 

2. 분산표현 (Distributed representation)

희소표현 (Sparse representation)

분산표현의 반대개념

희소표현의 예
//      [성별, 연령, 과일, 색깔]
    남자: [-1.0, 0.0, 0.0, 0.0],
    여자: [1.0, 0.0, 0.0, 0.0],
    사과: [0.0, 0.0, 1.0, 0.5],   // 빨갛게 잘 익은 사과
    바나나: [0.0, 0.0, 1.0, -0.5] // 노랗게 잘 익은 바나나

단점

  • 너무 고차원이 필요함.. 이 세상의 모든언어를 위해서는 옆으로 얼마나 늘어날지 모름.
  • 불필요한 메모리와 연산량이 낭비됨
  • 워드 벡터끼리는 단어들 간의 의미적 유사도를 계산할 수 없음
    • 코사인 유사도(Cosine Similarity) : 두 벡터의 방향이 완전히 동일한 경우에는 1의 값을 가지며, 90°의 각을 이루면 0, 180°로 반대의 방향을 가지면 -1의. 즉, 코사인 유사도는 -1 이상 1 이하의 값을 가지며 값이 1에 가까울수록 유사도가 높다고 판단할 수 있음. 두 벡터가 가리키는 방향이 얼마나 유사한가를 의미.

https://wikidocs.net/24603

분산표현 (Distributed representation)

그래서 embedding layer를 사용하여 각 단어가 몇 차원의 속성(깊이)를 가질지 정의하는 방식으로 표현하게 되었음.

단어를 분산표현, 밀집 벡터(dense vector)의 형태로 표현하는 방법을 워드 임베딩(word embedding)이라고 함.

그리고 이 밀집 벡터를 워드 임베딩 과정을 통해 나온 결과라고 하여 임베딩 벡터(embedding vector)라고도 함.

방법

  • LSA, Word2Vec, FastText, Glove
  • keras의 Embedding()

만약 100개의 단어를 256차원의 속성으로 표현하고 싶다면,

embedding_layer = tf.keras.layers.Embedding(input_dim=100, output_dim=256)
  • 256의 깊이 안에 우리가 정의할 수 없는 추상적인 표현들을 컴퓨터가 알아서 채워넣음.
  • 우리가 속성값을 줬던 희소표현과 가장 다른 부분이며,
  • 이 속성들 값을 통해 우리는 단어간의 유사도를 계산하거나 자연어 모델을 훈련할 수 있음.
  • 이 임베딩 레이어는 컴퓨터에게 단어사전과 같은 역할을 하게됨.
  • 워드 벡터 기법 (단어 속에 담긴 의미를 어떤 의미 벡터 공간안에 매핑하는 기법 = 인베딩레이어 = 분산표현)
  • But, 문장을 단어단위로 정확히 끊어내지 못하면 사전에 단어가 없거나 찾을 수 없는 문제가 발생.
  • 그래서 토큰화가 쟁점이자 필수!

https://wikidocs.net/33520


3. 토큰화 (Tokenization)

  • 자연어를 의미단위로 쪼개는 기법.
  • 토큰(Token) : 쪼개진 각 단어들
  • 쪼개는 방식에 따라 같은 문장도 완전히 다른 워드벡터리스트가 만들어질 수 있음.
  • 최신 기법 : Wordpiece Model, Subword level
  • 기존 기법들
    1. 공백 토큰화 (.split())
    2. 형태소 기반 토큰화
      •  KoNLPy, mecab, OKT, KOMORAN, 꼬꼬마, 한나눔, khaiii, soynlp(library)
      • mecab : 평균적으로 제일 우수, 속도 빠름
      • KOMORAN : 자소분리, 오탈자가 많고, 맞춤법 테러가 많을 때 좋음. (e.g. ㄴ ㅐ 가 ㅋㅋㅋ ㅡㅡ)
      • 내 주관적으로는,, 가장 한국어다운 분리는 OKT 인듯. mecab에 OKT가 내원픽임.
      • 문장의 길이보다는 띄어쓰기유무, 자소분리, 오탈자가 영향을 많이 미침.
      • 성능비교 : https://iostream.tistory.com/144   
    3. 사전에 없는 단어의 문제 (OOV문제 - Out of Vocabulary)
      • 위에 두 방법은 자주 등장한 상위 N개의 단어만 사용하고 나머지는 <unk> 토큰으로 치환해버림
      • 그러다보니 번역이나 혹은 중요한 신조어(ex.코로나, 우한) 일 경우 잘 분석이 되지 않음
      • 해결책 : Wordpiece Model (WPM)

4. WPM

접두어나 접미어로 떼어내어 한 단어를 여러개의 subword 집합으로 보는 방법.

WPM은 공개되어 있지 않음

Byte Pair Encoding(BPE)

1994년, 자연어 처리를 위해서가 아닌 데이터 압축을 위해 생겨난 알고리즘. 데이터에서 가장 많이 등장하는 Byte Pair을 새로운 단어로 치환하여 압축하는 작업을 반복함.

2015년, 모든 단어를 바이트 취급하면 자주 나오는 접두사와 접미사의 의미를 알 수 있고, (e.g. pre-전의) 처음보는 단어도 그 의미를 추리 가능하여 OOV 문제를 해결할 수 있다고 제안함.  

# BPE 예시
aaabdaaabac # 가장 많이 등장한 바이트 쌍 "aa"를 "Z"로 치환합니다.
→ 
ZabdZabac   # "aa" 총 두 개가 치환되어 4바이트를 2바이트로 압축하였습니다.
Z=aa        # 그다음 많이 등장한 바이트 쌍 "ab"를 "Y"로 치환합니다.
→ 
ZYdZYac     # "ab" 총 두 개가 치환되어 4바이트를 2바이트로 압축하였습니다.
Z=aa        # 여기서 작업을 멈추어도 되지만, 치환된 바이트에 대해서도 진행한다면
Y=ab        # 가장 많이 등장한 바이트 쌍 "ZY"를 "X"로 치환합니다.
→ 
XdXac
Z=aa
Y=ab
X=ZY       # 압축이 완료되었습니다!

해당 논문 (Neural Machin Translation of Rare Words with Subword Units| https://arxiv.org/pdf/1508.07909.pdf)

 

구글에서 BPE를 변형해 제안한 알고리즘이 바로 WPM

BPE와 다른점 두가지

만약에, 토큰화 한 결과가 [i, am, a, b, o, y, a, n, d, you, are, a, gir, l] 라고 하면,

  1. 공백 복원을 위해 단어의 시작 부분에 언더바 _ 를 추가
  2. 빈도수 기반이 아닌 가능도(Likelihood)를 증가시키는 방향으로 문자 쌍을 합침.  (더 '그럴듯한' 토큰을 만들어냅니다.)

결과 :  [_i, _am, _a, _b, o, y, _a, n, d, _you, _are, _a, _gir, l] 

 1) 모든 토큰을 합친 후, 2) 언더바 _를 공백으로 치환으로 마무리

 

참고) BLUE (bilingual evaluation understudy)

The BLUE (bilingual evaluation understudy) score is a metric used to evaluate the quality of machine-generated translations by comparing them to human translations. It measures the degree of overlap between the machine-generated translation and one or more reference translations, taking into account both precision (how much of the machine-generated translation matches the reference translation) and brevity (how much shorter the machine-generated translation is compared to the reference translation).

The BLUE score ranges from 0 to 1, with a higher score indicating a better quality translation. A score of 1 indicates that the machine-generated translation is identical to the reference translation, while a score of 0 indicates no overlap at all.

The BLUE score is commonly used in the field of natural language processing to assess the quality of machine translation systems, and it has been shown to correlate well with human judgments of translation quality.

 

 


5. 여러가지 라이브러리

sentenccepiece

WPM는 공개되어있지 않음. 대신 구글에서 sentenccepiece라는 라이브러리를 제공하고 있음.

이 라이브러리는 전처리 과정도 포함되어 있어서 데이터 정제가 필요없음.하위 

장점

  1. subword 토큰화: SentencePiece는 subword  토큰화 알고리즘을 구현합니다. 즉, 단어를 문자 n-그램과 같은 더 작은 단위로 분할하여 어휘 외(OOV) 단어를 처리하고 어휘 범위를 늘릴 수 있습니다.
  2. 언어에 구애받지 않음: SentencePiece는 언어에 구애받지 않습니다. 즉, 모든 언어나 스크립트에 사용할 수 있습니다. 라틴어, 키릴 문자, 한자 등 다양한 쓰기 시스템을 처리할 수 있습니다.
  3. 효율적인 training: SentencePiece는 BPE(Byte Pair Encoding) 알고리즘을 기반으로 하는 감독되지 않은 training방법을 사용합니다. 이 방법은 효율적이며 몇 가지 하이퍼 매개변수만 설정하면 됩니다. 또한 많은 메모리를 요구하지 않고도 대용량 데이터 세트를 처리할 수 있습니다.
  4. 유연성: SentencePiece는 사용자 정의가 가능하며 subword 단어 어휘의 크기 및 병합 작업 수와 같은 다양한 하위 단어 토큰화 설정을 허용합니다. 또한 사용자 정의 제약 조건이나 사전 토큰화 규칙을 통합할 수도 있습니다.
  5. 호환성: SentencePiece는 TensorFlow, PyTorch 및 Keras와 같은 다양한 딥 러닝 프레임워크와 호환되며 기계 번역, 텍스트 분류 및 언어 모델링과 같은 자연어 처리(NLP) 작업에 사용할 수 있습니다.
  6. 오픈 소스: SentencePiece는 오픈 소스 라이브러리이므로 누구나 자유롭게 사용, 수정 및 배포할 수 있습니다. 또한 개발 및 개선에 기여하는 대규모 개발자 커뮤니티의 혜택을 받습니다.

soynlp

한국어 자연어 처리를 위한 라이브러리이며, 단어 추출, 품사판별, 전처리, 토크나이저까지 됨.

soynlp의 토크나이저는 '학습데이터를 이용하지 않으면서 데이터에 존재하는 단어를 찾거나, 문장을 단어열로 분해, 혹은 품사 판별을 할 수 있는 비지도학습 접근법을 지향합니다' 라고 나와있음.

 

quoted.. " 문장에서 처음 단어를 받아들일 때 단어의 경계를 알아야 올바르게 토큰화를 할 수 있습니다. 이때 단어의 경계를 비지도학습을 통해 결정하겠다는 말이에요. 비지도학습을 통한 방법이기 때문에 미등록 단어도 토큰화가 가능합니다. 여기서 비지도학습을 가능케 하는 것이 통계적인 방법이라서 soynlp를 통계 기반 토크나이저로 분류하기도 합니다.

트와이스가 한 단어임을 인지하기 위해서 트, 트와, 트와이, 트와이스 각각 다음 글자의 확률을 계산해서 비교한다고 생각하면 좋습니다. 수학적으로 자세한 내용은 여기서는 다루지 않습니다. 다만 koNLPy외에도 soynlp가 있다는 점을 기억해 주세요. " - from Aiffel LMS

 


6. Word2Vec

분산표현의 하나. 단어의 깊이를 쌓는 시퀀스화 과정.

동시에 등장하는 단어끼리는 연관성이 있다는 아이디어로 시작된 알고리즘

  • CBOW(Continuous Bag of Words)
    • 주변에 있는 단어들을 입력으로 중간에 있는 단어들을 예측하는 방법
  • Skip-Gram (CBOW보다 성능 좋음)
    • 중간에 있는 단어들을 입력으로 주변 단어들을 예측하는 방법

Thanks for 수익님


7. FastText

Word2Vec는 자주 등장하지 않는 단어의 경우 단 한 번의 연산만을 거쳐 랜덤하게 초기화된 값 처럼 나올 수 있음.

FastText는 이를 해결하기 위해 BPE와 비슷한 아이디어를 적용함.

BPE와 비슷한 개념으로 n-gram을 사용하여 character 단위로 window를 씌워 벡터화함.


8. ELMo - the 1st Contextualized Word Embedding

동음이의어는 처리할 수 없었던 기존의 한계점을 극복한 최초의  문맥 기반의 워드 임베딩.

 

 


9. 결론

문장이 들어오면

 

1. 토큰화해서 잘 끊고 (KoNLPy, mecab 등등)
2. 분산표현으로 벡터화 해야하니 적절한 임베딩 방법으로 의미있는 숫자로 바꾸고 (Word2Vec, Fasttext, Elmo등등)

 

 

 

 

 

 

 

ELMo 관련 포스트

https://brunch.co.kr/@learning/12

 

전이 학습 기반 NLP (1): ELMo

Deep Contextualized Word Representations | 2018년은 기계학습 기반 자연어 처리 분야에 있어서 의미 있는 해였습니다. 2015년 이후로 컴퓨터 비전 분야에서 전이 학습(transfer learning)이 유행하기 시작한 이후

brunch.co.kr

 

한국어를 위한 어휘 임베딩 개발에 관련된 포스트

https://brunch.co.kr/@learning/7

 

한국어를 위한 어휘 임베딩의 개발 -1-

한국어 자모의 FastText의 결합 | 이 글은 Subword-level Word Vector Representations for Korean (ACL 2018)을 다룹니다. 두 편에 걸친 포스팅에서는 이 프로젝트를 시작하게 된 계기, 배경, 개발 과정의 디테일을 다

brunch.co.kr

 

728x90

'Study (Data Science) > NLP' 카테고리의 다른 글

벡터화 발전과정 (BoW/DTM/TF-IDF/SVD/LSA/LDA/토픽모델링)  (0) 2023.02.18
Keras Tokenizer 와 SentencePiece 비교 이해  (0) 2023.02.15
Chatbot  (0) 2023.01.27
Ex12_ NLP / 뉴스 요약봇  (0) 2023.01.25
NLP 기본개념  (0) 2022.12.29

댓글