import tensorflow as tfA tensor is an n-dimensional array of numbers — the fundamental data structure for everything that follows in this book.
ndarray, but GPU-accelerated and differentiable.In this section: how to create, reshape, index, operate on, and share memory with tensors.
A single import wires up the framework’s tensor library:
Two attributes you’ll reach for constantly:
.numel() — the total number of elements.shape — the size along each axis (a tuple)<tf.Tensor: shape=(), dtype=int32, numpy=12>
TensorShape([12])
reshape rearranges the same elements into a different shape — the total numel is preserved.
<tf.Tensor: shape=(3, 4), dtype=float32, numpy=
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]], dtype=float32)>
A 12-element vector becomes a 3\times 4 matrix. No data is copied; only the stride metadata changes.
Constant fills take a shape tuple — any rank, any size:
<tf.Tensor: shape=(2, 3, 4), dtype=float32, numpy=
array([[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]], dtype=float32)>
For weight initialization, randn draws from \mathcal{N}(0, 1) (elements sampled independently):
<tf.Tensor: shape=(3, 4), dtype=float32, numpy=
array([[-0.70818615, 1.7719774 , 1.2700077 , -0.3956194 ],
[ 2.7438252 , -0.2637143 , 1.3026156 , -0.7715996 ],
[ 0.0515474 , 0.69860435, -0.965453 , 0.19026478]],
dtype=float32)>
ones, full(shape, value), eye(n), empty (uninitialized, fastest), and *_like(x) round out the family.
For exact control, pass a (nested) list literal — same row-major convention as NumPy:
<tf.Tensor: shape=(3, 4), dtype=int32, numpy=
array([[2, 1, 4, 3],
[1, 2, 3, 4],
[4, 3, 2, 1]], dtype=int32)>
Standard NumPy-style indexing:
X[-1] — the last rowX[1:3] — rows 1 and 2 (3 is exclusive)(<tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 8., 9., 10., 11.], dtype=float32)>,
<tf.Tensor: shape=(2, 4), dtype=float32, numpy=
array([[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]], dtype=float32)>)
Assignment works the same way:
<tf.Variable 'Variable:0' shape=(3, 4) dtype=float32, numpy=
array([[ 0., 1., 2., 3.],
[ 4., 5., 9., 7.],
[ 8., 9., 10., 11.]], dtype=float32)>
A slice on the left sets multiple elements at once:
<tf.Variable 'Variable:0' shape=(3, 4) dtype=float32, numpy=
array([[12., 12., 12., 12.],
[12., 12., 12., 12.],
[ 8., 9., 10., 11.]], dtype=float32)>
Most common math is applied elementwise — same shape in, same shape out.
<tf.Tensor: shape=(12,), dtype=float32, numpy=
array([1.0000000e+00, 2.7182817e+00, 7.3890562e+00, 2.0085537e+01,
5.4598148e+01, 1.4841316e+02, 4.0342880e+02, 1.0966332e+03,
2.9809580e+03, 8.1030840e+03, 2.2026467e+04, 5.9874145e+04],
dtype=float32)>
The arithmetic operators are overloaded — +, -, *, /, ** all run elementwise:
(<tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 3., 4., 6., 10.], dtype=float32)>,
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([-1., 0., 2., 6.], dtype=float32)>,
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 2., 4., 8., 16.], dtype=float32)>,
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([0.5, 1. , 2. , 4. ], dtype=float32)>,
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 1., 4., 16., 64.], dtype=float32)>)
cat glues tensors along an existing axis. Pick the axis with dim:
dim=0 → stack rows (more rows out)dim=1 → stack columns (wider matrix out)(<tf.Tensor: shape=(6, 4), dtype=float32, numpy=
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[ 2., 1., 4., 3.],
[ 1., 2., 3., 4.],
[ 4., 3., 2., 1.]], dtype=float32)>,
<tf.Tensor: shape=(3, 8), dtype=float32, numpy=
array([[ 0., 1., 2., 3., 2., 1., 4., 3.],
[ 4., 5., 6., 7., 1., 2., 3., 4.],
[ 8., 9., 10., 11., 4., 3., 2., 1.]], dtype=float32)>)
Comparison operators broadcast and return a boolean tensor of the same shape — useful for masking entries that satisfy a condition:
<tf.Tensor: shape=(3, 4), dtype=bool, numpy=
array([[False, True, False, True],
[False, False, False, False],
[False, False, False, False]])>
When tensors of different shapes meet, the smaller one is virtually expanded along missing dimensions — no data copy.
The rule: dimensions of size 1 stretch; everything else must match.
(<tf.Tensor: shape=(3, 1), dtype=int32, numpy=
array([[0],
[1],
[2]], dtype=int32)>,
<tf.Tensor: shape=(1, 2), dtype=int32, numpy=array([[0, 1]], dtype=int32)>)
Y = Y + XEvery assignment of an arithmetic expression allocates a new tensor. Matters a lot when Y is gigabytes:
False
id(Y) == before is False: Y now points at a brand-new buffer.
Pre-allocate the output and write into it with Z[:] = ...:
id(Z): 130085433189312
id(Z): 130085433189312
If the original value of X isn’t needed afterward, the most ergonomic forms are X[:] = X + Y or X += Y:
<tf.Tensor: shape=(3, 4), dtype=float32, numpy=
array([[ 8., 9., 26., 27.],
[24., 33., 42., 51.],
[56., 57., 58., 59.]], dtype=float32)>
Tensors and NumPy ndarrays convert cheaply — most frameworks share storage with NumPy when possible:
(numpy.ndarray, tensorflow.python.framework.ops.EagerTensor)
arange / zeros / ones / randn / tensor(list) — create..shape, .numel(), reshape — inspect / reorganize.[i, j], [a:b, c:d] — read and write slices.+ - * / **, cat, ==, sum — element-wise ops, joins, comparisons, reductions..numpy() / .item() — leave the tensor world.