Spaces:
Running on Zero
Running on Zero
| """ | |
| Medical Image Captioning — Qwen2.5-VL-7B + LoRA (correctness-focused checkpoint) | |
| عشان ده يشتغل على HF Spaces مجانًا، بيستخدم ZeroGPU (GPU مشترك بيتاجَّر | |
| بس وقت التنفيذ الفعلي). لازم الـ Space نفسه يتظبط بـ SDK: Gradio + | |
| Hardware: ZeroGPU (مجاني، بس محتاج تفعيله من إعدادات الـ Space). | |
| """ | |
| import os | |
| import spaces | |
| import torch | |
| import gradio as gr | |
| from PIL import Image | |
| from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor | |
| from peft import PeftModel | |
| HF_TOKEN = os.environ.get("HF_TOKEN") # اتحطت كـ Secret في إعدادات الـ Space | |
| BASE_MODEL_ID = "Qwen/Qwen2.5-VL-7B-Instruct" | |
| ADAPTER_ID = "WafaaFraih/qwen25vl_correctness_checkpoint" | |
| PROMPTS = { | |
| "Generic": "Describe this image.", | |
| "Clinical": ( | |
| "You are a medical imaging expert. Describe this medical image " | |
| "with precise clinical terminology. Be concise and factual." | |
| ), | |
| "Chain-of-thought": ( | |
| "You are a medical imaging expert. " | |
| "Step 1: Identify the imaging modality. " | |
| "Step 2: Identify the anatomical region. " | |
| "Step 3: Describe the key findings. " | |
| "Now write one concise clinical caption." | |
| ), | |
| } | |
| # ⚠️ ZeroGPU: مكتبة `spaces` بتعترض حتى عمليات تحميل الـ safetensors | |
| # العادية لو حصلت برّه دالة معلَّمة بـ @spaces.GPU. عشان كده لازم | |
| # التحميل كله (base model + adapter) يبقى جوه الدالة، مش هنا. | |
| processor = None | |
| model = None | |
| def _ensure_loaded(): | |
| """يحمّل الموديل والـ adapter مرة واحدة بس، أول ما حد يستخدم الـ demo.""" | |
| global processor, model | |
| if model is not None: | |
| return | |
| print("▶ Loading base model + LoRA adapter (first request only)...") | |
| processor = AutoProcessor.from_pretrained(BASE_MODEL_ID) | |
| base_model = Qwen2_5_VLForConditionalGeneration.from_pretrained( | |
| BASE_MODEL_ID, | |
| torch_dtype=torch.float16, | |
| ) | |
| loaded = PeftModel.from_pretrained(base_model, ADAPTER_ID, token=HF_TOKEN) | |
| loaded.eval() | |
| loaded.to("cuda") | |
| model = loaded | |
| print("✅ Model ready on GPU.") | |
| def caption_image(image: Image.Image, prompt_style: str): | |
| _ensure_loaded() | |
| if image is None: | |
| return "⚠️ Please upload a medical image first." | |
| image = image.convert("RGB") | |
| prompt_text = PROMPTS[prompt_style] | |
| messages = [ | |
| { | |
| "role": "user", | |
| "content": [ | |
| {"type": "image"}, | |
| {"type": "text", "text": prompt_text}, | |
| ], | |
| } | |
| ] | |
| text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) | |
| inputs = processor(text=[text], images=[image], return_tensors="pt").to("cuda") | |
| with torch.no_grad(): | |
| output_ids = model.generate( | |
| **inputs, | |
| max_new_tokens=128, | |
| do_sample=False, | |
| ) | |
| generated = processor.batch_decode( | |
| output_ids[:, inputs["input_ids"].shape[1]:], | |
| skip_special_tokens=True, | |
| )[0].strip() | |
| return generated | |
| with gr.Blocks(title="Medical Image Captioning — Qwen2.5-VL (LoRA fine-tuned)") as demo: | |
| gr.Markdown( | |
| """ | |
| # 🩺 Medical Image Captioning | |
| **Qwen2.5-VL-7B**, LoRA fine-tuned on ROCO + MultiCare with a | |
| correctness-focused training recipe (see the accompanying paper | |
| for the full evaluation, including known limitations). | |
| ⚠️ **Research demo only.** Captions are automatically generated | |
| and are **not validated for clinical or diagnostic use**. Do not | |
| use this tool to inform real medical decisions. | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| image_input = gr.Image(type="pil", label="Upload a medical image") | |
| prompt_choice = gr.Radio( | |
| choices=list(PROMPTS.keys()), | |
| value="Clinical", | |
| label="Prompt style", | |
| ) | |
| run_button = gr.Button("Generate caption", variant="primary") | |
| with gr.Column(): | |
| output_text = gr.Textbox(label="Generated caption", lines=6) | |
| run_button.click(fn=caption_image, inputs=[image_input, prompt_choice], outputs=output_text) | |
| gr.Markdown( | |
| """ | |
| --- | |
| Model card and training details: see the linked paper and the | |
| [adapter repository](https://huggingface.co/WafaaFraih/qwen25vl_correctness_checkpoint). | |
| Base model: [Qwen2.5-VL-7B-Instruct](https://huggingface.co/Qwen/Qwen2.5-VL-7B-Instruct). | |
| """ | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |