Computer Science/구글 BERT의 정석

[구글 BERT의 정석] 2. BERT 이해하기

  • -
728x90
반응형

BERT는 다양한 자연어 처리 태스크 분야에서 가장 성능이 뛰어나고, 자연어 처리 분야에서 한 걸음 나아가는데 이바지한 모델이다.

2.1 Basic idea of BERT

기존의 word2vec와 같은 다른 인기있는 모델과 달리, BERT는 단어의 의미를 파악하는 과정에서 문맥을 고려하였다. 그 결과 질문에 대한 대답, 텍스트 생성, 문장 분류 등과 같은 태스크에서 가장 좋은 성능을 도출하여, 자연어 처리 분야에 크게 기여하였다.

 

단어의 의미를 파악하는 과정에서 문맥을 고려하는지 여부로 모델을 분류하면 다음과 같다.

  • 문맥 독립 모델 (Context-free-model) : word2vec
  • 문맥 기반 모델 (Context-based-model) : BERT

두 개념의 차이를 명확히 이해하기 위해, 다음과 같은 2개의 문장을 예시로 들어보자.

A : He got bit by python.

B : Python is my favorite programming language.

 

Context-free-model의 경우, A와 B에서 사용된 python의 문맥적 의미는 다르지만 해당 단어를 동일한 임베딩으로 잡는다.

하지만, Context-based-model의 경우는 문맥적 의미를 고려하여 다른 임베딩으로 잡는다는 점에서 차이가 존재한다.

 

이를 위하여, 각 단어의 의미를 파악할 때 모든 단어와 연결시켜서 이해하는 작업을 수행하게 된다.

왼쪽 : A에서 python의 문맥적 의미 파악, 오른쪽 : B에서 python의 문맥적 의미 파악

위 그림을 보고 1장에서 학습한 어텐션이 떠올랐는가? 정상이다.

BERT는 이름에서 볼 수 있는 것처럼 Bidirectional Encoder Representation from Transformer 즉 트랜스포머의 인코더 부분만을 활용한 모델이다.

 

좀 흥미가 생기는가? 그렇다면 자세한 동작 방식은 다음 장에서 살펴보도록 하겠다.

2.2 Working of BERT

1장에서 살펴본 것처럼, 인코더는 multi-head attention을 사용해서 문장의 각 단어의 문맥을 이해하여 문장에 있는 각 단어의 의미를 출력으로 반환한다. 이 과정에서 사용되는 인코더의 개수는 N개이다.

 

해당 과정을 도식화하면 다음과 같다.

2.3 Configurations of BERT

BERT 아키텍쳐를 처음 제안한 논문 저자들은 다음 두 가지 구성의 모델을 제안하였다.

  • BERT-base
  • BERT-large

각 모델에 대해서 자세하게 살펴보도록 하자.

2.3.1 BERT-base

  1. 12 Encoder layers
  2. All the encoders use 12 attention heads
  3. feedforward network in the encoder consists of 768 hidden units

일반적으로는 인코더 레이어의 개수를 $L$, 어텐션 헤드의 개수를 $A$, hidden unit는 $H$로 표현한다.

따라서, BERT-base의 경우, $$L = 12,  A = 12,  H = 768$$이다. Total parameter는 1억 1천만개이다.

BERT-base

2.3.2 BERT-large

  1. 24 Encoder layers
  2. All the encoders use 16 attention heads
  3. feedforward network in the encoder consists of 1024 hidden units

따라서, BERT-large의 경우, $$L = 24,  A = 16,  H = 1024$$이다. Total parameter는 3억 4천만개이다.

BERT-large

2.4 Pre-training the BERT model

BERT를 사전 학습 시키는 방법을 알아보기에 앞서, 사전학습이 무엇인지에 대해 알아보도록 하겠다.

 

설명의 편의를 위해 모델 하나를 학습시켜야한다고 가정하면, 사전 학습은 크게 다음과 같은 방법으로 진행된다.

  1. 특정 태스크에 대한 방대한 데이터셋으로 모델을 학습시키고, 해당 모델을 저장해둔다.
  2. 새로운 태스크가 주어졌을 때 처음부터 모델을 학습시키는 것이 아니라, 위에서 방대한 데이터를 통해 학습된 모델을 활용한다.

즉, 미리 방대한 데이터셋을 활용하여 적합한 모델을 구하고, 이를 활용하여 새로운 태스크에 가중치를 조정하는 방식으로 진행하게 된다.

 

