code: def forward(self, joints_in, rot=None, is_train=True, is_diff=False):
      # first we get additional infomation from the 2d inputs
      if self.use_scaler:
          bs = joints_in.size(0)
          hs, ws = self._get_extra_info(joints_in)
          hws = (hs + ws) / 2
          if self.scaler_input_size == 1:
              scaler_inputs = hws.view(bs, -1)
          elif self.scaler_input_size == 34:
              scaler_inputs = joints_in.view(bs, -1)
          elif self.scaler_input_size == 35:
              scaler_inputs = torch.cat(
                  [joints_in.view(bs, -1), hws], dim=1
              )
          elif self.scaler_input_size == 37:
              scaler_inputs = torch.cat(
                  [joints_in.view(bs, -1), hs, ws, hws], dim=1
              )
          else:
              raise NotImplementedError(
                  "Can not recognize {} for scaler's input size".format(
                      self.scaler_input_size
                  )
              )
          # output scales's shape shall be (N, 1)
          if self.learn_symmetry:
              scale_mids = self.scaler(scaler_inputs)
              scales = 2 * scale_mids - hws
          else:
              scales = self.scaler(scaler_inputs)
              scale_mids = (scales + hws) / 2
          # multiply the 2d inputs
          if not self.scale_on_3d:
              joints_in = joints_in * scales.view(-1, 1, 1)
          scaled_2d = None
      else:
          scale_mids = None
          scales = None
          scaled_2d = None
  
      if not is_train:
          center_joints_in = joints_in
          out_features, out_joints_sc = [], []
          features, joints_sc = self.lifter_before(joints_in)
  
          depths = self.lifter_after(features, joints_sc)
          if depths.size(1) == self.num_joints:
              estimated_joints_3d = self._compute_3d(
                  center_joints_in, depths
              )
          else:
              estimated_joints_3d = depths.view(
                  depths.size(0), self.num_joints, 3
              )
          if self.scale_on_3d:
              estimated_joints_3d = estimated_joints_3d * scales.view(
                  -1, 1, 1
              )
  
          if self.use_rotater:
              rot_out = self.rotater(estimated_joints_3d)
              estimated_joints_3d = self.rotate(
                  estimated_joints_3d, rot_out
              )
          return estimated_joints_3d, scales, scale_mids
  
      rot_y, rot_x, rot_z = rot[:, 0:1], rot[:, 1:2], rot[:, 2:3]
  
      out_features, out_joints_sc = [], []
      first_half_feature, second_half_feature = None, None
      # the center frame and its joints
      # if use multi new tmep, joints_in's shape will always be (N * 1 * J * 3)
      features, joints_sc = self.lifter_before(joints_in)
  
      depths = self.lifter_after(features, joints_sc)
      if depths.size(1) == self.num_joints:
          estimated_joints_3d = self._compute_3d(joints_in, depths)
      else:
          estimated_joints_3d = depths.view(depths.size(0), -1, 3)
  
      if self.scale_on_3d:
          estimated_joints_3d = estimated_joints_3d * scales.view(
              -1, 1, 1
          )
  
      # this will be used in inverse transformation later
      root_3d = (
          estimated_joints_3d[:, 13:14]
          if self.num_joints == 17
          else estimated_joints_3d[:, 12:13]
      )
  
      # transfrom
      transformed_joints_3d = transform_3d_v2(
          estimated_joints_3d,
          rot_y,
          rot_x,
          self.c,
          False,
          rot_z=rot_z,
          use_new_rot=self.use_new_rot,
          is_mpi=self.is_mpi,
      )
      projected_joints_2d = self._project(transformed_joints_3d)
      projected_joints_2d = projected_joints_2d + 1e-5
  
      # reconstruct
      recon_features, recon_joints_sc = self.lifter_before(
          projected_joints_2d
      )
      recon_depths = self.lifter_after(recon_features, recon_joints_sc)
      if recon_depths.size(1) == self.num_joints:
          recon_joints_3d = self._compute_3d(
              projected_joints_2d.detach(), recon_depths
          )
      else:
          recon_joints_3d = recon_depths.view(
              recon_depths.size(0), -1, 3
          )
  
      # transfrom inverse
      recovered_joints_3d = transform_3d_v2(
          recon_joints_3d,
          -rot_y,
          -rot_x,
          self.c,
          True,
          rot_z=-rot_z if rot_z is not None else None,
      )
      recovered_joints_3d += root_3d
      recovered_joints_2d = self._project(recovered_joints_3d)
      return (
          (first_half_feature, second_half_feature),
          estimated_joints_3d,
          transformed_joints_3d,
          projected_joints_2d,
          recon_joints_3d,
          recovered_joints_3d,
          recovered_joints_2d,
          scale_mids,
          scales,
      )
  
imports: import torch
  import torch.nn
  import numpy
  import pickle
  from lib.utils.misc import init_weights, load_pickle
  from lib.utils.utils import Transform3D, transform_3d, transform_3d_v2
  from lib.models.building_blocks import ResBlock
  from lib.models.scaler import get_scaler
  from lib.models.rotater import get_rotater
  from lib.models.lifter import get_lifter_before, get_lifter_after
  from lib.models.simple_model import LinearModelBefore, LinearModelAfter, Linear
  from lib.utils.utils import rotate, rotate2
label_desc: Use image node_id 5 for calling the PoseModel obj's underlying member method code with example usage: obj.forward(joints_in, rot, is_train, is_diff) and returns: first_half_feature,  second_half_feature,  estimated_joints_3d,  transformed_joints_3d,  projected_joints_2d,  recon_joints_3d,  recovered_joints_3d,  recovered_joints_2d,  scale_mids,  scales, estimated_joints_3d,  scales,  scale_mids