Skip to main content

HuggingFace, PyTorch, 그리고 Weights & Biases(W&B)로 구축하는 개체명 인식 시스템

이 글은 Hugging Face, PyTorch, W&B를 활용한 개체명 인식(NER)을 다룹니다. CoNLL-2003 데이터셋으로 모델을 학습하고 예문에 대해 NER을 수행하는 과정을 설명합니다. 이 글은 AI 번역본입니다. 오역이 의심되는 부분이 있으면 댓글로 알려주세요.
Created on September 15|Last edited on September 15
소스

소개

이 글에서는 NER의 세계를 깊이 살펴보고, 최신 기법을 활용해 강력한 NER 모델을 만드는 방법을 탐구합니다. 우리는 다음을 활용하는 데 집중할 것입니다 허깅 페이스 라이브러리로, 다양한 사전 학습 모델과 NLP 작업용 도구를 제공합니다. 구체적으로 우리는 활용할 것입니다 PyTorch, 널리 사용되는 딥러닝 프레임워크를 사용해 CoNLL-2003 데이터셋에 사전 학습된 BERT 모델을 파인튜닝합니다.
이 튜토리얼 전반에 걸쳐 데이터 준비, 토크나이즈, 모델 초기화, 학습, 평가 등 여러 중요한 단계를 다룹니다. 또한 학습된 모델을 사용해 예문에 NER을 수행하는 방법을 보여 주어, 고유 명칭을 정확하게 추출할 수 있도록 합니다.
이 글을 끝까지 읽으면 개체명 인식에 대한 탄탄한 이해와 Hugging Face, PyTorch, W&B를 활용한 실전 구현 방법을 갖추게 됩니다. 그럼 시작해 봅시다!

목차



개체명 인식이란 무엇인가

개체명 인식(NER) 의 한 분야입니다 자연어 처리(NLP) 텍스트에서 다양한 개체명을 식별하고 추출하는 작업을 말합니다. 여기서 개체명은 고유 명사로 지칭되는 특정한 사물, 사람, 장소, 조직 등입니다.
본질적으로 NER은 “농구 선수”나 “운동선수”가 아니라 “Michael Jordan”을 식별하려고 합니다.
뉴스 기사를 읽다 보면 사람, 장소, 조직의 이름이 자주 등장합니다. NER 알고리즘은 이러한 개체명을 자동으로 탐지하고 해당 범주로 분류하여, 방대한 텍스트에서 핵심 정보를 더 쉽게 추출할 수 있게 해줍니다.
왜 이것이 중요할까요? NER은 실제로 매우 다양한 활용 사례를 가지고 있습니다. 예를 들어 정보 추출 분야에서 NER은 방대한 비정형 텍스트에서 중요한 정보를 뽑아내는 데 사용됩니다. 뉴스 기사나 소셜 미디어 게시글에 언급된 사람, 조직, 위치의 이름을 식별하는 것처럼요. 또한 NER은 더 나은 요약, 분류, 검색, 추천, 비즈니스 인텔리전스에 도움이 됩니다. 질의응답, 감성 분석, 그리고 기계 번역등 다양한 분야에서 활용됩니다.

개체명 인식은 어떻게 작동할까요?

