優(yōu)化實踐:MToP平臺與MFEA算法解析)
簡介多任務(wù)優(yōu)化平臺MToP是一套面向科研人員與工程師的MATLAB工具箱聚焦進化多任務(wù)處理場景解決多目標、多任務(wù)聯(lián)合優(yōu)化問題。壓縮包內(nèi)共2000個文件以m源碼為核心收錄40余種多任務(wù)進化算法、40余種可參與多任務(wù)優(yōu)化的單任務(wù)算法并提供150余個實際問題案例與經(jīng)典基準題目輔以txt說明文檔、mat數(shù)據(jù)文件、png示意圖及mex動態(tài)庫兼顧跨平臺運行與二次開發(fā)。整個壓縮包約38.49MB結(jié)構(gòu)清晰已有173人學(xué)習(xí)瀏覽。讀者可獲取完整平臺源碼、圖形用戶界面、覆蓋單目標和多目標的20余種性能指標以及便于擴展新算法、新問題的統(tǒng)一接口既適合學(xué)術(shù)研究中算法對比與驗證也能直接支撐工程設(shè)計、投資組合、藥物劑量等真實優(yōu)化場景是深入理解并應(yīng)用多任務(wù)優(yōu)化的高效工具。1. MToP 把「多個相關(guān)任務(wù)」從串行改成協(xié)同優(yōu)化同時調(diào)兩個模型的超參數(shù)你會怎么做最常見的做法是寫個 for 循環(huán)串行跑或者用 parallel pool 并行跑。這沒問題但任務(wù)之間沒有任何信息交換。多任務(wù)優(yōu)化不滿足于「同時算」而是要讓任務(wù) A 收斂過程中學(xué)到的分布信息去幫助任務(wù) B 收斂。MToPMultitask Optimization Platform就是在 MATLAB 里把這套想法做成可重復(fù)實驗的平臺內(nèi)置多因子進化等算法支持多個任務(wù)在統(tǒng)一搜索空間內(nèi)共享種群。它適合兩類人需要跑大量對比實驗的進化計算研究者以及在 MATLAB 里維護著優(yōu)化工具箱相關(guān)代碼、想直接給現(xiàn)有問題加一層跨任務(wù)遷移的工程師。2. MToP 的核心機制多因子進化與知識遷移2.1 從多任務(wù)到多因子統(tǒng)一搜索空間的編碼MToP 不會直接把兩個任務(wù)各自的決策變量拿來做交叉。原因很直接任務(wù) A 可能是 10 維實數(shù)向量任務(wù) B 可能是 5 維整數(shù)組合兩者的上下界和語義都不一樣。直接在原始空間雜交會產(chǎn)生大量越界或語義混亂的后代。所以平臺在任務(wù)定義外面套了一層「統(tǒng)一搜索空間」通常是[0, 1]上的 D 維實數(shù)向量D 取所有任務(wù)決策變量維度的最大值。每個個體在這個統(tǒng)一空間里只有一個「身份」但它可以解碼到任意任務(wù)上。任務(wù) k 只讀取個體向量的前D_k個維度然后線性映射到該任務(wù)的變量范圍。這個截斷策略意味著超出D_k的維度對任務(wù) k 是冗余的但對其他更高維任務(wù)不是。function xk decode_task(ind, task) % 將統(tǒng)一搜索空間中的個體 ind 解碼為任務(wù) task 的真實變量 % ind: 1xD 的實數(shù)行向量取值在 [0, 1] 區(qū)間 % task.Dk: 當(dāng)前任務(wù)的決策變量維度 % task.lb, task.ub: 1xDk 的下界和上界向量 u ind(1:task.Dk); % 截取該任務(wù)需要的維度 xk task.lb (task.ub - task.lb) .* u; % 線性映射到真實范圍 end這里用線性映射是最常用的做法適合實數(shù)連續(xù)優(yōu)化問題。如果任務(wù)變量是離散的比如超參數(shù)搜索里的網(wǎng)絡(luò)層數(shù)、批大小我一般會在任務(wù)層維護一張離散取值表把取值序號映射到[0, 1]區(qū)間而不要直接讓 0.37 取整成 0。原因是一旦取整統(tǒng)一空間里的距離關(guān)系就被破壞了后續(xù)交叉變異的幾何意義會變得不可控。2.2 知識遷移怎么發(fā)生選型交配與垂直文化傳播有了統(tǒng)一空間還要回答一個問題一個個體到底屬于哪個任務(wù)MToP 沿用了多因子進化里的「技能因子」概念。每個個體保存一個整數(shù)skill_factor標記它當(dāng)前最擅長哪個任務(wù)。這個標簽不是固定的而是隨進化動態(tài)變化的如果一個個體在任務(wù) 2 上表現(xiàn)更好它下一輪就可能被標成任務(wù) 2 的因子。父代選擇時如果兩個個體的技能因子相同就按常規(guī)的單任務(wù)進化方式交叉如果因子不同則以隨機交配概率 rmp 決定是否讓它們跨任務(wù)交配。跨任務(wù)交配產(chǎn)生的子代只有一個技能因子規(guī)則是把子代解碼到兩個父代各自對應(yīng)的任務(wù)上做評估在哪個任務(wù)上排名更高就繼承哪個任務(wù)因子。這個過程就是垂直文化傳播。在 MToP 里這幾個術(shù)語會反復(fù)出現(xiàn)在配置項和實驗記錄里建議一開始就分清術(shù)語含義在 MToP 中的實現(xiàn)統(tǒng)一搜索空間所有任務(wù)共享的編碼空間[0,1]^D的實數(shù)向量技能因子個體最擅長哪個任務(wù)整數(shù)標號動態(tài)分配隨機交配概率 rmp異因子個體跨任務(wù)交配的概率0~1 的標量參數(shù)垂直文化傳播子代繼承哪種技能因子比較子代在兩個任務(wù)上的排名rmp 是整個 MToP 里最敏感的參數(shù)。它太低任務(wù)之間幾乎沒有交流等于退化成了多個獨立種群同時跑它太高負遷移會被放大——任務(wù) A 學(xué)到的不適合任務(wù) B 的基因會被頻繁引入任務(wù) B 的基因池。所以后面做實驗時rmp 一定要放進消融變量里不能當(dāng)固定值寫死。2.3 MToP 里 MFEA/MFEA-II 的算子組織方式MToP 不是一個單獨算法而是一套算法容器。以最常見的 MFEA 為例它的主循環(huán)會同時維護一個統(tǒng)一種群和一個技能因子列表每一代做選型交配、技能因子分配、環(huán)境選擇三步。下面這段偽代碼概括了主干流程實際平臺里的實現(xiàn)會把評估、選擇、變異拆分到不同函數(shù)里% MFEA 主干循環(huán)的 MATLAB 風(fēng)格偽代碼 while evals max_eval offspring []; for i 1:pop_size/2 [p1, p2] select_parents(pop); % 按技能因子選父代 if p1.skill_factor p2.skill_factor [c1, c2] crossover(p1, p2); % 同因子直接交叉 elseif rand rmp [c1, c2] crossover(p1, p2); % 跨任務(wù)交配 else c1 mutate(p1); c2 mutate(p2); % 各自變異 end c1.skill_factor assign_factor(c1); % 垂直文化傳播 c2.skill_factor assign_factor(c2); offspring [offspring; c1; c2]; % 累積子代 end pop environmental_selection([pop; offspring]); evals evals count_evals(offspring); endassign_factor的實現(xiàn)細節(jié)決定了遷移質(zhì)量。最簡單的規(guī)則是子代在父代 1 的任務(wù)上評估一次在父代 2 的任務(wù)上評估一次誰排名高就繼承誰的因子。這會讓同一個子代產(chǎn)生兩次評估開銷因此在統(tǒng)計max_eval時必須把重復(fù)評估算進去。很多人在 MToP 上跑出的結(jié)果和論文對不上就是這里少算了評估次數(shù)。MFEA-II 在 MToP 里也有實現(xiàn)它的核心改進是讓 rmp 隨種群狀態(tài)自適應(yīng)調(diào)整而不是用戶固定一個值。如果你正在跑一個新任務(wù)組對 rmp 沒有任何先驗我一般會先上 MFEA-II 跑一輪拿到一個參考區(qū)間再切回 MFEA 做精細消融。這樣兩個算法互相驗證結(jié)果會扎實很多。3. 用 MToP 在 MATLAB 里跑通第一個多任務(wù)實驗3.1 從下載目錄到 MATLAB 搜索路徑MToP 是源碼分發(fā)的 MATLAB 平臺核心算法都是.m文件不需要編譯 MEX。下載后第一件事不是打開 MATLAB 敲代碼而是確認 MATLAB 版本。建議 R2020b 以上我一般直接在 R2023b 上跑新版編輯器里的類方法斷點和變量檢查對調(diào)試這類平臺幫助明顯。拿到解壓目錄后把整個目錄遞歸加入 MATLAB 搜索路徑。寫在命令窗口或腳本開頭都可以% 將 MToP 根目錄及其子目錄加入搜索路徑 addpath(genpath(D:\matlab_projects\MToP)); % 改成你的實際路徑 savepath; % 保存到 pathdef.m下次免配置genpath會遞歸添加所有子目錄這樣benchmark、solver、util這些子目錄才不會漏。savepath會把當(dāng)前路徑保存到 MATLAB 啟動路徑文件里之后打開 MATLAB 不用重新addpath。但要注意如果你之后移動了 MToP 目錄位置保存的舊路徑會失效啟動時會報找不到模塊。遇到這種情況用pathtool手動清理一次即可。3.2 運行內(nèi)置 benchmark 的最短腳本確認路徑?jīng)]問題后先跑一個內(nèi)置 benchmark。以下面的典型雙任務(wù)配置為例一個腳本完成「定義任務(wù)組 → 設(shè)置參數(shù) → 運行 MFEA」% run_first_mtop.m addpath(genpath(D:\matlab_projects\MToP)); % 從平臺內(nèi)置 benchmark 中取一個雙任務(wù)測試組 tasks mtop_benchmark(PPS8); % 返回任務(wù)結(jié)構(gòu)體數(shù)組 % 設(shè)置算法參數(shù) opts mtop_options(); opts.max_eval 5e4; % 總評估預(yù)算 opts.pop_size 100; % 統(tǒng)一種群個體數(shù) opts.rmp 0.3; % 跨任務(wù)交配概率 opts.verbose true; % 每代打印進度 % 調(diào)用 MFEA solver result mtop_solve(tasks, MFEA, opts);這里mtop_benchmark、mtop_options、mtop_solve是平臺里常見的封裝函數(shù)名不同發(fā)布版的命名可能略有差異。如果你拿到的版本接口不一樣直接打開平臺自帶demo目錄下的某個run_demo.m看看它調(diào)用 solver 的骨架結(jié)構(gòu)就行。tasks是一個結(jié)構(gòu)體數(shù)組每個任務(wù)至少包含Dk、lb、ub、fn四個字段Dk是決策變量維度lb和ub是變量邊界fn是目標函數(shù)句柄。要注意max_eval是所有任務(wù)共享的總評估次數(shù)上限不是每個任務(wù)各自 5 萬次。這是多任務(wù)實驗和單任務(wù)實驗在設(shè)計上的根本區(qū)別平臺把一個跑 K 個任務(wù)的完整過程當(dāng)作一次實驗預(yù)算由所有任務(wù)共同消耗。3.3 讀取結(jié)果并畫收斂曲線跑完之后result結(jié)構(gòu)里最重要的是每個任務(wù)的最優(yōu)解、最優(yōu)值和收斂歷史。不同平臺版本的字段命名不會完全一致但通常可以從下表里找到對應(yīng)result 字段維度含義best_fitness1 x K每個任務(wù)當(dāng)前最優(yōu)評估值best_solution1 x K cell每個任務(wù)在真實變量空間的最優(yōu)解history{k}結(jié)構(gòu)體第 k 個任務(wù)的收斂記錄含best_errorpop_historycell按代保存的種群快照用于因子分布分析畫圖時我推薦用semilogy而不是plot因為進化誤差的收斂跨度往往有幾個數(shù)量級線性坐標會掩蓋早期迭代的變化% 畫兩個任務(wù)的收斂曲線 figure; for k 1:numel(tasks) semilogy(result.history{k}.best_error, LineWidth, 1.5); hold on; end grid on; legend(arrayfun((t) sprintf(Task %d, t.id), tasks, UniformOutput, false)); xlabel(Generation); ylabel(Best Error);history{k}.best_error是第 k 個任務(wù)歷史最優(yōu)解與理論最優(yōu)值之間的誤差。如果 benchmark 沒提供理論最優(yōu)就畫原始最優(yōu)值但曲線下降趨勢的解讀邏輯是一樣的。注意semilogy對零誤差會畫到負無窮位置平臺一般會把零誤差記成eps。如果你看到曲線掉到圖底之外先確認是不是誤差已經(jīng)歸零不要急著當(dāng)成 bug。4. MToP 參數(shù)怎么設(shè)從 benchmark 到遷移強度4.1 多任務(wù) benchmark 怎么選很多人在 MToP 上跑出的第一個結(jié)果很難看不是因為平臺有問題而是選了不合適的 benchmark。多任務(wù) benchmark 的設(shè)計要點不是「任務(wù)本身難」而是「任務(wù)之間的相關(guān)性可控」。常見的做法是把 sphere、rastrigin、rosenbrock 這類經(jīng)典函數(shù)做偏移和旋轉(zhuǎn)后組合成任務(wù)對偏移量決定最優(yōu)點的距離旋轉(zhuǎn)矩陣決定相關(guān)性強弱。MToP 內(nèi)置的問題集通常會按 CEC 多任務(wù)競賽的風(fēng)格打包一個任務(wù)組里有 2 到 50 個任務(wù)不等。新手階段我強烈建議從雙任務(wù)開始先把遷移機制跑明白再上多任務(wù)。并不是任務(wù)越多越好任務(wù)數(shù)增加后種群需要在更多技能因子之間分配負遷移的概率也會上升。任務(wù)組類型任務(wù)數(shù)典型維度適合驗證什么簡單函數(shù)對210平臺安裝是否正確、收斂趨勢是否正常偏移/旋轉(zhuǎn)復(fù)合問題2-520~50負遷移控制、rmp 敏感性大規(guī)模任務(wù)組10 以上50~100平臺可擴展性、因子分布是否失衡如果你手頭只有自己的應(yīng)用問題沒有 benchmark也可以沿用這個分級思路先用兩個經(jīng)過旋轉(zhuǎn)處理的測試函數(shù)對平臺做驗證再換成真實問題。直接用真實問題上手一旦結(jié)果不好很難判斷是遷移策略失效還是平臺配置不對。4.2 最值得調(diào)的先調(diào)這 3 個參數(shù)MToP 的可調(diào)參數(shù)比單任務(wù)優(yōu)化器多一層除了種群規(guī)模和評估預(yù)算還要額外面對 rmp。我建議參數(shù)調(diào)優(yōu)的順序固定為「種群規(guī)模 → rmp → 評估預(yù)算」不要上來就改交叉概率或變異概率。前面的參數(shù)沒定后面改了也沒法解釋。pop_size所有任務(wù)共用一個種群所以種群規(guī)模要能覆蓋所有任務(wù)的技能因子。K2 時 100~200 通常夠K10 時不是簡單線性放大而是取 200~400 后靠增加評估預(yù)算來補因為每個因子下至少要保持幾十個個體才能支撐排名選擇。rmp跨任務(wù)交配概率取值 0~1。0 表示完全不做跨任務(wù)交配等價于多種群獨立進化1 表示所有異因子父代都強制交配負遷移風(fēng)險最大。常用起點是 0.3但碰上強相關(guān)的任務(wù)對可以往上提碰上弱相關(guān)任務(wù)對應(yīng)該往下降。max_eval總評估次數(shù)直接決定實驗時長。多任務(wù)實驗的公平做法是「總預(yù)算相同」不是每個任務(wù)預(yù)算乘以任務(wù)數(shù)。如果任務(wù)多而預(yù)算沒加平均到每個任務(wù)的預(yù)算變少遷移帶來的收益和損失也會被一起放大。參數(shù)推薦起點主要作用常見坑pop_size100統(tǒng)一種群個體數(shù)任務(wù)多時個體過少技能因子分配會漂移rmp0.3控制跨任務(wù)交配頻率設(shè)過高會把負遷移基因引入全部任務(wù)max_eval5e4總函數(shù)評估預(yù)算誤以為是每個任務(wù)各有的預(yù)算4.3 用消融實驗判斷遷移是正還是負判斷一個任務(wù)組是否真正受益于多任務(wù)優(yōu)化不能只看一次有沒有跑出好結(jié)果。我一般固定max_eval把 rmp 掃一遍rmp0就是天然基線。如果 rmp 大于 0 的結(jié)果反而更差說明這兩個任務(wù)之間存在負遷移。% 掃描 rmp比較每個任務(wù)的最優(yōu)值 rmps [0 0.1 0.3 0.5 0.7]; final_error zeros(numel(rmps), numel(tasks)); for i 1:numel(rmps) opts.rmp rmps(i); r mtop_solve(tasks, MFEA, opts); for k 1:numel(tasks) final_error(i, k) r.best_fitness(k); end end % 以表格形式打印結(jié)果 disp(array2table(final_error, ... VariableNames, {Task1, Task2}, ... RowNames, string(rmps)));array2table把結(jié)果整理成可讀表格RowNames用 rmp 參數(shù)值標識每一行這樣橫向能看任務(wù)、縱向能看 rmp 趨勢。有一點必須說清rmp0時種群仍然是共享的、選擇仍然基于全局種群所以它不是嚴格的單任務(wù)基線只是「無遷移的多任務(wù)基線」。想和純單任務(wù)比必須另跑單任務(wù) solver 并把預(yù)算設(shè)置成同樣的總評估次數(shù)否則對比不公平。5. 從 MToP 結(jié)果反推遷移策略一個調(diào)試模板5.1 先看技能因子分配跑完一次實驗我第一件事不是看最優(yōu)值而是看技能因子分布。如果種群幾乎全被某一種因子占據(jù)說明另一個任務(wù)長期沒有貢獻個體所謂的多任務(wù)搜索已經(jīng)退化成單任務(wù)。查看方式很簡單從result.pop_history里取某一代的種群快照pop_10 result.pop_history{10}; histogram(pop_10.skill_factor, Normalization, probability); xlabel(Skill Factor); ylabel(Ratio);如果因子分布長期集中在 1先嘗試提高 rmp再檢查兩個任務(wù)維度是否差距過大。維度差太大會導(dǎo)致低維任務(wù)的高質(zhì)量基因在統(tǒng)一空間里被高維任務(wù)的冗余維度稀釋這是一個容易被忽略的結(jié)構(gòu)性原因。5.2 用收斂曲線判斷負遷移把不同 rmp 的收斂曲線畫到同一張半對數(shù)圖上能看出負遷移發(fā)生的階段。常見模式是rmp 較高的曲線前期下降很快因為早期異因子交配帶來了新鮮基因但到了后期劣質(zhì)基因持續(xù)跨任務(wù)注入曲線停在比低 rmp 更高的平臺上。這就是「遷移紅利吃在前期、負遷移代價付在后期」。遇到這種情況不需要立刻換算法。我經(jīng)常在循環(huán)里讓 rmp 隨代數(shù)衰減效果往往不錯opts.rmp 0.6 * (1 - gen / opts.max_gen); % rmp 從 0.6 線性衰減到 0這個衰減策略不是 MToP 平臺內(nèi)置選項但可以作為參數(shù)掃描的一部分寫進實驗?zāi)_本結(jié)果和 MFEA-II 的自適應(yīng)機制互為參照。5.3 把 MToP 結(jié)果接回 MATLAB 優(yōu)化工具箱如果你手頭的場景原本用的是 Optimization Toolbox 的fmincon不需要把整個流程替換掉。更穩(wěn)的做法是橋接先用 MToP 負責(zé)全局搜索找到每個任務(wù)最優(yōu)解附近的一個好起點再用fmincon做局部精修。因為 MFEA 這類進化算法擅長跨峰探索不擅長最后的局部收斂而fmincon在光滑局部區(qū)域收斂速度極快。把result.best_solution{k}解碼到真實變量后傳給fmincon精修后的值作為最終結(jié)果輸出。把這一段腳本存成refine_mtop_result.m以后換 benchmark 只需要改輸入結(jié)構(gòu)不用動精修流程。本文還有配套的精品資源點擊獲取