vlm-probe / examples /tutorials /attention_profile.py
gexinh's picture
Sync vlmprobe 1.1.0: MJ-Lens, audited fixes and current documentation
7dbdc9e verified
Raw History Blame Contribute Delete
2.78 kB
from pathlib import Path
import os
from io import BytesIO
from urllib.request import urlopen
import torch
from PIL import Image
from transformers import AutoImageProcessor, ViTForImageClassification
from vlmprobe import Prober
from vlmprobe import visualization as viz
import matplotlib.pyplot as plt
# Install: pip install "vlmprobe[transformers,visualization]"
# Set VLM_PROBING_MODEL to a local directory to avoid downloading this checkpoint.
model_id = os.environ.get("VLM_PROBING_MODEL", "google/vit-base-patch16-224")
device = os.environ.get("VLM_PROBING_DEVICE", "cuda:0" if torch.cuda.is_available() else "cpu")
model = ViTForImageClassification.from_pretrained(model_id, attn_implementation="eager").to(device).eval()
processor = AutoImageProcessor.from_pretrained(os.environ.get("VLM_PROBING_PROCESSOR", model_id))
probe = Prober(model, processor)
# A raw COCO image, not a saved attention map or a previous model result.
image_path = os.environ.get("VLM_PROBING_IMAGE")
image = (Image.open(image_path) if image_path else Image.open(BytesIO(urlopen(
"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/coco_sample.png"
).read()))).convert("RGB")
inputs = {k: v.to(device) for k, v in processor(images=image, return_tensors="pt").items()}
# Plot the actual processed image; its crop/resize aligns with the patch tokens.
mean = torch.tensor(processor.image_mean)[:, None, None]
std = torch.tensor(processor.image_std)[:, None, None]
rgb = (inputs["pixel_values"][0].detach().cpu() * std + mean).clamp(0, 1)
processed_image = Image.fromarray((rgb.permute(1, 2, 0).numpy() * 255).astype("uint8"))
patch = model.config.patch_size
grid_shape = tuple(int(n // patch) for n in inputs["pixel_values"].shape[-2:])
visual_positions = list(range(1, 1 + grid_shape[0] * grid_shape[1])) # CLS is 0.
last = probe.describe()["methods"]["attention.profile"]["sites"][-1]
output_dir = Path(os.environ.get("VLM_PROBING_OUTPUT", "outputs/attention-tutorial"))
output_dir.mkdir(parents=True, exist_ok=True)
result = probe.attention.profile(
layers=[last], queries=[0], groups={"patches": "visual", "cls": [0]},
include_attention=True,
).run(inputs)
print("Entropy [L,B,H,Q]:", result.tensors["entropy"].shape)
print("Selected query entropy:", result.tensors["entropy"][0, 0, :, 0])
print("Group order:", result.metadata["layer_results"][0]["groups"])
ax = viz.plot_attention_overlay(
processed_image, result, tensor="attention", grid_shape=grid_shape,
visual_positions=visual_positions, query_positions=[0],
signed=False, image_alpha=0.25, alpha=1.0,
title="Raw CLS attention (mean heads)",
)
ax.figure.savefig(output_dir / "attention-profile.png", dpi=160, bbox_inches="tight")
result.save(output_dir / "attention-profile")
plt.show()