열렬히.뛰기

6장 : 개체명 인식 모델

머신러닝 & 딥러닝 > 자연어처리 (1) : BERT와 GPT > 6장 : 개체명 인식 모델

1. 개요

개체명 인식이란? 토큰화된 문장에 개체명 태그를 붙여주는 과제

ex. 그 제품 삼성 건가요?

그 : 개체명 아님
제품 : 개체명 아님
삼성 : 기관명
건가요 : 개체명 아님.

준비하기

실습 데이터: 한국해양대학교 자연언어처리연구실에서 공개한 데이터 + 자체 제작 데이터

개체명 태그 수와 종류는 한국해양대학교 데이터셋을 기반으로 진행

PER : 인명  LOC : 지명  ORG : 기관명  DAT : 날짜  TIM : 시간
DUR : 기간  MNY : 통화  PNT : 비율    POH : 기타
NOH : 기타 수량표현 

각 토큰이 어떤 개체명 태그에 속할 지 확률로 나타냄 = 토큰 벡터

그     : [..., ..., ... , ...... , 0.9, ....]
제품   : [..., ..., ... , ...... , 0.9, ....]
삼성   : [..., ..., 0.87, ...... , ..., ....]
건가요 : [..., ..., ... , ...... , 0.9, ....]

모델 구조

  1. 문장을 토큰화
  2. 문장 앞뒤로 토큰 CLS, SEP를 붙인다.
    • CLS : 문장 앞에 붙이는 토큰
    • SEP : 문장 뒤에 붙이는 토큰
  3. BERT 모델에 입력
  4. 토큰 벡터 각각에 추가 모델 장착

태스크 모델(추가 모델) 구조

  1. 개별 토큰 벡터에 드롭아웃 적용
  2. 가중치 행렬 곱하기
  3. 소프트맥스 함수 이용
  4. 최종 출력 도출

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()

결과