Model yang kita bangun sejauh ini menjawab satu jenis pertanyaan: diberikan masukan x, apa label y atau kelanjutan urutannya. Section ini membalik arah pertanyaannya — kita ingin model yang menghasilkan data x baru yang menyerupai data pelatihan, tanpa diminta memprediksi label apa pun. Perpindahan fokus ini punya konsekuensi besar pada arsitektur, loss, dan cara mengevaluasi model. Chapter ini membangun fondasinya: definisi presisi discriminative vs generative, peta keluarga pendekatan, dan demo model generatif paling sederhana yang bisa kita tulis — sebuah Gaussian yang di-fit pada data 2D lalu dipakai menghasilkan sampel baru.

Discriminative vs Generative #

Perbedaan keduanya terletak pada distribusi probabilitas apa yang dipelajari dari data:

  • Discriminative memodelkan P(y|x) — peluang label conditional given masukan. Seluruh classifier yang kita latih sejak Neuron Artifisial masuk kategori ini.
  • Generative memodelkan P(x) (distribusi data itu sendiri) atau P(x,y) (data beserta labelnya secara bersama). Dari model ini kita bisa menarik sampel x baru.

| Aspek | Discriminative P(y|x) | Generative P(x) / P(x,y) | |—|—|—| | Pertanyaan | label apa untuk x ini? | bagaimana bentuk data ini? | | Keluaran | prediksi label / skor | sampel data baru | | Butuh label saat latih | ya | tidak (untuk P(x)) | | Bisa menebak label | ya, langsung | ya, lewat aturan Bayes | | Bisa menghasilkan data | tidak | ya |

Baris terakhir tabel inilah asimetri pentingnya: model generatif menghitung P(y|x) lewat Bayes — P(y|x) = P(x,y)/P(x) — tetapi model discriminative tidak punya representasi P(x) sehingga tidak ada jalan menghasilkan data baru darinya.

Demo: Gaussian, Model Generatif Paling Sederhana #

Sebelum neural network, mari kita buktikan asimetri tersebut dengan model generatif termudah: satu Gaussian per kelas pada data 2D. Meng-fit model ini hanya berarti menghitung mean dan kovarian empiris tiap kelas, ditambah prior kelas. Berkas gaussian_fit.py melatih dua model pada data yang sama — regresi logistik sebagai wakil discriminative, dan Gaussian per kelas sebagai wakil generatif:

python
"""Model generatif paling sederhana: Gaussian fit pada data 2D.

Dua sudut pandang dilatih pada data yang sama:
1. Discriminative: regresi logistik memodelkan P(y|x) -- menebak label.
2. Generative: Gaussian per kelas + prior memodelkan P(x,y) -- bisa sampling.

Sampel sintetis dari model generatif dibandingkan statistiknya dengan data
asli, lalu posterior Bayes P(y|x) dari model generatif dibandingkan dengan
prediksi regresi logistik. Deterministik (seed tetap), diuji di CPU.
"""

import numpy as np
from sklearn.linear_model import LogisticRegression

rng = np.random.default_rng(42)

# ---------- 1. Data sintetis: dua cluster 2D ----------
MU_ASLI = [(2.0, 3.0), (6.0, 5.0)]
COV_ASLI = [
    [[0.60, 0.30], [0.30, 0.50]],
    [[0.90, -0.25], [-0.25, 0.60]],
]
X0 = rng.multivariate_normal(MU_ASLI[0], COV_ASLI[0], size=300)
X1 = rng.multivariate_normal(MU_ASLI[1], COV_ASLI[1], size=500)
X = np.vstack([X0, X1])
y = np.array([0] * len(X0) + [1] * len(X1))

acak = rng.permutation(len(X))
batas = int(0.8 * len(X))
X_latih, y_latih = X[acak[:batas]], y[acak[:batas]]
X_uji, y_uji = X[acak[batas:]], y[acak[batas:]]
print(f"data: {len(X)} titik 2D -> {len(X_latih)} latih + {len(X_uji)} uji")
print(f"prior kelas 1 di data latih: {y_latih.mean():.3f}")
print()

# ---------- 2. Discriminative: P(y|x) lewat regresi logistik ----------
clf = LogisticRegression().fit(X_latih, y_latih)
akurasi_disc = clf.score(X_uji, y_uji)
print(f"=== Model discriminative: P(y|x) ===")
print(f"regresi logistik, akurasi uji: {akurasi_disc:.3f}")
print("yang dipelajari hanya garis pemisah; P(x) tidak dimodelkan.")
print()

