1. 程式人生 > >【keras】keras使用方法集合(持續更新中)

【keras】keras使用方法集合(持續更新中)

本文內容如下:

1. keras中,shape如何定義?

2. 關於model.compile 的引數傳遞,傳遞字串呢?還是傳遞物件?

3. 如何獲取模型中的每個layer資訊?如input_shape,output_shape,layer的引數配置等

4. 如何將預訓練好的詞向量載入到Embedding layer中?

5. 如何獲取單個layer的weight?

6. keras如何與tensorboard結合?

7. keras 如何做fine-tuning?

8. keras使用過程中,如何構造data與label?(將其構造為numpy陣列即可)

9. 如果data過大,不適合一次性載入到記憶體中,該如何處理?(文字訓練一般用不到,畢竟txt檔案,1M就是100萬char,已經很大了。一本小說幾百萬字,也就幾M,十幾M)

10 . keras中Sequential 模型 與函式式API的區別是什麼?

11.  GRU與LSTM的引數如何理解?

【一】keras中的shape定義

keras中,Sequential 模型中的第一層需要指定shape,否則keras無法自動計算後面的layer的shape而執行報錯。

1. 通過引數 input_shape 指定shape,該引數的shape資訊不包含batch_size資訊,batch_size預設為None

例如:指定shape為2D,則  input_shape = (100,)或者  input_shape = (None,)

          指定shape為3D,則 input_shape = (100,20) 或者 input_shape = (None,20)

         input_shape 可以是元組,也可以是列表。還是統一用元組吧。

2. 通過引數 batch_input_shape指定shape,該引數的shape資訊包含batch_size,且第一個維度就是batch_size大小。

例如:指定shape為2D,則  batch_input_shape = (None,100,)或者  batch_input_shape = (None,None)

          指定shape為3D,則 batch_input_shape = (None,100,20) 或者 batch_input_shape = (None,None,20)

程式碼示例如下:

# -*- coding:utf-8 -*-
import keras
from keras.layers import Dense

model = keras.Sequential()
# shape一般使用元組定義,列表也行,還是統一使用元組表示吧
# 必須是input_shape=(2,)不能是input_shape=(2)
# 輸入是2D,shape = (None,2)
model.add(Dense(units=3,input_shape=(2,)))
# shape = (None, 2, 3)
#model.add(Dense(units=3,input_shape=(2,2)))
#model.add(Dense(units=3,input_shape=[2,2]))
# shape=(2,3)
#model.add(Dense(units=3,batch_input_shape=(2,3)))
model.summary()

3. 那是不是第一層的layer都需要通過input_shape或者batch_input_shape引數來指定shape資訊呢?

答案是否定的,只要能推算出shape即可具體可以參見:https://keras.io/zh/getting-started/sequential-model-guide/

這裡對常見的第一層layer做個舉例。

3.1 第一層為Embedding

情況一:不知道輸入資料的長度,只知道詞典的大小與embedding_size。

model = keras.Sequential()
# input_dim就是詞典大小,out_dim就是embedding_size
model.add(Embedding(input_dim=10000,output_dim=100))
model.summary()

結果為:
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_1 (Embedding)      (None, None, 100)         1000000   
=================================================================

情況二:知道資料資料的長度,比如:輸入定長的句子

model = keras.Sequential()
# input_length就是資料資料的長度
model.add(Embedding(input_dim=10000,output_dim=100,input_length=200))
model.summary()

結果為:
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_1 (Embedding)      (None, 200, 100)          1000000   
=================================================================

embedding layer作為第一層時,就默認了,輸入資料必須是2D,經過embedding layer後,輸出一定為3D。

 

【二】model.compile 的引數傳遞

1. 引數之優化器,均在 keras.optimizers 模組下面定義

model.compile(optimizer='Adam')
model.compile(optimizer=keras.optimizers.Adam(lr=0.01))

2. 引數之損失 loss,均在 keras.losses下定義

該loss可以使用keras.losses模組下面定義的loss,也可以使用tf.loss模組下面定義的loss,可以參考:https://keras.io/zh/losses/

model.compile(optimizer=keras.optimizers.Adam(),loss=tf.losses.sigmoid_cross_entropy)
model.compile(optimizer='Adam',loss=keras.losses.binary_crossentropy)

3. 引數之 metrics

在訓練和測試期間的模型評估標準。通常你會使用 metrics = ['accuracy']。

metrics可以支援中評估方法:分別是:'accuracy', 'acc', 'crossentropy', 'ce'

這個從原始碼可以看出,雖然傳遞的是字串,但是最終還是使用 keras.metrics.模組中的評估方法,而且從字串到方法的對映,還和loss函式有關係。

從原始碼來看,傳遞'acc'和‘accuracy’是一樣的,傳遞'ce‘和'crossentropy‘是一樣的。一個是簡寫,一個是全稱罷了。

