Я пытаюсь реализовать опыт воспроизведения (ER) в среде OpenAI taxi-v2.Предполагается, что конвергенция ускорится, но, кажется, агент не учится, когда я включаю воспроизведение опыта.Из литературы предполагается, что ER ускоряет конвергенцию, что означает, что в моей реализации должна быть ошибка кодирования.Я тестирую базовый агент (один без ER) и тот, который использует ER параллельно, чтобы увидеть изменения в производительности.Базовый агент, кажется, учится, как и ожидалось.Я потратил больше времени, чтобы это взяло на себя, и я все еще в замешательстве.Я был бы признателен, если бы кто-нибудь взглянул на код и увидел, где я допустил ошибку в кодировании, и указал мне правильное направление.
Думаю, проблема в функции play_and_train_with_replay.Вот код:
env = gym.make("Taxi-v2")
n_actions = env.action_space.n
replay = ReplayBuffer(1000)
agent = QLearningAgent(alpha=0.5, epsilon=0.25, discount=0.99,
get_legal_actions = lambda s: range(n_actions))
# QLearningAgent is a class that implements q-learning.
def play_and_train_with_replay(env, agent, replay=None,
t_max=10**4, replay_batch_size=32):
"""
This function should
- run a full game, actions given by agent.getAction(s)
- train agent using agent.update(...) whenever possible
- return total reward
:param replay: ReplayBuffer where agent can store and sample (s,a,r,s',done) tuples.
If None, do not use experience replay
"""
total_reward = 0.0
s = env.reset()
for t in range(t_max):
# get agent to pick action given state s
a = agent.get_action(s)
next_s, r, done, _ = env.step(a)
agent.update(s,a,r,next_s) # update agent using q-learning
if replay is not None: # code for agent-experienceReplay
# store current <s,a,r,s'> transition in buffer
replay.add(s,a,r,next_s,done)
# sample replay_batch_size random transitions from replay,
slist,alist,rlist,next_slist,donelist = replay.sample(replay_batch_size) # randomly sample a batch of <s,a,r,s',done>
# then update agent on each of them in a loop
for indx in range(replay_batch_size):
s = slist[indx]
a = alist[indx]
r = rlist[indx]
next_s = next_slist[indx]
done = donelist[indx]
agent.update(s,a,r,next_s)
s = next_s
total_reward +=r
if done:break
return total_reward
Предполагается, что общее вознаграждение будет увеличиваться (и становиться положительным) с каждой итерацией, но с включенным воспроизведением опыта оно выравнивается до диапазона от -40 до -15.
Если вы хотите увидеть, как я реализовал функции replay.add и replay.sample, код приведен ниже.Я не уверен, что где-то там спрятана ошибка, но раньше я ошибался.Этот код ниже прошел все предварительные тесты.
import random
#from collections import OrderedDict, deque
class ReplayBuffer(object):
def __init__(self, size):
"""
Create Replay buffer.
Parameters
----------
size: int
Max number of transitions to store in the buffer. When the buffer
overflows the old memories are dropped.
"""
#self._storage = deque()
self._storage = []
self._maxsize = size
self._next_index = 0
def __len__(self):
return len(self._storage)
def add(self, obs_t, action, reward, obs_tp1, done):
'''
Make sure, _storage will not exceed _maxsize.
Make sure, FIFO rule is being followed: the oldest examples has to be removed earlier
'''
'''
data = [OrderedDict({'s':obs_t,
'a':action,
'r': reward,
's_prime': obs_tp1,
'is_done': done})]
# add data to storage
if self.__len__() >= self._maxsize:
diff = abs(self._maxsize - self.__len__())
for _ in range(diff+1):
self._storage.popleft()
self._storage.extend(data)
#elif self.__len__()==0:
# self._storage.extend(data)
else:
self._storage.extend(data)
'''
data = (obs_t, action, reward, obs_tp1, done)
if self._next_index >= self.__len__():
#diff = abs(self._maxsize - self.__len__())
#for _ in range(diff+1):
# self._storage.pop(0)
self._storage.append(data)
else:
self._storage[self._next_index] = data # overrides the first entered data
self._next_index = (self._next_index + 1)% self._maxsize # checks if the remainder is > 0 when compared to maxsize.
def sample(self, batch_size):
"""Sample a batch of experiences.
Parameters
----------
batch_size: int
How many transitions to sample.
Returns
-------
obs_batch: np.array
batch of observations
act_batch: np.array
batch of actions executed given obs_batch
rew_batch: np.array
rewards received as results of executing act_batch
next_obs_batch: np.array
next set of observations seen after executing act_batch
done_mask: np.array
done_mask[i] = 1 if executing act_batch[i] resulted in
the end of an episode and 0 otherwise.
"""
#idxes = <randomly generate batch_size integers to be used as indexes of samples
_indxs = random.choices(range(self.__len__()), k= batch_size)
obs_batch, act_batch, rew_batch, next_obs_batch, done_mask = [],[],[],[],[]
# collect <s,a,r,s',done> for each index
'''
for i in _indxs:
obs_batch.append(self._storage[i]['s'])
act_batch.append(self._storage[i]['a'])
rew_batch.append(self._storage[i]['r'])
next_obs_batch.append(self._storage[i]['s_prime'])
done_mask.append(self._storage[i]['is_done'])
'''
for i in _indxs:
data = self._storage[i]
obs_t, action, reward, obs_tp1, done = data
obs_batch.append(np.array(obs_t, copy=False))
act_batch.append(np.array(action, copy=False))
rew_batch.append(np.array(reward, copy=False))
next_obs_batch.append(np.array(obs_tp1, copy=False))
done_mask.append(np.array(done, copy=False))
return np.array(obs_batch), np.array(act_batch), np.array(rew_batch), np.array(next_obs_batch), np.array(done_mask)