번역

번역 (Translation)

번역은 한 언어의 텍스트 시퀀스를 다른 언어로 변환하는 작업이에요. 입력에서 출력을 만들어 내는 강력한 프레임워크인 시퀀스-투-시퀀스(sequence-to-sequence) 문제로 다룰 수 있는 여러 작업 중 하나로, 번역이나 요약처럼 활용돼요. 번역 시스템은 서로 다른 언어의 텍스트 사이 번역에 흔히 쓰이지만, 음성이나 그 중간의 조합(예: 텍스트-투-스피치 또는 스피치-투-텍스트)에도 쓰일 수 있어요.

출처: 문서

본문

이 가이드에서는 다음을 배워요:

  1. OPUS Books 데이터셋의 영어-프랑스어 하위 집합에서 T5를 파인튜닝해서 영어 텍스트를 프랑스어로 번역하기.
  2. 파인튜닝한 모델을 추론(inference)에 사용하기.

이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 task-page를 확인하는 걸 추천해요.

시작하기 전에 필요한 라이브러리를 모두 설치했는지 확인해요:

pip install transformers datasets evaluate sacrebleu

Hugging Face 계정에 로그인해서 모델을 커뮤니티에 업로드하고 공유하는 걸 권장해요. 로그인하라는 메시지가 나오면 토큰을 입력해서 로그인하세요:

>>> from huggingface_hub import notebook_login

>>> notebook_login()

OPUS Books 데이터셋 로드

먼저 🤗 Datasets 라이브러리에서 OPUS Books 데이터셋의 영어-프랑스어 하위 집합을 로드해요:

>>> from datasets import load_dataset

>>> books = load_dataset("opus_books", "en-fr")

train_test_split 메서드로 데이터셋을 훈련용과 테스트용으로 나눠요:

>>> books = books["train"].train_test_split(test_size=0.2)

그다음 예시 하나를 살펴봐요:

>>> books["train"][0]
{'id': '90560',
 'translation': {'en': 'But this lofty plateau measured only a few fathoms, and soon we reentered Our Element.',
  'fr': 'Mais ce plateau élevé ne mesurait que quelques toises, et bientôt nous fûmes rentrés dans notre élément.'}}

translation: 텍스트의 영어와 프랑스어 번역.

전처리

다음 단계는 영어-프랑스어 언어 쌍을 처리할 T5 토크나이저를 로드하는 거예요:

>>> from transformers import AutoTokenizer

>>> checkpoint = "google-t5/t5-small"
>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)

만들려는 전처리 함수는 다음을 해야 해요:

  1. 입력 앞에 프롬프트를 붙여서 T5가 이게 번역 작업임을 알게 해요. 여러 NLP 작업을 처리할 수 있는 일부 모델은 특정 작업을 위해 프롬프트가 필요해요.
  2. text_target 파라미터에 목표 언어(프랑스어)를 설정해서 토크나이저가 목표 텍스트를 올바르게 처리하도록 해요. text_target을 설정하지 않으면 토크나이저가 목표 텍스트를 영어로 처리해요.
  3. 시퀀스가 max_length 파라미터로 설정한 최대 길이를 넘지 않도록 자르는 것.
>>> source_lang = "en"
>>> target_lang = "fr"
>>> prefix = "translate English to French: "

>>> def preprocess_function(examples):
...     inputs = [prefix + example[source_lang] for example in examples["translation"]]
...     targets = [example[target_lang] for example in examples["translation"]]
...     model_inputs = tokenizer(inputs, text_target=targets, max_length=128, truncation=True)
...     return model_inputs

전처리 함수를 전체 데이터셋에 적용하려면 🤗 Datasets의 map 메서드를 사용해요. batched=True를 설정하면 데이터셋의 여러 요소를 한 번에 처리할 수 있어서 map 함수를 빠르게 할 수 있어요:

>>> tokenized_books = books.map(preprocess_function, batched=True)

이제 DataCollatorForSeq2Seq를 사용해 예시 배치를 만들어요. 콜레이션(collation) 과정에서 데이터셋 전체를 최대 길이로 패딩하는 것보다 배치 안의 문장들을 가장 긴 길이에 맞춰 동적으로 패딩하는 편이 더 효율적이에요.

>>> from transformers import DataCollatorForSeq2Seq

>>> data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model=checkpoint)

평가

학습 중에 메트릭을 포함하면 모델의 성능을 평가하는 데 종종 도움이 돼요. 🤗 Evaluate 라이브러리로 평가 방법을 빠르게 로드할 수 있어요. 이 작업에서는 SacreBLEU 메트릭을 로드해요 (메트릭을 로드하고 계산하는 방법은 🤗 Evaluate quick tour를 참고하세요):

>>> import evaluate

>>> metric = evaluate.load("sacrebleu")

그다음 예측값과 라벨을 compute에 넘겨 SacreBLEU 점수를 계산하는 함수를 만들어요:

