def forward(self,
                query,
                reference_points,
                value,
                value_spatial_shapes,
                value_mask=None):
        """
        Args:
            query (Tensor): [batch_num, query_len, num_heads * head_dim]
            reference_points (Tensor): [batch_num, query_length, n_levels, 2], range in [0, 1], top-left (0,0),
                bottom-right (1, 1), including padding area
            value (Tensor): [batch_num, value_len, num_heads * head_dim]
            value_spatial_shapes (Tensor): [n_levels, 2], [(H_0, W_0), (H_1, W_1), ..., (H_{L-1}, W_{L-1})]
            value_mask (Tensor): [batch_num, value_len], True for non-padding elements, False for padding elements

        Returns:
            output (Tensor): [bs, Length_{query}, C]
        """
        batch_num, query_len = query.shape[:2]
        value_len = value.shape[1]

        value = self.value_proj(value)
        if value_mask is not None:
            value_mask = value_mask.astype(value.dtype).unsqueeze(-1)
            value *= value_mask
        value = value.reshape([batch_num, value_len, self.num_heads, self.head_dim])

        sampling_offsets = self.sampling_offsets(query).reshape(
            [batch_num, query_len, self.num_heads, sum(self.num_points_list), 2])
        attention_weights = self.attention_weights(query).reshape(
            [batch_num, query_len, self.num_heads, sum(self.num_points_list)])
        attention_weights = F.softmax(attention_weights, axis=-1)

        if reference_points.shape[-1] == 2:
            offset_normalizer = value_spatial_shapes.flip([1]).reshape(
                [1, 1, 1, self.num_levels, 1, 2])
            sampling_locations = reference_points.reshape([
                batch_num, query_len, 1, self.num_levels, 1, 2
            ]) + sampling_offsets / offset_normalizer.astype(sampling_offsets.dtype)
        elif reference_points.shape[-1] == 4:
            offset = sampling_offsets * reference_points[:, :, None, :, 2:]
            num_points_scale = self.num_points_scale.astype(query.dtype).unsqueeze(-1)
            offset = offset * num_points_scale * self.offset_scale
            sampling_locations = reference_points[:, :, None, :, :2] + offset
        else:
            raise ValueError(
                "Last dim of reference_points must be 2 or 4, but get {} instead.".
                format(reference_points.shape[-1]))

        output = self.ms_deformable_attn_core(value, value_spatial_shapes,
                                              sampling_locations, attention_weights)
        output = self.output_proj(output)

        return output

        Args:
            query (Tensor): [batch_num, query_len, num_heads * head_dim]
            reference_points (Tensor): [batch_num, query_length, n_levels, 2], range in [0, 1], top-left (0,0),
                bottom-right (1, 1), including padding area
            value (Tensor): [batch_num, value_len, num_heads * head_dim]
            value_spatial_shapes (Tensor): [n_levels, 2], [(H_0, W_0), (H_1, W_1), ..., (H_{L-1}, W_{L-1})]
            value_mask (Tensor): [batch_num, value_len], True for non-padding elements, False for padding elements

        Returns:
            output (Tensor): [bs, Length_{query}, C]
        
ppdet/modeling/transformers/rtdetr_transformerv2.py