Loading problem...
In modern deep learning architectures, dense connectivity patterns have proven to be remarkably effective for feature extraction in convolutional neural networks. Unlike traditional sequential architectures where each layer only receives input from its immediate predecessor, a densely connected convolutional block establishes direct connections between every layer and all subsequent layers within the block.
The core innovation of this architecture lies in its feature reuse mechanism: at each layer, the output feature maps are concatenated with all preceding feature maps along the channel dimension, creating a cumulative feature representation that grows progressively richer. This design encourages gradient flow during backpropagation, reduces the vanishing gradient problem, and enables the network to learn more compact and discriminative features.
Dense Block Architecture:
A dense block consists of num_layers convolutional layers that operate iteratively. At layer l (0-indexed):
Apply ReLU Activation: The running feature tensor undergoes element-wise ReLU activation: activated = max(0, features)
Perform Convolution: The activated tensor is convolved with kernel kernels[l] using:
H and width WConcatenate Features: The convolution output (with growth_rate channels) is concatenated to the running tensor along the channel axis
Kernel Dimensions:
Each kernel kernels[l] must have the shape:
$$\text{kernels}[l] : (k_h, k_w, C_0 + l \times \text{growth_rate}, \text{growth_rate})$$
where:
(kₕ, kᵥ) is the spatial kernel size (default: 3×3)C₀ is the number of input channels in the original inputgrowth_rate is the number of new feature channels added per layerOutput Specification:
After processing all num_layers iterations, the function returns a tensor of shape:
$$(N, H, W, C_0 + \text{num_layers} \times \text{growth_rate})$$
Your Task:
Implement a function that performs the forward pass of a densely connected convolutional block. The function should:
num_layers iterative convolution operationsValueError if any kernel's input channel dimension doesn't match the expected number of accumulated channelsinput_data = np.array([[[[0.496714], [-0.138264]], [[0.647689], [1.52303]]]]) # Shape: (1, 2, 2, 1)
num_layers = 2
growth_rate = 1
kernels = [kernel_0, kernel_1] # Each adds 1 channel
kernel_size = (3, 3)[[[[0.4967, -0.0017, -0.0032], [-0.1383, -0.0063, -0.0006]], [[0.6477, 0.0041, -0.026], [1.523, -0.0033, -0.022]]]]Input: A single 2×2 image with 1 channel (C₀ = 1)
Layer 0 Processing:
Layer 1 Processing:
Output Shape: (1, 2, 2, 3) - original 1 channel + 2 growth layers = 3 total channels
Each spatial location now contains the original feature plus the two progressively computed dense features.
input_data = np.array([[[[0.2574, -0.908481], [-0.378503, -0.534916], [0.858073, -0.41301]],
[[0.498189, 2.010199], [1.262862, -0.439215], [-0.346438, 0.45532]],
[[-1.668663, -0.862085], [0.492911, -0.124313], [1.935136, -0.618443]]]]) # Shape: (1, 3, 3, 2)
num_layers = 1
growth_rate = 2
kernels = [kernel_0] # Adds 2 channels
kernel_size = (3, 3)[[[[0.2574, -0.9085, -0.3402, 0.1572], [-0.3785, -0.5349, -0.3047, 0.2286], [0.8581, -0.413, 0.0122, 0.4746]],
[[0.4982, 2.0102, -0.4733, 0.4941], [1.2629, -0.4392, -0.2155, 0.1974], [-0.3464, 0.4553, -0.1657, 0.4222]],
[[-1.6687, -0.8621, 0.075, 0.3034], [0.4929, -0.1243, 0.0999, 0.2887], [1.9351, -0.6184, -0.2739, 0.2888]]]]Input: A single 3×3 image with 2 channels (C₀ = 2)
Layer 0 Processing:
Output Shape: (1, 3, 3, 4)
The first two channel values at each position are preserved from the original input. The last two channels represent the learned dense features from the first (and only) convolutional layer.
input_data = np.array([...]) # Shape: (2, 4, 4, 3) - Batch of 2 images
num_layers = 2
growth_rate = 2
kernels = [kernel_0, kernel_1] # Each adds 2 channels
kernel_size = (3, 3)# Shape: (2, 4, 4, 7)Input: Batch of 2 images, each 4×4 with 3 channels (C₀ = 3)
Layer 0:
Layer 1:
Output Shape: (2, 4, 4, 7)
This demonstrates the progressive channel growth: C₀ + num_layers × growth_rate = 3 + 2 × 2 = 7 final channels. The batch dimension is preserved throughout.
Constraints