본문 바로가기

인공지능

LiveCodeBench

 

LiveCodeBench는 대규모 언어 모델(LLM)의 코드 관련 응용 분야에서의 성능을 포괄적이고 오염 없이 평가하기 위해 개발된 벤치마크입니다.

이 벤치마크는 LeetCode, AtCoder, CodeForces와 같은 세 개의 경쟁 플랫폼에서 지속적으로 새로운 문제를 수집하여, LLM의 코드 생성 능력뿐만 아니라 자기 수정(self-repair), 코드 실행, 테스트 출력 예측 등 다양한 코드 관련 기능을 평가합니다.

현재 LiveCodeBench는 2023년 5월부터 2024년 5월까지 발표된 400개의 고품질 코딩 문제를 포함하고 있습니다.

이러한 문제를 통해 18개의 기본 LLM과 34개의 명령어 튜닝된 LLM을 평가한 결과, 기존 벤치마크에서의 잠재적 과적합과 모델 간의 성능 차이를 발견하였습니다. LiveCodeBench는 커뮤니티의 추가 분석을 위해 모든 프롬프트와 모델 완성본을 공개할 예정이며, 새로운 시나리오와 모델을 추가할 수 있는 일반적인 도구 키트도 함께 제공합니다.

이러한 노력은 LLM의 코드 관련 응용 분야에서의 성능을 보다 정확하고 포괄적으로 평가하는 데 기여할 것으로 기대됩니다.

 

LiveCodeBench에서 사용하는 400개의 고품질 코딩 문제는 다양한 코딩 플랫폼(LeetCode, AtCoder, CodeForces)에서 엄선된 문제들로, 대규모 언어 모델(LLM)의 프로그래밍 능력을 평가하기 위해 설계되었습니다. 이 문제들은 프로그래밍 언어, 난이도, 주제 범위 등 여러 측면에서 다양성을 가지고 있습니다. 아래는 이 문제들이 가진 특징과 구성 요소를 구체적으로 설명합니다.


1. 문제의 출처

  1. LeetCode
    • 문제 유형: 알고리즘 및 자료 구조 중심.
    • 주제: 배열, 문자열 처리, 동적 프로그래밍, 그래프 알고리즘 등.
    • 난이도: 쉬움(Easy), 중간(Medium), 어려움(Hard).
  2. AtCoder
    • 문제 유형: 경쟁 프로그래밍에 적합한 수학 및 알고리즘 문제.
    • 주제: 조합론, 모듈러 연산, 세그먼트 트리 등.
    • 난이도: Beginner부터 Advanced까지.
  3. CodeForces
    • 문제 유형: 실전 코딩 대회 스타일 문제.
    • 주제: 해싱, 비트 조작, 네트워크 플로우, 게임 이론.
    • 난이도: Div2, Div1으로 구분.

2. 문제 구성 요소

  • 문제 설명:
    문제의 조건, 입력/출력 형식, 제약 조건 등이 명확히 기술됨.
  • 예제 입력/출력:
    테스트를 위한 샘플 입력/출력 데이터가 포함.
  • 제약 조건:
    시간 복잡도와 메모리 사용 제한이 명시되어 효율적인 코드를 요구.

3. 문제의 분류

  1. 알고리즘 문제
    • 정렬, 탐색, 최단 경로, 그래프 탐색(DFS/BFS) 등.
    • 예: "주어진 그래프에서 특정 노드 간의 최단 경로를 찾으시오."
  2. 자료 구조 문제
    • 배열, 해시 테이블, 이진 탐색 트리, 세그먼트 트리.
    • 예: "동적 배열에서 특정 범위의 합을 구하시오."
  3. 수학 문제
    • 소수 판별, 모듈러 산술, 조합론, 확률 계산.
    • 예: "n개의 숫자 중에서 k개를 고를 때 가능한 조합의 수를 계산하시오."
  4. 최적화 문제
    • 동적 프로그래밍, 그리디 알고리즘, 백트래킹.
    • 예: "주어진 숫자 배열에서 부분합이 최대가 되는 연속 부분 배열을 찾으시오."
  5. 기타 문제
    • 문자열 처리, 비트 연산, 시뮬레이션.
    • 예: "주어진 문자열에서 특정 패턴을 찾고, 해당 패턴을 뒤집으시오."

