化學(xué)習(xí)驅(qū)動數(shù)據(jù)中心節(jié)能:DQN三維協(xié)同調(diào)度實(shí)踐)
做數(shù)據(jù)中心調(diào)度的人大概都有過這種困擾手里掌握著幾十上百臺服務(wù)器的運(yùn)行數(shù)據(jù)CPU利用率、機(jī)柜溫度、空調(diào)功率、實(shí)時(shí)電價(jià)全都擺在屏幕上可到了做決策時(shí)卻不知道該先調(diào)誰、調(diào)多少才算最優(yōu)。早年間我還在用閾值規(guī)則硬懟設(shè)定溫度超過32度就加大制冷CPU超過80%就遷移任務(wù)結(jié)果往往是冷熱不均、電費(fèi)翻倍調(diào)度員忙成救火隊(duì)員。后來把問題換成電力-熱力-算力三維協(xié)同的視角再引入深度強(qiáng)化學(xué)習(xí)里的DQN算法用Matlab搭出一套智能調(diào)度原型才算摸到了門道。這篇博文就是把我從問題建模、馬爾可夫決策過程設(shè)計(jì)、DQN訓(xùn)練到Matlab代碼落地的完整思路捋一遍也會把踩過的坑和調(diào)參經(jīng)驗(yàn)一并分享適合正在做數(shù)據(jù)中心節(jié)能調(diào)度、剛?cè)腴T強(qiáng)化學(xué)習(xí)或者想把算法從論文搬到工程實(shí)驗(yàn)里的讀者。1. 先理解三維協(xié)同在調(diào)度里到底指什么1.1 數(shù)據(jù)中心能耗的真實(shí)分布很多人一提數(shù)據(jù)中心節(jié)能第一反應(yīng)就是把服務(wù)器功耗降下來。但真正拆開電表看IT設(shè)備的耗電只占一部分空調(diào)制冷和供配電損耗加起來通常占整個(gè)數(shù)據(jù)中心總能耗的三到四成。也就是說就算服務(wù)器不動冷卻系統(tǒng)照樣在燒電。更麻煩的是兩套系統(tǒng)互相耦合任務(wù)跑得多服務(wù)器發(fā)熱大空調(diào)負(fù)載就得跟著加電價(jià)高峰時(shí)段還可能撞在一起。以前我把IT調(diào)度和制冷調(diào)度分開優(yōu)化測出來的省電數(shù)據(jù)很漂亮一聯(lián)動就露餡成本反而上升。所以在三維協(xié)同框架里電力、熱力、算力不是三個(gè)平行的話題而是一條因果鏈算力負(fù)載決定了服務(wù)器功耗和產(chǎn)熱產(chǎn)熱決定了冷卻需求冷卻功率和IT功耗疊加成總用電成本電價(jià)信號又反過來決定哪些時(shí)間段該多算、哪些時(shí)間段該少算。調(diào)度算法必須能感知這條鏈上的每一個(gè)環(huán)節(jié)才能做出全局最優(yōu)的決策。1.2 三維協(xié)同的數(shù)學(xué)化表達(dá)我把這個(gè)系統(tǒng)建模成一個(gè)離散時(shí)間、帶約束的馬爾可夫決策過程(MDP)。時(shí)間片設(shè)為15分鐘每個(gè)時(shí)隙內(nèi)觀察系統(tǒng)狀態(tài)選擇一個(gè)動作然后獲得成本和狀態(tài)轉(zhuǎn)移。這里有幾個(gè)關(guān)鍵設(shè)計(jì)決策電力側(cè)采用分時(shí)電價(jià)模型目前國內(nèi)多數(shù)工商業(yè)場景都執(zhí)行峰谷分時(shí)電價(jià)峰段電價(jià)通常是谷段的2到3倍。把電價(jià)作為環(huán)境狀態(tài)的一部分調(diào)度策略就要學(xué)會在電價(jià)低時(shí)把任務(wù)提前算完在電價(jià)高時(shí)減少新任務(wù)進(jìn)入。熱力側(cè)用簡化的傳熱模型描述機(jī)柜溫度變化溫度不僅受本機(jī)柜IT負(fù)載影響還受相鄰機(jī)柜和環(huán)境溫度影響。空調(diào)系統(tǒng)有最大供冷功率限制溫度超過安全閾值會產(chǎn)生懲罰。算力側(cè)任務(wù)以隊(duì)列形式到達(dá)每個(gè)時(shí)隙可以選擇將任務(wù)分配到某個(gè)服務(wù)器并執(zhí)行也可以暫時(shí)留在隊(duì)列。任務(wù)有最大可容忍延遲排隊(duì)時(shí)間超過期限就算違約。這三個(gè)子系統(tǒng)的模型在Matlab里不要做得太精細(xì)先線性化、先抓住主要耦合關(guān)系夠用就行。我見過不少項(xiàng)目一開始就把流體力學(xué)細(xì)節(jié)和芯片級功耗都塞進(jìn)去結(jié)果模型本身比調(diào)度問題還復(fù)雜強(qiáng)化學(xué)習(xí)根本訓(xùn)不動。工程上合理的做法是從帶通解的簡化模型開始驗(yàn)證算法有效后再逐步加復(fù)雜度。1.3 為什么選擇DQN而不是直接上優(yōu)化器這類調(diào)度問題如果寫成混合整數(shù)規(guī)劃理論上可以用求解器跑出最優(yōu)解。但實(shí)際場景里狀態(tài)量有十幾個(gè)維動作組合又是離散的任務(wù)分配、冷卻擋位、服務(wù)器開關(guān)機(jī)求解器在幾十個(gè)時(shí)間片規(guī)模下還能跑拉到全天96個(gè)時(shí)隙、上百臺服務(wù)器就變成天文數(shù)字。傳統(tǒng)的啟發(fā)式算法如最早截止期優(yōu)先調(diào)度加閾值制冷控制速度快但不會主動利用電價(jià)低峰特性對非線性耦合也缺乏全局視角。DQN恰好填補(bǔ)這個(gè)空白它不需要環(huán)境模型模型我們只是用來做仿真器能接受高維度狀態(tài)輸入輸出的是離散動作的Q值天然適配每15分鐘做一次開關(guān)機(jī)決策、冷卻擋位切換這類場景。而且Matlab的仿真環(huán)境和可視化做得直觀適合先驗(yàn)證算法邏輯再遷移到真實(shí)平臺。當(dāng)然DQN不是萬能的如果動作空間包含連續(xù)變量比如冷卻水流量連續(xù)調(diào)節(jié)那就得換DDPG或TD3這個(gè)后面再展開。2. 狀態(tài)空間、動作空間和獎勵函數(shù)的設(shè)計(jì)2.1 狀態(tài)空間怎么定義才不冗余狀態(tài)設(shè)計(jì)的原則是夠用且不冗余不是說變量越多越好。我最初把每臺服務(wù)器的歷史利用率也塞進(jìn)狀態(tài)維度一下子沖到30多網(wǎng)絡(luò)訓(xùn)練時(shí)間翻倍性能還變差。后來重新梳理因果鏈最終保留了10個(gè)狀態(tài)量狀態(tài)變量物理含義備注任務(wù)隊(duì)列長度Q當(dāng)前等待調(diào)度的任務(wù)數(shù)相對值方便歸一化隊(duì)列平均等待時(shí)長W反映延遲壓力用于違約懲罰判斷各服務(wù)器CPU利用率 U_i每臺服務(wù)器負(fù)載水平一維向量維度等于服務(wù)器數(shù)機(jī)柜溫度 T_i對應(yīng)機(jī)柜出風(fēng)溫度與熱力模型耦合空調(diào)總制冷功率 P_c當(dāng)前冷卻系統(tǒng)用電可觀測實(shí)時(shí)電價(jià) price當(dāng)前時(shí)隙電價(jià)來自分時(shí)電價(jià)曲線外部環(huán)境溫度 T_out影響制冷效率可設(shè)為常量或隨時(shí)間變化狀態(tài)歸一化非常重要。我踩過的最大的坑就是原始狀態(tài)直接喂網(wǎng)絡(luò)結(jié)果大量利用率的數(shù)值都在0.5~0.8電價(jià)卻在0.3~1.5之間波動溫度又是30~40網(wǎng)絡(luò)梯度被大數(shù)值變量主導(dǎo)收斂特別慢。Matlab里有normalize函數(shù)但要注意不能一次性歸一化后直接用于在線推理得記錄訓(xùn)練集的min和max推理時(shí)用同樣的映射。2.2 動作空間與離散化策略DQN要求動作空間是離散的而調(diào)度問題天然包含連續(xù)量比如任務(wù)分配比例、冷卻功率所以需要人為離散化。我最終把動作設(shè)計(jì)成三種子動作的笛卡爾積任務(wù)分配策略任務(wù)分配給哪臺服務(wù)器每臺服務(wù)器一個(gè)離散選項(xiàng)。冷卻擋位調(diào)節(jié)制冷功率設(shè)定為低/中/高三擋避免連續(xù)功率帶來的動作爆炸。服務(wù)器開關(guān)機(jī)每臺服務(wù)器可以選擇關(guān)機(jī)或開機(jī)。這樣動作數(shù) 服務(wù)器數(shù) × 3 × 2如果服務(wù)器是5臺動作空間就是30。我實(shí)際實(shí)驗(yàn)里用5臺服務(wù)器和30個(gè)離散動作DQN訓(xùn)練還比較穩(wěn)定。如果動作空間超過100建議考慮動作分支架構(gòu)dueling DQN 分支輸出否則全連接網(wǎng)絡(luò)輸出層太大訓(xùn)練效率和穩(wěn)定性都扛不住。有一點(diǎn)要特別提醒服務(wù)器開關(guān)機(jī)動作會讓狀態(tài)轉(zhuǎn)移變成非完全馬爾可夫的因?yàn)榉?wù)器從關(guān)機(jī)到開機(jī)存在啟動時(shí)間理論上需要把正在啟動的服務(wù)器也納入狀態(tài)。為了簡化我在環(huán)境里規(guī)定關(guān)機(jī)動作后至少間隔兩個(gè)時(shí)間片才能重新開機(jī)并把服務(wù)器狀態(tài)作為記憶的一部分體現(xiàn)在仿真器里這樣MDP假設(shè)依然近似成立。2.3 獎勵函數(shù)成本的負(fù)數(shù)加上懲罰DQN訓(xùn)練的目標(biāo)是最大化累計(jì)獎勵調(diào)度場景下自然應(yīng)該把負(fù)成本作為獎勵。但單純負(fù)成本太稀疏需要加入懲罰項(xiàng)加速學(xué)習(xí)。我的獎勵函數(shù)構(gòu)造如下reward - (c_elec c_switch c_sla c_temp) c_elec price * (sum(P_idle P_dynamic*u_i) P_cool) * dt c_switch beta * sum(激活開關(guān)機(jī)動作的服務(wù)器數(shù)量) c_sla gamma * max(0, 任務(wù)等待時(shí)間 - 最大容忍時(shí)間) c_temp lambda * sum(max(0, T_i - T_max))各項(xiàng)的含義c_elec當(dāng)前時(shí)隙總電費(fèi)包含IT設(shè)備空載功耗、動態(tài)功耗和冷卻功耗。c_switch對頻繁開關(guān)機(jī)動作的懲罰避免策略抖動β一般取0.1~0.3。c_sla任務(wù)違約懲罰γ較大比如1.0讓算法優(yōu)先滿足服務(wù)約束。c_temp溫度超限懲罰λ也要設(shè)得比較重因?yàn)檫^熱會損壞設(shè)備。這個(gè)獎勵函數(shù)看起來簡單但細(xì)想是有講究的。如果把電價(jià)項(xiàng)權(quán)重設(shè)得太高算法會傾向于讓所有服務(wù)器都關(guān)機(jī)來省電然后任務(wù)瘋狂違約訓(xùn)練出來一個(gè)看起來很省電、實(shí)際完全不能用的策略。為了平衡我實(shí)驗(yàn)時(shí)會記錄純省電策略和純履約策略下的單步獎勵范圍然后反推權(quán)重讓兩個(gè)方向的最壞情況都不至于壓過對方。2.4 仿真環(huán)境的狀態(tài)轉(zhuǎn)移邏輯Matlab實(shí)現(xiàn)里環(huán)境仿真器其實(shí)就是一個(gè)函數(shù)輸入是當(dāng)前狀態(tài)和動作輸出是下一狀態(tài)和獎勵。我習(xí)慣寫成[next_state, reward, done] env_step(state, action, params)。內(nèi)部邏輯根據(jù)動作更新服務(wù)器開關(guān)狀態(tài)和冷卻擋位。任務(wù)隊(duì)列并入新到達(dá)任務(wù)將部分任務(wù)分配給指定服務(wù)器執(zhí)行更新各服務(wù)器利用率。調(diào)用熱力模型更新機(jī)柜溫度。計(jì)算各項(xiàng)成本與懲罰得到獎勵。檢查是否達(dá)到仿真終點(diǎn)例如96個(gè)時(shí)隙跑完。熱力模型我用的是一階熱平衡方程某一時(shí)刻溫度變化率等于產(chǎn)熱功率減去散熱功率再乘以熱容倒數(shù)。Matlab里用歐拉前向差分更新就行時(shí)間步長15分鐘穩(wěn)定性沒問題。真正要小心的是不能讓溫度狀態(tài)出現(xiàn)負(fù)值或者超出物理范圍否則后期仿真的數(shù)值會崩掉。3. DQN算法的核心機(jī)制與Matlab代碼實(shí)現(xiàn)3.1 DQN為什么能穩(wěn)定訓(xùn)練兩個(gè)關(guān)鍵機(jī)制如果只用一個(gè)普通神經(jīng)網(wǎng)絡(luò)做Q值擬合訓(xùn)練震蕩會非常嚴(yán)重。原因很簡單網(wǎng)絡(luò)在更新時(shí)目標(biāo)值也是同一個(gè)網(wǎng)絡(luò)算出來的參數(shù)一變目標(biāo)就跟著變模型在追一個(gè)移動靶子。DQN的兩個(gè)核心機(jī)制就是為了解決這個(gè)移動靶問題。第一個(gè)是經(jīng)驗(yàn)回放Experience Replay。把每一步的(state, action, reward, next_state, done)存進(jìn)經(jīng)驗(yàn)池訓(xùn)練時(shí)隨機(jī)采樣一個(gè)小批量打破數(shù)據(jù)的時(shí)間相關(guān)性避免網(wǎng)絡(luò)對近期經(jīng)驗(yàn)過擬合。第二個(gè)是目標(biāo)網(wǎng)絡(luò)Target Network。維護(hù)一個(gè)參數(shù)更新比較滯后的目標(biāo)網(wǎng)絡(luò)每隔C步才從當(dāng)前網(wǎng)絡(luò)同步權(quán)重用它來計(jì)算TD目標(biāo)讓訓(xùn)練目標(biāo)在一段時(shí)間內(nèi)保持穩(wěn)定。在Matlab里實(shí)現(xiàn)經(jīng)驗(yàn)池我直接用一個(gè)結(jié)構(gòu)體數(shù)組加頭尾指針簡單不花哨。經(jīng)驗(yàn)池容量設(shè)成20000~50000采樣批量64目標(biāo)網(wǎng)絡(luò)同步周期C設(shè)為200步這些是我試過比較穩(wěn)的參數(shù)。容量設(shè)太大比如100萬會導(dǎo)致早期經(jīng)驗(yàn)占太多學(xué)習(xí)效率低容量設(shè)太小則回放樣本高度相關(guān)效果還不如在線學(xué)習(xí)。3.2 神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)與Matlab代碼網(wǎng)絡(luò)結(jié)構(gòu)我用的三層全連接輸入層10個(gè)節(jié)點(diǎn)對應(yīng)10維狀態(tài)隱藏層分別64和32激活函數(shù)ReLU輸出層30個(gè)節(jié)點(diǎn)對應(yīng)30個(gè)離散動作。Matlab里有現(xiàn)成的強(qiáng)化學(xué)習(xí)工具箱可以構(gòu)造DQN智能體但我更推薦手寫訓(xùn)練循環(huán)因?yàn)楹竺嬉{(diào)獎勵權(quán)重、觀察中間值手寫控制力更強(qiáng)。% 定義Q網(wǎng)絡(luò) state_dim 10; action_dim 30; hidden 64; % 使用Deep Learning Toolbox的函數(shù)構(gòu)建網(wǎng)絡(luò) lgraph layerGraph([ imageInputLayer([state_dim 1 1], Normalization, none, Name, state_in) fullyConnectedLayer(hidden, Name, fc1) reluLayer(Name, relu1) fullyConnectedLayer(hidden/2, Name, fc2) reluLayer(Name, relu2) fullyConnectedLayer(action_dim, Name, fc_out) ]); % 注imageInputLayer要求輸入為[w h 1]格式這里把狀態(tài)向量當(dāng)1xN的圖像注意Matlab的imageInputLayer對單通道輸入有自己的尺寸要求習(xí)慣上把狀態(tài)向量當(dāng)做一個(gè)寬為N、高為1、通道為1的圖像來定義。也可以用featureInputLayer但我在R2021a下測試過featureInputLayer與rlVectorQValueFunction結(jié)合更順滑不過手寫訓(xùn)練時(shí)不必執(zhí)著于某個(gè)API能完成前向計(jì)算和梯度反向傳播就行。前向Q值計(jì)算和反向傳播我優(yōu)先用dlnetwork對象方便dlgradient自動求導(dǎo)% 將layerGraph轉(zhuǎn)為dlnetwork net dlnetwork(lgraph); targetNet dlnetwork(lgraph); % 目標(biāo)網(wǎng)絡(luò)初始相同 % 前向計(jì)算 Q(s) state dlarray(single(s_state), CB); Q_vals forward(net, state, Outputs, fc_out); Q_max_next max(forward(targetNet, state_next, Outputs, fc_out));3.3 訓(xùn)練主循環(huán)訓(xùn)練主循環(huán)結(jié)構(gòu)非常傳統(tǒng)每個(gè)時(shí)間步在仿真器里采一個(gè)經(jīng)驗(yàn)存進(jìn)經(jīng)驗(yàn)池每4步做一次小批量訓(xùn)練每200步同步一次目標(biāo)網(wǎng)絡(luò)。我自己寫的訓(xùn)練主循環(huán)核心代碼如下for ep 1:maxEps state env_reset(); done false; while ~done % epsilon-greedy動作選擇 if rand() epsilon action randi(action_dim); else Q_all predict_Q(net, state); [~, action] max(Q_all); end % 執(zhí)行動作獲得轉(zhuǎn)移 [next_state, reward, done] env_step(state, action, env_params); % 存入經(jīng)驗(yàn)池 buffer_add(buffer, state, action, reward, next_state, done); state next_state; % 每4步訓(xùn)練一次 if mod(t, 4) 0 buffer.size batchSize [s_b, a_b, r_b, s_next_b, done_b] buffer_sample(buffer, batchSize); train_dqn(net, targetNet, s_b, a_b, r_b, s_next_b, done_b, gamma, lr); end % 每200步同步目標(biāo)網(wǎng)絡(luò) if mod(t, 200) 0 targetNet net; end % epsilon線性衰減 epsilon max(epsilon_min, epsilon * epsilon_decay); t t 1; end end這里有個(gè)細(xì)節(jié)Matlab的forward和predict用法在深度學(xué)習(xí)工具箱里很靈活但每次前向都要構(gòu)造dlarray訓(xùn)練速度遠(yuǎn)不如Python的PyTorch。想要加速可以利用Matlab的并行計(jì)算工具箱把環(huán)境仿真和網(wǎng)絡(luò)訓(xùn)練分別放到不同的worker上或者減少批量訓(xùn)練的頻率。我在實(shí)驗(yàn)中把每4步訓(xùn)練一次改成每8步訓(xùn)練一次損失下降曲線穩(wěn)定很多電費(fèi)優(yōu)化率還稍微提升了這說明訓(xùn)練頻率過高也會導(dǎo)致策略在局部振蕩。3.4 超參數(shù)參考表超參數(shù)推薦范圍我的最終取值調(diào)參心得學(xué)習(xí)率1e-4~1e-35e-4過大會震蕩過小收斂慢也回不到最優(yōu)折扣因子γ0.9~0.990.95太大則算法短視太小則只看眼前ε初值0.5~1.00.8先充分探索再逐步利用ε最小值0.01~0.10.01保證后期仍有一點(diǎn)探索經(jīng)驗(yàn)池容量20000~5000030000容量不夠會讓目標(biāo)網(wǎng)絡(luò)失去意義批量大小32~12864大批量訓(xùn)練更穩(wěn)定但更慢目標(biāo)網(wǎng)絡(luò)同步周期100~500200太頻繁等于沒有目標(biāo)網(wǎng)絡(luò)隱藏層節(jié)點(diǎn)數(shù)64~12864狀態(tài)量不多時(shí)不需太寬這些參數(shù)不是死數(shù)關(guān)鍵是理解每個(gè)參數(shù)調(diào)節(jié)背后的物理直覺。比如折扣因子γ如果調(diào)大意味著策略更看重長期成本這跟電價(jià)峰谷周期長度有關(guān)電價(jià)周期是一天24小時(shí)96個(gè)時(shí)隙那γ0.99可能比0.95更合適因?yàn)槲磥?0個(gè)時(shí)隙的影響都不能忽視。我最終在γ0.95和0.99之間選擇的依據(jù)是累計(jì)獎勵的方差γ越大方差越大訓(xùn)練初期越不穩(wěn)定。4. 實(shí)驗(yàn)設(shè)計(jì)、對比基線與結(jié)果解讀4.1 實(shí)驗(yàn)場景與數(shù)據(jù)集生成實(shí)驗(yàn)的場景參數(shù)必須貼近實(shí)際否則驗(yàn)證結(jié)果沒有說服力。我用5臺規(guī)格相近的服務(wù)器每臺服務(wù)器空閑功耗150W滿負(fù)載功耗400W最高算力容量按單位任務(wù)計(jì)算。任務(wù)到達(dá)率用泊松過程模擬平均每小時(shí)到達(dá)16~24個(gè)任務(wù)每個(gè)任務(wù)需要1到3個(gè)單位的CPU資源。電價(jià)曲線采用典型的分時(shí)三段制峰時(shí)1.2元/度、平時(shí)0.7元/度、谷時(shí)0.3元/度峰值時(shí)段為上午10點(diǎn)到下午14點(diǎn)和傍晚18點(diǎn)到22點(diǎn)。外部環(huán)境溫度設(shè)置為25~35攝氏度的日變化曲線模擬夏季工況。每5次仿真使用相同隨機(jī)種子生成同一套任務(wù)到達(dá)序列確保不同策略對比的公平性。Matlab里用rng(seed)控制隨機(jī)數(shù)這個(gè)是實(shí)驗(yàn)復(fù)現(xiàn)的底線。4.2 對比基線的選擇做實(shí)驗(yàn)最忌諱只跟隨機(jī)策略比較說服力太弱。我選了三個(gè)有實(shí)際參考意義的基線隨機(jī)策略每個(gè)時(shí)隙隨機(jī)選動作。這個(gè)基線一般主要用來驗(yàn)證環(huán)境仿真器沒有bug。閾值啟發(fā)式策略當(dāng)隊(duì)列長度超過閾值時(shí)把任務(wù)分配給利用率最低的服務(wù)器機(jī)柜溫度超過35度時(shí)冷卻調(diào)高擋位。這是很多現(xiàn)場還在用的傳統(tǒng)做法。貪心策略每個(gè)時(shí)隙選擇當(dāng)前Q值最高的動作即DQN去掉了探索環(huán)節(jié)直接利用。這個(gè)對比能看出離線訓(xùn)練出的策略到底好不好用。此外如果環(huán)境允許還可以加一個(gè)理想化求解策略即用混合整數(shù)規(guī)劃求解器在小規(guī)模問題上求最優(yōu)解作為性能上界。我這里只有5臺服務(wù)器動作空間30用求解器算96個(gè)時(shí)隙的最優(yōu)解可行于是我也加了這個(gè)參照。4.3 結(jié)果分析與深層機(jī)制剖析實(shí)驗(yàn)結(jié)果顯示DQN策略在總電費(fèi)上比閾值啟發(fā)式策略節(jié)省了17%左右比隨機(jī)策略節(jié)省40%以上跟理想最優(yōu)解的差距縮小到6%以內(nèi)。最有意思的是電費(fèi)節(jié)約的構(gòu)成我原本以為主要省在制冷功率的調(diào)節(jié)結(jié)果拆解后發(fā)現(xiàn)最大一部分來自任務(wù)轉(zhuǎn)移——DQN學(xué)會了在電價(jià)低的夜間把能推遲的任務(wù)安排給服務(wù)器白天高峰時(shí)段只處理緊急任務(wù)服務(wù)器關(guān)機(jī)數(shù)量白天明顯多于夜間。這個(gè)現(xiàn)象背后是DQN通過獎勵函數(shù)逐步學(xué)到了電價(jià)差這個(gè)時(shí)間維度的特征這恰恰是傳統(tǒng)閾值策略做不到的。閾值策略只關(guān)心當(dāng)前隊(duì)列長度和溫度完全沒有對電價(jià)會在未來幾個(gè)時(shí)隙上漲的預(yù)判能力。溫度表現(xiàn)同樣滿足預(yù)期。DQN策略把機(jī)柜溫度控制在35度以下的概率約為98.7%略低于理想最優(yōu)策略的99.2%但遠(yuǎn)高于貪心策略的91.3%。貪心策略的問題在于訓(xùn)練結(jié)束后我把探索完全關(guān)掉網(wǎng)絡(luò)對某些狀態(tài)下Q值的變化很敏感偶發(fā)情況下會做出極端動作比如氣溫較高時(shí)關(guān)機(jī)過多導(dǎo)致剩余服務(wù)器超載可見探索噪聲在訓(xùn)練中的正則化作用對策略魯棒性也有貢獻(xiàn)。收斂性上DQN在3000個(gè)episode左右開始穩(wěn)定累計(jì)獎勵曲線波動幅度從±40%收窄到±8%。有趣的是我最初設(shè)置的訓(xùn)練episode是一萬但測試發(fā)現(xiàn)2500~4000個(gè)episode之間策略性能基本不再提升過早停止會差一些訓(xùn)練過頭也不見得更好有些子優(yōu)動作會慢慢占據(jù)上風(fēng)所以實(shí)踐里我建議訓(xùn)練中保存多個(gè)checkpoint最后用驗(yàn)證集上的表現(xiàn)挑選最優(yōu)模型而不是簡單取最后一個(gè)episode的結(jié)果。5. 工程實(shí)現(xiàn)中的常見問題與調(diào)試手記5.1 獎勵函數(shù)的稀疏與數(shù)值爆炸第一個(gè)常見問題是獎勵數(shù)值范圍跨度太大。電費(fèi)一檔可能是幾十塊錢溫度懲罰一算出來就是上百萬神經(jīng)網(wǎng)絡(luò)損失直接爆表。這個(gè)問題的解法不是簡單歸一化而是讓獎勵項(xiàng)量級盡量一致。我重新設(shè)計(jì)權(quán)重后把各項(xiàng)單步獎勵控制在[-10, 0]區(qū)間訓(xùn)練穩(wěn)定性立竿見影。這里有個(gè)實(shí)操技巧寫完獎勵函數(shù)先跑一次不訓(xùn)練的隨機(jī)策略把每項(xiàng)獎勵的分布打印出來看數(shù)量級用這個(gè)分布去定權(quán)重比憑感覺靠譜得多。5.2 Q值過估計(jì)問題DQN的Q值天然存在高估傾向因?yàn)閙ax操作符會累積噪聲。我在實(shí)驗(yàn)初期也觀察到訓(xùn)練后期網(wǎng)絡(luò)輸出的Q值比實(shí)際累計(jì)獎勵大好幾倍但最優(yōu)動作仍然正確所以這個(gè)問題沒有立刻影響策略。但如果Q值高估到一定程度次優(yōu)動作也可能被誤選尤其當(dāng)兩個(gè)動作的真實(shí)Q值非常接近時(shí)。緩解手段有兩個(gè)一個(gè)是把目標(biāo)網(wǎng)絡(luò)換成Double DQN用當(dāng)前網(wǎng)絡(luò)選擇最佳動作、目標(biāo)網(wǎng)絡(luò)計(jì)算該動作的Q值另一個(gè)是我實(shí)際用的——降低目標(biāo)網(wǎng)絡(luò)的同步頻率給目標(biāo)值一個(gè)冷卻期。如果項(xiàng)目時(shí)間充裕建議直接上Double DQN改動量只有3~5行代碼性價(jià)比很高。5.3 Matlab訓(xùn)練效率低下的應(yīng)對思路Matlab訓(xùn)練深度網(wǎng)絡(luò)的速度確實(shí)比C或Python慢我在入門階段也為此困擾過。但仔細(xì)分析后發(fā)現(xiàn)大部分時(shí)間花在dlarray創(chuàng)建和環(huán)境仿真的串行執(zhí)行上。三個(gè)優(yōu)化立竿見影第一狀態(tài)和獎勵盡量用MATLAB原生數(shù)組操作不要在循環(huán)里反復(fù)調(diào)用zeros和dlarray第二把env_step改成向量化計(jì)算一次仿真所有服務(wù)器溫度同步更新避免逐臺服務(wù)器for循環(huán)第三嘗試用MATLAB Coder把環(huán)境仿真轉(zhuǎn)成MEX如果項(xiàng)目周期允許這一步能帶來接近5倍的加速。另一個(gè)思路是用并行工具箱做多智能體并行訓(xùn)練——既然算法是獨(dú)立環(huán)境的可以開8個(gè)worker并行采樣再集中訓(xùn)練效果類似Ape-X架構(gòu)的簡化版。這個(gè)方案我實(shí)驗(yàn)過收斂速度大約提升3倍代價(jià)是實(shí)現(xiàn)復(fù)雜度增加不少。5.4 訓(xùn)練不收斂時(shí)先檢查環(huán)境還是先檢查算法我給初學(xué)者的建議是如果損失值完全不下降90%的問題在環(huán)境仿真器。比如獎勵函數(shù)寫錯符號、狀態(tài)轉(zhuǎn)移邏輯存在bug、狀態(tài)歸一化用了全局統(tǒng)計(jì)量導(dǎo)致分布偏移這些錯誤會讓算法覺得同一個(gè)狀態(tài)同一動作一會兒好一會兒壞網(wǎng)絡(luò)很難學(xué)會任何東西。一個(gè)快速診斷方法固定一個(gè)狀態(tài)和動作重復(fù)執(zhí)行1000次打印輸出的獎勵和下一狀態(tài)人工校驗(yàn)是否與物理直覺一致。我自己的仿真器曾經(jīng)在熱力模型更新時(shí)用錯了一層括號位置導(dǎo)致溫度永遠(yuǎn)不變當(dāng)時(shí)查了兩天才發(fā)現(xiàn)就是因?yàn)闆]有做這個(gè)單步檢測。還有一個(gè)更隱蔽的問題是動作不可逆。如果在同一狀態(tài)多次執(zhí)行同一動作得到完全不同的結(jié)果而狀態(tài)里又沒有記錄引起差異的隱藏變量那MDP假設(shè)就不成立DQN會怎么訓(xùn)都收斂不了。我在環(huán)境里加入服務(wù)器啟動延遲的隱藏狀態(tài)來處理這個(gè)問題不過這相當(dāng)于變相把動作的效果延遲了同時(shí)也會影響Q值的信用分配。在實(shí)際項(xiàng)目中遇到這類情況最簡單的緩解手段是把動作執(zhí)行后N個(gè)時(shí)隙內(nèi)的觀測直接拼接到狀態(tài)里讓網(wǎng)絡(luò)能夠看到動作的滯后效應(yīng)。6. 從仿真到落地的幾條實(shí)在建議寫到這里我的核心經(jīng)驗(yàn)已經(jīng)基本講完最后補(bǔ)充幾條從仿真原型往實(shí)際調(diào)度平臺遷移時(shí)的個(gè)人體會。在真實(shí)數(shù)據(jù)中心不要指望訓(xùn)練出來的DQN策略直接接管控制權(quán)。我見過太多項(xiàng)目在仿真里跑得飛快一上線就翻車原因是仿真模型跟物理世界存在誤差服務(wù)器實(shí)際功耗非線性的部分比線性模型復(fù)雜得多冷卻系統(tǒng)還有惰性和延遲。穩(wěn)妥的落地路徑是把強(qiáng)化學(xué)習(xí)策略當(dāng)成一個(gè)優(yōu)化建議器它輸出每個(gè)時(shí)隙的傾向性動作再由人工或者規(guī)則層做安全校驗(yàn)只有落在安全區(qū)間內(nèi)的動作才被采納。等到累計(jì)足夠多的真實(shí)數(shù)據(jù)后再微調(diào)仿真器參數(shù)縮小sim-to-real gap。模型泛化也是要注意的。在單一電價(jià)曲線、單一任務(wù)分布下訓(xùn)練好的DQN換一個(gè)場景大概率性能驟降。我在測試中發(fā)現(xiàn)如果把電價(jià)曲線改成節(jié)假日/工作日的規(guī)律性波動原先訓(xùn)練好的網(wǎng)絡(luò)前幾個(gè)episode表現(xiàn)很差但通過遷移學(xué)習(xí)用小學(xué)習(xí)率在少量新數(shù)據(jù)上微調(diào)很快就能恢復(fù)性能。這說明DQN學(xué)到的是調(diào)度規(guī)律而不是死板動作表只是規(guī)律會依賴電價(jià)波動的具體形態(tài)。落地時(shí)建議保留在線微調(diào)通道每周用真實(shí)運(yùn)行數(shù)據(jù)做一次增量訓(xùn)練。最后如果你在做的場景動作空間含連續(xù)變量比如水泵頻率、冷凍水溫度設(shè)定DQN就不合適了可以考慮DDPG或TD3這類actor-critic連續(xù)控制算法。但從我這個(gè)項(xiàng)目的經(jīng)驗(yàn)看很多看似連續(xù)的控制量其實(shí)可以按擋位離散化只要擋位分得夠細(xì)DQN的性能損失并不大而實(shí)現(xiàn)和調(diào)試的代價(jià)卻低了一個(gè)數(shù)量級。調(diào)度這件事從來不是算法越復(fù)雜越好而是越貼合物理約束越好希望這篇分享能幫你少走幾步彎路。