class_docstr: A block containing multiple subsequent dense layers.
  The block expects the input tensors to have the from (batch-dim, feature-dim).
  
  :param in_keys: One key identifying the input tensors.
  :param out_keys: One key identifying the output tensors.
  :param in_shapes: List of input shapes.
  :param hidden_units: List containing the number of hidden units for hidden layers.
  :param non_lin: The non-linearity to apply after each layer.
class_docstr_tok: ["A","block","containing","multiple","subsequent","dense","layers",".","The","block","expects","the","input","tensors","to","have","the","from","(","batch-dim",",","feature-dim",")",".",":","param","in_keys",":","One","key","identifying","the","input","tensors",".",":","param","out_keys",":","One","key","identifying","the","output","tensors",".",":","param","in_shapes",":","List","of","input","shapes",".",":","param","hidden_units",":","List","containing","the","number","of","hidden","units","for","hidden","layers",".",":","param","non_lin",":","The","non-linearity","to","apply","after","each","layer","."]
code: def __init__(
      self,
      in_keys: Union[str, List[str]],
      out_keys: Union[str, List[str]],
      in_shapes: Union[Sequence[int], List[Sequence[int]]],
      hidden_units: List[int],
      non_lin: Union[str, type(nn.Module)],
  ):
      super().__init__(
          in_keys=in_keys,
          out_keys=out_keys,
          in_shapes=in_shapes,
          in_num_dims=2,
          out_num_dims=2,
      )
      self.input_units = self.in_shapes[0][-1]
      self.hidden_units = hidden_units
      self.non_lin = Factory(base_type=nn.Module).type_from_name(
          non_lin
      )
      self.output_units = self.hidden_units[-1]
  
      # compile layer dictionary
      layer_dict = self.build_layer_dict()
  
      # compile network
      self.net = nn.Sequential(layer_dict)
  
file_path: maze/maze/perception/blocks/feed_forward/dense.py
imports: from collections import OrderedDict
  from typing import Union, List, Dict, Sequence
  import torch
  from torch import nn
  from maze.core.annotations import override
  from maze.core.utils.factory import Factory
  from maze.perception.blocks.shape_normalization import ShapeNormalizationBlock
label_desc: Use image node_id 1 to create a new DenseBlock object from inherited base classes: ShapeNormalizationBlock with example: obj = DenseBlock(in_keys, out_keys, in_shapes, hidden_units, non_lin)