def _generate_tile_kernel(patch: list, mask: list, tile_size: int) -> Tuple["torch.Tensor", "torch.Tensor"]:
    """
    Generate specific size of perturbed tiles from randomly selected patches.

    :param patch: Candidate patches.
    :param mask: Masks for each patch.
    :param tile_size: The size of each tile.
    :return: Perturbed tiles and corresponding masks.
    """
    import torch
    import torchvision

    idx_seq = list(range(len(patch)))
    target = random.sample(idx_seq, k=1)[0]
    t_patch = patch[target]
    t_mask = mask[target]
    if t_mask is None:
        t_mask = torch.ones_like(t_patch)
    width, height = t_patch.shape[-2], t_patch.shape[-1]
    boundary = 1
    tile_size = max(tile_size - 2 * boundary, 1)

    if height > width:
        flip = True
        FlipOp = torchvision.transforms.RandomVerticalFlip(0.2)  # pylint: disable=C0103
        max_len = height
        min_len = width
        t_patch = torch.permute(t_patch, (0, 2, 1))
        t_mask = torch.permute(t_mask, (0, 2, 1))
    else:
        flip = False
        FlipOp = torchvision.transforms.RandomHorizontalFlip(0.2)  # pylint: disable=C0103
        max_len = width
        min_len = height

    if max_len > tile_size:
        new_len = max(round(min_len * tile_size / max_len), 1)
        p_1 = torchvision.transforms.Resize((tile_size, new_len))(t_patch)
        # fix for the case that (strides - new_len) > new_len
        p_list = []

        for _ in range(tile_size // new_len):
            p_list.append(FlipOp(p_1))

        p_2 = torchvision.transforms.RandomCrop((tile_size, tile_size % new_len))(p_1)
        p_list.append(FlipOp(p_2))

        n_patch = torch.cat(p_list, dim=-1)
        n_patch = torchvision.transforms.CenterCrop((tile_size + 2 * boundary, tile_size + 2 * boundary))(n_patch)
        n_mask = torch.where(n_patch == 0, torch.zeros_like(n_patch), torch.ones_like(n_patch))

    elif max_len >= tile_size / 2.0:
        new_len = max(round(min_len * (tile_size / 2.0) / max_len), 1)

        p_list = []
        for _ in range(tile_size // new_len):
            repeat = 2
            p1_list = []
            for _ in range(repeat):
                p_1 = torchvision.transforms.Resize((max(tile_size // 2, 1), new_len))(t_patch)
                if torch.rand([]) < 0.6:
                    p1_list.append(FlipOp(p_1))
                else:
                    p1_list.append(torch.zeros_like(p_1))
            p_1 = torch.cat(p1_list, dim=-2)
            p_list.append(p_1)

        p_2 = torchvision.transforms.RandomCrop((tile_size, max(tile_size % new_len, 1)))(p_1)
        p_list.append(FlipOp(p_2))

        n_patch = torch.cat(p_list, dim=-1)
        n_patch = torchvision.transforms.CenterCrop((tile_size + 2 * boundary, tile_size + 2 * boundary))(n_patch)
        n_mask = torch.where(n_patch == 0, torch.zeros_like(n_patch), torch.ones_like(n_patch))

    else:
        t_1 = torch.cat([t_patch[None, :], t_mask[None, :]], dim=0)
        p_list = []
        n_list = []
        for _ in range(tile_size // min_len):
            p1_list = []
            m1_list = []
            for _ in range(tile_size // max_len):
                if torch.rand([]) < 0.4:
                    t_1 = FlipOp(t_1)
                    p1_list.append(t_1[0, :])
                    m1_list.append(t_1[1, :])
                else:
                    p1_list.append(torch.zeros_like(t_patch))
                    m1_list.append(torch.zeros_like(t_mask))
            p_1 = torch.cat(p1_list, dim=-2)
            m_1 = torch.cat(m1_list, dim=-2)
            p_list.append(p_1)
            n_list.append(m_1)
        n_patch = torch.cat(p_list, dim=-1)
        n_mask = torch.cat(n_list, dim=-1)
        n_patch = torchvision.transforms.CenterCrop((tile_size + 2 * boundary, tile_size + 2 * boundary))(n_patch)
        n_mask = torchvision.transforms.CenterCrop((tile_size + 2 * boundary, tile_size + 2 * boundary))(n_mask)

    if flip:
        n_patch = torch.permute(n_patch, (0, 2, 1))
        n_mask = torch.permute(n_mask, (0, 2, 1))

    return n_patch, n_mask

    Generate specific size of perturbed tiles from randomly selected patches.

    :param patch: Candidate patches.
    :param mask: Masks for each patch.
    :param tile_size: The size of each tile.
    :return: Perturbed tiles and corresponding masks.
    
art/attacks/evasion/steal_now_attack_later/steal_now_attack_later.py