This was a single question but it just kept going.
Start by defining the MLP forward pass with explicit shapes, then walk through a concrete example with a batch, showing how broadcasting applies the bias and how ReLU is applied elementwise. Next, explain how PyTorch vectorizes these operations on GPU using batched matrix multiplication and elementwise kernels. Finally, compare torch.matmul, @, and nn.Linear, and highlight common shape pitfalls like (B,1) vs (B,).
Pro tip: Emphasize that nn.Linear is a high-level module that encapsulates weight initialization, device placement, and optimized kernels, while torch.matmul and @ are lower-level ops; knowing when to use each shows depth. Also, mention that avoiding shape (B,1) vs (B,) bugs often involves using .squeeze() or .unsqueeze() appropriately, and that broadcasting can silently produce wrong shapes if not careful.
Write Y = XW + b, specify X shape (B, d_in), W shape (d_in, d_h), b shape (d_h,), and Y shape (B, d_h). Explain that b is broadcast across the batch dimension.
Describe how PyTorch broadcasting adds b to each row of XW, and then apply ReLU elementwise: A = max(0, Y). Track shapes through multiple layers, e.g., (B, d_in) -> (B, d_h) -> (B, d_out).
Explain that matrix multiplication is batched and parallelized on GPU using cuBLAS, and elementwise ops like ReLU are fused kernels that operate on all elements concurrently.
Clarify that torch.matmul and @ are equivalent for 2D tensors, but @ is syntactic sugar; nn.Linear is a module that holds weights and bias, handles initialization, and calls the underlying matmul with optimized kernels.
Discuss common issues: (B,1) vs (B,) can cause unintended broadcasting or errors; use .squeeze() or .unsqueeze() to align dimensions, and be mindful of batch dimensions in higher-rank tensors.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.