šŸ“ Artikel ini ditulis dalam Bahasa Indonesia & English
šŸ“ This article is available in English & Bahasa Indonesia

šŸ—ļø Belajar TensorFlow — Page 2Learn TensorFlow — Page 2

Keras API &
Model Building

Keras API &
Model Building

Keras adalah high-level API di dalam TensorFlow untuk membangun dan melatih model. Page 2 membahas: Sequential API untuk model sederhana, Functional API untuk arsitektur kompleks, compile/fit/evaluate workflow, Callbacks (EarlyStopping, TensorBoard, ModelCheckpoint), custom layers & models, dan membangun MNIST classifier 98%+ dalam beberapa baris kode.

Keras is TensorFlow's high-level API for building and training models. Page 2 covers: Sequential API for simple models, Functional API for complex architectures, compile/fit/evaluate workflow, Callbacks (EarlyStopping, TensorBoard, ModelCheckpoint), custom layers & models, and building an MNIST classifier at 98%+ in just a few lines of code.

šŸ“… MaretMarch 2026ā± 28 menit baca28 min read
šŸ· KerasSequentialFunctional APICallbacksMNISTCustom Layers
šŸ“š Seri Belajar TensorFlow:Learn TensorFlow Series:

šŸ“‘ Daftar Isi — Page 2

šŸ“‘ Table of Contents — Page 2

  1. Apa Itu Keras? — High-level API di dalam TensorFlow
  2. Sequential API — Stack layers: paling simpel, paling sering dipakai
  3. Compile & Fit — Optimizer, loss, metrics, dan training
  4. Evaluate & Predict — Testing dan inference
  5. Functional API — Multi-input, skip connections, arsitektur kompleks
  6. Callbacks — EarlyStopping, ModelCheckpoint, TensorBoard, ReduceLR
  7. Custom Layers & Models — Buat layer sendiri dengan subclassing
  8. Proyek: MNIST Classifier 98%+ — End-to-end dalam 30 baris
  9. Ringkasan & Preview Page 3
  1. What Is Keras? — High-level API inside TensorFlow
  2. Sequential API — Stack layers: simplest, most commonly used
  3. Compile & Fit — Optimizer, loss, metrics, and training
  4. Evaluate & Predict — Testing and inference
  5. Functional API — Multi-input, skip connections, complex architectures
  6. Callbacks — EarlyStopping, ModelCheckpoint, TensorBoard, ReduceLR
  7. Custom Layers & Models — Create your own layers with subclassing
  8. Project: MNIST Classifier 98%+ — End-to-end in 30 lines
  9. Summary & Page 3 Preview
šŸ¤”

1. Apa Itu Keras? — Tiga Cara Membangun Model

1. What Is Keras? — Three Ways to Build Models

Dari satu baris sampai arsitektur research-grade — Keras bisa semua
From one-liners to research-grade architectures — Keras does it all

Keras adalah API high-level yang terintegrasi di dalam TensorFlow (tf.keras). Ia menyediakan building blocks (layers, optimizers, losses, metrics) yang bisa dirangkai menjadi model. Ada 3 cara membangun model di Keras — pilih berdasarkan kompleksitas:

Keras is a high-level API integrated into TensorFlow (tf.keras). It provides building blocks (layers, optimizers, losses, metrics) that can be assembled into models. There are 3 ways to build models in Keras — choose based on complexity:

3 Cara Membangun Model Keras / 3 Ways to Build Keras Models 1. Sequential API 2. Functional API 3. Subclassing model = Sequential([ inputs = Input(shape) class MyModel(Model): Dense(128), x = Dense(64)(inputs) def call(self, x): Dense(10) outputs = Dense(10)(x) return self.fc(x) ]) model = Model(in, out) āœ… Simple stack āœ… Multi-input/output āœ… Full control āŒ No branching āœ… Skip connections āœ… Dynamic logic Best for: beginners Best for: most projects Best for: research
šŸ“š

2. Sequential API — Stack Layers Sederhana

2. Sequential API — Simple Layer Stacking

