1. 数据预处理
这是预处理模块,包括序列数据的处理、文本数据的处理、图像数据的处理。重点看一下图像数据的处理,keras提供了ImageDataGenerator函数,实现data augmentation,数据集扩增,对图像做一些弹性变换,比如水平翻转、垂直翻转、旋转等。
1.1 序列预处理
填充序列pad_sequences:sequences为浮点数或整数构成的两层嵌套列表。按maxlen长度截断或者补0。
keras.preprocessing.sequence.pad_sequences(sequences, maxlen=None, dtype='int32', padding='pre', truncating='pre', value=0.)
跳字skipgrams:
keras.preprocessing.sequence.skipgrams(sequence, vocabulary_size, window_size=4, negative_samples=1., shuffle=True, categorical=False, sampling_table=None)
1.2 文本预处理
句子分割:本函数将一个句子拆分成单词构成的列表。text是待处理的文本,filters是需要过滤字符的列表或者字符连接形成的字符串,lower表示是否将序列设为小写形式,split是单词的分隔符。
keras.preprocessing.text.text_to_word_sequence(text, filters='!"#$%&()*+,-./:;<=>?@[\]^_`{|}~\t\n', lower=True, split=" ")
one-hot编码:本函数将一段文本编码为one-hot形式的码,即仅记录词在词典中的下标。
keras.preprocessing.text.one_hot(text, n, filters='!"#$%&()*+,-./:;<=>?@[\]^_`{|}~\t\n', lower=True, split=" ")
特征哈希hashing_trick:将文本转换为固定大小的哈希空间中的索引序列;n为哈希空间的维度,hash_function默认为python hash函数。
keras.preprocessing.text.hashing_trick(text, n, hash_function=None, filters='!"#$%&()*+,-./:;<=>?@[\]^_`{|}~\t\n', lower=True, split=' ')
1.3 图片预处理
2. 模型
2.1 序贯模型(Sequential)
2.2 函数式模型(Model)
2.3 两类模型的相同方法
2.3.1 打印模型概况
model.summary():打印出模型概况,它实际调用的是keras.utils.print_summary。
2.3.2 保存、恢复模型的config信息
model.get_config():返回包含模型配置信息的Python字典。模型也可以从它的config信息中重构回去。
config = model.get_config()
model = Model.from_config(config)
# or, for Sequential:
model = Sequential.from_config(config)
2.3.3 保存、恢复模型的层、权重,设置模型的权重
model.get_layer():依据层名或下标获得层对象。
model.get_weights():返回模型权重张量的列表,类型为numpy array。
model.set_weights():从numpy array里将权重载入给模型,要求数组具有与model.get_weights()相同的形状。
2.3.4 得到模型的网络结构 JSON字符串
model.to_json:返回代表模型的JSON字符串,仅包含网络结构,不包含权值。可以从JSON字符串中重构原模型。
from models import model_from_json
json_string = model.to_json()
model = model_from_json(json_string)
2.3.5 保存、恢复模型的网络结构 YAML字符串
model.to_yaml:与model.to_json类似,同样可以从产生的YAML字符串中重构模型。
from models import model_from_yaml
yaml_string = model.to_yaml()
model = model_from_yaml(yaml_string)
2.3.6 保存、恢复模型的权重
model.save_weights(filepath):将模型权重保存到指定路径,文件类型是HDF5(后缀是.h5)。
model.load_weights(filepath, by_name=False):从HDF5文件中加载权重到当前模型中,默认情况下模型的结构将保持不变。如果想将权重载入不同的模型(有些层相同)中,则设置by_name=True,只有名字匹配的层才会载入权重。
2.3.7 保存、恢复模型的网络结构和权重
from keras.models import load_model
model.save('my_model.h5') # creates a HDF5 file 'my_model.h5'
del model # deletes the existing model
# returns a compiled model
# identical to the previous one
model = load_model('my_model.h5')
2.3.8 获取中间层的输出
要获取中间层的输出,最好的办法是新建一个模型。
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]
2.3.9 使用history函数来记录每一个epoch的training/validation的loss/accuracy
model.fit()会返回一个History对象。该对象有一个history属性,记录着loss和metrics的信息。
hist = model.fit(x, y, validation_split=0.2)
print(hist.history)
2.3.10 固定某些layer
frozen_layer = Dense(32, trainable=False)
2.3.11 模型的一些常用属性
model.layers: layer的list列表
model.inputs: input tensor的集合
model.outputs: output tensor的集合
3. 网络层
3.1 包装器Wrapper
3.1.1 TimeDistributed包装器
keras.layers.wrappers.TimeDistributed(layer)
参数:
layer:Keras层对象
输入至少为3D张量,下标为1的维度将被认为是时间维。例如,考虑一个含有32个样本的batch,每个样本都是10个向量组成的序列,每个向量长为16,则其输入维度为(32,10,16),其不包含batch大小的input_shape为(10,16)。
我们可以使用包装器TimeDistributed包装Dense,以产生针对各个时间步信号的独立全连接。
如何在长短期记忆(LSTM)网络中利用TimeDistributed层—python语言
model = Sequential()
model.add(TimeDistributed(Convolution2D(64, 3, 3), input_shape=(10, 3, 299, 299)))
3.1.2 Bidirectional包装器
keras.layers.wrappers.Bidirectional(layer, merge_mode='concat', weights=None)
model.add(Bidirectional(LSTM(10, return_sequences=True)))
双向RNN包装器
参数:
layer: Recurrent对象
merge_mode: 前向和后向RNN输出的结合方式,为sum,mul,concat,ave和None之一,若设为None,则返回值不结合,而是以列表的形式返回。
self.forward_layer = copy.copy(layer)
config = layer.get_config()
config['go_backwards'] = not config['go_backwards']
self.backward_layer = layer.__class__.from_config(config) 两个RNN层,一个go_backwards为True,一个go_backwards为False。
y = self.forward_layer.call(inputs, **kwargs)
y_rev = self.backward_layer.call(inputs, **kwargs)
if self.return_sequences:
y_rev = K.reverse(y_rev, 1)
if self.merge_mode == 'concat':
output = K.concatenate([y, y_rev])
3.2 循环层Recurrent
3.2.1 Recurrent层
keras.layers.recurrent.Recurrent(return_sequences=False, go_backwards=False, stateful=False, unroll=False, implementation=0)
参数:
return_sequences: 布尔值,默认False,控制返回类型。若为True则返回整个序列,否则仅返回输出序列的最后一个输出。
go_backwards: 布尔值,默认为False,若为True,则逆向处理输入序列并返回输出序列。
输入shape: 形如(samples,timesteps,input_dim)的3D张量。
输出shape: 如果return_sequences=True,返回形如(samples,timesteps,output_dim)的3D张量;否则,返回形如(samples,output_dim)的2D张量。
4. 网络配置
4.1 初始化方法 Initializer
4.2 激活函数 Activation
4.3 损失函数 loss
4.4 优化器 Optimizer
4.5 正则项 Regularizer
4.6 性能评估 Metrices
5. 利用Keras的扩展性,Keras的高级功能
5.1 自定义loss,并且设置compile的loss、loss_weights、metrics参数
如果是多输出的模型,只能给每个输出分别设置一个loss,然后加权求和,比较复杂的loss就不能定义。记住是“分别设置”、“加权求和”。也就是说loss函数应该以(y_true, y_pred)为参数,并返回单个张量,你有多个输出,每个输出都有这么一个函数,参数就是某个输出和预测的输出。
def mean_pred(y_true, y_pred):
return K.mean(y_pred)
下面例子,第一个loss参数为train_targets和predict;第二个loss参数为random_y和l2_loss,但是返回值就是l2_loss。整体loss为两个loss的加权和。
metrics为accuracy,参数为train_targets和predict。
model_train = Model(inputs=[input_image,input_target], outputs=[predict,l2_loss])
model_train.compile(optimizer='adam', loss=['sparse_categorical_crossentropy',lambda y_true,y_pred: y_pred], loss_weights=[1.,0.2], metrics={'softmax':'accuracy'})
model_train.fit([train_images,train_targets], [train_targets,random_y], epochs=10)
5.2 Lambda层
如果你只是想对流经该层的数据做个变换,而这个变换本身没有什么需要学习的参数,那么直接用Lambda Layer是最合适的了。
from keras.layers.core import Lambda
def sub_mean(x):
x -= K.mean(x,axis=1,keepdims=True)
return x
model.add(Lambda(sub_mean, output_shape=lambda input_shape:input_shape))
注意Lambda 是可以进行参数传递的。
def slice(x,index):
return x[:,:,index]
x1 = Lambda(slice,output_shape=(4,1),arguments={'index':0})(a)
x2 = Lambda(slice,output_shape=(4,1),arguments={'index':1})(a)
keras Lambda自定义层实现数据的切片,Lambda传参数
5.3 自定义非递归层
如果自己想定义的层中有需要学习的变量,那么就不能用lambda层了,需要自己写一个出来。
如下,实现的功能是对张量乘一个正对角阵(换句话说,输入向量与一个要学习的向量逐元素相乘)。
from keras import backend as K
from keras.engine.topology import Layer
import numpy as np
class MyLayer(Layer):
def __init__(self, output_dim, **kwargs):
self.output_dim = output_dim
super(MyLayer, self).__init__(**kwargs)
def build(self, input_shape):
# Create a trainable weight variable for this layer.
self.kernel = self.add_weight(name='kernel',
shape=(input_shape[1], self.output_dim),
initializer='uniform',
trainable=True)
super(MyLayer, self).build(input_shape) # Be sure to call this somewhere!
def call(self, x):
return K.dot(x, self.kernel)
def compute_output_shape(self, input_shape):
return (input_shape[0], self.output_dim)
5.4 自定义递归层
递归层的定义方法和非递归层不太一样。根据Keras内LSTM的写法,它还有一个reset_states函数和step函数,这是由递归的性质决定的。例子都在keras/layers/recurrent.py中。
可以在Keras中把LSTM的代码复制过来修修改改。不过LSTM也不能直接复制过来,还需要import如下几个依赖:
from keras.layers.recurrent import LSTM,Recurrent,time_distributed_dense
from keras import initializations,regularizers,activations
from keras.engine import InputSpec
5.5 自定义优化函数
Keras的代码确实好,耦合度很低。Keras内置的优化函数在keras/optimizers.py中,基类Optimizer也在这个文件里。例如把它内置的SGD算法拷贝到自己的文件中,只要先from keras.optimizers import Optimizer就能编译通过。
有时候要得到state-of-the-art的结果,需要用sgd加动量法充分收敛。比如学习率0.01学习上100epoch,再把学习率减半,再学100epoch,依次类推。如果不自定义优化函数的话,就要分阶段调用fit函数,修改学习率,可能还要重新compile。这就不是很优美了。其它一些奇葩的学习策略,也可以通过自定义优化函数来得到。
keras中自定义Layer 设置该层的input_spec,这个是通过InputSpec函数来实现。