tensorflow - 如何实现超像素池化层?

标签 tensorflow neural-network deep-learning keras theano

我想实现以下论文“Weakly Supervised Semantic Segmentation Using Superpixel Pooling Network”中定义的超像素池化层,最初是在Torch中实现的(实现不可用)。我希望使用 Theano 后端(最好)在 Keras 中进行。

我将举一个小例子来说明该层的作用。它需要以下输入:
feature_map :形状 = (batch_size, height, width, feature_dim)superpixel_map :形状 = (batch_size, height, width)
让我们假设两个小矩阵 batch_size = 1, height = width = 2, feature_dim = 1

feature_map = np.array([[[[ 0.1], [ 0.2 ]], [[ 0.3], [ 0.4]]]])  
superpixel_map = np.array([[[ 0,  0], [ 1,  2]]])

现在,输出的形状为 = (batch_size, n_superpixels, feature_dim) .这里n_superpixels基本上是 = np.amax(superpixel_map) + 1 .

输出计算如下。

找到 superpixel_map == i 所在的位置,其中 i不一样 0n_superpixels - 1 .让我们考虑 i = 0 . i = 0的职位是 (0, 0, 0)(0, 0, 1)
现在平均特征图中这些位置的元素。这给了我们值 (0.1 + 0.2) / 2 = 0.15 .为 i = 1 执行此操作和 i = 2 ,这给了我们值 0.30.4分别。

现在,问题变得复杂,因为通常 batch_size > 1height, width >> 1 .

我在 Keras 中实现了一个新层,它基本上可以做到这一点,但我使用了循环。现在,如果 height = width = 32 . Theano 给出了最大递归深度误差。任何人都知道如何解决这个问题?如果 TensorFlow 提供了一些新的东西,那么我也准备切换到 TensorFlow 后端。

我的新层的代码如下:

class SuperpixelPooling(Layer):
    def __init__(self, n_superpixels=None, n_features=None, batch_size=None, 
                 input_shapes=None, **kwargs):
        super(SuperpixelPooling, self).__init__(**kwargs)
        self.n_superpixels = n_superpixels
        self.n_features = n_features
        self.batch_size = batch_size
        self.input_shapes = input_shapes  # has to be a length-2 tuple, First tuple has the
                                          # shape of feature map and the next tuple has the
                                          # length of superpixel map. Shapes are of the
                                          # form (height, width, feature_dim)
    def compute_output_shape(self, input_shapes):
        return (input_shapes[0][0],
                    self.n_superpixels,
                    self.n_features)
    def call(self, inputs):
        # x = feature map
        # y = superpixel map, index from [0, n-1]
        x = inputs[0]  # batch_size x m x n x k
        y = inputs[1]  # batch_size x m x n
        ht = self.input_shapes[0][0]
        wd = self.input_shapes[0][1]
        z = K.zeros(shape=(self.batch_size, self.n_superpixels, self.n_features), 
                    dtype=float)
        count = K.zeros(shape=(self.batch_size, self.n_superpixels, self.n_features), 
                        dtype=int)
        for b in range(self.batch_size):
            for i in range(ht):
                for j in range(wd):
                    z = T.inc_subtensor(z[b, y[b, i, j], :], x[b, i, j, :])
                    count = T.inc_subtensor(count[b, y[b, i, j], :], 1)
        z /= count   
        return z

我认为递归深度超出问题是由于我使用了嵌套的 for 循环。我没有看到避免这些循环的方法。如果有人有任何建议,请告诉我。

交叉发布 here .如果我在那里得到任何答案,我会更新这篇文章。

最佳答案

我在 my GitHub 上有我的初始实现。它仍然没有准备好使用。请阅读以获得更多详情。为了完整起见,我将在此处发布实现及其简要说明(主要来自自述文件)。

