@@ -0,0 +1,35 @@
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.arrow filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
||||
*.ftz filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
*.joblib filter=lfs diff=lfs merge=lfs -text
|
||||
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
||||
*.model filter=lfs diff=lfs merge=lfs -text
|
||||
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
||||
*.npy filter=lfs diff=lfs merge=lfs -text
|
||||
*.npz filter=lfs diff=lfs merge=lfs -text
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ot filter=lfs diff=lfs merge=lfs -text
|
||||
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||
*.pickle filter=lfs diff=lfs merge=lfs -text
|
||||
*.pkl filter=lfs diff=lfs merge=lfs -text
|
||||
*.pt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
||||
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tflite filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
||||
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
library_name: diffusers
|
||||
pipeline_tag: image-to-image
|
||||
license: apache-2.0
|
||||
---
|
||||
# Model Card for StableNormal
|
||||
|
||||
This repository contains the weights of StableNormal: Reducing Diffusion Variance for Stable and Sharp Normal
|
||||
|
||||
## Usage
|
||||
|
||||
See the Github repository: https://github.com/Stable-X/StableNormal regarding installation instructions.
|
||||
|
||||
The model can then be used as follows:
|
||||
|
||||
```python
|
||||
import torch
|
||||
from PIL import Image
|
||||
# Load an image
|
||||
input_image = Image.open("path/to/your/image.jpg")
|
||||
# Create predictor instance
|
||||
predictor = torch.hub.load("hugoycj/StableNormal", "StableNormal_turbo", trust_repo=True, yoso_version='yoso-normal-v1-8-1')
|
||||
# Generate normal map using alpha channel for masking
|
||||
normal_map = predictor(rgba_image, data_type="object") # Will mask out background, if alpha channel is avalible, else use birefnet
|
||||
# Apply the model to the image
|
||||
normal_image = predictor(input_image)
|
||||
# Save or display the result
|
||||
normal_image.save("output/normal_map.png")
|
||||
```
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"_class_name": "ControlNetVAEModel",
|
||||
"_diffusers_version": "0.28.0",
|
||||
"_name_or_path": "weights/yoso-normal-v1-8-1/controlnet",
|
||||
"act_fn": "silu",
|
||||
"addition_embed_type": null,
|
||||
"addition_embed_type_num_heads": 64,
|
||||
"addition_time_embed_dim": null,
|
||||
"attention_head_dim": [
|
||||
5,
|
||||
10,
|
||||
20,
|
||||
20
|
||||
],
|
||||
"block_out_channels": [
|
||||
320,
|
||||
640,
|
||||
1280,
|
||||
1280
|
||||
],
|
||||
"class_embed_type": null,
|
||||
"conditioning_channels": 3,
|
||||
"conditioning_embedding_out_channels": [
|
||||
16,
|
||||
32,
|
||||
96,
|
||||
256
|
||||
],
|
||||
"controlnet_conditioning_channel_order": "rgb",
|
||||
"cross_attention_dim": 1024,
|
||||
"down_block_types": [
|
||||
"CrossAttnDownBlock2D",
|
||||
"CrossAttnDownBlock2D",
|
||||
"CrossAttnDownBlock2D",
|
||||
"DownBlock2D"
|
||||
],
|
||||
"downsample_padding": 1,
|
||||
"encoder_hid_dim": null,
|
||||
"encoder_hid_dim_type": null,
|
||||
"flip_sin_to_cos": true,
|
||||
"freq_shift": 0,
|
||||
"global_pool_conditions": false,
|
||||
"in_channels": 4,
|
||||
"layers_per_block": 2,
|
||||
"mid_block_scale_factor": 1,
|
||||
"mid_block_type": "UNetMidBlock2DCrossAttn",
|
||||
"norm_eps": 1e-05,
|
||||
"norm_num_groups": 32,
|
||||
"num_attention_heads": null,
|
||||
"num_class_embeds": null,
|
||||
"only_cross_attention": false,
|
||||
"projection_class_embeddings_input_dim": null,
|
||||
"resnet_time_scale_shift": "default",
|
||||
"transformer_layers_per_block": 1,
|
||||
"upcast_attention": true,
|
||||
"use_linear_projection": true
|
||||
}
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
# Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
import torch
|
||||
from torch import nn
|
||||
from torch.nn import functional as F
|
||||
|
||||
from diffusers.configuration_utils import ConfigMixin, register_to_config
|
||||
from diffusers.loaders.single_file_model import FromOriginalModelMixin
|
||||
from diffusers.utils import BaseOutput, logging
|
||||
from diffusers.models.attention_processor import (
|
||||
ADDED_KV_ATTENTION_PROCESSORS,
|
||||
CROSS_ATTENTION_PROCESSORS,
|
||||
AttentionProcessor,
|
||||
AttnAddedKVProcessor,
|
||||
AttnProcessor,
|
||||
)
|
||||
from diffusers.models.embeddings import TextImageProjection, TextImageTimeEmbedding, TextTimeEmbedding, TimestepEmbedding, Timesteps
|
||||
from diffusers.models.modeling_utils import ModelMixin
|
||||
from diffusers.models.unets.unet_2d_blocks import (
|
||||
CrossAttnDownBlock2D,
|
||||
DownBlock2D,
|
||||
UNetMidBlock2D,
|
||||
UNetMidBlock2DCrossAttn,
|
||||
get_down_block,
|
||||
)
|
||||
from diffusers.models.unets.unet_2d_condition import UNet2DConditionModel
|
||||
from diffusers.models.controlnet import ControlNetOutput
|
||||
from diffusers.models import ControlNetModel
|
||||
|
||||
import pdb
|
||||
|
||||
|
||||
class ControlNetVAEModel(ControlNetModel):
|
||||
def forward(
|
||||
self,
|
||||
sample: torch.Tensor,
|
||||
timestep: Union[torch.Tensor, float, int],
|
||||
encoder_hidden_states: torch.Tensor,
|
||||
controlnet_cond: torch.Tensor = None,
|
||||
conditioning_scale: float = 1.0,
|
||||
class_labels: Optional[torch.Tensor] = None,
|
||||
timestep_cond: Optional[torch.Tensor] = None,
|
||||
attention_mask: Optional[torch.Tensor] = None,
|
||||
added_cond_kwargs: Optional[Dict[str, torch.Tensor]] = None,
|
||||
cross_attention_kwargs: Optional[Dict[str, Any]] = None,
|
||||
guess_mode: bool = False,
|
||||
return_dict: bool = True,
|
||||
) -> Union[ControlNetOutput, Tuple[Tuple[torch.Tensor, ...], torch.Tensor]]:
|
||||
"""
|
||||
The [`ControlNetVAEModel`] forward method.
|
||||
|
||||
Args:
|
||||
sample (`torch.Tensor`):
|
||||
The noisy input tensor.
|
||||
timestep (`Union[torch.Tensor, float, int]`):
|
||||
The number of timesteps to denoise an input.
|
||||
encoder_hidden_states (`torch.Tensor`):
|
||||
The encoder hidden states.
|
||||
controlnet_cond (`torch.Tensor`):
|
||||
The conditional input tensor of shape `(batch_size, sequence_length, hidden_size)`.
|
||||
conditioning_scale (`float`, defaults to `1.0`):
|
||||
The scale factor for ControlNet outputs.
|
||||
class_labels (`torch.Tensor`, *optional*, defaults to `None`):
|
||||
Optional class labels for conditioning. Their embeddings will be summed with the timestep embeddings.
|
||||
timestep_cond (`torch.Tensor`, *optional*, defaults to `None`):
|
||||
Additional conditional embeddings for timestep. If provided, the embeddings will be summed with the
|
||||
timestep_embedding passed through the `self.time_embedding` layer to obtain the final timestep
|
||||
embeddings.
|
||||
attention_mask (`torch.Tensor`, *optional*, defaults to `None`):
|
||||
An attention mask of shape `(batch, key_tokens)` is applied to `encoder_hidden_states`. If `1` the mask
|
||||
is kept, otherwise if `0` it is discarded. Mask will be converted into a bias, which adds large
|
||||
negative values to the attention scores corresponding to "discard" tokens.
|
||||
added_cond_kwargs (`dict`):
|
||||
Additional conditions for the Stable Diffusion XL UNet.
|
||||
cross_attention_kwargs (`dict[str]`, *optional*, defaults to `None`):
|
||||
A kwargs dictionary that if specified is passed along to the `AttnProcessor`.
|
||||
guess_mode (`bool`, defaults to `False`):
|
||||
In this mode, the ControlNet encoder tries its best to recognize the input content of the input even if
|
||||
you remove all prompts. A `guidance_scale` between 3.0 and 5.0 is recommended.
|
||||
return_dict (`bool`, defaults to `True`):
|
||||
Whether or not to return a [`~models.controlnet.ControlNetOutput`] instead of a plain tuple.
|
||||
|
||||
Returns:
|
||||
[`~models.controlnet.ControlNetOutput`] **or** `tuple`:
|
||||
If `return_dict` is `True`, a [`~models.controlnet.ControlNetOutput`] is returned, otherwise a tuple is
|
||||
returned where the first element is the sample tensor.
|
||||
"""
|
||||
# check channel order
|
||||
|
||||
|
||||
channel_order = self.config.controlnet_conditioning_channel_order
|
||||
|
||||
if channel_order == "rgb":
|
||||
# in rgb order by default
|
||||
...
|
||||
elif channel_order == "bgr":
|
||||
controlnet_cond = torch.flip(controlnet_cond, dims=[1])
|
||||
else:
|
||||
raise ValueError(f"unknown `controlnet_conditioning_channel_order`: {channel_order}")
|
||||
|
||||
# prepare attention_mask
|
||||
if attention_mask is not None:
|
||||
attention_mask = (1 - attention_mask.to(sample.dtype)) * -10000.0
|
||||
attention_mask = attention_mask.unsqueeze(1)
|
||||
|
||||
# 1. time
|
||||
timesteps = timestep
|
||||
if not torch.is_tensor(timesteps):
|
||||
# TODO: this requires sync between CPU and GPU. So try to pass timesteps as tensors if you can
|
||||
# This would be a good case for the `match` statement (Python 3.10+)
|
||||
is_mps = sample.device.type == "mps"
|
||||
if isinstance(timestep, float):
|
||||
dtype = torch.float32 if is_mps else torch.float64
|
||||
else:
|
||||
dtype = torch.int32 if is_mps else torch.int64
|
||||
timesteps = torch.tensor([timesteps], dtype=dtype, device=sample.device)
|
||||
elif len(timesteps.shape) == 0:
|
||||
timesteps = timesteps[None].to(sample.device)
|
||||
|
||||
# broadcast to batch dimension in a way that's compatible with ONNX/Core ML
|
||||
timesteps = timesteps.expand(sample.shape[0])
|
||||
|
||||
t_emb = self.time_proj(timesteps)
|
||||
|
||||
# timesteps does not contain any weights and will always return f32 tensors
|
||||
# but time_embedding might actually be running in fp16. so we need to cast here.
|
||||
# there might be better ways to encapsulate this.
|
||||
t_emb = t_emb.to(dtype=sample.dtype)
|
||||
|
||||
emb = self.time_embedding(t_emb, timestep_cond)
|
||||
aug_emb = None
|
||||
|
||||
if self.class_embedding is not None:
|
||||
if class_labels is None:
|
||||
raise ValueError("class_labels should be provided when num_class_embeds > 0")
|
||||
|
||||
if self.config.class_embed_type == "timestep":
|
||||
class_labels = self.time_proj(class_labels)
|
||||
|
||||
class_emb = self.class_embedding(class_labels).to(dtype=self.dtype)
|
||||
emb = emb + class_emb
|
||||
|
||||
if self.config.addition_embed_type is not None:
|
||||
if self.config.addition_embed_type == "text":
|
||||
aug_emb = self.add_embedding(encoder_hidden_states)
|
||||
|
||||
elif self.config.addition_embed_type == "text_time":
|
||||
if "text_embeds" not in added_cond_kwargs:
|
||||
raise ValueError(
|
||||
f"{self.__class__} has the config param `addition_embed_type` set to 'text_time' which requires the keyword argument `text_embeds` to be passed in `added_cond_kwargs`"
|
||||
)
|
||||
text_embeds = added_cond_kwargs.get("text_embeds")
|
||||
if "time_ids" not in added_cond_kwargs:
|
||||
raise ValueError(
|
||||
f"{self.__class__} has the config param `addition_embed_type` set to 'text_time' which requires the keyword argument `time_ids` to be passed in `added_cond_kwargs`"
|
||||
)
|
||||
time_ids = added_cond_kwargs.get("time_ids")
|
||||
time_embeds = self.add_time_proj(time_ids.flatten())
|
||||
time_embeds = time_embeds.reshape((text_embeds.shape[0], -1))
|
||||
|
||||
add_embeds = torch.concat([text_embeds, time_embeds], dim=-1)
|
||||
add_embeds = add_embeds.to(emb.dtype)
|
||||
aug_emb = self.add_embedding(add_embeds)
|
||||
|
||||
|
||||
emb = emb + aug_emb if aug_emb is not None else emb
|
||||
# 2. pre-process
|
||||
sample = self.conv_in(sample)
|
||||
|
||||
# 3. down
|
||||
down_block_res_samples = (sample,)
|
||||
for downsample_block in self.down_blocks:
|
||||
if hasattr(downsample_block, "has_cross_attention") and downsample_block.has_cross_attention:
|
||||
sample, res_samples = downsample_block(
|
||||
hidden_states=sample,
|
||||
temb=emb,
|
||||
encoder_hidden_states=encoder_hidden_states,
|
||||
attention_mask=attention_mask,
|
||||
cross_attention_kwargs=cross_attention_kwargs,
|
||||
)
|
||||
else:
|
||||
sample, res_samples = downsample_block(hidden_states=sample, temb=emb)
|
||||
|
||||
down_block_res_samples += res_samples
|
||||
|
||||
# 4. mid
|
||||
if self.mid_block is not None:
|
||||
if hasattr(self.mid_block, "has_cross_attention") and self.mid_block.has_cross_attention:
|
||||
sample = self.mid_block(
|
||||
sample,
|
||||
emb,
|
||||
encoder_hidden_states=encoder_hidden_states,
|
||||
attention_mask=attention_mask,
|
||||
cross_attention_kwargs=cross_attention_kwargs,
|
||||
)
|
||||
else:
|
||||
sample = self.mid_block(sample, emb)
|
||||
|
||||
# 5. Control net blocks
|
||||
|
||||
controlnet_down_block_res_samples = ()
|
||||
|
||||
# NOTE that controlnet downblock is zeroconv, we discard
|
||||
for down_block_res_sample, controlnet_block in zip(down_block_res_samples, self.controlnet_down_blocks):
|
||||
down_block_res_sample = down_block_res_sample
|
||||
controlnet_down_block_res_samples = controlnet_down_block_res_samples + (down_block_res_sample,)
|
||||
|
||||
down_block_res_samples = controlnet_down_block_res_samples
|
||||
|
||||
mid_block_res_sample = sample
|
||||
|
||||
# 6. scaling
|
||||
if guess_mode and not self.config.global_pool_conditions:
|
||||
scales = torch.logspace(-1, 0, len(down_block_res_samples) + 1, device=sample.device) # 0.1 to 1.0
|
||||
scales = scales * conditioning_scale
|
||||
down_block_res_samples = [sample * scale for sample, scale in zip(down_block_res_samples, scales)]
|
||||
mid_block_res_sample = mid_block_res_sample * scales[-1] # last one
|
||||
else:
|
||||
down_block_res_samples = [sample * conditioning_scale for sample in down_block_res_samples]
|
||||
mid_block_res_sample = mid_block_res_sample * conditioning_scale
|
||||
|
||||
if self.config.global_pool_conditions:
|
||||
down_block_res_samples = [
|
||||
torch.mean(sample, dim=(2, 3), keepdim=True) for sample in down_block_res_samples
|
||||
]
|
||||
mid_block_res_sample = torch.mean(mid_block_res_sample, dim=(2, 3), keepdim=True)
|
||||
|
||||
if not return_dict:
|
||||
return (down_block_res_samples, mid_block_res_sample)
|
||||
|
||||
return ControlNetOutput(
|
||||
down_block_res_samples=down_block_res_samples, mid_block_res_sample=mid_block_res_sample
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"_class_name": "YOSONormalsPipeline",
|
||||
"_diffusers_version": "0.28.0",
|
||||
"controlnet": [
|
||||
"controlnetvae",
|
||||
"ControlNetVAEModel"
|
||||
],
|
||||
"requires_safety_checker": true,
|
||||
"unet": [
|
||||
"diffusers",
|
||||
"UNet2DConditionModel"
|
||||
],
|
||||
"vae": [
|
||||
"diffusers",
|
||||
"AutoencoderKL"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"_class_name": "UNet2DConditionModel",
|
||||
"_diffusers_version": "0.28.0",
|
||||
"_name_or_path": "weights/yoso-normal-v1-8-1/unet",
|
||||
"act_fn": "silu",
|
||||
"addition_embed_type": null,
|
||||
"addition_embed_type_num_heads": 64,
|
||||
"addition_time_embed_dim": null,
|
||||
"attention_head_dim": [
|
||||
5,
|
||||
10,
|
||||
20,
|
||||
20
|
||||
],
|
||||
"attention_type": "default",
|
||||
"block_out_channels": [
|
||||
320,
|
||||
640,
|
||||
1280,
|
||||
1280
|
||||
],
|
||||
"center_input_sample": false,
|
||||
"class_embed_type": null,
|
||||
"class_embeddings_concat": false,
|
||||
"conv_in_kernel": 3,
|
||||
"conv_out_kernel": 3,
|
||||
"cross_attention_dim": 1024,
|
||||
"cross_attention_norm": null,
|
||||
"down_block_types": [
|
||||
"CrossAttnDownBlock2D",
|
||||
"CrossAttnDownBlock2D",
|
||||
"CrossAttnDownBlock2D",
|
||||
"DownBlock2D"
|
||||
],
|
||||
"downsample_padding": 1,
|
||||
"dropout": 0.0,
|
||||
"dual_cross_attention": false,
|
||||
"encoder_hid_dim": null,
|
||||
"encoder_hid_dim_type": null,
|
||||
"flip_sin_to_cos": true,
|
||||
"freq_shift": 0,
|
||||
"in_channels": 4,
|
||||
"layers_per_block": 2,
|
||||
"mid_block_only_cross_attention": null,
|
||||
"mid_block_scale_factor": 1,
|
||||
"mid_block_type": "UNetMidBlock2DCrossAttn",
|
||||
"norm_eps": 1e-05,
|
||||
"norm_num_groups": 32,
|
||||
"num_attention_heads": null,
|
||||
"num_class_embeds": null,
|
||||
"only_cross_attention": false,
|
||||
"out_channels": 4,
|
||||
"projection_class_embeddings_input_dim": null,
|
||||
"resnet_out_scale_factor": 1.0,
|
||||
"resnet_skip_time_act": false,
|
||||
"resnet_time_scale_shift": "default",
|
||||
"reverse_transformer_layers_per_block": null,
|
||||
"sample_size": 128,
|
||||
"time_cond_proj_dim": null,
|
||||
"time_embedding_act_fn": null,
|
||||
"time_embedding_dim": null,
|
||||
"time_embedding_type": "positional",
|
||||
"timestep_post_act": null,
|
||||
"transformer_layers_per_block": 1,
|
||||
"up_block_types": [
|
||||
"UpBlock2D",
|
||||
"CrossAttnUpBlock2D",
|
||||
"CrossAttnUpBlock2D",
|
||||
"CrossAttnUpBlock2D"
|
||||
],
|
||||
"upcast_attention": true,
|
||||
"use_linear_projection": true
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"_class_name": "AutoencoderKL",
|
||||
"_diffusers_version": "0.28.0",
|
||||
"_name_or_path": "weights/yoso-normal-v1-8-1/vae",
|
||||
"act_fn": "silu",
|
||||
"block_out_channels": [
|
||||
128,
|
||||
256,
|
||||
512,
|
||||
512
|
||||
],
|
||||
"down_block_types": [
|
||||
"DownEncoderBlock2D",
|
||||
"DownEncoderBlock2D",
|
||||
"DownEncoderBlock2D",
|
||||
"DownEncoderBlock2D"
|
||||
],
|
||||
"force_upcast": true,
|
||||
"in_channels": 3,
|
||||
"latent_channels": 4,
|
||||
"latents_mean": null,
|
||||
"latents_std": null,
|
||||
"layers_per_block": 2,
|
||||
"norm_num_groups": 32,
|
||||
"out_channels": 3,
|
||||
"sample_size": 1024,
|
||||
"scaling_factor": 0.18215,
|
||||
"up_block_types": [
|
||||
"UpDecoderBlock2D",
|
||||
"UpDecoderBlock2D",
|
||||
"UpDecoderBlock2D",
|
||||
"UpDecoderBlock2D"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.arrow filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
||||
*.ftz filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
*.joblib filter=lfs diff=lfs merge=lfs -text
|
||||
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
||||
*.model filter=lfs diff=lfs merge=lfs -text
|
||||
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
||||
*.npy filter=lfs diff=lfs merge=lfs -text
|
||||
*.npz filter=lfs diff=lfs merge=lfs -text
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ot filter=lfs diff=lfs merge=lfs -text
|
||||
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||
*.pickle filter=lfs diff=lfs merge=lfs -text
|
||||
*.pkl filter=lfs diff=lfs merge=lfs -text
|
||||
*.pt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
||||
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tflite filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
||||
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
library_name: trellis
|
||||
pipeline_tag: image-to-3d
|
||||
license: mit
|
||||
language:
|
||||
- en
|
||||
---
|
||||
|
||||
An improved normal conditioned version of TRELLIS.
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "SLatMeshDecoder",
|
||||
"args": {
|
||||
"resolution": 64,
|
||||
"model_channels": 768,
|
||||
"latent_channels": 8,
|
||||
"num_blocks": 12,
|
||||
"num_heads": 12,
|
||||
"mlp_ratio": 4,
|
||||
"attn_mode": "swin",
|
||||
"window_size": 8,
|
||||
"use_fp16": true,
|
||||
"representation_config": {
|
||||
"use_color": true
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "SLatFlowModel",
|
||||
"args": {
|
||||
"resolution": 64,
|
||||
"in_channels": 8,
|
||||
"out_channels": 8,
|
||||
"model_channels": 1024,
|
||||
"cond_channels": 1024,
|
||||
"num_blocks": 24,
|
||||
"num_heads": 16,
|
||||
"mlp_ratio": 4,
|
||||
"patch_size": 2,
|
||||
"num_io_res_blocks": 2,
|
||||
"io_block_channels": [128],
|
||||
"pe_mode": "ape",
|
||||
"qk_rms_norm": true,
|
||||
"use_fp16": true
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
|
||||
{
|
||||
"name": "SparseStructureDecoder",
|
||||
"args": {
|
||||
"out_channels": 1,
|
||||
"latent_channels": 8,
|
||||
"num_res_blocks": 2,
|
||||
"num_res_blocks_middle": 2,
|
||||
"channels": [512, 128, 32],
|
||||
"use_fp16": true
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "SparseStructureFlowModel",
|
||||
"args": {
|
||||
"resolution": 16,
|
||||
"in_channels": 8,
|
||||
"out_channels": 8,
|
||||
"model_channels": 1024,
|
||||
"cond_channels": 1024,
|
||||
"num_blocks": 24,
|
||||
"num_heads": 16,
|
||||
"mlp_ratio": 4,
|
||||
"patch_size": 1,
|
||||
"pe_mode": "ape",
|
||||
"qk_rms_norm": true,
|
||||
"use_fp16": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "TrellisImageTo3DPipeline",
|
||||
"args": {
|
||||
"models": {
|
||||
"sparse_structure_decoder": "ckpts/ss_dec_conv3d_16l8_fp16",
|
||||
"sparse_structure_flow_model": "ckpts/ss_flow_normal_dit_L_16l8_fp16",
|
||||
"slat_decoder_mesh": "ckpts/slat_dec_mesh_swin8_B_64l8m256c_fp16",
|
||||
"slat_flow_model": "ckpts/slat_flow_normal_dit_L_64l8p2_fp16"
|
||||
},
|
||||
"sparse_structure_sampler": {
|
||||
"name": "FlowEulerGuidanceIntervalSampler",
|
||||
"args": {
|
||||
"sigma_min": 1e-5
|
||||
},
|
||||
"params": {
|
||||
"steps": 25,
|
||||
"cfg_strength": 5.0,
|
||||
"cfg_interval": [0.5, 1.0],
|
||||
"rescale_t": 3.0
|
||||
}
|
||||
},
|
||||
"slat_sampler": {
|
||||
"name": "FlowEulerGuidanceIntervalSampler",
|
||||
"args": {
|
||||
"sigma_min": 1e-5
|
||||
},
|
||||
"params": {
|
||||
"steps": 25,
|
||||
"cfg_strength": 5.0,
|
||||
"cfg_interval": [0.5, 1.0],
|
||||
"rescale_t": 3.0
|
||||
}
|
||||
},
|
||||
"slat_normalization": {
|
||||
"mean": [
|
||||
-2.1687545776367188,
|
||||
-0.004347046371549368,
|
||||
-0.13352349400520325,
|
||||
-0.08418072760105133,
|
||||
-0.5271206498146057,
|
||||
0.7238689064979553,
|
||||
-1.1414450407028198,
|
||||
1.2039363384246826
|
||||
],
|
||||
"std": [
|
||||
2.377650737762451,
|
||||
2.386378288269043,
|
||||
2.124418020248413,
|
||||
2.1748552322387695,
|
||||
2.663944721221924,
|
||||
2.371192216873169,
|
||||
2.6217446327209473,
|
||||
2.684523105621338
|
||||
]
|
||||
},
|
||||
"image_cond_model": "dinov2_vitl14_reg"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.arrow filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
||||
*.ftz filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
*.joblib filter=lfs diff=lfs merge=lfs -text
|
||||
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
||||
*.model filter=lfs diff=lfs merge=lfs -text
|
||||
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
||||
*.npy filter=lfs diff=lfs merge=lfs -text
|
||||
*.npz filter=lfs diff=lfs merge=lfs -text
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ot filter=lfs diff=lfs merge=lfs -text
|
||||
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||
*.pickle filter=lfs diff=lfs merge=lfs -text
|
||||
*.pkl filter=lfs diff=lfs merge=lfs -text
|
||||
*.pt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
||||
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tflite filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
||||
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
license: mit
|
||||
pipeline_tag: image-to-3d
|
||||
tags:
|
||||
- triposg
|
||||
- 3d-generation
|
||||
- rectified-flow
|
||||
---
|
||||
# TripoSG-scribble - Fast 3D Shape Prototyping with Scribble and Prompt
|
||||
|
||||
TripoSG-scribble converts a scribble image and a text prompt to a 3D shape. TripoSG-scribble is a variant of TripoSG. TripoSG is a state-of-the-art image-to-3D generation foundation model that leverages large-scale rectified flow transformers to produce high-fidelity 3D shapes from single images.
|
||||
|
||||
## Model Description
|
||||
|
||||
### Model Architecture
|
||||
|
||||
TripoSG utilizes a novel architecture combining:
|
||||
- Rectified Flow (RF) based Transformer for stable, linear trajectory modeling
|
||||
- Advanced VAE with SDF-based representation and hybrid geometric supervision
|
||||
- Cross-attention mechanism for image feature condition
|
||||
- 1.5B parameters operating on 2048 latent tokens
|
||||
|
||||
For inference efficiency, TripoSG-scribble is different from TripoSG in:
|
||||
- TripoSG-scribble is a CFG-distilled model and should be used with CFG=0
|
||||
- TripoSG-scribble is trained with 512 latent tokens
|
||||
|
||||
## Intended Uses
|
||||
|
||||
This model is designed for:
|
||||
- Converting scribble image and text prompt to high-quality 3D meshes
|
||||
- Creative and design applications
|
||||
- Gaming and VFX asset creation
|
||||
- Prototyping and visualization
|
||||
|
||||
## Requirements
|
||||
|
||||
- CUDA-capable GPU (>8GB VRAM)
|
||||
|
||||
## Usage
|
||||
|
||||
For detailed usage instructions, please visit our [GitHub repository](https://github.com/VAST-AI-Research/TripoSG).
|
||||
|
||||
## About
|
||||
|
||||
TripoSG-scribble is developed by [Tripo](https://www.tripo3d.ai), [VAST AI Research](https://github.com/orgs/VAST-AI-Research), pushing the boundaries of 3D Generative AI.
|
||||
For more information:
|
||||
- [GitHub Repository](https://github.com/VAST-AI-Research/TripoSG)
|
||||
- [Paper](https://arxiv.org/abs/2502.06608)
|
||||
- [Gradio Demo](https://huggingface.co/spaces/VAST-AI/TripoSG-scribble)
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"crop_size": {
|
||||
"height": 224,
|
||||
"width": 224
|
||||
},
|
||||
"do_center_crop": true,
|
||||
"do_convert_rgb": true,
|
||||
"do_normalize": true,
|
||||
"do_rescale": true,
|
||||
"do_resize": true,
|
||||
"image_mean": [
|
||||
0.485,
|
||||
0.456,
|
||||
0.406
|
||||
],
|
||||
"image_processor_type": "BitImageProcessor",
|
||||
"image_std": [
|
||||
0.229,
|
||||
0.224,
|
||||
0.225
|
||||
],
|
||||
"resample": 3,
|
||||
"rescale_factor": 0.00392156862745098,
|
||||
"size": {
|
||||
"shortest_edge": 256
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"apply_layernorm": true,
|
||||
"architectures": [
|
||||
"Dinov2Model"
|
||||
],
|
||||
"attention_probs_dropout_prob": 0.0,
|
||||
"drop_path_rate": 0.0,
|
||||
"hidden_act": "gelu",
|
||||
"hidden_dropout_prob": 0.0,
|
||||
"hidden_size": 1024,
|
||||
"image_size": 518,
|
||||
"initializer_range": 0.02,
|
||||
"layer_norm_eps": 1e-06,
|
||||
"layerscale_value": 1.0,
|
||||
"mlp_ratio": 4,
|
||||
"model_type": "dinov2",
|
||||
"num_attention_heads": 16,
|
||||
"num_channels": 3,
|
||||
"num_hidden_layers": 24,
|
||||
"out_features": [
|
||||
"stage24"
|
||||
],
|
||||
"out_indices": [
|
||||
24
|
||||
],
|
||||
"patch_size": 14,
|
||||
"qkv_bias": true,
|
||||
"reshape_hidden_states": true,
|
||||
"stage_names": [
|
||||
"stem",
|
||||
"stage1",
|
||||
"stage2",
|
||||
"stage3",
|
||||
"stage4",
|
||||
"stage5",
|
||||
"stage6",
|
||||
"stage7",
|
||||
"stage8",
|
||||
"stage9",
|
||||
"stage10",
|
||||
"stage11",
|
||||
"stage12",
|
||||
"stage13",
|
||||
"stage14",
|
||||
"stage15",
|
||||
"stage16",
|
||||
"stage17",
|
||||
"stage18",
|
||||
"stage19",
|
||||
"stage20",
|
||||
"stage21",
|
||||
"stage22",
|
||||
"stage23",
|
||||
"stage24"
|
||||
],
|
||||
"torch_dtype": "float16",
|
||||
"transformers_version": "4.50.3",
|
||||
"use_mask_token": true,
|
||||
"use_swiglu_ffn": false
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"_class_name": "TripoSGScribblePipeline",
|
||||
"_diffusers_version": "0.33.1",
|
||||
"feature_extractor_dinov2": [
|
||||
"transformers",
|
||||
"BitImageProcessor"
|
||||
],
|
||||
"image_encoder_dinov2": [
|
||||
"transformers",
|
||||
"Dinov2Model"
|
||||
],
|
||||
"scheduler": [
|
||||
"TripoSG.schedulers.scheduling_rectified_flow",
|
||||
"RectifiedFlowScheduler"
|
||||
],
|
||||
"text_encoder": [
|
||||
"transformers",
|
||||
"CLIPTextModelWithProjection"
|
||||
],
|
||||
"tokenizer": [
|
||||
"transformers",
|
||||
"CLIPTokenizer"
|
||||
],
|
||||
"transformer": [
|
||||
"TripoSG.models.transformers.triposg_transformer",
|
||||
"TripoSGDiTModel"
|
||||
],
|
||||
"vae": [
|
||||
"TripoSG.models.autoencoders.autoencoder_kl_triposg",
|
||||
"TripoSGVAEModel"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"_class_name": "RectifiedFlowScheduler",
|
||||
"_diffusers_version": "0.33.1",
|
||||
"num_train_timesteps": 1000,
|
||||
"shift": 1,
|
||||
"use_dynamic_shifting": false
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"architectures": [
|
||||
"CLIPTextModelWithProjection"
|
||||
],
|
||||
"attention_dropout": 0.0,
|
||||
"bos_token_id": 0,
|
||||
"dropout": 0.0,
|
||||
"eos_token_id": 2,
|
||||
"hidden_act": "quick_gelu",
|
||||
"hidden_size": 768,
|
||||
"initializer_factor": 1.0,
|
||||
"initializer_range": 0.02,
|
||||
"intermediate_size": 3072,
|
||||
"layer_norm_eps": 1e-05,
|
||||
"max_position_embeddings": 77,
|
||||
"model_type": "clip_text_model",
|
||||
"num_attention_heads": 12,
|
||||
"num_hidden_layers": 12,
|
||||
"pad_token_id": 1,
|
||||
"projection_dim": 768,
|
||||
"torch_dtype": "float16",
|
||||
"transformers_version": "4.50.3",
|
||||
"vocab_size": 49408
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"bos_token": {
|
||||
"content": "<|startoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"eos_token": {
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"pad_token": {
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"unk_token": {
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"add_prefix_space": false,
|
||||
"added_tokens_decoder": {
|
||||
"49406": {
|
||||
"content": "<|startoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"49407": {
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
}
|
||||
},
|
||||
"bos_token": "<|startoftext|>",
|
||||
"clean_up_tokenization_spaces": false,
|
||||
"do_lower_case": true,
|
||||
"eos_token": "<|endoftext|>",
|
||||
"errors": "replace",
|
||||
"extra_special_tokens": {},
|
||||
"model_max_length": 77,
|
||||
"pad_token": "<|endoftext|>",
|
||||
"tokenizer_class": "CLIPTokenizer",
|
||||
"unk_token": "<|endoftext|>"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"_class_name": "TripoSGDiTModel",
|
||||
"_diffusers_version": "0.33.1",
|
||||
"cross_attention_2_dim": 1024,
|
||||
"cross_attention_dim": 768,
|
||||
"in_channels": 64,
|
||||
"num_attention_heads": 16,
|
||||
"num_layers": 21,
|
||||
"use_cross_attention_2": true,
|
||||
"width": 2048
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"_class_name": "TripoSGVAEModel",
|
||||
"_diffusers_version": "0.33.1",
|
||||
"embed_frequency": 8,
|
||||
"embed_include_pi": false,
|
||||
"embedding_type": "frequency",
|
||||
"in_channels": 3,
|
||||
"latent_channels": 64,
|
||||
"num_attention_heads": 8,
|
||||
"num_layers_decoder": 16,
|
||||
"num_layers_encoder": 8,
|
||||
"width_decoder": 1024,
|
||||
"width_encoder": 512
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.arrow filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
||||
*.ftz filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
*.joblib filter=lfs diff=lfs merge=lfs -text
|
||||
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
||||
*.model filter=lfs diff=lfs merge=lfs -text
|
||||
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
||||
*.npy filter=lfs diff=lfs merge=lfs -text
|
||||
*.npz filter=lfs diff=lfs merge=lfs -text
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ot filter=lfs diff=lfs merge=lfs -text
|
||||
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||
*.pickle filter=lfs diff=lfs merge=lfs -text
|
||||
*.pkl filter=lfs diff=lfs merge=lfs -text
|
||||
*.pt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
||||
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tflite filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
||||
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar.gz filter=lfs diff=lfs merge=lfs -text
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
license: mit
|
||||
pipeline_tag: image-to-3d
|
||||
tags:
|
||||
- triposg
|
||||
- 3d-generation
|
||||
- rectified-flow
|
||||
---
|
||||
# TripoSG - High-Fidelity 3D Shape Synthesis using Large-Scale Rectified Flow Models
|
||||
|
||||
TripoSG is a state-of-the-art image-to-3D generation foundation model that leverages large-scale rectified flow transformers to produce high-fidelity 3D shapes from single images.
|
||||
|
||||
## Model Description
|
||||
|
||||
### Model Architecture
|
||||
|
||||
TripoSG utilizes a novel architecture combining:
|
||||
- Rectified Flow (RF) based Transformer for stable, linear trajectory modeling
|
||||
- Advanced VAE with SDF-based representation and hybrid geometric supervision
|
||||
- Cross-attention mechanism for image feature condition
|
||||
- 1.5B parameters operating on 2048 latent tokens
|
||||
|
||||
## Intended Uses
|
||||
|
||||
This model is designed for:
|
||||
- Converting single images to high-quality 3D meshes
|
||||
- Creative and design applications
|
||||
- Gaming and VFX asset creation
|
||||
- Prototyping and visualization
|
||||
|
||||
## Requirements
|
||||
|
||||
- CUDA-capable GPU (>8GB VRAM)
|
||||
|
||||
## Usage
|
||||
|
||||
For detailed usage instructions, please visit our [GitHub repository](https://github.com/VAST-AI-Research/TripoSG).
|
||||
|
||||
## About
|
||||
|
||||
TripoSG is developed by [Tripo](https://www.tripo3d.ai), [VAST AI Research](https://github.com/orgs/VAST-AI-Research), pushing the boundaries of 3D Generative AI.
|
||||
For more information:
|
||||
- [GitHub Repository](https://github.com/VAST-AI-Research/TripoSG)
|
||||
- [Paper](https://arxiv.org/abs/2502.06608)
|
||||
- [Gradio Demo](https://huggingface.co/spaces/VAST-AI/TripoSG)
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"crop_size": {
|
||||
"height": 224,
|
||||
"width": 224
|
||||
},
|
||||
"do_center_crop": true,
|
||||
"do_convert_rgb": true,
|
||||
"do_normalize": true,
|
||||
"do_rescale": true,
|
||||
"do_resize": true,
|
||||
"image_mean": [
|
||||
0.485,
|
||||
0.456,
|
||||
0.406
|
||||
],
|
||||
"image_processor_type": "BitImageProcessor",
|
||||
"image_std": [
|
||||
0.229,
|
||||
0.224,
|
||||
0.225
|
||||
],
|
||||
"resample": 3,
|
||||
"rescale_factor": 0.00392156862745098,
|
||||
"size": {
|
||||
"shortest_edge": 256
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"_name_or_path": "facebook/dinov2-large",
|
||||
"apply_layernorm": true,
|
||||
"architectures": [
|
||||
"Dinov2Model"
|
||||
],
|
||||
"attention_probs_dropout_prob": 0.0,
|
||||
"drop_path_rate": 0.0,
|
||||
"hidden_act": "gelu",
|
||||
"hidden_dropout_prob": 0.0,
|
||||
"hidden_size": 1024,
|
||||
"image_size": 518,
|
||||
"initializer_range": 0.02,
|
||||
"layer_norm_eps": 1e-06,
|
||||
"layerscale_value": 1.0,
|
||||
"mlp_ratio": 4,
|
||||
"model_type": "dinov2",
|
||||
"num_attention_heads": 16,
|
||||
"num_channels": 3,
|
||||
"num_hidden_layers": 24,
|
||||
"out_features": [
|
||||
"stage24"
|
||||
],
|
||||
"out_indices": [
|
||||
24
|
||||
],
|
||||
"patch_size": 14,
|
||||
"qkv_bias": true,
|
||||
"reshape_hidden_states": true,
|
||||
"stage_names": [
|
||||
"stem",
|
||||
"stage1",
|
||||
"stage2",
|
||||
"stage3",
|
||||
"stage4",
|
||||
"stage5",
|
||||
"stage6",
|
||||
"stage7",
|
||||
"stage8",
|
||||
"stage9",
|
||||
"stage10",
|
||||
"stage11",
|
||||
"stage12",
|
||||
"stage13",
|
||||
"stage14",
|
||||
"stage15",
|
||||
"stage16",
|
||||
"stage17",
|
||||
"stage18",
|
||||
"stage19",
|
||||
"stage20",
|
||||
"stage21",
|
||||
"stage22",
|
||||
"stage23",
|
||||
"stage24"
|
||||
],
|
||||
"torch_dtype": "float32",
|
||||
"transformers_version": "4.45.2",
|
||||
"use_swiglu_ffn": false
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"_class_name": "TripoSGPipeline",
|
||||
"_diffusers_version": "0.30.3",
|
||||
"feature_extractor_dinov2": [
|
||||
"transformers",
|
||||
"BitImageProcessor"
|
||||
],
|
||||
"image_encoder_dinov2": [
|
||||
"transformers",
|
||||
"Dinov2Model"
|
||||
],
|
||||
"scheduler": [
|
||||
"TripoSG.schedulers.scheduling_rectified_flow",
|
||||
"RectifiedFlowScheduler"
|
||||
],
|
||||
"transformer": [
|
||||
"TripoSG.models.transformers.triposg_transformer",
|
||||
"TripoSGDiTModel"
|
||||
],
|
||||
"vae": [
|
||||
"TripoSG.models.autoencoders.autoencoder_kl_triposg",
|
||||
"TripoSGVAEModel"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"_class_name": "RectifiedFlowScheduler",
|
||||
"_diffusers_version": "0.30.3",
|
||||
"num_train_timesteps": 1000,
|
||||
"shift": 1,
|
||||
"use_dynamic_shifting": false
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"_class_name": "TripoSGDiTModel",
|
||||
"_diffusers_version": "0.30.3",
|
||||
"cross_attention_dim": 1024,
|
||||
"in_channels": 64,
|
||||
"num_attention_heads": 16,
|
||||
"num_layers": 21,
|
||||
"width": 2048
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"_class_name": "Tripo2VAEModel",
|
||||
"_diffusers_version": "0.30.3",
|
||||
"embed_frequency": 8,
|
||||
"embed_include_pi": false,
|
||||
"embedding_type": "frequency",
|
||||
"in_channels": 3,
|
||||
"latent_channels": 64,
|
||||
"num_attention_heads": 8,
|
||||
"num_layers_decoder": 16,
|
||||
"num_layers_encoder": 8,
|
||||
"width_decoder": 1024,
|
||||
"width_encoder": 512
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
---
|
||||
library_name: hunyuan3d-2.0
|
||||
license: other
|
||||
license_name: tencent-hunyuan-community
|
||||
license_link: https://huggingface.co/tencent/Hunyuan3D-2/blob/main/LICENSE.txt
|
||||
language:
|
||||
- en
|
||||
- zh
|
||||
tags:
|
||||
- image-to-3d
|
||||
- text-to-3d
|
||||
pipeline_tag: image-to-3d
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/images/teaser.jpg">
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<a href=https://3d.hunyuan.tencent.com target="_blank"><img src=https://img.shields.io/badge/Hunyuan3D-black.svg?logo=homepage height=22px></a>
|
||||
<a href=https://huggingface.co/spaces/tencent/Hunyuan3D-2 target="_blank"><img src=https://img.shields.io/badge/%F0%9F%A4%97%20Demo-276cb4.svg height=22px></a>
|
||||
<a href=https://huggingface.co/tencent/Hunyuan3D-2 target="_blank"><img src=https://img.shields.io/badge/%F0%9F%A4%97%20Models-d96902.svg height=22px></a>
|
||||
<a href=https://3d-models.hunyuan.tencent.com/ target="_blank"><img src= https://img.shields.io/badge/Page-bb8a2e.svg?logo=github height=22px></a>
|
||||
<a href=https://discord.gg/GuaWYwzKbX target="_blank"><img src= https://img.shields.io/badge/Discord-white.svg?logo=discord height=22px></a>
|
||||
<a href=https://github.com/Tencent/Hunyuan3D-2/blob/main/assets/report/Tencent_Hunyuan3D_2_0.pdf target="_blank"><img src=https://img.shields.io/badge/Report-b5212f.svg?logo=arxiv height=22px></a>
|
||||
</div>
|
||||
|
||||
|
||||
[//]: # ( <a href=# target="_blank"><img src=https://img.shields.io/badge/Report-b5212f.svg?logo=arxiv height=22px></a>)
|
||||
|
||||
[//]: # ( <a href=# target="_blank"><img src= https://img.shields.io/badge/Colab-8f2628.svg?logo=googlecolab height=22px></a>)
|
||||
|
||||
[//]: # ( <a href="#"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/v/mulankit?logo=pypi" height=22px></a>)
|
||||
|
||||
<br>
|
||||
<p align="center">
|
||||
“ Living out everyone’s imagination on creating and manipulating 3D assets.”
|
||||
</p>
|
||||
|
||||
This repository contains the models of the paper [Hunyuan3D 2.0: Scaling Diffusion Models for High Resolution Textured 3D Assets Generation](https://huggingface.co/papers/2501.12202).
|
||||
For code and more details on how to use it, refer to the [Github repository](https://github.com/Tencent/Hunyuan3D-2).
|
||||
|
||||
## 🔥 News
|
||||
|
||||
- Jan 21, 2025: 💬 Release [Hunyuan3D 2.0](https://huggingface.co/spaces/tencent/Hunyuan3D-2). Please give it a try!
|
||||
|
||||
## **Abstract**
|
||||
|
||||
We present Hunyuan3D 2.0, an advanced large-scale 3D synthesis system for generating high-resolution textured 3D assets.
|
||||
This system includes two foundation components: a large-scale shape generation model - Hunyuan3D-DiT, and a large-scale
|
||||
texture synthesis model - Hunyuan3D-Paint.
|
||||
The shape generative model, built on a scalable flow-based diffusion transformer, aims to create geometry that properly
|
||||
aligns with a given condition image, laying a solid foundation for downstream applications.
|
||||
The texture synthesis model, benefiting from strong geometric and diffusion priors, produces high-resolution and vibrant
|
||||
texture maps for either generated or hand-crafted meshes.
|
||||
Furthermore, we build Hunyuan3D-Studio - a versatile, user-friendly production platform that simplifies the re-creation
|
||||
process of 3D assets. It allows both professional and amateur users to manipulate or even animate their meshes
|
||||
efficiently.
|
||||
We systematically evaluate our models, showing that Hunyuan3D 2.0 outperforms previous state-of-the-art models,
|
||||
including the open-source models and closed-source models in geometry details, condition alignment, texture quality, and
|
||||
e.t.c.
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/images/system.jpg">
|
||||
</p>
|
||||
|
||||
## ☯️ **Hunyuan3D 2.0**
|
||||
|
||||
### Architecture
|
||||
|
||||
Hunyuan3D 2.0 features a two-stage generation pipeline, starting with the creation of a bare mesh, followed by the
|
||||
synthesis of a texture map for that mesh. This strategy is effective for decoupling the difficulties of shape and
|
||||
texture generation and also provides flexibility for texturing either generated or handcrafted meshes.
|
||||
|
||||
<p align="left">
|
||||
<img src="assets/images/arch.jpg">
|
||||
</p>
|
||||
|
||||
### Performance
|
||||
|
||||
We have evaluated Hunyuan3D 2.0 with other open-source as well as close-source 3d-generation methods.
|
||||
The numerical results indicate that Hunyuan3D 2.0 surpasses all baselines in the quality of generated textured 3D assets
|
||||
and the condition following ability.
|
||||
|
||||
| Model | CMMD(⬇) | FID_CLIP(⬇) | FID(⬇) | CLIP-score(⬆) |
|
||||
|-------------------------|-----------|-------------|-------------|---------------|
|
||||
| Top Open-source Model1 | 3.591 | 54.639 | 289.287 | 0.787 |
|
||||
| Top Close-source Model1 | 3.600 | 55.866 | 305.922 | 0.779 |
|
||||
| Top Close-source Model2 | 3.368 | 49.744 | 294.628 | 0.806 |
|
||||
| Top Close-source Model3 | 3.218 | 51.574 | 295.691 | 0.799 |
|
||||
| Hunyuan3D 2.0 | **3.193** | **49.165** | **282.429** | **0.809** |
|
||||
|
||||
Generation results of Hunyuan3D 2.0:
|
||||
<p align="left">
|
||||
<img src="assets/images/e2e-1.gif" height=300>
|
||||
<img src="assets/images/e2e-2.gif" height=300>
|
||||
</p>
|
||||
|
||||
### Pretrained Models
|
||||
|
||||
| Model | Date | Huggingface |
|
||||
|----------------------|------------|--------------------------------------------------------|
|
||||
| Hunyuan3D-DiT-v2-0 | 2025-01-21 | [Download](https://huggingface.co/tencent/Hunyuan3D-2) |
|
||||
| Hunyuan3D-Paint-v2-0 | 2025-01-21 | [Download](https://huggingface.co/tencent/Hunyuan3D-2) |
|
||||
| Hunyuan3D-Delight-v2-0 | 2025-01-21 | [Download](https://huggingface.co/tencent/Hunyuan3D-2/tree/main/hunyuan3d-delight-v2-0) |
|
||||
|
||||
## 🤗 Get Started with Hunyuan3D 2.0
|
||||
|
||||
You may follow the next steps to use Hunyuan3D 2.0 via code or the Gradio App.
|
||||
|
||||
### Install Requirements
|
||||
|
||||
Please install Pytorch via the [official](https://pytorch.org/) site. Then install the other requirements via
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
# for texture
|
||||
cd hy3dgen/texgen/custom_rasterizer
|
||||
python3 setup.py install
|
||||
cd ../../..
|
||||
cd hy3dgen/texgen/differentiable_renderer
|
||||
bash compile_mesh_painter.sh OR python3 setup.py install (on Windows)
|
||||
```
|
||||
|
||||
### API Usage
|
||||
|
||||
We designed a diffusers-like API to use our shape generation model - Hunyuan3D-DiT and texture synthesis model -
|
||||
Hunyuan3D-Paint.
|
||||
|
||||
You could assess **Hunyuan3D-DiT** via:
|
||||
|
||||
```python
|
||||
from hy3dgen.shapegen import Hunyuan3DDiTFlowMatchingPipeline
|
||||
|
||||
pipeline = Hunyuan3DDiTFlowMatchingPipeline.from_pretrained('tencent/Hunyuan3D-2')
|
||||
mesh = pipeline(image='assets/demo.png')[0]
|
||||
```
|
||||
|
||||
The output mesh is a [trimesh object](https://trimesh.org/trimesh.html), which you could save to glb/obj (or other
|
||||
format) file.
|
||||
|
||||
For **Hunyuan3D-Paint**, do the following:
|
||||
|
||||
```python
|
||||
from hy3dgen.texgen import Hunyuan3DPaintPipeline
|
||||
from hy3dgen.shapegen import Hunyuan3DDiTFlowMatchingPipeline
|
||||
|
||||
# let's generate a mesh first
|
||||
pipeline = Hunyuan3DDiTFlowMatchingPipeline.from_pretrained('tencent/Hunyuan3D-2')
|
||||
mesh = pipeline(image='assets/demo.png')[0]
|
||||
|
||||
pipeline = Hunyuan3DPaintPipeline.from_pretrained('tencent/Hunyuan3D-2')
|
||||
mesh = pipeline(mesh, image='assets/demo.png')
|
||||
```
|
||||
|
||||
Please visit [minimal_demo.py](minimal_demo.py) for more advanced usage, such as **text to 3D** and **texture generation
|
||||
for handcrafted mesh**.
|
||||
|
||||
### Gradio App
|
||||
|
||||
You could also host a [Gradio](https://www.gradio.app/) App in your own computer via:
|
||||
|
||||
```bash
|
||||
pip3 install gradio==3.39.0
|
||||
python3 gradio_app.py
|
||||
```
|
||||
|
||||
Don't forget to visit [Hunyuan3D](https://3d.hunyuan.tencent.com) for quick use, if you don't want to host yourself.
|
||||
|
||||
## 📑 Open-Source Plan
|
||||
|
||||
- [x] Inference Code
|
||||
- [x] Model Checkpoints
|
||||
- [x] Technical Report
|
||||
- [ ] ComfyUI
|
||||
- [ ] TensorRT Version
|
||||
|
||||
## 🔗 BibTeX
|
||||
|
||||
If you found this repository helpful, please cite our report:
|
||||
|
||||
```bibtex
|
||||
@misc{hunyuan3d22025tencent,
|
||||
title={Hunyuan3D 2.0: Scaling Diffusion Models for High Resolution Textured 3D Assets Generation},
|
||||
author={Tencent Hunyuan3D Team},
|
||||
year={2025},
|
||||
eprint={2501.12202},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.CV}
|
||||
}
|
||||
|
||||
@misc{yang2024tencent,
|
||||
title={Tencent Hunyuan3D-1.0: A Unified Framework for Text-to-3D and Image-to-3D Generation},
|
||||
author={Tencent Hunyuan3D Team},
|
||||
year={2024},
|
||||
eprint={2411.02293},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.CV}
|
||||
}
|
||||
```
|
||||
|
||||
## Community Resources
|
||||
|
||||
Thanks for the contributions of community members, here we have these great extensions of Hunyuan3D 2.0:
|
||||
|
||||
- [ComfyUI-Hunyuan3DWrapper](https://github.com/kijai/ComfyUI-Hunyuan3DWrapper)
|
||||
- [Hunyuan3D-2-for-windows](https://github.com/sdbds/Hunyuan3D-2-for-windows)
|
||||
- [📦 A bundle for running on Windows | 整合包](https://github.com/YanWenKun/Comfy3D-WinPortable/releases/tag/r8-hunyuan3d2)
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
We would like to thank the contributors to
|
||||
the [DINOv2](https://github.com/facebookresearch/dinov2), [Stable Diffusion](https://github.com/Stability-AI/stablediffusion), [FLUX](https://github.com/black-forest-labs/flux), [diffusers](https://github.com/huggingface/diffusers)
|
||||
and [HuggingFace](https://huggingface.co) repositories, for their open research and exploration.
|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://star-history.com/#Tencent/Hunyuan3D-2&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=Tencent/Hunyuan3D-2&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=Tencent/Hunyuan3D-2&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=Tencent/Hunyuan3D-2&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 148 KiB |
@@ -0,0 +1,69 @@
|
||||
model:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.Hunyuan3DDiT
|
||||
params:
|
||||
in_channels: 64
|
||||
context_in_dim: 1536
|
||||
hidden_size: 1024
|
||||
mlp_ratio: 4.0
|
||||
num_heads: 16
|
||||
depth: 16
|
||||
depth_single_blocks: 32
|
||||
axes_dim: [ 64 ]
|
||||
theta: 10000
|
||||
qkv_bias: true
|
||||
guidance_embed: true
|
||||
|
||||
vae:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 3072
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 0.9990943042622529
|
||||
|
||||
conditioner:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.SingleImageEncoder
|
||||
params:
|
||||
main_image_encoder:
|
||||
type: DinoImageEncoder # dino giant
|
||||
kwargs:
|
||||
config:
|
||||
attention_probs_dropout_prob: 0.0
|
||||
drop_path_rate: 0.0
|
||||
hidden_act: gelu
|
||||
hidden_dropout_prob: 0.0
|
||||
hidden_size: 1536
|
||||
image_size: 518
|
||||
initializer_range: 0.02
|
||||
layer_norm_eps: 1.e-6
|
||||
layerscale_value: 1.0
|
||||
mlp_ratio: 4
|
||||
model_type: dinov2
|
||||
num_attention_heads: 24
|
||||
num_channels: 3
|
||||
num_hidden_layers: 40
|
||||
patch_size: 14
|
||||
qkv_bias: true
|
||||
torch_dtype: float32
|
||||
use_swiglu_ffn: true
|
||||
image_size: 518
|
||||
|
||||
scheduler:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.schedulers.FlowMatchEulerDiscreteScheduler
|
||||
params:
|
||||
num_train_timesteps: 1000
|
||||
|
||||
image_processor:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.preprocessors.ImageProcessorV2
|
||||
params:
|
||||
size: 512
|
||||
border_ratio: 0.15
|
||||
|
||||
pipeline:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.pipelines.Hunyuan3DDiTFlowMatchingPipeline
|
||||
@@ -0,0 +1,70 @@
|
||||
model:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.Hunyuan3DDiT
|
||||
params:
|
||||
in_channels: 64
|
||||
context_in_dim: 1536
|
||||
hidden_size: 1024
|
||||
mlp_ratio: 4.0
|
||||
num_heads: 16
|
||||
depth: 16
|
||||
depth_single_blocks: 32
|
||||
axes_dim: [ 64 ]
|
||||
theta: 10000
|
||||
qkv_bias: true
|
||||
guidance_embed: true
|
||||
|
||||
vae:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 3072
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 0.9990943042622529
|
||||
|
||||
conditioner:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.SingleImageEncoder
|
||||
params:
|
||||
main_image_encoder:
|
||||
type: DinoImageEncoder # dino giant
|
||||
kwargs:
|
||||
config:
|
||||
attention_probs_dropout_prob: 0.0
|
||||
drop_path_rate: 0.0
|
||||
hidden_act: gelu
|
||||
hidden_dropout_prob: 0.0
|
||||
hidden_size: 1536
|
||||
image_size: 518
|
||||
initializer_range: 0.02
|
||||
layer_norm_eps: 1.e-6
|
||||
layerscale_value: 1.0
|
||||
mlp_ratio: 4
|
||||
model_type: dinov2
|
||||
num_attention_heads: 24
|
||||
num_channels: 3
|
||||
num_hidden_layers: 40
|
||||
patch_size: 14
|
||||
qkv_bias: true
|
||||
torch_dtype: float32
|
||||
use_swiglu_ffn: true
|
||||
image_size: 518
|
||||
|
||||
scheduler:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.schedulers.ConsistencyFlowMatchEulerDiscreteScheduler
|
||||
params:
|
||||
num_train_timesteps: 1000
|
||||
pcm_timesteps: 100
|
||||
|
||||
image_processor:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.preprocessors.ImageProcessorV2
|
||||
params:
|
||||
size: 512
|
||||
border_ratio: 0.15
|
||||
|
||||
pipeline:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.pipelines.Hunyuan3DDiTFlowMatchingPipeline
|
||||
@@ -0,0 +1,35 @@
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.arrow filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
||||
*.ftz filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
*.joblib filter=lfs diff=lfs merge=lfs -text
|
||||
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
||||
*.model filter=lfs diff=lfs merge=lfs -text
|
||||
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
||||
*.npy filter=lfs diff=lfs merge=lfs -text
|
||||
*.npz filter=lfs diff=lfs merge=lfs -text
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ot filter=lfs diff=lfs merge=lfs -text
|
||||
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||
*.pickle filter=lfs diff=lfs merge=lfs -text
|
||||
*.pkl filter=lfs diff=lfs merge=lfs -text
|
||||
*.pt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
||||
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tflite filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
||||
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
license: openrail++
|
||||
tags:
|
||||
- stable-diffusion
|
||||
- text-to-image
|
||||
---
|
||||
|
||||
# SD v2.1-base with Zero Terminal SNR (LAION Aesthetic 6+)
|
||||
|
||||
This model is used in [Diffusion Model with Perceptual Loss](https://arxiv.org/abs/2401.00110) paper as the MSE baseline.
|
||||
|
||||
This model is trained using zero terminal SNR schedule following [Common Diffusion Noise Schedules and Sample Steps are Flawed](https://arxiv.org/abs/2305.08891) paper on LAION aesthetic 6+ data.
|
||||
|
||||
This model is finetuned from [stabilityai/stable-diffusion-2-1-base](https://huggingface.co/stabilityai/stable-diffusion-2-1-base).
|
||||
|
||||
This model is meant for research demonstration, not for production use.
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from diffusers import StableDiffusionPipeline
|
||||
prompt = "A young girl smiling"
|
||||
pipe = StableDiffusionPipeline.from_pretrained("ByteDance/sd2.1-base-zsnr-laionaes6").to("cuda")
|
||||
pipe(prompt, guidance_scale=7.5, guidance_rescale=0.7).images[0].save("out.jpg")
|
||||
```
|
||||
|
||||
## Related Models
|
||||
|
||||
* [bytedance/sd2.1-base-zsnr-laionaes5](https://huggingface.co/ByteDance/sd2.1-base-zsnr-laionaes5)
|
||||
* [bytedance/sd2.1-base-zsnr-laionaes6](https://huggingface.co/ByteDance/sd2.1-base-zsnr-laionaes6)
|
||||
* [bytedance/sd2.1-base-zsnr-laionaes6-perceptual](https://huggingface.co/ByteDance/sd2.1-base-zsnr-laionaes6-perceptual)
|
||||
|
||||
|
||||
## Cite as
|
||||
```
|
||||
@misc{lin2024diffusion,
|
||||
title={Diffusion Model with Perceptual Loss},
|
||||
author={Shanchuan Lin and Xiao Yang},
|
||||
year={2024},
|
||||
eprint={2401.00110},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.CV}
|
||||
}
|
||||
|
||||
@misc{lin2023common,
|
||||
title={Common Diffusion Noise Schedules and Sample Steps are Flawed},
|
||||
author={Shanchuan Lin and Bingchen Liu and Jiashi Li and Xiao Yang},
|
||||
year={2023},
|
||||
eprint={2305.08891},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.CV}
|
||||
}
|
||||
```
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"crop_size": 224,
|
||||
"do_center_crop": true,
|
||||
"do_convert_rgb": true,
|
||||
"do_normalize": true,
|
||||
"do_resize": true,
|
||||
"feature_extractor_type": "CLIPFeatureExtractor",
|
||||
"image_mean": [
|
||||
0.48145466,
|
||||
0.4578275,
|
||||
0.40821073
|
||||
],
|
||||
"image_std": [
|
||||
0.26862954,
|
||||
0.26130258,
|
||||
0.27577711
|
||||
],
|
||||
"resample": 3,
|
||||
"size": 224
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"_name_or_path": "D:\\.cache\\huggingface\\hub\\models--sudo-ai--zero123plus-v1.1\\snapshots\\36df7de980afd15f80b2e1a4e9a920d7020e2654\\vision_encoder",
|
||||
"architectures": [
|
||||
"CLIPVisionModelWithProjection"
|
||||
],
|
||||
"attention_dropout": 0.0,
|
||||
"dropout": 0.0,
|
||||
"hidden_act": "gelu",
|
||||
"hidden_size": 1280,
|
||||
"image_size": 224,
|
||||
"initializer_factor": 1.0,
|
||||
"initializer_range": 0.02,
|
||||
"intermediate_size": 5120,
|
||||
"layer_norm_eps": 1e-05,
|
||||
"model_type": "clip_vision_model",
|
||||
"num_attention_heads": 16,
|
||||
"num_channels": 3,
|
||||
"num_hidden_layers": 32,
|
||||
"patch_size": 14,
|
||||
"projection_dim": 1024,
|
||||
"torch_dtype": "float16",
|
||||
"transformers_version": "4.36.0"
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"crop_size": {
|
||||
"height": 224,
|
||||
"width": 224
|
||||
},
|
||||
"do_center_crop": true,
|
||||
"do_convert_rgb": true,
|
||||
"do_normalize": true,
|
||||
"do_rescale": true,
|
||||
"do_resize": true,
|
||||
"image_mean": [
|
||||
0.48145466,
|
||||
0.4578275,
|
||||
0.40821073
|
||||
],
|
||||
"image_processor_type": "CLIPImageProcessor",
|
||||
"image_std": [
|
||||
0.26862954,
|
||||
0.26130258,
|
||||
0.27577711
|
||||
],
|
||||
"resample": 3,
|
||||
"rescale_factor": 0.00392156862745098,
|
||||
"size": {
|
||||
"shortest_edge": 224
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"_class_name": "StableDiffusionPipeline",
|
||||
"_diffusers_version": "0.23.1",
|
||||
"feature_extractor": [
|
||||
"transformers",
|
||||
"CLIPImageProcessor"
|
||||
],
|
||||
"requires_safety_checker": false,
|
||||
"safety_checker": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"scheduler": [
|
||||
"diffusers",
|
||||
"DDIMScheduler"
|
||||
],
|
||||
"text_encoder": [
|
||||
"transformers",
|
||||
"CLIPTextModel"
|
||||
],
|
||||
"tokenizer": [
|
||||
"transformers",
|
||||
"CLIPTokenizer"
|
||||
],
|
||||
"image_encoder": [
|
||||
"transformers",
|
||||
"CLIPVisionModelWithProjection"
|
||||
],
|
||||
"unet": [
|
||||
"modules",
|
||||
"UNet2p5DConditionModel"
|
||||
],
|
||||
"vae": [
|
||||
"diffusers",
|
||||
"AutoencoderKL"
|
||||
]
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"_class_name": "DDIMScheduler",
|
||||
"_diffusers_version": "0.23.1",
|
||||
"beta_end": 0.012,
|
||||
"beta_schedule": "scaled_linear",
|
||||
"beta_start": 0.00085,
|
||||
"clip_sample": false,
|
||||
"num_train_timesteps": 1000,
|
||||
"prediction_type": "v_prediction",
|
||||
"set_alpha_to_one": true,
|
||||
"steps_offset": 1,
|
||||
"trained_betas": null,
|
||||
"timestep_spacing": "trailing",
|
||||
"rescale_betas_zero_snr": true
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"_name_or_path": "stabilityai/stable-diffusion-2",
|
||||
"architectures": [
|
||||
"CLIPTextModel"
|
||||
],
|
||||
"attention_dropout": 0.0,
|
||||
"bos_token_id": 0,
|
||||
"dropout": 0.0,
|
||||
"eos_token_id": 2,
|
||||
"hidden_act": "gelu",
|
||||
"hidden_size": 1024,
|
||||
"initializer_factor": 1.0,
|
||||
"initializer_range": 0.02,
|
||||
"intermediate_size": 4096,
|
||||
"layer_norm_eps": 1e-05,
|
||||
"max_position_embeddings": 77,
|
||||
"model_type": "clip_text_model",
|
||||
"num_attention_heads": 16,
|
||||
"num_hidden_layers": 23,
|
||||
"pad_token_id": 1,
|
||||
"projection_dim": 512,
|
||||
"torch_dtype": "float32",
|
||||
"transformers_version": "4.25.0.dev0",
|
||||
"vocab_size": 49408
|
||||
}
|
||||
+48895
File diff suppressed because it is too large
Load Diff
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"bos_token": {
|
||||
"content": "<|startoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"eos_token": {
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"pad_token": "!",
|
||||
"unk_token": {
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"add_prefix_space": false,
|
||||
"bos_token": {
|
||||
"__type": "AddedToken",
|
||||
"content": "<|startoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"do_lower_case": true,
|
||||
"eos_token": {
|
||||
"__type": "AddedToken",
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"errors": "replace",
|
||||
"model_max_length": 77,
|
||||
"name_or_path": "stabilityai/stable-diffusion-2",
|
||||
"pad_token": "<|endoftext|>",
|
||||
"special_tokens_map_file": "./special_tokens_map.json",
|
||||
"tokenizer_class": "CLIPTokenizer",
|
||||
"unk_token": {
|
||||
"__type": "AddedToken",
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": true,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
}
|
||||
}
|
||||
+49410
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"_class_name": "UNet2DConditionModel",
|
||||
"_diffusers_version": "0.10.0.dev0",
|
||||
"act_fn": "silu",
|
||||
"attention_head_dim": [
|
||||
5,
|
||||
10,
|
||||
20,
|
||||
20
|
||||
],
|
||||
"block_out_channels": [
|
||||
320,
|
||||
640,
|
||||
1280,
|
||||
1280
|
||||
],
|
||||
"center_input_sample": false,
|
||||
"cross_attention_dim": 1024,
|
||||
"down_block_types": [
|
||||
"CrossAttnDownBlock2D",
|
||||
"CrossAttnDownBlock2D",
|
||||
"CrossAttnDownBlock2D",
|
||||
"DownBlock2D"
|
||||
],
|
||||
"downsample_padding": 1,
|
||||
"dual_cross_attention": false,
|
||||
"flip_sin_to_cos": true,
|
||||
"freq_shift": 0,
|
||||
"in_channels": 4,
|
||||
"layers_per_block": 2,
|
||||
"mid_block_scale_factor": 1,
|
||||
"norm_eps": 1e-05,
|
||||
"norm_num_groups": 32,
|
||||
"num_class_embeds": null,
|
||||
"only_cross_attention": false,
|
||||
"out_channels": 4,
|
||||
"sample_size": 64,
|
||||
"up_block_types": [
|
||||
"UpBlock2D",
|
||||
"CrossAttnUpBlock2D",
|
||||
"CrossAttnUpBlock2D",
|
||||
"CrossAttnUpBlock2D"
|
||||
],
|
||||
"use_linear_projection": true
|
||||
}
|
||||
@@ -0,0 +1,610 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
from diffusers.models import UNet2DConditionModel
|
||||
from diffusers.models.attention_processor import Attention
|
||||
from diffusers.models.transformers.transformer_2d import BasicTransformerBlock
|
||||
from einops import rearrange
|
||||
|
||||
|
||||
def _chunked_feed_forward(ff: nn.Module, hidden_states: torch.Tensor, chunk_dim: int, chunk_size: int):
|
||||
# "feed_forward_chunk_size" can be used to save memory
|
||||
if hidden_states.shape[chunk_dim] % chunk_size != 0:
|
||||
raise ValueError(
|
||||
f"`hidden_states` dimension to be chunked: {hidden_states.shape[chunk_dim]}"
|
||||
f"has to be divisible by chunk size: {chunk_size}."
|
||||
f" Make sure to set an appropriate `chunk_size` when calling `unet.enable_forward_chunking`."
|
||||
)
|
||||
|
||||
num_chunks = hidden_states.shape[chunk_dim] // chunk_size
|
||||
ff_output = torch.cat(
|
||||
[ff(hid_slice) for hid_slice in hidden_states.chunk(num_chunks, dim=chunk_dim)],
|
||||
dim=chunk_dim,
|
||||
)
|
||||
return ff_output
|
||||
|
||||
|
||||
class Basic2p5DTransformerBlock(torch.nn.Module):
|
||||
def __init__(self, transformer: BasicTransformerBlock, layer_name, use_ma=True, use_ra=True, is_turbo=False) -> None:
|
||||
super().__init__()
|
||||
self.transformer = transformer
|
||||
self.layer_name = layer_name
|
||||
self.use_ma = use_ma
|
||||
self.use_ra = use_ra
|
||||
self.is_turbo = is_turbo
|
||||
|
||||
# multiview attn
|
||||
if self.use_ma:
|
||||
self.attn_multiview = Attention(
|
||||
query_dim=self.dim,
|
||||
heads=self.num_attention_heads,
|
||||
dim_head=self.attention_head_dim,
|
||||
dropout=self.dropout,
|
||||
bias=self.attention_bias,
|
||||
cross_attention_dim=None,
|
||||
upcast_attention=self.attn1.upcast_attention,
|
||||
out_bias=True,
|
||||
)
|
||||
|
||||
# ref attn
|
||||
if self.use_ra:
|
||||
self.attn_refview = Attention(
|
||||
query_dim=self.dim,
|
||||
heads=self.num_attention_heads,
|
||||
dim_head=self.attention_head_dim,
|
||||
dropout=self.dropout,
|
||||
bias=self.attention_bias,
|
||||
cross_attention_dim=None,
|
||||
upcast_attention=self.attn1.upcast_attention,
|
||||
out_bias=True,
|
||||
)
|
||||
if self.is_turbo:
|
||||
self._initialize_attn_weights()
|
||||
|
||||
def _initialize_attn_weights(self):
|
||||
|
||||
if self.use_ma:
|
||||
self.attn_multiview.load_state_dict(self.attn1.state_dict())
|
||||
with torch.no_grad():
|
||||
for layer in self.attn_multiview.to_out:
|
||||
for param in layer.parameters():
|
||||
param.zero_()
|
||||
if self.use_ra:
|
||||
self.attn_refview.load_state_dict(self.attn1.state_dict())
|
||||
with torch.no_grad():
|
||||
for layer in self.attn_refview.to_out:
|
||||
for param in layer.parameters():
|
||||
param.zero_()
|
||||
|
||||
def __getattr__(self, name: str):
|
||||
try:
|
||||
return super().__getattr__(name)
|
||||
except AttributeError:
|
||||
return getattr(self.transformer, name)
|
||||
|
||||
def forward(
|
||||
self,
|
||||
hidden_states: torch.Tensor,
|
||||
attention_mask: Optional[torch.Tensor] = None,
|
||||
encoder_hidden_states: Optional[torch.Tensor] = None,
|
||||
encoder_attention_mask: Optional[torch.Tensor] = None,
|
||||
timestep: Optional[torch.LongTensor] = None,
|
||||
cross_attention_kwargs: Dict[str, Any] = None,
|
||||
class_labels: Optional[torch.LongTensor] = None,
|
||||
added_cond_kwargs: Optional[Dict[str, torch.Tensor]] = None,
|
||||
) -> torch.Tensor:
|
||||
|
||||
# Notice that normalization is always applied before the real computation in the following blocks.
|
||||
# 0. Self-Attention
|
||||
batch_size = hidden_states.shape[0]
|
||||
|
||||
cross_attention_kwargs = cross_attention_kwargs.copy() if cross_attention_kwargs is not None else {}
|
||||
num_in_batch = cross_attention_kwargs.pop('num_in_batch', 1)
|
||||
mode = cross_attention_kwargs.pop('mode', None)
|
||||
if not self.is_turbo:
|
||||
mva_scale = cross_attention_kwargs.pop('mva_scale', 1.0)
|
||||
ref_scale = cross_attention_kwargs.pop('ref_scale', 1.0)
|
||||
else:
|
||||
position_attn_mask = cross_attention_kwargs.pop("position_attn_mask", None)
|
||||
position_voxel_indices = cross_attention_kwargs.pop("position_voxel_indices", None)
|
||||
mva_scale = 1.0
|
||||
ref_scale = 1.0
|
||||
|
||||
condition_embed_dict = cross_attention_kwargs.pop("condition_embed_dict", None)
|
||||
|
||||
if self.norm_type == "ada_norm":
|
||||
norm_hidden_states = self.norm1(hidden_states, timestep)
|
||||
elif self.norm_type == "ada_norm_zero":
|
||||
norm_hidden_states, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.norm1(
|
||||
hidden_states, timestep, class_labels, hidden_dtype=hidden_states.dtype
|
||||
)
|
||||
elif self.norm_type in ["layer_norm", "layer_norm_i2vgen"]:
|
||||
norm_hidden_states = self.norm1(hidden_states)
|
||||
elif self.norm_type == "ada_norm_continuous":
|
||||
norm_hidden_states = self.norm1(hidden_states, added_cond_kwargs["pooled_text_emb"])
|
||||
elif self.norm_type == "ada_norm_single":
|
||||
shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = (
|
||||
self.scale_shift_table[None] + timestep.reshape(batch_size, 6, -1)
|
||||
).chunk(6, dim=1)
|
||||
norm_hidden_states = self.norm1(hidden_states)
|
||||
norm_hidden_states = norm_hidden_states * (1 + scale_msa) + shift_msa
|
||||
else:
|
||||
raise ValueError("Incorrect norm used")
|
||||
|
||||
if self.pos_embed is not None:
|
||||
norm_hidden_states = self.pos_embed(norm_hidden_states)
|
||||
|
||||
# 1. Prepare GLIGEN inputs
|
||||
cross_attention_kwargs = cross_attention_kwargs.copy() if cross_attention_kwargs is not None else {}
|
||||
gligen_kwargs = cross_attention_kwargs.pop("gligen", None)
|
||||
|
||||
attn_output = self.attn1(
|
||||
norm_hidden_states,
|
||||
encoder_hidden_states=encoder_hidden_states if self.only_cross_attention else None,
|
||||
attention_mask=attention_mask,
|
||||
**cross_attention_kwargs,
|
||||
)
|
||||
|
||||
if self.norm_type == "ada_norm_zero":
|
||||
attn_output = gate_msa.unsqueeze(1) * attn_output
|
||||
elif self.norm_type == "ada_norm_single":
|
||||
attn_output = gate_msa * attn_output
|
||||
|
||||
hidden_states = attn_output + hidden_states
|
||||
if hidden_states.ndim == 4:
|
||||
hidden_states = hidden_states.squeeze(1)
|
||||
|
||||
# 1.2 Reference Attention
|
||||
if 'w' in mode:
|
||||
condition_embed_dict[self.layer_name] = rearrange(
|
||||
norm_hidden_states, '(b n) l c -> b (n l) c',
|
||||
n=num_in_batch
|
||||
) # B, (N L), C
|
||||
|
||||
if 'r' in mode and self.use_ra:
|
||||
condition_embed = condition_embed_dict[self.layer_name].unsqueeze(1).repeat(1, num_in_batch, 1,
|
||||
1) # B N L C
|
||||
condition_embed = rearrange(condition_embed, 'b n l c -> (b n) l c')
|
||||
|
||||
attn_output = self.attn_refview(
|
||||
norm_hidden_states,
|
||||
encoder_hidden_states=condition_embed,
|
||||
attention_mask=None,
|
||||
**cross_attention_kwargs
|
||||
)
|
||||
if not self.is_turbo:
|
||||
ref_scale_timing = ref_scale
|
||||
if isinstance(ref_scale, torch.Tensor):
|
||||
ref_scale_timing = ref_scale.unsqueeze(1).repeat(1, num_in_batch).view(-1)
|
||||
for _ in range(attn_output.ndim - 1):
|
||||
ref_scale_timing = ref_scale_timing.unsqueeze(-1)
|
||||
|
||||
hidden_states = ref_scale_timing * attn_output + hidden_states
|
||||
|
||||
if hidden_states.ndim == 4:
|
||||
hidden_states = hidden_states.squeeze(1)
|
||||
|
||||
# 1.3 Multiview Attention
|
||||
if num_in_batch > 1 and self.use_ma:
|
||||
multivew_hidden_states = rearrange(norm_hidden_states, '(b n) l c -> b (n l) c', n=num_in_batch)
|
||||
|
||||
if self.is_turbo:
|
||||
position_mask = None
|
||||
if position_attn_mask is not None:
|
||||
if multivew_hidden_states.shape[1] in position_attn_mask:
|
||||
position_mask = position_attn_mask[multivew_hidden_states.shape[1]]
|
||||
position_indices = None
|
||||
if position_voxel_indices is not None:
|
||||
if multivew_hidden_states.shape[1] in position_voxel_indices:
|
||||
position_indices = position_voxel_indices[multivew_hidden_states.shape[1]]
|
||||
attn_output = self.attn_multiview(
|
||||
multivew_hidden_states,
|
||||
encoder_hidden_states=multivew_hidden_states,
|
||||
attention_mask=position_mask,
|
||||
position_indices=position_indices,
|
||||
**cross_attention_kwargs
|
||||
)
|
||||
else:
|
||||
attn_output = self.attn_multiview(
|
||||
multivew_hidden_states,
|
||||
encoder_hidden_states=multivew_hidden_states,
|
||||
**cross_attention_kwargs
|
||||
)
|
||||
|
||||
attn_output = rearrange(attn_output, 'b (n l) c -> (b n) l c', n=num_in_batch)
|
||||
|
||||
hidden_states = mva_scale * attn_output + hidden_states
|
||||
if hidden_states.ndim == 4:
|
||||
hidden_states = hidden_states.squeeze(1)
|
||||
|
||||
# 1.2 GLIGEN Control
|
||||
if gligen_kwargs is not None:
|
||||
hidden_states = self.fuser(hidden_states, gligen_kwargs["objs"])
|
||||
|
||||
# 3. Cross-Attention
|
||||
if self.attn2 is not None:
|
||||
if self.norm_type == "ada_norm":
|
||||
norm_hidden_states = self.norm2(hidden_states, timestep)
|
||||
elif self.norm_type in ["ada_norm_zero", "layer_norm", "layer_norm_i2vgen"]:
|
||||
norm_hidden_states = self.norm2(hidden_states)
|
||||
elif self.norm_type == "ada_norm_single":
|
||||
# For PixArt norm2 isn't applied here:
|
||||
# https://github.com/PixArt-alpha/PixArt-alpha/blob/0f55e922376d8b797edd44d25d0e7464b260dcab/diffusion/model/nets/PixArtMS.py#L70C1-L76C103
|
||||
norm_hidden_states = hidden_states
|
||||
elif self.norm_type == "ada_norm_continuous":
|
||||
norm_hidden_states = self.norm2(hidden_states, added_cond_kwargs["pooled_text_emb"])
|
||||
else:
|
||||
raise ValueError("Incorrect norm")
|
||||
|
||||
if self.pos_embed is not None and self.norm_type != "ada_norm_single":
|
||||
norm_hidden_states = self.pos_embed(norm_hidden_states)
|
||||
|
||||
attn_output = self.attn2(
|
||||
norm_hidden_states,
|
||||
encoder_hidden_states=encoder_hidden_states,
|
||||
attention_mask=encoder_attention_mask,
|
||||
**cross_attention_kwargs,
|
||||
)
|
||||
|
||||
hidden_states = attn_output + hidden_states
|
||||
|
||||
# 4. Feed-forward
|
||||
# i2vgen doesn't have this norm 🤷♂️
|
||||
if self.norm_type == "ada_norm_continuous":
|
||||
norm_hidden_states = self.norm3(hidden_states, added_cond_kwargs["pooled_text_emb"])
|
||||
elif not self.norm_type == "ada_norm_single":
|
||||
norm_hidden_states = self.norm3(hidden_states)
|
||||
|
||||
if self.norm_type == "ada_norm_zero":
|
||||
norm_hidden_states = norm_hidden_states * (1 + scale_mlp[:, None]) + shift_mlp[:, None]
|
||||
|
||||
if self.norm_type == "ada_norm_single":
|
||||
norm_hidden_states = self.norm2(hidden_states)
|
||||
norm_hidden_states = norm_hidden_states * (1 + scale_mlp) + shift_mlp
|
||||
|
||||
if self._chunk_size is not None:
|
||||
# "feed_forward_chunk_size" can be used to save memory
|
||||
ff_output = _chunked_feed_forward(self.ff, norm_hidden_states, self._chunk_dim, self._chunk_size)
|
||||
else:
|
||||
ff_output = self.ff(norm_hidden_states)
|
||||
|
||||
if self.norm_type == "ada_norm_zero":
|
||||
ff_output = gate_mlp.unsqueeze(1) * ff_output
|
||||
elif self.norm_type == "ada_norm_single":
|
||||
ff_output = gate_mlp * ff_output
|
||||
|
||||
hidden_states = ff_output + hidden_states
|
||||
if hidden_states.ndim == 4:
|
||||
hidden_states = hidden_states.squeeze(1)
|
||||
|
||||
return hidden_states
|
||||
|
||||
@torch.no_grad()
|
||||
def compute_voxel_grid_mask(position, grid_resolution=8):
|
||||
|
||||
position = position.half()
|
||||
B,N,_,H,W = position.shape
|
||||
assert H%grid_resolution==0 and W%grid_resolution==0
|
||||
|
||||
valid_mask = (position != 1).all(dim=2, keepdim=True)
|
||||
valid_mask = valid_mask.expand_as(position)
|
||||
position[valid_mask==False] = 0
|
||||
|
||||
|
||||
position = rearrange(
|
||||
position,
|
||||
'b n c (num_h grid_h) (num_w grid_w) -> b n num_h num_w c grid_h grid_w',
|
||||
num_h=grid_resolution, num_w=grid_resolution
|
||||
)
|
||||
valid_mask = rearrange(
|
||||
valid_mask,
|
||||
'b n c (num_h grid_h) (num_w grid_w) -> b n num_h num_w c grid_h grid_w',
|
||||
num_h=grid_resolution, num_w=grid_resolution
|
||||
)
|
||||
|
||||
grid_position = position.sum(dim=(-2, -1))
|
||||
count_masked = valid_mask.sum(dim=(-2, -1))
|
||||
|
||||
grid_position = grid_position / count_masked.clamp(min=1)
|
||||
grid_position[count_masked<5] = 0
|
||||
|
||||
grid_position = grid_position.permute(0,1,4,2,3)
|
||||
grid_position = rearrange(grid_position, 'b n c h w -> b n (h w) c')
|
||||
|
||||
grid_position_expanded_1 = grid_position.unsqueeze(2).unsqueeze(4) # 形状变为 B, N, 1, L, 1, 3
|
||||
grid_position_expanded_2 = grid_position.unsqueeze(1).unsqueeze(3) # 形状变为 B, 1, N, 1, L, 3
|
||||
|
||||
# 计算欧氏距离
|
||||
distances = torch.norm(grid_position_expanded_1 - grid_position_expanded_2, dim=-1) # 形状为 B, N, N, L, L
|
||||
|
||||
weights = distances
|
||||
grid_distance = 1.73/grid_resolution
|
||||
|
||||
#weights = weights*-32
|
||||
#weights = weights.clamp(min=-10000.0)
|
||||
|
||||
weights = weights< grid_distance
|
||||
|
||||
return weights
|
||||
|
||||
def compute_multi_resolution_mask(position_maps, grid_resolutions=[32, 16, 8]):
|
||||
position_attn_mask = {}
|
||||
with torch.no_grad():
|
||||
for grid_resolution in grid_resolutions:
|
||||
position_mask = compute_voxel_grid_mask(position_maps, grid_resolution)
|
||||
position_mask = rearrange(position_mask, 'b ni nj li lj -> b (ni li) (nj lj)')
|
||||
position_attn_mask[position_mask.shape[1]] = position_mask
|
||||
return position_attn_mask
|
||||
|
||||
@torch.no_grad()
|
||||
def compute_discrete_voxel_indice(position, grid_resolution=8, voxel_resolution=128):
|
||||
|
||||
position = position.half()
|
||||
B,N,_,H,W = position.shape
|
||||
assert H%grid_resolution==0 and W%grid_resolution==0
|
||||
|
||||
valid_mask = (position != 1).all(dim=2, keepdim=True)
|
||||
valid_mask = valid_mask.expand_as(position)
|
||||
position[valid_mask==False] = 0
|
||||
|
||||
position = rearrange(
|
||||
position,
|
||||
'b n c (num_h grid_h) (num_w grid_w) -> b n num_h num_w c grid_h grid_w',
|
||||
num_h=grid_resolution, num_w=grid_resolution
|
||||
)
|
||||
valid_mask = rearrange(
|
||||
valid_mask,
|
||||
'b n c (num_h grid_h) (num_w grid_w) -> b n num_h num_w c grid_h grid_w',
|
||||
num_h=grid_resolution, num_w=grid_resolution
|
||||
)
|
||||
|
||||
grid_position = position.sum(dim=(-2, -1))
|
||||
count_masked = valid_mask.sum(dim=(-2, -1))
|
||||
|
||||
grid_position = grid_position / count_masked.clamp(min=1)
|
||||
grid_position[count_masked<5] = 0
|
||||
|
||||
grid_position = grid_position.permute(0,1,4,2,3).clamp(0, 1) # B N C H W
|
||||
voxel_indices = grid_position * (voxel_resolution - 1)
|
||||
voxel_indices = torch.round(voxel_indices).long()
|
||||
return voxel_indices
|
||||
|
||||
def compute_multi_resolution_discrete_voxel_indice(
|
||||
position_maps,
|
||||
grid_resolutions=[64, 32, 16, 8],
|
||||
voxel_resolutions=[512, 256, 128, 64]
|
||||
):
|
||||
voxel_indices = {}
|
||||
with torch.no_grad():
|
||||
for grid_resolution, voxel_resolution in zip(grid_resolutions, voxel_resolutions):
|
||||
voxel_indice = compute_discrete_voxel_indice(position_maps, grid_resolution, voxel_resolution)
|
||||
voxel_indice = rearrange(voxel_indice, 'b n c h w -> b (n h w) c')
|
||||
voxel_indices[voxel_indice.shape[1]] = {'voxel_indices':voxel_indice, 'voxel_resolution':voxel_resolution}
|
||||
return voxel_indices
|
||||
|
||||
class UNet2p5DConditionModel(torch.nn.Module):
|
||||
def __init__(self, unet: UNet2DConditionModel) -> None:
|
||||
super().__init__()
|
||||
self.unet = unet
|
||||
|
||||
self.use_ma = True
|
||||
self.use_ra = True
|
||||
self.use_camera_embedding = True
|
||||
self.use_dual_stream = True
|
||||
self.is_turbo = False
|
||||
|
||||
if self.use_dual_stream:
|
||||
self.unet_dual = copy.deepcopy(unet)
|
||||
self.init_attention(self.unet_dual)
|
||||
self.init_attention(self.unet, use_ma=self.use_ma, use_ra=self.use_ra, is_turbo=self.is_turbo)
|
||||
self.init_condition()
|
||||
self.init_camera_embedding()
|
||||
|
||||
@staticmethod
|
||||
def from_pretrained(pretrained_model_name_or_path, **kwargs):
|
||||
torch_dtype = kwargs.pop('torch_dtype', torch.float32)
|
||||
config_path = os.path.join(pretrained_model_name_or_path, 'config.json')
|
||||
unet_ckpt_path = os.path.join(pretrained_model_name_or_path, 'diffusion_pytorch_model.bin')
|
||||
with open(config_path, 'r', encoding='utf-8') as file:
|
||||
config = json.load(file)
|
||||
unet = UNet2DConditionModel(**config)
|
||||
unet = UNet2p5DConditionModel(unet)
|
||||
unet_ckpt = torch.load(unet_ckpt_path, map_location='cpu', weights_only=True)
|
||||
unet.load_state_dict(unet_ckpt, strict=True)
|
||||
unet = unet.to(torch_dtype)
|
||||
return unet
|
||||
|
||||
def init_condition(self):
|
||||
self.unet.conv_in = torch.nn.Conv2d(
|
||||
12,
|
||||
self.unet.conv_in.out_channels,
|
||||
kernel_size=self.unet.conv_in.kernel_size,
|
||||
stride=self.unet.conv_in.stride,
|
||||
padding=self.unet.conv_in.padding,
|
||||
dilation=self.unet.conv_in.dilation,
|
||||
groups=self.unet.conv_in.groups,
|
||||
bias=self.unet.conv_in.bias is not None)
|
||||
|
||||
self.unet.learned_text_clip_gen = nn.Parameter(torch.randn(1, 77, 1024))
|
||||
self.unet.learned_text_clip_ref = nn.Parameter(torch.randn(1, 77, 1024))
|
||||
|
||||
def init_camera_embedding(self):
|
||||
|
||||
if self.use_camera_embedding:
|
||||
time_embed_dim = 1280
|
||||
self.max_num_ref_image = 5
|
||||
self.max_num_gen_image = 12 * 3 + 4 * 2
|
||||
self.unet.class_embedding = nn.Embedding(self.max_num_ref_image + self.max_num_gen_image, time_embed_dim)
|
||||
|
||||
def init_attention(self, unet, use_ma=False, use_ra=False, is_turbo=False):
|
||||
|
||||
for down_block_i, down_block in enumerate(unet.down_blocks):
|
||||
if hasattr(down_block, "has_cross_attention") and down_block.has_cross_attention:
|
||||
for attn_i, attn in enumerate(down_block.attentions):
|
||||
for transformer_i, transformer in enumerate(attn.transformer_blocks):
|
||||
if isinstance(transformer, BasicTransformerBlock):
|
||||
attn.transformer_blocks[transformer_i] = Basic2p5DTransformerBlock(
|
||||
transformer,
|
||||
f'down_{down_block_i}_{attn_i}_{transformer_i}',
|
||||
use_ma, use_ra, is_turbo
|
||||
)
|
||||
|
||||
if hasattr(unet.mid_block, "has_cross_attention") and unet.mid_block.has_cross_attention:
|
||||
for attn_i, attn in enumerate(unet.mid_block.attentions):
|
||||
for transformer_i, transformer in enumerate(attn.transformer_blocks):
|
||||
if isinstance(transformer, BasicTransformerBlock):
|
||||
attn.transformer_blocks[transformer_i] = Basic2p5DTransformerBlock(
|
||||
transformer,
|
||||
f'mid_{attn_i}_{transformer_i}',
|
||||
use_ma, use_ra, is_turbo
|
||||
)
|
||||
|
||||
for up_block_i, up_block in enumerate(unet.up_blocks):
|
||||
if hasattr(up_block, "has_cross_attention") and up_block.has_cross_attention:
|
||||
for attn_i, attn in enumerate(up_block.attentions):
|
||||
for transformer_i, transformer in enumerate(attn.transformer_blocks):
|
||||
if isinstance(transformer, BasicTransformerBlock):
|
||||
attn.transformer_blocks[transformer_i] = Basic2p5DTransformerBlock(
|
||||
transformer,
|
||||
f'up_{up_block_i}_{attn_i}_{transformer_i}',
|
||||
use_ma, use_ra, is_turbo
|
||||
)
|
||||
|
||||
def __getattr__(self, name: str):
|
||||
try:
|
||||
return super().__getattr__(name)
|
||||
except AttributeError:
|
||||
return getattr(self.unet, name)
|
||||
|
||||
def forward(
|
||||
self, sample, timestep, encoder_hidden_states,
|
||||
*args, down_intrablock_additional_residuals=None,
|
||||
down_block_res_samples=None, mid_block_res_sample=None,
|
||||
**cached_condition,
|
||||
):
|
||||
B, N_gen, _, H, W = sample.shape
|
||||
assert H == W
|
||||
|
||||
if self.use_camera_embedding:
|
||||
camera_info_gen = cached_condition['camera_info_gen'] + self.max_num_ref_image
|
||||
camera_info_gen = rearrange(camera_info_gen, 'b n -> (b n)')
|
||||
else:
|
||||
camera_info_gen = None
|
||||
|
||||
sample = [sample]
|
||||
if 'normal_imgs' in cached_condition:
|
||||
sample.append(cached_condition["normal_imgs"])
|
||||
if 'position_imgs' in cached_condition:
|
||||
sample.append(cached_condition["position_imgs"])
|
||||
sample = torch.cat(sample, dim=2)
|
||||
|
||||
sample = rearrange(sample, 'b n c h w -> (b n) c h w')
|
||||
|
||||
encoder_hidden_states_gen = encoder_hidden_states.unsqueeze(1).repeat(1, N_gen, 1, 1)
|
||||
encoder_hidden_states_gen = rearrange(encoder_hidden_states_gen, 'b n l c -> (b n) l c')
|
||||
|
||||
if self.use_ra:
|
||||
if 'condition_embed_dict' in cached_condition:
|
||||
condition_embed_dict = cached_condition['condition_embed_dict']
|
||||
else:
|
||||
condition_embed_dict = {}
|
||||
ref_latents = cached_condition['ref_latents']
|
||||
N_ref = ref_latents.shape[1]
|
||||
if self.use_camera_embedding:
|
||||
camera_info_ref = cached_condition['camera_info_ref']
|
||||
camera_info_ref = rearrange(camera_info_ref, 'b n -> (b n)')
|
||||
else:
|
||||
camera_info_ref = None
|
||||
|
||||
ref_latents = rearrange(ref_latents, 'b n c h w -> (b n) c h w')
|
||||
|
||||
encoder_hidden_states_ref = self.unet.learned_text_clip_ref.unsqueeze(1).repeat(B, N_ref, 1, 1)
|
||||
encoder_hidden_states_ref = rearrange(encoder_hidden_states_ref, 'b n l c -> (b n) l c')
|
||||
|
||||
noisy_ref_latents = ref_latents
|
||||
timestep_ref = 0
|
||||
|
||||
if self.use_dual_stream:
|
||||
unet_ref = self.unet_dual
|
||||
else:
|
||||
unet_ref = self.unet
|
||||
unet_ref(
|
||||
noisy_ref_latents, timestep_ref,
|
||||
encoder_hidden_states=encoder_hidden_states_ref,
|
||||
class_labels=camera_info_ref,
|
||||
# **kwargs
|
||||
return_dict=False,
|
||||
cross_attention_kwargs={
|
||||
'mode': 'w', 'num_in_batch': N_ref,
|
||||
'condition_embed_dict': condition_embed_dict},
|
||||
)
|
||||
cached_condition['condition_embed_dict'] = condition_embed_dict
|
||||
else:
|
||||
condition_embed_dict = None
|
||||
|
||||
mva_scale = cached_condition.get('mva_scale', 1.0)
|
||||
ref_scale = cached_condition.get('ref_scale', 1.0)
|
||||
|
||||
if self.is_turbo:
|
||||
cross_attention_kwargs_ = {
|
||||
'mode': 'r', 'num_in_batch': N_gen,
|
||||
'condition_embed_dict': condition_embed_dict,
|
||||
'position_attn_mask':position_attn_mask,
|
||||
'position_voxel_indices':position_voxel_indices,
|
||||
'mva_scale': mva_scale,
|
||||
'ref_scale': ref_scale,
|
||||
}
|
||||
else:
|
||||
cross_attention_kwargs_ = {
|
||||
'mode': 'r', 'num_in_batch': N_gen,
|
||||
'condition_embed_dict': condition_embed_dict,
|
||||
'mva_scale': mva_scale,
|
||||
'ref_scale': ref_scale,
|
||||
}
|
||||
return self.unet(
|
||||
sample, timestep,
|
||||
encoder_hidden_states_gen, *args,
|
||||
class_labels=camera_info_gen,
|
||||
down_intrablock_additional_residuals=[
|
||||
sample.to(dtype=self.unet.dtype) for sample in down_intrablock_additional_residuals
|
||||
] if down_intrablock_additional_residuals is not None else None,
|
||||
down_block_additional_residuals=[
|
||||
sample.to(dtype=self.unet.dtype) for sample in down_block_res_samples
|
||||
] if down_block_res_samples is not None else None,
|
||||
mid_block_additional_residual=(
|
||||
mid_block_res_sample.to(dtype=self.unet.dtype)
|
||||
if mid_block_res_sample is not None else None
|
||||
),
|
||||
return_dict=False,
|
||||
cross_attention_kwargs=cross_attention_kwargs_,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"_class_name": "AutoencoderKL",
|
||||
"_diffusers_version": "0.10.0.dev0",
|
||||
"act_fn": "silu",
|
||||
"block_out_channels": [
|
||||
128,
|
||||
256,
|
||||
512,
|
||||
512
|
||||
],
|
||||
"down_block_types": [
|
||||
"DownEncoderBlock2D",
|
||||
"DownEncoderBlock2D",
|
||||
"DownEncoderBlock2D",
|
||||
"DownEncoderBlock2D"
|
||||
],
|
||||
"in_channels": 3,
|
||||
"latent_channels": 4,
|
||||
"layers_per_block": 2,
|
||||
"norm_num_groups": 32,
|
||||
"out_channels": 3,
|
||||
"sample_size": 768,
|
||||
"up_block_types": [
|
||||
"UpDecoderBlock2D",
|
||||
"UpDecoderBlock2D",
|
||||
"UpDecoderBlock2D",
|
||||
"UpDecoderBlock2D"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 3072
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 0.9990943042622529
|
||||
geo_decoder_mlp_expand_ratio: 1
|
||||
geo_decoder_downsample_ratio: 2
|
||||
geo_decoder_ln_post: false
|
||||
@@ -0,0 +1,15 @@
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 3072
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 0.9990943042622529
|
||||
geo_decoder_mlp_expand_ratio: 4
|
||||
geo_decoder_downsample_ratio: 1
|
||||
geo_decoder_ln_post: true
|
||||
@@ -0,0 +1,69 @@
|
||||
model:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.Hunyuan3DDiT
|
||||
params:
|
||||
in_channels: 64
|
||||
context_in_dim: 1536
|
||||
hidden_size: 1024
|
||||
mlp_ratio: 4.0
|
||||
num_heads: 16
|
||||
depth: 8
|
||||
depth_single_blocks: 16
|
||||
axes_dim: [ 64 ]
|
||||
theta: 10000
|
||||
qkv_bias: true
|
||||
guidance_embed: true
|
||||
|
||||
vae:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 512
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 1.0188137142395404
|
||||
|
||||
conditioner:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.SingleImageEncoder
|
||||
params:
|
||||
main_image_encoder:
|
||||
type: DinoImageEncoder # dino giant
|
||||
kwargs:
|
||||
config:
|
||||
attention_probs_dropout_prob: 0.0
|
||||
drop_path_rate: 0.0
|
||||
hidden_act: gelu
|
||||
hidden_dropout_prob: 0.0
|
||||
hidden_size: 1536
|
||||
image_size: 518
|
||||
initializer_range: 0.02
|
||||
layer_norm_eps: 1.e-6
|
||||
layerscale_value: 1.0
|
||||
mlp_ratio: 4
|
||||
model_type: dinov2
|
||||
num_attention_heads: 24
|
||||
num_channels: 3
|
||||
num_hidden_layers: 40
|
||||
patch_size: 14
|
||||
qkv_bias: true
|
||||
torch_dtype: float32
|
||||
use_swiglu_ffn: true
|
||||
image_size: 518
|
||||
|
||||
scheduler:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.schedulers.FlowMatchEulerDiscreteScheduler
|
||||
params:
|
||||
num_train_timesteps: 1000
|
||||
|
||||
image_processor:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.preprocessors.ImageProcessorV2
|
||||
params:
|
||||
size: 512
|
||||
border_ratio: 0.15
|
||||
|
||||
pipeline:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.pipelines.Hunyuan3DDiTFlowMatchingPipeline
|
||||
@@ -0,0 +1,70 @@
|
||||
model:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.Hunyuan3DDiT
|
||||
params:
|
||||
in_channels: 64
|
||||
context_in_dim: 1536
|
||||
hidden_size: 1024
|
||||
mlp_ratio: 4.0
|
||||
num_heads: 16
|
||||
depth: 8
|
||||
depth_single_blocks: 16
|
||||
axes_dim: [ 64 ]
|
||||
theta: 10000
|
||||
qkv_bias: true
|
||||
guidance_embed: true
|
||||
|
||||
vae:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 3072
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 1.0188137142395404
|
||||
|
||||
conditioner:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.SingleImageEncoder
|
||||
params:
|
||||
main_image_encoder:
|
||||
type: DinoImageEncoder # dino giant
|
||||
kwargs:
|
||||
config:
|
||||
attention_probs_dropout_prob: 0.0
|
||||
drop_path_rate: 0.0
|
||||
hidden_act: gelu
|
||||
hidden_dropout_prob: 0.0
|
||||
hidden_size: 1536
|
||||
image_size: 518
|
||||
initializer_range: 0.02
|
||||
layer_norm_eps: 1.e-6
|
||||
layerscale_value: 1.0
|
||||
mlp_ratio: 4
|
||||
model_type: dinov2
|
||||
num_attention_heads: 24
|
||||
num_channels: 3
|
||||
num_hidden_layers: 40
|
||||
patch_size: 14
|
||||
qkv_bias: true
|
||||
torch_dtype: float32
|
||||
use_swiglu_ffn: true
|
||||
image_size: 1022
|
||||
|
||||
scheduler:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.schedulers.ConsistencyFlowMatchEulerDiscreteScheduler
|
||||
params:
|
||||
num_train_timesteps: 1000
|
||||
pcm_timesteps: 100
|
||||
|
||||
image_processor:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.preprocessors.ImageProcessorV2
|
||||
params:
|
||||
size: 1022
|
||||
border_ratio: 0.15
|
||||
|
||||
pipeline:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.pipelines.Hunyuan3DDiTFlowMatchingPipeline
|
||||
@@ -0,0 +1,69 @@
|
||||
model:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.Hunyuan3DDiT
|
||||
params:
|
||||
in_channels: 64
|
||||
context_in_dim: 1536
|
||||
hidden_size: 1024
|
||||
mlp_ratio: 4.0
|
||||
num_heads: 16
|
||||
depth: 8
|
||||
depth_single_blocks: 16
|
||||
axes_dim: [ 64 ]
|
||||
theta: 10000
|
||||
qkv_bias: true
|
||||
guidance_embed: false
|
||||
|
||||
vae:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 512
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 1.0188137142395404
|
||||
|
||||
conditioner:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.SingleImageEncoder
|
||||
params:
|
||||
main_image_encoder:
|
||||
type: DinoImageEncoder # dino giant
|
||||
kwargs:
|
||||
config:
|
||||
attention_probs_dropout_prob: 0.0
|
||||
drop_path_rate: 0.0
|
||||
hidden_act: gelu
|
||||
hidden_dropout_prob: 0.0
|
||||
hidden_size: 1536
|
||||
image_size: 518
|
||||
initializer_range: 0.02
|
||||
layer_norm_eps: 1.e-6
|
||||
layerscale_value: 1.0
|
||||
mlp_ratio: 4
|
||||
model_type: dinov2
|
||||
num_attention_heads: 24
|
||||
num_channels: 3
|
||||
num_hidden_layers: 40
|
||||
patch_size: 14
|
||||
qkv_bias: true
|
||||
torch_dtype: float32
|
||||
use_swiglu_ffn: true
|
||||
image_size: 518
|
||||
|
||||
scheduler:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.schedulers.FlowMatchEulerDiscreteScheduler
|
||||
params:
|
||||
num_train_timesteps: 1000
|
||||
|
||||
image_processor:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.preprocessors.ImageProcessorV2
|
||||
params:
|
||||
size: 512
|
||||
border_ratio: 0.15
|
||||
|
||||
pipeline:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.pipelines.Hunyuan3DDiTFlowMatchingPipeline
|
||||
@@ -0,0 +1,69 @@
|
||||
model:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.Hunyuan3DDiT
|
||||
params:
|
||||
in_channels: 64
|
||||
context_in_dim: 1536
|
||||
hidden_size: 1024
|
||||
mlp_ratio: 4.0
|
||||
num_heads: 16
|
||||
depth: 16
|
||||
depth_single_blocks: 32
|
||||
axes_dim: [ 64 ]
|
||||
theta: 10000
|
||||
qkv_bias: true
|
||||
guidance_embed: true
|
||||
|
||||
vae:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 3072
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 0.9990943042622529
|
||||
|
||||
conditioner:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.SingleImageEncoder
|
||||
params:
|
||||
main_image_encoder:
|
||||
type: DinoImageEncoderMV # dino giant
|
||||
kwargs:
|
||||
config:
|
||||
attention_probs_dropout_prob: 0.0
|
||||
drop_path_rate: 0.0
|
||||
hidden_act: gelu
|
||||
hidden_dropout_prob: 0.0
|
||||
hidden_size: 1536
|
||||
image_size: 518
|
||||
initializer_range: 0.02
|
||||
layer_norm_eps: 1.e-6
|
||||
layerscale_value: 1.0
|
||||
mlp_ratio: 4
|
||||
model_type: dinov2
|
||||
num_attention_heads: 24
|
||||
num_channels: 3
|
||||
num_hidden_layers: 40
|
||||
patch_size: 14
|
||||
qkv_bias: true
|
||||
torch_dtype: float32
|
||||
use_swiglu_ffn: true
|
||||
image_size: 518
|
||||
|
||||
scheduler:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.schedulers.FlowMatchEulerDiscreteScheduler
|
||||
params:
|
||||
num_train_timesteps: 1000
|
||||
|
||||
image_processor:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.preprocessors.MVImageProcessorV2
|
||||
params:
|
||||
size: 512
|
||||
border_ratio: 0.15
|
||||
|
||||
pipeline:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.pipelines.Hunyuan3DDiTFlowMatchingPipeline
|
||||
@@ -0,0 +1,70 @@
|
||||
model:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.Hunyuan3DDiT
|
||||
params:
|
||||
in_channels: 64
|
||||
context_in_dim: 1536
|
||||
hidden_size: 1024
|
||||
mlp_ratio: 4.0
|
||||
num_heads: 16
|
||||
depth: 16
|
||||
depth_single_blocks: 32
|
||||
axes_dim: [ 64 ]
|
||||
theta: 10000
|
||||
qkv_bias: true
|
||||
guidance_embed: true
|
||||
|
||||
vae:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 3072
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 0.9990943042622529
|
||||
|
||||
conditioner:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.SingleImageEncoder
|
||||
params:
|
||||
main_image_encoder:
|
||||
type: DinoImageEncoderMV # dino giant
|
||||
kwargs:
|
||||
config:
|
||||
attention_probs_dropout_prob: 0.0
|
||||
drop_path_rate: 0.0
|
||||
hidden_act: gelu
|
||||
hidden_dropout_prob: 0.0
|
||||
hidden_size: 1536
|
||||
image_size: 518
|
||||
initializer_range: 0.02
|
||||
layer_norm_eps: 1.e-6
|
||||
layerscale_value: 1.0
|
||||
mlp_ratio: 4
|
||||
model_type: dinov2
|
||||
num_attention_heads: 24
|
||||
num_channels: 3
|
||||
num_hidden_layers: 40
|
||||
patch_size: 14
|
||||
qkv_bias: true
|
||||
torch_dtype: float32
|
||||
use_swiglu_ffn: true
|
||||
image_size: 518
|
||||
|
||||
scheduler:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.schedulers.ConsistencyFlowMatchEulerDiscreteScheduler
|
||||
params:
|
||||
num_train_timesteps: 1000
|
||||
pcm_timesteps: 100
|
||||
|
||||
image_processor:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.preprocessors.MVImageProcessorV2
|
||||
params:
|
||||
size: 512
|
||||
border_ratio: 0.15
|
||||
|
||||
pipeline:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.pipelines.Hunyuan3DDiTFlowMatchingPipeline
|
||||
@@ -0,0 +1,68 @@
|
||||
model:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.Hunyuan3DDiT
|
||||
params:
|
||||
in_channels: 64
|
||||
context_in_dim: 1536
|
||||
hidden_size: 1024
|
||||
mlp_ratio: 4.0
|
||||
num_heads: 16
|
||||
depth: 16
|
||||
depth_single_blocks: 32
|
||||
axes_dim: [ 64 ]
|
||||
theta: 10000
|
||||
qkv_bias: true
|
||||
|
||||
vae:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.ShapeVAE
|
||||
params:
|
||||
num_latents: 3072
|
||||
embed_dim: 64
|
||||
num_freqs: 8
|
||||
include_pi: false
|
||||
heads: 16
|
||||
width: 1024
|
||||
num_decoder_layers: 16
|
||||
qkv_bias: false
|
||||
qk_norm: true
|
||||
scale_factor: 0.9990943042622529
|
||||
|
||||
conditioner:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.models.SingleImageEncoder
|
||||
params:
|
||||
main_image_encoder:
|
||||
type: DinoImageEncoderMV # dino giant
|
||||
kwargs:
|
||||
config:
|
||||
attention_probs_dropout_prob: 0.0
|
||||
drop_path_rate: 0.0
|
||||
hidden_act: gelu
|
||||
hidden_dropout_prob: 0.0
|
||||
hidden_size: 1536
|
||||
image_size: 518
|
||||
initializer_range: 0.02
|
||||
layer_norm_eps: 1.e-6
|
||||
layerscale_value: 1.0
|
||||
mlp_ratio: 4
|
||||
model_type: dinov2
|
||||
num_attention_heads: 24
|
||||
num_channels: 3
|
||||
num_hidden_layers: 40
|
||||
patch_size: 14
|
||||
qkv_bias: true
|
||||
torch_dtype: float32
|
||||
use_swiglu_ffn: true
|
||||
image_size: 518
|
||||
|
||||
scheduler:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.schedulers.FlowMatchEulerDiscreteScheduler
|
||||
params:
|
||||
num_train_timesteps: 1000
|
||||
|
||||
image_processor:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.preprocessors.MVImageProcessorV2
|
||||
params:
|
||||
size: 512
|
||||
border_ratio: 0.15
|
||||
|
||||
pipeline:
|
||||
target: Hunyuan3D_V2.hy3dgen.shapegen.pipelines.Hunyuan3DDiTFlowMatchingPipeline
|
||||
@@ -0,0 +1,123 @@
|
||||
name: ig2mv
|
||||
tag: "r768-ortho-nv6-ig2mv-partialimg-dcrowcol-sdxl"
|
||||
exp_root_dir: "outputs"
|
||||
seed: 42
|
||||
|
||||
data_cls: mvadapter.data.multiview.MultiviewDataModule
|
||||
data:
|
||||
root_dir: data/texture_ortho6view_easylight
|
||||
scene_list: data/objaverse_list_6w.json
|
||||
background_color: gray
|
||||
image_names: ["0000", "0001", "0002", "0003", "0008", "0009"]
|
||||
image_modality: color
|
||||
num_views: 6
|
||||
|
||||
prompt_db_path: data/objaverse_short_captions.json
|
||||
return_prompt: true
|
||||
|
||||
projection_type: ORTHO
|
||||
|
||||
source_image_modality: ["position", "normal"]
|
||||
position_offset: 0.5
|
||||
position_scale: 1.0
|
||||
|
||||
reference_root_dir: ["data/texture_rand_easylight_objaverse"]
|
||||
reference_scene_list: ["data/objaverse_list_6w.json"]
|
||||
reference_image_modality: color
|
||||
reference_image_names: ["0000", "0001", "0002", "0003", "0004"]
|
||||
reference_mask_aug: true
|
||||
|
||||
train_indices: [0, -8]
|
||||
val_indices: [-8, null]
|
||||
test_indices: [-8, null]
|
||||
|
||||
height: 768
|
||||
width: 768
|
||||
|
||||
batch_size: 1
|
||||
num_workers: 16
|
||||
|
||||
system_cls: mvadapter.systems.mvadapter_image_sdxl.MVAdapterImageSDXLSystem
|
||||
system:
|
||||
check_train_every_n_steps: 1000
|
||||
cleanup_after_validation_step: true
|
||||
cleanup_after_test_step: true
|
||||
|
||||
# Model / Adapter
|
||||
pretrained_model_name_or_path: "stabilityai/stable-diffusion-xl-base-1.0"
|
||||
pretrained_vae_name_or_path: "madebyollin/sdxl-vae-fp16-fix"
|
||||
pretrained_adapter_name_or_path: null
|
||||
init_adapter_kwargs:
|
||||
# Multi-view adapter
|
||||
self_attn_processor: "mvadapter.models.attention_processor.DecoupledMVRowColSelfAttnProcessor2_0"
|
||||
# Condition encoder
|
||||
cond_in_channels: 6
|
||||
# For training
|
||||
copy_attn_weights: true
|
||||
zero_init_module_keys: ["to_out_mv", "to_out_ref"]
|
||||
|
||||
# Training
|
||||
train_cond_encoder: true
|
||||
trainable_modules: ["_mv", "_ref"]
|
||||
prompt_drop_prob: 0.1
|
||||
image_drop_prob: 0.1
|
||||
cond_drop_prob: 0.1
|
||||
|
||||
# Noise sampler
|
||||
shift_noise: true
|
||||
shift_noise_mode: interpolated
|
||||
shift_noise_scale: 8
|
||||
|
||||
# Evaluation
|
||||
eval_seed: 42
|
||||
eval_num_inference_steps: 30
|
||||
eval_guidance_scale: 3.0
|
||||
eval_height: ${data.height}
|
||||
eval_width: ${data.width}
|
||||
|
||||
# optimizer definition
|
||||
# you can set different learning rates separately for each group of parameters, but note that if you do this you should specify EVERY trainable parameters
|
||||
optimizer:
|
||||
name: AdamW
|
||||
args:
|
||||
lr: 5e-5
|
||||
betas: [0.9, 0.999]
|
||||
weight_decay: 0.01
|
||||
params:
|
||||
cond_encoder:
|
||||
lr: 5e-5
|
||||
unet:
|
||||
lr: 5e-5
|
||||
|
||||
scheduler:
|
||||
name: SequentialLR
|
||||
interval: step
|
||||
schedulers:
|
||||
- name: LinearLR
|
||||
interval: step
|
||||
args:
|
||||
start_factor: 1e-6
|
||||
end_factor: 1.0
|
||||
total_iters: 2000
|
||||
- name: ConstantLR
|
||||
interval: step
|
||||
args:
|
||||
factor: 1.0
|
||||
total_iters: 9999999
|
||||
milestones: [2000]
|
||||
|
||||
trainer:
|
||||
max_epochs: 10
|
||||
log_every_n_steps: 10
|
||||
num_sanity_val_steps: 1
|
||||
val_check_interval: 2000
|
||||
enable_progress_bar: true
|
||||
precision: bf16-mixed
|
||||
gradient_clip_val: 1.0
|
||||
strategy: ddp
|
||||
accumulate_grad_batches: 1
|
||||
|
||||
checkpoint:
|
||||
save_last: true # whether to save at each validation time
|
||||
save_top_k: -1
|
||||
every_n_epochs: 9999 # do not save at all for debug purpose
|
||||
@@ -0,0 +1,122 @@
|
||||
name: ig2mv
|
||||
tag: "r768-ortho-nv6-ig2mv-dcrowcol-sdxl"
|
||||
exp_root_dir: "outputs"
|
||||
seed: 42
|
||||
|
||||
data_cls: mvadapter.data.multiview.MultiviewDataModule
|
||||
data:
|
||||
root_dir: data/texture_ortho6view_easylight
|
||||
scene_list: data/objaverse_list_6w.json
|
||||
background_color: gray
|
||||
image_names: ["0000", "0001", "0002", "0003", "0008", "0009"]
|
||||
image_modality: color
|
||||
num_views: 6
|
||||
|
||||
prompt_db_path: data/objaverse_short_captions.json
|
||||
return_prompt: true
|
||||
|
||||
projection_type: ORTHO
|
||||
|
||||
source_image_modality: ["position", "normal"]
|
||||
position_offset: 0.5
|
||||
position_scale: 1.0
|
||||
|
||||
reference_root_dir: ["data/texture_rand_easylight_objaverse"]
|
||||
reference_scene_list: ["data/objaverse_list_6w.json"]
|
||||
reference_image_modality: color
|
||||
reference_image_names: ["0000", "0001", "0002", "0003", "0004"]
|
||||
|
||||
train_indices: [0, -8]
|
||||
val_indices: [-8, null]
|
||||
test_indices: [-8, null]
|
||||
|
||||
height: 768
|
||||
width: 768
|
||||
|
||||
batch_size: 1
|
||||
num_workers: 16
|
||||
|
||||
system_cls: mvadapter.systems.mvadapter_image_sdxl.MVAdapterImageSDXLSystem
|
||||
system:
|
||||
check_train_every_n_steps: 1000
|
||||
cleanup_after_validation_step: true
|
||||
cleanup_after_test_step: true
|
||||
|
||||
# Model / Adapter
|
||||
pretrained_model_name_or_path: "stabilityai/stable-diffusion-xl-base-1.0"
|
||||
pretrained_vae_name_or_path: "madebyollin/sdxl-vae-fp16-fix"
|
||||
pretrained_adapter_name_or_path: null
|
||||
init_adapter_kwargs:
|
||||
# Multi-view adapter
|
||||
self_attn_processor: "mvadapter.models.attention_processor.DecoupledMVRowColSelfAttnProcessor2_0"
|
||||
# Condition encoder
|
||||
cond_in_channels: 6
|
||||
# For training
|
||||
copy_attn_weights: true
|
||||
zero_init_module_keys: ["to_out_mv", "to_out_ref"]
|
||||
|
||||
# Training
|
||||
train_cond_encoder: true
|
||||
trainable_modules: ["_mv", "_ref"]
|
||||
prompt_drop_prob: 0.1
|
||||
image_drop_prob: 0.1
|
||||
cond_drop_prob: 0.1
|
||||
|
||||
# Noise sampler
|
||||
shift_noise: true
|
||||
shift_noise_mode: interpolated
|
||||
shift_noise_scale: 8
|
||||
|
||||
# Evaluation
|
||||
eval_seed: 42
|
||||
eval_num_inference_steps: 30
|
||||
eval_guidance_scale: 3.0
|
||||
eval_height: ${data.height}
|
||||
eval_width: ${data.width}
|
||||
|
||||
# optimizer definition
|
||||
# you can set different learning rates separately for each group of parameters, but note that if you do this you should specify EVERY trainable parameters
|
||||
optimizer:
|
||||
name: AdamW
|
||||
args:
|
||||
lr: 5e-5
|
||||
betas: [0.9, 0.999]
|
||||
weight_decay: 0.01
|
||||
params:
|
||||
cond_encoder:
|
||||
lr: 5e-5
|
||||
unet:
|
||||
lr: 5e-5
|
||||
|
||||
scheduler:
|
||||
name: SequentialLR
|
||||
interval: step
|
||||
schedulers:
|
||||
- name: LinearLR
|
||||
interval: step
|
||||
args:
|
||||
start_factor: 1e-6
|
||||
end_factor: 1.0
|
||||
total_iters: 2000
|
||||
- name: ConstantLR
|
||||
interval: step
|
||||
args:
|
||||
factor: 1.0
|
||||
total_iters: 9999999
|
||||
milestones: [2000]
|
||||
|
||||
trainer:
|
||||
max_epochs: 10
|
||||
log_every_n_steps: 10
|
||||
num_sanity_val_steps: 1
|
||||
val_check_interval: 2000
|
||||
enable_progress_bar: true
|
||||
precision: bf16-mixed
|
||||
gradient_clip_val: 1.0
|
||||
strategy: ddp
|
||||
accumulate_grad_batches: 1
|
||||
|
||||
checkpoint:
|
||||
save_last: true # whether to save at each validation time
|
||||
save_top_k: -1
|
||||
every_n_epochs: 9999 # do not save at all for debug purpose
|
||||
@@ -0,0 +1,117 @@
|
||||
name: tg2mv
|
||||
tag: "r768-ortho-nv6-tg2mv-dcrowcol-sdxl"
|
||||
exp_root_dir: "outputs"
|
||||
seed: 42
|
||||
|
||||
data_cls: mvadapter.data.multiview.MultiviewDataModule
|
||||
data:
|
||||
root_dir: data/texture_ortho10view_easylight_objaverse
|
||||
scene_list: data/objaverse_list_6w.json
|
||||
background_color: gray
|
||||
image_names: ["0000", "0001", "0002", "0003", "0008", "0009"]
|
||||
image_modality: color
|
||||
num_views: 6
|
||||
|
||||
prompt_db_path: data/objaverse_short_captions.json
|
||||
return_prompt: true
|
||||
|
||||
projection_type: ORTHO
|
||||
|
||||
source_image_modality: ["position", "normal"]
|
||||
position_offset: 0.5
|
||||
position_scale: 1.0
|
||||
|
||||
train_indices: [0, -8]
|
||||
val_indices: [-8, null]
|
||||
test_indices: [-8, null]
|
||||
|
||||
height: 768
|
||||
width: 768
|
||||
|
||||
batch_size: 1
|
||||
num_workers: 16
|
||||
|
||||
system_cls: mvadapter.systems.mvadapter_text_sdxl.MVAdapterTextSDXLSystem
|
||||
system:
|
||||
check_train_every_n_steps: 1000
|
||||
cleanup_after_validation_step: true
|
||||
cleanup_after_test_step: true
|
||||
|
||||
# Model / Adapter
|
||||
pretrained_model_name_or_path: "stabilityai/stable-diffusion-xl-base-1.0"
|
||||
pretrained_vae_name_or_path: "madebyollin/sdxl-vae-fp16-fix"
|
||||
pretrained_adapter_name_or_path: null
|
||||
init_adapter_kwargs:
|
||||
# Multi-view adapter
|
||||
self_attn_processor: "mvadapter.models.attention_processor.DecoupledMVRowColSelfAttnProcessor2_0"
|
||||
# Condition encoder
|
||||
cond_in_channels: 6
|
||||
# For training
|
||||
copy_attn_weights: true
|
||||
zero_init_module_keys: ["to_out_mv"]
|
||||
|
||||
# Training
|
||||
train_cond_encoder: true
|
||||
trainable_modules: ["_mv"]
|
||||
prompt_drop_prob: 0.1
|
||||
image_drop_prob: 0.1
|
||||
cond_drop_prob: 0.1
|
||||
|
||||
# Noise sampler
|
||||
shift_noise: true
|
||||
shift_noise_mode: interpolated
|
||||
shift_noise_scale: 8
|
||||
|
||||
# Evaluation
|
||||
eval_seed: 42
|
||||
eval_num_inference_steps: 30
|
||||
eval_guidance_scale: 3.0
|
||||
eval_height: ${data.height}
|
||||
eval_width: ${data.width}
|
||||
|
||||
# optimizer definition
|
||||
# you can set different learning rates separately for each group of parameters, but note that if you do this you should specify EVERY trainable parameters
|
||||
optimizer:
|
||||
name: AdamW
|
||||
args:
|
||||
lr: 5e-5
|
||||
betas: [0.9, 0.999]
|
||||
weight_decay: 0.01
|
||||
params:
|
||||
cond_encoder:
|
||||
lr: 5e-5
|
||||
unet:
|
||||
lr: 5e-5
|
||||
|
||||
scheduler:
|
||||
name: SequentialLR
|
||||
interval: step
|
||||
schedulers:
|
||||
- name: LinearLR
|
||||
interval: step
|
||||
args:
|
||||
start_factor: 1e-6
|
||||
end_factor: 1.0
|
||||
total_iters: 2000
|
||||
- name: ConstantLR
|
||||
interval: step
|
||||
args:
|
||||
factor: 1.0
|
||||
total_iters: 9999999
|
||||
milestones: [2000]
|
||||
|
||||
trainer:
|
||||
max_epochs: 10
|
||||
log_every_n_steps: 10
|
||||
num_sanity_val_steps: 1
|
||||
val_check_interval: 2000
|
||||
enable_progress_bar: true
|
||||
precision: bf16-mixed
|
||||
gradient_clip_val: 1.0
|
||||
strategy: ddp
|
||||
accumulate_grad_batches: 1
|
||||
|
||||
checkpoint:
|
||||
save_last: true # whether to save at each validation time
|
||||
save_top_k: -1
|
||||
every_n_epochs: 9999 # do not save at all for debug purpose
|
||||
@@ -0,0 +1,122 @@
|
||||
name: i2mv
|
||||
tag: "r512-ortho-nv6-ele0-sd21"
|
||||
exp_root_dir: "outputs"
|
||||
seed: 42
|
||||
|
||||
data_cls: mvadapter.data.multiview.MultiviewDataModule
|
||||
data:
|
||||
root_dir: "data/texture_ortho10view_easylight_objaverse"
|
||||
scene_list: "data/objaverse_list_6w.json"
|
||||
background_color: gray
|
||||
image_names: ["0000", "0004", "0001", "0002", "0003", "0005"]
|
||||
image_modality: color
|
||||
num_views: 6
|
||||
|
||||
prompt_db_path: data/objaverse_short_captions.json
|
||||
return_prompt: true
|
||||
|
||||
projection_type: ORTHO
|
||||
|
||||
source_image_modality: ["plucker"]
|
||||
plucker_offset: 1.0
|
||||
plucker_scale: 2.0
|
||||
|
||||
reference_root_dir: ["data/texture_rand_easylight_objaverse"]
|
||||
reference_scene_list: ["data/objaverse_list_6w.json"]
|
||||
reference_image_modality: color
|
||||
reference_image_names: ["0000", "0001", "0002", "0003", "0004"]
|
||||
|
||||
train_indices: [0, -8]
|
||||
val_indices: [-8, null]
|
||||
test_indices: [-8, null]
|
||||
|
||||
height: 512
|
||||
width: 512
|
||||
|
||||
batch_size: 1
|
||||
num_workers: 16
|
||||
|
||||
system_cls: mvadapter.systems.mvadapter_image_sd.MVAdapterImageSDSystem
|
||||
system:
|
||||
check_train_every_n_steps: 1000
|
||||
cleanup_after_validation_step: true
|
||||
cleanup_after_test_step: true
|
||||
|
||||
# Model / Adapter
|
||||
pretrained_model_name_or_path: "stabilityai/stable-diffusion-2-1-base"
|
||||
pretrained_vae_name_or_path: null
|
||||
pretrained_adapter_name_or_path: null
|
||||
init_adapter_kwargs:
|
||||
# Multi-view adapter
|
||||
self_attn_processor: "mvadapter.models.attention_processor.DecoupledMVRowSelfAttnProcessor2_0"
|
||||
# Condition encoder
|
||||
cond_in_channels: 6
|
||||
# For training
|
||||
copy_attn_weights: true
|
||||
zero_init_module_keys: ["to_out_mv", "to_out_ref"]
|
||||
|
||||
# Training
|
||||
train_cond_encoder: true
|
||||
trainable_modules: ["_mv", "_ref"]
|
||||
prompt_drop_prob: 0.1
|
||||
image_drop_prob: 0.1
|
||||
cond_drop_prob: 0.1
|
||||
|
||||
# Noise sampler
|
||||
shift_noise: true
|
||||
shift_noise_mode: interpolated
|
||||
shift_noise_scale: 8
|
||||
|
||||
# Evaluation
|
||||
eval_seed: 42
|
||||
eval_num_inference_steps: 30
|
||||
eval_guidance_scale: 3.0
|
||||
eval_height: ${data.height}
|
||||
eval_width: ${data.width}
|
||||
|
||||
# optimizer definition
|
||||
# you can set different learning rates separately for each group of parameters, but note that if you do this you should specify EVERY trainable parameters
|
||||
optimizer:
|
||||
name: AdamW
|
||||
args:
|
||||
lr: 5e-5
|
||||
betas: [0.9, 0.999]
|
||||
weight_decay: 0.01
|
||||
params:
|
||||
cond_encoder:
|
||||
lr: 5e-5
|
||||
unet:
|
||||
lr: 5e-5
|
||||
|
||||
scheduler:
|
||||
name: SequentialLR
|
||||
interval: step
|
||||
schedulers:
|
||||
- name: LinearLR
|
||||
interval: step
|
||||
args:
|
||||
start_factor: 1e-6
|
||||
end_factor: 1.0
|
||||
total_iters: 2000
|
||||
- name: ConstantLR
|
||||
interval: step
|
||||
args:
|
||||
factor: 1.0
|
||||
total_iters: 9999999
|
||||
milestones: [2000]
|
||||
|
||||
trainer:
|
||||
max_epochs: 5
|
||||
log_every_n_steps: 10
|
||||
num_sanity_val_steps: 1
|
||||
val_check_interval: 2000
|
||||
enable_progress_bar: true
|
||||
precision: bf16-mixed
|
||||
gradient_clip_val: 1.0
|
||||
strategy: ddp
|
||||
accumulate_grad_batches: 1
|
||||
|
||||
checkpoint:
|
||||
save_last: true # whether to save at each validation time
|
||||
save_top_k: -1
|
||||
every_n_epochs: 9999 # do not save at all for debug purpose
|
||||
@@ -0,0 +1,122 @@
|
||||
name: i2mv
|
||||
tag: "r768-ortho-nv6-ele0-sdxl"
|
||||
exp_root_dir: "outputs"
|
||||
seed: 42
|
||||
|
||||
data_cls: mvadapter.data.multiview.MultiviewDataModule
|
||||
data:
|
||||
root_dir: "data/texture_ortho10view_easylight_objaverse"
|
||||
scene_list: "data/objaverse_list_6w.json"
|
||||
background_color: gray
|
||||
image_names: ["0000", "0004", "0001", "0002", "0003", "0005"]
|
||||
image_modality: color
|
||||
num_views: 6
|
||||
|
||||
prompt_db_path: data/objaverse_short_captions.json
|
||||
return_prompt: true
|
||||
|
||||
projection_type: ORTHO
|
||||
|
||||
source_image_modality: ["plucker"]
|
||||
plucker_offset: 1.0
|
||||
plucker_scale: 2.0
|
||||
|
||||
reference_root_dir: ["data/texture_rand_easylight_objaverse"]
|
||||
reference_scene_list: ["data/objaverse_list_6w.json"]
|
||||
reference_image_modality: color
|
||||
reference_image_names: ["0000", "0001", "0002", "0003", "0004"]
|
||||
|
||||
train_indices: [0, -8]
|
||||
val_indices: [-8, null]
|
||||
test_indices: [-8, null]
|
||||
|
||||
height: 768
|
||||
width: 768
|
||||
|
||||
batch_size: 1
|
||||
num_workers: 16
|
||||
|
||||
system_cls: mvadapter.systems.mvadapter_image_sdxl.MVAdapterImageSDXLSystem
|
||||
system:
|
||||
check_train_every_n_steps: 1000
|
||||
cleanup_after_validation_step: true
|
||||
cleanup_after_test_step: true
|
||||
|
||||
# Model / Adapter
|
||||
pretrained_model_name_or_path: "stabilityai/stable-diffusion-xl-base-1.0"
|
||||
pretrained_vae_name_or_path: "madebyollin/sdxl-vae-fp16-fix"
|
||||
pretrained_adapter_name_or_path: null
|
||||
init_adapter_kwargs:
|
||||
# Multi-view adapter
|
||||
self_attn_processor: "mvadapter.models.attention_processor.DecoupledMVRowSelfAttnProcessor2_0"
|
||||
# Condition encoder
|
||||
cond_in_channels: 6
|
||||
# For training
|
||||
copy_attn_weights: true
|
||||
zero_init_module_keys: ["to_out_mv", "to_out_ref"]
|
||||
|
||||
# Training
|
||||
train_cond_encoder: true
|
||||
trainable_modules: ["_mv", "_ref"]
|
||||
prompt_drop_prob: 0.1
|
||||
image_drop_prob: 0.1
|
||||
cond_drop_prob: 0.1
|
||||
|
||||
# Noise sampler
|
||||
shift_noise: true
|
||||
shift_noise_mode: interpolated
|
||||
shift_noise_scale: 8
|
||||
|
||||
# Evaluation
|
||||
eval_seed: 42
|
||||
eval_num_inference_steps: 30
|
||||
eval_guidance_scale: 3.0
|
||||
eval_height: ${data.height}
|
||||
eval_width: ${data.width}
|
||||
|
||||
# optimizer definition
|
||||
# you can set different learning rates separately for each group of parameters, but note that if you do this you should specify EVERY trainable parameters
|
||||
optimizer:
|
||||
name: AdamW
|
||||
args:
|
||||
lr: 5e-5
|
||||
betas: [0.9, 0.999]
|
||||
weight_decay: 0.01
|
||||
params:
|
||||
cond_encoder:
|
||||
lr: 5e-5
|
||||
unet:
|
||||
lr: 5e-5
|
||||
|
||||
scheduler:
|
||||
name: SequentialLR
|
||||
interval: step
|
||||
schedulers:
|
||||
- name: LinearLR
|
||||
interval: step
|
||||
args:
|
||||
start_factor: 1e-6
|
||||
end_factor: 1.0
|
||||
total_iters: 2000
|
||||
- name: ConstantLR
|
||||
interval: step
|
||||
args:
|
||||
factor: 1.0
|
||||
total_iters: 9999999
|
||||
milestones: [2000]
|
||||
|
||||
trainer:
|
||||
max_epochs: 10
|
||||
log_every_n_steps: 10
|
||||
num_sanity_val_steps: 1
|
||||
val_check_interval: 2000
|
||||
enable_progress_bar: true
|
||||
precision: bf16-mixed
|
||||
gradient_clip_val: 1.0
|
||||
strategy: ddp
|
||||
accumulate_grad_batches: 1
|
||||
|
||||
checkpoint:
|
||||
save_last: true # whether to save at each validation time
|
||||
save_top_k: -1
|
||||
every_n_epochs: 9999 # do not save at all for debug purpose
|
||||
@@ -0,0 +1,123 @@
|
||||
name: i2mv
|
||||
tag: "r768-ortho-nv6-ele0-sdxl-aug-quantity"
|
||||
exp_root_dir: "outputs"
|
||||
seed: 42
|
||||
|
||||
data_cls: mvadapter.data.multiview.MultiviewDataModule
|
||||
data:
|
||||
root_dir: "data/texture_ortho10view_easylight_objaverse"
|
||||
scene_list: "data/objaverse_list_6w.json"
|
||||
background_color: gray
|
||||
image_names: ["0000", "0004", "0001", "0002", "0003", "0005"]
|
||||
image_modality: color
|
||||
num_views: 6
|
||||
random_view_list: [[0, 1, 2, 3, 4, 5], [0, 2, 3, 4], [0, 2, 3], [0, 3]]
|
||||
|
||||
prompt_db_path: data/objaverse_short_captions.json
|
||||
return_prompt: true
|
||||
|
||||
projection_type: ORTHO
|
||||
|
||||
source_image_modality: ["plucker"]
|
||||
plucker_offset: 1.0
|
||||
plucker_scale: 2.0
|
||||
|
||||
reference_root_dir: ["data/texture_rand_easylight_objaverse"]
|
||||
reference_scene_list: ["data/objaverse_list_6w.json"]
|
||||
reference_image_modality: color
|
||||
reference_image_names: ["0000", "0001", "0002", "0003", "0004"]
|
||||
|
||||
train_indices: [0, -8]
|
||||
val_indices: [-8, null]
|
||||
test_indices: [-8, null]
|
||||
|
||||
height: 768
|
||||
width: 768
|
||||
|
||||
batch_size: 1
|
||||
num_workers: 16
|
||||
|
||||
system_cls: mvadapter.systems.mvadapter_image_sdxl.MVAdapterImageSDXLSystem
|
||||
system:
|
||||
check_train_every_n_steps: 1000
|
||||
cleanup_after_validation_step: true
|
||||
cleanup_after_test_step: true
|
||||
|
||||
# Model / Adapter
|
||||
pretrained_model_name_or_path: "stabilityai/stable-diffusion-xl-base-1.0"
|
||||
pretrained_vae_name_or_path: "madebyollin/sdxl-vae-fp16-fix"
|
||||
pretrained_adapter_name_or_path: null
|
||||
init_adapter_kwargs:
|
||||
# Multi-view adapter
|
||||
self_attn_processor: "mvadapter.models.attention_processor.DecoupledMVRowSelfAttnProcessor2_0"
|
||||
# Condition encoder
|
||||
cond_in_channels: 6
|
||||
# For training
|
||||
copy_attn_weights: true
|
||||
zero_init_module_keys: ["to_out_mv", "to_out_ref"]
|
||||
|
||||
# Training
|
||||
train_cond_encoder: true
|
||||
trainable_modules: ["_mv", "_ref"]
|
||||
prompt_drop_prob: 0.1
|
||||
image_drop_prob: 0.1
|
||||
cond_drop_prob: 0.1
|
||||
|
||||
# Noise sampler
|
||||
shift_noise: true
|
||||
shift_noise_mode: interpolated
|
||||
shift_noise_scale: 8
|
||||
|
||||
# Evaluation
|
||||
eval_seed: 42
|
||||
eval_num_inference_steps: 30
|
||||
eval_guidance_scale: 3.0
|
||||
eval_height: ${data.height}
|
||||
eval_width: ${data.width}
|
||||
|
||||
# optimizer definition
|
||||
# you can set different learning rates separately for each group of parameters, but note that if you do this you should specify EVERY trainable parameters
|
||||
optimizer:
|
||||
name: AdamW
|
||||
args:
|
||||
lr: 5e-5
|
||||
betas: [0.9, 0.999]
|
||||
weight_decay: 0.01
|
||||
params:
|
||||
cond_encoder:
|
||||
lr: 5e-5
|
||||
unet:
|
||||
lr: 5e-5
|
||||
|
||||
scheduler:
|
||||
name: SequentialLR
|
||||
interval: step
|
||||
schedulers:
|
||||
- name: LinearLR
|
||||
interval: step
|
||||
args:
|
||||
start_factor: 1e-6
|
||||
end_factor: 1.0
|
||||
total_iters: 2000
|
||||
- name: ConstantLR
|
||||
interval: step
|
||||
args:
|
||||
factor: 1.0
|
||||
total_iters: 9999999
|
||||
milestones: [2000]
|
||||
|
||||
trainer:
|
||||
max_epochs: 10
|
||||
log_every_n_steps: 10
|
||||
num_sanity_val_steps: 1
|
||||
val_check_interval: 2000
|
||||
enable_progress_bar: true
|
||||
precision: bf16-mixed
|
||||
gradient_clip_val: 1.0
|
||||
strategy: ddp
|
||||
accumulate_grad_batches: 1
|
||||
|
||||
checkpoint:
|
||||
save_last: true # whether to save at each validation time
|
||||
save_top_k: -1
|
||||
every_n_epochs: 9999 # do not save at all for debug purpose
|
||||
@@ -0,0 +1,117 @@
|
||||
name: t2mv
|
||||
tag: "r512-ortho-nv6-ele0-sd"
|
||||
exp_root_dir: "outputs"
|
||||
seed: 42
|
||||
|
||||
data_cls: mvadapter.data.multiview.MultiviewDataModule
|
||||
data:
|
||||
root_dir: "data/texture_ortho10view_easylight_objaverse"
|
||||
scene_list: "data/objaverse_list_6w.json"
|
||||
background_color: gray
|
||||
image_names: ["0000", "0004", "0001", "0002", "0003", "0005"]
|
||||
image_modality: color
|
||||
num_views: 6
|
||||
|
||||
prompt_db_path: data/objaverse_short_captions.json
|
||||
return_prompt: true
|
||||
|
||||
projection_type: ORTHO
|
||||
|
||||
source_image_modality: ["plucker"]
|
||||
plucker_offset: 1.0
|
||||
plucker_scale: 2.0
|
||||
|
||||
train_indices: [0, -8]
|
||||
val_indices: [-8, null]
|
||||
test_indices: [-8, null]
|
||||
|
||||
height: 512
|
||||
width: 512
|
||||
|
||||
batch_size: 1
|
||||
num_workers: 16
|
||||
|
||||
system_cls: mvadapter.systems.mvadapter_text_sd.MVAdapterTextSDSystem
|
||||
system:
|
||||
check_train_every_n_steps: 1000
|
||||
cleanup_after_validation_step: true
|
||||
cleanup_after_test_step: true
|
||||
|
||||
# Model / Adapter
|
||||
pretrained_model_name_or_path: "stabilityai/stable-diffusion-2-1-base"
|
||||
pretrained_vae_name_or_path: null
|
||||
pretrained_adapter_name_or_path: null
|
||||
init_adapter_kwargs:
|
||||
# Multi-view adapter
|
||||
self_attn_processor: "mvadapter.models.attention_processor.DecoupledMVRowSelfAttnProcessor2_0"
|
||||
# Condition encoder
|
||||
cond_in_channels: 6
|
||||
# For training
|
||||
copy_attn_weights: true
|
||||
zero_init_module_keys: ["to_out_mv"]
|
||||
|
||||
# Training
|
||||
train_cond_encoder: true
|
||||
trainable_modules: ["_mv"]
|
||||
prompt_drop_prob: 0.1
|
||||
image_drop_prob: 0.1
|
||||
cond_drop_prob: 0.1
|
||||
|
||||
# Noise sampler
|
||||
shift_noise: true
|
||||
shift_noise_mode: interpolated
|
||||
shift_noise_scale: 8
|
||||
|
||||
# Evaluation
|
||||
eval_seed: 42
|
||||
eval_num_inference_steps: 30
|
||||
eval_guidance_scale: 3.0
|
||||
eval_height: ${data.height}
|
||||
eval_width: ${data.width}
|
||||
|
||||
# optimizer definition
|
||||
# you can set different learning rates separately for each group of parameters, but note that if you do this you should specify EVERY trainable parameters
|
||||
optimizer:
|
||||
name: AdamW
|
||||
args:
|
||||
lr: 5e-5
|
||||
betas: [0.9, 0.999]
|
||||
weight_decay: 0.01
|
||||
params:
|
||||
cond_encoder:
|
||||
lr: 5e-5
|
||||
unet:
|
||||
lr: 5e-5
|
||||
|
||||
scheduler:
|
||||
name: SequentialLR
|
||||
interval: step
|
||||
schedulers:
|
||||
- name: LinearLR
|
||||
interval: step
|
||||
args:
|
||||
start_factor: 1e-6
|
||||
end_factor: 1.0
|
||||
total_iters: 2000
|
||||
- name: ConstantLR
|
||||
interval: step
|
||||
args:
|
||||
factor: 1.0
|
||||
total_iters: 9999999
|
||||
milestones: [2000]
|
||||
|
||||
trainer:
|
||||
max_epochs: 10
|
||||
log_every_n_steps: 10
|
||||
num_sanity_val_steps: 1
|
||||
val_check_interval: 2000
|
||||
enable_progress_bar: true
|
||||
precision: bf16-mixed
|
||||
gradient_clip_val: 1.0
|
||||
strategy: ddp
|
||||
accumulate_grad_batches: 1
|
||||
|
||||
checkpoint:
|
||||
save_last: true # whether to save at each validation time
|
||||
save_top_k: -1
|
||||
every_n_epochs: 9999 # do not save at all for debug purpose
|
||||
@@ -0,0 +1,117 @@
|
||||
name: t2mv
|
||||
tag: "r768-ortho-nv6-ele0-sdxl"
|
||||
exp_root_dir: "outputs"
|
||||
seed: 42
|
||||
|
||||
data_cls: mvadapter.data.multiview.MultiviewDataModule
|
||||
data:
|
||||
root_dir: "data/texture_ortho10view_easylight_objaverse"
|
||||
scene_list: "data/objaverse_list_6w.json"
|
||||
background_color: gray
|
||||
image_names: ["0000", "0004", "0001", "0002", "0003", "0005"]
|
||||
image_modality: color
|
||||
num_views: 6
|
||||
|
||||
prompt_db_path: data/objaverse_short_captions.json
|
||||
return_prompt: true
|
||||
|
||||
projection_type: ORTHO
|
||||
|
||||
source_image_modality: ["plucker"]
|
||||
plucker_offset: 1.0
|
||||
plucker_scale: 2.0
|
||||
|
||||
train_indices: [0, -8]
|
||||
val_indices: [-8, null]
|
||||
test_indices: [-8, null]
|
||||
|
||||
height: 768
|
||||
width: 768
|
||||
|
||||
batch_size: 1
|
||||
num_workers: 16
|
||||
|
||||
system_cls: mvadapter.systems.mvadapter_text_sdxl.MVAdapterTextSDXLSystem
|
||||
system:
|
||||
check_train_every_n_steps: 1000
|
||||
cleanup_after_validation_step: true
|
||||
cleanup_after_test_step: true
|
||||
|
||||
# Model / Adapter
|
||||
pretrained_model_name_or_path: "stabilityai/stable-diffusion-xl-base-1.0"
|
||||
pretrained_vae_name_or_path: "madebyollin/sdxl-vae-fp16-fix"
|
||||
pretrained_adapter_name_or_path: null
|
||||
init_adapter_kwargs:
|
||||
# Multi-view adapter
|
||||
self_attn_processor: "mvadapter.models.attention_processor.DecoupledMVRowSelfAttnProcessor2_0"
|
||||
# Condition encoder
|
||||
cond_in_channels: 6
|
||||
# For training
|
||||
copy_attn_weights: true
|
||||
zero_init_module_keys: ["to_out_mv"]
|
||||
|
||||
# Training
|
||||
train_cond_encoder: true
|
||||
trainable_modules: ["_mv"]
|
||||
prompt_drop_prob: 0.1
|
||||
image_drop_prob: 0.1
|
||||
cond_drop_prob: 0.1
|
||||
|
||||
# Noise sampler
|
||||
shift_noise: true
|
||||
shift_noise_mode: interpolated
|
||||
shift_noise_scale: 8
|
||||
|
||||
# Evaluation
|
||||
eval_seed: 42
|
||||
eval_num_inference_steps: 30
|
||||
eval_guidance_scale: 3.0
|
||||
eval_height: ${data.height}
|
||||
eval_width: ${data.width}
|
||||
|
||||
# optimizer definition
|
||||
# you can set different learning rates separately for each group of parameters, but note that if you do this you should specify EVERY trainable parameters
|
||||
optimizer:
|
||||
name: AdamW
|
||||
args:
|
||||
lr: 5e-5
|
||||
betas: [0.9, 0.999]
|
||||
weight_decay: 0.01
|
||||
params:
|
||||
cond_encoder:
|
||||
lr: 5e-5
|
||||
unet:
|
||||
lr: 5e-5
|
||||
|
||||
scheduler:
|
||||
name: SequentialLR
|
||||
interval: step
|
||||
schedulers:
|
||||
- name: LinearLR
|
||||
interval: step
|
||||
args:
|
||||
start_factor: 1e-6
|
||||
end_factor: 1.0
|
||||
total_iters: 2000
|
||||
- name: ConstantLR
|
||||
interval: step
|
||||
args:
|
||||
factor: 1.0
|
||||
total_iters: 9999999
|
||||
milestones: [2000]
|
||||
|
||||
trainer:
|
||||
max_epochs: 10
|
||||
log_every_n_steps: 10
|
||||
num_sanity_val_steps: 1
|
||||
val_check_interval: 2000
|
||||
enable_progress_bar: true
|
||||
precision: bf16-mixed
|
||||
gradient_clip_val: 1.0
|
||||
strategy: ddp
|
||||
accumulate_grad_batches: 1
|
||||
|
||||
checkpoint:
|
||||
save_last: true # whether to save at each validation time
|
||||
save_top_k: -1
|
||||
every_n_epochs: 9999 # do not save at all for debug purpose
|
||||
@@ -0,0 +1,169 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
!hy3dgen/texgen/custom_rasterizer/lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
.DS_Store
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
gradio_cache/
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
@@ -0,0 +1,80 @@
|
||||
TENCENT HUNYUAN 3D 2.0 COMMUNITY LICENSE AGREEMENT
|
||||
Tencent Hunyuan 3D 2.0 Release Date: January 21, 2025
|
||||
THIS LICENSE AGREEMENT DOES NOT APPLY IN THE EUROPEAN UNION, UNITED KINGDOM AND SOUTH KOREA AND IS EXPRESSLY LIMITED TO THE TERRITORY, AS DEFINED BELOW.
|
||||
By clicking to agree or by using, reproducing, modifying, distributing, performing or displaying any portion or element of the Tencent Hunyuan 3D 2.0 Works, including via any Hosted Service, You will be deemed to have recognized and accepted the content of this Agreement, which is effective immediately.
|
||||
1. DEFINITIONS.
|
||||
a. “Acceptable Use Policy” shall mean the policy made available by Tencent as set forth in the Exhibit A.
|
||||
b. “Agreement” shall mean the terms and conditions for use, reproduction, distribution, modification, performance and displaying of Tencent Hunyuan 3D 2.0 Works or any portion or element thereof set forth herein.
|
||||
c. “Documentation” shall mean the specifications, manuals and documentation for Tencent Hunyuan 3D 2.0 made publicly available by Tencent.
|
||||
d. “Hosted Service” shall mean a hosted service offered via an application programming interface (API), web access, or any other electronic or remote means.
|
||||
e. “Licensee,” “You” or “Your” shall mean a natural person or legal entity exercising the rights granted by this Agreement and/or using the Tencent Hunyuan 3D 2.0 Works for any purpose and in any field of use.
|
||||
f. “Materials” shall mean, collectively, Tencent’s proprietary Tencent Hunyuan 3D 2.0 and Documentation (and any portion thereof) as made available by Tencent under this Agreement.
|
||||
g. “Model Derivatives” shall mean all: (i) modifications to Tencent Hunyuan 3D 2.0 or any Model Derivative of Tencent Hunyuan 3D 2.0; (ii) works based on Tencent Hunyuan 3D 2.0 or any Model Derivative of Tencent Hunyuan 3D 2.0; or (iii) any other machine learning model which is created by transfer of patterns of the weights, parameters, operations, or Output of Tencent Hunyuan 3D 2.0 or any Model Derivative of Tencent Hunyuan 3D 2.0, to that model in order to cause that model to perform similarly to Tencent Hunyuan 3D 2.0 or a Model Derivative of Tencent Hunyuan 3D 2.0, including distillation methods, methods that use intermediate data representations, or methods based on the generation of synthetic data Outputs by Tencent Hunyuan 3D 2.0 or a Model Derivative of Tencent Hunyuan 3D 2.0 for training that model. For clarity, Outputs by themselves are not deemed Model Derivatives.
|
||||
h. “Output” shall mean the information and/or content output of Tencent Hunyuan 3D 2.0 or a Model Derivative that results from operating or otherwise using Tencent Hunyuan 3D 2.0 or a Model Derivative, including via a Hosted Service.
|
||||
i. “Tencent,” “We” or “Us” shall mean THL A29 Limited.
|
||||
j. “Tencent Hunyuan 3D 2.0” shall mean the 3D generation models and their software and algorithms, including trained model weights, parameters (including optimizer states), machine-learning model code, inference-enabling code, training-enabling code, fine-tuning enabling code and other elements of the foregoing made publicly available by Us at https://github.com/Tencent/Hunyuan3D-2.
|
||||
k. “Tencent Hunyuan 3D 2.0 Works” shall mean: (i) the Materials; (ii) Model Derivatives; and (iii) all derivative works thereof.
|
||||
l. “Territory” shall mean the worldwide territory, excluding the territory of the European Union, United Kingdom and South Korea.
|
||||
m. “Third Party” or “Third Parties” shall mean individuals or legal entities that are not under common control with Us or You.
|
||||
n. “including” shall mean including but not limited to.
|
||||
2. GRANT OF RIGHTS.
|
||||
We grant You, for the Territory only, a non-exclusive, non-transferable and royalty-free limited license under Tencent’s intellectual property or other rights owned by Us embodied in or utilized by the Materials to use, reproduce, distribute, create derivative works of (including Model Derivatives), and make modifications to the Materials, only in accordance with the terms of this Agreement and the Acceptable Use Policy, and You must not violate (or encourage or permit anyone else to violate) any term of this Agreement or the Acceptable Use Policy.
|
||||
3. DISTRIBUTION.
|
||||
You may, subject to Your compliance with this Agreement, distribute or make available to Third Parties the Tencent Hunyuan 3D 2.0 Works, exclusively in the Territory, provided that You meet all of the following conditions:
|
||||
a. You must provide all such Third Party recipients of the Tencent Hunyuan 3D 2.0 Works or products or services using them a copy of this Agreement;
|
||||
b. You must cause any modified files to carry prominent notices stating that You changed the files;
|
||||
c. You are encouraged to: (i) publish at least one technology introduction blogpost or one public statement expressing Your experience of using the Tencent Hunyuan 3D 2.0 Works; and (ii) mark the products or services developed by using the Tencent Hunyuan 3D 2.0 Works to indicate that the product/service is “Powered by Tencent Hunyuan”; and
|
||||
d. All distributions to Third Parties (other than through a Hosted Service) must be accompanied by a “Notice” text file that contains the following notice: “Tencent Hunyuan 3D 2.0 is licensed under the Tencent Hunyuan 3D 2.0 Community License Agreement, Copyright © 2025 Tencent. All Rights Reserved. The trademark rights of “Tencent Hunyuan” are owned by Tencent or its affiliate.”
|
||||
You may add Your own copyright statement to Your modifications and, except as set forth in this Section and in Section 5, may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Model Derivatives as a whole, provided Your use, reproduction, modification, distribution, performance and display of the work otherwise complies with the terms and conditions of this Agreement (including as regards the Territory). If You receive Tencent Hunyuan 3D 2.0 Works from a Licensee as part of an integrated end user product, then this Section 3 of this Agreement will not apply to You.
|
||||
4. ADDITIONAL COMMERCIAL TERMS.
|
||||
If, on the Tencent Hunyuan 3D 2.0 version release date, the monthly active users of all products or services made available by or for Licensee is greater than 1 million monthly active users in the preceding calendar month, You must request a license from Tencent, which Tencent may grant to You in its sole discretion, and You are not authorized to exercise any of the rights under this Agreement unless or until Tencent otherwise expressly grants You such rights.
|
||||
Subject to Tencent's written approval, you may request a license for the use of Tencent Hunyuan 3D 2.0 by submitting the following information to hunyuan3d@tencent.com:
|
||||
a. Your company’s name and associated business sector that plans to use Tencent Hunyuan 3D 2.0.
|
||||
b. Your intended use case and the purpose of using Tencent Hunyuan 3D 2.0.
|
||||
5. RULES OF USE.
|
||||
a. Your use of the Tencent Hunyuan 3D 2.0 Works must comply with applicable laws and regulations (including trade compliance laws and regulations) and adhere to the Acceptable Use Policy for the Tencent Hunyuan 3D 2.0 Works, which is hereby incorporated by reference into this Agreement. You must include the use restrictions referenced in these Sections 5(a) and 5(b) as an enforceable provision in any agreement (e.g., license agreement, terms of use, etc.) governing the use and/or distribution of Tencent Hunyuan 3D 2.0 Works and You must provide notice to subsequent users to whom You distribute that Tencent Hunyuan 3D 2.0 Works are subject to the use restrictions in these Sections 5(a) and 5(b).
|
||||
b. You must not use the Tencent Hunyuan 3D 2.0 Works or any Output or results of the Tencent Hunyuan 3D 2.0 Works to improve any other AI model (other than Tencent Hunyuan 3D 2.0 or Model Derivatives thereof).
|
||||
c. You must not use, reproduce, modify, distribute, or display the Tencent Hunyuan 3D 2.0 Works, Output or results of the Tencent Hunyuan 3D 2.0 Works outside the Territory. Any such use outside the Territory is unlicensed and unauthorized under this Agreement.
|
||||
6. INTELLECTUAL PROPERTY.
|
||||
a. Subject to Tencent’s ownership of Tencent Hunyuan 3D 2.0 Works made by or for Tencent and intellectual property rights therein, conditioned upon Your compliance with the terms and conditions of this Agreement, as between You and Tencent, You will be the owner of any derivative works and modifications of the Materials and any Model Derivatives that are made by or for You.
|
||||
b. No trademark licenses are granted under this Agreement, and in connection with the Tencent Hunyuan 3D 2.0 Works, Licensee may not use any name or mark owned by or associated with Tencent or any of its affiliates, except as required for reasonable and customary use in describing and distributing the Tencent Hunyuan 3D 2.0 Works. Tencent hereby grants You a license to use “Tencent Hunyuan” (the “Mark”) in the Territory solely as required to comply with the provisions of Section 3(c), provided that You comply with any applicable laws related to trademark protection. All goodwill arising out of Your use of the Mark will inure to the benefit of Tencent.
|
||||
c. If You commence a lawsuit or other proceedings (including a cross-claim or counterclaim in a lawsuit) against Us or any person or entity alleging that the Materials or any Output, or any portion of any of the foregoing, infringe any intellectual property or other right owned or licensable by You, then all licenses granted to You under this Agreement shall terminate as of the date such lawsuit or other proceeding is filed. You will defend, indemnify and hold harmless Us from and against any claim by any Third Party arising out of or related to Your or the Third Party’s use or distribution of the Tencent Hunyuan 3D 2.0 Works.
|
||||
d. Tencent claims no rights in Outputs You generate. You and Your users are solely responsible for Outputs and their subsequent uses.
|
||||
7. DISCLAIMERS OF WARRANTY AND LIMITATIONS OF LIABILITY.
|
||||
a. We are not obligated to support, update, provide training for, or develop any further version of the Tencent Hunyuan 3D 2.0 Works or to grant any license thereto.
|
||||
b. UNLESS AND ONLY TO THE EXTENT REQUIRED BY APPLICABLE LAW, THE TENCENT HUNYUAN 3D 2.0 WORKS AND ANY OUTPUT AND RESULTS THEREFROM ARE PROVIDED “AS IS” WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND INCLUDING ANY WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, COURSE OF DEALING, USAGE OF TRADE, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING, REPRODUCING, MODIFYING, PERFORMING, DISPLAYING OR DISTRIBUTING ANY OF THE TENCENT HUNYUAN 3D 2.0 WORKS OR OUTPUTS AND ASSUME ANY AND ALL RISKS ASSOCIATED WITH YOUR OR A THIRD PARTY’S USE OR DISTRIBUTION OF ANY OF THE TENCENT HUNYUAN 3D 2.0 WORKS OR OUTPUTS AND YOUR EXERCISE OF RIGHTS AND PERMISSIONS UNDER THIS AGREEMENT.
|
||||
c. TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL TENCENT OR ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, FOR ANY DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY, CONSEQUENTIAL OR PUNITIVE DAMAGES, OR LOST PROFITS OF ANY KIND ARISING FROM THIS AGREEMENT OR RELATED TO ANY OF THE TENCENT HUNYUAN 3D 2.0 WORKS OR OUTPUTS, EVEN IF TENCENT OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF ANY OF THE FOREGOING.
|
||||
8. SURVIVAL AND TERMINATION.
|
||||
a. The term of this Agreement shall commence upon Your acceptance of this Agreement or access to the Materials and will continue in full force and effect until terminated in accordance with the terms and conditions herein.
|
||||
b. We may terminate this Agreement if You breach any of the terms or conditions of this Agreement. Upon termination of this Agreement, You must promptly delete and cease use of the Tencent Hunyuan 3D 2.0 Works. Sections 6(a), 6(c), 7 and 9 shall survive the termination of this Agreement.
|
||||
9. GOVERNING LAW AND JURISDICTION.
|
||||
a. This Agreement and any dispute arising out of or relating to it will be governed by the laws of the Hong Kong Special Administrative Region of the People’s Republic of China, without regard to conflict of law principles, and the UN Convention on Contracts for the International Sale of Goods does not apply to this Agreement.
|
||||
b. Exclusive jurisdiction and venue for any dispute arising out of or relating to this Agreement will be a court of competent jurisdiction in the Hong Kong Special Administrative Region of the People’s Republic of China, and Tencent and Licensee consent to the exclusive jurisdiction of such court with respect to any such dispute.
|
||||
|
||||
EXHIBIT A
|
||||
ACCEPTABLE USE POLICY
|
||||
|
||||
Tencent reserves the right to update this Acceptable Use Policy from time to time.
|
||||
Last modified: November 5, 2024
|
||||
|
||||
Tencent endeavors to promote safe and fair use of its tools and features, including Tencent Hunyuan 3D 2.0. You agree not to use Tencent Hunyuan 3D 2.0 or Model Derivatives:
|
||||
1. Outside the Territory;
|
||||
2. In any way that violates any applicable national, federal, state, local, international or any other law or regulation;
|
||||
3. To harm Yourself or others;
|
||||
4. To repurpose or distribute output from Tencent Hunyuan 3D 2.0 or any Model Derivatives to harm Yourself or others;
|
||||
5. To override or circumvent the safety guardrails and safeguards We have put in place;
|
||||
6. For the purpose of exploiting, harming or attempting to exploit or harm minors in any way;
|
||||
7. To generate or disseminate verifiably false information and/or content with the purpose of harming others or influencing elections;
|
||||
8. To generate or facilitate false online engagement, including fake reviews and other means of fake online engagement;
|
||||
9. To intentionally defame, disparage or otherwise harass others;
|
||||
10. To generate and/or disseminate malware (including ransomware) or any other content to be used for the purpose of harming electronic systems;
|
||||
11. To generate or disseminate personal identifiable information with the purpose of harming others;
|
||||
12. To generate or disseminate information (including images, code, posts, articles), and place the information in any public context (including –through the use of bot generated tweets), without expressly and conspicuously identifying that the information and/or content is machine generated;
|
||||
13. To impersonate another individual without consent, authorization, or legal right;
|
||||
14. To make high-stakes automated decisions in domains that affect an individual’s safety, rights or wellbeing (e.g., law enforcement, migration, medicine/health, management of critical infrastructure, safety components of products, essential services, credit, employment, housing, education, social scoring, or insurance);
|
||||
15. In a manner that violates or disrespects the social ethics and moral standards of other countries or regions;
|
||||
16. To perform, facilitate, threaten, incite, plan, promote or encourage violent extremism or terrorism;
|
||||
17. For any use intended to discriminate against or harm individuals or groups based on protected characteristics or categories, online or offline social behavior or known or predicted personal or personality characteristics;
|
||||
18. To intentionally exploit any of the vulnerabilities of a specific group of persons based on their age, social, physical or mental characteristics, in order to materially distort the behavior of a person pertaining to that group in a manner that causes or is likely to cause that person or another person physical or psychological harm;
|
||||
19. For military purposes;
|
||||
20. To engage in the unauthorized or unlicensed practice of any profession including, but not limited to, financial, legal, medical/health, or other professional practices.
|
||||
@@ -0,0 +1,214 @@
|
||||
Usage and Legal Notices:
|
||||
|
||||
Tencent is pleased to support the open source community by making Hunyuan 3D 2.0 available.
|
||||
|
||||
Copyright (C) 2025 THL A29 Limited, a Tencent company. All rights reserved. The below software and/or models in this distribution may have been modified by THL A29 Limited ("Tencent Modifications"). All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
Hunyuan 3D 2.0 is licensed under the TENCENT HUNYUAN 3D 2.0 COMMUNITY LICENSE AGREEMENT except for the third-party components listed below, which is licensed under different terms. Hunyuan 3D 2.0 does not impose any additional limitations beyond what is outlined in the respective licenses of these third-party components. Users must comply with all terms and conditions of original licenses of these third-party components and must ensure that the usage of the third party components adheres to all relevant laws and regulations.
|
||||
|
||||
For avoidance of doubts, Hunyuan 3D 2.0 means inference-enabling code, parameters, and weights of this Model only, which are made publicly available by Tencent in accordance with TENCENT HUNYUAN 3D 2.0 COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
||||
|
||||
Open Source Model Licensed under the MIT and CreativeML Open RAIL++-M License:
|
||||
--------------------------------------------------------------------
|
||||
1. Stable Diffusion
|
||||
Copyright (c) 2022 Stability AI
|
||||
|
||||
|
||||
Terms of the MIT and CreativeML Open RAIL++-M License:
|
||||
--------------------------------------------------------------------
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
CreativeML Open RAIL++-M License
|
||||
dated November 24, 2022
|
||||
|
||||
Section I: PREAMBLE
|
||||
|
||||
Multimodal generative models are being widely adopted and used, and have the potential to transform the way artists, among other individuals, conceive and benefit from AI or ML technologies as a tool for content creation.
|
||||
|
||||
Notwithstanding the current and potential benefits that these artifacts can bring to society at large, there are also concerns about potential misuses of them, either due to their technical limitations or ethical considerations.
|
||||
|
||||
In short, this license strives for both the open and responsible downstream use of the accompanying model. When it comes to the open character, we took inspiration from open source permissive licenses regarding the grant of IP rights. Referring to the downstream responsible use, we added use-based restrictions not permitting the use of the Model in very specific scenarios, in order for the licensor to be able to enforce the license in case potential misuses of the Model may occur. At the same time, we strive to promote open and responsible research on generative models for art and content generation.
|
||||
|
||||
Even though downstream derivative versions of the model could be released under different licensing terms, the latter will always have to include - at minimum - the same use-based restrictions as the ones in the original license (this license). We believe in the intersection between open and responsible AI development; thus, this License aims to strike a balance between both in order to enable responsible open-science in the field of AI.
|
||||
|
||||
This License governs the use of the model (and its derivatives) and is informed by the model card associated with the model.
|
||||
|
||||
NOW THEREFORE, You and Licensor agree as follows:
|
||||
|
||||
1. Definitions
|
||||
|
||||
- "License" means the terms and conditions for use, reproduction, and Distribution as defined in this document.
|
||||
- "Data" means a collection of information and/or content extracted from the dataset used with the Model, including to train, pretrain, or otherwise evaluate the Model. The Data is not licensed under this License.
|
||||
- "Output" means the results of operating a Model as embodied in informational content resulting therefrom.
|
||||
- "Model" means any accompanying machine-learning based assemblies (including checkpoints), consisting of learnt weights, parameters (including optimizer states), corresponding to the model architecture as embodied in the Complementary Material, that have been trained or tuned, in whole or in part on the Data, using the Complementary Material.
|
||||
- "Derivatives of the Model" means all modifications to the Model, works based on the Model, or any other model which is created or initialized by transfer of patterns of the weights, parameters, activations or output of the Model, to the other model, in order to cause the other model to perform similarly to the Model, including - but not limited to - distillation methods entailing the use of intermediate data representations or methods based on the generation of synthetic data by the Model for training the other model.
|
||||
- "Complementary Material" means the accompanying source code and scripts used to define, run, load, benchmark or evaluate the Model, and used to prepare data for training or evaluation, if any. This includes any accompanying documentation, tutorials, examples, etc, if any.
|
||||
- "Distribution" means any transmission, reproduction, publication or other sharing of the Model or Derivatives of the Model to a third party, including providing the Model as a hosted service made available by electronic or other remote means - e.g. API-based or web access.
|
||||
- "Licensor" means the copyright owner or entity authorized by the copyright owner that is granting the License, including the persons or entities that may have rights in the Model and/or distributing the Model.
|
||||
- "You" (or "Your") means an individual or Legal Entity exercising permissions granted by this License and/or making use of the Model for whichever purpose and in any field of use, including usage of the Model in an end-use application - e.g. chatbot, translator, image generator.
|
||||
- "Third Parties" means individuals or legal entities that are not under common control with Licensor or You.
|
||||
- "Contribution" means any work of authorship, including the original version of the Model and any modifications or additions to that Model or Derivatives of the Model thereof, that is intentionally submitted to Licensor for inclusion in the Model by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Model, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
- "Contributor" means Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Model.
|
||||
|
||||
Section II: INTELLECTUAL PROPERTY RIGHTS
|
||||
|
||||
Both copyright and patent grants apply to the Model, Derivatives of the Model and Complementary Material. The Model and Derivatives of the Model are subject to additional terms as described in Section III.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare, publicly display, publicly perform, sublicense, and distribute the Complementary Material, the Model, and Derivatives of the Model.
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License and where and as applicable, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this paragraph) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Model and the Complementary Material, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Model to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Model and/or Complementary Material or a Contribution incorporated within the Model and/or Complementary Material constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for the Model and/or Work shall terminate as of the date such litigation is asserted or filed.
|
||||
|
||||
Section III: CONDITIONS OF USAGE, DISTRIBUTION AND REDISTRIBUTION
|
||||
|
||||
4. Distribution and Redistribution. You may host for Third Party remote access purposes (e.g. software-as-a-service), reproduce and distribute copies of the Model or Derivatives of the Model thereof in any medium, with or without modifications, provided that You meet the following conditions:
|
||||
Use-based restrictions as referenced in paragraph 5 MUST be included as an enforceable provision by You in any type of legal agreement (e.g. a license) governing the use and/or distribution of the Model or Derivatives of the Model, and You shall give notice to subsequent users You Distribute to, that the Model or Derivatives of the Model are subject to paragraph 5. This provision does not apply to the use of Complementary Material.
|
||||
You must give any Third Party recipients of the Model or Derivatives of the Model a copy of this License;
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files;
|
||||
You must retain all copyright, patent, trademark, and attribution notices excluding those notices that do not pertain to any part of the Model, Derivatives of the Model.
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions - respecting paragraph 4.a. - for use, reproduction, or Distribution of Your modifications, or for any such Derivatives of the Model as a whole, provided Your use, reproduction, and Distribution of the Model otherwise complies with the conditions stated in this License.
|
||||
5. Use-based restrictions. The restrictions set forth in Attachment A are considered Use-based restrictions. Therefore You cannot use the Model and the Derivatives of the Model for the specified restricted uses. You may use the Model subject to this License, including only for lawful purposes and in accordance with the License. Use may include creating any content with, finetuning, updating, running, training, evaluating and/or reparametrizing the Model. You shall require all of Your users who use the Model or a Derivative of the Model to comply with the terms of this paragraph (paragraph 5).
|
||||
6. The Output You Generate. Except as set forth herein, Licensor claims no rights in the Output You generate using the Model. You are accountable for the Output you generate and its subsequent uses. No use of the output can contravene any provision as stated in the License.
|
||||
|
||||
Section IV: OTHER PROVISIONS
|
||||
|
||||
7. Updates and Runtime Restrictions. To the maximum extent permitted by law, Licensor reserves the right to restrict (remotely or otherwise) usage of the Model in violation of this License.
|
||||
8. Trademarks and related. Nothing in this License permits You to make use of Licensors’ trademarks, trade names, logos or to otherwise suggest endorsement or misrepresent the relationship between the parties; and any rights not expressly granted herein are reserved by the Licensors.
|
||||
9. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Model and the Complementary Material (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Model, Derivatives of the Model, and the Complementary Material and assume any risks associated with Your exercise of permissions under this License.
|
||||
10. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Model and the Complementary Material (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
11. Accepting Warranty or Additional Liability. While redistributing the Model, Derivatives of the Model and the Complementary Material thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
12. If any provision of this License is held to be invalid, illegal or unenforceable, the remaining provisions shall be unaffected thereby and remain valid as if such provision had not been set forth herein.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
|
||||
|
||||
Attachment A
|
||||
|
||||
Use Restrictions
|
||||
|
||||
You agree not to use the Model or Derivatives of the Model:
|
||||
|
||||
- In any way that violates any applicable national, federal, state, local or international law or regulation;
|
||||
- For the purpose of exploiting, harming or attempting to exploit or harm minors in any way;
|
||||
- To generate or disseminate verifiably false information and/or content with the purpose of harming others;
|
||||
- To generate or disseminate personal identifiable information that can be used to harm an individual;
|
||||
- To defame, disparage or otherwise harass others;
|
||||
- For fully automated decision making that adversely impacts an individual’s legal rights or otherwise creates or modifies a binding, enforceable obligation;
|
||||
- For any use intended to or which has the effect of discriminating against or harming individuals or groups based on online or offline social behavior or known or predicted personal or personality characteristics;
|
||||
- To exploit any of the vulnerabilities of a specific group of persons based on their age, social, physical or mental characteristics, in order to materially distort the behavior of a person pertaining to that group in a manner that causes or is likely to cause that person or another person physical or psychological harm;
|
||||
- For any use intended to or which has the effect of discriminating against individuals or groups based on legally protected characteristics or categories;
|
||||
- To provide medical advice and medical results interpretation;
|
||||
- To generate or disseminate information for the purpose to be used for administration of justice, law enforcement, immigration or asylum processes, such as predicting an individual will commit fraud/crime commitment (e.g. by text profiling, drawing causal relationships between assertions made in documents, indiscriminate and arbitrarily-targeted use).
|
||||
|
||||
|
||||
|
||||
Open Source Model Licensed under the TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT and Other Licenses of the Third-Party Components therein:
|
||||
--------------------------------------------------------------------
|
||||
1. HunyuanDiT
|
||||
Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
|
||||
Terms of the TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT:
|
||||
--------------------------------------------------------------------
|
||||
TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT
|
||||
Tencent Hunyuan Release Date: 2024/5/14
|
||||
By clicking to agree or by using, reproducing, modifying, distributing, performing or displaying any portion or element of the Tencent Hunyuan Works, including via any Hosted Service, You will be deemed to have recognized and accepted the content of this Agreement, which is effective immediately.
|
||||
1. DEFINITIONS.
|
||||
a. “Acceptable Use Policy” shall mean the policy made available by Tencent as set forth in the Exhibit A.
|
||||
b. “Agreement” shall mean the terms and conditions for use, reproduction, distribution, modification, performance and displaying of the Hunyuan Works or any portion or element thereof set forth herein.
|
||||
c. “Documentation” shall mean the specifications, manuals and documentation for Tencent Hunyuan made publicly available by Tencent.
|
||||
d. “Hosted Service” shall mean a hosted service offered via an application programming interface (API), web access, or any other electronic or remote means.
|
||||
e. “Licensee,” “You” or “Your” shall mean a natural person or legal entity exercising the rights granted by this Agreement and/or using the Tencent Hunyuan Works for any purpose and in any field of use.
|
||||
f. “Materials” shall mean, collectively, Tencent’s proprietary Tencent Hunyuan and Documentation (and any portion thereof) as made available by Tencent under this Agreement.
|
||||
g. “Model Derivatives” shall mean all: (i) modifications to Tencent Hunyuan or any Model Derivative of Tencent Hunyuan; (ii) works based on Tencent Hunyuan or any Model Derivative of Tencent Hunyuan; or (iii) any other machine learning model which is created by transfer of patterns of the weights, parameters, operations, or Output of Tencent Hunyuan or any Model Derivative of Tencent Hunyuan, to that model in order to cause that model to perform similarly to Tencent Hunyuan or a Model Derivative of Tencent Hunyuan, including distillation methods, methods that use intermediate data representations, or methods based on the generation of synthetic data Outputs by Tencent Hunyuan or a Model Derivative of Tencent Hunyuan for training that model. For clarity, Outputs by themselves are not deemed Model Derivatives.
|
||||
h. “Output” shall mean the information and/or content output of Tencent Hunyuan or a Model Derivative that results from operating or otherwise using Tencent Hunyuan or a Model Derivative, including via a Hosted Service.
|
||||
i. “Tencent,” “We” or “Us” shall mean THL A29 Limited.
|
||||
j. “Tencent Hunyuan” shall mean the large language models, image/video/audio/3D generation models, and multimodal large language models and their software and algorithms, including trained model weights, parameters (including optimizer states), machine-learning model code, inference-enabling code, training-enabling code, fine-tuning enabling code and other elements of the foregoing made publicly available by Us at https://huggingface.co/Tencent-Hunyuan/HunyuanDiT and https://github.com/Tencent/HunyuanDiT .
|
||||
k. “Tencent Hunyuan Works” shall mean: (i) the Materials; (ii) Model Derivatives; and (iii) all derivative works thereof.
|
||||
l. “Third Party” or “Third Parties” shall mean individuals or legal entities that are not under common control with Us or You.
|
||||
m. “including” shall mean including but not limited to.
|
||||
2. GRANT OF RIGHTS.
|
||||
We grant You a non-exclusive, worldwide, non-transferable and royalty-free limited license under Tencent’s intellectual property or other rights owned by Us embodied in or utilized by the Materials to use, reproduce, distribute, create derivative works of (including Model Derivatives), and make modifications to the Materials, only in accordance with the terms of this Agreement and the Acceptable Use Policy, and You must not violate (or encourage or permit anyone else to violate) any term of this Agreement or the Acceptable Use Policy.
|
||||
3. DISTRIBUTION.
|
||||
You may, subject to Your compliance with this Agreement, distribute or make available to Third Parties the Tencent Hunyuan Works, provided that You meet all of the following conditions:
|
||||
a. You must provide all such Third Party recipients of the Tencent Hunyuan Works or products or services using them a copy of this Agreement;
|
||||
b. You must cause any modified files to carry prominent notices stating that You changed the files;
|
||||
c. You are encouraged to: (i) publish at least one technology introduction blogpost or one public statement expressing Your experience of using the Tencent Hunyuan Works; and (ii) mark the products or services developed by using the Tencent Hunyuan Works to indicate that the product/service is “Powered by Tencent Hunyuan”; and
|
||||
d. All distributions to Third Parties (other than through a Hosted Service) must be accompanied by a “Notice” text file that contains the following notice: “Tencent Hunyuan is licensed under the Tencent Hunyuan Community License Agreement, Copyright © 2024 Tencent. All Rights Reserved. The trademark rights of “Tencent Hunyuan” are owned by Tencent or its affiliate.”
|
||||
You may add Your own copyright statement to Your modifications and, except as set forth in this Section and in Section 5, may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Model Derivatives as a whole, provided Your use, reproduction, modification, distribution, performance and display of the work otherwise complies with the terms and conditions of this Agreement. If You receive Tencent Hunyuan Works from a Licensee as part of an integrated end user product, then this Section 3 of this Agreement will not apply to You.
|
||||
4. ADDITIONAL COMMERCIAL TERMS.
|
||||
If, on the Tencent Hunyuan version release date, the monthly active users of all products or services made available by or for Licensee is greater than 100 million monthly active users in the preceding calendar month, You must request a license from Tencent, which Tencent may grant to You in its sole discretion, and You are not authorized to exercise any of the rights under this Agreement unless or until Tencent otherwise expressly grants You such rights.
|
||||
5. RULES OF USE.
|
||||
a. Your use of the Tencent Hunyuan Works must comply with applicable laws and regulations (including trade compliance laws and regulations) and adhere to the Acceptable Use Policy for the Tencent Hunyuan Works, which is hereby incorporated by reference into this Agreement. You must include the use restrictions referenced in these Sections 5(a) and 5(b) as an enforceable provision in any agreement (e.g., license agreement, terms of use, etc.) governing the use and/or distribution of Tencent Hunyuan Works and You must provide notice to subsequent users to whom You distribute that Tencent Hunyuan Works are subject to the use restrictions in these Sections 5(a) and 5(b).
|
||||
b. You must not use the Tencent Hunyuan Works or any Output or results of the Tencent Hunyuan Works to improve any other large language model (other than Tencent Hunyuan or Model Derivatives thereof).
|
||||
6. INTELLECTUAL PROPERTY.
|
||||
a. Subject to Tencent’s ownership of Tencent Hunyuan Works made by or for Tencent and intellectual property rights therein, conditioned upon Your compliance with the terms and conditions of this Agreement, as between You and Tencent, You will be the owner of any derivative works and modifications of the Materials and any Model Derivatives that are made by or for You.
|
||||
b. No trademark licenses are granted under this Agreement, and in connection with the Tencent Hunyuan Works, Licensee may not use any name or mark owned by or associated with Tencent or any of its affiliates, except as required for reasonable and customary use in describing and distributing the Tencent Hunyuan Works. Tencent hereby grants You a license to use “Tencent Hunyuan” (the “Mark”) solely as required to comply with the provisions of Section 3(c), provided that You comply with any applicable laws related to trademark protection. All goodwill arising out of Your use of the Mark will inure to the benefit of Tencent.
|
||||
c. If You commence a lawsuit or other proceedings (including a cross-claim or counterclaim in a lawsuit) against Us or any person or entity alleging that the Materials or any Output, or any portion of any of the foregoing, infringe any intellectual property or other right owned or licensable by You, then all licenses granted to You under this Agreement shall terminate as of the date such lawsuit or other proceeding is filed. You will defend, indemnify and hold harmless Us from and against any claim by any Third Party arising out of or related to Your or the Third Party’s use or distribution of the Tencent Hunyuan Works.
|
||||
d. Tencent claims no rights in Outputs You generate. You and Your users are solely responsible for Outputs and their subsequent uses.
|
||||
7. DISCLAIMERS OF WARRANTY AND LIMITATIONS OF LIABILITY.
|
||||
a. We are not obligated to support, update, provide training for, or develop any further version of the Tencent Hunyuan Works or to grant any license thereto.
|
||||
b. UNLESS AND ONLY TO THE EXTENT REQUIRED BY APPLICABLE LAW, THE TENCENT HUNYUAN WORKS AND ANY OUTPUT AND RESULTS THEREFROM ARE PROVIDED “AS IS” WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND INCLUDING ANY WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, COURSE OF DEALING, USAGE OF TRADE, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING, REPRODUCING, MODIFYING, PERFORMING, DISPLAYING OR DISTRIBUTING ANY OF THE TENCENT HUNYUAN WORKS OR OUTPUTS AND ASSUME ANY AND ALL RISKS ASSOCIATED WITH YOUR OR A THIRD PARTY’S USE OR DISTRIBUTION OF ANY OF THE TENCENT HUNYUAN WORKS OR OUTPUTS AND YOUR EXERCISE OF RIGHTS AND PERMISSIONS UNDER THIS AGREEMENT.
|
||||
c. TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL TENCENT OR ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, FOR ANY DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY, CONSEQUENTIAL OR PUNITIVE DAMAGES, OR LOST PROFITS OF ANY KIND ARISING FROM THIS AGREEMENT OR RELATED TO ANY OF THE TENCENT HUNYUAN WORKS OR OUTPUTS, EVEN IF TENCENT OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF ANY OF THE FOREGOING.
|
||||
8. SURVIVAL AND TERMINATION.
|
||||
a. The term of this Agreement shall commence upon Your acceptance of this Agreement or access to the Materials and will continue in full force and effect until terminated in accordance with the terms and conditions herein.
|
||||
b. We may terminate this Agreement if You breach any of the terms or conditions of this Agreement. Upon termination of this Agreement, You must promptly delete and cease use of the Tencent Hunyuan Works. Sections 6(a), 6(c), 7 and 9 shall survive the termination of this Agreement.
|
||||
9. GOVERNING LAW AND JURISDICTION.
|
||||
a. This Agreement and any dispute arising out of or relating to it will be governed by the laws of the Hong Kong Special Administrative Region of the People’s Republic of China, without regard to conflict of law principles, and the UN Convention on Contracts for the International Sale of Goods does not apply to this Agreement.
|
||||
b. Exclusive jurisdiction and venue for any dispute arising out of or relating to this Agreement will be a court of competent jurisdiction in the Hong Kong Special Administrative Region of the People’s Republic of China, and Tencent and Licensee consent to the exclusive jurisdiction of such court with respect to any such dispute.
|
||||
|
||||
|
||||
EXHIBIT A
|
||||
ACCEPTABLE USE POLICY
|
||||
|
||||
Tencent reserves the right to update this Acceptable Use Policy from time to time.
|
||||
Last modified: 2024/5/14
|
||||
|
||||
Tencent endeavors to promote safe and fair use of its tools and features, including Tencent Hunyuan. You agree not to use Tencent Hunyuan or Model Derivatives:
|
||||
1. In any way that violates any applicable national, federal, state, local, international or any other law or regulation;
|
||||
2. To harm Yourself or others;
|
||||
3. To repurpose or distribute output from Tencent Hunyuan or any Model Derivatives to harm Yourself or others;
|
||||
4. To override or circumvent the safety guardrails and safeguards We have put in place;
|
||||
5. For the purpose of exploiting, harming or attempting to exploit or harm minors in any way;
|
||||
6. To generate or disseminate verifiably false information and/or content with the purpose of harming others or influencing elections;
|
||||
7. To generate or facilitate false online engagement, including fake reviews and other means of fake online engagement;
|
||||
8. To intentionally defame, disparage or otherwise harass others;
|
||||
9. To generate and/or disseminate malware (including ransomware) or any other content to be used for the purpose of harming electronic systems;
|
||||
10. To generate or disseminate personal identifiable information with the purpose of harming others;
|
||||
11. To generate or disseminate information (including images, code, posts, articles), and place the information in any public context (including –through the use of bot generated tweets), without expressly and conspicuously identifying that the information and/or content is machine generated;
|
||||
12. To impersonate another individual without consent, authorization, or legal right;
|
||||
13. To make high-stakes automated decisions in domains that affect an individual’s safety, rights or wellbeing (e.g., law enforcement, migration, medicine/health, management of critical infrastructure, safety components of products, essential services, credit, employment, housing, education, social scoring, or insurance);
|
||||
14. In a manner that violates or disrespects the social ethics and moral standards of other countries or regions;
|
||||
15. To perform, facilitate, threaten, incite, plan, promote or encourage violent extremism or terrorism;
|
||||
16. For any use intended to discriminate against or harm individuals or groups based on protected characteristics or categories, online or offline social behavior or known or predicted personal or personality characteristics;
|
||||
17. To intentionally exploit any of the vulnerabilities of a specific group of persons based on their age, social, physical or mental characteristics, in order to materially distort the behavior of a person pertaining to that group in a manner that causes or is likely to cause that person or another person physical or psychological harm;
|
||||
18. For military purposes;
|
||||
19. To engage in the unauthorized or unlicensed practice of any profession including, but not limited to, financial, legal, medical/health, or other professional practices.
|
||||
|
||||
For the license of other third party components, please refer to the following URL:
|
||||
https://huggingface.co/Tencent-Hunyuan/HunyuanDiT/blob/main/Notice
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
This Model also incorporates insights from Flux's neural network architechtures (https://github.com/black-forest-labs/flux?tab=readme-ov-file). Credits are given to the orginal authors.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
|
||||
TARGET_DIR = "Checkpoints/Diffusers/tencent/Hunyuan3D-2"
|
||||
OLD_IMPORT = "hy3dgen"
|
||||
NEW_IMPORT = "Hunyuan3D_V2.hy3dgen"
|
||||
|
||||
def patch_yaml_imports(root_dir):
|
||||
for subdir, _, files in os.walk(root_dir):
|
||||
for file in files:
|
||||
if file.endswith(".yaml") or file.endswith(".yml"):
|
||||
file_path = os.path.join(subdir, file)
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
if OLD_IMPORT in content:
|
||||
new_content = content.replace(f"{OLD_IMPORT}.", f"{NEW_IMPORT}.")
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
f.write(new_content)
|
||||
print(f"✔ Updated: {file_path}")
|
||||
else:
|
||||
print(f"– Skipped (no match): {file_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
patch_yaml_imports(TARGET_DIR)
|
||||
@@ -1,13 +1,3 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
@@ -20,4 +10,4 @@
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
@@ -1,13 +1,3 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
@@ -22,7 +12,6 @@
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
|
||||
from PIL import Image
|
||||
from rembg import remove, new_session
|
||||
|
||||
|
||||
Regular → Executable
+1
-11
@@ -1,13 +1,3 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
@@ -23,5 +13,5 @@
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
from .pipelines import Hunyuan3DDiTPipeline, Hunyuan3DDiTFlowMatchingPipeline
|
||||
from .postprocessors import FaceReducer, FloaterRemover, DegenerateFaceRemover
|
||||
from .postprocessors import FaceReducer, FloaterRemover, DegenerateFaceRemover, MeshSimplifier
|
||||
from .preprocessors import ImageProcessorV2, IMAGE_PROCESSORS, DEFAULT_IMAGEPROCESSOR
|
||||
|
||||
Regular → Executable
+2
-2
@@ -23,6 +23,6 @@
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
|
||||
from .autoencoders import ShapeVAE
|
||||
from .conditioner import DualImageEncoder, SingleImageEncoder, DinoImageEncoder, CLIPImageEncoder
|
||||
from .hunyuan3ddit import Hunyuan3DDiT
|
||||
from .vae import ShapeVAE
|
||||
from .denoisers import Hunyuan3DDiT
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
from .attention_blocks import CrossAttentionDecoder
|
||||
from .attention_processors import FlashVDMCrossAttentionProcessor, CrossAttentionProcessor, \
|
||||
FlashVDMTopMCrossAttentionProcessor
|
||||
from .model import ShapeVAE, VectsetVAE
|
||||
from .surface_extractors import SurfaceExtractors, MCSurfaceExtractor, DMCSurfaceExtractor, Latent2MeshOutput
|
||||
from .volume_decoders import HierarchicalVolumeDecoding, FlashVDMVolumeDecoding, VanillaVolumeDecoder
|
||||
+65
-208
@@ -1,13 +1,3 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
@@ -22,15 +12,25 @@
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
from typing import Tuple, List, Union, Optional
|
||||
|
||||
import numpy as np
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
from einops import rearrange, repeat
|
||||
from skimage import measure
|
||||
from tqdm import tqdm
|
||||
from einops import rearrange
|
||||
|
||||
from .attention_processors import CrossAttentionProcessor
|
||||
from ...utils import logger
|
||||
|
||||
scaled_dot_product_attention = nn.functional.scaled_dot_product_attention
|
||||
|
||||
if os.environ.get('USE_SAGEATTN', '0') == '1':
|
||||
try:
|
||||
from sageattention import sageattn
|
||||
except ImportError:
|
||||
raise ImportError('Please install the package "sageattention" to use this USE_SAGEATTN.')
|
||||
scaled_dot_product_attention = sageattn
|
||||
|
||||
|
||||
class FourierEmbedder(nn.Module):
|
||||
@@ -166,13 +166,14 @@ class MLP(nn.Module):
|
||||
def __init__(
|
||||
self, *,
|
||||
width: int,
|
||||
expand_ratio: int = 4,
|
||||
output_width: int = None,
|
||||
drop_path_rate: float = 0.0
|
||||
):
|
||||
super().__init__()
|
||||
self.width = width
|
||||
self.c_fc = nn.Linear(width, width * 4)
|
||||
self.c_proj = nn.Linear(width * 4, output_width if output_width is not None else width)
|
||||
self.c_fc = nn.Linear(width, width * expand_ratio)
|
||||
self.c_proj = nn.Linear(width * expand_ratio, output_width if output_width is not None else width)
|
||||
self.gelu = nn.GELU()
|
||||
self.drop_path = DropPath(drop_path_rate) if drop_path_rate > 0. else nn.Identity()
|
||||
|
||||
@@ -196,6 +197,8 @@ class QKVMultiheadCrossAttention(nn.Module):
|
||||
self.q_norm = norm_layer(width // heads, elementwise_affine=True, eps=1e-6) if qk_norm else nn.Identity()
|
||||
self.k_norm = norm_layer(width // heads, elementwise_affine=True, eps=1e-6) if qk_norm else nn.Identity()
|
||||
|
||||
self.attn_processor = CrossAttentionProcessor()
|
||||
|
||||
def forward(self, q, kv):
|
||||
_, n_ctx, _ = q.shape
|
||||
bs, n_data, width = kv.shape
|
||||
@@ -206,10 +209,9 @@ class QKVMultiheadCrossAttention(nn.Module):
|
||||
|
||||
q = self.q_norm(q)
|
||||
k = self.k_norm(k)
|
||||
|
||||
q, k, v = map(lambda t: rearrange(t, 'b n h d -> b h n d', h=self.heads), (q, k, v))
|
||||
out = F.scaled_dot_product_attention(q, k, v).transpose(1, 2).reshape(bs, n_ctx, -1)
|
||||
|
||||
out = self.attn_processor(self, q, k, v)
|
||||
out = out.transpose(1, 2).reshape(bs, n_ctx, -1)
|
||||
return out
|
||||
|
||||
|
||||
@@ -223,7 +225,8 @@ class MultiheadCrossAttention(nn.Module):
|
||||
n_data: Optional[int] = None,
|
||||
data_width: Optional[int] = None,
|
||||
norm_layer=nn.LayerNorm,
|
||||
qk_norm: bool = False
|
||||
qk_norm: bool = False,
|
||||
kv_cache: bool = False,
|
||||
):
|
||||
super().__init__()
|
||||
self.n_data = n_data
|
||||
@@ -240,10 +243,18 @@ class MultiheadCrossAttention(nn.Module):
|
||||
norm_layer=norm_layer,
|
||||
qk_norm=qk_norm
|
||||
)
|
||||
self.kv_cache = kv_cache
|
||||
self.data = None
|
||||
|
||||
def forward(self, x, data):
|
||||
x = self.c_q(x)
|
||||
data = self.c_kv(data)
|
||||
if self.kv_cache:
|
||||
if self.data is None:
|
||||
self.data = self.c_kv(data)
|
||||
logger.info('Save kv cache,this should be called only once for one mesh')
|
||||
data = self.data
|
||||
else:
|
||||
data = self.c_kv(data)
|
||||
x = self.attention(x, data)
|
||||
x = self.c_proj(x)
|
||||
return x
|
||||
@@ -256,6 +267,7 @@ class ResidualCrossAttentionBlock(nn.Module):
|
||||
n_data: Optional[int] = None,
|
||||
width: int,
|
||||
heads: int,
|
||||
mlp_expand_ratio: int = 4,
|
||||
data_width: Optional[int] = None,
|
||||
qkv_bias: bool = True,
|
||||
norm_layer=nn.LayerNorm,
|
||||
@@ -278,7 +290,7 @@ class ResidualCrossAttentionBlock(nn.Module):
|
||||
self.ln_1 = norm_layer(width, elementwise_affine=True, eps=1e-6)
|
||||
self.ln_2 = norm_layer(data_width, elementwise_affine=True, eps=1e-6)
|
||||
self.ln_3 = norm_layer(width, elementwise_affine=True, eps=1e-6)
|
||||
self.mlp = MLP(width=width)
|
||||
self.mlp = MLP(width=width, expand_ratio=mlp_expand_ratio)
|
||||
|
||||
def forward(self, x: torch.Tensor, data: torch.Tensor):
|
||||
x = x + self.attn(self.ln_1(x), self.ln_2(data))
|
||||
@@ -312,7 +324,7 @@ class QKVMultiheadAttention(nn.Module):
|
||||
k = self.k_norm(k)
|
||||
|
||||
q, k, v = map(lambda t: rearrange(t, 'b n h d -> b h n d', h=self.heads), (q, k, v))
|
||||
out = F.scaled_dot_product_attention(q, k, v).transpose(1, 2).reshape(bs, n_ctx, -1)
|
||||
out = scaled_dot_product_attention(q, k, v).transpose(1, 2).reshape(bs, n_ctx, -1)
|
||||
return out
|
||||
|
||||
|
||||
@@ -430,207 +442,52 @@ class CrossAttentionDecoder(nn.Module):
|
||||
fourier_embedder: FourierEmbedder,
|
||||
width: int,
|
||||
heads: int,
|
||||
mlp_expand_ratio: int = 4,
|
||||
downsample_ratio: int = 1,
|
||||
enable_ln_post: bool = True,
|
||||
qkv_bias: bool = True,
|
||||
qk_norm: bool = False,
|
||||
label_type: str = "binary"
|
||||
):
|
||||
super().__init__()
|
||||
|
||||
self.enable_ln_post = enable_ln_post
|
||||
self.fourier_embedder = fourier_embedder
|
||||
|
||||
self.downsample_ratio = downsample_ratio
|
||||
self.query_proj = nn.Linear(self.fourier_embedder.out_dim, width)
|
||||
|
||||
if self.downsample_ratio != 1:
|
||||
self.latents_proj = nn.Linear(width * downsample_ratio, width)
|
||||
if self.enable_ln_post == False:
|
||||
qk_norm = False
|
||||
self.cross_attn_decoder = ResidualCrossAttentionBlock(
|
||||
n_data=num_latents,
|
||||
width=width,
|
||||
mlp_expand_ratio=mlp_expand_ratio,
|
||||
heads=heads,
|
||||
qkv_bias=qkv_bias,
|
||||
qk_norm=qk_norm
|
||||
)
|
||||
|
||||
self.ln_post = nn.LayerNorm(width)
|
||||
if self.enable_ln_post:
|
||||
self.ln_post = nn.LayerNorm(width)
|
||||
self.output_proj = nn.Linear(width, out_channels)
|
||||
self.label_type = label_type
|
||||
self.count = 0
|
||||
|
||||
def forward(self, queries: torch.FloatTensor, latents: torch.FloatTensor):
|
||||
queries = self.query_proj(self.fourier_embedder(queries).to(latents.dtype))
|
||||
x = self.cross_attn_decoder(queries, latents)
|
||||
x = self.ln_post(x)
|
||||
def set_cross_attention_processor(self, processor):
|
||||
self.cross_attn_decoder.attn.attention.attn_processor = processor
|
||||
|
||||
def set_default_cross_attention_processor(self):
|
||||
self.cross_attn_decoder.attn.attention.attn_processor = CrossAttentionProcessor
|
||||
|
||||
def forward(self, queries=None, query_embeddings=None, latents=None):
|
||||
if query_embeddings is None:
|
||||
query_embeddings = self.query_proj(self.fourier_embedder(queries).to(latents.dtype))
|
||||
self.count += query_embeddings.shape[1]
|
||||
if self.downsample_ratio != 1:
|
||||
latents = self.latents_proj(latents)
|
||||
x = self.cross_attn_decoder(query_embeddings, latents)
|
||||
if self.enable_ln_post:
|
||||
x = self.ln_post(x)
|
||||
occ = self.output_proj(x)
|
||||
return occ
|
||||
|
||||
|
||||
def generate_dense_grid_points(bbox_min: np.ndarray,
|
||||
bbox_max: np.ndarray,
|
||||
octree_depth: int,
|
||||
indexing: str = "ij",
|
||||
octree_resolution: int = None,
|
||||
):
|
||||
length = bbox_max - bbox_min
|
||||
num_cells = np.exp2(octree_depth)
|
||||
if octree_resolution is not None:
|
||||
num_cells = octree_resolution
|
||||
|
||||
x = np.linspace(bbox_min[0], bbox_max[0], int(num_cells) + 1, dtype=np.float32)
|
||||
y = np.linspace(bbox_min[1], bbox_max[1], int(num_cells) + 1, dtype=np.float32)
|
||||
z = np.linspace(bbox_min[2], bbox_max[2], int(num_cells) + 1, dtype=np.float32)
|
||||
[xs, ys, zs] = np.meshgrid(x, y, z, indexing=indexing)
|
||||
xyz = np.stack((xs, ys, zs), axis=-1)
|
||||
xyz = xyz.reshape(-1, 3)
|
||||
grid_size = [int(num_cells) + 1, int(num_cells) + 1, int(num_cells) + 1]
|
||||
|
||||
return xyz, grid_size, length
|
||||
|
||||
|
||||
def center_vertices(vertices):
|
||||
"""Translate the vertices so that bounding box is centered at zero."""
|
||||
vert_min = vertices.min(dim=0)[0]
|
||||
vert_max = vertices.max(dim=0)[0]
|
||||
vert_center = 0.5 * (vert_min + vert_max)
|
||||
return vertices - vert_center
|
||||
|
||||
|
||||
class Latent2MeshOutput:
|
||||
|
||||
def __init__(self, mesh_v=None, mesh_f=None):
|
||||
self.mesh_v = mesh_v
|
||||
self.mesh_f = mesh_f
|
||||
|
||||
|
||||
class ShapeVAE(nn.Module):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
num_latents: int,
|
||||
embed_dim: int,
|
||||
width: int,
|
||||
heads: int,
|
||||
num_decoder_layers: int,
|
||||
num_freqs: int = 8,
|
||||
include_pi: bool = True,
|
||||
qkv_bias: bool = True,
|
||||
qk_norm: bool = False,
|
||||
label_type: str = "binary",
|
||||
drop_path_rate: float = 0.0,
|
||||
scale_factor: float = 1.0,
|
||||
):
|
||||
super().__init__()
|
||||
self.fourier_embedder = FourierEmbedder(num_freqs=num_freqs, include_pi=include_pi)
|
||||
|
||||
self.post_kl = nn.Linear(embed_dim, width)
|
||||
|
||||
self.transformer = Transformer(
|
||||
n_ctx=num_latents,
|
||||
width=width,
|
||||
layers=num_decoder_layers,
|
||||
heads=heads,
|
||||
qkv_bias=qkv_bias,
|
||||
qk_norm=qk_norm,
|
||||
drop_path_rate=drop_path_rate
|
||||
)
|
||||
|
||||
self.geo_decoder = CrossAttentionDecoder(
|
||||
fourier_embedder=self.fourier_embedder,
|
||||
out_channels=1,
|
||||
num_latents=num_latents,
|
||||
width=width,
|
||||
heads=heads,
|
||||
qkv_bias=qkv_bias,
|
||||
qk_norm=qk_norm,
|
||||
label_type=label_type,
|
||||
)
|
||||
|
||||
self.scale_factor = scale_factor
|
||||
self.latent_shape = (num_latents, embed_dim)
|
||||
|
||||
def forward(self, latents):
|
||||
latents = self.post_kl(latents)
|
||||
latents = self.transformer(latents)
|
||||
return latents
|
||||
|
||||
@torch.no_grad()
|
||||
def latents2mesh(
|
||||
self,
|
||||
latents: torch.FloatTensor,
|
||||
bounds: Union[Tuple[float], List[float], float] = 1.1,
|
||||
octree_depth: int = 7,
|
||||
num_chunks: int = 10000,
|
||||
mc_level: float = -1 / 512,
|
||||
octree_resolution: int = None,
|
||||
mc_algo: str = 'dmc',
|
||||
):
|
||||
device = latents.device
|
||||
|
||||
# 1. generate query points
|
||||
if isinstance(bounds, float):
|
||||
bounds = [-bounds, -bounds, -bounds, bounds, bounds, bounds]
|
||||
bbox_min = np.array(bounds[0:3])
|
||||
bbox_max = np.array(bounds[3:6])
|
||||
bbox_size = bbox_max - bbox_min
|
||||
xyz_samples, grid_size, length = generate_dense_grid_points(
|
||||
bbox_min=bbox_min,
|
||||
bbox_max=bbox_max,
|
||||
octree_depth=octree_depth,
|
||||
octree_resolution=octree_resolution,
|
||||
indexing="ij"
|
||||
)
|
||||
xyz_samples = torch.FloatTensor(xyz_samples)
|
||||
|
||||
# 2. latents to 3d volume
|
||||
batch_logits = []
|
||||
batch_size = latents.shape[0]
|
||||
for start in tqdm(range(0, xyz_samples.shape[0], num_chunks),
|
||||
desc=f"MC Level {mc_level} Implicit Function:"):
|
||||
queries = xyz_samples[start: start + num_chunks, :].to(device)
|
||||
queries = queries.half()
|
||||
batch_queries = repeat(queries, "p c -> b p c", b=batch_size)
|
||||
|
||||
logits = self.geo_decoder(batch_queries.to(latents.dtype), latents)
|
||||
if mc_level == -1:
|
||||
mc_level = 0
|
||||
logits = torch.sigmoid(logits) * 2 - 1
|
||||
print(f'Training with soft labels, inference with sigmoid and marching cubes level 0.')
|
||||
batch_logits.append(logits)
|
||||
grid_logits = torch.cat(batch_logits, dim=1)
|
||||
grid_logits = grid_logits.view((batch_size, grid_size[0], grid_size[1], grid_size[2])).float()
|
||||
|
||||
# 3. extract surface
|
||||
outputs = []
|
||||
for i in range(batch_size):
|
||||
try:
|
||||
if mc_algo == 'mc':
|
||||
vertices, faces, normals, _ = measure.marching_cubes(
|
||||
grid_logits[i].cpu().numpy(),
|
||||
mc_level,
|
||||
method="lewiner"
|
||||
)
|
||||
vertices = vertices / grid_size * bbox_size + bbox_min
|
||||
elif mc_algo == 'dmc':
|
||||
if not hasattr(self, 'dmc'):
|
||||
try:
|
||||
from diso import DiffDMC
|
||||
except:
|
||||
raise ImportError("Please install diso via `pip install diso`, or set mc_algo to 'mc'")
|
||||
self.dmc = DiffDMC(dtype=torch.float32).to(device)
|
||||
octree_resolution = 2 ** octree_depth if octree_resolution is None else octree_resolution
|
||||
sdf = -grid_logits[i] / octree_resolution
|
||||
verts, faces = self.dmc(sdf, deform=None, return_quads=False, normalize=True)
|
||||
verts = center_vertices(verts)
|
||||
vertices = verts.detach().cpu().numpy()
|
||||
faces = faces.detach().cpu().numpy()[:, ::-1]
|
||||
else:
|
||||
raise ValueError(f"mc_algo {mc_algo} not supported.")
|
||||
|
||||
outputs.append(
|
||||
Latent2MeshOutput(
|
||||
mesh_v=vertices.astype(np.float32),
|
||||
mesh_f=np.ascontiguousarray(faces)
|
||||
)
|
||||
)
|
||||
|
||||
except ValueError:
|
||||
outputs.append(None)
|
||||
except RuntimeError:
|
||||
outputs.append(None)
|
||||
|
||||
return outputs
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import os
|
||||
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
|
||||
scaled_dot_product_attention = F.scaled_dot_product_attention
|
||||
if os.environ.get('CA_USE_SAGEATTN', '0') == '1':
|
||||
try:
|
||||
from sageattention import sageattn
|
||||
except ImportError:
|
||||
raise ImportError('Please install the package "sageattention" to use this USE_SAGEATTN.')
|
||||
scaled_dot_product_attention = sageattn
|
||||
|
||||
|
||||
class CrossAttentionProcessor:
|
||||
def __call__(self, attn, q, k, v):
|
||||
out = scaled_dot_product_attention(q, k, v)
|
||||
return out
|
||||
|
||||
|
||||
class FlashVDMCrossAttentionProcessor:
|
||||
def __init__(self, topk=None):
|
||||
self.topk = topk
|
||||
|
||||
def __call__(self, attn, q, k, v):
|
||||
if k.shape[-2] == 3072:
|
||||
topk = 1024
|
||||
elif k.shape[-2] == 512:
|
||||
topk = 256
|
||||
else:
|
||||
topk = k.shape[-2] // 3
|
||||
|
||||
if self.topk is True:
|
||||
q1 = q[:, :, ::100, :]
|
||||
sim = q1 @ k.transpose(-1, -2)
|
||||
sim = torch.mean(sim, -2)
|
||||
topk_ind = torch.topk(sim, dim=-1, k=topk).indices.squeeze(-2).unsqueeze(-1)
|
||||
topk_ind = topk_ind.expand(-1, -1, -1, v.shape[-1])
|
||||
v0 = torch.gather(v, dim=-2, index=topk_ind)
|
||||
k0 = torch.gather(k, dim=-2, index=topk_ind)
|
||||
out = scaled_dot_product_attention(q, k0, v0)
|
||||
elif self.topk is False:
|
||||
out = scaled_dot_product_attention(q, k, v)
|
||||
else:
|
||||
idx, counts = self.topk
|
||||
start = 0
|
||||
outs = []
|
||||
for grid_coord, count in zip(idx, counts):
|
||||
end = start + count
|
||||
q_chunk = q[:, :, start:end, :]
|
||||
k0, v0 = self.select_topkv(q_chunk, k, v, topk)
|
||||
out = scaled_dot_product_attention(q_chunk, k0, v0)
|
||||
outs.append(out)
|
||||
start += count
|
||||
out = torch.cat(outs, dim=-2)
|
||||
self.topk = False
|
||||
return out
|
||||
|
||||
def select_topkv(self, q_chunk, k, v, topk):
|
||||
q1 = q_chunk[:, :, ::50, :]
|
||||
sim = q1 @ k.transpose(-1, -2)
|
||||
sim = torch.mean(sim, -2)
|
||||
topk_ind = torch.topk(sim, dim=-1, k=topk).indices.squeeze(-2).unsqueeze(-1)
|
||||
topk_ind = topk_ind.expand(-1, -1, -1, v.shape[-1])
|
||||
v0 = torch.gather(v, dim=-2, index=topk_ind)
|
||||
k0 = torch.gather(k, dim=-2, index=topk_ind)
|
||||
return k0, v0
|
||||
|
||||
|
||||
class FlashVDMTopMCrossAttentionProcessor(FlashVDMCrossAttentionProcessor):
|
||||
def select_topkv(self, q_chunk, k, v, topk):
|
||||
q1 = q_chunk[:, :, ::30, :]
|
||||
sim = q1 @ k.transpose(-1, -2)
|
||||
# sim = sim.to(torch.float32)
|
||||
sim = sim.softmax(-1)
|
||||
sim = torch.mean(sim, 1)
|
||||
activated_token = torch.where(sim > 1e-6)[2]
|
||||
index = torch.unique(activated_token, return_counts=True)[0].unsqueeze(0).unsqueeze(0).unsqueeze(-1)
|
||||
index = index.expand(-1, v.shape[1], -1, v.shape[-1])
|
||||
v0 = torch.gather(v, dim=-2, index=index)
|
||||
k0 = torch.gather(k, dim=-2, index=index)
|
||||
return k0, v0
|
||||
@@ -0,0 +1,189 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import os
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import yaml
|
||||
|
||||
from .attention_blocks import FourierEmbedder, Transformer, CrossAttentionDecoder
|
||||
from .surface_extractors import MCSurfaceExtractor, SurfaceExtractors
|
||||
from .volume_decoders import VanillaVolumeDecoder, FlashVDMVolumeDecoding, HierarchicalVolumeDecoding
|
||||
from ...utils import logger, synchronize_timer, smart_load_model
|
||||
|
||||
|
||||
class VectsetVAE(nn.Module):
|
||||
|
||||
@classmethod
|
||||
@synchronize_timer('VectsetVAE Model Loading')
|
||||
def from_single_file(
|
||||
cls,
|
||||
ckpt_path,
|
||||
config_path,
|
||||
device='cuda',
|
||||
dtype=torch.float16,
|
||||
use_safetensors=None,
|
||||
**kwargs,
|
||||
):
|
||||
# load config
|
||||
with open(config_path, 'r') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
# load ckpt
|
||||
if use_safetensors:
|
||||
ckpt_path = ckpt_path.replace('.ckpt', '.safetensors')
|
||||
if not os.path.exists(ckpt_path):
|
||||
raise FileNotFoundError(f"Model file {ckpt_path} not found")
|
||||
|
||||
logger.info(f"Loading model from {ckpt_path}")
|
||||
if use_safetensors:
|
||||
import safetensors.torch
|
||||
ckpt = safetensors.torch.load_file(ckpt_path, device='cpu')
|
||||
else:
|
||||
ckpt = torch.load(ckpt_path, map_location='cpu', weights_only=True)
|
||||
|
||||
model_kwargs = config['params']
|
||||
model_kwargs.update(kwargs)
|
||||
|
||||
model = cls(**model_kwargs)
|
||||
model.load_state_dict(ckpt)
|
||||
model.to(device=device, dtype=dtype)
|
||||
return model
|
||||
|
||||
@classmethod
|
||||
def from_pretrained(
|
||||
cls,
|
||||
model_path,
|
||||
device='cuda',
|
||||
dtype=torch.float16,
|
||||
use_safetensors=True,
|
||||
variant='fp16',
|
||||
subfolder='hunyuan3d-vae-v2-0',
|
||||
**kwargs,
|
||||
):
|
||||
config_path, ckpt_path = smart_load_model(
|
||||
model_path,
|
||||
subfolder=subfolder,
|
||||
use_safetensors=use_safetensors,
|
||||
variant=variant
|
||||
)
|
||||
|
||||
return cls.from_single_file(
|
||||
ckpt_path,
|
||||
config_path,
|
||||
device=device,
|
||||
dtype=dtype,
|
||||
use_safetensors=use_safetensors,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
volume_decoder=None,
|
||||
surface_extractor=None
|
||||
):
|
||||
super().__init__()
|
||||
if volume_decoder is None:
|
||||
volume_decoder = VanillaVolumeDecoder()
|
||||
if surface_extractor is None:
|
||||
surface_extractor = MCSurfaceExtractor()
|
||||
self.volume_decoder = volume_decoder
|
||||
self.surface_extractor = surface_extractor
|
||||
|
||||
def latents2mesh(self, latents: torch.FloatTensor, **kwargs):
|
||||
with synchronize_timer('Volume decoding'):
|
||||
grid_logits = self.volume_decoder(latents, self.geo_decoder, **kwargs)
|
||||
with synchronize_timer('Surface extraction'):
|
||||
outputs = self.surface_extractor(grid_logits, **kwargs)
|
||||
return outputs
|
||||
|
||||
def enable_flashvdm_decoder(
|
||||
self,
|
||||
enabled: bool = True,
|
||||
adaptive_kv_selection=True,
|
||||
topk_mode='mean',
|
||||
mc_algo='dmc',
|
||||
):
|
||||
if enabled:
|
||||
if adaptive_kv_selection:
|
||||
self.volume_decoder = FlashVDMVolumeDecoding(topk_mode)
|
||||
else:
|
||||
self.volume_decoder = HierarchicalVolumeDecoding()
|
||||
if mc_algo not in SurfaceExtractors.keys():
|
||||
raise ValueError(f'Unsupported mc_algo {mc_algo}, available: {list(SurfaceExtractors.keys())}')
|
||||
self.surface_extractor = SurfaceExtractors[mc_algo]()
|
||||
else:
|
||||
self.volume_decoder = VanillaVolumeDecoder()
|
||||
self.surface_extractor = MCSurfaceExtractor()
|
||||
|
||||
|
||||
class ShapeVAE(VectsetVAE):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
num_latents: int,
|
||||
embed_dim: int,
|
||||
width: int,
|
||||
heads: int,
|
||||
num_decoder_layers: int,
|
||||
geo_decoder_downsample_ratio: int = 1,
|
||||
geo_decoder_mlp_expand_ratio: int = 4,
|
||||
geo_decoder_ln_post: bool = True,
|
||||
num_freqs: int = 8,
|
||||
include_pi: bool = True,
|
||||
qkv_bias: bool = True,
|
||||
qk_norm: bool = False,
|
||||
label_type: str = "binary",
|
||||
drop_path_rate: float = 0.0,
|
||||
scale_factor: float = 1.0,
|
||||
):
|
||||
super().__init__()
|
||||
self.geo_decoder_ln_post = geo_decoder_ln_post
|
||||
|
||||
self.fourier_embedder = FourierEmbedder(num_freqs=num_freqs, include_pi=include_pi)
|
||||
|
||||
self.post_kl = nn.Linear(embed_dim, width)
|
||||
|
||||
self.transformer = Transformer(
|
||||
n_ctx=num_latents,
|
||||
width=width,
|
||||
layers=num_decoder_layers,
|
||||
heads=heads,
|
||||
qkv_bias=qkv_bias,
|
||||
qk_norm=qk_norm,
|
||||
drop_path_rate=drop_path_rate
|
||||
)
|
||||
|
||||
self.geo_decoder = CrossAttentionDecoder(
|
||||
fourier_embedder=self.fourier_embedder,
|
||||
out_channels=1,
|
||||
num_latents=num_latents,
|
||||
mlp_expand_ratio=geo_decoder_mlp_expand_ratio,
|
||||
downsample_ratio=geo_decoder_downsample_ratio,
|
||||
enable_ln_post=self.geo_decoder_ln_post,
|
||||
width=width // geo_decoder_downsample_ratio,
|
||||
heads=heads // geo_decoder_downsample_ratio,
|
||||
qkv_bias=qkv_bias,
|
||||
qk_norm=qk_norm,
|
||||
label_type=label_type,
|
||||
)
|
||||
|
||||
self.scale_factor = scale_factor
|
||||
self.latent_shape = (num_latents, embed_dim)
|
||||
|
||||
def forward(self, latents):
|
||||
latents = self.post_kl(latents)
|
||||
latents = self.transformer(latents)
|
||||
return latents
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
from typing import Union, Tuple, List
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
from skimage import measure
|
||||
|
||||
|
||||
class Latent2MeshOutput:
|
||||
|
||||
def __init__(self, mesh_v=None, mesh_f=None):
|
||||
self.mesh_v = mesh_v
|
||||
self.mesh_f = mesh_f
|
||||
|
||||
|
||||
def center_vertices(vertices):
|
||||
"""Translate the vertices so that bounding box is centered at zero."""
|
||||
vert_min = vertices.min(dim=0)[0]
|
||||
vert_max = vertices.max(dim=0)[0]
|
||||
vert_center = 0.5 * (vert_min + vert_max)
|
||||
return vertices - vert_center
|
||||
|
||||
|
||||
class SurfaceExtractor:
|
||||
def _compute_box_stat(self, bounds: Union[Tuple[float], List[float], float], octree_resolution: int):
|
||||
if isinstance(bounds, float):
|
||||
bounds = [-bounds, -bounds, -bounds, bounds, bounds, bounds]
|
||||
|
||||
bbox_min, bbox_max = np.array(bounds[0:3]), np.array(bounds[3:6])
|
||||
bbox_size = bbox_max - bbox_min
|
||||
grid_size = [int(octree_resolution) + 1, int(octree_resolution) + 1, int(octree_resolution) + 1]
|
||||
return grid_size, bbox_min, bbox_size
|
||||
|
||||
def run(self, *args, **kwargs):
|
||||
return NotImplementedError
|
||||
|
||||
def __call__(self, grid_logits, **kwargs):
|
||||
outputs = []
|
||||
for i in range(grid_logits.shape[0]):
|
||||
try:
|
||||
vertices, faces = self.run(grid_logits[i], **kwargs)
|
||||
vertices = vertices.astype(np.float32)
|
||||
faces = np.ascontiguousarray(faces)
|
||||
outputs.append(Latent2MeshOutput(mesh_v=vertices, mesh_f=faces))
|
||||
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
outputs.append(None)
|
||||
|
||||
return outputs
|
||||
|
||||
|
||||
class MCSurfaceExtractor(SurfaceExtractor):
|
||||
def run(self, grid_logit, *, mc_level, bounds, octree_resolution, **kwargs):
|
||||
vertices, faces, normals, _ = measure.marching_cubes(
|
||||
grid_logit.cpu().numpy(),
|
||||
mc_level,
|
||||
method="lewiner"
|
||||
)
|
||||
grid_size, bbox_min, bbox_size = self._compute_box_stat(bounds, octree_resolution)
|
||||
vertices = vertices / grid_size * bbox_size + bbox_min
|
||||
return vertices, faces
|
||||
|
||||
|
||||
class DMCSurfaceExtractor(SurfaceExtractor):
|
||||
def run(self, grid_logit, *, octree_resolution, **kwargs):
|
||||
device = grid_logit.device
|
||||
if not hasattr(self, 'dmc'):
|
||||
try:
|
||||
from diso import DiffDMC
|
||||
except:
|
||||
raise ImportError("Please install diso via `pip install diso`, or set mc_algo to 'mc'")
|
||||
self.dmc = DiffDMC(dtype=torch.float32).to(device)
|
||||
sdf = -grid_logit / octree_resolution
|
||||
sdf = sdf.to(torch.float32).contiguous()
|
||||
verts, faces = self.dmc(sdf, deform=None, return_quads=False, normalize=True)
|
||||
verts = center_vertices(verts)
|
||||
vertices = verts.detach().cpu().numpy()
|
||||
faces = faces.detach().cpu().numpy()[:, ::-1]
|
||||
return vertices, faces
|
||||
|
||||
|
||||
SurfaceExtractors = {
|
||||
'mc': MCSurfaceExtractor,
|
||||
'dmc': DMCSurfaceExtractor,
|
||||
}
|
||||
@@ -0,0 +1,435 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
from typing import Union, Tuple, List, Callable
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
from einops import repeat
|
||||
from tqdm import tqdm
|
||||
|
||||
from .attention_blocks import CrossAttentionDecoder
|
||||
from .attention_processors import FlashVDMCrossAttentionProcessor, FlashVDMTopMCrossAttentionProcessor
|
||||
from ...utils import logger
|
||||
|
||||
|
||||
def extract_near_surface_volume_fn(input_tensor: torch.Tensor, alpha: float):
|
||||
device = input_tensor.device
|
||||
D = input_tensor.shape[0]
|
||||
signed_val = 0.0
|
||||
|
||||
# 添加偏移并处理无效值
|
||||
val = input_tensor + alpha
|
||||
valid_mask = val > -9000 # 假设-9000是无效值
|
||||
|
||||
# 改进的邻居获取函数(保持维度一致)
|
||||
def get_neighbor(t, shift, axis):
|
||||
"""根据指定轴进行位移并保持维度一致"""
|
||||
if shift == 0:
|
||||
return t.clone()
|
||||
|
||||
# 确定填充轴(输入为[D, D, D]对应z,y,x轴)
|
||||
pad_dims = [0, 0, 0, 0, 0, 0] # 格式:[x前,x后,y前,y后,z前,z后]
|
||||
|
||||
# 根据轴类型设置填充
|
||||
if axis == 0: # x轴(最后一个维度)
|
||||
pad_idx = 0 if shift > 0 else 1
|
||||
pad_dims[pad_idx] = abs(shift)
|
||||
elif axis == 1: # y轴(中间维度)
|
||||
pad_idx = 2 if shift > 0 else 3
|
||||
pad_dims[pad_idx] = abs(shift)
|
||||
elif axis == 2: # z轴(第一个维度)
|
||||
pad_idx = 4 if shift > 0 else 5
|
||||
pad_dims[pad_idx] = abs(shift)
|
||||
|
||||
# 执行填充(添加batch和channel维度适配F.pad)
|
||||
padded = F.pad(t.unsqueeze(0).unsqueeze(0), pad_dims[::-1], mode='replicate') # 反转顺序适配F.pad
|
||||
|
||||
# 构建动态切片索引
|
||||
slice_dims = [slice(None)] * 3 # 初始化为全切片
|
||||
if axis == 0: # x轴(dim=2)
|
||||
if shift > 0:
|
||||
slice_dims[0] = slice(shift, None)
|
||||
else:
|
||||
slice_dims[0] = slice(None, shift)
|
||||
elif axis == 1: # y轴(dim=1)
|
||||
if shift > 0:
|
||||
slice_dims[1] = slice(shift, None)
|
||||
else:
|
||||
slice_dims[1] = slice(None, shift)
|
||||
elif axis == 2: # z轴(dim=0)
|
||||
if shift > 0:
|
||||
slice_dims[2] = slice(shift, None)
|
||||
else:
|
||||
slice_dims[2] = slice(None, shift)
|
||||
|
||||
# 应用切片并恢复维度
|
||||
padded = padded.squeeze(0).squeeze(0)
|
||||
sliced = padded[slice_dims]
|
||||
return sliced
|
||||
|
||||
# 获取各方向邻居(确保维度一致)
|
||||
left = get_neighbor(val, 1, axis=0) # x方向
|
||||
right = get_neighbor(val, -1, axis=0)
|
||||
back = get_neighbor(val, 1, axis=1) # y方向
|
||||
front = get_neighbor(val, -1, axis=1)
|
||||
down = get_neighbor(val, 1, axis=2) # z方向
|
||||
up = get_neighbor(val, -1, axis=2)
|
||||
|
||||
# 处理边界无效值(使用where保持维度一致)
|
||||
def safe_where(neighbor):
|
||||
return torch.where(neighbor > -9000, neighbor, val)
|
||||
|
||||
left = safe_where(left)
|
||||
right = safe_where(right)
|
||||
back = safe_where(back)
|
||||
front = safe_where(front)
|
||||
down = safe_where(down)
|
||||
up = safe_where(up)
|
||||
|
||||
# 计算符号一致性(转换为float32确保精度)
|
||||
sign = torch.sign(val.to(torch.float32))
|
||||
neighbors_sign = torch.stack([
|
||||
torch.sign(left.to(torch.float32)),
|
||||
torch.sign(right.to(torch.float32)),
|
||||
torch.sign(back.to(torch.float32)),
|
||||
torch.sign(front.to(torch.float32)),
|
||||
torch.sign(down.to(torch.float32)),
|
||||
torch.sign(up.to(torch.float32))
|
||||
], dim=0)
|
||||
|
||||
# 检查所有符号是否一致
|
||||
same_sign = torch.all(neighbors_sign == sign, dim=0)
|
||||
|
||||
# 生成最终掩码
|
||||
mask = (~same_sign).to(torch.int32)
|
||||
return mask * valid_mask.to(torch.int32)
|
||||
|
||||
|
||||
def generate_dense_grid_points(
|
||||
bbox_min: np.ndarray,
|
||||
bbox_max: np.ndarray,
|
||||
octree_resolution: int,
|
||||
indexing: str = "ij",
|
||||
):
|
||||
length = bbox_max - bbox_min
|
||||
num_cells = octree_resolution
|
||||
|
||||
x = np.linspace(bbox_min[0], bbox_max[0], int(num_cells) + 1, dtype=np.float32)
|
||||
y = np.linspace(bbox_min[1], bbox_max[1], int(num_cells) + 1, dtype=np.float32)
|
||||
z = np.linspace(bbox_min[2], bbox_max[2], int(num_cells) + 1, dtype=np.float32)
|
||||
[xs, ys, zs] = np.meshgrid(x, y, z, indexing=indexing)
|
||||
xyz = np.stack((xs, ys, zs), axis=-1)
|
||||
grid_size = [int(num_cells) + 1, int(num_cells) + 1, int(num_cells) + 1]
|
||||
|
||||
return xyz, grid_size, length
|
||||
|
||||
|
||||
class VanillaVolumeDecoder:
|
||||
@torch.no_grad()
|
||||
def __call__(
|
||||
self,
|
||||
latents: torch.FloatTensor,
|
||||
geo_decoder: Callable,
|
||||
bounds: Union[Tuple[float], List[float], float] = 1.01,
|
||||
num_chunks: int = 10000,
|
||||
octree_resolution: int = None,
|
||||
enable_pbar: bool = True,
|
||||
**kwargs,
|
||||
):
|
||||
device = latents.device
|
||||
dtype = latents.dtype
|
||||
batch_size = latents.shape[0]
|
||||
|
||||
# 1. generate query points
|
||||
if isinstance(bounds, float):
|
||||
bounds = [-bounds, -bounds, -bounds, bounds, bounds, bounds]
|
||||
|
||||
bbox_min, bbox_max = np.array(bounds[0:3]), np.array(bounds[3:6])
|
||||
xyz_samples, grid_size, length = generate_dense_grid_points(
|
||||
bbox_min=bbox_min,
|
||||
bbox_max=bbox_max,
|
||||
octree_resolution=octree_resolution,
|
||||
indexing="ij"
|
||||
)
|
||||
xyz_samples = torch.from_numpy(xyz_samples).to(device, dtype=dtype).contiguous().reshape(-1, 3)
|
||||
|
||||
# 2. latents to 3d volume
|
||||
batch_logits = []
|
||||
for start in tqdm(range(0, xyz_samples.shape[0], num_chunks), desc=f"Volume Decoding",
|
||||
disable=not enable_pbar):
|
||||
chunk_queries = xyz_samples[start: start + num_chunks, :]
|
||||
chunk_queries = repeat(chunk_queries, "p c -> b p c", b=batch_size)
|
||||
logits = geo_decoder(queries=chunk_queries, latents=latents)
|
||||
batch_logits.append(logits)
|
||||
|
||||
grid_logits = torch.cat(batch_logits, dim=1)
|
||||
grid_logits = grid_logits.view((batch_size, *grid_size)).float()
|
||||
|
||||
return grid_logits
|
||||
|
||||
|
||||
class HierarchicalVolumeDecoding:
|
||||
@torch.no_grad()
|
||||
def __call__(
|
||||
self,
|
||||
latents: torch.FloatTensor,
|
||||
geo_decoder: Callable,
|
||||
bounds: Union[Tuple[float], List[float], float] = 1.01,
|
||||
num_chunks: int = 10000,
|
||||
mc_level: float = 0.0,
|
||||
octree_resolution: int = None,
|
||||
min_resolution: int = 63,
|
||||
enable_pbar: bool = True,
|
||||
**kwargs,
|
||||
):
|
||||
device = latents.device
|
||||
dtype = latents.dtype
|
||||
|
||||
resolutions = []
|
||||
if octree_resolution < min_resolution:
|
||||
resolutions.append(octree_resolution)
|
||||
while octree_resolution >= min_resolution:
|
||||
resolutions.append(octree_resolution)
|
||||
octree_resolution = octree_resolution // 2
|
||||
resolutions.reverse()
|
||||
|
||||
# 1. generate query points
|
||||
if isinstance(bounds, float):
|
||||
bounds = [-bounds, -bounds, -bounds, bounds, bounds, bounds]
|
||||
bbox_min = np.array(bounds[0:3])
|
||||
bbox_max = np.array(bounds[3:6])
|
||||
bbox_size = bbox_max - bbox_min
|
||||
|
||||
xyz_samples, grid_size, length = generate_dense_grid_points(
|
||||
bbox_min=bbox_min,
|
||||
bbox_max=bbox_max,
|
||||
octree_resolution=resolutions[0],
|
||||
indexing="ij"
|
||||
)
|
||||
|
||||
dilate = nn.Conv3d(1, 1, 3, padding=1, bias=False, device=device, dtype=dtype)
|
||||
dilate.weight = torch.nn.Parameter(torch.ones(dilate.weight.shape, dtype=dtype, device=device))
|
||||
|
||||
grid_size = np.array(grid_size)
|
||||
xyz_samples = torch.from_numpy(xyz_samples).to(device, dtype=dtype).contiguous().reshape(-1, 3)
|
||||
|
||||
# 2. latents to 3d volume
|
||||
batch_logits = []
|
||||
batch_size = latents.shape[0]
|
||||
for start in tqdm(range(0, xyz_samples.shape[0], num_chunks),
|
||||
desc=f"Hierarchical Volume Decoding [r{resolutions[0] + 1}]"):
|
||||
queries = xyz_samples[start: start + num_chunks, :]
|
||||
batch_queries = repeat(queries, "p c -> b p c", b=batch_size)
|
||||
logits = geo_decoder(queries=batch_queries, latents=latents)
|
||||
batch_logits.append(logits)
|
||||
|
||||
grid_logits = torch.cat(batch_logits, dim=1).view((batch_size, grid_size[0], grid_size[1], grid_size[2]))
|
||||
|
||||
for octree_depth_now in resolutions[1:]:
|
||||
grid_size = np.array([octree_depth_now + 1] * 3)
|
||||
resolution = bbox_size / octree_depth_now
|
||||
next_index = torch.zeros(tuple(grid_size), dtype=dtype, device=device)
|
||||
next_logits = torch.full(next_index.shape, -10000., dtype=dtype, device=device)
|
||||
curr_points = extract_near_surface_volume_fn(grid_logits.squeeze(0), mc_level)
|
||||
curr_points += grid_logits.squeeze(0).abs() < 0.95
|
||||
|
||||
if octree_depth_now == resolutions[-1]:
|
||||
expand_num = 0
|
||||
else:
|
||||
expand_num = 1
|
||||
for i in range(expand_num):
|
||||
curr_points = dilate(curr_points.unsqueeze(0).to(dtype)).squeeze(0)
|
||||
(cidx_x, cidx_y, cidx_z) = torch.where(curr_points > 0)
|
||||
next_index[cidx_x * 2, cidx_y * 2, cidx_z * 2] = 1
|
||||
for i in range(2 - expand_num):
|
||||
next_index = dilate(next_index.unsqueeze(0)).squeeze(0)
|
||||
nidx = torch.where(next_index > 0)
|
||||
|
||||
next_points = torch.stack(nidx, dim=1)
|
||||
next_points = (next_points * torch.tensor(resolution, dtype=next_points.dtype, device=device) +
|
||||
torch.tensor(bbox_min, dtype=next_points.dtype, device=device))
|
||||
batch_logits = []
|
||||
for start in tqdm(range(0, next_points.shape[0], num_chunks),
|
||||
desc=f"Hierarchical Volume Decoding [r{octree_depth_now + 1}]"):
|
||||
queries = next_points[start: start + num_chunks, :]
|
||||
batch_queries = repeat(queries, "p c -> b p c", b=batch_size)
|
||||
logits = geo_decoder(queries=batch_queries.to(latents.dtype), latents=latents)
|
||||
batch_logits.append(logits)
|
||||
grid_logits = torch.cat(batch_logits, dim=1)
|
||||
next_logits[nidx] = grid_logits[0, ..., 0]
|
||||
grid_logits = next_logits.unsqueeze(0)
|
||||
grid_logits[grid_logits == -10000.] = float('nan')
|
||||
|
||||
return grid_logits
|
||||
|
||||
|
||||
class FlashVDMVolumeDecoding:
|
||||
def __init__(self, topk_mode='mean'):
|
||||
if topk_mode not in ['mean', 'merge']:
|
||||
raise ValueError(f'Unsupported topk_mode {topk_mode}, available: {["mean", "merge"]}')
|
||||
|
||||
if topk_mode == 'mean':
|
||||
self.processor = FlashVDMCrossAttentionProcessor()
|
||||
else:
|
||||
self.processor = FlashVDMTopMCrossAttentionProcessor()
|
||||
|
||||
@torch.no_grad()
|
||||
def __call__(
|
||||
self,
|
||||
latents: torch.FloatTensor,
|
||||
geo_decoder: CrossAttentionDecoder,
|
||||
bounds: Union[Tuple[float], List[float], float] = 1.01,
|
||||
num_chunks: int = 10000,
|
||||
mc_level: float = 0.0,
|
||||
octree_resolution: int = None,
|
||||
min_resolution: int = 63,
|
||||
mini_grid_num: int = 4,
|
||||
enable_pbar: bool = True,
|
||||
**kwargs,
|
||||
):
|
||||
processor = self.processor
|
||||
geo_decoder.set_cross_attention_processor(processor)
|
||||
|
||||
device = latents.device
|
||||
dtype = latents.dtype
|
||||
|
||||
resolutions = []
|
||||
if octree_resolution < min_resolution:
|
||||
resolutions.append(octree_resolution)
|
||||
while octree_resolution >= min_resolution:
|
||||
resolutions.append(octree_resolution)
|
||||
octree_resolution = octree_resolution // 2
|
||||
resolutions.reverse()
|
||||
resolutions[0] = round(resolutions[0] / mini_grid_num) * mini_grid_num - 1
|
||||
for i, resolution in enumerate(resolutions[1:]):
|
||||
resolutions[i + 1] = resolutions[0] * 2 ** (i + 1)
|
||||
|
||||
logger.info(f"FlashVDMVolumeDecoding Resolution: {resolutions}")
|
||||
|
||||
# 1. generate query points
|
||||
if isinstance(bounds, float):
|
||||
bounds = [-bounds, -bounds, -bounds, bounds, bounds, bounds]
|
||||
bbox_min = np.array(bounds[0:3])
|
||||
bbox_max = np.array(bounds[3:6])
|
||||
bbox_size = bbox_max - bbox_min
|
||||
|
||||
xyz_samples, grid_size, length = generate_dense_grid_points(
|
||||
bbox_min=bbox_min,
|
||||
bbox_max=bbox_max,
|
||||
octree_resolution=resolutions[0],
|
||||
indexing="ij"
|
||||
)
|
||||
|
||||
dilate = nn.Conv3d(1, 1, 3, padding=1, bias=False, device=device, dtype=dtype)
|
||||
dilate.weight = torch.nn.Parameter(torch.ones(dilate.weight.shape, dtype=dtype, device=device))
|
||||
|
||||
grid_size = np.array(grid_size)
|
||||
|
||||
# 2. latents to 3d volume
|
||||
xyz_samples = torch.from_numpy(xyz_samples).to(device, dtype=dtype)
|
||||
batch_size = latents.shape[0]
|
||||
mini_grid_size = xyz_samples.shape[0] // mini_grid_num
|
||||
xyz_samples = xyz_samples.view(
|
||||
mini_grid_num, mini_grid_size,
|
||||
mini_grid_num, mini_grid_size,
|
||||
mini_grid_num, mini_grid_size, 3
|
||||
).permute(
|
||||
0, 2, 4, 1, 3, 5, 6
|
||||
).reshape(
|
||||
-1, mini_grid_size * mini_grid_size * mini_grid_size, 3
|
||||
)
|
||||
batch_logits = []
|
||||
num_batchs = max(num_chunks // xyz_samples.shape[1], 1)
|
||||
for start in tqdm(range(0, xyz_samples.shape[0], num_batchs),
|
||||
desc=f"FlashVDM Volume Decoding", disable=not enable_pbar):
|
||||
queries = xyz_samples[start: start + num_batchs, :]
|
||||
batch = queries.shape[0]
|
||||
batch_latents = repeat(latents.squeeze(0), "p c -> b p c", b=batch)
|
||||
processor.topk = True
|
||||
logits = geo_decoder(queries=queries, latents=batch_latents)
|
||||
batch_logits.append(logits)
|
||||
grid_logits = torch.cat(batch_logits, dim=0).reshape(
|
||||
mini_grid_num, mini_grid_num, mini_grid_num,
|
||||
mini_grid_size, mini_grid_size,
|
||||
mini_grid_size
|
||||
).permute(0, 3, 1, 4, 2, 5).contiguous().view(
|
||||
(batch_size, grid_size[0], grid_size[1], grid_size[2])
|
||||
)
|
||||
|
||||
for octree_depth_now in resolutions[1:]:
|
||||
grid_size = np.array([octree_depth_now + 1] * 3)
|
||||
resolution = bbox_size / octree_depth_now
|
||||
next_index = torch.zeros(tuple(grid_size), dtype=dtype, device=device)
|
||||
next_logits = torch.full(next_index.shape, -10000., dtype=dtype, device=device)
|
||||
curr_points = extract_near_surface_volume_fn(grid_logits.squeeze(0), mc_level)
|
||||
curr_points += grid_logits.squeeze(0).abs() < 0.95
|
||||
|
||||
if octree_depth_now == resolutions[-1]:
|
||||
expand_num = 0
|
||||
else:
|
||||
expand_num = 1
|
||||
for i in range(expand_num):
|
||||
curr_points = dilate(curr_points.unsqueeze(0).to(dtype)).squeeze(0)
|
||||
(cidx_x, cidx_y, cidx_z) = torch.where(curr_points > 0)
|
||||
|
||||
next_index[cidx_x * 2, cidx_y * 2, cidx_z * 2] = 1
|
||||
for i in range(2 - expand_num):
|
||||
next_index = dilate(next_index.unsqueeze(0)).squeeze(0)
|
||||
nidx = torch.where(next_index > 0)
|
||||
|
||||
next_points = torch.stack(nidx, dim=1)
|
||||
next_points = (next_points * torch.tensor(resolution, dtype=torch.float32, device=device) +
|
||||
torch.tensor(bbox_min, dtype=torch.float32, device=device))
|
||||
|
||||
query_grid_num = 6
|
||||
min_val = next_points.min(axis=0).values
|
||||
max_val = next_points.max(axis=0).values
|
||||
vol_queries_index = (next_points - min_val) / (max_val - min_val) * (query_grid_num - 0.001)
|
||||
index = torch.floor(vol_queries_index).long()
|
||||
index = index[..., 0] * (query_grid_num ** 2) + index[..., 1] * query_grid_num + index[..., 2]
|
||||
index = index.sort()
|
||||
next_points = next_points[index.indices].unsqueeze(0).contiguous()
|
||||
unique_values = torch.unique(index.values, return_counts=True)
|
||||
grid_logits = torch.zeros((next_points.shape[1]), dtype=latents.dtype, device=latents.device)
|
||||
input_grid = [[], []]
|
||||
logits_grid_list = []
|
||||
start_num = 0
|
||||
sum_num = 0
|
||||
for grid_index, count in zip(unique_values[0].cpu().tolist(), unique_values[1].cpu().tolist()):
|
||||
if sum_num + count < num_chunks or sum_num == 0:
|
||||
sum_num += count
|
||||
input_grid[0].append(grid_index)
|
||||
input_grid[1].append(count)
|
||||
else:
|
||||
processor.topk = input_grid
|
||||
logits_grid = geo_decoder(queries=next_points[:, start_num:start_num + sum_num], latents=latents)
|
||||
start_num = start_num + sum_num
|
||||
logits_grid_list.append(logits_grid)
|
||||
input_grid = [[grid_index], [count]]
|
||||
sum_num = count
|
||||
if sum_num > 0:
|
||||
processor.topk = input_grid
|
||||
logits_grid = geo_decoder(queries=next_points[:, start_num:start_num + sum_num], latents=latents)
|
||||
logits_grid_list.append(logits_grid)
|
||||
logits_grid = torch.cat(logits_grid_list, dim=1)
|
||||
grid_logits[index.indices] = logits_grid.squeeze(0).squeeze(-1)
|
||||
next_logits[nidx] = grid_logits
|
||||
grid_logits = next_logits.unsqueeze(0)
|
||||
|
||||
grid_logits[grid_logits == -10000.] = float('nan')
|
||||
|
||||
return grid_logits
|
||||
Regular → Executable
+104
-12
@@ -22,6 +22,7 @@
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
from torchvision import transforms
|
||||
@@ -33,6 +34,26 @@ from transformers import (
|
||||
)
|
||||
|
||||
|
||||
def get_1d_sincos_pos_embed_from_grid(embed_dim, pos):
|
||||
"""
|
||||
embed_dim: output dimension for each position
|
||||
pos: a list of positions to be encoded: size (M,)
|
||||
out: (M, D)
|
||||
"""
|
||||
assert embed_dim % 2 == 0
|
||||
omega = np.arange(embed_dim // 2, dtype=np.float64)
|
||||
omega /= embed_dim / 2.
|
||||
omega = 1. / 10000 ** omega # (D/2,)
|
||||
|
||||
pos = pos.reshape(-1) # (M,)
|
||||
out = np.einsum('m,d->md', pos, omega) # (M, D/2), outer product
|
||||
|
||||
emb_sin = np.sin(out) # (M, D/2)
|
||||
emb_cos = np.cos(out) # (M, D/2)
|
||||
|
||||
return np.concatenate([emb_sin, emb_cos], axis=1)
|
||||
|
||||
|
||||
class ImageEncoder(nn.Module):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -67,7 +88,7 @@ class ImageEncoder(nn.Module):
|
||||
]
|
||||
)
|
||||
|
||||
def forward(self, image, mask=None, value_range=(-1, 1)):
|
||||
def forward(self, image, mask=None, value_range=(-1, 1), **kwargs):
|
||||
if value_range is not None:
|
||||
low, high = value_range
|
||||
image = (image - low) / (high - low)
|
||||
@@ -82,7 +103,7 @@ class ImageEncoder(nn.Module):
|
||||
|
||||
return last_hidden_state
|
||||
|
||||
def unconditional_embedding(self, batch_size):
|
||||
def unconditional_embedding(self, batch_size, **kwargs):
|
||||
device = next(self.model.parameters()).device
|
||||
dtype = next(self.model.parameters()).dtype
|
||||
zero = torch.zeros(
|
||||
@@ -110,11 +131,82 @@ class DinoImageEncoder(ImageEncoder):
|
||||
std = [0.229, 0.224, 0.225]
|
||||
|
||||
|
||||
class DinoImageEncoderMV(DinoImageEncoder):
|
||||
def __init__(
|
||||
self,
|
||||
version=None,
|
||||
config=None,
|
||||
use_cls_token=True,
|
||||
image_size=224,
|
||||
view_num=4,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(version, config, use_cls_token, image_size, **kwargs)
|
||||
self.view_num = view_num
|
||||
self.num_patches = self.num_patches
|
||||
pos = np.arange(self.view_num, dtype=np.float32)
|
||||
view_embedding = torch.from_numpy(
|
||||
get_1d_sincos_pos_embed_from_grid(self.model.config.hidden_size, pos)).float()
|
||||
|
||||
view_embedding = view_embedding.unsqueeze(1).repeat(1, self.num_patches, 1)
|
||||
self.view_embed = view_embedding.unsqueeze(0)
|
||||
|
||||
def forward(self, image, mask=None, value_range=(-1, 1), view_idxs=None):
|
||||
if value_range is not None:
|
||||
low, high = value_range
|
||||
image = (image - low) / (high - low)
|
||||
|
||||
image = image.to(self.model.device, dtype=self.model.dtype)
|
||||
|
||||
bs, num_views, c, h, w = image.shape
|
||||
image = image.view(bs * num_views, c, h, w)
|
||||
|
||||
inputs = self.transform(image)
|
||||
outputs = self.model(inputs)
|
||||
|
||||
last_hidden_state = outputs.last_hidden_state
|
||||
last_hidden_state = last_hidden_state.view(
|
||||
bs, num_views, last_hidden_state.shape[-2],
|
||||
last_hidden_state.shape[-1]
|
||||
)
|
||||
|
||||
view_embedding = self.view_embed.to(last_hidden_state.dtype).to(last_hidden_state.device)
|
||||
if view_idxs is not None:
|
||||
assert len(view_idxs) == bs
|
||||
view_embeddings = []
|
||||
for i in range(bs):
|
||||
view_idx = view_idxs[i]
|
||||
assert num_views == len(view_idx)
|
||||
view_embeddings.append(self.view_embed[:, view_idx, ...])
|
||||
view_embedding = torch.cat(view_embeddings, 0).to(last_hidden_state.dtype).to(last_hidden_state.device)
|
||||
|
||||
if num_views != self.view_num:
|
||||
view_embedding = view_embedding[:, :num_views, ...]
|
||||
last_hidden_state = last_hidden_state + view_embedding
|
||||
last_hidden_state = last_hidden_state.view(bs, num_views * last_hidden_state.shape[-2],
|
||||
last_hidden_state.shape[-1])
|
||||
return last_hidden_state
|
||||
|
||||
def unconditional_embedding(self, batch_size, view_idxs=None, **kwargs):
|
||||
device = next(self.model.parameters()).device
|
||||
dtype = next(self.model.parameters()).dtype
|
||||
zero = torch.zeros(
|
||||
batch_size,
|
||||
self.num_patches * len(view_idxs[0]),
|
||||
self.model.config.hidden_size,
|
||||
device=device,
|
||||
dtype=dtype,
|
||||
)
|
||||
return zero
|
||||
|
||||
|
||||
def build_image_encoder(config):
|
||||
if config['type'] == 'CLIPImageEncoder':
|
||||
return CLIPImageEncoder(**config['kwargs'])
|
||||
elif config['type'] == 'DinoImageEncoder':
|
||||
return DinoImageEncoder(**config['kwargs'])
|
||||
elif config['type'] == 'DinoImageEncoderMV':
|
||||
return DinoImageEncoderMV(**config['kwargs'])
|
||||
else:
|
||||
raise ValueError(f'Unknown image encoder type: {config["type"]}')
|
||||
|
||||
@@ -129,17 +221,17 @@ class DualImageEncoder(nn.Module):
|
||||
self.main_image_encoder = build_image_encoder(main_image_encoder)
|
||||
self.additional_image_encoder = build_image_encoder(additional_image_encoder)
|
||||
|
||||
def forward(self, image, mask=None):
|
||||
def forward(self, image, mask=None, **kwargs):
|
||||
outputs = {
|
||||
'main': self.main_image_encoder(image, mask=mask),
|
||||
'additional': self.additional_image_encoder(image, mask=mask),
|
||||
'main': self.main_image_encoder(image, mask=mask, **kwargs),
|
||||
'additional': self.additional_image_encoder(image, mask=mask, **kwargs),
|
||||
}
|
||||
return outputs
|
||||
|
||||
def unconditional_embedding(self, batch_size):
|
||||
def unconditional_embedding(self, batch_size, **kwargs):
|
||||
outputs = {
|
||||
'main': self.main_image_encoder.unconditional_embedding(batch_size),
|
||||
'additional': self.additional_image_encoder.unconditional_embedding(batch_size),
|
||||
'main': self.main_image_encoder.unconditional_embedding(batch_size, **kwargs),
|
||||
'additional': self.additional_image_encoder.unconditional_embedding(batch_size, **kwargs),
|
||||
}
|
||||
return outputs
|
||||
|
||||
@@ -152,14 +244,14 @@ class SingleImageEncoder(nn.Module):
|
||||
super().__init__()
|
||||
self.main_image_encoder = build_image_encoder(main_image_encoder)
|
||||
|
||||
def forward(self, image, mask=None):
|
||||
def forward(self, image, mask=None, **kwargs):
|
||||
outputs = {
|
||||
'main': self.main_image_encoder(image, mask=mask),
|
||||
'main': self.main_image_encoder(image, mask=mask, **kwargs),
|
||||
}
|
||||
return outputs
|
||||
|
||||
def unconditional_embedding(self, batch_size):
|
||||
def unconditional_embedding(self, batch_size, **kwargs):
|
||||
outputs = {
|
||||
'main': self.main_image_encoder.unconditional_embedding(batch_size),
|
||||
'main': self.main_image_encoder.unconditional_embedding(batch_size, **kwargs),
|
||||
}
|
||||
return outputs
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
from .hunyuan3ddit import Hunyuan3DDiT
|
||||
Regular → Executable
+34
-14
@@ -1,13 +1,3 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
@@ -23,6 +13,7 @@
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import math
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Tuple, Optional
|
||||
|
||||
@@ -30,9 +21,17 @@ import torch
|
||||
from einops import rearrange
|
||||
from torch import Tensor, nn
|
||||
|
||||
scaled_dot_product_attention = nn.functional.scaled_dot_product_attention
|
||||
if os.environ.get('USE_SAGEATTN', '0') == '1':
|
||||
try:
|
||||
from sageattention import sageattn
|
||||
except ImportError:
|
||||
raise ImportError('Please install the package "sageattention" to use this USE_SAGEATTN.')
|
||||
scaled_dot_product_attention = sageattn
|
||||
|
||||
|
||||
def attention(q: Tensor, k: Tensor, v: Tensor, **kwargs) -> Tensor:
|
||||
x = torch.nn.functional.scaled_dot_product_attention(q, k, v)
|
||||
x = scaled_dot_product_attention(q, k, v)
|
||||
x = rearrange(x, "B H L D -> B L (H D)")
|
||||
return x
|
||||
|
||||
@@ -61,6 +60,15 @@ def timestep_embedding(t: Tensor, dim, max_period=10000, time_factor: float = 10
|
||||
return embedding
|
||||
|
||||
|
||||
class GELU(nn.Module):
|
||||
def __init__(self, approximate='tanh'):
|
||||
super().__init__()
|
||||
self.approximate = approximate
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
return nn.functional.gelu(x.contiguous(), approximate=self.approximate)
|
||||
|
||||
|
||||
class MLPEmbedder(nn.Module):
|
||||
def __init__(self, in_dim: int, hidden_dim: int):
|
||||
super().__init__()
|
||||
@@ -163,7 +171,7 @@ class DoubleStreamBlock(nn.Module):
|
||||
self.img_norm2 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
||||
self.img_mlp = nn.Sequential(
|
||||
nn.Linear(hidden_size, mlp_hidden_dim, bias=True),
|
||||
nn.GELU(approximate="tanh"),
|
||||
GELU(approximate="tanh"),
|
||||
nn.Linear(mlp_hidden_dim, hidden_size, bias=True),
|
||||
)
|
||||
|
||||
@@ -174,7 +182,7 @@ class DoubleStreamBlock(nn.Module):
|
||||
self.txt_norm2 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
||||
self.txt_mlp = nn.Sequential(
|
||||
nn.Linear(hidden_size, mlp_hidden_dim, bias=True),
|
||||
nn.GELU(approximate="tanh"),
|
||||
GELU(approximate="tanh"),
|
||||
nn.Linear(mlp_hidden_dim, hidden_size, bias=True),
|
||||
)
|
||||
|
||||
@@ -240,7 +248,7 @@ class SingleStreamBlock(nn.Module):
|
||||
self.hidden_size = hidden_size
|
||||
self.pre_norm = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
||||
|
||||
self.mlp_act = nn.GELU(approximate="tanh")
|
||||
self.mlp_act = GELU(approximate="tanh")
|
||||
self.modulation = Modulation(hidden_size, double=False)
|
||||
|
||||
def forward(self, x: Tensor, vec: Tensor, pe: Tensor) -> Tensor:
|
||||
@@ -287,6 +295,7 @@ class Hunyuan3DDiT(nn.Module):
|
||||
theta: int = 10_000,
|
||||
qkv_bias: bool = True,
|
||||
time_factor: float = 1000,
|
||||
guidance_embed: bool = False,
|
||||
ckpt_path: Optional[str] = None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -303,6 +312,7 @@ class Hunyuan3DDiT(nn.Module):
|
||||
self.qkv_bias = qkv_bias
|
||||
self.time_factor = time_factor
|
||||
self.out_channels = self.in_channels
|
||||
self.guidance_embed = guidance_embed
|
||||
|
||||
if hidden_size % num_heads != 0:
|
||||
raise ValueError(
|
||||
@@ -316,6 +326,9 @@ class Hunyuan3DDiT(nn.Module):
|
||||
self.latent_in = nn.Linear(self.in_channels, self.hidden_size, bias=True)
|
||||
self.time_in = MLPEmbedder(in_dim=256, hidden_dim=self.hidden_size)
|
||||
self.cond_in = nn.Linear(context_in_dim, self.hidden_size)
|
||||
self.guidance_in = (
|
||||
MLPEmbedder(in_dim=256, hidden_dim=self.hidden_size) if guidance_embed else nn.Identity()
|
||||
)
|
||||
|
||||
self.double_blocks = nn.ModuleList(
|
||||
[
|
||||
@@ -374,7 +387,14 @@ class Hunyuan3DDiT(nn.Module):
|
||||
) -> Tensor:
|
||||
cond = contexts['main']
|
||||
latent = self.latent_in(x)
|
||||
|
||||
vec = self.time_in(timestep_embedding(t, 256, self.time_factor).to(dtype=latent.dtype))
|
||||
if self.guidance_embed:
|
||||
guidance = kwargs.get('guidance', None)
|
||||
if guidance is None:
|
||||
raise ValueError("Didn't get guidance strength for guidance distilled model.")
|
||||
vec = vec + self.guidance_in(timestep_embedding(guidance, 256, self.time_factor))
|
||||
|
||||
cond = self.cond_in(cond)
|
||||
pe = None
|
||||
|
||||
Regular → Executable
+308
-120
@@ -1,13 +1,3 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
@@ -25,7 +15,6 @@
|
||||
import copy
|
||||
import importlib
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
from typing import List, Optional, Union
|
||||
|
||||
@@ -35,11 +24,12 @@ import trimesh
|
||||
import yaml
|
||||
from PIL import Image
|
||||
from diffusers.utils.torch_utils import randn_tensor
|
||||
from diffusers.utils.import_utils import is_accelerate_version, is_accelerate_available
|
||||
from tqdm import tqdm
|
||||
|
||||
import comfy.utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from .models.autoencoders import ShapeVAE
|
||||
from .models.autoencoders import SurfaceExtractors
|
||||
from .utils import logger, synchronize_timer, smart_load_model
|
||||
|
||||
|
||||
def retrieve_timesteps(
|
||||
@@ -101,6 +91,7 @@ def retrieve_timesteps(
|
||||
return timesteps, num_inference_steps
|
||||
|
||||
|
||||
@synchronize_timer('Export to trimesh')
|
||||
def export_to_trimesh(mesh_output):
|
||||
if isinstance(mesh_output, list):
|
||||
outputs = []
|
||||
@@ -137,7 +128,11 @@ def instantiate_from_config(config, **kwargs):
|
||||
|
||||
|
||||
class Hunyuan3DDiTPipeline:
|
||||
model_cpu_offload_seq = "conditioner->model->vae"
|
||||
_exclude_from_cpu_offload = []
|
||||
|
||||
@classmethod
|
||||
@synchronize_timer('Hunyuan3DDiTPipeline Model Loading')
|
||||
def from_single_file(
|
||||
cls,
|
||||
ckpt_path,
|
||||
@@ -156,7 +151,7 @@ class Hunyuan3DDiTPipeline:
|
||||
ckpt_path = ckpt_path.replace('.ckpt', '.safetensors')
|
||||
if not os.path.exists(ckpt_path):
|
||||
raise FileNotFoundError(f"Model file {ckpt_path} not found")
|
||||
logger.info(f"Loading model from {ckpt_path}")
|
||||
# logger.info(f"Loading model from {ckpt_path}")
|
||||
|
||||
if use_safetensors:
|
||||
# parse safetensors
|
||||
@@ -170,7 +165,7 @@ class Hunyuan3DDiTPipeline:
|
||||
ckpt[model_name] = {}
|
||||
ckpt[model_name][new_key] = value
|
||||
else:
|
||||
ckpt = torch.load(ckpt_path, map_location='cpu')
|
||||
ckpt = torch.load(ckpt_path, map_location='cpu', weights_only=True)
|
||||
# load model
|
||||
model = instantiate_from_config(config['model'])
|
||||
model.load_state_dict(ckpt['model'])
|
||||
@@ -201,21 +196,27 @@ class Hunyuan3DDiTPipeline:
|
||||
def from_pretrained(
|
||||
cls,
|
||||
model_path,
|
||||
ckpt_name='model.ckpt',
|
||||
config_name='config.yaml',
|
||||
device='cuda',
|
||||
dtype=torch.float16,
|
||||
use_safetensors=None,
|
||||
use_safetensors=True,
|
||||
variant='fp16',
|
||||
subfolder='hunyuan3d-dit-v2-0',
|
||||
**kwargs,
|
||||
):
|
||||
model_path = os.path.join(model_path, 'hunyuan3d-dit-v2-0')
|
||||
|
||||
config_path = os.path.join(model_path, config_name)
|
||||
ckpt_path = os.path.join(model_path, ckpt_name)
|
||||
|
||||
if not os.path.exists(model_path):
|
||||
raise FileNotFoundError(f"Model path {model_path} not found")
|
||||
|
||||
kwargs['from_pretrained_kwargs'] = dict(
|
||||
model_path=model_path,
|
||||
subfolder=subfolder,
|
||||
use_safetensors=use_safetensors,
|
||||
variant=variant,
|
||||
dtype=dtype,
|
||||
device=device,
|
||||
)
|
||||
config_path, ckpt_path = smart_load_model(
|
||||
model_path,
|
||||
subfolder=subfolder,
|
||||
use_safetensors=use_safetensors,
|
||||
variant=variant
|
||||
)
|
||||
return cls.from_single_file(
|
||||
ckpt_path,
|
||||
config_path,
|
||||
@@ -241,29 +242,187 @@ class Hunyuan3DDiTPipeline:
|
||||
self.scheduler = scheduler
|
||||
self.conditioner = conditioner
|
||||
self.image_processor = image_processor
|
||||
|
||||
self.kwargs = kwargs
|
||||
self.to(device, dtype)
|
||||
|
||||
def compile(self):
|
||||
self.vae = torch.compile(self.vae)
|
||||
self.model = torch.compile(self.model)
|
||||
self.conditioner = torch.compile(self.conditioner)
|
||||
|
||||
def enable_flashvdm(
|
||||
self,
|
||||
enabled: bool = True,
|
||||
adaptive_kv_selection=True,
|
||||
topk_mode='mean',
|
||||
mc_algo='mc',
|
||||
replace_vae=True,
|
||||
):
|
||||
if enabled:
|
||||
model_path = self.kwargs['from_pretrained_kwargs']['model_path']
|
||||
turbo_vae_mapping = {
|
||||
'Hunyuan3D-2': ('tencent/Hunyuan3D-2', 'hunyuan3d-vae-v2-0-turbo'),
|
||||
'Hunyuan3D-2mv': ('tencent/Hunyuan3D-2', 'hunyuan3d-vae-v2-0-turbo'),
|
||||
'Hunyuan3D-2mini': ('tencent/Hunyuan3D-2mini', 'hunyuan3d-vae-v2-mini-turbo'),
|
||||
}
|
||||
model_name = model_path.split('/')[-1]
|
||||
if replace_vae and model_name in turbo_vae_mapping:
|
||||
model_path, subfolder = turbo_vae_mapping[model_name]
|
||||
self.vae = ShapeVAE.from_pretrained(
|
||||
model_path, subfolder=subfolder,
|
||||
use_safetensors=self.kwargs['from_pretrained_kwargs']['use_safetensors'],
|
||||
device=self.device,
|
||||
)
|
||||
self.vae.enable_flashvdm_decoder(
|
||||
enabled=enabled,
|
||||
adaptive_kv_selection=adaptive_kv_selection,
|
||||
topk_mode=topk_mode,
|
||||
mc_algo=mc_algo
|
||||
)
|
||||
else:
|
||||
model_path = self.kwargs['from_pretrained_kwargs']['model_path']
|
||||
vae_mapping = {
|
||||
'Hunyuan3D-2': ('tencent/Hunyuan3D-2', 'hunyuan3d-vae-v2-0'),
|
||||
'Hunyuan3D-2mv': ('tencent/Hunyuan3D-2', 'hunyuan3d-vae-v2-0'),
|
||||
'Hunyuan3D-2mini': ('tencent/Hunyuan3D-2mini', 'hunyuan3d-vae-v2-mini'),
|
||||
}
|
||||
model_name = model_path.split('/')[-1]
|
||||
if model_name in vae_mapping:
|
||||
model_path, subfolder = vae_mapping[model_name]
|
||||
self.vae = ShapeVAE.from_pretrained(model_path, subfolder=subfolder)
|
||||
self.vae.enable_flashvdm_decoder(enabled=False)
|
||||
|
||||
def to(self, device=None, dtype=None):
|
||||
if device is not None:
|
||||
self.device = torch.device(device)
|
||||
self.vae.to(device)
|
||||
self.model.to(device)
|
||||
self.conditioner.to(device)
|
||||
if dtype is not None:
|
||||
self.dtype = dtype
|
||||
self.vae.to(dtype=dtype)
|
||||
self.model.to(dtype=dtype)
|
||||
self.conditioner.to(dtype=dtype)
|
||||
|
||||
if device is not None:
|
||||
self.device = torch.device(device)
|
||||
self.vae.to(device)
|
||||
self.model.to(device)
|
||||
self.conditioner.to(device)
|
||||
return self
|
||||
|
||||
def encode_cond(self, image, mask, do_classifier_free_guidance, dual_guidance):
|
||||
@property
|
||||
def _execution_device(self):
|
||||
r"""
|
||||
Returns the device on which the pipeline's models will be executed. After calling
|
||||
[`~DiffusionPipeline.enable_sequential_cpu_offload`] the execution device can only be inferred from
|
||||
Accelerate's module hooks.
|
||||
"""
|
||||
for name, model in self.components.items():
|
||||
if not isinstance(model, torch.nn.Module) or name in self._exclude_from_cpu_offload:
|
||||
continue
|
||||
|
||||
if not hasattr(model, "_hf_hook"):
|
||||
return self.device
|
||||
for module in model.modules():
|
||||
if (
|
||||
hasattr(module, "_hf_hook")
|
||||
and hasattr(module._hf_hook, "execution_device")
|
||||
and module._hf_hook.execution_device is not None
|
||||
):
|
||||
return torch.device(module._hf_hook.execution_device)
|
||||
return self.device
|
||||
|
||||
def enable_model_cpu_offload(self, gpu_id: Optional[int] = None, device: Union[torch.device, str] = "cuda"):
|
||||
r"""
|
||||
Offloads all models to CPU using accelerate, reducing memory usage with a low impact on performance. Compared
|
||||
to `enable_sequential_cpu_offload`, this method moves one whole model at a time to the GPU when its `forward`
|
||||
method is called, and the model remains in GPU until the next model runs. Memory savings are lower than with
|
||||
`enable_sequential_cpu_offload`, but performance is much better due to the iterative execution of the `unet`.
|
||||
|
||||
Arguments:
|
||||
gpu_id (`int`, *optional*):
|
||||
The ID of the accelerator that shall be used in inference. If not specified, it will default to 0.
|
||||
device (`torch.Device` or `str`, *optional*, defaults to "cuda"):
|
||||
The PyTorch device type of the accelerator that shall be used in inference. If not specified, it will
|
||||
default to "cuda".
|
||||
"""
|
||||
if self.model_cpu_offload_seq is None:
|
||||
raise ValueError(
|
||||
"Model CPU offload cannot be enabled because no `model_cpu_offload_seq` class attribute is set."
|
||||
)
|
||||
|
||||
if is_accelerate_available() and is_accelerate_version(">=", "0.17.0.dev0"):
|
||||
from accelerate import cpu_offload_with_hook
|
||||
else:
|
||||
raise ImportError("`enable_model_cpu_offload` requires `accelerate v0.17.0` or higher.")
|
||||
|
||||
torch_device = torch.device(device)
|
||||
device_index = torch_device.index
|
||||
|
||||
if gpu_id is not None and device_index is not None:
|
||||
raise ValueError(
|
||||
f"You have passed both `gpu_id`={gpu_id} and an index as part of the passed device `device`={device}"
|
||||
f"Cannot pass both. Please make sure to either not define `gpu_id` or not pass the index as part of the device: `device`={torch_device.type}"
|
||||
)
|
||||
|
||||
# _offload_gpu_id should be set to passed gpu_id (or id in passed `device`) or default to previously set id or default to 0
|
||||
self._offload_gpu_id = gpu_id or torch_device.index or getattr(self, "_offload_gpu_id", 0)
|
||||
|
||||
device_type = torch_device.type
|
||||
device = torch.device(f"{device_type}:{self._offload_gpu_id}")
|
||||
|
||||
if self.device.type != "cpu":
|
||||
self.to("cpu")
|
||||
device_mod = getattr(torch, self.device.type, None)
|
||||
if hasattr(device_mod, "empty_cache") and device_mod.is_available():
|
||||
device_mod.empty_cache() # otherwise we don't see the memory savings (but they probably exist)
|
||||
|
||||
all_model_components = {k: v for k, v in self.components.items() if isinstance(v, torch.nn.Module)}
|
||||
|
||||
self._all_hooks = []
|
||||
hook = None
|
||||
for model_str in self.model_cpu_offload_seq.split("->"):
|
||||
model = all_model_components.pop(model_str, None)
|
||||
if not isinstance(model, torch.nn.Module):
|
||||
continue
|
||||
|
||||
_, hook = cpu_offload_with_hook(model, device, prev_module_hook=hook)
|
||||
self._all_hooks.append(hook)
|
||||
|
||||
# CPU offload models that are not in the seq chain unless they are explicitly excluded
|
||||
# these models will stay on CPU until maybe_free_model_hooks is called
|
||||
# some models cannot be in the seq chain because they are iteratively called, such as controlnet
|
||||
for name, model in all_model_components.items():
|
||||
if not isinstance(model, torch.nn.Module):
|
||||
continue
|
||||
|
||||
if name in self._exclude_from_cpu_offload:
|
||||
model.to(device)
|
||||
else:
|
||||
_, hook = cpu_offload_with_hook(model, device)
|
||||
self._all_hooks.append(hook)
|
||||
|
||||
def maybe_free_model_hooks(self):
|
||||
r"""
|
||||
Function that offloads all components, removes all model hooks that were added when using
|
||||
`enable_model_cpu_offload` and then applies them again. In case the model has not been offloaded this function
|
||||
is a no-op. Make sure to add this function to the end of the `__call__` function of your pipeline so that it
|
||||
functions correctly when applying enable_model_cpu_offload.
|
||||
"""
|
||||
if not hasattr(self, "_all_hooks") or len(self._all_hooks) == 0:
|
||||
# `enable_model_cpu_offload` has not be called, so silently do nothing
|
||||
return
|
||||
|
||||
for hook in self._all_hooks:
|
||||
# offload model and remove hook from model
|
||||
hook.offload()
|
||||
hook.remove()
|
||||
|
||||
# make sure the model is in the same state as before calling it
|
||||
self.enable_model_cpu_offload()
|
||||
|
||||
@synchronize_timer('Encode cond')
|
||||
def encode_cond(self, image, additional_cond_inputs, do_classifier_free_guidance, dual_guidance):
|
||||
bsz = image.shape[0]
|
||||
cond = self.conditioner(image=image, mask=mask)
|
||||
cond = self.conditioner(image=image, **additional_cond_inputs)
|
||||
|
||||
if do_classifier_free_guidance:
|
||||
un_cond = self.conditioner.unconditional_embedding(bsz)
|
||||
un_cond = self.conditioner.unconditional_embedding(bsz, **additional_cond_inputs)
|
||||
|
||||
if dual_guidance:
|
||||
un_cond_drop_main = copy.deepcopy(un_cond)
|
||||
@@ -279,8 +438,6 @@ class Hunyuan3DDiTPipeline:
|
||||
|
||||
cond = cat_recursive(cond, un_cond_drop_main, un_cond)
|
||||
else:
|
||||
un_cond = self.conditioner.unconditional_embedding(bsz)
|
||||
|
||||
def cat_recursive(a, b):
|
||||
if isinstance(a, torch.Tensor):
|
||||
return torch.cat([a, b], dim=0).to(self.dtype)
|
||||
@@ -326,25 +483,27 @@ class Hunyuan3DDiTPipeline:
|
||||
latents = latents * getattr(self.scheduler, 'init_noise_sigma', 1.0)
|
||||
return latents
|
||||
|
||||
def prepare_image(self, image):
|
||||
def prepare_image(self, image) -> dict:
|
||||
if isinstance(image, str) and not os.path.exists(image):
|
||||
raise FileNotFoundError(f"Couldn't find image at path {image}")
|
||||
|
||||
if not isinstance(image, list):
|
||||
image = [image]
|
||||
image_pts = []
|
||||
mask_pts = []
|
||||
for img in image:
|
||||
image_pt, mask_pt = self.image_processor(img, return_mask=True)
|
||||
image_pts.append(image_pt)
|
||||
mask_pts.append(mask_pt)
|
||||
|
||||
image_pts = torch.cat(image_pts, dim=0).to(self.device, dtype=self.dtype)
|
||||
if mask_pts[0] is not None:
|
||||
mask_pts = torch.cat(mask_pts, dim=0).to(self.device, dtype=self.dtype)
|
||||
else:
|
||||
mask_pts = None
|
||||
return image_pts, mask_pts
|
||||
outputs = []
|
||||
for img in image:
|
||||
output = self.image_processor(img)
|
||||
outputs.append(output)
|
||||
|
||||
cond_input = {k: [] for k in outputs[0].keys()}
|
||||
for output in outputs:
|
||||
for key, value in output.items():
|
||||
cond_input[key].append(value)
|
||||
for key, value in cond_input.items():
|
||||
if isinstance(value[0], torch.Tensor):
|
||||
cond_input[key] = torch.cat(value, dim=0)
|
||||
|
||||
return cond_input
|
||||
|
||||
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
||||
"""
|
||||
@@ -374,6 +533,17 @@ class Hunyuan3DDiTPipeline:
|
||||
assert emb.shape == (w.shape[0], embedding_dim)
|
||||
return emb
|
||||
|
||||
def set_surface_extractor(self, mc_algo):
|
||||
if mc_algo is None:
|
||||
return
|
||||
logger.info('The parameters `mc_algo` is deprecated, and will be removed in future versions.\n'
|
||||
'Please use: \n'
|
||||
'from hy3dgen.shapegen.models.autoencoders import SurfaceExtractors\n'
|
||||
'pipeline.vae.surface_extractor = SurfaceExtractors[mc_algo]() instead\n')
|
||||
if mc_algo not in SurfaceExtractors.keys():
|
||||
raise ValueError(f"Unknown mc_algo {mc_algo}")
|
||||
self.vae.surface_extractor = SurfaceExtractors[mc_algo]()
|
||||
|
||||
@torch.no_grad()
|
||||
def __call__(
|
||||
self,
|
||||
@@ -390,7 +560,7 @@ class Hunyuan3DDiTPipeline:
|
||||
octree_resolution=384,
|
||||
mc_level=-1 / 512,
|
||||
num_chunks=8000,
|
||||
mc_algo='mc',
|
||||
mc_algo=None,
|
||||
output_type: Optional[str] = "trimesh",
|
||||
enable_pbar=True,
|
||||
**kwargs,
|
||||
@@ -398,17 +568,22 @@ class Hunyuan3DDiTPipeline:
|
||||
callback = kwargs.pop("callback", None)
|
||||
callback_steps = kwargs.pop("callback_steps", None)
|
||||
|
||||
self.set_surface_extractor(mc_algo)
|
||||
|
||||
device = self.device
|
||||
dtype = self.dtype
|
||||
do_classifier_free_guidance = guidance_scale >= 0 and \
|
||||
getattr(self.model, 'guidance_cond_proj_dim', None) is None
|
||||
dual_guidance = dual_guidance_scale >= 0 and dual_guidance
|
||||
|
||||
image, mask = self.prepare_image(image)
|
||||
cond = self.encode_cond(image=image,
|
||||
mask=mask,
|
||||
do_classifier_free_guidance=do_classifier_free_guidance,
|
||||
dual_guidance=dual_guidance)
|
||||
cond_inputs = self.prepare_image(image)
|
||||
image = cond_inputs.pop('image')
|
||||
cond = self.encode_cond(
|
||||
image=image,
|
||||
additional_cond_inputs=cond_inputs,
|
||||
do_classifier_free_guidance=do_classifier_free_guidance,
|
||||
dual_guidance=False,
|
||||
)
|
||||
batch_size = image.shape[0]
|
||||
|
||||
t_dtype = torch.long
|
||||
@@ -420,46 +595,45 @@ class Hunyuan3DDiTPipeline:
|
||||
|
||||
guidance_cond = None
|
||||
if getattr(self.model, 'guidance_cond_proj_dim', None) is not None:
|
||||
print('Using lcm guidance scale')
|
||||
logger.info('Using lcm guidance scale')
|
||||
guidance_scale_tensor = torch.tensor(guidance_scale - 1).repeat(batch_size)
|
||||
guidance_cond = self.get_guidance_scale_embedding(
|
||||
guidance_scale_tensor, embedding_dim=self.model.guidance_cond_proj_dim
|
||||
).to(device=device, dtype=latents.dtype)
|
||||
|
||||
|
||||
for i, t in enumerate(tqdm(timesteps, disable=not enable_pbar, desc="Diffusion Sampling:", leave=False)):
|
||||
# expand the latents if we are doing classifier free guidance
|
||||
if do_classifier_free_guidance:
|
||||
latent_model_input = torch.cat([latents] * (3 if dual_guidance else 2))
|
||||
else:
|
||||
latent_model_input = latents
|
||||
latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)
|
||||
|
||||
# predict the noise residual
|
||||
timestep_tensor = torch.tensor([t], dtype=t_dtype, device=device)
|
||||
timestep_tensor = timestep_tensor.expand(latent_model_input.shape[0])
|
||||
noise_pred = self.model(latent_model_input, timestep_tensor, cond, guidance_cond=guidance_cond)
|
||||
|
||||
# no drop, drop clip, all drop
|
||||
if do_classifier_free_guidance:
|
||||
if dual_guidance:
|
||||
noise_pred_clip, noise_pred_dino, noise_pred_uncond = noise_pred.chunk(3)
|
||||
noise_pred = (
|
||||
noise_pred_uncond
|
||||
+ guidance_scale * (noise_pred_clip - noise_pred_dino)
|
||||
+ dual_guidance_scale * (noise_pred_dino - noise_pred_uncond)
|
||||
)
|
||||
with synchronize_timer('Diffusion Sampling'):
|
||||
for i, t in enumerate(tqdm(timesteps, disable=not enable_pbar, desc="Diffusion Sampling:", leave=False)):
|
||||
# expand the latents if we are doing classifier free guidance
|
||||
if do_classifier_free_guidance:
|
||||
latent_model_input = torch.cat([latents] * (3 if dual_guidance else 2))
|
||||
else:
|
||||
noise_pred_cond, noise_pred_uncond = noise_pred.chunk(2)
|
||||
noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_cond - noise_pred_uncond)
|
||||
latent_model_input = latents
|
||||
latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)
|
||||
|
||||
# compute the previous noisy sample x_t -> x_t-1
|
||||
outputs = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs)
|
||||
latents = outputs.prev_sample
|
||||
# predict the noise residual
|
||||
timestep_tensor = torch.tensor([t], dtype=t_dtype, device=device)
|
||||
timestep_tensor = timestep_tensor.expand(latent_model_input.shape[0])
|
||||
noise_pred = self.model(latent_model_input, timestep_tensor, cond, guidance_cond=guidance_cond)
|
||||
|
||||
if callback is not None and i % callback_steps == 0:
|
||||
step_idx = i // getattr(self.scheduler, "order", 1)
|
||||
callback(step_idx, t, outputs)
|
||||
# no drop, drop clip, all drop
|
||||
if do_classifier_free_guidance:
|
||||
if dual_guidance:
|
||||
noise_pred_clip, noise_pred_dino, noise_pred_uncond = noise_pred.chunk(3)
|
||||
noise_pred = (
|
||||
noise_pred_uncond
|
||||
+ guidance_scale * (noise_pred_clip - noise_pred_dino)
|
||||
+ dual_guidance_scale * (noise_pred_dino - noise_pred_uncond)
|
||||
)
|
||||
else:
|
||||
noise_pred_cond, noise_pred_uncond = noise_pred.chunk(2)
|
||||
noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_cond - noise_pred_uncond)
|
||||
|
||||
# compute the previous noisy sample x_t -> x_t-1
|
||||
outputs = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs)
|
||||
latents = outputs.prev_sample
|
||||
|
||||
if callback is not None and i % callback_steps == 0:
|
||||
step_idx = i // getattr(self.scheduler, "order", 1)
|
||||
callback(step_idx, t, outputs)
|
||||
|
||||
return self._export(
|
||||
latents,
|
||||
@@ -467,7 +641,17 @@ class Hunyuan3DDiTPipeline:
|
||||
box_v, mc_level, num_chunks, octree_resolution, mc_algo,
|
||||
)
|
||||
|
||||
def _export(self, latents, output_type, box_v, mc_level, num_chunks, octree_resolution, mc_algo):
|
||||
def _export(
|
||||
self,
|
||||
latents,
|
||||
output_type='trimesh',
|
||||
box_v=1.01,
|
||||
mc_level=0.0,
|
||||
num_chunks=20000,
|
||||
octree_resolution=256,
|
||||
mc_algo='mc',
|
||||
enable_pbar=True
|
||||
):
|
||||
if not output_type == "latent":
|
||||
latents = 1. / self.vae.scale_factor * latents
|
||||
latents = self.vae(latents)
|
||||
@@ -478,6 +662,7 @@ class Hunyuan3DDiTPipeline:
|
||||
num_chunks=num_chunks,
|
||||
octree_resolution=octree_resolution,
|
||||
mc_algo=mc_algo,
|
||||
enable_pbar=enable_pbar,
|
||||
)
|
||||
else:
|
||||
outputs = latents
|
||||
@@ -490,20 +675,20 @@ class Hunyuan3DDiTPipeline:
|
||||
|
||||
class Hunyuan3DDiTFlowMatchingPipeline(Hunyuan3DDiTPipeline):
|
||||
|
||||
@torch.no_grad()
|
||||
@torch.inference_mode()
|
||||
def __call__(
|
||||
self,
|
||||
image: Union[str, List[str], Image.Image] = None,
|
||||
image: Union[str, List[str], Image.Image, dict, List[dict]] = None,
|
||||
num_inference_steps: int = 50,
|
||||
timesteps: List[int] = None,
|
||||
sigmas: List[float] = None,
|
||||
eta: float = 0.0,
|
||||
guidance_scale: float = 7.5,
|
||||
guidance_scale: float = 5.0,
|
||||
generator=None,
|
||||
box_v=1.01,
|
||||
octree_resolution=384,
|
||||
mc_level=0.0,
|
||||
mc_algo='mc',
|
||||
mc_algo=None,
|
||||
num_chunks=8000,
|
||||
output_type: Optional[str] = "trimesh",
|
||||
enable_pbar=True,
|
||||
@@ -512,6 +697,8 @@ class Hunyuan3DDiTFlowMatchingPipeline(Hunyuan3DDiTPipeline):
|
||||
callback = kwargs.pop("callback", None)
|
||||
callback_steps = kwargs.pop("callback_steps", None)
|
||||
|
||||
self.set_surface_extractor(mc_algo)
|
||||
|
||||
device = self.device
|
||||
dtype = self.dtype
|
||||
do_classifier_free_guidance = guidance_scale >= 0 and not (
|
||||
@@ -519,10 +706,11 @@ class Hunyuan3DDiTFlowMatchingPipeline(Hunyuan3DDiTPipeline):
|
||||
self.model.guidance_embed is True
|
||||
)
|
||||
|
||||
image, mask = self.prepare_image(image)
|
||||
cond_inputs = self.prepare_image(image)
|
||||
image = cond_inputs.pop('image')
|
||||
cond = self.encode_cond(
|
||||
image=image,
|
||||
mask=mask,
|
||||
additional_cond_inputs=cond_inputs,
|
||||
do_classifier_free_guidance=do_classifier_free_guidance,
|
||||
dual_guidance=False,
|
||||
)
|
||||
@@ -543,36 +731,36 @@ class Hunyuan3DDiTFlowMatchingPipeline(Hunyuan3DDiTPipeline):
|
||||
if hasattr(self.model, 'guidance_embed') and \
|
||||
self.model.guidance_embed is True:
|
||||
guidance = torch.tensor([guidance_scale] * batch_size, device=device, dtype=dtype)
|
||||
# logger.info(f'Using guidance embed with scale {guidance_scale}')
|
||||
|
||||
comfy_pbar = comfy.utils.ProgressBar(num_inference_steps)
|
||||
for i, t in enumerate(tqdm(timesteps, disable=not enable_pbar, desc="Diffusion Sampling:")):
|
||||
# expand the latents if we are doing classifier free guidance
|
||||
if do_classifier_free_guidance:
|
||||
latent_model_input = torch.cat([latents] * 2)
|
||||
else:
|
||||
latent_model_input = latents
|
||||
with synchronize_timer('Diffusion Sampling'):
|
||||
for i, t in enumerate(tqdm(timesteps, disable=not enable_pbar, desc="Diffusion Sampling:")):
|
||||
# expand the latents if we are doing classifier free guidance
|
||||
if do_classifier_free_guidance:
|
||||
latent_model_input = torch.cat([latents] * 2)
|
||||
else:
|
||||
latent_model_input = latents
|
||||
|
||||
# NOTE: we assume model get timesteps ranged from 0 to 1
|
||||
timestep = t.expand(latent_model_input.shape[0]).to(
|
||||
latents.dtype) / self.scheduler.config.num_train_timesteps
|
||||
noise_pred = self.model(latent_model_input, timestep, cond, guidance=guidance)
|
||||
# NOTE: we assume model get timesteps ranged from 0 to 1
|
||||
timestep = t.expand(latent_model_input.shape[0]).to(
|
||||
latents.dtype) / self.scheduler.config.num_train_timesteps
|
||||
noise_pred = self.model(latent_model_input, timestep, cond, guidance=guidance)
|
||||
|
||||
if do_classifier_free_guidance:
|
||||
noise_pred_cond, noise_pred_uncond = noise_pred.chunk(2)
|
||||
noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_cond - noise_pred_uncond)
|
||||
if do_classifier_free_guidance:
|
||||
noise_pred_cond, noise_pred_uncond = noise_pred.chunk(2)
|
||||
noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_cond - noise_pred_uncond)
|
||||
|
||||
# compute the previous noisy sample x_t -> x_t-1
|
||||
outputs = self.scheduler.step(noise_pred, t, latents)
|
||||
latents = outputs.prev_sample
|
||||
# compute the previous noisy sample x_t -> x_t-1
|
||||
outputs = self.scheduler.step(noise_pred, t, latents)
|
||||
latents = outputs.prev_sample
|
||||
|
||||
if callback is not None and i % callback_steps == 0:
|
||||
step_idx = i // getattr(self.scheduler, "order", 1)
|
||||
callback(step_idx, t, outputs)
|
||||
|
||||
comfy_pbar.update_absolute(i + 1)
|
||||
if callback is not None and i % callback_steps == 0:
|
||||
step_idx = i // getattr(self.scheduler, "order", 1)
|
||||
callback(step_idx, t, outputs)
|
||||
|
||||
return self._export(
|
||||
latents,
|
||||
output_type,
|
||||
box_v, mc_level, num_chunks, octree_resolution, mc_algo,
|
||||
enable_pbar=enable_pbar,
|
||||
)
|
||||
|
||||
Regular → Executable
+73
-46
@@ -1,13 +1,3 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
@@ -26,10 +16,13 @@ import os
|
||||
import tempfile
|
||||
from typing import Union
|
||||
|
||||
import numpy as np
|
||||
import pymeshlab
|
||||
import torch
|
||||
import trimesh
|
||||
|
||||
from .models.vae import Latent2MeshOutput
|
||||
from .models.autoencoders import Latent2MeshOutput
|
||||
from .utils import synchronize_timer
|
||||
|
||||
|
||||
def load_mesh(path):
|
||||
@@ -42,6 +35,9 @@ def load_mesh(path):
|
||||
|
||||
|
||||
def reduce_face(mesh: pymeshlab.MeshSet, max_facenum: int = 200000):
|
||||
if max_facenum > mesh.current_mesh().face_number():
|
||||
return mesh
|
||||
|
||||
mesh.apply_filter(
|
||||
"meshing_decimation_quadric_edge_collapse",
|
||||
targetfacenum=max_facenum,
|
||||
@@ -64,15 +60,9 @@ def remove_floater(mesh: pymeshlab.MeshSet):
|
||||
|
||||
|
||||
def pymeshlab2trimesh(mesh: pymeshlab.MeshSet):
|
||||
temp_file = tempfile.NamedTemporaryFile(suffix='.ply', delete=True)
|
||||
temp_file.close()
|
||||
temp_file_name = temp_file.name
|
||||
|
||||
mesh.save_current_mesh(temp_file_name)
|
||||
mesh = trimesh.load(temp_file_name)
|
||||
if os.path.exists(temp_file_name):
|
||||
os.remove(temp_file_name)
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.ply', delete=False) as temp_file:
|
||||
mesh.save_current_mesh(temp_file.name)
|
||||
mesh = trimesh.load(temp_file.name)
|
||||
# 检查加载的对象类型
|
||||
if isinstance(mesh, trimesh.Scene):
|
||||
combined_mesh = trimesh.Trimesh()
|
||||
@@ -84,23 +74,17 @@ def pymeshlab2trimesh(mesh: pymeshlab.MeshSet):
|
||||
|
||||
|
||||
def trimesh2pymeshlab(mesh: trimesh.Trimesh):
|
||||
temp_file = tempfile.NamedTemporaryFile(suffix='.ply', delete=True)
|
||||
temp_file.close()
|
||||
temp_file_name = temp_file.name
|
||||
|
||||
if isinstance(mesh, trimesh.scene.Scene):
|
||||
for idx, obj in enumerate(mesh.geometry.values()):
|
||||
if idx == 0:
|
||||
temp_mesh = obj
|
||||
else:
|
||||
temp_mesh = temp_mesh + obj
|
||||
mesh = temp_mesh
|
||||
mesh.export(temp_file_name)
|
||||
mesh = pymeshlab.MeshSet()
|
||||
mesh.load_new_mesh(temp_file_name)
|
||||
if os.path.exists(temp_file_name):
|
||||
os.remove(temp_file_name)
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.ply', delete=False) as temp_file:
|
||||
if isinstance(mesh, trimesh.scene.Scene):
|
||||
for idx, obj in enumerate(mesh.geometry.values()):
|
||||
if idx == 0:
|
||||
temp_mesh = obj
|
||||
else:
|
||||
temp_mesh = temp_mesh + obj
|
||||
mesh = temp_mesh
|
||||
mesh.export(temp_file.name)
|
||||
mesh = pymeshlab.MeshSet()
|
||||
mesh.load_new_mesh(temp_file.name)
|
||||
return mesh
|
||||
|
||||
|
||||
@@ -132,6 +116,7 @@ def import_mesh(mesh: Union[pymeshlab.MeshSet, trimesh.Trimesh, Latent2MeshOutpu
|
||||
|
||||
|
||||
class FaceReducer:
|
||||
@synchronize_timer('FaceReducer')
|
||||
def __call__(
|
||||
self,
|
||||
mesh: Union[pymeshlab.MeshSet, trimesh.Trimesh, Latent2MeshOutput, str],
|
||||
@@ -144,6 +129,7 @@ class FaceReducer:
|
||||
|
||||
|
||||
class FloaterRemover:
|
||||
@synchronize_timer('FloaterRemover')
|
||||
def __call__(
|
||||
self,
|
||||
mesh: Union[pymeshlab.MeshSet, trimesh.Trimesh, Latent2MeshOutput, str],
|
||||
@@ -155,21 +141,62 @@ class FloaterRemover:
|
||||
|
||||
|
||||
class DegenerateFaceRemover:
|
||||
@synchronize_timer('DegenerateFaceRemover')
|
||||
def __call__(
|
||||
self,
|
||||
mesh: Union[pymeshlab.MeshSet, trimesh.Trimesh, Latent2MeshOutput, str],
|
||||
) -> Union[pymeshlab.MeshSet, trimesh.Trimesh, Latent2MeshOutput]:
|
||||
ms = import_mesh(mesh)
|
||||
|
||||
temp_file = tempfile.NamedTemporaryFile(suffix='.ply', delete=True)
|
||||
temp_file.close()
|
||||
temp_file_name = temp_file.name
|
||||
with tempfile.NamedTemporaryFile(suffix='.ply', delete=False) as temp_file:
|
||||
ms.save_current_mesh(temp_file.name)
|
||||
ms = pymeshlab.MeshSet()
|
||||
ms.load_new_mesh(temp_file.name)
|
||||
|
||||
ms.save_current_mesh(temp_file_name)
|
||||
ms = pymeshlab.MeshSet()
|
||||
ms.load_new_mesh(temp_file_name)
|
||||
if os.path.exists(temp_file_name):
|
||||
os.remove(temp_file_name)
|
||||
|
||||
mesh = export_mesh(mesh, ms)
|
||||
return mesh
|
||||
|
||||
|
||||
def mesh_normalize(mesh):
|
||||
"""
|
||||
Normalize mesh vertices to sphere
|
||||
"""
|
||||
scale_factor = 1.2
|
||||
vtx_pos = np.asarray(mesh.vertices)
|
||||
max_bb = (vtx_pos - 0).max(0)[0]
|
||||
min_bb = (vtx_pos - 0).min(0)[0]
|
||||
|
||||
center = (max_bb + min_bb) / 2
|
||||
|
||||
scale = torch.norm(torch.tensor(vtx_pos - center, dtype=torch.float32), dim=1).max() * 2.0
|
||||
|
||||
vtx_pos = (vtx_pos - center) * (scale_factor / float(scale))
|
||||
mesh.vertices = vtx_pos
|
||||
|
||||
return mesh
|
||||
|
||||
|
||||
class MeshSimplifier:
|
||||
def __init__(self, executable: str = None):
|
||||
if executable is None:
|
||||
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
executable = os.path.join(CURRENT_DIR, "mesh_simplifier.bin")
|
||||
self.executable = executable
|
||||
|
||||
@synchronize_timer('MeshSimplifier')
|
||||
def __call__(
|
||||
self,
|
||||
mesh: Union[trimesh.Trimesh],
|
||||
) -> Union[trimesh.Trimesh]:
|
||||
with tempfile.NamedTemporaryFile(suffix='.obj', delete=False) as temp_input:
|
||||
with tempfile.NamedTemporaryFile(suffix='.obj', delete=False) as temp_output:
|
||||
mesh.export(temp_input.name)
|
||||
os.system(f'{self.executable} {temp_input.name} {temp_output.name}')
|
||||
ms = trimesh.load(temp_output.name, process=False)
|
||||
if isinstance(ms, trimesh.Scene):
|
||||
combined_mesh = trimesh.Trimesh()
|
||||
for geom in ms.geometry.values():
|
||||
combined_mesh = trimesh.util.concatenate([combined_mesh, geom])
|
||||
ms = combined_mesh
|
||||
ms = mesh_normalize(ms)
|
||||
return ms
|
||||
|
||||
Regular → Executable
+57
-17
@@ -1,12 +1,3 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
@@ -87,7 +78,7 @@ class ImageProcessorV2:
|
||||
interpolation=cv2.INTER_AREA)
|
||||
|
||||
bg = np.ones((result.shape[0], result.shape[1], 3), dtype=np.uint8) * 255
|
||||
# bg = np.zeros((result.shape[0], result.shape[1], 3), dtype=np.uint8) * 255
|
||||
|
||||
mask = result[..., 3:].astype(np.float32) / 255
|
||||
result = result[..., :3] * mask + bg * (1 - mask)
|
||||
|
||||
@@ -96,15 +87,13 @@ class ImageProcessorV2:
|
||||
mask = mask.clip(0, 255).astype(np.uint8)
|
||||
return result, mask
|
||||
|
||||
def __call__(self, image, border_ratio=0.15, to_tensor=True, return_mask=False, **kwargs):
|
||||
if self.border_ratio is not None:
|
||||
border_ratio = self.border_ratio
|
||||
print(f"Using border_ratio from init: {border_ratio}")
|
||||
def load_image(self, image, border_ratio=0.15, to_tensor=True):
|
||||
if isinstance(image, str):
|
||||
image = cv2.imread(image, cv2.IMREAD_UNCHANGED)
|
||||
image, mask = self.recenter(image, border_ratio=border_ratio)
|
||||
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
||||
elif isinstance(image, Image.Image):
|
||||
image = image.convert("RGBA")
|
||||
image = np.asarray(image)
|
||||
image, mask = self.recenter(image, border_ratio=border_ratio)
|
||||
|
||||
@@ -115,13 +104,64 @@ class ImageProcessorV2:
|
||||
if to_tensor:
|
||||
image = array_to_tensor(image)
|
||||
mask = array_to_tensor(mask)
|
||||
if return_mask:
|
||||
return image, mask
|
||||
return image
|
||||
return image, mask
|
||||
|
||||
def __call__(self, image, border_ratio=0.15, to_tensor=True, **kwargs):
|
||||
if self.border_ratio is not None:
|
||||
border_ratio = self.border_ratio
|
||||
image, mask = self.load_image(image, border_ratio=border_ratio, to_tensor=to_tensor)
|
||||
outputs = {
|
||||
'image': image,
|
||||
'mask': mask
|
||||
}
|
||||
return outputs
|
||||
|
||||
|
||||
class MVImageProcessorV2(ImageProcessorV2):
|
||||
"""
|
||||
view order: front, front clockwise 90, back, front clockwise 270
|
||||
"""
|
||||
return_view_idx = True
|
||||
|
||||
def __init__(self, size=512, border_ratio=None):
|
||||
super().__init__(size, border_ratio)
|
||||
self.view2idx = {
|
||||
'front': 0,
|
||||
'left': 1,
|
||||
'back': 2,
|
||||
'right': 3
|
||||
}
|
||||
|
||||
def __call__(self, image_dict, border_ratio=0.15, to_tensor=True, **kwargs):
|
||||
if self.border_ratio is not None:
|
||||
border_ratio = self.border_ratio
|
||||
|
||||
images = []
|
||||
masks = []
|
||||
view_idxs = []
|
||||
for idx, (view_tag, image) in enumerate(image_dict.items()):
|
||||
view_idxs.append(self.view2idx[view_tag])
|
||||
image, mask = self.load_image(image, border_ratio=border_ratio, to_tensor=to_tensor)
|
||||
images.append(image)
|
||||
masks.append(mask)
|
||||
|
||||
zipped_lists = zip(view_idxs, images, masks)
|
||||
sorted_zipped_lists = sorted(zipped_lists)
|
||||
view_idxs, images, masks = zip(*sorted_zipped_lists)
|
||||
|
||||
image = torch.cat(images, 0).unsqueeze(0)
|
||||
mask = torch.cat(masks, 0).unsqueeze(0)
|
||||
outputs = {
|
||||
'image': image,
|
||||
'mask': mask,
|
||||
'view_idxs': view_idxs
|
||||
}
|
||||
return outputs
|
||||
|
||||
|
||||
IMAGE_PROCESSORS = {
|
||||
"v2": ImageProcessorV2,
|
||||
'mv_v2': MVImageProcessorV2,
|
||||
}
|
||||
|
||||
DEFAULT_IMAGEPROCESSOR = 'v2'
|
||||
|
||||
Regular → Executable
+173
@@ -12,6 +12,20 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Optional, Tuple, Union
|
||||
@@ -305,3 +319,162 @@ class FlowMatchEulerDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
||||
|
||||
def __len__(self):
|
||||
return self.config.num_train_timesteps
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConsistencyFlowMatchEulerDiscreteSchedulerOutput(BaseOutput):
|
||||
prev_sample: torch.FloatTensor
|
||||
pred_original_sample: torch.FloatTensor
|
||||
|
||||
|
||||
class ConsistencyFlowMatchEulerDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
||||
_compatibles = []
|
||||
order = 1
|
||||
|
||||
@register_to_config
|
||||
def __init__(
|
||||
self,
|
||||
num_train_timesteps: int = 1000,
|
||||
pcm_timesteps: int = 50,
|
||||
):
|
||||
sigmas = np.linspace(0, 1, num_train_timesteps)
|
||||
step_ratio = num_train_timesteps // pcm_timesteps
|
||||
|
||||
euler_timesteps = (np.arange(1, pcm_timesteps) * step_ratio).round().astype(np.int64) - 1
|
||||
euler_timesteps = np.asarray([0] + euler_timesteps.tolist())
|
||||
|
||||
self.euler_timesteps = euler_timesteps
|
||||
self.sigmas = sigmas[self.euler_timesteps]
|
||||
self.sigmas = torch.from_numpy((self.sigmas.copy())).to(dtype=torch.float32)
|
||||
self.timesteps = self.sigmas * num_train_timesteps
|
||||
self._step_index = None
|
||||
self._begin_index = None
|
||||
self.sigmas = self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||
|
||||
@property
|
||||
def step_index(self):
|
||||
"""
|
||||
The index counter for current timestep. It will increase 1 after each scheduler step.
|
||||
"""
|
||||
return self._step_index
|
||||
|
||||
@property
|
||||
def begin_index(self):
|
||||
"""
|
||||
The index for the first timestep. It should be set from pipeline with `set_begin_index` method.
|
||||
"""
|
||||
return self._begin_index
|
||||
|
||||
# Copied from diffusers.schedulers.scheduling_dpmsolver_multistep.DPMSolverMultistepScheduler.set_begin_index
|
||||
def set_begin_index(self, begin_index: int = 0):
|
||||
"""
|
||||
Sets the begin index for the scheduler. This function should be run from pipeline before the inference.
|
||||
|
||||
Args:
|
||||
begin_index (`int`):
|
||||
The begin index for the scheduler.
|
||||
"""
|
||||
self._begin_index = begin_index
|
||||
|
||||
def _sigma_to_t(self, sigma):
|
||||
return sigma * self.config.num_train_timesteps
|
||||
|
||||
def set_timesteps(
|
||||
self,
|
||||
num_inference_steps: int = None,
|
||||
device: Union[str, torch.device] = None,
|
||||
sigmas: Optional[List[float]] = None,
|
||||
):
|
||||
"""
|
||||
Sets the discrete timesteps used for the diffusion chain (to be run before inference).
|
||||
|
||||
Args:
|
||||
num_inference_steps (`int`):
|
||||
The number of diffusion steps used when generating samples with a pre-trained model.
|
||||
device (`str` or `torch.device`, *optional*):
|
||||
The device to which the timesteps should be moved to. If `None`, the timesteps are not moved.
|
||||
"""
|
||||
self.num_inference_steps = num_inference_steps if num_inference_steps is not None else len(sigmas)
|
||||
inference_indices = np.linspace(
|
||||
0, self.config.pcm_timesteps, num=self.num_inference_steps, endpoint=False
|
||||
)
|
||||
inference_indices = np.floor(inference_indices).astype(np.int64)
|
||||
inference_indices = torch.from_numpy(inference_indices).long()
|
||||
|
||||
self.sigmas_ = self.sigmas[inference_indices]
|
||||
timesteps = self.sigmas_ * self.config.num_train_timesteps
|
||||
self.timesteps = timesteps.to(device=device)
|
||||
self.sigmas_ = torch.cat(
|
||||
[self.sigmas_, torch.ones(1, device=self.sigmas_.device)]
|
||||
)
|
||||
|
||||
self._step_index = None
|
||||
self._begin_index = None
|
||||
|
||||
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
||||
if schedule_timesteps is None:
|
||||
schedule_timesteps = self.timesteps
|
||||
|
||||
indices = (schedule_timesteps == timestep).nonzero()
|
||||
|
||||
# The sigma index that is taken for the **very** first `step`
|
||||
# is always the second index (or the last index if there is only 1)
|
||||
# This way we can ensure we don't accidentally skip a sigma in
|
||||
# case we start in the middle of the denoising schedule (e.g. for image-to-image)
|
||||
pos = 1 if len(indices) > 1 else 0
|
||||
|
||||
return indices[pos].item()
|
||||
|
||||
def _init_step_index(self, timestep):
|
||||
if self.begin_index is None:
|
||||
if isinstance(timestep, torch.Tensor):
|
||||
timestep = timestep.to(self.timesteps.device)
|
||||
self._step_index = self.index_for_timestep(timestep)
|
||||
else:
|
||||
self._step_index = self._begin_index
|
||||
|
||||
def step(
|
||||
self,
|
||||
model_output: torch.FloatTensor,
|
||||
timestep: Union[float, torch.FloatTensor],
|
||||
sample: torch.FloatTensor,
|
||||
generator: Optional[torch.Generator] = None,
|
||||
return_dict: bool = True,
|
||||
) -> Union[ConsistencyFlowMatchEulerDiscreteSchedulerOutput, Tuple]:
|
||||
if (
|
||||
isinstance(timestep, int)
|
||||
or isinstance(timestep, torch.IntTensor)
|
||||
or isinstance(timestep, torch.LongTensor)
|
||||
):
|
||||
raise ValueError(
|
||||
(
|
||||
"Passing integer indices (e.g. from `enumerate(timesteps)`) as timesteps to"
|
||||
" `EulerDiscreteScheduler.step()` is not supported. Make sure to pass"
|
||||
" one of the `scheduler.timesteps` as a timestep."
|
||||
),
|
||||
)
|
||||
|
||||
if self.step_index is None:
|
||||
self._init_step_index(timestep)
|
||||
|
||||
sample = sample.to(torch.float32)
|
||||
|
||||
sigma = self.sigmas_[self.step_index]
|
||||
sigma_next = self.sigmas_[self.step_index + 1]
|
||||
|
||||
prev_sample = sample + (sigma_next - sigma) * model_output
|
||||
prev_sample = prev_sample.to(model_output.dtype)
|
||||
|
||||
pred_original_sample = sample + (1.0 - sigma) * model_output
|
||||
pred_original_sample = pred_original_sample.to(model_output.dtype)
|
||||
|
||||
self._step_index += 1
|
||||
|
||||
if not return_dict:
|
||||
return (prev_sample,)
|
||||
|
||||
return ConsistencyFlowMatchEulerDiscreteSchedulerOutput(prev_sample=prev_sample,
|
||||
pred_original_sample=pred_original_sample)
|
||||
|
||||
def __len__(self):
|
||||
return self.config.num_train_timesteps
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import logging
|
||||
import os
|
||||
from functools import wraps
|
||||
|
||||
import torch
|
||||
|
||||
|
||||
def get_logger(name):
|
||||
logger = logging.getLogger(name)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(logging.INFO)
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
console_handler.setFormatter(formatter)
|
||||
logger.addHandler(console_handler)
|
||||
return logger
|
||||
|
||||
|
||||
logger = get_logger('hy3dgen.shapgen')
|
||||
|
||||
|
||||
class synchronize_timer:
|
||||
""" Synchronized timer to count the inference time of `nn.Module.forward`.
|
||||
|
||||
Supports both context manager and decorator usage.
|
||||
|
||||
Example as context manager:
|
||||
```python
|
||||
with synchronize_timer('name') as t:
|
||||
run()
|
||||
```
|
||||
|
||||
Example as decorator:
|
||||
```python
|
||||
@synchronize_timer('Export to trimesh')
|
||||
def export_to_trimesh(mesh_output):
|
||||
pass
|
||||
```
|
||||
"""
|
||||
|
||||
def __init__(self, name=None):
|
||||
self.name = name
|
||||
|
||||
def __enter__(self):
|
||||
"""Context manager entry: start timing."""
|
||||
if os.environ.get('HY3DGEN_DEBUG', '0') == '1':
|
||||
self.start = torch.cuda.Event(enable_timing=True)
|
||||
self.end = torch.cuda.Event(enable_timing=True)
|
||||
self.start.record()
|
||||
return lambda: self.time
|
||||
|
||||
def __exit__(self, exc_type, exc_value, exc_tb):
|
||||
"""Context manager exit: stop timing and log results."""
|
||||
if os.environ.get('HY3DGEN_DEBUG', '0') == '1':
|
||||
self.end.record()
|
||||
torch.cuda.synchronize()
|
||||
self.time = self.start.elapsed_time(self.end)
|
||||
if self.name is not None:
|
||||
logger.info(f'{self.name} takes {self.time} ms')
|
||||
|
||||
def __call__(self, func):
|
||||
"""Decorator: wrap the function to time its execution."""
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
with self:
|
||||
result = func(*args, **kwargs)
|
||||
return result
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def smart_load_model(
|
||||
model_path,
|
||||
subfolder,
|
||||
use_safetensors,
|
||||
variant,
|
||||
):
|
||||
original_model_path = model_path
|
||||
# try local path
|
||||
base_dir = os.environ.get('HY3DGEN_MODELS', '~/.cache/hy3dgen')
|
||||
model_path = os.path.expanduser(os.path.join(base_dir, model_path, subfolder))
|
||||
logger.info(f'Try to load model from local path: {model_path}')
|
||||
if not os.path.exists(model_path):
|
||||
logger.info('Model path not exists, try to download from huggingface')
|
||||
try:
|
||||
from huggingface_hub import snapshot_download
|
||||
# 只下载指定子目录
|
||||
path = snapshot_download(
|
||||
repo_id=original_model_path,
|
||||
allow_patterns=[f"{subfolder}/*"], # 关键修改:模式匹配子文件夹
|
||||
)
|
||||
model_path = os.path.join(path, subfolder) # 保持路径拼接逻辑不变
|
||||
except ImportError:
|
||||
logger.warning(
|
||||
"You need to install HuggingFace Hub to load models from the hub."
|
||||
)
|
||||
raise RuntimeError(f"Model path {model_path} not found")
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
if not os.path.exists(model_path):
|
||||
raise FileNotFoundError(f"Model path {original_model_path} not found")
|
||||
|
||||
extension = 'ckpt' if not use_safetensors else 'safetensors'
|
||||
variant = '' if variant is None else f'.{variant}'
|
||||
ckpt_name = f'model{variant}.{extension}'
|
||||
config_path = os.path.join(model_path, 'config.yaml')
|
||||
ckpt_path = os.path.join(model_path, ckpt_name)
|
||||
return config_path, ckpt_path
|
||||
@@ -1,13 +1,3 @@
|
||||
# Open Source Model Licensed under the Apache License Version 2.0
|
||||
# and Other Licenses of the Third-Party Components therein:
|
||||
# The below Model in this distribution may have been modified by THL A29 Limited
|
||||
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
||||
|
||||
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
# The below software and/or models in this distribution may have been
|
||||
# modified by THL A29 Limited ("Tencent Modifications").
|
||||
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
'''
|
||||
from .hierarchy import BuildHierarchy, BuildHierarchyWithColor
|
||||
from .io_obj import LoadObj, LoadObjWithTexture
|
||||
from .render import rasterize, interpolate
|
||||
'''
|
||||
from .io_glb import *
|
||||
from .io_obj import *
|
||||
from .render import *
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import base64
|
||||
import io
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image as PILImage
|
||||
from pygltflib import GLTF2
|
||||
from scipy.spatial.transform import Rotation as R
|
||||
|
||||
|
||||
# Function to extract buffer data
|
||||
def get_buffer_data(gltf, buffer_view):
|
||||
buffer = gltf.buffers[buffer_view.buffer]
|
||||
buffer_data = gltf.get_data_from_buffer_uri(buffer.uri)
|
||||
byte_offset = buffer_view.byteOffset if buffer_view.byteOffset else 0
|
||||
byte_length = buffer_view.byteLength
|
||||
return buffer_data[byte_offset:byte_offset + byte_length]
|
||||
|
||||
|
||||
# Function to extract attribute data
|
||||
def get_attribute_data(gltf, accessor_index):
|
||||
accessor = gltf.accessors[accessor_index]
|
||||
buffer_view = gltf.bufferViews[accessor.bufferView]
|
||||
buffer_data = get_buffer_data(gltf, buffer_view)
|
||||
|
||||
comptype = {5120: np.int8, 5121: np.uint8, 5122: np.int16, 5123: np.uint16, 5125: np.uint32, 5126: np.float32}
|
||||
dtype = comptype[accessor.componentType]
|
||||
|
||||
t2n = {'SCALAR': 1, 'VEC2': 2, 'VEC3': 3, 'VEC4': 4, 'MAT2': 4, 'MAT3': 9, 'MAT4': 16}
|
||||
num_components = t2n[accessor.type]
|
||||
|
||||
# Calculate the correct slice of data
|
||||
byte_offset = accessor.byteOffset if accessor.byteOffset else 0
|
||||
byte_stride = buffer_view.byteStride if buffer_view.byteStride else num_components * np.dtype(dtype).itemsize
|
||||
count = accessor.count
|
||||
|
||||
# Extract the attribute data
|
||||
attribute_data = np.zeros((count, num_components), dtype=dtype)
|
||||
for i in range(count):
|
||||
start = byte_offset + i * byte_stride
|
||||
end = start + num_components * np.dtype(dtype).itemsize
|
||||
attribute_data[i] = np.frombuffer(buffer_data[start:end], dtype=dtype)
|
||||
|
||||
return attribute_data
|
||||
|
||||
|
||||
# Function to extract image data
|
||||
def get_image_data(gltf, image, folder):
|
||||
if image.uri:
|
||||
if image.uri.startswith('data:'):
|
||||
# Data URI
|
||||
header, encoded = image.uri.split(',', 1)
|
||||
data = base64.b64decode(encoded)
|
||||
else:
|
||||
# External file
|
||||
fn = image.uri
|
||||
if not os.path.isabs(fn):
|
||||
fn = folder + '/' + fn
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
else:
|
||||
buffer_view = gltf.bufferViews[image.bufferView]
|
||||
data = get_buffer_data(gltf, buffer_view)
|
||||
return data
|
||||
|
||||
|
||||
# Function to convert triangle strip to triangles
|
||||
def convert_triangle_strip_to_triangles(indices):
|
||||
triangles = []
|
||||
for i in range(len(indices) - 2):
|
||||
if i % 2 == 0:
|
||||
triangles.append([indices[i], indices[i + 1], indices[i + 2]])
|
||||
else:
|
||||
triangles.append([indices[i], indices[i + 2], indices[i + 1]])
|
||||
return np.array(triangles).reshape(-1, 3)
|
||||
|
||||
|
||||
# Function to convert triangle fan to triangles
|
||||
def convert_triangle_fan_to_triangles(indices):
|
||||
triangles = []
|
||||
for i in range(1, len(indices) - 1):
|
||||
triangles.append([indices[0], indices[i], indices[i + 1]])
|
||||
return np.array(triangles).reshape(-1, 3)
|
||||
|
||||
|
||||
# Function to get the transformation matrix from a node
|
||||
def get_node_transform(node):
|
||||
if node.matrix:
|
||||
return np.array(node.matrix).reshape(4, 4).T
|
||||
else:
|
||||
T = np.eye(4)
|
||||
if node.translation:
|
||||
T[:3, 3] = node.translation
|
||||
if node.rotation:
|
||||
R_mat = R.from_quat(node.rotation).as_matrix()
|
||||
T[:3, :3] = R_mat
|
||||
if node.scale:
|
||||
S = np.diag(node.scale + [1])
|
||||
T = T @ S
|
||||
return T
|
||||
|
||||
|
||||
def get_world_transform(gltf, node_index, parents, world_transforms):
|
||||
if parents[node_index] == -2:
|
||||
return world_transforms[node_index]
|
||||
|
||||
node = gltf.nodes[node_index]
|
||||
if parents[node_index] == -1:
|
||||
world_transforms[node_index] = get_node_transform(node)
|
||||
parents[node_index] = -2
|
||||
return world_transforms[node_index]
|
||||
|
||||
parent_index = parents[node_index]
|
||||
parent_transform = get_world_transform(gltf, parent_index, parents, world_transforms)
|
||||
world_transforms[node_index] = parent_transform @ get_node_transform(node)
|
||||
parents[node_index] = -2
|
||||
return world_transforms[node_index]
|
||||
|
||||
|
||||
def LoadGlb(path):
|
||||
# Load the GLB file using pygltflib
|
||||
gltf = GLTF2().load(path)
|
||||
|
||||
primitives = []
|
||||
images = {}
|
||||
# Iterate through the meshes in the GLB file
|
||||
|
||||
world_transforms = [np.identity(4) for i in range(len(gltf.nodes))]
|
||||
parents = [-1 for i in range(len(gltf.nodes))]
|
||||
for node_index, node in enumerate(gltf.nodes):
|
||||
for idx in node.children:
|
||||
parents[idx] = node_index
|
||||
# for i in range(len(gltf.nodes)):
|
||||
# get_world_transform(gltf, i, parents, world_transform)
|
||||
|
||||
for node_index, node in enumerate(gltf.nodes):
|
||||
if node.mesh is not None:
|
||||
world_transform = get_world_transform(gltf, node_index, parents, world_transforms)
|
||||
# Iterate through the primitives in the mesh
|
||||
mesh = gltf.meshes[node.mesh]
|
||||
for primitive in mesh.primitives:
|
||||
# Access the attributes of the primitive
|
||||
attributes = primitive.attributes.__dict__
|
||||
mode = primitive.mode if primitive.mode is not None else 4 # Default to TRIANGLES
|
||||
result = {}
|
||||
if primitive.indices is not None:
|
||||
indices = get_attribute_data(gltf, primitive.indices)
|
||||
if mode == 4: # TRIANGLES
|
||||
face_indices = indices.reshape(-1, 3)
|
||||
elif mode == 5: # TRIANGLE_STRIP
|
||||
face_indices = convert_triangle_strip_to_triangles(indices)
|
||||
elif mode == 6: # TRIANGLE_FAN
|
||||
face_indices = convert_triangle_fan_to_triangles(indices)
|
||||
else:
|
||||
continue
|
||||
result['F'] = face_indices
|
||||
|
||||
# Extract vertex positions
|
||||
if 'POSITION' in attributes and attributes['POSITION'] is not None:
|
||||
positions = get_attribute_data(gltf, attributes['POSITION'])
|
||||
# Apply the world transformation to the positions
|
||||
positions_homogeneous = np.hstack([positions, np.ones((positions.shape[0], 1))])
|
||||
transformed_positions = (world_transform @ positions_homogeneous.T).T[:, :3]
|
||||
result['V'] = transformed_positions
|
||||
|
||||
# Extract vertex colors
|
||||
if 'COLOR_0' in attributes and attributes['COLOR_0'] is not None:
|
||||
colors = get_attribute_data(gltf, attributes['COLOR_0'])
|
||||
if colors.shape[-1] > 3:
|
||||
colors = colors[..., :3]
|
||||
result['VC'] = colors
|
||||
|
||||
# Extract UVs
|
||||
if 'TEXCOORD_0' in attributes and not attributes['TEXCOORD_0'] is None:
|
||||
uvs = get_attribute_data(gltf, attributes['TEXCOORD_0'])
|
||||
result['UV'] = uvs
|
||||
|
||||
if primitive.material is not None:
|
||||
material = gltf.materials[primitive.material]
|
||||
if (
|
||||
material.pbrMetallicRoughness is not None
|
||||
and material.pbrMetallicRoughness.baseColorTexture is not None
|
||||
):
|
||||
texture_index = material.pbrMetallicRoughness.baseColorTexture.index
|
||||
texture = gltf.textures[texture_index]
|
||||
image_index = texture.source
|
||||
if not image_index in images:
|
||||
image = gltf.images[image_index]
|
||||
image_data = get_image_data(gltf, image, os.path.dirname(path))
|
||||
pil_image = PILImage.open(io.BytesIO(image_data))
|
||||
if pil_image.mode != 'RGB':
|
||||
pil_image = pil_image.convert('RGB')
|
||||
images[image_index] = pil_image
|
||||
result['TEX'] = image_index
|
||||
elif material.emissiveTexture is not None:
|
||||
texture_index = material.emissiveTexture.index
|
||||
texture = gltf.textures[texture_index]
|
||||
image_index = texture.source
|
||||
if not image_index in images:
|
||||
image = gltf.images[image_index]
|
||||
image_data = get_image_data(gltf, image, os.path.dirname(path))
|
||||
pil_image = PILImage.open(io.BytesIO(image_data))
|
||||
if pil_image.mode != 'RGB':
|
||||
pil_image = pil_image.convert('RGB')
|
||||
images[image_index] = pil_image
|
||||
result['TEX'] = image_index
|
||||
else:
|
||||
if material.pbrMetallicRoughness is not None:
|
||||
base_color = material.pbrMetallicRoughness.baseColorFactor
|
||||
else:
|
||||
base_color = np.array([0.8, 0.8, 0.8], dtype=np.float32)
|
||||
result['MC'] = base_color
|
||||
|
||||
primitives.append(result)
|
||||
|
||||
return primitives, images
|
||||
|
||||
|
||||
def RotatePrimitives(primitives, transform):
|
||||
for i in range(len(primitives)):
|
||||
if 'V' in primitives[i]:
|
||||
primitives[i]['V'] = primitives[i]['V'] @ transform.T
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = 'data/test.glb'
|
||||
LoadGlb(path)
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
|
||||
def LoadObj(fn):
|
||||
lines = [l.strip() for l in open(fn)]
|
||||
vertices = []
|
||||
faces = []
|
||||
for l in lines:
|
||||
words = [w for w in l.split(' ') if w != '']
|
||||
if len(words) == 0:
|
||||
continue
|
||||
if words[0] == 'v':
|
||||
v = [float(words[i]) for i in range(1, 4)]
|
||||
vertices.append(v)
|
||||
elif words[0] == 'f':
|
||||
f = [int(words[i]) - 1 for i in range(1, 4)]
|
||||
faces.append(f)
|
||||
|
||||
return np.array(vertices).astype('float32'), np.array(faces).astype('int32')
|
||||
|
||||
|
||||
def LoadObjWithTexture(fn, tex_fn):
|
||||
lines = [l.strip() for l in open(fn)]
|
||||
vertices = []
|
||||
vertex_textures = []
|
||||
faces = []
|
||||
face_textures = []
|
||||
for l in lines:
|
||||
words = [w for w in l.split(' ') if w != '']
|
||||
if len(words) == 0:
|
||||
continue
|
||||
if words[0] == 'v':
|
||||
v = [float(words[i]) for i in range(1, len(words))]
|
||||
vertices.append(v)
|
||||
elif words[0] == 'vt':
|
||||
v = [float(words[i]) for i in range(1, len(words))]
|
||||
vertex_textures.append(v)
|
||||
elif words[0] == 'f':
|
||||
f = []
|
||||
ft = []
|
||||
for i in range(1, len(words)):
|
||||
t = words[i].split('/')
|
||||
f.append(int(t[0]) - 1)
|
||||
ft.append(int(t[1]) - 1)
|
||||
for i in range(2, len(f)):
|
||||
faces.append([f[0], f[i - 1], f[i]])
|
||||
face_textures.append([ft[0], ft[i - 1], ft[i]])
|
||||
|
||||
tex_image = cv2.cvtColor(cv2.imread(tex_fn), cv2.COLOR_BGR2RGB)
|
||||
return np.array(vertices).astype('float32'), np.array(vertex_textures).astype('float32'), np.array(faces).astype(
|
||||
'int32'), np.array(face_textures).astype('int32'), tex_image
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
|
||||
import custom_rasterizer_kernel
|
||||
import torch
|
||||
|
||||
|
||||
def rasterize(pos, tri, resolution, clamp_depth=torch.zeros(0), use_depth_prior=0):
|
||||
assert (pos.device == tri.device)
|
||||
findices, barycentric = custom_rasterizer_kernel.rasterize_image(pos[0], tri, clamp_depth, resolution[1],
|
||||
resolution[0], 1e-6, use_depth_prior)
|
||||
return findices, barycentric
|
||||
|
||||
|
||||
def interpolate(col, findices, barycentric, tri):
|
||||
f = findices - 1 + (findices == 0)
|
||||
vcol = col[0, tri.long()[f.long()]]
|
||||
result = barycentric.view(*barycentric.shape, 1) * vcol
|
||||
result = torch.sum(result, axis=-2)
|
||||
return result.view(1, *result.shape)
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
||||
# except for the third-party components listed below.
|
||||
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
||||
# in the repsective licenses of these third-party components.
|
||||
# Users must comply with all terms and conditions of original licenses of these third-party
|
||||
# components and must ensure that the usage of the third party components adheres to
|
||||
# all relevant laws and regulations.
|
||||
|
||||
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
||||
# their software and algorithms, including trained model weights, parameters (including
|
||||
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
||||
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
||||
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user