added dino2 large support and some fixes

This commit is contained in:
Yousef Rafat 2025-07-13 01:36:08 +03:00
parent dff570e364
commit ee65d6ea41
10 changed files with 108 additions and 77 deletions

View File

@ -124,8 +124,12 @@ def load_clipvision_from_sd(sd, prefix="", convert_keys=False):
json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "clip_vision_config_vitl_336.json") json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "clip_vision_config_vitl_336.json")
else: else:
json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "clip_vision_config_vitl.json") json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "clip_vision_config_vitl.json")
elif "embeddings.patch_embeddings.projection.weight" in sd:
# Dinov2
elif 'encoder.layer.39.layer_scale2.lambda1' in sd:
json_config = os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "image_encoders"), "dino2_giant.json") json_config = os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "image_encoders"), "dino2_giant.json")
elif 'encoder.layer.23.layer_scale2.lambda1' in sd:
json_config = os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "image_encoders"), "dino2_large.json")
else: else:
return None return None

View File

@ -50,12 +50,14 @@ class SwiGLUFFN(torch.nn.Module):
class Dino2Block(torch.nn.Module): class Dino2Block(torch.nn.Module):
def __init__(self, dim, num_heads, layer_norm_eps, dtype, device, operations): def __init__(self, dim, num_heads, layer_norm_eps, dtype, device, operations, use_swiglu_ffn):
super().__init__() super().__init__()
self.attention = Dino2AttentionBlock(dim, num_heads, layer_norm_eps, dtype, device, operations) self.attention = Dino2AttentionBlock(dim, num_heads, layer_norm_eps, dtype, device, operations)
self.layer_scale1 = LayerScale(dim, dtype, device, operations) self.layer_scale1 = LayerScale(dim, dtype, device, operations)
self.layer_scale2 = LayerScale(dim, dtype, device, operations) self.layer_scale2 = LayerScale(dim, dtype, device, operations)
self.mlp = SwiGLUFFN(dim, dtype, device, operations) if use_swiglu_ffn:
self.mlp = SwiGLUFFN(dim, dtype, device, operations)
else: self.mlp = torch.nn.Identity()
self.norm1 = operations.LayerNorm(dim, eps=layer_norm_eps, dtype=dtype, device=device) self.norm1 = operations.LayerNorm(dim, eps=layer_norm_eps, dtype=dtype, device=device)
self.norm2 = operations.LayerNorm(dim, eps=layer_norm_eps, dtype=dtype, device=device) self.norm2 = operations.LayerNorm(dim, eps=layer_norm_eps, dtype=dtype, device=device)
@ -66,9 +68,10 @@ class Dino2Block(torch.nn.Module):
class Dino2Encoder(torch.nn.Module): class Dino2Encoder(torch.nn.Module):
def __init__(self, dim, num_heads, layer_norm_eps, num_layers, dtype, device, operations): def __init__(self, dim, num_heads, layer_norm_eps, num_layers, dtype, device, operations, use_swiglu_ffn):
super().__init__() super().__init__()
self.layer = torch.nn.ModuleList([Dino2Block(dim, num_heads, layer_norm_eps, dtype, device, operations) for _ in range(num_layers)]) self.layer = torch.nn.ModuleList([Dino2Block(dim, num_heads, layer_norm_eps, dtype, device, operations, use_swiglu_ffn = use_swiglu_ffn)
for _ in range(num_layers)])
def forward(self, x, intermediate_output=None): def forward(self, x, intermediate_output=None):
optimized_attention = optimized_attention_for_device(x.device, False, small_input=True) optimized_attention = optimized_attention_for_device(x.device, False, small_input=True)
@ -128,9 +131,10 @@ class Dinov2Model(torch.nn.Module):
dim = config_dict["hidden_size"] dim = config_dict["hidden_size"]
heads = config_dict["num_attention_heads"] heads = config_dict["num_attention_heads"]
layer_norm_eps = config_dict["layer_norm_eps"] layer_norm_eps = config_dict["layer_norm_eps"]
use_swiglu_ffn = config_dict["use_swiglu_ffn"]
self.embeddings = Dino2Embeddings(dim, dtype, device, operations) self.embeddings = Dino2Embeddings(dim, dtype, device, operations)
self.encoder = Dino2Encoder(dim, heads, layer_norm_eps, num_layers, dtype, device, operations) self.encoder = Dino2Encoder(dim, heads, layer_norm_eps, num_layers, dtype, device, operations, use_swiglu_ffn = use_swiglu_ffn)
self.layernorm = operations.LayerNorm(dim, eps=layer_norm_eps, dtype=dtype, device=device) self.layernorm = operations.LayerNorm(dim, eps=layer_norm_eps, dtype=dtype, device=device)
def forward(self, pixel_values, attention_mask=None, intermediate_output=None): def forward(self, pixel_values, attention_mask=None, intermediate_output=None):

View File

@ -0,0 +1,22 @@
{
"hidden_size": 1024,
"use_mask_token": true,
"patch_size": 14,
"image_size": 518,
"num_channels": 3,
"num_attention_heads": 16,
"initializer_range": 0.02,
"attention_probs_dropout_prob": 0.0,
"hidden_dropout_prob": 0.0,
"hidden_act": "gelu",
"mlp_ratio": 4,
"model_type": "dinov2",
"num_hidden_layers": 24,
"layer_norm_eps": 1e-6,
"qkv_bias": true,
"use_swiglu_ffn": false,
"layerscale_value": 1.0,
"drop_path_rate": 0.0,
"image_mean": [0.485, 0.456, 0.406],
"image_std": [0.229, 0.224, 0.225]
}

View File

@ -312,6 +312,8 @@ class CrossAttention(nn.Module):
b, s1, _ = x.shape b, s1, _ = x.shape
_, s2, _ = y.shape _, s2, _ = y.shape
y = y.to(next(self.to_k.parameters()).dtype)
q = self.to_q(x) q = self.to_q(x)
k = self.to_k(y) k = self.to_k(y)
v = self.to_v(y) v = self.to_v(y)
@ -531,14 +533,17 @@ class HunYuanDiTPlain(nn.Module):
qk_norm: bool = True, qk_norm: bool = True,
qkv_bias: bool = False, qkv_bias: bool = False,
num_moe_layers: int = 6, num_moe_layers: int = 6,
guidance_cond_proj_dim = None, guidance_cond_proj_dim = 2048,
norm_type = 'layer', norm_type = 'layer',
num_experts: int = 8, num_experts: int = 8,
moe_top_k: int = 2, moe_top_k: int = 2,
use_fp16: bool = False, use_fp16: bool = False,
dtype = None,
**kwargs **kwargs
): ):
self.dtype = dtype
super().__init__() super().__init__()
self.depth = depth self.depth = depth
@ -581,11 +586,13 @@ class HunYuanDiTPlain(nn.Module):
self.final_layer = FinalLayer(hidden_size, self.out_channels, use_fp16 = use_fp16) self.final_layer = FinalLayer(hidden_size, self.out_channels, use_fp16 = use_fp16)
def forward(self, x, t, contexts, **kwargs): def forward(self, x, t, context, **kwargs):
main_condition = contexts['main'] main_condition = context
time_embedded = self.t_embedder(t, condition = kwargs.get('guidance_cond')) time_embedded = self.t_embedder(t, condition = kwargs.get('guidance_cond'))
x = x.to(dtype = next(self.x_embedder.parameters()).dtype)
x_embedded = self.x_embedder(x) x_embedded = self.x_embedder(x)
combined = torch.cat([time_embedded, x_embedded], dim=1) combined = torch.cat([time_embedded, x_embedded], dim=1)

View File

