Reinforcement Learning dengan Gymnasium dan Stable-Baselines3
Daftar Isi
Pendahuluan
Reinforcement Learning (RL) atau Pembelajaran Penguatan adalah paradigma pembelajaran mesin di mana sebuah agen belajar membuat keputusan dengan berinteraksi langsung dengan lingkungannya. Berbeda dengan supervised learning, RL tidak memerlukan data berlabel. Sebagai gantinya, agen menemukan perilaku optimal melalui proses coba-coba (trial and error) yang dipandu oleh sinyal reward (imbalan).
Tutorial ini memberikan panduan praktis untuk membangun agen RL menggunakan Gymnasium (fork yang dikelola dari OpenAI Gym) untuk simulasi environment dan Stable-Baselines3 (SB3) untuk implementasi algoritma RL mutakhir. Anda akan belajar melatih agen dengan DQN, PPO, dan A2C, membuat environment kustom, memantau pelatihan, dan mengevaluasi performa model.
Prasyarat
- Python 3.9+
- Pemahaman dasar tentang jaringan saraf tiruan
- Familiaritas dengan PyTorch (membantu namun tidak wajib)
Instalasi paket yang diperlukan:
pip install gymnasium stable-baselines3[extra] tensorboard numpy matplotlib
Flag [extra] menginstal dependensi tambahan termasuk dukungan TensorBoard dan environment Gymnasium ekstra.
Konsep Inti Reinforcement Learning
Sebelum menulis kode apa pun, penting untuk memahami komponen fundamental dari sistem RL.
Kerangka Kerja RL
Agen <---> Lingkungan (Environment)
| |
|-- Aksi ----> |
| |-- State, Reward -->|
|<------------------------------ ---|
- Agen (Agent): Entitas yang belajar dan membuat keputusan, yaitu memilih aksi.
- Lingkungan (Environment): Dunia tempat agen berinteraksi. Lingkungan menerima aksi dan mengembalikan state serta reward.
- State (Observasi): Representasi situasi terkini dalam lingkungan.
- Aksi (Action): Keputusan yang dibuat agen yang mempengaruhi lingkungan.
- Reward (Imbalan): Sinyal umpan balik skalar yang menunjukkan seberapa baik aksi yang diambil.
- Kebijakan (Policy): Pemetaan dari state ke aksi. Inilah yang dipelajari oleh agen.
- Episode: Urutan lengkap dari state awal hingga state terminal.
- Faktor Diskon (Gamma): Nilai antara 0 dan 1 yang menentukan seberapa besar reward masa depan dihargai relatif terhadap reward langsung.
Fungsi Nilai
- V(s): Reward kumulatif yang diharapkan dimulai dari state s, mengikuti kebijakan pi.
- Q(s, a): Reward kumulatif yang diharapkan dimulai dari state s, mengambil aksi a, kemudian mengikuti kebijakan pi.
Eksplorasi vs Eksploitasi
Agen harus menyeimbangkan antara mengeksplorasi aksi baru (untuk menemukan strategi yang berpotensi lebih baik) dengan mengeksploitasi aksi yang diketahui baik (untuk memaksimalkan reward). Hal ini dikelola melalui strategi seperti epsilon-greedy atau regularisasi entropi.
Memulai dengan Gymnasium
Gymnasium menyediakan antarmuka standar untuk environment RL.
Menjelajahi Environment
import gymnasium as gym
import numpy as np
Membuat environment CartPole
env = gym.make("CartPole-v1", rendermode="human")
print(f"Ruang observasi: {env.observationspace}")
print(f"Ruang aksi: {env.actionspace}")
print(f"Bentuk observasi: {env.observationspace.shape}")
print(f"Jumlah aksi: {env.actionspace.n}")
Menjalankan agen acak
obs, info = env.reset(seed=42)
totalreward = 0
for langkah in range(500):
aksi = env.actionspace.sample() # aksi acak
obs, reward, terminated, truncated, info = env.step(aksi)
totalreward += reward
if terminated or truncated:
print(f"Episode berakhir pada langkah {langkah + 1} dengan total reward: {totalreward}")
obs, info = env.reset()
totalreward = 0
env.close()
Environment Gymnasium yang Umum Digunakan
# Ruang aksi diskrit
envcartpole = gym.make("CartPole-v1") # Menyeimbangkan tiang di atas kereta
envlunar = gym.make("LunarLander-v3") # Mendaratkan pesawat ruang angkasa
envmountain = gym.make("MountainCar-v0") # Mendaki gunung dengan mobil
Ruang aksi kontinu
envpendulum = gym.make("Pendulum-v1") # Mengayunkan pendulum ke posisi tegak
envbipedal = gym.make("BipedalWalker-v3") # Berjalan dengan biped 2D
Memeriksa environment apa pun
for nama, env in [("CartPole", envcartpole), ("LunarLander", envlunar)]:
print(f"\n{nama}:")
print(f" Ruang observasi: {env.observationspace}")
print(f" Ruang aksi: {env.actionspace}")
env.close()
Deep Q-Network (DQN)
DQN mengaproksimasi fungsi-Q menggunakan jaringan saraf. Algoritma ini dirancang untuk environment dengan ruang aksi diskrit.
Melatih Agen DQN
from stablebaselines3 import DQN
from stablebaselines3.common.evaluation import evaluatepolicy
Membuat environment
env = gym.make("CartPole-v1")
Menginisialisasi agen DQN
modeldqn = DQN(
policy="MlpPolicy",
env=env,
learningrate=1e-3,
buffersize=100000, # ukuran replay buffer
learningstarts=1000, # langkah sebelum pelatihan dimulai
batchsize=64,
tau=1.0, # koefisien pembaruan jaringan target
gamma=0.99, # faktor diskon
trainfreq=4, # perbarui model setiap 4 langkah
targetupdateinterval=1000,# perbarui jaringan target setiap 1000 langkah
explorationfraction=0.1, # fraksi pelatihan untuk penurunan eksplorasi
explorationinitialeps=1.0,
explorationfinaleps=0.05,
verbose=1,
seed=42,
)
Melatih agen
modeldqn.learn(totaltimesteps=50000)
Mengevaluasi agen terlatih
meanreward, stdreward = evaluatepolicy(modeldqn, env, nevalepisodes=20)
print(f"DQN - Reward rata-rata: {meanreward:.2f} +/- {stdreward:.2f}")
Menyimpan model
modeldqn.save("dqncartpole")
env.close()
Memuat dan Menggunakan Model Terlatih
# Memuat model yang tersimpan
modeldimuat = DQN.load("dqncartpole")
env = gym.make("CartPole-v1", rendermode="human")
obs, info = env.reset()
for in range(1000):
aksi, states = modeldimuat.predict(obs, deterministic=True)
obs, reward, terminated, truncated, info = env.step(aksi)
if terminated or truncated:
obs, info = env.reset()
env.close()
Proximal Policy Optimization (PPO)
PPO adalah metode policy gradient yang secara luas dianggap sebagai algoritma default untuk RL. PPO bekerja dengan ruang aksi diskrit maupun kontinu dan dikenal karena stabilitas serta efisiensi sampelnya.
Melatih Agen PPO
from stablebaselines3 import PPO
env = gym.make("LunarLander-v3")
modelppo = PPO(
policy="MlpPolicy",
env=env,
learningrate=3e-4,
nsteps=2048, # langkah per rollout
batchsize=64,
nepochs=10, # epoch optimisasi per pembaruan
gamma=0.999,
gaelambda=0.98, # parameter GAE
cliprange=0.2, # parameter clipping PPO
entcoef=0.01, # koefisien entropi untuk eksplorasi
vfcoef=0.5, # koefisien fungsi nilai
maxgradnorm=0.5,
verbose=1,
seed=42,
)
modelppo.learn(totaltimesteps=200000)
meanreward, stdreward = evaluatepolicy(modelppo, env, nevalepisodes=20)
print(f"PPO - Reward rata-rata: {meanreward:.2f} +/- {stdreward:.2f}")
modelppo.save("ppolunarlander")
env.close()
PPO dengan Aksi Kontinu
envkontinu = gym.make("Pendulum-v1")
model
ppokontinu = PPO(
policy="MlpPolicy",
env=env
kontinu,
learningrate=3e-4,
nsteps=1024,
batchsize=64,
nepochs=10,
gamma=0.98,
gaelambda=0.95,
cliprange=0.2,
verbose=1,
)
modelppokontinu.learn(totaltimesteps=100000)
meanreward, stdreward = evaluatepolicy(modelppokontinu, envkontinu, nevalepisodes=20)
print(f"PPO Kontinu - Reward rata-rata: {meanreward:.2f} +/- {stdreward:.2f}")
envkontinu.close()
Advantage Actor-Critic (A2C)
A2C adalah varian sinkron dari Asynchronous Advantage Actor-Critic (A3C). A2C menggunakan jaringan aktor (kebijakan) dan jaringan kritik (fungsi nilai) yang dilatih secara bersamaan.
Melatih Agen A2C
from stablebaselines3 import A2C
env = gym.make("CartPole-v1")
modela2c = A2C(
policy="MlpPolicy",
env=env,
learningrate=7e-4,
nsteps=5, # langkah per pembaruan environment
gamma=0.99,
gaelambda=1.0,
entcoef=0.0,
vfcoef=0.5,
maxgradnorm=0.5,
usermsprop=True,
normalizeadvantage=False,
verbose=1,
seed=42,
)
modela2c.learn(totaltimesteps=50000)
meanreward, stdreward = evaluatepolicy(modela2c, env, nevalepisodes=20)
print(f"A2C - Reward rata-rata: {meanreward:.2f} +/- {stdreward:.2f}")
modela2c.save("a2ccartpole")
env.close()
Membuat Environment Kustom
Masalah RL di dunia nyata sering memerlukan environment kustom. Gymnasium menyediakan antarmuka yang jelas untuk membangunnya.
Environment Grid World Kustom
import gymnasium as gym
from gymnasium import spaces
import numpy as np
class GridWorldEnv(gym.Env):
"""Grid world sederhana di mana agen harus mencapai posisi tujuan."""
metadata = {"rendermodes": ["human", "ansi"], "renderfps": 4}
def init(self, rendermode=None, ukurangrid=5):
super().init()
self.ukurangrid = ukurangrid
self.rendermode = rendermode
# Ruang aksi: 0=atas, 1=bawah, 2=kiri, 3=kanan
self.actionspace = spaces.Discrete(4)
# Ruang observasi: posisi agen (baris, kolom)
self.observationspace = spaces.Box(
low=0, high=ukurangrid - 1, shape=(2,), dtype=np.float32
)
self.posisitujuan = np.array([ukurangrid - 1, ukurangrid - 1], dtype=np.float32)
self.posisiagen = None
self.makslangkah = ukurangrid ukurangrid 2
self.langkahsaatini = 0
def reset(self, seed=None, options=None):
super().reset(seed=seed)
self.posisiagen = np.array([0, 0], dtype=np.float32)
self.langkahsaatini = 0
return self.posisiagen.copy(), {}
def step(self, action):
self.langkahsaatini += 1
# Terapkan pergerakan
if action == 0 and self.posisiagen[0] > 0:
self.posisiagen[0] -= 1 # atas
elif action == 1 and self.posisiagen[0] < self.ukurangrid - 1:
self.posisiagen[0] += 1 # bawah
elif action == 2 and self.posisiagen[1] > 0:
self.posisiagen[1] -= 1 # kiri
elif action == 3 and self.posisiagen[1] < self.ukurangrid - 1:
self.posisiagen[1] += 1 # kanan
# Hitung reward
jarak = np.linalg.norm(self.posisiagen - self.posisitujuan)
mencapaitujuan = jarak < 0.5
if mencapaitujuan:
reward = 100.0
else:
reward = -1.0 # penalti langkah untuk mendorong efisiensi
terminated = mencapaitujuan
truncated = self.langkahsaatini >= self.makslangkah
return self.posisiagen.copy(), reward, terminated, truncated, {}
def render(self):
if self.rendermode == "ansi":
grid = [["." for in range(self.ukurangrid)] for in range(self.ukurangrid)]
b, k = int(self.posisiagen[0]), int(self.posisiagen[1])
grid[b][k] = "A"
tb, tk = int(self.posisitujuan[0]), int(self.posisitujuan[1])
grid[tb][tk] = "T" if (b, k) != (tb, tk) else "W"
return "\n".join(" ".join(baris) for baris in grid)
Mendaftarkan dan Menggunakan Environment Kustom
from gymnasium.envs.registration import register
register(
id="GridWorld-v0",
entrypoint="main:GridWorldEnv",
maxepisodesteps=200,
)
Verifikasi environment
from stablebaselines3.common.envchecker import checkenv
env = GridWorldEnv(ukurangrid=5)
checkenv(env, warn=True)
print("Pemeriksaan environment berhasil.")
Melatih PPO pada environment kustom
env = GridWorldEnv(ukurangrid=5)
model = PPO("MlpPolicy", env, verbose=1, learningrate=3e-4, nsteps=512)
model.learn(totaltimesteps=50000)
meanreward, stdreward = evaluatepolicy(model, env, nevalepisodes=50)
print(f"Environment Kustom - Reward rata-rata: {meanreward:.2f} +/- {stdreward:.2f}")
Loop Pelatihan dan Pemantauan dengan Callback
Callback memungkinkan Anda memantau progres pelatihan, menyimpan checkpoint, dan menerapkan early stopping.
Callback Penting
from stablebaselines3.common.callbacks import (
EvalCallback,
CheckpointCallback,
CallbackList,
StopTrainingOnRewardThreshold,
)
env = gym.make("LunarLander-v3")
eval
env = gym.make("LunarLander-v3")
Hentikan pelatihan ketika reward rata-rata mencapai 200
stopcallback = StopTrainingOnRewardThreshold(rewardthreshold=200, verbose=1)
Evaluasi setiap 10.000 langkah dan simpan model terbaik
evalcallback = EvalCallback(
evalenv,
bestmodelsavepath="./modelterbaik/",
logpath="./logevaluasi/",
evalfreq=10000,
nevalepisodes=10,
deterministic=True,
callbackaftereval=stopcallback,
verbose=1,
)
Simpan checkpoint setiap 20.000 langkah
checkpointcallback = CheckpointCallback(
savefreq=20000,
savepath="./checkpoint/",
nameprefix="ppolunar",
)
Gabungkan callback
callback = CallbackList([evalcallback, checkpointcallback])
model = PPO("MlpPolicy", env, verbose=1)
model.learn(totaltimesteps=500000, callback=callback)
env.close()
evalenv.close()
Callback Kustom
from stablebaselines3.common.callbacks import BaseCallback
class CallbackMetrikPelatihan(BaseCallback):
"""Mencatat metrik kustom selama pelatihan."""
def init(self, verbose=0):
super().init(verbose)
self.reward
episode = []
self.panjangepisode = []
def onstep(self) -> bool:
# Periksa apakah episode telah berakhir
if self.locals.get("dones") is not None:
for i, selesai in enumerate(self.locals["dones"]):
if selesai:
info = self.locals["infos"][i]
if "episode" in info:
self.rewardepisode.append(info["episode"]["r"])
self.panjangepisode.append(info["episode"]["l"])
if len(self.rewardepisode) % 50 == 0:
terbaru = self.rewardepisode[-50:]
print(f" 50 episode terakhir - Rata-rata: {np.mean(terbaru):.1f}, "
f"Min: {np.min(terbaru):.1f}, Maks: {np.max(terbaru):.1f}")
return True # kembalikan False untuk menghentikan pelatihan
def ontrainingend(self):
print(f"\nPelatihan selesai. Total episode: {len(self.rewardepisode)}")
Evaluasi Model
Evaluasi Komprehensif
from stablebaselines3.common.evaluation import evaluatepolicy
import matplotlib.pyplot as plt
def evaluasi
komprehensif(model, envid, nepisode=100):
"""Menjalankan evaluasi menyeluruh terhadap model RL terlatih."""
env = gym.make(envid)
rewardepisode = []
panjangepisode = []
for ep in range(nepisode):
obs, info = env.reset()
totalreward = 0
langkah = 0
while True:
aksi, = model.predict(obs, deterministic=True)
obs, reward, terminated, truncated, info = env.step(aksi)
totalreward += reward
langkah += 1
if terminated or truncated:
break
rewardepisode.append(totalreward)
panjangepisode.append(langkah)
env.close()
rewards = np.array(rewardepisode)
panjang = np.array(panjangepisode)
print(f"=== Evaluasi atas {nepisode} episode ===")
print(f"Reward - Rata-rata: {rewards.mean():.2f}, Std: {rewards.std():.2f}, "
f"Min: {rewards.min():.2f}, Maks: {rewards.max():.2f}")
print(f"Panjang - Rata-rata: {panjang.mean():.1f}, Std: {panjang.std():.1f}")
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
axes[0].hist(rewards, bins=30, color="steelblue", edgecolor="black")
axes[0].axvline(rewards.mean(), color="red", linestyle="--", label=f"Rata-rata: {rewards.mean():.1f}")
axes[0].settitle("Distribusi Reward")
axes[0].setxlabel("Total Reward")
axes[0].legend()
axes[1].plot(rewards, alpha=0.6)
axes[1].axhline(rewards.mean(), color="red", linestyle="--")
axes[1].settitle("Reward per Episode")
axes[1].setxlabel("Episode")
axes[1].setylabel("Total Reward")
plt.tightlayout()
plt.savefig("evaluasirl.png", dpi=150)
plt.show()
return rewards, panjang
Penggunaan
modelppo = PPO.load("ppolunarlander")
rewards, panjang = evaluasikomprehensif(modelppo, "LunarLander-v3", nepisode=100)
Integrasi TensorBoard
Stable-Baselines3 memiliki logging TensorBoard bawaan.
Mengatur Logging TensorBoard
from stablebaselines3 import PPO
env = gym.make("LunarLander-v3")
model = PPO(
"MlpPolicy",
env,
verbose=1,
tensorboardlog="./logtb/",
)
Setiap pemanggilan learn membuat run baru
model.learn(totaltimesteps=100000, tblogname="pporun1")
model.learn(totaltimesteps=100000, tblogname="pporun2", resetnumtimesteps=False)
env.close()
Menjalankan TensorBoard
# Jalankan ini di terminal Anda
tensorboard --logdir ./logtb/ --port 6006
Kemudian buka http://localhost:6006 di browser Anda. Anda akan melihat metrik termasuk:
rollout/eprewmean- Reward episode rata-rata sepanjang wakturollout/eplenmean- Panjang episode rata-ratatrain/loss- Loss pelatihantrain/entropyloss- Entropi kebijakan (eksplorasi)train/policygradientloss- Loss gradient kebijakan
Membandingkan Beberapa Algoritma
env = gym.make("CartPole-v1")
Melatih ketiga algoritma dengan logging TensorBoard
for KelasAlgo, nama in [(DQN, "dqn"), (PPO, "ppo"), (A2C, "a2c")]:
model = KelasAlgo("MlpPolicy", env, verbose=0, tensorboardlog="./perbandingantb/")
model.learn(totaltimesteps=50000, tblogname=nama)
model.save(f"{nama}cartpole")
env.close()
Kemudian jalankan: tensorboard --logdir ./perbandingantb/
Praktik Terbaik
VecNormalize dari SB3 untuk menormalisasi observasi dan reward, terutama untuk environment kontinu.from stablebaselines3.common.vecenv import DummyVecEnv, VecNormalize
env = DummyVecEnv([lambda: gym.make("Pendulum-v1")])
env = VecNormalize(env, normobs=True, normreward=True, clipobs=10.0)
from stablebaselines3.common.vecenv import SubprocVecEnv
def buat
env(envid, rank, seed=0):
def
init():
env = gym.make(envid)
env.reset(seed=seed + rank)
return env
return init
jumlahenv = 4
env = SubprocVecEnv([buatenv("LunarLander-v3", i) for i in range(jumlahenv)])
checkenv() sebelum pelatihan. Environment yang bermasalah akan secara diam-diam menghasilkan agen yang buruk.deterministic=True saat evaluasi untuk mendapatkan hasil yang dapat direproduksi yang mencerminkan kebijakan yang dipelajari.Kesimpulan
Dalam tutorial ini, kita telah membahas dasar-dasar reinforcement learning dan mendemonstrasikan cara menerapkannya menggunakan perangkat modern:
- Gymnasium menyediakan environment yang terstandarisasi dan terpelihara dengan baik, dengan API yang bersih untuk environment bawaan maupun kustom.
- DQN efektif untuk ruang aksi diskrit dan memanfaatkan experience replay serta jaringan target.
- PPO adalah algoritma serbaguna yang menjadi pilihan utama, menawarkan stabilitas dan performa yang baik di berbagai tugas.
- A2C menyediakan pendekatan actor-critic yang lebih sederhana dan dapat efektif dengan penyetelan yang tepat.
- Environment kustom memungkinkan Anda menerapkan RL untuk masalah spesifik domain.
- Callback dan TensorBoard sangat penting untuk memantau dan mengelola sesi pelatihan.
Kunci sukses dalam RL adalah eksperimentasi iteratif: mulai dari yang sederhana, pantau semuanya, dan tingkatkan kompleksitas secara bertahap. Dengan perangkat yang dibahas dalam tutorial ini, Anda memiliki fondasi yang kokoh untuk menangani benchmark standar maupun tantangan RL di dunia nyata.