@@ -503,27 +503,42 @@ def _wait_unroller_registration():
503503 thread .daemon = True
504504 thread .start ()
505505
506- def _create_data_receiver_subprocess (self ):
507- """Create a process to receive experience data from unrollers.
506+ def _create_replay_buffer_sample_experience (self ):
507+ """
508+ Create a sample experience used to initialize the replay buffer.
508509 """
509- # First create the replay buffer in the main process. For this, we need
510- # to create a dummy experience to set up the replay buffer.
511510 time_step = self ._env .current_time_step ()
512511 rollout_state = self .get_initial_rollout_state (self ._env .batch_size )
513512 alg_step = self .rollout_step (time_step , rollout_state )
514513 exp = make_experience (time_step , alg_step , rollout_state )
515- exp = alf .utils .common .prune_exp_replay_state (exp ,
516- self ._use_rollout_state ,
517- self .rollout_state_spec ,
518- self .train_state_spec )
514+ return alf .utils .common .prune_exp_replay_state (exp ,
515+ self ._use_rollout_state ,
516+ self .rollout_state_spec ,
517+ self .train_state_spec )
519518
520- # enable multi_processing in replay_buffer here, because we need to
521- # receive data in a subprocess and process the data in the main process.
519+ def _create_multiprocessing_replay_buffer (self ):
520+ """
521+ Create the replay buffer in shared memory.
522+ """
522523 ctx = mp .get_context ('spawn' )
523- self ._set_replay_buffer (exp , mp_context = ctx )
524+ assert self ._replay_buffer is None
525+ self ._set_replay_buffer (self ._create_replay_buffer_sample_experience (),
526+ mp_context = ctx )
524527 assert self ._replay_buffer ._allow_multiprocess , (
525528 "The replay buffer must allow multi-processing." )
526529
530+ def _create_data_receiver_subprocess (self ):
531+ """
532+ Create a process to receive experience data from unrollers.
533+
534+ The warm-up train_iter() creates the normal trainer replay buffer in
535+ multiprocessing form before checkpoint restore, so restored shards
536+ load directly into the buffer that the receiver subprocess will use.
537+ """
538+ assert self ._replay_buffer is not None
539+ assert self ._replay_buffer ._allow_multiprocess
540+ ctx = mp .get_context ('spawn' )
541+
527542 # start the data receiver subprocess
528543 # Need to create the subprocess with 'spawn' so that we can pass a Module
529544 # object to subprocess with tensors in shared memory.
@@ -545,8 +560,13 @@ def _train_iter_off_policy(self):
545560 if self ._num_train_iters == 0 :
546561 # First time will be called by ``Trainer._restore_checkpoint()``
547562 # where the ckpt (if any) will be loaded after this function.
563+ # Create the normal trainer replay buffer in multiprocessing form
564+ # before checkpoint load so replay data is restored directly into
565+ # it. Do not start the receiver subprocess yet; it should only
566+ # consume unroller data after checkpoint restore has completed.
567+ self ._create_multiprocessing_replay_buffer ()
548568 self ._num_train_iters += 1
549- return super (). _train_iter_off_policy ()
569+ return 0
550570
551571 if self ._num_train_iters == 1 :
552572 # Only open the unroller registration after we are sure that
0 commit comments