Categories
程式開發

Fiber 簡明入門指南


Fiber,讓人工智能的分佈式計算變得簡單。

項目地址:https://github.com/uber/fiber

機器學習的最新進展一直都是通過不斷增加的計算量來實現的。越來越多的算法利用並行性,並依靠分佈式訓練來處理海量數據。無論是對更多數據的需求,還是對更多訓練的需求,都對管理和利用大規模計算資源的軟件提出了巨大的挑戰。

在 Uber 內部,我們開發了 POETGO-ExploreGTN 等算法,這些算法都利用了大量的計算。為了讓未來的大規模計算能夠實現這樣的算法,我們開發了一個名為 Fiber 的新系統,它可以幫助用戶將原本只能在本地進行的計算輕鬆地擴展到數百甚至數千台機器上。

大規模分佈式計算的挑戰

在理想情況下,將在一台機器上運行的應用程序擴展到在一組機器上運行的應用程序,應該與更改命令行參數一樣簡單。然而,在現實世界中,這並不是一件容易的事。

在與許多每天運行大規模分佈式計算作業的人們一起工作時,我們發現,為什麼很難利用分佈式計算,有幾個原因可以解釋:

  • 在筆記本或台式機上本地運行代碼與在生產集群上運行代碼,存在巨大的差距。 你可以讓 MPI 在本地運行,但在計算機集群上運行 MPI 則是一個完全不同的過程。
  • 沒有可用的動態縮放。 如果啟動一個需要大量資源的作業,那麼很可能需要等到所有資源都分配好後才能運行作業。這種等待擴大規模的做法,降低了它的效率。
  • 缺少錯誤處理。 在運行時,某些作業可能會失敗。你可能會陷入非常糟糕的境地,你必須恢復部分結果,或者放棄整個運行。
  • 學習成本高昂。 每個系統都有不同的 API 和編程約定。要使用新系統啟動作業,用戶必須學習一組全新的約定,然後才能啟動作業。

新的 Fiber 平台明確地解決了所有這些問題,有望為更廣泛的用戶群開放無縫的大規模分佈式計算。

Fiber 簡介

Fiber 是一個基於 Python 的現代計算機集群分佈式計算庫。現在,你可以為整個計算機集群進行編程了!而不是為你的台式機或筆記本電腦編程。最初,它是為像 POET 這樣的大規模並行計算項目開發的,現在已經被用於 Uber 內部的類似項目。 Fiber 的主要特點包括:

  • 易於使用。 Fiber 允許你編寫在計算機集群上運行的程序,而無需深入了解計算機集群的細節。
  • 易於學習。 Fiber 提供了與人們熟悉的 Python 標準multiprocessing (多處理)庫相同的 API。如果你知道如何使用多處理,你就可以使用 Fiber 為計算機集群編寫程序了。
  • 快速性能。 Fiber 的通信主幹是建立在 Nanomsg 之上的。 Nanomsg 是一個高性能的異步消息傳遞庫,可以實現快速且可靠的通信。
  • 無需部署。 運行 Fiber 應用程序的方式與在計算機集群上運行普通應用程序的方式相同,然後由 Fiber 處理其餘的事情。
  • 可靠計算。 當你運行一個工作池(Pool)時,Fiber 具有內置的錯誤處理功能。用戶可以專注於編寫實際的應用程序代碼,而不是處理崩潰的工作程序。

此外,在性能至關重要的領域,Fiber 可以與其他專用框架一起使用。例如分佈式 SGD,許多現有框架如 Horovodtouch.distributed,就已經提供了非常好的解決方案。通過使用 Fiber 的 Ring 功能,Fiber 可以與這些平台一起工作,以幫助在計算機集群上設置分佈式訓練作業。

Fiber 簡明入門指南 1

圖 1:Fiber 概述。 該圖顯示了 Fiber 在計算機集群中的工作方式。它啟動許多不同的作業支持進程,並在其中運行不同的 Fiber 組件和用戶進程。 Fiber Master 是管理所有其他進程的主進程。某些進程(如 Ring Node)維持每個成員之間的通信。

