Apply pixel unshuffle to the tensor `x` with spatial dimensions `spatial_dims` and scaling factor `scale_factor`. Inverse operation of pixelshuffle. See: Shi et al., 2016, "Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network."
(x: torch.Tensor, spatial_dims: int, scale_factor: int)
| 413 | |
| 414 | |
| 415 | def pixelunshuffle(x: torch.Tensor, spatial_dims: int, scale_factor: int) -> torch.Tensor: |
| 416 | """ |
| 417 | Apply pixel unshuffle to the tensor `x` with spatial dimensions `spatial_dims` and scaling factor `scale_factor`. |
| 418 | Inverse operation of pixelshuffle. |
| 419 | |
| 420 | See: Shi et al., 2016, "Real-Time Single Image and Video Super-Resolution |
| 421 | Using an Efficient Sub-Pixel Convolutional Neural Network." |
| 422 | |
| 423 | See: Aitken et al., 2017, "Checkerboard artifact free sub-pixel convolution". |
| 424 | |
| 425 | Args: |
| 426 | x: Input tensor with shape BCHW[D] |
| 427 | spatial_dims: number of spatial dimensions, typically 2 or 3 for 2D or 3D |
| 428 | scale_factor: factor to reduce the spatial dimensions by, must be >=1 |
| 429 | |
| 430 | Returns: |
| 431 | Unshuffled version of `x` with shape (B, C*(r**d), H/r, W/r) for 2D |
| 432 | or (B, C*(r**d), D/r, H/r, W/r) for 3D, where r is the scale_factor |
| 433 | and d is spatial_dims. |
| 434 | |
| 435 | Raises: |
| 436 | ValueError: When spatial dimensions are not divisible by scale_factor |
| 437 | """ |
| 438 | dim, factor = spatial_dims, scale_factor |
| 439 | input_size = list(x.size()) |
| 440 | batch_size, channels = input_size[:2] |
| 441 | scale_factor_mult = factor**dim |
| 442 | new_channels = channels * scale_factor_mult |
| 443 | |
| 444 | if any(d % factor != 0 for d in input_size[2:]): |
| 445 | raise ValueError( |
| 446 | f"All spatial dimensions must be divisible by factor {factor}. " f", spatial shape is: {input_size[2:]}" |
| 447 | ) |
| 448 | output_size = [batch_size, new_channels] + [d // factor for d in input_size[2:]] |
| 449 | reshaped_size = [batch_size, channels] + sum([[d // factor, factor] for d in input_size[2:]], []) |
| 450 | |
| 451 | permute_indices = [0, 1] + [(2 * i + 3) for i in range(spatial_dims)] + [(2 * i + 2) for i in range(spatial_dims)] |
| 452 | x = x.reshape(reshaped_size).permute(permute_indices) |
| 453 | x = x.reshape(output_size) |
| 454 | return x |
| 455 | |
| 456 | |
| 457 | @contextmanager |
searching dependent graphs…