Transformers documentation

Örnek segmentasyonu

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Örnek segmentasyonu

Nesne segmentasyonu, bir görüntüdeki nesneleri algılayıp her birini piksel düzeyinde segmente etme görevidir. Nesne algılama (bounding box çıktısı üreten) görevinden farklı olarak, nesne segmentasyonu algılanan her nesne için hassas bir maske üretir; bu sayede üst üste binen durumlarda bile bireysel örnekleri ayırt edebilirsiniz.

Bu kılavuzda şunları öğreneceksiniz:

  1. Hugging Face Hub'dan bir örnek segmentasyon veri seti yükleyin.
  2. Transformers Trainer kullanarak, transformer tabanlı bir örnek segmentasyon modeli olan RF-DETR-Seg'i ince ayarlayın.
  3. Modelinizi ortalama IoU ile değerlendirin.
  4. Çıkarım çalıştırın ve tahminleri görselleştirin.

satellite-building-segmentation veri setini kullanacağız; bu veri seti, bina örnek maskeleriyle etiketlenmiş yaklaşık 9,6k uydu görüntüsü içerir.

Bu görevle uyumlu tüm mimarileri ve denetim noktalarını görmek için görev sayfasını kontrol etmenizi öneririz.

Başlamadan önce, gerekli tüm kütüphaneleri yükleyin:

pip install -Uq "transformers>=5.9" datasets torchvision

Modelinizi toplulukla paylaşmanızı öneririz. Eğitim tamamlandığında Hub'a yüklemek için Hugging Face hesabınıza giriş yapın:

>>> from huggingface_hub import notebook_login

>>> notebook_login()

Veri setini yükleyin

satellite-building-segmentation veri seti yerel Hugging Face Datasets biçimindedir, bu nedenle doğrudan load_dataset ile yükleyebilirsiniz. Her satır şunları içerir:

  • image: uydu görüntüsü (PIL)
  • image_id: görüntünün benzersiz tanımlayıcısı
  • width / height: görüntü boyutları
  • objects: id, category, bbox, area, segmentation (poligon koordinatları) ve iscrowd alanlarına sahip, örnek başına açıklamalar içeren bir sözlük
>>> from datasets import load_dataset

>>> MODEL_ID = "Roboflow/rf-detr-seg-medium"
>>> DATASET_ID = "merve/satellite-building-segmentation"

>>> ds = load_dataset(DATASET_ID)
>>> train_ds = ds["train"]
>>> valid_ds = ds["validation"]
>>> print(f"Train: {len(train_ds)} images, Valid: {len(valid_ds)} images")
Train: 6764 images, Valid: 1934 images

Tek bir örneği inceleyin. Her kayıt bir image, bir image_id ve örnek başına açıklamaları içeren bir objects sözlüğü içerir. Her örneğin [x, y, width, height] biçiminde bir bbox ve çokgen koordinatlarını içeren bir segmentation alanı vardır:

>>> sample = train_ds[0]
>>> print(f"Image ID: {sample['image_id']}")
Image ID: 0
>>> print(f"Image size: {sample['image'].size}")
Image size: (512, 512)
>>> print(f"Number of instances: {len(sample['objects']['id'])}")
Number of instances: 7
>>> print(f"\nObjects keys: {list(sample['objects'].keys())}")
<BLANKLINE>
Objects keys: ['id', 'area', 'bbox', 'segmentation', 'category', 'iscrowd']
>>> print(f"First bbox: {sample['objects']['bbox'][0]}")
First bbox: [80.0, 0.0, 51.0, 51.5]
>>> print(f"First category: {sample['objects']['category'][0]}")
First category: 0

Gerçek değerli maskeleriyle bir örneği görselleştirin:

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from PIL import Image, ImageDraw

>>> sample = train_ds[0]
>>> image = sample["image"].convert("RGB")

>>> fig, axes = plt.subplots(1, 2, figsize=(14, 6))
>>> _ = axes[0].imshow(image)
>>> _ = axes[0].set_title("Original image")
>>> _ = axes[0].axis("off")