BERT의 경우 MLM, NSP라는 2개의 Task를 이용하여 거대한 말뭉치를 기반으로 사전학습 된다. 앞서 살펴본 것처럼, 새로운 태스크가 주어진 경우에도 처음부터 학습시키기보다는 사전 학습된 BERT를 이용하여 튜닝하게 된다.

 

BERT의 사전학습은 크게 input representation 부분, MLM 부분, NSP 부분으로 분류할 수 있다. 각각에 대해서 자세하게 알아보도록 하자.

2.4.1 Input representation

BERT의 input은 다음 3가지의 embedding의 합으로 이루어져 있다.

  • Token embedding
  • Segment embedding
  • Position embedding

각 embedding layer가 어떤식으로 동작하는 지 알아보도록 하자.

Tokenizing

위 3개의 embedding을 거치기 전에, 입력 데이터에 대해서 tokenizing 과정을 거치게 된다.

해당 과정은 다음과 같은 순서로 진행된다.

  1. WordPiece tokenizer를 활용하여 토큰화한다.
  2. 첫 번째 문장의 시작부분에만 [CLS] 토큰을 추가한다.
  3. 모든 문장 끝에 [SEP] 토큰을 추가한다.

예를 들어, 다음과 같은 2개의 문장이 있다고 생각해보자

Paris is a beautiful city. I love paris

 

먼저 BERT의 경우 위 문장을 토큰화 하기 위하여 WordPiece tokenizer를 활용하게 된다.

컴퓨터에게 존재하는 모든 단어들을 알려줄 수는 없다. 하지만 그렇게 되면 주어진 테스크를 수행하기 어려워지는 문제가 발생하게 된다. 이에 해당 문제를 해소하기 위해 WordPiece tokenizer를 활용하는 것이다. WordPiece tokenizer가 동작하는 과정은 다음과 같다.

  1. 단어가 어휘 사전(Dictionary)에 있는지 확인한다.
  2. 만약 존재하면 해당 단어를 토큰으로 사용하고, 존재하지 않으면 subword로 분할하고 1의 과정을 반복한다.

이 과정을 통해 어휘 사전 이외(out-of-vocabulary i.e OOV)의 단어를 처리하는데 효과적이다. 이를 통해 희귀어나 신조어 등을 분석하기 쉬워지고, 한국어나 영어 같이 접두사, 접미사 등에서 의미를 파악할 수 있기에 위 방식이 어느정도 효과적으로 작동되고 있다. subword로 tokenize하는 알고리즘은 여러가지가 있는데 관련해서는 마지막에 정리해서 살펴보도록 하자.

 

위 예시에서는 다음과 같이 tokenizing되었다고 가정하자.

tokens = [Paris, is, a, beautiful, city, I, love, Paris]

그 다음으로 첫 번째 문장의 시작부분에만 [CLS] 토큰을 추가한다. 해당 결과는 다음과 같다.

tokens = [[CLS], Paris, is, a, beautiful, city, I, love, Paris]

마지막으로 모든 문장의 끝에 [SEP] 토큰을 추가한다. 해당 결과는 다음과 같다.

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

Token embedding

위 과정을 통해 문장을 토큰화하고, 해당 토큰을 token embedding으로 변환한다. 이때, 모든 토큰에 대해서 대응되는 임베딩이 존재하기에 변환하는데 문제가 발생하지 않는다.

Token embedding

Segment embedding

다른 문장끼리 구별하기 위하여 사용되는 임베딩이다. 모델에 다른 문장끼리 구분하기 위하여 [SEP] 토큰과는 별도로 지표를 제공하는 역할을 수행하게 된다.  위 예시에서는 문장이 2개이므로, 각 문장에 속한 토큰 별로 다른 세그먼트 임베딩 처리가 진행되게 된다.

Segment embedding

Position embedding

1장에서 설명한 positional encoding과 다르지 않으므로 설명은 생략하도록 하겠다. RNN과 LSTM과 달리 모든 단어를 병렬로 처리하기에 단어 순서와 관련된 정보를 모델에 제공하기 위해서 해당 임베딩 처리를 진행하였다.

Position embedding

최종적으로는 3가지의 임베딩 결과를 모두 합산해서 BERT의 입력으로 제공되게 된다.

Input representation

2.4.2 Masked language modeling(MLM)

MLM은 주어진 입력 문장에서 전체 단어의 15%를 무작위로 마스킹하고 마스크된 단어를 예측하도록 모델을 학습시키는 것이다.

