手把手教你學會深度學習框架 — PyTorch

摘要: PyTorch是一個基於Python語言的深度學習框架,專門針對 GPU 加速的深度神經網絡(DNN)的程序開發。基本上,它全部的程序都是用python寫的,這就使得它的源碼看上去比較簡潔,在機器學習領域中有普遍的應用。

PyTorch是一個靈活的深度學習框架,它容許經過動態神經網絡(即if條件語句和while循環語句那樣利用動態控制流的網絡)自動分化。它支持GPU加速、分佈式訓練、多種優化以及更多的、更簡潔的特性。python

神經網絡是計算圖形的一個子類。計算圖形接收輸入數據,而且數據被路由到那些可能由對數據進行處理的節點進行轉換。在深度學習中,神經網絡中的神經元一般用參數和可微函數進行數據變換,從而能夠經過梯度降低來優化參數以最大程度的減小損失。更普遍來講,函數能夠是隨機的,而且圖形的結構能夠是動態的。所以,雖然神經網絡能夠很好地適合數據流開發,可是PyTorch的API卻圍繞着命令行式的編程,這是一種更常見的考慮程序的方式。這使得讀取複雜程序的代碼和理由變得更容易,而沒必要浪費大量的性能;PyTorch實際上運行的速度至關快,並帶有不少優化,你能夠放心地忘記你是個最終用戶。算法

該文件的其他部分是基於官方的MNIST示例,而且應該僅僅是在學習了官方初級教程以後再看。爲了提升可讀性,代碼放在了帶有註釋的區塊中,所以不會被分割成不一樣的函數或者是文件,由於一般要用於清晰的、模塊化的代碼。編程

clipboard.png

這些是很是標準的程序或者是包導入代碼,特別是用於解決計算機視覺問題的視覺模塊:數組

clipboard.png

argparse是一種處理在Python中命令行參數的標準方法。網絡

它是一種編寫與設備無關的代碼的好方法(在可用時受益於GPU加速,但當不可用時則返回到CPU)是選擇並保存適當的torch.device,它能夠用來決定應該存儲張量的位置。更多資料請參閱官方文檔。PyTorch方法是將設備放置在用戶的控制之下,這對於簡單的例子來講可能看起來是件討厭的事情,可是它使得更容易計算出張量的位置是對調試有用仍是使得手動使用設備變得高效。多線程

對於可重複的實驗,有必要爲任何使用隨機數生成的進行隨機種子設置。注意,cuDNN使用非肯定性算法,而且可使用torch.backends.cudnn.enabled = False來進行禁用。框架

clipboard.png

因爲torchvision模型在~/.torch/models/下面進行保存的,我在~/.torch/datasets保存torchvision數據集。一般來講,若是結束重用幾個數據集,那麼將數據集與代碼分離開來存放是很是值得的。torchvision.transforms包含不少給單個圖片的方便轉換的功能,如修剪和正常化。機器學習

DataLoader含有許多可選方案,可是在batch_size和shuffle參數以外,num_workers和pin_memory對於效率也是值得了解一下的。num_workers > 0使用了子進程來進行異步加載數據,而不是在這個過程當中使用主進程塊。pin_memory使用pinned RAM來加速RAM到GPU的傳輸。異步

clipboard.png

網絡初始化一般包括一些成員變量和可訓練參數的層,以及可能分開的可訓練參數和不可訓練的緩衝器。前向傳遞以後,使用那些來自純函數F的函數(不包含參數)的結合。有些人傾向具備徹底功能的網絡(例如,保持參數分離和使用F.conv2d,而不是nn.Conv2d)或者是那些徹底分層的網絡(例如,nn.ReLU,而不是F.relu)。分佈式

.to(device)是將設備參數(和緩衝器)發送到GPU的簡便方法,若是設備被設置爲GPU,則不作任何操做(當設備被設置爲CPU)時。在將網絡參數傳遞給優化器以前,將它們傳遞給合適的設備是很是重要的,不然優化器將不會正確跟蹤參數。

