1. 개요
개체명 인식이란? 토큰화된 문장에 개체명 태그를 붙여주는 과제
ex. 그 제품 삼성 건가요?
그 : 개체명 아님
제품 : 개체명 아님
삼성 : 기관명
건가요 : 개체명 아님.
준비하기
실습 데이터: 한국해양대학교 자연언어처리연구실에서 공개한 데이터 + 자체 제작 데이터
개체명 태그 수와 종류는 한국해양대학교 데이터셋을 기반으로 진행
PER : 인명 LOC : 지명 ORG : 기관명 DAT : 날짜 TIM : 시간
DUR : 기간 MNY : 통화 PNT : 비율 POH : 기타
NOH : 기타 수량표현
각 토큰이 어떤 개체명 태그에 속할 지 확률로 나타냄 = 토큰 벡터
그 : [..., ..., ... , ...... , 0.9, ....]
제품 : [..., ..., ... , ...... , 0.9, ....]
삼성 : [..., ..., 0.87, ...... , ..., ....]
건가요 : [..., ..., ... , ...... , 0.9, ....]
모델 구조
- 문장을 토큰화
- 문장 앞뒤로 토큰 CLS, SEP를 붙인다.
- CLS : 문장 앞에 붙이는 토큰
- SEP : 문장 뒤에 붙이는 토큰
- BERT 모델에 입력
- 토큰 벡터 각각에 추가 모델 장착
태스크 모델(추가 모델) 구조
- 개별 토큰 벡터에 드롭아웃 적용
- 가중치 행렬 곱하기
- 소프트맥스 함수 이용
- 최종 출력 도출
2. 모델 학습하기
각종 설정
패키지 설치하기
TPU 관련 패키지를 설치
python
!pip install cloud-tpu-client==0.10 torch==1.12.0 https://storage.googleapis.com/tpu-pytorch/wheels/colab/torch_xla-1.12-cp37-cp37m-linux_x86_64.whl
의존성 패키지 설치
python
!pip install ratsnlp
구글 드라이브 연동하기
모델 체크포인트 등을 저장해 둘 구글 드라이브를 연결한다. 자신의 구글 계정에 적용하기 위한 용도
python
from google.colab import drive
drive.mount('/gdrive', force_remount=True)
모델 환경 설정
모델 하이퍼파라메터(hyperparameter)와 저장 위치 등 설정 정보를 선언
python
import torch
from ratsnlp.nlpbook.ner import NERTrainArguments
args = NERTrainArguments(
pretrained_model_name="beomi/kcbert-base",
downstream_corpus_name="ner",
downstream_model_dir="/gdrive/My Drive/nlpbook/checkpoint-ner",
batch_size=32 if torch.cuda.is_available() else 4,
learning_rate=5e-5,
max_seq_length=64,
epochs=3,
tpu_cores=0 if torch.cuda.is_available() else 8,
seed=7,
)
랜덤 시드 고정
학습 재현을 위해 랜덤 시드를 고정
python
from ratsnlp import nlpbook
nlpbook.set_seed(args)
로거 설정
메세지 출력을 위한 logger를 설정
python
nlpbook.set_logger(args)
말뭉치 다운로드
실습에 사용할 말뭉치(NER)를 다운로드한다.
python
nlpbook.download_downstream_dataset(args)
토크나이저 준비
토큰화를 수행하는 토크나이저를 선언.
python
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained(
args.pretrained_model_name,
do_lower_case=False,
)
학습데이터 구축
python
from ratsnlp.nlpbook.ner import NERCorpus, NERDataset
from torch.utils.data import DataLoader, SequentialSampler, RandomSampler
corpus = NERCorpus(args)
train_dataset = NERDataset(
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,
)
테스트 데이터 구축
학습 중에 평가할 테스트 데이터를 구축.
python
val_dataset = NERDataset(
args=args,
corpus=corpus,
tokenizer=tokenizer,
mode="val",
)
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,
)
모델 초기화
• 프리트레인이 완료된 BERT 모델을 읽는다
• 개체명 인식 수행할 모델을 초기화.
python
from transformers import BertConfig
pretrained_model_config = BertConfig.from_pretrained(
args.pretrained_model_name,
num_labels=corpus.num_labels,
)
from transformers import BertForTokenClassification
model = BertForTokenClassification.from_pretrained(
args.pretrained_model_name,
config=pretrained_model_config,
)
학습 준비
Task와 Trainer를 준비.
python
from ratsnlp.nlpbook.ner import NERTask
task = NERTask(model, args)
trainer = nlpbook.get_trainer(args)
학습
준비한 데이터와 모델로 학습을 시작.
python
trainer.fit(
task,
train_dataloaders=train_dataloader,
val_dataloaders=val_dataloader,
)
3. 모델 실전투입
패키지 설치
pip 명령어로 의존성 패키지를 설치한다
python
!pip install ratsnlp
설정
구글 드라이브 연동하기
모델 체크포인트 등을 저장해 둘 구글 드라이브를 연결. 자신의 구글 계정에 적용.
python
from google.colab import drive
drive.mount('/gdrive', force_remount=True)
각종 설정
hyperparameter와 저장 위치 등을 선언합니다.
python
from ratsnlp.nlpbook.ner import NERDeployArguments
args = NERDeployArguments(
pretrained_model_name="beomi/kcbert-base",
downstream_model_dir="/gdrive/My Drive/nlpbook/checkpoint-ner",
max_seq_length=64,
)
토크나이저 및 모델 불러오기
파인튜닝을 마친 모델과 토크나이저를 읽어드림.
모델 로딩
python
import torch
from transformers import BertConfig, BertForTokenClassification
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 = BertForTokenClassification(pretrained_model_config)
model.load_state_dict({k.replace("model.", ""): v for k, v in fine_tuned_model_ckpt['state_dict'].items()})
model.eval()
토크나이저 로드
python
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained(
args.pretrained_model_name,
do_lower_case=False,
)
모델 출력값 만들고 후처리
레이블 맵 작성
python
labels = [label.strip() for label in open(args.downstream_model_labelmap_fpath, "r").readlines()]
id_to_label = {}
for idx, label in enumerate(labels):
if "PER" in label:
label = "인명"
elif "LOC" in label:
label = "지명"
elif "ORG" in label:
label = "기관명"
elif "DAT" in label:
label = "날짜"
elif "TIM" in label:
label = "시간"
elif "DUR" in label:
label = "기간"
elif "MNY" in label:
label = "통화"
elif "PNT" in label:
label = "비율"
elif "NOH" in label:
label = "기타 수량표현"
elif "POH" in label:
label = "기타"
else:
label = label
id_to_label[idx] = label
인퍼런스 함수 선언
인퍼런스 함수를 선언.
python
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()})
probs = outputs.logits[0].softmax(dim=1)
top_probs, preds = torch.topk(probs, dim=1, k=1)
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
predicted_tags = [id_to_label[pred.item()] for pred in preds]
result = []
for token, predicted_tag, top_prob in zip(tokens, predicted_tags, top_probs):
if token not in [tokenizer.pad_token, tokenizer.cls_token, tokenizer.sep_token]:
token_result = {
"token": token,
"predicted_tag": predicted_tag,
"top_prob": str(round(top_prob[0].item(), 4)),
}
result.append(token_result)
return {
"sentence": sentence,
"result": result,
}
웹서비스 만들기 준비
python
!mkdir /root/.ngrok2 && echo "authtoken: {토큰}" > /root/.ngrok2/ngrok.yml
웹서비스 개시
python
from ratsnlp.nlpbook.ner import get_web_service_app
app = get_web_service_app(inference_fn)
app.run()