天天看點

pytorch自帶網絡_一篇長文學懂 pytorch

pytorch自帶網絡_一篇長文學懂 pytorch

作為目前越來越受歡迎的深度學習架構,pytorch 基本上成了新人進入深度學習領域最常用的架構。相比于 TensorFlow,pytorch 更易學,更快上手,也可以更容易的實作自己想要的 demo。今天的文章就從 pytorch 的基礎開始,幫助大家實作成功入門。

首先,本篇文章需要大家對深度學習的理論知識有一定的了解,知道基本的 CNN,RNN 等概念,知道前向傳播和反向傳播等流程,畢竟本文重點是一篇實操性的教程。

其次,這篇文章我更想從一個總體性的視角展開,大家在學習的過程中更注重的應該是在接觸新知識時,如何設計學習路線的一種思路分享。這種思路不一定适合所有人,但是肯定可以對你有所借鑒,你也可以基于此總結出來更适合自己的方法。

接下來我們從以下幾個步驟去幫助大家入門 pytorch 的實戰教程。

1. 開始一個簡單的分類器 2. 在 MNIST 上實作一個 cnn 3. 常用網絡層介紹 4. tensorboard 可視化 5. 以 vgg 為例實作深層網絡的一些小技巧 6. GPU 加速和儲存加載模型 7. RNN 和 LSTM 實作分類和回歸 番外: 一個并行生成資料的例子告訴你,pytorch 未來的路該怎麼做

這八個步驟,對應了我的八篇學習筆記的文章,本文是從一個串講的思路來介紹學習路徑,對應步驟的更多細節會在具體的文章中展示。在每個步驟介紹的最後和全文的結尾,我們也會給出文章的連結,大家可以針對性食用~

1. 開始一個簡單的分類器

我個人在學習一門新語言,一個新架構,一個新技術時,最優先要保證的就是成就感回報。以學習 pytorch 為例,很多教程從張量開始。我自己也按照這種教程學習過,的确内容非常全盡,但是有兩個原因,我自己不太推薦以這種方式入門:1)前期學習過于枯燥,沒有成就感;2)有的知識内容屬于深度學習的基本功,過于贅述。

是以我覺得入門一個新知識的知識,最好是先搭起來結構,然後再去慢慢補充細節。是以我在這篇文章的第一部分,先選擇建構一個簡單的分類器,讓大家知道一個 pytorch 下的代碼流程應該是什麼樣子。

學過 c 語言的朋友肯定知道,我們先學第一個代碼的時候,肯定是先來一個 hello world,而不是去研究第一行的 #include。

對于第一個 pytorch 程式而言,我們要做的是首先跑通整個流程,如果是一個簡單的分類器,資料集也就不能太複雜。是以,我們從三方面考慮:1)自定義生成一些點,分為兩類;2)學習如何建構一個淺層的神經網絡;3)嘗試 pytorch 中的訓練和測試過程。

1.1 自定義生成資料集

首先,自定義生成我們的資料集。利用 torch 自帶的 zeros,ones 這些方法,我們生成一些随機的點,分為兩類。比如分别以(2,2)和(-2,-2)為均值,随機生成一些随機數,作為兩類,這樣子我們就得到了我們想要的資料集。

pytorch自帶網絡_一篇長文學懂 pytorch
1.2 學會建構網絡的流程

其次,就是建構一個淺層的神經網絡,這裡我們給出一個代碼示例,大家了解一下最基礎的 pytorch 的網絡應該如何建構:

class Net(torch.nn.Module):    def __init__(self, n_feature, n_hidden, n_output):        super(Net, self).__init__()        self.n_hidden = torch.nn.Linear(n_feature, n_hidden)        self.out = torch.nn.Linear(n_hidden, n_output)    def forward(self, x_layer):        x_layer = torch.relu(self.n_hidden(x_layer))        x_layer = self.out(x_layer)        x_layer = torch.nn.functional.softmax(x_layer)        return x_layernet = Net(n_feature=2, n_hidden=10, n_output=2)# print(net)optimizer = torch.optim.SGD(net.parameters(), lr=0.02)loss_func = torch.nn.CrossEntropyLoss()
           