>>> overlay = image.copy()
>>> draw = ImageDraw.Draw(overlay, "RGBA")
>>> objects = sample["objects"]
>>> for seg in objects["segmentation"]:
...     for poly in seg:
...         coords = list(zip(poly[0::2], poly[1::2]))
...         color = tuple(np.random.randint(50, 255, 3)) + (100,)
...         draw.polygon(coords, fill=color, outline="red")

>>> _ = axes[1].imshow(overlay)
>>> _ = axes[1].set_title(f"Ground truth ({len(objects['id'])} buildings)")
>>> _ = axes[1].axis("off")
>>> plt.tight_layout()
>>> plt.show()

Dataset Sample

Modeli ve görüntü işleyicisini yükleyin

RF-DETR-Seg modelini yüklemek için AutoImageProcessor ve AutoModelForInstanceSegmentation kullanın. Modeli yüklerken, tek “building” sınıfı için sınıflandırma başlığını yapılandırmak üzere id2label ve label2id eşlemelerini iletin. Ön eğitilmiş model COCO (91 sınıf) üzerinde eğitildiğinden, sınıflandırma başlığını doğru çıktı sayısı ile yeniden başlatmak için ignore_mismatched_sizes=True değerini ayarlayın.

Görüntü işleyici tüm ön işlemleri yönetir: en-boy oranını koruyarak görüntüleri yeniden boyutlandırma, ImageNet istatistikleriyle normalizasyon, boyutları eşitleme ve — nesne segmentasyonu için kritik olan — poligon etiketlerini ikili maskelere dönüştürme, bu maskeleri yeniden boyutlandırma ve modelin beklediği [0, 1] aralığında [cx, cy, w, h] biçiminde sınırlayıcı kutuları normalizasyon.

>>> from transformers import AutoImageProcessor, AutoModelForInstanceSegmentation

>>> id2label = {0: "building"}
>>> label2id = {"building": 0}

>>> image_processor = AutoImageProcessor.from_pretrained(MODEL_ID)
>>> model = AutoModelForInstanceSegmentation.from_pretrained(
...     MODEL_ID,
...     id2label=id2label,
...     label2id=label2id,
...     ignore_mismatched_sizes=True,
... )

Verileri ön işleme

Modeli ince ayar yapmak için, verileri modelin beklediği formata uygun hale getirecek şekilde ön işlemek zorundasınız. RfDetrImageProcessor, ona return_segmentation_masks=True ile birlikte görüntüler ve COCO formatında etiketler geçildiğinde tüm ağır işi yapar:

  1. Poligon segmentasyonlarını ikili maskelere rasterize eder
  2. Görselleri, sınırlayıcı kutuları ve maskeleri modelin giriş boyutuna yeniden boyutlandırır
  3. Piksel değerlerini ImageNet ortalama/standart sapması ile normalize eder
  4. Sınır kutularını [x, y, w, h] biçiminden normalize edilmiş [cx, cy, w, h] biçimine dönüştürür
  5. Görselleri bir boyuta getirir ve pixel_mask oluşturur

Transform, veri setinin objects sütunundan görüntü işleyicisinin beklediği COCO tarzı anotasyon sözlüklerini yeniden oluşturur.

Ön işlemin örnekler yüklendiğinde anlık olarak uygulanmasını sağlayarak, işlenmiş veri setinin tamamını bellekte tutmaktan kaçınmak için with_transform kullanın.

>>> from functools import partial
>>> from typing import Any


