PyTorch如何構(gòu)建和實(shí)驗(yàn)神經(jīng)網(wǎng)絡(luò)
點(diǎn)擊上方“小白學(xué)視覺(jué)”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)

作者 | Tirthajyoti Sarkar
來(lái)源?|?Medium
編輯?|?代碼醫(yī)生團(tuán)隊(duì)
在本文中,將展示一個(gè)簡(jiǎn)單的分步過(guò)程,以在PyTorch中構(gòu)建2層神經(jīng)網(wǎng)絡(luò)分類器(密集連接),從而闡明一些關(guān)鍵功能和樣式。
PyTorch為程序員提供了極大的靈活性,使其可以在張量流過(guò)網(wǎng)絡(luò)時(shí)創(chuàng)建,組合和處理張量……
?
?
用于構(gòu)建神經(jīng)分類器的PyTorch的核心組件是
張量(在PyTorch中央數(shù)據(jù)結(jié)構(gòu))
Tensor 的Autograd功能
nn.Module 類,用來(lái)建立任何其他神經(jīng)類分類
優(yōu)化器
損失函數(shù)

使用這些組件,將通過(guò)五個(gè)簡(jiǎn)單的步驟構(gòu)建分類器
將神經(jīng)網(wǎng)絡(luò)構(gòu)造為自定義類(從該類繼承nn.Module),其中包含隱藏層張量以及forward通過(guò)各種層和激活函數(shù)傳播輸入張量的方法
使用此forward方法通過(guò)網(wǎng)絡(luò)傳播特征(從數(shù)據(jù)集)張量-得到一個(gè)output張量
計(jì)算了loss通過(guò)比較output在地上真相,并使用內(nèi)置的損失函數(shù)
傳播的梯度loss使用自動(dòng)分化能力(Autograd)與backward方法
使用損耗的梯度來(lái)更新網(wǎng)絡(luò)的權(quán)重(這是通過(guò)執(zhí)行所謂的優(yōu)化器的一個(gè)步驟來(lái)實(shí)現(xiàn)的)optimizer.step()。
這個(gè)五步過(guò)程構(gòu)成了一個(gè)完整的訓(xùn)練時(shí)期。只重復(fù)一遍,以降低損失并獲得較高的分類精度。

在PyTorch,定義了一個(gè)神經(jīng)網(wǎng)絡(luò)作為一個(gè)自定義類,從而可以收獲的全部好處? bject-Orineted編程(OOP)范例。
?
?
torch.Tensor是一個(gè)多維矩陣,其中包含單個(gè)數(shù)據(jù)類型的元素。它是框架的中央數(shù)據(jù)結(jié)構(gòu)??梢詮?span style="font-family: Calibri;">Numpy數(shù)組或列表創(chuàng)建Tensor,并執(zhí)行各種操作,例如索引,數(shù)學(xué),線性代數(shù)。
張量支持一些其他增強(qiáng)功能,從而使其具有獨(dú)特性。除CPU外,它們還可以加載到GPU中(只需極其簡(jiǎn)單的代碼更改)即可進(jìn)行更快的計(jì)算。并且它們支持形成一個(gè)向后圖,該圖跟蹤使用動(dòng)態(tài)計(jì)算圖(DCG)應(yīng)用于它們的每個(gè)操作以計(jì)算梯度。
?
對(duì)于復(fù)雜的神經(jīng)網(wǎng)絡(luò),都不擅長(zhǎng)微積分。高維空間使頭腦混亂。幸運(yùn)的是有Autograd。
要處理14維空間中的超平面,請(qǐng)可視化3D空間并大聲對(duì)自己說(shuō)“十四”。每個(gè)人都做得到– Geoffrey Hinton
Tensor對(duì)象支持神奇的Autograd功能,即自動(dòng)區(qū)分,這是通過(guò)跟蹤和存儲(chǔ)在Tensor流經(jīng)網(wǎng)絡(luò)時(shí)執(zhí)行的所有操作來(lái)實(shí)現(xiàn)的。
在PyTorch中,通過(guò)將其定義為自定義類來(lái)構(gòu)建神經(jīng)網(wǎng)絡(luò)。然而不是從原來(lái)的Python派生object從該類繼承nn.Module類。這為神經(jīng)網(wǎng)絡(luò)類注入了有用的屬性和強(qiáng)大的方法。將在本文中看到此類定義的完整示例。
?
損失函數(shù)定義了神經(jīng)網(wǎng)絡(luò)的預(yù)測(cè)與地面真實(shí)情況之間的距離,而損失的定量度量則幫助驅(qū)動(dòng)網(wǎng)絡(luò)更接近對(duì)給定數(shù)據(jù)集進(jìn)行最佳分類的配置。
PyTorch提供了用于分類和回歸任務(wù)的所有常見(jiàn)損失函數(shù)
二元和多類交叉熵,
mean squared and mean absolute errors
smooth L1 loss
neg log-likelihood loss
Kullback-Leibler divergence
?
權(quán)重的優(yōu)化以實(shí)現(xiàn)最低的損失是用于訓(xùn)練神經(jīng)網(wǎng)絡(luò)的反向傳播算法的核心。PyTorch提供了大量的優(yōu)化器來(lái)完成這項(xiàng)工作,這些優(yōu)化器通過(guò)torch.optim模塊公開(kāi)
隨機(jī)梯度下降(SGD),
Adam, Adadelta, Adagrad, SpareAdam,
L-BFGS,
RMSprop
“五步過(guò)程構(gòu)成了完整的訓(xùn)練時(shí)期。只重復(fù)一遍。”
對(duì)于此示例任務(wù),首先使用Scikit-learn函數(shù)使用二進(jìn)制類創(chuàng)建一些合成數(shù)據(jù)。在以下圖表中,數(shù)據(jù)類別通過(guò)顏色區(qū)分。顯然,數(shù)據(jù)集無(wú)法通過(guò)簡(jiǎn)單的線性分類器進(jìn)行分離,而神經(jīng)網(wǎng)絡(luò)是解決此問(wèn)題的合適機(jī)器學(xué)習(xí)工具。

