튜토리얼: 스페인어용 RoBERTa 언어 모델 훈련 방법

SpanBERTa: RoBERTa 스페인어 언어 모델을 처음부터 학습시킨 방법

    Skim AI의 머신러닝 연구 인턴인 크리스 트란이 처음 게시했습니다.



spanberta_pretraining_bert_from_scratch





Google Colab에서 실행

소개

트랜스포머 모델을 사용한 자가 학습 방법은 대부분의 NLP 작업에서 최첨단 성능을 달성했습니다. 그러나 훈련에는 계산 비용이 많이 들기 때문에 현재 사용 가능한 대부분의 사전 훈련된 트랜스포머 모델은 영어 전용입니다. 따라서 스페인어 프로젝트에서 NLP 작업의 성능을 개선하기 위해 저희 팀은 스키밍 AI 훈련하기로 결정했습니다. RoBERTa 스페인어용 언어 모델을 처음부터 새로 만들어서 SpanBERTa라고 부릅니다.

SpanBERTa는 RoBERTa-base와 크기가 동일합니다. RoBERTa의 훈련 스키마를 따라 18GB의 OSCAR의 스페인어 말뭉치를 4개의 테슬라 P100 GPU를 사용해 8일 만에 완성했습니다.

이 블로그 게시물에서는 다음을 사용하여 BERT와 유사한 언어 모델을 처음부터 학습하는 엔드투엔드 프로세스를 안내합니다. 트랜스포머토큰화 도구 라이브러리를 사용할 수 있습니다. 이 글의 코드를 직접 실행할 수 있는 Google Colab 노트북도 있습니다. 노트북을 적절히 수정하여 다른 언어에 대해 BERT와 유사한 모델을 훈련하거나 사용자 지정 데이터 세트에서 미세 조정할 수도 있습니다.

계속 진행하기 전에 모든 사람이 최첨단 NLP 모델을 이용할 수 있도록 해준 Hugging Face 팀에게 큰 감사를 표하고 싶습니다.

설정

1. 설치 종속성

0]에 입력합니다:

%pture
!.pip uninstall -y tensorflow
!.pip 설치 트랜스포머==2.8.0

2. 데이터

SpanBERTa를 다음과 같이 사전 교육했습니다. OSCAR의 스페인어 말뭉치를 사용했습니다. 데이터 세트의 전체 크기는 150GB이며, 이 중 18GB의 일부를 훈련에 사용했습니다.

이 예제에서는 간단하게 하기 위해 다음의 스페인어 영화 자막 데이터 집합을 사용하겠습니다. OpenSubtitles. 이 데이터 세트의 크기는 5.4GB이며 약 300MB의 하위 집합으로 학습할 것입니다.
0]에 입력합니다:

가져오기
# 영화 자막 데이터셋 다운로드 및 압축 풀기
os.path.exists('data/dataset.txt')가 아니라면:
  !.wget "https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2016/mono/es.txt.gz" -O dataset.txt.gz
  !.gzip -d dataset.txt.gz
  !.mkdir data
  !.mv dataset.txt 데이터
-2020-04-06 15:53:04-- https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2016/mono/es.txt.gz
object.pouta.csc.fi 확인 중 (object.pouta.csc.fi)... 86.50.254.18, 86.50.254.19
(object.pouta.csc.fi)|86.50.254.18|:443... 연결 중 (object.pouta.csc.fi)에 연결 중입니다.
HTTP 요청 전송, 응답 대기 중... 200 OK
길이: 1859673728 (1.7G) [application/gzip]
저장 위치: 'dataset.txt.gz'

dataset.txt.gz 100%[===================>] 1.73G 17.0MB/s in 1m 46s

2020-04-06 15:54:51 (16.8MB/s) - 'dataset.txt.gz' 저장 [1859673728/1859673728]

0]에 입력합니다:

