Fine-tuning Model Merak-7B
Pada artikel ini, saya akan membahas proses fine-tuning model Merak-7B. Model ini didasari pada Meta Llama-2–7B-Chat-HF yang telah disempurnakan menggunakan data dari artikel Wikipedia Indonesia yang telah dibersihkan. Llama-2 adalah model bahasa yang dirancang untuk memahami dan menghasilkan teks dengan tingkat kompleksitas yang tinggi, meningkatkan kemampuan pemahaman bahasa alami dan kemampuan generatif model. Model ini biasanya digunakan dalam berbagai aplikasi seperti pemrosesan bahasa alami, chatbot, pencarian semantik, dan tugas linguistik lainnya. Dengan kemampuan yang luar biasa, Llama-2 membantu meningkatkan interaksi manusia-komputer dan menyediakan solusi cerdas dalam berbagai konteks berbasis teks. Fine-tuning model Merak-7B bertujuan untuk lebih meningkatkan performa dan adaptabilitasnya dalam pemrosesan bahasa Indonesia, sehingga memberikan hasil yang lebih relevan dan akurat dalam berbagai aplikasi.
Fine-Tuning
Fine-tuning adalah proses penyesuaian parameter suatu model mesin pembelajaran yang sudah dilatih sebelumnya, agar dapat secara khusus memahami dan mengatasi tugas atau data yang spesifik. Fine-tuning diperlukan ketika model yang sudah ada perlu disesuaikan dengan domain atau permasalahan tertentu yang tidak sepenuhnya tercakup oleh data pelatihan awalnya. Manfaat utama fine-tuning adalah meningkatkan kinerja model pada tugas khusus tersebut tanpa perlu melatih model dari awal, yang seringkali membutuhkan sumber daya komputasi yang besar.
Ada dua cara fine-tuning, yaitu Supervised Fine-Tuning (SFT) dan Reinforcement Learning from Human Feedback (RLHF). Masing-masing metode memiliki kekuatan dan kelemahan yang berbeda dalam konteks pembelajaran mesin, terutama dalam pengembangan model bahasa besar (Large Language Models, LLMs). Pada tutorial ini, saya akan menggunakan Supervised Fine-Tuning (SFT)
Supervised Fine-Tuning adalah proses pelatihan model menggunakan data yang diberi label secara eksplisit. Berikut adalah langkah-langkah umum dalam SFT:
- Pengumpulan Data: Mengumpulkan dataset yang berisi pasangan input-output. Misalnya, untuk tugas tanya-jawab, data ini mungkin berisi pertanyaan dan jawaban yang sesuai.
- Pemberian Label: Data diberi label secara manual oleh manusia atau menggunakan metode lain. Setiap contoh dalam dataset memiliki jawaban atau keluaran yang diinginkan.
- Pelatihan Model: Model dilatih untuk memprediksi output yang benar berdasarkan input yang diberikan, menggunakan algoritma optimasi seperti Adam atau SGD untuk meminimalkan loss function (misalnya, cross-entropy loss).
- Evaluasi dan Validasi: Model dievaluasi menggunakan dataset validasi untuk memastikan generalisasi yang baik dan menghindari overfitting.
SFT mengandalkan kualitas dan kuantitas data berlabel untuk meningkatkan kemampuan model. Keuntungan utama dari SFT adalah kesederhanaannya dan kemampuannya untuk dengan cepat mengadopsi pengetahuan baru dari data berlabel.
Pada tutorial ini, saya akan memberikan langkah-langkah untuk melakukan fine tuning yang diawali dengan data preprocessing dan dilanjutkan dengan proses Fine Tuning.
Instalasi
Jalankan perintah ‘create’ untuk membuat environment baru dengan nama finetuning
dan menginstal Python versi 3.9 di dalamnya. Setelah proses selesai, aktifkan environment tersebut.
Lalu, beberapa library juga perlu diinstal seperti, PyTorch versi 1.13.1, Torchvision versi 0.14.1, dan Torchaudio versi 0.13.1, serta mengkonfigurasi PyTorch untuk menggunakan CUDA 11.7. Paket-paket ini diambil dari channel pytorch
dan nvidia
.
Selain itu, beberapa package juga perlu diinstal dari channel conda-forge
, sebagai berikut.
huggingface_hub
: API untuk berinteraksi dengan hub Hugging Face.transformers
: Library untuk pemodelan bahasa menggunakan transformer.sentence-transformers
: Library untuk embedding kalimat.datasets
: Library untuk memuat dan memproses dataset NLP.matplotlib
: Library untuk visualisasi data.seaborn
: Library untuk visualisasi statistik.faiss-gpu
: Library untuk pencarian kesamaan vektor yang dioptimalkan untuk GPU.
conda create -n finetuning python=3.9
conda activate finetuning
conda update -n base -c conda-forge conda
conda install pytorch==2.3.0 torchvision==0.18.0 torchaudio==2.3.0 pytorch-cuda=12.1 -c pytorch -c nvidia
conda install -c conda-forge huggingface_hub transformers sentence-transformers datasets matplotlib seaborn faiss-gpu
pip install peft trl bitsandbytes wandb
Data Preprocessing
1. Import modul yang digunakan
Pada langkah ini, kita mengimpor berbagai modul yang diperlukan, termasuk datasets
untuk memuat dataset, transformers
untuk tokenizer, sentence_transformers
untuk model embedding kalimat, faiss
untuk pencarian yang efisien, serta beberapa modul Python standar lainnya.
from datasets import load_dataset
from transformers import AutoTokenizer
from sentence_transformers import SentenceTransformer
import faiss
from datasets import Dataset, DatasetDict
from tqdm.autonotebook import tqdm
import numpy as np
import pickle
2. Memuat Dataset dan Tokenizer
- Di notebook ini, saya akan menggunakan SQuAD data (https://huggingface.co/datasets/genta-tech/squad_pairs_indo).
- Stanford Question Answering Dataset (SQuAD) adalah terdiri dari pertanyaan-pertanyaan yang diajukan oleh crowdworkers pada sekumpulan artikel Wikipedia.
- Nah, data SQuAD yang akan kita pakai adalah versi terjemahan Indonesia. Diterjemahkan menggunakan Helsinki-NLP/EN-ID.
- Dataset teks yang berisi pasangan pertanyaan dan jawaban dalam Bahasa Indonesia ini selanjutnya akan diubah menjadi urutan token yang bisa dipahami oleh model menggunakan Tokenizer.
- Disini tokenizer yang digunakan adalah model Merak-7B-v2 yang sudah dilatih sebelumnya (pretrained model).
from datasets import load_dataset
from transformers import AutoTokenizer
# Memuat dataset "squad_pairs_indo"
dataset = load_dataset("genta-tech/squad_pairs_indo")
# Memuat tokenizer untuk model Llama-2
tokenizer = AutoTokenizer.from_pretrained("Ichsan2895/Merak-7B-v2")
3. Menganalisis Panjang Token
- Kode berikut digunakan untuk menghitung jumlah token untuk setiap instruksi (pertanyaan) dan jawaban di set pelatihan menggunakan tokenizer.
- Kemudian, script menggabungkan jumlah tersebut untuk mendapatkan jumlah total token untuk setiap pasangan pertanyaan-jawaban.
def tokenize_combined(dataset: Dataset):
instruction_token_counts = [
len(tokenizer.tokenize(example["0"])) for example in dataset["train"]
]
output_token_counts = [
len(tokenizer.tokenize(example["1"])) for example in dataset["train"]
]
combined_token_counts = [
instruction + output
for instruction, output in zip(instruction_token_counts, output_token_counts)
]
return combined_token_counts
combined_token_counts = tokenize_combined(dataset)
4. Memvalidasi dan Menyaring Data
Langkah ini bertujuan untuk memvalidasi dan menyaring data berdasarkan jumlah token. Hanya baris dengan jumlah token gabungan kurang dari atau sama dengan 100 yang dipertahankan.
valid_indices = [i for i, count in enumerate(combined_token_counts) if count <= 100]
print(f"Number of valid rows: {len(valid_indices)}")
print(f"Removing {len(dataset['train']) - len(valid_indices)} rows...")
# Ekstrak baris yang valid berdasarkan indeks
dataset["train"] = dataset["train"].select(valid_indices)
# Mendapatkan jumlah token untuk baris yang valid
token_counts = [combined_token_counts[i] for i in valid_indices]
5. Menghilangkan Duplikasi Data
- Fungsi
deduplicate_dataset
bertujuan untuk menghilangkan duplikasi data menggunakan embedding kalimat dan pencarian k-nearest neighbor dengan threshold kemiripan tertentu. Proses ini membantu memastikan bahwa data latih tidak mengandung duplikasi yang bisa mengganggu model. - Dalam konteks pemrosesan bahasa alami atau representasi data, embedding adalah representasi numerik dari kata, frasa, atau dokumen dalam ruang vektor. Embedding ini menangkap hubungan semantik dan kesamaan antar entitas.
- Idenya adalah mengubah data menjadi embedding dan kemudian mengukur kesamaan antara embedding tersebut. Jika embedding dua bagian data berdekatan satu sama lain dalam ruang vektor, hal ini menunjukkan bahwa konten dasarnya serupa atau hampir identik.
- Fungsi ini menggunakan model pre-trained sentence embedding
indo-sentence-bert-base
(https://huggingface.co/firqaaa/indo-sentence-bert-base) untuk mengubah kalimat jawaban menjadi representasi numerik. - Script membangun index pencarian menggunakan library Faiss untuk menemukan embedding yang mirip.
- Fungsi ini ber-iterasi melalui setiap embedding jawaban dan memeriksa kesamaannya dengan embedding lainnya menggunakan cosine similarity.
- Pertanyaan dan jawaban yang memiliki cosine similarity di atas ambang batas (0,95 dalam kasus ini) dianggap duplikat.
- Hanya satu pertanyaan dari setiap pasangan duplikat yang disimpan di dataset akhir.
- Proses deduplikasi dan pengunggahan dataset mungkin memakan waktu, tergantung pada ukuran dataset dan .
def deduplicate_dataset(dataset: Dataset, model: str, threshold: float):
sentence_model = SentenceTransformer(model, device="cuda")
outputs = [example["1"] for example in dataset["train"]]
print("Converting text to embeddings...")
embeddings = sentence_model.encode(outputs, show_progress_bar=True)
dimension = embeddings.shape[1]
index = faiss.IndexFlatIP(dimension)
normalized_embeddings = embeddings / np.linalg.norm(
embeddings, axis=1, keepdims=True
)
index.add(normalized_embeddings)
print("Filtering out near-duplicates...")
D, I = index.search(normalized_embeddings, k=2)
to_keep = []
for i in tqdm(range(len(embeddings)), desc="Filtering"):
if D[i, 1] >= threshold:
nearest_neighbor = I[i, 1]
if i not in to_keep and nearest_neighbor not in to_keep:
to_keep.append(i)
else:
to_keep.append(i)
dataset = dataset["train"].select(to_keep)
return DatasetDict({"train": dataset})
deduped_dataset = deduplicate_dataset(dataset, "firqaaa/indo-sentence-bert-base", 0.95)
6. Filtering Berdasarkan Panjang Token
- Filtering digunakan untuk mengambil
k
baris teratas berdasarkan jumlah token terbanyak. Sehingga hanya data yang paling relevan dan informatif untuk pelatihan model yang digunakan. Selain itu juga dapat mengurangi penggunaan memori selama pelatihan.
def get_top_k_rows(dataset, token_counts, k):
sorted_indices = sorted(
range(len(token_counts)), key=lambda i: token_counts[i], reverse=True
)
top_k_indices = sorted_indices[:k]
top_k_data = {
"0": [dataset["train"][i]["0"] for i in top_k_indices],
"1": [dataset["train"][i]["1"] for i in top_k_indices],
}
return Dataset.from_dict(top_k_data)
combined_token_counts = tokenize_combined(deduped_dataset)
k = 1000
top_k_dataset = get_top_k_rows(deduped_dataset, combined_token_counts, k)
7. Menerapkan Template Chat (chat_template)
- Fungsi
chat_template
menyusun ulang data menjadi format yang diinginkan dengan menambahkan template instruksi dan respon. Hal ini membantu dalam menyelaraskan format data untuk pelatihan model. - Fungsi ini menambahkan header “### Instruksi:” sebelum pertanyaan dan “### Respon:” sebelum jawaban.
def chat_template(example):
example["0"] = f"### Pertanyaan:\n{example['0']}\n\n### Jawaban:\n"
return example
# Terapkan template chat ke setiap data point
dataset = dataset.map(chat_template)
8. Menyimpan dan Mengunggah Dataset ke Hugging Face Hub
- Langkah terakhir adalah menyimpan dataset dan mengunggahnya ke Hugging Face Hub menggunakan token akses
access_token_write
adalah token yang diperlukan untuk mengunggah dataset ke Hugging Face Hub disediakan. Pastikan untuk menggantiaccess_token_write
dengan token Anda sendiri yang diperoleh dari Hugging Face Hub: https://huggingface.co/settings/tokens.- Pengunggahan: Dataset diunggah ke Hub dengan nama “squad_pairs_indo_1000” menggunakan fungsi
push_to_hub
.
# Akses token untuk mengunggah dataset ke Hugging Face Hub
access_token_write = "token_Anda"
# Unggah dataset ke Hugging Face Hub
dataset.push_to_hub("squad_pairs_indo_1000", token=access_token_write)
Overall Code
from datasets import load_dataset
from transformers import AutoTokenizer
from sentence_transformers import SentenceTransformer
import faiss
from datasets import Dataset, DatasetDict
from tqdm.autonotebook import tqdm
import numpy as np
import pickle
def tokenize_combined(dataset: Dataset):
instruction_token_counts = [
len(tokenizer.tokenize(example["0"])) for example in dataset["train"]
]
output_token_counts = [
len(tokenizer.tokenize(example["1"])) for example in dataset["train"]
]
combined_token_counts = [
instruction + output
for instruction, output in zip(instruction_token_counts, output_token_counts)
]
return combined_token_counts
def deduplicate_dataset(dataset: Dataset, model: str, threshold: float):
sentence_model = SentenceTransformer(model, device="cuda")
outputs = [example["1"] for example in dataset["train"]]
print("Converting text to embeddings...")
embeddings = sentence_model.encode(outputs, show_progress_bar=True)
dimension = embeddings.shape[1]
index = faiss.IndexFlatIP(dimension)
normalized_embeddings = embeddings / np.linalg.norm(
embeddings, axis=1, keepdims=True
)
index.add(normalized_embeddings)
print("Filtering out near-duplicates...")
D, I = index.search(normalized_embeddings, k=2)
to_keep = []
for i in tqdm(range(len(embeddings)), desc="Filtering"):
if D[i, 1] >= threshold:
nearest_neighbor = I[i, 1]
if i not in to_keep and nearest_neighbor not in to_keep:
to_keep.append(i)
else:
to_keep.append(i)
dataset = dataset["train"].select(to_keep)
return DatasetDict({"train": dataset})
def get_top_k_rows(dataset, token_counts, k):
sorted_indices = sorted(
range(len(token_counts)), key=lambda i: token_counts[i], reverse=True
)
top_k_indices = sorted_indices[:k]
top_k_data = {
"0": [dataset["train"][i]["0"] for i in top_k_indices],
"1": [dataset["train"][i]["1"] for i in top_k_indices],
}
return Dataset.from_dict(top_k_data)
def chat_template(example):
example["0"] = f"### Instruction:\n{example['0']}\n\n### Response:\n"
return example
dataset = load_dataset("genta-tech/squad_pairs_indo")
tokenizer = AutoTokenizer.from_pretrained("Ichsan2895/Merak-7B-v2")
combined_token_counts = tokenize_combined(dataset)
valid_indices = [i for i, count in enumerate(combined_token_counts) if count <= 100]
print(f"Number of valid rows: {len(valid_indices)}")
print(f"Removing {len(dataset['train']) - len(valid_indices)} rows...")
dataset["train"] = dataset["train"].select(valid_indices)
token_counts = [combined_token_counts[i] for i in valid_indices]
deduped_dataset = deduplicate_dataset(dataset, "firqaaa/indo-sentence-bert-base", 0.95)
combined_token_counts = tokenize_combined(deduped_dataset)
k = 1000
top_k_dataset = get_top_k_rows(deduped_dataset, combined_token_counts, k)
dataset = DatasetDict({"train": top_k_dataset})
dataset = dataset.map(chat_template)
access_token_write = "token_Anda"
dataset.push_to_hub("squad_pairs_indo_1000", token=access_token_write)
Fine Tuning
Dalam supervised fine-tuning (SFT), ada beberapa opsi teknik yang dapat digunakan untuk fine tuning LLM, seperti Full Fine-Tuning atau menggunakan teknik parameter-efficient fine-tuning (PEFT), seperti Low-Rank Adaptation (LoRA), dan Quantized Low-Rank Adaptation (QLoRA). Dalam tutorial ini, saya akan menggunakan QLoRA.
1. Import Library
import torch
from datasets import load_dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
pipeline,
)
from peft import LoraConfig, PeftModelForCausalLM, prepare_model_for_kbit_training
from trl import SFTTrainer, SFTConfig
Kode ini mengimpor pustaka yang diperlukan:
torch
: Pustaka utama untuk komputasi tensor dan machine learning.datasets
: Untuk memuat dataset yang akan digunakan.transformers
: Untuk bekerja dengan model transformer dari Huggingface.peft
: Untuk konfigurasi Low-Rank Adaptation (LoRA).trl
: Untuk fine-tuning supervised model dengan SFTTrainer.
2. Konfigurasi Model
Bagian ini menentukan model dasar (base_model
) dan model baru yang akan disimpan setelah fine-tuning (new_model
). Dataset yang digunakan adalah "fatyanosa/squad_pairs_indo_1000".
# Model
base_model = "Ichsan2895/Merak-7B-v2"
new_model = "Merak-7B-squadpairs-indo"
# Dataset
dataset = load_dataset("fatyanosa/squad_pairs_indo_1000", split="train")
3. Tokenizer
# Tokenizer
tokenizer = AutoTokenizer.from_pretrained(base_model, use_fast=True)
tokenizer.pad_token = tokenizer.unk_token
tokenizer.padding_side = "right"
Mengatur tokenizer untuk model dasar. Tokenizer digunakan untuk memetakan teks ke dalam token yang dapat diproses oleh model.
4. Konfigurasi Quantization
Quantization digunakan untuk mengurangi ukuran model dan meningkatkan efisiensi komputasi dengan menggunakan representasi bit yang lebih rendah (4-bit dalam kasus ini).
# Quantization configuration
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
5. Konfigurasi LoRA
LoRA digunakan untuk menyesuaikan bobot model dengan menambahkan parameter tambahan pada layer tertentu tanpa mengubah keseluruhan model.
# LoRA configuration
peft_config = LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
target_modules=[
"up_proj",
"down_proj",
"gate_proj",
"k_proj",
"q_proj",
"v_proj",
"o_proj",
],
)
6. Memuat Model dan Persiapan untuk Quantization
model = AutoModelForCausalLM.from_pretrained(
base_model, quantization_config=bnb_config, device_map={"": 0}
)
model = prepare_model_for_kbit_training(model)
Model dasar dimuat dengan konfigurasi quantization, kemudian dipersiapkan untuk pelatihan dengan konversi layer tertentu ke format FP32.
7. Konfigurasi dan Pelatihan
Mengatur argumen pelatihan seperti jumlah epoch, ukuran batch, strategi evaluasi, dan parameter optimisasi. Pelatihan dilakukan dengan menggunakan SFTTrainer
.
training_arguments = SFTConfig(
output_dir="./results",
num_train_epochs=1,
per_device_train_batch_size=1,
per_device_eval_batch_size=1,
gradient_accumulation_steps=4,
evaluation_strategy="steps",
eval_steps=1000,
logging_steps=1,
optim="paged_adamw_8bit",
learning_rate=2e-4,
lr_scheduler_type="linear",
warmup_steps=10,
report_to="wandb",
max_steps=2,
)
# Tetapkan parameter supervised fine-tuning
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
eval_dataset=dataset,
peft_config=peft_config,
dataset_text_field="0",
max_seq_length=512,
tokenizer=tokenizer,
args=training_arguments,
)
# Train model
trainer.train()
8. Menyimpan dan Mengunggah Model
Model yang telah dilatih disimpan dan dimuat kembali dengan konfigurasi quantization yang berbeda (8-bit). Bobot LoRA digabungkan dengan model utama. Model dan tokenizer kemudian diunggah ke hub menggunakan token akses.
Secara keseluruhan, kode ini menunjukkan proses fine-tuning model bahasa besar menggunakan dataset tertentu dengan quantization dan teknik LoRA untuk efisiensi komputasi, serta mengunggah model yang telah dilatih ke Huggingface Model Hub.
# Simpan trained model
trainer.model.save_pretrained(new_model)
# Reload model di FP16 dan gabungkan dengan bobot LoRA
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(
base_model,
low_cpu_mem_usage=True,
return_dict=True,
quantization_config=quantization_config,
torch_dtype=torch.float16,
device_map={"": 0},
)
model = PeftModelForCausalLM.from_pretrained(model, new_model)
model = model.merge_and_unload()
tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
access_token_write = "token_Anda"
model.generation_config.temperature = None
model.generation_config.top_p = None
model.push_to_hub(
new_model, use_temp_dir=False, token=access_token_write, check_pr=True
)
tokenizer.push_to_hub(
new_model, use_temp_dir=False, token=access_token_write, check_pr=True
)
Overall Code
import torch
from datasets import load_dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
AutoTokenizer,
)
from peft import LoraConfig, PeftModelForCausalLM, prepare_model_for_kbit_training
from trl import SFTTrainer, SFTConfig
# Model
base_model = "Ichsan2895/Merak-7B-v2"
new_model = "Merak-7B-squadpairs-indo"
# Dataset
dataset = load_dataset("fatyanosa/squad_pairs_indo_1000", split="train")
# Tokenizer
tokenizer = AutoTokenizer.from_pretrained(base_model, use_fast=True)
tokenizer.pad_token = tokenizer.unk_token
tokenizer.padding_side = "right"
# Quantization configuration
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
# LoRA configuration
peft_config = LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
target_modules=[
"up_proj",
"down_proj",
"gate_proj",
"k_proj",
"q_proj",
"v_proj",
"o_proj",
],
)
model = AutoModelForCausalLM.from_pretrained(
base_model, quantization_config=bnb_config, device_map={"": 0}
)
model = prepare_model_for_kbit_training(model)
training_arguments = SFTConfig(
output_dir="./results",
num_train_epochs=1,
per_device_train_batch_size=1,
per_device_eval_batch_size=1,
gradient_accumulation_steps=4,
evaluation_strategy="steps",
eval_steps=1000,
logging_steps=1,
optim="paged_adamw_8bit",
learning_rate=2e-4,
lr_scheduler_type="linear",
warmup_steps=10,
report_to="wandb",
max_steps=2,
)
# Tetapkan parameter supervised fine-tuning
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
eval_dataset=dataset,
peft_config=peft_config,
dataset_text_field="0",
max_seq_length=512,
tokenizer=tokenizer,
args=training_arguments,
)
# Train model
trainer.train()
# Simpan trained model
trainer.model.save_pretrained(new_model)
# Reload model di FP16 dan gabungkan dengan bobot LoRA
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(
base_model,
low_cpu_mem_usage=True,
return_dict=True,
quantization_config=quantization_config,
torch_dtype=torch.float16,
device_map={"": 0},
)
model = PeftModelForCausalLM.from_pretrained(model, new_model)
model = model.merge_and_unload()
tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
access_token_write = "token_Anda"
model.generation_config.temperature = None
model.generation_config.top_p = None
model.push_to_hub(
new_model, use_temp_dir=False, token=access_token_write, check_pr=True
)
tokenizer.push_to_hub(
new_model, use_temp_dir=False, token=access_token_write, check_pr=True
)
Inference
Setelah model diunggah ke HuggingFace, kita dapat melakukan inferensi (prediksi) menggunakan model tersebut.
1. Import Library
Mengimpor pustaka yang diperlukan:
torch
: Untuk komputasi tensor.peft
: Untuk konfigurasi dan penggunaan LoRA.transformers
: Untuk model transformer dari Huggingface, tokenisasi, dan pipeline inferensi.BitsAndBytesConfig
: Untuk konfigurasi quantization.
import torch
from peft import PeftModelForCausalLM, LoraConfig, get_peft_model, get_peft_config
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
pipeline,
BitsAndBytesConfig,
)
2. Konfigurasi Model dan Adapter
Menentukan model dasar (model_name
) dan adapter yang telah di-fine-tune (adapter
).
model_name = "Ichsan2895/Merak-7B-v2"
adapter = "fatyanosa/Merak-7B-squadpairs-indo"
3. Tokenizer
Menginisialisasi tokenizer dari model dasar yang akan digunakan untuk memproses teks input.
tokenizer = AutoTokenizer.from_pretrained(model_name)
4. Menentukan compute_dtype
Menentukan tipe data untuk komputasi berdasarkan dukungan dari perangkat GPU. Jika GPU mendukung bfloat16
, maka akan digunakan, jika tidak akan menggunakan float16
.
if torch.cuda.is_bf16_supported():
compute_dtype = torch.bfloat16
else:
compute_dtype = torch.float16
5. Konfigurasi LoRA
Mengatur konfigurasi LoRA untuk menyesuaikan bobot model pada layer tertentu tanpa mengubah keseluruhan model.
config = {
"r": 16,
"lora_alpha": 32,
"lora_dropout": 0.05,
"bias": "none",
"task_type": "CAUSAL_LM",
"peft_type": "LORA",
"target_modules": [
"up_proj",
"down_proj",
"gate_proj",
"k_proj",
"q_proj",
"v_proj",
"o_proj",
],
}
peft_config = get_peft_config(config)
6. Konfigurasi Quantization dan Memuat Model
Mengatur quantization untuk menggunakan 8-bit dan memuat model dasar dengan konfigurasi quantization. Kemudian, model diperluas dengan konfigurasi LoRA untuk memungkinkan penyesuaian parameter tertentu.
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=quantization_config,
torch_dtype=compute_dtype,
device_map={"": 0},
)
model = PeftModelForCausalLM(model, peft_config)
model.print_trainable_parameters()
7. Inisialisasi Pipeline
Menginisialisasi pipeline inferensi untuk tugas text-generation
menggunakan model dan tokenizer yang telah disiapkan. device_map="auto"
digunakan untuk memastikan model dijalankan pada perangkat yang sesuai (misalnya, GPU jika tersedia).
pipe = pipeline(
"text-generation",
model=model_name,
torch_dtype=torch.float16,
device_map="auto", # if you have GPU
tokenizer=tokenizer,
max_length=128,
)
8. Inferensi dengan Prompt
- Mendefinisikan prompt untuk inferensi.
- Membuat instruksi yang akan diberikan ke pipeline.
- Menjalankan inferensi dengan pipeline dan mencetak hasilnya.
prompt = "Jelaskan mengenai pembelajaran mesin?"
instruction = f"### Pertanyaan:\n{prompt}\n\n### Jawaban:\n"
result = pipe(instruction)
print(result[0]["generated_text"][len(instruction) :])
Overall Code
import torch
from peft import PeftModelForCausalLM, LoraConfig, get_peft_model, get_peft_config
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
pipeline,
BitsAndBytesConfig,
)
model_name = "Ichsan2895/Merak-7B-v2"
adapter = "fatyanosa/Merak-7B-squadpairs-indo"
tokenizer = AutoTokenizer.from_pretrained(model_name)
if torch.cuda.is_bf16_supported():
compute_dtype = torch.bfloat16
else:
compute_dtype = torch.float16
config = {
"r": 16,
"lora_alpha": 32,
"lora_dropout": 0.05,
"bias": "none",
"task_type": "CAUSAL_LM",
"peft_type": "LORA",
"target_modules": [
"up_proj",
"down_proj",
"gate_proj",
"k_proj",
"q_proj",
"v_proj",
"o_proj",
],
}
peft_config = get_peft_config(config)
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=quantization_config,
torch_dtype=compute_dtype,
device_map={"": 0},
)
model = PeftModelForCausalLM(model, peft_config)
model.print_trainable_parameters()
pipe = pipeline(
"text-generation",
model=model_name,
torch_dtype=torch.float16,
device_map="auto", # if you have GPU
tokenizer=tokenizer,
max_length=128,
)
# Jalankan pipeline text generation
prompt = "Jelaskan mengenai pembelajaran mesin?"
instruction = f"### Pertanyaan:\n{prompt}\n\n### Jawaban:\n"
result = pipe(instruction)
print(result[0]["generated_text"][len(instruction) :])
What next?
Ada beberapa ide yang bisa dipertimbangkan untuk diterapkan dalam proses fine-tuning model:
- Menambah Data Latihan: Gunakan dataset yang lebih besar dan lebih bervariasi untuk melatih model.
- Menyesuaikan Hyperparameter: Lakukan eksperimen dengan berbagai pengaturan hyperparameter seperti laju pembelajaran (learning rate), ukuran batch, dan jumlah epoch.
- Membandingkan hasil dengan Indonesian LLM yang lain.
- Membandingkan hasil dengan LORA dan full fine tuning.
Kode
Semua kode dapat diakses di Github saya berikut ini.
https://github.com/fatyanosa/natural-language-processing.git
Referensi
Fine-Tune Llama2 | Step by Step Guide to Customizing Your Own LLM