Compare commits

...

381 Commits

Author SHA1 Message Date
Liujie0926
3f87dac9b7 Delete .github/workflows/distribute-v100.yml 2026-05-23 10:54:28 +08:00
Liujie0926
be4f19628f Delete .github/workflows/distribute-a100.yml 2026-05-23 10:53:53 +08:00
xingmingyyj
587a5cdf97 fix load ema and model_meta path (#11203) 2025-12-17 17:19:22 +08:00
liufengwei0103
32b9a2e257 decouple sharding io and non zcc (#11201) 2025-12-16 19:12:37 +08:00
liufengwei0103
51f73a5104 disable only sharding opt in save stage (#11200) 2025-12-16 10:36:29 +08:00
baoqiwen
2ac85997c2 Fix loss for Align reduce precision with PyTorch 2.9.1. (#11199) 2025-12-15 15:45:57 +08:00
xingmingyyj
dcbdeaa819 change_save_meta_in_zcc_crossponding_to_paddle and fix flags (#11198)
* change_save_meta_in_zcc_crossponding_to_paddle

* delete

* fix

* change_save_meta_in_zcc_crossponding_to_paddle and fix args

* fix deadcode

---------

Co-authored-by: liufengwei02 <liufengwei02@baidu.com>
2025-12-13 17:03:13 +08:00
baoqiwen
7ab35ce94e Align reduce precision with PyTorch 2.9.1, disable precision checks. (#11195) 2025-12-12 17:16:21 +08:00
xingmingyyj
bc08aeec91 ban ckpt_converter test (#11194) 2025-12-12 14:15:15 +08:00
liufengwei0103
f8d0829e02 fix zcc error in eb5 (#11193) 2025-12-12 11:08:47 +08:00
xingmingyyj
b0276d735a 【FlexCheckpoint】adapter flex checkpoint (#11188)
* adapter flex checkpoint

* opt bf16 save

* fix multi moe_sharding_group load safetensors

* fix
2025-12-08 23:07:15 +08:00
liufengwei0103
fa007c8f85 cp add_fc_into_zcc to nlp (#11187) 2025-12-05 21:56:54 +08:00
xingmingyyj
c8f141476c add config memory_growth_threshold for save hf (#11183) 2025-11-28 19:37:10 +08:00
xingmingyyj
e4d28de5a8 【FlexCheckpoint】support save hf (#11180)
* support save hf

* fix
2025-11-26 23:28:16 +08:00
sneaxiy
53b85cbb34 fix EMA (#11177) 2025-11-18 12:10:34 +08:00
zhengshengning
9904cfc78e fix_int64_to_int (#11175) 2025-11-14 14:03:12 +08:00
sneaxiy
c07e0c8d3a Add Non ZCC EMA callback (#11173) 2025-11-13 10:12:55 +08:00
Wennie396
7c82a262f2 fix opt chunk offload (#11167) 2025-11-12 21:06:30 +08:00
Weiguo Zhu
61856820c3 fix model save for moe_sharding (#11162) 2025-11-12 18:50:34 +08:00
Zhuoqun Li
4eef1079f5 [Embedding] Expand training and shortgpt_prune code to support more model (#11168)
* final update

* expand training and shortgpt_prune code to support more model
2025-11-12 18:49:39 +08:00
zhengshengning
d38f3d696e big tensor: tokens_unzip_gather (#11172) 2025-11-12 11:18:15 +08:00
wanghuancoder
e68b135bfa fix eb5 big tensor bug (#11169)
* fix eb5 big tensor bug

* refine

* refine
2025-11-11 15:31:33 +08:00
Shing
6ac0402875 BugFix: qwen pp cannot send bool when using fuse loss (#11156)
* feat(model): add support for Qwen model in RL PipelineParallel

* feat(model): add support for QwenMoe model in RL PipelineParallel

* feat(model): add support for QwenMoe model in RL PipelineParallel

* BugFix: qwen model sequence parallel can not get batch size

* BugFix: qwen pp cannot send bool when using fuse loss
2025-11-07 20:39:41 +08:00
sneaxiy
6ede865d0f fix zcc ema GPU alloc bug (#11165) 2025-11-07 17:03:52 +08:00
Siyu Zhao
29f97bb461 TARE提交 (#11151)
Co-authored-by: zsy <zsy03260058@163.com>
2025-11-05 14:04:57 +08:00
a31413510
10014d8f0a Update run_finetune.py (#11159) 2025-11-03 21:51:38 +08:00
hsz06
e73341efa4 [codestyle] Modular convert tools (#11129)
* new file:   paddlenlp/transformers/convert/doc/README.md
	new file:   paddlenlp/transformers/convert/doc/llama_analysis.md
	new file:   paddlenlp/transformers/convert/doc/process.png
	new file:   paddlenlp/transformers/convert/doc/qwen2_analysis.md
	new file:   "paddlenlp/transformers/convert/doc/\351\241\271\347\233\256\346\212\245\345\221\212\357\274\232\351\243\236\346\241\250PaddleNLP-\345\211\215\346\262\277\346\250\241\345\236\213\346\250\241\345\235\227\345\214\226\350\256\276\350\256\241.md"
	new file:   paddlenlp/transformers/convert/main.py
	new file:   paddlenlp/transformers/convert/test_ability/test_base/test_modeling.py
	new file:   paddlenlp/transformers/convert/test_ability/test_paralle/compare_torch_with_paddle.py
	new file:   paddlenlp/transformers/convert/until/collect_import_modeling.py
	new file:   paddlenlp/transformers/convert/until/rename_identifiers.py
	new file:   paddlenlp/transformers/convert/until/rewrite_child_classes.py
	modified:   paddlenlp/transformers/qwen2/configuration.py
	new file:   paddlenlp/transformers/qwen2/modeling_qwen2.py
	new file:   paddlenlp/transformers/qwen2/modular_qwen2.py

* modified:   paddlenlp/transformers/qwen2/modeling_qwen2.py
	deleted:    paddlenlp/transformers/convert/doc/README.md
	deleted:    paddlenlp/transformers/convert/doc/llama_analysis.md
	deleted:    paddlenlp/transformers/convert/doc/process.png
	deleted:    paddlenlp/transformers/convert/doc/qwen2_analysis.md
	deleted:    "paddlenlp/transformers/convert/doc/\351\241\271\347\233\256\346\212\245\345\221\212\357\274\232\351\243\236\346\241\250PaddleNLP-\345\211\215\346\262\277\346\250\241\345\236\213\346\250\241\345\235\227\345\214\226\350\256\276\350\256\241.md"
	deleted:    paddlenlp/transformers/convert/main.py
	deleted:    paddlenlp/transformers/convert/test_ability/test_base/test_modeling.py
	deleted:    paddlenlp/transformers/convert/test_ability/test_paralle/compare_torch_with_paddle.py
	deleted:    paddlenlp/transformers/convert/until/collect_import_modeling.py
	deleted:    paddlenlp/transformers/convert/until/rename_identifiers.py
	deleted:    paddlenlp/transformers/convert/until/rewrite_child_classes.py
	deleted:    paddlenlp/transformers/qwen2/__init__.py
	deleted:    paddlenlp/transformers/qwen2/configuration.py
	deleted:    paddlenlp/transformers/qwen2/modeling.py
	deleted:    paddlenlp/transformers/qwen2/modeling_pp.py
	deleted:    paddlenlp/transformers/qwen2/modeling_qwen2.py
	deleted:    paddlenlp/transformers/qwen2/modular_qwen2.py
	deleted:    paddlenlp/transformers/qwen2/tokenizer.py
	deleted:    paddlenlp/transformers/qwen2/tokenizer_fast.py
	scripts/codestyle/convert/

* renamed:    paddlenlp/transformers/convert/doc/README.md -> scripts/codestyle/convert/doc/README.md
	renamed:    paddlenlp/transformers/convert/doc/llama_analysis.md -> scripts/codestyle/convert/doc/llama_analysis.md
	renamed:    paddlenlp/transformers/convert/doc/process.png -> scripts/codestyle/convert/doc/process.png
	renamed:    paddlenlp/transformers/convert/doc/qwen2_analysis.md -> scripts/codestyle/convert/doc/qwen2_analysis.md
	renamed:    "paddlenlp/transformers/convert/doc/\351\241\271\347\233\256\346\212\245\345\221\212\357\274\232\351\243\236\346\241\250PaddleNLP-\345\211\215\346\262\277\346\250\241\345\236\213\346\250\241\345\235\227\345\214\226\350\256\276\350\256\241.md" -> "scripts/codestyle/convert/doc/\351\241\271\347\233\256\346\212\245\345\221\212\357\274\232\351\243\236\346\241\250PaddleNLP-\345\211\215\346\262\277\346\250\241\345\236\213\346\250\241\345\235\227\345\214\226\350\256\276\350\256\241.md"
	renamed:    paddlenlp/transformers/convert/main.py -> scripts/codestyle/convert/main.py
	renamed:    paddlenlp/transformers/convert/test_ability/test_base/test_modeling.py -> scripts/codestyle/convert/test_ability/test_base/test_modeling.py
	renamed:    paddlenlp/transformers/convert/test_ability/test_paralle/compare_torch_with_paddle.py -> scripts/codestyle/convert/test_ability/test_paralle/compare_torch_with_paddle.py
	renamed:    paddlenlp/transformers/convert/until/collect_import_modeling.py -> scripts/codestyle/convert/until/collect_import_modeling.py
	renamed:    paddlenlp/transformers/convert/until/rename_identifiers.py -> scripts/codestyle/convert/until/rename_identifiers.py
	renamed:    paddlenlp/transformers/convert/until/rewrite_child_classes.py -> scripts/codestyle/convert/until/rewrite_child_classes.py
	renamed:    paddlenlp/transformers/qwen2/modeling_qwen2.py -> scripts/codestyle/qwen2/modeling_qwen2.py
	renamed:    paddlenlp/transformers/qwen2/modular_qwen2.py -> scripts/codestyle/qwen2/modular_qwen2.py

* modified:   scripts/codestyle/qwen2/modeling_qwen2.py

* modified:   paddlenlp/transformers/qwen2/configuration.py
	new file:   scripts/codestyle/convert/example/qwen2/__init__.py
	new file:   scripts/codestyle/convert/example/qwen2/configuration.py
	new file:   scripts/codestyle/convert/example/qwen2/modeling.py
	new file:   scripts/codestyle/convert/example/qwen2/modeling_pp.py
	renamed:    scripts/codestyle/qwen2/modeling_qwen2.py -> scripts/codestyle/convert/example/qwen2/modeling_qwen2.py
	renamed:    scripts/codestyle/qwen2/modular_qwen2.py -> scripts/codestyle/convert/example/qwen2/modular_qwen2.py
	new file:   scripts/codestyle/convert/example/qwen2/tokenizer.py
	new file:   scripts/codestyle/convert/example/qwen2/tokenizer_fast.py

* modified:   paddlenlp/transformers/qwen2/configuration.py

* modified:   scripts/codestyle/convert/doc/README.md
	deleted:    scripts/codestyle/convert/doc/process.png
2025-10-30 15:44:26 +08:00
aiyinyuedejustin
1bcf877c7f LoRA: add lora target modules support for qwen2 and qwen3 dense model when using fused keys (#11153) 2025-10-27 14:58:28 +08:00
Shing
c621f0cfa3 BugFix: qwen model sequence parallel can not get batch size (#11147)
* feat(model): add support for Qwen model in RL PipelineParallel

* feat(model): add support for QwenMoe model in RL PipelineParallel

* feat(model): add support for QwenMoe model in RL PipelineParallel

* BugFix: qwen model sequence parallel can not get batch size
2025-10-24 16:57:09 +08:00
Gu Shiwei
3f7eafc774 paddleformers PR check (#11150)
* paddleformers PR check

* echo line

* -x
2025-10-23 17:09:34 +08:00
Pioneer-wxh
51787ba815 commit dislora (#11122)
* commit dislora

* add DisLoRATrainer

* “readme文件修改”

* Delete docs/zh/llm/benchmark/rl/README.md
2025-10-22 14:52:10 +08:00
Shing
a4d16faf33 BugFix: Support for Qwen Model PipelineParallel Training in RLInfra (#11143)
* feat(model): add support for Qwen model in RL PipelineParallel

* feat(model): add support for QwenMoe model in RL PipelineParallel

* feat(model): add support for QwenMoe model in RL PipelineParallel
2025-10-22 10:58:50 +08:00
Xuxinyi
7d30769994 [AutoParallel]update code (#11145)
* update_code

* update_code
2025-10-21 20:52:46 +08:00
yujun
2f78db69b0 Upgrad swandlab code (#11105)
* Upgrad swandlab code

* add SWANLAB_EXP_NAME env
2025-10-16 20:43:18 +08:00
Shing
5dd2855a52 feat(model): add support for Qwen model in RL PipelineParallel (#11135) 2025-10-11 10:35:33 +08:00
ZhenxingLi
119ed11904 [Auto-Paralllel] fix intermediate api use1 (#11125)
* fix intermediate api use

* update
2025-09-30 15:39:42 +08:00
zhongtianyun
3c51eda5d6 [Embedding] Fix readme and env for contrastive_training (#11108)
modified:   csrc/gpu/unittest/test_get_padding_offset_v2.py
	modified:   paddlenlp/experimental/transformers/llama/modeling.py
	modified:   slm/pipelines/examples/contrastive_training/README.md
	modified:   slm/pipelines/examples/contrastive_training/evaluation/eval_mteb.py
	modified:   slm/pipelines/examples/contrastive_training/evaluation/eval_mteb.sh
	modified:   slm/pipelines/examples/contrastive_training/evaluation/modelling_quant.py
	modified:   slm/pipelines/examples/contrastive_training/shortgpt_prune.py
2025-09-29 10:53:53 +08:00
Liujie0926
937b766f21 [CI]Update loss (#11115)
Update loss
2025-09-25 15:21:34 +08:00
Tianyu Zheng
3432f69e07 Pr adapt flex checkpoint (#11065)
* adapt_flex_checkpoint

* Consistently use save_checkpoint_format and load_checkpoint_format

* fix the ckpt_format adapt

* delete the duplicate code

* delete safetensor
2025-09-25 14:16:35 +08:00
Liujie0926
586f5fb544 [CI]Update loss for Paddle#75367 (#11106)
* update loss_base

* update

* skip llama_dygraph_auto_bs8_fp16_DP2-MP2-PP2_hybrid_pp run dygraph auto hybrid pp in align mode

* fix

* fix

* fix
2025-09-24 16:21:02 +08:00
zhangyuqin1998
af07de0b01 [Distributed] refine training_pipeline_step to avoid memory leaks (#11103) 2025-09-23 14:59:25 +08:00
Gu Shiwei
b30ad6ad2b fix approval bypass (#11104)
* fix

* fix

* fix

* fix

* fix
2025-09-23 10:21:16 +08:00
co63oc
615a7c96ed fix typos (#11041) 2025-09-22 17:51:50 +08:00
Tianyu Zheng
03bc1a0063 [AutoParallel] GradientClipByGlobalNorm: Add align mode branch in autotrainer (#10960)
* Add test branch for align mode

* fix test bug

* rerun CI

* add the warning to warn the max_grad_norm is not 0.0
2025-09-22 16:30:31 +08:00
Liujie0926
b6f214efae [CI] Update loss_check (#11090)
* fix loss_check

* fix
2025-09-15 15:44:58 +08:00
Wennie396
e28c816070 Add chunk offload optimizer (#11084)
* add chunk offload optimizer

* fix get offload_opt_buffer_size arg
2025-09-15 11:19:03 +08:00
Zhuoqun Li
efd7d26434 [Embedding] Add qwen3 and update readme (#11034)
* add qwen3 and update readme

* update readme

* update readme

* update readme
2025-09-11 10:20:34 +08:00
sneaxiy
148206ea20 Make sharding_first by default (#11059)
* make sharding_first by default

* update run_ci.sh

* Update V100 baseline

* Update A100 baselines

* Revert "Update A100 baselines"

This reverts commit c682b2752a83b0e532a15a6b6f90ce08e386e447.

* Revert "Update V100 baseline"

This reverts commit 1ca17b7963d1912bc98c27a5ec1a4bfe0bf8abda.

* fix topo in CI cases

* fix JSON format error
2025-09-08 10:49:10 +08:00
Gu Shiwei
462597fc1a add bypass (#11077)
* add bypass

* add bypass
2025-09-08 10:23:53 +08:00
Ferrebo
85295b6955 [fea] support dp-moe for zcc and global_expert_id (#11050)
* support dp-moe for zcc (#10539)

* [fix] zcc ema under non-pp when `acc=1`

* zcc-ema fix load-state-dict when dp-moe

* [BugFix] shard-reshard下dp间is_matched行为不一致,以dp0为准 (#9404)

---------

Co-authored-by: Ferrebo <kebo01@baidu.com>

* [mod] Sharding IO: Added DP-Meta gather for MoE

---------

Co-authored-by: Meiyim <chenxuyi@baidu.com>
2025-09-08 09:56:41 +08:00
sneaxiy
509f005838 [Cherry-pick]Support to load sharded EMA checkpoint (#11075)
* support load sharded EMA checkpoints

* support_ema_loading_no_pdopt

* polish code
2025-09-08 09:55:39 +08:00
Junyuan Shang
20a584fb1a [cherry-pick] add zcc_ema_loss_threshold args to avoid merging models with loss spike (#11079) 2025-09-06 20:38:35 +08:00
Tian
68645cce6b Cherry-pick useful PRs from fleety (#11051)
* [LLM] fix normal sl (#10609)

* [LLM] support disable monkey patch (#10617)

* [LLM] use safer grad sync method when enabling sp (#10714)

* [RL] disable aistudio download and fix qwen bug (#10819)

* [RL] fix qwen load when fuse is enabled and modify gate presion to fp32 (#10842)

* 修复qwen3moe的一系列报错(justin) (#10818)

* [LLM] zcc support rng states (#10430) (#10485)

* [DLTP-85730] optimize save cost for zcc

* [LLM] fix moe using on tensor parallelism

* cherry-pick useful PRs from fleety and fix some typos

---------

Co-authored-by: aiyinyuedejustin <114650502+aiyinyuedejustin@users.noreply.github.com>
2025-09-05 23:21:13 +08:00
weiweisss
e050fd8f93 [PEFT]:nola (#10747)
* 'nola提交'

* Update test_nola.py

* solve conflicts
2025-09-05 17:24:02 +08:00
Liebele
e298ba42f6 LoriKiT (#9776)
* add linchain

* resolve confilct

* add linchain test

* resolve pre-commit

* resolve ci problem and add description.

---------

Co-authored-by: moge <lydo_0826@outlook.com>
2025-09-04 20:44:52 +08:00
XiangzheWang
19a585b507 use key-value to init dataloader (#11058) 2025-09-04 19:18:45 +08:00
Kunbo Ding
13790da6d0 Unified FuseLoss (#11057) 2025-09-04 16:52:05 +08:00
gongel
bad78900ba add more args to Qwen2ForCausalLM (#11068) 2025-09-04 14:24:49 +08:00
blacksheep-Aristotle
bbb8e004d3 token_dispatcher support expert_num 64 (#11066) 2025-09-04 13:23:32 +08:00
risemeup1
96a39777e3 fix custom op compile bug (#11064)
* fix bug

* Fix function calls in setup.py

---------

Co-authored-by: liym27 <33742067+liym27@users.noreply.github.com>
Co-authored-by: YUNSHEN XIE <1084314248@qq.com>
2025-09-04 11:05:56 +08:00
Yichen Zhang
1060ed47e7 [Cherry-pick] Cherry-pick hybrid-expert parallel related PRs from fleety (#11052)
* cherry-pick #10501

* cherry-pick #10526

* cherry-pick #10545
2025-09-03 17:27:47 +08:00
sneaxiy
206403950e Cherry-pick PRs from incubate/paddlenlp_fleety (#11049)
* add offload opt util (#10607)

* fix offload optimizer (#10608)

* fix sharding reshard bug (#10613)

* reset ema (#10790)

* Move fused_quanted_ops and token_dispatcher_utils to FleetY (#10803)

* move setup_fp8.py (#10820)

* Add tokens_zip_unique_add_subbatch and merge_subbatch_cast ops (#10822)

* add tokens_zip_unique_add_subbatch and merge_subbatch_cast ops

* enhance ut

* enhance ut again

* remove duplicate codes

* enhance ut again

* Sharding reshard supports mismatch parameter name (#10479)

* Sharding Reshard Supports N -> 1 (#10532)

* cherry-pick https://github.com/PaddlePaddle/PaddleNLP/pull/10531

* support tpdp-ep sharding reshard (#10568)

* fix typo

* revert sharding_first
2025-09-03 15:44:15 +08:00
zhangyuqin1998
87515b4a33 Support param and moment sync for pp (#11046) 2025-09-03 14:10:26 +08:00
ShenLiang
9c3ae1dbe6 [Cherry-pick] Cherry-pick from fleety (#11047)
* add timer log in trainer (#10880)

* add layer norm backward (#10886)

* add memory usage message in tensorboard (#10887)
2025-09-03 14:02:12 +08:00
umiswing
da9ddf7783 [feat] add params save_sharding_stage1_model_include_freeze_params (#9198) (#10551) (#11045)
Co-authored-by: Ferrebo <kebo01@baidu.com>
2025-09-03 10:59:16 +08:00
Liujie0926
abae89257e [CI]fix no data for dist (#11054)
* fix

* update
2025-09-03 10:57:43 +08:00
umiswing
c0ccc616eb [FEA] PP prepare_inputs add autocast (#10502) (#11043) 2025-09-03 10:28:48 +08:00
umiswing
8f88a68b05 Adapt to non-orthogonal context parallel (#11044)
* Adapt to non-orthogonal context parallel

* fix codestyle
2025-09-03 10:28:39 +08:00
XiangzheWang
42af154348 move the newer deep_gemm to fleety (#10860) (#11040)
Co-authored-by: wangxiangzhe <>
2025-09-02 13:23:23 +08:00
Liujie0926
b6c53b11fc update loss_base for paddle (#11027) 2025-09-01 10:11:34 +08:00
Liujie0926
89ec9af687 [CI] remove CI (#11024)
* remove CI

* remove cpu CI
2025-08-28 18:19:36 +08:00
Liujie0926
c5701e7f2a update is_cuda123 (#11009) 2025-08-28 14:42:41 +08:00
Zhan Rongrui
eda4a868ef Enable check for llama_dygraph_auto_bs8_fp16_DP2-MP2-PP2 and llama_dygraph_auto_bs8_fp32_DP2-MP2 (#10991)
* enable

* fix

* fix
2025-08-26 19:18:00 +08:00
tianshuo78520a
ab5071b359 ADD Approval CI (#10998)
* Update Approval CI

* Update Approval CI

* fix

* fix

* fix

* fix
2025-08-26 14:12:41 +08:00
Liujie0926
c39410ff72 add llm&unittest (#10993) 2025-08-25 13:01:12 +08:00
Liujie0926
ea228be896 [CI]Update Distribute CI (#10990)
* add cuda12.3 loss_base

* add a100 action
2025-08-25 11:24:12 +08:00
Zhuoqun Li
0bb61071d0 [infer] add mistral (#10668) 2025-08-25 10:14:07 +08:00
Zhan Rongrui
7f5cbdd7cc Disable check for llama_dygraph_auto_bs8_fp16_DP2-MP2-PP2 and llama_dygraph_auto_bs8_fp32_DP2-MP2 (#10989)
* update loss

* fix
2025-08-22 14:18:27 +08:00
zhongtianyun
1a58555b56 [feat] Add shortgpt (#10983)
* feat(shortgpt): add new script and polish existing code (typos, paths)

* fix: add shortgpt script, fix formatting and imports
2025-08-22 14:02:21 +08:00
Zhuoqun Li
c83684fe78 Fix hidden states and quant kv cache (#10854)
* fix hidden states

* fix quant kv_cache

* fix Lint style

* fix kv_cache_reuse key error

* fix kv_cache_reuse key error

* remove unused code

* fix kv_cache_reuse default
2025-08-21 15:35:25 +08:00
Liujie0926
887b5d27ae [CI] update loss for Paddle PR#74530 (#10949)
* update loss for Paddle PR#74530

* fix bug

* fix

* fix python
2025-08-21 15:26:29 +08:00
Liujie0926
d38a95c1e2 [CI]update build.sh (#10941)
* update build.sh

* add proxy

* update cache path

* skip aistudio down for connection

* fix
2025-08-20 16:51:05 +08:00
xingmingyyj
d74c950e15 fix path (#10955) 2025-08-19 20:23:03 +08:00
Siming Dai
704fd4fc3b fix ppo global_mini_batch_size (#10937) 2025-08-18 19:10:07 +08:00
zhaody
3e9d3518cb Update ppo (#10912)
* add ppo

* Update run_rl.py

* Update ppo_trainer.py

* Update config_utils.py

* Update run_rl.py

* Update gsm8k_processor.py

* Update run_rl.py

* Update score_model_utils.py

* Update score_model_utils.py

* Update run_rl.py

* Update ppo_trainer.py

* Update ppo_trainer.py

* Update ppo_trainer.py

* Update score_model_utils.py

* Update gsm8k_processor.py

* pre_commit

* Update advantage.py

* Update advantage.py

* pre-commit check

---------

Co-authored-by: DesmonDay <908660116@qq.com>
2025-08-07 14:21:56 +08:00
RevL147
2ae914eae9 fix ordered_save func (#10896)
Co-authored-by: luyuxiang <luyuxiang@YuxiangdeMacBook-Pro.local>
2025-08-05 12:08:30 +08:00
Liujie0926
5b9e0b33c1 fix CI bug (#10890) 2025-07-28 14:14:14 +08:00
ZhenxingLi
d250b3456c [Auto Parallel] Fix sp in gpt modeling_auto (#10835)
* Update modeling_auto.py

* Update pretrain-gpt3_13b_dynamic_auto.json

* update

* fix gpt sp model

* Update loss base

* update loss base

* disable benchmark SP for now
2025-07-25 14:44:38 +08:00
ZhenxingLi
b8f2101ebc clear flag (#10870) 2025-07-21 19:47:12 +08:00
ZhenxingLi
a205bc3f39 Update ci_case_auto.sh (#10855) 2025-07-18 16:41:32 +08:00
Liujie0926
06366431bd [CI] fix workflow (#10861)
* fix workflow

* remove codecov
2025-07-18 11:20:45 +08:00
Liujie0926
e042ac12e1 [CI] update workflow (#10846)
* update workflow for CI

* fix
2025-07-16 14:10:44 +08:00
danleifeng
f4846c1115 【AutoParallel】 add sep strategy for llama (#10837)
* autoparallel add sep strategy for llama

* fix ci

* fix ci error;

* fix ci error;
2025-07-14 19:14:56 +08:00
Yuntao Nie
58bed420fb [Auto Parallel] change fused_layers.py to support fused_linear_grad add/sync_mp_allreduce/sp_async_reduce_scatter in same time (#10797)
* add origin linear

* fix

* update mock_layer in run_pretrain_auto

* fix

* fix

* fix to_static

* fix to_static

* support sp_async_reducescatter

* polish

* fix ci bug: no flashattn in v100

* fix loss base

* close mp async when sp is on

---------

Co-authored-by: chenyuyan <2903319587@qq.com>
2025-07-11 11:15:59 +08:00
waliwali777
15d49bbe95 [AutoParallel] Open dynamic sharding CI test (#10793)
* open sharding CI test and remove flag

* update loss_base
2025-07-10 21:21:26 +08:00
danleifeng
44eff1f93f Add auto_parallel context_parallel strategy (#10722)
* add auto_parallel context_parallel and sep

* fix cp;add cp intermediate api demo

* fix

* fix

* fix

* fix

* fix modeling_auto

* fix modeling_auto

* fix pre-commit error

* fix pre-commit error

* fix ci error;add cp ut case

* fix ci error;add cp ut case

* fix ci error

* fix ci case loss diff error

* fix ci case loss diff error

* fix PaddleNLP-CI-gpt-3 ci error;cp not support non-a100

* fix PaddleNLP-CI-gpt-3 ci error;cp not support non-a100

* fix useless code;

* edit ci loss;changed cause paddle whl;0708
2025-07-09 14:33:27 +08:00
zty-king
78741f9c3e Fix the _save function so that it can save the optimizer parameters. (#10789)
* Fix the _save function so that it can save the optimizer parameters.

* 添加llama_dygraph_auto_bs8_fp16_DP2-MP2-PP2_hybrid_pp热启动单测

* 规范命名

* fix the log error
2025-07-08 11:35:55 +08:00
waliwali777
86621a3fe9 close dynamic sharding CI test (#10791) 2025-07-04 18:41:49 +08:00
gongel
baaa080477 fix_qwen3_moe (#10801) 2025-07-04 14:45:25 +08:00
XiangzheWang
2828bc7e88 fix ut (#10812) 2025-07-04 14:04:40 +08:00
Emmanuel Ferdman
9db95ee962 [tests] migrate to unittest.assertEqual (#10670)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2025-07-04 11:30:44 +08:00
ZhenxingLi
4355abbe93 [Auto-parallel] Fix sharding all_gather overlap in auto_dy (#10782)
* Update auto_trainer.py

* Update auto_trainer.py
2025-07-02 14:46:34 +08:00
ZhenxingLi
335905a07c Update pretrain-llama2_13b_dynamic_auto.json (#10785) 2025-07-02 11:48:08 +08:00
ZhenxingLi
46c25bfb58 Update pretrain-llama2_7b_dynamic_auto.json (#10786) 2025-07-02 11:47:56 +08:00
liym27
53545aa563 [Auto-Parallel] optimize the perfermance of GPT-3 (#10780) 2025-07-01 16:08:19 +08:00
XiangzheWang
24a8887610 Adapt new nccl version (#10768)
* adapt new nccl version

* adapt new nccl version

* adapt new nccl version

* fix

* fix

* fix

* fix

* fix

* add test

* add test

* fix

* fix ut
2025-07-01 11:42:09 +08:00
ZhenxingLi
6ff098b972 [Auto Parallel] Add enable_linear_fused_grad_add in qwen benchmark (#10779)
* Update qwen-14b_pretrain_dynamic_auto_bs32_bf16_DP1_MP2_Sharding16_Stage1.sh

* Update pretrain-qwen_14b_dynamic_auto.json

* Update pretrain-qwen_14b_dynamic_auto.json
2025-06-30 17:15:06 +08:00
Yuntao Nie
d4be4ab700 [Auto Parallel] Adapt mp_async_allreduce optimize in auto paralle (#10770)
* add mp_async_allreduce

* update mock_layer()

* add comment

* remove comment
2025-06-30 11:00:01 +08:00
YUNSHEN XIE
b8f4b0cba6 disable use_cinn for intermediate_api_meta-llama-Llama-2-7b (#10778) 2025-06-27 20:27:10 +08:00
Liujie0926
8fd74f0b74 [CI] update auto_parallel loss_base for paddle#73408 (#10771)
* update loss_base for paddle#73408

* update

* test for loss

* update loss

* update loss

* update loss

* update

* update

* revert test
2025-06-26 14:14:24 +08:00
waliwali777
06378bb4e5 Add gpt dyanmic auto benchamrk (#10759)
* update

* Update pretrain-gpt3_13b_pp.json

* Update modeling_auto_pp.py

* Update modeling_auto_pp.py

* Update modeling_auto_pp.py

* Update run_pretrain_auto.py

* Update run_pretrain_auto.py

* Update run_pretrain_auto.py

* Update modeling_auto_pp.py

* Update pretrain-gpt3_13b_pp.json

* Update trainer_utils.py

* init benchmark

* update json

* update json

* remove sd flag

* format

* fix rebase

* open enable_linear_fused_grad_add

* pre-commit

---------

Co-authored-by: Xing-lil <zhenxingli@hust.edu.cn>
Co-authored-by: ZhenxingLi <lizhenxing02@baidu.com>
Co-authored-by: Starrysea996 <2462405885@qq.com>
2025-06-25 14:55:32 +08:00
waliwali777
ecf7a0c3f6 add model_type (#10766) 2025-06-25 11:21:03 +08:00
Yuntao Nie
cd4db85734 [Auto Paralle] open llama test (#10762)
* open_ci

* add A100 data
2025-06-25 11:20:45 +08:00
waliwali777
f068df3006 Fix the import issues caused by Paddle version (#10760)
* adapt to the release version of Paddle, fix import

* format

---------

Co-authored-by: Starrysea996 <2462405885@qq.com>
2025-06-24 20:07:40 +08:00
waliwali777
544b7db39e open gpt dp CI test (#10740)
* open gpt dp CI test

* update a100 loss base

* update base

* update loss base

* run gpt base

* update base

* restore
2025-06-24 13:10:36 +08:00
megemini
f2477c0727 【Hackathon 8th No.32】 Adam-mini 精调算法复现 (#10413)
* [Init] AdamWMini

* [Update] blocks per neuron and other

* [Update] adamw_python

* [Update] adamw_python

* [update] fix grad mean

* [update] remove bad conflict resolve

* [update] moment shape align to torch

* [update] test layernorm

* [update] logger

* [add] test case for adamwmini
2025-06-24 10:36:03 +08:00
XiangzheWang
bfba64bb98 [Auto Parallel] add llama with auto pp (#10751)
* llama_with_auto_pp

* support change n_microbatches in json

* fix init model

* keep layers which are not in curr rank

* formal llama_with_auto_pp

* formal llama_with_auto_pp

* style

* formal

* fix

* fix

* fix

* fix

* add condition for hybrid pp

* fix

* add test case

* add test case

* add test case

* add llama type pp_schedule

* fix
2025-06-23 14:59:05 +08:00
waliwali777
1938c9e940 Run llama dyanmic pp perf (#10753)
* llama_with_auto_pp

* support change n_microbatches in json

* fix init model

* keep layers which are not in curr rank

* formal llama_with_auto_pp

* formal llama_with_auto_pp

* style

* formal

* fix

* fix

* fix

* fix

* add condition for hybrid pp

* fix

* add json

* remove old

* update json

---------

Co-authored-by: Waynezee <wangxiangzhe@baidu.com>
2025-06-20 20:27:56 +08:00
Yuntao Nie
e7420b1b38 [Auto Parallel] close llama dynamic dp test temporarily (#10750)
* close_ci

* fix
2025-06-19 11:40:43 +08:00
许万鹏
c6ed7a31e0 Integrate DataProto into the GRPO (#10597)
* Integrate DataProto into the GRPO

* Integrate DataProto into the GRPO, flake8

* Integrate DataProto into the GRPO, isort

* Update DataProto_ver250521

* Update DataProto_ver250530

* Update DataProto_ver250605, aligned

* Update DataProto_ver250610, aligned

* Update DataProto_ver250611, aligned, remove comment, recover Trainer

* Update DataProto_ver250611, aligned use outer autocast, remove comment, recover Trainer

* Update DataProto_ver250611, aligned use outer autocast, remove comment, recover Trainer, pre-commit

* Update DataProto_ver250612

* Update DataProto_ver250612, add copyright

* Update DataProto_ver250617, add docstring, follow style guidelines, black
2025-06-18 19:31:03 +08:00
Yuntao Nie
b79f03e037 [AutoParalle] fix fused layers fp32 multi precision (#10743)
* add enable_fused_linear_grad_add to run

* fix fused_layers fp32 multi precision
2025-06-18 17:11:28 +08:00
zhengzhonghui
7161461e59 Remove restrictions on the use of allgather_overlap (#10741) 2025-06-18 11:29:17 +08:00
Siming Dai
141499b287 fix tp model load (#10739) 2025-06-17 16:55:31 +08:00
Siming Dai
e5c7866c20 update architectures saving (#10738) 2025-06-17 16:55:17 +08:00
waliwali777
98b08b1242 close gpt dynamic dp test temporarily (#10736) 2025-06-13 18:13:29 +08:00
lugimzzz
9f9c1d3e83 fix wint4/8lora (#10728) 2025-06-12 22:53:49 +08:00
Yzc216
c9c0a3ec9e Aistudio 使用 SDK 进行下载 (#10678)
* aistudio SDK

* test: transformer download util

* style: pre-commit check

* test

* fix: remove redundant parameter

* Update aistudio-sdk requirement
2025-06-12 19:36:44 +08:00
bukejiyu
7f5d719555 [inference]Add support for splitting Paddle tensors. (#10721)
* 增加paddle tensor 切分逻辑

* update

* update

* update

---------

Co-authored-by: tangbinhan <tangbinhan@baidu.com>
2025-06-12 11:32:16 +08:00
Liujie0926
88b7a14ab0 [CI] skip unit case for hang (#10642)
* skip case for hang

* fix codestyle

* skip test_data_collator_for_language_modeling

* fix requirements
2025-06-11 14:18:37 +08:00
ZhenxingLi
eb9e7a0392 [AutoParallel] Fix fast_rms_norm (#10711)
* Update ln_api.cpp

* Update ln_api.cpp
2025-06-11 12:00:30 +08:00
lugimzzz
4615d005f6 update fp8 training (#10720) 2025-06-11 11:15:02 +08:00
AIbin
7309a5dde8 update moe_preprocess for wint2.x (#10702) 2025-06-07 12:19:28 +08:00
Siming Dai
7f2de6ea2f update mergekit with remove_keys input (#10693) 2025-06-06 23:14:40 +08:00
lugimzzz
46932b6629 fix ci (#10710) 2025-06-06 15:40:49 +08:00
ZhenxingLi
7c2fcbd778 Update llama_dygraph_auto_bs8_fp32_DP2 mem_base (#10707)
* Update ci_case_auto.sh

* Update ci_case_auto.sh
2025-06-06 14:13:56 +08:00
lugimzzz
ad548d3bcf [llm] support tensorwise fp8/int8 training (#10612) 2025-06-05 15:11:24 +08:00
waliwali777
fb80d7d0d9 improve qwen perf (#10692) 2025-06-05 14:50:11 +08:00
Ting
247ad86e16 [Template] apply chat template support openai format. (#10701)
Co-authored-by: ganzehua <ganzehua@baidu.com>
2025-06-04 21:21:14 +08:00
Siming Dai
acff7e1fa0 Update aistudio-sdk requirement (#10698) 2025-06-04 14:15:54 +08:00
Ting
38ebc26f08 [Template] add jinja plugin, apply_chat_template support dict messages (#10677) 2025-06-03 15:55:28 +08:00
liym27
b550133ff7 Revert "[Auto-Parallel] optimize llama-7b benchmark in temporary solution to …" (#10682)
This reverts commit e0921f0fa8.
2025-06-03 10:40:26 +08:00
Siming Dai
c1322be06c Update loading numpy format state dict (#10679)
* [UC] fix _load_state_dict_into_model

* update load numpy state_dict
2025-05-30 17:23:49 +08:00
ZhenxingLi
ea2976f396 [Auto-Parallel] Add benchmark for sharding opt in qwen N4C32 dy_auto (#10673)
* Update qwen-14b_pretrain_dynamic_auto_bs32_bf16_DP1_MP2_Sharding16_Stage1.sh

* Update pretrain-qwen_14b_dynamic_auto.json
2025-05-30 15:49:27 +08:00
liym27
e0921f0fa8 [Auto-Parallel] optimize llama-7b benchmark in temporary solution to avoid unnecessary communication (#10671) 2025-05-30 14:14:52 +08:00
waliwali777
9ba4e7e046 Remove num_hidden_layers for baichuan (#10655)
* remove num_hidden_layers for baichuan

* add enable_linear_fused_grad_add

* remove fused_linear_param_grad_add

* add tensor_fusion

* add fused_linear_param_grad_add
2025-05-28 19:31:51 +08:00
FireDog2
d67eaa42f1 LoRA-Pro Implemention (#10146)
* lorapro提交

* Fix issues in LoraPro tests and configuration

* Fix loRA-Pro test files bugs

* lorapro pr修改

* Trigger CI re-run
2025-05-28 19:25:24 +08:00
ZhenxingLi
e5858b1204 [Auto-Parallel] Add acc=2 case for tensor_fusion and overlap in auto-dy (#10665)
* Update ci_case_auto.sh

* Update loss_base

* Update ci_case_auto.sh

* Update ci_case_auto.sh
2025-05-28 15:06:17 +08:00
liym27
73118f6d37 [Auto-Parallel] optimize perfermance for qwen-14b (#10652) 2025-05-28 11:09:52 +08:00
waliwali777
988ad5d0d0 [AutoParallel] add use custom op test in pipeline mode (#10653)
* add use rms norm ci test in pp mode

* fix loss base

* fix base
2025-05-27 14:23:03 +08:00
Ze-Yi LIN
062debf2aa [Integration] add swanlab logger (#10594)
* feat: add swanlabcallback

* fix run

* fix lint

* fix requirements dev

* fix url
2025-05-27 11:25:16 +08:00
Hanlin Tang
c418bba09c [Docs] Change tables to list items (#10656) 2025-05-27 11:24:17 +08:00
ZhenxingLi
eb43056b95 Add benchmark for fused_linear in llama7b N4C32 dy_auto (#10647)
* Update pretrain-llama2_7b_dynamic_auto.json

* Update pretrain-llama2_7b_dynamic_auto.json

* Update pretrain-llama2_7b_dynamic_auto.json
2025-05-26 14:43:23 +08:00
Siming Dai
f0eccbde43 [UC] fix _load_state_dict_into_model (#10645) 2025-05-26 14:35:16 +08:00
co63oc
a38f7b7805 [Typos] Fix (#10651) 2025-05-26 11:33:35 +08:00
Hanlin Tang
5f5d9d4cfb [llm] Add pretrain tutorial (#10611) 2025-05-26 11:27:48 +08:00
Hanlin Tang
f90c7a53dd 【PaddleNLP No.2】Add finetune tutorial (#10625)
* [Docs] Add finetune tutorial

* [Docs] fix finetune_tutorial
2025-05-26 11:27:37 +08:00
Hanlin Tang
0643835e13 【PaddleNLP No.3】Add alignment tutorial (#10631)
* [Docs] Add alignment tutorial & fix rl doc formulas

* Update alignment_tutorial.md
2025-05-26 11:27:25 +08:00
Hanlin Tang
d267297277 【PaddleNLP No.4】 Add quant tutorial (#10640)
* [Docs] Add quant tutorial

* [Docs] del tables in quantization_tutorial.md
2025-05-26 11:27:12 +08:00
ZhenxingLi
c309aa7c80 Update meta-llama-Llama-2-7b_pretrain_dynamic_auto_bs32_bf16_Sharding32_Stage2.sh (#10599) 2025-05-23 15:13:42 +08:00
zty-king
c3e25ca527 [AutoParallel] Using local_map replace LocalLayer (#10309) 2025-05-23 15:01:59 +08:00
chen
99e1c105cf [infer] update_input_v2 op will not return eos when env_var is set (#10628)
* Revert "output_len truncated without eos_token_id (#10614)"

This reverts commit 850c6c2859.

* check

* check

* add env var
2025-05-23 14:12:30 +08:00
gongel
7dbba98070 [RL] Fix typo and add wandb log (#10641)
* add log

* add INFERENCE_TRUNCATED_RETURN_EOS

* add INFERENCE_TRUNCATED_RETURN_EOS
2025-05-23 14:11:06 +08:00
SdeeRK
eee766b5de [RL] reinforce learning benchmark framework (#10619)
* 增加rl目录下的init.py文件

* 增加copy rightb并格式化

* add reinforcement learning benchmark framework

* update copyright

* update

* add reinforce learning benchmark framework

* add elapsed time metrics in api serve framework

* fix some bug

* add reinforce learning framework with scripts file

* remove vllm quant type

* reformat rl benchmark code and scripts

* add readme file

* add fastdeploy engine support for api serve
2025-05-23 14:10:45 +08:00
cyy536
134a7b9958 Add ci for sp_async_reduce_scatter_in_dygraph_auto_mode (#10638) 2025-05-23 13:10:13 +08:00
ZhenxingLi
23e4c1ae80 [Auto-Parallel] Add ci for tensor_fusion and overlap in auto-dy (#10598)
* Update ci_case_auto.sh

* Update ci_case_auto.sh

* Update ci_case_auto.sh

* Update ci_case_auto.sh

* Update ci_case_auto.sh

* Update ci_case_auto.sh

* Update ci_case_auto.sh
2025-05-23 11:50:37 +08:00
Hanlin Tang
dbf9c44927 [LLM] fix quantization without qlora (#10639) 2025-05-22 18:01:06 +08:00
co63oc
3f2db10ffe [Typos] Fix (#10494)
* Fix
2025-05-22 17:53:07 +08:00
huangjiyi
adf2768fe2 add merge_all_horizontal_groups cinn flag for llama (#10629) 2025-05-22 15:38:25 +08:00
Zero Rains
64afc81733 [FIX] fix the bug that some gemm config did not be handled (#10627)
* fix the bug that some gemm config did not be handled

* change paddle_throw to std::runtime_err
2025-05-21 20:39:03 -07:00
cyy536
a6ea5390f7 Add sp_async_reduce_scatter in dygraph auto mode (#10620) 2025-05-22 10:52:02 +08:00
co63oc
3b0c8ff630 [Typos] Fix (#10486) 2025-05-21 11:48:08 +08:00
Hanlin Tang
af16c95c07 [PIR] Update simcse to apply pir (#10396) 2025-05-21 11:47:08 +08:00
Hanlin Tang
868f6eeed5 [Taskflow] Fix the recognition bug of json format with both PIR suffix and id2label (#10487) 2025-05-21 11:45:18 +08:00
Hanlin Tang
38828ba0bb [PIR] Update paddle.inference infer example for Ernie-vil2.0 (#10500)
* [PIR] Updated arrow data and paddle.inference infer example for Ernie-vil2.0

* [PIR] delete fastdeploy in ernie-vil2.0 doc
2025-05-21 11:37:31 +08:00
Echo-Nie
7ea6253132 【PaddleNLP No.1】 add pre-train.md (#10506)
* Paddle NLP No.1 pretrain.md

* add comment to printInfo

* fix according to review

* fix according to review

* 移除模型列表,改为参考根目录列表

* 修改模型列表措辞
2025-05-21 11:36:52 +08:00
co63oc
9bee5b36ad Fix (#10533) 2025-05-21 11:35:33 +08:00
chen
850c6c2859 output_len truncated without eos_token_id (#10614) 2025-05-20 12:49:14 +08:00
Siming Dai
6f80ea1562 Fix fp8 in dtype_byte_size (#10618) 2025-05-20 11:08:01 +08:00
Zong Wei
5c482b6b64 [INTEL_HPU] Enable FusedBlockMultiTransformerHPU (#10514)
add FusedBlockMultiTransformerHPU and prepare_input_hpu

atten output post-process

FusedBlockMultiTransformerHPU opti for-if-else

kv_head update for HPU shape

fix benchmark can't run with bigger bs issue

Co-authored-by: yanfeich <yanfei.cheng@intel.com>
2025-05-19 17:37:46 +08:00
Zhong Hui
6bdb71622c Update ppo_model_utils.py (#10593)
* Update ppo_model_utils.py

* Update pp_model_utils.py
2025-05-19 17:30:17 +08:00
Jinji Fu
c654d1ae21 merge reshard-1 (#10606) 2025-05-19 17:12:49 +08:00
yujun
ddcb722e3d [RL] logprob compute use the same method (#10596)
* fix logprob compute method

* update
2025-05-15 15:41:50 +08:00
FocusLuo
cd2d2dc05b [INTEL_HPU] add e2e auto test cases (#10108)
* [INTEL_HPU] add e2e auto test cases

* [INTEL_HPU] add e2e auto test cases

---------

Signed-off-by: Luo, Focus <focus.luo@intel.com>
2025-05-14 17:01:44 +08:00
Liujie0926
6de50e6750 [paddlenlp_ops] update whl (#10576)
* update whl

* update
2025-05-14 15:17:37 +08:00
Zhong Hui
2b1efb2efd Update serialization (#10584)
* Update serialization.py

* fix
2025-05-14 11:45:58 +08:00
Weiguo Zhu
91920a68cb fix (#10585) 2025-05-13 19:22:11 +08:00
gongel
477048cccd fix_eos_mask (#10588) 2025-05-13 15:19:54 +08:00
Zhong Hui
6d40971b6e Refactor RL (#10569)
* pathes to RLTrainerBase

* refactor ActorReferenceTrainerBase
2025-05-13 15:17:15 +08:00
chen
fe442e4173 check (#10587) 2025-05-13 15:11:54 +08:00
chen
47de2c6c04 [infer] get_output and save_output recover input without msg_queue_id (#10574)
* check

* fix input_text dy_insert

* check code
2025-05-13 13:06:28 +08:00
Liujie0926
8205e3d194 [CI]add rl to ci (#10553)
* fix scripts for docs

* fix timeout

* add grpo&rf++

* fix path

* update yaml

* fix

* fix data

* add install_external_ops

* fix fused_ln

* fix

* update cmd

* fix path

* fix

* fix path

* fix codestyle

* update class name

* update name
2025-05-13 10:02:56 +08:00
SdeeRK
3570aaac37 增加rl目录下的init.py文件 (#10581)
* 增加rl目录下的init.py文件

* 增加copy rightb并格式化
2025-05-12 17:44:42 +08:00
yulangz
c4e53f6820 [Dockerfile] Add xpu p800 release dockerfile (#10552) 2025-05-12 16:27:53 +08:00
Zhong Hui
c043487a16 [LLM] Add qwen3 (#10524)
* init qwen3

* first version.

* fisrt version support for qwen3

* add missing files.

* add readme

* refine copyright.

* init version for qwen moe.

* fix networks.

* fix generate.

* refine

* fix set_state_dict to slow for supper large network for network, such as moe model.

* fix

* fix

* fix set_state_dict to slow for supper large network for network, such as moe model.

* fix qwen2 tensor parallel.

---------

Co-authored-by: DrownFish19 <DrownFish19@gmail.com>
2025-05-12 10:35:58 +08:00
kebin liu
759ae99609 add qat_fp8linear (#10570) 2025-05-09 14:36:45 +08:00
Liujie0926
247f05e4a6 [paddlenlp_ops] update name (#10518)
* update paddlenlp_ops name

* fix

* update version
2025-05-09 14:30:16 +08:00
zhink
624510af1d [paddlenlp_ops] Fix custom all reduce and cpp_extensions.cu when sm70/75 (#10554) 2025-05-09 10:59:19 +08:00
Siming Dai
72dc85d2d7 fix stop_gradient in uc (#10571) 2025-05-08 18:22:06 +08:00
Hanlin Tang
6c0bfac329 【PaddleNLP No.22】Fix PIR for ernie-layout (#10484) 2025-05-08 15:01:44 +08:00
Tian
276cfc2cd4 [LLM] fix zcc typo (#10559) 2025-05-08 13:18:22 +08:00
lugimzzz
fa41a91efa fix quantlora bug (#10562) 2025-05-07 20:29:26 +08:00
yujun
aa9d8d5788 [RL] 加速推理模型qwen2的set state dict的性能 (#10550)
* 加速推理模型qwen2的set state dict的性能

* dim -> axis
2025-05-07 18:07:56 +08:00
Hanlin Tang
1f9b47ee14 [PIR]Fix ernie-3.0 deploy&add training without hf (#10475) 2025-05-07 15:22:16 +08:00
chen2016013
fea8d82586 fix llama13b bug (#10525) 2025-05-07 11:28:06 +08:00
Weiguo Zhu
c7d44f2bf9 [RL] Fix loading amp custom list from .yaml (#10544)
* fix

* add rf++
2025-05-06 22:17:43 +08:00
Tian
bb83432da0 [LLM] enhance logger output for real filename and lineno (#10537) 2025-05-06 19:18:41 +08:00
Hanlin Tang
1aadf1bce6 [PIR] Fix text_classification (#10497) 2025-05-06 13:13:12 +08:00
Jinji Fu
95901cb11b Fix qwen rl kl coeff (#10530) 2025-04-30 17:08:44 +08:00
yujun
93e58f2357 添加grpo_qwen32b 9机训练命令 (#10528) 2025-04-30 13:53:37 +08:00
Function-Samuel
9b3ef71b62 Add dynamic auto mode cross_entropy CI (#10515)
* add cross_entropy ci

* fix

* fix
2025-04-29 19:33:01 +08:00
Function-Samuel
d0044ab6cb Add qwen cross entropy optimize in dynamic auto mode (#10521) 2025-04-29 19:32:51 +08:00
gongel
713ef2b228 rename (#10523) 2025-04-29 16:45:01 +08:00
gongel
7c565f6f3c update rl doc (#10522) 2025-04-29 15:51:28 +08:00
lugimzzz
3fa6ac6a7c fix readme bug (#10520) 2025-04-29 15:37:10 +08:00
Function-Samuel
fab948ca4f Add qwen-14b benchmark (#10513) 2025-04-29 14:22:34 +08:00
yujun
5f782a840d add grpo kk 0.96 (#10519) 2025-04-29 14:07:42 +08:00
greycooker
a00471f1e9 [RL] Fix GRPO &&RF++ Docs (#10517)
* fix ppo doc

* fix grpo
2025-04-29 11:15:26 +08:00
yujun
edd34aa3bc [RL] RL support varlen flash mask (#10490)
* update rl

* 删除optimizer的timer时间

* 修改rollout_continue_batching_batch_size为rollout_max_num_seqs, quant_type为rollout_quant_type

* 更新global_mini_batch_size

* fix entropy_coeff dtype error

* add einops requirements

* 更新文档

* user rm padding so we donot need to pad_to_multiple_of tp degree

* update rollout_max_num_seqs

* squeeze unsqueeze

* shuffle

* fix training bug

* fix missing pad

* add dataloader_shuffle args
2025-04-28 19:48:17 +08:00
Zhong Hui
d6182ffa65 Update rl_dataset.py with apply_chat_template (#10510) 2025-04-28 16:04:32 +08:00
Liujie0926
4821b63869 [CI]skip unnecessary executions (#10509)
* skip unnecessary executions for unittest

* fix

* fix

* skip unnecessary executions for distribute

* fix unittest

* fix
2025-04-28 10:49:36 +08:00
Echo-Nie
e7516ee3c0 Fix llm_train.rst deaklink(#10505) 2025-04-27 17:12:45 +08:00
Zhong Hui
aad5cbe847 [ArgParser] Support pass python file as config. (#10489)
* fix import.

* add python script.

* support pass python file as config.
2025-04-27 17:06:51 +08:00
l1cacheDell
370702a6bd update setup_cuda.py (#10493) 2025-04-27 00:33:11 -07:00
Liujie0926
d3ee14fab8 [CI]update scripts for ci (#10496)
* update scripts for ci

* fix

* update     install_paddle

* fix

* fix install_paddle

* add timeout for taskflow

* fix case_list

* fix
2025-04-27 11:12:34 +08:00
Function-Samuel
4d358256f8 [Performance Optimization]Replace cross_entropy_with_softmax to c_softmax_with_cross_entropy in dynamic auto mode (#10471)
* Replace cross_entropy_with_softmax to c_softmax_with_cross_entropy in dynamic auto mode

* add sys_path

* add TODO

* add copyright
2025-04-27 10:57:16 +08:00
chen
acb6e224b5 【Inference】Fix Bug set_preids_token_penalty_multi_scores (#10492)
* fix

* check model_inputs[pre_ids] update in dynamic insert
2025-04-25 20:12:46 +08:00
Zero Rains
409fc407c9 [Inference] fix the bug for dynamic/static inference and dy2st for deepseekv2 in weight only int4/int8 (#10491)
* fix the bug in export deepseek_v2

* fix the deepseekv2 dynamic weight only int8

* fix

* fix

* update
2025-04-25 18:20:10 +08:00
Zhong Hui
f0c5aa2814 Fix predict import. (#10476) 2025-04-24 16:22:11 +08:00
co63oc
e8a19d361a Fix typos (#10483) 2025-04-24 12:02:41 +08:00
Echo-Nie
3a23130fa0 [PIR] Fix UIE (#10482) 2025-04-24 11:05:46 +08:00
Hanlin Tang
14bb7cfe7c [PIR] Create paddle.inference infer example of ernie-3.0-tiny (#10480) 2025-04-24 11:04:24 +08:00
Echo-Nie
d75d5ad904 [PIR] Fix ernie-vil2.0 (#10481) 2025-04-24 10:54:41 +08:00
Kunbo Ding
402e2e8494 [RL] Update reward training docs (#10473)
* update rm docs

* update rm docs
2025-04-24 10:51:23 +08:00
yulangz
323ffec4fa [XPU] support absorb mla, separate the model networking from GPU (#10353)
* 独立的,不和 GPU 混用的组网,现在还缺算子迁移过来

* update csrc

* fix

* fix

* 移除多余代码

* support infer param

* fix save output

* add warm script

* 组网剥离

* fix style

* update setup and remove useless files

* fused block attn

* hack 实现 int_wo MOE

* 多线程 mmlu 脚本

* mmlu 8K 输出

* add inference time for benchmark

* fix warm max_dec_len

* Revert "mmlu 8K 输出"

This reverts commit 0c89ea0fa7.

* Revert "多线程 mmlu 脚本"

This reverts commit fe6bfc5a3b.

* add high speed moe

* change rope cos sin to cpu

* fix save output
2025-04-23 20:47:12 +08:00
chen
2211480714 【infer】 predict_dy_insert support more inputs and append attn support excess_blocks input (#10446)
* support input input_ids, and all_rank_return in dy_insert

* refine code

* delete print

* fix kv_cache block mismatch block_table

* check input_ids len

* check input_ids len logger

* fix dy_insert cuda700, append attn support excess_blocks

* check empty_cache order

* check modeling forward input excess_blocks
2025-04-23 20:01:16 +08:00
l1cacheDell
345ff570ae [Triton Kernel] Add varlen segment mean triton kernel (#10369)
* upload triton kernel

* update kernel from review

* fix docstring

* update __init__
2025-04-23 19:55:30 +08:00
zhangyuqin1998
53273adb74 [Trainer] Add forward_backward_overlap_scheduler in pipeline_parallel_config (#10336)
* [Distributed] Add forward_backward_overlap_scheduler in pipeline_parallel_config

* fix codestyle
2025-04-23 17:14:03 +08:00
Liujie0926
671cf1accc [CI] Add timeout exception prompt for ci (#10450)
* fix paddlenlp build

* fix paddlenlp_ops install

* [CI] fix scripts

* exit_code=124

* fix

* add timeout

* add timeout for paddlenlp
2025-04-23 16:56:36 +08:00
co63oc
f65b90610e [Typos] Fix (#10290) 2025-04-23 15:51:51 +08:00
co63oc
e49945aea3 [Typos] Fix (#10289) 2025-04-23 15:46:40 +08:00
Hanlin Tang
fa8359d002 [PIR] Fix test_tipc configs/inference/docs (#10465) 2025-04-23 15:42:34 +08:00
Echo-Nie
5aa907c22c [PIR] Fix information_extraction (#10469) 2025-04-23 15:36:31 +08:00
Echo-Nie
46ebe6e67a [PIR] Fix lexical_analysis (#10470) 2025-04-23 15:36:05 +08:00
will-jl944
d80bce0469 In case dpo uses score-based loss (#10461) 2025-04-23 15:28:47 +08:00
lugimzzz
72e1994b38 add loralinear (#10385)
* add loralinear

* add wint8lora

* fix bug

* add a8w8linear

* add a8w8linear with hadamard

* support fused linear

* support backward

* support wint8

* add a8w8

* add a8w8

* fix following comments

* fix following comments
2025-04-23 15:12:49 +08:00
greycooker
843739d2fc [RL] Refactor code based on gloabl_batch_size (#10462)
* fix wandb proxy

* update num_return_sequences to rollout_n in .md and .json

* 当开启balance_batch的时候,强制prompt的input id需要padding到max_prompt_len

* fix

* fix all_reduce import for single card

* update with global_batch_size

* fix for acc<=0 or train_batch.shape[0] < batch_size

* revert micro upgrade

* fix data shape for multi dataset_world_size

* lint

* add hint

* update for dynamic sampling

* refoctor

* add warning for split_batch_into_micro_batches

* update logger info

* add pad_token_id for split_batch_into_micro_batches

* support prompt_key and prompt_key

* fix for compute_advantage_normalization and eos_mask

* update for args config

* enhance balance token

* add note

---------

Co-authored-by: DrownFish19 <DrownFish19@gmail.com>
Co-authored-by: yujun <573009727@qq.com>
2025-04-23 14:52:42 +08:00
Zong Wei
5d43923863 [INTEL_HPU] Enable Intel HPU fused multi transformer (#10284)
e2e integration

minial fix

refine code and remove unnecessary changes

integrate all fused ops, first fused op still need to optimize on
embedding.

reference pp kernels implementation

align final rms_norm shape with expected.

e2e shape fix

e2e bugs fix

e2e bugs fix2

e2e w/a cast place

e2e batchsize left padding fix

Refine _post_process code in generation_utils.py

combine k/v together

shape and benchmark

Refine Decoder Post-Processing HPU path code

fix multi-card perf benchmark hang issue

batch tokens early stop

optimize for-loop index

fsdpa and rmsNorm updates

code refine to reduce cpu operations

PP refine to remove cpu/gpu copy on python

support static graph mode execution

use cpu to concat all next_tokens to avoid compile and improve perf

fix static graph infer parameters corrupt

Co-authored-by: yanfeich <yanfei.cheng@intel.com>
2025-04-23 13:53:03 +08:00
zhangbo9674
ce7b4ccf35 Fix casual dataset bug (#10357)
* refine log

* fix bug
2025-04-23 11:52:58 +08:00
Weiguo Zhu
04e982f0bd fix (#10468) 2025-04-23 11:51:44 +08:00
Hanlin Tang
5392bdb612 [PaddleNLP No.18] Create new infer example validated on pd3.0 (#10422) 2025-04-23 11:50:08 +08:00
Hanlin Tang
fd22e8fc48 [PIR] Fix test cases (#10456)
* [PIR] Fix pir in comments

* [PIR] re-run pre-commit for pir in comments
2025-04-23 10:05:10 +08:00
Echo-Nie
c8ba30da8f [PIR] Fix ernie_text_matching (#10460)
* fix No33_NLP

* test
2025-04-23 10:03:35 +08:00
Echo-Nie
e9e3df5e37 [PIR] Fix inference_engine (#10466) 2025-04-23 09:56:26 +08:00
Hanlin Tang
55854f2f7d [PIR] Fix text_matching/ernie_matching (#10453) 2025-04-22 17:39:42 +08:00
yaqiang.sun
8e812f6fa6 [Application] Fix index bug for doccano convert (#10361)
Fix index bug for doccano convert
2025-04-22 17:38:35 +08:00
Zhong Hui
1a57b0a0c2 [DOC] Update model weights pages. (#10455)
* optimize_docs

* fix1

* fix2

* fix3

* change to github readme.

---------

Co-authored-by: jie-z-0607 <1712955306@qq.com>
Co-authored-by: Jie.Z <109219440+jie-z-0607@users.noreply.github.com>
2025-04-22 12:55:55 +08:00
chen2016013
9d0b63af34 update_llama_conf_cinn_0218 (#10006)
* update_llama_conf_cinn_0218

* update

* fix llama 13b

* Update run_benchmark.sh

* Update run_benchmark.sh

---------

Co-authored-by: liym27 <33742067+liym27@users.noreply.github.com>
2025-04-22 11:36:29 +08:00
chen
be45d21a94 [BugFix] Fix get_output serving (#10457)
* fix get_output serving

* change queue_id to msg_queue_id
2025-04-22 11:01:55 +08:00
Hanlin Tang
f071343332 [PIR] Fix sentiment_analysis (#10454) 2025-04-22 09:31:29 +08:00
zhangyuqin1998
f53e113c61 [Fix] fix recompute (#10452)
* [Fix] fix recompute

* fix codestyle
2025-04-21 16:08:44 +08:00
Hanlin Tang
031ff474cd [PIR] Fix machine_reading_comprehension SQuAD (#10445)
* [PIR] fix machine_reading_comprehension squad

* Update README.md
2025-04-21 13:10:57 +08:00
chen
d24ec24a08 [infer] Fix per_token_group_quant and support per_tensor_quant (#10359)
* support per_tensor_quant and per_token_group_quant

* check

* add per_token_group_quant, per_tensor_quant_fp8 into pybind_ops_list
2025-04-21 11:20:39 +08:00
greycooker
737a67949f [RL] Fix padding_side (#10448) 2025-04-21 09:35:18 +08:00
Kunbo Ding
97b7af4495 [RL] Fix flashmask reward training (#10443)
* [RL] Fix flashmask reward training

* [RL] Fix flashmask reward training

* [RL] Fix flashmask reward training

* [RL] Fix flashmask reward training
2025-04-18 18:07:52 +08:00
yujun
b3e99ef2ee [RL] Support balance batch (#10444) 2025-04-18 17:10:27 +08:00
chen
f889167043 [Infra] support dynamic_insert in dynamic run (#10387)
* support dynamic_insert in dynamic run

* remove duplicate code

* add save_output_dygraph op

* check pybind op

* note off

* code check

* check mla pybind function signature

* check pybind and batch_size

* support multi-proc save_output and get_output

* check pybind block gemm

* support pybind custom_import in dynamic run

* support non-msg queue stream output in dynamic insert

* check queue_id in d2s, and add sm80 sm90 for pybind

* check pybind for build_wheel.sh

* USE_PYBIND=False

* implement custom_import as context management and decorator

* code check

* add doc for pybind and dynamic_insert

* check

* change USE_PYBIND_CUSTOM_OPS to DYNAMIC_INFERENCE_MODE

* check doc

* code check

* check dynamic_insert debug

* check task_queue is empty when dynamic insert exit

* fix blocking when output_via_mq=1 in dynamic_insert
2025-04-18 16:57:18 +08:00
Zhong Hui
9e64bd09c6 Fix tutorial2 (#10442)
* fix tutorial

* fix

* fix link.
2025-04-18 15:05:22 +08:00
Weiguo Zhu
e887c44492 [Tools] Add Script for Torch Parameters Conversion (#10303)
* add

* format

* update name
2025-04-18 14:54:28 +08:00
Weiguo Zhu
c3091ebead [Inference] Fix for fused_qkv (Qwen2) (#10372)
* fix for fused_qkv

* update to  direct concat mode
2025-04-18 14:17:24 +08:00
Weiguo Zhu
0074e7e575 [Tokenizer] Compatible with the padding_side in _pad (#10423)
* Compatible with the padding_side

* Compatible with the padding_side

* fix
2025-04-18 12:10:39 +08:00
Hanlin Tang
d5b98565bc [PIR] update document_intelligence.py (#10394) 2025-04-18 12:05:49 +08:00
Hanlin Tang
045115a083 [PIR] Fix milvus (#10397) 2025-04-18 12:05:03 +08:00
Zhong Hui
5d8b59390e Fix fail ci Part2 (#10411)
* fix failed ci. part1

* fix ci part 2.

* fix all ci.
2025-04-18 10:56:59 +08:00
Weiguo Zhu
f62b248c16 [LLM] Fix the communication group settings in the moe_layer (#10441) 2025-04-18 10:55:49 +08:00
AIbin
5636299659 【Inference Fix】del while about predict (#10440)
* del while

* del while
2025-04-17 19:55:05 -07:00
Weiguo Zhu
5b161bb490 [Py38] Fix import issue (#10410)
* fix import

* fix import
2025-04-18 10:54:36 +08:00
Zhong Hui
7d6417bc1d Fix tutorial readme (#10432)
* fix tutorial

* fix
2025-04-17 20:03:42 +08:00
jzhang533
8521f027dc Update quick start codes in README.md (#10431)
Signed-off-by: Zhang Jun <jzhang533@gmail.com>
2025-04-17 16:43:18 +08:00
waliwali777
bc06b8a09e [Auto-Parallel] add test of fuse comm sharding optimize in dynamic auto mode (#10403)
* add fuse comm sharding test

* fix

* update

* fix

* add loss base

* update loss base

* fix

* fix ips

* fix
2025-04-17 15:22:30 +08:00
Hanlin Tang
1d5591bdab [PIR] Fix ernie-1.0 infer example and make it compatible with pd3.0.0 (#10426) 2025-04-17 10:18:01 +08:00
greycooker
e6e4928efa 【RL】Add DAPO (#10380)
* add dapo

* fix dapo

* fix conflict
2025-04-17 09:43:23 +08:00
gongel
d85474029a [RL] Add reshard for RL (#10412)
* add reshard

* fix eval
2025-04-16 20:35:24 +08:00
ltd0924
648f051a39 Fix message format type error (#10428) 2025-04-16 19:32:50 +08:00
Weiguo Zhu
9f5b697330 [CI] Fix workflows (#10417) 2025-04-16 12:58:59 +08:00
Function-Samuel
ce7550f6cf [Benchmark] Add baichuan2-13b dynamic auto benchmark (#10384)
* Add baichuan2-13b dynamic auto benchmark

* add FLAGS_fuse_reducescatter_in_opt

* add_hidden_layers

* fix
2025-04-16 10:57:35 +08:00
Hanlin Tang
92d6472fc2 [PIR] Fix cross encoder (#10398) 2025-04-16 09:30:36 +08:00
Hanlin Tang
65391cf483 [PIR] fix ernie_matching (#10399) 2025-04-16 09:29:42 +08:00
zhink
e48148d8c2 [Infra] Add custom all reduce (#10375)
* add custom all reduce

* cleanup_custom_ar safe
2025-04-15 11:56:40 +04:30
will-jl944
4e2fdf3f18 support setting min_lr for cosine lr scheduler (#10393) 2025-04-15 10:37:03 +04:30
zhengzhonghui
b98d8f850d Fix bug of calling TensorParallel multiple times (#10408) 2025-04-15 10:51:17 +08:00
Zhong Hui
d8f9caaa7f Fix failed ci. part1 (#10341) 2025-04-15 10:10:20 +08:00
dongzezhao
3e49b74908 Add pid and start timestamp to metrics dump (#10142)
* Add pid and start timestamp to metrics dump (#10142)

* Add pid and start timestamp to metrics dump

* update start timestamp

* update
2025-04-14 20:39:10 +08:00
Weiguo Zhu
4bf7945ea7 [RL] Update comments to English version (#10400) 2025-04-14 18:14:30 +08:00
AIbin
f232d82d20 [Inference Optimize] Support qwen2.5vl & deepseekvl2 language models to convert to static graph execution (#10377)
* qwen&deepseek_static

* update where

* update deepseek

* update __all__ qwen2

* update __all__ qwen2

* update code

* update deepseek modeling about multimodal inputs_embeds

* update qwen vl model
2025-04-14 11:19:09 +08:00
Zhong Hui
a153370f0d [DOC] Fix dead link (#10343) 2025-04-14 10:19:01 +08:00
Hanlin Tang
e3ed3a30b0 [PIR] update for server/engine/infer.py (#10379) 2025-04-11 15:04:29 +08:00
AIbin
ca1dcc85f2 【Inference Fix Bug】 fix moe_expert_reduce op output shape (#10390)
* fix moe_export_reduce op output shape

* fix moe_expert_reduce op output shape
2025-04-10 23:43:14 -07:00
Wennie396
5dca755f22 【Cherry-pick】add split_norm_comm to split global_norm comm to pp_comm & mp_comm (#10334) (#10368) 2025-04-11 11:37:01 +08:00
waliwali777
50c41840a4 add FLAGS_fuse_reducescatter_in_opt for llama7b benchmark (#10378) 2025-04-11 10:49:27 +08:00
Weiguo Zhu
3b97a283e7 [RL] Refactor code for PPO/GRPO/Reinforce++ Part2 (#10376)
* fix predict for colocate mode

* refoctor

* refactor

* add label_key for new load_dataset method

* fix

* rename  compute_reward to compute_value in critic_trainer
2025-04-11 10:12:11 +08:00
lugimzzz
41706b5b3c fix wint8 inference bug (#10383) 2025-04-11 10:07:18 +08:00
周周周
75550d87cb commit (#10381) 2025-04-10 21:37:55 +08:00
Tian
ae3d5def7f [LLM] fix metrics dumper (#10382) 2025-04-10 19:57:09 +08:00
Hanlin Tang
54c3ec31bf [PIR] Fix in-batch negative recall model for neural_search (#10352) 2025-04-10 19:36:28 +08:00
Weiguo Zhu
ae355c0b35 fix for auto_parallel (#10370) 2025-04-10 09:50:13 +08:00
Weiguo Zhu
d5275b72b0 fix predict for colocate mode (#10373) 2025-04-09 21:34:51 +08:00
Liujie0926
e67789d588 [CI]fix paddlenlp build (#10362)
* fix paddlenlp build

* fix paddlenlp_ops install
2025-04-09 17:07:00 +08:00
Weiguo Zhu
6be4378b1a [CI] Fix tensro_broadcast issues (#10364)
* fix

* fix
2025-04-09 16:19:28 +08:00
Function-Samuel
d2299b1416 remove hidden layers (#10354) 2025-04-09 14:45:16 +08:00
Function-Samuel
a2997336f4 add mem monitor (#10358) 2025-04-09 14:44:59 +08:00
Weiguo Zhu
4b2ae58158 [RL] Refactor code for PPO/GRPO/Reinforce++ (#10310)
* tmp update

* 对应数据流,修改infer的部分直接接收token id

* drop last

* 添加环境变量 JINGDUDUIQI

* add reinforce++

* rm info

* 新增actor_fused_pg_entropy_kl_loss

* 添加fused head loss计算

* entropy_loss

* update

* update

* 修复total_entropy_loss的错误,新增all reduce sum

* 新增optimizer的offload

* add fp32 compute

* support sharding training, add args logprob_batch_size

* per_device_eval_batch_size不能大于self.per_device_rollout_batch_size * self.num_return_sequences

* update rollout_logprob_batch_size

* 新的计算entropy梯度的方法,与原始计算等价,新增final_loss,解决entropy loss和kl loss都关闭的情况的梯度bug

* 支持32B

* sequence parallel支持动态padding到tp的倍数

* 默认关闭entropy_coeff,使用kunbo的fused head loss

* set attr save_output

* 修复temperature先除后除的bug,目前全部在fused算子里面除以.

* 修复entropy loss在tp情况下的问题,需要对entropy_loss_chunk进行all_reduce

* add pure_policy_loss and entropy_loss

* 修复entropy_from_logits的问题,使用pylayer实现VocabParallelEntropy

* update

* remove ptx

* truncation True, max_src_len

* support dataproto & fix dataflow

* update trainer

* rm shell

* 删除一些无用的修改

* update

* update user

* add use_fused_head_and_loss_fn

* fix infer utils

* update

* 中间版本

* temporary version

* temporary version

* temporary version

* temporary version

* no diff (without timer)

* fix prediction_step

* lint

* lint

* update timer_scope and compute_adv

* update compute logprob

* update reward and critic

* update

* update for dev

* update

* fix

* update fused_rms_norm

* fix import

* update inference and timers

* update timers

* update

* lazy_guard

* update

* lint

---------

Co-authored-by: yujun <573009727@qq.com>
Co-authored-by: gongenlei <>
Co-authored-by: yujun <50394665+JunnYu@users.noreply.github.com>
Co-authored-by: gongenlei <gongenlei@baidu.com>
Co-authored-by: greycooker <526929599@qq.com>
2025-04-09 13:05:18 +08:00
lugimzzz
fb694169e4 support wint8 (#10319)
* support wint8

* support wint8

* support wint8

* support wint inferenece

* fix little bug

* support wint8

* support wint8

* support wint8

* fix new bug
2025-04-09 11:56:51 +08:00
AIbin
91b510dc32 【Inference Optimize】Controls whether the message queue is enabled for output (#10185)
* fix mix model save_output

* update enable_stream_output

* del import tokenizer

* update config name

* Reduce redundant member variables
2025-04-08 13:25:57 +08:00
Tian
d53e8cf45e [LLM] release zero cost checkpoint (#10337)
* [LLM] Implement Flash Checkpoint (#9658)

* [LLM] add _save_checkpoint_flash for LLM

* [LLM] cache metas for saving in flash mode

* [LLM] get fused param from optimizer

* [LLM] save model state with plain API

* [LLM] implement flash checkpoint manager and worker

* [LLM] reformat flash checkpoint codes

* [LLM] Add flash save steps (#9664)

* [LLM] process PDC_FLASH_INIT_STEP in ft env

* [LLM] add flash_save_steps

* [LLM] fix compatibility for paddle of old version (#9667)

* [LLM] get sharding meta on all ranks (#9675)

* [LLM] enhance paddle recall for flash checkpoint (#9684)

* [FlashCheckpoint] support EMA (#9815)

* [FlashCheckpoint] support EMA

* refactor: move [flash checkpoint manager] to callback

* [flashcheckpoint] fix save under dp_degree > 1 with use-expert-parallel

* flash-checkpoint EMA: fix cpu mem

* Fc ema v2 (#9909)

* polish ZCC-EMA, remove opt offload

* polish code

* [LLM] format zcc codes

---------

Co-authored-by: Meiyim <chenxuyi@baidu.com>
2025-04-05 11:04:50 +08:00
Function-Samuel
64c0d04130 [test] match filename with model name (#10338)
* fix

* fix
2025-04-03 14:09:34 +08:00
Siming Dai
bfd053db08 [Unified Checkpoint] update moe (#10282)
* update moe

* fix optimizer moe

* update lora moe
2025-04-03 11:11:57 +08:00
LiYuRio
a8f83e3d07 Support dynamic pp scheduler in pp (#9861) (#10329) 2025-04-03 10:15:09 +08:00
Zero Rains
94142af83f [FIX] fix the bug for moe_gemm config searching in sm86 (#10325)
* fix the bug for moe_gemm config searching  in sm86

* rerun
2025-04-02 11:58:09 +08:00
Zhong Hui
4c61882b46 Support parse_yaml files. (#10321) 2025-04-02 11:25:24 +08:00
AIbin
eec767ed47 [Inference Optimize] Support MOE EP Parallel 2. fix moe_export_reduce bug (#10323)
* support MOE EP Parallel 2. fix moe_export_reduce bug

* format

* update
2025-04-01 20:48:42 +08:00
bukejiyu
4f578b9519 [Doc] update lm-serving-cuda124-cudnn9-v2.3 (#10315)
* update doc

* update images

* update
2025-04-01 19:32:57 +08:00
Yuanle Liu
5bf06241cb Fix bug pre_ids length (#10312) 2025-03-31 14:49:42 +08:00
Zhong Hui
88ca820e2b [Deprecated] Delete few used model and tools. (#10279)
* delete few used model and tools.

* fix
2025-03-31 12:06:23 +08:00
Zhong Hui
c050c6a392 Fix load torch. (#10246)
* fix load torch.

* Update serialization.py

* Update serialization.py

* re lint.
2025-03-31 11:35:08 +08:00
Zhong Hui
9df673c499 [Docs] Move docs to docs/zh (#10261)
* move docs to /docs/zh

* fix

* v1 with gpt-4o

* add deepseek part1.

* add deepseek translate part2.

* fix .readthedocs.yaml

* fix yaml.

* fix readme.

* update.

* optimizer docs.

* refine docs.
2025-03-31 09:58:04 +08:00
bukejiyu
81d7bace77 [inference]Update doc (#10278)
* update doc
2025-03-28 17:35:07 +08:00
Zhong Hui
36a8fb3273 Update index.rst (#10295)
* Update index.rst

* Update index.rst

* Update index.rst
2025-03-28 17:09:10 +08:00
yujun
d0752f383c Enhance RLHF (#10123)
* tmp update

* 对应数据流,修改infer的部分直接接收token id

* drop last

* 添加环境变量 JINGDUDUIQI

* add reinforce++

* rm info

* 新增actor_fused_pg_entropy_kl_loss

* 添加fused head loss计算

* entropy_loss

* update

* update

* 修复total_entropy_loss的错误,新增all reduce sum

* 新增optimizer的offload

* add fp32 compute

* support sharding training, add args logprob_batch_size

* per_device_eval_batch_size不能大于self.per_device_rollout_batch_size * self.num_return_sequences

* update rollout_logprob_batch_size

* 新的计算entropy梯度的方法,与原始计算等价,新增final_loss,解决entropy loss和kl loss都关闭的情况的梯度bug

* 支持32B

* sequence parallel支持动态padding到tp的倍数

* 默认关闭entropy_coeff,使用kunbo的fused head loss

* set attr save_output

* 修复temperature先除后除的bug,目前全部在fused算子里面除以.

* 修复entropy loss在tp情况下的问题,需要对entropy_loss_chunk进行all_reduce

* add pure_policy_loss and entropy_loss

* 修复entropy_from_logits的问题,使用pylayer实现VocabParallelEntropy

* truncation True, max_src_len

* rm shell

* 删除一些无用的修改

* update user

* add use_fused_head_and_loss_fn

* fix infer utils

---------

Co-authored-by: gongenlei <>
Co-authored-by: gongenlei <gongenlei@baidu.com>
2025-03-28 17:04:54 +08:00
gaoziyuan
5ff3797425 [Inference]migrate some moe file (#10292)
* migrate some moe file

* fix name
2025-03-28 15:58:08 +08:00
ltd0924
f6100806a4 [Serving] 支持配置version (#10293)
* [Serving] 支持配置version

* [Serving] 支持配置version
2025-03-28 15:35:48 +08:00
co63oc
4710fbcb8f Fix typos in multiple files (#10224)
* Fix
2025-03-27 19:19:49 +08:00
Function-Samuel
f607bad70b Add dynamic llama2-7b benchmark (#10271)
* add dynamic llama 7b benchmark

* rename dynamic suffix

* fix

* rename file

* fix

* fix

* fix

* fix
2025-03-27 14:51:28 +08:00
Yuanle Liu
712495cfc3 [MLA] move compute_out_linear out and fix bug when q_lora_rank is None (#10275) 2025-03-26 20:25:45 +08:00
AIbin
2d40d82d6e 【Inference Optimize】support MOE EP Parallel 1. (#10266)
* support MOE EP Parallel 1.

* support MOE EP Parallel 1. Changed from nranks to tp_degree
2025-03-26 19:27:15 +08:00
chen
a0c08bacb5 【Infer】MLA matrix absorption separation (#10249)
* bf16 batch gemm

* bf16 and wint8 matrix_absorption
2025-03-26 19:26:49 +08:00
Zhuoqun Li
27fa252d4e [Embedding] Add LLARA-passage and bge-en-icl with benchmark (#9887)
* move modeling.py and modeling_nv.py to transformers

* move modeling.py and modeling_nv.py to transformers and replace einops

* move modeling.py and modeling_nv.py to transformers and simplify import path

* move modeling.py and modeling_nv.py to transformers and add test_modeling

* add llara

* fix previous bug

* add bge-en-icl

* add nv-max_seq_length and update requirement

* delete irrelavent content

* update readme and delete irrelavent content

* update readme

* update readme

* update readme

* update msmarco-title file using

* update readme's paddle install

* Organize results and update readme

* update readme

* update readme

* update readme

* update readme

* add reocket qa eval_mteb.sh

* 适配RocketQA (#1)

Co-authored-by: Zhuoqun Li <2305932025@qq.com>

* update eval_mteb.sh and readme

* update eval_mteb.sh and readme

* fix modeling lint fail

* update readme and eval_mteb.sh

* update readme and eval_mteb.sh

* update readme and eval_mteb.sh

* update readme and eval_mteb.sh

* check run ok

* update results in readme

* add recall_at_10

* update recall_10 to readme

* update recall_10

* add mrr_10 and r_10 for mteb

* add scifact mrr_10 and r_10 for mteb

* fix tests

* fix tests

* fix tests

* fix tests

---------

Co-authored-by: Qiming Zhu <58735353+dfmz759837901@users.noreply.github.com>
2025-03-26 11:39:42 +08:00
liufengwei0103
0b09793921 [AutoParallel]: fix auto parallel json config error (#10126)
* [AutoParallel]: fix auto parallel json config error, test=document_fix

* fix log dir, test=document_fix
2025-03-26 10:40:07 +08:00
ooo oo
990d2b698b reopen test for zero-dim tensor (#10242) 2025-03-25 17:48:09 +08:00
bukejiyu
b62530e8bd update (#10255) 2025-03-25 14:36:15 +08:00
Weiguo Zhu
e44986b8e1 [Application] Update distill readme (#10260)
* update eval script

* update readme

* update docs

* update links
2025-03-25 12:03:44 +08:00
Yuanle Liu
f1840d549b fix src_length when --benchmark (#10237) 2025-03-25 11:27:05 +08:00
lugimzzz
be1429fbe5 fix dpop loss (#10239) 2025-03-24 21:05:35 +08:00
Zhong Hui
5b505e487b [Docs] Refactor docs. (#10223)
* refactor docs.

* Refine typos.
2025-03-24 14:39:54 +08:00
ZhenxingLi
7e0885d3d4 [AutoParallel] Add auto parallel DPO docs (#10234)
* update

* Update README.md
2025-03-24 11:55:21 +08:00
Chang Lu
d1e156af9f [Doc] add xpu doc and update llama xpu scripts (#10148)
* add xpu doc

* Update auto_trainer.py

* update amp custom list
2025-03-21 14:53:49 +08:00
lugimzzz
6bde6a2204 [LLM] fix pir problem (#10235)
* fix pir problem

* fix pir problem
2025-03-21 13:17:50 +08:00
ZhenxingLi
9fead81836 [AutoParallel] Add_llama_dpo_auto_parallel_intermediate (#10044)
* dpo_auto_intermediate

* add dpo ci dataset

* update flash_mask

* update

* update path

* update download data

* update

* update

* update

* update

* Update

* update

* Update dpo_auto_trainer.py

* Update ci_case_auto.sh

* Update ci_case_auto.sh

* Update dpo_argument.py

* Update run_dpo_auto.py

* Update dpo_criterion.py

* Update trl_data.py
2025-03-20 16:32:05 +08:00
bukejiyu
d9644fc339 [Inference] fix cpu install (#10218) 2025-03-20 16:12:18 +08:00
chen
f131d62d76 【Bug Fix】Fix triton_moe shape error (#10216) 2025-03-20 00:10:59 -07:00
co63oc
3925efcea4 Fix typos in multiple files (#10115) 2025-03-20 11:18:29 +08:00
aooxin
104e304e3b [LLM] Add Minimax-Text-01 (#9893)
* add minimax-text-01 model, init.

* fix path bugs.

* add model.

* fix _get_name_mappings.

* forward pass.

* fix MiniMaxText01ForCausalLM bugs.

* add copyright.

* fix MiniMaxText01ForSequenceClassification bugs.

* fix MiniMaxText01ForSequenceClassification bugs .

* add unittest.

* add test init.

* add @require_gpu.
2025-03-20 11:06:05 +08:00
Guanbin_whu
2233a476dc Save config file for inforence in automatic parallel training (#10175)
* save config file

* isort

* pre-commit check

* use _save function to save config, change the code structure

* change the code sturcture

* change the code sturcture

---------

Co-authored-by: jeff41404 <jeff41404@gmail.com>
2025-03-20 10:23:28 +08:00
lizhenyun01
d45bbf56a6 support mla while num_head=128 (#10168) 2025-03-19 05:38:10 -07:00
Liujie0926
bf473768d8 [CI]update upload for ci (#10135)
* update upload for ci

* add build.sh

* fix

* fix paddleocr error

* fix build

* fix

* fix

* del paddlenlp_ops upload

* cp paddlenlp_ops

* fix paddlenlp_ops bos

* fix upload
2025-03-19 17:39:07 +08:00
Liujie0926
98b084f69d [CI]fix bug for deepseek_data & paddleocr2.10_install & paddlenlp_ops whl (#10183)
* fix deepseek_data & paddleocr2.10_install

* update paddlenlp_ops bcebos
2025-03-19 16:43:54 +08:00
ltd0924
d1e956e6e1 [LLM] add port check and fix bugs (#10153) (#10195)
* [LLM] add port check and fix bugs

* [LLM] fix stream output

* [LLM] delete unused param

* [LLM] fix start script
2025-03-19 15:03:01 +08:00
Zhong Hui
f3e85d40db Delete dead links (#10188)
* Update README.md

* Delete docs/llm/auto_parallel/llama/README.md
2025-03-19 12:56:38 +08:00
freeliuzc
d234592a91 [Docs] update_docs (#10180) 2025-03-18 17:15:22 +08:00
Function-Samuel
9d6f81bb54 [Benchmark] modify config (#10181) 2025-03-18 17:14:30 +08:00
ZhenxingLi
33998272bc Update auto_trainer.py (#10170) 2025-03-18 16:22:10 +08:00
waliwali777
4afa702903 Add auto_parallel_sync_shared_params pass flag (#10057)
* fix gpt auto embedding dims_mapping[-1,1]

* add auto_parallel_sync_shared_params flag

* fix
2025-03-18 15:27:22 +08:00
waliwali777
5faa8ee771 [benchmark] Open rc for gpt (#10160) 2025-03-18 15:26:48 +08:00
Jie.Z
e8ad2fa854 Add Contrastive Learning (#10097)
* add_contrastive_learning
2025-03-18 14:38:38 +08:00
yulangz
4ed355a03a [Inference] Support deepseek on xpu (#10060)
* support deepseek on xpu

* remove useless comment

* fix

* support serving
2025-03-18 14:37:12 +08:00
Jie.Z
5475a8a067 Add XLMRoberta in Embedding Train (#10074)
* add xlmroberta in embedding train
2025-03-18 14:34:50 +08:00
gaoziyuan
63c4ea47b0 [Inference] Migrate MoE Kernel from Paddle Inner (#10063)
* save

* backup

* add moe_dispatch&moe_reduce

* add dongzhuanjing

* fix dispatch precis

* rm cutlass_extention

* add zkk inner commit

* fix

* add fused_moe

* add glog third party

* add fused_moe

* formar code style

* fix

* rm gemm config

* add test

* fix

* fix

* fix glog install

* add yazhu fix

* fix

* fix

* fix

* rm glog

* fix

* fix

* fix

* fix glog

* fix

* fix ci
2025-03-18 14:33:10 +08:00
zhaohaixu
550a558707 [predict] fix ddp bug for predict benchmark. (#10171) 2025-03-17 20:28:57 -07:00
Zero Rains
d7250f06bb Fix the bug in tiny_fused_bloom::test_wint8 (#9307) 2025-03-18 11:03:37 +08:00
Zhong Hui
8e213b4691 Update README.md (#10167)
DeepSeek-R1满血版单机部署实测
2025-03-17 20:26:23 +08:00
Weiguo Zhu
8fcd2ee5e3 [Application] Distill and finetune LLM (#10061)
* add distill files

* update

* add requirements.txt

* update filename and add readme

* update readme

* update

* update requirement.txt

* update

* update readme

* update table
2025-03-17 20:23:48 +08:00
lizhenyun01
8c57cc1497 [Hot Fix] hotfix for param decoder_chunk_size_cpu (#10111) 2025-03-17 01:31:14 -07:00
Function-Samuel
2415083412 fix (#10139) 2025-03-17 14:48:07 +08:00
Yuanle Liu
4fe19817d3 [Tools] add tool safetensors_filter (#10140)
* add tool safetensors_filter

* add metadata

* add comment

* add comment
2025-03-16 22:50:55 -07:00
xuxinyi389
2703ea15da [AutoParallel] Add ci for deepseek-v3 (#10064)
* add_ci

* fix

* fix

* open test on a100
2025-03-17 11:49:03 +08:00
AIbin
1998914d8f [Hot Fix] hotfix for param decoder_chunk_size_cpu (#10144)
* support qwen2_5_vl

* support qwen2_5_vl

* fix bug

* update support qwen2_vl & qwen2_5_vl & support multi models mapping

* fix BUG
2025-03-16 20:05:44 -07:00
liufengwei0103
b141f86d6a [AutoParallel]: fix bug because of renaming file (#10132) 2025-03-17 11:05:04 +08:00
Function-Samuel
44144a5753 Support reshard attention mask in intermediate_api (#10137)
* support reshard attention mask in intermediate_api

* fix_test

* set pp=1 in intermediate test case

* fix

* fix

---------

Co-authored-by: liym27 <33742067+liym27@users.noreply.github.com>
2025-03-17 10:57:20 +08:00
l1cacheDell
dd774f1223 [Hot Fix] hotfix for param decoder_chunk_size_cpu during LLM inferencing (#10141)
* hotfix for a param

* bugfix2
2025-03-14 05:28:52 -07:00
Guspan Tanadi
42ba2c0ad2 [docs]: update section links (#9717)
* docs(compression): section links

* docs(compression): section links step
2025-03-13 17:50:35 +08:00
liym27
1056fd7599 [AutoParallel] Pre alloc memory (#9979) 2025-03-13 15:56:55 +08:00
blacksheep-Aristotle
24039c6701 fix reshard_qkv alltoall error (#9949) 2025-03-13 15:01:11 +08:00
2282 changed files with 110891 additions and 40356 deletions

41
.github/actions/check-bypass/action.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: "Check bypass"
description: "A custom action to encapsulate PFCCLab/ci-bypass"
inputs:
github-token:
description: "GitHub token"
required: true
workflow-name:
description: "Workflow name"
required: true
outputs:
can-skip:
description: "Whether the workflow can be skipped."
value: ${{ steps.check-bypass.outputs.can-skip }}
runs:
using: "composite"
steps:
- id: check-bypass
name: Check Bypass
env:
CI_TEAM_MEMBERS: '["tianshuo78520a", "swgu98", "risemeup1", "XieYunshen","luotao1","From00"]'
uses: PFCCLab/ci-bypass@v1
with:
github-token: ${{ inputs.github-token }}
non-pull-request-event-strategy: 'never-skipped'
type: 'composite'
composite-rule: |
{
"any": [
{
"type": "labeled",
"label": ["skip-ci: ${{ inputs.workflow-name }}", "skip-ci: all"],
"username": ${{ env.CI_TEAM_MEMBERS }}
},
{
"type": "commented",
"comment-pattern": [".*/skip-ci ${{ inputs.workflow-name }}.*", ".*/skip-ci all.*"],
"username": ${{ env.CI_TEAM_MEMBERS }}
}
]
}

View File

@@ -0,0 +1,30 @@
name: 'Rerun Workflow'
description: 'Re-run GitHub Actions workflow for a given Pull Request'
inputs:
GITHUB_TOKEN:
description: 'GitHub token with repo scope'
required: true
OWNER:
description: 'Repository owner'
required: true
REPO:
description: 'Repository name'
required: true
PR_ID:
description: 'Pull Request ID'
required: true
JOB_NAME:
description: 'Job name to rerun'
required: true
runs:
using: 'composite'
steps:
- run: bash ./.github/actions/rerun-workflow/rerun.sh
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }}
OWNER: ${{ inputs.OWNER }}
REPO: ${{ inputs.REPO }}
PR_ID: ${{ inputs.PR_ID }}
JOB_NAME: ${{ inputs.JOB_NAME }}

77
.github/actions/rerun-workflow/rerun.sh vendored Normal file
View File

@@ -0,0 +1,77 @@
# Copyright (c) 2025 PaddleNLP Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e
COMMIT_SHA=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
"https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_ID" | jq -r '.head.sha')
echo "Commit SHA: $COMMIT_SHA"
response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
"https://api.github.com/repos/$OWNER/$REPO/actions/runs?head_sha=$COMMIT_SHA&per_page=100")
echo "Response: $response"
run_ids=$(echo "$response" | jq -r '.workflow_runs[].id')
if [ -n "$run_ids" ]; then
echo "Found run_ids for commit $COMMIT_SHA: $run_ids"
for run_id in $run_ids; do
if [ "$JOB_NAME" = "all-failed" ]; then
echo "Rerunning all failed jobs for run_id: $run_id"
rerun_response=$(curl -X POST -s -w "%{http_code}" -o /dev/null \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
"https://api.github.com/repos/$OWNER/$REPO/actions/runs/$run_id/rerun-failed-jobs")
if [ "$rerun_response" -eq 201 ]; then
echo "Successfully requested rerun for all blocked jobs in run_id: $run_id"
else
echo "Failed to request rerun for run_id: $run_id with status code $rerun_response"
fi
else
jobs_response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
"https://api.github.com/repos/$OWNER/$REPO/actions/runs/$run_id/jobs")
echo "Jobs Response for run_id $run_id: $jobs_response"
# if [[ "$JOB_NAME" == *"bypass"* ]]; then
block_jobs=$(echo "$jobs_response" | jq -r --arg job_name "$JOB_NAME" \
'.jobs[] | select(.name == $job_name) | .id')
# else
# block_jobs=$(echo "$jobs_response" | jq -r --arg job_name "$JOB_NAME" \
# '.jobs[] | select(.name == $job_name and .conclusion != "success") | .id')
# fi
if [ -n "$block_jobs" ]; then
echo "Found block jobs for run_id $run_id: $block_jobs"
for job_id in $block_jobs; do
echo "Rerunning job_id: $job_id"
curl -X POST -H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token $GITHUB_TOKEN" \
"https://api.github.com/repos/$OWNER/$REPO/actions/jobs/$job_id/rerun"
done
else
echo "No block jobs found for run_id $run_id with name $JOB_NAME."
fi
fi
done
else
echo "No matching workflow runs found for commit $COMMIT_SHA."
exit 1
fi

View File

@@ -0,0 +1,47 @@
name: PaddleFormers PR Check
on:
pull_request:
types: [opened, synchronize]
env:
BRANCH: ${{ github.base_ref }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_ID: ${{ github.event.pull_request.number }}
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
token: ${{ vars.ACTION_GITHUB_TOKEN }}
jobs:
check-approvers:
name: Check approval
runs-on:
group: APPROVAL
steps:
- name: Cleanup
run: |
rm -rf * .[^.]*
- name: Update paddle
run: |
wget -q --no-proxy https://xly-devops.bj.bcebos.com/PaddleTest/PaddleNLP/PaddleNLP-develop.tar.gz --no-check-certificate
tar zxf PaddleNLP-develop.tar.gz --strip-components=1 >/dev/null
rm -rf PaddleNLP-develop.tar.gz >/dev/null
git fetch origin pull/${PR_ID}/head
git checkout -b origin_pr FETCH_HEAD
git remote add upstream https://github.com/PaddlePaddle/PaddleNLP.git
git fetch upstream
git checkout -b test_pr upstream/${BRANCH}
git merge --no-edit origin_pr
git log --pretty=oneline -10
- name: Check bypass
id: check-bypass
uses: ./.github/actions/check-bypass
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
workflow-name: approval
- name: Display Required Approvers
if: steps.check-bypass.outputs.can-skip != 'true'
run: |
cd scripts/ci_approval
bash run_ci_approval_cherry-pick.sh

47
.github/workflows/approval.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
name: Approval
on:
pull_request:
types: [opened, synchronize]
env:
BRANCH: ${{ github.base_ref }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_ID: ${{ github.event.pull_request.number }}
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
token: ${{ vars.ACTION_GITHUB_TOKEN }}
jobs:
check-approvers:
name: Check approval
runs-on:
group: APPROVAL
steps:
- name: Cleanup
run: |
rm -rf * .[^.]*
- name: Update paddle
run: |
wget -q --no-proxy https://xly-devops.bj.bcebos.com/PaddleTest/PaddleNLP/PaddleNLP-develop.tar.gz --no-check-certificate
tar zxf PaddleNLP-develop.tar.gz --strip-components=1 >/dev/null
rm -rf PaddleNLP-develop.tar.gz >/dev/null
git fetch origin pull/${PR_ID}/head
git checkout -b origin_pr FETCH_HEAD
git remote add upstream https://github.com/PaddlePaddle/PaddleNLP.git
git fetch upstream
git checkout -b test_pr upstream/${BRANCH}
git merge --no-edit origin_pr
git log --pretty=oneline -10
- name: Check bypass
id: check-bypass
uses: ./.github/actions/check-bypass
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
workflow-name: approval
- name: Display Required Approvers
if: steps.check-bypass.outputs.can-skip != 'true'
run: |
cd scripts/ci_approval
bash -x run_ci_approval.sh

52
.github/workflows/check-bypass.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
on:
workflow_call:
inputs:
workflow-name:
required: true
type: string
secrets:
github-token:
required: true
outputs:
can-skip:
description: "Whether the workflow can be skipped."
value: ${{ jobs.check-bypass.outputs.can-skip }}
jobs:
check-bypass:
name: Check bypass
runs-on:
group: APPROVAL
permissions:
contents: read
env:
CI_TEAM_MEMBERS: '["tianshuo78520a", "swgu98", "risemeup1" , "XieYunshen","luotao1","From00"]'
outputs:
can-skip: ${{ steps.check-bypass.outputs.can-skip }}
steps:
- name: Cleanup
run: |
rm -rf * .[^.]*
- id: check-bypass
name: Check Bypass
uses: PFCCLab/ci-bypass@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
non-pull-request-event-strategy: 'never-skipped'
type: 'composite'
composite-rule: |
{
"any": [
{
"type": "labeled",
"label": ["skip-ci: ${{ inputs.workflow-name }}", "skip-ci: all"],
"username": ${{ env.CI_TEAM_MEMBERS }}
},
{
"type": "commented",
"comment-pattern": [".*/skip-ci ${{ inputs.workflow-name }}.*", ".*/skip-ci all.*"],
"username": ${{ env.CI_TEAM_MEMBERS }}
}
]
}

View File

@@ -1,17 +1,80 @@
name: Lint
name: Codestyle Check
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
env:
PR_ID: ${{ github.event.pull_request.number }}
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
BRANCH: ${{ github.event.pull_request.base.ref }}
TASK: PaddleNLP-CI-Lint-${{ github.event.pull_request.number }}
jobs:
check-bypass:
name: Check bypass
uses: ./.github/workflows/check-bypass.yml
with:
workflow-name: 'lint'
secrets:
github-token: ${{ secrets.GITHUB_TOKEN }}
Lint:
name: Lint
runs-on: ubuntu-20.04
needs: check-bypass
if: ${{ needs.check-bypass.outputs.can-skip != 'true' }}
runs-on: [self-hosted, ernie-cpu]
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: checkout develop
- name: Run Container
env:
work_dir: ${{ github.workspace }}
python_version: "3.10"
run: |
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
echo "container_name=${container_name}" >> ${{ github.env }}
docker_image="iregistry.baidu-int.com/paddlecloud/base-images:paddlecloud-ubuntu20.04-gcc12.2-cuda12.3-cudnn9.0-nccl2.20.3.1-openmpi4.1.5-latest"
docker run -d -t --name ${container_name} --net=host -v /dev/shm:/dev/shm --shm-size=32G \
-v $work_dir/../../..:$work_dir/../../.. \
-v $work_dir:/workspace \
-v /home/.cache/pip:/home/.cache/pip \
-e BRANCH \
-e PR_ID \
-e COMMIT_ID \
-e work_dir \
-e no_proxy \
-e python_version \
-w /workspace ${docker_image}
- name: Download Code
env:
work_dir: ${{ github.workspace }}
run: |
docker exec -t ${container_name} /bin/bash -c '
rm -rf * .[^.]*
echo "Downloading PaddleNLP.tar"
wget -q --no-proxy https://paddle-qa.bj.bcebos.com/CodeSync/develop/PaddleNLP.tar --no-check-certificate
echo "Extracting PaddleNLP.tar"
tar xf PaddleNLP.tar && rm -rf PaddleNLP.tar
source $work_dir/../../../proxy
cd PaddleNLP
git config --global user.name "PaddleCI"
git config --global user.email "paddle_ci@example.com"
git pull
git submodule update --init --recursive --force
if [ -n "${PR_ID}" ]; then
git fetch origin pull/${PR_ID}/head
git checkout -b PR_${PR_ID} FETCH_HEAD
git remote add upstream https://github.com/PaddlePaddle/PaddleNLP.git
git fetch upstream ${BRANCH}
git merge ${BRANCH} --no-edit
git diff --numstat ${BRANCH} -- | awk "{print \$NF}"
else
echo "Not in a pull_request event. Skipping PR-specific operations."
fi
git log --pretty=oneline -10
if ! git show-ref --quiet refs/heads/develop; then \
echo "local develop branch is missing, creating local develop branch that tracks remote develop branch"
git fetch origin develop
@@ -19,14 +82,32 @@ jobs:
else
echo "local develop branch exist, skipping"
fi
- uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip' # caching pip dependencies
- name: Install dependencies
'
- name: Setup Environment
run: |
docker exec -t $container_name /bin/bash -c '
unlink /usr/local/bin/python
ln -sf $(which python${python_version}) /usr/local/bin/python
set -e
python -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
python -m pip config set global.cache-dir "/home/.cache/pip"
source $work_dir/../../../proxy
python -m pip install --upgrade pip
cd /workspace/PaddleNLP && git config --global --add safe.directory $PWD
make install
- name: run the command
run: make lint
'
- name: Test
run: |
docker exec -t $container_name /bin/bash -c '
set -e
source $work_dir/../../../proxy
cd /workspace/PaddleNLP
make lint
'
- name: Terminate And Delete the Container
if: always()
run: |
docker rm -f $container_name 2>/dev/null || true

207
.github/workflows/llm.yml vendored Normal file
View File

@@ -0,0 +1,207 @@
# Disabled LLM CI workflow - manually enabled when needed
name: LLM CI (DISABLED)
#on:
# pull_request:
# types: [opened, synchronize, reopened]
# branches: [develop]
# schedule:
# - cron: "2 0 * * *"
# workflow_call:
# inputs:
# run_downstream:
# required: true
# type: string
# image_name:
# required: true
# type: string
#concurrency:
# group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
# cancel-in-progress: true
#env:
# PR_ID: ${{ github.event.pull_request.number }}
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
TASK: paddlenlp-CI-${{ github.event.pull_request.number }}-llm
ci_scripts: /workspace/PaddleNLP/scripts/regression
BRANCH: ${{ github.event.pull_request.base.ref }}
AGILE_COMPILE_BRANCH: ${{ github.event.pull_request.base.ref }}
CI_name: llm-ci
no_proxy: "localhost,bj.bcebos.com,su.bcebos.com,bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
HF_ENDPOINT: https://hf-mirror.com
STUDIO_GIT_HOST: http://git.prod.idc-to-cloud.aistudio.baidu-int.com
PPNLP_HOME: /ssd1/paddlenlp
HF_DATASETS_CACHE: /ssd1/paddlenlp/huggingface/datasets
TRANSFORMERS_CACHE: /ssd1/paddlenlp/huggingface
CCACHE_DIR: /home/data/gzcfs/.ccache/gpubox
RUN_DOWNSTREAM: ${{ inputs.run_downstream }}
#defaults:
# run:
# shell: bash
#jobs:
# llm-ci:
# name: llm-ci (DISABLED)
runs-on: [self-hosted, ernie-8gpu]
steps:
- name: Determine Image Name
env:
IMAGE_NAME: ${{ inputs.image_name }}
run: |
if [[ -n "${IMAGE_NAME}" ]]; then
echo "IMAGE_NAME=${IMAGE_NAME}" >> "$GITHUB_ENV"
else
echo "IMAGE_NAME=iregistry.baidu-int.com/paddlecloud/base-images:paddlecloud-ubuntu18.04-gcc8.2-cuda11.8-cudnn8.6-nccl2.15.5-paddlenlp-latest" >> "$GITHUB_ENV"
fi
- name: Run Container
env:
work_dir: ${{ github.workspace }}
CACHE_DIR: /home/data/cfs/.cache
FLAGS_dynamic_static_unified_comm: "True"
python_version: "3.10"
paddle_whl: https://paddle-qa.bj.bcebos.com/paddle-pipeline/Develop-GpuSome-LinuxCentos-Gcc82-Cuda118-Cudnn86-Trt85-Py310-CINN-Compile/latest/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
run: |
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
echo "container_name=${container_name}" >> "$GITHUB_ENV"
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping..."
else
docker run -d -t --name ${container_name} --net=host -v /dev/shm:/dev/shm --shm-size=32G \
-v $work_dir/../../..:$work_dir/../../.. \
-v $work_dir:/workspace \
-v /home/.cache/pip:/home/.cache/pip \
-v /ssd1/paddlenlp:/ssd1/paddlenlp \
-v /home/data/gzcfs/.ccache/gpubox:/home/data/gzcfs/.ccache/gpubox \
-e BRANCH \
-e AGILE_COMPILE_BRANCH \
-e PR_ID \
-e COMMIT_ID \
-e work_dir \
-e ci_scripts \
-e no_proxy \
-e CI_name \
-e paddle_whl \
-e HF_ENDPOINT \
-e STUDIO_GIT_HOST \
-e PPNLP_HOME \
-e HF_DATASETS_CACHE \
-e TRANSFORMERS_CACHE \
-e CACHE_DIR \
-e FLAGS_dynamic_static_unified_comm \
-e python_version \
-w /workspace --runtime=nvidia $IMAGE_NAME
fi
- name: Download Code
env:
work_dir: ${{ github.workspace }}
run: |
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping.."
else
docker exec -t $container_name /bin/bash -c '
rm -rf * .[^.]*
echo "Downloading PaddleNLP.tar.gz"
wget -q --no-proxy https://paddle-qa.bj.bcebos.com/CodeSync/develop/PaddleNLP.tar --no-check-certificate
echo "Extracting PaddleNLP.tar.gz"
tar xf PaddleNLP.tar && rm -rf PaddleNLP.tar
source $work_dir/../../../proxy
cd PaddleNLP
git config --global user.name "PaddleCI"
git config --global user.email "paddle_ci@example.com"
git pull
git submodule update --init --recursive --force
if [ -n "${PR_ID}" ]; then
git fetch origin pull/${PR_ID}/head
git checkout -b PR_${PR_ID} FETCH_HEAD
git remote add upstream https://github.com/PaddlePaddle/PaddleNLP.git
git fetch upstream ${BRANCH}
git merge ${BRANCH} --no-edit
git diff --numstat ${BRANCH} -- | awk "{print \$NF}"
else
echo "Not in a pull_request event. Skipping PR-specific operations."
fi
git log --pretty=oneline -10
'
fi
- name: Skip For Bug
run: |
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping..."
else
docker exec -t $container_name /bin/bash -c '
cd /workspace/PaddleNLP
git revert f2477c07272d04244cd3287d1f21c70482a4a85f --no-edit # 套件PR#10413引入bug-待修复
git revert d74c950e15a35b7a100d1688c89318195cc83bca --no-edit # 框架升级后配合修改,当前因框架bug固定commit适配
'
fi
- name: Test
run: |
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping..."
else
docker exec -t $container_name /bin/bash -c '
ldconfig
unlink /usr/bin/python3
ln -sf $(which python${python_version}) /usr/bin/python3
pip config set global.cache-dir "/home/.cache/pip"
set -e
source $work_dir/../../../proxy
cd /workspace/PaddleNLP && git config --global --add safe.directory $PWD
echo "Paddle PR#73283 PR#74484 import bug, set paddle_commit=8ae742 to skip "
export paddle_whl=https://paddle-qa.bj.bcebos.com/paddle-pipeline/Develop-GpuSome-LinuxCentos-Gcc82-Cuda118-Cudnn86-Trt85-Py310-CINN-Compile/8ae7423e99b2ea96e410968a0ebb3f1795e37205/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
timeout 2h bash scripts/regression/run_ci.sh python${python_version} ${paddle_whl}
'
fi
- name: Upload Allure-reports & Logs
if: always()
env:
home_path: ${{ github.workspace }}/../../..
bos_file: ${{ github.workspace }}/../../../bos/BosClient.py
allure_file: ${{ github.workspace }}/../../../allure-2.19.0/bin/allure
run: |
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping..."
else
docker exec -t $container_name /bin/bash -c '
unset http_proxy && unset https_proxy
if [ ! -f "${{ env.bos_file }}" ]; then
wget -q --no-proxy -O ${{ env.home_path }}/bos_new.tar.gz https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz --no-check-certificate
mkdir ${{ env.home_path }}/bos
tar xf ${{ env.home_path }}/bos_new.tar.gz -C ${{ env.home_path }}/bos
fi
if [ ! -f "${{ env.allure_file }}" ]; then
wget -q --no-proxy -O ${{ env.home_path }}/allure-2.19.0.zip https://xly-devops.bj.bcebos.com/tools/allure-2.19.0.zip --no-check-certificate
unzip -q ${{ env.home_path }}/allure-2.19.0.zip -d ${{ env.home_path }}/
fi
if [[ "${{ env.RUN_DOWNSTREAM }}" == "" && -n "${PR_ID}" ]]; then
bos_prefix="${PR_ID}/${COMMIT_ID}"
elif [[ "${{ env.RUN_DOWNSTREAM }}" == "true" && -n "${PR_ID}" ]]; then
bos_prefix="${PR_ID}/${COMMIT_ID}/test_build"
else
bos_prefix="schedule/$(date +%Y%m%d)"
fi
cd /workspace/PaddleNLP/model_logs
for FILE in /workspace/PaddleNLP/model_logs/*; do
file=$(basename "$FILE")
python ${{ env.bos_file }} $file paddle-github-action/PR/PaddleNLP/llm/${bos_prefix}/logs
echo "$file: https://paddle-github-action.bj.bcebos.com/PR/PaddleNLP/llm/${bos_prefix}/logs/$file"
done
cd /workspace/PaddleNLP/
${{ env.allure_file }} generate result -o report
tar -czf products.tar.gz report model_logs
python ${{ env.bos_file }} products.tar.gz paddle-github-action/PR/PaddleNLP/llm/${bos_prefix}/logs
echo "products: https://paddle-github-action.bj.bcebos.com/PR/PaddleNLP/llm/${bos_prefix}/logs/products.tar.gz"
'
fi
- name: Terminate And Delete the Container
if: always()
run: |
docker rm -f ${{ env.container_name }} 2>/dev/null || true

View File

@@ -12,7 +12,7 @@ on:
jobs:
Pipelines-Test:
name: Pipelines-Test
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4

View File

@@ -16,7 +16,7 @@ on:
jobs:
Release:
name: Release
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v1

73
.github/workflows/rerun.yml vendored Normal file
View File

@@ -0,0 +1,73 @@
name: Re-run
on:
issue_comment:
types: [created]
jobs:
re-run:
if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/re-run') && github.event.comment.user.login == github.event.issue.user.login }}
runs-on: [self-hosted, ernie-cpu]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Rerun all failed jobs
if: ${{ contains(github.event.comment.body, 'all-failed') }}
uses: ./.github/actions/rerun-workflow
with:
PR_ID: ${{ github.event.issue.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
JOB_NAME: 'all-failed'
- name: Rerun LLM
if: ${{ contains(github.event.comment.body, 'LLM') }}
uses: ./.github/actions/rerun-workflow
with:
PR_ID: ${{ github.event.issue.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
JOB_NAME: 'LLM CI / llm-ci'
- name: Unittest GPU
if: ${{ contains(github.event.comment.body, 'Unittest GPU') }}
uses: ./.github/actions/rerun-workflow
with:
PR_ID: ${{ github.event.issue.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
JOB_NAME: 'Unittest GPU CI / unittest-gpu-ci'
- name: Rerun Unittest CPU
if: ${{ contains(github.event.comment.body, 'Unittest CPU') }}
uses: ./.github/actions/rerun-workflow
with:
PR_ID: ${{ github.event.issue.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
JOB_NAME: 'Unittest CPU CI / unit-cpu-ci'
- name: Rerun Distribute (V100)
if: ${{ contains(github.event.comment.body, 'Distribute (V100)') }}
uses: ./.github/actions/rerun-workflow
with:
PR_ID: ${{ github.event.issue.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
JOB_NAME: 'Distribute CI (V100)/ distribute-v100-ci'
- name: Rerun Codestyle Check
if: ${{ contains(github.event.comment.body, 'Codestyle Check') }}
uses: ./.github/actions/rerun-workflow
with:
PR_ID: ${{ github.event.issue.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OWNER: ${{ github.repository_owner }}
REPO: ${{ github.event.repository.name }}
JOB_NAME: 'Codestyle Check / Lint'

View File

@@ -13,7 +13,7 @@ permissions:
jobs:
stale:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
permissions:
issues: write

View File

@@ -1,29 +0,0 @@
name: Test
on: [push, pull_request]
jobs:
Test:
name: Test
runs-on: ubuntu-20.04
permissions:
pull-requests: write
contents: read
id-token: write
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip' # caching pip dependencies
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r tests/requirements.txt
make install
- name: run the command
run: make test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

120
.github/workflows/unittest-cpu.yml vendored Normal file
View File

@@ -0,0 +1,120 @@
# Disabled unittest CPU workflow - manually enabled when needed
name: Unittest CPU CI (DISABLED)
#on: [pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
env:
PR_ID: ${{ github.event.pull_request.number }}
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
BRANCH: ${{ github.event.pull_request.base.ref }}
TASK: PaddleNLP-CI-${{ github.event.pull_request.number }}-unittest-cpu
HF_ENDPOINT: https://hf-mirror.com
STUDIO_GIT_HOST: http://git.prod.idc-to-cloud.aistudio.baidu-int.com
PPNLP_HOME: /home/disk1/cache
HF_DATASETS_CACHE: /home/disk1/cache/huggingface/datasets
TRANSFORMERS_CACHE: /home/disk1/cache/huggingface
#jobs:
# unittest-cpu-ci:
# name: unittest-cpu-ci (DISABLED)
runs-on: [self-hosted, ernie-cpu]
permissions:
pull-requests: write
contents: read
id-token: write
steps:
- name: Run Container
env:
work_dir: ${{ github.workspace }}
python_version: "3.10"
run: |
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
echo "container_name=${container_name}" >> ${{ github.env }}
docker_image="iregistry.baidu-int.com/paddlecloud/base-images:paddlecloud-ubuntu20.04-gcc12.2-cuda12.3-cudnn9.0-nccl2.20.3.1-openmpi4.1.5-latest"
docker run -d -t --name ${container_name} --net=host -v /dev/shm:/dev/shm --shm-size=32G \
-v $work_dir/../../..:$work_dir/../../.. \
-v $work_dir:/workspace \
-v /home/.cache/pip:/home/.cache/pip \
-v /home/disk1/cache:/home/disk1/cache \
-e BRANCH \
-e PR_ID \
-e COMMIT_ID \
-e work_dir \
-e no_proxy \
-e python_version \
-e HF_ENDPOINT \
-e STUDIO_GIT_HOST \
-e PPNLP_HOME \
-e HF_DATASETS_CACHE \
-e TRANSFORMERS_CACHE \
-w /workspace ${docker_image}
- name: Download Code
env:
work_dir: ${{ github.workspace }}
run: |
docker exec -t ${container_name} /bin/bash -c '
rm -rf * .[^.]*
echo "Downloading PaddleNLP.tar"
wget -q --no-proxy https://paddle-qa.bj.bcebos.com/CodeSync/develop/PaddleNLP.tar --no-check-certificate
echo "Extracting PaddleNLP.tar"
tar xf PaddleNLP.tar && rm -rf PaddleNLP.tar
source $work_dir/../../../proxy
cd PaddleNLP
git config --global user.name "PaddleCI"
git config --global user.email "paddle_ci@example.com"
git pull
git submodule update --init --recursive --force
if [ -n "${PR_ID}" ]; then
git fetch origin pull/${PR_ID}/head
git checkout -b PR_${PR_ID} FETCH_HEAD
git remote add upstream https://github.com/PaddlePaddle/PaddleNLP.git
git fetch upstream ${BRANCH}
git merge ${BRANCH} --no-edit
git diff --numstat ${BRANCH} -- | awk "{print \$NF}"
else
echo "Not in a pull_request event. Skipping PR-specific operations."
fi
git log --pretty=oneline -10
'
- name: Setup Environment
run: |
docker exec -t $container_name /bin/bash -c '
unlink /usr/bin/python3
ln -sf $(which python${python_version}) /usr/bin/python3
set -e
python -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
python -m pip config set global.cache-dir "/home/.cache/pip"
source $work_dir/../../../proxy
python -m pip install --upgrade pip
cd /workspace/PaddleNLP && git config --global --add safe.directory $PWD
pip install -r tests/requirements.txt
make install
'
- name: Test
run: |
docker exec -t $container_name /bin/bash -c '
source $work_dir/../../../proxy
cd /workspace/PaddleNLP
set -e
make test
'
# - name: Upload Coverage To Codecov
# uses: codecov/codecov-action@v3
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
# with:
# token: ${{ secrets.CODECOV_TOKEN }}
# files: ./PaddleNLP/coverage.xml
- name: Terminate And Delete the Container
if: always()
run: |
docker rm -f $container_name 2>/dev/null || true

204
.github/workflows/unittest-gpu.yml vendored Normal file
View File

@@ -0,0 +1,204 @@
# Disabled unittest GPU workflow - manually enabled when needed
name: Unittest GPU CI (DISABLED)
#on:
# pull_request:
# types: [opened, synchronize, reopened]
# branches: [develop]
# schedule:
# - cron: "3 0 * * *"
# workflow_call:
# inputs:
# run_downstream:
# required: true
# type: string
# image_name:
# required: true
# type: string
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
env:
PR_ID: ${{ github.event.pull_request.number }}
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
TASK: paddlenlp-CI-${{ github.event.pull_request.number }}-unit-gpu
ci_scripts: /workspace/PaddleNLP/scripts/unit_test
BRANCH: ${{ github.event.pull_request.base.ref }}
AGILE_COMPILE_BRANCH: ${{ github.event.pull_request.base.ref }}
CI_name: unittest-gpu-ci
no_proxy: "localhost,bj.bcebos.com,su.bcebos.com,bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
HF_ENDPOINT: https://hf-mirror.com
STUDIO_GIT_HOST: http://git.prod.idc-to-cloud.aistudio.baidu-int.com
PPNLP_HOME: /ssd1/paddlenlp
HF_DATASETS_CACHE: /ssd1/paddlenlp/huggingface/datasets
TRANSFORMERS_CACHE: /ssd1/paddlenlp/huggingface
CCACHE_DIR: /home/data/gzcfs/.ccache/gpubox
RUN_DOWNSTREAM: ${{ inputs.run_downstream }}
defaults:
run:
shell: bash
#jobs:
# unittest-gpu-ci:
# name: unittest-gpu-ci (DISABLED)
runs-on: [self-hosted, ernie-8gpu]
steps:
- name: Determine Image Name
env:
IMAGE_NAME: ${{ inputs.image_name }}
run: |
if [[ -n "${IMAGE_NAME}" ]]; then
echo "IMAGE_NAME=${IMAGE_NAME}" >> "$GITHUB_ENV"
else
echo "IMAGE_NAME=iregistry.baidu-int.com/paddlecloud/base-images:paddlecloud-ubuntu18.04-gcc8.2-cuda11.8-cudnn8.6-nccl2.15.5-paddlenlp-latest" >> "$GITHUB_ENV"
fi
- name: Run Container
env:
work_dir: ${{ github.workspace }}
CACHE_DIR: /home/data/cfs/.cache
FLAGS_dynamic_static_unified_comm: "True"
python_version: "3.10"
paddle_whl: https://paddle-qa.bj.bcebos.com/paddle-pipeline/Develop-GpuSome-LinuxCentos-Gcc82-Cuda118-Cudnn86-Trt85-Py310-CINN-Compile/latest/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
run: |
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
echo "container_name=${container_name}" >> "$GITHUB_ENV"
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping..."
else
docker run -d -t --name ${container_name} --net=host -v /dev/shm:/dev/shm --shm-size=32G \
-v $work_dir/../../..:$work_dir/../../.. \
-v $work_dir:/workspace \
-v /home/.cache/pip:/home/.cache/pip \
-v /ssd1/paddlenlp:/ssd1/paddlenlp \
-v /home/data/gzcfs/.ccache/gpubox:/home/data/gzcfs/.ccache/gpubox \
-e BRANCH \
-e AGILE_COMPILE_BRANCH \
-e PR_ID \
-e COMMIT_ID \
-e work_dir \
-e ci_scripts \
-e no_proxy \
-e CI_name \
-e paddle_whl \
-e HF_ENDPOINT \
-e STUDIO_GIT_HOST \
-e PPNLP_HOME \
-e HF_DATASETS_CACHE \
-e TRANSFORMERS_CACHE \
-e CACHE_DIR \
-e FLAGS_dynamic_static_unified_comm \
-e python_version \
-w /workspace --runtime=nvidia $IMAGE_NAME
fi
- name: Download Code
env:
work_dir: ${{ github.workspace }}
run: |
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping.."
else
docker exec -t $container_name /bin/bash -c '
rm -rf * .[^.]*
echo "Downloading PaddleNLP.tar.gz"
wget -q --no-proxy https://paddle-qa.bj.bcebos.com/CodeSync/develop/PaddleNLP.tar --no-check-certificate
echo "Extracting PaddleNLP.tar.gz"
tar xf PaddleNLP.tar && rm -rf PaddleNLP.tar
source $work_dir/../../../proxy
cd PaddleNLP
git config --global user.name "PaddleCI"
git config --global user.email "paddle_ci@example.com"
git pull
git submodule update --init --recursive --force
if [ -n "${PR_ID}" ]; then
git fetch origin pull/${PR_ID}/head
git checkout -b PR_${PR_ID} FETCH_HEAD
git remote add upstream https://github.com/PaddlePaddle/PaddleNLP.git
git fetch upstream ${BRANCH}
git merge ${BRANCH} --no-edit
git diff --numstat ${BRANCH} -- | awk "{print \$NF}"
else
echo "Not in a pull_request event. Skipping PR-specific operations."
fi
git log --pretty=oneline -10
'
fi
- name: Skip For Bug
run: |
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping..."
else
docker exec -t $container_name /bin/bash -c '
cd /workspace/PaddleNLP
echo "no skip for bug"
'
fi
- name: Test
run: |
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping..."
else
docker exec -t $container_name /bin/bash -c '
ldconfig
unlink /usr/bin/python3
ln -sf $(which python${python_version}) /usr/bin/python3
pip config set global.cache-dir "/home/.cache/pip"
source $work_dir/../../../proxy
set -e
cd /workspace/PaddleNLP && git config --global --add safe.directory $PWD
timeout 50m bash scripts/unit_test/ci_unit.sh ${paddle_whl}
'
fi
- name: Upload Allure-reports & Logs
if: always()
env:
home_path: ${{ github.workspace }}/../../..
bos_file: ${{ github.workspace }}/../../../bos/BosClient.py
allure_file: ${{ github.workspace }}/../../../allure-2.19.0/bin/allure
run: |
if [[ "$RUN_DOWNSTREAM" == "false" ]]; then
echo "Not in a pull_request or test_build event. Skipping..."
else
docker exec -t $container_name /bin/bash -c '
unset http_proxy && unset https_proxy
if [ ! -f "${{ env.bos_file }}" ]; then
wget -q --no-proxy -O ${{ env.home_path }}/bos_new.tar.gz https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz --no-check-certificate
mkdir ${{ env.home_path }}/bos
tar xf ${{ env.home_path }}/bos_new.tar.gz -C ${{ env.home_path }}/bos
fi
if [ ! -f "${{ env.allure_file }}" ]; then
wget -q --no-proxy -O ${{ env.home_path }}/allure-2.19.0.zip https://xly-devops.bj.bcebos.com/tools/allure-2.19.0.zip --no-check-certificate
unzip -q ${{ env.home_path }}/allure-2.19.0.zip -d ${{ env.home_path }}/
fi
if [[ "${{ env.RUN_DOWNSTREAM }}" == "" && -n "${PR_ID}" ]]; then
bos_prefix="${PR_ID}/${COMMIT_ID}"
elif [[ "${{ env.RUN_DOWNSTREAM }}" == "true" && -n "${PR_ID}" ]]; then
bos_prefix="${PR_ID}/${COMMIT_ID}/test_build"
else
bos_prefix="schedule/$(date +%Y%m%d)"
fi
cd /workspace/PaddleNLP/unittest_logs
for FILE in /workspace/PaddleNLP/unittest_logs/*; do
file=$(basename "$FILE")
python ${{ env.bos_file }} $file paddle-github-action/PR/PaddleNLP/unittest-gpu/${bos_prefix}/logs
echo "$file: https://paddle-github-action.bj.bcebos.com/PR/PaddleNLP/unittest-gpu/${bos_prefix}/logs/$file"
done
cd /workspace/PaddleNLP/
${{ env.allure_file }} generate result -o report
tar -czf products.tar.gz report unittest_logs
python ${{ env.bos_file }} products.tar.gz paddle-github-action/PR/PaddleNLP/unittest-gpu/${bos_prefix}/logs
echo "report: https://paddle-github-action.bj.bcebos.com/PR/PaddleNLP/unittest-gpu/${bos_prefix}/logs/products.tar.gz"
'
fi
- name: Terminate And Delete the Container
if: always()
run: |
docker rm -f $container_name 2>/dev/null || true

2
.gitignore vendored
View File

@@ -140,4 +140,4 @@ autogen/
#fp8
ops/csrc/fp8/deep_gemm/include/cutlass
ops/csrc/fp8/deep_gemm/include/cute
.ccls-cache

View File

@@ -62,3 +62,12 @@ repos:
language: python
files: \.(md|markdown|rst)$
pass_filenames: true
- repo: local
hooks:
- id: clang-format
name: clang-format
description: Format files with ClangFormat.
entry: bash ./tools/codestyle/clang_format.sh -i
language: system
files: \.(c|cc|cxx|cpp|cu|h|hpp|hxx|xpu|kps)$

View File

@@ -15,7 +15,7 @@ submodules:
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: docs/zh/conf.py
# Optionally build your docs in additional formats such as PDF
#formats:

View File

@@ -72,7 +72,7 @@ PaddleNLP 使用 [Git 分支模型](http://nvie.com/posts/a-successful-git-branc
类似于以下内容:
```text
➜ (my-virtual-env) git commit -m "commiting my cool feature"
➜ (my-virtual-env) git commit -m "committing my cool feature"
black....................................................................Passed
isort....................................................................Passed
flake8...................................................................Passed
@@ -91,7 +91,7 @@ PaddleNLP 使用 [Git 分支模型](http://nvie.com/posts/a-successful-git-branc
但大多数时候事情并没有那么顺利。当您的代码或文档不符合标准时,`pre-commit` 检查将失败。
```text
➜ (my-virtual-env) git commit -m "commiting my cool feature"
➜ (my-virtual-env) git commit -m "committing my cool feature"
black....................................................................Passed
isort....................................................................Failed
- hook id: isort

View File

@@ -33,14 +33,20 @@
## News 📢
* **2025.03.12 [PaddleNLP v3.0 Beta4](https://github.com/PaddlePaddle/PaddleNLP/releases/tag/v3.0.0-beta4)**:全面支持 DeepSeek V3/R1/R1-Distill, 及QwQ-32B等热门思考模型。**DeepSeek V3/R1完整版支持FP8、INT8、4-bit量化推理,MTP投机解码**。单机FP8推理输出超**1000 tokens/s**; 4-bit推理输出超**2100 tokens/s**! 发布新版推理部署镜像,热门模型[一键部署](https://paddlenlp.readthedocs.io/zh/latest/llm/server/docs/general_model_inference.html)。推理部署[使用文档](https://paddlenlp.readthedocs.io/zh/latest/llm/docs/predict/index.html)全面更新,体验全面提升!自研下一代通用信息抽取模型 PP-UIE [全新发布](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/application/information_extraction),支持8K长度信息抽取。新增大模型 Embedding 训练,支持INF-CL超大batch size训练。新增[MergeKit](https://paddlenlp.readthedocs.io/zh/latest/llm/docs/mergekit.html)模型融合工具,缓解对齐代价。低资源训练全面优化,16G小显存可以流畅训练。
* **2025.04.29 PaddleNLP 现已支持 Qwen3 系列模型**: Qwen3 系列模型支持持两种思考模式,预训练约 36 万亿个 token、119 种语言和方言。包括六个 Dense 模型, Qwen3-32B、Qwen3-14B、Qwen3-8B、Qwen3-4B、Qwen3-1.7B 和 Qwen3-0.6B。两个 MoE 模型的权重:Qwen3-235B-A22B,Qwen3-30B-A3B。
* **2025.03.12 [PaddleNLP v3.0 Beta4](https://github.com/PaddlePaddle/PaddleNLP/releases/tag/v3.0.0-beta4)**:全面支持 DeepSeek V3/R1/R1-Distill, 及 QwQ-32B 等热门思考模型。**DeepSeek V3/R1完整版支持 FP8、INT8、4-bit 量化推理,MTP 投机解码**。单机 FP8推理输出超**1000 tokens/s**; 4-bit 推理输出超**2100 tokens/s**! 发布新版推理部署镜像,热门模型[一键部署](https://paddlenlp.readthedocs.io/zh/latest/llm/server/docs/general_model_inference.html)。推理部署[使用文档](https://paddlenlp.readthedocs.io/zh/latest/llm/docs/predict/index.html)全面更新,体验全面提升!自研下一代通用信息抽取模型 PP-UIE [全新发布](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/application/information_extraction),支持8K 长度信息抽取。新增大模型 Embedding 训练,支持 INF-CL 超大 batch size 训练。新增[MergeKit](https://paddlenlp.readthedocs.io/zh/latest/llm/docs/mergekit.html)模型融合工具,缓解对齐代价。低资源训练全面优化,16G 小显存可以流畅训练。
* **2025.03.06 PaddleNLP 现已支持 Qwen/QwQ-32B 模型**: 其模型参数仅有 32B,但其数学推理、编程能力和通用能力可与具备 671B 参数(其中 37B 被激活)的 DeepSeek-R1 媲美。借助 PaddleNLP 3.0套件,现可实现多种并行策略[微调训练](./llm/README.md)、[高性能推理、低比特量化](./llm/docs/predict/qwen.md)和[服务化部署](./llm/server/README.md)。
* **2025.02.10 PaddleNLP 现已支持 DeepSeek-R1系列模型,[在线使用](https://aistudio.baidu.com/projectdetail/8775758)**:依托全新的 PaddleNLP 3.0套件,DeepSeek-R1系列模型现已全面支持。凭借数据并行、数据分组切分并行、模型并行、流水线并行以及专家并行等一系列先进的分布式训练能力,结合 Paddle 框架独有的列稀疏注意力掩码表示技术——FlashMask 方法,DeepSeek-R1系列模型在训练过程中显著降低了显存消耗,同时取得了卓越的训练性能提升。
<details><summary> <b>点击展开</b> </summary><div>
* **2025.03.17 《DeepSeek-R1满血版单机部署实测》** 🔥🔥🔥 飞桨框架3.0大模型推理部署全面升级,支持多款主流大模型,DeepSeek-R1满血版实现单机部署,吞吐提升一倍!欢迎广大用户开箱体验~现已开启有奖活动:完成 DeepSeek-R1-MTP 单机部署任务、提交高质量测评 blog,即可实时赢取奖金!💰💰💰
报名[地址](https://www.wjx.top/vm/OlzzmbG.aspx#), 活动详情:https://github.com/PaddlePaddle/PaddleNLP/issues/10166 , 参考文档:https://github.com/PaddlePaddle/PaddleNLP/issues/10157 。
* **2025.03.06 PaddleNLP 现已支持 Qwen/QwQ-32B 模型**: 其模型参数仅有 32B,但其数学推理、编程能力和通用能力可与具备 671B 参数(其中 37B 被激活)的 DeepSeek-R1 媲美。借助 PaddleNLP 3.0套件,现可实现多种并行策略[微调训练](./llm/README.md)、[高性能推理、低比特量化](./llm/docs/predict/qwen.md)和[服务化部署](./llm/server/README.md)。
* **2025.02.20 🔥🔥《PP-UIE 信息抽取智能引擎全新升级》** 强化零样本学习能力,支持极少甚至零标注数据实现高效冷启动与迁移学习,显著降低数据标注成本;具备处理长文本能力,支持 8192 个 Token 长度文档信息抽取,实现跨段落识别关键信息,形成完整理解;提供完整可定制化的训练和推理全流程,训练效率相较于 LLama-Factory 实现了1.8倍的提升。
2月26日(周三)19:00为您深度解析全新 PP-UIE 技术方案及在部署方面的功能、优势与技巧。报名链接:https://www.wjx.top/vm/mBKC6pb.aspx?udsid=606418
@@ -63,7 +69,7 @@
### <a href=#多硬件训推一体> 🔧 多硬件训推一体 </a>
支持英伟达 GPU、昆仑 XPU、昇腾 NPU、燧原 GCU 和海光 DCU 等多个硬件的大模型和自然语言理解模型训练和推理,套件接口支持硬件快速切换,大幅降低硬件切换研发成本。
当前支持的自然语言理解模型:[多硬件自然语言理解模型列表](./docs/model_zoo/model_list_multy_device.md)
当前支持的自然语言理解模型:[多硬件自然语言理解模型列表](./docs/zh/model_zoo/model_list_multy_device.md)
### <a href=#高效易用的预训练> 🚀 高效易用的预训练 </a>
@@ -116,6 +122,7 @@
| [Qwen2.5](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/Qwen2.5-0.5B, Qwen/Qwen2.5-0.5B-Instruct, Qwen/Qwen2.5-1.5B, Qwen/Qwen2.5-1.5B-Instruct, Qwen/Qwen2.5-3B, Qwen/Qwen2.5-3B-Instruct, Qwen/Qwen2.5-7B, Qwen/Qwen2.5-7B-Instruct, Qwen/Qwen2.5-7B-Instruct-1M, Qwen/Qwen2.5-14B, Qwen/Qwen2.5-14B-Instruct, Qwen/Qwen2.5-14B-Instruct-1M, Qwen/Qwen2.5-32B, Qwen/Qwen2.5-32B-Instruct, Qwen/Qwen2.5-72B, Qwen/Qwen2.5-72B-Instruct |
| [Qwen2.5-Math](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/Qwen2.5-Math-1.5B, Qwen/Qwen2.5-Math-1.5B-Instruct, Qwen/Qwen2.5-Math-7B, Qwen/Qwen2.5-Math-7B-Instruct, Qwen/Qwen2.5-Math-72B, Qwen/Qwen2.5-Math-72B-Instruct, Qwen/Qwen2.5-Math-RM-72B |
| [Qwen2.5-Coder](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/Qwen2.5-Coder-1.5B, Qwen/Qwen2.5-Coder-1.5B-Instruct, Qwen/Qwen2.5-Coder-7B, Qwen/Qwen2.5-Coder-7B-Instruct |
| [Qwen3](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/Qwen3-0.6B, Qwen/Qwen3-1.7B, Qwen/Qwen3-4B, Qwen/Qwen3-8B, Qwen/Qwen3-14B, Qwen/Qwen3-32B, Qwen/Qwen3-30B-A3B, Qwen/Qwen3-235B-A22B, Qwen/Qwen3-0.6B-Base, Qwen/Qwen3-1.7B-Base, Qwen/Qwen3-4B-Base, Qwen/Qwen3-8B-Base, Qwen/Qwen3-14B-Base, Qwen/Qwen3-30B-A3B-Base |
| [QwQ](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/QwQ-32B, Qwen/QwQ-32B-Preview |
| [Yuan2](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/yuan/) | IEITYuan/Yuan2-2B, IEITYuan/Yuan2-51B, IEITYuan/Yuan2-102B |
@@ -192,7 +199,7 @@ pip install --upgrade paddlenlp==3.0.0b4
pip install --pre --upgrade paddlenlp -f https://www.paddlepaddle.org.cn/whl/paddlenlp.html
```
更多关于 PaddlePaddle 和 PaddleNLP 安装的详细教程请查看[Installation](./docs/get_started/installation.rst)。
更多关于 PaddlePaddle 和 PaddleNLP 安装的详细教程请查看[Installation](./docs/zh/get_started/installation.rst)。
------------------------------------------------------------------------------------------
@@ -203,13 +210,14 @@ pip install --pre --upgrade paddlenlp -f https://www.paddlepaddle.org.cn/whl/pad
PaddleNLP 提供了方便易用的 Auto API,能够快速的加载模型和 Tokenizer。这里以使用 `Qwen/Qwen2-0.5B` 模型做文本生成为例:
```python
>>> from paddlenlp.transformers import AutoTokenizer, AutoModelForCausalLM
>>> tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-0.5B")
>>> model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2-0.5B", dtype="float16")
>>> input_features = tokenizer("你好!请自我介绍一下。", return_tensors="pd")
>>> outputs = model.generate(**input_features, max_length=128)
>>> print(tokenizer.batch_decode(outputs[0], skip_special_tokens=True))
['我是一个AI语言模型,我可以回答各种问题,包括但不限于:天气、新闻、历史、文化、科学、教育、娱乐等。请问您有什么需要了解的吗?']
from paddlenlp.transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-0.5B")
# if using CPU, please change float16 to float32
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2-0.5B", dtype="float16")
input_features = tokenizer("你好!请自我介绍一下。", return_tensors="pd")
outputs = model.generate(**input_features, max_new_tokens=128)
print(tokenizer.batch_decode(outputs[0], skip_special_tokens=True))
# ['我是一个AI语言模型,我可以回答各种问题,包括但不限于:天气、新闻、历史、文化、科学、教育、娱乐等。请问您有什么需要了解的吗?']
```
### 大模型预训练

View File

@@ -47,9 +47,11 @@ fi
cd xFasterTransformer
git apply paddle.patch
# #4. build xFasterTransformer
sh ./3rdparty/prepare_oneccl.sh
source ./3rdparty/oneccl/build/_install/env/setvars.sh
#4. build xFasterTransformer
cd 3rdparty
bash prepare_oneccl.sh
source ./oneccl/build/_install/env/setvars.sh
cd ..
rm -rf build
mkdir build && cd build

View File

@@ -15,7 +15,7 @@
#include "matmul_helper.h"
#include "my_types.h"
#include "paddle/extension.h"
git adtemplate <typename T>
template <typename T>
void AvxCompute(const paddle::Tensor &x,
const paddle::Tensor &weight,
bool trans,

View File

@@ -14,9 +14,20 @@
#include <stdlib.h>
#include <string.h>
#include "helper.h"
#include <stdio.h>
#include <vector>
#include "paddle/extension.h"
bool is_in_end(const int64_t id, const int64_t *end_ids, int length) {
bool flag = false;
for (int i = 0; i < length; i++) {
if (id == end_ids[i]) {
return true;
}
}
return flag;
}
void set_value_by_flags(const bool* stop_flags,
const int64_t* end_ids,

125
csrc/gpu/all_reduce.cu Normal file
View File

@@ -0,0 +1,125 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "helper.h"
#include "all_reduce.cuh"
// Fake pointer type, must match fptr_t type in ops.h.
// We use this type alias to indicate when pointers are passed in as int64_t.
using fptr_t = int64_t;
static_assert(sizeof(void*) == sizeof(fptr_t));
fptr_t init_custom_all_reduce(const std::vector<fptr_t>& fake_ipc_ptrs,
paddle::Tensor& rank_data, int64_t rank,
bool full_nvlink) {
int world_size = fake_ipc_ptrs.size();
if (world_size > 8)
throw std::invalid_argument("world size > 8 is not supported");
if (world_size % 2 != 0)
throw std::invalid_argument("Odd num gpus is not supported for now");
if (rank < 0 || rank >= world_size)
throw std::invalid_argument("invalid rank passed in");
paddle::Signal* ipc_ptrs[8];
for (int i = 0; i < world_size; i++) {
ipc_ptrs[i] = reinterpret_cast<paddle::Signal*>(fake_ipc_ptrs[i]);
}
return (fptr_t) new paddle::CustomAllreduce(ipc_ptrs, rank_data.data(),
rank_data.numel(), rank, world_size,
full_nvlink);
}
/**
* Performs an out-of-place allreduce and stores result in out.
*
* If _reg_buffer is null, assumes inp.data() is already IPC-registered.
* Otherwise, _reg_buffer is assumed to be IPC-registered and inp is first
* copied into _reg_buffer.
*/
void all_reduce(fptr_t _fa, paddle::Tensor& inp, paddle::Tensor& out,
fptr_t _reg_buffer, int64_t reg_buffer_sz_bytes) {
auto fa = reinterpret_cast<paddle::CustomAllreduce*>(_fa);
auto stream = inp.stream();
auto input_size = inp.numel() * 2;
auto reg_buffer = reinterpret_cast<void*>(_reg_buffer);
if (reg_buffer) {
cudaMemcpyAsync(reg_buffer, inp.data(), input_size,
cudaMemcpyDeviceToDevice, stream);
} else {
reg_buffer = inp.data();
}
switch (out.dtype()) {
case phi::DataType::FLOAT32: {
fa->allreduce<float>(stream, reinterpret_cast<float*>(reg_buffer),
reinterpret_cast<float*>(out.data()),
out.numel());
break;
}
case phi::DataType::FLOAT16: {
fa->allreduce<half>(stream, reinterpret_cast<half*>(reg_buffer),
reinterpret_cast<half*>(out.data()), out.numel());
break;
}
#if (!defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 800)
case phi::DataType::BFLOAT16: {
fa->allreduce<nv_bfloat16>(
stream, reinterpret_cast<nv_bfloat16*>(reg_buffer),
reinterpret_cast<nv_bfloat16*>(out.data()), out.numel());
break;
}
#endif
default:
throw std::runtime_error(
"custom allreduce only supports float32, float16 and bfloat16");
}
}
void dispose(fptr_t _fa) {
delete reinterpret_cast<paddle::CustomAllreduce*>(_fa);
}
int64_t meta_size() { return sizeof(paddle::Signal); }
void register_buffer(fptr_t _fa, const std::vector<fptr_t>& fake_ipc_ptrs) {
auto fa = reinterpret_cast<paddle::CustomAllreduce*>(_fa);
void* ipc_ptrs[8];
for (int i = 0; i < fake_ipc_ptrs.size(); i++) {
ipc_ptrs[i] = reinterpret_cast<void*>(fake_ipc_ptrs[i]);
}
fa->register_buffer(ipc_ptrs);
}
// Use vector<int64_t> to represent byte data for python binding compatibility.
std::tuple<std::vector<int64_t>, std::vector<int64_t>>
get_graph_buffer_ipc_meta(fptr_t _fa) {
auto fa = reinterpret_cast<paddle::CustomAllreduce*>(_fa);
auto [handle, offsets] = fa->get_graph_buffer_ipc_meta();
std::vector<int64_t> bytes(handle.begin(), handle.end());
return std::make_tuple(bytes, offsets);
}
// Use vector<int64_t> to represent byte data for python binding compatibility.
void register_graph_buffers(fptr_t _fa,
const std::vector<std::vector<int64_t>>& handles,
const std::vector<std::vector<int64_t>>& offsets) {
auto fa = reinterpret_cast<paddle::CustomAllreduce*>(_fa);
std::vector<std::string> bytes;
bytes.reserve(handles.size());
for (int i = 0; i < handles.size(); i++) {
bytes.emplace_back(handles[i].begin(), handles[i].end());
}
bytes.reserve(handles.size());
fa->register_graph_buffers(bytes, offsets);
}

528
csrc/gpu/all_reduce.cuh Normal file
View File

@@ -0,0 +1,528 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <cuda.h>
#include <cuda_bf16.h>
#include <cuda_fp16.h>
#include <cuda_runtime.h>
#include <iostream>
#include <array>
#include <limits>
#include <map>
#include <unordered_map>
#include <vector>
#define CUDACHECK(cmd) \
do { \
cudaError_t e = cmd; \
if (e != cudaSuccess) { \
printf("Failed: Cuda error %s:%d '%s'\n", __FILE__, __LINE__, \
cudaGetErrorString(e)); \
exit(EXIT_FAILURE); \
} \
} while (0)
namespace paddle {
constexpr int kMaxBlocks = 36;
// Counter may overflow, but it's fine since unsigned int overflow is
// well-defined behavior.
using FlagType = uint32_t;
struct Signal {
alignas(128) FlagType self_counter[kMaxBlocks][8];
// Two sets of peer counters are needed for two syncs. The reason is that
// it's possible for peer GPU block to arrive at the second sync point while
// the current GPU block haven't passed the first sync point. Thus, peer GPU
// may write counter+1 while current GPU is busy waiting for counter. We use
// alternating counter array to avoid this possibility.
alignas(128) FlagType peer_counter[2][kMaxBlocks][8];
};
struct __align__(16) RankData {
const void* __restrict__ ptrs[8];
};
struct __align__(16) RankSignals {
Signal* signals[8];
};
// like std::array, but aligned
template <typename T, int sz>
struct __align__(alignof(T) * sz) array_t {
T data[sz];
using type = T;
static constexpr int size = sz;
};
// use packed type to maximize memory efficiency
// goal: generate ld.128 and st.128 instructions
template <typename T>
struct packed_t {
// the (P)acked type for load/store
using P = array_t<T, 16 / sizeof(T)>;
// the (A)ccumulator type for reduction
using A = array_t<float, 16 / sizeof(T)>;
};
#define DINLINE __device__ __forceinline__
// scalar cast functions
DINLINE float upcast_s(half val) { return __half2float(val); }
template <typename T>
DINLINE T downcast_s(float val);
template <>
DINLINE half downcast_s(float val) {
return __float2half(val);
}
// scalar add functions
// for some reason when compiling with Paddle, the + operator for half and
// bfloat is disabled so we call the intrinsics directly
DINLINE half& assign_add(half& a, half b) {
a = __hadd(a, b);
return a;
}
DINLINE float& assign_add(float& a, float b) { return a += b; }
#if (!defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 800)
DINLINE float upcast_s(nv_bfloat16 val) { return __bfloat162float(val); }
template <>
DINLINE nv_bfloat16 downcast_s(float val) {
return __float2bfloat16(val);
}
DINLINE nv_bfloat16& assign_add(nv_bfloat16& a, nv_bfloat16 b) {
a = __hadd(a, b);
return a;
}
#endif
template <typename T, int N>
DINLINE array_t<T, N>& packed_assign_add(array_t<T, N>& a, array_t<T, N> b) {
#pragma unroll
for (int i = 0; i < N; i++) {
assign_add(a.data[i], b.data[i]);
}
return a;
}
template <typename T, int N>
DINLINE array_t<float, N> upcast(array_t<T, N> val) {
if constexpr (std::is_same<T, float>::value) {
return val;
} else {
array_t<float, N> out;
#pragma unroll
for (int i = 0; i < N; i++) {
out.data[i] = upcast_s(val.data[i]);
}
return out;
}
}
template <typename O>
DINLINE O downcast(array_t<float, O::size> val) {
if constexpr (std::is_same<typename O::type, float>::value) {
return val;
} else {
O out;
#pragma unroll
for (int i = 0; i < O::size; i++) {
out.data[i] = downcast_s<typename O::type>(val.data[i]);
}
return out;
}
}
static DINLINE void st_flag_release(FlagType* flag_addr, FlagType flag) {
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 700
asm volatile("st.release.sys.global.u32 [%1], %0;" ::"r"(flag),
"l"(flag_addr));
#else
asm volatile("membar.sys; st.volatile.global.u32 [%1], %0;" ::"r"(flag),
"l"(flag_addr));
#endif
}
static DINLINE FlagType ld_flag_acquire(FlagType* flag_addr) {
FlagType flag;
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 700
asm volatile("ld.acquire.sys.global.u32 %0, [%1];"
: "=r"(flag)
: "l"(flag_addr));
#else
asm volatile("ld.volatile.global.u32 %0, [%1]; membar.gl;"
: "=r"(flag)
: "l"(flag_addr));
#endif
return flag;
}
static DINLINE void st_flag_volatile(FlagType* flag_addr, FlagType flag) {
asm volatile("st.volatile.global.u32 [%1], %0;" ::"r"(flag), "l"(flag_addr));
}
static DINLINE FlagType ld_flag_volatile(FlagType* flag_addr) {
FlagType flag;
asm volatile("ld.volatile.global.u32 %0, [%1];"
: "=r"(flag)
: "l"(flag_addr));
return flag;
}
// is_start: whether this is the very first synchronization barrier.
// need_fence: whether a memory fence is needed. If true, a release-acquire
// semantic is used to enforce memory access order before and after this
// barrier.
template <int ngpus, bool is_start, bool need_fence = false>
DINLINE void multi_gpu_barrier(const RankSignals& sg, Signal* self_sg,
int rank) {
if constexpr (!is_start) __syncthreads();
static_assert(
!(is_start && need_fence)); // Start barrier shouldn't need fence.
if (threadIdx.x < ngpus) {
// Increment the counter. Technically we only need one counter, but we use
// multiple per block to eliminate the need to share the counter via smem.
auto val = self_sg->self_counter[blockIdx.x][threadIdx.x] += 1;
// Write the expected counter value to peer and wait for correct value from
// peer.
auto peer_counter_ptr =
&sg.signals[threadIdx.x]->peer_counter[val % 2][blockIdx.x][rank];
auto self_counter_ptr =
&self_sg->peer_counter[val % 2][blockIdx.x][threadIdx.x];
if constexpr (need_fence) {
st_flag_release(peer_counter_ptr, val);
while (ld_flag_acquire(self_counter_ptr) != val);
} else {
st_flag_volatile(peer_counter_ptr, val);
while (ld_flag_volatile(self_counter_ptr) != val);
}
}
if constexpr (is_start || need_fence) __syncthreads();
}
template <typename P, int ngpus, typename A>
DINLINE P packed_reduce(const P* ptrs[], int idx) {
A tmp = upcast(ptrs[0][idx]);
#pragma unroll
for (int i = 1; i < ngpus; i++) {
packed_assign_add(tmp, upcast(ptrs[i][idx]));
}
return downcast<P>(tmp);
}
template <typename T, int ngpus>
__global__ void __launch_bounds__(512, 1)
cross_device_reduce_1stage(RankData* _dp, RankSignals sg, Signal* self_sg,
T* __restrict__ result, int rank, int size) {
using P = typename packed_t<T>::P;
using A = typename packed_t<T>::A;
// note: we don't reorder the address so the accumulation order is the same
// for all ranks, ensuring bitwise identical results
auto dp = *_dp;
multi_gpu_barrier<ngpus, true>(sg, self_sg, rank);
// do the actual reduction
for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < size;
idx += gridDim.x * blockDim.x) {
((P*)result)[idx] = packed_reduce<P, ngpus, A>((const P**)&dp.ptrs[0], idx);
}
multi_gpu_barrier<ngpus, false>(sg, self_sg, rank);
}
template <typename P>
DINLINE P* get_tmp_buf(Signal* sg) {
return (P*)(((Signal*)sg) + 1);
}
template <typename T, int ngpus>
__global__ void __launch_bounds__(512, 1)
cross_device_reduce_2stage(RankData* _dp, RankSignals sg, Signal* self_sg,
T* __restrict__ result, int rank, int size) {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int stride = gridDim.x * blockDim.x;
using P = typename packed_t<T>::P;
using A = typename packed_t<T>::A;
int part = size / ngpus;
int start = rank * part;
int end = rank == ngpus - 1 ? size : start + part;
int largest_part = part + size % ngpus;
const P* ptrs[ngpus];
P* tmps[ngpus];
#pragma unroll
for (int i = 0; i < ngpus; i++) {
int target = (rank + i) % ngpus;
ptrs[i] = (const P*)_dp->ptrs[target];
tmps[i] = get_tmp_buf<P>(sg.signals[target]);
}
auto tmp_out = tmps[0];
multi_gpu_barrier<ngpus, true>(sg, self_sg, rank);
// stage 1: reduce scatter
for (int idx = start + tid; idx < end; idx += stride) {
tmp_out[idx - start] = packed_reduce<P, ngpus, A>(ptrs, idx);
}
multi_gpu_barrier<ngpus, false, true>(sg, self_sg, rank);
// stage 2: allgather. Note: it's important to match the tid between
// the two stages, because visibility across devices is only guaranteed
// between threads that have the same tid. If thread i computes the sum of
// start + i in the first stage, then thread i also gathers start + i from all
// ranks.
for (int idx = tid; idx < largest_part; idx += stride) {
#pragma unroll
for (int i = 0; i < ngpus; i++) {
int gather_from_rank = ((rank + i) % ngpus);
if (gather_from_rank == ngpus - 1 || idx < part) {
int dst_idx = gather_from_rank * part + idx;
((P*)result)[dst_idx] = tmps[i][idx];
}
}
}
}
using IPC_KEY = std::array<uint8_t, sizeof(cudaIpcMemHandle_t)>;
static_assert(sizeof(IPC_KEY) == sizeof(cudaIpcMemHandle_t));
static_assert(alignof(IPC_KEY) == alignof(cudaIpcMemHandle_t));
class CustomAllreduce {
public:
int rank_;
int world_size_;
bool full_nvlink_;
RankSignals sg_;
// Stores an map from a pointer to its peer pointters from all ranks.
std::unordered_map<void*, RankData*> buffers_;
Signal* self_sg_;
// Stores rank data from all ranks. This is mainly for cuda graph purposes.
// For cuda graph to work, all kernel arguments must be fixed during graph
// capture time. However, the peer pointers are not known during graph capture
// time. Therefore, during capture, we increment the rank data pointer and use
// that as the argument to the kernel. The kernel arguments are stored in
// graph_unreg_buffers_. The actual peer pointers will be filled in at the
// memory pointed to by the pointers in graph_unreg_buffers_ when
// the IPC handles are exchanged between ranks.
//
// The overall process looks like this:
// 1. Graph capture.
// 2. Each rank obtains the IPC handles for each addresses used during cuda
// graph capture using get_graph_buffer_ipc_meta.
// 3. (In Python) all gather the IPC handles.
// 4. Obtain the peer pointers by opening the IPC handles, and store them in
// the rank data array at corresponding positions.
RankData *d_rank_data_base_, *d_rank_data_end_;
std::vector<void*> graph_unreg_buffers_;
// a map from IPC handles to opened IPC pointers
std::map<IPC_KEY, char*> ipc_handles_;
/**
* Signals are an array of ipc-enabled buffers from all ranks.
* For each of the buffer, the layout is as follows:
* | -- sizeof(Signal) -- | ------ a few MB ----- |
* The first section is for allreduce synchronization, and the second section
* is for storing the intermediate results required by some allreduce algos.
*
* Note: this class does not own any device memory. Any required buffers
* are passed in from the constructor.
*/
CustomAllreduce(Signal** signals, void* rank_data, size_t rank_data_sz,
int rank, int world_size, bool full_nvlink = true)
: rank_(rank),
world_size_(world_size),
full_nvlink_(full_nvlink),
self_sg_(signals[rank]),
d_rank_data_base_(reinterpret_cast<RankData*>(rank_data)),
d_rank_data_end_(d_rank_data_base_ + rank_data_sz / sizeof(RankData)) {
for (int i = 0; i < world_size_; i++) {
sg_.signals[i] = signals[i];
}
}
char* open_ipc_handle(const void* ipc_handle) {
auto [it, new_handle] =
ipc_handles_.insert({*((IPC_KEY*)ipc_handle), nullptr});
if (new_handle) {
char* ipc_ptr;
CUDACHECK(cudaIpcOpenMemHandle((void**)&ipc_ptr,
*((const cudaIpcMemHandle_t*)ipc_handle),
cudaIpcMemLazyEnablePeerAccess));
it->second = ipc_ptr;
}
return it->second;
}
std::pair<std::string, std::vector<int64_t>> get_graph_buffer_ipc_meta() {
auto num_buffers = graph_unreg_buffers_.size();
auto handle_sz = sizeof(cudaIpcMemHandle_t);
std::string handles(handle_sz * num_buffers, static_cast<char>(0));
std::vector<int64_t> offsets(num_buffers);
for (int i = 0; i < num_buffers; i++) {
auto ptr = graph_unreg_buffers_[i];
void* base_ptr;
// note: must share the base address of each allocation, or we get wrong
// address
if (cuPointerGetAttribute(&base_ptr,
CU_POINTER_ATTRIBUTE_RANGE_START_ADDR,
(CUdeviceptr)ptr) != CUDA_SUCCESS)
throw std::runtime_error("failed to get pointer attr");
CUDACHECK(cudaIpcGetMemHandle(
(cudaIpcMemHandle_t*)&handles[i * handle_sz], base_ptr));
offsets[i] = ((char*)ptr) - ((char*)base_ptr);
}
return std::make_pair(handles, offsets);
}
void check_rank_data_capacity(size_t num = 1) {
if (d_rank_data_base_ + num > d_rank_data_end_)
throw std::runtime_error(
"Rank data buffer is overflowed by " +
std::to_string(d_rank_data_base_ + num - d_rank_data_end_));
}
/**
* Register already-shared IPC pointers.
*/
void register_buffer(void** ptrs) {
check_rank_data_capacity();
RankData data;
for (int i = 0; i < world_size_; i++) {
data.ptrs[i] = ptrs[i];
}
auto d_data = d_rank_data_base_++;
CUDACHECK(
cudaMemcpy(d_data, &data, sizeof(RankData), cudaMemcpyHostToDevice));
buffers_[ptrs[rank_]] = d_data;
}
// Note: when registering graph buffers, we intentionally choose to not
// deduplicate the addresses. That means if the allocator reuses some
// addresses, they will be registered again. This is to account for the remote
// possibility of different allocation patterns between ranks. For example,
// rank 1 may get the same input address for the second allreduce, but rank 2
// got a different address. IPC handles have internal reference counting
// mechanism so overhead should be small.
void register_graph_buffers(
const std::vector<std::string>& handles,
const std::vector<std::vector<int64_t>>& offsets) {
auto num_buffers = graph_unreg_buffers_.size();
check_rank_data_capacity(num_buffers);
std::vector<RankData> rank_data(num_buffers);
for (int i = 0; i < num_buffers; i++) {
auto self_ptr = graph_unreg_buffers_[i];
auto& rd = rank_data[i];
for (int j = 0; j < world_size_; j++) {
if (j != rank_) {
char* handle =
open_ipc_handle(&handles[j][i * sizeof(cudaIpcMemHandle_t)]);
handle += offsets[j][i];
rd.ptrs[j] = handle;
} else {
rd.ptrs[j] = self_ptr;
}
}
}
CUDACHECK(cudaMemcpy(d_rank_data_base_, rank_data.data(),
sizeof(RankData) * num_buffers,
cudaMemcpyHostToDevice));
d_rank_data_base_ += num_buffers;
graph_unreg_buffers_.clear();
}
/**
* Performs allreduce, assuming input has already been registered.
*
* Block and grid default configs are results after careful grid search. Using
* 36 blocks give the best or close to the best runtime on the devices I
* tried: A100, A10, A30, T4, V100. You'll notice that NCCL kernels also only
* take a small amount of SMs. Not quite sure the underlying reason, but my
* guess is that too many SMs will cause contention on NVLink bus.
*/
template <typename T>
void allreduce(cudaStream_t stream, T* input, T* output, int size,
int threads = 512, int block_limit = 36) {
// std::cout<<"input "<< input <<" output "<< output<<std::endl;
auto d = packed_t<T>::P::size;
if (size % d != 0)
throw std::runtime_error(
"custom allreduce currently requires input length to be multiple "
"of " +
std::to_string(d));
if (block_limit > kMaxBlocks)
throw std::runtime_error("max supported block limit is " +
std::to_string(kMaxBlocks) + ". Got " +
std::to_string(block_limit));
RankData* ptrs;
cudaStreamCaptureStatus status;
CUDACHECK(cudaStreamIsCapturing(stream, &status));
if (status == cudaStreamCaptureStatusActive) {
ptrs = d_rank_data_base_ + graph_unreg_buffers_.size();
graph_unreg_buffers_.push_back(input);
} else {
auto it = buffers_.find(input);
if (it == buffers_.end())
throw std::runtime_error(
"buffer address " +
std::to_string(reinterpret_cast<uint64_t>(input)) +
" is not registered!");
ptrs = it->second;
}
size /= d;
auto bytes = size * sizeof(typename packed_t<T>::P);
int blocks = std::min(block_limit, (size + threads - 1) / threads);
#define KL(ngpus, name) \
name<T, ngpus><<<blocks, threads, 0, stream>>>(ptrs, sg_, self_sg_, output, \
rank_, size);
// TODO(hanzhi713): Threshold is different for A100 and H100.
// Add per device threshold.
#define REDUCE_CASE(ngpus) \
case ngpus: { \
if (world_size_ == 2) { \
KL(ngpus, cross_device_reduce_1stage); \
} else if (full_nvlink_) { \
if ((world_size_ <= 4 && bytes < 512 * 1024) || \
(world_size_ <= 8 && bytes < 256 * 1024)) { \
KL(ngpus, cross_device_reduce_1stage); \
} else { \
KL(ngpus, cross_device_reduce_2stage); \
} \
} \
break; \
}
switch (world_size_) {
REDUCE_CASE(2)
REDUCE_CASE(4)
REDUCE_CASE(6)
REDUCE_CASE(8)
default:
throw std::runtime_error(
"custom allreduce only supports num gpus in (2,4,6,8). Actual num "
"gpus = " +
std::to_string(world_size_));
}
#undef REDUCE_CASE
#undef KL
}
~CustomAllreduce() {
for (auto [_, ptr] : ipc_handles_) {
CUDACHECK(cudaIpcCloseMemHandle(ptr));
}
}
};
} // namespace paddle

30
csrc/gpu/all_reduce.h Normal file
View File

@@ -0,0 +1,30 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "helper.h"
using fptr_t = int64_t;
fptr_t init_custom_all_reduce(const std::vector<int64_t>& fake_ipc_ptrs,
paddle::Tensor& rank_data, int64_t rank, bool full_nvlink);
void all_reduce(fptr_t _fa, paddle::Tensor& inp, paddle::Tensor& out,
fptr_t reg_buffer, int64_t reg_buffer_sz_bytes);
void dispose(fptr_t _fa);
int64_t meta_size();
void register_buffer(fptr_t _fa, const std::vector<int64_t>& fake_ipc_ptrs);
std::tuple<std::vector<int64_t>, std::vector<int64_t>>
get_graph_buffer_ipc_meta(fptr_t _fa);
void register_graph_buffers(fptr_t _fa,
const std::vector<std::vector<int64_t>>& handles,
const std::vector<std::vector<int64_t>>& offsets);

View File

@@ -53,6 +53,7 @@ std::vector<paddle::Tensor> AppendAttentionKernel(
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& out_linear_shifts,
const paddle::optional<paddle::Tensor>& out_linear_smooths,
const paddle::optional<paddle::Tensor>& excess_blocks,
const std::string& cache_quant_type_str,
const bool use_neox_rotary_style,
const int max_input_length,
@@ -140,6 +141,7 @@ std::vector<paddle::Tensor> AppendAttentionKernel(
cache_v_quant_scales,
cache_k_zp,
cache_v_zp,
excess_blocks,
cache_quant_type_str,
kv_num_blocks_data,
max_input_length,
@@ -167,6 +169,7 @@ std::vector<paddle::Tensor> AppendAttentionKernel(
cache_v_quant_scales,
cache_k_zp,
cache_v_zp,
excess_blocks,
cache_quant_type_str,
kv_num_blocks_data,
max_input_length,
@@ -568,6 +571,7 @@ std::vector<paddle::Tensor> AppendAttention(
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& out_linear_shifts,
const paddle::optional<paddle::Tensor>& out_linear_smooths,
const paddle::optional<paddle::Tensor>& excess_blocks,
const std::string& compute_dtype,
const std::string& cache_quant_type_str,
const bool use_neox_rotary_style,
@@ -632,6 +636,7 @@ std::vector<paddle::Tensor> AppendAttention(
cache_v_zp,
out_linear_shifts,
out_linear_smooths,
excess_blocks,
cache_quant_type_str,
use_neox_rotary_style,
max_input_length,
@@ -679,6 +684,7 @@ std::vector<paddle::Tensor> AppendAttention(
cache_v_zp,
out_linear_shifts,
out_linear_smooths,
excess_blocks,
cache_quant_type_str,
use_neox_rotary_style,
max_input_length,
@@ -727,6 +733,7 @@ std::vector<paddle::Tensor> AppendAttention(
cache_v_zp,
out_linear_shifts,
out_linear_smooths,
excess_blocks,
cache_quant_type_str,
use_neox_rotary_style,
max_input_length,
@@ -773,6 +780,7 @@ std::vector<paddle::Tensor> AppendAttention(
cache_v_zp,
out_linear_shifts,
out_linear_smooths,
excess_blocks,
cache_quant_type_str,
use_neox_rotary_style,
max_input_length,
@@ -831,7 +839,8 @@ std::vector<std::vector<int64_t>> AppendAttentionInferShape(
const paddle::optional<std::vector<int64_t>>& cache_k_zp_shape,
const paddle::optional<std::vector<int64_t>>& cache_v_zp_shape,
const paddle::optional<std::vector<int64_t>>& out_linear_shifts_shape,
const paddle::optional<std::vector<int64_t>>& out_linear_smooths_shape) {
const paddle::optional<std::vector<int64_t>>& out_linear_smooths_shape,
const paddle::optional<std::vector<int64_t>>& excess_blocks_shape) {
const int token_num = qkv_shape[0];
const int kv_num_heads = key_cache_shape[1];
const int head_dim_qk = key_cache_shape[3];
@@ -876,6 +885,7 @@ std::vector<paddle::DataType> AppendAttentionInferDtype(
const paddle::optional<paddle::DataType>& cache_v_zp_dtype,
const paddle::optional<paddle::DataType>& out_linear_shifts_dtype,
const paddle::optional<paddle::DataType>& out_linear_smooths_dtype,
const paddle::optional<paddle::DataType>& excess_blocks_dtype,
const std::string& compute_dtype,
const std::string& cache_quant_type_str,
const bool use_neox_rotary_style,
@@ -949,7 +959,8 @@ PD_BUILD_OP(append_attention)
paddle::Optional("cache_k_zp"),
paddle::Optional("cache_v_zp"),
paddle::Optional("out_linear_shifts"),
paddle::Optional("out_linear_smooths")})
paddle::Optional("out_linear_smooths"),
paddle::Optional("excess_blocks")})
.Outputs({"fmha_out", "qkv_out", "key_cache_out", "value_cache_out"})
.SetInplaceMap({{"key_cache", "key_cache_out"},
{"value_cache", "value_cache_out"}})

View File

@@ -146,8 +146,11 @@ __global__ void multi_query_decode_attention_kernel(T * __restrict__ q, // [toke
T * __restrict__ tmp_m, // [batch_size, num_chunks, num_heads]
T * __restrict__ tmp_d, // [batch_size, num_chunks, num_heads]
OutT * __restrict__ out) {
constexpr uint32_t q_block_num = GROUP_SIZE / bdy;
const uint32_t bidx = blockIdx.x, kv_head_idx = blockIdx.z;
const uint32_t bid = bidx, gid = threadIdx.y;
const uint32_t bid = bidx / q_block_num, q_block_idx = bidx % q_block_num;
const uint32_t bidy = threadIdx.y;
const uint32_t gid = q_block_idx * bdy + threadIdx.y;
const uint32_t tidx = threadIdx.x;
constexpr uint32_t num_vec_per_head_qk = HEAD_DIM_QK / VEC_SIZE;
constexpr uint32_t num_vec_per_head_v = HEAD_DIM_V / VEC_SIZE;
@@ -184,11 +187,10 @@ __global__ void multi_query_decode_attention_kernel(T * __restrict__ q, // [toke
extern __shared__ uint8_t smem[];
const T *q_now = q + (q_start_idx * q_num_heads + q_head_idx) * HEAD_DIM_QK;
T *q_smem = reinterpret_cast<T*>(smem); // [HEAD_DIM_QK * sizeof(T)]
T *cu_q_smem = q_smem + gid * HEAD_DIM_QK;
T *cu_q_smem = q_smem + bidy * HEAD_DIM_QK;
#pragma unroll
for(uint32_t vid = tidx; vid < num_vec_per_head_qk; vid += bdx) {
((float4*)(&cu_q_smem[vid * VEC_SIZE]))[0] = ((float4*)(&q_now[vid * VEC_SIZE]))[0];
}
__syncthreads();
using VecT = AlignedVector<T, VEC_SIZE>;
@@ -203,14 +205,14 @@ __global__ void multi_query_decode_attention_kernel(T * __restrict__ q, // [toke
}
CacheT *kv_smem = reinterpret_cast<CacheT*>(smem + GROUP_SIZE * HEAD_DIM_QK * sizeof(CacheT));
CacheT *kv_smem = reinterpret_cast<CacheT*>(smem + bdy * HEAD_DIM_QK * sizeof(CacheT));
uint32_t stage_idx = 0;
constexpr int loop_times = DEAL_EACH_TIME / bdy;
#pragma unroll
for (int i = 0; i < NUM_STAGES; ++i) {
#pragma unroll
for (int j = 0; j < loop_times; ++j) {
const uint32_t k_seq_offset = i * DEAL_EACH_TIME + j * bdy + gid;
const uint32_t k_seq_offset = i * DEAL_EACH_TIME + j * bdy + bidy;
const uint32_t k_seq_id = chunk_start + k_seq_offset;
produce_kv<SharedMemFillMode::kNoFill, HEAD_DIM_QK, VEC_SIZE, num_vec_per_head_qk, bdx, BLOCK_SIZE, CACHE_VEC_SIZE>(
kv_smem,
@@ -267,7 +269,7 @@ __global__ void multi_query_decode_attention_kernel(T * __restrict__ q, // [toke
#pragma unroll
for (int j = 0; j < loop_times; ++j) {
const uint32_t k_seq_offset = j * bdy + gid;
const uint32_t k_seq_offset = j * bdy + bidy;
produce_kv<SharedMemFillMode::kNoFill, HEAD_DIM_QK, VEC_SIZE, num_vec_per_head_qk, bdx, BLOCK_SIZE, CACHE_VEC_SIZE>(
kv_smem,
cache_k,
@@ -342,10 +344,10 @@ void MultiQueryDecoderAttention(
constexpr int num_vec_per_head = HEAD_DIM_QK / vec_size;
constexpr int blockx = num_vec_per_head < 32 ? num_vec_per_head : 32;
constexpr int blocky = GROUP_SIZE;
const int gridx = bsz;
constexpr int blocky = GROUP_SIZE > 16 ? 16 : GROUP_SIZE;
const int gridx = bsz * (GROUP_SIZE / blocky);
constexpr int num_threads = blockx * blocky;
constexpr int num_threads = blockx * blocky;
auto splitkv_kernel = multi_query_decode_attention_kernel<true, NV_TYPE, NV_TYPE, NV_TYPE, num_stages, DEAL_EACH_TIME, GROUP_SIZE, HEAD_DIM_QK, HEAD_DIM_V,
BLOCK_SIZE, vec_size, cache_vec_size, blockx, blocky>;
@@ -357,7 +359,7 @@ void MultiQueryDecoderAttention(
const uint32_t chunk_size = get_max_partition_size(bsz);
const int num_chunks = div_up(max_dec_len, chunk_size);
size_t smem_size = cache_smem_bytes + GROUP_SIZE * HEAD_DIM_QK * sizeof(T);
size_t smem_size = cache_smem_bytes + blocky * HEAD_DIM_QK * sizeof(T);
if (smem_size >= 48 * 1024) {
cudaFuncSetAttribute(

View File

@@ -691,6 +691,99 @@ __global__ void cache_kernel(
}
}
template <typename T, int VecSize = 1>
__global__ void cache_use_excess_kernel(
const T *__restrict__ qkv, // [num_tokens, num_heads + 2 * kv_num_heads,
// head_size]
T *__restrict__ key_cache, // [num_blocks, kv_num_heads, block_size,
// head_size]
T *__restrict__ value_cache, // [num_blocks, kv_num_heads, block_size,
// head_size]
const int *__restrict__ block_tables, // [bsz, max_blocks_per_seq]
const int *__restrict__ padding_offsets, // [num_tokens]
const int *__restrict__ cum_offsets,
const int *__restrict__ seq_lens, // [bsz]
const int *__restrict__ seq_lens_decoder, // [bsz]
const int *__restrict__ excess_blocks, // [bsz, excess_num]
const int max_seq_len,
const int max_blocks_per_seq,
const int num_heads,
const int head_size,
const int block_size,
const uint32_t elem_cnt,
const int kv_num_heads,
const int token_num,
const int excess_num) {
using LoadT = AlignedVector<T, VecSize>;
LoadT src_vec;
uint32_t global_thread_idx = blockDim.x * blockIdx.x + threadIdx.x;
const uint32_t hidden_size = kv_num_heads * head_size;
const uint32_t offset = 2 * hidden_size;
for (uint32_t linear_index = global_thread_idx * VecSize,
step = gridDim.x * blockDim.x * VecSize;
linear_index < elem_cnt;
linear_index += step) {
uint32_t token_idx = linear_index / offset;
const uint32_t bias = linear_index % offset;
const uint32_t qkv_id = bias / hidden_size; // skip q
const uint32_t qkv_bias = bias % hidden_size;
const uint32_t hi = qkv_bias / head_size;
const uint32_t h_bias = qkv_bias % head_size;
uint32_t block_idx, block_offset;
if (token_idx < token_num) {
const uint32_t ori_token_idx = token_idx + padding_offsets[token_idx];
const uint32_t ori_bi = ori_token_idx / max_seq_len;
const uint32_t last_offset = seq_lens[ori_bi] % block_size;
if (seq_lens[ori_bi] == 0) continue;
const int32_t *block_table_now = nullptr;
block_table_now = block_tables + ori_bi * max_blocks_per_seq;
const uint32_t ori_seq_id =
ori_token_idx % max_seq_len + seq_lens_decoder[ori_bi];
if (ori_seq_id >= seq_lens[ori_bi] - last_offset) continue;
block_idx = block_table_now[ori_seq_id / block_size];
block_offset = ori_seq_id % block_size;
} else {
const uint32_t excess_token_id = token_idx - token_num;
const uint32_t ori_bi = excess_token_id / (excess_num * block_size);
const uint32_t last_offset = seq_lens[ori_bi] % block_size;
if (seq_lens[ori_bi] == 0) continue;
const uint32_t excess_id =
(excess_token_id % (excess_num * block_size)) / block_size;
const uint32_t excess_token_offset = excess_token_id % block_size;
if (excess_token_offset < last_offset) {
token_idx = ori_bi * max_seq_len - cum_offsets[ori_bi] +
seq_lens[ori_bi] - last_offset + excess_token_offset;
} else {
continue;
}
block_idx = excess_blocks[ori_bi * excess_num + excess_id];
block_offset = excess_token_offset;
}
const uint32_t tgt_idx =
block_idx * kv_num_heads * block_size * head_size +
hi * block_size * head_size + block_offset * head_size + h_bias;
const uint32_t ori_idx =
token_idx * (num_heads + 2 * kv_num_heads) * head_size +
num_heads * head_size + qkv_id * hidden_size + hi * head_size + h_bias;
Load<T, VecSize>(&qkv[ori_idx], &src_vec);
if (qkv_id == 0) {
Store<T, VecSize>(src_vec, &key_cache[tgt_idx]);
} else {
Store<T, VecSize>(src_vec, &value_cache[tgt_idx]);
}
}
}
template <typename T,
uint32_t num_frags_y,
@@ -1463,9 +1556,12 @@ void CascadeAppendWriteCacheKVQKV(
// kv_num_heads, head_dim] if GQA)
const paddle::Tensor &block_table,
const paddle::Tensor &padding_offsets,
const paddle::Tensor &cum_offsets,
const paddle::Tensor &seq_lens_encoder,
const paddle::Tensor &seq_lens_decoder,
const int max_seq_len,
const int bsz,
const paddle::optional<paddle::Tensor>& excess_blocks,
cudaStream_t &stream,
paddle::Tensor *key_cache_out,
paddle::Tensor *value_cache_out) {
@@ -1477,29 +1573,58 @@ void CascadeAppendWriteCacheKVQKV(
auto head_dim_v = meta_data.head_dims_v;
auto block_size = meta_data.block_size;
const uint32_t elem_nums =
num_tokens * kv_num_heads * (head_dim_qk + head_dim_v);
int excess_block_num = 0;
int *excess_blocks_ptr = nullptr;
if (excess_blocks) {
excess_block_num = excess_blocks.get().dims()[1];
excess_blocks_ptr =const_cast<int*>(excess_blocks.get().data<int>());
}
uint32_t elem_nums = (num_tokens + bsz * excess_block_num * block_size) * kv_num_heads * (head_dim_qk + head_dim_v);
// 额外每个bid 多分配excess_block_num * block_size 个
constexpr int PackSize = 16 / sizeof(T);
const int pack_num = elem_nums / PackSize;
const int blocksize = 128;
int grid_size = 1;
GetNumBlocks<128>(pack_num, &grid_size);
cache_kernel<T, PackSize><<<grid_size, blocksize, 0, stream>>>(
reinterpret_cast<T *>(const_cast<T *>(qkv.data<T>())),
reinterpret_cast<T *>(key_cache_out->data<T>()),
reinterpret_cast<T *>(value_cache_out->data<T>()),
block_table.data<int>(),
padding_offsets.data<int>(),
seq_lens_encoder.data<int>(),
seq_lens_decoder.data<int>(),
max_seq_len,
max_blocks_per_seq,
num_heads,
head_dim_qk,
head_dim_v,
block_size,
elem_nums,
kv_num_heads);
if (excess_blocks_ptr) {
cache_use_excess_kernel<T, PackSize><<<grid_size, blocksize, 0, stream>>>(
reinterpret_cast<T *>(const_cast<T *>(qkv.data<T>())),
reinterpret_cast<T *>(key_cache_out->data<T>()),
reinterpret_cast<T *>(value_cache_out->data<T>()),
block_table.data<int>(),
padding_offsets.data<int>(),
cum_offsets.data<int>(),
seq_lens_encoder.data<int>(),
seq_lens_decoder.data<int>(),
excess_blocks_ptr,
max_seq_len,
max_blocks_per_seq,
num_heads,
head_dim_qk,
block_size,
elem_nums,
kv_num_heads,
num_tokens,
excess_block_num);
} else {
cache_kernel<T, PackSize><<<grid_size, blocksize, 0, stream>>>(
reinterpret_cast<T *>(const_cast<T *>(qkv.data<T>())),
reinterpret_cast<T *>(key_cache_out->data<T>()),
reinterpret_cast<T *>(value_cache_out->data<T>()),
block_table.data<int>(),
padding_offsets.data<int>(),
seq_lens_encoder.data<int>(),
seq_lens_decoder.data<int>(),
max_seq_len,
max_blocks_per_seq,
num_heads,
head_dim_qk,
head_dim_v,
block_size,
elem_nums,
kv_num_heads);
}
}
template <typename T, uint32_t HEAD_DIM, uint32_t BLOCK_SIZE>

View File

@@ -36,6 +36,7 @@ void EncoderWriteCacheWithRopeKernel(
const paddle::optional<paddle::Tensor>& cache_v_scale,
const paddle::optional<paddle::Tensor>& cache_k_zp,
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& excess_blocks,
const std::string& cache_quant_type_str,
const int num_blocks,
const int max_seq_len,
@@ -48,6 +49,7 @@ void EncoderWriteCacheWithRopeKernel(
auto num_heads = meta_data.q_num_heads;
auto kv_num_heads = meta_data.kv_num_heads;
auto head_dim = meta_data.head_dims;
int bsz = cum_offsets.dims()[0];
if (rotary_embs) {
if (num_heads == kv_num_heads) {
rotary_qk_variable(
@@ -93,9 +95,12 @@ void EncoderWriteCacheWithRopeKernel(
*qkv_out,
block_tables,
padding_offsets,
cum_offsets,
seq_lens_encoder,
seq_lens_decoder,
max_seq_len,
bsz,
excess_blocks,
stream,
key_cache_out,
value_cache_out);

View File

@@ -224,7 +224,7 @@ std::vector<paddle::Tensor> GetBlockShapeAndSplitKVBlock(
int max_dec_len_this_time_data = max_dec_len_this_time.data<int>()[0];
if (max_dec_len_this_time_data > 0) {
const bool mla_use_tensorcore = GetMlaUseTensorcore();
if (mla_use_tensorcore) {
if (mla_use_tensorcore && group_size <=64) {
const int set_chunk_size = get_mla_dec_chunk_size(bsz);
decoder_chunk_size_device =
GetEmptyTensor({1}, paddle::DataType::INT32, seq_lens_encoder.place());
@@ -296,6 +296,8 @@ std::vector<paddle::Tensor> GetBlockShapeAndSplitKVBlock(
group_size);
decoder_num_blocks_x_cpu =
decoder_num_blocks_x.copy_to(paddle::CPUPlace(), false);
decoder_chunk_size_cpu =
paddle::full({1}, 131072, paddle::DataType::INT32, paddle::CPUPlace());
}
} else {
decoder_batch_ids =
@@ -303,7 +305,7 @@ std::vector<paddle::Tensor> GetBlockShapeAndSplitKVBlock(
decoder_tile_ids_per_batch =
paddle::full({1}, -1, paddle::DataType::INT32, paddle::GPUPlace());
decoder_chunk_size_cpu =
paddle::full({64}, -1, paddle::DataType::INT32, paddle::CPUPlace());
paddle::full({1}, 131072, paddle::DataType::INT32, paddle::CPUPlace());
decoder_num_blocks_x =
paddle::full({1}, -1, paddle::DataType::INT32, paddle::GPUPlace());
decoder_num_blocks_x_cpu =
@@ -401,6 +403,7 @@ std::vector<paddle::DataType> GetBlockShapeAndSplitKVBlockInferDtype(
paddle::DataType::INT32,
paddle::DataType::INT32,
paddle::DataType::INT32,
paddle::DataType::INT32,
paddle::DataType::INT32};
}
@@ -423,6 +426,7 @@ std::vector<std::vector<int64_t>> GetBlockShapeAndSplitKVBlockInferShape(
dynamic_shape,
{1},
{1},
{1},
{1}};
}

View File

@@ -34,6 +34,7 @@ EncoderWriteCacheWithRopeKernel<paddle::bfloat16, paddle::bfloat16>(
const paddle::optional<paddle::Tensor>& cache_v_scale,
const paddle::optional<paddle::Tensor>& cache_k_zp,
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& excess_blocks,
const std::string& cache_quant_type_str,
const int num_blocks,
const int max_seq_len,

View File

@@ -33,6 +33,7 @@ template void EncoderWriteCacheWithRopeKernel<paddle::bfloat16, int>(
const paddle::optional<paddle::Tensor>& cache_v_scale,
const paddle::optional<paddle::Tensor>& cache_k_zp,
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& excess_blocks,
const std::string& cache_quant_type_str,
const int num_blocks,
const int max_seq_len,

View File

@@ -33,6 +33,7 @@ template void EncoderWriteCacheWithRopeKernel<paddle::float16, paddle::float16>(
const paddle::optional<paddle::Tensor>& cache_v_scale,
const paddle::optional<paddle::Tensor>& cache_k_zp,
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& excess_blocks,
const std::string& cache_quant_type_str,
const int num_blocks,
const int max_seq_len,

View File

@@ -33,6 +33,7 @@ template void EncoderWriteCacheWithRopeKernel<paddle::float16, int>(
const paddle::optional<paddle::Tensor>& cache_v_scale,
const paddle::optional<paddle::Tensor>& cache_k_zp,
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& excess_blocks,
const std::string& cache_quant_type_str,
const int num_blocks,
const int max_seq_len,

365
csrc/gpu/cpp_extensions.cu Normal file
View File

@@ -0,0 +1,365 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "paddle/extension.h"
#include "all_reduce.h"
namespace py = pybind11;
std::vector<paddle::Tensor> AppendAttention(
const paddle::Tensor& qkv,
const paddle::Tensor& key_cache,
const paddle::Tensor& value_cache,
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& seq_lens_this_time,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const paddle::Tensor& encoder_batch_ids,
const paddle::Tensor& encoder_tile_ids_per_batch,
const paddle::Tensor& encoder_num_blocks,
const paddle::Tensor& kv_batch_ids,
const paddle::Tensor& kv_tile_ids_per_batch,
const paddle::Tensor& kv_num_blocks,
const paddle::Tensor& decoder_batch_ids,
const paddle::Tensor& decoder_tile_ids_per_batch,
const paddle::Tensor& decoder_num_blocks,
const paddle::Tensor& max_enc_len_this_time,
const paddle::Tensor& max_dec_len_this_time,
const paddle::Tensor& max_len_kv,
const paddle::optional<paddle::Tensor>& rotary_embs,
const paddle::optional<paddle::Tensor>& attn_mask,
const paddle::optional<paddle::Tensor>& qkv_bias,
const paddle::optional<paddle::Tensor>& qkv_out_scales,
const paddle::optional<paddle::Tensor>& cache_k_quant_scales,
const paddle::optional<paddle::Tensor>& cache_v_quant_scales,
const paddle::optional<paddle::Tensor>& cache_k_dequant_scales,
const paddle::optional<paddle::Tensor>& cache_v_dequant_scales,
const paddle::optional<paddle::Tensor>& cache_k_zp,
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& out_linear_shifts,
const paddle::optional<paddle::Tensor>& out_linear_smooths,
const paddle::optional<paddle::Tensor>& excess_blocks,
const std::string& compute_dtype,
const std::string& cache_quant_type_str,
const bool use_neox_rotary_style,
const int max_input_length,
const float softmax_scale,
const float quant_max_bound,
const float quant_min_bound,
const float out_linear_in_scale,
const int speculate_max_draft_token_num,
const bool causal,
const bool speculate_decoder);
void FusedRotaryPositionEncoding(
paddle::Tensor& query, // [num_tokens, num_heads, head_size] or
// [num_tokens, num_heads * head_size]
paddle::Tensor& key,
// [num_tokens, num_kv_heads, head_size] or [num_tokens, num_kv_heads *
// head_size]
const paddle::Tensor& position_ids, // [num_tokens]
const paddle::Tensor& cos_sin_cache, // [max_position, rot_dim]
int head_size,
bool is_neox);
std::vector<paddle::Tensor> MultiHeadLatentAttention(
const paddle::Tensor& query,
const paddle::Tensor& key_cache,
const paddle::Tensor& value_cache,
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& seq_lens_this_time,
const paddle::Tensor& cu_seqlens_q,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const paddle::Tensor& encoder_batch_ids,
const paddle::Tensor& encoder_tile_ids_per_batch,
const paddle::Tensor& encoder_num_blocks,
const paddle::Tensor& kv_batch_ids,
const paddle::Tensor& kv_tile_ids_per_batch,
const paddle::Tensor& kv_num_blocks,
const paddle::Tensor& decoder_batch_ids,
const paddle::Tensor& decoder_tile_ids_per_batch,
const paddle::Tensor& decoder_num_blocks,
const paddle::Tensor& decoder_num_blocks_cpu,
const paddle::Tensor& decoder_chunk_size_cpu,
const paddle::Tensor& max_enc_len_this_time,
const paddle::Tensor& max_dec_len_this_time,
const paddle::Tensor& max_len_kv,
const paddle::optional<paddle::Tensor>& attn_mask,
const paddle::optional<paddle::Tensor>& query_bias,
const paddle::optional<paddle::Tensor>& query_out_scales,
const paddle::optional<paddle::Tensor>& cache_k_quant_scales,
const paddle::optional<paddle::Tensor>& cache_v_quant_scales,
const paddle::optional<paddle::Tensor>& cache_k_dequant_scales,
const paddle::optional<paddle::Tensor>& cache_v_dequant_scales,
const paddle::optional<paddle::Tensor>& cache_k_zp,
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& out_linear_shifts,
const paddle::optional<paddle::Tensor>& out_linear_smooths,
const std::string& compute_dtype,
const std::string& cache_quant_type_str,
const int nope_size,
const int max_input_length,
const float softmax_scale,
const float quant_max_bound,
const float quant_min_bound,
const float out_linear_in_scale,
const int speculate_draft_total_token_num,
const bool causal,
const bool speculate_decoder);
std::vector<paddle::Tensor> GetBlockShapeAndSplitKVBlock(
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& max_enc_len_this_time,
const paddle::Tensor& max_dec_len_this_time,
const paddle::Tensor& seq_lens_this_time,
const paddle::Tensor& cum_offsets,
const int group_size,
const int block_size,
const int decoder_step_token_num);
std::vector<paddle::Tensor> NoauxTc(paddle::Tensor& scores,
paddle::Tensor& scores_with_bias,
int n_group,
int topk_group,
int topk,
float routed_scaling_factor);
std::vector<paddle::Tensor> PrefillMLAWriteCacheKernel(
const paddle::Tensor& kv_nope,
const paddle::Tensor& kv_pe,
const paddle::Tensor& kv_cache,
const paddle::Tensor& seq_lens,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const std::string& cache_quant_type_str,
const int max_seq_len);
std::vector<paddle::Tensor> DecodeMLAWriteCacheKernel(
const paddle::Tensor& kv_nope,
const paddle::Tensor& kv_pe,
const paddle::Tensor& kv_cache,
const paddle::Tensor& seq_lens,
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const std::string& cache_quant_type_str,
const int max_seq_len,
const bool speculate_decoder);
paddle::Tensor cutlass_fp8_fp8_half_block_gemm_fused_func(
const paddle::Tensor& x,
const paddle::Tensor& y,
const paddle::Tensor& x_scale,
const paddle::Tensor& y_scale,
const paddle::optional<paddle::Tensor>& bias,
bool trans_x,
bool trans_y,
std::string output_dtype,
std::string activation_type);
void GetPositionIdsAndMaskEncoderBatch(
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& seq_lens_this_time,
const paddle::Tensor& position_ids,
const paddle::Tensor& mask_encoder_batch);
void SetPreidsTokenPenaltyMultiScores(const paddle::Tensor& pre_ids,
const paddle::Tensor& input_ids,
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& step_idx,
const paddle::Tensor& stop_flags,
const paddle::Tensor& logits,
const paddle::Tensor& penalty_scores,
const paddle::Tensor& frequency_scores,
const paddle::Tensor& presence_scores,
const paddle::Tensor& temperatures,
const paddle::Tensor& bad_tokens,
const paddle::Tensor& cur_len,
const paddle::Tensor& min_len,
const paddle::Tensor& eos_token_id);
void UpdateInputesV2(const paddle::Tensor& stop_flags,
const paddle::Tensor& step_idx,
const paddle::Tensor& not_need_stop, // cpu
const paddle::Tensor& seq_lens_this_time,
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& max_dec_len,
const paddle::Tensor& input_ids,
const paddle::Tensor& stop_nums,
const paddle::Tensor& next_tokens,
const paddle::Tensor& is_block_step,
const paddle::Tensor& end_ids,
const paddle::Tensor& kwargs_next_tokens);
paddle::Tensor RebuildPaddingV2Func(const paddle::Tensor& tmp_out, // [token_num, dim_embed]
const paddle::Tensor& cum_offsets, // [bsz, 1]
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& seq_lens_encoder,
const paddle::optional<paddle::Tensor>& output_padding_offset,
int max_input_length);
std::vector<paddle::Tensor> PerTokenGroupQuant(const paddle::Tensor& x,
const int group_size,
const bool transpose_scale,
const float quant_max_bound,
const float quant_min_bound);
std::vector<paddle::Tensor> PerTensorQuantFp8(const paddle::Tensor& x, const paddle::optional<paddle::Tensor>& scale);
std::vector<paddle::Tensor> GetPaddingOffsetV2(const paddle::Tensor& input_ids,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& token_num,
const paddle::Tensor& seq_len,
const paddle::optional<paddle::Tensor>& draft_tokens,
const paddle::optional<paddle::Tensor>& seq_lens_encoder);
void SaveOutMmsg(const paddle::Tensor& x,
const paddle::Tensor& not_need_stop, // cpu
int64_t rank_id);
void GetOutput(const paddle::Tensor& x,
int64_t rank_id,
bool wait_flag);
void StepPaddle(const paddle::Tensor &stop_flags,
const paddle::Tensor &seq_lens_this_time,
const paddle::Tensor &ori_seq_lens_encoder,
const paddle::Tensor &seq_lens_encoder,
const paddle::Tensor &seq_lens_decoder,
const paddle::Tensor &block_tables, // [bsz, block_num_per_seq]
const paddle::Tensor &encoder_block_lens,
const paddle::Tensor &is_block_step,
const paddle::Tensor &step_block_list,
const paddle::Tensor &step_lens,
const paddle::Tensor &recover_block_list,
const paddle::Tensor &recover_lens,
const paddle::Tensor &need_block_list,
const paddle::Tensor &need_block_len,
const paddle::Tensor &used_list_len,
const paddle::Tensor &free_list,
const paddle::Tensor &free_list_len,
const paddle::Tensor &input_ids,
const paddle::Tensor &pre_ids,
const paddle::Tensor &step_idx,
const paddle::Tensor &next_tokens,
const paddle::Tensor &first_token_ids,
const int block_size,
const int encoder_decoder_block_num);
void SaveOutputDygraph(
const paddle::Tensor& all_token_ids,
const paddle::Tensor& tokens,
const paddle::Tensor& result_ids,
const paddle::Tensor& step_idx
);
PYBIND11_MODULE(paddlenlp_ops, m) {
/**
* all_reduce.cu
*/
m.def("init_custom_all_reduce", &init_custom_all_reduce, "init all reduce class function");
m.def("all_reduce", &all_reduce, "all reduce function");
m.def("dispose", &dispose, "del function for python");
m.def("meta_size", &meta_size, "meta_size function for Signal struct");
m.def("register_buffer", &register_buffer, "register ipc buffer");
m.def("f_append_attention", &AppendAttention, "AppendAttention");
m.def("f_fused_rotary_position_encoding", &FusedRotaryPositionEncoding, "FusedRotaryPositionEncoding");
m.def("f_multi_head_latent_attention", &MultiHeadLatentAttention, "MultiHeadLatentAttention");
m.def("f_noaux_tc", &NoauxTc, "NoauxTc");
m.def("f_get_block_shape_and_split_kv_block", &GetBlockShapeAndSplitKVBlock, "GetBlockShapeAndSplitKVBlock");
m.def("f_prefill_mla_write_cache", &PrefillMLAWriteCacheKernel, "PrefillMLAWriteCacheKernel");
m.def("f_decode_mla_write_cache", &DecodeMLAWriteCacheKernel, "DecodeMLAWriteCacheKernel");
m.def("f_get_position_ids_and_mask_encoder_batch", &GetPositionIdsAndMaskEncoderBatch, "GetPositionIdsAndMaskEncoderBatch");
m.def("f_set_preids_token_penalty_multi_scores", &SetPreidsTokenPenaltyMultiScores, "SetPreidsTokenPenaltyMultiScores");
m.def("f_update_inputs_v2", &UpdateInputesV2, "UpdateInputesV2");
m.def("f_rebuild_padding_v2", &RebuildPaddingV2Func, "RebuildPaddingV2Func");
m.def("f_per_token_group_quant", &PerTokenGroupQuant, "PerTokenGroupQuant");
m.def("f_per_tensor_quant_fp8", &PerTensorQuantFp8, "PerTensorQuantFp8");
m.def("f_get_padding_offset_v2", &GetPaddingOffsetV2, "GetPaddingOffsetV2");
m.def("f_save_output", &SaveOutMmsg, "SaveOutMmsg");
m.def("f_get_output", &GetOutput, "GetOutput");
m.def("f_step_paddle", &StepPaddle, "StepPaddle");
m.def("f_save_output_dygraph", &SaveOutputDygraph, "SaveOutputDygraph");
// m.def("f_cutlass_fp8_fp8_half_block_gemm_fused", &cutlass_fp8_fp8_half_block_gemm_fused_func, "cutlass_fp8_fp8_half_block_gemm_fused_func");
}
PYBIND11_MODULE(paddlenlp_ops_80, m) {
/**
* all_reduce.cu
*/
m.def("init_custom_all_reduce", &init_custom_all_reduce, "init all reduce class function");
m.def("all_reduce", &all_reduce, "all reduce function");
m.def("dispose", &dispose, "del function for python");
m.def("meta_size", &meta_size, "meta_size function for Signal struct");
m.def("register_buffer", &register_buffer, "register ipc buffer");
m.def("f_append_attention", &AppendAttention, "AppendAttention");
m.def("f_fused_rotary_position_encoding", &FusedRotaryPositionEncoding, "FusedRotaryPositionEncoding");
m.def("f_multi_head_latent_attention", &MultiHeadLatentAttention, "MultiHeadLatentAttention");
m.def("f_noaux_tc", &NoauxTc, "NoauxTc");
m.def("f_get_block_shape_and_split_kv_block", &GetBlockShapeAndSplitKVBlock, "GetBlockShapeAndSplitKVBlock");
m.def("f_prefill_mla_write_cache", &PrefillMLAWriteCacheKernel, "PrefillMLAWriteCacheKernel");
m.def("f_decode_mla_write_cache", &DecodeMLAWriteCacheKernel, "DecodeMLAWriteCacheKernel");
m.def("f_get_position_ids_and_mask_encoder_batch", &GetPositionIdsAndMaskEncoderBatch, "GetPositionIdsAndMaskEncoderBatch");
m.def("f_set_preids_token_penalty_multi_scores", &SetPreidsTokenPenaltyMultiScores, "SetPreidsTokenPenaltyMultiScores");
m.def("f_update_inputs_v2", &UpdateInputesV2, "UpdateInputesV2");
m.def("f_rebuild_padding_v2", &RebuildPaddingV2Func, "RebuildPaddingV2Func");
m.def("f_per_token_group_quant", &PerTokenGroupQuant, "PerTokenGroupQuant");
m.def("f_per_tensor_quant_fp8", &PerTensorQuantFp8, "PerTensorQuantFp8");
m.def("f_get_padding_offset_v2", &GetPaddingOffsetV2, "GetPaddingOffsetV2");
m.def("f_save_output", &SaveOutMmsg, "SaveOutMmsg");
m.def("f_get_output", &GetOutput, "GetOutput");
m.def("f_step_paddle", &StepPaddle, "StepPaddle");
m.def("f_save_output_dygraph", &SaveOutputDygraph, "SaveOutputDygraph");
}
PYBIND11_MODULE(paddlenlp_ops_90, m) {
/**
* all_reduce.cu
*/
m.def("init_custom_all_reduce", &init_custom_all_reduce, "init all reduce class function");
m.def("all_reduce", &all_reduce, "all reduce function");
m.def("dispose", &dispose, "del function for python");
m.def("meta_size", &meta_size, "meta_size function for Signal struct");
m.def("register_buffer", &register_buffer, "register ipc buffer");
m.def("f_append_attention", &AppendAttention, "AppendAttention");
m.def("f_fused_rotary_position_encoding", &FusedRotaryPositionEncoding, "FusedRotaryPositionEncoding");
m.def("f_multi_head_latent_attention", &MultiHeadLatentAttention, "MultiHeadLatentAttention");
m.def("f_noaux_tc", &NoauxTc, "NoauxTc");
m.def("f_get_block_shape_and_split_kv_block", &GetBlockShapeAndSplitKVBlock, "GetBlockShapeAndSplitKVBlock");
m.def("f_prefill_mla_write_cache", &PrefillMLAWriteCacheKernel, "PrefillMLAWriteCacheKernel");
m.def("f_decode_mla_write_cache", &DecodeMLAWriteCacheKernel, "DecodeMLAWriteCacheKernel");
m.def("f_get_position_ids_and_mask_encoder_batch", &GetPositionIdsAndMaskEncoderBatch, "GetPositionIdsAndMaskEncoderBatch");
m.def("f_set_preids_token_penalty_multi_scores", &SetPreidsTokenPenaltyMultiScores, "SetPreidsTokenPenaltyMultiScores");
m.def("f_update_inputs_v2", &UpdateInputesV2, "UpdateInputesV2");
m.def("f_rebuild_padding_v2", &RebuildPaddingV2Func, "RebuildPaddingV2Func");
m.def("f_per_token_group_quant", &PerTokenGroupQuant, "PerTokenGroupQuant");
m.def("f_per_tensor_quant_fp8", &PerTensorQuantFp8, "PerTensorQuantFp8");
m.def("f_get_padding_offset_v2", &GetPaddingOffsetV2, "GetPaddingOffsetV2");
m.def("f_save_output", &SaveOutMmsg, "SaveOutMmsg");
m.def("f_get_output", &GetOutput, "GetOutput");
m.def("f_step_paddle", &StepPaddle, "StepPaddle");
m.def("f_save_output_dygraph", &SaveOutputDygraph, "SaveOutputDygraph");
}

View File

@@ -18,7 +18,7 @@
#include "fp8_gemm_fused/fuse_block_gemm_act_template_3x.h"
#include "fp8_gemm_fused/fp8_fp8_gemm_scale_bias_act.h"
std::vector<paddle::Tensor> cutlass_fp8_fp8_half_block_gemm_fused(
paddle::Tensor cutlass_fp8_fp8_half_block_gemm_fused_func(
const paddle::Tensor& x,
const paddle::Tensor& y,
const paddle::Tensor& x_scale,
@@ -145,29 +145,20 @@ std::vector<paddle::Tensor> cutlass_fp8_fp8_half_block_gemm_fused(
x_scale_ptr,
y_scale_ptr};
fp8_fp8_block_gemm_scale_bias_act(params);
// if(output_dtype == "bfloat16"){
// dispatch_fuse_block_gemm_c3x<phi::dtype::float8_e4m3fn,
// phi::dtype::bfloat16,
// false,
// cutlass::epilogue::thread::Identity,
// cute::Shape<_128, _128, _128>,
// cute::Shape<_1, _2, _1>,
// cutlass::gemm::KernelTmaWarpSpecializedCooperativeFP8GroupBlockScaledAccum<1>,
// cutlass::epilogue::TmaWarpSpecializedCooperative,
// cutlass::arch::Sm90>(params);
// }else{
// dispatch_fuse_block_gemm_c3x<phi::dtype::float8_e4m3fn,
// phi::dtype::float16,
// false,
// cutlass::epilogue::thread::Identity,
// cute::Shape<_128, _128, _128>,
// cute::Shape<_1, _2, _1>,
// cutlass::gemm::KernelTmaWarpSpecializedCooperativeFP8GroupBlockScaledAccum<1>,
// cutlass::epilogue::TmaWarpSpecializedCooperative,
// cutlass::arch::Sm90>(params);
// }
return {out};
return out;
}
std::vector<paddle::Tensor> cutlass_fp8_fp8_half_block_gemm_fused(
const paddle::Tensor& x,
const paddle::Tensor& y,
const paddle::Tensor& x_scale,
const paddle::Tensor& y_scale,
const paddle::optional<paddle::Tensor>& bias,
bool trans_x,
bool trans_y,
std::string output_dtype,
std::string activation_type) {
return {cutlass_fp8_fp8_half_block_gemm_fused_func(x,y,x_scale,y_scale,bias,trans_x,trans_y,output_dtype,activation_type)};
}
std::vector<std::vector<int64_t>> CutlassFp8Fp8HalfBlockGemmFusedInferShape(

View File

@@ -20,6 +20,7 @@
#include "paddle/extension.h"
#define MAX_BSZ 512
// #define GET_OUTPUT_DEBUG
struct msgdata {
long mtype;
@@ -32,8 +33,20 @@ void GetOutput(const paddle::Tensor& x,
if (rank_id > 0) return;
static struct msgdata msg_rcv;
static key_t key = ftok("./", 1);
int msg_queue_id = 1;
if (const char* inference_msg_queue_id_env_p =
std::getenv("INFERENCE_MSG_QUEUE_ID")) {
std::string inference_msg_queue_id_env_str(
inference_msg_queue_id_env_p);
int inference_msg_queue_id_from_env =
std::stoi(inference_msg_queue_id_env_str);
#ifdef GET_OUTPUT_DEBUG
std::cout << "Your INFERENCE_MSG_QUEUE_ID is: "
<< inference_msg_queue_id_from_env << std::endl;
#endif
msg_queue_id = inference_msg_queue_id_from_env;
}
static key_t key = ftok("./", msg_queue_id);
static int msgid = msgget(key, IPC_CREAT | 0666);

View File

@@ -1,201 +0,0 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "helper.h"
#include<string.h>
#include <cuda_runtime.h>
template <typename T>
__inline__ __device__ T WarpReduceAbsMax(T val, unsigned lane_mask) {
#pragma unroll
for (int mask = 16; mask > 0; mask >>= 1){
val = max(val, __shfl_xor_sync(lane_mask, val, mask, 32));
}
return val;
}
template <typename InType, typename OutType, int GroupSize, int VecSize, bool transpose_scale>
__global__ void GroupQuantKernel(const InType* input,
const int64_t numel,
const int scale_rows,
const int scale_cols,
const float quant_max_bound,
const float quant_min_bound,
OutType* output,
float* out_scale_data) {
const int idx = (blockIdx.x * GroupSize) + threadIdx.x * VecSize;
if (idx >= numel) return;
const int scale_row_idx = blockIdx.x / scale_cols;
const int scale_col_idx = blockIdx.x % scale_cols;
int scale_idx = 0;
float abs_max_val = 0.000001;
if constexpr (transpose_scale) {
scale_idx = scale_col_idx * scale_rows + scale_row_idx;
}else{
scale_idx = scale_row_idx * scale_cols + scale_col_idx;
}
AlignedVector<InType, VecSize> in_vec;
AlignedVector<OutType, VecSize> out_vec;
Load<InType, VecSize>(input + idx, &in_vec);
#pragma unroll
for (int i = 0; i < VecSize; ++i) {
abs_max_val = max(abs_max_val, abs(static_cast<float>(in_vec[i])));
}
abs_max_val = WarpReduceAbsMax(abs_max_val, 0xffffffff);
__syncthreads();
float scale = __shfl_sync(0xffffffff, abs_max_val, 0) / quant_max_bound;
#pragma unroll
for (int i = 0; i < VecSize; ++i) {
float quant_val = static_cast<float>(in_vec[i]) / scale;
quant_val = quant_val > quant_max_bound ? quant_max_bound : quant_val;
quant_val = quant_val < quant_min_bound ? quant_min_bound : quant_val;
out_vec[i] = static_cast<OutType>(quant_val);
}
Store<OutType, VecSize>(out_vec, output + idx);
if (threadIdx.x == 0) {
out_scale_data[scale_idx] = scale;
}
}
template <paddle::DataType InType, paddle::DataType OutType>
std::vector<paddle::Tensor> LaunchGroupQuantKernel(const paddle::Tensor& x,
const int group_size,
const bool transpose_scale,
const float quant_max_bound,
const float quant_min_bound) {
typedef PDTraits<InType> in_traits;
typedef typename in_traits::DataType InDataType;
typedef typename in_traits::data_t in_data_t;
paddle::Tensor out;
paddle::Tensor scale_out;
auto place = x.place();
cudaStream_t stream = x.stream();
int rank = x.dims().size();
std::vector<int64_t> out_shape = x.shape();
std::vector<int64_t> scale_shape = x.shape();
out = paddle::empty(out_shape, OutType, place);
int64_t batch = 1;
int64_t m = x.shape()[rank - 2];
int64_t n = x.shape()[rank - 1];
int64_t scale_n = n / group_size;
for(auto i = 0; i < rank - 1; ++i){
batch *= x.shape()[i];
}
if(transpose_scale){
scale_shape[rank - 2] = scale_n;
scale_shape[rank - 1] = m;
}else{
scale_shape[rank - 1] = scale_n;
}
scale_out = paddle::empty(scale_shape, paddle::DataType::FLOAT32, place);
int64_t numel = x.numel();
constexpr int VecSize = 4;
dim3 threadsPerBlock(group_size / VecSize, 1, 1);
dim3 block_per_grid((numel + group_size - 1) / group_size, 1, 1);
typedef PDTraits<OutType> out_traits;
typedef typename out_traits::DataType OutDataType;
typedef typename out_traits::data_t out_data_t;
if(group_size == 128){
GroupQuantKernel<InDataType, OutDataType, 128, VecSize, true><<<block_per_grid, threadsPerBlock, 0, stream>>>(reinterpret_cast<const InDataType*>(x.data<in_data_t>()),
numel,
m,
n / 128,
quant_max_bound,
quant_min_bound,
reinterpret_cast<OutDataType*>(out.data<out_data_t>()),
reinterpret_cast<float*>(scale_out.data<float>()));
}else{
PD_THROW("group_quant's group_size only support 128.");
}
return {out, scale_out};
}
template <paddle::DataType InType>
std::vector<paddle::Tensor> LaunchGroupQuant(const paddle::Tensor& x,
const int group_size,
const bool transpose_scale,
const float quant_max_bound,
const float quant_min_bound) {
if(fabs(quant_max_bound - 448.0f) < 0.000001){
return LaunchGroupQuantKernel<InType, paddle::DataType::FLOAT8_E4M3FN>(x, group_size, transpose_scale, quant_max_bound, quant_min_bound);
}else{
PD_THROW("Only supported float8_e4m3fn quantization, please set quant_max_bound=448, quant_min_bound=-448.");
}
}
std::vector<paddle::Tensor> GroupQuant(const paddle::Tensor& x,
const int group_size,
const bool transpose_scale,
const float quant_max_bound,
const float quant_min_bound) {
if(x.dtype() == paddle::DataType::FLOAT32){
return LaunchGroupQuant<paddle::DataType::FLOAT32>(x, group_size, transpose_scale, quant_max_bound, quant_min_bound);
}else if(x.dtype() == paddle::DataType::FLOAT16){
return LaunchGroupQuant<paddle::DataType::FLOAT16>(x, group_size, transpose_scale, quant_max_bound, quant_min_bound);
}else if(x.dtype() == paddle::DataType::BFLOAT16){
return LaunchGroupQuant<paddle::DataType::BFLOAT16>(x, group_size, transpose_scale, quant_max_bound, quant_min_bound);
}else{
PD_THROW("Unsupported data type.");
}
}
std::vector<std::vector<int64_t>> GroupQuantInferShape(const std::vector<int64_t>& input_shape, const int group_size, const bool transpose_scale, const float quant_max_bound,const float quant_min_bound) {
std::vector<int64_t> scale_shape = input_shape;
int rank = input_shape.size();
if(transpose_scale){
scale_shape[rank - 1] = input_shape[rank - 2];
scale_shape[rank - 2] = input_shape[rank - 1] / group_size;
}else{
scale_shape[rank - 1] = input_shape[rank - 1] / group_size;
}
return {input_shape, scale_shape};
}
std::vector<paddle::DataType> GroupQuantInferDtype(const paddle::DataType& input_dtype, const int group_size, const bool transpose_scale, const float quant_max_bound,const float quant_min_bound) {
if(fabs(quant_max_bound - 448.0f) < 0.000001){
return {paddle::DataType::FLOAT8_E4M3FN, paddle::DataType::FLOAT32};
}else{
PD_THROW("Only supported attr of quant_max_bound in ['448.0'].");
}
}
PD_BUILD_OP(group_quant)
.Inputs({"x"})
.Outputs({"output", "scale"})
.Attrs({"group_size: int",
"transpose_scale: bool",
"quant_max_bound: float",
"quant_min_bound: float"})
.SetKernelFn(PD_KERNEL(GroupQuant))
.SetInferShapeFn(PD_INFER_SHAPE(GroupQuantInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(GroupQuantInferDtype));

View File

@@ -45,6 +45,7 @@ namespace cub = hipcub;
#include "paddle/phi/backends/gpu/gpu_info.h"
#include "nlohmann/json.hpp"
using json = nlohmann::json;
#define CUDA_CHECK(call) \
@@ -161,6 +162,13 @@ public:
typedef paddle::float8_e4m3fn data_t;
};
template <>
class PDTraits<paddle::DataType::INT8> {
public:
typedef int8_t DataType;
typedef int8_t data_t;
};
template <typename T, int Size>
struct alignas(sizeof(T) * Size) AlignedVector {
T val[Size];
@@ -244,3 +252,35 @@ inline bool GetMlaUseTensorcore() {
const bool mla_use_tensorcore = flags_mla_use_tensorcore && enable_mla_tensorcore;
return mla_use_tensorcore;
}
__device__ __forceinline__ float atomicMaxFloat(float* addr, float value) {
float old;
old = (value >= 0) ? __int_as_float(atomicMax((int*)addr, __float_as_int(value)))
: __uint_as_float(atomicMin((unsigned int*)addr, __float_as_uint(value)));
return old;
}
__device__ __forceinline__ float warpReduceMax(float max_value) {
max_value = fmaxf(max_value, __shfl_xor_sync(0xffffffff, max_value, 16));
max_value = fmaxf(max_value, __shfl_xor_sync(0xffffffff, max_value, 8));
max_value = fmaxf(max_value, __shfl_xor_sync(0xffffffff, max_value, 4));
max_value = fmaxf(max_value, __shfl_xor_sync(0xffffffff, max_value, 2));
max_value = fmaxf(max_value, __shfl_xor_sync(0xffffffff, max_value, 1));
return max_value;
}
__device__ __forceinline__ float blockReduceMax(float max_value) {
static __shared__ float warpLevelMaxs[32];
const int laneId = threadIdx.x & 0x1f;;
const int warpId = threadIdx.x >> 5;
max_value = warpReduceMax(max_value);
if (laneId == 0) warpLevelMaxs[warpId] = max_value;
__syncthreads();
max_value = (threadIdx.x < blockDim.x / 32) ? warpLevelMaxs[laneId] : 0;
if (warpId == 0) max_value = warpReduceMax(max_value);
return max_value;
}

View File

@@ -144,7 +144,11 @@ void BatchMLAWithPagedKVCacheKernel(
params.cumsum_q_seqlens = const_cast<int*>(cu_seqlens_q.data<int>());
params.padding_offsets = const_cast<int*>(padding_offsets.data<int>());
params.batch_ids = const_cast<int*>(batch_ids.data<int>());
params.tile_ids_per_batch = const_cast<int*>(tile_ids_per_batch.data<int>());
if (q_head_num <=64) {
params.tile_ids_per_batch = const_cast<int*>(tile_ids_per_batch.data<int>());
} else {
params.q_tile_ids_per_batch = const_cast<int*>(tile_ids_per_batch.data<int>());
}
params.num_blocks_x = const_cast<int*>(num_blocks_x_device.data<int>());
params.num_blocks_x_int = num_blocks_x;
params.q_stride_bsz = q_head_num * q_head_dim;
@@ -186,7 +190,11 @@ void BatchMLAWithPagedKVCacheKernel(
params.cumsum_q_seqlens = const_cast<int*>(cu_seqlens_q.data<int>());
params.padding_offsets = const_cast<int*>(padding_offsets.data<int>());
params.batch_ids = const_cast<int*>(batch_ids.data<int>());
params.tile_ids_per_batch = const_cast<int*>(tile_ids_per_batch.data<int>());
if (q_head_num <=64) {
params.tile_ids_per_batch = const_cast<int*>(tile_ids_per_batch.data<int>());
} else {
params.q_tile_ids_per_batch = const_cast<int*>(tile_ids_per_batch.data<int>());
}
params.num_blocks_x = const_cast<int*>(num_blocks_x_device.data<int>());
params.num_blocks_x_int = num_blocks_x;
params.q_stride_bsz = q_head_num * q_head_dim;
@@ -217,6 +225,7 @@ void BatchMLAWithPagedKVCacheKernel(
}
}
template void BatchMLAWithPagedKVCacheKernel<paddle::bfloat16>(
const AppendAttnMetaData& meta_data,
const paddle::Tensor& q, // [token_num, q_head_num, head_dim]

View File

@@ -133,7 +133,7 @@ struct CollectiveEpilogue {
const int kv_len,
const int chunk_size,
const int draft_total_token_num,
const int o_stride_bsz) {
const int o_stride_head) {
const int q_group_offset = q_tile_idx * BLOCK_SHAPE_Q;
const int num_chunks = cute::ceil_div(kv_len, chunk_size);
Tensor sO = make_tensor(make_smem_ptr(shared_storage.smem_o.data()), SmemLayoutO{});
@@ -152,7 +152,7 @@ struct CollectiveEpilogue {
cutlass::arch::NamedBarrier::sync(NUM_MMA_THREADS,
/*id=*/static_cast<int>(NamedBarriers::kValueEmpty));
TiledCopyO gmem_tiled_copy_O;
auto O_ptr = num_chunks == 1 ? epilogue_params.O_ptr + (start_token_idx + q_group_offset) * o_stride_bsz : epilogue_params.O_ptr_tmp + (tile_idx * bsz + bid) * draft_total_token_num * o_stride_bsz;
auto O_ptr = num_chunks == 1 ? epilogue_params.O_ptr + (start_token_idx * Ktraits::GROUP_SIZE + q_group_offset) * o_stride_head : epilogue_params.O_ptr_tmp + (((tile_idx * bsz + bid) * draft_total_token_num) * Ktraits::GROUP_SIZE + q_group_offset) * o_stride_head;
Tensor mO = make_tensor(make_gmem_ptr(O_ptr), epilogue_params.layout_O);
Tensor gO = local_tile(mO, select<0, 1>(TileShape_PDV{}), make_coord(_, _0{}))(_, _, _0{});
Tensor cO = make_identity_tensor(gO.shape()); // (O, D) -> (o_idx, d_idx)

View File

@@ -242,8 +242,8 @@ struct CollectiveMainloop {
const int bid,
const int q_tile_idx) {
const int q_group_offset = q_tile_idx * BLOCK_SHAPE_Q;
int start_q_token_idx = mainloop_params.cumsum_q_seqlens[bid] + q_group_offset;
int offset_Q = mainloop_params.q_stride_bsz * start_q_token_idx;
int start_q_head_idx = mainloop_params.cumsum_q_seqlens[bid] * Ktraits::GROUP_SIZE + q_group_offset;
int offset_Q = mainloop_params.q_stride_head_num * start_q_head_idx;
Tensor mQ = make_tensor(make_gmem_ptr(mainloop_params.Q_ptr + offset_Q), mainloop_params.layout_Q);
Tensor gQ =
local_tile(mQ, select<0, 2>(TileShape_QKD{}), make_coord(_, _0{}))(_, _, _0{});

View File

@@ -77,7 +77,7 @@ struct Params {
alignas(16) IdType *batch_ids;
alignas(16) IdType *q_tile_ids_per_batch = nullptr;
alignas(16) IdType *tile_ids_per_batch;
alignas(16) IdType *tile_ids_per_batch = nullptr;
alignas(16) IdType *num_blocks_x;
@@ -117,6 +117,9 @@ struct Params {
} else if (group_size == 64) { \
constexpr size_t GROUP_SIZE = 64; \
__VA_ARGS__ \
} else if (group_size == 128) { \
constexpr size_t GROUP_SIZE = 128; \
__VA_ARGS__ \
} else { \
PD_THROW("not support the group_size: ", group_size); \
return cudaErrorNotSupported; \
@@ -210,7 +213,7 @@ MLAWithKVCacheKernel(CUTE_GRID_CONSTANT
PipelineState smem_pipe_write_kv = cutlass::make_producer_start_state<MainloopPipeline>();
const int block_id = blockIdx.x;
const int bid = mainloop_params.batch_ids[block_id];
const int tile_id = mainloop_params.tile_ids_per_batch[block_id];
const int tile_id = mainloop_params.tile_ids_per_batch ? mainloop_params.tile_ids_per_batch[block_id] : 0;
const int q_tile_id = mainloop_params.q_tile_ids_per_batch ? mainloop_params.q_tile_ids_per_batch[block_id] : 0;
const int seq_len_now = mainloop_params.seq_lens_this_time[bid];
const int seq_len_encoder_now = mainloop_params.seq_lens_encoder[bid];
@@ -268,7 +271,7 @@ MLAWithKVCacheKernel(CUTE_GRID_CONSTANT
clear(tOrO);
clear(attention_updater.scores_scale);
const int bid = mainloop_params.batch_ids[block_id];
const int tile_id = mainloop_params.tile_ids_per_batch[block_id];
const int tile_id = mainloop_params.tile_ids_per_batch ? mainloop_params.tile_ids_per_batch[block_id] : 0;
const int q_tile_id = mainloop_params.q_tile_ids_per_batch ? mainloop_params.q_tile_ids_per_batch[block_id] : 0;
const int seq_len_now = mainloop_params.seq_lens_this_time[bid];
const int seq_len_encoder_now = mainloop_params.seq_lens_encoder[bid];
@@ -325,7 +328,7 @@ MLAWithKVCacheKernel(CUTE_GRID_CONSTANT
seq_len_decoder_now,
mainloop_params.chunk_size,
mainloop_params.draft_total_token_num,
mainloop_params.o_stride_bsz);
mainloop_params.o_stride_head_num);
}
}

View File

@@ -149,7 +149,7 @@ MLAWithKVCacheWG4Kernel(CUTE_GRID_CONSTANT
PipelineState smem_pipe_write_kv = cutlass::make_producer_start_state<MainloopPipeline>();
const int block_id = blockIdx.x;
const int bid = mainloop_params.batch_ids[block_id];
const int tile_id = mainloop_params.tile_ids_per_batch[block_id];
const int tile_id = mainloop_params.tile_ids_per_batch ? mainloop_params.tile_ids_per_batch[block_id] : 0;
const int q_tile_id = mainloop_params.q_tile_ids_per_batch ? mainloop_params.q_tile_ids_per_batch[block_id] : 0;
const int seq_len_now = mainloop_params.seq_lens_this_time[bid];
const int seq_len_decoder_now = mainloop_params.seq_lens_decoder[bid] + seq_len_now;
@@ -202,7 +202,7 @@ MLAWithKVCacheWG4Kernel(CUTE_GRID_CONSTANT
const int block_id = blockIdx.x;
clear(attention_updater.scores_scale);
const int bid = mainloop_params.batch_ids[block_id];
const int tile_id = mainloop_params.tile_ids_per_batch[block_id];
const int tile_id = mainloop_params.tile_ids_per_batch ? mainloop_params.tile_ids_per_batch[block_id] : 0;
const int q_tile_id = mainloop_params.q_tile_ids_per_batch ? mainloop_params.q_tile_ids_per_batch[block_id] : 0;
const int seq_len_now = mainloop_params.seq_lens_this_time[bid];
const int seq_len_decoder_now = mainloop_params.seq_lens_decoder[bid] + seq_len_now;
@@ -290,7 +290,7 @@ MLAWithKVCacheWG4Kernel(CUTE_GRID_CONSTANT
seq_len_decoder_now,
mainloop_params.chunk_size,
mainloop_params.draft_total_token_num,
mainloop_params.o_stride_bsz);
mainloop_params.o_stride_head_num);
}
}

View File

@@ -0,0 +1,93 @@
/***************************************************************************************************
* Copyright (c) 2017 - 2022 NVIDIA CORPORATION & AFFILIATES. All rights
*reserved. SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
*this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
*LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
*INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
*CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
*ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************************************/
/*! \file
\brief Scheduler for grouped GEMM
*/
#pragma once
#include "cutlass/cutlass.h"
#include "cutlass/gemm/gemm.h"
#include "cutlass/gemm/kernel/gemm_grouped_problem_visitor.h"
#include "cutlass/matrix_coord.h"
#include "cutlass_extensions/gemm/kernel/moe_problem_visitor.h"
/////////////////////////////////////////////////////////////////////////////////////////////////
namespace cutlass {
namespace gemm {
namespace kernel {
/// Visitor class to abstract away the algorithm for iterating over tiles
template <typename ThreadblockShape,
GroupScheduleMode GroupScheduleMode_,
int PrefetchTileCount,
int ThreadCount,
bool Transposed = false>
struct GemmMoeProblemVisitor
: public MoeProblemVisitor<
detail::GemmGroupedProblemSizeHelper<ThreadblockShape, Transposed>,
ThreadblockShape,
GroupScheduleMode_,
PrefetchTileCount,
ThreadCount> {
static bool const kTransposed = Transposed;
using ProblemSizeHelper =
detail::GemmGroupedProblemSizeHelper<ThreadblockShape, Transposed>;
using Base = MoeProblemVisitor<ProblemSizeHelper,
ThreadblockShape,
GroupScheduleMode_,
PrefetchTileCount,
ThreadCount>;
using Params = typename Base::Params;
using SharedStorage = typename Base::SharedStorage;
//
// Methods
//
CUTLASS_DEVICE
GemmMoeProblemVisitor(Params const& params_,
SharedStorage& shared_storage_, // NOLINT
int32_t block_idx)
: Base(params_, shared_storage_, block_idx) {}
};
/////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace kernel
} // namespace gemm
} // namespace cutlass
/////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,346 @@
/***************************************************************************************************
* Copyright (c) 2017 - 2022 NVIDIA CORPORATION & AFFILIATES. All rights
*reserved. SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
*this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
*LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
*INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
*CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
*ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************************************/
/*! \file
\brief Base scheduler for grouped problems, using MoE
*/
#pragma once
#include "cutlass/gemm/kernel/grouped_problem_visitor.h"
/////////////////////////////////////////////////////////////////////////////////////////////////
namespace cutlass {
namespace gemm {
namespace kernel {
/////////////////////////////////////////////////////////////////////////////////////////////////
/// Visitor class to abstract away the algorithm for iterating over tiles
template <typename ProblemSizeHelper, typename ThreadblockShape_>
struct BaseMoeProblemVisitor {
using ThreadblockShape = ThreadblockShape_;
struct ProblemInfo {
static int32_t const kNoPrefetchEntry = -1;
int32_t problem_idx;
int32_t problem_start;
CUTLASS_DEVICE
ProblemInfo()
: problem_idx(kNoPrefetchEntry), problem_start(kNoPrefetchEntry) {}
CUTLASS_DEVICE
ProblemInfo(int32_t problem_idx_, int32_t problem_start_)
: problem_idx(problem_idx_), problem_start(problem_start_) {}
};
struct Params {
int64_t const* last_row_for_problem;
int64_t gemm_n;
int64_t gemm_k;
int32_t problem_count;
void const* workspace;
int32_t tile_count;
//
// Methods
//
/// Ctor
CUTLASS_HOST_DEVICE
Params()
: last_row_for_problem(nullptr),
gemm_n(0),
gemm_k(0),
problem_count(0),
workspace(nullptr),
tile_count(0) {}
/// Ctor
CUTLASS_HOST_DEVICE
Params(int64_t const* last_row_for_problem,
int64_t gemm_n,
int64_t gemm_k,
int32_t problem_count,
void const* workspace = nullptr,
int32_t tile_count = 0)
: last_row_for_problem(last_row_for_problem),
gemm_n(gemm_n),
gemm_k(gemm_k),
problem_count(problem_count),
workspace(workspace),
tile_count(tile_count) {}
};
Params const& params;
int32_t tile_idx;
int32_t problem_tile_start;
int32_t problem_idx;
//
// Methods
//
CUTLASS_DEVICE
BaseMoeProblemVisitor(Params const& params_, int32_t block_idx)
: params(params_),
tile_idx(block_idx),
problem_tile_start(0),
problem_idx(0) {}
/// Get the grid shape
CUTLASS_HOST_DEVICE
static cutlass::gemm::GemmCoord grid_shape(
const cutlass::gemm::GemmCoord& problem) {
return cutlass::gemm::GemmCoord(
((problem.m() - 1 + ThreadblockShape::kM) / ThreadblockShape::kM),
((problem.n() - 1 + ThreadblockShape::kN) / ThreadblockShape::kN),
1);
}
/// Gets the global tile index
CUTLASS_HOST_DEVICE
int32_t tile_index() const { return tile_idx; }
/// Gets the index of the problem
CUTLASS_HOST_DEVICE
int32_t problem_index() const { return problem_idx; }
CUTLASS_HOST_DEVICE
int32_t threadblock_idx() const { return tile_idx - problem_tile_start; }
CUTLASS_DEVICE
void advance(int32_t grid_size) { tile_idx += grid_size; }
CUTLASS_HOST_DEVICE
static void possibly_transpose_problem(
cutlass::gemm::GemmCoord& problem) { // NOLINT
ProblemSizeHelper::possibly_transpose_problem(problem);
}
/// Returns the problem size for the current problem
CUTLASS_HOST_DEVICE
cutlass::gemm::GemmCoord problem_size() const {
return problem_size(problem_idx);
}
CUTLASS_HOST_DEVICE
cutlass::gemm::GemmCoord problem_size(int idx) const {
const int64_t prev_problem_row =
idx == 0 ? 0 : params.last_row_for_problem[idx - 1];
const int64_t current_problem_row = params.last_row_for_problem[idx];
const int64_t gemm_m = current_problem_row - prev_problem_row;
GemmCoord problem(GemmCoord::Index(gemm_m),
GemmCoord::Index(params.gemm_n),
GemmCoord::Index(params.gemm_k));
ProblemSizeHelper::possibly_transpose_problem(problem);
return problem;
}
CUTLASS_HOST_DEVICE
static int32_t tile_count(const cutlass::gemm::GemmCoord& grid) {
return ProblemSizeHelper::tile_count(grid);
}
static int32_t group_tile_count(
const cutlass::gemm::GemmCoord* host_problem_sizes_ptr,
int32_t problem_count) {
int32_t total_tiles = 0;
for (int32_t i = 0; i < problem_count; ++i) {
auto problem = host_problem_sizes_ptr[i];
possibly_transpose_problem(problem);
auto grid = grid_shape(problem);
total_tiles += tile_count(grid);
}
return total_tiles;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////
template <typename ProblemSizeHelper,
typename ThreadblockShape,
GroupScheduleMode GroupScheduleMode_,
int PrefetchTileCount,
int ThreadCount>
struct MoeProblemVisitor;
/////////////////////////////////////////////////////////////////////////////////////////////////
// ProblemVisitor that performs all scheduling on device
//
template <typename ProblemSizeHelper,
typename ThreadblockShape,
int PrefetchTileCount,
int ThreadCount>
struct MoeProblemVisitor<ProblemSizeHelper,
ThreadblockShape,
GroupScheduleMode::kDeviceOnly,
PrefetchTileCount,
ThreadCount>
: public BaseMoeProblemVisitor<ProblemSizeHelper, ThreadblockShape> {
using Base = BaseMoeProblemVisitor<ProblemSizeHelper, ThreadblockShape>;
using Params = typename Base::Params;
static int const kThreadCount = ThreadCount;
static bool const kRequiresPrecomputation = false;
static int const kThreadsPerWarp = 32;
struct SharedStorage {};
// Final tile of the problem loaded by this thread. Each thread will hold
// a separate value.
int32_t problem_ending_tile;
SharedStorage& shared_storage;
//
// Methods
//
CUTLASS_DEVICE
MoeProblemVisitor(Params const& params_,
SharedStorage& shared_storage_, // NOLINT
int32_t block_idx)
: Base(params_, block_idx),
problem_ending_tile(0),
shared_storage(shared_storage_) {
this->problem_idx = -1 * kThreadsPerWarp;
this->problem_tile_start = 0;
}
CUTLASS_DEVICE
bool next_tile() {
// Check whether the tile to compute is within the range of the current
// problem.
int32_t problem_tile_end = __shfl_sync(
0xffffffff, problem_ending_tile, this->problem_idx % kThreadsPerWarp);
if (this->tile_idx < problem_tile_end) {
return true;
}
// Check whether the tile to compute is within the current group of problems
// fetched by the warp. The last tile for this group is the final tile of
// the problem held by the final thread in the warp.
int32_t group_tile_end =
__shfl_sync(0xffffffff, problem_ending_tile, kThreadsPerWarp - 1);
// Keep the starting problem for this group in `problem_idx`. This is done
// to reduce register pressure. The starting problem for this group is
// simply the first problem in the group most recently fetched by the warp.
int32_t& group_problem_start = this->problem_idx;
group_problem_start =
(this->problem_idx / kThreadsPerWarp) * kThreadsPerWarp;
// Keep the starting tile for this group in `problem_tile_start`. This is
// done to reduce register pressure.
int32_t& group_tile_start = this->problem_tile_start;
// Each thread in the warp processes a separate problem to advance until
// reaching a problem whose starting tile is less less than tile_idx.
while (group_tile_end <= this->tile_idx) {
group_problem_start += kThreadsPerWarp;
if (group_problem_start > this->params.problem_count) {
return false;
}
// Since `group_tile_start` is a reference to `this->problem_tile_start`,
// this also sets `this->problem_tile_start`. The fact that
// `this->problem_tile_start` is also set here is used later in
// `next_tile`.
group_tile_start = group_tile_end;
int lane_idx = threadIdx.x % kThreadsPerWarp;
int32_t lane_problem = group_problem_start + lane_idx;
// Compute the number of tiles in the problem assigned to each thread.
problem_ending_tile = 0;
if (lane_problem < this->params.problem_count) {
cutlass::gemm::GemmCoord problem = this->problem_size(lane_problem);
cutlass::gemm::GemmCoord grid = this->grid_shape(problem);
problem_ending_tile = this->tile_count(grid);
}
// Compute a warp-wide inclusive prefix sum to compute the ending tile
// index of each thread's problem.
CUTLASS_PRAGMA_UNROLL
for (int i = 1; i < kThreadsPerWarp; i <<= 1) {
int32_t val = __shfl_up_sync(0xffffffff, problem_ending_tile, i);
if (lane_idx >= i) {
problem_ending_tile += val;
}
}
// The total tile count for this group is now in the final position of the
// prefix sum
int32_t tiles_in_group =
__shfl_sync(0xffffffff, problem_ending_tile, kThreadsPerWarp - 1);
problem_ending_tile += group_tile_start;
group_tile_end += tiles_in_group;
}
// The next problem to process is the first one that does not have ending
// tile position that is greater than or equal to tile index.
int32_t problem_idx_in_group = __popc(
__ballot_sync(0xffffffff, problem_ending_tile <= this->tile_idx));
this->problem_idx = group_problem_start + problem_idx_in_group;
// The starting tile for this problem is the ending tile of the previous
// problem. In cases where `problem_idx_in_group` is the first problem in
// the group, we do not need to reset `problem_tile_start`, because it is
// set to the previous group's ending tile in the while loop above.
if (problem_idx_in_group > 0) {
this->problem_tile_start = __shfl_sync(
0xffffffff, problem_ending_tile, problem_idx_in_group - 1);
}
return true;
}
static size_t get_workspace_size(
const cutlass::gemm::GemmCoord* host_problem_sizes_ptr,
int32_t problem_count,
int32_t block_count) {
return 0;
}
static void host_precompute(
const cutlass::gemm::GemmCoord* host_problem_sizes_ptr,
int32_t problem_count,
int32_t block_count,
void* host_workspace_ptr) {}
};
} // namespace kernel
} // namespace gemm
} // namespace cutlass

View File

@@ -0,0 +1,611 @@
/***************************************************************************************************
* Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
*modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
*this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
*notice, this list of conditions and the following disclaimer in the
*documentation and/or other materials provided with the distribution.
* * Neither the name of the NVIDIA CORPORATION nor the names of its
*contributors may be used to endorse or promote products derived from this
*software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
*AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
*IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY DIRECT,
*INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
*OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
*NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
*EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************************************/
/*! \file
\brief
*/
#pragma once
#include "cutlass/complex.h"
#include "cutlass/cutlass.h"
#include "cutlass/fast_math.h"
#include "cutlass/gemm/gemm.h"
#include "cutlass/matrix_coord.h"
#include "cutlass/semaphore.h"
#include "cutlass/gemm/kernel/gemm_transpose_operands.h"
#include "cutlass/layout/matrix.h"
#include "cutlass/trace.h"
#include "cutlass_extensions/gemm/kernel/gemm_moe_problem_visitor.h"
#include "paddle/phi/kernels/fusion/cutlass/cutlass_extensions/tile_interleaved_layout.h"
/////////////////////////////////////////////////////////////////////////////////////////////////
namespace cutlass {
namespace gemm {
namespace kernel {
/////////////////////////////////////////////////////////////////////////////////////////////////
// This section exists to that we can use the same kernel code for regular gemm
// and dequantizing gemms. It will dispatch to the dequantizing gemm if the Mma
// type has an Iterator for scales in global.
template <typename...>
using void_t = void;
template <typename Mma, typename = void>
struct use_dq_gemm : platform::false_type {};
template <typename Mma>
struct use_dq_gemm<Mma, void_t<typename Mma::IteratorScale>>
: platform::true_type {};
// SFINAE overload for dequantizing gemm
template <
typename Mma,
typename ElementScale,
typename platform::enable_if<use_dq_gemm<Mma>::value, bool>::type = true>
CUTLASS_DEVICE static void run_mma(Mma mma,
int gemm_k_iterations,
typename Mma::FragmentC& accum, // NOLINT
typename Mma::IteratorA iterator_A,
typename Mma::IteratorB iterator_B,
typename Mma::FragmentC const& src_accum,
ElementScale* weight_scale_ptr,
MatrixCoord scale_extent,
const int thread_idx,
MatrixCoord tb_offset_scale) {
typename Mma::IteratorScale iterator_scale(
Mma::IteratorScale::Layout(scale_extent.column()),
weight_scale_ptr,
scale_extent,
thread_idx,
tb_offset_scale);
mma(gemm_k_iterations,
accum,
iterator_A,
iterator_B,
iterator_scale,
src_accum);
}
// SFINAE overload for normal gemm. This completely ignores the scale parameters
template <
typename Mma,
typename ElementScale,
typename platform::enable_if<!use_dq_gemm<Mma>::value, bool>::type = true>
CUTLASS_DEVICE static void run_mma(Mma mma,
int gemm_k_iterations,
typename Mma::FragmentC& accum, // NOLINT
typename Mma::IteratorA iterator_A,
typename Mma::IteratorB iterator_B,
typename Mma::FragmentC const& src_accum,
ElementScale* weight_scale_ptr,
MatrixCoord scale_extent,
const int thread_idx,
MatrixCoord tb_offset_scale) {
mma(gemm_k_iterations, accum, iterator_A, iterator_B, src_accum);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Epilogue_, ///! Epilogue
typename ThreadblockSwizzle_, ///! Threadblock swizzling function
typename KernelArch, ///! The Architecture this kernel is compiled
/// for. Used since SIMT kernels lose top-level
/// arch.
GroupScheduleMode GroupScheduleMode_ ///! Type of scheduling to //
/// NOLINT perform
>
struct MoeFCGemm {
public:
using Mma = Mma_;
using Epilogue = Epilogue_;
using EpilogueOutputOp = typename Epilogue::OutputOp;
using ThreadblockSwizzle = ThreadblockSwizzle_;
static GroupScheduleMode const kGroupScheduleMode = GroupScheduleMode_;
static bool const kTransposed = false;
// Optional transpose
using MapArguments =
kernel::detail::MapArguments<typename Mma::IteratorA::Element,
typename Mma::IteratorA::Layout,
Mma::kTransformA,
Mma::IteratorA::AccessType::kElements,
typename Mma::IteratorB::Element,
typename Mma::IteratorB::Layout,
Mma::kTransformB,
Mma::IteratorB::AccessType::kElements,
typename Mma::LayoutC,
kTransposed>;
// Public-facing type definitions related to operand element type, layout, and
// complex conjugate operation. Must interact with the 'kTransposed' notion.
static_assert(!kTransposed, "Transpose problem not supported");
using ElementA = typename MapArguments::ElementA;
using LayoutA = typename MapArguments::LayoutA;
using ElementB = typename MapArguments::ElementB;
using LayoutB = typename MapArguments::LayoutB;
using ElementC = typename Epilogue::OutputTileIterator::Element;
using LayoutC = typename MapArguments::LayoutC;
using ElementScale = ElementC;
static ComplexTransform const kTransformA = MapArguments::kTransformA;
static ComplexTransform const kTransformB = MapArguments::kTransformB;
// Type definitions about the mainloop.
using Operator = typename Mma::Operator;
using OperatorClass = typename Mma::Operator::OperatorClass;
using ThreadblockShape = typename Mma::Shape;
using WarpShape = typename Mma::Operator::Shape;
using InstructionShape = typename Mma::Policy::Operator::InstructionShape;
using ArchTag = typename Mma::ArchTag;
static int const kStages = Mma::kStages;
static int const kAlignmentA = MapArguments::kAlignmentA;
static int const kAlignmentB = MapArguments::kAlignmentB;
static int const kAlignmentC =
Epilogue::OutputTileIterator::kElementsPerAccess;
/// Warp count (concept: GemmShape)
using WarpCount = typename Mma::WarpCount;
static int const kThreadCount = 32 * WarpCount::kCount;
using ProblemVisitor = GemmMoeProblemVisitor<ThreadblockShape,
kGroupScheduleMode,
kThreadCount,
kThreadCount,
kTransposed>;
//
// Structures
//
/// Argument structure
struct Arguments {
//
// Data members
//
int problem_count;
int threadblock_count;
typename EpilogueOutputOp::Params output_op;
ElementA* ptr_A;
ElementB* ptr_B;
ElementScale* weight_scales;
ElementC* ptr_C;
ElementC* ptr_D;
int64_t* total_rows_before_expert;
int64_t gemm_n;
int64_t gemm_k;
// Only used by device-level operator
GemmCoord* host_problem_sizes;
//
// Methods
//
/// Default ctor
CUTLASS_HOST_DEVICE
Arguments()
: problem_count(0),
threadblock_count(0),
ptr_A(nullptr),
ptr_B(nullptr),
weight_scales(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
total_rows_before_expert(nullptr),
gemm_n(0),
gemm_k(0),
host_problem_sizes(nullptr) {}
/// Ctor
CUTLASS_HOST_DEVICE
Arguments(int problem_count,
int threadblock_count,
typename EpilogueOutputOp::Params output_op,
const ElementA* ptr_A,
const ElementB* ptr_B,
const ElementScale* weight_scales,
const ElementC* ptr_C,
ElementC* ptr_D,
int64_t* total_rows_before_expert,
int64_t gemm_n,
int64_t gemm_k,
GemmCoord* host_problem_sizes = nullptr)
: problem_count(problem_count),
threadblock_count(threadblock_count),
output_op(output_op),
ptr_A(const_cast<ElementA*>(ptr_A)),
ptr_B(const_cast<ElementB*>(ptr_B)),
weight_scales(const_cast<ElementScale*>(weight_scales)),
ptr_C(const_cast<ElementC*>(ptr_C)),
ptr_D(ptr_D),
total_rows_before_expert(total_rows_before_expert),
gemm_n(gemm_n),
gemm_k(gemm_k),
host_problem_sizes(nullptr) {
if (platform::is_same<uint8_t, ElementB>::value ||
platform::is_same<uint4b_t, ElementB>::value) {
assert(weight_scales);
}
}
};
//
// Structure for precomputing values in host memory and passing to kernels
//
/// Parameters structure
struct Params {
typename ProblemVisitor::Params problem_visitor;
int threadblock_count;
typename EpilogueOutputOp::Params output_op;
ElementA* ptr_A;
ElementB* ptr_B;
ElementScale* weight_scales;
ElementC* ptr_C;
ElementC* ptr_D;
//
// Methods
//
CUTLASS_HOST_DEVICE
Params()
: ptr_A(nullptr),
ptr_B(nullptr),
weight_scales(nullptr),
ptr_C(nullptr),
ptr_D(nullptr) {}
CUTLASS_HOST_DEVICE
Params(Arguments const& args,
void* workspace = nullptr,
int tile_count = 0) // NOLINT
: problem_visitor(args.total_rows_before_expert,
args.gemm_n,
args.gemm_k,
args.problem_count,
workspace,
tile_count),
threadblock_count(args.threadblock_count),
output_op(args.output_op),
ptr_A(args.ptr_A),
ptr_B(args.ptr_B),
weight_scales(args.weight_scales),
ptr_C(args.ptr_C),
ptr_D(args.ptr_D) {}
CUTLASS_HOST_DEVICE
void update(Arguments const& args,
void* workspace = nullptr,
int tile_count = 0) {
problem_visitor =
typename ProblemVisitor::Params(args.total_rows_before_expert,
args.gemm_n,
args.gemm_k,
args.problem_count,
workspace,
tile_count);
threadblock_count = args.threadblock_count;
output_op = args.output_op;
ptr_A = args.ptr_A;
ptr_B = args.ptr_B;
weight_scales = args.weight_scales;
ptr_C = args.ptr_C;
ptr_D = args.ptr_D;
}
};
/// Shared memory storage structure
union SharedStorage {
typename ProblemVisitor::SharedStorage problem_visitor;
typename Mma::SharedStorage main_loop;
typename Epilogue::SharedStorage epilogue;
};
public:
//
// Methods
//
CUTLASS_DEVICE
MoeFCGemm() {}
/// Determines whether kernel satisfies alignment
static Status can_implement(cutlass::gemm::GemmCoord const& problem_size) {
return Status::kSuccess;
}
static Status can_implement(Arguments const& args) {
if (platform::is_same<uint8_t, ElementB>::value ||
platform::is_same<uint4b_t, ElementB>::value) {
if (args.weight_scales == nullptr) {
CUTLASS_TRACE_HOST(
"MoeFCGemm::can_implement() - weight scales are required for "
"uint8_t and uint4b_t");
return Status::kInvalid;
}
} else if (args.weight_scales != nullptr) {
CUTLASS_TRACE_HOST(
"MoeFCGemm::can_implement() - weight scales are ignored for all "
"types except uint8_t and uint4b_t");
return Status::kInvalid;
}
return Status::kSuccess;
}
static size_t get_extra_workspace_size(
Arguments const& args, cutlass::gemm::GemmCoord const& grid_tiled_shape) {
return 0;
}
// The dummy template parameter is not used and exists so that we can compile
// this code using a standard earlier than C++17. Prior to C++17, fully
// specialized templates HAD to exists in a namespace
template <bool B, typename dummy = void>
struct KernelRunner {
CUTLASS_DEVICE
static void run_kernel(Params const& params,
SharedStorage& shared_storage) { // NOLINT
CUTLASS_NOT_IMPLEMENTED();
}
};
template <typename dummy>
struct KernelRunner<true, dummy> {
CUTLASS_DEVICE
static void run_kernel(Params const& params,
SharedStorage& shared_storage) { // NOLINT
//
// These types shadow the type-level definitions and support the ability
// to implement a 'transposed' GEMM that computes the transposed problems.
//
using ElementA = typename Mma::IteratorA::Element;
using LayoutA = typename Mma::IteratorA::Layout;
using ElementB = typename Mma::IteratorB::Element;
using LayoutB = typename Mma::IteratorB::Layout;
using ElementC = typename Epilogue::OutputTileIterator::Element;
using LayoutC = typename Epilogue::OutputTileIterator::Layout;
static constexpr int kInterleave =
Mma::IteratorB::Shape::kRow / Mma::Shape::kK;
static_assert(
platform::is_same<LayoutB, layout::RowMajor>::value &&
kInterleave == 1 ||
platform::is_same<LayoutB, layout::ColumnMajor>::value &&
kInterleave >= 1,
"B must be row major/col major OR col major interleaved.");
//
// Problem visitor.
//
ProblemVisitor problem_visitor(
params.problem_visitor, shared_storage.problem_visitor, blockIdx.x);
const int64_t gemm_k = params.problem_visitor.gemm_k;
const int64_t gemm_n = params.problem_visitor.gemm_n;
int64_t bytes_per_expert_matrix =
(gemm_k * gemm_n / 8) * cutlass::sizeof_bits<ElementB>::value;
// Outer 'persistent' loop to iterate over tiles
while (problem_visitor.next_tile()) {
GemmCoord problem_size = problem_visitor.problem_size();
int32_t problem_idx = problem_visitor.problem_index();
int32_t cta_idx = int32_t(problem_visitor.threadblock_idx());
GemmCoord grid_shape = problem_visitor.grid_shape(problem_size);
cutlass::gemm::GemmCoord threadblock_offset(
int(cta_idx / grid_shape.n()) * Mma::Shape::kM, // NOLINT
int(cta_idx % grid_shape.n()) * Mma::Shape::kN, // NOLINT
0);
// Load element pointers. Exchange pointers and strides if working on
// the transpose
const int64_t rows_to_jump =
problem_idx == 0
? 0
: params.problem_visitor.last_row_for_problem[problem_idx - 1];
ElementA* ptr_A =
reinterpret_cast<ElementA*>(params.ptr_A) + rows_to_jump * gemm_k;
typename LayoutA::LongIndex ldm_A = gemm_k;
char* byte_ptr_B = ((char*)params.ptr_B) + // NOLINT
problem_idx * bytes_per_expert_matrix; // NOLINT
ElementB* ptr_B = reinterpret_cast<ElementB*>(byte_ptr_B);
typename LayoutB::LongIndex ldm_B =
platform::is_same<layout::RowMajor, LayoutB>::value
? gemm_n
: gemm_k * kInterleave;
// Compute initial location in logical coordinates
cutlass::MatrixCoord tb_offset_A{
threadblock_offset.m(),
0,
};
cutlass::MatrixCoord tb_offset_B{0,
threadblock_offset.n() / kInterleave};
cutlass::MatrixCoord tb_offset_scale{0, threadblock_offset.n()};
// Compute position within threadblock
int thread_idx = threadIdx.x;
// Construct iterators to A and B operands
typename Mma::IteratorA iterator_A(LayoutA(ldm_A),
ptr_A,
{problem_size.m(), problem_size.k()},
thread_idx,
tb_offset_A);
typename Mma::IteratorB iterator_B(
LayoutB(ldm_B),
ptr_B,
{problem_size.k() * kInterleave, problem_size.n() / kInterleave},
thread_idx,
tb_offset_B);
typename Mma::FragmentC accumulators;
accumulators.clear();
// Broadcast the warp_id computed by lane 0 to ensure dependent code
// is compiled as warp-uniform.
int warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0);
int lane_idx = threadIdx.x % 32;
//
// Matrix multiply phase
//
// Construct thread-scoped matrix multiply
auto CreateMMA = [&]() {
if constexpr (use_dq_gemm<Mma>::value)
return Mma(
shared_storage.main_loop, -1, thread_idx, warp_idx, lane_idx);
else
return Mma(
shared_storage.main_loop, thread_idx, warp_idx, lane_idx);
};
Mma mma = CreateMMA();
// Compute threadblock-scoped matrix multiply-add
int gemm_k_iterations =
(problem_size.k() + Mma::Shape::kK - 1) / Mma::Shape::kK;
// Wait for all threads to finish their epilogue phases from the
// previous tile.
__syncthreads();
// Compute threadblock-scoped matrix multiply-add
ElementScale* weight_scale_ptr =
params.weight_scales + problem_idx * problem_size.n();
run_mma<Mma>(mma,
gemm_k_iterations,
accumulators,
iterator_A,
iterator_B,
accumulators,
weight_scale_ptr,
{1, problem_size.n()},
thread_idx,
tb_offset_scale);
//
// Epilogue
//
EpilogueOutputOp output_op(params.output_op);
ElementC* ptr_C =
reinterpret_cast<ElementC*>(params.ptr_C) + problem_idx * gemm_n;
ElementC* ptr_D =
reinterpret_cast<ElementC*>(params.ptr_D) + rows_to_jump * gemm_n;
LayoutC layout_C(0);
LayoutC layout_D(gemm_n);
typename Epilogue::OutputTileIterator::Params params_C(layout_C);
typename Epilogue::OutputTileIterator::Params params_D(layout_D);
// Tile iterator loading from source tensor.
typename Epilogue::OutputTileIterator iterator_C(
params_C,
ptr_C,
problem_size.mn(),
thread_idx,
threadblock_offset.mn());
// Tile iterator writing to destination tensor.
typename Epilogue::OutputTileIterator iterator_D(
params_D,
ptr_D,
problem_size.mn(),
thread_idx,
threadblock_offset.mn());
Epilogue epilogue(
shared_storage.epilogue, thread_idx, warp_idx, lane_idx);
// Execute the epilogue operator to update the destination tensor.
epilogue(output_op, iterator_D, accumulators, iterator_C);
// Next tile
problem_visitor.advance(gridDim.x);
}
}
};
/*
To improve compilation speed, we do not compile the device operator if the
CUDA_ARCH does not correspond to the ArchTag of the cutlass kernel operator.
*/
/// Executes one GEMM
CUTLASS_DEVICE
void operator()(Params const& params,
SharedStorage& shared_storage) { // NOLINT
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 700) && (__CUDA_ARCH__ < 750)
static constexpr bool compile_needed =
platform::is_same<KernelArch, arch::Sm70>::value;
KernelRunner<compile_needed>::run_kernel(params, shared_storage);
#elif defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 750) && (__CUDA_ARCH__ < 800)
static constexpr bool compile_needed =
platform::is_same<KernelArch, arch::Sm75>::value;
KernelRunner<compile_needed>::run_kernel(params, shared_storage);
#elif defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800) && (__CUDA_ARCH__ < 900)
static constexpr bool compile_needed =
platform::is_same<KernelArch, arch::Sm80>::value;
KernelRunner<compile_needed>::run_kernel(params, shared_storage);
#elif defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && (__CUDA_ARCH__ < 910)
static constexpr bool compile_needed =
platform::is_same<KernelArch, arch::Sm80>::value;
KernelRunner<compile_needed>::run_kernel(params, shared_storage);
#else
CUTLASS_NOT_IMPLEMENTED();
#endif
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace kernel
} // namespace gemm
} // namespace cutlass
/////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cuda_runtime_api.h>
#include <string>
#include "paddle/phi/kernels/fusion/cutlass/cutlass_extensions/ft_gemm_configs.h"
using namespace phi;
template <typename T, /*The type used for activations/scales/compute*/
typename WeightType /* The type for the MoE weights */>
class MoeGemmRunner {
public:
MoeGemmRunner();
void moe_gemm_bias_act(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
std::string activation_type,
cudaStream_t stream);
void moe_gemm(const T* A,
const WeightType* B,
const T* weight_scales,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
cudaStream_t stream);
private:
template <typename EpilogueTag>
void dispatch_to_arch(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
cudaStream_t stream,
int* occupancy = nullptr);
template <typename EpilogueTag>
void run_gemm(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
cudaStream_t stream);
private:
int sm_;
int multi_processor_count_;
};

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels.h"
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels_template.h"
#include "helper.h"
#ifdef PADDLE_CUDA_BF16
template class MoeGemmRunner<__nv_bfloat16, __nv_bfloat16>;
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels.h"
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels_template.h"
#include "helper.h"
#ifdef PADDLE_CUDA_BF16
template class MoeGemmRunner<__nv_bfloat16, cutlass::uint4b_t>;
#endif

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels.h"
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels_template.h"
#include "helper.h"
#ifdef PADDLE_CUDA_BF16
template class MoeGemmRunner<__nv_bfloat16, uint8_t>;
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels.h"
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels_template.h"
#include "helper.h"
template class MoeGemmRunner<half, half>;

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels.h"
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels_template.h"
#include "helper.h"
template class MoeGemmRunner<half, cutlass::uint4b_t>;

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels.h"
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels_template.h"
#include "helper.h"
template class MoeGemmRunner<half, uint8_t>;

View File

@@ -0,0 +1,819 @@
/*
* Copyright (c) 2020-2024, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Ignore CUTLASS warnings about type punning
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma once
#include <cuda.h>
#include <cuda_fp16.h>
#include <math.h>
#include <optional>
#include <sstream>
#include "cutlass/array.h"
#include "cutlass/gemm/device/gemm_grouped.h"
#include "cutlass/gemm/kernel/default_gemm_grouped.h"
#include "cutlass/numeric_conversion.h"
#include "cutlass_kernels/moe_gemm/fused_moe_cutlass_kernel.h"
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels.h"
#include "paddle/common/errors.h"
#include "paddle/phi/core/enforce.h"
#include "paddle/phi/kernels/fusion/cutlass/cutlass_extensions/compute_occupancy.h"
#include "paddle/phi/kernels/fusion/cutlass/cutlass_extensions/epilogue_helpers.h"
#include "paddle/phi/kernels/fusion/cutlass/cutlass_extensions/gemm/kernel/default_fpA_intB_traits.h"
#include "paddle/phi/kernels/fusion/cutlass/cutlass_extensions/gemm/threadblock/default_mma.h"
#pragma GCC diagnostic pop
#include "helper.h"
#include "paddle/phi/kernels/fusion/cutlass/cutlass_kernels/cutlass_heuristic.h"
#include "paddle/phi/kernels/fusion/cutlass/cutlass_kernels/gemm_config_manager.h"
using namespace phi;
// ============================= Variable batched Gemm things
// ===========================
template <typename T,
typename WeightType,
typename arch,
typename EpilogueTag,
typename ThreadblockShape,
typename WarpShape,
int Stages>
void generic_moe_gemm_kernelLauncher(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
const int multi_processor_count,
cudaStream_t stream,
int* kernel_occupancy = nullptr) {
if (gemm_config.split_k_style != SplitKStyle::NO_SPLIT_K) {
throw std::runtime_error(
"[MoeGemm] Grouped gemm does not support split-k");
}
#ifdef PADDLE_CUDA_BF16
static_assert(cutlass::platform::is_same<T, __nv_bfloat16>::value ||
cutlass::platform::is_same<T, half>::value ||
cutlass::platform::is_same<T, float>::value,
"Specialized for bfloat16, half, float");
#else
static_assert(cutlass::platform::is_same<T, half>::value ||
cutlass::platform::is_same<T, float>::value,
"Specialized for half, float");
#endif
static_assert(
cutlass::platform::is_same<T, WeightType>::value ||
cutlass::platform::is_same<WeightType, uint8_t>::value ||
cutlass::platform::is_same<WeightType, cutlass::uint4b_t>::value,
"");
// The cutlass type for the input elements. This is needed to convert to
// cutlass::half_t if necessary.
using ElementType_ = typename cutlass::platform::conditional<
cutlass::platform::is_same<T, half>::value,
cutlass::half_t,
T>::type;
#ifdef PADDLE_CUDA_BF16
using ElementType = typename cutlass::platform::conditional<
cutlass::platform::is_same<ElementType_, __nv_bfloat16>::value,
cutlass::bfloat16_t,
ElementType_>::type;
#else
using ElementType = ElementType_;
#endif
using CutlassWeightType_ = typename cutlass::platform::conditional<
cutlass::platform::is_same<WeightType, half>::value,
cutlass::half_t,
WeightType>::type;
#ifdef PADDLE_CUDA_BF16
using CutlassWeightType = typename cutlass::platform::conditional<
cutlass::platform::is_same<CutlassWeightType_, __nv_bfloat16>::value,
cutlass::bfloat16_t,
CutlassWeightType_>::type;
#else
using CutlassWeightType = CutlassWeightType_;
#endif
// We need separate config for each architecture since we will target
// different tensorcore instructions. For float, we do not target TCs.
using MixedGemmArchTraits = cutlass::gemm::kernel::
MixedGemmArchTraits<ElementType, CutlassWeightType, arch>;
using ElementAccumulator = typename MixedGemmArchTraits::AccType;
using EpilogueOp = typename Epilogue<ElementType,
MixedGemmArchTraits::ElementsPerAccessC,
ElementAccumulator,
EpilogueTag>::Op;
// Finally, set up the kernel.
using GemmKernel_ = typename cutlass::gemm::kernel::DefaultGemmGrouped<
ElementType,
cutlass::layout::RowMajor,
cutlass::ComplexTransform::kNone,
MixedGemmArchTraits::ElementsPerAccessA,
CutlassWeightType,
typename MixedGemmArchTraits::LayoutB,
cutlass::ComplexTransform::kNone,
MixedGemmArchTraits::ElementsPerAccessB,
ElementType,
cutlass::layout::RowMajor,
ElementAccumulator,
typename MixedGemmArchTraits::OperatorClass,
arch,
ThreadblockShape,
WarpShape,
typename MixedGemmArchTraits::InstructionShape,
EpilogueOp,
cutlass::gemm::threadblock::GemmBatchedIdentityThreadblockSwizzle,
Stages,
cutlass::gemm::kernel::GroupScheduleMode::kDeviceOnly,
typename MixedGemmArchTraits::Operator>::GemmKernel;
using GemmKernel =
cutlass::gemm::kernel::MoeFCGemm<typename GemmKernel_::Mma,
typename GemmKernel_::Epilogue,
typename GemmKernel_::ThreadblockSwizzle,
arch, // Ensure top level arch is used
// for dispatch
GemmKernel_::kGroupScheduleMode>;
using GemmGrouped = cutlass::gemm::device::GemmGrouped<GemmKernel>;
if (kernel_occupancy != nullptr) {
*kernel_occupancy = compute_occupancy_for_kernel<GemmKernel>();
return;
}
int occupancy = std::min(2, GemmGrouped::maximum_active_blocks());
if (occupancy == 0) {
throw std::runtime_error(
"[MoE Runner] GPU lacks the shared memory resources to run "
"GroupedGEMM kernel");
}
const int threadblock_count = multi_processor_count * occupancy;
typename EpilogueOp::Params epilogue_op(ElementAccumulator(1.f),
ElementAccumulator(0.f));
typename GemmGrouped::Arguments args(
num_experts,
threadblock_count,
epilogue_op,
reinterpret_cast<const ElementType*>(A),
reinterpret_cast<const CutlassWeightType*>(B),
reinterpret_cast<const ElementType*>(weight_scales),
reinterpret_cast<const ElementType*>(biases),
reinterpret_cast<ElementType*>(C),
total_rows_before_expert,
gemm_n,
gemm_k);
GemmGrouped gemm;
auto can_implement = gemm.can_implement(args);
if (can_implement != cutlass::Status::kSuccess) {
std::string err_msg = "MoEFC kernel will fail for params. Error: " +
std::string(cutlassGetStatusString(can_implement));
throw std::runtime_error("[MoE Runner] " + err_msg);
}
auto init_status = gemm.initialize(args);
if (init_status != cutlass::Status::kSuccess) {
std::string err_msg =
"Failed to initialize cutlass variable batched gemm. Error: " +
std::string(cutlassGetStatusString(init_status));
throw std::runtime_error("[MoE Runner] " + err_msg);
}
auto run_status = gemm.run(stream);
if (run_status != cutlass::Status::kSuccess) {
std::string err_msg =
"Failed to run cutlass variable batched gemm. Error: " +
std::string(cutlassGetStatusString(run_status));
throw std::runtime_error("[MoE Runner] " + err_msg);
}
}
template <typename T,
typename WeightType,
typename arch,
typename EpilogueTag,
typename ThreadblockShape,
typename WarpShape,
int Stages,
typename Enable = void>
struct dispatch_stages {
static void dispatch(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
int multi_processor_count,
cudaStream_t stream,
int* occupancy = nullptr) {
// FT_LOG_DEBUG(__PRETTY_FUNCTION__);
std::string err_msg = "Cutlass fpA_intB gemm. Not instantiates for arch " +
std::to_string(arch::kMinComputeCapability) +
" with stages set to " + std::to_string(Stages);
throw std::runtime_error("[dispatch_stages::dispatch] " + err_msg);
}
};
template <typename T,
typename WeightType,
typename arch,
typename EpilogueTag,
typename ThreadblockShape,
typename WarpShape>
struct dispatch_stages<T,
WeightType,
arch,
EpilogueTag,
ThreadblockShape,
WarpShape,
2> {
static void dispatch(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
int multi_processor_count,
cudaStream_t stream,
int* occupancy = nullptr) {
generic_moe_gemm_kernelLauncher<T,
WeightType,
arch,
EpilogueTag,
ThreadblockShape,
WarpShape,
2>(A,
B,
weight_scales,
biases,
C,
total_rows_before_expert,
gemm_n,
gemm_k,
num_experts,
gemm_config,
multi_processor_count,
stream,
occupancy);
}
};
template <typename T,
typename WeightType,
typename EpilogueTag,
typename ThreadblockShape,
typename WarpShape,
int Stages>
struct dispatch_stages<T,
WeightType,
cutlass::arch::Sm80,
EpilogueTag,
ThreadblockShape,
WarpShape,
Stages,
typename std::enable_if<(Stages > 2)>::type> {
static void dispatch(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
int multi_processor_count,
cudaStream_t stream,
int* occupancy = nullptr) {
generic_moe_gemm_kernelLauncher<T,
WeightType,
cutlass::arch::Sm80,
EpilogueTag,
ThreadblockShape,
WarpShape,
Stages>(A,
B,
weight_scales,
biases,
C,
total_rows_before_expert,
gemm_n,
gemm_k,
num_experts,
gemm_config,
multi_processor_count,
stream,
occupancy);
}
};
template <typename T,
typename WeightType,
typename arch,
typename EpilogueTag,
typename ThreadblockShape,
typename WarpShape>
void dispatch_gemm_config(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
int multi_processor_count,
cudaStream_t stream,
int* occupancy = nullptr) {
#define dispatch_stages_macro(STAGE) \
case STAGE: \
dispatch_stages<T, \
WeightType, \
arch, \
EpilogueTag, \
ThreadblockShape, \
WarpShape, \
STAGE>::dispatch(A, \
B, \
weight_scales, \
biases, \
C, \
total_rows_before_expert, \
gemm_n, \
gemm_k, \
num_experts, \
gemm_config, \
multi_processor_count, \
stream, \
occupancy); \
break;
switch (gemm_config.stages) {
dispatch_stages_macro(2);
dispatch_stages_macro(3);
dispatch_stages_macro(4);
dispatch_stages_macro(5);
default:
std::string err_msg = "dispatch_gemm_config does not support stages " +
std::to_string(gemm_config.stages);
throw std::runtime_error(
"[MoE][dispatch_gemm_config] " + err_msg);
break;
}
}
#define dispatch_gemm_config_macro(AA, BB, CC, DD, EE, FF) \
case CutlassTileConfig:: \
CtaShape##AA##x##BB##x##CC##_WarpShape##DD##x##EE##x##FF: \
dispatch_gemm_config<T, \
WeightType, \
arch, \
EpilogueTag, \
cutlass::gemm::GemmShape<AA, BB, CC>, \
cutlass::gemm::GemmShape<DD, EE, FF>>( \
A, \
B, \
weight_scales, \
biases, \
C, \
total_rows_before_expert, \
gemm_n, \
gemm_k, \
num_experts, \
gemm_config, \
multi_processor_count, \
stream, \
occupancy); \
break;
// This overload will handle tensorop gemms. It is disabled via SFINAE for fp32.
// This overload is only enabled when T == WeightType.
template <typename T,
typename WeightType,
typename arch,
typename EpilogueTag,
typename std::enable_if<!std::is_same<T, float>::value &&
std::is_same<T, WeightType>::value>::type* =
nullptr>
void dispatch_moe_gemm_to_cutlass(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
int sm_version,
int multi_processor_count,
cudaStream_t stream,
int* occupancy = nullptr) {
switch (gemm_config.tile_config) {
dispatch_gemm_config_macro(32, 128, 64, 32, 32, 64);
dispatch_gemm_config_macro(64, 128, 64, 32, 64, 64);
dispatch_gemm_config_macro(128, 128, 64, 64, 32, 64);
case CutlassTileConfig::Undefined:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass] gemm config undefined.");
break;
case CutlassTileConfig::ChooseWithHeuristic:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass] gemm config should have "
"already been set by heuristic.");
break;
default:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass] Config is invalid for same "
"type MoE tensorop GEMM.");
break;
}
}
// Tensorop GEMM overload
// Overload for quantize MoE GEMMs. We disable some warp configs here since they
// will not be used and we can improve compile time
template <typename T,
typename WeightType,
typename arch,
typename EpilogueTag,
typename std::enable_if<!std::is_same<T, float>::value &&
!std::is_same<T, WeightType>::value>::type* =
nullptr>
void dispatch_moe_gemm_to_cutlass(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
int sm_version,
int multi_processor_count,
cudaStream_t stream,
int* occupancy = nullptr) {
if constexpr (std::is_same<arch, cutlass::arch::Sm70>::value) {
switch (gemm_config.tile_config) {
dispatch_gemm_config_macro(32, 128, 64, 32, 32, 64);
dispatch_gemm_config_macro(64, 128, 64, 64, 64, 64);
case CutlassTileConfig::Undefined:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass] gemm config undefined.");
break;
case CutlassTileConfig::ChooseWithHeuristic:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass] gemm config should have "
"already been set by heuristic.");
break;
default:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass] Config is invalid for "
"mixed type tensorop GEMM.");
break;
}
} else {
switch (gemm_config.tile_config) {
dispatch_gemm_config_macro(16, 128, 64, 16, 32, 64);
dispatch_gemm_config_macro(16, 256, 64, 16, 64, 64);
dispatch_gemm_config_macro(64, 64, 64, 32, 32, 64);
dispatch_gemm_config_macro(32, 128, 64, 32, 32, 64);
dispatch_gemm_config_macro(128, 64, 64, 64, 32, 64);
dispatch_gemm_config_macro(64, 128, 64, 64, 64, 64);
dispatch_gemm_config_macro(128, 128, 64, 64, 64, 64);
dispatch_gemm_config_macro(128, 128, 64, 128, 32, 64);
dispatch_gemm_config_macro(128, 256, 64, 64, 64, 64);
dispatch_gemm_config_macro(64, 128, 64, 64, 32, 64);
dispatch_gemm_config_macro(256, 128, 64, 64, 64, 64);
case CutlassTileConfig::Undefined:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass] gemm config undefined.");
break;
case CutlassTileConfig::ChooseWithHeuristic:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass] gemm config should have "
"already been set by heuristic.");
break;
default:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass] Config is invalid for "
"mixed type tensorop GEMM.");
break;
}
}
}
// This overload will handle simt gemms. It is disabled via SFINAE for tensorop.
template <
typename T,
typename WeightType,
typename arch,
typename EpilogueTag,
typename std::enable_if<std::is_same<T, float>::value>::type* = nullptr>
void dispatch_moe_gemm_to_cutlass(const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
int sm_version,
int multi_processor_count,
cudaStream_t stream,
int* occupancy = nullptr) {
switch (gemm_config.tile_config) {
dispatch_gemm_config_macro(128, 128, 8, 64, 64, 8);
case CutlassTileConfig::Undefined:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass][SIMT] gemm config "
"undefined.");
break;
case CutlassTileConfig::ChooseWithHeuristic:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass][SIMT] gemm config should "
"have already been set by heuristic.");
break;
default:
throw std::runtime_error(
"[dispatch_moe_gemm_to_cutlass][SIMT] Unsupported config "
"for float MoE gemm.");
break;
}
}
template <typename T, typename WeightType>
MoeGemmRunner<T, WeightType>::MoeGemmRunner() {
int device{-1};
check_cuda_error(cudaGetDevice(&device));
sm_ = getSMVersion();
check_cuda_error(cudaDeviceGetAttribute(
&multi_processor_count_, cudaDevAttrMultiProcessorCount, device));
}
template <typename T, typename WeightType>
template <typename EpilogueTag>
void MoeGemmRunner<T, WeightType>::dispatch_to_arch<EpilogueTag>(
const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
CutlassGemmConfig gemm_config,
cudaStream_t stream,
int* occupancy) {
#define dispatch_moe_gemm_to_cutlass_macro(ARCH) \
dispatch_moe_gemm_to_cutlass<T, WeightType, ARCH, EpilogueTag>( \
A, \
B, \
weight_scales, \
biases, \
C, \
total_rows_before_expert, \
total_rows, \
gemm_n, \
gemm_k, \
num_experts, \
gemm_config, \
sm_, \
multi_processor_count_, \
stream, \
occupancy);
if (sm_ >= 70 && sm_ < 75) {
dispatch_moe_gemm_to_cutlass_macro(cutlass::arch::Sm70);
} else if (sm_ >= 75 && sm_ < 80) {
dispatch_moe_gemm_to_cutlass_macro(cutlass::arch::Sm75);
} else if (sm_ >= 80 && sm_ < 91) {
dispatch_moe_gemm_to_cutlass_macro(cutlass::arch::Sm80);
} else {
PADDLE_FATAL("[MoE][GEMM Dispatch] Arch unsupported for MoE GEMM");
}
}
template <typename T, typename WeightType>
template <typename EpilogueTag>
void MoeGemmRunner<T, WeightType>::run_gemm<EpilogueTag>(
const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
cudaStream_t stream) {
static constexpr bool is_weight_only = !std::is_same<T, WeightType>::value;
static constexpr bool only_simt_configs = std::is_same<T, float>::value;
std::vector<CutlassGemmConfig> candidate_configs =
get_candidate_configs(sm_, -1, is_weight_only, only_simt_configs, true);
static constexpr int warm_time = 5;
static constexpr int test_time = 10;
auto& gemmConfigManager = GemmConfigManager::Instance();
constexpr GemmDataType dtype = getGemmDataType<T>();
constexpr GemmDataType wdtype = getGemmDataType<WeightType>();
GemmIDType gemmId{
gemm_n, gemm_k, GemmType::MOEGEMM, dtype, wdtype, num_experts};
CutlassGemmConfig chosen_config;
auto chosen_config_optional =
gemmConfigManager.getBestConfig(gemmId, total_rows);
if (chosen_config_optional != std::nullopt) {
chosen_config = chosen_config_optional.value();
} else {
float best_time = std::numeric_limits<float>::max();
CutlassGemmConfig best_config;
int profile_total_rows =
std::min(gemmConfigManager.nextPowerOfTwo(total_rows),
gemmConfigManager.getMaxProfileM());
bool find_one = false;
for (size_t ii = 0; ii < candidate_configs.size(); ++ii) {
try {
for (int i = 0; i < warm_time; i++) {
dispatch_to_arch<EpilogueTag>(A,
B,
weight_scales,
biases,
C,
total_rows_before_expert,
total_rows,
gemm_n,
gemm_k,
num_experts,
candidate_configs[ii],
stream);
}
cudaEvent_t start;
cudaEvent_t stop;
check_cuda_error(cudaEventCreate(&start));
check_cuda_error(cudaEventCreate(&stop));
check_cuda_error(cudaStreamSynchronize(stream));
check_cuda_error(cudaEventRecord(start, stream));
for (int i = 0; i < test_time; i++) {
dispatch_to_arch<EpilogueTag>(A,
B,
weight_scales,
biases,
C,
total_rows_before_expert,
total_rows,
gemm_n,
gemm_k,
num_experts,
candidate_configs[ii],
stream);
}
check_cuda_error(cudaEventRecord(stop, stream));
check_cuda_error(cudaEventSynchronize(stop));
float elapsed;
check_cuda_error(cudaEventElapsedTime(&elapsed, start, stop));
check_cuda_error(cudaEventDestroy(start));
check_cuda_error(cudaEventDestroy(stop));
if (elapsed < best_time) {
best_time = elapsed;
best_config = candidate_configs[ii];
}
find_one = true;
} catch (const std::exception& e) {
std::cerr << "MOE config[" << ii << "] Caught exception: " << e.what()
<< std::endl;
}
}
if (find_one) {
gemmConfigManager.addBestConfig(gemmId, profile_total_rows, best_config);
chosen_config = best_config;
} else {
PADDLE_FATAL("[MoE Configure Search] find no one available config.");
}
}
dispatch_to_arch<EpilogueTag>(A,
B,
weight_scales,
biases,
C,
total_rows_before_expert,
total_rows,
gemm_n,
gemm_k,
num_experts,
chosen_config,
stream);
}
template <typename T, typename WeightType>
void MoeGemmRunner<T, WeightType>::moe_gemm_bias_act(
const T* A,
const WeightType* B,
const T* weight_scales,
const T* biases,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
std::string activation_type,
cudaStream_t stream) {
if (activation_type == "none") {
if (biases) {
run_gemm<EpilogueOpBias>(A,
B,
weight_scales,
biases,
C,
total_rows_before_expert,
total_rows,
gemm_n,
gemm_k,
num_experts,
stream);
} else {
run_gemm<EpilogueOpNoBias>(A,
B,
weight_scales,
nullptr,
C,
total_rows_before_expert,
total_rows,
gemm_n,
gemm_k,
num_experts,
stream);
}
}
}
template <typename T, typename WeightType>
void MoeGemmRunner<T, WeightType>::moe_gemm(const T* A,
const WeightType* B,
const T* weight_scales,
T* C,
int64_t* total_rows_before_expert,
int64_t total_rows,
int64_t gemm_n,
int64_t gemm_k,
int num_experts,
cudaStream_t stream) {
run_gemm<EpilogueOpNoBias>(A,
B,
weight_scales,
nullptr,
C,
total_rows_before_expert,
total_rows,
gemm_n,
gemm_k,
num_experts,
stream);
}

View File

@@ -0,0 +1,192 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Ignore CUTLASS warnings about type punning
#pragma once
#include "cutlass/numeric_conversion.h"
#include "helper.h"
#include "moe/fused_moe_helper.h"
__global__ void compute_total_rows_before_expert_kernel(
int* sorted_experts,
const int64_t sorted_experts_len,
const int64_t num_experts,
int64_t* total_rows_before_expert) {
// First, compute the global tid. We only need 1 thread per expert.
const int expert = blockIdx.x * blockDim.x + threadIdx.x;
if (expert >= num_experts) return;
// This should construct the last index where each expert occurs.
total_rows_before_expert[expert] =
find_total_elts_leq_target(sorted_experts, sorted_experts_len, expert);
}
void compute_total_rows_before_expert(int* sorted_indices,
const int64_t total_indices,
const int64_t num_experts,
int64_t* total_rows_before_expert,
cudaStream_t stream) {
const int threads = std::min(int64_t(1024), num_experts);
const int blocks = (num_experts + threads - 1) / threads;
compute_total_rows_before_expert_kernel<<<blocks, threads, 0, stream>>>(
sorted_indices, total_indices, num_experts, total_rows_before_expert);
}
template <paddle::DataType T>
void FusedMoeKernel(const paddle::Tensor& input,
const paddle::Tensor& gate_weight,
const paddle::Tensor& ffn1_weight,
const paddle::optional<paddle::Tensor>& ffn1_scale,
const paddle::optional<paddle::Tensor>& ffn1_bias,
const paddle::Tensor& ffn2_weight,
const paddle::optional<paddle::Tensor>& ffn2_scale,
const paddle::optional<paddle::Tensor>& ffn2_bias,
const std::string& quant_method,
const int moe_topk,
const bool group_moe,
const bool norm_topk_prob,
paddle::Tensor* output) {
typedef PDTraits<T> traits_;
typedef typename traits_::DataType DataType_;
typedef typename traits_::data_t data_t;
auto* output_data = output->data<data_t>();
auto fp16_moe_gemm_runner = MoeGemmRunner<DataType_, DataType_>();
auto int8_moe_gemm_runner = MoeGemmRunner<DataType_, uint8_t>();
auto int4_moe_gemm_runner = MoeGemmRunner<DataType_, cutlass::uint4b_t>();
using NvType = typename traits_::DataType;
auto moe_compute = MoeHelper<data_t, NvType>(quant_method,
&fp16_moe_gemm_runner,
&int8_moe_gemm_runner,
&int4_moe_gemm_runner);
moe_compute.ComputeFFN(&input,
&gate_weight,
&ffn1_weight,
ffn1_scale ? ffn1_scale.get_ptr() : nullptr,
ffn1_bias ? ffn1_bias.get_ptr() : nullptr,
&ffn2_weight,
ffn2_scale ? ffn2_scale.get_ptr() : nullptr,
ffn2_bias ? ffn2_bias.get_ptr() : nullptr,
nullptr,
moe_topk,
group_moe,
norm_topk_prob,
1.0, // ComputeFFN
"ffn",
output);
}
std::vector<paddle::Tensor> FusedExpertMoe(
const paddle::Tensor& input,
const paddle::Tensor& gate_weight,
const paddle::Tensor& ffn1_weight,
const paddle::Tensor& ffn2_weight,
const paddle::optional<paddle::Tensor>& ffn1_bias,
const paddle::optional<paddle::Tensor>& ffn1_scale,
const paddle::optional<paddle::Tensor>& ffn2_bias,
const paddle::optional<paddle::Tensor>& ffn2_scale,
const std::string& quant_method,
const int moe_topk,
const bool norm_topk_prob,
const bool group_moe) {
const auto input_type = input.dtype();
auto output = paddle::empty_like(input);
switch (input_type) {
case paddle::DataType::BFLOAT16:
FusedMoeKernel<paddle::DataType::BFLOAT16>(input,
gate_weight,
ffn1_weight,
ffn1_scale,
ffn1_bias,
ffn2_weight,
ffn2_scale,
ffn2_bias,
quant_method,
moe_topk,
group_moe,
norm_topk_prob,
&output);
break;
case paddle::DataType::FLOAT16:
FusedMoeKernel<paddle::DataType::FLOAT16>(input,
gate_weight,
ffn1_weight,
ffn1_scale,
ffn1_bias,
ffn2_weight,
ffn2_scale,
ffn2_bias,
quant_method,
moe_topk,
group_moe,
norm_topk_prob,
&output);
break;
default:
PD_THROW("Unsupported data type for FusedMoeKernel");
}
return {output};
}
std::vector<std::vector<int64_t>> FusedExpertMoeInferShape(
const std::vector<int64_t>& input_shape,
const std::vector<int64_t>& gate_weight_shape,
const std::vector<int64_t>& ffn1_weight_shape,
const std::vector<int64_t>& ffn2_weight_shape,
const paddle::optional<std::vector<int64_t>>& ffn1_bias_shape,
const paddle::optional<std::vector<int64_t>>& ffn1_scale_shape,
const paddle::optional<std::vector<int64_t>>& ffn2_bias_shape,
const paddle::optional<std::vector<int64_t>>& ffn2_scale_shape) {
return {input_shape};
}
std::vector<paddle::DataType> FusedExpertMoeInferDtype(
const paddle::DataType& input_dtype,
const paddle::DataType& gate_weight_dtype,
const paddle::DataType& ffn1_weight_dtype,
const paddle::DataType& ffn2_weight_dtype,
const paddle::optional<paddle::DataType>& ffn1_bias_dtype,
const paddle::optional<paddle::DataType>& ffn1_scale_dtype,
const paddle::optional<paddle::DataType>& ffn2_bias_dtype,
const paddle::optional<paddle::DataType>& ffn2_scale_dtype) {
return {input_dtype};
}
PD_BUILD_OP(fused_expert_moe)
.Inputs({"input",
"gate_weight",
"ffn1_weight",
"ffn2_weight",
paddle::Optional("ffn1_bias"),
paddle::Optional("ffn1_scale"),
paddle::Optional("ffn2_bias"),
paddle::Optional("ffn2_scale")})
.Outputs({"output"})
.Attrs({"quant_method:std::string",
"moe_topk:int",
"norm_topk_prob:bool",
"group_moe:bool"})
.SetKernelFn(PD_KERNEL(FusedExpertMoe))
.SetInferShapeFn(PD_INFER_SHAPE(FusedExpertMoeInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(FusedExpertMoeInferDtype));

View File

@@ -0,0 +1,14 @@
#pragma once
#include <iostream>
/// @brief Defines a macro to disable log output.
/// @details This macro returns a `NullStream` object, and all content passed via `<<` is ignored.
/// It is designed to keep the code compilable without modifying log call statement.
/// @param level The log level (ignored).
class NullStream {
public:
template <typename T>
NullStream& operator<<(const T&) { return *this; }
};
#define VLOG(level) NullStream()

View File

@@ -0,0 +1,427 @@
/* Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#pragma once
#include "cutlass_kernels/moe_gemm/fused_moe_gemm_kernels.h"
#include "moe/fused_moe_op.h"
using namespace phi;
template <typename T, int VecSize>
__global__ void moe_token_type_ids_kernel(T *gating_output,
const int *moe_token_type_ids_out,
const int num_rows,
const int num_experts,
const int k) {
const int moe_token_index = blockIdx.x * blockDim.x + threadIdx.x;
if (moe_token_index >= num_rows) {
return;
}
gating_output[moe_token_index * 2] =
gating_output[moe_token_index * 2] +
(moe_token_type_ids_out[moe_token_index]) * -1e10;
gating_output[moe_token_index * 2 + 1] =
gating_output[moe_token_index * 2 + 1] +
(1 - moe_token_type_ids_out[moe_token_index]) * -1e10;
}
template <typename T>
void moe_token_type_ids_kernelLauncher(T *gating_output,
const int *moe_token_type_ids_out,
const int num_rows,
const int num_experts,
const int k,
cudaStream_t stream) {
const int blocks = num_rows * k / 512 + 1;
const int threads = 512;
moe_token_type_ids_kernel<T, 1><<<blocks, 512, 0, stream>>>(
gating_output, moe_token_type_ids_out, num_rows, num_experts, k);
}
template <typename T, typename NvType>
class MoeHelper {
public:
MoeHelper(const std::string gemm_method,
MoeGemmRunner<NvType, NvType> *fp16_moe_gemm_runner,
MoeGemmRunner<NvType, uint8_t> *int8_moe_gemm_runner,
MoeGemmRunner<NvType, cutlass::uint4b_t> *int4_moe_gemm_runner,
int layernum = 0)
: gemm_method_(gemm_method),
fp16_moe_gemm_runner_(fp16_moe_gemm_runner),
int8_moe_gemm_runner_(int8_moe_gemm_runner),
int4_moe_gemm_runner_(int4_moe_gemm_runner),
layernum_(layernum) {}
// -------- getWorkspaceSize -------- //
template <typename KeyT>
size_t getWorkspaceSize(const int64_t num_rows,
const int64_t hidden_size,
const int64_t inter_size,
const int64_t num_experts,
const int64_t k) {
const size_t buf_size = AlignTo16(k * num_rows * hidden_size);
const size_t interbuf_size = AlignTo16(k * num_rows * inter_size);
const size_t padded_experts = AlignTo16(num_experts);
const size_t num_moe_inputs = AlignTo16(k * num_rows);
// softmax output, permuted_rows and permuted_experts have moved to outside
// of moe kernel, allocate them in Encoder or Decoder before invoking
// FfnLayer forward.
size_t total_ws_bytes =
5 * num_moe_inputs *
sizeof(int); // source_rows_, permuted_rows_, permuted_experts_
total_ws_bytes += buf_size * sizeof(KeyT); // permuted_data
total_ws_bytes +=
padded_experts * sizeof(int64_t); // Hold total_rows_before_expert_
const size_t bytes_for_fc1_result = interbuf_size * sizeof(KeyT);
const size_t sorter_ws_size_bytes =
AlignTo16(sorter_.getWorkspaceSize(num_rows));
sorter_.update_num_experts(num_experts);
int64_t bytes_for_intermediate_and_sorting = bytes_for_fc1_result;
if (sorter_ws_size_bytes > bytes_for_fc1_result) {
int64_t remaining_bytes =
AlignTo16(sorter_ws_size_bytes - bytes_for_fc1_result);
bytes_for_intermediate_and_sorting += remaining_bytes;
}
total_ws_bytes +=
bytes_for_intermediate_and_sorting; // intermediate (fc1) output + cub
// sorting workspace
int64_t num_softmax_outs = 0;
const bool is_pow_2 =
(num_experts != 0) && ((num_experts & (num_experts - 1)) == 0);
if (!is_pow_2 || num_experts > 256) {
num_softmax_outs = AlignTo16(num_rows * num_experts);
}
total_ws_bytes += num_softmax_outs * sizeof(float);
return total_ws_bytes;
}
void ComputeFFN(const paddle::Tensor *input,
const paddle::Tensor *gate_weight,
const paddle::Tensor *ffn1_weight,
const paddle::Tensor *ffn1_scale,
const paddle::Tensor *ffn1_bias,
const paddle::Tensor *ffn2_weight,
const paddle::Tensor *ffn2_scale,
const paddle::Tensor *ffn2_bias,
const paddle::Tensor *moe_token_type_ids,
const int moe_topk,
const bool group_moe,
const bool norm_topk_prob,
const float routed_scaling_factor,
const std::string moe_type,
paddle::Tensor *output) {
auto *input_activations = input->data<T>();
auto *gating_weights = gate_weight->data<float>();
const T *fc1_expert_biases = ffn1_bias ? ffn1_bias->data<T>() : nullptr;
const T *fc2_expert_biases = ffn2_bias ? ffn2_bias->data<T>() : nullptr;
auto *output_ = output->data<T>();
auto stream = input->stream();
auto place = input->place();
auto input_type = input->dtype();
auto input_dims = input->dims();
auto ffn1_dims = ffn1_weight->dims();
int64_t token_num = 0;
if (input_dims.size() == 3) {
token_num = input_dims[0] * input_dims[1];
} else {
token_num = input_dims[0];
}
const int64_t num_rows = token_num;
const int64_t hidden_size = ffn1_dims[1];
int64_t inter_dim = 0;
if (moe_type == "qkv") {
inter_dim = ffn1_dims[2] * ffn1_dims[3] * ffn1_dims[4];
} else {
inter_dim = ffn1_dims[2];
}
if (gemm_method_ == "weight_only_int4") {
inter_dim = inter_dim * 2;
}
const int64_t inter_size = inter_dim;
const int64_t num_experts = ffn1_dims[0];
const int64_t k = moe_topk;
int64_t bytes =
getWorkspaceSize<T>(num_rows, hidden_size, inter_size, num_experts, k);
// Pointers
int *expert_for_source_row;
int *source_rows_;
int *permuted_rows_;
int *permuted_experts_;
int *expanded_source_row_to_expanded_dest_row;
T *permuted_data_;
int64_t *total_rows_before_expert_;
T *fc1_result_;
float *softmax_out_;
paddle::Tensor ws_ptr_tensor =
GetEmptyTensor({bytes}, paddle::DataType::INT8, place);
int8_t *ws_ptr = ws_ptr_tensor.data<int8_t>();
const int64_t buf_size = AlignTo16(k * num_rows * hidden_size);
const int64_t interbuf_size = AlignTo16(k * num_rows * inter_size);
const int64_t padded_experts = AlignTo16(num_experts);
const int64_t num_moe_inputs = AlignTo16(k * num_rows);
expert_for_source_row = reinterpret_cast<int *>(ws_ptr);
source_rows_ = expert_for_source_row + num_moe_inputs;
permuted_rows_ = source_rows_ + num_moe_inputs;
permuted_experts_ = permuted_rows_ + num_moe_inputs;
expanded_source_row_to_expanded_dest_row =
permuted_experts_ + num_moe_inputs;
permuted_data_ = reinterpret_cast<T *>(
expanded_source_row_to_expanded_dest_row + num_moe_inputs);
total_rows_before_expert_ =
reinterpret_cast<int64_t *>(permuted_data_ + buf_size);
fc1_result_ =
reinterpret_cast<T *>(total_rows_before_expert_ + padded_experts);
const bool is_pow_2 =
(num_experts != 0) && ((num_experts & (num_experts - 1)) == 0);
if (!is_pow_2 || num_experts > 256) {
softmax_out_ = reinterpret_cast<float *>(fc1_result_ + interbuf_size);
} else {
softmax_out_ = nullptr;
}
paddle::Tensor expert_scales_float_tensor =
GetEmptyTensor({num_rows, moe_topk}, paddle::DataType::FLOAT32, place);
float *expert_scales_float = expert_scales_float_tensor.data<float>();
float *softmax_max_prob = nullptr;
if (group_moe) {
paddle::Tensor softmax_max_prob_tensor = GetEmptyTensor(
{num_rows, moe_topk}, paddle::DataType::FLOAT32, place);
// (TODO: check fill success ?)
paddle::experimental::fill(softmax_max_prob_tensor, 0.f);
softmax_max_prob = softmax_max_prob_tensor.data<float>();
}
paddle::Tensor fc1_out_tensor =
GetEmptyTensor({num_rows * k, inter_size}, input_type, place);
T *fc1_out = fc1_out_tensor.data<T>();
auto input_cast_tensor =
paddle::experimental::cast(*input, paddle::DataType::FLOAT32);
auto gate_tensor =
paddle::experimental::matmul(input_cast_tensor, *gate_weight);
float *gating_output = gate_tensor.data<float>();
if (moe_token_type_ids) {
auto *moe_token_type_ids_out = moe_token_type_ids->data<int>();
moe_token_type_ids_kernelLauncher<float>(gating_output,
moe_token_type_ids_out,
num_rows,
num_experts,
k,
stream);
}
topk_gating_softmax_kernelLauncher<float>(gating_output,
expert_scales_float,
softmax_out_,
expert_for_source_row,
source_rows_,
softmax_max_prob,
num_rows,
num_experts,
k,
group_moe,
stream);
const int64_t sorter_ws_size_bytes =
AlignTo16(sorter_.getWorkspaceSize(int64_t(k * num_rows)));
sorter_.run(fc1_result_,
sorter_ws_size_bytes,
expert_for_source_row,
permuted_experts_,
source_rows_,
permuted_rows_,
k * num_rows,
false,
stream);
initialize_moe_routing_kernelLauncher(
input_activations,
permuted_data_,
permuted_rows_,
expanded_source_row_to_expanded_dest_row,
num_rows,
num_rows,
hidden_size,
k,
stream);
const int64_t expanded_active_expert_rows = k * num_rows;
compute_total_rows_before_expert(permuted_experts_,
expanded_active_expert_rows,
num_experts,
total_rows_before_expert_,
stream);
if (gemm_method_ == "weight_only_int8") {
int8_moe_gemm_runner_->moe_gemm_bias_act(
reinterpret_cast<NvType *>(permuted_data_),
reinterpret_cast<const uint8_t *>(ffn1_weight->data<int8_t>()),
reinterpret_cast<const NvType *>(ffn1_scale->data<T>()),
reinterpret_cast<const NvType *>(fc1_expert_biases),
reinterpret_cast<NvType *>(fc1_out),
total_rows_before_expert_,
expanded_active_expert_rows,
inter_size,
hidden_size,
num_experts,
"none",
stream);
} else if (gemm_method_ == "weight_only_int4") {
int4_moe_gemm_runner_->moe_gemm_bias_act(
reinterpret_cast<NvType *>(permuted_data_),
reinterpret_cast<const cutlass::uint4b_t *>(
ffn1_weight->data<int8_t>()),
reinterpret_cast<const NvType *>(ffn1_scale->data<T>()),
reinterpret_cast<const NvType *>(fc1_expert_biases),
reinterpret_cast<NvType *>(fc1_out),
total_rows_before_expert_,
expanded_active_expert_rows,
inter_size,
hidden_size,
num_experts,
"none",
stream);
} else {
fp16_moe_gemm_runner_->moe_gemm_bias_act(
reinterpret_cast<NvType *>(permuted_data_),
reinterpret_cast<const NvType *>(ffn1_weight->data<T>()),
nullptr,
reinterpret_cast<const NvType *>(fc1_expert_biases),
reinterpret_cast<NvType *>(fc1_out),
total_rows_before_expert_,
expanded_active_expert_rows,
inter_size,
hidden_size,
num_experts,
"none",
stream);
}
if (moe_type == "ffn") {
auto act_out_tensor =
paddle::experimental::swiglu(fc1_out_tensor, nullptr);
auto act_out = act_out_tensor.data<T>();
paddle::Tensor fc2_output_tensor =
GetEmptyTensor({k * num_rows, hidden_size}, input_type, place);
T *fc2_result = fc2_output_tensor.data<T>();
if (gemm_method_ == "weight_only_int8") {
int8_moe_gemm_runner_->moe_gemm(
reinterpret_cast<NvType *>(act_out),
reinterpret_cast<const uint8_t *>(ffn2_weight->data<int8_t>()),
reinterpret_cast<const NvType *>(ffn2_scale->data<T>()),
reinterpret_cast<NvType *>(fc2_result),
total_rows_before_expert_,
expanded_active_expert_rows,
hidden_size,
inter_size / 2,
num_experts,
stream);
} else if (gemm_method_ == "weight_only_int4") {
int4_moe_gemm_runner_->moe_gemm(
reinterpret_cast<NvType *>(act_out),
reinterpret_cast<const cutlass::uint4b_t *>(
ffn2_weight->data<int8_t>()),
reinterpret_cast<const NvType *>(ffn2_scale->data<T>()),
reinterpret_cast<NvType *>(fc2_result),
total_rows_before_expert_,
expanded_active_expert_rows,
hidden_size,
inter_size / 2,
num_experts,
stream);
} else {
fp16_moe_gemm_runner_->moe_gemm(
reinterpret_cast<NvType *>(act_out),
reinterpret_cast<const NvType *>(ffn2_weight->data<T>()),
nullptr,
reinterpret_cast<NvType *>(fc2_result),
total_rows_before_expert_,
expanded_active_expert_rows,
hidden_size,
inter_size / 2,
num_experts,
stream);
}
finalize_moe_routing_kernelLauncher(
fc2_result,
output_,
fc2_expert_biases,
reinterpret_cast<float *>(expert_scales_float),
expanded_source_row_to_expanded_dest_row,
expert_for_source_row,
num_rows,
hidden_size,
k,
static_cast<int>(1),
norm_topk_prob,
routed_scaling_factor,
stream);
} else {
finalize_moe_routing_kernelLauncher(
// fc2_result,
fc1_out,
output_,
fc1_expert_biases, // fc2_expert_biases,
reinterpret_cast<float *>(expert_scales_float),
expanded_source_row_to_expanded_dest_row,
expert_for_source_row,
num_rows,
inter_size,
k,
static_cast<int>(0),
norm_topk_prob,
routed_scaling_factor,
stream);
}
}
private:
std::string gemm_method_;
MoeGemmRunner<NvType, NvType> *fp16_moe_gemm_runner_;
MoeGemmRunner<NvType, uint8_t> *int8_moe_gemm_runner_;
MoeGemmRunner<NvType, cutlass::uint4b_t> *int4_moe_gemm_runner_;
int layernum_;
CubKeyValueSorter sorter_;
};

View File

@@ -0,0 +1,123 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION &
* AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <string>
#include <sstream>
#include "cub/cub.cuh"
static const float HALF_FLT_MAX = 65504.F;
static const float HALF_FLT_MIN = -65504.F;
static inline size_t AlignTo16(const size_t& input) {
static constexpr int ALIGNMENT = 16;
return ALIGNMENT * ((input + ALIGNMENT - 1) / ALIGNMENT);
}
class CubKeyValueSorter {
public:
CubKeyValueSorter() : num_experts_(0), num_bits_(sizeof(int) * 8) {}
explicit CubKeyValueSorter(const int num_experts)
: num_experts_(num_experts),
num_bits_(static_cast<int>(log2(num_experts)) + 1) {}
void update_num_experts(const int num_experts) {
num_experts_ = num_experts;
num_bits_ = static_cast<int>(log2(num_experts)) + 1;
}
size_t getWorkspaceSize(const size_t num_key_value_pairs,
bool descending = false) {
num_key_value_pairs_ = num_key_value_pairs;
size_t required_storage = 0;
int* null_int = nullptr;
if (descending) {
cub::DeviceRadixSort::SortPairsDescending(NULL,
required_storage,
null_int,
null_int,
null_int,
null_int,
num_key_value_pairs,
0,
32);
} else {
cub::DeviceRadixSort::SortPairs(NULL,
required_storage,
null_int,
null_int,
null_int,
null_int,
num_key_value_pairs,
0,
num_bits_);
}
return required_storage;
}
template <typename KeyT>
void run(void* workspace,
const size_t workspace_size,
const KeyT* keys_in,
KeyT* keys_out,
const int* values_in,
int* values_out,
const size_t num_key_value_pairs,
bool descending,
cudaStream_t stream) {
size_t expected_ws_size = getWorkspaceSize(num_key_value_pairs);
size_t actual_ws_size = workspace_size;
if (expected_ws_size > workspace_size) {
std::stringstream err_ss;
err_ss << "[Error][CubKeyValueSorter::run]\n";
err_ss << "Error. The allocated workspace is too small to run this "
"problem.\n";
err_ss << "Expected workspace size of at least " << expected_ws_size
<< " but got problem size " << workspace_size << "\n";
throw std::runtime_error(err_ss.str());
}
if (descending) {
cub::DeviceRadixSort::SortPairsDescending(workspace,
actual_ws_size,
keys_in,
keys_out,
values_in,
values_out,
num_key_value_pairs,
0,
32,
stream);
} else {
cub::DeviceRadixSort::SortPairs(workspace,
actual_ws_size,
keys_in,
keys_out,
values_in,
values_out,
num_key_value_pairs,
0,
num_bits_,
stream);
}
}
private:
size_t num_key_value_pairs_;
int num_experts_;
int num_bits_;
};

View File

@@ -0,0 +1,990 @@
// /*
// * SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION &
// * AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// * http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
#pragma once
#include <cuda.h>
#include <cuda_fp16.h>
#include "moe/fused_moe_imp_op.h"
#include "moe/fused_moe_helper.h"
#include "cutlass/numeric_conversion.h"
// Ignore CUTLASS warnings about type punning
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Wunused-function"
// #include "paddle/phi/backends/gpu/gpu_info.h"
#pragma GCC diagnostic pop
#include "helper.h"
#define WARP_SIZE 32
struct GpuLaunchConfig {
dim3 block_per_grid;
dim3 thread_per_block;
};
inline GpuLaunchConfig Get1DBlocksAnd2DGridsMoe(const int64_t cols) {
int blocks_x = cols;
int blocks_y = 1;
int blocks_z = 1;
if (blocks_x > 1024) {
blocks_y = 256;
blocks_x = (blocks_x + blocks_y - 1) / blocks_y;
}
GpuLaunchConfig config;
config.block_per_grid.x = blocks_x;
config.block_per_grid.y = blocks_y;
config.block_per_grid.z = blocks_z;
return config;
}
// ====================== Softmax things ===============================
// We have our own implementation of softmax here so we can support transposing
// the output in the softmax kernel when we extend this module to support
// expert-choice routing.
template <typename T, int TPB>
__launch_bounds__(TPB) __global__
void group_moe_softmax(const T* input,
T* output,
T* softmax_max_prob,
const int64_t num_cols,
const int64_t softmax_num_rows) {
using BlockReduce = cub::BlockReduce<float, TPB>;
__shared__ typename BlockReduce::TempStorage tmpStorage;
__shared__ float normalizing_factor;
__shared__ float float_max;
__shared__ float max_out;
int globalIdx = blockIdx.x + blockIdx.y * gridDim.x;
if (globalIdx >= softmax_num_rows) {
return;
}
const int64_t thread_row_offset = globalIdx * num_cols;
cub::Sum sum;
float threadData(-FLT_MAX);
for (int ii = threadIdx.x; ii < num_cols; ii += TPB) {
const int idx = thread_row_offset + ii;
threadData = max(static_cast<float>(input[idx]), threadData);
}
const float maxElem = BlockReduce(tmpStorage).Reduce(threadData, cub::Max());
if (threadIdx.x == 0) {
float_max = maxElem;
}
__syncthreads();
threadData = 0;
for (int ii = threadIdx.x; ii < num_cols; ii += TPB) {
const int idx = thread_row_offset + ii;
threadData += exp((static_cast<float>(input[idx]) - float_max));
}
const auto Z = BlockReduce(tmpStorage).Reduce(threadData, sum);
if (threadIdx.x == 0) {
normalizing_factor = 1.f / Z;
}
__syncthreads();
threadData = 0;
for (int ii = threadIdx.x; ii < num_cols; ii += TPB) {
const int idx = thread_row_offset + ii;
const float val =
exp((static_cast<float>(input[idx]) - float_max)) * normalizing_factor;
output[idx] = T(val);
threadData = max(static_cast<float>(T(val)), threadData);
}
const float maxOut = BlockReduce(tmpStorage).Reduce(threadData, cub::Max());
if (threadIdx.x == 0) {
// group max probs
max_out = 1.f / maxOut;
softmax_max_prob[globalIdx] = T(max_out);
}
__syncthreads();
for (int ii = threadIdx.x; ii < num_cols; ii += TPB) {
const int idx = thread_row_offset + ii;
// group softmax normalization
output[idx] = output[idx] * static_cast<T>(max_out);
}
}
template <typename T, int TPB>
__launch_bounds__(TPB) __global__ void moe_top_k(const T* inputs_after_softmax,
T* output,
int* indices,
int* source_rows,
T* softmax_max_prob,
const int64_t num_experts,
const int64_t k,
const int64_t num_rows) {
using cub_kvp = cub::KeyValuePair<int, T>;
using BlockReduce = cub::BlockReduce<cub_kvp, TPB>;
__shared__ typename BlockReduce::TempStorage tmpStorage;
cub_kvp thread_kvp;
cub::ArgMax arg_max;
const int block_row = blockIdx.x + blockIdx.y * gridDim.x;
if (block_row >= num_rows) {
return;
}
const bool should_process_row = true;
const int thread_read_offset = block_row * num_experts;
for (int k_idx = 0; k_idx < k; ++k_idx) {
thread_kvp.key = 0;
thread_kvp.value = T(-1.f); // This is OK because inputs are probabilities
cub_kvp inp_kvp;
for (int expert = threadIdx.x; expert < num_experts; expert += TPB) {
const int idx = thread_read_offset + expert;
inp_kvp.key = expert;
inp_kvp.value = inputs_after_softmax[idx];
for (int prior_k = 0; prior_k < k_idx; ++prior_k) {
const int prior_winning_expert = indices[k * block_row + prior_k];
if (prior_winning_expert == expert) {
inp_kvp = thread_kvp;
}
}
thread_kvp = arg_max(inp_kvp, thread_kvp);
}
const cub_kvp result_kvp =
BlockReduce(tmpStorage).Reduce(thread_kvp, arg_max);
if (threadIdx.x == 0) {
const int idx = k * block_row + k_idx;
// restore normalized probes
output[idx] = result_kvp.value / T(softmax_max_prob[idx]);
indices[idx] = should_process_row ? result_kvp.key : num_experts;
source_rows[idx] = k_idx * num_rows + block_row;
}
__syncthreads();
}
}
template <typename T, int TPB>
__launch_bounds__(TPB) __global__ void moe_softmax(const T* input,
T* output,
const int64_t num_cols,
const int64_t num_rows) {
using BlockReduce = cub::BlockReduce<float, TPB>;
__shared__ typename BlockReduce::TempStorage tmpStorage;
__shared__ float normalizing_factor;
__shared__ float float_max;
int globalIdx = blockIdx.x + blockIdx.y * gridDim.x;
if (globalIdx >= num_rows) {
return;
}
const int64_t thread_row_offset = globalIdx * num_cols;
cub::Sum sum;
float threadData(-FLT_MAX);
for (int ii = threadIdx.x; ii < num_cols; ii += TPB) {
const int idx = thread_row_offset + ii;
threadData = max(static_cast<float>(input[idx]), threadData);
}
const float maxElem = BlockReduce(tmpStorage).Reduce(threadData, cub::Max());
if (threadIdx.x == 0) {
float_max = maxElem;
}
__syncthreads();
threadData = 0;
for (int ii = threadIdx.x; ii < num_cols; ii += TPB) {
const int idx = thread_row_offset + ii;
threadData += exp((static_cast<float>(input[idx]) - float_max));
}
const auto Z = BlockReduce(tmpStorage).Reduce(threadData, sum);
if (threadIdx.x == 0) {
normalizing_factor = 1.f / Z;
}
__syncthreads();
for (int ii = threadIdx.x; ii < num_cols; ii += TPB) {
const int idx = thread_row_offset + ii;
const float val =
exp((static_cast<float>(input[idx]) - float_max)) * normalizing_factor;
output[idx] = T(val);
}
}
template <typename T, int TPB>
__launch_bounds__(TPB) __global__ void moe_top_k(const T* inputs_after_softmax,
T* output,
int* indices,
int* source_rows,
const int64_t num_experts,
const int64_t k,
const int64_t num_rows) {
using cub_kvp = cub::KeyValuePair<int, T>;
using BlockReduce = cub::BlockReduce<cub_kvp, TPB>;
__shared__ typename BlockReduce::TempStorage tmpStorage;
cub_kvp thread_kvp;
cub::ArgMax arg_max;
const int block_row = blockIdx.x + blockIdx.y * gridDim.x;
if (block_row >= num_rows) {
return;
}
const bool should_process_row = true;
const int thread_read_offset = block_row * num_experts;
for (int k_idx = 0; k_idx < k; ++k_idx) {
thread_kvp.key = 0;
thread_kvp.value = T(-1.f); // This is OK because inputs are probabilities
cub_kvp inp_kvp;
for (int expert = threadIdx.x; expert < num_experts; expert += TPB) {
const int idx = thread_read_offset + expert;
inp_kvp.key = expert;
inp_kvp.value = inputs_after_softmax[idx];
for (int prior_k = 0; prior_k < k_idx; ++prior_k) {
const int prior_winning_expert = indices[k * block_row + prior_k];
if (prior_winning_expert == expert) {
inp_kvp = thread_kvp;
}
}
thread_kvp = arg_max(inp_kvp, thread_kvp);
}
const cub_kvp result_kvp =
BlockReduce(tmpStorage).Reduce(thread_kvp, arg_max);
if (threadIdx.x == 0) {
const int idx = k * block_row + k_idx;
output[idx] = result_kvp.value;
indices[idx] = should_process_row ? result_kvp.key : num_experts;
source_rows[idx] = k_idx * num_rows + block_row;
}
__syncthreads();
}
}
// ====================== TopK softmax things ===============================
/*
A Top-K gating softmax written to exploit when the number of experts in the
MoE layers are a small power of 2. This allows us to cleanly share the rows
among the threads in a single warp and eliminate communication between warps
(so no need to use shared mem).
It fuses the softmax, max and argmax into a single kernel.
Limitations:
1) This implementation is intended for when the number of experts is a small
power of 2. 2) This implementation assumes k is small, but will work for any
k.
*/
template <typename T,
int VPT,
int NUM_EXPERTS,
int WARPS_PER_CTA,
int BYTES_PER_LDG>
__launch_bounds__(WARPS_PER_CTA* WARP_SIZE) __global__
void topk_gating_softmax(const T* input,
T* output,
const int64_t num_rows,
int* indices,
int* source_rows,
const int64_t k) {
// We begin by enforcing compile time assertions and setting up compile time
// constants.
static_assert(VPT == (VPT & -VPT), "VPT must be power of 2");
static_assert(NUM_EXPERTS == (NUM_EXPERTS & -NUM_EXPERTS),
"NUM_EXPERTS must be power of 2");
static_assert(BYTES_PER_LDG == (BYTES_PER_LDG & -BYTES_PER_LDG),
"BYTES_PER_LDG must be power of 2");
static_assert(BYTES_PER_LDG <= 16, "BYTES_PER_LDG must be leq 16");
// Number of bytes each thread pulls in per load
static constexpr int ELTS_PER_LDG = BYTES_PER_LDG / sizeof(T);
static constexpr int ELTS_PER_ROW = NUM_EXPERTS;
static constexpr int THREADS_PER_ROW = ELTS_PER_ROW / VPT;
static constexpr int LDG_PER_THREAD = VPT / ELTS_PER_LDG;
// Restrictions based on previous section.
static_assert(
VPT % ELTS_PER_LDG == 0,
"The elements per thread must be a multiple of the elements per ldg");
static_assert(WARP_SIZE % THREADS_PER_ROW == 0,
"The threads per row must cleanly divide the threads per warp");
static_assert(THREADS_PER_ROW == (THREADS_PER_ROW & -THREADS_PER_ROW),
"THREADS_PER_ROW must be power of 2");
static_assert(THREADS_PER_ROW <= WARP_SIZE,
"THREADS_PER_ROW can be at most warp size");
// We have NUM_EXPERTS elements per row. We specialize for small #experts
static constexpr int ELTS_PER_WARP = WARP_SIZE * VPT;
static constexpr int ROWS_PER_WARP = ELTS_PER_WARP / ELTS_PER_ROW;
static constexpr int ROWS_PER_CTA = WARPS_PER_CTA * ROWS_PER_WARP;
// Restrictions for previous section.
static_assert(ELTS_PER_WARP % ELTS_PER_ROW == 0,
"The elts per row must cleanly divide the total elt per warp");
// ===================== From this point, we finally start computing run-time
// variables. ========================
// Compute CTA and warp rows. We pack multiple rows into a single warp, and a
// block contains WARPS_PER_CTA warps. This, each block processes a chunk of
// rows. We start by computing the start row for each block.
const int cta_base_row = blockIdx.x * ROWS_PER_CTA;
// Now, using the base row per thread block, we compute the base row per warp.
const int warp_base_row = cta_base_row + threadIdx.y * ROWS_PER_WARP;
// The threads in a warp are split into sub-groups that will work on a row.
// We compute row offset for each thread sub-group
const int thread_row_in_warp = threadIdx.x / THREADS_PER_ROW;
const int thread_row = warp_base_row + thread_row_in_warp;
// Threads with indices out of bounds should early exit here.
if (thread_row >= num_rows) return;
const bool should_process_row = true;
// We finally start setting up the read pointers for each thread. First, each
// thread jumps to the start of the row it will read.
const T* thread_row_ptr = input + thread_row * ELTS_PER_ROW;
// Now, we compute the group each thread belong to in order to determine the
// first column to start loads.
const int thread_group_idx = threadIdx.x % THREADS_PER_ROW;
const int first_elt_read_by_thread = thread_group_idx * ELTS_PER_LDG;
const T* thread_read_ptr = thread_row_ptr + first_elt_read_by_thread;
// Determine the pointer type to use to read in the data depending on the
// BYTES_PER_LDG template param. In theory, this can support all powers of 2
// up to 16.
using AccessType = cutlass::AlignedArray<T, ELTS_PER_LDG>;
// Finally, we pull in the data from global mem
cutlass::Array<T, VPT> row_chunk_input;
AccessType* row_chunk_vec_ptr =
reinterpret_cast<AccessType*>(&row_chunk_input);
const AccessType* vec_thread_read_ptr =
reinterpret_cast<const AccessType*>(thread_read_ptr);
#pragma unroll
for (int ii = 0; ii < LDG_PER_THREAD; ++ii) {
row_chunk_vec_ptr[ii] = vec_thread_read_ptr[ii * THREADS_PER_ROW];
}
using ComputeType = float;
using Converter = cutlass::NumericArrayConverter<ComputeType, T, VPT>;
Converter compute_type_converter;
cutlass::Array<ComputeType, VPT> row_chunk =
compute_type_converter(row_chunk_input);
// First, we perform a max reduce within the thread. We can do the max in fp16
// safely (I think) and just convert to float afterwards for the exp + sum
// reduction.
ComputeType thread_max = row_chunk[0];
#pragma unroll
for (int ii = 1; ii < VPT; ++ii) {
thread_max = max(thread_max, row_chunk[ii]);
}
// Now, we find the max within the thread group and distribute among the
// threads. We use a butterfly reduce.
#pragma unroll
for (int mask = THREADS_PER_ROW / 2; mask > 0; mask /= 2) {
thread_max =
max(thread_max,
__shfl_xor_sync(0xFFFFFFFF, thread_max, mask, THREADS_PER_ROW));
}
// From this point, thread max in all the threads have the max within the row.
// Now, we subtract the max from each element in the thread and take the exp.
// We also compute the thread local sum.
float row_sum = 0;
#pragma unroll
for (int ii = 0; ii < VPT; ++ii) {
row_chunk[ii] = expf(row_chunk[ii] - thread_max);
row_sum += row_chunk[ii];
}
// Now, we perform the sum reduce within each thread group. Similar to the max
// reduce, we use a bufferfly pattern.
#pragma unroll
for (int mask = THREADS_PER_ROW / 2; mask > 0; mask /= 2) {
row_sum += __shfl_xor_sync(0xFFFFFFFF, row_sum, mask, THREADS_PER_ROW);
}
// From this point, all threads have the max and the sum for their rows in the
// thread_max and thread_sum variables respectively. Finally, we can scale the
// rows for the softmax. Technically, for top-k gating we don't need to
// compute the entire softmax row. We can likely look at the maxes and only
// compute for the top-k values in the row. However, this kernel will likely
// not be a bottle neck and it seems better to closer match torch and find the
// argmax after computing the softmax.
const float reciprocal_row_sum = 1.f / row_sum;
#pragma unroll
for (int ii = 0; ii < VPT; ++ii) {
row_chunk[ii] = row_chunk[ii] * reciprocal_row_sum;
}
// Now, softmax_res contains the softmax of the row chunk. Now, I want to find
// the topk elements in each row, along with the max index.​
int start_col = first_elt_read_by_thread;
static constexpr int COLS_PER_GROUP_LDG = ELTS_PER_LDG * THREADS_PER_ROW;
for (int k_idx = 0; k_idx < k; ++k_idx) {
// First, each thread does the local argmax
float max_val = row_chunk[0];
int expert = start_col;
#pragma unroll
for (int ldg = 0, col = start_col; ldg < LDG_PER_THREAD;
++ldg, col += COLS_PER_GROUP_LDG) {
#pragma unroll
for (int ii = 0; ii < ELTS_PER_LDG; ++ii) {
float val = row_chunk[ldg * ELTS_PER_LDG + ii];
// No check on the experts here since columns with the smallest index
// are processed first and only updated if > (not >=)
if (val > max_val) {
max_val = val;
expert = col + ii;
}
}
}
// Now, we perform the argmax reduce. We use the butterfly pattern so threads
// reach consensus about the max. This will be useful for K > 1 so that the
// threads can agree on "who" had the max value. That thread can then blank out
// their max with -inf and the warp can run more iterations...
#pragma unroll
for (int mask = THREADS_PER_ROW / 2; mask > 0; mask /= 2) {
float other_max =
__shfl_xor_sync(0xFFFFFFFF, max_val, mask, THREADS_PER_ROW);
int other_expert =
__shfl_xor_sync(0xFFFFFFFF, expert, mask, THREADS_PER_ROW);
// We want lower indices to "win" in every thread so we break ties this
// way
if (other_max > max_val ||
(other_max == max_val && other_expert < expert)) {
max_val = other_max;
expert = other_expert;
}
}
// Write the max for this k iteration to global memory.
if (thread_group_idx == 0) {
// The lead thread from each sub-group will write out the final results to
// global memory. (This will be a single) thread per row of the
// input/output matrices.
const int idx = k * thread_row + k_idx;
output[idx] = T(max_val);
indices[idx] = should_process_row ? expert : NUM_EXPERTS;
source_rows[idx] = k_idx * num_rows + thread_row;
}
// Finally, we clear the value in the thread with the current max if there
// is another iteration to run.
if (k_idx + 1 < k) {
const int ldg_group_for_expert = expert / COLS_PER_GROUP_LDG;
const int thread_to_clear_in_group =
(expert / ELTS_PER_LDG) % THREADS_PER_ROW;
// Only the thread in the group which produced the max will reset the
// "winning" value to -inf.
if (thread_group_idx == thread_to_clear_in_group) {
const int offset_for_expert = expert % ELTS_PER_LDG;
// Safe to set to any negative value since row_chunk values must be
// between 0 and 1.
row_chunk[ldg_group_for_expert * ELTS_PER_LDG + offset_for_expert] =
ComputeType(-10000.f);
}
}
}
}
namespace detail {
// Constructs some constants needed to partition the work across threads at
// compile time.
template <typename T, int EXPERTS, int BYTES_PER_LDG>
struct TopkConstants {
static constexpr int ELTS_PER_LDG = BYTES_PER_LDG / sizeof(T);
static_assert(EXPERTS / (ELTS_PER_LDG * WARP_SIZE) == 0 ||
EXPERTS % (ELTS_PER_LDG * WARP_SIZE) == 0,
"");
static constexpr int VECs_PER_THREAD =
std::max(1, EXPERTS / (ELTS_PER_LDG * WARP_SIZE));
static constexpr int VPT = VECs_PER_THREAD * ELTS_PER_LDG;
static constexpr int THREADS_PER_ROW = EXPERTS / VPT;
static constexpr int ROWS_PER_WARP = WARP_SIZE / THREADS_PER_ROW;
};
} // namespace detail
template <typename T, int EXPERTS, int WARPS_PER_TB>
void topk_gating_softmax_launcher_helper(const T* input,
T* output,
int* indices,
int* source_row,
const int64_t num_rows,
const int64_t num_experts,
const int64_t k,
cudaStream_t stream) {
static constexpr uint64_t MAX_BYTES_PER_LDG = 16;
static constexpr int BYTES_PER_LDG =
std::min(MAX_BYTES_PER_LDG, sizeof(T) * EXPERTS);
using Constants = detail::TopkConstants<T, EXPERTS, BYTES_PER_LDG>;
static constexpr int VPT = Constants::VPT;
static constexpr int ROWS_PER_WARP = Constants::ROWS_PER_WARP;
const int num_warps = (num_rows + ROWS_PER_WARP - 1) / ROWS_PER_WARP;
const int num_blocks = (num_warps + WARPS_PER_TB - 1) / WARPS_PER_TB;
dim3 block_dim(WARP_SIZE, WARPS_PER_TB);
topk_gating_softmax<T, VPT, EXPERTS, WARPS_PER_TB, BYTES_PER_LDG>
<<<num_blocks, block_dim, 0, stream>>>(
input, output, num_rows, indices, source_row, k);
}
template <typename T>
void topk_gating_softmax_kernelLauncher(const T* input,
T* output,
T* softmax,
int* indices,
int* source_row,
T* softmax_max_prob,
const int64_t num_rows,
const int64_t num_experts,
const int64_t k,
const bool group_moe,
cudaStream_t stream,
const bool topk_only_mode = false) {
if (topk_only_mode) {
static constexpr int TPB = 256;
const auto config_topk = Get1DBlocksAnd2DGridsMoe(num_rows);
moe_top_k<T, TPB><<<config_topk.block_per_grid, TPB, 0, stream>>>(
input, output, indices, source_row, num_experts, k, num_rows);
return;
}
static constexpr int WARPS_PER_TB = 4;
#define LAUNCH_TOPK_GATING_SOFTMAX_HELPER(N) \
case N: { \
topk_gating_softmax_launcher_helper<T, N, WARPS_PER_TB>( \
input, output, indices, source_row, num_rows, num_experts, k, stream); \
break; \
}
switch (num_experts) {
LAUNCH_TOPK_GATING_SOFTMAX_HELPER(2)
LAUNCH_TOPK_GATING_SOFTMAX_HELPER(4)
LAUNCH_TOPK_GATING_SOFTMAX_HELPER(8)
LAUNCH_TOPK_GATING_SOFTMAX_HELPER(16)
LAUNCH_TOPK_GATING_SOFTMAX_HELPER(32)
LAUNCH_TOPK_GATING_SOFTMAX_HELPER(64)
LAUNCH_TOPK_GATING_SOFTMAX_HELPER(128)
LAUNCH_TOPK_GATING_SOFTMAX_HELPER(256)
default: {
static constexpr int TPB = 256;
if (group_moe) {
const int group_experts = num_experts / k;
const int softmax_num_rows = num_rows * k;
const auto config_softmax = Get1DBlocksAnd2DGridsMoe(softmax_num_rows);
group_moe_softmax<T, TPB>
<<<config_softmax.block_per_grid, TPB, 0, stream>>>(
input,
softmax,
softmax_max_prob,
group_experts,
softmax_num_rows);
const auto config_topk = Get1DBlocksAnd2DGridsMoe(num_rows);
moe_top_k<T, TPB>
<<<config_topk.block_per_grid, TPB, 0, stream>>>(softmax,
output,
indices,
source_row,
softmax_max_prob,
num_experts,
k,
num_rows);
} else {
const auto config_topk = Get1DBlocksAnd2DGridsMoe(num_rows);
moe_softmax<T, TPB><<<config_topk.block_per_grid, TPB, 0, stream>>>(
input, softmax, num_experts, num_rows);
moe_top_k<T, TPB>
<<<config_topk.block_per_grid, TPB, 0, stream>>>(softmax,
output,
indices,
source_row,
num_experts,
k,
num_rows);
}
}
}
}
// ========================== Permutation things
// =======================================
// Duplicated and permutes rows for MoE. In addition, reverse the permutation
// map to help with finalizing routing.
// "expanded_x_row" simply means that the number of values is num_rows x k. It
// is "expanded" since we will have to duplicate some rows in the input matrix
// to match the dimensions. Duplicates will always get routed to separate
// experts in the end.
// Note that the expanded_dest_row_to_expanded_source_row map referred to here
// has indices in the range (0, k*rows_in_input - 1). However, it is set up so
// that index 0, rows_in_input, 2*rows_in_input ... (k-1)*rows_in_input all map
// to row 0 in the original matrix. Thus, to know where to read in the source
// matrix, we simply take the modulus of the expanded index.
template <typename T, int VecSize>
__global__ void initialize_moe_routing_kernel(
const T* unpermuted_input,
T* permuted_output,
const int* expanded_dest_row_to_expanded_source_row,
int* expanded_source_row_to_expanded_dest_row,
const int64_t num_rows,
const int64_t active_rows,
const int64_t cols,
const int64_t num_rows_k) {
using LoadT = AlignedVector<T, VecSize>;
LoadT src_vec;
// Reverse permutation map.
// I do this so that later, we can use the source -> dest map to do the k-way
// reduction and unpermuting. I need the reverse map for that reduction to
// allow each threadblock to do 1 k-way reduce without atomics later in MoE. 1
// thread block will be responsible for all k summations.
const int expanded_dest_row = blockIdx.x + blockIdx.y * gridDim.x;
if (expanded_dest_row >= num_rows_k) return;
const int expanded_source_row =
expanded_dest_row_to_expanded_source_row[expanded_dest_row];
if (threadIdx.x == 0) {
expanded_source_row_to_expanded_dest_row[expanded_source_row] =
expanded_dest_row;
}
if ((blockIdx.x + blockIdx.y * gridDim.x) < active_rows) {
// Duplicate and permute rows
const int source_row = expanded_source_row % num_rows;
const T* source_row_ptr = unpermuted_input + source_row * cols;
T* dest_row_ptr = permuted_output + expanded_dest_row * cols;
for (int tid = threadIdx.x * VecSize; tid < cols;
tid += blockDim.x * VecSize) {
// dest_row_ptr[tid] = source_row_ptr[tid];
Load<T, VecSize>(&source_row_ptr[tid], &src_vec);
Store<T, VecSize>(src_vec, &dest_row_ptr[tid]);
}
}
}
template <typename T>
void initialize_moe_routing_kernelLauncher(
const T* unpermuted_input,
T* permuted_output,
const int* expanded_dest_row_to_expanded_source_row,
int* expanded_source_row_to_expanded_dest_row,
const int64_t num_rows,
const int64_t active_rows,
const int64_t cols,
const int64_t k,
cudaStream_t stream) {
const int threads = std::min(cols, int64_t(1024));
constexpr int max_pack_size = 16 / sizeof(T);
const auto config_initialize = Get1DBlocksAnd2DGridsMoe(num_rows * k);
if (cols % max_pack_size == 0) {
initialize_moe_routing_kernel<T, max_pack_size>
<<<config_initialize.block_per_grid, threads, 0, stream>>>(
unpermuted_input,
permuted_output,
expanded_dest_row_to_expanded_source_row,
expanded_source_row_to_expanded_dest_row,
num_rows,
k * active_rows,
cols,
num_rows * k);
} else {
initialize_moe_routing_kernel<T, 1>
<<<config_initialize.block_per_grid, threads, 0, stream>>>(
unpermuted_input,
permuted_output,
expanded_dest_row_to_expanded_source_row,
expanded_source_row_to_expanded_dest_row,
num_rows,
k * active_rows,
cols,
num_rows * k);
}
}
// ============================== Infer GEMM sizes
// =================================
__device__ inline int find_total_elts_leq_target(int* sorted_indices,
const int64_t arr_length,
const int64_t target) {
int64_t low = 0, high = arr_length - 1, target_location = -1;
while (low <= high) {
int64_t mid = (low + high) / 2;
if (sorted_indices[mid] > target) {
high = mid - 1;
} else {
low = mid + 1;
target_location = mid;
}
}
return target_location + 1;
}
void compute_total_rows_before_expert(int* sorted_indices,
const int64_t total_indices,
const int64_t num_experts,
int64_t* total_rows_before_expert,
cudaStream_t stream);
// Final kernel to unpermute and scale
// This kernel unpermutes the original data, does the k-way reduction and
// performs the final skip connection.
template <typename T, int RESIDUAL_NUM>
__global__ void finalize_moe_routing_kernel(
const T* expanded_permuted_rows,
T* reduced_unpermuted_output,
const T* bias,
const float* scales,
const int* expanded_source_row_to_expanded_dest_row,
const int* expert_for_source_row,
const int64_t cols,
const int64_t k,
const int64_t compute_bias,
const bool norm_topk_prob,
const float routed_scaling_factor,
const int64_t num_rows) {
const int original_row = blockIdx.x + blockIdx.y * gridDim.x;
// const int original_row = blockIdx.x;
// const int num_rows = gridDim.x;
if (original_row >= num_rows) return;
T* reduced_row_ptr = reduced_unpermuted_output + original_row * cols;
for (int tid = threadIdx.x; tid < cols; tid += blockDim.x) {
T thread_output{0.f};
float row_rescale{0.f};
for (int k_idx = 0; k_idx < k; ++k_idx) {
const int expanded_original_row = original_row + k_idx * num_rows;
const int expanded_permuted_row =
expanded_source_row_to_expanded_dest_row[expanded_original_row];
const int64_t k_offset = original_row * k + k_idx;
const float row_scale = scales[k_offset];
row_rescale = row_rescale + row_scale;
const T* expanded_permuted_rows_row_ptr =
expanded_permuted_rows + expanded_permuted_row * cols;
const int expert_idx = expert_for_source_row[k_offset];
const T* bias_ptr = bias ? bias + expert_idx * cols : nullptr;
const T bias_value = bias_ptr ? bias_ptr[tid] : T{0.f};
thread_output =
static_cast<float>(thread_output) +
row_scale * static_cast<float>(
expanded_permuted_rows_row_ptr[tid] +
bias_value *
static_cast<T>(static_cast<float>(compute_bias)));
}
thread_output = static_cast<float>(thread_output) /
(norm_topk_prob ? row_rescale : 1.0f) *
routed_scaling_factor;
reduced_row_ptr[tid] = thread_output;
}
}
template <typename T>
void finalize_moe_routing_kernelLauncher(
const T* expanded_permuted_rows,
T* reduced_unpermuted_output,
const T* bias,
const float* scales,
const int* expanded_source_row_to_expanded_dest_row,
const int* expert_for_source_row,
const int64_t num_rows,
const int64_t cols,
const int64_t k,
const int64_t compute_bias,
const bool norm_topk_prob,
const float routed_scaling_factor,
cudaStream_t stream) {
const int threads = std::min(cols, int64_t(1024));
const auto config_final = Get1DBlocksAnd2DGridsMoe(num_rows);
finalize_moe_routing_kernel<T, 1>
<<<config_final.block_per_grid, threads, 0, stream>>>(
expanded_permuted_rows,
reduced_unpermuted_output,
bias,
scales,
expanded_source_row_to_expanded_dest_row,
expert_for_source_row,
cols,
k,
compute_bias,
norm_topk_prob,
routed_scaling_factor,
num_rows);
}
// ========================= TopK Softmax specializations
// ===========================
template void topk_gating_softmax_kernelLauncher(const float*,
float*,
float*,
int*,
int*,
float*,
const int64_t,
const int64_t,
const int64_t,
const bool,
cudaStream_t,
const bool);
template void topk_gating_softmax_kernelLauncher(const half*,
half*,
half*,
int*,
int*,
half*,
const int64_t,
const int64_t,
const int64_t,
const bool,
cudaStream_t,
const bool);
#ifdef PADDLE_CUDA_BF16
template void topk_gating_softmax_kernelLauncher(const __nv_bfloat16*,
__nv_bfloat16*,
__nv_bfloat16*,
int*,
int*,
__nv_bfloat16*,
const int64_t,
const int64_t,
const int64_t,
const bool,
cudaStream_t,
const bool);
#endif
// ===================== Specializations for init routing
// =========================
template void initialize_moe_routing_kernelLauncher(const float*,
float*,
const int*,
int*,
const int64_t,
const int64_t,
const int64_t,
const int64_t,
cudaStream_t);
template void initialize_moe_routing_kernelLauncher(const half*,
half*,
const int*,
int*,
const int64_t,
const int64_t,
const int64_t,
const int64_t,
cudaStream_t);
#ifdef PADDLE_CUDA_BF16
template void initialize_moe_routing_kernelLauncher(const __nv_bfloat16*,
__nv_bfloat16*,
const int*,
int*,
const int64_t,
const int64_t,
const int64_t,
const int64_t,
cudaStream_t);
#endif
// ==================== Specializations for final routing
// ===================================
template void finalize_moe_routing_kernelLauncher(const float*,
float*,
const float*,
const float*,
const int*,
const int*,
const int64_t,
const int64_t,
const int64_t,
const int64_t,
const bool,
const float,
cudaStream_t);
template void finalize_moe_routing_kernelLauncher(const half*,
half*,
const half*,
const float*,
const int*,
const int*,
const int64_t,
const int64_t,
const int64_t,
const int64_t,
const bool,
const float,
cudaStream_t);
#ifdef PADDLE_CUDA_BF16
template void finalize_moe_routing_kernelLauncher(const __nv_bfloat16*,
__nv_bfloat16*,
const __nv_bfloat16*,
const float*,
const int*,
const int*,
const int64_t,
const int64_t,
const int64_t,
const int64_t,
const bool,
const float,
cudaStream_t);
#endif

View File

@@ -0,0 +1,276 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Ignore CUTLASS warnings about type punning
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma once
#include "moe/fused_moe_helper.h"
#include "moe/fused_moe_op.h"
#pragma GCC diagnostic pop
#include "helper.h"
template <paddle::DataType T>
void MoeDispatchKernel(const paddle::Tensor& input,
const paddle::Tensor& gating_output,
const int moe_topk,
const bool group_moe,
const bool topk_only_mode,
const int num_rows,
const int hidden_size,
const int expert_num,
paddle::Tensor* permute_input,
paddle::Tensor* tokens_expert_prefix_sum,
paddle::Tensor* permute_indices_per_token,
paddle::Tensor* top_k_weight,
paddle::Tensor* top_k_indices) {
typedef PDTraits<T> traits_;
typedef typename traits_::DataType DataType_;
typedef typename traits_::data_t data_t;
auto stream = input.stream();
auto place = input.place();
if (group_moe) {
// Check if expert_num is divisible by moe_topk, else throw an error
PADDLE_ENFORCE_EQ(expert_num % moe_topk,
0,
common::errors::InvalidArgument(
"The number of experts (expert_num) "
"must be divisible by moe_topk. "
"Got expert_num = %d and moe_topk = %d.",
expert_num,
moe_topk));
}
const int num_moe_inputs = AlignTo16(num_rows * moe_topk);
const int bytes = num_moe_inputs * sizeof(int);
CubKeyValueSorter sorter_;
sorter_.update_num_experts(expert_num);
const int sorter_ws_size_bytes =
AlignTo16(sorter_.getWorkspaceSize(moe_topk * num_rows));
const int sort_tmp_in_out_size = num_moe_inputs * 2 * sizeof(int);
paddle::Tensor ws_ptr_tensor =
GetEmptyTensor({bytes + sorter_ws_size_bytes + sort_tmp_in_out_size},
paddle::DataType::INT8,
place);
int8_t* ws_ptr = ws_ptr_tensor.data<int8_t>();
int* source_rows_ = reinterpret_cast<int*>(ws_ptr);
int8_t* sorter_ws_ptr = reinterpret_cast<int8_t*>(ws_ptr + bytes);
int* permuted_experts_ =
reinterpret_cast<int*>(sorter_ws_ptr + sorter_ws_size_bytes);
int* permuted_rows_ = permuted_experts_ + num_moe_inputs;
int* expert_for_source_row = top_k_indices->data<int>();
float* softmax_max_prob = nullptr;
if (group_moe) {
paddle::Tensor softmax_max_prob_tensor =
GetEmptyTensor({num_rows, moe_topk}, paddle::DataType::FLOAT32, place);
// (TODO: check fill success ?)
paddle::experimental::fill(softmax_max_prob_tensor, 0.f);
softmax_max_prob = softmax_max_prob_tensor.data<float>();
}
float* softmax_out_;
const bool is_pow_2 =
(expert_num != 0) && ((expert_num & (expert_num - 1)) == 0);
paddle::Tensor softmax_buffer;
if (!is_pow_2 || expert_num > 256 || group_moe) {
softmax_buffer = GetEmptyTensor(
{num_rows * expert_num}, paddle::DataType::FLOAT32, place);
softmax_out_ = softmax_buffer.data<float>();
} else {
softmax_out_ = nullptr;
}
topk_gating_softmax_kernelLauncher<float>(gating_output.data<float>(),
top_k_weight->data<float>(),
softmax_out_,
expert_for_source_row,
source_rows_,
softmax_max_prob,
num_rows,
expert_num,
moe_topk,
group_moe,
stream,
topk_only_mode);
sorter_.run(reinterpret_cast<void*>(sorter_ws_ptr),
sorter_ws_size_bytes,
expert_for_source_row,
permuted_experts_,
source_rows_,
permuted_rows_,
moe_topk * num_rows,
false,
stream);
initialize_moe_routing_kernelLauncher(
input.data<data_t>(),
permute_input->data<data_t>(),
permuted_rows_,
permute_indices_per_token->data<int32_t>(),
num_rows,
num_rows,
hidden_size,
moe_topk,
stream);
compute_total_rows_before_expert(
permuted_experts_,
moe_topk * num_rows,
expert_num,
tokens_expert_prefix_sum->data<int64_t>(),
stream);
}
std::vector<paddle::Tensor> MoeExpertDispatch(
const paddle::Tensor& input,
const paddle::Tensor& gating_output,
const int moe_topk,
const bool group_moe,
const bool topk_only_mode) {
const auto input_type = input.dtype();
auto place = input.place();
int token_rows = 0;
auto input_dims = input.dims();
auto gating_dims = gating_output.dims();
const int expert_num = gating_dims[gating_dims.size() - 1];
if (input_dims.size() == 3) {
token_rows = input_dims[0] * input_dims[1];
} else {
token_rows = input_dims[0];
}
const int num_rows = token_rows;
const int hidden_size = input.dims()[input_dims.size() - 1];
auto permute_input =
GetEmptyTensor({moe_topk * num_rows, hidden_size}, input_type, place);
// correspond to the weighted coefficients of the results from each expert.
auto top_k_weight =
GetEmptyTensor({num_rows, moe_topk}, paddle::DataType::FLOAT32, place);
auto top_k_indices =
GetEmptyTensor({num_rows, moe_topk}, paddle::DataType::INT32, place);
auto tokens_expert_prefix_sum =
GetEmptyTensor({expert_num}, paddle::DataType::INT64, place);
auto permute_indices_per_token =
GetEmptyTensor({moe_topk, num_rows}, paddle::DataType::INT32, place);
switch (input_type) {
case paddle::DataType::BFLOAT16:
MoeDispatchKernel<paddle::DataType::BFLOAT16>(input,
gating_output,
moe_topk,
group_moe,
topk_only_mode,
num_rows,
hidden_size,
expert_num,
&permute_input,
&tokens_expert_prefix_sum,
&permute_indices_per_token,
&top_k_weight,
&top_k_indices);
break;
case paddle::DataType::FLOAT16:
MoeDispatchKernel<paddle::DataType::FLOAT16>(input,
gating_output,
moe_topk,
group_moe,
topk_only_mode,
num_rows,
hidden_size,
expert_num,
&permute_input,
&tokens_expert_prefix_sum,
&permute_indices_per_token,
&top_k_weight,
&top_k_indices);
break;
default:
PD_THROW("Unsupported data type for MoeDispatchKernel");
}
return {permute_input,
tokens_expert_prefix_sum,
permute_indices_per_token,
top_k_weight,
top_k_indices};
}
std::vector<std::vector<int64_t>> MoeExpertDispatchInferShape(
const std::vector<int64_t>& input_shape,
const std::vector<int64_t>& gating_output_shape,
const int moe_topk) {
int token_rows = -1;
if (input_shape.size() == 3) {
token_rows = input_shape[0] * input_shape[1];
} else {
token_rows = input_shape[0];
}
const int expert_num = gating_output_shape[gating_output_shape.size() - 1];
const int num_rows = token_rows;
const int hidden_size = input_shape[input_shape.size() - 1];
return {{moe_topk * num_rows, hidden_size},
{expert_num},
{moe_topk, num_rows},
{num_rows, moe_topk},
{num_rows, moe_topk}};
}
std::vector<paddle::DataType> MoeExpertDispatchInferDtype(
const paddle::DataType& input_dtype,
const paddle::DataType& gating_output_dtype,
const int moe_topk) {
return {input_dtype,
paddle::DataType::INT64,
paddle::DataType::INT32,
paddle::DataType::FLOAT32,
paddle::DataType::INT32};
}
PD_BUILD_OP(moe_expert_dispatch)
.Inputs({"input", "gating_output"})
.Outputs({"permute_input",
"tokens_expert_prefix_sum",
"permute_indices_per_token",
"top_k_weight",
"top_k_indices"})
.Attrs({"moe_topk:int", "group_moe:bool", "topk_only_mode:bool"})
.SetKernelFn(PD_KERNEL(MoeExpertDispatch))
.SetInferShapeFn(PD_INFER_SHAPE(MoeExpertDispatchInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(MoeExpertDispatchInferDtype));

View File

@@ -0,0 +1,232 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "cutlass/numeric_conversion.h"
#include "helper.h"
#include "moe/fused_moe_helper.h"
template <paddle::DataType T>
void MoeFFNKernel(const paddle::Tensor& permute_input,
const paddle::Tensor& tokens_expert_prefix_sum,
const paddle::Tensor& ffn1_weight,
const paddle::Tensor& ffn2_weight,
const paddle::optional<paddle::Tensor>& ffn1_bias,
const paddle::optional<paddle::Tensor>& ffn1_scale,
const paddle::optional<paddle::Tensor>& ffn2_scale,
const std::string& quant_method,
paddle::Tensor ffn_out) {
typedef PDTraits<T> traits_;
typedef typename traits_::DataType DataType_;
typedef typename traits_::data_t data_t;
auto ffn_out_data = ffn_out.data<data_t>();
auto permuted_data = permute_input.data<data_t>();
auto place = permute_input.place();
auto input_type = permute_input.dtype();
auto stream = permute_input.stream();
auto fp16_moe_gemm_runner = MoeGemmRunner<DataType_, DataType_>();
auto int8_moe_gemm_runner = MoeGemmRunner<DataType_, uint8_t>();
auto int4_moe_gemm_runner = MoeGemmRunner<DataType_, cutlass::uint4b_t>();
const int64_t expanded_active_expert_rows = permute_input.dims()[0];
const int num_experts = ffn1_weight.dims()[0];
const int hidden_size = ffn1_weight.dims()[1];
int inter_dim = ffn1_weight.dims()[2];
if (quant_method == "weight_only_int4") {
inter_dim = inter_dim * 2;
}
const int64_t inter_size = inter_dim;
paddle::Tensor fc1_out_tensor = GetEmptyTensor(
{expanded_active_expert_rows, inter_size}, input_type, place);
auto fc1_out = fc1_out_tensor.data<data_t>();
using NvType = typename traits_::DataType;
auto fc1_expert_biases =
ffn1_bias
? const_cast<paddle::Tensor*>(ffn1_bias.get_ptr())->data<data_t>()
: nullptr;
if (quant_method == "weight_only_int8") {
int8_moe_gemm_runner.moe_gemm_bias_act(
reinterpret_cast<const NvType*>(permuted_data),
reinterpret_cast<const uint8_t*>(ffn1_weight.data<int8_t>()),
reinterpret_cast<const NvType*>(
const_cast<paddle::Tensor*>(ffn1_scale.get_ptr())->data<data_t>()),
reinterpret_cast<const NvType*>(fc1_expert_biases),
reinterpret_cast<NvType*>(fc1_out),
const_cast<int64_t*>(tokens_expert_prefix_sum.data<int64_t>()),
expanded_active_expert_rows,
inter_size,
hidden_size,
num_experts,
"none",
stream);
} else if (quant_method == "weight_only_int4") {
int4_moe_gemm_runner.moe_gemm_bias_act(
reinterpret_cast<const NvType*>(permuted_data),
reinterpret_cast<const cutlass::uint4b_t*>(ffn1_weight.data<int8_t>()),
reinterpret_cast<const NvType*>(
const_cast<paddle::Tensor*>(ffn1_scale.get_ptr())->data<data_t>()),
reinterpret_cast<const NvType*>(fc1_expert_biases),
reinterpret_cast<NvType*>(fc1_out),
const_cast<int64_t*>(tokens_expert_prefix_sum.data<int64_t>()),
expanded_active_expert_rows,
inter_size,
hidden_size,
num_experts,
"none",
stream);
} else {
fp16_moe_gemm_runner.moe_gemm_bias_act(
reinterpret_cast<const NvType*>(permuted_data),
reinterpret_cast<const NvType*>(ffn1_weight.data<data_t>()),
nullptr,
reinterpret_cast<const NvType*>(fc1_expert_biases),
reinterpret_cast<NvType*>(fc1_out),
const_cast<int64_t*>(tokens_expert_prefix_sum.data<int64_t>()),
expanded_active_expert_rows,
inter_size,
hidden_size,
num_experts,
"none",
stream);
}
auto act_out_tensor = paddle::experimental::swiglu(fc1_out_tensor, nullptr);
auto act_out = act_out_tensor.data<data_t>();
if (quant_method == "weight_only_int8") {
int8_moe_gemm_runner.moe_gemm(
reinterpret_cast<const NvType*>(act_out),
reinterpret_cast<const uint8_t*>(ffn2_weight.data<int8_t>()),
reinterpret_cast<const NvType*>(
const_cast<paddle::Tensor*>(ffn2_scale.get_ptr())->data<data_t>()),
reinterpret_cast<NvType*>(ffn_out_data),
const_cast<int64_t*>(tokens_expert_prefix_sum.data<int64_t>()),
expanded_active_expert_rows,
hidden_size,
inter_size / 2,
num_experts,
stream);
} else if (quant_method == "weight_only_int4") {
int4_moe_gemm_runner.moe_gemm(
reinterpret_cast<const NvType*>(act_out),
reinterpret_cast<const cutlass::uint4b_t*>(ffn2_weight.data<int8_t>()),
reinterpret_cast<const NvType*>(
const_cast<paddle::Tensor*>(ffn2_scale.get_ptr())->data<data_t>()),
reinterpret_cast<NvType*>(ffn_out_data),
const_cast<int64_t*>(tokens_expert_prefix_sum.data<int64_t>()),
expanded_active_expert_rows,
hidden_size,
inter_size / 2,
num_experts,
stream);
} else {
fp16_moe_gemm_runner.moe_gemm(
reinterpret_cast<const NvType*>(act_out),
reinterpret_cast<const NvType*>(ffn2_weight.data<data_t>()),
nullptr,
reinterpret_cast<NvType*>(ffn_out_data),
const_cast<int64_t*>(tokens_expert_prefix_sum.data<int64_t>()),
expanded_active_expert_rows,
hidden_size,
inter_size / 2,
num_experts,
stream);
}
}
std::vector<paddle::Tensor> MoeExpertFFN(
const paddle::Tensor& permute_input,
const paddle::Tensor& tokens_expert_prefix_sum,
const paddle::Tensor& ffn1_weight,
const paddle::Tensor& ffn2_weight,
const paddle::optional<paddle::Tensor>& ffn1_bias,
const paddle::optional<paddle::Tensor>& ffn1_scale,
const paddle::optional<paddle::Tensor>& ffn2_scale,
const std::string& quant_method) {
const auto input_type = permute_input.dtype();
auto ffn_out = paddle::empty_like(permute_input);
switch (input_type) {
case paddle::DataType::BFLOAT16:
MoeFFNKernel<paddle::DataType::BFLOAT16>(permute_input,
tokens_expert_prefix_sum,
ffn1_weight,
ffn2_weight,
ffn1_bias,
ffn1_scale,
ffn2_scale,
quant_method,
ffn_out);
break;
case paddle::DataType::FLOAT16:
MoeFFNKernel<paddle::DataType::FLOAT16>(permute_input,
tokens_expert_prefix_sum,
ffn1_weight,
ffn2_weight,
ffn1_bias,
ffn1_scale,
ffn2_scale,
quant_method,
ffn_out);
break;
default:
PD_THROW("Unsupported data type for MoeExpertFFN");
}
return {ffn_out};
}
std::vector<std::vector<int64_t>> MoeExpertFFNInferShape(
const std::vector<int64_t>& permute_input_shape,
const std::vector<int64_t>& tokens_expert_prefix_sum_shape,
const std::vector<int64_t>& ffn1_weight_shape,
const std::vector<int64_t>& ffn2_weight_shape,
const paddle::optional<std::vector<int64_t>>& ffn1_bias_shape,
const paddle::optional<std::vector<int64_t>>& ffn1_scale_shape,
const paddle::optional<std::vector<int64_t>>& ffn2_scale_shape) {
return {permute_input_shape};
}
std::vector<paddle::DataType> MoeExpertFFNInferDtype(
const paddle::DataType& permute_input_dtype,
const paddle::DataType& tokens_expert_prefix_sum_dtype,
const paddle::DataType& ffn1_weight_dtype,
const paddle::DataType& ffn2_weight_dtype,
const paddle::optional<paddle::DataType>& ffn1_bias_dtype,
const paddle::optional<paddle::DataType>& ffn1_scale_dtype,
const paddle::optional<paddle::DataType>& ffn2_scale_dtype) {
return {permute_input_dtype};
}
PD_BUILD_OP(moe_expert_ffn)
.Inputs({"permute_input",
"tokens_expert_prefix_sum",
"ffn1_weight",
"ffn2_weight",
paddle::Optional("ffn1_bias"),
paddle::Optional("ffn1_scale"),
paddle::Optional("ffn2_scale")})
.Outputs({"output_tensor"})
.Attrs({"quant_method:std::string"})
.SetKernelFn(PD_KERNEL(MoeExpertFFN))
.SetInferShapeFn(PD_INFER_SHAPE(MoeExpertFFNInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(MoeExpertFFNInferDtype));

View File

@@ -0,0 +1,146 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Ignore CUTLASS warnings about type punning
#pragma once
#include "helper.h"
#include "moe/fused_moe_helper.h"
#include "moe/fused_moe_op.h"
template <paddle::DataType T>
void MoeReduceKernel(const paddle::Tensor& ffn_out,
const paddle::Tensor& top_k_weight,
const paddle::Tensor& permute_indices_per_token,
const paddle::Tensor& top_k_indices,
const paddle::optional<paddle::Tensor>& ffn2_bias,
const bool norm_topk_prob,
const float routed_scaling_factor,
const int num_rows,
const int hidden_size,
const int topk,
paddle::Tensor* output) {
typedef PDTraits<T> traits_;
typedef typename traits_::DataType DataType_;
typedef typename traits_::data_t data_t;
auto stream = ffn_out.stream();
finalize_moe_routing_kernelLauncher(
ffn_out.data<data_t>(),
output->data<data_t>(),
ffn2_bias ? ffn2_bias->data<data_t>() : nullptr,
top_k_weight.data<float>(),
permute_indices_per_token.data<int32_t>(),
top_k_indices.data<int>(),
num_rows,
hidden_size,
topk,
static_cast<int>(1),
norm_topk_prob,
routed_scaling_factor,
stream);
}
std::vector<paddle::Tensor> MoeExpertReduce(
const paddle::Tensor& ffn_out,
const paddle::Tensor& top_k_weight,
const paddle::Tensor& permute_indices_per_token,
const paddle::Tensor& top_k_indices,
const paddle::optional<paddle::Tensor>& ffn2_bias,
const bool norm_topk_prob,
const float routed_scaling_factor) {
const auto input_type = ffn_out.dtype();
auto place = ffn_out.place();
const int topk = top_k_indices.dims()[1];
const int num_rows = ffn_out.dims()[0] / topk;
const int hidden_size = ffn_out.dims()[1];
auto output = GetEmptyTensor({num_rows, hidden_size}, input_type, place);
// Avoids ‘invalid configuration argument’ when we launch the kernel.
if (ffn_out.dims()[0] == 0) return {output};
switch (input_type) {
case paddle::DataType::BFLOAT16:
MoeReduceKernel<paddle::DataType::BFLOAT16>(ffn_out,
top_k_weight,
permute_indices_per_token,
top_k_indices,
ffn2_bias,
norm_topk_prob,
routed_scaling_factor,
num_rows,
hidden_size,
topk,
&output);
break;
case paddle::DataType::FLOAT16:
MoeReduceKernel<paddle::DataType::BFLOAT16>(ffn_out,
top_k_weight,
permute_indices_per_token,
top_k_indices,
ffn2_bias,
norm_topk_prob,
routed_scaling_factor,
num_rows,
hidden_size,
topk,
&output);
break;
default:
PD_THROW("Unsupported data type for MoeDispatchKernel");
}
return {output};
}
std::vector<std::vector<int64_t>> MoeExpertReduceInferShape(
const std::vector<int64_t>& ffn_out_shape,
const std::vector<int64_t>& top_k_weight_shape,
const std::vector<int64_t>& permute_indices_per_token_shape,
const std::vector<int64_t>& top_k_indices_shape,
const paddle::optional<std::vector<int64_t>>& ffn2_bias_shape) {
const int topk = top_k_indices_shape[1];
std::vector<int64_t> fused_moe_out_shape = {ffn_out_shape[0] / topk,
ffn_out_shape[1]};
return {fused_moe_out_shape};
}
std::vector<paddle::DataType> MoeExpertReduceInferDtype(
const paddle::DataType& ffn_out_dtype,
const paddle::DataType& top_k_weight_dtype,
const paddle::DataType& permute_indices_per_token_dtype,
const paddle::DataType& top_k_indices_dtype,
const paddle::optional<paddle::DataType>& ffn2_bias_dtype) {
return {ffn_out_dtype};
}
PD_BUILD_OP(moe_expert_reduce)
.Inputs({"ffn_out",
"top_k_weight",
"permute_indices_per_token",
"top_k_indices",
paddle::Optional("ffn2_bias")})
.Outputs({"output"})
.Attrs({"norm_topk_prob:bool", "routed_scaling_factor:float"})
.SetKernelFn(PD_KERNEL(MoeExpertReduce))
.SetInferShapeFn(PD_INFER_SHAPE(MoeExpertReduceInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(MoeExpertReduceInferDtype));

View File

@@ -140,12 +140,14 @@ std::vector<paddle::Tensor> preprocess_for_moe_kernel(const paddle::Tensor& topk
if (num_experts == 8) {
run_align_kernel(8);
} else if (num_experts == 64) {
run_align_kernel(64);
} else if (num_experts == 256) {
run_align_kernel(256);
} else if (num_experts == 2) {
run_align_kernel(2);
} else {
printf("errors");
printf("【ERROR】, please add the current number of experts in the case");
}
const int block_threads = 256;

View File

@@ -205,6 +205,7 @@ std::vector<paddle::Tensor> MultiHeadLatentAttention(
meta_data.batch_size = cum_offsets.dims()[0];
switch (query.dtype()) {
#if (!defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 800)
case paddle::DataType::BFLOAT16: {
return MultiHeadLatentAttentionKernel<paddle::DataType::BFLOAT16>(
meta_data,
@@ -253,6 +254,7 @@ std::vector<paddle::Tensor> MultiHeadLatentAttention(
causal,
speculate_decoder);
}
#endif
case paddle::DataType::FLOAT16: {
return MultiHeadLatentAttentionKernel<paddle::DataType::FLOAT16>(
meta_data,

View File

@@ -0,0 +1,169 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "helper.h"
#include<string.h>
#include <cuda_runtime.h>
template <typename InType>
__global__ void
per_tensor_absmax_kernel(const InType* __restrict__ input, float* __restrict__ output_s, const int64_t num_elements) {
float max_value = 0.0f;
unsigned int tid = threadIdx.x;
unsigned int gid = blockIdx.x * blockDim.x + threadIdx.x;
const int grid_size = blockDim.x * gridDim.x;
constexpr uint32_t vec_size = 16 / sizeof(InType);
using in_vec_t = AlignedVector<InType, vec_size>;
const int32_t num_vec_elems = num_elements / vec_size;
for (int32_t i = gid; i < num_vec_elems; i += grid_size) {
in_vec_t input_vec;
Load<InType, vec_size>(input + i * vec_size, &input_vec);
#pragma unroll
for (uint32_t j = 0; j < vec_size; ++j) {
float val = static_cast<float>(input_vec[j]);
max_value = fmaxf(max_value, fabsf(val));
}
}
const int32_t remaining_start = num_vec_elems * vec_size;
for (int32_t idx = remaining_start + gid; idx < num_elements; idx += grid_size) {
float val = static_cast<float>(input[idx]);
max_value = fmaxf(max_value, fabsf(val));
}
max_value = blockReduceMax(max_value);
if (tid == 0) {
atomicMaxFloat(output_s, max_value / 448);
}
}
template <typename InType, typename OutType>
__global__ void per_tensor_quant_fp8_kernel(
const InType* __restrict__ input,
OutType* __restrict__ output,
const float* __restrict__ scale,
const int64_t num_elements) {
const int gid = blockIdx.x * blockDim.x + threadIdx.x;
const int grid_size = blockDim.x * gridDim.x;
const float scale_val = 1.0f / (*scale);
constexpr uint32_t vec_size = 16 / sizeof(InType);
using in_vec_t = AlignedVector<InType, vec_size>;
using out_vec_t = AlignedVector<OutType, vec_size>;
in_vec_t input_vec;
out_vec_t output_vec;
const int32_t num_vec_elems = num_elements / vec_size;
for (int32_t i = gid; i < num_vec_elems; i += grid_size) {
Load<InType, vec_size>(input + i * vec_size, &input_vec);
#pragma unroll
for (uint32_t j = 0; j < vec_size; ++j) {
float val = fmax(fmin(static_cast<float>(input_vec[j]) * scale_val, 448), -448);
output_vec[j] = static_cast<OutType>(val);
}
Store<OutType, vec_size>(output_vec, output + i * vec_size);
}
const int32_t remaining_start = num_vec_elems * vec_size;
for (int32_t idx = remaining_start + gid; idx < num_elements; idx += grid_size) {
float val = fmax(-448, fmin(static_cast<float>(input[idx]) * scale_val, 448));
output[idx] = static_cast<OutType>(val);
}
}
template <paddle::DataType InType, paddle::DataType OutType>
std::vector<paddle::Tensor> LaunchPerTensorQuantFp8Kernel(const paddle::Tensor& x, const paddle::optional<paddle::Tensor>& scale) {
typedef PDTraits<InType> in_traits;
typedef typename in_traits::DataType InDataType;
typedef typename in_traits::data_t in_data_t_pd;
typedef PDTraits<OutType> out_traits;
typedef typename out_traits::DataType OutDataType;
typedef typename out_traits::data_t out_data_t_pd;
paddle::Tensor out;
paddle::Tensor scale_out;
auto place = x.place();
cudaStream_t stream = x.stream();
int rank = x.dims().size();
std::vector<int64_t> out_shape = x.shape();
std::vector<int64_t> scale_shape = {1};
out = paddle::empty(out_shape, OutType, place);
if(scale){
scale_out = scale.get();
}else{
scale_out = paddle::empty(scale_shape, paddle::DataType::FLOAT32, place);
}
const int block_size = 256;
const int64_t num_elements = x.numel();
const int64_t num_blocks = min((num_elements + block_size - 1) / block_size, static_cast<int64_t>(1024));
dim3 grid(num_blocks);
dim3 block(block_size);
if(scale){
per_tensor_absmax_kernel<InDataType><<<grid, block, 0, stream>>>(
reinterpret_cast<const InDataType*>(x.data<in_data_t_pd>()), reinterpret_cast<float*>(scale_out.data<float>()), num_elements);
}
per_tensor_quant_fp8_kernel<InDataType, OutDataType><<<grid, block, 0, stream>>>(
reinterpret_cast<const InDataType*>(x.data<in_data_t_pd>()),
reinterpret_cast<OutDataType*>(out.data<out_data_t_pd>()),
reinterpret_cast<float*>(scale_out.data<float>()),
num_elements);
return {out, scale_out};
}
template <paddle::DataType InType>
std::vector<paddle::Tensor> LaunchPerTensorQuantFp8(const paddle::Tensor& x, const paddle::optional<paddle::Tensor>& scale) {
return LaunchPerTensorQuantFp8Kernel<InType, paddle::DataType::FLOAT8_E4M3FN>(x, scale);
}
std::vector<paddle::Tensor> PerTensorQuantFp8(const paddle::Tensor& x, const paddle::optional<paddle::Tensor>& scale) {
if(x.dtype() == paddle::DataType::FLOAT32){
return LaunchPerTensorQuantFp8<paddle::DataType::FLOAT32>(x, scale);
}else if(x.dtype() == paddle::DataType::FLOAT16){
return LaunchPerTensorQuantFp8<paddle::DataType::FLOAT16>(x, scale);
}else if(x.dtype() == paddle::DataType::BFLOAT16){
return LaunchPerTensorQuantFp8<paddle::DataType::BFLOAT16>(x, scale);
}else{
PD_THROW("Unsupported data type.");
}
}
std::vector<std::vector<int64_t>> PerTensorQuantFp8InferShape(const std::vector<int64_t>& input_shape, const paddle::optional<std::vector<int64_t>>& scale_shape) {
std::vector<int64_t> scale_out_shape = {1};
if(scale_shape){
return {input_shape, scale_shape.get()};
}
return {input_shape, scale_out_shape};
}
std::vector<paddle::DataType> PerTensorQuantFp8InferDtype(const paddle::DataType& input_dtype, const paddle::optional<paddle::DataType>& scale_dtype) {
return {paddle::DataType::FLOAT8_E4M3FN, paddle::DataType::FLOAT32};
}
PD_BUILD_OP(per_tensor_quant_fp8)
.Inputs({"x", paddle::Optional("scale")})
.Outputs({"output", "scale_out"})
.SetKernelFn(PD_KERNEL(PerTensorQuantFp8))
.SetInferShapeFn(PD_INFER_SHAPE(PerTensorQuantFp8InferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(PerTensorQuantFp8InferDtype));

View File

@@ -0,0 +1,251 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "helper.h"
#include<string.h>
#include <cuda_runtime.h>
__device__ __forceinline__ float GroupReduceMax(float val, const int tid) {
unsigned mask = 0xffff;
val = fmaxf(val, __shfl_xor_sync(mask, val, 8));
val = fmaxf(val, __shfl_xor_sync(mask, val, 4));
val = fmaxf(val, __shfl_xor_sync(mask, val, 2));
val = fmaxf(val, __shfl_xor_sync(mask, val, 1));
return val;
}
template <typename InType, typename OutType>
__global__ void PerTokenGroupQuantKernel(
const InType* __restrict__ input,
OutType* __restrict__ output_q,
float* __restrict__ output_s,
const int group_size,
const int num_groups,
const int groups_per_block,
const float eps,
const float quant_min_bound,
const float quant_max_bound,
bool transpose_scale = false,
const int scale_num_rows = 0,
const int scale_stride = 0) {
const int threads_per_group = 16;
const int local_group_id = threadIdx.x / threads_per_group;
const int lane_id = threadIdx.x % threads_per_group;
const int block_group_id = blockIdx.x * groups_per_block;
const int global_group_id = block_group_id + local_group_id;
const int block_group_offset = global_group_id * group_size;
float local_absmax = eps;
const InType* group_input = input + block_group_offset;
OutType* group_output = output_q + block_group_offset;
float* scale_output;
if (transpose_scale) {
const int row_idx = global_group_id / scale_num_rows;
const int col_idx = global_group_id % scale_num_rows;
scale_output = output_s + (col_idx * scale_stride + row_idx);
} else {
scale_output = output_s + global_group_id;
}
constexpr uint32_t vec_size = 16 / sizeof(InType);
using vec_t = AlignedVector<InType, vec_size>;
const int32_t num_vec_elems = group_size / vec_size;
for (int32_t i = lane_id; i < num_vec_elems; i += 16) {
vec_t input_vec;
Load<InType, vec_size>(group_input + i * vec_size, &input_vec);
#pragma unroll
for (uint32_t j = 0; j < vec_size; ++j) {
float val = static_cast<float>(input_vec[j]);
float abs_val = fabsf(val);
local_absmax = fmaxf(local_absmax, abs_val);
}
}
local_absmax = GroupReduceMax(local_absmax, lane_id);
const float y_s = local_absmax / quant_max_bound;
if (lane_id == 0) {
*scale_output = y_s;
}
for (int32_t i = lane_id; i < num_vec_elems; i += 16) {
vec_t input_vec;
Load<InType, vec_size>(group_input + i * vec_size, &input_vec);
#pragma unroll
for (uint32_t j = 0; j < vec_size; ++j) {
float val = static_cast<float>(input_vec[j]);
float q_val = fminf(fmaxf(val / y_s, quant_min_bound), quant_max_bound);
group_output[i * vec_size + j] = static_cast<OutType>(q_val);
}
}
}
template <paddle::DataType InType, paddle::DataType OutType>
std::vector<paddle::Tensor> LaunchPerTokenGroupQuantKernel(const paddle::Tensor& x,
const int group_size,
const bool transpose_scale,
const float quant_max_bound,
const float quant_min_bound) {
typedef PDTraits<InType> in_traits;
typedef typename in_traits::DataType InDataType;
typedef typename in_traits::data_t in_data_t;
paddle::Tensor out;
paddle::Tensor scale_out;
auto place = x.place();
cudaStream_t stream = x.stream();
int rank = x.dims().size();
std::vector<int64_t> out_shape = x.shape();
std::vector<int64_t> scale_shape = x.shape();
int64_t m = x.shape()[rank - 2];
int64_t k = x.shape()[rank - 1];
PD_CHECK(k % group_size == 0);
int64_t scale_k = k / group_size;
out = paddle::empty(out_shape, OutType, place);
if(transpose_scale){
scale_shape[rank - 2] = scale_k;
scale_shape[rank - 1] = m;
}else{
scale_shape[rank - 1] = scale_k;
}
scale_out = paddle::empty(scale_shape, paddle::DataType::FLOAT32, place);
int64_t numel = x.numel();
const int num_groups = numel / group_size;
constexpr int THREADS_PER_GROUP = 16;
int groups_per_block = 1;
if (num_groups % 16 == 0) {
groups_per_block = 16;
} else if (num_groups % 8 == 0) {
groups_per_block = 8;
} else if (num_groups % 4 == 0) {
groups_per_block = 4;
} else if (num_groups % 2 == 0) {
groups_per_block = 2;
}
const int num_blocks = num_groups / groups_per_block;
const int num_threads = groups_per_block * THREADS_PER_GROUP;
int scale_num_rows = 0;
int scale_stride = 0;
if (transpose_scale){
scale_num_rows = m;
scale_stride = scale_k;
}
dim3 grid(num_blocks);
dim3 block(num_threads);
typedef PDTraits<OutType> out_traits;
typedef typename out_traits::DataType OutDataType;
typedef typename out_traits::data_t out_data_t;
float eps = 0.000001f;
PerTokenGroupQuantKernel<InDataType, OutDataType><<<grid, block, 0, stream>>>(reinterpret_cast<const InDataType*>(x.data<in_data_t>()),
reinterpret_cast<OutDataType*>(out.data<out_data_t>()),
reinterpret_cast<float*>(scale_out.data<float>()),
group_size,
num_groups,
groups_per_block,
eps,
quant_min_bound,
quant_max_bound,
transpose_scale,
scale_num_rows,
scale_stride);
return {out, scale_out};
}
template <paddle::DataType InType>
std::vector<paddle::Tensor> LaunchPerTokenGroupQuant(const paddle::Tensor& x,
const int group_size,
const bool transpose_scale,
const float quant_max_bound,
const float quant_min_bound) {
if(fabs(quant_max_bound - 448.0f) < 0.000001){
return LaunchPerTokenGroupQuantKernel<InType, paddle::DataType::FLOAT8_E4M3FN>(x, group_size, transpose_scale, quant_max_bound, quant_min_bound);
}else if(fabs(quant_max_bound - 127.0f) < 0.000001){
return LaunchPerTokenGroupQuantKernel<InType, paddle::DataType::INT8>(x, group_size, transpose_scale, quant_max_bound, quant_min_bound);
}else{
PD_THROW("Only supported float8_e4m3fn and int8 quantization.");
}
}
std::vector<paddle::Tensor> PerTokenGroupQuant(const paddle::Tensor& x,
const int group_size,
const bool transpose_scale,
const float quant_max_bound,
const float quant_min_bound) {
if(x.dtype() == paddle::DataType::FLOAT32){
return LaunchPerTokenGroupQuant<paddle::DataType::FLOAT32>(x, group_size, transpose_scale, quant_max_bound, quant_min_bound);
}else if(x.dtype() == paddle::DataType::FLOAT16){
return LaunchPerTokenGroupQuant<paddle::DataType::FLOAT16>(x, group_size, transpose_scale, quant_max_bound, quant_min_bound);
}else if(x.dtype() == paddle::DataType::BFLOAT16){
return LaunchPerTokenGroupQuant<paddle::DataType::BFLOAT16>(x, group_size, transpose_scale, quant_max_bound, quant_min_bound);
}else{
PD_THROW("Unsupported data type.");
}
}
std::vector<std::vector<int64_t>> PerTokenGroupQuantInferShape(const std::vector<int64_t>& input_shape, const int group_size, const bool transpose_scale, const float quant_max_bound,const float quant_min_bound) {
std::vector<int64_t> scale_shape = input_shape;
int rank = input_shape.size();
PD_CHECK(scale_shape[rank-1] % group_size == 0);
if(transpose_scale){
scale_shape[rank - 1] = input_shape[rank - 2];
scale_shape[rank - 2] = input_shape[rank - 1] / group_size;
}else{
scale_shape[rank - 1] = input_shape[rank - 1] / group_size;
}
return {input_shape, scale_shape};
}
std::vector<paddle::DataType> PerTokenGroupQuantInferDtype(const paddle::DataType& input_dtype, const int group_size, const bool transpose_scale, const float quant_max_bound,const float quant_min_bound) {
if(fabs(quant_max_bound - 448.0f) < 0.000001){
return {paddle::DataType::FLOAT8_E4M3FN, paddle::DataType::FLOAT32};
}else if(fabs(quant_max_bound - 127.0f) < 0.000001){
return {paddle::DataType::INT8, paddle::DataType::FLOAT32};
}else{
PD_THROW("Only supported attr of quant_max_bound in [448.0, 127.0].");
}
}
PD_BUILD_OP(per_token_group_quant)
.Inputs({"x"})
.Outputs({"output", "scale"})
.Attrs({"group_size: int",
"transpose_scale: bool",
"quant_max_bound: float",
"quant_min_bound: float"})
.SetKernelFn(PD_KERNEL(PerTokenGroupQuant))
.SetInferShapeFn(PD_INFER_SHAPE(PerTokenGroupQuantInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(PerTokenGroupQuantInferDtype));

View File

@@ -138,7 +138,7 @@ std::vector<paddle::Tensor> rebuild_padding_v2(const paddle::Tensor& tmp_out, //
return {out};
}
std::vector<paddle::Tensor> RebuildPaddingV2(const paddle::Tensor& tmp_out, // [token_num, dim_embed]
paddle::Tensor RebuildPaddingV2Func(const paddle::Tensor& tmp_out, // [token_num, dim_embed]
const paddle::Tensor& cum_offsets, // [bsz, 1]
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& seq_lens_encoder,
@@ -153,7 +153,7 @@ std::vector<paddle::Tensor> RebuildPaddingV2(const paddle::Tensor& tmp_out, // [
seq_lens_encoder,
output_padding_offset,
max_input_length
);
)[0];
}
case paddle::DataType::FLOAT16: {
return rebuild_padding_v2<paddle::DataType::FLOAT16>(
@@ -163,7 +163,7 @@ std::vector<paddle::Tensor> RebuildPaddingV2(const paddle::Tensor& tmp_out, // [
seq_lens_encoder,
output_padding_offset,
max_input_length
);
)[0];
}
case paddle::DataType::FLOAT32: {
return rebuild_padding_v2<paddle::DataType::FLOAT32>(
@@ -173,7 +173,7 @@ std::vector<paddle::Tensor> RebuildPaddingV2(const paddle::Tensor& tmp_out, // [
seq_lens_encoder,
output_padding_offset,
max_input_length
);
)[0];
}
default: {
PD_THROW(
@@ -184,6 +184,22 @@ std::vector<paddle::Tensor> RebuildPaddingV2(const paddle::Tensor& tmp_out, // [
}
}
std::vector<paddle::Tensor> RebuildPaddingV2(const paddle::Tensor& tmp_out, // [token_num, dim_embed]
const paddle::Tensor& cum_offsets, // [bsz, 1]
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& seq_lens_encoder,
const paddle::optional<paddle::Tensor>& output_padding_offset,
int max_input_length) {
return {RebuildPaddingV2Func(
tmp_out,
cum_offsets,
seq_lens_decoder,
seq_lens_encoder,
output_padding_offset,
max_input_length
)};
}
std::vector<std::vector<int64_t>> RebuildPaddingV2InferShape(const std::vector<int64_t>& tmp_out_shape,
const std::vector<int64_t>& cum_offsets_shape,
const std::vector<int64_t>& seq_lens_decoder_shape,

View File

@@ -568,7 +568,7 @@ __global__ void qk_int_sv_f8_attn_kernel(int8_t *__restrict__ Q, int8_t *__restr
normalize_d<num_tiles_q, num_tiles_v, ComputeUnit::kCudaCore>(RO, m, d);
// ! here we just implement the case for fp32 acumulation
// ! here we just implement the case for fp32 accumulation
if constexpr (fuse_v_scale)
{
float v_scale[4];

View File

@@ -48,7 +48,7 @@
#include "paddle/extension.h"
// currently we do not support INT4, so we implement INT8 sage attention inference temperarily
// currently we do not support INT4, so we implement INT8 sage attention inference temporarily
#define FINAL_MASK 0xffffffff
#define WARP_SIZE 32
@@ -1288,7 +1288,7 @@ using b128_t = uint4;
* permutation in the granularity of 128bit.
*
* This struct treats all offsets to be the number of `b128_t` elements. It is designed to be stateless,
* meaning it does not maintain any information about the current pointer position. The offset returnd by
* meaning it does not maintain any information about the current pointer position. The offset returned by
* the struct can be used to access the shared memory through the provided interface.
*
* The struct guarantees that the read to permuted offset (i, j) will be the value stored in permuted offset (i, j).

View File

@@ -0,0 +1,76 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "helper.h"
template<typename T>
__global__ void SaveOutputDygraphKernel(
T* out_pool,
const T* cur_out,
const int64_t* step_idx,
const int* result_idx,
const int bsz,
const int result_num,
const int max_dec_len) {
for (int bid = blockIdx.x; bid < bsz; bid += gridDim.x) {
auto src_addr = cur_out + bid;
auto cur_step_idx = step_idx[bid] - 1;
for (int i = threadIdx.x; i < result_num; i += blockDim.x) {
auto tgt_id = result_idx[bid * result_num + i];
if (tgt_id >= 0) {
auto tgt_addr = out_pool + tgt_id * max_dec_len + cur_step_idx;
*tgt_addr = *src_addr;
}
}
}
}
void SaveOutputDygraph(
const paddle::Tensor& all_token_ids,
const paddle::Tensor& tokens,
const paddle::Tensor& result_ids,
const paddle::Tensor& step_idx
) {
auto cu_stream = all_token_ids.stream();
const int bsz = tokens.shape()[0];
const int result_num = result_ids.shape()[1];
const int max_dec_len = all_token_ids.shape()[1];
SaveOutputDygraphKernel<<<bsz, 256, 0, cu_stream>>>(
const_cast<int64_t*>(all_token_ids.data<int64_t>()),
tokens.data<int64_t>(),
step_idx.data<int64_t>(),
result_ids.data<int>(),
bsz,
result_num,
max_dec_len
);
// SaveOutputDygraphKernel<<<bsz, 256, 0, cu_stream>>>(
// const_cast<float*>(all_scores.data<float>()),
// scores.data<float>(),
// step_idx.data<int64_t>(),
// result_ids.data<int>(),
// bsz,
// result_num,
// max_dec_len
// );
}
PD_BUILD_OP(save_output_dygraph)
.Inputs({"all_token_ids", "tokens", "result_ids", "step_idx"})
.Outputs({"all_token_ids_out"})
.SetInplaceMap({{"all_token_ids", "all_token_ids_out"}})
.SetKernelFn(PD_KERNEL(SaveOutputDygraph));

View File

@@ -20,6 +20,7 @@
#include "paddle/extension.h"
#define MAX_BSZ 512
// #define SAVE_WITH_OUTPUT_DEBUG
struct msgdata {
long mtype;
@@ -35,7 +36,25 @@ void SaveOutMmsg(const paddle::Tensor& x,
auto not_need_stop_data = not_need_stop.data<bool>()[0];
static struct msgdata msg_sed;
static key_t key = ftok("./", 1);
int msg_queue_id = 1;
if (const char* inference_msg_queue_id_env_p =
std::getenv("INFERENCE_MSG_QUEUE_ID")) {
std::string inference_msg_queue_id_env_str(
inference_msg_queue_id_env_p);
int inference_msg_queue_id_from_env =
std::stoi(inference_msg_queue_id_env_str);
msg_queue_id = inference_msg_queue_id_from_env;
#ifdef SAVE_WITH_OUTPUT_DEBUG
std::cout << "Your INFERENCE_MSG_QUEUE_ID is: "
<< inference_msg_queue_id_from_env << std::endl;
#endif
} else {
#ifdef SAVE_WITH_OUTPUT_DEBUG
std::cout << "Failed to got INFERENCE_MSG_QUEUE_ID at env, use default."
<< std::endl;
#endif
}
static key_t key = ftok("./", msg_queue_id);
static int msgid = msgget(key, IPC_CREAT | 0666);
msg_sed.mtype = 1;

View File

@@ -41,11 +41,11 @@ __global__ void set_preids_token_penalty_multi_scores_kernel(const bool *stop_fl
T *logits_now = logits + bi * length;
int tid = threadIdx.x;
if (tid < bs && !stop_flags[tid]) {
int64_t *pre_ids_now = pre_ids + tid * length;
const int64_t *input_ids_now = input_ids + tid * length_input_ids;
const int seq_len_dec = seq_lens_decoder[tid];
const int seq_len_enc = seq_lens_encoder[tid];
if (bi < bs && !stop_flags[bi]) {
int64_t *pre_ids_now = pre_ids + bi * length_id;
const int64_t *input_ids_now = input_ids + bi * length_input_ids;
const int seq_len_dec = seq_lens_decoder[bi];
const int seq_len_enc = seq_lens_encoder[bi];
if (seq_len_dec == 0 && seq_len_enc == 0) return; // stopped
const int step_idx_now = step_idx[bi];

View File

@@ -0,0 +1,88 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import numpy as np
import paddle
from paddlenlp_ops import per_tensor_quant_fp8
paddle.seed(1)
def create_random_cuda_tensor(shape, dtype, mean: float = 0, std: float = 1):
return paddle.empty(shape, dtype=dtype).normal_(mean, std)
class DynamicPerTensorQuantFP8Test(unittest.TestCase):
def native_per_tensor_quant_fp8(self, x, scale=None):
x_fp32 = x.cast("float32")
if scale is None:
x_s = x_fp32.abs().max() / 448.0
else:
x_s = scale
x_q = x_fp32 / x_s
x_q = x_q.clip(min=-448.0, max=448.0)
return x_q.cast("float8_e4m3fn"), x_s.reshape([1])
def test_dynamic_per_tensor_quant_fp8_bf16(self):
num_tokens = 1024
hidden_size = 1152
dtype = paddle.bfloat16
x = paddle.rand([num_tokens, hidden_size], dtype=dtype)
ref_out, ref_scale = self.native_per_tensor_quant_fp8(x)
out, scale = per_tensor_quant_fp8(x, None)
np.testing.assert_allclose(ref_out.numpy(), out.numpy(), rtol=1e-3, atol=1e-3)
np.testing.assert_allclose(ref_scale.numpy(), scale.numpy(), rtol=1e-3, atol=1e-3)
def test_dynamic_per_tensor_quant_fp8_fp32(self):
num_tokens = 1024
hidden_size = 1152
dtype = paddle.float32
x = paddle.rand([num_tokens, hidden_size], dtype=dtype)
ref_out, ref_scale = self.native_per_tensor_quant_fp8(x)
out, scale = per_tensor_quant_fp8(x, None)
np.testing.assert_allclose(ref_out.numpy(), out.numpy(), rtol=1e-3, atol=1e-3)
np.testing.assert_allclose(ref_scale.numpy(), scale.numpy(), rtol=1e-3, atol=1e-3)
def test_dynamic_per_tensor_quant_fp8_fp16(self):
num_tokens = 1024
hidden_size = 1152
dtype = paddle.float16
x = paddle.rand([num_tokens, hidden_size], dtype=dtype)
ref_out, ref_scale = self.native_per_tensor_quant_fp8(x)
out, scale = per_tensor_quant_fp8(x, None)
np.testing.assert_allclose(ref_out.numpy(), out.numpy(), rtol=1e-3, atol=1e-3)
np.testing.assert_allclose(ref_scale.numpy(), scale.numpy(), rtol=1e-3, atol=1e-3)
def test_static_per_tensor_quant_fp8_bf16(self):
num_tokens = 1024
hidden_size = 1152
dtype = paddle.bfloat16
x = paddle.rand([num_tokens, hidden_size], dtype=dtype)
scale = paddle.rand([1], dtype=paddle.float32).clip(0.0001)
ref_out, ref_scale = self.native_per_tensor_quant_fp8(x, scale)
out, scale = per_tensor_quant_fp8(x, scale)
np.testing.assert_allclose(ref_out.numpy(), out.numpy(), rtol=1e-3, atol=1e-3)
np.testing.assert_allclose(ref_scale.numpy(), scale.numpy(), rtol=1e-3, atol=1e-3)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,210 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import numpy as np
from paddlenlp_ops import (
fused_expert_moe,
moe_expert_dispatch,
moe_expert_ffn,
moe_expert_reduce,
)
import paddle
import paddle.nn.functional as F
from paddle import nn
from paddle.incubate.nn.functional import swiglu
paddle.seed(42)
np.random.seed(42)
class Expert(nn.Layer):
def __init__(self, d_model, d_feedforward):
super().__init__()
self.fc1 = nn.Linear(d_model, d_feedforward * 2)
self.fc2 = nn.Linear(d_feedforward, d_model)
def forward(self, x, idx):
x = self.fc1(x)
x = swiglu(x)
return self.fc2(x)
class TestSimpleFusedMoe(unittest.TestCase):
def setUp(self):
self.set_config()
self.init_parameters()
self.prepare_data()
def set_config(self):
self.dtype = "bfloat16"
self.batch_size = 16
self.seq_len = 128
self.num_experts = 4
self.d_model = 64
self.d_feedforward = 128
self.top_k = 2
self.rtol = 1e-2
self.atol = 1e-2
paddle.set_default_dtype(self.dtype)
def init_parameters(self):
# 创建专家层
self.experts = nn.LayerList([
Expert(self.d_model, self.d_feedforward)
for _ in range(self.num_experts)
])
# 初始化门控权重
self.gate = nn.Linear(self.d_model, self.num_experts)
self.gate_weight = self.gate.weight.cast("float32")
def prepare_data(self):
"""准备输入数据"""
self.x = paddle.randn(
[self.batch_size, self.seq_len, self.d_model],
dtype=self.dtype
)
self.w0 = paddle.stack(
[e.fc1.weight for e in self.experts], axis=0
).astype(self.dtype)
self.b0 = paddle.stack(
[e.fc1.bias for e in self.experts], axis=0
).reshape([self.num_experts, 1, -1]).astype(self.dtype)
self.w1 = paddle.stack(
[e.fc2.weight for e in self.experts], axis=0
).astype(self.dtype)
self.b1 = paddle.stack(
[e.fc2.bias for e in self.experts], axis=0
).reshape([self.num_experts, 1, -1]).astype(self.dtype)
def baseline_forward(self, hidden_states):
"""(逐个专家计算)"""
batch_size, seq_len, hidden_dim = hidden_states.shape
hidden_states = hidden_states.reshape([-1, hidden_dim])
# 路由计算
logits = paddle.matmul(hidden_states.cast("float32"), self.gate_weight)
weights = F.softmax(logits, axis=-1)
routing_weights, selected_experts = paddle.topk(weights, self.top_k, axis=-1)
# 结果累加
final_hidden_states = paddle.zeros_like(hidden_states)
expert_mask = paddle.transpose(
F.one_hot(selected_experts, num_classes=self.num_experts), [2, 1, 0]
)
for expert_id in range(self.num_experts):
expert_layer = self.experts[expert_id]
idx, top_x = paddle.where(expert_mask[expert_id])
current_state = paddle.index_select(
hidden_states, top_x, axis=0
).reshape([-1, hidden_dim])
current_hidden_states = (
expert_layer(current_state, expert_id)
* routing_weights[top_x, idx]
)
paddle.index_add_(
x=final_hidden_states,
index=top_x.squeeze(),
axis=0,
value=current_hidden_states.to(hidden_states.dtype),
)
final_hidden_states = paddle.reshape(
final_hidden_states, [batch_size, seq_len, hidden_dim]
)
return final_hidden_states
def fused_forward(self, x):
"""测试融合实现"""
return fused_expert_moe(
x,
self.gate_weight,
self.w0,
self.w1,
self.b0,
None,
self.b1,
None,
"None",
self.top_k,
False,
False
)
def split_forward(self, hidden_states):
'''测试拆分实现'''
batch_size, seq_len, hidden_dim = hidden_states.shape
hidden_states = hidden_states.reshape([-1, hidden_dim])
# 路由计算
logits = paddle.matmul(hidden_states.cast("float32"), self.gate_weight)
scores = F.softmax(logits, axis=-1)
(
permute_input,
token_nums_per_expert,
permute_indices_per_token,
top_k_weights,
top_k_indices,
) = moe_expert_dispatch(hidden_states, scores, self.top_k, False, topk_only_mode=True)
ffn_out = moe_expert_ffn(
permute_input,
token_nums_per_expert,
self.w0,
self.w1,
self.b0,
None,
None,
"none",
)
output = moe_expert_reduce(
ffn_out,
top_k_weights,
permute_indices_per_token,
top_k_indices,
None,
norm_topk_prob=False,
routed_scaling_factor=1.0,
)
output = paddle.reshape(output, [batch_size, seq_len, hidden_dim])
return output
def test_consistency(self):
"""测试一致性"""
base_out = self.baseline_forward(self.x)
fused_out = self.fused_forward(self.x)
split_out = self.split_forward(self.x)
np.testing.assert_allclose(
base_out.cast("float32").numpy().astype("float32"),
fused_out.cast("float32").numpy().astype("float32"),
rtol=self.rtol,
atol=self.atol
)
np.testing.assert_allclose(
base_out.cast("float32").numpy().astype("float32"),
split_out.cast("float32").numpy().astype("float32"),
rtol=self.rtol,
atol=self.atol
)
print("Test passed! Outputs match within tolerance.")
if __name__ == "__main__":
unittest.main()

View File

@@ -64,6 +64,5 @@ class GetPaddingOffsetV2Test(unittest.TestCase):
assert sum(ref_cu_seqlens_q - cu_seqlens_q) == 0, "Check cu_seqlens_q failed."
assert sum(ref_cu_seqlens_k - cu_seqlens_k) == 0, "Check cu_seqlens_k failed."
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,119 @@
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import numpy as np
import paddle
from paddlenlp_ops import per_token_group_quant
class PerTokenGroupQuantTest(unittest.TestCase):
def native_per_token_group_quant(self, x, group_size, quant_max_bound, quant_min_bound):
eps = 0.000001
x = x.cast(paddle.float32)
x_ = x.reshape([x.numel() // group_size, group_size])
amax = x_.abs().max(axis=-1, keepdim=True).clip(min=eps)
x_s = amax / quant_max_bound
x_q = (x_ / x_s).clip(min=quant_min_bound, max=quant_max_bound)
x_q = x_q.reshape(x.shape)
s_shape = x.shape[:-1] + [x.shape[-1] // group_size]
x_s = x_s.reshape(s_shape)
if abs(quant_max_bound - 448) < 0.00001:
x_q = x_q.cast(paddle.float8_e4m3fn)
elif abs(quant_max_bound - 127) < 0.00001:
x_q = x_q.cast(paddle.int8)
else:
assert f"Error quant_max_bound {quant_max_bound}."
return x_q, x_s
def test_per_token_group_quant_fp8_t(self):
M = 32
K = 1024
x = np.random.rand(M, K).astype(np.float32)
x_tensor = paddle.to_tensor(x).cast(paddle.float16)
x_q_ref, x_s_ref = self.native_per_token_group_quant(
x_tensor, group_size=128, quant_max_bound=448.0, quant_min_bound=-448.0
)
x_s_ref = x_s_ref.transpose([1, 0])
x_q, x_s = per_token_group_quant(
x_tensor, group_size=128, transpose_scale=True, quant_max_bound=448.0, quant_min_bound=-448.0
)
x_q_ref = x_q_ref.cast(paddle.float32)
x_q = x_q.cast(paddle.float32)
np.testing.assert_allclose(x_q.numpy(), x_q_ref.numpy(), rtol=1e-3, atol=1e-3)
np.testing.assert_allclose(x_s.numpy(), x_s_ref.numpy(), rtol=1e-3, atol=1e-3)
def test_per_token_group_quant_fp8(self):
M = 32
K = 1024
x = np.random.rand(M, K).astype(np.float32)
x_tensor = paddle.to_tensor(x).cast(paddle.float16)
x_q_ref, x_s_ref = self.native_per_token_group_quant(
x_tensor, group_size=128, quant_max_bound=448.0, quant_min_bound=-448.0
)
x_q, x_s = per_token_group_quant(
x_tensor, group_size=128, transpose_scale=False, quant_max_bound=448.0, quant_min_bound=-448.0
)
x_q_ref = x_q_ref.cast(paddle.float32)
x_q = x_q.cast(paddle.float32)
np.testing.assert_allclose(x_q.numpy(), x_q_ref.numpy(), rtol=1e-3, atol=1e-3)
np.testing.assert_allclose(x_s.numpy(), x_s_ref.numpy(), rtol=1e-3, atol=1e-3)
def test_per_token_group_quant_int8_t(self):
M = 32
K = 1024
x_tensor = paddle.randn([M, K], dtype=paddle.float16)
x_q_ref, x_s_ref = self.native_per_token_group_quant(
x_tensor, group_size=128, quant_max_bound=127.0, quant_min_bound=-127.0
)
x_s_ref = x_s_ref.transpose([1, 0])
x_q, x_s = per_token_group_quant(
x_tensor, group_size=128, transpose_scale=True, quant_max_bound=127.0, quant_min_bound=-127.0
)
x_q_ref = x_q_ref.cast(paddle.float32)
x_q = x_q.cast(paddle.float32)
np.testing.assert_allclose(x_q.numpy(), x_q_ref.numpy(), rtol=1e-3, atol=1e-3)
np.testing.assert_allclose(x_s.numpy(), x_s_ref.numpy(), rtol=1e-3, atol=1e-3)
def test_per_token_group_quant_int8(self):
M = 32
K = 1024
x = np.random.rand(M, K).astype(np.float32)
x_tensor = paddle.to_tensor(x).cast(paddle.float16)
x_q_ref, x_s_ref = self.native_per_token_group_quant(
x_tensor, group_size=128, quant_max_bound=127.0, quant_min_bound=-127.0
)
x_q, x_s = per_token_group_quant(
x_tensor, group_size=128, transpose_scale=False, quant_max_bound=127.0, quant_min_bound=-127.0
)
x_q_ref = x_q_ref.cast(paddle.float32)
x_q = x_q.cast(paddle.float32)
np.testing.assert_allclose(x_q.numpy(), x_q_ref.numpy(), rtol=1e-3, atol=1e-3)
np.testing.assert_allclose(x_s.numpy(), x_s_ref.numpy(), rtol=1e-3, atol=1e-3)
if __name__ == "__main__":
unittest.main()

View File

@@ -42,8 +42,10 @@ __global__ void update_inputs_kernel_v2(
const int bsz,
const int max_bsz,
const int input_ids_stride,
const int end_length) {
const int end_length,
const int Flag_truncated_return_eos) {
int thread_idx = threadIdx.x;
bool output_len_truncated = false;
// update step_idx and stop_flags
if (thread_idx < max_bsz) {
bool stop_flag = stop_flags[thread_idx];
@@ -52,6 +54,7 @@ __global__ void update_inputs_kernel_v2(
}
if (step_idx[thread_idx] >= max_dec_len[thread_idx]) {
stop_flags[thread_idx] = true;
output_len_truncated = true;
}
}
__syncthreads();
@@ -61,8 +64,13 @@ __global__ void update_inputs_kernel_v2(
if (seq_lens_this_time[thread_idx] == 0) {
next_tokens[thread_idx] = -1;
} else {
next_tokens[thread_idx] = end_ids[0];
kwargs_next_tokens[thread_idx] = end_ids[0];
if (!Flag_truncated_return_eos && output_len_truncated) {
// output len truncated will not return eos for rl.
kwargs_next_tokens[thread_idx] = next_tokens[thread_idx];
}else{
next_tokens[thread_idx] = end_ids[0];
kwargs_next_tokens[thread_idx] = end_ids[0];
}
}
} else {
kwargs_next_tokens[thread_idx] = next_tokens[thread_idx];
@@ -127,6 +135,15 @@ void UpdateInputesV2(const paddle::Tensor& stop_flags,
const int end_length = end_ids.shape()[0];
auto not_need_stop_gpu = not_need_stop.copy_to(stop_flags.place(), false);
int Flag_truncated_return_eos = 1;
if (const char* inference_truncated_return_eos_env_p =
std::getenv("INFERENCE_TRUNCATED_RETURN_EOS")) {
std::string inference_truncated_return_eos_env_str(
inference_truncated_return_eos_env_p);
int inference_truncated_return_eos_from_env =
std::stoi(inference_truncated_return_eos_env_str);
Flag_truncated_return_eos = inference_truncated_return_eos_from_env;
}
update_inputs_kernel_v2<1024><<<1, 1024, 0, input_ids.stream()>>>(
const_cast<bool*>(not_need_stop_gpu.data<bool>()),
@@ -145,7 +162,8 @@ void UpdateInputesV2(const paddle::Tensor& stop_flags,
now_bsz,
max_bsz,
input_ids_stride,
end_length
end_length,
Flag_truncated_return_eos
);
auto not_need_stop_cpu = not_need_stop_gpu.copy_to(not_need_stop.place(), false);

View File

@@ -15,12 +15,24 @@
import os
import shutil
import subprocess
from packaging.version import parse, Version
import paddle
from paddle.utils.cpp_extension import CUDAExtension, setup
sm_version = int(os.getenv("CUDA_SM_VERSION", "0"))
def get_nvcc_cuda_version(cuda_dir: str) -> Version:
"""Get the CUDA version from nvcc.
Adapted from https://github.com/NVIDIA/apex/blob/8b7a1ff183741dd8f9b87e7bafd04cfde99cea28/setup.py
"""
nvcc_output = subprocess.check_output([cuda_dir + "/bin/nvcc", "-V"],
universal_newlines=True)
output = nvcc_output.split()
release_idx = output.index("release") + 1
nvcc_cuda_version = parse(output[release_idx].split(",")[0])
return nvcc_cuda_version
def update_git_submodule():
try:
@@ -80,7 +92,7 @@ def get_gencode_flags():
gencode_flags = get_gencode_flags()
library_path = os.environ.get("LD_LIBRARY_PATH", "/usr/local/cuda/lib64")
library_path = [os.environ.get("LD_LIBRARY_PATH", "/usr/local/cuda/lib64")]
sources = [
"./gpu/save_with_output.cc",
@@ -105,8 +117,7 @@ sources = [
"./gpu/step.cu",
"./gpu/quant_int8.cu",
"./gpu/dequant_int8.cu",
"./gpu/group_quant.cu",
"./gpu/preprocess_for_moe.cu",
"./gpu/moe/preprocess_for_moe.cu",
"./gpu/get_position_ids_and_mask_encoder_batch.cu",
"./gpu/fused_rotary_position_encoding.cu",
"./gpu/flash_attn_bwd.cc",
@@ -118,6 +129,10 @@ sources = [
"./gpu/speculate_decoding_kernels/ngram_match.cc",
"./gpu/speculate_decoding_kernels/speculate_save_output.cc",
"./gpu/speculate_decoding_kernels/speculate_get_output.cc",
"./gpu/save_output_dygraph.cu",
"./gpu/all_reduce.cu",
"./gpu/quantization/per_token_group_quant.cu",
"./gpu/quantization/per_tensor_quant_fp8.cu",
]
sources += find_end_files("./gpu/speculate_decoding_kernels", ".cu")
@@ -132,18 +147,22 @@ nvcc_compile_args += [
"-U__CUDA_NO_BFLOAT16_CONVERSIONS__",
"-U__CUDA_NO_BFLOAT162_OPERATORS__",
"-U__CUDA_NO_BFLOAT162_CONVERSIONS__",
"-Igpu",
"-Igpu/cutlass_kernels",
"-Igpu/fp8_gemm_with_cutlass",
"-Igpu/cutlass_kernels/fp8_gemm_fused/autogen",
"-Ithird_party/cutlass/include",
"-Ithird_party/cutlass/tools/util/include",
"-Ithird_party/nlohmann_json/single_include",
"-Igpu/sample_kernels",
]
include_dirs = [
"./gpu",
"./gpu/cutlass_kernels",
"./gpu/fp8_gemm_with_cutlass",
"./gpu/cutlass_kernels/fp8_gemm_fused/autogen",
"./third_party/cutlass/include",
"./third_party/cutlass/tools/util/include",
"./third_party/nlohmann_json/single_include",
"./gpu/sample_kernels",
"./gpu/moe/fused_moe",
]
cc = get_sm_version()
cuda_version = float(paddle.version.cuda())
nvcc_version = get_nvcc_cuda_version(os.environ.get("CUDA_HOME", "/usr/local/cuda"))
if cc >= 80:
sources += ["gpu/int8_gemm_with_cutlass/gemm_dequant.cu"]
@@ -152,12 +171,16 @@ if cc >= 80:
sources += find_end_files("./gpu/append_attn", ".cu")
sources += find_end_files("./gpu/append_attn/template_instantiation", ".cu")
sources += find_end_files("./gpu/moe/fused_moe/cutlass_kernels/moe_gemm/", ".cu")
sources += find_end_files("./gpu/moe/fused_moe/", ".cu")
sources += "./gpu/cpp_extensions.cu",
fp8_auto_gen_directory = "gpu/cutlass_kernels/fp8_gemm_fused/autogen"
if os.path.isdir(fp8_auto_gen_directory):
shutil.rmtree(fp8_auto_gen_directory)
if cc == 89 and cuda_version >= 12.4:
os.system("python utils/auto_gen_fp8_fp8_gemm_fused_kernels.py --cuda_arch 89")
os.system("python utils/auto_gen_fp8_fp8_dual_gemm_fused_kernels.py --cuda_arch 89")
@@ -168,7 +191,8 @@ if cc == 89 and cuda_version >= 12.4:
"gpu/fp8_gemm_with_cutlass/fp8_fp8_fp8_dual_gemm.cu",
]
if cc >= 80 and cuda_version >= 12.4:
if cc >= 80 and nvcc_version >= Version("12.4"):
os.environ.pop('PADDLE_CUDA_ARCH_LIST', None)
nvcc_compile_args += [
"-std=c++17",
"--use_fast_math",
@@ -177,21 +201,17 @@ if cc >= 80 and cuda_version >= 12.4:
]
sources += ["./gpu/sage_attn_kernels/sageattn_fused.cu"]
if cc >= 80 and cc < 89:
sources += [
"./gpu/sage_attn_kernels/sageattn_qk_int_sv_f16_kernel_sm80.cu"
]
nvcc_compile_args += ["-gencode", f"arch=compute_80,code=compute_80"]
sources += ["./gpu/sage_attn_kernels/sageattn_qk_int_sv_f16_kernel_sm80.cu"]
nvcc_compile_args += ["-gencode", "arch=compute_80,code=compute_80"]
elif cc >= 89 and cc < 90:
sources += [
"./gpu/sage_attn_kernels/sageattn_qk_int_sv_f8_kernel_sm89.cu"
]
nvcc_compile_args += ["-gencode", f"arch=compute_89,code=compute_89"]
sources += ["./gpu/sage_attn_kernels/sageattn_qk_int_sv_f8_kernel_sm89.cu"]
nvcc_compile_args += ["-gencode", "arch=compute_89,code=compute_89"]
elif cc >= 90:
sources += [
"./gpu/sage_attn_kernels/sageattn_qk_int_sv_f8_kernel_sm90.cu",
"./gpu/sage_attn_kernels/sageattn_qk_int_sv_f8_dsk_kernel_sm90.cu"
"./gpu/sage_attn_kernels/sageattn_qk_int_sv_f8_dsk_kernel_sm90.cu",
]
nvcc_compile_args += ["-gencode", f"arch=compute_90a,code=compute_90a"]
nvcc_compile_args += ["-gencode", "arch=compute_90a,code=compute_90a"]
if cc >= 90 and cuda_version >= 12.0:
os.system("python utils/auto_gen_fp8_fp8_gemm_fused_kernels_sm90.py --cuda_arch 90")
@@ -209,12 +229,17 @@ if cc >= 90 and cuda_version >= 12.0:
sources += find_end_files("./gpu/mla_attn", ".cu")
ops_name = f"paddlenlp_ops_{sm_version}" if sm_version != 0 else "paddlenlp_ops"
setup(
name=ops_name,
ext_modules=CUDAExtension(
sources=sources,
extra_compile_args={"cxx": ["-O3", "-fopenmp", "-lgomp", "-std=c++17", "-DENABLE_BF16"], "nvcc": nvcc_compile_args},
extra_compile_args={
"cxx": ["-O3", "-fopenmp", "-lgomp", "-std=c++17", "-DENABLE_BF16"],
"nvcc": nvcc_compile_args,
},
libraries=["cublasLt"],
library_dirs=[library_path],
library_dirs=library_path,
include_dirs=include_dirs,
),
)

View File

@@ -60,8 +60,8 @@ function generate_sm_version(){
if [ ! -z "$SM_VERSION" ]; then
sm_versions=($SM_VERSION )
elif [ "$ARCHITECTURE" = "all" ]; then
if echo "$cuda_version >= 12.0" | awk '{if ($0) exit 0; exit 1}'; then
sm_versions=(70 80 80 86 89 90 )
if awk -v version="$cuda_version" 'BEGIN { exit !(version >= 12.0) }'; then
sm_versions=(70 75 80 86 89 90 )
else
sm_versions=(70 75 80 86 89 )
fi
@@ -72,10 +72,12 @@ function generate_sm_version(){
}
function create_directories(){
mkdir -p $OPS_SRC_DIR/tmp/paddlenlp_ops
touch $OPS_SRC_DIR/tmp/setup.py
touch $OPS_SRC_DIR/tmp/paddlenlp_ops/__init__.py
echo '# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
for sm_version in "${sm_versions[@]}"; do
echo "create sm$sm_version"
mkdir -p $OPS_SRC_DIR/tmp/paddlenlp_ops
touch $OPS_SRC_DIR/tmp/setup.py
touch $OPS_SRC_DIR/tmp/paddlenlp_ops/__init__.py
echo '# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -93,6 +95,7 @@ function create_directories(){
import os
from datetime import datetime
import paddle
from setuptools import find_packages, setup
@@ -109,14 +112,19 @@ def read(file: str):
content = f.read().strip()
return content
def read_version():
"""
read version and return content
"""
__version__ = "3.0.0b4.post"
formatted_date = datetime.now().date().strftime("%Y%m%d")
__version__ = __version__.replace(".post", ".post{}".format(formatted_date))
cuda_version = float(paddle.version.cuda())
sm_version=80
paddle_commit = paddle.__git_commit__[:7]
build_tag = "{}+cuda{}sm{}paddle{}".format(formatted_date, cuda_version, sm_version, paddle_commit)
__version__ = __version__.replace(".post", ".post{}".format(build_tag))
return __version__
@@ -184,12 +192,9 @@ try:
except ImportError:
logger.WARNING(f"No {module_name} ")
' > $OPS_SRC_DIR/tmp/paddlenlp_ops/__init__.py
for sm_version in "${sm_versions[@]}"; do
echo "create sm$sm_version"
mkdir -p $OPS_SRC_DIR/tmp/paddlenlp_ops/sm${sm_version}
touch $OPS_SRC_DIR/tmp/paddlenlp_ops/sm${sm_version}/__init__.py
echo '# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
mkdir -p $OPS_SRC_DIR/tmp/paddlenlp_ops/sm${sm_version}
touch $OPS_SRC_DIR/tmp/paddlenlp_ops/sm${sm_version}/__init__.py
echo '# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -210,6 +215,7 @@ try:
except ImportError:
logger.WARNING("No paddlenlp_ops_'${sm_version}' ops")
' > $OPS_SRC_DIR/tmp/paddlenlp_ops/sm${sm_version}/__init__.py
build_ops
done
}
@@ -228,11 +234,11 @@ function init() {
}
function build_ops() {
for sm_version in "${sm_versions[@]}"; do
echo "Building and installing for sm_version: $sm_version"
build_and_install_ops $sm_version
done
return
echo "Building and installing for sm_version: $sm_version"
build_and_install_ops $sm_version
build_and_install_whl
unittest
cleanup
}
function copy_ops(){
@@ -269,6 +275,7 @@ function build_and_install_whl() {
echo -e "${BLUE}[build]${NONE} building paddlenlp_ops wheel..."
rm -rf ./dist
cd ${TMP_DIR}
sed -i "s/sm_version=80/sm_version=${sm_version}/g" setup.py
${python} setup.py bdist_wheel --dist-dir ./$DIST_DIR
if [ $? -ne 0 ]; then
echo -e "${RED}[FAIL]${NONE} build paddlenlp_ops wheel failed !"
@@ -286,7 +293,8 @@ function build_and_install_whl() {
fi
echo -e "${BLUE}[install]${NONE} ${GREEN}paddlenlp_ops install success\n"
cd ..
mv $DIST_DIR ../
mkdir -p ../$DIST_DIR
mv $DIST_DIR/* ../$DIST_DIR/
cd ..
}
@@ -321,10 +329,6 @@ trap 'abort' 0
set -e
init
build_ops
build_and_install_whl
unittest
cleanup
# get Paddle version
PADDLE_VERSION=`${python} -c "import paddle; print(paddle.version.full_version)"`

View File

@@ -0,0 +1,219 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
#include <core/ctx_manager.h>
#include <core/xft_check.h>
#include <core/xft_event.h>
#include <core/xft_params.h>
#include <xft/xdnn_plugin.h>
#include <xft/operation/page_attn.h>
#include <xft/operation/fmha.h>
#include <flash_api.h> // link xfa
#include "ops.h"
namespace xftkernel = baidu::xpu::xftkernel;
template <typename T>
struct kl3_pa_TL_trait {
using TL = T;
};
template <>
struct kl3_pa_TL_trait<bfloat16> {
using TL = float;
};
std::vector<paddle::Tensor> MlaDeAttn(
const paddle::Tensor& q,
const paddle::Tensor& kv_cache,
const paddle::Tensor& decoder_context_len,
const paddle::Tensor& decoder_batch_map,
const paddle::Tensor& decoder_context_len_cpu,
const paddle::Tensor& decoder_batch_map_cpu,
const paddle::Tensor& dec_batch_tensor,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const float softmax_scale,
const int block_size,
const int num_head,
const int kv_lora_rank,
const int rope_head_dim,
const int dim_qk,
const int dim_v) {
baidu::xpu::api::plugin::print_times("[TIME BEGIN] MlaDeAttn" );
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
xpu::ctx_guard RAII_GUARD(xpu_ctx->x_context());
using QType = typename XPUTypeTrait<bfloat16>::Type;
using CacheType = typename XPUTypeTrait<bfloat16>::Type;
typedef paddle::bfloat16 qdata_t, cache_t;
const auto& input_dims = q.dims();
const int bsz = cum_offsets.dims()[0];
const int token_num = input_dims[0];
const int block_batch = block_tables.dims()[0]; // TODO参数含义 block_batch_ PageParam page_param_
const int max_block_per_seq = block_tables.dims()[1];
const int max_seq_len = block_size * max_block_per_seq;
int dec_batch = dec_batch_tensor.data<int32_t>()[0];
// 初始化输入:q k v
auto q_xft = baidu::xpu::xft::xftTensor<QType, 3>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(q.data<qdata_t>())),
std::array<int64_t, 3>{q.shape()[0],
q.shape()[1],
q.shape()[2]});
// 初始化输入:k cache
auto kv_cache_xft = baidu::xpu::xft::xftTensor<CacheType, 4>(
reinterpret_cast<CacheType*>(const_cast<paddle::bfloat16*>(kv_cache.data<cache_t>())),
std::array<int64_t, 4>{kv_cache.shape()[0],
kv_cache.shape()[1],
kv_cache.shape()[2],
kv_cache.shape()[3]});
// 初始化输入:block table
auto block_tables_xft = baidu::xpu::xft::xftTensor<int, 2>(
reinterpret_cast<int*>(const_cast<int*>(block_tables.data<int>())),
std::array<int64_t, 2>{block_tables.shape()[0],
block_tables.shape()[1]});
// 初始化输出tensor
auto fmha_out = paddle::full({q.shape()[0], num_head * kv_lora_rank}, -2, q.type(), q.place());
auto fmha_out_xft = baidu::xpu::xft::xftTensor<QType, 2>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(fmha_out.data<qdata_t>())),
std::array<int64_t, 2>{fmha_out.shape()[0],
fmha_out.shape()[1]});
// decoder
if(dec_batch > 0){
// context_len
baidu::xpu::api::VectorParam<int32_t> context_len_vp{const_cast<int32_t*>(decoder_context_len_cpu.data<int32_t>()), dec_batch, const_cast<int32_t*>(decoder_context_len.data<int32_t>())};
// real batch
baidu::xpu::api::VectorParam<int32_t> valid_batch_vp{const_cast<int32_t*>(decoder_batch_map_cpu.data<int32_t>()), dec_batch, const_cast<int32_t*>(decoder_batch_map.data<int32_t>())};
// multi_latent_attention
using TQ = bfloat16;
using TKVCACHE = bfloat16;
using TO = TQ;
using TGEMM = float;
using TEW = float;
using TID = int;
constexpr int quant_mode = 0;
// xpu_ctx->x_context().set_debug_level(0xa1);
int ret = baidu::xpu::xfa::multi_latent_attention<
TQ,
TKVCACHE,
TO,
TGEMM,
TEW,
TID,
quant_mode>(
xpu_ctx->x_context(),
fmha_out_xft.data(),
q_xft.data(),
kv_cache_xft.data(),
block_tables_xft.data(),
context_len_vp,
valid_batch_vp,
block_batch,
max_seq_len,
num_head,
kv_lora_rank,
rope_head_dim,
nullptr, // attn_mask
softmax_scale, // 0.13523377478122711f, // scale
block_size,
max_block_per_seq,
-1,
nullptr,
nullptr,
nullptr);
}
baidu::xpu::api::plugin::print_times("[TIME END] MlaDeAttn");
return {fmha_out};
}
std::vector<std::vector<int64_t>> MlaDeAttnInferShape(
const std::vector<int64_t>& q_shape,
const std::vector<int64_t>& kv_cache_shape,
const std::vector<int64_t>& decoder_context_len_shape,
const std::vector<int64_t>& decoder_batch_map_shape,
const std::vector<int64_t>& decoder_context_len_cpu_shape,
const std::vector<int64_t>& decoder_batch_map_cpu_shape,
const std::vector<int64_t>& dec_batch_tensor_shape,
const std::vector<int64_t>& padding_offsets_shape,
const std::vector<int64_t>& cum_offsets_shape,
const std::vector<int64_t>& block_tables_shape,
const float softmax_scale,
const int block_size,
const int num_head,
const int kv_lora_rank,
const int rope_head_dim,
const int dim_qk,
const int dim_v) {
return {{q_shape[0], num_head * kv_lora_rank}};
}
std::vector<paddle::DataType> MlaDeAttnInferDtype(
const paddle::DataType& q_dtype,
const paddle::DataType& kv_cache_dtype,
const paddle::DataType& decoder_context_len_dtype,
const paddle::DataType& decoder_batch_map_dtype,
const paddle::DataType& decoder_context_len_cpu_dtype,
const paddle::DataType& decoder_batch_map_cpu_dtype,
const paddle::DataType& dec_batch_tensor_dtype,
const paddle::DataType& padding_offsets_dtype,
const paddle::DataType& cum_offsets_dtype,
const paddle::DataType& block_tables_dtype,
const float softmax_scale,
const int block_size,
const int num_head,
const int kv_lora_rank,
const int rope_head_dim,
const int dim_qk,
const int dim_v) {
if (q_dtype == paddle::DataType::FLOAT16) {
return {paddle::DataType::FLOAT16};
} else if(q_dtype == paddle::DataType::BFLOAT16){
return {paddle::DataType::BFLOAT16};
}
else {
PD_THROW("Only supported attr of compute_dtype in ['fp16','bfp16'].");
}
}
PD_BUILD_OP(absorb_mla_block_mha_decoder_xpu)
.Inputs({"q",
"kv_cache",
"decoder_context_len",
"decoder_batch_map",
"decoder_context_len_cpu",
"decoder_batch_map_cpu",
"dec_batch_tensor",
"padding_offsets",
"cum_offsets",
"block_tables"})
.Outputs({"fmha_out"})
.Attrs({"softmax_scale: float",
"block_size: int",
"num_head: int",
"kv_lora_rank: int",
"rope_head_dim: int",
"dim_qk: int",
"dim_v: int"})
.SetKernelFn(PD_KERNEL(MlaDeAttn))
.SetInferShapeFn(PD_INFER_SHAPE(MlaDeAttnInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(MlaDeAttnInferDtype));

View File

@@ -0,0 +1,251 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
#include <core/ctx_manager.h>
#include <core/xft_check.h>
#include <core/xft_event.h>
#include <core/xft_params.h>
#include <xft/xdnn_plugin.h>
#include <xft/operation/page_attn.h>
#include <xft/operation/fmha.h>
#include <flash_api.h> // link xfa
#include "ops.h"
namespace xftkernel = baidu::xpu::xftkernel;
template <typename T>
struct kl3_pa_TL_trait {
using TL = T;
};
template <>
struct kl3_pa_TL_trait<bfloat16> {
using TL = float;
};
std::vector<paddle::Tensor> MlaEnAttn(
const paddle::Tensor& q,
const paddle::Tensor& k,
const paddle::Tensor& v,
const paddle::Tensor& encoder_seq_lod,
const paddle::Tensor& encoder_batch_map,
const paddle::Tensor& encoder_seq_lod_cpu,
const paddle::Tensor& encoder_batch_map_cpu,
const paddle::Tensor& enc_batch_tensor,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const paddle::Tensor& max_enc_len_this_time,
const paddle::Tensor& max_dec_len_this_time,
const float softmax_scale,
const int block_size,
const int num_head,
const int dim_qk,
const int dim_v) {
baidu::xpu::api::plugin::print_times("[TIME BEGIN] MlaEnAttn");
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
xpu::ctx_guard RAII_GUARD(xpu_ctx->x_context());
using QType = typename XPUTypeTrait<bfloat16>::Type;
using CacheType = typename XPUTypeTrait<bfloat16>::Type;
typedef paddle::bfloat16 qdata_t, cache_t;
const auto& input_dims = q.dims();
const int bsz = cum_offsets.dims()[0];
const int token_num = input_dims[0];
const int block_batch = block_tables.dims()[0]; // TODO参数含义 block_batch_ PageParam page_param_
const int max_block_per_seq = block_tables.dims()[1];
const int max_seq_len = block_size * max_block_per_seq;
int enc_batch = enc_batch_tensor.data<int32_t>()[0];
// 初始化输入:q k v
auto q_xft = baidu::xpu::xft::xftTensor<QType, 3>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(q.data<qdata_t>())),
std::array<int64_t, 3>{q.shape()[0],
q.shape()[1],
q.shape()[2]});
auto k_xft = baidu::xpu::xft::xftTensor<QType, 3>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(k.data<qdata_t>())),
std::array<int64_t, 3>{k.shape()[0],
k.shape()[1],
k.shape()[2]});
auto v_xft = baidu::xpu::xft::xftTensor<QType, 3>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(v.data<qdata_t>())),
std::array<int64_t, 3>{v.shape()[0],
v.shape()[1],
v.shape()[2]});
// 初始化输出tensor
auto fmha_out = paddle::full({q.shape()[0], num_head * dim_v}, -2, q.type(), q.place());
auto fmha_out_xft = baidu::xpu::xft::xftTensor<QType, 2>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(fmha_out.data<qdata_t>())),
std::array<int64_t, 2>{fmha_out.shape()[0],
fmha_out.shape()[1]});
// encoder
if(max_enc_len_this_time.data<int>()[0] > 0){
// q_lod
baidu::xpu::api::VectorParam<int32_t> context_len_vp{const_cast<int32_t*>(encoder_seq_lod_cpu.data<int32_t>()), enc_batch + 1, const_cast<int32_t*>(encoder_seq_lod.data<int32_t>())};
// real batch(encoder阶段 kv cache写需要)
baidu::xpu::api::VectorParam<int32_t> valid_batch_vp{const_cast<int32_t*>(encoder_batch_map_cpu.data<int32_t>()), enc_batch, const_cast<int32_t*>(encoder_batch_map.data<int32_t>())};
// prefix (not support)
baidu::xpu::api::VectorParam<int32_t> prefix_lens_vp = baidu::xpu::api::VectorParam<int32_t>();
// kv_lod (非prefix cache情况与q_lod一致)
baidu::xpu::api::VectorParam<int32_t> encoder_kv_lods_vp{const_cast<int32_t*>(encoder_seq_lod_cpu.data<int32_t>()), enc_batch + 1, const_cast<int32_t*>(encoder_seq_lod.data<int32_t>())};
// page_param_
baidu::xpu::xft::PageParam page_param_(block_batch, // block_batch_
max_enc_len_this_time.data<int>()[0], // max_enc_len_this_time.data<int>()[0],max_seq_len // max_context_len_
block_size, // block_size_
max_block_per_seq, // max_num_blocks_per_seq_
false); // v_trans
// attn_param
baidu::xpu::xft::PageAttnParam attn_param_(dim_qk, // head_dim(q,k)
num_head, // q_head_num
num_head, // kv_head_num
false, // vp_lod_flag
context_len_vp, // context_len_vp
valid_batch_vp, // valid_batch_vp
prefix_lens_vp, // prefix_lens_vp
encoder_kv_lods_vp); // encoder_kv_lods_vp
// fmha op
using FMHA_Type = typename baidu::xpu::xft::FMHA_QBF16_KVBF16;
using TQ = typename FMHA_Type::Qtype;
using TK = typename FMHA_Type::Ktype;
using TV = typename FMHA_Type::Vtype;
using TBIAS = typename FMHA_Type::Btype;
using TO = typename FMHA_Type::Otype;
using TMASK = typename FMHA_Type::Mtype;
int ret = baidu::xpu::xfa::flash_attention_context_vllm<
TQ,
TK,
TV,
TBIAS,
TO,
float, // T_GEMM0
float, // T_GEMM1
float, // T_EW
int,
0>(
xpu_ctx->x_context(),
q_xft.data(), // q
std::is_same<TK, int8_t>::value ? nullptr : reinterpret_cast<TK*>(k_xft.data()), // k
std::is_same<TK, int8_t>::value ? nullptr : reinterpret_cast<TV*>(v_xft.data()), // v
nullptr, // p_bias == nullptr ? nullptr : p_bias->data(), // mask_bias
fmha_out_xft.data(), //o
enc_batch, // batch_size
page_param_.max_context_len_, // max_seq_q
page_param_.max_context_len_, // max_seq_kv, (prefix cache是会不一样)
attn_param_.q_head_num_,
attn_param_.head_dim_,
attn_param_.kv_head_num_,
nullptr,
attn_param_.context_len_vp_,
attn_param_.encoder_kv_lods_vp_,
{}, // mask_shape_
{}, // alibi_slopes_shape
true, // is_causal_mask_
false, // is_qkv_fusion_
0x0010, // param.qkv_layout_ = AttnQKVLayout_t::ATTN_BLHD
0x10, // vsl_flag_ = VslConverter::FMHA_LVSL
nullptr, // q_maxptr
nullptr, // k_maxptr
nullptr, // v_maxptr
nullptr,
dim_v, // vo_head_dim
nullptr, // p_cache_k->data(),
nullptr, // p_cache_v->data(),
nullptr, // std::is_same<TK, int8_t>::value ? p_kcache_perhead_scale->data() : p_cache_k->max_data(),
nullptr, // std::is_same<TK, int8_t>::value ? p_vcache_perhead_scale->data() : p_cache_v->max_data(),
block_size, // block_size
max_block_per_seq, // max_blocks_per_seq (prefix cache)
page_param_.max_context_len_, // prefill_len
nullptr,
softmax_scale * sqrt(dim_qk)); // block_tables (prefix cache)
// std::cout << "fmha kernel done " <<std::endl;
}
baidu::xpu::api::plugin::print_times("[TIME END] MlaEnAttn:");
return {fmha_out};
}
std::vector<std::vector<int64_t>> MlaEnAttnInferShape(
const std::vector<int64_t>& q_shape,
const std::vector<int64_t>& k_shape,
const std::vector<int64_t>& v_shape,
const std::vector<int64_t>& encoder_seq_lod_shape,
const std::vector<int64_t>& encoder_batch_map_shape,
const std::vector<int64_t>& encoder_seq_lod_cpu_shape,
const std::vector<int64_t>& encoder_batch_map_cpu_shape,
const std::vector<int64_t>& enc_batch_tensor_shape,
const std::vector<int64_t>& padding_offsets_shape,
const std::vector<int64_t>& cum_offsets_shape,
const std::vector<int64_t>& block_tables_shape,
const std::vector<int64_t>& max_enc_len_this_time_shape,
const std::vector<int64_t>& max_dec_len_this_time_shape) {
return {v_shape};
}
std::vector<paddle::DataType> MlaEnAttnInferDtype(
const paddle::DataType& q_dtype,
const paddle::DataType& k_dtype,
const paddle::DataType& v_dtype,
const paddle::DataType& encoder_seq_lod_dtype,
const paddle::DataType& encoder_batch_map_dtype,
const paddle::DataType& encoder_seq_lod_cpu_dtype,
const paddle::DataType& encoder_batch_map_cpu_dtype,
const paddle::DataType& enc_batch_tensor_dtype,
const paddle::DataType& padding_offsets_dtype,
const paddle::DataType& cum_offsets_dtype,
const paddle::DataType& block_tables_dtype,
const paddle::DataType& max_enc_len_this_time_dtype,
const paddle::DataType& max_dec_len_this_time_dtype) {
if (q_dtype == paddle::DataType::FLOAT16) {
return {paddle::DataType::FLOAT16};
} else if(q_dtype == paddle::DataType::BFLOAT16){
return {paddle::DataType::BFLOAT16};
}
else {
PD_THROW("Only supported attr of compute_dtype in ['fp16','bfp16'].");
}
}
PD_BUILD_OP(absorb_mla_block_mha_encoder_xpu)
.Inputs({"q",
"k",
"v",
"encoder_seq_lod",
"encoder_batch_map",
"encoder_seq_lod_cpu",
"encoder_batch_map_cpu",
"enc_batch_tensor",
"padding_offsets",
"cum_offsets",
"block_tables",
"max_enc_len_this_time",
"max_dec_len_this_time"})
.Outputs({"fmha_out"})
.Attrs({"softmax_scale: float",
"block_size: int",
"num_head: int",
"dim_qk: int",
"dim_v: int"})
.SetKernelFn(PD_KERNEL(MlaEnAttn))
.SetInferShapeFn(PD_INFER_SHAPE(MlaEnAttnInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(MlaEnAttnInferDtype));

View File

@@ -0,0 +1,100 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "xpu/plugin.h"
#include <xft/xdnn_plugin.h>
namespace xftkernel = baidu::xpu::xftkernel;
std::vector<paddle::Tensor> AdjustBatch(const paddle::Tensor& tmp_out, // [token_num, dim_embed]
const paddle::Tensor& cum_offsets, // [bsz, 1]
const paddle::Tensor& encoder_seq_lod,
const paddle::Tensor& encoder_batch_idx,
const paddle::Tensor& decoder_batch_idx,
const paddle::Tensor& encoder_seq_lod_cpu,
const paddle::Tensor& encoder_batch_idx_cpu,
const paddle::Tensor& decoder_batch_idx_cpu,
const paddle::Tensor& enc_batch_tensor,
const paddle::Tensor& dec_batch_tensor,
const paddle::optional<paddle::Tensor>& output_padding_offset,
int max_input_length) {
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
using XPUType = typename XPUTypeTrait<bfloat16>::Type; // only support bfloat16
typedef paddle::bfloat16 data_t;
const int token_num = tmp_out.dims()[0];
const int dim = tmp_out.dims()[1];
const int bsz = cum_offsets.shape()[0];
int enc_batch = enc_batch_tensor.data<int32_t>()[0];
int dec_batch = dec_batch_tensor.data<int32_t>()[0];
baidu::xpu::api::VectorParam<int32_t> encoder_seqs_lods_vp{const_cast<int32_t*>(encoder_seq_lod_cpu.data<int32_t>()), enc_batch + 1, const_cast<int32_t*>(encoder_seq_lod.data<int32_t>())};
baidu::xpu::api::VectorParam<int32_t> encoder_batch_map_vp{const_cast<int32_t*>(encoder_batch_idx_cpu.data<int32_t>()), enc_batch, const_cast<int32_t*>(encoder_batch_idx.data<int32_t>())};
baidu::xpu::api::VectorParam<int32_t> decoder_batch_map_vp{const_cast<int32_t*>(decoder_batch_idx_cpu.data<int32_t>()), dec_batch, const_cast<int32_t*>(decoder_batch_idx.data<int32_t>())};
auto out = paddle::full({token_num, dim}, -2, tmp_out.type(), tmp_out.place());
int r = xftkernel::xft_eb_adjust_batch<XPUType, XPUType>(
xpu_ctx->x_context(),
reinterpret_cast<const XPUType*>(tmp_out.data<data_t>()),
reinterpret_cast<XPUType*>(out.data<data_t>()),
encoder_seqs_lods_vp,
encoder_batch_map_vp,
decoder_batch_map_vp,
dim);
return {out};
}
std::vector<std::vector<int64_t>> AdjustBatchInferShape(const std::vector<int64_t>& tmp_out_shape,
const std::vector<int64_t>& cum_offsets_shape,
const std::vector<int64_t>& encoder_seq_lod_shape,
const std::vector<int64_t>& encoder_batch_idx_shape,
const std::vector<int64_t>& decoder_batch_idx_shape,
const std::vector<int64_t>& encoder_seq_lod_cpu_shape,
const std::vector<int64_t>& encoder_batch_idx_cpu_shape,
const std::vector<int64_t>& decoder_batch_idx_cpu_shape,
const std::vector<int64_t>& enc_batch_tensor_shape,
const std::vector<int64_t>& dec_batch_tensor_shape,
const paddle::optional<std::vector<int64_t>>& output_padding_offset_shape) {
if (output_padding_offset_shape) {
PD_THROW("speculative decoding is not supported in XPU.");
}
int64_t token_num = tmp_out_shape[0];
int64_t dim_embed = tmp_out_shape[1];
return {{token_num, dim_embed}};
}
std::vector<paddle::DataType> AdjustBatchInferDtype(const paddle::DataType& tmp_out_dtype,
const paddle::DataType& cum_offsets_dtype,
const paddle::DataType& encoder_seq_lod_dtype,
const paddle::DataType& encoder_batch_idx_dtype,
const paddle::DataType& decoder_batch_idx_dtype,
const paddle::DataType& encoder_seq_lod_cpu_dtype,
const paddle::DataType& encoder_batch_idx_cpu_dtype,
const paddle::DataType& decoder_batch_idx_cpu_dtype,
const paddle::DataType& enc_batch_tensor_dtype,
const paddle::DataType& dec_batch_tensor_dtype,
const paddle::optional<paddle::DataType>& output_padding_offset_dtype) {
return {tmp_out_dtype};
}
PD_BUILD_OP(adjust_batch)
.Inputs({"tmp_out", "cum_offsets", "encoder_seq_lod", "encoder_batch_idx", "decoder_batch_idx", "encoder_seq_lod_cpu", "encoder_batch_idx_cpu", "decoder_batch_idx_cpu", "enc_batch_tensor", "dec_batch_tensor", paddle::Optional("output_padding_offset")})
.Outputs({"out"})
.Attrs({"max_input_length: int"})
.SetKernelFn(PD_KERNEL(AdjustBatch))
.SetInferShapeFn(PD_INFER_SHAPE(AdjustBatchInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(AdjustBatchInferDtype));

View File

@@ -0,0 +1,76 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "xpu/plugin.h"
#include <xft/xdnn_plugin.h>
#include "cublasLt.h"
#include "ops.h"
namespace xftkernel = baidu::xpu::xftkernel;
std::vector<paddle::Tensor> Bmm(const paddle::Tensor& input,
const paddle::Tensor& weight) {
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
xpu::ctx_guard RAII_GUARD(xpu_ctx->x_context());
using XPUType = typename XPUTypeTrait<bfloat16>::Type; // only support bfloat16
typedef paddle::bfloat16 data_t;
const int batch = input.dims()[0];
const int m = input.dims()[1];
const int n = weight.dims()[2];
const int k = weight.dims()[1];
auto out = paddle::full({batch, m, n}, -2, input.type(), input.place());
int ret = baidu::xpu::xblas::fc_batched<XPUType, XPUType, XPUType, float, float, 0>(
xpu_ctx->x_context(),
batch,
false,
false,
m,
n,
k,
1.0f,
reinterpret_cast<const XPUType*>(input.data<data_t>()),
m * k,
reinterpret_cast<const XPUType*>(weight.data<data_t>()),
k * n,
0.0f,
reinterpret_cast<XPUType*>(out.data<data_t>()),
m * n,
nullptr,
nullptr);
return {out};
}
std::vector<std::vector<int64_t>> BmmInferShape(const std::vector<int64_t>& input_shape,
const std::vector<int64_t>& weight_shape) {
int64_t batch = input_shape[0];
int64_t m = input_shape[1];
int64_t n = weight_shape[2];
return {{batch, m, n}};
}
std::vector<paddle::DataType> BmmInferDtype(const paddle::DataType& input_dtype,
const paddle::DataType& weight_dtype) {
return {input_dtype};
}
PD_BUILD_OP(batch_matmul_xpu)
.Inputs({"imput", "weight"})
.Outputs({"out"})
.SetKernelFn(PD_KERNEL(Bmm))
.SetInferShapeFn(PD_INFER_SHAPE(BmmInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(BmmInferDtype));

448
csrc/xpu/src/block_attn.cc Normal file
View File

@@ -0,0 +1,448 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
#include "ops.h"
#include <core/ctx_manager.h>
#include <core/xft_check.h>
#include <core/xft_event.h>
#include <core/xft_params.h>
#include <xft/xdnn_plugin.h>
#include <xft/operation/page_attn.h>
#include <xft/operation/fmha.h>
#include <flash_api.h> // link xfa
namespace xftkernel = baidu::xpu::xftkernel;
namespace api = baidu::xpu::api;
std::vector<paddle::Tensor> MlaBlockAttn(
const paddle::Tensor& attn_input, // [m, 7168]
const paddle::Tensor& q_a_proj_weights, // self.q_a_proj_weights[i] [7168, 1536] 【enc】【dec】
const paddle::Tensor& q_b_proj_weights, // self.q_b_proj_weights[i] [1536, 24576] 【enc】【dec】
const paddle::Tensor& q_a_layernorm_weights, // self.q_a_layernorm_weights[i] [1536] 【enc】【dec】
const paddle::Tensor& kv_a_proj_with_mqa_weights, // self.kv_a_proj_with_mqa_weights[i] [7168, 576] 【enc】
const paddle::Tensor& kv_a_layernorm_weights, // self.kv_a_layernorm_weights[i] [512] 【enc】【dec】
const paddle::Tensor& kv_b_proj_weights, // self.kv_b_proj_weights[i] [512, 32768] 【enc】
const paddle::Tensor& linear_weights, // self.linear_weights[i] [16384, 7168] 【enc】【dec】
const paddle::Tensor& k_b_proj_weights, // self.k_b_proj_weights[i] [128, 128, 512] 【dec】
const paddle::Tensor& v_b_proj_weights, // self.v_b_proj_weights[i] [128, 512, 128] 【dec】
const paddle::Tensor& cos_sin_cache, // self.config.rotary_emb.cos_sin_cache [163840, 64]
const paddle::Tensor& position_ids, // self.position_ids [m]
const paddle::Tensor& kv_cache,
const paddle::Tensor& block_tables,
const paddle::Tensor& encoder_seq_lod,
const paddle::Tensor& encoder_batch_map,
const paddle::Tensor& start_token_raw,
const paddle::Tensor& decoder_context_len_cache,
const paddle::Tensor& decoder_context_len,
const paddle::Tensor& decoder_batch_map,
const paddle::Tensor& kv_seq_lod_raw,
const paddle::Tensor& encoder_seq_lod_cpu,
const paddle::Tensor& encoder_batch_map_cpu,
const paddle::Tensor& start_token_raw_cpu,
const paddle::Tensor& decoder_context_len_cache_cpu,
const paddle::Tensor& decoder_context_len_cpu,
const paddle::Tensor& decoder_batch_map_cpu,
const paddle::Tensor& kv_seq_lod_raw_cpu,
const paddle::Tensor& enc_batch_tensor,
const paddle::Tensor& dec_batch_tensor,
const paddle::Tensor& total_enc_len_tensor,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& max_enc_len_this_time,
const paddle::Tensor& max_dec_len_this_time,
const std::string& cache_quant_type_str,
const float softmax_scale,
const int block_size,
const int num_heads, // self.num_heads
const int q_lora_rank, // 传 self.config.mla_config.q_lora_rank = 1536
const int qk_head_dim, // self.config.mla_config.qk_head_dim 192
const int qk_nope_head_dim, // self.config.mla_config.qk_nope_head_dim 128
const int qk_rope_head_dim, // self.config.mla_config.qk_rope_head_dim 64
const int kv_lora_rank, // self.config.mla_config.kv_lora_rank 512
const int v_head_dim // self.config.mla_config.v_head_dim 128
) {
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
xpu::ctx_guard RAII_GUARD(xpu_ctx->x_context());
using CType = typename XPUTypeTrait<bfloat16>::Type;
using CacheType = typename XPUTypeTrait<bfloat16>::Type;
typedef paddle::bfloat16 data_t, cache_t;
const int bsz = encoder_batch_map.dims()[0]; // batch map tensor长度都是max_batch_size, 有效长度根据
// const int block_batch = block_tables.dims()[0]; // TODO参数含义 block_batch_ PageParam page_param_
const int max_block_per_seq = block_tables.dims()[1];
const int max_seq_len = block_size * max_block_per_seq;
const int token_num = attn_input.dims()[0];
const int hidden_dim = attn_input.dims()[1];
int enc_batch = enc_batch_tensor.data<int32_t>()[0];
int dec_batch = dec_batch_tensor.data<int32_t>()[0];
int total_enc_len = total_enc_len_tensor.data<int32_t>()[0];
// 输出tensor
auto block_attn_out = paddle::full({token_num, hidden_dim}, -1, attn_input.type(), attn_input.place());
// encoder
if(enc_batch > 0){
// split and copy
auto ln_out_encoder = paddle::experimental::slice(attn_input, {0}, {0}, {total_enc_len}, {0}, {});
auto position_ids_enc = paddle::experimental::slice(position_ids, {0}, {0}, {total_enc_len}, {0}, {});
// encoder no absorb fc
if (q_lora_rank <= 0) {
assert("Not supported in block attn");
}
auto query_0 = paddle::matmul(ln_out_encoder, q_a_proj_weights);
auto query_1 = std::get<0>(paddle::experimental::rms_norm(query_0, NULL, NULL, q_a_layernorm_weights, NULL, 1e-06, 1, -1, 0, 0, 0));
auto query_2 = paddle::matmul(query_1, q_b_proj_weights);
// auto query_nope = paddle::full({total_enc_len, num_heads, qk_nope_head_dim}, -1, query_2.type(), query_2.place());
auto query_pe = paddle::full({total_enc_len, num_heads, qk_rope_head_dim}, -1, query_2.type(), query_2.place());
int r = api::split<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(query_2.data<data_t>()),
{nullptr, reinterpret_cast<CType*>(query_pe.data<data_t>())},
{total_enc_len, num_heads, qk_head_dim},
{qk_nope_head_dim, qk_rope_head_dim},
2); // axis = 2
PD_CHECK(r == 0, "api::split failed.");
auto compressed_kv = paddle::matmul(ln_out_encoder, kv_a_proj_with_mqa_weights);
auto compressed_kv_0 = paddle::full({total_enc_len, kv_lora_rank}, -1, compressed_kv.type(), compressed_kv.place());
auto key_pe = paddle::full({total_enc_len, qk_rope_head_dim}, -1, compressed_kv.type(), compressed_kv.place());
r = api::split<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(compressed_kv.data<data_t>()),
{reinterpret_cast<CType*>(compressed_kv_0.data<data_t>()), reinterpret_cast<CType*>(key_pe.data<data_t>())},
{total_enc_len, kv_lora_rank + qk_rope_head_dim},
{kv_lora_rank, qk_rope_head_dim},
1); // axis = 1
PD_CHECK(r == 0, "api::split failed.");
auto compressed_kv_1 = std::get<0>(paddle::experimental::rms_norm(compressed_kv_0, NULL, NULL, kv_a_layernorm_weights, NULL, 1e-06, 1, -1, 0, 0, 0));
FusedRotaryPositionEncoding(query_pe, key_pe, position_ids_enc, cos_sin_cache, qk_rope_head_dim, false);
PrefillMLAWriteCacheKernel(
compressed_kv_1,
key_pe,
kv_cache,
encoder_seq_lod,
encoder_batch_map,
start_token_raw,
encoder_seq_lod_cpu,
encoder_batch_map_cpu,
start_token_raw_cpu,
enc_batch_tensor,
dec_batch_tensor,
padding_offsets,
cum_offsets,
block_tables,
cache_quant_type_str,
max_seq_len,
num_heads);
auto key_value = paddle::matmul(compressed_kv_1, kv_b_proj_weights);
auto key_nope = paddle::full({total_enc_len, num_heads, qk_nope_head_dim}, -1, key_value.type(), key_value.place());
auto value = paddle::full({total_enc_len, num_heads, v_head_dim}, -1, key_value.type(), key_value.place());
r = api::split<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(key_value.data<data_t>()),
{reinterpret_cast<CType*>(key_nope.data<data_t>()), reinterpret_cast<CType*>(value.data<data_t>())},
{total_enc_len, num_heads, qk_nope_head_dim + v_head_dim},
{qk_nope_head_dim, v_head_dim},
2); // axis = 2
PD_CHECK(r == 0, "api::split failed.");
r = api::strided_slice_view_update<CType>(
xpu_ctx->x_context(),
reinterpret_cast<CType*>(query_pe.data<data_t>()),
reinterpret_cast<CType*>(query_2.data<data_t>()),
{total_enc_len, num_heads, qk_rope_head_dim},
{total_enc_len, num_heads, qk_head_dim},
{0, 0, qk_nope_head_dim}, // start
{total_enc_len, num_heads, qk_head_dim}, // end
{1, 1, 1}); // stride
PD_CHECK(r == 0, "api::strided_slice_view_update failed.");
auto key = paddle::full({total_enc_len, num_heads, qk_head_dim}, -1, query_2.type(), query_2.place());
r = api::strided_slice_view_update<CType>(
xpu_ctx->x_context(),
reinterpret_cast<CType*>(key_nope.data<data_t>()),
reinterpret_cast<CType*>(key.data<data_t>()),
{total_enc_len, num_heads, qk_nope_head_dim},
{total_enc_len, num_heads, qk_head_dim},
{0, 0, 0}, // start
{total_enc_len, num_heads, qk_nope_head_dim}, // end
{1, 1, 1}); // stride
PD_CHECK(r == 0, "api::strided_slice_view_update failed.");
auto key_pe_broadcast = paddle::full({total_enc_len, num_heads, qk_rope_head_dim}, -1, query_2.type(), query_2.place());
r = api::broadcast<CType>(
xpu_ctx->x_context(),
reinterpret_cast<CType*>(key_pe.data<data_t>()),
reinterpret_cast<CType*>(key_pe_broadcast.data<data_t>()),
{total_enc_len, 1, qk_rope_head_dim},
{total_enc_len, num_heads, qk_rope_head_dim});
PD_CHECK(r == 0, "api::broadcast failed.");
r = api::strided_slice_view_update<CType>(
xpu_ctx->x_context(),
reinterpret_cast<CType*>(key_pe_broadcast.data<data_t>()),
reinterpret_cast<CType*>(key.data<data_t>()),
{total_enc_len, num_heads, qk_rope_head_dim},
{total_enc_len, num_heads, qk_head_dim},
{0, 0, qk_nope_head_dim}, // start
{total_enc_len, num_heads, qk_head_dim}, // end
{1, 1, 1}); // stride
PD_CHECK(r == 0, "api::strided_slice_view_update failed.");
// attn
auto fmha_out_prefill = MlaEnAttn(
query_2,
key,
value,
encoder_seq_lod,
encoder_batch_map,
encoder_seq_lod_cpu,
encoder_batch_map_cpu,
enc_batch_tensor,
padding_offsets,
cum_offsets,
block_tables,
max_enc_len_this_time,
max_dec_len_this_time,
softmax_scale,
block_size,
num_heads,
qk_head_dim,
v_head_dim)[0];
auto out_linear_out_prefill = paddle::matmul(fmha_out_prefill, linear_weights);
r = api::copy<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(out_linear_out_prefill.data<data_t>()),
reinterpret_cast<CType*>(block_attn_out.data<data_t>()),
{total_enc_len * hidden_dim});
PD_CHECK(r == 0, "api::copy failed.");
}
// decoder
if(dec_batch > 0){
// split
auto ln_out_decoder = paddle::experimental::slice(attn_input, {0}, {total_enc_len}, {token_num}, {0}, {});
auto position_ids_dec = paddle::experimental::slice(position_ids, {0}, {total_enc_len}, {token_num}, {0}, {});
// decoder absorb fc
auto compressed_kv = paddle::matmul(ln_out_decoder, kv_a_proj_with_mqa_weights);
auto compressed_kv_0 = paddle::full({dec_batch, kv_lora_rank}, -1, compressed_kv.type(), compressed_kv.place());
auto key_pe = paddle::full({dec_batch, qk_rope_head_dim}, -1, compressed_kv.type(), compressed_kv.place());
int r = api::split<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(compressed_kv.data<data_t>()),
{reinterpret_cast<CType*>(compressed_kv_0.data<data_t>()), reinterpret_cast<CType*>(key_pe.data<data_t>())},
{dec_batch, kv_lora_rank + qk_rope_head_dim},
{kv_lora_rank, qk_rope_head_dim},
1); // axis = 1
PD_CHECK(r == 0, "api::split failed.");
auto compressed_kv_1 = std::get<0>(paddle::experimental::rms_norm(compressed_kv_0, NULL, NULL, kv_a_layernorm_weights, NULL, 1e-06, 1, -1, 0, 0, 0)); // TODO inplace
if (q_lora_rank <= 0) {
assert("Not supported in block attn");
}
auto query_0 = paddle::matmul(ln_out_decoder, q_a_proj_weights);
auto query_1 = std::get<0>(paddle::experimental::rms_norm(query_0, NULL, NULL, q_a_layernorm_weights, NULL, 1e-06, 1, -1, 0, 0, 0));
auto query_2 = paddle::matmul(query_1, q_b_proj_weights);
auto query_nope = paddle::full({dec_batch, num_heads, qk_nope_head_dim}, -1, query_2.type(), query_2.place());
auto query_pe = paddle::full({dec_batch, num_heads, qk_rope_head_dim}, -1, query_2.type(), query_2.place());
r = api::split<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(query_2.data<data_t>()),
{reinterpret_cast<CType*>(query_nope.data<data_t>()), reinterpret_cast<CType*>(query_pe.data<data_t>())},
{dec_batch, num_heads, qk_head_dim},
{qk_nope_head_dim, qk_rope_head_dim},
2); // axis = 2
PD_CHECK(r == 0, "api::split failed.");
auto query_nope_trans = paddle::full({num_heads, dec_batch, qk_nope_head_dim}, -1, query_2.type(), query_2.place());
r = api::transpose<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(query_nope.data<data_t>()),
reinterpret_cast<CType*>(query_nope_trans.data<data_t>()),
{dec_batch, num_heads, qk_nope_head_dim},
{1, 0, 2});
PD_CHECK(r == 0, "api::transpose failed.");
auto q_nope_bmm = Bmm(query_nope_trans, k_b_proj_weights)[0];
auto q_nope_out = paddle::full({dec_batch, num_heads, kv_lora_rank}, -1, query_2.type(), query_2.place());
r = api::transpose<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(q_nope_bmm.data<data_t>()),
reinterpret_cast<CType*>(q_nope_out.data<data_t>()),
{num_heads, dec_batch, kv_lora_rank},
{1, 0, 2});
PD_CHECK(r == 0, "api::transpose failed.");
FusedRotaryPositionEncoding(query_pe, key_pe, position_ids_dec, cos_sin_cache, qk_rope_head_dim, false);
DecodeMLAWriteCacheKernel(
compressed_kv_1,
key_pe,
kv_cache,
decoder_context_len_cache,
decoder_batch_map,
kv_seq_lod_raw,
decoder_context_len_cache_cpu,
decoder_batch_map_cpu,
kv_seq_lod_raw_cpu,
enc_batch_tensor,
dec_batch_tensor,
padding_offsets,
cum_offsets,
block_tables,
cache_quant_type_str,
max_seq_len,
num_heads,
false); // self.config.speculate_config.speculate_method is not None
auto q_input = paddle::full({dec_batch, num_heads * (kv_lora_rank + qk_rope_head_dim)}, -1, query_2.type(), query_2.place()); // TODO inplace
r = api::concat<CType>(
xpu_ctx->x_context(),
{reinterpret_cast<const CType*>(q_nope_out.data<data_t>()), reinterpret_cast<const CType*>(query_pe.data<data_t>())},
reinterpret_cast<CType*>(q_input.data<data_t>()),
{{dec_batch, num_heads, kv_lora_rank}, {dec_batch, num_heads, qk_rope_head_dim}},
2); // axis = 2
// attn
auto fmha_out_decode = MlaDeAttn( // [dec_batch, 128*512]
q_input,
kv_cache,
decoder_context_len,
decoder_batch_map,
decoder_context_len_cpu,
decoder_batch_map_cpu,
dec_batch_tensor,
padding_offsets,
cum_offsets,
block_tables,
softmax_scale,
block_size,
num_heads,
kv_lora_rank,
qk_rope_head_dim,
qk_head_dim,
v_head_dim)[0];
auto fmha_out_decode_trans = paddle::full({num_heads, dec_batch, kv_lora_rank}, -1, query_2.type(), query_2.place()); // shape要跟transpose后的对齐,下面的BMM会读取shape做计算
r = api::transpose<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(fmha_out_decode.data<data_t>()),
reinterpret_cast<CType*>(fmha_out_decode_trans.data<data_t>()),
{dec_batch, num_heads, kv_lora_rank},
{1, 0, 2});
PD_CHECK(r == 0, "api::transpose failed.");
auto fmha_out_decode_bmm = Bmm(fmha_out_decode_trans, v_b_proj_weights)[0]; // fmha_out_decode_bmm = [dec_batch, 128*128]
auto fmha_out_decode_out = paddle::full({dec_batch, num_heads * v_head_dim}, -1, query_2.type(), query_2.place());
r = api::transpose<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(fmha_out_decode_bmm.data<data_t>()),
reinterpret_cast<CType*>(fmha_out_decode_out.data<data_t>()),
{num_heads, dec_batch, v_head_dim},
{1, 0, 2});
PD_CHECK(r == 0, "api::transpose failed.");
auto out_linear_out_decode = paddle::matmul(fmha_out_decode_out, linear_weights);
r = api::copy<CType>(
xpu_ctx->x_context(),
reinterpret_cast<const CType*>(out_linear_out_decode.data<data_t>()),
reinterpret_cast<CType*>(block_attn_out.data<data_t>()) + total_enc_len * hidden_dim,
{dec_batch * hidden_dim});
PD_CHECK(r == 0, "api::copy failed.");
}
return {block_attn_out};
}
std::vector<std::vector<int64_t>> MlaBlockAttnInferShape(const std::vector<int64_t>& attn_input_shape) {
return {attn_input_shape};
}
std::vector<paddle::DataType> MlaBlockAttnInferDtype(const paddle::DataType& attn_input_dtype) {
return {attn_input_dtype};
}
PD_BUILD_OP(absorb_mla_block_attention_xpu)
.Inputs({"attn_input",
"q_a_proj_weights",
"q_b_proj_weights",
"q_a_layernorm_weights",
"kv_a_proj_with_mqa_weights",
"kv_a_layernorm_weights",
"kv_b_proj_weights",
"linear_weights",
"k_b_proj_weights",
"v_b_proj_weights",
"cos_sin_cache",
"position_ids",
"kv_cache",
"block_tables",
"encoder_seq_lod",
"encoder_batch_map",
"start_token_raw",
"decoder_context_len_cache",
"decoder_context_len",
"decoder_batch_map",
"kv_seq_lod_raw",
"encoder_seq_lod_cpu",
"encoder_batch_map_cpu",
"start_token_raw_cpu",
"decoder_context_len_cache_cpu",
"decoder_context_len_cpu",
"decoder_batch_map_cpu",
"kv_seq_lod_raw_cpu",
"enc_batch_tensor",
"dec_batch_tensor",
"total_enc_len_tensor",
"padding_offsets",
"cum_offsets",
"max_enc_len_this_time",
"max_dec_len_this_time",})
.Outputs({"block_attn_out"})
// .SetInplaceMap({{"kv_cache", "kv_cache_out"}})
.Attrs({"cache_quant_type_str: std::string",
"softmax_scale: float",
"block_size: int",
"num_heads: int",
"q_lora_rank: int",
"qk_head_dim: int",
"qk_nope_head_dim: int",
"qk_rope_head_dim: int",
"kv_lora_rank: int",
"v_head_dim: int"})
.SetKernelFn(PD_KERNEL(MlaBlockAttn))
.SetInferShapeFn(PD_INFER_SHAPE(MlaBlockAttnInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(MlaBlockAttnInferDtype));

View File

@@ -0,0 +1,102 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cassert>
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "xpu/plugin.h"
#include <xft/xdnn_plugin.h>
namespace xftkernel = baidu::xpu::xftkernel;
std::vector<paddle::Tensor> DynamicSetValue(const paddle::Tensor& input,
const paddle::Tensor& index,
paddle::Tensor* output,
bool is_before_index) { // true: [ : index, :] ; false: [index : , :]
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
using XPUType = typename XPUTypeTrait<bfloat16>::Type; // only support bfloat16
typedef paddle::bfloat16 data_t;
int index_num = index.data<int64_t>()[0];
int total_len = output->dims()[0];
int dim = output->dims()[1];
int copy_num = input.numel();
assert(dim == input.dims()[1] && "input.dim != output.dim! ");
assert((index_num >= 0 && index_num <= total_len) && "index out of range! ");
if (is_before_index) {
assert((index_num - 0) * dim == copy_num && "copy_num wrong! ");
}
else{
assert((total_len - index_num) * dim == copy_num && "copy_num wrong! ");
}
int r = baidu::xpu::api::copy<XPUType>(
xpu_ctx->x_context(),
reinterpret_cast<const XPUType*>(input.data<data_t>()),
reinterpret_cast<XPUType*>(output->data<data_t>() + (is_before_index ? 0 : index_num * dim)),
copy_num);
return {};
}
PD_BUILD_OP(dynamic_set_value)
.Inputs({"input", "index", "output"})
.Outputs({"output_"})
.SetInplaceMap({{"output_", "output"}})
.Attrs({"is_before_index: bool"})
.SetKernelFn(PD_KERNEL(DynamicSetValue));
// std::vector<paddle::Tensor> DynamicSplitValue(const paddle::Tensor& input,
// const paddle::Tensor& index,
// bool is_before_index) { // true: [ : index, :] ; false: [index : , :]
// phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
// auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
// auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
// using XPUType = typename XPUTypeTrait<bfloat16>::Type; // only support bfloat16
// typedef paddle::bfloat16 data_t;
// int index_num = index.data<int64_t>()[0];
// int total_len = input.dims()[0];
// int dim = input.dims()[1];
// int copy_len = 0;
// if (is_before_index) {
// copy_len = index_num
// }
// else{
// copy_len = total_len - index_num
// }
// auto output = paddle::full({copy_len, dim}, 0, seq_lens_encoder.type(), seq_lens_encoder.place());
// assert(dim == input.dims()[1] && "input.dim != output.dim! ");
// assert((index_num >= 0 && index_num <= total_len) && "index out of range! ");
// if (is_before_index) {
// assert((index_num - 0) * dim == copy_len && "copy_len wrong! ");
// }
// else{
// assert((total_len - index_num) * dim == copy_len && "copy_len wrong! ");
// }
// int r = baidu::xpu::api::copy<XPUType>(
// xpu_ctx->x_context(),
// reinterpret_cast<const XPUType*>(input.data<data_t>()),
// reinterpret_cast<XPUType*>(output->data<data_t>() + (is_before_index ? 0 : index_num * dim)),
// copy_len);
// return {};
// }

View File

@@ -0,0 +1,72 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "xpu/plugin.h"
#include "ops.h"
#include <xft/xdnn_plugin.h>
void FusedRotaryPositionEncoding(
paddle::Tensor& query, // [num_tokens, num_heads, head_size] or
// [num_tokens, num_heads * head_size]
paddle::Tensor& key,
// [num_tokens, num_kv_heads, head_size] or [num_tokens, num_kv_heads *
// head_size]
const paddle::Tensor& position_ids, // [num_tokens]
const paddle::Tensor& cos_sin_cache, // [max_position, rot_dim]
int head_size,
bool is_neox) {
baidu::xpu::api::plugin::print_times("[TIME BEGIN] FusedRotaryPositionEncoding" );
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
xpu::ctx_guard RAII_GUARD(xpu_ctx->x_context());
typedef paddle::bfloat16 data_t;
using XPUType = typename XPUTypeTrait<data_t>::Type;
int64_t num_tokens = query.dims()[0];
int num_heads = query.numel() / num_tokens / head_size;
int num_kv_heads = key.numel() / num_tokens / head_size;
int rot_dim = cos_sin_cache.dims()[1];
int64_t query_stride = num_heads * head_size;
int64_t key_stride = num_kv_heads * head_size;
baidu::xpu::api::plugin::rotary_embedding_neox<XPUType, XPUType>(xpu_ctx->x_context(),
position_ids.data<int>(),
reinterpret_cast<XPUType*>(query.data<data_t>()),
reinterpret_cast<XPUType*>(key.data<data_t>()),
reinterpret_cast<const XPUType*>(cos_sin_cache.data<data_t>()),
rot_dim,
num_heads,
num_kv_heads,
head_size,
num_tokens);
baidu::xpu::api::plugin::print_times("[TIME END] FusedRotaryPositionEncoding" );
}
PD_BUILD_OP(fused_rotary_position_encoding)
.Inputs({"query", "key", "position_ids", "cos_sin_cache"})
.Outputs({"query_out", "key_out"})
.Attrs({"head_size: int", "is_neox: bool"})
.SetInplaceMap({{"query", "query_out"}, {"key", "key_out"}})
.SetKernelFn(PD_KERNEL(FusedRotaryPositionEncoding));

View File

@@ -0,0 +1,98 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "xpu/plugin.h"
#include <xft/xdnn_plugin.h>
namespace xftkernel = baidu::xpu::xftkernel;
std::vector<paddle::Tensor> GatherNextToken(const paddle::Tensor& tmp_out, // [token_num, dim_embed]
const paddle::Tensor& cum_offsets, // [bsz, 1]
const paddle::Tensor& encoder_seq_lod,
const paddle::Tensor& encoder_batch_map,
const paddle::Tensor& decoder_batch_map,
const paddle::Tensor& encoder_seq_lod_cpu,
const paddle::Tensor& encoder_batch_map_cpu,
const paddle::Tensor& decoder_batch_map_cpu,
const paddle::Tensor& enc_batch_tensor,
const paddle::Tensor& dec_batch_tensor,
const paddle::optional<paddle::Tensor>& output_padding_offset,
int max_input_length) {
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
using XPUType = typename XPUTypeTrait<bfloat16>::Type; // only support bfloat16
typedef paddle::bfloat16 data_t;
const int dim = tmp_out.dims()[1];
const int bsz = cum_offsets.shape()[0];
int enc_batch = enc_batch_tensor.data<int32_t>()[0];
int dec_batch = dec_batch_tensor.data<int32_t>()[0];
baidu::xpu::api::VectorParam<int32_t> encoder_seqs_lods_vp{const_cast<int32_t*>(encoder_seq_lod_cpu.data<int32_t>()), enc_batch + 1, const_cast<int32_t*>(encoder_seq_lod.data<int32_t>())};
baidu::xpu::api::VectorParam<int32_t> encoder_batch_map_vp{const_cast<int32_t*>(encoder_batch_map_cpu.data<int32_t>()), enc_batch, const_cast<int32_t*>(encoder_batch_map.data<int32_t>())};
baidu::xpu::api::VectorParam<int32_t> decoder_batch_map_vp{const_cast<int32_t*>(decoder_batch_map_cpu.data<int32_t>()), dec_batch, const_cast<int32_t*>(decoder_batch_map.data<int32_t>())};
auto out = paddle::full({bsz, dim}, -2, tmp_out.type(), tmp_out.place());
int r = xftkernel::xft_eb_gather_next_token<XPUType, XPUType>(
xpu_ctx->x_context(),
reinterpret_cast<const XPUType*>(tmp_out.data<data_t>()),
reinterpret_cast<XPUType*>(out.data<data_t>()),
encoder_seqs_lods_vp,
encoder_batch_map_vp,
decoder_batch_map_vp,
dim);
return {out};
}
std::vector<std::vector<int64_t>> GatherNextTokenInferShape(const std::vector<int64_t>& tmp_out_shape,
const std::vector<int64_t>& cum_offsets_shape,
const std::vector<int64_t>& encoder_seq_lod_shape,
const std::vector<int64_t>& encoder_batch_map_shape,
const std::vector<int64_t>& decoder_batch_map_shape,
const std::vector<int64_t>& encoder_seq_lod_cpu_shape,
const std::vector<int64_t>& encoder_batch_map_cpu_shape,
const std::vector<int64_t>& decoder_batch_map_cpu_shape,
const std::vector<int64_t>& enc_batch_tensor_shape,
const std::vector<int64_t>& dec_batch_tensor_shape,
const paddle::optional<std::vector<int64_t>>& output_padding_offset_shape) {
if (output_padding_offset_shape) {
PD_THROW("speculative decoding is not supported in XPU.");
}
int64_t bsz = cum_offsets_shape[0];
int64_t dim_embed = tmp_out_shape[1];
return {{bsz, dim_embed}};
}
std::vector<paddle::DataType> GatherNextTokenInferDtype(const paddle::DataType& tmp_out_dtype,
const paddle::DataType& cum_offsets_dtype,
const paddle::DataType& encoder_seq_lod_dtype,
const paddle::DataType& encoder_batch_map_dtype,
const paddle::DataType& decoder_batch_map_dtype,
const paddle::DataType& encoder_seq_lod_cpu_dtype,
const paddle::DataType& encoder_batch_map_cpu_dtype,
const paddle::DataType& decoder_batch_map_cpu_dtype,
const paddle::DataType& enc_batch_tensor_dtype,
const paddle::DataType& dec_batch_tensor_dtype,
const paddle::optional<paddle::DataType>& output_padding_offset_dtype) {
return {tmp_out_dtype};
}
PD_BUILD_OP(gather_next_token)
.Inputs({"tmp_out", "cum_offsets", "encoder_seq_lod", "encoder_batch_map", "decoder_batch_map","encoder_seq_lod_cpu", "encoder_batch_map_cpu", "decoder_batch_map_cpu", "enc_batch_tensor", "dec_batch_tensor", paddle::Optional("output_padding_offset")})
.Outputs({"out"})
.Attrs({"max_input_length: int"})
.SetKernelFn(PD_KERNEL(GatherNextToken))
.SetInferShapeFn(PD_INFER_SHAPE(GatherNextTokenInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(GatherNextTokenInferDtype));

View File

@@ -0,0 +1,196 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "xpu/plugin.h"
#include <xft/xdnn_plugin.h>
namespace xftkernel = baidu::xpu::xftkernel;
std::vector<paddle::Tensor> GetInferParam(const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder) {
baidu::xpu::api::plugin::print_times("[TIME BEGIN] GetInferParam" );
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
const int bsz = seq_lens_encoder.dims()[0];
// 判断逻辑
std::vector<int32_t> seq_lens_encoder_vec(bsz, 0); // input
std::vector<int32_t> seq_lens_decoder_vec(bsz, 0); // input
std::vector<int32_t> encoder_batch_map_vec(bsz, 0); //
std::vector<int32_t> decoder_batch_map_vec(bsz, 0); //
std::vector<int32_t> encoder_batch_idx_vec(bsz, 0); // 去除空隙的batch map
std::vector<int32_t> decoder_batch_idx_vec(bsz, 0); // 去除空隙的batch map
std::vector<int32_t> encoder_seq_lod_vec(bsz + 1, 0);
std::vector<int32_t> decoder_context_len_vec(bsz, 0);
std::vector<int32_t> decoder_context_len_cache_vec(bsz, 0);
xpu_wait(xpu_ctx->x_context()->xpu_stream); // 是否需要!!!!TODO
int r = xpu_memcpy(seq_lens_encoder_vec.data(),
seq_lens_encoder.data<int32_t>(),
sizeof(int32_t) * bsz,
XPUMemcpyKind::XPU_DEVICE_TO_HOST);
r = xpu_memcpy(seq_lens_decoder_vec.data(),
seq_lens_decoder.data<int32_t>(),
sizeof(int32_t) * bsz,
XPUMemcpyKind::XPU_DEVICE_TO_HOST);
int enc_batch = 0, dec_batch = 0;
int total_enc_len = 0;
int batch_offset = 0;
for(int i = 0; i < bsz; ++i){
if(seq_lens_encoder_vec[i] > 0){
enc_batch++;
total_enc_len += seq_lens_encoder_vec[i];
encoder_batch_map_vec[enc_batch - 1] = i;
encoder_batch_idx_vec[enc_batch - 1] = i - batch_offset;
encoder_seq_lod_vec[enc_batch] = seq_lens_encoder_vec[i] + encoder_seq_lod_vec[enc_batch - 1];
}
else if(seq_lens_decoder_vec[i] > 0){
dec_batch++;
decoder_batch_map_vec[dec_batch - 1] = i;
decoder_batch_idx_vec[dec_batch - 1] = i - batch_offset;
decoder_context_len_vec[dec_batch - 1] = seq_lens_decoder_vec[i] + 1;
decoder_context_len_cache_vec[dec_batch - 1] = seq_lens_decoder_vec[i];
}
else{
batch_offset++;
}
}
auto encoder_batch_map_xpu = paddle::full({encoder_batch_map_vec.size()}, 0, seq_lens_encoder.type(), seq_lens_encoder.place());
auto decoder_batch_map_xpu = paddle::full({decoder_batch_map_vec.size()}, 0, seq_lens_encoder.type(), seq_lens_encoder.place());
auto encoder_batch_idx_xpu = paddle::full({encoder_batch_idx_vec.size()}, 0, seq_lens_encoder.type(), seq_lens_encoder.place());
auto decoder_batch_idx_xpu = paddle::full({decoder_batch_idx_vec.size()}, 0, seq_lens_encoder.type(), seq_lens_encoder.place());
auto encoder_seq_lod_xpu = paddle::full({encoder_seq_lod_vec.size()}, 0, seq_lens_encoder.type(), seq_lens_encoder.place());
auto decoder_context_len_xpu = paddle::full({decoder_context_len_vec.size()}, 0, seq_lens_encoder.type(), seq_lens_encoder.place());
auto decoder_context_len_cache_xpu = paddle::full({decoder_context_len_cache_vec.size()}, 0, seq_lens_encoder.type(), seq_lens_encoder.place());
auto encoder_batch_map_cpu = paddle::full({encoder_batch_map_vec.size()}, 0, seq_lens_encoder.type(), paddle::CPUPlace());
auto decoder_batch_map_cpu = paddle::full({decoder_batch_map_vec.size()}, 0, seq_lens_encoder.type(), paddle::CPUPlace());
auto encoder_batch_idx_cpu = paddle::full({encoder_batch_idx_vec.size()}, 0, seq_lens_encoder.type(), paddle::CPUPlace());
auto decoder_batch_idx_cpu = paddle::full({decoder_batch_idx_vec.size()}, 0, seq_lens_encoder.type(), paddle::CPUPlace());
auto encoder_seq_lod_cpu = paddle::full({encoder_seq_lod_vec.size()}, 0, seq_lens_encoder.type(), paddle::CPUPlace());
auto decoder_context_len_cpu = paddle::full({decoder_context_len_vec.size()}, 0, seq_lens_encoder.type(), paddle::CPUPlace());
auto decoder_context_len_cache_cpu = paddle::full({decoder_context_len_cache_vec.size()}, 0, seq_lens_encoder.type(), paddle::CPUPlace());
int ret = 0;
ret = xpu_memcpy(reinterpret_cast<int32_t*>(const_cast<int32_t*>(encoder_batch_map_xpu.data<int32_t>())), encoder_batch_map_vec.data(), sizeof(int32_t) * encoder_batch_map_vec.size(), XPUMemcpyKind::XPU_HOST_TO_DEVICE);
ret = xpu_memcpy(reinterpret_cast<int32_t*>(const_cast<int32_t*>(decoder_batch_map_xpu.data<int32_t>())), decoder_batch_map_vec.data(), sizeof(int32_t) * decoder_batch_map_vec.size(), XPUMemcpyKind::XPU_HOST_TO_DEVICE);
ret = xpu_memcpy(reinterpret_cast<int32_t*>(const_cast<int32_t*>(encoder_batch_idx_xpu.data<int32_t>())), encoder_batch_idx_vec.data(), sizeof(int32_t) * encoder_batch_idx_vec.size(), XPUMemcpyKind::XPU_HOST_TO_DEVICE);
ret = xpu_memcpy(reinterpret_cast<int32_t*>(const_cast<int32_t*>(decoder_batch_idx_xpu.data<int32_t>())), decoder_batch_idx_vec.data(), sizeof(int32_t) * decoder_batch_idx_vec.size(), XPUMemcpyKind::XPU_HOST_TO_DEVICE);
ret = xpu_memcpy(reinterpret_cast<int32_t*>(const_cast<int32_t*>(encoder_seq_lod_xpu.data<int32_t>())), encoder_seq_lod_vec.data(), sizeof(int32_t) * encoder_seq_lod_vec.size(), XPUMemcpyKind::XPU_HOST_TO_DEVICE);
ret = xpu_memcpy(reinterpret_cast<int32_t*>(const_cast<int32_t*>(decoder_context_len_xpu.data<int32_t>())), decoder_context_len_vec.data(), sizeof(int32_t) * decoder_context_len_vec.size(), XPUMemcpyKind::XPU_HOST_TO_DEVICE);
ret = xpu_memcpy(reinterpret_cast<int32_t*>(const_cast<int32_t*>(decoder_context_len_cache_xpu.data<int32_t>())), decoder_context_len_cache_vec.data(), sizeof(int32_t) * decoder_context_len_cache_vec.size(), XPUMemcpyKind::XPU_HOST_TO_DEVICE);
std::memcpy(encoder_batch_map_cpu.data<int32_t>(), encoder_batch_map_vec.data(), sizeof(int32_t) * encoder_batch_map_vec.size());
std::memcpy(decoder_batch_map_cpu.data<int32_t>(), decoder_batch_map_vec.data(), sizeof(int32_t) * decoder_batch_map_vec.size());
std::memcpy(encoder_batch_idx_cpu.data<int32_t>(), encoder_batch_idx_vec.data(), sizeof(int32_t) * encoder_batch_idx_vec.size());
std::memcpy(decoder_batch_idx_cpu.data<int32_t>(), decoder_batch_idx_vec.data(), sizeof(int32_t) * decoder_batch_idx_vec.size());
std::memcpy(encoder_seq_lod_cpu.data<int32_t>(), encoder_seq_lod_vec.data(), sizeof(int32_t) * encoder_seq_lod_vec.size());
std::memcpy(decoder_context_len_cpu.data<int32_t>(), decoder_context_len_vec.data(), sizeof(int32_t) * decoder_context_len_vec.size());
std::memcpy(decoder_context_len_cache_cpu.data<int32_t>(), decoder_context_len_cache_vec.data(), sizeof(int32_t) * decoder_context_len_cache_vec.size());
// auto batch_tensor = paddle::full({3}, 0, seq_lens_encoder.type(), paddle::CPUPlace());
// auto batch_tensor_data = const_cast<int32_t*>(batch_tensor.data<int32_t>());
// batch_tensor_data[0] = enc_batch;
// batch_tensor_data[1] = dec_batch;
// batch_tensor_data[2] = encoder_seq_lod_vec[enc_batch];
auto enc_batch_tensor = paddle::full({1}, enc_batch, seq_lens_encoder.type(), paddle::CPUPlace());
auto dec_batch_tensor = paddle::full({1}, dec_batch, seq_lens_encoder.type(), paddle::CPUPlace());
auto total_enc_len_tensor = paddle::full({1}, total_enc_len, seq_lens_encoder.type(), paddle::CPUPlace());
baidu::xpu::api::plugin::print_times("[TIME END] GetInferParam" );
return {encoder_batch_map_xpu,
decoder_batch_map_xpu,
encoder_batch_idx_xpu,
decoder_batch_idx_xpu,
encoder_seq_lod_xpu,
decoder_context_len_xpu,
decoder_context_len_cache_xpu,
encoder_batch_map_cpu,
decoder_batch_map_cpu,
encoder_batch_idx_cpu,
decoder_batch_idx_cpu,
encoder_seq_lod_cpu,
decoder_context_len_cpu,
decoder_context_len_cache_cpu,
enc_batch_tensor,
dec_batch_tensor,
total_enc_len_tensor};
}
std::vector<std::vector<int64_t>> GetInferParamInferShape(const std::vector<int64_t>& seq_lens_encoder_shape,
const std::vector<int64_t>& seq_lens_decoder_shape) {
return {seq_lens_encoder_shape,
seq_lens_encoder_shape,
seq_lens_encoder_shape,
seq_lens_encoder_shape,
{seq_lens_encoder_shape[0] + 1},
seq_lens_encoder_shape,
seq_lens_encoder_shape,
seq_lens_encoder_shape,
seq_lens_encoder_shape,
seq_lens_encoder_shape,
seq_lens_encoder_shape,
seq_lens_encoder_shape,
seq_lens_encoder_shape,
seq_lens_encoder_shape,
{1},{1},{1}};
}
std::vector<paddle::DataType> GetInferParamInferDtype(const paddle::DataType& seq_lens_encoder_dtype,
const paddle::DataType& seq_lens_decoder_dtype) {
return {seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype,
seq_lens_encoder_dtype};
}
PD_BUILD_OP(get_infer_param)
.Inputs({"seq_lens_encoder", "seq_lens_decoder"})
.Outputs({"encoder_batch_map_xpu",
"decoder_batch_map_xpu",
"encoder_batch_idx_xpu",
"decoder_batch_idx_xpu",
"encoder_seq_lod_xpu",
"decoder_context_len_xpu",
"decoder_context_len_cache_xpu",
"encoder_batch_map_cpu",
"decoder_batch_map_cpu",
"encoder_batch_idx_cpu",
"decoder_batch_idx_cpu",
"encoder_seq_lod_cpu",
"decoder_context_len_cpu",
"decoder_context_len_cache_cpu",
"enc_batch_tensor",
"dec_batch_tensor",
"total_enc_len_tensor"})
.SetKernelFn(PD_KERNEL(GetInferParam))
.SetInferShapeFn(PD_INFER_SHAPE(GetInferParamInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(GetInferParamInferDtype));

View File

@@ -0,0 +1,70 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include "paddle/extension.h"
#define MAX_BSZ 512
struct msgdata {
long mtype;
int mtext[MAX_BSZ + 2]; // stop_flag, bsz, tokens
};
void GetOutput(const paddle::Tensor& x,
const paddle::Tensor& msg_queue_id,
int64_t rank_id,
bool wait_flag) {
if (rank_id > 0) return;
static struct msgdata msg_rcv;
int msg_queue_id_val = msg_queue_id.data<int>()[0];
static key_t key = ftok("./", msg_queue_id_val);
static int msgid = msgget(key, IPC_CREAT | 0666);
int64_t *out_data = const_cast<int64_t*>(x.data<int64_t>());
int ret = -1;
if (!wait_flag) {
ret = msgrcv(msgid, &msg_rcv, (MAX_BSZ + 2) * 4, 0, IPC_NOWAIT);
} else {
ret = msgrcv(msgid, &msg_rcv, (MAX_BSZ + 2) * 4, 0, 0);
}
if(ret == -1)
{
// read none
out_data[0] = -2;
out_data[1] = 0;
return;
}
int bsz = msg_rcv.mtext[1];
for (int64_t i = 0; i < bsz + 2; i++) {
out_data[i] = (int64_t)msg_rcv.mtext[i];
}
return;
}
PD_BUILD_OP(get_output)
.Inputs({"x", "msg_queue_id"})
.Attrs({"rank_id: int64_t",
"wait_flag: bool"})
.Outputs({"x_out"})
.SetInplaceMap({{"x", "x_out"}})
.SetKernelFn(PD_KERNEL(GetOutput));

View File

@@ -16,10 +16,15 @@
#include "paddle/extension.h"
#include "xpu/plugin.h"
std::vector<paddle::Tensor> GetPaddingOffset(const paddle::Tensor& input_ids,
std::vector<paddle::Tensor> GetPaddingOffsetV2(const paddle::Tensor& input_ids,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& token_num,
const paddle::Tensor& seq_len) {
const paddle::Tensor& seq_len,
const paddle::optional<paddle::Tensor>& draft_tokens,
const paddle::optional<paddle::Tensor>& seq_lens_encoder) {
if (draft_tokens) {
PD_THROW("speculative decoding is not supported in XPU.");
}
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
@@ -60,35 +65,29 @@ std::vector<paddle::Tensor> GetPaddingOffset(const paddle::Tensor& input_ids,
cu_seqlens_k};
}
std::vector<std::vector<int64_t>> GetPaddingOffsetInferShape(
const std::vector<int64_t>& input_ids_shape,
const std::vector<int64_t>& cum_offsets_shape,
const std::vector<int64_t>& token_num_shape,
const std::vector<int64_t>& seq_len_shape) {
int64_t bsz = seq_len_shape[0];
int64_t seq_len = input_ids_shape[1];
return {{-1}, {bsz}, {-1}, {bsz + 1}, {bsz + 1}};
std::vector<std::vector<int64_t>> GetPaddingOffsetV2InferShape(const std::vector<int64_t>& input_ids_shape,
const std::vector<int64_t>& cum_offsets_shape,
const std::vector<int64_t>& token_num_shape,
const std::vector<int64_t>& seq_len_shape,
const std::vector<int64_t>& draft_tokens_shape,
const std::vector<int64_t>& seq_lens_encoder_shape) {
int64_t bsz = seq_len_shape[0];
int64_t seq_len = input_ids_shape[1];
return {{-1}, {bsz}, {-1}, {bsz + 1}, {bsz + 1}};
}
std::vector<paddle::DataType> GetPaddingOffsetInferDtype(
const paddle::DataType& input_ids_dtype,
const paddle::DataType& cum_offsets_dtype,
const paddle::DataType& token_num_dtype,
const paddle::DataType& seq_len_dtype) {
return {input_ids_dtype,
seq_len_dtype,
seq_len_dtype,
seq_len_dtype,
seq_len_dtype};
std::vector<paddle::DataType> GetPaddingOffsetV2InferDtype(const paddle::DataType& input_ids_dtype,
const paddle::DataType& cum_offsets_dtype,
const paddle::DataType& token_num_dtype,
const paddle::DataType& seq_len_dtype,
const paddle::DataType& draft_tokens_dtype,
const paddle::DataType& seq_lens_encoder_dtype) {
return {input_ids_dtype, seq_len_dtype, seq_len_dtype, seq_len_dtype, seq_len_dtype};
}
PD_BUILD_OP(get_padding_offset_v2)
.Inputs({"input_ids", "token_num", "cum_offsets", "seq_len"})
.Outputs({"x_remove_padding",
"cum_offsets_out",
"padding_offset",
"cu_seqlens_q",
"cu_seqlens_k"})
.SetKernelFn(PD_KERNEL(GetPaddingOffset))
.SetInferShapeFn(PD_INFER_SHAPE(GetPaddingOffsetInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(GetPaddingOffsetInferDtype));
.Inputs({"input_ids", "cum_offsets", "token_num", "seq_len", paddle::Optional("draft_tokens"), paddle::Optional("seq_lens_encoder"),})
.Outputs({"x_remove_padding", "cum_offsets_out", "padding_offset", "cu_seqlens_q", "cu_seqlens_k"})
.SetKernelFn(PD_KERNEL(GetPaddingOffsetV2))
.SetInferShapeFn(PD_INFER_SHAPE(GetPaddingOffsetV2InferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(GetPaddingOffsetV2InferDtype));

View File

@@ -0,0 +1,53 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
#include <xft/xdnn_plugin.h>
#include "xblas_legacy_api.h"
namespace xftkernel = baidu::xpu::xftkernel;
namespace api = baidu::xpu::api;
// namespace xblas = baidu::xpu::xblas;
void GetPositionIdsKernel(
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& seq_lens_this_time,
const paddle::Tensor& position_ids) {
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
const int bs = seq_lens_encoder.shape()[0];
int ret = baidu::xpu::api::plugin::get_position_ids(
xpu_ctx->x_context(),
seq_lens_encoder.data<int32_t>(),
seq_lens_decoder.data<int32_t>(),
seq_lens_this_time.data<int32_t>(),
const_cast<int32_t*>(position_ids.data<int32_t>()),
bs
);
PD_CHECK(ret == 0, "api::plugin::get_position_ids failed");
}
PD_BUILD_OP(get_position_ids)
.Inputs({"seq_lens_encoder", "seq_lens_decoder", "seq_lens_this_time", "position_ids"})
.Outputs({"position_ids_out"})
.SetInplaceMap({{"position_ids", "position_ids_out"}})
.SetKernelFn(PD_KERNEL(GetPositionIdsKernel));

View File

@@ -0,0 +1,82 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
#include <xft/xdnn_plugin.h>
#include "xblas_legacy_api.h"
namespace xftkernel = baidu::xpu::xftkernel;
namespace api = baidu::xpu::api;
// namespace xblas = baidu::xpu::xblas;
std::vector<paddle::Tensor> GetPositionIdsKernelV2(
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& seq_lens_this_time) {
baidu::xpu::api::plugin::print_times("[TIME BEGIN] GetPositionIdsKernelV2" );
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
const int bs = seq_lens_this_time.shape()[0];
std::vector<int> seq_lens_this_time_cpu(bs, 0);
int r = xpu_memcpy(seq_lens_this_time_cpu.data(),
seq_lens_this_time.data<int>(),
sizeof(int32_t) * bs,
XPUMemcpyKind::XPU_DEVICE_TO_HOST);
int total_len = 0;
for (int i = 0; i < bs; ++i) {
total_len += seq_lens_this_time_cpu[i];
}
auto position_ids_out = paddle::full({total_len}, 0, seq_lens_encoder.type(), seq_lens_encoder.place());
int ret = baidu::xpu::api::plugin::get_position_ids(
xpu_ctx->x_context(),
seq_lens_encoder.data<int32_t>(),
seq_lens_decoder.data<int32_t>(),
seq_lens_this_time.data<int32_t>(),
const_cast<int32_t*>(position_ids_out.data<int32_t>()),
bs
);
PD_CHECK(ret == 0, "api::plugin::get_position_ids failed");
baidu::xpu::api::plugin::print_times("[TIME END] GetPositionIdsKernelV2" );
return {position_ids_out};
}
std::vector<std::vector<int64_t>> GetPositionIdsV2InferShape(const std::vector<int64_t>& seq_lens_encoder,
const std::vector<int64_t>& seq_lens_decoder,
const std::vector<int64_t>& seq_lens_this_time) {
return {{-1}};
}
std::vector<paddle::DataType> GetPositionIdsV2InferDtype(const paddle::DataType& seq_lens_encoder_dtype,
const paddle::DataType& seq_lens_decoder_dtype,
const paddle::DataType& seq_lens_this_time_dtype) {
return {seq_lens_encoder_dtype};
}
PD_BUILD_OP(get_position_ids_v2)
.Inputs({"seq_lens_encoder", "seq_lens_decoder", "seq_lens_this_time"})
.Outputs({"position_ids_out"})
.SetKernelFn(PD_KERNEL(GetPositionIdsKernelV2))
.SetInferShapeFn(PD_INFER_SHAPE(GetPositionIdsV2InferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(GetPositionIdsV2InferDtype));;

View File

@@ -27,6 +27,7 @@ void TokenPenaltyMultiScores(const paddle::Tensor& pre_ids,
const paddle::Tensor& cur_len,
const paddle::Tensor& min_len,
const paddle::Tensor& eos_token_id) {
baidu::xpu::api::plugin::print_times("[TIME BEGIN] TokenPenaltyMultiScores");
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
@@ -90,8 +91,11 @@ void TokenPenaltyMultiScores(const paddle::Tensor& pre_ids,
"Only float16 and float32 are supported. ");
break;
}
baidu::xpu::api::plugin::print_times("[TIME END] TokenPenaltyMultiScores");
}
PD_BUILD_OP(get_token_penalty_multi_scores_v2)
.Inputs({"pre_ids",
"logits",

View File

@@ -0,0 +1,604 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
#include <core/ctx_manager.h>
#include <core/xft_check.h>
#include <core/xft_event.h>
#include <core/xft_params.h>
#include <xft/xdnn_plugin.h>
#include <xft/operation/page_attn.h>
#include <xft/operation/fmha.h>
#include <flash_api.h> // link xfa
namespace xftkernel = baidu::xpu::xftkernel;
template <typename T>
struct kl3_pa_TL_trait {
using TL = T;
};
template <>
struct kl3_pa_TL_trait<bfloat16> {
using TL = float;
};
std::vector<paddle::Tensor> MlaAttn(
const paddle::Tensor& q,
const paddle::Tensor& k,
const paddle::Tensor& v,
const paddle::Tensor& key_cache,
const paddle::Tensor& value_cache,
const paddle::Tensor& seq_lens_encoder,
const paddle::Tensor& seq_lens_decoder,
const paddle::Tensor& seq_lens_this_time,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const paddle::Tensor& encoder_batch_ids,
const paddle::Tensor& encoder_tile_ids_per_batch,
const paddle::Tensor& encoder_num_blocks,
const paddle::Tensor& kv_batch_ids,
const paddle::Tensor& kv_tile_ids_per_batch,
const paddle::Tensor& kv_num_blocks,
const paddle::Tensor& decoder_batch_ids,
const paddle::Tensor& decoder_tile_ids_per_batch,
const paddle::Tensor& decoder_num_blocks,
const paddle::Tensor& max_enc_len_this_time,
const paddle::Tensor& max_dec_len_this_time,
const paddle::Tensor& max_len_kv,
const paddle::optional<paddle::Tensor>& rotary_embs,
const paddle::optional<paddle::Tensor>& attn_mask,
const paddle::optional<paddle::Tensor>& qkv_bias,
const paddle::optional<paddle::Tensor>& qkv_out_scales,
const paddle::optional<paddle::Tensor>& cache_k_quant_scales,
const paddle::optional<paddle::Tensor>& cache_v_quant_scales,
const paddle::optional<paddle::Tensor>& cache_k_dequant_scales,
const paddle::optional<paddle::Tensor>& cache_v_dequant_scales,
const paddle::optional<paddle::Tensor>& cache_k_zp,
const paddle::optional<paddle::Tensor>& cache_v_zp,
const paddle::optional<paddle::Tensor>& out_linear_shifts,
const paddle::optional<paddle::Tensor>& out_linear_smooths,
const std::string& cache_quant_type_str,
const bool use_neox_rotary_style,
const int max_input_length,
const float softmax_scale,
const float quant_max_bound,
const float quant_min_bound,
const float out_linear_in_scale,
const int speculate_max_draft_token_num,
const bool causal,
const bool speculate_decoder) {
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
xpu::ctx_guard RAII_GUARD(xpu_ctx->x_context());
using QType = typename XPUTypeTrait<bfloat16>::Type;
using CacheType = typename XPUTypeTrait<bfloat16>::Type;
typedef paddle::bfloat16 qdata_t, cache_t;
const auto& input_dims = q.dims();
const auto& key_cache_dims = key_cache.dims();
const auto& value_cache_dims = value_cache.dims();
const int bsz = seq_lens_encoder.dims()[0];
const int token_num = input_dims[0];
const int num_head = key_cache_dims[1];
const int dim_qk = key_cache_dims[3];
const int dim_v = value_cache_dims[3];
const int block_batch = block_tables.dims()[0]; // TODO参数含义 block_batch_ PageParam page_param_
const int max_block_per_seq = block_tables.dims()[1];
const int block_size = key_cache_dims[2];
const int max_seq_len = block_size * max_block_per_seq;
// 初始化输入:q k v
auto q_xft = baidu::xpu::xft::xftTensor<QType, 2>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(q.data<qdata_t>())),
std::array<int64_t, 2>{q.shape()[0],
q.shape()[1]});
auto k_xft = baidu::xpu::xft::xftTensor<QType, 2>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(k.data<qdata_t>())),
std::array<int64_t, 2>{k.shape()[0],
k.shape()[1]});
auto v_xft = baidu::xpu::xft::xftTensor<QType, 2>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(v.data<qdata_t>())),
std::array<int64_t, 2>{v.shape()[0],
v.shape()[1]});
// 初始化输入:k cache
auto key_cache_xft = baidu::xpu::xft::xftTensor<CacheType, 4>(
reinterpret_cast<CacheType*>(const_cast<paddle::bfloat16*>(key_cache.data<cache_t>())),
std::array<int64_t, 4>{key_cache.shape()[0],
key_cache.shape()[1],
key_cache.shape()[2],
key_cache.shape()[3]});
// 初始化输入:v cache
auto value_cache_xft = baidu::xpu::xft::xftTensor<CacheType, 4>(
reinterpret_cast<CacheType*>(const_cast<paddle::bfloat16*>(value_cache.data<cache_t>())),
std::array<int64_t, 4>{value_cache.shape()[0],
value_cache.shape()[1],
value_cache.shape()[2],
value_cache.shape()[3]});
// 初始化输入:block table
auto block_tables_xft = baidu::xpu::xft::xftTensor<int, 2>(
reinterpret_cast<int*>(const_cast<int*>(block_tables.data<int>())),
std::array<int64_t, 2>{block_tables.shape()[0],
block_tables.shape()[1]});
// 初始化输出tensor
auto fmha_out = paddle::full({q.shape()[0], num_head * dim_v}, -2, q.type(), q.place());
auto fmha_out_xft = baidu::xpu::xft::xftTensor<QType, 2>(
reinterpret_cast<QType*>(const_cast<paddle::bfloat16*>(fmha_out.data<qdata_t>())),
std::array<int64_t, 2>{fmha_out.shape()[0],
fmha_out.shape()[1]});
// encoder 判断逻辑
std::vector<int> seq_lens_encoder_cpu(bsz, 0);
std::vector<int> seq_lens_decoder_cpu(bsz, 0);
std::vector<int> encoder_batch_map; //
std::vector<int> decoder_batch_map; //
std::vector<int> encoder_batch_idx; // 去除空隙的batch map
std::vector<int> decoder_batch_idx; // 去除空隙的batch map
std::vector<int> encoder_seq_lod;
std::vector<int> decoder_context_len;
std::vector<int> decoder_context_len_cache;
xpu_wait(xpu_ctx->x_context()->xpu_stream); // 是否需要!!!!TODO
int r = xpu_memcpy(seq_lens_encoder_cpu.data(),
seq_lens_encoder.data<int>(),
sizeof(int32_t) * bsz,
XPUMemcpyKind::XPU_DEVICE_TO_HOST);
r = xpu_memcpy(seq_lens_decoder_cpu.data(),
seq_lens_decoder.data<int>(),
sizeof(int32_t) * bsz,
XPUMemcpyKind::XPU_DEVICE_TO_HOST);
int enc_batch = 0, dec_batch = 0;
int64_t total_enc_len = 0;
int batch_offset = 0;
encoder_seq_lod.push_back(0);
for(int i = 0; i < bsz; ++i){
if(seq_lens_encoder_cpu[i] > 0){
enc_batch++;
total_enc_len += seq_lens_encoder_cpu[i];
encoder_batch_map.push_back(i);
encoder_batch_idx.push_back(i - batch_offset);
encoder_seq_lod.push_back(seq_lens_encoder_cpu[i]);
encoder_seq_lod[enc_batch] += encoder_seq_lod[enc_batch - 1];
}
else if(seq_lens_decoder_cpu[i] > 0){
dec_batch++;
decoder_batch_map.push_back(i);
decoder_batch_idx.push_back(i - batch_offset);
decoder_context_len.push_back(seq_lens_decoder_cpu[i] + 1);
decoder_context_len_cache.push_back(seq_lens_decoder_cpu[i]);
}
else{
batch_offset++;
}
}
// encoder
if(max_enc_len_this_time.data<int>()[0] > 0){
// q_lod
baidu::xpu::api::VectorParam<int32_t> context_len_vp =
baidu::xpu::api::VectorParam<int32_t>{encoder_seq_lod.data(), enc_batch + 1, nullptr}
.to_xpu(RAII_GUARD);
// real batch(encoder阶段 kv cache写需要)
baidu::xpu::api::VectorParam<int32_t> valid_batch_vp =
baidu::xpu::api::VectorParam<int32_t>{encoder_batch_map.data(), enc_batch, nullptr}
.to_xpu(RAII_GUARD);
// prefix (not support)
baidu::xpu::api::VectorParam<int32_t> prefix_lens_vp = baidu::xpu::api::VectorParam<int32_t>();
// kv_lod (非prefix cache情况与q_lod一致)
baidu::xpu::api::VectorParam<int32_t> encoder_kv_lods_vp =
baidu::xpu::api::VectorParam<int32_t>{encoder_seq_lod.data(), enc_batch + 1, nullptr}
.to_xpu(RAII_GUARD);
// page_param_
baidu::xpu::xft::PageParam page_param_(block_batch, // block_batch_
max_enc_len_this_time.data<int>()[0], // max_enc_len_this_time.data<int>()[0],max_seq_len // max_context_len_
block_size, // block_size_
max_block_per_seq, // max_num_blocks_per_seq_
false); // v_trans
// attn_param
baidu::xpu::xft::PageAttnParam attn_param_(dim_qk, // head_dim(q,k)
num_head, // q_head_num
num_head, // kv_head_num
false, // vp_lod_flag
context_len_vp, // context_len_vp
valid_batch_vp, // valid_batch_vp
prefix_lens_vp, // prefix_lens_vp
encoder_kv_lods_vp); // encoder_kv_lods_vp
// k v cache write
std::vector<int> start_tokens(enc_batch, 0);
baidu::xpu::api::VectorParam<int32_t> start_tokens_vp =
baidu::xpu::api::VectorParam<int32_t>{start_tokens.data(), enc_batch, nullptr}.to_xpu(RAII_GUARD);
int ret_cache = xftkernel::xft_reshape_cached_kv<float16, float16, int>(
xpu_ctx->x_context(),
reinterpret_cast<float16*>(k_xft.data()),
reinterpret_cast<float16*>(key_cache_xft.data()),
block_tables_xft.data(),
context_len_vp,
start_tokens_vp,
valid_batch_vp,
enc_batch,
num_head,
dim_qk,
block_batch,
block_size,
max_block_per_seq,
"BLHD", // qkv_layout,
"HLD", // page_layout,
nullptr, // scale,
nullptr, // batch_max_ptrs,
nullptr); // max_ptrs
ret_cache = xftkernel::xft_reshape_cached_kv<float16, float16, int>(
xpu_ctx->x_context(),
reinterpret_cast<float16*>(v_xft.data()),
reinterpret_cast<float16*>(value_cache_xft.data()),
block_tables_xft.data(),
context_len_vp,
start_tokens_vp,
valid_batch_vp,
enc_batch,
num_head,
dim_v,
block_batch,
block_size,
max_block_per_seq,
"BLHD", // qkv_layout,
"HLD", // page_layout,
nullptr, // scale,
nullptr, // batch_max_ptrs,
nullptr); // max_ptrs
// fmha op
using FMHA_Type = typename baidu::xpu::xft::FMHA_QBF16_KVBF16;
// auto fmha_op = baidu::xpu::xft::FMHAOperation<FMHA_Type>(
// enc_batch,
// attn_param_.head_dim_,
// attn_param_.q_head_num_,
// attn_param_.kv_head_num_,
// page_param_.max_context_len_,
// page_param_.max_context_len_,
// attn_param_.context_len_vp_,
// attn_param_.encoder_kv_lods_vp_);
using TQ = typename FMHA_Type::Qtype;
using TK = typename FMHA_Type::Ktype;
using TV = typename FMHA_Type::Vtype;
using TBIAS = typename FMHA_Type::Btype;
using TO = typename FMHA_Type::Otype;
using TMASK = typename FMHA_Type::Mtype;
int ret = baidu::xpu::xfa::flash_attention_context_vllm<
TQ,
TK,
TV,
TBIAS,
TO,
float, // T_GEMM0
float, // T_GEMM1
float, // T_EW
int,
0>(
xpu_ctx->x_context(),
q_xft.data(), // q
std::is_same<TK, int8_t>::value ? nullptr : reinterpret_cast<TK*>(k_xft.data()), // k
std::is_same<TK, int8_t>::value ? nullptr : reinterpret_cast<TV*>(v_xft.data()), // v
nullptr, // p_bias == nullptr ? nullptr : p_bias->data(), // mask_bias
fmha_out_xft.data(), //o
enc_batch, // batch_size
page_param_.max_context_len_, // max_seq_q
page_param_.max_context_len_, // max_seq_kv, (prefix cache是会不一样)
attn_param_.q_head_num_,
attn_param_.head_dim_,
attn_param_.kv_head_num_,
nullptr,
attn_param_.context_len_vp_,
attn_param_.encoder_kv_lods_vp_,
{}, // mask_shape_
{}, // alibi_slopes_shape
true, // is_causal_mask_
false, // is_qkv_fusion_
0x0010, // param.qkv_layout_ = AttnQKVLayout_t::ATTN_BLHD
0x10, // vsl_flag_ = VslConverter::FMHA_LVSL
nullptr, // q_maxptr
nullptr, // k_maxptr
nullptr, // v_maxptr
nullptr,
dim_v, // vo_head_dim
nullptr, // p_cache_k->data(),
nullptr, // p_cache_v->data(),
nullptr, // std::is_same<TK, int8_t>::value ? p_kcache_perhead_scale->data() : p_cache_k->max_data(),
nullptr, // std::is_same<TK, int8_t>::value ? p_vcache_perhead_scale->data() : p_cache_v->max_data(),
block_size, // block_size
max_block_per_seq, // max_blocks_per_seq (prefix cache)
page_param_.max_context_len_, // prefill_len
nullptr,
softmax_scale * sqrt(dim_qk)); // block_tables (prefix cache)
// std::cout << "fmha kernel done " <<std::endl;
}
// decoder
if(max_dec_len_this_time.data<int>()[0] > 0){
// context_len
baidu::xpu::api::VectorParam<int32_t> context_len_vp =
baidu::xpu::api::VectorParam<int32_t>{decoder_context_len.data(), dec_batch, nullptr}
.to_xpu(RAII_GUARD);
baidu::xpu::api::VectorParam<int32_t> context_len_vp_cache =
baidu::xpu::api::VectorParam<int32_t>{decoder_context_len_cache.data(), dec_batch, nullptr}
.to_xpu(RAII_GUARD);
// real batch
baidu::xpu::api::VectorParam<int32_t> valid_batch_vp =
baidu::xpu::api::VectorParam<int32_t>{decoder_batch_map.data(), dec_batch, nullptr}
.to_xpu(RAII_GUARD);
// prefix (not support)
baidu::xpu::api::VectorParam<int32_t> prefix_lens_vp = baidu::xpu::api::VectorParam<int32_t>();
// kv_lod (decoder 不需要)
baidu::xpu::api::VectorParam<int32_t> encoder_kv_lods_vp = baidu::xpu::api::VectorParam<int32_t>();
// page_param_
baidu::xpu::xft::PageParam page_param_(block_batch, // block_batch_
max_seq_len, // max_dec_len_this_time.data<int>()[0],max_seq_len // max_context_len_ // max_dec_len_this_time.data<int>()[0]
block_size, // block_size_
max_block_per_seq, // max_num_blocks_per_seq_
false); // v_trans
// attn_param
baidu::xpu::xft::PageAttnParam attn_param_(dim_qk, // head_dim(q,k)
num_head, // q_head_num
num_head, // kv_head_num
false, // vp_lod_flag
context_len_vp, // context_len_vp
valid_batch_vp, // valid_batch_vp
prefix_lens_vp, // prefix_lens_vp
encoder_kv_lods_vp); // encoder_kv_lods_vp
// k v cache write
std::vector<int> kv_seq_lod(dec_batch + 1);
std::iota(kv_seq_lod.begin(), kv_seq_lod.end(), 0);
baidu::xpu::api::VectorParam<int32_t> kv_seq_lod_vp =
baidu::xpu::api::VectorParam<int32_t>{kv_seq_lod.data(), dec_batch + 1, nullptr}.to_xpu(RAII_GUARD);
int ret_cache = xftkernel::xft_reshape_cached_kv<float16, float16, int>(
xpu_ctx->x_context(),
reinterpret_cast<float16*>(k_xft.data() + total_enc_len * dim_qk * num_head),
reinterpret_cast<float16*>(key_cache_xft.data()),
block_tables_xft.data(),
kv_seq_lod_vp,
context_len_vp_cache,
valid_batch_vp,
dec_batch,
num_head,
dim_qk,
block_batch,
block_size,
max_block_per_seq,
"BLHD", // qkv_layout,
"HLD", // page_layout,
nullptr, // scale,
nullptr, // batch_max_ptrs,
nullptr); // max_ptrs
ret_cache = xftkernel::xft_reshape_cached_kv<float16, float16, int>(
xpu_ctx->x_context(),
reinterpret_cast<float16*>(v_xft.data() + total_enc_len * dim_v * num_head),
reinterpret_cast<float16*>(value_cache_xft.data()),
block_tables_xft.data(),
kv_seq_lod_vp,
context_len_vp_cache,
valid_batch_vp,
dec_batch,
num_head,
dim_v,
block_batch,
block_size,
max_block_per_seq,
"BLHD", // qkv_layout,
"HLD", // page_layout,
nullptr, // scale,
nullptr, // batch_max_ptrs,
nullptr); // max_ptrs
// paged attention op
using PA_Type = typename baidu::xpu::xft::PA_QBF16_KVBF16;
using TQ = typename PA_Type::Qtype; // bfloat16
using TKV = typename PA_Type::KVtype; // bfloat16
using TO = typename PA_Type::Otype; // bfloat16
using TID = typename PA_Type::TIDtype; // int
using TL = float;
using TGEMM0 = float;
using TGEMM1 = float;
using TEW = float;
auto pa_func = &baidu::xpu::xfa::paged_attention_xft<TQ, TKV, TO, TL, TGEMM0, TGEMM1, TEW, TID, false>;
int ret = pa_func(
xpu_ctx->x_context(),
fmha_out_xft.data() + total_enc_len * dim_v * num_head,
q_xft.data() + total_enc_len * dim_qk * num_head,
nullptr, /* k_cur */
nullptr, /* v_cur */
const_cast<TKV*>(key_cache_xft.data()),
const_cast<TKV*>(value_cache_xft.data()),
attn_param_.kv_head_num_,
softmax_scale,
block_tables_xft.data(),
attn_param_.context_len_vp_,
attn_param_.valid_batch_vp_,
page_param_.block_size_,
page_param_.max_context_len_,
nullptr, // (TBIAS*)alibi_slopes,
block_batch, // page_param_.block_batch_,
attn_param_.q_head_num_,
attn_param_.head_dim_,
page_param_.max_num_blocks_per_seq_,
nullptr, // shift,
nullptr, // smooth,
nullptr, // query_maxptr,
nullptr, // key_cache_maxptr,
nullptr, // value_cache_maxptr,
nullptr, // p_k_scales_inv,
nullptr, // p_k_zeros,
nullptr, // p_v_scales_inv,
nullptr, // p_v_zeros,
nullptr, // out_maxptr,
dim_v); // v_head_dim
}
return {fmha_out};
}
std::vector<std::vector<int64_t>> MlaAttnInferShape(
const std::vector<int64_t>& q_shape,
const std::vector<int64_t>& k_shape,
const std::vector<int64_t>& v_shape,
const std::vector<int64_t>& key_cache_shape,
const std::vector<int64_t>& value_cache_shape,
const std::vector<int64_t>& seq_lens_encoder_shape,
const std::vector<int64_t>& seq_lens_decoder_shape,
const std::vector<int64_t>& seq_lens_this_time_shape,
const std::vector<int64_t>& padding_offsets_shape,
const std::vector<int64_t>& cum_offsets_shape,
const std::vector<int64_t>& block_tables_shape,
const std::vector<int64_t>& encoder_batch_ids_shape,
const std::vector<int64_t>& encoder_tile_ids_per_batch_shape,
const std::vector<int64_t>& encoder_num_blocks_shape,
const std::vector<int64_t>& kv_batch_ids_shape,
const std::vector<int64_t>& kv_tile_ids_per_batch_shape,
const std::vector<int64_t>& kv_num_blocks_shape,
const std::vector<int64_t>& decoder_batch_ids_shape,
const std::vector<int64_t>& decoder_tile_ids_per_batch_shape,
const std::vector<int64_t>& decoder_num_blocks_shape,
const std::vector<int64_t>& max_enc_len_this_time_shape,
const std::vector<int64_t>& max_dec_len_this_time_shape,
const std::vector<int64_t>& max_len_kv_shape,
const paddle::optional<std::vector<int64_t>>& rotary_embs_shape,
const paddle::optional<std::vector<int64_t>>& attn_mask_shape,
const paddle::optional<std::vector<int64_t>>& qkv_bias_shape,
const paddle::optional<std::vector<int64_t>>& qkv_out_scales_shape,
const paddle::optional<std::vector<int64_t>>& cache_k_quant_scales_shape,
const paddle::optional<std::vector<int64_t>>& cache_v_quant_scales_shape,
const paddle::optional<std::vector<int64_t>>& cache_k_dequant_scales_shape,
const paddle::optional<std::vector<int64_t>>& cache_v_dequant_scales_shape,
const paddle::optional<std::vector<int64_t>>& cache_k_zp_shape,
const paddle::optional<std::vector<int64_t>>& cache_v_zp_shape,
const paddle::optional<std::vector<int64_t>>& out_linear_shifts_shape,
const paddle::optional<std::vector<int64_t>>& out_linear_smooths_shape) {
const int token_num = q_shape[0];
const int all_v_dim = value_cache_shape[3];
return {{token_num, all_v_dim}};
}
std::vector<paddle::DataType> MlaAttnInferDtype(
const paddle::DataType& q_dtype,
const paddle::DataType& k_dtype,
const paddle::DataType& v_dtype,
const paddle::DataType& key_cache_dtype,
const paddle::DataType& value_cache_dtype,
const paddle::DataType& seq_lens_encoder_dtype,
const paddle::DataType& seq_lens_decoder_dtype,
const paddle::DataType& seq_lens_this_time_dtype,
const paddle::DataType& padding_offsets_dtype,
const paddle::DataType& cum_offsets_dtype,
const paddle::DataType& block_tables_dtype,
const paddle::DataType& encoder_batch_ids_dtype,
const paddle::DataType& encoder_tile_ids_per_batch_dtype,
const paddle::DataType& encoder_num_blocks_dtype,
const paddle::DataType& kv_batch_ids_dtype,
const paddle::DataType& kv_tile_ids_per_batch_dtype,
const paddle::DataType& kv_num_blocks_dtype,
const paddle::DataType& decoder_batch_ids_dtype,
const paddle::DataType& decoder_tile_ids_per_batch_dtype,
const paddle::DataType& decoder_num_blocks_dtype,
const paddle::DataType& max_enc_len_this_time_dtype,
const paddle::DataType& max_dec_len_this_time_dtype,
const paddle::DataType& max_len_kv_dtype,
const paddle::optional<paddle::DataType>& rotary_embs_dtype,
const paddle::optional<paddle::DataType>& attn_mask_dtype,
const paddle::optional<paddle::DataType>& qkv_bias_dtype,
const paddle::optional<paddle::DataType>& qkv_out_scales_dtype,
const paddle::optional<paddle::DataType>& cache_k_quant_scales_dtype,
const paddle::optional<paddle::DataType>& cache_v_quant_scales_dtype,
const paddle::optional<paddle::DataType>& cache_k_dequant_scales_dtype,
const paddle::optional<paddle::DataType>& cache_v_dequant_scales_dtype,
const paddle::optional<paddle::DataType>& cache_k_zp_dtype,
const paddle::optional<paddle::DataType>& cache_v_zp_dtype,
const paddle::optional<paddle::DataType>& out_linear_shifts_dtype,
const paddle::optional<paddle::DataType>& out_linear_smooths_dtype,
const std::string& cache_quant_type_str,
const bool use_neox_rotary_style,
const int max_input_length,
const float softmax_scale,
const float quant_max_bound,
const float quant_min_bound,
const float out_linear_in_scale,
const int speculate_max_draft_token_num,
const bool causal,
const bool speculate_decoder) {
if (q_dtype == paddle::DataType::FLOAT16) {
return {paddle::DataType::FLOAT16};
} else if(q_dtype == paddle::DataType::BFLOAT16){
return {paddle::DataType::BFLOAT16};
}
else {
PD_THROW("Only supported attr of compute_dtype in ['fp16','bfp16'].");
}
}
PD_BUILD_OP(mla_block_multihead_attention_xpu)
.Inputs({"q",
"k",
"v",
"key_cache",
"value_cache",
"seq_lens_encoder",
"seq_lens_decoder",
"seq_lens_this_time",
"padding_offsets",
"cum_offsets",
"block_tables",
"encoder_batch_ids",
"encoder_tile_ids_per_batch",
"encoder_num_blocks",
"kv_batch_ids",
"kv_tile_ids_per_batch",
"kv_num_blocks",
"decoder_batch_ids",
"decoder_tile_ids_per_batch",
"decoder_num_blocks",
"max_enc_len_this_time",
"max_dec_len_this_time",
"max_len_kv",
paddle::Optional("rotary_embs"),
paddle::Optional("attn_mask"),
paddle::Optional("qkv_bias"),
paddle::Optional("qkv_out_scales"),
paddle::Optional("cache_k_quant_scales"),
paddle::Optional("cache_v_quant_scales"),
paddle::Optional("cache_k_dequant_scales"),
paddle::Optional("cache_v_dequant_scales"),
paddle::Optional("cache_k_zp"),
paddle::Optional("cache_v_zp"),
paddle::Optional("out_linear_shifts"),
paddle::Optional("out_linear_smooths")})
.Outputs({"fmha_out"})
// .SetInplaceMap({{"key_cache", "key_cache_out"},
// {"value_cache", "value_cache_out"}})
.Attrs({"cache_quant_type: std::string",
"use_neox_rotary_style: bool",
"max_input_length: int",
"softmax_scale: float",
"quant_max_bound: float",
"quant_min_bound: float",
"out_linear_in_scale: float",
"speculate_max_draft_token_num: int",
"causal: bool",
"speculate_decoder: bool"})
.SetKernelFn(PD_KERNEL(MlaAttn))
.SetInferShapeFn(PD_INFER_SHAPE(MlaAttnInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(MlaAttnInferDtype));

View File

@@ -0,0 +1,477 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <core/ctx_manager.h>
#include <core/xft_check.h>
#include <core/xft_event.h>
#include <core/xft_params.h>
#include <paddle/phi/backends/xpu/xpu_context.h>
#include <xft/operation/xft_fc_helper.h>
#include <xft/xdnn_plugin.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
#include "ops.h"
namespace xftkernel = baidu::xpu::xftkernel;
template <paddle::DataType D>
class PaddleTypeToXPUType;
template <>
class PaddleTypeToXPUType<paddle::DataType::FLOAT32> {
public:
typedef float DataType;
typedef float data_t;
};
template <>
class PaddleTypeToXPUType<paddle::DataType::FLOAT16> {
public:
typedef float16 DataType;
typedef paddle::float16 data_t;
};
template <>
class PaddleTypeToXPUType<paddle::DataType::BFLOAT16> {
public:
typedef bfloat16 DataType;
typedef paddle::bfloat16 data_t;
};
template <paddle::DataType T>
std::vector<paddle::Tensor> PrefillMLAWriteCache(
const paddle::Tensor& kv_nope,
const paddle::Tensor& kv_pe,
const paddle::Tensor& encoder_seq_lod,
const paddle::Tensor& encoder_batch_map,
const paddle::Tensor& start_token_raw, // encoder cache写时 start token为0 (不算prefix cache)
const paddle::Tensor& encoder_seq_lod_cpu,
const paddle::Tensor& encoder_batch_map_cpu,
const paddle::Tensor& start_token_raw_cpu, // encoder cache写时 start token为0 (不算prefix cache)
const paddle::Tensor& enc_batch_tensor,
const paddle::Tensor& dec_batch_tensor,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const int max_seq_len,
const int kv_num_heads,
paddle::Tensor* kv_cache) {
baidu::xpu::api::plugin::print_times("[TIME BEGIN] PrefillMLAWriteCache");
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
typedef PaddleTypeToXPUType<T> traits_;
typedef typename traits_::DataType DataType_;
typedef typename traits_::data_t data_t;
const auto& kv_nope_dims = kv_nope.dims();
const auto& kv_pe_dims = kv_pe.dims();
const auto& kv_cache_dims = kv_cache->dims();
auto num_tokens = kv_nope_dims[0];
auto block_size = kv_cache_dims[2];
auto block_batch = block_tables.dims()[0];
auto max_blocks_per_seq = block_tables.dims()[1];
auto kv_lora_rank = kv_nope_dims[kv_nope_dims.size() - 1];
auto rope_head_dim = kv_pe_dims[kv_pe_dims.size() - 1];
auto bsz = cum_offsets.dims()[0];
int enc_batch = enc_batch_tensor.data<int32_t>()[0];
int dec_batch = dec_batch_tensor.data<int32_t>()[0];
// 初始化输入
auto kv_nope_xft = baidu::xpu::xft::xftTensor<DataType_, 2>(
reinterpret_cast<DataType_*>(const_cast<data_t*>(kv_nope.data<data_t>())),
std::array<int64_t, 2>{num_tokens,
kv_lora_rank});
auto kv_pe_xft = baidu::xpu::xft::xftTensor<DataType_, 2>(
reinterpret_cast<DataType_*>(const_cast<data_t*>(kv_pe.data<data_t>())),
std::array<int64_t, 2>{num_tokens,
rope_head_dim});
// 初始化输入 cache
auto cache_xft = baidu::xpu::xft::xftTensor<DataType_, 4>(
reinterpret_cast<DataType_*>(const_cast<data_t*>(kv_cache->data<data_t>())),
std::array<int64_t, 4>{kv_cache->shape()[0],
kv_cache->shape()[1],
kv_cache->shape()[2],
kv_cache->shape()[3]});
// 初始化输入:block table
auto block_tables_xft = baidu::xpu::xft::xftTensor<int, 2>(
reinterpret_cast<int*>(const_cast<int*>(block_tables.data<int>())),
std::array<int64_t, 2>{block_tables.shape()[0],
block_tables.shape()[1]});
// 初始化concat
std::vector<const DataType_*> concat_input;
concat_input.push_back(kv_nope_xft.data());
concat_input.push_back(kv_pe_xft.data());
auto concat_out = paddle::full({num_tokens, kv_lora_rank + rope_head_dim}, -2, kv_nope.type(), kv_nope.place());
auto concat_out_xft = baidu::xpu::xft::xftTensor<DataType_, 2>(
reinterpret_cast<DataType_*>(const_cast<data_t*>(concat_out.data<data_t>())),
std::array<int64_t, 2>{concat_out.shape()[0],
concat_out.shape()[1]});
// 拼接kv_nope和kv_pe
baidu::xpu::api::concat<DataType_>(xpu_ctx->x_context(),
concat_input,
concat_out_xft.data(),
{{num_tokens, kv_lora_rank},{num_tokens, rope_head_dim}},
1);
baidu::xpu::api::VectorParam<int32_t> context_len_vp{const_cast<int32_t*>(encoder_seq_lod_cpu.data<int32_t>()), enc_batch + 1, const_cast<int32_t*>(encoder_seq_lod.data<int32_t>())};
baidu::xpu::api::VectorParam<int32_t> valid_batch_vp{const_cast<int32_t*>(encoder_batch_map_cpu.data<int32_t>()), enc_batch, const_cast<int32_t*>(encoder_batch_map.data<int32_t>())};
baidu::xpu::api::VectorParam<int32_t> start_tokens_vp{const_cast<int32_t*>(start_token_raw_cpu.data<int32_t>()), enc_batch, const_cast<int32_t*>(start_token_raw.data<int32_t>())};
int ret_cache = xftkernel::xft_reshape_cached_kv<float16, float16, int>(
xpu_ctx->x_context(),
reinterpret_cast<float16*>(concat_out_xft.data()),
reinterpret_cast<float16*>(cache_xft.data()),
block_tables_xft.data(),
context_len_vp,
start_tokens_vp,
valid_batch_vp,
enc_batch,
1, // num_head == 1 吸收版
kv_lora_rank + rope_head_dim,
block_batch,
block_size,
max_blocks_per_seq,
"BLHD", // qkv_layout,
"HLD", // page_layout,
nullptr, // scale,
nullptr, // batch_max_ptrs,
nullptr); // max_ptrs
baidu::xpu::api::plugin::print_times("[TIME END] PrefillMLAWriteCache");
return {};
}
std::vector<paddle::Tensor> PrefillMLAWriteCacheKernel(
const paddle::Tensor& kv_nope,
const paddle::Tensor& kv_pe,
const paddle::Tensor& kv_cache,
const paddle::Tensor& encoder_seq_lod,
const paddle::Tensor& encoder_batch_map,
const paddle::Tensor& start_token_raw, // encoder cache写时 start token为0 (不算prefix cache)
const paddle::Tensor& encoder_seq_lod_cpu,
const paddle::Tensor& encoder_batch_map_cpu,
const paddle::Tensor& start_token_raw_cpu,
const paddle::Tensor& enc_batch_tensor,
const paddle::Tensor& dec_batch_tensor,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const std::string& cache_quant_type_str,
const int max_seq_len,
const int kv_num_heads) {
switch (kv_pe.dtype()) {
case paddle::DataType::BFLOAT16: {
return PrefillMLAWriteCache<paddle::DataType::BFLOAT16>(
kv_nope,
kv_pe,
encoder_seq_lod,
encoder_batch_map,
start_token_raw,
encoder_seq_lod_cpu,
encoder_batch_map_cpu,
start_token_raw_cpu,
enc_batch_tensor,
dec_batch_tensor,
padding_offsets,
cum_offsets,
block_tables,
max_seq_len,
kv_num_heads,
const_cast<paddle::Tensor*>(&kv_cache));
}
case paddle::DataType::FLOAT16: {
return PrefillMLAWriteCache<paddle::DataType::FLOAT16>(
kv_nope,
kv_pe,
encoder_seq_lod,
encoder_batch_map,
start_token_raw,
encoder_seq_lod_cpu,
encoder_batch_map_cpu,
start_token_raw_cpu,
enc_batch_tensor,
dec_batch_tensor,
padding_offsets,
cum_offsets,
block_tables,
max_seq_len,
kv_num_heads,
const_cast<paddle::Tensor*>(&kv_cache));
}
}
return {};
}
template <paddle::DataType T>
std::vector<paddle::Tensor> DecodeMLAWriteCache(
const paddle::Tensor& kv_nope,
const paddle::Tensor& kv_pe,
const paddle::Tensor& decoder_context_len_cache,
const paddle::Tensor& decoder_batch_map,
const paddle::Tensor& kv_seq_lod_raw, // decoder cache写时,lod为0,1,2,3,……
const paddle::Tensor& decoder_context_len_cache_cpu,
const paddle::Tensor& decoder_batch_map_cpu,
const paddle::Tensor& kv_seq_lod_raw_cpu, // decoder cache写时,lod为0,1,2,3,……
const paddle::Tensor& enc_batch_tensor,
const paddle::Tensor& dec_batch_tensor,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const int max_seq_len,
const int kv_num_heads,
const bool speculate_decoder,
paddle::Tensor* kv_cache) {
baidu::xpu::api::plugin::print_times("[TIME BEGIN] DecodeMLAWriteCache");
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
xpu::ctx_guard RAII_GUARD(xpu_ctx->x_context());
typedef PaddleTypeToXPUType<T> traits_;
typedef typename traits_::DataType DataType_;
typedef typename traits_::data_t data_t;
const auto& kv_nope_dims = kv_nope.dims();
const auto& kv_pe_dims = kv_pe.dims();
const auto& kv_cache_dims = kv_cache->dims();
auto num_tokens = kv_nope_dims[0];
auto block_size = kv_cache_dims[2];
auto block_batch = block_tables.dims()[0];
auto max_blocks_per_seq = block_tables.dims()[1];
auto kv_lora_rank = kv_nope_dims[kv_nope_dims.size() - 1];
auto rope_head_dim = kv_pe_dims[kv_pe_dims.size() - 1];
auto bsz = cum_offsets.dims()[0];
int enc_batch = enc_batch_tensor.data<int32_t>()[0];
int dec_batch = dec_batch_tensor.data<int32_t>()[0];
// 初始化输入
auto kv_nope_xft = baidu::xpu::xft::xftTensor<DataType_, 2>(
reinterpret_cast<DataType_*>(const_cast<data_t*>(kv_nope.data<data_t>())),
std::array<int64_t, 2>{num_tokens,
kv_lora_rank});
auto kv_pe_xft = baidu::xpu::xft::xftTensor<DataType_, 2>(
reinterpret_cast<DataType_*>(const_cast<data_t*>(kv_pe.data<data_t>())),
std::array<int64_t, 2>{num_tokens,
rope_head_dim});
// 初始化输入 cache
auto cache_xft = baidu::xpu::xft::xftTensor<DataType_, 4>(
reinterpret_cast<DataType_*>(const_cast<data_t*>(kv_cache->data<data_t>())),
std::array<int64_t, 4>{kv_cache->shape()[0],
kv_cache->shape()[1],
kv_cache->shape()[2],
kv_cache->shape()[3]});
// 初始化输入:block table
auto block_tables_xft = baidu::xpu::xft::xftTensor<int, 2>(
reinterpret_cast<int*>(const_cast<int*>(block_tables.data<int>())),
std::array<int64_t, 2>{block_tables.shape()[0],
block_tables.shape()[1]});
// 初始化concat
// std::vector<DataType_*> concat_input = {kv_nope_xft.data(), kv_pe_xft.data()};
std::vector<const DataType_*> concat_input;
concat_input.push_back(kv_nope_xft.data());
concat_input.push_back(kv_pe_xft.data());
auto concat_out = paddle::full({num_tokens, kv_lora_rank + rope_head_dim}, -2, kv_nope.type(), kv_nope.place());
auto concat_out_xft = baidu::xpu::xft::xftTensor<DataType_, 2>(
reinterpret_cast<DataType_*>(const_cast<data_t*>(concat_out.data<data_t>())),
std::array<int64_t, 2>{concat_out.shape()[0],
concat_out.shape()[1]});
// 拼接kv_nope和kv_pe
baidu::xpu::api::concat<DataType_>(xpu_ctx->x_context(),
concat_input,
concat_out_xft.data(),
{{num_tokens, kv_lora_rank},{num_tokens, rope_head_dim}},
1);
// context_len
baidu::xpu::api::VectorParam<int32_t> context_len_vp_cache{const_cast<int32_t*>(decoder_context_len_cache_cpu.data<int32_t>()), dec_batch, const_cast<int32_t*>(decoder_context_len_cache.data<int32_t>())};
// real batch
baidu::xpu::api::VectorParam<int32_t> valid_batch_vp{const_cast<int32_t*>(decoder_batch_map_cpu.data<int32_t>()), dec_batch, const_cast<int32_t*>(decoder_batch_map.data<int32_t>())};
// baidu::xpu::api::VectorParam<int32_t> kv_seq_lod_vp{const_cast<int32_t*>(kv_seq_lod_raw_cpu.data<int32_t>()), dec_batch + 1, const_cast<int32_t*>(kv_seq_lod_raw.data<int32_t>())};
// baidu::xpu::api::VectorParam<int32_t> kv_seq_lod_vp = baidu::xpu::api::VectorParam<int32_t>{const_cast<int32_t*>(kv_seq_lod_raw_cpu.data<int32_t>()), dec_batch + 1, const_cast<int32_t*>(kv_seq_lod_raw.data<int32_t>())};
std::vector<int> kv_seq_lod(dec_batch + 1);
std::iota(kv_seq_lod.begin(), kv_seq_lod.end(), 0);
baidu::xpu::api::VectorParam<int32_t> kv_seq_lod_vp =
baidu::xpu::api::VectorParam<int32_t>{kv_seq_lod.data(), dec_batch + 1, nullptr}.to_xpu(RAII_GUARD);
// std::cout << "Tensor dtype: " << kv_seq_lod_raw_cpu.dtype() << std::endl;
// std::cout << "Tensor place: " << kv_seq_lod_raw_cpu.place() << std::endl;
// // 打印形状信息
// std::cout << "Tensor shape: [";
// for (int i = 0; i < kv_seq_lod_raw_cpu.dims().size(); ++i) {
// if (i > 0) std::cout << ", ";
// std::cout << kv_seq_lod_raw_cpu.dims()[i];
// }
// std::cout << "]" << std::endl;
// std::cout << "Tensor dtype: " << kv_seq_lod_raw.dtype() << std::endl;
// std::cout << "Tensor place: " << kv_seq_lod_raw.place() << std::endl;
// // 打印形状信息
// std::cout << "Tensor shape: [";
// for (int i = 0; i < kv_seq_lod_raw.dims().size(); ++i) {
// if (i > 0) std::cout << ", ";
// std::cout << kv_seq_lod_raw.dims()[i];
// }
// std::cout << "]" << std::endl;
int ret_cache = xftkernel::xft_reshape_cached_kv<float16, float16, int>(
xpu_ctx->x_context(),
reinterpret_cast<float16*>(concat_out_xft.data()),
reinterpret_cast<float16*>(cache_xft.data()),
block_tables_xft.data(),
kv_seq_lod_vp,
context_len_vp_cache,
valid_batch_vp,
dec_batch,
1, // num_head == 1
kv_lora_rank + rope_head_dim,
block_batch,
block_size,
max_blocks_per_seq,
"BLHD", // qkv_layout,
"HLD", // page_layout,
nullptr, // scale,
nullptr, // batch_max_ptrs,
nullptr); // max_ptrs
baidu::xpu::api::plugin::print_times("[TIME END] DecodeMLAWriteCache");
return {};
}
std::vector<paddle::Tensor> DecodeMLAWriteCacheKernel(
const paddle::Tensor& kv_nope,
const paddle::Tensor& kv_pe,
const paddle::Tensor& kv_cache,
const paddle::Tensor& decoder_context_len_cache,
const paddle::Tensor& decoder_batch_map,
const paddle::Tensor& kv_seq_lod_raw,
const paddle::Tensor& decoder_context_len_cache_cpu,
const paddle::Tensor& decoder_batch_map_cpu,
const paddle::Tensor& kv_seq_lod_raw_cpu,
const paddle::Tensor& enc_batch_tensor,
const paddle::Tensor& dec_batch_tensor,
const paddle::Tensor& padding_offsets,
const paddle::Tensor& cum_offsets,
const paddle::Tensor& block_tables,
const std::string& cache_quant_type_str,
const int max_seq_len,
const int kv_num_heads,
const bool speculate_decoder) {
switch (kv_pe.dtype()) {
case paddle::DataType::BFLOAT16: {
return DecodeMLAWriteCache<paddle::DataType::BFLOAT16>(
kv_nope,
kv_pe,
decoder_context_len_cache,
decoder_batch_map,
kv_seq_lod_raw,
decoder_context_len_cache_cpu,
decoder_batch_map_cpu,
kv_seq_lod_raw_cpu,
enc_batch_tensor,
dec_batch_tensor,
padding_offsets,
cum_offsets,
block_tables,
max_seq_len,
kv_num_heads,
speculate_decoder,
const_cast<paddle::Tensor*>(&kv_cache));
}
case paddle::DataType::FLOAT16: {
return DecodeMLAWriteCache<paddle::DataType::FLOAT16>(
kv_nope,
kv_pe,
decoder_context_len_cache,
decoder_batch_map,
kv_seq_lod_raw,
decoder_context_len_cache_cpu,
decoder_batch_map_cpu,
kv_seq_lod_raw_cpu,
enc_batch_tensor,
dec_batch_tensor,
padding_offsets,
cum_offsets,
block_tables,
max_seq_len,
kv_num_heads,
speculate_decoder,
const_cast<paddle::Tensor*>(&kv_cache));
}
}
return {};
}
PD_BUILD_OP(prefill_mla_write_cache_xpu)
.Inputs({"kv_nope",
"kv_pe",
"kv_cache",
"encoder_seq_lod",
"encoder_batch_map",
"start_token_raw",
"encoder_seq_lod_cpu",
"encoder_batch_map_cpu",
"start_token_raw_cpu",
"enc_batch_tensor",
"dec_batch_tensor",
"padding_offsets",
"cum_offsets",
"block_tables"})
.Outputs({"kv_cache_out"})
.SetInplaceMap({{"kv_cache", "kv_cache_out"}})
.Attrs({"cache_quant_type_str: std::string",
"max_seq_len: int",
"kv_num_heads: int"})
.SetKernelFn(PD_KERNEL(PrefillMLAWriteCacheKernel));
PD_BUILD_OP(decode_mla_write_cache_xpu)
.Inputs({"kv_nope",
"kv_pe",
"kv_cache",
"decoder_context_len_cache",
"decoder_batch_map",
"kv_seq_lod_raw",
"decoder_context_len_cache_cpu",
"decoder_batch_map_cpu",
"kv_seq_lod_raw_cpu",
"enc_batch_tensor",
"dec_batch_tensor",
"padding_offsets",
"cum_offsets",
"block_tables"})
.Outputs({"kv_cache_out"})
.SetInplaceMap({{"kv_cache", "kv_cache_out"}})
.Attrs({"cache_quant_type_str: std::string",
"max_seq_len: int",
"kv_num_heads: int",
"speculate_decoder: bool"})
.SetKernelFn(PD_KERNEL(DecodeMLAWriteCacheKernel));

View File

@@ -0,0 +1,110 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <paddle/phi/backends/xpu/xpu_context.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
#include <xft/xdnn_plugin.h>
namespace xftkernel = baidu::xpu::xftkernel;
std::vector<paddle::Tensor> MoeDispatchKernel(
const paddle::Tensor& X,
const paddle::Tensor& gating_output,
const int moe_topk,
const bool group_moe,
const bool topk_only_mode) {
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
int token_rows = 0;
auto input_dims = X.shape();
if (input_dims.size() == 3) {
token_rows = input_dims[0] * input_dims[1];
} else {
token_rows = input_dims[0];
}
const int num_rows = token_rows;
const int hidden_size = X.shape()[input_dims.size() - 1];
auto gating_dims = gating_output.shape();
const int expert_num = gating_dims[gating_dims.size() - 1];
if (group_moe) {
// Check if expert_num is divisible by moe_topk, else throw an error
PADDLE_ENFORCE_EQ(
expert_num % moe_topk,
0,
common::errors::InvalidArgument(
"The number of experts (expert_num) "
"must be divisible by moe_topk. "
"Got expert_num = %d and moe_topk = %d.",
expert_num,
moe_topk));
}
auto permute_input = paddle::full({num_rows * moe_topk, hidden_size}, -1, X.type(), X.place());
auto token_nums_per_expert = paddle::full({expert_num}, 0, paddle::DataType::INT32, X.place());
auto permute_indices_per_token = paddle::full({moe_topk, num_rows}, -1, paddle::DataType::INT32, X.place());
auto expert_scales_float = paddle::full({num_rows, moe_topk}, 0.0f, paddle::DataType::FLOAT32, X.place());
auto top_k_indices = paddle::full({num_rows, moe_topk}, -1, paddle::DataType::INT32, X.place());
using XPUType = typename XPUTypeTrait<bfloat16>::Type;
typedef paddle::bfloat16 data_t;
auto index_data = permute_indices_per_token.data<int32_t>();
// auto index = paddle::full({num_rows, moe_topk}, -1, paddle::DataType::INT32, X.place());
int ret = xftkernel::xft_moe_group_topk_fusion<float, float, int32_t>(
xpu_ctx->x_context(),
gating_output.data<float>(),
expert_scales_float.data<float>(),
index_data,
nullptr,
num_rows,
expert_num,
0,
0,
moe_topk, // num of shared expert
0);
PD_CHECK(ret == 0, "xftkernel::xft_moe_softmax_topk_norm_fusion failed");
auto sorted_tokens_num_lod = paddle::full({expert_num + 1}, -1, paddle::DataType::INT32, X.place());
ret = xftkernel::xft_moe_ffn_pre_sorted<XPUType, int32_t>(
xpu_ctx->x_context(),
reinterpret_cast<const XPUType*>(X.data<data_t>()),
index_data,
nullptr,
reinterpret_cast<XPUType*>(permute_input.data<data_t>()),
top_k_indices.data<int32_t>(),
token_nums_per_expert.data<int32_t>(),
sorted_tokens_num_lod.data<int32_t>(),
token_rows,
hidden_size,
expert_num,
moe_topk,
0);
PD_CHECK(ret == 0, "xftkernel::xft_moe_ffn_pre_sorted failed");
return {permute_input,
sorted_tokens_num_lod,
permute_indices_per_token,
expert_scales_float,
top_k_indices};
}
PD_BUILD_OP(moe_dispatch_xpu)
.Inputs({"X", "gating_output"})
.Outputs(
{"permute_input",
"token_nums_per_expert",
"permute_indices_per_token",
"expert_scales_float",
"expert_scales_int"})
.Attrs({"moe_topk: int", "group_moe: bool", "topk_only_mode: bool"})
.SetKernelFn(PD_KERNEL(MoeDispatchKernel));

277
csrc/xpu/src/moe_ffn.cc Normal file
View File

@@ -0,0 +1,277 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <core/ctx_manager.h>
#include <core/xft_check.h>
#include <core/xft_event.h>
#include <core/xft_params.h>
#include <paddle/phi/backends/xpu/xpu_context.h>
#include <xft/operation/xft_fc_helper.h>
#include <xft/xdnn_plugin.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
namespace xftkernel = baidu::xpu::xftkernel;
std::vector<paddle::Tensor> MoeFFNKernel(
const paddle::Tensor& permute_input,
const paddle::Tensor& token_nums_per_expert,
const paddle::Tensor& ffn1_weight,
const paddle::Tensor& ffn2_weight,
const paddle::optional<paddle::Tensor>& ffn1_bias,
const paddle::optional<paddle::Tensor>& ffn1_scale,
const paddle::optional<paddle::Tensor>& ffn2_scale,
const std::string& quant_method) {
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
using XPUType = typename XPUTypeTrait<bfloat16>::Type;
typedef paddle::bfloat16 data_t;
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
auto ffn_out_paddle = permute_input.copy_to(permute_input.place(), false);
const int64_t expanded_active_expert_rows = permute_input.shape()[0];
const int num_experts = ffn1_weight.shape()[0];
const int hidden_size = ffn1_weight.shape()[2];
int64_t inter_size = ffn1_weight.shape()[1];
if (quant_method == "weight_only_int4") {
inter_size = inter_size * 2;
}
auto ffn1_input = baidu::xpu::xft::xftTensor<XPUType, 2>(
reinterpret_cast<XPUType*>(
const_cast<paddle::bfloat16*>(permute_input.data<data_t>())),
std::array<int64_t, 2>{permute_input.shape()[0],
permute_input.shape()[1]});
auto ffn1_bias_tenosor = baidu::xpu::xft::xftVec<float>(
ffn1_bias ? const_cast<float*>(ffn1_bias->data<float>()) : nullptr,
std::array<int64_t, 1>{inter_size});
auto ffn1_out_paddle = paddle::full({expanded_active_expert_rows, inter_size},
-1,
permute_input.type(),
permute_input.place());
auto ffn1_out_tensor = baidu::xpu::xft::xftTensor<XPUType, 2>(
reinterpret_cast<XPUType*>(ffn1_out_paddle.data<data_t>()),
std::array<int64_t, 2>{ffn1_out_paddle.shape()[0],
ffn1_out_paddle.shape()[1]});
auto token_nums_per_expert_tensor = baidu::xpu::xft::xftVec<int32_t>(
const_cast<int32_t*>(token_nums_per_expert.data<int>()),
std::array<int64_t, 1>{num_experts});
auto empty_tensor = baidu::xpu::xft::xftTensor<int32_t, 2>();
auto sorted_tokens_idx_paddle = paddle::full({expanded_active_expert_rows, 1},
-1,
paddle::DataType::INT32,
permute_input.place());
auto sorted_tokens_idx_tensor = baidu::xpu::xft::xftTensor<int32_t, 2>(
sorted_tokens_idx_paddle.data<int>(),
std::array<int64_t, 2>{sorted_tokens_idx_paddle.shape()[0],
sorted_tokens_idx_paddle.shape()[1]});
int ret = 0;
if (quant_method == "weight_only_int4") {
auto ffn1_w_tensor = baidu::xpu::xft::xftMat<int4_t>(
reinterpret_cast<int4_t*>(
const_cast<int8_t*>(ffn1_weight.data<int8_t>())),
nullptr,
const_cast<float*>(
ffn1_scale->data<
float>()), // 这个地方GPU是float16,我们需要的是float,需要check
std::array<int64_t, 2>{num_experts * inter_size, hidden_size});
ret = baidu::xpu::xft::xft_moe_sort_fc_block<XPUType,
int4_t,
XPUType,
float,
int32_t,
int4_wo_int15>(
xpu_ctx->x_context(),
ffn1_input,
ffn1_w_tensor,
ffn1_out_tensor,
&ffn1_bias_tenosor,
token_nums_per_expert_tensor,
sorted_tokens_idx_tensor,
nullptr,
empty_tensor,
baidu::xpu::api::Activation_t::LINEAR,
false,
true,
1.0,
0.0,
num_experts,
1, // topk
0,
2,
1);
} else {
auto ffn1_w_tensor = baidu::xpu::xft::xftMat<int8_t>(
const_cast<int8_t*>(ffn1_weight.data<int8_t>()),
nullptr,
const_cast<float*>(
ffn1_scale->data<
float>()), // 这个地方GPU是float16,我们需要的是float,需要check
std::array<int64_t, 2>{num_experts * inter_size, hidden_size});
ret = baidu::xpu::xft::xft_moe_sort_fc_block<XPUType,
int8_t,
XPUType,
float,
int32_t,
float>(
xpu_ctx->x_context(),
ffn1_input,
ffn1_w_tensor,
ffn1_out_tensor,
&ffn1_bias_tenosor,
token_nums_per_expert_tensor,
sorted_tokens_idx_tensor,
nullptr,
empty_tensor,
baidu::xpu::api::Activation_t::LINEAR,
false,
true,
1.0,
0.0,
num_experts,
1, // topk
0,
2,
1);
}
auto ffn2_input_paddle =
paddle::full({expanded_active_expert_rows, inter_size / 2},
-1,
permute_input.type(),
permute_input.place());
auto ffn2_input_tensor = baidu::xpu::xft::xftTensor<XPUType, 2>(
reinterpret_cast<XPUType*>(ffn2_input_paddle.data<data_t>()),
std::array<int64_t, 2>{ffn2_input_paddle.shape()[0],
ffn2_input_paddle.shape()[1]});
ret = xftkernel::xft_fast_swiglu_add_mul_fusion<XPUType>(
xpu_ctx->x_context(),
ffn1_out_tensor.data(),
ffn2_input_tensor.data(),
expanded_active_expert_rows,
inter_size,
nullptr,
nullptr,
true,
nullptr,
nullptr);
// auto ffn2_bias_tenosor = baidu::xpu::xft::xftVec<float>(
// ffn1_bias ? const_cast<float*>(ffn2_bias->data<float>()):
// nullptr, std::array<int64_t, 1>{hidden_size});
auto ffn2_out_tensor = baidu::xpu::xft::xftTensor<XPUType, 2>(
reinterpret_cast<XPUType*>(ffn_out_paddle.data<data_t>()),
std::array<int64_t, 2>{ffn_out_paddle.shape()[0],
ffn_out_paddle.shape()[1]});
if (quant_method == "weight_only_int4") {
auto ffn2_w_tensor = baidu::xpu::xft::xftMat<int4_t>(
reinterpret_cast<int4_t*>(
const_cast<int8_t*>(ffn2_weight.data<int8_t>())),
nullptr,
const_cast<float*>(
ffn2_scale->data<
float>()), // 这个地方GPU是float16,我们需要的是float,需要check
std::array<int64_t, 2>{num_experts * hidden_size, inter_size / 2});
ret = baidu::xpu::xft::xft_moe_sort_fc_block<XPUType,
int4_t,
XPUType,
float,
int32_t,
int4_wo_int15>(
xpu_ctx->x_context(),
ffn2_input_tensor,
ffn2_w_tensor,
ffn2_out_tensor,
nullptr,
token_nums_per_expert_tensor,
sorted_tokens_idx_tensor,
nullptr,
empty_tensor,
baidu::xpu::api::Activation_t::LINEAR,
false,
true,
1.0,
0.0,
num_experts,
1, // topk
0,
2,
1);
} else {
auto ffn2_w_tensor = baidu::xpu::xft::xftMat<int8_t>(
const_cast<int8_t*>(ffn2_weight.data<int8_t>()),
nullptr,
const_cast<float*>(
ffn2_scale->data<
float>()), // 这个地方GPU是float16,我们需要的是float,需要check
std::array<int64_t, 2>{num_experts * hidden_size, inter_size / 2});
ret = baidu::xpu::xft::xft_moe_sort_fc_block<XPUType,
int8_t,
XPUType,
float,
int32_t,
float>(
xpu_ctx->x_context(),
ffn2_input_tensor,
ffn2_w_tensor,
ffn2_out_tensor,
nullptr,
token_nums_per_expert_tensor,
sorted_tokens_idx_tensor,
nullptr,
empty_tensor,
baidu::xpu::api::Activation_t::LINEAR,
false,
true,
1.0,
0.0,
num_experts,
1, // topk
0,
2,
1);
}
return {
ffn_out_paddle,
};
}
PD_BUILD_OP(moe_ffn_xpu)
.Inputs({"permute_input",
"token_nums_per_expert",
"ffn1_weight",
"ffn2_weight",
"ffn1_bias",
"ffn1_scale",
"ffn2_scale"})
.Outputs({"ffn_out"})
.Attrs({"quant_method: std::string"})
.SetKernelFn(PD_KERNEL(MoeFFNKernel));

173
csrc/xpu/src/moe_fused.cc Normal file
View File

@@ -0,0 +1,173 @@
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <core/ctx_manager.h>
#include <core/xft_tensor.h>
#include <core/xft_check.h>
#include <core/xft_event.h>
#include <core/xft_params.h>
#include <paddle/phi/backends/xpu/xpu_context.h>
#include <xft/operation/ffn_moe_vllm.h>
#include <xft/xdnn_plugin.h>
#include "paddle/extension.h"
#include "paddle/phi/core/enforce.h"
#include "xpu/plugin.h"
namespace xftkernel = baidu::xpu::xftkernel;
namespace xft = baidu::xpu::xft;
inline uint32_t get_xpu_moe_speed_layers() {
static const char* xpu_moe_speed_layers_env = std::getenv("FLAGS_xpu_moe_speed_layers");
static const uint32_t xpu_moe_speed_layers =
xpu_moe_speed_layers_env == nullptr ? 0 : std::stoul(std::string(xpu_moe_speed_layers_env));
return xpu_moe_speed_layers;
}
std::vector<paddle::Tensor> MoeFusedKernel(
const paddle::Tensor& input, //[980. 7168]
const paddle::Tensor& gate_weight,//[7168. 256] ->[256,7168]
const paddle::Tensor& ffn_inter_weights,//[256, 7168,4096] reshape
const paddle::Tensor& ffn_output_weights,//[256, 2048, 7168] reshape
const paddle::Tensor& ffn1_weights_scale,// [256, 4096]
const paddle::Tensor& ffn2_weights_scale,// [256, 7168]
const paddle::Tensor& score_bias, // 256
int moe_top_k,
int expert_group_num,
int moe_topk_group,
int layer) {
baidu::xpu::api::plugin::print_times("[TIME BEGIN] MoeFusedKernel");
phi::XPUPlace place(phi::backends::xpu::GetXPUCurrentDeviceId());
auto dev_ctx = paddle::experimental::DeviceContextPool::Instance().Get(place);
auto xpu_ctx = static_cast<const phi::XPUContext*>(dev_ctx);
using XPUType = typename XPUTypeTrait<bfloat16>::Type;
typedef paddle::bfloat16 data_t;
const int64_t m = input.shape()[0];
const int64_t hidden_size = input.shape()[1];
const int64_t expert_num = gate_weight.shape()[0];
const int64_t ffn_inter_hidden_size = ffn_inter_weights.shape()[2];
const int64_t ffn_output_hidden_size = ffn_output_weights.shape()[2];
xft::Tensor input_tensor(
reinterpret_cast<XPUType*>(const_cast<data_t*>(input.data<data_t>())),
xft::DataType::DT_BFLOAT16,
input.shape());
xft::Tensor gate_weight_tensor(
const_cast<float*>(gate_weight.data<float>()),
xft::DataType::DT_FLOAT,
gate_weight.shape());
xft::Tensor ffn_inter_weights_tensor(
const_cast<int8_t*>(ffn_inter_weights.data<int8_t>()),
nullptr,
const_cast<float*>(ffn1_weights_scale.data<float>()),
xft::DataType::DT_INT8,
{expert_num, ffn_inter_hidden_size, hidden_size});
xft::Tensor ffn_output_weights_tensor(
const_cast<int8_t*>(ffn_output_weights.data<int8_t>()),
nullptr,
const_cast<float*>(ffn2_weights_scale.data<float>()),
xft::DataType::DT_INT8,
{expert_num, ffn_output_hidden_size, ffn_inter_hidden_size / 2});
xft::Tensor score_bias_tensor(const_cast<float*>(score_bias.data<float>()),
xft::DataType::DT_FLOAT,
score_bias.shape());
auto output = paddle::full({m, hidden_size}, -1, input.type(), input.place());
xft::Tensor output_tensor(reinterpret_cast<XPUType*>(output.data<data_t>()),
xft::DataType::DT_BFLOAT16,
output.shape());
xft::MoeFFNWeight moe_weight{&gate_weight_tensor,
&ffn_inter_weights_tensor,
nullptr,
&ffn_output_weights_tensor,
nullptr,
nullptr,
nullptr,
&score_bias_tensor};
xft::MoeFFNParam moe_param{
expert_num,
moe_top_k,
false,
true,
expert_group_num,
moe_topk_group,
true,
false,
1,
0,
"sigmoid"
};
if (layer >= get_xpu_moe_speed_layers()) {
xft::xft_moe_ffn_block_sorted<XPUType, int8_t, XPUType, float>(
xpu_ctx->x_context(), &input_tensor, &output_tensor, moe_weight, moe_param);
} else {
xft::xft_moe_ffn_block_sorted<XPUType, int8_t, XPUType, int8_wo_t>(
xpu_ctx->x_context(), &input_tensor, &output_tensor, moe_weight, moe_param);
}
baidu::xpu::api::plugin::print_times("[TIME END] MoeFusedKernel");
return {
output,
};
}
std::vector<std::vector<int64_t>> MoeFusedInferShape(
const std::vector<int64_t>& input_shape,
const std::vector<int64_t>& gate_weight_shape,
const std::vector<int64_t>& ffn_inter_weights_shape,
const std::vector<int64_t>& ffn_output_weights_shape,
const std::vector<int64_t>& ffn1_weights_scale_shape,
const std::vector<int64_t>& ffn2_weights_scale_shape,
const std::vector<int64_t>& score_bias_shape) {
return {input_shape};
}
std::vector<paddle::DataType> MoeFusedInferDtype(
const paddle::DataType& input_type,
const paddle::DataType& gate_weight_type,
const paddle::DataType& ffn_inter_weights_type,
const paddle::DataType& ffn_output_weights_type,
const paddle::DataType& ffn1_weights_scale_type,
const paddle::DataType& ffn2_weights_scale_type,
const paddle::DataType& score_bias_type,
const int moe_top_k,
const int expert_group_num,
const int moe_topk_group,
const int layer) {
return {input_type};
}
PD_BUILD_OP(moe_fused_xpu)
.Inputs({
"input",
"gate_weight",
"ffn_inter_weights",
"ffn_outer_weights",
"ffn1_weights_scale",
"ffn2_weights_scale",
"score_bias",
})
.Outputs({"output"})
.Attrs({"moe_top_k: int", "expert_group_num: int", "moe_topk_group: int", "layer: int"})
.SetKernelFn(PD_KERNEL(MoeFusedKernel))
.SetInferShapeFn(PD_INFER_SHAPE(MoeFusedInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(MoeFusedInferDtype));

Some files were not shown because too many files have changed in this diff Show More