具体请查看官方文档keras官方文档
neural layers(神经层), cost functions(损失函数), optimizers(优化器), initialization schemes(初始化方案), activation functions(激活函数), regularization(正则化项)在keras中都是独立的模块,可以自由组合。
keras的核心是一个模型,用来阻止各个网络层次结构。最简单的是Sequential模型,即序贯模型,是一个个网络层的线性叠加。对于更复杂的结构,应该使用keras提供的function API(功能API)。function API允许构建任何的网络结构。
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)
TensorFlow安装
Theano安装
CNTK安装
在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
字段说明:
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"))
model = Seqnential()
model.add(Dense(32, input_shape=(784, )))
或者
model = Sequential()
model.add(Dense(32, input_dim=784))
训练模型之前,需要先配置模型的学习过程。通过使用compile()函数实现,compile()函数有3个参数:
# 多分类
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])
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例子
keras的functional API可以用来定义复杂的模型,如多输出模型,有向无环图或具有共享图层的模型。
functional API的调用过程:
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的矩阵
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
保存模型的结构、权重和优化器状态,不推荐cPickle来保存。可以使用model.save(filepath)来将模型保存为一个HDF5文件。该文件中包含:
使用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")
#保存为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)
使用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来实现
要获取中间层的输出,最好的办法是新建一个模型
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]
model.fit()会返回一个History对象。该对象有一个history属性,记录着loss和metrics的信息
hist = model.fit(x, y, validation_split=0.2)
print(hist.history)
在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) #会改变权重
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
通过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)
有两种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来加载哪些名称相同的层的权重。
model.layers:模型中一些列layer的list集合。
常用的方法:
compile(self, optimizer, loss, metrics=None, sample_weitght_mode=None, weightd_metrics=None)来配置学习过程。参数:
例子:
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次的训练。参数如下:
返回:
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上的数据进行梯度迭代更新。
参数:
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: 生成器,输出必须为以下两种中的一种:
generator会在数据上不断地进行循环。一个epoch完成的标志是: steps_per_epoch个batch都已经训练完成了。
例子:
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)
返回:scala或者scala的列表。
predict_generator方法:
predict_generator(self, generator, steps, max_queue_size=10, workers=1, use_multiprocessing=False, verbose=0)
通过对generator产生的数据来生成输出。返回类型和predict_on_batch一样。
参数:
get_layer方法:
get_layer(self, name=None, index=None)
获取模型中的一层。通过名称或者索引来获取层。索引是自下而上的顺序。
参数:
在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])
常用的属性:
有两种方法来实现层的merge:
from keras.layeres import merge #注意:merge函数用来对functional API进行整合,Merge类用来对Sequential来进行整合
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)
Multiply()类,该层接收一个列表的同shape张量,并返回它们的逐元素积的张量,shape不变。
keras.layers.merge.Multiply()和Add类似。
Average()类,该层接收一个列表的同shape张量,并返回它们的逐元素的均值的tensor,shape不变。与Add和Multiply类似。
Maximun()类,该层接收一个列表的同shape张量,并返回它们的逐元素积的最大值的tensor,shape不变。
Concatenate():该层接收一个列表的同shape张量,并返回它们的按照给定轴相接构成的向量。
Dot(axes, normalize=False):计算两个tensor中样本的张量乘积。例如,如果两个张量a和b的shape都为(batch_size, n),则输出为形如(batch_size,1)的张量,结果张量每个batch的数据都是a[i,:]和b[i,:]的矩阵(向量)点积。
使用函数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())
)
参数如下:
返回值
keras.preprocessing.image.ImageDataGenerator
方法:
fit(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)
参数:
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 p r e d i c t _ g e n e r a t o r 来预测标签,注意最终的输出顺序按照文件夹和文件的顺序来,linux文件夹和文件的排序方式和windows不同。最后使用 test_gen.filenames t e s t _ g e n . f i l e n a m e s 来获取标签对应的文件:
#注意要把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的预测结果对应的顺序对应
一般的时候,可以直接使用内置的准确率:
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])
通常先将前面的卷积层固定,先用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'])