Skip to content
Advertisement

how to perform a backwards correlation/convolution in python

I am trying to perform a backwards correlation (at least that’s what I think it’s called) on 2 matrices to get a resultant matrix.

Note: backwards convolution works too, because I’m applying this to a CNN.

I have the following two matrices:

vals:

[[ 2  1 -3 -4 -4]
 [ 2 -3  3  1  2]
 [ 2  5 -6  6 -2]
 [-5  4  1  5  4]
 [ 0  0  1 -3 -4]]

w0:

[[[0,  1, -1],
  [1, -1,  0],
  [0,  0,  0]],

 [[1,  0,  0],
  [0, -1,  1],
  [1,  0,  1]],

 [[ 1, -1,  0],
  [-1,  0, -1],
  [-1,  0,  1]]]

I essentially want to apply a sliding window, except in this case all the values of w0 are multiplied by the scalar value at each point in vals, then added with adjacent values.

Assuming a stride of 1 and a padding of same (wrt vals), the following code gives the result I want:

concat = np.zeros((3,7,7))
for k in range(len(w0)):
    for i in range(len(vals)):
        for j in range(len(vals[i])):
            v = w0[k] * vals[i][j]
            concat[k][i:i+v.shape[0], j:j+v.shape[1]] += v
print(concat)

Resulting in:

[[[  0.   2.  -1.  -4.  -1.   0.   4.]
  [  2.   1.  -9.   5.  -2.   5.  -2.]
  [  2.  -3.   9. -13.  13. -10.   2.]
  [  2.  -2.  -2.   9.  -4.   1.  -4.]
  [ -5.   9.  -3.   5.  -5.  -5.   4.]
  [  0.   0.   1.  -4.  -1.   4.   0.]
  [  0.   0.   0.   0.   0.   0.   0.]]

 [[  2.   1.  -3.  -4.  -4.   0.   0.]
  [  2.  -5.   4.   5.   3.   0.  -4.]
  [  4.   4.  -2.  -3.  -7.  -5.  -2.]
  [ -3.  -1.   3.  14.  -3.   9.   0.]
  [  2.  10. -12.  11. -16.   7.   2.]
  [ -5.   4.  -4.   8.   9.   6.   0.]
  [  0.   0.   1.  -3.  -3.  -3.  -4.]]

 [[  2.  -1.  -4.  -1.   0.   4.   0.]
  [  0.  -6.   7.   1.   8.   2.   4.]
  [ -2.   5. -11.  19. -12.  -3.  -6.]
  [ -9.   7.   0. -11.   8.  -9.   4.]
  [  3.  -9.  13. -14. -10.   5.  -6.]
  [  5.  -4.  -7.   2.   0.   8.   8.]
  [  0.   0.  -1.   3.   5.  -3.  -4.]]]

Which I would then shrink to exclude the padding, so:

print(concat[:,1:-1, 1:-1])

>>> [[[  1.  -9.   5.  -2.   5.]
      [ -3.   9. -13.  13. -10.]
      [ -2.  -2.   9.  -4.   1.]
      [  9.  -3.   5.  -5.  -5.]
      [  0.   1.  -4.  -1.   4.]]

     [[ -5.   4.   5.   3.   0.]
      [  4.  -2.  -3.  -7.  -5.]
      [ -1.   3.  14.  -3.   9.]
      [ 10. -12.  11. -16.   7.]
      [  4.  -4.   8.   9.   6.]]

     [[ -6.   7.   1.   8.   2.]
      [  5. -11.  19. -12.  -3.]
      [  7.   0. -11.   8.  -9.]
      [ -9.  13. -14. -10.   5.]
      [ -4.  -7.   2.   0.   8.]]]

Either of the two results for concat would be fine, but preferably the one that includes the padding.

Does anyone know of a way to do this without using python loops? I’d prefer to use numpy or some other library as it is bound to perform the same calculation faster than my code.

EDIT:

I also want to perform the same kind of backward correlation on w0, so using vals again but instead using:

a:

[[[2, 0, 2, 2, 2],
  [1, 1, 0, 2, 0],
  [0, 0, 1, 2, 2],
  [2, 2, 2, 0, 0],
  [1, 0, 1, 2, 0]],

 [[1, 2, 1, 0, 1],
  [0, 2, 0, 0, 1],
  [0, 0, 2, 2, 1],
  [2, 0, 1, 0, 2],
  [0, 1, 2, 2, 2]],

 [[0, 0, 2, 2, 2],
  [0, 1, 2, 1, 0],
  [0, 0, 0, 2, 0],
  [0, 2, 0, 0, 2],
  [0, 0, 2, 2, 1]]]

And in this case taking a 3×3 sliding window along a with a padding of 1, and multiply all values in the sliding window by the associated index of the scalar value in vals, and finally getting an output the same size as w0. The following code achieves this:

concat = np.zeros((3,3,3))
for k in range(len(w0)):
    f = np.pad(a[k], 1)
    for i in range(len(vals)):
        for j in range(len(vals[i])):
            v = f[i:i+w0.shape[1], j:j+w0.shape[2]] * vals[i][j]
            concat[k] += v

with:

print(concat)
>>>[[[  4.  56.   8.]
     [  1. -20.   1.]
     [ 22.  12.  21.]]

    [[  7.  18.  21.]
     [  5. -22.  20.]
     [ 35.  26.  33.]]

    [[ 20.  13.   4.]
     [-25.   2. -26.]
     [ -5.  15.  38.]]]

Advertisement

Answer

scipy.signal‘s convolve is actually what you want:

from scipy.signal import convolve

convolve(vals[None, :, :], w0)[:, 1:-1, 1:-1]
Out[]: 
array([[[  1,  -9,   5,  -2,   5],
        [ -3,   9, -13,  13, -10],
        [ -2,  -2,   9,  -4,   1],
        [  9,  -3,   5,  -5,  -5],
        [  0,   1,  -4,  -1,   4]],

       [[ -5,   4,   5,   3,   0],
        [  4,  -2,  -3,  -7,  -5],
        [ -1,   3,  14,  -3,   9],
        [ 10, -12,  11, -16,   7],
        [  4,  -4,   8,   9,   6]],

       [[ -6,   7,   1,   8,   2],
        [  5, -11,  19, -12,  -3],
        [  7,   0, -11,   8,  -9],
        [ -9,  13, -14, -10,   5],
        [ -4,  -7,   2,   0,   8]]])
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement