【Bug已解决】FSDP2 fails due to KeyError: ‘lm_head.weight‘ 解决方案

发布时间:2026/9/21 18:38:25

【Bug已解决】FSDP2 fails due to KeyError: ‘lm_head.weight‘ 解决方案 【Bug已解决】FSDP2 fails due to KeyError lm_head.weight 解决方案一、现象长什么样用 FSDP2 训练一个tie_word_embeddingsTrue的模型即lm_head.weight与model.embed_tokens.weight共享在fully_shard或加载 / 分片阶段直接抛KeyError lm_head.weight最小判据触发FSDP2 模型 tie_word_embeddingsTruelm_head 与 embed 共享 现象fully_shard / 分片计划找不到 lm_head.weight 根因tied 后 lm_head.weight 不是独立参数是 embed 的别名 分片代码按名字查 lm_head.weight 却查不到 影响带 tied embedding 的模型无法用 FSDP2最迷惑的是不 tie 的模型lm_head 独立用 FSDP2 正常一旦 tie 就 KeyError。因为 tied 后lm_head.weight从独立参数变成了embed_tokens 的别名名字还在但参数对象不在参数列表里按名查找即失败。二、背景tie_word_embeddingsTrue时模型的lm_head不持有独立nn.Parameter而是直接复用embed_tokens.weight。在 PyTorch 里这通常通过self.lm_head.weight self.model.embed_tokens.weight别名赋值实现于是model.parameters()里只有一份embed_tokens.weight没有独立的lm_head.weight。FSDP2 的fully_shard或infer_auto_device_map/ 分片计划在某些实现里会遍历模块的命名参数或按预定义的权重名清单去规划分片清单里包含lm_head.weight因为很多模型 lm_head 独立用lm_head.weight去named_parameters/state_dict里查tied 模型里这个键不存在被别名合并了-KeyError。更深层FSDP2 在分片时需要知道每组参数属于哪个 module、怎么切。如果它用固定名字lm_head.weight去找 lm_head 模块的参数而 tied 后该模块没有独立参数查找失败。根因是分片代码按固定权重名查找未处理 tied embedding 的别名合并。三、根因抽象成代码示意def shard_plan(model): names [n for n, _ in model.named_parameters()] # BUG假设 lm_head.weight 一定存在 plan build_plan_for(names [lm_head.weight]) # tied 时 lm_head.weight 不在 names if lm_head.weight not in names: raise KeyError(lm_head.weight) # 这里炸根因链条tied 模型里lm_head.weight是embed_tokens.weight的别名参数列表只有一份分片代码按固定名lm_head.weight查找该键在 tied 模型里不存在 -KeyError不 tie 模型有独立lm_head.weight正常根因是分片代码假设 lm_head 总是独立参数。一句话tied embedding 把lm_head.weight合并成 embed 别名FSDP2 按固定名查找即 KeyError。四、最小可运行复现用纯 Python 模拟按固定名查找 tied 缺失参数# repro_tied_lmhead.py def shard_plan_buggy(param_names, expected): if expected not in param_names: raise KeyError(expected) return planned def main(): # tied 模型只有 embed_tokens.weight没有独立 lm_head.weight tied_params [model.embed_tokens.weight, model.layers.0.weight] try: shard_plan_buggy(tied_params, lm_head.weight) except KeyError as e: print(复现成功 -, e) if __name__ __main__: main()运行输出复现成功 - lm_head.weighttied 模型参数列表里没有lm_head.weight按名查找即 KeyError正是真实 bug 的抽象。五、解决方案第一层最小直接修复最小且必须的一步分片前识别 tied把lm_head.weight解析回它实际指向的embed_tokens.weight不再按不存在的名字查找# fix_layer1.py def resolve_lm_head(params, tie_map): # tie_map: {lm_head.weight: model.embed_tokens.weight} resolved [] for name in params: resolved.append(name) for alias, target in tie_map.items(): if alias not in params and target in params: resolved.append(alias) # 补上别名入口指向同一份 return resolved # 用法 tie_map {lm_head.weight: model.embed_tokens.weight} plan_names resolve_lm_head(list(model.state_dict().keys()), tie_map)要点resolve_lm_head把别名lm_head.weight补回查找清单指向真实embed_tokens.weight分片时两者共享同一份参数不重复分片不再KeyError。六、解决方案第二层结构性改进把tied 权重解析做成模型结构感知的预处理在分片前统一把 tied 别名映射好并校验别名与目标确实指向同一对象防误配# fix_layer2.py from dataclasses import dataclass, field from typing import Dict dataclass class TieResolver: tie_map: Dict[str, str] field(default_factorydict) def expand(self, param_names): out list(param_names) for alias, target in self.tie_map.items(): if alias not in param_names and target in param_names: out.append(alias) # 别名补入口 return out def validate_shared_object(self, model): # 校验别名和目标确实指向同一 Parameter 对象tied 的本质 for alias, target in self.tie_map.items(): a dict(model.named_parameters()).get(alias) t dict(model.named_parameters()).get(target) if a is not None and t is not None: assert a is t, f{alias} 与 {target} 未共享同一对象tie 配置错误 # 用法 resolver TieResolver({lm_head.weight: model.embed_tokens.weight}) plan_names resolver.expand(list(model.state_dict().keys())) resolver.validate_shared_object(model)要点TieResolver.expand把 tied 别名补回分片清单validate_shared_object校验别名和目标确实is同一对象防 tie 配置错分片逻辑只面对展开后的名字不再 KeyError。七、解决方案第三层断言 / CI 守护写 pytest 验证tied 模型分片不 KeyError、别名指向同一对象# test_tied_lmhead.py import pytest def expand(tie_map, names): out list(names) for alias, target in tie_map.items(): if alias not in names and target in names: out.append(alias) return out def test_tied_no_keyerror(): tied [model.embed_tokens.weight, model.layers.0.weight] tie_map {lm_head.weight: model.embed_tokens.weight} out expand(tie_map, tied) assert lm_head.weight in out, tied 别名应被补回不 KeyError def test_alias_points_to_target(): tie_map {lm_head.weight: model.embed_tokens.weight} assert tie_map[lm_head.weight] model.embed_tokens.weight def test_untied_untouched(): untied [lm_head.weight, model.embed_tokens.weight] out expand({}, untied) assert out untied, 不 tie 时不应改动CI 一旦有人把 tied 处理删掉test_tied_no_keyerror立刻变红。八、排查清单FSDP2 报KeyError: lm_head.weight时确认模型是否tie_word_embeddingsTrue检查分片代码是否按固定名lm_head.weight查找打印list(model.state_dict().keys())看是否真的没有lm_head.weight按第五 / 六节把 tied 别名解析回embed_tokens.weight不 tie 正常、tie 异常几乎可断定是 tied 别名缺失校验别名与目标指向同一对象防 tie 配置错把第七节的 pytest 接进 CI守护 tied 模型可分片。九、小结FSDP2 在tie_word_embeddingsTrue的模型上报KeyError: lm_head.weight根因是 tied 后lm_head.weight是embed_tokens.weight的别名、不再是独立参数而分片代码按固定名lm_head.weight查找查不到即 KeyError。不 tie 模型有独立 lm_head正常。三层层级第一层分片前把lm_head.weight解析回embed_tokens.weight补回别名入口第二层用TieResolver统一展开 tied 别名并校验共享对象第三层pytest 验证 tied 模型不 KeyError、别名指向同一对象锁进 CI。核心教训任何按固定权重名查找的分片 / 加载代码都必须先处理tied embedding 的别名合并。把 tie 关系做成显式映射并校验别名与目标共享同一对象是支持各类模型结构的前提——本系列第 531 篇GPT-OSS从 dispatcher 角度、本篇从 FSDP2 分片角度覆盖了同一类问题。
延伸阅读

