|
|
|
|
|
import torch |
|
from torch import nn |
|
|
|
from detectron2.config import CfgNode |
|
from detectron2.layers import ConvTranspose2d, interpolate |
|
|
|
from ...structures import DensePoseEmbeddingPredictorOutput |
|
from ..utils import initialize_module_params |
|
from .registry import DENSEPOSE_PREDICTOR_REGISTRY |
|
|
|
|
|
@DENSEPOSE_PREDICTOR_REGISTRY.register() |
|
class DensePoseEmbeddingPredictor(nn.Module): |
|
""" |
|
Last layers of a DensePose model that take DensePose head outputs as an input |
|
and produce model outputs for continuous surface embeddings (CSE). |
|
""" |
|
|
|
def __init__(self, cfg: CfgNode, input_channels: int): |
|
""" |
|
Initialize predictor using configuration options |
|
|
|
Args: |
|
cfg (CfgNode): configuration options |
|
input_channels (int): input tensor size along the channel dimension |
|
""" |
|
super().__init__() |
|
dim_in = input_channels |
|
n_segm_chan = cfg.MODEL.ROI_DENSEPOSE_HEAD.NUM_COARSE_SEGM_CHANNELS |
|
embed_size = cfg.MODEL.ROI_DENSEPOSE_HEAD.CSE.EMBED_SIZE |
|
kernel_size = cfg.MODEL.ROI_DENSEPOSE_HEAD.DECONV_KERNEL |
|
|
|
self.coarse_segm_lowres = ConvTranspose2d( |
|
dim_in, n_segm_chan, kernel_size, stride=2, padding=int(kernel_size / 2 - 1) |
|
) |
|
|
|
self.embed_lowres = ConvTranspose2d( |
|
dim_in, embed_size, kernel_size, stride=2, padding=int(kernel_size / 2 - 1) |
|
) |
|
self.scale_factor = cfg.MODEL.ROI_DENSEPOSE_HEAD.UP_SCALE |
|
initialize_module_params(self) |
|
|
|
def interp2d(self, tensor_nchw: torch.Tensor): |
|
""" |
|
Bilinear interpolation method to be used for upscaling |
|
|
|
Args: |
|
tensor_nchw (tensor): tensor of shape (N, C, H, W) |
|
Return: |
|
tensor of shape (N, C, Hout, Wout), where Hout and Wout are computed |
|
by applying the scale factor to H and W |
|
""" |
|
return interpolate( |
|
tensor_nchw, scale_factor=self.scale_factor, mode="bilinear", align_corners=False |
|
) |
|
|
|
def forward(self, head_outputs): |
|
""" |
|
Perform forward step on DensePose head outputs |
|
|
|
Args: |
|
head_outputs (tensor): DensePose head outputs, tensor of shape [N, D, H, W] |
|
""" |
|
embed_lowres = self.embed_lowres(head_outputs) |
|
coarse_segm_lowres = self.coarse_segm_lowres(head_outputs) |
|
embed = self.interp2d(embed_lowres) |
|
coarse_segm = self.interp2d(coarse_segm_lowres) |
|
return DensePoseEmbeddingPredictorOutput(embedding=embed, coarse_segm=coarse_segm) |
|
|