這個 Net 類,就是我們建構的代碼架構,用它生成的對象就是一個我們可以用來訓練和測試的網絡。這個類中,初始化函數中表示了每個網絡層的結構設定,而 forward() 方法表示了每個層之間的互動順序和關系。

而 optimizer 就是優化器,包含了需要優化的參數有哪些,loss_func 就是我們設定的損失函數。

這個就像我們寫一個 hello,world 一樣,我們隻需要知道自己該如何構造一個網絡。當我們需要調整的時候,就将其中對應的子產品替換掉。

1.3 訓練與測試

接下來就是訓練與測試的階段。訓練我們需要知道三句代碼是核心:

optimizer.zero_grad()    loss.backward()    optimizer.step()
           

這裡的核心思路是,梯度清空,反向傳播,參數更新。分别對應了這三句代碼的作用。在pytorch 中,梯度會保留,是以需要用 zero_grad() 來清空,然後利用損失函數反向傳播計算梯度,最後就是用我們定義的優化器将每個需要優化的參數進行更新。

測試階段就很簡單了,直接将輸入丢進去就可以看到預測結果。現在我們重新随機生成一些資料點作為測試集,可以看到訓練集對它的分類結果就很明顯。

pytorch自帶網絡_一篇長文學懂 pytorch

至此,我們就完成了一個對于簡單分類器的描述。當然,如果你對前面的文章沒有任何了解,可能會覺得這部分不夠入門。那麼可以看一下我的第一篇筆記:pytorch學習筆記(1):開始一個簡單的分類器,這裡詳細的介紹了如何實作一個簡單分類器的細節介紹。

2. 在 MNIST 上實作一個 cnn

完成了一個線性分類器後,我們的學習路線應該是什麼樣子呢?我覺得比較合适的做法是先改動 “hello,world” 的部分,讓我們看看把最直覺的部分進行修改,會有哪些變化。并且可以得到很直接的成就回報。

做深度學習,肯定最熟悉的就是 CNN 做圖檔分類。在一張圖檔上,通過卷積來一層層的提取特征,最終實作分類的效果。那麼我們既然已經知道如何實作一個分類器,接下來就來看看如何用 CNN 完成圖檔的分類。

這裡的資料集我們選擇 mnist,是大家經常用來作為入門的圖檔分類資料集,内容是各種手寫數字的展示。在安裝 torch 的時候,大家參考的教程一般也會推薦安裝 torchvision。在這個之中給出了一個 dataset 的集合,其中包括了各種各樣的常見資料集,mnist 自然也是其中之一。

對于這些資料集的使用方法,主要是 root,transform 等幾個參數,并不是很難。然後對應的有一個 torch.data 中的 DataLoader 方法,可以用來讓資料按自己想要的 batch 生成。具體的如何并行式生成資料,在本文的最後一部分會進行介紹。這裡我們隻需要知道可以使用 DataLoader 并行式按批生成資料。

核心的是如何建構一個 CNN 網絡。我們前面學會了分類器,隻使用了一個隐藏層進行 embedding 操作就可以了。那麼如果要實作 CNN,我們自然要加入卷積層,激活層,池化層這些操作。

class CNN(nn.Module):    def __init__(self):        super(CNN, self).__init__()        self.conv1 = nn.Sequential(            nn.Conv2d(                in_channels=1,                out_channels=16,                kernel_size=5,                stride=2,                padding=2,            ),            nn.ReLU(),            nn.MaxPool2d(2)        )        self.conv2 = nn.Sequential(            nn.Conv2d(16, 32, 5, 1, 2),            nn.ReLU()        )        self.out = nn.Linear(32 * 7 * 7, 10)    def forward(self, x):        x = self.conv1(x)        x = self.conv2(x)        x = x.view(x.size(0), -1)        output = self.out(x)        return output
           

是以按照這個樣子,我們就可以改造前面簡單分類器的結構,生成我們現在的 CNN 結構。從代碼中可以看到,将第一個卷積層設計為:卷積+激活+最大池化;第二個卷積層設計為:卷積+激活。最後跟上一個全連接配接層,實作整個 CNN 的網絡結構設計。

最終的網絡運作結果可以對 mnist 資料集達到 97% 以上的分類精度,可見 CNN 在圖檔分類領域的确有獨到的優勢。

