RuntimeError: The size of tensor a (2) must match the size of tensor b (4) at non-singleton dimension 1

在 InvokeAI 打补丁时,如果 LoHa 被作用到 Conv2d 层,而该 LoHa 的因子仍保留卷积形状(例如由 OneTrainer 生成的 [rank, in, kh, kw] 与 [out, rank, 1, 1] 组合),就会触发 RuntimeError: The size of

快速结论:在 InvokeAI 打补丁时,如果 LoHa 被作用到 Conv2d 层,而该 LoHa 的因子仍保留卷积形状(例如由 OneTrainer 生成的 [rank, in, kh, kw] 与 [out, rank, 1, 1] 组合),就会触发 RuntimeError: The size of tensor a (2) must match the size of tensor b (4) at non-singleton dimension 1。优先检查 LoHALayer.get_weight 的乘法是否对 4D 因子直接执行了 @。

适用环境:InvokeAI 手动 dev checkout(main 分支 0ddc9df91b);操作系统 Windows;问题与 GPU 无关,在 CPU 上同样可以复现。Issue 未给出 Python、PyTorch、CUDA 或显卡版本。

最快修复方案:暂无确认的一步修复方案(Issue 讨论中提出的 flatten 修复仍属于待合并的 fork 方案,未合入主线)。可优先尝试:在非 Tucker 路径中,对每个因子从第 1 维起展平,再按普通矩阵相乘,最后交由 get_parameters 还原为原 Conv2d 权重形状。

注意事项:该修复只针对非 Tucker 的 LoHa Conv2d 因子;Tucker 重建路径不应改动。已有 2D 线性 LoHa 因子展平后形状不变,理论上行为仍保持。上述方案来自个人 fork 的提议,合并前的实际验证需以原作者 PR 及 CI 结果为准。

问题场景

用户使用 InvokeAI dev checkout,加载由 OneTrainer 生成的 LoHa。LoHa 可正常安装与加载,但在生成阶段对包含 Conv2d 层的模型打补丁时失败。典型触发对象包括 SD1.x LoHa(即使只训练注意力层,因为 proj_in/proj_out 是 1×1 卷积)、训练了 ResNet 卷积的 SD2.x/SDXL LoHa,以及全层训练的 ERNIE-Image、SD3 的 patch-embedding 卷积。

报错原文

  File "invokeai/backend/patches/layers/loha_layer.py", line 80, in get_weight
    weight: torch.Tensor = (self.w1_a @ self.w1_b) * (self.w2_a @ self.w2_b)
RuntimeError: The size of tensor a (2) must match the size of tensor b (4) at non-singleton dimension 1

原因分析

最可能的原因:LoHALayer.get_weight 的非 Tucker 路径默认每个 LoHa 因子已经是二维矩阵,并直接使用 @ 相乘。OneTrainer 会保留卷积形状,把 hada_w*_b 存为 [rank, in, kh, kw]、hada_w*_a 存为 [out, rank, 1, 1]。对两个 4D 张量使用 @ 会走 PyTorch 的批量矩阵乘法语义,前导批次维不兼容,于是触发尺寸不匹配。LyCORIS 的非 Tucker 卷积因子已展平为 2D,因此不受影响。

环境排查

  • 确认 InvokeAI 版本/提交号,Issue 中为 main 的 0ddc9df91b。
  • 确认 LoHa 文件来源(如 OneTrainer)及其因子存储形状是否符合 [rank, in, kh, kw] / [out, rank, 1, 1]。
  • 确认触发层是否为 Conv2d(如 proj_in/proj_out、ResNet conv、patch-embedding conv)。
  • 确认是否为 Tucker 路径;本问题仅涉及非 Tucker 路径。
  • Issue 未提供 Python、PyTorch、CUDA、显卡型号或依赖版本,这些项目需自行核对。

解决步骤

  1. 用 Issue 给出的最小复现代码确认:构造 hada_w1_a 形状 [8, 2, 1, 1]、hada_w1_b 形状 [2, 4, 3, 3] 的 LoHa,并对 torch.zeros(8, 4, 3, 3) 权重调用 get_parameters,观察是否抛出上述 RuntimeError。
  2. 可优先尝试(来自讨论中 fork 的提议,尚未合入主线):在 LoHALayer.get_weight 的非 Tucker 路径中,将每个因子从第 1 维起展平,up 因子变为 [out, rank],down 因子变为 [rank, in × kh × kw]。
  3. 将两组因子按普通二维矩阵相乘,再执行原有的逐元素 LoHa 乘积。
  4. 保持 get_parameters 现有逻辑,把乘积结果 reshape 回原 Conv2d 权重形状 [out, in, kh, kw]。
  5. 不要修改 Tucker 重建路径;线性 LoHa 因展平后形状不变,行为应保持一致。
  6. 若不便修改代码,可先将 Conv2d 因子在 LoHa 文件中预先展平为 2D(类似 LyCORIS 的存储方式)作为临时规避;该做法 Issue 未验证,需自行测试。

验证方法

使用 Issue 中的 CPU 回归用例:对 [8, 2, 1, 1] 与 [2, 4, 3, 3] 因子的 LoHa,调用 get_parameters 后应得到形状为 [8, 4, 3, 3] 的权重且不再抛错,并可与手工计算的矩阵乘积结果做数值比对。随后重新加载原先失败的 LoHa 模型执行生成,确认打补丁阶段不再出现该 RuntimeError。讨论中提到回归测试与 Ruff 检查已通过,但以合并后的代码为准。

参考来源

invoke-ai/InvokeAI #10017

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 30669

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注