Transformers documentation
생성 전략
생성 전략
디코딩 전략은 모델이 다음 생성 토큰을 선택하는 방식을 결정합니다. 디코딩 전략에는 다양한 유형이 있으며, 적절한 전략을 선택하는 것은 생성된 텍스트의 품질에 상당한 영향을 미칩니다.
이 가이드는 Transformers에서 사용할 수 있는 다양한 디코딩 전략과 이를 언제, 어떻게 사용하는지 이해하는 데 도움을 드립니다.
기본 디코딩 방법
이것들은 잘 확립된 디코딩 방법이며, 텍스트 생성 작업의 시작점으로 사용해야 합니다.
탐욕스러운 탐색
Greedy search는 기본 디코딩 전략입니다. 각 단계에서 가장 가능성이 높은 다음 토큰을 선택합니다. GenerationConfig에서 명시되지 않는 한, 이 전략은 최대 20개의 새 토큰을 생성합니다.
Greedy search는 창의성이 우선시되지 않는 비교적 짧은 출력을 생성하는 작업에서 잘 작동합니다. 그러나 더 긴 시퀀스를 생성할 때 스스로를 반복하기 시작하므로 성능이 저하됩니다.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator
device = Accelerator().device
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to default length because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=20)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that provides a suite of tools and services for building, deploying, and maintaining natural language processing'샘플링
Sampling, 또는 다항 분포 샘플링(multinomial sampling)은 가장 가능성이 높은 토큰을 선택하는 greedy search와 달리, 모델 전체 어휘에 대한 확률 분포를 기반으로 토큰을 무작위로 선택합니다. 이는 확률이 0이 아닌 모든 토큰이 선택될 수 있는 기회를 갖는다는 것을 의미합니다. 샘플링 전략은 반복을 줄이고 더 창의적이고 다양한 출력을 생성할 수 있습니다.
do_sample=True와 num_beams=1을 설정하여 다항샘플링을 활성화합니다.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator
device = Accelerator().device
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, do_sample=True, num_beams=1)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company 🤗\nWe are open-source and believe that open-source is the best way to build technology. Our mission is to make AI accessible to everyone, and we believe that open-source is the best way to achieve that.'Beam search
Beam search는 각 시간 단계에서 여러 생성된 시퀀스(beam)를 추적합니다. 특정 단계 수 이후에는 전체 확률이 가장 높은 시퀀스를 선택합니다. Greedy search와 달리, 이 전략은 초기 토큰의 확률이 낮더라도 전체적으로 더 높은 확률을 가진 시퀀스를 선택할 수 있도록 “앞을 내다볼” 수 있습니다. 이미지 설명이나 음성 인식과 같이 입력에 기반한 작업에 가장 적합합니다. do_sample=True를 beam search와 함께 사용하여 각 단계에서 샘플링할 수도 있지만, beam search는 여전히 단계 사이에 낮은 확률의 시퀀스를 greedy하게 제거합니다.
beam search visualizer를 확인하여 beam search가 어떻게 작동하는지 살펴보세요.
num_beams 매개변수를 사용하여 beam search를 활성화합니다(1보다 커야 하며, 그렇지 않으면 greedy search와 동일합니다).
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator
device = Accelerator().device
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, num_beams=2)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
"['Hugging Face is an open-source company that develops and maintains the Hugging Face platform, which is a collection of tools and libraries for building and deploying natural language processing (NLP) models. Hugging Face was founded in 2018 by Thomas Wolf']"사용자 정의 생성 방법
커스텀 생성 메서드를 사용하면 다음과 같은 특수한 동작을 활성화할 수 있습니다:
- 모델이 불확실한 경우 계속 생각하도록 합니다;
- 모델이 멈추면 생성을 되돌립니다;
- 커스텀 로직으로 특수 토큰을 처리합니다;
- 전용 KV 캐시를 사용하세요;
모델 저장소를 통해 사용자 정의 생성 방법을 활성화합니다. 이 기능은 특정 모델 태그와 파일 구조를 가정하며(아래 소절 참조), 사용자 정의 모델링 코드의 확장 기능입니다. 따라서 trust_remote_code=True를 설정해야 합니다.
모델 저장소에 커스텀 생성 방법이 포함된 경우, 이를 가장 쉽게 테스트하는 방법은 모델을 로드하고 해당 모델로 생성하는 것입니다:
from transformers import AutoModelForCausalLM, AutoTokenizer
# `transformers-community/custom_generate_example` holds a copy of `Qwen/Qwen2.5-0.5B-Instruct`, but
# with custom generation code -> calling `generate` uses the custom generation method!
tokenizer = AutoTokenizer.from_pretrained("transformers-community/custom_generate_example")
model = AutoModelForCausalLM.from_pretrained(
"transformers-community/custom_generate_example", device_map="auto", trust_remote_code=True
)
inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# The custom generation method is a minimal greedy decoding implementation. It also prints a custom message at run time.
gen_out = model.generate(**inputs)
# you should now see its custom message, "✨ using a custom generation method ✨"
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True))
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'커스텀 생성 방법을 가진 모델 저장소는 특별한 속성을 가지고 있습니다. generate()의 custom_generate 인수를 통해 어떤 모델에서도 해당 생성 방법을 로드할 수 있습니다. 이는 사용자가 추가적인 Python 패키지를 설치할 필요 없이, 누구나 커스텀 생성 방법을 만들어 공유하고 Transformers의 어떤 모델과도 함께 사용할 수 있음을 의미합니다.
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct", device_map="auto")
inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# `custom_generate` replaces the original `generate` by the custom generation method defined in
# `transformers-community/custom_generate_example`
gen_out = model.generate(**inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True)
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True)[0])
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'커스텀 생성 전략이 포함된 저장소의 README.md 파일을 읽어서 새로운 인자와 출력 형식의 차이가 있는지 확인해야 합니다. 차이가 없다면 기본 generate() 메서드와 동일하게 동작한다고 가정할 수 있습니다.
커스텀 태그인
custom_generate를 검색하여 모든 커스텀 생성 방법을 찾을 수 있습니다.
Hub 저장소 transformers-community/custom_generate_example를 예로 들어 보겠습니다. README.md에는 프롬프트 앞에 패딩 토큰을 추가하는 추가 입력 인자 left_padding가 있다고 명시되어 있습니다.
gen_out = model.generate(
**inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True, left_padding=5
)
print(tokenizer.batch_decode(gen_out)[0])
'<|endoftext|><|endoftext|><|endoftext|><|endoftext|><|endoftext|>The quick brown fox jumps over the lazy dog.\n\nThe sentence "The quick'커스텀 메서드에 현재 환경이 충족하지 못하는 고정된 Python 요구 사항이 있는 경우, 누락된 요구 사항에 대한 예외가 발생합니다. 예를 들어, transformers-community/custom_generate_bad_requirements는 custom_generate/requirements.txt 파일에 불가능한 요구 사항 집합이 정의되어 있으며, 이를 실행하려고 하면 아래 오류 메시지가 표시됩니다.
ImportError: Missing requirements in your local environment for `transformers-community/custom_generate_bad_requirements`: foo (installed: None) bar==0.0.0 (installed: None) torch>=99.0 (installed: 2.6.0)
Python 요구 사항을 이에 맞게 업데이트하면 이 오류 메시지가 제거됩니다.
커스텀 생성 방법 만들기
새로운 생성 방법을 만들려면 새로운 Model 저장소를 만들고 몇 가지 파일을 푸시해야 합니다.
- 생성 방법을 설계할 때 사용한 모델입니다.
custom_generate/generate.py에는 사용자 정의 생성 방식의 모든 로직이 포함되어 있습니다.custom_generate/requirements.txt는 해당 메서드를 올바르게 사용하기 위해 새로운 Python 요구 사항을 선택적으로 추가하고/또는 특정 버전을 고정하는 데 사용됩니다.README.md파일에는custom_generate태그를 추가하고, 커스텀 메서드의 새로운 인자나 출력 형식 차이를 여기에 문서화해야 합니다.
필요한 모든 파일을 추가한 후, 저장소는 다음과 같은 모습이어야 합니다
your_repo/
├── README.md # include the 'custom_generate' tag
├── config.json
├── ...
└── custom_generate/
├── generate.py
└── requirements.txt기본 모델 추가
사용자가 직접 구현한 생성 방식의 출발점은 다른 모델 저장소와 동일한 모델 저장소입니다. 이 저장소에 추가할 모델은 해당 생성 방식을 설계할 때 사용한 모델이어야 하며, 이는 작동하는 자체 완결형 모델-생성 쌍의 일부로 의도됩니다. 이 저장소의 모델이 로드되면, 사용자가 구현한 생성 방식이 generate를 오버라이드합니다. 걱정하지 마세요. 위 섹션에서 설명한 대로, 사용자의 생성 방식은 다른 어떤 Transformers 모델과도 함께 로드될 수 있습니다.
…
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("source/model_repo")
model = AutoModelForCausalLM.from_pretrained("source/model_repo")
tokenizer.save_pretrained("your/generation_method", push_to_hub=True)
model.save_pretrained("your/generation_method", push_to_hub=True)generate.py
이것은 생성 메서드의 핵심입니다. 반드시 generate라는 이름의 메서드를 포함해야 하며, 이 메서드는 첫 번째 인수로 model 인수를 반드시 포함해야 합니다. model은 모델 인스턴스이므로, GenerationMixin에 정의된 것(기본 generate 메서드 등)을 포함하여 모델의 모든 속성과 메서드에 접근할 수 있습니다.
generate.py는 저장소 루트 레벨이 아닌custom_generate라는 이름의 폴더에 배치해야 합니다. 이 기능의 파일 경로는 하드코딩되어 있습니다.
내부적으로, custom_generate 인수가 포함된 기본 generate() 메서드가 호출되면 먼저 Python 요구 사항(있는 경우)을 확인한 다음, generate.py에서 사용자 정의 generate 메서드를 찾은 뒤, 마지막으로 사용자 정의 generate를 호출합니다. 사용자 정의 생성을 트리거하는 인(trust_remote_code 및 custom_generate)을 제외한 모든 수신 인(model 포함)은 사용자 정의 generate 메서드로 전달됩니다.
이는 아래에 표시된 바와 같이 generate에 원래의 인자와 사용자 정의 인자(그리고 다른 출력 유형)가 혼합되어 있을 수 있음을 의미합니다.
import torch
def generate(model, input_ids, generation_config=None, left_padding=None, **kwargs):
generation_config = generation_config or model.generation_config # default to the model generation config
cur_length = input_ids.shape[1]
max_length = generation_config.max_length or cur_length + generation_config.max_new_tokens
# Example of custom argument: add `left_padding` (integer) pad tokens before the prompt
if left_padding is not None:
if not isinstance(left_padding, int) or left_padding < 0:
raise ValueError(f"left_padding must be an integer larger than 0, but is {left_padding}")
pad_token = kwargs.pop("pad_token", None) or generation_config.pad_token_id or model.config.pad_token_id
if pad_token is None:
raise ValueError("pad_token is not defined")
batch_size = input_ids.shape[0]
pad_tensor = torch.full(size=(batch_size, left_padding), fill_value=pad_token).to(input_ids.device)
input_ids = torch.cat((pad_tensor, input_ids), dim=1)
cur_length = input_ids.shape[1]
# Simple greedy decoding loop
while cur_length < max_length:
logits = model(input_ids).logits
next_token_logits = logits[:, -1, :]
next_tokens = torch.argmax(next_token_logits, dim=-1)
input_ids = torch.cat((input_ids, next_tokens[:, None]), dim=-1)
cur_length += 1
return input_ids커스텀 생성 방법이 의도대로 작동하도록 하기 위해 아래 권장 사항을 따르세요.
- 원본 generate()의 검증 및 입력 준비 로직을 자유롭게 재사용할 수 있습니다.
model의 비공개 메서드/속성을 사용하는 경우, requirements에transformers버전을 고정하세요.- 사용자가 자신의 환경에서 코드를 검증할 수 있도록 모델 검증, 입력 검증 또는 별도의 테스트 파일을 추가하는 것을 고려해 보세요.
사용자가 정의한 generate 메서드는 custom_generate 폴더에서 상대 경로로 코드를 가져올 수 있습니다. 예를 들어, utils.py 파일이 있는 경우 다음과 같이 가져올 수 있습니다:
from .utils import some_function같은 수준의 custom_generate 폴더에서 상대 경로로 가져오는 것만 지원됩니다. 상위/형제 폴더에서 가져오는 것은 유효하지 않습니다. custom_generate 인수는 custom_generate 구조를 포함하는 로컬의 어떤 디렉터리에서도 작동하며, 이는 사용자 정의 생성 방법을 개발하는 데 권장되는 워크플로입니다.
gen_out = model.generate(**inputs, custom_generate="path/to/local/dir", trust_remote_code=True)로컬 디렉터리를 로드해도
custom_generate/generate.py가 실행되므로, Hub 저장소와 마찬가지로trust_remote_code=True가 필요합니다. 직접 작성하거나 검토한 코드에 대해서만trust_remote_code=True를 전달하세요.
requirements.txt
custom_generate 폴더 안의 requirements.txt 파일에서 추가 Python 요구 사항을 선택적으로 지정할 수 있습니다. 이 요구 사항은 런타임에 확인되며, 누락된 항목이 있으면 예외가 발생하여 사용자가 환경을 적절히 업데이트하도록 안내합니다.
README.md
모델 저장소의 루트 레벨에 있는 README.md 파일은 일반적으로 해당 저장소에 포함된 모델에 대한 설명을 담고 있습니다. 그러나 이 저장소의 초점이 커스텀 생성 방식에 있으므로, 커스텀 생성 방식에 대한 설명으로 초점을 전환하는 것을 강력히 권장합니다. 방식에 대한 설명 외에도, 원래의 generate()와 다른 입력 및/또는 출력 사항이 있다면 이를 문서화하는 것을 권장합니다. 이렇게 하면 사용자는 새로운 부분에 집중할 수 있고, 일반적인 구현 세부 사항은 Transformers 문서에 의존할 수 있습니다.
검색 가능성을 높이기 위해 저장소에 custom_generate 태그를 추가하는 것을 강력히 권장합니다. 이를 위해 README.md 파일의 상단을 아래 예시와 같이 작성하세요. 파일을 push한 후 저장소에서 태그를 확인할 수 있습니다!
--- library_name: transformers tags: - custom_generate --- (your markdown content here)
권장 사항:
- generate()의 입력 및 출력 차이를 문서화합니다.
- 빠른 실험을 가능하도록 자체 완결형 예제를 추가합니다.
- 특정 모델 계열에서만 잘 작동하는지와 같은 소프트 요구 사항을 설명합니다.
generate의 입력 준비 재사용
새로운 디코딩 루프를 추가하는 경우, generate에 포함된 입력 준비 과정(배치 확장, 어텐션 마스크, 로짓 프로세서, 종료 조건 등)을 유지하는 것이 좋습니다. custom_generate에 callable을 전달하여 generate()의 전체 준비 파이프라인을 재사용하면서 디코딩 루프만 오버라이드할 수도 있습니다.
def custom_loop(model, input_ids, attention_mask, logits_processor, stopping_criteria, generation_config, **model_kwargs):
next_tokens = input_ids
while input_ids.shape[1] < stopping_criteria[0].max_length:
logits = model(next_tokens, attention_mask=attention_mask, **model_kwargs).logits
next_token_logits = logits_processor(input_ids, logits[:, -1, :])
next_tokens = torch.argmax(next_token_logits, dim=-1)[:, None]
input_ids = torch.cat((input_ids, next_tokens), dim=-1)
attention_mask = torch.cat((attention_mask, torch.ones_like(next_tokens)), dim=-1)
return input_ids
output = model.generate(
**inputs,
custom_generate=custom_loop,
max_new_tokens=10,
)
custom_generate저장소를 게시하면,generate구현 자체에서 콜러블(callable)을 정의하여model.generate()에 전달할 수 있습니다. 이를 통해 Transformers의 내장 입력 준비 로직의 이점을 유지하면서 디코딩 루프를 사용자 정의할 수 있습니다.
커스텀 생성 방법 찾기
커스텀 태그를 검색하여 모든 커스텀 생성 방법을 찾을 수 있습니다. custom_generate. 태그 외에도 custom_generate 방법의 컬렉션 두 가지를 큐레이션합니다:
- 커스텀 생성 방법 - 커뮤니티 — 커뮤니티에서 기여한 강력한 방법들의 모음;
- 커스텀 생성 방법 - 튜토리얼 — 이전에
transformers의 일부였던 방법들의 참조 구현 모음 및custom_generate튜토리얼.
리소스
공통 디코딩 전략이 작동하는 방식에 대한 설명은 텍스트 생성 방법: Transformers를 활용한 언어 생성을 위한 다양한 디코딩 메서드 사용 블로그 포스트를 참고하세요.
Update on GitHub