문서가 주어졌을 때, 해당 문서의 범주를 분류하는 모델 설계
- 뉴스 → 어떤 종류의 뉴스인가? 경제, 정치, 사회 등등
- 영화 리뷰 → 긍정적인가? 부정적인가?
네이버 영화리뷰 말뭉치 사용.
영화 리뷰 문장 → 긍정/부정 확률 → 결과값 도출
1. 구조파악
모델 구조
- 토큰 시퀀스 앞뒤로 CLS와 SEP를 붙인다.
- 이를 BERT 모델에 입력, 후 문장 수준의 벡터(pooler_output) 도출
- 여기에 다시 작은 추가 모듈을 붙임.
- 최종적으로 [긍정일 확률, 부정일 확률] 구조의 벡터가 도출
<추가 모듈의 구조>
- 드롭아웃 적용 : 과적합 방지를 위한 수단
- 가중치 행렬 곱
- 소프트맥스 함수 취하기
모델 출력이 정답 레이블과 같아질 때까지 이 과정을 반복.
이를 파인튜닝 이라고 함.
2. 모델 만들기 1 : 모델의 학습
중요 : TPU 설정!
TPU를 쓰고 싶다면 사전에 무조건 여기 들어가서 설정 확인하기
colab.research.google.com/github/pytorch/xla/blob/master/contrib/colab/getting-started.ipynb관련 코드 모조리 입력하고 시작! 안 그러면 TPU를 구동할 수 없음.
코랩 노트북 초기화
- bit.ly/3FjJJ1H 에 접속 (모든 코드가 다 있음)
# 의존성 패키지 설치
!pip install ratsnlp
# 구글 드라이브와 연결
from google.colab import drive
drive.mount('/gdrive', force_remount=True)
각종 설정하기
# 모델 환경설정
import torch
from ratsnlp.nlpbook.classification import ClassificationTrainArguments
args = ClassificationTrainArguments(
pretrained_model_name="beomi/kcbert-base",
downstream_corpus_name="nsmc",
downstream_model_dir="/gdrive/My Drive/nlpbook/checkpoint-doccls",
batch_size=32 if torch.cuda.is_available() else 4,
learning_rate=5e-5,
max_seq_length=128,
epochs=3,
tpu_cores=0 if torch.cuda.is_available() else 8,
seed=7,
)
파라미터 설명
- batch_size = gpu / tpu에 따른 배치 사이즈.
- 배치란? 클릭
- learning rate = 러닝 레이트 (보폭). 1회 스텝에서 얼마나 업데이트할지에 대한 크기
- 스텝이란? 클릭
- epoch = 에포크
- 순전파와 역전파 1번을 왔다갔다 한 과정을 1 에포크라고 함.
- seed = 랜덤 시드
# 랜덤 시드 고정 : 학습 재현을 위해 랜덤 시드를 고정합니다.
from ratsnlp import nlpbook
nlpbook.set_seed(args)
# 로거 설정 : 메세지 출력 등을 위한 logger를 설정합니다.
nlpbook.set_logger(args)
네이버 말뭉치 다운로드
# 네이버 말뭉치 다운로드
from Korpora import Korpora
Korpora.fetch(
corpus_name=args.downstream_corpus_name,
root_dir=args.downstream_corpus_root_dir,
force_download=True,
)
토크나이저 준비
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained(
args.pretrained_model_name,
do_lower_case=False,
)
데이터전처리 준비
# 학습데이터 구축
from torch.utils.data import DataLoader, SequentialSampler, RandomSampler
from ratsnlp.nlpbook.classification import NsmcCorpus, ClassificationDataset
corpus = NsmcCorpus()
train_dataset = ClassificationDataset(
args=args,
corpus=corpus,
tokenizer=tokenizer,
mode="train",
)
train_dataloader = DataLoader(
train_dataset,
batch_size=args.batch_size,
sampler=RandomSampler(train_dataset, replacement=False),
collate_fn=nlpbook.data_collator,
drop_last=False,
num_workers=args.cpu_workers,
)
NsmcCorpus : CSV 파일 형식의 NSMC 데이터를 문장과 레이블로 읽어들임
classificationDataset : 문장 & 레이블을 모델이 학습가능한 형태 4가지로 변경
- input_ids : 인덱스로 변환한 토큰 시퀀스
- attention_mask : 해당 토큰이 패딩 토큰인지 아닌지 나타냄. 패딩 토큰이란? 클릭
- token_type_ids : 세그먼트 정보 (첫번째 문서인지 아닌지 나타내 준다.)
- label : 정수로 바뀐 레이블 정보
# 테스트 데이터 구축 : 학습 중에 평가할 테스트 데이터를 구축합니다.
val_dataset = ClassificationDataset(
args=args,
corpus=corpus,
tokenizer=tokenizer,
mode="test",
)
val_dataloader = DataLoader(
val_dataset,
batch_size=args.batch_size,
sampler=SequentialSampler(val_dataset),
collate_fn=nlpbook.data_collator,
drop_last=False,
num_workers=args.cpu_workers,
)
DataLoader : 배치 크기만큼 인스턴스를 뽑아 배치 형태로 가공
- sampler : 샘플링 방식을 정의.
- SequentialSampler : 항상 같은 순서로 샘플 추출
- collate_fn : 인스턴스를 배치로 만드는 함수
모델 초기화
from transformers import BertConfig, BertForSequenceClassification
pretrained_model_config = BertConfig.from_pretrained(
args.pretrained_model_name,
num_labels=corpus.num_labels,
)
model = BertForSequenceClassification.from_pretrained(
args.pretrained_model_name,
config=pretrained_model_config,
)
학습 준비
Task와 Trainer를 준비.
from ratsnlp.nlpbook.classification import ClassificationTask
task = ClassificationTask(model, args)
ClassificationTask에는 아담 옵티마이저 사용. (아담 옵티마이저란? 클릭)
러닝 레이트 스케줄러에는 ExponentialLR 사용. ExponentialLR ??
# 트레이너: 귀찮은 설정을 한방에 해결.
trainer = nlpbook.get_trainer(args)
학습
준비한 데이터와 모델로 학습을 시작합니다. 학습 결과물(체크포인트)은
미리 연동해둔 구글 드라이브의 준비된 위치
(/gdrive/My Drive/nlpbook/checkpoint-doccls)에 저장.
trainer.fit(
task,
train_dataloaders=train_dataloader,
val_dataloaders=val_dataloader,
)
3. 모델 만들기 2 : 모델 투입
코랩 노트북 초기화
- bit.ly/3leMWYr 에 접속 (모든 코드가 다 있음)
- 런타임 유형 > None으로.
환경 설정하기
# 의존성 패키지 설치
!pip install ratsnlp
# 구글 드라이브 연결
from google.colab import drive
drive.amount('\gdrive', force_remount=True)
# 인퍼런스 설정
from ratsnlp.nlpbook.classification import ClassificationDeployArguments
args = ClassificationDeployArguments(
pretrained_model_name = "beomi/kcbert-base",
downstream_model_dir = "/gdrive/My Drive/nlpbook/checkpoint-doccls",
max_seq_length = 128,
)
각종 설정
모델 하이퍼파라메터(hyperparameter)와 저장 위치 등 설정 정보를 선언합니다.
from ratsnlp.nlpbook.classification import ClassificationDeployArguments
args = ClassificationDeployArguments(
pretrained_model_name="beomi/kcbert-base",
downstream_model_dir="/gdrive/My Drive/nlpbook/checkpoint-doccls",
max_seq_length=128,
)
모델 로딩
파인튜닝을 마친 모델과 토크나이저를 읽어 들입니다.
import torch
from transformers import BertConfig, BertForSequenceClassification
fine_tuned_model_ckpt = torch.load(
args.downstream_model_checkpoint_fpath,
map_location=torch.device("cpu")
)
pretrained_model_config = BertConfig.from_pretrained(
args.pretrained_model_name,
num_labels=fine_tuned_model_ckpt['state_dict']['model.classifier.bias'].shape.numel(),
)
model = BertForSequenceClassification(pretrained_model_config)
model.load_state_dict({k.replace("model.", ""): v for k, v in fine_tuned_model_ckpt['state_dict'].items()})
model.eval()
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained(
args.pretrained_model_name,
do_lower_case=False,
)
인퍼런스 함수 선언
인퍼런스 함수를 선언합니다.
def inference_fn(sentence):
inputs = tokenizer(
[sentence],
max_length=args.max_seq_length,
padding="max_length",
truncation=True,
)
with torch.no_grad():
outputs = model(**{k: torch.tensor(v) for k, v in inputs.items()})
prob = outputs.logits.softmax(dim=1)
positive_prob = round(prob[0][1].item(), 4)
negative_prob = round(prob[0][0].item(), 4)
pred = "긍정 (positive)" if torch.argmax(prob) == 1 else "부정 (negative)"
return {
'sentence': sentence,
'prediction': pred,
'positive_data': f"긍정 {positive_prob}",
'negative_data': f"부정 {negative_prob}",
'positive_width': f"{positive_prob * 100}%",
'negative_width': f"{negative_prob * 100}%",
}
문장의 토큰화를 수행한 뒤, input_ids와 attention_mask, token_type_ids를 만듬.
이들을 텐서로 바꾼 뒤, 모델에 입력.
모델 출력 값은 로짓 형태. 여기에 softmax() 함수로 모델 출력을 [부정확률, 긍정확률]로 바꿈.
웹서비스 만들기 준비
ngrok은 코랩 로컬에서 실행 중인 웹서비스를 안전하게 외부에서 접근 가능하도록 해주는 도구.
ngrok을 실행하려면 회원가입 후 로그인을 한 뒤 이곳에 접속해 인증 토큰(authtoken)을 확인해야 합니다. 예를 들어 확인된 authtoken이 test111이라면 다음과 같이 실행한다.
!mkdir /root/.ngrok2 && echo "authtoken: test111" > /root/.ngrok2/ngrok.yml
웹 서비스 배포
아래처럼 실행해 인퍼런스 함수를 웹서비스로 만든다.
from ratsnlp.nlpbook.classification import get_web_service_app
app = get_web_service_app(inference_fn)
app.run()
만약 웹 서비스가 안된다면?
- 직접 문장을 입력한 뒤 함수에 밀어넣자.
- while문을 쓰면 실시간 서비스 마냥 해볼 수 있다.
while 1:
s = input("문장을 입력하세요: ")
inference_fn(s)