Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import numpy as np | |
| import torch | |
| import torch.nn as nn | |
| import matplotlib | |
| matplotlib.use('Agg') | |
| import matplotlib.pyplot as plt | |
| class SentinelNoiseSchedule: | |
| def __init__(self, timesteps=1000, z=2.0): | |
| self.timesteps = timesteps | |
| self.z = z | |
| self.betas = self._sentinel_schedule() | |
| self.alphas = 1.0 - self.betas | |
| self.alpha_bars = torch.cumprod(self.alphas, dim=0) | |
| def _sentinel_schedule(self): | |
| n = torch.arange(1, self.timesteps + 1, dtype=torch.float64) | |
| t_norm = n / self.timesteps | |
| beta = torch.zeros_like(n) | |
| for i in range(self.timesteps): | |
| t = t_norm[i].item() | |
| if t < 0.5: | |
| beta[i] = 0.0001 + 0.01 * (2 * t) ** (1 / (2 * t + 0.01)) | |
| else: | |
| beta[i] = 0.01 + 0.02 * ((2 * t - 1) ** (2 * t - 1)) | |
| return torch.clamp(beta, 0.0001, 0.999).float() | |
| def add_noise(self, x, t): | |
| sqrt_alpha_bar = torch.sqrt(self.alpha_bars[t]) | |
| sqrt_one_minus = torch.sqrt(1.0 - self.alpha_bars[t]) | |
| noise = torch.randn_like(x) | |
| return sqrt_alpha_bar.view(-1,1,1,1) * x + sqrt_one_minus.view(-1,1,1,1) * noise, noise | |
| def visualize_schedule(timesteps, z): | |
| """Visualize Sentinel noise schedule.""" | |
| schedule = SentinelNoiseSchedule(timesteps, z) | |
| fig, axes = plt.subplots(1, 3, figsize=(15, 4)) | |
| t = np.arange(timesteps) | |
| axes[0].plot(t, schedule.betas.numpy(), linewidth=2, color='purple') | |
| axes[0].set_title('Sentinel β Schedule (Super-Exponential)') | |
| axes[0].set_xlabel('Timestep') | |
| axes[0].set_ylabel('β') | |
| axes[0].grid(True, alpha=0.3) | |
| axes[1].plot(t, schedule.alpha_bars.numpy(), linewidth=2, color='blue') | |
| axes[1].set_title('ᾱ (Cumulative Product)') | |
| axes[1].set_xlabel('Timestep') | |
| axes[1].set_ylabel('ᾱ') | |
| axes[1].grid(True, alpha=0.3) | |
| # Compare with cosine schedule | |
| cos_betas = np.cos(np.linspace(0, np.pi/2, timesteps)) ** 2 * 0.02 | |
| axes[2].plot(t, schedule.betas.numpy(), label='Sentinel', linewidth=2, color='purple') | |
| axes[2].plot(t, cos_betas, label='Cosine', linewidth=2, color='orange', linestyle='--') | |
| axes[2].set_title('Schedule Comparison') | |
| axes[2].set_xlabel('Timestep') | |
| axes[2].set_ylabel('β') | |
| axes[2].legend() | |
| axes[2].grid(True, alpha=0.3) | |
| plt.tight_layout() | |
| plt.savefig('/tmp/diffusion_sched.png', dpi=150) | |
| plt.close() | |
| return '/tmp/diffusion_sched.png' | |
| def add_noise_demo(image_size, timesteps, step, z): | |
| """Demo noise addition on synthetic image.""" | |
| schedule = SentinelNoiseSchedule(timesteps, z) | |
| # Create synthetic image (colored pattern) | |
| img = torch.zeros(1, 3, image_size, image_size) | |
| for c in range(3): | |
| for i in range(image_size): | |
| for j in range(image_size): | |
| img[0, c, i, j] = np.sin(i * 0.3 + c) * np.cos(j * 0.3 + c) * 0.5 + 0.5 | |
| t = torch.tensor([step]) | |
| noisy_img, noise = schedule.add_noise(img, t) | |
| fig, axes = plt.subplots(1, 3, figsize=(15, 5)) | |
| def show_tensor(ax, tensor, title): | |
| arr = tensor[0].permute(1, 2, 0).numpy() | |
| arr = np.clip(arr, 0, 1) | |
| ax.imshow(arr) | |
| ax.set_title(title) | |
| ax.axis('off') | |
| show_tensor(axes[0], img, 'Original Image') | |
| show_tensor(axes[1], noisy_img, f'Noisy (t={step}, β={schedule.betas[step]:.4f})') | |
| show_tensor(axes[2], noise * 0.3 + 0.5, 'Noise (scaled)') | |
| plt.tight_layout() | |
| plt.savefig('/tmp/diffusion_noise.png', dpi=150) | |
| plt.close() | |
| info = f""" | |
| ## Sentinel Diffusion Noise Addition | |
| | Property | Value | | |
| |----------|-------| | |
| | Timestep | {step}/{timesteps} | | |
| | β (noise level) | {schedule.betas[step]:.6f} | | |
| | ᾱ (signal retained) | {schedule.alpha_bars[step]:.6f} | | |
| | Schedule type | **Super-exponential** | | |
| ### Key Innovation | |
| Sentinel noise schedule uses **super-exponential growth** of β: | |
| - Early steps: small noise (preserve structure) | |
| - Late steps: rapid increase (destroy structure) | |
| - Sharper transitions than cosine/linear schedules | |
| """ | |
| return '/tmp/diffusion_noise.png', info | |
| with gr.Blocks(title="Sentinel Diffusion Model") as demo: | |
| gr.Markdown(""" | |
| # 🎨 Sentinel Diffusion Model | |
| **Super-exponential noise schedule for sharper transitions.** | |
| The Sentinel partition function F(z) = Σ zⁿ/nⁿ inspires a noise schedule | |
| with super-exponential β growth — potentially requiring fewer steps. | |
| """) | |
| with gr.Tab("Noise Schedule"): | |
| with gr.Row(): | |
| ts_sched = gr.Slider(100, 2000, value=1000, step=100, label="Timesteps") | |
| z_sched = gr.Slider(0.5, 5.0, value=2.0, label="z Parameter") | |
| btn_sched = gr.Button("Visualize Schedule", variant="primary") | |
| img_sched = gr.Image() | |
| btn_sched.click(visualize_schedule, [ts_sched, z_sched], img_sched) | |
| with gr.Tab("Noise Addition Demo"): | |
| with gr.Row(): | |
| img_size = gr.Slider(16, 128, value=64, step=16, label="Image Size") | |
| ts_noise = gr.Slider(100, 2000, value=1000, step=100, label="Total Timesteps") | |
| step_noise = gr.Slider(0, 999, value=500, label="Current Step") | |
| z_noise = gr.Slider(0.5, 5.0, value=2.0, label="z Parameter") | |
| btn_noise = gr.Button("Add Noise", variant="primary") | |
| img_noise = gr.Image() | |
| info_noise = gr.Markdown() | |
| btn_noise.click(add_noise_demo, [img_size, ts_noise, step_noise, z_noise], [img_noise, info_noise]) | |
| gr.Markdown(""" | |
| ## About Sentinel Diffusion | |
| - **Noise schedule**: Super-exponential β growth (from partition function) | |
| - **Transition**: Sharper than cosine/linear (phase-like) | |
| - **Structure preservation**: Strong early, weak late | |
| - **Potential**: Fewer diffusion steps needed | |
| [Model Repo](https://huggingface.co/5dimension/sentinel-diffusion) | |
| """) | |
| if __name__ == "__main__": | |
| demo.launch() | |