4. 난이도별 문제 예시

  1. 쉬움(Easy):
    • 문제: "주어진 배열의 요소를 오름차순으로 정렬하시오."
    • 평가: 기본적인 프로그래밍 및 알고리즘 이해를 측정.
  2. 중간(Medium):
    • 문제: "두 개의 정렬된 배열을 병합하고, 중복을 제거하시오."
    • 평가: 효율적인 자료 구조 사용과 알고리즘 설계를 평가.
  3. 어려움(Hard):
    • 문제: "방향 그래프에서 사이클을 탐지하는 알고리즘을 작성하시오."
    • 평가: 복잡한 알고리즘 설계 및 구현 능력을 측정.

5. LiveCodeBench에서 문제를 사용하는 방식

  1. 프롬프트 생성:
    문제 설명을 모델에 제공하여 모델이 코드를 생성하도록 요청.
  2. 결과 비교:
    • 모델이 생성한 코드의 정확성 테스트.
    • 효율성과 최적화를 분석.
  3. 자기 수정(Self-repair):
    모델이 자신의 오류를 인식하고 수정할 수 있는지 평가.

6. 고품질 문제로 인정받는 기준

  1. 명확성:
    문제의 조건과 제약이 명확히 정의.
  2. 다양성:
    다양한 알고리즘, 데이터 구조, 프로그래밍 언어를 포괄.
  3. 실용성:
    실제 응용 분야나 경쟁 프로그래밍에서 유용한 문제.
  4. 테스트 커버리지:
    다양한 입력 사례를 포함하여 엣지 케이스도 검증 가능.

7. 평가 목적과 중요성

  • 모델 간 성능 비교:
    기존 벤치마크의 과적합 문제를 방지하고, 실제 프로그래밍 성능을 평가.
  • 코딩 능력 강화:
    문제 해결 능력과 코드 작성 품질을 개선.
  • 실제 적용 가능성:
    실제 소프트웨어 개발과 응용 프로그램에서 사용될 가능성을 평가.

이와 같은 고품질 문제들은 LiveCodeBench를 통해 LLM의 프로그래밍 성능을 객관적이고 체계적으로 측정하는 데 사용됩니다. 이러한 평가 과정은 LLM의 강점과 약점을 이해하고, 향후 개선 방향을 제시하는 데 중요한 역할을 합니다.

 

 

LiveCodeBench에서 사용되는 고품질 코딩 문제를 기반으로 한 구체적인 예제는 다음과 같습니다. 각 문제는 다양한 난이도와 주제를 포함하며, 평가 목적에 맞게 설계되었습니다.


1. 난이도: 쉬움(Easy)

문제: 배열의 짝수 합 구하기

  • 설명: 주어진 정수 배열에서 짝수 숫자만 더한 값을 반환하세요.
  • 입력:
    • 첫 줄에 배열의 길이 nn (1 ≤ nn ≤ 100).
    • 두 번째 줄에 nn개의 정수 (-10^3 ≤ 정수 ≤ 10^3).
  • 출력:
    • 배열 내 짝수 숫자의 합.
  • 예제 입력:
    5
    1 2 3 4 5
    
  • 예제 출력:
    6
    
  • 솔루션 (Python):
    def sum_of_evens(arr):
        return sum(x for x in arr if x % 2 == 0)
    
    n = int(input())
    arr = list(map(int, input().split()))
    print(sum_of_evens(arr))
    

2. 난이도: 중간(Medium)

