天天看點

Keras入門(2)——麻雀雖小,五髒俱全1. 什麼是Keras2. Hello World3. 小結

1. 什麼是Keras

不知什麼時候,突然對于Keras是什麼産生了困惑。Keras中文為克拉斯,相傳也是銅管樂器。

其實,Keras的名字源于希臘古典史詩《奧德賽》裡的牛角之門,是真實事物進出夢境和現實的地方。《奧德賽》裡面說,象牙之門内隻是一場無法應驗的夢境,唯有走進牛角之門奮鬥的人,能夠擁有真正的回報。其用意不可謂不深刻。

但事實上,Keras隻是深度學習模組化的一個上層建築,其後端可以靈活使用CNTK、TensorFlow或者Theano。這樣就可以避免不同深度學習架構的差異而集中于模組化過程。并且可以進行CPU和GPU之間的無縫切換。

2. Hello World

在之前的一個快速入門裡,我們隻是大概的講述了如何安裝Keras環境以及一個簡易的Demo,這次我們将會詳細講述一個真正的Hello World.下面我們先看這個示例:

##2.1引用包
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.optimizers import SGD
from keras import metrics
import keras
##2.2生成資料
# Generate dummy data
import numpy as np
x_train = np.random.random((, ))
y_train = keras.utils.to_categorical(np.random.randint(, size=(, )), num_classes=)
x_test = np.random.random((, ))
y_test = keras.utils.to_categorical(np.random.randint(, size=(, )), num_classes=)
##2.3構模組化型
model = Sequential()
# Dense(64) is a fully-connected layer with 64 hidden units.
# in the first layer, you must specify the expected input data shape:
# here, 20-dimensional vectors.
model.add(Dense(, activation='relu', input_dim=))
model.add(Dropout())
model.add(Dense(, activation='relu'))
model.add(Dropout())
model.add(Dense(, activation='softmax'))

sgd = SGD(lr=, decay=, momentum=, nesterov=True)
model.compile(loss='categorical_crossentropy',
              optimizer=sgd,
              metrics=[metrics.categorical_accuracy,metrics.mae])
##2.4訓練模型
model.fit(x_train, y_train,
          epochs=,
          batch_size=)
##2.5評估模型
score=model.evaluate(x_test, y_test, batch_size=)
print(score);
           

先别急,我們先統一說一下上述這段代碼的作用是,通過深度學習方法實作10分類問題的訓練及測試過程。具體來講,就是生成一個1000條訓練樣例,每個樣例20維,再使用同樣20維的測試資料100條,通過一個序列模型使用SGD優化算法進行訓練,其模型層數不多,3個全連接配接層和2個放棄層。就這樣一個簡單的深度學習(算不上深度)模型就搭建完畢了。不過不用擔心,我們會在接下來的部分詳細介紹這部分代碼,俗話說,麻雀雖小,五髒俱全。

2.1 引用包

先來回顧一下這部分代碼:

#引入序列模型
from keras.models import Sequential
#引入全連接配接層、放棄層、激活層(激活層沒有直接用到,但是在全連接配接層裡間接用到了。)
from keras.layers import Dense, Dropout, Activation
#引入SGD優化算法
from keras.optimizers import SGD
#引入了metrics評估子產品
from keras import metrics
#引入了keras
import keras
           

這樣一寫,我們就清楚很多了,這是編碼的必備。

2.2生成資料

還是先來回顧一下這部分代碼:

# Generate dummy data
#使用numpy來模拟生成資料
import numpy as np
#生成一個1000*20維的向量
x_train = np.random.random((, ))
#生成一個1000*10維的向量
y_train = keras.utils.to_categorical(np.random.randint(, size=(, )), num_classes=)
#同上
x_test = np.random.random((, ))
y_test = keras.utils.to_categorical(np.random.randint(, size=(, )), num_classes=)
           

别急,我知道這裡可能有些難以了解。

尤其是

keras.utils.to_categorical

這個方法,源碼中,它是這樣寫的:

Converts a class vector (integers) to binary class matrix.

E.g. for use with categorical_crossentropy.

也就是說它是對于一個類型的容器(整型)的轉化為二進制類型矩陣。比如用來計算多類别交叉熵來使用的。

其參數也很簡單:

def to_categorical(y, num_classes=None):

Arguments

y: class vector to be converted into a matrix

(integers from 0 to num_classes).

num_classes: total number of classes.

說的很明白了,y就是待轉換容器(其類型為從0到類型數目),而num_classes則是類型的總數。

這樣這一句就比較容易了解了:

#先通過np生成一個1000*1維的其值為0-9的矩陣,然後再通過```keras.utils.to_categorical```方法擷取成一個1000*10維的二進制矩陣。
y_train = keras.utils.to_categorical(np.random.randint(, size=(, )), num_classes=)
           

說了這麼多,其實就是使用onehot對類型标簽進行編碼。下面的也都是這樣解釋。

2.3構模組化型

這部分代碼如下:

#建構序列模型
model = Sequential()
# Dense(64) is a fully-connected layer with 64 hidden units.
# in the first layer, you must specify the expected input data shape:
# here, 20-dimensional vectors.
#第一層為全連接配接層,隐含單元數為64,激活函數為relu,在第一層中一定要指明輸入的次元。
model.add(Dense(, activation='relu', input_dim=))
#放棄層,将在訓練過程中每次更新參數時随機斷開一定百分比(rate)的輸入神經元,Dropout層用于防止過拟合。這裡是斷開50%的輸入神經元。
model.add(Dropout())
model.add(Dense(, activation='relu'))
model.add(Dropout())
model.add(Dense(, activation='softmax'))
#執行個體化優化算法為sgd優化算法
sgd = SGD(lr=, decay=, momentum=, nesterov=True)
#對模型進行預編譯,其損失函數為多類别交叉熵,優化算法為sgd,評估方法為多類别準确度和平均絕對誤差。
model.compile(loss='categorical_crossentropy',
              optimizer=sgd,
              metrics=[metrics.categorical_accuracy,metrics.mae])
           

這裡才是核心,我們将會分開來講。

2.3.1模型

首先這裡接觸到了model,model在Keras裡有兩種,一種是序貫模型,一種是函數式模型。

  1. 序貫模型

    序貫模型是多個網絡層的線性堆疊,也就是“一條路走到黑”。這也是非常常用的和傻瓜式的方法。

  2. 函數式(Functional)模型

    這已經是進階階段了,目前我們隻能摘取Keras中文文檔中的簡介來告訴大家,在後面我們會單獨講解。

    我們起初将Functional一詞譯作泛型,想要表達該類模型能夠表達任意張量映射的含義,但表達的不是很精确,在Keras 2裡我們将這個詞改譯為“函數式”,對函數式程式設計有所了解的同學應能夠快速get到該類模型想要表達的含義。函數式模型稱作Functional,但它的類名是Model,是以我們有時候也用Model來代表函數式模型。

    Keras函數式模型接口是使用者定義多輸出模型、非循環有向模型或具有共享層的模型等複雜模型的途徑。一句話,隻要你的模型不是類似VGG一樣一條路走到黑的模型,或者你的模型需要多于一個的輸出,那麼你總應該選擇函數式模型。函數式模型是最廣泛的一類模型,序貫模型(Sequential)隻是它的一種特殊情況。

2.3.2添加層

代碼如下:

model.add(Dense(, activation='relu', input_dim=))
           

這就是序貫模型的添加層數的方法,很簡單。這裡添加的是Keras的常用層中的全連接配接層(Dense)。它是最常用的層,也是多層感覺機(MLP)的基本構成機關。

下面我們來簡單的介紹一下目前用到的幾個層,他們都屬于常用層(Core)。

2.3.2.1. Dense層

這個層的聲明如下:

keras.layers.core.Dense(units, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, **kwargs)
           

Dense就是常用的全連接配接層,所實作的運算是output = activation(dot(input, kernel)+bias)。其中activation是逐元素計算的激活函數,kernel是本層的權值矩陣,bias為偏置向量,隻有當use_bias=True才會添加。

如果本層的輸入資料的次元大于2,則會先被壓為與kernel相比對的大小。

但是我們更關注的是參數的含義:

  • units:大于0的整數,代表該層的輸出次元。
  • activation:激活函數,為預定義的激活函數名(參考激活函數),或逐元素(element-wise)的Theano函數。如果不指定該參數,将不會使用任何激活函數(即使用線性激活函數:a(x)=x)
  • use_bias: 布爾值,是否使用偏置項
  • kernel_initializer:權值初始化方法,為預定義初始化方法名的字元串,或用于初始化權重的初始化器。參考initializers
  • bias_initializer:權值初始化方法,為預定義初始化方法名的字元串,或用于初始化權重的初始化器。參考initializers
  • kernel_regularizer:施加在權重上的正則項,為Regularizer對象
  • bias_regularizer:施加在偏置向量上的正則項,為Regularizer對象
  • activity_regularizer:施加在輸出上的正則項,為Regularizer對象
  • kernel_constraints:施加在權重上的限制項,為Constraints對象
  • bias_constraints:施加在偏置上的限制項,為Constraints對象

而這裡我們看到了一個不同,那就是輸入的單元

input_dim

沒有出現在定義中,其實它藏在了

**kwargs

中,因為源碼中這樣寫道:

if 'input_shape' not in kwargs and 'input_dim' in kwargs:
            kwargs['input_shape'] = (kwargs.pop('input_dim'),)
           

這裡就有出現問題了,什麼是

input_dim

input_shape

。他們的差別在于,如果是2D張量,則可以使用

input_dim

即可,但是如果是三維的話,可能就需要

input_length

來幫忙了,具體來講,他們之間的聯系是:

input_dim = input_shape(input_dim,)
input_dim, input_length = input_shape(input_length, input_dim,)
#像我們上面例子中的就是一個20維的資料,但是如果是識别手寫體的話,你的原始資料是二維的,比如這個是 (28, 28) = 784,這個是mnist的手寫資料。2維資料可以看成是1維的,那1維的shape就是(28*28,)了。
           

2.3.2.2. Activation層

這個激活函數在本例中沒有出現,其實不是,它間接的在Dense層中出現過了,預設的激活層常見的有以下幾種:

  1. softmax

    這是歸一化的多分類,可以把K維實數域壓縮到(0,1)的值域中,并且使得K個數值和為1。

  2. sigmoid

    這時歸一化的二進制分類,可以把K維實數域壓縮到近似為0,1二值上。

  3. relu

    這也是常用的激活函數,它可以把K維實數域映射到[0,inf)區間。

  4. tanh

    這時三角雙曲正切函數,它可以把K維實數域映射到(-1,1)區間。

還有其他激活函數我們就不一一介紹了。

2.3.2.3. Dropout層

它的原型為:

keras.layers.core.Dropout(rate, noise_shape=None, seed=None)
           

正如上面所述,為輸入資料施加Dropout。Dropout将在訓練過程中每次更新參數時随機斷開一定百分比(rate)的輸入神經元,Dropout層用于防止過拟合。

其參數含義如下:

  • rate:0~1的浮點數,控制需要斷開的神經元的比例。
  • noise_shape:整數張量,為将要應用在輸入上的二值Dropout mask的shape,例如你的輸入為(batch_size, timesteps, features),并且你希望在各個時間步上的Dropout mask都相同,則可傳入noise_shape=(batch_size, 1, features)。
  • seed:整數,使用的随機數種子

    還有幾個常用層,我們會在接下來的講解中講到。這裡不再贅述。

2.3.3優化算法

優化算法最常用的為SGD算法,也就是随機梯度下降算法。這裡我們不多講,因為優化算法我們會單開一章來總結一下所有的優化算法。

這裡我們隻講這裡用到的SGD,它的原型為:

keras.optimizers.SGD(lr=, momentum=, decay=, nesterov=False)
           

它就是随機梯度下降法,支援動量參數,支援學習衰減率,支援Nesterov動量。這幾個參數就是SGD的幾個改進,優化算法那章我們會講到。

其參數含義如下:

  • lr:大于0的浮點數,學習率
  • momentum:大于0的浮點數,動量參數
  • decay:大于0的浮點數,每次更新後的學習率衰減值
  • nesterov:布爾值,确定是否使用Nesterov動量

2.3.4模型的編譯

上面的注釋已經講的很明白了。在訓練模型之前,我們需要通過compile來對學習過程進行配置。compile接收三個參數:

  • 優化器optimizer:該參數可指定為已預定義的優化器名,如rmsprop、adagrad,或一個Optimizer類的對象,詳情見optimizers
  • 損失函數loss:該參數為模型試圖最小化的目标函數,它可為預定義的損失函數名,如categorical_crossentropy、mse,也可以為一個損失函數。詳情見losses
  • 名額清單metrics:對分類問題,我們一般将該清單設定為metrics=[‘accuracy’]。名額可以是一個預定義名額的名字,也可以是一個使用者定制的函數.名額函數應該傳回單個張量,或一個完成metric_name - > metric_value映射的字典.請參考性能評估

