Verificar contra PyTorch
La atención en NumPy se comprueba de tres formas: contra bucles explícitos (un np.dot por entrada), contra qh @ kh.swapaxes(-1, -2) / sqrt(D_k), y contra F.scaled_dot_product_attention de PyTorch con dropout_p=0.0.
Las cabezas en PyTorch se construyen igual — reshape(B, S, H, D // H).permute(0, 2, 1, 3) — y coinciden exactamente con qh de NumPy, aunque el tensor permutado no es contiguo.
La salida de PyTorch coincide con los valores de cabeza de NumPy hasta rtol=1e-10, y también el resultado unido tras .contiguous().view(B, S, D).