Fiber 可以:

(1)幫助從事大規模分佈式計算的用戶減少從構思到在計算集群上實際運行分佈式作業的時間;

(2)保護用戶不受配置和資源分配任務的細節的影響;

(3)加快調試週期;

(4)簡化從本地開發到集群開發的過渡。

架構

Fiber 連接了經典的多處理 API,後端可以在不同的集群管理系統上靈活地選擇。為了實現這種集成,Fiber 被分為三個不同的層:API 層後端層集群層API 層為 Fiber 提供基本的構建塊,如進程、隊列、池和管理器等。它們具有多處理相同的語義,但是可以擴展到分佈式環境中工作。後端層處理在不同集群管理器上創建或終止作業之類的任務。當添加新的後端時,所有其他 Fiber 組件(如隊列、池等)都無需更改。最後,集群層由不同的集群管理器組成。雖然它們不是 Fiber 本身的一部分,但它們可以幫助 Fiber 管理資源並跟踪不同的作業,從而減少了 Fiber 需要跟踪的項目數量。圖 2 對這一總體架構進行了總結。

Fiber 簡明入門指南 2

圖 2:Fiber 架構。

作業支持進程

Fiber 引入了一個新概念,稱為作業支持進程(也稱為 Fiber 進程)。它類似於 Python 的multiprocessing 庫的進程,但更靈活:雖然多處理進程僅在本地計算機上運行,但 Fiber 進程可以在不同的計算機上遠程運行,也可以在同一台計算上本地運行。啟動新的 Fiber 進程時,Fiber 會在當前計算機集群上使用適當的 Fiber 後端創建一個新的作業。

Fiber 簡明入門指南 3

圖 3:作業支持進程。 每個作業支持進程都是在計算機集群上運行的容器化作業。每個作業支持進程也將有自己的 CPU、GPU 和其他類型的資源分配。在容器內運行的代碼是獨立發布(self-contained)的。

Fiber 使用容器封裝當前進程的運行環境,包括所有需要的文件、輸入數據、其他依賴的程序包等,以確保一切都是獨立發布的。所有進程都使用與父進程相同的容器映像啟動,以保證一致的運行環境。因為每個進程都是一個集群作業,所以它的生命週期與集群中的任何作業相同。為了方便用戶,Fiber 被設計為可直接與計算機集群管理器進行交互。因此,與 Spark 或 IPyParallel 不同,Fiber 並不需要在多台機器上進行設置,也不需要由任何其他機制引導。它只需要作為一個普通的 Python pip 包安裝在一台機器上即可。

組件

Fiber 在 Fiber 進程(包括管道、隊列、池和管理器等)之上實現了大多數多處理 API。

Fiber 中的隊列和管道的行為與多處理中的行為相同。不同之處在於,隊列和管道現在由運行在不同機器上的多個進程共享。兩個進程可以對同一管道進行讀寫操作。此外,隊列可以在不同機器上的多個進程之間共享,每個進程可以同時發送或接受來自同一隊列的數據。 Fiber 隊列採用高性能異步消息隊列系統 Nanomsg 實現。

Fiber 簡明入門指南 4

圖 4:Fiber 隊列。 該圖顯示了在三個不同 Fiber 進程之間共享的 Fiber 隊列。一個 Fiber 進程與隊列位於同一台計算機上,另外兩個進程位於另一台機器上。其中一個進程向隊列寫入數據,另外兩個進程從隊列中讀取數據。

Fiber 也支持池。它們允許用戶管理工作進程池。 Fiber 使用作業支持進程來對池進行擴展,因此它可以管理每個池中的數千個(遠程)工作進程。用戶還可以同時創建多個池。

Fiber 簡明入門指南 5

圖 5:Fiber 池。 該圖顯示了一個包含三個工作進程的池。其中兩個位於一台機器上,另一個位於另一台機器上。它們共同處理在主進程中提交給任務隊列的任務,並將結果發送到結果隊列。

