❝
阿澤推薦:這是 Miracle 同學 Pytorch 系列的第十篇,共有十篇。
至此,該系列便完結了,恭喜能夠堅持下來的同學。
❞
1. 寫在前面
疫情在家的這段時間,想系統的學習一遍 Pytorch 基礎知識,因為我發現雖然直接 Pytorch 實戰上手比較快,但是關于一些内部的原理知識其實并不是太懂,這樣學習起來感覺很不踏實, 對 Pytorch 的使用依然是模模糊糊, 跟着人家的代碼用 Pytorch 玩神經網絡還行,也能讀懂,但自己親手做的時候,直接無從下手,啥也想不起來, 我覺得我這種情況就不是對于某個程式練得不熟了,而是對 Pytorch 本身在自己的腦海根本沒有形成一個概念架構,不知道它内部運作原理和邏輯,是以自己寫的時候沒法形成一個代碼邏輯,就無從下手。這種情況即使背過人家這個程式,那也隻是某個程式而已,不能說會 Pytorch, 并且這種背程式的思想本身就很可怕, 是以我還是習慣學習知識先有架構(至少先知道有啥東西)然後再通過實戰(各個東西具體咋用)來填充這個架構。而這個系列的目的就是在腦海中先建一個 Pytorch 的基本架構出來, 學習知識,知其然,知其是以然才更有意思;)。
今天是本系列的第十篇,也是最後一篇了, 哈哈,又是十全十美,正好,希望這十篇文章,能讓你在腦海中建立一個關于 Pytorch 的架構,真正的做到 Pytorch 的入門。通過前面的 9 篇文章,我們就可以通過 Pytorch 搭建一個模型并且進行有效的訓練,而模型搭建完了之後我們要儲存下來,以備後面的使用,并且在大型任務中我們不可能從頭自己搭模組化型,往往需要模型的遷移, 為了提高訓練效率,我們往往需要使用 GPU, 最後再整理一些 Pytorch 中常見的報錯作為結束。是以今天的這篇内容,我們從模型的儲存與加載, 模型的微調技術, GPU 使用和 Pytorch 常見報錯四方面來整理。
大綱如下:
- 模型的儲存與加載
- 模型的 finetune
- GPU 使用
- Pytorch 的常見報錯
2. 模型的儲存與加載
我們的建立的模型訓練好了是需要儲存的,以備我們後面的使用,是以究竟如何儲存模型和加載模型呢?我們下面重點來看看, 主要分為三塊:首先介紹一下序列化和反序列化,然後介紹模型儲存和加載的兩種方式,最後是斷點的續訓練技術。
2.1 序列化與反序列化
序列化就是說記憶體中的某一個對象儲存到硬碟當中,以二進制序列的形式存儲下來,這就是一個序列化的過程。而反序列化,就是将硬碟中存儲的二進制的數,反序列化到記憶體當中,得到一個相應的對象,這樣就可以再次使用這個模型了。

