Files
Dontdrunk-ComfyUI-DD-Nodes/node/model_optimizer.py
T

244 lines
9.6 KiB
Python

import torch
import folder_paths
import comfy.sd
import comfy.utils
import comfy.model_management as model_management
import sys
import gc
import psutil
from datetime import datetime
import time
from pathlib import Path
class DDModelOptimizer:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"模型文件": (folder_paths.get_filename_list("diffusion_models"), ),
"智能模式": ("BOOLEAN", {"default": False}),
"加载模式": ([
"标准加载",
"分步加载",
],),
"优化模式": ([
"禁用优化", # 改为更直观的名称
"FP8基础内存优化", # fp8_e4m3fn
"FP8高速性能优化", # fp8_e4m3fn_fast
"FP8稳定质量优化" # fp8_e5m2
],),
}
}
RETURN_TYPES = ("MODEL",)
RETURN_NAMES = ("优化模型",)
FUNCTION = "optimize_model"
CATEGORY = "🍺DD系列节点"
def get_system_info(self):
"""获取系统配置信息"""
system_info = {
"total_memory": psutil.virtual_memory().total / (1024**3), # GB
"available_memory": psutil.virtual_memory().available / (1024**3), # GB
"cpu_count": psutil.cpu_count(logical=False),
"gpu_info": None,
}
if torch.cuda.is_available():
system_info["gpu_info"] = {
"name": torch.cuda.get_device_name(),
"total_memory": torch.cuda.get_device_properties(0).total_memory / (1024**3), # GB
"free_memory": torch.cuda.memory_allocated(0) / (1024**3), # GB
}
return system_info
def determine_smart_options(self, system_info, model_path):
"""根据系统配置和模型智能确定最佳选项
Args:
system_info: 系统信息
model_path: 模型路径
"""
try:
# 将字符串路径转换为Path对象
path_obj = Path(model_path)
# 安全获取文件大小
if path_obj.exists():
model_size = path_obj.stat().st_size / (1024**3) # GB
print(f"\n模型文件大小: {model_size:.2f}GB")
else:
print(f"警告: 模型文件不存在: {model_path}")
model_size = 0
except Exception as e:
print(f"警告: 无法获取模型文件信息: {str(e)}")
model_size = 0
options = {
"加载模式": "标准加载",
"优化模式": "禁用优化"
}
# 获取显存和内存信息
vram = 0
ram = system_info["total_memory"]
if system_info["gpu_info"]:
vram = system_info["gpu_info"]["total_memory"]
print(f"GPU总显存: {vram:.2f}GB")
print(f"系统总内存: {ram:.2f}GB")
# 设置缓冲系数
vram_scale_factor = 1.5
ram_scale_factor = 1.5
# 决定加载模式
# 如果模型大小大于可用显存的70%或大于显存总量,使用分步加载
if model_size > vram * 0.7:
options["加载模式"] = "分步加载"
print("由于模型大小超过可用显存的70%,选择分步加载模式")
# 应用新的优化规则
if model_size <= vram:
options["优化模式"] = "禁用优化"
print("模型完全适配显存,获得最佳质量")
elif model_size <= vram * vram_scale_factor and model_size <= ram:
options["优化模式"] = "禁用优化"
print("模型可通过显存+虚拟内存加载,保持最佳质量")
elif model_size > vram * vram_scale_factor and model_size <= ram:
options["优化模式"] = "FP8稳定质量优化"
print("模型显著超出显存但适配内存,启动质量优先优化")
elif model_size > ram and model_size <= ram * ram_scale_factor:
options["优化模式"] = "FP8基础内存优化"
print("模型超出物理内存,启动内存优化")
else: # model_size > ram * ram_scale_factor
options["优化模式"] = "FP8高速性能优化"
print("模型严重超出物理内存,启动性能优先优化")
return options
def show_step_progress(self, step_name, progress=0):
"""显示步骤进度
Args:
step_name: 步骤名称
progress: 进度值(0-100)
"""
bar_width = 30
filled = int(bar_width * progress / 100)
bar = '#' * filled + '-' * (bar_width - filled)
sys.stdout.write(f'\r{step_name} [{bar}] {progress}%')
sys.stdout.flush()
if progress >= 100:
print()
def optimize_model(self, 模型文件, 智能模式, 加载模式, 优化模式):
"""
模型优化加载主函数
Args:
模型文件: 要加载的模型文件名
智能模式: 是否启用智能模式
加载模式: 标准加载或分步加载
优化模式: 禁用优化/FP8基础内存优化/FP8高速性能优化/FP8稳定质量优化
Returns:
优化后的模型
"""
start_time = time.time()
print(f"\n开始处理模型: {模型文件}")
print(f"处理时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
try:
# 获取模型路径
model_path = folder_paths.get_full_path_or_raise("diffusion_models", 模型文件)
# 如果启用智能模式,重新确定加载模式和优化模式
if 智能模式:
system_info = self.get_system_info()
smart_options = self.determine_smart_options(system_info, model_path)
加载模式 = smart_options["加载模式"]
优化模式 = smart_options["优化模式"]
print("\n智能模式已启用:")
print(f"系统配置: {'GPU: ' + system_info['gpu_info']['name'] if system_info['gpu_info'] else 'CPU'}")
print(f"自动选择 - 加载模式: {加载模式}")
print(f"自动选择 - 优化模式: {优化模式}")
# 设置优化选项
model_options = {}
needs_optimization = True # 是否需要进行优化处理
if 优化模式 == "FP8基础内存优化":
print("使用 FP8 基础内存优化模式")
model_options["dtype"] = torch.float8_e4m3fn
elif 优化模式 == "FP8高速性能优化":
print("使用 FP8 高速性能优化模式")
model_options["dtype"] = torch.float8_e4m3fn
model_options["fp8_optimizations"] = True
elif 优化模式 == "FP8稳定质量优化":
print("使用 FP8 稳定质量优化模式")
model_options["dtype"] = torch.float8_e5m2
else:
print("优化已禁用,使用原始加载模式")
needs_optimization = False
if 加载模式 == "标准加载":
print("使用标准加载模式...")
self.show_step_progress("加载模型", 0)
model = comfy.sd.load_diffusion_model(model_path, model_options=model_options)
self.show_step_progress("加载模型", 100)
else:
print("使用分步加载模式...")
# 第一步:加载模型文件
print("步骤1: 加载模型文件")
self.show_step_progress("加载文件", 0)
state_dict = comfy.utils.load_torch_file(model_path)
self.show_step_progress("加载文件", 100)
# 第二步:预处理权重
print("\n步骤2: 预处理权重")
total_keys = len(state_dict)
processed = 0
update_interval = max(1, total_keys // 100) # 确保至少显示100个更新点
if needs_optimization: # 只在需要优化时进行处理
for key, value in state_dict.items():
if torch.is_tensor(value):
state_dict[key] = value.to(model_options["dtype"])
processed += 1
if processed % update_interval == 0:
progress = int(processed / total_keys * 100)
self.show_step_progress("处理权重", progress)
self.show_step_progress("处理权重", 100)
# 第三步:创建模型
print("\n步骤3: 构建模型")
self.show_step_progress("构建模型", 0)
model = comfy.sd.load_diffusion_model_state_dict(state_dict, model_options)
self.show_step_progress("构建模型", 100)
# 清理内存
gc.collect()
if torch.cuda.is_available():
torch.cuda.empty_cache()
end_time = time.time()
duration = end_time - start_time
print(f"\n模型加载完成!用时: {duration:.2f}秒")
return (model,)
except Exception as e:
print(f"\n模型加载失败: {str(e)}")
raise e
NODE_CLASS_MAPPINGS = {
"DD-ModelOptimizer": DDModelOptimizer
}
NODE_DISPLAY_NAME_MAPPINGS = {
"DD-ModelOptimizer": "DD Model Optimizer"
}