AWS Machine Learning출처 게시일

Amazon SageMaker HyperPod에서 GPT-OSS-20B를 다국어 추론용으로 파인튜닝하기

GPT-OSS-20B는 영어로 사고하는 오픈 웨이트 추론 모델입니다. 프랑스어, 독일어, 스페인어 또는 이탈리아어로 추론하라고 요청하면 해당 지시를 인지한 뒤에도 체인 오브 소트(chain-of-thought)를 결국 영어로 생성합니다.

GPT-OSS-20B는 영어로 사고하는 오픈 웨이트 추론 모델입니다. 프랑스어, 독일어, 스페인어 또는 이탈리아어로 추론하라고 요청하면 해당 지시를 인지한 뒤에도 체인 오브 소트(chain-of-thought)를 결국 영어로 생성합니다. 50개 예제로 구성된 다국어 추론 테스트에서 베이스 모델은 22퍼센트의 경우에만 올바른 대상 언어로 추론했습니다. 그 22퍼센트는 거의 전부 영어 예제였습니다(영어 100퍼센트, 프랑스어 0퍼센트, 독일어 10퍼센트, 스페인어 0퍼센트, 이탈리아어 0퍼센트).

영어가 아닌 언어를 사용하는 사용자를 위해 추론 모델을 배포하는 팀에게 이 격차는 중요합니다. 프랑스어로 질문하는 사용자는 모델이 영어로 중간에 전환하지 않고 프랑스어로 추론하고 답변하기를 기대합니다. 이 격차를 메우는 것은 파인튜닝 문제입니다. 이는 오픈 웨이트 모델을 커스터마이징하기 시작하는 모든 팀이 마주하는 질문을 제기합니다. 지도 파인튜닝(SFT), Group Relative Policy Optimization(GRPO)을 활용한 강화 학습, 아니면 둘 다 중 무엇일까요?

이 게시물에서는 Amazon SageMaker HyperPod에서 GPT-OSS-20B를 다국어 추론용으로 파인튜닝한 과정을 Amazon SageMaker HyperPod소개합니다. SFT만으로 충분했던 경우와 GRPO가 그 위에 측정 가능한 가치를 더한 경우를 보여드립니다. GRPO가 언제 도움이 되는지 더 폭넓게 이해하기 위해, 서로 다른 역량 격차를 가진 두 작업에 대해 제어된 Qwen2.5-7B 실험도 수행했습니다. 요약하면 다음과 같습니다. SFT가 대부분의 작업을 수행하고, GRPO는 개선할 여지가 있을 때 다듬으며, 역량 격차에 맞는 기법을 선택하는 것이 결과를 결정합니다.

솔루션 개요

이 섹션에서는 다국어 추론 작업 및 데이터 세트, SFT와 GRPO가 서로를 어떻게 보완하는지, 그리고 Amazon SageMaker HyperPod에서 실행한 학습 스택을 다룹니다.

작업 및 데이터 세트

데이터 세트는 HuggingFaceH4/Multilingual-Thinking 입니다. 영어와 함께 프랑스어, 스페인어, 독일어, 이탈리아어로 번역된 체인 오브 소트 추론 데이터 세트로, 대략 949개의 학습 예제와 50개의 검증 예제를 포함합니다. 모델은 reasoning language: 시스템 프롬프트 지시를 받고, 강력한 영어 선향을 뛰어넘어 해당 대상 언어로 추론하고 답변해야 합니다. 평가는 50개 테스트 케이스로 구성됩니다. 5개 언어(EN/FR/DE/ES/IT)에 걸쳐 10개의 수학/논리 문제입니다.

두 가지 지표가 중요합니다:

  • 추론 언어 정확성 – 체인 오브 소트가 요청된 언어로 되어 있는가?
  • 답변 언어 정확성 – 최종 답변이 요청된 언어로 되어 있는가?

SFT와 GRPO의 결합 방식

두 기법을 생각하는 가장 명확한 방법은 다음과 같습니다. SFT는 모델이 갖고 있지 않은 동작을 가르칩니다. GRPO는 모델이 이미 때때로 생성할 수 있는 동작을 최적화합니다. GRPO는 프롬프트당 응답 그룹을 샘플링하고 정책을 평균 이상의 응답 쪽으로 밀어붙이는 방식으로 작동합니다. 원하는 동작이 베이스 분포에서 확률 0이라면 GRPO가 강화할 것이 거의 없습니다. 이 하나의 아이디어가 이 게시물의 거의 모든 결과를 설명합니다.

