Lucidnonsense
Lucidnonsense

Reputation: 1243

How to reproduce scipy.convolve with theano

I've read the previous responses regarding the theano conv1d problem but I can't seem to make it work:

x = np.arange(50) * 1.
y = np.random.normal((x+0.1)/5, 1, 50)

def tophat(x, centre, width, amplitude):
    return tt.switch((x < centre + (width/2)) & (x >= centre - (width/2)), np.float64(amplitude) / width,  np.float64(0.))

import theano.tensor.signal.conv
def theano_convolve(x, y, filt_range, centre, width, amplitude):
    a = tt.matrix('a', dtype='float64')
    b = tt.matrix('b', dtype='float64')

    filt = tophat(b, centre, width, amplitude)

    func = tt.signal.conv.conv2d(a, filt, (1, y.shape[0]), (1, filt_range.shape[0]), border_mode='full') / filt.sum()

    return theano.function([a, b], func)(y[None, :], filt_range[None, :])

from scipy.signal import convolve

def scipy_convolve(x, y, filt_range, centre, width, amplitude):
    a = tt.vector('a')
    filt = theano.function([a], tophat(a, centre, width, amplitude))(filt_range)
    return convolve(y, filt, mode='same') / sum(filt)

convolved_theano = theano_convolve(x, y, np.linspace(-10, 10, len(x)), 0, 3, 1)

convolved_scipy = scipy_convolve(x, y, np.linspace(-10, 10, len(x)), 0, 3, 1)

plt.plot(x, y, '.', label='data')
plt.plot(r[0], label='theano')
plt.plot(convolved_scipy, label='scipy');
plt.legend();

enter image description here

This results in a zero-padded convolution with theano. I could just strip out the zeroes but I'd rather know what is going on!

How do you convolve a tophat function with some data (1-dimensional) in theano?

Thanks

Upvotes: 1

Views: 229

Answers (1)

Makis Tsantekidis
Makis Tsantekidis

Reputation: 2738

The behavior you see is caused by the different mode you use for the two convolutions.

In the scipy.signal.convolve you use mode='same' while in the theano.tensor.signal.conv.conv2d you use mode='full'.

Changing the scipy.signal.convolve to use mode='full' yields the exact same vector. For the image I added .1 to the theano vector to make the line visible and not overlap with the sicpy.convolve one.

import numpy as np
import theano.tensor as tt
import seaborn as sns

plt = sns.plt

x = np.arange(50) * 1.
y = np.random.normal((x+0.1)/5, 1, 50)

def tophat(x, centre, width, amplitude):
    return tt.switch((x < centre + (width/2)) & (x >= centre - (width/2)), np.float64(amplitude) / width,  np.float64(0.))

import theano.tensor.signal.conv
def theano_convolve(x, y, filt_range, centre, width, amplitude):
    a = tt.matrix('a', dtype='float64')
    b = tt.matrix('b', dtype='float64')

    filt = tophat(b, centre, width, amplitude)

    func = tt.signal.conv.conv2d(a, filt, (1, y.shape[0]), (1, filt_range.shape[0]), border_mode='full') / filt.sum()

    return theano.function([a, b], func)(y[None, :], filt_range[None, :])

from scipy.signal import convolve

def scipy_convolve(x, y, filt_range, centre, width, amplitude):
    a = tt.vector('a')
    filt = theano.function([a], tophat(a, centre, width, amplitude))(filt_range)
    return convolve(y, filt, mode='full') / sum(filt)

convolved_theano = theano_convolve(x, y, np.linspace(-10, 10, len(x)), 0, 3, 1)

convolved_scipy = scipy_convolve(x, y, np.linspace(-10, 10, len(x)), 0, 3, 1)

plt.plot(x, y, '.', label='data')
plt.plot(convolved_theano[0]+0.1, label='theano')
plt.plot(convolved_scipy, label='scipy')
plt.legend()
plt.show(block=True)

scipy vs theano convolution

Unfortunately looking at the theano documentation conv2d for theano does not support border_mode='same'.

Upvotes: 1

Related Questions