參數伺服器是機器學習訓練一種範式,是為了解決分布式機器學習問題的一個程式設計架構。本文是參數伺服器系列第一篇,介紹ps-lite的總體設計和基礎子產品 Postoffice。
目錄
[源碼解析] 機器學習參數伺服器ps-lite 之(1) ----- PostOffice
0x00 摘要
0x01 概要
1.1 參數伺服器是什麼
1.2 曆史溯源
1.3 論文架構
1.4 ps-lite發展曆程
1.5 ps-lite 系統總體
1.6 基礎子產品
0x02 系統啟動
2.1 如何啟動
2.2 啟動腳本
2.3 示例程式
0x03 Postoffice
3.1 定義
3.2 ID 映射功能
3.2.1 概念
3.2.2 邏輯組的實作
3.2.3 Rank vs node id
3.2.4 Group vs node
3.3 參數表示
3.3.1 KV格式
3.3.2 key-values
3.3.3 Range 操作
3.4 路由功能(keyslice)
3.5 初始化環境
3.6 啟動
3.7 Barrier
3.7.1 同步
3.7.2 初始化
3.7.2.1 等待 BARRIER 消息
3.7.2.2 處理 BARRIER 消息
0xEE 個人資訊
0xFF 參考
參數伺服器是機器學習訓練一種範式,是為了解決分布式機器學習問題的一個程式設計架構,其主要包括伺服器端,用戶端和排程器,與其他範式相比,參數伺服器把模型參數存儲和更新提升為主要元件,并且使用多種方法提高了處理能力。
本文是參數伺服器系列第一篇,介紹ps-lite的總體設計和基礎子產品 Postoffice。
l
如果做一個類比,參數伺服器是機器學習領域的分布式記憶體資料庫,其作用是存儲模型和更新模型。
我們來看看機器學習的幾個步驟,這些步驟不斷循環往複。
準備資料:訓練程序拿到權重 weight 和資料(data + label);
前向計算:訓練程序使用資料進行前向計算,得到 loss = f(weight, data & label);
反向求導:通過對 loss 反向求導,得到導數 grad = b(loss, weight, data & label);
更新權重:weight -= grad * lr;
來到1,進行下一次疊代;
如果使用參數伺服器訓練,我們可以把如上步驟對應如下:
參數下發:參數伺服器服務端 将 weight 發給 每個worker(或者worker自行拉取),worker就是參數伺服器Client端;
并行計算:每個worker 分别完成自己的計算(包括前向計算和反向求導);
grad 收集:參數伺服器服務端 從每個 Worker 處得到 grad,完成歸并(或者worker自行推送);
更新權重:參數伺服器服務端 自行将 grad 應用到 weight 上;
具體如下圖:
手機如下:

