Skip to content

Feature[add model mistralai/ministral3]#4293

Open
learncat163 wants to merge 19 commits into
PaddlePaddle:developfrom
learncat163:feature/add-model-ministral3
Open

Feature[add model mistralai/ministral3]#4293
learncat163 wants to merge 19 commits into
PaddlePaddle:developfrom
learncat163:feature/add-model-ministral3

Conversation

@learncat163

Copy link
Copy Markdown
Contributor

PR 新增 mistralai系列的ministral3 模型

权重信息

目前提供了 Ministral-3-3B-Instruct-2512 和 Ministral-3-8B-Instruct-2512 2个版本的支持和权重转换。

代码即可以直接加载HF上的原始权重,也可以支持paddle格式权重的直接加载。

精度对齐

使用 tests/transformers/ministral3/test_modeling.pyTestMistral3DiffAlignment 类实现精度对齐测试断言(top10 token和logits diff)。

token top 10 对齐

使用prompt: 'Hello, how are you today?'

输出的token ids

Step Torch Paddle Status
1 1362 1362 OK
2 4525 4525 OK
3 7771 7771 OK
4 1044 1044 OK
5 15412 15412 OK
6 1636 1636 OK
7 1046 1046 OK
8 3075 3075 OK
9 2314 2314 OK
10 1636 1636 OK

PyTorch 生成文本: " I'm fine, thank you. How about you"

Paddle 生成文本: " I'm fine, thank you. How about you"

最后一层输出的logits diff

logits max_diff: 5.912781e-05 (threshold: 0.01)
logits mean_diff: 3.532475e-06

微调loss下降对比

step ms-swift paddle
2 1.182000 0.982295
3 1.659000 0.715159
4 1.533000 0.894038
5 1.773000 0.490606
6 0.929800 1.107558
7 0.995100 1.125524
8 0.517400 0.672211
9 0.671700 0.469049
10 1.126000 0.149397
11 1.089000 0.210774
12 1.221000 0.229611
13 1.037000 0.142172
14 0.757500 0.381565
15 0.828500 0.190437
16 0.630000 0.078277
17 0.552100 0.073114
18 0.424100 0.036691
19 0.732700 0.061551
20 0.363100 0.018962
21 0.490500 0.022519
... ... ...
total 97

paddle使用配置 tests/config/ci/ministral3_sft.yaml

ms-swift需要特别注意,需要安装一下依赖,不然可能会有问题pip install "mistral-common>=1.8.6" -U

ms-swift使用配置如下:

注册模板my_register.py
from swift.template import TemplateMeta, register_template
register_template(
    TemplateMeta(
        template_type='mistral_2512_text',
        prefix=['<s>'],
        prompt=['[INST]{{QUERY}}[/INST]'],
        chat_sep=['</s>'],
        suffix=['</s>'],
        system_prefix=['<s>[SYSTEM_PROMPT]{{SYSTEM}}[/SYSTEM_PROMPT]'],
        default_system=None,
        auto_add_bos=False,
    )
)
print("Registered 'mistral_2512_text' template")

from transformers.quantizers.auto import AUTO_QUANTIZER_MAPPING

_fp8_quantizer_cls = AUTO_QUANTIZER_MAPPING.get('fp8')
if _fp8_quantizer_cls:
    _orig_fp8_init = _fp8_quantizer_cls.__init__

    def _patched_fp8_init(self, quantization_config, **kwargs):
        quantization_config.dequantize = True  # 加载时将 FP8 权重转为 BF16
        _orig_fp8_init(self, quantization_config, **kwargs)

    _fp8_quantizer_cls.__init__ = _patched_fp8_init
    print("[PATCH] FP8 Quantizer: force dequantize=True")
else:
    print("[WARN] FP8 Quantizer not found in AUTO_QUANTIZER_MAPPING")
启动命令
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
MODEL_PATH="$HOME/llm/mistralai/Ministral-3-8B-Instruct-2512"
TRAIN_DATA="$PROJECT_DIR/tmp/gsm8k/gsm8k_train_swift.jsonl"
OUTPUT_DIR="$PROJECT_DIR/tmp/mistral3-8b-sft-swift"
REGISTER_SCRIPT="$SCRIPT_DIR/my_register.py"

# HF 镜像
export HF_ENDPOINT=https://hf-mirror.com

