Проблема глубокого RL: потери уменьшаются, но агент не учитсяPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Проблема глубокого RL: потери уменьшаются, но агент не учится

Сообщение Anonymous »

Надеюсь, кто-нибудь сможет мне помочь. Я реализую базовый алгоритм градиента политики Vanilla для среды спортзала CartPole-v1 и не знаю, что делаю неправильно.
Что бы я ни пробовал, во время цикла обучения потери уменьшаются (так что модель на самом деле чему-то учится), но общее вознаграждение за эпизод также уменьшается, пока не достигнет примерно 9-10 шагов (что, как я полагаю, является минимальным количеством шагов, необходимых для падения шеста). Значит, он учится делать это плохо!
Я не знаю, связано ли это как-то со знаками, с тем, как я вычисляю потери, с оптимизатором... Понятия не имею.
Для получения вознаграждений со скидкой я использую
$ Q_{k,t} = \sum_{i=0}{\gamma^{ i-t} r_i} $
И за проигрыш:
$ L = -\sum_{k,t}Q_{k,t}log \pi_{\theta}(a_t | s_t)$
Код представляет собой смесь из книги Максима Лапана «Deep RL Hands-On», примера Karpathy’s Pong (блог, код) и личных настроек. .
Вот мой код:

Код: Выделить всё

import gymnasium as gym
import torch
from torch import nn
import torch.nn.functional as F
from torch.nn.init import xavier_uniform_
import numpy as np

GAMMA = 0.99
LEARNING_RATE = 0.001
BATCH_SIZE = 4
DEVICE = torch.device('mps')

class XavierLinear(nn.Linear):
def __init__(self, in_features: int, out_features: int, bias: bool = True, device=None, dtype=None) -> None:
super().__init__(in_features, out_features, bias, device, dtype)
xavier_uniform_(self.weight)

class VPG(nn.Module):
def __init__(self, input_size, output_size):
super(VPG, self).__init__()
self.net = nn.Sequential(
XavierLinear(input_size, 128),
nn.ReLU(),
XavierLinear(128, output_size),
)

def forward(self, x):
return F.softmax(self.net(x), dim=0)

def run_episode(model, env):
obs = env.reset()[0]
obs = torch.Tensor(env.reset()[0]).to(DEVICE)
te = tr = False
rewards, outputs, actions = [], [], []
while not (te or tr):
probs = model(obs)
action = probs.multinomial(1).item()
obs, r, te, tr, _ = env.step(action)
obs = torch.Tensor(obs).to(DEVICE)
if (te or tr):
r = 0
rewards.append(r)
outputs.append(probs)
actions.append(action)
return torch.Tensor(rewards).to(DEVICE), torch.concatenate(outputs).reshape(len(rewards), 2), actions

def discount_rewards(rewards):
discounted_r = torch.zeros_like(rewards)
additive_r = 0
for idx in range(len(rewards)-1, -1, -1):
to_add = GAMMA * additive_r
additive_r = to_add + rewards[idx]
discounted_r[idx] = additive_r
return discounted_r.to(DEVICE)

def loss_function(discounted_r, probs, actions):
logprobs = torch.log(probs)
selected = logprobs[range(probs.shape[0]), actions]
# discounted_r = (discounted_r - discounted_r.mean()) / discounted_r.std()
weighted = selected * discounted_r
return -weighted.sum()

# The actual training loop:

episode_total_reward = 0
batch_losses = torch.Tensor().to(DEVICE)
batch_actions = []
batch_disc_r = torch.Tensor().to(DEVICE)
batch_probs = torch.Tensor().to(DEVICE)
best_ep_reward = 0
losses, ep_total_lenghts = [], [0]

episodes = 0
TARGET_REWARD = 100

env = gym.make("CartPole-v1")
model = VPG(env.observation_space.shape[0],
2).to(DEVICE)
optim = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)

while np.array(ep_total_lenghts)[-100:].mean() < TARGET_REWARD:
rewards, probs, actions = run_episode(model, env)
discounted_r = discount_rewards(rewards)
episode_total_reward = rewards.shape[0]
ep_total_lenghts.append(episode_total_reward)
episodes += 1
batch_actions += actions
batch_disc_r = torch.concatenate([batch_disc_r, discounted_r])
batch_probs = torch.concatenate([batch_probs, probs])

if episodes % BATCH_SIZE == 0:
loss = loss_function(batch_disc_r, batch_probs, batch_actions)
losses.append(loss.item())
model.zero_grad()
loss.backward()
optim.step()
batch_actions = []
batch_disc_r = torch.Tensor().to(DEVICE)
batch_probs = torch.Tensor().to(DEVICE)
print(f"Episode {episodes}. Loss: {loss}. Reward: {episode_total_reward}")
print(f"Success in {episodes} episodes. Loss: {loss}.  Reward: {episode_total_reward}")
Пробывал: менять знаки в функциях потерь, менять награды (нетерминальный шаг = 0 и конечный шаг = -1), обновлять веса вручную (добавлять градиент или вычитать его... ). В каждом случае я получаю одно и то же: потери уменьшаются, но агент не учится удерживать шест.
Ожидание: потери уменьшаются, а общее вознаграждение за эпизод (пройденные шаги) увеличивается.< /p>
РЕДАКТИРОВАТЬ:
Наконец-то я смог решить проблему, применив эти изменения:
  • < li>Внутри run_episode я меняю награду на -1, если эпизод завершен, и на 0 в противном случае:

Код: Выделить всё

r = -1 if te else 0
  • Раскомментировала эту строку внутри loss_function:

Код: Выделить всё

discounted_r = (discounted_r - discounted_r.mean()) / discounted_r.std()
[*]Также внутри loss_function возвращается отрицательное значение среднего вместо отрицательного значения суммы:

Код: Выделить всё

return - wieghted.mean()
С этими изменениями я мог бы решить проблему. Тем не менее я не знаю, почему раньше он уменьшал потери, но работал все хуже и хуже. Это было своего рода обучение задом наперед :).

Подробнее здесь: https://stackoverflow.com/questions/791 ... esnt-learn
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»