【免费下载链接】PaddleNLP
Easy-to-use and powerful LLM and SLM library with awesome model zoo.
导读
本文讲解 PaddleNLP 提供的 Torch2Paddle 权重自动转换能力:只需在 from_pretrained 中开启一个参数,即可把 PyTorch 格式的模型权重(含 Llama、Qwen、Bloom、GPT 等主流系列)自动转换为 Paddle 权重并保存到本地。读完本文,你将掌握单文件权重的一键转换方法、分片权重(sharded checkpoint)的合并预处理流程、底层转换原理(名称映射 + 张量搬运),以及转换过程中的常见注意事项。
一、一键转换:convert_from_torch=True
PaddleNLP 在 AutoModelForCausalLM(以及各个 PretrainedModel)的 from_pretrained 接口中内置了权重转换能力,核心代码如下:
from paddlenlp.transformers import AutoModelForCausalLM
AutoModelForCausalLM.from_pretrained("/path/to/pytorch/model", convert_from_torch=True, dtype="float16")
执行上述代码后,PaddleNLP 会自动完成以下流程:
- 读取指定目录下的 PyTorch 权重文件(
pytorch_model.bin)与config.json; - 依据模型配置解析"PyTorch 参数名 → Paddle 参数名"的映射关系;
- 将每个张量从
torch.Tensor搬运为paddle.Tensor(必要时做转置、合并/拆分等变换); - 用转换后的权重初始化 Paddle 模型,并把转换结果保存回
/path/to/pytorch/model目录,生成 Paddle 格式权重。
关键参数说明
| 参数 | 说明 | 取值 |
|---|---|---|
convert_from_torch | 是否从 PyTorch 权重自动转换为 Paddle 权重 | True / False,默认 False(ModelScope/HF Hub 场景下默认自动开启,见下文) |
dtype | 转换后权重的实际数据类型 | 通常为 float16、bfloat16、float32 |
dtype 说明:
dtype指定的是转换后权重的真实数据类型,而非仅表示加载时的临时精度。常见用法是dtype="float16"(半精度推理/训练)或dtype="bfloat16"(BF16 训练)。底层实现中,dtype会被写入config.dtype,并通过dtype_guard(dtype)约束模型初始化与权重落盘的精度(见 model_utils.py)。
从源码看转换的完整调用链
转换逻辑集中在 paddlenlp/transformers/model_utils.py 的 from_pretrained 中,关键步骤:
- 默认值推导:当
convert_from_torch未显式指定时,若环境变量from_modelscope开启,或from_hf_hub=True,则默认置为True——也就是说从 ModelScope / Hugging Face Hub 直接拉取权重时,默认就会把 Torch 权重转换为 Paddle 权重(model_utils.py)。普通本地路径加载时默认False。 - 能力检查:
convert_from_torch = cls.support_conversion(config) and convert_from_torch——先通过support_conversion判断当前模型类是否实现了名称映射(未实现_get_name_mappings的模型会抛NotImplementedError并被判定为不支持,见 conversion_utils.py)。 - 权重文件解析:
_resolve_model_file_path负责定位pytorch_model.bin、pytorch_model.index.json、model.safetensors等候选文件(model_utils.py)。 - 执行转换:当文件是 Torch 权重(以
pytorch_model.bin、pytorch_model.index.json、model.safetensors、model.safetensors.index.json结尾)时,调用模型类的convert()完成张量级转换,并把结果写入权重所在目录(model_utils.py)。
ConversionMixin.convert() 是转换的核心实现(conversion_utils.py):
@classmethod
def convert(cls, weight_file: str, config: PretrainedConfig, cache_dir: str) -> None:
# 1. 解析当前模型的 name-mapping 信息
name_mappings = cls._get_name_mappings(config)
# 2. 加载 pytorch 权重(.index.json 时自动合并分片)
if weight_file.endswith(".index.json"):
...
state_dict = {}
for file in sorted(files):
sub_state_dict = load_torch(os.path.join(os.path.dirname(weight_file), file))
state_dict.update(sub_state_dict)
else:
state_dict = load_torch(weight_file)
# 3. 按映射逐键转换
for name_mapping in name_mappings:
if name_mapping.source_name not in state_dict:
logger.warning(f"key<{name_mapping.source_name}> not in the pytorch weight file.")
continue
state_dict[name_mapping.target_name] = name_mapping.run(state_dict, name_mapping.source_name)
...
return state_dict
张量是如何从 torch 变成 paddle 的
load_torch(paddlenlp/utils/serialization.py)负责把 Torch 权重读取为 Paddle 张量:
- 对
pytorch_model.bin/pytorch_model-*文件:torch.load(..., map_location="cpu")后,通过 DLPack(torch.utils.dlpack.to_dlpack+paddle.utils.dlpack.from_dlpack) 实现零拷贝级的高效张量搬运,无需先落盘 numpy; - 对
model.safetensors:直接用 safetensors 反序列化,按 dtype 构造paddle.Tensor(BF16 数据会被显式转为bfloat16类型)。
由此可见,转换过程全程在 CPU 内存中完成张量形态变换,然后再以目标 dtype 写盘,因此转换时机的内存占用与原始权重规模基本相当。
二、分片权重合并:先把 sharded checkpoint 合成单文件
当前 PaddleNLP 的 Torch2Paddle 转换只支持单个权重文件 pytorch_model.bin。 当 HF 权重以分片形式(pytorch_model-00001-of-00002.bin + pytorch_model.index.json)存在时,需要先合并。
从源码看,
convert()其实对.index.json也做了兼容(会自动收集同目录下pytorch_model-*分片并合并加载),但作为稳妥的通用做法,仍建议按官方教程先手动合并,以便在转换前获得一份干净的单文件权重,也便于自行校验。
官方提供的合并脚本如下:
import torch, os
state_dict = {}
files = [file for file in os.list("./path/to/pytorch/weight") if file.startswith("pytorch_model-")]
for file in files:
state_dict.update(torch.load(file))
torch.save(state_dict, "pytorch_model.bin")
脚本要点
- 只收集
pytorch_model-前缀的分片文件(如pytorch_model-00001-of-00002.bin、pytorch_model-00002-of-00002.bin),不会误收pytorch_model.bin本身、config.json或 optimizer 状态; torch.load默认在 CPU 上加载(脚本未传map_location,请确保分片文件由标准torch.save产生);- 合并结果
pytorch_model.bin会保存在当前工作目录下,如需放进模型目录,请自行调整输出路径; - 合并后建议顺带确认
config.json、tokenizer相关文件与pytorch_model.bin位于同一目录,转换时需要一并读取。
更通用的验证流程(可选)
合并完成后,可以先用下面的片段快速核对参数总量与转换结果是否自洽:
import torch
state_dict = torch.load("pytorch_model.bin", map_location="cpu")
print(f"tensor 数量: {len(state_dict)}")
print(f"总参数量: {sum(v.numel() for v in state_dict.values()) / 1e9:.2f}B")
若分片来自 model.safetensors,也可以先用官方 safetensors 工具合并后再导出为 pytorch_model.bin,PaddleNLP 的转换入口对两类来源均做了兼容(见上文 load_torch 的实现)。
三、支持的模型列表
下表为当前仓库中支持 Torch → Paddle 权重自动转换的模型系列(对应各模型目录下 modeling.py 中的 _get_name_mappings 实现):
| 模型 | 是否支持 |
|---|---|
| AlBert | ✅ |
| Bart | ✅ |
| Bert | ✅ |
| Bloom | ✅ |
| Clip | ✅ |
| DistilBert | ✅ |
| Electra | ✅ |
| ErnieCode | ✅ |
| GLM | ✅ |
| Gpt | ✅ |
| Llama | ✅ |
| Mt5 | ✅ |
| Opt | ✅ |
| Qwen | ✅ |
| Roberta | ✅ |
| Roformer | ✅ |
| RW | ✅ |
| T5 | ✅ |
列表以当前仓库 docs/en/llm/docs/torch2paddle.md 与 docs/zh/llm/docs/torch2paddle.md 为准。表中未列出的模型不代表一定无法转换,可通过
support_conversion机制运行时判定;但不要假定未列出模型一定支持,使用前建议以实际报错或源码为准。
四、转换原理:StateDictNameMapping 与参数名映射
Torch2Paddle 的本质是 "参数名映射 + 张量变换"。每个支持转换的模型类都通过 _get_name_mappings 声明一张映射表,条目格式为:
[PyTorch 参数名, Paddle 参数名, 变换函数]
其中 StateDictNameMapping(定义于 conversion_utils.py)负责在 run() 时按需执行 transpose(转置)、切分/拼接等操作。以 Llama 为例,其映射定义在 paddlenlp/transformers/llama/modeling.py:
@classmethod
def _get_name_mappings(cls, config: LlamaConfig) -> list[StateDictNameMapping]:
model_mappings = [
["embed_tokens.weight"], # 同名直通
["norm.weight"],
]
for layer_index in range(config.num_hidden_layers):
layer_mappings = [
[f"layers.{layer_index}.self_attn.q_proj.weight", None, "transpose"],
[f"layers.{layer_index}.self_attn.k_proj.weight", None, "transpose"],
[f"layers.{layer_index}.self_attn.v_proj.weight", None, "transpose"],
[f"layers.{layer_index}.self_attn.o_proj.weight", None, "transpose"],
[f"layers.{layer_index}.self_attn.rotary_emb.inv_freq"],
[f"layers.{layer_index}.mlp.gate_proj.weight", None, "transpose"],
[f"layers.{layer_index}.mlp.down_proj.weight", None, "transpose"],
[f"layers.{layer_index}.mlp.up_proj.weight", None, "transpose"],
[f"layers.{layer_index}.input_layernorm.weight"],
[f"layers.{layer_index}.post_attention_layernorm.weight"],
]
model_mappings.extend(layer_mappings)
init_name_mappings(mappings=model_mappings)
# 带 "LlamaModel" 前缀的架构(如 LlamaForCausalLM)需要补前缀
if "LlamaModel" not in config.architectures:
for mapping in model_mappings:
mapping[0] = "model." + mapping[0]
mapping[1] = "llama." + mapping[1]
if not config.tie_word_embeddings:
model_mappings.append(["lm_head.weight", "lm_head.weight", "transpose"])
return [StateDictNameMapping(*mapping, index=index) for index, mapping in enumerate(model_mappings)]
从中可以读出的关键信息:
transpose是高频变换:PyTorch 的nn.Linear权重布局为[out, in],而 Paddle 的Linear布局为[in, out],因此几乎所有*_proj.weight都需要转置,这也是转换后数值完全一致、但必须做变换的根本原因;- 前缀自动推导:同一个权重文件既可能来自
LlamaModel(无前缀),也可能来自LlamaForCausalLM(带model./llama.前缀),映射表通过config.architectures自动判断并补前缀; - 映射表可做量化扩展:在
_get_tensor_parallel_mappings等流程中,add_quant_mapping还会把weight替换为quant_weight/quant_scale以适配量化模型(conversion_utils.py)。
五、常见问题与排查思路
- 提示 "not support convert torch model" 或
support_conversion返回 False:说明当前模型类未实现_get_name_mappings,即该系列暂不在支持列表内(model_utils.py 会给出Please set convert_from_torch=True ...的引导提示)。请参考支持列表选用模型,或等待上游实现。 - 日志出现 "key
not in the pytorch weight file"
:个别参数在源权重中缺失(如 tie word embeddings 时
lm_head.weight不在文件中),转换会跳过该键并用 Paddle 侧默认初始化,属于正常现象;若缺失的是关键层,请核对权重来源是否与config.json匹配。 - 转换后存在 "N tensors not initialized" 警告:说明部分源参数名未命中任何映射,通常是权重版本与当前 PaddleNLP 模型结构不一致导致,建议核对 PaddleNLP 版本与权重对应模型版本。
- 加载后数值异常/NaN:优先检查
dtype是否与源权重一致,以及分片是否合并完整(漏分片会导致state_dict.update覆盖缺失,参数量偏小)。 torch环境问题:转换依赖torch.load读取.bin权重,请确保安装了与权重序列化版本兼容的 PyTorch;PaddleNLP 已通过 paddlenlp/utils/import_utils.py 对 torch 可用性做了运行时探测,缺失时会给出明确提示。
六、进阶:把转换能力接入迁移工作流
Torch2Paddle 转换通常出现在两条工作流中:
- 从 Hugging Face / ModelScope 直接加载:
from_pretrained("model-name", from_hf_hub=True)或开启from_modelscope环境变量时,convert_from_torch默认为True,下载的 Torch 权重会被自动转换并缓存为 Paddle 权重,后续加载直接复用,无需重复转换(model_utils.py)。 - 本地权重迁移 + 后续微调/推理:按本文第一节代码将 PyTorch 权重转换为 Paddle 权重保存在本地目录,之后
AutoModelForCausalLM.from_pretrained("/path/to/paddle/model")即可直接加载,供 llm/run_finetune.py、llm/run_pretrain.py、llm/run_quantization.py 等训练/量化脚本使用。
配合仓库中的 llm/docs/finetune.md、llm/docs/pretrain.md 等教程,可以构建一套完整的 "PyTorch 权重 → Paddle 权重 → 微调/推理" 迁移链路,将社区生态中的大量预训练模型无缝接入 PaddleNLP。
【免费下载链接】PaddleNLP
Easy-to-use and powerful LLM and SLM library with awesome model zoo.
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



