한 권으로 끝내는 실전 LLM 파인튜닝 - 강다솔 지음/위키북스 |
03. 전체 파인튜닝
키워드 데이터 생성
데이터셋(jaehy12/new3)에 포함되지 않은 각 기사별 키워드 정보를 추출하는 것부터 시작한다. 주요 코드는 아래와 같다.
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer, device_map="auto")
def key_word_prompt(input_text, summary_text):
return [
{"role": "user", "content": f"{input_text}"},
{"role": "assistant", "content": f"{summary_text}"},
{"role": "user", "content": "중요한 키워드 5개를 뽑아주세요."},
{"role": "assistant", "content": ""}
]
def extract_keywords_batch(batch):
prompts = [key_word_prompt(original, summary) for original, summary in zip(batch["original"], batch["summary"])]
generated_texts = pipe(prompts, max_new_tokens=150, return_full_text=False)
keywords = [gen_text[0]["generated_text"] for gen_text in generated_texts]
batch["keywords"] = keywords
return batch
트랜스포머 라이브러리 pipeline을 이용해서 키워드를 생성한다. 첫 번째 인자로 수행할 작업을 지정하는데 텍스트 생성 작업에 해당하는 "text-generation"을 넣는다. 생성된 결과물의 각 항목은 generated_text 키를 갖는 딕셔너리 형태다. key_word_prompt 함수를 사용해 원본 텍스트와 요약 텍스트로 짝지어진 텍스트들을 '모델이 이해할 수 있는 질문-답변 형식의 지시문 목록'으로 변경한다. 모델이 맥락을 이해할 수 있도록 하는 과정이라고 하는데, 이렇게 role(user, assistant), content 형식으로 뭔가를 요청하는 방식은 전통적인 프로그래밍에 익숙한 내게는 여전히 어색하다. 차치하고 이제 데이터셋은 기존 '원본 텍스트', '요약 텍스트'에 '키워드'까지 포함된 형태가 된다. 방금 구현한 extract_keywords_batch 함수를 사용해서 아래와 같이 데이터를 만드는 로직을 작성한다.
# dataset에 keyword 열 추가 (batch 단위로 처리)
sample_dataset = dataset["train"].shuffle(seed=42).select(range(1000))
sample_dataset = sample_dataset.map(extract_keywords_batch, batched=True, batch_size=20) # 적절한 batch_size 선택
sample_dataset
위 코드의 출력 결과는 아래와 같은데 keywords라는 새로운 항목이 데이터셋에 더해진 것을 확인할 수 있다.
Dataset({
features: ['original', 'summary', 'keywords'],
num_rows: 1000
})
데이터 전처리
이제 모델이 쉽게 이해할 수 있도록 '대화 형식'으로 데이터를 전처리한다.
def chat_keyword_summary_format(example):
return [
{"role": "user", "content": f"다음 텍스트를 한국어로 간단히 요약 및 관련 키워를 추출해주세요:\n{example['original']}"},
{"role": "assistant", "content": f"한국어 요약:{example['summary']}\n키워드:{example['keywords']}"}
]
formatted = tokenizer.apply_chat_template(
chat_keyword_summary_format(sample_dataset[0]), tokenize=False
)
print(formatted)
사용자(user)는 원본 텍스트를 요약하고 키워드도 추출해 달라고 요청한다. 이에 대해 AI(assistant)는 요청받은 대로 요약본과 키워드를 사용자에게 전달한다. 이 두 가지 정보는 각각 example['summary'], example['keywords'] 항목에 저장된다. 이어서 아래 코드와 같이 (모델이 학습할 수 있도록) 데이터셋에 tokenize 함수를 적용해서 토큰화된 새로운 데이터셋인 tokenized_sample_dataset으로 변환시킨다.
EOS_TOKEN = tokenizer.eos_token
def tokenize(element):
formatted = tokenizer.apply_chat_template(
chat_keyword_summary_format(element), tokenize=False
) + EOS_TOKEN
outputs = tokenizer(formatted)
return {
"input_ids": outputs["input_ids"],
"attention_mask": outputs["attention_mask"],
}
tokenized_sample_dataset = sample_dataset.map(tokenize)
데이터셋 분리 및 콜레이터 설정
먼저 데이터셋을 학습용/테스트용으로 분리한다.
tokenized_sample_dataset = tokenized_sample_dataset.train_test_split(
test_size=0.1,
seed=42
)
tokenized_sample_dataset
전체 데이터의 10%를 테스트 데이터로 설정한 것을 확인할 수 있다(훈련 데이터는 자연히 90%로 설정됨). 이어서 모델이 중점적으로 학습해야 할 부분을 알려주는 콜레이터(Collator)를 설정한다. 콜레이터는 데이터 처리 과정에서 다양한 역할을 수행하는데 여기서는 특히 라벨러(labeler) 역할로 사용한다.
response_template_ids = tokenizer.encode(
"<start_of_turn>model\n",
add_special_tokens=False
)
collator = DataCollatorForCompletionOnlyLM(
response_template_ids, tokenizer=tokenizer
)
위 코드는 모델이 <start_of_turn>model\n 이후의 대화에 집중하도록 도와주는 로직이다. DataCollatorForCompletionOnlyLM 는 TRL 라이브러리에서 제공하는 데이터 정리(collation) 도구라고 한다. 8일 차 스터디는 여기까지. 9일 차에서는 학습 파라미터를 설정하는 작업이 이어진다.
끝.
'개발 > AI' 카테고리의 다른 글
[Day9] LLM 스터디 1기 - 단일 GPU Gemma 파인튜닝 3 (1) | 2025.01.19 |
---|---|
[Day7] LLM 스터디 1기 - 단일 GPU Gemma 파인튜닝 (1) | 2025.01.17 |
[Day6] LLM 스터디 1기 - GPU 병렬화 기법 (0) | 2025.01.16 |
[Day5] LLM 스터디 1기 - GPT, Gemma, Llama3 모델 특징 비교 (1) | 2025.01.15 |
[Day4] LLM 스터디 1기 - 파인튜닝 개념 (1) | 2025.01.11 |