女生学网站设计,seo双标题软件,东莞公司想建网站,建设银行的英语网站首页大容量向量相似度TOPK搜索 解决这一问题的常用的算法学术话题解决向量检索问题的2个切入点索引结构向量量化向量检索方法选择 Faiss超大矩阵计算框架几种开源的向量检索开源库或框架Faiss能够做什么#xff1f;Faiss的核心搜索算法来源 最新的基于GPU实现的图结构的近似最近邻… 大容量向量相似度TOPK搜索 解决这一问题的常用的算法学术话题解决向量检索问题的2个切入点索引结构向量量化向量检索方法选择 Faiss超大矩阵计算框架几种开源的向量检索开源库或框架Faiss能够做什么Faiss的核心搜索算法来源 最新的基于GPU实现的图结构的近似最近邻算法GGNN论文提出的相关算法的执行顺序 基本描述 在图像异常检测应用中通过特征提取网络提取了大量的特征向量通过将提取的特征向量与之前存储的不同类别的特征向量集进行相似度比对寻早到最为相似的前TOPk个向量然后根据这些topk向量归属的类别将提取的特征向量进行类别划分以实现整个图像的分类判断进而实现异常的检测。 解决这一问题的常用的算法
学术话题
这一问题引发了大量的研究统称为向量检索 。 向量检索的定义 在一个给定向量数据集中按照某种度量方式检索出与查询向量相近的k个向量KNN但由于KNN计算量过大通常使用近似近邻问题进行替代。 度量方法 欧式距离、余弦距离、内积、海明距离。 欧式用于图片检索、余弦用于人脸识别、内积用于推荐、海明用于大规模视频检索。 评估向量检索效果的几个维度 召回率、速度、内存损耗。 召回率的计算方法 给定向量q其在数据集上的K近邻为N向量集,通过检索召回的K个近邻集合为M其中 K|N| (K等于N的模)。
解决向量检索问题的2个切入点
减少候选向量集----为了避免在左右候选集上进行计算引入了索引结构。降低单个向量计算的复杂度-----对向量进行量化处理。
索引结构
暴力搜索方法-----召回率100%,内存消耗大、速度慢。基于树结构的方法。速度较慢局部敏感哈希方法–不是适用于所有的度量方法。基于倒排的方法inverted file structure基于图的方法–KGraph、NSG、HNSW、NGT等图索引方法。基本检索步骤step1—选好入口点、step2—遍历图、step3----收敛。
向量量化
定义 将高纬度的向量映射到低纬度的向量空间上。
PQOPQ、LOPQ和二值处理。聚类方法K-means\k-means、one pass k-means\Yin Yang k-means内积转换可以直接用于图索引结构。
向量检索方法选择
量化图 基于图的索引结构同时引入向量量化操作减少处理的向量数据。 特点速度快缺点是内存空间消耗较大。图倒排 索引结构空间消耗小、且速度和召回率很好的均衡。
Faiss超大矩阵计算框架
几种开源的向量检索开源库或框架
开源向量检索框架或源代码库以及常见应用选择的案例
各种算法的demo实现
Faiss能够做什么
返回与查询向量最相近的k个检索向量。同时支持多个向量的搜索速度更快。支持使用精度换取时间和内存空间以10%的精度损失获取10倍的时间或空间。执行最大内积搜索而不是最小欧几里得搜索。对其他距离的支持也是有限的,比如L1Linf。返回查询点半径范围内的所有元素范围搜索。存储索引在硬盘上而不是在内存上。降低了内存需求
Faiss的核心搜索算法来源
内积量化方法PQ这是一种高维向量的一种有损压缩技术它能够实现在压缩的向量中进行相对准确的重建和距离计算。论文地址三级量化方法IVFADC-R论文地址优化的内积量化方法OPQ此方法可以看作是向量空间的线性变换使其更适合使用乘积量化器进行索引。论文地址内计量化器的距离预过滤方法。该方法在计算PQ距离之前会先执行一个二进制的滤波处理。论文地址GPU实现了更快的k搜索。论文地址HNSW索引方法-论文地址
所有内积量化以及相关方法的论文综述地址------内积量化
最新的基于GPU实现的图结构的近似最近邻算法GGNN
github源码地址 论文地址https://arxiv.org/abs/1912.01059
论文提出的相关算法的执行顺序 Created with Raphaël 2.3.0 开始 图没有构建(文件check) 多层搜索图构建BuildGraph(Data, L, k, tau_build) 图细化操作重复执行合并和对称链接操作 分层KNN的query(G,s,q,tau_query,k) 结束 yes no 多层图构建过程 多层图查询过程 源代码中的api的相关参数 相关参数的含义 // 用于创建距离计算和结果保存模板类的输入数据类型的设置
KeyT int32_t // 数据索引的类型这里应该是groudtruth数据中存储的向量类型其实就是base中的index
BaseT float // 支撑数据集向量元素的数据类型
ValueT float // 向量之间的距离值类型
BAddrT uint32_t // 用于访问数据集向量
GAddrT uint32_t // 用来访问领域向量的地址类型// 数据集的配置
FLAGS_tau
FLAGS_refinement_iterations 表示执行细化操作的迭代次数
D 数据的特征维度384维
measure 表示距离准则需要使用余弦距离Cosine或Euclidean
KBuild 表示构建图时图中每个节点的邻居数
KF 图中每个节点的最大逆向链接数其中必须满足 KBuild - KF S ?
S 构件图时将图划分成的子集块数推荐为32
L 构建几层图推荐为4
KOuery 在查询过程中要检索的最近的邻居的数量需要具体分析,时间与精度平衡// 具体的核心代码执行流程及功能
GGNN类模板类measure, KeyT, ValueT, GAddrT, BaseT, BAddrT, D, KBuild, KF, KQuery, S
GGNN类的初始化GGNN m_ggnn{FLAGS_base_filename, FLAGS_query_filename, FLAGS_groundtruth_filename, L, static_castfloat(FLAGS_tau)}; // 传递搜索数据集、查询数据集、真实数据集、图构建松弛参数
GGNN实例对象调用ggnnMain(FLAGS_graph_filename, FLAGS_refinement_iterations)函数构建搜索图传入图文件和图细化迭代次数
// ggnnMain函数首先判断传递的图文件是否存在,不存在执行构建操作存在的话判断当前文件是否存在并导出保存供下次调用// 执行build函数主要完成merge操作和对称链路// 执行图细化操作
// 下面开始执行向量检索操作// 将查询松弛参数tau_query写入到CUDA中// 执行m_ggnn.queryLayer32, 200, 256, 64进行分层查询操作传入的参数表示每层的批次数量// 获取分层查询的结果数据// 查询结果分为明确一点-----输出结果的存储一定在queryLayer中发生。// 结果保存在GGNNResults结构体实例对象的KeyT* h_sorted_ids_gpu和ValueT* h_sorted_dists_gpu的地址上。其他重要参数num_result结果数量 如何存储的呢// 结果数据的获取直接查看ggnn_result.evaluateResults()函数是比较快的方式。// 查询结果展示开源数据集SIFTIM格式介绍数据集地址 SIFT共有4个不同大小的数据集。其中ANN_SIFT10K-----ANN_GTST1M中包含4个子数据集具体的如下图所示注意对于ANN_SIFT1B采用的是.bvecs格式存储 在下面数据集中 groundtruth.ivecs存储的shape为10000100其中100指的是查询向量中的索引值、sift_query.fvecs的数据shape为(10000, 128) 上面几种数据集格式读取的python代码注意下面的代码仅仅适用于sift开源数据集
def fvecs_write(filename, arr): # 保存为浮点数的向量输入的arr的形式是什么N, D arr.shapewith open(filename, wb) as fp:for row in arr:d struct.pack(I, D)fp.write(d)for x in row:fp.write(struct.pack(f, float(x)))def ivecs_write(filename, arr): # 保存为整数型号的向量N, D arr.shapewith open(filename, wb) as fp:for row in arr:d struct.pack(I, D)fp.write(d)for x in row:fp.write(struct.pack(I, int(x)))def fvecs_read(filename, c_contiguousTrue): # 浮点型向量的读取fv np.fromfile(filename, dtypenp.float32)if fv.size 0:return np.zeros(0, 0)dim fv.view(np.int32)[0]assert dim 0fv fv.reshape(-1, 1 dim)if not all(fv.view(np.int32)[:, 0] dim):raise IOError(Non-uniform vector sizes in filename)fv fv[:, 1:]if c_contiguous:fv fv.copy()return fv# 从文件名称中创建np数据
def ivecs_read(filename, c_contiguousTrue):fv np.fromfile(filename, dtypenp.int32)if fv.size 0:return np.zeros(0, 0)dim fv.view(np.int32)[0] # 更改数据类型为int32,且查看该数组的第一个维度assert dim 0fv fv.reshape(-1, 1 dim) #if not all(fv.view(np.int32)[:, 0] dim):raise IOError(Non-uniform vector sizes in filename)fv fv[:, 1:]if c_contiguous:fv fv.copy()return fv# 阅读.bvecs格式的文件
def bvecs_read(filename, c_contiguousTrue):fv np.fromfile(filename, dtypenp.byte)if fv.size 0:return np.zeros(0, 0)dim fv.view(np.int32)[0] # 更改数据类型为int32,且查看该数组的第一个维度assert dim 0fv fv.reshape(-1, 4dim) #if not all(fv.view(np.int32)[:, 0] dim):raise IOError(Non-uniform vector sizes in filename)fv fv[:, 4:]if c_contiguous:fv fv.copy()return fv使用c读取fvecs和ivecs格式的数据,以及一些基本的数据操作
// CreatData.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。
//
#include windows.h
#include iostream
#include fstream
#include vector
#include ctime
#include algorithm
#include string
#include cmathusing namespace std;/*
brif 在指定范围内生成随机的数字
*/
float getRand(int min, int max)
{return (rand() % (max - min 1)) min;
}/*brif: 将单维向量数据保存到.txt文件
param len 表示向量的总长度
param dim 表示每个向量的长度
param over 是否覆盖之前的数据
*/
templatetypename T
void writeTxt(string savePath, T data, size_t len, size_t dim, bool overfalse)
{ofstream f;if (!over) {f.open(savePath, ios::trunc | ios::out);}else f.open(savePath, ios::app | ios::out);int j 0;for (j; j len; j) {if ((j1) % (dim) 0) // j 0{f *(dataj) \n;}else f *(dataj) ,;}f.close();return;
}/*brif: 将2维向量数据保存到.txt文件
*/
templatetypename T
void writeTxt2dim(string savePath, vectorvectorT data, bool overtrue)
{size_t len data.size();for (int i 0; i len; i) {writeTxt(savePath, data[i][0], data[i].size(), data[i].size(), over);}return;
}/*
brif 只找最好的一个
param dim true_dim 2, 3842386,
param baseNum表示查询向量条数1
param queryNum基础向量数据的向量条数5
param baseNum 表示基础向量集的条数
param dim 表示真实的存储维度// param knn 后续再进行修改
*/
vectorvectorfloat ComputerDis(float* query, float* base, int queryNum, int baseNum, int dim)
{vectorvectorfloat distances;distances.clear();if (query nullptr || base nullptr){return distances;}for (int query_id0; query_id queryNum; query_id) {vectorfloat temDis;for (int base_id 0; base_id baseNum; base_id) {// 计算两者之间的距离float* ptrStartQuery query query_id * dim; // 记录每个查询向量的起始指针float* ptrStartBase base base_id * dim; float computerDis 0;for (int i 0; i dim; i) {if (i 1) {computerDis (*ptrStartQuery) * (*ptrStartBase); // 不能将0和1索引值加上去}ptrStartQuery;ptrStartBase;}temDis.push_back(computerDis);}distances.push_back(temDis);}return distances;
}/*
brif 直接获取最佳的匹配向量的索引以及向量值、距离值。一般是在执行ComputerDis函数之后。
param distances是查询向量与基础向量之间的距离
param baseVector是基础向量
param indexBestVector是最佳索引
param disBestVector是最佳距离值
param BestMatchVector最佳匹配向量,
param dim: 向量的维度,这里的维度还是真实存储的维度而不是计算时所需的维度。
*/
void findBestMatchVector(vectorvectorfloat distances, float* baseVector, vectorsize_t indexBestVector, vectorfloat disBestVector, vectorvectorfloat BestMatchVector, size_t dim,size_t baseDataNum)
{size_t numObject 0;indexBestVector.clear();disBestVector.clear();BestMatchVector.clear();numObject distances.size();for (int i 0; i numObject; i) {vectorfloat::iterator biggest max_element(distances[i].begin(), distances[i].end());disBestVector.push_back(*biggest);size_t temIndex std::distance(begin(distances[i]), biggest);indexBestVector.push_back(temIndex);// 直接在baseVector中去查询对应的向量值vectorfloat PerBestMatchVector;PerBestMatchVector.clear();float* temStartPtr baseVector temIndex*dim;for (int k 0; k dim; k){PerBestMatchVector.emplace_back(*temStartPtr);temStartPtr 1;}BestMatchVector.push_back(PerBestMatchVector);}return;
}/*
brif 直接获取最佳KNN个的匹配向量的索引以及向量值、距离值。一般是在执行ComputerDis函数之后。
param distances是查询向量与基础向量之间的距离
param baseVector是支撑向量集合2384dim
param indexBestKnnVector是最佳索引
param disBestKnnVector是最佳距离值
param typeBestKnnVector是最佳类别向量
param dim: 向量的维度,这里的维度还是真实存储的维度而不是计算时所需的维度。
param Knn: 表示检索前k个相邻的向量 在进行数据标注的时候是100.
return: 返回每个查询向量的前Knn个最佳匹配的index、dis、type向量
*/
void findKnnBestMatchVector(vectorvectorfloat distances, float* baseVector, vectorvectorint IdBestKnnVector, vectorvectorint indexBestKnnVector, vectorvectorfloat disBestKnnVector, vectorvectorinttypeBestKnnVector, size_t dim, int Knn)
{size_t numObject 0;IdBestKnnVector.clear();disBestKnnVector.clear();typeBestKnnVector.clear();indexBestKnnVector.clear();numObject distances.size(); // 该numObject表示的是查询向量的长度distances[i].size()表示支撑向量集的长度for (int i 0; i numObject; i){vectorfloat temDis(distances[i]);// 从大到小进行排序sort(temDis.begin(), temDis.end());reverse(temDis.begin(), temDis.end());if (temDis.size() Knn) {cout 查询的K近邻数量超过了基础数据集的数量 endl;return;}vectorint indexTem;vectorfloat disTem;vectorint typeTem;vectorint IdTem;// 逐步取出前KNN个值for (int j 0; j Knn; j) {float value temDis[j];vectorfloat::iterator itr find(distances[i].begin(), distances[i].end(),value);int index distance(distances[i].begin(), itr);disTem.push_back(value); // 获取的是距离值进行保存indexTem.push_back(index); // 获取index进行保存IdTem.push_back((int)*(baseVector index * dim)); // 获取的是真实的id编号但是这样直接取值会存在问题typeTem.push_back((int)*(baseVector index * dim 1)); // 根据索引获取所属类别// cout 类别归属 .................. (int)*(baseVector index * dim 1) endl;}IdBestKnnVector.push_back(IdTem);indexBestKnnVector.push_back(indexTem);disBestKnnVector.push_back(disTem);typeBestKnnVector.push_back(typeTem);}return;
}/*
brif 将生成的数据保存为适用于ggnn的基本数据格式, 注意fvecs的基本格式是dim vectors 4 dim * 4
filename 表示存储的地址
vectorData 表示存储向量的指针地址
vectorNum 表示向量集的数据条数
dim 表示单个向量的维度比实际的数据长1
*/
void SaveToGgnn(const char* filename,float* vectorData, size_t vectorNum, size_t dim)
{float* GgnnVectorData new float[vectorNum*(dim-1)]; // 注意这里的dim-1是因为Anomaly中的数据比ggnn维度多一个for (int i 0; i vectorNum; i) {int j0, k 0;float* temStartPtr vectorData i * dim;for (j, k; k dim; k, temStartPtr1){if (k 0) {GgnnVectorData[i*(dim - 1) j] dim - 1; // 每一个向量的起始位存储的是向量的维度385dimj;} else if (k 1);else{GgnnVectorData[i*(dim - 1) j] *temStartPtr;j;}}}ofstream writeFile;// 必须保证filename以.fvecs结尾writeFile.open(filename, ios_base::binary | ios_base::out | ios_base::trunc);//ofstream writeFile(filename, ios_base::binary|ios_base::out|ios_base::trunc);if (!writeFile.is_open()){cout ................打开文件失败................. endl;return;}writeFile.write(reinterpret_castchar*(GgnnVectorData), sizeof(float)*vectorNum*(dim-1));writeFile.close();delete[] GgnnVectorData;
}/*
brif 读取存储的.fvecs数据并将数据转换为txt文档中
filename ggnn数据集的文件路径
data 读取的数据保存地址
num 向量条数保存地址
dim 向量维度保存地址
*/
void ReadGgnnToTxt(char* filename, float* data, unsigned num, unsigned dim)
{std::ifstream in(filename, std::ios::binary); //以二进制的方式打开文件if (!in.is_open()) {std::cout open file error std::endl;exit(-1);}in.read((char*)dim, 4); //读取向量维度in.seekg(0, std::ios::end); //光标定位到文件末尾std::ios::pos_type ss in.tellg(); //获取文件大小多少字节size_t fsize (size_t)ss;num (unsigned)(fsize / (dim 1) / 4); //数据的个数data new float[(size_t)num * (size_t)dim];in.seekg(0, std::ios::beg); //光标定位到起始处for (size_t i 0; i num; i) {in.seekg(4, std::ios::cur); //光标向右移动4个字节in.read((char*)(data i * dim), dim * 4); //读取数据到一维数据data中}for (size_t i 0; i num * dim; i) { //输出数据std::cout (float)data[i];if (!i) {std::cout ;continue;}if (i % (dim - 1) ! 0) {std::cout ;}else {std::cout std::endl;}}in.close();
}/*
brif 用于自动生成支撑和检索向量数据集
param storeDataPtr 表示存储生成数据集的指针
param ReadDim 表示真实的维度3842dim composion
param RealNum 表示生成向量的数量
*/
void GeneratorTestData(float* storeDataPtr, size_t ReadDim, size_t RealNum)
{for (int i 0; i ReadDim * RealNum; i){if (i % ReadDim 0){storeDataPtr[i] i / (int)ReadDim;}else if (i % ReadDim 1){storeDataPtr[i] 1;}else storeDataPtr[i] getRand(0.1, 100);}double temsum 0;for (int i 0; i ReadDim * RealNum; i){if (i % ReadDim ! 0 i % ReadDim ! 1){temsum storeDataPtr[i] * storeDataPtr[i];}}temsum sqrtf(temsum);for (int i 0; i ReadDim * RealNum; i){if (i % ReadDim ! 0 i % ReadDim ! 1){storeDataPtr[i] storeDataPtr[i] / temsum;}}return;
}/*
brif 用于保存生成的数据为Anomaly格式的二进制文件
param saveFile 表示保存的二进制文件地址
param DataNum 表示所有数据的条数
param Realdim 表示实际存储过程的向量实际维度3842
param generateData 传入的存储数据的指针
*/
void SaveDataToAnomaly(const char* saveFile, size_t DataNum, size_t Realdim, float* generateData)
{std::FILE *fp;fopen_s(fp, saveFile,wb);int m_featureN DataNum;int m_featureC Realdim-2; fwrite(m_featureN, sizeof(int), 1, fp);fwrite(m_featureC, sizeof(int), 1, fp);fwrite(generateData, sizeof(float), Realdim * DataNum, fp);fclose(fp);return;
}/*
brif: 用于计算向量检索的正确率,可以实现一对一的检测多对一多对多一对多
Anomaly检测结果.txt
GenerateLaw真实的最近邻索引.txt
Mutile1 anomalyDetecteID对应的数据是否为单列
lawID anomalyDetecteID对应的数据是否为单列
*/
float ComputerAccuracyOneToOne(const char* anomalyDetecteID, const char* lawID, bool Mutile1false, bool Mutile2false)
{vectorsize_t anomalyIds;vectorsize_t lawIds;ifstream aIdfile(anomalyDetecteID);ifstream lawIdfile(lawID);string line;if (aIdfile) {while (getline(aIdfile,line)){string TemValue ;if (Mutile1){size_t index line.find(,);TemValue line.substr(0,index);}else TemValue line;int temValue atoi(TemValue.c_str());anomalyIds.emplace_back(temValue);}}aIdfile.close();if (lawIdfile){while (getline(lawIdfile, line)){string TemValue1 ;if (Mutile2){size_t index line.find(,);TemValue1 line.substr(0, index);}else TemValue1 line;int temValue1 atoi(TemValue1.c_str());lawIds.emplace_back(temValue1);}}lawIdfile.close();cout Anamaly检测: anomalyIds.size() 标注的数据的数量 lawIds.size();if (anomalyIds.size()! lawIds.size()){cout 数据有误 endl;return 0;}size_t equalNum 0;for (int i 0; i anomalyIds.size(); i){if(anomalyIds[i] lawIds[i]) equalNum 1;}return (equalNum / (float)anomalyIds.size());
}/*
brif: 查看base.db数据集的结构并转换为.txt文件进行保存
baseDbPath 是存储base的.db路劲
saveTxtPath 是存储base的.txt路劲
saveTotxt 表示是否需要将读取的数据保存到txt中
buf 用于缓存读取的数据
m_Num 表示数据的条数
m_Dim 表示数据的维度
composion 表示数据实际存储的维度比m_Dim多几个数默认为2
*/
float* ReadDB(const char* baseDbPath, const char* saveTxtPath, bool saveTotxt, intm_Num, intm_Dim, int composion2)
{std::FILE *fp; fopen_s(fp, baseDbPath, rb);std::fread(m_Num, sizeof(int), 1, fp); std::fread(m_Dim, sizeof(int), 1, fp);//int num -1;//std::fread(m_Dim, sizeof(int), 1, fp);size_t m_Size m_Num * m_Dim * sizeof(float);if (0 m_Size){m_Num m_Dim 0;fclose(fp);return nullptr;}// float temValue 0;float* buf new float[m_Num * (m_Dim composion)];std::fread(buf, sizeof(float), m_Num * (m_Dim composion), fp);fclose(fp);if (saveTotxt) {ofstream f;f.open(saveTxtPath, ios::trunc | ios::out);for (int j 0; j m_Num; j){for (int k 0; k m_Dim composion; k){if (k m_Dim (composion-1)) f buf[j * (m_Dim composion) k] \n;else f buf[j * (m_Dim composion) k] ,;}}f.close();}return buf;
}/*
brif: 用于读取.db数据集可选择是否转换为.txt文件。注意使用后需要释放指针 这里相对于上面的函数做了些许调整。
*/
float* ReadDBOpt(const char* baseDbPath, const char* saveTxtPath, bool saveTotxt, intm_Num, intm_Dim, int composion 2)
{std::FILE *fp;std::fstream db_file(baseDbPath, std::ios::in | std::ios::binary);db_file.read((char*)m_Num, sizeof(int));db_file.read((char*)m_Dim, sizeof(int));size_t m_Size m_Num * m_Dim * sizeof(float);if (0 m_Size){m_Num m_Dim 0;db_file.close();return nullptr;}float* buf new float[m_Num * (m_Dim composion)];memset(buf, 0x00, m_Num * (m_Dim composion)*sizeof(float));int *L new int[386];memset(L, 0x00, 386 * sizeof(int));int id, type;for (int i 0; i m_Num; i){db_file.read((char*)L, 386 * sizeof(int));id L[0];type L[1];buf[i*(m_Dim composion)] (float)id;buf[i*(m_Dim composion)1] (float)type;for (int j 0; j 384; j) {buf[i*(m_Dim composion) j 2] ((float*)L 2)[j];}}db_file.close();delete[] L;if (saveTotxt){ofstream f;f.open(saveTxtPath, ios::trunc | ios::out);for (int j 0; j m_Num; j){for (int k 0; k m_Dim composion; k){if (k m_Dim (composion - 1)) f buf[j * (m_Dim composion) k] \n;else f buf[j * (m_Dim composion) k] ,;}}f.close();}return buf;
}int main()
{int funId 5;/*brif: 用于对比Anomaly检索结果与查询向量真实的最接近向量索引进行对比获得anomaly检索精度。*/if (funId 0){string anomalyDetecteID D:\\GenerateData\\GenerateDataLaw\\bestMatchIndex.txt;string lawID D:\\GenerateData\\AnomalyGenerateData\\AnomalyBestIndex_id.txt;float accuracyResult ComputerAccuracyOneToOne(anomalyDetecteID.c_str(), lawID.c_str());cout ................计算的准确率为 accuracyResult ..................... endl;}/*brif: 查看Base.DB数据集的结构并保存到C:\\Users\\admin\\Desktop\\CompareTest\\BaseData\\test.txt中base.db: C:\\Users\\admin\\Desktop\\CompareTest\\BaseData\\test.db*/else if (funId 1){int m_Num 0, m_Dim 0;float* tembuff nullptr;std::string baseDbPath C:\\Users\\admin\\Desktop\\CompareTest\\BaseData\\1516_up.db;std::string saveTxtPath C:\\Users\\admin\\Desktop\\CompareTest\\BaseData\\test.txt;tembuff ReadDBOpt(baseDbPath.c_str(), saveTxtPath.c_str(), true, m_Num, m_Dim);delete tembuff;tembuff nullptr;//ReadDB();}/*brif: 标注提取的全图特征获得2张图全部特征对应与base特征中真实的id序号、类别号、距离值直接保存前40个最相近的数据值.............................ok。step1: 加载whole.db数据以及base.db到内存step2: 使用暴力搜索算法计算出whole中每个向量与base.db中全部向量之间的距离。并选出前40个与base最相似的向量索引以及距离值。保存的数据简介 groudtrue_id(389376, 100(int)); groudtrue_dis(389376, 100(float)), groudtrue_type(389376, 100(type类型));*/else if (funId 2){// step1: 加载全图db和Base.db数据集std::string baseDbPath C://Users//admin//Desktop//CompareTest//wholeFeatures//base1.db; // C:\\Users\\admin\\Desktop\\CompareTest\\BaseData\\4242_up.db;std::string wholeDbPath C://Users//admin//Desktop//CompareTest//wholeFeatures//Whole12.db; // C://Users//admin//Desktop//CompareTest//wholeFeatures//Whole1_up.db;/*std::string baseDbPath C://Users//admin//Desktop//CompareTest//wholeFeatures//base1.db;std::string wholeDbPath C://Users//admin//Desktop//CompareTest//wholeFeatures//Whole12.db;*/int m_NumBase 0, m_DimBase 0, m_NumWhole 0, m_DimWhole 0;float* Base ReadDBOpt(baseDbPath.c_str(), NULL, false, m_NumBase, m_DimBase);float* Whole ReadDBOpt(wholeDbPath.c_str(), NULL, false, m_NumWhole, m_DimWhole);// step2计算whole向量与base向量之间的距离考虑使用opencv的CUDA变成提速vectorvectorfloat WholeAndBaseDistance;WholeAndBaseDistance ComputerDis(Whole, Base, m_NumWhole, m_NumBase, m_DimBase 2);if (WholeAndBaseDistance.size() 0){return 0;}delete[] Whole; Whole nullptr;// step3: 算出每个查询向量最佳匹配值的前100个dis以及对应的索引值.需要将数据进行保存vectorvectorint groudTrue_id;vectorvectorint groudTrue_Index;vectorvectorfloat groudTrue_dis;vectorvectorint groudTrue_type;// 直接获取前100个最近邻的数据,包括index\id\type\distanceint Knn 100;findKnnBestMatchVector(WholeAndBaseDistance, Base, groudTrue_id, groudTrue_Index, groudTrue_dis, groudTrue_type, m_DimBase 2, Knn);cout 类别id的长度 groudTrue_type.size() Knn: groudTrue_type[0].size() groudTrue_type[0][0];delete[] Base; Base nullptr;// 将所得结果保存到.txt文件;string trueIdTxtPath C:\\Users\\admin\\Desktop\\CompareTest\\MarkingGlobalFeatures\\trueIdMark.txt; // (389376, 100) 保存idstring trueIdexTxtPath C:\\Users\\admin\\Desktop\\CompareTest\\MarkingGlobalFeatures\\trueIndexMark.txt; // (389376, 100) 保存indexstring trueDisTxtPath C:\\Users\\admin\\Desktop\\CompareTest\\MarkingGlobalFeatures\\trueDiMark.txt; // (389376, 100) 保存距离string trueTypeTxtPath C:\\Users\\admin\\Desktop\\CompareTest\\MarkingGlobalFeatures\\trueTypeMark.txt; // (389376, 100) 保存类别writeTxt2dim(trueIdTxtPath, groudTrue_id, true);writeTxt2dim(trueIdexTxtPath, groudTrue_Index, true);writeTxt2dim(trueTypeTxtPath, groudTrue_type, true);writeTxt2dim(trueDisTxtPath, groudTrue_dis, true);groudTrue_dis.clear();groudTrue_type.clear();groudTrue_id.clear();// 将knn的索引进行保存主要是前100个auto add [](vectorvectorint idVector, const char* dbPath, int Knn){std::FILE *fp;fopen_s(fp, dbPath, wb);int m_featureDim Knn;for (int i 0; i idVector.size(); i){fwrite(Knn, sizeof(int), 1, fp);fwrite(idVector[i][0], sizeof(int), idVector[i].size(), fp);}fclose(fp);return;};string groudTrueIndexIvecs C:\\Users\\admin\\Desktop\\CompareTest\\GGNNBaseData\\GroundTruthBig.ivecs;add(groudTrue_Index, groudTrueIndexIvecs.c_str(), Knn);groudTrue_Index.clear();}/*brif: 将whole和base数据集转换为适用于GGNN数据的输出数据。........................................................ok*/else if (funId 3){string queryWholeFvecs C:\\Users\\admin\\Desktop\\CompareTest\\GGNNBaseData\\Query.fvecs;string BaseFvecs C:\\Users\\admin\\Desktop\\CompareTest\\GGNNBaseData\\Base.fvecs;// 读取数据Whole和Base数据集到vectorint m_Num_base 0, m_Dim_base 0;int m_Num_query 0, m_Dim_query 0;std::string baseDbPath C://Users//admin//Desktop//CompareTest//wholeFeatures//base1.db;std::string wholeDbPath C://Users//admin//Desktop//CompareTest//wholeFeatures//Whole12.db;std::string baseTxt C:\\Users\\admin\\Desktop\\CompareTest\\BaseData\\base1.txt;std::string wholeTxt C://Users//admin//Desktop//CompareTest//wholeFeatures//Whole12.txt;float* BaseDataPtr ReadDBOpt(baseDbPath.c_str(), baseTxt.c_str(), true, m_Num_base, m_Dim_base);float* QueryDataPtr ReadDBOpt(wholeDbPath.c_str(), wholeTxt.c_str(), true, m_Num_query, m_Dim_query);auto add [](const char*savePath, float* idVector, int num, int dim){std::FILE *fp;fopen_s(fp, savePath, wb);float* temPtr nullptr;for (int i 0; i num; i){temPtr idVector i * (dim 2) 2;fwrite(dim, sizeof(int), 1, fp);fwrite(temPtr, sizeof(float), dim, fp);if (i 0) // 用于查看query和base数据集都是进行了归一化处理{for (int j 0; j 40; j){cout *(temPtr j) ,;}cout endl endl;}}fclose(fp);return;};add(BaseFvecs.c_str(), BaseDataPtr, m_Num_base, m_Dim_base);add(queryWholeFvecs.c_str(), QueryDataPtr, m_Num_query, m_Dim_query);delete[] BaseDataPtr;delete[] QueryDataPtr;}/*brif: 查看ivecs以及fvecs数据集*/else if (funId 4){int m_Num 4006, m_Dim 385;float* tembuff nullptr;std::string baseDbPath C:\\Users\\admin\\Desktop\\CompareTest\\GGNNBaseData\\WholeQuery.fvecs;std::string saveTxtPath C:\\Users\\admin\\Desktop\\CompareTest\\GGNNBaseData\\GroundTruth.txt;std::FILE *fp;fopen_s(fp, baseDbPath.c_str(), rb);int Dim 0;tembuff new float[m_Num * (m_Dim 1)];for (int i 0; i m_Num * (m_Dim 1); i){std::fread(Dim, sizeof(uint32_t), 1, fp);tembuff[i] Dim;}fclose(fp);ofstream f;f.open(saveTxtPath, ios::trunc | ios::out);for (int j 0; j m_Num; j){for (int k 0; k (m_Dim 1); k){if (k m_Dim) f tembuff[j * (m_Dim 1) k] \n;else f tembuff[j * (m_Dim 1) k] ,;}}f.close();delete[] tembuff;tembuff nullptr;}/*brif: 统计Anomaly和GGNN的 index检索正确率以及分类正确率*/else if(funId 5) {string AnomalyIndex C:\\Users\\admin\\Desktop\\CompareTest\\AnomalyResult\\AnomalyBestIndex_id.txt;string MarkingIndex C:\\Users\\admin\\Desktop\\CompareTest\\MarkingGlobalFeatures\\trueIndexMark.txt;string GGNNIndex C:\\Users\\admin\\Desktop\\CompareTest\\GGNNresult\\GgnnBeseKnnIndex.txt;string AnomalyType C:\\Users\\admin\\Desktop\\CompareTest\\AnomalyResult\\AnomalyBestType.txt;string MarkingType C:\\Users\\admin\\Desktop\\CompareTest\\MarkingGlobalFeatures\\trueTypeMark.txt;string GGNNType C:\\Users\\admin\\Desktop\\CompareTest\\GGNNresult\\GGnnBestType.txt;// index准确率float accuaracyIndex1 ComputerAccuracyOneToOne(AnomalyIndex.c_str(), MarkingIndex.c_str(), false, true);float accuaracyIndex2 ComputerAccuracyOneToOne(GGNNIndex.c_str(), MarkingIndex.c_str(), true, true);// 分类准确率//float accuaracyIndex3 ComputerAccuracyOneToOne(AnomalyType.c_str(), MarkingType.c_str(), false, true);//float accuaracyIndex4 ComputerAccuracyOneToOne(GGNNType.c_str(), MarkingType.c_str(), false, true);cout Anomaly检索准确率 accuaracyIndex1 GGNN检索准确率 accuaracyIndex2 endl;//cout Anomaly分类准确率 accuaracyIndex3 GGNN分类准确率 accuaracyIndex4 endl;}/*brif: 更具Anomaly检测的数据去查询对应的id和类别信息*/else if (funId 6) {// 读取Base数据集string BaseData C:\\Users\\admin\\Desktop\\CompareTest\\BaseData\\4242_up.db;int m_Num_base 0, m_Dim_base 0;float* BaseDataPtr ReadDBOpt(BaseData.c_str(), , false, m_Num_base, m_Dim_base);// 读取anomaly的检索结果.txt数据去获取id和typevectorsize_t anomalyIndexs;string AnomalyTxt C:\\Users\\admin\\Desktop\\CompareTest\\GGNNresult\\GgnnBeseKnnIndex.txt;ifstream lawIdfile(AnomalyTxt.c_str());string line;if (lawIdfile){while (getline(lawIdfile, line)){int temValue atoi(line.substr(0, line.find(,)).c_str());anomalyIndexs.emplace_back(temValue);}}lawIdfile.close();vectorsize_t anomalyIds;vectorsize_t anomalyTypes;for (int i 0; i m_Num_base; i){anomalyIds.push_back(*(BaseDataPtr i*(m_Dim_base2)));anomalyTypes.push_back(*(BaseDataPtr i * (m_Dim_base 2)1));}delete[] BaseDataPtr;BaseDataPtr nullptr;// 将数据写入到指定文件txtofstream index, type;// //C:\\Users\\admin\\Desktop\\CompareTest\\GGNNresult\\GgnnBeseKnnIndex.txtindex.open(C:\\Users\\admin\\Desktop\\CompareTest\\GGNNresult\\GGnnBestId.txt, ios::trunc | ios::in | ios::out);type.open(C:\\Users\\admin\\Desktop\\CompareTest\\GGNNresult\\GGnnBestType.txt, ios::trunc | ios::in | ios::out);for (int i 0; i anomalyIds.size(); i){if (i anomalyIds.size()-1){index anomalyIds[i] \n;type anomalyTypes[i] \n;}else {index anomalyIds[i];type anomalyTypes[i];}}index.close();type.close();}/*brif: 使用随机生成函数生成适用于Anomaly和GGNN测试的数据集并保存为.txt文件和.db文件以及.fvecs文件。包括标注文件*/else if (funId 7) {/*step1: 生成自定义的anomaly数据集 dim: 表示向量真实数据的维度composion 表示idx和type所占用的位置数queryNum 表示查询向量的条数baseNum 表示支撑向量的条数baseData 存储支撑向量数据指针queryData 存储查询向量指针*/srand(time(0));size_t dim 384; int composion 2;size_t queryNum 16384; // 389376;size_t baseNum 250000; // float* baseData new float[(dim composion) * baseNum];float* queryData new float[(dim composion) * queryNum];/*step2: 下面是用于生成支撑向量数据集并对数据进行归一化处理*/GeneratorTestData(baseData, dim composion, baseNum);/*step3: 生成检索数据集并进行归一化处理*/GeneratorTestData(queryData, dim composion, queryNum);/*step4: 将上面生成的baseData和queryData数据保存为txt文件 D:\\NewAnomaly\\buildTestData\\CreatData\\base.txt 存储支撑数据集 D:\\NewAnomaly\\buildTestData\\CreatData\\query.txt 存储查询数据集*//*writeTxt(D:\\GenerateData\\GenerateDataLaw\\Aomalybase.txt, baseData, (dim composion) * baseNum, (dim composion));writeTxt(D:\\GenerateData\\GenerateDataLaw\\Anomalyquery.txt, queryData, (dim composion)* queryNum, (dim composion));*//*step5: 将生成的DB数据保存到指定的二进制文件中param baseDb 表示基础数据集param queryDb 表示查询数据集*/std::string baseDb D:\\GenerateData\\GenerateDataLaw\\AnomalyBaseDB.db;std::string queryDb D:\\GenerateData\\GenerateDataLaw\\AnomalyQueryDB.db;SaveDataToAnomaly(baseDb.c_str(), baseNum, dim composion, baseData);SaveDataToAnomaly(queryDb.c_str(), queryNum, dim composion, queryData);/*step6: 将生成的数据转换为GGNN项目需要的数据格式1 使用ComputerDis函数计算查询向量到支撑集向量之间的距离2 findBestMatchVector将1中的计算结果用于获取每一个查询向量与支撑集向量最近似的向量之间的距离、索引值、真实的向量数据3: 将检索的结果保存到二进制文件以及txt文件中param baseVector 是生成的支撑向量集param indexBestVector 存储查询向量对应的最佳索引param disBestVector 存储查询向量对应最佳向量的距离param BestMatchVector 存储查询向量最佳匹配向量*//*vectorvectorfloat AllDisQueryAndBase;AllDisQueryAndBase ComputerDis(queryData, baseData, queryNum, baseNum, dim composion);*/// vectorfloat baseVector;/*vectorsize_t indexBestVector;vectorfloat disBestVector;vectorvectorfloat BestMatchVectorValue;findBestMatchVector(AllDisQueryAndBase, baseData, indexBestVector, disBestVector, BestMatchVectorValue, dim composion, baseNum);*//* brif: 相当于获取到了查询向量的grundTrue数据1 BestMatchIndex 存储索引2 BestMatchDistance 存储最佳向量的距离3 BestMatchVector 存储最佳向量*/std::string BestMatchIndex D:\\GenerateData\\GenerateDataLaw\\bestMatchIndex.txt;std::string BestMatchDistance D:\\GenerateData\\GenerateDataLaw\\bestMatchDis.txt;std::string BestMatchVector D:\\GenerateData\\GenerateDataLaw\\bestMatchVector.txt;writeTxt(BestMatchIndex, indexBestVector[0], queryNum, 1);writeTxt(BestMatchDistance, disBestVector[0], queryNum, 1);writeTxt2dim(BestMatchVector, BestMatchVectorValue);/*1 再将生成的数据存储为适合GGNN输入的数据格式*/std::string GGnnQueryPath D:\\GenerateData\\GenerateDataLaw\\GGNNQuery.fvecs;std::string GGnnBasePath D:\\GenerateData\\GenerateDataLaw\\GGNNBase.fvecs;SaveToGgnn(GGnnQueryPath.c_str(), queryData, queryNum, dim composion);SaveToGgnn(GGnnBasePath.c_str(), baseData, baseNum, dim composion);/*释放内存*/delete[] baseData; baseData nullptr;delete[] queryData; queryData nullptr;}
}