今天介紹一種新的GPU多卡計(jì)算的通信優(yōu)化算法——Ring Allreduce。
先來講一下常規(guī)的GPU多卡分布式計(jì)算的原理。
第一點(diǎn):我們知道GPU在矩陣并行化計(jì)算方面非常有優(yōu)勢,所以適合深度學(xué)習(xí)的訓(xùn)練。
第二點(diǎn):使用多個(gè)GPU卡訓(xùn)練同一個(gè)深度學(xué)習(xí)任務(wù)就是分布式計(jì)算。
第三點(diǎn):在分布式計(jì)算過程中,需要對(duì)計(jì)算任務(wù)資源進(jìn)行分片,通常的方式是將完整的網(wǎng)絡(luò)結(jié)構(gòu)放到每一個(gè)GPU上,然后將訓(xùn)練數(shù)據(jù)進(jìn)行分片分發(fā)到不同的GPU卡上。
于是GPU分布式計(jì)算的具體形式就比較清晰了,以上圖為例。GPU1~4卡負(fù)責(zé)網(wǎng)絡(luò)參數(shù)的訓(xùn)練,每個(gè)卡上都布置了相同的深度學(xué)習(xí)網(wǎng)絡(luò),每個(gè)卡都分配到不同的數(shù)據(jù)的minibatch。每張卡訓(xùn)練結(jié)束后將網(wǎng)絡(luò)參數(shù)同步到GPU0,也就是Reducer這張卡上,然后再求參數(shù)變換的平均下發(fā)到每張計(jì)算卡,整個(gè)流程有點(diǎn)像mapreduce的原理。
這里面就涉及到了兩個(gè)問題:
問題一,每一輪的訓(xùn)練迭代都需要所有卡都將數(shù)據(jù)同步完做一次Reduce才算結(jié)束。如果卡數(shù)比較少的情況下,其實(shí)影響不大,但是如果并行的卡很多的時(shí)候,就涉及到計(jì)算快的卡需要去等待計(jì)算慢的卡的情況,造成計(jì)算資源的浪費(fèi)。
問題二,每次迭代所有的計(jì)算GPU卡多需要針對(duì)全部的模型參數(shù)跟Reduce卡進(jìn)行通信,如果參數(shù)的數(shù)據(jù)量大的時(shí)候,那么這種通信開銷也是非常龐大,而且這種開銷會(huì)隨著卡數(shù)的增加而線性增長。
為了解決這樣的問題,就引入了一種通信算法Ring Allreduce,通過將GPU卡的通信模式拼接成一個(gè)環(huán)形,從而減少隨著卡數(shù)增加而帶來的資源消耗,如下圖所示:
將GPU卡以環(huán)形通信之后,每張卡都有一個(gè)左手卡和右手卡,那么具體的模型參數(shù)是如何傳遞的呢,可以看下圖:
因?yàn)槊繌埧ㄉ厦娴木W(wǎng)絡(luò)結(jié)構(gòu)是固定的,所以里面的參數(shù)結(jié)構(gòu)相同。每次通信的過程中,只將參數(shù)send到右手邊的卡,然后從左手邊的卡receive數(shù)據(jù)。經(jīng)過不斷地迭代,就會(huì)實(shí)現(xiàn)整個(gè)參數(shù)的同步,也就是reduce。
形成以下這張圖的樣式:
通過Ring Allreduce的方式,基本上可以實(shí)現(xiàn)當(dāng)GPU并行卡數(shù)的增加,實(shí)現(xiàn)計(jì)算性能的線性增長。