Jahnavibh Claude commited on
Commit
6e578b1
·
1 Parent(s): 4fde660

Fix consistent white background across entire viewport

Browse files

Remove patchy background issue where HuggingFace shows white content area with black margins.
Changed background-color from #fafafa to white for consistent styling.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>

Files changed (1) hide show
  1. app.py +32 -244
app.py CHANGED
@@ -5,18 +5,12 @@ from io import BytesIO
5
  from PIL import Image
6
  import tensorflow as tf
7
  from huggingface_hub import hf_hub_download
8
- import tempfile
9
- import shutil
10
- import os
11
- import subprocess
12
- import re
13
 
14
  # Download the TFLite model and labels from your Hugging Face repository
15
  MODEL_REPO = "JahnaviBhansali/mobilenet-v2-ethos-u55"
16
  MODEL_FILE = "mobilenet_v2_1.0_224_INT8.tflite" # Using original INT8 model for Gradio compatibility
17
  VELA_MODEL_FILE = "mobilenet_v2_1.0_224_INT8_vela.tflite" # Vela-optimized model for Ethos-U55
18
  LABELS_FILE = "labelmappings.txt"
19
- DEFAULT_CONFIG = "u55_eval_with_TA_config_400_and_200_MHz.ini"
20
 
21
  print("Downloading model and labels from Hugging Face...")
22
  model_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
@@ -41,166 +35,6 @@ print(f"Vela-optimized model also available: {VELA_MODEL_FILE}")
41
  # Force rebuild with modern design
42
  print(f"Repository: {MODEL_REPO}")
43
 
