PyTorch Fundamentals · lesson 07/9
Special Tensors (eye, rand, arange, linspace)
PyTorch ships constructors for the arrays that show up in every loop: identity matrices, random weights, integer ranges, and evenly spaced grids. Knowing which one returns which shape and dtype removes a lot of guesswork.
The idea
torch.eye(n, m=None)— identity matrix.torch.eye(3)→(3, 3)with ones on the diagonal. Useful for residual checks and one-hot construction.torch.rand(*size)— uniform in[0, 1), dtypefloat32.torch.randn(*size)— standard normal.torch.randint(low, high, size)— uniform integers, dtypeint64, exclusive ofhigh.torch.arange(start, end, step)— like Pythonrange, exclusive ofend.torch.arange(0, 10, 2)→tensor([0, 2, 4, 6, 8]), dtypeint64unless you pass floats.torch.linspace(start, end, steps)— inclusive of both endpoints, always exactlystepsvalues.
The arange versus linspace split causes classic off-by-one bugs. arange(0, 1, 0.25) yields 4 values and cannot promise it lands on 1.0 exactly, because floating-point addition drifts. linspace(0, 1, 5) yields 5 values and always includes both ends. linspace takes a count, not a gap.
Call torch.manual_seed(0) before random constructors to make a run reproducible. Every constructor also accepts dtype and device.
Worked example
Positional encodings for T = 8 tokens with model width D = 4 start from a geometric frequency range:
p = torch.arange(8)→(8,)f = torch.arange(0, 4, 2)→tensor([0, 2]), shape(2,)p.unsqueeze(1) / 10000 ** (f / 4)→(8, 2), broadcasting positions against frequencies- repeating each column twice and applying
sin/cosgives the(8, 4)encoding
Two more fixtures you will write constantly:
torch.rand(2, 3) < 0.5→ a boolean(2, 3)masktorch.eye(4)→(4, 4), andx @ torch.eye(4)returnsxunchanged for any(B, 4)
In code
import torch
torch.manual_seed(0)
print(torch.eye(3).shape) # torch.Size([3, 3])
print(torch.rand(2, 3).dtype) # torch.float32
print(torch.randint(0, 10, (5,)).dtype) # torch.int64
print(torch.arange(0, 10, 2)) # tensor([0, 2, 4, 6, 8])
print(torch.linspace(0, 1, 5))
# tensor([0.0000, 0.2500, 0.5000, 0.7500, 1.0000])
p = torch.arange(8) # (8,)
f = torch.arange(0, 4, 2).float() # (2,)
angle = p.unsqueeze(1) / 10000 ** (f / 4) # (8, 2)
print(angle.shape) # torch.Size([8, 2])Check yourself
- What is the difference between
arange(0, 1, 0.2)andlinspace(0, 1, 5)? - What shape and dtype does
torch.randint(0, 10, (3, 4))have? - Why does
p.unsqueeze(1) / fproduce(8, 2)instead of raising an error?
Key takeaways
arangeexcludes its endpoint and takes a step;linspaceincludes both ends and takes a count.- Random constructors return
float32by default;randintandarangewith integers returnint64. - Seed before randomness, and check dtype before feeding a model.