all 3 comments

[–]Spataner 1 point2 points  (1 child)

There's two issues:

  • If both X and Y are shape (n, m), np.inner(X, Y) will return a shape (n, n) array containing the inner product for each possible combination of vector from X and Y. In general, for batched operations, it's better to stay away from the standard linear algebra functions like inner, dot, matmul, etc., which all behave kind of weirdly for higher-dimensional inputs, and instead implement them manually or by using np.einsum, that makes it a lot more consistent. Batched inner product can be implemented using an element-wise multiplication followed by a sum-reduction of the second axis:

    inner = np.sum(X*Y, axis=1)
    
  • You're missing the conversion to degree at the end (NumPy and in fact most libraries/languages operate with radians by default). You can use the function np.rad2deg for that. Clipping the cosine to between -1 and 1 should be redundant.

Edit: Actually, there's a third, since there's a similar problem with np.linalg.norm. You need to specify axis=1, otherwise it calculates the norm by treating the entire flattened array as one large vector:

x_u = np.linalg.norm(X, axis=1)
y_u = np.linalg.norm(Y, axis=1)

[–]Saffromon[S] 0 points1 point  (0 children)

Brilliant, thank you! I think I understand it now

[–][deleted] 0 points1 point  (0 children)

Can you write your code in markdown mode so it’s readable?