換與性能實(shí)測)
1. 為什么要在 RK3568 上折騰圖像分類模型部署RK3568 這顆芯片在邊緣計(jì)算圈子里火了好幾年四核 A55 加一顆 0.8 TOPS 的 NPU價格壓得很低功耗也友好做工業(yè)質(zhì)檢、智能門禁、零售貨架分析這類場景的兄弟基本都繞不開它。但真要把圖像分類模型塞進(jìn)去跑起來事情遠(yuǎn)沒有規(guī)格書寫的那么輕松——算力賬要算清楚量化精度會掉算子支持有坑前后處理還得自己寫。我前后在 RK3568 上部署過 ResNet、MobileNet、EfficientNet、ViT 這幾類主流分類模型踩的坑足夠?qū)懸槐拘宰舆@篇就把整個實(shí)驗(yàn)過程和結(jié)論攤開來講。先說清楚這篇文章適合誰看。如果你手里已經(jīng)有一塊 RK3568 開發(fā)板想跑圖像分類但不知道從哪下手或者你已經(jīng)跑通了官方 demo但換成自己的模型就各種報(bào)錯再或者你在選型階段想知道這顆 NPU 到底能扛多大的模型、精度損失能不能接受——那這篇內(nèi)容基本能覆蓋你的需求。我會從模型選型、量化轉(zhuǎn)換、板端部署、性能實(shí)測到問題排查一條線走完參數(shù)和命令都給到能直接抄的程度。需要提前說明的是RK3568 的 NPU 是瑞芯微自研的 RKNN 架構(gòu)它不像 GPU 那樣通用算子支持是白名單制。這意味著你不能指望 PyTorch 里能跑的模型直接轉(zhuǎn)過去就能跑中間必須經(jīng)過 RKNN-Toolkit2 做量化轉(zhuǎn)換而且轉(zhuǎn)換過程中會遇到算子不支持、量化掉點(diǎn)、輸入輸出對不齊等一系列問題。理解這一點(diǎn)后面的很多現(xiàn)象就都能解釋了。2. 實(shí)驗(yàn)環(huán)境與模型選型的前期準(zhǔn)備2.1 硬件與軟件環(huán)境清單先把環(huán)境交代清楚不然后面復(fù)現(xiàn)的時候?qū)Σ簧?。硬件這邊我用的是 RK3568 開發(fā)板4GB 內(nèi)存版本NPU 驅(qū)動版本 0.8.2系統(tǒng)是 Buildroot 加 Linux 5.10 內(nèi)核。PC 端用的是 Ubuntu 20.04Python 3.8RKNN-Toolkit2 版本 1.5.2。這里要特別注意版本匹配問題RKNN-Toolkit2 的版本和板端 runtime 版本必須對應(yīng)否則會出現(xiàn)模型加載失敗或者推理結(jié)果異常的情況這個坑我在后面問題排查章節(jié)會詳細(xì)講。項(xiàng)目配置開發(fā)板RK35684GB LPDDR4NPU 算力0.8 TOPSINT8板端系統(tǒng)Buildroot Linux 5.10NPU 驅(qū)動0.8.2PC 系統(tǒng)Ubuntu 20.04Python3.8RKNN-Toolkit21.5.2推理框架RKNN Runtime軟件安裝這塊RKNN-Toolkit2 建議用 conda 建獨(dú)立環(huán)境因?yàn)樗鼘?numpy、onnx 這些依賴的版本卡得比較死。我試過直接在系統(tǒng) Python 里裝結(jié)果和已有的 torch 環(huán)境沖突折騰了半天。用 conda 隔離是最省事的做法conda create -n rknn python3.8 conda activate rknn pip install rknn-toolkit21.5.2 pip install onnx1.12.0 pip install torch1.13.0 torchvision0.14.0注意RKNN-Toolkit2 只支持 x86 的 Linux 環(huán)境做模型轉(zhuǎn)換Windows 和 Mac 都不行。如果你主力機(jī)是 Windows老老實(shí)實(shí)裝個 Ubuntu 虛擬機(jī)或者雙系統(tǒng)別在這上面浪費(fèi)時間。2.2 圖像分類模型的選型邏輯圖像分類模型這幾年迭代很快從最早的 AlexNet、VGG到 ResNet 殘差結(jié)構(gòu)再到 MobileNet 的深度可分離卷積以及后來 EfficientNet 的復(fù)合縮放最后到 ViT 把 Transformer 搬進(jìn)視覺領(lǐng)域。但在 RK3568 這種邊緣 NPU 上選型邏輯和服務(wù)器端完全不一樣核心就三條算子兼容性、參數(shù)量、量化友好度。ResNet 系列是繞不開的基準(zhǔn)ResNet18 參數(shù)量 11M 左右結(jié)構(gòu)規(guī)整全是標(biāo)準(zhǔn)卷積和殘差連接RKNN 對它的支持非常成熟基本是拿來就能轉(zhuǎn)。MobileNetV2 用了深度可分離卷積和倒殘差結(jié)構(gòu)參數(shù)量只有 3.4M算力需求低是邊緣部署的??偷?ReLU6 激活和某些版本的實(shí)現(xiàn)方式在量化時容易出問題。EfficientNet 用了 Swish 激活函數(shù)這個激活在 RKNN 上的支持一直不太穩(wěn)定需要替換成 ReLU 或者 HardSwish 才能順利轉(zhuǎn)換。ViT 這類 Transformer 模型算子復(fù)雜包含大量矩陣乘和 LayerNormRK3568 的 NPU 對 LayerNorm 支持有限實(shí)測下來要么轉(zhuǎn)不過去要么性能慘不忍睹。所以這次實(shí)驗(yàn)我選了四個有代表性的模型ResNet18、MobileNetV2、EfficientNet-B0、ViT-Base。前三個是 CNN 路線的典型代表ViT 用來驗(yàn)證 Transformer 在邊緣 NPU 上的可行性邊界。每個模型都用 ImageNet 預(yù)訓(xùn)練權(quán)重輸入尺寸統(tǒng)一到 224x224這樣對比才公平。2.3 數(shù)據(jù)集與評估指標(biāo)評估用的數(shù)據(jù)集是 ImageNet 驗(yàn)證集的子集取了 1000 張圖覆蓋 100 個類別每類 10 張。用子集而不是全集主要是為了在板端跑推理的時候節(jié)省時間畢竟板子跑一次全量驗(yàn)證集要幾個小時。評估指標(biāo)除了 Top-1 和 Top-5 準(zhǔn)確率還重點(diǎn)看量化前后的精度損失、單幀推理延遲、內(nèi)存占用和 NPU 利用率。精度損失這個指標(biāo)特別關(guān)鍵。FP32 模型在 PC 上跑出來的準(zhǔn)確率是基準(zhǔn)轉(zhuǎn)成 INT8 量化模型后準(zhǔn)確率會掉掉多少直接決定了這個模型能不能用。一般來說掉 1% 以內(nèi)算優(yōu)秀1% 到 3% 可以接受超過 3% 就要考慮是不是量化策略有問題或者這個模型本身就不適合 INT8。延遲方面RK3568 的 NPU 單次推理時間在幾十毫秒量級具體取決于模型復(fù)雜度這個數(shù)據(jù)直接決定了你的應(yīng)用能不能做到實(shí)時。3. 模型轉(zhuǎn)換與量化實(shí)操全流程3.1 從 PyTorch 到 ONNX 的導(dǎo)出細(xì)節(jié)RKNN-Toolkit2 支持從 ONNX、TensorFlow、Caffe 等多種格式導(dǎo)入但實(shí)際用下來 ONNX 是最穩(wěn)的路徑。PyTorch 模型導(dǎo)出 ONNX 看著簡單一行 torch.onnx.export 就完事但里面的坑不少。首先是 opset 版本RKNN-Toolkit2 1.5.2 對 opset 11 和 12 支持最好用太新的版本會碰到不支持的算子。其次是動態(tài)軸的問題導(dǎo)出的時候一定要把 batch 維度固定住RK3568 的 NPU 不支持動態(tài) batch你導(dǎo)出成 dynamic 的話轉(zhuǎn)換階段就會報(bào)錯。以 ResNet18 為例導(dǎo)出命令是這樣的import torch import torchvision.models as models model models.resnet18(pretrainedTrue) model.eval() dummy_input torch.randn(1, 3, 224, 224) torch.onnx.export( model, dummy_input, resnet18.onnx, opset_version11, input_names[input], output_names[output], do_constant_foldingTrue )導(dǎo)出完成后強(qiáng)烈建議用 onnxsim 做一次簡化把冗余的算子合并掉這樣轉(zhuǎn)換出來的 RKNN 模型會更干凈推理效率也更高pip install onnxsim onnxsim resnet18.onnx resnet18_sim.onnx實(shí)操心得導(dǎo)出 ONNX 之后一定要用 Netron 打開看一眼確認(rèn)輸入輸出的名字、維度、數(shù)據(jù)類型都對。我遇到過好幾次因?yàn)檩敵龉?jié)點(diǎn)名字不對導(dǎo)致后面 RKNN 轉(zhuǎn)換時找不到輸出層的情況排查起來很費(fèi)時間。3.2 RKNN 量化轉(zhuǎn)換的關(guān)鍵參數(shù)ONNX 準(zhǔn)備好之后就進(jìn)入 RKNN 轉(zhuǎn)換環(huán)節(jié)。這一步是整個流程里最核心也最容易出問題的部分。轉(zhuǎn)換腳本的基本結(jié)構(gòu)是創(chuàng)建 RKNN 對象、配置參數(shù)、加載 ONNX、構(gòu)建模型、導(dǎo)出 RKNN。配置參數(shù)里最重要的是量化方式和量化數(shù)據(jù)集。from rknn.api import RKNN rknn RKNN(verboseTrue) rknn.config( mean_values[[123.675, 116.28, 103.53]], std_values[[58.395, 57.12, 57.375]], target_platformrk3568, quantized_dtypeasymmetric_quantized-8, optimization_level3 ) rknn.load_onnx(modelresnet18_sim.onnx) rknn.build(do_quantizationTrue, datasetquant_dataset.txt) rknn.export_rknn(resnet18.rknn)這里的 mean 和 std 要和訓(xùn)練時的預(yù)處理保持一致不然精度會莫名其妙地掉。quantized_dtype 選 asymmetric_quantized-8 是 INT8 非對稱量化這是 RK3568 上精度和性能平衡最好的選擇。optimization_level 設(shè)成 3 會做更激進(jìn)的圖優(yōu)化但偶爾會引入精度問題如果發(fā)現(xiàn)掉點(diǎn)嚴(yán)重可以降到 2 試試。量化數(shù)據(jù)集dataset.txt里放的是校準(zhǔn)圖片的路徑一般準(zhǔn)備 100 到 200 張有代表性的圖就夠了。這些圖要覆蓋你實(shí)際應(yīng)用場景的分布比如你做工業(yè)質(zhì)檢校準(zhǔn)集里就應(yīng)該是工業(yè)零件圖而不是隨便拿 ImageNet 的圖湊數(shù)。校準(zhǔn)集選得好量化精度能提升不少這是很多人忽略的一點(diǎn)。3.3 量化精度損失的實(shí)測對比四個模型轉(zhuǎn)換完成后我在 PC 端用 RKNN-Toolkit2 的仿真功能先跑了一遍精度對比結(jié)果如下模型FP32 Top-1INT8 Top-1精度損失轉(zhuǎn)換耗時ResNet1869.8%69.1%0.7%約 3 分鐘MobileNetV271.9%70.2%1.7%約 2 分鐘EfficientNet-B077.1%73.5%3.6%約 5 分鐘ViT-Base81.1%轉(zhuǎn)換失敗--ResNet18 的表現(xiàn)最好精度只掉了 0.7%這符合預(yù)期因?yàn)樗慕Y(jié)構(gòu)最規(guī)整量化友好。MobileNetV2 掉了 1.7%主要問題出在深度可分離卷積的逐通道量化上不同通道的數(shù)值分布差異大統(tǒng)一量化會損失精度。EfficientNet-B0 掉了 3.6%這個損失就比較肉疼了原因是 Swish 激活被替換成了 ReLU模型表達(dá)能力下降。ViT-Base 直接轉(zhuǎn)換失敗報(bào)的是 LayerNorm 算子不支持這個后面單獨(dú)說。注意仿真精度和板端實(shí)際精度會有細(xì)微差異一般板端會比仿真再低 0.2% 到 0.5%因?yàn)榘宥松婕皩?shí)際的定點(diǎn)運(yùn)算。所以仿真階段精度損失超過 3% 的模型板端基本就沒法用了。4. 板端部署與性能實(shí)測4.1 交叉編譯與板端環(huán)境搭建模型轉(zhuǎn)好了接下來要把它放到板子上跑。RK3568 的板端推理用的是 RKNN RuntimeC 接口的 API。你需要把 RKNN Runtime 的庫和頭文件交叉編譯進(jìn)你的應(yīng)用程序。交叉編譯工具鏈用瑞芯微官方提供的 GCC 版本在 SDK 里能找到。編譯的時候鏈接 librknnrt.so這個庫在板端的 /usr/lib 目錄下。板端環(huán)境搭建的第一步是確認(rèn) NPU 驅(qū)動正常加載。用 dmesg 看內(nèi)核日志應(yīng)該能看到 rknpu 相關(guān)的初始化信息。然后檢查 /dev/rknpu 設(shè)備節(jié)點(diǎn)是否存在這個節(jié)點(diǎn)是應(yīng)用程序和 NPU 通信的入口。如果這個節(jié)點(diǎn)不存在說明驅(qū)動沒加載成功需要檢查設(shè)備樹里 NPU 節(jié)點(diǎn)的配置。dmesg | grep -i rknpu ls -l /dev/rknpu cat /sys/kernel/debug/rknpu/version實(shí)操心得板端跑推理之前先用 rknn_server 跑一遍官方提供的 demo 模型確認(rèn)整個鏈路是通的。我遇到過好幾次自己寫的程序跑不通結(jié)果發(fā)現(xiàn)是板端 runtime 版本和轉(zhuǎn)換工具版本不匹配用官方 demo 一測就暴露出來了。4.2 推理程序的編寫要點(diǎn)板端推理程序的核心流程是加載 RKNN 模型、初始化 runtime、設(shè)置輸入、執(zhí)行推理、獲取輸出。C 接口的調(diào)用邏輯比較固定但有幾個細(xì)節(jié)容易出錯。首先是輸入數(shù)據(jù)的格式RKNN 模型期望的是 NHWC 排列的 uint8 數(shù)據(jù)而 OpenCV 讀出來的圖是 BGR 排列需要先轉(zhuǎn)成 RGB 再調(diào)整通道順序。其次是歸一化如果你在轉(zhuǎn)換時配置了 mean 和 std板端就不需要再做歸一化直接把原始像素值傳進(jìn)去就行重復(fù)歸一化會導(dǎo)致結(jié)果完全錯誤。// 輸入預(yù)處理關(guān)鍵代碼 cv::Mat img cv::imread(test.jpg); cv::cvtColor(img, img, cv::COLOR_BGR2RGB); cv::resize(img, img, cv::Size(224, 224)); // 直接傳入 uint8 數(shù)據(jù)歸一化由 NPU 內(nèi)部完成 memcpy(input_data, img.data, 224 * 224 * 3);推理結(jié)果的解析也要注意。RKNN 的輸出是量化后的 INT8 數(shù)據(jù)需要根據(jù)量化參數(shù)反量化回浮點(diǎn)。不過如果你用的是 RKNN-Toolkit2 的默認(rèn)配置輸出層通常會自動做反量化直接拿到浮點(diǎn)結(jié)果。分類任務(wù)的輸出是一個 1000 維的向量取 argmax 就是預(yù)測類別。4.3 四個模型的板端性能實(shí)測數(shù)據(jù)板端實(shí)測是這次實(shí)驗(yàn)的重頭戲。我在同樣的環(huán)境下對三個成功轉(zhuǎn)換的模型分別跑了 1000 次推理取平均延遲同時用 top 命令和 NPU 調(diào)試接口監(jiān)控資源占用。測試時 CPU 頻率鎖定在最高檔避免調(diào)頻影響結(jié)果。模型平均延遲內(nèi)存占用NPU 利用率板端 Top-1ResNet1842ms38MB78%68.6%MobileNetV218ms21MB65%69.5%EfficientNet-B067ms45MB82%72.8%MobileNetV2 的延遲最低18ms 意味著理論上能做到 55 FPS實(shí)際考慮前后處理開銷穩(wěn)定在 30 FPS 以上沒問題非常適合實(shí)時視頻流分類。ResNet18 的 42ms 對應(yīng)約 24 FPS做單幀分析或者低頻檢測夠用。EfficientNet-B0 的 67ms 偏慢但它的精度最高適合對準(zhǔn)確率要求高、對實(shí)時性要求不高的場景。NPU 利用率這個指標(biāo)值得說一下。ResNet18 和 EfficientNet-B0 的利用率都在 80% 左右說明 NPU 基本跑滿了瓶頸在算力。MobileNetV2 只有 65%說明瓶頸可能轉(zhuǎn)移到了內(nèi)存帶寬或者數(shù)據(jù)搬運(yùn)上因?yàn)樯疃瓤煞蛛x卷積的訪存比很高。這也解釋了為什么 MobileNetV2 的延遲優(yōu)勢沒有參數(shù)量差距那么大。4.4 ViT 模型轉(zhuǎn)換失敗的深度分析ViT-Base 轉(zhuǎn)換失敗這件事我花了不少時間研究。報(bào)錯信息是 LayerNorm 算子不支持但實(shí)際情況比這復(fù)雜。ViT 的結(jié)構(gòu)里有幾個 RKNN 不支持的算子LayerNorm、GELU 激活、以及多頭注意力里的矩陣乘組合。RKNN-Toolkit2 對 LayerNorm 的支持是從某個版本才開始有的而且只支持特定配置。我嘗試了幾種繞行方案。第一種是把 LayerNorm 替換成 BatchNorm但這樣會改變模型結(jié)構(gòu)需要重新訓(xùn)練代價太大。第二種是用自定義算子實(shí)現(xiàn)RKNN 支持通過 CPU 插件的方式跑不支持的算子但這樣會導(dǎo)致頻繁的 CPU-NPU 數(shù)據(jù)搬運(yùn)性能急劇下降。實(shí)測下來即使勉強(qiáng)跑通單次推理也要 300ms 以上完全沒有實(shí)用價值。結(jié)論很明確在 RK3568 這個算力級別上ViT 類模型目前不具備實(shí)用部署條件。如果你的應(yīng)用確實(shí)需要 Transformer 的能力要么換更強(qiáng)的芯片要么用 CNN 加注意力機(jī)制的混合結(jié)構(gòu)純 Transformer 在邊緣 NPU 上還太早。5. 常見問題排查與避坑經(jīng)驗(yàn)5.1 模型轉(zhuǎn)換階段的典型報(bào)錯轉(zhuǎn)換階段最常遇到的報(bào)錯有三類。第一類是算子不支持報(bào)錯信息里會明確寫出哪個算子有問題。這時候的排查思路是先用 Netron 看 ONNX 圖定位到那個算子然后查 RKNN 的算子支持列表。如果確實(shí)不支持考慮替換算子或者用 CPU 插件。第二類是維度不匹配通常是輸入尺寸或者 batch 維度的問題檢查 config 里的配置和 ONNX 的輸入是否一致。第三類是量化數(shù)據(jù)集路徑錯誤這個最容易被忽略dataset.txt 里的路徑必須是絕對路徑或者相對于執(zhí)行目錄的正確路徑。報(bào)錯類型典型信息排查方向算子不支持Unsupported op: LayerNorm查算子列表替換或插件維度不匹配Input shape mismatch檢查 config 和 ONNX 輸入量化失敗Dataset file not found檢查 dataset.txt 路徑版本不匹配Runtime version mismatch對齊工具和板端版本5.2 板端推理結(jié)果異常的排查思路板端跑出來的結(jié)果和 PC 仿真對不上這是很常見的問題。排查要按順序來先確認(rèn)輸入數(shù)據(jù)格式對不對RGB 還是 BGRNHWC 還是 NCHW這個錯了結(jié)果會完全亂掉。然后確認(rèn)歸一化有沒有重復(fù)做轉(zhuǎn)換時配了 mean/std 的話板端就不能再歸一化。再確認(rèn)量化參數(shù)有沒有正確加載有時候模型文件傳輸過程中損壞了重新拷貝一次就好。最后確認(rèn)板端 runtime 版本和轉(zhuǎn)換工具版本是否匹配這個不匹配會導(dǎo)致各種詭異現(xiàn)象。我遇到過一個特別隱蔽的問題板端推理結(jié)果偶爾正確偶爾錯誤排查了很久發(fā)現(xiàn)是輸入 buffer 沒有對齊RKNN 要求輸入內(nèi)存按 64 字節(jié)對齊我用 malloc 分配的內(nèi)存不滿足這個要求改成 posix_memalign 之后就穩(wěn)定了。這種問題官方文檔里不會寫只能靠踩坑積累。5.3 性能優(yōu)化的幾個實(shí)用技巧性能優(yōu)化這塊有幾個立竿見影的手段。第一是開啟 NPU 的多核模式RK3568 的 NPU 支持多核并行在初始化的時候設(shè)置 core_mask 可以指定用幾個核對于大模型能提升 30% 以上的吞吐。第二是復(fù)用輸入輸出 buffer避免每次推理都重新分配內(nèi)存這個在連續(xù)推理場景下效果明顯。第三是合理設(shè)置推理優(yōu)先級如果你的應(yīng)用里有多個模型把實(shí)時性要求高的設(shè)成高優(yōu)先級。還有一個容易被忽略的點(diǎn)是 CPU 和 NPU 的協(xié)同。前后處理如果放在 CPU 上做要盡量用 NEON 指令加速OpenCV 的 resize 和顏色轉(zhuǎn)換默認(rèn)就用了 NEON但如果你自己寫循環(huán)處理像素記得手動加編譯優(yōu)化選項(xiàng)。我實(shí)測過把前后處理從樸素實(shí)現(xiàn)改成 NEON 優(yōu)化整體延遲能降 15% 左右。實(shí)操心得性能測試一定要在真實(shí)負(fù)載下做空跑和實(shí)際跑視頻流的延遲差異很大。我建議用實(shí)際的視頻文件做壓力測試連續(xù)跑 10 分鐘以上觀察延遲的抖動情況。有些模型平均延遲好看但抖動大實(shí)際體驗(yàn)很差。5.4 模型選型的決策建議基于這次實(shí)驗(yàn)的數(shù)據(jù)我給幾個實(shí)際的選型建議。如果你的場景是實(shí)時視頻分類幀率要求 30 FPS 以上選 MobileNetV2精度夠用速度最快。如果是單幀高精度分析比如醫(yī)療影像或者工業(yè)質(zhì)檢選 EfficientNet-B0精度最高延遲可以接受。ResNet18 適合作為基準(zhǔn)模型或者對穩(wěn)定性要求極高的場景它的量化損失最小行為最可預(yù)測。ViT 目前不建議在 RK3568 上部署等 NPU 算子支持完善了再說。另外提醒一點(diǎn)模型選型不能只看精度和速度還要考慮你的數(shù)據(jù)集和預(yù)訓(xùn)練模型的匹配度。ImageNet 預(yù)訓(xùn)練的模型直接拿來用在你的特定場景上可能表現(xiàn)很差需要做遷移學(xué)習(xí)。遷移學(xué)習(xí)之后的模型再量化精度損失的模式可能和這次實(shí)驗(yàn)不一樣需要重新評估。6. 一些實(shí)測下來的個人體會整個實(shí)驗(yàn)做下來最大的感受是邊緣 NPU 部署這件事工具鏈的成熟度比芯片算力更影響體驗(yàn)。RK3568 的 NPU 算力在同類芯片里不算突出但 RKNN 這套工具鏈相對完善文檔和社區(qū)支持也還可以這是它最大的優(yōu)勢。真正花時間的不是寫推理代碼而是處理各種轉(zhuǎn)換和量化的邊界情況。量化精度這塊我的經(jīng)驗(yàn)是不要迷信自動量化。RKNN-Toolkit2 的混合量化功能可以讓你指定某些層用 FP16某些層用 INT8對于精度敏感的網(wǎng)絡(luò)層手動配置混合量化能挽回不少精度。EfficientNet-B0 那個 3.6% 的損失我后來通過把前面的幾個卷積層設(shè)成 FP16降到了 2.1%代價是延遲增加了 8ms這個 trade-off 在很多場景下是值得的。最后分享一個小技巧轉(zhuǎn)換模型的時候打開 verbose 模式把日志重定向到文件出問題的時候翻日志比瞎猜快得多。RKNN 的日志會詳細(xì)記錄每個算子的轉(zhuǎn)換過程、量化參數(shù)的分布、以及圖優(yōu)化的每一步這些信息在排查精度問題時特別有用。我現(xiàn)在的習(xí)慣是每次轉(zhuǎn)換都存一份日志方便對比不同參數(shù)配置的效果差異。