
# 训练常见问题
#### Q1：复制文档中提供的样例脚本，运行时为什么出现 syntax error near unexpected token \`$'{\\r''？提示
A：通过复制文档中提供的的样例脚本后创建文件，可能由于Windows系统文件的换行符和Linux有所不同，导致了换行符识别不匹配。可以在Linux系统中执行dos2unix xxx.sh 或者使用vim执行以下两条命令进行格式转换。
```
:set ff=unix
:wq
```
#### Q2：所有的模型是否都通用本文档提供的脚本参数？切换模型的时候需要注意什么？
A：使用不同模型的时候，或者进行不同类型的训练时，都需要参考[MindSpeed-LLM/docs/quick_start.md · Ascend/MindSpeed-LLM - AtomGit \| GitCode](https://gitcode.com/Ascend/MindSpeed-LLM/tree/2.2.0/examples/mcore) 下每种模型具体的example脚本。
但是总体流程都是执行以下脚本，再根据本文档中的说明修改脚本参数后即可开始训练。
- hf到mg格式的权重转换脚本ckpt_convert_XXX_hf2mcore.sh
- 数据处理脚本data_convert_XXX_instruction.sh，如果是预训练则是data_convert_XXX_pretrain.sh
- 训练脚本，微调选择tune，预训练选择pretrain，全量微调选择full，Low-Rank Adaptation则选择LoRA。
- mg到hf格式的权重转换脚本ckpt_convert_XXX_mcore2hf.sh
- 训练任务总脚本**run_distributed_task.sh**也需要根据上述修改进行调整。
 
#### Q3：能否单独执行模型权重转换、数据格式转换、训练任务执行脚本，而不使用训练作业启动总脚本?
A：不推荐。训练任务总脚本**run_distributed_task.sh** 中，除了处理通信之外，也处理了OBS路径以及模型保存等相关操作。环境变量在训练任务总脚本**run_distributed_task.sh**中进行配置也更为规范和方便。使用总脚本也可以在一台实例上进行训练。
#### Q4：如果训练任务执行失败，但权重转换和数据格式转换都已成功执行并且保存到存储中，那再次训练时可以不重新转换权重或数据吗？
A：可以，只要保证参数和路径不变的情况下，在训练总脚本**run_distributed_task.sh**中对权重转换脚本ckpt_convert_XXX_hf2mcore.sh和数据格式转换脚本data_convert_XXX_instruction.sh增加注释，然后将相应的模型、并行参数以及路径填入到run_distributed_task.sh中即可直接进行训练。
#### Q5：MindSpeed-LLM安装在哪里？想要进行一些修改或者添加打印应该如何找到这个路径？
A：MindSpeed-LLM安装在/home/ma-user/MA_Turbo/src/open_source/MindSpeed-LLM下，其他依赖安装在/home/ma-user/MA_Turbo/src/open_source下。
在MindSpeed-LLM目录下即可看到与官方仓相同的分支内容。自定义使用MindSpeed-LLM的组件和文件时（例如convert_ckpt.py脚本），请注意路径是否正确，或者使用绝对路径/home/ma-user/MA_Turbo/src/open_source/MindSpeed-LLM/convert_ckpt.py。
#### Q6：训练完成之后得到的是什么格式的权重？为什么数量和一开始的HF模型文件数量不一致?
A：训练刚结束时生成的是 **Megatron-Core (mcore)** 格式权重（为了极致的分布式训练效率，将权重切分到了不同 GPU 上）。经过 mg2hf 转换脚本处理后，最终得到的是标准的 **HuggingFace (HF)** 格式权重，这是主流推理引擎（如 vLLM）所通用的格式。
转换后的 .safetensors 文件数量与原始模型不一致是正常的，因为配置的切分策略不同。虽然文件数量变了，但在 model.safetensors.index.json 索引文件的映射下，模型参数是完整的，可以正常加载和使用。
使用前请自行根据mg2hf转化完成的权重生成新的model.safetensors.index.json，避免出现model.safetensors.index.json中仍为旧的未训练的模型权重索引。
convert_ckpt.py的说明文档如下：
v1文档：[convert_ckpt.py文档](https://gitcode.com/Ascend/MindSpeed-LLM/blob/2.2.0/docs/pytorch/solutions/checkpoint/checkpoint_convert.md)
v2文档：[convert_ckpt_v2.py文档](https://gitcode.com/Ascend/MindSpeed-LLM/blob/2.2.0/docs/pytorch/solutions/checkpoint/checkpoint_convert_v2.md)
v1版本的examples较多且更稳定，推荐使用v1版本进行权重转化。如果希望使用v2，请保持hf2mg和mg2hf均为v2。可以自行阅读上述文档了解两者差异。
lora训练时权重转化方式区别较大，请自行阅读v1文档中的介绍修改训练脚本和权重转化脚本。
生成新的model.safetensors.index.json示例代码如下
```
import os
import json
from safetensors import safe_open
# === 修改这里为你的实际路径 ===
models_dir = "$TRAINED_HF_MODELS"
# ===========================
def generate_index(dir_path):
    print(f"正在扫描目录: {dir_path}")
    files = sorted([f for f in os.listdir(dir_path) if f.endswith(".safetensors")])
    
    if not files:
        print("错误：目录下没有找到 .safetensors 文件！")
        return
    weight_map = {}
    total_size = 0
    print(f"找到 {len(files)} 个权重文件，开始重构索引...")
    
    for file_name in files:
        file_path = os.path.join(dir_path, file_name)
        try:
            # 打开文件读取里面的 key
            with safe_open(file_path, framework="pt") as f:
                keys = f.keys()
                # 将该文件里的所有 key 都注册到 map 中
                for k in keys:
                    weight_map[k] = file_name
                    
            # 获取文件大小（可选，用于 metadata）
            total_size += os.path.getsize(file_path)
            print(f"已处理: {file_name} (包含 {len(keys)} 个参数)")
        except Exception as e:
            print(f"读取文件 {file_name} 失败: {e}")
            return
    # 构建最终的 index 字典
    index_dict = {
        "metadata": {
            "total_size": total_size
        },
        "weight_map": weight_map
    }
    # 保存新的 index.json
    save_path = os.path.join(dir_path, "model.safetensors.index.json")
    with open(save_path, "w") as f:
        json.dump(index_dict, f, indent=2)
    
    print("-" * 30)
    print(f"成功！新的索引文件已生成于: {save_path}")
if __name__ == "__main__":
    generate_index(models_dir)
```
