1. 程式人生 > >keras學習筆記

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模型的使用

  1. 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"))
  2. 指定模型的輸入維度
    模型需要知道輸入的維度。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() #不放任何引數

使用predict_generator來預測標籤,注意最終的輸出順序按照資料夾和檔案的順序來,linux資料夾和檔案的排序方式和windows不同。最後使用test_gen.filenames來獲取標籤對應的檔案:

#注意要把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'])