class_docstr: Handles spawning new individuals from a parent, computing an estimated gradient,
  and applying that gradient to mutate the parent.
code: def __init__(
      self,
      seed: int,
      es_params: EvolutionParameters,
      tensor_sizes: Dict[str, List[int]],
  ) -> None:
      self.es_params = es_params
      self.tensor_sizes = tensor_sizes
      self.seed = seed
      assert (
          self.seed < MAX_RNG_SEED
      ), "The random seed must be less than " + str(MAX_RNG_SEED)
      logger.info("Starting pool with RNG seed: " + str(self.seed))
  
      # Fill the population with empty values: will populate later
      self.population_tensors: List[Dict[str, torch.Tensor]] = []
      for _ in range(es_params.population_size):
          individual = {}
          for tensor_name, tensor_size in self.tensor_sizes.items():
              individual[tensor_name] = torch.zeros(
                  tensor_size, dtype=torch.float
              )
          self.population_tensors.append(individual)
  
      torch.manual_seed(self.seed)
      self.parent_tensors: Dict[str, torch.Tensor] = {}
      for tensor_name, tensor_size in self.tensor_sizes.items():
          self.parent_tensors[tensor_name] = torch.randn(
              tensor_size, dtype=torch.float
          )
          self.parent_tensors[tensor_name].grad = torch.randn(
              tensor_size, dtype=torch.float
          )
  
      self.optimizer = torch.optim.Adam(
          self.parent_tensors.values(), lr=self.es_params.learning_rate
      )
  
      self.populate_children(0)
  
file_path: ReAgent/reagent/training/gradient_free/evolution_pool.py
imports: import logging
  from typing import Dict, List
  import torch
  import torch.fb.rendezvous.zeus
  import torch.nn
  import torch.optim
  from reagent.core.parameters import EvolutionParameters
label_desc: Use image node_id 1 to create a new EvolutionPool object  with example: obj = EvolutionPool(seed, es_params, tensor_sizes)