Textbooks are all you need (phi-1)
1. 들어가기 전에
2. 개요
3. 고퀄리티의 데이터셋 만들기
3.1. filtered code-language dataset
3.2. synthetic textbook
3.3 synthetic exercises
4. phi-1 모델 구조와 훈련
5. finetuning의 효과
5.1. Finetuning improves the model's understanding
5.2. Finetuning improves the model's ability to use external libraries
6. 모델 성능 평가 방법
6.1. 새로운 평가 데이터셋과 GPT로 모델 성능 평가하기
6.2. HumanEval에 편향되지 않도록 학습 데이터 필터링하기
7. 결론
1. 들어가기 전에
Transformer의 등장과 함께 점차 대규모의 데이터, 대규모의 파라미터를 이용해 모델의 성능을 높이는 연구들이 강세를 보이고 있습니다. 하지만 정말 데이터의 양과 모델의 크기만이 정답일까요? 이런 초거대 모델들은 매우 좋은 성능을 보이고 있지만 너무 자원이 많이 들어 뭔가 더 효율적인 학습 방식을 생각해보게 됩니다.
그래서 모델의 성능을 높이기 위한 방식으로 데이터의 양뿐만 아니라 데이터의 퀄리티를 높여 모델의 성능을 높이고자 하는 연구들도 많이 생기고 있습니다. 이번에 소개드릴 phi-1 역시 그렇습니다. 본 논문에서 주장하는 핵심은 기존 SOTA 모델들에 비해 훨씬 적은 데이터, 훨씬 작은 모델을 이용해도 SOTA를 달성할 수 있다는 것을 보여주는 것입니다. 본 논문을 보며 높은 퀄리티의 데이터셋을 생산하기 위해 어떤 점들을 고려하고 어떤 식으로 데이터셋을 만들었는지 알아보겠습니다.
2. 개요
phi-1은 프로그래밍 코드를 작성하는 인공지능 모델입니다. 모델의 성능을 테스트하는 데는 HumanEval이라는 데이터셋이 사용됩니다. HumanEval은 영어로 설명이 주어졌을 때 이를 실행하는 알맞은 파이썬 코드를 작성해야 하는 task입니다.
# HumanEval 데이터셋 예시
# 문제
from typing import List
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
"""
# 답
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
이 task를 해결하기 위해 연구된 모델들은 이전까지 아래와 같은 데이터셋들을 사용했었습니다.
- The Stack : github의 repository들로부터 허가된 라이센스를 가진 코드들에 한해서 수집된 데이터셋. 3TB 크기에 30개의 프로그래밍 언어 소스를 담고 있다. (https://huggingface.co/datasets/bigcode/the-stack)
- StackOverflow : Stackoverflow에 올라온 프로그래밍 관련 질문과 답변들을 모은 데이터셋 (https://www.kaggle.com/datasets/stackoverflow/stackoverflow)
- CodeContest : 코드 문제가 주어지고, 이에 대해 사람들이 작성한 코드와 설명들을 담고 있는 데이터셋 (https://huggingface.co/datasets/deepmind/code_contests)
하지만 본 논문의 연구자들은 위 데이터셋들이 모델이 코드 작성을 학습하는데 좋은 데이터셋이 아니라고 주장합니다. 그 이유는 위 데이터셋들은 너무나도 광범위한 범위에서 수집되었기 때문입니다. 만약 여러분이 실제로 코딩을 공부한다고 하더라도 c언어를 봤다가, python을 봤다가, java를 보기도 하고, 어려운 문제, 쉬운 문제, 여러 가지 알고리즘 등이 뒤섞여 한꺼번에 공부를 하게 된다면 코딩이 너무 어렵게 느껴질 것입니다. 마찬가지로 인공지능 입장에서도 너무 다양한 정보들을 랜덤으로 보게 되는 식으로 학습을 한다면 제대로 된 코딩을 배우기 어려울 것이라는 것입니다. 구체적으로는,
- 수집된 많은 소스 코드들이 소스 코드에 나타나지 않은 외부의 모듈, 코드를 사용해 이런 것까지 이해하기 어려움.
- 특정 코드들은 아무 의미 없는 boilerplate code만으로 구성되어 있어 학습에 도움이 되지 않는다.
- 학습에 도움이 될 것으로 보이는 코드들은 대부분 코드에 대한 설명이 복잡하거나, 혹은 설명이 부족해 코드를 이해하기가 어려움.
- 데이터의 편향성이 나타날 수 있음.
위와 같은 문제들 때문에 모델이 이런 데이터셋을 이용해 제대로 학습하기 어렵다고 판단합니다. 그렇다면 어떻게 하면 위의 문제점들을 발생시키지 않는 좋은 퀄리티의 데이터셋을 만들 수 있을까요? phi-1은 아래와 같은 방식으로 생성한 데이터셋들을 이용해 학습합니다.
<Code Textbook>
- filtered code-language dataset : The Stack과 StackOverflow 데이터셋에서 쓸모 있는 데이터셋만 필터링한 데이터셋. (총 6B token)
- synthetic textbook : GPT-3.5를 이용해 생성한 python 코드집. (1B token 미만)
<Code Exercises>
- synthetic exercises : python exercise와 solution을 담고 있는 데이터셋 (180M token)
위 데이터셋들은 모두 합쳐서 총 70억개가 되지 않는 토큰으로 구성되어 있습니다. 위 2개의 데이터셋을 합쳐서 "CodeTextbook" 데이터셋이라고 칭하며, phi-1의 pretraining에 사용됩니다. 아래의 1개 데이터셋은 "CodeExercises" 데이터셋이라고 칭하며 phi-1의 fine-tuning에 사용됩니다.
3. 고퀄리티의 데이터셋 만들기
3.1. filtered code-language dataset
The Stack과 StackOverflow 데이터셋은 총 35B 개의 토큰을 갖고 있습니다. 여기서 학습에 도움이 될만한 고퀄리티의 데이터만 추려내기 위해 GPT-4를 이용했다고 합니다.
"determine its educational value for a student whose goal is to learn basic coding concepts."
위와 같은 prompt와 함께 데이터를 보여주고 GPT-4가 학습가치가 있다라고 답변한 데이터만 사용하는 것입니다. 이렇게 데이터셋에서 10만개 정도의 샘플을 라벨링 한 뒤, 간단한 random forest classifier를 사용해 이를 학습합니다. 마지막으로 classifier를 이용해 전체 35B개 토큰 분량의 데이터 중, 6B개 토큰 분량만 필터링 해서 남겼습니다.
이렇게 필터링하는 것이 과연 효과가 있었을까요? 테스트를 위해 phi-1 small 모델을 학습해 봤습니다. 필터링되지 않은 데이터셋으로는 96k step을 학습하고도 HumanEval에서 12.19%의 정확도를 보였지만, 필터링된 데이터셋으로는 36k step만 학습하고도 17.68%의 정확도를 보였습니다. 필터링이 효과가 있었던 것으로 보이네요.
3.2. synthetic textbook
고퀄리티의 소스코드란 무엇일까요? 여기선 고퀄리티를 만족하기 위한 소스코드의 조건 중 하나로 코드의 다양성과 비반복성을 들었습니다. 같은 기능을 하더라도 구현하는 방식이 다양하고, 상황에 따라 구현 방식이 다를 수도 있습니다. 또 다양한 문제에 관련된 소스코드들을 보는 것이 성능에 도움을 줄 것입니다. 그리고 반복되는 코드가 적을수록 모델이 과적합되는 현상도 막을 수 있겠죠.
좀 더 다양한 고퀄리티의 코드를 얻기 위해 이번에도 사전학습된 GPT(3.5)를 사용합니다. 하지만 GPT에게 코드를 작성해달라고 부탁할 때도 주의해야 하는 점이 있습니다. 단순히 어떤 코드를 생성해 달라고 할 경우 모델이 흔하고 같은 패턴의 코드를 작성하기 일쑤이기 때문입니다. 따라서 좀 더 자세하고 정확한 prompt를 모델에 전달해야 할 필요가 있습니다. 더 다양한 소스코드를 얻기 위해 더 자세하고 정확한 prompt를 제시하되, prompt를 정해놓고 특정 단어들을 랜덤으로 바꾸면서 GPT에 입력하는 방식을 사용했습니다.
예를 들면 "코딩 입문자에게 보여줄 피벗 정렬을 구현해줘.", "코딩 전문가에게 보여줄 피벗 정렬을 구현해줘."와 같이 같은 코드라도 보여줄 대상을 다르게 함으로써 GPT가 다른 코드를 생성하도록 하는 것입니다. 더 자세한 prompt나 랜덤 단어에 대한 설명은 나와있지 않았지만 아마 이런 식으로 텍스트를 생성한 것으로 보입니다.
3.3. synthetic exercises
이 데이터 역시 GPT-3.5를 이용해 생성하는 소스코드 데이터셋입니다. 여기선 함수의 이름과 함께 함수의 역할에 대한 설명을 GPT에 입력해 함수를 완성하도록 하여 코드를 생성합니다.
4. phi-1 모델 구조와 훈련
phi-1은 transformer decoder 구조(GPT구조)를 사용하며, FlashAttention과 multi-head attention을 사용합니다. Flash Attention은 attention 연산을 좀 더 빠르게 하는 방법으로, 기존의 attention 방식은 query, key, value를 메모리에서 불러온 뒤, attention 연산을 하나 수행한 뒤 다시 메모리에 저장하고 다시 다음 attention 연산을 수행하고 다시 메모리에 저장하는 식으로 과정이 반복되지만, Flash Attention은 메모리에서 query, key, value를 불러온 뒤에 attention 연산을 결합하여 한번에 수행한 뒤에 메모리에 기록하는 식으로 더 빠르게 수행됩니다. (https://huggingface.co/docs/text-generation-inference/conceptual/flash_attention)
그리고 이전 모델들 CodeGen, PaLM, GPT-NeoX와 같이 parallel configuration을 사용합니다. (구글의 BARD와 openAI의 ChatGPT는 어떻게 다를까? 참고)
모델은 phi-1-small과 phi-1 2가지 모델을 사용했습니다.
phi-1-small | phi-1 | |
파라미터 수 | 1.3B | 350M |
레이어 수 | 24 | 20 |
hidden_dim | 2048 | 1024 |
MLP inner_dim | 8192 | 4096 |
attention_head | 32 | 16 |
pretraining과 fine-tuning 모두 "<|EndOfText|>" 토큰을 이용해 서로 다른 코드 파일을 구분하였으며 시퀀스는 2048개의 토큰씩 잘라서 학습했습니다. GPT와 같이 next token prediction으로 학습합니다.
그 외에도 Fp16 사용, AdamW 사용, linear-warmup-linear-decay, dropout(0.1) 등을 적용했으며 학습은 8개의 Nvidia-A100 GPU를 사용해 pretraining에 4일, fine-tuning에 7시간이 소모되었다고 합니다. 개인적으론 여전히 적은 자원은 아니란 생각이 들지만 기존의 초거대 모델들에 비하면 확실히 현실성 있는 시간과 GPU인 것 같습니다.
5. Finetuning의 효과
Finetuning은 CodeExercises 데이터셋으로 수행됩니다. CodeExercises는 기본적인 python library만을 사용하는 짧은 python task들로 구성되어 있으며 그 양도 180M개의 토큰으로 CodeTextbook에 비해 매우 적습니다. 그래서 이 fine-tuning이 정말 효과가 있을지에 대한 의구심이 들 수 있습니다. fine-tuning 결과를 보면서 성능에 어떤 영향을 미쳤는지 확인해 보도록 하겠습니다.
5.1. Finetuning improves the model's understanding
Fine-tuning을 거치기 전과 후의 차이 중 하나는 모델이 prompt를 이해하게 되었다는 것입니다.
Fine-tuning을 하지 않은 phi-1-base는 prompt와 관계없이 단순히 변수들을 정의하는데 그쳤지만 fine-tuning을 한 모델들은 prompt에 맞춰 코드를 작성한 것을 확인할 수 있습니다. phi-1-small 모델도 비록 답은 틀렸지만 그래도 Alice와 Bob의 점수를 구현하려 한 것을 확인할 수 있습니다. 이를 통해 CodeExercises 데이터셋이 비록 양도 작고 간단한 코드 위주로 구성되어 있지만, 오히려 pretraining 과정에서 얻은 방대한 코드소스들을 실용적으로 이용하는 방법을 배웠다는 것을 알 수 있습니다.
5.2. Finetuning improves the model's ability to use external libraries
Fine-tuning이 보여준 효과가 놀라운 것은 CodeExercises 데이터셋에서 나타나지 않은 Pygame이나 Tkinter와 같은 라이브러리를 활용하는 능력도 향상된 것을 확인할 수 있었다는 것입니다.
위 결과를 보면 phi-1만 유일하게 코드를 제대로 작성한 것을 확인할 수 있습니다. phi-1-small은 실패한걸 보니 350M개의 파라미터로는 어려운 작업이었던 것 같습니다. phi-1-base와 phi-1의 결과를 비교하면 CodeExercises 데이터셋에 pygame 라이브러리가 등장하지 않았음에도 확실히 fine-tuning을 통해 pygame 라이브러리를 활용하는 능력이 향상되었다는 것을 확인할 수 있습니다.
이런 현상은 Tkinter 라이브러리를 활용하는 모습에서도 나타났습니다. phi-1-base와 phi-1-small은 제대로 된 코드를 구현하는데 실패했지만 phi-1 모델만 유일하게 tkinter를 제대로 활용해 코드를 구현한 것을 볼 수 있습니다.
또, 코딩 관련된 질문에 대한 답변 능력도 fine-tuning을 통해 향상된 것을 확인할 수 있습니다. 이것 역시 CodeExercises에선 나타나지 않은 유형이지만 모델 성능이 향상된 것입니다.
이렇게 종합적으로 봤을 때, 놀랍게도 fine-tuning에서 간단한 python 라이브러리 활용 예제들만 봤음에도 모델이 소스 코드를 활용하는 전반적인 능력이 향상되었다는 것을 확인할 수 있습니다. 정확한 원리를 설명하긴 어렵지만 실제 사람처럼 정확한 소스코드들을 보는 것만으로도 코딩에 대한 전반적인 이해도가 향상된 것입니다.
6. 모델 성능 평가 방법
6.1. 새로운 평가 데이터셋과 GPT로 모델 성능 평가하기
phi-1 모델이 학습하는 과정에서 혹시나 HumanEval에서 등장하는 문제 유형이나 특정 패턴을 봤을 수도 있으므로, CodeExercises 데이터셋에 포함되지 않는 HumanEval과 같은 유형의 문제들을 50문제 새로 만들어서 모델의 평가를 수행했습니다.
이에 더해 기존엔 모델이 문제의 예제들을 모두 통과했느냐 못했느냐로 모델의 성능을 평가했지만 이런 방식으론 모델의 정확한 성능을 평가하기에 무리가 있다고 생각했습니다. 사실 하나 빼고 모든 예제를 통과한 모델과 모든 예제를 통과하지 못한 모델의 성능이 같다라고 판단할 수는 없을 것입니다.
따라서 모델의 알고리즘 logic 이해도를 판단하기 위해 새로운 평가 방법을 사용했습니다. 바로 GPT-4를 이용하는 것입니다. GPT-4에게 phi-1이 생성한 소스코드를 보여주고 이 코드가 적절한지를 0에서 1사이 점수로 평가하도록 지시하여 모델의 성능을 평가하는 것입니다.
GPT-4를 모델 성능 평가에 사용하는 이유로는 2가지가 있습니다.
- 대규모 데이터로 학습된 GPT-4의 지식을 이용해 모델의 성능을 평가할 수 있다.
- 사람이 필요없고 평가를 자동으로 빠르게 할 수 있다.
GPT-4가 평가한 결과 모델의 성능은 아래와 같습니다.
표를 보면 phi-1의 점수가 모델 크기나 학습에 사용한 데이터의 양에 비해 점수가 높은 것을 확인할 수 있습니다. 다만 개인적으로 GPT를 사용해 만든 데이터를 보고 학습한 phi-1 모델을 GPT를 이용해 평가하는데 기존 모델들보다 조금 더 유리한 부분이 생길 수 있지 않을까 하는 의문이 살짝 들기는 합니다. 뭐 그렇다 치더라도 저 정도 자원량으로 이정도 성능을 보인다는 것은 분명히 놀라운 점이라는 것에는 동의하지만.
6.2. HumanEval에 편향되지 않도록 학습 데이터 필터링하기
GPT를 이용해 데이터를 생성했지만 여기에도 HumanEval 데이터와 유사한 데이터들이 포함될 수 있습니다. 그렇기 때문에 이런 데이터들을 최대한 필터링해서 학습한 뒤에도 phi-1이 기존 모델들보다 좋은 성능을 보이는지 확인할 필요가 있습니다.
6.2.1 N-gram overlap
N-gram overlap은 두 텍스트에서 N개의 단어 패턴이 서로 얼마나 겹치는지를 확인하는 방법입니다. 어느정도 의미 있는 겹침을 측정하려는 N이 커져야 겠지요. (너무 짧은 단어는 당연히 겹칠 수 밖에 없음. if, while, import 등과 같이) 탐색한 결과 총 4개의 humaneval의 질문이 CodeExercises 데이터와 13-gram이 겹친다는 것을 확인했습니다. 그러나 이 결과도 아래 예시와 같이 모델이 HumanEval의 문제를 예습했다고 보기 어려운 문장이었다고 합니다.
6.2.2. Embedding and syntax-based similarity analysis
HumanEval과 CodeExercises의 유사한 문장을 찾기 위해 2가지 방법을 더 사용했습니다.
Embedding distance는 사전학습된 CodeGen-Mono 350M 모델을 이용해 두 소스코드의 feature representation(embedding)을 출력한 뒤, 두 embedding 값의 차이(L2 distance)를 비교하는 것입니다. 두 embedding 값의 l2 distance가 작을수록 두 소스코드가 유사하다라고 판단할 수 있습니다.
Syntax-based distance는 2개의 코드를 abstract syntax trees(AST)를 이용해 거리를 측정하는 방식입니다. AST는 소스코드의 구조를 트리 형식으로 표현하는 그래프입니다. 2개의 소스코드를 AST로 변환한 뒤에 특정 알고리즘을 사용해서 두 AST를 비교하는 방식으로 보입니다.
AST-distance를 이용해 측정한 결과 유사도가 match rate $\tau$를 초과할 경우 두 코드는 유사하다고 판단합니다. 이를 이용해 $\tau$의 값을 조절해 가며 데이터를 필터링하고 각 데이터로 학습해 모델의 성능을 확인합니다.
위 결과를 보면 HumanEval과 CodeExercises 사이에 유사한 문제의 경우 정확도가 조금 떨어지긴 하지만 (phi-1과 phi-1 retrained on pruned data의 similar 문제에 대한 결과) 여전히 StarCoder라는 이전 SOTA 모델보다는 높은 정확도를 보입니다. 이를 통해 phi-1 모델이 HumanEval에 높은 성능을 보이는 것이 CodeExercises에서 유사한 패턴을 미리 학습했기 때문은 아니란 것을 증명합니다.
7. 결론
이렇게 phi-1에 대해서 살펴봤습니다. 저자들이 설명한 phi-1 모델의 한계점은 3가지가 있습니다.
- phi-1은 오로지 python 코드만 학습함.
- 잘 쓰이지 않는 API, package들의 활용능력이 떨어짐.
- 코드 스타일의 다양성이 부족하고 prompt에 오류가 있는 경우 성능이 급격하게 떨어짐.
기존의 코딩 모델들에 비해 크기가 작기 때문에 어쩔 수 없는 문제로 보이지만 언젠간 이런 문제들도 해결할 수 있는 작은 모델이 나오길 바랍니다.
또 고퀄리티의 데이터셋이 모델의 성능에 긍정적인 영향을 미친다는 것도 이 연구를 통해서 증명했습니다. 여기선 GPT를 이용해 생성했지만 진정한 고퀄리티의 데이터를 생성하는데는 사실 더 많은 점들이 고려되어야 합니다. 고퀄리티의 소스코드 데이터셋은 다양한 content와 concept를 담고 있어야 하고, 중복되지 않아야 합니다. 그리고 무엇보다도 만들어진 데이터가 정말로 위의 퀄리티를 담고 있는지 측정할 수 있는 방법이 필요합니다.
개인적으로는 phi-1은 GPT를 정말 잘 활용한 연구라는 생각이 들었습니다. GPT와 같은 대규모 모델을 학습하기 어려운 작은 단체나 개인이 이 자원을 활용할 수 있는 가장 효율적인 방법이라는 생각이 들고, 특히 모델 평가를 GPT-4를 사용해서 하는 것이 인상적이었던 것 같습니다. 사람만 할 수 있던 작업들을 자동화 할 수 있었다는 점에서 높게 생각됩니다.