def DynamicConvFilter(inputs, filters, out_channel,
                      kernel_shape,
                      stride=1,
                      padding='SAME'):
    """ see "Dynamic Filter Networks" (NIPS 2016)
        by Bert De Brabandere*, Xu Jia*, Tinne Tuytelaars and Luc Van Gool

    Remarks:
        This is the convolution version of a dynamic filter.

    Args:
        inputs : unfiltered input [b, h, w, 1] only grayscale images.
        filters : learned filters of [b, k, k, 1] (dynamically generated by the network).
        out_channel (int): number of output channel.
        kernel_shape: (h, w) tuple or a int.
        stride: (h, w) tuple or a int.
        padding (str): 'valid' or 'same'. Case insensitive.

    Returns
        tf.Tensor named ``output``.
    """

    # tf.unstack only works with known batch_size :-(
    batch_size, h, w, in_channel = inputs.get_shape().as_list()
    stride = shape4d(stride)

    inputs = tf.unstack(inputs)
    filters = tf.reshape(filters, [batch_size] + shape2d(kernel_shape) + [in_channel, out_channel])
    filters = tf.unstack(filters)

    # this is ok as TF uses the cuda stream context
    rsl = [tf.nn.conv2d(tf.reshape(d, [1, h, w, in_channel]),
                        tf.reshape(k, [kernel_shape, kernel_shape, in_channel, out_channel]),
                        stride, padding="SAME") for d, k in zip(inputs, filters)]
    rsl = tf.concat(rsl, axis=0, name='output')
    return rsl