BERT란?
Bidirectoinal Encoder Representations from Transformers(이하 BERT)는 2018년 10월에 구글이 공개한 Pretrained Model입니다. (BERT라는 이름의 유래는 세서미 스트리트 미국 인형극의 캐릭터 이름이기도 합니다)
BERT는 등장과 동시에 수많은 NLP 태스크에서 최고 성능을 보여주면서 명실공히 NLP의 한 획을 그은 Model로 평가 받고 있습니다.

BERT는 Transformer의 Encoder 부분을 이용하여 구현 되었으며, Wikipedia(25억 단어)와 Book corpus(8억 단어)와 같은 레이블이 없는 텍스트 데이터로 Pretrained Model 입니다.
BERT가 높은 성능을 얻을 수 있었던 것은, 레이블이 없는 방대한 데이터로 Pretrained Model을 가지고 레이블이 없는 다른 작업(Task)에서 추가 훈련과 함께 Hyper parameter를 재조종하여 이 모델을 사용하면 성능이 높게 나오는 기존의 사례들을 참고하였기 때문입니다. (파라미터 재조정을 위한 추가 훈련 관정 : Fine - tuning)
우리가 하고 싶은 Task가 스팸 메일 분류라고 하였을 때, 이미 Wikipedia 등으로 Pretrained BERT위에 분류를 위한 신경망을 하나 추가합니다. 이 경우, 비유하자면 BERT가 언어 모델 사전 학습 과정에서 얻은 지식을 활용할 수 있기 때문에 SPAM 메일 분류에서 더 좋은 성능을 낼 수 있습니다.
BERT 크기

BERT의 구조는 Transformer의 Encoder를 쌓아 올린 구조입니다. Base 버전에서는 총 12개를 쌓았으며, Large 버전에서는 총 24개를 쌓았습니다. 그 외에도 Large버전은 Base버전보다 d_model의 크기나 Self Attention Heads 의 수가 더 커졌으며 Transformer 인코더 층의 수를 L, d_model의 크기를 D, Self Attention heads 수를 A라고 하였을 때 각각의 크기는 다음과 같습니다.
- BERT-Base: L=12, D=768, A=12 : 110M개의 Parameters
- BERT-Large: L=24, D=1024, A=16: 340M개의 Parameters
초기의 Transformer 모델이 L=6, D=512, A=8 이었다는 것과 비교하면 Base 또한 초기 Transformer 보다는 큰 모델임을 알 수 있습니다. 여기서 BERT-base는 BERT보다 앞서 등장한 Open AI GPT-1과 Hyperparameter가 동일한데, 이는 BERT 연구진이 직접적으로 GPT-1과 성능을 비교하기 위해서 GPT-1과 동등한 크기로 BERT-Base를 설계했기 때문입니다. 반면 BERT-Large는 BERT의 최대 성능을 보여주기 위해 만들어진 모델입니다. 따라서 BERT가 세운 대부분의 기록들은 BERT-Large가 세운 기록입니다.
Contextual Embedding
BERT는 ELMO나 GPT-1과 같은 문맥을 반영한(Contextual Embedding)을 사용합니다.

BERT의 입력은 앞서 배운 딥 러닝 모델들과 마찬가지로 Embedding Layer를 지난 Embedding vector입니다.
d_model을 768로 정의하였으므로, 모든 단어들은 768차원의 Embedding vector가 되어 BERT의 입력으로 사용됩니다. BERT는 내부적인 연산을 거친 후, 동일 하게 각 단어에 대해서 768차원의 벡터를 출력. 위의 그림은 BERT가 각 768차원의 [CLS], I, love, you라는 4개의 벡터를 입력 받아서(Input embedding) 동일하게 768차원의 4개의 벡터를 출력하는 모습(Output embedding)을 보여줍니다.

BERT의 연산을 거친 후의 Output embedding은 문장의 문맥을 모두 참고한 문맥을 반영한 Embedding이 됩니다. 위의 좌측 그림에서 [CLS]라는 Vector는 BERT의 초기 입력으로 사용되었을 입력 Embedding입니다. 당시에는 단순히 Embedding layer를 지난 Embedding vector였지만 BERT를 지나고 나서는 [CLS], I, love, you라는 모든 단어 벡터들을 모두 참고한 후에 문맥정보를 가진 Vector가 됩니다. 위의 좌측 그림에서는 모든 단어를 참고하고 있다는 것을 점선의 화살표로 표현합니다.
이는 [CLS]라는 단어 뿐만 아니라 다른 벡터들도 전부 마찬가지 입니다. 가령, 우측의 그림에서 출력 Embedding 단계의 Love를 보면 BERT는 입력이었던 모든 단어들인 [CLS], I, love, you를 모두 참고 하고 있습니다.

