- 在tensorflow的官方文档:https://www.tensorflow.org/guide/keras?hl=zh-cn
- 原生文档:https://keras.io/
Keras中最重要的两个组件即:Model
和Layer
,二者在构建模型时核心的接口类似;Model
还另外包含训练和测试相关的接口。
Model简介
关键成员
updates
:返回模型中,从输入到输出的所有的layer中,layer.updates
的op。compile(...)
:将模型所需要的其他核心组件配置好,比如metric、loss、optimizer。evaluate(...)
:在测试模式下,计算损失值和指标值。fit(...)
:模型训练,可以在callbacks
中设置常用的内置Callback
对象或者自定义Callback
的对象。predict(...)
:生成预测。load_weights(filepath, by_name=False)
:加载模型权重。save_weights(filepath, overwrite=True, save_format=None)
:保存模型权重。summary()
:输出模型描述文本。
常见使用范式
直接使用内置Model
比如最简单的tf.keras.Sequential()
。
1 | model = tf.keras.Sequential() |
- 优点:简单安全。
- 缺点:只能用于层堆叠的简单模型,不能表示其他拓扑结构。
自定义模型
方式一:函数式API
1 | inputs = tf.keras.Input(shape=(3,)) |
- 优点:可以构建复杂的函数拓扑(多输入、多输出、共享层)。相对比较安全。
- 缺点:没有子类化灵活。
方式二:模型子类化
1 | class MyModel(tf.keras.Model): |
- 优点:最灵活,在启用
Eager Execution
时,可以命令式地编写前向传播。 - 缺点:复杂性更高且用户出错率更高,
model.inputs
、model.outputs
、model.to_yaml()
、model.to_json()
、model.get_config()
、model.save()
不可用。
继承Model
必须重写的方法:
__init__
:创建模型用到的层,并设置为类实例的属性。call
:定义前向传播,即连接上面定义的层(定义层的输入输出)。
自定义Layer
参考keras官方文档:Writing your own Keras layers
自定义layer最佳方法是继承tf.keras.Layer
。
1 | class MyDenseLayer(tf.keras.layers.Layer): |
必须重写的方法:
__init__
:所有和input无关的初始化。call
:定义前向传播。
keras文档中还提到必须重写compute_output_shape
:根据input的shape,返回output的shape。
非必须但很重要:
build
:- 传入input的shape,然后做所有剩下的初始化。
- 也可以将所有初始化过程都写在
__init__
中,这就意味着参数的shape必须固定下来,input的shape也因此需要固定。 - 必须在最后调用
self.built=True
。 - 在模型第一次调用
call()
之前会调用build()
。
1 | import tensorflow as tf |
1 | my_dense_layer build() is called. |
1 | print(layer(tf.zeros([10, 5]))) |
1 | my_dense_layer call() is called. |
可见,在模型第一次调用call()
之前会调用build()
。
官方文档:
build()
: Called once from__call__
, when we know the shapes of inputs anddtype
. Should have the calls toadd_weight()
, and then call the super’sbuild()
(which setsself.built = True
, which is nice in case the user wants to callbuild()
manually before the first__call__
).
源代码:
1 | def _maybe_build(self, inputs): |
_maybe_build
会被__call__()
调用,layer
用self.built
标识是否已经调用过build()
。
复杂模型
参考tensorflow官方文档:Writing layers and models with TensorFlow Keras
在自定义layer中使用其他layer
一些很常用的layer比如Dense
,很可能被一个layer作为一部分,那Dense
的代码如果不想重写,就需要在自定义的Layer中使用其他Layer。
官方推荐在__init__
方法里实例化所有的子layer。子layer里面的build
会在外层layer的build
被调用时调用。
1 | class MyDenseBlock(tf.keras.layers.Layer): |
1 | my_dense_block build() is called. |
在自定义model中使用其他model
这个方法也可以使用,但也有一些坑。
如果被使用的子model是使用函数式api定义的,一般可以正常使用,但如果是子类的方式,则必须重写build
和compute_output_shape
如下:
1 | def build(self, input_shape): |
原因是子model会被当做layer使用,这两个函数经常会被一些layer的wrapper调用,所以需要加上(血的教训)。