Just as tensors have shapes, they also possess data types, often referred to as dtype
. The data type dictates the kind of numerical values a tensor can hold (like integers or floating-point numbers) and how much memory each element occupies. Selecting the appropriate data type is significant for managing computational resources and ensuring numerical precision in your deep learning models.
PyTorch supports a variety of numerical data types, mirroring those found in NumPy. Each type serves different purposes, balancing memory usage, computational speed, and the range or precision of representable numbers.
dtype
Every tensor has a dtype
attribute that specifies the type of its elements. By default, PyTorch creates floating-point tensors with torch.float32
and integer tensors with torch.int64
. You can check a tensor's data type like this:
import torch
# Default float tensor
a = torch.tensor([1.0, 2.0, 3.0])
print(f"Tensor a: {a}")
print(f"dtype of a: {a.dtype}")
# Default integer tensor
b = torch.tensor([1, 2, 3])
print(f"\nTensor b: {b}")
print(f"dtype of b: {b.dtype}")
Output:
Tensor a: tensor([1., 2., 3.])
dtype of a: torch.float32
Tensor b: tensor([1, 2, 3])
dtype of b: torch.int64
You can also explicitly specify the dtype
during tensor creation:
# Create a tensor with 64-bit floating point numbers
c = torch.tensor([1.0, 2.0], dtype=torch.float64)
print(f"\nTensor c: {c}")
print(f"dtype of c: {c.dtype}")
# Create a tensor with 32-bit integers
d = torch.ones(2, 2, dtype=torch.int32)
print(f"\nTensor d:\n{d}")
print(f"dtype of d: {d.dtype}")
Output:
Tensor c: tensor([1., 2.], dtype=torch.float64)
dtype of c: torch.float64
Tensor d:
tensor([[1, 1],
[1, 1]], dtype=torch.int32)
dtype of d: torch.int32
You can find out the default floating-point type PyTorch uses with torch.get_default_dtype()
.
Here are some of the most commonly used data types in PyTorch:
Floating-Point Types:
torch.float32
(or torch.float
): Standard 32-bit single-precision floating-point. This is the most common type for model parameters and general computations due to its balance of precision and performance on CPUs and GPUs.torch.float64
(or torch.double
): 64-bit double-precision floating-point. Offers higher precision but uses twice the memory and can be significantly slower, especially on GPUs not optimized for double-precision. Use it when high numerical accuracy is absolutely necessary.torch.float16
(or torch.half
): 16-bit half-precision floating-point. Uses less memory and can accelerate computations significantly on modern GPUs (like NVIDIA Tensor Cores). However, its limited range and precision can sometimes lead to numerical instability (overflow or underflow). Often used in mixed-precision training.torch.bfloat16
: An alternative 16-bit format (Brain Floating Point). It has a similar range to float32
but less precision. It's becoming popular for deep learning training on compatible hardware (e.g., newer NVIDIA GPUs, Google TPUs) as it offers memory savings and speedups while often maintaining stability better than float16
.Integer Types:
torch.int64
(or torch.long
): 64-bit signed integer. Default integer type. Frequently used for indexing tensors and representing categorical labels in classification tasks.torch.int32
(or torch.int
): 32-bit signed integer.torch.int16
: 16-bit signed integer.torch.int8
: 8-bit signed integer. Smaller integer types save memory and can be faster for certain operations, often used in model quantization.torch.uint8
).Boolean Type:
torch.bool
: Represents boolean True
or False
values. Essential for logical operations, indexing with masks, and conditional logic.You often need to convert tensors from one data type to another. This is known as type casting. The primary way to cast a tensor is using the .to()
method, which we also saw in the context of moving tensors between devices (CPU/GPU).
float_tensor = torch.tensor([1.1, 2.2, 3.3], dtype=torch.float32)
print(f"Original tensor: {float_tensor}, dtype: {float_tensor.dtype}")
# Cast to int64 using .to()
int_tensor = float_tensor.to(torch.int64)
print(f"Casted to int64: {int_tensor}, dtype: {int_tensor.dtype}") # Note the truncation
# Cast back to float16 using .to()
half_tensor = int_tensor.to(dtype=torch.float16) # Can specify only dtype
print(f"Casted to float16: {half_tensor}, dtype: {half_tensor.dtype}")
Output:
Original tensor: tensor([1.1000, 2.2000, 3.3000]), dtype: torch.float32
Casted to int64: tensor([1, 2, 3]), dtype: torch.int64
Casted to float16: tensor([1., 2., 3.], dtype=torch.float16), dtype: torch.float16
Notice that converting from float to int truncates the decimal part.
PyTorch also provides convenience methods for common casts:
tensor_a = torch.tensor([0, 1, 0, 1])
# Cast to float using .float()
tensor_b = tensor_a.float() # Equivalent to .to(torch.float32)
print(f"\n.float(): {tensor_b}, dtype: {tensor_b.dtype}")
# Cast to long using .long()
tensor_c = tensor_b.long() # Equivalent to .to(torch.int64)
print(f".long(): {tensor_c}, dtype: {tensor_c.dtype}")
# Cast to bool using .bool()
tensor_d = tensor_a.bool() # Equivalent to .to(torch.bool)
print(f".bool(): {tensor_d}, dtype: {tensor_d.dtype}")
Output:
.float(): tensor([0., 1., 0., 1.]), dtype: torch.float32
.long(): tensor([0, 1, 0, 1]), dtype: torch.int64
.bool(): tensor([False, True, False, True]), dtype: torch.bool
Keep in mind that casting usually creates a new tensor in memory with the specified data type, rather than modifying the original tensor in place.
When you perform operations between tensors of different data types, PyTorch often automatically promotes the types to ensure compatibility. The general rule is that integer types interacting with floating-point types will result in a floating-point type. Operations between different floating-point types usually result in the higher-precision type.
int_t = torch.tensor([1, 2], dtype=torch.int32)
float_t = torch.tensor([0.5, 0.5], dtype=torch.float32)
double_t = torch.tensor([0.1, 0.1], dtype=torch.float64)
# int32 + float32 -> float32
result1 = int_t + float_t
print(f"\nint32 + float32 = {result1}, dtype: {result1.dtype}")
# float32 + float64 -> float64
result2 = float_t + double_t
print(f"float32 + float64 = {result2}, dtype: {result2.dtype}")
Output:
int32 + float32 = tensor([1.5000, 2.5000]), dtype: torch.float32
float32 + float64 = tensor([0.6000, 0.6000], dtype=torch.float64), dtype: torch.float64
While convenient, be mindful of automatic type promotion as it might lead to unexpected results or performance implications if not anticipated. Explicit casting using .to()
provides clearer control over the desired data types in your computations.
Understanding and managing tensor data types is an essential part of efficient PyTorch programming. It allows you to control memory footprint, leverage hardware acceleration (like FP16 on GPUs), and maintain the necessary numerical precision for your specific deep learning tasks.
© 2025 ApX Machine Learning