학습 스택

Amazon Elastic Kubernetes Service(Amazon EKS) 오케스트레이션과 함께 Amazon SageMaker HyperPod에서 실행했습니다. GPT-OSS-20B에 대한 초기 SFT 및 GRPO 실행에는 PyTorch TRL 라이브러리를 사용했습니다. Qwen 제어 실험에는 트레이너로 veRL로 전환하고, 분산 오케스트레이션에는 Ray와 KubeRay, 빠른 롤아웃 생성에는 vLLM을 사용했습니다. 체크포인트와 데이터 세트는 Amazon FSx for Lustre에 저장했으며, 노드 간 패브릭은 Elastic Fabric Adapter(EFA)를 사용했습니다. 모든 파인튜닝은 파라미터 효율적이며 SFT와 GRPO 모두에 적합한 Low-Rank Adaptation(LoRA)을 사용했습니다.

다음 다이어그램은 학습 데이터 경로를 엔드 투 엔드로 보여줍니다. 사용자의 제출물은 Amazon SageMaker HyperPod 클러스터의 Amazon EKS 컨트롤 플레인에 도착합니다. Amazon EKS는 veRL 트레이너와 vLLM 롤아웃 워커를 실행하는 Ray 헤드 포드와 워커 포드를 스케줄링합니다. 두 포드 세트 모두 베이스 모델, 학습 데이터 및 체크포인트를 위해 Amazon FSx for Lustre를 마운트합니다. 노드 간 콜렉티브는 EFA를 사용합니다. 롤아웃은 vLLM에서 veRL 트레이너로 스트리밍되고, 트레이너는 체크포인트를 Amazon FSx for Lustre에 다시 기록합니다.

그림 1: Qwen 제어 실험을 위한 veRL, Ray, KubeRay, vLLM 및 Amazon FSx for Lustre를 갖춘 Amazon SageMaker HyperPod에서의 SFT 및 GRPO 파인튜닝 엔드 투 엔드 학습 데이터 경로

다음에서는 각 단계를 더 자세히 설명합니다. 제출자는 Amazon SageMaker Studio 또는 AWS Command Line Interface(AWS CLI)에서 실행을 시작합니다. Amazon SageMaker HyperPod의 Amazon EKS 컨트롤 플레인은 GPU 노드에 포드를 배치하고 veRL 트레이너와 vLLM 롤아웃 워커를 위한 워커 포드와 함께 Ray 헤드를 시작합니다. Amazon FSx for Lustre는 베이스 모델, 학습 데이터 및 체크포인트를 위한 공유 고처리량 스토리지를 제공합니다. 학습이 완료되면 트레이너는 다운스트림 평가 또는 서빙을 위해 LoRA 어댑터를 Amazon FSx for Lustre에 다시 기록합니다.

사전 조건

따라하려면 다음이 필요합니다:

  • Amazon EKS 오케스트레이션이 있는 Amazon SageMaker HyperPod 클러스터. GPT-OSS SFT에는 4× ml.g6e.12xlarge(16× L40S 48GB)를 사용했습니다. Qwen 제어 실험에는 2× g6e.48xlarge(16× L40S)를 사용했습니다.
  • 클러스터에 마운트된 Amazon FSx for Lustre 파일 시스템과 PersistentVolumeClaim named fsx-claim at /fsx.
  • EFA가 활성화된 인스턴스와 정상 작동하는 NVIDIA Collective Communications Library(NCCL) 및 aws-ofi-nccl 멀티 노드 SFT를 위한 스택.
  • 참조 리포지토리에서 빌드한 훈련 이미지를 보관하기 위한 Amazon Elastic Container Registry(Amazon ECR)와 같은 컨테이너 레지스트리.
  • 다음을 위한 HuggingFace 액세스 토큰 openai/gpt-oss-20b 그리고 그 HuggingFaceH4/Multilingual-Thinking 데이터셋.
  • AWS 명령줄 인터페이스(AWS CLI)는 kubectl, docker, 그리고 envsubst 워크스테이션에서 사용할 수 있습니다.