更多相关文章

2026/9/20 3:07:39

PHP反序列化漏洞CVE-2016-7124:从GC机制到安全防御

1. 项目概述:从漏洞编号到机制本质每次在安全社区或者技术论坛里,看到有人讨论PHP反序列化漏洞,尤其是提到CVE-2016-7124时,我总能看到类似的对话:“这个漏洞就是__wakeup()方法在反序列化时如果属性数量被修改&#x…

2026/9/21 18:38:25

CTF入门实战:从零掌握Web安全、密码学与逆向工程基础

1. 从零开始的CTF初体验:NewStarCTF 2023公开赛道Week1复盘如果你对网络安全感兴趣,或者听说过CTF(Capture The Flag)比赛,但总觉得它门槛太高、无从下手,那么NewStarCTF的公开赛道可能就是为你量身定做的“…

2026/9/20 3:07:43

华为P40激活锁破解:从Bootloader到Fastboot的深度解锁技术解析

1. 从“锁”开始:理解华为P40的几道安全防线如果你手头有一台华为P40,因为忘记了锁屏密码、或者是从二手渠道购入后发现被前机主的华为账号锁死,屏幕上那个“设备已锁定”或“请输入华为账号密码”的提示,无疑是一盆冷水。这不仅仅…

2026/9/21 18:34:22

Codex 跑 Trae+Docker+SSH 插件恢复脚本:Key 用 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 18:34:22

HarmonyOS无线调试全流程指南:从配对原理到故障排查

1. 摆脱数据线的执念:无线调试到底改变了什么先聊个最实际的问题:你上一次因为USB线材问题浪费了多少时间?我做鸿蒙应用开发这几年,前前后后用过不下十条数据线。原装的、第三方的、支持快充的、编织网包的,看起来差别…

2026/9/21 18:34:22

在 Vercel 上部署 Hono:从本地开发到云端发布的完整工作流

CLI后端云原生 【免费下载链接】vercel Develop. Preview. Ship. 项目地址: https://gitcode.com/gh_mirrors/ve/vercel 点击查看 免费下载 导读 本文以 vercel 仓库中的 Hono 示例 为主线,完整讲解一个基于 Web 标准的 Hono 应用如何通过 Vercel CLI …

2026/9/21 18:29:20

Java优先级队列与堆的实现原理及应用

1. 优先级队列与堆的基本概念优先级队列(Priority Queue)是一种特殊的队列数据结构,它不再遵循传统队列的先进先出(FIFO)原则,而是根据元素的优先级来决定出队顺序。在Java集合框架中,PriorityQ…

2026/9/21 3:28:31

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/21 3:33:19

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/21 0:02:23

OpenResearch:构建可复现的开放式研究工作流

第一次看到“OpenResearch”这个名字,我脑子里冒出的不是某个具体软件,而更像一种研究方式的宣言:开放、可复现、可验证。这三件事放在一起,其实比大多数人想象中难得多。过去几年我一直在折腾自己的研究工作流,从纯纸…

2026/9/20 4:54:47

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/21 18:32:12

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/21 10:29:02

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码