class_docstr: Encapsulates multiple torch state action critics for training in structured environments.
  
  :param networks: Mapping of value functions (critic) to encapsulate.
  :param num_policies: The number of corresponding policies.
  :param device: Device the policy should be located on (cpu or cuda)
  :param only_discrete_spaces: A dict specifying if the action spaces w.r.t. the step only hold discrete action
                               spaces.
class_docstr_tok: ["Encapsulates","multiple","torch","state","action","critics","for","training","in","structured","environments",".",":","param","networks",":","Mapping","of","value","functions","(","critic",")","to","encapsulate",".",":","param","num_policies",":","The","number","of","corresponding","policies",".",":","param","device",":","Device","the","policy","should","be","located","on","(","cpu","or","cuda",")",":","param","only_discrete_spaces",":","A","dict","specifying","if","the","action","spaces","w.r.t",".","the","step","only","hold","discrete","action","spaces","."]
docstr: Preform a soft or hard update depending on the tau value chosen. tau==1 results in a hard update
  
  :param tau: Parameter weighting the soft update of the target network.
docstr_tok: ["Preform","a","soft","or","hard","update","depending","on","the","tau","value","chosen",".","tau==1","results","in","a","hard","update",":","param","tau",":","Parameter","weighting","the","soft","update","of","the","target","network","."]
code: def update_target_weights(self, tau: float) -> None:
      """Preform a soft or hard update depending on the tau value chosen. tau==1 results in a hard update
  
      :param tau: Parameter weighting the soft update of the target network.
      """
      for step_key in self.step_critic_keys:
          for critic_key, target_critic_key in zip(
              self.critic_key_mapping[step_key],
              self.critic_key_mapping[(step_key, self.target_key)],
          ):
              # Copy from q-critic to q-target-critic
              for target_param, source_param in zip(
                  self.networks[target_critic_key].parameters(),
                  self.networks[critic_key].parameters(),
              ):
                  target_param.data.copy_(
                      target_param.data * (1.0 - tau)
                      + source_param.data * tau
                  )
  
imports: import copy
  import itertools
  from abc import abstractmethod
  from typing import Mapping, Union, List, Dict
  import torch
  from gym import spaces
  from torch import nn
  from torch.distributions.utils import logits_to_probs
  from maze.core.agent.state_action_critic import StateActionCritic
  from maze.core.agent.torch_model import TorchModel
  from maze.core.annotations import override
  from maze.core.wrappers.observation_preprocessing.preprocessors.one_hot import OneHotPreProcessor
  from maze.perception.blocks.inference import InferenceBlock
  from maze.perception.perception_utils import flatten_spaces, convert_to_numpy, convert_to_torch
  from maze.perception.weight_init import make_module_init_normc
  from maze.utils.bcolors import BColors
label_desc: Use image node_id 8 for calling the TorchStateActionCritic obj's underlying member method code with example usage: obj.update_target_weights(tau) without return types