個人電腦在pip
上下載Pytorch報錯,所以使用Anaconda下載,在此再也不贅述。html
首先咱們約定嘗試搭建兩層神經網絡,數據量$N=64$,輸入層、隱藏層、輸出層的維度分別是:$d_{in}=1000,H=100,d_{out}=10$python
由於是一個Demo
,因此嘗試直接使用一些隨機數據進行測試:網絡
# 64個數據,1000-dim,,中間層100-dim,輸出10-dim x = torch.randn(N, d_in, requires_grad=True) y = torch.randn(N, d_out, requires_grad=True)
注意在這個時候須要寫出requires_grad=True
,方便後續使用.grad
屬性直接計算梯度。app
接下來就是要定義一個模型,這個模型咱們是打算使用兩層的神經網絡,首先在官方的Doc中是這樣定義torch.nn.module
的用法的:框架
Base class for all neural network modules.ide
Your models should also subclass this class.函數
查閱Doc,主要有幾個點是應該會用到的:學習
torch.nn.module
應當是全部神經網絡的基類,而且你要是寫一個神經網絡也應該繼承自此。.cuda()
函數。對於其中的__init__
,就是勾勒出整個模型的框架,咱們首先須要把基類的構造函數進行調用,而後把本模型所須要的函數進行定義,由於咱們想要作兩層的神經網絡,因此分別聲明兩層線性的函數。測試
對於其中的forward
,是全部的子類都必須得進行override,表明了前向傳播的逐層映射關係。激活函數咱們約定使用ReLu
也就是.clamp(min=0)
。優化
因此咱們能夠寫成下面這個樣子:
class TwoLayerNet(torch.nn.module): # 定義了init和forward就想到於給定了一個模型 # init至關於給了這個框架 def __init__(self, d_in, H, d_out): super(TwoLayerNet, self).__init__() self.linear1 = nn.Linear(d_in, H) self.linear2 = nn.Linear(H, d_out) # forward是定義前向傳播的部分 def forward(self, x): y_pred = self.linear2(self.linear1(x).clamp(min=0)) return y_pred
主要是兩個方面,第一是把上面定義好的框架應用起來,第二是給定學習率和loss function。
# 初始化model model = TwoLayerNet(d_in, H, d_out) # 規定loss function loss_fn = nn.MSELoss(reduction='sum') # 規定學習率 learning_rate = 1e-4
首先,咱們約定反向傳播的模型是SGD
這種比較簡單的模型:
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) loss_list = [] # 爲了畫圖
至此,咱們須要對模型有個直觀認識,對於整個模型而言應當是$x \rightarrow H \rightarrow y_{pred}$爲正向傳播路徑,而損失函數爲:
$$loss = \sqrt{y_{pred}^2-y^2} $$
對於各層神經網絡,我借用網圖來講明一下關係:
第一層神經網絡是輸入部分:因此權重矩陣$w_1$應該是$d_{in}\times H$的維度,同理,第二層神經網絡輸出權重矩陣應當是$H \times d_{out}$維度。
咱們接下來就是進行訓練迭代,咱們先約定訓練$200$代,觀察收斂效果。
for it in range(200): # forward pass y_pred = model(x) # compute loss loss = loss_fn(y_pred.float(), y.float()) print(it, loss.item()) loss_list.append(loss) # backward pass optimizer.zero_grad() loss.backward() optimizer.step()
forward pass
部分是把自變量$x$輸入到模型中,而compute loss
是計算損失數值,咱們須要注意如下這些點:
loss_fn(y_pred.float(), y.float())
不能夠寫成loss_fn(y_pred- y)
,不然會缺失一個target
參數loss.item()
是用來輸出loss
這個tensor
包含的數值而backward pass
中,咱們須要注意,每次求梯度降低以前,都須要把以前的梯度清零,緣由就是這個梯度若是不被清零,在每次迭代的時候都會被自動疊加,這樣自動疊加的好處是對於一些連鎖的梯度運算的時候更爲方便了,可是對於每一代而言都須要手動進行清零。
最後咱們只要簡單的把迭代的圖畫出來便可,效果大概是這樣的:
plt.plot(range(200), loss_list) plt.show()
大概在$10$代附近就已經收斂了,效果仍是蠻不錯的。能夠經過第一次運行的結果調整迭代次數。
下面附上整個代碼:
import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt N, d_in, H, d_out = 64, 1000, 100, 10 # 隨機建立一些訓練數據 x = torch.randn(N, d_in, requires_grad=True) y = torch.randn(N, d_out, requires_grad=True) class TwoLayerNet(torch.nn.module): # 定義了init和forward就想到於給定了一個模型 # init至關於給了這個框架 def __init__(self, D_in, H, D_out): super(TwoLayerNet, self).__init__() self.linear1 = nn.Linear(D_in, H) self.linear2 = nn.Linear(H, D_out) # forward是 def forward(self, x): y_pred = self.linear2(self.linear1(x).clamp(min=0)) return y_pred # 初始化model model = TwoLayerNet(d_in, H, d_out) # 規定loss function loss_fn = nn.MSELoss(reduction='sum') # 規定學習率 learning_rate = 1e-4 # 定義optimizer作優化 optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) loss_list = [] for it in range(200): # forward pass y_pred = model(x) # compute loss loss = loss_fn(y_pred.float(), y.float()) print(it, loss.item()) loss_list.append(loss) # backward pass optimizer.zero_grad() loss.backward() optimizer.step() plt.plot(range(200), loss_list) plt.show()