Models are compositions of these ops; reading TF code means reading them fluently.
Arithmetic operators work element-wise and follow NumPy broadcasting rules: shapes are aligned from the right and each dimension must match or be 1. Math functions live in tf.math (many also at top level): tf.exp, tf.sqrt, tf.nn.relu, tf.nn.softmax.
a @ b or tf.matmul(a, b) multiplies matrices, batching over leading dimensions.
Reductions are named tf.reduce_*: reduce_sum, reduce_mean, reduce_max, reduce_any. They take axis and keepdims arguments; without axis they reduce everything to a scalar. tf.argmax(x, axis) gives indices.
The biggest surprise for NumPy users: TensorFlow does not promote dtypes implicitly. Adding an int32 tensor to a float32 tensor raises an error instead of converting. Use tf.cast(x, tf.float32) explicitly. Python scalars are fine: x * 2 adapts the literal to the tensor's dtype. This strictness catches precision bugs early, at the price of some casting noise.
Shape helpers you will reach for constantly: tf.reshape(x, [-1, 4]), tf.transpose, tf.expand_dims, tf.squeeze, tf.concat and tf.stack.
Example
import tensorflow as tf
a = tf.constant([[1.0, 2.0], [3.0, 4.0]])
b = tf.constant([10.0, 20.0])
print((a + b).numpy()) # [[11. 22.] [13. 24.]] broadcast
print((a @ a).numpy()) # [[ 7. 10.] [15. 22.]]
print(tf.reduce_sum(a, axis=0).numpy()) # [4. 6.]
print(tf.reduce_mean(a).numpy()) # 2.5
print(tf.argmax(a, axis=1).numpy()) # [1 1]
print(tf.nn.softmax([0.0, 0.0]).numpy()) # [0.5 0.5]
i = tf.constant([1, 2]) # int32
# a[0] + i -> error: no implicit int32 -> float32 promotion
print((a[0] + tf.cast(i, tf.float32)).numpy()) # [2. 4.]
print((a * 2).numpy()) # Python scalars adapt: [[2. 4.] [6. 8.]]Remember
- Element-wise ops broadcast like NumPy;
@is matmul - Reductions are
tf.reduce_*withaxisandkeepdims - No implicit dtype promotion: use
tf.cast
Watch out for
- Mixing int and float tensors and getting an InvalidArgumentError; cast explicitly.