文章目录
简介
一些特点:
-
提供了对 tensorflow low-level api 的高级封装,用户代码更清爽, 简洁.
-
各种新式trick都有,比如Batch normalization,PReLU等等
-
架构灵活,model基于一层层的layer叠加,可插拔性十分强
-
作者简介
keras 之父, google brain 研究员 François Chollet, 他也参与了 TensorFlow 的框架研发.
一. Layer
类比于 torch 中的 Module, 是一个计算子图的抽象与封装, 面向对象的风格更易阅读维护.
1.1 api
-
class
tf.keras.layers.Layer
, 位于 tensorflow.python.keras.engine.base_layer.Layer. 是抽象类.__init__
(self, trainable=True, name=None, dtype=None, **kwargs)build
(), 创建 variable 并 构图. Called once from__call__()
. 子类覆写时, 用户逻辑后要调用 super’sbuild()
.call()
, 用户自定义逻辑写在这里.
-
简明源码
@tf_export('keras.layers.Layer') class Layer(checkpointable.CheckpointableBase): @property def name(self): return self._name @property def variables(self): return self.weights def build(self, input_shape): """Creates the variables of the layer.""" self.built = True def add_weight(self, name, shape, dtype=None, initializer=None, regularizer=None, trainable=None, constraint=None, partitioner=None, use_resource=None, synchronization=tf_variables.VariableSynchronization.AUTO, aggregation=tf_variables.VariableAggregation.NONE, **kwargs): pass return variable def call(self, inputs, **kwargs): return inputs def __call__(self, inputs, *args, **kwargs): with ops.name_scope(self._name_scope()): if not self.built: self.build(input_shapes) self.built = True outputs = self.call(inputs, *args, **kwargs) return outputs
-
class tensorflow.python.layers.base., 过时的 class, 要用 keras Layer 替代.Layer
1.2 库中自带子类
1.2.1 Dense
- keras.layers.core.Dense(Layer)
普通的全连接神经网络层. - Dense#
__init__
(self, units,
activation=None,
use_bias=True,
kernel_initializer=‘glorot_uniform’,
bias_initializer=‘zeros’,
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
**kwargs)
# 以下两行等价
model.add(Dense(32, input_shape=(784,)))
model.add(Dense(32, input_dim=784))
# 只有首层需要指定输入维度. 后续各层只需指定神经元个数.
Dense(10, activation='relu', input_dim=4)
1.2.2 activation
- keras.layers.advanced_activations.PReLU(Layer)
- keras.activations 模块
有 softplus, relu, tanh 等.
1.2.3 dropout
- keras.layers.core.Dropout(Layer)
类. - Dropout#
__init__
(self, rate, noise_shape=None, seed=None, **kwargs)
rate
指的是要扔掉的占比, 而不是keep_rate.
1.2.4 batach nomarlization
- keras.layers.normalization.BatchNormalization(Layer)
类. 对前面一层每个batch的输出作正规化. - BatchNormalization#
__init__
(self,
axis=-1,
momentum=0.99,
epsilon=1e-3,
center=True,
scale=True,
beta_initializer=‘zeros’,
gamma_initializer=‘ones’,
moving_mean_initializer=‘zeros’,
moving_variance_initializer=‘ones’,
beta_regularizer=None,
gamma_regularizer=None,
beta_constraint=None,
gamma_constraint=None,
**kwargs)
1.3 用户自定义子类
为了代码重用, 风格一致,可以自定义 layer. 详见参考[3].
一般地, 在build()
中创建参数, 在call()
中基于已创建的参数(即 trainable variables) 作逻辑实现.
命名空间 variable_scope 的讨论: 若没有给 self._scope
赋值, 则 tf 会解析你的大驼峰格式类名(如FeedForward) 转化为小写字符串加下划线的格式(如 feed_forward).
class FeedForward(tf.keras.layers.Layer):
"""position-wise feed forward net. See 3.3
inputs: A 3d tensor with shape of [N, T, C].
num_units: A list of two integers.
Returns:
A 3d tensor with the same shape and dtype as inputs
"""
def __init__(self, num_units, scope='position_wise_feed_forward',**kwargs):
# self._scope = scope
self.num_units = num_units
super(FeedForward,self).__init__(**kwargs)
def call(self, inputs, **kwargs):
# Inner layer, ReLU
outputs = Dense(self.num_units[0], activation=tf.nn.relu)(inputs)
# Outer layer, linear
outputs = Dense(self.num_units[1])(outputs)
# Residual connection
outputs += inputs
# Normalize
outputs = layer_norm(outputs)
return outputs
build() 方法
可以把 self.add_weight()
这样的调用从 构造方法中 下放到 build() 方法中. 一方面逻辑更清晰, 还可以做到 shape 的延迟(lazy)确定.
def build(self, input_shape):
self.w = self.add_weight(shape=(input_shape[-1], self.units))
1.4. layer 重用
多个不同的输入共享同样的网络处理. 详见参考[3].
使用举例: 在DSSM中, 输入是[query, {doc_1,doc_2,…,doc_n}]. 只有两个网络, 分别映射两种不同类型的文本. 所以多个doc的输入就要共享第二个网络.
可以与tf的API搭配使用. 比如
self.keras_shared_content_sideinfo_linear_layer = tf.keras.layers.Dense(units=128, input_shape=[128+64+128, ],name='keras_shared_content_sideinfo_linear_layer')
def get_content_emb(self):
# ...
content_side_info_concat = tf.concat(content_side_info_tensors, axis=-1)
emb = self.keras_shared_content_sideinfo_linear_layer(content_side_info_concat)
二. Model
2.1 api
class
tensorflow.python.keras.engine.training.Model
存在 keras.Layer <- keras.Network <- keras.Model 的派生关系.
2.2 用户自定义子类
详见参考[3].
2.3 model 搭建
有 序列模型 与 函数式模型 两种网络拓扑搭建法.
在处理像TextCNN这种 先分支再融合 的网络, 函数式模型更灵活.
Sequential 序列风格
- keras.models.
Sequential
(Model)
类. 代表普通的多层前馈神经网络. - keras.models.Sequential#add(self,layer)
方法. 像搭积木一样, 往后加上一层.
model = Sequential()
model.add(Dense(10, activation='relu', input_dim=4))
model.add(Dropout(0.8))
model.add(Dense(5, activation='relu'))
model.add(Dense(3, activation='softmax'))
函数式风格
与上面对比.
inputs=Input(shape=(FEATURE_DIM,))
dense1=Dense(10, activation='relu', input_dim=4)(inputs)
dense2=Dense(5, activation='relu')(dense1)
outpus=Dense(3, activation='softmax')(dense2)
# type(dense2) 是 Tensor类型, tensorflow.python.framework.ops.Tensor ,与backend有关.
model=Model(inputs=inputs,outputs=outpus)
这种调用方法看起来比较特殊, 因为Layer类拥有__call__()
方法, 它的对象就变成了可调用对象.
模型拓扑
model.summary()
"""
会得到以下输出: 各层的out_shape
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_2 (InputLayer) (None, 4) 0
_________________________________________________________________
dense_5 (Dense) (None, 10) 50
_________________________________________________________________
dense_6 (Dense) (None, 5) 55
_________________________________________________________________
dense_7 (Dense) (None, 3) 18
=================================================================
Total params: 123
Trainable params: 123
Non-trainable params: 0
_________________________________________________________________
"""
#边写边调试的时候, 可以用`dense2._keras_shape`字段来查看output_shape.
dense2._keras_shape #(None, 5)
# 也可以直接print tensor
print (embedding) #Tensor("embedding_1/Gather:0", shape=(?, 10, 10), dtype=float32)
还可以画图, 见我的另一篇博文,keras 的可视化
三. train loop 相关
5. compile
- keras.models.Sequential#compile(self, optimizer, loss,
metrics=None,
… )
对模型描述进行编译, 然后才能训练. - metrics
常用的有 ‘accuracy’, ‘mae’ - loss
详见 keras.losses模块, 常用的有:
mse = MSE = mean_squared_error
mae = MAE = mean_absolute_error
mape = MAPE = mean_absolute_percentage_error
6.fit
- keras.engine.training.Model#fit(self, x=None,
y=None,
batch_size=None,
epochs=1,
verbose=1,
callbacks=None,
validation_split=0.,
validation_data=None,
shuffle=True,
class_weight=None,
sample_weight=None,
initial_epoch=0,
steps_per_epoch=None,
validation_steps=None,
**kwargs)
训练模型, 类 sklearn 的写法.
可以加入validation_data, 观察各种指标在训练期间在验证集上的表现. 如validation_data=([x_1,x_2],[y_1,y_2])
,也支持多输入和多输出. - verbose
建议设置为2, 表示每个epoch只输出一行.
7. callback
fit()
函数中的callbacks参数可以传入一个list, 包含丰富的callbacks.
keras自带了一些使用的callback实现类.
- EarlyStopping
如keras.callbacks.EarlyStopping(monitor='val_loss', patience=3, verbose=1, mode='auto')
并使用各种callback来达到early stop的目的. - ModelCheckpoint
如keras.callbacks.ModelCheckpoint(filepath, monitor='val_loss', verbose=0, save_best_only=False, save_weights_only=False, mode='auto', period=1)
- save_best_only:当设置为True时,将只保存在验证集上性能最好的模型
8. evaluate
- keras.engine.training.Model#metrics_names
字段. 一个模型的多个metric值. 同 compile 阶段的 metric. - keras.engine.training.Model#evaluate(self, x, y,
batch_size=None,
verbose=1,
sample_weight=None,
steps=None)
Returns theloss value
&metrics values
for the model in test mode. 与keras.engine.training.Model#metrics_names
一 一对应.
参考
- keras 官方文档
- keras 官方文档, shared-layers
- keras&tf 官方文档, making_new_layers_and_models_via_subclassing