【问题标题】:Implementing LeCun Local Contrast Normalization with Theano使用 Theano 实现 LeCun 局部对比度归一化
【发布时间】:2016-02-08 06:05:46
【问题描述】:

我正在尝试使用我发现的代码来实现 LeCun 局部对比度标准化,但我得到了不正确的结果。代码在 Python 中并使用 theano 库。

def lecun_lcn(input, img_shape, kernel_shape, threshold=1e-4):
    """
    Yann LeCun's local contrast normalization
    Orginal code in Theano by: Guillaume Desjardins
    """
    input = input.reshape(input.shape[0], 1, img_shape[0], img_shape[1])
    X = T.matrix(dtype=theano.config.floatX)
    X = X.reshape(input.shape)

    filter_shape = (1, 1, kernel_shape, kernel_shape)
    filters = gaussian_filter(kernel_shape).reshape(filter_shape)

    convout = conv.conv2d(input=X,
                             filters=filters,
                             image_shape=(input.shape[0], 1, img_shape[0], img_shape[1]),
                             filter_shape=filter_shape,
                             border_mode='full')

    # For each pixel, remove mean of 9x9 neighborhood

    mid = int(np.floor(kernel_shape / 2.))
    centered_X = X - convout[:, :, mid:-mid, mid:-mid]
    # Scale down norm of 9x9 patch if norm is bigger than 1
    sum_sqr_XX = conv.conv2d(input=centered_X ** 2,
                             filters=filters,
                             image_shape=(input.shape[0], 1, img_shape[0], img_shape[1]),
                             filter_shape=filter_shape,
                             border_mode='full')

    denom = T.sqrt(sum_sqr_XX[:, :, mid:-mid, mid:-mid])
    per_img_mean = denom.mean(axis=[1, 2])
    divisor = T.largest(per_img_mean.dimshuffle(0, 'x', 'x', 1), denom)
    divisor = T.maximum(divisor, threshold)

    new_X = centered_X / divisor
    new_X = new_X.dimshuffle(0, 2, 3, 1)
    new_X = new_X.flatten(ndim=3)

    f = theano.function([X], new_X)
    return f(input)

这里是测试代码:

x_img_origin = plt.imread("..//data//Lenna.png")
x_img = plt.imread("..//data//Lenna.png")
x_img_real_result = plt.imread("..//data//Lenna_Processed.png")

x_img = x_img.reshape(1, x_img.shape[0], x_img.shape[1], x_img.shape[2])
for d in range(3):
    x_img[:, :, :, d] = tools.lecun_lcn(x_img[:, :, :, d], (x_img.shape[1], x_img.shape[2]), 9)
x_img = x_img[0]

pylab.subplot(1, 3, 1); pylab.axis('off'); pylab.imshow(x_img_origin)
pylab.gray()
pylab.subplot(1, 3, 2); pylab.axis('off'); pylab.imshow(x_img)
pylab.subplot(1, 3, 3); pylab.axis('off'); pylab.imshow(x_img_real_result)
pylab.show()

结果如下:

(从左到右:原点、我的结果、预期的结果)

谁能告诉我我的代码做错了什么?

【问题讨论】:

  • 我曾经做过类似的事情,但不幸的是无法运行您的代码,因为它不是独立的。你能让它可运行,从而可调试吗?除其他事项外,您还需要指定您使用的高斯滤波器函数。
  • 您好eickenberg,这是代码,请根据需要更改图像路径。 pastebin.com/x6WREp7D 这是图片:upload.wikimedia.org/wikipedia/en/2/24/Lenna.png 如果您还需要什么,请告诉我。我认为门槛是罪魁祸首。如果我增加阈值,它会变得更类似于预期的结果。

标签: python machine-learning theano


【解决方案1】:

