Instructions to use SD-Next/Ming-Image-0.1-sdnq-uint4 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use SD-Next/Ming-Image-0.1-sdnq-uint4 with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("SD-Next/Ming-Image-0.1-sdnq-uint4", 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
File size: 20,059 Bytes
12c3a55 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 | # Copyright 2026 inclusionAI and The HuggingFace Team. All rights reserved.
#
# Licensed under the MIT License. See the LICENSE file in this repository.
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from diffusers.configuration_utils import ConfigMixin, register_to_config
from diffusers.models.modeling_utils import ModelMixin
class MingImageRMSNorm(nn.Module):
def __init__(self, hidden_size: int, eps: float = 1e-6):
super().__init__()
self.weight = nn.Parameter(torch.ones(hidden_size))
self.variance_epsilon = eps
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
input_dtype = hidden_states.dtype
hidden_states = hidden_states.to(torch.float32)
variance = hidden_states.pow(2).mean(-1, keepdim=True)
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
return self.weight * hidden_states.to(input_dtype)
def rotate_half(x: torch.Tensor) -> torch.Tensor:
x1 = x[..., : x.shape[-1] // 2]
x2 = x[..., x.shape[-1] // 2 :]
return torch.cat((-x2, x1), dim=-1)
def video_rope_cos_sin(cos: torch.Tensor, sin: torch.Tensor, mrope_section: list[int]):
"""Interleave the (frame, height, width) rotary tables into the "video_rope" channel layout.
`cos` / `sin` are `(3, batch, seq_len, rotary_dim)` for the frame, height and width axes. Height and width
alternate channel by channel, and the frame axis takes the last channels of each half.
"""
sections = [mrope_section[0], mrope_section[1] + mrope_section[2]] * 2
index = 0
result_cos, result_sin = [], []
for i, section in enumerate(sections[::-1]):
if i % 2 == 0:
for j in range(section):
row = 1 if j % 2 == 0 else 2
result_cos.append(cos[row, ..., index : index + 1])
result_sin.append(sin[row, ..., index : index + 1])
index += 1
else:
result_cos.append(cos[0, ..., index : index + section])
result_sin.append(sin[0, ..., index : index + section])
index += section
return torch.cat(result_cos, dim=-1), torch.cat(result_sin, dim=-1)
class MingImageRotaryEmbedding(nn.Module):
def __init__(self, rotary_dim: int, theta: float):
super().__init__()
inv_freq = 1.0 / (theta ** (torch.arange(0, rotary_dim, 2, dtype=torch.int64).float() / rotary_dim))
self.register_buffer("inv_freq", inv_freq, persistent=False)
@torch.no_grad()
def forward(self, x: torch.Tensor, position_ids: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
# position_ids: (3, batch, seq_len) for the frame, height and width axes
inv_freq = self.inv_freq[None, None, :, None].float().expand(3, position_ids.shape[1], -1, 1).to(x.device)
position_ids = position_ids[:, :, None, :].float()
with torch.autocast(device_type=x.device.type if x.device.type != "mps" else "cpu", enabled=False):
freqs = (inv_freq @ position_ids).transpose(2, 3)
emb = torch.cat((freqs, freqs), dim=-1)
return emb.cos().to(x.dtype), emb.sin().to(x.dtype)
class MingImageMLP(nn.Module):
def __init__(self, hidden_size: int, intermediate_size: int):
super().__init__()
self.gate_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
self.up_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
class MingImageGate(nn.Module):
"""Sigmoid router with expert bias and group-limited top-k selection."""
def __init__(self, hidden_size, num_experts, top_k, n_group, topk_group, routed_scaling_factor):
super().__init__()
self.top_k = top_k
self.num_experts = num_experts
self.n_group = n_group
self.topk_group = topk_group
self.routed_scaling_factor = routed_scaling_factor
self.weight = nn.Parameter(torch.zeros((num_experts, hidden_size)))
self.expert_bias = nn.Parameter(torch.zeros(num_experts), requires_grad=False)
def forward(self, hidden_states: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
hidden_states = hidden_states.view(-1, hidden_states.shape[-1])
logits = F.linear(hidden_states.float(), self.weight.float())
scores = torch.sigmoid(logits)
# pick the top `topk_group` groups by the sum of their two best (bias-corrected) scores, then the top-k
# experts inside those groups
scores_for_routing = scores + self.expert_bias
num_tokens = scores_for_routing.shape[0]
group_scores = scores_for_routing.view(num_tokens, self.n_group, -1).topk(2, dim=-1)[0].sum(dim=-1)
group_idx = torch.topk(group_scores, k=self.topk_group, dim=-1, sorted=False)[1]
group_mask = torch.zeros_like(group_scores).scatter_(1, group_idx, 1)
score_mask = (
group_mask.unsqueeze(-1)
.expand(num_tokens, self.n_group, self.num_experts // self.n_group)
.reshape(num_tokens, -1)
)
masked_scores = scores_for_routing.masked_fill(~score_mask.bool(), float("-inf"))
topk_idx = torch.topk(masked_scores, k=self.top_k, dim=-1, sorted=False)[1]
topk_weight = torch.gather(scores, dim=1, index=topk_idx).type_as(logits)
topk_weight = topk_weight / (topk_weight.sum(dim=-1, keepdim=True) + 1e-20)
return topk_idx, topk_weight * self.routed_scaling_factor
class MingImageSparseMoeBlock(nn.Module):
"""Routed experts plus a shared expert. Tokens at image positions are routed by `image_gate`."""
def __init__(self, config):
super().__init__()
gate_kwargs = {
"hidden_size": config.hidden_size,
"num_experts": config.num_experts,
"top_k": config.num_experts_per_tok,
"n_group": config.n_group,
"topk_group": config.topk_group,
"routed_scaling_factor": config.routed_scaling_factor,
}
self.gate = MingImageGate(**gate_kwargs)
self.image_gate = MingImageGate(**gate_kwargs)
self.experts = nn.ModuleList(
[MingImageMLP(config.hidden_size, config.moe_intermediate_size) for _ in range(config.num_experts)]
)
self.shared_experts = MingImageMLP(
config.hidden_size, config.moe_intermediate_size * config.num_shared_experts
)
def forward(self, hidden_states: torch.Tensor, image_mask: torch.Tensor) -> torch.Tensor:
batch_size, seq_len, hidden_size = hidden_states.shape
topk_idx, topk_weight = self.gate(hidden_states)
image_topk_idx, image_topk_weight = self.image_gate(hidden_states)
image_mask = image_mask.view(-1, 1)
topk_idx = torch.where(image_mask, image_topk_idx, topk_idx)
topk_weight = torch.where(image_mask, image_topk_weight, topk_weight)
routed = self.moe_infer(hidden_states.view(-1, hidden_size), topk_idx, topk_weight)
return routed.view(batch_size, seq_len, hidden_size) + self.shared_experts(hidden_states)
def moe_infer(self, x: torch.Tensor, topk_ids: torch.Tensor, topk_weight: torch.Tensor) -> torch.Tensor:
tokens_per_expert = torch.bincount(topk_ids.view(-1), minlength=len(self.experts)).tolist()
idxs = topk_ids.view(-1).argsort()
sorted_tokens = x[idxs // topk_ids.shape[1]]
outputs = []
start_idx = 0
for expert, num_tokens in zip(self.experts, tokens_per_expert):
if num_tokens == 0:
continue
outputs.append(expert(sorted_tokens[start_idx : start_idx + num_tokens]))
start_idx += num_tokens
outs = torch.cat(outputs, dim=0)
new_x = torch.empty_like(outs)
new_x[idxs] = outs
return (
new_x.view(*topk_ids.shape, -1)
.type(topk_weight.dtype)
.mul_(topk_weight.unsqueeze(dim=-1))
.sum(dim=1)
.type(new_x.dtype)
)
class MingImageTextAttention(nn.Module):
def __init__(self, config):
super().__init__()
self.num_heads = config.num_attention_heads
self.num_kv_heads = config.num_key_value_heads
self.head_dim = config.head_dim
self.mrope_section = config.mrope_section
self.query_key_value = nn.Linear(
config.hidden_size, (self.num_heads + 2 * self.num_kv_heads) * self.head_dim, bias=False
)
self.q_norm = MingImageRMSNorm(self.head_dim, eps=config.rms_norm_eps)
self.k_norm = MingImageRMSNorm(self.head_dim, eps=config.rms_norm_eps)
self.dense = nn.Linear(self.num_heads * self.head_dim, config.hidden_size, bias=False)
def forward(
self,
hidden_states: torch.Tensor,
attention_mask: torch.Tensor,
position_embeddings: tuple[torch.Tensor, torch.Tensor],
) -> torch.Tensor:
batch_size, seq_len, _ = hidden_states.shape
qkv = self.query_key_value(hidden_states).view(
batch_size, seq_len, self.num_heads + 2 * self.num_kv_heads, self.head_dim
)
query, key, value = qkv.split([self.num_heads, self.num_kv_heads, self.num_kv_heads], dim=2)
query = self.q_norm(query)
key = self.k_norm(key)
# partial rotary: only the first `rotary_dim` channels of each head are rotated
cos, sin = video_rope_cos_sin(*position_embeddings, self.mrope_section)
cos, sin = cos.unsqueeze(2), sin.unsqueeze(2)
rotary_dim = cos.shape[-1]
q_rot, q_pass = query[..., :rotary_dim], query[..., rotary_dim:]
k_rot, k_pass = key[..., :rotary_dim], key[..., rotary_dim:]
query = torch.cat([q_rot * cos + rotate_half(q_rot) * sin, q_pass], dim=-1)
key = torch.cat([k_rot * cos + rotate_half(k_rot) * sin, k_pass], dim=-1)
# (batch, heads, seq_len, head_dim), with the key/value heads repeated for grouped-query attention
query = query.transpose(1, 2)
key = key.repeat_interleave(self.num_heads // self.num_kv_heads, dim=2).transpose(1, 2)
value = value.repeat_interleave(self.num_heads // self.num_kv_heads, dim=2).transpose(1, 2)
# Explicit attention matching the original model's default ("eager") implementation operation for operation.
# A fused kernel changes the rounding, which is enough to flip some near-tied expert choices in the MoE
# layers; at the text encoder's sequence lengths the explicit form costs next to nothing.
attn_weights = torch.matmul(query / math.sqrt(self.head_dim), key.transpose(2, 3)) + attention_mask
attn_weights = torch.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
hidden_states = torch.matmul(attn_weights, value).transpose(1, 2)
return self.dense(hidden_states.flatten(2, 3))
class MingImageTextDecoderLayer(nn.Module):
def __init__(self, config, layer_idx: int):
super().__init__()
self.attention = MingImageTextAttention(config)
self.is_moe = layer_idx >= config.first_k_dense_replace
self.mlp = (
MingImageSparseMoeBlock(config)
if self.is_moe
else MingImageMLP(config.hidden_size, config.intermediate_size)
)
self.input_layernorm = MingImageRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
self.post_attention_layernorm = MingImageRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
def forward(self, hidden_states, attention_mask, position_embeddings, image_mask) -> torch.Tensor:
hidden_states = hidden_states + self.attention(
self.input_layernorm(hidden_states), attention_mask, position_embeddings
)
residual = hidden_states
hidden_states = self.post_attention_layernorm(hidden_states)
hidden_states = self.mlp(hidden_states, image_mask) if self.is_moe else self.mlp(hidden_states)
return residual + hidden_states
class MingImageTextEncoder(ModelMixin, ConfigMixin):
r"""
The Ming-Image text encoder: the language model of the Ming multimodal LLM (a BailingMoeV2 mixture-of-experts
decoder with a separate router for image positions and 3D "video_rope" positions), together with the learnable
image-generation query tokens it is prompted with.
The query tokens are placed in `input_ids` as a block of `image_patch_token` ids between `image_start_token` and
`image_end_token`. They are treated as a `1 x num_query_tokens` image: they are routed by the image router and get
image positions.
Args:
vocab_size (`int`): Vocabulary size.
hidden_size (`int`): Hidden size.
intermediate_size (`int`): FFN width of the dense layers.
moe_intermediate_size (`int`): FFN width of each expert.
num_hidden_layers (`int`): Number of decoder layers.
num_attention_heads (`int`): Number of query heads.
num_key_value_heads (`int`): Number of key/value heads.
head_dim (`int`): Head dimension.
rms_norm_eps (`float`): RMSNorm epsilon.
rope_theta (`float`): RoPE base.
partial_rotary_factor (`float`): Fraction of each head's channels that are rotated.
mrope_section (`list[int]`): Rotary channels of the frame, height and width axes.
rope_time_scale (`float`): Frame-axis position step of image tokens.
spatial_merge_size (`int`): Merge factor between an image grid and its tokens.
num_experts (`int`): Number of routed experts.
num_experts_per_tok (`int`): Experts per token.
n_group (`int`): Number of expert groups for group-limited routing.
topk_group (`int`): Number of groups a token may route to.
routed_scaling_factor (`float`): Scale applied to the routing weights.
num_shared_experts (`int`): Width multiplier of the shared expert.
first_k_dense_replace (`int`): Number of leading layers with a dense FFN instead of experts.
pad_token_id (`int`): Padding token id.
image_patch_token (`int`): Placeholder id of image (and query) tokens.
image_start_token (`int`): Id that opens an image block.
image_end_token (`int`): Id that closes an image block.
num_query_tokens (`int`): Number of image-generation query tokens.
"""
_no_split_modules = ["MingImageTextDecoderLayer"]
@register_to_config
def __init__(
self,
vocab_size: int = 157184,
hidden_size: int = 2048,
intermediate_size: int = 5120,
moe_intermediate_size: int = 512,
num_hidden_layers: int = 20,
num_attention_heads: int = 16,
num_key_value_heads: int = 4,
head_dim: int = 128,
rms_norm_eps: float = 1e-6,
rope_theta: float = 600000.0,
partial_rotary_factor: float = 0.5,
mrope_section: list[int] = [8, 12, 12],
rope_time_scale: float = 2.0,
spatial_merge_size: int = 2,
num_experts: int = 256,
num_experts_per_tok: int = 8,
n_group: int = 8,
topk_group: int = 4,
routed_scaling_factor: float = 2.5,
num_shared_experts: int = 1,
first_k_dense_replace: int = 1,
pad_token_id: int = 156892,
image_patch_token: int = 157157,
image_start_token: int = 157158,
image_end_token: int = 157159,
num_query_tokens: int = 256,
):
super().__init__()
self.word_embeddings = nn.Embedding(vocab_size, hidden_size, pad_token_id)
self.query_tokens = nn.Parameter(torch.zeros(num_query_tokens, hidden_size))
self.layers = nn.ModuleList(
[MingImageTextDecoderLayer(self.config, layer_idx) for layer_idx in range(num_hidden_layers)]
)
self.norm = MingImageRMSNorm(hidden_size, eps=rms_norm_eps)
self.rotary_emb = MingImageRotaryEmbedding(int(head_dim * partial_rotary_factor), rope_theta)
def get_position_ids(self, input_ids: torch.Tensor, attention_mask: torch.Tensor) -> torch.Tensor:
"""3D (frame, height, width) positions: text tokens advance all three axes together; each query-token block
is laid out as a `1 x num_query_tokens` image grid, centred and offset by the text before it."""
position_ids = torch.ones(3, *input_ids.shape, dtype=input_ids.dtype, device=input_ids.device)
query_grid_w = self.config.num_query_tokens
for i in range(input_ids.shape[0]):
tokens = input_ids[i][attention_mask[i] == 1].tolist()
num_images = sum(
1
for idx, token in enumerate(tokens[:-1])
if token == self.config.image_start_token and tokens[idx + 1] == self.config.image_patch_token
)
positions = []
start = 0
for _ in range(num_images):
end = tokens.index(self.config.image_patch_token, start)
text_len = end - start
st_idx = positions[-1][0].max() + 1 if positions else 0
positions.append(torch.arange(text_len).view(1, -1).expand(3, -1) + st_idx)
t_index = torch.zeros(query_grid_w, dtype=torch.long) * self.config.rope_time_scale + text_len + st_idx
h_index = torch.zeros(query_grid_w, dtype=torch.long) + t_index
w_index = torch.arange(query_grid_w) - (query_grid_w - 1) // 2 + t_index
positions.append(torch.stack([t_index, h_index, w_index]))
start = end + query_grid_w
if start < len(tokens):
st_idx = positions[-1][0].max() + 1 if positions else 0
positions.append(torch.arange(len(tokens) - start).view(1, -1).expand(3, -1) + st_idx)
position_ids[..., i, attention_mask[i] == 1] = torch.cat(positions, dim=1).to(position_ids)
return position_ids
def forward(self, input_ids: torch.Tensor, attention_mask: torch.Tensor) -> tuple[torch.Tensor, ...]:
r"""
Args:
input_ids (`torch.Tensor`):
Token ids of shape `(batch_size, seq_len)`, with each item's query-token block already inserted.
attention_mask (`torch.Tensor`):
Padding mask of shape `(batch_size, seq_len)`, 1 for real tokens.
Returns:
`tuple[torch.Tensor, ...]`:
`num_hidden_layers + 1` hidden states of shape `(batch_size, seq_len, hidden_size)`: the input
embeddings, the outputs of layers 1 to `num_hidden_layers - 1`, and the final normalized output.
"""
image_mask = input_ids == self.config.image_patch_token
inputs_embeds = self.word_embeddings(input_ids.clip(0, self.config.vocab_size - 1))
query_tokens = self.query_tokens.to(inputs_embeds.dtype).repeat(input_ids.shape[0], 1)
inputs_embeds = inputs_embeds.masked_scatter(image_mask.unsqueeze(-1), query_tokens)
position_ids = self.get_position_ids(input_ids, attention_mask)
position_embeddings = self.rotary_emb(inputs_embeds, position_ids)
# Additive causal mask that also excludes padded keys, (batch, 1, seq_len, seq_len)
seq_len = input_ids.shape[1]
attend = torch.ones(seq_len, seq_len, dtype=torch.bool, device=input_ids.device).tril()[None, None]
attend = attend & attention_mask.bool()[:, None, None, :]
mask = torch.zeros(attend.shape, dtype=inputs_embeds.dtype, device=input_ids.device)
mask = mask.masked_fill(~attend, torch.finfo(inputs_embeds.dtype).min)
hidden_states = inputs_embeds
all_hidden_states = ()
for layer in self.layers:
all_hidden_states += (hidden_states,)
hidden_states = layer(hidden_states, mask, position_embeddings, image_mask)
all_hidden_states += (self.norm(hidden_states),)
return all_hidden_states
|