日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

参数服务器训练基本理论

發(fā)布時(shí)間:2023/11/28 生活经验 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 参数服务器训练基本理论 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

參數(shù)服務(wù)器訓(xùn)練基本理論
參數(shù)服務(wù)器訓(xùn)練是分布式訓(xùn)練領(lǐng)域普遍采用的編程架構(gòu),主要解決以下兩類問題:
? 模型參數(shù)過大:單機(jī)內(nèi)存空間不足,需要采用分布式存儲(chǔ)。
? 訓(xùn)練數(shù)據(jù)過多:單機(jī)訓(xùn)練太慢,需要加大訓(xùn)練節(jié)點(diǎn),來提高并發(fā)訓(xùn)練速度。
如圖所示,參數(shù)服務(wù)器主要包含Server和Worker兩個(gè)部分,其中Server負(fù)責(zé)參數(shù)的存儲(chǔ)和更新,而Worker負(fù)責(zé)訓(xùn)練。簡單來說,參數(shù)服務(wù)器訓(xùn)練的基本思路:當(dāng)訓(xùn)練數(shù)據(jù)過多,一個(gè)Worker訓(xùn)練太慢時(shí),可以引入多個(gè)Worker同時(shí)訓(xùn)練,這時(shí)Worker之間需要同步模型參數(shù)。直觀想法是,引入一個(gè)Server,Server充當(dāng)Worker間參數(shù)交換的媒介。當(dāng)模型參數(shù)過大,以至于單機(jī)存儲(chǔ)空間不足時(shí),或Worker過多導(dǎo)致一個(gè)Server是瓶頸時(shí),就需要引入多個(gè)Server。

參數(shù)服務(wù)器訓(xùn)練的具體流程如下:
? 將訓(xùn)練數(shù)據(jù)均勻的分配給不同的Worker。
? 將模型參數(shù)分片,存儲(chǔ)在不同的Server上。
? Worker端:讀取一個(gè)minibatch訓(xùn)練數(shù)據(jù),從Server端拉取最新的參數(shù),計(jì)算梯度,并根據(jù)分片上傳給不同的Server。
? Server端:接收Worker端上傳的梯度,根據(jù)優(yōu)化算法更新參數(shù)。根據(jù)Server端每次參數(shù)更新是否需要等待所有Worker端的梯度,分為同步訓(xùn)練和異步訓(xùn)練兩種機(jī)制。
飛槳paddle的參數(shù)服務(wù)器框架,也是基于這種經(jīng)典的參數(shù)服務(wù)器模式進(jìn)行設(shè)計(jì)和開發(fā)的,在這基礎(chǔ)上進(jìn)行了SGD(Stochastic Gradient Descent)算法的創(chuàng)新(GEO-SGD)。目前飛槳paddle支持3種模式,分別是同步訓(xùn)練模式、異步訓(xùn)練模式、GEO異步訓(xùn)練模式,三者之間的差異如下圖所示。
當(dāng)前經(jīng)過大量的實(shí)驗(yàn)驗(yàn)證,最佳的方案是每臺(tái)機(jī)器上啟動(dòng)Server和Worker兩個(gè)進(jìn)程,而一個(gè)Worker進(jìn)程中,可以包含多個(gè)用于訓(xùn)練的線程。

同步訓(xùn)練
Worker在訓(xùn)練一個(gè)batch的數(shù)據(jù)后,會(huì)合并所有線程的梯度發(fā)給Server, Server在收到所有節(jié)點(diǎn)的梯度后,會(huì)統(tǒng)一進(jìn)行梯度合并及參數(shù)更新。同步訓(xùn)練的優(yōu)勢(shì)在于Loss可以比較穩(wěn)定的下降,缺點(diǎn)是整個(gè)訓(xùn)練速度較慢,這是典型的木桶原理,速度的快慢取決于最慢的那個(gè)線程的訓(xùn)練計(jì)算時(shí)間,在訓(xùn)練較為復(fù)雜的模型時(shí),即模型訓(xùn)練過程中神經(jīng)網(wǎng)絡(luò)訓(xùn)練耗時(shí),遠(yuǎn)大于節(jié)點(diǎn)間通信耗時(shí)的場(chǎng)景下,推薦使用同步訓(xùn)練模式。
異步訓(xùn)練
在訓(xùn)練一個(gè)batch的數(shù)據(jù)后,Worker的每個(gè)線程會(huì)發(fā)送梯度給Server。而Server不會(huì)等待接收所有節(jié)點(diǎn)的梯度,而是直接基于已收到的梯度進(jìn)行參數(shù)更新。異步訓(xùn)練去除了訓(xùn)練過程中的等待機(jī)制,訓(xùn)練速度得到了極大的提升,但是缺點(diǎn)也很明顯,那就是Loss下降不穩(wěn)定,容易發(fā)生抖動(dòng)。建議在個(gè)性化推薦(召回、排序)、語義匹配等數(shù)據(jù)量大的場(chǎng)景使用。 尤其是推薦領(lǐng)域的點(diǎn)擊率預(yù)估場(chǎng)景,該場(chǎng)景可能會(huì)出現(xiàn)千億甚至萬億規(guī)模的稀疏特征,而稀疏參數(shù)也可以達(dá)到萬億數(shù)量級(jí),且需要小時(shí)級(jí)或分鐘級(jí)流式增量訓(xùn)練。如果使用異步訓(xùn)練模式,可以很好的滿足該場(chǎng)景的online-learning需求。
GEO異步訓(xùn)練
GEO(Geometric Stochastic Gradient Descent)異步訓(xùn)練是飛槳paddle自研的異步訓(xùn)練模式,其最大的特點(diǎn)是將參數(shù)的更新從Server轉(zhuǎn)移到Worker上。每個(gè)Worker在本地訓(xùn)練過程中,使用SGD優(yōu)化算法更新本地模型參數(shù),在訓(xùn)練若干個(gè)batch的數(shù)據(jù)后,Worker將發(fā)送參數(shù)更新信息給Server。Server在接收后會(huì)通過加和方式更新保存的參數(shù)信息。所以顯而易見,在GEO異步訓(xùn)練模式下,Worker不用再等待Server發(fā)來新的參數(shù)即可執(zhí)行訓(xùn)練,在訓(xùn)練效果和訓(xùn)練速度上有了極大的提升。但是此模式比較適合可以在單機(jī)內(nèi)能完整保存的模型,在搜索、NLP等類型的業(yè)務(wù)上應(yīng)用廣泛,推薦在詞向量、語義匹配等場(chǎng)景中使用。
運(yùn)行策略的詳細(xì)描述可以參考文檔PaddlePaddle 參數(shù)服務(wù)器分布式訓(xùn)練策略定義
基于分類模型的訓(xùn)練示例
本文檔以二分類模型舉例,介紹單機(jī)訓(xùn)練和參數(shù)服務(wù)器訓(xùn)練(異步模式)兩種模式的詳細(xì)代碼,方便用戶快速了解兩種模式的具體差異。
本文涉及的所有源碼,可通過此鏈接獲取:https://github.com/seiriosPlus/Fleet/tree/distribtued_training/examples/distributed_ctr 建議親手操作,畢竟只有親手敲過的代碼才真正是自己的。
單機(jī)訓(xùn)練示例
環(huán)境準(zhǔn)備
訓(xùn)練前,請(qǐng)確保:
? 已正確安裝飛槳paddle最新版本。安裝操作請(qǐng)參見飛槳paddle。
? 運(yùn)行環(huán)境基于Linux,示例代碼支持Unbuntu及CentOS。
? 運(yùn)行環(huán)境中Python版本高于2.7。
數(shù)據(jù)處理
數(shù)據(jù)集采用Display Advertising Challenge所用的Criteo數(shù)據(jù)集。該數(shù)據(jù)集包括兩部分:訓(xùn)練集和測(cè)試集。訓(xùn)練集包含一段時(shí)間內(nèi)Criteo的部分流量,測(cè)試集則對(duì)應(yīng)訓(xùn)練數(shù)據(jù)后一天的廣告點(diǎn)擊流量。
數(shù)據(jù)預(yù)處理共包括兩步:
? 將原始訓(xùn)練集按9:1劃分為訓(xùn)練集和驗(yàn)證集。
? 數(shù)值特征(連續(xù)特征)需進(jìn)行歸一化處理,但需要注意的是,對(duì)每一個(gè)特征,歸一化時(shí)用到的最大值并不是用全局最大值,而是取排序后95%位置處的特征值作為最大值,同時(shí)保留極值。
模型設(shè)計(jì)
模型屬于二分類模型,網(wǎng)絡(luò)結(jié)構(gòu)如下圖所示。輸入是N類稀疏特征,比如詞的id。通過查取embedding表(字典大小xM維的向量表),變換成N個(gè)M維向量。將所有NxM維向量連接在一起融合為一個(gè)向量。網(wǎng)絡(luò)由多個(gè)輸入數(shù)據(jù)層(paddle.static.data)、多個(gè)共享參數(shù)的嵌入層(paddle.nn.functional.embedding),若干個(gè)全連接層(paddle.static.fc),以及相應(yīng)的分類任務(wù)的Loss計(jì)算和auc計(jì)算。經(jīng)過多層全連接層+激活函數(shù)(relu)后,進(jìn)行0/1分類。

