0
$\begingroup$

I have finished implementing an Asynchronous Advantage Actor-Critic (A3C) agent for TensorFlow (gpu). By using a single RMSprop optimizer with shared statistics. To do so, a central controller holds both the Global Network (ActorCriticModel) and the Optimizer. Workers, to update the global network, need to communicate gradients to the Controller, while receiving back the updated model weights. It works decently: despite there might be some errors in the code, it still achieves the results pretty fast. Each Worker is a thread on its own.

class Worker(Thread):

Problem is Workers need to extend the Thread class while I would like to use heavy Processes (from multiprocessing) instead (Queues used in the following snippet of code are imported from the multiprocessing class).

class Controller:

    def __init__(self, **kwargs):

        self.terminated_workers = 0
        self.env_name = kwargs["env_name"]
        self.available_actions = kwargs["available_actions"]
        self.action_size = len(self.available_actions)
        self.env = make_env(kwargs, env_name=self.env_name)
        self.state_shape = self.env.observation_space.shape

        self.number_of_workers = kwargs["number_of_workers"]
        self.workers = []
        self.controller_queue = Queue()
        self.worker_queues = []

        # Initialization of threads
        for i in range(self.number_of_workers):
            worker_queue = Queue()
            self.worker_queues.append(worker_queue)

            updater = GlobalUpdater(self.controller_queue, worker_queue)
            worker = Worker(i, updater, self.state_shape, kwargs)
            self.workers.append(worker)

        # Only import tensorflow after heavy Process initialization
        import tensorflow as tf

        self.global_model = ActorCriticModel(self.state_shape, self.action_size)
        self.opt = tf.keras.optimizers.RMSprop(
            learning_rate=kwargs["lr_schedule"],
            rho=kwargs["rho"],
            centered=kwargs["centered"],
            clipvalue=kwargs["clipvalue"]
        ) 

As soon as i change the Worker to extend Processes instead of threads, I get the following message for every worker instantiated:

F tensorflow/stream_executor/cuda/cuda_driver.cc:152] Failed setting context: CUDA_ERROR_NOT_INITIALIZED: initialization error

Technically, since multiple methods of the Worker class need to use tensorflow, the library is imported statically, before declaring the Worker class, as follows:

import tensorflow as tf

class Worker(Process):
   ...

I'm using Linux and the libraries' versions are:

  • TensorFlow: 2.9.1
  • CUDA: 11.2.2-1
  • cuDNN: 8.1.1.33-1+cuda11.2

I tried every other solution I found online, including setting mp.set_start_method('spawn') and trying to postpone as much as i can the import of the tensorflow library, so to postpone as much as possible the heavy process initialization but nothing seems to work. How would you approach this problem? Do you have any idea on how to solve it? Thanks in advance.

$\endgroup$
4
  • $\begingroup$ Firstly, this question is well suited for StackOverflow, but this forum is less about implementation issues - so this will probably get closed. However, this sounds to me like an issue with memory being not shared petween Processes. Have you tried to import tensorflow in the constructor and reference it as self.tf or use global tf? Also you should use gpu memory growth, otherwise the first process will occupy the whole space on the GPU. $\endgroup$
    – Chillston
    Commented Jul 12, 2022 at 18:58
  • $\begingroup$ Thank you for your kind answer. That's pretty smart, but unfortunately the self.tf is not compatible with the code (as I'm using the @tf.function). $\endgroup$ Commented Jul 12, 2022 at 21:44
  • 1
    $\begingroup$ So, I gave it a try by commenting tf.function, setting multiprocessing.set_start_method('spawn', force=True), importing TensorFlow within the spawned process upon creation and putting global tf right after the import. And it actually works. You're a beast! I've spent months trying to figure this out, it's a pity this post will be removed as I think a lot of people would actually need to see this. $\endgroup$ Commented Jul 12, 2022 at 21:52
  • $\begingroup$ Oh Really? :D That's amazing! I'm glad I was helpful Maybe the post stays I don't know, usually these post get removed but who reads the manual anyways^^ $\endgroup$
    – Chillston
    Commented Jul 13, 2022 at 12:57

0

You must log in to answer this question.