전반적으로 NER은 다음 단계로 나눌 수 있습니다:
토크나이즈: 개체명 인식의 첫 단계에서는 입력 텍스트가 토크나이즈됩니다. 토크나이즈 텍스트를 단어, 서브워드, 또는 문자와 같은 개별 단위로 분해하는 과정이며, 이를 통해 NER 모델이 텍스트를 세밀한 수준에서 처리하고 이해할 수 있게 합니다.
사전 학습된 모델: NER 모델은 종종 다음과 같은 강력한 딥러닝 아키텍처에 의존합니다 BERT(양방향 트랜스포머 인코더 표현)이러한 모델은 방대한 데이터셋으로 사전 학습되어 단어 간의 맥락화된 의미와 관계를 파악합니다. 이 사전 학습을 활용하면 모델은 언어와 그 미묘한 뉘앙스에 대한 깊은 이해를 갖추게 됩니다.
토큰 분류: 훈련 단계에서는 사전 학습된 모델이 미세 조정된 레이블이 지정된 텍스트 시퀀스와 해당 엔터티 레이블이 포함된 데이터셋을 사용합니다. 모델은 입력 시퀀스의 각 토큰을 특정 엔터티 범주로 분류하는 방법을 학습하며, 엔터티가 아닌 토큰에는 별도의 특수 레이블을 부여할 수도 있습니다. 이러한 학습을 통해 모델은 엔터티를 정확하게 인식하고 분류할 수 있게 됩니다.
추론: NER 모델의 학습이 완료되면, 보지 못한 새로운 텍스트에 대해서도 예측을 수행할 수 있습니다. 예측을 위해 입력 텍스트를 토크나이즈한 뒤, 모델이 이 토크나이즈된 시퀀스를 처리합니다. 모델은 토큰 내부의 문맥 정보를 분석하여 각 토큰에 대한 예측을 생성하고, 해당 토큰이 어떤 엔터티 범주에 속하는지 표시합니다.
후처리: 예측된 레이블에는 신뢰도 점수나 확률 분포와 같은 추가 정보가 포함될 수 있습니다. 최종 개체명을 얻기 위해서는 예측된 레이블에 후처리 단계를 적용합니다. 이 단계에서는 불필요한 레이블을 걸러내고, 겹치는 개체를 해소하며, 모호성을 처리하고, 언어별 규칙을 적용하여 예측을 정제합니다. 이를 통해 출력 결과가 정확하고 의미 있는 개체명만을 반영하도록 보장합니다.
평가: NER 모델의 성능을 평가하려면 예측된 개체명과 정답 레이블을 비���합니다. 평가지표로는 정밀도, 재현율, 그리고 F1 점수 점수는 NER 시스템이 올바른 개체를 식별하는 데 있어 정확성과 완전성을 측정하는 데 흔히 사용됩니다. 이러한 평가는 모델의 효과를 판단하고 성능 개선 방향을 제시하는 데 도움이 됩니다.

HuggingFace를 활용한 개체명 인식 튜토리얼

우리가 달성하려는 목표

이 튜토리얼의 목표는 개체명 인식(NER)을 수행할 수 있는 파이썬 기반 머신러닝 모델을 구축하는 것입니다. 구체적으로는 텍스트에서 개체명을 정확하게 식별하고 추출할 수 있는 모델을 개발하는 데 초점을 맞춥니다.
이를 달성하기 위해 우리는 다음을 활용할 것입니다 BERT(양방향 트랜스포머 인코더 표현)는 Google AI가 개발한 초기 트랜스포머 언어 모델 중 하나입니다. BERT는 방대한 텍스트 데이터로 사전 학습되었으며, NER을 포함한 다양한 NLP 작업에서 뛰어난 성능을 입증했습니다.
사전 학습된 BERT 모델을 미세 조정함으로써 CoNLL-2003 데이터셋에는 개체명이 라벨링된 예시가 포함되어 있어, 이를 활용해 사람, 지명, 조직 등 다양한 유형의 개체명을 인식하고 분류하도록 모델을 학습할 수 있습니다.

우리 데이터셋에 대한 추가 정보

CoNLL-2003 데이터셋은 Reuters Corpus의 영어 뉴스 기사들을 폭넓게 수집하고, 여기에 개체명 레이블을 주석으로 달아 구성한 것입니다. 이 데이터셋은 자연어 처리에서 개체명 인식(NER) 과제를 위한 벤치마크 데이터셋으로 널리 사용됩니다.
데이터셋을 찾으려면 다음 링크를 확인하세요: CoNLL-2003 데이터셋.
💡

단계별 튜토리얼

1단계: 패키지 설치 및 종속성 임포트

먼저 pip 패키지 관리자를 사용해 seqeval, transformers, datasets 등 필요한 패키지를 설치합니다. 또한 torch, numpy, AutoTokenizer 등 필수 종속성도 임포트합니다.
!pip install seqeval
!pip install transformers
!pip install datasets

import torch
from transformers import AutoTokenizer, AutoModelForTokenClassification, Trainer, TrainingArguments
from datasets import load_dataset, load_metric, Dataset, DatasetDict
import numpy as np
from seqeval.metrics import f1_score, precision_score, recall_score, classification_report

2단계: CUDA 사용 가능 여부와 디바이스 정보 확인

다음으로, GPU 가속을 위해 CUDA 사용 가능 여부를 확인해 봅시다.
print("CUDA available:", torch.cuda.is_available())
print("Current device index:", torch.cuda.current_device())
print("Device name:", torch.cuda.get_device_name(torch.cuda.current_device()))

