트랜스포머를 사용한 네임드 엔티티 인식

소개영구 링크

이전 블로그 게시물에서 저희 팀이 스페인어용 트랜스포머 언어 모델인 SpanBERTa를 처음부터 대규모 말뭉치에 대해 사전 학습시킨 방법에 대해 설명한 바 있습니다. 이 모델은 문맥에 따라 시퀀스에서 마스킹된 단어를 정확하게 예측할 수 있는 것으로 나타났습니다. 이 블로그 게시물에서는 트랜스포머 모델의 성능을 실제로 활용하기 위해 명명된 엔티티 인식 작업을 위해 SpanBERTa를 미세 조정해 보겠습니다.

의 정의에 따르면 Wikipedia엔티티 식별, 엔티티 청킹, 엔티티 추출이라고도 하는 명명된 엔티티 인식(NER)은 비정형 텍스트에 언급된 명명된 엔티티를 찾아서 사람 이름, 조직, 위치, 의료 코드, 시간 표현, 수량, 화폐 가치, 백분율 등과 같은 사전 정의된 카테고리로 분류하는 정보 추출의 하위 작업입니다.

스크립트를 사용합니다. run_ner.py 허깅 페이스와 CoNLL-2002 데이터 세트 를 사용하여 SpanBERTa를 미세 조정할 수 있습니다.

설정영구 링크

다운로드 트랜스포머 를 클릭하고 필요한 패키지를 설치합니다.

%%캡처
!git 복제 https://github.com/포옹하는 얼굴/트랜스포머
%cd 트랜스포머
!pip 설치 .
!pip 설치 -r ./예제/요구 사항.txt
%cd ..

데이터영구 링크

1. 데이터 세트 다운로드영구 링크

아래 명령은 데이터 세트를 다운로드하고 압축을 해제합니다. 파일에는 다음 세 가지 부분에 대한 훈련 및 테스트 데이터가 포함되어 있습니다. CoNLL-2002 공유 작업:

  • esp.testa: 개발 단계를 위한 스페인어 테스트 데이터
  • esp.testb: 스페인어 테스트 데이터
  • esp.train: 스페인 열차 데이터
%%캡처
!wget -O 'conll2002.zip' 'https://drive.google.com/uc?export=download&id=1Wrl1b39ZXgKqCeAFNM9EoXtA1kzwNhCe'
!압축 해제 'conll2002.zip'

각 데이터 집합의 크기입니다:

!wc -l conll2002/esp.기차
!wc -l conll2002/esp.testa
!wc -l conll2002/esp.testb
273038 conll2002/esp.train
54838 conll2002/esp.testa
53050 conll2002/esp.testb

모든 데이터 파일에는 단어, 관련 품사 태그, IOB2 형식의 명명된 엔티티 태그의 세 가지 열이 있습니다. 문장 나누기는 빈 줄로 인코딩됩니다.

!head -n20 conll2002/esp.기차
멜버른 NP B-LOC
( Fpa O
호주 NP B-LOC
) Fpt O
, Fc O
25 Z O
may NC O
( Fpa O
EFE NC B-ORG
) Fpt O
. Fp O
- Fg O
El DA O
Abogado NC B-PER
일반 AQ I-PER
델 SP I-PER
NC 상태 I-PER
, Fc O

훈련, 개발 및 테스트 데이터 세트의 경우 단어 열과 명명된 엔티티 태그 열만 유지합니다.

!cat conll2002/esp.기차 |  -d " " -f 1,3 > train_temp.txt
!cat conll2002/esp.testa |  -d " " -f 1,3 > dev_temp.txt
!cat conll2002/esp.testb |  -d " " -f 1,3 > test_temp.txt

2. 전처리영구 링크

추가 전처리 단계와 모델 학습에 필요한 몇 가지 변수를 정의해 보겠습니다:

MAX_LENGTH = 120 #@param {유형: "정수"}
모델 = "크리스칸트란/스팬버타" #@param ["chriskhanhtran/spanberta", "bert-base-multilingual-cased"]

아래 스크립트는 다음보다 긴 문장을 분할합니다. MAX_LENGTH (토큰 기준)을 작은 토큰으로 줄여야 합니다. 그렇지 않으면 토큰화할 때 긴 문장이 잘려서 학습 데이터가 손실되고 테스트 세트의 일부 토큰이 예측되지 않을 수 있습니다.

