Lesson 9.5 从0实现多层神经网络的正向传播
五、從0實現深度神經網絡的正向傳播
學到這里,我們已經學完了一個普通深度神經網絡全部的基本元素——用來構筑神經網絡的結構的層與激活函數,輸入神經網絡的數據(特征、權重、截距),并且我們了解從左向右的過程是神經網絡的正向傳播(也叫做前向傳播,或者向前傳播)。還記得我們的架構圖嗎?在過去的課程中我們所學習的內容都是在torch.nn這個模塊下,現在我們就使用封裝好的torch.nn模塊來實現一個完整、多層的神經網絡的正向傳播。
假設我們有500條數據,20個特征,標簽為3分類。我們現在要實現一個三層神經網絡,這個神經網絡的架構如下:第一層有13個神經元,第二層有8個神經元,第三層是輸出層。其中,第一層的激活函數是relu,第二層是sigmoid。我們要如何實現它呢?來看代碼:
#繼承nn.Module類完成正向傳播 import torch import torch.nn as nn from torch.nn import functional as F #確定數據torch.manual_seed(420) X = torch.rand((500,20),dtype=torch.float32) y = torch.randint(low=0,high=3,size=(500,1),dtype=torch.float32) #繼承nn.Modules類來定義神經網路的架構class Model(nn.Module):#init:定義類本身,__init__函數是在類被實例化的瞬間就會執行的函數def __init__(self,in_features=10,out_features=2): #in_features: 輸入該神經網絡的特征數目#out_features: 神經網絡的輸的出數目(分類的數目)super(Model,self).__init__() #super(請查找這個類的父類,請使用找到的父類替換現在的類)self.linear1 = nn.Linear(in_features,13,bias=True) #輸入層不用寫,這里是隱藏層的第一層self.linear2 = nn.Linear(13,8,bias=True)self.output = nn.Linear(8,out_features,bias=True)#__init__之外的函數,是在__init__被執行完畢后,就可以被調用的函數def forward(self, x):z1 = self.linear1(x)sigma1 = torch.relu(z1)z2 = self.linear2(sigma1)sigma2 = torch.sigmoid(z2)z3 = self.output(sigma2)sigma3 = F.softmax(z3,dim=1)return sigma3input_ = X.shape[1] #特征的數目 output_ = len(y.unique()) #分類的數目#實例化神經網絡類 torch.manual_seed(420) net = Model(in_features=input_, out_features=output_) #在這一瞬間,所有的層就已經被實例化了,所有隨機的w和b也都被建立好了net.forward(X) #查看輸出的標簽 #net(X)的結果也一樣,因為除了init外只有forward函數 #tensor([[0.4140, 0.3496, 0.2365], # [0.4210, 0.3454, 0.2336], # [0.4011, 0.3635, 0.2355], # ..., # [0.4196, 0.3452, 0.2352], # [0.4153, 0.3455, 0.2392], # [0.4153, 0.3442, 0.2405]], grad_fn=<SoftmaxBackward0>) net.forward(X).shape #torch.Size([500, 3]) net.forward(X).argmax(axis = 1) #tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # . # . # . # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) sigma = net.forward(X) sigma.max(axis=1) #torch.return_types.max(values=tensor([0.4140, 0.4210, 0.4011, 0.4253, 0.4321, 0.4133, 0.4034, 0.4247, 0.4265, # 0.4131, 0.4177, 0.4101, 0.4164, 0.4234, 0.4195, 0.4163, 0.4154, 0.4090, # 0.4183, 0.4149, 0.4096, 0.4119, 0.4098, 0.4181, 0.4208, 0.4206, 0.4203, # . # . # . # 0.4150, 0.4169, 0.4135, 0.4201, 0.4259, 0.4095, 0.4218, 0.4181, 0.4158, # 0.4081, 0.4123, 0.4196, 0.4153, 0.4153], grad_fn=<MaxBackward0>), #indices=tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # . # . # . # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) net.linear1.weight #Parameter containing: #tensor([[ 1.3656e-01, -1.3459e-01, 2.1281e-01, -1.7763e-01, -6.8218e-02, # -1.5410e-01, 1.7245e-01, 8.3885e-02, -1.1153e-01, -1.7294e-01, # -1.2947e-01, -4.3138e-02, -1.1413e-01, 1.6295e-01, -9.4082e-02, # -1.4629e-01, -6.8982e-02, -2.1836e-01, -1.0859e-01, -1.2199e-01], # . # . # . # [-1.2258e-01, -6.8325e-02, -2.1929e-01, -1.4939e-01, 1.9226e-01, # -6.2922e-02, -7.6377e-02, 2.1955e-01, -4.5838e-02, 9.8011e-03, # -2.9400e-03, -9.5241e-02, -7.9775e-02, -1.8708e-01, 1.7828e-01, # -1.7552e-01, -1.0328e-01, -1.9697e-02, -1.7449e-01, 2.0408e-02]], # requires_grad=True) net.linear1.bias #Parameter containing: #tensor([ 1.3508e-01, 1.5439e-01, -1.9350e-01, -6.8777e-02, 1.3787e-01, # -1.8474e-01, 1.2763e-01, 1.8031e-01, 9.5152e-02, -1.2660e-01, # 1.4317e-01, -1.4945e-01, 3.4258e-05], requires_grad=True) net.linear1.weight.shape #torch.Size([13, 20]) # w*X X(500,20)——>自動轉化成——>(20,500) (13, 20)*(20,500) = (13,500) net.linear2.weight.shape #后 #前 #torch.Size([8, 13]) net.output.weight.shape #torch.Size([3, 8]) 最后從(3,500)——>自動轉化成——>(500,3)如果你是初次接觸“類”,那這段代碼中新內容可能會有點多。但如果你對python基礎比較熟悉,你就會發現這個類其實非常簡單。在神經網絡的類中,我們以線性的順序從左向右描繪神經網絡的計算過程,并且無需考慮在這之間www的結構是如何,矩陣之間如何進行相互運算。所以只要你對自己要建立的神經網絡的架構是熟悉的,pytorch代碼就非常容易。在這里,特別需要強調一下的可能是super函數的用法。
super函數用于調用父類的一個函數,在這里我們使用super函數來幫助子類(我們建立的神經網絡模型)繼承一些通過類名調用無法被繼承的屬性和方法。謹防小伙伴們不熟悉super的用法,在這里我們來說明一下:
#建立一個父類 class FooParent(object):def __init__(self):self.parent = 'PARENT!!'print ('Running __init__, I am parent')def bar(self,message):self.bar = "This is bar"print ("%s from Parent" % message) FooParent() #父類實例化的瞬間,運行自己的__init__ #Running __init__, I am parent #<__main__.FooParent at 0x7f93b8c122e0> FooParent().parent #父類運行自己的__init__中定義的屬性 #Running __init__, I am parent #'PARENT!!'#建立一個子類,并通過類名調用讓子類繼承父類的方法與屬性 class FooChild(FooParent):def __init__(self):print ('Running __init__, I am child') #查看子類是否繼承了方法 FooChild() #Running __init__, I am child #<__main__.FooChild at 0x7f9388024eb0> FooChild().bar("HAHAHA") #Running __init__, I am child #HAHAHA from Parent FooChild().parent '''子類沒有繼承到父類的__init__中定義的屬性 為了讓子類能夠繼承到父類的__init__函數中的內容,我們使用super函數 新建一個子類,并使用super函數''' #Running __init__, I am child #-------------------------------------------------------------#-------------- #AttributeError Traceback (most #recent call last) #<ipython-input-39-8b9902cbe6fd> in <module> #----> 1 FooChild().parent #子類沒有繼承到父類的__init__中定義的屬性 # 2 #為了讓子類能夠繼承到父類的__init__函數中的內容,我們使用super函數 # 3 #新建一個子類,并使用super函數 # #AttributeError: 'FooChild' object has no attribute 'parent' '''以上內容表示,通過class a(b)方法不能繼承父類的__init__中定義的屬性和方法'''class FooChild(FooParent):def __init__(self):super(FooChild,self).__init__()print ('Child')print ("I am running the __init__") #再次調用parent屬性 FooChild() #執行自己的init功能的同時,也執行了父類的init函數定義的功能 #Running __init__, I am parent #父類那里繼承來的 #Child #I am running the __init__ #<__main__.FooChild at 0x7f93a256b6a0> FooChild().parent #Running __init__, I am parent #Child #I am running the __init__ #'PARENT!!'通過使用super函數,我們的神經網絡模型從nn.Module那里繼承了哪些有用的屬性和方法呢?首先,如果不加super函數,神經網絡的向前傳播是無法運行的:
class Model(nn.Module):def __init__(self,in_features=10,out_features=2):#super(Model,self).__init__() #super(請查找這個類的父類,請使用找到的父類替換現在的類)self.linear1 = nn.Linear(in_features,13,bias=True) #輸入層不用寫,這里是隱藏層的第一層self.linear2 = nn.Linear(13,8,bias=True)self.output = nn.Linear(8,out_features,bias=True)def forward(self, x):z1 = self.linear1(x)sigma1 = torch.relu(z1)z2 = self.linear2(sigma1)sigma2 = torch.sigmoid(z2)z3 = self.output(sigma2)sigma3 = F.softmax(z3,dim=1)return sigma3 net=Model(in_features=input_, out_features=output_)輸出結果:
nn.Module類的定義代碼有一千多行,其__init__函數中有許多復雜的內容需要被繼承,因此super函數一定不能漏下。
我們從nn.Module中繼承了這些有用的方法:
輸出結果:
#一個特殊的方法 net.parameters() #一個迭代器,我們可以通過循環的方式查看里面究竟是什么內容 for param in net.parameters():print(param) #[*net.parameters()]輸出結果:
當然,nn.Module中的方法完全不止這幾個。之后我們用到更多方法時,我們會一一向大家進行介紹。相信你現在已經對從0建立自己的神經網絡有些感覺了,之后我們會在這個代碼的基礎上,不斷加入新知識,并讓我們的代碼變得越來越豐富。試試看自己編寫一個架構,進行一些探索,并執行完整的向前傳播流程吧。
總結
以上是生活随笔為你收集整理的Lesson 9.5 从0实现多层神经网络的正向传播的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Lesson 8.5 SOFTMAX回归
- 下一篇: LESSON 10.110.210.3