훈련 환경 설정

아래에서 언급된 모든 명령어, 매니페스트 및 스크립트는 다음에 있습니다. awsome-distributed-ai GitHub 저장소는 다음 위치에 있습니다: 3.test_cases/pytorch/trl/gpt-oss-lora-grpo/. 저장소를 복제하고 테스트 케이스 디렉터리로 이동합니다:

git clone https://github.com/awslabs/awsome-distributed-ai
cd awsome-distributed-ai/3.test_cases/pytorch/trl/gpt-oss-lora-grpo

환경 템플릿을 복사한 후 편집합니다 env_vars ECR 레지스트리, 이미지 이름, 태그 및 HuggingFace 토큰을 설정하려면:

cp env_vars.example env_vars
source env_vars

학습 이미지를 빌드하여 레지스트리에 푸시하세요. 이 이미지에는 PyTorch, TRL, HuggingFace Transformers, PEFT, 그리고 학습 및 추론 스크립트가 포함되어 있습니다:

cd artifacts && ./build_push.sh && cd ..

포인트 kubectl 클러스터에 적용하고 FSx 스토리지 매니저 파드를 배포하세요. 스토리지 매니저는 체크포인트 변환과 평가 로그 검사를 위해 공유 파일 시스템에 대한 셸을 제공합니다:

aws eks update-kubeconfig --name <YOUR_CLUSTER_NAME> --region us-east-2
envsubst '$REGISTRY $IMAGE $TAG $HF_TOKEN' \
  < kubernetes/fsx-storage-manager.yaml | kubectl apply -f -

GPT-OSS-20B를 SFT 및 LoRA로 파인튜닝하기

먼저 베이스 모델을 측정한 후, SFT 실행을 구성하고 결과를 살펴봅니다.

기본 모델 격차

50건 평가 기준 GPT-OSS-20B 베이스의 점수는 22퍼센트 추론-언어 정답률 (11/50). 언어별: 영어 100 퍼센트, 프랑스어 0 퍼센트, 독일어 10 퍼센트, 스페인어 0 퍼센트, 이탈리아어 0 퍼센트. 이 모델은 지시와 무관하게 기본적으로 영어로 추론합니다.

SFT 설정

SFT 셋업은 LoRA r=8, α=16을 사용했으며, 4× ml.g6e.12xlarge(16× L40S 48GB)에서 Fully Sharded Data Parallel(FSDP) full-shard, bf16 정밀도, 그리고 gradient checkpointing을 적용해 1,000 스텝 동안 학습했습니다. 이 작업은 elastic 형태로 실행되며 HyperPodPyTorchJob Kueue가 관리하며, 다음과 함께 시작됩니다. hyperpodrun.

SFT 매니페스트를 적용합니다:

envsubst '$REGISTRY $IMAGE $TAG $HF_TOKEN' \
  < hyperpod-eks/train-lora-hyperpod-elastic-g6e.yaml | kubectl apply -f -

훈련 진행 상황 보기:

kubectl get pods -l app=gpt-oss-lora-elastic
kubectl logs -f -l app=gpt-oss-lora-elastic

손실과 그래디언트 노름이 매 스텝마다 출력됩니다. 정상적인 실행 결과는 다음과 같습니다:

{'loss': 1.035, 'grad_norm': 0.163, 'learning_rate': 0.0002, 'mean_token_accuracy': 0.716, 'epoch': 3.25}
{'loss': 1.003, 'grad_norm': 0.171, 'lr': 0.0002, 'acc': 0.722, 'epoch': 3.32}
{'loss': 0.976, 'grad_norm': 0.159, 'lr': 0.0002, 'acc': 0.726, 'epoch': 3.57}

학습이 완료되면 TRL의 GRPO 트레이너와 추론 스크립트가 기대하는 Parameter-Efficient Fine-Tuning(PEFT) 형식으로 FSDP 체크포인트를 변환합니다:

kubectl exec -it fsx-storage-manager -- python /app/convert_fsdp_checkpoint.py \
  --checkpoint /fsx/checkpoints/checkpoint-1000 \
  --output    /fsx/checkpoints/converted-peft/lora-checkpoint-1000-peft

