Instructions to use chenzeyang1/T with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use chenzeyang1/T with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("chenzeyang1/T", torch_dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
| """ | |
| Exponential Moving Average (EMA) for Model Weights | |
| Maintains a shadow copy of model parameters with exponentially decayed averaging: | |
| θ_ema = decay * θ_ema + (1 - decay) * θ | |
| Benefits: | |
| - More stable inference (smoother weight updates) | |
| - Better generalization (less prone to overfitting) | |
| - Standard practice for diffusion models (IP2P, SD, DALL-E, etc.) | |
| Usage: | |
| # Initialize | |
| ema = EMA(model.parameters(), decay=0.9999) | |
| # After optimizer.step() | |
| ema.update() | |
| # For validation/inference | |
| with ema.average_parameters(): | |
| # Use EMA weights | |
| output = model(input) | |
| """ | |
| import torch | |
| import torch.nn as nn | |
| from contextlib import contextmanager | |
| from typing import Iterable, Optional | |
| from copy import deepcopy | |
| class EMA: | |
| """ | |
| Exponential Moving Average of model parameters. | |
| Args: | |
| parameters: Iterable of model parameters to track | |
| decay: EMA decay rate (default: 0.9999) | |
| Higher = slower update, more stable | |
| Common values: 0.999, 0.9999, 0.99999 | |
| update_every: Update EMA every N steps (default: 1) | |
| min_decay: Minimum decay value (default: 0.0, no minimum) | |
| use_num_updates: Adjust decay based on num_updates (default: True) | |
| """ | |
| def __init__( | |
| self, | |
| parameters: Iterable[nn.Parameter], | |
| decay: float = 0.9999, | |
| update_every: int = 1, | |
| min_decay: float = 0.0, | |
| use_num_updates: bool = True, | |
| ): | |
| self.decay = decay | |
| self.min_decay = min_decay | |
| self.update_every = update_every | |
| self.use_num_updates = use_num_updates | |
| # Store model parameters | |
| self.online_params = list(parameters) | |
| # Create shadow copy of parameters on the same device | |
| self.shadow_params = [p.clone().detach().to(p.device) for p in self.online_params] | |
| # Track number of updates | |
| self.num_updates = 0 | |
| # Flag to track if we're currently using EMA weights | |
| self.using_ema = False | |
| def get_decay(self, num_updates: Optional[int] = None) -> float: | |
| """ | |
| Compute current decay value. | |
| Optionally adjusts decay based on number of updates: | |
| decay = min(decay, (1 + num_updates) / (10 + num_updates)) | |
| This starts with lower decay for faster initial updates, | |
| then gradually increases to target decay. | |
| """ | |
| if num_updates is None: | |
| num_updates = self.num_updates | |
| decay = self.decay | |
| if self.use_num_updates: | |
| # Adjust decay based on num_updates (starts lower, gradually increases) | |
| decay = min(decay, (1 + num_updates) / (10 + num_updates)) | |
| # Apply minimum decay | |
| decay = max(decay, self.min_decay) | |
| return decay | |
| def update(self): | |
| """ | |
| Update EMA parameters. | |
| Called after optimizer.step() during training. | |
| """ | |
| self.num_updates += 1 | |
| # Only update every N steps | |
| if self.num_updates % self.update_every != 0: | |
| return | |
| decay = self.get_decay() | |
| # Update shadow parameters | |
| for i, (shadow_param, online_param) in enumerate(zip(self.shadow_params, self.online_params)): | |
| if online_param.requires_grad: | |
| # Ensure shadow parameter is on the same device as online parameter | |
| if shadow_param.device != online_param.device: | |
| self.shadow_params[i] = shadow_param.to(online_param.device) | |
| shadow_param = self.shadow_params[i] | |
| # EMA update: θ_ema = decay * θ_ema + (1 - decay) * θ | |
| shadow_param.mul_(decay).add_(online_param.data, alpha=1 - decay) | |
| def copy_to(self, parameters: Iterable[nn.Parameter]): | |
| """Copy EMA parameters to given parameters""" | |
| for shadow_param, param in zip(self.shadow_params, parameters): | |
| # Ensure shadow parameter is on the same device as target parameter | |
| if shadow_param.device != param.device: | |
| shadow_param = shadow_param.to(param.device) | |
| param.data.copy_(shadow_param.data) | |
| def store(self): | |
| """Store current model parameters (before loading EMA)""" | |
| if self.using_ema: | |
| raise RuntimeError("Already using EMA parameters!") | |
| self.backup_params = [p.clone() for p in self.online_params] | |
| def restore(self): | |
| """Restore original model parameters (after using EMA)""" | |
| if not self.using_ema: | |
| raise RuntimeError("Not currently using EMA parameters!") | |
| for param, backup_param in zip(self.online_params, self.backup_params): | |
| param.data.copy_(backup_param.data) | |
| del self.backup_params | |
| def load_ema_into_model(self): | |
| """Load EMA parameters into model""" | |
| self.store() | |
| self.copy_to(self.online_params) | |
| self.using_ema = True | |
| def restore_model_from_ema(self): | |
| """Restore model parameters from backup""" | |
| self.restore() | |
| self.using_ema = False | |
| def average_parameters(self): | |
| """ | |
| Context manager for using EMA parameters. | |
| Usage: | |
| with ema.average_parameters(): | |
| # Model now uses EMA weights | |
| output = model(input) | |
| # Model back to normal weights | |
| """ | |
| self.load_ema_into_model() | |
| try: | |
| yield | |
| finally: | |
| self.restore_model_from_ema() | |
| def state_dict(self): | |
| """Get EMA state for checkpointing""" | |
| return { | |
| 'shadow_params': self.shadow_params, | |
| 'num_updates': self.num_updates, | |
| 'decay': self.decay, | |
| 'min_decay': self.min_decay, | |
| 'update_every': self.update_every, | |
| 'use_num_updates': self.use_num_updates, | |
| } | |
| def load_state_dict(self, state_dict): | |
| """Load EMA state from checkpoint""" | |
| self.shadow_params = state_dict['shadow_params'] | |
| self.num_updates = state_dict['num_updates'] | |
| self.decay = state_dict.get('decay', self.decay) | |
| self.min_decay = state_dict.get('min_decay', self.min_decay) | |
| self.update_every = state_dict.get('update_every', self.update_every) | |
| self.use_num_updates = state_dict.get('use_num_updates', self.use_num_updates) | |
| def __repr__(self): | |
| return ( | |
| f"EMA(decay={self.decay}, num_updates={self.num_updates}, " | |
| f"current_decay={self.get_decay():.6f}, num_params={len(self.shadow_params)})" | |
| ) | |
| class EMAWarmupScheduler: | |
| """ | |
| Scheduler for EMA decay with warmup. | |
| Gradually increases EMA decay from min to max over warmup steps. | |
| Useful for stable training start. | |
| Args: | |
| ema: EMA instance | |
| warmup_steps: Number of warmup steps | |
| min_decay: Starting decay value (default: 0.95) | |
| max_decay: Target decay value (default: 0.9999) | |
| """ | |
| def __init__( | |
| self, | |
| ema: EMA, | |
| warmup_steps: int, | |
| min_decay: float = 0.95, | |
| max_decay: float = 0.9999, | |
| ): | |
| self.ema = ema | |
| self.warmup_steps = warmup_steps | |
| self.min_decay = min_decay | |
| self.max_decay = max_decay | |
| self.original_decay = ema.decay | |
| def step(self): | |
| """Update EMA decay based on num_updates""" | |
| if self.ema.num_updates < self.warmup_steps: | |
| # Linear warmup | |
| progress = self.ema.num_updates / self.warmup_steps | |
| self.ema.decay = self.min_decay + (self.max_decay - self.min_decay) * progress | |
| else: | |
| # Use original decay | |
| self.ema.decay = self.original_decay | |
| if __name__ == "__main__": | |
| # Test EMA | |
| print("Testing EMA module...") | |
| # Create dummy model | |
| model = nn.Linear(10, 10) | |
| # Initialize EMA | |
| ema = EMA(model.parameters(), decay=0.9999) | |
| print(f"\n[1] Initialized: {ema}") | |
| # Simulate training | |
| print("\n[2] Simulating training...") | |
| optimizer = torch.optim.Adam(model.parameters(), lr=0.001) | |
| for step in range(100): | |
| # Forward pass | |
| x = torch.randn(4, 10) | |
| y = model(x) | |
| loss = y.mean() | |
| # Backward pass | |
| optimizer.zero_grad() | |
| loss.backward() | |
| optimizer.step() | |
| # Update EMA | |
| ema.update() | |
| if step % 20 == 0: | |
| print(f" Step {step}: decay={ema.get_decay():.6f}, num_updates={ema.num_updates}") | |
| # Test context manager | |
| print("\n[3] Testing context manager...") | |
| with torch.no_grad(): | |
| x_test = torch.randn(4, 10) | |
| # Normal weights | |
| output_normal = model(x_test) | |
| # EMA weights | |
| with ema.average_parameters(): | |
| output_ema = model(x_test) | |
| # Back to normal weights | |
| output_normal_2 = model(x_test) | |
| print(f" Normal output mean: {output_normal.mean().item():.4f}") | |
| print(f" EMA output mean: {output_ema.mean().item():.4f}") | |
| print(f" Normal output (after EMA) mean: {output_normal_2.mean().item():.4f}") | |
| print(f" ✓ Weights correctly restored: {torch.allclose(output_normal, output_normal_2)}") | |
| # Test state dict | |
| print("\n[4] Testing state dict...") | |
| state = ema.state_dict() | |
| print(f" State dict keys: {list(state.keys())}") | |
| # Create new EMA and load state | |
| ema_new = EMA(model.parameters(), decay=0.999) # Different decay | |
| ema_new.load_state_dict(state) | |
| print(f" Loaded EMA: {ema_new}") | |
| print(f" ✓ num_updates match: {ema_new.num_updates == ema.num_updates}") | |
| # Test warmup scheduler | |
| print("\n[5] Testing EMA warmup scheduler...") | |
| model2 = nn.Linear(10, 10) | |
| ema2 = EMA(model2.parameters(), decay=0.9999) | |
| scheduler = EMAWarmupScheduler(ema2, warmup_steps=50, min_decay=0.95, max_decay=0.9999) | |
| for step in range(100): | |
| # Simulate training | |
| ema2.update() | |
| scheduler.step() | |
| if step % 20 == 0: | |
| print(f" Step {step}: decay={ema2.decay:.6f}") | |
| print("\n✓ All EMA tests passed!") | |