管理器和代理對象使 Fiber 能夠支持共享存儲,這對分佈式系統至關重要。通常,這個功能是通過外部存儲器來處理的,比如 Cassandra、Redis 等等,這些存儲器都是通過計算機集群來實現的。取而代之的是,Fiber 為應用程序提供了內置的內存存儲。該接口與多處理的 Manager(管理器)類型相同。

Ring 是多處理 API 的擴展,可以在分佈式計算設置中提供幫助。 Fiber 中的 Ring 代表一組進程,它們以相對平等的方式共同工作。與 Pool 不同,Ring 並沒有主進程和輔助進程的概念。 Ring 內的所有成員都承擔著相同的責任。 Fiber 的 Ring 對一種拓撲進行建模,這種拓撲在進行分佈式 SGD 時在機器學習中非常常見。例如 torch.distributedHorovod 等。一般來說,在計算機集群上啟動這類工作負載是非常具有挑戰性的;Fiber 提供了 Ring 功能來幫助設置這種拓撲。

Fiber 簡明入門指南 6

圖 6:Fiber Ring。 該圖展示了一個具有 4 個節點的 Fiber Ring。 Ring 節點 0 和 Ring 節點 3 運行在同一台機器上,但卻在兩個不同的容器中。 Ring 節點 1 和 Ring 節點 2 都在單獨的計算機上運行。所有這些進程共同運行同一函數的副本,並在運行期間相互通信。

應用

為新應用提供支持

我們在本文闡述瞭如何應用 Fiber 進行大規模分佈式計算的示例。該示例是一個強化學習(Reinforcement Learning,RL)算法的演示。分佈式強化學習的通信模式通常涉及在機器之間發送不同類型的數據:動作、神經網絡參數、梯度、每一步/每一集的觀察、獎勵等等。

Fiber 實現管道和池來傳輸這些數據。在底層,池是普通的 Unix 套接字,為使用 Fiber 的應用程序提供接近線速的通信。現代計算機網絡的帶寬通常高達每秒數百千兆位。通過網絡傳輸少量的數據通常速度較快

此外,如果有許多不同的進程向一個進程發送數據,則進程間通信延遲並不會增加太多,因為數據傳輸是可以並行進行的。這一事實使得 Fiber 的池適合提供許多強化學習算法的基礎,因為模擬器可以在每個池工作進程中運行,且結果可以並行地傳回。

# fiber.BaseManager is a manager that runs remotely
class RemoteEnvManager(fiber.managers.AsyncManager):
    pass
class Env(gym.env):
    # gym env
    pass
RemoteEnvManager.register('Env', Env)
def build_model():
    # create a new policy model
    return model
def update_model(model, observations):
    # update model with observed data
    return new_model
def train():
    model = build_model()
    manager = RemoteEnvManager()
    num_envs = 10
    envs = [manager.Env() for i in range(num_envs)]
    handles = [envs[i].reset() for i in num_envs]
    obs = [handle.get() for handle in handles]
    for i in range(1000):
        actions = model(obs)
        handles = [env.step() for action in actions]
        obs = [handle.get() for handle in handles]
        model = update_model(model, obs)

代碼示例 1: Fiber 實現的簡化強化學習代碼。

啟用現有多處理應用程序

由於在 Python 世界中廣泛使用了多處理,因此,Fiber 為這類應用程序提供了廣泛的機會,因為現在它們只需更改幾行代碼就可以在 Kubernetes 這樣的計算機集群上以分佈式設置中運行!

這裡有一個例子:OpenAI Baselines 是一個非常流行的強化學習庫,它有許多參考算法,如 DQNPPO 等。但它的缺點是只能在一台機器上工作。如果你想大規模訓練 PPO,就必須創建自己的基於 MPI 的設置,並手動設置集群以將所有內容連接起來。

