import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
from sklearn.linear_model import LinearRegression
import pandas as pd
from plotnine import *
# Generate synthetic data
42)
np.random.seed(= np.random.randn(100, 1) * 2 # 100 samples, 1 feature
X = 3 * X + 2 + np.random.randn(100, 1) * 0.5 # y = 3x + 2 + noise
y
# Convert to PyTorch tensors
= torch.FloatTensor(X)
X_tensor = torch.FloatTensor(y)
y_tensor
# define a linear model
class LinearModel(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(1, 1) # 1 input feature, 1 output
def forward(self, x):
return self.linear(x)
# instantiate the model
= LinearModel()
model
# define a loss function
= nn.MSELoss()
loss_fn
# define an optimizer
= optim.SGD(model.parameters(), lr=0.01)
optimizer
# Train: iterate over the data and update the model
= 100
num_epochs for epoch in range(num_epochs):
# Forward pass: compute model predictions and loss
= model(X_tensor)
y_pred = loss_fn(y_pred, y_tensor)
loss
# Backward pass and parameter update
# Clear previous gradients
optimizer.zero_grad() # Compute gradients via backpropagation
loss.backward() # Update model parameters
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
# check performance
# compute PyTorch model predictions
eval()
model.with torch.no_grad():
= model(X_tensor).numpy()
y_pred_pytorch
# compute scikit-learn predictions
= LinearRegression()
lr
lr.fit(X, y)= lr.predict(X)
y_pred_sklearn
# compare coefficients
print("\nPyTorch model coefficients:")
print(f"Slope: {model.linear.weight.item():.4f}")
print(f"Intercept: {model.linear.bias.item():.4f}")
print("\nScikit-learn coefficients:")
print(f"Slope: {lr.coef_[0][0]:.4f}")
print(f"Intercept: {lr.intercept_[0]:.4f}")
# compare MSE
= np.mean((y - y_pred_pytorch) ** 2)
mse_pytorch = np.mean((y - y_pred_sklearn) ** 2)
mse_sklearn print(f"\nPyTorch MSE: {mse_pytorch:.4f}")
print(f"Scikit-learn MSE: {mse_sklearn:.4f}")
Fit linear mode to linear data
fit a linear model to linear data
We generate a data Y linearly dependent on features X: Y = X\beta + \epsilon
We fit a linear model
with gradient descent
with pytorch framework
with traditional linear regression estimate \hat\beta = (X^TX)^{-1}X^TY
plot predictions vs true
# Create a plot comparing predictions
# Create a DataFrame for plotting
= pd.DataFrame({
plot_df 'y_true': y.flatten(),
'y_pred_pytorch': y_pred_pytorch.flatten(),
'y_pred_sklearn': y_pred_sklearn.flatten()
})
# Create the plot
= (ggplot(plot_df)
p + geom_point(aes(x='y_true', y='y_pred_pytorch', color='"PyTorch"'), size=1)
+ geom_point(aes(x='y_true', y='y_pred_sklearn', color='"Scikit-learn"'), size=1)
+ geom_abline(intercept=0, slope=1, color='gray', linetype='dashed', alpha=0.5) # Identity line
+ scale_color_manual(values=['red', 'blue'])
+ labs(x='True Values', y='Predicted Values',
='True vs Predicted Values',
title='Model')
color+ theme_minimal()
)
p
(ggplot(plot_df)+ geom_point(aes(x='y_pred_sklearn', y='y_pred_pytorch'), size=1)
+ geom_abline(intercept=0, slope=1, color='gray', linetype='dashed', alpha=0.5) # Identity line
+ labs(x='Y sklearn', y='Y pytorch',
='ptorch vs sklearn predictions',
title='Model')
color+ theme_minimal()
)
Fit linear model using the GPU
# Train on GPU (checking for both MPS and CUDA)
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
from sklearn.linear_model import LinearRegression
import pandas as pd
from plotnine import *
# Check for available GPU devices
if torch.backends.mps.is_available():
= torch.device('mps') # Apple Silicon
device print("Using MPS (Apple Silicon GPU)")
elif torch.cuda.is_available():
= torch.device('cuda') # NVIDIA GPU
device print("Using CUDA (NVIDIA GPU)")
else:
= torch.device('cpu') # Fallback to CPU
device print("Using CPU (no GPU available)")
# Generate synthetic data (stays on CPU)
42)
np.random.seed(= np.random.randn(100, 1) * 2
X = 3 * X + 2 + np.random.randn(100, 1) * 0.5
y
# Convert to PyTorch tensors and move to GPU
= torch.FloatTensor(X).to(device)
X_tensor = torch.FloatTensor(y).to(device)
y_tensor
# Define and move model to GPU
class LinearModel(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(1, 1)
def forward(self, x):
return self.linear(x)
= LinearModel().to(device)
model = nn.MSELoss()
loss_fn = optim.SGD(model.parameters(), lr=0.01)
optimizer
# Training loop (same as before, but data is on GPU)
= 100
num_epochs for epoch in range(num_epochs):
# Forward pass
= model(X_tensor)
y_pred = loss_fn(y_pred, y_tensor)
loss
# Backward pass and optimize
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
# Get predictions back to CPU for comparison
eval()
model.with torch.no_grad():
= model(X_tensor).cpu().numpy() # Move back to CPU before converting to numpy
y_pred_pytorch
# Compare with scikit-learn (on CPU)
= LinearRegression()
lr
lr.fit(X, y)= lr.predict(X)
y_pred_sklearn
# Compare coefficients
print("\nPyTorch model coefficients:")
print(f"Slope: {model.linear.weight.item():.4f}")
print(f"Intercept: {model.linear.bias.item():.4f}")
print("\nScikit-learn coefficients:")
print(f"Slope: {lr.coef_[0][0]:.4f}")
print(f"Intercept: {lr.intercept_[0]:.4f}")
# Compare MSE
= np.mean((y - y_pred_pytorch) ** 2)
mse_pytorch = np.mean((y - y_pred_sklearn) ** 2)
mse_sklearn print(f"\nPyTorch MSE: {mse_pytorch:.4f}")
print(f"Scikit-learn MSE: {mse_sklearn:.4f}")
# Create a plot comparing predictions
= pd.DataFrame({
plot_df 'y_true': y.flatten(),
'y_pred_pytorch': y_pred_pytorch.flatten(),
'y_pred_sklearn': y_pred_sklearn.flatten()
})
# Create the plot
= (ggplot(plot_df)
p + geom_point(aes(x='y_true', y='y_pred_pytorch', color='"PyTorch"'), size=1)
+ geom_point(aes(x='y_true', y='y_pred_sklearn', color='"Scikit-learn"'), size=1)
+ geom_abline(intercept=0, slope=1, color='gray', linetype='dashed', alpha=0.5) # Identity line
+ scale_color_manual(values=['red', 'blue'])
+ labs(x='True Values', y='Predicted Values',
=f'True vs Predicted Values (Training on {device})',
title='Model')
color+ theme_minimal()
)
p