Skip to content

BERT는 트랜스포머를 이용하여 구현되었으며, 위키피디아(25억 단어)와 BooksCorpus(8억 단어)와 같은 레이블이 없는 텍스트 데이터로 사전 훈련된 언어 모델이다.

BERT가 높은 성능을 얻을 수 있었던 것은, 레이블이 없는 방대한 데이터로 사전 훈련된 모델을 가지고 레이블이 있는 다른 작업(Task)에서 추가 훈련과 함께 하이퍼파라미터를 재조정하였기 때문이다. 넓은 범위에 대해 학습한 모델을 기반으로 다른 작업에 대해서 파라미터 재조정을 위한 추가 훈련 과정을 거치는 것을 파인 튜닝(Fine-tuning)이라고 한다.

스팸 메일 분류를 하고 싶다고 할때, 이미 위키피디아 등으로 사전 학습된 BERT 위에 분류를 위한 신경망을 한 층 추가한다. 이 경우, 비유하자면 BERT가 언어 모델 사전 학습 과정에서 얻은 지식을 활용할 수 있으므로 스팸 메일 분류에서 보다 더 좋은 성능을 얻을 수 있다. ELMo나 OpenAI GPT-1 등이 이러한 파인 튜닝 사례의 대표적인 예이다.

image

BERT의 크기

image

BERT의 기본 구조는 트랜스포머의 인코더를 쌓아올린 구조이다. Base 버전에서는 총 12개를 쌓았으며, Large 버전에서는 총 24개를 쌓았다. 그 외에도 Large 버전은 Base 버전보다 d_model의 크기나 셀프 어텐션 헤드(Self Attention Heads)의 수가 더 크다. 트랜스포머 인코더 층의 수를 L, d_model의 크기를 D, 셀프 어텐션 헤드의 수를 A라고 하였을 때 각각의 크기는 다음과 같다.

  • BERT-Base : L=12, D=768, A=12 : 110M개의 파라미터
  • BERT-Large : L=24, D=1024, A=16 : 340M개의 파라미터

Base 또한 초기 트랜스포머보다는 큰 네트워크이다. BERT-base는 BERT보다 앞서 등장한 Open AI GPT-1과 하이퍼파라미터가 동일한데, 이는 BERT 연구진이 직접적으로 GPT-1과 성능을 비교하기 위해서 GPT-1과 동등한 크기로 BERT-Base를 설계하였기 때문이다. 반면, BERT-Large는 BERT의 최대 성능을 보여주기 위해 만들어진 모델이다. BERT가 세운 기록들은 대부분 BERT-Large를 통해 이루어졌다.

BERT의 문맥을 반영한 임베딩(Contextual Embedding)

BERT는 ELMo나 GPT-1과 마찬가지로 문맥을 반영한 임베딩(Contextual Embedding)을 사용한다.

BERT의 입력은 임베딩 층(Embedding layer)를 지난 임베딩 벡터들이다. d_model을 768로 정의하였으므로 모든 단어들은 768차원의 임베딩 벡터가 되어 BERT의 입력으로 사용된다. BERT는 내부적인 연산을 거친 후, 동일하게 각 단어에 대해서 768차원의 벡터를 출력한다.

image

BERT의 연산을 거친 후의 출력 임베딩은 문장의 문맥을 모두 참고한 문맥을 반영한 임베딩이 된다.

위의 좌측 그림에서 [CLS]라는 벡터는 BERT의 초기 입력으로 사용되었을 입력 임베딩 당시에는 단순히 임베딩 층(embedding layer)를 지난 임베딩 벡터였지만, BERT를 지나고 나서는 [CLS], I, love, you라는 모든 단어 벡터들을 모두 참고한 후에 문맥 정보를 가진 벡터가 된다. ([CLS] 토큰은 BERT가 분류 문제를 풀기위한 특별 토큰이다.)

이는 [CLS]라는 단어 벡터 뿐만 아니라 다른 벡터들도 전부 마찬가지이다. 우측의 그림에서 출력 임베딩 단계의 love도 BERT의 입력이었던 모든 단어들인 [CLS], I, love, you를 참고하고 있다.

