vjepa-demo / app.py
yuto090612's picture
Upload app.py with huggingface_hub
f57d992 verified
Raw
History Blame Contribute Delete
4.35 kB
"""Gradio Web UI for V-JEPA / I-JEPA mask prediction demo.
Demonstrates the Joint Embedding Predictive Architecture (JEPA) concept:
- Upload an image
- Randomly mask a portion of its patches
- Visualize how the model attends to the masked regions
"""
import logging
import os
import gradio as gr
from PIL import Image
from src.predictor import Predictor
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)
TITLE = "V-JEPA / I-JEPA - Joint Embedding Predictive Architecture Demo"
DESCRIPTION = """
## What is JEPA?
**Joint Embedding Predictive Architecture (JEPA)** is a self-supervised learning
framework by Meta AI that learns image/video representations by predicting abstract
patch representations rather than pixel values.
### How this demo works
1. **Upload** an image
2. **Adjust** the mask ratio (fraction of patches to hide)
3. The model (I-JEPA ViT-H/14) processes the image:
- **Left**: Shows which patches are masked (grey regions with red borders)
- **Right**: Attention rollout heatmap showing how the encoder distributes
attention across patches. White borders mark the masked regions.
The attention map reveals the model's learned spatial reasoning: how it relates
visible context to predict missing regions.
**Model**: `facebook/ijepa_vith14_1k` (ViT-Huge, 632M params, ImageNet-1K pretrained)
"""
def run_prediction(
image: Image.Image | None,
mask_ratio: float,
) -> tuple[Image.Image | None, Image.Image | None]:
"""Execute mask prediction and return visualization.
Args:
image: Uploaded PIL image (or None if not provided).
mask_ratio: Fraction of patches to mask.
Returns:
Tuple of (masked_image, attention_map), or (None, None) on error.
"""
if image is None:
gr.Warning("Please upload an image first.")
return None, None
predictor = Predictor()
if not predictor.is_initialized:
gr.Info("Loading model for the first time, this may take a moment...")
predictor.initialize()
try:
masked_image, attention_map = predictor.predict(image, mask_ratio)
except Exception as e:
logger.exception("Prediction failed")
gr.Warning(f"Prediction failed: {e}")
return None, None
return masked_image, attention_map
def build_ui() -> gr.Blocks:
"""Construct the Gradio Blocks interface.
Returns:
Configured Gradio Blocks app.
"""
with gr.Blocks(
title=TITLE,
theme=gr.themes.Soft(),
) as demo:
gr.Markdown(f"# {TITLE}")
gr.Markdown(DESCRIPTION)
with gr.Row():
with gr.Column(scale=1):
input_image = gr.Image(
label="Upload Image",
type="pil",
height=300,
)
mask_slider = gr.Slider(
minimum=0.1,
maximum=0.9,
value=0.5,
step=0.05,
label="Mask Ratio",
info="Fraction of image patches to mask",
)
run_button = gr.Button("Run Prediction", variant="primary")
with gr.Column(scale=2):
with gr.Row():
masked_output = gr.Image(
label="Masked Input (grey = masked patches)",
height=300,
)
attention_output = gr.Image(
label="Attention Rollout Map",
height=300,
)
run_button.click(
fn=run_prediction,
inputs=[input_image, mask_slider],
outputs=[masked_output, attention_output],
)
gr.Markdown(
"---\n"
"**References**: "
"[I-JEPA (Assran et al., 2023)](https://arxiv.org/abs/2301.08243) | "
"[V-JEPA (Bardes et al., 2024)](https://arxiv.org/abs/2404.08471) | "
"[V-JEPA 2 (Meta, 2025)](https://arxiv.org/abs/2506.09985)"
)
return demo
# Module-level demo for HF Spaces
demo = build_ui()
if __name__ == "__main__":
port = int(os.environ.get("GRADIO_SERVER_PORT", "7860"))
demo.launch(server_port=port)