4

我正在尝试在本文中重新创建 char 级 CNN,但在需要创建 k-max 池化层的最后一步有点卡住,因为我使用的是 MXNet,但它没有这个。

一个重要的区别还在于引入了多个时间 k-max 池化层。这允许检测句子中最重要的 k 个特征,独立于它们的特定位置,保持它们的相对顺序。

然而,MXNet 确实有能力添加一个新的操作,我一直在尝试这样做(尽管对数据的形状、给定的过滤器和批量大小有点困惑)。

传入数据的形状:

128 (min-batch) x 512 (number of filters) x 1 (height) x 125 (width)

出来的数据的形状(k-max pooling,k = 7):

128 (min-batch) x 512 (number of filters) x 1 (height)  x 7 (width)

到目前为止我的想法......:

class KMaxPooling(mx.operator.CustomOp):
    def forward(self, is_train, req, in_data, out_data, aux):
        # Desired (k=3):
        # in_data = np.array([1, 2, 4, 10, 5, 3])
        # out_data = [4, 10, 5]
        x = in_data[0].asnumpy()
        idx = x.argsort()[-k:]
        idx.sort(axis=0)
        y = x[idx]

但是,我不确定几件事:

  1. 如何测试这是否有效(一旦我有一些完整的代码)
  2. 尺寸应该是多少?我正在对最后一个维度进行排序(轴 = 0)
  3. 对backward()函数做什么,即梯度传播
  4. 这是否适用于 GPU - 我猜我将不得不用 C/cuda 重写它?

我为 keras 的其他人找到了这个示例(但没有代表链接):

import numpy as np
import theano.tensor as T
from keras.layers.core import MaskedLayer

class KMaxPooling(MaskedLayer):
    def __init__(self, pooling_size):
        super(MaskedLayer, self).__init__()
        self.pooling_size = pooling_size
        self.input = T.tensor3()

    def get_output_mask(self, train=False):
        return None

    def get_output(self, train=False):
        data = self.get_input(train)
        mask = self.get_input_mask(train)

        if mask is None:
            mask = T.sum(T.ones_like(data), axis=-1)
        mask = mask.dimshuffle(0, 1, "x")

        masked_data = T.switch(T.eq(mask, 0), -np.inf, data)

        result = masked_data[T.arange(masked_data.shape[0]).dimshuffle(0, "x", "x"),
                             T.sort(T.argsort(masked_data, axis=1)[:, -self.pooling_size:, :], axis=1),
                             T.arange(masked_data.shape[2]).dimshuffle("x", "x", 0)]
4

1 回答 1

2

事实上,到目前为止,Mxnet 中还没有 KMaxPooling 支持,实现它可能会很棘手。但是,如果您决定实施它,我可以想到一些提示来帮助您:

  1. 如果使用 Gluon,则可以将 KMaxPooling 实现为 HybridBlock,然后使用HybridSequential运行它。只要您使用提供的函数作为参数“F”-后端(避免使用 numpy),您就可以在 GPU 上运行您的代码。所以,你不需要做 C++。

  2. 仅使用“F”后端的 HybridBlock 和函数也将解决反向传播的问题。您基本上不需要编写它,因为 Autograd 会为您完成。

  3. 使用 HybridBlock,您可以更轻松地调试代码。你只是不调用 net.hybridize() 方法,你会得到“nd”-backend,它比“sym”-backend 慢,但允许你使用调试器。

  4. 至于尺寸,如果您注意到 Gluon 中有不同版本的 MaxPool 块:MaxPool1D、MaxPool2D、MaxPool3D。您只能为您的案例实施 1 KMaxPool1D。然后,您将堆叠 KMaxPool1D 的输出,就像应用了多个过滤器一样,本质上是将值添加到“z”维度的末尾。

希望有帮助。

于 2018-01-19T23:13:12.013 回答