Code Beginner easy · 5 min

Reshaping: .view() vs .reshape()

What you will learn
.view() and .reshape() both change tensor dimensions, but they have different memory requirements and use cases.

Why this matters

You'll reshape tensors constantly: preparing data for models, flattening after convolution layers, batching. Picking the wrong one causes crashes or silent inefficiency.

Skip if: Don't use .view() on tensors that are not contiguous in memory (e.g., after certain transpose operations). Use .reshape() instead, or call .contiguous() first.

Explanation

.view() and .reshape() both change a tensor's shape without changing its data. The key difference: .view() requires the tensor to be contiguous in memory: laid out in a single block. .reshape() handles non-contiguous tensors automatically by copying data if needed, making it more flexible but potentially slower.

Mechanically, .view() is a zero-copy operation that only changes the "view" of the underlying storage. .reshape() will create a contiguous copy if the tensor isn't already contiguous. In practice, .reshape() is safer and nearly always the right choice for beginners; .view() is an optimization when you know your tensor is contiguous and performance matters.

Use .reshape() by default. Only switch to .view() after profiling reveals it's a bottleneck, or when you're certain the tensor is contiguous.

Analogy

Think of a bookshelf: .view() just relabels which books belong to which shelf without moving them: works only if they're already in the right physical order. .reshape() picks up books, reorganizes them physically if needed, and puts them back. More work, but always works.

Code

python
import torch

# Create a 2x3 tensor
t = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(f"Original shape: {t.shape}")
print(f"Original tensor:\n{t}")
print()

# Using .reshape() — safe, always works
reshaped = t.reshape(3, 2)
print(f"After .reshape(3, 2):\n{reshaped}")
print()

# Using .view() — works here because tensor is contiguous
viewed = t.view(6)
print(f"After .view(6): {viewed}")
print()

# Demonstrate the contiguity check
print(f"Is original tensor contiguous? {t.is_contiguous()}")
print()

# Transpose breaks contiguity
transposed = t.t()
print(f"After .t() (transpose), is contiguous? {transposed.is_contiguous()}")
print()

# .reshape() works on non-contiguous tensor
reshaped_noncontig = transposed.reshape(6)
print(f".reshape() on non-contiguous: {reshaped_noncontig}")
print()

# .view() fails on non-contiguous tensor — uncomment to see error
# viewed_noncontig = transposed.view(6)  # RuntimeError
print("Note: transposed.view(6) would raise RuntimeError")
print("But transposed.contiguous().view(6) would work (with copy overhead)")
contiguous_first = transposed.contiguous().view(6)
print(f"transposed.contiguous().view(6): {contiguous_first}")
Output
Original shape: torch.Size([2, 3])
Original tensor:
tensor([[1, 2, 3],
        [4, 5, 6]])

After .reshape(3, 2):
tensor([[1, 2],
        [3, 4],
        [5, 6]])

After .view(6): tensor([1, 2, 3, 4, 5, 6])

Is original tensor contiguous? True

After .t() (transpose), is contiguous? False

.reshape() on non-contiguous: tensor([1, 4, 2, 5, 3, 6])

Note: transposed.view(6) would raise RuntimeError
But transposed.contiguous().view(6) would work (with copy overhead)
transposed.contiguous().view(6): tensor([1, 4, 2, 5, 3, 6])

What just happened?

The code created a 2×3 tensor, reshaped it to 3×2 using both methods (both work on contiguous tensors), then demonstrated the critical difference: after transposing (which breaks memory contiguity), .reshape() silently handles it, but .view() would crash. We showed the workaround: calling .contiguous() first, which copies data.

Common gotcha

Developers often use .view() habitually without checking contiguity, then hit a cryptic RuntimeError: view size is incompatible with input tensor after operations like transpose, permute, or slicing. The error message doesn't say 'not contiguous': it says 'incompatible': which is confusing.

Error recovery

RuntimeError: view size is incompatible with input tensor
Your tensor is not contiguous in memory. Use .reshape() instead, or call .contiguous() before .view(): tensor.contiguous().view(shape)
RuntimeError: cannot reshape tensor of size X into shape Y
The total number of elements doesn't match. For reshape([2, 3]) on a 6-element tensor, that works. For reshape([2, 4]), it fails. Count elements: 2×4=8, but you only have 6.

Experienced dev note

In PyTorch 2.11+, just use .reshape() everywhere unless you've profiled and found .view() to be a genuine bottleneck. The performance difference is negligible in most real workloads, and .reshape() prevents hard-to-debug crashes when tensors flow through unexpected code paths (like inside a framework or after gradient operations). Old PyTorch tutorials pushed .view() as the 'correct' method; that's outdated advice.

Check your understanding

You have a tensor of shape [4, 5, 6] that you transposed to [6, 5, 4]. You need to flatten it to 1D. Would you use .view(120) or .reshape(120)? Why? What would happen if you chose wrong?

Show answer hint

A correct answer explains that transpose breaks contiguity, so .view(120) would fail with a RuntimeError. You must use .reshape(120) (or .contiguous().view(120) if .view() is required for some reason). The 'why' is memory layout: transposed tensors are physically rearranged in memory.

VERSION No breaking changes between PyTorch 2.6.x and 2.11.x for .view() and .reshape(). Both remain stable. However, PyTorch 2.11.x improved .reshape() performance on non-contiguous tensors through better memory layout optimization.
NEXT

Next, learn about <code>tensor.squeeze()</code> and <code>tensor.unsqueeze()</code>, which remove and add dimensions of size 1: a complementary reshaping technique for data preparation.

Community Notes

No notes yetBe the first to share a version-specific fix or tip.