?
選擇了一個(gè)簡(jiǎn)單的完全連接的2隱藏層體系結(jié)構(gòu)。如下圖所示

?
n_input = X.shape[1] # Must match the shape of the input featuresn_hidden1 = 8 # Number of neurons in the 1st hidden layern_hidden2 = 4 # Number of neurons in the 2nd hidden layern_output = 1 # Number of output units (for example 1 for binary classification)
定義與該架構(gòu)相對(duì)應(yīng)的變量,然后定義主類。神經(jīng)網(wǎng)絡(luò)類定義如下所示。如前所述,它從nn.Module基類繼承。

該代碼幾乎沒(méi)有解釋,帶有添加的注釋。在方法的定義中,forward,與Keras對(duì)模型的定義有很強(qiáng)的相似性。
另外,請(qǐng)注意使用內(nèi)置線性代數(shù)運(yùn)算nn.Linear(如在各層之間)和激活函數(shù)(如nn.ReLU和nn.Sigmoid在各層的輸出處)。
如果實(shí)例化一個(gè)模型對(duì)象并打印它,將看到結(jié)構(gòu)(與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())
?
為此任務(wù)選擇二進(jìn)制交叉熵?fù)p失,并將其定義如下(按照慣例,損失函數(shù)通常criterion在PyTorch中調(diào)用)
criterion = nn.BCELoss() # Binary cross-entropy loss在這一點(diǎn)上,通過(guò)定義的神經(jīng)網(wǎng)絡(luò)模型運(yùn)行輸入數(shù)據(jù)集,即一次向前通過(guò)并計(jì)算輸出概率。由于權(quán)重已初始化為隨機(jī),因此將看到隨機(jī)輸出概率(大多數(shù)接近0.5)。該網(wǎng)絡(luò)尚未訓(xùn)練。
logits = model.forward(X) # Output of the forward pass (logits i.e. probabilities)如果打印出前10個(gè)概率,將得到類似的結(jié)果,
tensor([[0.5926],[0.5854],[0.5369],[0.5802],[0.5905],[0.6010],[0.5723],[0.5842],[0.5971],[0.5883]], grad_fn=) 所有輸出概率看起來(lái)都接近0.5,

平均損失的計(jì)算方法很簡(jiǎn)單,
loss = criterion(logits,y)對(duì)于優(yōu)化程序,選擇簡(jiǎn)單的隨機(jī)梯度下降(SGD),并將學(xué)習(xí)率指定為0.1,
from torch import optimoptimizer = optim.SGD(model.parameters(),lr=0.1)
現(xiàn)在進(jìn)行訓(xùn)練。再次遵循五個(gè)步驟
將漸變重置為零(以防止?jié)u變累積)
將張量向前穿過(guò)層
計(jì)算損失張量
計(jì)算損失的梯度
通過(guò)將優(yōu)化器增加一級(jí)(沿負(fù)梯度的方向)來(lái)更新權(quán)重
令人驚訝的是,如果閱讀了上面的五個(gè)步驟,這正是在神經(jīng)網(wǎng)絡(luò)的所有理論討論(以及所有教科書(shū))中看到的。而且借助PyTorch,可以一步一步使用看似簡(jiǎn)單的代碼來(lái)實(shí)現(xiàn)此過(guò)程。
沒(méi)有任何東西隱藏或抽象。會(huì)感到用五行Python代碼實(shí)施神經(jīng)網(wǎng)絡(luò)訓(xùn)練過(guò)程的原始力量和興奮!
# Resets the gradients i.e. do not accumulate over passesoptimizer.zero_grad()# Forward passoutput = model.forward(X)# Calculate lossloss = criterion(output,y)# Backward pass (AutoGrad)loss.backward()# One step of the optimizeroptimizer.step()

?
那只是一個(gè)時(shí)期?,F(xiàn)在很清楚一個(gè)時(shí)期不會(huì)削減它,是嗎?要運(yùn)行多個(gè)時(shí)期,只需使用循環(huán)即可。
epochs = 10for i,e in enumerate(range(epochs)):optimizer.zero_grad() # Reset the gradsoutput = model.forward(X) # Forward passloss = criterion(output.view(output.shape[0]),y) # Calculate lossprint(f"Epoch - {i+1}, Loss - {round(loss.item(),3)}") # Print lossloss.backward() # Backpropagationoptimizer.step() # Optimizer one step
當(dāng)運(yùn)行1000個(gè)時(shí)期時(shí),可以輕松生成所有熟悉的損耗曲線。

PyTorch能夠進(jìn)行實(shí)驗(yàn),探查,弄碎和晃動(dòng)物品。
只是為了好玩,如果想檢查輸出層概率在多個(gè)時(shí)期內(nèi)如何演變,只需對(duì)前面的代碼進(jìn)行簡(jiǎn)單的修改就可以了,


?
顯然未經(jīng)訓(xùn)練的網(wǎng)絡(luò)輸出都接近1,即在正類別和負(fù)類別之間沒(méi)有區(qū)別。隨著訓(xùn)練的繼續(xù),概率彼此分離,通過(guò)調(diào)整網(wǎng)絡(luò)的權(quán)重逐漸嘗試匹配地面真理的分布。
PyTorch使您能夠進(jìn)行實(shí)驗(yàn),探查,弄碎和晃動(dòng)物品。
?
PyTorch從其早期版本開(kāi)始就非常受歡迎,尤其是在學(xué)術(shù)研究人員和初創(chuàng)公司中。這背后的原因很簡(jiǎn)單-它可以通過(guò)簡(jiǎn)單的代碼重構(gòu)嘗試瘋狂的想法。實(shí)驗(yàn)是任何科學(xué)領(lǐng)域新思想發(fā)展的核心,當(dāng)然,深度學(xué)習(xí)也不例外。
只是為了(有點(diǎn))瘋狂,假設(shè)想將其與兩個(gè)不同的激活函數(shù)-ReLU和Hyperbolic tangent(tanh)混合在一起。想將張量分成兩個(gè)平行的部分,分別對(duì)它們應(yīng)用這些激活,添加結(jié)果張量,然后正常地傳播它。
?

看起來(lái)復(fù)雜嗎?實(shí)現(xiàn)所期望的代碼。將輸入張量(例如X)傳遞通過(guò)第一個(gè)隱藏層,然后通過(guò)使結(jié)果張量流經(jīng)單獨(dú)的激活函數(shù)來(lái)創(chuàng)建兩個(gè)張量X1和X2 。只需將結(jié)果張量加起來(lái),然后使其通過(guò)第二個(gè)隱藏層即可。
?

可以執(zhí)行此類實(shí)驗(yàn)性工作,并使用PyTorch輕松更改網(wǎng)絡(luò)的體系結(jié)構(gòu)。
實(shí)驗(yàn)是任何科學(xué)領(lǐng)域新思想發(fā)展的核心,當(dāng)然,深度學(xué)習(xí)也不例外。
可能會(huì)想嘗試自己的自定義損失函數(shù)。自高中時(shí)代起,都使用均方誤差。嘗試對(duì)回歸問(wèn)題進(jìn)行四次方次冪運(yùn)算怎么樣?
只需定義功能...

然后在代碼中使用它(請(qǐng)注意reg_model,可以通過(guò)在Network類輸出中關(guān)閉S型激活來(lái)構(gòu)造新模型。

現(xiàn)在,有這種感覺(jué)嗎?

可以在Github存儲(chǔ)庫(kù)中找到此演示的所有代碼。
https://github.com/tirthajyoti/PyTorch_Machine_Learning
在本文中,總結(jié)了一些關(guān)鍵步驟,可以遵循這些關(guān)鍵步驟來(lái)快速構(gòu)建用于分類或回歸任務(wù)的神經(jīng)網(wǎng)絡(luò)。還展示了如何使用此框架輕松地嘗試巧妙的想法。
交流群
歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺(jué)、傳感器、自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN、算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三?+?上海交大?+?視覺(jué)SLAM“。請(qǐng)按照格式備注,否則不予通過(guò)。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~
