TensorFlow Cheatsheet

Building Models

Use this TensorFlow reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

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'},
)