Downloads · 30 days
21
24% of all-time downloads
Adicandra/Qwen3.5-4B-ImageCaptioning-LoRA
Qwen3.5-4B-ImageCaptioning-LoRA is a image-text-to-text model from Adicandra. Use it for the image-text-to-text task on the model card, and read the license before you ship it in a product. It is set up for transformers. The card lists the license as apache-2.0.
Model ini merupakan hasil fine-tuning (LoRA, sudah di-merge ke base weights) dari Qwen/Qwen3.5-4B-Base untuk tugas image captioning Bahasa Indonesia.
Downloads · 30 days
21
24% of all-time downloads
All-time downloads
87
Public
Parameters
4.5B
9.1 GB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors9.1 GB · 100%
From the Hugging Face model README
Model ini merupakan hasil fine-tuning (LoRA, sudah di-merge ke base weights) dari
Qwen/Qwen3.5-4B-Base untuk tugas image captioning Bahasa Indonesia.
| Atribut | Nilai |
|---|---|
| Base model | Qwen/Qwen3.5-4B-Base |
| Metode fine-tune | LoRA (rank/alpha sesuai config SFT) |
| Status adapter | Merged ke base weights |
| Bahasa output | Bahasa Indonesia 🇮🇩 |
| Format output | JSON — {"caption": "..."} |
enable_thinking saat training | False |
| EOS token | <|im_end|> (+ <|endoftext|>) |
| Precision | bfloat16 |
import torch
from PIL import Image
from transformers import AutoProcessor, AutoModelForImageTextToText
REPO = "Adicandra/Qwen3.5-4B-ImageCaptioning-LoRA"
processor = AutoProcessor.from_pretrained(REPO)
model = AutoModelForImageTextToText.from_pretrained(
REPO,
torch_dtype=torch.bfloat16,
device_map="auto",
)
model.eval()
SYSTEM_PROMPT = (
"Annotator dataset image captioning. Tulis caption Bahasa Indonesia yang deskriptif.\n\n"
"Aturan:\n"
"- Deskripsikan subjek utama, detail visual (warna, posisi, atribut), dan latar belakang.\n"
"- Jika gambar mengandung teks penting (meme, infografis, berita, poster), sertakan isi teksnya dalam caption.\n"
"- KHUSUS UNTUK GAMBAR MEME: Analisis dan jelaskan makna sarkasme, ironi, atau humor yang terkandung di dalamnya jika ada.\n"
"- Panjang caption fleksibel: 2-3 kalimat untuk gambar biasa, lebih panjang jika ada teks/informasi penting atau sarkasme.\n"
"- Hanya deskripsikan yang terlihat (serta konteks humor/sarkasme jika itu meme). Jangan tebak identitas/nama. Jangan awali dengan \"gambar ini menunjukkan\".\n"
'- Output: Harus berupa JSON valid dengan format: {"caption": "isi caption disini"}'
)
import json, re
USER_PROMPT = "Buatkan caption deskriptif untuk gambar ini."
MAX_IMAGE_SIZE = (560, 560)
# ── Load & resize gambar ──────────────────────────────────────────────────────
img = Image.open("path/to/image.jpg").convert("RGB")
img.thumbnail(MAX_IMAGE_SIZE, Image.Resampling.LANCZOS)
# ── Susun messages ────────────────────────────────────────────────────────────
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": [
{"type": "image"},
{"type": "text", "text": USER_PROMPT},
]},
]
# ── Render template (enable_thinking=False wajib) ────────────────────────────
text = processor.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
enable_thinking=False,
)
# ── Tokenize ──────────────────────────────────────────────────────────────────
inputs = processor(text=[text], images=[[img]], return_tensors="pt").to(model.device)
input_len = inputs.input_ids.shape[1]
# ── EOS tokens ───────────────────────────────────────────────────────────────
im_end_id = processor.tokenizer.convert_tokens_to_ids("<|im_end|>")
eot_id = processor.tokenizer.convert_tokens_to_ids("<|endoftext|>")
eos_ids = list({im_end_id, eot_id} - {-1})
# ── Generate — greedy (deterministik) ────────────────────────────────────────
with torch.no_grad():
out = model.generate(
**inputs,
max_new_tokens=256,
do_sample=False,
use_cache=True,
eos_token_id=eos_ids,
pad_token_id=processor.tokenizer.pad_token_id,
)
raw = processor.tokenizer.decode(out[0, input_len:], skip_special_tokens=True)
# ── Parse JSON output ─────────────────────────────────────────────────────────
def extract_caption(raw: str):
cleaned = re.sub(r"<think>.*?</think>", "", raw, flags=re.DOTALL).strip()
try:
obj = json.loads(cleaned)
if isinstance(obj, dict) and "caption" in obj:
return obj["caption"], "valid"
except Exception:
pass
m = re.search(r"\{.*\}", cleaned, flags=re.DOTALL)
if m:
try:
obj = json.loads(m.group(0))
if isinstance(obj, dict) and "caption" in obj:
return obj["caption"], "recovered"
except Exception:
pass
return cleaned, "invalid"
caption, status = extract_caption(raw)
print(f"[{status}] {caption}")
# Tambahkan argumen berikut ke model.generate() untuk sampling:
with torch.no_grad():
out = model.generate(
**inputs,
max_new_tokens=256,
do_sample=True,
temperature=0.7,
top_p=0.8,
top_k=20,
min_p=0.0,
repetition_penalty=1.2,
use_cache=True,
eos_token_id=eos_ids,
pad_token_id=processor.tokenizer.pad_token_id,
)
Model selalu menghasilkan JSON valid:
{"caption": "Seekor kucing oranye sedang duduk di atas meja kayu berwarna cokelat, menatap ke arah kanan frame dengan mata setengah terpejam. Latar belakang berupa dinding putih yang sedikit buram."}
Jika gambar mengandung teks (meme, infografis, poster), teks tersebut akan disertakan dalam caption beserta konteks humor/sarkasme bila relevan.
<think> MunculModel di-train dengan enable_thinking=False. Pastikan argumen tersebut selalu diteruskan ke apply_chat_template. Jika token <think> masih muncul di output:
enable_thinking=False di apply_chat_template.suppress_tokens=[think_id] saat generate() sebagai fallback.extract_caption() di atas sudah mem-strip blok <think>...</think> secara otomatis.Mengikuti lisensi base model: Apache 2.0.
Jika menggunakan model ini dalam penelitian, silakan sitasi base model Qwen3.5 dan sebutkan repo ini sebagai fine-tune untuk image captioning Bahasa Indonesia.