[부스트캠프 Ai-tech] NLP 2주차 학습정리
1. BERT 소개
BERT(Bidirectional Encoder Representations from Transformers)는 2018년에 구글이 공개한 사전 훈련(Pre-trained)된 모델로 풀어서 설명하면 Transformer의 Encoder를 양방향으로 표현한 모델
이라는 뜻입니다.
2. Language Model
일반적인 Language model은 앞에 있는 단어로부터 다음에 나올 단어를 예측한다던가, 또는 뒤에 주어진 단어로부터 앞의 단어를 예측하는 단방향 Language model입니다. 예를 들어, BERT 이전에 나왔던 Language model 중 GPT-1은 Transformer의 Decoder만을 이용해서 다음 단어를 예측하는 방식을 사용하고, ELMo는 순방향 역방향 LSTM을 따로 학습한 후 하나로 만들어주는 방법을 취했습니다. 그동안 단방향 모델만을 사용했던 이유는 양방향 언어모델을 사용할 경우 예측하고자 하는 단어를 미리 보게되는 문제가 발생하기 때문이었습니다. 그렇다면 굳이 양방향 언어 모델을 사용하고자 하는 이유는 무엇일까요? 양방향 언어 모델을 사용하게 되면, 문장 하나를 모두 이용해 단어르르 예측하기 때문에, 문장의 문맥, 앞 뒤 상황을 임베딩 벡터에 더 잘 담아낼 수 있습니다. 결과적으로 ‘사과’와 같이 의미는 다르지만 소리가 같은 단어들이라고 하더라도 임베딩 벡터값이 달라지므로, Word2Vec이나 GloVe 등과 같은 워드 임베딩의 문제점을 해결할 수 있었습니다. 그러면 BERT에서 양방향 모델을 어떻게 구현해서 cheating문제를 해결
하고 전체 문장의 문맥을 반영한 임베딩 벡터
를 얻을 수 있게 되었는지 살펴봅시다.
3. BERT의 구조
BERT는 이전 챕터에서 배웠던 트랜스포머를 이용하여 구현되었으며, 위키피디아(25억 단어)와 BooksCorpus(8억 단어)와 같은 레이블이 없는 텍스트 데이터로 사전 훈련된 언어 모델입니다.
BERT가 높은 성능을 얻을 수 있었던 것은, 레이블이 없는 방대한 데이터로 사전 훈련된 모델
을 가지고, 레이블이 있는 다른 작업(Task)에서 추가 훈련
과 함께 하이퍼파라미터를 재조정
하여 이 모델을 사용하면 성능이 높게 나오는 기존의 사례들을 참고하였기 때문입니다. 다른 작업에 대해서 파라미터 재조정을 위한 추가 훈련 과정을 파인 튜닝(Fine-tuning)
이라고 합니다.
1) BERT 모델
BERT의 기본 구조는 트랜스포머의 인코더를 쌓아올린 구조입니다. Base 버전에서는 총 12개를 쌓았으며, Large 버전에서는 총 24개를 쌓았습니다.
2) pre-training에서 BERT의 두 가지 task
a) Masked Language Model
BERT 모델은 Masked Language Model을 사용하여 Bidirectional한 성질을 얻었습니다. 마스크드 언어 모델은 입력 텍스트의 단어 집합의 15%의 단어를 랜덤으로 마스킹(Masking)
합니다. 여기서 마스킹이란 원래의 단어가 무엇이었는지 모르게 한다는 뜻입니다. 그리고 인공 신경망에게 이렇게 마스킹 된 단어들을(Masked words) 예측
하도록 합니다. 우리가 영어 시험을 볼 때 종종 마주하는 빈칸 채우기 문제에 비유할 수 있습니다. 예를 들어 ‘나는 [MASK]에 가서 그곳에서 빵과 [MASK]를 샀다’를 주고 [MASK]에 들어갈 단어를 맞추게 합니다.
더 정확히는 전부 [MASK]로 변경하지는 않고, 랜덤으로 선택된 20%의 단어들은 다시 다음과 같은 비율로 규칙이 적용됩니다.
이렇게 하는 이유는 [MASK]만 사용할 경우에는 [MASK] 토큰이 파인 튜닝 단계에서는 나타나지 않으므로 사전 학습 단계와 파인 튜닝 단계에서의 불일치가 발생하는 문제가 있습니다. 이 문제를 완화하기 위해서 랜덤으로 선택된 20%의 단어들의 모든 토큰을 [MASK]로 사용하지 않습니다.
전체 단어의 85%는 마스크드 언어 모델의 학습에 사용되지 않습니다. 마스크드 언어 모델의 학습에 사용되는 단어는 전체 단어의 15%입니다.
예시를 통해 이해해봅시다. ‘My dog is cute. he likes playing’이라는 문장에 대해서 마스크드 언어 모델을 학습하고자 합니다. 약간의 전처리와 BERT의 서브워드 토크나이저에 의해 이 문장은 `[‘my’, ‘dog’, ‘is’ ‘cute’, ‘he’, ‘likes’, ‘play’, ‘##ing’]로 토큰화가 되어 BERT의 입력으로 사용됩니다. 그리고 언어 모델 학습을 위해서 다음과 같이 데이터가 변경되었다고 가정해봅시다.
'dog' 토큰은 [MASK]로 변경되었습니다.
'dog' 토큰은 [MASK]로 변경되었습니다.
'he'는 랜덤 단어 'king'으로 변경되었습니다.
'play'는 변경되진 않았지만 예측에 사용됩니다.
이제 BERT는 랜던 단어 ‘king’으로 변경된 토큰에 대해서도 원래 단어가 무엇인지, 변경되지 않은 단어 ‘play’에 대해서도 원래 단어가 무엇인지를 예측해야 합니다. ‘play’는 변경되지 않았지만 BERT 입장에서는 이것이 변경된 단어인지 아닌지 모르므로 마찬가지로 원래 단어를 예측해야 합니다.
여기서 출력층에 있는 다른 위치의 벡터들은 예측과 학습에 사용되지 않고, 오직 마스킹된 위치의 출력층의 벡터만이 사용됩니다. 구체적으로는 BERT의 손실 함수에서 다른 위치에서의 예측은 무시합니다. 출력층에서는 예측을 위해 단어 집합의 크기만큼의 밀집층(Dense layer)에 소프트맥스 함수가 사용된 1개의 층을 사용하여 원래 단어가 무엇인지를 맞추게 됩니다.
b) Next Sentence Prediction(NSP): 다음 문장 예측
BERT 이전까지의 language model들은 매번 1개의 문장만을 이용해서 학습을 진행했습니다. 그렇다보니 문장 간의 관계를 파악하는 중요한 QA(Question Answering), NLI(Natural Language Inference)와 같은 task에서는 높은 성능을 보이기 어려웠습니다. 이러한 문제를 해결하고자 BERT에서는 학습할 때 50% 확률로 실제 이어지는 두 개의 문장
과 랜덤으로 이어붙인 두 개의 문장
을 주고 훈련시키고, output에서 두 문장이 이어지는지 확인하는 binary classification에 관한 hidden vector를 생성함으로써 문장 간의 관계를 파악할 수 있도록 하였습니다.
3) BERT의 Input 특징
a) Special Token
<SEP> : BERT의 입력으로 넣을 때에는 [SEP]라는 특별 토큰을 사용해서 문장을 구분합니다. 첫번째 문장의 끝에 [SEP] 토큰을 넣고, 두번째 문장이 끝나면 역시 [SEP] 토큰을 붙여줍니다.
<CLS> : [CLS] 토큰의 위치의 출력층에서 두 문장이 실제 이어지는 문장인지 아닌지 이진 분류 문제를 풀도록 합니다. [CLS] 토큰은 BERT가 분류 문제를 풀기 위해 추가된 특별 토큰입니다.
b) Token(WordPiece) Embedding
BERT는 단어보다 더 작은 단위로 쪼개는 서브워드 토크나이저
를 사용합니다. BERT가 사용한 토크나이저는 WordPiece 토크나이저로 기본적으로 자주 등장하는 단어는 그대로 단어 집합에 추가하지만
, 자주 등장하지 않는 단어의 경우에는 더 작은 단위인 서브워드로 분리
되어 서브워드들이 단어 집합에 추가
된다는 아이디어를 갖고있습니다. 이렇게 단어 집합이 만들어지고 나면, 이 단어 집합을 기반으로 토큰화를 수행합니다. (단어 집합 내부적으로 정수로 맵핑)
참고로 BERT에서 사용되는 특별 토큰들과 그와 맵핑되는 정수는 다음과 같습니다.
c) Segment Embedding
앞서 언급했듯이 BERT는 QA 등과 같은 두 개의 문장 입력이 필요한 태스크를 풀기도 합니다.
문장 구분을 위해
서 BERT는 세그먼트 임베딩
이라는 또 다른 임베딩 층(Embedding layer)을 사용합니다. 첫번째 문장에는 Sentence 0
임베딩, 두번째 문장에는 Sentence 1
임베딩을 더해주는 방식이며 임베딩 벡터는 두 개만 사용됩니다.
d) Position Embedding
트랜스포머에서는 포지셔널
인코딩(Positional Encoding)이라는 방법을 통해서 단어의 위치 정보를 표현했습니다. 포지셔널 인코딩은 사인 함수와 코사인 함수를 사용하여 위치에 따라 다른 값을 가지는 행렬을 만들어 이를 단어 벡터들과 더하는 방법입니다. BERT에서는 이와 유사하지만, 위치 정보를 사인 함수와 코사인 함수로 만드는 것이 아닌 학습을 통해서 얻는 포지션
임베딩(Position Embedding)이라는 방법을 사용합니다.
포지션 임베딩의 아이디어는 굉장히 간단한데, 위치 정보를 위한 임베딩 층(Embedding layer)을 하나 더 사용
합니다. 가령, 문장의 길이가 4라면 4개의 포지션 임베딩 벡터를 학습시킵니다. 그리고 BERT의 입력마다 다음과 같이 포지션 임베딩 벡터를 더해주는 것
입니다.
첫번째 단어의 임베딩 벡터 + 0번 포지션 임베딩 벡터
두번째 단어의 임베딩 벡터 + 1번 포지션 임베딩 벡터
세번째 단어의 임베딩 벡터 + 2번 포지션 임베딩 벡터
네번째 단어의 임베딩 벡터 + 3번 포지션 임베딩 벡터
실제 BERT에서는 문장의 최대 길이를 512로 하고 있으므로, 총 512개의 포지션 임베딩 벡터가 학습됩니다. 결론적으로 현재 설명한 내용을 기준으로는 BERT에서는 총 두 개의 임베딩 층이 사용됩니다. 단어 집합의 크기가 30,522개인 단어 벡터를 위한 임베딩 층과 문장의 최대 길이가 512이므로 512개의 포지션 벡터를 위한 임베딩 층입니다.
🔔 어텐션 마스크
BERT를 실제로 실습하게 되면 어텐션 마스크라는 시퀀스 입력이 추가로 필요합니다. 어텐션 마스크는 BERT가 어텐션 연산을 할 때, 불필요하게 패딩 토큰에 대해서 어텐션을 하지 않도록 실제 단어와 패딩 토큰을 구분할 수 있도록 알려주는 입력입니다. 이 값은 0과 1 두 가지 값을 가지는데, 숫자 1은 해당 토큰은 실제 단어이므로 마스킹을 하지 않는다라는 의미이고, 숫자 0은 해당 토큰은 패딩 토큰이므로 마스킹을 한다는 의미입니다. 위의 그림과 같이 실제 단어의 위치에는 1, 패딩 토큰의 위치에는 0의 값을 가지는 시퀀스를 만들어 BERT의 또 다른 입력으로 사용하면 됩니다.
4) 파인 튜닝(Fine-tuning)으로 개별 태스크에 적용하기
이번에는 사전 학습 된 BERT에 우리가 풀고자 하는 태스크의 데이터를 추가로 학습 시켜서 테스트하는 단계인 파인 튜닝 단계에 대해서 알아보겠습니다. 실질적으로 태스크에 BERT를 사용하는 단계에 해당됩니다.
a) 하나의 텍스트에 대한 텍스트 분류(Classification)
텍스트 분류 문제를 풀기 위해서 [CLS] 토큰의 위치의 출력층에서 밀집층(Dense layer) 또는 같은 이름으로는 완전 연결층(fully-connected layer)이라고 불리는 층들을 추가하여 분류에 대한 예측을 하게됩니다.
b) 하나의 텍스트에 대한 태깅 작업(Tagging)
BERT를 사용하는 두번째 유형은 태깅 작업입니다. 대표적으로 문장의 각 단어에 품사를 태깅하는 품사 태깅 작업과 개체를 태깅하는 개체명 인식 작업이 있습니다. 출력층에서는 입력 텍스트의 각 토큰의 위치에 밀집층을 사용하여 분류에 대한 예측을 하게 됩니다.
c) 질의 응답(Question Answering)
텍스트의 쌍을 입력으로 받는 또 다른 태스크로 QA(Question Answering)가 있습니다. BERT로 QA를 풀기 위해서 질문과 본문이라는 두 개의 텍스트의 쌍을 입력합니다. 이 태스크의 대표적인 데이터셋으로 SQuAD(Stanford Question Answering Dataset) v1.1이 있습니다. 이 데이터셋을 푸는 방법은 질문과 본문을 입력받으면, 본문의 일부분을 추출해서 질문에 답변하는 것입니다.
4. 참조
[BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding]