Ana içeriğe geç

Qwen3-VL 8B İnce Ayarı: Adım Adım Kılavuz

Qwen3‑VL‑8B’yi LoRA ile elektronik şemalar üzerinde ince ayarlayın. Veriyi hazırlamadan modelinizi Hugging Face Hub’da yayımlamaya kadar tüm hattı öğrenin.
· 10 dk. oku

Yapay Zeka ile Keşfedin

Qwen3‑VL‑8B, Qwen serisindeki en güçlü ve en yaygın kullanılan görsel‑dil modelidir; metin, görsel ve videoyu birlikte anlamlandırmak üzere tasarlanmıştır.

Metin üretimi, görsel akıl yürütme, mekânsal algı, uzun bağlam yönetimi ve ajan etkileşimi alanlarında önemli iyileştirmeler sunar; bu sayede hem uçta hem de bulutta, araştırmadan üretime kadar farklı ortamlara uygundur.

Bu eğitimde ince ayar yaparak Qwen3‑VL‑8B‑Instruct’ı elektronik şema diyagramları üzerinde eğiteceğiz. Modeli şema sembollerini, bağlantıları ve mekânsal ilişkileri yorumlamaya alıştırarak, devre tasarımlarını doğru anlamasını ve gerçek bir devrede hangi elektronik bileşenlerin eklenmesi gerektiğini belirleyebilmesini sağlayacağız.

Şunları öğreneceksiniz:

  1. Veri kümesini Hugging Face’ten yükleyip temizlemek.
  2. Eğitim için çok modlu bir sohbet şablonu oluşturmak.
  3. Qwen3-VL görsel‑dil hattını kurmak.
  4. Bellek verimli eğitim için LoRA’yı yapılandırmak.
  5. Modeli ince ayar ile eğitip kontrol noktasını kaydetmek.
  6. Eğitilen adaptörü Hugging Face’e yayımlamak.
  7. İnce ayar öncesi ve sonrası sonuçları karşılaştırmak.

Hugging Face sizin için hâlâ yeniyse, Hugging Face Fundamentals beceri yolu tam size göre!

1. Qwen3-VL-8B için İnce Ayar Ortamının Kurulumu

görsel–dil modelleri ile çalışırken GPU belleği kritik bir kısıt haline gelir. Yüksek çözünürlüklü görseller ve çok modlu kodlayıcılar VRAM’i hızla tüketebilir; bu nedenle bol belleğe sahip bir GPU kullanmanız şiddetle önerilir.

Bu eğitimde, en güncel PyTorch imajını kullanarak bir RunPod A100 (80GB) örneği başlatacağız. Bu kurulum, eğitim için yeterli VRAM payı sunar ve ince ayar sırasında gereksiz bellek darboğazlarını önler.

Aşağı kaydırıp Pod Template bölümünü bulun. Burada en güncel PyTorch imajını seçin. Depolama ayarlarını düzenleyip ortam değişkenleri ekleyebileceğiniz yer de burasıdır.

Edit the PyTorch RunPod

Edit’e tıklayın ve şu değişiklikleri yapın:

  • Kapsayıcı disk boyutu: 40 GB olarak ayarlayın
  • Hacim disk boyutu: 40 GB olarak ayarlayın
  • Ortam değişkenleri: HF_TOKEN ekleyin ve değerini Hugging Face erişim belirtecinize ayarlayın (bir tane oluşturmak için Hugging Face Ayarları sayfasını kullanın)

Configure the RunPod disk size and environment variables

İşiniz bittiğinde şablonu kaydedin ve pod’u dağıtın.

Pod summary

Pod çalışmaya başladıktan sonra:

  1. JupyterLab’i açın.
  2. Yeni bir Python defteri (notebook) oluşturun.
  3. Gerekli bağımlılıkları kurun.

Bağımlılıkları kurmak için aşağıdaki kod hücresini çalıştırın. Jupyter’da satır başındaki ünlem, komutun Python kodu olarak değil kabuk komutu olarak yürütülmesini sağlar.

!pip -q install -U accelerate datasets pillow sentencepiece safetensors peft
!pip install --quiet "transformers==5.0.0rc1"
!pip install --quiet --no-deps trl
!pip install --no-cache-dir flash-attn --no-build-isolation

Sonraki adımda, tekrarlanabilirlik için sabit bir rastgele tohum ayarlayın ve A100’e özgü performans iyileştirmelerini etkinleştirin.

import torch
from transformers import set_seed

set_seed(42)

# A100: TF32 gives speedups without changing your bf16 training setup
torch.backends.cuda.matmul.allow_tf32 = True
torch.backends.cudnn.allow_tf32 = True

print("CUDA:", torch.cuda.is_available(), torch.cuda.get_device_name(0) if torch.cuda.is_available() else None)
print("bf16 supported:", torch.cuda.is_available() and torch.cuda.is_bf16_supported())
CUDA: True NVIDIA A100 80GB PCIe
bf16 supported: True

2. Hugging Face’ten Open Schematics Veri Kümesini İndirme

Şimdi Hugging Face Hub’dan Open Schematics veri kümesini yükleyeceğiz. Bu veri kümesi, her devreyi tanımlayan zengin üst verilerle birlikte elektronik şema görselleri içerir; bu da onu görsel–dil eğitimi için oldukça uygun kılar.

import torch
from datasets import load_dataset

DATASET_ID = "bshada/open-schematics"

ds_all = load_dataset(DATASET_ID, split="train")
print(ds_all)
Dataset({
    features: ['schematic', 'image', 'components_used', 'json', 'yaml', 'name', 'description', 'type'],
    num_rows: 84470
})

Veri kümesi, her birine bir şema görselinin eşlendiği ve bileşen listeleri ile makinece okunabilir biçimler (JSON ve YAML) gibi yapısal bilgilerin bulunduğu 84 binin üzerinde örnek içeriyor.

3. Veri Kümesi Yapısını Keşfetme

Veri kümesi yapısını daha iyi anlamak için tek bir örneği inceleyelim.

# quick peek
ex = ds_all[0]
print("\nSample keys:", ex.keys())
print("name:", ex.get("name"))
print("type:", ex.get("type"))
print("components_used:", (ex.get("components_used") or [])[:10])
print("has schematic:", bool(ex.get("schematic")))
print("has json/yaml:", bool(ex.get("json")), bool(ex.get("yaml")))
print("image:", ex.get("image"))
Sample keys: dict_keys(['schematic', 'image', 'components_used', 'json', 'yaml', 'name', 'description', 'type'])
name: TiebeDeclercq/Uart-programmer
type: .kicad_sch
components_used: ['Conn_01x01_Pin', 'Conn_01x06_Pin', 'USB_A', 'Conn_02x05_Odd_Even', 'Conn_01x06_MountingPin', 'C', 'Fuse_Small', 'LED', 'R', 'CH340C']
has schematic: True
has json/yaml: True True
image: <PIL.PngImagePlugin.PngImageFile image mode=RGBA size=1123x794 at 0x7FBC6FD060F0>

Bu, her örneğin yüksek çözünürlüklü bir şema görseli, bir bileşen listesi ve devrenin yapısal temsillerini içerdiğini doğrular.

Artık şema görselini doğrudan Jupyter defterinde görüntüleyebiliriz.

ex.get("image")

Electronic Schematic diagram

Son olarak, bu şemada kullanılan bileşenlerin tam listesini inceliyoruz.

print(ex.get("components_used"))
['Conn_01x01_Pin', 'Conn_01x06_Pin', 'USB_A', 'Conn_02x05_Odd_Even', 'Conn_01x06_MountingPin', 'C', 'Fuse_Small', 'LED', 'R', 'CH340C', 'Jumper_3_Open', 'MountingHole', 'AMS1117-3.3', 'MMBT3904', '1N5819HW-7-F', 'LESD5D5.0CT1G', '+3.3V', '+5V', 'GND', 'VCC']

Bu bileşen listesi, şema görseli ile devrede bulunan elektronik unsurlar arasında net bir bağ kurar.

4. Veri Kümesini Temizleme ve Süzme

Eğitimden önce, her örneğin görsel–dil öğrenimi için gerekli asgari bilgileri içerdiğinden emin olmak üzere veri kümesini temizleyip süzüyoruz. Özellikle, geçerli bileşen açıklamalarına ve karşılık gelen bir şema görseline sahip örnekleri korumaya odaklanıyoruz.

Önce, kaç örnekte components_used girişinin eksik, boş ya da geçersiz olduğunu inceliyoruz.

need_cols = [c for c in ["components_used", "schematic", "name", "type"] if c in ds_all.column_names]
ds_small = ds_all.select_columns(need_cols)

missing_key = none_components = empty_components = missing_any = 0
has_schematic_but_missing = 0

for ex in ds_small:
    if "components_used" not in ex:
        missing_key += 1
        missing_any += 1
        if ex.get("schematic"):
            has_schematic_but_missing += 1
        continue

    cu = ex["components_used"]
    bad = (cu is None) or (isinstance(cu, list) and len(cu) == 0)

    if cu is None:
        none_components += 1
    elif isinstance(cu, list) and len(cu) == 0:
        empty_components += 1

    if bad:
        missing_any += 1
        if ex.get("schematic"):
            has_schematic_but_missing += 1

print("\n=== Missing components report ===")
print("Total:", len(ds_all))
print("Missing key:", missing_key)
print("None:", none_components)
print("Empty list:", empty_components)
print("Missing (any):", missing_any)
if "schematic" in need_cols:
    print("Has schematic but missing components:", has_schematic_but_missing)
=== Missing components report ===
Total: 84470
Missing key: 0
None: 47558
Empty list: 8
Missing (any): 47566
Has schematic but missing components: 47566

Aşağıdaki özet, örneklerin önemli bir bölümünün şema verisi içerdiğini ancak kullanılabilir bileşen açıklamalarından yoksun olduğunu gösteriyor.

Süzme sırasında gereksiz bellek kullanımını önlemek için görsel kod çözmeyi özellikle devre dışı bırakıyoruz. Bu, Hugging Face’in filtre uygularken görselleri belleğe yüklememesini sağlar.

from datasets.features import Image as HFImage 
ds_all = ds_all.cast_column("image", HFImage(decode=False))

Ardından, yalnızca boş olmayan bir bileşen listesine ve geçerli bir görsel referansına sahip örnekleri tutan bir filtre tanımlıyoruz.

def keep_components_and_image(components_used, image):
    # keep only rows with components
    if not (isinstance(components_used, list) and len(components_used) > 0):
        return False

    # image must exist
    if image is None:
        return False

    # when decode=False, image is dict-like: {"path": ...} or {"bytes": ...}
    if isinstance(image, dict):
        return bool(image.get("path")) or bool(image.get("bytes"))

    return True

Bu filtrenin uygulanması, veri kümesini yüksek kaliteli ve tamamen kullanılabilir örneklere önemli ölçüde indirger.

ds_clean = ds_all.filter(
    keep_components_and_image,
    input_columns=["components_used", "image"],
)

print("Original:", len(ds_all))
print("Clean:", len(ds_clean))
print("Dropped:", len(ds_all) - len(ds_clean))
Original: 84470
Clean: 33275
Dropped: 51195

Süzme sonrası, hem geçerli şema görsellerini hem de açık bileşen açıklamalarını içeren 33 binin üzerinde temiz örnek kaldı. Bu temizlenmiş veri kümesi, sonraki ön işleme ve model eğitimi adımları için güvenilir bir temel oluşturur.

5. Qwen3-VL-8B Görsel‑Dil Modelini Yükleme

Şimdi Qwen3-VL-8B-Instruct modelini ve karşılık gelen işlemcisini yüklüyoruz. Bu geniş ölçekli görsel–dil modeli, görseller ve metin üzerinde ortak akıl yürütme yapabilir; bu da onu şema anlama görevleri için uygun kılar.

Model, bellek kullanımını azaltırken sayısal kararlılığı korumak için bfloat16 hassasiyetinde yüklenir. A100 GPU’da daha hızlı ve bellek verimli dikkat için Flash Attention 2 de etkinleştirilir. device_map="auto" seçeneği, model katmanlarını kullanılabilir GPU’ya otomatik olarak yerleştirir.

from transformers import Qwen3VLForConditionalGeneration, AutoProcessor

MODEL_ID = "Qwen/Qwen3-VL-8B-Instruct"

model = Qwen3VLForConditionalGeneration.from_pretrained(
    MODEL_ID,
    dtype=torch.bfloat16,
    device_map="auto",
    attn_implementation="flash_attention_2",
)
processor = AutoProcessor.from_pretrained(MODEL_ID)

6. Devre Analizi için İstem Tasarımı

Bu adım, görsel–dil eğitimi için istem, hedef ve görselleri hazırlayan hafif yardımcıları tanımlar. Tek bir hat, TASK değişkeni (components, YAML, JSON veya şema yeniden oluşturma) değiştirilerek birden çok görev için kullanılır.

Eğitimi kararlı ve bellek açısından verimli tutmak için hedef uzunluğu ve görsel boyutu üzerinde temel güvenlik sınırları uygulanır.

from PIL import Image


TASK = "components"  # "components" | "yaml" | "json" | "schematic"
MAX_TARGET_CHARS = 5000  # safety cap for long targets like schematic/json
MAX_IMAGE_SIDE = 1024          # bigger side
MAX_IMAGE_PIXELS = 1024 * 1024 # safety cap (1.0 MP). raise to 1.5MP if stable

İstemi oluşturma

build_prompt() işlevi, modele iletilen yönerge metnini oluşturur. Bağlam için veri kümesi üst verilerini kullanır ve hayal ürünü üretimi azaltmak ile gözetimi görevler arasında tutarlı kılmak için katı çıktı kısıtları uygular.

def build_prompt(example):
    # Use dataset fields to give better context (name/type are helpful)
    name = example.get("name") or "Unknown project"
    ftype = example.get("type") or "unknown format"

    if TASK == "components":
        return (
            f"Project: {name}\nFormat: {ftype}\n"
            "From the schematic image, extract all component labels and identifiers exactly as shown "
            "(part numbers, values, footprints, net labels like +5V/GND).\n"
            "Output only a comma-separated list. Do not generalize or add extra text."
        )

    if TASK == "yaml":
        return (
            f"Project: {name}\nFormat: {ftype}\n"
            "From the schematic image, produce YAML metadata for the design.\n"
            "Return valid YAML only. No markdown, no explanations."
        )

    if TASK == "json":
        return (
            f"Project: {name}\nFormat: {ftype}\n"
            "From the schematic image, produce a JSON representation of the schematic structure.\n"
            "Return valid JSON only. No markdown, no explanations."
        )

    if TASK == "schematic":
        return (
            f"Project: {name}\nFormat: {ftype}\n"
            "From the schematic image, reconstruct the raw KiCad schematic content.\n"
            "Return only the schematic text. No markdown, no explanations."
        )

    raise ValueError("Unknown TASK")

Hedefi oluşturma

build_target() işlevi, seçilen görev için gerçek çıktıyı doğrudan veri kümesinden çıkarır. İçerik, modelin yeniden anlatım değil birebir üretim öğrenmesi için olduğu gibi döndürülür.

def build_target(example):
    if TASK == "components":
        comps = example.get("components_used") or []
        return ", ".join(comps)

    if TASK == "yaml":
        return (example.get("yaml") or "").strip()

    if TASK == "json":
        return (example.get("json") or "").strip()

    if TASK == "schematic":
        return (example.get("schematic") or "").strip()

    raise ValueError("Unknown TASK")

clamp_text() işlevi hedefler için sert bir karakter sınırı uygular. Bu, büyük boyutlu JSON, YAML veya şema dosyalarının eğitim sırasında bellek sorunlarına yol açmasını önler.

def clamp_text(s: str, max_chars: int = MAX_TARGET_CHARS) -> str:
    s = (s or "").strip()
    return s if len(s) <= max_chars else s[:max_chars].rstrip()

Görselleri yeniden boyutlandırma

_resize_pil() işlevi, şema görsellerini işlemden önce normalize eder ve yeniden boyutlandırır. Hem azami kenar uzunluğu hem de azami toplam piksel sayısını zorunlu kılar; bu da görsel ayrıntıyı korurken öngörülebilir GPU bellek kullanımı sağlar.

def _resize_pil(pil: Image.Image, max_side: int = MAX_IMAGE_SIDE, max_pixels: int = MAX_IMAGE_PIXELS) -> Image.Image:
    pil = pil.convert("RGB")
    w, h = pil.size

    # Scale down if max side too large
    scale_side = min(1.0, max_side / float(max(w, h)))

    # Scale down if too many pixels (area cap)
    scale_area = (max_pixels / float(w * h)) ** 0.5 if (w * h) > max_pixels else 1.0

    scale = min(scale_side, scale_area)

    if scale < 1.0:
        nw, nh = max(1, int(w * scale)), max(1, int(h * scale))
        pil = pil.resize((nw, nh), resample=Image.BICUBIC)

    return pil

7. Çok Modlu Sohbet Şablonunun Kurulumu

Bu adımda, her temizlenmiş veri kümesi örneğini Qwen görsel–dil modeli tarafından doğrudan tüketilebilecek çok modlu sohbet tarzı bir biçime dönüştürüyoruz. Bu biçim, şema görselini açıkça bir metin yönergesi ve karşılık gelen hedef çıktı ile hizalar.

def to_messages(example):
    prompt = build_prompt(example)
    target = clamp_text(build_target(example))

    example["messages"] = [
        {
            "role": "user",
            "content": [
                {"type": "image"},
                {"type": "text", "text": prompt},
            ],
        },
        {
            "role": "assistant",
            "content": [{"type": "text", "text": target}],
        },
    ]
    return example

Sıralama yanlılığını kaldırmak için veri kümesini karıştırıyor ve ilk denemeler için küçük bir alt küme seçiyoruz. 

Ardından veri kümesi, çok modlu eğitim örnekleri üretmek üzere to_messages() üzerinden eşlenir. Son olarak, ön işlemenin hafif ve bellek açısından verimli kalması için görseller yalnızca eğitim sırasında yüklenecek şekilde görsel kod çözme yeniden etkinleştirilir.

