데이터 한 그릇

BERT 이해하기 본문

NLP/구글 BERT의 정석

BERT 이해하기

장사이언스 2022. 2. 9. 12:44

두 가지 태스크 기반 BERT 모델이 사전 학습을 어떻게 진행하는지 살펴볼 것.

 

  • 마스크 언어 모델링(Masked language modeling) : (MLM)
  • 다음 문장 예측 (Next sentence prediction) : (NSP)

 

마지막장

  • 바이트 쌍 인코딩
  • 바이트 수준 바이트 쌍 인코딩
  • 워드피스

하위 단어 토큰화 알고리즘들 알아볼 것.

 


이번 장에서 알아볼 것들

  • BERT의 기본 개념
  • BERT의 동작 방식
  • BERT의 구조
  • BERT 사전 학습
  • 사전 학습 절차
  • 하위 단어 토큰화 알고리즘

BERT 의 기본 개념

BERT는 word2vec 과 같은 다른 인기 있는 임베딩 모델이 고려하지 못한 문맥(context) 에 대해서 고려한다.

문맥 기반 임베딩 모델과 문맥 독립 임베딩 모델의 차이를 살펴보자.

 

 

A : He got bit by python

 

B : Python is my favorite programming language (내가 가장 좋아하는 프로그래밍 언어는 파이썬이다.)

 

 

위의 두 문장에서 공통으로 나온 단어는 "python" 이다. A문장은 뱀을 의미하며 B문장은 프로그래밍 언어 파이썬을 의미한다. word2vec 같은 경우 두 python 단어에 대해서 동일한 벡터를 반환한다. 하지만 BERT의 경우 각각 다른 벡터를 반환한다. 이는 BERT가 문맥을 고려해서 단어에 대한 벡터를 생성했기 때문에 가능한 일이다.

 

 

BERT는 단어의 문맥상의 의미를 이해하기 위해서 문장 내 어떤 단어의 의미를 문장 내 다른 단어들과 연결시켜 이해한다.

 

따라서 A문장의 파이썬은 문장 내 다른 단어들, 예를 들어서 bit 과 같은 단어들과 연결되어서 이해되기 때문에 뱀이라고 컴퓨터가 이해할 수 있다.


BERT의 동작 방식

BERT는 트랜스포머의 인코더만 사용한 임베딩 모델이다.

트랜스포머의 인코더에 어떤 문장을 넣게 되면, 그 문장의 각 단어에 대한 표현 벡터를 출력한다.

예를 들어서 "He got bit by python" 이라는 문장을 넣게 되면 멀테 헤드 어텐션을 거치고 피드 포워드를 거쳐서 각 단어에 대한 표현 벡터를 출력한다.(Z)


BERT의 구조

BERT는 두 가지 구성의 모델이 존재한다.

  1. BERT - base
  2. BERT - large

BERT - base

12개의 인코더 레이어.

각 인코더는 12개의 어텐션 헤드.

인코더의 피드포워드 네트워크는 768개 차원의 은닉 유닛. => 따라서 BERT를 통해 얻은 단어 벡터의 차원은 768.

 

  • 인코더 레이어의 수 : L
  • 어텐션 헤드 : A
  • 은닉 유닛 : H

BERT - large

24개의 인코더 레이어가 스택처럼 쌓인 형태

각각의 인코더는 16개의 어텐션 헤드를 사용한다.

인코더의 피드포워드 네트워크는 1,024개의 은닉 유닛으로 구성된다.

즉, L : 24, A : 16, H : 1024


그 밖의 여러 BERT 구조

앞의 두 가지 조합 이외에도 다른 조합으로 BERT를 구축할 수 있다.

  1. BERT-tiny : L = 2, A = 2, H = 128
  2. BERT-mini : L = 4, A = 4, H = 256
  3. BERT-small : L = 4, A = 8, H = 521
  4. BERT-medium : L = 8, A = 8, H = 521

컴퓨팅 리소스가 제한되면 작은 크기의 BERT를 사용하는 게 좋을 수 있다.

그러나 표준적으로 BERT-small, BERT-large 가 성능이 좋기 때문에 많이 사용한다.

BERT의 작동 방식과 구조를 살펴봤는데 남은 이슈가 있다.

  • 입력 문장에 대한 적절한 표현을 생성하게 하려면 "BERT를 어떻게 학습" 시켜야 할까?
  • 학습에 어떤 데이터셋을 사용해야 할까?
  • 학습 방법은 무엇일까?

