🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Instruction Tuning과 RLHF 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 2. · 13 Views

Instruction Tuning과 RLHF 완벽 가이드

대규모 언어 모델을 사람의 의도에 맞게 학습시키는 핵심 기법인 Instruction Tuning과 RLHF를 초급 개발자도 이해할 수 있도록 설명합니다. 실제 코드 예제와 함께 SFT부터 PPO까지 단계별로 알아봅니다.


목차

  1. Instruction_Tuning_개념
  2. 데이터셋_구성_방법
  3. SFT_Supervised_Fine_tuning
  4. RLHF_원리
  5. Reward_Model_학습
  6. PPO_알고리즘_기초

1. Instruction Tuning 개념

김개발 씨는 회사에서 챗봇 프로젝트를 맡게 되었습니다. GPT 같은 대규모 언어 모델을 사용하면 될 것 같았는데, 막상 적용해보니 질문에 엉뚱한 대답만 늘어놓습니다.

"모델이 똑똑하다던데, 왜 내 말을 못 알아듣는 거지?"

Instruction Tuning은 한마디로 AI에게 "지시를 따르는 법"을 가르치는 것입니다. 마치 신입사원에게 업무 매뉴얼을 주고 "이렇게 하면 돼요"라고 알려주는 것과 같습니다.

이 과정을 거치면 모델이 사용자의 의도를 정확히 파악하고 원하는 형식으로 응답할 수 있게 됩니다.

다음 코드를 살펴봅시다.

# Instruction Tuning 데이터 형식 예시
instruction_data = {
    "instruction": "다음 문장을 영어로 번역해주세요.",
    "input": "오늘 날씨가 정말 좋습니다.",
    "output": "The weather is really nice today."
}

# 학습용 프롬프트 구성
def format_instruction(example):
    prompt = f"### 지시사항:\n{example['instruction']}\n\n"
    prompt += f"### 입력:\n{example['input']}\n\n"
    prompt += f"### 응답:\n{example['output']}"
    return prompt

# 실제 학습 데이터로 변환
formatted = format_instruction(instruction_data)
print(formatted)

김개발 씨는 입사 6개월 차 ML 엔지니어입니다. 최근 회사에서 고객 상담용 챗봇을 만들라는 미션을 받았습니다.

"요즘 GPT가 대세라던데, 그거 쓰면 되겠지"라고 생각하며 기본 언어 모델을 적용했습니다. 그런데 결과는 참담했습니다.

"환불 절차를 알려주세요"라고 물으면, 모델은 환불에 관한 위키피디아 스타일의 설명을 장황하게 늘어놓았습니다. 정작 원하는 "1단계: 마이페이지 접속, 2단계: 주문내역 클릭..."같은 안내는 해주지 않았습니다.

선배 개발자 박시니어 씨가 다가와 물었습니다. "혹시 Instruction Tuning 해봤어요?" 그렇다면 Instruction Tuning이란 정확히 무엇일까요?

쉽게 비유하자면, 기본 언어 모델은 수많은 책을 읽은 박식한 학자와 같습니다. 이 학자는 세상의 온갖 지식을 알고 있지만, 정작 "이것 좀 해주세요"라는 요청에는 서툽니다.

질문을 하면 관련된 모든 정보를 쏟아내거나, 질문을 이어서 완성하려고 하죠. Instruction Tuning은 이 박식한 학자에게 "비서 교육"을 시키는 것입니다.

"지시가 들어오면 이렇게 응답하면 됩니다"라고 수천, 수만 개의 예시를 보여주는 거죠. 이 과정이 왜 필요할까요?

기본 언어 모델은 인터넷의 방대한 텍스트로 학습됩니다. 이 텍스트들은 대부분 "다음 단어 예측"에 최적화되어 있습니다.

하지만 실제 서비스에서는 "사용자의 의도를 파악하고 적절히 응답하는 것"이 필요합니다. 이 간극을 메우는 것이 바로 Instruction Tuning입니다.

위의 코드를 살펴보겠습니다. 데이터는 세 부분으로 구성됩니다.

instruction은 모델에게 무엇을 해야 하는지 알려줍니다. input은 처리해야 할 실제 데이터입니다.

output은 기대하는 정답입니다. format_instruction 함수는 이 세 요소를 하나의 학습용 텍스트로 조합합니다.

모델은 이런 형식의 데이터를 수만 개 학습하면서 "지시를 따르는 법"을 배웁니다. 실제 현업에서는 다양한 종류의 지시를 포함시킵니다.

