class_docstr: Temporal Entropy Model
class_docstr_tok: ["Temporal","Entropy","Model"]
docstr: Compress patched latents to strings
  
  Args:
      latent_patched: unquantized latent of shape [b', seq_len_dec, C], where
          b' = #patches * actual batch size, which is 1 (for compress/decompress)
      encoded: the "features" used to code the latent, ie what we condition on
          to predict the distribution of the current latent. This should be a
          tensor of shape [b', context_len*seq_len_enc, d_model] with b'=
  
  Returns:
      strings (list of strings), extra (dict with tensors).
          NB: In theory, nothing in the  dict (e.g. means and scales) should be
          be used at decode time. In practice, the below ._decode method
          uses them, to avoid issues with non-determinism of the transformer.
docstr_tok: ["Compress","patched","latents","to","strings","Args",":","latent_patched",":","unquantized","latent","of","shape","[","b","'",",","seq_len_dec",",","C","]",",","where","b","'","=","#","patches","*","actual","batch","size",",","which","is","1","(","for","compress\/decompress",")","encoded",":","the","``","features","''","used","to","code","the","latent",",","ie","what","we","condition","on","to","predict","the","distribution","of","the","current","latent",".","This","should","be","a","tensor","of","shape","[","b","'",",","context_len","*","seq_len_enc",",","d_model","]","with","b'=","Returns",":","strings","(","list","of","strings",")",",","extra","(","dict","with","tensors",")",".","NB",":","In","theory",",","nothing","in","the","dict","(","e.g",".","means","and","scales",")","should","be","be","used","at","decode","time",".","In","practice",",","the","below","._decode","method","uses","them",",","to","avoid","issues","with","non-determinism","of","the","transformer","."]
code: def _encode(
      self, latent_patched: Tensor, encoded: Tensor
  ) -> Tuple[List[str], Dict[str, Tensor]]:
      """
      Compress patched latents to strings
  
      Args:
          latent_patched: unquantized latent of shape [b', seq_len_dec, C], where
              b' = #patches * actual batch size, which is 1 (for compress/decompress)
          encoded: the "features" used to code the latent, ie what we condition on
              to predict the distribution of the current latent. This should be a
              tensor of shape [b', context_len*seq_len_enc, d_model] with b'=
  
      Returns:
          strings (list of strings), extra (dict with tensors).
              NB: In theory, nothing in the  dict (e.g. means and scales) should be
              be used at decode time. In practice, the below ._decode method
              uses them, to avoid issues with non-determinism of the transformer.
      """
  
      strings = []
      # all 3 tensors are [b', seq_len_dec, C]
      quantized = torch.full_like(latent_patched, fill_value=10.0)
      autoreg_means = torch.full_like(latent_patched, fill_value=100.0)
      autoreg_scales = torch.full_like(latent_patched, fill_value=100.0)
      # the decoder output has shape [b', seq_len_dec, d_model]
      dec_output_shape = (*latent_patched.shape[:-1], self.d_model)
      dec_output = torch.full(
          dec_output_shape,
          fill_value=100.0,
          dtype=torch.float32,
          device=quantized.device,
      )
  
      prev_mean = None
      prev_scale = None
  
      # add 0 at the end to to code the very last symbol and then break
      for i in itertools.chain(range(self.seq_len_dec), [0]):
          if (
              prev_mean is not None and prev_scale is not None
          ):  # ensures i > 0
              latent_i = latent_patched[:, i - 1, :]
              # # !!! unsqueeze -- batch size 1
              quantized_i, string = self.bottleneck.compress(
                  inputs=latent_i.unsqueeze(0),
                  scales=prev_scale.unsqueeze(0),
                  means=prev_mean.unsqueeze(0),
              )  # [1, b', C] tensor of ints, [string] list of a string
              strings.append(string)  # each string is a list of len 1
              # quantized should contain the mean.
              quantized[:, i - 1, :] = quantized_i.squeeze(0)
  
              if i == 0:
                  break
  
          mean_i, scale_i, dec_output_i = self._get_transformer_output(
              encoded_patched=encoded, latent_q_patched=quantized
          )  # [b', seq_len_dec, C]*2, [b', seq_len_dec, d_model]
  
          prev_mean = autoreg_means[:, i, :] = mean_i[
              :, i, :
          ]  # [b', C]
          prev_scale = autoreg_scales[:, i, :] = scale_i[
              :, i, :
          ]  # [b', C]
          dec_output[:, i, :] = dec_output_i[
              :, i, :
          ]  # assigning [b', d_model]
  
      # NOTE: `autoreg_means` and `autoreg_scales` must not be used at decode time.
      # However, due to transofmer non-determinism, we return them and allow "fake"
      # decoding by setting use_output_from_encode=True in `._decode`
      extra = {
          "means": autoreg_means,
          "scales": autoreg_scales,
          "dec_output": dec_output,
          "quantized": quantized,
      }
      return strings, extra
  
imports: import itertools
  import sys
  from typing import Dict, List, NamedTuple, Optional, Sequence, Tuple
  import torch
  import torch.nn
  from torch import Tensor
  from .bottlenecks import GsnConditionalLocScaleShift
  from .entropy_model_layers import EncoderSection, LearnedPosition, StartSym, Transformer
  from .layers_utils import make_embedding
  from .patcher import Patcher
label_desc: Use image node_id 11 for calling the VCTEntropyModel obj's underlying member method code with example usage: obj._encode(latent_patched, encoded) and returns: strings,  extra