def forward(self,
                mlvl_feats,
                img_metas,
                prev_bev=None,
                only_bev=False,
                ego_his_trajs=None,
                ego_lcf_feat=None,
                cf_img=None,
                command_wp=None,
                command_id=None,
                target_point=None,
                ego_fut_trajs=None
            ):
        """Forward function.
        Args:
            mlvl_feats (tuple[Tensor]): Features from the upstream
                network, each is a 5D-tensor with shape
                (B, N, C, H, W).
            prev_bev: previous bev featues
            only_bev: only compute BEV features with encoder. 
        Returns:
            all_cls_scores (Tensor): Outputs from the classification head, \
                shape [nb_dec, bs, num_query, cls_out_channels]. Note \
                cls_out_channels should includes background.
            all_bbox_preds (Tensor): Sigmoid outputs from the regression \
                head with normalized coordinate format (cx, cy, w, l, cz, h, theta, vx, vy). \
                Shape [nb_dec, bs, num_query, 9].
        """
        
        if not only_bev and not self.training:
            self.plan_fut_mode = self.plan_fut_mode_testing

        bs, num_cam, _, _, _ = mlvl_feats[0].shape
        dtype = mlvl_feats[0].dtype
        object_query_embeds = self.query_embedding.weight.to(dtype)
        
        # import pdb;pdb.set_trace()
        if self.map_query_embed_type == 'all_pts':
            map_query_embeds = self.map_query_embedding.weight.to(dtype)
        elif self.map_query_embed_type == 'instance_pts':
            map_pts_embeds = self.map_pts_embedding.weight.unsqueeze(0)
            map_instance_embeds = self.map_instance_embedding.weight.unsqueeze(1)
            map_query_embeds = (map_pts_embeds + map_instance_embeds).flatten(0, 1).to(dtype)

        bev_queries = self.bev_embedding.weight.to(dtype)

        bev_mask = torch.zeros((bs, self.bev_h, self.bev_w),
                               device=bev_queries.device).to(dtype)
        bev_pos = self.positional_encoding(bev_mask).to(dtype)
            
        if only_bev:  # only use encoder to obtain BEV features, TODO: refine the workaround
            return self.transformer.get_bev_features(
                mlvl_feats,
                bev_queries,
                self.bev_h,
                self.bev_w,
                grid_length=(self.real_h / self.bev_h,
                             self.real_w / self.bev_w),
                bev_pos=bev_pos,
                img_metas=img_metas,
                prev_bev=prev_bev,
            )
        else:
            outputs = self.transformer(
                mlvl_feats,
                bev_queries,
                object_query_embeds,
                map_query_embeds,
                self.bev_h,
                self.bev_w,
                grid_length=(self.real_h / self.bev_h,
                             self.real_w / self.bev_w),
                bev_pos=bev_pos,
                reg_branches=self.reg_branches if self.with_box_refine else None,  # noqa:E501
                cls_branches=self.cls_branches if self.as_two_stage else None,
                map_reg_branches=self.map_reg_branches if self.with_box_refine else None,  # noqa:E501
                map_cls_branches=self.map_cls_branches if self.as_two_stage else None,
                img_metas=img_metas,
                prev_bev=prev_bev
            )

        bev_embed, hs, init_reference, inter_references, \
            map_hs, map_init_reference, map_inter_references = outputs

        hs = hs.permute(0, 2, 1, 3)
        outputs_classes = []
        outputs_coords = []
        outputs_coords_bev = []
        outputs_mot_trajs = []
        outputs_mot_trajs_classes = []

        map_hs = map_hs.permute(0, 2, 1, 3)
        map_outputs_classes = []
        map_outputs_coords = []
        map_outputs_pts_coords = []
        map_outputs_coords_bev = []

        for lvl in range(hs.shape[0]):
            if lvl == 0:
                reference = init_reference
            else:
                reference = inter_references[lvl - 1]
            reference = inverse_sigmoid(reference)
            outputs_class = self.cls_branches[lvl](hs[lvl])
            tmp = self.reg_branches[lvl](hs[lvl])

            # TODO: check the shape of reference
            assert reference.shape[-1] == 3
            tmp[..., 0:2] = tmp[..., 0:2] + reference[..., 0:2]
            tmp[..., 0:2] = tmp[..., 0:2].sigmoid()
            outputs_coords_bev.append(tmp[..., 0:2].clone().detach())
            tmp[..., 4:5] = tmp[..., 4:5] + reference[..., 2:3]
            tmp[..., 4:5] = tmp[..., 4:5].sigmoid()
            tmp[..., 0:1] = (tmp[..., 0:1] * (self.pc_range[3] -
                             self.pc_range[0]) + self.pc_range[0])
            tmp[..., 1:2] = (tmp[..., 1:2] * (self.pc_range[4] -
                             self.pc_range[1]) + self.pc_range[1])
            tmp[..., 4:5] = (tmp[..., 4:5] * (self.pc_range[5] -
                             self.pc_range[2]) + self.pc_range[2])

            # TODO: check if using sigmoid
            outputs_coord = tmp
            outputs_classes.append(outputs_class)
            outputs_coords.append(outputs_coord)
        
        for lvl in range(map_hs.shape[0]):
            if lvl == 0:
                reference = map_init_reference
            else:
                reference = map_inter_references[lvl - 1]
            reference = inverse_sigmoid(reference)
            map_outputs_class = self.map_cls_branches[lvl](
                map_hs[lvl].view(bs,self.map_num_vec, self.map_num_pts_per_vec,-1).mean(2)
            )
            tmp = self.map_reg_branches[lvl](map_hs[lvl])
            # TODO: check the shape of reference
            assert reference.shape[-1] == 2
            tmp[..., 0:2] += reference[..., 0:2]
            tmp = tmp.sigmoid() # cx,cy,w,h
            map_outputs_coord, map_outputs_pts_coord = self.map_transform_box(tmp)
            map_outputs_coords_bev.append(map_outputs_pts_coord.clone().detach())
            map_outputs_classes.append(map_outputs_class)
            map_outputs_coords.append(map_outputs_coord)
            map_outputs_pts_coords.append(map_outputs_pts_coord)
            
        if self.mot_decoder is not None:
            batch_size, num_agent = outputs_coords_bev[-1].shape[:2]
            # mot_query
            mot_query = hs[-1].permute(1, 0, 2)  # [A, B, D]
            mode_query = self.mot_mode_query.weight  # [mot_fut_mode, D]
            # [M, B, D], M=A*mot_fut_mode
            mot_query = (mot_query[:, None, :, :] + mode_query[None, :, None, :]).flatten(0, 1)

            if self.interaction_pe_type is not None:
                mot_coords = outputs_coords_bev[-1]  # [B, A, 2]
                mot_coords = pos2posemb2d(mot_coords, num_pos_feats=self.embed_dims // 2) if self.interaction_pe_type == 'sine_mlp' else mot_coords
                mot_pos = self.pe_embed_mlps[0](mot_coords)  # [B, A, D]
                mot_pos = mot_pos.unsqueeze(2).repeat(1, 1, self.mot_fut_mode, 1).flatten(1, 2)
                mot_pos = mot_pos.permute(1, 0, 2)  # [M, B, D]
            else:
                mot_pos = None

            if self.mot_det_score is not None:
                mot_score = outputs_classes[-1]
                max_mot_score = mot_score.max(dim=-1)[0]
                invalid_mot_idx = max_mot_score < self.mot_det_score  # [B, A]
                invalid_mot_idx = invalid_mot_idx.unsqueeze(2).repeat(1, 1, self.mot_fut_mode).flatten(1, 2)
            else:
                invalid_mot_idx = None

            mot_hs = self.mot_decoder(
                query=mot_query,
                key=mot_query,
                value=mot_query,
                query_pos=mot_pos,
                key_pos=mot_pos,
                key_padding_mask=invalid_mot_idx)

            if self.mot_map_decoder is not None:
                # map preprocess
                mot_coords = outputs_coords_bev[-1]  # [B, A, 2]
                mot_coords = mot_coords.unsqueeze(2).repeat(1, 1, self.mot_fut_mode, 1).flatten(1, 2)
                map_query = map_hs[-1].view(batch_size, self.map_num_vec, self.map_num_pts_per_vec, -1)
                map_query = self.lane_encoder(map_query)  # [B, P, pts, D] -> [B, P, D]
                map_score = map_outputs_classes[-1]
                map_pos = map_outputs_coords_bev[-1]
                map_query, map_pos, key_padding_mask = self.select_and_pad_pred_map(
                    mot_coords, map_query, map_score, map_pos,
                    map_thresh=self.mot_map_thresh, dis_thresh=self.mot_dis_thresh,
                    pe_normalization=self.pe_normalization, use_fix_pad=True)
                map_query = map_query.permute(1, 0, 2)  # [P, B*M, D]
                ca_mot_query = mot_hs.permute(1, 0, 2).flatten(0, 1).unsqueeze(0)

                # position encoding
                if self.interaction_pe_type is not None:
                    (attn_num_query, attn_batch) = ca_mot_query.shape[:2] 
                    mot_pos = torch.zeros((attn_num_query, attn_batch, 2), device=mot_hs.device)
                    mot_pos = pos2posemb2d(mot_pos, num_pos_feats=self.embed_dims // 2) if self.interaction_pe_type == 'sine_mlp' else mot_pos
                    mot_pos = self.pe_embed_mlps[1](mot_pos)
                    map_pos = map_pos.permute(1, 0, 2)
                    map_pos = pos2posemb2d(map_pos, num_pos_feats=self.embed_dims // 2) if self.interaction_pe_type == 'sine_mlp' else map_pos
                    map_pos = self.pe_embed_mlps[1](map_pos)
                else:
                    mot_pos, map_pos = None, None
                
                ca_mot_query = self.mot_map_decoder(
                    query=ca_mot_query,
                    key=map_query,
                    value=map_query,
                    query_pos=mot_pos,
                    key_pos=map_pos,
                    key_padding_mask=key_padding_mask)
            else:
                ca_mot_query = mot_hs.permute(1, 0, 2).flatten(0, 1).unsqueeze(0)

            batch_size = outputs_coords_bev[-1].shape[0]
            mot_hs = mot_hs.permute(1, 0, 2).unflatten(
                dim=1, sizes=(num_agent, self.mot_fut_mode)
            )
            ca_mot_query = ca_mot_query.squeeze(0).unflatten(
                dim=0, sizes=(batch_size, num_agent, self.mot_fut_mode)
            )
            mot_hs = torch.cat([mot_hs, ca_mot_query], dim=-1)  # [B, A, mot_fut_mode, 2D]
        else:
            raise NotImplementedError('Not implement yet')

        outputs_traj = self.mot_reg_branches[0](mot_hs)
        outputs_mot_trajs.append(outputs_traj)
        outputs_mot_class = self.mot_cls_branches[0](mot_hs)
        outputs_mot_trajs_classes.append(outputs_mot_class.squeeze(-1))

        map_outputs_classes = torch.stack(map_outputs_classes)
        map_outputs_coords = torch.stack(map_outputs_coords)
        map_outputs_pts_coords = torch.stack(map_outputs_pts_coords)
        outputs_classes = torch.stack(outputs_classes)
        outputs_coords = torch.stack(outputs_coords)
        outputs_mot_trajs = torch.stack(outputs_mot_trajs)
        outputs_mot_trajs_classes = torch.stack(outputs_mot_trajs_classes)

        # planning
        (batch, num_agent) = mot_hs.shape[:2]


        # kinodynamic filtering      
        # dynamic voca      ego_lcf_feat   ego_his_trajs   ego_fut_trajs
        # from carla_simulation.team_code_autopilot.autopilot import EgoModel
        # self.ego_model = EgoModel(dt=0.5)
        # vx, vy = ego_lcf_feat[0,0,0,:2]
        # spds = (vx**2 + vy**2).sqrt()
        # self.ego_model.forward(locs=np.array([0,0]), yaws=0, spds=spds, acts=np.array([-1, 1, 0]))       # steer, throt, brake

        Dt = 0.5
        vx, vy, ax, ay = ego_lcf_feat[0,0,0,:4]
        v_xy = torch.sqrt(vx**2 + vy**2)
        a_xy = torch.sqrt(ax**2 + ay**2)
        pred_dis = v_xy * Dt + 1 / 2 * a_xy * Dt**2
        kinodynamic_mask = (torch.norm(self.plan_anchors[:,0,:], dim=-1) - pred_dis).abs() < 100000000000
        used_index = torch.multinomial(kinodynamic_mask.float(), self.plan_fut_mode, replacement=False)
        # used_index = torch.LongTensor(random.sample(list(range(self.plan_anchors.shape[0]))[kinodynamic_mask], self.plan_fut_mode)).to(mot_hs.device)
        if self.training:
            best_match_idx = torch.linalg.norm(ego_fut_trajs[0].cumsum(dim=-2) - self.plan_anchors, dim=-1).sum(dim=-1).argmin() 
            # torch.linalg.norm(ego_traj_preds[:,:,:] - ego_fut_gt.cumsum(dim=-2)[:,:,:], dim=-1).sum(dim=-1) 
            if best_match_idx in used_index:
                pass
            else:
                used_index[-1] = best_match_idx

        self.used_plan_anchors = torch.index_select(self.plan_anchors, 0, used_index)


        # set stop traj to zero
        self.used_plan_anchors[self.used_plan_anchors[:,0].norm(dim=-1) < 1e-2] = 0.
        # fix one stop traj
        self.used_plan_anchors[0] = 0.

        _tmp = pos2posemb2d(self.used_plan_anchors.reshape(1, self.plan_fut_mode * self.fut_ts, -1), num_pos_feats=self.embed_dims // 2) \
                .reshape(self.plan_fut_mode, self.fut_ts, -1)
        ego_query = _tmp.unsqueeze(0).repeat(batch, 1, 1, 1).reshape(batch, self.plan_fut_mode, -1)


        ego_query = self.ego_query_pre_branch(ego_query)
        # ego_query = self.ego_query.weight.unsqueeze(0).repeat(batch, 1, 1)
        # ego-environment Interaction
        # ego<->agent query & pos
        agent_conf = outputs_classes[-1]
        agent_query = mot_hs.reshape(batch, num_agent, -1)
        agent_query = self.fus_mlp(agent_query) # [B, A, mot_fut_mode*2*D] -> [B, A, D]
        agent_pos = outputs_coords_bev[-1]

        agent_query, agent_pos, agent_mask = self.select_and_pad_query(
            agent_query, agent_pos, agent_conf,
            score_thresh=self.ego_query_thresh,
            use_fix_pad=self.query_use_fix_pad)

        if self.interaction_pe_type is not None:
            ego_agent_pos = torch.ones((batch, ego_query.shape[1], 2), device=ego_query.device)*0.5  # ego in the center
            ego_agent_pos = pos2posemb2d(ego_agent_pos, num_pos_feats=self.embed_dims // 2) if self.interaction_pe_type == 'sine_mlp' else ego_agent_pos
            ego_agent_pos = self.pe_embed_mlps[2](ego_agent_pos)
            agent_pos = pos2posemb2d(agent_pos, num_pos_feats=self.embed_dims // 2) if self.interaction_pe_type == 'sine_mlp' else agent_pos
            agent_pos = self.pe_embed_mlps[2](agent_pos)
            ego_agent_pos = ego_agent_pos.permute(1, 0, 2)
            agent_pos = agent_pos.permute(1, 0, 2)
        else:
            ego_agent_pos, agent_pos = None, None

        # ego <-> map query & pos
        map_query = map_hs[-1].view(batch_size, self.map_num_vec, self.map_num_pts_per_vec, -1)
        map_query = self.lane_encoder(map_query)  # [B, P, pts, D] -> [B, P, D]
        map_conf = map_outputs_classes[-1]
        map_pos = map_outputs_coords_bev[-1]
        # use the most close pts pos in each map inst as the inst's pos
        batch, num_map = map_pos.shape[:2]
        map_dis = torch.sqrt(map_pos[..., 0]**2 + map_pos[..., 1]**2)
        min_map_pos_idx = map_dis.argmin(dim=-1).flatten()  # [B*P]
        min_map_pos = map_pos.flatten(0, 1)  # [B*P, pts, 2]
        min_map_pos = min_map_pos[range(min_map_pos.shape[0]), min_map_pos_idx]  # [B*P, 2]
        min_map_pos = min_map_pos.view(batch, num_map, 2)  # [B, P, 2]
        map_query, map_pos, map_mask = self.select_and_pad_query(
            map_query, min_map_pos, map_conf,
            score_thresh=self.ego_query_thresh,
            use_fix_pad=self.query_use_fix_pad)

        if self.interaction_pe_type is not None:
            ego_map_pos = torch.ones((batch, ego_query.shape[1], 2), device=agent_query.device)*0.5  # ego in the center
            ego_map_pos = pos2posemb2d(ego_map_pos, num_pos_feats=self.embed_dims // 2) if self.interaction_pe_type == 'sine_mlp' else ego_map_pos
            ego_map_pos = self.pe_embed_mlps[3](ego_map_pos)
            map_pos = pos2posemb2d(map_pos, num_pos_feats=self.embed_dims // 2) if self.interaction_pe_type == 'sine_mlp' else map_pos
            map_pos = self.pe_embed_mlps[3](map_pos)
            ego_map_pos = ego_map_pos.permute(1, 0, 2)
            map_pos = map_pos.permute(1, 0, 2)
        else:
            ego_map_pos, map_pos = None, None

        # ego_pv_query = ego_query
        # ego <-> pv interaction
        batch, _, c_dim, _, _ = mlvl_feats[-1].shape
        attn_pv_feats = mlvl_feats[-1].permute(1, 3, 4, 0, 2).reshape(-1, batch, c_dim)
        ego_pv_query = self.ego_pv_decoder(
            query=ego_query.permute(1, 0, 2),
            key=attn_pv_feats,
            value=attn_pv_feats,
            query_pos=ego_agent_pos,
            key_pos=self.pv_pos_embedding.weight[:,None,:].repeat(1, batch, 1)[:attn_pv_feats.shape[0]]
        )
        
        # ego <-> agent interaction
        ego_agent_query = self.ego_agent_decoder(
            query=ego_pv_query,
            key=agent_query.permute(1, 0, 2),
            value=agent_query.permute(1, 0, 2),
            query_pos=ego_agent_pos,
            key_pos=agent_pos,
            key_padding_mask=agent_mask)

        # ego <-> map interaction
        ego_map_query = self.ego_map_decoder(
            query=ego_agent_query,
            key=map_query.permute(1, 0, 2),
            value=map_query.permute(1, 0, 2),
            query_pos=ego_map_pos,
            key_pos=map_pos,
            key_padding_mask=map_mask)

        # camera front feat -> embedding
        assert cf_img is not None
        # (B, 3, 320, 416) -> (B, 3, 160, 320)
        cf_img_h, cf_img_w = cf_img.shape[2:]
        crop_h = int(cf_img_h/2)
        crop_w1, crop_w2 = int(cf_img_w/4), int(cf_img_w*3/4)
        front_view_img = cf_img[:, :, :crop_h, crop_w1:crop_w2]
        cf_img_feats = self.cf_backbone(cf_img)
        if isinstance(cf_img_feats, dict):
            cf_img_feats = list(cf_img_feats.values())
        cf_img_feats = torch.cat((cf_img_feats[-1].flatten(1, 3),  mlvl_feats[-1].flatten(1, 4)), dim=-1)
        cf_img_feats = self.tl_feats_branch(cf_img_feats)
        cf_img_feats = cf_img_feats.unsqueeze(1)

        # Ego prediction
        assert self.ego_lcf_feat_idx is not None
        ego_pv_query = ego_pv_query.permute(1, 0, 2)
        ego_agent_query = ego_agent_query.permute(1, 0, 2)
        ego_map_query = ego_map_query.permute(1, 0, 2)
        ego_pv_feat = self.ego_feat_projs[6](ego_pv_query)
        ego_agent_feat = self.ego_feat_projs[0](ego_agent_query)
        ego_map_feat = self.ego_feat_projs[1](ego_map_query)
        ego_cf_feat = self.ego_feat_projs[2](cf_img_feats.clone().detach())
        # ego_wp_feat = self.ego_feat_projs[3](target_point.squeeze(1))
        if isinstance(target_point, torch.Tensor):
            _tmp_target_point = target_point.unsqueeze(1)
        else:
            _tmp_target_point = torch.tensor(target_point[None,None], device=ego_cf_feat.device)
        # range (-70m, +70m) grid_size 1m
        _tmp_rasterized_feat = torch.zeros((batch, 140, 140), dtype=torch.float32, device=ego_cf_feat.device)

        # TODO no need / 2.
        _idx = torch.floor((_tmp_target_point.clip(min=-69., max=69.) - (-70.)) / 2.).long()
        for i in range(batch):
            _tmp_rasterized_feat[i, _idx[i,0,0], _idx[i,0,1]] = 1.
        _tmp_rasterized_feat = _tmp_rasterized_feat.reshape(batch, 1, 140 * 140)
        ego_wp_feat = self.ego_feat_projs[3](_tmp_target_point)
        ego_wp_feat += 1. * self.ego_feat_projs[7](_tmp_rasterized_feat)


        # [VOID,LEFT,RIGHT,STRAIGHT,LANEFOLLOW,CHANGELANELEFT,CHANGELANERIGHT]
        if isinstance(command_id, torch.Tensor):
            cmdid_onehot = torch.zeros((batch, 1, 6), device=ego_cf_feat.device, dtype=torch.float32)
            assert command_id.max() <= 6 and command_id.min() >= 1
            for i in range(batch):
                cmdid_onehot[i, 0, command_id[i]-1] = 1.
            ego_cmdid_feat = self.ego_feat_projs[5](cmdid_onehot)
        else:
            cmdid_onehot = torch.zeros((batch, 1, 6), device=ego_cf_feat.device, dtype=torch.float32)
            assert command_id.max() <= 6 and command_id.min() >= 1
            assert batch == 1
            cmdid_onehot[0, 0, command_id - 1] = 1.
            ego_cmdid_feat = self.ego_feat_projs[5](cmdid_onehot)


        ego_status = ego_lcf_feat.squeeze(1)[..., self.ego_lcf_feat_idx]
        ego_status_feat = self.ego_feat_projs[4](ego_status)
        ego_feats = ego_agent_feat + ego_map_feat + \
                     1. * ego_wp_feat + 0. * ego_cmdid_feat + ego_status_feat + ego_cf_feat + 0. * ego_pv_feat

        outputs_ego_trajs = self.plan_reg_branch(ego_feats)
        outputs_ego_trajs = outputs_ego_trajs.reshape(outputs_ego_trajs.shape[0], 
                                                    self.plan_fut_mode, self.fut_ts, 2)
        # if self.training:                        
        #     outputs_ego_trajs = outputs_ego_trajs * 0. + self.plan_anchors[None].to(outputs_ego_trajs.device)
        # else:
        #     outputs_ego_trajs = outputs_ego_trajs * 0.  + self.centerline_trajs[None]
        outputs_ego_trajs = outputs_ego_trajs * 0. + self.used_plan_anchors[None].to(outputs_ego_trajs.device)

        # traffic light classification
        tl_status_cls_scores = self.tl_status_cls_branch(cf_img_feats)
        tl_trigger_cls_scores = self.tl_trigger_cls_branch(cf_img_feats)
        stopsign_trigger_cls_scores = self.stopsign_trigger_cls_branch(cf_img_feats)

        outputs_ego_cls_col = self.plan_cls_col_branch(ego_feats)
        outputs_ego_cls_bd = self.plan_cls_bd_branch(ego_feats)
        outputs_ego_cls_cl = self.plan_cls_cl_branch(ego_feats)
        outputs_ego_cls_expert = self.plan_cls_expert_branch(ego_feats)

        
        outs = {
            'bev_embed': bev_embed,
            'all_cls_scores': outputs_classes,
            'all_bbox_preds': outputs_coords,
            'all_mot_preds': outputs_mot_trajs.repeat(outputs_coords.shape[0], 1, 1, 1, 1),
            'all_mot_cls_scores': outputs_mot_trajs_classes.repeat(outputs_coords.shape[0], 1, 1, 1),
            'map_all_cls_scores': map_outputs_classes,
            'map_all_bbox_preds': map_outputs_coords,
            'map_all_pts_preds': map_outputs_pts_coords,
            'enc_cls_scores': None,
            'enc_bbox_preds': None,
            'map_enc_cls_scores': None,
            'map_enc_bbox_preds': None,
            'map_enc_pts_preds': None,
            'ego_fut_preds': outputs_ego_trajs,
            'tl_status_cls_scores': tl_status_cls_scores,
            'tl_trigger_cls_scores': tl_trigger_cls_scores,
            'stopsign_trigger_cls_scores': stopsign_trigger_cls_scores,
            'ego_cls_col_preds': outputs_ego_cls_col,
            'ego_cls_bd_preds': outputs_ego_cls_bd,
            'ego_cls_cl_preds': outputs_ego_cls_cl,
            'ego_cls_expert_preds': outputs_ego_cls_expert,
        }

        return outs
Forward function.
        Args:
            mlvl_feats (tuple[Tensor]): Features from the upstream
                network, each is a 5D-tensor with shape
                (B, N, C, H, W).
            prev_bev: previous bev featues
            only_bev: only compute BEV features with encoder. 
        Returns:
            all_cls_scores (Tensor): Outputs from the classification head,                 shape [nb_dec, bs, num_query, cls_out_channels]. Note                 cls_out_channels should includes background.
            all_bbox_preds (Tensor): Sigmoid outputs from the regression                 head with normalized coordinate format (cx, cy, w, l, cz, h, theta, vx, vy).                 Shape [nb_dec, bs, num_query, 9].
        
VADv2/VADv2_head.py