Welcome to the fourth post in our series on Linear Algebra for Machine Learning! After exploring matrix arithmetic, we now focus on the dot product and cosine similarity, two fundamental concepts for measuring relationships between vectors. These tools are crucial in machine learning (ML) for tasks like similarity search, projections, and word embeddings. In this post, we’ll cover their mathematical foundations, their applications in ML, and how to implement them in Python using NumPy and PyTorch. We’ll include visualizations and Python exercises to solidify your understanding.
The dot product of two vectors and in is a scalar computed as:
Geometrically, the dot product relates to the angle between the vectors:
where is the Euclidean norm (length) of . The dot product is:
The dot product also represents the projection of one vector onto another, scaled by the length of the second vector.
Cosine similarity measures the cosine of the angle between two vectors, focusing on their directional similarity, regardless of magnitude:
The value ranges from:
Cosine similarity is widely used in ML because it’s robust to vector magnitude, making it ideal for comparing high-dimensional data like word embeddings.
In machine learning, these concepts are essential:
Understanding these tools helps you quantify relationships in data and build effective ML models.
Let’s implement dot product and cosine similarity using NumPy and PyTorch, with visualizations to illustrate their geometric meaning.
Install the required libraries if needed:
pip install numpy torch matplotlib
Let’s compute the dot product of two vectors:
import numpy as np
import matplotlib.pyplot as plt
# Define two 2D vectors
u = np.array([1, 2])
v = np.array([3, 1])
# Compute dot product
dot_product = np.dot(u, v)
# Print results
print("Vector u:", u)
print("Vector v:", v)
print("Dot product u · v:", dot_product)
# Visualize vectors
def plot_2d_vectors(vectors, labels, colors):
plt.figure(figsize=(6, 6))
origin = np.zeros(2)
for vec, label, color in zip(vectors, labels, colors):
plt.quiver(*origin, *vec, color=color, scale=1, scale_units='xy', angles='xy')
plt.text(vec[0], vec[1], label, color=color, fontsize=12)
plt.grid(True)
plt.xlim(-1, 4)
plt.ylim(-1, 4)
plt.axhline(0, color='black', linewidth=0.5)
plt.axvline(0, color='black', linewidth=0.5)
plt.xlabel('X')
plt.ylabel('Y')
plt.title("Vectors for Dot Product")
plt.show()
plot_2d_vectors(
[u, v],
['u', 'v'],
['blue', 'red']
)
Output:
Vector u: [1 2]
Vector v: [3 1]
Dot product u · v: 5
This computes and plots the vectors to show their directional relationship.
Let’s compute cosine similarity:
# Compute norms
norm_u = np.linalg.norm(u)
norm_v = np.linalg.norm(v)
# Compute cosine similarity
cosine_sim = dot_product / (norm_u * norm_v)
# Print results
print("Norm of u:", norm_u)
print("Norm of v:", norm_v)
print("Cosine similarity:", cosine_sim)
Output:
Norm of u: 2.23606797749979
Norm of v: 3.1622776601683795
Cosine similarity: 0.7071067811865475
This computes , indicating the angle between and is about .
Let’s use PyTorch’s cosine_similarity
:
import torch
# Convert to PyTorch tensors
u_torch = torch.tensor(u, dtype=torch.float32)
v_torch = torch.tensor(v, dtype=torch.float32)
# Compute cosine similarity
cosine_sim_torch = torch.cosine_similarity(u_torch, v_torch, dim=0)
# Print result
print("PyTorch cosine similarity:", cosine_sim_torch.item())
Output:
PyTorch cosine similarity: 0.7071067690849304
This confirms PyTorch’s result matches NumPy’s, with minor floating-point differences.
Let’s compare vectors with different similarities:
# Define vectors with varying similarity
v1 = np.array([1, 0]) # Same direction as u
v2 = np.array([0, 1]) # Orthogonal to v1
v3 = np.array([-1, 0]) # Opposite to v1
# Compute cosine similarities
cos_sim_v1 = np.dot(u, v1) / (np.linalg.norm(u) * np.linalg.norm(v1))
cos_sim_v2 = np.dot(u, v2) / (np.linalg.norm(u) * np.linalg.norm(v2))
cos_sim_v3 = np.dot(u, v3) / (np.linalg.norm(u) * np.linalg.norm(v3))
# Print results
print("Cosine similarity u, v1:", cos_sim_v1)
print("Cosine similarity u, v2:", cos_sim_v2)
print("Cosine similarity u, v3:", cos_sim_v3)
# Plot vectors
plot_2d_vectors(
[u, v1, v2, v3],
['u', 'v1 (similar)', 'v2 (orthogonal)', 'v3 (opposite)'],
['blue', 'green', 'red', 'purple']
)
Output:
Cosine similarity u, v1: 0.4472135954999579
Cosine similarity u, v2: 0.8944271909999159
Cosine similarity u, v3: -0.4472135954999579
This shows how cosine similarity reflects directional relationships, with being somewhat similar, nearly orthogonal, and opposite to .
Try these Python exercises to deepen your understanding. Solutions will be discussed in the next post!
torch.cosine_similarity
.
Verify the result matches NumPy’s.In the next post, we’ll explore linear independence and span, key concepts for understanding feature redundancy and the expressiveness of ML models. We’ll provide more Python code and exercises to keep building your intuition.
Happy learning, and see you in Part 5!