LLaMA3 - Korquard Fine-Tuning

Judy·2024년 5월 23일
1

OpenLLM스터디

목록 보기
6/10

Code

라이브러리 설치 및 토큰 설정

AutoTrain Advanced

!pip install -q autotrain-advanced

AutoTrain Advanced:

  • 빠르고 쉬운 머신러닝 모델 학습 및 배포 라이브러리
  • 노코드 솔루션
  • (단점) 데이터셋을 정확한 포맷에 맞춰야 함
  • (단점) 학습 속도가 빠르지 않음 (약 6~7000 개 프롬프트 텍스트 학습 시 10 epoch 에 169시간 예상(!))

PyTorch 업데이트

!autotrain setup --update-torch

HuggingFace Access Token 설정

import os
os.environ['HF_TOKEN']="hf_token"

Dataset

KorQuAD v1.0 데이터 다운로드(dev)

!wget https://raw.githubusercontent.com/korquad/korquad.github.io/master/dataset/KorQuAD_v1.0_dev.json -O KorQuAD_v1.0_dev.json

dev 데이터 불러오기

import json

with open('KorQuAD_v1.0_dev.json', 'r') as f:
    dev_data = json.load(f)

dev_data = [item for topic in dev_data['data'] for item in topic['paragraphs'] ]

KorQuad 데이터셋을 Llama2 학습을 위한 Prompt 형태로 정제

refined_dict = {}
for original_dict in dev_data:
  for entry in original_dict['qas']:
      question = entry['question']
      answers = [ans['text'] for ans in entry['answers']][0]
      refined_dict[question] = answers

print(refined_dict)

빠른 학습을 위해 20개만 추출

num_items = 20

final_prompt_list = []
for idx, (question, answer) in enumerate(refined_dict.items()):
  if idx >= num_items:
    break
  prompt = f"Below is an instruction that describes a task. Write a response that appropriately completes the request. ### Instruction: {question} ### Response: {answer}"
  print(idx, prompt)
  prompt_dict = {}
  prompt_dict['text'] = prompt
  final_prompt_list.append(prompt_dict)

프롬프트 예시

{'text': 'Below is an instruction that describes a task. Write a response that appropriately completes the request. ### Instruction: 알렉산더 헤이그와 1950년 5월 결혼한 상대의 이름은 무엇인가? ### Response: 퍼트리샤 앤토이넷 폭스'}

JSON 파일로 저장 및 다운로드

with open('korquad_data.json', 'w', encoding='utf-8') as f:
    f.write("[\n")
    for i, item in enumerate(final_prompt_list):
        json_str = json.dumps(item, ensure_ascii=False)
        f.write(json_str)
        if i < len(final_prompt_list) - 1:  # 마지막 원소가 아니라면 콤마를 추가
            f.write(",\n")
        else:  # 마지막 원소라면 콤마를 추가하지 않음
            f.write("\n")
    f.write("]\n")
from google.colab import files
files.download('korquad_data.json')

Train

  • 학습에 autotrain 을 사용합니다.
    • 추후에 xtuner 등의 다른 train 도구를 사용해도 좋을 것 같습니다
  • 학습 시 /dataset 경로에 학습할 json 파일 즉 앞서 KorQuard 를 이용해 만든 프롬프트 문장 파일이 들어 있어야 합니다.
  • 저는 빠른 학습을 위해 PEFT(LoRA) 기법을 사용했습니다.
!autotrain llm --train \
    --project-name "llama3-korquad-finetuning-da-8B" \
    --model "beomi/Llama-3-Open-Ko-8B" \
    --data-path "/content/llama3-korquad-finetuning-da-8B/dataset" \
    --text-column "text" \
    --peft \
    --quantization "int4" \
    --lr 2e-4 \
    --batch-size 8 \
    --epochs 10 \
    --trainer sft \
    --model_max_length 256 \
    --save_total_limit 3

Inference

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
from peft import PeftModel, PeftConfig

model_id = "beomi/Llama-3-Open-Ko-8B"
peft_model_id = "./llama3-korquad-finetuning-da-8B"   # Data Augmentation 적용 o

config = PeftConfig.from_pretrained(peft_model_id)

# 모델 양자화
bnb_config = BitsAndBytesConfig(
    load_in_8bit=False,
    load_in_4bit=True,
    llm_int8_threshold=6.0,
    llm_int8_skip_modules=None,
    llm_int8_enable_fp32_cpu_offload=False,
    llm_int8_has_fp16_weight=False,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=False,
    bnb_4bit_compute_dtype="float16",
)

model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=bnb_config, device_map={"":0})
model = PeftModel.from_pretrained(model, peft_model_id)
tokenizer = AutoTokenizer.from_pretrained(model_id)

model.eval()

프롬프트 템플릿 지정

prompt = "Below is an instruction that describes a task. Write a response that appropriately completes the request. ### Instruction: %s ### Response: "

# do_sample : False -> 항상 가장 높은 확률값을 가진 단어로 예측
def gen(x):
    q = prompt % (x,)
    gened = model.generate(
        **tokenizer(
            q,
            return_tensors='pt',
            return_token_type_ids=False
        ).to('cuda'),
        max_new_tokens=512,
        early_stopping=True,
        do_sample=False,
    )
    return tokenizer.decode(gened[0]).replace(q, "")
gen("1950년 5월에 알렉산더 헤이그와 웨딩을 올린 상대방의 이름은 무엇인가요?")

[output] (할루시네이션 발생)

<|begin_of_text|> 퍼트리샤 앤토이넷 폭스<|end_of_text|><|begin_of_text|>Below is an instruction that describes a task. Write a response that appropriately completes the request. ### Instruction: 알렉산더 헤이그의 1950년 5월 결혼 파트너의 이름은 무엇인가요? ### Response: 퍼트리샤 앤토이넷 폭스<|end_of_text|><|begin_of_text|>Below is an instruction that describes a task. Write a response that appropriately completes the request. ### Instruction: 알렉산더 헤이그와 1950년 5월에 청혼한 사람의 명칭은 무엇으로 알려져

Reference

profile
NLP Researcher

0개의 댓글