tensorflow review
TensorFlow 2.21.0 is a compiled machine-learning framework with tensor operations, automatic differentiation, Keras training APIs, data pipelines, distributed execution, and export paths for serving and devices. The 2.21 release drops Python 3.9 and removes TensorBoard as an automatic dependency. It also adds JPEG XL decoding, public `NoneTensorSpec`, and more int2, int4, uint4, and int16x8 operations in TensorFlow Lite. The framework fits training plus a TensorFlow deployment chain; it is excessive when the job is only array math or inference of an exported model.
TensorFlow 2.21.0 installed successfully in 14 seconds but occupied 2,027 MB and took 6.43 seconds to import in our CPU sandbox, so its deployment reach must justify a very large dependency. Choose it for existing TensorFlow, Keras, Serving, TPU, or Lite systems; start elsewhere for lightweight inference or research ecosystems centered on PyTorch and JAX.
We installed it
| Install | ✓ · 14s | 32 packages on disk · 2027 MB |
| Import | ✓ | import tensorflow in 6.43s · compiled extensions · requires Python >=3.10 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does tensorflow install cleanly?
Yes. In a fresh container with an empty cache, pip install tensorflow finished in 14 seconds, leaving 32 packages and 2027 MB on disk. pip-audit reported no known vulnerabilities.
What does tensorflow need to run?
Python >=3.10, and a platform wheel with compiled extensions. In our run import tensorflow succeeded in 6.43s.
tensorflow or torch: which should you use?
torch: Use it for most new research, LLM, and community-model work where upstream examples are PyTorch-first. TensorFlow 2.21.0 installed successfully in 14 seconds but occupied 2,027 MB and took 6.43 seconds to import in our CPU sandbox, so its deployment reach must justify a very large dependency.
When should you not use tensorflow?
Disk and cold-start cost matter; our CPU install occupied 2,027 MB and import tensorflow took 6.43 seconds
Use it if
- An existing production stack already uses TensorFlow models, SavedModel, TensorFlow Serving, or Lite deployment
- Keras `compile` and `fit` cover the training loop while lower-level `GradientTape` remains available
- The organization is committed to Google Cloud, TPUs, TFX, or TensorFlow-specific tooling
- One project must train models and export optimized artifacts for mobile or embedded inference
- Disk and cold-start cost matter; our CPU install occupied 2,027 MB and `import tensorflow` took 6.43 seconds
- The project is research-first or LLM-first and depends on current PyTorch or JAX implementations appearing upstream
- You need native Windows GPU training on TensorFlow 2.21; official pip documentation says 2.10 was the last release supporting that path and directs current users to WSL2
- You only need inference for an ONNX model; a dedicated runtime avoids TensorFlow's 32-package installation in our test
- Python 3.9 support is mandatory; version 2.21 removes it and requires Python 3.10 or newer
Setup reality
Our TensorFlow 2.21.0 install completed in 14 seconds in a fresh Python 3.12 container. It left 32 packages using 2,027 MB on disk, and pip-audit reported 0 known vulnerabilities. The measured distribution declared 34 direct dependencies and Python 3.10 or newer. It includes compiled .so extensions, carries Apache 2.0 licensing, and has no py.typed marker. Import succeeded in 6.43 seconds.
Use a dedicated virtual environment because TensorFlow constrains packages such as NumPy, protobuf, Keras, h5py, and ml-dtypes. Version 2.21 no longer installs TensorBoard as a dependency, so add TensorBoard explicitly when training callbacks or workflows need it. Prebuilt wheels avoid a source compile on supported platforms; an unsupported Python, CPU architecture, or operating system can turn installation into a compatibility problem rather than a normal pip step.
Linux NVIDIA users can install tensorflow[and-cuda], then must verify that tf.config.list_physical_devices('GPU') sees the device. Native Windows GPU support stopped after 2.10; current Windows GPU instructions use WSL2. The official macOS pip page states that there is no official GPU support there. These platform paths are different enough that CI should test the same wheel and accelerator setup used in production.
TensorFlow may initialize hardware and emit platform logs during its 6.43-second import. GPU memory policy must be set before the first operation touches a device. tf.data pipelines need batching and prefetching to prevent accelerators waiting on input. Saving also has two distinct targets in current Keras: .keras for a reloadable Keras model and model.export() for a SavedModel serving artifact. Validate converted Lite models because quantization can change predictions.
Patterns
Train a logits-based classifier keras-classifier
import tensorflow as tf
model = tf.keras.Sequential([
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10),
])
model.compile(
optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'],
)
model.fit(x_train, y_train, epochs=5, validation_split=0.1)The last layer returns logits, so `from_logits=True` is required. Do not add softmax while leaving that flag enabled.
Shuffle, batch, and prefetch training data tf-data
ds = (
tf.data.Dataset.from_tensor_slices((features, labels))
.shuffle(10_000)
.batch(32)
.prefetch(tf.data.AUTOTUNE)
)
model.fit(ds, epochs=5)Shuffle before batching and prefetch last. A slow input pipeline can leave an available GPU idle.
Separate Keras saving from serving export save-and-export
model.save('model.keras')
reloaded = tf.keras.models.load_model('model.keras')
# SavedModel artifact for serving
model.export('serving/1')Current Keras uses `.keras` for editable reload and `model.export()` for a SavedModel inference artifact.
Write one compiled training step gradient-tape
optimizer = tf.keras.optimizers.Adam(1e-3)
@tf.function
def train_step(x, y):
with tf.GradientTape() as tape:
logits = model(x, training=True)
loss = loss_fn(y, logits)
grads = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
return lossDifferentiated operations must run inside the tape. Custom loops must pass `training=True` when layers need training behavior.
List GPUs before enabling memory growth gpu-memory
gpus = tf.config.list_physical_devices('GPU')
print(gpus)
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)Set memory growth before any TensorFlow operation initializes the GPU, or the configuration change raises an error.
Create a reproducible folder-based split folder-images
train_ds = tf.keras.utils.image_dataset_from_directory(
'data/train',
image_size=(180, 180),
batch_size=32,
validation_split=0.2,
subset='training',
seed=42,
)Use the same seed and 0.2 split in the separate validation call. Class indices follow alphabetically sorted folder names.
Restore and persist the best validation state early-stop
callbacks = [
tf.keras.callbacks.EarlyStopping(
monitor='val_loss', patience=3, restore_best_weights=True
),
tf.keras.callbacks.ModelCheckpoint(
'best.keras', monitor='val_loss', save_best_only=True
),
]
model.fit(ds, validation_data=val_ds, epochs=100, callbacks=callbacks)`restore_best_weights=True` avoids leaving the in-memory model at the final, possibly worse epoch.
Freeze a pretrained backbone correctly transfer-learning
base = tf.keras.applications.EfficientNetV2B0(
include_top=False, weights='imagenet', pooling='avg'
)
base.trainable = False
inputs = tf.keras.Input(shape=(224, 224, 3))
x = base(inputs, training=False)
outputs = tf.keras.layers.Dense(num_classes)(x)
model = tf.keras.Model(inputs, outputs)Calling the frozen base with `training=False` keeps BatchNormalization layers in inference mode during head training.
Compile a repeated scoring function graph-function
@tf.function
def score(x):
return tf.reduce_sum(model(x, training=False), axis=-1)
print(score.pretty_printed_concrete_signatures())New shapes, dtypes, and Python-side arguments can retrace the function. Stable tensor signatures reduce that cost.
Quantize a model for Lite inference tflite-convert
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()
with open('model.tflite', 'wb') as file:
file.write(tflite_model)Default optimization can reduce artifact size and alter numerical output. Test accuracy on the converted model before release.
Set mixed precision before model creation mixed-precision
tf.keras.mixed_precision.set_global_policy('mixed_float16')
model = build_model()
outputs = tf.keras.layers.Activation('linear', dtype='float32')(x)Build layers after setting the policy and keep numerically sensitive final output in float32.
Seed libraries and require deterministic ops deterministic-run
import tensorflow as tf
tf.keras.utils.set_random_seed(42)
tf.config.experimental.enable_op_determinism()Deterministic execution can reduce performance, and operations without a deterministic implementation may raise instead of running.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| torch | PyPI | Use it for most new research, LLM, and community-model work where upstream examples are PyTorch-first. |
| jax | PyPI | Use it for composable `grad`, `jit`, and `vmap` transforms or a JAX-first TPU codebase. |
| keras | PyPI | Use standalone Keras 3 when one model API should remain portable across TensorFlow, JAX, and PyTorch backends. |
| onnxruntime | PyPI | Use it when the task is serving an exported ONNX model rather than training one. |
More ai / ml guides
openai · mcp · huggingface-hub · @modelcontextprotocol/sdk · scikit-learn · tiktoken · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