現在我們通過适當的改造實作了一個 CNN 在圖檔分類上的應用,具體的更多細節可以參考:pytorch學習筆記(2):在 MNIST 上實作一個 cnn

那麼在完成了這一步的操作後,我們可能需要思考一點:如果我自己想去做一些更自定義的網絡結構出來,該如何實作呢?我又怎麼知道去修改哪裡,以及修改成什麼樣子呢?是以接下來需要了解的是 torch 都提供了哪些內建好的常用網絡層。

3. 常用網絡層介紹

通過兩個遞進的例子,我們已經知道了該如何實作一個基本的 CNN 網絡結構。但是如前面提到的問題一樣,如果想改某一部分,應該怎麼改呢?

是以從學習的角度出發的話,現在應該考慮的是介紹常用的網絡層都有哪些。然後我們就可以(成為一個調包俠。哈哈,入門肯定要從調包開始嘛~)開始針對自己想要設計的網絡結構選擇合适的子產品啦~

在這部分我們從以下幾個方面去對 pytorch 提供的網絡層進行了介紹:

卷積層

:自帶了一維,二維,三維等卷積函數;

池化層

:可選的有最大池化,平均池化等;

Dropout

:有一維,二維等選擇;

BN層

:是否加入 BN 層的操作;

激活函數

:elu,relu,sigmoid,tanh,softmax 等層可供選擇;

損失函數

:mse,CrossEntropy 等可供選擇。

總體來說這部分内容,我簡單的給一個大綱,就不過多贅述了,具體的每部分的細節參數設定,以及一些幫助大家了解的執行個體都可以在這篇文章中進一步檢視:pytorch學習筆記(3):常用網絡層介紹。

4. tensorboard 可視化

現在我們具備了初步建構自定義網絡結構的能力,也可以完成在自帶資料集上進行訓練和測試的操作。那麼如何讓我們對訓練過程中的性能有一個更直覺的認識呢?對網絡結構如何進行可視化呢?資料集的内容是什麼樣子的?

這些功能我們都可以用一個名為 tensorboard 的工具來實作,這個工具在 TensorFlow 中也很常用。

如何學習使用 tensorboard 呢?這部分我們建議從如下幾個步驟去進行:首先舉一個簡單的例子,讓代碼示例跑起來;然後将整個訓練過程可視化出來;最後再展示如何可視化資料集的内容以及網絡結構流程。

4.1 run一個例子

這裡我們選擇先運作一個官方教程給出的例子,了解如何使用 tensorboard 的基本流程:

from torch.utils.tensorboard import SummaryWriterwriter = SummaryWriter()x = range(100)for i in x:    writer.add_scalar('y=2x', i * 2, i)writer.close()
           

從這個流程中我們可以看到,引入了一個 SummaryWriter 類,然後生成一個 writer 對象,在 for 循環中,每次調用 add_scalar() 方法,往進添加内容。

在完成這個代碼後,如果我們在終端中輸入:

tensorboard --logdir='runs'
           

我們會得到一副 y=2x 的斜線,這就相當于揭示了 tensorboard 的本質。每次将一個值傳入 ‘runs’ 檔案夾中的檔案中,然後在終端中去調用儲存的資料,産生我們想要的圖形。

這一步我們主要是了解上面的這個流程,那麼我們就來看看該怎麼替換想要換掉的子產品,來生成我們想要生成的圖形。

4.2 可視化 CNN 的訓練資料

前面第二部分,我們定義了一個 CNN 來實作對圖檔的分類效果。那麼在訓練過程中的 accuracy 和 loss 是如何變化的呢?

output = cnn(b_x)loss = loss_func(output, b_y)optimizer.zero_grad()loss.backward()optimizer.step()if step % 50 == 0:    test_output = cnn(test_x)    pred_y = torch.max(test_output, 1)[1].data                accuracy = float((pred_y == test_y.data.numpy()).astype(int).sum()) / float(test_y.size(0))    writer.add_scalar("Train/Accuracy", accuracy, step)writer.add_scalar("Train/Loss", loss.item(), step)
           

這裡我們可以看出來是訓練部分的内容,隻是在後面加上了我們前面的一個步驟:添加了兩行 add_scalar() 方法。其實就是訓練時每隔 50 步都進行一次測試,并将測試結果記錄下來,并且每一步的 loss 也都會儲存下來。

是以到最後,我們在終端中輸入上面提到的:tensorboard —logdir=dir,就可以看到下面這幅圖:

pytorch自帶網絡_一篇長文學懂 pytorch
4.3 圖檔和模型的可視化

除了上面對數值的記錄,tensorboard 還提供了諸如圖檔和模型等的可視化,相比于使用 add_scalar(),這裡我們使用 add_image() 和 add_graph() 來實作對應的功能。

add_image() 對圖檔資料進行儲存,每次輸入一個 batch 的資料,也就是說 batch 有多大,其實相當于可視化了多少的 image。

add_graph() 則是對模型結構的儲存,在可視化的時候,就可以對這些内容進行自動展示。

這裡我們主要是介紹概括性的方法與學習流程,具體的關于 tensorboard 的内容,每個方法的參數設定,包括資料儲存的路徑等内容,大家可以進一步參考:pytorch學習筆記(4):tensorboard 可視化。

5. vgg 及一些 tricks

這一部分的内容就比較簡單了,找一個比較經典的深層網絡來實作一下,驗證一下我們之前的基礎。此外,再介紹一種方法來簡化深層網絡的構造方法。

首先實作一個 vgg 本身并沒有太多難度,我們看一看 paper,就可以知道網絡的結構設定。我們不拘泥于 vgg,而是說一個深層次的網絡的構成。

實作一個長的網絡,本質上還是按照前面的思路,一層層的把網絡堆疊起來。我們先看使用 Sequential 建構一個卷積層的樣子:

pytorch自帶網絡_一篇長文學懂 pytorch

這是一層的網絡樣子,我們根據自己要實作的網絡定義,比如參考 vgg 的 paper 内容,定義了卷積層的各個參數,加上 BN 層,加上 relu 進行激活。

整體就是我們定義好的一層,其它層以此類推,用我們前面介紹的常用網絡層就可以像搭積木一樣,把它們搭建起來。

是以按照前面的教程思路,一個深層的神經網絡,例如 vgg,本質上是可以通過簡單的堆疊來實作的。最後我們在 forward 函數中,定義好如下内容:

def forward(self, x):    x = self.conv1(x)    x = self.conv2(x)    x = self.conv3(x)    x = self.conv4(x)    x = self.conv5(x)    x = self.conv6(x)    x = self.conv7(x)    x = self.conv8(x)    x = self.conv9(x)    x = self.conv10(x)    x = self.conv11(x)    x = self.conv12(x)    x = self.conv13(x)    x = x.view(x.size(0), -1)    output = self.out(x)    return output
           

可以看到從内容上就是前面的 CNN 的擴充,沒有技術上的新東西。但是也顯然易見,有點醜陋,寫這麼長個 forward,而且還看起來都是重複的東西,程式員當然不能容忍重複的内容一直出現。

是以這裡分為兩步我們去考慮如何簡化一個模型:sequential 以 list 的形式輸入各層的網絡結構;更加友善的生成各層網絡結構的 list。具體的意思是什麼呢?我們簡單的展開來講一下。

  1. 對一個網絡的設定而言,我們使用 Sequential 來定義我們想要的一層網絡。這裡的一層往往指代卷積+激活+池化等,當然不固定是這樣子。換句話說,一個 Sequential 裡面本身就定義了不止一個網絡,那麼我們是否可以将所有網絡都放到一個 Sequential 裡面來?答案是可以的!
  2. 對于一個 Sequential,我們可以将所有的網絡結構都輸入進去,以動态參數的方式。也就是說,我們讓 Sequential 的輸入是這個形式:*[網絡層1,網絡層2,…,網絡層n]。可以看到,是一個 list 前面加 *,就可以将 list 中的所有元素以參數的方式傳進去。
  3. 但是這樣輸入進來的參數,需要一個非常非常長的 list。在定義這個 list 的時候,顯得我們的模型更加難看。是以我們需要一個優雅的方式,來生成這樣一個 list,其中的每個元素都是我們想要的網絡層結構。是以我們介紹的生成方式就是下述代碼:
