Implement NumPy neural-network layers
OpenAIData Scientist · OnsiteLast updated
This question tests your ability to implement fundamental neural network components using NumPy, focusing on matrix operations, broadcasting, and numerical stability.
Problem Statement
Implement a basic fully connected (Dense) layer and a Softmax activation function from scratch using only NumPy. You should structure these as Python classes with forward methods.
Requirements
- Dense Layer: Implement a
Denseclass that takesinput_dimandoutput_dimas initialization parameters. It should maintainweightsandbiasesas attributes. Theforwardmethod should perform the operation:y = x @ W + b. - Softmax Layer: Implement a
Softmaxclass. Theforwardmethod should take a 2D array of logitsx(shape:batch_size, num_classes) and return the probabilities.
Crucial: Your Softmax implementation must be numerically stable. You should subtract the maximum value across the feature dimension for each sample to prevent exponentiation of large numbers, which would lead to overflow.
Example
# Dense Layer Example
layer = Dense(input_dim=3, output_dim=2)
layer.weights = np.array([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]])
layer.biases = np.array([0.1, 0.1])
x = np.array([[1.0, 2.0, 3.0]])
output = layer.forward(x)
# Output: [[2.3, 2.9]]
Constraints
xis a 2D NumPy array of shape(batch_size, input_dim).- Use
np.expandnp.sumfor the Softmax logic. - Ensure your broadcasting is explicit and correct.
Hints
Hint 1
For the Dense layer, ensure your weight matrix initialization has dimensions (input_dim, output_dim) to allow for the dot product with the input.
Hint 2
For Softmax stability, remember that exp(x - max(x)) / sum(exp(x - max(x))) is mathematically equivalent to exp(x) / sum(exp(x)) but prevents overflow.
Hint 3
When computing the Softmax sum, use `keepdims=True` in `np.sum` to ensure the resulting array shape is compatible with the input for division broadcasting.
Follow-up questions
- How would you implement the `backward` pass for these layers, specifically calculating the gradient with respect to the weights?
- If you were to implement a ReLU activation layer, how would you handle the gradient calculation during the backward pass?
- Why is it common to initialize weights with a small variance (e.g., Xavier initialization) rather than initializing all weights to zero?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.