임베딩
- 사람이 사용하는 언어를 컴퓨터가 이해할 수 있는 벡터로 변환하는 과정
희소 표현 기반 임베딩
- 희소 표현은 대부분의 값이 0으로 채워져 있는 경우로, 대표적으로 원-핫 인코딩이 있음
- 원-핫 인코딩(아래의 이미지 참고)
- 단어끼리 관계성 없이 서로 독립적임
- 하나의 단어를 표현하는 데 말뭉치에 있는 수만큼 차원이 존재해야 함
횟수 기반 임베딩
- 단어가 출현한 빈도를 고려하여 임베딩하는 방법
- 대표적으로 카운터 벡터와 TF-IDF가 있음
- 카운터 벡터
- 문서 집합에서 단어를 토큰으로 생성하고 각 단어의 출현 빈도수를 이용하여 인코딩해서 벡터를 만드는 방법(사이킷런의 CountVectorizer() 사용하여 코드 구현 가능 -> 값은 해당 단어가 나온 횟수)
- 문서 벡터는 단어 사전의 크기와 동일한 차원을 가지며, 각 인덱스 위치에 해당 단어의 등장 빈도가 저장됨
- TF-IDF
- TF(단어 빈도)는 문서 내에서 특정 단어가 출현한 빈도를 의미하며, IDF(역문서 빈도)는 문서 빈도에 역수 취해준 값
- IDF = log(전체 문서 개수/1+특정 단어가 포함된 문서 개수) -> 전체 문서에 특정 단어가 발생하는 빈도가 0일 수도 있어 분모에 1을 더해줌
- 사이킷런의 TfidfVectorizer() 사용하여 코드 구현 가능
from sklearn.feature_extraction.text import TfidfVectorizer
doc = ['I like machine learning', 'I love deep learning', 'I run everyday']
tfidf_vectorizer = TfidfVectorizer(min_df=1) # 단어의 최소 등장 빈도
tfidf_matrix = tfidf_vectorizer.fit_transform(doc)
doc_distance = (tfidf_matrix * tfidf_matrix.T)
print ('유사도를 위한', str(doc_distance.get_shape()[0]), 'x', str(doc_distance.get_shape()[1]), 'matrix를 만들었습니다.')
print(doc_distance.toarray())
유사도를 위한 3 x 3 matrix를 만들었습니다.
[[1. 0.224325 0. ]
[0.224325 1. 0. ]
[0. 0. 1. ]]
---------------------------------------------------
참고) print(tfidf_matrix)
(0, 2) 0.4736296010332684 -> 0번째 문서에서 인덱스 2의 값은 0.4736... 임을 의미
(0, 5) 0.6227660078332259
(0, 3) 0.6227660078332259
(1, 0) 0.6227660078332259
(1, 4) 0.6227660078332259
(1, 2) 0.4736296010332684
(2, 1) 0.7071067811865476
(2, 6) 0.7071067811865476
예측 기반 임베딩(임베딩 벡터 만들어지는 과정 좀 더 생각해보기!)
- 신경망 구조 혹은 모델을 이용하여 특정 문맥에서 어떤 단어가 나올지 예측하면서 단어를 벡터로 만드는 방식
- 대표적으로 워드투벡터가 있음
- 워드투벡터
- 유사한 단어의 벡터는 서로 가깝게 표현('서로 가깝다'는 의미는 코사인 유사도를 이용하여 단어 간의 거리를 측정한 결과)
CBOW
- 단어를 여러 개 나열한 후 이와 관련된 단어를 추정하는 방식
- 예를 들어, "calm cat slept on the sofa"라는 문장이 있을 때 "calm cat on the sofa"라는 문맥이 주어지면 "slept"를 예측하는 것
- 아래의 그림에서 은닉층 크기는 5이기 때문에 해당 CBOW를 수행한 후 벡터의 크기는 5가 됨
참고) https://m.blog.naver.com/jittij1/221793873335
- gensim.models.Word2Vec(data, min_count = 1, size = 100, window = 5, sg=0)
- 첫 번째 파라미터: CBOW를 적용할 데이터셋
- min_count: 단어에 대한 최소 빈도 수(빈도가 적은 단어들은 학습하지 않음)
- size: 워드 벡터의 특징 값(즉, 임베딩된 벡터의 차원)
- sg: 0일 때는 CBOW(기본값), 1일 때는 skip-gram
skip-gram
- CBOW 방식과 반대로 특정한 단어에서 문맥이 될 수 있는 단어를 예측
패스트텍스트
- 워드투벡터의 단점을 보완하고자 페이스북에서 개발한 임베딩 알고리즘
- 워드투벡터는 사전에 없는 단어에 대해서는 벡터 값을 얻을 수 없다는 단점이 있음
- 이외에도 자주 사용되지 않는 단어에 대한 학습이 불안정함
- 패스트텍스트는 노이즈에 강하며, 새로운 단어에 대해서는 형태적 유사성을 고려한 벡터값을 얻음
- 사전에 없는 단어에 벡터 값을 부여하는 방법
- 학습이 완료된 후 데이터셋의 모든 단어를 각 n-gram에 대해 임베딩 -> 사전에 없는 단어가 등장한다면 n-gram으로 분리된 부분 단어와 유사도를 계산하여 의미 유추
- 자주 사용되지 않는 단어에 학습 안정성을 확보하는 방법
- 등장 빈도 수가 낮더라도 n-gram으로 임베딩하기 때문에 참고할 수 있는 경우의 수가 많아 정확도가 높아짐
- gensim.models.FastText(data, vector_size = 4, window = 3, min_count = 1, epochs=10)
- 첫 번째 파라미터: 패스트텍스트에 적용할 데이터셋
- vector_size: 워드 벡터의 특징 값(즉, 임베딩된 벡터의 차원)
- window: 고려할 앞뒤 폭(예를 들어, 앞뒤 세 단어)
- min_count: 단어에 대한 최소 빈도 수(빈도가 적은 단어들은 학습하지 않음)
- epochs: 반복 횟수
- 패스트텍스트에서는 각 단어는 글자 단위 n-gram의 구성으로 취급하며, 예를 들어 n을 3으로 설정하면 apple은 <ap, app, ppl, ple, le>를 벡터로 만듦(단어의 시작과 끝도 각각 <, >로 취급)
횟수/예측 기반 임베딩
- 횟수 기반과 예측 기반의 단점을 보완하기 위한 임베딩 기법에는 대표적으로 글로브가 있음
글로브(자세히 공부하기)
참고) https://wikidocs.net/22885
- 횟수 기반의 LSA(잠재 의미 분석)와 예측 기반의 워드투벡터 단점을 보완하기 위한 모델
- LSA는 카운트 기반으로 코퍼스의 전체적인 통계 정보를 고려하지만 왕:남자=여왕:?와 같이 같은 단어 의미의 유추 작업에는 성능이 떨어지며, 워드투벡터는 주변 단어만 고려하기 때문에 코퍼스의 전체적인 통계 정보를 반영하지 못 함
- 단어에 대한 글로벌 동시 발생 확률 정보를 포함하는 단어 임베딩 방법(단어에 대한 통계 정보와 skip-gram을 합친 방식)
- 윈도우 기반 동시 등장 행렬
- 단어의 동시 등장 행렬은 행과 열을 전체 단어 집합의 단어들로 구성하고, i단어의 윈도우 크기 내에서 k단어가 등장한 횟수를 i행 k열에 기재한 행렬
- 예시) I like deep learning, I like NLP, I enjoy flying
- 글로브의 핵심 아이디어는 "임베딩 된 중심 단어와 주변 단어 벡터의 내적이 전체 코퍼스에서의 동시 등장 빈도가 되도록 만드는 것"
- 위의 핵심 아이디어를 식으로 표현하면 [식 1]과 같으며, 이를 위해 손실함수는 [식 2]와 같이 정의함
- [식 2]에서 편향 b_m과 b_n은 학습을 돕기 위해 추가된 항임
- 또한, it's와 같이 불용어의 동시 등장 빈도수가 높다고 해서 지나친 가중치를 주는 것을 방지하기 위해 X_mn 대신 f(X_mn)을 활용함([그림 1] 참고)
트랜스포머 어텐션
- 어텐션은 입력에 대한 벡터 변환을 인코더에서 처리하고 모든 벡터를 디코더로 보냄(이와 같이 모든 벡터를 전달하는 이유는 시간이 흐를수록 초기 정보를 잃어버리는 기울기 소멸 문제를 해결하기 위해)
- 하지만 모든 벡터가 전달되기 때문에 행렬의 크기가 굉장히 커지는 단점이 있는데 이를 해결하기 위해 소프트맥스 함수를 사용하여 가중합을 구하고 그 값을 디코더에 전달
- 가중합만 전달되었더라도 정보를 많이 전달받은 디코더는 부담 -> 디코더는 은닉 상태에 대해 중점적으로 집중해서 보아야 할 벡터를 소프트맥스 함수로 점수를 매긴 후 각각을 은닉 상태의 벡터들과 곱함(이 은닉 상태를 모두 더해서 하나의 값으로 만듦)
- 어텐션에서 다룬 인코더와 디코더에는 네트워크가 하나씩 있었는데 트랜스포머는 인코더와 디코더를 여러 개 중첩시킨 구조임
- 인코더는 셀프 어텐션(문장에서 각 단어끼리 얼마나 관계가 있는지를 계산해서 반영)과 전방향 신경망으로 구성되어 있음
- 디코더는 셀프 어텐션(인코더와 동일), 인코더-디코더 어텐션(인코더가 처리한 정보를 받아 어텐션 메커니즘 수행), 전방향 신경망의 3개의 층을 가지고 있음
어텐션 메커니즘
- 어텐션 메커니즘을 이용하기 위해서는 가장 먼저 어텐션 스코어를 구해야 함
- 어텐션 스코어란 현재 디코더의 시점에서 단어를 예측하기 위해 인코더의 모든 은닉 상태 값이 디코더의 현 시점의 은닉 상태와 얼마나 관련이 있는지 판단하는 값(인코더의 모든 은닉 상태의 값과 디코더에서의 이전 시점의 은닉 상태 값을 이용해서 구할 수 있음)
- 어텐션 스코어가 계산되었다면 이 값을 소프트맥스 함수에 적용하여 학률로 변환 -> 이렇게 계산된 값은 특정 시점에 대한 가중치로 사용됨
- 컨텍스트 벡터는 위에서 구한 어텐션 스코어에 은닉 상태의 가중합을 계산한 하나의 벡터
- 앞에서 구한 컨텍스트 벡터와 디코더 이전 시점의 은닉 상태와 출력을 이용하여 최종적으로 다음 디코더의 은닉 상태를 출력
seq2seq
- 입력 시퀀스에 대한 출력 시퀀스를 만들기 위한 모델
- 품사 판별과 달리 x_i, y_i 간의 관계가 중요하지 않으며, 각 시퀀스 길이도 서로 다름
re 모듈
- 정규표현식(특정한 규칙을 갖는 문자열의 집합을 표현하기 위한 형식)을 사용하고자 할 때 씀
- 일반적으로 복잡한 문자열의 검색과 치환을 위해 사용됨
실습
- 인코더 네트워크
- 디코더 네트워크
- 티처포스(teacher_force)는 seq2seq 모델에서 많이 사용되는 기법으로 예측하려는 목표 단어를 디코더의 다음 입력으로 넣어 주는 기법임 -> 학습 초기에 안정적인 훈련이 가능하며, 기울기를 계산할 때 빠른 수렴이 가능한 장점이 있지만 네트워크가 불안정해질 수 있는 단점
어텐션 메커니즘이 등장한 이유
- 하나의 고정된 크기의 벡터에 모든 정보를 담다 보니 정보의 손실 발생
- RNN에서 발생할 수 있는 기울기 소멸 문제 발생
버트(BERT)
- 기존의 단방향 자연어 처리 모델들의 단점을 보완한 양방향 자연어 처리 모델
- 문장의 단어를 입력된 순서대로 하나씩 처리하는 것이 아니라 트랜스포머를 이용하여 구현되었으며 방대한 양의 텍스트 데이터로 사전 훈련된 언어 모델
버트의 학습 절차
- 문장을 버트의 입력 형식에 맞게 변환 -> 문장의 시작은 [CLS], 문장의 끝은 [SEP]로 표시
- 한 문장의 단어들에 대해 토큰화 진행(예를 들어 고양이라는 단어의 경우 고##, #양#, ##이로 토큰화)
- 각 토큰들에 대해 고유의 아이디 부여(토큰이 존재하지 않는 자리는 0으로 채움)
- BertTokenizer.from_pretrained는 사전 훈련된 버트의 토크나이저를 사용하겠다는 의미
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') # 버트의 가장 기본적인 모델(uncased는 모든 문장을 소문자로 대체)
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
model.to(device)
한국어 임베딩
- 영어의 경우 단어를 기준으로 잘 쪼개지지만 다른 언어의 경우 정확하지 않을 수 있기 때문에 KoBert를 이용하는 것이 좋음
- 버트는 문장을 구별하기 위해 1과 0을 사용함(예를 들어, 문장이 바뀔 때마다 0에서 1로 바꿈)
import torch
from transformers import BertTokenizer, BertModel
tokenizer = BertTokenizer.from_pretrained('bert-base-multilingual-cased')
출처: 서지영(2022). 딥러닝 파이토치 교과서. p542-p611.
'파이토치' 카테고리의 다른 글
[딥러닝 파이토치 교과서] 강화 학습 (0) | 2023.06.24 |
---|---|
[딥러닝 파이토치 교과서] 클러스터링 (0) | 2023.06.24 |
[딥러닝 파이토치 교과서] 자연어 전처리 (0) | 2023.06.18 |
[딥러닝 파이토치 교과서] 성능 최적화 (0) | 2023.06.17 |
[딥러닝 파이토치 교과서] 합성곱 신경망2 (0) | 2023.05.28 |