# Hidden layer gradients are more complex due to chain rule print("Hidden layer gradient breakdown:") print("dz1 = (dz2 @ W2.T) * sigmoid_derivative(z1)") # Step by step error_propagated = dz2 @ W2.T # Propagate error backwards print(f"Error propagated shape: {error_propagated.shape}") print(f"This spreads output error to each hidden neuron") hidden_sigmoid_grad = sigmoid_derivative(z1) # Local gradient print(f"Hidden sigmoid gradient shape: {hidden_sigmoid_grad.shape}") dz1_step = error_propagated * hidden_sigmoid_grad # Final gradient print(f"Combined hidden gradient (dz1) shape: {dz1_step.shape}")