Transformers documentation

Causal language modeling

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Causal language modeling

언어 모델링에는 causal과 masked의 두 가지 유형이 있습니다. 이 가이드에서는 causal language modeling을 다룹니다. Causal language model은 텍스트 생성에 자주 사용됩니다. 이러한 모델은 선택형 텍스트 어드벤처나 Copilot, CodeParrot와 같은 지능형 코딩 어시스턴트와 같은 창의적인 애플리케이션에 활용할 수 있습니다.

Causal language modeling은 토큰 시퀀스에서 다음 토큰을 예측하며, 모델은 왼쪽에 있는 토큰에만 attend할 수 있습니다. 즉, 모델은 미래의 토큰을 볼 수 없습니다. GPT-2는 causal language model의 예입니다.

이 가이드에서는 다음 내용을 보여 드립니다:

  1. ELI5 데이터셋의 r/askscience 하위 집합에서 DistilGPT2를 파인튜닝합니다.
  2. 파인튜닝한 모델을 추론에 사용하세요.

이 작업과 호환되는 모든 아키텍처와 체크포인트를 확인하려면 task-page를 확인하는 것을 권장합니다.

시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:

pip install transformers datasets evaluate

모델을 업로드하여 커뮤니티와 공유할 수 있도록 Hugging Face 계정에 로그인하는 것을 권장합니다. 프롬프트가 표시되면 토큰을 입력하여 로그인하세요:

>>> from huggingface_hub import notebook_login

>>> notebook_login()

ELI5 데이터셋 로드

datasets 라이브러리를 사용하여 ELI5-Category 데이터셋의 첫 5000개 예시를 로드하는 것으로 시작합니다. 이렇게 하면 전체 데이터셋으로 더 많은 시간을 들여 학습하기 전에 실험을 해보고 모든 것이 정상적으로 작동하는지 확인할 수 있습니다.

>>> from datasets import load_dataset

>>> eli5 = load_dataset("dany0407/eli5_category", split="train[:5000]")

데이터셋의 train 스플릿을 train_test_split 메서드를 사용하여 학습 세트와 테스트 세트로 분리합니다:

>>> eli5 = eli5.train_test_split(test_size=0.2)

다음은 예시입니다:

>>> eli5["train"][0]
{'q_id': '7h191n',
 'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
 'selftext': '',
 'category': 'Economics',
 'subreddit': 'explainlikeimfive',
 'answers': {'a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
  'text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
   'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
   'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
   'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
  'score': [21, 19, 5, 3],
  'text_urls': [[],
   [],
   [],
   ['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']]},
 'title_urls': ['url'],
 'selftext_urls': ['url']}

이것은 많아 보일 수 있지만, 실제로는 text 필드만 관심 있으면 됩니다. 언어 모델링 작업의 멋진 점은 라벨이 필요 없다는 것입니다(무감독 작업이라고도 함). 다음 단어 가 바로 라벨이기 때문입니다.

전처리

다음 단계는 text 하위 필드를 처리하기 위해 DistilGPT2 토크나이저를 로드하는 것입니다:

>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilgpt2")

위 예시에서 text 필드가 실제로는 answers 안에 중첩되어 있음을 확인할 수 있습니다. 따라서 flatten 메서드를 사용하여 중첩 구조에서 text 하위 필드를 추출해야 합니다:

>>> eli5 = eli5.flatten()
>>> eli5["train"][0]
{'q_id': '7h191n',
 'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
 'selftext': '',
 'category': 'Economics',
 'subreddit': 'explainlikeimfive',
 'answers.a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
 'answers.text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
  'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
  'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
  'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
 'answers.score': [21, 19, 5, 3],
 'answers.text_urls': [[],
  [],
  [],
  ['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']],
 'title_urls': ['url'],
 'selftext_urls': ['url']}

각 하위 필드는 answers 접두어에 표시된 대로 이제 별도의 열이 되었고, text 필드는 이제 리스트입니다. 각 문장을 개별적으로 토큰화하는 대신, 리스트를 문자열로 변환하여 함께 토큰화할 수 있도록 하세요.

각 예시별로 문자열 목록을 결합하고 결과를 토큰화하는 첫 번째 전처리 함수를 소개합니다:

>>> def preprocess_function(examples):
...     return tokenizer([" ".join(x) for x in examples["answers.text"]])

이 전처리 함수를 데이터셋 전체에 적용하려면 🤗 Datasets의 map 메서드를 사용합니다. map 함수에서 batched=True를 설정하여 데이터셋의 여러 요소를 한 번에 처리하고, num_proc로 프로세스 수를 늘리면 속도를 높일 수 있습니다. 필요하지 않은 열은 제거하세요:

>>> tokenized_eli5 = eli5.map(
...     preprocess_function,
...     batched=True,
...     num_proc=4,
...     remove_columns=eli5["train"].column_names,
... )

이 데이터셋에는 토큰 시퀀스가 포함되어 있지만, 일부 시퀀스는 모델의 최대 입력 길이를 초과합니다.

이제 두 번째 전처리 함수를 사용하여

  • 모든 시퀀스를 연결
  • block_size로 정의된 더 짧은 청크로 연결된 시퀀스를 분할합니다. 이 값은 최대 입력 길이보다 짧아야 하며, GPU RAM에 적합할 정도로 충분히 작아야 합니다.
>>> block_size = 128


