Mengapa replay dan target network ada

Triad instabilitas pada Q-learning nonlinear, pada tingkat pengenalan.

Daftar isi

Kedua teknik yang membedakan DQN dari Q-learning naif pada jaringan saraf, yaitu replay buffer dan target network, ada bukan karena kenyamanan, melainkan untuk meredam instabilitas yang muncul ketika Q-learning dipasangkan dengan aproksimasi fungsi nonlinear. Topik ini mengenali tiga sumber instabilitas yang disebut triad instabilitas, menjelaskan peran masing-masing teknik, lalu memperagankan keduanya dengan demo terpisah. Pembaca akan melihat replay buffer menghasilkan batch acak yang berbeda dari urutan penyimpanan, dan target network menjaga nilai QQ tetap stabil saat online network diperbarui.

Triad instabilitas#

Tiga sumber instabilitas bekerja bersamaan pada Q-learning dengan jaringan saraf. Pertama, data transisi yang berurutan sangat berkorelasi, sehingga gradien pada satu trajektori pendek mendominasi pelatihan dan menyesatkan arah pembaruan. Kedua, distribusi data berubah seiring kebijakan bergeser, karena transisi yang dihasilkan kebijakan saat ini berbeda dari yang dihasilkan kebijakan sebelumnya. Ketiga, target pembaruan bergantung pada parameter yang sama yang sedang diupdate, sehingga target ikut bergeser pada setiap langkah dan mengejar nilai yang bergerak.

Tanpa salah satu intervensi, pelatihan cenderung divergen atau terjebak pada osilasi. Replay buffer mengatasi korelasi temporal dengan mengocok transisi masa lalu menjadi batch yang stokastik, dan mengatasi distribusi yang berubah dengan memakai campuran transisi dari berbagai periode kebijakan. Target network mengatasi target yang bergerak dengan membekukan bobot target selama beberapa langkah, sehingga target menjadi konstan dalam jangka pendek dan pelatihan dapat mengejar nilai yang stabil sebelum target diperbarui berkala.

Demo replay dan target network#

Berkas replay_target.py berikut memperagakan kedua teknik secara terpisah. Bagian pertama mengisi buffer dengan 20 transisi berlabel, lalu menarik batch acak berukuran delapan dan membandingkan indeksnya dengan urutan penyimpanan. Bagian kedua membandingkan keluaran online network dan target network sebelum serta sesudah penyalinan bobot, lalu memperbarui online network beberapa langkah dan mengamati target network tetap stabil.

python replay_target.py
import warnings; warnings.filterwarnings("ignore")
import numpy as np, torch
np.random.seed(0); torch.manual_seed(0)
import random; random.seed(0)
from collections import deque
torch.set_printoptions(precision=4, sci_mode=False)

# Demo replay buffer
buffer = deque(maxlen=100)
for i in range(20):
    buffer.append((i, f"trans_{i}"))

batch = random.sample(list(buffer), 8)
indices = [t[0] for t in batch]
buf_list = list(buffer)
print("indices_in_buffer_order =", [t[0] for t in buf_list[:8]])
print("indices_sampled         =", indices)

# Demo target network stability
class QNet(torch.nn.Module):
    def __init__(self, obs_dim, n_actions, hidden=32):
        super().__init__()
        self.net = torch.nn.Sequential(
            torch.nn.Linear(obs_dim, hidden),
            torch.nn.ReLU(),
            torch.nn.Linear(hidden, n_actions),
        )
    def forward(self, x):
        return self.net(x)

online = QNet(4, 2, 32)
target = QNet(4, 2, 32)
# sebelum copy
obs = np.array([0.1, -0.2, 0.05, 0.3], dtype=np.float32)
obs_t = torch.tensor(obs).unsqueeze(0)
with torch.no_grad():
    diff_before = (online(obs_t) - target(obs_t)).abs().mean().item()
print("diff_Q_before_copy =", f"{diff_before:.4f}")

target.load_state_dict(online.state_dict())
with torch.no_grad():
    diff_after = (online(obs_t) - target(obs_t)).abs().mean().item()