这是我在 Jarrett 等人 (http://yann.lecun.com/exdb/publis/pdf/jarrett-iccv-09.pdf) 中报告的实现局部对比度归一化的方法。您可以将其用作单独的图层。

我在 theano 的 LeNet 教程中的代码上对其进行了测试,其中我将 LCN 应用于输入和每个卷积层,从而产生了更好的结果。

您可以在此处找到完整的代码: https://github.com/jostosh/theano_utils/blob/master/lcn.py

class LecunLCN(object):
def __init__(self, X, image_shape, threshold=1e-4, radius=9, use_divisor=True):
    """
    Allocate an LCN.

    :type X: theano.tensor.dtensor4
    :param X: symbolic image tensor, of shape image_shape

    :type image_shape: tuple or list of length 4
    :param image_shape: (batch size, num input feature maps,
                         image height, image width)
    :type threshold: double
    :param threshold: the threshold will be used to avoid division by zeros

    :type radius: int
    :param radius: determines size of Gaussian filter patch (default 9x9)

    :type use_divisor: Boolean
    :param use_divisor: whether or not to apply divisive normalization
    """

    # Get Gaussian filter
    filter_shape = (1, image_shape[1], radius, radius)

    self.filters = theano.shared(self.gaussian_filter(filter_shape), borrow=True)

    # Compute the Guassian weighted average by means of convolution
    convout = conv.conv2d(
        input=X,
        filters=self.filters,
        image_shape=image_shape,
        filter_shape=filter_shape,
        border_mode='full'
    )

    # Subtractive step
    mid = int(numpy.floor(filter_shape[2] / 2.))

    # Make filter dimension broadcastable and subtract
    centered_X = X - T.addbroadcast(convout[:, :, mid:-mid, mid:-mid], 1)

    # Boolean marks whether or not to perform divisive step
    if use_divisor:
        # Note that the local variances can be computed by using the centered_X
        # tensor. If we convolve this with the mean filter, that should give us
        # the variance at each point. We simply take the square root to get our
        # denominator

        # Compute variances
        sum_sqr_XX = conv.conv2d(
            input=T.sqr(centered_X),
            filters=self.filters,
            image_shape=image_shape,
            filter_shape=filter_shape,
            border_mode='full'
        )


        # Take square root to get local standard deviation
        denom = T.sqrt(sum_sqr_XX[:,:,mid:-mid,mid:-mid])

        per_img_mean = denom.mean(axis=[2,3])
        divisor = T.largest(per_img_mean.dimshuffle(0, 1, 'x', 'x'), denom)
        # Divisise step
        new_X = centered_X / T.maximum(T.addbroadcast(divisor, 1), threshold)
    else:
        new_X = centered_X

    self.output = new_X


def gaussian_filter(self, kernel_shape):
    x = numpy.zeros(kernel_shape, dtype=theano.config.floatX)

    def gauss(x, y, sigma=2.0):
        Z = 2 * numpy.pi * sigma ** 2
        return  1. / Z * numpy.exp(-(x ** 2 + y ** 2) / (2. * sigma ** 2))

    mid = numpy.floor(kernel_shape[-1] / 2.)
    for kernel_idx in xrange(0, kernel_shape[1]):
        for i in xrange(0, kernel_shape[2]):
            for j in xrange(0, kernel_shape[3]):
                x[0, kernel_idx, i, j] = gauss(i - mid, j - mid)

    return x / numpy.sum(x)

【讨论】:

  • 如果您还添加了如何调用该函数的示例,那将非常酷。我对这些方法很陌生,调用 LecunLCN 得到的结果是Elemwise{true_div, no_inplace}.0,我不知道它是否正确以及如何从中提取图像。
  • 对于像我这样对theano一无所知的人,函数的输出是一个尚未通过评估对象编译的对象。因此,如果你想提取卷积图像,你必须写LecunLCN(X).output.eval()[0][0]
【解决方案2】:

我认为这两行可能在矩阵轴上有一些错误:

per_img_mean = denom.mean(axis=[1, 2])
divisor = T.largest(per_img_mean.dimshuffle(0, 'x', 'x', 1), denom)

应该改写为:

per_img_mean = denom.mean(axis=[2, 3])
divisor = T.largest(per_img_mean.dimshuffle(0, 1, 'x', 'x'), denom)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    • 2022-11-05
    • 2013-01-30
    • 1970-01-01
    • 2015-01-22
    • 2013-01-02
    • 2015-07-01
    相关资源
    最近更新 更多