Skip to content

Commit 82b9463

Browse files
Initial conv2d attempts prior to backprop integration.
1 parent 0b139e4 commit 82b9463

File tree

4 files changed

+101
-1
lines changed

4 files changed

+101
-1
lines changed

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ readme = "README.md"
88

99
packages = [
1010
{ include = "activation_functions", from = "src" },
11-
{ include = "my_neural_network", from = "src" }
11+
{ include = "my_neural_network", from = "src" },
12+
{ include = "cnn", from = "src" }
1213
]
1314

1415
# Python version and any project dependencies here

src/cnn/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .conv2d import Conv2D

src/cnn/conv2d.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import numpy as np
2+
3+
4+
class Conv2D:
5+
def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1):
6+
self.in_channels = in_channels
7+
self.out_channels = out_channels
8+
self.kernel_size = kernel_size
9+
self.stride = stride
10+
self.padding = padding
11+
12+
# init kernels and biases
13+
self.kernels = (
14+
np.random.randn(out_channels, in_channels, kernel_size, kernel_size) * 0.1
15+
)
16+
self.biases = np.zeros((out_channels, 1))
17+
18+
def _pad_input(self, X):
19+
if self.padding > 0:
20+
return np.pad(
21+
X,
22+
(
23+
(0, 0),
24+
(0, 0),
25+
(self.padding, self.padding),
26+
(self.padding, self.padding),
27+
),
28+
mode="constant",
29+
)
30+
return X
31+
32+
def forward(self, X):
33+
"""
34+
Perform forward propagation for convolutional layer.
35+
36+
Args:
37+
X: Input tensor of shape (batch_size, in_channels, height, width)
38+
39+
Returns:
40+
np.ndarray: Output tensor after convolution
41+
"""
42+
batch_size, in_channels, height, width = X.shape
43+
assert (
44+
in_channels == self.in_channels
45+
), "Input channels must match kernel channels."
46+
47+
# calculate output dimensions
48+
out_height = (height + 2 * self.padding - self.kernel_size) // self.stride + 1
49+
out_width = (width + 2 * self.padding - self.kernel_size) // self.stride + 1
50+
51+
# apply padding
52+
X_padded = self._pad_input(X)
53+
54+
# allocate output tensor to store convolution results
55+
output = np.zeros((batch_size, self.out_channels, out_height, out_width))
56+
57+
# convolve
58+
for b in range(batch_size): # iterate over each sample in batch
59+
for o in range(
60+
self.out_channels
61+
): # for each filter (each filter makes one feature map)
62+
for i in range(
63+
out_height
64+
): # traverse over the locations of the feature map
65+
for j in range(out_width):
66+
# region of the input matrix that the kernel processes
67+
h_start = i * self.stride
68+
h_end = h_start + self.kernel_size
69+
w_start = j * self.stride
70+
w_end = w_start + self.kernel_size
71+
72+
# extract the input region
73+
input_region = X_padded[b, :, h_start:h_end, w_start:w_end]
74+
75+
# element-wise multiplication and summation
76+
output[b, o, i, j] = (
77+
np.sum(input_region * self.kernels[o, :, :, :])
78+
+ self.biases[o]
79+
)
80+
81+
return output

src/cnn/simple_cnn.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from cnn import Conv2D
2+
from my_neural_network import SimpleNeuralNetwork
3+
4+
5+
class SimpleNeuralNetworkWithConv(SimpleNeuralNetwork):
6+
def __init__(self, config, conv_params):
7+
super().__init__(config)
8+
self.conv_layer = Conv2D(**conv_params) # add a convolutional layer
9+
10+
def forward_propagation(self, X, mode="train"):
11+
conv_output = self.conv_layer.forward(X)
12+
13+
# flatten output of convolutional layer (needed for input to FFNN?)
14+
flat_output = conv_output.reshape(conv_output.shape[0], -1).T
15+
16+
# pass to fully connected layers
17+
return super().forward_propagation(flat_output, mode)

0 commit comments

Comments
 (0)