fix fleet fa version dispatch - #1396
Conversation
risemeup1111
left a comment
There was a problem hiding this comment.
发现需要修正后再合入的问题,细节已放在行级评论中。主要风险是 FA4 不可用时 fallback 到 FA3 后,没有继续用有效版本参与 deterministic 降级或返回给后向,可能导致进入不支持路径或前后向版本不一致。
当前还有部分 CI 任务未完成,建议修复后等待完整 CI 结果。
| if fa_version == 3: | ||
| if "block_mask" in inspect.signature(flashmask_attention).parameters: | ||
| if deterministic and query.shape[-1] > 128: | ||
| fa_version = 2 | ||
| elif deterministic: | ||
| fa_version = 2 | ||
| elif deterministic: | ||
| fa_version = 2 | ||
|
|
||
| if fa_version == 4 and _flash_mask_available: |
There was a problem hiding this comment.
优先级:P1
这里用原始 flag 直接判断 fa_version == 3,会漏掉 FLAGS_flash_attn_version=4 但 _flash_mask_available=False 的路径。该路径实际会走下面的 flashmask_attention(...) fallback,但函数仍返回 fa_version=4 给 backward;cp_flashmask_allgatherkv_balance_backward 只有 fa_version == 4 and _flash_mask_available 分支,未安装 cute backend 时会落到 ValueError。请先把不可用的 FA4 规范化到有效 fallback 版本,再做 deterministic 降级并返回这个有效版本。
| if fa_version == 3: | |
| if "block_mask" in inspect.signature(flashmask_attention).parameters: | |
| if deterministic and query.shape[-1] > 128: | |
| fa_version = 2 | |
| elif deterministic: | |
| fa_version = 2 | |
| elif deterministic: | |
| fa_version = 2 | |
| if fa_version == 4 and _flash_mask_available: | |
| if fa_version == 4 and not _flash_mask_available: | |
| fa_version = 3 | |
| if fa_version == 3: | |
| if "block_mask" in inspect.signature(flashmask_attention).parameters: | |
| if deterministic and query.shape[-1] > 128: | |
| fa_version = 2 | |
| elif deterministic: | |
| fa_version = 2 | |
| if fa_version == 4: |
There was a problem hiding this comment.
此处应该直接报错,提醒用户H卡上不要指定使用FA4
There was a problem hiding this comment.
可以,直接报错也能解决这里的问题,而且语义更明确:用户显式指定 FLAGS_flash_attn_version=4 时,如果当前 H 卡/环境没有 cute FA4 backend,就不应该静默走 flashmask_attention(...) 并把 fa_version=4 传给 backward。关键是要在进入 fallback 调用前拦住,例如:
if fa_version == 4 and not _flash_mask_available:
raise NotImplementedError(
"FA4 FlashMask requires cute backend; do not set FLAGS_flash_attn_version=4 on H-card/current environment."
)如果采用这个方案,后面 if fa_version == 4 and _flash_mask_available: 也可以相应简化成 if fa_version == 4:,并确保函数不会再返回一个实际未使用的 fa_version=4。
| if fa_version == 3: | ||
| if "block_mask" in inspect.signature(flashmask_attention).parameters: | ||
| if ( | ||
| paddle.get_flags(["FLAGS_cudnn_deterministic"])[ | ||
| "FLAGS_cudnn_deterministic" | ||
| ] | ||
| and hdim > 128 | ||
| ): | ||
| return 2 | ||
| elif paddle.get_flags(["FLAGS_cudnn_deterministic"])[ | ||
| "FLAGS_cudnn_deterministic" | ||
| ]: | ||
| return 2 | ||
| # Fall back to version 3 if flash_mask is not available | ||
| if fa_version == 4 and not _flash_mask_available: |
There was a problem hiding this comment.
优先级:P1
fa_version == 4 and not _flash_mask_available 时当前代码会在这个 block 之后直接 return 3,因此没有再应用 deterministic fallback。结果是在用户打开 deterministic、flashmask_attention 支持 block_mask 且 hdim > 128 时,原本应该避开不支持的 FA3 大 head_dim deterministic 路径,却会返回 3 并进入 _C_ops.flash_attn_v3/flashmask_attention_v2。请先把不可用的 FA4 规范化成 3,再复用同一段 deterministic 降级逻辑。
| if fa_version == 3: | |
| if "block_mask" in inspect.signature(flashmask_attention).parameters: | |
| if ( | |
| paddle.get_flags(["FLAGS_cudnn_deterministic"])[ | |
| "FLAGS_cudnn_deterministic" | |
| ] | |
| and hdim > 128 | |
| ): | |
| return 2 | |
| elif paddle.get_flags(["FLAGS_cudnn_deterministic"])[ | |
| "FLAGS_cudnn_deterministic" | |
| ]: | |
| return 2 | |
| # Fall back to version 3 if flash_mask is not available | |
| if fa_version == 4 and not _flash_mask_available: | |
| if fa_version == 4 and not _flash_mask_available: | |
| logger.warning( | |
| "FlashMask (fa_version=4) is not available, falling back to fa_version=3" | |
| ) | |
| fa_version = 3 | |
| if fa_version == 3: | |
| if "block_mask" in inspect.signature(flashmask_attention).parameters: | |
| if ( | |
| paddle.get_flags(["FLAGS_cudnn_deterministic"])[ | |
| "FLAGS_cudnn_deterministic" | |
| ] | |
| and hdim > 128 | |
| ): | |
| return 2 | |
| elif paddle.get_flags(["FLAGS_cudnn_deterministic"])[ | |
| "FLAGS_cudnn_deterministic" | |
| ]: | |
| return 2 |
There was a problem hiding this comment.
此处应该直接报错,提醒用户在H卡上不要指定使用FA4
There was a problem hiding this comment.
可以,直接报错也可以作为修复方案。这里的问题不在于一定要 fallback 到 3,而是当前 fa_version=4 && !_flash_mask_available 会继续 return 3,从而绕过 deterministic 降级并进入不期望的 FA3 路径。
如果预期是提醒用户 H 卡上不要指定 FA4,建议把这个分支改成明确异常,而不是 warning 后 return 3:
if fa_version == 4 and not _flash_mask_available:
raise NotImplementedError(
"FA4 FlashMask requires cute backend; do not set FLAGS_flash_attn_version=4 on H-card/current environment."
)这样也能消除我前面指出的 fallback 后继续执行 FA3/后向分发风险。
PaddlePaddle-bot
left a comment
There was a problem hiding this comment.
🤖 Paddle-CI-Agent | pr_review |
2026-07-04 15:46:05
📋 Review 摘要
PR 概述:调整 Fleet FlashAttention/FlashMask 的 fa_version deterministic 分发逻辑
变更范围:context_parallel_utils.py、refined_recompute/flash_attn.py
影响面 Tag:CP Recompute Attention
问题
| 级别 | 文件 | 概述 |
|---|---|---|
| 🔴 Bug | src/paddlefleet/refined_recompute/flash_attn.py:67 |
fa_version=4 不可用回退到有效 v3 时跳过 deterministic v2 fallback |
| 🔴 Bug | src/paddlefleet/context_parallel_utils.py:733 |
CP forward 在 v4 backend 不可用时仍返回 fa_version=4,deterministic 下会导致 backward 分发错误 |
📝 PR 规范检查
标题缺少官方 Tag;描述结构符合规范。
标题建议(可直接复制):
[Bug fixes] fix fleet fa version dispatch
总体评价
变更方向和 PR 意图一致,但当前把 deterministic fallback 绑定到原始 flag 值,遗漏了 fa_version=4 不可用后形成的有效 v3 路径。建议先统一计算 effective fa_version,再做 deterministic 降级,并在 CP forward/backward 之间只传实际使用的版本。
| fa_version = paddle.base.framework.get_flags(["FLAGS_flash_attn_version"])[ | ||
| "FLAGS_flash_attn_version" | ||
| ] | ||
| if fa_version == 3: |
There was a problem hiding this comment.
🔴 Bug 这里只在原始 FLAGS_flash_attn_version == 3 时执行 deterministic 降级,但下面 fa_version == 4 and not _flash_mask_available 会把有效版本回退成 3。
在未安装/不支持 cute FlashMask 且用户设置 FLAGS_flash_attn_version=4 时,deterministic + hdim > 128(或旧签名无 block_mask)会直接返回 3,后续 refined recompute 会走 v3 kernel,绕过此前的 v2 fallback。
建议修复方式:先把 flag 解析成实际可用版本,再对有效 v3 套 deterministic 降级,例如:
if fa_version == 4 and not _flash_mask_available:
logger.warning(...)
fa_version = 3
if fa_version == 3 and deterministic_fallback_needed:
return 2
return fa_version| ] | ||
| if "block_mask" in inspect.signature(flashmask_attention).parameters: | ||
| if deterministic and query.shape[-1] > 128: | ||
| if fa_version == 3: |
There was a problem hiding this comment.
🔴 Bug 这里同样只处理原始 fa_version == 3。当 FLAGS_flash_attn_version=4 但 _flash_mask_available=False 时,forward 实际不会进入 v4 _flash_attn_fwd,却仍把 fa_version=4 返回给 FlashMaskContextParallel.backward。
随后 cp_flashmask_allgatherkv_balance_backward 的 v4 分支又要求 _flash_mask_available 为真;在 deterministic 训练场景下,这次改动会跳过原本的 v2 fallback,并在 backward 分发到 unsupported version。
建议修复方式:在 forward 中先计算 effective_fa_version。如果 v4 backend 不可用,应先降为 3,再按 deterministic 规则必要时降为 2,并把这个实际使用的版本返回给 backward。
Codecov Report❌ Patch coverage is
❌ Your patch status has failed because the patch coverage (54.54%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## develop #1396 +/- ##
==========================================
Coverage ? 54.54%
==========================================
Files ? 2
Lines ? 11
Branches ? 8
==========================================
Hits ? 6
Misses ? 3
Partials ? 2
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
PaddleFleet Log Analysis
日志分析报告
失败的测试case: 根本原因分析: PR #1396 将 修复建议:
🔄 每次 Re-run 后自动更新 |
|
✅ Cherry-pick successful! Created PR: #1398 |
PR Category
Distributed Strategy
PR Types
Bug fixes
Description
fix fa version dispatch in fleet
是否引起精度变化
否