根据我在this问题中提出的需求,我决定对Conv2D图层进行子类化,以便它首先正确包裹输入张量。
但是我无法使其工作。具体来说,我什至无法进行单元测试,以使用给定的内核初始化该层,然后将给定的输入张量传递给它,并验证.call()
方法中定义的计算是否产生了预期的结果。
因此,我退后一步,为了避免我的代码成为问题,我首先集中精力于如何处理已经存在的Keras父层Conv2D
。
import unittest
from numpy import asarray, arange
import keras.backend as K
from keras.models import Sequential #, Model,
from keras.layers import Conv2D #, Input, MaxPooling2D
from keras.initializers import Constant
from keras.optimizers import SGD
class Test(unittest.TestCase):
def testConv2D(self):
''' verify that I can initialize, invoke, and test a given Keras layer
'''
# kernel to make convolution constant except at borders
kern = asarray([[ 1, 0, -1]]).T + asarray([[ 0.5, 1, 0, -1, -0.5 ]])
print(kern)
kern = Constant(kern)
input_shape = (10, 10, 3)
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
base_model = Sequential()
base_layer = Conv2D(10, (3, 5),
input_shape=input_shape,
kernel_initializer=kern,
use_bias=False)
base_model.add(base_layer)
base_model.compile(loss='mean_squared_error', optimizer=sgd)
x = arange(5 * 10 * 10 * 3).reshape((5, 10, 10, 3)) # 5 samples, 3 channels
x = K.variable(x)
# the print() statements to be replaced by asserts of course
y = base_layer(x)
print(y) # this just prints Tensor("conv2d_1_1/convolution:0", shape=(5, 8, 6, 10), dtype=float32)
yp = base_model.predict(x) # this throws a ValueError about specifying the `steps` argument
print(yp)
pass
# once this works I'll replace Conv2D with a subclass of it, and
# verify that I can preprocess the input tensor; and will be able
# to verify that the convolution gives the right result
pass
# once also this works, I'll replace partial tests with a single test that verifies only the result
pass
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
unittest.main()
尝试执行此操作,表明我什至无法在给定数据上调用现有的Keras层。我不知道如何做得更好(也许我最好使用功能性API?)
我怀疑我完全迷路了。如果有一些示例或链接可以启发我,或者有任何关于正确执行上述操作方法的提示,我将不胜感激。
PS。我还检查了这些问题,这些问题为如何实现所需的内容提供了一些启示,但实际上我专注于如何测试实现的内容:
在其他人指出这一点之前,我找到了一些初步答案,我可以说出我要遵循的方向:
y = base_layer(x)
;不直接适合测试,因为它不会产生任何值(在Functional API中,它只是声明如何转换变量x以获取层的输出)yp = base_model.predict(x)
是正确的,但是x必须是numpy
数组。比任何Keras variable
或Constant
都简单得多(我更认为它是 declarative 对象)keras.initializers.Constant
数组创建的numpy
对象显式初始化内核,只要提供的内核大小合适,就可以正常工作!< / strong>在这种情况下,我想使用[3,5]
内核,但这样做却非常糟糕:如果我们要处理具有C
颜色层的图像,则一个滤镜意味着一个内核[3,5,C]
。最后,由于Conv2D层具有F=10
过滤器,因此正确的内核初始化程序必须来自形状为[3,5,C,F]
的四维数组。请注意,过滤器尺寸是最后一个(不是第一个)。get_weights()
层方法并检查初始化程序的形状是否一致(描述为here)来实现这一点(可以进行特定的检查和警告消息)初始化程序包含显式数组时将其插入Keras代码中,以防止发生此错误。所以现在我知道要去的方向了。我会及时通知您,希望能为您提供完整的答案以及可行的解决方案。