새소식

부스트캠프 AI Tech 4기

[NLP_KLUE] 4. BERT / Huggingface Tokenizer

  • -

BERT

 

왼쪽의 그림은 AutoEncoder이다. 이 모델은 encoder와 decoder로 구성되어있다.

Encoder는 입력된 이미지를 압축된 형태로 표현하는 역할로, RNN의 context vector를 만들어낸다고 볼 수 있다.

Decoder는 압축된 형태를 원본으로 다시 복원하는 역할이다.

즉, AutoEncoder는 원본 이미지를 잘 표현할 수 있게 학습된 모델이다.

 

오른쪽 그림은 BERT이다.

BERT는 Transformer의 Encoder로 이루어진 모델로, 입력된 정보를 다시 입력된 정보로 representation 하는 것을 목적으로 학습된다.

AutoEncoder와의 차이점은 학습을 할 때 중간 중간의 단어를 Masking 함으로써 복원하기 더 어렵게 만들어서 언어를 좀 더 확실하게 학습하도록 만들어졌다.

 

 

  • input으로 sentence 2개를 입력받는다.
    sent1 + [SEP] + sent2
  • 12개의 Transformer layer로 구성되어 있다.
  • [CLS] 토큰은 sent1과 sent2가 Next Sentence 관계인지 혹은 전혀 상관없는 Sentence인지를 분류하기 위해 학습된다.
  • BERT 내부의 Transformer는 All-to-all network로 연결되어있기 때문에 [CLS] 토큰의 출력벡터가 sent1과 sent2의 정보들이 모두 담긴 embedding 벡터라고 가정한다.
    실제로 [CLS] 토큰이 sent1과 sent2를 잘 표현하기 위해 [CLS] 토큰 위에 Classification layer를 부착해서 pre-training을 진행하게 된다.

학습 코퍼스 데이터

  • BooksCorpus (800M words)
  • English Wikipedia (2,500M words without lists, tables and headers)
  • 30,000 token vocabulary

데이터의 tokenizing

  • WordPiece tokenizing
    • 빈도수 기반으로 tokenizing
  • 2개의 token sequence가 학습에 사용
    • Next sentence나 Random Chosen sentence

 

Maksed Language Model

토큰들 중 15%의 확률로 랜덤 토큰을 선택하고

80%의 확률로 Masking, 10% 확률로 Random replacing, 10%의 확률로 Unchanging 해준다.

 

 

 

 


Huggingface Tokenizer

 

from transformers import AutoModel, AutoTokenizer

MODEL_NAME = "bert-base-multilingual-cased"

model = AutoModel.from_pretrained(MODEL_NAME)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)

 

토크나이저 vocab size 확인 : 119547개

print(tokenizer.vocab_size)
# 119547

 

tokenizer(text) 처럼 사용할 경우에는 input_idstoken_type_idsattention_mask 를 바탕으로 값이 출력된다.

 

text = "이순신은 조선 중기의 무신이다."

tokenized_input_text = tokenizer(text, return_tensors="pt")

print(tokenized_input_text['input_ids'])    # input text를 tokenizing한 후 vocab의 id
# tensor([[   101,   9638, 119064,  25387,  10892,  59906,   9694,  46874,   9294,
#          25387,  11925,    119,    102]])
          
print(tokenized_input_text['token_type_ids'])   # segment id (sentA or sentB)
# tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

print(tokenized_input_text['attention_mask'])   # special token (pad, cls, sep) or not
# tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])

 

  • tokenizer.tokenize() : 입력된 문장을 tokenizing
  • tokenizer.encode() : 토큰화된 문장의 인코딩된 결과
  • tokenizer.decode() : [CLS], [SEP] 토큰이 들어간 형태로 디코딩
tokenized_text = tokenizer.tokenize(
    text,
    add_special_tokens=True,
    max_length=20,
    padding="max_length"
    )
print(tokenized_text)
# ['[CLS]', '이', '##순', '##신', '##은', '[MASK]', '중', '##기의', '무', '##신', '##이다', '.', '[SEP]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]']


input_ids = tokenizer.encode(
    text,
    add_special_tokens=True,
    max_length=20,
    padding="max_length"
    )
print(input_ids)
# [101, 9638, 119064, 25387, 10892, 103, 9694, 46874, 9294, 25387, 11925, 119, 102, 0, 0, 0, 0, 0, 0, 0]


decoded_ids = tokenizer.decode(input_ids)
print(decoded_ids)
# [CLS] 이순신은 [MASK] 중기의 무신이다. [SEP] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]

 

 

새로운 토큰 추가

아래와 같이 토크나이징을 할 수 없는 단어는 [UNK]으로 표기된다.

[UNK] 토큰이 많으면 많을수록 원본 데이터의 의미가 사라져버리게 된다.

text = "깟뻬뜨랑 리뿔이 뜨럽거 므리커럭이 케쇽 냐왜쇼 우뤼갸 쳥쇼섀료다혀뚜여"

tokenized_text = tokenizer.tokenize(text, add_special_tokens=False)
print(tokenized_text)
# ['[UNK]', '리', '##뿔', '##이', '뜨', '##럽', '##거', '므', '##리', '##커', '##럭', '##이', '[UNK]', '냐', '##왜', '##쇼', '[UNK]', '[UNK]']

 

따라서 add_tokens()로 vocab을 추가해줄 수  있다.

added_token_num = tokenizer.add_tokens(["깟뻬뜨랑", "케쇽", "우뤼갸", "쳥쇼", "섀료"])
print(added_token_num) 
# 5
tokenized_text = tokenizer.tokenize(text, add_special_tokens=False)
print(tokenized_text)
# ['깟뻬뜨랑', '리', '##뿔', '##이', '뜨', '##럽', '##거', '므', '##리', '##커', '##럭', '##이', '케쇽', '냐', '##왜', '##쇼', '우뤼갸', '쳥쇼', '섀료', '다', '##혀', '##뚜', '##여']

 

add_special_tokens()로 특정 역할을 위한 Special Token도 추가해줄 수 있다.

ENTITY TAG 를 [ENTITY] 이순신 [/ENTITY] 처럼 넣어서 BERT 모델에게 명시적으로 이순신은 ENTITY 입니다를 알려주고 싶다면 special token 을 추가해줘야 한다.

text = "[SHKIM]이순신은 조선 중기의 무신이다.[/SHKIM]"
tokenized_text = tokenizer.tokenize(text, add_special_tokens=False)
print(tokenized_text)
# ['[', 'SH', '##KI', '##M', ']', '이', '##순', '##신', '##은', '조선', '중', '##기의', '무', '##신', '##이다', '.', '[', '/', 'SH', '##KI', '##M', ']']
added_token_num += tokenizer.add_special_tokens({"additional_special_tokens":["[SHKIM]", "[/SHKIM]"]})
tokenized_text = tokenizer.tokenize(text, add_special_tokens=False)
print(tokenized_text)
# ['[SHKIM]', '이', '##순', '##신', '##은', '조선', '중', '##기의', '무', '##신', '##이다', '.', '[/SHKIM]']
print(added_token_num)
# 7

 

vocab을 새롭게 추가했다면, 반드시 model의 embedding layer 사이즈를 늘려주어야 한다!

print(model.get_input_embeddings())
#  Embedding(119547, 768, padding_idx=0)

model.resize_token_embeddings(tokenizer.vocab_size + added_token_num)
print(model.get_input_embeddings())
# Embedding(119554, 768)

 

 


부스트캠프 AI Tech 교육 자료를 참고하였습니다.

728x90
Contents