Skip to content

[Florence]: Add Florence-2 model support - #4780

Open
cf-icehzgzh wants to merge 5 commits into
PaddlePaddle:developfrom
cf-icehzgzh:feat/add-florence2
Open

[Florence]: Add Florence-2 model support#4780
cf-icehzgzh wants to merge 5 commits into
PaddlePaddle:developfrom
cf-icehzgzh:feat/add-florence2

Conversation

@cf-icehzgzh

Copy link
Copy Markdown
Contributor

本 PR 完成 Microsoft Florence-2-base 从 Hugging Face Transformers 到 PaddleFormers 的迁移,并对模型权重、前向精度、生成、训练和 LoRA 链路进行了验证。

1. 模型实现

模型:microsoft/Florence-2-base
支持:

  • DaViT Vision Encoder;
  • Image Projection;
  • BART Encoder-Decoder;
  • 图像和文本多模态前向;
  • Seq2Seq loss;
  • KV cache 和 greedy generation;
  • backward、AdamW 更新;
  • LoRA 训练和 merge。

2. 标准接口

新增:

  • Florence2Config
  • Florence2Processor
  • Florence2ForConditionalGeneration
  • DaViT 和 Florence-2 视觉模型

注册:

  • AutoConfig
  • AutoModelForCausalLM
  • AutoProcessor
    支持直接加载官方 Florence-2 checkpoint。

3. 精度与参数对齐

使用官方 microsoft/Florence-2-base 权重验证:

指标 结果
Logits max abs diff 7.2956085e-05
Logits mean abs diff 9.48057e-06
Loss abs diff 6.1948994e-06
Cache max abs diff 6.7234039e-05
Greedy generation token 完全一致
LoRA merge max abs diff 4.2915344e-06

额外检查了:

  • Paddle/PyTorch Linear 权重布局;
  • image projection 参数;
  • encoder/decoder attention 梯度;
  • tied embedding 和 lm head;
  • AdamW 单步更新;
  • Seq2Seq label shift 和 -100 mask。

4. 300-step 训练验证

使用官方 GSM8K train split,配置如下:

  • FP32;
  • train mode;
  • batch size = 1;
  • AdamW;
  • learning rate = 2e-5
  • weight decay = 0
  • seed = 23
  • 300 steps。
指标 PaddleFormers PyTorch ms-swift
Step 0 loss 6.457370 7.766876 7.766876
Step 299 loss 2.310060 2.377993 2.408321
最后 10 步均值 2.289445 2.262520 2.253360
ms-swift 与 PyTorch 的平均绝对差为:
0.00262687

三条曲线整体下降趋势一致。由于跨框架 dropout、drop-path 和 AdamW 数值实现不同,不声明 train 模式逐 step loss 完全一致。

5. 测试

新增 Florence-2 单测,覆盖:

  • forward、loss、backward;
  • labels shift;
  • LoRA 单步训练和 merge;
  • cache 和 generation;
  • AutoConfig、AutoModel、AutoProcessor;
  • 真实 checkpoint logits/loss 对齐。

测试结果:

普通单测:11 passed,4 skipped
真实 checkpoint:15 passed
git diff --check:passed

6. 提交范围

本 PR 仅包含 Florence-2 模型、配置、Processor、Auto 注册和单元测试,不包含训练数据、checkpoint、临时脚本和实验输出。

@paddle-bot

paddle-bot Bot commented Jul 18, 2026

Copy link
Copy Markdown

Thanks for your contribution!

@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.

已复查,新提交修掉了 lint 问题,但仍有需要修正的实现与 API 约定问题,细节见 inline review comments。

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

Comment on lines +105 to +110
if text is None:
text = ""
if isinstance(text, str):
text = [text]
if isinstance(images, (list, tuple)) and len(images) < len(text):
raise ValueError("Each prompt must be associated with an image.")

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
这里的批量校验只拦截了 len(images) < len(text),但 text is None 时会被展开成单条空串;images 是多图时,或者 textimages 多时,都会返回批次维度不一致的 BatchFeature。官方 Florence-2 processor 是按“一图一 prompt”处理的,这里需要把数量校验补全。
处理要求:请针对该评论进行回复(同意并已修改请回复 "Done",不同意请说明理由)。

