In order to really understand convolutional layers, I have reimplemented the forward method of a single keras Conv2D layer in basic numpy. The outputs of both seam almost identical, but there are some minor differences.

Getting the keras output:

```
inp = K.constant(test_x)
true_output = model.layers[0].call(inp).numpy()

```

My output:

```
def relu(x):
    return np.maximum(0, x)

def forward(inp, filter_weights, filter_biases):

    result = np.zeros((1, 64, 64, 32))

    inp_with_padding = np.zeros((1, 66, 66, 1))
    inp_with_padding[0, 1:65, 1:65, :] = inp

    for filter_num in range(32):
        single_filter_weights = filter_weights[:, :, 0, filter_num]

        for i in range(64):
            for j in range(64):
                prod = single_filter_weights * inp_with_padding[0, i:i+3, j:j+3, 0]
                filter_sum = np.sum(prod) + filter_biases[filter_num]
                result[0, i, j, filter_num] = relu(filter_sum)
    return result

my_output = forward(test_x, filter_weights, biases_weights)

```

The results are largely the same, but here are some examples of differences:

```
Mine: 2.6608338356018066
Keras: 2.660834312438965

Mine: 1.7892705202102661
Keras: 1.7892701625823975

Mine: 0.007190803997218609
Keras: 0.007190565578639507

Mine: 4.970898151397705
Keras: 4.970897197723389

```

I've tried converting everything to float32, but that does not solve it. Any ideas?

Edit:
I plotted the distribution over errors, and it might give some insight into what is happening. As can be seen, the errors all have very similar values, falling into four groups. However, these errors are not exactly these four values, but are almost all unique values around these four peaks. 
[![enter image description here](https://i.stack.imgur.com/1uN0j.png)](https://i.stack.imgur.com/1uN0j.png)

I am very interested in how to get my implementation to exactly match the keras one. Unfortunately, the errors seem to increase exponentially when implementing multiple layers. Any insight would help me out a lot!