keras學習筆記
1.基本概述
neural layers(神經層), cost functions(損失函式), optimizers(優化器), initialization schemes(初始化方案), activation functions(啟用函式), regularization(正則化項)在keras中都是獨立的模組,可以自由組合。
keras的核心是一個模型,用來阻止各個網路層次結構。最簡單的是Sequential模型,即序貫模型,是一個個網路層的線性疊加。對於更復雜的結構,應該使用keras提供的function API(功能API)。function API允許構建任何的網路結構。
2. 構建簡單的Sequential模型
from keras.models import Sequential
model = Sequential()
使用add()方法來新增網路層
from keras.layers import Dense, Activation
model.add(Dense(units=64, input_dim=100))
model.add(Activation("relu"))
model.add(Dense(units=10))
model.add(Activation("softmax"))
模型構建完成之後,使用compile()方法來配置模型(相當於翻譯成backend框架的程式碼)
model.compile(loss="categorial_crossentropy", optimiizer="sgd", metrics=["accuracy"])
如果有需要,可以繼續配置模型,或者修改模型的配置
model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizer.SGD(lr=0.01, momentum=0.9, nesterov=True))
編譯完成之後,開始以batch為單位訓練模型
# X_train, y_train都是numpy array型別,就像scikit-learn當中一樣
model.fit(X_train, y_train, epochs=5, batch_size=32)
還可以手動只在batch上訓練
model.train_on_batch(x_batch, y_batch)
評價模型
loss_and_metrics = model.evaluate(X_valid, y_valid, batch_size=128)
在新資料上進行預測
classes = model.predict(X_test, batch_size=128)
3. 安裝
3.1 先安裝backend
3.2 儲存模型的外掛的安裝
- HDF5和h5py的安裝:可以將keras模型儲存到磁碟上。
- graphviz和pydot,可以用來視覺化模型。
3.3 修改backend
在home目錄下的~/.keras/keras.json檔案中儲存中backend的配置檔案。如果沒有這個檔案可以自己新建。預設的配置為:
{
"image_data_format": "channels_last",
"epsilon": 1e-07,
"floatx": "float32",
"backend": "tensorflow"
}
只需要將backend欄位改為:”theano”、”tensorflow”或者”cntk”就可以了。另外一種方法是在環境變數中新增:
KERAS_BACKEND=tensorflow python -c "from keras import backend"
Using TensorFlow backend
欄位說明:
- image_data_format
theano是channel是channel_first,TensorFlow是channel_last。
- 2D資料: channel_last就是(rows, cols, channels),channel_last就是(channels, rows, cols)。
- 3D資料:channel_last就是(conv_dim1, conv_dim2, conv_dim3, channels),channel_first就是(channels, conv_dim1, conv_dim2, conv_dim3)。
- epsilon:一個浮點數,用來避免某些情況下的除0操作。
- floatX:”float16”、”float32”或者”float64”,預設的浮點數型別。
- backend: “tensorflow”, “theano”或者”cntk”。
4. Sequential模型的使用
sequential是一系列模型的簡單線性疊加,可以在建構函式中傳入一些列的網路層:
from keras.models import Sequential from keras.layers import Dense, Activation model = Sequential([Dense(32, input_shape=(784,)), Activation("relu"), Dense(10), Activation("softmax")])
也可以通過add()方法新增
model = Sequential() model.add(Dense(32, input_dim=784)) model.add(Activation("relu"))
- 指定模型的輸入維度
模型需要知道輸入的維度。Sequential的第一層(只有第一層,後面的層會自動匹配)需要知道輸入的shape。有3種方法指定:
- 在第一層加入一個input_shape引數,input_shape應該是一個shape的tuple資料型別。input_shape是一系列整數的tuple,某些位置可為None。input_shape中不用指明batch_size的數目。
- 某些2D的網路層,如Dense,允許在層的建構函式的input_dim中指定輸入的維度。對於某些3D時間層,可以在建構函式中指定input_dim和input_length來實現。
- 對於某些RNN,可以指定batch_size。這樣後面的輸入必須是(batch_size, input_shape)的輸入。
例如:
model = Seqnential()
model.add(Dense(32, input_shape=(784, )))
或者
model = Sequential()
model.add(Dense(32, input_dim=784))
5. 編譯
訓練模型之前,需要先配置模型的學習過程。通過使用compile()函式實現,compile()函式有3個引數:
- optimizer: string型別,優化器的型別
- loss: 模型需要減小的物件,即損失函式。
- metrics: 評價指標的list集合。可以是自定義的metric。
例如:
# 多分類
model.compile(optimizer="rmsprop", loss="categorical_crossentropy", metrics=["accuracy"])
# 二分類
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
# 對於均方差迴歸模型
model.compile(optimizer='rmsprop', loss='mse')
自定義metrics:
import keras.backend as K
def mean_perd(y_true, y_pred):
return K.mean(y_pred)
model.compile(optimizer="rmsprop", loss='binary_crossentropy', metrics=['accuracy', mean_pred])
6. 訓練
keras模型訓練的輸入資料是numy array型別,使用fit方法:
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"])
# 生成dummy data
import numpy as np
data = np.random.random((1000, 100))
labels = np.random.random((1000,1))
#訓練模型,使用32的batch來訓練
model.fit(data, labels, epochs=10, batch_size=32)
多分類
# For a single-input model with 10 classes (categorical classification):
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'])
# Generate dummy data
import numpy as np
data = np.random.random((1000, 100))
labels = np.random.randint(10, size=(1000, 1))
# Convert labels to categorical one-hot encoding
one_hot_labels = keras.utils.to_categorical(labels, num_classes=10)
# Train the model, iterating on the data in batches of 32 samples
model.fit(data, one_hot_labels, epochs=10, batch_size=32)
更多關於keras的簡單例子見:keras例子
7. keras的functional API(功能API)
keras的functional API可以用來定義複雜的模型,如多輸出模型,有向無環圖或具有共享圖層的模型。
functional API的呼叫過程:
- 首先在一個tensor上呼叫該圖層例項,並返回一個tensor
- 使用input tensor和output tensor來定義一個Model
- 用類似Sequential的方式來訓練模型
from keras.layers import Input, Dense
from keras.models import Model
# 返回一個tensor
inputs = Input(shape=(784,))
# 在tensor上呼叫一個layer例項,並返回一個tensor
x = Dense(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
# 定義一個model,該model包含輸入層和3個全連線層
model = Model(inputs=inputs, outputs=predictions)
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(data, labels) # starts training
模型的重用,可以直接將模型當作一個層來使用
x = Input(shape=(784, ))
y = model(x) # 返回一個包含10個元素的陣列
將傳統的影象分類模型用作視訊分類
from keras.layers import TimeDistributed
input_seq = Input(shape=(784, 20)) #輸入是一個20幀的視訊
processed_sequences = TimeDistributed(model)(input_seq) # 輸出是一個20×10的矩陣
7.1 多輸入和多輸出模型
functional API使得可以方便的處理交織的資料流。
例如,實現如下的網路結構
其中main_input是一個詞的序列,每個詞用(0, 10000)之間的整數代替,詞的長度是100。
from keras.layers import Input, Embedding, LSTM, Dense
from keras.models import Model
main_input = Input(shape=(100,), dtype="int32", name="main_input") #可以給層命名
x = Embedding(output_dim = 512, input_dim=10000, input_length = 100)(main_input)
lstm_out = LSTM(32)(x)
auxiliary_output = Dense(1, activation='sigmoid', name='aux_output')(lstm_out)
auxiliary_input = Input(shape=(5,), name='aux_input')
x = keras.layers.concatenate([lstm_out, auxiliary_input])
# We stack a deep densely-connected network on top
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
# And finally we add the main logistic regression layer
main_output = Dense(1, activation='sigmoid', name='main_output')(x)
model = Model(inputs=[main_input, auxiliary_input], outputs=[main_output, auxiliary_output])
model.compile(optimizer='rmsprop', loss='binary_crossentropy', loss_weights=[1., 0.2])
model.compile(optimizer='rmsprop',
loss={'main_output': 'binary_crossentropy', 'aux_output': 'binary_crossentropy'},
loss_weights={'main_output': 1., 'aux_output': 0.2})
# And trained it via:
model.fit({'main_input': headline_data, 'aux_input': additional_data},
{'main_output': labels, 'aux_output': labels},
使用layer.input/output和layer.input_shape/output_shape來獲取輸入輸出tensor。
x = Dense(units=32)(x)
x.output
8. 儲存和載入模型
儲存模型的結構、權重和優化器狀態,不推薦cPickle來儲存。可以使用model.save(filepath)來將模型儲存為一個HDF5檔案。該檔案中包含:
- 模型的結構,允許重構
- 模型的權重
- 巡禮啊配置(包含loss, optimizer等)
- optimizer的狀態,允許在上次中斷的地方繼續訓練
8.1 儲存/載入整個模型
使用keras.models.load_model(filepath)來載入模型。load_model也會載入訓練的配置(loss, optimizer等)。
from keras.models import load_model
model.save("my_model.hdf5") #建立一個檔案my_model.hdf5
del model #刪除模型
#返回一個已經編譯過的模型,和之前的模型一模一樣
model = load_model("my_model.hdf5")
8.2 只儲存/載入模型的結構(只有網路結構,沒有權重和配置)
#儲存為json
json_str = model.to_json()
#儲存為yaml
yanm_str = model.to_yaml()
儲存下來的JSON/YAML是可閱讀的文字,可以被編輯,通過以下方式載入:
from keras.models import model_from_json
model = model_from_json(json_string)
from keras.models import model_from_yaml
model = model_fram_yaml(yaml_str)
8.3 只儲存/載入權重
使用hdf5來只加載權重(需要先安裝HDF5和h5py)
model.save_weights("my_model_weights.h5")
定義好模型之後,載入權重
model.load_weights("my_model_weights.h5")
如果想載入權重到不同的網路結構,網路只有某些層相同,例如transfer learning和fine tuning,可以使用name屬性實現:
"""
Assuming the original model looks like this:
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) #通過制定by_name為True來實現
8.4 獲取中間層的輸出
要獲取中間層的輸出,最好的辦法是新建一個模型
from keras.models import Model
model = ... #原始model
layer_name = "my_layer"
intermediate_layer_model = Model(inputs=model.input, outputs=model.get_layer(layer_name).output)
intermediate_output = intermediate_layer_model.predict(data)
或者使用keras function來實現返回一個特定的輸出
from keras import backend as K
get_3rd_layer_output = K.function([model.layers[0].input, model.layers[3].output])
layer_output = get_3rd_layer_output([x])[0]
8.5 使用history函式來記錄每一個epoch的training/validation 的loss/accuracy。
model.fit()會返回一個History物件。該物件有一個history屬性,記錄著loss和metrics的資訊
hist = model.fit(x, y, validation_split=0.2)
print(hist.history)
8.5 固定某些layer
在fine-tuning中要保持某些layer的權重weight不變,可以使用trainable引數實現
frozen_layer = Dense(32, trainable=False)
還可以使用trainable屬性來指定某些層的係數是否可以改變,但要改變trainable屬性,需要重新呼叫compile方法:
x = Input(shape=(32,))
layer = Dense(32)
layer.trainable = False
y = layer(x)
frozen_model = Model(x, y)
#下面的模型引數不變
frozen_model.compile(optimizer="rmsprop", loss="mse")
layer.trainable = True
trainable_model = Model(x, y)
#訓練的時候,權重會改變,因此也會影響froze_model
trainable_model.compile(optimizer="rmsprop", loss="mse")
frozen_model.fit(data, labels) #不會改變權重
trainable_model.fit(data, labels) #會改變權重
8.6 使用pop方法來刪除最後一層
model = Sequential()
model.add(Dense(32, activation="relu", input_dim=784))
model.add(Dense(32, activation="relu"))
print(len(model.layers)) #輸出2
model.pop()
print(len(model.layers)) #輸出1
8.7 使用預訓練的模型
通過keras.applications來使用預訓練的模型
from keras.applications.xception import Xception
from keras.applications.vgg16 import VGG16
from keras.applications.vgg19 import VGG19
from keras.applications.resnet50 import ResNet50
from keras.applications.inception_v3 import InceptionV3
from keras.applications.inception_resnet_v2 import InceptionResNetV2
from keras.applications.mobilenet import MobileNet
model = VGG16(weights='imagenet', include_top=True)
9. Keras的models
有兩種model, Sequential model和functional API model,兩種模型有以下的方法:
model.summary(): 列印model的資訊
model.get_config() 返回一個dict,包含模型的配置資訊。可以通過以下的方法來載入該配置
config = model.get_config()
model = Model.from_config(config)
#或者
model = Sequential.from_config(config)
model.get_weights():以numpy.array的形式返回所有weight的list列表。
model.set_weights(weights):從numpy.array裡面給模型設定引數。list裡面的引數應該和model.get_weights()的結構相同。
model.to_json():返回一個描述模型的json字串。這些字串不包含權重資訊,只有結構。可以通過以下方法載入這些模型:
from models import model_from_json
json_str = model.to_json()
model = model_from_json(json_str)
model.to_yaml():和json類似
model.save_weights(filapath):將模型的權重存到一個hdf5檔案中。
model.load_weights(filepath, by_name=False):將save_weights儲存的權重載入進來。通常結構不變。如果結構不同,而只想載入某些特殊層的權重,可以使用by_name=True來載入哪些名稱相同的層的權重。
10. Sequential模型
model.layers:模型中一些列layer的list集合。
常用的方法:
10.1 compile
compile(self, optimizer, loss, metrics=None, sample_weitght_mode=None, weightd_metrics=None)來配置學習過程。引數:
- optimizer: 優化器
- loss: 損失函式
- metrics:訓練過程中的評價函式的list集合。通常使用metrics=[“accuracy”]
- sample_weight_mode:是否需要做時間的取樣
- weighted_metrics:不同的metrics的權重
例子:
model = Sequential()
model.add(Dense(32, input_shape=(500,)))
model.add(Dense(10, activation='softmax'))
model.compile(optimizer='rmsprop', loss='categorical_crossentropy',metrics=['accuracy'])
fit方法:
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)
在模型上進行epochs次的訓練。引數如下:
- x: 輸入,numpy.array型別或者array的list集合(此時對應有多個輸入)
- y: 標籤,numpy.array型別
- batch_size: 整數,每次梯度迭代更新使用的樣本數目。
- epochs: 迭代的總次數。
- verbose: 0代表沒有日誌輸出,, 1代表用進度條輸出日誌, 2代表每個epoch列印一行日誌。
- callbacks: keras.callbacks.Callback的list列表,在訓練過程中會被呼叫。
- validation_split: (0,1)之間的浮點數,用來將資料分一部分作為驗證集合。
- validation_data: 一個元組型別(tuple(x_val, y_val)或者(x_val, y_val, val_sample_weights)),作為驗證集,會覆蓋掉validation_split。
- shuffle: boolean,每個epoch是否會將資料打亂。
- class_weight: dictionary mapping classes to a weight value。
- sample_weight: Numpy array of weights for the training samples。
- initial_epoch: 哪一個epoch開始訓練,通常對於之前已經訓練了的model有用。
返回:
History物件。其history方法能夠記錄訓練過程中的loss和metrics value的值。
evaluate方法:
evaluate(self, x, y, batch_size=32, verbose=1, sample_weight=None)
在某些input data上一個個batch的計算總的loss。
返回:
一個loss的標量或者loss的列表(如果有多個metrics)。
predict方法:
predict(self, x, batch_size=32, verbose=0)
針對input輸出對應的predict值,通過batch一個一個batch的計算。
返回: numpy.array型別。
train_on_batch方法:
train_on_batch(self, x, y, class_weight=None, sample_weight=None)
對於某個batch上的資料進行梯度迭代更新。
引數:
- x: numpy.array或者numpy.array的list列表(多個輸入)。
- y: numpy.array
返回:
scala或者scala的list列表。
test_on_batch:
test_on_batch(self, x, y, sample_weight=None)
對於一個batch的資料進行評估。
返回:
scala或者scala的list列表。
predict_on_batch方法:
predict_on_batch(self, x)
x: numpy.array或者numpy.array的list列表。
返回:
numpy.array的預測值。
fit_generator方法:
fit_generator(self, generator, steps_per_epoch, epochs=1, verbose=1, callbacks=None, validation_data=None, validation_steps=None, class_weight=None, max_queue_size=10, workers=1, use_multiprocessing=False, initial_epoch=0)
對通過python的generator產生的資料一個一個batch的進行訓練。generator並行地在模型上執行來提升效率。這樣可以同時在CPU上做影象的augmentation和GPU上的訓練。
引數:
generator: 生成器,輸出必須為以下兩種中的一種:
- tuple型別。(inputs, targets)
- tuple型別。(inputs, targets, sample_weights)。
generator會在資料上不斷地進行迴圈。一個epoch完成的標誌是: steps_per_epoch個batch都已經訓練完成了。
- steps_per_epoch:每個epoch完成,generator會執行多少次。也就是batch的數目,通常為1+(len(train_data) // batch_size)
- epochs:迭代的次數
- verbose:列印日誌的方式,0,1或2
- callbacks: callbacks的列表,訓練期間每個epoch完成時會呼叫會呼叫。
- validation_data: 驗證集,可以是以下幾種:
- validation data的生成器
- 元組, tuple(inputs, targets)或者(tuple, targets, sample_weights)
- validation_steps:只有當validation_data是一個generator的時候有用。每次epoch完成時generator會執行多少次,通常為1+(len(validation_data) // batch_size)
- class_weight: dict型別
- max_queue_size: generator佇列的最大容量
- workers: 程序的最大數目
- use_multiprocessing:是否使用多執行緒
- initial_epoch: 哪一個epoch開始訓練,對於恢復前面訓練的模型有用
返回:
History物件。
例子:
def generate_arrays_from_file(path):
while 1:
f = open(path)
for line in f:
# create Numpy arrays of input data
# and labels, from each line in the file
x, y = process_line(line)
yield (x, y)
f.close()
model.fit_generator(generate_arrays_from_file('/my_file.txt'),
steps_per_epoch=1000, epochs=10)
evaluate_generator方法:
在一個data generator上評估模型,返回的資料型別和test_on_batch一樣。
evaluate_generator(self, generator, steps, max_queue_size=10, workers=1, use_multiprocessing=False)
- generator: generator生成的numpy元組(inputs, targets)或(inputs, targets, sample_weights)
- steps: batch的數目。
返回:scala或者scala的列表。
predict_generator方法:
predict_generator(self, generator, steps, max_queue_size=10, workers=1, use_multiprocessing=False, verbose=0)
通過對generator產生的資料來生成輸出。返回型別和predict_on_batch一樣。
引數:
- generator:生成一批input樣本的生成器
- steps: batch的數量
返回:
numpy.array的預測值。
get_layer方法:
get_layer(self, name=None, index=None)
獲取模型中的一層。通過名稱或者索引來獲取層。索引是自下而上的順序。
引數:
- name: str型別,layer的名稱
- index: int,layer的序號
返回:
一個layer的例項。
11. functional API
在function API當中,通過給定一個輸入input tensor和一個輸出output tensor,可以構建一個模型:
from keras.models import Model
from keras.layers import Input, Dense
a = Input(shape=(32,)) #a是一個tensor
b = Dense(32)(a) #b也是一個tensor
model = Model(inputs=a, outputs=b)
該模型會包含所有計算b所需要的圖層。
對於多輸入和多輸出,使用list來給定:
model = Model(inputs=[a1, a2], outputs=[b1, b2, b3])
常用的屬性:
- model.layers: layer的list列表
- model.inputs: input tensor的集合
- model.outputs: output tensor的集合
常用的方法和上面相同。
12 keras的layers
12.1 Merge層
有兩種方法來實現層的merge:
- 使用merge函式
from keras.layeres import merge #注意:merge函式用來對functional API進行整合,Merge類用來對Sequential來進行整合
12.1.2
Add()類:輸入一些列tensor(shape必須相同),輸入一個tensor(同shape)。返回這些tensor的逐元素和的tensor,shape不變。
import keras
input1 = keras.layers.Input(shape=(16,))
x1 = keras.layers.Dense(8, activation='relu')(input1)
input2 = keras.layers.Input(shape=(32,))
x2 = keras.layers.Dense(8, activation='relu')(input2)
added = keras.layers.Add()([x1, x2]) # equivalent to added = keras.layers.add([x1, x2]),shape為(8,)
out = keras.layers.Dense(4)(added)
model = keras.models.Model(inputs=[input1, input2], outputs=out)
12.1.2
Multiply()類,該層接收一個列表的同shape張量,並返回它們的逐元素積的張量,shape不變。
keras.layers.merge.Multiply()和Add類似。
12.1.3
Average()類,該層接收一個列表的同shape張量,並返回它們的逐元素的均值的tensor,shape不變。與Add和Multiply類似。
12.1.4
Maximun()類,該層接收一個列表的同shape張量,並返回它們的逐元素積的最大值的tensor,shape不變。
12.1.5
Concatenate():該層接收一個列表的同shape張量,並返回它們的按照給定軸相接構成的向量。
12.1.6
Dot(axes, normalize=False):計算兩個tensor中樣本的張量乘積。例如,如果兩個張量a和b的shape都為(batch_size, n),則輸出為形如(batch_size,1)的張量,結果張量每個batch的資料都是a[i,:]和b[i,:]的矩陣(向量)點積。
13 keras影象預處理
使用函式keras.preprocessing.image.ImageDataGenerator()
keras.preprocessing.image.ImageDataGenerator(featurewise_center=False,
samplewise_center=False,
featurewise_std_normalization=False,
samplewise_std_normalization=False,
zca_whitening=False,
zca_epsilon=1e-6,
rotation_range=0,
width_shift_range=0,
height_shift_range=0,
shear_range=0,
zoom_range=0,
channel_shift_range=0,
fill_mode="nearest",
cval=0.,
horizontal_flip=False,
vertical_filp=False,
rescale=None,
preprocessing_function=None,
data_format=K.image_data_format())
)
引數如下:
- featurewise_center:布林值,使輸入資料集去中心化(均值為0), 按feature執行
- samplewise_center:布林值,使輸入資料的每個樣本均值為0
- featurewise_std_normalization:布林值,將輸入除以資料集的標準差以完成標準化, 按feature執行
- samplewise_std_normalization:布林值,將輸入的每個樣本除以其自身的標準差
- zca_whitening:布林值,對輸入資料施加ZCA白化
- zca_epsilon: ZCA使用的eposilon,預設1e-6
- rotation_range:整數,資料提升時圖片隨機轉動的角度
- width_shift_range:浮點數,圖片寬度的某個比例,資料提升時圖片水平偏移的幅度
- height_shift_range:浮點數,圖片高度的某個比例,資料提升時圖片豎直偏移的幅度
- shear_range:浮點數,剪下強度(逆時針方向的剪下變換角度)
- zoom_range:浮點數或形如[lower,upper]的列表,隨機縮放的幅度,若為浮點數,則相當於[lower,upper] = [1 - zoom_range, 1+zoom_range]
- channel_shift_range:浮點數,隨機通道偏移的幅度
- fill_mode:;‘constant’,‘nearest’,‘reflect’或‘wrap’之一,當進行變換時超出邊界的點將根據本引數給定的方法進行處理
- cval:浮點數或整數,當fill_mode=constant時,指定要向超出邊界的點填充的值
- horizontal_flip:布林值,進行隨機水平翻轉
- vertical_flip:布林值,進行隨機豎直翻轉
- rescale: 重放縮因子,預設為None. 如果為None或0則不進行放縮,否則會將該數值乘到資料上(在應用其他變換之前)
- preprocessing_function: 將被應用於每個輸入的函式。該函式將在任何其他修改之前執行。該函式接受一個引數,為一張圖片(秩為3的numpy array),並且輸出一個具有相同shape的numpy array
- data_format:字串,“channel_first”或“channel_last”之一,代表影象的通道維的位置。該引數是Keras 1.x中的image_dim_ordering,“channel_last”對應原本的“tf”,“channel_first”對應原本的“th”。以128x128的RGB影象為例,“channel_first”應將資料組織為(3,128,128),而“channel_last”應將資料組織為(128,128,3)。該引數的預設值是~/.keras/keras.json中設定的值,若從未設定過,則為“channel_last”
返回值
keras.preprocessing.image.ImageDataGenerator
方法:
fit(x, y)
引數:- x: 資料,維度必須為4,第一維是樣本數量
- y: labels,也是矩陣,一般2維
- batch_size: default 32
- seed: int
- save_to_dir: None或者str,將圖片儲存到哪個路徑下
- save_prefix: default ” “,儲存圖片的字首
- save_format: png, jpg。
返回值
(x, y): x是一個numpy.ndarray的image,而y是對應的numpy.ndarray的標籤。如果只有x,則不會返回y
必須使用keras 2.0.0以上版本
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
from keras.utils.np_utils import to_categorical
img = load_img("../input/lena.jpg") # return type: PIL.JpegImagePlugin.JpegImageFile
x = img_to_array(img) # return type: numpy.ndarray
x = x.reshape((1,) + x.shape) # 輸入資料必須為(num_samples, height, width, channels)
datagen = ImageDataGenerator(
rotation_range=30,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True
)
#將變換的圖片儲存下來
datagen.fit(x)
y = to_categorical([1])
for i, (x_batch, y_batch) in enumerate(datagen.flow(x, y, batch_size, save_to_dir=my_path, save_prefix="lena", save_format="jpg")):
# 此處必須設定停止次數,否則會一直進行下去
if i > times:
break
#如果只有圖片,可以不指定y
for i, x_batch in enumerate(datagen.flow(x, batch_size, save_to_dir=my_path, save_prefix="lena", save_format="jpg")):
# 此處必須設定停止次數,否則會一直進行下去
if i > times:
break
使用ImageDataGenerator來訓練資料
datagen = ImageDataGenerator(
featurewise_center=False, # set input mean to 0 over the dataset
samplewise_center=False, # set each sample mean to 0
featurewise_std_normalization=False, # divide inputs by std of the dataset
samplewise_std_normalization=False, # divide each input by its std
zca_whitening=False, # apply ZCA whitening
rotation_range=0, # randomly rotate images in the range (degrees, 0 to 180)
width_shift_range=0.1, # randomly shift images horizontally (fraction of total width)
height_shift_range=0.1, # randomly shift images vertically (fraction of total height)
horizontal_flip=True, # randomly flip images
vertical_flip=False) # randomly flip images
datagen.fit(x_train)
model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size),
steps_per_epoch=x_train.shape[0] // batch_size, epochs=epochs, validation_data=(x_test, y_test),
workers=4)
datagenerator的工作過程:每次一個epoch取資料的時候,將圖片進行隨機變化然後輸入進模型。與傳統的未進行過變化的區別是:未進行過變化的模型每個epoch看到的圖片都是一模一樣的原圖。而進過datagenerator變化過後,每個epoch看到的都是經過變化後的圖片,甚至從來都不會看到原圖。
flow_from_directory(directory)
引數:
- directory:存放圖片的資料夾名稱。通常在不同的類下面,再建立子資料夾,該方法會自動根據子資料夾的名稱來設定類標籤。
- target_size:最終訓練時將圖片的大小設定為多少,預設(256,256)
- color_mode: 灰度圖為,”grayscale”, 彩色圖為,”rbg”. 預設: “rgb”。
- classes:可選引數,為子資料夾的列表,如[‘dogs’,’cats’]預設為None. 若未提供,則該類別列表將從directory下的子資料夾名稱/結構自動推斷。每一個子資料夾都會被認為是一個新的類。(類別的順序將按照字母表順序對映到標籤值)。通過屬性class_indices可獲得資料夾名與類的序號的對應字典。
- class_mode:”categorical”, “binary”, “sparse”或None之一. 預設為”categorical. 該引數決定了返回的標籤陣列的形式, “categorical”會返回2D的one-hot編碼標籤,”binary”返回1D的二值標籤.”sparse”返回1D的整數標籤,如果為None則不返回任何標籤, 生成器將僅僅生成batch資料, 這種情況在使用model.predict_generator()和model.evaluate_generator()等函式時會用到.
- batch_size:batch資料的大小,預設32。
- shuffle:是否打亂資料,預設為True。
- seed:可選引數,打亂資料和進行變換時的隨機數種子。
- save_to_dir:None或字串,該引數能讓你將提升後的圖片儲存起來,用以視覺化。
- save_prefix:字串,儲存提升後圖片時使用的字首, 僅當設定了save_to_dir時生效。
- save_format:”png”或”jpeg”之一,指定儲存圖片的資料格式,預設”jpeg”。
- follow_links:是否訪問子資料夾中的軟連結。
返回值:
ImageDataGenerator
例子:
for i, (x_batch, y_batch) in enumerate(datagen.flow_from_directory(directory="valid",save_to_dir="E:/a", save_prefix="lena", save_format="jpg", shuffle=False, target_size=(512,512))):
print(y_batch)
if i > 20:
break;
注意在使用flow_from_directory方法的時候,要將資料分成train和valid兩個資料夾,然後每個資料夾下面根據不同的標籤再建立子資料夾,然後每個子資料夾下再防止相應類的圖片。在predict_genertor的時候要將shuffle設定為False,否則標籤和相應的影象對不上。
當使用model.fit_generator訓練的時候,使用如下方法:
model.fit_generator(datagen.flow(x_train, y_train, batch_size=32),
steps_per_epoch=len(x_train), epochs=epochs))
或者
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
'data/train',
target_size=(150, 150),
batch_size=32,
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
'data/validation',
target_size=(150, 150),
batch_size=32,
class_mode='binary')
model.fit_generator(
train_generator,
steps_per_epoch=2000,
epochs=50,
validation_data=validation_generator,
validation_steps=800)
注意,一般valid_generator和test_generator不需要做影象變換,而只在train_generator當中做影象變換。即:
valid_gen = ImageDataGeneraotr() #不放任何引數
test_gen = ImageDataGenerator() #不放任何引數
使用來預測標籤,注意最終的輸出順序按照資料夾和檔案的順序來,linux資料夾和檔案的排序方式和windows不同。最後使用來獲取標籤對應的檔案:
#注意要把shuffle設定為False, class_model設定為False表示不產生標籤
test_gen = ImageDataGeneraotr().flow_from_directory(test_path, shuffle=False, class_model=None, target_size=target_size, batch_size=batch_size)
result = model.predict_generator(generator=test_gen, ...)
filenames = test_gen.filenames #這時,對應的檔名的順序和result的預測結果對應的順序對應
14. 定義top-K準確率
一般的時候,可以直接使用內建的準確率:
from keras import metrics
model.compile(loss='mean_squared_error',
optimizer='sgd',
metrics=[metrics.mae, metrics.categorical_accuracy, metrics.top_k_categorical_accuracy]) #k預設5
自定義top-K準確率:
def top_3_accuracy(y_true, y_pred):
return top_k_categorical_accuracy(y_true, y_pred, k=3)
model.compile(..........., metrics=[top_3_accuracy])
15. transfer learning和fine tuning
通常先將前面的卷積層固定,先用Adam Optimizer訓練全連線層。帶基本收斂(通常2~3個epoch),然後開始全部訓練,全部訓練時,用SGD Optimizer比較好。
for layer in base_model.layers[:25]:
layer.trainable = False
sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])