其他引數暫時不探討了,可以參考原始碼或者keras官方文件(https://keras.io/zh/models/sequential/)

【三】如何獲取模型中的每個layer資訊?

# -*- coding:utf-8 -*-
import keras
import tensorflow as tf
from keras.layers import Dense
from keras.layers import Embedding
model = keras.Sequential()
model.add(Embedding(input_dim=10000,output_dim=100,input_length=200,name="emb"))
model.summary()
# 通過layer的名字獲取layer
emb_layer = model.get_layer(name="emb")
# 獲取layer的shape資訊
print(emb_layer.input_shape)
print(emb_layer.output_shape)
# 獲取layer的引數配置資訊
print(emb_layer.get_config())



結果如下:
(None, 200)
(None, 200, 100)
{'name': 'emb', 'trainable': True, 'batch_input_shape': (None, 200), 'dtype': 'float32', 'input_dim': 10000, 'output_dim': 100, 'embeddings_initializer': {'class_name': 'RandomUniform', 'config': {'minval': -0.05, 'maxval': 0.05, 'seed': None}}, 'embeddings_regularizer': None, 'activity_regularizer': None, 'embeddings_constraint': None, 'mask_zero': False, 'input_length': 200}

【四】如何將預訓練好的詞向量載入到Embedding layer中?

這裡以斯坦福大學通過glove訓練好的word embedding為例(https://nlp.stanford.edu/projects/glove/)

# 初始化詞典
embedding_matrix = np.zeros(shape=(V,m))
word_index = {}
embedding_index = {}
# 選擇m=50的預訓練資料,將預訓練的詞與vector提取到embedding_index中儲存起來
with open("glove.6B.50d.txt") as f:
    for line in f:
        values = line.split()
        word = values[0]
        coefs = np.asarray(values[1:],dtype=np.float32)
        embedding_index[word] = coefs
'''
x_train,t_train = imdb_load("train")
token = text.Tokenizer(num_words=max_features)
token.fit_on_texts(x_train)
'''
# 獲取當前語料(imdb)的詞
word_index = token.word_index
not_find = 0
for word,i in word_index.items():
    if i < V:
        # 查預訓練的詞表
        embedding_vec = embedding_index.get(word)
        if embedding_vec is not None:
            embedding_matrix[i] = embedding_vec
        else:
            not_find += 1
# 將權值設定到embedding layer中
model.layers[0].set_weigth([embedding_matrix])
# frozen embedding layer,也可以不凍結。不凍結的話就可以fine-tuning該層
model.layers[0].trainable = False

【五】 如何獲取單個layer的weight?

# 通過layer的名字獲取layer
emb_layer = model.get_layer(name="emb")
weigth = emb_layer.get_weights()
print(weigth)

返回的是np陣列
結果如下:
[array([[-0.04013518,  0.04399543,  0.03000858, ..., -0.0194814 ,
        -0.04092554, -0.02486232],
       [-0.00160228, -0.04412872,  0.03846688, ...,  0.02017101,
        -0.02005241,  0.01420185],
       [ 0.04151604,  0.04445838,  0.03028882, ...,  0.04380548,
         0.04354296, -0.02567321],
       ...,
       [ 0.02195187, -0.01256204,  0.01097646, ..., -0.04138255,
        -0.01372109,  0.02588195],
       [-0.00363313,  0.01956742, -0.00567082, ..., -0.03723276,
         0.02284933, -0.04223878],
       [-0.0346414 ,  0.01633375,  0.03251269, ...,  0.04532002,
        -0.02762125, -0.03938962]], dtype=float32)]

【六】keras如何與tensorboard結合?

使用方式比較簡單,給fit函式傳遞一個keras.callbacks.TensorBoard 作為callback物件即可

    tensorboard = keras.callbacks.TensorBoard(log_dir="./logs/")
    train_history = model.fit(x=x_train,
                              y=y_train,
                              batch_size=128,
                              epochs=1,
                              validation_data=(x_test,y_test),
                              callbacks=[tensorboard])

啟動tensorboard(tensorboard --logdir=./logs/)之後,然後在瀏覽器輸入:http://localhost:6006 ,即可看到各種資訊

參考官方文件(https://keras.io/zh/callbacks/),該回調介面,有很多引數。

其中關於embedding的視覺化,參考官方案例:(https://github.com/keras-team/keras/blob/master/examples/tensorboard_embeddings_mnist.py)

【七】keras 如何做fine-tuning?

1. fine-tuning 一般是指,將模型的部分層保留,部分層刪除或者修改,進而形成一個新的模型。比如在CV的分類網路中,一本將基於ImageNet訓練出來的resnet等網路的最後一層修改,然後將預訓練的模型引數匯入新的模型中。那麼要實現fine-tuning,在keras中如何實現呢?

思路還是一致:先儲存原有模型引數,構造新模型,最後將原有模型中與新模型layer一致的引數,用過layer-name匯入到新的模型中。

1)定義原始模型,並儲存模型引數。

# -*- coding:utf-8 -*-
import keras
from keras.layers import Dense
model = keras.Sequential()
model.add(Dense(units=5,batch_input_shape=(2,5),name="fc1"))
model.add(Dense(units=3,name="fc2"))
model.summary()
# 儲存模型
model.save_weights('./models/fc.h5')

2)定義新模型,載入原始模型的權值引數

# -*- coding:utf-8 -*-
import keras
from keras.layers import Dense

# 定義模型,模型的前2層和原始模型一致
model = keras.Sequential()
model.add(Dense(units=5,batch_input_shape=(2,5),name="fc1"))
model.add(Dense(units=3,name="fc2"))
# 第三層是新模型新增的層
model.add(Dense(units=1,name="fc3"))
# 載入原始模型的引數到新模型中,通過設定by_name=True來實現,即通過layer名字查詢對應的引數,其底層機制,與tf和caffe應該是一致的
model.load_weights(filepath='./models/fc.h5',by_name=True)
model.summary()



注意地點,進行引數載入時,layer的配置資訊必須完全一致,比如shape

【十】 keras中Sequential 模型 與函式式API的區別是什麼?

1. 首先看看官網對函式式API的定義:

2. 函式式API的使用方法這裡便不再講述了,可參考:https://keras.io/zh/getting-started/functional-api-guide/

3. 函式式API的返回值是什麼?

  • 網路層的例項是可呼叫的,它以張量為引數,並且返回一個張量

     ----- 這個是官網描述,我們來看看程式碼

from keras.layers import Input


x = Input(shape=(5,))
print(type(x))

結果如下:
<class 'tensorflow.python.framework.ops.Tensor'>

可以看出,網路層的例項返回的確是張量。

使用函式式API,可以向TensorFlow一樣編寫程式碼,而且比TensorFlow簡單很多。

x = Input(shape=(5,),name="x")
fc1 = Dense(units=5)(x)
fc1 = keras.activations.relu(x=fc1)
print(fc1)
# 結果如下
Tensor("Relu:0", shape=(?, 5), dtype=float32)

keras.layer將所需定義的W、b等variable自動定義了。

有些layer可能返回多個輸出值,當我們僅需要其中的幾個返回值而丟棄其他的返回值值時,函式式API給以滿足這種需求(比如GRU/LSTM)

【十一】GRU與LSTM的引數如何理解?

1. GRU引數

2. 這個return相關的兩個引數,實在令人費解,GRU和LSTM還不一樣。

先看看例子:

from keras.layers import Input
from keras.layers import GRU
from keras.layers import LSTM

x = Input(shape=(None, 20))

y = GRU(units=10)
print(y(x))
Tensor("gru_1/TensorArrayReadV3:0", shape=(?, 10), dtype=float32)

y = GRU(units=10,return_state=True)
print(y(x))
[<tf.Tensor 'gru_2/TensorArrayReadV3:0' shape=(?, 10) dtype=float32>, <tf.Tensor 'gru_2/while/Exit_2:0' shape=(?, 10) dtype=float32>]


y = GRU(units=10,return_state=True,return_sequences=True)
print(y(x))
[<tf.Tensor 'gru_3/transpose_1:0' shape=(?, ?, 10) dtype=float32>, <tf.Tensor 'gru_3/while/Exit_2:0' shape=(?, 10) dtype=float32>]


y = LSTM(units=10)
print(y(x))
Tensor("lstm_1/TensorArrayReadV3:0", shape=(?, 10), dtype=float32)

y = LSTM(units=10,return_state=True)
print(y(x))
[<tf.Tensor 'lstm_2/TensorArrayReadV3:0' shape=(?, 10) dtype=float32>, <tf.Tensor 'lstm_2/while/Exit_2:0' shape=(?, 10) dtype=float32>, <tf.Tensor 'lstm_2/while/Exit_3:0' shape=(?, 10) dtype=float32>]


y = LSTM(units=10,return_state=True,return_sequences=True)
print(y(x))
[<tf.Tensor 'lstm_3/transpose_1:0' shape=(?, ?, 10) dtype=float32>, <tf.Tensor 'lstm_3/while/Exit_2:0' shape=(?, 10) dtype=float32>, <tf.Tensor 'lstm_3/while/Exit_3:0' shape=(?, 10) dtype=float32>]

return_state: 布林值。除了輸出之外是否返回最後一個狀態 ----> 也就是返回值中的list中的第二個值,list[1]。即LSTM或者GRU計算完成之後的左右一個狀態值

return_sequences: 布林值。是返回輸出序列中的最後一個輸出,還是全部序列 ------>也就是返回值list中的第一個值,list[0]。即LSTM或者GRU,是否返回所有的輸出值,即y0,y1,y2,......,yt。如果返回,則增加一個shape維度。

x = Input(shape=(50, 20))
y = GRU(units=10)
print(y(x))
y = GRU(units=10,return_sequences=True)
print(y(x))

Tensor("gru_1/TensorArrayReadV3:0", shape=(?, 10), dtype=float32)
Tensor("gru_2/transpose_1:0", shape=(?, ?, 10), dtype=float32)

關於這return的配置使用,keras給出了一個官方案例,在實現seq2seq時提到了。(https://github.com/keras-team/keras/blob/master/examples/lstm_seq2seq.py)