
NVIDIA B200에서 Gemma 4의 MMLU-Pro 점수 재현하기: 단계별 가이드
요약
NVIDIA B200 환경에서 Google의 Gemma 4 31B-IT 모델의 MMLU-Pro 성능을 재현하기 위한 기술 가이드입니다. 환경 설정부터 CUDA 13.0 및 Blackwell 아키텍처에서 발생하는 nvcc 컴파일러 버그를 해결하는 구체적인 회피책을 다룹니다.
핵심 포인트
- Gemma 4의 MMLU-Pro 점수 재현을 위한 환경 설정 방법
- NVIDIA B200 및 CUDA 13.0 기반의 하드웨어/소프트웨어 스택
- Blackwell 아키텍처에서 발생하는 nvcc -fPIC 에러 해결법
- vLLM과 lm-evaluation-harness 연동 시 주의사항
서론
Google의 Gemma 4 31B-IT는 모델 카드에 따르면 MMLU-Pro에서 약 85.2%라는 높은 점수를 달성했다. 하지만 직접 그 점수를 재현하는 것은 단순히 lm_eval 명령어를 한 번 실행하는 것보다 훨씬 어렵다. 점수는 컨텍스트 길이(Context Length), 생성 토큰 예산(Generation Token Budget), 그리고 간과하기 쉬운 미묘한 프롬프트 선택에 민감하게 좌우된다. 본 기사에서는 처음으로 동작을 확인한 시점부터 85.4~85.5%의 점수를 재현하기까지의 과정을 환경 측면의 회피책과 실험상의 막다른 길을 포함하여 기록한다.
하드웨어 및 소프트웨어 개요
하드웨어: NVIDIA B200 (Blackwell), 단일 GPU -
드라이버 / CUDA: CUDA 13.0 (Slurm 클러스터 상에서 module load) -
Python: mamba/conda를 통한 3.13 -
주요 패키지: vLLM ≥ 0.19.0, lm-evaluation-harness (0.4.13.dev0), transformers 5.5.0 -
모델: Hugging Face의 google/gemma-4-31b-it
이용 환경의 상세 내용은 여기에서 확인할 수 있습니다.
Step 1: 환경 설정하기
Python 3.13의 conda 환경을 생성하고, uv를 사용하여 의존성을 설치한다.
environment.yml
name: gemma4-env
channels:
- conda-forge
...
pyproject.toml
[project]
name = "gemma4-eval"
version = "0.1.0"
...
lm-evaluation-harness의 vLLM 연동 측에 의존성 지연이 있어, 분산 추론(Distributed Inference)을 사용하지 않는 경우에도 ray에 관한 주의사항이 있다: ray가 필요하다. 자세한 내용은 이 issue를 참조하라.
환경을 생성하고 설치한다.
mamba env create -f environment.yml
mamba activate gemma4-env
uv pip install --upgrade --index-strategy unsafe-best-match -e .
nvcc 버그 회피하기
Step 2: CUDA 12.8+ / 13.x의 Blackwell 하드웨어에서 CUDA 12.8, 12.9 또는 13.x를 사용하면 다음과 같은 에러가 발생할 가능성이 높다.
nvcc fatal: Unknown option '-fPIC'
이는 새로운 nvcc가 -fPIC나 -Wno-psabi와 같은 일부 호스트 컴파일러 플래그(Host Compiler Flags)를 이전처럼 암묵적으로 하위 C++ 컴파일러로 전달하지 않기 때문에 발생한다. Triton은 아직 이러한 플래그를 필요한 -Xcompiler 접두사(Prefix) 없이 전달하고 있다. 업스트림(Upstream)에서 수정될 때까지는, 호출을 인터셉트하여 필요한 부분에 -Xcompiler를 삽입하는 얇은 래퍼 스크립트(Wrapper Script)를 사용하는 것이 회피책이 된다.
Note: 이 회피책은 위의 CUDA 13.0 및 패키지 구성에서 nvcc fatal: Unknown option '-fPIC'가 발생했을 때 필요했던 것이다. 새로운 Triton, vLLM, CUDA에서는 먼저 shim 없이 실행해 보고, 동일한 에러가 발생하는 경우에만 적용하라.
NVCC shim 생성하기
export REAL_CUDA_PATH=/usr/local/cuda-13.0 # CUDA 설치 경로에 맞춰 조정
export SHADOW_DIR=$HOME/cuda_shadow_130
mkdir -p $SHADOW_DIR/bin
...
실제 CUDA 경로가 다른 경우에는 /usr/local/cuda-13.0을 교체한다.
실행 전 shim 환경을 export 하기
vLLM 또는 lm-eval을 호출하는 모든 셸 세션(Shell Session)에서 다음 변수를 설정해야 한다.
export NVCC="$HOME/cuda_shadow_130/bin/nvcc"
export CC="$HOME/cuda_shadow_130/bin/nvcc"
export CXX="$HOME/cuda_shadow_130/bin/nvcc"
...
LD_LIBRARY_PATH=""는 충돌하는 cuBLAS 경로를 클리어하기 위한 것이다.
Step 3: 모델이 로드되는지 확인하기
벤치마크를 실행하기 전에, vLLM이 모델을 서빙 (serve) 할 수 있는지 확인한다.
python -m vllm.entrypoints.openai.api_server \
--model google/gemma-4-31b-it \
--dtype bfloat16 \
...
동일한 노드 상의 다른 터미널에서 테스트 요청을 보낸다.
curl -s http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
...
포트(Port) 관련 주의사항: 공유 클러스터에서는 vLLM 서버는 통상적으로 동일한 Slurm 잡(Job) 내부에서만 접근 가능하다. 실행 중인 잡 내부에서 셸(Shell)을 열려면 srun --jobid <JOBID> --overlap --pty /bin/bash를 사용한다.
Step 4: MMLU-Pro 실행하기
여기에 세부적인 함정이 있다. 최종 설정이 성공하기 전에 실패했던 내용들을 압축하여 정리한다.
실패했던 설정
초기 두 가지 설정에서는 약 **55~60%**에 머물렀으며, 목표치인 약 85%를 크게 밑돌았다.
0-shot, → 약 55% mmlu_pro 태스크, system instruction 없음, max_gen_toks=4096, max_model_len=32768
위와 동일하지만, → 약 59.98% <thought>를 앞에 붙인 system instruction 있음
이러한 낮은 점수는 모델의 진정한 능력으로 해석해서는 안 된다. 답변 추출(Answer extraction)이나 프롬프트 형식의 불일치로 인해 발생했을 가능성이 높다.
안정적인 베이스라인 (83.4%)
vLLM 인자에 reasoning_parser=gemma4를 추가하고, 적절한 system instruction을 사용하면서 0-shot, max_model_len=32768, max_gen_toks=4096 상태를 유지하면, 여러 시드(seed)에서 안정적으로 **83.4%**를 얻을 수 있었다.
seed 1235 → 83.48%
seed 1236 → 83.39%
seed 1237 → 83.40%
...
이 결과를 도출한 명령어는 다음과 같다.
MODEL_NAME="google/gemma-4-31b-it"
SEED=1234
lm_eval --model vllm \
...
어블레이션 실험 (Ablation Study, 최대 85.4%)
2026-04-27에 몇 가지 프로토콜 변형을 대상으로 실험을 수행했다. 결과는 다음과 같다.
| 실험 | 점수 |
|---|---|
| 결정론적 베이스라인 (동일 설정, 명시적 seed) | 83.69% |
system instruction에 <thought> 태그를 넣지 않음 | 85.42% |
| system instruction 없음 | 85.33% |
--fewshot_as_multiturn이 포함된 5-shot CoT | 85.11% |
--fewshot_as_multiturn이 없는 5-shot CoT | 85.11% |
가장 큰 레버(Lever)는 system instruction에서 <thought> 태그를 제거하는 것이었다. 이 <thought> 태그는 과거의 시행착오 과정에서 넣었던 설정의 잔재로서 lm_eval.sh 스크립트의 기본값(default)으로 되어 있었으나, 최종 단계까지 이것이 점수를 저해하고 있다는 사실을 알아차리지 못했고, 결과적으로 약 2포인트의 하락을 초래했다.
최적 설정 (85.4~85.5%)
"<thought> 태그 없음"이라는 발견에 더 긴 컨텍스트 길이(context length)와 생성 토큰 예산을 결합하자, 최종적으로 최상의 점수를 얻을 수 있었다.
MODEL_NAME="google/gemma-4-31b-it"
SEED=1235 # 안정성 확인을 위해 seed 1235〜1238로 실행
lm_eval --model vllm \
...
83.4% 베이스라인(baseline)과의 주요 차이점은 다음과 같다.
| 파라미터 | 베이스라인 | 최적 설정 |
|---|---|---|
max_model_len | 32,768 | 131,072 (128K) |
max_gen_toks | 4,096 | 32,768 |
| System instruction | <think>로 시작 | 일반 텍스트, think 태그 없음 |
4개의 시드(seed) 결과.
| Seed | 점수 | 표준 오차 |
|---|---|---|
| 1235 | 85.50% | ±0.32% |
| ... |
Step 5: Slurm으로 실행하기
Slurm 클러스터에서 실행할 경우, 최적 설정을 4개의 시드 어레이 잡(array job)으로 실행하는 전체 잡 스크립트는 다음과 같다.
#!/bin/bash
#SBATCH --job-name=gemma_eval
#SBATCH --partition=GPU
...
다음 명령어로 제출한다.
sbatch eval_gemma4.sh
기대되는 출력
정상적으로 실행되면 마지막에 다음과 같은 테이블이 출력된다.
| Tasks |Version| Filter |n-shot| Metric | |Value | |Stderr|
|-------------------|------:|--------------|-----:|-----------|---|-----:|---|-----:|
|mmlu_pro | 2|custom-extract| 0|exact_match|↑ |0.8541|± |0.0032|
...
여러 시드에 걸쳐 전체 점수는 85.4~85.5% 범위 내에 들어올 것이다.
중요한 포인트
초기 실패한 실행(약 55%)과 목표치(약 85%) 사이의 30포인트 차이는 하드웨어 나 모델의 문제가 아니라, 전적으로 설정의 문제였다. 영향이 큰 순서대로 정리하면 다음과 같다.
-
Reasoning Parser — 이것이 없으면 모델의 사고 사슬 (chain-of-thought) 출력이 올바르게 파싱되지 않아 답변이 추출되지 않는다.
reasoning_parser=gemma4필요. -
System instruction —
<think>태그를 넣지 않아야 한다.<think>를 맨 앞에 붙이면 약 2포인트 하락했다. -
더 긴 컨텍스트 길이와 생성 토큰 예산 —
max_model_len=32768과max_gen_toks=4096으로도 83.4%에서 안정되지만, 85.4~85.5%에 도달하려면 128K / 32K가 필요했다. -
CUDA shim — 이것이 없으면 검증 시점의 Blackwell + CUDA 13.x 환경에서 vLLM이 아예 구동되지 않았다. 다만, 이는
nvcc fatal: Unknown option '-fPIC'가 발생하는 경우의 회피책이며, 새로운 Triton, vLLM, CUDA 환경에서는 먼저 shim 없이 시도해야 한다.
결과는 안정적이다. 동일한 설정을 4개의 서로 다른 시드로 실행하면, 모델 카드(model card)에 기재된 값인 약 85.2% 범위 내인 **85.41~85.50%**가 일관되게 얻어진다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기