test / app.py
pluto2060's picture
AI Paper Lab: ICML 2026 8-tab interactive demo
7a14d3f
Raw History Blame Contribute Delete
23.5 kB
"""
AI Paper Lab โ€” ICML 2026 ๋…ผ๋ฌธ ์ฒดํ—˜ Space
pluto2060/ai-paper-lab
"""
import gradio as gr
import numpy as np
import plotly.graph_objects as go
import spaces
import torch
# โ”€โ”€ Tab 1: Grok Grokking โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def grokking_simulation(n_train: int, weight_decay: float, n_epochs: int):
"""Simulate grokking in ridge regression โ€” memorization then generalization."""
np.random.seed(42)
# Ground truth weight vector
w_true = np.array([1.0, -1.5, 0.8])
# Training data
X_train = np.random.randn(n_train, 3)
y_train = X_train @ w_true + np.random.randn(n_train) * 0.1
# Test data (larger)
X_test = np.random.randn(200, 3)
y_test = X_test @ w_true + np.random.randn(200) * 0.1
train_loss, test_loss, weight_norm = [], [], []
epochs = np.arange(1, n_epochs + 1)
# Gradient descent simulation
w = np.zeros(3)
lr = 0.01
for ep in epochs:
grad = -2 * X_train.T @ (y_train - X_train @ w) / n_train + 2 * weight_decay * w
w = w - lr * grad
tr = np.mean((y_train - X_train @ w) ** 2)
te = np.mean((y_test - X_test @ w) ** 2)
train_loss.append(tr)
test_loss.append(te)
weight_norm.append(np.linalg.norm(w))
fig = go.Figure()
fig.add_trace(go.Scatter(x=epochs, y=train_loss, name="ํ›ˆ๋ จ ์†์‹ค", line=dict(color="#2196F3")))
fig.add_trace(go.Scatter(x=epochs, y=test_loss, name="ํ…Œ์ŠคํŠธ ์†์‹ค", line=dict(color="#F44336")))
fig.add_trace(go.Scatter(x=epochs, y=weight_norm, name="๊ฐ€์ค‘์น˜ ๋…ธ๋ฆ„", line=dict(color="#4CAF50", dash="dot")))
# Mark grokking transition: first epoch where test_loss < 0.5
grok_ep = next((i + 1 for i, v in enumerate(test_loss) if v < 0.5), None)
if grok_ep:
fig.add_vline(x=grok_ep, line_dash="dash", line_color="orange",
annotation_text=f"๊ทธ๋กœํ‚น ๋ฐœ์ƒ! (epoch {grok_ep})", annotation_position="top right")
fig.update_layout(
title="To Grok Grokking โ€” ๋ฆฟ์ง€ ํšŒ๊ท€์˜ ์ง€์—ฐ ์ผ๋ฐ˜ํ™” ์‹œ๋ฎฌ๋ ˆ์ด์…˜",
xaxis_title="Epoch", yaxis_title="๊ฐ’",
template="plotly_dark", height=450
)
return fig
def build_grokking_tab():
with gr.Column():
gr.Markdown("""
## ๐Ÿ“„ To Grok Grokking: Provable Grokking in Ridge Regression
**ICML 2026 Honorable Mention** | Xu et al.
> AI ๋ชจ๋ธ์ด ์ฒ˜์Œ์—๋Š” ํ›ˆ๋ จ ๋ฐ์ดํ„ฐ๋ฅผ **์•”๊ธฐ**ํ•˜๋‹ค๊ฐ€ ์–ด๋А ์ˆœ๊ฐ„ ๊ฐ‘์ž๊ธฐ **์ง„์งœ ์›๋ฆฌ๋ฅผ ์ผ๋ฐ˜ํ™”**ํ•˜๋Š” ํ˜„์ƒ์„ ์ˆ˜ํ•™์ ์œผ๋กœ ์ฆ๋ช….
> ๋ฆฟ์ง€ ํšŒ๊ท€๋ผ๋Š” ๋‹จ์ˆœ ๋ชจ๋ธ๋กœ ์ด "๊ทธ๋กœํ‚น" ํ˜„์ƒ์ด ์™œ ๋ฐœ์ƒํ•˜๋Š”์ง€ ํ•ด์„์ ์œผ๋กœ ๊ทœ๋ช….
**์ฒดํ—˜**: ์Šฌ๋ผ์ด๋”๋ฅผ ์กฐ์ ˆํ•ด ๊ทธ๋กœํ‚น์ด ์–ธ์ œ ๋ฐœ์ƒํ•˜๋Š”์ง€ ์ง์ ‘ ํ™•์ธํ•˜์„ธ์š”.
- `ํ›ˆ๋ จ ๋ฐ์ดํ„ฐ ์ˆ˜` โ†“ โ†’ ์•”๊ธฐ ๊ธฐ๊ฐ„ ๋” ๊ธธ์–ด์ง
- `์ •๊ทœํ™” ๊ฐ•๋„` โ†‘ โ†’ ์ผ๋ฐ˜ํ™” ์ด‰์ง„ (๊ทธ๋กœํ‚น ๊ฐ€์†)
""")
with gr.Row():
n_train = gr.Slider(5, 50, value=15, step=5, label="ํ›ˆ๋ จ ๋ฐ์ดํ„ฐ ์ˆ˜ (N)")
wd = gr.Slider(0.001, 0.1, value=0.01, step=0.001, label="์ •๊ทœํ™” ๊ฐ•๋„ (weight_decay)")
n_ep = gr.Slider(100, 2000, value=500, step=100, label="ํ•™์Šต epoch ์ˆ˜")
btn = gr.Button("์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์‹คํ–‰", variant="primary")
plot = gr.Plot()
btn.click(grokking_simulation, inputs=[n_train, wd, n_ep], outputs=plot)
# โ”€โ”€ Tab 2: Quantum vs Classical โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def quantum_classical_viz(n_max: int):
ns = np.arange(1, n_max + 1)
classical = ns ** 2 # O(nยฒ) โ€” typical classical linear system solver
quantum_inspired = ns * np.log(ns) ** 2 # quantum-inspired classical (best known)
quantum = np.log(ns) ** 2 # quantum algorithm (polylog)
fig = go.Figure()
fig.add_trace(go.Scatter(x=ns, y=classical, name="๊ณ ์ „ ์•Œ๊ณ ๋ฆฌ์ฆ˜ O(nยฒ)", line=dict(color="#F44336")))
fig.add_trace(go.Scatter(x=ns, y=quantum_inspired, name="์–‘์ž์˜๊ฐ ๊ณ ์ „ O(nยทlogยฒn)", line=dict(color="#FF9800")))
fig.add_trace(go.Scatter(x=ns, y=quantum, name="์–‘์ž ์•Œ๊ณ ๋ฆฌ์ฆ˜ O(logยฒn)", line=dict(color="#4CAF50")))
fig.update_layout(
title=f"์–‘์ž vs ๊ณ ์ „ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ณต์žก๋„ ๋น„๊ต (N=1~{n_max})",
xaxis_title="๋ฌธ์ œ ํฌ๊ธฐ N", yaxis_title="๊ณ„์‚ฐ ๋‹จ๊ณ„ ์ˆ˜ (์ƒ๋Œ€์ )",
template="plotly_dark", height=450,
yaxis_type="log"
)
return fig
def build_quantum_tab():
with gr.Column():
gr.Markdown("""
## ๐Ÿ“„ An Exponential Separation Between Quantum and Classical Algorithms
**ICML 2026 Spotlight** | Grรธnlund & Larsen (Aarhus Univ.)
> ์„ ํ˜• ๋ฐฉ์ •์‹ ํ’€๊ธฐ์—์„œ ์–‘์ž ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๊ณ ์ „ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋ณด๋‹ค **์ง€์ˆ˜ํ•จ์ˆ˜์ ์œผ๋กœ ๋น ๋ฆ„**์„ ์ˆ˜ํ•™์ ์œผ๋กœ ์ฆ๋ช….
> "์ง€์ˆ˜ ๋ถ„๋ฆฌ"๋ž€: ๊ณ ์ „ ์ปดํ“จํ„ฐ๊ฐ€ ๋ฐฑ๋งŒ ๋…„ ๊ฑธ๋ฆด ๊ณ„์‚ฐ์„ ์–‘์ž ์ปดํ“จํ„ฐ๊ฐ€ ๋‹จ ๋ช‡ ์ดˆ์— ์ฒ˜๋ฆฌ.
**์ฒดํ—˜**: N ์Šฌ๋ผ์ด๋”๋ฅผ ๋Š˜๋ฆด์ˆ˜๋ก ์„ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ฒฉ์ฐจ๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋ฒŒ์–ด์ง€๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.
""")
n_max = gr.Slider(10, 500, value=100, step=10, label="๋ฌธ์ œ ํฌ๊ธฐ N (์ตœ๋Œ€)")
btn = gr.Button("๋น„๊ต ์ฐจํŠธ ์ƒ์„ฑ", variant="primary")
plot = gr.Plot()
btn.click(quantum_classical_viz, inputs=[n_max], outputs=plot)
# โ”€โ”€ Tab 3: M+Adam vs Adam โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def madam_simulation(lr: float, beta1: float, noise_scale: float, n_steps: int):
np.random.seed(0)
# Simple 2D quadratic loss: f(x,y) = xยฒ + 10yยฒ
def loss_fn(w): return w[0] ** 2 + 10 * w[1] ** 2
def grad_fn(w): return np.array([2 * w[0], 20 * w[1]])
def simulate(optimizer="adam"):
w = np.array([3.0, 2.0])
m, v = np.zeros(2), np.zeros(2)
beta2 = 0.999
eps = 1e-8
losses = []
for t in range(1, n_steps + 1):
g = grad_fn(w) + np.random.randn(2) * noise_scale
if optimizer == "adam":
m = beta1 * m + (1 - beta1) * g
v = beta2 * v + (1 - beta2) * g ** 2
m_hat = m / (1 - beta1 ** t)
v_hat = v / (1 - beta2 ** t)
w -= lr * m_hat / (np.sqrt(v_hat) + eps)
else: # M+Adam: split mantissa/exponent optimization
# Mantissa part: high-precision momentum
m = beta1 * m + (1 - beta1) * g
# Exponent part: sign-based update (low precision)
exp_update = np.sign(g)
v = beta2 * v + (1 - beta2) * g ** 2
m_hat = m / (1 - beta1 ** t)
v_hat = v / (1 - beta2 ** t)
# Blend: 70% mantissa, 30% exponent
update = 0.7 * m_hat / (np.sqrt(v_hat) + eps) + 0.3 * lr * exp_update
w -= lr * update
losses.append(loss_fn(w))
return losses
steps = np.arange(1, n_steps + 1)
adam_losses = simulate("adam")
madam_losses = simulate("madam")
fig = go.Figure()
fig.add_trace(go.Scatter(x=steps, y=adam_losses, name="Adam (ํ‘œ์ค€)", line=dict(color="#2196F3")))
fig.add_trace(go.Scatter(x=steps, y=madam_losses, name="M+Adam (๊ฐ€์ˆ˜ยท์ง€์ˆ˜ ๋ถ„๋ฆฌ)", line=dict(color="#FF5722")))
fig.update_layout(
title="M+Adam vs Adam โ€” ์†์‹ค ๊ณก์„  ๋น„๊ต",
xaxis_title="Step", yaxis_title="Loss",
template="plotly_dark", height=450, yaxis_type="log"
)
return fig
def build_madam_tab():
with gr.Column():
gr.Markdown("""
## ๐Ÿ“„ M+Adam: Low-Precision Training via Mantissaโ€“Exponent Optimization
**ICML 2026 Spotlight** | Liang, Loeschcke, Anandkumar et al.
> ์ˆซ์ž์˜ **๊ฐ€์ˆ˜๋ถ€(mantissa)**์™€ **์ง€์ˆ˜๋ถ€(exponent)**๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ๊ฐ ๋‹ค๋ฅด๊ฒŒ ์ตœ์ ํ™” โ†’
> ์ €์ •๋ฐ€๋„(FP8/INT8)์—์„œ๋„ Adam ์ˆ˜์ค€์˜ ์•ˆ์ •์  ํ•™์Šต ๋‹ฌ์„ฑ.
> AI ํ›ˆ๋ จ ๋น„์šฉ ๋Œ€ํญ ์ ˆ๊ฐ ๊ฐ€๋Šฅ.
**์ฒดํ—˜**: ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์กฐ์ ˆํ•ด M+Adam์ด Adam ๋Œ€๋น„ ์–ด๋–ป๊ฒŒ ์ˆ˜๋ ดํ•˜๋Š”์ง€ ๋น„๊ตํ•˜์„ธ์š”.
""")
with gr.Row():
lr = gr.Slider(0.001, 0.1, value=0.01, step=0.001, label="ํ•™์Šต๋ฅ  (lr)")
beta1 = gr.Slider(0.5, 0.99, value=0.9, step=0.01, label="๋ชจ๋ฉ˜ํ…€ ฮฒโ‚")
noise = gr.Slider(0.0, 2.0, value=0.5, step=0.1, label="๊ทธ๋ž˜๋””์–ธํŠธ ๋…ธ์ด์ฆˆ")
n_steps = gr.Slider(50, 500, value=200, step=50, label="Step ์ˆ˜")
btn = gr.Button("๋น„๊ต ์‹คํ–‰", variant="primary")
plot = gr.Plot()
btn.click(madam_simulation, inputs=[lr, beta1, noise, n_steps], outputs=plot)
# โ”€โ”€ Tab 4: Linear RNN Parallelism โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def rnn_parallel_viz(seq_len: int, n_layers: int):
seq_lens = np.arange(1, seq_len + 1)
# Standard RNN: O(T) sequential โ€” each step depends on previous
rnn_latency = seq_lens * n_layers # strictly sequential
# Linear RNN: can use parallel scan (O(log T) depth)
linear_rnn_latency = np.ceil(np.log2(np.maximum(seq_lens, 1))) * n_layers
# Transformer: O(Tยฒ) attention but fully parallel โ€” single pass
transformer_latency = np.ones_like(seq_lens) * n_layers # parallel, O(1) depth
fig = go.Figure()
fig.add_trace(go.Scatter(x=seq_lens, y=rnn_latency, name="ํ‘œ์ค€ RNN (์ˆœ์ฐจ, O(T))", line=dict(color="#F44336")))
fig.add_trace(go.Scatter(x=seq_lens, y=linear_rnn_latency, name="์„ ํ˜• RNN (๋ณ‘๋ ฌ ์Šค์บ”, O(log T))", line=dict(color="#4CAF50")))
fig.add_trace(go.Scatter(x=seq_lens, y=transformer_latency, name="Transformer (์™„์ „ ๋ณ‘๋ ฌ, O(1))", line=dict(color="#2196F3", dash="dot")))
fig.update_layout(
title=f"RNN ์œ ํ˜•๋ณ„ ๋ณ‘๋ ฌํ™” ๊นŠ์ด ๋น„๊ต (๋ ˆ์ด์–ด {n_layers}๊ฐœ)",
xaxis_title="์‹œํ€€์Šค ๊ธธ์ด T", yaxis_title="๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๊นŠ์ด (๋‚ฎ์„์ˆ˜๋ก ๋น ๋ฆ„)",
template="plotly_dark", height=450
)
return fig
def build_rnn_tab():
with gr.Column():
gr.Markdown("""
## ๐Ÿ“„ Why Are Linear RNNs More Parallelizable?
**ICML 2026 Poster** | Merrill, Jiang, Li, Lin, Sabharwal
> ํ‘œ์ค€ RNN์€ ๊ฐ ์Šคํ…์ด ์ด์ „ ์Šคํ…์— **์˜์กด** โ†’ ์ˆœ์ฐจ ์‹คํ–‰ ๊ฐ•์ œ โ†’ ๋ณ‘๋ ฌํ™” ๋ถˆ๊ฐ€.
> ์„ ํ˜• RNN์€ **๋ณ‘๋ ฌ ์Šค์บ”(prefix sum)** ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ ์šฉ ๊ฐ€๋Šฅ โ†’ O(log T) ๊นŠ์ด๋กœ ๋‹จ์ถ•.
> ์ด ๋…ผ๋ฌธ์€ ์ด๋ฅผ ๋ณต์žก๋„ ํด๋ž˜์Šค ์ด๋ก ์œผ๋กœ ํ˜•์‹ํ™”.
**์ฒดํ—˜**: ์‹œํ€€์Šค ๊ธธ์ด๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์„ธ ๋ชจ๋ธ์˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๊นŠ์ด๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‹ฌ๋ผ์ง€๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.
""")
with gr.Row():
seq_len = gr.Slider(10, 512, value=128, step=16, label="์‹œํ€€์Šค ๊ธธ์ด T")
n_layers = gr.Slider(1, 24, value=6, step=1, label="๋ ˆ์ด์–ด ์ˆ˜")
btn = gr.Button("๋น„๊ต ์‹คํ–‰", variant="primary")
plot = gr.Plot()
btn.click(rnn_parallel_viz, inputs=[seq_len, n_layers], outputs=plot)
# โ”€โ”€ Tab 5: Random Matrix Diffusion โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def diffusion_consistency_viz(n_steps: int, noise_sigma: float, seed: int):
np.random.seed(seed)
img_size = 32
# Simulate forward diffusion (noise injection)
clean = np.random.randn(img_size, img_size) * 0.3 + 0.5
clean = np.clip(clean, 0, 1)
alphas = np.linspace(1.0, 0.0, n_steps + 1) # noise schedule
noisy_imgs = []
for t in range(n_steps + 1):
alpha = alphas[t]
noise = np.random.randn(img_size, img_size) * noise_sigma
noisy = alpha * clean + (1 - alpha) * noise
noisy_imgs.append(noisy)
# Plot selected timesteps
show_steps = [0, n_steps // 4, n_steps // 2, 3 * n_steps // 4, n_steps]
fig, _ = __import__('matplotlib.pyplot', fromlist=['']), None
import matplotlib.pyplot as plt
fig_mpl, axes = plt.subplots(1, len(show_steps), figsize=(14, 3))
fig_mpl.patch.set_facecolor('#1a1a2e')
for ax, t in zip(axes, show_steps):
ax.imshow(noisy_imgs[t], cmap='viridis', vmin=-1, vmax=2)
ax.set_title(f't={t}', color='white', fontsize=10)
ax.axis('off')
fig_mpl.suptitle("ํ™•์‚ฐ ๊ณผ์ • ์‹œ๊ฐํ™” โ€” ๋…ธ์ด์ฆˆ ์ฃผ์ž… (t=0: ์›๋ณธ โ†’ t=T: ์ˆœ์ˆ˜ ๋…ธ์ด์ฆˆ)", color='white')
fig_mpl.tight_layout()
return fig_mpl
def build_diffusion_tab():
with gr.Column():
gr.Markdown("""
## ๐Ÿ“„ A Random Matrix Perspective on the Consistency of Diffusion Models
**ICML 2026 Honorable Mention** | Wang, Zavatone-Veth, Pehlevan (Harvard)
> ํ™•์‚ฐ ๋ชจ๋ธ์ด ์™œ ๋น„์Šทํ•œ ์ž…๋ ฅ์— ๋น„์Šทํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋Š”์ง€(์ผ๊ด€์„ฑ) **๋žœ๋ค ํ–‰๋ ฌ ์ด๋ก **์œผ๋กœ ์ˆ˜ํ•™์  ์„ค๋ช….
> ๋ฌด์ž‘์œ„ ๊ฐ€์ค‘์น˜ ํ–‰๋ ฌ์˜ ์ŠคํŽ™ํŠธ๋Ÿผ ํŠน์„ฑ โ†’ ํ™•์‚ฐ ๊ถค์ ์˜ ์˜ˆ์ธก ๊ฐ€๋Šฅ์„ฑ์„ ์ด๋ก ์ ์œผ๋กœ ๊ทœ๋ช….
**์ฒดํ—˜**: ๋…ธ์ด์ฆˆ ์ฃผ์ž… ๊ณผ์ •์„ ์ง์ ‘ ์‹œ๊ฐํ™”. ์›๋ณธ ์ด๋ฏธ์ง€๊ฐ€ ๋‹จ๊ณ„์ ์œผ๋กœ ๋…ธ์ด์ฆˆ๋กœ ๋ณ€ํ™˜๋จ.
""")
with gr.Row():
n_steps = gr.Slider(10, 100, value=40, step=10, label="ํ™•์‚ฐ ๋‹จ๊ณ„ ์ˆ˜ T")
noise_sigma = gr.Slider(0.1, 2.0, value=0.8, step=0.1, label="๋…ธ์ด์ฆˆ ๊ฐ•๋„ ฯƒ")
seed = gr.Slider(0, 99, value=42, step=1, label="๋žœ๋ค ์‹œ๋“œ")
btn = gr.Button("์‹œ๊ฐํ™”", variant="primary")
plot = gr.Plot(label="ํ™•์‚ฐ ๊ณผ์ •")
btn.click(diffusion_consistency_viz, inputs=[n_steps, noise_sigma, seed], outputs=plot)
# โ”€โ”€ Tab 6: LM Circuits (ZeroGPU) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@spaces.GPU
def lm_circuits_demo(text: str, layer_idx: int):
from transformers import GPT2Model, GPT2Tokenizer
import torch
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2Model.from_pretrained("gpt2", output_hidden_states=True)
model.eval()
inputs = tokenizer(text, return_tensors="pt", max_length=32, truncation=True)
with torch.no_grad():
outputs = model(**inputs)
# hidden state at chosen layer: [1, seq_len, 768]
hidden = outputs.hidden_states[layer_idx][0].cpu().numpy() # [seq_len, 768]
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
# Sparsity: fraction of near-zero activations (|h| < threshold)
threshold = 0.1
sparsity_per_neuron = (np.abs(hidden) < threshold).mean(axis=0) # [768]
sparsity_per_token = (np.abs(hidden) < threshold).mean(axis=1) # [seq_len]
fig = go.Figure()
# Heatmap: tokens ร— first 64 neurons
n_show = min(64, hidden.shape[1])
fig = go.Figure(data=go.Heatmap(
z=hidden[:, :n_show],
x=[f"N{i}" for i in range(n_show)],
y=tokens,
colorscale="RdBu",
zmid=0,
))
fig.update_layout(
title=f"GPT-2 ๋ ˆ์ด์–ด {layer_idx} โ€” ๋‰ด๋Ÿฐ ํ™œ์„ฑํ™” ํžˆํŠธ๋งต (์ฒซ 64๊ฐœ ๋‰ด๋Ÿฐ)\n"
f"์ „์ฒด ๋‰ด๋Ÿฐ ํฌ์†Œ์„ฑ: {sparsity_per_neuron.mean():.1%}",
xaxis_title="๋‰ด๋Ÿฐ ์ธ๋ฑ์Šค", yaxis_title="ํ† ํฐ",
template="plotly_dark", height=max(300, len(tokens) * 30 + 100)
)
info = f"๋ ˆ์ด์–ด {layer_idx} ํฌ์†Œ์„ฑ: {sparsity_per_neuron.mean():.1%} (|ํ™œ์„ฑํ™”|<{threshold} ๋น„์œจ)\n"
info += "ํฌ์†Œ์„ฑ์ด ๋†’์„์ˆ˜๋ก โ†’ ํšŒ๋กœ ํ•ด์„์ด ์‰ฌ์›€ (๋…ผ๋ฌธ ํ•ต์‹ฌ ์ฃผ์žฅ)"
return fig, info
def build_circuits_tab():
with gr.Column():
gr.Markdown("""
## ๐Ÿ“„ Language Model Circuits Are Sparse in the Neuron Basis
**ICML 2026 Spotlight** | Arora, Wu, Steinhardt, Schwettmann
> LLM ๋‚ด๋ถ€์˜ "ํšŒ๋กœ"(ํŠน์ • ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋‰ด๋Ÿฐ ์ง‘ํ•ฉ)๊ฐ€ **๋‰ด๋Ÿฐ ๊ธฐ์ €์—์„œ ํฌ์†Œ**ํ•จ์„ ์‹ค์ฆ.
> ๋Œ€๋ถ€๋ถ„ ๋‰ด๋Ÿฐ์€ ํŠน์ • ์‹œ์ ์— ๊ฑฐ์˜ ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์Œ โ†’ AI ๋ธ”๋ž™๋ฐ•์Šค ํ•ด์„ ๊ฐ€๋Šฅ์„ฑ ํ–ฅ์ƒ.
**์ฒดํ—˜**: ํ…์ŠคํŠธ ์ž…๋ ฅ โ†’ GPT-2 ๊ฐ ๋ ˆ์ด์–ด์˜ ๋‰ด๋Ÿฐ ํ™œ์„ฑํ™” ํŒจํ„ด ์‹œ๊ฐํ™”. ํฌ์†Œํ• ์ˆ˜๋ก ํšŒ๋กœ ํ•ด์„ ์šฉ์ด.
*ZeroGPU ์‚ฌ์šฉ โ€” ์ฒซ ์‹คํ–‰ ์‹œ ๋ชจ๋ธ ๋กœ๋”ฉ์— 15โ€“30์ดˆ ์†Œ์š”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.*
""")
text_in = gr.Textbox(value="The cat sat on the mat", label="๋ถ„์„ํ•  ํ…์ŠคํŠธ (์˜์–ด)")
layer_idx = gr.Slider(0, 11, value=6, step=1, label="GPT-2 ๋ ˆ์ด์–ด ์ธ๋ฑ์Šค (0~11)")
btn = gr.Button("ํ™œ์„ฑํ™” ๋ถ„์„ (ZeroGPU)", variant="primary")
plot = gr.Plot()
info_out = gr.Textbox(label="ํฌ์†Œ์„ฑ ์ •๋ณด", interactive=False)
btn.click(lm_circuits_demo, inputs=[text_in, layer_idx], outputs=[plot, info_out])
# โ”€โ”€ Tab 7: Any-Diffusion / SDXL Turbo (ZeroGPU) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@spaces.GPU
def any_diffusion_demo(prompt: str, n_steps: int, seed: int):
from diffusers import AutoPipelineForText2Image
import torch
pipe = AutoPipelineForText2Image.from_pretrained(
"stabilityai/sdxl-turbo",
torch_dtype=torch.float16,
variant="fp16"
).to("cuda")
generator = torch.Generator("cuda").manual_seed(seed)
image = pipe(
prompt=prompt,
num_inference_steps=n_steps,
guidance_scale=0.0,
generator=generator,
).images[0]
return image
def build_anydiff_tab():
with gr.Column():
gr.Markdown("""
## ๐Ÿ“„ Any-Diffusion: Unified Multimodal Understanding and Generation
**ICML 2026 Poster** | Li, Long, Shen, Gao, Cao et al.
> ํ…์ŠคํŠธยท์ด๋ฏธ์ง€ยท์Œ์„ฑ์„ **any-to-any** ๋ฐฉ์‹์œผ๋กœ ํ†ตํ•ฉ ์ฒ˜๋ฆฌํ•˜๋Š” ํ™•์‚ฐ ๋ชจ๋ธ.
> ๋งˆ์Šคํฌ ๊ธฐ๋ฐ˜ ์ด์‚ฐ ํ™•์‚ฐ์œผ๋กœ ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ ๊ฒฝ๊ณ„๋ฅผ ์ œ๊ฑฐ.
**์ฒดํ—˜**: ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ โ†’ ์ด๋ฏธ์ง€ ์ƒ์„ฑ (SDXL-Turbo, Any-Diffusion ๊ฐœ๋… ๊ตฌํ˜„์ฒด).
SDXL-Turbo๋Š” ๋‹จ 1โ€“4 step์œผ๋กœ ๊ณ ํ’ˆ์งˆ ์ด๋ฏธ์ง€ ์ƒ์„ฑ โ€” Any-Diffusion์˜ ํšจ์œจ์„ฑ ๊ฐœ๋…๊ณผ ๋™์ผ์„ ์ƒ.
*ZeroGPU ์‚ฌ์šฉ โ€” ์ฒซ ์‹คํ–‰ ์‹œ ๋ชจ๋ธ ๋กœ๋”ฉ์— 20โ€“40์ดˆ ์†Œ์š”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.*
""")
prompt = gr.Textbox(value="a futuristic AI laboratory with neural network visualizations", label="์ด๋ฏธ์ง€ ํ”„๋กฌํ”„ํŠธ (์˜์–ด)")
with gr.Row():
n_steps = gr.Slider(1, 4, value=2, step=1, label="์ถ”๋ก  ์Šคํ… ์ˆ˜ (1โ€“4)")
seed = gr.Slider(0, 9999, value=42, step=1, label="์‹œ๋“œ")
btn = gr.Button("์ด๋ฏธ์ง€ ์ƒ์„ฑ (ZeroGPU)", variant="primary")
img_out = gr.Image(label="์ƒ์„ฑ ์ด๋ฏธ์ง€")
btn.click(any_diffusion_demo, inputs=[prompt, n_steps, seed], outputs=img_out)
# โ”€โ”€ Tab 8: Flexibility Trap (LLM API comparison) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@spaces.GPU
def flexibility_trap_demo(prompt: str, max_new_tokens: int):
"""Compare autoregressive (fixed order) vs masked diffusion LM (random order) generation."""
from transformers import GPT2LMHeadModel, GPT2Tokenizer
import torch
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained("gpt2").to("cuda")
model.eval()
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
input_len = inputs["input_ids"].shape[1]
# 1. Standard autoregressive (left-to-right, fixed order)
with torch.no_grad():
out_ar = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
do_sample=True,
temperature=0.8,
pad_token_id=tokenizer.eos_token_id,
)
text_ar = tokenizer.decode(out_ar[0][input_len:], skip_special_tokens=True)
# 2. Simulate "arbitrary order" by shuffling generation positions
# (simplified proxy โ€” actual diffusion LM requires MDLM architecture)
with torch.no_grad():
out_perm1 = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
do_sample=True,
temperature=1.2, # higher temp = more "random" order effect
pad_token_id=tokenizer.eos_token_id,
)
text_perm1 = tokenizer.decode(out_perm1[0][input_len:], skip_special_tokens=True)
with torch.no_grad():
out_perm2 = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
do_sample=True,
temperature=1.2,
pad_token_id=tokenizer.eos_token_id,
)
text_perm2 = tokenizer.decode(out_perm2[0][input_len:], skip_special_tokens=True)
result = f"""[๊ณ ์ • ์ˆœ์„œ ์ƒ์„ฑ (Autoregressive โ€” ์™ผ์ชฝโ†’์˜ค๋ฅธ์ชฝ)]
{text_ar}
[์ž„์˜ ์ˆœ์„œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ #1 (higher temperature)]
{text_perm1}
[์ž„์˜ ์ˆœ์„œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ #2]
{text_perm2}
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
๋…ผ๋ฌธ ํ•ต์‹ฌ: ์ž„์˜ ์ˆœ์„œ ์ƒ์„ฑ์€ ํ‘œ๋ฉด์ ์œผ๋กœ ๋‹ค์–‘ํ•ด ๋ณด์ด์ง€๋งŒ
์‹ค์ œ ์ถ”๋ก  ๊ฒฝ๋กœ์˜ ๋‹ค์–‘์„ฑ์€ ์˜คํžˆ๋ ค ๋‚ฎ์•„์ง‘๋‹ˆ๋‹ค (The Flexibility Trap).
๊ณ ์ • ์ˆœ์„œ ์ƒ์„ฑ #1์ด ๋Œ€๋ถ€๋ถ„์˜ ๋ฒค์น˜๋งˆํฌ์—์„œ ๋” ์ผ๊ด€๋œ ์ถ”๋ก ์„ ๋ณด์ž…๋‹ˆ๋‹ค."""
return result
def build_flexibility_tab():
with gr.Column():
gr.Markdown("""
## ๐Ÿ“„ The Flexibility Trap: Rethinking the Value of Arbitrary Order in Diffusion LMs
**ICML 2026 Outstanding Paper** | Ni, Wang, Yue et al.
> ํ™•์‚ฐ ์–ธ์–ด ๋ชจ๋ธ์˜ **์ž„์˜ ์ˆœ์„œ ์ƒ์„ฑ**์ด ์ถ”๋ก  ๋‹ค์–‘์„ฑ์„ ์˜คํžˆ๋ ค ๋‚ฎ์ถ˜๋‹ค๋Š” ์—ญ์„ค์  ๋ฐœ๊ฒฌ.
> "์œ ์—ฐํ• ์ˆ˜๋ก ๋” ํš์ผ์ " โ€” JustGRPO ํ›ˆ๋ จ์œผ๋กœ ๊ฐœ์„ .
**์ฒดํ—˜**: ๊ฐ™์€ ํ”„๋กฌํ”„ํŠธ๋กœ ๊ณ ์ • ์ˆœ์„œ vs ์ž„์˜ ์ˆœ์„œ ์ƒ์„ฑ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ตํ•˜์„ธ์š”.
(GPT-2๋กœ ๊ฐœ๋… ์‹œ์—ฐ โ€” ์‹ค์ œ ํ™•์‚ฐ LM ํ–‰๋™์˜ proxy)
*ZeroGPU ์‚ฌ์šฉ*
""")
prompt = gr.Textbox(value="The future of artificial intelligence will", label="์‹œ์ž‘ ํ”„๋กฌํ”„ํŠธ")
max_tokens = gr.Slider(20, 100, value=40, step=10, label="์ƒ์„ฑ ํ† ํฐ ์ˆ˜")
btn = gr.Button("์ƒ์„ฑ ๋น„๊ต (ZeroGPU)", variant="primary")
out = gr.Textbox(label="์ƒ์„ฑ ๊ฒฐ๊ณผ ๋น„๊ต", lines=12)
btn.click(flexibility_trap_demo, inputs=[prompt, max_tokens], outputs=out)
# โ”€โ”€ Main App โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
with gr.Blocks(
title="AI Paper Lab โ€” ICML 2026",
theme=gr.themes.Base(primary_hue="violet"),
css="""
.paper-header { background: linear-gradient(135deg, #1a1a2e, #16213e); padding: 20px; border-radius: 10px; margin-bottom: 10px; }
"""
) as demo:
gr.Markdown("""
# AI Paper Lab
### ICML 2026 ์ฃผ์š” ๋…ผ๋ฌธ์„ ์ง์ ‘ ์ฒดํ—˜ํ•˜์„ธ์š”
๊ฐ ํƒญ์—์„œ ๋…ผ๋ฌธ์˜ ํ•ต์‹ฌ ๊ฐœ๋…์„ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•˜๊ฒŒ ๊ฒฝํ—˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
CPU ํƒญ์€ ์ฆ‰์‹œ ์‹คํ–‰, ZeroGPU ํƒญ์€ ์ฒซ ์‹คํ–‰ ์‹œ 20โ€“40์ดˆ ๋Œ€๊ธฐ ๋ฐœ์ƒ.
""")
with gr.Tabs():
with gr.Tab("1. Grok Grokking (CPU)"):
build_grokking_tab()
with gr.Tab("2. Quantum vs Classical (CPU)"):
build_quantum_tab()
with gr.Tab("3. M+Adam (CPU)"):
build_madam_tab()
with gr.Tab("4. Linear RNN (CPU)"):
build_rnn_tab()
with gr.Tab("5. Diffusion ์‹œ๊ฐํ™” (CPU)"):
build_diffusion_tab()
with gr.Tab("6. LM Circuits (ZeroGPU)"):
build_circuits_tab()
with gr.Tab("7. Any-Diffusion (ZeroGPU)"):
build_anydiff_tab()
with gr.Tab("8. Flexibility Trap (ZeroGPU)"):
build_flexibility_tab()
if __name__ == "__main__":
demo.launch()