3단계: 데이터 읽기 및 준비

이 단계에서는 보조 함수를 정의합니다. read_conll_file제공된 파일 경로에서 CoNLL 데이터셋을 읽어들이는 함수입니다. 데이터셋은 학습, 검증, 테스트 세트로 분할됩니다. 각 데이터셋은 토크나이즈된 문장들의 목록으로 구성되며, 각 토큰에는 해당하는 개체 명칭 태그가 연결되어 있습니다.
def read_conll_file(file_path):
with open(file_path, "r") as f:
content = f.read().strip()
sentences = content.split("\n\n")
data = []
for sentence in sentences:
tokens = sentence.split("\n")
token_data = []
for token in tokens:
token_data.append(token.split())
data.append(token_data)
return data

train_data = read_conll_file("/kaggle/input/conll2003-dataset/conll2003/eng.train")
validation_data = read_conll_file("/kaggle/input/conll2003-dataset/conll2003/eng.testa")
test_data = read_conll_file("/kaggle/input/conll2003-dataset/conll2003/eng.testb")

def convert_to_dataset(data, label_map):
formatted_data = {"tokens": [], "ner_tags": []}
for sentence in data:
tokens = [token_data[0] for token_data in sentence]
ner_tags = [label_map[token_data[3]] for token_data in sentence]
formatted_data["tokens"].append(tokens)
formatted_data["ner_tags"].append(ner_tags)
return Dataset.from_dict(formatted_data)

label_list = sorted(list(set([token_data[3] for sentence in train_data for token_data in sentence])))
label_map = {label: i for i, label in enumerate(label_list)}

train_dataset = convert_to_dataset(train_data, label_map)
validation_dataset = convert_to_dataset(validation_data, label_map)
test_dataset = convert_to_dataset(test_data, label_map)

datasets = DatasetDict({
"train": train_dataset,
"validation": validation_dataset,
"test": test_dataset,
})

4단계: 토크나이저와 모델 초기화

이 단계에서는 보조 함수인 convert_to_dataset를 정의하여 형식화된 CoNLL 데이터를 Hugging Face 데이터셋 형식으로 변환합니다. 이 함수는 데이터셋과 레이블 맵을 입력으로 받아, 토크나이즈된 문장과 해당 개체 명칭 태그를 포함한 Dataset 객체를 반환합니다.
model_name = "bert-base-cased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForTokenClassification.from_pretrained(model_name, num_labels=len(label_list))

5단계: 평가 지표와 토크나이제이션 함수 정의

여기에서는 평가 지표와 토크나이제이션 함수를 정의합니다. 평가 지표에는 정밀도(precision), 재현율(recall), F1 점수, 분류 보고서가 포함되며, 다음에서 가져옵니다. seqeval.metrics. 그 compute_metrics() 함수는 예측 레이블과 실제 레이블을 비교하여 이러한 지표를 계산합니다. The tokenize_and_align_labels() 이 함수는 입력 예제를 토크나이즈하고 해당 레이블을 정렬하는 역할을 합니다.
def compute_metrics(eval_prediction):
predictions, labels = eval_prediction
predictions = np.argmax(predictions, axis=2)

# Remove ignored index (special tokens)
true_predictions = [
[label_list[p] for (p, l) in zip(prediction, label) if l != -100]
for prediction, label in zip(predictions, labels)
]
true_labels = [
[label_list[l] for (p, l) in zip(prediction, label) if l != -100]
for prediction, label in zip(predictions, labels)
]

return {
"precision": precision_score(true_labels, true_predictions),
"recall": recall_score(true_labels, true_predictions),
"f1": f1_score(true_labels, true_predictions),
"classification_report": classification_report(true_labels, true_predictions),
}

def tokenize_and_align_labels(examples):
tokenized_inputs = tokenizer(
examples["tokens"], truncation=True, is_split_into_words=True, padding=True
)
labels = []
for i, label in enumerate(examples["ner_tags"]):
word_ids = tokenized_inputs.word_ids(batch_index=i)
previous_word_idx = None
label_ids = []
for word_idx in word_ids:
if word_idx is None:
label_ids.append(-100)
elif word_idx != previous_word_idx:
label_ids.append(label[word_idx])
else:
label_ids.append(-100)
previous_word_idx = word_idx
labels.append(label_ids)
tokenized_inputs["labels"] = labels
return tokenized_inputs

