REINFORCE adalah policy gradient Monte Carlo yang paling sederhana, yaitu memperbarui parameter kebijakan setelah sebuah episode selesai, dengan bobot berupa return kumulatif sepanjang trajectory. Topik ini menurunkan rumus gradien secara ringan dari objective log-likelihood yang diharapkan, lalu mengimplementasikannya di CartPole-v1 dengan jaringan kecil selama 200 episode. Karena kebijakan acak awal gagal dalam sekitar 20 sampai 30 langkah, reward rata-rata tidak melonjak dramatis, dan keluaran yang dicetak mencerminkan keadaan tersebut.
Objektif log-likelihood dibobot return#
Tujuan policy gradient adalah memaksimalkan expected return dari kebijakan:
dengan adalah trajectory yang dihasilkan dengan mengikuti . Karena return bergantung pada kebijakan melalui jalur yang panjang, optimasi langsung sulit. Jalan keluarnya adalah memanfaatkan fakta bahwa gradien expected return terhadap dapat ditulis ulang sebagai ekspektasi atas log-probability aksi yang dibobot return.
Penurunan ringan#
Probabilitas sebuah trajectory di bawah kebijakan adalah
Gradien logaritma terhadap hanya menyentuh faktor kebijakan karena dinamika lingkungan tidak bergantung pada :
Dengan trik identitas log-derivative , dan menyederhanakan jumlah reward menjadi return , diperoleh estimator gradien:
Estimator ini disebut REINFORCE, atau Monte Carlo policy gradient. Setiap langkah dalam trajectory menyumbang sebesar gradien log-probability aksinya dikalikan return mulai dari langkah itu. Karena ekspektasi di atas tidak dapat dihitung secara analitik, ia diperkirakan dengan rata-rata atas beberapa trajectory sampel, dan diperbarui dengan gradient ascent.
Implementasi REINFORCE di CartPole#
Berkas reinforce.py berikut menjalankan REINFORCE penuh pada CartPole-v1 selama 200 episode, dengan discount , optimizer Adam learning rate 1e-2, dan jaringan satu lapis tersembunyi berukuran 32. Setiap episode dikumpulkan utuh, return dihitung secara mundur dengan diskon, lalu loss adalah jumlah yang diminimalkan oleh Adam.
import warnings; warnings.filterwarnings("ignore")
import numpy as np, torch, random
np.random.seed(0); torch.manual_seed(0); random.seed(0)
import gymnasium as gym
GAMMA = 0.99
LR = 1e-2
N_EPISODES = 200
class Policy(torch.nn.Module):
def __init__(self, obs_dim, n_aksi, hidden=32):
super().__init__()
self.net = torch.nn.Sequential(
torch.nn.Linear(obs_dim, hidden),
torch.nn.Tanh(),
torch.nn.Linear(hidden, n_aksi),
)
def forward(self, x):
return self.net(x)
env = gym.make("CartPole-v1")
obs, info = env.reset(seed=0)
env.action_space.seed(0)
env.observation_space.seed(0)
pi = Policy(4, 2, hidden=32)
opt = torch.optim.Adam(pi.parameters(), lr=LR)
episode_rewards = []
grad_norms = []
sample_logprob = None
for ep in range(N_EPISODES):
obs, _ = env.reset()
log_probs = []
rewards = []
done = False
while not done:
x = torch.tensor(obs, dtype=torch.float32).unsqueeze(0)
logits = pi(x)
dist = torch.distributions.Categorical(logits=logits)
a = dist.sample()
lp = dist.log_prob(a)
obs, r, term, trunc, _ = env.step(int(a.item()))
log_probs.append(lp)
rewards.append(r)
done = term or trunc
G = 0.0
returns = []
for r in reversed(rewards):
G = r + GAMMA * G
returns.insert(0, G)
returns_t = torch.tensor(returns, dtype=torch.float32)
log_probs_t = torch.stack(log_probs)
loss = -(log_probs_t * returns_t).sum()
opt.zero_grad()
loss.backward()
total_gn = 0.0
for p in pi.parameters():
if p.grad is not None:
total_gn += float(p.grad.pow(2).sum())
grad_norms.append(total_gn ** 0.5)
if ep == 0:
sample_logprob = float(log_probs_t[0].item())
opt.step()
episode_rewards.append(sum(rewards))
last20 = float(np.mean(episode_rewards[-20:]))
avg_gn = float(np.mean(grad_norms))
print(f"episodes = {N_EPISODES}")
print(f"avg_reward 20 terakhir = {last20:.4f}")
print(f"contoh log-prob(ep0) = {sample_logprob:.4f}")
print(f"norm gradien rata-rata = {avg_gn:.4f}")
env.close()episodes = 200
avg_reward 20 terakhir = 38.2000
contoh log-prob(ep0) = -0.8126
norm gradien rata-rata = 5793.0995Membaca keluaran#
Reward rata-rata 20 episode terakhir mencapai 38.2, naik dari garis dasar acak sekitar 20 langkah, namun masih jauh dari batas atas 500 langkah CartPole-v1. Kenaikan ini wajar: 200 episode dengan learning rate 1e-2 tidak cukup untuk membuat kebijakan konvergen, dan REINFORCE murni memiliki variance besar sehingga pembaruan tunggal sering goyah. Angka 38.2 mencerminkan kebijakan yang mulai memilih aksi sedikit lebih baik daripada acak, bukan kebijakan terlatih.
Contoh log-probability dari episode pertama adalah , yang setara dengan probabilitas sekitar . Nilai ini mendekati karena kebijakan awal mendekati seragam. Norma gradien rata-rata sangat besar, dan inilah gejala inti masalah REINFORCE: karena return kumulatif tidak dinormalisasi, magnitudo gradien bergeser bersama skala reward, sehingga optimizer perlu learning rate kecil agar stabil. Reduksi variance pada topik selanjutnya menangani masalah ini dengan rewards-to-go dan baseline.
Kesalahan umum#
Mengganti return dengan reward sesaat. Penyebabnya, hanya reward langkah yang dikalikan dengan log-probability, sehingga kontribusi aksi terhadap reward masa depan hilang. Akibatnya, kebijakan hanya belajar dari konsekuensi langsung. Perbaikannya, pakai return yang menjumlahkan reward sejak langkah , sebagaimana diperlihatkan di atas.
Mengabaikan diskon pada return panjang. Penyebabnya, dianggap opsional pada episode pendek. Akibatnya, return dari episode yang kebetulan panjang mendominasi gradien dan menimbulkan variance besar. Perbaikannya, tetapkan kurang dari satu, misalnya 0,99, agar kontribusi reward jauh meredup secara eksponensial.
Ringkasan#
- REINFORCE memperbarui dengan estimator , diturunkan dari trik log-derivative atas probabilitas trajectory.
- Pada CartPole-v1 selama 200 episode, reward rata-rata 20 episode terakhir mencapai 38.2, jauh di bawah batas 500, dengan norma gradien rata-rata 5793.0995 yang menandakan variance besar.
- Return kumulatif tanpa normalisasi menyebabkan magnitudo gradien bergeser bersama skala reward, sehingga learning rate harus kecil agar pelatihan stabil.
Referensi#
- Simple statistical gradient-following algorithms for connectionist reinforcement learning — Williams 1992 — Makalah asli REINFORCE yang menurunkan estimator gradien Monte Carlo.
- Vanilla Policy Gradient — OpenAI Spinning Up — Penjelasan REINFORCE termasuk pseudokode dan diskusi variance-nya.