print("diff_Q_after_copy  =", f"{diff_after:.4f}")

# ubah online sedikit
opt = torch.optim.SGD(online.parameters(), lr=0.5)
target_val = torch.tensor([[1.0, 0.0]])
for _ in range(3):
    pred = online(obs_t)
    loss = torch.nn.MSELoss()(pred, target_val)
    opt.zero_grad()
    loss.backward()
    opt.step()
with torch.no_grad():
    diff_after_update = (online(obs_t) - target(obs_t)).abs().mean().item()
print("diff_Q_after_online_update =", f"{diff_after_update:.4f}")
print("Q_online                   =", online(obs_t).detach().flatten())
print("Q_target                   =", target(obs_t).detach().flatten())
text Keluaran
indices_in_buffer_order = [0, 1, 2, 3, 4, 5, 6, 7]
indices_sampled         = [12, 13, 1, 8, 15, 6, 19, 4]
diff_Q_before_copy = 0.2694
diff_Q_after_copy  = 0.0000
diff_Q_after_online_update = 0.6047
Q_online                   = tensor([ 1.0250, -0.0034])
Q_target                   = tensor([-0.1153, -0.0724])

Membaca demo#

Indeks yang terambil dari buffer, yaitu [12,13,1,8,15,6,19,4][12, 13, 1, 8, 15, 6, 19, 4], berbeda sepenuhnya dari urutan penyimpanan [0,1,2,…,7][0, 1, 2, \dots, 7]. Inilah peran replay buffer: memutus korelasi temporal dengan mengocok transisi sehingga batch tidak didominasi oleh trajektori pendek. Karena transisi dari periode kebijakan berbeda bercampur dalam satu batch, pembaruan tidak terjebak mengejar distribusi terbaru saja.

Pada bagian target network, selisih QQ antara online dan target sebelum disalin adalah 0,2694 karena kedua jaringan berinisialisasi acak berbeda. Setelah load_state_dict, selisih menjadi 0,0000, yang berarti kedua jaringan identik. Setelah tiga langkah pembaruan online network, selisih melonjak ke 0,6047, sedangkan QQ online bergeser ke [1,0250,−0,0034][1{,}0250, -0{,}0034] sementara QQ target tetap [−0,1153,−0,0724][-0{,}1153, -0{,}0724]. Inilah stabilisasi yang dimaksud: target tidak ikut bergeser selama beberapa langkah, sehingga pelatihan mengejar nilai yang konstan sebelum target diperbarui berkala.

Kesalahan umum#

Memperbarui target network setiap langkah. Penyebabnya, target network disalin dari online network pada setiap iterasi. Akibatnya, target network tidak lagi menjaga target tetap stabil, sehingga manfaatnya hilang dan pelatihan kembali mengejar nilai yang bergerak. Perbaikannya, perbarui target network secara berkala, misalnya setiap 50 atau 100 langkah, atau gunakan rata-rata bergerak (soft update).

Mengosongkan buffer saat kebijakan bergeser. Penyebabnya, transisi lama dianggap tidak relevan setelah kebijakan membaik. Akibatnya, buffer kehilangan campuran periode kebijakan yang justru menstabilkan distribusi data. Perbaikannya, pertahankan kapasitas buffer yang cukup besar agar transisi berbagai periode tetap terwakili, dan kosongkan hanya bila lingkungan berubah secara fundamental.

Ringkasan#

  • Triad instabilitas Q-learning nonlinear terdiri atas korelasi temporal data, distribusi data yang berubah, dan target yang bergantung pada parameter yang diupdate.
  • Replay buffer mengocok transisi masa lalu menjadi batch acak, memutus korelasi temporal sekaligus mencampur transisi dari berbagai periode kebijakan.
  • Target network yang disalin secara berkala menjaga target konstan dalam jangka pendek, terbukti pada demo di mana QQ target tetap [−0,1153,−0,0724][-0{,}1153, -0{,}0724] sementara QQ online bergeser ke [1,0250,−0,0034][1{,}0250, -0{,}0034].

Referensi#