# Start small (increase later)
train_ds = ds_clean.shuffle(seed=42).select(range(min(800, len(ds_clean)))).map(to_messages)
train_ds = train_ds.cast_column("image", HFImage(decode=True))

8. Qwen3-VL-8B’yi Değerlendirme (İnce Ayar Öncesi)

İnce ayara başlamadan önce, Qwen3‑VL 8B Instruct modelinin görevimizde kutudan çıktığı haliyleki performansını değerlendiriyoruz. Bu temel ölçüt, önceden eğitilmiş modelin herhangi bir göreve özgü uyarlama olmaksızın şema görsellerinden ne kadar bilgi çıkarabildiğini anlamamıza yardımcı olur.

run_inference() işlevi, daha sonra eğitimde de kullanılacak aynı istem ve görsel ön işleme mantığıyla tek bir örnek üzerinde tek geçişlik çıkarım yapar.

import torch

def run_inference(model_, example, max_new_tokens=256):
    prompt = build_prompt(example)

    messages = [
        {
            "role": "user",
            "content": [
                {"type": "image", "image": _resize_pil(example["image"])},
                {"type": "text", "text": prompt},
            ],
        }
    ]

    inputs = processor.apply_chat_template(
        messages,
        tokenize=True,
        add_generation_prompt=True,
        return_dict=True,
        return_tensors="pt",
    ).to(model_.device)

    with torch.inference_mode():
        out = model_.generate(**inputs, max_new_tokens=max_new_tokens, do_sample=False)

    gen = out[0][inputs["input_ids"].shape[1]:]
    return processor.decode(gen, skip_special_tokens=True)

baseline_ex = train_ds.shuffle(seed=120).select(range(1))[0]

Önce eğitim setinden rastgele seçilen bir örnek üzerinde modeli değerlendiriyoruz.

print("\n--- BASELINE OUTPUT ---\n", run_inference(model, baseline_ex))
print("\n--- TARGET (dataset) ---\n", clamp_text(build_target(baseline_ex), 1500))
--- BASELINE OUTPUT ---
 J1,Conn_02x11_Odd_Even,CINT6,CINT5,CINT4,CINT3,CINT2,CINT1,CINT0,CINT15,CINT14,CINT13,CINT12,CINT11,CINT10,CINT9,CINT8,CINT7,CINT16,CINT17,CINT18,CINT19,CINT20,CINT21,CINT22,CINT23,CINT24,CINT25,CINT26,CINT27,CINT28,CINT29,CINT30,CINT31,CINT32,CINT33,CINT34,CINT35,CINT36,CINT37,CINT38,CINT39,CINT40,CINT41,CINT42,CINT43,CINT44,CINT45,CINT46,CINT47,CINT48,CINT49,CINT50,CINT51,CINT52,CINT53,CINT54,CINT55,CINT56,CINT57,CINT58,CINT59,CINT60,CINT61,CINT62

--- TARGET (dataset) ---
 Conn_02x11_Odd_Even, R_Pack04, GND

Bu örnekte model bazı yapısal unsurları doğru saptasa da pin ve sinyal adlarını aşırı üretiyor ve veri kümesinde kullanılan bileşen tanımlayıcılarını tam olarak yakalayamıyor. Değerlendirdiğim daha fazla örnekte de aynı deseni gördüm.

Genel olarak, bu temel sonuçlar modelin güçlü bir genel görsel ve metinsel anlayışa sahip olduğunu; ancak veri kümesine özgü bileşen açıklamalarıyla hizalamanın eksik kaldığını gösteriyor. Bu davranış, hayali çıktıları azaltmak ve kesinliği artırmak için ince ayarın gerekliliğinin altını çiziyor.

9. Eğitim için Görsel‑Dil Veri Birleştirici (Collator) Oluşturma

Bu bölüm, çok modlu sohbet tarzı yığınları hazırlayan özel bir veri birleştiricisini tanımlar. Her örneği, metin ve görselleri birlikte kodlayarak modele hazır tensörlere dönüştürür ve kaybın yalnızca asistanın yanıtı üzerinde hesaplanmasını sağlar.

Birleştirici, giriş kodlaması için sohbet metninin tam bir sürümünü (istem ve hedef) ve istem belirteç uzunluklarını hesaplamak için yalnızca istem içeren bir sürüm oluşturur. Bu uzunluklar kullanılarak, tüm istem ve dolgu belirteçleri etiketlerde maskelenir; böylece yalnızca asistan çıktısı kayba katkı verir. Görseller tutarlı şekilde yeniden boyutlandırılır ve bellek kontrolü için sabit bir azami dizi uzunluğu uygulanır.

