下载
中文
注册

快速入门

本章节提供了一个简单的样例,帮助用户快速体验运用mxIndex进行检索的流程。

假定有业务需要使用到暴搜(Flat)算法,底库大小为100w,维度是512维,需要检索的向量是128个,topk是10,编写一个Demo调用Index接口大致步骤如下:

  1. 已完成mxIndex的安装部署。

    安装部署完成后,再检查以下环境变量是否都配置完成;根据个人安装目录不同,环境变量路径不同,以下为本次配置的环境变量:

    export LD_LIBRARY_PATH=/opt/OpenBLAS/lib:$LD_LIBRARY_PATH
    export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
    export LD_LIBRARY_PATH=/home/work/FeatureRetrieval/mxIndex/host/lib:$LD_LIBRARY_PATH
    export LD_LIBRARY_PATH=/usr/local/faiss/faiss1.7.1/lib/:$LD_LIBRARY_PATH
    export MX_INDEX_MODELPATH=/home/work/FeatureRetrieval/mxIndex/modelpath/
    source /usr/local/Ascend/ascend-toolkit/set_env.sh
  2. 生成Flat和AICPU算子。
    1. 按照如下方法生成Flat算子:

      用法

      python3 flat_generate_model.py -d <dim> --cores <core_num> -p <process_id> -pool <pool_size> -t <npu_type>

      参数名称

      <dim>:特征向量维度D。

      <core_num>:昇腾AI处理器AI Core的个数,默认值为“2”。不指定该值时,根据<npu_type>配置:当npu_type配置为310时,<core_num>配置为2;当npu_type配置为310P时,<core_num>配置为8。

      <process_id>:批量生成算子多进程调度的进程ID,默认值为“0”,无需设置。

      <pool_size>:批量生成算子多进程调度的进程池大小,默认值为“10”

      <npu_type>:硬件形态,当前<npu_type>支持Atlas 200/300/500 推理产品以及Atlas 推理系列产品,取值范围分别为:310、310P,默认为“310”

      说明

      执行此命令,用户可以得到一组距离计算算子模型文件,用户需要自行修改命令中参数。

      约束说明

      • dim ∈ {32, 64, 128, 256, 384, 512, 1024, 2048}(2048只支持L2距离)
      • 0 ≤ pool_size ≤ 32
    2. 按照如下方法生成AICPU算子:

      用法

      python3 aicpu_generate_model.py --cores <core_num> -p <process_id> -t <npu_type>

      参数名称

      <core_num>:昇腾AI处理器AI Core的个数,默认为“2”。(预留参数,暂不使用)

      <process_id>:批量生成算子多进程调度的进程ID,默认值为“0”,无需设置。

      <npu_type>:硬件形态,当前<npu_type>支持Atlas 200/300/500 推理产品以及Atlas 推理系列产品,取值范围分别为:310、310P,默认为“310”

      说明

      执行此命令,用户可以得到一组算子模型文件。

      AICPU算子模型文件只需生成一次,会全部生成所有算法的算子。

  3. 构造demo,过程包括:
    1. Demo中引入暴搜(Flat)的头文件。
    2. 构造底库向量数据,这里用随机数生成代替。
    3. 归一化底库数据。
    4. 初始化Flat的Index。
    5. 调用接口添加底库。
    6. 调用接口进行检索。

    demo.cpp代码如下:

    #include <faiss/ascend/AscendIndexFlat.h>
    #include <sys/time.h>
    #include <random>
    // 获取当前时间
    inline double GetMillisecs()
    {
        struct timeval tv = {0, 0};
        gettimeofday(&tv, nullptr);
        return tv.tv_sec * 1e3 + tv.tv_usec * 1e-3;
    }
    // 使用随机数构造底库数据
    void Generate(size_t ntotal, std::vector<float> &data, int seed = 5678)
    {
        std::default_random_engine e(seed);
        std::uniform_real_distribution<float> rCode(0.0f, 1.0f);
        data.resize(ntotal);
        for (size_t i = 0; i < ntotal; ++i) {
            data[i] = static_cast<float>(255 * rCode(e) - 128);
        }
    }
    // 底库数据归一化
    void Norm(size_t total, std::vector<float> &data, int dim)
    {
        for (size_t i = 0; i < total; ++i) {
            float mod = 0;
            for (int j = 0; j < dim; ++j) {
                mod += data[i * dim + j] * data[i * dim + j];
            }
            mod = sqrt(mod);
            for (int j = 0; j < dim; ++j) {
                data[i * dim + j] = data[i * dim + j] / mod;
            }
        }
    }
    int main()
    {
        int dim = 512;
        std::vector<int> device{0};
        size_t ntotal = 1000000;
        int searchnum = 128;
        std::vector<float> features(dim * ntotal);
        int64_t resourceSize = static_cast<int64_t>(1024) * 1024 * 1024;
        int topK = 10;
        printf("Generating random numbers start!\r\n");
        Generate(ntotal, features);
        Norm(ntotal, features, dim);
        try {
            // index初始化
            faiss::ascend::AscendIndexFlatConfig conf(device, resourceSize);
            auto metricType = faiss::METRIC_INNER_PRODUCT;
            faiss::ascend::AscendIndexFlat index(dim, metricType, conf);
            index.reset();
            // add底库
            printf("add start!\r\n");
            index.add(ntotal, features.data());
            size_t tmpTotal = index.getBaseSize(0);
            if (tmpTotal != ntotal) {
                printf("------- Error -----------------\n");
                return -1;
            }
            // search
            printf("search start!\r\n");
            int loopTimes = 1;
            std::vector<float> dist(searchnum * topK, 0);
            std::vector<faiss::Index::idx_t> label(searchnum * topK, 0);
            auto ts = GetMillisecs();
            for (int i = 0; i < loopTimes; i++) {
                index.search(searchnum, features.data(), topK, dist.data(), label.data());
            }
            auto te = GetMillisecs();
            printf("search end!\r\n");
            printf("flat, base:%lu, dim:%d, searchnum:%d, topk:%d, duration:%.3lf, QPS:%.4f\n",
                ntotal,
                dim,
                searchnum,
                topK,
                te - ts,
                1000 * searchnum * loopTimes / (te - ts));
            return 0;
        } catch(...) {
            printf("Exception caught! \r\n");
            return -1;
        }
    }
  4. 编译demo.cpp
    # XXX替换为环境上index组件的安装目录
    g++ --std=c++11 -fPIE -fstack-protector-all -Wall -D_FORTIFY_SOURCE=2 -O3  -Wl,-z,relro,-z,now,-z,noexecstack -s -pie \
    -o demo demo.cpp \
    -I/home/XXX/mxIndex/include \
    -I/usr/local/faiss/faiss1.7.1/include \
    -I/usr/local/Ascend/driver/include \
    -I/opt/OpenBLAS/include \
    -L/home/XXX/mxIndex/host/lib \
    -L/usr/local/faiss/faiss1.7.1/lib \
    -L/usr/local/Ascend/driver/lib64 \
    -L/usr/local/Ascend/driver/lib64/driver \
    -L/opt/OpenBLAS/lib/include \
    -L/usr/local/Ascend/ascend-toolkit/latest/lib64 \
    -lfaiss -lascendfaiss -lopenblas -lc_sec -lascendcl -lascend_hal -lascendsearch -lock_hmm
  5. 运行Demo,显示search end!即表示Demo运行成功。
    ./demo
    ...
    search end!