Ainsteinx Logo
Ainsteinx
👤
ຍິນດີຕ້ອນຮັບສູ່ Ainsteinx
ເຂົ້າສູ່ລະບົບ

ປ່ຽນພາສາ

ສະກຸນເງິນ

ໜ້າທຳອິດ
ບົດຄວາມ
ບໍລິການ
ບົດ 09 · Value-based Deep RL

DQN ແລະ Double DQN

ເຮັດໃຫ້ RL ຄ້າຍກັບ supervised learning ຫຼາຍຂຶ້ນ.

DQN ເພີ່ມ 2 ເທັກນິກໃຫ້ NFQ ເພື່ອໃຫ້ຮຽນໄດ້ສະຖຽນ: replay buffer ແລະ target network. Double DQN ແກ້ບັນຫາການປະເມີນຄ່າສູງເກີນ ໂດຍແຍກໜ້າທີ່ເລືອກ ແລະ ປະເມີນ action.

ຄະແນນສູງສຸດຂອງ CartPole ແມ່ນ 500. ສັງເກດວ່າຄະແນນຂຶ້ນລົງບໍ່ໝັ້ນຄົງ ເຊິ່ງເປັນລັກສະນະປົກກະຕິຂອງ DRL: ລອງປ່ຽນ seed ຫຼື learning rate ແລ້ວປຽບທຽບເບິ່ງ. ໂຄດນີ້ໃຊ້ເວລາລັນປະມານ 2–5 ນາທີ.

Replay bufferເກັບປະສົບການ (s, a, r, s', done) ໄວ້ຈຳນວນຫຼາຍ ແລ້ວສຸ່ມ mini-batch ມາຮຽນ ເຮັດໃຫ້ຂໍ້ມູນໃກ້ IID ຂຶ້ນ
Target networkສຳເນົາ network ໄວ້ໃຊ້ຄິດໄລ່ target. ອັບເດດເປັນໄລຍະ ເຮັດໃຫ້ target ບໍ່ເຄື່ອນທີ່ທຸກກ້າວ
DQN : y = r + γ · max_a' Q_target(s', a') DDQN : y = r + γ · Q_target(s', argmax_a' Q_online(s', a'))

Huber loss ເປັນ MSE ເມື່ອ error ນ້ອຍ ແລະ ເປັນ MAE ເມື່ອ error ໃຫຍ່ ຈຶ່ງບໍ່ໃຫ້ gradient ລະເບີດ.

ສິ່ງທີ່ຄວນຈື່

  • Replay buffer ແກ້ບັນຫາ IID, target network ແກ້ບັນຫາ target ເຄື່ອນທີ່
  • Double DQN ປ່ຽນໂຄດພຽງ 1–2 ແຖວ ແຕ່ຊ່ວຍໄດ້ຫຼາຍ
deep-rl-ep09-dqn.py
import random, collections
import numpy as np, torch, torch.nn as nn
import gymnasium as gym

env = gym.make("CartPole-v1")
n_obs, n_act = env.observation_space.shape[0], env.action_space.n
torch.manual_seed(0); random.seed(0)

def make_net():
    return nn.Sequential(nn.Linear(n_obs, 128), nn.ReLU(),
                         nn.Linear(128, 128), nn.ReLU(),
                         nn.Linear(128, n_act))       # state in -> Q ທຸກ action out

online, target = make_net(), make_net()
target.load_state_dict(online.state_dict())           # target network
opt = torch.optim.Adam(online.parameters(), lr=1e-3)
buffer = collections.deque(maxlen=50_000)             # replay buffer
gamma, batch_size, step = 0.99, 64, 0

for ep in range(400):
    s, _ = env.reset(seed=ep)
    done, ep_return = False, 0.0
    while not done:
        eps = max(0.05, 1.0 - step / 10_000)          # epsilon ຫຼຸດແບບເສັ້ນຊື່
        if random.random() < eps:
            a = env.action_space.sample()
        else:
            with torch.no_grad():
                a = int(online(torch.tensor(s)).argmax())
        s2, r, term, trunc, _ = env.step(a)
        buffer.append((s, a, r, s2, term))
        s, done, ep_return, step = s2, term or trunc, ep_return + r, step + 1

        if len(buffer) >= 1000:
            batch = random.sample(buffer, batch_size)   # ສຸ່ມ → ຂໍ້ມູນໃກ້ IID
            S, A, R, S2, T = (torch.tensor(np.array(x)) for x in zip(*batch))
            with torch.no_grad():
                a2 = online(S2).argmax(1, keepdim=True)          # Double DQN:
                q2 = target(S2).gather(1, a2).squeeze(1)         # online ເລືອກ, target ປະເມີນ
                y = R.float() + gamma * q2 * (1 - T.float())
            q = online(S).gather(1, A.long().unsqueeze(1)).squeeze(1)
            loss = nn.functional.huber_loss(q, y)                # Huber loss
            opt.zero_grad(); loss.backward(); opt.step()
        if step % 200 == 0:
            target.load_state_dict(online.state_dict())          # ອັບເດດ target ເປັນໄລຍະ
    if ep % 25 == 0:
        print(f"ເກມທີ {ep:3d}  ຄະແນນ {ep_return:5.0f}")

ຜົນລັບ

ເກມທີ   0  ຄະແນນ    12
ເກມທີ  25  ຄະແນນ    20
ເກມທີ  50  ຄະແນນ    15
ເກມທີ  75  ຄະແນນ    20
ເກມທີ 100  ຄະແນນ    42
ເກມທີ 125  ຄະແນນ    12
ເກມທີ 150  ຄະແນນ   128
ເກມທີ 175  ຄະແນນ    17
ເກມທີ 200  ຄະແນນ   128
ເກມທີ 225  ຄະແນນ   108
ເກມທີ 250  ຄະແນນ   136
ເກມທີ 275  ຄະແນນ   148
ເກມທີ 300  ຄະແນນ   500
ເກມທີ 325  ຄະແນນ   500
ເກມທີ 350  ຄະແນນ    89
ເກມທີ 375  ຄະແນນ   242
  • #DeepRL
  • #ReinforcementLearning
  • #PythonສຳລັບຄົນLaos
  • #AI
  • #ບອກຕໍ່ຄວາມຮູ້