mirror of https://github.com/milvus-io/milvus.git
Add IVF_HNSW index (#4613)
* Add IVF_HNSW index Signed-off-by: sahuang <xiaohaix@student.unimelb.edu.au> * Fix serialize-load bug Signed-off-by: sahuang <xiaohaix@student.unimelb.edu.au>pull/4654/head
parent
91a1494b57
commit
df500c923e
|
@ -71,6 +71,7 @@ set(vector_index_srcs
|
|||
knowhere/index/vector_index/IndexIVF.cpp
|
||||
knowhere/index/vector_index/IndexIVFPQ.cpp
|
||||
knowhere/index/vector_index/IndexIVFSQ.cpp
|
||||
knowhere/index/vector_index/IndexIVFHNSW.cpp
|
||||
knowhere/index/vector_index/IndexAnnoy.cpp
|
||||
knowhere/index/vector_index/IndexRHNSW.cpp
|
||||
knowhere/index/vector_index/IndexHNSW.cpp
|
||||
|
|
|
@ -25,6 +25,7 @@ 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_IVFSQ8H = "IVF_SQ8_HYBRID";
|
||||
const char* INDEX_FAISS_IVFHNSW = "IVF_HNSW";
|
||||
const char* INDEX_FAISS_BIN_IDMAP = "BIN_FLAT";
|
||||
const char* INDEX_FAISS_BIN_IVFFLAT = "BIN_IVF_FLAT";
|
||||
const char* INDEX_NSG = "NSG";
|
||||
|
|
|
@ -54,6 +54,7 @@ extern const char* INDEX_FAISS_IVFFLAT;
|
|||
extern const char* INDEX_FAISS_IVFPQ;
|
||||
extern const char* INDEX_FAISS_IVFSQ8;
|
||||
extern const char* INDEX_FAISS_IVFSQ8H;
|
||||
extern const char* INDEX_FAISS_IVFHNSW;
|
||||
extern const char* INDEX_FAISS_BIN_IDMAP;
|
||||
extern const char* INDEX_FAISS_BIN_IVFFLAT;
|
||||
extern const char* INDEX_NSG;
|
||||
|
|
|
@ -207,6 +207,34 @@ IVFPQConfAdapter::CheckCPUPQParams(int64_t dimension, int64_t m) {
|
|||
return (dimension % m == 0);
|
||||
}
|
||||
|
||||
bool
|
||||
IVFHNSWConfAdapter::CheckTrain(Config& oricfg, const IndexMode mode) {
|
||||
// HNSW param check
|
||||
CheckIntByRange(knowhere::IndexParams::efConstruction, HNSW_MIN_EFCONSTRUCTION, HNSW_MAX_EFCONSTRUCTION);
|
||||
CheckIntByRange(knowhere::IndexParams::M, HNSW_MIN_M, HNSW_MAX_M);
|
||||
|
||||
// IVF param check
|
||||
CheckIntByRange(knowhere::IndexParams::nlist, MIN_NLIST, MAX_NLIST);
|
||||
|
||||
// auto tune params
|
||||
auto rows = oricfg[knowhere::meta::ROWS].get<int64_t>();
|
||||
auto nlist = oricfg[knowhere::IndexParams::nlist].get<int64_t>();
|
||||
oricfg[knowhere::IndexParams::nlist] = MatchNlist(rows, nlist);
|
||||
|
||||
return ConfAdapter::CheckTrain(oricfg, mode);
|
||||
}
|
||||
|
||||
bool
|
||||
IVFHNSWConfAdapter::CheckSearch(Config& oricfg, const IndexType type, const IndexMode mode) {
|
||||
// HNSW param check
|
||||
CheckIntByRange(knowhere::IndexParams::ef, oricfg[knowhere::meta::TOPK], HNSW_MAX_EF);
|
||||
|
||||
// IVF param check
|
||||
CheckIntByRange(knowhere::IndexParams::nprobe, MIN_NPROBE, MAX_NPROBE);
|
||||
|
||||
return ConfAdapter::CheckSearch(oricfg, type, mode);
|
||||
}
|
||||
|
||||
bool
|
||||
NSGConfAdapter::CheckTrain(Config& oricfg, const IndexMode mode) {
|
||||
const int64_t MIN_KNNG = 5;
|
||||
|
|
|
@ -61,6 +61,15 @@ class IVFPQConfAdapter : public IVFConfAdapter {
|
|||
CheckCPUPQParams(int64_t dimension, int64_t m);
|
||||
};
|
||||
|
||||
class IVFHNSWConfAdapter : public ConfAdapter {
|
||||
public:
|
||||
bool
|
||||
CheckTrain(Config& oricfg, const IndexMode mode) override;
|
||||
|
||||
bool
|
||||
CheckSearch(Config& oricfg, const IndexType type, const IndexMode mode) override;
|
||||
};
|
||||
|
||||
class NSGConfAdapter : public IVFConfAdapter {
|
||||
public:
|
||||
bool
|
||||
|
|
|
@ -41,6 +41,7 @@ AdapterMgr::RegisterAdapter() {
|
|||
REGISTER_CONF_ADAPTER(IVFPQConfAdapter, IndexEnum::INDEX_FAISS_IVFPQ, ivfpq_adapter);
|
||||
REGISTER_CONF_ADAPTER(IVFSQConfAdapter, IndexEnum::INDEX_FAISS_IVFSQ8, ivfsq8_adapter);
|
||||
REGISTER_CONF_ADAPTER(IVFSQConfAdapter, IndexEnum::INDEX_FAISS_IVFSQ8H, ivfsq8h_adapter);
|
||||
REGISTER_CONF_ADAPTER(IVFHNSWConfAdapter, IndexEnum::INDEX_FAISS_IVFHNSW, ivfhnsw_adapter);
|
||||
REGISTER_CONF_ADAPTER(BinIDMAPConfAdapter, IndexEnum::INDEX_FAISS_BIN_IDMAP, idmap_bin_adapter);
|
||||
REGISTER_CONF_ADAPTER(BinIVFConfAdapter, IndexEnum::INDEX_FAISS_BIN_IVFFLAT, ivf_bin_adapter);
|
||||
REGISTER_CONF_ADAPTER(NSGConfAdapter, IndexEnum::INDEX_NSG, nsg_adapter);
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
// 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 <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <faiss/IndexFlat.h>
|
||||
#include <faiss/IndexIVFFlat.h>
|
||||
#include <faiss/clone_index.h>
|
||||
#include <faiss/index_io.h>
|
||||
|
||||
#include "faiss/IndexRHNSW.h"
|
||||
|
||||
#include "knowhere/common/Exception.h"
|
||||
#include "knowhere/index/vector_index/IndexIVFHNSW.h"
|
||||
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
|
||||
#include "knowhere/index/vector_index/helpers/IndexParameter.h"
|
||||
|
||||
namespace milvus {
|
||||
namespace knowhere {
|
||||
|
||||
BinarySet
|
||||
IVFHNSW::Serialize(const Config& config) {
|
||||
if (!index_ || !index_->is_trained) {
|
||||
KNOWHERE_THROW_MSG("index not initialize or trained");
|
||||
}
|
||||
|
||||
try {
|
||||
// Serialize IVF index and HNSW data
|
||||
auto res_set = SerializeImpl(index_type_);
|
||||
auto index = dynamic_cast<faiss::IndexIVFFlat*>(index_.get());
|
||||
auto real_idx = dynamic_cast<faiss::IndexRHNSWFlat*>(index->quantizer);
|
||||
if (real_idx == nullptr) {
|
||||
KNOWHERE_THROW_MSG("Quantizer index is not a faiss::IndexRHNSWFlat");
|
||||
}
|
||||
|
||||
MemoryIOWriter writer;
|
||||
faiss::write_index(real_idx->storage, &writer);
|
||||
std::shared_ptr<uint8_t[]> data(writer.data_);
|
||||
res_set.Append("HNSW_META", data, writer.rp);
|
||||
|
||||
if (config.contains(INDEX_FILE_SLICE_SIZE_IN_MEGABYTE)) {
|
||||
Disassemble(config[INDEX_FILE_SLICE_SIZE_IN_MEGABYTE].get<int64_t>() * 1024 * 1024, res_set);
|
||||
}
|
||||
return res_set;
|
||||
} catch (std::exception& e) {
|
||||
KNOWHERE_THROW_MSG(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IVFHNSW::Load(const BinarySet& binary_set) {
|
||||
try {
|
||||
// Load IVF index and HNSW data
|
||||
Assemble(const_cast<BinarySet&>(binary_set));
|
||||
LoadImpl(binary_set, index_type_);
|
||||
|
||||
auto index = dynamic_cast<faiss::IndexIVFFlat*>(index_.get());
|
||||
MemoryIOReader reader;
|
||||
auto binary = binary_set.GetByName("HNSW_META");
|
||||
reader.total = static_cast<size_t>(binary->size);
|
||||
reader.data_ = binary->data.get();
|
||||
|
||||
auto idx = faiss::read_index(&reader);
|
||||
auto real_idx = dynamic_cast<faiss::IndexRHNSWFlat*>(index->quantizer);
|
||||
real_idx->storage = new faiss::IndexFlat(idx->d, idx->metric_type);
|
||||
real_idx->storage->add(idx->ntotal,
|
||||
reinterpret_cast<const float*>(dynamic_cast<faiss::IndexFlat*>(idx)->xb.data()));
|
||||
real_idx->init_hnsw();
|
||||
} catch (std::exception& e) {
|
||||
KNOWHERE_THROW_MSG(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IVFHNSW::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>());
|
||||
auto coarse_quantizer = new faiss::IndexRHNSWFlat(dim, config[IndexParams::M], metric_type);
|
||||
coarse_quantizer->hnsw.efConstruction = config[IndexParams::efConstruction];
|
||||
auto index = std::make_shared<faiss::IndexIVFFlat>(coarse_quantizer, dim, config[IndexParams::nlist].get<int64_t>(),
|
||||
metric_type);
|
||||
index->own_fields = true;
|
||||
index->train(rows, reinterpret_cast<const float*>(p_data));
|
||||
index_ = index;
|
||||
}
|
||||
|
||||
VecIndexPtr
|
||||
IVFHNSW::CopyCpuToGpu(const int64_t device_id, const Config& config) {
|
||||
KNOWHERE_THROW_MSG("IVFHNSW::CopyCpuToGpu not supported.");
|
||||
}
|
||||
|
||||
void
|
||||
IVFHNSW::UpdateIndexSize() {
|
||||
if (!index_) {
|
||||
KNOWHERE_THROW_MSG("index not initialize");
|
||||
}
|
||||
auto ivf_index = static_cast<faiss::IndexIVFFlat*>(index_.get());
|
||||
auto nb = ivf_index->invlists->compute_ntotal();
|
||||
auto code_size = ivf_index->code_size;
|
||||
auto hnsw_quantizer = dynamic_cast<faiss::IndexRHNSWFlat*>(ivf_index->quantizer);
|
||||
// ivf codes, ivf ids and hnsw_flat quantizer
|
||||
index_size_ = nb * code_size + nb * sizeof(int64_t) + hnsw_quantizer->cal_size();
|
||||
}
|
||||
|
||||
void
|
||||
IVFHNSW::QueryImpl(int64_t n, const float* data, int64_t k, float* distances, int64_t* labels, const Config& config,
|
||||
const faiss::BitsetView& bitset) {
|
||||
auto params = GenParams(config);
|
||||
auto ivf_index = dynamic_cast<faiss::IndexIVF*>(index_.get());
|
||||
ivf_index->nprobe = std::min(params->nprobe, ivf_index->invlists->nlist);
|
||||
if (params->nprobe > 1 && n <= 4) {
|
||||
ivf_index->parallel_mode = 1;
|
||||
} else {
|
||||
ivf_index->parallel_mode = 0;
|
||||
}
|
||||
// Update HNSW quantizer search param
|
||||
auto hnsw_quantizer = dynamic_cast<faiss::IndexRHNSWFlat*>(ivf_index->quantizer);
|
||||
hnsw_quantizer->hnsw.efSearch = config[IndexParams::ef].get<int64_t>();
|
||||
ivf_index->search(n, data, k, distances, labels, bitset);
|
||||
}
|
||||
|
||||
} // namespace knowhere
|
||||
} // namespace milvus
|
|
@ -0,0 +1,56 @@
|
|||
// 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/IndexIVF.h"
|
||||
|
||||
namespace milvus {
|
||||
namespace knowhere {
|
||||
|
||||
class IVFHNSW : public IVF {
|
||||
public:
|
||||
IVFHNSW() : IVF() {
|
||||
index_type_ = IndexEnum::INDEX_FAISS_IVFHNSW;
|
||||
}
|
||||
|
||||
explicit IVFHNSW(std::shared_ptr<faiss::Index> index) : IVF(std::move(index)) {
|
||||
index_type_ = IndexEnum::INDEX_FAISS_IVFHNSW;
|
||||
}
|
||||
|
||||
BinarySet
|
||||
Serialize(const Config&) override;
|
||||
|
||||
void
|
||||
Load(const BinarySet&) override;
|
||||
|
||||
void
|
||||
Train(const DatasetPtr&, const Config&) override;
|
||||
|
||||
VecIndexPtr
|
||||
CopyCpuToGpu(const int64_t, const Config&) override;
|
||||
|
||||
void
|
||||
UpdateIndexSize() override;
|
||||
|
||||
protected:
|
||||
void
|
||||
QueryImpl(int64_t n, const float* data, int64_t k, float* distances, int64_t* labels, const Config& config,
|
||||
const faiss::BitsetView& bitset) override;
|
||||
};
|
||||
|
||||
using IVFHNSWPtr = std::shared_ptr<IVFHNSW>;
|
||||
|
||||
} // namespace knowhere
|
||||
} // namespace milvus
|
|
@ -19,7 +19,6 @@
|
|||
#include <faiss/IndexFlat.h>
|
||||
#include <faiss/IndexScalarQuantizer.h>
|
||||
#include <faiss/clone_index.h>
|
||||
#include <faiss/index_factory.h>
|
||||
|
||||
#include "knowhere/common/Exception.h"
|
||||
#include "knowhere/index/vector_index/IndexIVFSQ.h"
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <faiss/IndexFlat.h>
|
||||
#include <faiss/IndexScalarQuantizer.h>
|
||||
#include <faiss/gpu/GpuCloner.h>
|
||||
#include <faiss/index_factory.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <faiss/IndexIVFFlat.h>
|
||||
#include <faiss/IndexIVFPQ.h>
|
||||
#include <faiss/clone_index.h>
|
||||
#include <faiss/index_factory.h>
|
||||
#include <faiss/index_io.h>
|
||||
#ifdef MILVUS_GPU_VERSION
|
||||
#include <faiss/gpu/GpuAutoTune.h>
|
||||
|
|
|
@ -277,7 +277,7 @@ IndexHNSW::~IndexHNSW() {
|
|||
void IndexHNSW::train(idx_t n, const float* x)
|
||||
{
|
||||
FAISS_THROW_IF_NOT_MSG(storage,
|
||||
"Please use IndexHSNWFlat (or variants) instead of IndexHNSW directly");
|
||||
"Please use IndexHNSWFlat (or variants) instead of IndexHNSW directly");
|
||||
// hnsw structure does not require training
|
||||
storage->train (n, x);
|
||||
is_trained = true;
|
||||
|
@ -288,7 +288,7 @@ void IndexHNSW::search (idx_t n, const float *x, idx_t k,
|
|||
|
||||
{
|
||||
FAISS_THROW_IF_NOT_MSG(storage,
|
||||
"Please use IndexHSNWFlat (or variants) instead of IndexHNSW directly");
|
||||
"Please use IndexHNSWFlat (or variants) instead of IndexHNSW directly");
|
||||
size_t nreorder = 0;
|
||||
|
||||
idx_t check_period = InterruptCallback::get_period_hint (
|
||||
|
@ -348,7 +348,7 @@ void IndexHNSW::search (idx_t n, const float *x, idx_t k,
|
|||
void IndexHNSW::add(idx_t n, const float *x)
|
||||
{
|
||||
FAISS_THROW_IF_NOT_MSG(storage,
|
||||
"Please use IndexHSNWFlat (or variants) instead of IndexHNSW directly");
|
||||
"Please use IndexHNSWFlat (or variants) instead of IndexHNSW directly");
|
||||
FAISS_THROW_IF_NOT(is_trained);
|
||||
int n0 = ntotal;
|
||||
storage->add(n, x);
|
||||
|
|
|
@ -230,7 +230,7 @@ IndexRHNSW::clear_stats() {
|
|||
void IndexRHNSW::train(idx_t n, const float* x)
|
||||
{
|
||||
FAISS_THROW_IF_NOT_MSG(storage,
|
||||
"Please use IndexHSNWFlat (or variants) instead of IndexRHNSW directly");
|
||||
"Please use IndexRHNSWFlat (or variants) instead of IndexRHNSW directly");
|
||||
// hnsw structure does not require training
|
||||
storage->train (n, x);
|
||||
is_trained = true;
|
||||
|
@ -241,7 +241,7 @@ void IndexRHNSW::search (idx_t n, const float *x, idx_t k,
|
|||
|
||||
{
|
||||
FAISS_THROW_IF_NOT_MSG(storage,
|
||||
"Please use IndexHSNWFlat (or variants) instead of IndexRHNSW directly");
|
||||
"Please use IndexRHNSWFlat (or variants) instead of IndexRHNSW directly");
|
||||
size_t nreorder = 0;
|
||||
|
||||
idx_t check_period = InterruptCallback::get_period_hint (
|
||||
|
@ -324,7 +324,7 @@ void IndexRHNSW::search (idx_t n, const float *x, idx_t k,
|
|||
void IndexRHNSW::add(idx_t n, const float *x)
|
||||
{
|
||||
FAISS_THROW_IF_NOT_MSG(storage,
|
||||
"Please use IndexHSNWFlat (or variants) instead of IndexRHNSW directly");
|
||||
"Please use IndexRHNSWFlat (or variants) instead of IndexRHNSW directly");
|
||||
FAISS_THROW_IF_NOT(is_trained);
|
||||
int n0 = ntotal;
|
||||
storage->add(n, x);
|
||||
|
|
|
@ -65,6 +65,7 @@ set(faiss_srcs
|
|||
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_index/IndexIVF.cpp
|
||||
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_index/IndexIVFSQ.cpp
|
||||
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_index/IndexIVFPQ.cpp
|
||||
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_index/IndexIVFHNSW.cpp
|
||||
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_offset_index/OffsetBaseIndex.cpp
|
||||
${INDEX_SOURCE_DIR}/knowhere/knowhere/index/vector_offset_index/IndexIVF_NM.cpp
|
||||
)
|
||||
|
@ -127,6 +128,14 @@ endif ()
|
|||
target_link_libraries(test_ivf ${depend_libs} ${unittest_libs} ${basic_libs})
|
||||
install(TARGETS test_ivf DESTINATION unittest)
|
||||
|
||||
################################################################################
|
||||
#<IVFHNSW-TEST>
|
||||
if (NOT TARGET test_ivf_hnsw)
|
||||
add_executable(test_ivf_hnsw test_ivf_hnsw.cpp ${faiss_srcs} ${util_srcs})
|
||||
endif ()
|
||||
target_link_libraries(test_ivf_hnsw ${depend_libs} ${unittest_libs} ${basic_libs})
|
||||
install(TARGETS test_ivf_hnsw DESTINATION unittest)
|
||||
|
||||
################################################################################
|
||||
#<IVFNM-TEST-CPU>
|
||||
if (NOT TARGET test_ivf_cpu_nm)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "knowhere/index/IndexType.h"
|
||||
#include "knowhere/index/vector_index/IndexIVF.h"
|
||||
#include "knowhere/index/vector_index/IndexIVFHNSW.h"
|
||||
#include "knowhere/index/vector_index/IndexIVFPQ.h"
|
||||
#include "knowhere/index/vector_index/IndexIVFSQ.h"
|
||||
#include "knowhere/index/vector_index/helpers/IndexParameter.h"
|
||||
|
@ -45,6 +46,8 @@ IndexFactory(const milvus::knowhere::IndexType& type, const milvus::knowhere::In
|
|||
return std::make_shared<milvus::knowhere::IVFPQ>();
|
||||
} else if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8) {
|
||||
return std::make_shared<milvus::knowhere::IVFSQ>();
|
||||
} else if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFHNSW) {
|
||||
return std::make_shared<milvus::knowhere::IVFHNSW>();
|
||||
} else if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFSQ8H) {
|
||||
std::cout << "IVFSQ8H does not support MODE_CPU" << std::endl;
|
||||
} else {
|
||||
|
@ -124,6 +127,19 @@ class ParamGenerator {
|
|||
{milvus::knowhere::INDEX_FILE_SLICE_SIZE_IN_MEGABYTE, 4},
|
||||
{milvus::knowhere::meta::DEVICEID, DEVICEID},
|
||||
};
|
||||
} else if (type == milvus::knowhere::IndexEnum::INDEX_FAISS_IVFHNSW) {
|
||||
return milvus::knowhere::Config{
|
||||
{milvus::knowhere::meta::DIM, DIM},
|
||||
{milvus::knowhere::meta::TOPK, K},
|
||||
{milvus::knowhere::IndexParams::nlist, 100},
|
||||
{milvus::knowhere::IndexParams::nprobe, 4},
|
||||
{milvus::knowhere::IndexParams::M, 16},
|
||||
{milvus::knowhere::IndexParams::efConstruction, 200},
|
||||
{milvus::knowhere::IndexParams::ef, 200},
|
||||
{milvus::knowhere::Metric::TYPE, milvus::knowhere::Metric::L2},
|
||||
{milvus::knowhere::INDEX_FILE_SLICE_SIZE_IN_MEGABYTE, 4},
|
||||
{milvus::knowhere::meta::DEVICEID, DEVICEID},
|
||||
};
|
||||
} else {
|
||||
std::cout << "Invalid index type " << type << std::endl;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
// 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/fiu-local.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "knowhere/common/Exception.h"
|
||||
#include "knowhere/common/Timer.h"
|
||||
#include "knowhere/index/IndexType.h"
|
||||
#include "knowhere/index/vector_index/IndexIVF.h"
|
||||
#include "knowhere/index/vector_index/IndexIVFHNSW.h"
|
||||
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
|
||||
|
||||
#include "unittest/Helper.h"
|
||||
#include "unittest/utils.h"
|
||||
|
||||
using ::testing::Combine;
|
||||
using ::testing::TestWithParam;
|
||||
using ::testing::Values;
|
||||
|
||||
class IVFHNSWTest : public DataGen,
|
||||
public TestWithParam<::std::tuple<milvus::knowhere::IndexType, milvus::knowhere::IndexMode>> {
|
||||
protected:
|
||||
void
|
||||
SetUp() override {
|
||||
std::tie(index_type_, index_mode_) = GetParam();
|
||||
Generate(dim, nb, nq);
|
||||
index_ = IndexFactory(index_type_, index_mode_);
|
||||
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, IVFHNSWTest,
|
||||
Values(
|
||||
std::make_tuple(milvus::knowhere::IndexEnum::INDEX_FAISS_IVFHNSW, milvus::knowhere::IndexMode::MODE_CPU)));
|
||||
|
||||
TEST_P(IVFHNSWTest, ivfhnsw_basic_cpu) {
|
||||
assert(!xb.empty());
|
||||
|
||||
if (index_mode_ != milvus::knowhere::IndexMode::MODE_CPU) {
|
||||
return;
|
||||
}
|
||||
|
||||
// null faiss index
|
||||
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);
|
||||
|
||||
auto result = index_->Query(query_dataset, conf_, nullptr);
|
||||
AssertAnns(result, nq, k);
|
||||
}
|
||||
|
||||
TEST_P(IVFHNSWTest, ivfhnsw_slice) {
|
||||
fiu_init(0);
|
||||
{
|
||||
// serialize index
|
||||
index_->Train(base_dataset, conf_);
|
||||
index_->AddWithoutIds(base_dataset, conf_);
|
||||
auto binaryset = index_->Serialize(conf_);
|
||||
// load index
|
||||
index_->Load(binaryset);
|
||||
EXPECT_EQ(index_->Count(), nb);
|
||||
EXPECT_EQ(index_->Dim(), dim);
|
||||
auto result = index_->Query(query_dataset, conf_, nullptr);
|
||||
AssertAnns(result, nq, k);
|
||||
}
|
||||
}
|
|
@ -192,6 +192,7 @@ ValidateVectorIndexType(std::string& index_type, bool is_binary) {
|
|||
knowhere::IndexEnum::INDEX_FAISS_IVFFLAT,
|
||||
knowhere::IndexEnum::INDEX_FAISS_IVFPQ,
|
||||
knowhere::IndexEnum::INDEX_FAISS_IVFSQ8,
|
||||
knowhere::IndexEnum::INDEX_FAISS_IVFHNSW,
|
||||
#ifdef MILVUS_GPU_VERSION
|
||||
knowhere::IndexEnum::INDEX_FAISS_IVFSQ8H,
|
||||
#endif
|
||||
|
@ -354,6 +355,19 @@ ValidateIndexParams(const milvus::json& index_params, int64_t dimension, const s
|
|||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (index_type == knowhere::IndexEnum::INDEX_FAISS_IVFHNSW) {
|
||||
auto status = CheckParameterRange(index_params, knowhere::IndexParams::nlist, 1, 65536);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
status = CheckParameterRange(index_params, knowhere::IndexParams::M, 4, 64);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
status = CheckParameterRange(index_params, knowhere::IndexParams::efConstruction, 8, 512);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
|
|
|
@ -21,6 +21,7 @@ const char* NAME_ENGINE_TYPE_IVFSQ8 = "IVF_SQ8";
|
|||
const char* NAME_ENGINE_TYPE_IVFSQ8H = "IVF_SQ8H";
|
||||
const char* NAME_ENGINE_TYPE_RNSG = "RNSG";
|
||||
const char* NAME_ENGINE_TYPE_IVFPQ = "IVF_PQ";
|
||||
const char* NAME_ENGINE_TYPE_IVFHNSW = "IVF_HNSW";
|
||||
const char* NAME_ENGINE_TYPE_HNSW = "HNSW";
|
||||
const char* NAME_ENGINE_TYPE_ANNOY = "ANNOY";
|
||||
const char* NAME_ENGINE_TYPE_RHNSWFLAT = "RHNSW_FLAT";
|
||||
|
|
|
@ -24,6 +24,7 @@ extern const char* NAME_ENGINE_TYPE_IVFSQ8;
|
|||
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_IVFHNSW;
|
||||
extern const char* NAME_ENGINE_TYPE_HNSW;
|
||||
extern const char* NAME_ENGINE_TYPE_ANNOY;
|
||||
extern const char* NAME_ENGINE_TYPE_RHNSWFLAT;
|
||||
|
|
|
@ -46,6 +46,7 @@ enum class IndexType {
|
|||
RHNSWSQ = 15,
|
||||
NGTPANNG = 16,
|
||||
NGTONNG = 17,
|
||||
IVFHNSW = 18,
|
||||
};
|
||||
|
||||
enum class MetricType {
|
||||
|
|
Loading…
Reference in New Issue