from typing import List, Dict, Any
import torch

MAX_LEN = 1500

def collate_fn(batch: List[Dict[str, Any]]):
    # 1) Build full chat text (includes assistant answer)
    full_texts = [
        processor.apply_chat_template(
            ex["messages"],
            tokenize=False,
            add_generation_prompt=False,
        )
        for ex in batch
    ]

    # 2) Build prompt-only text (up to user turn; generation prompt on)
    prompt_texts = [
        processor.apply_chat_template(
            ex["messages"][:-1],
            tokenize=False,
            add_generation_prompt=True,
        )
        for ex in batch
    ]

    # 3) Images
    images = [_resize_pil(ex["image"]) for ex in batch]

    # 4) Tokenize full inputs ONCE (text + images)
    enc = processor(
        text=full_texts,
        images=images,
        return_tensors="pt",
        padding=True,
        truncation=True,
        max_length=MAX_LEN,
    )

    input_ids = enc["input_ids"]
    pad_id = processor.tokenizer.pad_token_id

    # 5) Compute prompt lengths with TEXT-ONLY tokenization (much cheaper than text+images)
    prompt_ids = processor.tokenizer(
        prompt_texts,
        return_tensors="pt",
        padding=True,
        truncation=True,
        max_length=MAX_LEN,
        add_special_tokens=False,  # chat template already includes special tokens
    )["input_ids"]

    # Count non-pad tokens in prompt
    prompt_lens = (prompt_ids != pad_id).sum(dim=1)

    # 6) Labels: copy + mask prompt tokens + mask padding
    labels = input_ids.clone()
    bs, seqlen = labels.shape

    for i in range(bs):
        pl = int(prompt_lens[i].item())
        pl = min(pl, seqlen)
        labels[i, :pl] = -100

    # Mask padding positions too
    labels[labels == pad_id] = -100

    # If your processor produces pixel_values / image_grid_thw, keep them
    enc["labels"] = labels
    return enc

Bu birleştirici, görsel–dil ince ayarı için verimli ve doğru gözetim sağlar.

10. Qwen3-VL-8B’yi Verimli Biçimde İnce Ayar için LoRA’yı Yapılandırma

Şimdi, tüm model ağırlıklarını güncellemeden Qwen3‑VL modelini verimli biçimde ince ayarlamak için LoRA’yı (Low‑Rank Adaptation) yapılandıracağız. LoRA, seçili izdüşüm katmanlarına eğitilebilir düşük dereceli matrisler ekler; böylece performansı korurken bellek kullanımını önemli ölçüde azaltır.

from peft import LoraConfig, TaskType, get_peft_model

lora = LoraConfig(
    r=16,
    lora_alpha=32,
    lora_dropout=0.05,
    bias="none",
    task_type=TaskType.CAUSAL_LM,
    target_modules=[
        "q_proj","k_proj","v_proj","o_proj",
        "gate_proj","up_proj","down_proj"
    ],
)

SFTConfig kullanarak eğitim yapılandırmasını tanımlıyoruz; A100 GPU’da kararlı ince ayar için uygun yığın boyutu, öğrenme oranı, hassasiyet ve günlükleme seçeneklerini ayarlıyoruz.

from trl import SFTTrainer, SFTConfig

args = SFTConfig(
    output_dir=f"qwen3vl-open-schematics-{TASK}-lora",
    num_train_epochs=1,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=4,
    gradient_checkpointing=False,
    learning_rate=1e-4,             
    warmup_steps=10,
    weight_decay=0.01,
    max_grad_norm=1.0,
    bf16=True,
    fp16=False,
    lr_scheduler_type="cosine",
    logging_steps=10,
    report_to="none",
    remove_unused_columns=False,
)

Son olarak, denetimli ince ayara başlamak için modeli, veri kümesini, özel birleştiriciyi ve LoRA yapılandırmasını bir araya getiren SFTTrainer’ı başlatıyoruz.

trainer = SFTTrainer(
    model=model,
    args=args,
    train_dataset=train_ds,
    data_collator=collate_fn,
    peft_config=lora
)

11. Qwen3‑VL-8B’yi Open Schematics Veri Kümesi Üzerinde İnce Ayarla Eğitme

Şimdi yapılandırılmış eğitici ile ince ayar sürecini başlatıyoruz.

trainer.train()

Eğitim başladıktan sonra RunPod telemetri panosunu izleyebilirsiniz. A100 80GB örneğinde süreç tipik olarak 40–45 GB VRAM kullanır ve verimli donanım kullanımını gösteren neredeyse tam GPU kullanımına ulaşır.

