ASTRALK's picture
Upload README.md with huggingface_hub
65a44d1 verified
|
Raw History Blame Contribute Delete
2.19 kB
metadata
license: other
base_model: LiquidAI/LFM2.5-VL-450M
library_name: transformers
tags:
  - vision-language
  - remote-sensing
  - illegal-mining
  - image-classification
pipeline_tag: image-text-to-text

sentinel-lfm — LFM2.5-VL-450M FULL fine-tune v2 (improved recipe)

All-layers fine-tune of LiquidAI/LFM2.5-VL-450M with an improved training recipe over ASTRALK/sentinel-lfm-mining-450m-full: (1) all 1965 train patches (no downsampling) + class-weighted loss, (2) validation-based best-checkpoint selection (balanced accuracy), (3) weight decay, longer schedule. Replies {"mine_present": true|false}.

Results on the held-out test split (419 patches, 303 pos / 116 neg)

model acc F1 recall recall_neg precision
base (zero-shot) 0.7208 0.8326 0.9604 0.0948 0.7348
LoRA fine-tuned 0.7995 0.8645 0.8845 0.5776 0.8454
FULL fine-tuned (v1) 0.8138 0.8754 0.9043 0.5776 0.8483
FULL fine-tuned v2 (this) 0.8353 0.8900 0.9208 0.6121 0.8611

Training

  • FULL fine-tune, 448718848 params, class-weighted loss
  • 6 epochs, lr=2e-05 (warmup->cosine), wd=0.01
  • best checkpoint by val balanced-acc: epoch 1 (bal_acc=0.7713)
  • bf16 autocast + gradient checkpointing, ~25.8 min on H100

Usage

from transformers import AutoProcessor, AutoModelForImageTextToText
from transformers.image_utils import load_image

model = AutoModelForImageTextToText.from_pretrained("ASTRALK/sentinel-lfm-mining-450m-full-v2", dtype="bfloat16", device_map="auto")
proc = AutoProcessor.from_pretrained("ASTRALK/sentinel-lfm-mining-450m-full-v2")
img = load_image("patch.png")
conv = [{"role":"user","content":[
    {"type":"image","image":img},
    {"type":"text","text":'Does this satellite patch show illegal mining? Reply with only this JSON: {"mine_present": true} or {"mine_present": false}'}]}]
inp = proc.apply_chat_template(conv, add_generation_prompt=True, return_tensors="pt", return_dict=True, tokenize=True).to(model.device)
print(proc.decode(model.generate(**inp, max_new_tokens=16)[0][inp["input_ids"].shape[1]:], skip_special_tokens=True))