keras中Lambda层的使用

在keras中搭建模型常用的方法有两种:

(1)一种是较为简单的序列模型Sequential(该方法适用于搭建简单的模型)

(2)一种是使用Keras函数式的API(该方法最为常用)

无论使用哪种方法在搭建model时都要求使用keras中继承自Layer的层(例如keras.layers.Conv1D等等),但有时候又需要使用一些keras.layers中没有的层(例如expand_dim, squeeze或者自己定义的层等)。这时候必须想办法将其转换成keras中的Layer,一般有两种方法,一种是直接定义类class然后继承Layer,一种是直接使用Lambda函数。这里主要讲使用Lambda函数的方法,该方法比较简单。

例1:定义一个squeeze层,其中x是上一层的输出,arguments中的axis参数是传给keras.backend.squeeze的。

from tensorflow import keras

squeeze = keras.layers.Lambda(keras.backend.squeeze, arguments={'axis': -1})(x)

或者:

squeeze = keras.layers.Lambda(lambda x: keras.backend.squeeze(x, axis=-1))(x)

再或者:

def squeeze_function(x):
    return keras.backend.squeeze(x, axis=-1)

squeeze = keras.layers.Lambda(squeeze_function)(x)

-------------------------------------------------------下面的内容可能会误导大家,谨慎查看

例2:定义一个DepthwiseConv1D层,在keras中并没有这个层,keras只有SeparableConv1D和Depthwise2D层。(我不确定是否正确仅供参考)

def DepthwiseConv1D(x):
    expand_dim = keras.backend.expand_dims(x, axis=2)
    depthwiseConv2D = keras.layers.DepthwiseConv2D(kernel_size=[int(expand_dim.shape[1], 1)])(expand_dim)
    squeeze_dim = keras.backend.squeeze(depthwiseConv2D, axis=2)
    return squeeze_dim

depwiseconv = keras.layers.Lambda(DepthwiseConv1D)(x)

这里需要注意下扩展与压缩哪个维度。

比如我的目的是将(batch,500,16)通过depwiseconv1d变为(batch,1,16)。输入的tensor格式是(batch, 500, 16),在扩充维度axis=2后变成了(batch,500,1,16)你可以理解为是一个高度为500、宽度为1、深度为16的一个矩阵,我们使用了depthwiseconv2d(kernel_size=[500, 1], stride=[1, 1])后变为(batch,1,1,16),然后压缩维度axis=2得到我想要的(batch,1,16)。

看到这有人会说为什么不去扩展最后一个维度axis=-1,用同样的kernel和stride也能得到相同的结果,(batch,500,16)->(batch,500,16,1)->(batch,1,16,1)->(batch,1,16)。嗯...我也试过,确实可以,但是有个问题,训练网络的速度会比前一个方法慢接近一倍。我猜应该是第二种方法的channel为1的原因(可能depthwiseconv对多维做了优化但这里没能体现出来)。

还有一个问题,使用自己搭建的depthwiseconv1d方法训练模型收敛很慢,使用自己的depthwiseconv1d加上普通的conv1d效果没有官方自带的SeparableConv1D好,如果有大神,还请赐教。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章