TensorFlow Interview Questions
This document provides a curated list of TensorFlow interview questions commonly asked in technical interviews for Machine Learning Engineer, Deep Learning, and Senior Data Scientist roles. It covers fundamental concepts of tensors and automatic differentiation, the Keras model APIs, high-performance input pipelines with tf.data, and production topics like distributed training and serving.
This is updated frequently but right now this is the most exhaustive list of type of questions being asked.
Premium Interview Questions
What Is a Tensor and How Does It Differ from a NumPy Array? - Google, Amazon Interview Question
Difficulty: đĸ Easy | Tags: Tensors, Fundamentals | Asked by: Google, Amazon, Netflix
View Answer
A tensor is TensorFlow's core data structure: an immutable, n-dimensional array with a uniform data type (dtype) and a shape. Scalars are rank-0 tensors, vectors are rank-1, matrices are rank-2, and so on.
Key differences from a NumPy array:
- Tensors are immutable: operations return new tensors rather than mutating in place. Use
tf.Variablewhen you need mutable state. - Tensors can live on a GPU or TPU, not just host memory.
- Tensors integrate with automatic differentiation and graph tracing via
tf.function.
import tensorflow as tf
import numpy as np
t = tf.constant([[1, 2], [3, 4]], dtype=tf.float32)
print(t.shape) # (2, 2)
print(t.dtype) # <dtype: 'float32'>
print(t.ndim) # 2
# Interop is zero-copy on CPU
arr = t.numpy() # tensor -> ndarray
back = tf.convert_to_tensor(arr) # ndarray -> tensor
Interop note: Many TensorFlow ops accept NumPy arrays directly and NumPy functions accept tensors, because tensors implement the array interface. The conversion shares memory on CPU when possible, so it is cheap but not free on GPU (data must be copied to host).
Interviewer's Insight
- Explains immutability and why
tf.Variableexists for trainable state - Mentions device placement and autodiff as the real reasons to use tensors over ndarrays
- Real-world: Netflix serves recommendation models where tensors move between GPU compute and NumPy post-processing
Eager Execution vs tf.function Graphs: What Changes? - Google, OpenAI Interview Question
Difficulty: đĄ Medium | Tags: tf.function, Graphs | Asked by: Google, OpenAI, Meta
View Answer
Eager execution (the TensorFlow 2.x default) runs operations immediately, like normal Python, which makes debugging with prints and breakpoints easy. tf.function traces your Python function once and compiles it into a static dataflow graph that runs faster and can be serialized, distributed, and deployed.
| Aspect | Eager | tf.function graph |
|---|---|---|
| Execution | Op-by-op immediately | Compiled graph |
| Debugging | Easy (print, pdb) | Harder (runs once at trace) |
| Speed | Slower | Faster, fused ops |
| Python side effects | Run every call | Run only during tracing |
import tensorflow as tf
@tf.function
def add(a, b):
print("tracing") # prints only during tracing
return a + b
add(tf.constant(1), tf.constant(2)) # prints "tracing"
add(tf.constant(3), tf.constant(4)) # no print, reuses graph
Gotcha: Python side effects (printing, appending to lists, mutating globals) execute only during tracing, not on later calls. Use tf.print for graph-time printing and keep functions pure with respect to Python state.
Interviewer's Insight
- Distinguishes trace-time from run-time behavior
- Knows Python side effects fire only during tracing, a classic bug source
- Real-world: OpenAI wraps training steps in tf.function to fuse ops and cut per-step Python overhead
Explain tf.function Retracing and How to Avoid It - Meta, NVIDIA Interview Question
Difficulty: đ´ Hard | Tags: tf.function, Tracing, Performance | Asked by: Meta, NVIDIA, Google
View Answer
A tf.function creates a separate ConcreteFunction (graph) for each distinct input signature, defined by the dtype and shape of tensor arguments and the identity of Python arguments. Every new signature triggers a retrace, which is expensive and, in loops, can silently destroy performance.
Common causes of excessive retracing:
- Passing Python scalars (like
1,2,3) instead of tensors, since each value is a new signature. - Feeding tensors with varying shapes (variable-length batches or sequences).
- Passing new Python objects each call.
import tensorflow as tf
# Bad: Python ints cause a retrace per value
@tf.function
def f(x):
return x * 2
for i in range(3):
f(i) # 3 traces
# Fix 1: pass tensors, not Python scalars
for i in range(3):
f(tf.constant(i)) # 1 trace
# Fix 2: fix the signature for variable shapes
@tf.function(input_signature=[tf.TensorSpec(shape=[None], dtype=tf.float32)])
def g(x):
return tf.reduce_sum(x)
Diagnostics: enable tf.data.experimental.enable_debug_mode() or set @tf.function(experimental_get_tracing_count) style checks, and watch for repeated tracing warnings. An input_signature with None dimensions makes the graph shape-polymorphic so variable batch sizes reuse one graph.
Practical rule: keep the number of distinct signatures small and bounded; if you see retracing every iteration, your loop is running in eager-equivalent cost with graph overhead on top.
Interviewer's Insight
- Defines retracing in terms of input signatures (dtype + shape + Python identity)
- Uses input_signature with None dims to make graphs shape-polymorphic
- Real-world: NVIDIA tunes tf.function signatures so dynamic sequence lengths do not retrace on every GPU step
tf.Variable vs tf.constant: When to Use Each? - Amazon, Apple Interview Question
Difficulty: đĸ Easy | Tags: Variables, Fundamentals | Asked by: Amazon, Apple, Microsoft
View Answer
tf.constant creates an immutable tensor whose value is fixed at creation. tf.Variable creates a mutable tensor whose value can be updated in place with assign, assign_add, and similar methods. Trainable model parameters (weights, biases) are always variables.
import tensorflow as tf
c = tf.constant([1.0, 2.0])
# c.assign(...) would fail: constants are immutable
w = tf.Variable([1.0, 2.0])
w.assign([3.0, 4.0]) # replace value
w.assign_add([1.0, 1.0]) # in-place add -> [4.0, 5.0]
print(w.trainable) # True by default
Key points:
- Variables are tracked automatically by
GradientTapefor gradient computation. - Set
trainable=Falsefor state you update manually but do not optimize (for example, batch-norm moving averages or step counters). - Constants get baked into the graph, so large constants bloat serialized models; prefer variables or inputs for big data.
Interviewer's Insight
- Connects mutability to trainable parameters and optimizer updates
- Knows
trainable=Falsefor non-optimized state like BN statistics - Real-world: Apple on-device models freeze most variables with trainable=False and fine-tune only a small head
How Does GradientTape Compute Gradients? - OpenAI, NVIDIA Interview Question
Difficulty: đĄ Medium | Tags: Autodiff, GradientTape | Asked by: OpenAI, NVIDIA, Google
View Answer
tf.GradientTape records operations onto a tape during the forward pass, then applies reverse-mode automatic differentiation to compute gradients of a target with respect to sources. By default it watches all trainable tf.Variable objects touched inside the context.
import tensorflow as tf
x = tf.Variable(3.0)
with tf.GradientTape() as tape:
y = x ** 2 + 2 * x # y = x^2 + 2x
dy_dx = tape.gradient(y, x) # dy/dx = 2x + 2 = 8.0
print(dy_dx.numpy()) # 8.0
Important behaviors:
- The tape is consumed after one
gradientcall. Usepersistent=Trueto compute multiple gradients. - Constants are not watched by default; call
tape.watch(t)to differentiate with respect to a non-variable tensor. - Only ops executed inside the
withblock are recorded.
x = tf.constant(3.0)
with tf.GradientTape(persistent=True) as tape:
tape.watch(x)
y = x ** 2
z = x ** 3
print(tape.gradient(y, x).numpy()) # 6.0
print(tape.gradient(z, x).numpy()) # 27.0
del tape
Higher-order gradients come from nesting tapes: an outer tape differentiates the gradient produced by an inner tape.
Interviewer's Insight
- Explains reverse-mode autodiff and why the tape records the forward pass
- Knows
persistent=Trueandtape.watchfor constants and multiple targets - Real-world: OpenAI custom training loops use GradientTape to apply gradient clipping and mixed-precision scaling before the optimizer step
Explain Broadcasting Rules in TensorFlow - Microsoft, Meta Interview Question
Difficulty: đĄ Medium | Tags: Shapes, Broadcasting | Asked by: Microsoft, Meta, Amazon
View Answer
Broadcasting lets ops combine tensors of different shapes without copying data, by virtually stretching dimensions. TensorFlow follows the same rules as NumPy: align shapes from the trailing (rightmost) dimension and, for each dimension, they are compatible if they are equal or one of them is 1.
import tensorflow as tf
a = tf.constant([[1], [2], [3]]) # shape (3, 1)
b = tf.constant([10, 20, 30]) # shape (3,)
print((a + b).shape) # (3, 3)
Here a is (3, 1) and b is treated as (1, 3); both stretch to (3, 3).
Step-by-step for (3, 1) and (3,):
- Right-align:
(3, 1)and(_, 3)where the missing left dim is treated as 1, giving(1, 3). - Dimension 0:
3vs1-> stretch to3. - Dimension 1:
1vs3-> stretch to3. - Result:
(3, 3).
Common mistakes:
- Shapes like
(4,)and(3,)are incompatible (neither is 1 and they are unequal) and raise an error. - Silent broadcasting can hide bugs; a
(N, 1)label accidentally broadcasting against(N, N)predictions produces a wrong loss without any error.
Use tf.broadcast_to to make broadcasting explicit and tf.reshape or tf.expand_dims to add size-1 dimensions deliberately.
Interviewer's Insight
- States the trailing-dimension alignment rule precisely
- Flags silent broadcasting as a real correctness hazard in loss functions
- Real-world: Microsoft debugging pipelines add explicit shape asserts to catch unintended broadcasts before they corrupt training
What Are Ragged and Sparse Tensors and When Do You Use Them? - Airbnb, Uber Interview Question
Difficulty: đĄ Medium | Tags: Ragged, Sparse, Tensors | Asked by: Airbnb, Uber, Google
View Answer
Standard tensors are dense and rectangular. Ragged and sparse tensors handle two different irregular-data cases efficiently.
RaggedTensor: rows of variable length, such as tokenized sentences or user session sequences. It avoids padding waste while still supporting batched ops.
import tensorflow as tf
rt = tf.ragged.constant([[1, 2, 3], [4], [5, 6]])
print(rt.shape) # (3, None)
print(rt.row_lengths()) # [3, 1, 2]
print((rt + 1).to_list()) # [[2, 3, 4], [5], [6, 7]]
SparseTensor: mostly zeros stored as indices, values, and dense_shape, ideal for one-hot categorical features, bag-of-words, or huge embedding lookups.
st = tf.sparse.SparseTensor(
indices=[[0, 0], [1, 2]],
values=[10, 20],
dense_shape=[3, 4],
)
dense = tf.sparse.to_dense(st) # zeros everywhere except the two entries
| Type | Irregularity | Storage | Typical use |
|---|---|---|---|
| Ragged | Variable row length | Values + row splits | Text, sequences |
| Sparse | Mostly zeros | Indices + values | One-hot, embeddings |
Rule of thumb: ragged for variable length, sparse for mostly empty. Both convert to dense when a downstream op requires it, but converting a huge sparse tensor to dense can blow up memory.
Interviewer's Insight
- Separates variable-length (ragged) from mostly-zero (sparse) cleanly
- Warns that dense conversion of large sparse tensors is a memory trap
- Real-world: Uber and Airbnb feature stores use sparse tensors for high-cardinality categorical inputs feeding embedding layers
How Do You Control Device Placement Across CPU and GPU? - NVIDIA, Netflix Interview Question
Difficulty: đĸ Easy | Tags: Devices, GPU | Asked by: NVIDIA, Netflix, Amazon
View Answer
TensorFlow places ops on the GPU automatically when a compatible GPU is visible, falling back to CPU otherwise. You override placement explicitly with tf.device.
import tensorflow as tf
print(tf.config.list_physical_devices('GPU'))
with tf.device('/CPU:0'):
a = tf.constant([1.0, 2.0])
with tf.device('/GPU:0'):
b = tf.constant([3.0, 4.0])
c = b * 2 # runs on GPU if available
Key points:
- Enable
tf.debugging.set_log_device_placement(True)to log where each op runs. - Ops that lack a GPU kernel automatically fall back to CPU, which can cause hidden host-device copies that slow training.
- Use
tf.config.set_visible_devicesto restrict which GPUs a process sees, andset_memory_growthto avoid grabbing all GPU memory at startup.
gpus = tf.config.list_physical_devices('GPU')
if gpus:
tf.config.experimental.set_memory_growth(gpus[0], True)
Interop caution: moving data between CPU and GPU (for example, calling .numpy() inside a training loop) forces a copy and a synchronization, so keep hot-path computation on one device.
Interviewer's Insight
- Knows automatic placement plus explicit
tf.deviceoverrides - Flags hidden host-device copies and CPU fallback as performance killers
- Real-world: NVIDIA profiling flows use set_memory_growth and device-placement logs to keep the full training step on the GPU
How Do You Ensure Reproducibility with Random Seeds? - Google, Apple Interview Question
Difficulty: đ´ Hard | Tags: Reproducibility, Seeds | Asked by: Google, Apple, Microsoft
View Answer
Reproducibility requires controlling every source of randomness: weight initialization, data shuffling, dropout, and augmentation. TensorFlow has both a global seed and operation-level seeds, and results depend on both.
import tensorflow as tf
tf.random.set_seed(42) # global seed
print(tf.random.uniform([2])) # deterministic given the global seed
How the two seeds interact:
- With only a global seed, each op still derives its own deterministic stream, so repeated identical programs match.
- An op-level seed (
tf.random.uniform(..., seed=1)) makes that specific op deterministic regardless of surrounding ops. - Setting neither gives fully nondeterministic results.
For full determinism, also:
import numpy as np, random, os
os.environ['PYTHONHASHSEED'] = '0'
random.seed(42)
np.random.seed(42)
tf.random.set_seed(42)
tf.config.experimental.enable_op_determinism() # deterministic GPU kernels
Remaining gotchas:
- Some GPU kernels (certain reductions, atomics) are nondeterministic unless
enable_op_determinism()is set, at a speed cost. tf.datapipelines must setshuffle(..., seed=...)and avoidnum_parallel_callsnondeterminism by settingdeterministic=True.- Use the stateless generators (
tf.random.stateless_uniform) when you need results that depend only on an explicit seed tensor, which is ideal for reproducible per-example augmentation.
Interviewer's Insight
- Distinguishes global vs op-level seeds and how they combine
- Knows enable_op_determinism and the deterministic tf.data flags for true reproducibility
- Real-world: Google research paper reproductions pin seeds, enable op determinism, and use stateless RNGs so runs match bit for bit
Sequential vs Functional vs Subclassed Models - Google, Meta Interview Question
Difficulty: đĸ Easy | Tags: Keras, Model API | Asked by: Google, Meta, Amazon
View Answer
Keras offers three ways to build models, each trading simplicity for flexibility.
| API | Best for | Limitation |
|---|---|---|
| Sequential | Plain stacks of layers | Single input, single output, no branching |
| Functional | Multi-input/output, shared layers, DAGs | Static graph, no dynamic control flow |
| Subclassed | Fully custom call, dynamic behavior | No automatic graph, harder to serialize |
Sequential: a linear stack where each layer feeds the next.
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
seq = keras.Sequential([
layers.Input(shape=(784,)),
layers.Dense(128, activation="relu"),
layers.Dense(10, activation="softmax"),
])
Functional: you connect layers as callables on tensors, so branching and merging are natural.
inputs = keras.Input(shape=(784,))
x = layers.Dense(128, activation="relu")(inputs)
outputs = layers.Dense(10, activation="softmax")(x)
func = keras.Model(inputs, outputs)
Subclassed: you write imperative logic in call, useful for research and dynamic graphs.
class MyModel(keras.Model):
def __init__(self):
super().__init__()
self.d1 = layers.Dense(128, activation="relu")
self.d2 = layers.Dense(10, activation="softmax")
def call(self, x):
return self.d2(self.d1(x))
Rule of thumb: reach for Sequential for prototypes, Functional for most production models because it stays serializable and inspectable, and subclassing only when you need imperative control flow.
Interviewer's Insight
- Knows the Functional API is a DAG of layers, not arbitrary Python
- Understands subclassed models lose static shape inference and
model.summary()until built - Real-world: most Google production Keras models use the Functional API for tooling support
What Do compile, fit, evaluate, and predict Do? - Amazon, Microsoft Interview Question
Difficulty: đĸ Easy | Tags: Keras, Training | Asked by: Amazon, Microsoft, Apple
View Answer
These four methods form the core Keras training workflow.
compileconfigures the model for training: it attaches the optimizer, loss function, and metrics. Nothing trains yet; it just wires up the objective.fitruns the actual training loop over batches for a number of epochs, updating weights via backpropagation.evaluateruns a forward pass over a dataset and returns the loss and metrics with no weight updates.predictreturns raw model outputs (probabilities, logits, regressions) for inference.
model.compile(
optimizer=keras.optimizers.Adam(1e-3),
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
history = model.fit(
x_train, y_train,
validation_data=(x_val, y_val),
epochs=10, batch_size=32,
)
test_loss, test_acc = model.evaluate(x_test, y_test)
probs = model.predict(x_new)
Key distinctions:
fitreturns aHistoryobject whose.historydict holds per-epoch loss and metric values.evaluateuses the same loss and metrics set incompile, but in inference mode (dropout off, BatchNorm using running stats).predictdoes not need labels and never touches the loss.
Interviewer's Insight
- Knows compile does not run computation, it only configures
- Understands layers behave differently in training vs inference (dropout, BatchNorm)
- Real-world: Amazon teams log
Historyobjects to compare hyperparameter sweeps
How Do Keras Callbacks Work? - Netflix, Uber Interview Question
Difficulty: đĸ Easy | Tags: Keras, Callbacks | Asked by: Netflix, Uber, Google
View Answer
Callbacks are objects passed to fit that hook into the training loop at defined points (epoch start/end, batch start/end) to observe or alter behavior without rewriting the loop.
Three you should know cold:
EarlyStoppinghalts training when a monitored metric stops improving, avoiding wasted epochs and overfitting.ModelCheckpointsaves the model (or just weights) periodically, typically the best so far.TensorBoardlogs scalars, histograms, and graphs for visualization.
callbacks = [
keras.callbacks.EarlyStopping(
monitor="val_loss", patience=3, restore_best_weights=True
),
keras.callbacks.ModelCheckpoint(
"best.keras", monitor="val_loss", save_best_only=True
),
keras.callbacks.TensorBoard(log_dir="./logs"),
]
model.fit(x_train, y_train,
validation_data=(x_val, y_val),
epochs=50, callbacks=callbacks)
Important flags:
restore_best_weights=Truerolls the model back to the epoch with the best monitored value, not the last one.patienceis how many epochs of no improvement to tolerate before stopping.save_best_only=Trueoverwrites the checkpoint only when the metric improves.
You can also write a custom callback by subclassing keras.callbacks.Callback and overriding methods like on_epoch_end.
Interviewer's Insight
- Knows
restore_best_weightsmatters, otherwise you keep the overfit final epoch - Understands callbacks compose; order matters when one modifies state
- Real-world: Netflix uses ModelCheckpoint to resume long recommender training runs
How Do You Write a Custom Keras Layer? - Meta, NVIDIA Interview Question
Difficulty: đĄ Medium | Tags: Keras, Custom Layers | Asked by: Meta, NVIDIA, OpenAI
View Answer
Subclass keras.layers.Layer and implement three methods:
__init__stores configuration (units, activation) but should not create weights that depend on input shape.build(input_shape)creates weights lazily once the input shape is known, usingself.add_weight.call(inputs)defines the forward computation.
import tensorflow as tf
from tensorflow import keras
class DenseWithScale(keras.layers.Layer):
def __init__(self, units, **kwargs):
super().__init__(**kwargs)
self.units = units
def build(self, input_shape):
self.w = self.add_weight(
shape=(input_shape[-1], self.units),
initializer="glorot_uniform", trainable=True, name="w",
)
self.b = self.add_weight(
shape=(self.units,), initializer="zeros",
trainable=True, name="b",
)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
def get_config(self):
config = super().get_config()
config.update({"units": self.units})
return config
Why build instead of __init__? It defers weight creation until the layer sees real input, so you do not hardcode the input dimension. Keras calls build automatically on the first forward pass.
Why get_config? It makes the layer serializable, so a saved model can be reloaded with keras.models.load_model when you pass custom_objects.
Use self.add_weight(trainable=False) for non-trained state like running statistics.
Interviewer's Insight
- Knows
buildenables shape-agnostic layers and lazy weight creation - Implements
get_configfor round-trip serialization - Real-world: NVIDIA writes custom fused layers to hit specific GPU kernels
How Do You Define Custom Losses and Metrics? - Microsoft, Airbnb Interview Question
Difficulty: đĄ Medium | Tags: Keras, Losses | Asked by: Microsoft, Airbnb, Amazon
View Answer
A custom loss is any callable taking (y_true, y_pred) and returning a scalar (or per-sample tensor Keras reduces).
import tensorflow as tf
from tensorflow import keras
def huber_loss(y_true, y_pred, delta=1.0):
error = y_true - y_pred
abs_error = tf.abs(error)
quadratic = tf.minimum(abs_error, delta)
linear = abs_error - quadratic
return 0.5 * quadratic**2 + delta * linear
For a loss with hyperparameters or state, subclass keras.losses.Loss so it serializes cleanly.
class HuberLoss(keras.losses.Loss):
def __init__(self, delta=1.0, **kwargs):
super().__init__(**kwargs)
self.delta = delta
def call(self, y_true, y_pred):
error = y_true - y_pred
abs_error = tf.abs(error)
quadratic = tf.minimum(abs_error, self.delta)
linear = abs_error - quadratic
return 0.5 * quadratic**2 + self.delta * linear
def get_config(self):
return {**super().get_config(), "delta": self.delta}
Custom metrics differ from losses: they accumulate state across batches. Subclass keras.metrics.Metric and use add_weight plus update_state, result, and reset_state.
class F1Score(keras.metrics.Metric):
def __init__(self, name="f1", **kwargs):
super().__init__(name=name, **kwargs)
self.tp = self.add_weight(name="tp", initializer="zeros")
self.fp = self.add_weight(name="fp", initializer="zeros")
self.fn = self.add_weight(name="fn", initializer="zeros")
def update_state(self, y_true, y_pred, sample_weight=None):
y_pred = tf.cast(y_pred > 0.5, tf.float32)
y_true = tf.cast(y_true, tf.float32)
self.tp.assign_add(tf.reduce_sum(y_true * y_pred))
self.fp.assign_add(tf.reduce_sum((1 - y_true) * y_pred))
self.fn.assign_add(tf.reduce_sum(y_true * (1 - y_pred)))
def result(self):
precision = self.tp / (self.tp + self.fp + 1e-7)
recall = self.tp / (self.tp + self.fn + 1e-7)
return 2 * precision * recall / (precision + recall + 1e-7)
def reset_state(self):
for v in self.variables:
v.assign(0.0)
Key point: metrics are stateful and averaged over an epoch, losses are computed per batch to drive gradients.
Interviewer's Insight
- Knows metrics need
update_state/result/reset_statefor correct epoch aggregation - Understands a loss must be differentiable; a metric like F1 need not be
- Real-world: Microsoft tracks F1 as a metric while optimizing a smooth surrogate loss
How Does Transfer Learning and Fine-Tuning Work in Keras? - Google, Apple Interview Question
Difficulty: đĄ Medium | Tags: Transfer Learning, Keras | Asked by: Google, Apple, Meta
View Answer
Transfer learning reuses a network pretrained on a large dataset as a feature extractor for a new, usually smaller, task. The standard recipe has two phases.
Phase 1: feature extraction. Freeze the pretrained backbone and train only a fresh head.
import tensorflow as tf
from tensorflow import keras
base = keras.applications.ResNet50(
include_top=False, weights="imagenet",
input_shape=(224, 224, 3), pooling="avg",
)
base.trainable = False # freeze all backbone weights
inputs = keras.Input((224, 224, 3))
x = keras.applications.resnet50.preprocess_input(inputs)
x = base(x, training=False) # keep BatchNorm in inference mode
outputs = keras.layers.Dense(5, activation="softmax")(x)
model = keras.Model(inputs, outputs)
model.compile(optimizer=keras.optimizers.Adam(1e-3),
loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
model.fit(train_ds, epochs=10)
Phase 2: fine-tuning. Unfreeze part or all of the backbone and continue training with a much lower learning rate so you do not destroy the pretrained weights.
base.trainable = True
# optionally keep early layers frozen
for layer in base.layers[:100]:
layer.trainable = False
model.compile(optimizer=keras.optimizers.Adam(1e-5), # 10-100x smaller
loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
model.fit(train_ds, epochs=10)
Critical details:
- Pass
training=Falsewhen calling the base so frozen BatchNorm layers use running statistics rather than updating them. - You must recompile after changing
trainablefor the change to take effect in the training step. - Fine-tune with a small learning rate; large steps wipe out useful pretrained features.
Interviewer's Insight
- Knows BatchNorm must stay in inference mode while the backbone is frozen
- Understands you recompile after toggling
trainable - Real-world: Apple fine-tunes vision backbones on-device for personalization
.keras Format vs SavedModel: How Do You Save and Load Models? - Amazon, NVIDIA Interview Question
Difficulty: đĄ Medium | Tags: Serialization, Keras | Asked by: Amazon, NVIDIA, Netflix
View Answer
Keras 3 has two main serialization targets, plus a weights-only path.
| Format | Call | Contains | Use case |
|---|---|---|---|
.keras | model.save("m.keras") | Architecture, weights, optimizer, config | Default; resume training in Keras |
| SavedModel | model.export("dir") | Serving graph (signatures) | TF Serving, TFLite, cross-language deploy |
| Weights only | model.save_weights("w.weights.h5") | Just weights | Reload into identical architecture |
The .keras file is a single zip archive holding the full model. It is the recommended format for saving and reloading inside Keras.
model.save("model.keras")
reloaded = keras.models.load_model("model.keras")
For custom layers or losses, either register them or pass custom_objects:
@keras.saving.register_keras_serializable()
class DenseWithScale(keras.layers.Layer):
...
reloaded = keras.models.load_model(
"model.keras",
custom_objects={"HuberLoss": HuberLoss},
)
SavedModel via export produces a language-neutral inference graph for deployment. It drops the Python training state and keeps only serving signatures.
model.export("saved_model_dir") # for TF Serving / TFLite
infer = tf.saved_model.load("saved_model_dir")
When to use which:
- Iterating and resuming training in Python:
.keras. - Deploying to TF Serving, mobile, or another runtime:
exportto SavedModel. - Sharing weights across code that rebuilds the architecture:
save_weights.
Interviewer's Insight
- Knows
.keraskeeps optimizer state so training resumes exactly - Understands
exportis for serving, not for resuming training - Real-world: NVIDIA exports SavedModels then converts to TensorRT for inference
How Do You Write a Custom Training Loop with GradientTape? - OpenAI, Uber Interview Question
Difficulty: đ´ Hard | Tags: Custom Training, GradientTape | Asked by: OpenAI, Uber, Google
View Answer
When fit is too rigid (multiple optimizers, custom gradient manipulation, GANs, RL), write the loop yourself with tf.GradientTape.
import tensorflow as tf
from tensorflow import keras
model = keras.Sequential([
keras.layers.Dense(64, activation="relu"),
keras.layers.Dense(10),
])
optimizer = keras.optimizers.Adam(1e-3)
loss_fn = keras.losses.SparseCategoricalCrossentropy(from_logits=True)
train_acc = keras.metrics.SparseCategoricalAccuracy()
@tf.function # compile to a graph for speed
def train_step(x, y):
with tf.GradientTape() as tape:
logits = model(x, training=True) # training=True for dropout/BN
loss = loss_fn(y, logits)
grads = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
train_acc.update_state(y, logits)
return loss
for epoch in range(epochs):
train_acc.reset_state()
for x_batch, y_batch in train_ds:
loss = train_step(x_batch, y_batch)
print(f"epoch {epoch}: acc={train_acc.result():.3f}")
What each piece does:
GradientTaperecords operations on watched tensors (trainable variables by default) so you can compute gradients of the loss.tape.gradient(loss, vars)does reverse-mode autodiff.optimizer.apply_gradientsapplies the update rule to the variables.@tf.functiontraces the Python function into a static graph, giving large speedups; keep it side-effect free.training=Truein the forward call activates dropout and BatchNorm updates.
Gradient tricks: clip with tf.clip_by_global_norm(grads, 1.0) before applying, or use tape.watch(tensor) to differentiate w.r.t. a non-variable. Use persistent=True if you need multiple gradient calls from one tape.
Interviewer's Insight
- Knows
@tf.functiongraph-compiles the step and why side effects are dangerous inside it - Understands
training=TruevsFalsechanges layer behavior in the forward pass - Real-world: OpenAI-style RLHF loops need custom steps for policy and value gradients
Compare Dropout, Weight Decay, and Other Regularization in Keras - Meta, Microsoft Interview Question
Difficulty: đ´ Hard | Tags: Regularization, Keras | Asked by: Meta, Microsoft, Amazon
View Answer
Regularization fights overfitting by constraining model capacity or adding noise. Keras exposes several complementary tools.
| Technique | Mechanism | Where applied |
|---|---|---|
| Dropout | Randomly zeros activations during training | Between layers |
| L2 / weight decay | Penalizes large weights | Per-layer kernel_regularizer |
| L1 | Encourages sparse weights | Per-layer kernel_regularizer |
| BatchNorm | Normalizes activations, mild regularizing effect | Between layers |
| Early stopping | Stops before overfitting | Callback |
from tensorflow import keras
from tensorflow.keras import layers, regularizers
model = keras.Sequential([
layers.Dense(256, activation="relu",
kernel_regularizer=regularizers.l2(1e-4)),
layers.Dropout(0.5),
layers.Dense(128, activation="relu",
kernel_regularizer=regularizers.l2(1e-4)),
layers.Dropout(0.3),
layers.Dense(10, activation="softmax"),
])
Key nuances:
- Dropout is active only in training. In inference Keras scales activations so expected values match; you never manually toggle it.
- L2 penalty vs decoupled weight decay are not identical for adaptive optimizers. With Adam, adding an L2
kernel_regularizeris not the same as true weight decay. Usekeras.optimizers.AdamW, which decouples decay from the gradient update, for the correct behavior.
optimizer = keras.optimizers.AdamW(
learning_rate=1e-3, weight_decay=1e-4,
)
- Do not stack aggressive dropout on top of BatchNorm carelessly. They can interact poorly; a common pattern is BatchNorm in conv blocks and dropout in the dense head.
- Regularization strength is a hyperparameter: too much underfits, too little overfits. Tune with validation curves.
Rule of thumb: start with L2/AdamW weight decay plus modest dropout (0.2 to 0.5), add early stopping, and only then reach for heavier schemes.
Interviewer's Insight
- Knows L2 regularizer with Adam is not true weight decay; AdamW fixes this
- Understands dropout auto-scales at inference, no manual switch needed
- Real-world: Meta uses AdamW with tuned weight decay as the default for transformers
What is tf.data and Why Use It Over a Plain Python Generator? - Google, Netflix Interview Question
Difficulty: đĸ Easy | Tags: tf.data, Input Pipeline | Asked by: Google, Netflix, Amazon
View Answer
tf.data.Dataset is TensorFlow's API for building input pipelines that stream data into training loops efficiently. Instead of loading everything into memory, you describe a pipeline of transformations that execute lazily and in C++, overlapping with GPU compute.
Why prefer it over a Python generator:
- Performance: transformations run in the TensorFlow runtime, not the Python interpreter, so they escape the Global Interpreter Lock and parallelize across cores.
- Prefetching: data for step N+1 is prepared while step N trains, keeping the accelerator busy.
- Portability: the same pipeline plugs into
model.fit, custom loops, and distribution strategies. - Composability:
map,batch,shuffle,repeat,filterchain cleanly.
import tensorflow as tf
dataset = (
tf.data.Dataset.from_tensor_slices((features, labels))
.shuffle(buffer_size=10000)
.map(preprocess, num_parallel_calls=tf.data.AUTOTUNE)
.batch(32)
.prefetch(tf.data.AUTOTUNE)
)
model.fit(dataset, epochs=10)
For large corpora on disk, tf.data.TFRecordDataset reads sharded TFRecord files, and Dataset.list_files plus interleave reads many shards concurrently.
Interviewer's Insight
- Knows tf.data runs transformations in C++ outside the GIL
- Mentions lazy evaluation and streaming rather than loading into memory
- Real-world: Netflix builds petabyte-scale training pipelines on tf.data with TFRecords
How Do prefetch, cache, and AUTOTUNE Improve Pipeline Throughput? - Google, NVIDIA Interview Question
Difficulty: đĄ Medium | Tags: tf.data, Performance | Asked by: Google, NVIDIA, Meta
View Answer
A slow input pipeline starves the GPU, so these three tools remove that bottleneck.
prefetch(buffer_size) overlaps preprocessing on the CPU with model execution on the GPU. While the accelerator trains on batch N, the CPU prepares batch N+1. Always place it last in the pipeline.
cache() stores the results of expensive upstream transformations after the first epoch, either in memory or in a file. Everything before the cache runs once; everything after runs every epoch. Place cache after costly deterministic ops (decode, resize) but before random augmentation so you still get fresh randomness each epoch.
tf.data.AUTOTUNE lets the runtime dynamically tune buffer sizes and parallelism at runtime based on available CPU and memory, instead of you hardcoding magic numbers.
dataset = (
tf.data.Dataset.from_tensor_slices(paths)
.map(load_and_decode, num_parallel_calls=tf.data.AUTOTUNE)
.cache() # cache decoded images (deterministic)
.map(random_augment, num_parallel_calls=tf.data.AUTOTUNE)
.batch(64)
.prefetch(tf.data.AUTOTUNE) # overlap CPU prep with GPU compute
)
| Op | What it fixes | Placement |
|---|---|---|
prefetch | GPU idle between steps | Last |
cache | Repeated expensive decode | After decode, before augment |
AUTOTUNE | Manual buffer tuning | In map/prefetch args |
Order matters: a common mistake is caching after random augmentation, which freezes the augmentations to the first epoch's values.
Interviewer's Insight
- Explains why prefetch goes last and why cache goes before augmentation
- Uses AUTOTUNE rather than hardcoded buffer sizes
- Real-world: NVIDIA benchmarks show input pipeline tuning can double GPU utilization
What Does interleave Do and When Would You Use It? - Amazon, Uber Interview Question
Difficulty: đĄ Medium | Tags: tf.data, Performance | Asked by: Amazon, Uber, Google
View Answer
Dataset.interleave maps a function that produces a dataset over each element, then interleaves the results from multiple source datasets concurrently. Its main use is parallel reading of many files so I/O latency from one file overlaps with reading another.
Compared to map, which produces one output element per input, interleave produces a whole sub-dataset per input and pulls from several of them at once.
files = tf.data.Dataset.list_files("gs://bucket/train-*.tfrecord")
dataset = files.interleave(
lambda path: tf.data.TFRecordDataset(path),
cycle_length=8, # read 8 files concurrently
num_parallel_calls=tf.data.AUTOTUNE,
deterministic=False, # allow out-of-order for speed
)
Key knobs:
cycle_lengthcontrols how many input elements (files) are processed concurrently. Higher values raise parallelism and memory use.block_lengthsets how many consecutive elements are drawn from each open sub-dataset before rotating.deterministic=Falselets the runtime emit elements as soon as they are ready, trading reproducible ordering for throughput.
When to reach for it: reading from sharded TFRecords, remote object stores where per-file latency is high, or any case where a single reader cannot saturate bandwidth. For pure element-wise transforms, plain map with num_parallel_calls is the right tool instead.
Interviewer's Insight
- Distinguishes interleave (dataset per element, parallel files) from map (element per element)
- Knows cycle_length and deterministic=False trade ordering for throughput
- Real-world: Uber reads sharded training data from object storage with interleave
How Does Mixed Precision Training Work in TensorFlow? - NVIDIA, OpenAI Interview Question
Difficulty: đĄ Medium | Tags: Mixed Precision, Performance | Asked by: NVIDIA, OpenAI, Google
View Answer
Mixed precision runs most operations in 16-bit floats (float16 on GPU, bfloat16 on TPU) while keeping numerically sensitive parts in float32. On modern GPUs with Tensor Cores this cuts memory roughly in half and can speed training 2 to 3 times.
The policy: set a global policy so layers compute in 16-bit but keep their variables (weights) in float32 for stable updates.
import tensorflow as tf
tf.keras.mixed_precision.set_global_policy("mixed_float16")
model = build_model()
# IMPORTANT: final layer outputs float32 for numerical stability
outputs = tf.keras.layers.Dense(10)(x)
outputs = tf.keras.layers.Activation("softmax", dtype="float32")(outputs)
Loss scaling is the critical piece. float16 has a small dynamic range, so tiny gradients underflow to zero. A loss scaler multiplies the loss by a large factor before backprop and unscales the gradients afterward. Keras applies this automatically when you compile with the default optimizer wrapper:
optimizer = tf.keras.optimizers.Adam(1e-3)
# Keras wraps it with LossScaleOptimizer under mixed_float16 policy
model.compile(optimizer=optimizer, loss="categorical_crossentropy")
Gotchas:
- Keep the softmax/output layer in float32 to avoid unstable probabilities.
- Mixed precision helps most on GPUs with Tensor Cores (Volta and newer); older cards see little gain.
- On TPU use
mixed_bfloat16, which has float32's range and needs no loss scaling.
Interviewer's Insight
- Explains loss scaling to prevent float16 gradient underflow
- Knows variables stay float32 while compute is float16
- Real-world: NVIDIA and OpenAI train large models in mixed precision to fit bigger batches
Explain MirroredStrategy and MultiWorkerMirroredStrategy - Meta, Microsoft Interview Question
Difficulty: đĄ Medium | Tags: Distributed, Strategy | Asked by: Meta, Microsoft, Amazon
View Answer
tf.distribute.Strategy is TensorFlow's API for distributing training across multiple devices with minimal code change. Two common ones:
MirroredStrategy does synchronous data parallelism across multiple GPUs on a single machine. Each GPU holds a full replica of the model, processes a different slice of the batch, and gradients are combined with all-reduce before each weight update, so replicas stay identical.
strategy = tf.distribute.MirroredStrategy()
print("Replicas:", strategy.num_replicas_in_sync)
with strategy.scope():
model = build_model()
model.compile(optimizer="adam", loss="mse")
# Scale the global batch size by replica count
model.fit(dataset, epochs=10)
MultiWorkerMirroredStrategy extends the same synchronous all-reduce approach across multiple machines. Each worker is configured through the TF_CONFIG environment variable describing the cluster and this worker's index.
# TF_CONFIG example (set per worker before starting):
# {"cluster": {"worker": ["host1:12345", "host2:12345"]},
# "task": {"type": "worker", "index": 0}}
strategy = tf.distribute.MultiWorkerMirroredStrategy()
Key points to raise:
- Everything that creates variables (model, optimizer, metrics) must be built inside
strategy.scope(). - The batch size you pass is the global batch size; it is split across replicas, so scale it up and often the learning rate too.
- Multi-worker requires each worker to save checkpoints to avoid conflicts and to handle fault tolerance; only the chief writes the final model.
- For huge embedding tables,
ParameterServerStrategy(async) may suit better than mirrored all-reduce.
Interviewer's Insight
- Knows model and optimizer must be created inside strategy.scope()
- Explains global vs per-replica batch size and all-reduce
- Real-world: Meta and Microsoft scale training across GPU clusters with multi-worker strategies
How Do You Serve a TensorFlow Model in Production? - Google, Airbnb Interview Question
Difficulty: đĸ Easy | Tags: Deployment, Serving | Asked by: Google, Airbnb, Amazon
View Answer
The standard path is the SavedModel format served by TensorFlow Serving, a high-performance C++ server with gRPC and REST endpoints.
Step 1: export a SavedModel.
model.export("saved_model/my_model/1") # note the version subdirectory
The trailing 1 is a version number; TF Serving watches the directory and can hot-swap versions without downtime.
Step 2: run TensorFlow Serving (typically via Docker):
docker run -p 8501:8501 \
--mount type=bind,source=$(pwd)/saved_model/my_model,target=/models/my_model \
-e MODEL_NAME=my_model tensorflow/serving
Step 3: send a REST request:
import requests, json
resp = requests.post(
"http://localhost:8501/v1/models/my_model:predict",
data=json.dumps({"instances": inputs.tolist()}),
)
predictions = resp.json()["predictions"]
What TF Serving gives you:
- Dynamic batching of concurrent requests for higher throughput.
- Version management with canary and A/B rollout across versions.
- gRPC for low-latency, high-volume traffic; REST for convenience.
For on-device or edge deployment, convert to TFLite / LiteRT instead (covered separately). For full MLOps pipelines, TFX wraps training, validation, and serving.
Interviewer's Insight
- Uses SavedModel with a version subdirectory for hot-swapping
- Mentions dynamic batching and gRPC vs REST trade-offs
- Real-world: Airbnb serves ranking models through TensorFlow Serving with versioned rollouts
How Would You Deploy a Model to a Mobile Device? - Apple, Google Interview Question
Difficulty: đĸ Easy | Tags: TFLite, Edge | Asked by: Apple, Google, Meta
View Answer
For phones, wearables, and microcontrollers you convert to TFLite (now branded LiteRT), a compact runtime optimized for low latency and small binary size.
Convert the SavedModel:
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model("saved_model/my_model/1")
converter.optimizations = [tf.lite.Optimize.DEFAULT] # enables quantization
tflite_model = converter.convert()
with open("model.tflite", "wb") as f:
f.write(tflite_model)
Quantization is the main lever for shrinking and accelerating models:
- Dynamic range quantization: weights to int8, activations computed in float. Roughly 4x smaller, easy default.
- Full integer quantization: weights and activations to int8 using a representative dataset; needed for integer-only accelerators and Edge TPUs.
- Float16 quantization: halves size, good for GPU delegates.
# Full integer quantization with a representative dataset
def rep_data():
for sample in calibration_samples.take(100):
yield [tf.cast(sample, tf.float32)]
converter.representative_dataset = rep_data
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
Running inference uses the Interpreter, and on device you attach delegates (GPU, NNAPI on Android, Core ML on Apple) to offload to hardware accelerators.
| Concern | TF Serving | TFLite / LiteRT |
|---|---|---|
| Target | Servers, cloud | Phones, edge, MCUs |
| Size | Large | Tiny, quantized |
| Latency | Network round trip | On-device, offline |
Interviewer's Insight
- Knows quantization types and when a representative dataset is required
- Mentions hardware delegates (GPU, NNAPI, Core ML)
- Real-world: Apple runs on-device vision models converted to compact int8 formats
How Do You Debug Shape Errors and Inspect Tensors During Training? - Microsoft, Uber Interview Question
Difficulty: đ´ Hard | Tags: Debugging, Best Practices | Asked by: Microsoft, Uber, Google
View Answer
TensorFlow 2.x runs eagerly by default, so you can debug with normal Python tools until you wrap code in @tf.function, where graph tracing changes the rules.
1. Shape errors. Most bugs are dimension mismatches. Inspect and assert shapes explicitly:
print(x.shape, x.dtype) # eager: works like NumPy
tf.debugging.assert_shapes([(x, ("batch", 128)), (w, (128, 10))])
A frequent culprit is a missing or extra batch dimension, or broadcasting that silently succeeds then fails downstream.
2. Printing inside graphs. A plain Python print runs once at trace time, not every step. To print actual runtime values inside a @tf.function, use tf.print, which becomes a graph op that executes each call:
@tf.function
def step(x):
tf.print("x mean:", tf.reduce_mean(x)) # prints every execution
print("traced once") # prints only during tracing
return model(x)
3. Force eager execution to debug. Temporarily run functions eagerly so breakpoints and print behave normally:
tf.config.run_functions_eagerly(True) # disable graph mode globally
# ... reproduce the bug, step through with pdb ...
tf.config.run_functions_eagerly(False) # re-enable for speed
You can also pass model.compile(..., run_eagerly=True) to debug a fit loop.
4. NaNs and Infs. Enable the numeric checker to pinpoint where they first appear:
tf.debugging.enable_check_numerics()
5. Retracing warnings. Repeated retracing (from passing Python ints or varying shapes) silently slows training; use input_signature on tf.function to lock shapes.
Interviewer's Insight
- Knows print traces once while tf.print runs every step
- Uses run_functions_eagerly to drop back into normal Python debugging
- Real-world: Uber teams gate graph mode off in dev to catch shape bugs before scaling
TensorFlow vs PyTorch and How Do You Handle GPU Out-of-Memory Errors? - OpenAI, Meta Interview Question
Difficulty: đ´ Hard | Tags: Frameworks, Memory | Asked by: OpenAI, Meta, NVIDIA
View Answer
Framework trade-offs. The two have converged, but differences remain:
| Dimension | TensorFlow | PyTorch |
|---|---|---|
| Default execution | Eager, graphs via @tf.function | Eager, graphs via torch.compile |
| Deployment | Mature: TF Serving, TFLite, TFX | TorchServe, ExecuTorch, growing |
| Mobile / edge | Strong (LiteRT, Edge TPU) | Improving (ExecuTorch) |
| Research adoption | Solid | Dominant in papers |
| TPU support | First-class | Via XLA / PyTorch-XLA |
Rule of thumb: PyTorch for research flexibility and rapid iteration; TensorFlow when you need a battle-tested serving and edge story. Both support XLA compilation and mixed precision.
Handling GPU OOM. When training crashes with an out-of-memory error, work through these levers:
- Reduce batch size, then recover the effective batch with gradient accumulation (accumulate grads over several micro-batches before one update).
- Mixed precision (
mixed_float16) roughly halves activation memory. - Gradient checkpointing trades compute for memory by recomputing activations during the backward pass instead of storing them.
- Limit or grow GPU memory so TensorFlow does not grab all of it up front:
gpus = tf.config.list_physical_devices("GPU")
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
- Shrink the model (fewer layers, smaller hidden size) or shard it with model parallelism across GPUs.
- Trim the input pipeline: smaller image resolution, or lower
cache/shufflebuffers that themselves consume host memory. - Free references: avoid accumulating tensors in Python lists across steps, which keeps them alive and leaks memory.
Diagnosing: watch nvidia-smi, and note that memory that spikes then crashes usually points to a too-large batch or an unbounded buffer, while a slow climb points to a leak from retained tensors.
Interviewer's Insight
- Pairs batch reduction with gradient accumulation to preserve effective batch size
- Knows gradient checkpointing trades compute for memory
- Real-world: OpenAI and Meta combine mixed precision, checkpointing, and sharding to fit large models
Quick Reference: 100 TensorFlow Questions
| # | Question Title | Practice Links | Companies Asking | Difficulty | Topics |
|---|---|---|---|---|---|
| 1 | What is TensorFlow and what are its core use cases? | TensorFlow Docs | Google, Amazon | Easy | Fundamentals |
| 2 | What is a tensor and how does it differ from a NumPy array? | TensorFlow Docs | Google, Microsoft | Easy | Fundamentals, Tensors |
| 3 | Explain the rank, shape, and dtype of a tensor. | TensorFlow Docs | Amazon, Meta | Easy | Tensors |
| 4 | What is the difference between tf.constant and tf.Variable? | TensorFlow Docs | Google, Netflix | Easy | Tensors, Variables |
| 5 | How do you create tensors filled with zeros, ones, or random values? | TensorFlow Docs | Amazon, Apple | Easy | Tensors |
| 6 | What is eager execution and why was it made the default in TF 2.x? | TF Guide | Google, Microsoft | Medium | Fundamentals, Execution |
| 7 | Explain the difference between TF 1.x graph mode and TF 2.x eager mode. | TF Guide | Meta, Amazon | Medium | Fundamentals, Execution |
| 8 | What does the @tf.function decorator do? | TF Guide | Google, Uber | Medium | Graphs, Performance |
| 9 | How does AutoGraph convert Python control flow into graph ops? | TF Guide | Google, Microsoft | Hard | Graphs, AutoGraph |
| 10 | What is a computational graph and why is it useful? | TF Guide | Amazon, Meta | Medium | Graphs |
| 11 | How do you perform basic tensor arithmetic and broadcasting? | TensorFlow Docs | Google, Apple | Easy | Tensors, Broadcasting |
| 12 | Explain broadcasting rules in TensorFlow. | TensorFlow Docs | Amazon, Netflix | Medium | Broadcasting |
| 13 | How do you reshape, transpose, and squeeze tensors? | TensorFlow Docs | Google, Microsoft | Easy | Tensors |
| 14 | What is the difference between tf.reshape and tf.transpose? | TensorFlow Docs | Meta, Amazon | Easy | Tensors |
| 15 | How do you concatenate and stack tensors? | TensorFlow Docs | Google, Uber | Easy | Tensors |
| 16 | How do you slice and index into tensors? | TensorFlow Docs | Amazon, Apple | Easy | Tensors, Indexing |
| 17 | What is tf.gather and when would you use it? | TensorFlow Docs | Google, Meta | Medium | Tensors, Indexing |
| 18 | Explain tf.reduce_sum, tf.reduce_mean, and axis arguments. | TensorFlow Docs | Amazon, Microsoft | Easy | Tensors, Reductions |
| 19 | How do you cast a tensor from one dtype to another? | TensorFlow Docs | Google, Netflix | Easy | Tensors, dtypes |
| 20 | What are ragged tensors and when are they needed? | TensorFlow Docs | Google, Amazon | Hard | Tensors, Ragged |
| 21 | What are sparse tensors and how do you work with them? | TensorFlow Docs | Meta, Google | Hard | Tensors, Sparse |
| 22 | What is a string tensor and how do you manipulate text tensors? | TensorFlow Docs | Amazon, Apple | Medium | Tensors, Text |
| 23 | How does automatic differentiation work in TensorFlow? | TF Guide | Google, Microsoft | Medium | Autodiff, Gradients |
| 24 | What is tf.GradientTape and how do you use it? | TF Guide | Google, Meta | Medium | Autodiff, Gradients |
| 25 | How do you compute higher-order derivatives with nested GradientTapes? | TF Guide | Amazon, Google | Hard | Autodiff, Gradients |
| 26 | What does persistent=True do in tf.GradientTape? | TF Guide | Meta, Uber | Medium | Autodiff |
| 27 | How do you stop gradients from flowing with tf.stop_gradient? | TensorFlow Docs | Google, Amazon | Medium | Autodiff, Gradients |
| 28 | What is the difference between watched and unwatched variables in GradientTape? | TF Guide | Google, Microsoft | Medium | Autodiff |
| 29 | What is Keras and how does it relate to TensorFlow? | Keras API | Amazon, Google | Easy | Keras, Fundamentals |
| 30 | Compare the Sequential, Functional, and Subclassing model APIs. | Keras API | Google, Meta | Medium | Keras, Models |
| 31 | How do you build a model with the Keras Sequential API? | Keras API | Amazon, Apple | Easy | Keras, Models |
| 32 | How do you build a model with the Keras Functional API? | Keras API | Google, Netflix | Medium | Keras, Models |
| 33 | How do you create a custom model by subclassing tf.keras.Model? | Keras API | Meta, Amazon | Medium | Keras, Models |
| 34 | How do you write a custom Keras layer? | Keras API | Google, Microsoft | Medium | Keras, Layers |
| 35 | What is the difference between a layer's build and call methods? | Keras API | Amazon, Google | Medium | Keras, Layers |
| 36 | What common layer types does Keras provide? | Keras API | Google, Uber | Easy | Keras, Layers |
| 37 | Explain Dense, Conv2D, and LSTM layers. | Keras API | Amazon, Meta | Medium | Keras, Layers |
| 38 | What is the purpose of an activation function and which are available? | Keras API | Google, Apple | Easy | Keras, Activations |
| 39 | Compare ReLU, sigmoid, tanh, and softmax activations. | Keras API | Amazon, Microsoft | Medium | Activations |
| 40 | How do you compile a Keras model? | Keras API | Google, Netflix | Easy | Keras, Training |
| 41 | What arguments does model.fit accept? | Keras API | Meta, Amazon | Easy | Keras, Training |
| 42 | How do you evaluate and predict with a Keras model? | Keras API | Google, Apple | Easy | Keras, Training |
| 43 | What is a loss function and how do you choose one? | Keras API | Amazon, Google | Medium | Losses |
| 44 | Compare MSE, categorical crossentropy, and binary crossentropy. | Keras API | Google, Meta | Medium | Losses |
| 45 | How do you write a custom loss function in Keras? | Keras API | Amazon, Microsoft | Medium | Losses, Keras |
| 46 | What is an optimizer and how does gradient descent work? | Keras API | Google, Uber | Medium | Optimizers |
| 47 | Compare SGD, Adam, RMSprop, and Adagrad optimizers. | Keras API | Amazon, Meta | Medium | Optimizers |
| 48 | What is a learning rate and how do you schedule it? | Keras API | Google, Apple | Medium | Optimizers, Training |
| 49 | How do learning rate schedules and warmup work in Keras? | Keras API | Amazon, Google | Hard | Optimizers, Training |
| 50 | What are Keras metrics and how do you track them? | Keras API | Google, Netflix | Easy | Metrics |
| 51 | How do you write a custom training loop with GradientTape? | TF Guide | Meta, Google | Hard | Training, Autodiff |
| 52 | What are Keras callbacks and give examples? | Keras API | Amazon, Google | Medium | Callbacks, Training |
| 53 | How does the EarlyStopping callback work? | Keras API | Google, Microsoft | Medium | Callbacks |
| 54 | How do you use ModelCheckpoint to save the best model? | Keras API | Amazon, Apple | Medium | Callbacks, Saving |
| 55 | What is the ReduceLROnPlateau callback? | Keras API | Google, Uber | Medium | Callbacks |
| 56 | How do you write a custom Keras callback? | Keras API | Meta, Amazon | Medium | Callbacks |
| 57 | What is the tf.data API and why use it? | tf.data | Google, Amazon | Medium | Data, Input Pipeline |
| 58 | How do you create a Dataset from tensors or NumPy arrays? | tf.data | Google, Apple | Easy | Data |
| 59 | Explain Dataset map, batch, shuffle, and repeat. | tf.data | Amazon, Meta | Medium | Data, Input Pipeline |
| 60 | What does dataset.prefetch do and why is it important? | tf.data | Google, Microsoft | Medium | Data, Performance |
| 61 | What is tf.data.AUTOTUNE? | tf.data | Amazon, Google | Medium | Data, Performance |
| 62 | How do you build an efficient input pipeline for large datasets? | tf.data | Google, Netflix | Hard | Data, Performance |
| 63 | What is the TFRecord format and when should you use it? | tf.data | Meta, Google | Hard | Data, TFRecord |
| 64 | How do you parse tf.train.Example protos from TFRecords? | tf.data | Amazon, Google | Hard | Data, TFRecord |
| 65 | How do you cache a dataset and when does it help? | tf.data | Google, Uber | Medium | Data, Performance |
| 66 | How do you interleave reads from multiple files? | tf.data | Amazon, Meta | Hard | Data, Performance |
| 67 | How do you load image data with image_dataset_from_directory? | Keras API | Google, Apple | Easy | Data, Images |
| 68 | How do you perform data augmentation in TensorFlow? | Keras API | Amazon, Google | Medium | Data, Augmentation |
| 69 | What preprocessing layers does Keras offer (Normalization, Rescaling)? | Keras API | Google, Microsoft | Medium | Preprocessing |
| 70 | How do you handle text tokenization with TextVectorization? | Keras API | Meta, Amazon | Medium | Preprocessing, Text |
| 71 | What is feature engineering with tf.feature_column? | TF Guide | Google, Amazon | Hard | Preprocessing, Features |
| 72 | How do you save and load an entire Keras model? | Keras API | Google, Apple | Easy | Saving, Deployment |
| 73 | What is the difference between SavedModel and HDF5 formats? | TF Guide | Amazon, Google | Medium | Saving, Deployment |
| 74 | How do you save and restore only model weights? | Keras API | Google, Netflix | Medium | Saving |
| 75 | What is a tf.train.Checkpoint and how does it differ from SavedModel? | TF Guide | Meta, Google | Hard | Saving, Checkpoints |
| 76 | How do you use transfer learning with a pretrained model? | TF Tutorials | Amazon, Google | Medium | Transfer Learning |
| 77 | How do you freeze and unfreeze layers for fine-tuning? | TF Tutorials | Google, Apple | Medium | Transfer Learning |
| 78 | What is TensorBoard and what can you visualize with it? | TF Guide | Google, Microsoft | Medium | TensorBoard, Debugging |
| 79 | How do you log scalars, histograms, and images to TensorBoard? | TF Guide | Amazon, Google | Medium | TensorBoard |
| 80 | How do you debug NaN or exploding gradients during training? | SO: tensorflow | Google, Meta | Hard | Debugging, Training |
| 81 | What causes shape mismatch errors and how do you fix them? | SO: tensorflow | Amazon, Google | Medium | Debugging |
| 82 | How do you profile a TensorFlow model for bottlenecks? | TF Guide | Google, Uber | Hard | Performance, Profiling |
| 83 | What is mixed precision training and how do you enable it? | TF Guide | Amazon, Google | Hard | Performance, Mixed Precision |
| 84 | What is XLA and how does it accelerate TensorFlow? | TF Guide | Google, Microsoft | Hard | Performance, XLA |
| 85 | How do you use GPUs with TensorFlow and control memory growth? | TF Guide | Google, Amazon | Medium | GPU, Performance |
| 86 | What is a tf.distribute.Strategy? | TF Guide | Meta, Google | Hard | Distributed |
| 87 | Explain MirroredStrategy for multi-GPU training. | TF Guide | Amazon, Google | Hard | Distributed |
| 88 | What is MultiWorkerMirroredStrategy and how does it work? | TF Guide | Google, Microsoft | Hard | Distributed |
| 89 | How does TPUStrategy enable training on TPUs? | TF Guide | Google, Apple | Hard | Distributed, TPU |
| 90 | What is data parallelism versus model parallelism? | TF Guide | Amazon, Meta | Hard | Distributed |
| 91 | What is TensorFlow Serving and how do you deploy a model with it? | TF Tutorials | Google, Amazon | Hard | Deployment, Serving |
| 92 | What is TensorFlow Lite and when do you use it? | TF Tutorials | Google, Apple | Medium | Deployment, TFLite |
| 93 | How do you quantize a model for edge deployment? | TF Tutorials | Amazon, Google | Hard | Deployment, Quantization |
| 94 | What is TensorFlow.js and what can it do? | TF Tutorials | Google, Meta | Medium | Deployment, TFjs |
| 95 | What is TFX and what problem does it solve? | TF Guide | Amazon, Google | Hard | Ecosystem, TFX |
| 96 | What is TensorFlow Hub? | TF Tutorials | Google, Microsoft | Easy | Ecosystem, Hub |
| 97 | What is TensorFlow Datasets (TFDS)? | TF Tutorials | Amazon, Google | Easy | Ecosystem, Data |
| 98 | How do you handle overfitting with dropout and regularization? | Keras API | Google, Meta | Medium | Regularization |
| 99 | How does batch normalization work and where do you place it? | Keras API | Amazon, Google | Medium | Normalization |
| 100 | How do you set random seeds for reproducibility in TensorFlow? | SO: tensorflow | Google, Apple | Medium | Reproducibility |
Code Examples
1. Minimal End-to-End Training Script
Difficulty: đĸ Easy | Tags: Code Example | Asked by: Code Pattern
View Code Example
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
# Load and normalize MNIST
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
# Build a simple classifier with the Sequential API
model = keras.Sequential([
layers.Input(shape=(28, 28)),
layers.Flatten(),
layers.Dense(128, activation="relu"),
layers.Dropout(0.2),
layers.Dense(10, activation="softmax"),
])
model.compile(
optimizer=keras.optimizers.Adam(1e-3),
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
model.fit(
x_train, y_train,
validation_split=0.1,
epochs=5, batch_size=64,
callbacks=[keras.callbacks.EarlyStopping(patience=2,
restore_best_weights=True)],
)
test_loss, test_acc = model.evaluate(x_test, y_test)
print(f"test accuracy: {test_acc:.4f}")
model.save("mnist.keras")
2. Custom Layer and Model with GradientTape
Difficulty: đĄ Medium | Tags: Code Example | Asked by: Code Pattern
View Code Example
import tensorflow as tf
from tensorflow import keras
# A reusable custom layer with lazy weight creation and serialization
@keras.saving.register_keras_serializable()
class Linear(keras.layers.Layer):
def __init__(self, units, **kwargs):
super().__init__(**kwargs)
self.units = units
def build(self, input_shape):
self.w = self.add_weight(
shape=(input_shape[-1], self.units),
initializer="glorot_uniform", trainable=True, name="w",
)
self.b = self.add_weight(
shape=(self.units,), initializer="zeros",
trainable=True, name="b",
)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
def get_config(self):
return {**super().get_config(), "units": self.units}
model = keras.Sequential([Linear(64), keras.layers.ReLU(), Linear(10)])
optimizer = keras.optimizers.Adam(1e-3)
loss_fn = keras.losses.SparseCategoricalCrossentropy(from_logits=True)
@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 loss
# for x_batch, y_batch in train_ds:
# loss = train_step(x_batch, y_batch)
3. High-Performance tf.data Pipeline
Difficulty: đĄ Medium | Tags: Code Example | Asked by: Code Pattern
View Code Example
import tensorflow as tf
AUTOTUNE = tf.data.AUTOTUNE
IMG_SIZE = 224
def load_and_decode(path, label):
image = tf.io.read_file(path)
image = tf.io.decode_jpeg(image, channels=3)
image = tf.image.resize(image, [IMG_SIZE, IMG_SIZE])
image = tf.cast(image, tf.float32) / 255.0
return image, label
def augment(image, label):
image = tf.image.random_flip_left_right(image)
image = tf.image.random_brightness(image, max_delta=0.1)
return image, label
train_ds = (
tf.data.Dataset.from_tensor_slices((file_paths, labels))
.shuffle(buffer_size=10000, seed=42)
.map(load_and_decode, num_parallel_calls=AUTOTUNE)
.cache() # cache decoded images before random augment
.map(augment, num_parallel_calls=AUTOTUNE)
.batch(64)
.prefetch(AUTOTUNE) # overlap CPU prep with GPU compute
)
# model.fit(train_ds, epochs=10)
Questions asked in Google interview
- Explain the difference between eager execution and tf.function graphs
- How would you diagnose and fix excessive tf.function retracing?
- Design an efficient tf.data pipeline for a petabyte-scale image dataset
- How do you make a TensorFlow training run bit-for-bit reproducible?
- Implement a custom training loop with GradientTape and gradient clipping
- How does AutoGraph translate Python control flow into graph ops?
- Explain XLA compilation and when it speeds up a model
- How would you serve a versioned SavedModel with TensorFlow Serving?
- Compare data parallelism and model parallelism for large models
- How do you profile and remove input-pipeline bottlenecks?
Questions asked in Amazon interview
- What is the difference between tf.constant and tf.Variable?
- Walk through compile, fit, evaluate, and predict in Keras
- How do you write and serialize a custom Keras layer?
- Explain how prefetch, cache, and AUTOTUNE improve throughput
- How would you parse tf.train.Example protos from TFRecords?
- Design a transfer-learning pipeline for a small labeled dataset
- How do you save and restore only model weights across architectures?
- Explain the trade-offs between SavedModel and the .keras format
- How would you handle a GPU out-of-memory error during training?
- Implement a custom stateful metric like F1 in Keras
Questions asked in Meta interview
- Explain broadcasting rules and a silent broadcasting bug you have seen
- When do you use ragged versus sparse tensors?
- Compare Sequential, Functional, and subclassed model APIs
- How does MirroredStrategy combine gradients across GPUs?
- Explain L2 regularization versus decoupled weight decay with AdamW
- How do you build a custom model by subclassing tf.keras.Model?
- Explain how batch normalization behaves in training versus inference
- How would you scale synchronous training across many workers?
- Implement semantic-style feature hashing for high-cardinality inputs
- How do you debug exploding gradients in a deep network?
Questions asked in Microsoft interview
- How does tf.GradientTape compute gradients under the hood?
- What is the difference between a layer's build and call methods?
- How do you enable and reason about mixed precision training?
- Explain MultiWorkerMirroredStrategy and the role of TF_CONFIG
- How do you debug shape mismatch errors in a graph-mode function?
- What does persistent=True do in a GradientTape?
- How would you log scalars and histograms to TensorBoard?
- Explain learning rate schedules and warmup in Keras
- How do you control GPU memory growth to avoid grabbing all memory?
- Compare SavedModel and HDF5 serialization formats
Questions asked in OpenAI interview
- Why do Python side effects run only during tf.function tracing?
- How do you implement gradient accumulation for large effective batches?
- Explain loss scaling and why float16 gradients underflow
- How would you write an RLHF-style custom training step?
- Compare TensorFlow and PyTorch for research and deployment
- How does gradient checkpointing trade compute for memory?
- How do you compute higher-order derivatives with nested tapes?
- Explain how stop_gradient is used in practice
- How do you keep a training step fully on the GPU with no host copies?
- How would you shard a model that does not fit on one GPU?