在 Tensorflow 中实现 ConvND

Implement ConvND in Tensorflow

所以我需要一个同样支持复数的ND卷积层。所以我决定自己编码。

我单独在 numpy 上测试了这段代码并且它有效。测试了多个通道,2D 和 1D 以及复杂的。但是,我在TF上做的时候遇到了问题。

到目前为止,这是我的代码:

def call(self, inputs):
    with tf.name_scope("ComplexConvolution_" + str(self.layer_number)) as scope:
        inputs = self._verify_inputs(inputs)            # Check inputs are of expected shape and format
        inputs = self.apply_padding(inputs)             # Add zeros if needed
        output_np = np.zeros(                           # I use np because tf does not support the assigment
            (inputs.shape[0],) +                        # Per each image
            self.output_size,                           # Image out size
            dtype=self.input_dtype                      # To support complex numbers
        )
        img_index = 0
        for image in inputs:
            for filter_index in range(self.filters):
                for i in range(int(np.prod(self.output_size[:-1]))):  # for each element in the output
                    index = np.unravel_index(i, self.output_size[:-1])
                    start_index = tuple([a * b for a, b in zip(index, self.stride_shape)])
                    end_index = tuple([a+b for a, b in zip(start_index, self.kernel_shape)])
                    # set_trace()
                    sector_slice = tuple(
                        [slice(start_index[ind], end_index[ind]) for ind in range(len(start_index))]
                    )
                    sector = image[sector_slice]
                    new_value = tf.reduce_sum(sector * self.kernels[filter_index]) + self.bias[filter_index]
                    # I use Tied Bias https://datascience.stackexchange.com/a/37748/75968
                    output_np[img_index][index][filter_index] = new_value  # The complicated line
                    img_index += 1
        output = apply_activation(self.activation, output_np)
    return output

input_size 是一个形状元组 (dim1, dim2, ..., dim3, channels)。例如,2D rgb conv 将是 (32, 32, 3) 并且 inputs 将具有形状 (None, 32, 32, 3).

输出大小是根据我在本文中找到的公式计算得出的:A guide to convolution arithmetic for deep learning

out_list = []
for i in range(len(self.input_size) - 1):   # -1 because the number of input channels is irrelevant
    out_list.append(int(np.floor((self.input_size[i] + 2 * self.padding_shape[i] - self.kernel_shape[i]) / self.stride_shape[i]) + 1))
out_list.append(self.filters)

基本上,我使用 np.zeros 因为如果我使用 tf.zeros 我无法分配 new_value 我得到: TypeError: 'Tensor' object does not support item assignment

但是,在当前状态下,我得到:
NotImplementedError: Cannot convert a symbolic Tensor (placeholder_1:0) to a numpy array.

在同一个任务上。我没有看到一个简单的修复方法,我想我应该完全改变代码的策略。

最后,我基于这个 comment, also commented here 以一种非常低效的方式完成了它,但至少它有效:

new_value = tf.reduce_sum(sector * self.kernels[filter_index]) + self.bias[filter_index]
indices = (img_index,) + index + (filter_index,)
mask = tf.Variable(tf.fill(output_np.shape, 1))
mask = mask[indices].assign(0)
mask = tf.cast(mask, dtype=self.input_dtype)
output_np = array * mask + (1 - mask) * new_value

我说效率低下是因为我为每个作业创建了一个全新的数组。我的代码目前需要很长时间才能计算,所以我会继续寻求改进,如果我得到更好的东西,post 会在这里。