PLM NSMC Finetuning

2024. 11. 8. 14:14·KT AIVLE School/언어지능 딥러닝

 

Hugging Face 사용

 

Hugging Face – The AI community building the future.

The Home of Machine Learning Create, discover and collaborate on ML better. We provide paid Compute and Enterprise solutions. We are building the foundation of ML tooling with the community.

huggingface.co

 

1. 환경 설정 및 데이터 이해

from google.colab import drive
drive.mount('/content/drive')

# install datasets 라이브러리
!pip install -qq datasets

import os
import numpy as np
import pandas as pd
from tqdm.auto import tqdm

import torch
import torch.nn.functional as F
from tqdm.auto import tqdm
from datasets import load_dataset
from transformers import (AutoTokenizer,
                          AutoModelForSequenceClassification,
                          TrainingArguments,
                          Trainer)
WORKSPACE = '경로지정'                    
!mkdir {WORKSPACE}/data
!ls {WORKSPACE}
dataset = load_dataset("e9t/nsmc")
dataset
dataset['train'].features
dataset['train'].num_rows
for i  in range(10):
    print(dataset['train'][i])

 

 

 

2. token 사용법

# Hugging Face Hub에서 tokenizer 다운로드
tokenizer = AutoTokenizer.from_pretrained("klue/roberta-base")

# 동작 확인을 위한 문장
sentence1 = "지미 카터: 제임스 얼 지미 카터 주니어(1924년 10월 1일~)는 민주당 출신 미국의 제39대 대통령 (1977-81)이다."
sentence2 = "수학: 수학(math)은 수, 양, 구조, 공간, 변화 등의 개념을 다루는 학문이다."
# tokenizer tokens 확인
tokens = tokenizer.tokenize(sentence1)
# tokens to ids
token_ids = tokenizer.convert_tokens_to_ids(tokens)
# [CLS], tokens ids, [SEP] 형식으로 변환
token_ids = tokenizer.encode(sentence1)

# 실제 모델에 입력형식으로 변환
# 배열에 미니배치 형식으로 여러 문장을 넣을 수 있음
inputs = tokenizer([sentence1, sentence2],
                   padding=True,         # 길이가 짧은 문장에 PAD를 붙여서 길이를 맞춤
                   truncation=True,      # 길이가 너무 긴 문장을 잘라서 버림
                   max_length=256,       # 최대 token 길이
                   return_tensors="pt")  # pytorch 형식으로 값 리턴
inputs

 

3. 모델 사용법

# Hugging Face Hub에서 tokenizer 다운로드
tokenizer = AutoTokenizer.from_pretrained("klue/roberta-base")
# Hugging Face Hub에서 model 다운로드
model = AutoModelForSequenceClassification.from_pretrained("klue/roberta-base",
                                                           num_labels=2)  # 예측할 class 개수
# 입력 생성
inputs = tokenizer([sentence1,
                    sentence2],
                   padding=True,         # 길이가 짧은 문장에 PAD를 붙여서 길이를 맞춤
                   truncation=True,      # 길이가 너무 긴 문장을 잘라서 버림
                   max_length=256,       # 최대 token 길이
                   return_tensors="pt")  # pytorch 형식으로 값 리턴
inputs

# 추론
# 미세조정(finetuning)을 하지 않았기 때문에 현재는 답변을 신뢰 할 수 없음)
results = model(**inputs)
# logits 확인
results.logits

model 추가된 부분

 

- PLM finetuning

# TODO: Hugging Face Hub에서 dataset 다운로드
dataset = load_dataset("e9t/nsmc")
# TODO: Hugging Face Hub에서 tokenizer 다운로드
tokenizer = AutoTokenizer.from_pretrained("klue/roberta-base")
# TODO: Hugging Face Hub에서 model 다운로드
model = AutoModelForSequenceClassification.from_pretrained("klue/roberta-base",
                                                           num_labels=2)

# dataset 선언
class NSMCDataset(torch.utils.data.Dataset):
    def __init__(self, dataset):
        super().__init__()
        self.dataset = dataset

    def __len__(self):
        return len(self.dataset)

    def __getitem__(self, idx):
        return self.dataset[idx]['document'], self.dataset[idx]['label']

