16. PyTorch Fundamentals and Tensors¶
Learn the foundations of PyTorch, understand tensors, tensor operations, device management, automatic differentiation, neural network modules, parameters, GPU acceleration, and the core building blocks required to develop Deep Learning models using PyTorch.
๐ฏ Learning Objectives¶
After completing this chapter, you will be able to:
- Explain what PyTorch is
- Understand the architecture of PyTorch
- Understand PyTorch tensors
- Understand tensor dimensions, shape, rank, and data types
- Create tensors using different methods
- Perform tensor indexing and slicing
- Perform tensor arithmetic and matrix operations
- Understand broadcasting
- Reshape, transpose, squeeze, and unsqueeze tensors
- Understand tensor devices
- Move tensors between CPU and GPU
- Understand tensor memory and performance considerations
- Understand
requires_grad - Understand the role of tensors in automatic differentiation
- Understand
torch.nn - Build neural network components using
nn.Module - Understand parameters and trainable variables
- Build a basic PyTorch neural network
- Understand the PyTorch training workflow
- Understand the difference between training and inference
- Save and load PyTorch models
- Understand PyTorch GPU acceleration
- Understand the relationship between tensors, models, autograd, and optimizers
- Prepare for PyTorch datasets, DataLoaders, and custom training loops
๐ Overview¶
PyTorch is an open-source Deep Learning framework widely used for:
- Neural network development
- Computer Vision
- Natural Language Processing
- Generative AI
- Reinforcement Learning
- Research
- Production Machine Learning
The core PyTorch ecosystem can be viewed as:
PyTorch
โ
โโโ Tensors
โ
โโโ Autograd
โ
โโโ torch.nn
โ
โโโ Optimizers
โ
โโโ Data Utilities
โ
โโโ GPU / CUDA
โ
โโโ Model Serialization
๐ง What Is PyTorch?¶
PyTorch is a tensor-based Deep Learning framework that provides:
Tensor Computation
+
Automatic Differentiation
+
Neural Network APIs
+
Optimization
+
GPU Acceleration
+
Data Loading
A typical PyTorch Deep Learning workflow is:
flowchart LR
DATA["Data"]
TENSOR["PyTorch Tensors"]
MODEL["Neural Network"]
LOSS["Loss"]
AUTOGRAD["Autograd"]
OPT["Optimizer"]
UPDATE["Updated Parameters"]
DATA --> TENSOR
TENSOR --> MODEL
MODEL --> LOSS
LOSS --> AUTOGRAD
AUTOGRAD --> OPT
OPT --> UPDATE
UPDATE --> MODEL
๐ง PyTorch vs TensorFlow¶
Both frameworks provide the fundamental capabilities required for Deep Learning.
| Capability | PyTorch | TensorFlow |
|---|---|---|
| Tensor Operations | torch.Tensor |
tf.Tensor |
| Neural Networks | torch.nn |
tf.keras |
| Automatic Differentiation | torch.autograd |
tf.GradientTape |
| Optimizers | torch.optim |
tf.keras.optimizers |
| Data Pipeline | Dataset / DataLoader |
tf.data |
| GPU | CUDA / device APIs | CUDA / device APIs |
| Model Definition | nn.Module |
Keras Model |
| Training | Custom / higher-level tooling | model.fit() / custom |
| Ecosystem | PyTorch ecosystem | TensorFlow ecosystem |
The important point is that both frameworks implement similar Deep Learning concepts using different APIs and abstractions.
๐ง The PyTorch Mental Model¶
A useful mental model is:
Tensor
โ
Model
โ
Prediction
โ
Loss
โ
Autograd
โ
Gradients
โ
Optimizer
โ
Parameter Update
This loop is repeated across batches and epochs.
๐ข What Is a PyTorch Tensor?¶
A PyTorch tensor is a multidimensional data structure used for numerical computation.
Examples:
Deep Learning models operate primarily on tensors.
๐ Tensor Rank¶
Tensor rank represents the number of dimensions.
Rank 0 โ Scalar¶
Conceptually:
Rank 1 โ Vector¶
Conceptually:
Rank 2 โ Matrix¶
Conceptually:
Rank 3 Tensor¶
๐ง Tensor Dimensions¶
A tensor can be represented as:
For example:
may represent:
flowchart LR
B["Batch<br>32"]
H["Height<br>224"]
W["Width<br>224"]
C["Channels<br>3"]
B --> H
H --> W
W --> C
๐ Importing PyTorch¶
For neural networks:
For optimization:
๐งช Creating Tensors¶
From Python Lists¶
Matrix¶
Random Tensor¶
Normal Distribution¶
Zeros¶
Ones¶
Empty Tensor¶
empty() allocates memory without initializing the values to a meaningful default.
๐ง Tensor Creation Summary¶
| Function | Purpose |
|---|---|
torch.tensor() |
Create from existing data |
torch.zeros() |
Create zeros |
torch.ones() |
Create ones |
torch.rand() |
Uniform random values |
torch.randn() |
Normal random values |
torch.empty() |
Uninitialized tensor |
torch.arange() |
Sequence of values |
torch.linspace() |
Evenly spaced values |
๐ข torch.arange()¶
Result:
๐ torch.linspace()¶
Conceptually:
๐ Inspecting a Tensor¶
Typical information:
๐ง Tensor Shape¶
For:
the shape is:
This commonly means:
๐ง Tensor ndim¶
returns the number of dimensions.
Example:
Result:
๐ง Tensor Data Types¶
Common PyTorch data types include:
torch.float32
torch.float64
torch.float16
torch.bfloat16
torch.int32
torch.int64
torch.uint8
torch.bool
For many Deep Learning workloads:
is a common default.
๐ Converting Data Types¶
Or:
๐ง Why Data Type Matters¶
Data type affects:
For example:
Mixed precision is explored further in advanced training and optimization topics.
๐ข Tensor Indexing¶
Access the first row:
Access the first element:
Access the second row, third element:
โ๏ธ Tensor Slicing¶
selects the first column.
selects the first row.
selects columns 1 and 2.
๐งฎ Tensor Arithmetic¶
a = torch.tensor(
[1, 2, 3]
)
b = torch.tensor(
[4, 5, 6]
)
print(a + b)
print(a - b)
print(a * b)
print(a / b)
These operations are element-wise.
โ๏ธ Matrix Multiplication¶
Matrix multiplication is fundamental to neural networks.
a = torch.tensor(
[
[1.0, 2.0],
[3.0, 4.0]
]
)
b = torch.tensor(
[
[5.0, 6.0],
[7.0, 8.0]
]
)
result = torch.matmul(
a,
b
)
You can also use:
Mathematically:
[ C=AB ]
๐งฎ Dot Product¶
For vectors:
๐ Reshaping¶
PyTorch provides:
Example:
Result:
๐ง view()¶
view() can reshape tensors when the underlying memory layout permits it.
In modern PyTorch code, reshape() is often more convenient because it can handle non-contiguous tensors by creating a copy when necessary.
๐ Flattening¶
The result is:
This is commonly used when transitioning from image feature maps to fully connected layers.
โ๏ธ Transpose¶
For more general dimensions:
๐งฉ permute()¶
permute() changes the ordering of dimensions.
Example:
Shape changes from:
to:
This is particularly important because many PyTorch vision layers commonly use channel-first tensor layouts.
๐ง Tensor Layout¶
A common PyTorch image tensor format is:
where:
For example:
๐ผ๏ธ Image Tensor Pipeline¶
flowchart LR
IMAGE["Image"]
LOAD["Load"]
TENSOR["Tensor"]
FORMAT["N ร C ร H ร W"]
CNN["CNN"]
IMAGE --> LOAD
LOAD --> TENSOR
TENSOR --> FORMAT
FORMAT --> CNN
๐ unsqueeze()¶
unsqueeze() adds a dimension.
Shape:
becomes:
๐ squeeze()¶
squeeze() removes dimensions of size 1.
๐ง Broadcasting¶
PyTorch supports broadcasting for compatible shapes.
Conceptually:
Result:
๐ง Tensor Reduction¶
Common reduction operations include:
Example:
๐ Reduction Along a Dimension¶
x = torch.tensor(
[
[1.0, 2.0],
[3.0, 4.0]
]
)
row_mean = x.mean(
dim=1
)
column_mean = x.mean(
dim=0
)
Understanding dimensions is critical when building neural networks.
๐ง Device Management¶
PyTorch tensors can live on different devices.
Common examples:
A tensor's device can be inspected using:
๐ฅ๏ธ CPU Tensor¶
Typical result:
๐ GPU Availability¶
For NVIDIA CUDA:
Example:
๐ง Selecting a Device¶
A common pattern is:
Then:
๐ง Device-Agnostic Code¶
A production-friendly approach is:
device = torch.device(
"cuda"
if torch.cuda.is_available()
else "cpu"
)
model = model.to(
device
)
x = x.to(
device
)
This allows the same code to run on:
without hardcoding one environment.
๐ง CPU โ GPU¶
๐ง GPU โ CPU¶
When converting tensors to NumPy:
For a GPU tensor:
โ Device Mismatch¶
Model and input tensors generally need to be on compatible devices.
Incorrect:
This can produce runtime errors.
Correct:
flowchart LR
MODEL["Model"]
INPUT["Input"]
DEVICE["Same Device"]
MODEL --> DEVICE
INPUT --> DEVICE
๐ง GPU Memory¶
GPU memory is consumed by:
Therefore, GPU memory usage can increase significantly with:
๐ง PyTorch Autograd¶
PyTorch provides automatic differentiation through:
The key concept is:
Example:
๐งฎ Automatic Differentiation¶
Suppose:
[ y=x^2 ]
Then:
[ \frac{dy}{dx}=2x ]
PyTorch can calculate this automatically.
๐งช Basic Autograd Example¶
Result:
๐ง Autograd Workflow¶
flowchart TD
X["Input Tensor<br>requires_grad=True"]
FORWARD["Forward Computation"]
LOSS["Output / Loss"]
BACK["backward()"]
GRAD["Gradients"]
X --> FORWARD
FORWARD --> LOSS
LOSS --> BACK
BACK --> GRAD
GRAD --> X
๐ง Computational Graph¶
PyTorch tracks operations involving tensors that require gradients.
For:
the computational graph conceptually becomes:
During:
PyTorch traverses the graph backward to compute gradients.
๐ง Gradient Accumulation¶
PyTorch gradients accumulate by default.
Example:
If another backward pass is performed without clearing the gradient, the gradient can accumulate.
Therefore, training loops commonly reset gradients.
๐งน Clearing Gradients¶
With an optimizer:
Then:
Then:
The standard sequence is:
๐ง PyTorch Neural Networks¶
PyTorch provides:
for neural network components.
Common modules include:
๐งฑ nn.Module¶
The fundamental abstraction for neural network models is:
A model generally:
๐งช Basic PyTorch Model¶
import torch
import torch.nn as nn
class SimpleNetwork(
nn.Module
):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(
784,
128
)
self.fc2 = nn.Linear(
128,
64
)
self.output = nn.Linear(
64,
10
)
def forward(
self,
x
):
x = torch.relu(
self.fc1(x)
)
x = torch.relu(
self.fc2(x)
)
return self.output(x)
๐ง PyTorch Model Architecture¶
flowchart LR
INPUT["784 Features"]
FC1["Linear 128"]
RELU1["ReLU"]
FC2["Linear 64"]
RELU2["ReLU"]
OUT["Linear 10"]
INPUT --> FC1
FC1 --> RELU1
RELU1 --> FC2
FC2 --> RELU2
RELU2 --> OUT
๐ง Why nn.Module?¶
nn.Module automatically manages:
- Parameters
- Child modules
- Model hierarchy
- Device movement
- Training/inference modes
- State dictionaries
For example:
returns trainable parameters.
๐ Inspecting Model Parameters¶
model = SimpleNetwork()
for name, parameter in model.named_parameters():
print(
name,
parameter.shape
)
Typical parameters include:
๐งฎ Parameter Count¶
For:
the parameter count is:
[ 784\times128+128 ]
This includes:
๐ง forward()¶
The forward() method defines the forward computation.
Example:
You normally invoke the model as:
rather than calling:
directly.
๐ง Model Call Flow¶
flowchart TD
INPUT["Input"]
MODEL["model(x)"]
CALL["nn.Module Call"]
FORWARD["forward(x)"]
OUTPUT["Output"]
INPUT --> MODEL
MODEL --> CALL
CALL --> FORWARD
FORWARD --> OUTPUT
The nn.Module call mechanism also supports hooks and other framework behavior.
๐ง nn.Linear¶
The PyTorch equivalent of a fully connected layer is:
Mathematically:
[ y=xW^T+b ]
Example:
๐ง Activation Functions¶
PyTorch provides activation functions such as:
Example:
or:
๐งช Using nn.Sequential¶
PyTorch also provides a convenient sequential model API.
model = nn.Sequential(
nn.Linear(
784,
128
),
nn.ReLU(),
nn.Linear(
128,
64
),
nn.ReLU(),
nn.Linear(
64,
10
)
)
This is conceptually similar to Keras Sequential.
๐ง Sequential vs Custom nn.Module¶
| Approach | Best Use |
|---|---|
nn.Sequential |
Simple linear stacks |
Custom nn.Module |
Complex architectures |
| Functional Tensor Operations | Specialized computations |
For architectures involving:
a custom nn.Module is generally more appropriate.
๐ง Training Mode and Evaluation Mode¶
PyTorch models have two important modes:
and:
Training mode enables training-specific behavior such as:
Evaluation mode switches the model to inference behavior.
๐งช Training Mode¶
๐งช Evaluation Mode¶
๐ง torch.no_grad()¶
During inference, gradients are generally unnecessary.
This reduces unnecessary autograd tracking and can lower memory usage.
๐ง Training vs Inference¶
flowchart LR
TRAIN["Training"]
TRAIN --> MODE1["model.train()"]
MODE1 --> FORWARD1["Forward"]
FORWARD1 --> LOSS["Loss"]
LOSS --> BACK["Backward"]
BACK --> UPDATE["Optimizer Step"]
INFER["Inference"]
INFER --> MODE2["model.eval()"]
MODE2 --> NOGRAD["torch.no_grad()"]
NOGRAD --> FORWARD2["Forward"]
FORWARD2 --> OUTPUT["Prediction"]
๐ง PyTorch Training Workflow¶
The fundamental training loop is:
for x_batch, y_batch in train_loader:
optimizer.zero_grad()
predictions = model(
x_batch
)
loss = loss_fn(
predictions,
y_batch
)
loss.backward()
optimizer.step()
The workflow is:
๐ง PyTorch Training Loop Architecture¶
flowchart TD
DATA["DataLoader"]
BATCH["Batch"]
ZERO["optimizer.zero_grad()"]
FORWARD["model(x)"]
LOSS["loss_fn()"]
BACKWARD["loss.backward()"]
STEP["optimizer.step()"]
DATA --> BATCH
BATCH --> ZERO
ZERO --> FORWARD
FORWARD --> LOSS
LOSS --> BACKWARD
BACKWARD --> STEP
STEP --> BATCH
๐ง Loss Functions¶
PyTorch provides many loss functions.
Common examples:
Example:
๐ง Optimizers¶
PyTorch provides:
Common optimizers include:
Example:
๐ง Optimizer Workflow¶
flowchart LR
MODEL["Model"]
PRED["Prediction"]
LOSS["Loss"]
GRAD["Gradients"]
OPT["Optimizer"]
UPDATE["Updated Parameters"]
MODEL --> PRED
PRED --> LOSS
LOSS --> GRAD
GRAD --> OPT
OPT --> UPDATE
UPDATE --> MODEL
๐งช Complete PyTorch Classification Example¶
import torch
import torch.nn as nn
device = torch.device(
"cuda"
if torch.cuda.is_available()
else "cpu"
)
class Classifier(
nn.Module
):
def __init__(self):
super().__init__()
self.network = nn.Sequential(
nn.Linear(
784,
128
),
nn.ReLU(),
nn.Linear(
128,
64
),
nn.ReLU(),
nn.Linear(
64,
10
)
)
def forward(
self,
x
):
return self.network(
x
)
model = Classifier().to(
device
)
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.AdamW(
model.parameters(),
lr=0.001
)
Training:
for epoch in range(
10
):
model.train()
for x_batch, y_batch in train_loader:
x_batch = x_batch.to(
device
)
y_batch = y_batch.to(
device
)
optimizer.zero_grad()
predictions = model(
x_batch
)
loss = loss_fn(
predictions,
y_batch
)
loss.backward()
optimizer.step()
๐ง Why CrossEntropyLoss Expects Logits¶
For multi-class classification, the model commonly returns raw logits:
The final layer is usually:
without explicitly applying:
when using:
CrossEntropyLoss internally combines the required log-softmax and negative log-likelihood behavior.
Therefore:
is the common PyTorch pattern.
๐ง PyTorch Classification Architecture¶
flowchart LR
INPUT["Input"]
FC1["Linear"]
RELU1["ReLU"]
FC2["Linear"]
RELU2["ReLU"]
LOGITS["Class Logits"]
LOSS["CrossEntropyLoss"]
INPUT --> FC1
FC1 --> RELU1
RELU1 --> FC2
FC2 --> RELU2
RELU2 --> LOGITS
LOGITS --> LOSS
๐งช PyTorch Regression Example¶
class RegressionModel(
nn.Module
):
def __init__(self):
super().__init__()
self.network = nn.Sequential(
nn.Linear(
10,
64
),
nn.ReLU(),
nn.Linear(
64,
32
),
nn.ReLU(),
nn.Linear(
32,
1
)
)
def forward(
self,
x
):
return self.network(
x
)
Loss:
Optimizer:
๐ง Classification vs Regression¶
| Problem | Output | Typical Loss |
|---|---|---|
| Binary Classification | Logit / Sigmoid interpretation | BCEWithLogitsLoss |
| Multi-Class Classification | Class Logits | CrossEntropyLoss |
| Regression | Continuous Value | MSELoss / L1Loss |
๐ง PyTorch Parameters¶
Parameters are represented by:
They are tensors that PyTorch tracks as trainable model parameters.
Example:
๐ง Parameter Registration¶
When layers are assigned as attributes of an nn.Module:
PyTorch automatically registers the layer and its parameters.
This allows:
to discover them.
๐ง state_dict()¶
A PyTorch model's parameters and persistent buffers can be accessed through:
Example:
๐พ Saving Model Weights¶
A common approach is:
Load:
The exact loading approach can depend on the PyTorch version and whether the artifact contains weights, a checkpoint, or another object.
๐ง Model Checkpoint¶
A production checkpoint may contain more than model weights.
For example:
checkpoint = {
"model_state_dict":
model.state_dict(),
"optimizer_state_dict":
optimizer.state_dict(),
"epoch":
epoch,
"loss":
loss
}
Save:
This allows training to resume more completely.
๐ง Checkpoint Architecture¶
flowchart TD
TRAIN["Training"]
MODEL["Model State"]
OPT["Optimizer State"]
META["Training Metadata"]
CHECK["Checkpoint"]
TRAIN --> MODEL
TRAIN --> OPT
TRAIN --> META
MODEL --> CHECK
OPT --> CHECK
META --> CHECK
CHECK --> RESUME["Resume Training"]
๐ง PyTorch Device + Model¶
A common production pattern:
For each batch:
๐ง GPU Training Architecture¶
flowchart LR
DATA["CPU Dataset"]
LOADER["DataLoader"]
CPU_BATCH["CPU Batch"]
GPU["GPU"]
MODEL["PyTorch Model"]
GRAD["Gradients"]
UPDATE["Parameter Update"]
DATA --> LOADER
LOADER --> CPU_BATCH
CPU_BATCH --> GPU
GPU --> MODEL
MODEL --> GRAD
GRAD --> UPDATE
UPDATE --> MODEL
โก CUDA Device Selection¶
For multiple GPUs:
Check GPU count:
Get device name:
๐ง CUDA Memory¶
Useful information:
and:
These help diagnose GPU memory consumption.
๐ง CPU โ GPU Data Movement¶
Moving data between devices has a cost.
Therefore, efficient Deep Learning systems try to avoid unnecessary transfers.
โ Common Device Mistake¶
Avoid repeatedly moving tensors:
Instead, structure the pipeline so that device movement occurs at a predictable point.
๐ง Tensor Memory Sharing¶
When converting data from NumPy:
PyTorch may share the underlying memory with the NumPy array.
This differs from:
which generally creates a new tensor and copies the data.
This distinction can matter for performance and mutation behavior.
๐ง Detaching Tensors¶
If a tensor is part of an autograd graph:
creates a tensor that does not require gradient tracking through that history.
Example:
๐ง NumPy Conversion¶
For tensors that do not require gradients:
For tensors that require gradients:
๐ง detach() Mental Model¶
flowchart LR
TENSOR["Tensor"]
GRAPH["Autograd Graph"]
DETACH["detach()"]
OUTPUT["Detached Tensor"]
TENSOR --> GRAPH
GRAPH --> DETACH
DETACH --> OUTPUT
๐ง torch.no_grad() vs detach()¶
These are related but serve different purposes.
torch.no_grad()¶
Disables gradient tracking for operations inside the context.
detach()¶
Creates a tensor disconnected from the current autograd graph.
๐ง inference_mode()¶
For inference workloads, PyTorch also provides:
This can provide additional performance benefits compared with ordinary no_grad() in appropriate inference scenarios.
๐ง PyTorch Model Lifecycle¶
A typical workflow is:
flowchart LR
DATA["Dataset"]
TENSOR["Tensor"]
MODEL["nn.Module"]
COMPILE["Configure Loss + Optimizer"]
TRAIN["Training"]
CHECKPOINT["Checkpoint"]
EVAL["Evaluation"]
DEPLOY["Deployment"]
DATA --> TENSOR
TENSOR --> MODEL
MODEL --> COMPILE
COMPILE --> TRAIN
TRAIN --> CHECKPOINT
CHECKPOINT --> EVAL
EVAL --> DEPLOY
๐ง PyTorch vs Keras Mental Mapping¶
| Concept | Keras / TensorFlow | PyTorch |
|---|---|---|
| Tensor | tf.Tensor |
torch.Tensor |
| Layer | tf.keras.layers.Layer |
nn.Module |
| Model | tf.keras.Model |
nn.Module |
| Dense | Dense |
nn.Linear |
| Conv2D | Conv2D |
nn.Conv2d |
| ReLU | ReLU |
nn.ReLU |
| Gradient | GradientTape |
Autograd |
| Optimizer | tf.keras.optimizers |
torch.optim |
| Dataset Pipeline | tf.data |
Dataset / DataLoader |
| Training | model.fit() |
Training loop |
| Evaluation Mode | training=False |
model.eval() |
| No Gradients | Context / inference logic | torch.no_grad() / inference_mode() |
| Save Model | .keras / SavedModel workflows |
state_dict() / checkpoints |
๐ง The Core PyTorch Training Equation¶
The fundamental parameter update is:
[ \theta_{t+1} = \theta_t - \eta \nabla_\theta L ]
Where:
The PyTorch training loop implements this concept through:
๐ข Enterprise Perspective¶
PyTorch should not be viewed only as a model-building library.
In production, it is one component of a larger Deep Learning platform:
Data Sources
โ
Data Pipeline
โ
Dataset / DataLoader
โ
PyTorch Model
โ
Training Infrastructure
โ
GPU / Accelerator
โ
Checkpoint
โ
Model Validation
โ
Model Registry
โ
Serving
โ
Monitoring
Production concerns include:
- Dataset versioning
- Reproducibility
- Configuration management
- GPU utilization
- Checkpointing
- Model versioning
- Experiment tracking
- Model validation
- Deployment
- Monitoring
- Security
- Cost management
Production Insight
PyTorch gives you significant control over the Deep Learning execution model.
That flexibility is powerful, but it also means the engineering team must explicitly manage:
A model that trains successfully on a developer laptop is not automatically production-ready.
โ Common Mistakes¶
Avoid these common PyTorch mistakes:
- Mixing CPU and GPU tensors
- Forgetting to move the model to the target device
- Forgetting to move input batches to the target device
- Forgetting
optimizer.zero_grad() - Calling
backward()without understanding gradient accumulation - Forgetting
model.train()during training - Forgetting
model.eval()during evaluation - Calculating inference with unnecessary gradient tracking
- Using an inappropriate output activation with a chosen loss function
- Applying Softmax before
CrossEntropyLossunnecessarily - Ignoring tensor shape conventions
- Confusing
view()andreshape() - Misusing
squeeze()and accidentally removing meaningful dimensions - Using incorrect
permute()ordering - Performing unnecessary CPU/GPU transfers
- Converting GPU tensors directly to NumPy
- Failing to detach tensors before converting them for logging
- Saving only partial training state when resuming is required
- Ignoring GPU memory consumption
- Using unnecessarily large batch sizes
- Creating tensors on the wrong device inside the model
๐ง Interview Questions¶
Beginner¶
1. What is PyTorch?¶
PyTorch is a Deep Learning framework providing tensor computation, automatic differentiation, neural network abstractions, optimization, and hardware acceleration.
2. What is a tensor?¶
A tensor is a multidimensional numerical data structure used as the fundamental data representation in PyTorch.
3. What is nn.Module?¶
nn.Module is the base class used to define neural network models and reusable neural network components in PyTorch.
4. What does forward() do?¶
It defines how input data flows through a PyTorch model.
5. What is requires_grad=True?¶
It tells PyTorch to track operations involving the tensor so gradients can be computed through autograd.
Intermediate¶
6. What is autograd?¶
PyTorch's automatic differentiation system that records differentiable operations and computes gradients during backward propagation.
7. What is the standard PyTorch training loop?¶
8. Why call optimizer.zero_grad()?¶
Because PyTorch gradients accumulate by default. Existing gradients need to be cleared before computing the next update.
9. What is the difference between model.train() and model.eval()?¶
They switch the model between training and evaluation behavior, which affects layers such as Dropout and Batch Normalization.
10. Why use torch.no_grad() during inference?¶
It disables gradient tracking for the enclosed operations, reducing unnecessary computation and memory usage.
11. What is state_dict()?¶
It provides the model's parameters and persistent buffers in a dictionary-like structure that is commonly used for saving and loading model state.
12. Why use DataLoader?¶
DataLoader provides batching, iteration, shuffling, and other mechanisms for efficiently feeding data into a training loop. Its details are covered in the next chapter.
Advanced¶
13. Why does PyTorch use nn.Module for both layers and models?¶
Because complex neural networks can be composed hierarchically from reusable modules. This allows PyTorch to recursively track parameters and submodules.
14. Why are model and tensors required to be on compatible devices?¶
Operations generally require tensors participating in the same computation to reside on compatible devices.
15. Why does CrossEntropyLoss typically receive raw logits?¶
PyTorch's CrossEntropyLoss combines the relevant log-softmax and negative-log-likelihood computation internally, so an explicit Softmax layer is normally unnecessary before it.
16. What is the difference between detach() and torch.no_grad()?¶
detach() disconnects a tensor from its existing autograd history. torch.no_grad() disables gradient tracking for operations executed inside its context.
17. Why can view() fail when reshape() works?¶
view() requires a compatible memory layout, while reshape() can create a copy when necessary.
18. Why is permute() important in Computer Vision?¶
Different frameworks and operations expect different dimension orders. PyTorch vision models commonly use:
so tensors may need to be permuted into that format.
19. What consumes GPU memory during training?¶
Typically:
20. How would you design production PyTorch training?¶
Separate:
Dataset
DataLoader
Model
Loss
Optimizer
Training Loop
Evaluation
Checkpointing
Configuration
Logging
and make device placement, reproducibility, checkpointing, and monitoring explicit.
๐งช Practical Exercises¶
Exercise 1 โ Tensor Fundamentals¶
Create:
For each tensor print:
Exercise 2 โ Tensor Operations¶
Implement:
Addition
Subtraction
Multiplication
Matrix Multiplication
Reshape
Transpose
Permute
Squeeze
Unsqueeze
Mean
Sum
Verify the resulting shapes.
Exercise 3 โ Autograd¶
Create:
Calculate:
[ y=x3+2x2+x ]
and use:
to calculate the gradient.
Exercise 4 โ Build a Classification Model¶
Create:
Use:
for training.
Exercise 5 โ Build a Regression Model¶
Create:
Use:
and:
for optimization.
Exercise 6 โ CPU vs GPU¶
Detect:
Train the same model using:
Compare:
Exercise 7 โ Model Checkpointing¶
Save:
Create a checkpoint and resume training from it.
Exercise 8 โ Tensor Layout¶
Create an image batch in:
and convert it to:
using:
Verify the resulting shape.
๐ Key Takeaways¶
- PyTorch is a tensor-based Deep Learning framework.
- Tensors are the fundamental data structure in PyTorch.
- Tensor rank represents the number of dimensions.
- Tensor shape describes the size of each dimension.
- Tensor data types affect memory, precision, and performance.
- PyTorch supports CPU and accelerator-based tensor computation.
- Device management is critical when using GPUs.
torch.autogradprovides automatic differentiation.requires_grad=Trueenables gradient tracking for tensors.backward()computes gradients through the autograd graph.- PyTorch gradients accumulate by default.
optimizer.zero_grad()clears previous gradients.optimizer.step()updates model parameters.nn.Moduleis the fundamental abstraction for PyTorch neural networks.forward()defines the model's forward computation.nn.Linearrepresents a fully connected layer.nn.Sequentialis useful for simple linear architectures.- Complex architectures should generally use custom
nn.Moduleimplementations. model.train()enables training behavior.model.eval()enables evaluation behavior.torch.no_grad()andtorch.inference_mode()help avoid unnecessary gradient tracking during inference.state_dict()is commonly used for model state serialization.- Efficient GPU training requires careful management of device placement and memory.
- PyTorch gives developers significant control over the training process.
- That flexibility also creates greater responsibility for training infrastructure, reproducibility, checkpointing, and production reliability.
๐ Further Reading¶
Continue with:
- 17. PyTorch Autograd, Dataset and DataLoader
- 18. Building Classification and Regression Models
- 19. Convolutional Neural Networks
- 20. CNN Architecture, Optimization and Training
- 22. ResNet, Residual Connections and TorchVision
- 35. GPU-Accelerated Deep Learning
- 36. Deep Learning Training and Model Lifecycle
The next chapter goes deeper into PyTorch Autograd, Dataset, and DataLoader, connecting tensor computation with efficient real-world data pipelines and training workflows.
โก๏ธ Next Chapter¶
17. PyTorch Autograd, Dataset and DataLoader
Enterprise AI Engineering Handbook
Building Production-Grade Enterprise AI Systems โ One Chapter at a Time.