>>> def transform_batch(examples: dict[str, Any], image_processor) -> dict[str, Any]:
...     """Convert HF dataset rows into COCO-style dicts and pass to the processor."""
...     images, targets = [], []
...     for image, img_id, objects in zip(
...         examples["image"], examples["image_id"], examples["objects"]
...     ):
...         if not objects["id"]:
...             continue
...         annotations = [
...             {
...                 "id": ann_id,
...                 "image_id": img_id,
...                 "category_id": cat,
...                 "bbox": bbox,
...                 "area": area,
...                 "segmentation": seg,
...                 "iscrowd": crowd,
...             }
...             for ann_id, cat, bbox, area, seg, crowd in zip(
...                 objects["id"],
...                 objects["category"],
...                 objects["bbox"],
...                 objects["area"],
...                 objects["segmentation"],
...                 objects["iscrowd"],
...             )
...         ]
...         images.append(image.convert("RGB"))
...         targets.append({"image_id": img_id, "annotations": annotations})
...
...     if not images:
...         return {}
...     return image_processor(
...         images=images, annotations=targets, return_segmentation_masks=True, return_tensors="pt"
...     )


>>> transform = partial(transform_batch, image_processor=image_processor)
>>> train_ds = train_ds.shuffle(seed=42).with_transform(transform)
>>> valid_ds = valid_ds.with_transform(transform)

Ön işlenmiş bir örneği doğrulayın. İçeriği pixel_values (normalize edilmiş görüntü tensörü), pixel_mask (gerçek pikseller ile dolgu arasındaki farkı gösteren) ve labels (normalize edilmiş merkez formatında class_labels, boxes ve ikili masks içeren bir sözlük):

>>> example = train_ds[0]
>>> print(f"pixel_values shape: {example['pixel_values'].shape}")
pixel_values shape: torch.Size([3, 432, 432])
>>> print(f"pixel_mask shape: {example['pixel_mask'].shape}")
pixel_mask shape: torch.Size([432, 432])
>>> print(f"labels keys: {list(example['labels'].keys())}")
labels keys: ['size', 'image_id', 'class_labels', 'boxes', 'area', 'iscrowd', 'orig_size', 'masks']
>>> print(f"  class_labels: {example['labels']['class_labels']}")
  class_labels: tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0])
>>> print(f"  boxes shape: {example['labels']['boxes'].shape}")
  boxes shape: torch.Size([26, 4])
>>> print(f"  masks shape: {example['labels']['masks'].shape}")
  masks shape: torch.Size([26, 432, 432])

Veri toplayıcısı

Her görüntünün farklı sayıda nesne örneği içerdiği için etiketler değişken uzunlukta sözlüklerdir ve tek bir tensöre yığılamaz. pixel_values ve pixel_mask değerlerini normal şekilde yığan, ancak labels değerini görüntü başına sözlüklerden oluşan bir liste olarak koruyan özel bir collate fonksiyonu tanımlayın:

>>> import torch


>>> def collate_fn(batch: list[dict[str, Any]]) -> dict[str, Any]:
...     out = {
...         "pixel_values": torch.stack([x["pixel_values"] for x in batch]),
...         "labels": [x["labels"] for x in batch],
...     }
...     if "pixel_mask" in batch[0]:
...         out["pixel_mask"] = torch.stack([x["pixel_mask"] for x in batch])
...     return out

Değerlendirme metriğini tanımlayın

Eğitim sırasında segmentasyon kalitesini izlemek için, her değerlendirme döneminde birleşim tabanlı ortalama IoU hesaplayın. Her görüntü için:

  1. Tahmin edilen tüm örnek maskelerini tek bir ikili “buildings” haritasında birleştirin (her sorgunun mask logitlerini sigmoid > 0.5 ile ikileştirin)
  2. Tüm gerçek etiketli örnek maskelerini tek bir ikili haritaya birleştirin
  3. İki harita arasında Intersection-over-Union (IoU) hesaplayın

RF-DETR-Seg'in sorgu maskeleri sınıf puanı eşiğiyle sınırlandırılmadığından, metrik sınıf puanlarını yok sayar ve sorgu başına mask logitlerini doğrudan birleştirir. Eşleşmeyen sorgular neredeyse boş maskeler üretir, bu nedenle birleşimi kirletmezler.

Bu, “model binaları ne kadar iyi kapsıyor” sorusuna yönelik görüntü başına bir metrik verir ve bu metrik, tüm doğrulama kümesi üzerinde ortalaması alınır.