# 총 회선 수 및 일부 임의 회선 수
!wc -l 데이터/데이터셋.txt
!shuf -n 5 데이터/데이터셋.txt
179287150 data/dataset.txt
제 생각에는 제 남편을 통해 싸울 수있는 더 많은 펠로트가 있다고 생각했습니다.
엘프와 오크의 모든 언어에 담긴 모든 매력을 느껴보세요.
이전에는 블루 블러드에서:
그리고 다니엘 스태포드와는 거래하지 않겠다고 약속하고 싶습니다.
웃겼어요.

0]에 입력합니다:

# 훈련용 첫 1,000,000줄의 하위 집합 가져오기
TRAIN_SIZE = 1000000 #@param {type:"integer"}
!(head -n $TRAIN_SIZE data/dataset.txt) > data/train.txt

0]에 입력합니다:

# 유효성 검사를 위해 다음 10,000줄의 하위 집합 가져오기
VAL_SIZE = 10000 #@param {type:"integer"}
!(sed -n {TRAIN_SIZE + 1},{TRAIN_SIZE + VAL_SIZE}p data/dataset.txt) > data/dev.txt

3. 토큰화 트레이닝

원래의 BERT 구현은 32K 개의 하위 단어 단위로 구성된 어휘를 가진 WordPiece 토큰화기를 사용합니다. 그러나 이 방법은 희귀 단어를 처리할 때 "알 수 없는" 토큰이 발생할 수 있습니다.

이 구현에서는 50,265개의 하위 단어 단위로 구성된 어휘를 가진 바이트 수준의 BPE 토큰화기를 사용합니다(RoBERTa-base와 동일). 바이트 수준의 BPE를 사용하면 "알 수 없는" 토큰 없이 모든 입력을 인코딩할 수 있는 적당한 크기의 하위 단어 어휘를 학습할 수 있습니다.

왜냐하면 바이트 레벨BPETokenizer 2개의 파일을 생성합니다. ["vocab.json", "merges.txt"] 동안 버트워드피스토큰라이저 파일 하나만 생성합니다. vocab.txt를 사용하면 오류가 발생합니다. 버트워드피스토큰라이저 를 사용하여 BPE 토큰화기의 출력을 로드합니다.
0]에 입력합니다:

%%타임
토큰화 도구에서 ByteLevelBPETokenizer를 가져옵니다.
경로 = "data/train.txt"
# 토큰화기를 초기화합니다.
토큰화기 = ByteLevelBPETokenizer()
# 트레이닝 사용자 지정
tokenizer.train(files=path,
                vocab_size=50265,
                min_frequency=2,
                special_tokens=["", "", "", "", ""]))
# 디스크에 파일 저장
!.mkdir -p "models/roberta"
tokenizer.save("models/roberta")
CPU 시간: 사용자 1분 37초, 시스템: 1.02초, 총 1분 38초
벽 시간: 1분 38초

매우 빠릅니다! 1,000만 회선을 훈련하는 데 2분밖에 걸리지 않습니다.

처음부터 트레이닝 언어 모델

1. 모델 아키텍처

RoBERTa는 BERT와 아키텍처가 완전히 동일합니다. 유일한 차이점은 다음과 같습니다:

  • RoBERTa는 더 큰 하위 단어 어휘(50,000개 대 32,000개)를 가진 바이트 수준의 BPE 토큰화기를 사용합니다.
  • RoBERTa는 동적 단어 마스킹을 구현하고 다음 문장 예측 작업을 삭제합니다.
  • RoBERTa의 트레이닝 하이퍼파라미터.

다른 아키텍처 구성은 문서에서 확인할 수 있습니다(RoBERTa, BERT).
0]에 입력합니다:

