系統學習Pytorch筆記十: 模型的保存加載、模型微調、GPU使用及Pytorch常見報錯

Pytorch官方英文文檔:https://pytorch.org/docs/stable/torch.html?
Pytorch中文文檔:https://pytorch-cn.readthedocs.io/zh/latest/

1. 寫在前面

疫情在家的這段時間,想系統的學習一遍Pytorch基礎知識,因爲我發現雖然直接Pytorch實戰上手比較快,但是關於一些內部的原理知識其實並不是太懂,這樣學習起來感覺很不踏實, 對Pytorch的使用依然是模模糊糊, 跟着人家的代碼用Pytorch玩神經網絡還行,也能讀懂,但自己親手做的時候,直接無從下手,啥也想不起來, 我覺得我這種情況就不是對於某個程序練得不熟了,而是對Pytorch本身在自己的腦海根本沒有形成一個概念框架,不知道它內部運行原理和邏輯,所以自己寫的時候沒法形成一個代碼邏輯,就無從下手。 這種情況即使背過人家這個程序,那也只是某個程序而已,不能說會Pytorch, 並且這種背程序的思想本身就很可怕, 所以我還是習慣學習知識先有框架(至少先知道有啥東西)然後再通過實戰(各個東西具體咋用)來填充這個框架。 而這個系列的目的就是在腦海中先建一個Pytorch的基本框架出來, 學習知識,知其然,知其所以然才更有意思 😉

今天是本系列的第十篇,也是最後一篇了, 哈哈,又是十全十美,正好,希望這十篇文章,能讓你在腦海中建立一個關於Pytorch的框架,真正的做到Pytorch的入門。 通過前面的9篇文章,我們就可以通過Pytorch搭建一個模型並且進行有效的訓練,而模型搭建完了之後我們要保存下來,以備後面的使用,並且在大型任務中我們不可能從頭自己搭建模型,往往需要模型的遷移, 爲了提高訓練效率,我們往往需要使用GPU, 最後再整理一些Pytorch中常見的報錯作爲結束。 所以今天的這篇內容,我們從模型的保存與加載, 模型的微調技術, GPU使用和Pytorch常見報錯四方面來整理。

注意,本系列都默認已經安裝了Cuda,搭建好了Pytorch環境,如果你電腦是Windows,並且沒有裝Pytorch,那麼巧了, 我之前寫過一篇怎麼搭建環境,可以先看看 Pytorch入門+實戰系列一:Windows下的Pytorch環境手把手搭建 😉

大綱如下:

  • 模型的保存與加載
  • 模型的finetune
  • GPU使用
  • Pytorch的常見報錯

Ok, let’s go!

2. 模型的保存與加載

我們的建立的模型訓練好了是需要保存的,以備我們後面的使用,所以究竟如何保存模型和加載模型呢? 我們下面重點來看看, 主要分爲三塊: 首先介紹一下序列化和反序列化,然後介紹模型保存和加載的兩種方式,最後是斷點的續訓練技術。

2.1 序列化與反序列化

序列化就是說內存中的某一個對象保存到硬盤當中,以二進制序列的形式存儲下來,這就是一個序列化的過程。 而反序列化,就是將硬盤中存儲的二進制的數,反序列化到內存當中,得到一個相應的對象,這樣就可以再次使用這個模型了。
在這裏插入圖片描述
序列化和反序列化的目的就是將我們的模型長久的保存。

Pytorch中序列化和反序列化的方法:

  • torch.save(obj, f): obj表示對象, 也就是我們保存的數據,可以是模型,張量, dict等等, f表示輸出的路徑
  • torch.load(f, map_location): f表示文件的路徑, map_location指定存放位置, CPU或者GPU, 這個參數挺重要,在使用GPU訓練的時候再具體說。

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裏面去)
在這裏插入圖片描述
模型微調的步驟:

  1. 獲取預訓練模型參數(源任務當中學習到的知識)
  2. 加載模型(load_state_dict)將學習到的知識放到新的模型
  3. 修改輸出層, 以適應新的任務