Runpod Telemetry during training the model

Eğitim ilerledikçe, eğitim kaybının istikrarlı biçimde azalıp sonra dengelendiğini görmelisiniz. Bizim durumumuzda kayıp yaklaşık 6,5 civarında yakınsayıp plato yaptı; bu da modelin şema bileşeni çıkarımı görevine uyum sağladığına dair temel bir gösterge oldu.

Training loss reduced gradually

Bu noktada LoRA adaptörleri başarıyla ince ayarlanmış, değerlendirme ve dışa aktarıma hazırdır.

12. İnce Ayarlı Modeli Hugging Face Hub’a Yayımlama

İnce ayar tamamlandıktan sonra, önce eğitilen LoRA adaptörlerini ve ilişkili işlemciyi yerel olarak kaydediyoruz.

out_dir = trainer.args.output_dir  # from your SFTConfig/TrainingArguments

trainer.save_model(out_dir)  # saves model/adapters into output_dir
processor.save_pretrained(out_dir)  # save processor (tokenizer + image processor)

Sonraki adımda, ince ayarlı modeli Hugging Face Hub’a yayımlıyoruz. Bu sayede adaptörler ve işlemci, çıkarım veya daha fazla ince ayar için yeniden kullanılabilir.

import os

repo_id = "kingabzpro/qwen3vl-open-schematics-lora" # replace with your username/repo

# Push model/adapters
trainer.model.push_to_hub(
    repo_id,
    token=os.getenv("HF_TOKEN"),
)

# Push processor
processor.push_to_hub(
    repo_id,
    token=os.getenv("HF_TOKEN"),
)

Pushing the model adapter and processor to the Hugging Face Hub

Yükleme tamamlandığında, ince ayarlı LoRA adaptörleri ve işlemci belirtilen depoda herkese açık olarak kullanılabilir.

Pushed the Fine-tuned LoRA to the Hugging Face Hub

12. İnce Ayarlı Qwen3-VL-8B Modelini Değerlendirme

İnce ayardan sonra, modeli ve işlemciyi doğrudan Hugging Face Hub’dan yeniden yüklüyoruz. Bu, değerlendirmenin gerçek çıkarım ortamında kullanılacağı şekliyle, dışa aktarılan LoRA adaptörleriyle yapılmasını sağlar.

model = Qwen3VLForConditionalGeneration.from_pretrained(
    repo_id,
    dtype=torch.bfloat16,
    device_map="auto",
    attn_implementation="flash_attention_2",
)
processor = AutoProcessor.from_pretrained(repo_id)
```
We now repeat the same inference procedure used during the baseline evaluation, allowing for a direct comparison between pre-fine-tuning and post-fine-tuning behavior.
```python
baseline_ex = train_ds.shuffle(seed=120).select(range(1))[0]
print("\n--- FINETUNED OUTPUT ---\n", run_inference(model, baseline_ex))
print("\n--- TARGET (dataset) ---\n", clamp_text(build_target(baseline_ex), 1500))
--- FINETUNED OUTPUT ---
 Conn_02x11_0dd_Even, P3.3V
--- TARGET (dataset) ---
 Conn_02x11_Odd_Even, R_Pack04, GND

Temel duruma kıyasla, ince ayarlı model çok daha kısa ve odaklı bir çıktı üreterek pin adları ve türetilmiş sinyallerin büyük ölçekli aşırı üretiminden kaçınıyor. 

Öngörü hâlâ eksik ve küçük hatalar içeriyor olsa da, veri kümesine uyumlu bileşen tanımlayıcılarına doğru belirgin bir ilerleme gösteriyor.

Bu davranışı doğrulamak için şimdi ikinci bir örneği değerlendireceğiz.

baseline_ex = train_ds.shuffle(seed=170).select(range(1))[0]
print("\n--- FINETUNED OUTPUT ---\n", run_inference(model, baseline_ex))
print("\n--- TARGET (dataset) ---\n", clamp_text(build_target(baseline_ex), 1500))
--- FINETUNED OUTPUT ---
 ATMEGA328P-PU, +5V, GND, R, C, C16MHz, SERVO_A, SERVO_B, SERVO_C, SERVO_D, SERVO_E, SERVO_F, SERVO_G
--- TARGET (dataset) ---
 +5V, 7.62MM-3P, 7.62MM-3P_1, 7.62MM-3P_2, 7.62MM-3P_3, 7.62MM-3P_4, 7.62MM-3P_5, 7.62MM-3P_6, ATMEGA328P-PU, ATMEGA328P-PU_1, GND, MBB02070C1002FCT00, MBB02070C1002FCT00_1, Unknown_0_-806, X49SD16MSD2SC, Y5P102K2KV16CC0224, Y5P102K2KV16CC0224_1, Y5P102K2KV16CC0224_2

