0

Im writing a project about convolutional neural network's and I need to implement an example of a convolution with a given input which is a 3x4-matrix and a 2x2 kernel. enter image description here

I already have the answer for this equation, which is the picture under.
enter image description here

I have written this code where the output isn't right and I can't figure out what is wrong. Im sorry if this is the wrong format, I hope someone can help!

import numpy as np 

def convolution(I,k): 
    #sikre dig først at de givende matricer er 2-dimensionelle
    assert(I.ndim == 2)
    assert(k.ndim == 2)

    #Find størrelsen af de givende matricer rækker m og søjler n
    I_x = I.shape[1]
    I_y = I.shape[0]
    k_x = k.shape[1]
    k_y = k.shape[0]

    # find herefter størrelsen af rækker og søjler i output-matrixen 
    Output_x = I_x - k_x + 1
    Output_y = I_y - k_y + 1

    #Skab nu en tom output-matrix
    Output = np.zeros((Output_y, Output_x))

    #Find først størrelsen af output matrixen
    for m in range(Output_y): 
        for n in range(Output_x):
            #"Scan" nu kernel-matrixen over input-matrixen og find elementerne i output-matrixen. 
            for i in range(k_y): 
                for j in range(k_x):
                    if (m-i >= 0) and (m-i < I_y) and (n-j >= 0) and (n-j < I_x):
                        Output[m,n] = Output[m,n] + k[i,j]*I[i-m,j-n]

    return Output

if __name__=="__main__": 
    Input_data = np.array([[2,3,6,9],
                           [1,9,5,1],
                           [4,7,8,5]])

    kernel = np.array([[1,2],
                       [3,1]])
    
    print(convolution(Input_data, kernel)) 

Egelund48
  • 11
  • 1
  • First of all the width of the result matrix should be `Output_x = I_x - k_x + 1` (similar for height). – Michael Butscher Mar 23 '23 at 13:25
  • 2
    It's important for you to don't use existing function? – Corralien Mar 23 '23 at 13:29
  • Linear algebra says you can't multiply a 4x4 matrix with a 2x2. Multiplying A*B requires that the number of columns in A must equal the number of rows in B. Your shapes are off. – duffymo Mar 23 '23 at 13:36
  • 1
    @duffymo This is a convolutional-operation, not matrixmultiplication therefore its possible to get a result by convoluting a 3x4 matrix, with a 2x2 kernel because you aren't multiplying matrices – Egelund48 Mar 23 '23 at 13:51
  • @Corralien I would prefer it being used, since I have to solve equation. It is also easier for me to check if the solution is right:) – Egelund48 Mar 23 '23 at 13:53
  • @Egelund48 I think this is what you want: https://towardsdatascience.com/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1#:~:text=The%202D%20convolution%20is%20a,into%20a%20single%20output%20pixel. – duffymo Mar 23 '23 at 13:59
  • @duffymo Thank you very much for the link. Im trying to show how convolution from different pixels is calculated, which is also what the link talks about. However im trying to show the calculations through program. Do you maybe a solution for the code? – Egelund48 Mar 23 '23 at 14:09
  • I'm debugging you code now. You are off on Output_x - should be 3, but you calculate 5 - and Output_y - should should be 2, but you calculate 4. This is an easy problem to solve if you go slowly with a debugger. – duffymo Mar 23 '23 at 14:15
  • @duffymo i have changed Output_x and Output_y = I_x/I_y - k_x/k_y + 1, which as you said was an easy fix. But I think my biggest problem is calculating the different elements in the output-matrix, which are all wrong. – Egelund48 Mar 23 '23 at 14:26
  • Change your code to include these lines: Output_x = I_x - k_x + 1 Output_y = I_y - k_y + 1. Signs aren't right. Output matrix is the right shape after this change, but the values are still wrong. – duffymo Mar 23 '23 at 14:27
  • 1
    @duffymo I have just solved it. I wrote minus - when calculating the different element, when it should be plus +. Thank you for the help, you have saved my day<3 – Egelund48 Mar 23 '23 at 14:31
  • I would recommend using NumPy matmul method. That is what it's for. – duffymo Mar 23 '23 at 14:32
  • Glad to help. Sorry I wasn't moving fast enough to keep up with you. I was on a call. – duffymo Mar 23 '23 at 14:33
  • This might help you, too. https://medium.com/analytics-vidhya/2d-convolution-using-python-numpy-43442ff5f381 – duffymo Mar 23 '23 at 14:51

1 Answers1

0

I took your code and played around with it a bit. I tried to solve the problem with fewer loops and more NumPy functions (e.g. ravel and dot). I think it's a bit simpler. See if you agree.

Thank you - yours was a good problem. I learned something.

import numpy as np
import pandas as pd

# see https://stackoverflow.com/questions/75823514/implementing-2d-convolution-in-python?noredirect=1#comment133749287_75823514
# see https://towardsdatascience.com/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1#:~:text=The%202D%20convolution%20is%20a,into%20a%20single%20output%20pixel.
# see https://medium.com/analytics-vidhya/2d-convolution-using-python-numpy-43442ff5f381

def convolution(input, kernel):
    assert (input.ndim == 2)
    assert (kernel.ndim == 2)
    result_cols = input.shape[1] - kernel.shape[1] + 1
    result_rows = input.shape[0] - kernel.shape[0] + 1
    assert (result_rows > 0)
    assert (result_cols > 0)
    result = np.zeros((result_rows, result_cols))

    for m in range(result_rows):
        for n in range(result_cols):
            a = np.array(input[m:(m+kernel.shape[0]), n:(n+kernel.shape[1])])
            term = np.dot(a.ravel(), kernel.ravel())
            result[m,n] = term
    return result

if __name__ == "__main__":
    input = np.array([[2, 3, 6, 9],
                      [1, 9, 5, 1],
                      [4, 7, 8, 5]])

    kernel = np.array([[1, 2],
                       [3, 1]])

    expected = pd.DataFrame(np.array([[20., 47., 40.],
                                      [38., 48., 36.]]))

    actual = pd.DataFrame(convolution(input, kernel))
    print(expected)
    print(actual)
    print('Correct?: ', actual.equals(expected))
duffymo
  • 305,152
  • 44
  • 369
  • 561