train_dataset = NSMCDataset(dataset['train'])
test_dataset = NSMCDataset(dataset['test'])

# collator 선언
class NSMCCollator:
    def __init__(self, tokenizer, max_length=256):
        self.tokenizer = tokenizer
        self.max_length = max_length

    def __call__(self, batch):
        texts, labels = zip(*batch)

        inputs = self.tokenizer(
            texts,
            padding=True,
            truncation=True,
            max_length=self.max_length,
            return_tensors="pt",
        )

        return_value = {
            "input_ids": inputs["input_ids"],
            "attention_mask": inputs["attention_mask"],
            "labels": torch.tensor(labels, dtype=torch.long),
        }

        return return_value

nsmc_collator = NSMCCollator(tokenizer)
# epoch 당 step 수 계산
steps_per_epoch = int(np.ceil(len(dataset['train']) / 128))
steps_per_epoch
# Train arguments 선언
training_args = TrainingArguments(
    output_dir=f"{WORKSPACE}/checkpoint/klue-roberta-base",
    overwrite_output_dir=True,
    per_device_train_batch_size=128,
    per_device_eval_batch_size=128,
    gradient_accumulation_steps=1,
    eval_accumulation_steps=1,
    learning_rate=5e-5,
    weight_decay=0.01,
    lr_scheduler_type='linear',
    warmup_steps=1000,
    num_train_epochs=3,
    logging_strategy="epoch",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    save_total_limit=5,
    # bf16=config.fp16,
    # bf16_full_eval=config.fp16,
    fp16=True,
    fp16_full_eval=True,
    half_precision_backend=True,
    load_best_model_at_end=True,
    report_to="none"
)

# trainer 선언
trainer = Trainer(
        model=model,
        args=training_args,
        train_dataset=train_dataset,
        eval_dataset=test_dataset,
        tokenizer=tokenizer,
        data_collator=nsmc_collator,
    )
    
# train
trainer.train()

 

 

 

- 평가하기

# TODO: Hugging Face Hub에서 dataset 다운로드
dataset = load_dataset("e9t/nsmc")

# 저장된 결과 확인
!ls {WORKSPACE}/checkpoint/klue-roberta-base

# TODO: 가장 성능이 좋은 경로를 입력하세요.
best_fn = f"{WORKSPACE}/checkpoint/klue-roberta-base/성능좋은 경로"

# TODO: 저장된 tokenizer 로드
tokenizer = AutoTokenizer.from_pretrained(best_fn)

# TODO: 저장된 model 로드
model = AutoModelForSequenceClassification.from_pretrained(best_fn,
                                                           num_labels=2)
                                                           
                                                           
# dataset 선언
class NSMCDataset(torch.utils.data.Dataset):
    def __init__(self, dataset):
        super().__init__()

        self.dataset = dataset

    def __len__(self):
        return len(self.dataset)

    def __getitem__(self, idx):
        return self.dataset[idx]['document'], self.dataset[idx]['label']

train_dataset = NSMCDataset(dataset['train'])
test_dataset = NSMCDataset(dataset['test'])

# collator 선언
class NSMCCollator:
    def __init__(self, tokenizer, max_length=256):
        self.tokenizer = tokenizer
        self.max_length = max_length

    def __call__(self, batch):
        texts, labels = zip(*batch)

        inputs = self.tokenizer(
            texts,
            padding=True,
            truncation=True,
            max_length=self.max_length,
            return_tensors="pt",
        )

        return_value = {
            "input_ids": inputs["input_ids"],
            "attention_mask": inputs["attention_mask"],
            "labels": torch.tensor(labels, dtype=torch.long),
        }

        return return_value

nsmc_collator = NSMCCollator(tokenizer)

# test loader 생성
test_loader = torch.utils.data.DataLoader(
    test_dataset,
    batch_size=128,
    shuffle=False,
    collate_fn=nsmc_collator
)

# gpu 사용 가능 여부 확인
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 맞은거 확인
total_correct_cnt = 0
total_sample_cnt = 0