BERT가 모든 단어들을 참고하여 문맥을 반영한 출력 임베딩을 얻는 것은 ‘셀프 어텐션’ 때문이다. 트랜스포머 인코더를 12번 쌓은 것이므로 내부적으로 각 층마다 멀티 헤드 셀프 어텐션과 포지션 와이즈 피드 포워드 신경망을 수행하고 있다.

BERT의 서브워드 토크나이저 : WordPiece

BERT는 단어보다 더 작은 단위로 쪼개는 서브워드 토크나이저를 사용한다. BERT가 사용한 토크나이저는 WordPiece 토크나이저로 바이트 페어 인코딩(Byte Pair Encoding, BPE)의 유사 알고리즘이다. 동작 방식은 BPE와 조금 다르지만, 글자로부터 서브워드들을 병합해가는 방식으로 최종 단어 집합(Vocabulary)을 만드는 것은 BPE와 유사하다.

서브워드 토크나이저는 기본적으로 자주 등장하는 단어는 그대로 단어 집합에 추가하고, 자주 등장하지 않는 단어는 더 작은 단위인 서브워드로 분리하여 추가하는 방식으로 동작한다. 이렇게 단어 집합이 만들어지고 나면 이 단어 집합을 기반으로 토큰화를 수행한다. BERT의 서브워드 토크나이저도 이와 마찬가지로 동작한다.

BERT에서 토큰화를 수행하는 방식은 다음과 같다.

준비물 : 이미 훈련 데이터로부터 만들어진 단어 집합
1. 토큰이 단어 집합에 존재한다.
=> 해당 토큰을 분리하지 않는다.
2. 토큰이 단어 집합에 존재하지 않는다.
=> 해당 토큰을 서브워드로 분리한다.
=> 해당 토큰의 첫번째 서브워드를 제외한 나머지 서브워드들은 앞에 "##"를 붙인 것을 토큰으로 한다.

예를 들어 embeddings이라는 단어가 입력으로 들어왔을 때, BERT의 단어 집합에 해당 단어가 존재하지 않았다고 해보자. 만약, 서브워드 토크나이저가 아닌 토크나이저라면 여기서 OOV 문제가 발생한다. 하지만 서브워드 토크나이저의 경우에는 해당 단어가 단어 집합에 존재하지 않아도 서브워드는 존재할 수 있으므로 해당 단어를 더 쪼개려고 시도한다. 만약, BERT의 단어 집합에 em, ##bed, ##ding, #s라는 서브 워드들이 존재한다면, embeddings는 em, ##bed, ##ding, #s로 분리됩니다. 여기서 ##은 이 서브워드들은 단어의 중간부터 등장하는 서브워드라는 것을 알려주기 위해 단어 집합 생성시 표시해둔 기호이다.

포지션 임베딩(Position Embedding)

트랜스포머에서는 포지셔널 인코딩(Positional Encoding)이라는 방법을 통해서 단어의 위치 정보를 표현했다. 포지셔널 인코딩은 사인 함수와 코사인 함수를 사용하여 위치에 따라 다른 값을 가지는 행렬을 만들어 이를 단어 벡터들과 더하는 방법이다. BERT에서는 이와 유사하지만, 학습을 통해서 위치 정보를 얻는 포지션 임베딩(Position Embedding)이라는 방법을 사용한다.

image

위의 그림은 포지션 임베딩을 사용하는 방법을 보여준다. 우선, 위의 그림에서 WordPiece Embedding은 우리가 이미 알고 있는 단어 임베딩으로 실질적인 입력입니다. 그리고 이 입력에 포지션 임베딩을 통해서 위치 정보를 더해주어야 한다. 포지션 임베딩의 아이디어는 굉장히 간단한데, 위치 정보를 위한 임베딩 층(Embedding layer)을 하나 더 사용한다. 가령, 문장의 길이가 4라면 4개의 포지션 임베딩 벡터를 학습시킨다. 그리고 BERT의 입력마다 다음과 같이 포지션 임베딩 벡터를 더해준다.

  • 첫번째 단어의 임베딩 벡터 + 0번 포지션 임베딩 벡터
  • 두번째 단어의 임베딩 벡터 + 1번 포지션 임베딩 벡터
  • 세번째 단어의 임베딩 벡터 + 2번 포지션 임베딩 벡터
  • 네번째 단어의 임베딩 벡터 + 3번 포지션 임베딩 벡터

