들어가기 전에
지금까지 자연어를 모델에 입력하기 적합한 형태로 변환하기 위한 전처리, 토큰화 방법들을 학습해왔습니다. 이제는 열심히 갈고 닦은 데이터를 학습하기 위한 언어 모델에 대해서 알아봅시다!
학습 목표
Huggingface 라이브러리를 활용해 BERT 모델을 구현하고, 다양한 자연어처리 태스크들을 수행할 수 있습니다.
핵심 단어
- BERT
- GLUE
- [CLS] 토큰
- huggingface
강의 듣기
들어가기 전에
지금까지 자연어를 모델에 입력하기 적합한 형태로 변환하기 위한 전처리, 토큰화 방법들을 학습해왔습니다. 이제는 열심히 갈고 닦은 데이터를 학습하기 위한 언어 모델에 대해서 알아봅시다!
학습 목표
Huggingface 라이브러리를 활용해 BERT 모델을 구현하고, 다양한 자연어처리 태스크들을 수행할 수 있습니다.
핵심 단어
강의 듣기
BERT 모델
자연어 처리를 위해 Seq2seq, 어텐션과 Seq2seq을 조합한 방법 그리고 트랜스포머까지 다양한 모델들이 개발되어왔습니다.
BERT는 앞선 모델들과 어떤 차이가 있을까요?
BERT를 자세하게 알아보기전에, 잠깐 다른 예시를 하나 보고 가겠습니다.
이미지를 처리하기 위한 모델 중에는 오토인코더라는 모델이 있습니다.
입력된 이미지를 어떠한 압축된 벡터로 나타내고, 이 벡터로 부터 원본 이미지를 재구성하는 것이 목적입니다.
압축된 벡터는 자연어 임베딩에서 배웠던 것과 동일하게 이미지의 어떤 정보들을 담고있는 수학적 표현이라고 볼 수 있습니다.
BERT는 위와 유사한 학습방법을 가지고 있습니다.
입력된 자연어를 압축하고, 재구성하는 과정에서 해당 자연어에 대한 수학적 표현인 벡터를 만드는 것을 학습합니다.
여기서 다른점은 입력으로 자연어를 제공할 때, 마스킹 기법을 활용한다는 것입니다.
마스킹 기법이란 "이순신은 조선의 무신이다." 라는 문장을 "이순신은 [MASK]의 무신이다." 와 같이 처리하는 방법입니다.
BERT는 일반적으로 12개의 트랜스포머 층으로 이루어져있습니다.
이들이 모두 All-to-all로 연결이 되어있기 때문에, 입력된 문장에 대한 정보가 잘 녹아서 벡터화 될 수 있습니다.
BERT를 학습하기 위해서 책에서 800M개의 단어들을 사용을 했고, 위키피디아에서 2,500M 단어들을 사용했습니다.
총 사전의 크기는 30,000으로 지정되어 있고, 토큰화는 WordPiece 기법을 활용하였습니다.
그리고 입력으로는 2개의 문장을 활용했습니다.
이 2개의 문장은 연속된 문장일 수도 있고, 아닐 수도 있습니다.
이를 이용해서도 BERT를 학습시켰습니다.
바로 주어진 두 문장이 연결된 문장인지 아닌지 판단하도록 학습시키는 것으로 그 의미를 벡터에 담도록 유도하였습니다.
이후에 위에서 소개드린 마스킹 기법을 활용해, 최종적인 입력 데이터를 만들었습니다.
자연어 처리의 다양한 태스크
GLUE(General Language Understanding Evaluation)는 자연어 처리를 위해 다양한 데이터셋을 가지고 있는 대표적인 데이터 셋중 하나입니다.
이 외에도 SQuAD v1.1 질의응답 데이터셋, CoNLL 2003 개체명 분류 데이터셋, SWAG(SituationsWithAdversarialGenerations)는 이어질 자연스러운 문장 선택을 위한 데이터셋과 같은 다양한 데이터들이 존재합니다.
정의되어 있는 데이터 셋들을 살펴보면, 대부분 아래 그림과 같이 4가지 형태로 분류할 수 있다는 것을 알 수 있습니다.
주의 깊게 보실 부분 중 하나는 입력마다 모두 [CLS]라는 토큰이 맨 앞에 나온다는 것입니다.
BERT에서 이 [CLS] 토큰은 문장 전체에 대한 의미를 지니게 되고, 해당 벡터를 활용해 많은 분류 작업들을 수행할 수 있습니다.
다음으로 주의깊게 생각해 보실 부분은 각 태스크들을 잘 학습하기 위해서 "어떤 특징"들이 필요한가? 입니다.
예를 들어서 질의 응답 태스크를 수행한다고 생각해보겠습니다.
모델의 입력으로는 질문과 답을 찾기 위한 문장 또는 문단이 주어질 것 입니다.
이때, 잘 생각해본다면 문장내에서 질문에 답이 되는 것은 개체일 것입니다.
다른 의미없는 단어들이 아니고 말이지요.
그렇기 때문에 입력으로 문장을 줄때 "[E]이순신[/E]은 [E]조선[/E]의 [E]무신[/E]이다." 와 같이 더 많은 특징을 제공해 준다면, 모델의 성능은 더욱 좋아질 것입니다.
실제로도 이러한 방법을 사용하는 모델이 질의 응답 분야에서 가장 좋은 성능을 발휘하고 있습니다.
Huggingface 라이브러리 활용하기
Huggingface는 트랜스포머기반의 모델들을 쉽게 다룰 수 있게 만들어진 라이브러리입니다.
계속해서 업데이트되고 있으며, 많은 자연어 처리 연구자분들이 사용하고 있습니다.
토크나이저와 트랜스포머계열 모델을 아래 3줄의 코드로 쉽게 불러올수 있습니다.
from transformers import TFAutoModel, AutoTokenizer
model = TFAutoModel.from_pretrained("<model-name>")
tokenizer = AutoTokenizer.from_pretrained("<model-name>")
이제 실제로 활용할 수 있도록 모델을 불러와 봅시다!
huggingface 라이브러리에는 git과 유사하게 수많은 사람들 또는 기업이 이미 학습해둔 모델들이 많이 업로드 되어있습니다.
다음과 같은 코드를 통해, huggingface에 저장되어있는 "bert-base-multilingual-cased"의 토크나이저와 모델을 쉽게 불러올 수 있습니다.
MODEL_NAME = "bert-base-multilingual-cased"
model = AutoModel.from_pretrained(MODEL_NAME)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
print(tokenizer.vocab_size)
토크나이저의 단어사전 개수를 한번 출력해볼까요?
119547 |
어떤 단어들이 사전에 들어있는지도 확인할 수 있습니다.
for i, key in enumerate(tokenizer.get_vocab()):
print(key)
if i > 4:
break
Vol Estadual ##երը সংস্করণ |
이제 문장을 토크나이저에게 입력으로 제공해봅시다.
return_tensors는 토큰화 후 반환되는 타입을 텐서 타입으로 만들어서 반환해 줍니다.
"pt"는 파이토치용 텐서, 텐서플로우용 텐서로도 반환 받을 수 있습니다.
text = "이순신은 조선 중기의 무신이다."
tokenized_input_text = tokenizer(text, return_tensors="pt")
tokenized_input_text에는 어떤 것들이 들어있을까요?
다음과 같은 3가지 데이터가 반환됩니다. 더 자세하게 알아봅시다.!
먼저 제대로 토큰화가 된것인지 한번 확인해 보겠습니다.
토크나이저의 decode함수를 사용하면 인덱스로 변환됬던 토큰을 다시 문자형태로 돌려놓을 수 있습니다.
input_ids = tokenized_input_text['input_ids']
decoded_ids = tokenizer.decode(input_ids)
print(decoded_ids)
[CLS] 이순신은 조선 중기의 무신이다. [SEP] |
제대로 토큰화가 된 것 같네요!
만약 새로운 스페셜 토큰과 단어를 추가하고 싶다면 어떻게 해야할까요?
add_tokens, add_special_tokens 두 함수를 이용해 쉽게 기존의 토크나이저에 추가할 수 있습니다.
tokenizer.add_tokens(["깟뻬뜨랑", "케쇽", "우뤼갸", "쳥쇼", "섀료"])
tokenizer.add_special_tokens({"additional_special_tokens": ["[SHKIM]", "[/SHKIM]"]})
이제 모델에 대해 한번 알아보겠습니다.
트랜스포머즈 라이브러리에는 쉽게 태스크들을 수행할 수 있는 pipeline 기능을 제공합니다.
pipeline 모듈에 원하는 태스크와, 모델 이름(bert-base-multilingual-cased 와 같은)을 제공해 쉽게 생성할 수 있습니다.
아래 코드는 그 예시입니다.
간단하게 [MASK] 토큰을 예측하는 태스크를 생성했습니다.
from transformers import pipeline
nlp_fill = pipeline('fill-mask', model=MODEL_NAME)
nlp_fill("이순신은 [MASK] 중기의 무신이다.")
어떤 결과를 반환해주었을까요? 한번 직접 실행해보세요!
아래 예시는 문장의 유사도를 한번 계산해보는 과정입니다.
먼저 문장들을 토큰화 해주고, 모델에 각각 입력으로 주어 반환된 결과를 저장합니다.
여기서 pooler_output은 [CLS] 토큰의 임베딩 벡터를 의미합니다!
sent1 = tokenizer("오늘 하루 어떻게 보냈나요?", return_tensors="pt")
sent2 = tokenizer("오늘은 어떤 하루를 보내셨나요?", return_tensors="pt")
sent3 = tokenizer("이순신은 조선 중기의 무신이다.", return_tensors="pt")
sent4 = tokenizer("깟뻬뜨랑 리뿔이 뜨럽거 므리커럭이 케쇽 냐왜쇼 우뤼갸 쳥쇼섀료다혀뚜여", return_tensors="pt")
outputs = model(**sent1)
sent_1_pooler_output = outputs.pooler_output
outputs = model(**sent2)
sent_2_pooler_output = outputs.pooler_output
outputs = model(**sent3)
sent_3_pooler_output = outputs.pooler_output
outputs = model(**sent4)
sent_4_pooler_output = outputs.pooler_output
각 문장들의 임베딩 벡터를 획득했습니다.
이제 벡터를 활용해 문장들의 유사도를 구해보겠습니다.
유사도를 구하는 작업는 파이토치 라이브러리에 코사인유사도 함수를 활용합니다.
from torch import nn
cos = nn.CosineSimilarity(dim=1, eps=1e-6)
print(cos(sent_1_pooler_output, sent_2_pooler_output))
print(cos(sent_2_pooler_output, sent_3_pooler_output))
print(cos(sent_3_pooler_output, sent_4_pooler_output))
print(cos(sent_1_pooler_output, sent_4_pooler_output))
tensor([0.9757]) tensor([0.6075]) tensor([0.6396]) tensor([0.9385]) |
생각해보기
1) 감성분석을 진행한다면 어떤 특징들을 강조해 주는 것이 좋을까요?
2) 문장 자체에 특징을 강조하는 방법 말고 또 다른 방법이 있을까요?
3) 문장 유사도를 활용해 간단한 챗봇도 제작이 가능합니다. 한번 도전해보세요! (강의 영상을 확인해봅시다!)
참고자료
https://arxiv.org
https://huggingface.co
https://huggingface.co
https://gluebenchmark.com
comment
-
공지 간소화* 인공지능 전문가 특강 바로가기>> https://www.boostcourse.org/ai101/lectures/320054?isDesc=false
* 인공지능 전문가 특강 바로가기>> https://www.boostcourse.org/ai101/lectures/320054?isDesc=false