def make_layers(cfg, batch_norm=False):    layers = []    in_channels = 3    for v in cfg:        if v == 'M':            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]        else:            conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)            if batch_norm:                layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]            else:                layers += [conv2d, nn.ReLU(inplace=True)]            in_channels = v    return nn.Sequential(*layers)cfg = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M']
           

這裡就可以很直接的看到,最終生成的 layers 這個 list,就是我們想要的内容,其中包含了我們需要的每個網絡層結構。在 for 循環中就是我們生成的方式,按照在參數 cfg 中定義的内容,依次往 layers 中添加我們需要的内容。數字表示該卷積層的輸出通道,字母 ‘M' 表示最大池化。

可以看到,以這種方式,我們就可以通過隻調整 cfg 這個 list,最終實作目标的深層次的神經網絡的設計。更詳細的介紹和設計,可以參考我們之前的學習筆記:pytorch學習筆記(5):vgg 實作以及一些 tricks。

6. GPU 和如何儲存加載模型

到了這一步,我們的網絡深度也加上來了,是時候考慮一下 GPU 加速的問題了。GPU 在深度學習中是無論如何也繞不過去的一個話題,好在 pytorch 在 GPU 的使用方面給了非常友好的接口,下面我們就看一下如何使用 GPU 加速,以及如何儲存訓練好的模型,到測試時再加載出來。

6.1 先看看 GPU 咋用吧

我們就來說一下 GPU 在 pytorch 中有多麼簡單易用吧。首先如下簡單指令:

torch.cuda.is_available()
           

這條指令可以判讀你是否安裝好了 GPU 版本的 pytorch,或者你的顯示卡是否可以使用,如果結果顯示

True

,那我們就可以進行下一步了。

GPU 的使用在 pytorch 中,我們就記住三部分:遷移資料,遷移模型,遷回資料。

首先遷移資料是指,我們需要将資料遷移到 GPU 上,這個時候就展現出顯存的重要性,顯存越大,就可以往進遷移的資料越多;

其次是遷移模型,也就是說将我們定義好的網絡模型也遷移到 GPU 上,這個時候就可以在 GPU 上對給定模型,利用遷移進來的資料進行訓練和測試;

最後是遷回資料,也就是說将測試好的結果再傳回 CPU,進行下一步的其它處理,比如計算精度之類。

這裡給一個小栗子來為大家看一下這三步:

# 指定好用的 GPU 裝置,如果是單卡,一般就是 0.device = "cuda:0"# 遷移資料images = images.to(device)labels = labels.to(device)# 遷移網絡,将我們定義好的網絡 cnn 遷移到 GPU 中。cnn.to(device)# 訓練...# 測試... 生成測試結果 pred_y# 遷回資料,将 pred_y 再遷回 CPU。pred_y = pred_y.cpu()
           

通過這個例子,我們可以很清晰的看到如何使用 GPU 完成我們上所述的三個步驟。隻要保證了将這三部分加入到你的代碼中,中間的訓練和測試依然保持原樣,我們就實作了利用 GPU 加速的目的。

6.2 訓練好的模型如何儲存和加載呢?

關于 pytorch 中的模型儲存,一般有兩種途徑:隻儲存網絡參數,儲存整個網絡。

首先要知道的一點是,在 pytorch 中所有的網路參數資料都是一個 dict,也就是網絡對象的 state_dict() 參數。那麼我們如果想儲存下來需要的内容,其實在底層操作方面并不複雜。

現在來看如何儲存模型,其實就一條語句:torch.save(content,path),就可以将需要的 content 儲存到目标的 path 中。這裡唯一的需要思考的是如何區分隻儲存網絡參數,還是儲存整個網絡。

隻儲存網絡參數時,我們的 content 就是 cnn.state_dict(),如果儲存整個網絡,content 就是 cnn。下面兩行代碼分别是隻儲存參數和儲存整個網絡:

torch.save(cnn.state_dict(), PATH)torch.save(cnn, PATH)
           

可以看到儲存的方式非常友善,一個函數就可以完成。那麼對應的,讀取的方式是什麼呢?

分别用兩個不同的方法來進行讀取:load_state_dict() 和 load()。

隻看名稱也可以想到前者是讀取參數,後者是讀取整個網絡。但是隻讀取參數的話,我們需要提前定義好對應的網絡對象,然後通過讀取參數的方式,為網絡的結構中填充相應的參數。

