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","."]
docstr: Compiles a block-specific dictionary of network layers.
  This could be overwritten by derived layers
  (e.g. to get a 'BatchNormalizedDenseBlock').
  
  :return: Ordered dictionary of torch modules [str, nn.Module]
docstr_tok: ["Compiles","a","block-specific","dictionary","of","network","layers",".","This","could","be","overwritten","by","derived","layers","(","e.g",".","to","get","a","'BatchNormalizedDenseBlock","'",")",".",":","return",":","Ordered","dictionary","of","torch","modules","[","str",",","nn.Module","]"]
code: def build_layer_dict(self) -> OrderedDict:
      """Compiles a block-specific dictionary of network layers.
      This could be overwritten by derived layers
      (e.g. to get a 'BatchNormalizedDenseBlock').
  
      :return: Ordered dictionary of torch modules [str, nn.Module]
      """
      layer_dict = OrderedDict()
  
      # treat first layer
      layer_dict["linear_0"] = nn.Linear(
          self.input_units, self.hidden_units[0]
      )
      layer_dict[f"{self.non_lin.__name__}_0"] = self.non_lin()
  
      # treat remaining layers
      for i, h in enumerate(self.hidden_units[1:], start=1):
          layer_dict[f"linear_{i}"] = nn.Linear(
              self.hidden_units[i - 1], self.hidden_units[i]
          )
          layer_dict[f"{self.non_lin.__name__}_{i}"] = self.non_lin()
  
      return 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 3 for calling the DenseBlock obj's underlying member method code with example usage: obj.build_layer_dict() and returns: layer_dict