Paling populer: 80% model bisa dibangun dengan Sequential
Most popular: 80% of models can be built with Sequential

Sequential = tumpukan layer linear dari input ke output. Cocok untuk model yang datanya mengalir lurus tanpa percabangan. Ini cara tercepat untuk membuat model di Keras.

Sequential = a linear stack of layers from input to output. Perfect for models where data flows straight through without branching. This is the fastest way to build a model in Keras.

06_sequential_api.py — Sequential API Lengkappython
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

# ===========================
# Cara 1: List di constructor
# ===========================
model = keras.Sequential([
    layers.Dense(256, activation='relu', input_shape=(784,)),
    layers.BatchNormalization(),
    layers.Dropout(0.3),
    layers.Dense(128, activation='relu'),
    layers.BatchNormalization(),
    layers.Dropout(0.2),
    layers.Dense(10, activation='softmax')
])

# ===========================
# Cara 2: .add() satu per satu
# ===========================
model2 = keras.Sequential()
model2.add(layers.Dense(256, activation='relu', input_shape=(784,)))
model2.add(layers.BatchNormalization())
model2.add(layers.Dropout(0.3))
model2.add(layers.Dense(128, activation='relu'))
model2.add(layers.Dense(10, activation='softmax'))

# ===========================
# Inspect model
# ===========================
model.summary()
# ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”³ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”³ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”“
# ā”ƒ Layer (type)       ā”ƒ Output Shape    ā”ƒ  Param # ā”ƒ
# ┣━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━━━━━━┫
# ā”ƒ dense (Dense)      ā”ƒ (None, 256)     ā”ƒ  200,960 ā”ƒ
# ā”ƒ batch_norm         ā”ƒ (None, 256)     ā”ƒ    1,024 ā”ƒ
# ā”ƒ dropout            ā”ƒ (None, 256)     ā”ƒ        0 ā”ƒ
# ā”ƒ dense_1 (Dense)    ā”ƒ (None, 128)     ā”ƒ   32,896 ā”ƒ
# ā”ƒ ...                ā”ƒ                 ā”ƒ          ā”ƒ
# ┗━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━━━━━━┛
# Total params: ~236k

# Common layers cheat sheet:
# Dense(units, activation)     — fully connected
# Conv2D(filters, kernel)      — convolution (Page 3)
# LSTM(units)                  — recurrent (Page 5)
# BatchNormalization()         — normalize activations
# Dropout(rate)                — regularization
# Flatten()                    — 3D → 1D
# Embedding(vocab, dim)        — word → vector

šŸŽ“ Activation Functions di Keras:
'relu' → hidden layers (default terbaik).
'softmax' → output layer multi-kelas (probabilitas, sum=1).
'sigmoid' → output layer biner (0 atau 1).
'linear' → output layer regresi (nilai kontinu). Atau: None = no activation.

šŸŽ“ Activation Functions in Keras:
'relu' → hidden layers (best default).
'softmax' → multi-class output layer (probabilities, sum=1).
'sigmoid' → binary output layer (0 or 1).
'linear' → regression output layer (continuous values). Or: None = no activation.

⚔

3. Compile & Fit — Training dalam 3 Baris

3. Compile & Fit — Training in 3 Lines

compile() → pilih optimizer & loss. fit() → mulai training. Selesai.
compile() → choose optimizer & loss. fit() → start training. Done.
07_compile_fit.py — Training Workflowpython
import tensorflow as tf
from tensorflow import keras

# ===========================
# 1. COMPILE — configure training
# ===========================
model.compile(
    optimizer='adam',                         # or keras.optimizers.Adam(lr=1e-3)
    loss='sparse_categorical_crossentropy',    # labels: integers [0,1,2...]
    # loss='categorical_crossentropy',        # labels: one-hot [[1,0,0],...]
    # loss='binary_crossentropy',             # binary classification
    # loss='mse',                             # regression
    metrics=['accuracy']                      # track during training
)

