Pada chapter sebelumnya kita menjalankan agen acak dan memperoleh angka pembanding berupa rata-rata return -0.430. Loop agent-environment tampak sederhana, tetapi di dalamnya tersimpan satu keputusan yang sepenuhnya berada di tangan kita sebagai perancang: rumusan reward. Environment ditentukan oleh masalah yang dihadapi, begitu pula ruang state dan daftar aksi; reward adalah satu-satunya bagian yang kita tulis sendiri, dan rumusan itulah seluruh “materi ajar” yang dibaca agen. Pada chapter ini kita membedah anatomi satu interaksi, membedakan observasi dari state, lalu membuktikan dengan pencarian lengkap bahwa dua desain reward yang berbeda menghasilkan kebijakan optimal yang berlawanan arah pada dunia yang sama persis.
Anatomi Satu Interaksi #
Setiap langkah reinforcement learning terdiri atas empat peristiwa berurutan: agent membaca state s, memilih aksi a, lalu environment membalas dengan reward r dan state baru s'. Tabel berikut memetakan keempatnya ke dunia mini yang kita pakai:
| Peristiwa | Pelaku | Padanan di GridWorld mini |
|---|---|---|
| membaca state | agent | posisi agen (baris, kolom) |
| memilih aksi | agent (kebijakan π) | kanan, kiri, bawah, atas |
| menghitung reward | environment | misalnya -0.05 per langkah, +1 di target |
| memindahkan agen | environment | posisi baru, atau tetap bila menabrak dinding |
Pembagian peran ini penting: agent tidak pernah melihat aturan environment, agent hanya melihat pasangan (reward, state_baru) yang datang setiap kali aksi dikirim. Segala perbaikan perilaku harus digali dari pola pasangan itu, tanpa koreksi langsung seperti label pada supervised learning.
Demo Dunia Lumpur: Dua Desain Reward #
Kita uji seberapa besar pengaruh desain reward dengan dunia kecil 2 baris × 4 kolom. Agen mulai di (0,0); target (0,3) memberi +1 dan episode berakhir. Dua sel di baris atas, (0,1) dan (0,2), adalah lumpur yang mengenai penalti -0.2 saat dimasuki. Dari start tersedia dua keluarga rute: rute lurus sepanjang 3 langkah yang melewati dua sel lumpur, atau rute memutar lewat baris bawah sepanjang 5 langkah tanpa lumpur.
Agar perbedaan perilaku murni berasal dari desain reward — bukan dari keanehan algoritma belajar — kebijakan optimal tiap desain dicari dengan pencarian lengkap: seluruh 4^7 = 16.384 kebijakan deterministik diuji satu per satu memakai product dari itertools
. Berkas desain_reward.py membandingkan desain A (tanpa penalti langkah) melawan desain B (setiap langkah dikenai -0.3):
"""Dua desain reward pada dunia lumpur 2x4 -> kebijakan optimal berbeda.
Papan 2 baris x 4 kolom. Start (0,0), target (0,3) terminal bernilai +1.
Sel (0,1) dan (0,2) adalah lumpur: memasukinya dikenai penalti -0.2.
Rute memutar lewat baris bawah panjang 5 langkah tanpa lumpur; rute lurus
lewat baris atas panjang 3 langkah melewati 2 sel lumpur.
Desain A: tanpa penalti langkah. Desain B: setiap langkah dikenai -0.3.
Kedua desain diselesaikan dengan pencarian lengkap (brute force) atas
seluruh 4^7 = 16.384 kebijakan deterministik, tanpa algoritma belajar.
"""
from itertools import product
BARIS, KOLOM = 2, 4
START = (0, 0)
GOAL = (0, 3)
LUMPUR = {(0, 1): -0.2, (0, 2): -0.2}
AKSI = [(0, 1), (0, -1), (1, 0), (-1, 0)] # kanan, kiri, bawah, atas
NAMA = ["kanan", "kiri ", "bawah", "atas "]
STATE_URUT = [s for s in [(b, k) for b in range(BARIS) for k in range(KOLOM)]
if s != GOAL] # 7 state non-terminal
def step(state, aksi, penalti_langkah):
"""Satu interaksi: kembalikan (state_baru, reward, selesai)."""
db, dk = AKSI[aksi]
nb, nk = state[0] + db, state[1] + dk
if not (0 <= nb < BARIS and 0 <= nk < KOLOM):
nb, nk = state # dinding: agen diam
reward = penalti_langkah
if (nb, nk) in LUMPUR:
reward += LUMPUR[(nb, nk)]
if (nb, nk) == GOAL:
reward += 1.0
return (nb, nk), reward, (nb, nk) == GOAL
def jalankan(kebijakan, penalti_langkah, maks_langkah=50):
"""Evaluasi satu kebijakan dari START; kembalikan (return, rute)."""
state, total, rute = START, 0.0, [START]
for _ in range(maks_langkah):
state, reward, selesai = step(state, kebijakan[state], penalti_langkah)
total += reward
rute.append(state)
if selesai:
return total, rute
return total, rute
def cari_terbaik(penalti_langkah):
"""Brute force seluruh 16.384 kebijakan; kembalikan yang terbaik."""
terbaik, return_terbaik, sampai_target = None, -1e9, 0
for kombinasi in product(range(4), repeat=len(STATE_URUT)):
kebijakan = dict(zip(STATE_URUT, kombinasi))
total, rute = jalankan(kebijakan, penalti_langkah)
if rute[-1] == GOAL:
sampai_target += 1
if total > return_terbaik:
terbaik, return_terbaik = kebijakan, total
return terbaik, return_terbaik, sampai_target
# ---- Bagian 1: anatomi loop di bawah desain B ----
print("Anatomi loop agent-environment (desain B, penalti langkah -0.30):")
state = START
for aksi in [0, 2, 0, 0]:
nama = NAMA[aksi].strip()
state_baru, reward, selesai = step(state, aksi, -0.3)
print(f" state {state} --aksi {nama}--> reward {reward:+.2f}, "
f"state baru {state_baru}")
state = state_baru
print(" (setiap langkah = reward diterima agen, state berpindah)\n")
# ---- Bagian 2: dua desain reward ----
for nama_desain, penalti in [("A (tanpa penalti langkah)", 0.0),
("B (penalti langkah -0.30)", -0.3)]:
kebijakan, return_terbaik, jumlah_sampai = cari_terbaik(penalti)
_, rute = jalankan(kebijakan, penalti)
lumpur_dilalui = sum(1 for s in rute[:-1] if s in LUMPUR)
print(f"Desain {nama_desain}:")
print(f" return terbaik : {return_terbaik:+.2f}")
print(f" rute kebijakan : " + " -> ".join(str(s) for s in rute))
print(f" panjang rute : {len(rute) - 1} langkah, "
f"{lumpur_dilalui} sel lumpur dilalui")
peta = [[" . "] * KOLOM for _ in range(BARIS)]
for b, k in rute:
peta[b][k] = " * "
peta[GOAL[0]][GOAL[1]] = " G "
for baris in peta:
print(" " + "".join(baris))
print(f" kebijakan mencapai target: {jumlah_sampai}/16384")
print()Output yang Dihasilkan:
Anatomi loop agent-environment (desain B, penalti langkah -0.30):
state (0, 0) --aksi kanan--> reward -0.50, state baru (0, 1)
state (0, 1) --aksi bawah--> reward -0.30, state baru (1, 1)
state (1, 1) --aksi kanan--> reward -0.30, state baru (1, 2)
state (1, 2) --aksi kanan--> reward -0.30, state baru (1, 3)
(setiap langkah = reward diterima agen, state berpindah)
Desain A (tanpa penalti langkah):
return terbaik : +1.00
rute kebijakan : (0, 0) -> (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> (0, 3)
panjang rute : 5 langkah, 0 sel lumpur dilalui
* . . G
* * * *
kebijakan mencapai target: 353/16384
Desain B (penalti langkah -0.30):
return terbaik : -0.30
rute kebijakan : (0, 0) -> (0, 1) -> (0, 2) -> (0, 3)
panjang rute : 3 langkah, 2 sel lumpur dilalui
* * * G
. . . .
kebijakan mencapai target: 353/16384Hasilnya tegas. Desain A memilih rute memutar 5 langkah lewat baris bawah (return +1.00) karena lumpur mengurangi nilai, sedangkan langkah gratis. Desain B justru memilih rute lurus 3 langkah menembus dua sel lumpur (return -0.30): dengan penalti langkah -0.3, lima langkah bersih (-0.5) lebih buruk daripada tiga langkah berlumpur (-0.3). Dunia, start, dan target sama persis; satu konstanta yang berubah membalik arah kebijakan optimal. Perhatikan juga baris terakhir tiap desain: dari 16.384 kebijakan, hanya 353 yang benar-benar sampai target — mayoritas kebijakan acak bahkan tidak pernah selesai. Mari kita telaah kode di atas baris per baris:
- Baris 13: mengimpor
productuntuk menyusun hasil kali Kartesius — alat pencarian lengkap kita. - Baris 15-18: konstanta papan: ukuran 2×4, titik start, target, dan dua sel lumpur bernilai
-0.2. - Baris 20-21: empat arah aksi beserta nama tampilannya.
- Baris 23-24: daftar 7 state non-terminal; kebijakan memetakan 7 state ini ke 4 aksi, sehingga jumlah kebijakan
4^7 = 16.384. - Baris 27-38 (
step): satu interaksi penuh — posisi baru dihitung (dinding membuat agen diam), reward disusun dari penalti langkah, penalti lumpur, dan bonus target. - Baris 41-50 (
jalankan): menjalankan satu kebijakan dari start hingga target atau 50 langkah, mengembalikan total reward dan rute yang dilalui. - Baris 53-63 (
cari_terbaik): menguji seluruh 16.384 kebijakan dan menyimpan yang return-nya tertinggi — pencarian lengkap, bukan pembelajaran. - Baris 67-74: mencetak anatomi loop untuk empat aksi tetap pada desain B; reward
-0.50pada langkah pertama adalah penalti langkah-0.30ditambah penalti lumpur-0.20. - Baris 78-95: menyelesaikan kedua desain, mencetak rute terbaik, peta, dan jumlah kebijakan yang mencapai target.
Observasi vs State #
State adalah deskripsi lengkap atas situasi; observasi adalah bagian yang benar-benar terbaca agent. Keduanya sama hanya bila dunia sepenuhnya teramati:
| Istilah | Definisi | Contoh ketika berbeda |
|---|---|---|
| state | informasi penuh penentu masa depan | seluruh kartu pemain poker, termasuk yang tertutup |
| observasi | potongan state yang diterima agent | kartu di tangan sendiri saja |
Pada seluruh demo section ini observasi identik dengan state — posisi papan sudah menggambarkan segalanya. Pada dunia nyata, kamera robot tidak melihat seluruh ruangan dan sensor memiliki derau; pembahasan ruang observasi parsial kita singgung kembali pada section lanjutan.
Reward Sparse, Dense, dan Perilaku Tak Terduga #
Reward sparse hanya muncul di kejadian langka (misalnya +1 di target); ia jujur terhadap tujuan, tetapi membuat agen sulit tahu aksi mana yang berjasa — masalah penetapan kredit yang sudah kita rasakan pada chapter Dasar Reinforcement Learning
. Reward dense memberi sinyal di setiap langkah (penalti langkah, penalti lumpur) sehingga arah perbaikan lebih cepat ditemukan; imbalannya, struktur reward ikut menentukan jalan yang dipilih — persis seperti desain B yang rela menembus lumpur demi kecepatan.
Desain reward menentukan perilaku yang akan dipelajari, dan kita baru membuktikannya dengan mencari kebijakan terbaik secara membabi buta. Pertanyaan berikutnya adalah kerangka formal: bagaimana menyatakan dunia, transisi, dan reward dalam satu model matematis agar kebijakan optimal dapat dihitung secara sistematis tanpa menguji 16.384 kandidat? Jawabannya adalah Markov Decision Process, topik chapter berikutnya.