BERT 사전 학습

일반적으로 사전학습이란 이미 학습시켜 놓은 모델을 다음 과제에 사용하는 방식을 말한다.

예를 들어서 특정 태스크에 대한 방대한 데이터셋으로 모델을 학습시키고, 다음 태스크에 이미 학습된 가중치를 초깃값으로 사용한다. 그 이후 새로운 태스크에 맞추어서 가중치를 조정한다.

위의 과정이 일반적인 사전 학습이라고 할 수 있으며 이를 "파인 튜닝" 이라고 부른다.

 


BERT의 입력 표현

BERT에 데이터를 입력하기 전에 다음 세 가지 임베딩 레이어를 기반으로 입력 데이터를 임베딩으로 변환해야 한다.

(3가지 임베딩 레이어를 기반으로 입력 데이터를 임베딩으로 변환)

  • 토큰 임베딩(token embedding)
  • 세그먼트 임베딩 (segment embedding)
  • 위치 임베딩 (position embedding)

 

토큰 임베딩

 

 

A문장 : Paris is a beautiful city (파리는 아름다운 도시다.)

 

B문장 : I love paris (나는 파리를 좋아한다.)

 

 

token = [paris, is, a, ..........love] 처럼 두 문장에 대해서 토큰을 추출한다.

 

첫 번째 문장의 시작 부분에만 [CLS] 를 넣어주고 문장이 끝날 때마다 [SEP] 를 넣어준다.

즉, token = [[CLS] paris, is, a, beautiful, city, [SEP] ..........love]

 

그 다음 토큰 임베딩 레이어를 통해서 추출한 토큰들을 임베딩화 한다.

 

E_cls 는 CLS 토큰을 임베딩한 값이다.

 

세그먼트 임베딩

 

 

세그먼트 임베딩은 주어진 두 문장을 구별하는데 사용된다.

 

 

A문장 : Paris is a beautiful city

 

B문장 : I love paris

 

 

세그먼트 임베딩은 입력값으로 토큰들을 받는다. (위에서 추출한 토큰)

 

출력으로는 문장의 개수만큼 출력값을 출력한다.

위의 예시에서는 두 개의 문장이 토큰화되어 입력값으로 들어갔기 때문에, 출력값으로 E_a, E_b 를 반환한다.

문장 A의 모든 토큰들은 E_a 에 매핑되고, 문장 B의 모든 토큰들은 E_b에 매핑된다.

만일 문장이 A문장만 들어가 있었다면 모든 토큰들은 E_a 에 매핑된다.

 

위치 임베딩

 

 

BERT 자체가 트랜스포머 인코더에 영향을 받은 것이기 때문에 위치 정보가 입력데이터에 들어가 있지 않다. 따라서 위치 정보에 대한 정보를 부여해야만 한다.

 

앞의 토큰한 결과를 이용해서 이해해보자.

위치 임베딩의 입력값으로 다음과 같은 값이 들어갈 것이다.

 

 

[[CLS], Paris, is, a, beautiful, city, [SEP], I, love, Paris, [SEP]]

 

 

 

위치 임베딩은 위의 토큰들에 위치 임베딩을 부여한다.

 

[CLS] : E_0 이 부여되고, Paris : E_1 이 부여된다.

 

최종 입력 데이터 표현

  1. 주어진 입력 문장을 토큰으로 변환
  2. 토큰들을 토큰 임베딩에 공급
  3. 세그먼트 임베딩에 공급
  4. 위치 임베딩에 공급
  5. 모든 임베딩을 합산해 최종적인 BERT의 입력값으로 결정

 

워드 피스 토크나이저

 

 

BERT는 워드피스 토크나이저라는 특별한 유형의 토크나이저를 사용한다.

 

이는 하위 단어 토큰화 알고리즘을 기반으로 한다.

 

예를 들면 다음과 같이 문장을 토큰화할 수 있다.

 

 

Let us start pretraining the model (모델 사전 학습을 시작하자.)