# ===========================
# 2. FIT — train the model!
# ===========================
history = model.fit(
    X_train, y_train,              # training data
    epochs=20,                     # number of full passes
    batch_size=32,                 # samples per gradient update
    validation_split=0.2,          # 20% for validation
    # validation_data=(X_val, y_val),  # or provide explicit val set
    verbose=1,                     # progress bar
)
# Epoch 1/20 — loss: 0.3421 — accuracy: 0.9012 — val_loss: 0.1542
# Epoch 2/20 — loss: 0.1523 — accuracy: 0.9543 — val_loss: 0.1123
# ...

# ===========================
# 3. History — training curves
# ===========================
print(history.history.keys())
# dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])

# Plot training curves
import matplotlib.pyplot as plt
plt.plot(history.history['accuracy'], label='Train')
plt.plot(history.history['val_accuracy'], label='Val')
plt.xlabel('Epoch'); plt.ylabel('Accuracy'); plt.legend()
plt.show()

šŸŽ“ Loss Function Cheat Sheet:
sparse_categorical_crossentropy → labels integer (0, 1, 2, ...) — paling umum.
categorical_crossentropy → labels one-hot ([1,0,0], [0,1,0], ...).
binary_crossentropy → binary (0 atau 1).
mse → regresi (prediksi angka kontinu).
Tips: Jika bingung antara sparse vs categorical — pakai sparse (lebih mudah, tidak perlu one-hot encode labels).

šŸŽ“ Loss Function Cheat Sheet:
sparse_categorical_crossentropy → integer labels (0, 1, 2, ...) — most common.
categorical_crossentropy → one-hot labels ([1,0,0], [0,1,0], ...).
binary_crossentropy → binary (0 or 1).
mse → regression (predict continuous numbers).
Tip: If confused between sparse vs categorical — use sparse (easier, no need to one-hot encode labels).

šŸŽÆ

4. Evaluate & Predict — Testing dan Inference

4. Evaluate & Predict — Testing and Inference

Ukur performa di test set dan buat prediksi data baru
Measure performance on test set and make predictions on new data
08_evaluate_predict.pypython
# ===========================
# Evaluate on test set
# ===========================
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f"Test Loss: {test_loss:.4f}")
print(f"Test Accuracy: {test_acc:.1%}")  # 98.1%

# ===========================
# Predict on new data
# ===========================
predictions = model.predict(X_test[:5])
print(predictions.shape)  # (5, 10) — probabilities per class
print(predictions[0])     # [0.00, 0.00, 0.01, 0.97, ...] → class 3

# Get predicted class
import numpy as np
predicted_classes = np.argmax(predictions, axis=1)
print(f"Predicted: {predicted_classes}")  # [3, 1, 7, 2, 4]
print(f"Actual:    {y_test[:5]}")          # [3, 1, 7, 2, 4] āœ“

# ===========================
# Save & Load model
# ===========================
model.save("my_model.keras")                    # save entire model
loaded = keras.models.load_model("my_model.keras") # load back
# loaded.predict(X_test[:5]) → same results! āœ“
šŸ”€

5. Functional API — Arsitektur Kompleks

5. Functional API — Complex Architectures

Multi-input, multi-output, skip connections, shared layers — semua bisa
Multi-input, multi-output, skip connections, shared layers — all possible

Untuk arsitektur yang lebih kompleks dari "stack lurus", gunakan Functional API. Anda mendefinisikan alur data sebagai graf — setiap layer adalah fungsi yang dipanggil pada output layer sebelumnya.

For architectures more complex than a "straight stack", use the Functional API. You define the data flow as a graph — each layer is a function called on the output of the previous layer.

09_functional_api.py — Functional API & Residualpython
from tensorflow import keras
from tensorflow.keras import layers

# ===========================
# 1. Basic Functional API
# ===========================
inputs = keras.Input(shape=(784,), name="digits")
x = layers.Dense(128, activation="relu")(inputs)
x = layers.Dropout(0.3)(x)
x = layers.Dense(64, activation="relu")(x)
outputs = layers.Dense(10, activation="softmax")(x)

model = keras.Model(inputs=inputs, outputs=outputs, name="digit_classifier")

