PyTorch Tensors: Creating Them Five Ways

A
Author
23 Oct, 2026 4 min read 0 views

A tensor is PyTorch's n-dimensional array: a scalar is 0-D, a vector 1-D, a matrix 2-D, and a batch of images is usually 4-D. You can create tensors from existing Python data, filled with constants, with random numbers, from numeric ranges, or by copying the shape of another tensor. Knowing these five routes covers almost everything you will write.

1. From Python data with torch.tensor

torch.tensor copies data from lists or nested lists and infers the dtype.

import torch

a = torch.tensor([1, 2, 3])
b = torch.tensor([[1.0, 2.0], [3.0, 4.0]])

print(a, a.dtype)   # tensor([1, 2, 3]) torch.int64
print(b, b.dtype)   # float32 by default for Python floats
print(b.shape)      # torch.Size([2, 2])

Integers become int64 and Python floats become float32. If one element is a float, the whole tensor becomes float. Note that torch.tensor always copies; use it for small literal data. Do not confuse it with torch.Tensor (capital T), which is the class and creates uninitialised float tensors when called with sizes.

2. Filled with constants

zeros = torch.zeros(2, 3)           # all 0.0
ones = torch.ones(2, 3)             # all 1.0
full = torch.full((2, 3), 7.0)      # all 7.0
eye = torch.eye(3)                  # identity matrix
empty = torch.empty(2, 2)           # uninitialised: random leftovers

print(zeros.shape, full[0, 0].item())

Use torch.empty only when you will overwrite every value immediately. It does not clear memory, so printing it shows meaningless numbers. Shapes can be given as separate integers or as a tuple.

3. Random tensors

torch.manual_seed(0)                # make results repeatable

u = torch.rand(2, 3)                # uniform in [0, 1)
n = torch.randn(2, 3)               # normal, mean 0, std 1
i = torch.randint(0, 10, (2, 3))    # integers in [0, 10)
p = torch.randperm(5)               # random permutation of 0..4

print(u)
print(i)

Random tensors are used to initialise weights, create fake test data and shuffle indices. Calling torch.manual_seed first makes the numbers repeat between runs on the same machine and version.

4. Ranges and evenly spaced values

r = torch.arange(0, 10, 2)          # tensor([0, 2, 4, 6, 8])
l = torch.linspace(0, 1, steps=5)   # tensor([0.00, 0.25, 0.50, 0.75, 1.00])
print(r, l)

arange works like Python's range and excludes the end value. linspace includes both ends and you choose the number of points, which is handy for plotting and for making toy datasets.

5. Shaped like another tensor

The *_like functions copy the shape, dtype and device of an existing tensor. This avoids device and dtype mismatches later.

x = torch.rand(4, 5)

z = torch.zeros_like(x)
o = torch.ones_like(x)
r = torch.randn_like(x)

print(z.shape == x.shape)   # True

If x lives on a GPU, zeros_like(x) does too. This is the safest way to create helper tensors inside model code.

Choosing a dtype and device at creation

Most factory functions accept dtype and device arguments, so you do not need a second conversion step.

t = torch.zeros(3, dtype=torch.float64)
h = torch.ones(2, 2, dtype=torch.float16)
print(t.dtype, h.dtype)

Common mistakes

  • Wrong dtype: torch.tensor([1, 2, 3]) is integer. Most layers need floats, so write [1., 2., 3.] or pass dtype=torch.float32.
  • Confusing torch.tensor and torch.Tensor: prefer lowercase torch.tensor for data.
  • Forgetting the seed: when comparing two runs, set torch.manual_seed so random tensors match.
  • Using empty and reading it: its values are undefined.

When to use which

In practice you will mix these constantly. A typical model file calls torch.randn to make dummy input for a shape test, torch.zeros to build an initial hidden state, torch.arange to create position indices, and torch.tensor to wrap a handful of constants such as class weights. The *_like functions appear inside layers, where you want a new tensor that automatically matches whatever device and precision the input has.

A good exercise is to create each kind of tensor, print its shape, dtype and device, and then predict what torch.arange(5) + torch.ones(5) returns before running it. Doing this builds the intuition that tensors of different dtypes can be combined, and the result takes the wider type. Also try creating a tensor with requires_grad=True through a factory function, for example torch.ones(3, requires_grad=True). Factory functions accept that flag, and it is the usual way to create trainable parameters by hand before you meet nn.Parameter.

Quick reference

From data: tensor. Constants: zeros, ones, full, eye. Random: rand, randn, randint, randperm. Ranges: arange, linspace. Same shape as another: zeros_like, ones_like, randn_like. The next post explains the attributes every tensor carries: shape, dtype and device.

Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.