class_docstr: Coupling block that follows the GLOW design but is applied to all the scales in parallel.
  
  Args:
      dims_in (list[tuple[int]]): list of dimensions of the input tensors
      subnet_args (dict): arguments of the subnet
      clamp (float): clamp value for the output of the subnet
docstr: Applies GLOW coupling for the three scales.
docstr_tok: ["Applies","GLOW","coupling","for","the","three","scales","."]
code: def forward(
      self, input_tensor: list[Tensor], rev=False, jac=True
  ) -> tuple[list[Tensor], Tensor]:
      """Applies GLOW coupling for the three scales."""
  
      # Even channel split. The two splits are used by cross-scale convolution to compute scale and transform
      # parameters.
      x01, x02 = (
          input_tensor[0].narrow(1, 0, self.split_len1),
          input_tensor[0].narrow(1, self.split_len1, self.split_len2),
      )
      x11, x12 = (
          input_tensor[1].narrow(1, 0, self.split_len1),
          input_tensor[1].narrow(1, self.split_len1, self.split_len2),
      )
      x21, x22 = (
          input_tensor[2].narrow(1, 0, self.split_len1),
          input_tensor[2].narrow(1, self.split_len1, self.split_len2),
      )
  
      if not rev:
          # Outputs of cross convolutions at three scales
          r02, r12, r22 = self.cross_convolution2(x02, x12, x22)
  
          # Scale and transform parameters are obtained by splitting the output of cross convolutions.
          s02, t02 = (
              r02[:, : self.split_len1],
              r02[:, self.split_len1 :],
          )
          s12, t12 = (
              r12[:, : self.split_len1],
              r12[:, self.split_len1 :],
          )
          s22, t22 = (
              r22[:, : self.split_len1],
              r22[:, self.split_len1 :],
          )
  
          # apply element wise affine transformation on the first part
          y01 = self.exp(s02) * x01 + t02
          y11 = self.exp(s12) * x11 + t12
          y21 = self.exp(s22) * x21 + t22
  
          r01, r11, r21 = self.cross_convolution1(y01, y11, y21)
  
          s01, t01 = (
              r01[:, : self.split_len2],
              r01[:, self.split_len2 :],
          )
          s11, t11 = (
              r11[:, : self.split_len2],
              r11[:, self.split_len2 :],
          )
          s21, t21 = (
              r21[:, : self.split_len2],
              r21[:, self.split_len2 :],
          )
  
          # apply element wise affine transformation on the second part
          y02 = self.exp(s01) * x02 + t01
          y12 = self.exp(s11) * x12 + t11
          y22 = self.exp(s21) * x22 + t21
  
      else:  # names of x and y are swapped!
          # Inverse affine transformation at three scales.
          r01, r11, r21 = self.cross_convolution1(x01, x11, x21)
  
          s01, t01 = (
              r01[:, : self.split_len2],
              r01[:, self.split_len2 :],
          )
          s11, t11 = (
              r11[:, : self.split_len2],
              r11[:, self.split_len2 :],
          )
          s21, t21 = (
              r21[:, : self.split_len2],
              r21[:, self.split_len2 :],
          )
  
          y02 = (x02 - t01) / self.exp(s01)
          y12 = (x12 - t11) / self.exp(s11)
          y22 = (x22 - t21) / self.exp(s21)
  
          r02, r12, r22 = self.cross_convolution2(y02, y12, y22)
  
          s02, t02 = (
              r02[:, : self.split_len2],
              r01[:, self.split_len2 :],
          )
          s12, t12 = (
              r12[:, : self.split_len2],
              r11[:, self.split_len2 :],
          )
          s22, t22 = (
              r22[:, : self.split_len2],
              r21[:, self.split_len2 :],
          )
  
          y01 = (x01 - t02) / self.exp(s02)
          y11 = (x11 - t12) / self.exp(s12)
          y21 = (x21 - t22) / self.exp(s22)
  
      # Concatenate the outputs of the three scales to get three transformed outputs that have the same shape as the
      # inputs.
      z_dist0 = torch.cat((y01, y02), 1)
      z_dist1 = torch.cat((y11, y12), 1)
      z_dist2 = torch.cat((y21, y22), 1)
  
      z_dist0 = torch.clamp(z_dist0, -1e6, 1e6)
      z_dist1 = torch.clamp(z_dist1, -1e6, 1e6)
      z_dist2 = torch.clamp(z_dist2, -1e6, 1e6)
  
      jac0 = torch.sum(self.log_e(s01), dim=(1, 2, 3)) + torch.sum(
          self.log_e(s02), dim=(1, 2, 3)
      )
      jac1 = torch.sum(self.log_e(s11), dim=(1, 2, 3)) + torch.sum(
          self.log_e(s12), dim=(1, 2, 3)
      )
      jac2 = torch.sum(self.log_e(s21), dim=(1, 2, 3)) + torch.sum(
          self.log_e(s22), dim=(1, 2, 3)
      )
  
      # Since Jacobians are only used for computing loss and summed in the loss, the idea is to sum them here
      return [z_dist0, z_dist1, z_dist2], torch.stack(
          [jac0, jac1, jac2], dim=1
      ).sum()
  
imports: from __future__ import annotations
  from math import exp
  import numpy
  import torch
  import torch.nn.functional
  from FrEIA.framework import GraphINN, InputNode, Node, OutputNode
  from FrEIA.modules import InvertibleModule
  from torch import Tensor, nn
  from torchvision.models.efficientnet import EfficientNet_B5_Weights
  from anomalib.models.components.feature_extractors import TorchFXFeatureExtractor
  from .anomaly_map import AnomalyMapGenerator, AnomalyMapMode
label_desc: Use image node_id 4 for calling the ParallelGlowCouplingLayer obj's underlying member method code with example usage: obj.forward(input_tensor, rev, jac) and returns: list,  torch