def _compute_max_attention_per_index(
        self,
        attention_maps: torch.Tensor,
        indices_to_alter: List[int],
        smooth_attentions: bool = False,
        sigma: float = 0.5,
        kernel_size: int = 3,
        normalize_eot: bool = False,
        bboxes: List[int] = None,
        L: int = 1,
        P: float = 0.2,
    ) -> List[torch.Tensor]:
        """Computes the maximum attention value for each of the tokens we wish to alter."""
        last_idx = -1
        if normalize_eot:
            prompt = self.prompt
            if isinstance(self.prompt, list):
                prompt = self.prompt[0]
            last_idx = len(self.tokenizer(prompt)["input_ids"]) - 1
        attention_for_text = attention_maps[:, :, 1:last_idx]
        attention_for_text *= 100
        attention_for_text = torch.nn.functional.softmax(attention_for_text, dim=-1)

        # Shift indices since we removed the first token "1:last_idx"
        indices_to_alter = [index - 1 for index in indices_to_alter]

        # Extract the maximum values
        max_indices_list_fg = []
        max_indices_list_bg = []
        dist_x = []
        dist_y = []

        cnt = 0
        for i in indices_to_alter:
            image = attention_for_text[:, :, i]

            # TODO
            # box = [max(round(b / (512 / image.shape[0])), 0) for b in bboxes[cnt]]
            # x1, y1, x2, y2 = box
            H, W = image.shape
            x1 = min(max(round(bboxes[cnt][0] * W), 0), W)
            y1 = min(max(round(bboxes[cnt][1] * H), 0), H)
            x2 = min(max(round(bboxes[cnt][2] * W), 0), W)
            y2 = min(max(round(bboxes[cnt][3] * H), 0), H)
            box = [x1, y1, x2, y2]
            cnt += 1

            # coordinates to masks
            obj_mask = torch.zeros_like(image)
            ones_mask = torch.ones([y2 - y1, x2 - x1], dtype=obj_mask.dtype).to(obj_mask.device)
            obj_mask[y1:y2, x1:x2] = ones_mask
            bg_mask = 1 - obj_mask

            if smooth_attentions:
                smoothing = GaussianSmoothing(channels=1, kernel_size=kernel_size, sigma=sigma, dim=2).to(image.device)
                input = F.pad(image.unsqueeze(0).unsqueeze(0), (1, 1, 1, 1), mode="reflect")
                image = smoothing(input).squeeze(0).squeeze(0)

            # Inner-Box constraint
            k = (obj_mask.sum() * P).long()
            max_indices_list_fg.append((image * obj_mask).reshape(-1).topk(k)[0].mean())

            # Outer-Box constraint
            k = (bg_mask.sum() * P).long()
            max_indices_list_bg.append((image * bg_mask).reshape(-1).topk(k)[0].mean())

            # Corner Constraint
            gt_proj_x = torch.max(obj_mask, dim=0)[0]
            gt_proj_y = torch.max(obj_mask, dim=1)[0]
            corner_mask_x = torch.zeros_like(gt_proj_x)
            corner_mask_y = torch.zeros_like(gt_proj_y)

            # create gt according to the number config.L
            N = gt_proj_x.shape[0]
            corner_mask_x[max(box[0] - L, 0) : min(box[0] + L + 1, N)] = 1.0
            corner_mask_x[max(box[2] - L, 0) : min(box[2] + L + 1, N)] = 1.0
            corner_mask_y[max(box[1] - L, 0) : min(box[1] + L + 1, N)] = 1.0
            corner_mask_y[max(box[3] - L, 0) : min(box[3] + L + 1, N)] = 1.0
            dist_x.append((F.l1_loss(image.max(dim=0)[0], gt_proj_x, reduction="none") * corner_mask_x).mean())
            dist_y.append((F.l1_loss(image.max(dim=1)[0], gt_proj_y, reduction="none") * corner_mask_y).mean())

        return max_indices_list_fg, max_indices_list_bg, dist_x, dist_y
Computes the maximum attention value for each of the tokens we wish to alter.
examples/community/pipeline_stable_diffusion_boxdiff.py