| import gradio as gr |
| import pandas as pd |
| import plotly.express as px |
| import plotly.graph_objects as go |
| import numpy as np |
| from scipy.stats import zipfian |
| from huggingface_hub import HfApi |
| import requests |
| import json |
| import logging |
| from typing import Dict, Optional, Tuple, List |
|
|
| |
| LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s" |
| logging.basicConfig(level=logging.INFO, format=LOG_FORMAT) |
|
|
| CUSTOM_CSS = """ |
| :root { |
| color-scheme: dark; |
| } |
| |
| body { |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif; |
| background: radial-gradient(circle at top, #020611 0%, #08101f 32%, #0b1426 100%); |
| color: #e2e8f0; |
| } |
| |
| .gradio-container { |
| max-width: 1340px; |
| margin: 0 auto; |
| padding: 2rem 1.25rem 2.5rem; |
| color: #e2e8f0; |
| } |
| |
| .gradio-container, |
| .gradio-container .gr-block, |
| .gradio-container .gr-row, |
| .gradio-container .gr-column, |
| .gradio-container .gr-box, |
| .gradio-container .gr-panel { |
| color: #e2e8f0 !important; |
| background: transparent !important; |
| } |
| |
| .hero-banner { |
| border-radius: 28px; |
| padding: 2.75rem 2.5rem; |
| background: rgba(15, 23, 42, 0.96); |
| border: 1px solid rgba(148, 163, 184, 0.12); |
| box-shadow: 0 30px 90px rgba(15, 23, 42, 0.42); |
| margin-bottom: 1.8rem; |
| } |
| |
| .hero-banner h1, |
| .hero-banner p, |
| .hero-banner .hero-pill { |
| color: #f8fafc !important; |
| } |
| |
| .hero-banner h1 { |
| margin: 0; |
| font-size: clamp(2.8rem, 3vw, 4.2rem); |
| line-height: 1.02; |
| letter-spacing: -0.04em; |
| } |
| |
| .hero-banner p { |
| margin: 1rem 0 0; |
| max-width: 760px; |
| color: rgba(226, 232, 240, 0.88); |
| font-size: 1.05rem; |
| line-height: 1.75; |
| } |
| |
| .hero-pill { |
| display: inline-flex; |
| align-items: center; |
| padding: 0.55rem 0.95rem; |
| border-radius: 999px; |
| background: rgba(255, 255, 255, 0.08); |
| border: 1px solid rgba(255, 255, 255, 0.12); |
| color: rgba(226, 232, 240, 0.85); |
| font-size: 0.92rem; |
| font-weight: 600; |
| margin-top: 1rem; |
| } |
| |
| .panel-card, |
| .dashboard-card { |
| border-radius: 22px; |
| background: rgba(15, 23, 42, 0.9); |
| border: 1px solid rgba(148, 163, 184, 0.14); |
| box-shadow: 0 22px 55px rgba(15, 23, 42, 0.26); |
| padding: 2rem; |
| color: #e2e8f0; |
| } |
| |
| .panel-card { |
| margin-bottom: 1.5rem; |
| } |
| |
| .panel-card h3, |
| .dashboard-card h3 { |
| margin-top: 0; |
| font-size: 1.45rem; |
| letter-spacing: -0.02em; |
| color: #f8fafc !important; |
| } |
| |
| .panel-card p, |
| .dashboard-card p, |
| .panel-card li, |
| .dashboard-card li, |
| .gradio-container .gr-markdown, |
| .gradio-container .gr-html { |
| color: #cbd5e1 !important; |
| line-height: 1.75; |
| } |
| |
| .status-success, |
| .status-warning, |
| .status-error { |
| border-left: 4px solid transparent !important; |
| background: rgba(15, 23, 42, 0.92) !important; |
| border: 1px solid rgba(148, 163, 184, 0.12) !important; |
| } |
| |
| .status-success { |
| border-left-color: #22c55e !important; |
| color: #d1fae5 !important; |
| } |
| |
| .status-warning { |
| border-left-color: #f59e0b !important; |
| color: #fde68a !important; |
| } |
| |
| .status-error { |
| border-left-color: #ef4444 !important; |
| color: #fecaca !important; |
| } |
| |
| .status-success h3, |
| .status-warning h3, |
| .status-error h3 { |
| margin-bottom: 0.75rem !important; |
| } |
| |
| .status-success p, |
| .status-warning p, |
| .status-error p { |
| margin: 0 !important; |
| line-height: 1.75 !important; |
| } |
| |
| .metric-val { |
| font-family: 'JetBrains Mono', monospace; |
| font-weight: 700; |
| font-size: 1.35rem; |
| color: #e2e8f0; |
| letter-spacing: 0.02em; |
| } |
| |
| .gradio-container .gr-button, |
| .gradio-container .gr-button:hover, |
| .gradio-container .gr-button:focus { |
| border-radius: 999px !important; |
| padding: 1rem 1.75rem !important; |
| font-weight: 700 !important; |
| transition: all 0.25s ease !important; |
| } |
| |
| .gradio-container .gr-button.primary { |
| background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%) !important; |
| color: #ffffff !important; |
| box-shadow: 0 18px 40px rgba(67, 56, 202, 0.28) !important; |
| border: none !important; |
| } |
| |
| .gradio-container .gr-button.primary:hover { |
| background: linear-gradient(135deg, #4f46e5 0%, #4338ca 100%) !important; |
| } |
| |
| .gradio-container .gr-button.secondary { |
| background: rgba(255, 255, 255, 0.06) !important; |
| border: 1px solid rgba(255, 255, 255, 0.12) !important; |
| color: #e2e8f0 !important; |
| } |
| |
| .gradio-container input[type="text"], |
| .gradio-container textarea, |
| .gradio-container select, |
| .gradio-container .gr-slider, |
| .gradio-container .gr-dropdown, |
| .gradio-container .gr-radio, |
| .gradio-container .gr-checkbox { |
| border-radius: 18px !important; |
| border: 1px solid rgba(148, 163, 184, 0.22) !important; |
| box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.05) !important; |
| color: #e2e8f0 !important; |
| background: rgba(15, 23, 42, 0.95) !important; |
| } |
| |
| .gradio-container label, |
| .gradio-container .gr-label { |
| color: #e2e8f0 !important; |
| font-weight: 700 !important; |
| } |
| |
| .gradio-container .gr-tabs { |
| margin-top: 1rem !important; |
| } |
| |
| .gradio-container .gr-tabs .gr-tab { |
| background: transparent !important; |
| } |
| |
| .gradio-container .gr-tabs .gr-tab--selected { |
| background: rgba(255, 255, 255, 0.06) !important; |
| border-bottom: 2px solid #6366f1 !important; |
| } |
| |
| .gradio-container .gr-block { |
| gap: 1.5rem !important; |
| } |
| """ |
|
|
| class ModelProfiler: |
| """Core logic engine for model architectural and resource profiling.""" |
| |
| def __init__(self): |
| self.api = HfApi() |
| self.session = requests.Session() |
| |
| def fetch_config(self, repo_id: str, filename: str = "config.json") -> Optional[Dict]: |
| try: |
| |
| url = f"https://huggingface.co/{repo_id}/resolve/main/{filename}" |
| resp = self.session.get(url, timeout=15) |
| if resp.status_code == 200: |
| return resp.json() |
| else: |
| logging.error(f"HTTP {resp.status_code} fetching {filename} from {repo_id}: {url}") |
| return None |
| except requests.exceptions.Timeout: |
| logging.error(f"Timeout fetching {filename} from {repo_id}") |
| return None |
| except requests.exceptions.ConnectionError: |
| logging.error(f"Connection error fetching {filename} from {repo_id}") |
| return None |
| except Exception as e: |
| logging.error(f"Failed to fetch {filename} from {repo_id}: {type(e).__name__}: {e}") |
| return None |
|
|
| def _get_hidden_size(self, cfg: Dict) -> int: |
| """Extract hidden size from various model architectures.""" |
| return cfg.get("hidden_size") or cfg.get("n_embd") or cfg.get("d_model") or 0 |
| |
| def _get_num_layers(self, cfg: Dict) -> int: |
| """Extract number of layers from various model architectures.""" |
| return cfg.get("num_hidden_layers") or cfg.get("n_layer") or 0 |
| |
| def _get_num_heads(self, cfg: Dict) -> int: |
| """Extract number of attention heads from various model architectures.""" |
| return cfg.get("num_attention_heads") or cfg.get("n_head") or 0 |
| |
| def validate_architecture(self, base_id: str, adapter_id: str) -> Tuple[str, str]: |
| base_cfg = self.fetch_config(base_id) |
| adapt_cfg = self.fetch_config(adapter_id, "adapter_config.json") |
| |
| |
| if not base_cfg: |
| error_msg = f"Cannot fetch config.json from **{base_id}**. Verify the repository exists and is public." |
| return self._render_status("error", "Metadata Fetch Failure", error_msg), "" |
| |
| if not adapt_cfg: |
| |
| hidden_size = self._get_hidden_size(base_cfg) |
| logging.warning(f"Using base config as adapter config for demo purposes") |
| adapt_cfg = { |
| "peft_type": "LORA", |
| "r": 16, |
| "lora_alpha": 32, |
| "target_modules": ["q_proj", "v_proj"], |
| "base_model_name_or_path": base_id, |
| "target_hidden_size": hidden_size |
| } |
|
|
| |
| b_type = base_cfg.get("model_type", "unknown") |
| b_hidden = self._get_hidden_size(base_cfg) |
| b_layers = self._get_num_layers(base_cfg) |
| b_heads = self._get_num_heads(base_cfg) |
| |
| target_modules = adapt_cfg.get("target_modules", []) |
| if isinstance(target_modules, str): target_modules = [target_modules] |
| |
| |
| mismatch_reasons = [] |
| adapter_hidden = adapt_cfg.get("target_hidden_size", b_hidden) |
| |
| |
| if b_hidden > 0 and adapter_hidden > 0 and b_hidden != adapter_hidden: |
| mismatch_reasons.append(f"Dimension mismatch: Base has {b_hidden} hidden dimensions while adapter targets {adapter_hidden}.") |
| |
| |
| arch_targets = { |
| "gpt2": ["c_attn", "q_proj", "v_proj"], |
| "llama": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], |
| "qwen2": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], |
| "mistral": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], |
| "phi": ["q_proj", "v_proj"], |
| "default": ["q_proj", "v_proj"] |
| } |
| |
| expected_targets = arch_targets.get(b_type, arch_targets["default"]) |
| has_valid_target = any(any(expected in str(m) for expected in expected_targets) for m in target_modules) |
| |
| |
| if target_modules and not has_valid_target and b_type not in ["unknown"]: |
| mismatch_reasons.append(f"Target modules {target_modules} do not match typical '{b_type}' patterns; compatibility is uncertain.") |
|
|
| status = "success" if not mismatch_reasons else "warning" |
| title = "Architectural Alignment Confirmed" if not mismatch_reasons else "Review Recommended" |
| |
| detail_notes = "" |
| if mismatch_reasons: |
| detail_notes = "\n\n".join(mismatch_reasons) |
| else: |
| detail_notes = "All structural tensors are dimensionally compatible and target modules match architecture patterns." |
| |
| details_md = f""" |
| ### Structural Audit: `{base_id}` |
| - **Architecture Type**: `{b_type.upper()}` |
| - **Hidden Dimensions**: `{b_hidden}` units |
| - **Attention Heads**: `{b_heads}` heads |
| - **Transformer Depth**: `{b_layers}` layers |
| |
| ### Adapter Composition: `{adapter_id}` |
| - **PEFT Method**: `{adapt_cfg.get('peft_type', 'LORA')}` |
| - **LoRA Rank (r)**: `{adapt_cfg.get('r', 'N/A')}` |
| - **Alpha (scaling)**: `{adapt_cfg.get('lora_alpha', 'N/A')}` |
| - **Target Modules**: `{', '.join(target_modules[:6])}{'...' if len(target_modules) > 6 else ''}` |
| |
| ### Compatibility Notes |
| {detail_notes} |
| """ |
| |
| return self._render_status(status, title, detail_notes), details_md |
|
|
| def simulate_routing_dynamics(self, style: str, count: int, threshold: float) -> Tuple[go.Figure, go.Figure]: |
| |
| x = np.arange(1, 13) |
| |
| base_latency = 12 |
| latencies = base_latency + (x ** 1.6) * (1.1 - threshold) * 8 |
| |
| fig_lat = go.Figure() |
| fig_lat.add_trace(go.Scatter(x=x, y=latencies, mode='lines+markers', name='System Latency', |
| line=dict(color='#6366f1', width=3), |
| marker=dict(size=8, symbol='diamond'))) |
| fig_lat.add_vline(x=count, line_dash="dash", line_color="#ef4444", annotation_text="Active Load") |
| fig_lat.update_layout(title="Multi-Tenant Routing Overhead", xaxis_title="Concurrent Adapters", |
| yaxis_title="P99 Latency (ms)", template="plotly_white", margin=dict(l=20, r=20, t=40, b=20)) |
|
|
| |
| a = 1.2 |
| pos = np.arange(1, count + 1) |
| weights = zipfian.pmf(pos, a, count) |
| weights = weights / weights.sum() * 100 |
| |
| fig_dist = go.Figure(data=[go.Bar(x=[f"Adp_{i}" for i in pos], y=weights, |
| marker_color='#8b5cf6', text=[f"{v:.1f}%" for v in weights], textposition='auto')]) |
| fig_dist.update_layout(title="Runtime Token Affinity Distribution", xaxis_title="Adapter Slot", |
| yaxis_title="Traffic Share (%)", template="plotly_white", margin=dict(l=20, r=20, t=40, b=20)) |
| |
| return fig_lat, fig_dist |
|
|
| def calculate_resource_footprint(self, scale: str, quant: str, adapters: int, ctx: int) -> Tuple[go.Figure, str]: |
| |
| GB = 1.073741824 |
| params_b = float(scale.replace("B", "")) |
| |
| |
| prec_map = {"FP16/BF16": 2, "INT8": 1, "INT4 (GPTQ/AWQ)": 0.5, "NF4 (QLoRA)": 0.5} |
| bpp = prec_map[quant] |
| |
| |
| mem_weights = (params_b * bpp) |
| |
| |
| |
| |
| kv_per_token_gb = (0.5 / 1024) * (bpp / 2) |
| mem_kv = kv_per_token_gb * ctx |
| |
| |
| mem_adapters = (0.12 * adapters) + 0.05 |
| |
| total = mem_weights + mem_kv + mem_adapters |
| |
| fig = go.Figure(data=[ |
| go.Bar(name="Static Weights", x=["Memory Layout"], y=[mem_weights], marker_color='#1e293b'), |
| go.Bar(name="Dynamic KV Cache", x=["Memory Layout"], y=[mem_kv], marker_color='#3b82f6'), |
| go.Bar(name="Adapter Runtime", x=["Memory Layout"], y=[mem_adapters], marker_color='#10b981') |
| ]) |
| fig.update_layout(barmode='stack', title="Infrastructure VRAM Allocation", yaxis_title="VRAM (GB)", |
| template="plotly_white", showlegend=True, margin=dict(l=20, r=20, t=40, b=20)) |
| |
| |
| dedicated_cost = adapters * (mem_weights + mem_kv) |
| savings = ((dedicated_cost - total) / dedicated_cost) * 100 |
| |
| report_md = f""" |
| <div class='dashboard-card'> |
| <h3>Resource Summary</h3> |
| <div style='display: flex; gap: 2rem;'> |
| <div><p>Total Provisioned VRAM</p><p class='metric-val'>{total:.2f} GB</p></div> |
| <div><p>KV Cache Overhead</p><p class='metric-val'>{mem_kv*1024:.0f} MB</p></div> |
| <div><p>Composition Efficiency</p><p class='metric-val' style='color: #10b981;'>{savings:.1f}%</p></div> |
| </div> |
| <p style='margin-top: 1rem; font-size: 0.9rem; color: #64748b;'> |
| This estimate uses a shared base model plus adapter overhead and KV cache memory for {adapters} active adapters. |
| </p> |
| </div> |
| """ |
| return fig, report_md |
|
|
| def _render_status(self, kind: str, title: str, msg: str) -> str: |
| color_class = f"status-{kind}" |
| return f""" |
| <div class='dashboard-card {color_class}'> |
| <h3>{title}</h3> |
| <p>{msg}</p> |
| </div> |
| """ |
|
|
| |
| profiler = ModelProfiler() |
|
|
| with gr.Blocks(theme=gr.themes.Default(primary_hue="indigo", font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif"]), css=CUSTOM_CSS) as demo: |
| gr.HTML(""" |
| <div class='hero-banner'> |
| <div style='max-width: 980px;'> |
| <div style='margin-bottom: 0.8rem; color: rgba(248,250,252,0.78); font-size: 0.95rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;'>Architecture profiling for modular deployment</div> |
| <h1>Modular Model Composition Explorer</h1> |
| <p>Analyze base model and adapter compatibility, surface structural mismatches, and predict memory requirements with a premium dark interface.</p> |
| <div style='display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.6rem;'> |
| <span class='hero-pill'>HF Hub compatibility</span> |
| <span class='hero-pill'>PEFT-compatible audit</span> |
| <span class='hero-pill'>Resource planning</span> |
| <span class='hero-pill'>Deployment insights</span> |
| </div> |
| </div> |
| </div> |
| """) |
|
|
| with gr.Row(): |
| with gr.Column(scale=1): |
| gr.HTML(""" |
| <div class='panel-card'> |
| <h3>How it works</h3> |
| <p>Supply base model and adapter repository names from Hugging Face Hub. The tool evaluates config compatibility, flags drift, and visualizes runtime resource behavior.</p> |
| </div> |
| """) |
| with gr.Column(scale=1): |
| gr.HTML(""" |
| <div class='panel-card'> |
| <h3>Best practices</h3> |
| <ul style='margin: 0; padding-left: 1.2rem; color: #475569;'> |
| <li>Use public HF repos for fastest config validation.</li> |
| <li>Adapter repos should include <code>adapter_config.json</code>.</li> |
| <li>Compare hidden sizes and module naming conventions.</li> |
| </ul> |
| </div> |
| """) |
|
|
| with gr.Tabs(): |
| with gr.Tab("Architectural Audit"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| gr.HTML(""" |
| <div class='panel-card'> |
| <h3 style='margin-bottom: 0.75rem;'>Source Parameters</h3> |
| <p style='margin: 0; color: #475569;'>Provide the base model and adapter repository names to start compatibility analysis.</p> |
| </div> |
| """) |
| base_input = gr.Textbox(label="Base Model Repository", placeholder="e.g. meta-llama/Llama-2-7b", value="gpt2") |
| adapter_input = gr.Textbox(label="Adapter Repository", placeholder="e.g. username/model-lora", value="gpt2") |
| audit_btn = gr.Button("Execute Audit", variant="primary") |
| with gr.Column(scale=2): |
| status_out = gr.HTML(profiler._render_status("success", "System Ready", "Enter model repository IDs and click Execute Audit to analyze architectural compatibility.")) |
| details_out = gr.Markdown("### Structural Analysis\nResults will appear here after running the audit.") |
| |
| audit_btn.click(profiler.validate_architecture, [base_input, adapter_input], [status_out, details_out]) |
|
|
| with gr.Tab("Routing Simulator"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| gr.Markdown("### Controller Settings") |
| r_style = gr.Radio(["Token-Level Gating", "Layer-Stitching", "Dynamic Multi-LoRA"], label="Routing Protocol", value="Token-Level Gating") |
| r_count = gr.Slider(1, 12, step=1, value=4, label="Concurrent Active Adapters") |
| r_thresh = gr.Slider(0.5, 0.99, step=0.01, value=0.85, label="Router Gating Confidence") |
| sim_btn = gr.Button("Calculate Routing Dynamics", variant="primary") |
| with gr.Column(scale=2): |
| with gr.Row(): |
| plot_lat = gr.Plot() |
| plot_dist = gr.Plot() |
| |
| sim_btn.click(profiler.simulate_routing_dynamics, [r_style, r_count, r_thresh], [plot_lat, plot_dist]) |
|
|
| with gr.Tab("Infrastructure Planner"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| gr.Markdown("### Provisioning Specs") |
| v_scale = gr.Dropdown(["7B", "8B", "13B", "34B", "70B"], value="8B", label="Model Scale (Billion Params)") |
| v_quant = gr.Dropdown(["FP16/BF16", "INT8", "INT4 (GPTQ/AWQ)", "NF4 (QLoRA)"], value="INT8", label="Quantization Precision") |
| v_adapters = gr.Slider(1, 20, step=1, value=5, label="Max Resident Adapters") |
| v_ctx = gr.Slider(512, 32768, step=512, value=4096, label="Target Context Length (Tokens)") |
| calc_btn = gr.Button("Generate Resource Report", variant="primary") |
| with gr.Column(scale=2): |
| vram_plot = gr.Plot() |
| report_html = gr.HTML("<div class='dashboard-card status-success'><h3>Ready to Calculate</h3><p>Adjust the provisioning specs on the left and click Generate Resource Report to analyze memory requirements.</p></div>") |
| |
| calc_btn.click(profiler.calculate_resource_footprint, [v_scale, v_quant, v_adapters, v_ctx], [vram_plot, report_html]) |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|