44
- # Vela config file is now copied from SR app
45
-
46
- def extract_summary_from_log(log_text):
47
- summary_keys = [
48
- "Accelerator configuration",
49
- "Accelerator clock",
50
- "Total SRAM used",
51
- "Total On-chip Flash used",
52
- "CPU operators",
53
- "NPU operators",
54
- "Batch Inference time"
55
- ]
56
- summary = []
57
- for key in summary_keys:
58
- match = re.search(rf"{re.escape(key)}\s+(.+)", log_text)
59
- if match:
60
- value = match.group(1).strip()
61
- if key == "Batch Inference time":
62
- value = value.split(",")[0].strip()
63
- key = "Inference time"
64
- summary.append((key, value))
65
- return summary
66
-
67
- def run_vela(model_file):
68
- accel = "ethos-u55-128"
69
- optimise = "Size"
70
- mem_mode = "Sram_Only"
71
- sys_config = "Ethos_U55_400MHz_SRAM_3.2_GBs_Flash_0.05_GBs"
72
- tmpdir = tempfile.mkdtemp()
73
- try:
74
- # Use the original uploaded model filename
75
- original_model_name = os.path.basename(model_file)
76
- model_path = os.path.join(tmpdir, original_model_name)
77
- shutil.copy(model_file, model_path)
78
-
79
- config_path = os.path.join(tmpdir, DEFAULT_CONFIG)
80
- shutil.copy(DEFAULT_CONFIG, config_path)
81
-
82
- output_dir = os.path.join(tmpdir, "vela_out")
83
- os.makedirs(output_dir, exist_ok=True)
84
-
85
- cmd = [
86
- "vela",
87
- f"--accelerator-config={accel}",
88
- f"--optimise={optimise}",
89
- f"--config={config_path}",
90
- f"--memory-mode={mem_mode}",
91
- f"--system-config={sys_config}",
92
- model_path,
93
- "--verbose-cycle-estimate",
94
- "--verbose-performance",
95
- f"--output-dir={output_dir}"
96
- ]
97
-
98
- result = subprocess.run(cmd, capture_output=True, text=True, check=True)
99
- vela_stdout = result.stdout
100
-
101
- # Check for unsupported model patterns in logs
102
- unsupported_patterns = [
103
- "Warning: Unsupported TensorFlow Lite semantics",
104
- "Network Tops/s nan Tops/s",
105
- "Neural network macs 0 MACs/batch"
106
- ]
107
- if any(pat in vela_stdout for pat in unsupported_patterns):
108
- summary_html = (
109
- "<div class='sr110-results' style='background:#fff3f3;border-radius:14px;padding:24px 18px 18px 18px;"
110
- "max-width:430px;min-width:320px;width:100%;margin:auto;color:#d32f2f;font-family:sans-serif;"
111
- "font-size:1.1em;text-align:left;font-weight:600;'>"
112
- "This model has unsupported layers and needs investigation based on layers.<br>"
113
- "Please use Vela compiler on your Host Machine for further analysis."
114
- "</div>"
115
- )
116
- # Try to provide per-layer.csv if available for download
117
- per_layer_csv = None
118
- for log_fname in os.listdir(output_dir):
119
- if log_fname.endswith("per-layer.csv"):
120
- per_layer_csv = os.path.join("/tmp", log_fname)
121
- shutil.copy(os.path.join(output_dir, log_fname), per_layer_csv)
122
- break
123
- return summary_html, None, per_layer_csv
124
-
125
- model_filename = os.path.basename(model_file)
126
- if model_filename:
127
- vela_stdout = vela_stdout.replace(
128
- "Network summary for",
129
- f"Network summary for {model_filename} ("
130
- )
131
-
132
- summary_items = extract_summary_from_log(vela_stdout)
133
- # Convert summary_items to dict for easy access
134
- summary_dict = dict(summary_items) if summary_items else {}
135
-
136
- # Build 4 cards for results
137
- def clean_ops(val):
138
- # Remove '=' and leading/trailing spaces
139
- return val.lstrip("= ").strip() if isinstance(val, str) else val
140
-
141
- summary_html = (
142
- "<div class='sr110-results' style='background:#1e1e2f;border-radius:18px;padding:18px 18px 12px 18px;"
143
- "max-width:430px;min-width:320px;width:100%;margin:auto;color:#eee;font-family:sans-serif;'>"
144
- "<h3 class='sr110-title' style='margin-top:0;margin-bottom:12px;font-size:1.35em;color:#00b0ff;text-align:left;'>Estimated Results on SR110</h3>"
145
- "<div style='display:flex;flex-wrap:wrap;gap:10px;justify-content:center;'>"
146
- # Card 1: Accelerator
147
- "<div class='sr110-card' style='flex:1 1 170px;min-width:170px;max-width:180px;background:#23233a;border-radius:12px;padding:10px 10px 8px 10px;'>"
148
- "<div class='sr110-title' style='font-size:1em;font-weight:520;margin-bottom:6px;color:#00b0ff;'>🚀 Accelerator</div>"
149
- f"<div style='margin-bottom:2px;'><span class='sr110-label' style='color:#ccc;'>Configuration:</span> <span class='sr110-value' style='color:#fff;font-weight:500'>{summary_dict.get('Accelerator configuration','-')}</span></div>"
150
- f"<div><span class='sr110-label' style='color:#ccc;'>Accelerator clock:</span> <span class='sr110-value' style='color:#fff;font-weight:500'>{summary_dict.get('Accelerator clock','-')}</span></div>"
151
- "</div>"
152
- # Card 2: Memory Usage
153
- "<div class='sr110-card' style='flex:1 1 170px;min-width:170px;max-width:180px;background:#23233a;border-radius:12px;padding:10px 10px 8px 10px;'>"
154
- "<div class='sr110-title' style='font-size:1em;font-weight:520;margin-bottom:6px;color:#00b0ff;'>💾 Memory Usage</div>"
155
- f"<div style='margin-bottom:2px;'><span class='sr110-label' style='color:#ccc;'>Total SRAM:</span> <span class='sr110-value' style='color:#fff;font-weight:500'>{summary_dict.get('Total SRAM used','-')}</span></div>"
156
- f"<div><span class='sr110-label' style='color:#ccc;'>Total On-chip Flash:</span> <span class='sr110-value' style='color:#fff;font-weight:500'>{summary_dict.get('Total On-chip Flash used','-')}</span></div>"
157
- "</div>"
158
- # Card 3: Operator Distribution
159
- "<div class='sr110-card' style='flex:1 1 170px;min-width:170px;max-width:180px;background:#23233a;border-radius:12px;padding:10px 10px 8px 10px;'>"
160
- "<div class='sr110-title' style='font-size:1em;font-weight:520;margin-bottom:6px;color:#00b0ff;'>📈 Operator Distribution</div>"
161
- f"<div style='margin-bottom:2px;'><span class='sr110-label' style='color:#ccc;'>CPU Operators:</span> <span class='sr110-value' style='color:#fff;font-weight:500'>{clean_ops(summary_dict.get('CPU operators','-'))}</span></div>"
162
- f"<div><span class='sr110-label' style='color:#ccc;'>NPU Operators:</span> <span class='sr110-value' style='color:#fff;font-weight:500'>{clean_ops(summary_dict.get('NPU operators','-'))}</span></div>"
163
- "</div>"
164
- # Card 4: Performance
165
- "<div class='sr110-card' style='flex:1 1 170px;min-width:170px;max-width:180px;background:#23233a;border-radius:12px;padding:10px 10px 8px 10px;'>"
166
- "<div class='sr110-title' style='font-size:1em;font-weight:520;margin-bottom:6px;color:#00b0ff;'>⚡ Performance</div>"
167
- f"<div><span class='sr110-label' style='color:#ccc;'>Inference time:</span> <span class='sr110-value' style='color:#fff;font-weight:500'>{summary_dict.get('Inference time','-')}</span></div>"
168
- "</div>"
169
- "</div></div>"
170
- ) if summary_items else "<div style='color:red'>Summary info not found in log.</div>"
171
-
172
- for fname in os.listdir(output_dir):
173
- if fname.endswith("vela.tflite"):
174
- final_path = os.path.join("/tmp", fname)
175
- shutil.copy(os.path.join(output_dir, fname), final_path)
176
- # Find per-layer.csv file for logs
177
- per_layer_csv = None
178
- for log_fname in os.listdir(output_dir):
179
- if log_fname.endswith("per-layer.csv"):
180
- per_layer_csv = os.path.join("/tmp", log_fname)
181
- shutil.copy(os.path.join(output_dir, log_fname), per_layer_csv)
182
- break
183
- return summary_html, final_path, per_layer_csv
184
-
185
- # If no tflite, still try to return per-layer.csv if present
186
- per_layer_csv = None
187
- for log_fname in os.listdir(output_dir):
188
- if log_fname.endswith("per-layer.csv"):
189
- per_layer_csv = os.path.join("/tmp", log_fname)
190
- shutil.copy(os.path.join(output_dir, log_fname), per_layer_csv)
191
- break
192
- return summary_html, None, per_layer_csv
193
- finally:
194
- shutil.rmtree(tmpdir)
195
-
196
-
197
- # Run Vela analysis on startup and cache results
198
- print("Running Vela analysis on MobileNetV2 model...")
199
- try:
200
- vela_html, compiled_model, per_layer_csv = run_vela(model_path)
201
- except Exception as e:
202
- vela_html = f"<div style='color:red'>Vela analysis failed: {str(e)}</div>"
203
-
204
  def preprocess_image(image):