數(shù)據(jù)輸入聲明

Criteo數(shù)據(jù)集分連續(xù)數(shù)據(jù)與離散(稀疏)數(shù)據(jù),整體而言,數(shù)據(jù)輸入層包括三個(gè),分別是:dense_input用于輸入連續(xù)數(shù)據(jù),維度由超參數(shù)dense_feature_dim指定,數(shù)據(jù)類型是歸一化后的浮點(diǎn)型數(shù)據(jù)。sparse_input_ids用于記錄離散數(shù)據(jù),在Criteo數(shù)據(jù)集中,共有26個(gè)slot,所以創(chuàng)建了名為C1~C26的26個(gè)稀疏參數(shù)輸入,并設(shè)置lod_level=1,代表其為變長數(shù)據(jù),數(shù)據(jù)類型為整數(shù);最后是每條樣本的label,代表了是否被點(diǎn)擊,數(shù)據(jù)類型是整數(shù),0代表負(fù)樣例,1代表正樣例。

在飛槳paddle中數(shù)據(jù)輸入的聲明使用paddle.static.data(),會(huì)創(chuàng)建指定類型的占位符,數(shù)據(jù)IO會(huì)依據(jù)此定義進(jìn)行數(shù)據(jù)的輸入

def input_data(self, params):
dense_input = paddle.static.data(name=“dense_input”,
shape=[params.dense_feature_dim],
dtype=“float32”)

sparse_input_ids = [paddle.static.data(name="C" + str(i),shape=[1],lod_level=1,dtype="int64") for i in range(1, 27)
]label = paddle.static.data(name="label", shape=[1], dtype="int64")inputs = [dense_input] + sparse_input_ids + [label]
return inputs

def net(self, inputs, params):

Embedding層

Embedding層的組網(wǎng)方式:Embedding層的輸入是sparse_input,shape由超參的sparse_feature_dimembedding_size定義

指定is_sprase=True后,計(jì)算圖會(huì)將該參數(shù)視為稀疏參數(shù),反向更新以及分布式通信時(shí),都以稀疏的方式進(jìn)行,會(huì)極大的提升運(yùn)行效率,同時(shí)保證效果一致。

def embedding_layer(input):return paddle.nn.functional.embedding(input=input,is_sparse=params.is_sparse,size=[params.sparse_feature_dim, params.embedding_size]),)sparse_embed_seq = list(map(embedding_layer, inputs[1:-1]))# 各個(gè)稀疏的輸入通過Embedding層后,將其合并起來,置于一個(gè)list內(nèi),以方便進(jìn)行concat的操作
concated = paddle.concat(sparse_embed_seq + inputs[0:1], axis=1)

將離散數(shù)據(jù)通過embedding查表得到的值,與連續(xù)數(shù)據(jù)的輸入進(jìn)行concat操作,合為一個(gè)整體輸入,作為全鏈接層的原始輸入。共設(shè)計(jì)了3層FC,每層FC的輸出維度都為400,每層FC都后接一個(gè)relu激活函數(shù),每層FC的初始化方式為符合正態(tài)分布的隨機(jī)初始化,標(biāo)準(zhǔn)差與上一層的輸出維度的平方根成反比。

fc1 = paddle.static.fc(input=concated,size=400,act="relu"
)
fc2 = paddle.static.fc(input=fc1,size=400,act="relu"
)
fc3 = paddle.static.fc(input=fc2,size=400,act="relu"
)
predict =paddle.static.fc(input=fc3,size=2,act="softmax"
)

Loss及Auc計(jì)算

預(yù)測(cè)的結(jié)果通過一個(gè)輸出shape為2的FC層給出,該FC層的激活函數(shù)softmax,會(huì)給出每條樣本分屬于正負(fù)樣本的概率。

