Context:
I've implemented Muzero for the game Tic-tac-toe. Unfortunately, the self-play and training is very slow (like 10 hours until it plays quite well). I ran the python profiler to find the parts that take the most time. The result is that most time is spent doing Monte Carlo tree searches, specifically querying the neural networks for the next hidden state and the value, policy predictions.
While running self-play, my GPU is only on 30% load and my CPU is on max load (single process since GIL)
Note: In the muzero paper, they have done some fancy stuff like scaling some gradients, which I haven't implemented yet. This will probably also result in a small speedup
What I'm trying to do:
I want to speed up the self-play by running multiple MCTS's in different threads so that they pause whenever they want to query the neural network until enough other threads have queries for the network. Then I put all the queries into a batch and sent the batch to the network. Once I have the results, I return them to each thread, and they continue until they try to query the network again.
Reason:
Let's say I want to play 100 self-play games. I do 50 simulations per move, the average game length is 7 and the observation shape is (3,3,3). With my current approach, this would result in 100 * 7 * 50 = 35000 network queries of shape (1,3,3,3).
With the approach described above, I could run all 100 games at once and batch the network queries, resulting in 7 * 50 = 350 network queries of shape (100,3,3,3)
I hope that this will result in a significant speedup.
Questions:
- What are your thoughts on this plan?
- Any frameworks/PyTorch features that can help me with my plan?
- How would you implement something like this?
- How would you tackle problems like threads never waking up because the batch never gets full enough (if there's something better than timeouts), or possible race conditions?
Don't feel obligated to answer all of these questions.