>>> import numpy as np

>>> def postprocess_text(preds, labels):
...     preds = [pred.strip() for pred in preds]
...     labels = [[label.strip()] for label in labels]

...     return preds, labels

>>> def compute_metrics(eval_preds):
...     preds, labels = eval_preds
...     if isinstance(preds, tuple):
...         preds = preds[0]
...     decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True)

...     labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
...     decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)

...     decoded_preds, decoded_labels = postprocess_text(decoded_preds, decoded_labels)

...     result = metric.compute(predictions=decoded_preds, references=decoded_labels)
...     result = {"bleu": result["score"]}

...     prediction_lens = [np.count_nonzero(pred != tokenizer.pad_token_id) for pred in preds]
...     result["gen_len"] = np.mean(prediction_lens)
...     result = {k: round(v, 4) for k, v in result.items()}
...     return result

이제 compute_metrics 함수를 쓸 준비가 됐어요. 학습을 설정할 때 다시 사용하게 될 거예요.

학습

Trainer로 모델을 파인튜닝하는 방법에 익숙하지 않다면 여기의 기본 튜토리얼을 확인해 보세요!

이제 모델 학습을 시작할 준비가 됐어요! T5를 AutoModelForSeq2SeqLM으로 로드해요:

>>> from transformers import AutoModelForSeq2SeqLM, Seq2SeqTrainingArguments, Seq2SeqTrainer

>>> model = AutoModelForSeq2SeqLM.from_pretrained(checkpoint)

이 시점에서 남은 단계는 세 가지뿐이에요:

  1. Seq2SeqTrainingArguments에서 학습 하이퍼파라미터를 정의해요. 유일하게 필수인 파라미터는 모델을 저장할 위치를 지정하는 output_dir이에요. push_to_hub=True로 설정하면 모델을 Hub에 푸시할 수 있어요 (모델을 업로드하려면 Hugging Face에 로그인해야 해요). 각 에폭이 끝날 때마다 Trainer가 SacreBLEU 메트릭을 평가하고 학습 체크포인트를 저장해요.
  2. 학습 인수를 Seq2SeqTrainer에 모델, 데이터셋, 토크나이저, 데이터 콜레이터, compute_metrics 함수와 함께 전달해요.
  3. train()을 호출해서 모델을 파인튜닝해요.
>>> training_args = Seq2SeqTrainingArguments(
...     output_dir="my_awesome_opus_books_model",
...     eval_strategy="epoch",
...     learning_rate=2e-5,
...     per_device_train_batch_size=16,
...     per_device_eval_batch_size=16,
...     weight_decay=0.01,
...     save_total_limit=3,
...     num_train_epochs=2,
...     predict_with_generate=True,
...     fp16=True, #change to bf16=True for XPU
...     push_to_hub=True,
... )

>>> trainer = Seq2SeqTrainer(
...     model=model,
...     args=training_args,
...     train_dataset=tokenized_books["train"],
...     eval_dataset=tokenized_books["test"],
...     processing_class=tokenizer,
...     data_collator=data_collator,
...     compute_metrics=compute_metrics,
... )

>>> trainer.train()

학습이 완료되면 push_to_hub() 메서드로 모델을 Hub에 공유해서 모두가 쓸 수 있게 해요:

>>> trainer.push_to_hub()

번역용으로 모델을 파인튜닝하는 더 심층적인 예시는 해당 PyTorch notebook을 참고하세요.

추론 (Inference)

좋아요, 이제 모델을 파인튜닝했으니 추론에 활용할 수 있어요!

다른 언어로 번역하고 싶은 텍스트를 하나 떠올려요. T5의 경우 작업에 따라 입력에 프롬프트를 붙여야 해요. 영어에서 프랑스어로 번역할 때는 아래처럼 입력에 프롬프트를 붙이세요:

>>> text = "translate English to French: Legumes share resources with nitrogen-fixing bacteria."

텍스트를 토크나이즈하고 input_ids를 PyTorch 텐서로 반환해요:

>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_opus_books_model")
>>> inputs = tokenizer(text, return_tensors="pt").input_ids

generate() 메서드를 사용해 번역을 만드세요. 다양한 텍스트 생성 전략과 생성을 제어하는 파라미터에 대한 자세한 내용은 Text Generation API를 확인해 보세요.

>>> from transformers import AutoModelForSeq2SeqLM

>>> model = AutoModelForSeq2SeqLM.from_pretrained("username/my_awesome_opus_books_model")
>>> outputs = model.generate(inputs, max_new_tokens=40, do_sample=True, top_k=30, top_p=0.95)

생성된 토큰 id를 다시 텍스트로 디코딩해요:

>>> tokenizer.decode(outputs[0], skip_special_tokens=True)
'Les lignées partagent des ressources avec des bactéries enfixant l'azote.'