相比之下,有了 Fiber,事情就容易多了。它可以無縫地擴展像 PPO 這樣的強化學習算法,以利用數百個分佈式環境的工作負載。 Fiber 提供了與多處理相同的 API,這是 OpenAI Baseline 用來獲取本地多核 CPU 處理能力的方法。因此,要將 OpenAI Baselines 與 Fiber 一起使用,所需的更改只有一行:

Fiber 簡明入門指南 7

然後,你就可以在 Kubernetes 上運行 OpenAI Baselines 了!我們已經提供了一份完整版指南,講述瞭如何在 Kubernetes 上進行更改和運行 Baselines。

錯誤處理

Fiber 實現了基於池的錯誤處理。創建新池時,還將創建關聯的任務隊列、結果隊列和暫掛(Pending)表。然後將新創建的任務添加到任務隊列中,該任務隊列在主進程和輔助進程之間共享。每個工作進程從任務隊列中獲取一個任務,然後在該任務中運行任務函數。每次從任務隊列中刪除任務時,都會在暫掛錶中添加一個條目。一旦工作進程完成該任務,它就會將其結果放入結果隊列中。然後從暫掛錶中刪除與該任務關聯的條目。

Fiber 簡明入門指南 8

圖 7:Fiber 錯誤處理。 左側是一個普通的 Fiber 池,有 4 個工作進程。在右側,工作進程 3 失敗,因此啟動了一個新的工作進程(工作進程 5),準備將其添加到池中。

如果池工作進程在處理過程中失敗,則作為所有工作進程的進程管理器的父進程將檢測到這一失敗。然後,如果先前失敗的進程有一個掛起的任務,則父池將暫掛錶中的掛起任務放回任務隊列中。接下來,它啟動一個新的工作進程來替換之前失敗的進程,並將新創建的輔助進程綁定到任務隊列和結果隊列。

性能

Fiber 最重要的應用之一是擴展像強化學習這樣等算法和像 ES 這樣的基於人口的方法的計算。強化學習和基於人口的方法通常應用於此類設置中,這類設置需要與模擬器頻繁交互以評估策略和收集經驗,如 ALEGymMujoco 等。從模擬器獲得結果所引入的延遲,嚴重影響了整體訓練性能。在這些測試中,我們評估了 Fiber 的性能,並與其他框架進行了比較。我們還在框架開銷測試中添加了 Ray,以提供一些初步的結果,詳細的結果預計有望在以後添加。

通常有兩種方法可以減少這種延遲。我們可以減少需要傳輸的數據量,或者使不同進程之間的通信通道變得更快。為了實現快速通信,Fiber 使用 Nanomsg 實現管道和池,為使用 Fiber 的應用程序提供快速通信的能力。此外,人們還可以使用 speedus 這樣的庫來選擇更高的性能。

框架開銷

本節中的測試將探討框架給工作負載增加了多少開銷。我們比較了 Fiber、Python 多處理庫、Spark 和 IPyParallel。測試的過程是創建一批總共需要固定時間才能完成的工作負載。每個任務的持續時間從 1 秒到 1 毫秒不等。我們在本地為每個框架運行 5 個工作進程,並調整批大小,以確保每個框架的總完成時間大約為 1 秒(即在 1 毫秒的持續時間內,運行 5000 個任務)。我們的假設是,Fiber 應該具有類似於多功能的性能,因它們都不響應複雜的調度機制。但是,Spark 和 IpyParallel 應該會比 Fiber 慢,因為它們依賴於中間的調度器。

Fiber 簡明入門指南 9

圖 8:測試框架開銷。

當任務持續時間為 100 毫秒或更長時,Fiber 與其他框架幾乎沒有什麼區別,當任務持續時間下降到 10 毫秒或 1 毫秒時,Fiber 比其他框架更接近多處理。

我們使用多處理作為參考,因為它非常輕量級,除了創建新進程和並行運行任務之外,並不會實現任何其他功能。此外,它利用了僅在本地可用的通信機制(如功能內存、Unix 域套接字等),這使得它很難被其他支持跨多台機器的分佈式資源管理的框架所超越,而這些框架不能利用類似的機制。因此,對於可預期的性能而言,它可以作為一個很好的參考。