하나의 단어가 모든 단어를 참고하는 연산은 사실 BERT의 12개의 층에서 전부 이루어지는 연산입니다. 그리고 이를 12개의 층을 지난후에 최종적으로 Output embedding을 얻게됩니다.
가령 위의 그림은 BERT의 첫번째 층에 입력된 각 단어가 모든 단어를 참고한 후에 출력되는 과정을 화살표로 표현됩니다. BERT의 첫번째 층의 Output Embedding은 BERT의 두번째 층에서는 Input embedding이 됩니다.
그렇다면 BERT 는 어떻게 모든 단어들을 참고하여 문맥을 반영한 Output embedding을 얻게 되는 이유는 Self-Attention 기법 때문입니다. BERT 는 기본적으로 Transformer encoder를 12번 쌓은 것이므로 내부적으로 각 층마다 Multi-head Attention과 Position wise feed forward를 수행하고 있습니다.
Word piece
BERT는 단어보다 더 작은 단위로 쪼개는 Sub-word tokenizer를 사용합니다. BERT가 사용하는 Tokenizer는 Word piece tokenizer로 14챕터에서 공부한 Byte Pair Encoding(BPE)의 유사 알고리즘입니다. 동작 방식은 BPE와 조금 다르지만, 글자로부터 Sub-word들을 병합해가는 방식으로 최종 단어 집합(Vocabulary)을 만드는 것은 BPE와 유사합니다.
Sub-word tokenizer는 기본적으로 자주 등장하는 단어는 그대로 단어 집합에 추가하지만, 자주 등장하지 않는 단어의 경우에는 더 작은 단위인 Sub-word로 분리되어 Sub-word들이 단어 집합에 추가된다는 아이디어를 갖고 있습니다. 이렇게 단어 집합이 만들어지고 나면, 이 단어 집합을 기반으로 토큰화를 수행. 이는 대표적인 Sub-word tokenizer 패키지인 Sentence piece 실습을 통해 이해한 내용입니다. BERT의 Sub-word tokenizer도 이와 마찬가지로 동작합니다.
Position Embedding
Transformer에서는 Positional Encoding이라는 방법을 통해서 단어의 위치 정보를 표현했습니다. Positional Encoding은 Sin 함수와 Cos 함수를 사용하여 위치에 따라 다른 값을 가지는 행렬을 만들어 이를 단어 벡터들과 더하는 방식입니다. BERT에서는 Transformer와는 달리 Sin/Cos 함수를 이용하는 대신 학습을 통해서 얻는 Position Embedding이라는 방법을 사용합니다.

위의 그림은 Position Embedding을 사용하는 방법을 보여줍니다. 위의 그림에서 Word-Piece Embedding은 우리가 이미 알고 있는 단어 Embedding으로 실질적인 입력, 그리고 Position Embedding 통해서 위치 정보를 더해주어야 합니다. Position Embedding의 아이디어는 생각보다 간단한데, 위치 정보를 위한 Embedding layer를 하나 더 사용 해준것 뿐입니다. 가령 문장의 길이가 4라면 4개의 Position embedding vector를 학습시킴. 그리고 BERT의 입력마다 다음과 같이 포지션 Embedding vector를 더해주는 것임.
- 첫번째 단어의 Embedding vector + 0번 Position embedding vector
- 두번째 단어의 Embedding vector + 1번 Position embedding vector
- 세번째 단어의 Embedding vector + 2번 Position embedding vector
- 네번째 단어의 Embedding vector + 3번 Position embedding vector
실제 BERT에서는 문장의 최대 길이를 512로 하고 있으므로, 총 512개의 Position embedding vector가 학습됨.
Pre-training

