class_docstr: pytorch nn.Module implementation for gan.network.DoppelGANgerGenerator
docstr: Some explanation of params:
  :param feedback: bool, this is a typical RNN mode
  :param noise: bool, this is True for most of the case
         since it is the version of Figure 7.
  :param attribute_input_noise_dim: defaults to 5.
  :param addi_attribute_input_noise_dim: defaults to 5.
  :param attribute_dim: only used for Min/Max Generator(MLP)
  :param feature_outputs: A list of Output objects, indicating the
         dimension, type, normalization of each feature
  :param attribute_outputs A list of Output objects, indicating the
         dimension, type, normalization of each attribute
  :param sample_len: parameter S in Section 4.1 in the paper
         refer to https://github.com/fjxmlzn/DoppelGANger/issues/9
  :param real_attribute_mask: List of True/False, the length equals the
         number of attributes. False if the attribute is (max-min)/2 or
         (max+min)/2, True otherwise
docstr_tok: ["Some","explanation","of","params",":",":","param","feedback",":","bool",",","this","is","a","typical","RNN","mode",":","param","noise",":","bool",",","this","is","True","for","most","of","the","case","since","it","is","the","version","of","Figure","7.",":","param","attribute_input_noise_dim",":","defaults","to","5.",":","param","addi_attribute_input_noise_dim",":","defaults","to","5.",":","param","attribute_dim",":","only","used","for","Min\/Max","Generator","(","MLP",")",":","param","feature_outputs",":","A","list","of","Output","objects",",","indicating","the","dimension",",","type",",","normalization","of","each","feature",":","param","attribute_outputs","A","list","of","Output","objects",",","indicating","the","dimension",",","type",",","normalization","of","each","attribute",":","param","sample_len",":","parameter","S","in","Section","4.1","in","the","paper","refer","to","https",":","\/\/github.com\/fjxmlzn\/DoppelGANger\/issues\/9",":","param","real_attribute_mask",":","List","of","True\/False",",","the","length","equals","the","number","of","attributes",".","False","if","the","attribute","is","(","max-min",")","\/2","or","(","max+min",")","\/2",",","True","otherwise"]
code: def __init__(
      self,
      feed_back,
      noise,
      feature_outputs,
      attribute_outputs,
      real_attribute_mask,
      sample_len,
      attribute_num_units=100,
      attribute_num_layers=3,
      feature_num_units=100,
      feature_num_layers=2,
      attribute_input_noise_dim=5,
      addi_attribute_input_noise_dim=5,
      feature_input_noise_dim=5,
      attribute_dim=None,
      initial_state=RNNInitialStateType.RANDOM,
      initial_stddev=0.02,
  ):
      """
      Some explanation of params:
      :param feedback: bool, this is a typical RNN mode
      :param noise: bool, this is True for most of the case
             since it is the version of Figure 7.
      :param attribute_input_noise_dim: defaults to 5.
      :param addi_attribute_input_noise_dim: defaults to 5.
      :param attribute_dim: only used for Min/Max Generator(MLP)
      :param feature_outputs: A list of Output objects, indicating the
             dimension, type, normalization of each feature
      :param attribute_outputs A list of Output objects, indicating the
             dimension, type, normalization of each attribute
      :param sample_len: parameter S in Section 4.1 in the paper
             refer to https://github.com/fjxmlzn/DoppelGANger/issues/9
      :param real_attribute_mask: List of True/False, the length equals the
             number of attributes. False if the attribute is (max-min)/2 or
             (max+min)/2, True otherwise
      """
      super().__init__()
  
      # feedback or noise(Recommeneded)
      self.feed_back = feed_back
      self.noise = noise
  
      # parameter S in Section 4.1
      self.sample_len = sample_len
  
      # MLP generator layer num and hidden units
      self.attribute_num_units = attribute_num_units
      self.attribute_num_layers = attribute_num_layers
      # LSTM generator layer num and hidden units
      self.feature_num_units = feature_num_units
      self.feature_num_layers = feature_num_layers
  
      # abstract output meta information
      self.feature_outputs = feature_outputs
      self.attribute_outputs = attribute_outputs
      self.feature_out_dim = (
          np.sum([t.dim for t in feature_outputs]) * self.sample_len
      )
      self.attribute_out_dim = np.sum(
          [t.dim for t in attribute_outputs]
      )
  
      # real attribute(all attribute other than min/max related)
      self.real_attribute_mask = real_attribute_mask
  
      # RNN init state
      self.initial_state = initial_state
  
      # same as line 137-165 in gan.network.DoppelGANgerGenerator
      # split the output meta information to real and additional(max/min)
      self.real_attribute_outputs = []
      self.addi_attribute_outputs = []
      self.real_attribute_out_dim = 0
      self.addi_attribute_out_dim = 0
      for i in range(len(self.real_attribute_mask)):
          if self.real_attribute_mask[i]:
              self.real_attribute_outputs.append(
                  self.attribute_outputs[i]
              )
              self.real_attribute_out_dim += self.attribute_outputs[
                  i
              ].dim
          else:
              self.addi_attribute_outputs.append(
                  self.attribute_outputs[i]
              )
              self.addi_attribute_out_dim += self.attribute_outputs[
                  i
              ].dim
  
      # real attribute should come first
      from bigdl.nano.utils.common import invalidInputError
  
      for i in range(len(self.real_attribute_mask) - 1):
          if (
              self.real_attribute_mask[i] is False
              and self.real_attribute_mask[i + 1] is True
          ):
              invalidInputError(
                  False, "Real attribute should come first"
              )
  
      # find the output id of gen flag in feature outputs
      self.gen_flag_id = None
      for i in range(len(self.feature_outputs)):
          if self.feature_outputs[i].is_gen_flag:
              self.gen_flag_id = i
              break
      if self.gen_flag_id is None:
          invalidInputError(False, "cannot find gen_flag_id")
      # gen flag can only be [0,1] or [1,0]
      # gen flag is explained in appendix B, right below table 8.
      if self.feature_outputs[self.gen_flag_id].dim != 2:
          invalidInputError(False, "gen flag output's dim should be 2")
  
      # prepare noise meta data (need more discussion or understanding)
      if attribute_dim is None:
          # attribute_dim is None for the 2 Generator(MLP), both take
          # noise(and nothing else) as input.
          all_attribute_dim = []
          all_discrete_attribute_dim = []
          if len(self.addi_attribute_outputs) > 0:
              self.all_attribute_input_noise_dim = [
                  attribute_input_noise_dim,
                  addi_attribute_input_noise_dim,
              ]
              self.all_attribute_outputs = [
                  self.real_attribute_outputs,
                  self.addi_attribute_outputs,
              ]
              self.all_attribute_out_dim = [
                  self.real_attribute_out_dim,
                  self.addi_attribute_out_dim,
              ]
          else:
              self.all_attribute_input_noise_dim = [
                  attribute_input_noise_dim
              ]
              self.all_attribute_outputs = [self.real_attribute_outputs]
              self.all_attribute_out_dim = [self.real_attribute_out_dim]
      else:
          # attribute is not None for only one Generator(MLP)
          # attribute_dim is m for (A1, ..., Am)
          all_attribute_dim = [attribute_dim]
          all_discrete_attribute_dim = [attribute_dim]
          if len(self.addi_attribute_outputs) > 0:
              self.all_attribute_input_noise_dim = [
                  addi_attribute_input_noise_dim
              ]
              self.all_attribute_outputs = [self.addi_attribute_outputs]
              self.all_attribute_out_dim = [self.addi_attribute_out_dim]
          else:
              self.all_attribute_input_noise_dim = []
              self.all_attribute_outputs = []
              self.all_attribute_out_dim = []
  
      # prepare MLP geneartors(Metadata Generator and Min/Max Generator)
      self.mlp_1 = None
      # Metadata Generator if mlp_2 is not None, Min/Max Generator if mlp_2 is None
      self.mlp_2 = None
      # Min/Max Generator if not None
      for part_i in range(len(self.all_attribute_input_noise_dim)):
          # the loop will run at most 2 rounds
          # generate mlp each layer dim
          if len(all_discrete_attribute_dim) > 0:
              layers_dim = [
                  self.all_attribute_input_noise_dim[part_i]
                  + all_discrete_attribute_dim[-1]
              ]
          else:
              layers_dim = [self.all_attribute_input_noise_dim[part_i]]
          layers_dim += [self.attribute_num_units] * (
              self.attribute_num_layers - 1
          )
  
          mlp_list = []
          for i in range(len(layers_dim) - 1):
              mlp_list.append(linear(layers_dim[i], layers_dim[i + 1]))
              mlp_list.append(torch.nn.ReLU())
              mlp_list.append(
                  nn.BatchNorm1d(
                      layers_dim[i + 1], eps=1e-05, momentum=0.1
                  )
              )
          mlp_list.append(
              linear(layers_dim[-1], self.all_attribute_out_dim[part_i])
          )
  
          invalidInputError(
              part_i <= 1, "part_i should smaller than 2!"
          )
          if part_i == 0:
              self.mlp_1 = nn.Sequential(*mlp_list)
          if part_i == 1:
              self.mlp_2 = nn.Sequential(*mlp_list)
          all_discrete_attribute_dim.append(
              self.all_attribute_out_dim[part_i]
          )
  
      # prepare the RNN for meaturements(features) generation
      self.rnn_network = nn.LSTM(
          input_size=self.attribute_out_dim + feature_input_noise_dim,
          hidden_size=self.feature_num_units,
          num_layers=self.feature_num_layers,
          batch_first=True,
      )  # use batch_first to reduce many transpose
  
      # mlp_rnn_list = []
      # for i in range(self.sample_len):
      #     mlp_rnn_list.append(linear(self.feature_num_units, self.feature_out_dim))
      # self.mlp_rnn_list = nn.ModuleList(mlp_rnn_list)
      self.mlp_rnn = linear(
          self.feature_num_units, self.feature_out_dim
      )
  
imports: import torch
  from torch import nn
  import torch.nn.functional
  import numpy
  from enum import Enum
  from .op import linear, flatten
  from .output import OutputType, Normalization
label_desc: Use image node_id 1 to create a new DoppelGANgerGenerator object from inherited base classes: nn with example: obj = DoppelGANgerGenerator(feed_back, noise, feature_outputs, attribute_outputs, real_attribute_mask, sample_len, attribute_num_units, attribute_num_layers, feature_num_units, feature_num_layers, attribute_input_noise_dim, addi_attribute_input_noise_dim, feature_input_noise_dim, attribute_dim, initial_state, initial_stddev)