%%캡처
!wget "https://raw.githubusercontent.com/stefan-it/fine-tuned-berts-seq/master/scripts/preprocess.py"
!python3 전처리.py train_temp.txt $모델 $MAX_LENGTH > 기차.txt
!python3 전처리.py dev_temp.txt $모델 $MAX_LENGTH > dev.txt
!python3 전처리.py test_temp.txt $모델 $MAX_LENGTH > 테스트.txt
2020-04-22 23:02:05.747294: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] 동적 라이브러리 libcudart.so.10.1을 성공적으로 열었습니다.
다운로드 중입니다: 100% 1.03k/1.03k [00:00<00:00, 704kB/s]
다운로드 중입니다: 100% 954k/954k [00:00<00:00, 1.89MB/s]
다운로드 중: 100% 512k/512k [00:00<00:00, 1.19MB/s]
다운로드 중: 100% 16.0/16.0 [00:00<00:00, 12.6kB/s]
2020-04-22 23:02:23.409488: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] 동적 라이브러리 libcudart.so.10.1을 성공적으로 열었습니다.
2020-04-22 23:02:31.168967: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] 동적 라이브러리 libcudart.so.10.1을 성공적으로 열었습니다.

3. 라벨영구 링크

CoNLL-2002/2003 데이터 세트에는 9가지 클래스의 NER 태그가 있습니다:

  • O, 명명된 엔티티 외부
  • B-MIS, 다른 기타 법인 바로 뒤의 기타 법인 시작
  • I-MIS, 기타 법인
  • B-PER, 다른 사람 이름 바로 뒤의 이름 시작 부분
  • I-PER, 개인 이름
  • B-ORG, 다른 조직의 바로 뒤에서 시작되는 조직의 시작
  • I-ORG, 조직
  • B-LOC, 다른 위치 바로 뒤에 있는 위치의 시작점
  • I-LOC, 위치

데이터 집합에 CoNLL-2002/2003 데이터 집합과 다른 레이블이 있거나 더 많은 레이블이 있는 경우 아래 줄을 실행하여 데이터에서 고유 레이블을 가져와서 다음 위치에 저장합니다. labels.txt. 이 파일은 모델 미세 조정을 시작할 때 사용됩니다.

!cat 기차.txt dev.txt 테스트.txt |  -d " " -f 2 | grep -v "^$"| 정렬 | 유니크 > 레이블.txt

미세 조정 모델영구 링크

다음은 다음의 예제 스크립트입니다. 트랜스포머의 저장소에서 NER용 모델을 미세 조정하는 데 사용할 것입니다. 2020년 4월 21일 이후 Hugging Face는 예제 스크립트를 업데이트하여 새로운 트레이너 클래스를 사용하세요. 향후 충돌을 방지하려면 이러한 업데이트 이전 버전을 사용하세요.

%%캡처
!wget "https://raw.githubusercontent.com/chriskhanhtran/spanish-bert/master/ner/run_ner.py"
!wget "https://raw.githubusercontent.com/chriskhanhtran/spanish-bert/master/ner/utils_ner.py"

이제 이전 학습을 할 차례입니다. 내 이전 블로그 게시물저는 대규모 스페인어 말뭉치에 대해 RoBERTa 언어 모델을 사전 학습시켜 문맥에 따라 마스크된 단어를 예측했습니다. 이를 통해 모델은 언어의 고유한 속성을 학습했습니다. 사전 학습된 모델을 허깅 페이스의 서버에 업로드했습니다. 이제 모델을 로드하고 NER 작업에 맞게 미세 조정을 시작하겠습니다.

아래는 트레이닝 하이퍼파라미터입니다.

MAX_LENGTH = 128 #@param {유형: "정수"}
모델 = "크리스칸트란/스팬버타" #@param ["chriskhanhtran/spanberta", "bert-base-multilingual-cased"]
OUTPUT_DIR = "spanberta-ner" #@param ["spanberta-ner", "bert-base-ml-ner"]
BATCH_SIZE = 32 #@param {유형: "정수"}
NUM_EPOCHS = 3 #@param {유형: "정수"}
SAVE_STEPS = 100 #@param {유형: "정수"}
로그인_단계 = 100 #@param {유형: "정수"}
SEED = 42 #@param {유형: "정수"}

교육을 시작하겠습니다.

!python3 run_ner.py \
 --data_dir ./ \
 --모델 유형 bert \
 --레이블 ./레이블.txt \
 --모델_이름_또는_경로 $모델 \
 --output_dir $OUTPUT_DIR \
 --MAX_SEQ_LENGTH $MAX_LENGTH \
 --NUM_TRIN_EPOCHS $NUM_EPOCHS \
 --per_gpu_train_batch_size $BATCH_SIZE \
 --저장_단계 $SAVE_STEPS \
 --로깅_스텝 $로그인_단계 \
 --seed $SEED \
 --do_train \
 --do_eval \
 --do_predict \
 --오버라이트_출력_디렉터