每條樣本的損失由交叉熵給出,交叉熵的輸入維度為[batch_size,2],數(shù)據(jù)類型為float,label的輸入維度為[batch_size,1],數(shù)據(jù)類型為int。該batch的損失avg_cost是各條樣本的損失之和

同時(shí)還會(huì)計(jì)算預(yù)測(cè)的auc,auc的結(jié)果由paddle.static..auc()給出,該層的返回值有三個(gè),分別是全局auc: auc_var,當(dāng)前batch的auc: batch_auc_var,以及auc_states: auc_states,auc_states包含了batch_stat_pos, batch_stat_neg, stat_pos, stat_neg信息。

cost = paddle.nn.functional.cross_entropy(input=predict, label=inputs[-1])
avg_cost = paddle.sum(cost)
auc_var, batch_auc_var, _ = paddle.static.auc(input=predict,label=inputs[-1])return avg_cost, auc_var, batch_auc_var 

模型訓(xùn)練
def train(params):
# 引入模型的組網(wǎng)
ctr_model = CTR()
inputs = ctr_model.input_data(params)
avg_cost, auc_var, batch_auc_var = ctr_model.net(inputs,params)

# 選擇反向更新優(yōu)化策略
optimizer = paddle.optimizer.Adam(params.learning_rate)
optimizer.minimize(avg_cost)# 創(chuàng)建訓(xùn)練的執(zhí)行器
exe = paddle.static.Executor(paddle.CPUPlace())
exe.run(paddle.static.default_startup_program())# 引入數(shù)據(jù)讀取
dataset = get_dataset(inputs,params)# 開始訓(xùn)練
for epoch in range(params.epochs):# 啟動(dòng)pyreader的異步訓(xùn)練線程# PyRreader是飛槳paddle提供的簡潔易用的數(shù)據(jù)讀取API接口,支持同步數(shù)據(jù)讀取及異步數(shù)據(jù)讀取,用戶自行定義數(shù)據(jù)處理的邏輯后,以迭代器的方式傳遞給PyReader,完成訓(xùn)練的數(shù)據(jù)讀取部分reader.start()batch_id = 0try:while True:# 獲取網(wǎng)絡(luò)中,所需的輸出,如loss、auc等loss_val, auc_val, batch_auc_val = exe.run(program=compiled_prog,fetch_list=[avg_cost.name, auc_var.name, batch_auc_var.name])loss_val = np.mean(loss_val)auc_val = np.mean(auc_val)batch_auc_val = np.mean(batch_auc_val)# 每隔10個(gè)Batch打印一次輸出if batch_id % 10 == 0 and batch_id != 0:logger.info("TRAIN --> pass: {} batch: {} loss: {} auc: {}, batch_auc: {}".format(epoch, batch_id,loss_val / params.batch_size, auc_val,batch_auc_val))batch_id += 1except paddle.core.EOFException::# 一次訓(xùn)練完成后,要調(diào)用reset來將Reader恢復(fù)為初始狀態(tài),為下一輪訓(xùn)練準(zhǔn)備reader.reset()logger.info("Train Success!")

