淺談PyTorch的可重復(fù)性問(wèn)題(如何使實(shí)驗(yàn)結(jié)果可復(fù)現(xiàn))
由于在模型訓(xùn)練的過(guò)程中存在大量的隨機(jī)操作,使得對(duì)于同一份代碼,重復(fù)運(yùn)行后得到的結(jié)果不一致。因此,為了得到可重復(fù)的實(shí)驗(yàn)結(jié)果,我們需要對(duì)隨機(jī)數(shù)生成器設(shè)置一個(gè)固定的種子。
許多博客都有介紹如何解決這個(gè)問(wèn)題,但是很多都不夠全面,往往不能保證結(jié)果精確一致。我經(jīng)過(guò)許多調(diào)研和實(shí)驗(yàn),總結(jié)了以下方法,記錄下來(lái)。
全部設(shè)置可以分為三部分:
1. CUDNN
cudnn中對(duì)卷積操作進(jìn)行了優(yōu)化,犧牲了精度來(lái)?yè)Q取計(jì)算效率。如果需要保證可重復(fù)性,可以使用如下設(shè)置:
from torch.backends import cudnn cudnn.benchmark = False # if benchmark=True, deterministic will be False cudnn.deterministic = True
不過(guò)實(shí)際上這個(gè)設(shè)置對(duì)精度影響不大,僅僅是小數(shù)點(diǎn)后幾位的差別。所以如果不是對(duì)精度要求極高,其實(shí)不太建議修改,因?yàn)闀?huì)使計(jì)算效率降低。
2. Pytorch
torch.manual_seed(seed) # 為CPU設(shè)置隨機(jī)種子 torch.cuda.manual_seed(seed) # 為當(dāng)前GPU設(shè)置隨機(jī)種子 torch.cuda.manual_seed_all(seed) # 為所有GPU設(shè)置隨機(jī)種子
3. Python & Numpy
如果讀取數(shù)據(jù)的過(guò)程采用了隨機(jī)預(yù)處理(如RandomCrop、RandomHorizontalFlip等),那么對(duì)python、numpy的隨機(jī)數(shù)生成器也需要設(shè)置種子。
import random import numpy as np random.seed(seed) np.random.seed(seed)
最后,關(guān)于dataloader:
注意,如果dataloader采用了多線程(num_workers > 1), 那么由于讀取數(shù)據(jù)的順序不同,最終運(yùn)行結(jié)果也會(huì)有差異。也就是說(shuō),改變num_workers參數(shù),也會(huì)對(duì)實(shí)驗(yàn)結(jié)果產(chǎn)生影響。目前暫時(shí)沒(méi)有發(fā)現(xiàn)解決這個(gè)問(wèn)題的方法,但是只要固定num_workers數(shù)目(線程數(shù))不變,基本上也能夠重復(fù)實(shí)驗(yàn)結(jié)果。
對(duì)于不同線程的隨機(jī)數(shù)種子設(shè)置,主要通過(guò)DataLoader的worker_init_fn參數(shù)來(lái)實(shí)現(xiàn)。默認(rèn)情況下使用線程ID作為隨機(jī)數(shù)種子。如果需要自己設(shè)定,可以參考以下代碼:
GLOBAL_SEED = 1 def set_seed(seed): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed(seed) torch.cuda.manual_seed_all(seed) GLOBAL_WORKER_ID = None def worker_init_fn(worker_id): global GLOBAL_WORKER_ID GLOBAL_WORKER_ID = worker_id set_seed(GLOBAL_SEED + worker_id) dataloader = DataLoader(dataset, batch_size=16, shuffle=True, num_workers=2, worker_init_fn=worker_init_fn)
以上這篇淺談PyTorch的可重復(fù)性問(wèn)題(如何使實(shí)驗(yàn)結(jié)果可復(fù)現(xiàn))就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解使用Selenium爬取豆瓣電影前100的愛(ài)情片相關(guān)信息
這篇文章主要介紹了詳解使用Selenium爬取豆瓣電影前100的愛(ài)情片相關(guān)信息,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Python迭代器iterator生成器generator使用解析
這篇文章主要介紹了Python迭代器iterator生成器generator使用解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
Python實(shí)現(xiàn)把多維數(shù)組展開成DataFrame
今天小編就為大家分享一篇Python實(shí)現(xiàn)把多維數(shù)組展開成DataFrame,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
Python中optparser庫(kù)用法實(shí)例詳解
這篇文章主要介紹了Python中optparser庫(kù)用法實(shí)例詳解,介紹了optparser的引入,初始化等相關(guān)內(nèi)容,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
python elasticsearch從創(chuàng)建索引到寫入數(shù)據(jù)的全過(guò)程
這篇文章主要介紹了python elasticsearch從創(chuàng)建索引到寫入數(shù)據(jù)的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08
Python實(shí)現(xiàn)的Kmeans++算法實(shí)例
這篇文章主要介紹了Kmeans和kmeans++算法,講解了Kmeans算法的缺點(diǎn)和kmeans++算法的實(shí)現(xiàn)思路,以及Python和matlab中實(shí)現(xiàn)的Kmeans++算法,需要的朋友可以參考下2014-04-04

