Post

LLaMA 3.0 SFT (2) Tokenizer, Dataset

앞서 ‘LLaMA 3.0 SFT (1) 환경 세팅’에서 LLaMA 3.0 SFT를 위한 실험 환경 구성에 대해 살펴보았습니다.

7. Tokenizer

1
2
3
4
5
6
# Tokenizer 설정
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B")
tokenizer.add_special_tokens({"pad_token": "<|reserved_special_token_250|>"})
model.config.pad_token_id = tokenizer.pad_token_id

LLaMA-3.0 모델의 SFT를 위해서는 위와 같이 Tokenizer를 정의합니다. 한가지 독특한 점이 있습니다. “pad_token”을 special token으로 별도 추가해준다는 점입니다. LLaMA-3.0 모델은 기본적으로 tokenizer에서 “pad_token”을 정의하고 있지 않습니다. Meta에서는 LLaMA 3.0 사전학습 과정에서 GPU를 보다 효율적으로 사용하기 위해, 모든 데이터를 LLaMA-3.0의 max-length에 맞춰 학습을 진행했습니다. 즉 sequence 길이에 여분이 없도록 했다는 것입니다. max-length는 8,192 토큰입니다. 이보다 짧은 입력 데이터는 함께 붙이고, 모아서 이를 붙여서 max-length에 맞도록 했다는 것입니다. 주로 문서 단위의 데이터가 학습에 활용되었고, 이 과정에서 서로 다른 문서들이 합쳐질 경우, self-attention이 문서 경계를 넘지 않도록 masking을 진행했다고 합니다.

더 자세한 내용은 논문과 위 thread를 참고할 수 있습니다. 중요한 점은 사전학습 과정에서 pad_token이 사용되지 않았고, 우리는 사용해야한다는 점입니다. 따라서 새로 정의를 해줘야 겠죠? 그래서 위와 같이 add_special_tokens를 추가합니다.

  • eos_tokenpad_token으로 적용해 SFT를 수행하는 경우도 있다고 하는 데, 이는 학습 과정에서 혼선을 초래할 수 있습니다. 따라서 별도의 pad_token을 설정해줍니다.

8. Dataset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Prompt/Response Format 관련 설정
EOS_TOKEN = tokenizer.eos_token

def convert_to_alpaca_format(instruction, response):
    alpaca_format_str = f"""
    Below is an instruction that describes a task. \
    Write a response that appropriately completes the request.\
    \n\n### Instruction:\n{instruction}\n\n### Response:\n{response}\
    """
    return alpaca_format_str

def prompt_formatting_func(examples):
    instructions = examples["instruction"]
    outputs      = examples["output"]
    texts = []
    for instruction, output in zip(instructions, outputs):
        alpaca_formatted_str = convert_to_alpaca_format(instruction, output) + EOS_TOKEN
        texts.append(alpaca_formatted_str)
    return { "text" : texts, }

LLaMA-3.0을 SFT할 때, Instruction Prompt를 입력 데이터로 구성해 진행할 예정입니다(‘Instruction Tuning’). 따라서 위와 같이 ‘convert_to_alpaca_format’ 함수로 Instruction Formatting을 정의하고, 이를 활용해 ‘prompt_formatting_func’ 함수에서 학습 데이터 샘플을 전처리 수행하는 함수를 정의합니다.

중요한 점은 + EOS_TOKEN 입니다.

  • alpaca_formatted_str = convert_to_alpaca_format(instruction, output) + EOS_TOKEN

입력 데이터의 마지막을 EOS_TOKEN으로 처리해줘야, 모델이 문장을 마치는 법까지 제대로 학습할 수 있습니다.

이렇게 정의한 함수를 이용해 아래와 같이 SFT에 활용할 학습 데이터셋을 제작합니다.

‘alpaca-cleaned’ 데이터를 불러와, 앞서 정의한 두 함수를 활용해 Instruction Tuning을 위한 데이터셋을 정의합니다.

  • no_input_dataset = dataset.filter(lambda example: example['input'] == '')

위 과정은 Alaca 데이터 샘플 중 ‘input’이 들어간 샘플을 모두 제외하는 과정입니다. 선택의 영역이지만 input값 없이 Instruction과 Response를 pair로만 학습 데이터를 구성하고자 했습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Dataset Load
from datasets import load_dataset

dataset = load_dataset("yahma/alpaca-cleaned", split="train")

dataset = dataset.shuffle(seed=42)
no_input_dataset = dataset.filter(lambda example: example['input'] == '')
mapped_dataset = no_input_dataset.map(prompt_formatting_func, batched=True)
split_dataset = mapped_dataset.train_test_split(test_size=0.01, seed=42)

train_dataset = split_dataset['train']
test_dataset = split_dataset['test']

print(f"Train dataset size: {len(train_dataset)}")
print(f"Test dataset size: {len(test_dataset)}")

그리고 한가지 더 정의합니다. 이 부분은 모델이 조금 더 학습을 잘하길 기대하며 추가로 세팅해주는 부분입니다. DataCollatorForCompletionOnlyLM를 정의해 SFT 과정에서 모델의 response(:= completion)에만 더욱 집중하도록 합니다.

이는 input 데이터에서 모델의 loss backpropagation이 competion외에는 ignore되도록 함으로써, 모델의 generation 성능 향상에 더욱 효율적으로 집중할 수 있도록 도와줍니다.

1
2
3
4
5
6
# Data Collator 설정
from trl import DataCollatorForCompletionOnlyLM
data_collator_param = {}
response_template = "### Response:\n"
collator = DataCollatorForCompletionOnlyLM(response_template=response_template, tokenizer=tokenizer, mlm=False)
data_collator_param["data_collator"] = collator

다음 post ‘LLaMA 3.0 SFT (3) Trainer’에서는 직접 모델을 학습하는 과정을 이어서 살펴보겠습니다.

Reference

This post is licensed under CC BY 4.0 by the author.