【PyTorch】PyTorch如何構建和實驗神經網路

作者 | Tirthajyoti Sarkar

來源 | Medium

編輯 | 程式碼醫生團隊

介紹

在本文中,將展示一個簡單的分步過程,以在PyTorch中構建2層神經網路分類器(密集連接),從而闡明一些關鍵功能和樣式。

PyTorch為程式設計師提供了極大的靈活性,使其可以在張量流過網路時創建,組合和處理張量……

核心組成

用於構建神經分類器的PyTorch的核心組件是

  • 張量(在PyTorch中央數據結構)
  • Tensor 的Autograd功能
  • nn.Module 類,用來建立任何其他神經類分類
  • 優化器
  • 損失函數

使用這些組件,將通過五個簡單的步驟構建分類器

  • 將神經網路構造為自定義類(從該類繼承nn.Module),其中包含隱藏層張量以及forward通過各種層和激活函數傳播輸入張量的方法
  • 使用此forward方法通過網路傳播特徵(從數據集)張量-得到一個output張量
  • 計算了loss通過比較output在地上真相,並使用內置的損失函數
  • 傳播的梯度loss使用自動分化能力(Autograd)與backward方法
  • 使用損耗的梯度來更新網路的權重(這是通過執行所謂的優化器的一個步驟來實現的)optimizer.step()。

這個五步過程構成了一個完整的訓練時期。只重複一遍,以降低損失並獲得較高的分類精度。

包含五個核心組件的五步過程

在PyTorch,定義了一個神經網路作為一個自定義類,從而可以收穫的全部好處Ø bject-Orineted編程(OOP)範例。

張量

torch.Tensor是一個多維矩陣,其中包含單個數據類型的元素。它是框架的中央數據結構。可以從Numpy數組或列表創建Tensor,並執行各種操作,例如索引,數學,線性代數。

張量支援一些其他增強功能,從而使其具有獨特性。除CPU外,它們還可以載入到GPU中(只需極其簡單的程式碼更改)即可進行更快的計算。並且它們支援形成一個向後圖,該圖跟蹤使用動態計算圖(DCG)應用於它們的每個操作以計算梯度。

Autograd

對於複雜的神經網路,都不擅長微積分。高維空間使頭腦混亂。幸運的是有Autograd。

要處理14維空間中的超平面,請可視化3D空間並大聲對自己說「十四」。每個人都做得到– Geoffrey Hinton

Tensor對象支援神奇的Autograd功能,即自動區分,這是通過跟蹤和存儲在Tensor流經網路時執行的所有操作來實現的。

nn.Module類

在PyTorch中,通過將其定義為自定義類來構建神經網路。然而不是從原來的Python派生object從該類繼承nn.Module類。這為神經網路類注入了有用的屬性和強大的方法。將在本文中看到此類定義的完整示例。

損失函數

損失函數定義了神經網路的預測與地面真實情況之間的距離,而損失的定量度量則幫助驅動網路更接近對給定數據集進行最佳分類的配置。

PyTorch提供了用於分類和回歸任務的所有常見損失函數

  • 二元和多類交叉熵,
  • mean squared and mean absolute errors
  • smooth L1 loss
  • neg log-likelihood loss
  • Kullback-Leibler divergence

優化器

權重的優化以實現最低的損失是用於訓練神經網路的反向傳播演算法的核心。PyTorch提供了大量的優化器來完成這項工作,這些優化器通過torch.optim模組公開

  • 隨機梯度下降(SGD),
  • Adam, Adadelta, Adagrad, SpareAdam,
  • L-BFGS,
  • RMSprop

「五步過程構成了完整的訓練時期。只重複一遍。」

神經網路類與訓練

數據

對於此示例任務,首先使用Scikit-learn函數使用二進位類創建一些合成數據。在以下圖表中,數據類別通過顏色區分。顯然,數據集無法通過簡單的線性分類器進行分離,而神經網路是解決此問題的合適機器學習工具。

用於分類示例的綜合數據集

架構

選擇了一個簡單的完全連接的2隱藏層體系結構。如下圖所示

類的定義

n_input = X.shape[1] # Must match the shape of the input features  n_hidden1 = 8 # Number of neurons in the 1st hidden layer  n_hidden2 = 4 # Number of neurons in the 2nd hidden layer  n_output = 1 # Number of output units (for example 1 for binary classification)

定義與該架構相對應的變數,然後定義主類。神經網路類定義如下所示。如前所述,它從nn.Module基類繼承。

該程式碼幾乎沒有解釋,帶有添加的注釋。在方法的定義中,forward,與Keras對模型的定義有很強的相似性。

另外,請注意使用內置線性代數運算nn.Linear(如在各層之間)和激活函數(如nn.ReLU和nn.Sigmoid在各層的輸出處)。

如果實例化一個模型對象並列印它,將看到結構(與Keras的model.summary()方法平行)。

model = Network()  print(model)    Network(    (hidden1): Linear(in_features=5, out_features=8, bias=True)    (hidden2): Linear(in_features=8, out_features=4, bias=True)    (relu): ReLU()    (output): Linear(in_features=4, out_features=1, bias=True)    (sigmoid): Sigmoid()  )

損失函數,優化器和訓練

為此任務選擇二進位交叉熵損失,並將其定義如下(按照慣例,損失函數通常criterion在PyTorch中調用)

criterion = nn.BCELoss() # Binary cross-entropy loss

在這一點上,通過定義的神經網路模型運行輸入數據集,即一次向前通過並計算輸出概率。由於權重已初始化為隨機,因此將看到隨機輸出概率(大多數接近0.5)。該網路尚未訓練。

logits = model.forward(X) # Output of the forward pass (logits i.e. probabilities)

如果列印出前10個概率,將得到類似的結果,

tensor([[0.5926],[0.5854],[0.5369],[0.5802],[0.5905],[0.6010],[0.5723],[0.5842],[0.5971],[0.5883]], grad_fn=<SliceBackward>)

所有輸出概率看起來都接近0.5,

平均損失的計算方法很簡單,

loss = criterion(logits,y)

對於優化程式,選擇簡單的隨機梯度下降(SGD),並將學習率指定為0.1,

from torch import optim  optimizer = optim.SGD(model.parameters(),lr=0.1)

現在進行訓練。再次遵循五個步驟

  • 將漸變重置為零(以防止漸變累積)
  • 將張量向前穿過層
  • 計算損失張量
  • 計算損失的梯度
  • 通過將優化器增加一級(沿負梯度的方向)來更新權重

令人驚訝的是,如果閱讀了上面的五個步驟,這正是在神經網路的所有理論討論(以及所有教科書)中看到的。而且藉助PyTorch,可以一步一步使用看似簡單的程式碼來實現此過程。

沒有任何東西隱藏或抽象。會感到用五行Python程式碼實施神經網路訓練過程的原始力量和興奮!

# Resets the gradients i.e. do not accumulate over passes  optimizer.zero_grad()  # Forward pass  output = model.forward(X)  # Calculate loss  loss = criterion(output,y)  # Backward pass (AutoGrad)  loss.backward()  # One step of the optimizer  optimizer.step()

訓練多個時期

那只是一個時期。現在很清楚一個時期不會削減它,是嗎?要運行多個時期,只需使用循環即可。

epochs = 10  for i,e in enumerate(range(epochs)):      optimizer.zero_grad() # Reset the grads      output = model.forward(X) # Forward pass      loss = criterion(output.view(output.shape[0]),y) # Calculate loss      print(f"Epoch - {i+1}, Loss - {round(loss.item(),3)}")  # Print loss      loss.backward() # Backpropagation      optimizer.step() # Optimizer one step

當運行1000個時期時,可以輕鬆生成所有熟悉的損耗曲線。

想看看概率隨時間變化嗎?

PyTorch能夠進行實驗,探查,弄碎和晃動物品。

只是為了好玩,如果想檢查輸出層概率在多個時期內如何演變,只需對前面的程式碼進行簡單的修改就可以了,

顯然未經訓練的網路輸出都接近1,即在正類別和負類別之間沒有區別。隨著訓練的繼續,概率彼此分離,通過調整網路的權重逐漸嘗試匹配地面真理的分布。

PyTorch使您能夠進行實驗,探查,弄碎和晃動物品。

還有其他流行的想法嗎?試試

PyTorch從其早期版本開始就非常受歡迎,尤其是在學術研究人員和初創公司中。這背後的原因很簡單-它可以通過簡單的程式碼重構嘗試瘋狂的想法。實驗是任何科學領域新思想發展的核心,當然,深度學習也不例外。

與兩個激活功能混在一起嗎?

只是為了(有點)瘋狂,假設想將其與兩個不同的激活函數-ReLU和Hyperbolic tangent(tanh)混合在一起。想將張量分成兩個平行的部分,分別對它們應用這些激活,添加結果張量,然後正常地傳播它。

看起來複雜嗎?實現所期望的程式碼。將輸入張量(例如X)傳遞通過第一個隱藏層,然後通過使結果張量流經單獨的激活函數來創建兩個張量X1和X2 。只需將結果張量加起來,然後使其通過第二個隱藏層即可。

可以執行此類實驗性工作,並使用PyTorch輕鬆更改網路的體系結構。

實驗是任何科學領域新思想發展的核心,當然,深度學習也不例外。

嘗試自己的自定義損失函數?

可能會想嘗試自己的自定義損失函數。自高中時代起,都使用均方誤差。嘗試對回歸問題進行四次方次冪運算怎麼樣?

只需定義功能…

然後在程式碼中使用它(請注意reg_model,可以通過在Network類輸出中關閉S型激活來構造新模型。

現在,有這種感覺嗎?

結論

可以在Github存儲庫中找到此演示的所有程式碼。

https://github.com/tirthajyoti/PyTorch_Machine_Learning

在本文中,總結了一些關鍵步驟,可以遵循這些關鍵步驟來快速構建用於分類或回歸任務的神經網路。還展示了如何使用此框架輕鬆地嘗試巧妙的想法。