我在尝试实现一个ResNet模型。我希望使用一个函数来生成“基础”层(即在未修改的输入上添加的conv-relu-conv-relu),这样我可以快速地以编程方式增加层数。然而,当我将层作为函数参数传递给函数时,它表示这不是一个Keras张量。第一部分是我的函数定义,第二部分是调用,其中x_in是层对象,y是残差块的输出。我使用“x”作为前一层和下一层的名称。
def ResBlock(x_in, n_filt, l_filt, pool): ... return yx = ResBlock(x, 32, 16, 0)
在谷歌上搜索了一些内容后,我发现这是正确的语法:
def ResBlock(n_filt, l_filt, pool): def unit(x_in): x = Conv1D(n_filt, l_filt, padding='same')(x_in) x = BatchNormalization()(x) x = relu(x) x = Dropout(0.1)(x) x = Conv1D(n_filt, l_filt, padding='same')(x) if pool: x = MaxPooling1D()(x) x_in = MaxPooling1D()(x_in) y = keras.layers.add([x, x_in]) return y return unitx = ResBlock(32, 16, 0)(x)
谁能解释为什么这是正确的方法?具体来说,我很好奇为什么我们需要为层对象使用嵌套的def?
回答:
Keras的标准“风格”是:首先定义一个层,然后应用它。因此,您提供的代码不是正确的风格,这就是为什么您会感到困惑的原因。
正确的风格应该是这样的:
def ResBlock(n_filt, l_filt, pool): conv_1 = Conv1D(n_filt, l_filt, padding='same') bn = BatchNormalization() dropout = Dropout(0.1) conv_2 = Conv1D(n_filt, l_filt, padding='same') maxpool_1 = MaxPooling1D() maxpool_2 = MaxPooling1D() def unit(x_in): x = conv_1(x_in) x = bn(x) x = relu(x) x = dropout(x) x = conv_2(x) if pool: x = maxpool_1(x) x_in = maxpool_2(x_in) y = keras.layers.add([x, x_in]) return y return unitx = ResBlock(32, 16, 0)(x)
我们这样编写代码的原因是为了允许层的重用。也就是说,如果我们像这样调用它
resblock = ResBlock(32, 16, 0)x = resblock(x)x = resblock(x)
resblock
会在两次调用之间共享所有参数。使用您示例中的语法,这将是不可能的。