神經網絡(nn.Module)和優化器(optim.Optimizer)都具備保存和加載其內部狀態的能力,而且.load_state_dict(state_dict)是推薦這麼作的方法,你將須要從新加載這兩個狀態以恢復以前保存的狀態字典的訓練。保存整個對象可能會容易出錯。

這裏沒有指出的一些要點是,正向傳遞可使用控制流,例如,成員變量,或者甚至數據自己能夠決定if語句的執行。在中間打印出張量也是很是有效的,這會使調試變得更加容易。最後,前向傳遞可使用多個參數。用一個簡短的代碼片斷來講明這一點:

clipboard.png

默認狀況下,網絡模塊設置爲訓練模式—這影響了一些模塊的運行效果,最明顯的是流失和批量標準化。不管如何,最好經過.train()來進行手動設置參數,它將訓練標誌繼承到全部的子模塊。

在用loss.backward()收集一組新的梯度並用optimiser.step()進行反向傳播以前,有必要手動地集中那些用優化器.zero_grad()優化過了參數的梯度。默認狀況下,PyTorch逐漸增長梯度,這是很是方便的,尤爲是當你沒有足夠的資源來計算全部你一次性須要的梯度的時候。

PyTorch使用基於磁帶的自動梯度系統—它按必定的順序收集對張量進行的操做,而後對它們進行重放以進行逆向模式求導。這就是爲何它是超級靈活的緣由,而且容許任意的計算圖形。若是張量中沒有一個須要梯度(當構造張量時,你必須設置requires_grad=True),則不存儲任何圖形!然而,網絡每每趨向那些具備須要梯度的參數,因此從一個網絡的輸出所作的任何計算都將存儲在圖形中。所以,若是要想存儲由此產生的數據,那麼你須要手動禁用梯度,或者更常見地,將其存儲爲Python數字(經過使用PyTorch標量上的.item())或numpy數組。請在autograd上參閱官方文檔以瞭解更多信息。

切割計算圖形的一種方法是使用.detach(),當經過截斷反向傳播時間來訓練RNNs時,可使用這個方法來隱藏狀態。當一個成分是另外一個網絡的輸出時,它也很方便的區分一個損耗,可是這個網絡不該該在損失方面被優化 — 例如在GAN訓練中從生成器的輸出中訓練一個鑑別器,或者使用值函數做爲基線(例如A2C)的算法訓練一個演員評論算法的策略,另外一種防止梯度計算的技術在GAN訓練中是有效的(訓練來自鑑別器的生成器),以及一般在微調中是經過網絡參數並設置param.requires_grad = False進行循環。

除了在控制檯或者在日誌文件中的日誌記錄結果外,檢查點模型參數(和優化器狀態)是很是重要的,用於以防萬一。你還可使用torch.save()來保存普通的Python對象,但其它標準選擇包括在內置的配置中。

clipboard.png

其餘:

CUDA調試錯誤,一般是邏輯問題,會在CPU上產生更明白易懂的錯誤消息。若是你正在計劃使用GPU,最好的方式是能在CPU和GPU之間輕鬆地切換。一個更廣泛的開發技巧是可以設置你的代碼,以便在啓動一個合適的工做任務以前快速運行全部的邏輯來檢查代碼—示例是準備一個小的、合成的數據集,運行一個訓練、測試周期等等。若是是一個CUDA錯誤,或者你真的不能切換到CPU模式,那麼設置CUDA_LAUNCH_BLOCKING=1將使CUDA內核同步啓動,從而會提供更清楚明確的錯誤消息。

對於torch.multiprocessing的記錄,甚至只是一次性運行多個PyTorch腳本。由於PyTorch使用多線程的BLAS庫來加速CPU上的線性代數運算,所以它一般會使用多個內核。若是想同時使用多個處理進程或者多個腳原本運行多個程序,那麼你能夠手動地經過將環境變量OMP_NUM_THREADS設置爲1或另外一個小的數字參數來實現—這減小了CPU大幅震動的機會。官方文檔中有特別用於多處理技術的註釋。

本文做者:【方向】

閱讀原文

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索