序列化和反序列化的目的就是将我們的模型長久的儲存。
Pytorch 中序列化和反序列化的方法:
- torch.save (obj, f):
表示對象, 也就是我們儲存的資料,可以是模型,張量, dict 等等,obj
表示輸出的路徑f
- torch.load (f, map_location):
表示檔案的路徑,f
指定存放位置, CPU 或者 GPU, 這個參數挺重要,在使用 GPU 訓練的時候再具體說。map_location
2.2 模型儲存與加載的兩種方式
Pytorch 的模型儲存有兩種方法, 一種是儲存整個 Module, 另外一種是儲存模型的參數。
- 儲存和加載整個 Module:torch.save (net, path), torch.load (fpath)
- 儲存模型參數:torch.save (net.state_dict (), path), net.load_state_dict (torch.load (path))
第一種方法比較懶,儲存整個的模型架構, 比較費時占記憶體, 第二種方法是隻保留模型上的可學習參數, 等建立一個新的網絡結構,然後放上這些參數即可,是以推薦使用第二種。 下面通過代碼看看具體怎麼使用:這裡先建立一個網絡模型:
class LeNet2 (nn.Module):
def __init__(self, classes):
super (LeNet2, self).__init__()
self.features = nn.Sequential (
nn.Conv2d (3, 6, 5),
nn.ReLU (),
nn.MaxPool2d (2, 2),
nn.Conv2d (6, 16, 5),
nn.ReLU (),
nn.MaxPool2d (2, 2)
)
self.classifier = nn.Sequential (
nn.Linear (16*5*5, 120),
nn.ReLU (),
nn.Linear (120, 84),
nn.ReLU (),
nn.Linear (84, classes)
)
def forward (self, x):
x = self.features (x)
x = x.view (x.size ()[0], -1)
x = self.classifier (x)
return x
def initialize (self):
for p in self.parameters ():
p.data.fill_(20191104)
## 建立一個網絡
net = LeNet2 (classes=2019)
# "訓練"
print ("訓練前:", net.features [0].weight [0, ...])
net.initialize ()
print ("訓練後:", net.features [0].weight [0, ...])
下面就是儲存整個模型和儲存模型參數的方法:
通過上面,我們已經把模型儲存到硬碟裡面了,那麼如果要用的時候,應該怎麼導入呢? 如果我們儲存的是整個模型的話, 那麼導入的時候就非常簡單, 隻需要:
path_model = "./model.pkl"
net_load = torch.load (path_model)
并且我們可以直接列印出整個模型的結構:
下面看看隻保留模型參數的話應該怎麼再次使用:
上面就是兩種模型加載與儲存的方式了,使用起來也是非常簡單的,推薦使用第二種。
2.3 模型斷點續訓練
斷點續訓練技術就是當我們的模型訓練的時間非常長,而訓練到了中途出現了一些意外情況,比如斷電了,當再次來電的時候,我們肯定是希望模型在中途的那個地方繼續往下訓練,這就需要我們在模型的訓練過程中儲存一些斷點,這樣發生意外之後,我們的模型可以從斷點處繼續訓練而不是從頭開始。 是以模型訓練過程中設定 checkpoint 也是非常重要的。
那麼就有一個問題了, 這個 checkpoint 裡面需要保留哪些參數呢? 我們可以再次回憶模型訓練的五個步驟:資料 -> 模型 -> 損失函數 -> 優化器 -> 疊代訓練。 在這五個步驟中,我們知道資料,損失函數這些是沒法變得, 而在疊代訓練過程中,我們模型裡面的可學習參數, 優化器裡的一些緩存是會變的, 是以我們需要保留這些東西。是以我們的 checkpoint 裡面需要儲存模型的資料,優化器的資料,還有疊代到了第幾次。
下面通過人民币二分類的實驗,模拟一個訓練過程中的意外中斷和恢複,看看怎麼使用這個斷點續訓練:
我們上面發生了一個意外中斷,但是我們設定了斷點并且進行儲存,那麼我們下面就進行恢複, 從斷點處進行訓練,也就是上面的第 6 個 epoch 開始,我們看看怎麼恢複斷點訓練:
是以在模型的訓練過程當中, 以一定的間隔去儲存我們的模型,儲存斷點,在斷點裡面不僅要儲存模型的參數,還要儲存優化器的參數。這樣才可以在意外中斷之後恢複訓練。
3. 模型的 finetune
在說模型的 finetune 之前,得先知道一個概念,就是遷移學習。
遷移學習:機器學習分支, 研究源域的知識如何應用到目标域,将源任務中學習到的知識運用到目标任務當中,用來提升目标任務裡模型的性能。
是以,當我們某個任務的資料比較少的時候,沒法訓練一個好的模型時, 就可以采用遷移學習的思路,把類似任務訓練好的模型給遷移過來,由于這種模型已經在原來的任務上訓練的差不多了,遷移到新任務上之後,隻需要微調一些參數,往往就能比較好的應用于新的任務, 當然我們需要在原來模型的基礎上修改輸出部分,畢竟任務不同,輸出可能不同。這個技術非常實用。但是一定要注意,類似任務上模型遷移(不要試圖将一個 NLP 的模型遷移到 CV 裡面去)
模型微調的步驟:
- 擷取預訓練模型參數(源任務當中學習到的知識)
- 加載模型(load_state_dict)将學習到的知識放到新的模型
- 修改輸出層, 以适應新的任務
模型微調的訓練方法:
- 固定預訓練的參數 (requires_grad=False; lr=0)
- Features Extractor 較國小習率 (params_group)
好了,下面就通過一個例子,看看如何使用模型的 finetune:
下面使用訓練好的 ResNet-18 進行二分類:讓模型分出螞蟻和蜜蜂:
訓練集 120 張, 驗證集 70 張,是以我們可以看到這裡的資料太少了,如果我們建立立模型進行訓練預測,估計沒法訓練。是以看看遷移技術, 我們用訓練好的 ResNet-18 來完成這個任務。
首先我們看看 ResNet-18 的結構,看看我們需要在哪裡進行改動:
下面看看具體應該怎麼使用:
當然,訓練時的 trick 還有第二個,就是不當機前面的層,而是修改前面的參數學習率,因為我們的優化器裡面有參數組的概念,我們可以把網絡的前面和後面分成不同的參數組,使用不同的學習率進行訓練,目前面的學習率為 0 的時候,就是和當機前面的層一樣的效果了,但是這種寫法比較靈活
通過模型的遷移,可以發現這個任務就會完成的比較好。
4. GPU 的使用
4.1 CPU VS GPU
CPU(Central Processing Unit, 中央處理器):主要包括控制器和運算器 GPU(Graphics Processing Unit, 圖形處理器):處理統一的, 無依賴的大規模資料運算
4.2 資料遷移至 GPU
首先, 這個資料主要有兩種:Tensor 和 Module
- CPU -> GPU:data.to ("cpu")
- GPU -> CPU: data.to ("cuda")
to 函數:轉換資料類型 / 裝置
- tensor.to (*args,kwargs)
x = torch.ones ((3,3)) x = x.to (torch.float64) # 轉換資料類型 x = torch.ones ((3,3)) x = x.to ("cuda") # 裝置轉移
- module.to (*args,kwargs)
上面兩個方法的差別:張量不執行 inplace, 是以上面看到需要等号重新指派,而模型執行 inplace, 是以不用等号重新指派。下面從代碼中學習上面的兩個方法:linear = nn.Linear (2,2) linear.to (torch.double) # 這樣模型裡面的可學習參數的資料類型變成 float64 gpu1 = torch.device ("cuda") linear.to (gpu1) # 把模型從 CPU 遷移到 GPU
下面看一下 Module 的pytorch checkpoint_【Pytorch 】筆記十:剩下的一些内容(完結)1. 寫在前面2. 模型的儲存與加載3. 模型的 finetune4. GPU 的使用5. Pytorch 的常見報錯6. 總結
函數:to
如果模型在 GPU 上, 那麼資料也必須在 GPU 上才能正常運作。也就是說資料和模型必須在相同的裝置上。pytorch checkpoint_【Pytorch 】筆記十:剩下的一些内容(完結)1. 寫在前面2. 模型的儲存與加載3. 模型的 finetune4. GPU 的使用5. Pytorch 的常見報錯6. 總結
torch.cuda 常用的方法:
- torch.cuda.device_count (): 計算目前可見可用的 GPU 數
- torch.cuda.get_device_name (): 擷取 GPU 名稱
- torch.cuda.manual_seed (): 為目前 GPU 設定随機種子
- torch.cuda.manual_seed_all (): 為所有可見可用 GPU 設定随機種子
- torch.cuda.set_device (): 設定主 GPU(預設 GPU)為哪一個實體 GPU(不推薦) 推薦的方式是設定系統的環境變量:
通過這個方法合理的配置設定 GPU,使得多個人使用的時候不沖突。但是這裡要注意一下, 這裡的 2,3 指的是實體 GPU 的 2,3。但是在邏輯 GPU 上, 這裡表示的 0,1。 這裡看一個對應關系吧:os.environ.setdefault ("CUDA_VISIBLE_DEVICES","2,3")
那麼假設我這個地方設定的實體 GPU 的可見順序是 0,3,2 呢?實體 GPU 與邏輯 GPU 如何對應?pytorch checkpoint_【Pytorch 】筆記十:剩下的一些内容(完結)1. 寫在前面2. 模型的儲存與加載3. 模型的 finetune4. GPU 的使用5. Pytorch 的常見報錯6. 總結 這個到底幹啥用呢? 在邏輯 GPU 中,我們有個主 GPU 的概念,通常指的是 GPU0。 而這個主 GPU 的概念,在多 GPU 并行運算中就有用了。pytorch checkpoint_【Pytorch 】筆記十:剩下的一些内容(完結)1. 寫在前面2. 模型的儲存與加載3. 模型的 finetune4. GPU 的使用5. Pytorch 的常見報錯6. 總結
4.3 多 GPU 并行運算
多 GPU 并且運算, 簡單的說就是我又很多塊 GPU,比如 4 塊, 而這裡面有個主 GPU, 當拿到樣本資料之後,比如主 GPU 拿到了 16 個樣本, 那麼它會經過 16/4=4 的運算,把資料分成 4 份, 自己留一份,然後把那 3 份分發到另外 3 塊 GPU 上進行運算, 等其他的 GPU 運算完了之後, 主 GPU 再把結果收回來負責整合。這時候看到主 GPU 的作用了吧。多 GPU 并行運算可以大大節省時間。是以, 多 GPU 并行運算的三步:分發 -> 并行計算 -> 收回結果整合。
Pytorch 中的多 GPU 并行運算機制如何實作呢?
torch.nn.DataParallel
: 包裝模型,實作分發并行機制。
主要參數:
- module: 需要包裝分發的模型
- device_ids: 可分發的 gpu, 預設分發到所有的可見可用GPU, 通常這個參數不管它,而是在環境變量中管這個。
- output_device: 結果輸出裝置, 通常是輸出到主 GPU
下面從代碼中看看多 GPU 并行怎麼使用:
由于這裡沒有多 GPU,是以可以看看在多 GPU 伺服器上的一個運作結果:
下面這個代碼是多 GPU 的時候,檢視每一塊 GPU 的緩存,并且排序作為邏輯 GPU 使用, 排在最前面的一般設定為我們的主 GPU:
def get_gpu_memory ():
import platform
if 'Windows' != platform.system ():
import os
os.system ('nvidia-smi -q -d Memory | grep -A4 GPU | grep Free > tmp.txt')
memory_gpu = [int (x.split ()[2]) for x in open ('tmp.txt', 'r').readlines ()]
os.system ('rm tmp.txt')
else:
memory_gpu = False
print ("顯存計算功能暫不支援 windows 作業系統")
return memory_gpu
gpu_memory = get_gpu_memory ()
if not gpu_memory:
print ("\ngpu free memory: {}".format (gpu_memory))
gpu_list = np.argsort (gpu_memory)[::-1]
gpu_list_str = ','.join (map (str, gpu_list))
os.environ.setdefault ("CUDA_VISIBLE_DEVICES", gpu_list_str)
device = torch.device ("cuda" if torch.cuda.is_available () else "cpu")
在 GPU 模型加載當中常見的兩個問題:
這個報錯是我們的模型是以 cuda 的形式進行儲存的,也就是在 GPU 上訓練完儲存的,儲存完了之後我們想在一個沒有 GPU 的機器上使用這個模型,就會報上面的錯誤。是以解決辦法就是:
torch.load (path_state_dict, map_location="cpu")
, 這樣既可以在 CPU 裝置上加載 GPU 上儲存的模型了。
這個報錯資訊是出現在我們用多 GPU 并行運算的機制訓練好了某個模型并儲存,然後想再建立一個普通的模型使用儲存好的這些參數,就會報這個錯誤。這是因為我們在多 GPU 并行運算的時候,我們的模型 net 先進行一個并行的一個包裝,這個包裝使得每一層的參數名稱前面會加了一個 module。這時候,如果我們想把這些參數移到我們普通的 net 裡面去,發現找不到這種
module.
開頭的這些參數,即比對不上,因為我們普通的 net 裡面的參數是沒有前面的 module 的。這時候我們就需要重新建立一個字典,把名字改了之後再導入。我們首先先在多 GPU 的環境下,建立一個網絡,并且進行包裝,放到多 GPU 環境上訓練儲存:
下面主要是看看加載的時候是怎麼報錯的:
那麼怎麼解決這種情況呢?下面這幾行代碼就可以搞定了:
from collections import OrderedDict
new_state_dict = OrderedDict ()
for k, v in state_dict_load.items ():
namekey = k [7:] if k.startswith ('module.') else k
new_state_dict [namekey] = v
print ("new_state_dict:\n {}".format (new_state_dict))
net.load_state_dict (new_state_dict)
下面看看效果:
5. Pytorch 的常見報錯
這裡先給出一份 Pytorch 常見錯誤與坑的一份文檔:https://shimo.im/docs/PvgHytYygPVGJ8Hv,這裡面目前有一些常見的報錯資訊,可以檢視, 也歡迎大家貢獻報錯資訊。
- 報錯:
可能的原因:傳入的 Dataset 中的ValueError: num_samples should be a positive interger value, but got num_samples=0
, 即傳入該 DataLoader 的 dataset 裡沒有資料。解決方法:len (self.data_info)==0
- 檢查 dataset 中的路徑
- 檢查 Dataset 的__len__() 函數為何輸出 0
- 報錯:
可能原因:目前操作需要 PIL Image 或 ndarry 資料類型, 但傳入了 Tensor 解決方法:TypeError: pic should be PIL Image or ndarry. Got
- 檢查 transform 中是否存在兩次 ToTensor () 方法
- 檢查 transform 中每一個操作的資料類型變化
- 報錯:
可能的原因:dataloader 的__getitem__函數中,傳回的圖檔形狀不一緻,導緻無法 stack 解決方法:檢查__getitem__函數中的操作RuntimeError: invalid argument 0: Sizes of tensors must match except in dimension 0. Got 93 and 89 in dimension 1 at /Users/soumith/code/builder/wheel/pytorch-src/aten/src/TH/generic/THTensorMath.cpp:3616
- 報錯:
可能的原因:網絡層輸入資料與網絡的參數不比對 解決方法:conv: RuntimeError: Given groups=1, weight of size 6 1 5 5, expected input [16, 3, 32, 32] to have 1 channels, but got 3 channels instead linear: RuntimeError: size mismatch, m1: [16 x 576], m2: [400 x 120] at ../aten/src/TH/generic/THTensorMath.cpp:752
- 檢查對應網絡層前後定義是否有誤
- 檢查輸入資料 shape
- 報錯:
可能的原因:并行運算時,模型被 dataparallel 包裝,所有 module 都增加一個屬性 module. 是以需要通過AttributeError: 'DataParallel' object has no attribute 'linear'
調用 解決方法:net.module.linear
- 網絡層前加入 module.
- 報錯:
可能的原因:gpu 訓練的模型儲存後,在無 gpu 裝置上無法直接加載 解決方法:python RuntimeError: Attempting to deserialize object on a CUDA device but torch.cuda.is_available () is False. If you are running on a CPU-only machine, please use torch.load with map_location=torch.device ('cpu') to map your storages to the CPU.
- 需要設定 map_location="cpu"
- 報錯:
這個就是如果我們儲存了整個網絡模型需要重新加載進來的時候要注意的地方。 需要先定義網絡的類。AttributeError: Can't get attribute 'FooNet2' on 可能的原因:儲存的網絡模型在目前 python 腳本中沒有定義 解決方法:
- 提前定義該類
- 報錯:
可能的原因:标簽數大于等于類别數量,即不滿足 cur_target < n_classes,通常是因為标簽從 1 開始而不是從 0 開始 解決方法:修改 label,從 0 開始,例如:10 分類的标簽取值應該是 0-9 交叉熵損失函數中會見到的。RuntimeError: Assertion cur_target >= 0 && cur_target < n_classes' failed. at ../aten/src/THNN/generic/ClassNLLCriterion.c:94
- 報錯:
可能的原因:需計算的兩個資料不在同一個裝置上 解決方法:采用 to 函數将資料遷移到同一個裝置上python RuntimeError: expected device cuda:0 and dtype Long but got device cpu and dtype Long Expected object of backend CPU but got backend CUDA for argument #2 'weight'
- 報錯:
可能原因:記憶體不夠(不是 gpu 顯存,是記憶體) 解決方法:申請更大記憶體RuntimeError: DataLoader worker (pid 27) is killed by signal: Killed. Details are lost due to multiprocessing. Rerunning with num_workers=0 may give better error trace.
- 報錯:
可能的原因:采用 BCE 損失函數的時候,input 必須是 0-1 之間,由于模型最後沒有加 sigmoid 激活函數,導緻的。解決方法:讓模型輸出的值域在 [0, 1]RuntimeError: reduce failed to synchronize: device-side assert triggered
- 報錯:
torch.load 加載模型過程報錯,因為模型傳輸過程中有問題,重新傳一遍模型即可RuntimeError: unexpected EOF. The file might be corrupted.
- 報錯:
可能的原因:python2 儲存,python3 加載,會報錯 解決方法:把 encoding 改為 encoding='iso-8859-1' check_p = torch.load (path, map_location="cpu", encoding='iso-8859-1')UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 1: invalid start byte
- 報錯:
問題原因:資料張量已經轉換到 GPU 上,但模型參數還在 cpu 上,造成計算不比對問題。解決方法:通過添加 model.cuda () 将模型轉移到 GPU 上以解決這個問題。或者通過添加 model.to (cuda) 解決問題RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same
6. 總結
這篇文章到這裡也就結束了,也就意味着 Pytorch 的基礎知識,基本概念也都整理完畢,首先先快速回顧一下這次學習的知識,這次學習的比較雜了,把一些零零散散的知識放到這一篇文章裡面。首先學習了模型的儲存與加載問題,介紹了兩種模型儲存與加載的方法, 然後學習了模型的微調技術,這個在遷移學習中用處非常大,還介紹了遷移學習中常用的兩個 trick。然後學習了如何使用 GPU 加速訓練和 GPU 并行訓練方式, 最後整理了 Pytorch 中常見的幾種報錯資訊。
到這裡為止,關于 Pytorch 的基本知識結束, 下面也對這十篇文章進行一個梳理和總結,這十篇文章的邏輯其實也非常簡單,就是圍繞着機器學習模型訓練的五大步驟進行展開的:首先是先學習了一下《Pytorch 的基本知識》知道了什麼是張量, 然後學習了《自動求導系統,計算圖機制》, 對 Pytorch 有了一個基本的了解之後,我們就開始學習《Pytorch 的資料讀取機制》,在裡面知道了 DataLoader 和 Dataset,還學習了圖像預處理的子產品 transform。接着學習《模型子產品》,知道了如何去搭建一個模型,一個模型是怎麼去進行初始化的,還學習了容器,《常用網絡層的使用》。再往後就是《網絡層的權重初始化方法和 8 種損失函數》, 有了損失函數之後,接着就開始學習《各種優化器》幫助我們更新參數,還有學習率調整的各種政策。有了資料,模型,損失,優化器,就可以疊代訓練模型了,是以在疊代訓練過程中學習了《Tensorboard》這個非常強大的可視化工具,可以幫助我們更好的監控模型訓練的效果,這裡面還順帶介紹了點進階技術 hook 機制。然後學習了《正則化和标準化技術》, 正則化可以幫助緩解模型的過拟合,這裡面學習了 L1,L2 和 Dropout 的原理和使用,而标準化可以更好的解決資料尺度不平衡的問題,這裡面有 BN, LN, IN, GN 四種标準化方法,并對比了它們的不同及應用場景。 最後我們以一篇雜記作為收尾,雜記裡面學習了模型的儲存加載,模型微調,如何使用 GPU 以及常用的報錯。這就是這十篇文章的一個邏輯了。
希望這些知識能幫助你真正的入門 Pytorch,在腦海中建立一個 Pytorch 學習架構,掌握 Pytorch 的内部運作機制, 學習知識,知其然,更要知其是以然,這樣在以後用起來的時候才能體會更加深刻。這十篇文章用了大約半個月的時間整理總結, 學習完之後,收獲很多,當然這種收獲不是立馬就能用 Pytorch 訓練一個神經網絡出來,立即用 Pytorch 搞定一個項目,而是 Pytorch 在我腦海中不是那麼的陌生了,慢慢的變得熟悉起來, 從 DataLoader 和 Dataset 的運作機制,差不多對 Pytorch 的資料讀取有了一個了解,從各種模型搭建的過程,權重初始化,損失函數有哪些怎麼用,優化器的運作原理漸漸的熟悉了一個模型應該怎麼去訓練。這樣過來一遍之後,真的能深入了解每一個細節,也知道了模型訓練中出現的一些問題,比如權重初始化不适當就容易出現梯度消失和爆炸,在代碼中的結果就是容易 nan。再比如損失不下降反而上升, 這有可能是學習率過大導緻的, 還有各種技術及原理,真的是收獲頗多,也希望你也有所收獲吧。
這十篇文章雖然裡面圖檔很多,還有各種調試, 整體看起來還是挺亂的, 相信大家看起來也心煩意亂,能堅持看完的并不會太多,但依然希望能有所幫助,即使沒法看完一遍,等遇到問題了,當做查閱的手冊也可以,反正我是這樣的,這十篇文章寫得過程中沒有注意各種排版啥的,依然是以詳細為主,是以為了說明原理,我用了各種調試,各種圖檔,這樣回來看的時候就能很容易記起來,畢竟隻看一遍肯定是記不住的,我後期依然會回來查閱觀看。
踏踏實實的搞定這十篇文章,相信對 Pytorch 真正入門了,那麼接下來就可以去用 Pytorch 做一些項目了,想象一下,當你無障礙讀懂大佬的 Pytorch 代碼,當你無障礙用 Pytorch 複現論文,無障礙用 Pytorch 實作項目, 理直氣壯對面試官說熟悉 Pytorch,那是多麼的爽, 哈哈, 爽一下即可, 先别睡,Pytorch 的路依然是任重而道遠,因為這些都得去練,如果想無障礙手寫神經網絡, 就得照着代碼反複練,反複看,重點是練習手寫神經網絡的感覺,然後多做項目,多寫代碼,依然是那句話無它,唯手熟爾;)
所有代碼連結:
❝
連結:https://pan.baidu.com/s/1c5EYdd0w8j6w3g54KTxJJA 提取碼:k7rh
❞
阿澤的學習交流群開通了,加微信,我拉你進群(有問題在群裡聊,可以集思廣益):