Tutorial Distilabel: Framework Generasi Data Sintetis untuk Fine-Tuning LLM

# Tutorial Distilabel: Framework Generasi Data Sintetis untuk Fine-Tuning LLM Dalam dunia pengembangan Large Language Model (LLM), kualitas data pelatihan merupakan faktor penentu keberhasilan model....

By Ruby Abdullah · · tutorial
DistilabelSynthetic DataLLMFine-TuningArgilla

Tutorial Distilabel: Framework Generasi Data Sintetis untuk Fine-Tuning LLM

Dalam dunia pengembangan Large Language Model (LLM), kualitas data pelatihan merupakan faktor penentu keberhasilan model. Distilabel hadir sebagai framework open-source dari Argilla yang memungkinkan Anda membangun pipeline untuk menghasilkan data sintetis berkualitas tinggi, melakukan evaluasi model, dan menyiapkan dataset untuk fine-tuning. Tutorial ini akan membahas secara mendalam cara menggunakan Distilabel mulai dari instalasi hingga pembuatan pipeline produksi yang kompleks.

Apa Itu Distilabel?

Distilabel adalah framework Python yang dikembangkan oleh tim Argilla untuk membuat pipeline generasi data sintetis dan evaluasi LLM. Framework ini dirancang untuk mengatasi tantangan utama dalam pengembangan AI: mendapatkan data pelatihan berkualitas tinggi dalam jumlah besar tanpa biaya anotasi manual yang mahal.

Fitur utama Distilabel meliputi:

  • Pipeline berbasis DAG: Arsitektur Directed Acyclic Graph yang memungkinkan pemrosesan data secara paralel dan efisien
  • Multi-provider LLM: Dukungan untuk OpenAI, Anthropic, Google, Hugging Face, vLLM, Ollama, dan banyak lagi
  • Teknik generasi canggih: Implementasi built-in untuk Self-Instruct, Evol-Instruct, UltraFeedback, Magpie, dan teknik lainnya
  • Skalabilitas: Kemampuan menjalankan pipeline di kluster Ray untuk pemrosesan data skala besar
  • Integrasi Argilla dan Hugging Face Hub: Ekspor data langsung ke Argilla untuk validasi manusia atau ke Hugging Face Hub

Instalasi

Prasyarat

Pastikan Anda memiliki Python 3.9 atau lebih baru terinstal di sistem Anda.

Instalasi Dasar

pip install distilabel

Instalasi dengan Provider Tertentu

Distilabel menggunakan sistem extras untuk menginstal dependensi provider LLM:

# Untuk menggunakan OpenAI

pip install "distilabel[openai]"

Untuk menggunakan Anthropic

pip install "distilabel[anthropic]"

Untuk menggunakan vLLM (lokal)

pip install "distilabel[vllm]"

Untuk menggunakan Hugging Face Inference Endpoints

pip install "distilabel[hf-inference-endpoints]"

Untuk menggunakan Ollama

pip install "distilabel[ollama]"

Instalasi lengkap semua provider

pip install "distilabel[openai,anthropic,vllm,ollama]"

Instalasi dengan Ray untuk Skalabilitas

pip install "distilabel[ray,openai]"

Verifikasi Instalasi

import distilabel

print(distilabel.version)

Konfigurasi API Key

Sebelum menggunakan provider LLM berbasis cloud, konfigurasikan API key:

export OPENAIAPIKEY="sk-your-api-key"

export ANTHROPICAPIKEY="your-anthropic-key"

export HFTOKEN="hfyour-token"

Penggunaan Dasar

Konsep Utama