參數(shù)服務(wù)器訓(xùn)練示例
對(duì)于參數(shù)服務(wù)器訓(xùn)練來說,訓(xùn)練前也需要完成環(huán)境準(zhǔn)備、數(shù)據(jù)處理、模型設(shè)計(jì)工作。其中,數(shù)據(jù)處理和模型設(shè)計(jì)與單機(jī)訓(xùn)練完全相同,可以直接拿來使用。
環(huán)境準(zhǔn)備
執(zhí)行模型訓(xùn)練前,需要確保運(yùn)行環(huán)境滿足以下要求:
? 飛槳paddle參數(shù)服務(wù)器模式的訓(xùn)練,目前只支持在Liunx環(huán)境下運(yùn)行,推薦使用ubuntu或CentOS
? 飛槳paddle參數(shù)服務(wù)器模式的Python環(huán)境支持python 2.7及python 3.5+, 安裝和運(yùn)行前請(qǐng)檢查版本是否符合要求
? 使用飛槳paddle的參數(shù)服務(wù)器分布式訓(xùn)練,確保各自之間可以通過ip:port的方式訪問rpc服務(wù),使用http/https代理會(huì)導(dǎo)致通信失敗
? 參數(shù)服務(wù)器使用RPC通信完成整個(gè)訓(xùn)練流程,訓(xùn)練節(jié)點(diǎn)存在于同一個(gè)機(jī)房、IDC會(huì)獲得更好的速度
? 飛槳paddle的參數(shù)服務(wù)器訓(xùn)練支持多種訓(xùn)練環(huán)境的啟動(dòng)和運(yùn)行,包括kubernetes/MPI/其他自定義環(huán)境等。
數(shù)據(jù)處理
參數(shù)服務(wù)器訓(xùn)練的數(shù)據(jù)處理與單機(jī)訓(xùn)練完全相同,這里不再重復(fù)贅述。
模型設(shè)計(jì)
參數(shù)服務(wù)器訓(xùn)練的模型設(shè)計(jì)與單機(jī)訓(xùn)練完全相同,這里不再重復(fù)贅述。
模型訓(xùn)練
飛槳paddle的參數(shù)服務(wù)器中存在Worker和PServer兩種角色,下面會(huì)結(jié)合2X2的實(shí)際情況講述啟動(dòng)流程。 飛槳paddle的參數(shù)服務(wù)器的訓(xùn)練分為3個(gè)階段, 一是將PServer全部啟動(dòng), PServer會(huì)根據(jù)用戶定義的監(jiān)聽端口啟動(dòng)監(jiān)聽服務(wù),等待Worker連接;二是啟動(dòng)全部Worker節(jié)點(diǎn),Worker節(jié)點(diǎn)會(huì)根據(jù)配置的Pserver的端口號(hào)跟每一個(gè)PServer進(jìn)行連接檢查,確保能夠順利連接后,進(jìn)行參數(shù)的初始化和同步;三是啟動(dòng)訓(xùn)練流程,通過跟多個(gè)PServer的通信完成整個(gè)訓(xùn)練流程。 假設(shè)有兩臺(tái)機(jī)器,想要在每臺(tái)機(jī)器上分別啟動(dòng)一個(gè)server進(jìn)程以及一個(gè)worker進(jìn)程,完成2x2(2個(gè)參數(shù)服務(wù)器,2個(gè)訓(xùn)練節(jié)點(diǎn))的參數(shù)服務(wù)器模式分布式訓(xùn)練,按照如下步驟操作。
啟動(dòng)server
機(jī)器A,IP地址是10.89.176.11,通信端口是36000,配置如下環(huán)境變量后,運(yùn)行訓(xùn)練的入口程序:
export PADDLE_PSERVERS_IP_PORT_LIST=“10.89.176.11:36000,10.89.176.12:36000”
export TRAINING_ROLE=PSERVER
export POD_IP=10.89.176.11 # node A:10.89.176.11
export PADDLE_PORT=36000
export PADDLE_TRAINERS_NUM=2
python -u train.py --is_cloud=1
應(yīng)能在日志中看到如下輸出:
server.cpp:1040] Check out http://10.89.176.11:36000 in web browser.
查看系統(tǒng)進(jìn)程
8624 | ttys000 | 0:02.31 | python -u train.py --is_cloud=1
查看系統(tǒng)進(jìn)程及端口占用:
python3.7 | 8624 | paddle | 8u | IPv6 | 0xe149b87d093872e5 | 0t0 | TCP | localhost:36000 (LISTEN)
也可以看到的server進(jìn)程8624的確在36000端口開始了監(jiān)聽,等待worker的通信。
機(jī)器B,IP地址是10.89.176.12,通信端口是36000,配置如下環(huán)境變量后,運(yùn)行訓(xùn)練的入口程序:
export PADDLE_PSERVERS_IP_PORT_LIST=“10.89.176.11:36000,10.89.176.12:36000”
export TRAINING_ROLE=PSERVER
export POD_IP=10.89.176.12 # node B: 10.89.176.12
export PADDLE_PORT=36000
export PADDLE_TRAINERS_NUM=2
python -u train.py --is_cloud=1
也可以看到相似的日志輸出與進(jìn)程狀況。(進(jìn)行驗(yàn)證時(shí),請(qǐng)務(wù)必確保IP與端口的正確性)
啟動(dòng)worker
接下來分別在機(jī)器A與B上開啟訓(xùn)練進(jìn)程。配置如下環(huán)境變量并開啟訓(xùn)練進(jìn)程:
機(jī)器A:
export PADDLE_PSERVERS_IP_PORT_LIST=“10.89.176.11:36000,10.89.176.12:36000”
export TRAINING_ROLE=TRAINER
export PADDLE_TRAINERS_NUM=2
export PADDLE_TRAINER_ID=0 # node A:trainer_id = 0
python -u train.py --is_cloud=1
機(jī)器B:
export PADDLE_PSERVERS_IP_PORT_LIST=“10.89.176.11:36000,10.89.176.12:36000”
export TRAINING_ROLE=TRAINER
export PADDLE_TRAINERS_NUM=2
export PADDLE_TRAINER_ID=1 # node B: trainer_id = 1
python -u train.py --is_cloud=1
運(yùn)行該命令時(shí),若Pserver還未就緒,可在日志輸出中看到如下信息:
server not ready, wait 3 sec to retry…
not ready endpoints:[‘10.89.176.11:36000’, ‘10.89.176.12:36000’]
Worker進(jìn)程將持續(xù)等待,直到Pserver開始監(jiān)聽,或等待超時(shí)。
當(dāng)Pserver都準(zhǔn)備就緒后,可以在日志輸出看到如下信息:
I0317 11:38:48.099179 16719 communicator.cc:271] Communicator start
I0317 11:38:49.838711 16719 rpc_client.h:107] init rpc client with trainer_id 0
至此,分布式訓(xùn)練啟動(dòng)完畢,開始訓(xùn)練。
參數(shù)服務(wù)器訓(xùn)練數(shù)據(jù)切分
飛槳paddle的參數(shù)服務(wù)器訓(xùn)練目前主要是數(shù)據(jù)并行模式。通過增加訓(xùn)練節(jié)點(diǎn)來提高訓(xùn)練數(shù)據(jù)的并行度的,需要對(duì)數(shù)據(jù)進(jìn)行劃分,即將全部的訓(xùn)練數(shù)據(jù)均勻的分成Worker個(gè)數(shù)份,每一個(gè)Worker需要分配全部訓(xùn)練數(shù)據(jù)中的一份,每個(gè)Worker節(jié)點(diǎn)訓(xùn)練自己的一份數(shù)據(jù),參數(shù)由PServer端完成聚合和更新。要確保每個(gè)節(jié)點(diǎn)都能拿到數(shù)據(jù),希望每個(gè)節(jié)點(diǎn)的數(shù)據(jù)同時(shí)滿足:各個(gè)節(jié)點(diǎn)數(shù)據(jù)無重復(fù)和各個(gè)節(jié)點(diǎn)數(shù)據(jù)數(shù)量均勻。
Fleet提供了split_files()的接口,輸入值是一個(gè)穩(wěn)定的目錄List,隨后該函數(shù)會(huì)根據(jù)節(jié)點(diǎn)自身的編號(hào)拿到相應(yīng)的數(shù)據(jù)文件列表,訓(xùn)練數(shù)據(jù)在同一個(gè)目錄下,使用該接口,給各個(gè)進(jìn)程(扮演不同的訓(xùn)練節(jié)點(diǎn))分配不同的數(shù)據(jù)文件。
file_list = [
str(args.train_files_path) + “/%s” % x
for x in os.listdir(args.train_files_path)
]

請(qǐng)確保每一個(gè)訓(xùn)練節(jié)點(diǎn)都持有不同的訓(xùn)練文件

當(dāng)用本地多進(jìn)程模擬分布式時(shí),每個(gè)進(jìn)程需要拿到不同的文件

使用 fleet.split_files 可以便捷的以文件為單位分配訓(xùn)練樣本

files= fleet.split_files(file_list)
基于得到的files,每個(gè)節(jié)點(diǎn)開始獨(dú)立進(jìn)行數(shù)據(jù)讀取和訓(xùn)練。如果數(shù)據(jù)在HDFS上,可以根據(jù)files列表將數(shù)據(jù)下載會(huì)本地進(jìn)行讀取。如果數(shù)據(jù)在本地,則可直接根據(jù)files列表進(jìn)行讀取。
詳細(xì)訓(xùn)練代碼示例
異步模式分布式訓(xùn)練代碼的詳細(xì)說明如下所示。
# 根據(jù)環(huán)境變量確定當(dāng)前機(jī)器/進(jìn)程在分布式訓(xùn)練中的角色分配Worker/PSERVER
# 然后使用 fleet api的 init()方法初始化這個(gè)節(jié)點(diǎn)
role = role_maker.PaddleCloudRoleMaker()
fleet.init(role)