Nesne segmentasyonu benchmark'ları (COCO gibi) genellikle mask ortalama ortalama hassasiyetini (mAP) raporlar; bu metrik, her tahmin edilen nesne maskesini bir dizi IoU eşiği boyunca yerinde gerçek (ground truth) ile karşılaştırarak puanlar ve bu nedenle bireysel nesnelerin doğru şekilde ayrıştırılmasını ödüllendirir. Burada kullanılan birleşim tabanlı ortalama IoU, daha basit ve hızlı bir vekildir: nesne bazlı kalite yerine genel piksel kapsamını ölçer, bu da eğitim sırasında ilerlemeyi izlemek için pratik hale getirir. Standart, nesne farkında bir değerlendirme için, örneğin torchmetrics'in MeanAveragePrecision(iou_type="segm") ile mask mAP değerini hesaplayın.

Bunu trainer'ı alt sınıflandırmak yerine Trainer'a compute_metrics fonksiyonu olarak iletin. eval_do_concat_batches=False (aşağıdaki TrainingArguments içinde ayarlanır) kullanıldığında, standart değerlendirme geçişinde üretilen tahminler ve etiketler, compute_metrics'e parti başına çıktılar listesi olarak iletilir; böylece metrik bu tahminleri yeniden kullanır ve doğrulama kümesi üzerinde ikinci bir ileri geçişe gerek kalmaz. Model çıktı demetinde 3 indeksi pred_masks değerini içerir:

>>> import torch.nn.functional as F


>>> @torch.no_grad()
... def compute_mean_iou(pred_masks, gt_masks, target_size):
...     """Union-based IoU: merge all instances per image, then compute IoU."""
...     pred_masks = F.interpolate(pred_masks[None], size=target_size, mode="bilinear", align_corners=False)[0]
...     pred_union = (pred_masks.sigmoid() > 0.5).any(dim=0)
...
...     gt_union = gt_masks.any(dim=0).bool()
...
...     intersection = (pred_union & gt_union).sum().float()
...     union = (pred_union | gt_union).sum().float()
...     return (intersection / union.clamp(min=1)).item()


>>> @torch.no_grad()
... def compute_metrics(evaluation_results):
...     predictions, targets = evaluation_results.predictions, evaluation_results.label_ids
...     ious = []
...     for pred_batch, target_batch in zip(predictions, targets):
...         batch_masks = pred_batch[3]
...         for i, gt_label in enumerate(target_batch):
...             gt_masks = torch.as_tensor(gt_label["masks"])
...             if gt_masks.numel() == 0:
...                 continue
...             target_size = gt_masks.shape[-2:]
...             pred_masks = torch.as_tensor(batch_masks[i])
...             ious.append(compute_mean_iou(pred_masks, gt_masks, target_size))
...
...     mean_iou = sum(ious) / len(ious) if ious else 0.0
...     return {"mean_iou": mean_iou}

Trainer, döndürülen anahtarların başına otomatik olarak eval_ öneki ekler; bu nedenle aşağıda checkpoint seçimi için kullanılan eval_mean_iou metriği üretilir.

Eğitim

Veri, model ve metrikler hazır olduğuna göre eğitimi yapılandırın. TrainingArguments ile ilgili birkaç önemli not:

  • remove_unused_columns=False: Dönüşümümüz çalışmadan önce sütunları düşüren varsayılan davranışı engellemek için gereklidir.
  • eval_do_concat_batches=False: Örnek segmentasyon etiketleri değişken uzunlukta sözlüklerdir ve batch'ler arasında birleştirilemezler. Bu, tahminlerin batch başına gruplu kalmasını da sağlar; böylece compute_metrics onları ilgili etiketlerle eşleştirebilir.
  • metric_for_best_model="eval_mean_iou": Sadece kayıp değil, segmentasyon kalitesine göre en iyi checkpoint'i seçin.
  • fp16=True: Karmaşıklık hassasiyeti eğitimi, modern GPU'larda eğitimi önemli ölçüde hızlandırır.
>>> from transformers import Trainer, TrainingArguments

