2. 快速入门

2.1. 软件包

2.1.1. 软件包信息

如果使用离线镜像文件,可以忽略本节。

表 2.1 mcVS发布的软件包

软件包类型

文件名示例

说明

C++库

librmm-x.y.z+bu.v.w.m-py3-none-linux_x86_64.whl

提供RMM头文件和so文件

Python wheel包

rmmx-x.y.z+bu.v.w.m-cp310-cp310-linux_x86_64.whl

RMM的Python扩展包,适用于Python3.10

Python wheel包

rmmx-x.y.z+bu.v.w.m-cp312-cp312-linux_x86_64.whl

RMM的Python扩展包,适用于Python3.12

C++库

libraft-x.y.z+bu.v.w.m-py3-none-linux_x86_64.whl

提供RAFT头文件和so文件

Python wheel包

pylibraft-x.y.z+bu.v.w.m-cp310-cp310-linux_x86_64.whl

RAFT的Python扩展包,适用于Python3.10

Python wheel包

pylibraft-x.y.z+bu.v.w.m-cp312-cp312-linux_x86_64.whl

RAFT的Python扩展包,适用于Python3.12

C++库

libmcvs-x.y.z+bu.v.w.m-py3-none-linux_x86_64.whl

提供mcVS头文件和so文件

Python wheel包

mcvs-x.y.z+bu.v.w.m-cp310-cp310-linux_x86_64.whl

mcVS的Python扩展包,适用于Python3.10

Python wheel包

mcvs-x.y.z+bu.v.w.m-cp312-cp312-linux_x86_64.whl

mcVS的Python扩展包,适用于Python3.12

Python wheel包

mcvs_bench-x.y.z+bu.v.w.m-py3-none-any.whl

mcVS的Python扩展包

Python wheel包

mcpy-x.y.z+bu.v.w.m-cp310-cp310-linux_x86_64.whl

mcpy的Python扩展包,适用于Python3.10

Python wheel包

mcpy-x.y.z+bu.v.w.m-cp312-cp312-linux_x86_64.whl

mcpy的Python扩展包,适用于Python3.12

备注

  • x.y.z表示对应模块的开源版本号,u.v.w.m表示构建版本号。

  • x86_64表示CPU架构。

2.1.2. 软件包内容

安装libmcvs会在python安装第三方包的目录下 /path/to/site-packages/libcuvs 安装相关的二进制开发库和头文件。以 /path/to/site-packages/libcuvs 为起始路径,可得到如下文件内容:

├─include/
│   └─cuvs/
│      ├─neighbors
│      │   ├─all_neighbors.h
│      │   ├─bruef_force.h
│      │   ├─ivf_flat.h
│      │   └─......
│      ├─distance
│      │   ├─distance.h
│      │   └─......
│      └─...
├─lib/
│   ├─cmake
│   │  └─cuvs
│   │      ├─cuvs-config.cmake
│   │      ├─cuvs-targets.cmake
│   │      └─......
│   ├─libcuvs.so
│   └─libcuvs_c.so
  • 目录 include/cuvs/ 包含了mcVS所有的头文件

  • 目录 lib/cmake/cuvs/ 包含了cmake config文件

  • 文件 lib/libfcuvs.solib/libcuvs_c.so 是动态链接库

2.2. 离线镜像文件部署方式

执行以下命令进入容器:

sudo docker load -i mcvs_mcdf_25.12_macax.y.z.n_py312_ubuntu24.04_amd64.tar.gz
sudo docker run -it --device=/dev/mxcd --device=/dev/dri --group-add video mxcr.io/dc-release/c500/mcvs_mcdf_25.12:x.y.z.n-ubuntu2404-x86_64 /bin/bash

2.3. 软件包安装部署方式

如果使用离线镜像文件,可以忽略本节。

2.3.1. 操作系统及依赖

mcVS 的libmcvs和mcvs 二进制包支持的操作系统及相关依赖,参见表 2.2

表 2.2 mcVS支持的操作系统及相关依赖

操作系统

相关依赖

说明

Ubuntu 20.04

依赖版本的MXMACA Runtime

  • MXMACA Runtime依赖的详细版本,参见《MXMAP发布说明》

  • 如果需要使用mcVS Python的扩展包,请使用对应的Python版本