6단계: 데이터셋 토크나이즈 및 학습 인자 설정

이 단계에서는 다음을 사용해 데이터셋을 토크나이즈합니다. map() datasets 라이브러리의 함수입니다. The tokenize_and_align_labels() 함수는 각 데이터셋에 배치 방식으로 적용됩니다. 예제를 토크나이즈하고 토크나이즈된 입력에 레이블을 정렬합니다. 이렇게 생성된 토크나이즈된 데이터셋은 tokenized_datasets 변수에 저장됩니다.
또한 출력 디렉터리, 평가 전략, 배치 크기, 학습률, 학습 에폭 수와 같은 학습 인자도 다음을 사용해 정의합니다. TrainingArguments 클래스.
tokenized_datasets = datasets.map(tokenize_and_align_labels, batched=True)

training_args = TrainingArguments(
output_dir="./results",
evaluation_strategy="steps",
eval_steps=500,
save_steps=500,
num_train_epochs=1,
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
logging_steps=100,
learning_rate=5e-5,
load_best_model_at_end=True,
metric_for_best_model="f1",
)

7단계: 데이터 콜레이터 정의 및 트레이너 초기화

여기서는 학습에 사용할 입력 데이터를 준비하는 데이터 콜레이터 함수를 정의합니다. data_collator() 함수는 배치 데이터를 받아 PyTorch 텐서로 변환합니다. 패딩 필요에 따라 시퀀스에 패딩을 적용합니다. 그런 다음 모델, 학습 인자, 데이터셋, 데이터 콜레이터, 토크나이저, 그리고 학습 중 평가를 위한 compute_metrics() 함수를 포함해 Trainer 객체를 초기화합니다.
def data_collator(data):
input_ids = [torch.tensor(item["input_ids"]) for item in data]
attention_mask = [torch.tensor(item["attention_mask"]) for item in data]
labels = [torch.tensor(item["labels"]) for item in data]

input_ids = torch.nn.utils.rnn.pad_sequence(input_ids, batch_first=True, padding_value=tokenizer.pad_token_id)
attention_mask = torch.nn.utils.rnn.pad_sequence(attention_mask, batch_first=True, padding_value=0)
labels = torch.nn.utils.rnn.pad_sequence(labels, batch_first=True, padding_value=-100)

return {
"input_ids": input_ids,
"attention_mask": attention_mask,
"labels": labels,
}

trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["validation"],
data_collator=data_collator,
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)

8단계: 모델 학습하기

trainer.train() 메서드를 호출하여 학습을 시작합니다. 모델은 앞서 정의한 학습 인자를 사용해 지정한 데이터셋으로 학습됩니다.
trainer.train()

9단계: 예제에 명명 엔터티 인식 수행하기

이 단계에서는 학습된 모델과 토크나이저를 사용해 여러 예문에 대해 명명 엔터티 인식(NER)을 수행하는 방법을 보여줍니다. 주어진 문장을 입력하고, 모델이 생성한 모든 출력 결과를 출력합니다.

예제 1

sentence = "John Smith is a software engineer who works at Google."

tokenized_input = tokenizer(sentence, return_tensors="pt").to(model.device)

outputs = model(**tokenized_input)

predicted_labels = outputs.logits.argmax(-1)[0]

named_entities = [tokenizer.decode([token]) for token, label in zip(tokenized_input["input_ids"][0], predicted_labels) if label != 0 and label != label_map['O']]

print("Named Entities - Example 1:", named_entities)
출력: 명명 엔터티 - 예제 1: ['John', 'Smith', 'Google']

예제 2

sentence2 = "The company Apple Inc. announced its new product, the iPhone 12, at a press conference held in San Francisco."

tokenized_input2 = tokenizer(sentence2, return_tensors="pt").to(model.device)

outputs2 = model(**tokenized_input2)

predicted_labels2 = outputs2.logits.argmax(-1)[0]

named_entities2 = [tokenizer.decode([token]) for token, label in zip(tokenized_input2["input_ids"][0], predicted_labels2) if label != 0 and label != label_map['O']]

print("Named Entities - Example 2:", named_entities2)
출력: 명명 엔터티 - 예제 2: ['Apple', 'Inc', 'iPhone', '12', 'Francisco']

예제 3

sentence3 = "The actor Tom Hanks starred in the movie Forrest Gump."

tokenized_input3 = tokenizer(sentence3, return_tensors="pt").to(model.device)