번역, 요약, 질의응답, 코드 생성, 감정 분석 등 다양한 태스크를 학습시켜 모델의 범용성을 높입니다. 주의할 점도 있습니다.

단순히 데이터 양만 늘린다고 좋은 것이 아닙니다. 데이터의 다양성과 품질이 더 중요합니다.

편향된 데이터로 학습하면 편향된 모델이 나옵니다. 다시 김개발 씨 이야기로 돌아가 봅시다.

박시니어 씨의 조언을 듣고 Instruction Tuning을 적용한 결과, 챗봇은 드디어 "환불 절차를 알려주세요"라는 질문에 깔끔한 단계별 안내를 제공하기 시작했습니다.

실전 팁

💡 - instruction은 구체적이고 명확할수록 모델이 잘 따릅니다

  • 다양한 표현 방식의 지시를 포함시켜 일반화 성능을 높이세요

2. 데이터셋 구성 방법

Instruction Tuning의 개념을 이해한 김개발 씨는 바로 실행에 옮기려 했습니다. 그런데 막상 시작하려니 막막했습니다.

"데이터를 어떻게 모으지? 직접 다 만들어야 하나?" 수만 개의 고품질 데이터를 만드는 것은 생각만 해도 막막한 일이었습니다.

Instruction 데이터셋은 크게 세 가지 방법으로 구성할 수 있습니다. 첫째, 기존 NLP 데이터셋을 instruction 형식으로 변환하는 방법입니다.

둘째, 사람이 직접 작성하는 방법입니다. 셋째, 더 강력한 AI 모델을 활용해 생성하는 방법입니다.

다음 코드를 살펴봅시다.

# 방법 1: 기존 데이터셋 변환 (예: 감정 분석 데이터)
def convert_sentiment_to_instruction(original):
    return {
        "instruction": "다음 리뷰의 감정을 분석해주세요.",
        "input": original["review_text"],
        "output": "긍정" if original["label"] == 1 else "부정"
    }

# 방법 2: Self-Instruct 방식 (GPT-4 활용)
import openai

def generate_instruction_data(seed_task):
    response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=[{
            "role": "user",
            "content": f"'{seed_task}'와 유사하지만 다른 지시-응답 쌍을 만들어주세요."
        }]
    )
    return response.choices[0].message.content

# 방법 3: 다양성 확보를 위한 템플릿
templates = [
    "다음을 요약해주세요: {text}",
    "아래 내용을 한 문장으로 줄여주세요: {text}",
    "{text}\n\n위 글의 핵심을 정리해주세요."
]

김개발 씨는 데이터 수집 방법을 고민하다가 박시니어 씨를 찾아갔습니다. "선배, 데이터를 어떻게 구하죠?

수만 개를 직접 만들 수는 없잖아요." 박시니어 씨가 웃으며 대답했습니다. "다 직접 만들 필요 없어요.

영리하게 접근하면 됩니다." 첫 번째 방법은 기존 데이터셋의 재활용입니다. 세상에는 이미 수많은 NLP 데이터셋이 존재합니다.

감정 분석, 번역, 질의응답 등 다양한 태스크의 데이터가 공개되어 있죠. 이것들을 instruction 형식으로 변환하면 됩니다.

위 코드의 convert_sentiment_to_instruction 함수가 바로 그 예시입니다. 기존 감정 분석 데이터에 "다음 리뷰의 감정을 분석해주세요"라는 지시를 붙이면 instruction 데이터가 완성됩니다.

같은 원리로 번역 데이터, QA 데이터 등을 모두 변환할 수 있습니다. 두 번째 방법은 Self-Instruct 기법입니다.

이름 그대로 AI가 스스로 instruction을 만들어내는 방식입니다. GPT-4 같은 강력한 모델에게 "이런 유형의 지시-응답 쌍을 만들어줘"라고 요청하는 거죠.

이 방법의 장점은 확장성입니다. 소수의 시드 데이터만 있으면 수천, 수만 개의 데이터를 빠르게 생성할 수 있습니다.

실제로 Stanford의 Alpaca 모델은 단 175개의 시드 데이터에서 52,000개의 instruction 데이터를 생성했습니다. 세 번째 방법은 템플릿 활용입니다.

같은 태스크라도 여러 가지 방식으로 지시할 수 있습니다. "요약해주세요", "한 문장으로 줄여주세요", "핵심을 정리해주세요"는 모두 같은 요청이지만 표현이 다릅니다.