>>> def group_texts(examples):
...     # Concatenate all texts.
...     concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
...     total_length = len(concatenated_examples[list(examples.keys())[0]])
...     # We drop the small remainder, we could add padding if the model supported it instead of this drop, you can
...     # customize this part to your needs.
...     if total_length >= block_size:
...         total_length = (total_length // block_size) * block_size
...     # Split by chunks of block_size.
...     result = {
...         k: [t[i : i + block_size] for i in range(0, total_length, block_size)]
...         for k, t in concatenated_examples.items()
...     }
...     result["labels"] = result["input_ids"].copy()
...     return result

전체 데이터셋에 group_texts 함수를 적용합니다:

>>> lm_dataset = tokenized_eli5.map(group_texts, batched=True, num_proc=4)

이제 DataCollatorForLanguageModeling를 사용하여 예시 배치(batch)를 생성합니다. 데이터셋 전체를 최대 길이에 맞게 패딩하는 대신, collation 단계에서 배치 내 가장 긴 길이에 맞춰 문장을 동적으로 패딩하는 것이 더 효율적입니다.

시퀀스 종료 토큰을 패딩 토큰으로 사용하고 mlm=False를 설정합니다. 이렇게 하면 입력이 1개 요소만큼 오른쪽으로 이동된 라벨로 사용됩니다:

>>> from transformers import DataCollatorForLanguageModeling

>>> tokenizer.pad_token = tokenizer.eos_token
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)

학습

Trainer를 사용하여 모델을 fine-tuning하는 방법에 익숙하지 않다면 기본 튜토리얼을 참고하세요!

이제 모델 학습을 시작할 준비가 되었습니다! AutoModelForCausalLM으로 DistilGPT2를 로드하세요:

>>> from transformers import AutoModelForCausalLM, TrainingArguments, Trainer

>>> model = AutoModelForCausalLM.from_pretrained("distilbert/distilgpt2")

이 시점에서 남은 단계는 단 세 가지입니다:

  1. TrainingArguments에서 학습 하이퍼파라미터를 정의합니다. 필수 파라미터는 모델 저장 위치를 지정하는 output_dir 하나뿐입니다. push_to_hub=True를 설정하여 모델을 Hub에 업로드할 수 있습니다(모델 업로드를 위해 Hugging Face에 로그인되어 있어야 합니다).
  2. 모델, 데이터셋, 데이터 콜레이터와 함께 학습 인수를 Trainer에 전달합니다.
  3. 모델을 파인튜닝하려면 train()을 호출하세요.
>>> training_args = TrainingArguments(
...     output_dir="my_awesome_eli5_clm-model",
...     eval_strategy="epoch",
...     learning_rate=2e-5,
...     weight_decay=0.01,
...     push_to_hub=True,
... )

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

>>> trainer.train()

학습이 완료되면 evaluate() 메서드를 사용하여 모델을 평가하고 그 perplexity를 확인합니다:

>>> import math

>>> eval_results = trainer.evaluate()
>>> print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
Perplexity: 49.61

그런 다음 push_to_hub() 메서드를 사용하여 모델을 Hub에 공유하여 누구나 모델을 사용할 수 있도록 하세요:

>>> trainer.push_to_hub()

causal language modeling을 위해 모델을 finetune하는 방법에 대한 더 자세한 예제는 해당 PyTorch notebook을 참고하세요.

추론

좋습니다. 이제 모델을 fine-tuning 했으므로 추론에 사용할 수 있습니다!

텍스트 생성을 위해 원하는 프롬프트를 작성해 보세요:

>>> prompt = "Somatic hypermutation allows the immune system to"

파인튜닝한 모델을 추론에 적용해 보는 가장 간단한 방법은 pipeline()을 사용하는 것입니다. 해당 모델로 텍스트 생성용 pipeline을 인스턴스화한 후, 텍스트를 전달하세요:

>>> from transformers import pipeline

>>> generator = pipeline("text-generation", model="username/my_awesome_eli5_clm-model")
>>> generator(prompt)
[{'generated_text': "Somatic hypermutation allows the immune system to be able to effectively reverse the damage caused by an infection.\n\n\nThe damage caused by an infection is caused by the immune system's ability to perform its own self-correcting tasks."}]

텍스트를 토큰화하고 input_ids를 PyTorch 텐서로 반환합니다:

>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_eli5_clm-model")
>>> inputs = tokenizer(prompt, return_tensors="pt").input_ids

generate() 메서드를 사용하여 텍스트를 생성합니다. 다양한 텍스트 생성 전략 및 생성을 제어하는 매개변수에 대한 자세한 내용은 Text generation strategies 페이지를 참고하세요.

>>> from transformers import AutoModelForCausalLM

>>> model = AutoModelForCausalLM.from_pretrained("username/my_awesome_eli5_clm-model")
>>> outputs = model.generate(inputs, max_new_tokens=100, do_sample=True, top_k=50, top_p=0.95)

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

>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
["Somatic hypermutation allows the immune system to react to drugs with the ability to adapt to a different environmental situation. In other words, a system of 'hypermutation' can help the immune system to adapt to a different environmental situation or in some cases even a single life. In contrast, researchers at the University of Massachusetts-Boston have found that 'hypermutation' is much stronger in mice than in humans but can be found in humans, and that it's not completely unknown to the immune system. A study on how the immune system"]
Update on GitHub