Skip to main content

Python PyTorch: How to Access the Metadata of a Tensor in PyTorch

When working with PyTorch tensors, understanding their metadata - such as shape, data type, device, and memory layout - is essential for debugging, ensuring compatibility between operations, and optimizing performance. Metadata tells you everything about a tensor's structure without looking at the actual data.

This guide covers all the key metadata properties and methods available on PyTorch tensors, with practical examples.

What Is Tensor Metadata?​

Tensor metadata is information about the tensor's structure rather than its values. This includes:

  • Shape / Size - the dimensions of the tensor
  • Data type (dtype) - whether it holds floats, integers, etc.
  • Device - whether it's on CPU or GPU
  • Number of elements - total count of values
  • Number of dimensions - how many axes the tensor has
  • Memory layout - how the data is stored in memory

Shape and Size​

The most commonly accessed metadata is a tensor's shape - its dimensions. PyTorch provides two equivalent ways to get this:

import torch

tensor = torch.tensor([
[5, 1, 7],
[7, 2, 9],
[4, 7, 9],
[8, 12, 14],
[2, 4, 7]
])

# Both return the same result
print("Using .size():", tensor.size())
print("Using .shape: ", tensor.shape)

Output:

Using .size(): torch.Size([5, 3])
Using .shape: torch.Size([5, 3])
  • .size() is a method (can accept a dimension argument).
  • .shape is a property (more concise, same as NumPy).

Getting the Size of a Specific Dimension​

import torch

tensor = torch.randn(3, 4, 5)

print("Full shape:", tensor.shape)
print("Dimension 0:", tensor.size(0)) # 3
print("Dimension 1:", tensor.size(1)) # 4
print("Dimension 2:", tensor.size(2)) # 5

Output:

Full shape: torch.Size([3, 4, 5])
Dimension 0: 3
Dimension 1: 4
Dimension 2: 5

Number of Dimensions​

The ndim property (or dim() method) returns how many axes the tensor has:

import torch

scalar = torch.tensor(42)
vector = torch.tensor([1, 2, 3])
matrix = torch.tensor([[1, 2], [3, 4]])
tensor_3d = torch.randn(2, 3, 4)

print(f"Scalar dimensions: {scalar.ndim}")
print(f"Vector dimensions: {vector.ndim}")
print(f"Matrix dimensions: {matrix.ndim}")
print(f"3D tensor dimensions: {tensor_3d.dim()}")

Output:

Scalar dimensions: 0
Vector dimensions: 1
Matrix dimensions: 2
3D tensor dimensions: 3

Total Number of Elements​

Use torch.numel() or .numel() to count the total number of elements in a tensor:

import torch

tensor = torch.tensor([
[5, 1, 7],
[7, 2, 9],
[4, 7, 9],
[8, 12, 14],
[2, 4, 7]
])

print("Shape:", tensor.shape)
print("Total elements:", torch.numel(tensor))
print("Total elements:", tensor.numel()) # Equivalent

Output:

Shape: torch.Size([5, 3])
Total elements: 15
Total elements: 15

The total element count is the product of all dimensions: 5 × 3 = 15.

Data Type (dtype)​

Every tensor has a data type that determines what kind of values it stores:

import torch

int_tensor = torch.tensor([1, 2, 3])
float_tensor = torch.tensor([1.0, 2.0, 3.0])
bool_tensor = torch.tensor([True, False, True])
explicit_tensor = torch.zeros(3, dtype=torch.float16)

print("Integer tensor dtype:", int_tensor.dtype)
print("Float tensor dtype:", float_tensor.dtype)
print("Boolean tensor dtype:", bool_tensor.dtype)
print("Explicit dtype:", explicit_tensor.dtype)

Output:

Integer tensor dtype: torch.int64
Float tensor dtype: torch.float32
Boolean tensor dtype: torch.bool
Explicit dtype: torch.float16
Common PyTorch data types
dtypeDescriptionCommon Use
torch.float3232-bit float (default for floats)Neural network weights
torch.float1616-bit floatMixed precision training
torch.int6464-bit integer (default for ints)Indices, labels
torch.boolBooleanMasks, conditions

Device (CPU vs GPU)​

The .device property tells you where the tensor is stored - CPU or a specific GPU:

import torch

cpu_tensor = torch.tensor([1, 2, 3])
print("Device:", cpu_tensor.device)

# Move to GPU if available
if torch.cuda.is_available():
gpu_tensor = cpu_tensor.to('cuda')
print("GPU Device:", gpu_tensor.device)
else:
print("CUDA not available, tensor stays on CPU")

