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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

硬件太差不要慌 做时间的朋友

發(fā)布時間:2024/5/15 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 硬件太差不要慌 做时间的朋友 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

背景

天之道,損有余以補不足。

深度學(xué)習(xí),那是先富的游戲。窮導(dǎo)致硬件不行,非科班導(dǎo)致工程也不行,每次比賽數(shù)據(jù)量一大,我心里浮現(xiàn)的都是水滸傳名場面

相聲,講究的是說學(xué)逗唱;而工程,講究的是一個吹德偶夫(trade-off)。那,我們就用時間換空間。時間是每個人的朋友,跑的慢,就多等等。之前kdd cup百度比賽,我在嘗試復(fù)現(xiàn)baseline的時候就遇到了麻煩。

215天的訓(xùn)練歷史,產(chǎn)生了400萬樣本。batch_size選擇1024,但每個step大概耗時800ms,單個epoch慢的離譜。不禁感慨生活太殘忍了。

本文記錄一下,我做了哪些改動。很多人喜歡強調(diào):什么算法工程師先要是一個工程師。我雖然不懂這話的含義,但工地上,他們都叫我Yue工,贏麻了。

讀取

首先是讀取文件過程,想把csv保存為pickle后加載。但發(fā)現(xiàn)csv讀取只花2秒。可以接受,未采納。

dataset中窗口滑動轉(zhuǎn)化為時序樣本,原本pandas操作變?yōu)閚umpy操作。單個樣本處理時間從2e-4s 降低為2e-6s,訓(xùn)練單個step從800ms可以降為250ms。但二者切片時對左開右閉的設(shè)置不一樣,坑了很久

原本我沾沾自喜的設(shè)計了,一個day到index到樣本的數(shù)據(jù)提取路線,每個過程都封裝的很好。實際跑起來,發(fā)現(xiàn)訓(xùn)練前啥預(yù)處理沒有,要花三十分鐘(1933s)。從所有index選取不在drop_list的,普通寫法特別耗時,轉(zhuǎn)化為集合求差。三十分鐘變成3秒。
很慢
idx = [i for i in all_idx if i not in dropidx] # very slow
很快
idx = sorted(list(set(all_idx) - set(dropidx)))
樣本選取idx過程中,通過分布式提取并保存為pickle,訓(xùn)練可以開始的快些?groupby還是很耗時。

def get_idx_from_days2(data, selected_days, day_columns='Day', mode='train', train_sequence_length=2*24*6, predict_sequence_length=2*24*6, strides=1*6, max_lags=1):""" sample1: 固定間隔,每個間隔選一個sample2: 間隔1-6隨機, 此時先選出每個的間隔序列,再cumsum到原始序列進(jìn)行選擇"""def func(data):return data.tail(predict_sequence_length - 1).index.tolist()def func2(data):return data.head(max(train_sequence_length, max_lags) + 1).index.tolist() cpu_count = os.cpu_count()all_idx = data.loc[data[day_columns].isin(selected_days)].index.tolist()data_grouped = data.groupby(['TurbID'])dropidx = joblib.Parallel(cpu_count)(joblib.delayed(func)(group) for name, group in data_grouped)dropidx = list(itertools.chain(*dropidx))if mode == 'train':dropidx2 = joblib.Parallel(cpu_count)(joblib.delayed(func2)(group) for name, group in data_grouped)dropidx2 = list(itertools.chain(*dropidx2)) dropidx += dropidx2 idx = sorted(list(set(all_idx) - set(dropidx)))return idx

tensorflow可以存成tf-records二進(jìn)制文件加速加載,這里我沒有使用。

特征

本來我最喜歡的結(jié)構(gòu)是數(shù)據(jù)原始列原封不動,作為網(wǎng)絡(luò)輸入。特征部分盡量在神經(jīng)網(wǎng)絡(luò)里使用tf實現(xiàn),感覺只適合簡單任務(wù)與小數(shù)據(jù)。因此,把特征工程部分采用多進(jìn)程完成并保存。或者采用tf.data里的多線程map

pipeline

