From f6999be3274892599d876ccf2c5bccd840947abd Mon Sep 17 00:00:00 2001 From: chenpipi0807 <144689950+chenpipi0807@users.noreply.github.com> Date: Wed, 30 Apr 2025 18:43:07 +0800 Subject: [PATCH 1/2] V1 I tried to integrate Hunyuan's LoRA into FramePack, and it seems to work. --- .gitignore | 358 +-- .../__pycache__/bucket_tools.cpython-311.pyc | Bin 0 -> 1356 bytes .../__pycache__/dit_common.cpython-311.pyc | Bin 0 -> 3231 bytes .../__pycache__/memory.cpython-311.pyc | Bin 0 -> 7863 bytes .../__pycache__/utils.cpython-311.pyc | Bin 0 -> 35601 bytes .../__pycache__/uni_pc_fm.cpython-311.pyc | Bin 0 -> 7038 bytes .../__pycache__/wrapper.cpython-311.pyc | Bin 0 -> 3075 bytes .../hunyuan_video_packed.cpython-311.pyc | Bin 0 -> 56902 bytes .../k_diffusion_hunyuan.cpython-311.pyc | Bin 0 -> 5008 bytes .../framepack-with-lora_hv_example.json | 2378 +++++++++++++++++ nodes.py | 653 ++++- 11 files changed, 3208 insertions(+), 181 deletions(-) create mode 100644 diffusers_helper/__pycache__/bucket_tools.cpython-311.pyc create mode 100644 diffusers_helper/__pycache__/dit_common.cpython-311.pyc create mode 100644 diffusers_helper/__pycache__/memory.cpython-311.pyc create mode 100644 diffusers_helper/__pycache__/utils.cpython-311.pyc create mode 100644 diffusers_helper/k_diffusion/__pycache__/uni_pc_fm.cpython-311.pyc create mode 100644 diffusers_helper/k_diffusion/__pycache__/wrapper.cpython-311.pyc create mode 100644 diffusers_helper/models/__pycache__/hunyuan_video_packed.cpython-311.pyc create mode 100644 diffusers_helper/pipelines/__pycache__/k_diffusion_hunyuan.cpython-311.pyc create mode 100644 example_workflows/framepack-with-lora_hv_example.json diff --git a/.gitignore b/.gitignore index e29ac43..d2a4293 100644 --- a/.gitignore +++ b/.gitignore @@ -1,179 +1,179 @@ -hf_download/ -outputs/ -repo/ - -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -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/ - -# Cython debug symbols -cython_debug/ - -# 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/ - -# Ruff stuff: -.ruff_cache/ - -# PyPI configuration file -.pypirc -demo_gradio.py \ No newline at end of file +# hf_download/ +# outputs/ +# repo/ + +# # Byte-compiled / optimized / DLL files +# __pycache__/ +# *.py[cod] +# *$py.class + +# # C extensions +# *.so + +# # Distribution / packaging +# .Python +# build/ +# develop-eggs/ +# dist/ +# downloads/ +# eggs/ +# .eggs/ +# 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/ + +# # Cython debug symbols +# cython_debug/ + +# # 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/ + +# # Ruff stuff: +# .ruff_cache/ + +# # PyPI configuration file +# .pypirc +# demo_gradio.py \ No newline at end of file diff --git a/diffusers_helper/__pycache__/bucket_tools.cpython-311.pyc b/diffusers_helper/__pycache__/bucket_tools.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8ca85152b6a7339cf5d36d0dc7a960a3e16621e GIT binary patch literal 1356 zcmb7DPly{;7=QCGnaym{PFpim-R-8hmk6%bD#|J~aqU7|t=dx5H9Af5CQV2(6W&Z% z8zzuL4>@>9LFhs&Lh0q=yzI#!Op>962JpgMi~9TY$42J_8zmvVD2VL3zrhm+-0W- zrl$xbc3Hv$MF3JhMfo8lz!{4Ba}53I0ps(xDc=eB+ms*rJdvr+$v~$M)N~l=OO&U+ zVXZS1pAN7{aWudx#Y%vwMG~ipDi*1;Fz7U`4-26G0NIekz|4O>u`>T8pT6K!*j;6zGnoB!q|hsA8w z_ee^BxfX1$g94Qy^(TEirEzEIP{My}YjY_qNzCf2Qx ze0h`P>-xv}V)av!Z!~n0!^s~ac^!<= z&%^oyQU^`sWUqOD>D#5w)$yrh=h`H-HbcDdil1C@sjK$hn#gB*pX{jjbN%c<{Qd*? zxmR8J!oGZ=8yQP-Z|jM)GLlxtXIHvc$1l9t|7`U9TKC#t2T{3q^GQ@4Mb)u#zJJ+O z(%r?0y1Y{zoPT5t9QWMYdj`2TWNXZeOJcO;H z>uJWnWoeeILg^pGE+TJGd=b)9@twMfn>GCsc@s){@ho~+Gmc@H8GGUsJ40dWBxb88 M8D)n4Bl)U-168F|-~a#s literal 0 HcmV?d00001 diff --git a/diffusers_helper/__pycache__/dit_common.cpython-311.pyc b/diffusers_helper/__pycache__/dit_common.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..26b87e39e65a0f5ed9f0967cdbb28a34adf7cfcf GIT binary patch literal 3231 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 literal 0 HcmV?d00001 diff --git a/diffusers_helper/__pycache__/utils.cpython-311.pyc b/diffusers_helper/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd208fb48992d44249e988c545fb0f5f92698aaa GIT binary patch literal 35601 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 literal 0 HcmV?d00001 diff --git a/diffusers_helper/k_diffusion/__pycache__/uni_pc_fm.cpython-311.pyc b/diffusers_helper/k_diffusion/__pycache__/uni_pc_fm.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f7317e03388975056ac486d6ef8529f4a3b5b08 GIT binary patch literal 7038 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 2 else target_key_simple + + up_down_pairs[target_key_simple] = (lora_key, down_key) + if target_key_simple != target_key_compound: + up_down_pairs[target_key_compound] = (lora_key, down_key) + total_pairs += 1 + + elif lora_format == "kohya": + # Kohya格式: key.weight/key.alpha + weights = {} + alphas = {} + + for k in lora_sd.keys(): + if ".weight" in k and not ".alpha" in k: + weights[k.replace(".weight", "")] = k + elif ".alpha" in k: + alphas[k.replace(".alpha", "")] = k + + for base in weights.keys(): + if base in alphas: + up_key = weights[base] + alpha_key = alphas[base] + # 在Kohya格式中,同一个key包含了up和down权重 + target_key_simple = base.split(".")[-1] + target_key_compound = '.'.join(base.split(".")[-2:]) if len(base.split(".")) >= 2 else target_key_simple + + # 存储(up键, down键)tuple,在Kohya格式中下两个值相同 + up_down_pairs[target_key_simple] = (up_key, up_key) + if target_key_simple != target_key_compound: + up_down_pairs[target_key_compound] = (up_key, up_key) + total_pairs += 1 + + elif lora_format == "diffusers": + # Diffusers格式: key_lora_a.weight/key_lora_b.weight + for lora_key in lora_sd.keys(): + if "_lora_a.weight" in lora_key: + base_key = lora_key.replace("_lora_a.weight", "") + down_key = base_key + "_lora_b.weight" + + if down_key in lora_sd: + target_key_simple = base_key.split(".")[-1] + target_key_compound = '.'.join(base_key.split(".")[-2:]) if len(base_key.split(".")) >= 2 else target_key_simple + + up_down_pairs[target_key_simple] = (lora_key, down_key) + if target_key_simple != target_key_compound: + up_down_pairs[target_key_compound] = (lora_key, down_key) + total_pairs += 1 + elif lora_format == "lycoris": + # LyCORIS格式: key.lora_A.weight/key.lora_B.weight + for lora_key in lora_sd.keys(): + if ".lora_A.weight" in lora_key: + base_key = lora_key.replace(".lora_A.weight", "") + down_key = base_key + ".lora_B.weight" + + if down_key in lora_sd: + # 尝试多种提取目标键的方式 + parts = base_key.split(".") + + # 尝试提取目标模块名 + target_keys = [] + # 1. 只取最后一部分(例如img_mlp.fc1的fc1) + target_keys.append(parts[-1]) + # 2. 取最后两部分(例如img_mlp.fc1) + if len(parts) >= 2: + target_keys.append(f"{parts[-2]}.{parts[-1]}") + # 3. 也可能是分开的两部分 + target_keys.append(parts[-2]) + # 4. 如果是double_blocks或single_transformer_blocks格式,取出相关部分 + if "double_blocks" in base_key or "transformer_blocks" in base_key or "single_transformer_blocks" in base_key: + for i in range(len(parts)): + if parts[i] in ["double_blocks", "transformer_blocks", "single_transformer_blocks"] and i+2 < len(parts): + # 尝试用block_idx.module_name格式 + target_keys.append(f"{parts[i+1]}.{parts[i+2]}") + # 单独的模块名 + target_keys.append(parts[i+2]) + + # 将所有可能的目标键添加到字典 + for key in set(target_keys): # 使用set去除重复 + up_down_pairs[key] = (lora_key, down_key) + + total_pairs += 1 + else: + # 尝试直接匹配模型的权重键 + print("未知LoRA格式,尝试直接匹配...") + for key in lora_sd.keys(): + if ".weight" in key: + base_key = key.replace(".weight", "") + # 提取多种可能的目标键 + parts = base_key.split(".") + if len(parts) > 0: + target_key_simple = parts[-1] + up_down_pairs[target_key_simple] = (key, key) # 同一个键作为up和down + # 如果有两部分以上,尝试当做复合名称 + if len(parts) >= 2: + target_key_compound = f"{parts[-2]}.{parts[-1]}" + up_down_pairs[target_key_compound] = (key, key) + total_pairs += 1 + + print(f"找到 {len(up_down_pairs)} 个有效的LoRA up-down对") + + # 收集模型中的所有可能目标 + model_module_names = set() + model_module_paths = {} + + def collect_module_names(module, name_prefix=""): + for name, child in module.named_children(): + full_name = name_prefix + "." + name if name_prefix else name + + # 添加各种可能的模块名称形式 + model_module_names.add(name) # 简单名称 + model_module_paths[name] = full_name # 记录完整路径 + + # 复合名称 (例如: parent.child) + if len(name_prefix.split(".")) > 0: + parent = name_prefix.split(".")[-1] + compound_name = f"{parent}.{name}" + model_module_names.add(compound_name) + model_module_paths[compound_name] = full_name + + # 如果是transformer块,添加特殊匹配 + if ("double_blocks" in name_prefix or "transformer_blocks" in name_prefix or + "single_transformer_blocks" in name_prefix): + # 提取块索引 + parts = name_prefix.split(".") + for i, part in enumerate(parts): + if part in ["double_blocks", "transformer_blocks", "single_transformer_blocks"] and i+1 < len(parts): + block_idx = parts[i+1] + # 块索引.module格式 + block_module = f"{block_idx}.{name}" + model_module_names.add(block_module) + model_module_paths[block_module] = full_name + + # 递归处理子模块 + collect_module_names(child, full_name) + + collect_module_names(transformer) + print(f"模型中有 {len(model_module_names)} 个可能的模块名称") + print(f"模型模块示例: {', '.join(sorted(list(model_module_names))[:5])}{'...' if len(model_module_names) > 5 else ''}") + + # 查找LoRA键与模型模块名称的交集 + common_keys = set(up_down_pairs.keys()).intersection(model_module_names) + print(f"找到 {len(common_keys)} 个可能匹配的模块名称") + if common_keys: + print(f"匹配的模块名称: {', '.join(sorted(list(common_keys))[:5])}{'...' if len(common_keys) > 5 else ''}") + + # 打印LoRA中的一些键来帮助诊断 + print(f"未匹配的LoRA键的示例: {', '.join(list(up_down_pairs.keys())[:5])}") + + # 如果没有匹配,尝试更宽松的匹配方式 + if len(common_keys) == 0 and lora_format == "lycoris": + print("没有找到精确匹配,尝试部分字符串匹配...") + # 创建一个映射来存储模糊匹配 + fuzzy_matches = {} + + for lora_key in up_down_pairs.keys(): + best_match = None + best_score = 0 + + for model_key in model_module_names: + # 基本匹配: 如果一个是另一个的子字符串 + if lora_key in model_key or model_key in lora_key: + score = len(set(lora_key).intersection(set(model_key))) + if score > best_score: + best_score = score + best_match = model_key + + if best_match and best_score > len(lora_key) / 2: # 至少半数字符匹配 + fuzzy_matches[lora_key] = best_match + + if fuzzy_matches: + print(f"模糊匹配到 {len(fuzzy_matches)} 个可能的模块") + for lora_key, model_key in list(fuzzy_matches.items())[:5]: + print(f" LoRA键: '{lora_key}' 匹配到模型模块: '{model_key}'") + + # 将模糊匹配添加到common_keys + for lora_key, model_key in fuzzy_matches.items(): + common_keys.add(model_key) + + # 递归遍历模型的所有参数 + applied_modules = set() # 记录已经应用过LoRA的模块路径 + + # 查找直接匹配的模块路径,获取直接的参数引用 + for model_key in common_keys: + if model_key in model_module_paths: + full_path = model_module_paths[model_key] + parts = full_path.split('.') + + # 试图获取指定路径的模块 + current = transformer + for part in parts: + if hasattr(current, part): + current = getattr(current, part) + else: + current = None + break + + if current is not None and hasattr(current, 'weight'): + # 直接获得了模块,并且有weight参数 + param = current.weight + up_key, down_key = up_down_pairs[model_key] + up_weight = lora_sd[up_key] + down_weight = lora_sd[down_key] + + # 当使用LyCORIS格式时,需要尝试不同的矩阵计算 + try: + if lora_format == "lycoris": + # LyCORIS格式通常的A/B矩阵需要特殊处理 + print(f"LyCORIS格式: 尝试应用到 {full_path}.weight") + print(f" 参数形状: {param.shape}, A形状: {up_weight.shape}, B形状: {down_weight.shape}") + + # 由于LoRA格式变化,尝试多种矩阵乘法 + delta = None + + # 1. 尝试标准LoRA方式:B x A + if down_weight.shape[1] == up_weight.shape[0]: + delta = torch.mm(down_weight, up_weight) * lora_strength + print(" 使用标准LoRA矩阵乘法: B x A") + + # 2. 尝试反转方式:A x B + elif up_weight.shape[1] == down_weight.shape[0]: + delta = torch.mm(up_weight, down_weight) * lora_strength + print(" 使用反转矩阵乘法: A x B") + + # 3. 尝试转置矩阵 + elif up_weight.shape[0] == down_weight.shape[0]: + delta = torch.mm(up_weight.t(), down_weight) * lora_strength + print(" 使用转置矩阵乘法: A^T x B") + elif up_weight.shape[1] == down_weight.shape[1]: + delta = torch.mm(up_weight, down_weight.t()) * lora_strength + print(" 使用转置矩阵乘法: A x B^T") + + if delta is not None: + print(f" 计算得到delta形状: {delta.shape}") + # 如果形状直接匹配 + if delta.shape == param.shape: + param.data += delta + matched_count += 1 + applied_modules.add(full_path) + print(f" 直接应用LoRA到 {full_path}.weight") + # 尝试reshape + else: + try: + delta_reshaped = delta.reshape(param.shape) + param.data += delta_reshaped + matched_count += 1 + applied_modules.add(full_path) + print(f" 通过reshape成功应用LoRA到 {full_path}.weight") + except Exception as e: + print(f" 无法reshape到参数形状: {str(e)}") + else: + # 其他LoRA格式的标准处理 + if up_weight.shape[0] == param.shape[0] and down_weight.shape[1] == param.shape[1]: + delta = torch.mm(up_weight, down_weight) * lora_strength + param.data += delta + matched_count += 1 + applied_modules.add(full_path) + print(f"成功应用LoRA到 {full_path}.weight") + except Exception as e: + print(f"应用LoRA到 {full_path}.weight 时出错: {str(e)}") + + # 如果上面的直接方法没有匹配到足够数量的参数,则使用递归遍历方法 + if matched_count < min(10, len(common_keys)): + print("直接路径方法匹配数量较少,尝试递归遍历方法...") + + def apply_lora_to_module(module, name_prefix=""): + nonlocal matched_count + + # 如果当前模块路径已经应用过LoRA,则跳过 + if name_prefix in applied_modules: + return + + for name, child in module.named_children(): + full_name = name_prefix + "." + name if name_prefix else name + apply_lora_to_module(child, full_name) + + for param_name, param in module.named_parameters(recurse=False): + if param_name != "weight": + continue + + # 生成各种可能的模块名称匹配 + module_name = name_prefix.split(".")[-1] if name_prefix else "" + compound_name = '.'.join(name_prefix.split(".")[-2:]) if len(name_prefix.split(".")) >= 2 else module_name + + # 如果在transformer块中,尝试取块索引 + block_idx = None + for i, part in enumerate(name_prefix.split(".")): + if part in ["double_blocks", "transformer_blocks", "single_transformer_blocks"] and i+1 < len(name_prefix.split(".")): + block_idx = name_prefix.split(".")[i+1] + break + + block_module = f"{block_idx}.{module_name}" if block_idx else None + + # 尝试不同的匹配方式 + target_key = None + if module_name in common_keys: + target_key = module_name + elif compound_name in common_keys: + target_key = compound_name + elif block_module and block_module in common_keys: + target_key = block_module + + if target_key: + up_key, down_key = up_down_pairs[target_key] + up_weight = lora_sd[up_key] + down_weight = lora_sd[down_key] + + # 尝试不同的矩阵计算方式 + try: + if lora_format == "lycoris": + # 尝试多种矩阵乘法 + delta = None + + # 1. 标准方式 + if down_weight.shape[1] == up_weight.shape[0]: + delta = torch.mm(down_weight, up_weight) * lora_strength + # 2. 反转方式 + elif up_weight.shape[1] == down_weight.shape[0]: + delta = torch.mm(up_weight, down_weight) * lora_strength + # 3. 转置矩阵 + elif up_weight.shape[0] == down_weight.shape[0]: + delta = torch.mm(up_weight.t(), down_weight) * lora_strength + elif up_weight.shape[1] == down_weight.shape[1]: + delta = torch.mm(up_weight, down_weight.t()) * lora_strength + + if delta is not None: + # 如果形状匹配 + if delta.shape == param.shape: + param.data += delta + matched_count += 1 + print(f"成功应用LoRA到 {name_prefix}.{param_name} (匹配键: {target_key})") + # 尝试reshape + else: + try: + delta_reshaped = delta.reshape(param.shape) + param.data += delta_reshaped + matched_count += 1 + print(f"通过reshape成功应用LoRA到 {name_prefix}.{param_name}") + except: + print(f"形状不匹配: {name_prefix}.{param_name} (匹配键: {target_key})") + print(f" 参数形状: {param.shape}, delta形状: {delta.shape}") + else: + # 其他LoRA格式的标准处理 + if up_weight.shape[0] == param.shape[0] and down_weight.shape[1] == param.shape[1]: + delta = torch.mm(up_weight, down_weight) * lora_strength + param.data += delta + matched_count += 1 + print(f"成功应用LoRA到 {name_prefix}.{param_name} (匹配键: {target_key})") + else: + print(f"形状不匹配: {name_prefix}.{param_name} (匹配键: {target_key})") + print(f" 参数形状: {param.shape}, up形状: {up_weight.shape}, down形状: {down_weight.shape}") + except Exception as e: + print(f"应用LoRA到 {name_prefix}.{param_name} 时出错: {str(e)}") + + # 开始递归应用 + apply_lora_to_module(transformer) + + print(f"成功应用了 {matched_count}/{total_pairs} 个LoRA权重对") + return transformer + script_directory = os.path.dirname(os.path.abspath(__file__)) vae_scaling_factor = 0.476986 @@ -101,6 +533,7 @@ def INPUT_TYPES(s): "sageattn", ], {"default": "sdpa"}), "compile_args": ("FRAMEPACKCOMPILEARGS", ), + "lora": ("FRAMEPACKLORA", {"default": None}), } } @@ -110,11 +543,12 @@ def INPUT_TYPES(s): CATEGORY = "FramePackWrapper" def loadmodel(self, model, base_precision, quantization, - compile_args=None, attention_mode="sdpa"): + compile_args=None, attention_mode="sdpa", lora=None): base_dtype = {"fp8_e4m3fn": torch.float8_e4m3fn, "fp8_e4m3fn_fast": torch.float8_e4m3fn, "bf16": torch.bfloat16, "fp16": torch.float16, "fp16_fast": torch.float16, "fp32": torch.float32}[base_precision] device = mm.get_torch_device() + offload_device = mm.unet_offload_device() model_path = os.path.join(folder_paths.models_dir, "diffusers", "lllyasviel", "FramePackI2V_HY") if not os.path.exists(model_path): @@ -127,6 +561,30 @@ def loadmodel(self, model, base_precision, quantization, ) transformer = HunyuanVideoTransformer3DModelPacked.from_pretrained(model_path, torch_dtype=base_dtype, attention_mode=attention_mode).cpu() + + # 创建一个ModelPatcher用于应用LoRA + from comfy import model_patcher + comfy_model = model_patcher.ModelPatcher(transformer, device, offload_device) + + # 加载LoRA + if lora is not None: + from comfy.sd import load_lora_for_models + for l in lora: + print(f"Loading LoRA: {l['name']} with strength: {l['strength']}") + lora_path = l["path"] + lora_strength = l["strength"] + lora_sd = load_torch_file(lora_path, safe_load=True) + lora_sd = standardize_lora_key_format(lora_sd) + + if l["blocks"]: + lora_sd = filter_state_dict_by_blocks(lora_sd, l["blocks"]) + + comfy_model, _ = load_lora_for_models(comfy_model, None, lora_sd, lora_strength, 0) + + # 恢复使用transformer对象 + transformer = comfy_model.model + comfy.model_management.load_models_gpu([comfy_model]) + params_to_keep = {"norm", "bias", "time_in", "vector_in", "guidance_in", "txt_in", "img_in"} if quantization == 'fp8_e4m3fn' or quantization == 'fp8_e4m3fn_fast': transformer = transformer.to(torch.float8_e4m3fn) @@ -173,6 +631,7 @@ def INPUT_TYPES(s): "sageattn", ], {"default": "sdpa"}), "compile_args": ("FRAMEPACKCOMPILEARGS", ), + "lora": ("FRAMEPACKLORA", {"default": None}), } } @@ -182,7 +641,7 @@ def INPUT_TYPES(s): CATEGORY = "FramePackWrapper" def loadmodel(self, model, base_precision, quantization, - compile_args=None, attention_mode="sdpa"): + compile_args=None, attention_mode="sdpa", lora=None): base_dtype = {"fp8_e4m3fn": torch.float8_e4m3fn, "fp8_e4m3fn_fast": torch.float8_e4m3fn, "bf16": torch.bfloat16, "fp16": torch.float16, "fp16_fast": torch.float16, "fp32": torch.float32}[base_precision] @@ -216,6 +675,29 @@ def loadmodel(self, model, base_precision, quantization, set_module_tensor_to_device(transformer, name, device=offload_device, dtype=dtype_to_use, value=sd[name]) + # 创建一个ModelPatcher用于应用LoRA + from comfy import model_patcher + comfy_model = model_patcher.ModelPatcher(transformer, device, offload_device) + + # 加载LoRA + if lora is not None: + from comfy.sd import load_lora_for_models + for l in lora: + print(f"Loading LoRA: {l['name']} with strength: {l['strength']}") + lora_path = l["path"] + lora_strength = l["strength"] + lora_sd = load_torch_file(lora_path, safe_load=True) + lora_sd = standardize_lora_key_format(lora_sd) + + if l["blocks"]: + lora_sd = filter_state_dict_by_blocks(lora_sd, l["blocks"]) + + comfy_model, _ = load_lora_for_models(comfy_model, None, lora_sd, lora_strength, 0) + + # 恢复使用transformer对象 + transformer = comfy_model.model + comfy.model_management.load_models_gpu([comfy_model]) + if quantization == "fp8_e4m3fn_fast": from .fp8_optimization import convert_fp8_linear convert_fp8_linear(transformer, base_dtype, params_to_keep=params_to_keep) @@ -239,6 +721,104 @@ def loadmodel(self, model, base_precision, quantization, } return (pipe, ) +class LoadFramePackModelWithLoRA: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "model": (folder_paths.get_filename_list("diffusion_models"), {"tooltip": "These models are loaded from the 'ComfyUI/models/diffusion_models' -folder",}), + + "base_precision": (["fp32", "bf16", "fp16"], {"default": "bf16"}), + "quantization": (['disabled', 'fp8_e4m3fn', 'fp8_e4m3fn_fast', 'fp8_e5m2'], {"default": 'disabled', "tooltip": "optional quantization method"}), + }, + "optional": { + "attention_mode": ([ + "sdpa", + "flash_attn", + "sageattn", + ], {"default": "sdpa"}), + "compile_args": ("FRAMEPACKCOMPILEARGS", ), + "lora": ("FRAMEPACKLORA", {"default": None}), + } + } + + RETURN_TYPES = ("FramePackMODEL",) + RETURN_NAMES = ("model", ) + FUNCTION = "loadmodel" + CATEGORY = "FramePackWrapper" + DESCRIPTION = "加载FramePack模型并使用手动方法应用LoRA" + + def loadmodel(self, model, base_precision, quantization, + compile_args=None, attention_mode="sdpa", lora=None): + + base_dtype = {"fp8_e4m3fn": torch.float8_e4m3fn, "fp8_e4m3fn_fast": torch.float8_e4m3fn, "bf16": torch.bfloat16, "fp16": torch.float16, "fp16_fast": torch.float16, "fp32": torch.float32}[base_precision] + + device = mm.get_torch_device() + offload_device = mm.unet_offload_device() + + model_path = folder_paths.get_full_path_or_raise("diffusion_models", model) + model_config_path = os.path.join(script_directory, "transformer_config.json") + import json + with open(model_config_path, "r") as f: + config = json.load(f) + sd = load_torch_file(model_path, device=offload_device, safe_load=True) + + with init_empty_weights(): + transformer = HunyuanVideoTransformer3DModelPacked(**config, attention_mode=attention_mode) + + params_to_keep = {"norm", "bias", "time_in", "vector_in", "guidance_in", "txt_in", "img_in"} + if quantization == "fp8_e4m3fn" or quantization == "fp8_e4m3fn_fast" or quantization == "fp8_scaled": + dtype = torch.float8_e4m3fn + elif quantization == "fp8_e5m2": + dtype = torch.float8_e5m2 + else: + dtype = base_dtype + print("Using accelerate to load and assign model weights to device...") + param_count = sum(1 for _ in transformer.named_parameters()) + for name, param in tqdm(transformer.named_parameters(), + desc=f"Loading transformer parameters to {offload_device}", + total=param_count, + leave=True): + dtype_to_use = base_dtype if any(keyword in name for keyword in params_to_keep) else dtype + + set_module_tensor_to_device(transformer, name, device=offload_device, dtype=dtype_to_use, value=sd[name]) + + # 使用手动方法应用LoRA,避免使用ModelPatcher + if lora is not None: + for l in lora: + print(f"Loading LoRA: {l['name']} with strength: {l['strength']}") + lora_path = l["path"] + lora_strength = l["strength"] + lora_sd = load_torch_file(lora_path, safe_load=True) + lora_sd = standardize_lora_key_format(lora_sd) + + if l["blocks"]: + lora_sd = filter_state_dict_by_blocks(lora_sd, l["blocks"]) + + # 使用我们的自定义函数手动应用LoRA + transformer = apply_lora_weights_manually(transformer, lora_sd, lora_strength) + + if quantization == "fp8_e4m3fn_fast": + from .fp8_optimization import convert_fp8_linear + convert_fp8_linear(transformer, base_dtype, params_to_keep=params_to_keep) + + + DynamicSwapInstaller.install_model(transformer, device=device) + + if compile_args is not None: + if compile_args["compile_single_blocks"]: + for i, block in enumerate(transformer.single_transformer_blocks): + transformer.single_transformer_blocks[i] = torch.compile(block, fullgraph=compile_args["fullgraph"], dynamic=compile_args["dynamic"], backend=compile_args["backend"], mode=compile_args["mode"]) + if compile_args["compile_double_blocks"]: + for i, block in enumerate(transformer.transformer_blocks): + transformer.transformer_blocks[i] = torch.compile(block, fullgraph=compile_args["fullgraph"], dynamic=compile_args["dynamic"], backend=compile_args["backend"], mode=compile_args["mode"]) + + pipe = { + "transformer": transformer.eval(), + "dtype": base_dtype, + } + return (pipe, ) + class FramePackFindNearestBucket: @classmethod def INPUT_TYPES(s): @@ -493,6 +1073,69 @@ def process(self, model, shift, positive, negative, latent_window_size, use_teac mm.soft_empty_cache() return {"samples": real_history_latents / vae_scaling_factor}, +class FramePackLoraBlockEdit: + def __init__(self): + self.loaded_lora = None + + @classmethod + def INPUT_TYPES(s): + arg_dict = {} + argument = ("BOOLEAN", {"default": True}) + + for i in range(20): + arg_dict[f"transformer_blocks.{i}."] = argument + + for i in range(40): + arg_dict[f"single_transformer_blocks.{i}."] = argument + + return {"required": arg_dict} + + RETURN_TYPES = ("SELECTEDBLOCKS", ) + RETURN_NAMES = ("blocks", ) + FUNCTION = "select" + CATEGORY = "FramePackWrapper" + DESCRIPTION = "选择要应用LoRA的模型块" + + def select(self, **kwargs): + selected_blocks = {k: v for k, v in kwargs.items() if v is True} + print("Selected blocks: ", selected_blocks) + return (selected_blocks,) + +class FramePackLoraSelect: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "lora": (folder_paths.get_filename_list("loras"), + {"tooltip": "LORA模型应位于ComfyUI/models/loras目录,扩展名为.safetensors"}), + "strength": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.0001, "tooltip": "LoRA的强度,设置为0可卸载LoRA"}), + }, + "optional": { + "prev_lora":("FRAMEPACKLORA", {"default": None, "tooltip": "用于加载多个LoRA"}), + "blocks":("SELECTEDBLOCKS", ), + } + } + + RETURN_TYPES = ("FRAMEPACKLORA",) + RETURN_NAMES = ("lora", ) + FUNCTION = "getlorapath" + CATEGORY = "FramePackWrapper" + DESCRIPTION = "从ComfyUI/models/loras选择LoRA模型" + + def getlorapath(self, lora, strength, blocks=None, prev_lora=None): + loras_list = [] + + lora = { + "path": folder_paths.get_full_path("loras", lora), + "strength": strength, + "name": lora.split(".")[0], + "blocks": blocks + } + if prev_lora is not None: + loras_list.extend(prev_lora) + + loras_list.append(lora) + return (loras_list,) NODE_CLASS_MAPPINGS = { "DownloadAndLoadFramePackModel": DownloadAndLoadFramePackModel, @@ -500,6 +1143,9 @@ def process(self, model, shift, positive, negative, latent_window_size, use_teac "FramePackTorchCompileSettings": FramePackTorchCompileSettings, "FramePackFindNearestBucket": FramePackFindNearestBucket, "LoadFramePackModel": LoadFramePackModel, + "FramePackLoraBlockEdit": FramePackLoraBlockEdit, + "FramePackLoraSelect": FramePackLoraSelect, + "LoadFramePackModelWithLoRA": LoadFramePackModelWithLoRA, } NODE_DISPLAY_NAME_MAPPINGS = { "DownloadAndLoadFramePackModel": "(Down)Load FramePackModel", @@ -507,5 +1153,8 @@ def process(self, model, shift, positive, negative, latent_window_size, use_teac "FramePackTorchCompileSettings": "Torch Compile Settings", "FramePackFindNearestBucket": "Find Nearest Bucket", "LoadFramePackModel": "Load FramePackModel", + "FramePackLoraBlockEdit": "FramePack LoRA Block Edit", + "FramePackLoraSelect": "FramePack LoRA Select", + "LoadFramePackModelWithLoRA": "Load FramePackModel With LoRA", } From 87cb8a96ebbfdc4f2126163472261848455f1c01 Mon Sep 17 00:00:00 2001 From: chenpipi0807 <144689950+chenpipi0807@users.noreply.github.com> Date: Wed, 30 Apr 2025 18:46:59 +0800 Subject: [PATCH 2/2] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index c739ce3..3d49ae4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ # ComfyUI Wrapper for [FramePack by lllyasviel](https://lllyasviel.github.io/frame_pack_gitpage/) +# What have I modified? + +![微信截图_20250430184400](https://github.com/user-attachments/assets/94e7ed1d-109d-410f-927d-67092f21d918) + +I tried to add Hunyuan LoRA to it. Currently, most of the keys are matched correctly, but I'm not sure if it's really effective. I hope this is a start to attract more valuable opinions. +You can find the example workflow at \example_workflows\framepack-with-lora_hv_example.json + # WORK IN PROGRESS Mostly working, took some liberties to make it run faster.