# 텍스트 생성

텍스트 생성은 대규모 언어 모델(LLM)의 가장 인기 있는 응용 분야입니다. LLM은 초기 텍스트(프롬프트)와 모델이 자체적으로 생성한 출력을 기반으로, 미리 정의된 길이에 도달하거나 시퀀스 종료(`EOS`) 토큰을 만나기까지 다음 단어(토큰)를 생성하도록 학습됩니다.

Transformers에서 [generate()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationMixin.generate) API는 텍스트 생성을 처리하며, 생성 기능이 있는 모든 모델에서 사용할 수 있습니다. 이 가이드에서는 [generate()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationMixin.generate)를 사용한 텍스트 생성의 기본 사항과 피해야 할 일반적인 함정을 보여줍니다.

> [!TIP]
> 다음 명령어의 경우 [`transformers serve`가 실행 중인지 확인](./serve-cli/serving)하십시오.
>
> ```shell
> transformers chat Qwen/Qwen2.5-0.5B-Instruct
> ```

## 기본 generate

시작하기 전에, 메모리 사용량을 줄이기 위해 매우 큰 모델을 양자화하려면 [bitsandbytes](https://hf.co/docs/bitsandbytes/index)를 설치하는 것이 도움이 됩니다.

```bash
!pip install -U transformers bitsandbytes
```

Bitsandbytes는 CUDA 기반 GPU 외에도 여러 백엔드를 지원합니다. 자세한 내용은 멀티 백엔드 설치 [가이드](https://huggingface.co/docs/bitsandbytes/main/en/installation#multi-backend)를 참고하세요.

LLM을 [from_pretrained()](/docs/transformers/main/ko/main_classes/model#transformers.PreTrainedModel.from_pretrained)로 로드하고 메모리 요구 사항을 줄이기 위해 다음 두 매개변수를 추가합니다.

- `device_map="auto"`는 Accelerate의 [Big Model Inference](./models#big-model-inference) 기능을 활성화하여, 가장 빠른 장치(GPU)부터 시작해 모든 사용 가능한 장치에 걸쳐 모델 스켈레톤을 자동으로 초기화하고 모델 가중치를 로드 및 분배합니다.
- `quantization_config`는 양자화 설정을 정의하는 구성 객체입니다. 이 예제는 양자화 백엔드로 bitsandbytes를 사용하며(사용 가능한 다른 백엔드는 [Quantization](./quantization/overview) 섹션을 참조하세요) 모델을 [4-bits](./quantization/bitsandbytes)로 로드합니다.

```py
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_4bit=True)
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", device_map="auto", quantization_config=quantization_config)
```

입력을 토큰화하고, LLM은 패딩 토큰에서 생성을 계속하도록 학습되지 않았으므로 `padding_side()` 매개변수를 `"left"`로 설정합니다. 토크나이저는 입력 ID와 어텐션 마스크를 반환합니다.

> [!TIP]
> 토크나이저에 문자열 목록을 전달하여 한 번에 여러 프롬프트를 처리합니다. 입력을 배치(batch)로 처리하면 지연 시간과 메모리에 소폭의 비용이 발생하지만 처리량(throughput)을 개선할 수 있습니다.

```py
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
model_inputs = tokenizer(["A list of colors: red, blue"], return_tensors="pt").to(model.device)
```

입력을 [generate()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationMixin.generate)에 전달하여 토큰을 생성한 후, 생성된 토큰을 [batch_decode()](/docs/transformers/main/ko/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.batch_decode)로 텍스트로 복원합니다.

```py
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
"A list of colors: red, blue, green, yellow, orange, purple, pink,"
```

## 생성 구성

모든 생성 설정은 [GenerationConfig](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationConfig)에 포함되어 있습니다. 위의 예시에서 생성 설정은 [mistralai/Mistral-7B-v0.1](https://huggingface.co/mistralai/Mistral-7B-v0.1)의 `generation_config.json` 파일에서 파생됩니다. 모델에 설정이 저장되지 않은 경우 기본 디코딩 전략이 사용됩니다.

`generation_config` 속성을 통해 구성을 확인합니다. 기본 구성과 다른 값만 표시되며, 이 경우 `bos_token_id`와 `eos_token_id`입니다.

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", device_map="auto")
model.generation_config
GenerationConfig {
  "bos_token_id": 1,
  "eos_token_id": 2
}
```

[generate()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationMixin.generate)는 [GenerationConfig](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationConfig)의 매개변수와 값을 재정의하여 사용자 정의할 수 있습니다. 일반적으로 조정하는 매개변수에 대해서는 [아래 섹션](#common-options)을 참조하세요.

```py
# enable beam search sampling strategy
model.generate(**inputs, num_beams=4, do_sample=True)
```

[generate()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationMixin.generate)는 외부 라이브러리나 사용자 정의 코드로도 확장할 수 있습니다:

1. `logits_processor` 매개변수는 다음 토큰 확률 분포를 조작하기 위한 사용자 정의 [LogitsProcessor](/docs/transformers/main/ko/internal/generation_utils#transformers.LogitsProcessor) 인스턴스를 허용합니다.
2. `stopping_criteria` 매개변수는 텍스트 생성을 중단하기 위한 사용자 정의 [StoppingCriteria](/docs/transformers/main/ko/internal/generation_utils#transformers.StoppingCriteria)를 지원합니다.
3. 기타 사용자 정의 생성 방법은 `custom_generate` 플래그([문서](./generation_strategies#custom-generation-methods))를 통해 로드할 수 있습니다.

[생성 전략](./generation_strategies) 가이드를 참고하여 탐색, 샘플링 및 디코딩 전략에 대해 자세히 알아보세요.

### 저장

[GenerationConfig](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationConfig)의 인스턴스를 생성하고 원하는 디코딩 매개변수를 지정합니다.

```py
from transformers import AutoModelForCausalLM, GenerationConfig

model = AutoModelForCausalLM.from_pretrained("my_account/my_model")
generation_config = GenerationConfig(
    max_new_tokens=50, do_sample=True, top_k=50, eos_token_id=model.config.eos_token_id
)
```

[save_pretrained()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationConfig.save_pretrained)을 사용하여 특정 생성 구성을 저장하고, `push_to_hub` 매개변수를 `True`로 설정하여 Hub에 업로드합니다.

```py
generation_config.save_pretrained("my_account/my_model", push_to_hub=True)
```

`config_file_name` 매개변수는 비워 두세요. 이 매개변수는 단일 디렉터리에 여러 생성 구성을 저장할 때 사용해야 합니다. 이 매개변수를 통해 로드할 생성 구성을 지정할 수 있습니다. 단일 모델에 사용할 수 있도록, 다양한 생성 작업(샘플링을 활용한 창의적 텍스트 생성, 빔 서치를 활용한 요약)에 대해 서로 다른 구성을 만들 수 있습니다.

```py
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, GenerationConfig

tokenizer = AutoTokenizer.from_pretrained("google-t5/t5-small")
model = AutoModelForSeq2SeqLM.from_pretrained("google-t5/t5-small")

translation_generation_config = GenerationConfig(
    num_beams=4,
    early_stopping=True,
    decoder_start_token_id=0,
    eos_token_id=model.config.eos_token_id,
    pad_token=model.config.pad_token_id,
)

translation_generation_config.save_pretrained("/tmp", config_file_name="translation_generation_config.json", push_to_hub=True)

generation_config = GenerationConfig.from_pretrained("/tmp", config_file_name="translation_generation_config.json")
inputs = tokenizer("translate English to French: Configuration files are easy to use!", return_tensors="pt")
outputs = model.generate(**inputs, generation_config=generation_config)
print(tokenizer.batch_decode(outputs, skip_special_tokens=True))
```

## 공통 옵션

[generate()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationMixin.generate)는 폭넓게 커스터마이즈할 수 있는 강력한 도구입니다. 이는 신규 사용자에게 부담스럽게 느껴질 수 있습니다. 이 섹션에서는 Transformers의 대부분의 텍스트 생성 도구인 [generate()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationMixin.generate), [GenerationConfig](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationConfig), `pipelines`, `chat` CLI 등에서 정의할 수 있는 인기 있는 생성 옵션 목록을 제공합니다.

| 옵션 이름 | 유형 | 간소화된 설명 |
|---|---|---|
| `max_new_tokens` | `int` | 최대 생성 길이를 제어합니다. 일반적으로 작은 값으로 기본 설정되므로 반드시 정의해야 합니다. |
| `do_sample` | `bool` | 다음 토큰을 샘플링하여 생성할지(`True`), 아니면 그레디 방식으로 생성할지(`False`)를 정의합니다. 대부분의 사용 사례에서는 이 플래그를 `True`로 설정해야 합니다. 자세한 내용은 [이 가이드](./generation_strategies)를 확인하세요. |
| `temperature` | `float` | 다음으로 선택될 토큰의 예측 불가능성을 나타냅니다. 높은 값(`>0.8`)은 창의적인 작업에 적합하고, 낮은 값(예: `<0.4`)은 "사고"가 필요한 작업에 적합합니다. `do_sample=True`가 필요합니다. |
| `num_beams` | `int` | `>1`으로 설정하면 beam search 알고리즘이 활성화됩니다. Beam search는 입력 기반(input-grounded) 작업에 적합합니다. 자세한 내용은 [이 가이드](./generation_strategies)를 참고하세요. |
| `repetition_penalty` | `float` | 모델이 자주 반복되는 것을 확인했다면 `>1.0`으로 설정하세요. 값이 클수록 더 큰 페널티가 적용됩니다. |
| `eos_token_id` | `list[int]` | 생성을 중단시키는 토큰입니다. 기본값은 일반적으로 적절하지만, 다른 토큰을 지정할 수 있습니다. |

## 주의할 점

아래 섹션에서는 텍스트 생성 과정에서 발생할 수 있는 일반적인 문제와 해결 방법을 다룹니다.

### 출력 길이

[generate()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationMixin.generate)는 기본적으로 최대 20개의 토큰을 반환하며, 모델의 [GenerationConfig](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationConfig)에서 별도로 지정하지 않는 한 이 값이 적용됩니다. 출력 길이를 제어하기 위해 `max_new_tokens` 매개변수를 사용하여 생성할 토큰 수를 수동으로 설정하는 것이 강력히 권장됩니다. [Decoder-only](https://hf.co/learn/nlp-course/chapter1/6?fw=pt) 모델은 초기 프롬프트와 함께 생성된 토큰을 반환합니다.

```py
model_inputs = tokenizer(["A sequence of numbers: 1, 2"], return_tensors="pt").to(model.device)
```

```py
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'A sequence of numbers: 1, 2, 3, 4, 5'
```

```py
generated_ids = model.generate(**model_inputs, max_new_tokens=50)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'A sequence of numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,'
```

### 디코딩 전략

[generate()](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationMixin.generate)의 기본 디코딩 전략은 *greedy search*로, 다음에 올 가능성이 가장 높은 토큰을 선택합니다. 모델의 [GenerationConfig](/docs/transformers/main/ko/main_classes/text_generation#transformers.GenerationConfig)에서 별도로 지정하지 않는 한 이 전략이 적용됩니다. 이 디코딩 전략은 입력 기반 작업(전사, 번역)에는 잘 작동하지만, 더 창의적인 사용 사례(스토리 작성, 채팅 애플리케이션)에는 최적이지 않습니다.

예를 들어, [multinomial sampling](./generation_strategies#sampling) 전략을 활성화하여 더 다양한 출력을 생성할 수 있습니다. 추가적인 디코딩 전략에 대해서는 [Generation strategy](./generation_strategies) 가이드를 참조하세요.

```py
model_inputs = tokenizer(["I am a cat."], return_tensors="pt").to(model.device)
```

```py
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
```

```py
generated_ids = model.generate(**model_inputs, do_sample=True)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
```

### 패딩 측면

입력의 길이가 서로 다르면 패딩이 필요합니다. 그러나 LLM은 패딩 토큰에서 생성을 계속하도록 학습되지 않았으므로, `padding_side()` 매개변수를 입력의 왼쪽으로 설정해야 합니다. 상태 공간 모델과 하이브리드 모델의 경우 오른쪽 패딩이 더 불리합니다. 재귀 상태가 뒤쪽의 패딩 토큰에 대해 계속 업데이트되기 때문에 캐시가 프롬프트의 끝과 더 이상 일치하지 않게 됩니다.

```py
model_inputs = tokenizer(
    ["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
).to(model.device)
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'1, 2, 33333333333'
```

```py
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
tokenizer.pad_token = tokenizer.eos_token
model_inputs = tokenizer(
    ["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
).to(model.device)
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'1, 2, 3, 4, 5, 6,'
```

### 프롬프트 형식

일부 모델과 작업은 특정 입력 프롬프트 형식을 요구하며, 형식이 올바르지 않으면 모델이 최적이지 않은 출력을 반환합니다. 프롬프팅에 대한 자세한 내용은 [프롬프트 엔지니어링](./tasks/prompting) 가이드에서 확인하세요.

예를 들어, 채팅 모델은 입력을 [채팅 템플릿](./chat_templating) 형식으로 기대합니다. 프롬프트에는 대화에 참여하는 주체를 나타내기 위해 `role`과 `content`를 포함해야 합니다. 프롬프트를 단일 문자열로 전달하면 모델이 항상 예상된 출력을 반환하지 않을 수 있습니다.

```py
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-alpha")
model = AutoModelForCausalLM.from_pretrained(
    "HuggingFaceH4/zephyr-7b-alpha", device_map="auto", quantization_config=BitsAndBytesConfig(load_in_4bit=True)
)
```

```py
prompt = """How many cats does it take to change a light bulb? Reply as a pirate."""
model_inputs = tokenizer([prompt], return_tensors="pt").to(model.device)
input_length = model_inputs.input_ids.shape[1]
generated_ids = model.generate(**model_inputs, max_new_tokens=50)
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
"Aye, matey! 'Tis a simple task for a cat with a keen eye and nimble paws. First, the cat will climb up the ladder, carefully avoiding the rickety rungs. Then, with"
```

```py
messages = [
    {
        "role": "system",
        "content": "You are a friendly chatbot who always responds in the style of a pirate",
    },
    {"role": "user", "content": "How many cats does it take to change a light bulb?"},
]
model_inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to(model.device)
input_length = model_inputs["input_ids"].shape[1]
generated_ids = model.generate(**model_inputs, do_sample=True, max_new_tokens=50)
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
"Arr, matey! According to me beliefs, 'twas always one cat to hold the ladder and another to climb up it an’ change the light bulb, but if yer looking to save some catnip, maybe yer can
```

## 리소스

더 구체적이고 전문적인 텍스트 생성 라이브러리가 있는지 아래를 확인해 보세요.

- [Optimum](https://github.com/huggingface/optimum): 특정 하드웨어 디바이스에서 학습 및 추론을 최적화하는 데 초점을 맞춘 Transformers 확장
- [Outlines](https://github.com/dottxt-ai/outlines): 제약 조건이 있는 텍스트 생성을 위한 라이브러리(예: JSON 파일 생성).
- [SynCode](https://github.com/uiuc-focal-lab/syncode): 컨텍스트프리 문법 기반 생성(JSON, SQL, Python)을 위한 라이브러리.
- [Text Generation Inference](https://github.com/huggingface/text-generation-inference): LLM용 프로덕션급 서버.
- [Text generation web UI](https://github.com/oobabooga/text-generation-webui): 텍스트 생성을 위한 Gradio 웹 UI입니다.
- [logits-processor-zoo](https://github.com/NVIDIA/logits-processor-zoo): 텍스트 생성을 제어하기 위한 추가 logits 프로세서.