개발 세트에서의 성능:

04/21/2020 02:24:31 - INFO - __main__ - ***** 평가 결과 *****
04/21/2020 02:24:31 - INFO - __main__ - f1 = 0.831027443864822
04/21/2020 02:24:31 - INFO - __main__ - 손실 = 0.1004064822183894
04/21/2020 02:24:31 - INFO - __main__ - 정밀도 = 0.8207885304659498
04/21/2020 02:24:31 - INFO - __main__ - recall = 0.8415250344510795

테스트 세트에서의 성능:

04/21/2020 02:24:48 - INFO - __main__ - ***** 평가 결과 *****
04/21/2020 02:24:48 - INFO - __main__ - f1 = 0.8559533721898419
04/21/2020 02:24:48 - INFO - __main__ - 손실 = 0.06848683688204177
04/21/2020 02:24:48 - INFO - __main__ - 정밀도 = 0.845858475041141
04/21/2020 02:24:48 - INFO - __main__ - recall = 0.8662921348314607

다음은 미세 조정의 텐서보드입니다. 스팬버타bert-기반-다국어-케이스 를 5개의 에포크로 설정합니다. 3개의 에포크 이후에는 모델이 학습 데이터에 과도하게 적합하다는 것을 알 수 있습니다.

분류 보고서

모델이 실제로 얼마나 잘 작동하는지 이해하기 위해 예측을 로드하고 분류 보고서를 살펴 보겠습니다.

def 파일에서 읽기_예제_파일(파일_경로):
 """CoNLL-2002/2003 데이터 파일에서 단어와 레이블을 읽습니다.
 Args:
 file_path (str): NER 데이터 파일의 경로.
 반환합니다:
 examples (딕셔너리): 두 개의 키가 있는 딕셔너리: 단어`(목록 목록)
 (목록 목록), 그리고 각 시퀀스에 해당하는 레이블을 포함하는
 (목록 목록).
 """
 와 함께 열기(파일_경로, 인코딩="utf-8") as f:
 예제 = {"단어": [], "레이블": []}
 단어 = []
 레이블 = []
 에 대한 라인 in f:
 만약 라인.시작("-DOCSTART-") 또는 라인 == "" 또는 라인 == "\n":
 만약 단어:
 예제["단어"].추가(단어)
 예제["레이블"].추가(레이블)
 단어 = []
 레이블 = []
 else:
 분할 = 라인.분할(" ")
 단어.추가(분할[0])
 만약 len(분할) > 1:
 레이블.추가(분할[-1].대체("\n", ""))
 else:
 # 예제에는 모드 = "테스트"에 대한 레이블이 없을 수 있습니다.
 레이블.추가("O")
 반환 예제

원시 텍스트 파일에서 데이터와 레이블을 읽습니다:

y_true = 파일에서 읽기_예제_파일("test.txt")["레이블"]
y_pred = 파일에서 읽기_예제_파일("spanberta-ner/test_predictions.txt")["레이블"]

분류 보고서를 인쇄합니다:

에서 seqeval.metrics 가져오기 분류_보고서 as 분류_보고_세분화
인쇄(분류_보고_세분화(y_true, y_pred))
 정밀 리콜 F1 점수 지원
 LOC 0.87 0.84 0.85 1084
 ORG 0.82 0.87 0.85 1401
 기타 0.63 0.66 0.65 340
 PER 0.94 0.96 0.95 735
마이크로 평균 0.84 0.86 0.85 3560
매크로 평균 0.84 0.86 0.85 3560

이 보고서에 표시되는 메트릭은 엔티티의 모든 단어가 정확하게 예측되어야 하나의 정확한 예측으로 계산되는 NER 및 POS 태깅과 같은 NLP 작업을 위해 특별히 설계되었습니다. 따라서 이 분류 보고서의 메트릭은 다음보다 훨씬 낮습니다. SCIKIT-Learn의 분류 보고서.

가져오기 numpy as np
에서 sklearn.metrics 가져오기 분류_보고서
인쇄(분류_보고서(np.연결(y_true), np.연결(y_pred)))
 정밀 리콜 F1 점수 지원
 B-LOC 0.88 0.85 0.86 1084
 B-MISC 0.73 0.73 0.73 339
 B-OG 0.87 0.91 0.89 1400
 B-PER 0.95 0.96 0.95 735
 I-LOC 0.82 0.81 0.81 325
 I-MISC 0.85 0.76 0.80 557
 I-OG 0.89 0.87 0.88 1104
 I-PER 0.98 0.98 0.98 634
 O 1.00 1.00 1.00 45355
 정확도 0.98 51533
 매크로 평균 0.89 0.87 0.88 51533
