Spaces:
Sleeping
Sleeping
| import time | |
| import torch | |
| import gradio as gr | |
| from PIL import Image | |
| from transformers import AutoModelForImageTextToText, AutoProcessor | |
| CKPT = "q-future/Q-ReAlign-Mini-0.8B" | |
| LEVELS = ["excellent", "good", "fair", "poor", "bad"] | |
| WEIGHTS = [1.0, 0.75, 0.5, 0.25, 0.0] | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| print(f"[{time.strftime('%X')}] Loading model on {device}...") | |
| processor = AutoProcessor.from_pretrained(CKPT) | |
| model = AutoModelForImageTextToText.from_pretrained(CKPT, dtype="auto").to(device).eval() | |
| print(f"[{time.strftime('%X')}] Model loaded successfully.") | |
| def score_image(image, task_type): | |
| if image is None: | |
| yield "Error", "Please upload an image." | |
| return | |
| start_time = time.time() | |
| # ЭТАП 1: Оптимизация размера изображения (Критично для CPU) | |
| yield "0.0000", "⏳ Step 1: Resizing image to prevent CPU overload..." | |
| max_size = 768 # Ограничиваем максимальную сторону, сохраняя пропорции | |
| image.thumbnail((max_size, max_size)) | |
| print(f"[{time.strftime('%X')}] Image resized to {image.size}") | |
| if task_type == "Quality (IQA)": | |
| prompt = "How would you rate the quality of this image?" | |
| stem = "The quality of the image is" | |
| else: | |
| prompt = "How would you rate the aesthetics of this image?" | |
| stem = "The aesthetics of the image is" | |
| messages = [{"role": "user", "content": [ | |
| {"type": "image"}, | |
| {"type": "text", "text": prompt}, | |
| ]}] | |
| # ЭТАП 2: Подготовка токенов | |
| yield "0.0000", "⏳ Step 2: Preprocessing and tokenizing..." | |
| text = processor.apply_chat_template(messages, add_generation_prompt=True) + stem | |
| inputs = processor( | |
| text=[text], | |
| images=[image.convert("RGB")], | |
| return_tensors="pt" | |
| ).to(device) | |
| print(f"[{time.strftime('%X')}] Preprocessing done. Input shape: {inputs['input_ids'].shape}") | |
| ids = [processor.tokenizer(" " + w, add_special_tokens=False).input_ids[0] for w in LEVELS] | |
| # ЭТАП 3: Прогон через нейросеть | |
| # Здесь нельзя добавить прогресс-бар, так как это одна атомарная C++ операция PyTorch | |
| yield "0.0000", "⏳ Step 3: Running neural network forward pass (This takes the longest)..." | |
| print(f"[{time.strftime('%X')}] Starting forward pass...") | |
| with torch.no_grad(): | |
| outputs = model(**inputs) | |
| print(f"[{time.strftime('%X')}] Forward pass completed!") | |
| # ЭТАП 4: Расчет оценки | |
| yield "0.0000", "⏳ Step 4: Calculating final score..." | |
| probs = outputs.logits[0, -1, ids].softmax(-1) | |
| score = (probs * torch.tensor(WEIGHTS, device=device)).sum().item() | |
| total_time = time.time() - start_time | |
| print(f"[{time.strftime('%X')}] Done! Score: {score:.4f}. Total time: {total_time:.1f}s") | |
| # ИТОГ | |
| yield f"{score:.4f}", f"✅ Done in {total_time:.1f} seconds." | |
| with gr.Blocks(title="Q-ReAlign Mini (0.8B)") as demo: | |
| gr.Markdown("# Q-ReAlign Mini (0.8B) Image Judge") | |
| gr.Markdown( | |
| "Rates the perceptual quality or aesthetics of an image using the Qwen3.5-VL multimodal model. " | |
| "The result is a score ranging from 0 (worst) to 1 (best)." | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| input_image = gr.Image(type="pil", label="Input Image") | |
| task_dropdown = gr.Dropdown( | |
| choices=["Quality (IQA)", "Aesthetics (IAA)"], | |
| value="Quality (IQA)", | |
| label="Task" | |
| ) | |
| submit_btn = gr.Button("Evaluate", variant="primary") | |
| with gr.Column(): | |
| output_score = gr.Textbox(label="Final Score", lines=1) | |
| status_box = gr.Textbox(label="Status Log", lines=1, interactive=False) | |
| # Используем outputs в виде списка, чтобы обновлять и оценку, и лог | |
| submit_btn.click( | |
| fn=score_image, | |
| inputs=[input_image, task_dropdown], | |
| outputs=[output_score, status_box] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |