keras系列(一):引數設定
常用的 權重/偏置 初始化
常數初始化
為了在虛擬碼中形象化,讓我們考慮一個具有64個輸入和32個輸出的神經網路的任意一層。
W = np.zeros((64, 32))
W = np.ones((64, 32))
W = np.ones((64, 32)) * C
雖然常量初始化很容易理解和理解,但使用這種方法的問題是,我們幾乎不可能打破啟用的對稱性。因此,它很少被用作神經網路的權重初始化器。
均勻/正態分佈
W = np.random.uniform(low=-0.05, high=0.05, size=(64, 32)) W = np.random.normal(0.0, 0.5, size=(64, 32))
在神經網路中,均勻分佈和正態分佈都可以用來初始化權值;然而,我們通常使用各種啟發式來建立更好的初始化方案。
LeCun 均勻/正態分佈
在這裡,作者定義了一個引數Fin(稱為fan in,或者是層的輸入數)和Fout(稱為fan out,或層的輸出數)。使用這些值,我們可以應用統一的初始化。
F_in = 64
F_out = 32
limit = np.sqrt(3 / float(F_in))
W = np.random.uniform(low=-limit, high=limit, size=(F_in, F_out))
我們也可以用正態分佈。Keras庫使用一個截斷的正態分佈來構造上下限,以及零均值。
F_in = 64
F_out = 32
limit = np.sqrt(1 / float(F_in))
W = np.random.normal(0.0, limit, size=(F_in, F_out))
Glorot/Xavier 均勻/正態分佈
在Keras庫中使用的預設權值初始化方法稱為Glorot初始化或Xavier初始化。 對於正態分佈,其極限值是由平均的Fin和Fout組合而成,然後取平方根。然後使用一個零中心(均值為0)。
F_in = 64 F_out = 32 limit = np.sqrt(2 / float(F_in + F_out)) W = np.random.normal(0.0, limit, size=(F_in, F_out))
對於均勻分佈,同樣可以這樣做,但一般在limit上給予更強的限制。
F_in = 64
F_out = 32
limit = np.sqrt(6 / float(F_in + F_out))
W = np.random.uniform(low=-limit, high=limit, size=(F_in, F_out))
學習使用這種初始化方法是非常有效的,我推薦它適用於大多數神經網路。
He et al. / Kaiming / MSRA 均勻/正態分佈
我們通常在訓練非常深的神經網路時使用這種方法,這種神經網路使用類似於relu的啟用函式(特別是,一個’ PReLU ',或Parametric Rectified Linear Unit)。
F_in = 64
F_out = 32
limit = np.sqrt(6 / float(F_in))
W = np.random.uniform(low=-limit, high=limit, size=(F_in, F_out))
對於正態分佈可以設定均值為0,方差為 2/Fin 開方,如下:
F_in = 64
F_out = 32
limit = np.sqrt(2 / float(F_in))
W = np.random.normal(0.0, limit, size=(F_in, F_out))
其中在Keras通常設定如下:
random_uniform:
權值被初始化為一致隨機的小數值(-0.05,0.05)。換句話說,給定區間內的任何值都可能被取得。
random_normal:
根據高斯函式初始化權值,均值為零,標準差為0.05。
zero:
所有權重初始化為0。
啟用函式
左上:Step函式 右上:Sigmoid函式 左中:tanh函式 右中:Relu函式 左下:Leaky Relu函式(Relu變種) 右下:ELU函式(Relu變種)
Step函式
step函式是最簡單的啟用函式,形式如下: 然而,雖然這一階躍函式是直觀且易於使用的,但它是不可微的,當應用梯度下降和訓練我們的網路時,它會導致問題。
Sigmoid函式
如下圖所示,當輸入變化時,它的輸出變化很小(0,1)。從數學上講,函式是連續的。典型的sigmoid函式在下圖中表示:
一個神經元可以使用sigmoid來計算非線性函式 F(z = wx + b)。請注意,如果z = wx + b的值是非常大的且為正的,那麼F(z = wx + b)趨於0,如果z = wx + b的值是非常大的且為負的,那麼F(z = wx + b)趨於1。換句話說,具有sigmoid啟用的神經元具有類似於感知器的行為,但變化是漸進的,輸出值(如0.5539或0.123191)是完全可行的。
Tanh函式
tanh函式以零為中心,但當神經元飽和時,梯度仍然會消失。
ReLU函式
sigmoid並不是用於神經網路的唯一一種平滑啟用函式。最近,一個非常簡單的函式稱為整流線性單元(ReLU)變得非常流行,因為它能產生非常好的效果。
一個ReLU被簡單地定義為 F(x) = max(0,x),而非線性函式在下圖中表示。正如你在下面的圖中所看到的,負值的函式為零,它在正值方向線性增長。 截止到2015年,Relu函式是深度學習中最流行的啟用函式,但是問題是當有一個值為0時,梯度就無法取得。
Leaky Relus函式
一種名為Leaky ReLUs的ReLUs變體,當該神經元未啟用時,允許有一個小的、非零的梯度。
我們可以看到,這個函式確實被允許帶有負值,而傳統的ReLUs則是從0開始輸出。
ELUs函式
也是Relus函式的一個變體,通常情況下ELUs會獲得比Relus更好的分類精度。
Summary
在Keras部分的不同優化器中,我們將看到這些典型的sigmoid和ReLU函式,是開發一種學習演算法的基本模組.。在幾乎所有的情況下,我建議從一個ReLU開始,以獲得基本的準確性(就像大多數發表在深度學習文獻中的論文一樣)。從那裡你可以試著把你的標準ReLU換成一個Leaky ReLU變體。
我個人的偏好是,從一個ReLU開始,調優我的網路和優化器引數(體系結構、學習速率、正則化強度等),並注意準確性。一旦我對準確性相當滿意,我就會在ELU上進行交換,並且通常會注意到根據資料集的分類精度提高了1-5%。
Keras支援許多啟用函式,具體如下: 啟用函式
損失函式
MSE
這是預測和真實值之間的平均平方誤差。
Binary cross-entropy
其中 p 是模型的預測值,t 是目標值,這個目標函式適用於二分類的問題。
Categorical cross-entropy
這個目標函式適用於多分類任務,它也是與softmax啟用關聯的預設選擇。
其他一些常用的目標函式如下: 目標函式
模型評判指標
Accuracy
這是對目標的正確預測的比例。
Precision
Precision = TP / (TP + NF)
Recall
Recall = TF / (NP + TF) 指標與目標函式相似,惟一的區別是它們不用於培訓模型,而僅用於評估模型,在Keras中編譯模型很簡單。
其他一些常用的評判標準如下: 評判標準
Optimizers
Keras實現了梯度下降的快速變種,稱為隨機梯度下降(SGD)和兩種更高階的優化技術,稱為RMSprop和Adam。 RMSprop和Adam包括了動量的概念(速度分量),除了SGD的加速度分量。這允許以更高的計算速度更快地收斂。
SGD
即使有了一些更新的優化方法,SGD仍然是深度學習的工具,大多數神經網路都是通過SGD訓練的,包括在像ImageNet這樣的具有挑戰性的影象資料集上獲得最先進精度的網路。
當訓練深度學習網路時,特別是當你第一次開始學習和學習的時候,SGD應該是你選擇的優化器。然後需要設定適當的學習速率和正則化強度,需要訓練網路的總時數,以及是否應該使用動量(如果有的話,是哪個值)或Nesterov加速。花些時間和SGD進行儘可能多的實驗,並熟悉調優引數。
Adam/RMSprop
from keras.optimizers import RMSprop, Adam
...
OPTIMIZER = RMSprop() # optimizer
OPTIMIZER = Adam() # optimizer
SGD的延伸
在實踐中,將遇到兩個主要的擴充套件。
Momentum(動量)
在SGD上應用的動量和我們的目標一樣,我們的目標是在標準的重量更新中增加一個動量項,從而使我們的模型在更少的迭代中獲得更低的損失(更高的精度)。
之前SGD的更新方式為: 現在介紹動態項 V ,如下:
動量項 r 通常設為0.9,雖然另一種常見的做法是將g調到0.5,直到學習穩定,然後將其增加到0.9,但是很少看到動量< 0.5。
Nesterov加速度
Nesterov加速可以被概念化為對動量的修正更新。 使用標準動量,我們計算梯度(小藍向量),然後在梯度方向(大藍色向量)上大跳躍。在Nesterov加速度下,我們首先會在我們之前的梯度(棕色向量)的方向上做一個大的跳躍,測量梯度,然後做一個修正(紅色向量)綠色向量是Nesterov加速度的最終修正的更新。
我個人的經驗是,每當使用SGD時,要應用動量。在大多數情況下,可以設定為0.9。儘管有建議從0.5開始,並隨著時間的增加,將其增加到更大的值。
對於Nesterov加速,我傾向於在較小的資料集上使用它,但是對於更大的資料集(如ImageNet),我幾乎總是避免使用它。
Regularization
正則化幫助我們控制模型容量,確保我們的模型能夠更好地在未訓練的資料上正確分類,這也成為泛化能力。正則化是僅次於學習速率,模型最重要的引數(用於解決overfitting)。
正則化技術有多種型別,如L1正則化、L2正則化(通常稱為權衰減)和Elastic Net[98],用於更新損失函式本身,增加一個附加引數來約束模型的容量。
然而,過多的正規化可能是一件壞事。在這種情況下,我們的模型在訓練資料上可能表現不佳,無法對輸入資料和輸出類標籤之間的關係建模(因為我們的模型容量太有限),即underfitting。
包含L2正則化的Cross-entropy loss函式: 同樣,加入正則化的Multi-class SVM loss函式如下: 該方法根據學習速率的梯度倍數對權重進行更新,考慮正則化的權重更新為:
L2 正則化
模型的複雜度表示為權重平方和。
L1正則化
模型的複雜性表示為權重絕對值的和。
Elastic net 正則化
該模型的複雜性是由上述兩種技術的組合而成的。
keras中正則化的設定如下:
from keras import regularizers
model.add(Dense(64, input_dim=64,
kernel_regularizer=regularizers.l2(0.01),
activity_regularizer=regularizers.l1(0.01)))
Drop out
Drop out實際上是一種正規化的形式,目的是通過提高測試的準確性來防止過度擬合,也許是以犧牲訓練的準確性為代價。
在網路結構的FC層之間,最常見的是加入drop out層,並設定 p = 0.5。在網路的前些層,也可以設定p = 0.10-0.25。
keras.layers.core.Dropout(rate, noise_shape=None, seed=None)
其中:
rate:它是一個介於0和1之間的浮點數,它表示輸入單元的下降速率。
noise_shape:它是一個1維整數張量,它表示將與輸入相乘的二維dropout mask的形狀。
seed:它是一個被用作隨機種子的整數。
其他超引數調節
batch sizes
通常設定為32,64,128 和 256
Batch normalization
Batch normalization:通過減少內部協變數轉變加速深層網路訓練,簡稱BN。顧名思義,是用來在網路中傳遞到下一層前規範給定輸入的啟用值。
如果認為x是mini-batch的啟用值,則:
BN已經被證明在減少訓練神經網路的時間上是非常有效的。批量標準化也有幫助穩定訓練的附加好處,允許更大的學習速率和正則化強度。使用批量標準化並不會減少對這些引數的調整,但是這會使學習速率和正則化變得更簡單,更容易調整。也就是說,我建議在幾乎所有情況下使用批量標準化,因為它確實有很大的不同。
BN最大的缺點是,它實際上可以使網路執行速度慢下來。
keras.layers.normalization.BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001, center=
也就是說,額外的訓練時間往往超過了負面效果,我強烈建議您將批處理規範化應用到您自己的網路體系結構中。
如在VGGNet中:
# first CONV => RELU => CONV => RELU => POOL layer set
model.add(Conv2D(32, (3, 3), padding="same",
input_shape=inputShape))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(32, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
學習率
梯度下降演算法是通過學習速率來控制的,在訓練你自己的模型時,學習率是最重要的引數。
通常設定學習速率是恆定的,然後在不改變學習速率的情況下訓練網路。這種方法在某些情況下可能會很有效,但隨著時間的推移,降低我們的學習速度通常會表現更好。
The Standard Decay Schedule in Keras
一種常見的學習率衰減方法是將初始學習速率除以當前訓練的總次數,如:用初始學習速率0.01來訓練網路,總共訓練次數為epochs,因此衰減= 0.01 / epochs。
在keras中使用學習率變化的公式如下: 如果設定decay (公式中 r)為0,則不更新學習率。
opt = SGD(lr=0.01, decay=0.01 / 40, momentum=0.9, nesterov=True)
model = MiniVGGNet.build(width=32, height=32, depth=3, classes=10)
model.compile(loss="categorical_crossentropy", optimizer=opt,metrics=["accuracy"])
通過學習速率衰減,我們不僅可以提高分類精度,還可以減少過度擬合的影響,從而提高模型的泛化能力。
Step-based Decay
當我們的學習速度逐步衰減時,我們有兩個選擇:
1.定義一個方程,模型是我們希望達到的學習速率的分段下降。 2.使用我所稱的***ctrl + c方法***來訓練一個深度學習網路,在一個給定的學習速率下,我們訓練一些不同的時代,最終發現驗證效能已經停滯,然後按ctrl + c停止指令碼,調整我們的學習速度,並繼續訓練。
在keras自定義學習率函式
學習率函式設定如下: F越大,則學習率下降的越慢。 公式形式如下:
alpha = initAlpha * (factor ** np.floor((1 + epoch) / dropEvery))
在keras的程式碼如下:
from keras.callbacks import LearningRateScheduler
從Keras庫中匯入我們的LearningRateScheduler,這個類將使我們能夠定義我們自己的自定義學習速率排程器。
def step_decay(epoch):
# initialize the base initial learning rate, drop factor, and
# epochs to drop every
initAlpha = 0.01
factor = 0.25
dropEvery = 5
# compute learning rate for the current epoch
alpha = initAlpha * (factor ** np.floor((1 + epoch) / dropEvery))
# return the learning rate
return float(alpha)
定義初始學習速率0.01,下降因子0.25,設定dropEvery = 5,這意味著我們每5個epochs會將學習速率降低0.25。
# define the set of callbacks to be passed to the model during
# training
callbacks = [LearningRateScheduler(step_decay)]
# initialize the optimizer and model
opt = SGD(lr=0.01, momentum=0.9, nesterov=True)
model = MiniVGGNet.build(width=32, height=32, depth=3, classes=10)
model.compile(loss="categorical_crossentropy", optimizer=opt,metrics=["accuracy"])
# train the network
H = model.fit(trainX, trainY, validation_data=(testX, testY),batch_size=64, epochs=40, callbacks=callbacks, verbose=1)