tensorflow本身的一個優(yōu)勢是其自帶的tf.data模塊,可以高效的給模型喂子彈。官方文檔里有如何
Profiling tf.profiler.experimental.Trace
原來Tensorboard 里有個profile_batch的參數(shù),可以直接幫著分析。由于每次都要端口轉(zhuǎn)發(fā),后來用tensorboard就比較少了, 不過實際訓(xùn)練的時候,還是去掉TB吧,很粘時間也

metrics

預(yù)測48小時,并迭代15天。因此可以很多值預(yù)測了多遍,可以轉(zhuǎn)化一下,用向量方法求出來。在嘗試規(guī)則模型的時候,發(fā)現(xiàn)本地評分過程消耗了兩個小時。單個風(fēng)機消耗的是6秒,為啥到134,就到兩小時了。

首先看了一下代碼,看起來沒有很容易優(yōu)化的地方。那第一步就是把采樣加上去,因為不采樣自己憑一次分要2小時,太久。另一方面,我發(fā)現(xiàn)比賽規(guī)則我第一印象是按個滾動,現(xiàn)在里面也是有采樣的。所以既可以減少時間,也與線上評價更吻合。
發(fā)現(xiàn)循環(huán)的時候,其實可以更簡單點,就是逐行循環(huán),而不是每一輪都篩選。

還是不行的感覺,如果換成多線程感覺比較麻煩。其實,之前我?guī)缀鯖]怎么用過多線程。我一直都有一顆仁慈的人。很多人對待電腦,就像資本家對我們一樣,就不讓閑著。我干完了等別人結(jié)果都不行,非要整什么異步。
最終版本:

def _process(index: int):y_true = pd.read_pickle('../../data/user_data/y_true.pkl')y_pred = pd.read_pickle('../../data/user_data/y_pred.pkl')raw_data = pd.read_pickle('../../data/user_data/valid_df_raw.pkl') predict_sequence_length = y_true.shape[1] - 2total_rows = len(y_true)strides = total_rows // os.cpu_count()start = index * stridesy_true_process = y_true.iloc[start: start+strides]y_pred_process = y_pred.iloc[start: start+strides]scores_process = []for true, pred in zip(y_true_process.iterrows(), y_pred_process.iterrows()): start_time = true[1]['start_time']turbine = true[1]['TurbID']raw_index = raw_data.loc[(raw_data['start_time']== start_time) & (raw_data['TurbID'] == turbine)].index[0] scores_process.append(turbine_score(true[1].iloc[2:].values,pred[1].iloc[2:].values,raw_data.loc[raw_index: raw_index + predict_sequence_length-1]))return scores_process def kdd_score_parallel():#多線程版本,每個線程從保存的pkl中截取自己處理的片段,然后分別處理,最后合成n_process = os.cpu_count()scores = []with multiprocessing.Pool(n_process) as p:process_scores = p.map(_process, range(n_process)) scores.append(process_scores)scores = np.concatenate(scores)scores = scores.reshape([-1, 2]) return scores

做出多線程版本。發(fā)現(xiàn)需要保存下來,才能方便序列化,多核之后從7000秒降到600秒了,幾乎可以達(dá)到實用了。

如果再有心思的話,可以用numba和cython進(jìn)一步優(yōu)化速度。
實驗迭代
另外關(guān)于迭代,就是可以采樣部分?jǐn)?shù)據(jù)進(jìn)行實驗,加速迭代歷程。時序里,當(dāng)然是選擇最后的,或者同期的。
家里條件好的,可以把apex和多卡都搞上。1080這種卡收益不大,那就讓老爺們先走吧。

深刻的感受到了從30分鐘轉(zhuǎn)化為3秒完成,都是因為自己薄弱的基礎(chǔ)。
再比如,主辦方給的tensorflow版本較低,我甚至要降cuda版本才能用。我就給主辦方以時間,一個月沒做比賽,他們就把版本升了。

最后,即使成績暫時不夠好,或生活不如意,問題不大。做時間的朋友,慢慢積累。也許,成績提高了,也許期待就降低了。牢記:給文明以歲月,給自己以時間,路線對了,穩(wěn)贏,無非是小贏、中贏,還是大贏的問題。

以上措施幫助我可以在兩個小時左右完成訓(xùn)練和驗證

總結(jié)

以上是生活随笔為你收集整理的硬件太差不要慌 做时间的朋友的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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