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