Fiber 簡明入門指南 10

圖 9:不同框架在完成一批任務的平均時間上的比較,任務持續的時間不同(線性比例)。 最佳完成時間為 1 秒。

與 Fiber 相比,IPyParallel 和 Spark 在每個任務持續時間上都落後很多。當任務持續時間為 1 毫秒時,IPyParallel 耗費的時間幾乎是 Fiber 的 24 倍,Spark 耗費的時間是 Fiber 的 38 倍。這一結果突出地表明了:當任務持續時間較短時,IPyParallel 和Spark 都會帶來相當大的開銷,而且對於強化學習和基於人口的方法(其中使用了模擬器,響應時間為幾毫秒)來說,它們都不如Fiber 合適。我們還發現,在運行持續時間為 1 毫秒的任務時,Ray 耗費的時間大約是 Fiber 的 2.5 倍。

分佈式任務測試

為了探討 Fiber 的可伸縮性和效率,我們在本文中,僅將其與 IPyParallel 進行比較,因為 Spark 比 IPyParallel 慢(如上所示),而且多處理不能擴展到超過一台機器。我們通過運行 50 次 ES 算法(演化策略)迭代來測試兩個框架的可伸縮性和效率,以評估這兩個框架。

在工作負載相同的情況下,我們希望 Fiber 能夠完成得更快,因為它的開銷比 IPyParallel 要少得多,如先前的測試所示。對於 Fiber 和 IPyParallel,人口大小為 2.048,因此,無論工作進程數量多少,總計算量都是固定的。在這兩種方法中也實現了相同的共享噪聲表(noise table)技巧。每 8 個工作進程共享一個噪聲表。這項工作的實驗域是 OpenAI Gym 的 “Bipedal Walker Hardcore” 環境的修改版本。點此處查看關於此修改的描述。

Fiber 簡明入門指南 11

圖 10:ES 的 50 次迭代。在不同工作進程數量下運行 ES 時,Fiber 的可伸縮性優於 IPyParallel。每個工作進程都在單個 CPU 上運行。

我們得到的主要結論是,Fiber 的可伸縮性比 IPyParallel 要好得多,並且完成每個測試的速度都要快得多。隨著工作進程從 32 個增加到 1024 個,Fiber 運行所需的時間逐漸減少。相比之下,相同的時間,IPyParallel 才從 256 個工作進程增加到 512 個工作進程。由於進程之間的通信錯誤,IPyParallel 並未能完成 1024 個工作進程的運行測試。這一失敗摧毀了 IPyParallel 運行大規模並行計算的能力。達到 512 個工作進程後,隨著工作進程數量的增加,我們發現,Fiber 的回報在遞減。這是因為 Amdahl 定律。在這種情況下,主進程處理數據的速度成了瓶頸。

總的來說,在所有測試的工作進程中,Fiber 的性能都超過了 IPyParallel。此外,與 IPyParallel 不同的是,Fiber 還完成了 1024 個工作進程的測試工作。這一結果突出了與 IPyParallel 相比,Fiber 具有更好的可伸縮性,同時它也非常易於使用和設置。

總結

Fiber 是一個新的 Python 分佈式庫,現已開源。它的設計目的是讓用戶在計算機集群上能夠輕鬆地實現大規模計算。本文的實驗突出地表明了,Fiber 實現了許多目標,包括有效利用大量易購計算硬件,動態縮放算法來提高資源使用效率,以及減少在計算機集群上運行複雜算法所需的工程負擔。

我們希望,Fiber 能夠通過使開發方法變得更容易,並在必要的規模上運行以真正看到它的閃光點,從而進一步使解決困難問題的進展成為可能。欲知更多詳情,請查看我們的 Fiber GitHub 倉庫和 Fiber 論文

作者介紹:

Jiale Zhi、Rui Wang、Jeff Clune 與 Kenneth O. Stanley,皆供職於 Uber。

原文鏈接:

https://uber.github.io/fiber/introduction/