문제: 두 개의 정렬된 배열 병합

  • 설명: 두 개의 정렬된 배열을 병합하여 하나의 정렬된 배열을 반환하세요.
  • 입력:
    • 첫 줄에 두 배열의 길이 nn, mm (1 ≤ n,mn, m ≤ 100).
    • 두 번째 줄에 첫 번째 배열의 원소.
    • 세 번째 줄에 두 번째 배열의 원소.
  • 출력:
    • 병합된 정렬 배열.
  • 예제 입력:
    3 4
    1 3 5
    2 4 6 8
    
  • 예제 출력:
    1 2 3 4 5 6 8
    
  • 솔루션 (Python):
    def merge_sorted_arrays(arr1, arr2):
        return sorted(arr1 + arr2)
    
    n, m = map(int, input().split())
    arr1 = list(map(int, input().split()))
    arr2 = list(map(int, input().split()))
    print(*merge_sorted_arrays(arr1, arr2))
    

3. 난이도: 어려움(Hard)

문제: 방향 그래프에서 사이클 탐지

  • 설명: 방향 그래프가 주어질 때, 사이클이 존재하는지 판별하세요.
  • 입력:
    • 첫 줄에 노드 수 nn과 간선 수 mm (1 ≤ nn ≤ 10^3, 0 ≤ mm ≤ 10^4).
    • 이후 mm개의 줄에 간선 정보 u,vu, v (1 ≤ u,vu, vnn).
  • 출력:
    • "YES" (사이클이 존재) 또는 "NO" (사이클이 존재하지 않음).
  • 예제 입력:
    4 4
    1 2
    2 3
    3 4
    4 2
    
  • 예제 출력:
    YES
    
  • 솔루션 (Python):
    from collections import defaultdict
    
    def has_cycle(n, edges):
        graph = defaultdict(list)
        for u, v in edges:
            graph[u].append(v)
        
        visited = [0] * (n + 1)
        
        def dfs(node):
            if visited[node] == 1:  # 사이클 발견
                return True
            if visited[node] == 2:  # 이미 처리된 노드
                return False
            
            visited[node] = 1  # 방문 중 표시
            for neighbor in graph[node]:
                if dfs(neighbor):
                    return True
            visited[node] = 2  # 처리 완료
            return False
        
        for i in range(1, n + 1):
            if not visited[i]:
                if dfs(i):
                    return True
        return False
    
    n, m = map(int, input().split())
    edges = [tuple(map(int, input().split())) for _ in range(m)]
    print("YES" if has_cycle(n, edges) else "NO")
    

4. 난이도: 추가 도전 (Advanced)

문제: 최소 스패닝 트리 (MST)

  • 설명: 가중치가 주어진 연결된 무방향 그래프에서 최소 스패닝 트리를 구성하세요.
  • 입력:
    • 첫 줄에 노드 수 nn과 간선 수 mm (2 ≤ nn ≤ 10^3, 1 ≤ mm ≤ 10^4).
    • 이후 mm개의 줄에 간선 정보 u,v,wu, v, w (1 ≤ u,vu, vnn, ww는 가중치).
  • 출력:
    • 최소 스패닝 트리의 총 가중치.
  • 예제 입력:
    4 5
    1 2 1
    2 3 2
    3 4 3
    4 1 4
    1 3 5
    
  • 예제 출력:
    6
    
  • 솔루션 (Python):
    import heapq
    
    def minimum_spanning_tree(n, edges):
        graph = defaultdict(list)
        for u, v, w in edges:
            graph[u].append((w, v))
            graph[v].append((w, u))
        
        visited = [False] * (n + 1)
        min_heap = [(0, 1)]  # (가중치, 시작 노드)
        mst_weight = 0
    
        while min_heap:
            weight, node = heapq.heappop(min_heap)
            if visited[node]:
                continue
            visited[node] = True
            mst_weight += weight
            
            for edge in graph[node]:
                if not visited[edge[1]]:
                    heapq.heappush(min_heap, edge)
    
        return mst_weight
    
    n, m = map(int, input().split())
    edges = [tuple(map(int, input().split())) for _ in range(m)]
    print(minimum_spanning_tree(n, edges))
    

결론

이와 같은 문제들은 LiveCodeBench에서 고품질로 간주되는 문제들로, 다양한 난이도와 주제를 다룹니다. 이를 통해 LLM의 프로그래밍 능력을 평가하고 실제적인 코드 생성 및 문제 해결 능력을 테스트할 수 있습니다.