深度學習之Pytorch(一)神經網路基礎及程式碼實現

是豬豬呀發表於2020-10-08

1.1 Tensor (張量)

  • Tensor 可以和 numpy 的 ndarray相互轉換
  • Tensor有不同資料型別,有32位浮點型torch.FloatTensor、64位浮點型 torch.DoubleTensor等

1.2 Variable (變數)

  • Variable 和 Tensor 本質上沒有區別,不過 Variable 會被放入一個計算圖中,然後進行前向傳播,反向傳播,自動求導。
  • Variable 有三個比較重要的組成屬性: data, grad 和 grad_fn通過 data可以取出 Variable 裡面的 tensor 數值, grad_fn 表示的是得到這個Variable 的操作,比如通過加減還是乘除來得到的,最後 grad 是這個Variabel 的反向傳播梯度.
  • 構建Variable. 要注意引數 requires_grad=True/ False,這個參數列示是否對這個變數求梯度,預設的是 False ,也就是不對這個變數求梯度
  • XXX.backward() 是對於標量求導,裡面的引數可以不寫;對於向量求導,要傳入引數宣告,比如:y.backward(torch.FloatTensor( [1, 0.1 , 0. 01] )),這樣得到的梯度就是它們原本的梯度分別乘上1,0.1和0.01

例子P37

1.3 Dataset (資料集)

  • torch.utils.data.Dataset是代表這一資料的抽象類,可以自定義資料類 繼承和重寫這個抽象類,可以通過迭代的方式來取得每一個資料。
  • 通過torch.utils.data.DataLoader定義一個新的迭代器,實現取batch, shuffle或者是多執行緒去讀取資料。

例:

torch.utils.data.DataLoader(dataset,batch_size=1,shuffle=False,sampler=None, batch_sampler

=None,num_workers=0,collate_fn=<function default_collate>, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None): 自定義資料載入器。組合了一個資料集和取樣器,並提供關於資料的迭代器。

dataset (Dataset):需要載入的資料集(可以是自定義或者自帶的資料集)。

batch_sizebatch的大小(可選項,預設值為1)。

shuffle:是否在每個epoch中shuffle整個資料集, 預設值為False

sampler:定義從資料中抽取樣本的策略. 如果指定了, shuffle引數必須為False

num_workers:表示讀取樣本的執行緒數,0表示只有主執行緒。

collate_fn:合併一個樣本列表稱為一個batch

pin_memory:是否在返回資料之前將張量拷貝到CUDA

drop_last (bool, optional) :設定是否丟棄最後一個不完整的batch,預設為False

  • 在torchvision這個包中還有更高階的有關於計算機視覺的資料讀取類: ImageFolder

要求圖片是下面這種存放形式:

root/dog/xxx.png 

root/dog/xxy.png

root/cat/ 123.png

root/cat/ 456.png

dset = lmageFolder(root='root_path',transform=None,loader=default_loader)

root是根目錄,該目錄下有幾個資料夾,每個資料夾表示一個類別: transform和 target_transform 是圖片增強,之後我們會詳細講;

loader是圖片讀取的辦法,然後通過 loader將圖片轉換成我們需要的圖片型別進入神經網路

 

1.4 nn.Module (模組)

  • 所有的層結構和損失函式都來自於torch.nn,所有的模型構建都是從這個基類nn.Module 繼承的,所有的網路層都是由 nn 這個包得到的,比如線性層 nn.Linear。
  • 定義完模型之後,我們需要通過 nn 這個包來定義損失函式。

1.5 torch.optim (優化)

優化演算法是一種調整模型引數更新的策略,通過修改引數使得損失函式最小化(或最大化)

1. 一階優化演算法

使用各個引數的梯度值來更新引數,最常用的一階優化演算法是梯度下降。梯度下降的功能是通過尋找最小值,控制方差,更新模型引數,最終使模型收斂

網路的引數更新公式

 

2. 二階優化演算法

使用了二階導數(也叫做 Hessian 方法)來最小化或最大化損失函 數,主要基於牛頓法,但是由於二階導數的計算成本很高,所以這種方法並沒有廣泛使用。

 torch.optim 是一個實現各種優化演算法的包,大多數常見的演算法都能夠直接通過這個包來呼叫,比如隨機梯度下降,具體官方例項(在優化之前需要先將梯度歸零,即 optimizer.zeros() , 然後通過 loss.backward()反向傳播,自動求導得到每個引數的梯度,最後只需要 optimizer. step ()就可以通過梯度做一步引數更新)

 