SFT 결과와 단계별 학습 곡선

SFT 후, 모델은 올바른 언어로 추론합니다. 100퍼센트의 확률로 모든 5개 언어에서 (50/50). SFT는 이를 두 단계에 걸쳐 학습했습니다:

  • 약 200 스텝에서 모델은 대상 언어로 추론 하는 법을 학습했습니다(추론 언어 지표가 100 퍼센트에 도달).
  • 약 1000 스텝에서 모델은 추가로 대상 언어로 답변 하는 법을 학습했습니다.

최종 SFT 평가(1000 스텝):

  • 추론 언어 정확: 100 퍼센트 (50/50).
  • 답변 언어 정확: 62 퍼센트 (31/50).
  • 둘 다 정확: 62 퍼센트 (31/50).
  • 언어별 답변 정확도: FR 60 퍼센트, DE 60 퍼센트, ES 30 퍼센트, IT 60 퍼센트, EN 100 퍼센트.

핵심 요약: 여기서 SFT는 선택 사항이 아닙니다. 베이스 모델은 추론 언어 지시를 전혀 따르지 못했고, SFT는 추론 언어를 22 퍼센트에서 100 퍼센트로 끌어올렸습니다. 남은 격차는 62 퍼센트의 답변 언어입니다. 그것이 더 어려운 절반인데, 최종 답변은 짧고 영어 사전 확률이 그 부분에서 가장 강하기 때문입니다.

GRPO로 답변 언어 개선하기

답변 언어는 GRPO의 명백한 목표였습니다. SFT는 이미 100 퍼센트의 시간 동안 올바른 추론을 생성했고, 모델은 때때로 올바른 언어로 답변을 생성했으므로, 강화할 신호가 존재했습니다.

SFT 체크포인트 위에서 GRPO 실행

우리는 SFT 체크포인트에서 시작하여 TRL의 GRPOTrainer을(를) 사용해 GRPO를 실행했습니다. 설정: SFT LoRA를 로드하고, merge_and_unload을(를) 호출한 뒤, 새로운 LoRA를 추가했습니다(r=8, α=16, 약 0.068 퍼센트의 학습 가능 파라미터, 20B 중 13.6M). 학습은 프롬프트당 K=8 생성, device_map=auto, 학습률 1e-6, 그리고 10 에포크를 사용했습니다. 보상 함수는 답변 언어(±5.0), 추론 언어(±1.5), 간결성(+0.5 또는 −1.0)을 채점하여 합산 범위는 −7.5에서 +7.0이었습니다.

변환된 SFT 체크포인트에서 GRPO 실행:

envsubst '$REGISTRY $IMAGE $TAG $HF_TOKEN' \
  < kubernetes/train-grpo-singlenode.yaml | kubectl apply -f -
kubectl logs -f grpo-single

GRPO는 체크포인트를 다음 위치에 기록합니다 /fsx/checkpoints/grpo-singlenode/. 보류(held-out) 평가셋을 기준으로 최고의 체크포인트를 선택하고(이번 실행에서는 답변 언어 지표가 초반에 최고치를 기록했습니다), 이를 PEFT 형식으로 변환하여 추론 및 평가에 사용하세요.

결과(SFT 체크포인트 기준):

  • 추론 언어 확인: 100퍼센트 (판결: GRPO는 SFT가 학습시킨 것을 깨뜨리지 않았다.)
  • 답변 언어 정확성: 62~70퍼센트 (+8 포인트, 35/50).
  • 둘 다 정답: 70 퍼센트.
  • 언어별 정답률: FR 70 퍼센트, DE 80 퍼센트, ES 60 퍼센트, IT 40 퍼센트, EN 100 퍼센트.

GRPO는 추론을 100 퍼센트로 유지하면서 답변 언어 메트릭에서 실제 +8 포인트의 향상을 달성했습니다. 향상은 개선 여지가 있었던 부분에서 나왔습니다. 답변 언어는 SFT가 완전히 수렴하지 못한 간혹-correct 행동이었고, GRPO가 이를 강화했습니다.

베이스, SFT, GRPO 추론을 나란히 비교

정성적 차이를 확인하기 위해 동일한 베이스 모델을 공유하지만 서로 다른 어댑터를 로드하는 세 개의 추론 pod를 배포합니다:

