0. Introduction
HuggingFace는 빠르고 쉽게 데이터셋을 다운로드하고 모델을 만들 수 있게 도와줍니다. 또한 다양한 사람들이 사전학습한 모델을 다운로드 받아서 직접 실험해 볼 수 있습니다. 이번 포스트에서는 HuggingFace를 이용하여 가장 기본이라고도 볼 수 있는 Text Classification task를 수행해보고자 합니다.
1. Data
데이터는 HuggingFace에서 제공하는 'emotion dataset'을 사용합니다. emotion dataset은 train, validation, test dataset으로 구성되어 있으며, 각각의 데이터셋은 'text'와 'label'로 구성되어 있습니다.
이 데이터에서 예시를 하나 출력해보면 다음과 같이 text와 label이 dictionary 형태로 들어가 있음을 알 수 있습니다.
emotion dataset에 존재하는 feature를 살펴보면, label의 종류는 총 6개가 존재하며 각각 sadness, joy, love, anger, fear, surprise로 구성되어 있습니다. 아래 그림과 같이 슬라이싱을 이용하여 출력해 보면, text와 이에 해당되는 감정이 매칭되어 있습니다. 예를 들면 마지막 문장인 'i am feeling grouchy'는 3과 매칭되어 있으므로 'anger'에 해당하는 텍스트임을 알 수 있습니다.
2. Tokenizer
텍스트를 모델에 입력하기 위해서는 tokenization을 수행해야 합니다. DistillBERT는 knowledge distillation(지식 증류)을 적용하여 BERT보다 모델의 크기는 작으면서 더 빠르게 동작하고 BERT와 비슷한 성능을 보여주는 모델입니다.
이 모델을 사용하여 간단히 tokenize 함수를 만들어보겠습니다. 이 함수는 train,validation,test dataset을 입력받으면, 각 데이터셋의 텍스트만을 tokenize 하는 함수입니다. 또한 tokenize를 수행하면서 sequence length를 통일해 주기 위해 padding과 truncation을 적용하였습니다. 또한 텍스트의 시작([CLS])과 끝([SEP])을 알려주는 special token을 추가하였습니다.
위 함수를 이용하여 train dataset에서 2개의 데이터만 tokenization을 수행해보겠습니다.
위 결과를 살펴보면 토큰화 결과로 'input_ids'와 'attention_mask'를 잘 return 하는 모습을 볼 수 있습니다. 여기서 attention_mask에서 0의 의미는 attention연산 시 padding으로 추가된 의미가 없는 부분에 대해서는 attention 연산을 수행하지 않는다는 의미를 가지고 있습니다. 반대로 1은 실제 토큰에 위치한 자리로써 attention 연산을 수행한다는 의미입니다.
이제, 위의 함수를 이용하여 모든 dataset에 토큰화를 수행하고, 해당 결과를 dataset에 추가해 줍니다.
map 함수를 이용하면 한 번에 모든 dataset에 tokenize함수를 적용하고, 해당 결과를 자동으로 column에 추가시켜 줍니다.
실제로 모든 column name을 출력하면 기존 text와 label 뿐만 아니라 tokenize함수의 return 값인 input_ids와 attention_mask도 추가되어 있음을 확인할 수 있습니다.
3. Model
일반적으로 사전학습된 모델을 사용할 때 model과 tokenizer로 사용한 모델을 일치시켜 줍니다. 왜냐하면, 사전학습된 모델의 단어사전의 정보가 tokenizer에 모두 담겨 있기 때문입니다. 따라서 tokenizer에 사용한 DistillBERT를 모델로 선정하여 학습하였습니다. tokenizer와 마찬가지로 transformers를 이용하여 AutoModelForSequencClassfication 클래스를 이용하여 사전학습된 모델을 로드하여 사용합니다.
AutoModelForSequenceClassification 클래스는 사전 학습된 모델 출력과 함께 쉽게 훈련할 수 있는 분류 head가 있기 때문에 AutoModel을 사용하였을 때 보다 더 간편하게 분류 모델을 구현할 수 있습니다. 그리고 분류 head가 있기 때문에, 몇 개의 label로 분류하는지에 대한 정보를 입력해 주어야 합니다. 여기서는 num_labels로 표현하였습니다.
huggingface는 학습 과정에서 생성된 정보를 저장해 주는 hub 기능도 제공합니다!
https://huggingface.co/docs/hub/security-tokens를 참고해서 access token을 생성한 다음, 아래 코드를 입력하면 access token을 입력하는 창이 뜨게 됩니다. 여기에 생성한 access token을 입력하면 됩니다. 저장소를 만들고 파일을 추가해야 하므로 'write'로 설정하시면 됩니다.
위의 토큰을 입력하고, 이후에 모델 학습을 진행하면 자동으로 아래 그림처럼 model card가 생성되어 모델 학습과 관련된 정보를 볼 수 있습니다. 또한 다른 사람들에게 공유도 가능합니다.
다음으로는 TrainingArguments 클래스를 이용하여 훈련과 평가와 관련된 상세한 내용을 저장합니다. 참고로 hugging face hub에 생성되는 저장소 이름은 output_dir로 설정됩니다.
batch size, epoch, learning rate 등등 훈련과 관련된 정보를 입력하고, 최고로 좋은 성능을 보여주는 모델을 로드할 수 있도록 load_best_model_at_end 를 True로 설정하였습니다. 이제, Trainer 객체를 만들고 fine-tuning을 진행합니다.
진행 결과 생각보다 좋은 분류 성능을 보여줍니다. accuracy score는 약 93%를 달성하였습니다. 이 결과가 얼마나 괜찮은 결과인지 보기 위해 비교 모델로 로지스틱 회귀(Logistic Regression) 모델을 사용하여 보겠습니다. 간단히 scikit-learn을 이용하여 구현할 수 있습니다.
실험 결과, 약 63%의 정확도를 보여줌을 확인할 수 있습니다. 구체적으로 각 label을 얼마나 잘 예측하는지 보기 위해 confusion matrix를 살펴보았습니다. confusion matrix는 다음과 같이 구현하였습니다.
위 함수를 이용하여 우선, logistic regression 결과를 살펴보면 다음과 같습니다.
결과를 살펴보면, 실제 anger에 대해서는 sadness와 joy로 많이 헷갈려하고 있고, 실제 surprise에 대해서는 sadness와 joy로 헷갈려하는 모습을 볼 수 있습니다. 그렇다면, DistillBERT의 결과도 한번 살펴보겠습니다.
scikit-learn과 마찬가지로 학습한 모델을 이용하여 validation data에 대해 예측을 진행하였습니다.
예측 결과, 이전 logistic regression에 비하면 매우 높은 정확도로 예측함을 알 수 있습니다! 하지만 여전히 실제 surprise는 fear로 혼동하는 모습을 볼 수 있습니다.
마지막으로, 학습된 결과를 huggingface hub에 업로드해보겠습니다.
간단히 push_to_hub 함수를 이용하여 업로드할 수 있습니다.
업로드가 완료되면 본인의 계정의 model 부분에서 업로드된 모델을 확인할 수 있습니다.
업로드가 완성되었기 때문에, 모델을 바로 불러와서 바로 예측을 수행해 볼 수 있습니다.
transformers의 pipeline 함수를 이용하여 모델과 수행할 task를 입력하여 바로 수행해 볼 수 있습니다.
저는 "I can't stop tears!! The film is very beautiful and the actors' chemistry is very noticeable." 문장에 대해 테스트를 수행해 보았습니다. 문장을 보면 어떤 사람은 joy라고 생각할 수도 있고, 반대로 surprise라고 생각할 수도 있는 문장입니다.
예시 문장을 입력해서 수행한 결과, 이번에 학습한 모델은 joy로 예측하는 모습을 볼 수 있습니다.
'자연어 처리(NLP) > 모델(Model)' 카테고리의 다른 글
LLaMA: Open and Efficient Foundation Language Models 정리 (1) | 2024.06.10 |
---|---|
RoBERTa : A Robustly Optimized BERT Pretraining Approach 정리 및 이해 (0) | 2024.03.07 |
BERT(Bidirectional Encoder Representations from Transformers) 개념 정리 및 이해 (0) | 2024.02.17 |
Positional encoding과 Relative position representation은 어떻게 동작하는가 (0) | 2023.10.11 |
RNN/LSTM/GRU 의 구조를 이해해보자 (0) | 2022.11.08 |