# 設(shè)置分布式運(yùn)行模式為異步(async),同時(shí)將參數(shù)進(jìn)行切分,以分配到不同的節(jié)點(diǎn)
strategy = StrategyFactory.create_async_strategy()ctr_model = CTR()
inputs = ctr_model.input_data(params)
avg_cost, auc_var, batch_auc_var = ctr_model.net(inputs, params)
optimizer = paddle.optimizer.Adam(params.learning_rate)# 配置分布式的optimizer,傳入指定的strategy,構(gòu)建program
optimizer = fleet.distributed_optimizer(optimizer, strategy)
optimizer.minimize(avg_cost)# 根據(jù)節(jié)點(diǎn)角色,分別運(yùn)行不同的邏輯
if fleet.is_server():# 初始化及運(yùn)行參數(shù)服務(wù)器節(jié)點(diǎn)fleet.init_server()fleet.run_server()elif fleet.is_worker():# 初始化工作節(jié)點(diǎn)fleet.init_worker()exe = paddle.static.Executor(paddle.CPUPlace())# 初始化含有分布式流程的fleet.startup_programexe.run(fleet.startup_program)for epoch in range(params.epochs):# 啟動(dòng)dataloader的異步訓(xùn)練線程# DataLoader是飛槳paddle提供的簡潔易用的數(shù)據(jù)讀取API接口,支持同步數(shù)據(jù)讀取及異步數(shù)據(jù)讀取,用戶自行定義數(shù)據(jù)處理的邏輯后,以迭代器的方式傳遞給DataLoader,完成訓(xùn)練的數(shù)據(jù)讀取部分reader.start()batch_id = 0try:while True:# 獲取網(wǎng)絡(luò)中,所需的輸出,如loss、auc等loss_val, auc_val, batch_auc_val = exe.run(program=compiled_prog,fetch_list=[avg_cost.name, auc_var.name, batch_auc_var.name])loss_val = np.mean(loss_val)auc_val = np.mean(auc_val)batch_auc_val = np.mean(batch_auc_val)# 每隔10個(gè)Batch打印一次輸出if batch_id % 10 == 0 and batch_id != 0:logger.info("TRAIN --> pass: {} batch: {} loss: {} auc: {}, batch_auc: {}".format(epoch, batch_id,loss_val / params.batch_size, auc_val,batch_auc_val))batch_id += 1except paddle.core.EOFException:# 一次訓(xùn)練完成后,要調(diào)用reset來將Reader恢復(fù)為初始狀態(tài),為下一輪訓(xùn)練準(zhǔn)備reader.reset()# 默認(rèn)使用0號(hào)節(jié)點(diǎn)保存模型if  fleet.is_first_worker():model_path = (str(params.model_path) + "/" + "epoch_" +str(epoch))fleet.save_persistables(executor=exe, dirname=model_path)fleet.stop_worker()

使用pyreader進(jìn)行多輪訓(xùn)練時(shí),有一些固有的使用方法,如示例代碼所示,使用try & except捕獲異常的方式得到reader讀取完數(shù)據(jù)的信號(hào),使用reset重置reader,以進(jìn)行下一輪訓(xùn)練的數(shù)據(jù)讀取。 執(zhí)行exe.run()時(shí),傳入的是CompiledProgram,同時(shí)可以通過加入fetch_list來直接獲取想要監(jiān)控的變量。
運(yùn)行:本地模擬分布式
運(yùn)行方式有兩種方式。
方法一 運(yùn)行l(wèi)ocal_cluster.sh腳本
運(yùn)行l(wèi)ocal_cluster.sh腳本,設(shè)置啟動(dòng)命令為sync:
sh local_cluster.sh sync
使用該腳本開啟分布式模擬訓(xùn)練,默認(rèn)啟用2x2的訓(xùn)練模式。Worker與Pserver的運(yùn)行日志,存放于./log/文件夾,保存的模型位于./model/。
方法二 運(yùn)行飛槳paddle內(nèi)置的一個(gè)啟動(dòng)器launch_ps
在單機(jī)模擬多機(jī)訓(xùn)練的啟動(dòng)命令,飛槳paddle內(nèi)置的一個(gè)啟動(dòng)器launch_ps,用戶可以指定Worker和server的數(shù)量進(jìn)行參數(shù)服務(wù)器任務(wù)的啟動(dòng)。

python -m paddle.distributed.launch_ps --worker_num 2 --server_num 2 train.py

使用該腳本開啟分布式模擬訓(xùn)練,也將啟用2個(gè)Worker x 2個(gè)server的訓(xùn)練模式。Worker與Pserver的運(yùn)行日志,存放于./logs/文件夾,保存的模型位于./model/。
開啟本地模擬分布式訓(xùn)練后的日志輸出
使用快速驗(yàn)證數(shù)據(jù)集,本地模擬同步模式的分布式訓(xùn)練的理想輸出為:
pserver.0.log
INFO:file list: [‘train_data/part-1’]
get_pserver_program() is deprecated, call get_pserver_programs() to get pserver main and startup in a single call.
I1128 11:34:50.242866 459 grpc_server.cc:477] Server listening on 127.0.0.1:36011 successful, selected port: 36011
trainer.0.log
INFO:file list: [‘train_data/part-1’]
server not ready, wait 3 sec to retry…
not ready endpoints:[‘127.0.0.1:36012’]
I1128 11:34:53.424834 32649 rpc_client.h:107] init rpc client with trainer_id 0
I1128 11:34:53.526729 32649 parallel_executor.cc:423] The Program will be executed on CPU using ParallelExecutor, 2 cards are used, so 2 programs are executed in parallel.
I1128 11:34:53.537334 32649 parallel_executor.cc:287] Inplace strategy is enabled, when build_strategy.enable_inplace = True
I1128 11:34:53.541473 32649 parallel_executor.cc:370] Garbage collection strategy is enabled, when FLAGS_eager_delete_tensor_gb = 0
INFO:TRAIN --> pass: 0 batch: 10 loss: 0.588123535156 auc: 0.497622251208, batch_auc: 0.496669348982
INFO:TRAIN --> pass: 0 batch: 20 loss: 0.601480102539 auc: 0.501770208439, batch_auc: 0.520060819177
INFO:TRAIN --> pass: 0 batch: 30 loss: 0.581234985352 auc: 0.513533941098, batch_auc: 0.552742309157
INFO:TRAIN --> pass: 0 batch: 40 loss: 0.551335083008 auc: 0.523242733864, batch_auc: 0.586762885637
INFO:TRAIN --> pass: 0 batch: 50 loss: 0.532891052246 auc: 0.538684471661, batch_auc: 0.617389479234
INFO:TRAIN --> pass: 0 batch: 60 loss: 0.564157531738 auc: 0.552346798675, batch_auc: 0.628245358534
INFO:TRAIN --> pass: 0 batch: 70 loss: 0.547578674316 auc: 0.565243961316, batch_auc: 0.651260427476
INFO:TRAIN --> pass: 0 batch: 80 loss: 0.554214599609 auc: 0.57554000345, batch_auc: 0.648544028986
INFO:TRAIN --> pass: 0 batch: 90 loss: 0.549561889648 auc: 0.585579565556, batch_auc: 0.660180398731
INFO:epoch 0 finished, use time=40

