译者|朱宪忠评论|孙淑娟介绍神经网络嵌入可以实现输入数据的低维表示,从而服务于各种类型的神经网络应用。嵌入具有一些有趣的功能,因为它们捕获数据点的语义。这对于图像和视频等非结构化数据特别有用,在这些数据中,不仅可以对像素级相似性进行编码,还可以对一些更复杂的关系进行编码。使用FiftyOne和Plotly可视化BDD100K数据集的嵌入并对这些嵌入执行搜索可以应用于许多场景,例如分类任务、构建推荐系统,甚至异常检测任务。对这些任务的嵌入执行最近邻搜索的主要好处之一是您不需要为每个新问题创建自定义网络;您通常可以使用预训练模型。此外,完全可以使用一些公开可用模型生成的嵌入,而无需任何进一步的微调。虽然有许多涉及嵌入的强大用例,但在执行嵌入式搜索的工作流程中通常存在不同程度的挑战。具体来说,对大型数据集执行最近邻搜索,然后有效地对搜索结果采取行动——例如执行自动标记数据等工作流——都提出了技术和工具方面的挑战。为此,两个开源软件Qdrant和FiftyOne可以帮助简化这些工作流任务。Qdrant是一个开源矢量数据库,旨在对密集的神经嵌入执行近似最近邻搜索(ANN),这对于任何预期扩展到大数据量的生产就绪系统都是必不可少的。FiftyOne是一种开源数据集管理和模型评估工具,可让开发人员高效地管理和可视化数据集、生成嵌入并改进模型结果。在本文中,我们将MNIST数据集加载到FiftyOne中,并基于ANN进行分类。通过从训练数据集中最近的K个点中选择最频繁的参考答案标签来对数据点进行分类。换句话说,对于每个测试样本,我们将使用选定的距离函数选择它的K个最近邻居,然后通过投票选出最佳标签。另一方面,向量空间中的所有搜索都将使用Qdrant来完成以提高速度。然后我们将在FiftyOne中评估这种分类的结果。安装如果您想开始使用Qdrant的语义搜索,您需要运行它的一个实例,因为该工具以客户端-服务器方式工作。最简单的方法是使用官方Docker映像之一并仅使用一个命令启动Qdrant:dockerrun-p"6333:6333"-p"6334:6334"-dqdrant/qdrant在命令后运行,我们将运行Qdrant服务器,HTTPAPI暴露在端口6333上,gRPC接口暴露在端口6334上。此外,我们需要安装一些Python包。我们将使用FiftyOne可视化数据、它们的参考答案标签以及嵌入式相似性模型预测的数据。嵌入将通过torchvision中可用的MobileNetv2创建。当然,我们还需要以某种方式与Qdrant服务器进行通信,并且由于我们将使用Python,Qdrant_client是实现此目的的首选方式。pipinstallfiftyonepipinstalltorchvisionpipinstallqdrant_client总体任务流程1.加载数据集2.生成嵌入3.将嵌入加载到Qdrant中4.最近邻分类5.FiftyOne评估加载数据集我们需要采取几个步骤才能使事情正常进行.首先,我们需要加载MNIST数据集并从中提取训练样本,因为我们将在搜索操作中使用它们。为了让一切更快,我们不会使用所有样本,只使用2500个样本。我们可以使用FiftyOne数据集Zoo并使用一行代码加载所需的MNIST子集。importfiftyoneasfoimportfiftyone.zooasfoz#加载数据dataset=foz.load_zoo_dataset("mnist",max_samples=2500)#获取所有训练样本train_view=dataset.match_tags(tags=["train"])接下来,让我们取仔细查看FiftyOne应用程序中使用的数据集。#在FiftyOne中可视化数据集session=fo.launch_app(train_view)生成嵌入下一步是在数据集中的样本上生成嵌入。这始终可以在FiftyOne之外使用您的自定义模型完成。然而,FiftyOne在其FiftyOneModelZoo中也提供了各种模型,可以直接用于生成嵌入。在此示例中,我们使用在ImageNet上训练的MobileNetv2来计算每个图像的嵌入。#计算每张图片的embeddingmodel=foz.load_zoo_model("mobilenet-v2-imagenet-torch")train_embeddings=train_view.compute_embeddings(model)将embedding结果加载到QdrantQdrant不仅可以存储向量,还可以存储一些对应的属性——每个数据点都有一个关联的向量,可选地伴随一个JSON类型的属性项。我们想用它来传递参考答案标签,以确保我们以后可以做出预测。ground_truth_labels=train_view.values("ground_truth.label")train_payload=[{"ground_truth":gt}forgtinground_truth_labels]创建嵌入后,我们可以开始与Qdrant服务器通信。应该注意的是,拥有QdrantClient的类实例是很有用的,因为它包含所有必要的方法。让我们连接并创建一个名为“mnist”的点集合。矢量大小取决于模型输出;因此,如果我们以后想尝试不同的模型,我们需要导入不同的模型,但其余的将保持不变。最后,在确保集合存在之后,我们可以发送所有向量及其包含真实标签的有效负载。importqdrant_clientasqcfromqdrant_client.http.modelsimportDistance#将训练好的嵌入加载到Qdrantdefcreate_and_upload_collection(embeddings,payload,collection_name="mnist"):client=qc.QdrantClient(host="localhost")client.recreate_collection(collection_=collection_name,vector_size=embeddings.shape[1],distance=Distance.COSINE,)client.upload_collection(collection_name=collection_name,vectors=embeddings,payload=payload,)returnclientclient=create_and_upload_collection(train_embeddings,train_classificationpayload)最近邻进行推理一个数据集。我们可以为测试数据集创建一个嵌入,但忽略groundtruth,并尝试使用ANN找到它,然后比较两者是否匹配。让我们从逐步创建嵌入开始。#通过选择每个样本邻域中最常见的标签,将标签分配给测试嵌入。让我们迭代测试数据集的样本和相应的嵌入,并使用搜索操作从训练集中找到15个最接近的嵌入。我们还需要选择有效载荷,因为它们包含找到特定点附近最常见标签所需的参考答案标签。在Python的Counter类的帮助下,我们可以避免重写任何样板代码。在FiftyOne的每个测试样本上,最常见的标签将存储为“ann_production”。这些内容反映在以下函数中。此函数将嵌入向量作为输入,并使用Qdrant搜索函数找到测试嵌入的最近邻居,生成类别预测,并返回FiftyOne分类对象,我们可以将其存储在FiftyOne数据集中。importcollectionsfromtqdmimporttqdmdefgenerate_fiftyone_classification(embedding,collection_name="mnist"):search_results=client.search(collection_name=collection_name,query_vector=embedding,with_payload=True,top=15,)#计算每种类型出现的次数,并选择最常见标签,置信度估计为最常见标签的出现次数除以结果总数(1)[0]confidence=occurrences_num/sum(counter.values())prediction=fo.Classification(label=predicted_class,confidence=confidence)returnpredictionpredictions=[]#调用Qdrant寻找最近的数据点嵌入tqdm(test_embeddings):prediction=generate_fiftyone_classification(embedding)predictions.append(prediction)test_view.set_values("ann_prediction",predictions)我们通过计算t来估计置信度属于最常见标签的样本部分。这让我们直观地了解我们在预测每个案例的标签时有多确定,并且可以在FiftyOne中使用它来轻松发现混淆的样本。FiftyOne评估现在是得出一些结果的时候了!让我们从可视化这个分类器的性能开始。我们可以轻松启动FiftyOne应用程序来查看参考答案标签、预测结果和图像。session=fo.launch_app(test_view)FiftyOne提供了多种内置方法来评估模型预测,包括图像和视频数据集上的回归、分类、检测、多边形、实例和语义分割。通过下面两行代码,我们可以计算并打印分类器的评估报告。#根据ground_truth=test_view.evaluate_classifications("ann_prediction",gt_field="ground_truth",eval_key="eval_simple")中的值评估ANN预测结果#显示分类指标results.print_report()评估FiftyOne后,我们可以使用结果对象生成一个交互式混淆矩阵(https://voxel51.com/docs/fiftyone/user_guide/plots.html#confusion-matrices),允许我们点击单元格并自动更新应用程序以显示相应的样本。plot=results.plot_confusion_matrix()plot.show()我们可以更进一步。我们可以使用FiftyOne精密的查询语言轻松找到所有与现实不符的预测,但对预测的置信度很高。这些通常是数据集中最令人困惑的样本,但也是我们可以从中获得最多洞察力的样本。fromfiftyoneimportViewFieldasF#显示FiftyOne应用程序,但仅包括以合理置信度预测的错误预测>0.7))session.view=false_view上图显示了模型中最令人困惑的样本,正如您所看到的,与数据集中的其他图像相比,它们非常不规则。我们可以采取的提高模型性能的下一步可能是使用FiftyOne添加像这样的准确样本。然后可以通过FiftyOne和CVAT之间的集成以及Labelbox等工具对这些样本进行注释。此外,我们可以使用更多的向量进行训练,或者通过相似性学习对模型进行微调,例如使用三元组损失算法。但就目前而言,这个使用FiftyOne和Quadrant的向量相似性分类示例效果很好。就这么简单,我们使用FiftyOne和Qdrant作为嵌入后端创建了一个ANN分类模型,因此寻找向量之间的相似性不再像传统的k-NN那样成为我们任务的瓶颈。亲自尝试最后,Github存储库中的Notebook文件包含您在本文中看到的所有内容的源代码。此外,它还包括在BDD100K道路场景数据集上执行夜间和白天属性预注释过程的实际用例。总之,FiftyOne和Qdrant这两个开源库可以一起使用,以高效地对嵌入执行最近邻搜索并对图像和视频数据集的结果进行操作。这个过程的美妙之处在于它的灵活性和可重复性。您可以轻松地将新字段的附加参考答案标签加载到FiftyOne和Qdrant中,并使用现有嵌入重复此预注释过程。这可以快速降低注释成本并更快地生成更高质量的数据集。译者介绍朱宪忠,社区编辑,专家博主,讲师,潍坊某高校计算机教师,自由编程资深人士。原标题:NearestNeighborEmbeddingsSearchWithQdrantandFiftyOne,作者:EricHofesmann