mkdir -p "$OUTPUT_DIR"

echo "========================================"
echo "ms-swift SFT Training - Ministral-3-8B"
echo "========================================"
echo "model:       $MODEL_PATH"
echo "data:        $TRAIN_DATA"
echo "output:      $OUTPUT_DIR"
echo "register:    $REGISTER_SCRIPT"
echo "max_steps:   200"
echo "========================================"

# 检查模型路径是否存在
if [ ! -d "$MODEL_PATH" ]; then
    echo "ERROR: Model path not found: $MODEL_PATH"
    exit 1
fi

# 检查数据文件是否存在
if [ ! -f "$TRAIN_DATA" ]; then
    echo "ERROR: Training data not found: $TRAIN_DATA"
    echo "Please run prepare_data.py first."
    exit 1
fi

# 激活 swift conda 环境并运行训练
source ~/miniconda3/etc/profile.d/conda.sh && conda activate swift && \
swift sft \
    --model "$MODEL_PATH" \
    --model_type mistral3 \
    --tuner_type full \
    --template mistral_2512_text \
    --custom_register_path "$REGISTER_SCRIPT" \
    --dataset "$TRAIN_DATA" \
    --max_length 2048 \
    --per_device_train_batch_size 1 \
    --learning_rate 2e-5 \
    --optim adamw_torch \
    --weight_decay 0 \
    --max_steps 200 \
    --warmup_steps 2 \
    --gradient_accumulation_steps 1 \
    --num_train_epochs 1 \
    --bf16 true \
    --seed 23 \
    --max_grad_norm -1 \
    --output_dir "$OUTPUT_DIR" \
    --logging_steps 1 \
    --save_strategy no \
    2>&1 | tee "$OUTPUT_DIR/training.log"

@paddle-bot

paddle-bot Bot commented Apr 16, 2026

Copy link
Copy Markdown

Thanks for your contribution!

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 61.56584% with 216 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (develop@e660ee5). Learn more about missing BASE report.

Files with missing lines Patch % Lines
paddleformers/transformers/ministral3/modeling.py 55.55% 208 Missing ⚠️
...leformers/transformers/ministral3/configuration.py 92.77% 6 Missing ⚠️
paddleformers/cli/utils/llm_utils.py 0.00% 2 Missing ⚠️

❌ Your patch status has failed because the patch coverage (61.56%) is below the target coverage (75.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             develop    #4293   +/-   ##
==========================================
  Coverage           ?   35.00%           
==========================================
  Files              ?      478           
  Lines              ?    89900           
  Branches           ?        0           
==========================================
  Hits               ?    31467           
  Misses             ?    58433           
  Partials           ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@a31413510

Copy link
Copy Markdown
Collaborator

确保带Required的CI测试项通过,如果报错原因非此PR导致的,可以自行评论 /re-run all-failed 重跑CI

@risemeup1111 risemeup1111 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已完成初轮审查,发现需要先修复的问题,具体证据和建议都放在行级评论里。CI 当前显示通过,但这些问题会影响 use_cache=True 生成路径以及部分权重加载路径,建议修复后再合入。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

Comment on lines +921 to +932
model_inputs = {
"input_ids": input_ids,
"past_key_values": past_key_values,
"use_cache": kwargs.get("use_cache", True),
}
if is_first_iteration or not kwargs.get("use_cache", True):
model_inputs["pixel_values"] = pixel_values
if attention_mask is not None:
model_inputs["attention_mask"] = attention_mask
if cache_position is not None:
model_inputs["cache_position"] = cache_position
return model_inputs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1

这里重写后没有复用 GenerationMixin.prepare_inputs_for_generation 的裁剪逻辑。PaddleFormers 的 generate 循环每一步都会传入累计增长的 input_ids,基类会在 past_key_values 已存在且 cache 非空时只保留最后一个 token;当前实现把完整序列连同旧 cache 再送进 decoder,会把已缓存 token 重复追加,导致 past_key_values 长度膨胀、后续位置/attention mask 错位,model.generate(..., use_cache=True) 的输出会和无 cache 推理不一致。建议复用基类准备输入,只在首轮保留视觉输入。

Suggested change
model_inputs = {
"input_ids": input_ids,
"past_key_values": past_key_values,
"use_cache": kwargs.get("use_cache", True),
}
if is_first_iteration or not kwargs.get("use_cache", True):
model_inputs["pixel_values"] = pixel_values
if attention_mask is not None:
model_inputs["attention_mask"] = attention_mask
if cache_position is not None:
model_inputs["cache_position"] = cache_position
return model_inputs
model_inputs = super().prepare_inputs_for_generation(
input_ids,
past_key_values=past_key_values,
inputs_embeds=inputs_embeds,
attention_mask=attention_mask,
cache_position=cache_position,
logits_to_keep=logits_to_keep,
**kwargs,
)
if past_key_values is not None:
model_inputs["pixel_values"] = None
elif pixel_values is not None:
model_inputs["pixel_values"] = pixel_values
return model_inputs

Comment on lines +576 to +589
if any(f.endswith(".safetensors") for f in files):
return False
marker_file = os.path.join(model_path, ".paddleformers_converted")
if os.path.exists(marker_file):
return True
config_file = os.path.join(model_path, "config.json")
if os.path.exists(config_file):
try:
import json

with open(config_file, "r") as f:
config = json.load(f)
if config.get("_paddleformers_converted", False):
return True

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1

这里在看到任意 .safetensors 后立即返回 False,导致下面的 .paddleformers_convertedconfig.json 里的 _paddleformers_converted 分支永远不可达。from_pretrained() 因此会把已转换的 Paddle safetensors 误走 _load_hf_safetensors_to_paddle(),按 HF 原始 FP8 规则重命名/转置后再 legacy 加载,PR 描述里的“paddle 格式权重直接加载”对 safetensors 格式会失败。请先检查显式 converted 标记,再把无标记 safetensors 当作 HF 原始权重处理。

Suggested change
if any(f.endswith(".safetensors") for f in files):
return False
marker_file = os.path.join(model_path, ".paddleformers_converted")
if os.path.exists(marker_file):
return True
config_file = os.path.join(model_path, "config.json")
if os.path.exists(config_file):
try:
import json
with open(config_file, "r") as f:
config = json.load(f)
if config.get("_paddleformers_converted", False):
return True
marker_file = os.path.join(model_path, ".paddleformers_converted")
if os.path.exists(marker_file):
return True
config_file = os.path.join(model_path, "config.json")
if os.path.exists(config_file):
try:
import json
with open(config_file, "r") as f:
config = json.load(f)
if config.get("_paddleformers_converted", False):
return True
except Exception:
pass
if any(f.endswith(".safetensors") for f in files):
return False

".*o_proj.*",
".*gate.*",
]
elif model.config.model_type == "mistral3":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 优先级:P2

ministral3 的 MLP 在本 PR 里定义的是 gate_proj/up_proj/down_proj,但这个新分支沿用了 w1/w2/w3 规则;默认 LoRA 目标因此不会匹配 up_projdown_proj,SFT/DPO 在不显式配置 lora_target_modules 时会少训练两组 FFN 权重。请把该分支的 FFN 目标层改成实际层名,例如:

            ".*gate_proj.*",
            ".*up_proj.*",
            ".*down_proj.*",

@risemeup1111 risemeup1111 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查最新提交。此前关于 use_cache=True 生成输入裁剪、已转换 safetensors 检测以及 mistral3 LoRA 目标层的行级问题在当前代码中均已修复;本轮没有发现新的阻塞问题。CI 当前通过。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

@liuhao2638 liuhao2638 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查最新提交。此次更新主要是合入上游变更,Ministral3 相关代码与上次通过审查的状态一致;此前行级问题仍保持已修复,未发现新的阻塞问题。CI 当前通过。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

@liuhao2638 liuhao2638 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查最新提交。此前关于生成输入裁剪、converted safetensors 检测和 LoRA 目标层的问题仍保持已修复;但本次新增的 RoPE fallback 处理引入了一个会影响默认配置初始化的阻塞问题,细节已放在行级评论里。CI 当前显示通过,但建议先修复该配置路径后再合入。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

self.rope_parameters = cfg_dict.get("rope_parameters", cfg_dict.get("rope_scaling"))
rope_theta = cfg_dict.get("rope_theta", 1000000.0)
if self.rope_parameters is None:
self.rope_parameters = {"rope_type": "yarn", "rope_theta": rope_theta}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1

