# Smol-Course

## Docs

- [소형 언어 모델 과정](https://huggingface.co/learn/smol-course/ko/README.md)
- [🤗 smol-course에 오신 것을 환영합니다](https://huggingface.co/learn/smol-course/ko/unit0/1.md)
- [지시 조정(Instruction Tuning)](https://huggingface.co/learn/smol-course/ko/unit1/1.md)
- [지도 학습 기반 미세 조정(Supervised Fine-Tuning)](https://huggingface.co/learn/smol-course/ko/unit1/3.md)
- [대화 템플릿(Chat Templates)](https://huggingface.co/learn/smol-course/ko/unit1/2.md)
- [Parameter-Efficient Fine-Tuning, PEFT](https://huggingface.co/learn/smol-course/ko/unit3/1.md)
- [프롬프트 튜닝](https://huggingface.co/learn/smol-course/ko/unit3/3.md)
- [LoRA (Low-Rank Adaptation)](https://huggingface.co/learn/smol-course/ko/unit3/2.md)

### 소형 언어 모델 과정
https://huggingface.co/learn/smol-course/ko/README.md

# 소형 언어 모델 과정

이 과정에서는 특정 사용 사례에 맞게 언어 모델을 정렬하는 법을 다룹니다. 모든 자료는 대부분의 로컬 컴퓨터에서 실행되므로 간편하게 언어 모델 정렬을 시작해볼 수 있습니다. 이 과정을 위해 필요한 최소한의 GPU 요구 사항이나 유료 서비스가 없습니다. [SmolLM2](https://github.com/huggingface/smollm/tree/main) 시리즈 모델을 기반으로 하는 과정이지만, 여기서 배운 기술을 더 큰 모델이나 다른 작은 언어 모델로 옮길 수 있습니다.

<a href="http://hf.co/join/discord">
<img src="https://img.shields.io/badge/Discord-7289DA?&logo=discord&logoColor=white"/>
</a>

<div style="background: linear-gradient(to right, #e0f7fa, #e1bee7, orange); padding: 20px; border-radius: 5px; margin-bottom: 20px; color: purple;">
    <h2>지금 바로 참여하세요!</h2>
    <p>이 과정은 열려 있으며 다른 사용자와의 상호 검토를 진행할 수 있습니다. 이 과정에 참여하려면 <strong>pull request(PR)</strong>를 열고 검토 받을 수 있도록 결과물을 제출하세요. 다음 단계를 따르면 됩니다:</p>
    <ol>
        <li><a href="https://github.com/huggingface/smol-course/fork">여기</a>에서 레포지토리를 fork하세요.</li>
        <li>자료를 읽고, 바꿔 보고, 실습해보고, 나만의 예제를 추가해보세요.</li>
        <li>december-2024 브랜치에 PR을 보내세요.</li>
        <li>검토가 끝나면 december-2024 브랜치에 병합됩니다.</li>
    </ol>
    <p>이 과정은 학습에 도움이 될 뿐만 아니라 지속적으로 발전하는 커뮤니티 기반 코스를 형성하는 데에도 기여할 것입니다.</p>
</div>

[discussion thread](https://github.com/huggingface/smol-course/discussions/2#discussion-7602932)에서 과정에 대해 토론할 수도 있습니다.

## 과정 개요

이 과정은 소형 언어 모델의 초기 학습부터 결과물 배포까지 실습할 수 있는 실용적인 내용을 제공합니다.

| 모듈 | 설명 | 상태 | 공개일 |
|--------|-------------|---------|--------------|
| [Instruction Tuning](./1_instruction_tuning) | 지도 학습 기반 미세 조정, 대화 템플릿 작성, 기본적인 지시를 따르게 하는 방법 학습 | ✅ 학습 가능 | 2024. 12. 3 |
| [Preference Alignment](./2_preference_alignment) | 모델을 인간 선호도에 맞게 정렬하기 위한 DPO와 ORPO 기법 학습 | ✅ 학습 가능 | 2024. 12. 6 |
| [Parameter-efficient Fine-tuning](./3_parameter_efficient_finetuning) | LoRA, 프롬프트 튜닝을 포함한 효율적인 적응 방법 학습 | ✅ 학습 가능 | 2024. 12. 9 |
| [Evaluation](./4_evaluation) | 자동 벤치마크 사용법 및 사용자 정의 도메인 평가 수행 방법 학습 | ✅ 학습 가능 | 2024. 12. 13 |
| [Vision-language Models](./5_vision_language_models) | 비전-언어 태스크를 위한 멀티모달 모델 적용 방법 학습 | [🚧 준비중](https://github.com/huggingface/smol-course/issues/49) | 2024. 12. 16 |
| [Synthetic Datasets](./6_synthetic_datasets) | 모델 학습을 위한 합성 데이터셋 생성 및 검증 | [🚧 준비중](https://github.com/huggingface/smol-course/issues/83) | 2024. 12. 20 |
| [Inference](./7_inference) | 모델의 효율적인 추론 방법 학습 | 📝 작성 예정 | 2024. 12. 23 |

## 왜 소형 언어 모델을 사용하나요?

대형 언어 모델은 뛰어난 능력을 보여주지만, 상당한 연산 자원을 필요로 하며 특정 기능에 초점을 맞춘 애플리케이션에 대해서는 대형 언어 모델이 과한 경우도 있습니다. 소형 언어 모델은 도메인 특화 애플리케이션에 있어서 몇 가지 이점을 제공합니다: 

- **효율성**: 대형 언어 모델보다 훨씬 적은 연산 자원으로 학습 및 배포 가능
- **맞춤화**: 특정 도메인에 대한 미세 조정 및 적응 용이
- **제어**: 모델 동작 과정을 잘 이해할 수 있고 모델의 동작을 쉽게 제어 가능
- **비용**: 학습과 추론 과정에서 필요한 비용 감소
- **프라이버시**: 데이터를 외부 API로 보내지 않고 로컬에서 실행 가능
- **친환경**: 탄소 발자국을 줄이는 효율적인 자원 사용
- **쉬운 학술 연구 및 개발**: 최신 LLM을 활용해 물리적 제약 없이 학술 연구를 쉽게 시작할 수 있도록 지원

## 사전 준비 사항

시작하기 전에 아래 사항이 준비되어 있는지 확인하세요:
- 머신러닝과 자연어처리에 대한 기본적인 이해가 필요합니다.
- Python, PyTorch 및 `transformers` 라이브러리에 익숙해야 합니다.
- 사전 학습된 언어 모델과 레이블이 있는 액세스할 수 있어야 합니다.

## 설치

이 과정은 패키지 형태로 관리되기 때문에 패키지 매니저를 이용해 의존성 설치를 쉽게 진행할 수 있습니다. 이를 위해 [uv](https://github.com/astral-sh/uv) 사용을 권장하지만 `pip`나 `pdm`을 사용할 수도 있습니다.

### `uv` 사용

`uv`를 설치한 후, 아래 명령어로 소형 언어 모델 과정을 설치할 수 있습니다:

```bash
uv venv --python 3.11.0
uv sync
```

### `pip` 사용

모든 예제는 동일한 **python 3.11** 환경에서 실행되기 때문에 아래처럼 환경을 생성하고 의존성을 설치해야 합니다:

```bash
# python -m venv .venv
# source .venv/bin/activate
pip install -r requirements.txt
```

### Google Colab

**Google Colab**에서는 사용하는 하드웨어에 따라 유연하게 의존성을 설치해야 합니다. 아래와 같이 진행하세요:

```bash
pip install transformers trl datasets huggingface_hub
```

## 참여

많은 사람이 고가의 장비 없이 LLM을 미세 조정하는 법을 배울 수 있도록 이 자료를 공유해 봅시다!

[![Star History Chart](https://api.star-history.com/svg?repos=huggingface/smol-course&type=Date)](https://star-history.com/#huggingface/smol-course&Date)


<EditOnGithub source="https://github.com/huggingface/smol-course/blob/main/units/ko/README.md" />

### 🤗 smol-course에 오신 것을 환영합니다
https://huggingface.co/learn/smol-course/ko/unit0/1.md

# 🤗 smol-course에 오신 것을 환영합니다

이 코스의 전체 소개는 영어 버전을 참조하세요:

[Read the full introduction in English](https://huggingface.co/learn/smol-course/unit0/1)

## 이 코스에 대해 간단히

- **언어 모델 파인튜닝을 위한 포괄적인 코스**
- **초보자부터 전문가까지**를 위한 단계별 학습
- 인스트럭션 튜닝, 평가, 프리퍼런스 얼라이먼트 등 학습
- 실습과 실제 프로젝트 포함

## 코스 구성

1. 인스트럭션 튜닝
2. 평가
3. 프리퍼런스 얼라이먼트
4. 파라미터 효율적 파인튜닝
5. 비전 언어 모델
6. 합성 데이터셋

[코스 시작하기](https://huggingface.co/smol-course)


<EditOnGithub source="https://github.com/huggingface/smol-course/blob/main/units/ko/unit0/1.md" />

### 지시 조정(Instruction Tuning)
https://huggingface.co/learn/smol-course/ko/unit1/1.md

# 지시 조정(Instruction Tuning)

이 모듈에서는 언어 모델의 지시 조정(instruction tuning) 방법을 설명합니다. 지시 조정이란, 사전 학습된 모델을 특정 태스크에 맞게 조정하기 위해 해당 태스크와 관련된 데이터셋으로 추가 학습시키는 과정을 의미합니다. 이를 통해 목표로 하는 작업에서 모델이 더 나은 성능을 발휘할 수 있습니다.

이 모듈에서는 다음 두 가지 주제를 다룰 예정입니다: 1) 대화 템플릿(Chat Templates) 2) 지도 학습 기반 미세 조정(Supervised Fine-Tuning)

## 1️⃣ 대화 템플릿

채팅 템플릿(Chat Templates)은 사용자와 AI 모델 간의 상호작용을 구조화하여 모델의 일관되고 적절한 맥락의 응답을 보장합니다. 템플릿에는 시스템 프롬프트와 역할 기반 메시지와 같은 구성 요소가 포함됩니다. 더 자세한 내용은 [대화 템플릿](./chat_templates.md) 섹션을 참고하세요.

## 2️⃣ 지도 학습 기반 미세 조정

지도 학습 기반 미세 조정(SFT)은 사전 학습된 언어 모델이 특정 작업에 적합하도록 조정하는 데 핵심적인 과정입니다. 이 과정에서는 레이블이 포함된 태스크별 데이터셋을 사용해 모델을 학습시킵니다. SFT의 주요 단계와 모범 사례를 포함한 자세한 가이드는 [지도 학습 기반 미세 조정](./supervised_fine_tuning.md) 섹션을 참고하세요.

## 참고

- [Transformers documentation on chat templates](https://huggingface.co/docs/transformers/main/en/chat_templating)
- [Script for Supervised Fine-Tuning in TRL](https://github.com/huggingface/trl/blob/main/examples/scripts/sft.py)
- [`SFTTrainer` in TRL](https://huggingface.co/docs/trl/main/en/sft_trainer)
- [Direct Preference Optimization Paper](https://arxiv.org/abs/2305.18290)
- [Supervised Fine-Tuning with TRL](https://huggingface.co/docs/trl/main/en/tutorials/supervised_finetuning)
- [How to fine-tune Google Gemma with ChatML and Hugging Face TRL](https://www.philschmid.de/fine-tune-google-gemma)
- [Fine-tuning LLM to Generate Persian Product Catalogs in JSON Format](https://huggingface.co/learn/cookbook/en/fine_tuning_llm_to_generate_persian_product_catalogs_in_json_format)

<EditOnGithub source="https://github.com/huggingface/smol-course/blob/main/units/ko/unit1/1.md" />

### 지도 학습 기반 미세 조정(Supervised Fine-Tuning)
https://huggingface.co/learn/smol-course/ko/unit1/3.md

# 지도 학습 기반 미세 조정(Supervised Fine-Tuning)

<CourseFloatingBanner chapter={10}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/smol-course/blob/main/notebooks/ko/1_instruction_tuning/sft_finetuning_example.ipynb"}
  ]} />

지도 학습 기반 미세 조정(SFT)은 사전 학습된 언어 모델을 특정 작업이나 도메인에 맞게 조정하는 데 핵심적인 과정입니다. 사전 학습된 모델의 능력은 일반적으로 뛰어나지만, 특정 사용 사례에서 우수한 성능을 발휘하려면 맞춤화가 필요할 때가 많습니다. SFT는 사람이 검증한 예제를 포함하여 신중하게 선별된 데이터셋으로 모델을 추가 학습시켜 이러한 격차를 해소합니다.

## SFT 이해하기

SFT의 핵심은 레이블이 있는 토큰을 통해 사전 학습된 모델이 특정 작업을 수행하도록 학습시키는 것입니다. 이 과정에서 원하는 입력-출력 동작 예제를 모델에 많이 보여줌으로써, 해당 사용 사례에 특화된 패턴을 학습하도록 합니다.

SFT가 효과적인 이유는 사전 학습 과정에서 습득한 기초 지식을 활용하면서도 사용자의 특정 요구에 맞게 모델의 동작을 조정할 수 있기 때문입니다.

## SFT를 언제 사용해야 하나요?

SFT 사용 여부는 주로 모델이 현재 가지고 있는 능력과 특정 요구 사항 간의 차이에 따라 결정됩니다. SFT는 특히 모델 출력에 대한 정교한 제어가 필요하거나 전문적인 도메인에서 작업할 때 매우 유용합니다.

예를 들어, 고객 서비스 애플리케이션을 개발하는 경우 모델이 회사 지침을 일관되게 따르고 기술적인 질문을 표준화된 방식으로 처리하도록 만들고 싶을 것입니다. 마찬가지로 의료나 법률 애플리케이션에서는 정확성과 도메인 특화 용어를 사용하는 것이 중요합니다. SFT는 이러한 경우에서 모델의 응답이 전문적인 표준을 따르고 모델 응답을 도메인 전문 지식에 맞게 조정하는 데 도움을 줄 수 있습니다.

## 미세 조정 과정

지도 학습 기반 미세 조정은 특정 태스크에 맞춘 데이터셋으로 모델 가중치를 학습시키는 과정을 포함합니다.

먼저, 목표 태스크를 대표할 수 있는 데이터셋을 준비하거나 선택해야 합니다. 이 데이터셋은 모델이 마주하게 될 다양한 시나리오를 포괄할 수 있는 예제를 포함하고 있어야 합니다. 데이터 품질이 매우 중요하며 각 예제는 모델이 생성하길 원하는 출력 유형을 명확히 보여줘야 합니다. 이후 Hugging Face의 `transformers` 및 `trl`과 같은 프레임워크를 사용하여 데이터셋을 기반으로 모델을 학습시키는 실제 미세 조정 단계가 이어집니다.

이 과정 전반에서 지속적인 평가가 필수적입니다. 모델이 원하는 동작을 학습하면서도 일반적인 능력을 잃지 않도록 검증 데이터셋을 사용해 성능을 모니터링해야 합니다. 모델을 평가하는 방법에 대해서는 [모듈 4](../4_evaluation)에서 다룰 예정입니다.

## 선호도 조정에서 SFT의 역할

SFT는 언어 모델을 인간의 선호도에 맞추는 데 기본적인 역할을 합니다. 인간 피드백을 통한 강화 학습(Reinforcement Learning from Human Feedback, RLHF) 및 직접 선호도 최적화(Direct Preference Optimization, DPO)와 같은 기술은 SFT를 사용하여 기본적인 수준으로 태스크를 이해하게 한 후 모델의 응답을 원하는 결과에 맞게 조정합니다. 사전 학습된 모델은 일반적인 언어 능력을 가지고 있음에도 불구하고 항상 사람의 선호도와 일치하는 결과를 생성하지 못할 수 있습니다. SFT는 도메인별 데이터와 지침을 도입하여 이러한 격차를 해소함으로써 모델이 인간의 기대에 부합하는 응답을 생성할 수 있도록 합니다.

## TRL을 활용한 SFT

지도 학습 기반 미세 조정에서 중요한 소프트웨어 패키지 중 하나는 Transformer 강화 학습(Transformer Reinforcement Learning, TRL)입니다. TRL은 강화 학습(Reinforcement Learning, RL)을 사용하여 트랜스포머 언어 모델을 학습시키기 위한 도구입니다.

Hugging Face Transformers 라이브러리를 기반으로 구축된 TRL은 사용자가 사전 학습된 언어 모델을 직접 로드할 수 있게 하며, 대부분의 디코더 및 인코더-디코더 아키텍처를 지원합니다. 이 라이브러리는 언어 모델링에 사용되는 주요 RL 프로세스를 지원하고 지도 학습 기반 미세 조정(SFT), 보상 모델링(Reward Modeling, RM), 근접 정책 최적화(Proximal Policy Optimization, PPO), 직접 선호 최적화(Direct Preference Optimization, DPO)와 같은 과정을 용이하게 만듭니다.

이 레포지토리의 여러 모듈에서 TRL을 활용할 예정입니다.

# 다음 단계

다음 튜토리얼을 통해 TRL을 활용한 SFT 실습 경험을 쌓아 보세요: 

⏭️ [Chat Templates 튜토리얼](../../../notebooks/ko/1_instruction_tuning/../notebooks/ko/1_instruction_tuning/supervised_fine_tuning_tutorial.ipynb)

<EditOnGithub source="https://github.com/huggingface/smol-course/blob/main/units/ko/unit1/3.md" />

### 대화 템플릿(Chat Templates)
https://huggingface.co/learn/smol-course/ko/unit1/2.md

# 대화 템플릿(Chat Templates)

<CourseFloatingBanner chapter={10}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/smol-course/blob/main/notebooks/ko/1_instruction_tuning/chat_templates_example.ipynb"}
  ]} />

대화 템플릿은 언어 모델과 사용자 간 상호작용을 구조화하는 데 필수적입니다. 이 템플릿은 대화에 일관된 형식을 제공하여, 모델이 각 메시지의 맥락과 역할을 이해하고 적절한 응답 패턴을 유지할 수 있도록 합니다.

## 기본 모델 vs 지시 모델

기본 모델은 다음 토큰을 예측하기 위해 대량의 원시 텍스트 데이터로 학습되는 반면, 지시 모델은 특정 지시를 따르고 대화를 나눌 수 있도록 미세 조정된 모델입니다. 예를 들어, `SmolLM2-135M`은 기본 모델이고, `SmolLM2-135M-Instruct`는 이를 지시 조정한 변형 모델입니다.

기본 모델이 지시 모델처럼 동작하도록 만들기 위해서는 모델이 이해할 수 있는 방식으로 프롬프트를 일관되게 만들어야 합니다. 이때 대화 템플릿이 유용합니다. ChatML은 이러한 템플릿 형식 중 하나로 대화를 구조화하고 명확한 역할 지시자(시스템, 사용자, 어시스턴트)를 제공합니다.

기본 모델은 서로 다른 대화 템플릿으로 미세 조정될 수 있으므로, 지시 모델을 사용할 때는 반드시 해당 모델에 적합한 대화 템플릿을 사용하는 것이 중요합니다.

## 대화 템플릿 이해하기

대화 템플릿의 핵심은 언어 모델과 소통할 때 대화가 어떤 형식으로 이루어져야 하는지 정의하는 것입니다. 템플릿에는 시스템 수준의 지침, 사용자 메시지, 어시스턴트의 응답이 포함되어 있으며, 모델이 이해할 수 있는 구조화된 형식을 제공합니다. 이러한 구조는 상호작용의 일관성을 유지하고, 모델이 다양한 유형의 입력에 적절히 응답하도록 돕습니다. 아래는 채팅 템플릿의 예시입니다:

```sh
<|im_start|>user
안녕하세요!<|im_end|>
<|im_start|>assistant
만나서 반갑습니다!<|im_end|>
<|im_start|>user
질문을 해도 될까요?<|im_end|>
<|im_start|>assistant
```

`transformers` 라이브러리는 모델의 토크나이저와 관련하여 대화 템플릿을 자동으로 처리해줍니다. 대화 템플릿이 transformers에서 어떻게 구성되는지 자세히 알아보려면 [여기](https://huggingface.co/docs/transformers/en/chat_templating#how-do-i-use-chat-templates)를 참고하세요. 우리가 메시지를 올바른 형식으로 구조화하기만 하면 나머지는 토크나이저가 처리합니다. 아래는 기본적인 대화 예시입니다:
```python
messages = [
    {"role": "system", "content": "You are a helpful assistant focused on technical topics."},
    {"role": "user", "content": "Can you explain what a chat template is?"},
    {"role": "assistant", "content": "A chat template structures conversations between users and AI models..."}
]
```

위 예시를 자세히 보면서 대화 템플릿 형식에 어떻게 매핑되는지 살펴봅시다.

## 시스템 메시지

시스템 메시지는 모델의 기본 동작 방식을 설정합니다. 이는 이후 모든 상호작용에 영향을 미치는 지속적인 지침이 됩니다.

```python
system_message = {
    "role": "system",
    "content": "You are a professional customer service agent. Always be polite, clear, and helpful."
}
```

## 대화

대화 템플릿은 대화 기록을 통해 맥락을 유지하며, 사용자와 어시스턴트 간의 이전 대화를 저장합니다. 이를 통해 더욱 일관된 멀티 턴 대화가 가능해집니다:

```python
conversation = [
    {"role": "user", "content": "I need help with my order"},
    {"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"},
    {"role": "user", "content": "It's ORDER-123"},
]
```

## Transformers 기반 구현

transformers 라이브러리는 대화 템플릿을 위한 내장 기능을 지원합니다.사용 방법은 다음과 같습니다:

```python
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-135M-Instruct")

messages = [
    {"role": "system", "content": "You are a helpful coding assistant."},
    {"role": "user", "content": "Write a Python function to sort a list"},
]

# 대화 템플릿 적용
formatted_chat = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True
)
```

## 사용자 정의 형식

메시지 유형별로 원하는 형식을 설정할 수 있습니다. 예를 들어, 역할에 따라 특수 토큰을 추가하거나 형식을 지정할 수 있습니다:

```python
template = """
<|system|>{system_message}
<|user|>{user_message}
<|assistant|>{assistant_message}
""".lstrip()
```

## 멀티 턴 지원

템플릿은 문맥을 유지하면서 복잡한 멀티 턴 대화도 처리할 수 있습니다:

```python
messages = [
    {"role": "system", "content": "You are a math tutor."},
    {"role": "user", "content": "What is calculus?"},
    {"role": "assistant", "content": "Calculus is a branch of mathematics..."},
    {"role": "user", "content": "Can you give me an example?"},
]
```

⏭️ [다음: Supervised Fine-Tuning](./supervised_fine_tuning.md)

## 참고

- [Hugging Face Chat Templating Guide](https://huggingface.co/docs/transformers/main/en/chat_templating)
- [Transformers Documentation](https://huggingface.co/docs/transformers)
- [Chat Templates Examples Repository](https://github.com/chujiezheng/chat_templates) 


<EditOnGithub source="https://github.com/huggingface/smol-course/blob/main/units/ko/unit1/2.md" />

### Parameter-Efficient Fine-Tuning, PEFT
https://huggingface.co/learn/smol-course/ko/unit3/1.md

# Parameter-Efficient Fine-Tuning, PEFT

언어 모델이 커지면서 전통적인 미세 조정 방식을 적용하는 것이 점점 어려워지고 있습니다. 1.7B 모델조차도 전체 미세 조정을 수행하려면 상당한 GPU 메모리가 필요하며, 모델 사본을 별도로 저장하기 위한 비용이 많이 들고, 모델의 원래 능력을 상실하는 위험이 존재합니다. Parmeter-Efficient Fine-Tuning(PEFT) 방법은 대부분의 모델 파라미터가 고정된 상태에서 모델 파라미터의 일부만 수정하여 전체 미세 조정 과정에서 발생하는 문제를 해결헙니다.

학습 과정에서 모델의 모든 파라미터를 업데이트하는 전통적인 미세 조정 방법을 대형 언어 모델에 적용하는 것은 현실적으로 어렵습니다. PEFT는 원래 모델 크기의 1% 미만에 해당하는 파라미터만 학습시켜 모델을 조정하는 방법입니다. 학습 가능한 파라미터를 크게 줄이는 것은 다음과 같은 이점을 제공합니다:

- 제한된 GPU 메모리를 가진 하드웨어에서도 미세 조정 가능
- 효율적인 태스크별 적응 모델 저장
- 데이터가 적은 상황에서도 뛰어난 일반화 성능 제공
- 더 빠른 학습 및 반복 가능

## 사용 가능한 방법

이 모듈에서는 많이 사용되는 두 가지 PEFT 방법을 다룹니다:

### 1️⃣ LoRA (Low-Rank Adaptation)

LoRA는 효율적인 모델 적응을 위한 멋진 솔루션을 제공하면서 가장 많이 사용되는 PEFT 방법으로 자리 잡았습니다. LoRA는 전체 모델을 수정하는 대신 **학습 가능한 파라미터를 모델의 어텐션 레이어에 주입**합니다. 이 접근법은 전체 미세 조정과 비슷한 성능을 유지하면서 학습 가능한 파라미터를 약 90%까지 줄입니다. [LoRA (Low-Rank Adaptation)](./lora_adapters.md) 섹션에서 LoRA에 대해 자세히 알아보겠습니다.
 
### 2️⃣ 프롬프트 튜닝

프롬프트 튜닝은 모델 가중치를 수정하는 대신 **입력에 학습 가능한 토큰을 추가**하여 **더 경량화된** 접근법을 제공합니다. 프롬프트 튜닝은 LoRA만큼 유명하지는 않지만, 모델을 새로운 태스크나 도메인에 빠르게 적용할 때 유용하게 쓰일 수 있는 기술입니다. [프롬프트 튜닝](./prompt_tuning.md) 섹션에서 프롬프트 튜닝에 대해 탐구해볼 예정입니다.

## 참고
- [Hugging Face PEFT 문서](https://huggingface.co/docs/peft)
- [LoRA 논문](https://arxiv.org/abs/2106.09685)
- [QLoRA 논문](https://arxiv.org/abs/2305.14314)
- [프롬프트 튜닝 논문](https://arxiv.org/abs/2104.08691)
- [Hugging Face PEFT 가이드](https://huggingface.co/blog/peft)
- [How to Fine-Tune LLMs in 2024 with Hugging Face](https://www.philschmid.de/fine-tune-llms-in-2024-with-trl) 
- [TRL](https://huggingface.co/docs/trl/index)

<EditOnGithub source="https://github.com/huggingface/smol-course/blob/main/units/ko/unit3/1.md" />

### 프롬프트 튜닝
https://huggingface.co/learn/smol-course/ko/unit3/3.md

# 프롬프트 튜닝

<CourseFloatingBanner chapter={10}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/smol-course/blob/main/notebooks/ko/3_parameter_efficient_finetuning/finetune_sft_peft.ipynb"},
]} />

프롬프트 튜닝은 모델 가중치 대신 입력 표현을 변경하는 파라미터 효율적인 접근법입니다. 모델의 모든 파라미터를 업데이트하는 전통적인 미세 조정과 다르게, 프롬프트 튜닝은 기본 모델의 파라미터가 고정된 상태를 유지하면서 소수의 학습 가능한 토큰을 추가하고 최적화합니다. 

## 프롬프트 튜닝 이해하기

프롬프트 튜닝은 모델 미세 조정의 대안으로, 학습 가능한 연속 벡터(소프트 프롬프트)를 입력 텍스트에 추가하는 파라미터 효율적인 방식입니다. 소프트 프롬프트는 이산적인 텍스트 프롬프트와 다르게 모델 파라미터가 고정된 상태에서 역전파를 통해 학습됩니다. 이 방식은 ["The Power of Scale for Parameter-Efficient Prompt Tuning"](https://arxiv.org/abs/2104.08691) (Lester et al., 2021)에서 처음 소개되었으며, 이 논문은 모델 크기가 커질수록 미세 조정과 비교했을 때 프롬프트 튜닝이 경쟁력을 가진다는 것을 보였습니다. 논문에 따르면, 약 100억 개의 파라미터를 가진 모델에서 프롬프트 튜닝의 성능은 태스크당 수백 개의 매개변수 수정만으로 모델 미세 조정의 성능과 일치하는 것으로 나타났습니다.

모델의 임베딩 공간에 존재하는 연속적인 벡터인 소프트 프롬프트는 학습 과정에서 최적화됩니다. 자연어 토큰을 사용하는 전통적인 이산 프롬프트와 달리 소프트 프롬프트는 고유한 의미를 가지고 있지는 않지만 경사 하강법을 통해 파라미터가 고정된 모델에서 원하는 동작을 이끌어내는 방법을 학습합니다. 이 기법은 모델 전체를 복사하지 않고 적은 수(일반적으로 몇백 개의 파라미터)에 해당하는 프롬프트 벡터만을 저장하기 때문에 멀티 태스크 시나리오에 더욱 효과적입니다. 이 접근 방식은 최소한의 메모리 사용량을 유지할 뿐만 아니라, 프롬프트 벡터만 교체하여 모델을 다시 로드하지 않고도 신속하게 작업을 전환할 수 있게 합니다.

## 학습 과정

소프트 프롬프트는 일반적으로 8~32개의 토큰으로 구성되며 무작위 또는 기존 텍스트로 초기화할 수 있습니다. 초기화 방법은 학습 과정에서 중요한 역할을 하며 텍스트 기반 초기화가 무작위 초기화보다 좋은 성능을 보이는 경우가 많습니다.

학습이 진행되는 동안 기본 모델의 파라미터는 고정되어 있고 프롬프트 파라미터만 업데이트 됩니다. 프롬프트 파라미터에 초점을 맞춘 이 접근 방식은 일반적인 학습 목표를 따르지만 학습률과 프롬프트 토큰의 경사 동작에 세심한 주의가 필요합니다.

## PEFT 라이브러리를 활용한 프롬프트 튜닝 구현

PEFT 라이브러리를 이용해 프롬프트 튜닝을 직관적으로 구현할 수 있습니다. 기본적인 예제는 다음과 같습니다:

```python
from peft import PromptTuningConfig, TaskType, get_peft_model
from transformers import AutoModelForCausalLM, AutoTokenizer

# 기본 모델 불러오기
model = AutoModelForCausalLM.from_pretrained("your-base-model")
tokenizer = AutoTokenizer.from_pretrained("your-base-model")

# 프롬프트 튜닝 configuration 설정
peft_config = PromptTuningConfig(
    task_type=TaskType.CAUSAL_LM,
    num_virtual_tokens=8,  # 학습 가능한 토큰 수
    prompt_tuning_init="TEXT",  # 텍스트 기반 초기화
    prompt_tuning_init_text="Classify if this text is positive or negative:",
    tokenizer_name_or_path="your-base-model",
)

# 프롬프트 튜닝 가능한 모델 생성
model = get_peft_model(model, peft_config)
```

## 프롬프트 튜닝과 다른 PEFT 방법 비교

다른 PEFT 접근 방식과 비교했을 때 프롬프트 튜닝은 효율성이 뛰어납니다. LoRA는 파라미터 수와 메모리 사용량이 적지만 태스크 전환을 위해 어댑터를 불러와야 하는 반면 프롬프트 튜닝은 자원을 더 적게 사용하면서 즉각적인 태스크 전환이 가능합니다. 반면에 전체 미세 조정은 상당한 양의 자원을 필요로 하고 서로 다른 태스크를 수행하기 위해 태스크에 맞는 각각의 모델을 필요로 합니다.

| 방법 | 파라미터 수 | 메모리 사용량 | 태스크 전환 |
|--------|------------|---------|----------------|
| 프롬프트 튜닝 | 매우 적음 | 메모리 사용량 최소화 | 쉬움 |
| LoRA | 적음 | 적음 | 모델을 다시 불러와야 함 |
| 전체 미세 조정 | 많음 | 많음 | 새로운 모델 복사 필요 |

프롬프트 튜닝을 구현할 때는 적은 수(8~16개)의 가상 토큰으로 시작한 후 태스크의 복잡성에 따라 토큰 수를 점차 늘려가세요. 태스크와 관련된 텍스트로 초기화를 수행하는 것이 무작위 초기화보다 일반적으로 더 나은 결과를 가져옵니다. 초기화 전략은 목표 태스크의 복잡성을 반영해야 합니다.

학습 과정은 전체 미세 조정과 약간의 차이가 있습니다. 보통 높은 학습률이 효과적이지만 프롬프트 토큰 경사를 신중하게 모니터링해야 합니다. 다양한 예제를 활용한 주기적인 검증은 서로 다른 시나리오에서 강력한 성능을 보장하는 데 도움이 됩니다.

## 응용

프롬프트 튜닝은 다음과 같은 시나리오에서 특히 뛰어납니다:

1. 멀티 태스크 배포
2. 자원이 제한적인 환경
3. 신속한 태스크 적응
4. 프라이버시에 민감한 애플리케이션

그러나 모델 크기가 작아질수록 전체 미세 조정과 비교했을 때 프롬프트 튜닝의 경쟁력이 떨어집니다. 예를 들어, SmolLM2 크기의 모델은 프롬프트 튜닝보다 전체 미세 조정를 수행하는 것이 좀 더 의미있습니다.

## 다음 단계

⏭️ [LoRA 어댑터 튜토리얼](../../../notebooks/ko/3_parameter_efficient_finetuning/finetune_sft_peft.ipynb)에서 LoRA 어댑터를 활용해 모델을 미세 조정하는 법을 배워봅시다.

## 참고
- [Hugging Face PEFT 문서](https://huggingface.co/docs/peft)
- [프롬프트 튜닝 논문](https://arxiv.org/abs/2104.08691)
- [Hugging Face Cookbook](https://huggingface.co/learn/cookbook/prompt_tuning_peft)


<EditOnGithub source="https://github.com/huggingface/smol-course/blob/main/units/ko/unit3/3.md" />

### LoRA (Low-Rank Adaptation)
https://huggingface.co/learn/smol-course/ko/unit3/2.md

# LoRA (Low-Rank Adaptation)

<CourseFloatingBanner chapter={10}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/smol-course/blob/main/notebooks/ko/3_parameter_efficient_finetuning/finetune_sft_peft.ipynb"},
]} />

LoRA는 널리 쓰이는 PEFT 방법으로 자리 잡았습니다. 어텐션 가중치에 작은 랭크 분해 행렬을 추가하는 방식으로 동작작하며 일반적으로 학습 가능한 파라미터를 약 90% 줄여줍니다.

## LoRA 이해하기

LoRA(Low-Rank Adaptation)는 사전 학습된 모델 가중치를 고정한 상태에서 학습 가능한 랭크 분해 행렬을 모델 레이어에 주입하는 파라미터 효율적인 미세 조정 기법입니다. 미세 조정 과정에서 모든 모델 파라미터를 학습시키는 대신, LoRA는 저랭크 분해를 통해 가중치 업데이트를 더 작은 행렬로 나눠 모델 성능은 유지하면서 학습 가능한 파라미터 수를 크게 줄입니다. 예를 들어, GPT-3 175B에 LoRA를 적용했을 때 전체 미세 조정 대비 학습 가능한 파라미터 수는 10,000배, GPU 메모리 요구 사항은 3배 감소했습니다. [LoRA 논문](https://arxiv.org/pdf/2106.09685)에서 LoRA에 관한 자세한 내용을 확인할 수 있습니다.

LoRA는 일반적으로 트랜스포머 레이어 중 어텐션 가중치에 랭크 분해 행렬 쌍을 추가하는 방식으로 동작합니다. 어댑터 가중치는 추론 과정에서 기본 모델과 병합될 수 있고 추가적인 지연 시간이 발생하지 않습니다. LoRA는 자원 요구 사항을 적절한 수준으로 유지하면서 대형 언어 모델을 특정 태스크나 도메인에 맞게 조정하는 데 특히 유용합니다.

## LoRA 어댑터 불러오기

load_adapter()를 사용하여 사전 학습된 모델에 어댑터를 불러올 수 있으며 가중치가 병합되지 않은 다른 어댑터를 사용해 볼 때 유용합니다. set_adapter() 함수로 활성 어댑터 가중치를 설정합니다. 기본 모델을 반환하려면 unload()를 사용하여 불러온 모든 LoRA 모듈을 내릴 수 있습니다. 이렇게 하면 태스크별 가중치를 쉽게 전환할 수 있습니다.

```python
from transformers import AutoModelForCausalLM
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained("<base_model_name>")
peft_model_id = "<peft_adapter_id>"
model = PeftModel.from_pretrained(base_model, peft_model_id)
```

![lora_load_adapter](./images/lora_adapter.png)

## LoRA 어댑터 병합

LoRA로 학습한 후에는 더 쉬운 배포를 위해 어댑터 가중치를 기본 모델에 다시 병합할 수 있습니다. 이를 통해 결합된 가중치를 가진 단일 모델을 생성할 수 있기 때문에 추론 과정에서 별도로 어댑터를 불러올 필요가 없습니다.

병합 과정에서는 메모리 관리와 정밀도에 주의해야 합니다. 기본 모델과 어댑터 가중치를 동시에 불러와야 하므로 GPU/CPU 메모리가 충분해야 합니다. `transformers`의 `device_map="auto"`를 사용하면 메모리를 자동으로 관리할 수 있습니다. 학습 중 사용한 정밀도(예: float16)를 병합 과정에서도 일관되게 유지하고, 병합된 모델을 같은 형식으로 저장하여 배포하세요. 배포 전에 반드시 병합된 모델의 출력 결과와 성능 지표를 어댑터 기반 버전과 비교하여 검증해야 합니다.

어댑터는 서로 다른 태스크나 도메인 간 전환도 간편하게 만듭니다. 기본 모델과 어댑터 가중치를 별도로 불러오면 빠르게 태스크별 가중치를 전환할 수 있습니다.

## 구현 가이드

`notebooks/` 디렉토리에는 다양한 PEFT 방법을 구현하기 위한 실용적인 튜토리얼과 예제가 포함되어 있습니다. `load_lora_adapter_example.ipynb`에서 기본 소개를 살펴본 다음, `lora_finetuning.ipynb`를 통해 LoRA와 SFT를 사용한 모델 미세 조정 과정을 더 자세히 탐구해 보세요.

PEFT 방법을 구현할 때는 LoRA의 랭크를 4~8 정도의 작은 값으로 설정하고 학습 손실을 지속적으로 모니터링하는 것이 좋습니다. 과적합을 방지하기 위해 검증 세트를 활용하고 가능하다면 전체 미세 조정 기준선과 결과를 비교하세요. 다양한 태스크에서 각 방법의 효과는 다를 수 있으므로 실험을 통해 최적의 방법을 찾는 것이 중요합니다.

## OLoRA

[OLoRA](https://arxiv.org/abs/2406.01775)는 LoRA 어댑터 초기화를 위해 QR 분해를 활용합니다. OLoRA는 모델의 기본 가중치를 QR 분해 계수에 따라 변환합니다. 즉, 모델 학습 전에 가중치를 변경합니다. 이 접근 방식은 안정성을 크게 향상시키고 수렴 속도를 빠르게 하여, 궁극적으로 더 우수한 성능을 달성합니다.

## PEFT와 함께 TRL 사용하기

효율적인 미세 조정을 위해 PEFT 방법을 TRL(Transformers Reinforcements Learning)과 결합할 수 있습니다. 이러한 통합은 메모리 요구사항을 줄여주기 때문에 RLHF (Reinforcement Learning from Human Feedback)에 특히 유용합니다.

```python
from peft import LoraConfig
from transformers import AutoModelForCausalLM

# PEFT configuration 설정
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

# 특정 디바이스에서 모델 불러오기
model = AutoModelForCausalLM.from_pretrained(
    "your-model-name",
    load_in_8bit=True,  # 선택 사항: 8비트 정밀도 사용
    device_map="auto",
    peft_config=lora_config
)
```

위 코드에서 `device_map="auto"`를 사용해 모델을 적절한 디바이스에 자동으로 할당했습니다. `device_map={"": device_index}`를 써서 모델을 특정 디바이스에 직접 할당할 수도 있습니다. 또한, 메모리 사용량을 효율적으로 유지하면서 여러 GPU에 걸쳐 학습을 확장할 수도 있습니다.

## 기본적인 병합 구현

LoRA 어댑터 학습이 끝나면 어댑터 가중치를 기본 모델에 합칠 수 있습니다. 합치는 방법은 다음과 같습니다:

```python
import torch
from transformers import AutoModelForCausalLM
from peft import PeftModel

# 1. 기본 모델 불러오기
base_model = AutoModelForCausalLM.from_pretrained(
    "base_model_name",
    dtype=torch.float16,
    device_map="auto"
)

# 2. 어댑터가 있는 PEFT 모델 불러오기
peft_model = PeftModel.from_pretrained(
    base_model,
    "path/to/adapter",
    dtype=torch.float16
)

# 3. 어댑터 가중치를 기본 모델에 병합하기
try:
    merged_model = peft_model.merge_and_unload()
except RuntimeError as e:
    print(f"Merging failed: {e}")
    # fallback 전략 또는 메모리 최적화 구현

# 4. 병합된 모델 저장
merged_model.save_pretrained("path/to/save/merged_model")
```

저장된 모델의 크기가 일치하지 않으면 토크나이저도 함께 저장했는지 확인하세요:

```python
# 모델과 토크나이저를 모두 저장
tokenizer = AutoTokenizer.from_pretrained("base_model_name")
merged_model.save_pretrained("path/to/save/merged_model")
tokenizer.save_pretrained("path/to/save/merged_model")
```

## 다음 단계

⏩ [프롬프트 튜닝](prompt_tuning.md) 가이드로 이동해 프롬프트 튜닝으로 미세 조정하는 법을 배워보세요.
⏩ [LoRA 어댑터 튜토리얼](../../../notebooks/ko/3_parameter_efficient_finetuning/load_lora_adapter.ipynb)에서 LoRA 어댑터를 불러오는 방법을 배워보세요.

# 참고

- [LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS](https://arxiv.org/pdf/2106.09685)
- [Hugging Face PEFT 문서](https://huggingface.co/docs/peft)
- [Hugging Face blog post on PEFT](https://huggingface.co/blog/peft)


<EditOnGithub source="https://github.com/huggingface/smol-course/blob/main/units/ko/unit3/2.md" />