실제 BERT에서는 문장의 최대 길이를 512로 하고 있으므로, 총 512개의 포지션 임베딩 벡터가 학습된다. 결론적으로 현재 설명한 내용을 기준으로는 BERT에서는 총 두 개의 임베딩 층이 사용된다. 단어 집합의 크기가 30,522개인 단어 벡터를 위한 임베딩 층과 문장의 최대 길이가 512이므로 512개의 포지션 벡터를 위한 임베딩 층이다.

BERT의 사전 훈련(Pre-training)

image

위의 그림은 BERT의 논문에 첨부된 그림으로 ELMo와 GPT-1, 그리고 BERT의 구조적인 차이를 보여준다. 가장 우측 그림의 ELMo는 정방향 LSTM과 역방향 LSTM을 각각 훈련시키는 방식으로 양방향 언어 모델을 만들었다. 가운데 그림의 GPT-1은 트랜스포머의 디코더를 이전 단어들로부터 다음 단어를 예측하는 방식으로 단방향 언어 모델을 구성한다.

단방향(→)으로 설계된 Open AI GPT와 달리 가장 좌측 그림의 BERT는 화살표가 양방향으로 뻗어나가는데, 이는 마스크드 언어 모델(Masked Language Model)을 통해 양방향성을 얻었기 때문이다.

BERT의 사전 훈련 방법은 마스크드 언어 모델, 문장 예측(Next sentence prediction, NSP)의 두가지로 설명할 수 있다.

마스크드 언어 모델

BERT는 사전 훈련을 위해서 인공 신경망의 입력으로 들어가는 입력 텍스트의 15%의 단어를 랜덤으로 마스킹(Masking)한다.그리고 인공 신경망에게 이 가려진 단어들을(Masked words) 예측하도록 한다.

‘나는 ㅇㅇ에 가서 그곳에서 빵과 ㅇㅇ를 샀다’라는 문장이 주어지면, ‘슈퍼’와 ‘우유’를 맞추게 하는 식이다.

문장 예측(Next sentence prediction, NSP)

BERT는 두 개의 문장을 준 후에 이 문장이 이어지는 문장인지 아닌지를 맞추는 방식으로 훈련시킨다. 이를 위해서 50:50 비율로 실제 이어지는 두 개의 문장과 랜덤으로 이어붙인 두 개의 문장을 주고 훈련시킨다.

  • => 문장1: 저 남자는 회사에 출근했다
  • => 문장2: 저 남자는 회사에 출근하자마자 커피를 끓여 마셨다. (순서가 맞음)

  • => 문장3: 저 여자는 퇴근하려 한다.
  • => 문장4: 강아지는 예쁘다. (순서가 틀린 문장)

BERT가 언어 모델 외에도 다음 문장 예측이라는 태스크를 학습하는 이유는 BERT가 풀고자 하는 태스크 중에서는 QA(Question Answering)나 NLI(Natural Language Inference)와 같이 두 문장의 관계를 이해하는 것이 중요한 태스크들이 있기 때문이다.

세그먼트 임베딩(Segment Embedding)

image

앞서 언급했듯이 BERT는 QA 등과 같은 두 개의 문장 입력이 필요한 태스크를 풀기도 하는데, 이 때 문장 구분을 위해서 BERT는 세그먼트 임베딩이라는 또 다른 임베딩 층(Embedding layer)을 사용한다. 첫번째 문장에는 Sentence 0 임베딩, 두번째 문장에는 Sentence 1 임베딩을 더해주는 방식이며 임베딩 벡터는 두 개만 사용된다.

결론적으로 BERT는 총 3개의 임베딩 층이 사용된다.

  • WordPiece Embedding : 실질적인 입력이 되는 워드 임베딩. 임베딩 벡터의 종류는 단어 집합의 크기로 30,522개.
  • Position Embedding : 위치 정보를 학습하기 위한 임베딩. 임베딩 벡터의 종류는 문장의 최대 길이인 512개.
  • Segment Embedding : 두 개의 문장을 구분하기 위한 임베딩. 임베딩 벡터의 종류는 문장의 최대 개수인 2개.

BERT를 파인 튜닝(Fine-tuning)하기

