mahmoudalyosify commited on
Commit
db2a1fe
·
verified ·
1 Parent(s): 66cdd70

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +53 -54
src/streamlit_app.py CHANGED
@@ -156,7 +156,6 @@ def perform_search(features_batch, top_k=5):
156
  # ==========================================================================
157
  st.set_page_config(
158
  page_title="SimCLR ResNet-50 Visual Search",
159
- page_icon="🔍",
160
  layout="wide",
161
  initial_sidebar_state="expanded"
162
  )
@@ -208,7 +207,7 @@ st.markdown("""
208
  # ==========================================================================
209
  # Sidebar Configuration
210
  # ==========================================================================
211
- st.sidebar.markdown("### Engine Settings")
212
  top_k_slider = st.sidebar.slider("Number of results (K)", min_value=3, max_value=20, value=6, step=1)
213
 
214
  st.sidebar.markdown("---")
@@ -224,7 +223,7 @@ st.sidebar.markdown("""
224
  """)
225
 
226
  st.sidebar.markdown("---")
227
- st.sidebar.markdown("### Backend Pipeline")
228
  st.sidebar.markdown("""
229
  * **Inference Engine**: ONNX Runtime CPU
230
  * **Vector Database**: FAISS (IndexFlatIP)
@@ -263,7 +262,7 @@ with tab1:
263
 
264
  # Method 2: Pick a random image from the database
265
  st.markdown("<p style='text-align: center; color: #94A3B8; margin: 10px 0;'>— OR —</p>", unsafe_allow_html=True)
266
- if st.button("🎲 Pick a Random Test Image from Database", use_container_width=True):
267
  st.session_state.random_img_id = random.randint(0, len(metadata["images"]) - 1)
268
 
269
  # Display selected/uploaded image
@@ -323,53 +322,53 @@ with tab1:
323
  else:
324
  st.markdown(f'<div class="glass-card"><div class="metric-value">N/A</div><div class="metric-label">Upload class unknown</div></div>', unsafe_allow_html=True)
325
 
326
- # Display Results Grid
327
  st.markdown("#### Retrieved Nearest Neighbors")
328
 
329
- # Create dynamic grid columns
330
- grid_cols = st.columns(3)
331
-
332
- for idx, res in enumerate(results):
333
- col = grid_cols[idx % 3]
334
-
335
- with col:
336
- # Determine styling color based on class match if query info exists
337
- is_match = False
338
- border_color = "rgba(255, 255, 255, 0.05)"
339
- bg_color = "rgba(30, 41, 59, 0.7)"
340
- badge_html = f'<span style="background-color: #475569; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; color: white;">{res["class_name"]}</span>'
341
-
342
- if query_info is not None:
343
- is_match = (res["class_name"] == query_info["class_name"])
344
- if is_match:
345
- border_color = "rgba(16, 185, 129, 0.3)"
346
- bg_color = "rgba(6, 78, 59, 0.3)"
347
- badge_html = f'<span style="background-color: #10B981; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; color: white;">{res["class_name"]} (MATCH)</span>'
348
- else:
349
- border_color = "rgba(239, 68, 68, 0.2)"
350
- bg_color = "rgba(127, 29, 29, 0.1)"
351
- badge_html = f'<span style="background-color: #EF4444; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; color: white;">{res["class_name"]}</span>'
352
-
353
- # Custom card container
354
- card_content = f"""
355
- <div style="background: {bg_color}; border: 1px solid {border_color}; border-radius: 8px; padding: 12px; margin-bottom: 12px; text-align: center;">
356
- <div style="color: #38BDF8; font-size: 1.1rem; font-weight: 700; margin-bottom: 8px;">Rank #{res["rank"]}</div>
357
- <div style="margin-bottom: 10px;">{badge_html}</div>
358
- <div style="color: #94A3B8; font-size: 0.9rem; margin-bottom: 4px;">Cosine Similarity:</div>
359
- <div style="color: #E2E8F0; font-size: 1.4rem; font-weight: 700; margin-bottom: 10px;">{res["similarity"] * 100:.2f}%</div>
360
- <div style="color: #64748B; font-size: 0.8rem;">Vector ID: {res["id"]}</div>
361
- </div>
362
- """
363
-
364
- # Render matched image and custom card
365
- if os.path.exists(res["image_path"]):
366
- matched_img = Image.open(res["image_path"])
367
- col.image(matched_img, use_container_width=True)
368
- else:
369
- col.error("Image file missing.")
370
-
371
- col.markdown(card_content, unsafe_allow_html=True)
372
-
373
  else:
374
  st.info("Please upload a custom image or click the button to select a random test image to query the visual search engine!")
375
 
@@ -377,8 +376,8 @@ with tab1:
377
  # TAB 2: Ablation Study Dashboard
378
  # ==========================================================================
379
  with tab2:
380
- st.markdown("### 🧪 Experiment Ablation Study & Color Jitter Findings")
381
- st.markdown("##### Evaluating Natalie's Midterm Pipelines against Mahmoud's Final Jittered Re-runs")
382
 
383
  st.markdown("""
384
  This section presents the results of the complete **Color Jitter Shortcut-Learning Ablation Study** (Experiments 38-42).
@@ -412,12 +411,12 @@ with tab2:
412
  st.markdown(card_html, unsafe_allow_html=True)
413
 
414
  st.markdown("---")
415
- st.markdown("#### Key Project Takeaways")
416
  col1, col2 = st.columns(2)
417
 
418
  with col1:
419
  st.markdown("""
420
- ##### 1. The Shortcut-Learning Problem 🧩
421
  Without Color Jitter, contrastive self-supervised encoders exploit low-level **color histograms** as a shortcut to maximize mutual information, rather than learning general shapes and semantic features. This results in weaker downstream representations, showing a severe performance limit (e.g. baseline Crop+Flip+Blur achieves only **64.49%**).
422
 
423
  ##### 2. The Color Jitter Shield
@@ -433,4 +432,4 @@ with tab2:
433
  Our zero-shot CLIP ViT-B/32 foundation model evaluation sets the academic upper bound at **88.80%**. Our custom-trained SimCLR ResNet-50 achieves **95% of this performance** (**84.30%**) while using **8,000x less training data**!
434
  """)
435
 
436
- st.success("🎉 Weights & Biases Dashboard has archived all 5 experiments complete with training curves, checkpoints, and t-SNE files.")
 
156
  # ==========================================================================
157
  st.set_page_config(
158
  page_title="SimCLR ResNet-50 Visual Search",
 
159
  layout="wide",
160
  initial_sidebar_state="expanded"
161
  )
 
207
  # ==========================================================================
208
  # Sidebar Configuration
209
  # ==========================================================================
210
+ st.sidebar.markdown("### Engine Settings")
211
  top_k_slider = st.sidebar.slider("Number of results (K)", min_value=3, max_value=20, value=6, step=1)
212
 
213
  st.sidebar.markdown("---")
 
223
  """)
224
 
225
  st.sidebar.markdown("---")
226
+ st.sidebar.markdown("### Backend Pipeline")
227
  st.sidebar.markdown("""
228
  * **Inference Engine**: ONNX Runtime CPU
229
  * **Vector Database**: FAISS (IndexFlatIP)
 
262
 
263
  # Method 2: Pick a random image from the database
264
  st.markdown("<p style='text-align: center; color: #94A3B8; margin: 10px 0;'>— OR —</p>", unsafe_allow_html=True)
265
+ if st.button("Pick a Random Test Image from Database", use_container_width=True):
266
  st.session_state.random_img_id = random.randint(0, len(metadata["images"]) - 1)
267
 
268
  # Display selected/uploaded image
 
322
  else:
323
  st.markdown(f'<div class="glass-card"><div class="metric-value">N/A</div><div class="metric-label">Upload class unknown</div></div>', unsafe_allow_html=True)
324
 
325
+ # Display Results Grid (Fixed to prevent layout shift)
326
  st.markdown("#### Retrieved Nearest Neighbors")
327
 
328
+ # Create dynamic rows to prevent shaking/layout shifting
329
+ for i in range(0, len(results), 3):
330
+ cols = st.columns(3)
331
+ for j in range(3):
332
+ if i + j < len(results):
333
+ res = results[i + j]
334
+ with cols[j]:
335
+ # Determine styling color based on class match if query info exists
336
+ is_match = False
337
+ border_color = "rgba(255, 255, 255, 0.05)"
338
+ bg_color = "rgba(30, 41, 59, 0.7)"
339
+ badge_html = f'<span style="background-color: #475569; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; color: white;">{res["class_name"]}</span>'
340
+
341
+ if query_info is not None:
342
+ is_match = (res["class_name"] == query_info["class_name"])
343
+ if is_match:
344
+ border_color = "rgba(16, 185, 129, 0.3)"
345
+ bg_color = "rgba(6, 78, 59, 0.3)"
346
+ badge_html = f'<span style="background-color: #10B981; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; color: white;">{res["class_name"]} (MATCH)</span>'
347
+ else:
348
+ border_color = "rgba(239, 68, 68, 0.2)"
349
+ bg_color = "rgba(127, 29, 29, 0.1)"
350
+ badge_html = f'<span style="background-color: #EF4444; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; color: white;">{res["class_name"]}</span>'
351
+
352
+ # Custom card container
353
+ card_content = f"""
354
+ <div style="background: {bg_color}; border: 1px solid {border_color}; border-radius: 8px; padding: 12px; margin-bottom: 12px; text-align: center;">
355
+ <div style="color: #38BDF8; font-size: 1.1rem; font-weight: 700; margin-bottom: 8px;">Rank #{res["rank"]}</div>
356
+ <div style="margin-bottom: 10px;">{badge_html}</div>
357
+ <div style="color: #94A3B8; font-size: 0.9rem; margin-bottom: 4px;">Cosine Similarity:</div>
358
+ <div style="color: #E2E8F0; font-size: 1.4rem; font-weight: 700; margin-bottom: 10px;">{res["similarity"] * 100:.2f}%</div>
359
+ <div style="color: #64748B; font-size: 0.8rem;">Vector ID: {res["id"]}</div>
360
+ </div>
361
+ """
362
+
363
+ # Render matched image and custom card
364
+ if os.path.exists(res["image_path"]):
365
+ matched_img = Image.open(res["image_path"])
366
+ st.image(matched_img, use_container_width=True)
367
+ else:
368
+ st.error("Image file missing.")
369
+
370
+ st.markdown(card_content, unsafe_allow_html=True)
371
+
372
  else:
373
  st.info("Please upload a custom image or click the button to select a random test image to query the visual search engine!")
374
 
 
376
  # TAB 2: Ablation Study Dashboard
377
  # ==========================================================================
378
  with tab2:
379
+ st.markdown("### Experiment Ablation Study & Color Jitter Findings")
380
+ st.markdown("##### Evaluating Midterm Pipelines against Jittered Re-runs")
381
 
382
  st.markdown("""
383
  This section presents the results of the complete **Color Jitter Shortcut-Learning Ablation Study** (Experiments 38-42).
 
411
  st.markdown(card_html, unsafe_allow_html=True)
412
 
413
  st.markdown("---")
414
+ st.markdown("#### Key Project Takeaways")
415
  col1, col2 = st.columns(2)
416
 
417
  with col1:
418
  st.markdown("""
419
+ ##### 1. The Shortcut-Learning Problem
420
  Without Color Jitter, contrastive self-supervised encoders exploit low-level **color histograms** as a shortcut to maximize mutual information, rather than learning general shapes and semantic features. This results in weaker downstream representations, showing a severe performance limit (e.g. baseline Crop+Flip+Blur achieves only **64.49%**).
421
 
422
  ##### 2. The Color Jitter Shield
 
432
  Our zero-shot CLIP ViT-B/32 foundation model evaluation sets the academic upper bound at **88.80%**. Our custom-trained SimCLR ResNet-50 achieves **95% of this performance** (**84.30%**) while using **8,000x less training data**!
433
  """)
434
 
435
+ st.success("Weights & Biases Dashboard has archived all 5 experiments complete with training curves, checkpoints, and t-SNE files.")