这里把缺省 RoPE 配置改成了 rope_type="yarn",但没有提供 factor。当前 Ministral3RotaryEmbedding.__init__() 会在 rope_type != "default" 时直接调用 ROPE_INIT_FUNCTIONS["yarn"],而共享的 _compute_yarn_parameters() 明确要求 config.rope_parameters["factor"];因此 Mistral3Config() 的默认 text_config(只有 rope_theta,没有 rope_scaling)或任何未显式传 rope_scaling.factor 的配置都会在模型初始化时触发 AssertionError: factor is required in rope_parameters_dict。请让“无 scaling 配置”的 fallback 与实际初始化路径一致,例如两个 fallback 分支都使用 default RoPE,或者补齐完整的 yarn 参数。

建议按下面的形状同步修复 Ministral3TextConfig wrapper 和 Mistral3TextConfig(PretrainedConfig) 的无 scaling fallback:

if self.rope_parameters is None:
    self.rope_parameters = {"rope_type": "default", "rope_theta": rope_theta}

如果希望默认仍走 yarn,则需要至少补齐 factororiginal_max_position_embeddings 等 yarn 参数,并增加一个不传 rope_parameters/rope_scaling 的默认配置初始化测试。

@liuhao2638 liuhao2638 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查最新提交。此前指出的 RoPE fallback 缺少 yarn factor 的问题已修复,并新增了无 rope_scaling/rope_parameters 初始化覆盖;之前关于生成输入裁剪、converted safetensors 检测和 LoRA 目标层的问题也保持已修复。本轮未发现新的阻塞问题,CI 当前通过。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

@a31413510

Copy link
Copy Markdown
Collaborator

需要解决代码冲突
image

…l-ministral3

Resolve conflicts in template.py, transformers/__init__.py and auto/configuration.py by keeping both ministral3 and gemma4_moe/phi4 entries.

@risemeup1111 risemeup1111 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查最新提交。本轮主要是合入上游变更,Ministral3 相关实现和测试相对上次通过审查的状态未再改动;此前两个 P1 代码问题在当前 head 仍保持已修复,未新增行级代码意见。

当前还不能重新批准:此前 mistral3 LoRA 目标层那条 P2 行级评论虽然代码已按建议修改,但该线程尚未看到作者回复。请作者在对应行级线程回复 Done(或说明不同意的理由),以便按当前流程关闭该项。

另外,CI 目前仍有任务运行中,且两个 H20 integration job 在容器启动阶段失败(exit code 125),尚未进入实际测试步骤;建议待 CI 完成或重跑确认后再合入。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

@Paddle-CI-Bot

Copy link
Copy Markdown

PaddleFormers Log Analysis

Run #29110263281 · Attempt 1

日志分析报告

流水线名称 问题标签 修复建议 日志片段
Integration test (H20, single card) nvidia-container-cli 初始化超时 与本PR无关,H20 runner GPU 驱动 RPC 不通,CI 维护人员检查机器 nvidia-container-runtime 状态,rerun 报错代码
Integration test (H20, multi-card) nvidia-container-cli 初始化超时 与本PR无关,H20 runner GPU 驱动 RPC 不通,CI 维护人员检查机器 nvidia-container-runtime 状态,rerun 报错代码

失败的测试case:

无(两个 job 均在 docker run 启动阶段就失败,未进入任何测试用例执行)

根本原因分析:
两个 H20 runner(paddle-6-1567435 / paddle-9-1567435,同一物理机 yqlcc01-bbc-yqonlinea-com-1567435)的 nvidia-container-runtime 与宿主机 GPU 驱动之间的 RPC 调用超时(driver rpc error: timed out),导致 docker 容器启动时 OCI hook 执行失败,exit code 125,与 PR 代码改动(feature/add-model-ministral3)无关。

修复建议:

  1. CI 维护人员登录 yqlcc01-bbc-yqonlinea-com-1567435,检查 nvidia-smi 是否正常,nvidia-container-runtime 服务是否运行。
  2. 重启 nvidia-container-runtime:sudo systemctl restart nvidia-container-runtime
  3. 确认 runner 状态恢复后,对 PR Feature[add model mistralai/ministral3] #4293 触发 rerun。

🔍 准确性记录:请点击评论底部 😊 图标,选择 👍(准确)或 👎(有误),将自动记录到 CI 监控系统

🔄 每次 Re-run 后自动更新

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants