1. 程式人生 > >Python機器學習筆記:深入理解Keras中序貫模型和函式模型

Python機器學習筆記:深入理解Keras中序貫模型和函式模型

  先從sklearn說起吧,如果學習了sklearn的話,那麼學習Keras相對來說比較容易。為什麼這樣說呢?

  我們首先比較一下sklearn的機器學習大致使用流程和Keras的大致使用流程:

sklearn的機器學習使用流程:

1

2

3

4

5

6

7

8

9

10

from  sklearn.模型簇    import  模型名

from  sklearn.metrics   import  評價指標

 

 

'''  資料預處理及訓練測試集分離提取'''

 

myModel = 模型名稱()     # 物件初始化

myModel.fit(訓練集x ,  訓練集y)     #模型訓練

y預測集  = myModel.predict(開發集x)  #模型預測

評價指標 = 評價指標(y預測集,y測試集)   #模型效果評估

  

Keras的機器學習使用流程:

1

2

3

4

5

6

7

8

import keras

...根據具體需求引入keras的包...

 

...keras模型搭建...

...keras模型編譯(可選擇模型指標)...

 

kerasModel.fit(訓練集x,訓練集y)#keras模型訓練

y預測集=myModel.predict(開發集x)#keras模型預測

  

兩者的區別

  由上面虛擬碼可知Keras和sklearn最大不同在於需要進行模型搭建,可是既然有了這麼多模型為什麼還要模型搭建?

  如果你瞭解過神經網路感知機就會比較理解這個過程,一個感知器相當於一個神經元,可根據輸入資訊反饋出需要的電訊號,根據我們的世界觀,一個細胞可以單獨執行很多功能但是大量單純的任務會讓細胞只針對一個方向發展。用生物學的說話就是分化能力逐漸減弱,機器學習說法就是過擬合。因此,只有大量細胞通過不同的組合才能完成紛繁複雜的預測任務,因而有證明說神經網路理論上可擬合出任何曲線。

  那麼話說回來,Keras需要自行搭建模型,搭建方法有兩種:序貫模型和函式式模型。而我本次的筆記就是學習序貫模型和函式式模型。

序貫模型

  序貫模型是多個網路蹭的線性堆疊,是函式式模型的簡略版,為最簡單的線性,從頭到尾的結構順序,不發生分叉。是多個網路層的線性堆疊。

  Keras實現了很多層,包括core核心層,Convolution卷積層,Pooling池化層等非常豐富有趣的網路結構。

應用序貫模型的基本步驟

  • 1,model.add()           新增層
  • 2,model.compile()     模型訓練的BP模式設定
  • 3,model.fit()         模型訓練引數設定+訓練
  • 4,model.evaluate()         模型評估
  • 5,model.predict()     模型預測

序貫模型的建立

  1,可以通過向Sequential模型傳遞一個layer的list來構造Sequential模型:

1

2

3

4

5

6

7

8

9

10

11

from keras.models import Sequential

from keras.layers import Dense ,Activation

 

model = Sequential([

    Dense(32,input_shape=(784,)),

    Activation('relu'),

    Dense(10),

    Activation('softmax')

])

 

model.summary()

  

  2,也可以通過.add()方法一個個的將layer加入模型中:

1

2

3

4

5

6

7

8

9

10

from keras.models import Sequential

from keras.layers import Dense ,Activation

 

model = Sequential()

model.add(Dense(32,input_shape=(784,)))

model.add(Activation('relu'))

model.add(Dense(10))

model.add(Activation('softmax'))

 

model.summary()

  結果如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

Using TensorFlow backend.

_________________________________________________________________

Layer (type)                 Output Shape              Param #  

=================================================================

dense_1 (Dense)              (None, 32)                25120    

_________________________________________________________________

activation_1 (Activation)    (None, 32)                0        

_________________________________________________________________

dense_2 (Dense)              (None, 10)                330      

_________________________________________________________________

activation_2 (Activation)    (None, 10)                0        

=================================================================

Total params: 25,450

Trainable params: 25,450

Non-trainable params: 0

_________________________________________________________________

  

3,指定輸入資料的shape

  模型需要知道輸入資料的shape,因此,Sequential的第一層需要接受一個關於輸入資料shape的引數,後面的各個層則可以自動的推匯出中間資料的shape,因此不需要為每一層都指定這個引數。有幾種方法來為第一層指定輸入資料的shape

  1,傳遞一個input_shape的關鍵字引數給第一層,input_shape是一個tupel型別的資料(一個整數或者None的元祖,其中None表示可能為任何正整數)在input_shape中不包含資料的batch大小。

1

2

model = Sequential()

model.add(Dense(64,input_shape=(20,),activation='relu'))

  

  2,有些2D層,如Dense,支援通過指定其輸入維度input_dim來隱含的指定輸入資料shape,是一個Int型別的資料。一些3D的時域層支援通過引數input_dim和input_length來指定輸入shape。

1

2

model = Sequential()

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

  3,如果你需要為你的輸入指定一個固定的batch大小(這對於statsful RNNs很有用),你可以傳遞一個batch_size引數給一個層。如果你同時將batch_size=32和input_shape = (6,8)傳遞給一個層,那麼每一批輸入的尺寸就是(32,6,8)。

  因此下面的程式碼是等價的:

1

2

3

4

5

model = Sequential()

model.add(Dense(32, input_shape=(784,)))

  

model = Sequential()

model.add(Dense(32, input_dim=784))

  下面三種方法也是嚴格等價的

1

2

3

4

5

6

7

8

9

10

model = Sequential()

model.add(LSTM(32, input_shape=(10, 64)))

  

  

model = Sequential()

model.add(LSTM(32, batch_input_shape=(None, 10, 64)))

  

  

model = Sequential()

model.add(LSTM(32, input_length=10, input_dim=64))

  

4,編譯

  在訓練模型之前,我們需要通過compile來對學習過程進行配置,compile接收三個引數:優化器optimizer,損失函式loss,指標列表metrics。

1

compile(self, optimizer, loss, metrics=None, sample_weight_mode=None)

其中:

  optimizer:字串(預定義優化器名)或者優化器物件,,如 rmsprop 或 adagrad,也可以是 Optimizer 類的例項。詳見:optimizers

  loss:字串(預定義損失函式名)或目標函式,模型試圖最小化的目標函式,它可以是現有損失函式的字串識別符號,如categorical_crossentropy 或 mse,也可以是一個目標函式。詳見:losses

  metrics:列表,包含評估模型在訓練和測試時的網路效能的指標,典型用法是metrics=[‘accuracy’]。評估標準可以是現有的標準的字串識別符號,也可以是自定義的評估標準函式。

注意:

  模型在使用前必須編譯,否則在呼叫fit或者evaluate時會丟擲異常。

例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

# 多分類問題

model.compile(optimizer='rmsprop',

              loss='categorical_crossentropy',

              metrics=['accuracy'])

  

# 二分類問題

model.compile(optimizer='rmsprop',

              loss='binary_crossentropy',

              metrics=['accuracy'])

  

# 均方誤差迴歸問題

model.compile(optimizer='rmsprop',

              loss='mse')

  

# 自定義評估標準函式

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])

  

5,訓練

  Keras 模型在輸入資料和標籤的 Numpy 矩陣上進行訓練。為了訓練一個模型,你通常會使用 fit 函式。文件詳見此處

1

2

3

fit(self, x, y, batch_size=32, epochs=10, verbose=1, callbacks=None,

 validation_split=0.0, validation_data=None, shuffle=True,

 class_weight=None, sample_weight=None, initial_epoch=0)

  本函式將模型訓練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變化的情況,如果有驗證集的話,也包含了驗證集的這些指標變化情況。

 示例一:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

# 對於具有2個類的單輸入模型(二進位制分類):

  

model = Sequential()

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

model.add(Dense(1, activation='sigmoid'))

model.compile(optimizer='rmsprop',

              loss='binary_crossentropy',

              metrics=['accuracy'])

  

# 生成虛擬資料

import numpy as np

data = np.random.random((1000, 100))

labels = np.random.randint(2, size=(1000, 1))

  

# 訓練模型,以 32 個樣本為一個 batch 進行迭代

model.fit(data, labels, epochs=10, batch_size=32)

  

示例二:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

# 對於具有10個類的單輸入模型(多分類分類):

  

model = Sequential()

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

model.add(Dense(10, activation='softmax'))

model.compile(optimizer='rmsprop',

              loss='categorical_crossentropy',

              metrics=['accuracy'])

  

# 生成虛擬資料

import numpy as np

data = np.random.random((1000, 100))

labels = np.random.randint(10, size=(1000, 1))

  

# 將標籤轉換為分類的 one-hot 編碼

one_hot_labels = keras.utils.to_categorical(labels, num_classes=10)

  

# 訓練模型,以 32 個樣本為一個 batch 進行迭代

model.fit(data, one_hot_labels, epochs=10, batch_size=32)

  

6,評估

  根據驗證集評估模型的好壞

1

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

  本函式按batch計算在某些輸入資料上模型的誤差,其引數有:

  x:輸入資料,與fit一樣,是numpy array 或者numpy array的list

  y:標籤,numpy array

  batch_size:整數,含義同fit的同名引數

  verbose:含義同fit的同名引數,但是隻能取0或1

  sample_weight:numpy array ,含義同fit的同名引數

  本函式返回一個測試誤差的標量值(如果模型沒有其他評價指標),或一個標量的list(如果模型還有其他的評價指標)。model.metrics_names將給出list中各個值的含義。

  如果沒有特殊說明,以下函式的引數均保持與fit的同名引數相同的含義

  如果沒有特殊說明,以下函式的verbose引數(如果有)均只能取0或者1

1

2

3

score = model.evaluate(x_val , y_val ,batch_size = 128)

print('val score:', score[0])

print('val accuracy:', score[1])

  

7,預測

  對已經訓練完成的模型,輸入特徵值x會預測得到標籤y。

1

2

3

predict(self, x, batch_size=32, verbose=0)

predict_classes(self, x, batch_size=32, verbose=1)

predict_proba(self, x, batch_size=32, verbose=1)

  本函式按batch獲得輸入資料對應的輸出,其引數有:

  函式的返回值是預測值的numpy array

  predict_classes:本函式按batch產生輸入資料的類別預測結果

  predict_proba:本函式按batch產生輸入資料屬於各個類別的概率

1

2

3

x = 1

y = model.predict(x,verbose=0)

print(y)

  

8,on_batch,batch的結果,檢查

1

2

3

train_on_batch(self, x, y, class_weight=None, sample_weight=None)

test_on_batch(self, x, y, sample_weight=None)

predict_on_batch(self, x)

  train_on_batch:本函式在batch的資料上進行一次引數更新,函式返回訓練誤差的標量值或者標量值的list,與evaluate的情形相同。

  test_on_batch:本函式在一個batch的樣本上對模型進行評估,函式的返回與evaluate的情形相同。

  predict_on_batch:本函式在一個batch的樣本上對模型進行測試,函式返回模型在一個batch上的預測結果。

 

9,完整程式碼及其一次結果

程式碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

from keras.models import Sequential

from keras.layers import Dense ,Activation,Dropout

import numpy as np

 

# 準備訓練集和驗證集

x_train = np.random.random((1000,20))

y_train = np.random.randint(2,size=(1000,1))

x_val = np.random.random((100,20))

y_val = np.random.randint(2,size=(100,1))

 

model = Sequential()

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

model.add(Dropout(0.5))

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

model.add(Dropout(0.5))

model.add(Dense(1,activation='sigmoid'))

 

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

model.fit(x_train,y_train,epochs=20,batch_size=128)

 

score = model.evaluate(x_val , y_val ,batch_size = 128)

print('val score:', score[0])

print('val accuracy:', score[1])

 

# x = 1

# y = model.predict(x,verbose=0)

# print(y)

 

結果:

+ View Code

 

函式式模型

  比序貫模型要複雜,但是效果很好,可以同時/分階段輸入變數,分階段輸出想要的模型。

  所以說,只要你的模型不是類似VGG一樣

1,應用函式式模型的基本步驟

1,model.layers()     新增層

2,model.compile()  模型訓練的BP模式設定

3,model.fit()       模型訓練引數設定+訓練

4,evaluate()             模型評估

5,predict()                模型預測

 

2,常用Model屬性

1

2

3

model.layers:組成模型圖的各個層

model.inputs:模型的輸入張量列表

model.outputs:模型的輸出張量列表

  

1

model = Model(inputs=, outputs = )

  

3,指定輸入資料的shape

1

inputs = Input(shape = (20, ))

 

4,編譯,訓練,評估,預測等步驟與序貫式模型相同(這裡不再贅述)

1

compile(self, optimizer, loss, metrics=None, loss_weights=None, sample_weight_mode=None)

  本函式按batch計算在某些輸入資料上模型的誤差,其引數有:

  x:輸入資料,與fit一樣,是numpy array或者numpy array的list

  y:標籤,numpy array

  batch_size:整數,含義同fit的同名函式

  verbose:含義與fit的同名函式,但是隻能取0或者1

  sample_weight:numpy array,含義同fit的同名函式

  本函式編譯模型以供訓練,引數有:

1

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

  

5,示例一(基於上面序貫模型進行改造)

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

import numpy as np

from keras.models import Model

from keras.layers import Dense , Dropout,Input

 

# 準備訓練集和驗證集

x_train = np.random.random((1000,20))

y_train = np.random.randint(2,size=(1000,1))

x_val = np.random.random((100,20))

y_val = np.random.randint(2,size=(100,1))

 

inputs = Input(shape = (20,))

x = Dense(64,activation='relu')(inputs)

x = Dropout(0.5)(x)

x = Dense(64,activation='relu')(x)

x = Dropout(0.5)(x)

predictions = Dense(1,activation='sigmoid')(x)

model=Model(inputs=inputs, outputs=predictions)

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

model.fit(x_train, y_train,epochs=20,batch_size=128)

 

score = model.evaluate(x_val, y_val, batch_size=128)

print('val score:', score[0])

print('val accuracy:', score[1])

  

 

序貫模型和函式模型共同的API

  model.summary():打印出模型的概況,它實際呼叫的是keras.utils.print_summary

  model.get_config():返回包含模型配置資訊的Python字典,模型也可以從config中重構回去。

1

2

3

config = model.get_config()

model = Model.from_config(config)

model = Sequential.from_config(config)

  上面是分別對序貫模型和函式式模型載入config

model.get_layer():依據層名或下標獲得層物件

model.get_weights():返回模型權重張量的列表,型別為numpy.array

model.set_weights():從numpy array裡載入給模型,要求陣列與model.get_weights()一樣

model.to_json():返回代表模型的JSON字串,僅僅包含網路結構,不包含權重,可以從JSON字串中重構模型

 

Keras模型儲存

  首先不推薦使用pickle或者cPickle來儲存Keras模型

1,儲存結構

   可以使用model.save(filepath)將Keras模型和權重儲存在一個HDF5檔案中,該檔案將包含:

  • 模型的結構,以便重構該模型
  • 模型的權重
  • 訓練配置(損失函式,優化器等)
  • 優化器的狀態,以便從上次訓練中斷的地方開始

  使用Keras.models.load_model(filepath)來重新例項化你的模型,如果檔案中儲存了訓練配置的話,該函式還會同時完成模型的編譯。例如:

1

2

3

4

5

6

7

8

9

10

11

from keras.models  import load_model

 

# create a HDF5 file 'my_load.h5'

model.save('my_load.h5')

 

# deletes the existing model

del  model

 

# returns a compiled model

# indentical to the previous one

model = load_model('my_load.h5')

  

2,儲存結構

  如果你只是希望儲存模型的結構,而不包括其權重或者配置資訊,可以使用:

1

2

3

4

5

# save as JSON

json_string = model.to_json()

 

# save as YAML

yaml_string = model.to_yaml()

  這項操作可以將模型序列化為json或者yaml檔案,如果需要的話你甚至可以手動開啟這些檔案進行編輯。

  當然你也可以從儲存好的json檔案或者yaml檔案中載入模型:

1

2

3

4

5

6

# model reconstruction from JSON:

from keras.models import model_from_json

model = model_from_json(json_string)

 

# model reconstruction from YAML

model = model_from_yaml(yaml_string)

  

3,儲存模型的權重

  如果需要儲存模型,可通過下面的程式碼利用HDF5進行儲存。注意,在使用前需要確保你已經安裝了HDF5 和Python的庫h5py。

1

model.save_weights('my_model_weights.h5')

  如果你需要在程式碼中初始化一個完全相同的模型,請使用:

1

model.load_weights('my_model_weights.h5')

  

4,載入權重到不同的網路結構

  如果你需要載入權重到不同的網路結構(有些層一樣)中,例如fine-tune或transfer-learning,你可以通過層名字來載入模型。

1

model.load_weights('my_model_weights.h5', by_name=True)

  例如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

"""

假如原模型為:

    model = Sequential()

    model.add(Dense(2, input_dim=3, name="dense_1"))

    model.add(Dense(3, name="dense_2"))

    ...

    model.save_weights(fname)

"""

# new model

model = Sequential()

model.add(Dense(2, input_dim=3, name="dense_1"))  # will be loaded

model.add(Dense(10, name="new_dense"))  # will not be loaded

 

# load weights from first model; will only affect the first layer, dense_1.

model.load_weights(fname, by_name=True)

  載入權重到不同的網路結構上多數用於遷移學習。

鄭州婦科醫院哪家好

鄭州婦科醫院

鄭州專業婦科醫院

鄭州專業婦科醫院