json 가져오기
config = {
    "아키텍처": [
        "RobertaForMaskedLM"
    ],
    "attention_probs_dropout_prob": 0.1,
    "hidden_act": "젤루",
    "hidden_dropout_prob": 0.1,
    "hidden_size": 768,
    "initializer_range": 0.02,
    "intermediate_size": 3072,
    "LAYER_NORM_EPS": 1e-05,
    "max_position_embedings": 514,
    "model_type": "로베르타",
    "num_attention_heads": 12,
    "num_hidden_layers": 12,
    "type_vocab_size": 1,
    "vocab_size": 50265
}
open("models/roberta/config.json", 'w') 를 fp로 사용합니다:
    json.dump(config, fp)
토큰화기_설정 = {"max_len": 512}
with open("models/roberta/tokenizer_config.json", 'w') as fp:
    json.dump(tokenizer_config, fp)

2. 교육 하이퍼파라미터

하이퍼파라미터 BERT 기반 RoBERTa-base
시퀀스 길이 128, 512 512
배치 크기 256 8K
최대 학습률 1e-4 6e-4
최대 걸음 수 1M 500K
워밍업 단계 10K 24K
무게 감소 0.01 0.01
아담 1TP4텝실론$ 1e-6 1e-6
Adam $beta_1$ 0.9 0.9
Adam $beta_2$ 0.999 0.98
그라데이션 클리핑 0.0 0.0

RoBERTa를 훈련할 때 배치 크기는 8000개입니다. 따라서 RoBERTa-base는 500만 걸음으로 훈련되었지만 훈련 계산 비용은 BERT-base의 16배에 달합니다. 에서 RoBERTa 종이를 통해 대규모 배치로 학습하면 최종 작업 정확도뿐만 아니라 마스크 언어 모델링 목표에 대한 난해성이 향상되는 것으로 나타났습니다. 다음을 조정하여 더 큰 배치 크기를 얻을 수 있습니다. 그라데이션_누적_단계.

계산상의 제약으로 인해 BERT-base의 훈련 스키마를 따라 8일 동안 4개의 Tesla P100 GPU를 사용하여 20만 단계에 걸쳐 SpanBERTa 모델을 훈련했습니다.

3. 교육 시작

다음을 사용하여 모델을 처음부터 훈련합니다. run_language_modeling.py에서 제공하는 스크립트를 사용하여 전처리, 말뭉치 토큰화 및 모델 학습을 수행합니다. 마스크 언어 모델링 작업을 수행합니다. 이 스크립트는 하나의 대규모 말뭉치에서 학습하도록 최적화되어 있습니다. 따라서 데이터 세트가 크고 이를 분할하여 순차적으로 훈련하려면 스크립트를 수정하거나 메모리가 많은 몬스터 머신을 구할 준비가 되어 있어야 합니다.
0]에 입력합니다:

# 업데이트 2020년 4월 22일: 허깅페이스가 run_language_modeling.py 스크립트를 업데이트했습니다.
# 업데이트 전에 이 버전을 사용하세요.
!.wget -c https://raw.githubusercontent.com/chriskhanhtran/spanish-bert/master/run_language_modeling.py
-2020-04-24 02:28:21-- https://raw.githubusercontent.com/chriskhanhtran/spanish-bert/master/run_language_modeling.py
raw.githubusercontent.com(raw.githubusercontent.com) 확인 중... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
연결 중 (raw.githubusercontent.com)|151.101.0.133|:443... 연결됨.
HTTP 요청 전송, 응답 대기 중... 200 OK
길이: 34328 (34K) [텍스트/일반]
저장하는 중 'run_language_modeling.py'

run_language_modeli 100%[===================>] 33.52K --.-KB/s in 0.003s

2020-04-24 02:28:21 (10.1 MB/s) - 'run_language_modeling.py' 저장 [34328/34328]

