본문 바로가기

Deep Learning/NLP

서브워드 토크나이저 (Subword Tokenizer)

예를 들어 텍스트를 분류하는 문제를 다룬다고 하였을 때 토크나이저가 모든 단어에 대해서 알 필요가 없는 것은 사실이다. 그래서 vocabulary size를 정하고 빈도가 낮은 단어들은 OOV(out-of-vocabulary) 또는 UNK로 표현한다.

 

그렇지만 만약에 OOV로 표현된 단어가 분류 작업에 결정적인 단서인 경우엔 어떨까? 예를 들어 어떤 카테고리로 분류할 때 quit이라는 동사가 영향이 크다고 가정해보자. 그런데 이의 현재 진행형인 quitting은 출현 빈도가 낮아 OOV 처리가 되었다. 이럴 때 사용하는 것이 서브워드 분리 작업이다. 하나의 단어가 더 작은 단위의 의미있는 여러 서브워드(quit + ing)들로 구성되어 있는 경우가 많아, 이를 분리해서를 단어를 인코딩 및 임베딩 하겠는다는 작업이다.

 

바이트 페어 인코딩(Byte Pair Encoding, BPE)

아래와 같은 문자열이 주어졌을 때 BPE를 수행해보자.

aaabdaaabac

BPE는 기본적으로 연속적으로 가장 많이 등장한 글자의 쌍을 찾아서 하나의 글자로 병합하는 방식을 수행한다. 위의 문자열에서 가장 자주 등장하고있는 바이트의 쌍은 'aa'이다. 이를 'Z'로 치환해보자

ZabdZabac
Z=aa

그 다음은 'ab'이다.

ZYdZYac
Y=ab
Z=aa

그 다음은 'ZY'이다.

XdXac
X=ZY
Y=ab
Z=aa

더 이상 병합할 바이트의 쌍이 없으므로 BPE를 수행한 최종 결과는 위와 같다.

자연어 처리에서의 BPE

paper: https://arxiv.org/pdf/1508.07909.pdf

자연어 처리에서의 BPE는 서브워드 분리(subword segmentation) 알고리즘이다. 기존에 있던 단어를 분리한다는 의미이다. BPE을 요약하면, 글자(charcter) 단위에서 점차적으로 단어 집합(vocabulary)을 만들어 내는 Bottom up 방식의 접근을 사용한다. 우선 훈련 데이터에 있는 단어들을 모든 글자(chracters) 또는 유니코드(unicode) 단위로 단어 집합(vocabulary)를 만들고, 가장 많이 등장하는 유니그램을 하나의 유니그램으로 통합한다.

 

기존의 접근

어떤 훈련 데이터로부터 각 단어의 빈도수를 카운트하여 딕셔너리로 만든다고 해보자.

# dictionary
# 훈련 데이터에 있는 단어와 등장 빈도수
low : 5, lower : 2, newest : 6, widest : 3

이 훈련 데이터의 단어 집합에는 'low', 'lower', 'newest', 'widest'라는 4개의 단어가 존재한다. 만약에 테스트 데이터에 'lowest'란 단어가 등장한다면 모델은 해당 단어에 대해 제대로 대응하지 못하는 OOV 문제가 발생한다.

 

BPE 알고리즘을 사용한 경우

위의 딕셔너리에 BPE를 적용해보자. 우선 딕셔너리의 모든 단어들을 글자(chracter) 단위로 분리한다.

# dictionary
l o w : 5,  l o w e r : 2,  n e w e s t : 6,  w i d e s t : 3

단어 집합은 아래와 같다.

# vocabulary
l, o, w, e, r, n, s, t, i, d

BPE의 특징은 알고리즘의 동작을 몇 회 반복(iteration)할 것인지를 사용자가 정한다는 점이다. 여기서는 총 10회를 수행한다고 가정해보자.

 

1회 - 딕셔너리를 참고로 하였을 때 빈도수가 9로 가장 높은 (e, s)의 쌍을 es로 통합

# dictionary update!
l o w : 5,
l o w e r : 2,
n e w es t : 6,
w i d es t : 3

# vocabulary update!
l, o, w, e, r, n, s, t, i, d, es

2회 - 빈도수가 9로 가장 높은 (es, t)의 쌍을 est로 통합

# dictionary update!
l o w : 5,
l o w e r : 2,
n e w est : 6,
w i d est : 3

# vocabulary update!
l, o, w, e, r, n, s, t, i, d, es, est