Distilabel dibangun di atas tiga konsep utama:

  • Step: Unit pemrosesan terkecil dalam pipeline (GeneratorStep, Step, GlobalStep)
  • Task: Jenis khusus dari Step yang berinteraksi dengan LLM
  • Pipeline: Orkestrator yang menghubungkan Step-step dalam urutan DAG
  • Menjalankan LLM Sederhana

    from distilabel.llms import OpenAILLM
    
    

    llm = OpenAILLM(model="gpt-4o-mini")

    llm.load()

    result = llm.generateoutputs(

    inputs=[

    [

    {"role": "user", "content": "Jelaskan apa itu machine learning dalam 2 kalimat."}

    ]

    ]

    )

    print(result[0][0])

    Pipeline Pertama: Generasi Teks Sederhana

    from distilabel.llms import OpenAILLM
    

    from distilabel.pipeline import Pipeline

    from distilabel.steps.tasks import TextGeneration

    from distilabel.steps import LoadDataFromDicts

    data = [

    {"instruction": "Jelaskan konsep neural network untuk pemula."},

    {"instruction": "Apa perbedaan antara supervised dan unsupervised learning?"},

    {"instruction": "Bagaimana cara kerja gradient descent?"},

    ]

    with Pipeline(name="tutorial-dasar") as pipeline:

    loaddata = LoadDataFromDicts(data=data)

    textgen = TextGeneration(

    llm=OpenAILLM(model="gpt-4o-mini"),

    numgenerations=1,

    )

    loaddata >> textgen

    distiset = pipeline.run()

    df = distiset["default"]["train"].topandas()

    print(df[["instruction", "generation"]].tostring())

    Menggunakan Multiple LLM

    Salah satu kekuatan Distilabel adalah kemampuan menggunakan beberapa LLM dalam satu pipeline:

    from distilabel.llms import OpenAILLM, AnthropicLLM
    

    from distilabel.pipeline import Pipeline

    from distilabel.steps.tasks import TextGeneration

    from distilabel.steps import LoadDataFromDicts, CombineOutputs

    data = [

    {"instruction": "Apa itu transfer learning?"},

    {"instruction": "Jelaskan konsep attention mechanism."},

    ]

    with Pipeline(name="multi-llm") as pipeline:

    loaddata = LoadDataFromDicts(data=data)

    genopenai = TextGeneration(

    name="genopenai",

    llm=OpenAILLM(model="gpt-4o-mini"),

    numgenerations=1,

    outputmappings={"generation": "generationopenai"},

    )

    genanthropic = TextGeneration(

    name="genanthropic",

    llm=AnthropicLLM(model="claude-sonnet-4-6"),

    numgenerations=1,

    outputmappings={"generation": "generationanthropic"},

    )

    combine = CombineOutputs()

    loaddata >> [genopenai, genanthropic] >> combine

    distiset = pipeline.run()

    Penggunaan Lanjutan

    Self-Instruct: Generasi Dataset Instruksi

    Self-Instruct adalah teknik yang memungkinkan LLM menghasilkan instruksi pelatihan baru berdasarkan seed instructions. Ini sangat berguna untuk memperluas dataset fine-tuning:

    from distilabel.llms import OpenAILLM
    

    from distilabel.pipeline import Pipeline

    from distilabel.steps.tasks import SelfInstruct

    from distilabel.steps import LoadDataFromDicts

    seeddata = [

    {

    "input": "Kamu adalah asisten AI yang ahli dalam data science dan machine learning. "

    "Tugasmu adalah membantu pengguna memahami konsep-konsep teknis dengan cara yang mudah dipahami."

    }

    ]

    with Pipeline(name="self-instruct-pipeline") as pipeline:

    loaddata = LoadDataFromDicts(data=seeddata)

    selfinstruct = SelfInstruct(

    llm=OpenAILLM(model="gpt-4o-mini"),

    numinstructions=5,

    criteriaforquerygeneration=(

    "Instruksi harus berkaitan dengan data science, machine learning, atau AI. "

    "Instruksi harus bervariasi dalam tingkat kesulitan. "

    "Instruksi harus praktis dan bisa dijawab secara konkret."

    ),

    )

    loaddata >> selfinstruct

    distiset = pipeline.run()

    df = distiset["default"]["train"].topandas()

    for idx, row in df.iterrows():

    print(f"\nInstruksi yang dihasilkan:")

    for instruction in row["instructions"]:

    print(f" - {instruction}")

    Evol-Instruct: Evolusi Instruksi

    Evol-Instruct adalah teknik dari paper WizardLM yang mengembangkan instruksi sederhana menjadi lebih kompleks dan menantang:

    from distilabel.llms import OpenAILLM
    

    from distilabel.pipeline import Pipeline

    from distilabel.steps.tasks import EvolInstruct

    from distilabel.steps import LoadDataFromDicts

    data = [

    {"instruction": "Hitung rata-rata dari sebuah list."},

    {"instruction": "Buat fungsi untuk sorting."},

    {"instruction": "Jelaskan apa itu API."},

    ]

    with Pipeline(name="evol-instruct-pipeline") as pipeline:

    loaddata = LoadDataFromDicts(data=data)

    evolinstruct = EvolInstruct(

    llm=OpenAILLM(model="gpt-4o-mini"),

    numevolutions=3,

    storeevolutions=True,

    includeoriginalinstruction=True,

    )

    loaddata >> evolinstruct

    distiset = pipeline.run()

    df = distiset["default"]["train"].topandas()

    for idx, row in df.iterrows():

    print(f"\nOriginal: {row['instruction']}")

    print(f"Evolved: {row['evolvedinstruction']}")

    UltraFeedback: Evaluasi dan Scoring Respons

    UltraFeedback memungkinkan Anda mengevaluasi kualitas respons dari berbagai model, yang berguna untuk membuat dataset preference untuk RLHF/DPO:

    from distilabel.llms import OpenAILLM
    

    from distilabel.pipeline import Pipeline

    from distilabel.steps.tasks import TextGeneration, UltraFeedback

    from distilabel.steps import LoadDataFromDicts, CombineOutputs, FormatTextGenerationDPO

    data = [

    {"instruction": "Jelaskan perbedaan antara list dan tuple di Python."},

    {"instruction": "Bagaimana cara mengoptimasi query SQL yang lambat?"},

    ]

    with Pipeline(name="ultrafeedback-pipeline") as pipeline:

    loaddata = LoadDataFromDicts(data=data)

    gen1 = TextGeneration(

    name="genmodela",

    llm=OpenAILLM(model="gpt-4o-mini"),

    outputmappings={"generation": "generationa"},

    )

    gen2 = TextGeneration(

    name="genmodelb",

    llm=OpenAILLM(model="gpt-4o"),

    outputmappings={"generation": "generationb"},

    )

    combine = CombineOutputs()

    feedback = UltraFeedback(

    llm=OpenAILLM(model="gpt-4o"),

    aspect="overall-quality",

    )

    formatdpo = FormatTextGenerationDPO()

    loaddata >> [gen1, gen2] >> combine >> feedback >> formatdpo

    distiset = pipeline.run()

    Magpie: Generasi Data Percakapan dari Pre-trained LLM

    Magpie adalah teknik yang mengekstrak kemampuan instruction-following dari LLM yang sudah di-align untuk menghasilkan pasangan instruksi-respons berkualitas:

    from distilabel.llms import OpenAILLM
    

    from distilabel.pipeline import Pipeline

    from distilabel.steps.tasks import Magpie

    with Pipeline(name="magpie-pipeline") as pipeline:

    magpie = Magpie(

    llm=OpenAILLM(model="gpt-4o-mini"),

    nturns=1,

    numrows=20,

    systemprompt=(

    "Kamu adalah asisten AI yang ahli dalam pemrograman Python. "

    "Berikan jawaban yang detail dengan contoh kode."

    ),

    )

    distiset = pipeline.run()

    df = distiset["default"]["train"].topandas()

    for idx, row in df.iterrows():

    print(f"\n{'='*60}")

    print(f"Instruksi: {row['instruction'][:100]}...")

    print(f"Respons: {row['generation'][:100]}...")

    Membuat Custom Task

    Anda dapat membuat task kustom untuk kebutuhan spesifik:

    from typing import Any
    

    from distilabel.steps.tasks import Task

    from distilabel.steps.tasks.typing import ChatType

    class CodeReviewTask(Task):

    systemprompt: str = (

    "Kamu adalah senior code reviewer yang berpengalaman. "

    "Review kode berikut dan berikan feedback konstruktif."

    )

    @property

    def inputs(self) -> list[str]:

    return ["code"]

    @property

    def outputs(self) -> list[str]:

    return ["review", "score", "suggestions"]

    def formatinput(self, input: dict[str, Any]) -> ChatType:

    return [

    {"role": "system", "content": self.systemprompt},

    {

    "role": "user",

    "content": (

    f"Review kode berikut:\n\n

    python\n{input['code']}\n``\n\n"

    "Berikan output dalam format:\n"

    "REVIEW: [review detail]\n"

    "SCORE: [1-10]\n"

    "SUGGESTIONS: [saran perbaikan]"

    ),

    },

    ]

    def formatoutput(

    self, output: str | None, input: dict[str, Any] | None = None

    ) -> dict[str, Any]:

    if output is None:

    return {"review": None, "score": None, "suggestions": None}

    parts = output.split("\n")

    review = ""

    score = ""

    suggestions = ""

    for part in parts:

    if part.startswith("REVIEW:"):

    review = part.replace("REVIEW:", "").strip()

    elif part.startswith("SCORE:"):

    score = part.replace("SCORE:", "").strip()

    elif part.startswith("SUGGESTIONS:"):

    suggestions = part.replace("SUGGESTIONS:", "").strip()

    return {"review": review, "score": score, "suggestions": suggestions}

    
    

    Structured Generation dengan JSON Schema

    Distilabel mendukung generasi terstruktur menggunakan JSON schema:

    python

    from distilabel.llms import OpenAILLM

    from distilabel.pipeline import Pipeline

    from distilabel.steps.tasks import TextGeneration

    from distilabel.steps import LoadDataFromDicts

    structuredllm = OpenAILLM(

    model="gpt-4o-mini",

    structuredoutput={

    "format": "json",

    "schema": {

    "type": "object",

    "properties": {

    "topic": {"type": "string", "description": "Topik utama"},

    "difficulty": {

    "type": "string",

    "enum": ["beginner", "intermediate", "advanced"],

    },

    "keyconcepts": {

    "type": "array",

    "items": {"type": "string"},

    "description": "Konsep-konsep kunci",

    },

    "explanation": {

    "type": "string",

    "description": "Penjelasan detail",

    },

    },

    "required": ["topic", "difficulty", "keyconcepts", "explanation"],

    },

    },

    )

    data = [

    {"instruction": "Jelaskan tentang Retrieval-Augmented Generation (RAG)."},

    {"instruction": "Apa itu Model Quantization dalam konteks LLM?"},

    ]

    with Pipeline(name="structured-output") as pipeline:

    loaddata = LoadDataFromDicts(data=data)

    textgen = TextGeneration(

    llm=structuredllm,

    numgenerations=1,

    )

    loaddata >> textgen

    distiset = pipeline.run()

    
    

    Pipeline dengan Caching dan Checkpoint

    Distilabel secara otomatis menyimpan cache untuk menghindari pemrosesan ulang:

    python

    from distilabel.pipeline import Pipeline

    from distilabel.steps.tasks import TextGeneration

    from distilabel.steps import LoadDataFromDicts

    from distilabel.llms import OpenAILLM

    with Pipeline(

    name="cached-pipeline",

    cachedir="./pipelinecache",

    ) as pipeline:

    loaddata = LoadDataFromDicts(

    data=[{"instruction": f"Buat fakta menarik tentang angka {i}"} for i in range(100)]

    )

    textgen = TextGeneration(

    llm=OpenAILLM(model="gpt-4o-mini"),

    numgenerations=1,

    inputbatchsize=10,

    )

    loaddata >> textgen

    distiset = pipeline.run()

    print(f"Total data: {len(distiset['default']['train'])}")

    
    

    Ekspor ke Hugging Face Hub dan Argilla

    python

    distiset = pipeline.run()

    Push ke Hugging Face Hub

    distiset.pushtohub(

    repoid="username/my-synthetic-dataset",

    private=True,

    token="hfyourtoken",

    )

    Atau push ke Argilla untuk validasi manusia

    import argilla as rg

    client = rg.Argilla(apiurl="http://localhost:6900", apikey="your-key")

    dataset = rg.Dataset(

    name="synthetic-review",

    workspace="default",

    settings=rg.Settings(

    fields=[

    rg.TextField(name="instruction"),

    rg.TextField(name="generation"),

    ],

    questions=[

    rg.RatingQuestion(name="quality", values=[1, 2, 3, 4, 5]),

    rg.TextQuestion(name="feedback"),

    ],

    ),

    )

    dataset.create()

    records = [

    rg.Record(

    fields={

    "instruction": row["instruction"],

    "generation": row["generation"],

    }

    )

    for , row in df.iterrows()

    ]

    dataset.records.log(records)

    
    

    Best Practices

    1. Desain Pipeline yang Modular

    Pisahkan setiap tahap pemrosesan ke dalam step yang berbeda. Ini memudahkan debugging, reuse, dan testing:

    python

    with Pipeline(name="modular-pipeline") as pipeline:

    loaddata = LoadDataFromDicts(data=data)

    generate = TextGeneration(llm=llm, name="generate")

    evaluate = UltraFeedback(llm=judgellm, name="evaluate")

    formatoutput = FormatTextGenerationDPO(name="format")

    loaddata >> generate >> evaluate >> formatoutput

    
    

    2. Gunakan Batch Size yang Tepat

    Sesuaikan inputbatchsize dengan kapasitas API dan kebutuhan memori:

    python

    textgen = TextGeneration(

    llm=OpenAILLM(model="gpt-4o-mini"),

    inputbatchsize=50,

    )

    
    

    Untuk dataset besar, gunakan batch size yang lebih kecil untuk menghindari rate limiting. Untuk dataset kecil, batch size yang lebih besar meningkatkan throughput.

    3. Implementasikan Error Handling

    Gunakan parameter retries dan tangani kegagalan dengan baik:

    python

    llm = OpenAILLM(

    model="gpt-4o-mini",

    maxretries=3,

    timeout=120,

    )

    
    

    4. Validasi Kualitas Data

    Selalu validasi output sebelum menggunakan untuk fine-tuning:

    python

    import json

    df = distiset["default"]["train"].topandas()

    Filter respons kosong

    dfclean = df[df["generation"].notna() & (df["generation"] != "")]

    Filter berdasarkan panjang minimum

    dfclean = dfclean[dfclean["generation"].str.len() > 50]

    Simpan dataset yang sudah dibersihkan

    print(f"Data valid: {len(dfclean)} dari {len(df)} total")

    
    

    5. Gunakan System Prompt yang Spesifik

    System prompt yang detail menghasilkan data yang lebih konsisten dan berkualitas:

    python

    textgen = TextGeneration(

    llm=llm,

    systemprompt=(

    "Kamu adalah instruktur machine learning berpengalaman dengan keahlian "

    "dalam Python, TensorFlow, dan PyTorch. Jawab pertanyaan dengan detail, "

    "sertakan contoh kode yang bisa langsung dijalankan, dan jelaskan setiap "

    "langkah dengan bahasa yang mudah dipahami oleh pemula."

    ),

    )

    
    

    6. Diversifikasi Sumber Data

    Gabungkan beberapa teknik untuk dataset yang lebih kaya:

    python

    with Pipeline(name="diverse-pipeline") as pipeline:

    loadseeds = LoadDataFromDicts(data=seeddata)

    selfinstruct = SelfInstruct(

    name="expand",

    llm=llm,

    numinstructions=10,

    )

    evolinstruct = EvolInstruct(

    name="evolve",

    llm=llm,

    numevolutions=2,

    )

    generate = TextGeneration(

    name="answer",

    llm=llm,

    )

    loadseeds >> selfinstruct >> evolinstruct >> generate

    
    

    7. Monitor Penggunaan Token

    Pantau konsumsi token untuk mengontrol biaya:

    python

    distiset = pipeline.run()

    Periksa statistik pipeline

    print(f"Pipeline selesai")

    print(f"Total baris diproses: {len(distiset['default']['train'])}")

    
    

    8. Gunakan LLM Lokal untuk Iterasi Cepat

    Saat mengembangkan pipeline, gunakan model lokal via Ollama untuk menghemat biaya:

    python

    from distilabel.llms import OllamaLLM

    devllm = OllamaLLM(model="llama3.2")

    prodllm = OpenAILLM(model="gpt-4o")

    llm = devllm # Ganti ke prodllm saat siap produksi

    ``

    Kesimpulan

    Distilabel adalah framework yang sangat powerful untuk membangun pipeline generasi data sintetis dan evaluasi LLM. Dengan arsitektur berbasis pipeline yang fleksibel, dukungan multi-provider, dan implementasi teknik-teknik canggih seperti Self-Instruct, Evol-Instruct, dan UltraFeedback, Distilabel mempermudah proses pembuatan dataset berkualitas tinggi untuk fine-tuning model.

    Poin-poin penting yang perlu diingat:

    • Mulai dari yang sederhana: Buat pipeline dasar terlebih dahulu, lalu tambahkan kompleksitas secara bertahap
    • Validasi selalu: Jangan pernah menggunakan data sintetis tanpa validasi kualitas
    • Iterasi dengan model lokal: Gunakan Ollama atau vLLM untuk pengembangan, lalu beralih ke API produksi
    • Manfaatkan integrasi: Gunakan Argilla untuk human-in-the-loop validation dan Hugging Face Hub untuk berbagi dataset
    • Perhatikan biaya: Monitor penggunaan token dan gunakan caching untuk menghindari pemrosesan ulang

    Dengan menggabungkan Distilabel ke dalam workflow pengembangan AI Anda, Anda dapat secara signifikan mengurangi biaya dan waktu yang dibutuhkan untuk menyiapkan data pelatihan berkualitas tinggi, sambil tetap mempertahankan kontrol penuh atas proses generasi data.

    Artikel Terkait

    Tutorial LitGPT: Framework untuk Melatih dan Fine-Tuning Large Language Models

    Tutorial LitGPT: Framework untuk Melatih dan Fine-Tuning Large Language Models LitGPT adalah framework open-source dari ...

    Fireworks AI: Platform Inference Super Cepat buat Open LLM dan Model Multimodal

    Fireworks AI: Platform Inference Super Cepat buat Open LLM dan Model Multimodal Halo temen-temen, di tutorial kali ini a...

    Together AI: Panduan Lengkap Inference dan Fine-Tuning Model Open Source dengan Satu API

    Together AI: Panduan Lengkap Inference dan Fine-Tuning Model Open Source dengan Satu API Halo temen-temen! Kali ini aku ...

    Tutorial TRL: Post-Training LLM dengan SFT, DPO, dan Reward Modeling

    Post-Training LLM dengan TRL: SFT, Reward Modeling, dan DPO Setelah sebuah base language model selesai dipretraining, mo...