我希望在TensorFlow中实现类似于2D卷积的操作。根据我的理解,实现卷积的最常用方法是首先对图像应用im2col
操作(参见here - 子部分“实现为矩阵乘法”) - 将图像转换为2D矩阵的操作,其中内核作为扁平列应用于图像的各个“块”。
换句话说,上述链接资源的摘录解释了im2col
做得很好:
[...]例如,如果输入是[227x227x3] (格式为高x宽x n_channels)并且要在步幅4处与11x11x3滤波器进行卷积,那么我们将输入中的[11x11x3]像素块取出并将每个块拉伸为大小为11 * 11 * 3 = 363的列向量。在输入处以4的步长迭代此过程给出(227-11)/ 4 + 1 =沿宽度和高度的55个位置,导致
X_col
的输出矩阵im2col
大小为[363 x 3025],其中每列都是伸出的感受野,并且有55 * 55 = 3025的他们总共。请注意,由于感知字段重叠,因此输入卷中的每个数字都可能在多个不同的列中重复。
据我所知TensorFlow docs,这也是tf.nn.conv2d
内部所做的事情。
现在,我想在TensorFlow中单独实现所述im2col
操作(因为我希望能够访问此中间结果)。由于这涉及以非平凡的方式复制值,我将如何为此操作自己构建相对有效的计算图?同样,如何实现反向操作?
答案 0 :(得分:4)
您可以使用extract_image_patches
轻松完成此操作。
此函数将图像的每个filter_size x filter_size
补丁放入深度,产生[batch_size, height, width, 9]
张量。
要与tf.nn.conv2d
进行比较,您可以为图像实施Sobel算子
import tensorflow as tf
import numpy as np
image = np.arange(10 * 10 * 1).reshape(1, 10, 10, 1)
images = tf.convert_to_tensor(image.astype(np.float32))
filter_size = 3
sobel_x = tf.constant([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], tf.float32)
sobel_x_filter = tf.reshape(sobel_x, [3, 3, 1, 1])
image_patches = tf.extract_image_patches(images,
[1, filter_size, filter_size, 1],
[1, 1, 1, 1], [1, 1, 1, 1],
padding='SAME')
actual = tf.reduce_sum(tf.multiply(image_patches, tf.reshape(sobel_x_filter, [9])), 3, keep_dims=True)
expected = tf.nn.conv2d(images, sobel_x_filter, strides=[1, 1, 1, 1], padding='SAME')
with tf.Session() as sess:
print sess.run(tf.reduce_sum(expected - actual))
这会为您提供0.0
,因为它们是等效的。这不需要反向功能。
修改强>:
正如我从TensorFlow文档中了解到的那样,就是这样做的 内部也有tf.nn.conv2d。
不,不是真的。例如,GPU上的TF依赖于CuDNN,这是complex beast(winograd,ptx,...)。只有在某些情况下,它才会在CPU上使用im2col
方法here和量化版本here。