Spaces:
Build error
Build error
File size: 6,098 Bytes
67f827d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | import streamlit as st
import torch
import numpy as np
import matplotlib.pyplot as plt
from transformers import BlipProcessor, BlipForConditionalGeneration
from transformers import AutoProcessor, AutoModelForVisualQuestionAnswering
from PIL import Image, ImageOps
import io
import torchvision.transforms as T
import torch.nn.functional as F
# **Cek Device**
device = "cuda" if torch.cuda.is_available() else "cpu"
# **Konfigurasi Halaman Streamlit**
st.set_page_config(
initial_sidebar_state="expanded",
page_title="Explainable Image Caption Bot"
)
# **Load Model BLIP**
@st.cache_resource
def load_blip_model():
# processor = BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base")
# model = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base").to(device)
processor = AutoProcessor.from_pretrained("Salesforce/blip2-opt-2.7b")
model = AutoModelForVisualQuestionAnswering.from_pretrained("Salesforce/blip2-opt-2.7b").to(device)
return processor, model
processor, model = load_blip_model()
# **Transformasi Gambar untuk Model**
def transform_image(img):
transform = T.Compose([
T.Resize((384, 384)), # Resize sesuai model BLIP
T.ToTensor(),
T.Normalize((0.5,), (0.5,))
])
return transform(img)
def generate_caption(image, processor, model):
inputs = processor(images=image, return_tensors="pt").to(device)
# Pastikan kita menangkap perhatian dari Transformer
attention_maps = []
def get_attention_hook(module, input, output):
print("✅ Hook executed! Attention captured.") # Debugging
attention_maps.append(output) # Output adalah tuple
# Pasang hook ke layer yang sesuai
handle = model.vision_model.encoder.layers[-1].self_attn.register_forward_hook(get_attention_hook)
# Generate caption
with torch.no_grad():
caption_ids = model.generate(**inputs)
# Hapus hook setelah digunakan
handle.remove()
caption = processor.decode(caption_ids[0], skip_special_tokens=True)
# **Periksa apakah attention_maps berhasil ditangkap**
if not attention_maps:
print("❌ Attention Maps tidak terisi! Hook mungkin tidak bekerja.")
return caption, None
# **Ambil tensor dari tuple**
attention_tensor = attention_maps[0][0] # Ambil tensor pertama dari tuple
attention = attention_tensor.cpu().detach().numpy().mean(axis=1)
return caption, attention
# **Fungsi untuk Memuat Gambar**
@st.cache_data
def load_uploaded_image(img):
if isinstance(img, str):
image = Image.open(img)
else:
img_bytes = img.read()
image = Image.open(io.BytesIO(img_bytes)).convert("RGB")
image = ImageOps.exif_transpose(image) # Perbaiki orientasi gambar
return image
def plot_attention(image, caption, attention):
"""
Menampilkan heatmap attention untuk setiap kata dalam caption.
"""
if attention is None or len(attention.shape) != 2:
st.error("Attention map tidak valid! Tidak bisa menampilkan heatmap.")
return
num_words = len(caption.split())
num_attention_steps = min(num_words, attention.shape[0]) # Sesuaikan panjang attention
fig, axes = plt.subplots(1, num_attention_steps, figsize=(num_attention_steps * 3, 5))
if num_attention_steps == 1:
axes = [axes] # Pastikan list jika hanya ada satu kata
for i in range(num_attention_steps):
attn_map = attention[i]
# **Reshape attention ke bentuk yang sesuai**
if attn_map.shape[0] == 768:
grid_size = 24 # Vision Transformer biasanya menggunakan 24x32 patches
attn_map = attn_map[:grid_size * grid_size].reshape(grid_size, grid_size)
else:
st.warning(f"Attention map tidak bisa diubah menjadi grid! (Token count: {attn_map.shape[0]})")
continue
# **Interpolasi agar ukuran sesuai dengan gambar**
attn_resized = F.interpolate(
torch.tensor(attn_map).unsqueeze(0).unsqueeze(0),
size=(image.size[1], image.size[0]), # Sesuaikan ke ukuran gambar
mode="bilinear",
align_corners=False
).squeeze().numpy()
# **Plot setiap heatmap per kata**
axes[i].imshow(image)
axes[i].imshow(attn_resized, cmap='jet', alpha=0.5)
axes[i].set_title(caption.split()[i])
axes[i].axis("off")
plt.tight_layout()
st.pyplot(fig)
# **Streamlit UI**
st.title("Explainable Image Captioning Bot 🤖🖼️")
st.text("Powered by BLIP (Salesforce) - A Transformer-based Image Captioning Model")
st.success("Upload an image and generate a caption!")
# **File Upload**
uploaded_file = st.file_uploader("Upload an image (JPG, PNG, JPEG)", type=["png", "jpg", "jpeg", "webp"])
img_path = "imgs/test2.jpeg" if uploaded_file is None else uploaded_file
# **Muat dan Tampilkan Gambar**
image = load_uploaded_image(img_path)
st.image(image, use_column_width=True, caption="Uploaded Image")
# **Generate Caption Button**
# Jika tombol ditekan, jalankan captioning dan attention visualization
if st.button("Generate Caption"):
caption, attention = generate_caption(image, processor, model)
if attention is None:
st.error("Attention map tidak tersedia! Coba ganti layer yang di-hook.")
else:
st.markdown(f"### **Generated Caption:**\n📢 *{caption}*")
plot_attention(image, caption, attention) # ✅ Panggil dengan 3 argumen
st.balloons()
# **Sidebar Info**
st.sidebar.markdown("""
### About This App 📝
This app generates captions for images using **Hugging Face's BLIP model** trained by **Salesforce**.
It also provides **explainable AI insights** into how images are understood by deep learning models.
### How to Use:
1. **Upload an image** 📷 (JPG/PNG/JPEG).
2. **Click "Generate Caption"** 🏷️.
3. **View AI-generated caption** for your image along with **attention heatmap**!
### Want More Features?
Check the model on [Hugging Face](https://huggingface.co/Salesforce/blip-image-captioning-base).
""")
|