코드 생성 대규모 언어모델 평가 (Evaluating Large Language Models Trained on Code)

Digest: 2021년 기준 LLM의 코드 생성 능력을 체계적으로 평가할 벤치마크가 부재했다. OpenAICodex(GitHub 코드로 파인튜닝한 GPT 모델)를 개발하면서, 함수 docstring으로부터 올바른 Python 코드를 생성하는 능력을 측정하는 HumanEval 벤치마크(164개 수작업 프로그래밍 문제)를 함께 공개했다. 핵심 기여는 pass@k 메트릭(k개 샘플 중 하나라도 통과하면 성공)의 통계적으로 올바른 추정 방법을 제안한 것으로, 이는 이후 모든 코드 생성 벤치마크의 표준이 되었다. Codex는 HumanEval에서 28.8% (pass@1), 반복 샘플링으로 70.2% (pass@100)를 달성하여 (Table 1), GPT-3의 0%와 극적인 차이를 보였다.


메타데이터

항목내용
제목Evaluating Large Language Models Trained on Code
저자Mark Chen, Jerry Tworek, Heewoo Jun, Qiming Yuan, … Wojciech Zaremba
소속OpenAI
연도2021
발표arXiv:2107.03374
링크arXiv, GitHub
키워드HumanEval, Codex, pass@k, code generation, functional correctness

데이터셋 구성

규모 및 분할

항목내용
전체 크기164개 프로그래밍 문제
Train/TestTest only (학습용 데이터 없음, 평가 전용)
언어Python
작성 방식OpenAI 연구원이 수작업으로 작성
평균 테스트 케이스문제당 약 7.7개 unit test

Feature/Column 구조

필드설명예시
task_id고유 문제 식별자HumanEval/0
prompt함수 시그니처 + docstringdef has_close_elements(numbers, threshold):
canonical_solution정답 코드참조 구현
testunit test 함수assert has_close_elements([1.0, 2.0], 0.5) == False
entry_point함수 이름has_close_elements

난이도 체계

HumanEval은 공식적인 난이도 분류를 제공하지 않지만, 문제 유형별로 다음과 같이 분포한다:

유형비율 (약)설명
문자열 처리25%문자열 조작, 파싱
수학/수치20%수학 연산, 소수 판별 등
리스트/배열30%정렬, 필터링, 변환
논리/조건15%조건 분기, 불리언 연산
기타 (재귀 등)10%재귀, 트리 등

실제 데이터 예시

예시 1: 간단한 리스트 처리

# Prompt
def has_close_elements(numbers: List[float], threshold: float) -> bool:
    """Check if in given list of numbers, are any two numbers
    closer to each other than given threshold.
    >>> has_close_elements([1.0, 2.0, 3.0], 0.5)
    False
    >>> has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3)
    True
    """
 
# Canonical Solution
for idx, elem in enumerate(numbers):
    for idx2, elem2 in enumerate(numbers):
        if idx != idx2:
            distance = abs(elem - elem2)
            if distance < threshold:
                return True
return False

예시 2: 문자열 처리

# Prompt
def remove_vowels(text: str) -> str:
    """remove_vowels is a function that takes string and returns
    string without vowels.
    >>> remove_vowels('')
    ''
    >>> remove_vowels("abcdef\nghijklm")
    'bcdf\nghjklm'
    >>> remove_vowels('aeiou')
    ''
    """
 
# Canonical Solution
return "".join([s for s in text if s.lower() not in "aeiou"])

예시 3: 수학적 문제

# Prompt
def is_prime(n: int) -> bool:
    """Return true if a given number is prime, and false otherwise.
    >>> is_prime(6)
    False
    >>> is_prime(101)
    True
    >>> is_prime(2)
    True
    """
 
# Canonical Solution
if n < 2:
    return False
for k in range(2, n - 1):
    if n % k == 0:
        return False
return True

왜 이 연구를 하는가?

핵심 질문

LLM이 docstring만으로 기능적으로 올바른 코드를 생성할 수 있는가? 그리고 이를 어떻게 신뢰성 있게 측정할 수 있는가?

기존 접근법의 한계

한계설명
BLEU 기반 평가의 부적절성코드의 정확성은 텍스트 유사도로 측정할 수 없음. 의미적으로 동일한 코드가 구조적으로 다를 수 있음
Match 기반 메트릭 한계정확히 일치하는 코드만 정답으로 인정하면, 다양한 올바른 구현을 놓침
기존 벤치마크의 contamination학습 데이터에 포함된 문제로 평가하면 실제 능력 측정 불가

핵심 통찰

코드 생성 능력은 **기능적 정확성(functional correctness)**으로 평가해야 하며, 이는 unit test 통과 여부로 결정된다. 또한 단일 샘플이 아닌 다중 샘플링 전략이 실용적으로 매우 효과적이다.