205
  """
206
  Preprocess image for MobileNetV2 INT8 quantized model.
@@ -300,45 +134,6 @@ def load_example_image(example_path):
300
  return None
301
  return None
302
 
303
- def compile_uploaded_model(model_file):
304
- """Compile uploaded model with Vela and return results"""
305
- if model_file is None:
306
- error_html = (
307
- "<div class='sr110-results' style='background:#fff3f3;border-radius:14px;padding:24px 18px 18px 18px;"
308
- "max-width:430px;min-width:320px;width:100%;margin:auto;color:#d32f2f;font-family:sans-serif;"
309
- "font-size:1.1em;text-align:center;font-weight:600;'>"
310
- "No model file uploaded."
311
- "</div>"
312
- )
313
- return (
314
- error_html,
315
- gr.update(visible=False, value=None),
316
- gr.update(visible=False, value=None)
317
- )
318
-
319
- try:
320
- # Run Vela analysis on uploaded model
321
- results_html, compiled_model_path, per_layer_csv = run_vela(model_file)
322
-
323
- return (
324
- results_html,
325
- gr.update(visible=compiled_model_path is not None, value=compiled_model_path),
326
- gr.update(visible=per_layer_csv is not None, value=per_layer_csv)
327
- )
328
- except Exception as e:
329
- error_html = (
330
- "<div class='sr110-results' style='background:#fff3f3;border-radius:14px;padding:24px 18px 18px 18px;"
331
- "max-width:430px;min-width:320px;width:100%;margin:auto;color:#d32f2f;font-family:sans-serif;"
332
- "font-size:1.1em;text-align:center;font-weight:600;'>"
333
- f"Vela compilation failed: {str(e)}"
334
- "</div>"
335
- )
336
- return (
337
- error_html,
338
- gr.update(visible=False, value=None),
339
- gr.update(visible=False, value=None)
340
- )
341
-
342
  # Create Gradio interface
343
  with gr.Blocks(
344
  theme=gr.themes.Default(),
@@ -347,7 +142,7 @@ with gr.Blocks(
347
  .gradio-container {
348
  max-width: 1200px !important;
349
  margin: auto !important;
350
- background-color: #fafafa !important;
351
  font-family: 'Inter', 'Segoe UI', -apple-system, sans-serif !important;
352
  }
353
  .main-header {
@@ -383,10 +178,7 @@ with gr.Blocks(
383
  font-weight: 600 !important;
384
  font-size: 1.1rem !important;
385
  }
386
- .card-header,
387
- div.card-header,
388
- div.card-header span,
389
- div.card-header * {
390
  color: white !important;
391
  }
392
  .card-content {
@@ -469,36 +261,7 @@ with gr.Blocks(
469
  .card-header * {
470
  color: white !important;
471
  }
472
- /* Override grey colors for SR110 Vela results section - MUST be after prose rules */
473
- .prose .sr110-results,
474
- .prose .sr110-results *,
475
- .prose .sr110-results h3,
476
- .prose .sr110-results div,
477
- .prose .sr110-results span,
478
- .sr110-results,
479
- .sr110-results *,
480
- .sr110-results h3,
481
- .sr110-results div,
482
- .sr110-results span {
483
- color: inherit !important;
484
- }
485
- /* Preserve original colors for dark theme cards with higher specificity */
486
- .prose .sr110-results .sr110-card,
487
- .sr110-results .sr110-card {
488
- background: #23233a !important;
489
- }
490
- .prose .sr110-results .sr110-title,
491
- .sr110-results .sr110-title {
492
- color: #00b0ff !important;
493
- }
494
- .prose .sr110-results .sr110-label,
495
- .sr110-results .sr110-label {
496
- color: #ccc !important;
497
- }
498
- .prose .sr110-results .sr110-value,
499
- .sr110-results .sr110-value {
500
- color: #fff !important;
501
- }
502
  .example-grid {
503
  display: grid !important;
504
  grid-template-columns: 1fr !important;
@@ -579,11 +342,37 @@ with gr.Blocks(
579
  with gr.Row():
580
  example_car = gr.Button("Car", size="sm", elem_classes=["btn-example"])
581
  example_food = gr.Button("Food", size="sm", elem_classes=["btn-example"])
582
-
583
 
584
  with gr.Column(scale=1):
585
- # Display Vela analysis results (dynamic)
586
- vela_results_html = gr.HTML(vela_html)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
587
 
588
  with gr.Group(elem_classes=["card"]):
589
  gr.HTML('<div class="card-header"><span style="color: white; font-weight: 600;">Classification Results</span></div>')
@@ -608,7 +397,6 @@ with gr.Blocks(
608
  example_car.click(lambda: load_example_image("Car"), outputs=input_image)
609
  example_food.click(lambda: load_example_image("Food"), outputs=input_image)
610
 
611
-
612
  # Auto-classify when image is uploaded
613
  input_image.change(
614
  fn=classify_image,
 
5
  from PIL import Image
6
  import tensorflow as tf
7
  from huggingface_hub import hf_hub_download
 
 
 
 
 
8
 
9
  # Download the TFLite model and labels from your Hugging Face repository
10
  MODEL_REPO = "JahnaviBhansali/mobilenet-v2-ethos-u55"
11
  MODEL_FILE = "mobilenet_v2_1.0_224_INT8.tflite" # Using original INT8 model for Gradio compatibility
12
  VELA_MODEL_FILE = "mobilenet_v2_1.0_224_INT8_vela.tflite" # Vela-optimized model for Ethos-U55
13
  LABELS_FILE = "labelmappings.txt"
 
14
 
15
  print("Downloading model and labels from Hugging Face...")
16
  model_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
 
35
  # Force rebuild with modern design
36
  print(f"Repository: {MODEL_REPO}")
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  def preprocess_image(image):
39
  """