다양한 템플릿을 사용하면 모델의 일반화 능력이 향상됩니다. 실제 프로젝트에서는 이 세 방법을 조합합니다.

기존 데이터셋으로 기본 골격을 만들고, Self-Instruct로 양을 늘리고, 템플릿으로 다양성을 확보합니다. 마지막으로 사람이 직접 검수하여 품질을 보장합니다.

주의할 점은 데이터 오염입니다. AI가 생성한 데이터에는 할루시네이션이 포함될 수 있습니다.

따라서 생성된 데이터를 그대로 쓰지 말고 반드시 필터링 과정을 거쳐야 합니다. 김개발 씨는 고개를 끄덕였습니다.

"그러니까 똑똑하게 조합하면 되는 거군요!" 이제 데이터 구축의 큰 그림이 보이기 시작했습니다.

실전 팁

💡 - 처음에는 공개된 instruction 데이터셋(Alpaca, Dolly 등)으로 시작해보세요

  • AI 생성 데이터는 반드시 품질 검수 과정을 거쳐야 합니다

3. SFT Supervised Fine tuning

데이터가 준비되었습니다. 이제 본격적으로 모델을 학습시킬 차례입니다.

김개발 씨는 "Fine-tuning이요? 그냥 학습시키면 되는 거 아닌가요?"라고 물었습니다.

박시니어 씨가 고개를 저었습니다. "단순히 돌리기만 하면 안 돼요.

몇 가지 알아야 할 것들이 있습니다."

**SFT(Supervised Fine-tuning)**는 준비된 instruction 데이터셋으로 사전학습된 모델을 미세조정하는 과정입니다. 마치 대학교를 졸업한 신입사원에게 회사 업무를 가르치는 것과 같습니다.

기본 지식은 있으니 실무에 맞게 다듬어주는 것이죠.

다음 코드를 살펴봅시다.

from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers import TrainingArguments, Trainer
from peft import LoraConfig, get_peft_model

# 기본 모델 로드
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b")

# LoRA 설정 (효율적인 파인튜닝)
lora_config = LoraConfig(
    r=16,                    # rank: 작을수록 가벼움
    lora_alpha=32,           # 스케일링 파라미터
    target_modules=["q_proj", "v_proj"],  # 어텐션 레이어만 학습
    lora_dropout=0.1
)
model = get_peft_model(model, lora_config)

# 학습 설정
training_args = TrainingArguments(
    output_dir="./sft_model",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    learning_rate=2e-5,
    warmup_ratio=0.1
)

SFT는 RLHF 파이프라인의 첫 번째 단계입니다. 아무리 좋은 강화학습 알고리즘이 있어도, 기본기가 없으면 소용없습니다.

운동선수가 고급 기술을 배우기 전에 기초 체력을 다지는 것처럼, 모델도 먼저 기본적인 instruction following 능력을 갖춰야 합니다. 그렇다면 왜 LoRA를 사용할까요?

7B 파라미터 모델을 전체 학습시키려면 엄청난 GPU 메모리가 필요합니다. 일반적인 회사에서는 감당하기 어려운 수준이죠.

LoRA는 이 문제를 해결합니다. 모델의 모든 파라미터를 학습시키는 대신, 작은 어댑터 레이어만 학습시키는 것입니다.

위 코드에서 r=16은 LoRA의 rank를 의미합니다. 이 값이 작을수록 학습 파라미터가 줄어들지만, 너무 작으면 성능이 떨어집니다.

16은 일반적으로 좋은 균형점입니다. target_modules에서 q_proj와 v_proj만 지정한 것도 중요합니다.

트랜스포머의 어텐션 레이어만 학습시키는 것인데, 연구에 따르면 이것만으로도 충분한 성능을 얻을 수 있습니다. 학습률(learning_rate)은 2e-5로 설정했습니다.

사전학습된 모델을 미세조정할 때는 학습률을 낮게 잡아야 합니다. 너무 높으면 기존에 배운 지식을 잊어버리는 Catastrophic Forgetting 현상이 발생합니다.

warmup_ratio는 학습 초기에 학습률을 천천히 올리는 설정입니다. 처음부터 높은 학습률로 시작하면 모델이 불안정해질 수 있기 때문입니다.

실무에서는 학습 중간중간 모델을 평가해야 합니다. 손실값이 줄어든다고 무조건 좋은 것이 아닙니다.

실제로 instruction을 잘 따르는지 정성적으로 평가하는 것이 중요합니다. 김개발 씨가 물었습니다.

