The Story — Ice Cube Trays
A tensor is the same. It has a fixed shape (rows, columns, and more). Every slot holds the same dtype, such as float32.
TensorFlow gives you many ways to make a tray. You can fill it with your own numbers (tf.constant), with zeros or ones (tf.zeros, tf.ones), or with random numbers (tf.random). Neural networks need all three.
In this lesson you will learn every common way to create a tensor. You will also see why random tensors matter so much, and how to make them repeatable with a seed.
tf.constant — Tensors From Your Data
tf.constant(value, dtype=None, shape=None) makes a tensor from a Python number, a list, a nested list, or a NumPy array.
If you do not give a dtype, TensorFlow guesses it from the values.
import tensorflow as tf
import numpy as np
scalar = tf.constant(7) # rank 0
vector = tf.constant([1.5, 2.5, 3.5]) # rank 1
matrix = tf.constant([[1, 2, 3],
[4, 5, 6]]) # rank 2
print(scalar)
print(vector)
print(matrix)
How TensorFlow Picks the dtype
| You pass | dtype you get | Note |
|---|---|---|
tf.constant(5) | int32 | Python int |
tf.constant(5.0) | float32 | Python float |
tf.constant(True) | bool | |
tf.constant("hi") | string | Bytes, not maths |
tf.constant(np.array([1.0])) | float64 | NumPy default is float64! |
from_numpy = tf.constant(np.array([1.0, 2.0]))
print("From NumPy:", from_numpy.dtype)
fixed = tf.constant(np.array([1.0, 2.0]), dtype=tf.float32) # ask for float32
print("With dtype:", fixed.dtype)
filled = tf.constant(9, shape=(2, 3)) # repeat one value into a shape
print(filled)
Neural network weights are float32. NumPy arrays are float64 by default. Mixing them gives an error later. Pass dtype=tf.float32 when you convert NumPy data.
Tensors Must Be Rectangles
Every row must have the same length. A "jagged" list fails.
try:
tf.constant([[1, 2, 3], [4, 5]])
except ValueError as e:
print("ValueError:", str(e).split(".")[0])
For jagged data, TensorFlow has tf.ragged.constant. We cover it later in the course.
Tensors Are Immutable
You cannot change a value inside a tf.constant. You create a new tensor instead. For values that must change, such as model weights, use tf.Variable.
t = tf.constant([1, 2, 3])
try:
t[0] = 100
except TypeError as e:
print("TypeError:", e)
v = tf.Variable([1, 2, 3])
v[0].assign(100) # Variables can change
print(v.numpy())
Filled Tensors — zeros, ones, fill, eye
print(tf.zeros([2, 3])) # all 0.0, float32
print(tf.ones([3], dtype=tf.int32)) # all 1
print(tf.fill([2, 2], 7.5)) # any value you like
print(tf.eye(3)) # identity matrix
Copy Another Tensor's Shape — zeros_like / ones_like
weights = tf.constant([[0.3, -1.2], [2.0, 0.7]])
grad_sum = tf.zeros_like(weights) # same shape and dtype, all zeros
print(grad_sum)
Sequences — tf.range and tf.linspace
print(tf.range(5)) # 0..4, like Python range
print(tf.range(2, 12, delta=3)) # start, limit (not included), step
print(tf.linspace(0.0, 1.0, num=5)) # 5 points, end included
| You choose the step |
| End value is not included |
| Keeps int dtype for int inputs |
| You choose the count |
| End value is included |
| Needs float start and stop |
Try It — The Tensor Factory
Pick a function and type the arguments. Press Create. Watch the tensor fill up, and see the Python code for it. Shape examples: 4, 2,3, 2,2,3.
Random Tensors — tf.random
Why do we need random numbers? A new neural network starts with random weights. If all weights were zero, every neuron would learn the same thing. Randomness breaks this symmetry. Random numbers are also used for dropout, data augmentation and shuffling.
tf.random.set_seed(42)
print(tf.random.normal([2, 3], mean=0.0, stddev=1.0))
print(tf.random.uniform([2, 3], minval=0, maxval=10, dtype=tf.int32))
print(tf.random.truncated_normal([4], stddev=0.5))
Other useful random ops:
tf.random.set_seed(7)
cards = tf.range(10)
print("shuffled :", tf.random.shuffle(cards).numpy())
logits = tf.math.log([[0.7, 0.2, 0.1]]) # class probabilities
print("samples :", tf.random.categorical(logits, num_samples=8).numpy())
Seeds — Making Randomness Repeatable
TensorFlow uses two seeds together: a global seed (tf.random.set_seed) and an optional op seed (the seed= argument).
tf.random.set_seed(1)
print("run 1:", tf.random.uniform([3]).numpy(), tf.random.uniform([3]).numpy())
tf.random.set_seed(1) # reset -> the same sequence again
print("run 2:", tf.random.uniform([3]).numpy(), tf.random.uniform([3]).numpy())
Notice: within one run, the two calls give different numbers. But after resetting the seed, the whole sequence repeats.
The Modern Way — tf.random.Generator
A Generator keeps its own random state. It does not depend on the global seed. This is the clearest way to control randomness.
g = tf.random.Generator.from_seed(2024)
print(g.normal([3]).numpy())
g2 = tf.random.Generator.from_seed(2024) # same seed -> same numbers
print(g2.normal([3]).numpy())
Stateless Random Ops
Stateless ops always return the same output for the same seed pair. They are handy inside tf.data pipelines.
a = tf.random.stateless_normal([3], seed=[1, 2])
b = tf.random.stateless_normal([3], seed=[1, 2])
print(a.numpy())
print("Same?", bool(tf.reduce_all(a == b)))
Try It — Random Distribution Explorer
Draw many random numbers and see them as a histogram. Change the settings and press Sample. Use the same seed twice to get the same picture. Leave the seed empty for new numbers each time.
(1) Compare normal and truncated_normal with the same stddev. See the tails cut off at ±2 stddev. (2) Set samples to 50, then 20000. Small samples look messy. Large samples match the true shape. (3) Type seed 42, sample twice. The picture does not change.
Cheat Sheet
| Function | Example | Default dtype | Use it for |
|---|---|---|---|
tf.constant | tf.constant([[1, 2]]) | inferred | Your own data |
tf.zeros / tf.ones | tf.zeros([3, 4]) | float32 | Biases, masks |
tf.fill | tf.fill([2, 2], 5) | from value | Any constant value |
tf.zeros_like | tf.zeros_like(x) | same as x | Match another tensor |
tf.eye | tf.eye(3) | float32 | Identity matrix |
tf.range | tf.range(0, 10, 2) | int32 | Indices, steps |
tf.linspace | tf.linspace(0., 1., 5) | float32 | Plot points |
tf.random.normal | tf.random.normal([3]) | float32 | Weights, noise |
tf.random.uniform | tf.random.uniform([3]) | float32 | Weights, dropout masks |
Golden Rules
dtype=tf.float32. NumPy's default float64 causes dtype errors later.tf.Variable for values that change.tf.zeros_like / tf.ones_like to match another tensor's shape and dtype.tf.random.set_seed() at the top of your script, or use a tf.random.Generator, to make results repeatable.