# ===========================
# 2. Residual Connection (Skip Connection)
# Sama seperti di ResNet!
# ===========================
inputs = keras.Input(shape=(256,))
x = layers.Dense(256, activation="relu")(inputs)
x = layers.BatchNormalization()(x)
x = layers.Dense(256)(x)                # no activation yet!
x = layers.Add()([x, inputs])            # ← SKIP CONNECTION!
x = layers.Activation("relu")(x)         # activate after add
outputs = layers.Dense(10, activation="softmax")(x)

residual_model = keras.Model(inputs, outputs, name="residual_net")

# ===========================
# 3. Multi-Input Model
# e.g., Image + Text → Classification
# ===========================
img_input = keras.Input(shape=(224, 224, 3), name="image")
txt_input = keras.Input(shape=(100,), name="text")

# Image branch
img_features = layers.Conv2D(32, 3, activation="relu")(img_input)
img_features = layers.GlobalAveragePooling2D()(img_features)
img_features = layers.Dense(64)(img_features)

# Text branch
txt_features = layers.Dense(64, activation="relu")(txt_input)

# Merge branches
merged = layers.Concatenate()([img_features, txt_features])
merged = layers.Dense(64, activation="relu")(merged)
output = layers.Dense(5, activation="softmax")(merged)

multi_model = keras.Model(
    inputs=[img_input, txt_input],
    outputs=output,
    name="multimodal"
)
multi_model.summary()

# Train with dict inputs:
# multi_model.fit({"image": img_data, "text": txt_data}, labels)

šŸŽ“ Sequential vs Functional — Kapan Pakai Mana?
Sequential: model lurus (Dense → Dense → Output). ~80% kasus.
Functional: ada percabangan, merge, skip connection, multi-input/output. ResNet, Inception, multi-modal models.
Subclassing: butuh dynamic logic di forward pass (if/else, loops). Research / custom architectures.

šŸŽ“ Sequential vs Functional — When to Use Which?
Sequential: straight-line model (Dense → Dense → Output). ~80% of cases.
Functional: branching, merging, skip connections, multi-input/output. ResNet, Inception, multi-modal models.
Subclassing: need dynamic logic in forward pass (if/else, loops). Research / custom architectures.

šŸ“ž

6. Callbacks — Kontrol Training Otomatis

6. Callbacks — Automatic Training Control

Stop otomatis, save model terbaik, monitor di TensorBoard — tanpa kode manual
Auto-stop, save best model, monitor in TensorBoard — no manual code needed

Callbacks adalah fungsi yang dipanggil di titik-titik tertentu selama training (akhir epoch, akhir batch, dll). Ini memungkinkan Anda mengontrol training secara otomatis tanpa mengawasi manual.

Callbacks are functions called at certain points during training (end of epoch, end of batch, etc). They let you automatically control training without manual monitoring.

10_callbacks.py — Callbacks Paling Pentingpython
from tensorflow import keras

callbacks = [
    # 1. EarlyStopping — stop jika val_loss tidak membaik
    keras.callbacks.EarlyStopping(
        monitor='val_loss',       # watch validation loss
        patience=5,               # wait 5 epochs before stopping
        restore_best_weights=True # rollback to best epoch!
    ),

    # 2. ModelCheckpoint — save model terbaik
    keras.callbacks.ModelCheckpoint(
        filepath='best_model.keras',
        monitor='val_accuracy',
        save_best_only=True,       # only save if improved
        verbose=1
    ),

    # 3. ReduceLROnPlateau — kurangi LR jika stuck
    keras.callbacks.ReduceLROnPlateau(
        monitor='val_loss',
        factor=0.5,               # LR Ɨ 0.5
        patience=3,               # wait 3 epochs
        min_lr=1e-6,              # floor
        verbose=1
    ),

    # 4. TensorBoard — visualisasi training
    keras.callbacks.TensorBoard(
        log_dir='./logs',
        histogram_freq=1,        # log weight histograms
    ),
]

# Use in training:
model.fit(X_train, y_train, epochs=100, callbacks=callbacks,
          validation_split=0.2)