>>> training_args = TrainingArguments(
...     output_dir="rf-detr-seg-satellite-buildings",
...     num_train_epochs=10,
...     per_device_train_batch_size=16,
...     per_device_eval_batch_size=16,
...     learning_rate=1e-4,
...     weight_decay=1e-4,
...     lr_scheduler_type="cosine",
...     warmup_steps=0.1,
...     fp16=True,
...     dataloader_num_workers=4,
...     eval_strategy="epoch",
...     save_strategy="epoch",
...     save_total_limit=2,
...     load_best_model_at_end=True,
...     metric_for_best_model="eval_mean_iou",
...     greater_is_better=True,
...     remove_unused_columns=False,
...     eval_do_concat_batches=False,
...     push_to_hub=False,
... )

>>> trainer = Trainer(
...     model=model,
...     args=training_args,
...     train_dataset=train_ds,
...     eval_dataset=valid_ds,
...     processing_class=image_processor,
...     data_collator=collate_fn,
...     compute_metrics=compute_metrics,
... )

>>> trainer.train()

Eğitim argümanlarında push_to_hub=True değerini ayarlarsanız, eğitim kontrol noktaları Hugging Face Hub'a gönderilir. Eğitim tamamlandığında, push_to_hub() metodunu çağırarak nihai modeli de Hub'a gönderin.

>>> trainer.push_to_hub(
...     dataset=DATASET_ID,
...     tags=["instance-segmentation", "rf-detr-seg", "vision", "satellite", "building"],
... )

Çıkarım

İnce ayarlanmış modeliniz artık hazır olduğuna göre, yeni uydu görüntülerinde çıkarım (inference) için kullanın. İş akışı şu şekildedir:

  1. Görseli görüntü işleyiciyle ön işleme tabi tutun
  2. Modelden bir ileri geçiş çalıştırın
  3. Çıktıları post_process_instance_segmentation ile işleyerek piksel düzeyinde maskeler alın

Son işleme adımı, ham sorgu çıktıları (logitler + düşük çözünürlüklü maskeler) tam çözünürlüklü örnek segmentasyon haritalarına dönüştürülürken skor eşikleme ve maske ikileştirmeyi uygular.

>>> from datasets import load_dataset

>>> test_ds = load_dataset(DATASET_ID, split="test")
>>> sample = test_ds[0]
>>> image = sample["image"].convert("RGB")

>>> device = next(model.parameters()).device
>>> inputs = image_processor(images=image, return_tensors="pt").to(device)

>>> with torch.no_grad():
...     outputs = model(**inputs)

>>> results = image_processor.post_process_instance_segmentation(
...     outputs, threshold=0.5, target_sizes=[(image.height, image.width)]
... )[0]

>>> print(f"Detected {len(results['segments_info'])} buildings")
Detected 0 buildings
>>> for seg_info in results["segments_info"][:5]:
...     print(f"  Building (score: {seg_info['score']:.3f})")

Tahminleri görselleştirin. Segmentasyon haritası her piksele bir segment kimliği atar (arka plan için -1). Her tespit edilen binayı rastgele bir renkle üst üste bindirin:

>>> fig, axes = plt.subplots(1, 2, figsize=(14, 6))

>>> _ = axes[0].imshow(image)
>>> _ = axes[0].set_title("Input satellite image")
>>> _ = axes[0].axis("off")

>>> seg_map = results["segmentation"].cpu().numpy()
>>> overlay = np.array(image).copy()
>>> for seg_info in results["segments_info"]:
...     mask = seg_map == seg_info["id"]
...     color = np.random.randint(0, 255, 3)
...     overlay[mask] = (overlay[mask] * 0.4 + color * 0.6).astype(np.uint8)

>>> _ = axes[1].imshow(overlay)
>>> _ = axes[1].set_title(f"Predicted masks ({len(results['segments_info'])} buildings)")
>>> _ = axes[1].axis("off")
>>> plt.tight_layout()
>>> plt.show()

Fine-tuning Result

Update on GitHub