快速上手微軟 “羣策 MARO” 平臺,打造簡易的共享單車場景

作者 | 王金予、石文磊

來源 | 微軟研究院AI頭條(ID:MSRAsia)

編者按:2020年9月,微軟亞洲研究院發佈了多智能體資源優化平臺“羣策 MARO”,並在 Github 上開源。近日,MARO 更新了0.2版本,新版本進一步完善了多項功能,提升了使用體驗。作爲一個面向多行業橫截面上的全鏈條資源優化 AI 解決方案,MARO 平臺可支持多種預設定的資源優化任務,例如航運網絡中的空集裝箱調度問題、共享單車服務中的單車調度問題、雲平臺上的虛擬機分配問題等,同時也支持用戶利用核心組件,快速地定義高效的場景。不僅如此,MARO 還提供了全棧的強化學習支持,包含常用算法以及相關的分佈式訓練。本文將通過構造一個簡單的共享單車場景,來幫助大家理解 MARO 的核心功能和邏輯,以及其與環境交互所實現的優化策略。

*本文僅介紹場景設計邏輯和與環境進行交互的關鍵代碼,完整的 Notebook 代碼可以參考 Notebook (https://github.com/microsoft/maro/blob/master/notebooks/articles/simple_bike_repositioning.ipynb)。

共享單車是大家非常熟悉的出行方式,既健康又低碳環保,但是經常使用共享單車的小夥伴們肯定遇到過這樣的苦惱:早上稍微晚些出門,小區門口就空空蕩蕩,沒有一輛可用的單車,而在地鐵站入口則會發現大量的單車幾乎把道路堵得水泄不通;等下班從公司去地鐵站的時候,同樣的狀況再次上演。這種單車分佈的不均衡事實上是由出行需求的不均衡所導致的。如果任由其發展會顯著影響單車的使用效率以及用戶體驗。

想要打破這種不平衡,必須通過主動調度單車資源的方式來解決,即在合適的時間把單車從需求小的地方調度到需求大的地方。那麼,如何設計有效的單車平衡調度策略來解決單車需求的不平衡呢?接下來讓我們將從一個簡易的問題出發,看看如何使用“羣策 MARO”來構造模擬場景,並基於簡單規則進行調度嘗試。

問題設定

爲了簡化問題,可以考慮只有四個單車停放站點的情況,這裏用 {s_i∣i=0,1,2,3} 來表示單車站點。如圖1左側所示,s_i 和 s_j 之間的有向邊代表會有從 s_i 到 s_j 的單車需求,其具體的需求量是由一個時間 t 上的函數 F_ij (t) 決定的。不同站點之間的需求明顯是不一樣的,若模擬這一點則要求設計多種需求函數,圖1右側即爲這些需求函數的曲線示例。

圖1:共享單車站點間的拓撲關係與需求

可以發現,對於 s_0 和 s_2,F_02 (t) 和 F_20 (t) 呈現對稱的週期性轉換,而其他站點對之間的需求函數相對穩定。具體而言,對於任意一個時間點,F_02 (t) 和 F_20 (t) 中僅有一個值可以大於0,即 s_0 和 s_2 之間僅有一個方向的單車需求數量大於0,在需求函數週期的前半段,F_02 (t) 會從0逐漸增長到峯值再降回0,而在需求函數週期的後半段,則換做 F_20 (t) 從0逐漸增長到峯值再降回0。對於 s_1 和 s_3 來說,F_13 (t) 和 F_13 (t) 基本相當,僅在極少數時刻會存在小的數值差異。而 F_01 (t) 和 F_32 (t) 則表現爲一個常數函數,取值固定且相等。

在這樣的單車需求設定下,想要最大化這個單車世界內的單車需求滿足率,s_0 和 s_2 需要依據給定時間段內其供需角色的不同,將富餘的單車從沒有單車需求的站點調度到單車需求多的站點(如:t=15時,將單車從 s_2 調度到 s_0,而 t=50 時,將單車從 s_0 調度到 s_2)。同時,由於 s_1 和 s_3 之間的供需基本守恆,在無法準確預見未來單車需求量的情況下,無需額外的單車調度。對於 F_01 (t) 和 F_32 (t) 這兩個需求函數所帶來的單車穩定地被從行程起始站點運往目的站點的現象,可以規律地將單車從行程目的站點運往起始站點。

單車場景在MARO中的運行邏輯

爲了方便用戶自己定義場景,微軟亞洲研究院的研究員們在 MARO 中採取了模擬器(Simulator)、業務引擎(Business Engine)和智能體(Agents)分離的設計。

概括來講:

  • 模擬器是用來承載整個場景的運行容器,它銜接着業務引擎和智能體。其中有兩個關鍵模塊:數據模型(Data Model)和事件緩存(Event Buffer),前者用於高效地存儲整個環境的結構化數據,後者主要用來處理場景的業務事件以及智能體的決策事件,進而推動環境運行;

  • 業務引擎維護的是整個場景的業務邏輯,包括修改環境數據、觸發事件、執行智能體的動作等等,每個場景需要有自己的業務引擎,它也是自定義場景中主要需要實現的模塊;

  • 智能體則主要負責對動作事件響應,並返回合適的動作。

在這個簡易的單車調度場景中,可以把主要業務邏輯歸爲兩類:由單車需求觸發的單車消耗與回收,以及由此帶來的單車移動;爲了優化單車使用率,提升單車需求滿足度而主動驅動的單車調度。其中,單車需求的處理邏輯如圖2所示:在每個時間點上,業務引擎會按照預先設定的單車需求曲線生成特定的單車使用請求,當站點存在空閒單車能滿足該請求時,單車將被消耗(模擬器將記錄由此引發的狀態變化)並記錄爲一次訂單滿足(fulfillment)。在特定時間之後該單車會到達請求的目的地站點,成爲目的地站點的可用單車(模擬器將再次對各站點狀態進行更新);若請求產生時站點空閒單車不足,對應的單車請求將得不到滿足,會被記錄爲一次請求未滿足(shortage)。

圖2:單車需求的處理邏輯

圖3則展示了單車調度邏輯:在每個時間點上,業務引擎會檢查各個站點的剩餘單車數量,當余車不足時,業務引擎會生成並拋出一個單車調度請求事件。模擬器接收到這一請求事件後會將此事件轉發給決策方,即智能體(Agent)。智能體會依據當前系統的狀態,按照自己的策略給出執行決策——(a,b,n) 從 s_a 調度 n 輛單車運往 s_b。被調度的單車會在特定時間後到達目的地站點,成爲目的地站點的可用單車,在這一過程中模擬器負責對相關站點的狀態進行更新。

圖3:單車調度邏輯

上述是整個場景的運行邏輯,也就是業務引擎需要實現的內容,具體代碼可參考 Notebook(https://github.com/microsoft/maro/blob/master/notebooks/articles/simple_bike_repositioning.ipynb)中 SimpleCitibikeBusinessEngine 類。

基於規則的調度算法

在完成業務引擎的實現之後,下面就可以利用 MARO 提供的接口,實例化一個環境示例,並與之交互。具體過程如下圖代碼所示:

首先是創建環境,參數分別爲環境執行總時間和業務邏輯引擎。環境在執行過程中的所有狀態信息都存儲在 snapshot_list 中。其次是創建策略對象,策略對象可以是任意類的實例,只需在環境需要執行動作時提供決策即可。接下來是與環境的交互,這裏用一個 while 循環實現,即執行環境的 step 操作直至環境結束。當調用 step 函數時,環境會持續推進業務邏輯,直到需要執行動作。此時,需要調用策略對象獲得動作。該動作是一個三元組,包括調度源站點 A、調度目的地站點 B 和調度數量 x,描述了從站點 A 到站點 B 運送 x 輛車的調度操作。此外,動作爲 None 代表不做任何調度。

接下來將實現三種調度策略,分別是不做任何調度(no action)、基於規則的調度(rule based)和基於統計數據的調度(statistics based)。圖4展示了單車總需求和這三種策略下的各個時刻單車缺口數量曲線。

圖4:各時刻單車總需求和三種策略下單車缺口數量曲線

在策略的具體實現上,用戶可以定義一個類,並重載__call__(event) 函數,在該函數中根據環境的信息處理當前事件。首先可以看一下如果不做調度會產生多少缺箱。這個策略非常簡單,只需要對任何的事件返回 None 值即可。

整個環境跑下來總的單車需求爲2096,單車需求缺口爲945。圖4展示了每個時間點的單車缺口曲線。

下面再通過對環境內部的邏輯觀察,給出一個合理的基線。爲了敘述方便,定義第 i 個站點爲 s_i。通過觀察可以發現,如果把系統分爲左右兩個子集,即 {s_0,s_2 } 和 {s_1,s_3 },從左子集指向右子集的需求(由函數 F_01 定義)和從右子集指向左子集的需求(由函數 F_32 定義)剛好抵消。這意味着,如果兩個子集各自能夠提供足夠多的單車滿足其內部需求,那麼只需要分別在兩個子集內部調度即可。

首先考慮右子集 {s_1,s_3 }。由於外界的單車總是從 s_1 流入,並從 s_3 流出,因此只需要將所有從 s_1 流入的單車都發往 s_3 即可。爲了簡單起見,在每次調度時保留固定數量的單車而將剩下所有單車發給 s_3。設保留數量爲常數 R_13。

對於左子集 {s_0,s_2 } 而言,情況要稍微複雜一些。由於左子集內部的需求函數 F_02 和 F_20 是以 20π 爲週期的函數,因此可以以週期爲單位進行分析。在前半週期,左子集內部只有從 s_0 指向 s_2 的需求,且外界的單車總是從 s_2 流入,並從 s_0 流出。s_0 只出不進,而 s_2 只進不出。因此在這個期間,將所有 s_2 的單車都運往 s_0 即可。在後半週期,左子集內部只有從 s_2 指向 s_0 的需求。由於 s_0 還需要滿足 F_01 的需求,所以 s_0 需要保留一部分單車,並將剩餘的全部運給 s_2。同樣,設此保留數量爲 R_02。

當該算法在系統中存在單車數量爲0的站點時觸發。算法需要從環境中獲取當前每個站點的單車數量,再通過上述規則返回調度結果。調度結果以三元組 (s_i,s_j,x) 的形式給出,表示從站點 s_i 運輸 x 個單車到站點 s_j。

整個算法如下圖所示:

在代碼中設置:R_13=5,R_02=5。用戶可以通過 event 的 station_index 成員變量獲取當前需要單車的站點,還可以通過環境的 tick 變量獲得當前時刻,通過 snapshot_list 獲得各個站點的狀態。

這裏簡單介紹一下 snapshot_list 的接口:通過鍵值 “station” 可以獲得每個站點在歷史上每個 tick 的屬性值,屬性值由三個部分索引組成,按順序分別爲時間 tick、站點下標 index 和屬性名,若其中任一索引省略,那麼接口將返回該索引的所有值。例如,上述程序中 [self.env.tick::”bikes”] 代表獲得在環境當前 tick 所有站點的單車數量。

執行該策略最後總的單車短缺數量爲107,各時刻的缺口數量可以參見圖4。

在實際場景中我們並不能實時瞭解真實的用車需求,用車需求時時刻刻都在發生變化,無法通過固定的策略獲得很好的調度效果。因此可以採用一種自適應的方法,該方法的思想也很簡單:如果人在不清楚用車需求的情況下做決策,最直接的辦法就是,先讓系統運行一段時間,觀察哪個站點缺車就往哪個站點運輸。這種方法雖然存在延遲響應的問題,但執行起來往往簡單而有效。

具體而言,研究員們統計了每個站點缺車數量的指數衰減累積量,並以此衡量站點的缺車程度。每次系統發現缺車點,並觸發調度動作,就從最不缺車的站點運單車過去。此外,由於系統可能在同一個 tick 多次觸發調度,爲了防止一個站點多次被選擇,所以每次選擇都會降低該站點的優先級。具體代碼可參考 Notebook 內容。其中的超參可以通過簡單的網格搜索進行優化,找到最優的超參組合:{decay_factor=0.8,weight=0.8},此時單車缺口爲278。各時刻的缺口數量可參見圖4,詳細代碼請參見 Notebook。

結語

本文通過自定義一個簡單的共享單車場景介紹了 MARO 的核心模塊、運行邏輯以及與智能體的交互方式。除了方便使用者自定義場景之外,MARO 的另一個核心優勢是擁有很多基於真實數據與業務邏輯打造的預定義場景,例如基於紐約自行車數據的 Citi Bike 場景[1]、基於真實海洋拓撲的空集裝箱調度、使用真實 Azure 數據的虛擬機分配問題[2]。基於 MARO,研究員們也已經在集裝箱調度問題上做了一系列的研究工作[3,4]。

除了場景之外,MARO 還擁有易用的多智能體框架,高效的分佈式訓練算法和預定義的主流強化學習算法工具包,這些部分會在後續的文章中向大家介紹,幫助大家使用 MARO,提高開發和訓練效率,助力強化學習在資源優化領域的應用。

相關鏈接:

MARO 0.2 版本具體更新歷史:

https://github.com/microsoft/maro/pull/239 

MARO 中預設定的資源優化任務:

  • 航運網絡中的空集裝箱調度問題:

https://maro.readthedocs.io/en/latest/scenarios/container_inventory_management.html

  • 共享單車服務中的單車調度問題:

https://maro.readthedocs.io/en/latest/scenarios/citi_bike.html

  • 雲平臺上的虛擬機分配問題:

https://maro.readthedocs.io/en/latest/scenarios/vm_scheduling.html

參考資料:

[1] Citi Bike 數據集:https://www.citibikenyc.com/system-data

[2] Azure數據集:https://github.com/Azure/AzurePublicDataset

[3] Li X, Zhang J, Bian J, et al. A cooperative multi-agent reinforcement learning framework for resource balancing in complex logistics network. AAMAS, 2019.

[4] Shi W, Wei X, Zhang J, et al. Cooperative Policy Learning with Pre-trained Heterogeneous Observation Representations. AAMAS, 2021.

更多精彩推薦
☞打造 AI 語音新標杆,英特爾與騰訊雲小微創新共贏
☞三種方法,用Python輕鬆提取PDF中的全部圖片
☞這25條極簡Python代碼,你還不知道

☞告別手敲 SQL ?GPT-3 自動幫你寫
點分享點收藏點點贊點在看
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章