Florence-2: Model Vision Multi-Task dari Microsoft

# Florence-2: Model Vision Multi-Task dari Microsoft ## Daftar Isi 1. [Pendahuluan](#pendahuluan) 2. [Prasyarat](#prasyarat) 3. [Instalasi](#instalasi) 4. [Memuat Model Florence-2](#memuat-model-flo...

By Ruby Abdullah · · tutorial
Florence-2Computer VisionMicrosoftObject DetectionPython

Florence-2: Model Vision Multi-Task dari Microsoft

Daftar Isi

  • Pendahuluan
  • Prasyarat
  • Instalasi
  • Memuat Model Florence-2
  • Task Prompts yang Didukung
  • Image Captioning
  • Object Detection
  • OCR dan Text Recognition
  • Region Proposal dan Segmentasi
  • Visual Grounding dan Referring Expression
  • Batch Processing
  • Fine-Tuning pada Dataset Kustom
  • Integrasi dengan Supervision untuk Visualisasi
  • Contoh Praktis: Pipeline Analisis Dokumen
  • Praktik Terbaik
  • Kesimpulan
  • Pendahuluan

    Florence-2 adalah model vision foundation dari Microsoft yang dirancang untuk menangani berbagai tugas computer vision dalam satu model tunggal. Tidak seperti model-model sebelumnya yang memerlukan arsitektur terpisah untuk setiap tugas, Florence-2 menggunakan pendekatan sequence-to-sequence yang unified, di mana semua tugas vision dirumuskan sebagai masalah generasi teks berdasarkan prompt tertentu.

    Keunggulan utama Florence-2:

    • Multi-task dalam satu model: Captioning, deteksi objek, OCR, segmentasi, dan grounding dalam satu arsitektur
    • Prompt-based: Cukup ganti prompt teks untuk beralih antar tugas tanpa mengubah model
    • Dua varian ukuran: Florence-2-base (232M parameter) dan Florence-2-large (771M parameter)
    • Zero-shot yang kuat: Performa baik tanpa fine-tuning pada banyak tugas
    • Ringan dan efisien: Ukuran model relatif kecil dibanding VLM lain dengan kemampuan sebanding
    • Open-source: Tersedia di Hugging Face untuk penggunaan penelitian dan komersial

    Florence-2 dilatih pada dataset FLD-5B yang berisi 5,4 miliar anotasi visual-linguistik, mencakup 126 juta gambar. Dalam tutorial ini, Anda akan belajar menggunakan Florence-2 untuk berbagai tugas vision, melakukan batch processing, fine-tuning pada dataset kustom, dan membangun pipeline analisis dokumen.

    Prasyarat

    • Python 3.9 atau lebih tinggi
    • PyTorch 2.0+ dengan dukungan CUDA (GPU sangat direkomendasikan)
    • Minimal 8GB VRAM GPU untuk Florence-2-base, 16GB untuk Florence-2-large
    • Pemahaman dasar tentang konsep computer vision
    • Akun Hugging Face (untuk mengunduh model)

    Instalasi

    # Instal PyTorch (periksa pytorch.org untuk versi CUDA Anda)
    

    pip install torch torchvision

    Instal dependensi utama

    pip install transformers accelerate einops timm

    pip install Pillow matplotlib

    Instal flash-attn untuk inferensi lebih cepat (opsional, memerlukan CUDA)

    pip install flash-attn --no-build-isolation

    Instal supervision untuk visualisasi (opsional)

    pip install supervision

    Verifikasi instalasi:

    import torch
    

    from transformers import AutoProcessor, AutoModelForCausalLM

    print(f"PyTorch: {torch.version}")

    print(f"CUDA tersedia: {torch.cuda.isavailable()}")

    if torch.cuda.isavailable():

    print(f"GPU: {torch.cuda.getdevicename(0)}")

    print(f"VRAM: {torch.cuda.getdeviceproperties(0).totalmem / 1e9:.1f} GB")

    Memuat Model Florence-2

    Florence-2 tersedia dalam dua varian utama beserta versi fine-tuned-nya:

    from transformers import AutoProcessor, AutoModelForCausalLM
    

    import torch

    Pilih model - varian yang tersedia:

    "microsoft/Florence-2-base" - 232M parameter

    "microsoft/Florence-2-large" - 771M parameter

    "microsoft/Florence-2-base-ft" - base, fine-tuned pada downstream tasks

    "microsoft/Florence-2-large-ft" - large, fine-tuned pada downstream tasks

    MODELID = "microsoft/Florence-2-base-ft"

    Muat processor dan model

    processor = AutoProcessor.frompretrained(MODELID, trustremotecode=True)

    model = AutoModelForCausalLM.frompretrained(

    MODELID,

    trustremotecode=True,

    torchdtype=torch.float16,

    devicemap="auto" # otomatis pilih GPU/CPU

    )

    print(f"Model dimuat: {MODELID}")

    print(f"Device: {model.device}")

    Membuat fungsi helper untuk menjalankan inferensi:

    from PIL import Image
    
    

    def runflorence(model, processor, image, taskprompt, textinput=None):

    """

    Jalankan inferensi Florence-2 dengan task prompt tertentu.

    Args:

    model: Model Florence-2

    processor: Processor Florence-2

    image: PIL Image

    taskprompt: Task prompt string (misal '')

    textinput: Teks tambahan untuk prompt (opsional)

    Returns:

    dict: Hasil parsed dari model

    """

    # Gabungkan prompt

    prompt = taskprompt if textinput is None else taskprompt + textinput

    # Proses input

    inputs = processor(

    text=prompt,

    images=image,

    returntensors="pt"

    ).to(model.device, torch.float16)

    # Generate output

    generatedids = model.generate(

    inputids=inputs["inputids"],

    pixelvalues=inputs["pixelvalues"],

    maxnewtokens=1024,

    numbeams=3,

    earlystopping=False,

    dosample=False

    )

    # Decode dan parse hasil

    generatedtext = processor.batchdecode(

    generatedids, skipspecialtokens=False

    )[0]

    parsed = processor.postprocessgeneration(

    generatedtext,

    task=taskprompt,

    imagesize=(image.width, image.height)

    )

    return parsed

    Muat gambar contoh

    image = Image.open("contoh.jpg").convert("RGB")

    Task Prompts yang Didukung

    Florence-2 mendukung berbagai tugas melalui task prompt khusus. Berikut daftar lengkapnya:

    # Dictionary semua task prompt yang didukung Florence-2
    

    TASKPROMPTS = {

    # Captioning

    "caption": "",

    "detailedcaption": "CAPTION>",

    "moredetailed": "DETAILEDCAPTION>",

    # Object Detection

    "objectdetection": "",

    # Dense Region Captioning

    "densecaption": "REGIONCAPTION>",

    # Region Proposal

    "regionproposal": "PROPOSAL>",

    # OCR

    "ocr": "",

    "ocrwithregion": "WITHREGION>",

    # Phrase Grounding

    "phrasegrounding": "TOPHRASEGROUNDING>",

    # Referring Expression

    "refexpression": "EXPRESSIONSEGMENTATION>",

    # Region to Segmentation

    "regiontoseg": "TOSEGMENTATION>",

    # Open Vocabulary Detection

    "openvocabdetect": "VOCABULARYDETECTION>",

    # Region to Category

    "regiontocat": "TOCATEGORY>",

    # Region to Description

    "regiontodesc": "TODESCRIPTION>",

    }

    Image Captioning

    Florence-2 mendukung tiga level captioning dengan detail yang berbeda:

    from PIL import Image
    
    

    image = Image.open("fotokota.jpg").convert("RGB")

    Level 1: Caption singkat

    result = runflorence(model, processor, image, "")

    print("Caption:", result[""])

    Output: "A busy street with cars and pedestrians"

    Level 2: Caption detail

    result = runflorence(model, processor, image, "CAPTION>")

    print("Detail:", result["CAPTION>"])

    Output: "A busy urban street scene with multiple cars parked along

    the road, pedestrians walking on sidewalks, and tall

    buildings in the background under a clear blue sky"

    Level 3: Caption sangat detail

    result = runflorence(model, processor, image, "DETAILEDCAPTION>")

    print("Sangat Detail:", result["DETAILEDCAPTION>"])

    Output: Deskripsi sangat panjang dan komprehensif tentang gambar

    Dense Region Captioning memberikan caption untuk setiap region yang terdeteksi:

    result = runflorence(model, processor, image, "REGIONCAPTION>")
    
    

    Hasil berisi bounding boxes dan label untuk setiap region

    for bbox, label in zip(

    result["REGIONCAPTION>"]["bboxes"],

    result["REGIONCAPTION>"]["labels"]

    ):

    x1, y1, x2, y2 = bbox

    print(f"Region [{x1:.0f},{y1:.0f},{x2:.0f},{y2:.0f}]: {label}")

    Object Detection

    Object detection menghasilkan bounding boxes dengan label untuk semua objek yang terdeteksi:

    image = Image.open("ruangan.jpg").convert("RGB")
    
    

    Deteksi objek standar

    result = runflorence(model, processor, image, "")

    detections = result[""]

    print(f"Terdeteksi {len(detections['bboxes'])} objek:\n")

    for bbox, label in zip(detections["bboxes"], detections["labels"]):

    x1, y1, x2, y2 = bbox

    w, h = x2 - x1, y2 - y1

    print(f" {label}: posisi=({x1:.0f},{y1:.0f}) ukuran=({w:.0f}x{h:.0f})")

    Open Vocabulary Detection memungkinkan deteksi objek berdasarkan deskripsi teks:

    # Deteksi objek berdasarkan teks
    

    result = runflorence(

    model, processor, image,

    "VOCABULARYDETECTION>",

    textinput="a red car. a person wearing hat. a traffic light."

    )

    detections = result["VOCABULARYDETECTION>"]

    for bbox, label in zip(detections["bboxes"], detections["labels"]):

    print(f" {label}: {bbox}")

    Phrase Grounding menghubungkan frasa dalam caption ke region di gambar:

    caption = "A cat sitting on a wooden table next to a laptop"
    
    

    result = runflorence(

    model, processor, image,

    "TOPHRASEGROUNDING>",

    textinput=caption

    )

    grounding = result["TOPHRASEGROUNDING>"]

    for bbox, phrase in zip(grounding["bboxes"], grounding["labels"]):

    print(f" '{phrase}' -> bbox: {bbox}")

    OCR dan Text Recognition

    Florence-2 dapat melakukan OCR dengan atau tanpa informasi lokasi teks:

    image = Image.open("dokumen.jpg").convert("RGB")
    
    

    OCR tanpa lokasi - hanya teks

    result = runflorence(model, processor, image, "")

    print("Teks terdeteksi:")

    print(result[""])

    OCR dengan lokasi - teks + bounding boxes

    result = runflorence(model, processor, image, "WITHREGION>")

    ocrdata = result["WITHREGION>"]

    for bbox, text in zip(ocrdata["quadboxes"], ocrdata["labels"]):

    # quadboxes berisi 4 titik (x1,y1,x2,y2,x3,y3,x4,y4)

    print(f" Teks: '{text}'")

    print(f" Lokasi: {[f'{v:.0f}' for v in bbox]}")

    print()

    Contoh memproses hasil OCR menjadi struktur terorganisir:

    def extracttextblocks(image, model, processor):
    

    """Ekstrak blok teks dari gambar dan urutkan berdasarkan posisi."""

    result = runflorence(model, processor, image, "WITHREGION>")

    ocr = result["WITHREGION>"]

    blocks = []

    for quad, text in zip(ocr["quadboxes"], ocr["labels"]):

    # Ambil y tengah untuk sorting vertikal

    ycenter = (quad[1] + quad[5]) / 2

    xcenter = (quad[0] + quad[4]) / 2

    blocks.append({

    "text": text,

    "y": ycenter,

    "x": xcenter,

    "quad": quad

    })

    # Urutkan: atas ke bawah, lalu kiri ke kanan

    blocks.sort(key=lambda b: (round(b["y"] / 20) 20, b["x"]))

    return blocks

    blocks = extracttextblocks(image, model, processor)

    fulltext = " ".join(b["text"] for b in blocks)

    print("Teks lengkap:", fulltext)

    Region Proposal dan Segmentasi

    Region Proposal menghasilkan area-area menarik dalam gambar:

    image = Image.open("foto.jpg").convert("RGB")
    
    

    Region Proposal

    result = runflorence(model, processor, image, "PROPOSAL>")

    proposals = result["PROPOSAL>"]

    print(f"Ditemukan {len(proposals['bboxes'])} region proposal")

    for i, bbox in enumerate(proposals["bboxes"]):

    print(f" Region {i}: {bbox}")

    Region to Segmentation menghasilkan mask segmentasi untuk region tertentu:

    # Segmentasi dari bounding box tertentu
    

    Format: "x1>y1>x2>y2>"

    Koordinat dinormalisasi ke range 0-999

    region = "100>200>500>600>"

    result = runflorence(

    model, processor, image,

    "TOSEGMENTATION>",

    textinput=region

    )

    segresult = result["TOSEGMENTATION>"]

    print("Polygons:", segresult.get("polygons"))

    print("Labels:", segresult.get("labels"))

    Region to Category dan Region to Description:

    # Dapatkan kategori untuk region tertentu
    

    region = "100>200>500>600>"

    result = runflorence(

    model, processor, image,

    "TOCATEGORY>",

    textinput=region

    )

    print("Kategori:", result["TOCATEGORY>"])

    Dapatkan deskripsi untuk region tertentu

    result = runflorence(

    model, processor, image,

    "TODESCRIPTION>",

    textinput=region

    )

    print("Deskripsi:", result["TODESCRIPTION>"])

    Visual Grounding dan Referring Expression

    Referring Expression Segmentation menemukan dan men-segmentasi objek berdasarkan deskripsi teks:

    image = Image.open("mejakerja.jpg").convert("RGB")
    
    

    Segmentasi berdasarkan deskripsi

    result = runflorence(

    model, processor, image,

    "EXPRESSIONSEGMENTATION>",

    textinput="the laptop on the left side of the desk"

    )

    seg = result["EXPRESSIONSEGMENTATION>"]

    print("Polygons segmentasi:", seg["polygons"])

    print("Label:", seg["labels"])

    Membuat mask dari polygon hasil segmentasi:

    import numpy as np
    

    from PIL import Image, ImageDraw

    def polygonstomask(polygons, imagesize):

    """Konversi polygon Florence-2 ke binary mask."""

    w, h = imagesize

    mask = Image.new("L", (w, h), 0)

    draw = ImageDraw.Draw(mask)

    for polygongroup in polygons:

    for polygon in polygongroup:

    if len(polygon) >= 6: # minimal 3 titik

    points = [(polygon[i], polygon[i+1])

    for i in range(0, len(polygon), 2)]

    draw.polygon(points, fill=255)

    return np.array(mask)

    Buat mask dari hasil referring expression

    mask = polygonstomask(

    seg["polygons"],

    (image.width, image.height)

    )

    Visualisasi overlay

    overlay = np.array(image).copy()

    overlay[mask > 0] = overlay[mask > 0] 0.5 + np.array([0, 255, 0]) 0.5

    overlayimg = Image.fromarray(overlay.astype(np.uint8))

    overlayimg.save("segmentasihasil.jpg")

    Batch Processing

    Untuk memproses banyak gambar secara efisien, gunakan batch processing:

    import os
    

    from pathlib import Path

    def batchprocessflorence(

    model, processor, imagepaths, taskprompt,

    textinput=None, batchsize=4

    ):

    """

    Proses banyak gambar dalam batch.

    Args:

    model: Model Florence-2

    processor: Processor Florence-2

    imagepaths: List path gambar

    taskprompt: Task prompt

    textinput: Teks tambahan (opsional)

    batchsize: Ukuran batch

    Returns:

    list: Hasil untuk setiap gambar

    """

    allresults = []

    prompt = taskprompt if textinput is None else taskprompt + textinput

    for i in range(0, len(imagepaths), batchsize):

    batchpaths = imagepaths[i:i + batchsize]

    batchimages = []

    for path in batchpaths:

    img = Image.open(path).convert("RGB")

    batchimages.append(img)

    # Proses batch

    inputs = processor(

    text=[prompt] len(batchimages),

    images=batchimages,

    returntensors="pt",

    padding=True

    ).to(model.device, torch.float16)

    generatedids = model.generate(

    inputids=inputs["inputids"],

    pixelvalues=inputs["pixelvalues"],

    maxnewtokens=1024,

    numbeams=3,

    dosample=False

    )

    generatedtexts = processor.batchdecode(

    generatedids, skipspecialtokens=False

    )

    # Parse setiap hasil

    for img, text in zip(batchimages, generatedtexts):

    parsed = processor.postprocessgeneration(

    text,

    task=taskprompt,

    imagesize=(img.width, img.height)

    )

    allresults.append(parsed)

    print(f"Diproses {min(i + batchsize, len(imagepaths))}"

    f"/{len(imagepaths)} gambar")

    return allresults

    Contoh penggunaan

    imagedir = Path("dataset/images")

    imagepaths = list(imagedir.glob(".jpg"))

    results = batchprocessflorence(

    model, processor, imagepaths,

    taskprompt="",

    batchsize=4

    )

    Rangkum hasil

    for path, result in zip(imagepaths, results):

    detections = result[""]

    nobjects = len(detections["bboxes"])

    labels = set(detections["labels"])

    print(f"{path.name}: {nobjects} objek ({', '.join(labels)})")

    Fine-Tuning pada Dataset Kustom

    Fine-tuning Florence-2 pada dataset Anda sendiri untuk meningkatkan performa pada domain spesifik:

    import json
    

    from torch.utils.data import Dataset, DataLoader

    from transformers import (

    AutoProcessor, AutoModelForCausalLM,

    TrainingArguments, Trainer

    )

    class Florence2Dataset(Dataset):

    """Dataset kustom untuk fine-tuning Florence-2."""

    def init(self, datadir, annotationsfile, processor, taskprompt):

    self.datadir = Path(datadir)

    self.processor = processor

    self.taskprompt = taskprompt

    with open(annotationsfile, "r") as f:

    self.annotations = json.load(f)

    def len(self):

    return len(self.annotations)

    def getitem(self, idx):

    ann = self.annotations[idx]

    # Muat gambar

    image = Image.open(

    self.datadir / ann["image"]

    ).convert("RGB")

    # Siapkan input dan target

    # Format target tergantung task:

    # - Captioning: teks biasa

    # - Detection: format khusus Florence-2

    prompt = self.taskprompt

    target = ann["target"] # Teks target sesuai format task

    # Proses input

    inputs = self.processor(

    text=prompt,

    images=image,

    returntensors="pt",

    padding="maxlength",

    maxlength=512,

    truncation=True

    )

    # Proses target/labels

    labels = self.processor.tokenizer(

    target,

    returntensors="pt",

    padding="maxlength",

    maxlength=512,

    truncation=True

    )

    return {

    "inputids": inputs["inputids"].squeeze(),

    "pixelvalues": inputs["pixelvalues"].squeeze(),

    "attentionmask": inputs["attentionmask"].squeeze(),

    "labels": labels["inputids"].squeeze()

    }

    Format anotasi untuk berbagai tugas:

    # Contoh file annotations.json untuk captioning
    

    annotationscaption = [

    {

    "image": "img001.jpg",

    "target": "A red excavator digging on a construction site"

    },

    {

    "image": "img002.jpg",

    "target": "Workers wearing safety helmets inspecting equipment"

    }

    ]

    Contoh untuk object detection

    Target menggunakan format Florence-2: "x1>y1>x2>y2>label"

    annotationsdetection = [

    {

    "image": "img001.jpg",

    "target": "excavator120>200>450>500>"

    "worker50>100>150>400>"

    }

    ]

    Simpan anotasi

    with open("annotations.json", "w") as f:

    json.dump(annotationscaption, f, indent=2)

    Menjalankan fine-tuning:

    # Muat model untuk fine-tuning
    

    MODELID = "microsoft/Florence-2-base-ft"

    processor = AutoProcessor.frompretrained(MODELID, trustremotecode=True)

    model = AutoModelForCausalLM.frompretrained(

    MODELID,

    trustremotecode=True,

    torchdtype=torch.float16

    )

    Siapkan dataset

    traindataset = Florence2Dataset(

    datadir="dataset/train/images",

    annotationsfile="dataset/train/annotations.json",

    processor=processor,

    taskprompt=""

    )

    valdataset = Florence2Dataset(

    datadir="dataset/val/images",

    annotationsfile="dataset/val/annotations.json",

    processor=processor,

    taskprompt=""

    )

    Konfigurasi training

    trainingargs = TrainingArguments(

    outputdir="florence2-finetuned",

    numtrainepochs=10,

    perdevicetrainbatchsize=4,

    perdeviceevalbatchsize=4,

    gradientaccumulationsteps=4,

    learningrate=1e-5,

    weightdecay=0.01,

    warmupratio=0.1,

    lrschedulertype="cosine",

    loggingsteps=50,

    evalstrategy="steps",

    evalsteps=200,

    savesteps=200,

    savetotallimit=3,

    loadbestmodelatend=True,

    metricforbestmodel="evalloss",

    fp16=True,

    dataloadernumworkers=4,

    removeunusedcolumns=False,

    reportto="none",

    )

    Buat trainer dan mulai training

    trainer = Trainer(

    model=model,

    args=trainingargs,

    traindataset=traindataset,

    evaldataset=valdataset,

    )

    trainer.train()

    Simpan model

    trainer.savemodel("florence2-finetuned/best")

    processor.savepretrained("florence2-finetuned/best")

    Memuat model yang sudah di-fine-tune:

    # Muat model fine-tuned
    

    finetunedmodel = AutoModelForCausalLM.frompretrained(

    "florence2-finetuned/best",

    trustremotecode=True,

    torchdtype=torch.float16,

    devicemap="auto"

    )

    finetunedprocessor = AutoProcessor.frompretrained(

    "florence2-finetuned/best",

    trustremotecode=True

    )

    Gunakan seperti biasa

    result = runflorence(

    finetunedmodel, finetunedprocessor,

    image, ""

    )

    print(result)

    Integrasi dengan Supervision untuk Visualisasi

    Library supervision dari Roboflow menyediakan tools visualisasi yang sangat baik untuk hasil deteksi:

    import supervision as sv
    

    import numpy as np

    from PIL import Image

    def florencetosvdetections(result, taskkey, imagesize):

    """Konversi hasil Florence-2 ke format supervision Detections."""

    data = result[taskkey]

    if "bboxes" not in data or len(data["bboxes"]) == 0:

    return sv.Detections.empty()

    bboxes = np.array(data["bboxes"])

    labels = data.get("labels", [])

    return sv.Detections(

    xyxy=bboxes,

    data={"classname": np.array(labels)}

    )

    Jalankan deteksi

    image = Image.open("foto.jpg").convert("RGB")

    result = runflorence(model, processor, image, "")

    Konversi ke format supervision

    detections = florencetosvdetections(

    result, "", (image.width, image.height)

    )

    Visualisasi dengan bounding boxes

    imagenp = np.array(image)

    bboxannotator = sv.BoxAnnotator(

    thickness=2,

    color=sv.ColorPalette.DEFAULT

    )

    labelannotator = sv.LabelAnnotator(

    textscale=0.5,

    textpadding=5,

    color=sv.ColorPalette.DEFAULT

    )

    annotated = bboxannotator.annotate(

    scene=imagenp.copy(),

    detections=detections

    )

    annotated = labelannotator.annotate(

    scene=annotated,

    detections=detections,

    labels=detections.data["classname"].tolist()

    )

    Simpan hasil

    sv.plotimage(annotated, size=(12, 8))

    Image.fromarray(annotated).save("deteksihasil.jpg")

    print(f"Terdeteksi {len(detections)} objek")

    Visualisasi untuk dense region captioning:

    # Dense region captioning dengan visualisasi
    

    result = runflorence(model, processor, image, "REGIONCAPTION>")

    detections = florencetosvdetections(

    result, "REGIONCAPTION>", (image.width, image.height)

    )

    Annotasi dengan caption per region

    annotated = bboxannotator.annotate(

    scene=np.array(image).copy(),

    detections=detections

    )

    annotated = labelannotator.annotate(

    scene=annotated,

    detections=detections,

    labels=detections.data["classname"].tolist()

    )

    Image.fromarray(annotated).save("densecaptionhasil.jpg")

    Visualisasi OCR dengan quad boxes:

    def visualizeocrresults(image, ocrresult):
    

    """Visualisasi hasil OCR dengan supervision."""

    data = ocrresult["WITHREGION>"]

    if "quadboxes" not in data or len(data["quadboxes"]) == 0:

    return np.array(image)

    # Konversi quadboxes ke xyxy format

    bboxes = []

    for quad in data["quadboxes"]:

    xcoords = [quad[i] for i in range(0, 8, 2)]

    ycoords = [quad[i] for i in range(1, 8, 2)]

    bboxes.append([

    min(xcoords), min(ycoords),

    max(xcoords), max(ycoords)

    ])

    detections = sv.Detections(

    xyxy=np.array(bboxes),

    data={"classname": np.array(data["labels"])}

    )

    annotated = bboxannotator.annotate(

    scene=np.array(image).copy(),

    detections=detections

    )

    annotated = labelannotator.annotate(

    scene=annotated,

    detections=detections,

    labels=data["labels"]

    )

    return annotated

    result = runflorence(model, processor, image, "WITHREGION>")

    ocrvis = visualizeocrresults(image, result)

    Image.fromarray(ocrvis).save("ocrhasil.jpg")

    Contoh Praktis: Pipeline Analisis Dokumen

    Berikut contoh lengkap pipeline untuk menganalisis dokumen menggunakan Florence-2, menggabungkan OCR, deteksi layout, dan captioning:

    import json
    

    from pathlib import Path

    from dataclasses import dataclass, field, asdict

    from PIL import Image

    import numpy as np

    @dataclass

    class DocumentElement:

    """Representasi elemen dalam dokumen."""

    type: str # "text", "table", "figure", "header"

    bbox: list # [x1, y1, x2, y2]

    content: str = "" # Teks atau caption

    confidence: float = 0.0

    @dataclass

    class DocumentAnalysis:

    """Hasil analisis dokumen lengkap."""

    filename: str

    fulltext: str = ""

    caption: str = ""

    detailedcaption: str = ""

    elements: list = field(defaultfactory=list)

    def todict(self):

    return asdict(self)

    class DocumentAnalyzer:

    """Pipeline analisis dokumen menggunakan Florence-2."""

    def init(self, modelid="microsoft/Florence-2-large-ft"):

    self.processor = AutoProcessor.frompretrained(

    modelid, trustremotecode=True

    )

    self.model = AutoModelForCausalLM.frompretrained(

    modelid,

    trustremotecode=True,

    torchdtype=torch.float16,

    devicemap="auto"

    )

    def run(self, image, task, textinput=None):

    """Helper untuk menjalankan inferensi."""

    return runflorence(

    self.model, self.processor, image, task, textinput

    )

    def analyze(self, imagepath):

    """Analisis dokumen lengkap."""

    image = Image.open(imagepath).convert("RGB")

    doc = DocumentAnalysis(filename=str(imagepath))

    # Langkah 1: Dapatkan caption keseluruhan

    captionresult = self.run(image, "")

    doc.caption = captionresult[""]

    detailresult = self.run(image, "CAPTION>")

    doc.detailedcaption = detailresult["CAPTION>"]

    # Langkah 2: Ekstrak teks dengan OCR

    ocrresult = self.run(image, "WITHREGION>")

    ocrdata = ocrresult["WITHREGION>"]

    textelements = []

    if "quadboxes" in ocrdata:

    for quad, text in zip(

    ocrdata["quadboxes"], ocrdata["labels"]

    ):

    xcoords = [quad[i] for i in range(0, 8, 2)]

    ycoords = [quad[i] for i in range(1, 8, 2)]

    bbox = [

    min(xcoords), min(ycoords),

    max(xcoords), max(ycoords)

    ]

    textelements.append(

    DocumentElement("text", bbox, text)

    )

    # Urutkan teks dari atas ke bawah

    textelements.sort(

    key=lambda e: (

    round(e.bbox[1] / 30) 30, e.bbox[0]

    )

    )

    doc.elements.extend(textelements)

    doc.fulltext = " ".join(e.content for e in textelements)

    # Langkah 3: Deteksi elemen visual (gambar, tabel, dll)

    odresult = self.run(image, "")

    oddata = odresult[""]

    if "bboxes" in oddata:

    for bbox, label in zip(

    oddata["bboxes"], oddata["labels"]

    ):

    # Identifikasi tipe elemen

    labellower = label.lower()

    if any(w in labellower for w in

    ["table", "chart", "graph"]):

    elemtype = "table"

    elif any(w in labellower for w in

    ["image", "photo", "figure", "picture"]):

    elemtype = "figure"

    else:

    elemtype = "object"

    # Dapatkan deskripsi untuk region ini

    x1, y1, x2, y2 = bbox

    nx1 = int(x1 / image.width 999)

    ny1 = int(y1 / image.height 999)

    nx2 = int(x2 / image.width 999)

    ny2 = int(y2 / image.height 999)

    region = (f"{nx1}>{ny1}>"

    f"{nx2}>{ny2}>")

    descresult = self.run(

    image, "TODESCRIPTION>",

    textinput=region

    )

    description = descresult.get(

    "TODESCRIPTION>", label

    )

    doc.elements.append(

    DocumentElement(

    elemtype, list(bbox),

    str(description)

    )

    )

    return doc

    def analyzebatch(self, imagedir, outputfile):

    """Analisis batch dokumen dan simpan hasil."""

    imagedir = Path(imagedir)

    extensions = {".jpg", ".jpeg", ".png", ".bmp", ".tiff"}

    images = [

    p for p in imagedir.iterdir()

    if p.suffix.lower() in extensions

    ]

    results = []

    for i, imgpath in enumerate(images):

    print(f"\nMemproses [{i+1}/{len(images)}]: {imgpath.name}")

    try:

    doc = self.analyze(imgpath)

    results.append(doc.todict())

    print(f" Caption: {doc.caption}")

    print(f" Elemen: {len(doc.elements)}")

    print(f" Teks: {doc.fulltext[:100]}...")

    except Exception as e:

    print(f" Error: {e}")

    results.append({

    "filename": str(imgpath),

    "error": str(e)

    })

    # Simpan hasil

    with open(outputfile, "w", encoding="utf-8") as f:

    json.dump(results, f, indent=2, ensureascii=False)

    print(f"\nHasil disimpan ke {outputfile}")

    return results

    Penggunaan

    analyzer = DocumentAnalyzer("microsoft/Florence-2-large-ft")

    Analisis satu dokumen

    doc = analyzer.analyze("dokumeninvoice.jpg")

    print(f"Caption: {doc.caption}")

    print(f"Teks: {doc.fulltext}")

    print(f"Jumlah elemen: {len(doc.elements)}")

    Analisis batch

    results = analyzer.analyzebatch(

    "folderdokumen/",

    "hasilanalisis.json"

    )

    Praktik Terbaik

    Berikut beberapa tips untuk menggunakan Florence-2 secara optimal:

    Pemilihan Model:
    # Gunakan base-ft untuk kecepatan dan efisiensi memori
    

    Gunakan large-ft untuk akurasi terbaik

    Perbandingan varian:

    Florence-2-base : 232M params, inferensi cepat, cocok untuk edge

    Florence-2-base-ft : 232M params + fine-tuned, keseimbangan terbaik

    Florence-2-large : 771M params, akurasi tinggi

    Florence-2-large-ft : 771M params + fine-tuned, performa terbaik

    Artikel Terkait

    Supervision: Toolkit Computer Vision dari Roboflow

    Supervision: Toolkit Computer Vision dari Roboflow Dalam proyek computer vision, setelah model mendeteksi objek, Anda ma...

    Tutorial Lengkap Ultralytics: Object Detection dengan YOLO

    Tutorial Lengkap Ultralytics: Object Detection dengan YOLO Ultralytics adalah framework Python yang menyediakan implemen...

    Panduan Lengkap DETR: Object Detection dengan Transformers

    Panduan Lengkap DETR: Object Detection dengan Transformers DETR (DEtection TRansformer) adalah pendekatan revolusioner u...

    Tutorial Surya OCR: Document AI untuk Text Detection, OCR, dan Layout Analysis

    Tutorial Surya OCR: Document AI untuk Text Detection, OCR, dan Layout Analysis Surya adalah library Document AI open-sou...