def _perform_iterative_refinement_step(
        self,
        latents: torch.Tensor,
        indices_to_alter: List[int],
        loss_fg: torch.Tensor,
        threshold: float,
        text_embeddings: torch.Tensor,
        text_input,
        attention_store: AttentionStore,
        step_size: float,
        t: int,
        attention_res: int = 16,
        smooth_attentions: bool = True,
        sigma: float = 0.5,
        kernel_size: int = 3,
        max_refinement_steps: int = 20,
        normalize_eot: bool = False,
        bboxes: List[int] = None,
        L: int = 1,
        P: float = 0.2,
    ):
        """
        Performs the iterative latent refinement introduced in the paper. Here, we continuously update the latent
        code according to our loss objective until the given threshold is reached for all tokens.
        """
        iteration = 0
        target_loss = max(0, 1.0 - threshold)

        while loss_fg > target_loss:
            iteration += 1

            latents = latents.clone().detach().requires_grad_(True)
            # noise_pred_text = self.unet(latents, t, encoder_hidden_states=text_embeddings[1].unsqueeze(0)).sample
            self.unet.zero_grad()

            # Get max activation value for each subject token
            (
                max_attention_per_index_fg,
                max_attention_per_index_bg,
                dist_x,
                dist_y,
            ) = self._aggregate_and_get_max_attention_per_token(
                attention_store=attention_store,
                indices_to_alter=indices_to_alter,
                attention_res=attention_res,
                smooth_attentions=smooth_attentions,
                sigma=sigma,
                kernel_size=kernel_size,
                normalize_eot=normalize_eot,
                bboxes=bboxes,
                L=L,
                P=P,
            )

            loss_fg, losses_fg = self._compute_loss(
                max_attention_per_index_fg, max_attention_per_index_bg, dist_x, dist_y, return_losses=True
            )

            if loss_fg != 0:
                latents = self._update_latent(latents, loss_fg, step_size)

            # with torch.no_grad():
            #     noise_pred_uncond = self.unet(latents, t, encoder_hidden_states=text_embeddings[0].unsqueeze(0)).sample
            #     noise_pred_text = self.unet(latents, t, encoder_hidden_states=text_embeddings[1].unsqueeze(0)).sample

            # try:
            #     low_token = np.argmax([l.item() if not isinstance(l, int) else l for l in losses_fg])
            # except Exception as e:
            #     print(e)  # catch edge case :)
            #     low_token = np.argmax(losses_fg)

            # low_word = self.tokenizer.decode(text_input.input_ids[0][indices_to_alter[low_token]])
            # print(f'\t Try {iteration}. {low_word} has a max attention of {max_attention_per_index_fg[low_token]}')

            if iteration >= max_refinement_steps:
                # print(f'\t Exceeded max number of iterations ({max_refinement_steps})! '
                #       f'Finished with a max attention of {max_attention_per_index_fg[low_token]}')
                break

        # Run one more time but don't compute gradients and update the latents.
        # We just need to compute the new loss - the grad update will occur below
        latents = latents.clone().detach().requires_grad_(True)
        # noise_pred_text = self.unet(latents, t, encoder_hidden_states=text_embeddings[1].unsqueeze(0)).sample
        self.unet.zero_grad()

        # Get max activation value for each subject token
        (
            max_attention_per_index_fg,
            max_attention_per_index_bg,
            dist_x,
            dist_y,
        ) = self._aggregate_and_get_max_attention_per_token(
            attention_store=attention_store,
            indices_to_alter=indices_to_alter,
            attention_res=attention_res,
            smooth_attentions=smooth_attentions,
            sigma=sigma,
            kernel_size=kernel_size,
            normalize_eot=normalize_eot,
            bboxes=bboxes,
            L=L,
            P=P,
        )
        loss_fg, losses_fg = self._compute_loss(
            max_attention_per_index_fg, max_attention_per_index_bg, dist_x, dist_y, return_losses=True
        )
        # print(f"\t Finished with loss of: {loss_fg}")
        return loss_fg, latents, max_attention_per_index_fg

        Performs the iterative latent refinement introduced in the paper. Here, we continuously update the latent
        code according to our loss objective until the given threshold is reached for all tokens.
        
examples/community/pipeline_stable_diffusion_boxdiff.py