PyTorch
Essential PyTorch patterns for tensor ops, autograd, model building, training loops, and deployment.
Tensors
3 topics
Creating Tensors
Tensors are the core data structure in PyTorch — multi-dimensional arrays that can live on CPU or GPU.
import torch
# From Python list
t = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
# Filled tensors
zeros = torch.zeros(3, 4) # all zeros
ones = torch.ones(3, 4) # all ones
rand = torch.rand(3, 4) # uniform [0, 1)
randn = torch.randn(3, 4) # standard normal
# Like another tensor (same shape/dtype)
like = torch.zeros_like(t)
# From NumPy (shares memory on CPU)
import numpy as np
arr = np.array([1.0, 2.0])
t2 = torch.from_numpy(arr)Use dtype=torch.float32 explicitly — PyTorch defaults to float32 for most ops.
torch.from_numpy shares memory; modifying one changes the other.
Tensor Operations
Element-wise math, matrix multiplication, reshaping, and indexing.
a = torch.tensor([[1., 2.], [3., 4.]])
b = torch.tensor([[5., 6.], [7., 8.]])
# Element-wise
a + b; a * b; a ** 2
# Matrix multiply
c = a @ b # or torch.matmul(a, b)
# Reshape / view
flat = a.view(-1) # [1, 2, 3, 4] — shares storage
reshaped = a.reshape(1, 4) # safe even on non-contiguous
# Indexing & slicing (same as NumPy)
a[0] # first row
a[:, 1] # second column
a[a > 2] # boolean mask
# Reduce
a.sum(); a.mean(); a.max()view() requires contiguous memory; reshape() handles non-contiguous tensors safely.
In-place ops end with _: a.add_(b) modifies a directly — breaks autograd graphs.
Moving to GPU
Tensors and models must be on the same device. Always check availability before assuming CUDA.
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
t = torch.randn(3, 3).to(device)
# Or pass device at creation
t2 = torch.ones(3, 3, device=device)
# Move back to CPU for NumPy conversion
arr = t.cpu().numpy()Apple Silicon: use device='mps' for GPU acceleration on Mac.
Call .detach() before .numpy() if the tensor has requires_grad=True.
Autograd
1 topic
Gradients & backward()
PyTorch tracks operations on tensors with requires_grad=True to build a computation graph, then computes gradients via backward().
x = torch.tensor(3.0, requires_grad=True)
y = x ** 2 + 2 * x + 1 # y = (x+1)^2
y.backward() # compute dy/dx
print(x.grad) # tensor(8.) — dy/dx at x=3 is 2x+2=8
# Accumulates! Zero before each step
x.grad.zero_()
# Stop tracking (inference / data preprocessing)
with torch.no_grad():
val = x ** 2 # no graph builtGradients accumulate by default — always call optimizer.zero_grad() before backward().
Use torch.no_grad() during validation to save memory and speed up inference.
Building Models
2 topics
nn.Module
Subclass nn.Module to define any model. Layers are declared in init and the forward pass in forward().
import torch.nn as nn
class MLP(nn.Module):
def __init__(self, in_features, hidden, out_features):
super().__init__()
self.net = nn.Sequential(
nn.Linear(in_features, hidden),
nn.ReLU(),
nn.Linear(hidden, out_features),
)
def forward(self, x):
return self.net(x)
model = MLP(784, 256, 10)
print(model) # shows layer tree
print(sum(p.numel() for p in model.parameters())) # param countNever call forward() directly — call model(x), which runs hooks + forward.
nn.Sequential is fine for simple stacks; use a custom forward for skip connections or branching.
Common Layers
Reference for the most-used layer types.
nn.Linear(in, out) # fully-connected
nn.Conv2d(in_ch, out_ch, kernel) # 2D convolution
nn.MaxPool2d(kernel_size) # spatial downsampling
nn.BatchNorm2d(num_features) # batch normalization
nn.Dropout(p=0.5) # regularization
nn.Embedding(vocab, dim) # lookup table for NLP
nn.LSTM(input, hidden, layers) # recurrent
nn.MultiheadAttention(embed, heads) # transformer blockTraining Loop
3 topics
Standard Training Loop
The canonical PyTorch training loop: forward pass → loss → backward → optimizer step.
import torch.optim as optim
model = MLP(784, 256, 10).to(device)
optimizer = optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()
for epoch in range(num_epochs):
model.train() # enables dropout/batchnorm
for X, y in train_loader:
X, y = X.to(device), y.to(device)
optimizer.zero_grad() # clear accumulated grads
logits = model(X) # forward
loss = criterion(logits, y) # compute loss
loss.backward() # compute gradients
optimizer.step() # update weights
print(f'Epoch {epoch}: loss={loss.item():.4f}')model.train() and model.eval() toggle dropout/BatchNorm behavior — always switch modes.
loss.item() extracts a Python float; avoids accumulating the whole graph in memory.
Validation Loop
Run on held-out data after each epoch with gradients disabled.
model.eval()
correct = total = 0
with torch.no_grad():
for X, y in val_loader:
X, y = X.to(device), y.to(device)
logits = model(X)
preds = logits.argmax(dim=1)
correct += (preds == y).sum().item()
total += y.size(0)
acc = correct / total
print(f'Val accuracy: {acc:.4f}')torch.no_grad() cuts memory roughly in half during inference — always use it in eval.
DataLoader & Dataset
Wrap any dataset in DataLoader for automatic batching, shuffling, and parallel loading.
from torch.utils.data import Dataset, DataLoader
class MyDataset(Dataset):
def __init__(self, X, y):
self.X = torch.tensor(X, dtype=torch.float32)
self.y = torch.tensor(y, dtype=torch.long)
def __len__(self):
return len(self.X)
def __getitem__(self, idx):
return self.X[idx], self.y[idx]
train_loader = DataLoader(
MyDataset(X_train, y_train),
batch_size=64,
shuffle=True,
num_workers=4, # parallel loading
pin_memory=True, # faster CPU→GPU transfer
)pin_memory=True + non_blocking=True on .to(device) overlaps data transfer with compute.
num_workers > 0 can cause issues on Windows; set to 0 if you see multiprocessing errors.
Save & Load
1 topic
Saving & Loading Checkpoints
Save model weights (state_dict) rather than the full object — more portable across code changes.
# Save
torch.save({
'epoch': epoch,
'model_state': model.state_dict(),
'optimizer_state': optimizer.state_dict(),
'loss': loss,
}, 'checkpoint.pt')
# Load
checkpoint = torch.load('checkpoint.pt', map_location=device)
model.load_state_dict(checkpoint['model_state'])
optimizer.load_state_dict(checkpoint['optimizer_state'])
start_epoch = checkpoint['epoch']Always pass map_location=device when loading — avoids CUDA errors on CPU-only machines.
For inference-only: torch.save(model.state_dict(), 'weights.pt') is enough.
Inference & Export
1 topic
TorchScript & ONNX Export
Export models for production deployment without a Python runtime.
# TorchScript — serialize the model
scripted = torch.jit.script(model)
scripted.save('model_scripted.pt')
loaded = torch.jit.load('model_scripted.pt')
# ONNX — interoperable with TensorRT, ONNX Runtime, CoreML
dummy = torch.randn(1, 784, device=device)
torch.onnx.export(
model, dummy, 'model.onnx',
input_names=['input'],
output_names=['output'],
dynamic_axes={'input': {0: 'batch'}}, # variable batch size
opset_version=17,
)Prefer TorchScript for PyTorch-native serving (TorchServe, C++ LibTorch).
ONNX is better for cross-framework deployment (e.g. running in ONNX Runtime on edge devices).
Related Cheat Sheets
More hands-on references connected to this topic.
FastAPI routes, request models, dependency injection, authentication, and async patterns.
shared topics, same difficulty
A practical cheat sheet for loading, cleaning, transforming, analyzing, and exporting tabular data with Pandas, plus how it fits with PyTorch workflows.
shared topics
shared topics
Python syntax, data structures, comprehensions, OOP, error handling, and standard library essentials.
shared topics
Related Articles
Background reading and deeper explanations for this sheet.
Cost Optimization in Agentic Systems: The Most Underrated Lever for Reliable AI at Scale
Most teams building agentic systems obsess over accuracy and latency, but ignore the fastest path to sustainable scale: cost optimization. In this guide, you’ll learn practical cost models, real architecture patterns, and implementation tactics to cut spend without sacrificing quality or autonomy.
keyword overlap
AI Product Pricing Strategies: How to Monetize for Growth, Margin, and Customer Trust
Pricing an AI product is not just a finance decision—it shapes adoption, retention, margins, and user trust. In this practical guide, you’ll learn how to choose the right pricing model, align price with value and costs, and avoid common mistakes using real-world examples and implementation frameworks.
keyword overlap
FastAPI Interview Questions: Practical Cheat Sheet for Developers
Preparing for FastAPI interviews can feel overwhelming if you only memorize definitions. This practical cheat sheet helps you answer common FastAPI interview questions with confidence using real-world examples, production-ready patterns, and beginner-friendly explanations with depth.
keyword overlap
GenAI SaaS Architecture: A Practical Blueprint for Building, Scaling, and Securing AI Products
Designing a SaaS product on top of GenAI is more than calling an LLM API—it requires thoughtful architecture across product, data, safety, and operations. This practical guide walks you through a beginner-friendly yet deep system blueprint, with real-world patterns, code snippets, and deployment strategies you can use immediately.
keyword overlap