Files
2024-05-26 20:35:16 +08:00

129 lines
7.0 KiB
Markdown

# Documentation
- Class name: MagicAnimateModelLoader
- Category: ComfyUI Magic Animate
- Output node: False
- Repo Ref: https://github.com/thecooltechguy/ComfyUI-MagicAnimate
MagicAnimateModelLoader类负责管理和加载魔法动画模型的各个组件。它作为控制网络、外观编码器、运动模块和其他相关模块的集中存储库。load_model方法旨在清除任何现有的模型,加载新配置,并初始化用于动画目的的模型组件。
# Input types
## Optional
- controlnet
- controlnet参数指定控制网络的检查点或路径,这是动画模型的关键部分。它用于指导生成过程。
- Comfy dtype: str
- Python dtype: str
- appearance_encoder
- appearance_encoder参数表示外观编码器的检查点或文件路径,它负责编码输入的视觉特征。
- Comfy dtype: str
- Python dtype: str
- motion_module
- motion_module参数指向运动模块的检查点或文件路径,这对于根据给定的运动对输入进行动画制作至关重要。
- Comfy dtype: str
- Python dtype: str
- device
- device参数确定用于模型执行的计算设备,通常为'cuda'以进行GPU加速或'cpu'。
- Comfy dtype: str
- Python dtype: str
# Output types
- MAGIC_ANIMATE_MODEL
- 输出是一个包含已加载模型和配置的字典。它包括VAE、文本编码器、外观编码器、分词器、UNet、控制网络和动画流水线。
- Comfy dtype: dict
- Python dtype: Dict[str, torch.nn.Module]
# Usage tips
- Infra type: GPU
# Source code
```
class MagicAnimateModelLoader:
def __init__(self):
self.models = {}
@classmethod
def INPUT_TYPES(s):
magic_animate_checkpoints = folder_paths.get_filename_list('magic_animate')
devices = []
if True:
devices.append('cuda')
devices.append('cpu')
return {'required': {'controlnet': (magic_animate_checkpoints, {'default': magic_animate_checkpoints[0]}), 'appearance_encoder': (magic_animate_checkpoints, {'default': magic_animate_checkpoints[0]}), 'motion_module': (magic_animate_checkpoints, {'default': magic_animate_checkpoints[0]}), 'device': (devices,)}}
RETURN_TYPES = ('MAGIC_ANIMATE_MODEL',)
FUNCTION = 'load_model'
CATEGORY = 'ComfyUI Magic Animate'
def load_model(self, controlnet, appearance_encoder, motion_module, device):
if self.models:
all_keys = list(self.models.keys())
for key in all_keys:
del self.models[key]
self.models = {}
gc.collect()
current_dir = os.path.dirname(os.path.realpath(__file__))
config = OmegaConf.load(os.path.join(current_dir, 'configs', 'prompts', 'animation.yaml'))
inference_config = OmegaConf.load(os.path.join(current_dir, 'configs', 'inference', 'inference.yaml'))
magic_animate_models_dir = folder_paths.get_folder_paths('magic_animate')[0]
config.pretrained_model_path = os.path.join(magic_animate_models_dir, 'stable-diffusion-v1-5')
config.pretrained_vae_path = os.path.join(magic_animate_models_dir, 'sd-vae-ft-mse')
config.pretrained_appearance_encoder_path = os.path.join(magic_animate_models_dir, os.path.dirname(appearance_encoder))
config.pretrained_controlnet_path = os.path.join(magic_animate_models_dir, os.path.dirname(controlnet))
motion_module = os.path.join(magic_animate_models_dir, motion_module)
config.motion_module = motion_module
tokenizer = CLIPTokenizer.from_pretrained(config.pretrained_model_path, subfolder='tokenizer')
text_encoder = CLIPTextModel.from_pretrained(config.pretrained_model_path, subfolder='text_encoder')
if config.pretrained_unet_path:
unet = UNet3DConditionModel.from_pretrained_2d(config.pretrained_unet_path, unet_additional_kwargs=OmegaConf.to_container(inference_config.unet_additional_kwargs))
else:
unet = UNet3DConditionModel.from_pretrained_2d(config.pretrained_model_path, subfolder='unet', unet_additional_kwargs=OmegaConf.to_container(inference_config.unet_additional_kwargs))
appearance_encoder = AppearanceEncoderModel.from_pretrained(config.pretrained_appearance_encoder_path).to(device)
reference_control_writer = ReferenceAttentionControl(appearance_encoder, do_classifier_free_guidance=True, mode='write', fusion_blocks=config.fusion_blocks)
reference_control_reader = ReferenceAttentionControl(unet, do_classifier_free_guidance=True, mode='read', fusion_blocks=config.fusion_blocks)
vae = AutoencoderKL.from_pretrained(config.pretrained_vae_path)
controlnet = ControlNetModel.from_pretrained(config.pretrained_controlnet_path)
vae.to(torch.float16)
unet.to(torch.float16)
text_encoder.to(torch.float16)
appearance_encoder.to(torch.float16)
controlnet.to(torch.float16)
pipeline = AnimationPipeline(vae=vae, text_encoder=text_encoder, tokenizer=tokenizer, unet=unet, controlnet=controlnet, scheduler=DDIMScheduler(**OmegaConf.to_container(inference_config.noise_scheduler_kwargs)))
motion_module_state_dict = torch.load(motion_module, map_location='cpu')
motion_module_state_dict = motion_module_state_dict['state_dict'] if 'state_dict' in motion_module_state_dict else motion_module_state_dict
try:
state_dict = OrderedDict()
for key in motion_module_state_dict.keys():
if key.startswith('module.'):
_key = key.split('module.')[-1]
state_dict[_key] = motion_module_state_dict[key]
else:
state_dict[key] = motion_module_state_dict[key]
motion_module_state_dict = state_dict
del state_dict
(missing, unexpected) = pipeline.unet.load_state_dict(motion_module_state_dict, strict=False)
assert len(unexpected) == 0
except:
_tmp_ = OrderedDict()
for key in motion_module_state_dict.keys():
if 'motion_modules' in key:
if key.startswith('unet.'):
_key = key.split('unet.')[-1]
_tmp_[_key] = motion_module_state_dict[key]
else:
_tmp_[key] = motion_module_state_dict[key]
(missing, unexpected) = unet.load_state_dict(_tmp_, strict=False)
assert len(unexpected) == 0
del _tmp_
del motion_module_state_dict
pipeline.to(device)
self.models['vae'] = vae
self.models['text_encoder'] = text_encoder
self.models['appearance_encoder'] = appearance_encoder
self.models['tokenizer'] = tokenizer
self.models['unet'] = unet
self.models['controlnet'] = controlnet
self.models['pipeline'] = pipeline
self.models['config'] = config
self.models['reference_control_writer'] = reference_control_writer
self.models['reference_control_reader'] = reference_control_reader
return (self.models,)
```