docstr: Build the flow model.
  First we start with the input nodes, which have to match the feature extractor output.
  Then, we build the U-Shaped flow. Starting from the bottom (the coarsest scale), the flow is built as follows:
      1. Pass the input through a Flow Stage (`build_flow_stage`).
      2. Split the output of the flow stage into two parts, one that goes directly to the output,
      3. and the other is up-sampled, and will be concatenated with the output of the next flow stage (next scale)
      4. Repeat steps 1-3 for the next scale.
  Finally, we build the Flow graph using the input nodes, the flow stages, and the output nodes.
  
  Args:
      flow_steps (int): Number of flow steps.
  
  Returns:
      ff.GraphINN: Flow model.
docstr_tok: ["Build","the","flow","model",".","First","we","start","with","the","input","nodes",",","which","have","to","match","the","feature","extractor","output",".","Then",",","we","build","the","U-Shaped","flow",".","Starting","from","the","bottom","(","the","coarsest","scale",")",",","the","flow","is","built","as","follows",":","1",".","Pass","the","input","through","a","Flow","Stage","(","`","build_flow_stage","`",")",".","2",".","Split","the","output","of","the","flow","stage","into","two","parts",",","one","that","goes","directly","to","the","output",",","3.","and","the","other","is","up-sampled",",","and","will","be","concatenated","with","the","output","of","the","next","flow","stage","(","next","scale",")","4",".","Repeat","steps","1-3","for","the","next","scale",".","Finally",",","we","build","the","Flow","graph","using","the","input","nodes",",","the","flow","stages",",","and","the","output","nodes",".","Args",":","flow_steps","(","int",")",":","Number","of","flow","steps",".","Returns",":","ff.GraphINN",":","Flow","model","."]
code: def build_flow(self, flow_steps: int) -> ff.GraphINN:
      """
      Build the flow model.
      First we start with the input nodes, which have to match the feature extractor output.
      Then, we build the U-Shaped flow. Starting from the bottom (the coarsest scale), the flow is built as follows:
          1. Pass the input through a Flow Stage (`build_flow_stage`).
          2. Split the output of the flow stage into two parts, one that goes directly to the output,
          3. and the other is up-sampled, and will be concatenated with the output of the next flow stage (next scale)
          4. Repeat steps 1-3 for the next scale.
      Finally, we build the Flow graph using the input nodes, the flow stages, and the output nodes.
  
      Args:
          flow_steps (int): Number of flow steps.
  
      Returns:
          ff.GraphINN: Flow model.
      """
      input_nodes = []
      for channel, s_factor in zip(
          self.feature_extractor.channels,
          self.feature_extractor.scale_factors,
      ):
          input_nodes.append(
              ff.InputNode(
                  channel,
                  self.input_size[0] // s_factor,
                  self.input_size[1] // s_factor,
                  name=f"cond_{channel}",
              )
          )
  
      nodes, output_nodes = [], []
      last_node = input_nodes[-1]
      for i in reversed(range(1, len(input_nodes))):
          flows = self.build_flow_stage(last_node, flow_steps)
          volume_size = flows[-1].output_dims[0][0]
          split = ff.Node(
              flows[-1],
              fm.Split,
              {
                  "section_sizes": (
                      volume_size // 8 * 4,
                      volume_size - volume_size // 8 * 4,
                  ),
                  "dim": 0,
              },
              name=f"split_{i + 1}",
          )
          output = ff.OutputNode(
              split.out1, name=f"output_scale_{i + 1}"
          )
          up = ff.Node(
              split.out0, fm.IRevNetUpsampling, {}, name=f"up_{i + 1}"
          )
          last_node = ff.Node(
              [input_nodes[i - 1].out0, up.out0],
              fm.Concat,
              {"dim": 0},
              name=f"cat_{i}",
          )
  
          output_nodes.append(output)
          nodes.extend([*flows, split, up, last_node])
  
      flows = self.build_flow_stage(last_node, flow_steps)
      output = ff.OutputNode(flows[-1], name="output_scale_1")
  
      output_nodes.append(output)
      nodes.extend(flows)
  
      return ff.GraphINN(input_nodes + nodes + output_nodes[::-1])
  
file_path: anomalib/src/anomalib/models/uflow/torch_model.py
imports: import torch.nn
  from FrEIA import framework
  from FrEIA import modules
  from anomalib.models.components.flow import AllInOneBlock
  from .anomaly_map import AnomalyMapGenerator
  from .feature_extraction import get_feature_extractor
label_desc: Use image node_id 2 for calling the UflowModel obj's underlying member method code with example usage: obj.build_flow(flow_steps) and returns: ff