# Training might stop at epoch 15 if val_loss plateaus!
# Best model auto-saved to best_model.keras
# View in TensorBoard: tensorboard --logdir ./logs

šŸŽ‰ Best Practice: Selalu gunakan minimal EarlyStopping + ModelCheckpoint di setiap training. Set epochs ke angka besar (100-1000) dan biarkan EarlyStopping menentukan kapan berhenti. Ini mencegah overfitting sekaligus memastikan Anda selalu punya model terbaik tersimpan.

šŸŽ‰ Best Practice: Always use at least EarlyStopping + ModelCheckpoint in every training run. Set epochs to a large number (100-1000) and let EarlyStopping decide when to stop. This prevents overfitting while ensuring you always have the best model saved.

šŸ”§

7. Custom Layers & Models — Subclassing

7. Custom Layers & Models — Subclassing

Buat layer dan model custom dengan Python class — full control
Create custom layers and models with Python classes — full control
11_custom_layers.py — Custom Layer & Modelpython
import tensorflow as tf
from tensorflow import keras

# ===========================
# 1. Custom Layer
# ===========================
class ResidualBlock(keras.layers.Layer):
    """Residual block: x + F(x)"""

    def __init__(self, units, **kwargs):
        super().__init__(**kwargs)
        self.dense1 = keras.layers.Dense(units, activation='relu')
        self.dense2 = keras.layers.Dense(units)  # no activation!
        self.bn = keras.layers.BatchNormalization()
        self.add = keras.layers.Add()

    def call(self, inputs, training=False):
        x = self.dense1(inputs)
        x = self.bn(x, training=training)
        x = self.dense2(x)
        return tf.nn.relu(self.add([x, inputs]))  # residual!

# ===========================
# 2. Custom Model
# ===========================
class MyClassifier(keras.Model):
    def __init__(self, num_classes):
        super().__init__()
        self.flatten = keras.layers.Flatten()
        self.block1 = ResidualBlock(128)
        self.block2 = ResidualBlock(128)
        self.dropout = keras.layers.Dropout(0.3)
        self.classifier = keras.layers.Dense(num_classes, activation='softmax')

    def call(self, inputs, training=False):
        x = self.flatten(inputs)
        x = keras.layers.Dense(128, activation='relu')(x)  # project to 128
        x = self.block1(x, training=training)
        x = self.block2(x, training=training)
        x = self.dropout(x, training=training)
        return self.classifier(x)

# Use exactly like any Keras model!
model = MyClassifier(num_classes=10)
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
# model.fit(X_train, y_train, ...)

šŸŽ“ Penting: training=True/False
Beberapa layer berperilaku berbeda saat training vs inference: Dropout (aktif saat training, off saat inference), BatchNorm (pakai batch stats saat training, running stats saat inference). Selalu forward training parameter ke layer-layer ini!

šŸŽ“ Important: training=True/False
Some layers behave differently during training vs inference: Dropout (active during training, off during inference), BatchNorm (uses batch stats during training, running stats during inference). Always forward the training parameter to these layers!

šŸ”¢

8. Proyek: MNIST Classifier 98%+ — End to End

8. Project: MNIST Classifier 98%+ — End to End

Dari load data sampai evaluasi — semua dalam satu file
From loading data to evaluation — everything in one file
12_mnist_complete.py — MNIST 98%+ Classifier šŸ”„python
import tensorflow as tf
from tensorflow import keras
import numpy as np

# ===========================
# 1. LOAD & PREPROCESS DATA
# ===========================
(X_train, y_train), (X_test, y_test) = keras.datasets.mnist.load_data()

# Normalize: [0, 255] → [0, 1]
X_train = X_train.reshape(-1, 784).astype('float32') / 255.0
X_test = X_test.reshape(-1, 784).astype('float32') / 255.0

print(f"Train: {X_train.shape}, Test: {X_test.shape}")
# Train: (60000, 784), Test: (10000, 784)

