docs: def sg_rnn_layer_func(func):
      r"""Decorates function as sg_rnn_layer functions.
      Args:
          func: function to decorate
      """
      @wraps(func)
      def wrapper(tensor, **kwargs):
          r"""Manages arguments of `tf.sg_opt`.
  
          Args:
            tensor: automatically passed by decorator
            kwargs:
                in_dim: An integer. The size of input dimension, which is set to the last one by default.
                dim: An integer. The size of output dimension. Has the same value as in_dim by default.
                ln: Boolean. If True, layer normalization is applied.
                bias: Boolean. If True, biases are added. As a default, it is set to True
                name: A name for the layer. As a default, the function name is assigned.
                reuse: `True` or `None`; if `True`, we go into reuse mode for this `layer` scope
                  as well as all sub-scopes; if `None`, we just inherit the parent scope reuse.
                summary: If True, summaries are added. The default is True.
          """
  
          # kwargs parsing
          opt = tf.sg_opt(kwargs) + sg_get_context()
  
          # set default argument
          try:
              shape = tensor.get_shape().as_list()
              # dropout off
              opt += tf.sg_opt(shape=shape, in_dim=shape[-1], dim=shape[-1], dout=0, summary=True)
              # disable bias when normalization on
              opt += tf.sg_opt(bias=not opt.ln)
          finally:
              pass
  
          # automatic layer naming
          if opt.name is None:
  
              # layer function name will be used as layer name
              opt.name = func.__name__.replace('sg_', '')
  
              # find existing layer names
              exist_layers = []
              for t in tf.global_variables():
                  scope_name = tf.get_variable_scope().name
                  prefix = scope_name + '/' if len(scope_name) > 0 else ''
                  i = t.name.rfind(prefix + opt.name)
                  if i >= 0:
                      exist_layers.append(t.name[i:].split('/')[-2])
              exist_layers = list(set(exist_layers))
  
              # layer name numbering
              if len(exist_layers) == 0:
                  opt.name += '_1'
              else:
                  opt.name += '_%d' % (max([int(n.split('_')[-1]) for n in exist_layers]) + 1)
  
          with tf.variable_scope(opt.name, reuse=opt.reuse) as scope:
  
              # call layer function
              out = func(tensor, opt)
  
              # apply dropout
              if opt.dout:
                  out = tf.cond(_phase,
                                lambda: tf.nn.dropout(out, 1 - opt.dout),
                                lambda: out)
  
              # rename tensor
              out = tf.identity(out, 'out')
  
              # add final output summary
              if opt.summary:
                  tf.sg_summary_activation(out)
  
              # save node info for reuse
              out._sugar = tf.sg_opt(func=func, arg=tf.sg_opt(kwargs) + sg_get_context(),
                                     prev=tensor, is_layer=True, name=opt.name)
              # inject reuse function
              out.sg_reuse = types.MethodType(sg_reuse, out)
  
          return out
  
      return wrapper