"그런데 SFT만으로는 부족한 건가요?" 박시니어 씨가 답했습니다. "SFT는 시작일 뿐이에요.

진짜 마법은 RLHF에서 일어납니다."

실전 팁

💡 - 처음에는 LoRA rank를 16으로 시작하고, 필요시 조정하세요

  • 학습률은 1e-5에서 5e-5 사이에서 실험해보세요

4. RLHF 원리

SFT로 기본기를 갖춘 모델이 완성되었습니다. 하지만 김개발 씨는 여전히 불만이었습니다.

"문법적으로 맞는 답변은 하는데, 뭔가 어색해요. 사람처럼 자연스럽지가 않아요." 이것이 바로 RLHF가 필요한 이유입니다.

**RLHF(Reinforcement Learning from Human Feedback)**는 사람의 선호도를 학습에 반영하는 기법입니다. 마치 요리사가 손님들의 피드백을 받아 레시피를 개선하는 것과 같습니다.

"이 답변이 더 좋아요"라는 인간의 판단을 모델이 학습하게 됩니다.

다음 코드를 살펴봅시다.

# RLHF 파이프라인 개요
class RLHFPipeline:
    def __init__(self, sft_model, reward_model):
        self.policy = sft_model      # SFT로 학습된 정책 모델
        self.reward = reward_model   # 인간 선호도를 학습한 보상 모델
        self.ref_policy = sft_model.copy()  # 참조 정책 (KL 페널티용)

    def generate_response(self, prompt):
        # 현재 정책으로 응답 생성
        response = self.policy.generate(prompt)
        return response

    def compute_reward(self, prompt, response):
        # 보상 모델로 점수 계산
        score = self.reward.predict(prompt, response)
        # KL divergence 페널티 추가
        kl_penalty = self.compute_kl(response)
        return score - 0.1 * kl_penalty

    def update_policy(self, rewards):
        # PPO로 정책 업데이트
        self.policy.ppo_step(rewards)

왜 SFT만으로는 부족할까요? SFT는 "정답"을 알려주는 방식입니다.

하지만 언어에는 정답이 하나가 아닙니다. "오늘 날씨 어때요?"라는 질문에 "좋습니다", "화창합니다", "맑고 따뜻합니다" 모두 좋은 답변입니다.

그런데 어떤 답변이 더 좋을까요? 이것은 상황과 맥락에 따라 다릅니다.

RLHF는 이 문제를 해결합니다. 사람들에게 "A와 B 중 어떤 답변이 더 좋은가요?"라고 물어보고, 그 선호도를 학습시키는 것입니다.

RLHF는 세 단계로 이루어집니다. 첫째, SFT로 기본 모델을 만듭니다.

둘째, 인간 피드백으로 Reward Model을 학습시킵니다. 셋째, 이 Reward Model의 점수를 높이는 방향으로 정책을 업데이트합니다.

위 코드에서 ref_policy는 중요한 역할을 합니다. 강화학습만 하면 모델이 보상만 높이려고 이상한 방향으로 갈 수 있습니다.

이를 Reward Hacking이라고 합니다. 참조 정책과 너무 다르면 페널티를 주어 이를 방지합니다.

이것이 KL Divergence 페널티입니다. compute_reward 함수를 보면, 단순히 보상 점수만 반환하지 않습니다.

KL 페널티를 빼줍니다. 0.1은 페널티의 강도를 조절하는 하이퍼파라미터입니다.

이 값이 크면 원래 모델에서 크게 벗어나지 않고, 작으면 더 자유롭게 변할 수 있습니다. 실제 ChatGPT, Claude 같은 모델들이 자연스럽게 대화하는 비결이 바로 RLHF입니다.

수만 명의 평가자들이 "이 답변이 더 좋다"라고 선택한 데이터로 모델을 개선한 결과입니다. 김개발 씨가 감탄했습니다.

"그래서 ChatGPT가 그렇게 자연스러운 거군요!" 하지만 아직 배울 것이 남았습니다. Reward Model은 어떻게 만들까요?

실전 팁

💡 - KL 페널티 계수는 0.01에서 0.2 사이에서 실험해보세요

  • RLHF는 계산 비용이 높으므로 작은 모델로 먼저 검증하세요

5. Reward Model 학습

RLHF의 핵심은 Reward Model입니다. 김개발 씨가 물었습니다.

"인간이 일일이 점수를 매기는 건 불가능하잖아요. 어떻게 하는 거죠?" 박시니어 씨가 대답했습니다.

"바로 그래서 Reward Model을 따로 학습시키는 겁니다. 인간의 판단을 모방하는 모델을요."

Reward Model은 주어진 응답이 얼마나 좋은지 점수를 매기는 모델입니다. 사람들의 선호도 데이터를 학습하여, 새로운 응답에 대해서도 "인간이라면 이 정도로 평가했을 것"이라는 점수를 예측합니다.

마치 와인 소믈리에가 맛을 평가하는 것처럼, AI가 응답의 품질을 판별합니다.

다음 코드를 살펴봅시다.

import torch
import torch.nn as nn
from transformers import AutoModel

class RewardModel(nn.Module):
    def __init__(self, base_model_name):
        super().__init__()
        self.backbone = AutoModel.from_pretrained(base_model_name)
        self.reward_head = nn.Linear(self.backbone.config.hidden_size, 1)

    def forward(self, input_ids, attention_mask):
        outputs = self.backbone(input_ids, attention_mask=attention_mask)
        last_hidden = outputs.last_hidden_state[:, -1, :]  # 마지막 토큰
        reward = self.reward_head(last_hidden)
        return reward

# Bradley-Terry 손실 함수 (선호도 학습)
def compute_preference_loss(reward_chosen, reward_rejected):
    # chosen이 rejected보다 높은 점수를 받도록 학습
    loss = -torch.log(torch.sigmoid(reward_chosen - reward_rejected))
    return loss.mean()

# 학습 데이터 예시
preference_data = {
    "prompt": "Python에서 리스트를 정렬하는 방법은?",
    "chosen": "sorted() 함수나 list.sort() 메서드를 사용합니다.",
    "rejected": "정렬은 어렵습니다. 직접 구현해야 합니다."
}

Reward Model 학습의 핵심은 비교 데이터입니다. 절대적인 점수가 아닌, "A가 B보다 낫다"는 상대적 판단을 수집합니다.

왜 상대 비교를 사용할까요? 사람에게 "이 답변은 10점 만점에 몇 점인가요?"라고 물으면 답하기 어렵습니다.

하지만 "A와 B 중 어떤 게 더 낫나요?"는 훨씬 쉽습니다. 이런 비교 데이터가 더 일관성 있고 수집하기도 쉽습니다.

위 코드의 RewardModel 클래스를 살펴봅시다. 기존 언어 모델을 백본으로 사용하고, 마지막에 선형 레이어를 추가합니다.

이 레이어가 하나의 스칼라 값, 즉 보상 점수를 출력합니다. 왜 마지막 토큰을 사용할까요?

전체 응답을 읽은 후의 hidden state가 응답 전체의 품질을 담고 있다고 가정하기 때문입니다. 마치 책을 다 읽은 후에 "이 책 어땠어?"라고 평가하는 것과 같습니다.

compute_preference_loss 함수가 핵심입니다. 이것은 Bradley-Terry 모델에 기반한 손실 함수입니다.

chosen 응답의 보상이 rejected 응답보다 높으면 손실이 낮아지고, 그 반대면 높아집니다. 수식을 풀어보면 간단합니다.

sigmoid(reward_chosen - reward_rejected)는 chosen이 더 좋을 확률입니다. 이 확률의 로그를 최대화하면, 자연스럽게 chosen에 높은 점수를, rejected에 낮은 점수를 주게 됩니다.

실무에서 중요한 것은 데이터 품질입니다. 평가자들의 의견이 일치하지 않는 경우도 많습니다.

같은 응답에 어떤 사람은 A가 낫다 하고, 다른 사람은 B가 낫다고 합니다. 이런 노이즈를 줄이기 위해 여러 평가자의 의견을 종합하고, 일관성 있는 평가자의 데이터에 가중치를 높이 줍니다.

김개발 씨가 궁금해했습니다. "그래서 이 Reward Model로 뭘 하는 건가요?" 다음 단계, PPO 알고리즘에서 이 점수를 활용하여 정책을 개선합니다.

실전 팁

💡 - 평가 데이터는 최소 수천 쌍 이상 수집해야 안정적인 모델이 됩니다

  • 평가자 간 일치도(Inter-annotator agreement)를 꼭 측정하세요

6. PPO 알고리즘 기초

모든 준비가 끝났습니다. SFT 모델도 있고, Reward Model도 있습니다.

이제 마지막 단계, 실제로 모델을 개선하는 강화학습 차례입니다. 김개발 씨가 긴장한 표정으로 물었습니다.

"강화학습이요? 그거 엄청 어렵다던데..." 박시니어 씨가 웃었습니다.