위의 그림은 BERT의 논문에 첨부된 그림으로, ELMo / GPT-1 / BERT의 구조적인 차이를 보여줍니다.
가장 우측 그림의 ELMo는 정방향 LSTM과 역방향 LSTM을 각각 훈련 시키는 방식으로 양방향 언어 모델을 만들었습니다. 가운데 그림의 GPT-1은 Transformer의 Decoder를 이전 단어들로 부터 다음 단어를 예측하는 방식으로 단방향 언어 모델을 만들었습니다. 그림에서 Trm은 Transformer를 의미합니다. 단방향으로 설계된 Open AI GPT-1와 달리 가장 왼쪽 그림의 BERT는 화살표가 양방향으로 뻗어 나가는 모습을 보여줌. 이는 Masked Language Model을 통해 양방향성을 얻었기 때문입니다. BERT의 훈련 방식은 MLM(Masked Language Model)과 NSP(Next Sentence Prediction)가 있습니다.
MLM (Masked Language Model)
BERT는 사전 훈련을 위해서 인공 신경망의 입력으로 들어가는 입력 텍스트의 15%의 단어를 랜덤으로 Masking합니다. 그리고 인공망에게 이 가려진 단어들을(Masked words) 예측하도록 합니다. Sentence 중간에 빈칸을 만들어 놓고, 빈칸에 들어갈 단어들을 예측하게 하는 식입니다.
예를 들어 ‘나는 [MASK]에 가서 그곳에서 빵과 [MASK]를 샀다’를 주고 ‘슈퍼’와 ‘우유’를 맞추게 합니다.
더 정확히는 전부 [MASK]로 변경하지는 않고, 랜덤으로 선택된 15%의 단어들을 다시 다음과 같은 비율의 규칙이 적용됩니다.
- 80% 단어들은 [MASK]로 변경한다.
- Ex) The man went to the store. The man went to the [MASK]
- 10% 단어들은 랜덤으로 단어가 변경된다.
- Ex) The man went to the store. The man went to the dog
- 10% 단어들은 동일하게 둔다.
- Ex) The man went to the store. The man went to the store.
이렇게 하는 이유는 [MASK]만 사용할 경우에는 [MASK] Token이 Fine-tuning 단계에서는 나타나지 않으므로 사전 학습 단계와 Fine-Tuning 단계에서의 불일치가 발생하는 문제가 있습니다. 이 문제를 완화하기 위해서 랜덤으로 선택된 15%의 단어들의 모든 Token을 [MASK]로 사용하지 않음. 이를 전체 단어 관점에서 그래프를 통해 정리하면 다음과 같습니다.
전체 단어의 85%는 Masked Language Model의 학습에 사용되지 않습니다. Masked Language Model에 학습에 사용되는 단어는 전체의 15%입니다.
학습에 사용되는 12%는 [MASK]로 변경 후에 원래 단어를 예측합니다. 1.5%는 랜덤으로 단어가 변경된 후에 원래 단어를 예측하며 1.5%는 단어가 변경되지는 않았지만 BERT는 이 단어가 변경된 단어인지 원래 단어가 맞는지는 알 수 없습니다. 이 경우에도 BERT는 원래 단어가 무엇인지를 예측하도록 합니다.
NSP (Next Sentence Prediction)
NSP 훈련 방식은 두 개의 문장을 준 후에 이 문장이 이어지는 문장인지 아닌지를 맞추는 식의 훈련 방법입니다. 이를 위해서 50:50 비율로 실제 이어지는 두 개의 문장과 랜덤으로 이어 붙인 두 개의 문장을 주고 훈련시킴. 이를 각각 Sentence A와 Sentence B라고 하였을 때, 다음의 예는 문장의 연속성을 확인한 경우가 그렇지 않은 경우를 보여줍니다.
- 이어지는 문장의 경우
- Sentence A: The man went to the store.
- Sentence B: He bought a gallon of milk.
- Label: isNextSentence
- 이어지는 문장이 아닌 경우
- Sentence A: The man went to the store.
- Sentence B: dogs are so cute.
- Label: NotNextSentence

BERT의 입력으로 넣을 때에는 [SEP]라는 특별 토큰을 사용해서 문장을 구분합니다. 첫번째 문장의 끝에 [SEP] 토큰을 넣고, 두번째 문장이 끝나면 역시 [SEP] 토큰을 붙여 줍니다. 그리고 이 두 문장이 실제 이어지는 문장인지 아닌지 [CLS] 토큰의 위치의 출력층에서 이진 분류 문제를 풀도록 합니다. [CLS] 토큰은 BERT가 분류 문제를 풀기 위해 추가된 특별 토큰 입니다.
그리고 위의 그림과 같이 Masked Language Model과 다음 문장 예측은 따로 학습하는 것이 아닌 loss를 합하여 학습이 동시에 진행됩니다.
BERT가 언어 모델 외에도 다음 문장 예측이라는 Task를 학습하는 이유는 BERT가 풀고자 하는 Task중에서는 QA(Question and Answering)나 NLI(Natural Language Inference)와 같이 두 문장의 관계를 이해하는 것이 중요한 Task가 있기 때문입니다.
Segment Embedding

앞서 언급했듯이 BERT는 QA등과 같은 두 개의 문장 입력이 필요한 Task를 풀기도 합니다. 문장 구분을 위해서 BERT는 Segment Embedding이라는 또 다른 Embedding layer를 사용합니다. 첫 번째 문장에는 Sentence 0 Embedding, Sentence 1 Embedding을 더해주는 방식이며 Embedding vector는 두개만 사용됩니다.
결론적으로 BERT는 총 3개의 Embedding layer가 사용됩니다.
- Word-Piece Embedding: 실질적인 입력이 되는 워드 임베딩. 벡터의 종류는 단어 집합의 크기로 30,522개
- Position Embedding: 위치 정보를 학습하기 위한 Embedding, Embedding vector 종류는 문장의 최대 길이인 512개
- Segment Embedding: 두 개의 문장을 구분하기 위한 Embedding, Embedding vector 종류는 문장의 최대 개수인 2개.