model.to(device)
model.eval()

with torch.no_grad():
    for batch in tqdm(test_loader):
        output = model(
            input_ids=batch["input_ids"].to(device),
            attention_mask=batch["attention_mask"].to(device),
        )
        probs = torch.functional.F.softmax(output.logits, dim=-1)
        prob, pred = torch.max(probs, dim=-1)

        correct_cnt = (pred.cpu() == batch["labels"]).sum().item()
        sample_cnt = len(batch["labels"])

        total_correct_cnt += correct_cnt
        total_sample_cnt += sample_cnt

print(f"Test Accuracy: {total_correct_cnt / total_sample_cnt * 100:.2f}%")
print(f"Correct / Total: {total_correct_cnt} / {total_sample_cnt}")

# idx -> label
idx2label = {0: '부정', 1: '긍정'}

# 랜덤하게 10개 셈플 결과 확인
idxs = np.random.randint(0, dataset['test'].num_rows, 10)

with torch.no_grad():
    for idx in idxs:
        document = dataset['test'][int(idx)]['document']
        # inputs 생성
        inputs = tokenizer(
                    document,
                    truncation=True,
                    max_length=256,
                    return_tensors="pt",
                ).to(device)
        # 추론
        logit = model(**inputs).logits[0]
        prob = F.softmax(logit, dim=-1)
        # 가장 높은 확률을 정답으로 예측
        y = prob.argmax(dim=-1)
        # 출력
        print(f"{idx2label[y.item()]}\t{prob[y].item():.4f}\t{document}")
        
       
# 직접 입력을 받아서 긍정/부정 예측
while True:
    print("input> ", end="")
    document = str(input())
    if len(document) == 0:
        break
    # TODO: inputs 생성
    inputs = tokenizer(
    document,
    truncation=True,
    max_length=256,
    return_tensors="pt",
    ).to(device)
    # TODO: 추론
    logit = model(**inputs).logits[0]
    prob = F.softmax(logit, dim=-1)
    # TODO: 가장 높은 확률을 정답으로 예측
    y = prob.argmax(dim=-1)
    # 출력
    print(f"{idx2label[y.item()]}\t{prob[y].item():.4f}\t{document}")

커플이 부정인게 재밌네요ㅎㅎ

 

'KT AIVLE School > 언어지능 딥러닝' 카테고리의 다른 글

LLM  (4) 2024.11.08
인공지능 신경망  (0) 2024.11.07
영화 리뷰 가져오기  (2) 2024.11.05
RSS로 전자신문 검색기능 만들기  (5) 2024.11.05
언어지능  (2) 2024.11.04
'KT AIVLE School/언어지능 딥러닝' 카테고리의 다른 글
  • LLM
  • 인공지능 신경망
  • 영화 리뷰 가져오기
  • RSS로 전자신문 검색기능 만들기
Rabet
Rabet
  • 블로그 메뉴

    • 관리자
    • 글쓰기
  • Rabet
    卯
    Rabet
  • 전체
    오늘
    어제
    • Root (139)
      • KT AIVLE School (85)
        • Start (4)
        • Python프로그래밍 & 라이브러리 (6)
        • 데이터 처리 및 분석 (7)
        • 데이터 분석 및 의미 찾기 (7)
        • 웹크롤링 (10)
        • 머신러닝 (10)
        • 딥러닝 (6)
        • 시각지능 딥러닝 (10)
        • 언어지능 딥러닝 (6)
        • JAVA (4)
        • SQL (2)
        • 가상화 클라우드 (5)
        • 프로젝트 (8)
      • QA (2)
        • 오류사항 (1)
      • 웹공부 (14)
        • SPRING (11)
        • React (1)
      • 코딩 알고리즘 스터디 (23)
      • 코딩테스트 (9)
        • JAVA (8)
        • HTML (1)
      • CS공부 (3)
      • 자격증공부 (3)
        • 정보처리기사 (1)
        • 컴퓨터활용능력 1급 (1)
        • AICE Associate (1)
        • CSTS (0)
  • 인기 글

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
Rabet
PLM NSMC Finetuning
상단으로

티스토리툴바