燈相位時(shí)間優(yōu)化:從SUMO仿真到實(shí)戰(zhàn)調(diào)參)
簡介面向畢業(yè)設(shè)計(jì)與課程設(shè)計(jì)場景資源提供了一套基于開源SUMO交通仿真平臺(tái)和深度強(qiáng)化學(xué)習(xí)DQN算法的信號(hào)燈相位時(shí)間優(yōu)化項(xiàng)目。整套代碼采用Python編寫覆蓋路網(wǎng)構(gòu)建、仿真交互、模型訓(xùn)練與結(jié)果分析等關(guān)鍵環(huán)節(jié)適合對智能交通和強(qiáng)化學(xué)習(xí)感興趣的開發(fā)者快速上手。項(xiàng)目共32個(gè)文件包含路網(wǎng)配置、地圖數(shù)據(jù)、算法腳本、實(shí)驗(yàn)結(jié)果表格及說明文檔其中XML和OSM文件用于構(gòu)建仿真環(huán)境PY文件為核心控制邏輯壓縮包僅533KB部署輕量。目前已有545人學(xué)習(xí)使用。通過閱讀源碼可以理解狀態(tài)特征選取、動(dòng)作輸出方式和獎(jiǎng)勵(lì)函數(shù)設(shè)計(jì)并掌握將DQN應(yīng)用于交通信號(hào)控制的完整流程理解從路網(wǎng)搭建、仿真交互到模型訓(xùn)練與收斂評(píng)估的整個(gè)鏈路便于在此基礎(chǔ)上擴(kuò)展優(yōu)先級(jí)決策或遷移至其他路網(wǎng)場景。 大概半年前我準(zhǔn)備一個(gè)交通仿真的課程項(xiàng)目時(shí)盯著SUMO仿真界面里的紅綠燈發(fā)呆東西方向已經(jīng)堵成一片南北方向卻一輛車都沒有可信號(hào)燈依然按著固定配時(shí)在傻傻地放行。那一刻我意識(shí)到交通信號(hào)燈控制遠(yuǎn)比看起來復(fù)雜它本質(zhì)上是一個(gè)動(dòng)態(tài)環(huán)境下的序列決策問題而這類問題恰好是強(qiáng)化學(xué)習(xí)的看家本領(lǐng)。于是我基于Python SUMO仿真平臺(tái)用DQN做了一套能根據(jù)實(shí)時(shí)車流調(diào)整交通信號(hào)燈相位時(shí)間的方案整套源碼也整理成了一個(gè)開源項(xiàng)目。這篇文章就把這套方案從環(huán)境搭建、算法設(shè)計(jì)到訓(xùn)練調(diào)參的完整過程拆給你看適合正在做畢設(shè)、參加競賽或者想入門強(qiáng)化學(xué)習(xí)在交通領(lǐng)域應(yīng)用的同學(xué)參考。1. 信號(hào)燈控制的痛點(diǎn)為什么固定配時(shí)總是差一口氣1.1 交通流本身就是非平穩(wěn)的傳統(tǒng)路口信號(hào)機(jī)用的都是固定配時(shí)方案也就是預(yù)先算好每個(gè)相位的紅綠燈時(shí)長然后按周期循環(huán)執(zhí)行。這種方式在車流比較穩(wěn)定的時(shí)候勉強(qiáng)夠用但一旦遇到早晚高峰、學(xué)校放假、突發(fā)事故、旁邊路口修路車流特征就會(huì)完全變化。固定配時(shí)沒有任何感知能力只能按部就班地放行結(jié)果就是綠燈方向沒車紅燈方向排隊(duì)幾百米整個(gè)路口通行效率大幅下降。很多同學(xué)可能會(huì)覺得那我用多時(shí)段配時(shí)方案不就行了高峰一套、平峰一套。這確實(shí)比固定配時(shí)強(qiáng)但本質(zhì)上還是開環(huán)控制交通流一旦出現(xiàn)計(jì)劃之外的波動(dòng)多時(shí)段方案照樣失靈。交通仿真里我們經(jīng)常說一句話交通流本身是非平穩(wěn)的每分鐘的車流量都在變所以真正有效的策略必須是閉環(huán)的、能根據(jù)實(shí)時(shí)狀態(tài)做出反應(yīng)的。1.2 DQN在信號(hào)燈場景里到底做什么用DQN解決信號(hào)燈問題其實(shí)是把信號(hào)燈控制器當(dāng)成一個(gè)智能體讓它通過與環(huán)境不斷試錯(cuò)來學(xué)習(xí)一套控制策略。每個(gè)決策時(shí)刻智能體觀察當(dāng)前路口的狀態(tài)比如各個(gè)方向的車隊(duì)有多長、車輛等了多久然后決定當(dāng)前綠燈相位應(yīng)該繼續(xù)延長還是切換到下一個(gè)相位。切換之后環(huán)境發(fā)生改變智能體會(huì)得到一個(gè)獎(jiǎng)勵(lì)信號(hào)比如等待車輛減少了多少。經(jīng)過成千上萬次試探DQN會(huì)逐漸學(xué)會(huì)什么情況下該延長、什么情況下該切換。用一個(gè)生活化類比固定配時(shí)相當(dāng)于一臺(tái)自動(dòng)售貨機(jī)投幣后永遠(yuǎn)出同一瓶飲料DQN相當(dāng)于一個(gè)有經(jīng)驗(yàn)的老交警他會(huì)看一眼各個(gè)方向的車流再?zèng)Q定先放誰、放多久而且隨著經(jīng)驗(yàn)積累判斷越來越準(zhǔn)。1.3 這個(gè)項(xiàng)目適合誰、能學(xué)到什么如果你正在做智慧交通方向的畢設(shè)或競賽項(xiàng)目這個(gè)題目幾乎是標(biāo)配如果你想入門強(qiáng)化學(xué)習(xí)但不想跑那種玩具環(huán)境交通信號(hào)燈也是一個(gè)很合適的實(shí)戰(zhàn)場景。跑通這個(gè)項(xiàng)目你至少能收獲四樣?xùn)|西SUMO這個(gè)專業(yè)交通仿真器的基本使用包括路網(wǎng)生成、車流配置、TraCI接口調(diào)用強(qiáng)化學(xué)習(xí)三要素——狀態(tài)、動(dòng)作、獎(jiǎng)勵(lì)函數(shù)——如何映射到真實(shí)工程問題里DQN的完整訓(xùn)練鏈路包括經(jīng)驗(yàn)回放、目標(biāo)網(wǎng)絡(luò)、epsilon-greedy探索一套可以擴(kuò)展的多路口信號(hào)燈控制源碼框架后續(xù)換算法比如DQN換PPO只需要改agent部分。2. SUMO環(huán)境搭建與TraCI通信先說環(huán)境再談算法2.1 SUMO安裝與環(huán)境變量配置SUMO全稱Simulation of Urban MObility是一款開源的微觀交通仿真平臺(tái)。所謂微觀就是每輛車都有獨(dú)立的加速度、最大速度、換道行為能夠比較真實(shí)地模擬交通流。安裝方式取決于操作系統(tǒng)。Windows用戶可以直接去官網(wǎng)下載安裝包也可以用包管理器安裝Ubuntu等Linux系統(tǒng)推薦命令安裝macOS用brew也能裝。安裝完成后需要確認(rèn)SUMO_HOME環(huán)境變量指向安裝目錄并且把sumo和netconvert這些可執(zhí)行文件所在目錄加入PATH否則后續(xù)Python調(diào)用會(huì)找不到命令。驗(yàn)證安裝可以打開終端執(zhí)行一句命令sumo --version如果能看到版本號(hào)說明安裝成功。要注意的是SUMO更新迭代很快不同大版本的TraCI接口函數(shù)會(huì)有差異我這邊用的是1.15.0版本如果你用的版本比較新個(gè)別接口名可能需要微調(diào)。2.2 搭建一個(gè)十字路口仿真場景訓(xùn)練信號(hào)燈控制先得有一個(gè)能反復(fù)實(shí)驗(yàn)的路口場景。最經(jīng)典的就是單十字路口兩個(gè)方向交叉每條進(jìn)口道雙向各兩車道中間路口設(shè)置信號(hào)燈。SUMO里搭建場景有兩種方式一是用自帶的netedit圖形化編輯器畫二是用XML文件定義節(jié)點(diǎn)和邊然后通過netconvert命令生成路網(wǎng)。圖形化適合微調(diào)命令行適合自動(dòng)化生成我項(xiàng)目中用的是后者的思路。路網(wǎng)的基本結(jié)構(gòu)是nodes.xml里定義節(jié)點(diǎn)坐標(biāo)edges.xml里定義連接的邊。一個(gè)簡單十字路口可以這樣描述nodes node idN x0 y300/ node idS x0 y0/ node idE x300 y150/ node idW x0 y150/ /nodes定義好節(jié)點(diǎn)后用netconvert生成路網(wǎng)時(shí)給中間節(jié)點(diǎn)加一個(gè)typetraffic_light屬性系統(tǒng)就會(huì)自動(dòng)為該路口分配一套兩相位信號(hào)燈方案。車流文件rou.xml則定義了車輛什么時(shí)候出現(xiàn)、從哪個(gè)進(jìn)口道到哪個(gè)出口道可以通過flow標(biāo)簽靈活設(shè)置每小時(shí)車流量。最后用sumo.sumocfg把這些文件匯總起來。訓(xùn)練時(shí)只需要在Python里用一行命令啟動(dòng)仿真import traci traci.start([sumo, -c, config.sumocfg])訓(xùn)練階段我強(qiáng)烈建議不用sumo-gui因?yàn)閳D形界面會(huì)拖慢仿真速度。要看可視化效果時(shí)再換回sumo-gui即可。2.3 TraCI接口讓Python成為交通指揮官TraCITraffic Control Interface是SUMO提供的通信接口基于TCP協(xié)議。Python通過import traci連接上仿真進(jìn)程后就能實(shí)時(shí)讀取路網(wǎng)狀態(tài)、控制車輛和信號(hào)燈相當(dāng)于給仿真環(huán)境開了一個(gè)后門。日常用得最多的TraCI方法大概是這幾個(gè)功能方法說明獲取當(dāng)前仿真時(shí)間traci.simulation.getTime()單位秒獲取車道排隊(duì)車輛數(shù)traci.lane.getLastStepVehicleNumber(laneID)通過具體車道ID查詢獲取路段等待時(shí)間traci.edge.getWaitingTime(edgeID)返回所有車輛等待總秒數(shù)獲取當(dāng)前信號(hào)燈相位traci.trafficlight.getPhase(tlsID)返回相位序號(hào)設(shè)置當(dāng)前相位剩余時(shí)間traci.trafficlight.setPhaseDuration(tlsID, dur)控制綠燈延長/縮短切換相位序號(hào)traci.trafficlight.setPhase(tlsID, idx)直接跳轉(zhuǎn)到指定相位項(xiàng)目里為了統(tǒng)一獲取當(dāng)前路口的綜合狀態(tài)我會(huì)封裝一個(gè)StateExtractor類把所有TraCI查詢集中在一起這樣訓(xùn)練主程序看起來更干凈后面加特征也好維護(hù)。3. DQN建模三件套狀態(tài)、動(dòng)作、獎(jiǎng)勵(lì)函數(shù)的設(shè)計(jì)邏輯3.1 狀態(tài)空間給智能體一雙能看路況的眼睛狀態(tài)空間的設(shè)計(jì)直接決定智能體能不能學(xué)會(huì)策略。如果只給一個(gè)當(dāng)前時(shí)間DQN什么都學(xué)不會(huì)如果給全路網(wǎng)幾百輛車的坐標(biāo)輸入維度太大訓(xùn)練難度又會(huì)爆炸。需要找到一組既能描述路況、又足夠精簡的特征。我最終使用的狀態(tài)向量由一個(gè)路口的關(guān)鍵信息拼裝而成四個(gè)進(jìn)口道方向的排隊(duì)車輛數(shù)單位輛四個(gè)方向的平均等待時(shí)間單位秒當(dāng)前相位編號(hào)和當(dāng)前相位已經(jīng)持續(xù)的秒數(shù)路口總等待時(shí)間單位秒。之所以要把當(dāng)前相位編號(hào)和相位已持續(xù)時(shí)長放進(jìn)去是因?yàn)镈QN的動(dòng)作決策跟當(dāng)前信號(hào)燈在哪個(gè)狀態(tài)密切相關(guān)。同時(shí)排隊(duì)長度和等待時(shí)間這兩類特征一個(gè)體現(xiàn)空間擁堵一個(gè)體現(xiàn)時(shí)間延誤組合起來能幫助智能體平衡放行效率和公平性。有一點(diǎn)必須提醒喂給網(wǎng)絡(luò)的輸入一定要做歸一化。排隊(duì)長度可能到幾十輛等待時(shí)間可能到幾百秒這些數(shù)值直接放在一起會(huì)讓神經(jīng)網(wǎng)絡(luò)初期的梯度被大數(shù)值維度主導(dǎo)導(dǎo)致訓(xùn)練很不穩(wěn)定。我的做法比較簡單排隊(duì)車輛數(shù)除以路口最大車道容量等待時(shí)間除以一個(gè)經(jīng)驗(yàn)上限比如180秒把大部分特征壓到0到1范圍內(nèi)。3.2 動(dòng)作空間把相位時(shí)間調(diào)整變成DQN的輸出標(biāo)題里的相位時(shí)間調(diào)整在代碼上其實(shí)可以抽象成兩類動(dòng)作設(shè)計(jì)方式。第一種是把綠燈時(shí)間離散成幾個(gè)固定檔位比如動(dòng)作0表示延長5秒動(dòng)作1表示延長10秒動(dòng)作2表示延長15秒動(dòng)作3表示立即切換相位。這種方式動(dòng)作空間更細(xì)但會(huì)讓訓(xùn)練收斂變慢因?yàn)閹讉€(gè)延長時(shí)間選項(xiàng)產(chǎn)生的狀態(tài)差異很小Q值難分高下。第二種是把動(dòng)作簡化為二分類繼續(xù)延長當(dāng)前綠燈相位或者結(jié)束當(dāng)前相位、進(jìn)入下一相位。我最終選擇的是這個(gè)方案。原因很簡單單路口信號(hào)燈控制的本質(zhì)決策就是切換還是不切換至于延長多久可以通過決策頻率來間接控制。我的決策間隔設(shè)為10秒也就是說每10秒智能體評(píng)估一次如果選擇保持綠燈自動(dòng)加10秒如果選擇切換信號(hào)燈就會(huì)在下一個(gè)仿真步進(jìn)入黃燈過渡再進(jìn)入下一相位。這個(gè)設(shè)計(jì)還有一個(gè)好處它完全符合真實(shí)信號(hào)機(jī)的工作邏輯?,F(xiàn)實(shí)中信號(hào)燈并不可能每秒鐘都在調(diào)整決策頻率過低或過高都不合理。決策間隔太短會(huì)導(dǎo)致頻繁切換形成綠燈剛亮就滅的抖動(dòng)現(xiàn)象間隔太長又會(huì)讓智能體反應(yīng)遲鈍。10秒是我在試驗(yàn)中覺得平衡性最好的值。3.3 獎(jiǎng)勵(lì)函數(shù)排隊(duì)長度變化量怎么量化獎(jiǎng)勵(lì)函數(shù)是強(qiáng)化學(xué)習(xí)最容易被忽略、但也最決定成敗的部分。信號(hào)燈控制最常見的優(yōu)化目標(biāo)是減小車輛平均等待時(shí)間、減少排隊(duì)、提高通行量但這些目標(biāo)直接作為獎(jiǎng)勵(lì)并不好優(yōu)化因?yàn)樗鼈兌际情L期累積量反饋稀疏且延遲嚴(yán)重。我采用的獎(jiǎng)勵(lì)公式是R - (L_t - L_{t-1})其中L_t是當(dāng)前時(shí)刻路口所有進(jìn)口道的排隊(duì)車輛總數(shù)L_{t-1}是上一決策時(shí)刻的排隊(duì)車輛總數(shù)。這個(gè)公式的含義非常直觀如果這次決策讓排隊(duì)車輛減少了獎(jiǎng)勵(lì)為正讓排隊(duì)增加了獎(jiǎng)勵(lì)為負(fù)。智能體最大化累積獎(jiǎng)勵(lì)本質(zhì)上就是在最小化整個(gè)仿真時(shí)段內(nèi)的排隊(duì)增量。為什么不用平均等待時(shí)間作為直接獎(jiǎng)勵(lì)因?yàn)榈却龝r(shí)間的變化到?jīng)Q策之間有時(shí)序滯后而且受偶發(fā)車流波動(dòng)影響大方差很高。排隊(duì)長度變化量則是一個(gè)相對平滑、立竿見影的指標(biāo)SRStability也更好。如果你想進(jìn)一步優(yōu)化可以在獎(jiǎng)勵(lì)里加一個(gè)切換懲罰項(xiàng)比如每次切換相位時(shí)額外減一個(gè)固定值防止智能體頻繁抖動(dòng)。我試驗(yàn)后發(fā)現(xiàn)加了切換懲罰反而會(huì)導(dǎo)致智能體過于保守該切換時(shí)不切換所以最終版本里沒加。3.4 三件套的整體聯(lián)動(dòng)狀態(tài)、動(dòng)作、獎(jiǎng)勵(lì)這三者不是孤立的它們共同定義了馬爾可夫決策過程。具體到運(yùn)行流程每個(gè)決策時(shí)刻智能體根據(jù)狀態(tài)選擇動(dòng)作動(dòng)作改變信號(hào)燈相位時(shí)間相位時(shí)間影響車流運(yùn)行車流運(yùn)行產(chǎn)生新的狀態(tài)和獎(jiǎng)勵(lì)然后進(jìn)入下一個(gè)決策循環(huán)。只有三者都合理DQN才能真正學(xué)到東西。我見過不少同學(xué)跑不出效果第一反應(yīng)是改網(wǎng)絡(luò)結(jié)構(gòu)和學(xué)習(xí)率其實(shí)問題往往出在狀態(tài)特征不夠或獎(jiǎng)勵(lì)函數(shù)設(shè)計(jì)不當(dāng)上。4. 訓(xùn)練流程與源碼拆解從經(jīng)驗(yàn)回放到目標(biāo)網(wǎng)絡(luò)4.1 網(wǎng)絡(luò)結(jié)構(gòu)與超參數(shù)設(shè)置DQN的核心是用深度神經(jīng)網(wǎng)絡(luò)來逼近Q函數(shù)也就是在當(dāng)前狀態(tài)下每個(gè)動(dòng)作能帶來的未來累計(jì)獎(jiǎng)勵(lì)期望。我的網(wǎng)絡(luò)結(jié)構(gòu)非常簡單三層全連接import torch.nn as nn import torch.nn.functional as F class DQN(nn.Module): def __init__(self, state_dim, action_dim): super().__init__() self.fc1 nn.Linear(state_dim, 128) self.fc2 nn.Linear(128, 128) self.fc3 nn.Linear(128, action_dim) def forward(self, x): x F.relu(self.fc1(x)) x F.relu(self.fc2(x)) return self.fc3(x)信號(hào)燈控制的狀態(tài)維度本就不高一兩百維以內(nèi)沒必要上CNN、Transformer這類復(fù)雜的結(jié)構(gòu)。全連接網(wǎng)絡(luò)加兩到三層隱藏層就完全夠用隱藏層寬度設(shè)為128或256即可參數(shù)太多反而容易過擬合。經(jīng)驗(yàn)里比較關(guān)鍵的超參數(shù)我整理成了表格方便直接抄作業(yè)參數(shù)推薦值說明學(xué)習(xí)率1e-4調(diào)大容易出現(xiàn)Q值發(fā)散折扣因子gamma0.95兼顧短期排隊(duì)和長期效果經(jīng)驗(yàn)池容量20000太大舊樣本占比過高batch size64常用值32偏慢128偏抖目標(biāo)網(wǎng)絡(luò)同步步數(shù)500太頻繁等于沒有目標(biāo)網(wǎng)絡(luò)epsilon初始值1.0早期充分探索epsilon最小值0.05保留一定隨機(jī)性epsilon衰減步數(shù)5000線性衰減4.2 訓(xùn)練主循環(huán)的流程拆解訓(xùn)練主循環(huán)的代碼骨架并不復(fù)雜關(guān)鍵是理解每個(gè)步驟為什么存在。最核心的邏輯如下for episode in range(EPISODES): traci.start(sumoCmd) state get_state() total_reward 0 while traci.simulation.getMinExpectedNumber() 0: action epsilon_greedy(state, epsilon) reward, next_state execute_action(action) replay_buffer.push((state, action, reward, next_state, False)) if len(replay_buffer) BATCH_SIZE: train_step() state next_state total_reward reward traci.close()每個(gè)episode相當(dāng)于一次完整的仿真比如模擬3600秒的早高峰交通。仿真開始后循環(huán)不斷讀取狀態(tài)、選動(dòng)作、執(zhí)行動(dòng)作、攢經(jīng)驗(yàn)、更新網(wǎng)絡(luò)直到所有車輛都離開路網(wǎng)一個(gè)episode結(jié)束。execute_action這個(gè)函數(shù)是關(guān)鍵。當(dāng)智能體選擇保持當(dāng)前相位時(shí)我會(huì)調(diào)用traci.trafficlight.setPhaseDuration(tlsID, currentRemain 10)讓當(dāng)前綠燈相位繼續(xù)延長10秒當(dāng)選擇切換時(shí)就把當(dāng)前相位的剩余時(shí)間設(shè)為1秒讓SUMO自然進(jìn)入黃燈過渡相位再切換到下一相位。這樣做的目的是把相位切換的過渡處理交給SUMO內(nèi)部機(jī)制避免手動(dòng)跳相位導(dǎo)致車輛沖突。4.3 經(jīng)驗(yàn)回放和目標(biāo)網(wǎng)絡(luò)到底解決了什么DQN相比傳統(tǒng)Q-learning最大的改進(jìn)就是引入了經(jīng)驗(yàn)回放和目標(biāo)網(wǎng)絡(luò)這兩個(gè)機(jī)制都是在解決訓(xùn)練穩(wěn)定性的問題。經(jīng)驗(yàn)回放是把智能體探索過的所有(state, action, reward, next_state)存進(jìn)一個(gè)緩沖區(qū)訓(xùn)練時(shí)按batch隨機(jī)采樣。為什么要隨機(jī)采樣因?yàn)閺?qiáng)化學(xué)習(xí)的樣本之間存在高度時(shí)間相關(guān)性——車輛排隊(duì)、放行這個(gè)過程中相鄰幾步的狀態(tài)幾乎差不多如果直接用連續(xù)樣本訓(xùn)練網(wǎng)絡(luò)會(huì)在這段局部模式上來回震蕩學(xué)不到全局規(guī)律。隨機(jī)采樣打破了這個(gè)相關(guān)性讓每次梯度更新盡量來自于多樣的、獨(dú)立分布的經(jīng)驗(yàn)。目標(biāo)網(wǎng)絡(luò)是另一個(gè)穩(wěn)定器。DQN的損失函數(shù)是Loss (r gamma * max_a Q_target(s, a) - Q_online(s, a))^2注意這里計(jì)算目標(biāo)值時(shí)用的是Q_target網(wǎng)絡(luò)而不是正在更新的Q_online網(wǎng)絡(luò)。因?yàn)槿绻猛粋€(gè)網(wǎng)絡(luò)同時(shí)計(jì)算預(yù)測值和目標(biāo)值每一輪更新都會(huì)讓目標(biāo)和預(yù)測一起動(dòng)優(yōu)化過程就會(huì)變成追一個(gè)不斷移動(dòng)的靶子很容易震蕩甚至發(fā)散。目標(biāo)網(wǎng)絡(luò)的做法是定期比如每500步把在線網(wǎng)絡(luò)的參數(shù)復(fù)制過來固定一段時(shí)間讓目標(biāo)值相對穩(wěn)定訓(xùn)練才能收斂。4.4 源碼目錄結(jié)構(gòu)項(xiàng)目源碼的組織方式盡可能清晰核心目錄如下project/ ├── env/ │ ├── config.sumocfg # SUMO仿真配置 │ ├── net.net.xml # 路網(wǎng)文件 │ └── rou.xml # 車流文件 ├── agent/ │ ├── dqn.py # DQN網(wǎng)絡(luò)定義 │ ├── replay_buffer.py # 經(jīng)驗(yàn)回放緩沖區(qū) │ └── train.py # 訓(xùn)練主循環(huán) ├── utils/ │ ├── state_extractor.py # 從TraCI獲取狀態(tài)與獎(jiǎng)勵(lì) │ └── config.py # 超參數(shù)配置 └── evaluate.py # 訓(xùn)練后評(píng)測腳本源碼本身并不復(fù)雜但把它拆成環(huán)境、算法、工具三個(gè)模塊會(huì)讓你后續(xù)擴(kuò)展起來非常舒服。比如想換成PPO算法只需要替換agent目錄里的文件想換成多路口場景只需要在utils里增加一個(gè)狀態(tài)聚合器。5. 實(shí)驗(yàn)結(jié)果對比與參數(shù)調(diào)優(yōu)DQN比固定配時(shí)強(qiáng)在哪5.1 評(píng)價(jià)指標(biāo)與固定配時(shí)基線訓(xùn)練完成后需要用一套客觀指標(biāo)來評(píng)估DQN到底有沒有用。我做了兩輪實(shí)驗(yàn)第一輪把DQN和固定60秒周期配時(shí)做了對比第二輪嘗試了不同的車流強(qiáng)度。評(píng)測用的核心指標(biāo)有三個(gè)平均等待時(shí)間所有車輛在路口前停車的平均總時(shí)長平均排隊(duì)長度每個(gè)決策時(shí)刻各進(jìn)口道排隊(duì)的車輛數(shù)均值路網(wǎng)吞吐量仿真時(shí)段內(nèi)通過路口的車輛總數(shù)。固定配時(shí)的基線直接用SUMO默認(rèn)信號(hào)機(jī)方案不做任何優(yōu)化。評(píng)測時(shí)把DQN的信號(hào)燈控制程序接到同一套路網(wǎng)和車流文件上其他條件完全一致只讓信號(hào)燈決策邏輯不同。5.2 訓(xùn)練曲線怎么解讀DQN訓(xùn)練初期通常會(huì)有一段表現(xiàn)很差的階段。我的經(jīng)驗(yàn)里前20個(gè)episode獎(jiǎng)勵(lì)值甚至明顯低于固定配時(shí)的對照值因?yàn)閑psilon很大智能體在瘋狂探索經(jīng)常做出不合常理的切換動(dòng)作導(dǎo)致路口頻繁出現(xiàn)放行空車道、堵住車流量大的方向這種尷尬局面。這其實(shí)是正?,F(xiàn)象不要慌。隨著訓(xùn)練進(jìn)行epsilon逐漸衰減經(jīng)驗(yàn)池里累積了足夠的有效樣本網(wǎng)絡(luò)開始學(xué)到排隊(duì)長的方向優(yōu)先放行這類規(guī)律獎(jiǎng)勵(lì)曲線會(huì)逐步上升并超過基線。大概訓(xùn)練到150個(gè)episode左右獎(jiǎng)勵(lì)曲線變得平穩(wěn)這時(shí)再跑評(píng)測DQN的每個(gè)指標(biāo)都會(huì)有可觀提升。我在一次典型的對比實(shí)驗(yàn)里得到的數(shù)字大概是在中等流量下DQN比固定配時(shí)降低了約18%的平均等待時(shí)間和22%的平均排隊(duì)長度在輕流量場景下兩者差別不大因?yàn)檐嚤緛砭筒欢略谥亓髁炕蛄髁客蛔儓鼍跋翫QN的優(yōu)勢會(huì)進(jìn)一步拉開有時(shí)等待時(shí)間能降低30%以上。這說明DQN強(qiáng)項(xiàng)在于應(yīng)對不均衡、不穩(wěn)定的車流而不是替代所有配時(shí)方案。5.3 影響收斂的關(guān)鍵參數(shù)訓(xùn)練過程中有幾處參數(shù)是真正決定成敗的我單獨(dú)拿出來說。第一個(gè)是獎(jiǎng)勵(lì)的尺度。如果獎(jiǎng)勵(lì)數(shù)值波動(dòng)太大比如排隊(duì)長度變化從-30到30網(wǎng)絡(luò)會(huì)對梯度方向非常敏感必須把獎(jiǎng)勵(lì)除一個(gè)縮放因子我這里除以了最大排隊(duì)長度讓獎(jiǎng)勵(lì)落在[-1,1]區(qū)間訓(xùn)練穩(wěn)定很多。第二個(gè)是決策間隔。10秒是我最后選定的值但建議你做一次敏感性分析。間隔太短信號(hào)燈頻繁變動(dòng)車流根本來不及響應(yīng)間隔太長智能體在兩次決策之間會(huì)錯(cuò)失很多優(yōu)化機(jī)會(huì)。用不同流量腳本做幾組對照你會(huì)找到最適合自己場景的數(shù)字。第三個(gè)是目標(biāo)網(wǎng)絡(luò)同步步數(shù)。設(shè)成太小比如每100步同步一次目標(biāo)網(wǎng)絡(luò)幾乎等于在線網(wǎng)絡(luò)失去意義設(shè)成太大比如每5000步目標(biāo)值和當(dāng)前預(yù)測偏離過大訓(xùn)練早期容易不穩(wěn)定。500到1000步是一個(gè)經(jīng)驗(yàn)合理區(qū)間。6. 踩坑記錄與個(gè)人心得十幾個(gè)小時(shí)仿真換來的經(jīng)驗(yàn)6.1 相位切換導(dǎo)致的處處紅燈問題我第一次把切換動(dòng)作設(shè)為直接調(diào)用traci.trafficlight.setPhase跳轉(zhuǎn)到下一個(gè)綠燈相位訓(xùn)練出來的效果慘不忍睹路口經(jīng)常出現(xiàn)四個(gè)方向全是紅燈的狀態(tài)車輛全部停擺。原因是SUMO信號(hào)燈內(nèi)部是有相位順序的直接跳轉(zhuǎn)跳過了黃燈過渡階段破壞了信號(hào)燈狀態(tài)機(jī)的內(nèi)部一致性。后來我把切換邏輯改成設(shè)置當(dāng)前相位剩余時(shí)長為極短值1秒讓信號(hào)燈按SUMO自己的規(guī)則進(jìn)入黃燈過渡相位再進(jìn)入下一個(gè)相位問題就消失了。這里的一個(gè)經(jīng)驗(yàn)是不要跟仿真器內(nèi)置的狀態(tài)機(jī)對抗盡量順著它的機(jī)制去做控制否則你會(huì)在很多莫名其妙的仿真異常上浪費(fèi)時(shí)間。6.2 獎(jiǎng)勵(lì)函數(shù)方差過大導(dǎo)致訓(xùn)練崩潰還有一個(gè)坑出現(xiàn)在換用平均等待時(shí)間變化量作為獎(jiǎng)勵(lì)時(shí)。等待時(shí)間受單輛車極端值影響很大偶爾一輛車等了3分鐘這個(gè)變量的變動(dòng)會(huì)讓獎(jiǎng)勵(lì)瞬間產(chǎn)生很大波動(dòng)DQN的損失函數(shù)跟著震蕩訓(xùn)練曲線一路發(fā)散。后來我把獎(jiǎng)勵(lì)改成排隊(duì)長度變化量再乘一個(gè)縮放系數(shù)訓(xùn)練曲線立刻穩(wěn)定下來了。如果你的任務(wù)必須用等待時(shí)間做獎(jiǎng)勵(lì)我建議對單值進(jìn)行截?cái)嗵幚肀热缱畲蟮却龝r(shí)間封頂180秒或者對獎(jiǎng)勵(lì)做clip到[-1,1]總之不要讓極端值主導(dǎo)梯度方向。6.3 如果打算擴(kuò)展到多路口該怎么做單路口跑通之后很多人會(huì)想擴(kuò)展到多路口協(xié)調(diào)控制。我的建議是不要簡單粗暴地把每個(gè)路口都放一個(gè)獨(dú)立DQN那樣多個(gè)智能體在共同環(huán)境中各自優(yōu)化容易出現(xiàn)震蕩。更穩(wěn)妥的方式是先做一個(gè)多路口共享參數(shù)的單智能體方案把所有路口的狀態(tài)拼接成一個(gè)大向量輸入同一個(gè)網(wǎng)絡(luò)輸出所有路口的動(dòng)作這樣訓(xùn)練穩(wěn)定且代碼改動(dòng)不大。再往上的圖神經(jīng)網(wǎng)絡(luò)或多智能體強(qiáng)化學(xué)習(xí)屬于進(jìn)階方向建議先把單路口基本功打扎實(shí)再碰。最后再分享一個(gè)小技巧訓(xùn)練時(shí)每隔幾個(gè)episode就把當(dāng)前模型保存一份同時(shí)跑一次固定配時(shí)基線作為對照。這樣你能在訓(xùn)練過程中實(shí)時(shí)觀察智能體是否真的超過了基線也能在崩潰時(shí)回滾到之前效果最好的模型。我在這個(gè)項(xiàng)目里前前后后跑了十幾個(gè)小時(shí)的仿真大部分時(shí)間都花在調(diào)參和修bug上只有把環(huán)境、建模、訓(xùn)練鏈路都理順了強(qiáng)化學(xué)習(xí)在信號(hào)燈上的效果才真正凸顯出來。本文還有配套的精品資源點(diǎn)擊獲取