1.6 模型的儲存與載入

使用 torch.save,有兩種儲存方式:
(1) 儲存整個模型的結構和引數,儲存的物件是模型 model
(2) 儲存模型的引數,儲存的物件是模型的狀態 model.state dict()

對應於儲存模型,載入模型的方式:
(1) 載入完整的模型和引數,使用 load model = torch.load('XXX' )
(2) 載入模型引數,需要先匯入模型的結構,然後model.load state dic (torch.load('XXX')) 來匯入

 

2.1 分類問題

二分類演算法一一Logistic 迴歸

  • 非線性變換 Sigmoid 函式是 Logistic 分佈函式中 γ=1 ,μ=0 的特殊形式。

  •  Logistic 迴歸要更進一步,通過找到分類概率 P(Y =1) 與輸入變數x的直接關係,然後通過比較概率值來判斷類別.
  •  Logistic 迴歸的思路是先擬合決策邊界(這裡的決策邊界不侷限於線性,還可以是多項式),再建立這個邊界和分類概率的關係,從而得到二分類情況下的概率。
  • 模型的引數估計 具體見P44

 

2.2 程式碼實現

  • 定義模型並訓練

定義 Logistic 迴歸的模型

class  LogisticRegression(nn.Module) :

    self.lr=nn.Linear()  

    self.sm=nn.Sigmoid ()

criterion = nn.BCELoss ()

optimizer = torch . optim.SGD( logistic_model.parameters () , lr=le-3 ,momentum=0.9 )

訓練模型

for epoch in range(50000):

    變數轉成Variable形式

    前向傳播:out = model (x)    #self.lr=nn.Linear()  self.sm=nn.Sigmoid ()

              loss = criterion(out , y)

    反向傳播:optimizer. zero_grad ()

              loss.backward ()

              optimizer. step () 

 

3.1 啟用函式

簡單的一層神經網路的數學形式簡單,可以看成一個線性運算再加上一個啟用函式(可啟用變大/變小),Logistic 迴歸是使用了 Sigmoid 作為啟用函式的一層神經網路

 

適合用於前向傳播(實際基本不用)

Sigmoid 函式有以下兩大缺點

( 1 )  Sigmoid 函式靠近1和0的兩端會造成梯度消失,梯度下降法通過梯度乘上學習率來更新引數,因此如果梯度接近 0,那麼沒有任何資訊來更新引數,造成模型不收斂

( 2 )  經過 Sigmoid 啟用函式的輸出,作為後一層網路的輸入是非 0 均值的,若輸入進入下一層神經元的時候全是正的,則導致梯度全是正的,在更新引數時永遠都是正梯度。

ReLU 的優點:適合用於後向傳播

(1)相比於 Sigmoid 和 Tanh 啟用函式, ReLU 啟用函式可極大地加速隨機梯度下降法的收斂速度,這因為它是線性的,且不存在梯度消失的問題

( 2 )相比於 Sigmoid 和 Tanh 啟用函式, ReLU 的計算方法更加簡單.只需要一個閾值運算就可以得到結果,不需要進行一大堆複雜的運算。

ReLU 的缺點:

訓練的時候很脆弱.舉個例子:由於ReLU在x<0時梯度為0,這樣就導致負的梯度在這個ReLU被置零,那麼這個神經元之後的梯度就永遠是0了,不再對任何資料有所響應。在實際操作中可以通過設定比較小的學習率來避免這個小問題

 

4.Leaky ReLU  

5.Maxout  

 

3.2 神經網路的結構、模型的表示能力與容量

  • N 層神經網路並不會把輸入層算進去,因此一個一層的神經網路是指沒有隱藏層,只有輸入層和輸出層的神經網路。Logistic 迴歸就是一個一層的神經網路
  • 但是更深的全連線神經網路結構效果提升就不大了,而與此對比的是卷積神經網路的深層結構則會有更好的效果。
  • 對於容量更大(更深)的神經網路,它的區域性極小點的方差特別小,也就是說訓練多次雖然可能陷入不同的區域性極小點,但是它們之間的差異是很小的,這樣訓練就不會完全依靠隨機初始化。
  • 控制網路過擬合見後面

 

4.1 梯度下降法

  • 損失函式f , 我們用反向傳播演算法算出 f 的梯度 f(x),更新引數
  • 反向傳播就是鏈式求導:如果需要對其中的元素求導,那麼可以一層一層求導,然後將結果乘起來。求解每層網路的引數都是通過鏈式法則將前面的結果求出不斷迭代到這一層的
  • 引數更新:

第一個引數代表下一步的位置

第二個引數代表當前位置

α代表學習率,每邁出一步的距離,不能太大也不能太小

代表梯度,損失函式

 

4.2 梯度下降法的變式

人工設定學習率

1.SGD 隨機梯度下降

每次使用一批 (batch) 數掘進行梯度的計算,而不是計算全部資料的梯度

2.Momentum

相比於標準梯度下降演算法,Momentum項能夠在相關方向加速SGD,使得引數更新方向更多地沿著橫軸進行,抑制振盪,從而加快收斂

3.Nesterov

Momentum加上nesterov項後,梯度在大的跳躍後,進行計算對當前梯度進行校正

 

自適應學習率

1.Adagrad

  • 適合處理稀疏梯度
  • 中後期,分母上梯度平方的累加將會越來越大,使gradient→0,使得訓練提前結束

2.Adadelta

  • 訓練初中期,加速效果不錯,很快
  • 訓練後期,反覆在區域性最小值附近抖動

3.RMSprop

  • RMSprop算是Adagrad的一種發展,和Adadelta的變體,效果趨於二者之間
  • 適合處理非平穩目標
  • 對於RNN效果很好

4.Adam

這是一種綜合型的學習方法,可以看成是RMSprop 加上動量 (Momentum) 的學習方法,達到比 RMSProp 更好的效果。

經驗之談

  • 對於稀疏資料,儘量使用學習率可自適應的優化方法,不用手動調節,而且最好採用預設值
  • SGD通常訓練時間更長,容易陷入鞍點,但是在好的初始化和學習率排程方案的情況下,結果更可靠
  • 如果在意更快的收斂,並且需要訓練較深較複雜的網路時,推薦使用學習率自適應的優化方法。
  • Adadelta,RMSprop,Adam是比較相近的演算法,在相似的情況下表現差不多
  • 在想使用帶動量的RMSprop,或者Adam的地方,大多可以使用Nadam取得更好的效果

補充 深度學習最全優化方法總結比較

 

5.1 資料預處理

1.中心化

每個特徵維度都減去相應的均值實現中心化,這樣可以使得資料變成 0 均值,特別對於一些影像資料.

2.標準化/歸一化

  • 有兩種常用的方法:

StandardScaler:減去均值然後除以方差(或標準差),這種資料標準化方法經過處理後資料符合標準正態分佈,即均值為0,標準差為1

MinMaxScaler:將特徵縮放到給定的最小值和最大值之間,或者也可以將每個特徵的最大絕對值轉換至單位大小。

  • 標準化(歸一化)兩個優點:

  1)歸一化後加快了梯度下降求最優解的速度;

  2)歸一化有可能提高精度。

  • 經驗之談

1)在分類、聚類演算法中,需要使用距離來度量相似性的時候、或者使用PCA技術進行降維的時候,StandardScaler表現更好。

2)在不涉及協方差計算、資料不符合正態分佈的時候,可以使用MinMaxScaler。比如影像處理中,將RGB影像轉換為灰度影像後將其值限定在[0,255]的範圍。

3)使用MinMaxScaler,其協方差產生了倍數值的縮放,因此無法消除量綱對方差、協方差的影響,對PCA分析影響巨大;同時,由於量綱的存在,距離的計算結果會不同。

StandardScaler中,每個維度都是去量綱化的,避免了不同量綱的選取對距離計算產生的巨大影響。

4)若資料包含許多異常值RobustScaler 對資料的中心和範圍使用更有魯棒性的估計。

      針對稀疏矩陣,用MaxAbs

3.PCA(去噪)

資料中心化,用協方差矩陣對資料進行去相關性,投影到一個特徵空間,取主要特徵向量。

4.白噪聲(加噪)

將資料投影到一個特徵空間, 然後每個維度除以特徵值來標準化這些資料,直觀上就是一個多元高斯分佈轉化到了 一個 0 均值,協方差矩陣為 1 的多元高斯分佈 。

3. 4.在CNN中基本不用

 

5.2 權重初始化

1.全 0 初始化

不可取,否則權重相同

2. 隨機初始化

經常用,在訓練深度神經網路時可能會造成兩個問題,梯度消失和梯度爆炸

梯度消失和梯度爆炸 補充:詳解機器學習中的梯度消失、爆炸原因及其解決方法

3. 稀疏初始化

實際較少用到

4. 初始化偏置( bias )

偏置 (bias)通常是初始化為 0

5. 批標準化( Batch Normalization )

效果好,它位於X=WU+B啟用值獲得之後,非線性函式變換之前

對於每個隱層神經元,把逐漸往非線性函式的取值區間的上下限兩端靠近的啟用輸入分佈 強制拉回到 均值為0方差為1的比較標準的正態分佈,使得輸入值落入非線性函式比較敏感的區域,以此避免梯度消失問題。

具體見 深入理解Batch Normalization批標準化

 

5.3 防止過擬合

1.正則化(目的是限制引數過多或者過大,避免模型更加複雜)

L2正則化是正則化(regularization)中比較常用的形式:對於權重過大的部分進行懲罰,讓引數更新之後更加靠近0 

L1正則化是另一種正則化方法:在損失函式中增加權重的 1 範數

 

  • 在實際中通常使用 L2 正則化,我們也可以把L1正則化和 L2 正則化結合起來,如
  • L1相對於 L2 ,在優化的過程中可以讓權重變得更加稀疏,在優化結束的時候,權重只會取一些與最重要的輸入有關的權重,這就使得與噪聲相關的權重被儘可能降為 0
  • L2 會比L1更加發散,權重也會被限制得更小

補充:機器學習中 L1 和 L2 正則化的直觀解釋

還有一種正則化方法叫做最大範數限制,其迫使權重在更新的過程中範數有一個上界,可以使得當學習率設定太高的時候網路不會"爆炸"

 

2.Dropout

  • 在前向傳播的時候,讓某個神經元的啟用值以一定的概率p停止工作, 也就是說每次訓練忽略一部分的特徵檢測器(讓一部分的隱層節點值為0)
  • 在預測的時候,如果保留所有的權重(預測沒辦法隨機丟棄,若丟棄一些神經元,會帶來結果不穩定的問題),每一個神經單元的權重引數要乘以概率p。
  • 每一次訓練batch,Dropout之後就可以看作是一個新的模型,然後訓練了很多次之後就可以看成是這些模型的整合,整個dropout過程就相當於對很多個不同的神經網路取平均

 

5.4 神經網路實現

快速回憶版

1、構建好一個神經網路

2、訓練網路必須經過4步:

第一步:將輸入input向前傳播,進行運算後得到輸出output

第二步:將output再輸入loss函式,計算loss值(是個標量)

第三步:將梯度反向傳播到每個引數

第四步:利用公式進行權重更新

 

細摳程式碼版

1、搭建網路:

黃字重點

2、匯入包、定義超引數(如 batch size 、 learning rate 還有 num_epoches)

3、用torchvision.transforms進行資料預處理

4、讀取資料集(見1.3

torchvision.datasets

torch.utils.data.DataLoader。建立資料迭代器

5、匯入網路,定義損害函式和優化方法

model =  net.Batch_Net(輸入圖片維度, 隱藏層1 , 隱藏層2, 分類數)

criterion  =  nn.CrossEntropyLoss()

optimizer =  optim.SGD(model.parameters() ,  lr=learning_rate)

6、訓練網路

例:for epoch in range(50000):

    變數轉成Variable形式

    前向傳播:out = model (x)    #self.lr=nn.Linear()  self.sm=nn.Sigmoid ()

              loss = criterion(out , y)

    反向傳播:optimizer. zero_grad ()

              loss.backward ()

              optimizer. step () 

7、測試網路

 

 

 

 

 


相關文章