
1. DeepSpeed 保存 Qwen3 共享张量报错场景DeepSpeed 保存 Qwen3 共享张量报错通常发生在 DeepSpeed-Chat 的 SFT 阶段你微调完 Qwen3-0.6B训练日志看着正常走到最后保存那一步safetensors 突然提示某些张量共享内存。这个问题的核心不是训练没跑通而是 Qwen3 这类模型开启tie_word_embeddings后lm_head.weight和model.embed_tokens.weight指向同一块存储。原版save_hf_format()直接拿state_dict去save_filesafetensors 检测到共享data_ptr就会拒绝或者即使写出去也可能在加载时出现重复内存和值不一致。本文按排障视角走先用 TaoToken 给 Codex 配好 Key 和 Base URL让 Codex 对照utils.py、main.py定位并补上克隆共享张量的逻辑最后重新跑保存验证能加载 311 个张量。TaoToken 在这里只负责给 Codex 这个 AI 编程工具提供 Key 和 Base URL不参与 DeepSpeed 训练或张量保存本身。你需要改的还是本地仓库里的保存函数和调用位置。1.1 报错长什么样常见报错类似下面这种RuntimeError: Some tensors share memory, this will lead to duplicate memory on disk and potential differences when loading them. Please clone the tensors before saving.在 DeepSpeed-Chat 的step1_supervised_finetuning里保存入口通常还是save_hf_format(model, tokenizer, args)。它内部会走model.state_dict()然后调用safetensors.torch.save_file。Qwen3-0.6B 的config.json里有tie_word_embeddings: true所以输入嵌入和输出 LM Head 共享权重。safetensors 出于安全考虑不允许直接保存两个共享同一块内存的张量因为反序列化时它们会变成两份独立内存后续如果一方被修改加载结果就可能和训练时不一致。1.2 为什么只发生在 Qwen3 这类模型不是所有模型都会触发这个报错。像 Qwen3 这种小模型为了减少参数量、节省显存会把lm_head.weight和model.embed_tokens.weight绑定在一起。训练时这没问题DeepSpeed 也能正常更新。但保存时原逻辑没有处理共享关系于是 safetensors 检查data_ptr时发现两个 key 指向同一地址直接抛错。修复思路不是关掉tie_word_embeddings也不是改训练超参而是改保存逻辑在保存前遍历state_dict检测哪些张量共享data_ptr对后出现的共享张量执行clone()再交给 safetensors 保存。这样保存出来的文件里两个 key 各有一份独立权重加载时不会报共享内存错误。1.3 排障目标改 utils.py 和 main.py这条排障路线要盯住两个文件。第一个是dschat/utils/utils.py里面通常有原版save_hf_format()你要新增save_hf_format_safetensors()。第二个是training/step1_supervised_finetuning/main.py里面会调用原保存函数你要把调用替换成新函数。做完之后重新跑保存日志里出现克隆共享张量的提示并且最后能加载 311 个张量就说明链路通了。2. 用 TaoToken 给 Codex 配好排障通道2.1 TaoToken 在这个流程里的边界TaoToken 只负责给 Codex 提供 Key 和 Base URL不参与 DeepSpeed 训练、不参与张量保存、也不碰你的模型权重。Codex 的作用是读报错、读utils.py和main.py的相关片段帮你生成修改建议和补丁。你仍然在本地终端执行训练和保存命令。这个边界要先分清否则容易把排障问题误判成平台问题。官网入口在这里https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content2.2 创建 Key 与填写 Base URL打开官网注册后进入控制台创建 API Key。然后把 Codex 的 Base URL 填成https://taotoken.net/api注意不要加/v1也不要加 UTM 参数。很多配置失败不是 Key 错而是 Base URL 多写了后缀。API 地址本身是 https://taotoken.net/api Codex 侧只认这个根地址。Key 建议放在环境变量里不要硬编码到脚本。2.3 Codex 侧环境变量与配置片段如果你的 Codex 版本走环境变量可以这样设置export TAOTOKEN_API_KEY你的TaoTokenKey export OPENAI_API_KEY$TAOTOKEN_API_KEY export OPENAI_BASE_URLhttps://taotoken.net/api如果你的 Codex 使用config.toml可以参考下面这种写法不同版本字段可能略有差异以本地版本为准model gpt-5-codex model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY配好之后先在终端里跑一个最简单的 Codex 请求确认它能正常返回。不要等训练跑完才验证通道否则后面分不清是 Codex 没配好还是保存函数没改对。3. 让 Codex 对照 utils.py 与 main.py 的可复制做法3.1 先给 Codex 的上下文与提问模板把报错全文、dschat/utils/utils.py里原版save_hf_format函数、training/step1_supervised_finetuning/main.py里调用保存的位置一起丢给 Codex。只给报错不够它可能改到别的保存函数。我试过只把报错丢给 Codex结果它改的是另一个工具函数main.py里的调用没动重新跑还是原报错。可以用下面这个提问模板我在 DeepSpeed-Chat SFT 阶段保存 Qwen3-0.6B 时遇到 safetensors 共享内存报错。 报错信息RuntimeError: Some tensors share memory... 相关文件 1. dschat/utils/utils.py 中的 save_hf_format 函数 2. training/step1_supervised_finetuning/main.py 中调用 save_hf_format 的位置 请帮我 - 定位 state_dict 中所有共享 data_ptr 的张量 - 新增 save_hf_format_safetensors()对共享张量执行 clone - 替换 main.py 中的保存调用 - 给出保存后加载验证张量数量的代码。 不要修改训练超参和 DeepSpeed 配置。3.2 新增 save_hf_format_safetensors() 的对照修改Codex 给出的函数要满足几个点解包 DeepSpeed 的module遍历state_dict检测共享data_ptr克隆共享张量保存model.safetensors同时保存 tokenizer最后用load_file验证。下面是一个可参照的版本import os import torch from safetensors.torch import save_file, load_file def save_hf_format_safetensors(model, tokenizer, args, sub_folder): model_to_save model.module if hasattr(model, module) else model output_dir os.path.join(args.output_dir, sub_folder) os.makedirs(output_dir, exist_okTrue) state_dict model_to_save.state_dict() new_state_dict {} seen_ptrs {} for key, tensor in state_dict.items(): if not isinstance(tensor, torch.Tensor): continue origin_ptr tensor.data_ptr() if origin_ptr in seen_ptrs: print(f检测到共享内存张量 {key} 与 {seen_ptrs[origin_ptr]} 共享内存正在克隆) tensor tensor.clone() new_state_dict[key] tensor.detach().cpu().contiguous() seen_ptrs.setdefault(origin_ptr, key) output_file os.path.join(output_dir, model.safetensors) save_file(new_state_dict, output_file, metadata{format: pt}) tokenizer.save_pretrained(output_dir) print(f模型权重已保存至: {output_file}) loaded load_file(output_file) print(f验证通过成功加载 {len(loaded)} 个张量) return output_file关键点是origin_ptr要在转 CPU 之前取否则每个张量经过.cpu()后可能变成新的地址你就检测不到原本的共享关系。另外clone()要作用在即将保存的张量上克隆后不要再被原state_dict覆盖回去。3.3 替换 main.py 的保存调用改完utils.py后还要去main.py里替换调用。原代码可能是save_hf_format(model, tokenizer, args)改成from dschat.utils.utils import save_hf_format_safetensors save_hf_format_safetensors(model, tokenizer, args)如果main.py里已经有from dschat.utils.utils import ...就把新函数加进导入列表不要重复导入。替换完成后最好让 Codex 再 grep 一遍save_hf_format(确认没有漏掉其他调用点。DeepSpeed-Chat 有些分支会在不同阶段保存你只替换 SFT 阶段的入口就行。3.4 保存后验证 311 个张量保存成功后用独立脚本加载model.safetensors确认 key 数量和张量内容。Qwen3-0.6B 在这种保存逻辑下应该能加载 311 个张量。可以这样验证from safetensors.torch import load_file sd load_file(./output/model.safetensors) print(tensor count:, len(sd)) print(has lm_head:, lm_head.weight in sd) print(has embed:, model.embed_tokens.weight in sd) print(same ptr:, sd[lm_head.weight].data_ptr() sd[model.embed_tokens.weight].data_ptr())预期结果是张量数量为 311两个 key 都存在并且same ptr为False。如果数量少很多通常是你保存时过滤了非张量参数或者保存的是 DeepSpeed 的优化器状态而不是模型权重。4. 验证请求与成功结果4.1 重新跑保存请求改完文件后回到训练脚本目录重新跑 Qwen3-0.6B 的 SFT 启动脚本。命令类似cd DeepSpeedExamples/applications/DeepSpeed-Chat/training/step1_supervised_finetuning bash training_scripts/qwen/run_qwen3-0.6b.sh如果你已经训练完只想验证保存逻辑也可以让 Codex 帮你写一个独立加载模型并调用save_hf_format_safetensors()的小脚本。但更贴近原场景的做法还是重新跑训练脚本让它在训练结束触发保存。跑之前先确认main.py里的调用已经替换utils.py里新函数没有语法错误。4.2 加载 safetensors 验证保存完成后直接到输出目录看文件ls -lh ./output/model.safetensors python -c from safetensors.torch import load_file; sdload_file(./output/model.safetensors); print(len(sd))如果打印出 311说明 safetensors 文件结构完整。再检查config.json、tokenizer.json等文件是否也写在同一个输出目录。新函数里除了保存权重还要调用tokenizer.save_pretrained(output_dir)否则后续加载模型时可能找不到 tokenizer 配置。4.3 日志关键行成功时日志里会出现类似内容检测到共享内存张量 lm_head.weight 与 model.embed_tokens.weight 共享内存正在克隆 模型权重已保存至: ./output/model.safetensors 验证通过成功加载 311 个张量看到这三行基本可以确定共享张量问题已经解决。如果只看到保存路径没有克隆提示说明lm_head.weight和model.embed_tokens.weight的共享检测没有命中。回头检查origin_ptr是不是在.cpu()之后才取或者检查state_dict里是否已经因为其他包装变成了不同 storage。5. 本篇 DeepSpeed/Qwen3 保存报错常见错排查5.1 仍然报共享内存如果重新跑还是提示共享内存先在保存前打印所有张量的data_ptr看看除了lm_head.weight和model.embed_tokens.weight之外是否还有别的 key 共享。不要硬编码只克隆这两个 key应该让循环自动检测。另一个常见原因是克隆后又被原state_dict覆盖比如先写了new_state_dict[key] tensor后面又写了new_state_dict[key] state_dict[key]这样克隆等于没做。5.2 加载张量数量不对311 是 Qwen3-0.6B 在当前保存逻辑下的预期数量。如果数量明显不对先看new_state_dict是否把非张量项也塞进去了safetensors只接受 tensor。再看是否保存了 DeepSpeed 的module.前缀或_orig_mod.前缀导致加载时 key 名和模型结构不匹配。可以用表格对照一下常见现象现象可能原因处理数量少于 311过滤了部分 tensor打印 state_dict 的 key 对比数量多于 311保存了优化器或调度器状态只保存模型 state_dict加载缺 key保存时加了前缀去掉module.等包装前缀加载多 key保存了 DeepSpeed 额外状态不要合并 optimizer state5.3 main.py 没有真正替换有时utils.py已经加了新函数但main.py里还是调用旧函数。最直接的检查方式是grep -n save_hf_format training/step1_supervised_finetuning/main.py如果输出里还有save_hf_format(model, tokenizer, args)就把它替换成save_hf_format_safetensors(model, tokenizer, args)。如果导入报错检查PYTHONPATH是否包含 DeepSpeed-Chat 根目录。5.4 DeepSpeed 包装与 device 问题DeepSpeed 包装后模型可能在model.module里也可能带_orig_mod。新函数里用hasattr(model, module)解包是一种常见做法但如果你的 DeepSpeed 版本包装层数更多需要让 Codex 根据实际对象结构补一层。保存前把张量转 CPU 可以避免显存翻倍但要在检测共享之后再转顺序不要反。5.5 环境配置小坑CUDA_HOME没设置、PYTHONPATH没加、safetensors没安装都会让保存阶段报不同错误。基础命令可以先跑pip install safetensors export PYTHONPATH/path/to/DeepSpeedExamples/applications/DeepSpeed-Chat:$PYTHONPATH export CUDA_HOME/usr/local/cuda-12.4 export PATH$CUDA_HOME/bin:$PATH export LD_LIBRARY_PATH$CUDA_HOME/lib64:$LD_LIBRARY_PATH如果第二次训练加载了旧缓存也可以清理临时数据目录后再跑。保存报错和缓存问题有时会混在一起先把保存函数改对再看数据侧。6. 语义一致 CTA排障后继续用 TaoToken 接 Codex这条排障线的关键就是让 Codex 同时看到报错、utils.py和main.py而不是只改其中一个文件。共享张量检测、克隆逻辑、保存调用替换、311 个张量验证四步都做完DeepSpeed 保存 Qwen3 的 safetensors 报错基本就能收住。后续如果你还要让 Codex 帮你继续看环境配置、训练日志或模型评测脚本可以先把 TaoToken 的 Key 和 Base URL 保持好Base URL 仍然是https://taotoken.net/api不要加/v1或 UTM。需要创建或管理 Key可以走 API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentdeepspeed_qwen3_shared_tensorutm_campaignrewriteCodex 的接入方式和参数说明可以对照接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdeepspeed_qwen3_shared_tensorutm_campaignrewrite配好之后把save_hf_format_safetensors()和main.py的改动再让 Codex 复查一遍重点看data_ptr检测顺序、clone 是否生效、保存后加载数量是否为 311。跑通保存后再去接模型评测或长期编码任务链路会顺很多。