INFO:Distribute Train Success!
模型預(yù)測(cè)
完成前面的單機(jī)訓(xùn)練和參數(shù)服務(wù)器訓(xùn)練完成后,需要在測(cè)試集上測(cè)試離線預(yù)測(cè)的結(jié)果,驗(yàn)證模型的泛化能力。本節(jié)內(nèi)容對(duì)應(yīng)示例代碼中的infer.py。
單機(jī)訓(xùn)練和參數(shù)服務(wù)器訓(xùn)練均采用此操作進(jìn)行模型預(yù)測(cè)。
構(gòu)建預(yù)測(cè)網(wǎng)絡(luò)及加載模型參數(shù)
預(yù)測(cè)網(wǎng)絡(luò)與訓(xùn)練網(wǎng)絡(luò)一致,無需更改,使用相同的方式構(gòu)建inputs、loss、auc。加載參數(shù)使用paddle.io.load_vars()接口,從保存好的模型文件夾中加載同名參數(shù)。

paddle中對(duì)于program的獨(dú)立作用域限定, 在此作用域下配置的所有組網(wǎng)相關(guān)的操作均作用于test_program, startup_program上

with paddle.static.program_guard(test_program, startup_program):

paddle中對(duì)于參數(shù)命名的獨(dú)立作用域限定, 在此作用域下配置的組網(wǎng),會(huì)重新開始編號(hào),不會(huì)和其他網(wǎng)絡(luò)沖突

with paddle.static.unique_name.guard():inputs = ctr_model.input_data(params)loss, auc_var, batch_auc_var = ctr_model.net(inputs, params)exe = paddle.static.Executor(place)feeder =paddle.io.DataLoader(feed_list=inputs, place=place)paddle.static.load_vers(executor=exe,dirname=model_path,main_program=paddle.static.default_main_program())

在進(jìn)行上述流程時(shí),有一些需要關(guān)注的細(xì)節(jié):
? 傳入的program不是default_main_program(),而是新建的空的program。因?yàn)樵跍y(cè)試時(shí),要從零開始,保證預(yù)測(cè)program的干凈,沒有其它的影響因素。
? startup_program = paddle.static.Program()
? test_program = paddle.static.Program()
? 在創(chuàng)建預(yù)測(cè)網(wǎng)絡(luò)時(shí),加入了with paddle.static.unique_name.guard(): 作用是讓所有新建的參數(shù)的自動(dòng)編號(hào)再次從零開始。飛槳paddle的參數(shù)Variable以變量名作為區(qū)分手段,保證變量名相同,就可以從保存的模型中找到對(duì)應(yīng)參數(shù)。
飛槳paddle創(chuàng)建的臨時(shí)變量,編號(hào)會(huì)自動(dòng)順延,如果沒有指定變量名,可以觀察到這一現(xiàn)象,比如:fc_1.w_0->fc_2.w_0,想要共享相同的參數(shù),必需要保證編號(hào)可以對(duì)應(yīng)。
獲取測(cè)試數(shù)據(jù)
測(cè)試數(shù)據(jù)的讀取使用同步模式中使用過的pyreader方法。
運(yùn)行測(cè)試
為了快速驗(yàn)證,僅取用測(cè)試數(shù)據(jù)集的一個(gè)part文件,進(jìn)行測(cè)試。在代碼目錄下,鍵入以下命令,進(jìn)行預(yù)測(cè):
python -u infer.py &> test.log &
測(cè)試結(jié)果的日志位于test.log,僅訓(xùn)練一個(gè)epoch后,在part-220上的的理想測(cè)試結(jié)果為:
2019-11-26 08:56:19,985 - INFO - Test model model/epoch_0
open file success
2019-11-26 08:56:20,323 - INFO - TEST --> batch: 0 loss: [0.5577456] auc: [0.61541704]
2019-11-26 08:56:37,839 - INFO - TEST --> batch: 100 loss: [0.5395161] auc: [0.6346397]
2019-11-26 08:56:55,189 - INFO - {‘loss’: 0.5571399, ‘a(chǎn)uc’: array([0.6349838])}
2019-11-26 08:56:55,189 - INFO - Inference complete
因?yàn)榭焖衮?yàn)證的訓(xùn)練數(shù)據(jù)與測(cè)試數(shù)據(jù)極少,同時(shí)只訓(xùn)練了一輪,所以遠(yuǎn)遠(yuǎn)沒有達(dá)到收斂,且初始化帶有隨機(jī)性,在您的環(huán)境下出現(xiàn)測(cè)試結(jié)果與示例輸出不一致是正常情況。
參數(shù)服務(wù)器訓(xùn)練的性能調(diào)優(yōu)
優(yōu)化的目的是在給定數(shù)據(jù)集上,以最快速度訓(xùn)練得到最優(yōu)的效果。參數(shù)服務(wù)器訓(xùn)練的性能調(diào)優(yōu)分為速度提升和效果提升。
速度提升
參數(shù)服務(wù)器訓(xùn)練涉及的訓(xùn)練如下圖所示。