具體的如何使用 GPU 加速模型,如何存儲和讀取訓練好的網絡,細節的代碼和例子可以看:pytorch學習筆記(6):GPU 和如何儲存加載模型。

7. RNN 回歸

前面我們介紹了 CNN 的建立方式,常用的網絡層,基于此的基礎上,又介紹了一些其它的相關操作,比如 GPU 加速等。現在我們來看系列教程的最後一部分,就是如何使用 RNN。

以 RNN 為例,我們建構一個回歸器,以此來介紹 RNN 在 pytorch 中的使用方法,幫助大家入門 RNN 的操作過程。

7.1 RNN 參數

我們這裡不再贅述 RNN 的定義和内容,在本節後面的文章連結中,詳細的介紹了這一部分。我們在這裡隻說一下在 pytorch 中的 RNN 類可以設定的參數。

input_size

:這個參數表示的輸入資料的次元。比如輸入一個句子,這裡表示的就是每個單詞的詞向量的次元。

hidden_size

 :可以了解為在 CNN 中,一個卷積層的輸出次元一樣。這裡表示将前面的 input_size 映射到一個什麼次元上。

num_layers

:表示循環的層數。舉個栗子,将 num_layers 設定為 2,也就是将兩個 RNN 堆疊在一起,第一層的輸出作為第二層的輸入。預設為 1。

nonlinearity

:這個參數對激活函數進行選擇,目前 pytorch 支援 tanh 和 relu,預設的激活函數是 tanh。

bias

:這個參數表示是否需要偏置項,預設為 True。

batch_first

:這個是我們資料的格式描述,在 pytorch 中我們經常以 batch 分組來訓練資料。這裡的 batch_size 表示 batch 是否在輸入資料的第一個次元,如果在第一個次元則為 True,預設為 False,也就是第二個次元。

dropout

:這裡就是對每一層的輸出是否加一個 dropout 層,如果參數非 0,那麼就會加上這個 dropout 層。值得注意的是,對最後的輸出層并不會加,也就是這個參數隻有在 num_layers 參數大于 1 的時候才有意義。預設為 0。

bidirectional

:如果為 True,則表示 RNN 網絡為雙向結構,預設為 False。

這些參數的給定,我們就可以輕松的去設定我們想要的 RNN 結構。此處 input_size 和 hidden_size 是兩個必須傳入的參數,需要讓網絡知道将什麼次元的輸入映射到什麼次元上去。其餘的參數都給了比較常用的預設值。

7.2 回歸器:用 sin 預測 cos

在這裡我們舉一個非常容易了解的例子。也不去折騰什麼複雜資料集,我們同樣使用一個簡單的自定義資料集:sin 函數作為 data,cos 函數作為 label。因為重點是學習 RNN 的使用,是以我們無需測試集,隻看訓練的拟合程度,判斷是否成功收斂就可以了。

首先給出來我們定義的 RNN 結構,再對其中的細節進行解讀:

class RNN(nn.Module):    def __init__(self):        super(RNN, self).__init__()        self.rnn = nn.RNN(            input_size=1,            hidden_size=32,            batch_first=True,        )        self.out = nn.Linear(32, 1)    def forward(self, x, h_state):        r_out, h_state = self.rnn(x, h_state)        outs = []        for time_step in range(r_out.size(1)):            outs.append(self.out(r_out[:, time_step, :]))        return torch.stack(outs, dim=1), h_state
           

我們先看第一部分 RNN 的結構上,定義了三個參數:input_size,hidden_size,batch_first。

input_size 我們設定為 1,是因為每次輸入的資料上,隻有一個點的位置,資料是一維資料;

hidden_size 設定為 32,表示我們想要将這個資料映射到 32 維的隐空間上,這個值由自己進行選擇,不要太小,也不要太大(太小會導緻拟合能力較差,太大會導緻計算資源消耗過多);

batch_first 設為

True

,表示我們的資料格式中,第一個次元是 batch。

最終,根據前面對參數的介紹,可以得知,我們建構了一個單層的 RNN 網絡,輸入的每個 time_step 上的資料都是一維的,通過将其映射到 32 維的隐空間上,來發掘對标簽資料的拟合關系。