envsubst '$REGISTRY $IMAGE $TAG $HF_TOKEN' \
  < kubernetes/inference-g6e-base.yaml    | kubectl apply -f -
envsubst '$REGISTRY $IMAGE $TAG $HF_TOKEN' \
  < kubernetes/inference-g6e-trained.yaml | kubectl apply -f -
envsubst '$REGISTRY $IMAGE $TAG $HF_TOKEN' \
  < kubernetes/inference-g6e-grpo.yaml    | kubectl apply -f -

동일한 프랑스어 추론 프롬프트를 각 변형에 실행합니다:

kubectl exec -it inference-base    -- python /app/inference_g6e.py \
  --reasoning_language French

kubectl exec -it inference-trained -- python /app/inference_g6e.py \
  --checkpoint /fsx/checkpoints/converted-peft/lora-checkpoint-1000-peft \
  --reasoning_language French

kubectl exec -it inference-grpo    -- python /app/inference_grpo_new.py \
  --use_grpo \
  --grpo_checkpoint /fsx/checkpoints/converted-peft/checkpoint-1470-peft \
  --reasoning_language French

베이스 pod는 지시에도 불구하고 영어로 추론합니다. SFT pod는 프랑스어로 추론하지만 종종 영어로 답변합니다. GRPO pod는 프랑스어로 추론하고 답변합니다. 앞서 수치를 생성한 전체 50-케이스 평가를 재현하려면 평가 매니페스트를 실행하고 FSx 스토리지 매니저에서 결과 파일을 읽으십시오:

envsubst '$REGISTRY $IMAGE $TAG $HF_TOKEN' \
  < kubernetes/eval-grpo.yaml | kubectl apply -f -
kubectl logs -f eval-grpo
kubectl exec fsx-storage-manager -- \
  cat /fsx/experiments/grpo_eval_checkpoint1470_*.txt

GRPO가 언제 가치를 더하는지 더 폭넓게 이해하기 위해, 서로 다른 capability 격차를 가진 두 작업에 대해 Qwen2.5-7B로 통제 실험을 수행했습니다.

Qwen2.5-7B 대조군으로 패턴 테스트

다른 모델과 다른 작업에서 "capability 격차에 기법을 맞춘다"는 논제를 테스트하기 위해 Qwen2.5-7B-Instruct로 통제 실험을 수행했습니다. 첫 번째 작업은 동일한 다국어 추론 작업(개선 여지가 있는 곳)입니다. 두 번째 작업은 모델이 이미 최대 정확도에 도달한 GSM8K입니다. 이는 내부 실험이며, 공개 repo는 아직 출시되지 않았습니다.

인프라: 2× g6e.48xlarge (16× L40S), EFA 100Gbps, FSx Lustre, Ray 2.44 + KubeRay 1.4.2, veRL v0.6.1, vLLM 0.8.4.

실험군: A = 베이스, B = SFT-only, C = SFT+GRPO.

다국어 추론 (50 케이스)

메트릭 A 베이스 B SFT C SFT+GRPO Δ GRPO
구조화된 형식 0% 92% 98% +6
추론 언어 0% 96% 98% +2
답변 언어 0% 38% 44% +6
둘 다 정답 0% 38% 44% +6

여유가 없는 과제, GSM8K

GSM8K에서 base Qwen2.5-7B는 이미 90.5 퍼센트 (181/200)을 기록합니다. 30단계의 GRPO 역시 90.5 퍼센트를 기록합니다. 대부분의 샘플링된 그룹이 전부 정답일 때 그룹 상대적 어드밴티지는 0으로 수렴하므로 학습 신호가 없습니다. 이것이 이 논문의 나머지 절반입니다: GRPO가 최적화할 대상을 가지려면 여유(pass@k >> pass@1)가 필요합니다. 여유가 없으면 이득도 없습니다.