WEIGHTED AVG 0.98 0.98 0.98 51533

위의 보고서에서 볼 수 있듯이 저희 모델은 사람, 위치, 조직을 예측하는 데 좋은 성능을 보입니다. 다음을 위해 더 많은 데이터가 필요합니다. MISC 엔티티를 추가하여 이러한 엔티티에 대한 모델의 성능을 개선합니다.

파이프라인영구 링크

모델을 미세 조정한 후에는 이 튜토리얼에 따라 커뮤니티와 공유할 수 있습니다. 페이지. 이제 Hugging Face의 서버에서 미세 조정된 모델을 로드하여 스페인어 문서에서 명명된 엔티티를 예측하는 데 사용할 수 있습니다.

에서 트랜스포머 가져오기 파이프라인, 자동모델포토큰분류, 오토토큰라이저
모델 = 자동모델포토큰분류.from_pretrained("스키마이/스판베르타-베이스-케이스-너-콘엘02")
토큰화 = 오토토큰라이저.from_pretrained("스키마이/스판베르타-베이스-케이스-너-콘엘02")
ner_model = 파이프라인('ner', 모델=모델, 토큰화=토큰화)

아래 예는 다음에서 가져온 것입니다. 의견 그리고 "스티븐 므누신 재무장관은 코로나19 팬데믹 이후 미국의 경제 회복은 수개월이 걸릴 것이라고 말했습니다."

시퀀스 = "미국 경제의 회복은 " \
 "코로나 바이러스 팬데믹은 몇 달 안에 끝날 것"이라고 " \
 "테조로 장관, 스티븐 므누신."
ner_model(시퀀스)
[{'entity': 'B-ORG', 'score': 0.9155661463737488, 'word': 'ĠEstados'},
 {'entity': 'I-ORG', 'score': 0.800682544708252, 'word': 'ĠUnidos'},
 {'entity': 'I-MISC', 'score': 0.5006815791130066, 'word': 'Ġcorona'},
 {'entity': 'I-MISC', 'score': 0.510674774646759, 'word': 'virus'},
 {'entity': 'B-PER', 'score': 0.5558510422706604, 'word': 'ĠSecretario'},
 {'entity': 'I-PER', 'score': 0.7758238315582275, 'word': 'Ġdel'},
 {'entity': 'I-PER', 'score': 0.7096233367919922, 'word': 'ĠTesoro'},
 {'entity': 'B-PER', 'score': 0.9940345883369446, 'word': 'ĠSteven'},
 {'entity': 'I-PER', 'score': 0.9962581992149353, 'word': 'ĠM'},
 {'entity': 'I-PER', 'score': 0.9918380379676819, 'word': 'n'},
 {'entity': 'I-PER', 'score': 0.9848328828811646, 'word': 'uch'},
 {'entity': 'I-PER', 'score': 0.8513168096542358, 'word': 'in'}]

멋지네요! 미세 조정된 모델은 예제에서 모든 엔티티를 성공적으로 인식하고 심지어 "코로나 바이러스"도 인식합니다.

결론영구 링크

명명된 개체 인식은 텍스트에서 중요한 정보를 빠르게 추출하는 데 도움이 될 수 있습니다. 따라서 비즈니스에 적용하면 계약서나 문서를 읽는 사람의 생산성 향상에 직접적인 영향을 미칠 수 있습니다. 그러나 NER은 단어 수준에서 정확한 분류가 필요하기 때문에 백오브워드와 같은 단순한 접근 방식으로는 이 작업을 처리할 수 없기 때문에 까다로운 NLP 작업입니다.

사전 학습된 BERT 모델을 활용하여 스페인어에 대한 NER 작업에서 우수한 성능을 빠르게 얻을 수 있는 방법을 살펴보았습니다. 사전 훈련된 SpanBERTa 모델은 문서 분류와 같은 다른 작업에도 미세 조정할 수 있습니다. 시퀀스 분류 및 감정 분석을 위해 BERT를 미세 조정하는 자세한 튜토리얼을 작성했습니다.

다음 시리즈에서는 최신 성능을 빠르게 달성할 수 있는 변압기 모델에 대한 보다 효율적인 사전 교육 접근 방식인 ELECTRA에 대해 설명합니다. 기대해주세요!

ko_KR한국어