Hi,
When I implement a class of computation logic like below, I need both render_imgs
and Landmark_p
for further loss calculation.
But when I keep it both, it arise error:
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn]
So how could this problem solved? my code is here:
# BFM 3D face model
class BFM():
def __init__(self,
model_path='BFM/BFM_model_front.mat'):
model = loadmat(model_path)
self.meanshape = torch.from_numpy(model['meanshape']).double() # mean face shape. [3*N,1]
self.idBase = torch.from_numpy(model['idBase']).double() # identity basis. [3*N,80]
self.exBase = torch.from_numpy(model['exBase']).double() # expression basis. [3*N,64]
self.meantex = torch.from_numpy(model['meantex']).double() # mean face texture. [3*N,1] (0-255)
self.texBase = torch.from_numpy(model['texBase']).double() # texture basis. [3*N,80]
self.point_buf = torch.from_numpy(
model['point_buf']).double() # triangle indices for each vertex that lies in. starts from 1. [N,8]
self.face_buf = torch.from_numpy(model['tri']).int() # vertex indices in each triangle. starts from 1. [F,3]
self.keypoints = torch.from_numpy(
model['keypoints']).squeeze().int() # vertex indices of 68 facial landmarks. starts from 1. [68,1]
# Analytic 3D face reconstructor
class Face3D(torch.nn.Module):
"""
This is a pytorch implementation of the BFM model.
original: Face3D(object)
now: Face3D(torch.nn.Module)
"""
def __init__(self):
super(Face3D, self).__init__()
self.facemodel = BFM()
# [107127, 1]
self.meanshape = torch.nn.Parameter(self.facemodel.meanshape, requires_grad=False)
# [107127, 80]
self.idBase = torch.nn.Parameter(self.facemodel.idBase, requires_grad=False)
# self.register_buffer("idBase", self.facemodel.idBase)
# [107127, 64]
# self.register_buffer("exBase", self.facemodel.exBase)
self.exBase = torch.nn.Parameter(self.facemodel.exBase, requires_grad=False)
# [107127, 1]
# self.register_buffer("meantex", self.facemodel.meantex)
self.meantex = torch.nn.Parameter(self.facemodel.meantex, requires_grad=False)
# [107121, 80]
# self.register_buffer('texBase', self.facemodel.texBase)
self.texBase = torch.nn.Parameter(self.facemodel.texBase, requires_grad=False)
# [70789, 3]
# self.register_buffer('face_buf', self.facemodel.face_buf)
self.face_buf = torch.nn.Parameter(self.facemodel.face_buf, requires_grad=False)
# [35709, 8] Max is 70789;
# self.register_buffer('point_buf', self.facemodel.point_buf)
self.point_buf = torch.nn.Parameter(self.facemodel.point_buf, requires_grad=False)
# [68]
# self.register_buffer('keypoints', self.facemodel.keypoints)
self.keypoints = torch.nn.Parameter(self.facemodel.keypoints, requires_grad=False)
# analytic 3D face reconstructions with coefficients from R-Net
def forward(self, coeff, batchsize):
# coeff: [batchsize,257] reconstruction coefficients
id_coeff, ex_coeff, tex_coeff, angles, translation, gamma = self.Split_coeff(coeff)
# [batchsize,N,3] canonical face shape in BFM space
face_shape = self.Shape_formation_block(id_coeff, ex_coeff)
# [batchsize,N,3] vertex texture (in RGB order)
face_texture = self.Texture_formation_block(tex_coeff)
self.face_texture = face_texture
# [batchsize,3,3] rotation matrix for face shape
rotation = self.Compute_rotation_matrix(angles)
# [batchsize,N,3] vertex normal
face_norm = self.Compute_norm(face_shape)
norm_r = torch.bmm(face_norm, rotation)
# do rigid transformation for face shape using predicted rotation and translation
face_shape_t = self.Rigid_transform_block(face_shape, rotation, translation)
self.face_shape_t = face_shape_t
# [batchsize,N,3] vertex color (in RGB order)
face_color = self.Illumination_block(face_texture, norm_r, gamma)
self.face_color = face_color
# compute 2d landmark projections
# landmark_p: [batchsize,68,2]
face_landmark_t = self.Compute_landmark(face_shape_t)
landmark_p = self.Projection_block(face_landmark_t) # 256*256 train_data
landmark_p = torch.stack((landmark_p[:, :, 0], 223. - landmark_p[:, :, 1]), dim=2)
# reconstruction images
render_imgs = self.Render_block(face_shape_t, norm_r, face_color, batchsize)
render_imgs = render_imgs.clamp(0, 255) / 255.
# render_imgs = (render_imgs - render_imgs.min()) / (render_imgs.max() - render_imgs.min())
# https://discuss.pytorch.org/t/how-to-cast-a-tensor-to-another-type/2713
# return render_imgs.float(), landmark_p
return render_imgs.float(), landmark_p
Thank you very much!