def deformable_attention_core_func_v2(value,
                                      value_spatial_shapes,
                                      sampling_locations,
                                      attention_weights,
                                      num_points_list,
                                      sampling_method='default'):
    """
    Args:
        value (Tensor): [batch_num, value_len, num_heads, head_dim]
        value_spatial_shapes (Tensor|List): [n_levels, 2]
        sampling_locations (Tensor): [batch_num, query_len, num_heads, total_num_points, 2]
        attention_weights (Tensor): [batch_num, query_len, num_heads, total_num_points]
        num_points_list (List): The number of sampling point corresponding to each level
        sampling_method (str): default(grid_sample) or discrete(discrete_sample)

    Returns:
        output (Tensor): [batch_num, query_len, num_heads * head_dim]
    """
    assert sampling_method in ['default', 'discrete'], NotImplementedError
    batch_num, _, num_heads, head_dim = value.shape
    query_len = sampling_locations.shape[1]
    num_levels = len(num_points_list)

    value = value.transpose([0, 2, 3, 1]).flatten(0, 1)
    split_shape = [h * w for h, w in value_spatial_shapes]
    value_list = value.split(split_shape, axis=-1)
    value_list = [
        value.reshape([batch_num * num_heads, head_dim, h, w])
        for value, (h, w) in zip(value_list, value_spatial_shapes)
    ]

    if sampling_method == 'default':
        sampling_grids = 2 * sampling_locations - 1
    else:
        sampling_grids = sampling_locations

    sampling_grids = sampling_grids.transpose([0, 2, 1, 3, 4]).flatten(0, 1)
    sampling_grids_list = sampling_grids.split(num_points_list, axis=-2)

    sampling_value_list = []
    for idx in range(num_levels):
        # value_list[idx]: [batch_num * num_heads, head_dim, h, w]
        # sampling_grids_list[idx]: [batch_num * num_heads, query_len, num_points, 2]
        # _sampling_value: [batch_num * num_heads, head_dim, query_len, num_points]
        if sampling_method == 'default':
            _sampling_value = F.grid_sample(value_list[idx],
                                            sampling_grids_list[idx],
                                            mode='bilinear',
                                            padding_mode='zeros',
                                            align_corners=False)
        else:
            _sampling_value = discrete_sample(value_list[idx],
                                              sampling_grids_list[idx])
        sampling_value_list.append(_sampling_value)

    attn_weights = attention_weights.transpose([0, 2, 1, 3])
    attn_weights = attn_weights.flatten(0, 1).unsqueeze(1)
    sampling_value = paddle.concat(sampling_value_list, axis=-1)
    # attn_weights: [batch_num * num_heads, 1, query_len, total_num_points]
    # sampling_value: [batch_num * num_heads, head_dim, query_len, total_num_points]
    # output: [batch_num * num_heads, head_dim, query_len]
    output = (sampling_value * attn_weights).sum(-1)
    output = output.reshape([batch_num, num_heads * head_dim, query_len])
    return output.transpose([0, 2, 1])

    Args:
        value (Tensor): [batch_num, value_len, num_heads, head_dim]
        value_spatial_shapes (Tensor|List): [n_levels, 2]
        sampling_locations (Tensor): [batch_num, query_len, num_heads, total_num_points, 2]
        attention_weights (Tensor): [batch_num, query_len, num_heads, total_num_points]
        num_points_list (List): The number of sampling point corresponding to each level
        sampling_method (str): default(grid_sample) or discrete(discrete_sample)

    Returns:
        output (Tensor): [batch_num, query_len, num_heads * head_dim]
    
ppdet/modeling/transformers/utils.py