# ---------- 3. Generative: P(x,y) = P(x|y) * P(y) ----------
mu = [X_latih[y_latih == k].mean(axis=0) for k in (0, 1)]
cov = [np.cov(X_latih[y_latih == k].T) for k in (0, 1)]
prior1 = y_latih.mean()
print("=== Model generative: P(x,y) = P(x|y) P(y) ===")
for k in (0, 1):
    print(f"kelas {k}: mean {mu[k].round(3)}, kovarian {cov[k].round(3).tolist()}")
print()

# ---------- 4. Sampling dari model generatif ----------
y_sint = rng.random(800) < prior1
x_sint = np.vstack([
    rng.multivariate_normal(mu[0], cov[0], size=int((~y_sint).sum())),
    rng.multivariate_normal(mu[1], cov[1], size=int(y_sint.sum())),
])
print("=== Sampling 800 titik dari model ===")
print(f"{'statistik':24s} {'data asli':>18s} {'sampel model':>18s}")
for nama, f in [
    ("mean x1", lambda M: M[:, 0].mean()),
    ("mean x2", lambda M: M[:, 1].mean()),
    ("std x1", lambda M: M[:, 0].std()),
    ("std x2", lambda M: M[:, 1].std()),
    ("korelasi x1,x2", lambda M: np.corrcoef(M.T)[0, 1]),
]:
    print(f"{nama:24s} {f(X):>18.3f} {f(x_sint):>18.3f}")
print()


# ---------- 5. Generative juga bisa menebak label (lewat Bayes) ----------
def logpdf(X, mu_k, cov_k):
    """Log-density Gaussian multivariat untuk tiap baris X."""
    d = X.shape[1]
    diff = X - mu_k
    inv = np.linalg.inv(cov_k)
    _, logdet = np.linalg.slogdet(cov_k)
    kuadrat = np.einsum("ij,jk,ik->i", diff, inv, diff)
    return -0.5 * (d * np.log(2 * np.pi) + logdet + kuadrat)


log_rasio = (
    logpdf(X_uji, mu[1], cov[1]) + np.log(prior1)
    - logpdf(X_uji, mu[0], cov[0]) - np.log(1 - prior1)
)
posterior_bayes = 1 / (1 + np.exp(-log_rasio))
pred_bayes = posterior_bayes > 0.5
akurasi_bayes = (pred_bayes == y_uji).mean()
print("=== P(y|x) dari model generative (aturan Bayes) ===")
print(f"akurasi uji aturan Bayes : {akurasi_bayes:.3f}")
print(f"akurasi uji regresi log. : {akurasi_disc:.3f}")
print()
print("perbandingan P(y=1|x) pada 3 titik uji pertama:")
prob_log = clf.predict_proba(X_uji)[:, 1]
for i in range(3):
    titik = X_uji[i].round(2)
    print(f"  x={str(titik.tolist()):<16s} logistik={prob_log[i]:.3f}"
          f"  bayes={posterior_bayes[i]:.3f}")

Output yang Dihasilkan:

text
data: 800 titik 2D -> 640 latih + 160 uji
prior kelas 1 di data latih: 0.633

=== Model discriminative: P(y|x) ===
regresi logistik, akurasi uji: 0.994
yang dipelajari hanya garis pemisah; P(x) tidak dimodelkan.

=== Model generative: P(x,y) = P(x|y) P(y) ===
kelas 0: mean [2.011 2.984], kovarian [[0.691, 0.309], [0.309, 0.428]]
kelas 1: mean [5.999 4.999], kovarian [[0.856, -0.272], [-0.272, 0.63]]

=== Sampling 800 titik dari model ===
statistik                         data asli       sampel model
mean x1                               4.523              4.569
mean x2                               4.224              4.265
std x1                                2.130              2.137
std x2                                1.214              1.203
korelasi x1,x2                        0.684              0.734

=== P(y|x) dari model generative (aturan Bayes) ===
akurasi uji aturan Bayes : 0.994
akurasi uji regresi log. : 0.994

