Downsamples the provided mask tensor to match the expected dimensions for scaled dot-product attention. If the aspect ratio of the mask does not match the aspect ratio of the output image, a warning is issued. Args: mask (`torch.Tensor`): The inp
(mask: torch.Tensor, batch_size: int, num_queries: int, value_embed_dim: int)
| 1310 | |
| 1311 | @staticmethod |
| 1312 | def downsample(mask: torch.Tensor, batch_size: int, num_queries: int, value_embed_dim: int): |
| 1313 | """ |
| 1314 | Downsamples the provided mask tensor to match the expected dimensions for scaled dot-product attention. If the |
| 1315 | aspect ratio of the mask does not match the aspect ratio of the output image, a warning is issued. |
| 1316 | |
| 1317 | Args: |
| 1318 | mask (`torch.Tensor`): |
| 1319 | The input mask tensor generated with `IPAdapterMaskProcessor.preprocess()`. |
| 1320 | batch_size (`int`): |
| 1321 | The batch size. |
| 1322 | num_queries (`int`): |
| 1323 | The number of queries. |
| 1324 | value_embed_dim (`int`): |
| 1325 | The dimensionality of the value embeddings. |
| 1326 | |
| 1327 | Returns: |
| 1328 | `torch.Tensor`: |
| 1329 | The downsampled mask tensor. |
| 1330 | |
| 1331 | """ |
| 1332 | o_h = mask.shape[1] |
| 1333 | o_w = mask.shape[2] |
| 1334 | ratio = o_w / o_h |
| 1335 | mask_h = int(math.sqrt(num_queries / ratio)) |
| 1336 | mask_h = int(mask_h) + int((num_queries % int(mask_h)) != 0) |
| 1337 | mask_w = num_queries // mask_h |
| 1338 | |
| 1339 | mask_downsample = F.interpolate(mask.unsqueeze(0), size=(mask_h, mask_w), mode="bicubic").squeeze(0) |
| 1340 | |
| 1341 | # Repeat batch_size times |
| 1342 | if mask_downsample.shape[0] < batch_size: |
| 1343 | mask_downsample = mask_downsample.repeat(batch_size, 1, 1) |
| 1344 | |
| 1345 | mask_downsample = mask_downsample.view(mask_downsample.shape[0], -1) |
| 1346 | |
| 1347 | downsampled_area = mask_h * mask_w |
| 1348 | # If the output image and the mask do not have the same aspect ratio, tensor shapes will not match |
| 1349 | # Pad tensor if downsampled_mask.shape[1] is smaller than num_queries |
| 1350 | if downsampled_area < num_queries: |
| 1351 | warnings.warn( |
| 1352 | "The aspect ratio of the mask does not match the aspect ratio of the output image. " |
| 1353 | "Please update your masks or adjust the output size for optimal performance.", |
| 1354 | UserWarning, |
| 1355 | ) |
| 1356 | mask_downsample = F.pad(mask_downsample, (0, num_queries - mask_downsample.shape[1]), value=0.0) |
| 1357 | # Discard last embeddings if downsampled_mask.shape[1] is bigger than num_queries |
| 1358 | if downsampled_area > num_queries: |
| 1359 | warnings.warn( |
| 1360 | "The aspect ratio of the mask does not match the aspect ratio of the output image. " |
| 1361 | "Please update your masks or adjust the output size for optimal performance.", |
| 1362 | UserWarning, |
| 1363 | ) |
| 1364 | mask_downsample = mask_downsample[:, :num_queries] |
| 1365 | |
| 1366 | # Repeat last dimension to match SDPA output shape |
| 1367 | mask_downsample = mask_downsample.view(mask_downsample.shape[0], mask_downsample.shape[1], 1).repeat( |
| 1368 | 1, 1, value_embed_dim |
| 1369 | ) |