Hello! Welcome to the third lesson in our course.
In our previous session, we established the critical difference between a tensor view and a copy. We learned that views share the underlying data with the original tensor, making them memory-efficient, while copies are completely independent. You also saw that many common tensor operations, particularly those that change a tensor's dimensionality, often return views.
Today, we will take a practical look at the most common functions for manipulating tensor dimensions: reshape, squeeze, and unsqueeze. This lesson directly addresses the learning outcome: to use reshape, squeeze, and unsqueeze to alter tensor dimensions. Mastering these tools is fundamental for any machine learning practitioner, as you constantly need to mold your data to fit the expected input shapes of different neural network layers.
1. reshape() and view(): The General-Purpose Shapers
The most frequent reshaping task is changing a tensor's shape while preserving the total number of elements. For instance, you might have a flat list of 12 numbers that you want to represent as a 3x4 matrix. This is precisely what reshape() is for.
A key constraint for any reshape operation is that the total number of elements must remain constant. A tensor with 12 elements can be reshaped to (3, 4), (2, 6), (4, 3), (2, 2, 3), etc., because the product of the dimensions in each case is 12. You cannot, however, reshape it to (3, 5).
In the previous lesson, we touched upon the difference between reshape() and view(). Let's solidify that understanding with a practical demonstration. The main takeaway is that view() requires the tensor's data to be contiguous in memory (laid out sequentially), while reshape() is more flexible—it will try to return a view, but if it can't, it will create a copy. For this reason, reshape() is often the safer, more convenient choice.
The following video provides a clear, code-driven explanation of reshape and view, and also introduces a very useful trick for inferring dimensions.
Complete Pytorch Tensor Tutorial (Initializing Tensors, Math, Indexing, Reshaping)
This video from Aladdin Persson's 'Complete Pytorch Tensor Tutorial' demonstrates how to use reshape and view and explains the important practical differences between them.
Please watch the segment from 00:44:58 to 00:49:27. Focus on: The basic syntax of .view() and .reshape(). The concept of a contiguous tensor and why .view() fails on a non-contiguous tensor (like after a transpose). How .reshape() is a 'safe bet' that handles both cases.
As you saw, reshape() is more robust. Another powerful feature it shares with view() is the ability to automatically calculate one of the dimensions. If you pass -1 as one of the dimensions, PyTorch will infer its size based on the total number of elements and the other specified dimensions.
For example, if you have a tensor x with 100 elements and you call x.reshape(5, -1), PyTorch will automatically calculate the second dimension to be 20, resulting in a (5, 20) tensor. This is extremely common in practice, especially when dealing with batches of data where you want to reshape each item in the batch but leave the batch dimension untouched.
For a more detailed written explanation with code examples that you can run yourself, the article "Expert Guide to Resizing PyTorch Tensors" is an excellent resource.
Expert Guide to Resizing PyTorch Tensors
This article provides a concise comparison of torch.reshape and torch.view.
Read the section 'a) Using torch.reshape and torch.view: Differences and When to Use Each'. It reinforces the concepts from the video and includes performance tips that will be relevant to you as a developer.
2. unsqueeze() and squeeze(): Adding and Removing Dimensions
Sometimes, you don't want to overhaul the shape completely but just add or remove dimensions of size 1. This is where unsqueeze() and squeeze() come in. These operations are essential for aligning tensors for operations like broadcasting (which we'll cover soon) and for managing batch dimensions.
unsqueeze(dim)adds a new dimension of size 1 at the position specified bydim.squeeze(dim)removes a dimension of size 1 at the positiondim. Ifdimis not specified, it removes all dimensions of size 1.
A classic use case for unsqueeze() is adding a batch dimension. A model typically expects a batch of data, e.g., a tensor of shape (batch_size, channels, height, width). If you have a single image with shape (channels, height, width), you can use unsqueeze(0) to add the batch dimension, resulting in a (1, channels, height, width) tensor that the model can now process.
The following image provides a fantastic visual intuition for these operations.

Now, let's see how this is implemented in code.
Complete Pytorch Tensor Tutorial (Initializing Tensors, Math, Indexing, Reshaping)
Let's return to Aladdin Persson's tutorial, where he demonstrates unsqueeze and squeeze.
Watch the following two short segments: unsqueeze (00:53:21 - 00:54:12): See how to add a dimension at the beginning (dim=0) or end (dim=1) of a vector. squeeze (00:54:12 - 00:54:50): Observe how squeeze acts as the inverse of unsqueeze, removing the singleton dimensions.
These two functions are simple but powerful. They don't change the number of elements or the underlying data; like view, they are very fast operations that just change the tensor's metadata (its shape and stride).
3. Practical Application: Flattening Data for a Neural Network
Let's tie these concepts together with a concrete machine learning example. One of the most common reshaping operations inside a neural network is flattening.
Consider a Convolutional Neural Network (CNN) used for image classification. The initial layers are convolutional, and they process the input image as a 2D (or 3D, if you include channels) grid. These layers are great at extracting spatial features like edges and textures. However, the final part of the network usually consists of standard "fully connected" or "dense" layers, which expect their input as a 1D vector of features.
To bridge the gap between the convolutional layers and the dense layers, we must flatten the output of the last convolutional layer. This means taking a multi-dimensional feature map (e.g., shape (batch_size, channels, height, width)) and reshaping it into a 2D tensor of shape (batch_size, features), where features is simply channels * height * width.
This is a perfect job for reshape().
Flatten, Reshape, and Squeeze Explained - Tensors for Deep Learning with PyTorch
The deeplizard channel has a video that explains this exact flattening process with excellent visuals.
Watch the segment from 00:05:10 to 00:07:44. It explains what flattening is, why it's necessary when moving from convolutional to fully connected layers, and how to implement it using reshape(batch_size, -1).
As the video shows, an operation like output.reshape(batch_size, -1) is all you need. This keeps the batch dimension intact while collapsing all the other dimensions (channels, height, width) into a single feature vector for each item in the batch. This is an operation you will see in nearly every CNN implementation.
Conclusion
In this lesson, we moved from the theory of tensor memory to the practice of tensor manipulation. We've added three essential functions to your toolkit that allow you to mold data into the precise shapes required by machine learning models.
Key Takeaways:
reshape()changes a tensor's shape while keeping the number of elements constant. It's a flexible and safe choice that will create a copy if a view isn't possible.- The
-1argument inreshape()is a powerful shortcut to automatically infer a dimension's size. unsqueeze()adds a dimension of size 1, which is crucial for tasks like adding a batch dimension to a single data sample.squeeze()removes dimensions of size 1, cleaning up tensor shapes.- These operations are fundamental in ML, with flattening (using
reshape) being a prime example of preparing data for different neural network layers.
Preview of the Next Lesson:
We noted that reshape() sometimes returns a view and sometimes a copy. In the next lesson, we will delve into exactly what determines this behavior. You will learn to predict whether a reshaping operation will produce a view or a copy, a skill that deepens your understanding of tensor memory layout and helps you write more efficient code.