Text-to-Image
Diffusers
Safetensors
prism-dit
diffusion
dit
flow-matching
rectified-flow
artistic
custom-architecture
Instructions to use WZRD-AI/PRISM-1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use WZRD-AI/PRISM-1 with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("WZRD-AI/PRISM-1", 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
- Local Apps Settings
- Draw Things
- DiffusionBee
Download model.py from WZRD-AI/PRISM-1: direct link, hf CLI and curl.
- Browser
- Download file 10.1 kB
-
https://huggingface.co/WZRD-AI/PRISM-1/resolve/main/model.py
- Command line
-
hf download hf://WZRD-AI/PRISM-1/model.py
-
curl -L -o model.py https://huggingface.co/WZRD-AI/PRISM-1/resolve/main/model.py
10.1 kB
| """ | |
| PRISM Custom DiT (Diffusion Transformer) Architecture Definition. | |
| Implements a modular Diffusion Transformer with AdaLN-Zero conditioning, | |
| 2D spatial patchification, and cross-attention text guidance. | |
| """ | |
| import math | |
| from typing import Optional, Tuple | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| def modulate(x: torch.Tensor, shift: torch.Tensor, scale: torch.Tensor) -> torch.Tensor: | |
| """Modulates input tensor using affine scale and shift parameters.""" | |
| return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1) | |
| class TimestepEmbedder(nn.Module): | |
| """ | |
| Embeds scalar timesteps into vector representations via sinusoidal embeddings | |
| followed by a two-layer MLP. | |
| """ | |
| def __init__(self, hidden_size: int, frequency_embedding_size: int = 256): | |
| super().__init__() | |
| self.mlp = nn.Sequential( | |
| nn.Linear(frequency_embedding_size, hidden_size, bias=True), | |
| nn.SiLU(), | |
| nn.Linear(hidden_size, hidden_size, bias=True), | |
| ) | |
| self.frequency_embedding_size = frequency_embedding_size | |
| def sinusoidal_embedding(t: torch.Tensor, dim: int, max_period: int = 10000) -> torch.Tensor: | |
| half = dim // 2 | |
| freqs = torch.exp( | |
| -math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32, device=t.device) / half | |
| ) | |
| args = t[:, None].float() * freqs[None] | |
| embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1) | |
| if dim % 2 == 1: | |
| embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1) | |
| return embedding | |
| def forward(self, t: torch.Tensor) -> torch.Tensor: | |
| t_freq = self.sinusoidal_embedding(t, self.frequency_embedding_size) | |
| return self.mlp(t_freq) | |
| class PatchEmbed(nn.Module): | |
| """2D Image/Latent to Patch Embedding.""" | |
| def __init__(self, patch_size: int = 2, in_channels: int = 16, embed_dim: int = 1152): | |
| super().__init__() | |
| self.patch_size = patch_size | |
| self.proj = nn.Conv2d( | |
| in_channels, embed_dim, kernel_size=patch_size, stride=patch_size, bias=True | |
| ) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| # x: (B, C, H, W) -> proj -> (B, D, H/p, W/p) -> flatten -> (B, N, D) | |
| x = self.proj(x) | |
| x = x.flatten(2).transpose(1, 2) | |
| return x | |
| class PrismDiTBlock(nn.Module): | |
| """ | |
| DiT Block with AdaLN-Zero conditioning and Cross-Attention for text conditioning. | |
| """ | |
| def __init__(self, hidden_size: int, num_heads: int, context_dim: int = 1024, mlp_ratio: float = 4.0): | |
| super().__init__() | |
| self.hidden_size = hidden_size | |
| self.num_heads = num_heads | |
| self.head_dim = hidden_size // num_heads | |
| # Normalization layers | |
| self.norm1 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6) | |
| self.norm2 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6) | |
| self.norm_cross = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6) | |
| # Self-Attention | |
| self.self_attn = nn.MultiheadAttention(hidden_size, num_heads, batch_first=True) | |
| # Cross-Attention for text embeddings | |
| self.cross_attn = nn.MultiheadAttention( | |
| embed_dim=hidden_size, | |
| kdim=context_dim, | |
| vdim=context_dim, | |
| num_heads=num_heads, | |
| batch_first=True, | |
| ) | |
| # Feed-Forward Network | |
| mlp_hidden_dim = int(hidden_size * mlp_ratio) | |
| self.mlp = nn.Sequential( | |
| nn.Linear(hidden_size, mlp_hidden_dim, bias=True), | |
| nn.GELU(approximate="tanh"), | |
| nn.Linear(mlp_hidden_dim, hidden_size, bias=True), | |
| ) | |
| # AdaLN modulation table: 6 modulation scales (shift, scale, gate for self-attn and mlp) | |
| self.adaLN_modulation = nn.Sequential( | |
| nn.SiLU(), | |
| nn.Linear(hidden_size, 6 * hidden_size, bias=True), | |
| ) | |
| def forward( | |
| self, | |
| x: torch.Tensor, | |
| c: torch.Tensor, | |
| context: Optional[torch.Tensor] = None, | |
| context_mask: Optional[torch.Tensor] = None, | |
| ) -> torch.Tensor: | |
| # Modulation vectors from timestep / conditioning vector c | |
| shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = ( | |
| self.adaLN_modulation(c).chunk(6, dim=1) | |
| ) | |
| # 1. Self Attention with AdaLN modulation | |
| normed_x = modulate(self.norm1(x), shift_msa, scale_msa) | |
| attn_out, _ = self.self_attn(normed_x, normed_x, normed_x) | |
| x = x + gate_msa.unsqueeze(1) * attn_out | |
| # 2. Cross Attention with text context (if provided) | |
| if context is not None: | |
| normed_cross = self.norm_cross(x) | |
| cross_out, _ = self.cross_attn( | |
| query=normed_cross, | |
| key=context, | |
| value=context, | |
| key_padding_mask=context_mask, | |
| ) | |
| x = x + cross_out | |
| # 3. Feed Forward with AdaLN modulation | |
| normed_mlp = modulate(self.norm2(x), shift_mlp, scale_mlp) | |
| mlp_out = self.mlp(normed_mlp) | |
| x = x + gate_mlp.unsqueeze(1) * mlp_out | |
| return x | |
| class FinalLayer(nn.Module): | |
| """Final AdaLN layer and linear unpatchify projection.""" | |
| def __init__(self, hidden_size: int, patch_size: int, out_channels: int): | |
| super().__init__() | |
| self.norm_final = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6) | |
| self.linear = nn.Linear(hidden_size, patch_size * patch_size * out_channels, bias=True) | |
| self.adaLN_modulation = nn.Sequential( | |
| nn.SiLU(), | |
| nn.Linear(hidden_size, 2 * hidden_size, bias=True), | |
| ) | |
| def forward(self, x: torch.Tensor, c: torch.Tensor) -> torch.Tensor: | |
| shift, scale = self.adaLN_modulation(c).chunk(2, dim=1) | |
| x = modulate(self.norm_final(x), shift, scale) | |
| return self.linear(x) | |
| class PrismDiT(nn.Module): | |
| """ | |
| PRISM Diffusion Transformer Backbone. | |
| Supports: | |
| - Flow-matching or v-prediction / epsilon diffusion | |
| - Flexible latent channels (default: 16 channels for high-fidelity VAE) | |
| - Full multimodal context cross-attention | |
| """ | |
| def __init__( | |
| self, | |
| input_size: int = 64, | |
| patch_size: int = 2, | |
| in_channels: int = 16, | |
| hidden_size: int = 1152, | |
| depth: int = 28, | |
| num_heads: int = 16, | |
| mlp_ratio: float = 4.0, | |
| context_dim: int = 1024, | |
| ): | |
| super().__init__() | |
| self.in_channels = in_channels | |
| self.out_channels = in_channels | |
| self.patch_size = patch_size | |
| self.num_heads = num_heads | |
| self.hidden_size = hidden_size | |
| self.x_embedder = PatchEmbed(patch_size, in_channels, hidden_size) | |
| self.t_embedder = TimestepEmbedder(hidden_size) | |
| # 2D Positional embeddings (learnable or fixed sinusoidal) | |
| num_patches = (input_size // patch_size) ** 2 | |
| self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, hidden_size)) | |
| # Transformer blocks | |
| self.blocks = nn.ModuleList([ | |
| PrismDiTBlock(hidden_size, num_heads, context_dim=context_dim, mlp_ratio=mlp_ratio) | |
| for _ in range(depth) | |
| ]) | |
| # Final projection layer | |
| self.final_layer = FinalLayer(hidden_size, patch_size, self.out_channels) | |
| self.initialize_weights() | |
| def initialize_weights(self): | |
| # Initialize patch embedding like linear projection | |
| w = self.x_embedder.proj.weight.data | |
| nn.init.xavier_uniform_(w.view([w.shape[0], -1])) | |
| nn.init.constant_(self.x_embedder.proj.bias, 0) | |
| # Initialize pos_embed | |
| nn.init.normal_(self.pos_embed, std=0.02) | |
| # Zero-out AdaLN modulation layers for identity start | |
| for block in self.blocks: | |
| nn.init.constant_(block.adaLN_modulation[-1].weight, 0) | |
| nn.init.constant_(block.adaLN_modulation[-1].bias, 0) | |
| nn.init.constant_(self.final_layer.adaLN_modulation[-1].weight, 0) | |
| nn.init.constant_(self.final_layer.adaLN_modulation[-1].bias, 0) | |
| nn.init.constant_(self.final_layer.linear.weight, 0) | |
| nn.init.constant_(self.final_layer.linear.bias, 0) | |
| def unpatchify(self, x: torch.Tensor, h: int, w: int) -> torch.Tensor: | |
| """ | |
| x: (B, N, patch_size**2 * C) | |
| Returns: (B, C, H, W) | |
| """ | |
| c = self.out_channels | |
| p = self.patch_size | |
| ph, pw = h // p, w // p | |
| assert ph * pw == x.shape[1] | |
| x = x.reshape(shape=(x.shape[0], ph, pw, p, p, c)) | |
| x = torch.einsum("nhwpqc->nchpwq", x) | |
| imgs = x.reshape(shape=(x.shape[0], c, ph * p, pw * p)) | |
| return imgs | |
| def forward( | |
| self, | |
| x: torch.Tensor, | |
| t: torch.Tensor, | |
| context: Optional[torch.Tensor] = None, | |
| context_mask: Optional[torch.Tensor] = None, | |
| ) -> torch.Tensor: | |
| """ | |
| Forward pass for PRISM DiT. | |
| x: (B, C, H, W) Latent tensor | |
| t: (B,) Timestep tensor | |
| context: (B, L, context_dim) Text/multimodal conditioning sequence | |
| """ | |
| b, c, h, w = x.shape | |
| x = self.x_embedder(x) | |
| # Add positional embedding (interpolating if resolution differs) | |
| if x.shape[1] == self.pos_embed.shape[1]: | |
| x = x + self.pos_embed | |
| else: | |
| # Dynamic positional interpolation for arbitrary aspect ratios | |
| pos_embed = F.interpolate( | |
| self.pos_embed.transpose(1, 2).reshape(1, self.hidden_size, int(math.sqrt(self.pos_embed.shape[1])), -1), | |
| size=(h // self.patch_size, w // self.patch_size), | |
| mode="bicubic", | |
| align_corners=False, | |
| ).flatten(2).transpose(1, 2) | |
| x = x + pos_embed | |
| c_emb = self.t_embedder(t) | |
| for block in self.blocks: | |
| x = block(x, c_emb, context=context, context_mask=context_mask) | |
| x = self.final_layer(x, c_emb) | |
| x = self.unpatchify(x, h, w) | |
| return x | |