code: def split_cross_attention_forward(
      self, x, context=None, mask=None, **kwargs
  ):
      h = self.heads
  
      q_in = self.to_q(x)
      context = default(context, x)
  
      context_k, context_v = hypernetwork.apply_hypernetworks(
          shared.loaded_hypernetworks, context
      )
      k_in = self.to_k(context_k)
      v_in = self.to_v(context_v)
  
      dtype = q_in.dtype
      if shared.opts.upcast_attn:
          q_in, k_in, v_in = (
              q_in.float(),
              k_in.float(),
              v_in if v_in.device.type == "mps" else v_in.float(),
          )
  
      with devices.without_autocast(
          disable=not shared.opts.upcast_attn
      ):
          k_in = k_in * self.scale
  
          del context, x
  
          q, k, v = (
              rearrange(t, "b n (h d) -> (b h) n d", h=h)
              for t in (q_in, k_in, v_in)
          )
          del q_in, k_in, v_in
  
          r1 = torch.zeros(
              q.shape[0],
              q.shape[1],
              v.shape[2],
              device=q.device,
              dtype=q.dtype,
          )
  
          mem_free_total = get_available_vram()
  
          gb = 1024**3
          tensor_size = (
              q.shape[0] * q.shape[1] * k.shape[1] * q.element_size()
          )
          modifier = 3 if q.element_size() == 2 else 2.5
          mem_required = tensor_size * modifier
          steps = 1
  
          if mem_required > mem_free_total:
              steps = 2 ** (
                  math.ceil(math.log(mem_required / mem_free_total, 2))
              )
              # print(f"Expected tensor size:{tensor_size/gb:0.1f}GB, cuda free:{mem_free_cuda/gb:0.1f}GB "
              #       f"torch free:{mem_free_torch/gb:0.1f} total:{mem_free_total/gb:0.1f} steps:{steps}")
  
          if steps > 64:
              max_res = (
                  math.floor(
                      math.sqrt(math.sqrt(mem_free_total / 2.5)) / 8
                  )
                  * 64
              )
              raise RuntimeError(
                  f"Not enough memory, use lower resolution (max approx. {max_res}x{max_res}). "
                  f"Need: {mem_required / 64 / gb:0.1f}GB free, Have:{mem_free_total / gb:0.1f}GB free"
              )
  
          slice_size = q.shape[1] // steps
          for i in range(0, q.shape[1], slice_size):
              end = min(i + slice_size, q.shape[1])
              s1 = einsum("b i d, b j d -> b i j", q[:, i:end], k)
  
              s2 = s1.softmax(dim=-1, dtype=q.dtype)
              del s1
  
              r1[:, i:end] = einsum("b i j, b j d -> b i d", s2, v)
              del s2
  
          del q, k, v
  
      r1 = r1.to(dtype)
  
      r2 = rearrange(r1, "(b h) n d -> b n (h d)", h=h)
      del r1
  
      return self.to_out(r2)
  
imports: from __future__ import annotations
  import math
  import psutil
  import platform
  import torch
  from torch import einsum
  from ldm.util import default
  from einops import rearrange
  from modules import shared, errors, devices, sub_quadratic_attention
  from modules.hypernetworks import hypernetwork
  import ldm.modules.attention
  import ldm.modules.diffusionmodules.model
  import sgm.modules.attention
  import sgm.modules.diffusionmodules.model
label_desc: Use image node_id 4 for calling a global function with example usage: split_cross_attention_forward(x, context, mask) and returns: self