Model pada Chapter sebelumnya hanya punya satu parameter yang kita perbarui dengan tangan lewat assign_sub. Model nyata memuat ratusan hingga jutaan parameter yang tersusun dari layer, dan menulis loop manual untuk semuanya membuat kode cepat membesar tanpa perlu. Keras menyediakan dua gaya penyusunan model — Sequential untuk tumpukan lurus dan Functional untuk graf dengan percabangan — dan keduanya menghasilkan objek tf.keras.Model dengan antarmuka latih yang sama. Chapter ini membangun model pertama kita dengan kedua gaya tersebut, membaca model.summary(), menghitung jumlah parameter tiap layer Dense, lalu menjalankan forward pass dengan predict pada data mainan yang diuji nyata.
Sequential API: Tumpukan Layer #
Sequential adalah gaya paling ringkas: kita mendaftar layer dari bawah ke atas, dan data mengalir lurus mengikuti urutan itu. tf.keras.Input(shape=(2,)) mendeklarasikan bahwa setiap contoh data punya dua fitur — sumbu batch tidak ditulis karena ukurannya bebas. Setiap Dense menyimpan matriks bobot dan vektor bias yang bentuknya ditentukan dari bentuk masukan dan jumlah unit. Berkas model_sequential.py membangun jaringan kecil 2 → 4 → 1 lalu memeriksanya:
"""Model Sequential: susun layer Dense, baca summary, dan jalankan predict."""
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
import numpy as np
import tensorflow as tf
tf.keras.utils.set_random_seed(42)
model = tf.keras.Sequential(
[
tf.keras.Input(shape=(2,), name="masukan"),
tf.keras.layers.Dense(4, activation="relu", name="sembunyi"),
tf.keras.layers.Dense(1, name="keluaran"),
]
)
model.summary()
print()
print("Parameter per layer:")
for layer in model.layers:
bobot, bias = layer.get_weights()
print(f" {layer.name:9s}: bobot {bobot.shape} + bias {bias.shape} = {bobot.size + bias.size} parameter")
print("model.count_params() :", model.count_params())
X = np.array([[0.0, 0.0],
[1.0, 0.0],
[0.0, 1.0],
[1.0, 1.0]], dtype=np.float32)
y_pred = model.predict(X, verbose=0)
print()
print("Prediksi model (belum dilatih):")
print(np.round(y_pred, 4))
model_tunda = tf.keras.Sequential([tf.keras.layers.Dense(1)])
print()
print("Sebelum build -> jumlah tensor bobot:", len(model_tunda.weights))
model_tunda.build(input_shape=(None, 2))
print("Setelah build(input_shape=(None, 2)):", len(model_tunda.weights))Output yang Dihasilkan:
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type) ┃ Output Shape ┃ Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ sembunyi (Dense) │ (None, 4) │ 12 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ keluaran (Dense) │ (None, 1) │ 5 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 17 (68.00 B)
Trainable params: 17 (68.00 B)
Non-trainable params: 0 (0.00 B)
Parameter per layer:
sembunyi : bobot (2, 4) + bias (4,) = 12 parameter
keluaran : bobot (4, 1) + bias (1,) = 5 parameter
model.count_params() : 17
Prediksi model (belum dilatih):
[[0. ]
[1.2181]
[0.5366]
[0.4845]]
Sebelum build -> jumlah tensor bobot: 0
Setelah build(input_shape=(None, 2)): 2Ringkasan model menunjukkan arsitektur 2 → 4 → 1 dengan 17 parameter — angka yang bisa kita hitung ulang dari rumus layer Dense: bobot berbentuk (masukan × unit) ditambah bias sebanyak unit. Prediksi empat baris data juga sudah bisa dijalankan meskipun model belum pernah dilatih, karena predict hanya melakukan forward pass — kompilasi loss dan optimizer belum diperlukan pada tahap ini.
Mari kita telaah kode di atas baris per baris:
- Baris 10 (
tf.keras.utils.set_random_seed(42)): menyetel seed Python, NumPy, TensorFlow, dan Keras sekaligus sehingga inisialisasi bobot serta hasilpredictsama pada setiap eksekusi. - Baris 12-18 (
tf.keras.Sequential([...])): tiga anggota daftar —Inputdua fitur,Denseempat unit dengan aktivasi ReLU, danDensesatu unit tanpa aktivasi (keluaran linear, standar untuk regresi). - Baris 19 (
model.summary()): mencetak tabel layer beserta shape keluaran(None, 4)dan(None, 1);Nonedi posisi pertama berarti ukuran batch bebas, dan kolomParam #menghitung bobot plus bias tiap layer. - Baris 23-26 (
get_weightsdancount_params): tiapDensemenyimpan dua tensor — bobot(2, 4)dan bias(4,)pada layer tersembunyi,(4, 1)dan(1,)pada layer keluaran. Hitungan manualnya:2×4 + 4 = 12dan4×1 + 1 = 5, total17— cocok denganmodel.count_params(). - Baris 28-35 (
model.predict): mengalirkan empat contoh data melalui jaringan. Nilai keluaran seperti1.2181dan0.5366belum bermakna — bobotnya masih acak — tetapi bentuk mekanismenya sudah lengkap. - Baris 37-41 (
model_tunda): model tanpaInputtidak punya bobot sama sekali (0tensor) sampaibuild(input_shape=(None, 2))dipanggil; setelah itu kernel dan bias tercipta (2tensor). Inilah sebabnyasummarykadang tidak bisa menampilkan apa pun sebelum bentuk masukan diketahui.
Functional API: Graf Eksplisit #
Gaya Functional membangun model seperti merangkai kalimat: kita membuat tensor masukan, memanggil layer atas tensor itu untuk menghasilkan tensor baru, lalu membungkus ujung ke ujungnya menjadi satu Model. Kekuatan gaya ini baru terasa ketika graf bercabang — beberapa masukan, beberapa keluaran, atau sambungan lompatan yang akan kita jumpai pada section CNN. Alur bentuk data pada model di bawah ini dapat dilukiskan sebagai:
Berkas model_functional.py membangun graf tersebut — klasifikasi tiga kelas dengan keluaran softmax:
"""Functional API: susun graf layer eksplisit lalu bungkus jadi Model."""
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
import numpy as np
import tensorflow as tf
tf.keras.utils.set_random_seed(42)
masukan = tf.keras.Input(shape=(2,), name="masukan")
sembunyi = tf.keras.layers.Dense(8, activation="relu", name="sembunyi")(masukan)
keluaran = tf.keras.layers.Dense(3, activation="softmax", name="probabilitas")(sembunyi)
model = tf.keras.Model(inputs=masukan, outputs=keluaran, name="klasifikasi_mini")
model.summary()
X = np.array([[0.5, -1.0],
[-2.0, 0.3],
[1.5, 1.5]], dtype=np.float32)
y_pred = model.predict(X, verbose=0)
print()
print("Probabilitas tiga kelas (belum dilatih):")
print(np.round(y_pred, 4))
print("Jumlah tiap baris:", np.round(y_pred.sum(axis=1), 4))Output yang Dihasilkan:
Model: "klasifikasi_mini"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type) ┃ Output Shape ┃ Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ masukan (InputLayer) │ (None, 2) │ 0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ sembunyi (Dense) │ (None, 8) │ 24 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ probabilitas (Dense) │ (None, 3) │ 27 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 51 (204.00 B)
Trainable params: 51 (204.00 B)
Non-trainable params: 0 (0.00 B)
Probabilitas tiga kelas (belum dilatih):
[[0.3168 0.3299 0.3534]
[0.4793 0.2363 0.2844]
[0.2186 0.3055 0.4758]]
Jumlah tiap baris: [1. 1. 1.]Mari kita telaah kode di atas baris per baris:
- Baris 12 (
masukan = tf.keras.Input(shape=(2,))): membuat tensor simbolik yang menjadi titik masuk graf; belum ada data sungguhan yang mengalir. - Baris 13-14 (pemanggilan layer):
Dense(8, activation="relu")(masukan)memanggil layer atas tensor masukan dan mengembalikan tensor keluaran baru — polalayer(tensor)inilah tanda tangan Functional API. Tensor itu langsung dipakai layer berikutnya hingga menghasilkankeluaranberukuran tiga dengan softmax. - Baris 16 (
tf.keras.Model(...)): membungkus jalurmasukan→keluaranmenjadi model utuh; argumenname="klasifikasi_mini"muncul sebagai judul padasummary. - Baris 17 (
model.summary()): berbeda dari Sequential, ringkasan menampilkan barisInputLayereksplisit dengan nol parameter. Hitungan parameternya:2×8 + 8 = 24dan8×3 + 3 = 27, total51. - Baris 19-26 (
predict): tiga contoh data menghasilkan matriks probabilitas3×3. Baris terakhir memverifikasi sifat softmax — jumlah probabilitas tiap baris tepat1.0, sehingga ketiga kelas saling melengkapi.
Kapan Memakai Gaya yang Mana #
Ketiga gaya menghasilkan tf.keras.Model yang sama-sama bisa di-compile, di-fit, dan di-predict; pilihan gaya urusan bentuk graf dan kenyamanan, bukan kemampuan. Tabel berikut menjadi panduan singkat:
| Gaya | Cocok untuk | Contoh pemakaian |
|---|---|---|
| Sequential | tumpukan lurus tanpa cabang | MLP regresi dan klasifikasi dasar |
| Functional | graf bercabang, multi masukan/keluaran | model dua masukan, sambungan lompatan CNN |
| Subclassing | perilaku forward yang sepenuhnya kustom | arsitektur riset dengan logika khusus |
Gaya Subclassing — mewarisi tf.keras.Model dan menulis metode call() sendiri — kita bahas lebih dalam ketika tiba waktunya menulis komponen kustom. Dokumentasi resmi ketiga gaya tersedia di tensorflow.org/guide/keras
, dan rincian layer Dense di tf.keras.layers.Dense
.
Ringkasan #
Kita telah menyusun model dua gaya: Sequential membangun tumpukan 2 → 4 → 1 dengan 17 parameter yang jumlahnya bisa diverifikasi manual, sementara Functional merangkai graf 2 → 8 → 3 dengan 51 parameter dan keluaran softmax. model.summary(), get_weights(), count_params(), dan build(input_shape=...) memberi kita kaca pembesar untuk membaca isi model sebelum dilatih. Namun model-model ini masih belum tahu cara belajar: prediksinya acak karena tidak ada ukuran kesalahan dan aturan pembaruan bobot. Kedua bahan itulah — loss dan optimizer — yang menjadi topik Chapter berikutnya, disatukan lewat model.compile().