Download presentation.py from MuskAI/LTF-Demo: direct link, hf CLI and curl.
- Browser
- Download file 10.8 kB
-
https://huggingface.co/spaces/MuskAI/LTF-Demo/resolve/main/presentation.py
- Command line
-
hf download hf://spaces/MuskAI/LTF-Demo/presentation.py
-
curl -L -o presentation.py https://huggingface.co/spaces/MuskAI/LTF-Demo/resolve/main/presentation.py
10.8 kB
| """Readable presentation of model scores and quantitative attention weights.""" | |
| from html import escape | |
| import math | |
| import numpy as np | |
| CARD_CSS = """ | |
| .ltf-card{font-family:ui-sans-serif,system-ui,sans-serif;color:#15243c;line-height:1.5} | |
| .ltf-card *{box-sizing:border-box}.ltf-eyebrow{font-size:12px;font-weight:750;letter-spacing:.11em;color:#60748c;text-transform:uppercase} | |
| .ltf-decision{border:1px solid #dce5ef;border-radius:20px;padding:25px;background:#fff;min-height:325px} | |
| .ltf-decision h2{font-size:25px;line-height:1.25;margin:10px 0 20px;letter-spacing:-.03em} | |
| .ltf-score{font-size:58px;line-height:1;font-weight:800;letter-spacing:-.06em;color:var(--accent,#087f85)} | |
| .ltf-score-label{font-size:13px;color:#60748c;margin:8px 0 18px}.ltf-chip{display:inline-block;padding:5px 10px;border-radius:8px;background:#eef3f8;color:#42566e;font-size:12px;font-weight:650;margin-right:5px} | |
| .ltf-mini{display:flex;align-items:center;gap:8px;margin:12px 0;font-size:13px}.ltf-mini b{width:57px}.ltf-mini>span{flex:1;background:#edf1f6;height:7px;border-radius:5px;overflow:hidden}.ltf-mini i{display:block;background:#14888e;height:100%;border-radius:5px}.ltf-mini em{width:45px;text-align:right;font-style:normal;font-variant-numeric:tabular-nums} | |
| .ltf-note{font-size:12px;color:#60748c;margin-top:18px}.ltf-wait{color:#405772;font-size:16px;margin:30px 0 10px} | |
| .ltf-stat-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin:2px 0 20px}.ltf-stat{background:#fff;border:1px solid #dce5ef;padding:17px 20px;border-radius:13px}.ltf-stat strong{display:block;font-size:27px;letter-spacing:-.04em}.ltf-stat span{font-size:12px;color:#60748c} | |
| .ltf-chart{background:#fff;border:1px solid #dce5ef;border-radius:14px;padding:18px 16px}.ltf-chart h3{font-size:17px;margin:0 0 5px}.ltf-chart p{font-size:12px;color:#60748c;margin:0 0 12px}.ltf-scale{display:flex;justify-content:space-between;font-size:11px;color:#52687e;margin-top:5px}.ltf-colorbar{height:11px;border-radius:5px;background:linear-gradient(90deg,#23395d,#6886ab,#b4bfcb,#f7a342,#ee503c);margin-top:12px} | |
| .ltf-callout{padding:11px 13px;background:#edf5f8;border-left:3px solid #14888e;border-radius:6px;font-size:12px;color:#33506b;margin-top:12px} | |
| .ltf-hero{font-family:ui-sans-serif,system-ui,sans-serif;padding:29px 32px;border-radius:20px;background:linear-gradient(110deg,#10243e,#153c51);color:white;margin:0 0 24px}.ltf-card .ltf-hero h1{font-size:31px;margin:10px 0;letter-spacing:-.04em;color:#fff!important}.ltf-card .ltf-hero p{font-size:14px;color:#bed2e3!important;margin:7px 0}.ltf-hero .ltf-eyebrow{color:#75dcd2}.ltf-hero .ltf-chip{background:#ffffff12;color:#d9e9f1;border:1px solid #ffffff18;margin-top:12px} | |
| @media(max-width:650px){.ltf-stat-grid{grid-template-columns:repeat(2,1fr)}.ltf-hero{padding:22px}.ltf-hero h1{font-size:25px}.ltf-decision{min-height:250px}.ltf-score{font-size:47px}} | |
| @media(max-width:760px){ | |
| .gradio-container{padding:14px 12px 35px!important;min-width:0!important;width:100%!important;max-width:100vw!important} | |
| .gradio-container .main{padding:0!important;min-width:0!important;width:100%!important} | |
| .gradio-container .wrap,.gradio-container .contain{min-width:0!important;max-width:100%!important} | |
| .gradio-container .row,.gradio-container .column,.gradio-container .block{min-width:0!important;max-width:100%!important} | |
| } | |
| """ | |
| def card(content): | |
| return f'<style>{CARD_CSS}</style><div class="ltf-card">{content}</div>' | |
| HEADER = card("""<div class="ltf-hero"><div class="ltf-eyebrow">LTF / MODEL EXPLORER</div> | |
| <h1>Image Detection & Attention Analysis</h1><p>Upload an original image to inspect model scores, tile attention, and patch details.</p> | |
| <span class="ltf-chip">CLIP ViT-L/14</span><span class="ltf-chip">CLIP block 24 features</span> | |
| <span class="ltf-chip">224 × 224 tiles</span><span class="ltf-chip">Research demo</span></div>""") | |
| EMPTY_RESULT = card("""<div class="ltf-decision"><div class="ltf-eyebrow">ANALYSIS RESULT</div> | |
| <h2>Ready to analyze</h2><div class="ltf-wait">Upload an image and select Run Analysis, or click a GenImage example.</div> | |
| <p class="ltf-note">The prediction, generated score, and branch comparison will appear here. Attention analysis opens below.</p></div>""") | |
| def result_card(result): | |
| score = float(result["score_fake"]) | |
| generated = result["label"] == 1 | |
| accent = "#d75536" if generated else "#087f85" | |
| verdict = "AI-generated image" if generated else "Real image" | |
| branch = { | |
| "fusion": "Fusion", | |
| "level1": "L1 · Patch-level", | |
| "level2": "L2 · View-level", | |
| }[result["branch"]] | |
| bars = "" | |
| for key, label in (("fusion", "Fusion"), ("level1", "L1"), ("level2", "L2")): | |
| value = result["probabilities"][key]["fake"] | |
| bars += ( | |
| f'<div class="ltf-mini"><b>{label}</b><span><i style="width:{value*100:.3f}%"></i></span>' | |
| f"<em>{value:.3f}</em></div>" | |
| ) | |
| return card(f"""<div class="ltf-decision" style="--accent:{accent};border-top:4px solid {accent}"> | |
| <div class="ltf-eyebrow">Model prediction · {branch}</div><h2>{verdict}</h2> | |
| <div class="ltf-score">{score:.3f}</div><div class="ltf-score-label">Generated score · threshold {result['threshold']:.2f}</div> | |
| {bars}<div class="ltf-note">{result['width']:,} × {result['height']:,} px · {result['views']-1} local tiles | |
| <br>Scores are uncalibrated model outputs, not definitive evidence of image origin.</div></div>""") | |
| def stats_card(state): | |
| if not state: | |
| return "" | |
| attention = state["attention"] | |
| layer = next( | |
| (row[2] for row in state["parameters"] if row[1] == "Feature extraction layer"), | |
| "24", | |
| ) | |
| stats = [ | |
| (str(len(state["boxes"])), "Local tiles + 1 global view"), | |
| (str(attention["l1_heads"].shape[0]), "L1 aggregation heads"), | |
| ( | |
| f"{attention['patch'].shape[1]} × {attention['patch'].shape[2]}", | |
| "Patch grid per tile", | |
| ), | |
| (str(layer), "CLIP feature block"), | |
| ] | |
| return card( | |
| '<div class="ltf-stat-grid">' | |
| + "".join( | |
| f'<div class="ltf-stat"><strong>{escape(value)}</strong><span>{label}</span></div>' | |
| for value, label in stats | |
| ) | |
| + "</div>" | |
| ) | |
| def scale_legend(): | |
| return ( | |
| '<div class="ltf-colorbar"></div><div class="ltf-scale"><span>≤0.25×</span><span>0.5×</span>' | |
| "<span>1× uniform</span><span>2×</span><span>≥4×</span></div>" | |
| ) | |
| def weight_chart(state, selection="mean", level="l1"): | |
| if not state: | |
| return "" | |
| attention = state["attention"] | |
| if level == "l2": | |
| weights = attention["l2"] | |
| labels = ["Global"] + [f"T{i+1}" for i in range(len(weights) - 1)] | |
| title = "L2 View Weights" | |
| else: | |
| weights = ( | |
| attention["l1"] | |
| if selection == "mean" | |
| else attention["l1_heads"][int(selection.split("_")[-1]) - 1] | |
| ) | |
| labels = [f"T{i+1}" for i in range(len(weights))] | |
| title = "L1 Tile Weights · " + ( | |
| "Mean of 8 heads" if selection == "mean" else selection.replace("_", " ") | |
| ) | |
| n = len(weights) | |
| order = np.argsort(-weights, kind="stable")[:10] | |
| maximum = max(float(weights.max()), 1 / n) * 1.12 | |
| width, left, track, row_height = 430, 63, 290, 32 | |
| height = 38 + row_height * len(order) | |
| baseline = left + track * (1 / n) / maximum | |
| svg = [ | |
| f'<svg viewBox="0 0 {width} {height}" role="img" aria-label="{escape(title)}" style="width:100%;font-family:system-ui,sans-serif">', | |
| f'<line x1="{baseline:.2f}" y1="8" x2="{baseline:.2f}" y2="{height-22}" stroke="#8394a8" stroke-dasharray="3 4"/>', | |
| ] | |
| for rank, index in enumerate(order): | |
| y, value = 12 + rank * row_height, float(weights[index]) | |
| fill = ( | |
| "#102e4b" | |
| if labels[index] == "Global" | |
| else ("#078b93" if rank == 0 else "#66aab1") | |
| ) | |
| svg.extend( | |
| [ | |
| f'<text x="0" y="{y+15}" fill="#30465e" font-size="13" font-weight="650">{labels[index]}</text>', | |
| f'<rect x="{left}" y="{y}" width="{track}" height="21" rx="4" fill="#edf2f7"/>', | |
| f'<rect x="{left}" y="{y}" width="{track*value/maximum:.3f}" height="21" rx="4" fill="{fill}">' | |
| f"<title>{labels[index]}: {value:.8f} · {value*n:.4f}× uniform</title></rect>", | |
| f'<text x="{left+track+8}" y="{y+15}" fill="#30465e" font-size="12">{value*100:.2f}%</text>', | |
| ] | |
| ) | |
| svg.append( | |
| f'<text x="{left}" y="{height-4}" fill="#60748c" font-size="10">Dashed: uniform {100/n:.2f}% · Top 10 shown</text></svg>' | |
| ) | |
| ratio = float(weights.max()) * n | |
| message = ( | |
| "Attention is nearly uniform, with no pronounced concentration. The heatmap does not exaggerate small differences." | |
| if float(np.ptp(weights)) * n < 0.10 | |
| else f"The largest weight is {ratio:.2f}× uniform. Rankings show attention, not evidence of forgery." | |
| ) | |
| if level == "l2": | |
| message = ( | |
| f"The global view receives {float(weights[0])*100:.2f}%; the overlay shows local tiles only. " | |
| + message | |
| ) | |
| return card( | |
| f'<div class="ltf-chart"><h3>{title}</h3><p>Normalized attention weights sum to 100% across all items.</p>' | |
| + "".join(svg) | |
| + scale_legend() | |
| + f'<div class="ltf-callout">{message}</div></div>' | |
| ) | |
| def patch_matrix(state, tile_number): | |
| if not state: | |
| return "" | |
| from attention import attention_levels, colors | |
| index = int(tile_number) - 1 | |
| weights = state["attention"]["patch"][index] | |
| palette = colors(attention_levels(weights, weights.size)) | |
| h, w = weights.shape | |
| cells = [] | |
| for y in range(h): | |
| for x in range(w): | |
| color = "#%02x%02x%02x" % tuple(palette[y, x]) | |
| value = float(weights[y, x]) | |
| cells.append( | |
| f'<rect x="{x*20}" y="{y*20}" width="20" height="20" fill="{color}" stroke="#ffffff40" stroke-width=".6">' | |
| f"<title>Row {y+1}, column {x+1} · {value*100:.5f}% · {value*weights.size:.3f}× uniform</title></rect>" | |
| ) | |
| return card( | |
| f'<div class="ltf-chart"><h3>T{index+1} · Patch Attention Matrix</h3><p>Hover to inspect exact weights. Each cell corresponds to 14 × 14 input pixels.</p>' | |
| f'<svg viewBox="0 0 {w*20} {h*20}" role="img" aria-label="Patch attention matrix" style="width:100%;max-height:420px">' | |
| + "".join(cells) | |
| + "</svg>" | |
| + scale_legend() | |
| + '<div class="ltf-callout">Shared scale relative to uniform attention: gray is near uniform, blue is lower, and orange-red is higher.</div></div>' | |
| ) | |