是以我們可以推導出參數伺服器之中各個子產品的作用:
伺服器端(Server ):存放機器學習模型參數,接收用戶端發送的梯度,完成歸并,對本地模型參數進行更新。
用戶端(Client 或者 Worker):
從伺服器端擷取目前最新的參數;
使用訓練資料和從最新參數計算得到預測值,根據損失函數來計算關于訓練參數的梯度;
将梯度發送給伺服器端;
排程器(Scheduler):管理伺服器/用戶端節點,完成節點之間資料同步,節點添加/删除等功能。
參數伺服器屬于機器學習訓練的一個範式,具體可以分為三代(目前各大公司應該有自己内部最新實作,可以算為第四代)。
在參數伺服器之前,大部分分布式機器學習算法是通過定期同步來實作的,比如集合通信的all-reduce,或者 map-reduce類系統的reduce步驟。但是定期同步有兩個問題:
同步時期隻能做同步,不能訓練。
straggler問題:由于一些軟硬體的原因,節點的計算能力往往不盡相同。對于疊代問題來說,每一輪結束時算得快的節點都需等待算得慢的節點算完,再進行下一輪疊代。這種等待在節點數增多時将變得尤為明顯,進而拖慢整體的性能。
是以,當async sgd出現之後,就有人提出了參數伺服器。
參數伺服器的概念最早來自于Alex Smola于2010年提出的并行LDA的架構。它通過采用一個分布式的Memcached作為存放共享參數的存儲,這樣就提供了有效的機制用于分布式系統中不同的Worker之間同步模型參數,而每個Worker隻需要儲存他計算時是以來的一小部分參數即可,也避免了所有程序在一個時間點上都停下來同步。但是獨立的kv對帶來了很大的通信開銷,而且服務端端難以程式設計。
第二代由Google的Jeff Dean進一步提出了第一代Google大腦的解決方案:DistBelief。DistBelief将巨大的深度學習模型分布存儲在全局的參數伺服器中,計算節點通過參數伺服器進行資訊傳遞,很好地解決了SGD和L-BFGS算法的分布式訓練問題。
再後來就是李沐所在的DMLC組所設計的參數伺服器。根據論文中所寫,該parameter server屬于第三代參數伺服器,就是提供了更加通用的設計。架構上包括一個Server Group和若幹個Worker Group。
我們首先用沐神論文中的圖來看看系統架構。
解釋一下圖中整體架構中每個子產品:
resource manager:資源配置設定及管理器。參數伺服器使用業界現有的資源管理系統,比如yarn,k8s。
training data:幾十上百億的訓練資料一般存儲在分布式檔案系統上(比如HDFS),resource manager會均勻的配置設定到每個worker上。
參數伺服器的節點被劃分到一個 server group 和多個 worker group。
server group:一次訓練任務中申請的servers,用于模型參數的更新和pull應答。
server group 中的每個 server 隻負責自己分到的部分全局共享參數(server 共同維持一個全局共享參數),一般優化器在此實作。
server 之間互相通信以便進行參數的備份/遷移。
server group 有一個 server manager node,負責維護 server 中繼資料的一緻性,例如節點狀态,參數的配置設定情況。一般不會有什麼邏輯,隻有當有server node加入或退出的時候,為了維持一緻性哈希而做一些調整。
worker group:一次訓練任務中申請的workers,用于前向過程和梯度計算。
每個 worker group 運作一個計算任務,worker group 中的 每個worker 使用部分資料進行訓練。
分成多個group,這樣就可以支援多任務的并行計算。
每個 worker group 有一個 task scheduler,負責向 worker 配置設定任務,并監控他們的運作情況,當有 worker 進入或者退出時,task scheduler 重新配置設定未完成的任務。
worker 之間沒有通信,隻和對應的 server 通信進行參數更新。
在分布式計算梯度時,系統的資料流如下:
圖中每個步驟的作用為:
worker 節點 基于該 batch 内的樣本計算模型權重的梯度;
worker将梯度以key-value的形式推送給server;
server按指定的優化器對模型權重進行梯度更新;
worker從server中拉取最新的模型權重;
上面兩個圖的依據是其原始代碼。ps-lite 是後來的精簡版代碼,是以有些功能在 ps-lite 之中沒有提供。
從網上找到了一些 ps-lite發展曆程,可以看到其演進的思路。
第一代是parameter,針對特定算法(如邏輯回歸和LDA)進行了設計和優化,以滿足規模龐大的工業機器學習任務(數百億個示例和10-100TB資料大小的功能)。
後來嘗試為機器學習算法建構一個開源通用架構。 該項目位于dmlc / parameter_server。
鑒于其他項目的需求不斷增長,建立了ps-lite,它提供了一個幹淨的資料通信API和一個輕量級的實作。 該實作基于dmlc / parameter_server,但為不同的項目重構了作業啟動器,檔案IO和機器學習算法代碼,如dmlc-core和wormhole
根據在開發dmlc / mxnet期間學到的經驗,從v1進一步重構了API和實作。 主要變化包括:
庫依賴性較少;
更靈活的使用者定義回調,便于其他語言綁定;
讓使用者(如mxnet的依賴引擎)管理資料一緻性;
ps-lite 其實是Paramter Server的實作的一個架構,其中參數處理具體相關政策需使用者自己實作。
Parameter Server包含三種角色:Worker,Server,Scheduler。具體關系如下圖:
具體角色功能為:
worker(工作節點):若幹個,執行data pipeline、前向和梯度計算,以key-value的形式将模型權重梯度push到server節點以及從server節點拉取模型最新權重;
server(服務節點):若幹個,負責對worker的push和pull請求做response,存儲,維護和更新模型權重以供各個worker使用(每個server僅維護模型的一部分);
scheduler(控制節點):系統内隻有一個。負責所有節點的心跳監測、節點id配置設定和worker&server間的通信建立,它還可用于将控制信号發送到其他節點并收集其進度。
其中引入scheduler的好處如下:
引入一個 scheduler 子產品,則會形成一個比較經典的三角色分布式系統架構;worker 和 server 的角色和職責不變,而 scheduler 子產品則有比較多的選擇:
隻承擔和下層資源排程系統般若(類似 yarn、mesos)的互動;
額外增加對 worker、server 心跳監控、流程控制的功能;
引入 scheduler 子產品的另一個好處是給實作模型并行留出了空間;
scheduler 子產品不僅有利于實作模型并行訓練範式,還有其他好處:比如通過針對特定模型參數相關性的了解,對參數訓練過程進行細粒度的排程,可以進一步加快模型收斂速度,甚至有機會提升模型名額。
熟悉分布式系統的同學可能會擔心 scheduler 子產品的單點問題,這個通過 raft、zab 等 paxos 協定可以得到比較好的解決。
ps-lite系統中的一些基礎子產品如下:
Environment:一個單例模式的環境變量類,它通過一個 <code>std::unordered_map<std::string, std::string> kvs</code> 維護了一組 kvs 借以儲存所有環境變量名以及值;
PostOffice:一個單例模式的全局管理類,一個 node 在生命期内具有一個PostOffice,依賴它的類成員對Node進行管理;
Van:通信子產品,負責與其他節點的網絡通信和Message的實際收發工作。PostOffice持有一個Van成員;
SimpleApp:KVServer和KVWorker的父類,它提供了簡單的Request, Wait, Response,Process功能;KVServer和KVWorker分别根據自己的使命重寫了這些功能;
Customer:每個SimpleApp對象持有一個Customer類的成員,且Customer需要在PostOffice進行注冊,該類主要負責:
跟蹤由SimpleApp發送出去的消息的回複情況;
維護一個Node的消息隊列,為Node接收消息;
Node :資訊類,存儲了本節點的對應資訊,每個 Node 可以使用 hostname + port 來唯一辨別。
從源碼中的例子可以看出,使用ps-lite 提供的腳本 local.sh 可以啟動整個系統,這裡 test_connection 為編譯好的可執行程式。
具體 local.sh 代碼如下。注意,在shell腳本中,有三個shift,這就讓腳本中始終使用$1。
針對我們的例子,腳本參數對應了就是
DMLC_NUM_SERVER 為 2;
DMLC_NUM_WORKER 為 3;
bin 是 ./test_connection;
可以從腳本中看到,本腳本做了兩件事:
每次執行應用程式之前,都會依據本次執行的角色來對環境變量進行各種設定,除了DMLC_ROLE設定得不同外,其他變量在每個節點上都相同。
在本地運作多個不同角色。這樣 ps-lite 就用多個不同的程序(程式)共同合作完成工作。
首先啟動Scheduler節點。這是要固定好Server和Worker數量,Scheduler節點管理所有節點的位址。
啟動Worker或Server節點。每個節點要知道Scheduler節點的IP、port。啟動時連接配接Scheduler節點,綁定本地端口,并向Scheduler節點注冊自己資訊(報告自己的IP,port)。
Scheduler等待所有Worker節點都注冊後,給其配置設定id,并把節點資訊傳送出去(例如Worker節點要知道Server節點IP和端口,Server節點要知道Worker節點的IP和端口)。此時Scheduler節點已經準備好。
Worker或Server接收到Scheduler傳送的資訊後,建立對應節點的連接配接。此時Worker或Server已經準備好,會正式啟動。
具體如下:
我們依然使用官方例子看看。
ps-lite 使用的是 C++語言,其中 worker, server, scheduler 都使用同一套代碼。這會讓習慣于Java,python的同學非常不适應,大家需要适應一個階段。
針對這個示例程式,起初會讓人疑惑,為什麼每次程式運作,代碼中都會啟動 scheduler,worker,server?其實,從下面注釋就能看出來,具體執行是依據環境變量來決定。如果環境變量設定了本次角色是 server,則不會啟動 scheduler 和 worker。
其中KVServerDefaultHandle是functor,用與處理server收到的來自worker的請求,具體如下:
Postoffice 是一個單例模式的全局管理類,其維護了系統的一個全局資訊,具有如下特點:
三種Node角色都依賴 Postoffice 進行管理,每一個 node 在生命期内具有一個單例 PostOffice。
如我們之前所說,ps-lite的特點是 worker, server, scheduler 都使用同一套代碼,Postoffice也是如此,是以我們最好分開描述。
在 Scheduler側,顧名思義,Postoffice 是郵局,可以認為是一個位址簿,一個調控中心,其記錄了系統(由scheduler,server, worker 集體構成的這個系統)中所有節點的資訊。具體功能如下:
維護了一個Van對象,負責整個網絡的拉起、通信、指令管理如增加節點、移除節點、恢複節點等等;
負責整個叢集基本資訊的管理,比如worker、server數的擷取,管理所有節點的位址,server 端 feature分布的擷取,worker/server Rank與node id的互轉,節點角色身份等等;
負責 Barrier 功能;
在 Server / Worker 端,負責:
配置目前node的一些資訊,例如目前node是哪種類型(server,worker),nodeid是啥,以及worker/server 的rank 到 node id的轉換。
路由功能:負責 key 與 server 的對應關系。
Barrier 功能;
請注意:這些代碼都是在 Postoffice 類内,沒有按照角色分開成多個子產品。
類 UML 圖如下:
下面我們隻給出關鍵變量和成員函數說明,因為每個節點都包含一個 PostOffice,是以 PostOffice 的資料結構中包括了各種節點所需要的變量,會顯得比較繁雜。
主要變量作用如下:
van_ :底層通訊對象;
customers_ :本節點目前有哪些 customer;
node_ids_ :node id 映射表;
server_key_ranges_ :Server key 區間範圍對象
is_worker_, is_server_, is_scheduler_ :标注了本節點類型;
heartbeats_ :節點心跳對象;
barrier_done_ : Barrier 同步變量;
主要函數作用如下:
InitEnvironment :初始化環境變量,建立 van 對象;
Start :建立通信初始化;
Finalize :節點阻塞退出;
Manage :退出 barrier 阻塞狀态;
Barrier :進入 barrier 阻塞狀态;
UpdateHeartbeat :
GetDeadNodes :根據 heartbeats_ 擷取已經 dead 的節點;
首先我們介紹下 node id 映射功能,就是如何在邏輯節點和實體節點之間做映射,如何把實體節點劃分成各個邏輯組,如何用簡便的方法做到給組内實體節點統一發消息。
1,2,4分别辨別Scheduler, ServerGroup, WorkerGroup。
SingleWorker:rank * 2 + 9;SingleServer:rank * 2 + 8。
任意一組節點都可以用單個id辨別,等于所有id之和。
Rank 是一個邏輯概念,是每一個節點(scheduler,work,server)内部的唯一邏輯标示。
Node id 是實體節點的唯一辨別,可以和一個 host + port 的二進制組唯一對應。
Node Group 是一個邏輯概念,每一個 group 可以包含多個 node id。ps-lite 一共有三組 group : scheduler 組,server 組,worker 組。
Node group id 是 是節點組的唯一标示。
ps-lite 使用 1,2,4 這三個數字分别辨別 Scheduler,ServerGroup,WorkerGroup。每一個數字都代表着一組節點,等于所有該類型節點 id 之和。比如 2 就代表server 組,就是所有 server node 的組合。
為什麼選擇這三個數字?因為在二進制下這三個數值分别是 "001, 010, 100",這樣如果想給多個 group 發消息,直接把 幾個 node group id 做 或操作 就行。
即 1-7 内任意一個數字都代表的是Scheduler / ServerGroup / WorkerGroup的某一種組合。
如果想把某一個請求發送給所有的 worker node,把請求目标節點 id 設定為 4 即可。
假設某一個 worker 希望向所有的 server 節點 和 scheduler 節點同時發送請求,則隻要把請求目标節點的 id 設定為 3 即可,因為 3 = 2 + 1 = kServerGroup + kScheduler。
如果想給所有節點發送消息,則設定為 7 即可。
三個邏輯組的定義如下:
node id 是實體節點的唯一标示,rank 是每一個邏輯概念(scheduler,work,server)内部的唯一标示。這兩個标示由一個算法來确定。
如下面代碼所示,如果配置了 3 個worker,則 worker 的 rank 從 0 ~ 2,那麼這幾個 worker 實際對應的 實體 node ID 就會使用 WorkerRankToID 來計算出來。
具體計算規則如下:
這樣我們可以知道,1-7 的id表示的是node group,單個節點的id 就從 8 開始。
而且這個算法保證server id為偶數,node id為奇數。
SingleWorker:rank * 2 + 9;
SingleServer:rank * 2 + 8;
因為有時請求要發送給多個節點,是以ps-lite用了一個 map 來存儲每個 node group / single node 對應的實際的node節點集合,即 确定每個id值對應的節點id集。
如何使用這個node_ids_?我們還是需要看之前的代碼:
我們回憶一下之前的節點資訊:
1 ~ 7 的 id 表示的是 node group;
後續的 id(8,9,10,11 ...)表示單個的 node。其中雙數 8,10,12... 表示 worker 0, worker 1, worker 2,... 即(2n + 8),9,11,13,...,表示 server 0, server 1,server 2,...,即(2n + 9);
是以,為了實作 “設定 1-7 内任意一個數字 可以發送給其對應的 所有node” 這個功能,對于每一個新節點,需要将其對應多個id(node,node group)上,這些id組就是本節點可以與之通訊的節點。例如對于 worker 2 來說,其 node id 是 2 * 2 + 8 = 12,是以需要将它與
12(本身)
4(kWorkerGroup)li
4+1(kWorkerGroup + kScheduler)
4+2(kWorkerGroup + kServerGroup)
4+1+2,(kWorkerGroup + kServerGroup + kScheduler )
這 5 個id 相對應,即需要在 node_ids_ 這個映射表中對應的 4, 4 + 1, 4 + 2, 4 +1 + 2, 12 這五個 item 之中添加。就是上面代碼中的内部 for 循環條件。即,node_ids_ [4], node_ids_ [5],node_ids_ [6],node_ids_ [7] ,node_ids_ [12] 之中,都需要把 12 添加到 vector 最後。
workers 跟 servers 之間通過 push 跟 pull 來通信。worker 通過 push 将計算好的梯度發送到server,然後通過 pull 從server更新參數。
parameter server 中,參數都是可以被表示成(key, value)的集合,比如一個最小化損失函數的問題,key就是feature ID,而value就是它的權值。對于稀疏參數來說,value不存在的key,就可以認為value是0。
把參數表示成 k-v, 形式更自然,易于了解和程式設計實作。
分布式算法有兩個額外成本:資料通信成本,負載均衡不理想和機器性能差異導緻的同步成本。
對于高維機器學習訓練來說,因為高頻特征更新極為頻繁,所會導緻網絡壓力極大。如果每一個參數都設一個key并且按key更新,那麼會使得通信變得更加頻繁低效,為了抹平這個問題,就需要有折衷和平衡,即,
利用機器學習算法的特性,給每個key對應的value賦予一個向量或者矩陣,這樣就可以一次性傳遞多個參數,權衡了融合與同步的成本。
做這樣的操作的前提是假設參數是有順序的。缺點是在對于稀疏模型來說,總會在向量或者矩陣裡會有參數為0,這在單個參數狀态下是不用存的,是以,造成了資料的備援。
但這樣做有兩點好處:
降低網絡通信
使得向量層面的操作變得可行,進而很多線性庫的優化特性可以利用的上,比如BLAS、LAPACK、ATLAS等。
為了提高計算性能和帶寬效率,參數伺服器也會采用批次更新的辦法,來減輕高頻 key 的壓力。比如把minibatch之中高頻key合并成一個minibatch進行更新。
ps-lite 允許使用者使用 Range Push 跟 Range Pull 操作。
路由功能指的就是:Worker 在做 Push/Pull 時候,如何知道把消息發送給哪些 Servers。
我們知道,ps-lite 是多 Server 架構,一個很重要的問題是如何分布多個參數。比如給定一個參數的鍵,如何确定其存儲在哪一台 Server 上。是以必然有一個路由邏輯用來确立 key與server的對應關系。
PS Lite 将路由邏輯放置在 Worker 端,采用範圍劃分的政策,即每一個 Server 有自己固定負責的鍵的範圍。這個範圍是在 Worker 啟動的時候确定的。細節如下:
根據編譯 PS Lite 時是否設定的宏 USE_KEY32 來決定參數的鍵的資料類型,要麼是 32 位無符号整數,要麼是 64 位的。
根據鍵的資料類型,确定其值域的上界。例如 uint32_t 的上界是 4294967295。
根據鍵域的上界和啟動時擷取的 Server 數量(即環境變量 DMLC_NUM_SERVER 的值)來劃分範圍。
每個server維護的key範圍按 uint32_t / uint64_t 從小到大等距分區間。給定上界 MAX 和 Server 數量 N,第 i 個 Server 負責的範圍是 <code>[MAX/N*i, MAX/N*(i+1))</code>。
對key的hash值構造有一定的要求以避免server間的key傾斜(如32位、16位、8位、4位、2位高低位對調)。
Worker push和pull的key按升序排列進行slice以實作zero copy。
需要注意的是,在不能剛好整除的情況下,鍵域上界的一小段被丢棄了。
具體實作如下:
首先,ps-lite的key隻支援int類型。
其次,将int範圍均分即可
從之前分析中我們可以知道,ps-lite 是通過環境變量來控制具體節點。
具體某個節點屬于哪一種取決于啟動節點之前設定了哪些環境變量以及其數值。
環境變量包括:節點角色,worker&server個數、ip、port等。
InitEnvironment 函數就是建立了 Van,得到了 worker 和 server 的數量,得到了本節點的類型。
主要就是:
調用 InitEnvironment() 來初始化環境,建立 VAN 對象;
node_ids_初始化。根據worker和server節點個數,确定每個id值對應的節點id集。具體邏輯我們前面有分析。
啟動 van,這裡會進行各種互動(有一個 ADD_NODE 同步等待,與後面的 barrier 等待不同);
如果是第一次調用PostOffice::Start,初始化start_time_成員;
如果設定了需要 barrier,則調用 Barrier 來進行 等待/處理 最終系統統一啟動。即 所有Node準備并向Scheduler發送要求同步的Message,進行第一次同步;
具體代碼如下:
總的來講,schedular節點通過計數的方式實作各個節點的同步。具體來說就是:
每個節點在自己指定的指令運作完後會向schedular節點發送一個Control::BARRIER指令的請求并自己阻塞直到收到schedular對應的傳回後才解除阻塞;
schedular節點收到請求後則會在本地計數,看收到的請求數是否和barrier_group的數量是否相等,相等則表示每個機器都運作完指定的指令了,此時schedular節點會向barrier_group的每個機器發送一個傳回的資訊,并解除其阻塞。
ps-lite 使用 Barrier 來控制系統的初始化,就是大家都準備好了再一起前進。這是一個可選項。具體如下:
Scheduler等待所有的worker和server發送BARRIER資訊;
在完成ADD_NODE後,各個節點會進入指定 group 的Barrier阻塞同步機制(發送 BARRIER 給 Scheduler),以保證上述過程每個節點都已經完成;
所有節點(worker和server,包括scheduler) 等待scheduler收到所有節點 BARRIER 資訊後的應答;
最終所有節點收到scheduler 應答的Barrier message後退出阻塞狀态;
Node會調用 Barrier 函數 告知Scheduler,随即自己進入等待狀态。
注意,調用時候是
這就是說,等待所有的 group,即 scheduler 節點也要給自己發送消息。
處理等待的動作在 Van 類之中,我們提前放出來。
具體ProcessBarrierCommand邏輯如下:
如果 msg->meta.request 為true,說明是 scheduler 收到消息進行處理。
Scheduler會對Barrier請求進行增加計數。
當 Scheduler 收到最後一個請求時(計數等于此group節點總數),則将計數清零,發送結束Barrier的指令。這時候 meta.request 設定為 false;
向此group所有節點發送<code>request==false</code>的<code>BARRIER</code>消息。
如果 msg->meta.request 為 false,說明是收到消息這個 respones,可以解除barrier了,于是進行處理,調用 Manage 函數 。
Manage 函數 将app_id對應的所有costomer的<code>barrier_done_</code>置為true,然後通知所有等待條件變量<code>barrier_cond_.notify_all()</code>。
Manage 函數就是解除了 barrier。
具體示意如下:
至此,Postoffice的分析我們初步完成,其餘功能我們将會結合 Van 和 Customer 在後續文章中分析。
★★★★★★關于生活和技術的思考★★★★★★
微信公衆賬号:羅西的思考
如果您想及時得到個人撰寫文章的消息推送,或者想看看個人推薦的技術資料,敬請關注。
MXNet設計和實作簡介
史上最全面的ps-lite了解
ps-lite 深度源碼解讀
ps-lite源碼剖析
基于Parameter Server的可擴充分布式機器學習架構
ps-lite代碼解析
ps-lite代碼筆記
分布式TensorFlow入門教程
分布式機器學習(上)-并行計算與機器學習
分布式機器學習(中)-并行計算與機器學習
分布式機器學習(下)-聯邦學習
ps-lite 源代碼分析
Talk - Scaling Distributed Machine Learning with System and Algorithm Co-design 筆記