import numpy as np

# 1. Convolution 2D
correct_conv2d_out = np.array([[4.15602761, 1.71696586, 3.03274771],
                               [1.38663883, 4.34007508, 2.56793368],
                               [0.30468451, 7.06794329, 1.50587495]])

# 3. Convolution Layer
correct_conv_out = np.array([[[[-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5]],
  [[-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5]],
  [[-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5]]],
 [[[-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5]],
  [[-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5]],
  [[-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5]]]])

# 4. Pooling Layer
correct_pooled = np.array([[[[5., 10.],
                             [1., 11.]]]])
correct_d_pool = np.array([[[[1., 0., 0., 1.],
                             [0., 0., 0., 0.],
                             [0., 0., 1., 0.],
                             [0., 1., 0., 0.]]]])

# 5. FC Layer
correct_fc_forward = np.array([[1.03, -3.25],
                            [-0.99, 0.]])
correct_fc_backward = np.array([[5.75, -3.01],
                            [1.25, -1.]])
correct_fc_dW = np.array([[1., -3.],
                       [-3., 10.]])
correct_fc_db = np.array([-1, 4])

# 6. Softmax Layer
correct_sm = np.array([[2.48168930e-02, 6.72851458e-01, 3.02331649e-01],
                       [9.99831219e-01, 1.23388975e-04, 4.53922671e-05],
                       [1.38389653e-87, 3.72007598e-44, 1.00000000e+00],
                       [3.33333333e-01, 3.33333333e-01, 3.33333333e-01]])

correct_ce_loss = 1.5991806917017481
correct_d_softmax = np.array([[-0.25, 0.08333333, 0.08333333,  0.08333333],
                              [0.3, -0.32233333,  0.011, 0.011],
                              [ 0., 0., 0., 0.]])
import numpy as np

# 1. Convolution 2D
correct_conv2d_out = np.array([[4.15602761, 1.71696586, 3.03274771],
                               [1.38663883, 4.34007508, 2.56793368],
                               [0.30468451, 7.06794329, 1.50587495]])

# 3. Convolution Layer
correct_conv_out = np.array([[[[-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5]],
  [[-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5]],
  [[-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5]]],
 [[[-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5],
   [-4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5]],
  [[-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5],
   [-3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5, -3.5]],
  [[-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5],
   [-2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5, -2.5]]]])

# 4. Pooling Layer
correct_pooled = np.array([[[[5., 10.],
                             [1., 11.]]]])
correct_d_pool = np.array([[[[1., 0., 0., 1.],
                             [0., 0., 0., 0.],
                             [0., 0., 1., 0.],
                             [0., 1., 0., 0.]]]])

# 5. FC Layer
correct_fc_forward = np.array([[1.03, -3.25],
                            [-0.99, 0.]])
correct_fc_backward = np.array([[5.75, -3.01],
                            [1.25, -1.]])
correct_fc_dW = np.array([[1., -3.],
                       [-3., 10.]])
correct_fc_db = np.array([-1, 4])

# 6. Softmax Layer
correct_sm = np.array([[2.48168930e-02, 6.72851458e-01, 3.02331649e-01],
                       [9.99831219e-01, 1.23388975e-04, 4.53922671e-05],
                       [1.38389653e-87, 3.72007598e-44, 1.00000000e+00],
                       [3.33333333e-01, 3.33333333e-01, 3.33333333e-01]])

correct_ce_loss = 1.5991806917017481
correct_d_softmax = np.array([[-0.25, 0.08333333, 0.08333333,  0.08333333],
                              [0.3, -0.32233333,  0.011, 0.011],
                              [ 0., 0., 0., 0.]])
# 1. Convolution 2D # 3. Convolution Layer # 4. Pooling Layer # 5. FC Layer # 6. Softmax Layer