Output:

Device: cpu
CUDA not available, tensor stays on CPU
Device mismatch errors

Operations between tensors on different devices will raise a RuntimeError. Always check devices before performing operations:

# This would fail if tensors are on different devices:
result = cpu_tensor + gpu_tensor # RuntimeError!

# Fix: move to the same device
result = cpu_tensor.to('cuda') + gpu_tensor

Memory Layout and Strides​

Strides describe how many elements to skip in memory to move to the next position along each dimension. This metadata is important for understanding memory efficiency and contiguity:

import torch

tensor = torch.tensor([
[1, 2, 3],
[4, 5, 6]
])

print("Shape:", tensor.shape)
print("Strides:", tensor.stride())
print("Is contiguous:", tensor.is_contiguous())

Output:

Shape: torch.Size([2, 3])
Strides: (3, 1)
Is contiguous: True

The stride (3, 1) means: moving to the next row requires skipping 3 elements, and moving to the next column requires skipping 1 element.

After Transposing​

import torch

tensor = torch.tensor([[1, 2, 3], [4, 5, 6]])
transposed = tensor.T

print("Transposed shape:", transposed.shape)
print("Transposed strides:", transposed.stride())
print("Is contiguous:", transposed.is_contiguous())

Output:

Transposed shape: torch.Size([3, 2])
Transposed strides: (1, 3)
Is contiguous: False

After transposing, the tensor is no longer contiguous in memory. Some operations require contiguous tensors, which you can create with .contiguous().

Requires Grad (Gradient Tracking)​

The requires_grad property indicates whether PyTorch tracks operations on this tensor for automatic differentiation (essential for training neural networks):

import torch

# By default, requires_grad is False
data = torch.tensor([1.0, 2.0, 3.0])
print("Requires grad:", data.requires_grad)

# Enable gradient tracking
weights = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
print("Requires grad:", weights.requires_grad)
print("Grad function:", weights.grad_fn)

Output:

Requires grad: False
Requires grad: True
Grad function: None

Complete Metadata Summary Function​

Here's a utility function that prints all metadata for any tensor:

import torch

def tensor_info(tensor, name="Tensor"):
"""Print comprehensive metadata about a tensor."""
print(f"--- {name} ---")
print(f" Shape: {tensor.shape}")
print(f" Dimensions: {tensor.ndim}")
print(f" Total elements:{tensor.numel()}")
print(f" Data type: {tensor.dtype}")
print(f" Device: {tensor.device}")
print(f" Strides: {tensor.stride()}")
print(f" Contiguous: {tensor.is_contiguous()}")
print(f" Requires grad: {tensor.requires_grad}")
print()

# Test with different tensors
tensor_info(torch.randn(3, 4, 5), "3D Random Tensor")
tensor_info(torch.zeros(10, dtype=torch.int32), "Integer Zeros")
tensor_info(torch.ones(2, 2, requires_grad=True), "Trainable Weights")

Output:

--- 3D Random Tensor ---
Shape: torch.Size([3, 4, 5])
Dimensions: 3
Total elements:60
Data type: torch.float32
Device: cpu
Strides: (20, 5, 1)
Contiguous: True
Requires grad: False

--- Integer Zeros ---
Shape: torch.Size([10])
Dimensions: 1
Total elements:10
Data type: torch.int32
Device: cpu
Strides: (1,)
Contiguous: True
Requires grad: False

--- Trainable Weights ---
Shape: torch.Size([2, 2])
Dimensions: 2
Total elements:4
Data type: torch.float32
Device: cpu
Strides: (2, 1)
Contiguous: True
Requires grad: True

Quick Reference​

Property/MethodReturnsDescription
.shapetorch.SizeDimensions of the tensor
.size()torch.SizeSame as .shape (can take dim argument)
.ndim / .dim()intNumber of dimensions
.numel()intTotal number of elements
.dtypetorch.dtypeData type of elements
.devicetorch.deviceCPU or GPU location
.stride()tupleMemory strides per dimension
.is_contiguous()boolWhether memory layout is contiguous
.requires_gradboolWhether gradients are tracked
.grad_fnFunction or NoneGradient function (if part of computation graph)

Conclusion​

Accessing tensor metadata in PyTorch is straightforward and essential for building reliable deep learning pipelines.

  • Use .shape and .dtype for everyday checks,
  • Use .device to ensure tensors are on the correct hardware
  • Use .stride() and .is_contiguous() when optimizing memory layout.

Understanding these properties helps you debug shape mismatches, prevent device errors, and write more efficient PyTorch code.