模型微調的訓練方法:

  • 固定預訓練的參數(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函數: 轉換數據類型/設備

  1. tensor.to(*args, **kwargs)

    x = torch.ones((3,3))
    x = x.to(torch.float64)    # 轉換數據類型
    
    x = torch.ones((3,3))
    x = x.to("cuda")    # 設備轉移
    
  2. module.to(*args, **kwargs)

    linear = nn.Linear(2,2)
    linear.to(torch.double)  # 這樣模型裏面的可學習參數的數據類型變成float64
    
    gpu1 = torch.device("cuda")
    linear.to(gpu1)    # 把模型從CPU遷移到GPU
    

上面兩個方法的區別: 張量不執行inplace, 所以上面看到需要等號重新賦值,而模型執行inplace, 所以不用等號重新賦值。下面從代碼中學習上面的兩個方法:
在這裏插入圖片描述
下面看一下Module的to函數:
在這裏插入圖片描述
如果模型在GPU上, 那麼數據也必須在GPU上才能正常運行。也就是說數據和模型必須在相同的設備上

torch.cuda常用的方法:

  1. torch.cuda.device_count(): 計算當前可見可用的GPU數
  2. torch.cuda.get_device_name(): 獲取GPU名稱
  3. torch.cuda.manual_seed(): 爲當前GPU設置隨機種子
  4. torch.cuda.manual_seed_all(): 爲所有可見可用GPU設置隨機種子
  5. torch.cuda.set_device(): 設置主GPU(默認GPU)爲哪一個物理GPU(不推薦)
    推薦的方式是設置系統的環境變量:os.environ.setdefault("CUDA_VISIBLE_DEVICES", "2,3") 通過這個方法合理的分配GPU,使得多個人使用的時候不衝突。 但是這裏要注意一下, 這裏的2,3指的是物理GPU的2,3。但是在邏輯GPU上, 這裏表示的0,1。 這裏看一個對應關係吧:
    在這裏插入圖片描述
    那麼假設我這個地方設置的物理GPU的可見順序是0,3,2呢? 物理GPU與邏輯GPU如何對應?
    在這裏插入圖片描述
    這個到底幹啥用呢? 在邏輯GPU中,我們有個主GPU的概念,通常指的是GPU0。 而這個主GPU的概念,在多GPU並行運算中就有用了。

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,這裏面目前有一些常見的報錯信息,可以查看, 也歡迎大家貢獻報錯信息。

  1. 報錯:ValueError: num_samples should be a positive interger value, but got num_samples=0
    可能的原因: 傳入的Dataset中的len(self.data_info)==0, 即傳入該DataLoader的dataset裏沒有數據。
    解決方法

    1. 檢查dataset中的路徑
    2. 檢查Dataset的__len__()函數爲何輸出0
  2. 報錯:TypeError: pic should be PIL Image or ndarry. Got <class 'torch.Tensor'>
    可能原因:當前操作需要PIL Image 或 ndarry數據類型, 但傳入了Tensor
    解決方法

    1. 檢查transform中是否存在兩次ToTensor()方法
    2. 檢查transform中每一個操作的數據類型變化
  3. 報錯: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
    可能的原因:dataloader的__getitem__函數中,返回的圖片形狀不一致,導致無法stack
    解決方法:檢查__getitem__函數中的操作

  4. 報錯: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
    可能的原因:網絡層輸入數據與網絡的參數不匹配
    解決方法

    1. 檢查對應網絡層前後定義是否有誤
    2. 檢查輸入數據shape
  5. 報錯:AttributeError: 'DataParallel' object has no attribute 'linear'
    可能的原因:並行運算時,模型被dataparallel包裝,所有module都增加一個屬性 module. 因此需要通過 net.module.linear調用
    解決方法

    1. 網絡層前加入module.
  6. 報錯: 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.

    可能的原因:gpu訓練的模型保存後,在無gpu設備上無法直接加載
    解決方法

    1. 需要設置map_location=“cpu”
  7. 報錯:AttributeError: Can't get attribute 'FooNet2' on <module '__main__' from '
    可能的原因:保存的網絡模型在當前python腳本中沒有定義
    解決方法

    1. 提前定義該類

    這個就是如果我們保存了整個網絡模型需要重新加載進來的時候要注意的地方。 需要先定義網絡的類。

  8. 報錯:RuntimeError: Assertion cur_target >= 0 && cur_target < n_classes' failed. at ../aten/src/THNN/generic/ClassNLLCriterion.c:94
    可能的原因:標籤數大於等於類別數量,即不滿足 cur_target < n_classes,通常是因爲標籤從1開始而不是從0開始
    解決方法:修改label,從0開始,例如:10分類的標籤取值應該是0-9
    交叉熵損失函數中會見到的。

  9. 報錯: 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'

    可能的原因:需計算的兩個數據不在同一個設備上
    解決方法:採用to函數將數據遷移到同一個設備上

  10. 報錯: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.
    可能原因:內存不夠(不是gpu顯存,是內存)
    解決方法:申請更大內存

  11. 報錯:RuntimeError: reduce failed to synchronize: device-side assert triggered
    可能的原因:採用BCE損失函數的時候,input必須是0-1之間,由於模型最後沒有加sigmoid激活函數,導致的。
    解決方法:讓模型輸出的值域在[0, 1]

  12. 報錯:RuntimeError: unexpected EOF. The file might be corrupted.
    torch.load加載模型過程報錯,因爲模型傳輸過程中有問題,重新傳一遍模型即可

  13. 報錯:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 1: invalid start byte
    可能的原因:python2保存,python3加載,會報錯
    解決方法:把encoding改爲encoding=‘iso-8859-1’
    check_p = torch.load(path, map_location=“cpu”, encoding=‘iso-8859-1’)

  14. 報錯:RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same
    問題原因:數據張量已經轉換到GPU上,但模型參數還在cpu上,造成計算不匹配問題。
    解決方法:通過添加model.cuda()將模型轉移到GPU上以解決這個問題。或者通過添加model.to(cuda)解決問題

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的路依然是任重而道遠,因爲這些都得去練,如果想無障礙手寫神經網絡, 就得照着代碼反覆練,反覆看,重點是練習手寫神經網絡的感覺,然後多做項目,多寫代碼,依然是那句話無它,唯手熟爾 😉

PS: 本次學習視頻來自B站https://www.bilibili.com/video/BV1EE41177ot?from=search&seid=13894259699897815176, 時間長了有可能被和諧了。 所有代碼鏈接:

鏈接:https://pan.baidu.com/s/1c5EYdd0w8j6w3g54KTxJJA
提取碼:k7rh

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章