최근 자연어처리와 관련한 기사들을 살펴보면 알파카나 라마라는 단어를 자주 보실 수 있을 텐데요. 이번 페이지에서는 그 중 알파카라는 자연어처리 모델에 대해 알아보도록 하겠습니다.
간단하게 소개하면 알파카는 라마(LLaMA)라는 모델을 튜닝하여 만든 모델입니다. 원본 모델인 라마를 튜닝했기에 비슷한 동물인 알파카라는 명칭을 지은 것 같습니다. 참고로 LLaMA는 Large Language model Meta AI의 약자입니다. 오픈소스 LLM은 대부분 이 LLaMA의 가중치, 학습방법 등을 모두 공개함으로써 시작했다고 볼 수 있을만큼 중요한 모델입니다.
LLaMA와 마찬가지로 학습 방법 등에 대해서 모두 공개를 했는데요, 가중치의 경우 LLaMA가 아직 부분 공개이기 때문에 공개하지 못했다고 저자가 밝혔습니다.
LLaMA의 가중치를 얼른 오픈소스로 풀어주었으면 좋겠습니다!
→ LLaMA2가 나오며 사실상 라마 가중치를 오픈했습니다. 감사합니다 Meta!
저자는 현재의 LLM이 많은 발전을 이루었지만 잘못된 정보를 전파하거나 편향된 정보를 제공하는 등의 문제가 여전히 발생하고 있다고 말하고 있습니다. 이러한 문제들을 해결하기 위해서는 학계의 참여가 중요하다고 강조하고 있는데요. 대부분의 LLM은 모델을 공개하지 않았기 때문에 이에 대한 연구를 수행하는 것은 어려운 일이었습니다.
학계에서 LLM을 만들기는 비용적으로 상당히 어렵기 때문입니다. 비교적 가벼운 모델인 LLaMA-65B를 학습하는 데 A100을 100만 시간 사용했다고 하는데 하드웨어 구입 비용은 우선 생각하지 않는다고 해도 엄청난 전기세를 감당해야 합니다. GPT-4는 파라미터가 1.4 트릴리온(1400B)이라고 하니 이쪽은 어느정도의 비용이 발생할지 생각하기도 어렵습니다.
이러한 때에 Meta에서 LLaMA 모델을 공개하면서 제한적이지만 가중치까지 공개를 해 주었고, 저자는 그 덕에 LLaMA를 파인튜닝한 Alpaca를 발표할 수 있었습니다.
Alpaca에 대해 자체적으로 평가한 결과 OpenAI의 text-davinci-003과 상당히 유사한 결과를 보여주면서도 크기가 작고, 재현이 쉽고 저렴하다고 합니다.
그럼 이제 알파카의 학습 방법에 대해 알아보도록 하겠습니다.
Training recipe
높은 퀄리티의 Instruction-Following Model을 만들기 위해서는 두 가지의 중요한 태스크가 있는데요. 바로 강력한 사전 훈련된 LLM 모델과 고품질의 Instruction-Following Data입니다.
메타의 강력한 LLM, LLaMA의 공개 덕에 첫 번째 태스크는 해결이 되었습니다. 이제 두 번째 태스크를 해결해야 하는데, 알파카팀은 self-instruct 논문을 기반으로 데이터셋을 생성하는 방법으로 이 문제를 해결했습니다.
이 self-instruct 논문의 방식을 간략하게 요약하면, 기존에 존재하는 강력한 언어 모델을 사용하여 데이터셋을 생성해보겠다! 로 요약할 수 있습니다. 스탠포드는 ChatGPT를 사용하여 데이터를 생성하여 이를 LLaMA에 학습시켜 알파카를 개발했습니다.
즉 Stanford Alpaca는 text-davinci-003에서 생성된 데이터를 사용하여 LLaMA를 Instruction Full-Finetunning한 모델입니다.
이를 파이프라인으로 요약하면 다음과 같습니다.
맨 앞에 보이는 175 Self-instruction seed set는 사람이 만든 instruction-output pairs 데이터입니다. 즉 175개의 데이터셋을 먼저 seed set으로 사람이 직접 만들었다고 보시면 됩니다.
이렇게 만든 seed set을 사용하여 ChatGPT(text-davinci-003)에게 질문을 하며 데이터셋을 추가 생성하였고, 52K개의 데이터를 만들었다고 합니다.
기존 논문에서의 파이프라인을 조금 더 단순화함으로써 비용을 절감했다고 하고, OpenAI API에 사용된 비용은 500달러 미만이라고 합니다.
저자는 이러한 파이프라인에 따라 학습을 수행했으며 7B LLaMA 모델을 파인튜닝하는데 8개의 80GB A100에서 3시간 정도가 소요되었다고 합니다. 이는 AWS 등에서 약 100달러 미만의 금액이라고 합니다.
생성 프로세스
그렇다면 어떻게 해서 데이터를 생성할 수 있었는지 알아보도록 하겠습니다. 우선은 데이터셋이 어떻게 생겼는지를 살펴보도록 하겠습니다.
데이터셋
우선 알파카를 파인튜닝하는데 사용된 52K 데이터는 공개가 되어 있는데요. 아래 링크에서 확인하실 수 있습니다.
https://github.com/tatsu-lab/stanford_alpaca/blob/main/alpaca_data.json
이 데이터셋의 형식은 다음과 같습니다.
instruction
: 모델이 수행해야하는 작업을 설명합니다. 52K 크기에서 각각의 instrunction은 유니크합니다.input
: 작업에 대한 context 또는 input을 의미합니다. 예를 들어 instruction이 “다음 기사 요약”인 경우 input은 기사가 됩니다. example의 약 40%는 input이 있습니다.output
:text-davinci-003
에 의해 생성된 명령에 대한 답변입니다
{"instruction": "Give three tips for staying healthy.",
"input": "",
"output": "1.Eat a balanced diet and make sure to include plenty of fruits and vegetables. \n2. Exercise regularly to keep your body active and strong. \n3. Get enough sleep and maintain a consistent sleep schedule."
},
이 데이터는 알파카 모델을 파인튜닝 할 때 다음과 같은 프롬포트를 작성하여 학습합니다.
- 비어 있지 않은 input field가 있는 예시
Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.
### Instruction:
{instruction}
### Input:
{input}
### Response:
- 비어 있는 Input field가 있는 예시
Below is an instruction that describes a task. Write a response that appropriately completes the request.
### Instruction:
{instruction}
### Response:
데이터 생성 프로세스
스탠포드 알파카팀은 생성 프로세스 코드도 공개했는데요. 깃헙에서 포크 후 다음 과정만 거치면 데이터 생성을 수행할 수 있습니다.
OPENAI_API_KEY
환경 변수를 자신의 OpenAI API키로 설정합니다.pip install -r requirements.txt
를 통해 패키지를 설치합니다.python -m generate_instruction generate_instruction_following_data
를 실행하여 데이터를 생성합니다.
알파카팀은 self-instruct 에 따라 생성 파이프라인을 구축했으며, 다음과 같은 수정사항이 있습니다.
davinci
대신text-davinci-003
를 사용하여 생성 파이프라인을 구축했습니다.- 새로운 prompt(
prompt.txt
)를 사용했으며, 이는 instruction 생성에 대해text-davinci-003
에 명시적인 요구사항을 제공하는 프롬포트입니다. 다만 약간의 오류가 있어서 이를 사용할 때는 https://github.com/tatsu-lab/stanford_alpaca/pull/24 이 내용을 수정해야 합니다. - classification 및 non-classification instructions 간의 차이를 삭제하여 데이터 생성 파이프라인을 단순화했습니다.
- 라마 논문과 같이 2~3개의 인스턴스를 사용하는 대신 각 명령에 대해 단일 인스턴스만 생성했습니다.
이제 정말로 생성 프로세스를 확인해보도록 하겠습니다. 데이터 생성은 다음과 같은 프로세스로 수행됩니다.
- 미리 준비한 seed set을 불러옵니다.
- 해당 seed set을 기반으로 ChatGPT(text-davinci-003)에게 질문(준비된 프롬포트를 사용)하여 데이터를 생성합니다.
- 생성된 데이터가 기존의 데이터와 유사한지를 체크하여 일정 비율 이상으로 유사할 경우 제거하고, 일정 비율 미만일 경우 데이터셋에 추가합니다. 즉 유니크한 질문을 수집한다고 보시면 됩니다.
생성에 사용된 프롬포트는 다음과 같습니다.
You are asked to come up with a set of 20 diverse task instructions. These task instructions will be given to a GPT model and we will evaluate the GPT model for completing the instructions.
Here are the requirements:
1. Try not to repeat the verb for each instruction to maximize diversity.
2. The language used for the instruction also should be diverse. For example, you should combine questions with imperative instrucitons.
3. The type of instructions should be diverse. The list should include diverse types of tasks like open-ended generation, classification, editing, etc.
2. A GPT language model should be able to complete the instruction. For example, do not ask the assistant to create any visual or audio output. For another example, do not ask the assistant to wake you up at 5pm or set a reminder because it cannot perform any action.
3. The instructions should be in English.
4. The instructions should be 1 to 2 sentences long. Either an imperative sentence or a question is permitted.
5. You should generate an appropriate input to the instruction. The input field should contain a specific example provided for the instruction. It should involve realistic data and should not contain simple placeholders. The input should provide substantial content to make the instruction challenging but should ideally not exceed 100 words.
6. Not all instructions require input. For example, when a instruction asks about some general information, "what is the highest peak in the world", it is not necssary to provide a specific context. In this case, we simply put "<noinput>" in the input field.
7. The output should be an appropriate response to the instruction and the input. Make sure the output is less than 100 words.
List of 20 tasks:
여기서 List of 20 tasks: 아래에 위에서 준비한 seed task 중 3개 정도를 넣고 나머지 17개를 생성하는 방식이라고 볼 수 있습니다. 즉 예시를 들면 아래와 같습니다.
You are asked to come up with a set of 20 diverse task instructions. These task instructions will be given to a GPT model and we will evaluate the GPT model for completing the instructions.
Here are the requirements:
1. Try not to repeat the verb for each instruction to maximize diversity.
2. The language used for the instruction also should be diverse. For example, you should combine questions with imperative instrucitons.
3. The type of instructions should be diverse. The list should include diverse types of tasks like open-ended generation, classification, editing, etc.
2. A GPT language model should be able to complete the instruction. For example, do not ask the assistant to create any visual or audio output. For another example, do not ask the assistant to wake you up at 5pm or set a reminder because it cannot perform any action.
3. The instructions should be in English.
4. The instructions should be 1 to 2 sentences long. Either an imperative sentence or a question is permitted.
5. You should generate an appropriate input to the instruction. The input field should contain a specific example provided for the instruction. It should involve realistic data and should not contain simple placeholders. The input should provide substantial content to make the instruction challenging but should ideally not exceed 100 words.
6. Not all instructions require input. For example, when a instruction asks about some general information, "what is the highest peak in the world", it is not necssary to provide a specific context. In this case, we simply put "<noinput>" in the input field.
7. The output should be an appropriate response to the instruction and the input. Make sure the output is less than 100 words.
List of 20 tasks:
1. Instruction: Converting 85 F to Celsius.
1. Input:
<noinput>
1. Output:
85 degrees Fahrenheit is equal to 29.44 degrees Celsius.
###
2. Instruction: Find out the largest one from a set of numbers. Output the number directly.
2. Input:
{1001, 22, 500, -3999, 1e6, 85, -2e6}
2. Output:
1e6
###
3. Instruction: Sort the given list ascendingly.
3. Input:
List: [10, 2, 5, -4, 92, 101]
3. Output:
[-4, 2, 5, 10, 92, 101]
###
4. Instruction:
이렇게 ChatGPT에게 질문을 주면 4번부터 20번까지 스스로 instruction, output 등을 생성하게 됩니다. 아주 좋은 아이디어인 것 같습니다.
이런 방식으로 만든 데이터셋은 500달러 미만이라는 저렴한 비용밖에 소모되지 않았습니다. 연구진은 또한 52K 생성 데이터가 기존 self-instruct 논문에서 공개된 데이터보다 훨씬 더 다양한 데이터를 보여준다는 것을 발견했다고 합니다. 이러한 다양성은 아래 그림에서 확인할 수 있습니다. 그림의 안쪽 원은 instruction의 root verb를 나타내고, 바깥 원은 direct objects를 나타냅니다.
Fine-tuning
알파카팀은 다음과 같은 파라미터 설정을 통해 파인튜닝을 수행했습니다.
Hyperparameter | LLaMA-7B | LLaMA-13B |
---|---|---|
Batch size | 128 | 128 |
Learning rate | 2e-5 | 1e-5 |
Epochs | 3 | 5 |
Max length | 512 | 512 |
Weight decay | 0 | 0 |
참고로 알파카팀에서 사용한 Instruction Fine Tunning이 무엇인지 소개해 드리면, Instruction Fine-tunning은 질문-대답 형식으로 이루어진 Instruction Datasets로 모델을 학습시키는 방법을 말합니다. 일반적인 파인튜닝과는 다르게 어떠한 특정 태스크(감정 분석, 요약문 생성 등)에 맞춰 파인튜닝하는 방식이 아닌 여러가지 주제를 주어 모델 학습을 수행하는데, 이러한 방법 덕에 전반적인 질문에 대한 문제해결능력이 생긴다고 합니다.
훈련 코드도 공개해주었습니다. 아래의 코드는 FSDP full_shard
mode에서 4개의 A100 80G GPU에서 LLaMA-7B를 파인튜닝하는 코드입니다. Python 3.10을 사용하면 되며, 다음 설정을 변경해야 합니다.
<your_random_port>
: 소유중인 포트<your_path_to_hf_converted_llama_ckpt_and_tokenizer>
: 체크포인트 변환 및 토크나이저를 저장할 경로<your_output_dir>
: 결과물을 저장할 경로
torchrun --nproc_per_node=4 --master_port=<your_random_port> train.py \
--model_name_or_path <your_path_to_hf_converted_llama_ckpt_and_tokenizer> \
--data_path ./alpaca_data.json \
--bf16 True \
--output_dir <your_output_dir> \
--num_train_epochs 3 \
--per_device_train_batch_size 4 \
--per_device_eval_batch_size 4 \
--gradient_accumulation_steps 8 \
--evaluation_strategy "no" \
--save_strategy "steps" \
--save_steps 2000 \
--save_total_limit 1 \
--learning_rate 2e-5 \
--weight_decay 0. \
--warmup_ratio 0.03 \
--lr_scheduler_type "cosine" \
--logging_steps 1 \
--fsdp "full_shard auto_wrap" \
--fsdp_transformer_layer_cls_to_wrap 'LlamaDecoderLayer' \
--tf32 True
아래의 코드는 OPT Fine-tuning 을 위한 코드입니다.
torchrun --nproc_per_node=4 --master_port=<your_random_port> train.py \
--model_name_or_path "facebook/opt-6.7b" \
--data_path ./alpaca_data.json \
--bf16 True \
--output_dir <your_output_dir> \
--num_train_epochs 3 \
--per_device_train_batch_size 4 \
--per_device_eval_batch_size 4 \
--gradient_accumulation_steps 8 \
--evaluation_strategy "no" \
--save_strategy "steps" \
--save_steps 2000 \
--save_total_limit 1 \
--learning_rate 2e-5 \
--weight_decay 0. \
--warmup_ratio 0.03 \
--lr_scheduler_type "cosine" \
--logging_steps 1 \
--fsdp "full_shard auto_wrap" \
--fsdp_transformer_layer_cls_to_wrap 'OPTDecoderLayer' \
--tf32 True
OOM 처리
LLaMA 7B 모델을 파인튜닝하기 위해서는 약 7 x 4 x 4 = 112GB의 VRAM이 필요합니다. 이런 경우 대부분의 컴퓨터에서는 OOM이 일어날 수 밖에 없는데요. 저자는 아래와 같은 옵션을 통해 메모리 사용 공간을 줄일 수 있다고 소개하고 있습니다.
- .NET으로 FSDP에 대한 CPU 오프로드를 켭니다.
-fsdp "full_shard auto_wrap offload"
이렇게 하면 런타임이 길어지는 대신 VRAM이 절약됩니다. - 경험상 DeepSpeed 3단계(오프로드 포함)는 때때로 오프로드가 있는 FSDP보다 메모리 효율성이 더 높을 수 있습니다. 다음은 파라미터 오프로드와 옵티마이저 오프로드가 모두 있는 GPU 4개와 함께 DeepSpeed 3단계를 사용하는 예입니다.
pip install deepspeed
torchrun --nproc_per_node=4 --master_port=<your_random_port> train.py \
--model_name_or_path <your_path_to_hf_converted_llama_ckpt_and_tokenizer> \
--data_path ./alpaca_data.json \
--bf16 True \
--output_dir <your_output_dir> \
--num_train_epochs 3 \
--per_device_train_batch_size 4 \
--per_device_eval_batch_size 4 \
--gradient_accumulation_steps 8 \
--evaluation_strategy "no" \
--save_strategy "steps" \
--save_steps 2000 \
--save_total_limit 1 \
--learning_rate 2e-5 \
--weight_decay 0. \
--warmup_ratio 0.03 \
--deepspeed "./configs/default_offload_opt_param.json" \
--tf32 True
LoRA
또한 LoRA에 대해 언급을 해 주었는데요. 저자가 직접 실험해 본 결과 총 메모리 공간을 112GB에서 약 7x4=28GB로 줄일 수 있었다고 합니다.
평가
스탠포드 알파카는 5명의 학생을 선발하여 text-davinci-003과 생성이 얼마나 잘 되었는지를 비교하였는데 90대 89라는 비슷한 성능을 보였다고 합니다.
다만 hallucination 문제 등이 있었는데, text-davinci-003에 비해 잘못된 정보를 퍼트리는 빈도가 많았다는 문제가 있습니다.
알파카의 수치화된 성능은 이후에 나온 Vicuna에서 확인할 수 있는데요.
성능 면에서 아쉬움은 있겠지만 LLaMA, 그리고 Alpaca의 공개 덕에 이러한 다양한 연구들이 시도되고 있다는 걸 확인할 수 있습니다.
KoAlpaca
스탠포드에서 학습 방법들을 공유해 준 덕에 한국에서도 다양한 도전이 이어지고 있는데요. 그 중 KoAlpaca 라는 프로젝트를 소개해드리도록 하겠습니다.
코알파카팀은 알파카의 학습 데이터셋과 동일한 방법으로 학습을 시도했는데, 스탠포드에서 공개한 seed set을 번역한 후 같은 프로세스를 따라 데이터셋을 생성했다고 합니다.
LLaMA를 backbone으로 한 경우에 성능이 좋지 않아서, Polyglot이라는 한국어 기반 LLM을 backbone으로 변경했다는 점이 아쉽기는 하지만 알파카의 학습 방식을 그대로 사용한 점이 의의가 있다고 생각합니다.
아래 링크에서 ChatKoAlpaca(Polyglot-12.8B)를 경험해 볼 수 있습니다.