# ===========================
# 2. BUILD MODEL
# ===========================
model = keras.Sequential([
    keras.layers.Dense(256, activation='relu', input_shape=(784,)),
    keras.layers.BatchNormalization(),
    keras.layers.Dropout(0.3),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.BatchNormalization(),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10, activation='softmax')
])

# ===========================
# 3. COMPILE
# ===========================
model.compile(
    optimizer=keras.optimizers.Adam(learning_rate=1e-3),
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

# ===========================
# 4. TRAIN with callbacks
# ===========================
callbacks = [
    keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True),
    keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=3)
]

history = model.fit(
    X_train, y_train,
    epochs=50,
    batch_size=64,
    validation_split=0.1,
    callbacks=callbacks,
    verbose=1
)

# ===========================
# 5. EVALUATE
# ===========================
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f"\nšŸŽÆ Test Accuracy: {test_acc:.1%}")
# šŸŽÆ Test Accuracy: 98.2% ← with just Dense layers! šŸŽ‰
# With CNN (Page 3) → 99%+

# ===========================
# 6. SAVE
# ===========================
model.save("mnist_classifier.keras")
print("āœ… Model saved!")

šŸŽ‰ 98.2% Akurasi MNIST — Hanya Dense Layers!
Bandingkan: di seri Neural Network, kita butuh ratusan baris NumPy manual untuk mencapai 97%. Dengan Keras: 30 baris kode, lengkap dengan BatchNorm, Dropout, Adam optimizer, EarlyStopping, dan save model. Dan ini bahkan belum pakai CNN (Page 3)!

šŸŽ‰ 98.2% MNIST Accuracy — Just Dense Layers!
Compare: in our Neural Network series, we needed hundreds of lines of manual NumPy to achieve 97%. With Keras: 30 lines of code, complete with BatchNorm, Dropout, Adam optimizer, EarlyStopping, and model saving. And this doesn't even use CNN (Page 3)!

šŸ“

9. Ringkasan Page 2

9. Page 2 Summary

Apa yang sudah kita pelajari
What we've learned
KonsepApa ItuKode Kunci
Sequential APIStack layers linear sederhanaSequential([Dense(), ...])
Functional APIArsitektur kompleks (multi-input, skip)Model(inputs, outputs)
compile()Pilih optimizer, loss, metricsmodel.compile('adam', ...)
fit()Training loop otomatismodel.fit(X, y, epochs=N)
evaluate()Test performa di test setmodel.evaluate(X_test, y)
predict()Inference pada data barumodel.predict(X_new)
EarlyStoppingStop jika val_loss tidak turunpatience=5
ModelCheckpointAuto-save model terbaiksave_best_only=True
Custom LayerBuat layer sendiri via subclassclass MyLayer(Layer)
ConceptWhat It IsKey Code
Sequential APISimple linear layer stackSequential([Dense(), ...])
Functional APIComplex architectures (multi-input, skip)Model(inputs, outputs)
compile()Choose optimizer, loss, metricsmodel.compile('adam', ...)
fit()Automatic training loopmodel.fit(X, y, epochs=N)
evaluate()Test performance on test setmodel.evaluate(X_test, y)
predict()Inference on new datamodel.predict(X_new)
EarlyStoppingStop if val_loss doesn't improvepatience=5
ModelCheckpointAuto-save best modelsave_best_only=True
Custom LayerCreate own layer via subclassclass MyLayer(Layer)
← Page Sebelumnya← Previous Page

Page 1 — Pengenalan TensorFlow & Tensor Operations

šŸ“˜

Coming Next: Page 3 — CNN & Image Classification

Computer vision dengan TensorFlow: Conv2D, MaxPooling, data augmentation (tf.image & Keras layers), transfer learning dengan MobileNet & ResNet, klasifikasi CIFAR-10 dan custom dataset, TensorBoard visualization. Stay tuned!

šŸ“˜

Coming Next: Page 3 — CNN & Image Classification

Computer vision with TensorFlow: Conv2D, MaxPooling, data augmentation (tf.image & Keras layers), transfer learning with MobileNet & ResNet, CIFAR-10 and custom dataset classification, TensorBoard visualization. Stay tuned!