사전 학습 된 BERT에 우리가 풀고자 하는 태스크의 데이터를 추가로 학습 시켜서 테스트하는 단계인 파인 튜닝 단계에 대해서 알아보자. 실질적으로 태스크에 BERT를 사용하는 단계에 해당된다.

1. 하나의 텍스트에 대한 텍스트 분류 유형(Single Text Classification)

BERT를 사용하는 첫번째 유형은 하나의 문서에 대한 텍스트 분류 유형이다. 이 유형은 영화 리뷰 감성 분류, 로이터 뉴스 분류 등과 같이 입력된 문서에 대해서 분류를 하는 유형으로 문서의 시작에 [CLS] 라는 토큰을 입력한다.

앞서 언급했듯이 [CLS] 토큰은 BERT가 분류 문제를 풀기위한 특별 토큰이다. 이는 BERT를 실질적으로 사용하는 단계인 파인 튜닝 단계에서도 마찬가지이다. 텍스트 분류 문제를 풀기 위해서 [CLS] 토큰의 위치의 출력층에서 밀집층(Dense layer) 또는 같은 이름으로는 완전 연결층(fully-connected layer)이라고 불리는 층들을 추가하여 분류에 대한 예측을 하게된다.

2. 하나의 텍스트에 대한 태깅 작업(Tagging)

BERT를 사용하는 두번째 유형은 태깅 작업이다. 대표적으로 문장의 각 단어에 품사를 태깅하는 품사 태깅 작업과 개체를 태깅하는 개체명 인식 작업이 있다. 출력층에서는 입력 텍스트의 각 토큰의 위치에 밀집층을 사용하여 분류에 대한 예측을 하게 된다.

3. 텍스트의 쌍에 대한 분류 또는 회귀 문제(Text Pair Classification or Regression)

BERT는 텍스트의 쌍을 입력으로 받는 태스크도 풀 수 있다. 텍스트의 쌍을 입력으로 받는 대표적인 태스크로 자연어 추론(Natural language inference)이 있다. 자연어 추론 문제란, 두 문장이 주어졌을 때, 하나의 문장이 다른 문장과 논리적으로 어떤 관계에 있는지를 분류하는 것이 다. 유형으로는 모순 관계(contradiction), 함의 관계(entailment), 중립 관계(neutral)가 있다.

텍스트의 쌍을 입력받는 이러한 태스크의 경우에는 입력 텍스트가 1개가 아니므로, 텍스트 사이에 [SEP] 토큰을 집어넣고, Sentence 0 임베딩과 Sentence 1 임베딩이라는 두 종류의 세그먼트 임베딩을 모두 사용하여 문서를 구분한다.

4. 질의 응답(Question Answering)

텍스트의 쌍을 입력으로 받는 또 다른 태스크로 QA(Question Answering)가 있다. 질문과 본문을 입력받으면 본문의 일부분을 추출해서 질문에 답변하는 것이다. 이 태스크의 대표적인 데이터셋으로 SQuAD(Stanford Question Answering Dataset) v1.1이 있다.

”기상학에서 강우는 대기 수증기가 응결되어 중력의 영향을 받고 떨어지는 것을 의미합니다. 강우의 주요 형태는 이슬비, 비, 진눈깨비, 눈, 싸락눈 및 우박이 있습니다.” 라는 본문이 주어졌을 때, “강우가 떨어지도록 영향을 주는 것은?” 라는 질문이 주어지면 “중력”을 반환하는 식으로 문제를 풀게 된다.

어텐션 마스크(Attention Mask)

image

BERT를 실제로 실습하게 되면 어텐션 마스크라는 시퀀스 입력이 추가로 필요하다. 어텐션 마스크는 BERT가 어텐션 연산을 할 때, 불필요하게 패딩 토큰에 대해서 어텐션을 하지 않도록 실제 단어와 패딩 토큰을 구분할 수 있도록 알려주는 입력이다. 이 값은 0과 1 두 가지 값을 가지는데, 숫자 1은 해당 토큰은 실제 단어이므로 마스킹을 하지 않는다라는 의미이고, 숫자 0은 해당 토큰은 패딩 토큰이므로 마스킹을 한다는 의미이다. 위의 그림과 같이 실제 단어의 위치에는 1, 패딩 토큰의 위치에는 0의 값을 가지는 시퀀스를 만들어 BERT의 또 다른 입력으로 사용하면 된다.


참고