| 22 | } |
| 23 | |
| 24 | class _grid_encode(Function): |
| 25 | @staticmethod |
| 26 | @custom_fwd |
| 27 | def forward(ctx, inputs, embeddings, offsets, per_level_scale, base_resolution, calc_grad_inputs=False, gridtype=0, align_corners=False, interpolation=0): |
| 28 | # inputs: [B, D], float in [0, 1] |
| 29 | # embeddings: [sO, C], float |
| 30 | # offsets: [L + 1], int |
| 31 | # RETURN: [B, F], float |
| 32 | |
| 33 | inputs = inputs.contiguous() |
| 34 | |
| 35 | B, D = inputs.shape # batch size, coord dim |
| 36 | L = offsets.shape[0] - 1 # level |
| 37 | C = embeddings.shape[1] # embedding dim for each level |
| 38 | S = np.log2(per_level_scale) # resolution multiplier at each level, apply log2 for later CUDA exp2f |
| 39 | H = base_resolution # base resolution |
| 40 | |
| 41 | # manually handle autocast (only use half precision embeddings, inputs must be float for enough precision) |
| 42 | # if C % 2 != 0, force float, since half for atomicAdd is very slow. |
| 43 | if torch.is_autocast_enabled() and C % 2 == 0: |
| 44 | embeddings = embeddings.to(torch.half) |
| 45 | |
| 46 | # L first, optimize cache for cuda kernel, but needs an extra permute later |
| 47 | outputs = torch.empty(L, B, C, device=inputs.device, dtype=embeddings.dtype) |
| 48 | |
| 49 | if calc_grad_inputs: |
| 50 | dy_dx = torch.empty(B, L * D * C, device=inputs.device, dtype=embeddings.dtype) |
| 51 | else: |
| 52 | dy_dx = None |
| 53 | |
| 54 | _backend.grid_encode_forward(inputs, embeddings, offsets, outputs, B, D, C, L, S, H, dy_dx, gridtype, align_corners, interpolation) |
| 55 | |
| 56 | # permute back to [B, L * C] |
| 57 | outputs = outputs.permute(1, 0, 2).reshape(B, L * C) |
| 58 | |
| 59 | ctx.save_for_backward(inputs, embeddings, offsets, dy_dx) |
| 60 | ctx.dims = [B, D, C, L, S, H, gridtype, interpolation] |
| 61 | ctx.align_corners = align_corners |
| 62 | |
| 63 | return outputs |
| 64 | |
| 65 | @staticmethod |
| 66 | #@once_differentiable |
| 67 | @custom_bwd |
| 68 | def backward(ctx, grad): |
| 69 | |
| 70 | inputs, embeddings, offsets, dy_dx = ctx.saved_tensors |
| 71 | B, D, C, L, S, H, gridtype, interpolation = ctx.dims |
| 72 | align_corners = ctx.align_corners |
| 73 | |
| 74 | # grad: [B, L * C] --> [L, B, C] |
| 75 | grad = grad.view(B, L, C).permute(1, 0, 2).contiguous() |
| 76 | |
| 77 | grad_embeddings = torch.zeros_like(embeddings) |
| 78 | |
| 79 | if dy_dx is not None: |
| 80 | grad_inputs = torch.zeros_like(inputs, dtype=embeddings.dtype) |
| 81 | else: |
nothing calls this directly
no outgoing calls
no test coverage detected