下面給出一些樣例:

# For a multi-class classification problem
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# For a binary classification problem
model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])

# For a mean squared error regression problem
model.compile(optimizer='rmsprop',
              loss='mse')

# For custom metrics
import keras.backend as K

def mean_pred(y_true, y_pred):
    return K.mean(y_pred)

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy', mean_pred])
           

要注意的是,這裡loss和metrics的名額都會在最後的評估中展現。

2.4 模型的訓練

模型訓練都是如出一轍,全是

fit

方法:

fit(self, x, y, batch_size=, epochs=, verbose=, callbacks=None, validation_split=, validation_data=None, shuffle=True, class_weight=None, sample_weight=None, initial_epoch=)
           

本函數将模型訓練nb_epoch輪,其參數有:

  • x:輸入資料。如果模型隻有一個輸入,那麼x的類型是numpy array,如果模型有多個輸入,那麼x的類型應當為list,list的元素是對應于各個輸入的numpy array
  • y:标簽,numpy array
  • batch_size:整數,指定進行梯度下降時每個batch包含的樣本數。訓練時一個batch的樣本會被計算一次梯度下降,使目标函數優化一步。
  • epochs:整數,訓練的輪數,每個epoch會把訓練集輪一遍。
  • verbose:日志顯示,0為不在标準輸出流輸出日志資訊,1為輸出進度條記錄,2為每個epoch輸出一行記錄
  • callbacks:list,其中的元素是keras.callbacks.Callback的對象。這個list中的回調函數将會在訓練過程中的适當時機被調用,參考回調函數
  • validation_split:0~1之間的浮點數,用來指定訓練集的一定比例資料作為驗證集。驗證集将不參與訓練,并在每個epoch結束後測試的模型的名額,如損失函數、精确度等。注意,validation_split的劃分在shuffle之前,是以如果你的資料本身是有序的,需要先手工打亂再指定validation_split,否則可能會出現驗證集樣本不均勻。
  • validation_data:形式為(X,y)的tuple,是指定的驗證集。此參數将覆寫validation_spilt。
  • shuffle:布爾值或字元串,一般為布爾值,表示是否在訓練過程中随機打亂輸入樣本的順序。若為字元串“batch”,則是用來處理HDF5資料的特殊情況,它将在batch内部将資料打亂。
  • class_weight:字典,将不同的類别映射為不同的權值,該參數用來在訓練過程中調整損失函數(隻能用于訓練)
  • sample_weight:權值的numpy array,用于在訓練時調整損失函數(僅用于訓練)。可以傳遞一個1D的與樣本等長的向量用于對樣本進行1對1的權重,或者在面對時序資料時,傳遞一個的形式為(samples,sequence_length)的矩陣來為每個時間步上的樣本賦不同的權。這種情況下請确定在編譯模型時添加了sample_weight_mode=’temporal’。
  • initial_epoch: 從該參數指定的epoch開始訓練,在繼續之前的訓練時有用。

fit函數傳回一個History的對象,其History.history屬性記錄了損失函數和其他名額的數值随epoch變化的情況,如果有驗證集的話,也包含了驗證集的這些名額變化情況。

2.5 模型的評估

模型評估使用的是evaluate方法:

evaluate(self, x, y, batch_size=, verbose=, sample_weight=None)
           

它最終傳回的是一個score,第0維為編譯中的loss名額,剩下的就是metrics中的名額了。

參數含義如下:

  • x:輸入資料,與fit一樣,是numpy array或numpy array的list
  • y:标簽,numpy array
  • batch_size:整數,含義同fit的同名參數
  • verbose:含義同fit的同名參數,但隻能取0或1
  • sample_weight:numpy array,含義同fit的同名參數

3. 小結

在本文中,我們庖丁解牛般的詳細的介紹了一個麻雀的五髒六腑,基本上是解說到了最基礎的部分,這也增加了我們對于Keras的了解。在接下來的過程中,我們将會對于每一部分進行一個詳細的講解。

最後緻謝《Keras中文文檔》、百度知道、Stack Overflow以及各位同行的部落格。

繼續閱讀