cu-bridge

Python3.12

Ubuntu 22.04

同Ubuntu 20.04

Ubuntu 24.04

同Ubuntu 20.04

请参考 cu-bridge使用指南安装并配置cu-bridge环境,建议安装到 /opt/maca/tools/ 目录下。

可以检查以下文件是否存在,并确认cu-bridge环境是否准备完毕:

/opt/maca/tools/cu-bridge/bin/cucc
/opt/maca/tools/cu-bridge/tools/cmake_maca

2.3.2. mcVS安装

Python wheel包

在支持的Linux系统中,可以使用pip进行安装(这里以python3.10环境为例)。

  1. 安装librmm和rmmx

$ pip install librmm-x.y.z.n+bu.v.w.m-py3-none-linux_x86_64.whl
$ pip install rmmx-x.y.z.n+bu.v.w.m-cp310-cp310-linux_x86_64.whl
  1. 安装libraft和pylibraft

$ pip install libraft-x.y.z.n+bu.v.w.m-py3-none-linux_x86_64.whl
$ pip install pylibraft-x.y.z.n+bu.v.w.m-cp310-cp310-linux_x86_64.whl
  1. 安装libmcvs和mcvs

$ pip install libmcvs-x.y.z.n+bu.v.w.m-py3-none-linux_x86_64.whl
$ pip install mcvs-x.y.z.n+bu.v.w.m-cp310-cp310-linux_x86_64.whl
  1. 安装mcpy

$ pip install mcpy-x.y.z.n+bu.v.w.m-cp310-cp310-linux_x86_64.whl

2.4. mcVS使用

mcVS提供C++和Python两种语言的接口,mcVS的C++/Python接口和cuVS提供的接口完全一致。

2.4.1. 环境变量设置

mcVS 编译运行依赖如下环境变量:

  • MACA_PATH : 指向 MXMACA 包的安装路径, 比如 /opt/maca

  • CUDA_PATH : 指向 cu-bridge 安装路径, 比如 $MACA_PATH/tools/cu-bridge

2.4.2. 代码示例(C++)

使用C++进行brute_force索引完成向量添加、搜索,代码brute_force_example.cu示例如下:

#include <raft/core/resources.hpp>
#include <raft/core/device_mdspan.hpp>
#include <raft/core/device_resources.hpp>
#include <cuvs/neighbors/brute_force.hpp>
#include <rmm/device_uvector.hpp>

#include <algorithm>
#include <iostream>
#include <numeric>
#include <random>
#include <vector>

using namespace cuvs::neighbors;

int main() {
  raft::device_resources res;
  int64_t n_rows = 10, dim = 4, n_queries = 2, k = 3;

  // 1. Generate deterministic data on CPU
  std::vector<float> h_dataset(n_rows * dim);
  std::vector<float> h_queries(n_queries * dim);

  std::mt19937 gen(42); // Fixed seed
  std::uniform_real_distribution<float> dis(0.0, 1.0);
  auto rand_func = [&]() { return dis(gen); };

  std::generate(h_dataset.begin(), h_dataset.end(), rand_func);
  std::generate(h_queries.begin(), h_queries.end(), rand_func);

  // 2. Move data to GPU
  rmm::device_uvector<float> d_dataset(n_rows * dim, res.get_stream());
  rmm::device_uvector<float> d_queries(n_queries * dim, res.get_stream());
  raft::update_device(d_dataset.data(), h_dataset.data(), h_dataset.size(), res.get_stream());
  raft::update_device(d_queries.data(), h_queries.data(), h_queries.size(), res.get_stream());

  // 3. Setup views and Search
  auto dataset_view = raft::make_device_matrix_view<const float, int64_t>(d_dataset.data(), n_rows, dim);
  auto queries_view = raft::make_device_matrix_view<float, int64_t>(d_queries.data(), n_queries, dim);

  rmm::device_uvector<int64_t> d_indices(n_queries * k, res.get_stream());
  rmm::device_uvector<float> d_distances(n_queries * k, res.get_stream());
  auto out_idx_view = raft::make_device_matrix_view<int64_t, int64_t>(d_indices.data(), n_queries, k);
  auto out_dist_view = raft::make_device_matrix_view<float, int64_t>(d_distances.data(), n_queries, k);

  brute_force::index_params idx_p;
  idx_p.metric = cuvs::distance::DistanceType::L2Expanded;
  auto index = brute_force::build(res, idx_p, dataset_view);
  brute_force::search(res, brute_force::search_params{}, index, queries_view, out_idx_view, out_dist_view);

  // 4. Copy results back to CPU to print
  std::vector<int64_t> h_indices(n_queries * k);
  std::vector<float> h_distances(n_queries * k);
  raft::update_host(h_indices.data(), d_indices.data(), d_indices.size(), res.get_stream());
  raft::update_host(h_distances.data(), d_distances.data(), d_distances.size(), res.get_stream());
  res.sync_stream();

  // 5. Print results
  for (int i = 0; i < n_queries; ++i) {
      std::cout << "Query " << i << ":\n";
      for (int j = 0; j < k; ++j) {
          std::cout << "  Neighbor " << j << ": Index " << h_indices[i * k + j]
                    << ", Distance " << h_distances[i * k + j] << "\n";
      }
  }

  return 0;
}