이를 통해 모델은 양방향으로 문장을 읽으면서 MASK 처리된 토큰의 원래 단어를 정확하게 예측하게끔 학습된다. 또한 MLM은 cloze task라고도 불리기도 한다.

 

하지만, fine-tune하는 과정에서는 [MASK] 토큰이 없기때문에 사전 학습 방향의 방식과 차이가 발생하게 된다. 이에 해당 문제를 해결하기 위해서 80-10-10% 규칙을 도입하였다. 

  • 15% 중 80%를 [MASK] 토큰으로 교체한다.
  • 15% 중 10%를 임의의 토큰(임의의 단어)로 교체한다.
  • 15% 중 10%를 어떠한 변경도 하지 않는다.

이를 위한 순서를 나타내면 다음과 같다.

  1. 2.4.1의 Tokenizing을 처리한다.
  2. 위에서 언급한 masking 작업을 수행한다.
  3. 2.4.1의 3가지 embedding 값을 구하고 해당 결과를 더하여 input embedding을 얻는다.
  4. 3에서 얻은 결과를 BERT에 제공한다. 그 결과 각 토큰마다 representation vector를 얻게 된다.
  5. 4의 결과 중 MASK 처리 된 토큰의 표현을 softmax 처리 후 피드포워드 네트워크에 입력한다. 그 결과 vocabulary안에 속한 단어들 이 MASK 처리된 단어일 확률을 출력하게 된다. (차원은 vocabulary에 속한 단어의 수)
  6. 가장 높은 출력값을 가지는 값을 mask된 단어로 추정한다.

위 내용을 도식화하면 다음과 같다.

Representation of each token
Predicting the masked token

Whole Word Masking(WWM)

추가적으로 Whole Word Masking(i.e WWM)의 경우도 위와 같이 비슷하게 진행되나, 마스킹하는 부분에서만 차이가 발생한다.

앞에서는 랜덤한 15% 토큰으로 MASK 후보를 착출했다면, 이 방식은 그 과정에서 하위 단어(subword)가 마스킹되면 그것과 관련된 모든 단어를 마스킹처리한다는 점에서 차이가 있다. 그 과정에서 마스크 비율이 15%를 초과한다면, 다른 단어의 마스킹 단어를 무시함으로써 그 비율을 유지하게 된다.

 

예를 들어 tokenizing 처리 후의 결과가 다음과 같다고 가정해보자.

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

만약 15%를 랜덤하게 마스킹하는 과정에서 let과 ##train이 선택되면, ##train이 subword이기에 해당 토큰과 관련된 pre, ##ing도 추가적으로 마스킹 처리를 진행하게 된다. 이 과정에서 15%를 초과하게 되므로 let이라는 단어의 마스킹을 무시하게 된다. 따라서 최종적으로 마스킹 처리된 결과는 다음과 같다.

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

2.4.3 Next sentence prediction(NSP)

NSP 태스크에서는 BERT에 두 문장을 입력하고 두 번째 문장이 첫 번째 문장의 다음 문장인지 예측한다. 위 사전학습을 진행하는 이유는 여러 중요한 NLP task 중 QA나 Natural Language Inference(NLI)는 두 문장 사이의 관계를 이해하는 것이 중요하지만, 이들은 language modeling에서 caputre되지 않기 때문이다. 

 

사전 학습 과정에서는 실제로 이어지는 문장과, 랜덤으로 추출된 두 문장을 각각 50%, 50% 비율로 제공하여 균형을 이룰 수 있게끔 한다.

NSP

위 그림에서 볼 수 있는 것처럼 CLS의 representation을 가져와서 softmax와 피드포워드 네트워크를 통과시켜서 두 문장이 연결되어있는지, 아닌지 판단하게 된다. CLS 토큰의 representation을 사용하는 이유는, 해당 토큰이 모든 토큰의 representation을 보유하고 있으므로 문장 전체에 대한 표현을 담고 있기 때문이다.

2.4.4 Pre-training Procedure

