code: def encoder_decoder(
      name,
      x,
      hparams,
      eps=None,
      reverse=False,
      cond_latents=None,
      condition=False,
      states=None,
      temperature=1.0,
  ):
      """Glow encoder-decoder. n_levels of (Squeeze + Flow + Split.) operations.
  
      Args:
        name: variable scope.
        x: 4-D Tensor, shape=(NHWC).
        hparams: HParams.
        eps: Stores (glow(x) - mu) / sigma during the forward pass.
             Used only to test if the network is reversible.
        reverse: Forward or reverse pass.
        cond_latents: list of lists of tensors.
                      outer length equals hparams.num_cond_latents
                      innter length equals hparams.num_levels - 1.
        condition: If set to True, condition the encoder/decoder on cond_latents.
        states: LSTM states, used only if hparams.latent_dist_encoder is set
                to "conv_lstm.
        temperature: Temperature set during sampling.
      Returns:
        x: If reverse, decoded image, else the encoded glow latent representation.
        objective: log-likelihood.
        eps: list of tensors, shape=(num_levels-1).
             Stores (glow(x) - mu_level(x)) / sigma_level(x)) for each level.
        all_latents: list of tensors, shape=(num_levels-1).
                     Latent representatios for each level.
        new_states: list of tensors, shape=(num_levels-1).
                    useful only if hparams.latent_dist_encoder="conv_lstm", returns
                    the current state of each level.
      """
      # TODO(mechcoder) Change return_type to a dict to be backward compatible.
      with tf.variable_scope(name, reuse=tf.AUTO_REUSE):
          if states and len(states) != hparams.n_levels - 1:
              raise ValueError(
                  "Expected length of states to be %d, got %d"
                  % (hparams.n_levels - 1, len(states))
              )
          if states is None:
              states = [None] * (hparams.n_levels - 1)
          if eps and len(eps) != hparams.n_levels - 1:
              raise ValueError(
                  "Expected length of eps to be %d, got %d"
                  % (hparams.n_levels - 1, len(eps))
              )
          if eps is None:
              eps = [None] * (hparams.n_levels - 1)
          check_cond_latents(cond_latents, hparams)
  
          objective = 0.0
          all_eps = []
          all_latents = []
          new_states = []
  
          if not reverse:
              # Squeeze + Flow + Split
              for level in range(hparams.n_levels):
                  x = squeeze(
                      "squeeze_%d" % level, x, factor=2, reverse=False
                  )
  
                  x, obj = revnet(
                      "revnet_%d" % level, x, hparams, reverse=False
                  )
                  objective += obj
  
                  if level < hparams.n_levels - 1:
                      curr_cond_latents = get_cond_latents_at_level(
                          cond_latents, level, hparams
                      )
                      x, obj, eps, z, state = split(
                          "split_%d" % level,
                          x,
                          reverse=False,
                          cond_latents=curr_cond_latents,
                          condition=condition,
                          hparams=hparams,
                          state=states[level],
                      )
                      objective += obj
                      all_eps.append(eps)
                      all_latents.append(z)
                      new_states.append(state)
  
              return x, objective, all_eps, all_latents, new_states
  
          else:
              for level in reversed(range(hparams.n_levels)):
                  if level < hparams.n_levels - 1:
                      curr_cond_latents = get_cond_latents_at_level(
                          cond_latents, level, hparams
                      )
  
                      x, latent, state = split(
                          "split_%d" % level,
                          x,
                          eps=eps[level],
                          reverse=True,
                          cond_latents=curr_cond_latents,
                          condition=condition,
                          hparams=hparams,
                          state=states[level],
                          temperature=temperature,
                      )
                      new_states.append(state)
                      all_latents.append(latent)
  
                  x, obj = revnet(
                      "revnet_%d" % level,
                      x,
                      hparams=hparams,
                      reverse=True,
                  )
                  objective += obj
                  x = squeeze("squeeze_%d" % level, x, reverse=True)
              return x, objective, all_latents[::-1], new_states[::-1]
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import functools
  import numpy
  import scipy
  from tensor2tensor.layers import common_layers
  from tensor2tensor.layers import common_video
  from tensor2tensor.utils import contrib
  import tensorflow.compat.v1
  from tensorflow.compat.v1 import estimator
  import tensorflow_probability
label_desc: Use image node_id 40 for calling a global function with example usage: encoder_decoder(name, x, hparams, eps, reverse, cond_latents, condition, states, temperature) and returns: x,  objective,  all_eps,  all_latents,  new_states, x,  objective,  all_latents,  new_states