class SuperpixelPooling(Layer):
    def __init__(self, n_superpixels=None, n_features=None, batch_size=None, input_shapes=None, positions=None, superpixel_positions=None, superpixel_hist=None, **kwargs):
        super(SuperpixelPooling, self).__init__(**kwargs)

        # self.input_spec = InputSpec(ndim=4)
        self.n_superpixels = n_superpixels
        self.n_features = n_features
        self.batch_size = batch_size
        self.input_shapes = input_shapes  # has to be a length-2 tuple, First tuple has shape of feature map and the next tuple has 
                                          # length of superpixel map. Shapes are of the form (height, width, feature_dim)
        self.positions = positions  # has three columns
        self.superpixel_positions = superpixel_positions  # has two columns
        self.superpixel_hist = superpixel_hist  # is a vector
    def compute_output_shape(self, input_shapes):
        return (self.batch_size, self.n_superpixels, self.n_features)
    def call(self, inputs):
        # x = feature map
        # y = superpixel map, index from [0, n-1]
        x = inputs[0]  # batch_size x k x m x n
        y = inputs[1]  # batch_size x m x n
        ht = self.input_shapes[0][0]
        wd = self.input_shapes[0][1]
        z = K.zeros(shape=(self.batch_size, self.n_superpixels, self.n_features), dtype=float)
        z = T.inc_subtensor(z[self.superpixel_positions[:, 0], self.superpixel_positions[:, 1], :], x[self.positions[:, 0], :, self.positions[:, 1], self.positions[:, 2]])
        z /= self.superpixel_hist
        return z

解释:

在 Keras 中实现超像素池化层。参见 keras.layers.pooling 实现。

超像素池化层的概念可以在论文:“Weakly Supervised Semantic Segmentation Using Superpixel Pooling Network”,AAAI 2017 中找到。该层有两个输入,一个超像素图(大小 M x N)和一个特征图(大小 K x M x N)。它汇集了属于同一超像素的特征(在这个实现中,平均池)并形成一个 1 x K 向量,其中 K 是特征图深度/ channel 。

一个简单的实现将需要三个 for 循环:一个迭代批处理,另一个迭代行,最后一个迭代特征图的列并即时池化。但是,每当您尝试编译包含该层的模型时,都会在 Theano 中出现“超出最大递归深度”错误。即使特征图宽度和高度只有 32 时也会出现此错误。

为了克服这个问题,我认为将所有东西作为参数传递给这一层至少会摆脱两个 for 循环。最终,我能够创建一个单行代码来实现整个平均池化操作的核心。你需要通过:
  • 图像中的超像素数
  • 特征图深度/ channel
  • 批次大小
  • 特征图和超像素图的形状
  • 一个 N x 3 矩阵,其中包含与 (batch_size, row, column) 对应的所有可能的索引组合,称为 positions 。如果您的输入图像大小和批量大小保持不变,则只需在训练期间生成一次。
  • 一个名为 N x 2superpixel_positions 矩阵。第 i 行包含与矩阵 i 的第 positions 行中的索引对应的超像素索引。例如,如果矩阵 i 的第 positions 行包含 (12, 10, 20) ,那么同一行超像素位置将包含 (12, sp_i) ,其中 sp_i = superpixel_map[12, 10, 20]
  • 一个 N x S 矩阵 - superpixel_hist - 其中 S 是该图像中超像素的数量。顾名思义,这个矩阵保留了当前图像中存在的超像素的直方图。

  • 这种实现的缺点是这些参数必须针对每个图像进行更改(特别是第 6 点和第 7 点中提到的参数)。当 GPU 一次处理整个批次时,这是不切实际的。我认为这可以通过将所有这些参数作为输入传递给外部层来解决。基本上,它们可以从(比如)HDF5 文件中读取。我打算很快做到这一点。完成后我会更新这个。

    关于tensorflow - 如何实现超像素池化层?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43905784/

    相关文章:

    python - 在 Keras 中将多个输入样本映射到单个输出样本

    machine-learning - 为什么神经网络中权重向量与决策平面正交

    machine-learning - 回到 XOR 问题的基础 - 从根本上感到困惑

    tensorflow - YOLO 物体检测 : how does the algorithm predict bounding boxes larger than a grid cell?

    machine-learning - 在 Keras 中使用 LSTM 将一系列向量映射到单个向量

    python - 如何从 COCO 数据集创建蒙版图像?

    python - 如何在 TensorFlow 2.0 中控制冗长

    python - Tensorflow、大图像推理——内存不够

    machine-learning - 为什么门控激活函数(在 Wavenet 中使用)比 ReLU 效果更好?

    machine-learning - 使用 PyTorch 预测网格坐标序列