앞에서 설명한 것들을 종합하여 사전학습이 진행되는 순서를 살펴보도록 하자.

  1. Corpus에서 2개의 문장을 샘플링한다. 단, NSP에서 언급한 것처럼 실제로 연결되어있는 문장 2개와, 랜덤으로 추출된 문장 2개의 비율이 각각 50%가 되게끔 한다. (OOM(out of memory)때문에 2개 문장의 토큰 수의 합은 512보다 작거나 같아야 한다.)
  2. Tokenizing 처리를 한다.
  3. 80-10-10% 규칙에 따라 토큰의 15%를 무작위로 마스킹한다.
  4. Token embedding, Segment embedding, Position embedding를 구하고, 이를 통해 input embedding을 구한다.
  5. 해당 결과를 BERT에 넣고, MLM과 NSP 작업을 동시에 사용해 BERT를 학습시킨다.

Hyper Parameter

  • Batch size : 256 sequence (256 sequence * 512 tokens = 128,000 tokens/batch) for 1,000,000 steps. 이는 3.3 billion word corpus를 40 epochs 돌린 것에 근사한 수치이다.
  • Adam optimizer, $lr$ : 1e-4, $\beta_1$ = 0.9, $\beta_2$ = 0.999, L2 weight decay of 0.01
  • Learning rate warmup over the first 10,000 steps, linear decay of the learning rate
  • Dropout : 0.1
  • GELU

이때, GELU를 사용한 점이 되게 독특한데 해당 내용은 "Gaussian Error Linear Units (GELUs), by Dan Hendrycks and Kevin Gimpel" 논문을 참고하도록 하자. 필기본은 하단에 첨부하도록 하겠다.

GELU.pdf
2.60MB

짧게 짚어보자면 GELU는 기존의 Nonlinearitity를 주는 부분과 stochastic regularizer가 구분되어있던 부분을 하나로 묶는 역할을 수행하게 된다고 이해해주면 된다. 또한, 해당 식에 Gaussian CDF가 등장하게 되는데 이는 input값이 일반적으로 정규분포를 따르는 경향이 있기 때문이다(Batch normalize면 특히 더)

 

Input값에 영향을 받기에 non-linearity를 가지면서도, 확률적으로 해당 값이 zero-one mask를 취하게 된다는 점에서는 stochastic regularizer 역할을 수행하고 있다고 볼 수 있다.

 

해당 함수의 개형은 다음과 같다.

GELU

2.5 Subword tokenization algorithms

앞서 WordPiece tokenizer를 설명하면서 subword로 tokenize하는 알고리즘이 여러가지 있다고 소개하였다.

위 챕터에서는 대표적인 알고리즘 3가지를 살펴보도록 하겠다.

  • BPE(Byte pair encoding)
  • BBPE(Byte level byte pair encoding)
  • WordPiece

기본적으로 해당 알고리즘을 통해서 OOV(Out of vocabulary)문제를 해결할 수 있게 된다.

2.5.1 BPE(Byte pair encoding)

  1. Dataset에서 모든 단어를 빈도수와 함께 추출한다.
  2. 모든 단어를 문자로 나누고 문자 시퀀스로 만든다.
  3. 어휘 사전 크기를 정의한다.
  4. 문자 시퀀스에 있는 모든 고유문자를 어휘 사전에 추가한다.
  5. 가장 빈도수가 큰 기호 쌍을 식별하고, 해당 쌍을 병합해서 어휘 사전에 추가한다.
  6. 어휘 사전 크기에 도달할 때까지 5번과정을 반복한다.

새부적인 동작방식은 다음 ipynb 파일에 적어두었으니 참고하도록 하자.

BPE.ipynb
0.03MB

대략적으로 빈도수가 높은 어휘부터 일치되는지를 판단하고, 일치된다면 병합해주는 과정을 거치면 된다.

2.5.2 BBPE(Byte level byte pair encoding)

기본적으로 BPE와 작동방식이 거의 유사하나, 단어를 문자 시퀀스로 변환하지 않고 바이트 수준 시퀀스로 변환한다. 이렇게 되면 다국어 설정에서 매우 유용하고, 여러 언어로 어휘 사전을 공유하기 좋아진다는 장점이 있다.

2.5.3 Wordpiece

마찬가지로 BPE와 작동방식이 거의 유사하나, BPE의 경우 빈도 수를 기준으로 병합했다면 wordpiece의 경우는 likelihood를 기준으로 병합하게 된다.

 

likelihood의 경우는 기호 쌍들의 확률에 의해서 결정된다.

예를 들어, s와 t의 가능도를 계산하기 위해서는 $$\frac{p(st)}{p(s)p(t)}$$를 구해주면 된다.

 

해당 값이 큰 것을 기준으로 병합을 최우선적으로 처리해주면 BPE와 거의 동일한 매커니즘으로 작동되게 된다.

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.