Florence-2: Model Vision Multi-Task dari Microsoft
Daftar Isi
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
"ref
expression": "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 = run
florence(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