TensorFlow Cheatsheet

Building Models

Use this TensorFlow reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Sequential vs Functional vs Subclass

StyleFlexibilitySerializationTypical use
SequentialLow — single I/O, linearFullSimple stacks
Functional APIHigh — DAG topologyFullMost production nets
SubclassMaximumManual get_configResearch / dynamic flow

Sequential Model

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

# All layers at construction
model = keras.Sequential([
    layers.Input(shape=(28, 28, 1), name='images'),
    layers.Conv2D(32, 3, activation='relu'),
    layers.MaxPooling2D(),
    layers.Flatten(),
    layers.Dense(128, activation='relu'),
    layers.Dense(10, activation='softmax'),
], name='cnn')

# Build incrementally
model2 = keras.Sequential(name='mlp')
model2.add(layers.Input(shape=(784,)))
model2.add(layers.Dense(256, activation='relu'))
model2.add(layers.Dense(10, activation='softmax'))

Always include an explicit layers.Input(...) so model.summary() shows output shapes and model.built is True before compile.

Functional API

# Single input/output
inp = keras.Input(shape=(784,))
x   = layers.Dense(256, activation='relu')(inp)
x   = layers.Dropout(0.3)(x)
out = layers.Dense(10, activation='softmax')(x)
model = keras.Model(inp, out)

# Multiple inputs
img   = keras.Input(shape=(224, 224, 3), name='image')
meta  = keras.Input(shape=(16,), name='metadata')
x     = layers.Conv2D(32, 3, activation='relu')(img)
x     = layers.GlobalAveragePooling2D()(x)
x     = layers.Concatenate()([x, meta])
out   = layers.Dense(5, activation='softmax')(x)
model = keras.Model(inputs=[img, meta], outputs=out)

# Multiple outputs
x     = layers.Dense(64, activation='relu')(inp)
cls   = layers.Dense(10, activation='softmax', name='class')(x)
reg   = layers.Dense(1, name='score')(x)
model = keras.Model(inp, [cls, reg])

Shared Layers

shared_emb = layers.Embedding(10000, 64)

inp_a = keras.Input(shape=(100,))
inp_b = keras.Input(shape=(100,))
enc_a = shared_emb(inp_a)
enc_b = shared_emb(inp_b)
diff  = layers.Subtract()([enc_a, enc_b])
out   = layers.Dense(1, activation='sigmoid')(diff)
model = keras.Model([inp_a, inp_b], out)

Residual Block

def residual_block(x, filters, kernel_size=3):
    shortcut = x
    x = layers.Conv2D(filters, kernel_size, padding='same', activation='relu')(x)
    x = layers.Conv2D(filters, kernel_size, padding='same')(x)
    x = layers.Add()([x, shortcut])
    return layers.Activation('relu')(x)

inp = keras.Input(shape=(32, 32, 64))
out = residual_block(inp, 64)
model = keras.Model(inp, out)

Model Subclassing

class ResidualNet(keras.Model):
    def __init__(self, num_classes):
        super().__init__()
        self.conv1  = layers.Conv2D(32, 3, activation='relu', padding='same')
        self.conv2  = layers.Conv2D(32, 3, padding='same')
        self.add    = layers.Add()
        self.act    = layers.Activation('relu')
        self.pool   = layers.GlobalAveragePooling2D()
        self.dense  = layers.Dense(num_classes, activation='softmax')

    def call(self, inputs, training=False):
        x = self.conv1(inputs)
        residual = x
        x = self.conv2(x)
        x = self.add([x, residual])
        x = self.act(x)
        x = self.pool(x)
        return self.dense(x)

    def get_config(self):
        return {'num_classes': self.dense.units}

For serialization, implement get_config and decorate with @keras.saving.register_keras_serializable() if you want model.save() / keras.models.load_model to reconstruct without importing the class.

Transfer Learning Pattern

base = keras.applications.MobileNetV3Small(
    include_top=False,
    weights='imagenet',
    input_shape=(224, 224, 3),
)
base.trainable = False   # freeze

inp = keras.Input(shape=(224, 224, 3))
x   = base(inp, training=False)   # pass training=False to freeze BN
x   = layers.GlobalAveragePooling2D()(x)
x   = layers.Dropout(0.2)(x)
out = layers.Dense(5, activation='softmax')(x)
model = keras.Model(inp, out)

# Fine-tune: unfreeze last N layers
base.trainable = True
for layer in base.layers[:-20]:
    layer.trainable = False

Inspecting Models

model.summary(line_length=120, expand_nested=True)

# Access layers
model.layers              # list
model.get_layer('dense')  # by name
model.get_layer(index=2)  # by index

# Weights
model.weights                   # all tf.Variable
model.trainable_weights
model.non_trainable_weights
model.get_weights()             # list of numpy arrays
model.set_weights(weights)      # list of numpy arrays (same shapes)

# Intermediate outputs (functional / inspect)
feature_model = keras.Model(
    inputs=model.inputs,
    outputs=model.get_layer('conv2d').output,
)

Building & Calling Manually

# Build without input data
model.build(input_shape=(None, 784))

# Forward pass
y = model(tf.random.normal([4, 784]))          # training=False by default
y = model(tf.random.normal([4, 784]), training=True)

# predict() vs __call__
# model(x)          — eager call, returns tensor, respects training flag
# model.predict(x)  — batched, returns numpy, progress bar, no gradients

Merging Layers

a = keras.Input(shape=(32,))
b = keras.Input(shape=(32,))

layers.Add()([a, b])
layers.Subtract()([a, b])
layers.Multiply()([a, b])
layers.Average()([a, b])
layers.Maximum()([a, b])
layers.Minimum()([a, b])
layers.Concatenate(axis=-1)([a, b])   # (None, 64)
layers.Dot(axes=1)([a, b])            # dot product

Preprocessing Inside the Model

Embedding preprocessing in the model ensures it runs at inference without extra steps.

# Normalization
norm = layers.Normalization()
norm.adapt(train_data)   # computes mean/var

# Discretization
disc = layers.Discretization(bin_boundaries=[0.0, 0.5, 1.0])
disc.adapt(train_data)

# Text
text_vec = layers.TextVectorization(max_tokens=10000, output_sequence_length=50)
text_vec.adapt(text_dataset)

model = keras.Sequential([text_vec, layers.Embedding(10000, 32), ...])

Multi-Output Model with Per-Head Losses

inp   = keras.Input(shape=(256,))
x     = layers.Dense(128, activation='relu')(inp)
cls   = layers.Dense(10, activation='softmax', name='cls')(x)
bbox  = layers.Dense(4, name='bbox')(x)

model = keras.Model(inp, {'cls': cls, 'bbox': bbox})

model.compile(
    optimizer='adam',
    loss={'cls': 'sparse_categorical_crossentropy', 'bbox': 'mse'},
    loss_weights={'cls': 1.0, 'bbox': 0.5},
    metrics={'cls': 'accuracy'},
)