可以看出:訓(xùn)練時(shí)間 = 數(shù)據(jù)讀取時(shí)間 + 節(jié)點(diǎn)訓(xùn)練(網(wǎng)絡(luò)前向后向執(zhí)行時(shí)間) + 通信時(shí)間 + 節(jié)點(diǎn)之間等待時(shí)間 + 更新參數(shù)時(shí)間。
因此可以從數(shù)據(jù)讀取、單節(jié)點(diǎn)訓(xùn)練、通信模塊、Server端參數(shù)更新這4個(gè)方面進(jìn)行參數(shù)服務(wù)器的優(yōu)化。
Dataset數(shù)據(jù)讀取
目前支持PyReader和Dataset兩種,后者速度更快。PyReader采用的模式是多個(gè)讀數(shù)據(jù)線程寫到一個(gè)隊(duì)列中,多個(gè)訓(xùn)練線程從這個(gè)一個(gè)隊(duì)列中讀取數(shù)據(jù),形成了多生產(chǎn)者多消費(fèi)者的模式,導(dǎo)致隊(duì)列成為瓶頸。Dataset采用多個(gè)讀數(shù)據(jù)線程寫到多個(gè)隊(duì)列中,多個(gè)訓(xùn)練線程之間完全異步的模式, 消除隊(duì)列瓶頸,在數(shù)據(jù)讀取速度上更勝一籌。
在模型比較簡單、數(shù)量比較大時(shí),可以使用參數(shù)服務(wù)器的全異步訓(xùn)練模式和高性能的IO數(shù)據(jù)讀取模式來高速的訓(xùn)練。Dataset是為多線程及全異步模式量身打造的數(shù)據(jù)讀取方式,每個(gè)數(shù)據(jù)讀取線程會(huì)與一個(gè)訓(xùn)練線程耦合,形成了多生產(chǎn)者-多消費(fèi)者的模式,極大的加速了模型訓(xùn)練。詳細(xì)的Dataset的設(shè)計(jì)文檔可以參考:Dataset
如何在的訓(xùn)練中引入Dataset讀取方式呢?
無需變更數(shù)據(jù)格式,只需在的訓(xùn)練代碼中加入以下內(nèi)容,便可達(dá)到媲美二進(jìn)制讀取的高效率,以下是一個(gè)比較完整的流程。
一、定義Dataset
以下是dataset_generator.py的全部代碼,具體流程如下:

  1. 首先需要引入Dataset庫,位于paddle.distributed.QueueDataset。
  2. 聲明一些在數(shù)據(jù)讀取中會(huì)用到的變量,如示例代碼中的cont_min_、categorical_range_等。
  3. 創(chuàng)建一個(gè)子類,繼承Dataset的基類,基類有多種選擇,如果是多種數(shù)據(jù)類型混合,并且需要轉(zhuǎn)化為數(shù)值進(jìn)行預(yù)處理的,建議使用MultiSlotDataGenerator;若已經(jīng)完成了預(yù)處理并保存為數(shù)據(jù)文件,可以直接以string的方式進(jìn)行讀取,使用MultiSlotStringDataGenerator,能夠進(jìn)一步加速。在示例代碼,繼承并實(shí)現(xiàn)了名為CriteoDataset的dataset子類,使用MultiSlotDataGenerator方法。
  4. 繼承并實(shí)現(xiàn)基類中的generate_sample函數(shù),逐行讀取數(shù)據(jù)。該函數(shù)應(yīng)返回一個(gè)可以迭代的reader方法(帶有yield的函數(shù)不再是一個(gè)普通的函數(shù),而是一個(gè)生成器generator,成為了可以迭代的對(duì)象,等價(jià)于一個(gè)數(shù)組、鏈表、文件、字符串etc.)
  5. 在這個(gè)可以迭代的函數(shù)中,如示例代碼中的def reader(),定義數(shù)據(jù)讀取的邏輯。例如對(duì)以行為單位的數(shù)據(jù)進(jìn)行截取,轉(zhuǎn)換及預(yù)處理。
  6. 最后,需要將數(shù)據(jù)整理為特定的格式,才能夠被Dataset正確讀取,并灌入訓(xùn)練網(wǎng)絡(luò)中。簡單來說,數(shù)據(jù)的輸出順序與在網(wǎng)絡(luò)中創(chuàng)建的inputs必須是嚴(yán)格一一對(duì)應(yīng)的,并轉(zhuǎn)換為類似字典的形式。在示例代碼中,使用zip的方法將參數(shù)名與數(shù)值構(gòu)成的元組組成了一個(gè)list,并將其yield輸出。如果展開來看,輸出的數(shù)據(jù)形如[(‘dense_feature’,[value]),(‘C1’,[value]),(‘C2’,[value]),…,(‘C26’,[value]),(‘label’,[value])]。
    import paddle.distributed.fleet.data_generator as dg

cont_min_ = [0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
cont_max_ = [20, 600, 100, 50, 64000, 500, 100, 50, 500, 10, 10, 10, 50]
cont_diff_ = [20, 603, 100, 50, 64000, 500, 100, 50, 500, 10, 10, 10, 50]
hash_dim_ = 1000001
continuous_range_ = range(1, 14)
categorical_range_ = range(14, 40)

class CriteoDataset(dg.MultiSlotDataGenerator):

def generate_sample(self, line):def reader():features = line.rstrip('\n').split('\t')dense_feature = []sparse_feature = []for idx in continuous_range_:if features[idx] == "":dense_feature.append(0.0)else:dense_feature.append((float(features[idx]) - cont_min_[idx - 1]) /cont_diff_[idx - 1])for idx in categorical_range_:sparse_feature.append([hash(str(idx) + features[idx]) % hash_dim_])label = [int(features[0])]process_line = dense_feature, sparse_feature, labelfeature_name = ["dense_feature"]for idx in categorical_range_:feature_name.append("C" + str(idx - 13))feature_name.append("label")yield zip(feature_name, [dense_feature] + sparse_feature + [label])return reader

d = CriteoDataset()
d.run_from_stdin()
二、引入Dataset

  1. 通過工廠類paddle.distributed.QueueDataset創(chuàng)建一個(gè)Dataset對(duì)象。
  2. 將定義好的數(shù)據(jù)輸入格式傳給Dataset,通過dataset._set_use_var(inputs)實(shí)現(xiàn)。
  3. 指定的數(shù)據(jù)讀取方式,由dataset_generator.py實(shí)現(xiàn)數(shù)據(jù)讀取的規(guī)則,后面會(huì)介紹讀取規(guī)則的實(shí)現(xiàn)。
  4. 指定數(shù)據(jù)讀取的batch_size。
  5. 指定數(shù)據(jù)讀取的線程數(shù),該線程數(shù)和訓(xùn)練線程應(yīng)保持一致,兩者為耦合的關(guān)系。
  6. 指定Dataset讀取的訓(xùn)練文件的列表。
    def get_dataset(inputs, params)
    dataset = paddle.distributed.fleet.dataset.DatasetBase()
    dataset._set_use_var(inputs)
    dataset._set_pipe_command(“python dataset_generator.py”)
    dataset._set_batch_size(params.batch_size)
    dataset._set_thread(int(params.cpu_num))
    file_list = [
    str(params.train_files_path) + “/%s” % x
    for x in os.listdir(params.train_files_path)
    ]
    dataset.set_filelist(file_list)
    logger.info(“file list: {}”.format(file_list))
    return dataset
    三、 Dataset Reader 快速調(diào)試
    可以脫離組網(wǎng)架構(gòu),單獨(dú)驗(yàn)證Dataset的輸出是否符合預(yù)期。使用命令 cat 數(shù)據(jù)文件 | python dataset讀取python文件進(jìn)行dataset代碼的調(diào)試:
    cat train_data/part-0 | python dataset_generator.py
    輸出的數(shù)據(jù)格式如下: dense_input:size ; dense_input:value ; sparse_input:size ; sparse_input:value ; … ; sparse_input:size ; sparse_input:value ; label:size ; label:value
    理想的輸出為(截取了一個(gè)片段):

    13 0.05 0.00663349917081 0.05 0.0 0.02159375 0.008 0.15 0.04 0.362 0.1 0.2 0.0 0.04 1 715353 1 817085 1 851010 1 833725 1 286835 1 948614 1 881652 1 507110 1 27346 1 646986 1 643076 1 200960 1 18464 1 202774 1 532679 1 729573 1 342789 1 562805 1 880474 1 984402 1 666449 1 26235 1 700326 1 452909 1 884722 1 787527 1 0

    使用Dataset的一些注意事項(xiàng)
    ? Dataset的基本原理:將數(shù)據(jù)print到緩存,再由C++端的代碼實(shí)現(xiàn)讀取,因此,不能在dataset的讀取代碼中,加入與數(shù)據(jù)讀取無關(guān)的print信息,會(huì)導(dǎo)致C++端拿到錯(cuò)誤的數(shù)據(jù)信息。
    ? Dataset目前只支持在unbuntu及CentOS等標(biāo)準(zhǔn)Linux環(huán)境下使用,在Windows及Mac下使用時(shí),會(huì)產(chǎn)生錯(cuò)誤,請(qǐng)知悉。
    節(jié)點(diǎn)訓(xùn)練
    加快訓(xùn)練速度,采用多線程的方式進(jìn)行單節(jié)點(diǎn)的訓(xùn)練,如配置更大的線程數(shù)來加速訓(xùn)練等。
    通信模塊
    ? 采用稀疏更新:目前部分OP實(shí)現(xiàn)了稀疏更新(embedding/nce/hsigmoid),采用稀疏更新的方式傳輸梯度,可以減少通信量,提升訓(xùn)練速度
    ? 減少通信時(shí)間:可以采用減少通信次數(shù)(GEO方式隔N個(gè)batch通信一次,可以調(diào)整N來減少通信)、壓縮單次通信量(稀疏通信), 采樣全異步、GEO異步等訓(xùn)練模式可以減少網(wǎng)絡(luò)通信,減少節(jié)點(diǎn)之間等待時(shí)間,達(dá)到加速的目的
    分布式訓(xùn)練策略GEO異步訓(xùn)練的配置,引入StrategyFactory后,只需調(diào)用create_geo_strategy即可。
optimizer = paddle.optimizer.SGD(params.learning_rate)
# geo異步模式可以指定通信間隔的MiniBatch數(shù),間隔Batch數(shù)越大,理論上速度越快,但是對(duì)效果可能有影響,需要在此進(jìn)行權(quán)衡strategy = paddle.distributed.fleet.DistributedStrategy()
strategy.a_sync = True
strategy.a_sync_configs = {"k_steps": 100}# 配置分布式的optimizer,傳入指定的strategy,構(gòu)建program
optimizer = fleet.distributed_optimizer(optimizer, strategy)
optimizer.minimize(avg_cost)

參數(shù)更新
? 稀疏更新:部分優(yōu)化器實(shí)現(xiàn)了稀疏更新的方式(既只更新有梯度的參數(shù)),在參數(shù)規(guī)模較大的情況下,可以極大的提升訓(xùn)練速度,目前包括SGD/Adagrad/Adam(需要在配置optimizer的時(shí)候指定lazy_mode=True)實(shí)現(xiàn)了稀疏更新,采用此方式可以提速。

稀疏參數(shù)(embedding等)會(huì)采用稀疏更新

optimizer = paddle.optimizer.AdamOptimizer(learning_rate=0.002, lazy_mode=True)

效果提升
可以通過調(diào)整訓(xùn)練數(shù)據(jù)分布、訓(xùn)練模式、優(yōu)化算法及超參等手段來提升模型效果。試想,在同步訓(xùn)練下,由于Pserver端更新參數(shù)時(shí)采用的是全局梯度,當(dāng)“多機(jī)下節(jié)點(diǎn)數(shù)乘以batchsize等于單機(jī)下batchsize”時(shí),多機(jī)效果可以和單機(jī)打平, 所以分布式下的效果優(yōu)化,可以歸結(jié)為向單機(jī)靠齊。
? 訓(xùn)練數(shù)據(jù)均勻分布或節(jié)點(diǎn)之間差異最小:隨機(jī)亂序,并均勻分配給不同訓(xùn)練節(jié)點(diǎn),使得節(jié)點(diǎn)之間訓(xùn)練數(shù)據(jù)分布差異最小,且訓(xùn)練速度差異最小,這樣效果會(huì)更穩(wěn)定。一般情況下,訓(xùn)練數(shù)據(jù)在訓(xùn)練開始只分配一次,然后訓(xùn)練多個(gè)Epoch。舉例,兩個(gè)節(jié)點(diǎn)AB,AB始終都在訓(xùn)同一個(gè)Epoch的效果,肯定好于節(jié)點(diǎn)A在訓(xùn)Epoch2,節(jié)點(diǎn)B在訓(xùn)Epoch20。因?yàn)楣?jié)點(diǎn)B在嚴(yán)重過擬合自己部分的數(shù)據(jù)。
? 優(yōu)化算法:在需訓(xùn)練多輪情況下,SGD最終效果會(huì)好些;在只需訓(xùn)練一輪情況下,Ada系列效果會(huì)更好些。
? 訓(xùn)練模式:同步模式的效果往往比異步好些,但異步速度更快。在異步下,可以通過減少節(jié)點(diǎn)差異,將效果向同步對(duì)齊。
? 超參:節(jié)點(diǎn)數(shù)調(diào)整的時(shí)候,batchsize、學(xué)習(xí)率要相應(yīng)的調(diào)整,保證收斂速度不變。

總結(jié)

以上是生活随笔為你收集整理的参数服务器训练基本理论的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。