class_docstr: The rollout generation is bound to a single worker environment by implementing it as a Wrapper class.
class_docstr_tok: ["The","rollout","generation","is","bound","to","a","single","worker","environment","by","implementing","it","as","a","Wrapper","class","."]
docstr: Generate a single training sample, consisting of two rollouts, obtained by adding and subtracting the
  same random perturbation vector from the policy.
  
  :param policy: Multi-step policy encapsulating the policy networks.
  :param noise_stddev: The standard deviation of the applied parameter noise.
  
  :return A result set with a pair of rollouts generated by adding/subtracting the perturbations
          (antithetic sampling)
docstr_tok: ["Generate","a","single","training","sample",",","consisting","of","two","rollouts",",","obtained","by","adding","and","subtracting","the","same","random","perturbation","vector","from","the","policy",".",":","param","policy",":","Multi-step","policy","encapsulating","the","policy","networks",".",":","param","noise_stddev",":","The","standard","deviation","of","the","applied","parameter","noise",".",":","return","A","result","set","with","a","pair","of","rollouts","generated","by","adding\/subtracting","the","perturbations","(","antithetic","sampling",")"]
code: def generate_training(
      self, policy: Union[Policy, TorchModel], noise_stddev: float
  ) -> ESRolloutResult:
      """Generate a single training sample, consisting of two rollouts, obtained by adding and subtracting the
      same random perturbation vector from the policy.
  
      :param policy: Multi-step policy encapsulating the policy networks.
      :param noise_stddev: The standard deviation of the applied parameter noise.
  
      :return A result set with a pair of rollouts generated by adding/subtracting the perturbations
              (antithetic sampling)
      """
      r = ESRolloutResult(is_eval=False)
  
      # generate a random noise vector
      noise_idx = self.shared_noise.sample_index(self.wrapper_rng)
  
      v = noise_stddev * self.shared_noise.get(
          noise_idx, policy.num_params
      )
      v = torch.from_numpy(v).to(policy._device)
  
      # backup the original parameters
      params = get_flat_parameters(policy)
  
      # prepare the aggregator to receive the result statistics
      aggregator = self.get_stats(LogStatsLevel.EPISODE)
  
      r.noise_indices.append(noise_idx)
  
      # --- positive perturbation ---
      # the positive and the negative rollout should be generated under the same conditions
      self.seed(noise_idx)
      set_flat_parameters(policy, params + v)
      self.rollout(policy)
      r.episode_stats.append(aggregator.last_stats)
  
      # --- negative perturbation ---
      # prepare second rollout
      self.seed(noise_idx)
      set_flat_parameters(policy, params - v)
      self.rollout(policy)
      r.episode_stats.append(aggregator.last_stats)
  
      # restore the policy state
      set_flat_parameters(policy, params)
  
      return r
  
imports: import itertools
  import logging
  import time
  from typing import TypeVar, Union
  import numpy
  import torch
  from maze.core.agent.policy import Policy
  from maze.core.agent.torch_model import TorchModel
  from maze.core.env.structured_env import StructuredEnv
  from maze.core.log_stats.log_stats import LogStatsLevel
  from maze.core.log_stats.log_stats_env import LogStatsEnv
  from maze.core.wrappers.wrapper import Wrapper
  from maze.perception.perception_utils import convert_to_numpy
  from maze.train.trainers.es.distributed.es_distributed_rollouts import ESRolloutResult
  from maze.train.trainers.es.es_shared_noise_table import SharedNoiseTable
  from maze.train.trainers.es.es_utils import get_flat_parameters, set_flat_parameters
label_desc: Use image node_id 6 for calling the ESRolloutWorkerWrapper obj's underlying member method code with example usage: obj.generate_training(policy, noise_stddev) and returns: r