3회 - 빈도수가 7로 가장 높은 (l, o)의 쌍을 lo로 통합

# dictionary update!
lo w : 5,
lo w e r : 2,
n e w est : 6,
w i d est : 3

# vocabulary update!
l, o, w, e, r, n, s, t, i, d, es, est, lo

이와 같은 방식으로 총 10회 반복하였을 때 얻은 딕셔너리와 단어 집합은 아래와 같다.

# dictionary update!
low : 5,
low e r : 2,
newest : 6,
widest : 3

# vocabulary update!
l, o, w, e, r, n, s, t, i, d, es, est, lo, low, ne, new, newest, wi, wid, widest

이 경우 테스트 과정에서 'lowest'란 단어가 등장한다면, 기존에는 OOV에 해당되는 단어가 되었겠지만 BPE 알고리즘을 사용한 위의 단어 집합에서는 더 이상 'lowest'는 OOV가 아니다. 모델는 우선 'lowest'를 전부 글자 단위로 분할한다. 즉, 'l, o, w, e, s, t'가 된다. 그리고 기계는 위의 단어 집합을 참고로 하여 'low'와 'est'를 찾아낸다. 즉, 'lowest'를 기계는 'low'와 'est' 두 단어로 인코딩한다. 그리고 이 두 단어는 둘 다 단어 집합에 있는 단어이므로 OOV가 아니다.

 

WordPiece Tokenizer

paper: https://static.googleusercontent.com/media/research.google.com/ko//pubs/archive/37842.pdf
구글이 위 WordPiece Tokenizer를 변형하여 번역기에 사용했다는 paper: https://arxiv.org/pdf/1609.08144.pdf

 

WordPiece Tokenizer은 BPE의 변형 알고리즘dl다. 해당 알고리즘은 BPE가 빈도수에 기반하여 가장 많이 등장한 쌍을 병합하는 것과는 달리, 병합되었을 때 corpus의 Likelihood를 가장 높이는 쌍을 병합합니다. 2016년의 위 논문에서 구글은 구글 번역기에서 WordPiece Tokenizer가 수행된 결과에 대해서 기술하였다.

 

수행하기 이전의 문장: Jet makers feud over seat width with big orders at stake
WordPiece Tokenizer를 수행한 결과(wordpieces): _J et _makers _fe ud _over _seat _width _with _big _orders _at _stake

 

Jet는 J와 et로 나누어졌으며, feud는 fe와 ud로 나누어진 것을 볼 수 있다. WordPiece Tokenizer는 모든 단어의 맨 앞에 _를 붙이고, 단어는 서브 워드(subword)로 통계에 기반하여 띄어쓰기로 분리한다. 여기서 언더바 _는 문장 복원을 위한 장치이다.

 

예컨대, WordPiece Tokenizer의 결과로 나온 문장을 보면, Jet → _J et와 같이 기존에 없던 띄어쓰기가 추가되어 서브 워드(subwords)들을 구분하는 구분자 역할을 하고 있다. 그렇다면 기존에 있던 띄어쓰기와 구분자 역할의 띄어쓰기는 어떻게 구별할까? 이 역할을 수행하는 것이 단어들 앞에 붙은 언더바 이다. WordPiece Tokenizer이 수행된 결과로부터 다시 수행 전의 결과로 돌리는 방법은 현재 있는 모든 띄어쓰기를 전부 제거하고, 언더바를 띄어쓰기로 바꾸면 된다. 이 알고리즘은 BERT를 훈련하기 위해서 사용되기도 하였다.

 

Unigram Language Model Tokenizer

paper: https://arxiv.org/pdf/1804.10959.pdf

 

유니그램 언어 모델 토크나이저는 각각의 서브워드들에 대해서 손실(loss)을 계산한다. 여기서 서브 단어의 손실이라는 것은 해당 서브워드가 단어 집합에서 제거되었을 경우, corpus의 Likelihood가 감소하는 정도를 말합니다. 이렇게 측정된 서브워드들을 손실의 정도로 정렬하여, 최악의 영향을 주는 10~20%의 토큰을 제거합니다. 이를 원하는 단어 집합의 크기에 도달할 때까지 반복합니다.

'Deep Learning > NLP' 카테고리의 다른 글

BERT  (0) 2024.02.07
ELMo(Embeddings from Language Model)  (0) 2024.02.06
트랜스포머  (0) 2024.01.11
어텐션 메커니즘  (0) 2024.01.11