Fused `Conv2d()` followed by `downsample_2d()`. Padding is performed only once at the beginning, not between the operations. The fused op is considerably more efficient than performing the same calculation using standard TensorFlow ops. It supports gradients of arbitrary orde
(
self,
hidden_states: torch.Tensor,
weight: torch.Tensor | None = None,
kernel: torch.Tensor | None = None,
factor: int = 2,
gain: float = 1,
)
| 177 | self.out_channels = out_channels |
| 178 | |
| 179 | def _downsample_2d( |
| 180 | self, |
| 181 | hidden_states: torch.Tensor, |
| 182 | weight: torch.Tensor | None = None, |
| 183 | kernel: torch.Tensor | None = None, |
| 184 | factor: int = 2, |
| 185 | gain: float = 1, |
| 186 | ) -> torch.Tensor: |
| 187 | """Fused `Conv2d()` followed by `downsample_2d()`. |
| 188 | Padding is performed only once at the beginning, not between the operations. The fused op is considerably more |
| 189 | efficient than performing the same calculation using standard TensorFlow ops. It supports gradients of |
| 190 | arbitrary order. |
| 191 | |
| 192 | Args: |
| 193 | hidden_states (`torch.Tensor`): |
| 194 | Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`. |
| 195 | weight (`torch.Tensor`, *optional*): |
| 196 | Weight tensor of the shape `[filterH, filterW, inChannels, outChannels]`. Grouped convolution can be |
| 197 | performed by `inChannels = x.shape[0] // numGroups`. |
| 198 | kernel (`torch.Tensor`, *optional*): |
| 199 | FIR filter of the shape `[firH, firW]` or `[firN]` (separable). The default is `[1] * factor`, which |
| 200 | corresponds to average pooling. |
| 201 | factor (`int`, *optional*, default to `2`): |
| 202 | Integer downsampling factor. |
| 203 | gain (`float`, *optional*, default to `1.0`): |
| 204 | Scaling factor for signal magnitude. |
| 205 | |
| 206 | Returns: |
| 207 | output (`torch.Tensor`): |
| 208 | Tensor of the shape `[N, C, H // factor, W // factor]` or `[N, H // factor, W // factor, C]`, and same |
| 209 | datatype as `x`. |
| 210 | """ |
| 211 | |
| 212 | assert isinstance(factor, int) and factor >= 1 |
| 213 | if kernel is None: |
| 214 | kernel = [1] * factor |
| 215 | |
| 216 | # setup kernel |
| 217 | kernel = torch.tensor(kernel, dtype=torch.float32) |
| 218 | if kernel.ndim == 1: |
| 219 | kernel = torch.outer(kernel, kernel) |
| 220 | kernel /= torch.sum(kernel) |
| 221 | |
| 222 | kernel = kernel * gain |
| 223 | |
| 224 | if self.use_conv: |
| 225 | _, _, convH, convW = weight.shape |
| 226 | pad_value = (kernel.shape[0] - factor) + (convW - 1) |
| 227 | stride_value = [factor, factor] |
| 228 | upfirdn_input = upfirdn2d_native( |
| 229 | hidden_states, |
| 230 | torch.tensor(kernel, device=hidden_states.device), |
| 231 | pad=((pad_value + 1) // 2, pad_value // 2), |
| 232 | ) |
| 233 | output = F.conv2d(upfirdn_input, weight, stride=stride_value, padding=0) |
| 234 | else: |
| 235 | pad_value = kernel.shape[0] - factor |
| 236 | output = upfirdn2d_native( |
no test coverage detected