Burada, ince ayarlı model mikrodenetleyici ve güç netleri gibi çekirdek bileşenleri doğru tanımlar ve alakasız sinyal düzeyi hayallerini önemli ölçüde azaltır. Ancak, bazı bileşenleri veri kümesine özgü tam tanımlayıcılar yerine hâlâ soyutlayıp genelleyebiliyor.

Genel olarak, bu sonuçlar ince ayarın aşırı üretimi başarıyla bastırdığını ve şema düzeyinde bileşen çıkarımıyla hizalamayı geliştirdiğini gösteriyor. Ek dönemler, daha büyük eğitim setleri veya daha sıkı çıktı kısıtlarıyla kesinlik daha da artırılabilir; ancak ince ayar sonrası davranış, temel duruma kıyasla açık ve ölçülebilir bir iyileşme sunuyor.

Bu eğitimdeki kodu çalıştırırken herhangi bir sorunla karşılaşırsanız, eşlik eden not defterine başvurun.

Son Düşünceler

Görsel–dil modelleri temelde metin‑odaklı modellerden farklıdır ve onları aynı şekilde ele almak çoğu zaman zayıf sonuçlara yol açar. 

Dikkatli olmazsanız, yığın boyutu bir olsa bile bellek yetersizliği hatalarıyla karşılaşmanız veya eğitiliyormuş gibi görünen ama gerçekte görevi öğrenemeyen bir modeli ince ayarla eğitmeniz çok kolaydır. Bunu zor yoldan öğrendim.

Sonuçta fark yaratan, özellikle çok modlu eğitim için önemli olan ayrıntılara dikkat etmek oldu. 

Görselleri güvenli sınırlara yeniden boyutlandırmak, bozuk veya kullanılamaz örnekleri kaldırmak için veri kümesini temizlemek ve modele yalnızca geçerli görsel–metin çiftlerinin aktarılmasını sağlamak, hepsi temel adımlardır. Bunlardan herhangi birini atlamak hızlıca kararsızlığa veya boşa harcanan hesaba yol açar.

Modelleme tarafında, yalnızca ilgili LoRA hedef katmanlarını kullanmak eğitimi verimli ve odaklı tutmaya yardımcı oldu; eğitim argümanlarının dikkatli ayarlanması ise bellek baskısını artırmadan yakınsamayı iyileştirdi. 

A100 GPU için optimize etmek, Flash Attention’ı etkinleştirmek ve bfloat16 kullanmak, eğitimin istikrarlı kalmasını sağlarken çalışma süresini de belirgin ölçüde azalttı. Uygulamada, bu iyileştirmeler eğitim süresini kaliteyi feda etmeden neredeyse yarıya indirdi.

Sonuçlar, güçlü bir ön eğitimli görsel–dil modelinin bile alan‑özel ince ayardan büyük fayda sağladığını gösteriyor. Doğru ön işleme, yapılandırma ve donanım farkındalığı olan iyileştirmelerle, büyük çok modlu modelleri güvenilir ve verimli biçimde uyarlamak mümkün.

İnce ayarı daha fazla pratik etmekle ilgileniyorsanız, Fine-Tuning with Llama 3 kursunu öneririm.

Abid Ali Awan

Yazar

Abid Ali Awan

Sertifikalı bir veri bilimcisi olarak, yenilikçi makine öğrenimi uygulamaları oluşturmak için en son teknolojileri kullanmaya büyük ilgi duyuyorum. Konuşma tanıma, veri analizi ve raporlama, MLOps, konuşma yapay zekası ve NLP alanlarında güçlü bir geçmişe sahip olarak, gerçek bir etki yaratabilecek akıllı sistemler geliştirme becerilerimi geliştirdim. Teknik uzmanlığımın yanı sıra, karmaşık kavramları açık ve özlü bir dille ifade etme yeteneğine sahip, becerikli bir iletişimciyim. Sonuç olarak, veri bilimi konusunda aranan bir blog yazarı oldum ve giderek büyüyen veri profesyonelleri topluluğuyla görüşlerimi ve deneyimlerimi paylaşıyorum. Şu anda, içerik oluşturma ve düzenlemeye odaklanıyorum. Büyük dil modelleriyle çalışarak, hem işletmelerin hem de bireylerin verilerinden en iyi şekilde yararlanmalarına yardımcı olabilecek güçlü ve ilgi çekici içerikler geliştiriyorum.

Konular

İlgili