"PPO를 이해하면 생각보다 어렵지 않아요."

**PPO(Proximal Policy Optimization)**는 안정적이고 효율적인 강화학습 알고리즘입니다. 핵심 아이디어는 "한 번에 너무 많이 바꾸지 말자"입니다.

마치 다이어트를 할 때 급격한 변화보다 점진적인 변화가 더 효과적인 것처럼, 정책도 조금씩 안정적으로 개선합니다.

다음 코드를 살펴봅시다.

import torch
from trl import PPOConfig, PPOTrainer
from transformers import AutoModelForCausalLMWithValueHead

# PPO 설정
ppo_config = PPOConfig(
    learning_rate=1e-5,
    batch_size=128,
    mini_batch_size=16,
    ppo_epochs=4,           # 한 배치를 몇 번 반복 학습할지
    cliprange=0.2,          # 정책 변화 제한 (핵심!)
    vf_coef=0.1,            # Value function 손실 계수
    gamma=1.0,              # 할인율 (언어 모델에선 보통 1.0)
    kl_penalty="kl",        # KL divergence 페널티 방식
    init_kl_coef=0.2        # KL 페널티 초기 계수
)

# PPO Trainer 초기화
ppo_trainer = PPOTrainer(
    config=ppo_config,
    model=policy_model,
    ref_model=ref_model,
    tokenizer=tokenizer
)

# 학습 루프 (한 스텝)
def train_step(prompts, responses, rewards):
    stats = ppo_trainer.step(prompts, responses, rewards)
    print(f"평균 보상: {stats['ppo/mean_scores']:.3f}")
    print(f"KL divergence: {stats['objective/kl']:.4f}")
    return stats

강화학습의 가장 큰 문제는 불안정성입니다. 조금만 잘못 업데이트해도 모델이 완전히 망가질 수 있습니다.

특히 언어 모델처럼 복잡한 환경에서는 더욱 그렇습니다. PPO는 이 문제를 clipping으로 해결합니다.

정책이 한 번에 바뀔 수 있는 정도를 제한하는 것입니다. 위 코드에서 cliprange=0.2가 핵심입니다.

이것은 "정책의 확률 비율이 0.8에서 1.2 사이를 벗어나면 무시하겠다"는 의미입니다. 아무리 보상이 높아도 너무 급격한 변화는 막는 것이죠.

비유하자면 이렇습니다. 운전을 배우는 초보 운전자가 있습니다.

급커브에서 핸들을 확 꺾으면 사고가 납니다. 그래서 핸들 조작에 제한을 두는 거죠.

PPO의 clipping도 같은 원리입니다. ppo_epochs=4는 같은 데이터로 4번 반복 학습한다는 뜻입니다.

한 번 수집한 데이터를 여러 번 사용하여 효율성을 높입니다. 다만 너무 많이 반복하면 오버피팅이 될 수 있으므로 적절한 값을 찾아야 합니다.

kl_penalty와 init_kl_coef는 앞서 설명한 KL divergence 페널티입니다. 원래 모델에서 너무 멀어지지 않도록 제동을 걸어줍니다.

학습 과정에서 모니터링해야 할 것들이 있습니다. 평균 보상은 점점 올라가야 합니다.

KL divergence는 적당한 범위 내에 있어야 합니다. 너무 낮으면 학습이 안 되는 것이고, 너무 높으면 모델이 불안정해집니다.

실무에서 PPO 튜닝은 까다롭습니다. 하이퍼파라미터가 많고, 잘못 설정하면 학습이 수렴하지 않습니다.

처음에는 검증된 설정으로 시작하고, 조금씩 조정하는 것을 권장합니다. 김개발 씨가 마지막으로 물었습니다.

"이렇게 학습하면 얼마나 걸려요?" 박시니어 씨가 답했습니다. "모델 크기와 데이터에 따라 다르지만, 보통 수천 스텝은 돌려야 효과가 보여요.

인내심이 필요한 작업입니다." 이렇게 Instruction Tuning부터 RLHF까지의 여정이 끝났습니다. 김개발 씨의 챗봇은 이제 사람처럼 자연스럽게 대화할 수 있게 되었습니다.

실전 팁

💡 - cliprange는 0.1에서 0.3 사이가 일반적입니다

  • 학습 중 KL divergence가 10을 넘으면 학습률을 낮춰보세요
  • TRL 라이브러리를 활용하면 PPO 구현이 훨씬 쉬워집니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#LLM#InstructionTuning#RLHF#SFT#PPO

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.