outputs3 = model(**tokenized_input3)

predicted_labels3 = outputs3.logits.argmax(-1)[0]

named_entities3 = [tokenizer.decode([token]) for token, label in zip(tokenized_input3["input_ids"][0], predicted_labels3) if label != 0 and label != label_map['O']]

print("Named Entities - Example 3:", named_entities3)
출력: 명명 엔터티 - 예제 3: ['Tom', 'Hank', '##s', 'Forrest', 'G', '##ump']

예제 4

sentence4 = "Paris is the capital city of France."

tokenized_input4 = tokenizer(sentence4, return_tensors="pt").to(model.device)

outputs4 = model(**tokenized_input4)

predicted_labels4 = outputs4.logits.argmax(-1)[0]

named_entities4 = [tokenizer.decode([token]) for token, label in zip(tokenized_input4["input_ids"][0], predicted_labels4) if label != 0 and label != label_map['O']]

print("Named Entities - Example 4:", named_entities4)
출력: 명명 엔터티 - 예제 4: []
위에서 본 것처럼, 해당 예시에서 모델은 개체명을 반환하지 못했습니다. 특정 예시에서 모델이 개체명을 식별하지 못하는 이유는 여러 가지일 수 있습니다. 성능을 향상시키기 위해 다음과 같은 접근을 고려하세요. (1) 학습 데이터의 다양성을 높이고, 특정 데이터셋에 맞춰 파인튜닝하세요. (2) 변이를 처리할 수 있도록 데이터를 전처리하고 정규화하세요. (3) 다양한 모델과 아키텍처를 실험해 보세요. (4) 오류를 분석하고 주석을 수동으로 교정하세요.

예제 5

sentence5 = "The scientist Marie Curie won the Nobel Prize in Physics and Chemistry."

tokenized_input5 = tokenizer(sentence5, return_tensors="pt").to(model.device)

outputs5 = model(**tokenized_input5)

predicted_labels5 = outputs5.logits.argmax(-1)[0]

named_entities5 = [tokenizer.decode([token]) for token, label in zip(tokenized_input5["input_ids"][0], predicted_labels5) if label != 0 and label != label_map['O']]

print("Named Entities - Example 5:", named_entities5)
출력: 명명 엔터티 - 예제 5: ['Marie', 'C', '##uri', '##e', 'Nobel', 'Prize', 'in', 'Physics', 'and', 'Chemistry']
예제 4와 유사하게, 이 예제의 출력에도 몇 가지 오류가 있지만 그 정도는 덜합니다. 이 모델을 개선하려면 위 예제에서 언급한 단계와 유사한 절차를 따라 진행하세요.

Weights & Biases 모니터링

모델의 학습 통계를 추적하기 위해 우리는 사용할 것입니다 Weights & Biases.
코드를 실행할 때, 다음을 입력하라는 요청이 표시됩니다 wandb API 키. 키를 받으려면 제공된 인증 링크를 사용하면 됩니다.


훈련이 완료되면 “View Project” 링크를 클릭하세요. 그러면 모델의 훈련 통계가 제공되며, 여기에는 포함됩니다 learning_rate, train_runtime, 그리고 더 많은 기능까지.


결론

이 튜토리얼에서는 Hugging Face, PyTorch, 그리고 W&B를 활용해 개체명 인식(NER)의 세계를 탐구했습니다. 텍스트에서 유용한 정보를 추출하는 데 있어 NER의 중요성과, BERT와 같은 딥러닝 아키텍처를 기반으로 한 NER 모델이 인상적인 성능을 낼 수 있다는 점을 배웠습니다.
단계별 튜토리얼을 따라가며, 우리는 개체명을 정확하게 식별하고 분류할 수 있는 학습된 NER 모델을 얻었습니다. 이 모델은 정보 추출, 질의응답, 감정 분석, 기계 번역 등 다양한 실제 응용 분야에 적용할 수 있습니다. Hugging Face, PyTorch, 그리고 W&B의 강점을 바탕으로 텍스트 데이터에서 의미 있는 인사이트를 추출하기 위해 NER 시스템을 계속 탐구하고 고도화할 수 있습니다.


이 글은 AI로 번역되었습니다. 오역이 의심되는 부분이 있으면 댓글로 알려주세요. 원문 보고서는 아래 링크에서 확인할 수 있습니다: 원문 보고서 보기