@ -5,10 +5,13 @@ import numpy as np
from skimage import measure from skimage import measure
from dataclasses import dataclass from dataclasses import dataclass
import torch.nn as nn import torch.nn as nn
from hunyuan3d.vae import (
import sys, os;
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..")))
from comfy.ldm.hunyuan3d.vae import (
CrossAttentionDecoder, Transformer, ResidualCrossAttentionBlock, FourierEmbedder, VanillaVolumeDecoder CrossAttentionDecoder, Transformer, ResidualCrossAttentionBlock, FourierEmbedder, VanillaVolumeDecoder
) )
def fps(src: Tensor, batch: Tensor, sampling_ratio: float, start_random: bool = True): def fps(src: Tensor, batch: Tensor, sampling_ratio: float, start_random: bool = True):
# manually create the pointer vector # manually create the pointer vector
@ -91,12 +94,11 @@ class PointCrossAttention(nn.Module):
self.self_attn = None self.self_attn = None
if layers > 0: if layers > 0:
self.self_attn = Transformer( self.self_attn = Transformer(
n_ctx = num_latents,
width = width, width = width,
heads = heads, heads = heads,
qkv_bias = qkv_bias, qkv_bias = qkv_bias,
qk_norm = qk_norm, qk_norm = qk_norm,
depth = layers layers = layers
) )
if use_ln_post: if use_ln_post:
@ -281,7 +283,7 @@ class Latent2MeshOutput():
vertices: None vertices: None
faces: None faces: None
class SufraceExtractor(): class SurfaceExtractor():
def compute_box_stat(self, bounds, octree_resolution: int): def compute_box_stat(self, bounds, octree_resolution: int):
# if float, turn it into a cube # if float, turn it into a cube
@ -293,14 +295,14 @@ class SufraceExtractor():
grid_size = [int(octree_resolution) + 1, int(octree_resolution) + 1, int(octree_resolution) + 1] grid_size = [int(octree_resolution) + 1, int(octree_resolution) + 1, int(octree_resolution) + 1]
return grid_size, bbox_min, bbox_size return grid_size, bbox_min, bbox_size
def run(self, grid_logit, *, bounds, octree_res, level: float = 0.0, **kwargs): def run(self, grid_logit, *, bounds, octree_resolution, level: float = 0.0, **kwargs):
# grid_logit from volume decoder # grid_logit from volume decoder
# use marching cube algo to turn an sdf to a mesh # use marching cube algo to turn an sdf to a mesh
vertices, faces, _, _ = measure.marching_cubes(grid_logit.cpu().numpy(), vertices, faces, _, _ = measure.marching_cubes(grid_logit.cpu().numpy(),
level, level,
method = "lewiner") method = "lewiner")
grid_size, bbox_min, bbox_size = self.compute_box_stat(bounds = bounds, octree_resolution = octree_res) grid_size, bbox_min, bbox_size = self.compute_box_stat(bounds = bounds, octree_resolution = octree_resolution)
vertices = vertices / grid_size * bbox_size + bbox_min vertices = vertices / grid_size * bbox_size + bbox_min
return vertices, faces return vertices, faces
@ -308,6 +310,8 @@ class SufraceExtractor():
def __call__(self, grid_logits, **kwds): def __call__(self, grid_logits, **kwds):
outputs = [] outputs = []
veritces_list = []
faces_list = []
# loop over the batches # loop over the batches
for i in range(grid_logits.shape[0]): for i in range(grid_logits.shape[0]):
try: try:
@ -315,7 +319,9 @@ class SufraceExtractor():
vertices, faces = self.run(grid_logits[i], **kwds) vertices, faces = self.run(grid_logits[i], **kwds)
vertices = vertices.astype(np.float32) vertices = vertices.astype(np.float32)
faces = np.ascontiguousarray(faces) faces = np.ascontiguousarray(faces)
outputs.append(Latent2MeshOutput(vertices = vertices, faces = faces)) #outputs.append(Latent2MeshOutput(vertices = vertices, faces = faces))
veritces_list.append(vertices)
faces_list.append(faces)
except Exception: except Exception:
import traceback import traceback
@ -552,9 +558,8 @@ class VAE(nn.Module):
pc_sharpedge_size = pc_sharpedge_size) pc_sharpedge_size = pc_sharpedge_size)
self.transformer = Transformer( self.transformer = Transformer(
n_ctx=num_latents,
width=width, width=width,
depth=num_decoder_layers, layers=num_decoder_layers,
heads=heads, heads=heads,
qkv_bias=qkv_bias, qkv_bias=qkv_bias,
qk_norm=qk_norm, qk_norm=qk_norm,
@ -564,7 +569,6 @@ class VAE(nn.Module):
self.geo_decoder = CrossAttentionDecoder( self.geo_decoder = CrossAttentionDecoder(
fourier_embedder = self.fourier_embedder, fourier_embedder = self.fourier_embedder,
out_channels = 1, out_channels = 1,
num_latents = num_latents,
mlp_expand_ratio = geo_decoder_mlp_expand_ratio, mlp_expand_ratio = geo_decoder_mlp_expand_ratio,
downsample_ratio = geo_decoder_downsample_ratio, downsample_ratio = geo_decoder_downsample_ratio,
enable_ln_post = geo_decoder_ln_post, enable_ln_post = geo_decoder_ln_post,
@ -578,7 +582,7 @@ class VAE(nn.Module):
self.post_kl = nn.Linear(embed_dim, width) self.post_kl = nn.Linear(embed_dim, width)
self.volume_decoder = VanillaVolumeDecoder() self.volume_decoder = VanillaVolumeDecoder()
self.surface_extractor = SufraceExtractor() self.surface_extractor = SurfaceExtractor()
def forward(self): def forward(self):
@ -596,8 +600,8 @@ class VAE(nn.Module):
return latents return latents
def decode(self, latents, to_mesh: bool = True, **kwargs): def decode(self, latents, **kwargs):
to_mesh = kwargs.pop("to_mesh", True)
latents = self.post_kl(latents) latents = self.post_kl(latents)
latents = self.transformer(latents) latents = self.transformer(latents)

View File

@ -1203,42 +1203,6 @@ class Hunyuan3Dv2_1(BaseModel):
def __init__(self, model_config, model_type=ModelType.FLOW, device=None): def __init__(self, model_config, model_type=ModelType.FLOW, device=None):
super().__init__(model_config, model_type, device=device, unet_model=comfy.ldm.hunyuan3dv2_1.hunyuandit.HunYuanDiTPlain) super().__init__(model_config, model_type, device=device, unet_model=comfy.ldm.hunyuan3dv2_1.hunyuandit.HunYuanDiTPlain)
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
assert len(w.shape) == 1
w = w * 1000.0
half_dim = embedding_dim // 2
emb = torch.log(torch.tensor(10000.0)) / (half_dim - 1)
emb = torch.exp(torch.arange(half_dim, dtype=dtype) * -emb)
emb = w.to(dtype)[:, None] * emb[None, :]
emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=1)
if embedding_dim % 2 == 1: # zero pad
emb = torch.nn.functional.pad(emb, (0, 1))
assert emb.shape == (w.shape[0], embedding_dim)
return emb
def extra_conds(self, **kwargs):
out = super().extra_conds(**kwargs)
guidance = kwargs.get("guidance", 5.0)
if guidance is not None:
guidance_scale = torch.tensor([guidance], dtype = torch.float32, device = self.device)
guidance_embed = self.get_guidance_scale_embedding(guidance_scale,
self.model.hidden_size,
dtype = next(self.model.parameters()).dtype)
out['guidance_cond'] = comfy.conds.CONDRegular(guidance_embed)
return out
class HiDream(BaseModel): class HiDream(BaseModel):
def __init__(self, model_config, model_type=ModelType.FLOW, device=None): def __init__(self, model_config, model_type=ModelType.FLOW, device=None):
super().__init__(model_config, model_type, device=device, unet_model=comfy.ldm.hidream.model.HiDreamImageTransformer2DModel) super().__init__(model_config, model_type, device=device, unet_model=comfy.ldm.hidream.model.HiDreamImageTransformer2DModel)

View File

@ -399,7 +399,7 @@ def detect_unet_config(state_dict, key_prefix, metadata=None):
dit_config["num_heads"] = 16 dit_config["num_heads"] = 16
dit_config["depth"] = count_blocks(state_dict_keys, f"{key_prefix}blocks.{{}}") dit_config["depth"] = count_blocks(state_dict_keys, f"{key_prefix}blocks.{{}}")
dit_config["qkv_bias"] = False dit_config["qkv_bias"] = False
dit_config["guidance_cond_proj_dim"] = f"{key_prefix}t_embedder.cond_proj.weight" in state_dict_keys dit_config["guidance_cond_proj_dim"] = None#f"{key_prefix}t_embedder.cond_proj.weight" in state_dict_keys
return dit_config return dit_config
if '{}caption_projection.0.linear.weight'.format(key_prefix) in state_dict_keys: # HiDream if '{}caption_projection.0.linear.weight'.format(key_prefix) in state_dict_keys: # HiDream

View File

@ -431,17 +431,6 @@ class VAE:
self.working_dtypes = [torch.bfloat16, torch.float16, torch.float32] self.working_dtypes = [torch.bfloat16, torch.float16, torch.float32]
self.memory_used_encode = lambda shape, dtype: 6000 * shape[3] * shape[4] * model_management.dtype_size(dtype) self.memory_used_encode = lambda shape, dtype: 6000 * shape[3] * shape[4] * model_management.dtype_size(dtype)
self.memory_used_decode = lambda shape, dtype: 7000 * shape[3] * shape[4] * (8 * 8) * model_management.dtype_size(dtype) self.memory_used_decode = lambda shape, dtype: 7000 * shape[3] * shape[4] * (8 * 8) * model_management.dtype_size(dtype)
elif "geo_decoder.cross_attn_decoder.ln_1.bias" in sd:
self.latent_dim = 1
ln_post = "geo_decoder.ln_post.weight" in sd
inner_size = sd["geo_decoder.output_proj.weight"].shape[1]
downsample_ratio = sd["post_kl.weight"].shape[0] // inner_size
mlp_expand = sd["geo_decoder.cross_attn_decoder.mlp.c_fc.weight"].shape[0] // inner_size
self.memory_used_encode = lambda shape, dtype: (1000 * shape[2]) * model_management.dtype_size(dtype) # TODO
self.memory_used_decode = lambda shape, dtype: (1024 * 1024 * 1024 * 2.0) * model_management.dtype_size(dtype) # TODO
ddconfig = {"embed_dim": 64, "num_freqs": 8, "include_pi": False, "heads": 16, "width": 1024, "num_decoder_layers": 16, "qkv_bias": False, "qk_norm": True, "geo_decoder_mlp_expand_ratio": mlp_expand, "geo_decoder_downsample_ratio": downsample_ratio, "geo_decoder_ln_post": ln_post}
self.first_stage_model = comfy.ldm.hunyuan3d.vae.ShapeVAE(**ddconfig)
self.working_dtypes = [torch.float16, torch.bfloat16, torch.float32]
# Hunyuan 3d v2 2.1 # Hunyuan 3d v2 2.1
elif 'geo_decoder.cross_attn_decoder.mlp.c_proj.weight' in sd: elif 'geo_decoder.cross_attn_decoder.mlp.c_proj.weight' in sd:
@ -462,9 +451,22 @@ class VAE:
self.memory_used_decode = lambda shape, dtype, num_layers = 16, kv_cache_multiplier = 2: \ self.memory_used_decode = lambda shape, dtype, num_layers = 16, kv_cache_multiplier = 2: \
estimate_memory(shape, dtype, num_layers, kv_cache_multiplier) estimate_memory(shape, dtype, num_layers, kv_cache_multiplier)
self.first_stage_model = comfy.ldm.hunyuan3dv2_1.vae.ShapeVAE() self.first_stage_model = comfy.ldm.hunyuan3dv2_1.vae.VAE()
self.working_dtypes = [torch.float16, torch.bfloat16, torch.float32] self.working_dtypes = [torch.float16, torch.bfloat16, torch.float32]
elif "geo_decoder.cross_attn_decoder.ln_1.bias" in sd:
self.latent_dim = 1
ln_post = "geo_decoder.ln_post.weight" in sd
inner_size = sd["geo_decoder.output_proj.weight"].shape[1]
downsample_ratio = sd["post_kl.weight"].shape[0] // inner_size
mlp_expand = sd["geo_decoder.cross_attn_decoder.mlp.c_fc.weight"].shape[0] // inner_size
self.memory_used_encode = lambda shape, dtype: (1000 * shape[2]) * model_management.dtype_size(dtype) # TODO
self.memory_used_decode = lambda shape, dtype: (1024 * 1024 * 1024 * 2.0) * model_management.dtype_size(dtype) # TODO
ddconfig = {"embed_dim": 64, "num_freqs": 8, "include_pi": False, "heads": 16, "width": 1024, "num_decoder_layers": 16, "qkv_bias": False, "qk_norm": True, "geo_decoder_mlp_expand_ratio": mlp_expand, "geo_decoder_downsample_ratio": downsample_ratio, "geo_decoder_ln_post": ln_post}
self.first_stage_model = comfy.ldm.hunyuan3d.vae.ShapeVAE(**ddconfig)
self.working_dtypes = [torch.float16, torch.bfloat16, torch.float32]
elif "vocoder.backbone.channel_layers.0.0.bias" in sd: #Ace Step Audio elif "vocoder.backbone.channel_layers.0.0.bias" in sd: #Ace Step Audio
self.first_stage_model = comfy.ldm.ace.vae.music_dcae_pipeline.MusicDCAE(source_sample_rate=44100) self.first_stage_model = comfy.ldm.ace.vae.music_dcae_pipeline.MusicDCAE(source_sample_rate=44100)
self.memory_used_encode = lambda shape, dtype: (shape[2] * 330) * model_management.dtype_size(dtype) self.memory_used_encode = lambda shape, dtype: (shape[2] * 330) * model_management.dtype_size(dtype)
@ -1039,6 +1041,27 @@ def load_state_dict_guess_config(sd, output_vae=True, output_clip=True, output_c
model = None model = None
model_patcher = None model_patcher = None
if isinstance(sd, dict) and all(k in sd for k in ["model", "vae", "conditioner"]):
from collections import OrderedDict
import gc
merged_sd = OrderedDict()
for k, v in sd["model"].items():
merged_sd[f"model.{k}"] = v
for k, v in sd["vae"].items():
merged_sd[f"vae.{k}"] = v
for key, value in sd["conditioner"].items():
merged_sd[f"conditioner.{key}"] = value
sd = merged_sd
del merged_sd
gc.collect()
torch.cuda.empty_cache()
diffusion_model_prefix = model_detection.unet_prefix_from_state_dict(sd) diffusion_model_prefix = model_detection.unet_prefix_from_state_dict(sd)
parameters = comfy.utils.calculate_parameters(sd, diffusion_model_prefix) parameters = comfy.utils.calculate_parameters(sd, diffusion_model_prefix)
weight_dtype = comfy.utils.weight_dtype(sd, diffusion_model_prefix) weight_dtype = comfy.utils.weight_dtype(sd, diffusion_model_prefix)

View File

@ -132,13 +132,15 @@ class VAEDecodeHunyuan3D:
}) })
return (VOXEL(voxel), None) return (VOXEL(voxel), None)
mesh = vae.decode(samples["samples"], to_mesh = True, mesh = vae.decode(samples["samples"],vae_options={
num_chunks = num_chunks, "num_chunks": num_chunks,
octree_resolution = octree_resolution) "octree_resolution": octree_resolution,
"to_mesh": True
})
# ensure batch dim # ensure batch dim
if mesh.verticies.ndim == 2: if mesh.vertices.ndim == 2:
mesh.verticies = mesh.verticies[np.newaxis, ...] mesh.vertices = mesh.vertices[np.newaxis, ...]
mesh.faces = mesh.faces[np.newaxis, ...] mesh.faces = mesh.faces[np.newaxis, ...]
return (None, mesh) return (None, mesh)

View File

@ -28,3 +28,4 @@ soundfile
av>=14.2.0 av>=14.2.0
pydantic~=2.0 pydantic~=2.0
pydantic-settings~=2.0 pydantic-settings~=2.0
scikit-image # for 3D mesh generation (marching cubes)