tokens = [let, us, start, pre, ##train, ##ing, the, model]

 

(## 해시 기호는 하위 단어임을 나타내고 앞에 다른 단어가 있음을 의미한다.)

 

워드 피스 토크나이저는 문장을 토큰화할 때 단어 사전을 사용한다.

 

만일 그 토큰이 어휘 사전에 속해 있으면 그대로 토큰으로 사용하고 어휘 사전에 없으면 그 단어를 하위 단어로 분할하고 그 하위 단어가 어휘 사전에 있는지 확인한다.

 

만일 분할된 하위단어가 어휘 사전에 속해있으면 토큰으로 사용하고 그 마저도 어휘 사전에 속해 있지 않으면 다시 하위 단어로 분할한다.

 

이런 식으로 개별 문자에 도달할때 까지 어휘 사전을 기반으로 하위 단어를 계속 분할하고 확인한다.

이 방식은 어휘 사전 이외의 단어를 처리하는데 효과적이다.

 

BERT 어휘 사전 크기는 3만 토큰이다. 토큰이 BERT의 3만 토크 내에 속하는지 확인하고 개별 문자에 도달할때 까지 하위 단어로 분할한다.

 

앞의 예시에서 pretraining 은 하위단어로 나뉘어졌다. 바로 ##train ##ing 이다. train과 ing 단어는 BERT 어휘 사전에 속하기 때문에 그대로 토큰으로 사용한다.

 

이제 이 토큰들에 문장의 첫 시작부분에 [CLS] 를 집어넣고, 문장의 끝나는 부분에 [SEP] 토큰을 집어넣는다.

 

그리고 앞에서 배운 토큰 임베딩, 세그먼트 임베딩, 위치 임베딩에 넣어주고 각각의 출력값을 더해서 BERT의 입력값을 도출한다.

 


사전 학습 전략

BERT는 다음 두 가지 태스크에 대해 사전학습된다.

두 가지 태스크

  1. 마스크 언어 모델링(MLM)
  2. 다음 문장 예측(NSP)

마스크 언어 모델링을 알아보기 전에 언어 모델링의 작동 방식에 대해서 알아보도록 하자.

 

언어 모델링

 

 

언어 모델링은 일반적으로 임의의 문장이 주어지고 단어를 순서대로 보면서 다음 단어를 예측하도록 모델을 학습시키는 것.

 

언어 모델링은 다음 두 가지로 분류될 수 있다

  1. 자동 회귀 언어 모델링(auto-regression language modeling)
  2. 자동 인코딩 언어 모델링(auto-encoding language modeling)
  • 자동 회귀 언어 모델링
    • 전방(왼쪽에서 오른쪽으로) 예측 (forward prediction)
    • 후방(오른쪽에서 왼쪽으로) 예측 (backward prediction)
    • ex) paris is a beautiful ____. I love paris.
    • 전방 예측은 왼쪽에서 오른쪽으로 공백 이전까지의 모든 단어를 읽는다. (paris is a beautiful)
    • 후방 예측은 오른쪽에서 왼쪽으로 공백 이전까지의 모든 단어를 읽는다. (I love paris)
  • 자동 인코딩 언어 모델링
    • 전방 및 후방 예측을 모두 사용한다. (양방향 모델)

여기까지 언어 모델링의 작동 방식을 살펴봤으며 작동 방식이 두 가지로 나뉨을 알아봤다.

이제 본격적으로 마스크 언어 모델링을 알아보자.

 

마스크 언어 모델링(MLM)

 

BERT는 위의 두 가지 언어 모델링 방식 중에서 자동 인코딩 언어 모델이다.

단어를 예측하기 위해서 문장을 **양방향**으로 읽는다.

 

마스크 언어 모델링은 주어진 입력 문장에서 임의의 15%를 무작위로 MASK로 마스킹한다.

그리고 그 무작위로 MASK 된 단어를 예측하도록 모델을 학습시킨다.

 

하지만 문제가 발생하는데, 사전 학습과 파인 튜닝 사이에 불일치가 생기게 된다. 즉 이미 학습해둔 가중치를 이용해서 새로운 입력값에 대해서 가중치를 조정할 때, 불일치가 발생한다.

 

사전 학습때는 MASK 토큰을 예측하면서 모델을 학습시키는데, 파인 튜닝에는 입력값에 MASK 가 없다. 따라서 불일치가 생긴다.

 

 

이 문제를 해결하기 위해서 80-10-10% 의 규칙을 적용한다.

 

문장에서 토큰의 15%를 마스킹하는 걸 살펴봤다. 그럼 그 15% 토큰에 대해서 다음을 수행한다.

  1. 80%의 토큰을 MASK 토큰으로 교체한다.
  2. 10%의 토큰을 임의의 토큰(단어) 으로 교체한다.
  3. 10% 토큰은 어떠한 변경도 하지 않는다.

토큰화 및 마스킹 후에 입력 토큰을 토큰, 세그먼트, 위치 레이어에 입력해서 최종 입력 임베딩을 얻는다.

 

 

최종 입력 임베딩을 인코딩에 넣어주면, 각 토큰의 표현 벡터가 도출된다. (R)

 

R_cls = cls 에 대한 표현 벡터, R_paris 는 paris 에 대한 표현 벡터다.

이제 이러한 표현으로 마스크된 토큰을 어떻게 예측하게 될까?

즉 R_mask 을 어떻게 예측할까?

 

입력 벡터를 넣어서 얻은 R_mask의 표현을 소프트맥스 활성화 함수에 넣어주고 피드포워드 네트워크에 입력한다.

 

즉, R_mask => 소프트맥스 => 피드포워드 순서를 거친다.

이때 반환되는 값은 R_mask 단어가 마스크된 단어가 될 확률이다.

 

반환값이 각 단어에 대한 확률이 나올텐데 만일 city 가 0.9로 가장 높으면 city라는 단어가 마스크된 단어일 확률이 가장 높음을 의미한다.

 

이 경우 마스크된 단어는 city로 예측된다.

 

위의 마스크 언어 모델링 태스크는 "빈칸 채우기 태스크" 라고도 한다.

 

 

지금까지 마스크 언어 모델링 태스크가 작동하는 방식과 마스크 언어 모델링 태스크를 사용해 BERT를 학습시키는 방법을 배웠다.

 

전체 단어 마스킹(WWM) 방법

 

 

전체 단어 마스킹(Whole Word Masking)(WWM) 에 대해서 살펴볼 것.

 

예시 문장으로 "let us start pretraining the model" 에 대해서 살펴보자.

 

 

BERT는 입력 문장에 대해서 워드피스 토크나이저 방식을 사용하기 때문에 BERT사전을 이용해서 토큰을 결정짓고, 사전에 없는 단어에 대해서 하위 단어로 쪼개게된다. 위의 예시 문장에 대해서 워드피스 토크나이저 방식을 사용하게 되면 아래와 같은 반환값을 얻을 수 있다.

 

 

 

[let, us, start, pre, ##train, ##ing, the, model]

 

 

그리고 문장의 시작에 문장이 끝날 때를 나타내는 태그를 단다.

 

 

[[CLS], let, us, start, pre, ##train, ##ing, the, model, [SEP]]

 

그리고 사전 학습을 할 때 마스크 언어 모델링을 사용했음을 살펴봤기 때문에 그 방식을 그대로 사용한다.

문장 내 15%의 토큰에 대해서 MASK 처리 한다.

이때 가정으로 하위 단어인 ##train 이 MASK 됐다고 가정해보자. 전체 단어 마스킹 방식에서는 하위 단어가 MASK 처리 되면 해당 하위 단어와 관련된 모든 단어를 마스킹한다. 따라서 아래와 같은 리스트를 반환한다.

 

[[CLS],[MASK],us, start,[MASK],[MASK],[MASK], the, model, [SEP]]

 

이때 WWM(전체 단어 마스킹) 방식은 마스킹의 비율을 15%를 유지하려고 하기 때문에 하위 단어 MASK 처리할 때 15%가 넘어서게 되면, 비율을 유지하기 위해서 다른 단어의 MASK 를 무시한다.

예를 들어서 아래는 하위 단어를 MASK 처리 하면서 15%가 넘어서려고 하기 때문에, let 토큰을 mask 처리하는 걸, 생략했다.

 

[[CLS], let, us, start, [MASK],[MASK],[MASK], the, model, [SEP]]

 

위와 같이 전체 단어 마스킹(WWM) 방식으로 토큰을 마스킹 한 이후, BERT에 입력하고 (토큰, 세그먼트, 위치) 레이어를 통과한 최종 입력 임베딩에 의해서 각 토큰의 표현 벡터가 생성이 된다.

마찬가지로 마스크된 토큰을 예측하도록 모델을 학습시킨다.(소프트맥스, 피드 포워드)

 

지금까지 마스커 언어 모델링을 살펴봤으며 그 방식으로 기본 마스크 언어 모델링과 전체 단어 마스킹 방식을 살펴봤다.

 

 

 

다음 문장 예측(NSP)

 

 

NSP는 이진 분류 테스트다.

 

BERT에 두 개의 문장을 입력하고, 두 번째 문장이 첫 번째 문장의 다음 문장인지 예측한다.

 

A : She cooked paste

 

B : It was delicious

 

 

여기서 b문장은 a문장의 후속 문장이다. 이 문장쌍을 isNext 로 표시해서 B문장이 A문장의 다음 문장임을 알 수 있게 한다.

 

 

A : Turn the radio on

 

B : She bought a new hat

 

 

이 문장에서 b문장은 a문장의 후속 문장이 아니다.

 

이 문장 쌍을 notNext 로 표시해 b문장이 a문장의 다음 문장이 아님을 알 수 있게 한다.

 

 

NSP 태스크의 목표는 문장 쌍이 isNext 범주에 속하는지 속하지 않는지 여부를 예측하는 것이다.

 

즉, 입력 문장 쌍을 bert 모델에 입력하고 b문장이 a문장 다음에 오는지 여부를 예측하도록 학습한다.

만일 b문장이 a문장에 이어지는 문장이면 isNext 를 반환하고 그렇지 않으면 notNext 를 반환한다.

따라서 NSP 는 본질적으로 이진 분류 태스크다.

(이로써 두 문장 사이의 관계를 파악할 수 있다.)

NSP 태스크 데이터셋 얻는법

두 문서가 있다고 가정.

isNext 클래스 경우 한 문서에서 연속된 두 문장을 isNext로 표시한다.

notNext 클래스 경우, 한 문서에서 한 문장을 다른 문서에서 다른 문장을 가져와서 notNext 로 표시한다.

이때 isNext 클래스와 notNext 클래스의 비율을 50 : 50 으로 맞추어 균형을 이룰 수 있도록 한다.

NSP 태스크를 위해서 BERT를 학습시키는 방법

isNext 인 문장 쌍과 notNext 인 문장 쌍이 존재한다고 가정하자.

문장 쌍에 대해서 토큰화를 진행하고 문장의 시작에 [CLS] 를 문장을 구별하기 위해서 [SEP] 을 문장의 끝에 넣어준다.

그리고 토큰 레이어, 세그먼트 레이어, 위치 레이어에 토큰 입력값을 넣어주고 임력 임베딩 값을 얻는다.

이 입력 임베딩 값을 BERT 모델에 넣어서 각 토큰의 표현 벡터를 반환받는다.

NSP 는 이진 분류라고 했는데, 지금 우리는 문장 쌍에서 각 토큰의 표현 벡터값만을 가지고 있다.

이러한 표현을 기반으로 문장 쌍을 어떻게 분류할 수 있나?

 

 

우리는 각 토큰을 벡터화할 때, [CLS] 토큰에 대해서 벡터값을 얻었다.

 

CLS토큰은 기본적으로 모든 토큰의 집계 표현을 보유하고 있다.

따라서 다른 토큰 표현을 무시하고 CLS 토큰 표현 R_cls 를 가져와서 소프트맥스 함수에 넣고 피드 포워드 신경망에 집어넣는다.

그러면 피드포워드는 isNext 에 대한 확률과 notNext 에 대한 확률을 반환한다.

(초반에는 당연히 예측을 잘 하지 못하지만, 역전파를 통해서 예측 성능을 향상시킨다.)

 

 

지금까지 마스크 언어 모델링(MLM) 과 다음 문장 예측(NSP) 태스크를 기반으로 해서 BERT를 사전 학습시키는 방법을 확인했다.

 

(마스크 언어 모델링 : 마스크된 토큰에 대해서 예측하는 방식)

 

다음으로 사전 학습 절차 볼 것.

 

 

사전 학습 절차

MLM과 NSP 두 개에 대해서 따로 진행하는 게 아니라 한꺼번에 진행한다.

BERT의 사전 학습에는 토론토 책 말뭉치 및 위키피디아 데이터셋을 사용한다.

 

 

말뭉치에서 두 문장을 샘플링하는데, A와 B문장의 총 토큰 수의 합은 512와 같거나 작아야한다.

 

또 두 문장을 샘플링할 때는 50%는 B문장이 A문장의 후속문장으로 준비하고 50%는 후속이 아니게 준비한다.

 

 

뽑은 두 개의 문장이 다음과 같다고 가정하자.

 

 

 

A : We enjoyed the game

 

B : Turn the radio on

 

 

bert는 토큰화를 위드피스 토크나이저를 사용한다. 따라서 다음과 같은 값을 얻었다고 해보자.

 

tokens = [[CLS], we, enjoyed, the, game, [SEP], turn, the radio, on, [SEP]]

 

 

마스크 언어 모델링을 위해서 15%를 MASK 처리하되, 80-10-10 규칙에 따라서 MASK 처리한다.(80%마스킹, 10% 다른 토큰으로 교체, 10% 정답 그대로)

 

위와 같은 작업으로 문장을 토큰화한 이후 BERT모델에 입력한다.

BERT 모델은 마스크된 토큰을 예측하기 위해 모델을 학습한다.

 

 

중요한건!! 이와 동시에 NSP(다음 문장 예측) 학습도 진행한다.즉, B문장이 A문장의 후속 문장인지 여부를 분류하게 한다.

 

그러면 MLM 작업과 NSP 작업을 동시에 진행한 것과 같다.

BERT는 100만 스탭을 학습, 각 스탭당 256 입력 시퀀스에 대해 학습,

학습률은 lr = 1e-4, B_1 = 0.9, B_2 = 0.999

optimizer 는 아담 옵티마이저

웜업은 1만 스텝

학습 초기에는 학습률을 크게 주어서 학습을 과감하게 하는 반면, 학습이 많이 진행될수록 학습률을 작게 주어 미세하게 조정하려고 한다.

이렇게 학습이 진행되면서 학습을 감소시키는 것을 "학습률 스케줄링" 이라고 한다.

웜업 스텝도 학습률 스케줄링의 일부다. 만일 웜업 스텝이 1만 스텝이고 학습률이 1e-4이면 초기 1만 스텝은 학습률이 0에서 1e-4로 선형적으로 증가한다는 것을 의미한다. 1만 스텝 후에는 수렴에 가까워지니까 선형적으로 학습률을 감소시킨다.

즉, 웜업 스텝의 스텝값은 어느 스텝까지 학습률만큼 선형적으로 증가시킬지에 대한 value이다.

 

드롭아웃 확률이 0.1인 모든 레이어에 드롭아웃을 적용.

BERT에서는 갤루(GELU) 활성화 함수를 사용한다.

GeLU 활성화함수를 내가 잘 이해하지 못한 거 같다. 어떡하지..


하위 단어 토큰화 알고리즘

일반적으로 단어를 토큰화할 때 단어 Vocabulary 를 사용한다.

Vocabulary 내에 모든 고유 단어들을 포함시킨다.

[game, the, I, played, walked, enjoy]

 

 

다음으로 문장 "I played the game" 이 있다고 가정하자. 이를 공백을 기준으로 나누고 리스트에 담으면 다음과 같다.

 

[I, played, the, game]

Vocabulary 사전을 보면 각 토큰에 해당하는 단어들이 존재한다. 따라서 토큰으로 그대로 인정한채 놔둔다.

 

 

하지만 I enjoyed the game 에 대해서 생각해보자. 토큰화를 하면 다음과 같은 리스트를 얻는다.

 

[I, enjoyed, the, game]

Vocabulary 내에는 enjoyed 가 존재하지 않는다. 따라서 이를 unknown 으로 처리한다. 태그 <UNK> 를 사용한다.

따라서 최종적으로는 다음과 같은 토큰 리스트를 얻는다.

 

 

tokens = [I, <UNK>, the, game]

 

 

 

unk 를 줄이기 위해서 어휘사전을 늘릴수도 있지만 이는 메모리 문제가 발생할 수 있다. 알 수 없는 단어에 대해서 해결하기 위해서 하위 단어 토큰화 알고리즘을 사용한다.

 

 

 

앞의 예제에서 Vocabulary 의 각 단어들에 대해서 하위 단어로 분할한다. 그러면 다음과 같은 결과를 얻는다.

 

 

[game, the, I, play, walk, ed, enjoy]

 

 

다음으로 i enjoyed the game 을 토큰화해보자. 그러면 다음과 같은 토큰 리스트를 얻을 수 있다.

[I, enjoy, ##ed, the, game]

 

앞에서 살펴봤듯이 ##은 앞에 단어가 있고 본인이 하위 단어임을 가리킨다.

 

그런데 enjoy는 하위 단어로 분리되어놓고 왜 ## 이 붙지 않았을까? 이는 단어의 시작 부분이기 때문에 해당하는 단어에는 ## 기호를 추가하지 않는다.

 

여기서 의문점이 존재한다. 앞서 어휘사전에 있는 단어들을 하위 단어로 만들때 played 와 walked 단어를 하위 단어로 만들었다. 그렇다면 왜 나머지 단어들에 대해서는 하위 단어를 만드는 작업을 수행하지 않을까? 즉, 하위 단어를 만들어야 하는 단어 선정은 어떻게 이루어지는걸까?

 

하위 단어 토큰화 알고리즘을 통해서 이 부분에 대해 알 수 있다.

 

 

하위 단어 토큰화 알고리즘

 

  • 바이트 쌍 인코딩
  • 바이트 수준 바이트 쌍 인코딩
  • 워드피스

 

바이트 쌍 인코딩

바이트 쌍 인코딩(byte pair encoding)(BPE) 가 동작하는 방식을 이해해보자.

데이터 셋에서 모든 단어를 빈도수와 함께 추출한다고 해보면 다음과 같은 튜플 형식으로 도출된다.

(cost, 2), (best, 2),(menu,1),(men,1),(camel,1)

 

 

여기서 모든 단어들에 대해서 문자 시퀀스로 만든다. 즉, Cost 면 C o s t 로 시퀀스로 만든다.

 

이와 같이 단어에 대한 문자 시퀀스와 그 문자 시퀀스에 대하 빈도수를 우리는 가지게 된다.

이제 바이트 쌍 인코딩을 통해서 어휘 사전을 생성한다.

어휘 사전의 크기를 14로 지정해보겠다.

먼저 문자 시퀀스 내에서 고유 문자들을 꺼내어 어휘 사전에 집어 넣는다.

 

 

Cost, best, menu, men, camel 의 문자 시퀀스가 있을 때, 이 때의 어휘 사전은 [a,b,c,e,l,m,n,o,s,t,u] 이다.

 

이 어휘 사전의 크기는 11이다.

14가 최대 크기기 때문에 어휘 사전에 새로운 토큰을 추가한다.

 

 

먼저 가장 빈도수가 큰 기호 쌍을 식별한다.

 

가장 빈번한 기호 쌍을 병합해 어휘 사전에 추가한다.

위의 예시에서는 Cost, best 중 s,t가 4번 발생했기 때문에 가장 빈번한 기호 쌍이 s와 t임을 알 수 있다.(cost시퀀스가 두 개, best 시퀀스가 두 개니까 s,t 발생은 4번)

"st"

따라서 어휘 사전에 st를 추가한다.

 

그 다음 과정도 마찬가지로, 같은 작업을 반복한다.

위의 st를 제외하고 우리가 가지고 있는 가장 빈번한 쌍은 m과 e이다.

men에서 한 번, menu 에서 한 번, 그리고 camel 에서 한 번 총 3번이다.

따라서 m과 e를 병합해서 어휘 사전에 추가한다.

 

 

자, 다시 한번 빈번한 쌍을 확인해보자.

 

그 다음으로 가장 빈번한 쌍은 me와 n이다.

menu 에서 한 번, men 에서 한 번 발생한다.

그래서 me와 n을 병합하고 어휘 사전에 추가한다.(men 어휘 사전에 추가)

우리는 어휘 사전의 최대 크기를 14로 지정했다. 따라서 바이트 쌍 인코딩을 마무리 한다.

 

 

바이트 쌍 인코딩(BPE) 의 순서는 다음과 같다.

 

  1. 빈도수와 함께 주어진 데이터셋에서 단어 추출
  2. 어휘 사전 크기 정의
  3. 단어를 문자 시퀀스로 분할 (C O S T)
  4. 문자 시퀀스의 모든 고유 문자를 어휘 사전에 추가
  5. 빈도가 높은 기호 쌍을 선택하고 병합
  6. 어휘 사전 크기에 도달할 때까지 앞 다섯 단계 반복

BPE 로 토큰화하기

 

 

Vocabulary = {a,b,c,e,l,m,n,o,s,t,u,st,me,men} 일 때,

 

입력 텍스트가 mean 단어 한 개라고 해보자.

mean 이라는 단어가 사전에 속해있지 않다.

따라서 me, an 으로 나누게 된다. me는 단어 사전에 있는 반면에 an은 단어 사전에 없음을 알 수 있다.

따라서 an을 또 토큰화한다. 그러면 me,a,n 이 되는데 a와 n이 단어 사전에 존재하므로 토큰으로 인정한다.

 

 

또 예를 들어서 bear 를 해보자.

 

be 와 ar로 단어를 나눌 수 있다. 그러면 be는 단어 사전에 있지만 ar은 단어 사전에 존재하지 않는다. 따라서 a, r 로 나눈다.

마지막으로 a,r 이 단어 사전에 존재하는지 확인한다.

a는 존재하는데 r은 존재하지 않는다. 결국 r은 <UNK> 토큰으로 교체된다.

따라서 최종 토큰은 [be, a, <UNK>] 가 된다.

 

 

지금까지 BERT의 사전 학습을 알아보면서 사전 학습 방식으로 마스크 언어 모델링과 다음 단어 예측을 살펴봤다.

 

마스크 언어 모델링을 하기 전에 단어 집합에 대해서 토큰화와 마스크를 지정했다. BERT의 토큰화 진행 방식은 하위 단어 토큰화 알고리즘을 따른다.

이때 하위 단어 토큰화 알고리즘의 단어 사전 지정 방식은 바이트 쌍 인코딩방식과 바이트 수준 바이트 쌍 인코딩 방식 그리고 워드피스가 있다.

 

지금까지는 바이트 쌍 인코딩 방식을 살펴봤으니 바이트 수준 바이트 쌍 인코딩 방식을 살펴보도록 하자.

 


바이트 수준 바이트 쌍 인코딩

바이트 수준 바이트 쌍 인코딩(byte-level byte pair encoding)(BBPE) 은 BPE와 매우 유사하게 작동하지만 문자 수준 시퀀스를 사용하는 대신에 바이트 수준 시퀀스를 사용한다.

 

예를 들어서 입력값으로 best 가 있다고 가정하자.

그러면 bpe는 이 입력값에 대해서 문자시퀀스로 바꾼다 [b e s t] 로 바꾼다.

 

그러면

 

[62 65 73 74 ] 가 된다.

각 유니코드 문자는 바이트로 변환되기에 단일 문자 크기는 1~4바이트가 될 수 있다.

이렇게 텍스트를 바이트 수준 시퀀스로 변환한 다음에 바이트 수준에서 bpe 방식을 적용해 빈번한 쌍을 구분해 어휘 사전을 구축한다.

바이트 수준 바이트 쌍 인코딩bbpe 를 사용하는 이유는 다국어 설정에 매우 유용하기 때문이다.


워드피스

지금까지 하위 단어 토큰화 알고리즘을 사용할 때 하위 단어 토큰화 알고리즘에 사용되는 bpe 와 bbpe를 살펴봤다. 다음으로 워드피스를 살펴보도록 하자.

bpe에서는 주어진 데이터셋에서 먼저 단어의 빈도수를 추출하고 단어를 문자 시퀀스로 분할한다.

다음으로 빈도수가 높은 기호 쌍을 병합한다.

어휘 사전 크기에 도달할 때까지 반복적으로 고빈도 기호쌍을 병합한다.

 

근데 차이점은 여기서는 빈도에 따라서 심볼 쌍을 병합하지 않는다.(bpe,bbpe는 빈도가 높은 순으로 심볼 쌍을 연결했다.)

워드피스는 가능도에 따라서 기호를 병합한다.

 

먼저 모든 기호쌍에 대해서 가능도를 확인한다.

가능도가 가장 높은 기호 쌍을 병합한다.

기호간 가능도 계산 식은 다음과 같다

p(st) / p(s)p(t)

가능도가 높으면 기호 쌍을 병합하고 가능도가 낮으면 병합하지 않는다.

(가능도가 최대 높은 것부터)

지금까지 우리는 bert의 사전 학습 방식에 대해서 살펴봤다.

앞으로는 사전학습된 bert를 적용하는 방법을 살펴볼 것이다.

 

마치며

BERT는 문맥에 관계없이 단어 임베딩을 수행했던 word2vec과 달리 문맥을 고려해서 임베딩함을 살펴봤다.

또한 bert는 트랜스포머 모델임을 살펴봤다.

bert의 사전 학습 방식인 MLM과 NSP 두 개 살펴봤다.

그리고 사전 학습 절차도 살펴봤고 끝으로는 문장을 토큰화 시키는 하위 단어 토큰화 알고리즘에 대해서 세 개의 원리를 살펴봤다.(BPE, BBPE, 워드피스)

다음으로는 BERT 활용을 살펴볼 것이다.

 

 

 

'NLP > 구글 BERT의 정석' 카테고리의 다른 글

텍스트 요약을 위한 BERTSUM 탐색  (0) 2022.02.17
BERT 파생 모델 2 : 지식 증류 기반  (0) 2022.02.16
BERT 파생 모델  (0) 2022.02.15
BERT 활용하기  (0) 2022.02.10
BERT시작하기 - 트랜스포머 입문  (0) 2022.02.03
Comments