如果需要在曦云系列GPU上编译并运行上述示例,需要使用mxcc进行编译。

$ export CUDA_PATH=$MACA_PATH/tools/cu-bridge
$ export PY_SITE_PKG=<path/to/site_pakages>
$ mxcc -o brute_force_example brute_force_example.cu \
    -std=c++17 \
    -DLIBCUDACXX_ENABLE_EXPERIMENTAL_MEMORY_RESOURCE \
    -I${CUDA_PATH}/include/cccl \
    -I${CUDA_PATH}/include \
    -I${MACA_PATH}/tools/cu-bridge/include \
    -I${MACA_PATH}/include/mcblas \
    -I${MACA_PATH}/include/mcsolver \
    -I${MACA_PATH}/include/mcsparse \
    -I${PY_SITE_PKG}/libcuvs/include \
    -I${PY_SITE_PKG}/libraft/include \
    -I${PY_SITE_PKG}/librmm/include \
    -L${PY_SITE_PKG}/libcuvs/lib \
    -L${PY_SITE_PKG}/librmm/lib \
    -lcuvs -lrmm -lruntime_cu

编译成功后,运行 brute_force_example 程序,可以得到如下的输出:

$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PY_SITE_PKG/libcuvs/lib:$LD_LIBRARY_PATH:$PY_SITE_PKG/librmm/lib ./ brute_force_example
Query 0:
  Neighbor 0: Index 2, Distance 0.213012
  Neighbor 1: Index 8, Distance 0.289476
  Neighbor 2: Index 6, Distance 0.346261
Query 1:
  Neighbor 0: Index 7, Distance 0.193986
  Neighbor 1: Index 8, Distance 0.207296
  Neighbor 2: Index 2, Distance 0.359122

2.4.3. 代码示例(Python)

使用Python进行IVFFlat索引完成向量添加、搜索,代码示例如下:

import cupy as cp
import numpy as np
from cuvs.neighbors import ivf_flat

d = 4
nb = 100
nq = 10
topk = 3

xb = cp.asarray(np.random.rand(nb, d).astype(np.float32))
xq = cp.asarray(np.random.rand(nq, d).astype(np.float32))

build_params = ivf_flat.IndexParams(n_lists=2)
index = ivf_flat.build(build_params, xb)

search_params = ivf_flat.SearchParams(n_probes=2)

distances, neighbors = ivf_flat.search(
    search_params,
    index,
    xq,
    topk
)

neighbors_cpu = cp.asnumpy(neighbors)

for i in range(nq):
    print(f"query {i}: {neighbors_cpu[i]}")

使用Python来运行上述脚本,可以得到类似如下的输出:

$ python example.py
query 0: [30  1 81]
query 1: [14  0 52]
query 2: [69 22 14]
query 3: [43 25  8]
query 4: [31 79 83]
query 5: [65 55 84]
query 6: [59  0 99]
query 7: [12 90 68]
query 8: [53 60 73]
query 9: [94  4 73]

2.5. 已知问题

  • 向量搜索的召回率在不同环境有差异是正常现象, 因为浮点数计算不满足结合律

  • BruteForce 索引类型的 filter 功能在部分场景下结果不正确,原因是依赖的cusparse接口还在完善中