I'm trying to understand DQNs. There is one concept that I cannot really understand yet. In the book "Introduction to Reinforcement Learning" as well this tutorial online introduce the concept of a memory buffer (most of the time a Python deque) which must be filled with the following data:
$S_{t}, a_{t}, r_{t}, S_{t+1}$
where $S_{t}$ is the current state, $r_{t}$ is the reward, $S_{t+1}$ is the next status of the system given the action $a_{t}$.
Now, the buffer will be filled up to a point. Then a batch of data will be taken randomly from the buffer. A code representation can be seen here: link.
...
replay.append(exp) #H
state1 = state2
if len(replay) > batch_size:
minibatch = random.sample(replay, batch_size)
state1_batch = torch.cat([s1 for (s1,a,r,s2,d) in minibatch])
action_batch = torch.Tensor([a for (s1,a,r,s2,d) in minibatch])
reward_batch = torch.Tensor([r for (s1,a,r,s2,d) in minibatch])
state2_batch = torch.cat([s2 for (s1,a,r,s2,d) in minibatch])
done_batch = torch.Tensor([d for (s1,a,r,s2,d) in minibatch])
Q1 = model(state1_batch)
...
The fact, that a batch is taken randomly is not intuitive for me for understanding the logic behind it. By taking the data randomly it would be very hard to figure out any possible pattern. It would be like going into a labyrinth marking the way and the directions choosen along the way. Then, after a while (an episode in our programming case), all those markings are randomly changing their direction/position.
Maybe I'm wrong with my example, but if the data is taken randomly, how can a DQN approximate a meaningful function?
UPDATE 17 October 2023
I really thanks @NeilSlater and @DeepQZero for their answers. But it seems, that probably my question was not really clear and/or lead to misinterpretations.
So I would present now an example. In many tutorials about DQN, the gymnasium (or gym) environment is going to be used. CartPole, FrozenLake and many more are simple application, where you can develop your DQN network and test it.
Let's take for instance the CartPole environment. In it you get a +1 as a reward, for every scene, in which the pole remains up within the +/- 12° range. So we can imagine to run one episode. In this episode the pole soon or later will definetly falls down leading to the end of the episode. In my tests, if my action is completely random, than an episode lasts about 20 steps, then it is over. But... it could be, that one episode is particular lucly and that pole will stay vertical for...let's say 50-60 steps (it is just an example). In other words, the sequence of actions led to a very high reward (+1 * number of steps). Which is good, because luckly or not, I got a sequence, which can be used to "solve" the next game.
But now, the problem. All those transistions are stored in one Python deque (or a long memory buffer). And now the surprise to me: one a small amount of those data taken from that buffer. Much worse, randomly. For my limited intuition capacity, this is hard to believe. Because due to the randomness of this batch, the sequence of actions played in one episode doesn't play any role anymore. And this is my question: How it is supposed to work?
Maybe I'm missing some important points here. But my thought were stronger after I read the book "Deep Reinforcement Learning" by Maxim Lapan. In the very first example, he does the following things:
- run one episode of CartPole
- collect action, state, new state and reward for every step
- create a new deque for every new episode
- take a batch of data containing only the most rewarded episodes (he used a percentile of 70%)
- train the network
- repeat
As you can see, he takes a batch based on the most successful episodes. That means, the sequence of actions is important. But for DQN, the batch is taken randomly as the sequence is no important anymore.
I hope, I explained my thoughts...