接下來我們看一下 forward 函數中的内容,與 CNN 的 forward 中有些不一樣。在 CNN 中,我們直接将對應的網絡結構往一起拼接就可以,這裡多了一些奇怪的參數。這是為什麼呢?

從第一行開始看起,首先 RNN 我們都知道,每個 time_step 的循環中,都是将上一個循環的隐狀态和目前的輸入結合起來作為輸入。那麼 r_out 和 h_state 就是目前狀态的輸出和隐狀态。

第二行的 outs 是一個空清單,用來存儲什麼内容呢?我們往下看。

後面是一個 for 循環,循環的次數取決于 r_out.size(1)。這個參數表示什麼呢?r_out 我們知道是輸出,這個輸出的格式應該和輸入是相同格式(batch,time_step,hidden_size),是以 r_out.size(1) 表示了這批資料的 time_step 的大小,也就是這批資料有多少個點。将對應的資料進行 self.out() 操作,也就是将 32 維的資料再映射到 1 維,并将結果 append 到 outs 中。

這裡我們就知道前面定義的 outs 清單用來裝什麼資料了,最後将結果 stack 起來,作為 forward 的傳回值。

這裡看一下訓練過程中的拟合情況:

pytorch自帶網絡_一篇長文學懂 pytorch

藍色線條展示了模型的拟合過程,可以看到最終逐漸拟合到了目标的 cos 曲線上(紅色線條)。

本部分更多的細節,包括 RNN 原理的簡單介紹,對應的網絡的運作細節都在:第七篇文章 中可以看到。除此之外,這篇文章中還進一步給出了一個利用 LSTM 實作一個對 mnist 資料集進行分類的例子,幫助我們可以學習 pytorch 中 LSTM 的使用方法,非常建議看一下這篇文章:pytorch學習筆記(7):RNN 和 LSTM 實作分類和回歸。

番外篇:如何進階

番外篇不是說不重要的一步,而是更多的想表達我對學習流程為何這麼設定的思路。通過前面的文章,大家肯定可以算是基本入門了 pytorch 的使用,至少不會出現想要實作一個網絡時,手足無措的情況。但是如果從學好這個架構出發,這肯定是遠遠不夠的。

那麼我們應該如何去學好這個非常流行的架構呢?我們首先應該是按照前面文章的思路一樣,将整體流程的思維架設起來,知道應該怎麼入手,可能大神還會給你說如何底層加速,如何優化細節,如何并行式加載資料等。但是我們如果一上來就學的那麼細,可能現在還雲裡霧裡,不知道那種細節性的文章在說什麼。

是以這裡我們給出一個并行式加載資料的例子,讓大家知道,在架設起來對 pytorch 的整體性認知以後,我們就可以很輕松的去針對性補充自己需要學會的内容。

這裡給出一篇文章的例子,講解了如何提高資料加載的速度,讓我們可以利用 pytorch 自帶的 DataLoader 類,自定義設定自己的資料加載類型,讓你的資料生成不再成為訓練的瓶頸。具體的細節可以看:一個例子告訴你,在 pytorch 中應該如何并行生成資料。

重點不是這篇文章,而是授之以漁。按照這類方法,大家就可以進一步去優化自己的知識體系,補充對細節上的提升。大家通過本篇系列文章的彙總教程以後,就可以很輕松的去學習其它對 pytorch 技能進行優化的進階文章了。

總結

這是一篇對 pytorch 進行入門教程的文章,不僅僅是對架構的學習,這樣的學習方法也可以借鑒到其它的架構,程式設計語言等中去。

系列教程詳細清單

pytorch學習筆記(1):開始一個簡單的分類器

pytorch學習筆記(2):在 MNIST 上實作一個 cnn

pytorch學習筆記(3):常用網絡層介紹

pytorch學習筆記(4):tensorboard 可視化

pytorch學習筆記(5):vgg 實作以及一些 tricks

pytorch學習筆記(6):GPU 和如何儲存加載模型

pytorch學習筆記(7):RNN 和 LSTM 實作分類和回歸

一個例子告訴你,在 pytorch 中應該如何并行生成資料

pytorch自帶網絡_一篇長文學懂 pytorch

繼續閱讀