40
  Preprocess image for MobileNetV2 INT8 quantized model.
 
134
  return None
135
  return None
136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  # Create Gradio interface
138
  with gr.Blocks(
139
  theme=gr.themes.Default(),
 
142
  .gradio-container {
143
  max-width: 1200px !important;
144
  margin: auto !important;
145
+ background-color: white !important;
146
  font-family: 'Inter', 'Segoe UI', -apple-system, sans-serif !important;
147
  }
148
  .main-header {
 
178
  font-weight: 600 !important;
179
  font-size: 1.1rem !important;
180
  }
181
+ .card-header * {
 
 
 
182
  color: white !important;
183
  }
184
  .card-content {
 
261
  .card-header * {
262
  color: white !important;
263
  }
264
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  .example-grid {
266
  display: grid !important;
267
  grid-template-columns: 1fr !important;
 
342
  with gr.Row():
343
  example_car = gr.Button("Car", size="sm", elem_classes=["btn-example"])
344
  example_food = gr.Button("Food", size="sm", elem_classes=["btn-example"])
 
345
 
346
  with gr.Column(scale=1):
347
+ gr.HTML("""
348
+ <div class="card">
349
+ <div class="card-header">
350
+ <span style="color: white; font-weight: 600;">Model Performance</span>
351
+ </div>
352
+ <div class="card-content">
353
+ <div class="stats-grid">
354
+ <div class="stat-item">
355
+ <div class="stat-label">Performance</div>
356
+ <div class="stat-value">
357
+ 6M cycles/inference<br>
358
+ 15.14ms @ 400MHz<br>
359
+ NPU Coverage: 100%<br>
360
+ ImageNet Top-1: 69.7%
361
+ </div>
362
+ </div>
363
+ <div class="stat-item">
364
+ <div class="stat-label">Memory Usage</div>
365
+ <div class="stat-value">
366
+ SRAM: 353.5 KiB<br>
367
+ Flash: 3.6 MiB<br>
368
+ Model: MobileNetV2<br>
369
+ Input: 224×224×3
370
+ </div>
371
+ </div>
372
+ </div>
373
+ </div>
374
+ </div>
375
+ """)
376
 
377
  with gr.Group(elem_classes=["card"]):
378
  gr.HTML('<div class="card-header"><span style="color: white; font-weight: 600;">Classification Results</span></div>')
 
397
  example_car.click(lambda: load_example_image("Car"), outputs=input_image)
398
  example_food.click(lambda: load_example_image("Food"), outputs=input_image)
399
 
 
400
  # Auto-classify when image is uploaded
401
  input_image.change(
402
  fn=classify_image,