久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    PyTorch深度學(xué)習(xí)模型訓(xùn)練加速指南2021

     520jefferson 2021-01-19

    作者:LORENZ KUHN

    編譯:ronghuaiyang

    導(dǎo)讀

    簡要介紹在PyTorch中加速深度學(xué)習(xí)模型訓(xùn)練的一些最小改動、影響最大的方法。我既喜歡效率又喜歡ML,所以我想我也可以把它寫下來。

    比如說,你正在PyTorch中訓(xùn)練一個深度學(xué)習(xí)模型。你能做些什么讓你的訓(xùn)練更快結(jié)束?

    在這篇文章中,我將概述一些在PyTorch中加速深度學(xué)習(xí)模型訓(xùn)練時改動最小,影響最大的方法。對于每種方法,我會簡要總結(jié)其思想,并估算預(yù)期的加速度,并討論一些限制。我將著重于傳達最重要的部分,并為每個部分給出額外的一些資源。大多數(shù)情況下,我會專注于可以直接在PyTorch中進行的更改,而不需要引入額外的庫,并且我將假設(shè)你正在使用GPU訓(xùn)練模型。

    1. 考慮使用另外一種學(xué)習(xí)率策略

    你選擇的學(xué)習(xí)率對收斂速度以及模型的泛化性能有很大的影響。

    循環(huán)學(xué)習(xí)率和1Cycle學(xué)習(xí)率策略都是Leslie N. Smith提出的方法,然后由推廣。本質(zhì)上,1Cycle學(xué)習(xí)率策略看起來像這樣:

    Sylvain寫道:

    [1cycle由兩個相同長度的步驟組成,一個是從較低的學(xué)習(xí)率到較高的學(xué)習(xí)率,另一個步驟是回到最低的學(xué)習(xí)速率。最大值應(yīng)該是使用Learning Rate Finder選擇的值,較低的值可以低十倍。然后,這個周期的長度應(yīng)該略小于epochs的總數(shù),并且,在訓(xùn)練的最后一部分,我們應(yīng)該允許學(xué)習(xí)率減少超過最小值幾個數(shù)量級。

    在最好的情況下,與傳統(tǒng)的學(xué)習(xí)率策略相比,這種策略可以實現(xiàn)巨大的加速 —— Smith稱之為“超級收斂”。例如,使用1Cycle策略,在ImageNet上減少了ResNet-56訓(xùn)練迭代數(shù)的10倍,就可以匹配原始論文的性能。該策略似乎在通用架構(gòu)和優(yōu)化器之間運行得很好。

    PyTorch實現(xiàn)了這兩個方法,torch.optim.lr_scheduler.CyclicLRtorch.optim.lr_scheduler.OneCycleLR

    這兩個策略的一個缺點是它們引入了許多額外的超參數(shù)。為什么會這樣呢?這似乎并不完全清楚,但一個可能的解釋是,定期提高學(xué)習(xí)率有助于更快的穿越鞍點。

    2. 在 DataLoader中使用多個workers和pinned memory

    當使用torch.utils.data.DataLoader時,設(shè)置num_workers > 0,而不是等于0,設(shè)置pin_memory=True而不是默認值False。詳細解釋:https://pytorch.org/docs/stable/data.html。

    Szymon Micacz通過使用4個workers和pinned memory,實現(xiàn)了單個訓(xùn)練epoch的2倍加速。

    一個經(jīng)驗法則,選擇workers的數(shù)量設(shè)置為可用GPU數(shù)量的4倍,更大或更小的workers數(shù)量會變慢。

    注意,增加num_workers會增加CPU內(nèi)存消耗。

    3. 最大化batch size

    這是一個頗有爭議的觀點。一般來說,然而,似乎使用GPU允許的最大的batch size可能會加速你的訓(xùn)練。注意,如果你修改了batch大小,你還必須調(diào)整其他超參數(shù),例如學(xué)習(xí)率。這里的一個經(jīng)驗法則是,當你把batch數(shù)量翻倍時,學(xué)習(xí)率也要翻倍。

    OpenAI有一篇很好的實證論文關(guān)于不同batch size需要的收斂步驟的數(shù)量。Daniel Huynh運行一些實驗用不同batch大小(使用上面所討論的1Cycle策略),從batch size 64到512他實現(xiàn)了4倍的加速。

    然而,使用大batch的缺點之一是,它們可能會導(dǎo)致泛化能力比使用小batch的模型差。

    4. 使用自動混合精度

    PyTorch 1.6的發(fā)行版包含了對PyTorch進行自動混合精度訓(xùn)練的本地實現(xiàn)。這里的主要思想是,與在所有地方都使用單精度(FP32)相比,某些操作可以在半精度(FP16)下運行得更快,而且不會損失精度。然后,AMP自動決定應(yīng)該以何種格式執(zhí)行何種操作。這允許更快的訓(xùn)練和更小的內(nèi)存占用。

    AMP的使用看起來像這樣:

    import torch
    # Creates once at the beginning of training
    scaler = torch.cuda.amp.GradScaler()

    for data, label in data_iter:
       optimizer.zero_grad()
       # Casts operations to mixed precision
       with torch.cuda.amp.autocast():
          loss = model(data)

       # Scales the loss, and calls backward()
       # to create scaled gradients
       scaler.scale(loss).backward()

       # Unscales gradients and calls
       # or skips optimizer.step()
       scaler.step(optimizer)

       # Updates the scale for next iteration
       scaler.update()

    在NVIDIA V100 GPU上對多個NLP和CV的benchmark進行測試,Huang和他的同事們發(fā)現(xiàn)使用AMP在FP32訓(xùn)練收益率常規(guī)大約2x,但最高可達5.5x。

    目前,只有CUDA ops可以通過這種方式自動轉(zhuǎn)換。

    5. 考慮使用另外的優(yōu)化器

    AdamW是由推廣的具有權(quán)重衰減(而不是L2正則化)的Adam。現(xiàn)在可以在PyTorch中直接使用,torch.optim.AdamW。無論在誤差還是訓(xùn)練時間上,AdamW都比Adam表現(xiàn)更好。

    Adam和AdamW都可以很好地使用上面描述的1Cycle策略。

    還有一些自帶優(yōu)化器最近受到了很多關(guān)注,最著名的是LARS和LAMB。

    NVIDA的APEX實現(xiàn)了許多常見優(yōu)化器的融合版本,如Adam。與Adam的PyTorch實現(xiàn)相比,這種實現(xiàn)避免了大量進出GPU內(nèi)存的操作,從而使速度提高了5%。

    6. 開啟cudNN benchmarking

    如果你的模型架構(gòu)保持不變,你的輸入大小保持不變,設(shè)置torch.backends.cudnn.benchmark = True可能是有益的。這使得cudNN能夠測試許多不同的卷積計算方法,然后使用最快的方法。

    對于加速的預(yù)期有一個粗略的參考,Szymon Migacz達到70%的forward的加速以及27%的forward和backward的加速。

    這里需要注意的是,如果你像上面提到的那樣將batch size最大化,那么這種自動調(diào)優(yōu)可能會變得非常緩慢。

    7. 注意CPU和GPU之間頻繁的數(shù)據(jù)傳輸

    小心使用tensor.cpu()tensor.cuda()頻繁地將張量從GPU和CPU之間相互轉(zhuǎn)換。對于.item().numpy()也是一樣,用.detach()代替。

    如果你正在創(chuàng)建一個新的張量,你也可以使用關(guān)鍵字參數(shù)device=torch.device('cuda:0')直接將它分配給你的GPU。

    如果你確實需要傳輸數(shù)據(jù),在傳輸后使用.to(non_blocking=True)可能會很有用,只要你沒有任何同步點。

    如果你真的需要,你可以試試Santosh Gupta的SpeedTorch,雖然不是很確定在什么情況下可以加速。

    8. 使用gradient/activation檢查點

    直接引用文檔中的話:

    檢查點的工作原理是用計算交換內(nèi)存,并不是存儲整個計算圖的所有中間激活用于向后計算,檢查點不保存中間的激活,而是在向后傳遞中重新計算它們。可以應(yīng)用于模型的任何部分。

    具體來說,在向前傳遞中,function會以torch.no_grad()的方式運行,也就是說,不存儲中間激活。相反,正向傳遞保存輸入和function的參數(shù)。在向后傳遞中,將檢索保存的輸入和function,并再次根據(jù)function計算向前傳遞,然后跟蹤中間的激活,再使用這些激活值計算梯度。

    因此,雖然這可能會略微增加給定batch大小的運行時間,但會顯著減少內(nèi)存占用。這反過來會允許你進一步增加你正在使用的batch大小,從而更好地利用GPU。

    檢查點的pytorch實現(xiàn)為torch.utils.checkpoint,需要想點辦法才能實現(xiàn)的很好。

    9. 使用梯度累加

    增加batch大小的另一種方法是在調(diào)用optimizer.step()之前,在多個.backward()中累積梯度。

    在Hugging Face的實現(xiàn)中,梯度累加可以實現(xiàn)如下:

    model.zero_grad()                                   # Reset gradients tensors
    for i, (inputs, labels) in enumerate(training_set):
        predictions = model(inputs)                     # Forward pass
        loss = loss_function(predictions, labels)       # Compute loss function
        loss = loss / accumulation_steps                # Normalize our loss (if averaged)
        loss.backward()                                 # Backward pass
        if (i+1) % accumulation_steps == 0:             # Wait for several backward steps
            optimizer.step()                            # Now we can do an optimizer step
            model.zero_grad()                           # Reset gradients tensors
            if (i+1) % evaluation_steps == 0:           # Evaluate the model when we...
                evaluate_model()                        # ...have no gradients accumulated

    這個方法主要是為了避開GPU內(nèi)存限制。fastai論壇上的這個討論:https://forums./t/accumulating-gradients/33219/28似乎表明它實際上可以加速訓(xùn)練,所以可能值得一試。

    10. 對于多個GPU使用分布式數(shù)據(jù)并行

    對于分布式訓(xùn)練加速,一個簡單的方法是使用torch.nn.DistributedDataParallel而不是torch.nn.DataParallel。通過這樣做,每個GPU將由一個專用的CPU核心驅(qū)動,避免了DataParallel的GIL問題。

    11. 將梯度設(shè)為None而不是0

    使用.zero_grad(set_to_none=True)而不是.zero_grad()。這樣做會讓內(nèi)存分配器去處理梯度,而不是主動將它們設(shè)置為0。正如在文檔中所說的那樣,這會導(dǎo)致產(chǎn)生一個適度的加速,所以不要期待任何奇跡。

    注意,這樣做并不是沒有副作用的!關(guān)于這一點的詳細信息請查看文檔。

    12. 使用.as_tensor() 而不是 .tensor()

    torch.tensor() 會拷貝數(shù)據(jù),如果你有一個numpy數(shù)組,你想轉(zhuǎn)為tensor,使用 torch.as_tensor() 或是 torch.from_numpy() 來避免拷貝數(shù)據(jù)。

    13. 需要的時候打開調(diào)試工具

    Pytorch提供了大量的有用的調(diào)試工具,如autograd.profiler,autograd.grad_check和autograd.anomaly_detection。在需要的時候使用它們,在不需要它們的時候關(guān)閉它們,因為它們會減慢你的訓(xùn)練。

    14. 使用梯度剪裁

    最初是用于RNNs避免爆炸梯度,有一些經(jīng)驗證據(jù)和一些理論支持認為剪裁梯度(粗略地說:gradient = min(gradient, threshold))可以加速收斂。Hugging Face的Transformer實現(xiàn)是關(guān)于如何使用梯度剪裁以及其他的一些方法如AMP的一個非常干凈的例子。

    在PyTorch中,這可以通過使用torch.nn.utils.clip_grad_norm_實現(xiàn)。我并不完全清楚哪個模型從梯度裁剪中獲益多少,但它似乎對RNN、基于Transformer和ResNets架構(gòu)以及一系列不同的優(yōu)化器都非常有用。

    15. 在BatchNorm之前不使用bias

    這是一個非常簡單的方法:在BatchNormalization 層之前不使用bias。對于二維卷積層,可以將關(guān)鍵字bias設(shè)為False: torch.nn.Conv2d(..., bias=False, ...)

    你會保存一些參數(shù),然而,與這里提到的其他一些方法相比,我對這個方法的加速期望相對較小。

    16. 在驗證的時候關(guān)閉梯度計算

    這個很直接:在驗證的時候使用 torch.no_grad()

    17. 對輸入和batch使用歸一化

    你可能已經(jīng)這么做了,但你可能想再檢查一下:

    • 你的輸入歸一化了嗎?
    • 你是否在使用batch-normalization

    來自評論的額外的技巧:使用 JIT融合point-wise的操作

    如果你有point-wise的操作,你可以使用PyTorch JIT將它們合并成一個FusionGroup,這樣就可以在單個核上啟動,而不是像默認情況下那樣在多個核上啟動。你還可以節(jié)省一些內(nèi)存的讀寫。

    Szymon Migacz展示了如何使用@torch.jit腳本裝飾器來融合GELU中的操作,例如:

    @torch.jit.script
    def fused_gelu(x):
        return x * 0.5 * (1.0 + torch.erf(x / 1.41421))

    在本例中,與未融合的版本相比,融合操作將導(dǎo)致fused_gelu的執(zhí)行速度提高5倍。

    一些相關(guān)的資源

    上面列出的許多技巧來自Szymon Migacz的談話,并發(fā)表在:https://pytorch.org/tutorials/recipes/recipes/tuning_guide.html。

    PyTorch Lightning的William Falcon有兩篇文章:

    https:///9-tips-for-training-lightning-fast-neural-networks-in-pytorch-8e63a502f565

    https:///7-tips-for-squeezing-maximum-performance-from-pytorch-ca4a40951259

    其中有加速訓(xùn)練的技巧。PyTorch Lightning已經(jīng)處理了上面默認的一些點。

    Hugging Face的Thomas Wolf有很多關(guān)于加速深度學(xué)習(xí)的有趣文章,其中特別關(guān)注語言模型。

    Sylvain Gugger和Jeremy Howard也有一些文章:

    關(guān)于學(xué)習(xí)率策略的:https://sgugger./the-1cycle-policy.html,

    關(guān)于找最佳學(xué)習(xí)率的:https://sgugger./how-do-you-find-a-good-learning-rate.html

    AdamW相關(guān)的:https://www./2018/07/02/adam-weight-decay/。

      本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
      轉(zhuǎn)藏 分享 獻花(0

      0條評論

      發(fā)表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 国产情侣激情在线对白| 亚洲精品色无码AV试看| 国产又黄又湿又刺激网站| 久久伊人色AV天堂九九小黄鸭| 色欲综合久久中文字幕网| 国产揄拍国产精品| 午夜美女裸体福利视频| 亚洲欧美高清在线精品一区二区| 九九久久精品国产免费看小说| 日韩国产精品无码一区二区三区| 国产成人久久综合一区| 成人AV无码一区二区三区| 国产鲁鲁视频在线观看| 日韩人妻无码精品久久| 少妇午夜啪爽嗷嗷叫视频| 各种少妇wbb撒尿| 欧美日韩一区二区三区视频播放| 国产在线观看播放av| 狠狠色丁香婷婷综合尤物| 亚洲精品一区二区动漫| 亚洲人成伊人成综合网久久久| 婷婷色香五月综合缴缴情香蕉| 再深点灬舒服灬太大了网站| 69天堂人成无码免费视频 | 国产av一区二区不卡| 亚洲AV无码久久久久网站蜜桃| 亚洲欧洲日产国无高清码图片| 撕开奶罩揉吮奶头高潮AV| 国产精品专区第1页| 99riav国产精品视频| 国产微拍精品一区二区| 免费VA国产高清大片在线| 欧美激情一区二区三区成人| 国产精品老熟女露脸视频| 少妇粗大进出白浆嘿嘿视频| 精品无码国产日韩制服丝袜| 一二三四在线视频观看社区| 老湿机69福利区18禁网站| 国产成人精彩在线视频| 亚洲国产成人无码电影| 亚洲日韩精品欧美一区二区|