Suggested change
if text is None:
text = ""
if isinstance(text, str):
text = [text]
if isinstance(images, (list, tuple)) and len(images) < len(text):
raise ValueError("Each prompt must be associated with an image.")
if text is None:
text = [""] * (len(images) if isinstance(images, (list, tuple)) else 1)
if isinstance(text, str):
text = [text]
if isinstance(images, (list, tuple)):
if len(images) != len(text):
raise ValueError("Each prompt must be associated with an image.")
elif len(text) != 1:
raise ValueError("Each prompt must be associated with an image.")

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
这次修复已经把 list/tuple 的等长校验补上了,但这里仍然只把 list/tuple 视为“多图输入”。如果调用方传入 batched 的 np.ndarray / paddle.Tensorlen(images) 明明能反映 batch size,却还是会走单图分支,pixel_valuesinput_ids 仍可能再次批次不一致。
建议先把 images 归一化成列表,再按归一化后的长度做等长校验,例如:

images = make_list_of_images(images)
if text is None:
    text = [""] * len(images)
elif isinstance(text, str):
    text = [text]
if len(images) != len(text):
    raise ValueError("Each prompt must be associated with an image.")

处理要求:请针对该评论进行回复(同意并已修改请回复 "Done",不同意请说明理由)。

)
output.image_hidden_states = image_features
return (
output if return_dict else ((output.loss, output.logits) if output.loss is not None else (output.logits,))

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
这个分支把 return_dict=False 裁成了只返回 (loss, logits),会丢掉 past_key_valuesdecoder_hidden_statesencoder_last_hidden_state 等信息,和仓库里其它 seq2seq 模型的 tuple 约定不一致。调用方如果依赖 tuple 输出或缓存,这里会直接退化。
处理要求:请针对该评论修复并提交新的 commit。

Suggested change
output if return_dict else ((output.loss, output.logits) if output.loss is not None else (output.logits,))
return output if return_dict else output.to_tuple()

@Paddle-CI-Bot

Paddle-CI-Bot commented Jul 18, 2026

Copy link
Copy Markdown

PaddleFormers Log Analysis

Run #29678037904 · Attempt 1

日志分析报告

流水线名称 问题标签 修复建议 日志片段
Integration test (H20, single card) CUDA 设备未正确初始化 与本PR无关,H20 runner 设备初始化异常,paddle 默认落到 Place(cpu),CI 维护人员检查 runner GPU 驱动状态,rerun 报错代码
Integration test (H20, multi-card) CUDA 设备未正确初始化 与本PR无关,H20 runner 设备初始化异常,paddle 默认落到 Place(cpu),CI 维护人员检查 runner GPU 驱动状态,rerun 报错代码

失败的测试case:

两个 job 均在 import paddlefleet 阶段即崩溃,未进入任何测试 case:
- paddlefleet_ops/__init__.py:114  paddle.cuda.get_device_capability()
  → ValueError: The device type Place(cpu) is not expected.

根本原因分析:
两个 job 的 runner 在启动时 GPU 设备未被正确识别(框架日志显示 CUDA device is not set properly. CPU device will be used by default),paddlefleet_ops__init__.py 顶层直接调用 paddle.cuda.get_device_capability() 时因设备为 Place(cpu) 而抛出 ValueError,导致 import paddlefleet 整体失败,与本 PR 改动无关。

修复建议:

  1. CI 维护人员重启 H20 runner 或检查 nvidia-container-runtime / GPU 驱动是否正常挂载 CUDA 设备。
  2. 确认恢复后直接 rerun 两个失败的 job。
  3. (可选)向 paddlefleet_ops 侧反馈:在 __init__.py 顶层调用 get_device_capability() 时应先判断 CUDA 是否可用(paddle.is_compiled_with_cuda() and paddle.device.cuda.device_count() > 0),避免 CPU 环境下 import 直接崩溃。

🔍 准确性记录:请点击评论底部 😊 图标,选择 👍(准确)或 👎(有误),将自动记录到 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.

4 participants