Lesson 8.18.2 单层回归神经网络torch.nn.Linear实现单层回归神经网络的正向传播
????????在之前的介紹中,我們已經了解了神經網絡是模仿人類大腦結構所構建的算法,在人腦里,我們有軸突連接神經元,在算法中,我們用圓表示神經元,用線表示神經元之間的連接,數據從神經網絡的左側輸入,讓神經元處理之后,從右側輸出結果。
上圖是一個最簡單的神經元的結構。從這里開始,我們正式開始認識神經網絡。
一、單層回歸網絡:線性回歸
1 單層回歸網絡的理論基礎
許多人都以為神經網絡是一個非常復雜的算法,其實它的基本原理其實并不難理解。還記得我們在講解GPU那一節曾提到過的,深度學習中的計算是“簡單大量”,而不是”復雜的單一問題“嗎?神經網絡的原理很多時候都比經典機器學習算法簡單。了解神經網絡,可以從線性回歸算法開始。在之前的課程中,我們講解過PyTorch基本數據結構Tensor和基本庫Autograd,在給autograd舉例時,我們對線性回歸其實已經有簡單的說明,在這里,給大家復習一下,并且明確一些數學符號。
線性回歸算法是機器學習中最簡單的回歸類算法,多元線性回歸指的就是一個樣本對應多個特征的線性回歸問題。假設我們的數據現在就是二維表,對于一個有個特征的樣本而言,它的預測結果可以寫作一個幾乎人人熟悉的方程:
z^i=b+w1xi1+w2xi2+…+wnxin\hat{z}_{i}=b+w_{1} x_{i 1}+w_{2} x_{i 2}+\ldots+w_{n} x_{i n} z^i?=b+w1?xi1?+w2?xi2?+…+wn?xin?
www和bbb被統稱為模型的權重,其中b被稱為截距(intercept),也叫做偏差(bias),w1w_{1}w1?~wnw_{n}wn?被稱為回歸系數(regression coefficient),也叫作權重(weights),wi1w_{i 1}wi1?~winw_{i n}win?是樣本 上的不同特征。這個表達式,其實就和我們小學時就無比熟悉的y=ax+by = ax + by=ax+b是同樣的性質。其中yyy被我們稱為因變量,在線性回歸中表示為zzz,在機器學習中也就表現為我們的標簽。如果寫作zzz ,則代表真實標簽。如果寫作z^\hat{z}z^(讀作z帽或者zhat),則代表預測出的標簽。模型得出的結果,一定是預測的標簽。
如果考慮我們有m個樣本,則回歸結果可以被寫作:
z^=b+w1x1+w2x2+…+wnxn\hat{\boldsymbol{z}}=b+w_{1} \boldsymbol{x}_{1}+w_{2} \boldsymbol{x}_{2}+\ldots+w_{n} \boldsymbol{x}_{n}z^=b+w1?x1?+w2?x2?+…+wn?xn?
其中z^\hat{z}z^是包含了m個全部的樣本的預測結果的列向量。注意,我們通常使用粗體的小寫字母來表示列向量,粗體的大寫字母表示矩陣或者行列式。并且在機器學習中,我們默認所有的一維向量都是列向量。我們可以使用矩陣來表示上面多個樣本的回歸結果的方程,其中www可以被看做是一個結構為(n+1,1)的列矩陣(這里的n加上的1是我們的截距b), 是一個結構為(m,n+1)的特征矩陣(這里的n加上的1是為了與截距b相乘而留下的一列1,這列1有時也被稱作x0x_{0}x0?),則有:
[z^1z^2z^3…z^m]=[1x11x12x13…x1n1x21x22x23…x2n1x31x32x33…x3n…1xm1xm2xm3…xmn]?[bw1w2…wn]z^=Xw\begin{aligned} \left[\begin{array}{c} \hat{z}_{1} \\ \hat{z}_{2} \\ \hat{z}_{3} \\ \ldots \\ \hat{z}_{m} \end{array}\right] &=\left[\begin{array}{cccccc} 1 & x_{11} & x_{12} & x_{13} & \ldots & x_{1 n} \\ 1 & x_{21} & x_{22} & x_{23} & \ldots & x_{2 n} \\ 1 & x_{31} & x_{32} & x_{33} & \ldots & x_{3 n} \\ & & \ldots & & & \\ 1 & x_{m 1} & x_{m 2} & x_{m 3} & \ldots & x_{m n} \end{array}\right] *\left[\begin{array}{c} b \\ w_{1} \\ w_{2} \\ \ldots \\ w_{n} \end{array}\right] \\ & \hat{\boldsymbol{z}}=\boldsymbol{X} \boldsymbol{w} \end{aligned} ???????z^1?z^2?z^3?…z^m??????????=???????1111?x11?x21?x31?xm1??x12?x22?x32?…xm2??x13?x23?x33?xm3??…………?x1n?x2n?x3n?xmn?????????????????bw1?w2?…wn?????????z^=Xw?
如果在我們的方程里沒有常量b,我們則可以不寫XXX中的第一列以及www中的第一行。
線性回歸的任務,就是構造一個預測函數來映射輸入的特征矩陣XXX和標簽值yyy的線性關系。這個預測函數的圖像是一條直線,所以線性回歸的求解就是對直線的擬合過程。預測函數的符號在不同的教材上寫法不同,可能寫作f(x)f(x)f(x),yw(x)y_{w}(x)yw?(x)或者h(x)h(x)h(x)等等形式,但無論如何,這個預測函數的本質就是我們需要構建的模型,而構造預測函數的核心就是找出模型的權重向量www,也就是求解線性方程組的參數(相當于求解y=ax+by = ax+by=ax+b里的aaa與bbb)。
現在假設,我們的數據只有2個特征,則線性回歸方程可以寫作如下結構:
z^=b+x1w1+x2w2\hat{z}=b+x_{1} w_{1}+x_{2} w_{2}z^=b+x1?w1?+x2?w2?
此時,我們只要對模型輸入特征x1x_{1}x1?,x2x_{2}x2?的取值,就可以得出對應的預測值z^\hat{z}z^。神經網絡的預測過程是從神經元左側輸入特征,讓神經元處理數據,并從右側輸出預測結果。這個過程和我們剛才說到的線性回歸輸出預測值的過程是一致的。如果我們使用一個神經網絡來表達線性回歸上的過程,則可以有:
?
這就是一個最簡單的單層回歸神經網絡的表示圖。
在神經網絡中,豎著排列在一起的一組神經元叫做“一層網絡”,所以線性回歸的網絡直觀看起來有兩層,兩層神經網絡通過寫有參數的線條相連。我們從左側輸入常數1和特征取值x1x_{1}x1?,x2x_{2}x2?,再讓它們與相對應的參數相乘,就可以得到bbb,w1x1w_{1}x_{1}w1?x1?,w2x2w_{2}x_{2}w2?x2?三個結果。這三個結果通過連接到下一層神經元的直線,被輸入下一層神經元。我們在第二層的神經元中將三個乘積進行加和(使用符號∑\sum∑表示),就可以得到加和結果z^\hat{z}z^,即b+w1x1+w2x2b+w_{1}x_{1}+w_{2}x_{2}b+w1?x1?+w2?x2?,這個值正是我們的預測值。可見,線性回歸方程與上面的神經網絡圖達到的效果是一模一樣的。
在上述過程中,左側的是神經網絡的輸入層(input layer)。輸入層由眾多承載數據用的神經元組成,數據從這里輸入,并流入處理數據的神經元中。在所有神經網絡中,輸入層永遠只有一層,且每個神經元上只能承載一個特征(一個xxx)或一個常量(通常都是1)。現在的二元線性回歸只有兩個特征,所以輸入層上只需要三個神經元,包括兩個特征和一個常量,其中這里的常量僅僅是被用來乘以偏差用的。對于沒有偏差的線性回歸來說,我們可以不設置常量1。
右側的是輸出層(output layer)。輸出層由大于等于一個神經元組成,我們總是從這一層來獲取預測結果。輸出層的每個神經元上都承載著單個或多個功能,可以處理被輸入神經元的數據。在線性回歸中,這個功能就是“加和”,當我們把加和替換成其他的功能,就能夠形成各種不同的神經網絡。
在神經元之間相互連接的線表示了數據流動的方向,就像人腦神經細胞之間相互聯系的“軸突”。在人腦神經細胞中,軸突控制電子信號流過的強度,在人工神經網絡中,神經元之間的連接線上的權重也代表了“信息可通過的強度。最簡單的例子是,當w1w_{1}w1?為0.5時,在特征x1x_{1}x1?上的信息就只有0.5倍能夠傳遞到下 一層神經元中,因為被輸入到下層神經元中去進行計算的實際值是0.5x1x_{1}x1?。相對的,如果x1x_{1}x1?是2.5,則會傳遞2.5倍的x1x_{1}x1?上的信息。因此,有的深度學習課程會將權重www比喻成是電路中的”電壓“,電壓越大,則電信號越強烈,電壓越小,信號也越弱,這都是在描述權重www會如何影響傳入下一層神經元的信息/數據量的大小。
到此,我們已經了解了線性回歸的網絡是怎么一回事,它是最簡單的回歸神經網絡,同時也是最簡單的神經網絡。類似于線性回歸這樣的神經網絡,被稱為單層神經網絡。
2 tensor實現單層神經網絡的正向傳播
讓我們使用一組非常簡單(簡直是簡單過頭了)的代碼來實現一下回歸神經網絡求解的過程,在神經網絡中,這個過程是從左向右進行的,被稱為神經網絡的正向傳播(forwardspread)(當然,這是正向傳播中非常簡單的一種情況)。來看下面這組數據:
我們將構造能夠擬合出以上數據的單層回歸神經網絡:
3 tensor計算中的新手陷阱
接下來,我們對這段代碼進行詳細的說明:
#導入庫 import torch #首先生成特征張量 X = torch.tensor([[1,0,0],[1,1,0],[1,0,1],[1,1,1]]) #我們輸入的是整數,默認生成的是int64的類型 X.dtype #torch.int64 #查看一下特征張量是什么樣子 X #tensor([[1, 0, 0], # [1, 1, 0], # [1, 0, 1], # [1, 1, 1]]) X.shape #torch.Size([4, 3]) #生成標簽z = torch.tensor([-0.2, -0.05, -0.05, 0.1]) #標簽我們輸入的是浮點數,默認生成的則是float32的類型 z.dtype #torch.float32 #查看標簽 z #tensor([-0.2000, -0.0500, -0.0500, 0.1000])#定義常量b和權重w #注意,常量b所在的位置必須與特征張量X中全為1的那一列所在的位置相對應,在這里,-0.2是b, 0.15是兩個w w = torch.tensor([-0.2,0.15,0.15]) w.shape #torch.Size([3])- tensor計算中的第一大坑: PyTorch的靜態性
可以看到,只要能夠給到適合的w和b,回歸神經網絡其實非常容易實現。在這里,我們需要提出PyTorch中另一個比較嚴肅的問題。
最安全的辦法定義的時候都把類型寫上float32,標簽來說定義成二維的。
- tensor計算中的第二大坑:精度問題
來看這段代碼。
在多元線性回歸中,我們的使用SSE(誤差平方和,有時候也叫做RSS殘差平方和)來衡量回歸的結果優劣:
SSE=∑i=1m(zi?z^i)2SSE=\sum_{i=1}^{m}\left(z_{i}-\hat{z}_{i}\right)^{2} SSE=i=1∑m?(zi??z^i?)2
如果預測值z^i\hat{z}_{i}z^i?與真實值zi{z}_{i}zi?完全相等,那SSE的結果應該為0。在這里,SSE雖然非常接近0,但的確是不為0的。
4 torch.nn.Linear實現單層回歸神經網絡的正向傳播
在PyTorch中,我們使用類torch.nn.Linear類來實現單層回歸神經網絡,不過需要注意的是, 它可不是代表單層回歸神經網絡這個算法。還記得之前我們的架構圖嗎?
從這張架構圖中我們可以看到,torch.nn是包含了構筑神經網絡結構基本元素的包,在這個包中,你可以找到任意的神經網絡層。這些神經網絡層都是nn.Module這個大類的子類。我們的torch.nn.Linear就是神經網絡中的”線性層“,它可以實現形如z^=Xw\hat{\mathbf{z}}=\boldsymbol{X} \boldsymbol{w}z^=Xw的加和功能。在我們的單層回歸神經網絡結構圖中,torch.nn.Linear類表示了我們的輸出層。現在我們就來看看它是如何使用的。
回顧一下我們的數據:
接下來,我們使用nn.Linear來實現單層回歸神經網絡:
怎么樣,代碼是不是異常簡單?但在這段代碼中,卻有許多細節需要聲明:
nn.Linear是一個類,在這里代表了輸出層,所以我使用output作為變量名,output = 的這一行相當于是類的實例化過程
實例化的時候,nn.Linear需要輸入兩個參數,分別是(上一層的神經元個數——上一層的神經元中,給這一層傳輸數據的神經元的個數,這一層的神經元個數——接收傳輸數據的神經元的個數)。上一層是輸入層,因此神經元個數由特征的個數決定(2個)。這一層是輸出層,作為回歸神經網絡,輸出層只有一個神經元。因此nn.Linear中輸入的是(2,1)。
我只定義了X,沒有定義w和b。所有nn.Module的子類,形如nn.XXX的層,都會在實例化的同時隨機生成w和b的初始值。所以實例化之后,我們就可以調用以下屬性來查看生成的和:
output.weight #查看生成的w #Parameter containing: #tensor([[ 0.3897, -0.2741]], requires_grad=True) output.bias #查看生成的b #Parameter containing: #tensor([0.0972], requires_grad=True)其中,w是必然會生成的,b是我們可以控制是否要生成的。在nn.Linear類中,有參數bias,默認bias = True。如果我們希望不擬合常量b,在實例化時將參數bias設置為False即可:
output = torch.nn.Linear(2,1,bias=False) #再次調用屬性weight和bias output.weight #Parameter containing: #tensor([[ 0.0868, -0.3132]], requires_grad=True) output.bias由于w和b是隨機生成的,所以同樣的代碼多次運行后的結果是不一致的。如果我們希望控制隨機性,則可以使用torch中的random類。如下所示:
torch.random.manual_seed(888) #人為設置隨機數種子 output = torch.nn.Linear(2,1) zhat = output(X) zhat #tensor([[-0.5236], # [-1.1635], # [-0.2499], # [-0.8898]], grad_fn=<AddmmBackward0>)由于不需要定義常量b,因此在特征張量中,也不需要留出與常數項相乘的x0那一列。在輸入數據時,我們只輸入了兩個特征x1與x2
輸入層只有一層,并且輸入層的結構(神經元的個數)由輸入的特征張量決定,因此在PyTorch中構筑神經網絡時,不需要定義輸入層
實例化之后,將特征張量輸入到實例化后的類中,即可得出輸出層的輸出結果。
讓我們來看看輸出結果的形狀:
這個形狀與我們自己定義的z是一致的。但就數字大小上來說,由于我們沒有自己定義w和b,所以我們無法讓nn.Linear輸出的zhat與我們真實的z接近——讓真實值與預測值差異更小的部分,我們會在之后進行講解。現在,讓我們繼續了解神經網絡。在下一節中,我們會將單層回歸神經網絡的例子推廣到分類問題上。
總結
以上是生活随笔為你收集整理的Lesson 8.18.2 单层回归神经网络torch.nn.Linear实现单层回归神经网络的正向传播的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Lesson 7 (3) 深入理解PyT
- 下一篇: Lesson 8.38.4 二分类神经网