測(cè)試實(shí)戰(zhàn):吞吐與尾部延遲的測(cè)量與解讀)
人工智能大模型模型推理服務(wù)后端【免費(fèi)下載鏈接】MooncakeMooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI.項(xiàng)目地址https://gitcode.com/gh_mirrors/mo/Mooncake點(diǎn)擊查看免費(fèi)下載導(dǎo)讀本文講解 Mooncake 專(zhuān)家并行Expert Parallel, EP模塊內(nèi)置的 dispatch/combine 基準(zhǔn)測(cè)試工具ep_benchmark它用于量化 Mooncake EP Buffer 在均勻路由uniform、k-hot 扇入incast和 Zipfian 路由三種流量模式下的吞吐量與尾部延遲。讀完本文你將掌握該基準(zhǔn)腳本的全部命令行參數(shù)、三種運(yùn)行方式單機(jī) spawn / 多機(jī) torchrun / 配置文件、輸出 JSON 的指標(biāo)語(yǔ)義并能結(jié)合底層Buffer.dispatch/Buffer.combine源碼理解每個(gè)參數(shù)對(duì)通信行為與性能結(jié)果的實(shí)際影響?;鶞?zhǔn)腳本與說(shuō)明文檔位于 mooncake-ep/benchmarks/ep_benchmark。一、基準(zhǔn)測(cè)試定位衡量什么為什么重要在 MoEMixture-of-Experts推理/訓(xùn)練中dispatch把每個(gè) token 按topk_idx發(fā)送到對(duì)應(yīng)專(zhuān)家所在的 rank與combine把各專(zhuān)家輸出按topk_weights加權(quán)聚合回原 rank是 EP 通信的性能關(guān)鍵路徑。Mooncake EP 為這一過(guò)程提供了專(zhuān)用的通信 BufferC 運(yùn)行時(shí)封裝為mooncake.epPython 層接口為 python/mooncake/mooncake_ep_buffer.py 中的Buffer類(lèi)。ep_benchmark的設(shè)計(jì)目標(biāo)是度量 dispatch/combine 吞吐以每秒處理的 token 數(shù)tokens_per_second為聚合吞吐指標(biāo)度量尾部延遲輸出 p50 / p90 / p99 / p999 及均值四個(gè)分位數(shù)覆蓋兩類(lèi)通信各自的延遲與端到端周期延遲覆蓋真實(shí)負(fù)載的偏斜特征真實(shí) MoE 路由往往高度偏斜少量熱門(mén)專(zhuān)家承接大部分 token因此除均勻路由外專(zhuān)門(mén)實(shí)現(xiàn)了 k-hot 扇入與 Zipfian 兩種偏斜模型。二、快速開(kāi)始三種運(yùn)行方式2.1 單機(jī)多卡內(nèi)部使用mp.spawnpython mooncake-ep/benchmarks/ep_benchmark/run_ep_benchmark.py \ --num-ranks 8 --num-experts 256 --hidden-size 7168 \ --top-k 8 --num-tokens 1024 --dtype bf16 \ --routing-mode k_hot --hot-experts 32 --hot-fraction 0.9 \ --zero-copy --async-finish \ --warmup-iters 20 --iters 100 \ --pg-backend nccl \ --json-output results/khot_8rank.json該模式不依賴(lài)外部啟動(dòng)器main()會(huì)檢查環(huán)境中是否存在RANK環(huán)境變量若不存在則調(diào)用torch.multiprocessing.spawn啟動(dòng)args.num_ranks個(gè) worker 進(jìn)程見(jiàn) run_ep_benchmark.py。2.2 多機(jī)多卡通過(guò)torchrun啟動(dòng)torchrun --nnodes2 --nproc_per_node4 --rdzv_backendc10d \ --rdzv_endpoint$HEAD_NODE \ mooncake-ep/benchmarks/ep_benchmark/run_ep_benchmark.py \ --num-experts 256 --hidden-size 7168 \ --top-k 8 --num-tokens 1024 --dtype bf16 \ --routing-mode k_hot --hot-experts 32 --hot-fraction 0.9 \ --zero-copy --async-finish \ --pg-backend nccl \ --json-output results/khot_8node.jsontorchrun模式下--num-ranks會(huì)被忽略腳本讀取WORLD_SIZE環(huán)境變量作為世界大小并分別使用RANK/LOCAL_RANK環(huán)境變量初始化進(jìn)程見(jiàn)main()中的RANK分支run_ep_benchmark.py。世界大小必須與--num-experts整除關(guān)系一致見(jiàn)下節(jié)校驗(yàn)規(guī)則。2.3 使用配置文件CLI 參數(shù)優(yōu)先覆蓋配置值倉(cāng)庫(kù)自帶了三個(gè)與三種路由模式一一對(duì)應(yīng)的現(xiàn)成配置python mooncake-ep/benchmarks/ep_benchmark/run_ep_benchmark.py \ --config mooncake-ep/benchmarks/ep_benchmark/configs/cuda_zipfian.json \ --num-ranks 8配置文件機(jī)制在解析階段實(shí)現(xiàn)腳本先用一個(gè)精簡(jiǎn)的預(yù)解析器提前讀取--config指向的 JSON再通過(guò)parser.set_defaults(**config_defaults)將其中字段設(shè)為默認(rèn)值隨后正常的命令行解析會(huì)覆蓋它們r(jià)un_ep_benchmark.py。三個(gè)示例配置分別為cuda_uniform.jsonrouting_mode uniform其余參數(shù)與默認(rèn)值一致cuda_incast_k_hot.jsonrouting_mode k_hot、hot_experts 32、hot_fraction 0.9cuda_zipfian.jsonrouting_mode zipf、zipf_alpha 1.0。三者均默認(rèn)backendcuda、zero_copytrue、async_finishtrue、pg_backendnccl、warmup_iters20、iters100即開(kāi)箱即用。三、參數(shù)全表與校驗(yàn)規(guī)則3.1 參數(shù)總覽Flag默認(rèn)值說(shuō)明--configNoneJSON 配置文件路徑CLI 參數(shù)覆蓋配置值--backendcuda輸出 JSON 中標(biāo)注的設(shè)備后端標(biāo)簽不改變實(shí)際執(zhí)行--num-ranks8EP rank / GPU 數(shù)量torchrun模式下被忽略--num-experts256全集群專(zhuān)家總數(shù)--hidden-size7168隱層維度對(duì)應(yīng) Kimi 類(lèi)大模型典型寬度--top-k8每個(gè) token 路由到的專(zhuān)家數(shù)--num-tokens1024每個(gè) rank 的 token 數(shù)--dtypebf16dispatch 數(shù)據(jù)類(lèi)型可選bf16或fp8--routing-modeuniform路由模式uniform、k_hot、zipf--hot-experts32k_hot 模式下熱門(mén)專(zhuān)家數(shù)量--hot-fraction0.9k_hot 模式下路由到熱門(mén)專(zhuān)家的 token 占比--zipf-alpha1.0Zipf 分布參數(shù) alphazipf 模式--zero-copyoff通過(guò)get_next_combine_buffer實(shí)現(xiàn)零拷貝 combine--async-finishoff基于 CUDA 事件的異步同步event-based--return-recv-hookoff基于回調(diào) hook 的同步與--async-finish互斥--pg-backendnccl進(jìn)程組后端nccl或mooncake后者要求 RDMA 環(huán)境--warmup-iters20預(yù)熱迭代次數(shù)不計(jì)時(shí)--iters100計(jì)時(shí)迭代次數(shù)--seed0隨機(jī)種子基值每個(gè) rank 使用seed rank--json-outputstdoutJSON 結(jié)果輸出路徑默認(rèn) rank 0 打印到 stdout--master-addr127.0.0.1進(jìn)程組 master 地址僅單機(jī) spawn 模式使用--master-port29500進(jìn)程組 master 端口3.2 參數(shù)校驗(yàn)與約束源碼級(jí)確認(rèn)腳本在validate_args()中強(qiáng)制以下規(guī)則run_ep_benchmark.pynum_experts必須能被num_ranks整除否則拋ValueError——因?yàn)槊總€(gè) rank 負(fù)責(zé)的本地專(zhuān)家數(shù)為num_experts // num_ranks對(duì)應(yīng)Buffer的assert num_experts % self.group_size 0檢查mooncake_ep_buffer.py--async-finish與--return-recv-hook互斥同時(shí)開(kāi)啟會(huì)拋錯(cuò)fp8 模式下hidden-size必須能被 128 整除——FP8 量化以 128 元素為 block 計(jì)算縮放因子_fp8_cast中x.view(m, -1, 128)的分組方式mooncake_ep_buffer.py 以及 routing.py 無(wú)直接關(guān)聯(lián)此約束主要源于 FP8 內(nèi)核的 block 粒度。此外Buffer.dispatch還對(duì)輸入張量做形狀斷言x必須為 2 維 BF16 連續(xù)張量、hidden同時(shí)滿(mǎn)足% 16 0與% 128 0、num_tokens num_max_dispatch_tokens_per_rankmooncake_ep_buffer.py基準(zhǔn)腳本以--num-tokens作為容量上限傳入因此--num-tokens也是 EP buffer 工作區(qū)容量參數(shù)。3.3 環(huán)境變量與后端選擇--pg-backend nccl標(biāo)準(zhǔn) PyTorch NCCL 進(jìn)程組dist.init_process_group(backendnccl)適用于無(wú) RDMA 的調(diào)試環(huán)境--pg-backend mooncake要求導(dǎo)入mooncake.pg擴(kuò)展腳本會(huì)顯式檢查并拋RuntimeErrorrun_ep_benchmark.py并依賴(lài) RDMA 傳輸IBGDA以獲得 fast-path 性能其初始化方式與 EP 快速開(kāi)始示例一致參見(jiàn) docs/source/api-reference/python/ep-backend.md 的 quick start 部分。四、三種路由模式的實(shí)現(xiàn)原理路由張量由 routing.py 中的生成器生成ROUTING_MODES字典將模式名映射到對(duì)應(yīng)函數(shù)。所有模式都返回(topk_idx, topk_weights)topk_idx形狀[num_tokens, top_k]int64topk_weights為 softmax 歸一化權(quán)重float32。4.1 uniform均勻路由uniform_routing為每個(gè) token 從全部num_experts中按標(biāo)準(zhǔn)正態(tài)分?jǐn)?shù)torch.randn(num_tokens, num_experts)取top_k個(gè)最大值的索引即每個(gè) token 的專(zhuān)家選擇近似均勻分布。它是負(fù)載均衡的理想基線用于衡量通信層在無(wú)偏斜壓力下的峰值能力。4.2 k_hot扇入incast偏斜路由k_hot_routing模擬真實(shí) MoE 中的熱點(diǎn)專(zhuān)家場(chǎng)景hot_fraction默認(rèn) 0.9比例的 token 的全部 top-k 都從前hot_experts個(gè)專(zhuān)家中選取在hot_experts維度上取 top-k其余 token 均勻路由。隨后用torch.randperm打亂 token 順序避免熱點(diǎn) token 聚簇影響計(jì)時(shí)。該模式的三個(gè)合法性約束源碼中顯式拋ValueError值得注意routing.pyhot_experts num_experts非法hot_experts top_k非法無(wú)法從比 top-k 還小的集合中選出 top-k 個(gè)不同專(zhuān)家hot_fraction必須在(0, 1)開(kāi)區(qū)間內(nèi)。--hot-experts 32配合--num-experts 256意味著 12.5% 的專(zhuān)家承擔(dān)約 90% 的流量會(huì)產(chǎn)生極端的不均衡專(zhuān)家負(fù)載見(jiàn)第六節(jié)imbalance_ratio這正是 incast 擁塞與尾延遲壓力的來(lái)源。4.3 zipfZipfian 路由zipfian_routing使專(zhuān)家選擇概率服從 Zipf 分布P(expert_i) ∝ 1 / (i1)^alphazipf_alpha默認(rèn) 1.0alpha 越大分布越陡峭且必須 0。實(shí)現(xiàn)上采用Gumbel-max trick進(jìn)行無(wú)放回 top-k 采樣先對(duì) log 概率加上 Gumbel(0,1) 噪聲-log(-log(U))U 下限裁剪到1e-20防止 NaN再取 noisy scores 的 top-krouting.py。相比 k_hot 的硬扇入Zipfian 提供的是無(wú)硬邊界的平滑偏斜梯度適合掃不同 alpha 觀察偏斜程度對(duì)尾延遲的影響曲線。五、基準(zhǔn)流程拆解worker 生命周期基準(zhǔn)的核心類(lèi)是EPBenchmarkWorkerrun_ep_benchmark.py每個(gè) rank 一個(gè)實(shí)例按warmup → run_measured → aggregate_and_output三段執(zhí)行5.1 初始化設(shè)置 CUDA 設(shè)備、初始化進(jìn)程組通過(guò)Buffer.get_ep_buffer_size_hint(num_tokens, hidden_size, num_ranks, num_experts)計(jì)算 EP 工作區(qū)字節(jié)數(shù)并構(gòu)造Buffer對(duì)應(yīng) C 側(cè)BufferPair布局計(jì)算每個(gè) rank 需要num_experts個(gè) int 的信號(hào)區(qū)與num_experts × num_max_dispatch_tokens_per_rank × (2·sizeof(int4) hidden·EP_BF16_SIZE)的數(shù)據(jù)區(qū)見(jiàn) mooncake-ep/include/mooncake_ep_buffer.h生成路由張量topk_idx/topk_weights種子為seed rank保證各 rank 路由分布獨(dú)立但可復(fù)現(xiàn)準(zhǔn)備隨機(jī)輸入xBF16、全 1 的active_ranks與零初始化輸出out_tensor。5.2 預(yù)熱與計(jì)時(shí)warmup()跑--warmup-iters輪完整 dispatch → mock 專(zhuān)家前向 → combine不計(jì)時(shí)最后torch.cuda.synchronize()用于建立連接、分配緩沖、觸發(fā) CUDA 內(nèi)核編譯run_measured()跑--iters輪每輪用torch.cuda.Event(enable_timingTrue)記錄四個(gè)時(shí)間點(diǎn)——dispatch 起止、combine 起止由此得到dispatch_latencydispatch 內(nèi)核耗時(shí)combine_latencycombine 內(nèi)核耗時(shí)end_to_end_latency完整 dispatch → mock 專(zhuān)家前向 → combine 周期dispatch_starts[i].elapsed_time(combine_ends[i])。5.3 mock 專(zhuān)家前向與 fp8 反量化mock_expert_forward()模擬專(zhuān)家計(jì)算對(duì)recv_x的每個(gè)本地專(zhuān)家槽位執(zhí)行recv_bf16[le] * (expert_id * 0.1 1.0)的線性縮放保持?jǐn)?shù)據(jù)形狀不變且成本極低。fp8 模式下dispatch 返回(fp8_data, scales)元組需先按 128 元素塊反量化為 BF16dequantize_fp8模式與test_ep_grid.py一致見(jiàn) run_ep_benchmark.py。5.4 零拷貝與兩種異步同步方式combine 前通過(guò)prepare_combine選擇數(shù)據(jù)路徑run_ep_benchmark.py默認(rèn)路徑expert_out.contiguous()后直接傳入combine--zero-copy調(diào)用buf.get_next_combine_buffer(handle)獲取 combine 目標(biāo)緩沖并copy_寫(xiě)入避免一次額外的張量復(fù)制Python 包裝層中該方法在非 fast-path 環(huán)境會(huì)拋NotImplementedError說(shuō)明零拷貝 combine 依賴(lài) C fast-path 運(yùn)行時(shí)mooncake_ep_buffer.py。同步方式二選一--async-finishdispatch/combine返回EventOverlap事件worker 調(diào)用event.current_stream_wait()讓當(dāng)前流等待通信事件完成事件式異步可與計(jì)算流重疊--return-recv-hook返回一個(gè)回調(diào)hook()worker 立即調(diào)用以等待接收完成hook 式同步。兩者互斥的校驗(yàn)已在 3.2 節(jié)說(shuō)明。六、輸出指標(biāo)詳解與 JSON 結(jié)構(gòu)結(jié)果先在aggregate_and_output中聚合各 rank 的延遲張量通過(guò)dist.all_gather匯集到 rank 0隨后取逐迭代的跨 rank 最大值作為關(guān)鍵路徑延遲torch.stack(all_dispatch).max(dim0)run_ep_benchmark.py——因?yàn)橐淮?EP step 的完成時(shí)間取決于最慢的 rank這保證了指標(biāo)反映真實(shí)的全局關(guān)鍵路徑而非單卡樂(lè)觀值。compute_global_expert_load通過(guò)torch.bincount統(tǒng)計(jì)本地專(zhuān)家分配次數(shù)再all_reduce(SUM)得到全局計(jì)數(shù)輸出max/min/mean_tokens_per_expert與imbalance_ratio max/meanmetrics.py——該比值是衡量路由偏斜導(dǎo)致的負(fù)載不均程度的直接讀數(shù)k_hot 模式90% 流量打入 32 個(gè)專(zhuān)家會(huì)產(chǎn)生遠(yuǎn)高于 uniform 模式的 imbalance_ratio配合 p99/p999 可以觀察負(fù)載不均與尾部延遲的相關(guān)性。tokens_per_second (num_tokens × world_size) / (mean_e2e_ms / 1000)metrics.py注意分母是端到端周期均值而非 dispatchcombine 之和。標(biāo)準(zhǔn)輸出 JSON 結(jié)構(gòu)如下來(lái)自 README.md 的 schemaassemble_json_output在 metrics.py 中實(shí)現(xiàn){ benchmark: mooncake_ep, world_size: 8, num_experts: 256, hidden_size: 7168, routing_mode: k_hot, metrics: { dispatch_latency_ms: {p50: 0, p90: 0, p99: 0, p999: 0, mean: 0}, combine_latency_ms: {p50: 0, p90: 0, p99: 0, p999: 0, mean: 0}, end_to_end_latency_ms: {p50: 0, p90: 0, p99: 0, p999: 0, mean: 0}, tokens_per_second: 0, expert_load: { max_tokens_per_expert: 0, min_tokens_per_expert: 0, mean_tokens_per_expert: 0, imbalance_ratio: 0 }, per_rank_stats: { dispatch_latency_ms: { rank0: {p50: 0, p90: 0, p99: 0, p999: 0, mean: 0}, rank1: {p50: 0, p90: 0, p99: 0, p999: 0, mean: 0} }, combine_latency_ms: { rank0: {p50: 0, p90: 0, p99: 0, p999: 0, mean: 0}, rank1: {p50: 0, p90: 0, p99: 0, p999: 0, mean: 0} }, e2e_latency_ms: { rank0: {p50: 0, p90: 0, p99: 0, p999: 0, mean: 0}, rank1: {p50: 0, p90: 0, p99: 0, p999: 0, mean: 0} } } } }實(shí)際運(yùn)行時(shí)還會(huì)在頂層補(bǔ)充backend、top_k、num_tokens、dtype、zero_copy、async_finish、return_recv_hook、warmup_iters、iters、pg_backend字段并在 k_hot 模式下追加hot_experts/hot_fraction、zipf 模式下追加zipf_alphametrics.py便于結(jié)果歸檔與復(fù)現(xiàn)。使用--json-output時(shí)結(jié)果寫(xiě)入指定文件否則 rank 0 將 JSON 打印到 stdout。七、底層原理速覽dispatch/combine 的 C 實(shí)現(xiàn)了解底層實(shí)現(xiàn)有助于正確解讀基準(zhǔn)數(shù)據(jù)。C 運(yùn)行時(shí)mooncake.ep擴(kuò)展在 mooncake-ep/include/mooncake_ep_api.cuh 中暴露三個(gè)核心內(nèi)核入口dispatch(...)接收x、topk_idx、active_ranks寫(xiě)出packed_recv_x打包的接收數(shù)據(jù)、packed_recv_x_scalesfp8 縮放、packed_recv_src_info來(lái)源 rank 信息、packed_recv_layout_range布局范圍與packed_recv_count各專(zhuān)家槽位接收計(jì)數(shù)并支持timeout_ticks超時(shí)檢測(cè)與phases分階段同步mark_phase_ack/wait_phase_ack/mark_and_wait_phase_ack階段確認(rèn)原語(yǔ)用于跨 rank 的同步屏障無(wú) CUDA 協(xié)作網(wǎng)格能力的平臺(tái)會(huì)走 split SEND/RECV 路徑Python 層對(duì)此會(huì)發(fā)出 RuntimeWarningmooncake_ep_buffer.pycombine(...)接收各專(zhuān)家輸出與topk_idx/topk_weights/src_info/layout_range加權(quán)聚合回combined_x支持zero_copy標(biāo)志。MooncakeEpBuffer類(lèi)mooncake-ep/include/mooncake_ep_buffer.h內(nèi)部管理兩條傳輸路徑節(jié)點(diǎn)內(nèi) NVLink P2PP2pTransport通過(guò) IPC handle 與對(duì)端共享與跨節(jié)點(diǎn) IBGDA RDMARdmaTransportnullptr表示不可用。use_fast_path()的判定邏輯是IBGDA 可用或所有對(duì)端均可 P2P 訪問(wèn)否則回退到 Python 實(shí)現(xiàn)的降級(jí)路徑性能下降。因此基準(zhǔn)結(jié)果在不同網(wǎng)絡(luò)拓?fù)銷(xiāo)VLink-only、RoCE、IBGDA下會(huì)有顯著差異--pg-backend nccl與mooncake的對(duì)比正是用于量化 fast-path 收益。Python 層Buffer.dispatch/Buffer.combine的完整簽名、參數(shù)語(yǔ)義num_max_dispatch_tokens_per_rank容量、timeout_us-1禁用超時(shí)、use_fp8返回(data, scales)元組等可進(jìn)一步參考 docs/source/api-reference/python/ep-backend.md 中的 API reference 與 quick start 示例。八、實(shí)操建議如何做一輪有效的對(duì)比實(shí)驗(yàn)綜合以上機(jī)制推薦的最小對(duì)比實(shí)驗(yàn)矩陣如下均可直接用現(xiàn)有配置或 CLI 組合完成基線--routing-mode uniformcuda_uniform.json衡量通信層峰值偏斜壓力--routing-mode k_hot --hot-experts 32 --hot-fraction 0.9cuda_incast_k_hot.json觀察imbalance_ratio與 p99/p999 的抬升偏斜梯度--routing-mode zipf掃--zipf-alpha 0.5/1.0/1.5觀察偏斜程度與尾延遲的關(guān)系特性開(kāi)關(guān)固定路由模式對(duì)比--zero-copy --async-finish組合的開(kāi)與關(guān)、以及--async-finish與--return-recv-hook兩種同步方式的差異后端對(duì)比在具備 RDMA 的環(huán)境中對(duì)比--pg-backend nccl與--pg-backend mooncake量化 fast-path 收益。注意事項(xiàng)num_experts必須被num_ranks整除fp8 時(shí)hidden-size須為 128 的倍數(shù)--async-finish與--return-recv-hook不可同時(shí)開(kāi)啟解讀end_to_end_latency_ms時(shí)應(yīng)記住它包含 mock 專(zhuān)家前向不是純通信延遲多機(jī)實(shí)驗(yàn)優(yōu)先用torchrun并由其管理WORLD_SIZE。贊分享人工智能大模型模型推理服務(wù)后端【免費(fèi)下載鏈接】MooncakeMooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI.項(xiàng)目地址https://gitcode.com/gh_mirrors/mo/Mooncake點(diǎn)擊查看免費(fèi)下載相關(guān)推薦GPT-NeoX推理性能測(cè)試終極指南如何優(yōu)化大語(yǔ)言模型的吞吐量與延遲GPT NeoX推理性能測(cè)試終極指南如何優(yōu)化大語(yǔ)言模型的吞吐量與延遲 GPT NeoX是由EleutherAI開(kāi)發(fā)的開(kāi)源大語(yǔ)言模型訓(xùn)練框架基于DeepSpe深度學(xué)習(xí)NLP大模型分布式訓(xùn)練預(yù)訓(xùn)練nanomsg性能測(cè)試報(bào)告吞吐量與延遲基準(zhǔn)測(cè)試結(jié)果nanomsg性能測(cè)試報(bào)告吞吐量與延遲基準(zhǔn)測(cè)試結(jié)果 nanomsg是一個(gè)輕量級(jí)、高性能的套接字庫(kù)為構(gòu)建分布式應(yīng)用提供了簡(jiǎn)單而強(qiáng)大的消息傳遞能力。作為下一代消消息隊(duì)列通信上一篇BetterGI終極指南打造你的原神自動(dòng)化游戲體驗(yàn)下一篇終極碧藍(lán)航線自動(dòng)化腳本告別重復(fù)操作重獲游戲樂(lè)趣創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考