未验证 提交 1042f2e1 编写于 作者: O op-hunter 提交者: GitHub

Remove useless index (#3157)

* update change log and make clang-format
Signed-off-by: Ncmli <chengming.li@zilliz.com>

* remove sq8nr_nm
Signed-off-by: Nsahuang <xiaohai.xu@zilliz.com>

* update changelog
Signed-off-by: Ncmli <chengming.li@zilliz.com>
Co-authored-by: Ncmli <chengming.li@zilliz.com>
Co-authored-by: Nsahuang <xiaohai.xu@zilliz.com>
Co-authored-by: Nshengjun.li <shengjun.li@zilliz.com>
上级 59640954
......@@ -55,11 +55,8 @@ Please mark all changes in change log and use the issue from GitHub
- \#2572 Support structured data index
- \#2585 Support IVF_PQ on GPU with using metric_type IP
- \#2689 Construct Knowhere Index Without Data
- \#2798 hnsw-sq8 support
- \#2802 Add new index: IVFSQ8NR
- \#2834 Add C++ sdk support 4 hnsw_sq8nr
- \#2940 Add option to build.sh for cuda arch
- \#3132 Refine the implementation of hnsw in faiss and add support for hnsw-flat, hnsw-pq and hnsw-sq8 based on faiss
- \#3132 Refine the implementation of hnsw in faiss and add support for hnsw-flat, hnsw-pq and hnsw-sq8
## Improvement
- \#2543 Remove secondary_path related code
......
......@@ -61,8 +61,7 @@ SetSnapshotIndex(const std::string& collection_name, const std::string& field_na
json[engine::PARAM_INDEX_EXTRA_PARAMS] = index_info.extra_params_;
index_element->SetParams(json);
if (index_info.index_name_ == knowhere::IndexEnum::INDEX_FAISS_IVFSQ8NR ||
index_info.index_name_ == knowhere::IndexEnum::INDEX_HNSW_SQ8NM) {
if (index_info.index_name_ == knowhere::IndexEnum::INDEX_RHNSWSQ) {
auto compress_element = std::make_shared<snapshot::FieldElement>(
ss->GetCollectionId(), field->GetID(), DEFAULT_INDEX_COMPRESS_NAME,
milvus::engine::FieldElementType::FET_COMPRESS_SQ8);
......
......@@ -715,8 +715,7 @@ ExecutionEngineImpl::CreateSnapshotIndexFile(AddSegmentFileOperation& operation,
// create snapshot compress file
std::string index_name = index_element->GetName();
if (index_name == knowhere::IndexEnum::INDEX_FAISS_IVFSQ8NR ||
index_name == knowhere::IndexEnum::INDEX_HNSW_SQ8NM) {
if (index_name == knowhere::IndexEnum::INDEX_RHNSWSQ) {
auto compress_visitor = field_visitor->GetElementVisitor(engine::FieldElementType::FET_COMPRESS_SQ8);
if (compress_visitor == nullptr) {
return Status(DB_ERROR,
......
......@@ -64,6 +64,7 @@ set(vector_index_srcs
knowhere/index/vector_index/VecIndexFactory.cpp
knowhere/index/vector_index/IndexAnnoy.cpp
knowhere/index/vector_index/IndexRHNSW.cpp
knowhere/index/vector_index/IndexHNSW.cpp
knowhere/index/vector_index/IndexRHNSWFlat.cpp
knowhere/index/vector_index/IndexRHNSWSQ.cpp
knowhere/index/vector_index/IndexRHNSWPQ.cpp
......@@ -72,10 +73,7 @@ set(vector_index_srcs
set(vector_offset_index_srcs
knowhere/index/vector_offset_index/OffsetBaseIndex.cpp
knowhere/index/vector_offset_index/IndexIVF_NM.cpp
knowhere/index/vector_offset_index/IndexIVFSQNR_NM.cpp
knowhere/index/vector_offset_index/IndexHNSW_NM.cpp
knowhere/index/vector_offset_index/IndexNSG_NM.cpp
knowhere/index/vector_offset_index/IndexHNSW_SQ8NM.cpp
)
if (MILVUS_SUPPORT_SPTAG)
......@@ -125,7 +123,6 @@ if (MILVUS_GPU_VERSION)
set(vector_offset_index_srcs ${vector_offset_index_srcs}
knowhere/index/vector_offset_index/gpu/IndexGPUIVF_NM.cpp
knowhere/index/vector_offset_index/gpu/IndexGPUIVFSQNR_NM.cpp
)
endif ()
......
......@@ -24,7 +24,6 @@ const char* INDEX_FAISS_IDMAP = "FLAT";
const char* INDEX_FAISS_IVFFLAT = "IVF_FLAT";
const char* INDEX_FAISS_IVFPQ = "IVF_PQ";
const char* INDEX_FAISS_IVFSQ8 = "IVF_SQ8";
const char* INDEX_FAISS_IVFSQ8NR = "IVF_SQ8NR";
const char* INDEX_FAISS_IVFSQ8H = "IVF_SQ8_HYBRID";
const char* INDEX_FAISS_BIN_IDMAP = "BIN_FLAT";
const char* INDEX_FAISS_BIN_IVFFLAT = "BIN_IVF_FLAT";
......@@ -38,7 +37,6 @@ const char* INDEX_RHNSWFlat = "RHNSW_FLAT";
const char* INDEX_RHNSWPQ = "RHNSW_PQ";
const char* INDEX_RHNSWSQ = "RHNSW_SQ";
const char* INDEX_ANNOY = "ANNOY";
const char* INDEX_HNSW_SQ8NM = "HNSW_SQ8NM";
} // namespace IndexEnum
} // namespace knowhere
......
......@@ -35,8 +35,6 @@ enum class OldIndexType {
SPTAG_BKT_RNT_CPU,
HNSW,
ANNOY,
FAISS_IVFSQ8NR,
HNSW_SQ8NM,
RHNSW_FLAT,
RHNSW_PQ,
RHNSW_SQ,
......@@ -53,7 +51,6 @@ extern const char* INDEX_FAISS_IDMAP;
extern const char* INDEX_FAISS_IVFFLAT;
extern const char* INDEX_FAISS_IVFPQ;
extern const char* INDEX_FAISS_IVFSQ8;
extern const char* INDEX_FAISS_IVFSQ8NR;
extern const char* INDEX_FAISS_IVFSQ8H;
extern const char* INDEX_FAISS_BIN_IDMAP;
extern const char* INDEX_FAISS_BIN_IVFFLAT;
......@@ -67,7 +64,6 @@ extern const char* INDEX_RHNSWFlat;
extern const char* INDEX_RHNSWPQ;
extern const char* INDEX_RHNSWSQ;
extern const char* INDEX_ANNOY;
extern const char* INDEX_HNSW_SQ8NM;
} // namespace IndexEnum
enum class IndexMode { MODE_CPU = 0, MODE_GPU = 1 };
......
......@@ -131,14 +131,6 @@ IVFSQConfAdapter::CheckTrain(Config& oricfg, const IndexMode mode) {
return IVFConfAdapter::CheckTrain(oricfg, mode);
}
bool
IVFSQ8NRConfAdapter::CheckTrain(Config& oricfg, const IndexMode mode) {
static int64_t DEFAULT_NBITS = 8;
oricfg[knowhere::IndexParams::nbits] = DEFAULT_NBITS;
return IVFConfAdapter::CheckTrain(oricfg, mode);
}
bool
IVFPQConfAdapter::CheckTrain(Config& oricfg, const IndexMode mode) {
static int64_t DEFAULT_NBITS = 8;
......@@ -257,29 +249,6 @@ HNSWConfAdapter::CheckSearch(Config& oricfg, const IndexType type, const IndexMo
return ConfAdapter::CheckSearch(oricfg, type, mode);
}
bool
HNSWSQ8NRConfAdapter::CheckTrain(Config& oricfg, const IndexMode mode) {
static int64_t MIN_EFCONSTRUCTION = 8;
static int64_t MAX_EFCONSTRUCTION = 512;
static int64_t MIN_M = 4;
static int64_t MAX_M = 64;
CheckIntByRange(knowhere::meta::ROWS, DEFAULT_MIN_ROWS, DEFAULT_MAX_ROWS);
CheckIntByRange(knowhere::IndexParams::efConstruction, MIN_EFCONSTRUCTION, MAX_EFCONSTRUCTION);
CheckIntByRange(knowhere::IndexParams::M, MIN_M, MAX_M);
return ConfAdapter::CheckTrain(oricfg, mode);
}
bool
HNSWSQ8NRConfAdapter::CheckSearch(Config& oricfg, const IndexType type, const IndexMode mode) {
static int64_t MAX_EF = 4096;
CheckIntByRange(knowhere::IndexParams::ef, oricfg[knowhere::meta::TOPK], MAX_EF);
return ConfAdapter::CheckSearch(oricfg, type, mode);
}
bool
RHNSWFlatConfAdapter::CheckTrain(Config& oricfg, const IndexMode mode) {
static int64_t MIN_EFCONSTRUCTION = 8;
......
......@@ -94,21 +94,6 @@ class ANNOYConfAdapter : public ConfAdapter {
CheckSearch(Config& oricfg, const IndexType type, const IndexMode mode) override;
};
class HNSWSQ8NRConfAdapter : public ConfAdapter {
public:
bool
CheckTrain(Config& oricfg, const IndexMode mode) override;
bool
CheckSearch(Config& oricfg, const IndexType type, const IndexMode mode) override;
};
class IVFSQ8NRConfAdapter : public IVFConfAdapter {
public:
bool
CheckTrain(Config& oricfg, const IndexMode mode) override;
};
class RHNSWFlatConfAdapter : public ConfAdapter {
public:
bool
......
......@@ -49,8 +49,6 @@ AdapterMgr::RegisterAdapter() {
#endif
REGISTER_CONF_ADAPTER(HNSWConfAdapter, IndexEnum::INDEX_HNSW, hnsw_adapter);
REGISTER_CONF_ADAPTER(ANNOYConfAdapter, IndexEnum::INDEX_ANNOY, annoy_adapter);
REGISTER_CONF_ADAPTER(HNSWSQ8NRConfAdapter, IndexEnum::INDEX_HNSW_SQ8NM, hnswsq8nr_adapter);
REGISTER_CONF_ADAPTER(IVFSQ8NRConfAdapter, IndexEnum::INDEX_FAISS_IVFSQ8NR, ivfsq8nr_adapter);
REGISTER_CONF_ADAPTER(RHNSWFlatConfAdapter, IndexEnum::INDEX_RHNSWFlat, rhnswflat_adapter);
REGISTER_CONF_ADAPTER(RHNSWPQConfAdapter, IndexEnum::INDEX_RHNSWPQ, rhnswpq_adapter);
REGISTER_CONF_ADAPTER(RHNSWSQConfAdapter, IndexEnum::INDEX_RHNSWSQ, rhnswsq_adapter);
......
......@@ -83,9 +83,9 @@ IndexHNSW::Train(const DatasetPtr& dataset_ptr, const Config& config) {
hnswlib::SpaceInterface<float>* space;
if (config[Metric::TYPE] == Metric::L2) {
space = new hnswlib_nm::L2Space(dim);
space = new hnswlib::L2Space(dim);
} else if (config[Metric::TYPE] == Metric::IP) {
space = new hnswlib_nm::InnerProductSpace(dim);
space = new hnswlib::InnerProductSpace(dim);
normalize = true;
}
index_ = std::make_shared<hnswlib::HierarchicalNSW<float>>(space, rows, config[IndexParams::M].get<int64_t>(),
......
......@@ -16,6 +16,7 @@
#include "knowhere/index/vector_index/IndexAnnoy.h"
#include "knowhere/index/vector_index/IndexBinaryIDMAP.h"
#include "knowhere/index/vector_index/IndexBinaryIVF.h"
#include "knowhere/index/vector_index/IndexHNSW.h"
#include "knowhere/index/vector_index/IndexIDMAP.h"
#include "knowhere/index/vector_index/IndexIVF.h"
#include "knowhere/index/vector_index/IndexIVFPQ.h"
......@@ -23,9 +24,6 @@
#include "knowhere/index/vector_index/IndexRHNSWFlat.h"
#include "knowhere/index/vector_index/IndexRHNSWPQ.h"
#include "knowhere/index/vector_index/IndexRHNSWSQ.h"
#include "knowhere/index/vector_offset_index/IndexHNSW_NM.h"
#include "knowhere/index/vector_offset_index/IndexHNSW_SQ8NM.h"
#include "knowhere/index/vector_offset_index/IndexIVFSQNR_NM.h"
#include "knowhere/index/vector_offset_index/IndexIVF_NM.h"
#include "knowhere/index/vector_offset_index/IndexNSG_NM.h"
......@@ -41,7 +39,6 @@
#include "knowhere/index/vector_index/gpu/IndexGPUIVFSQ.h"
#include "knowhere/index/vector_index/gpu/IndexIVFSQHybrid.h"
#include "knowhere/index/vector_index/helpers/Cloner.h"
#include "knowhere/index/vector_offset_index/gpu/IndexGPUIVFSQNR_NM.h"
#include "knowhere/index/vector_offset_index/gpu/IndexGPUIVF_NM.h"
#endif
......@@ -91,13 +88,9 @@ VecIndexFactory::CreateVecIndex(const IndexType& type, const IndexMode mode) {
return std::make_shared<knowhere::CPUSPTAGRNG>("BKT");
#endif
} else if (type == IndexEnum::INDEX_HNSW) {
return std::make_shared<knowhere::IndexHNSW_NM>();
return std::make_shared<knowhere::IndexHNSW>();
} else if (type == IndexEnum::INDEX_ANNOY) {
return std::make_shared<knowhere::IndexAnnoy>();
} else if (type == IndexEnum::INDEX_FAISS_IVFSQ8NR) {
return std::make_shared<knowhere::IVFSQNR_NM>();
} else if (type == IndexEnum::INDEX_HNSW_SQ8NM) {
return std::make_shared<knowhere::IndexHNSW_SQ8NM>();
} else if (type == IndexEnum::INDEX_RHNSWFlat) {
return std::make_shared<knowhere::IndexRHNSWFlat>();
} else if (type == IndexEnum::INDEX_RHNSWPQ) {
......
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License
#include <faiss/IndexFlat.h>
#include <faiss/IndexScalarQuantizer.h>
#include <faiss/gpu/GpuCloner.h>
#include <faiss/index_factory.h>
#include <memory>
#include <string>
#include "knowhere/common/Exception.h"
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
#include "knowhere/index/vector_index/gpu/IndexGPUIVFSQNR.h"
#include "knowhere/index/vector_index/helpers/IndexParameter.h"
#include "knowhere/index/vector_offset_index/IndexIVFSQNR_NM.h"
namespace milvus {
namespace knowhere {
void
GPUIVFSQNR::Train(const DatasetPtr& dataset_ptr, const Config& config) {
GET_TENSOR_DATA_DIM(dataset_ptr)
gpu_id_ = config[knowhere::meta::DEVICEID];
// std::stringstream index_type;
// index_type << "IVF" << config[IndexParams::nlist] << ","
// << "SQ" << config[IndexParams::nbits];
// faiss::MetricType metric_type = GetMetricType(config[Metric::TYPE].get<std::string>());
// auto build_index = faiss::index_factory(dim, index_type.str().c_str(), metric_type);
faiss::MetricType metric_type = GetMetricType(config[Metric::TYPE].get<std::string>());
faiss::Index* coarse_quantizer = new faiss::IndexFlat(dim, metric_type);
auto build_index =
new faiss::IndexIVFScalarQuantizer(coarse_quantizer, dim, config[IndexParams::nlist].get<int64_t>(),
faiss::QuantizerType::QT_8bit, metric_type, false);
auto gpu_res = FaissGpuResourceMgr::GetInstance().GetRes(gpu_id_);
if (gpu_res != nullptr) {
ResScope rs(gpu_res, gpu_id_, true);
auto device_index = faiss::gpu::index_cpu_to_gpu(gpu_res->faiss_res.get(), gpu_id_, build_index);
device_index->train(rows, (float*)p_data);
index_.reset(device_index);
res_ = gpu_res;
} else {
KNOWHERE_THROW_MSG("Build IVFSQ can't get gpu resource");
}
}
VecIndexPtr
GPUIVFSQNR::CopyGpuToCpu(const Config& config) {
std::lock_guard<std::mutex> lk(mutex_);
faiss::Index* device_index = index_.get();
faiss::Index* host_index = faiss::gpu::index_gpu_to_cpu(device_index);
std::shared_ptr<faiss::Index> new_index;
new_index.reset(host_index);
return std::make_shared<IVFSQNR_NM>(new_index);
}
} // namespace knowhere
} // namespace milvus
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License
#pragma once
#include <memory>
#include <utility>
#include "knowhere/index/vector_index/gpu/IndexGPUIVF.h"
namespace milvus {
namespace knowhere {
class GPUIVFSQNR : public GPUIVF {
public:
explicit GPUIVFSQNR(const int& device_id) : GPUIVF(device_id) {
index_type_ = IndexEnum::INDEX_FAISS_IVFSQ8;
}
explicit GPUIVFSQNR(std::shared_ptr<faiss::Index> index, const int64_t device_id, ResPtr& res)
: GPUIVF(std::move(index), device_id, res) {
index_type_ = IndexEnum::INDEX_FAISS_IVFSQ8;
}
void
Train(const DatasetPtr&, const Config&) override;
VecIndexPtr
CopyGpuToCpu(const Config&) override;
};
using GPUIVFSQNRPtr = std::shared_ptr<GPUIVFSQNR>;
} // namespace knowhere
} // namespace milvus
......@@ -19,7 +19,6 @@
#include "knowhere/index/vector_index/gpu/GPUIndex.h"
#include "knowhere/index/vector_index/gpu/IndexGPUIVF.h"
#include "knowhere/index/vector_index/gpu/IndexIVFSQHybrid.h"
#include "knowhere/index/vector_offset_index/IndexIVFSQNR_NM.h"
#include "knowhere/index/vector_offset_index/IndexIVF_NM.h"
namespace milvus {
......@@ -57,8 +56,6 @@ CopyCpuToGpu(const VecIndexPtr& index, const int64_t device_id, const Config& co
result = device_index->CopyGpuToGpu(device_id, config);
} else if (auto cpu_index = std::dynamic_pointer_cast<IVFSQ>(index)) {
result = cpu_index->CopyCpuToGpu(device_id, config);
} else if (auto cpu_index = std::dynamic_pointer_cast<IVFSQNR_NM>(index)) {
result = cpu_index->CopyCpuToGpu(device_id, config);
} else if (auto cpu_index = std::dynamic_pointer_cast<IVFPQ>(index)) {
result = cpu_index->CopyCpuToGpu(device_id, config);
} else if (auto cpu_index = std::dynamic_pointer_cast<IVF>(index)) {
......
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License.
#include "knowhere/index/vector_offset_index/IndexHNSW_NM.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <utility>
#include <vector>
#include "faiss/BuilderSuspend.h"
#include "hnswlib/space_ip.h"
#include "hnswlib/space_l2.h"
#include "knowhere/common/Exception.h"
#include "knowhere/common/Log.h"
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
#include "knowhere/index/vector_index/helpers/FaissIO.h"
namespace milvus {
namespace knowhere {
// void
// normalize_vector(float* data, float* norm_array, size_t dim) {
// float norm = 0.0f;
// for (int i = 0; i < dim; i++) norm += data[i] * data[i];
// norm = 1.0f / (sqrtf(norm) + 1e-30f);
// for (int i = 0; i < dim; i++) norm_array[i] = data[i] * norm;
// }
BinarySet
IndexHNSW_NM::Serialize(const Config& config) {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize or trained");
}
try {
MemoryIOWriter writer;
index_->saveIndex(writer);
std::shared_ptr<uint8_t[]> data(writer.data_);
BinarySet res_set;
res_set.Append("HNSW", data, writer.rp);
return res_set;
} catch (std::exception& e) {
KNOWHERE_THROW_MSG(e.what());
}
}
void
IndexHNSW_NM::Load(const BinarySet& index_binary) {
try {
auto binary = index_binary.GetByName("HNSW");
MemoryIOReader reader;
reader.total = binary->size;
reader.data_ = binary->data.get();
hnswlib_nm::SpaceInterface<float>* space;
index_ = std::make_shared<hnswlib_nm::HierarchicalNSW_NM<float>>(space);
index_->loadIndex(reader);
normalize = (index_->metric_type_ == 1); // 1 == InnerProduct
data_ = index_binary.GetByName(RAW_DATA)->data;
} catch (std::exception& e) {
KNOWHERE_THROW_MSG(e.what());
}
}
void
IndexHNSW_NM::Train(const DatasetPtr& dataset_ptr, const Config& config) {
try {
int64_t dim = dataset_ptr->Get<int64_t>(meta::DIM);
int64_t rows = dataset_ptr->Get<int64_t>(meta::ROWS);
hnswlib_nm::SpaceInterface<float>* space;
if (config[Metric::TYPE] == Metric::L2) {
space = new hnswlib_nm::L2Space(dim);
} else if (config[Metric::TYPE] == Metric::IP) {
space = new hnswlib_nm::InnerProductSpace(dim);
normalize = true;
}
index_ = std::make_shared<hnswlib_nm::HierarchicalNSW_NM<float>>(
space, rows, config[IndexParams::M].get<int64_t>(), config[IndexParams::efConstruction].get<int64_t>());
} catch (std::exception& e) {
KNOWHERE_THROW_MSG(e.what());
}
}
void
IndexHNSW_NM::Add(const DatasetPtr& dataset_ptr, const Config& config) {
// It will not call Query() just after Add()
// So, not to set 'data_' is allowed.
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize");
}
std::lock_guard<std::mutex> lk(mutex_);
GET_TENSOR_DATA_ID(dataset_ptr)
auto base = index_->getCurrentElementCount();
auto pp_data = const_cast<void*>(p_data);
index_->addPoint(pp_data, p_ids[0], base, 0);
#pragma omp parallel for
for (int i = 1; i < rows; ++i) {
faiss::BuilderSuspend::check_wait();
index_->addPoint(pp_data, p_ids[i], base, i);
}
}
DatasetPtr
IndexHNSW_NM::Query(const DatasetPtr& dataset_ptr, const Config& config) {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize or trained");
}
GET_TENSOR_DATA_DIM(dataset_ptr)
size_t k = config[meta::TOPK].get<int64_t>();
size_t id_size = sizeof(int64_t) * k;
size_t dist_size = sizeof(float) * k;
auto p_id = (int64_t*)malloc(id_size * rows);
auto p_dist = (float*)malloc(dist_size * rows);
index_->setEf(config[IndexParams::ef]);
using P = std::pair<float, int64_t>;
auto compare = [](const P& v1, const P& v2) { return v1.first < v2.first; };
faiss::ConcurrentBitsetPtr blacklist = GetBlacklist();
#pragma omp parallel for
for (unsigned int i = 0; i < rows; ++i) {
std::vector<P> ret;
const float* single_query = (float*)p_data + i * dim;
ret = index_->searchKnn_NM((void*)single_query, k, compare, blacklist, (float*)(data_.get()));
while (ret.size() < k) {
ret.emplace_back(std::make_pair(-1, -1));
}
std::vector<float> dist;
std::vector<int64_t> ids;
if (normalize) {
std::transform(ret.begin(), ret.end(), std::back_inserter(dist),
[](const std::pair<float, int64_t>& e) { return float(1 - e.first); });
} else {
std::transform(ret.begin(), ret.end(), std::back_inserter(dist),
[](const std::pair<float, int64_t>& e) { return e.first; });
}
std::transform(ret.begin(), ret.end(), std::back_inserter(ids),
[](const std::pair<float, int64_t>& e) { return e.second; });
memcpy(p_dist + i * k, dist.data(), dist_size);
memcpy(p_id + i * k, ids.data(), id_size);
}
auto ret_ds = std::make_shared<Dataset>();
ret_ds->Set(meta::IDS, p_id);
ret_ds->Set(meta::DISTANCE, p_dist);
return ret_ds;
}
int64_t
IndexHNSW_NM::Count() {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize");
}
return index_->cur_element_count;
}
int64_t
IndexHNSW_NM::Dim() {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize");
}
return (*(size_t*)index_->dist_func_param_);
}
void
IndexHNSW_NM::UpdateIndexSize() {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize");
}
index_size_ = index_->cal_size() + Dim() * Count() * sizeof(float);
}
} // namespace knowhere
} // namespace milvus
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License.
#pragma once
#include <memory>
#include <mutex>
#include "hnswlib/hnswalg_nm.h"
#include "hnswlib/hnswlib_nm.h"
#include "knowhere/common/Exception.h"
#include "knowhere/index/vector_index/VecIndex.h"
namespace milvus {
namespace knowhere {
class IndexHNSW_NM : public VecIndex {
public:
IndexHNSW_NM() {
index_type_ = IndexEnum::INDEX_HNSW;
}
BinarySet
Serialize(const Config& config = Config()) override;
void
Load(const BinarySet& index_binary) override;
void
Train(const DatasetPtr& dataset_ptr, const Config& config) override;
void
Add(const DatasetPtr& dataset_ptr, const Config& config) override;
void
AddWithoutIds(const DatasetPtr&, const Config&) override {
KNOWHERE_THROW_MSG("Incremental index is not supported");
}
DatasetPtr
Query(const DatasetPtr& dataset_ptr, const Config& config) override;
int64_t
Count() override;
int64_t
Dim() override;
void
UpdateIndexSize() override;
private:
bool normalize = false;
std::mutex mutex_;
std::shared_ptr<hnswlib_nm::HierarchicalNSW_NM<float>> index_ = nullptr;
std::shared_ptr<uint8_t[]> data_ = nullptr;
};
} // namespace knowhere
} // namespace milvus
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License.
#include "knowhere/index/vector_offset_index/IndexHNSW_SQ8NM.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <utility>
#include <vector>
#include "faiss/BuilderSuspend.h"
#include "hnswlib/space_ip.h"
#include "hnswlib/space_l2.h"
#include "knowhere/common/Exception.h"
#include "knowhere/common/Log.h"
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
#include "knowhere/index/vector_index/helpers/FaissIO.h"
namespace milvus {
namespace knowhere {
BinarySet
IndexHNSW_SQ8NM::Serialize(const Config& config) {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize or trained");
}
try {
MemoryIOWriter writer;
index_->saveIndex(writer);
std::shared_ptr<uint8_t[]> data(writer.data_);
BinarySet res_set;
res_set.Append("HNSW_SQ8", data, writer.rp);
res_set.Append(SQ8_DATA, data_, Dim() * (2 * sizeof(float) + Count()));
return res_set;
} catch (std::exception& e) {
KNOWHERE_THROW_MSG(e.what());
}
}
void
IndexHNSW_SQ8NM::Load(const BinarySet& index_binary) {
try {
auto binary = index_binary.GetByName("HNSW_SQ8");
MemoryIOReader reader;
reader.total = binary->size;
reader.data_ = binary->data.get();
hnswlib_nm::SpaceInterface<float>* space;
index_ = std::make_shared<hnswlib_nm::HierarchicalNSW_NM<float>>(space);
index_->loadIndex(reader);
normalize = (index_->metric_type_ == 1); // 1 == InnerProduct
data_ = index_binary.GetByName(SQ8_DATA)->data;
index_->SetSq8((float*)(data_.get() + Dim() * Count()));
} catch (std::exception& e) {
KNOWHERE_THROW_MSG(e.what());
}
}
void
IndexHNSW_SQ8NM::Train(const DatasetPtr& dataset_ptr, const Config& config) {
try {
GET_TENSOR_DATA_DIM(dataset_ptr)
hnswlib_nm::SpaceInterface<float>* space;
if (config[Metric::TYPE] == Metric::L2) {
space = new hnswlib_nm::L2Space(dim);
} else if (config[Metric::TYPE] == Metric::IP) {
space = new hnswlib_nm::InnerProductSpace(dim);
normalize = true;
}
index_ = std::make_shared<hnswlib_nm::HierarchicalNSW_NM<float>>(
space, rows, config[IndexParams::M].get<int64_t>(), config[IndexParams::efConstruction].get<int64_t>());
auto data_space = new uint8_t[dim * (rows + 2 * sizeof(float))];
index_->sq_train(rows, (const float*)p_data, data_space);
data_ = std::shared_ptr<uint8_t[]>(data_space);
} catch (std::exception& e) {
KNOWHERE_THROW_MSG(e.what());
}
}
void
IndexHNSW_SQ8NM::Add(const DatasetPtr& dataset_ptr, const Config& config) {
// It will not call Query() just after Add()
// So, not to set 'data_' is allowed.
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize");
}
std::lock_guard<std::mutex> lk(mutex_);
GET_TENSOR_DATA_ID(dataset_ptr)
auto base = index_->getCurrentElementCount();
auto pp_data = const_cast<void*>(p_data);
index_->addPoint(pp_data, p_ids[0], base, 0);
#pragma omp parallel for
for (int i = 1; i < rows; ++i) {
faiss::BuilderSuspend::check_wait();
index_->addPoint(pp_data, p_ids[i], base, i);
}
}
DatasetPtr
IndexHNSW_SQ8NM::Query(const DatasetPtr& dataset_ptr, const Config& config) {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize or trained");
}
GET_TENSOR_DATA_DIM(dataset_ptr)
size_t k = config[meta::TOPK].get<int64_t>();
size_t id_size = sizeof(int64_t) * k;
size_t dist_size = sizeof(float) * k;
auto p_id = (int64_t*)malloc(id_size * rows);
auto p_dist = (float*)malloc(dist_size * rows);
index_->setEf(config[IndexParams::ef]);
using P = std::pair<float, int64_t>;
auto compare = [](const P& v1, const P& v2) { return v1.first < v2.first; };
faiss::ConcurrentBitsetPtr blacklist = GetBlacklist();
#pragma omp parallel for
for (unsigned int i = 0; i < rows; ++i) {
std::vector<P> ret;
const float* single_query = (float*)p_data + i * dim;
ret = index_->searchKnn_NM((void*)single_query, k, compare, blacklist, (float*)(data_.get()));
while (ret.size() < k) {
ret.emplace_back(std::make_pair(-1, -1));
}
std::vector<float> dist;
std::vector<int64_t> ids;
if (normalize) {
std::transform(ret.begin(), ret.end(), std::back_inserter(dist),
[](const std::pair<float, int64_t>& e) { return float(1 - e.first); });
} else {
std::transform(ret.begin(), ret.end(), std::back_inserter(dist),
[](const std::pair<float, int64_t>& e) { return e.first; });
}
std::transform(ret.begin(), ret.end(), std::back_inserter(ids),
[](const std::pair<float, int64_t>& e) { return e.second; });
memcpy(p_dist + i * k, dist.data(), dist_size);
memcpy(p_id + i * k, ids.data(), id_size);
}
auto ret_ds = std::make_shared<Dataset>();
ret_ds->Set(meta::IDS, p_id);
ret_ds->Set(meta::DISTANCE, p_dist);
return ret_ds;
}
int64_t
IndexHNSW_SQ8NM::Count() {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize");
}
return index_->cur_element_count;
}
int64_t
IndexHNSW_SQ8NM::Dim() {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize");
}
return (*(size_t*)index_->dist_func_param_);
}
void
IndexHNSW_SQ8NM::UpdateIndexSize() {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize");
}
index_size_ = index_->cal_size() + Dim() * (2 * sizeof(float) + Count());
}
} // namespace knowhere
} // namespace milvus
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License.
#pragma once
#include <memory>
#include <mutex>
#include "hnswlib/hnswalg_nm.h"
#include "knowhere/common/Exception.h"
#include "knowhere/index/vector_index/VecIndex.h"
namespace milvus {
namespace knowhere {
class IndexHNSW_SQ8NM : public VecIndex {
public:
IndexHNSW_SQ8NM() {
index_type_ = IndexEnum::INDEX_HNSW_SQ8NM;
}
BinarySet
Serialize(const Config& config = Config()) override;
void
Load(const BinarySet& index_binary) override;
void
Train(const DatasetPtr& dataset_ptr, const Config& config) override;
void
Add(const DatasetPtr& dataset_ptr, const Config& config) override;
void
AddWithoutIds(const DatasetPtr&, const Config&) override {
KNOWHERE_THROW_MSG("Incremental index is not supported");
}
DatasetPtr
Query(const DatasetPtr& dataset_ptr, const Config& config) override;
int64_t
Count() override;
int64_t
Dim() override;
void
UpdateIndexSize() override;
private:
bool normalize = false;
std::mutex mutex_;
std::shared_ptr<hnswlib_nm::HierarchicalNSW_NM<float>> index_ = nullptr;
std::shared_ptr<uint8_t[]> data_ = nullptr;
};
} // namespace knowhere
} // namespace milvus
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License
#include <memory>
#include <string>
#include <vector>
#ifdef MILVUS_GPU_VERSION
#include <faiss/gpu/GpuAutoTune.h>
#include <faiss/gpu/GpuCloner.h>
#endif
#include <faiss/IndexFlat.h>
#include <faiss/IndexScalarQuantizer.h>
#include <faiss/clone_index.h>
#include <faiss/impl/ScalarQuantizer.h>
#include <faiss/index_factory.h>
#include "knowhere/common/Exception.h"
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
#include "knowhere/index/vector_index/helpers/IndexParameter.h"
#include "knowhere/index/vector_offset_index/IndexIVFSQNR_NM.h"
#ifdef MILVUS_GPU_VERSION
#include "knowhere/index/vector_index/gpu/IndexGPUIVFSQ.h"
#include "knowhere/index/vector_index/helpers/FaissGpuResourceMgr.h"
#endif
namespace milvus {
namespace knowhere {
BinarySet
IVFSQNR_NM::Serialize(const Config& config) {
if (!index_ || !index_->is_trained) {
KNOWHERE_THROW_MSG("index not initialize or trained");
}
std::lock_guard<std::mutex> lk(mutex_);
BinarySet res_set = SerializeImpl(index_type_);
size_t d = index_->d;
auto ivfsq_index = dynamic_cast<faiss::IndexIVFScalarQuantizer*>(index_.get());
auto invlists = ivfsq_index->invlists;
auto rows = invlists->compute_ntotal();
auto sq = ivfsq_index->sq;
auto code_size = ivfsq_index->code_size;
auto arranged_data = new uint8_t[code_size * rows + 2 * d * sizeof(float)];
size_t curr_index = 0;
// convert arranged sq8 data to sq8 data
auto ails = dynamic_cast<faiss::ArrayInvertedLists*>(invlists);
for (size_t i = 0; i < invlists->nlist; i++) {
auto list_size = ails->ids[i].size();
for (size_t j = 0; j < list_size; j++) {
memcpy(arranged_data + code_size * ails->ids[i][j], data_.get() + code_size * (curr_index + j), code_size);
}
curr_index += list_size;
}
memcpy(arranged_data + code_size * curr_index, sq.trained.data(), 2 * d * sizeof(float));
res_set.Append(SQ8_DATA, std::shared_ptr<uint8_t[]>(arranged_data),
code_size * rows * sizeof(uint8_t) + 2 * d * sizeof(float));
return res_set;
}
void
IVFSQNR_NM::Load(const BinarySet& binary_set) {
std::lock_guard<std::mutex> lk(mutex_);
data_ = binary_set.GetByName(SQ8_DATA)->data;
LoadImpl(binary_set, index_type_);
// arrange sq8 data
auto ivfsq_index = dynamic_cast<faiss::IndexIVFScalarQuantizer*>(index_.get());
auto invlists = ivfsq_index->invlists;
auto rows = invlists->compute_ntotal();
auto sq = ivfsq_index->sq;
auto code_size = sq.code_size;
auto d = sq.d;
auto arranged_data = new uint8_t[code_size * rows + 2 * d * sizeof(float)];
prefix_sum.resize(invlists->nlist);
size_t curr_index = 0;
#ifndef MILVUS_GPU_VERSION
auto ails = dynamic_cast<faiss::ArrayInvertedLists*>(invlists);
for (size_t i = 0; i < invlists->nlist; i++) {
auto list_size = ails->ids[i].size();
for (size_t j = 0; j < list_size; j++) {
memcpy(arranged_data + code_size * (curr_index + j), data_.get() + code_size * ails->ids[i][j], code_size);
}
prefix_sum[i] = curr_index;
curr_index += list_size;
}
#else
auto rol = dynamic_cast<faiss::ReadOnlyArrayInvertedLists*>(invlists);
auto lengths = rol->readonly_length;
auto rol_ids = (const int64_t*)rol->pin_readonly_ids->data;
for (size_t i = 0; i < invlists->nlist; i++) {
auto list_size = lengths[i];
for (size_t j = 0; j < list_size; j++) {
memcpy(arranged_data + code_size * (curr_index + j), data_.get() + code_size * rol_ids[curr_index + j],
code_size);
}
prefix_sum[i] = curr_index;
curr_index += list_size;
}
#endif
memcpy(arranged_data + code_size * curr_index, sq.trained.data(), 2 * d * sizeof(float));
data_ = std::shared_ptr<uint8_t[]>(arranged_data);
}
void
IVFSQNR_NM::Train(const DatasetPtr& dataset_ptr, const Config& config) {
GET_TENSOR_DATA_DIM(dataset_ptr)
faiss::MetricType metric_type = GetMetricType(config[Metric::TYPE].get<std::string>());
faiss::Index* coarse_quantizer = new faiss::IndexFlat(dim, metric_type);
index_ = std::shared_ptr<faiss::Index>(
new faiss::IndexIVFScalarQuantizer(coarse_quantizer, dim, config[IndexParams::nlist].get<int64_t>(),
faiss::QuantizerType::QT_8bit, metric_type, false));
index_->train(rows, (float*)p_data);
}
void
IVFSQNR_NM::Add(const DatasetPtr& dataset_ptr, const Config& config) {
if (!index_ || !index_->is_trained) {
KNOWHERE_THROW_MSG("index not initialize or trained");
}
std::lock_guard<std::mutex> lk(mutex_);
GET_TENSOR_DATA_ID(dataset_ptr)
index_->add_with_ids_without_codes(rows, (float*)p_data, p_ids);
ArrangeCodes(dataset_ptr, config);
}
void
IVFSQNR_NM::AddWithoutIds(const DatasetPtr& dataset_ptr, const Config& config) {
if (!index_ || !index_->is_trained) {
KNOWHERE_THROW_MSG("index not initialize or trained");
}
std::lock_guard<std::mutex> lk(mutex_);
GET_TENSOR_DATA(dataset_ptr)
index_->add_without_codes(rows, (float*)p_data);
ArrangeCodes(dataset_ptr, config);
}
VecIndexPtr
IVFSQNR_NM::CopyCpuToGpu(const int64_t device_id, const Config& config) {
#ifdef MILVUS_GPU_VERSION
if (auto res = FaissGpuResourceMgr::GetInstance().GetRes(device_id)) {
ResScope rs(res, device_id, false);
auto gpu_index =
faiss::gpu::index_cpu_to_gpu_without_codes(res->faiss_res.get(), device_id, index_.get(), data_.get());
std::shared_ptr<faiss::Index> device_index;
device_index.reset(gpu_index);
return std::make_shared<GPUIVFSQ>(device_index, device_id, res);
} else {
KNOWHERE_THROW_MSG("CopyCpuToGpu Error, can't get gpu_resource");
}
#else
KNOWHERE_THROW_MSG("Calling IVFSQNR_NM::CopyCpuToGpu when we are using CPU version");
#endif
}
void
IVFSQNR_NM::ArrangeCodes(const DatasetPtr& dataset_ptr, const Config& config) {
GET_TENSOR_DATA_DIM(dataset_ptr)
// Construct arranged sq8 data from original data
const float* original_data = (const float*)p_data;
auto ivfsq_index = dynamic_cast<faiss::IndexIVFScalarQuantizer*>(index_.get());
auto sq = ivfsq_index->sq;
auto invlists = ivfsq_index->invlists;
auto code_size = sq.code_size;
auto arranged_data = new uint8_t[code_size * rows + 2 * dim * sizeof(float)];
std::unique_ptr<faiss::Quantizer> squant(sq.select_quantizer());
std::vector<uint8_t> one_code(code_size);
size_t curr_index = 0;
auto ails = dynamic_cast<faiss::ArrayInvertedLists*>(invlists);
for (size_t i = 0; i < invlists->nlist; i++) {
auto list_size = ails->ids[i].size();
for (size_t j = 0; j < list_size; j++) {
const float* x_j = original_data + dim * ails->ids[i][j];
memset(one_code.data(), 0, code_size);
squant->encode_vector(x_j, one_code.data());
memcpy(arranged_data + code_size * (curr_index + j), one_code.data(), code_size);
}
curr_index += list_size;
}
memcpy(arranged_data + code_size * curr_index, sq.trained.data(), 2 * dim * sizeof(float));
data_ = std::shared_ptr<uint8_t[]>(arranged_data);
}
void
IVFSQNR_NM::UpdateIndexSize() {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize");
}
auto ivfsq_index = dynamic_cast<faiss::IndexIVFScalarQuantizer*>(index_.get());
auto nb = ivfsq_index->invlists->compute_ntotal();
auto code_size = ivfsq_index->code_size;
auto nlist = ivfsq_index->nlist;
auto d = ivfsq_index->d;
// ivf codes, ivf ids, sq trained vectors and quantizer
index_size_ = nb * code_size + nb * sizeof(int64_t) + 2 * d * sizeof(float) + nlist * d * sizeof(float);
}
} // namespace knowhere
} // namespace milvus
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License
#pragma once
#include <memory>
#include <utility>
#include "knowhere/index/vector_offset_index/IndexIVF_NM.h"
namespace milvus {
namespace knowhere {
class IVFSQNR_NM : public IVF_NM {
public:
IVFSQNR_NM() : IVF_NM() {
index_type_ = IndexEnum::INDEX_FAISS_IVFSQ8NR;
}
explicit IVFSQNR_NM(std::shared_ptr<faiss::Index> index) : IVF_NM(std::move(index)) {
index_type_ = IndexEnum::INDEX_FAISS_IVFSQ8NR;
}
explicit IVFSQNR_NM(std::shared_ptr<faiss::Index> index, uint8_t* data) : IVF_NM(std::move(index)) {
index_type_ = IndexEnum::INDEX_FAISS_IVFSQ8NR;
data_ = std::shared_ptr<uint8_t[]>(data, [&](uint8_t*) {});
}
BinarySet
Serialize(const Config& config = Config()) override;
void
Load(const BinarySet&) override;
void
Train(const DatasetPtr&, const Config&) override;
void
Add(const DatasetPtr&, const Config&) override;
void
AddWithoutIds(const DatasetPtr&, const Config&) override;
VecIndexPtr
CopyCpuToGpu(const int64_t, const Config&) override;
void
ArrangeCodes(const DatasetPtr&, const Config&);
void
UpdateIndexSize() override;
};
using IVFSQNRNMPtr = std::shared_ptr<IVFSQNR_NM>;
} // namespace knowhere
} // namespace milvus
......@@ -311,8 +311,7 @@ IVF_NM::QueryImpl(int64_t n, const float* data, int64_t k, float* distances, int
} else {
ivf_index->parallel_mode = 0;
}
bool is_sq8 =
(index_type_ == IndexEnum::INDEX_FAISS_IVFSQ8 || index_type_ == IndexEnum::INDEX_FAISS_IVFSQ8NR) ? true : false;
bool is_sq8 = (index_type_ == IndexEnum::INDEX_FAISS_IVFSQ8) ? true : false;
ivf_index->search_without_codes(n, (float*)data, (const uint8_t*)data_.get(), prefix_sum, is_sq8, k, distances,
labels, bitset_);
stdclock::time_point after = stdclock::now();
......
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License
#include <faiss/IndexFlat.h>
#include <faiss/IndexScalarQuantizer.h>
#include <faiss/gpu/GpuCloner.h>
#include <faiss/gpu/GpuIndexIVFScalarQuantizer.h>
#include <faiss/impl/ScalarQuantizer.h>
#include <faiss/index_factory.h>
#include <faiss/index_io.h>
#include <string>
#include <memory>
#include "knowhere/common/Exception.h"
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
#include "knowhere/index/vector_index/helpers/Cloner.h"
#include "knowhere/index/vector_index/helpers/FaissIO.h"
#include "knowhere/index/vector_index/helpers/IndexParameter.h"
#include "knowhere/index/vector_offset_index/IndexIVFSQNR_NM.h"
#include "knowhere/index/vector_offset_index/gpu/IndexGPUIVFSQNR_NM.h"
namespace milvus {
namespace knowhere {
void
GPUIVFSQNR_NM::Train(const DatasetPtr& dataset_ptr, const Config& config) {
GET_TENSOR_DATA_DIM(dataset_ptr)
gpu_id_ = config[knowhere::meta::DEVICEID];
faiss::MetricType metric_type = GetMetricType(config[Metric::TYPE].get<std::string>());
faiss::Index* coarse_quantizer = new faiss::IndexFlat(dim, metric_type);
auto build_index = std::shared_ptr<faiss::Index>(
new faiss::IndexIVFScalarQuantizer(coarse_quantizer, dim, config[IndexParams::nlist].get<int64_t>(),
faiss::QuantizerType::QT_8bit, metric_type, false));
auto gpu_res = FaissGpuResourceMgr::GetInstance().GetRes(gpu_id_);
if (gpu_res != nullptr) {
ResScope rs(gpu_res, gpu_id_, true);
auto device_index = faiss::gpu::index_cpu_to_gpu(gpu_res->faiss_res.get(), gpu_id_, build_index.get());
device_index->train(rows, (float*)p_data);
index_.reset(device_index);
res_ = gpu_res;
} else {
KNOWHERE_THROW_MSG("Build IVFSQNR can't get gpu resource");
}
}
VecIndexPtr
GPUIVFSQNR_NM::CopyGpuToCpu(const Config& config) {
std::lock_guard<std::mutex> lk(mutex_);
faiss::Index* device_index = index_.get();
faiss::Index* host_index_codes = faiss::gpu::index_gpu_to_cpu(device_index);
auto ivfsq_index = dynamic_cast<faiss::IndexIVFScalarQuantizer*>(host_index_codes);
auto ail = dynamic_cast<faiss::ArrayInvertedLists*>(ivfsq_index->invlists);
auto rol = dynamic_cast<faiss::ReadOnlyArrayInvertedLists*>(ail->to_readonly());
faiss::Index* host_index = faiss::gpu::index_gpu_to_cpu_without_codes(device_index);
std::shared_ptr<faiss::Index> new_index;
new_index.reset(host_index);
return std::make_shared<IVFSQNR_NM>(new_index, (uint8_t*)rol->get_all_codes());
}
} // namespace knowhere
} // namespace milvus
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License
#pragma once
#include <memory>
#include <utility>
#include "knowhere/index/vector_offset_index/gpu/IndexGPUIVF_NM.h"
namespace milvus {
namespace knowhere {
class GPUIVFSQNR_NM : public GPUIVF_NM {
public:
explicit GPUIVFSQNR_NM(const int& device_id) : GPUIVF_NM(device_id) {
index_type_ = IndexEnum::INDEX_FAISS_IVFSQ8;
}
explicit GPUIVFSQNR_NM(std::shared_ptr<faiss::Index> index, const int64_t device_id, ResPtr& res)
: GPUIVF_NM(std::move(index), device_id, res) {
index_type_ = IndexEnum::INDEX_FAISS_IVFSQ8;
}
void
Train(const DatasetPtr&, const Config&) override;
VecIndexPtr
CopyGpuToCpu(const Config&) override;
};
using GPUIVFSQNRNMPtr = std::shared_ptr<GPUIVFSQNR_NM>;
} // namespace knowhere
} // namespace milvus
......@@ -4,7 +4,7 @@
#include <mutex>
#include <algorithm>
namespace hnswlib_nm {
namespace hnswlib {
template<typename dist_t>
class BruteforceSearch : public AlgorithmInterface<dist_t> {
......
......@@ -28,9 +28,9 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
link_list_locks_(max_elements), element_levels_(max_elements) {
// linxj
space = s;
if (auto x = dynamic_cast<hnswlib_nm::L2Space*>(s)) {
if (auto x = dynamic_cast<hnswlib::L2Space*>(s)) {
metric_type_ = 0;
} else if (auto x = dynamic_cast<hnswlib_nm::InnerProductSpace*>(s)) {
} else if (auto x = dynamic_cast<hnswlib::InnerProductSpace*>(s)) {
metric_type_ = 1;
} else {
metric_type_ = 100;
......@@ -62,7 +62,7 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
cur_element_count = 0;
visited_list_pool_ = new hnswlib_nm::VisitedListPool(1, max_elements);
visited_list_pool_ = new hnswlib::VisitedListPool(1, max_elements);
......@@ -116,7 +116,7 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
int maxlevel_;
hnswlib_nm::VisitedListPool *visited_list_pool_;
hnswlib::VisitedListPool *visited_list_pool_;
std::mutex cur_element_count_guard_;
std::vector<std::mutex> link_list_locks_;
......@@ -169,9 +169,9 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
std::priority_queue<std::pair<dist_t, tableint>, std::vector<std::pair<dist_t, tableint>>, CompareByFirst>
searchBaseLayer(tableint ep_id, const void *data_point, int layer) {
hnswlib_nm::VisitedList *vl = visited_list_pool_->getFreeVisitedList();
hnswlib_nm::vl_type *visited_array = vl->mass;
hnswlib_nm::vl_type visited_array_tag = vl->curV;
hnswlib::VisitedList *vl = visited_list_pool_->getFreeVisitedList();
hnswlib::vl_type *visited_array = vl->mass;
hnswlib::vl_type visited_array_tag = vl->curV;
std::priority_queue<std::pair<dist_t, tableint>, std::vector<std::pair<dist_t, tableint>>, CompareByFirst> top_candidates;
std::priority_queue<std::pair<dist_t, tableint>, std::vector<std::pair<dist_t, tableint>>, CompareByFirst> candidateSet;
......@@ -252,9 +252,9 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
template <bool has_deletions>
std::priority_queue<std::pair<dist_t, tableint>, std::vector<std::pair<dist_t, tableint>>, CompareByFirst>
searchBaseLayerST(tableint ep_id, const void *data_point, size_t ef, faiss::ConcurrentBitsetPtr bitset) const {
hnswlib_nm::VisitedList *vl = visited_list_pool_->getFreeVisitedList();
hnswlib_nm::vl_type *visited_array = vl->mass;
hnswlib_nm::vl_type visited_array_tag = vl->curV;
hnswlib::VisitedList *vl = visited_list_pool_->getFreeVisitedList();
hnswlib::vl_type *visited_array = vl->mass;
hnswlib::vl_type visited_array_tag = vl->curV;
std::priority_queue<std::pair<dist_t, tableint>, std::vector<std::pair<dist_t, tableint>>, CompareByFirst> top_candidates;
std::priority_queue<std::pair<dist_t, tableint>, std::vector<std::pair<dist_t, tableint>>, CompareByFirst> candidate_set;
......@@ -555,7 +555,7 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
delete visited_list_pool_;
visited_list_pool_ = new hnswlib_nm::VisitedListPool(1, new_max_elements);
visited_list_pool_ = new hnswlib::VisitedListPool(1, new_max_elements);
......@@ -623,9 +623,9 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
readBinaryPOD(input, data_size_);
readBinaryPOD(input, dim);
if (metric_type_ == 0) {
space = new hnswlib_nm::L2Space(dim);
space = new hnswlib::L2Space(dim);
} else if (metric_type_ == 1) {
space = new hnswlib_nm::InnerProductSpace(dim);
space = new hnswlib::InnerProductSpace(dim);
} else {
// throw exception
}
......@@ -701,7 +701,7 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
std::vector<std::mutex>(max_elements).swap(link_list_locks_);
visited_list_pool_ = new hnswlib_nm::VisitedListPool(1, max_elements);
visited_list_pool_ = new hnswlib::VisitedListPool(1, max_elements);
linkLists_ = (char **) malloc(sizeof(void *) * max_elements);
......@@ -838,7 +838,7 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
size_links_level0_ = maxM0_ * sizeof(tableint) + sizeof(linklistsizeint);
std::vector<std::mutex>(max_elements).swap(link_list_locks_);
visited_list_pool_ = new hnswlib_nm::VisitedListPool(1, max_elements);
visited_list_pool_ = new hnswlib::VisitedListPool(1, max_elements);
linkLists_ = (char **) malloc(sizeof(void *) * max_elements);
if (linkLists_ == nullptr)
......
#pragma once
#include "hnswlib_nm.h"
#include "hnswlib.h"
#include <faiss/FaissHook.h>
namespace hnswlib_nm {
namespace hnswlib {
static float
InnerProduct(const void *pVect1, const void *pVect2, const void *qty_ptr) {
......
#pragma once
#include "hnswlib_nm.h"
#include "hnswlib.h"
#include <faiss/FaissHook.h>
namespace hnswlib_nm {
namespace hnswlib {
static float
L2Sqr(const void *pVect1, const void *pVect2, const void *qty_ptr) {
......
......@@ -4,7 +4,7 @@
#include <string.h>
#include <deque>
namespace hnswlib_nm {
namespace hnswlib {
typedef unsigned short int vl_type;
class VisitedList {
......
......@@ -64,7 +64,6 @@ set(faiss_srcs
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_index/IndexIVFPQ.cpp
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_offset_index/OffsetBaseIndex.cpp
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_offset_index/IndexIVF_NM.cpp
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_offset_index/IndexIVFSQNR_NM.cpp
)
if (MILVUS_GPU_VERSION)
set(faiss_srcs ${faiss_srcs}
......@@ -75,7 +74,6 @@ set(faiss_srcs ${faiss_srcs}
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_index/gpu/IndexGPUIVFPQ.cpp
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_index/gpu/IndexIVFSQHybrid.cpp
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_offset_index/gpu/IndexGPUIVF_NM.cpp
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_offset_index/gpu/IndexGPUIVFSQNR_NM.cpp
)
endif ()
......@@ -133,14 +131,6 @@ endif ()
target_link_libraries(test_ivf_cpu_nm ${depend_libs} ${unittest_libs} ${basic_libs})
install(TARGETS test_ivf_cpu_nm DESTINATION unittest)
################################################################################
#<IVFSQ8NM-TEST-CPU>
if (NOT TARGET test_ivfsq_cpu_nm)
add_executable(test_ivfsq_cpu_nm test_ivfsq_cpu_nm.cpp ${faiss_srcs} ${util_srcs})
endif ()
target_link_libraries(test_ivfsq_cpu_nm ${depend_libs} ${unittest_libs} ${basic_libs})
install(TARGETS test_ivfsq_cpu_nm DESTINATION unittest)
################################################################################
#<IVFNM-TEST-GPU>
if (NOT TARGET test_ivf_gpu_nm)
......@@ -149,14 +139,6 @@ endif ()
target_link_libraries(test_ivf_gpu_nm ${depend_libs} ${unittest_libs} ${basic_libs})
install(TARGETS test_ivf_gpu_nm DESTINATION unittest)
################################################################################
#<IVFSQ8NM-TEST-GPU>
if (NOT TARGET test_ivfsq_gpu_nm)
add_executable(test_ivfsq_gpu_nm test_ivfsq_gpu_nm.cpp ${faiss_srcs} ${util_srcs})
endif ()
target_link_libraries(test_ivfsq_gpu_nm ${depend_libs} ${unittest_libs} ${basic_libs})
install(TARGETS test_ivfsq_gpu_nm DESTINATION unittest)
################################################################################
#<BinaryIDMAP-TEST>
if (NOT TARGET test_binaryidmap)
......@@ -200,7 +182,7 @@ install(TARGETS test_nsg DESTINATION unittest)
################################################################################
#<HNSW-TEST>
set(hnsw_srcs
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_offset_index/IndexHNSW_NM.cpp
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_index/IndexHNSW.cpp
)
if (NOT TARGET test_hnsw)
add_executable(test_hnsw test_hnsw.cpp ${hnsw_srcs} ${util_srcs})
......@@ -208,17 +190,6 @@ endif ()
target_link_libraries(test_hnsw ${depend_libs} ${unittest_libs} ${basic_libs})
install(TARGETS test_hnsw DESTINATION unittest)
################################################################################
#<HNSWSQ8NR-TEST>
set(hnsw_sq8nm_srcs
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_offset_index/IndexHNSW_SQ8NM.cpp
)
if (NOT TARGET test_hnsw_sq8nm)
add_executable(test_hnsw_sq8nm test_hnsw_sq8nm.cpp ${hnsw_sq8nm_srcs} ${util_srcs})
endif ()
target_link_libraries(test_hnsw_sq8nm ${depend_libs} ${unittest_libs} ${basic_libs})
install(TARGETS test_hnsw_sq8nm DESTINATION unittest)
################################################################################
#<RHNSW_FLAT-TEST>
set(rhnsw_flat_srcs
......
......@@ -17,7 +17,6 @@
#include "knowhere/index/vector_index/IndexIVFPQ.h"
#include "knowhere/index/vector_index/IndexIVFSQ.h"
#include "knowhere/index/vector_index/helpers/IndexParameter.h"
#include "knowhere/index/vector_offset_index/IndexIVFSQNR_NM.h"
#include "knowhere/index/vector_offset_index/IndexIVF_NM.h"
#ifdef MILVUS_GPU_VERSION
......@@ -25,7 +24,6 @@
#include "knowhere/index/vector_index/gpu/IndexGPUIVFPQ.h"
#include "knowhere/index/vector_index/gpu/IndexGPUIVFSQ.h"
#include "knowhere/index/vector_index/gpu/IndexIVFSQHybrid.h"
#include "knowhere/index/vector_offset_index/gpu/IndexGPUIVFSQNR_NM.h"
#include "knowhere/index/vector_offset_index/gpu/IndexGPUIVF_NM.h"
#endif
......@@ -60,8 +58,6 @@ IndexFactory(const milvus::knowhere::IndexType& type, const milvus::knowhere::In
return std::make_shared<milvus::knowhere::GPUIVFPQ>(DEVICEID);
} else if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8) {
return std::make_shared<milvus::knowhere::GPUIVFSQ>(DEVICEID);
} else if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8NR) {
return std::make_shared<milvus::knowhere::GPUIVFSQNR_NM>(DEVICEID);
} else if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8H) {
return std::make_shared<milvus::knowhere::IVFSQHybrid>(DEVICEID);
} else {
......@@ -77,8 +73,6 @@ IndexFactoryNM(const milvus::knowhere::IndexType& type, const milvus::knowhere::
if (mode == milvus::knowhere::IndexMode::MODE_CPU) {
if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFFLAT) {
return std::make_shared<milvus::knowhere::IVF_NM>();
} else if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8NR) {
return std::make_shared<milvus::knowhere::IVFSQNR_NM>();
} else {
std::cout << "Invalid IndexType " << type << std::endl;
}
......@@ -117,7 +111,6 @@ class ParamGenerator {
{milvus::knowhere::meta::DEVICEID, DEVICEID},
};
} else if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8 ||
type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8NR ||
type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8H) {
return milvus::knowhere::Config{
{milvus::knowhere::meta::DIM, DIM},
......
......@@ -10,7 +10,8 @@
// or implied. See the License for the specific language governing permissions and limitations under the License.
#include <gtest/gtest.h>
#include <knowhere/index/vector_offset_index/IndexHNSW_NM.h>
#include <src/index/knowhere/knowhere/common/Config.h>
#include <src/index/knowhere/knowhere/index/vector_index/IndexHNSW.h>
#include <src/index/knowhere/knowhere/index/vector_index/helpers/IndexParameter.h>
#include <iostream>
#include <random>
......@@ -28,7 +29,7 @@ class HNSWTest : public DataGen, public TestWithParam<std::string> {
IndexType = GetParam();
std::cout << "IndexType from GetParam() is: " << IndexType << std::endl;
Generate(64, 10000, 10); // dim = 64, nb = 10000, nq = 10
index_ = std::make_shared<milvus::knowhere::IndexHNSW_NM>();
index_ = std::make_shared<milvus::knowhere::IndexHNSW>();
conf = milvus::knowhere::Config{
{milvus::knowhere::meta::DIM, 64}, {milvus::knowhere::meta::TOPK, 10},
{milvus::knowhere::IndexParams::M, 16}, {milvus::knowhere::IndexParams::efConstruction, 200},
......@@ -38,7 +39,7 @@ class HNSWTest : public DataGen, public TestWithParam<std::string> {
protected:
milvus::knowhere::Config conf;
std::shared_ptr<milvus::knowhere::IndexHNSW_NM> index_ = nullptr;
std::shared_ptr<milvus::knowhere::IndexHNSW> index_ = nullptr;
std::string IndexType;
};
......
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License.
#include <gtest/gtest.h>
#include <knowhere/index/vector_offset_index/IndexHNSW_SQ8NM.h>
#include <src/index/knowhere/knowhere/index/vector_index/helpers/IndexParameter.h>
#include <iostream>
#include <random>
#include "knowhere/common/Exception.h"
#include "unittest/utils.h"
using ::testing::Combine;
using ::testing::TestWithParam;
using ::testing::Values;
class HNSWSQ8NRTest : public DataGen, public TestWithParam<std::string> {
protected:
void
SetUp() override {
IndexType = GetParam();
std::cout << "IndexType from GetParam() is: " << IndexType << std::endl;
Generate(64, 10000, 10); // dim = 64, nb = 10000, nq = 10
// Generate(2, 10, 2); // dim = 64, nb = 10000, nq = 10
index_ = std::make_shared<milvus::knowhere::IndexHNSW_SQ8NM>();
conf = milvus::knowhere::Config{
{milvus::knowhere::meta::DIM, 64}, {milvus::knowhere::meta::TOPK, 10},
{milvus::knowhere::IndexParams::M, 16}, {milvus::knowhere::IndexParams::efConstruction, 200},
{milvus::knowhere::IndexParams::ef, 200}, {milvus::knowhere::Metric::TYPE, milvus::knowhere::Metric::L2},
};
/*
conf = milvus::knowhere::Config{
{milvus::knowhere::meta::DIM, 2}, {milvus::knowhere::meta::TOPK, 2},
{milvus::knowhere::IndexParams::M, 2}, {milvus::knowhere::IndexParams::efConstruction, 4},
{milvus::knowhere::IndexParams::ef, 7}, {milvus::knowhere::Metric::TYPE, milvus::knowhere::Metric::L2},
};
*/
}
protected:
milvus::knowhere::Config conf;
std::shared_ptr<milvus::knowhere::IndexHNSW_SQ8NM> index_ = nullptr;
std::string IndexType;
};
INSTANTIATE_TEST_CASE_P(HNSWParameters, HNSWSQ8NRTest, Values("HNSWSQ8NR"));
TEST_P(HNSWSQ8NRTest, HNSW_basic) {
assert(!xb.empty());
// null faiss index
/*
{
ASSERT_ANY_THROW(index_->Serialize());
ASSERT_ANY_THROW(index_->Query(query_dataset, conf));
ASSERT_ANY_THROW(index_->Add(nullptr, conf));
ASSERT_ANY_THROW(index_->AddWithoutIds(nullptr, conf));
ASSERT_ANY_THROW(index_->Count());
ASSERT_ANY_THROW(index_->Dim());
}
*/
index_->Train(base_dataset, conf);
index_->Add(base_dataset, conf);
EXPECT_EQ(index_->Count(), nb);
EXPECT_EQ(index_->Dim(), dim);
// Serialize and Load before Query
milvus::knowhere::BinarySet bs = index_->Serialize();
// int64_t dim = base_dataset->Get<int64_t>(milvus::knowhere::meta::DIM);
// int64_t rows = base_dataset->Get<int64_t>(milvus::knowhere::meta::ROWS);
// auto raw_data = base_dataset->Get<const void*>(milvus::knowhere::meta::TENSOR);
// milvus::knowhere::BinaryPtr bptr = std::make_shared<milvus::knowhere::Binary>();
// bptr->data = std::shared_ptr<uint8_t[]>((uint8_t*)raw_data, [&](uint8_t*) {});
// bptr->size = dim * rows * sizeof(float);
// bs.Append(RAW_DATA, bptr);
index_->Load(bs);
auto result = index_->Query(query_dataset, conf);
AssertAnns(result, nq, k);
}
TEST_P(HNSWSQ8NRTest, HNSW_delete) {
assert(!xb.empty());
index_->Train(base_dataset, conf);
index_->Add(base_dataset, conf);
EXPECT_EQ(index_->Count(), nb);
EXPECT_EQ(index_->Dim(), dim);
faiss::ConcurrentBitsetPtr bitset = std::make_shared<faiss::ConcurrentBitset>(nb);
for (auto i = 0; i < nq; ++i) {
bitset->set(i);
}
// Serialize and Load before Query
milvus::knowhere::BinarySet bs = index_->Serialize();
// int64_t dim = base_dataset->Get<int64_t>(milvus::knowhere::meta::DIM);
// int64_t rows = base_dataset->Get<int64_t>(milvus::knowhere::meta::ROWS);
// auto raw_data = base_dataset->Get<const void*>(milvus::knowhere::meta::TENSOR);
// milvus::knowhere::BinaryPtr bptr = std::make_shared<milvus::knowhere::Binary>();
// bptr->data = std::shared_ptr<uint8_t[]>((uint8_t*)raw_data, [&](uint8_t*) {});
// bptr->size = dim * rows * sizeof(float);
// bs.Append(RAW_DATA, bptr);
index_->Load(bs);
auto result1 = index_->Query(query_dataset, conf);
AssertAnns(result1, nq, k);
index_->SetBlacklist(bitset);
auto result2 = index_->Query(query_dataset, conf);
AssertAnns(result2, nq, k, CheckMode::CHECK_NOT_EQUAL);
/*
* delete result checked by eyes
auto ids1 = result1->Get<int64_t*>(milvus::knowhere::meta::IDS);
auto ids2 = result2->Get<int64_t*>(milvus::knowhere::meta::IDS);
std::cout << std::endl;
for (int i = 0; i < nq; ++ i) {
std::cout << "ids1: ";
for (int j = 0; j < k; ++ j) {
std::cout << *(ids1 + i * k + j) << " ";
}
std::cout << "ids2: ";
for (int j = 0; j < k; ++ j) {
std::cout << *(ids2 + i * k + j) << " ";
}
std::cout << std::endl;
for (int j = 0; j < std::min(5, k>>1); ++ j) {
ASSERT_EQ(*(ids1 + i * k + j + 1), *(ids2 + i * k + j));
}
}
*/
}
TEST_P(HNSWSQ8NRTest, HNSW_serialize) {
auto serialize = [](const std::string& filename, milvus::knowhere::BinaryPtr& bin, uint8_t* ret) {
{
FileIOWriter writer(filename);
writer(static_cast<void*>(bin->data.get()), bin->size);
}
FileIOReader reader(filename);
reader(ret, bin->size);
};
{
index_->Train(base_dataset, conf);
index_->Add(base_dataset, conf);
auto binaryset = index_->Serialize();
auto bin_index = binaryset.GetByName("HNSW_SQ8");
auto bin_sq8 = binaryset.GetByName(SQ8_DATA);
std::string filename = "/tmp/HNSW_SQ8NM_test_serialize_index.bin";
std::string filename2 = "/tmp/HNSW_SQ8NM_test_serialize_sq8.bin";
auto load_index_data = new uint8_t[bin_index->size];
serialize(filename, bin_index, load_index_data);
auto load_sq8_data = new uint8_t[bin_sq8->size];
serialize(filename2, bin_sq8, load_sq8_data);
binaryset.clear();
std::shared_ptr<uint8_t[]> data_index(load_index_data);
binaryset.Append("HNSW_SQ8", data_index, bin_index->size);
std::shared_ptr<uint8_t[]> sq8_index(load_sq8_data);
binaryset.Append(SQ8_DATA, sq8_index, bin_sq8->size);
index_->Load(binaryset);
EXPECT_EQ(index_->Count(), nb);
EXPECT_EQ(index_->Dim(), dim);
auto result = index_->Query(query_dataset, conf);
AssertAnns(result, nq, conf[milvus::knowhere::meta::TOPK]);
}
}
/*
* faiss style test
* keep it
int
main() {
int64_t d = 64; // dimension
int64_t nb = 10000; // database size
int64_t nq = 10; // 10000; // nb of queries
faiss::ConcurrentBitsetPtr bitset = std::make_shared<faiss::ConcurrentBitset>(nb);
int64_t* ids = new int64_t[nb];
float* xb = new float[d * nb];
float* xq = new float[d * nq];
// int64_t *ids = (int64_t*)malloc(nb * sizeof(int64_t));
// float* xb = (float*)malloc(d * nb * sizeof(float));
// float* xq = (float*)malloc(d * nq * sizeof(float));
for (int i = 0; i < nb; i++) {
for (int j = 0; j < d; j++) xb[d * i + j] = drand48();
xb[d * i] += i / 1000.;
ids[i] = i;
}
// printf("gen xb and ids done! \n");
// srand((unsigned)time(nullptr));
auto random_seed = (unsigned)time(nullptr);
// printf("delete ids: \n");
for (int i = 0; i < nq; i++) {
auto tmp = rand_r(&random_seed) % nb;
// printf("%ld\n", tmp);
// std::cout << "before delete, test result: " << bitset->test(tmp) << std::endl;
bitset->set(tmp);
// std::cout << "after delete, test result: " << bitset->test(tmp) << std::endl;
for (int j = 0; j < d; j++) xq[d * i + j] = xb[d * tmp + j];
// xq[d * i] += i / 1000.;
}
// printf("\n");
int k = 4;
int m = 16;
int ef = 200;
milvus::knowhere::IndexHNSW_NM index;
milvus::knowhere::DatasetPtr base_dataset = generate_dataset(nb, d, (const void*)xb, ids);
// base_dataset->Set(milvus::knowhere::meta::ROWS, nb);
// base_dataset->Set(milvus::knowhere::meta::DIM, d);
// base_dataset->Set(milvus::knowhere::meta::TENSOR, (const void*)xb);
// base_dataset->Set(milvus::knowhere::meta::IDS, (const int64_t*)ids);
milvus::knowhere::Config base_conf{
{milvus::knowhere::meta::DIM, d},
{milvus::knowhere::meta::TOPK, k},
{milvus::knowhere::IndexParams::M, m},
{milvus::knowhere::IndexParams::efConstruction, ef},
{milvus::knowhere::Metric::TYPE, milvus::knowhere::Metric::L2},
};
milvus::knowhere::DatasetPtr query_dataset = generate_query_dataset(nq, d, (const void*)xq);
milvus::knowhere::Config query_conf{
{milvus::knowhere::meta::DIM, d},
{milvus::knowhere::meta::TOPK, k},
{milvus::knowhere::IndexParams::M, m},
{milvus::knowhere::IndexParams::ef, ef},
{milvus::knowhere::Metric::TYPE, milvus::knowhere::Metric::L2},
};
index.Train(base_dataset, base_conf);
index.Add(base_dataset, base_conf);
// printf("------------sanity check----------------\n");
{ // sanity check
auto res = index.Query(query_dataset, query_conf);
// printf("Query done!\n");
const int64_t* I = res->Get<int64_t*>(milvus::knowhere::meta::IDS);
// float* D = res->Get<float*>(milvus::knowhere::meta::DISTANCE);
// printf("I=\n");
// for (int i = 0; i < 5; i++) {
// for (int j = 0; j < k; j++) printf("%5ld ", I[i * k + j]);
// printf("\n");
// }
// printf("D=\n");
// for (int i = 0; i < 5; i++) {
// for (int j = 0; j < k; j++) printf("%7g ", D[i * k + j]);
// printf("\n");
// }
}
// printf("---------------search xq-------------\n");
{ // search xq
auto res = index.Query(query_dataset, query_conf);
const int64_t* I = res->Get<int64_t*>(milvus::knowhere::meta::IDS);
printf("I=\n");
for (int i = 0; i < nq; i++) {
for (int j = 0; j < k; j++) printf("%5ld ", I[i * k + j]);
printf("\n");
}
}
printf("----------------search xq with delete------------\n");
{ // search xq with delete
index.SetBlacklist(bitset);
auto res = index.Query(query_dataset, query_conf);
auto I = res->Get<int64_t*>(milvus::knowhere::meta::IDS);
printf("I=\n");
for (int i = 0; i < nq; i++) {
for (int j = 0; j < k; j++) printf("%5ld ", I[i * k + j]);
printf("\n");
}
}
delete[] xb;
delete[] xq;
delete[] ids;
return 0;
}
*/
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License.
#include <gtest/gtest.h>
#include <fiu-control.h>
#include <fiu-local.h>
#include <iostream>
#include <thread>
#ifdef MILVUS_GPU_VERSION
#include <faiss/gpu/GpuIndexIVFFlat.h>
#endif
#include <faiss/IndexScalarQuantizer.h>
#include "knowhere/common/Exception.h"
#include "knowhere/common/Timer.h"
#include "knowhere/index/IndexType.h"
#include "knowhere/index/vector_index/IndexIVFSQ.h"
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
#include "knowhere/index/vector_offset_index/IndexIVFSQNR_NM.h"
#ifdef MILVUS_GPU_VERSION
#include "knowhere/index/vector_index/helpers/Cloner.h"
#include "knowhere/index/vector_index/helpers/FaissGpuResourceMgr.h"
#endif
#include "unittest/Helper.h"
#include "unittest/utils.h"
using ::testing::Combine;
using ::testing::TestWithParam;
using ::testing::Values;
class IVFSQNMCPUTest : public DataGen,
public TestWithParam<::std::tuple<milvus::knowhere::IndexType, milvus::knowhere::IndexMode>> {
protected:
void
SetUp() override {
#ifdef MILVUS_GPU_VERSION
milvus::knowhere::FaissGpuResourceMgr::GetInstance().InitDevice(DEVICEID, PINMEM, TEMPMEM, RESNUM);
#endif
std::tie(index_type_, index_mode_) = GetParam();
Generate(DIM, NB, NQ);
index_ = std::make_shared<milvus::knowhere::IVFSQNR_NM>();
conf_ = ParamGenerator::GetInstance().Gen(index_type_);
}
void
TearDown() override {
#ifdef MILVUS_GPU_VERSION
milvus::knowhere::FaissGpuResourceMgr::GetInstance().Free();
#endif
}
protected:
milvus::knowhere::IndexType index_type_;
milvus::knowhere::IndexMode index_mode_;
milvus::knowhere::Config conf_;
milvus::knowhere::IVFSQNRNMPtr index_ = nullptr;
};
INSTANTIATE_TEST_CASE_P(IVFParameters, IVFSQNMCPUTest,
Values(std::make_tuple(milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8NR,
milvus::knowhere::IndexMode::MODE_CPU)));
TEST_P(IVFSQNMCPUTest, ivf_basic_cpu) {
assert(!xb.empty());
if (index_mode_ != milvus::knowhere::IndexMode::MODE_CPU) {
return;
}
// null faiss index
ASSERT_ANY_THROW(index_->Add(base_dataset, conf_));
ASSERT_ANY_THROW(index_->AddWithoutIds(base_dataset, conf_));
index_->Train(base_dataset, conf_);
index_->AddWithoutIds(base_dataset, conf_);
EXPECT_EQ(index_->Count(), nb);
EXPECT_EQ(index_->Dim(), dim);
index_->SetIndexSize(nq * dim * sizeof(float));
milvus::knowhere::BinarySet bs = index_->Serialize();
index_->Load(bs);
auto result = index_->Query(query_dataset, conf_);
AssertAnns(result, nq, k);
auto AssertEqual = [&](milvus::knowhere::DatasetPtr p1, milvus::knowhere::DatasetPtr p2) {
auto ids_p1 = p1->Get<int64_t*>(milvus::knowhere::meta::IDS);
auto ids_p2 = p2->Get<int64_t*>(milvus::knowhere::meta::IDS);
for (int i = 0; i < nq * k; ++i) {
EXPECT_EQ(*((int64_t*)(ids_p2) + i), *((int64_t*)(ids_p1) + i));
}
};
#ifdef MILVUS_GPU_VERSION
// copy from cpu to gpu
{
EXPECT_NO_THROW({
auto clone_index = milvus::knowhere::cloner::CopyCpuToGpu(index_, DEVICEID, milvus::knowhere::Config());
auto clone_result = clone_index->Query(query_dataset, conf_);
AssertEqual(result, clone_result);
std::cout << "clone C <=> G [" << index_type_ << "] success" << std::endl;
});
EXPECT_ANY_THROW(milvus::knowhere::cloner::CopyCpuToGpu(index_, -1, milvus::knowhere::Config()));
}
#endif
faiss::ConcurrentBitsetPtr concurrent_bitset_ptr = std::make_shared<faiss::ConcurrentBitset>(nb);
for (int64_t i = 0; i < nq; ++i) {
concurrent_bitset_ptr->set(i);
}
index_->SetBlacklist(concurrent_bitset_ptr);
auto result_bs_1 = index_->Query(query_dataset, conf_);
AssertAnns(result_bs_1, nq, k, CheckMode::CHECK_NOT_EQUAL);
#ifdef MILVUS_GPU_VERSION
milvus::knowhere::FaissGpuResourceMgr::GetInstance().Dump();
#endif
}
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under the License.
#include <gtest/gtest.h>
#include <fiu-control.h>
#include <fiu-local.h>
#include <iostream>
#include <thread>
#ifdef MILVUS_GPU_VERSION
#include <faiss/gpu/GpuIndexIVFFlat.h>
#endif
#include "knowhere/common/Exception.h"
#include "knowhere/common/Timer.h"
#include "knowhere/index/IndexType.h"
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
#include "knowhere/index/vector_offset_index/IndexIVFSQNR_NM.h"
#include "knowhere/index/vector_offset_index/IndexIVF_NM.h"
#ifdef MILVUS_GPU_VERSION
#include "knowhere/index/vector_index/helpers/Cloner.h"
#include "knowhere/index/vector_index/helpers/FaissGpuResourceMgr.h"
#include "knowhere/index/vector_offset_index/gpu/IndexGPUIVFSQNR_NM.h"
#include "knowhere/index/vector_offset_index/gpu/IndexGPUIVF_NM.h"
#endif
#include "unittest/Helper.h"
#include "unittest/utils.h"
using ::testing::Combine;
using ::testing::TestWithParam;
using ::testing::Values;
class IVFSQNMGPUTest : public DataGen,
public TestWithParam<::std::tuple<milvus::knowhere::IndexType, milvus::knowhere::IndexMode>> {
protected:
void
SetUp() override {
#ifdef MILVUS_GPU_VERSION
milvus::knowhere::FaissGpuResourceMgr::GetInstance().InitDevice(DEVICEID, PINMEM, TEMPMEM, RESNUM);
#endif
index_type_ = milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8;
index_mode_ = milvus::knowhere::IndexMode::MODE_GPU;
Generate(DIM, NB, NQ);
#ifdef MILVUS_GPU_VERSION
index_ = std::make_shared<milvus::knowhere::GPUIVFSQNR_NM>(DEVICEID);
#endif
conf_ = ParamGenerator::GetInstance().Gen(index_type_);
}
void
TearDown() override {
#ifdef MILVUS_GPU_VERSION
milvus::knowhere::FaissGpuResourceMgr::GetInstance().Free();
#endif
}
protected:
milvus::knowhere::IndexType index_type_;
milvus::knowhere::IndexMode index_mode_;
milvus::knowhere::Config conf_;
milvus::knowhere::IVFPtr index_ = nullptr;
};
INSTANTIATE_TEST_CASE_P(IVFParameters, IVFSQNMGPUTest,
Values(std::make_tuple(milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8,
milvus::knowhere::IndexMode::MODE_GPU)));
#ifdef MILVUS_GPU_VERSION
TEST_P(IVFSQNMGPUTest, ivf_basic_gpu) {
assert(!xb.empty());
if (index_mode_ != milvus::knowhere::IndexMode::MODE_GPU) {
return;
}
// null faiss index
ASSERT_ANY_THROW(index_->Add(base_dataset, conf_));
ASSERT_ANY_THROW(index_->AddWithoutIds(base_dataset, conf_));
index_->Train(base_dataset, conf_);
index_->AddWithoutIds(base_dataset, conf_);
EXPECT_EQ(index_->Count(), nb);
EXPECT_EQ(index_->Dim(), dim);
index_->SetIndexSize(nq * dim * sizeof(float));
milvus::knowhere::BinarySet bs = index_->Serialize();
index_->Load(bs);
auto result = index_->Query(query_dataset, conf_);
AssertAnns(result, nq, k);
auto AssertEqual = [&](milvus::knowhere::DatasetPtr p1, milvus::knowhere::DatasetPtr p2) {
auto ids_p1 = p1->Get<int64_t*>(milvus::knowhere::meta::IDS);
auto ids_p2 = p2->Get<int64_t*>(milvus::knowhere::meta::IDS);
for (int i = 0; i < nq * k; ++i) {
EXPECT_EQ(*((int64_t*)(ids_p2) + i), *((int64_t*)(ids_p1) + i));
}
};
// copy from gpu to cpu
{
EXPECT_NO_THROW({
auto clone_index = milvus::knowhere::cloner::CopyGpuToCpu(index_, milvus::knowhere::Config());
milvus::knowhere::BinarySet bs = clone_index->Serialize();
clone_index->Load(bs);
auto clone_result = clone_index->Query(query_dataset, conf_);
AssertEqual(result, clone_result);
std::cout << "clone G <=> C [" << index_type_ << "] success" << std::endl;
});
}
faiss::ConcurrentBitsetPtr concurrent_bitset_ptr = std::make_shared<faiss::ConcurrentBitset>(nb);
for (int64_t i = 0; i < nq; ++i) {
concurrent_bitset_ptr->set(i);
}
index_->SetBlacklist(concurrent_bitset_ptr);
auto result_bs_1 = index_->Query(query_dataset, conf_);
AssertAnns(result_bs_1, nq, k, CheckMode::CHECK_NOT_EQUAL);
milvus::knowhere::FaissGpuResourceMgr::GetInstance().Dump();
}
#endif
......@@ -347,8 +347,7 @@ SegmentReader::LoadVectorIndex(const std::string& field_name, knowhere::VecIndex
}
// for some kinds index(SQ8), read compress file
if (index_type == knowhere::IndexEnum::INDEX_FAISS_IVFSQ8NR ||
index_type == knowhere::IndexEnum::INDEX_HNSW_SQ8NM) {
if (index_type == knowhere::IndexEnum::INDEX_RHNSWSQ) {
if (auto visitor = field_visitor->GetElementVisitor(engine::FieldElementType::FET_COMPRESS_SQ8)) {
auto file_path =
engine::snapshot::GetResPath<engine::snapshot::SegmentFile>(dir_collections_, visitor->GetFile());
......
......@@ -176,14 +176,15 @@ ValidateIndexType(const std::string& index_type) {
knowhere::IndexEnum::INDEX_FAISS_IVFFLAT,
knowhere::IndexEnum::INDEX_FAISS_IVFPQ,
knowhere::IndexEnum::INDEX_FAISS_IVFSQ8,
knowhere::IndexEnum::INDEX_FAISS_IVFSQ8NR,
knowhere::IndexEnum::INDEX_FAISS_IVFSQ8H,
knowhere::IndexEnum::INDEX_FAISS_BIN_IDMAP,
knowhere::IndexEnum::INDEX_FAISS_BIN_IVFFLAT,
knowhere::IndexEnum::INDEX_NSG,
knowhere::IndexEnum::INDEX_HNSW,
knowhere::IndexEnum::INDEX_ANNOY,
knowhere::IndexEnum::INDEX_HNSW_SQ8NM,
knowhere::IndexEnum::INDEX_RHNSWFlat,
knowhere::IndexEnum::INDEX_RHNSWPQ,
knowhere::IndexEnum::INDEX_RHNSWSQ,
};
if (s_valid_index_names.find(index_type) == s_valid_index_names.end()) {
......@@ -220,7 +221,6 @@ ValidateIndexParams(const milvus::json& index_params, int64_t dimension, const s
return Status::OK();
} else if (index_type == knowhere::IndexEnum::INDEX_FAISS_IVFFLAT ||
index_type == knowhere::IndexEnum::INDEX_FAISS_IVFSQ8 ||
index_type == knowhere::IndexEnum::INDEX_FAISS_IVFSQ8NR ||
index_type == knowhere::IndexEnum::INDEX_FAISS_IVFSQ8H ||
index_type == knowhere::IndexEnum::INDEX_FAISS_BIN_IVFFLAT) {
auto status = CheckParameterRange(index_params, knowhere::IndexParams::nlist, 1, 999999);
......@@ -279,7 +279,7 @@ ValidateIndexParams(const milvus::json& index_params, int64_t dimension, const s
if (!status.ok()) {
return status;
}
} else if (index_type == knowhere::IndexEnum::INDEX_HNSW || index_type == knowhere::IndexEnum::INDEX_HNSW_SQ8NM ||
} else if (index_type == knowhere::IndexEnum::INDEX_HNSW || index_type == knowhere::IndexEnum::INDEX_RHNSWFlat ||
index_type == knowhere::IndexEnum::INDEX_RHNSWPQ || index_type == knowhere::IndexEnum::INDEX_RHNSWSQ ||
index_type == knowhere::IndexEnum::INDEX_RHNSWFlat) {
auto status = CheckParameterRange(index_params, knowhere::IndexParams::M, 4, 64);
......
......@@ -23,8 +23,6 @@ const char* NAME_ENGINE_TYPE_RNSG = "RNSG";
const char* NAME_ENGINE_TYPE_IVFPQ = "IVFPQ";
const char* NAME_ENGINE_TYPE_HNSW = "HNSW";
const char* NAME_ENGINE_TYPE_ANNOY = "ANNOY";
const char* NAME_ENGINE_TYPE_IVFSQ8NR = "IVFSQ8NR";
const char* NAME_ENGINE_TYPE_HNSWSQ8NM = "HNSWSQ8NM";
const char* NAME_ENGINE_TYPE_RHNSWFLAT = "RHNSWFLAT";
const char* NAME_ENGINE_TYPE_RHNSWPQ = "RHNSWPQ";
const char* NAME_ENGINE_TYPE_RHNSWSQ8 = "RHNSWSQ8";
......
......@@ -21,12 +21,10 @@ namespace web {
extern const char* NAME_ENGINE_TYPE_FLAT;
extern const char* NAME_ENGINE_TYPE_IVFFLAT;
extern const char* NAME_ENGINE_TYPE_IVFSQ8;
extern const char* NAME_ENGINE_TYPE_IVFSQ8NR;
extern const char* NAME_ENGINE_TYPE_IVFSQ8H;
extern const char* NAME_ENGINE_TYPE_RNSG;
extern const char* NAME_ENGINE_TYPE_IVFPQ;
extern const char* NAME_ENGINE_TYPE_HNSW;
extern const char* NAME_ENGINE_TYPE_HNSW_SQ8NM;
extern const char* NAME_ENGINE_TYPE_ANNOY;
extern const char* NAME_ENGINE_TYPE_RHNSWFLAT;
extern const char* NAME_ENGINE_TYPE_RHNSWPQ;
......
......@@ -115,12 +115,14 @@ Utils::IndexTypeName(const milvus::IndexType& index_type) {
return "SPTAGBKT";
case milvus::IndexType::HNSW:
return "HNSW";
case milvus::IndexType::HNSW_SQ8NM:
return "HNSW_SQ8NM";
case milvus::IndexType::RHNSWFLAT:
return "RHNSWFLAT";
case milvus::IndexType::RHNSWSQ:
return "RHNSWSQ";
case milvus::IndexType::RHNSWPQ:
return "RHNSWPQ";
case milvus::IndexType::ANNOY:
return "ANNOY";
case milvus::IndexType::IVFSQ8NR:
return "IVFSQ8NR";
default:
return "Unknown index type";
}
......
......@@ -40,8 +40,9 @@ enum class IndexType {
SPTAGBKT = 8,
HNSW = 11,
ANNOY = 12,
IVFSQ8NR = 13,
HNSW_SQ8NM = 14,
RHNSWFLAT = 13,
RHNSWPQ = 14,
RHNSWSQ = 15,
};
enum class MetricType {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册