모범 사례

  1. SFT로 시작하세요. GRPO는 기저 확률이 0인 행동을 가르칠 수 없습니다. 모델이 이미 때때로 생성하는 응답만 강화할 수 있습니다. SFT가 추론 언어를 22 퍼센트에서 100 퍼센트로 끌어올렸고, 이 연구에서 GRPO가 얻은 모든 성과는 그 SFT 체크포인트 위에 세워졌습니다.
  2. SFT와 GRPO 모두에 LoRA를 사용하세요. LoRA r=8/α=16은 파라미터 효율적이었고(학습 가능 파라미터 0.068 퍼센트), Qwen 대조 실험에서 GRPO 전 과정에서 수치적으로 안정적으로 유지되었습니다(그래드 노름 0.23, GPU당 약 11.7 GB). SFT와 GRPO가 동일한 어댑터 형태를 공유하기를 원할 때 강력한 기본 선택입니다.
  3. 기법을 격차에 맞추세요. 없는 행동에는 SFT를 사용하세요. 이미 존재하는, 때때로 정답인 행동을 다듬는 데에는 GRPO를 사용하세요. 여기서 GRPO의 현실적인 상한은 +6에서 +8점이었습니다.
  4. GPU 시간을 소비하기 전에 reward headroom을 확인하십시오. 대부분의 그룹이 모두 정답이라면(GSM8K 90.5 percent base) 그룹 상대 어드밴티지가 0으로 수렴하여 GRPO는 그래디언트를 얻지 못합니다. GRPO 실행을 시작하기 전에 headroom이 있는지 확인하십시오(pass@k >> pass@1).

리소스 정리

지속적인 요금이 부과되지 않도록 하려면 워크로드 리소스를 삭제한 후 기반 인프라를 삭제하십시오:

  1. 훈련 및 추론 pod와 job을 삭제합니다:
    kubectl delete hyperpodpytorchjob lora-hyperpod-elastic --ignore-not-found
    kubectl delete pod grpo-single inference-base inference-trained inference-grpo \
      eval-grpo fsx-storage-manager --ignore-not-found
  2. Amazon SageMaker HyperPod 클러스터 또는 해당 노드 그룹을 축소하거나 삭제합니다.
  3. 보관하려는 체크포인트를 모두 내보낸 후 Amazon FSx for Lustre 파일 시스템을 삭제합니다.
  4. 훈련 데이터 또는 체크포인트 아카이브에 사용된 Amazon Simple Storage Service(Amazon S3) 버킷이나 객체를 모두 삭제합니다.

결론

우리는 Amazon SageMaker HyperPod에서 GPT-OSS-20B를 다국어 추론용으로 파인튜닝하는 방법과 SFT와 GRPO 중 선택하는 방법을 보여주었습니다. SFT가 대부분의 작업을 수행했습니다: 추론 언어가 22 percent에서 100 percent로 향상되었습니다. GRPO는 headroom이 존재하는 곳에서(answer 62 percent to 70 percent) 실질적이고 절제된 개선을 추가했습니다. 병렬로 진행한 Qwen2.5-7B 제어 실험이 이 패턴을 확인해 주었습니다. GRPO는 개선 여지가 있던 다국어 추론에서 +6 percent를 추가했습니다. 반면 모델이 이미 최고 정확도(90.5 percent)에 도달해 있던 GSM8K에서는 아무런 이득도 추가하지 못했습니다.

의사 결정 프레임워크:

  • 모델이 전혀 수행할 수 없는 동작: 사용 SFT.
  • 때때로 수행하며 headroom이 있는 동작: 사용 SFT then GRPO 를 사용해 몇 포인트를 더 확보하십시오.
  • 모델이 이미 최고 정확도에 도달했거나 대상의 기본 확률이 0인 경우: GRPO won’t help.

직접 시도해 보려면 awsome-distributed-ai 리포지토리의 테스트 사례를 살펴보십시오. Amazon SageMaker HyperPod에 대한 자세한 내용은 service detail page 및 Amazon SageMaker HyperPod documentation을 참조하십시오. Amazon SageMaker HyperPod에서 Ray를 사용하는 방법에 대한 안내는 관련 게시물인 Ray와 Amazon SageMaker Studio를 활용하여 Amazon SageMaker HyperPod에서 분산 학습 실행하기를 참조하십시오. 해당 링크는 해당 게시물이 게시된 후 추가될 예정입니다. 댓글에서 여러분의 결과를 공유해 주십시오.

 


저자 소개

원문 출처

AWS Machine Learning

내용 안내

원문 발행 및 권리는 출처에 있습니다.

기계 번역 · 원문을 참고하세요