戰(zhàn)指南)
推理引擎大模型【免費(fèi)下載鏈接】FlexGenRunning large language models on a single GPU for throughput-oriented scenarios.項(xiàng)目地址https://gitcode.com/gh_mirrors/fl/FlexGen點(diǎn)擊查看免費(fèi)下載本文以 FlexGen 倉(cāng)庫(kù)中收錄的論文《High-throughput Generative Inference of Large Language Models with a Single GPU》為核心骨架結(jié)合倉(cāng)庫(kù)源碼flexgen/flex_opt.py、flexgen/compression.py、experimental/cost_model.py 等展開(kāi)解讀。通過(guò)本文你將理解 FlexGen 如何在單塊普通 GPU如 16GB T4上通過(guò) GPU/CPU/磁盤(pán)三級(jí)異構(gòu)聚合、線性規(guī)劃策略搜索與 4-bit 分組量化將 OPT-175B 級(jí)別的模型吞吐推升至 1 token/s 以上并掌握--percent卸載策略、壓縮開(kāi)關(guān)、HELM 基準(zhǔn)接入與分布式擴(kuò)展的完整實(shí)操方法。FlexGen 的定位是面向吞吐優(yōu)先throughput-oriented場(chǎng)景的生成引擎這類任務(wù)批量評(píng)測(cè)、信息抽取、數(shù)據(jù)整理、表單處理需要以批處理方式在數(shù)百萬(wàn) token 上反復(fù)運(yùn)行 LLM對(duì)單次延遲不敏感但對(duì)整段運(yùn)行時(shí)間的 token 吞吐率極為敏感。其核心思想是用 I/O 效率換延遲在低成本單 GPU 硬件上把批大小做到傳統(tǒng)方案無(wú)法企及的規(guī)模從而顯著提升最大吞吐。倉(cāng)庫(kù) README 同時(shí)明確列出了其局限性作為基于卸載offloading的系統(tǒng)在弱 GPU 上、尤其是小批量場(chǎng)景下其速度仍遠(yuǎn)低于擁有足夠強(qiáng) GPU 將整個(gè)模型駐留顯存的方案因此它主要針對(duì)單 GPU 上的批量處理設(shè)置優(yōu)化。一、論文核心貢獻(xiàn)為什么單卡能跑 175B 模型1.1 問(wèn)題背景LLM 推理的資源門(mén)檻論文摘要指出大語(yǔ)言模型推理的傳統(tǒng)路徑需要多塊高端加速器才能可行。而現(xiàn)實(shí)中出現(xiàn)了一批延遲不敏感l(wèi)atency-insensitive的批量處理任務(wù)公司內(nèi)部全部私有文檔的分類與抽取、HELM 基準(zhǔn)上全部任務(wù)的跑分等。這類工作負(fù)載允許晚上提交作業(yè)、隔夜跑完的運(yùn)行方式代價(jià)是吞吐率直接決定成本——吞吐被定義為任務(wù)整個(gè)運(yùn)行時(shí)間可達(dá)數(shù)小時(shí)內(nèi)每秒處理的 token 數(shù)。這種特性使得用延遲換吞吐成為可行策略也讓低成本的普通商用 GPU 有了用武之地。1.2 三大關(guān)鍵技術(shù)FlexGen 應(yīng)對(duì)資源約束的三大手段README How It Works 一節(jié)與論文摘要一致異構(gòu)資源聚合GPU CPU Disk在不同硬件資源約束下靈活配置把權(quán)重、激活、注意力 KV cache 分散存放在 GPU 顯存、CPU 內(nèi)存與磁盤(pán)上按需加載計(jì)算線性規(guī)劃LP策略優(yōu)化器通過(guò)線性規(guī)劃自動(dòng)搜索張量存哪里、何時(shí)訪問(wèn)的最優(yōu)模式在給定硬件GPU/CPU/磁盤(pán)容量與帶寬約束下最大化吞吐4-bit 分組量化壓縮對(duì)權(quán)重與注意力 KV cache 均壓縮到 4 bit精度損失可忽略negligible從而把可容納的批大小上限大幅抬升。1.3 代表性結(jié)果以論文/README 為準(zhǔn)論文摘要給出了兩個(gè)標(biāo)志性結(jié)論均基于 GCP 上單塊 NVIDIA T416GB實(shí)例、208GB DRAM、1.5TB SSD 的環(huán)境input seq len512output seq len32批大小調(diào)至各系統(tǒng)最大吞吐值運(yùn)行 OPT-175B 時(shí)FlexGen首次在單 16GB GPU 上達(dá)到 1 token/s 的生成吞吐有效批大小 144配合壓縮后的數(shù)字見(jiàn)下文性能表在 HELM 基準(zhǔn)上FlexGen 用 16GB GPU 在 21 小時(shí)內(nèi)完成了 30B 模型在 7 個(gè)代表性子場(chǎng)景下的跑分。二、上手實(shí)測(cè)從 OPT-1.3B 到 OPT-175B2.1 安裝倉(cāng)庫(kù) README 給出兩種安裝方式唯一硬性要求是PyTorch 1.12# 方式一pip 安裝 pip install flexgen # 方式二源碼安裝 git clone https://github.com/FMInference/FlexGen.git cd FlexGen pip install -e .2.2 OPT-1.3B無(wú)卸載快速體驗(yàn)小模型可直接放進(jìn)單 GPU無(wú)需卸載。FlexGen 會(huì)自動(dòng)從 Hugging Face 下載權(quán)重python3 -m flexgen.flex_opt --model facebook/opt-1.3b運(yùn)行后會(huì)看到 OPT-1.3B 生成的文本以及 benchmark 結(jié)果prefill/decode 延遲與吞吐見(jiàn) flex_opt.py 的日志邏輯。2.3 OPT-30B引入 CPU 卸載與--percentpython3 -m flexgen.flex_opt --model facebook/opt-30b --percent 0 100 100 0 100 0--percent是 FlexGen 最核心的參數(shù)。它接收 6 個(gè)整數(shù)依次表示源碼注釋原文見(jiàn) flex_opt.py位置含義默認(rèn)值1權(quán)重放在 GPU 的百分比1002權(quán)重放在 CPU 的百分比03注意力 cache 放在 GPU 的百分比1004注意力 cache 放在 CPU 的百分比05激活activations放在 GPU 的百分比1006激活放在 CPU 的百分比0每一類的磁盤(pán)百分比是隱含的第三項(xiàng)由Policy屬性計(jì)算得出flex_opt.pyproperty def w_disk_percent(self): # 權(quán)重磁盤(pán)占比 return 100 - self.w_gpu_percent - self.w_cpu_percent property def cache_disk_percent(self): # cache 磁盤(pán)占比 return 100 - self.cache_gpu_percent - self.cache_cpu_percent property def act_disk_percent(self): # 激活磁盤(pán)占比 return 100 - self.act_gpu_percent - self.act_cpu_percent實(shí)際分配時(shí)init_weight_list會(huì)按張量體積的累計(jì)分布cumsum把不同權(quán)重切成三段分別落到磁盤(pán)、CPU、GPUflex_opt.py。因此--percent 0 100 100 0 100 0的含義是權(quán)重全部放 CPU、cache 與激活全部放 GPU——這是 30B 在 16GB 顯卡上的典型起點(diǎn)。參考策略可見(jiàn) benchmark/flexgen/bench_suite.py30B 無(wú)壓縮時(shí)通常采用--percent 20 80 0 100 0 100或--percent 10 90 0 100 0 100約 10%~20% 權(quán)重駐留 GPU其余在 CPU并搭配--gpu-batch-size 48 --num-gpu-batches 3之類的分批參數(shù)。2.4 OPT-175B全量卸載到磁盤(pán)OPT-175B 需要先從 metaseq 項(xiàng)目下載權(quán)重并按 Alpa 格式轉(zhuǎn)換然后可將全部權(quán)重卸載到 SSDpython3 -m flexgen.flex_opt --model facebook/opt-175b --percent 0 0 100 0 100 0 --offload-dir YOUR_SSD_FOLDER--offload-dir默認(rèn)值為~/flexgen_offload_dirflex_opt.py用于存放卸載到磁盤(pán)的張量。三、吞吐優(yōu)先場(chǎng)景HELM 基準(zhǔn)與數(shù)據(jù)整理應(yīng)用3.1 將 FlexGen 接入 HELMFlexGen 可以作為 HELM 的執(zhí)行后端。README 給出的 MMLU 場(chǎng)景示例命令可在單塊 T416GB 200GB DRAM 上運(yùn)行pip install crfm-helm python3 -m flexgen.apps.helm_run --description mmlu:modeltext,subjectabstract_algebra,data_augmentationcanonical --pad-to-seq-len 512 --model facebook/opt-30b --percent 20 80 0 100 0 100 --gpu-batch-size 48 --num-gpu-batches 3 --max-eval-instance 100實(shí)現(xiàn)側(cè)flexgen/apps/helm_run.py 中的execute會(huì)構(gòu)造ExecutionEnv與Policy將 HELM 請(qǐng)求按effective_bs分批get_batches先用 tokenizer 把 prompt 填充到pad_to_seq_len再按 batch_size 切分helm_run.py。README 提醒僅測(cè)試了部分 HELM 場(chǎng)景已測(cè)試場(chǎng)景清單見(jiàn) flexgen/apps/helm_passed_30b.sh。3.2 數(shù)據(jù)整理Data Wrangling任務(wù)論文的姊妹工作《Can Foundation Models Wrangle Your Data?》中的示例可以直接復(fù)現(xiàn)操作說(shuō)明位于 flexgen/apps/data_wrangle。該目錄下 data_wrangle_run.py 同時(shí)提供single_query_test與batch_query_test兩種模式分別對(duì)應(yīng)單條查詢與批量查詢測(cè)試腳本如 test_batch_query_all_opt30b.sh正是吞吐優(yōu)先場(chǎng)景的典型落地。四、API 使用Hugging Face 風(fēng)格的生成接口4.1 生成 APIFlexGen 提供仿 Hugging Face transformers 風(fēng)格的生成 API核心簽名見(jiàn) completion.pyoutput_ids model.generate( input_ids, do_sampleTrue, temperature0.7, max_new_tokens32, stopstop)底層OptLM.generate支持debug_mode、cut_gen_len截?cái)嗌砷L(zhǎng)度用于快速調(diào)試等參數(shù)并內(nèi)置 normal / overlap 兩類生成循環(huán)generation_loop_normal、generation_loop_overlap_single_batch、generation_loop_overlap_multi_batch等見(jiàn) flex_opt.py 中的方法定義。4.2 示例命令完整 OPT-6.7B至少 15GB 顯存python3 -m flexgen.apps.completion --model facebook/opt-6.7b完整 OPT-30B約需 90GB CPU 內(nèi)存python3 -m flexgen.apps.completion --model facebook/opt-30b --percent 0 100 100 0 100 0指令微調(diào)的 OPT-IML-MAX-30B同樣約需 90GB CPU 內(nèi)存python3 -m flexgen.apps.completion --model facebook/opt-iml-max-30b --percent 0 100 100 0 100 0注意completion.py內(nèi)置了兩個(gè)示例 prompt奧運(yùn)會(huì)地點(diǎn)問(wèn)答、機(jī)場(chǎng)代碼抽取并在生成結(jié)束后調(diào)用env.close_copy_threads()關(guān)閉磁盤(pán)拷貝線程completion.py。五、性能數(shù)據(jù)與復(fù)現(xiàn)方法5.1 生成吞吐對(duì)比表README Performance Results 中的對(duì)比表括號(hào)內(nèi)為有效批大小及其最低卸載層級(jí)硬件為 GCP 上 T4 16GB 208GB DRAM 1.5TB SSDworkload 為 input512 / output32批大小按各系統(tǒng)最大吞吐調(diào)優(yōu)吞吐定義為 生成 token 數(shù) ÷prompt 處理時(shí)間 生成時(shí)間系統(tǒng)OPT-6.7BOPT-30BOPT-175BHugging Face Accelerate25.12 (2 on GPU)0.62 (8 on CPU)0.01 (2 on disk)DeepSpeed ZeRO-Inference9.28 (16 on CPU)0.60 (4 on CPU)0.01 (1 on disk)Petals8.25 (2 on GPU)2.84 (2 on GPU)0.08 (2 on GPU)FlexGen25.26 (2 on GPU)7.32 (144 on CPU)0.69 (256 on disk)FlexGen with Compression29.12(72 on GPU)8.38(512 on CPU)1.12(144 on CPU)對(duì)應(yīng)的有效批大小表與 Petals 基線說(shuō)明見(jiàn) benchmark/batch_size_table.md。完整復(fù)現(xiàn)方法含 1x1 / 1x4 / 4x1 等多種拓?fù)涞?shell 腳本與 bench_suite.py 自動(dòng)化套件見(jiàn) benchmark/flexgen/README.md。從 bench_suite.py 可以直觀看到壓縮帶來(lái)的批大小提升30B 無(wú)壓縮時(shí)--gpu-batch-size 48 --num-gpu-batches 3有效批 144而啟用--compress-cache后達(dá)到--gpu-batch-size 64 --num-gpu-batches 8有效批 512——與 README 表中數(shù)字一一對(duì)應(yīng)。175B 壓縮配置則采用--percent 0 100 0 100 0 100 --compress-weight --compress-cache的全 CPU策略配合--pin-weight 0以緩解內(nèi)存壓力。5.2 延遲-吞吐權(quán)衡Pareto 前沿README 中docs/throughput_vs_latency.jpg查看圖片展示了三個(gè)基于卸載的系統(tǒng)在 OPT-175B左與 OPT-30B右上的延遲-吞吐曲線FlexGen 達(dá)成新的 Pareto 最優(yōu)前沿最大吞吐顯著更高而其他系統(tǒng)因內(nèi)存不足無(wú)法繼續(xù)增大批大小圖中 FlexGen(c) 即啟用壓縮的 FlexGen。六、工作原理批調(diào)度、I/O 重疊與策略搜索6.1 吞吐視角下的延遲-吞吐權(quán)衡FlexGen 的關(guān)鍵洞見(jiàn)是主動(dòng)利用延遲-吞吐權(quán)衡卸載方案天生難以實(shí)現(xiàn)低延遲但在吞吐優(yōu)先場(chǎng)景下卸載的 I/O 效率可以被大幅提升。具體手段是block schedule塊調(diào)度按塊復(fù)用權(quán)重、把 I/O 與計(jì)算重疊overlap而基線系統(tǒng)普遍采用低效的逐行row-by-row調(diào)度。README 用 docs/block_schedule.jpg 直觀對(duì)比了兩種調(diào)度方式a 為基線逐行、b 為 FlexGen 塊調(diào)度。這一思想在源碼中落地為Policy的overlap字段默認(rèn) True見(jiàn) flex_opt.py以及OptLM的三套生成循環(huán)generation_loop_overlap_single_batch與generation_loop_overlap_multi_batch專門(mén)負(fù)責(zé)在多 GPU batch 之間交錯(cuò)加載權(quán)重與計(jì)算從而隱藏磁盤(pán)/CPU 加載延遲。benchmark 套件中常見(jiàn)--overlap False的對(duì)照實(shí)驗(yàn)bench_suite.py便于量化重疊帶來(lái)的收益。6.2 線性規(guī)劃策略優(yōu)化器與成本模型論文所述通過(guò)線性規(guī)劃優(yōu)化器搜索張量存儲(chǔ)與訪問(wèn)的最優(yōu)模式對(duì)應(yīng)倉(cāng)庫(kù) experimental/cost_model.py。它基于pulp線性規(guī)劃庫(kù)實(shí)現(xiàn)典型用法# 1. 在給定硬件約束下自動(dòng)搜索最優(yōu)策略 python cost_model.py --model facebook/opt-30b --prompt-len 512 --gen-len 32 \ --gpu-mem 16 --cpu-mem 200 --nvme-mem 1500 # 2. 估算給定策略的吞吐 python cost_model.py --model facebook/opt-30b --prompt-len 512 --gen-len 32 \ --gpu-mem 16 --cpu-mem 200 --nvme-mem 1500 \ --gpu-batch-size 48 --num-gpu-batches 3 \ --percent 20 80 0 100 0 100 \ --alpha-g 1.2 --alpha-c 1.2 --alpha-n 1.2文件頭部注釋明確給出了使用須知cost_model.py硬件常數(shù)CostModelConfig需要針對(duì)自己的設(shè)備重新擬合作者通過(guò)采集真實(shí)運(yùn)行數(shù)據(jù)點(diǎn)用梯度下降擬合直接 profile 單個(gè)算子或從網(wǎng)絡(luò)抄數(shù)都不準(zhǔn)確alpha_g/alpha_c/alpha_n是峰值內(nèi)存估計(jì)的松弛系數(shù)調(diào)小策略偏保守、調(diào)大偏激進(jìn)當(dāng)前模型不考慮 CPU 計(jì)算委托且量化支持不完整。README 的 Roadmap 也標(biāo)注Release the cost model and policy optimizer為已完成項(xiàng)[X]。6.3 4-bit 分組量化權(quán)重與 KV cache 雙壓縮壓縮由 flexgen/compression.py 實(shí)現(xiàn)核心是CompressionConfig分組量化配置與TorchCompressedDevice壓縮張量管理設(shè)備。運(yùn)行時(shí)通過(guò)兩個(gè)開(kāi)關(guān)開(kāi)啟--compress-weight # 壓縮權(quán)重約省 70% 權(quán)重內(nèi)存 --compress-cache # 壓縮 KV cache兩者默認(rèn)的分組量化配置flex_opt.py為權(quán)重CompressionConfig(num_bits4, group_size64, group_dim0, symmetricFalse)cacheCompressionConfig(num_bits4, group_size64, group_dim2, symmetricFalse)從 compression.py 的實(shí)現(xiàn)可以看到壓縮存儲(chǔ)的具體形態(tài)4-bit 數(shù)據(jù)按group_size64分組data張量按每 2 個(gè) 4-bit 值打包成 1 個(gè) uint8的方式存放data_shape shape[:group_dim] (num_groups * (group_size // 2),) ...并附帶一個(gè) fp16 的scale張量記錄每組縮放因子。compress/decompress函數(shù)完成實(shí)際量化與反量化cache 壓縮時(shí)還會(huì)在 CPU 上分配 fp32 反量化工作區(qū)init_attention_compute_workspace見(jiàn) compression.py。README 提示權(quán)重壓縮大約可減少 70% 的權(quán)重內(nèi)存且論文報(bào)告壓縮后精度損失可忽略negligible。6.4 執(zhí)行環(huán)境與內(nèi)存層級(jí)抽象FlexGen 把硬件抽象為統(tǒng)一的內(nèi)存層級(jí)utils.py 的ExecutionEnv pytorch_backend.py 中的TorchDevice/TorchDisk/TorchMixedDevicegpu TorchDevice(cuda:0) cpu TorchDevice(cpu) disk TorchDisk(args.offload_dir) env ExecutionEnv(gpugpu, cpucpu, diskdisk, mixedTorchMixedDevice([gpu, cpu, disk]))權(quán)重按Policy的百分比切分后分別allocate在 disk/cpu/gpu 上init_weight_list推理時(shí)通過(guò)load_weight/load_cache/store_cache在層級(jí)間搬運(yùn)磁盤(pán)側(cè)使用多線程拷貝TorchDisk默認(rèn) 4 個(gè)拷貝線程隱藏 I/O 延遲。--pin-weight 0可關(guān)閉 CPU 端權(quán)重頁(yè)鎖定pinned memory約減少 20% 以上的 CPU 權(quán)重內(nèi)存占用README FAQ代價(jià)是拷貝稍慢。6.5 分布式擴(kuò)展卸載 流水線并行當(dāng)多機(jī)多卡但聚合顯存仍小于模型大小時(shí)FlexGen 可把卸載與流水線并行pipeline parallelism結(jié)合DistOptLMdist_flex_opt.py繼承OptLM引入pipeline_rank/num_pipeline_stages/comm_device等參數(shù)并通過(guò)send_hidden/recv_hidden在流水線階段間傳遞激活。README 提示要獲得可擴(kuò)展的性能GPU 應(yīng)分布在多臺(tái)機(jī)器上同機(jī)多卡性能優(yōu)化仍在其 Roadmap 中列為未完成項(xiàng)。分布式 benchmark 腳本見(jiàn) benchmark/flexgen/bench_dist_single_node.sh 與 benchmark/flexgen/bench_dist_multi_node.sh。七、FAQ策略調(diào)參與內(nèi)存不足排查7.1 如何設(shè)置卸載策略--percentREADME 明確說(shuō)明目前需要手工嘗試若干策略自動(dòng)策略優(yōu)化器已隨 cost model 發(fā)布但調(diào)優(yōu)仍需人工??傮w原則是盡可能把參數(shù)與注意力 cache 卸載到 CPU、必要時(shí)到磁盤(pán)從而把顯存讓給更大的批大小??芍苯訁⒖?bench_suite.py 中的基準(zhǔn)參考策略。出現(xiàn) OOM 時(shí)把--percent中對(duì)應(yīng)項(xiàng)調(diào)向 CPU/磁盤(pán)方向即可卸載更多張量。7.2 內(nèi)存不足OOM時(shí)怎么辦README FAQ 給出三條由省內(nèi)存 → 更慢排序的應(yīng)急手段不鎖定權(quán)重加--pin-weight 0CPU 權(quán)重內(nèi)存約省 20% 以上壓縮權(quán)重加--compress-weight權(quán)重內(nèi)存約省 70%權(quán)重全部落盤(pán)--percent 0 0 100 0 100 0配合--offload-dir幾乎不占 CPU 與 GPU 內(nèi)存。更進(jìn)階的排查可借助profile_bandwidth.pyflexgen/profile_bandwidth.py測(cè)磁盤(pán)與 PCIe 帶寬與profile_matmul.pyflexgen/profile_matmul.py測(cè)矩陣乘性能先行刻畫(huà)本機(jī)硬件常數(shù)再用 cost_model.py 預(yù)估各策略的吞吐減少盲目試參。八、結(jié)語(yǔ)與路線圖FlexGen 證明了一條弱硬件 極致 I/O 調(diào)度 壓縮 大批量的可行路徑在 16GB 單卡上首次達(dá)到 OPT-175B 的 1 token/s 生成吞吐并把 HELM 30B 跑分壓縮到 21 小時(shí)。它明確面向吞吐優(yōu)先的批量場(chǎng)景代價(jià)是小批量/低延遲場(chǎng)景不具優(yōu)勢(shì)。README Roadmap 顯示其后續(xù)計(jì)劃包括優(yōu)化同機(jī)多卡性能、支持更多模型BLOOM、CodeGen、GLM、MacbookM1/M2與 AMD 支持。論文全文出處為 docs/paper.md 所收錄的 arXiv 論文《High-throughput Generative Inference of Large Language Models with a Single GPU》arXiv:2303.06865作者包括 Ying Sheng、Lianmin Zheng 等Subj 分類為 cs.LG / cs.AI / cs.PF。贊分享推理引擎大模型【免費(fèi)下載鏈接】FlexGenRunning large language models on a single GPU for throughput-oriented scenarios.項(xiàng)目地址https://gitcode.com/gh_mirrors/fl/FlexGen點(diǎn)擊查看免費(fèi)下載相關(guān)推薦推薦文章FlexGen——單GPU下大型語(yǔ)言模型高吞吐量推理的新引擎推薦文章FlexGen——單GPU下大型語(yǔ)言模型高吞吐量推理的新引擎 在當(dāng)今人工智能的快速發(fā)展中大型語(yǔ)言模型LLMs正以前所未有的方式重塑我們對(duì)信息處理推理引擎大模型FlexGen 單 GPU 高吞吐大語(yǔ)言模型推理引擎從安裝、Offloading 策略到 HELM 與數(shù)據(jù)整理實(shí)戰(zhàn)FlexGen 單 GPU 高吞吐大語(yǔ)言模型推理引擎從安裝、Offloading 策略到 HELM 與數(shù)據(jù)整理實(shí)戰(zhàn) FlexGen 是一個(gè)面向吞吐優(yōu)先th推理引擎大模型FlexGen 基準(zhǔn)測(cè)試實(shí)戰(zhàn)指南單 GPU 與多機(jī)多卡 OPT 模型吞吐量測(cè)試全解析FlexGen 基準(zhǔn)測(cè)試實(shí)戰(zhàn)指南單 GPU 與多機(jī)多卡 OPT 模型吞吐量測(cè)試全解析 本篇技術(shù)指南圍繞 FlexGen 官方基準(zhǔn)測(cè)試方案 benchmark推理引擎大模型上一篇終極指南如何使用 cmp-buffer 插件提升 Neovim 代碼補(bǔ)全效率下一篇OpenVEX 漏洞披露數(shù)據(jù)管理指南以 minikube 倉(cāng)庫(kù) .openvex 模板目錄與 vexctl 發(fā)布集成為例創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考