중요 인수

  • --LINE_BY_LINE 데이터 세트의 고유한 텍스트 줄을 고유한 시퀀스로 처리할지 여부입니다. 데이터 세트의 각 줄이 길고 토큰이 최대 512개 이상인 경우 이 설정을 사용해야 합니다. 각 줄이 짧은 경우, 기본 텍스트 전처리는 모든 줄을 연결하고 토큰화하여 토큰화된 출력을 512개의 토큰 블록으로 분할합니다. 데이터 세트를 작은 덩어리로 분할하여 개별적으로 사전 처리할 수도 있습니다. 3GB의 텍스트는 기본값으로 처리하는 데 약 50분이 소요됩니다. 텍스트 데이터 세트 클래스.
  • --should_continue output_dir의 최신 체크포인트에서 계속할지 여부입니다.
  • --모델_이름_또는_경로 가중치 초기화를 위한 모델 체크포인트입니다. 모델을 처음부터 학습시키려면 없음으로 둡니다.
  • --mlm 언어 모델링 대신 마스킹된 언어 모델링 손실로 학습합니다.
  • --config_name, --tokenizer_name 모델_이름_또는_경로와 같지 않은 경우 사전 학습된 구성 및 토큰화기 이름 또는 경로(선택 사항). 둘 다 None인 경우 새 구성을 초기화합니다.
  • --per_gpu_train_batch_size 트레이닝을 위한 GPU/CPU당 배치 크기. GPU에 맞출 수 있는 가장 큰 숫자를 선택하세요. 배치 크기가 너무 크면 오류가 표시됩니다.
  • --gradient_accumulation_steps 뒤로/업데이트 패스를 수행하기 전에 누적할 업데이트 단계 수입니다. 이 트릭을 사용하여 배치 크기를 늘릴 수 있습니다. 예를 들어 다음과 같은 경우 per_gpu_train_batch_size = 16gradient_accumulation_steps = 4를 입력하면 총 열차 배치 크기는 64가 됩니다.
  • --overwrite_output_dir 출력 디렉터리의 콘텐츠를 덮어씁니다.
  • --no_cuda, --fp16, --fp16_opt_level GPU/CPU 트레이닝을 위한 인수입니다.
  • 다른 인수는 모델 경로와 학습 하이퍼파라미터입니다.

스크립트에서는 모델 경로에 모델 유형(예: "roberta", "bert", "gpt2" 등)을 포함할 것을 적극 권장합니다. 자동 모델 클래스를 사용하여 제공된 경로에서 패턴 매칭을 사용하여 모델의 구성을 추측합니다.
0]에 입력합니다:

# 모델 경로
MODEL_TYPE = "roberta" #@param ["roberta", "bert"]
MODEL_DIR = "models/roberta" #@param {type: "문자열"}
OUTPUT_DIR = "models/roberta/output" #@param {type: "문자열"}
TRAIN_PATH = "data/train.txt" #@param {type: "문자열"}
EVAL_PATH = "data/dev.txt" #@param {type: "문자열"}

이 예제에서는 Colab에서 제공하는 Tesla P4 GPU를 사용하여 25단계만 훈련하겠습니다.
0]에 입력합니다:

!.nvidia-smi
월 Apr 6 15:59:35 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.64.00 드라이버 버전: 418.67 CUDA 버전: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU 이름 지속성-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| 팬 온도 퍼프 Pwr:사용량/캡| 메모리 사용량 | GPU-Util Compute M. |
|===============================+======================+======================|
0 Tesla P4 Off | 00000000:00:04.0 Off | 0 | |
| N/A 31C P8 7W / 75W | 0MiB / 7611MiB | 0% 기본값 |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| 프로세스:                                                       GPU 메모리 |
| GPU PID 유형 프로세스 이름 사용 |
|=============================================================================|
실행 중인 프로세스 없음 | |
+-----------------------------------------------------------------------------+

0]에 입력합니다:

# 명령줄
cmd = """python run_language_modeling.py
    --output_dir {output_dir}
    --model_type {model_type}
    --mlm
    --config_name {config_name}
    --tokenizer_name {토큰라이저_이름}
    {line_by_line}
    {SHOULD_CONTINUE}
    {모델_이름_또는_경로}
    --train_data_file {train_path}
    --eval_data_파일 {eval_path}
    --do_train
    {do_eval}
    {evaluate_during_training}
    --overwrite_output_dir
    --block_size 512
    --max_step 25
    --warmup_steps 10
    --learning_rate 5e-5
    --per_gpu_train_batch_size 4
    --gradient_accumulation_steps 4
    --weight_decay 0.01
    --아담_엡실론 1e-6
    --max_grad_norm 100.0
    --save_total_limit 10
    --save_steps 10
    --logging_steps 2
    --seed 42
"""

0]에 입력합니다:

# 처음부터 훈련을 위한 인수. 평가_중_훈련을 끕니다,
# line_by_line, should_continue, model_name_or_path를 끕니다.
train_params = {
    "output_dir": OUTPUT_DIR,
    "model_type": MODEL_TYPE,
    "config_name": MODEL_DIR,
    "토큰화기_이름": MODEL_DIR,
    "train_path": TRAIN_PATH,
    "EVAL_PATH": EVAL_PATH,
    "do_eval": "--do_eval",
    "evaluate_during_training": "",
    "LINE_BY_LINE": "",
    "SHOULD_CONTINUE": "",
    "모델_이름_또는_경로": "",
}

가상 머신에서 교육하는 경우 텐서보드를 설치하여 교육 과정을 모니터링할 수 있습니다. 여기 텐서보드 스팬버타 교육용.

pip install tensorboard==2.1.0
tensorboard dev upload --logdir runs

20만 걸음 후 손실은 1.8, 당혹감은 5.2에 달했습니다.

이제 교육을 시작하겠습니다!
In [ ]:

!{cmd.format(**train_params)}
    04/06/2020 15:59:55 - INFO - __main__ - 데이터에서 데이터 세트 파일에서 기능 만들기
    04/06/2020 16:04:43 - INFO - __main__ - 캐시된 파일 data/roberta_cached_lm_510_train.txt에 기능 저장 중
    04/06/2020 16:04:46 - INFO - __main__ - ***** 트레이닝 실행 *****
    04/06/2020 16:04:46 - INFO - __main__ - 예제 수 = 165994
    04/06/2020 16:04:46 - INFO - __main__ - Num Epochs = 1
    04/06/2020 16:04:46 - INFO - __main__ - GPU당 순간 배치 크기 = 4
    04/06/2020 16:04:46 - INFO - __main__ - 총 트레인 배치 크기(병렬, 분산 및 누적 포함) = 16
    04/06/2020 16:04:46 - INFO - __main__ - 그라데이션 누적 단계 = 4
    04/06/2020 16:04:46 - INFO - __main__ - 총 최적화 단계 = 25
    에포크: 0% 0/1 [00:00<?, ?it/s]
    반복:   0% 0/41499 [00:00<?, ?it/s]
    반복   0% 1/41499 [00:01<13:18:02, 1.15s/it]
    반복:   0% 2/41499 [00:01<11:26:47, 1.01it/s]
    반복:   0% 3/41499 [00:02<10:10:30, 1.13it/s]
    반복   0% 4/41499 [00:03<9:38:10, 1.20it/s]
    반복   0% 5/41499 [00:03<8:52:44, 1.30it/s]
    반복   0% 6/41499 [00:04<8:22:47, 1.38it/s]
    반복:   0% 7/41499 [00:04<8:00:55, 1.44it/s]
    반복:   0% 8/41499 [00:05<8:03:40, 1.43it/s]
    반복:   0% 9/41499 [00:06<7:46:57, 1.48it/s]
    반복:   0% 10/41499 [00:06<7:35:35, 1.52it/s]
    반복:   0% 11/41499 [00:07<7:28:29, 1.54it/s]
    반복:   0% 12/41499 [00:08<7:41:41, 1.50it/s]
    반복   0% 13/41499 [00:08<7:34:28, 1.52it/s]
    반복:   0% 14/41499 [00:09<7:28:46, 1.54it/s]
    반복:   0% 15/41499 [00:10<7:23:29, 1.56it/s]
    반복   0% 16/41499 [00:10<7:38:06, 1.51it/s]
    반복:   0% 17/41499 [00:11<7:29:13, 1.54it/s]
    반복:   0% 18/41499 [00:12<7:24:04, 1.56it/s]
    반복:   0% 19/41499 [00:12<7:21:59, 1.56it/s]
    반복:   0% 20/41499 [00:13<7:38:06, 1.51it/s]
    04/06/2020 16:06:23 - INFO - __main__ - ***** 실행 평가 *****
    04/06/2020 16:06:23 - INFO - __main__ - 예제 수 = 156
    04/06/2020 16:06:23 - INFO - __main__ - 배치 크기 = 4
    평가 중입니다: 100% 39/39 [00:08<00:00, 4.41it/s]
    04/06/2020 16:06:32 - INFO - __main__ - ***** 평가 결과 *****
    04/06/2020 16:06:32 - INFO - __main__ - perplexity = tensor(6077.6812)

4. 마스크된 단어 예측

언어 모델을 학습한 후에는 모델을 업로드하고 커뮤니티와 공유할 수 있습니다. SpanBERTa 모델을 Hugging Face 서버에 업로드했습니다. 다운스트림 작업에서 모델을 평가하기 전에 모델이 주어진 문맥에서 가려진 단어를 채우는 방법을 어떻게 학습했는지 살펴봅시다.
0]에 입력합니다:

%%캡쳐
%%시간
트랜스포머에서 파이프라인 가져오기
fill_mask = 파이프라인(
    "fill-mask",
    model="chriskhanhtran/spanberta",
    tokenizer="chriskhanhtran/spanberta"
)

코로나19에 관한 Wikipedia의 기사에서 한 문장을 골라봅니다.

원래 문장은 "물과 젓가락으로 손을 자주 씻으세요," 의미 "비누와 물로 손을 자주 씻으세요."

마스크된 단어는 "자본"(비누) 상위 5가지 예측은 다음과 같습니다. 비누, 소금, 스팀, 레몬식초. 모델이 박테리아를 죽이거나 산을 함유 할 수있는 물건으로 손을 씻어야한다는 것을 어떻게 든 배운다는 것이 흥미 롭습니다.
0]에 입력합니다:

fill_mask("물과 로 손을 자주 닦아주세요.")

Out[0]:

[{'score': 0.6469631195068359,
  'sequence': ' 물과 젓가락으로 손을 자주 씻으십시오.',
  'token': 18493},
 {'score': 0.06074320897459984,
  'sequence': ' 물과 소금으로 손을 자주 씻으십시오.',
  '토큰': 619},
 {'score': 0.029787985607981682,
  'sequence': ' 물과 증기로 손을 자주 씻으십시오.',
  'token': 11079},
 {'score': 0.026410052552819252,
  'sequence': ' 물과 레몬으로 손을 자주 씻으십시오.',
  'token': 12788},
 {'score': 0.017029203474521637,
  'sequence': ' 물과 소금으로 손을 자주 씻으십시오.',
  'token': 18424}]

결론

스페인어에 대한 BERT 언어 모델을 처음부터 훈련하는 방법을 살펴보고, 주어진 문맥에서 마스크된 단어를 예측하여 모델이 언어의 속성을 학습하는 것을 확인했습니다. 이 문서에 따라 사용자 지정 데이터 세트에서 미리 학습된 BERT와 유사한 모델을 미세 조정할 수도 있습니다.

다음으로 시퀀스 분류, NER, POS 태깅, NLI를 포함한 다운스트림 작업에서 사전 학습된 모델을 구현하고 모델의 성능을 일부 비-BERT 모델과 비교해 보겠습니다.

다음 포스팅도 기대해주세요!

아이디어를 논의해 보세요

    관련 게시물

    비즈니스를 강화할 준비 완료

    LET'S
    TALK
    ko_KR한국어