방법 (Method)

프레임워크 개요

graph TB
    A["Docstring<br/>(함수 시그니처 + 설명)"] --> B["LLM 코드 생성<br/>(n개 샘플 생성)"]
    B --> C["Unit Test 실행<br/>(각 샘플에 대해)"]
    C --> D{"통과 여부"}
    D -->|"1개 이상 통과"| E["pass@k = 성공"]
    D -->|"모두 실패"| F["pass@k = 실패"]

    G["pass@k 추정<br/>1 - C(n-c, k) / C(n, k)"] --> H["최종 점수"]

pass@k 메트릭

pass@k의 통계적 추정: n개 샘플 중 c개가 통과했을 때, k개를 뽑아 최소 1개가 통과할 확률:

이 추정법은 나이브한 방법(독립 시행을 k번 반복하여 성공 확률 추정)보다 분산이 훨씬 낮다.

Tip

실제 eval-phase라고 생각해봤을 때, LLM에게 하나의 문제에 대해 n개의 answer를 만들라 시키고, eval을 개별적으로 했을 때, 총 c개의 유효한 answer가 확인되었다고 하자. 그 뒤, k를 1 혹은 3으로 마음대로 잡고 위에 공식에 넣어서 계산하여 보고. 즉, k는 약간 단위 같은 느낌임.

실무에서도 1문제에 대한 위의 pass@k 계산 뒤, 전체 문제에 대해 평균을 내어 계산하여 보고.

핵심 구성요소

  1. Codex 모델: GPT 모델을 GitHub의 159GB Python 코드로 파인튜닝
  2. Docstring 컨디셔닝: 함수 시그니처와 docstring을 프롬프트로 제공
  3. 샌드박스 실행: 생성된 코드를 안전한 환경에서 unit test 실행
  4. Nucleus Sampling: temperature와 top-p를 조절하여 다양한 샘플 생성

발견 (Findings)

주요 결과

모델pass@1pass@10pass@100
GPT-3 (175B)0.0%
GPT-J (6B)11.4%15.7%27.7%
Codex (12B)28.8%46.8%72.3%
Codex-S (12B, supervised)37.7%53.0%74.9%

(Table 1, Table 2)

핵심 발견

  1. 코드 파인튜닝의 효과: GPT-3 → Codex로 파인튜닝만으로 0% → 28.8% 달성 (Table 1)
  2. 반복 샘플링의 위력: pass@1 28.8%인 모델도 pass@100에서 72.3%에 도달, 다양한 시도가 핵심 (Table 1)
  3. 모델 크기와 성능: 300M → 12B 파라미터로 스케일링 시 pass@1이 약 3배 향상 (Figure 3)
  4. Docstring 길이의 영향: 긴 체인의 연산을 기술하는 docstring에서 성능이 급격히 저하 (Section 4)
  5. Temperature 최적화: pass@1에는 낮은 temperature(0.2), pass@100에는 높은 temperature(0.8)가 최적 (Figure 5)

Temperature

Temperature 최적화: pass@1에는 낮은 temperature(0.2), pass@100에는 높은 temperature(0.8)가 최적 (Figure 5)


이론적 의의

LLM 코드 평가의 표준 정립

HumanEval은 코드 생성 벤치마크의 사실상 표준(de facto standard)이 되었다. pass@k 메트릭은 이후 MBPP, SWE-bench, LiveCodeBench 등 거의 모든 코드 벤치마크에서 채택되었다. “기능적 정확성 = unit test 통과”라는 평가 철학은 BLEU 등 표면적 유사도 메트릭을 완전히 대체했다.

Scaling Law의 코드 도메인 확장

모델 크기에 따른 pass@k의 log-linear 증가는 코드 생성에서도 스케일링 법칙이 성립함을 보여주었다. 이는 이후 Codex → GPT-4 → Claude 등의 코드 능력 발전을 예측하는 근거가 되었다.


관련 연구


핵심 용어 정리

용어정의
pass@kn개 코드 샘플 중 k개를 선택했을 때 최소 1개가 unit test를 통과할 확률
Functional Correctness코드가 명세된 모든 unit test를 통과하는지로 판단하는 정확성 기준
CodexGPT 모델을 GitHub 코드로 파인튜닝한 OpenAI의 코드 생성 모델
Nucleus Sampling (top-p)누적 확률이 p 이하인 토큰들에서만 샘플링하는 디코딩 전략
Docstring함수의 동작을 설명하는 문자열, 여기서는 모델의 입력(프롬프트)으로 사용
Temperature소프트맥스 분포의 날카로움을 조절하는 파라미터. 낮으면 결정적, 높으면 다양한 출력

태그

paper #2021 benchmark code_generation HumanEval pass_at_k Codex OpenAI