perbandingan P(y=1|x) pada 3 titik uji pertama:
  x=[5.8, 5.62]      logistik=1.000  bayes=1.000
  x=[1.32, 3.47]     logistik=0.000  bayes=0.000
  x=[5.4, 3.04]      logistik=0.932  bayes=1.000

Dua kelompok angka layak digarisbawahi. Pertama, 800 sampel sintetis dari model generatif mereplikasi statistik data asli dengan akurat: mean dimensi pertama 4,569 vs 4,523, simpangan baku 2,137 vs 2,130, hingga korelasi antar dimensi 0,734 vs 0,684 — inilah makna “menyerupai data pelatihan” dalam bentuk terukur. Kedua, aturan Bayes dari model generatif mencapai akurasi uji 0,994, sama dengan regresi logistik, dan probabilitas per titik pun nyaris berimpit. Mari kita telaah kode di atas baris per baris:

  1. Baris 15 (rng = np.random.default_rng(42)): generator angka acak berbibit tetap — seluruh percobaan chapter ini dapat direproduksi persis.
  2. Baris 18-26: data sintetis 800 titik dari dua Gaussian 2D (rng.multivariate_normal, dokumentasi NumPy ); 300 titik kelas 0 dan 500 titik kelas 1 sehingga prior tidak seimbang.
  3. Baris 28-31: pembagian latih/uji lewat permutasi acak — model di-fit hanya pada 640 titik latih.
  4. Baris 37-38: sisi discriminative — LogisticRegression mempelajari garis pemisah P(y|x); tidak ada bagian dari model ini yang tahu bagaimana data tersebar.
  5. Baris 45-47: sisi generative — “training”-nya sesederhana statistik: mean dan kovarian empiris per kelas (P(x|y)) dikali proporsi kelas (P(y)).
  6. Baris 54-58: operasi yang mustahil bagi model discriminative — menarik 800 sampel baru: pilih kelas menurut prior, lalu tarik titik dari Gaussian kelas tersebut.
  7. Baris 61-68: perbandingan statistik data asli vs sampel model pada lima ukuran — angka-angka pada tabel keluaran.
  8. Baris 73-80: logpdf menghitung log-densitas Gaussian multivariat manual (invers dan determinan kovarian lewat np.linalg) — bahan baku aturan Bayes.
  9. Baris 83-89: aturan Bayes dalam bentuk log-rasio P(x|y=1)P(y=1) / P(x|y=0)P(y=0); sigmoid dari rasio itu adalah P(y=1|x) versi model generatif.
  10. Baris 94-99: perbandingan berdampingan P(y=1|x) dari dua model pada tiga titik uji — keduanya sepakat pada titik yang mudah; pada titik ambigu [5.4, 3.04] keduanya memilih kelas 1 dengan tingkat keyakinan berbeda (0,932 vs 1,000).

Peta Keluarga Model Generatif #

Gaussian pada demo di atas bekerja karena datanya memang Gaussian. Data nyata — gambar, teks, audio — terlalu kompleks untuk distribusi parametrik sederhana, sehingga muncul empat keluarga besar pendekatan neural:

Keempatnya berbeda pada cara menarik sampel. Autoregressive menulis token demi token mengikuti rantai kondisional — persis mekanisme yang kita bedah di chapter Next-Token Prediction ; LLM karenanya adalah model generatif. Pendekatan latent variable (VAE) menarik vektor laten dari distribusi sederhana lalu menerjemahkannya menjadi data. GAN menghasilkan data lewat kompetisi dua jaringan tanpa menulis P(x) secara eksplisit. Diffusion membalik proses penambahan derau selangkah demi selangkah.

Kegunaan Model Generatif #

KegunaanMekanismeContoh nyata
Data sintetis / augmentasisampel baru menyerupai data latihmenambah data latih yang langka
Denoisingmodel tahu “wajah” data, derau tidakmembersihkan sinyal dari noise
Mengisi bagian kosongdistribusi bersyarat pada bagian terlihatinpainting gambar, imputasi data
Deteksi anomalidata ganjil berpeluang rendah pada P(x)transaksi tidak wajar
Karya kreatifsampling dari area berpeluang tinggigambar, musik, teks

Satu masalah muncul begitu kita meninggalkan Gaussian: bagaimana jaringan neural mempelajari representasi data yang cukup baik sehingga bisa dibangkitkan ulang? Jawaban pertamanya adalah belajar mengompresi lalu merekonstruksi — autoencoder, chapter berikutnya.