Python tf.nn.conv2d和keras.layers.conv2d的输出不相等

Python tf.nn.conv2d和keras.layers.conv2d的输出不相等,python,function,tensorflow,keras,equivalent,Python,Function,Tensorflow,Keras,Equivalent,我一直在读Aurélien Géron()的机器学习手册(第二版)。我已经进入了将CNN应用于图像的内容。在题为第14章Tensorflow实现的部分中,他们手动创建过滤器,将其传递给tf.nn.conv2d,并应用于图像以生成一组特征图。在这些手动过滤器示例之后,本书说: 在真实的CNN中,您通常会将过滤器定义为可训练变量。。。不要手动创建变量,而是使用keras.layers.Conv2D层 上面的引文对我来说意味着,给定相同的输入(和等效的初始化),我们应该能够从tf.nn.conv2d和

我一直在读Aurélien Géron()的机器学习手册(第二版)。我已经进入了将CNN应用于图像的内容。在题为第14章Tensorflow实现的部分中,他们手动创建过滤器,将其传递给
tf.nn.conv2d
,并应用于图像以生成一组特征图。在这些手动过滤器示例之后,本书说:

在真实的CNN中,您通常会将过滤器定义为可训练变量。。。不要手动创建变量,而是使用
keras.layers.Conv2D

上面的引文对我来说意味着,给定相同的输入(和等效的初始化),我们应该能够从
tf.nn.conv2d
keras.layers.conv2d
导出相同的输出。为了验证这个想法,我查看了这两个函数是否相等。根据卷积的,这两个函数是相同的

WARNING:tensorflow:Layer conv2d is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because it's dtype defaults to floatx.
tf.keras.backend.set_floatx('float64')
我开始对它们的等价性进行一个简单的测试。我创建了一个卷积层,它由一个特征映射组成,使用全零的7x7过滤器(也称为卷积内核),分别为
tf.nn.conv2d
keras.layers.conv2d
实现。正如预期的那样,在对两幅图像的差值中的所有像素值求和之后,该过滤器确实使输出图像的每个像素值的值为零。此差值为零表示输出图像相同

然后我决定创建相同的7x7过滤器,但这次使用所有过滤器。理想情况下,两个函数应产生相同的输出,因此两个输出图像中的差异应为零。不幸的是,当我检查输出图像中的差异(并对每个像素的差异求和)时,我得到了一个非零和值。在绘制图像及其差异时,很明显,它们不是相同的图像(尽管它们看起来非常相似)

在阅读了这两个函数的文档之后,我相信我给了它们等价的输入我会做什么/错误地假设这会阻止两个函数产生相同的输出?

我在下面附上了我的代码和版本信息以供参考。代码使用scikit学习
china.jpg
示例图像作为输入,并使用
matplotlib.pyplot.imshow
帮助可视化输出图像及其差异

TF版本:2.2.0-dev20200229

Keras版本:2.3.1

Scikit学习版本:0.22.1

Matplotlib版本:3.1.3

Numpy版本:1.18.1

从sklearn.dataset导入加载样本图像
将matplotlib.pyplot作为plt导入
导入tensorflow作为tf
从tensorflow进口keras
将numpy作为np导入
#作为tf.nn.conv2d的结果获取特征映射
def featureMap1(批次):
#提取通道
批次尺寸、高度、宽度、通道=批次形状
#制作一套(7,7,3,1)滤波器组(每个通道一套7x7滤波器)
#只有一个。
filters=np.one(shape=(7,7,channels,1),dtype=np.float32)
#以1的步幅运行conv2d(即:in.shape=out.shape)
#为此conv图层生成一个要素地图
fmaps=tf.nn.conv2d(批次、过滤器、,
步幅=1,padding='SAME',
数据(格式为“NHWC”)
#返回要素图
返回FMAP
#作为keras.layers.Conv2D的结果获取要素地图
def featureMap2(批次):
#使用图像的形状创建输入层
inputLayer=keras.layers.Input(shape=batch.shape[1:])
#创建convLayer,该层应应用所有过滤器
convLayer=keras.layers.Conv2D(过滤器=1,内核大小=7,
步幅=1,padding='SAME',
kernel_初始值设定项='ones',
数据\u格式='channels\u last',
激活(线性)
#创建输出层
outputLayer=convLayer(inputLayer)
#建立模型
模型=keras.model(输入=输入层,
输出=输出层)
#执行预测,不进行模型拟合或编译
fmaps=模型预测(批次)
返回FMAP
def main():
#获取图像并将RGB值缩放为[0,1]
china=load\u sample\u image('china.jpg')/255
#只构建一个映像的批处理
batch=np.array([中国])
#获取特征映射并提取
#其中的图像
img1=featureMap1(批处理)[0,:,:,0]
img2=featureMap2(批处理)[0,:,:,0]
#计算图像中的差异
#理想情况下,这应该是全零。。。
diffImage=np.abs(img1-img2)
#将diffImage中的所有像素相加,
#如果图像为空,我们期望值为0
#相同的
打印('差异值:',diffImage.sum())
#将图像绘制为一组4
figsize=10
f、 axarr=plt.子批次(2,2,figsize=(figsize,figsize))
axarr[0,0]。设置标题(“原始图像”)
axarr[0,0]。imshow(批次[0],cmap='gray')
axarr[1,0]。设置标题('Conv2D到tf.nn.Conv2D')
axarr[1,0].imshow(img1,cmap='gray')
axarr[1,1]。设置标题('Conv2D到keras.layers.Conv2D')
axarr[1,1].imshow(img2,cmap='gray')
axarr[0,1]。设置标题('Diff'))
axarr[0,1]。imshow(diffImage,cmap='gray')
plt.show()
返回
main()

两个卷积层的输出应该相同

您正在将模型操作进行比较,而您应该将操作(tf.keras.Conv2D)与操作(tf.nn.Conv2D)进行比较

修改了功能映射2函数

def featureMap2(batch):
    # Create the convLayer which should apply the filter of all ones
    convLayer = keras.layers.Conv2D(filters=1, kernel_size = 7,
                                    strides=1, padding='SAME',
                                    kernel_initializer='ones',
                                    data_format='channels_last',
                                    activation='linear')
    fmaps = convLayer(batch)
    return fmaps
以下是生成的图

下面是在Google Colab环境中执行的完整修改代码段
tf.keras.backend.set_floatx('float64')