当前位置:首页|资讯

一文看懂如何实现照片图片的相似性模糊搜索(ASP.Net Framework 4.8 + IIS + ML大模型

作者:电脑不爱好者发布时间:2024-10-19

本人不擅长人工智能领域研究,以下内容仅代表本人的粗浅理解,极有可能使用了错误的概念和名词,请酌情理解。

工作上需要,给网站增加图片的相似度搜索功能,类似淘宝那种,通过拍照上传图片照片,搜索相似的商品。花费一周时间,各种试水跳坑,最终功能实现。欣喜之后,特将我的心得体会分享整理出来。没有高深的技术用语,以便于初学者理解。

最初,并没有考虑使用机器学习的方式来实现,觉得这种高深技术,不是一般单机服务器可以用的,而是通过云服务调用接口使用,比如百度云阿里云各种云,都提供了人工智能的相关接口,上传照片给云端接口后,云端返回一个分析结果。

当然某云也有图片相似度搜索,价格没有几千下不来,入库和检索,分别独立收费,1500 + 1700 = 3200 元/年,起步,公司也承受不住这个费用。

要在公司自己的服务器上实现这种非人工智能的方式,也不是没有实现方法。

均值哈希算法

均值哈希算法(Average Hash Algorithm)是一种用于图像识别的哈希算法。它通过将图像缩小到 8x8 的尺寸,并将每个像素转换为 64 级灰度,然后计算所有像素的灰度平均值。每个像素的灰度值与平均值比较,大于或等于平均值的记为 1,小于平均值的记为 0,最终得到一个 64 位的二进制值,即图像的指纹。

拿两张图片做测试

测试图片原图

图片中,小男孩的帽子顶部中间有颜色区别

第一步:缩小到 8*8 尺寸(下图为放大 3200 倍后的样式)

帽子顶部有颜色差异

一共得到 8 * 8 = 64 个像素点

第二步:转换为灰度图片(下图为放大 3200 倍后的样式)

帽子顶部有颜色差异

图片中,每一个像素点的颜色,都是由 红 R 绿 G 蓝 B,三种颜色数值构成

灰度转换有一个公认的换算公式。对大多数人来说,绿色最亮,红色次之,蓝色最暗。已知人类感知到的 R、G、B 的亮度比例约为 3:6:1。按照比例计算 灰度(亮度)的转换公式为:

灰度值 = 0.299 * R + 0.587 * G + 0.114 * B

当然,还有一种更简单的换算公式:

灰度值 = (R + G + B) / 3

这样转换后的图片,某一个像素点的 R \ G \ B 三个数值,均等于相同的灰度值

例如:转换前 R = 248, G = 67, B = 98,转换后 R = 129, G = 129, B = 129

第三步:计算灰度平均值

将 64 个像素的每个像素的点的 RGB 其中一个值相加,再除以 64,就得到灰度平均值。因为 像素点转换为灰度后,RGB 三个数值都一样,用哪个值都可以

第四步:遍历每个像素,与平均值比较

将 64 个像素的每个像素点的 RGB 其中一个值,与平均值比较,如果大于等于平均值,记为 1,小于平均值记为 0

第五步:得到数组结果值

第六步:比较结果之间的差异(汉明距离)

‌‌汉明距离(Hamming Distance)‌是一种用于比较两个等长字符串之间差异性的度量。它衡量了两个字符串之间在相同位置上不同字符的数量。

上面右边图片黄色标记出来的为差异数值,可以得知汉明距离为 6,有 6 个像素点的差异。

用均值哈希算法,将每张图片都处理后得到的数组,存入数据库表。通过上传图片得到的数组,去遍历数据表,与表里的每个数组计算比较汉明距离,如果小于 6,就算做接近的图片。这种方式,经过测试,准确率不高,如果数据表数据量较大,例如 15 万条图片数据,搜索耗时较长,用时 20 秒左右,非常影响用户体验。

ONNX Runtime

那么如何使用机器学习(ML)的方式,在自有服务器上搭建图片相似度识别功能呢?经过大量查阅,最终选择了 ONNX Runtime 运行时组件。

ONNX Runtime 是一款跨平台、高性能的机器学习推理和训练加速器,可与 PyTorch、Tensorflow/Keras、TFLite、scikit-learn 和其他框架中的模型一起使用。ONNX Runtime 的优点在于它适用于多种编程语言,并且模型和权重兼容。

通俗点理解,ONNX 可以使用多种开发语言,结合已经训练好的模型库,进行推理计算。因为本人使用的是 .Net Framework 框架开发,ONNX 恰好也支持。

该网站提供了 40 多万个模型文件,其中 clip-image-vit-32-float32.onnx 模型文件,来自于:https://huggingface.co/rocca/openai-clip-js/tree/main

clip-image-vit-32-float32.onnx 文件名中的有其内在的含义。

CLIP(Contrastive Language-Image Pre-Training 对比「语言-图像」预训练)是 OpenAI 于 2021 年开发的一种模型(https://openai.com/index/clip/),可以为文本和图像创建嵌入(Embeddings)。这些嵌入存在于同一个向量空间中,可以在两种模态之间进行比较。

CLIP 是一组模型。有 9 个图像编码器、5 个卷积编码器和 4 个 Transformer 编码器。卷积编码器是 ResNet-50、ResNet-101 和类似 EfficientNet 的模型,称为 RN50x4、RN50x16、RN50x64(数字越大,模型越好)。Transformer 编码器全名是 Vision Transformer(或称之为 ViT):ViT-B/32、ViT-B/16、ViT-L/14 和 ViT-L/14@336。只有 ViT-L/14@336在分辨率为 336×336 像素的图像上进行微调,其他的则在 224×224 像素上进行训练。

所以,这个模型文件的含义是:针对 image 图片使用 ViT-B/32 编码器,进行 Float32 浮点运算训练的 CLIP 模型。

通过 ML 模型进行图片向量化

现实中,物体之间的相似度比较,会通过观察物体的宽高尺寸,纹理色泽,内外轮廓等来进行判断。而在计算机体系内,一切都是数据,就需要把图片转换为数据,由模型文件进行推理演算。

clip-image-vit-32-float32 模型要求输入图像的尺寸为 224 x 224像素。

首先,把一张图片进行等比缩放,然后进行居中裁切,只取中间的 224 * 224 区域

接着,进行 224 * 224 次遍历,将每一个像素点的 RGB 红绿蓝的数值取出写入到“张量/数组”。

什么是 Tensors(张量)?一个标量(一个数字)是 0 维度,例如:3,一个向量有 1 维,例如:[3],一个矩阵有 2 维,例如:[3, 5],一个张量有 3 维或更多,例如:[3, 5, 7]。张量或向量或矢量,其实就是编程里数组的另一种叫法。

最后,代入模型文件,进行运算,得到 JSON 格式数组

最终输出的是这样的 JSON 数据

输出了一个 512 个维度的数组,也可称作向量/矢量(Vector)。这些数据根本无法看出与图片有任何关系,这些数据只是一个高维度的坐标系内的一个个定位坐标点,如果转换为三维数组,便可很好理解,如下图:

与猫相关相似性的坐标点聚集在一个区域范围,越靠近猫的中心点,越符合猫的特征,与猫接近的区域是狗,因为狗与猫有很高的相似性和重合性,香蕉和苹果则远离猫狗所在区域,分布在更远的坐标区域。每张图片内容的含义,都会在维度空间内有属于自己的定位点,含义越相似的图片坐标点靠的越近,反正则远离。

向量数据库

有了每张图片的向量数据,那么就要提及向量数据库

向量数据库不同于普通的关系型数据库,主要作用就是对向量数据进行相似性搜索。

向量数据库主要有:Milvus、Qdrant、Chroma 等。

搭建本地的向量数据库,是一个复杂费时费力的过程,本想自行搭建,最终放弃。不过各种云也提供有云端的向量数据库,不会占用服务器有限的资源。

这三种云,最低配置的价格如下:

阿里云 180 元/月,百度云 918 元/月,腾讯云 194 元/月

每家云的定价标准和配置都不同,对比后,腾讯云会更适合我的需求

腾讯云向量数据库 (Tencent Cloud VectorDB) 是一款全托管的自研企业级分布式数据库服务,专用于存储、检索、分析多维向量数据。该数据库支持多种索引类型和相似度计算方法,单索引支持 10 亿级向量规模,可支持百万级 QPS 及毫秒级查询延迟。腾讯云向量数据库不仅能为大模型提供外部知识库,提高大模型回答的准确性,还可广泛应用于推荐系统、自然语言处理等 AI 领域。

各种云都提供了免费 30 天的测试数据库。在向腾讯云数据库写入 43727 条 512 维的向量数据后,腾讯云的向量数据库显示占用了 20G 中的 89M。

通过粗略计算,大概 20G 数据库可写入接近 100 万条 512 维度的向量数据

向量数据库是如何进行相似性分析的?

向量相似性搜索,主要使用以下几种算法来实现:

点积

点积是一种简单但功能强大的相似性度量方法,广泛应用于机器学习、数据挖掘和统计学,用于查找两个向量之间的相似性。它在余弦相似性领域尤为重要,是搜索引擎和其他数据驱动型应用中算法的基础。

  • 余弦相似度基础:点积是计算余弦相似度的基础,余弦相似度是相似度搜索中广泛使用的度量。当向量被归一化时,点积本质上提供了两个向量之间角度的余弦,从而提供了相似度的有效度量。

  • 高效检索:它允许在大型数据库中高效地检索相似的向量,这对于速度至关重要的搜索引擎和推荐系统至关重要。

  • 机器学习模型:用于训练机器学习模型,尤其是深度学习,其中在前向和后向传播阶段广泛使用点积运算。

优点:

  • 速度:计算效率高,提供对实时应用至关重要的快速计算。

  • 简单:由于其公式简单明了,因此易于实现和理解。

限制:

  • 幅度敏感性:点积对向量的幅度很敏感,如果被比较的向量的幅度明显不同,它可能无法准确地表示相似性。

结论:

点积是一种基础向量相似性搜索算法,在各个领域具有广泛的应用和相关性。它的简单性和效率使其成为处理大型数据集并需要快速相似性计算的专业人士的首选。

余弦相似度

余弦相似度是一种广泛使用的度量标准,用于衡量两个向量之间的相似度,通常用于信息检索、文本挖掘和机器学习领域。它测量两个向量之间角度的余弦,从而了解它们在多维空间中的方向。

  • 文档相似度:常用于自然语言处理,衡量文本之间的相似度,有助于文档检索和聚类。

  • 推荐系统:协同过滤采用余弦相似度,通过比较用户或项目资料来生成推荐。

  • 图像比较:它应用于计算机视觉,用于比较图像的特征向量。

优点:

  • 角度测量:测量向量之间角度的余弦,可有效比较不同长度的文档。

  • 规范化:度量本质上对向量长度进行了规范化,使其对数据的方向而不是幅度敏感。

限制:

  • 零向量问题:它不能很好地处理零向量,因为它变得未定义。

  • 不是度量:余弦相似度不满足三角不等式,因此不是真正的度量。

结论:

余弦相似度是一种强大且通用的向量相似度搜索算法,广泛应用于各个领域。尽管它具有几个优点,例如对幅度不敏感,但了解其局限性对于有效应用至关重要。通过谨慎实施,它仍然是数据科学和人工智能领域从事相似度搜索、文档检索和推荐系统的专业人士的宝贵工具。

曼哈顿距离(L1距离)

曼哈顿距离,也称为 L1 范数或城市街区距离,是一种用于计算网格路径中两点之间距离的方法,类似于城市街道的布局。这种方法在计算机科学、信息论和统计学等多个领域都很流行。

  • 聚类算法:曼哈顿距离经常用于各种聚类算法中,其中数据点之间的距离测量至关重要。

  • 分类任务:在机器学习中,它可以作为分类任务的启发式函数。

  • 图像分析:该测量方法通常用于图像分析和计算机视觉中,用于比较图像之间的相似性。

优点:

  • 网格路径的相关性:对于具有网格状架构的应用程序特别有用,因为无法进行对角线移动。

  • 对异常值的敏感性:曼哈顿距离对异常值的敏感度较低,因为它不强调极端值。

限制:

  • 不是最短距离:它并不总是代表两点之间的最短距离,因为它仅限于沿网格线的移动。

结论:

曼哈顿距离提供了一种直接有效的方法来测量各种应用中的相似性,特别是在数据以网格状结构组织的情况下。虽然简单,但了解其应用、优势和局限性对于在相似性搜索和分析任务中有效地部署它至关重要。对于从事数据科学、机器学习和相关领域的专业人士和研究人员来说,了解何时何地使用曼哈顿距离至关重要。

欧几里得距离(L2距离)

欧几里得距离是数据挖掘、机器学习和统计学中常用的相似度度量方法。它计算欧几里得空间中两点之间的“直线”距离,作为矢量差异的直接度量。

相似性搜索中的应用:

  • 聚类算法:欧几里得距离是 K-Means 等聚类算法的基础,通过最小化到聚类中心的距离来帮助将数据点分配给聚类。

  • 图像相似性:它通常应用于计算机视觉,通过比较特征向量之间的距离来查找相似的图像。

  • 推荐系统:用于推荐系统,欧几里得距离有助于找到相似的物品或用户。

优点:

  • 直观性:量度直观,反映空间中各点之间的物理距离。

  • 简单:公式简单,易于实现和理解。

限制:

  • 尺度敏感性:欧几里得距离对特征的尺度很敏感,需要对特征进行缩放才能获得准确的结果。

  • 高维问题:在高维空间中,点之间的距离趋于均匀,使得欧几里得距离不太有效。

结论:

欧几里德距离是一种重要的向量相似性搜索算法,在各个领域都有应用。虽然简单直观,但必须考虑其局限性,尤其是对于高维数据或不同尺度的特征。对于那些希望在相似性搜索任务和数据分析中有效实施欧几里德距离的人来说,了解其细微差别至关重要。

在腾讯云向量数据库中,创建集合表的时候,可以指定搜索使用的相似性算法,腾讯提供了 L2(欧几里得距离)、IP(点积)和 COSIN(余弦相似度)三种算法。

我们必须认识到,没有一种算法在所有情况下都占主导地位。选择最合适的算法取决于数据的性质、维度和手头的具体问题。因此,算法选择的灵活性是关键。

综合实践

ONNX Runtime 支持 .Net Framework 4.8 和 .Net 6.0

Visual Studio 开发时,如果使用 .Net Framework 4.8,需要引用以下 DLL 组件库

如果是用在网站内运行,这些 DLL 文件还需放入 bin 目录

如果使用 .Net 6.0 开发,只需引用 Microsoft.ML.OnnxRuntime.dll 组件即可

本人开发 VS 程序不喜欢在项目内引用 Nuget 上的库包,因为会造成项目文件臃肿庞大,以上 DLL 组件是在 Nuget 引用 Microsoft.ML.OnnxRuntime 后,做了排除优化后,分离出来的实际用到的 DLL,然后新建项目,只引入这些有用的 DLL 文件,项目总容量会大减。

Microsoft.ML.OnnxRuntime.dll 会在程序运行时,寻找和加载 onnxruntime.dll 文件,onnxruntime.dll 分 x86 和 x64 版本,需要 Microsoft Visual C++ Redistributable 2019 或更高版本支持,如果不安装 VC++ 2019 或更高版本的组件包,便会出现各种报错问题,下载地址:https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist

onnxruntime.dll 的版本会直接影响到最终的模型运算速度,本人做了四种测试,不同版本和不同位数下的测试如下:

32 位 1.15 版 onnxruntime.dll

64 位 1.15 版 onnxruntime.dll

32 位 1.91 版 onnxruntime.dll

64 位 1.91 版 onnxruntime.dll

每次测试均使用 10 次运算,首次运算较慢,之后速度维持正常均值

32 位 1.15 版平均耗时 1.39 秒
64 位 1.15 版平均耗时 1.12 秒
32 位 1.91 版平均耗时 1.22 秒
64 位 1.91 版平均耗时 1.08 秒

由此得知,64 位 1.91 版的运算速度最快,运算中包含了图片裁剪处理的时间,重新修改程序,将图片提前裁剪处理好,直接进行运算,得到下图:

可以得知,将一张图片生成向量数据,64 位 1.91 版的运算速度在 0.8 秒。不过也有说法是 PyTorch 比 ONNX 运行速度快 2-3 倍,不知真假。

另外,在 .Net 6.0 环境下,同样的代码,64 位 1.91 版的测试结果如下:

.Net 6.0 环境下,运算耗时与 .Net Framework 4.8 下,耗时几乎一致

再测试向量数据库的查询速度

只传递向量数据,平均查询获取时长只需 0.03 秒,可以说优化和效率非常高

那么绝对处理时间就是 0.8 + 0.03 = 0.83 秒,这个时间是模型处理和相似查询占用的绝对时间,多出来的时间,取决于图片上传到服务器的时长、图片裁切处理的时长,以及服务器的配置高低产生的影响等。

结论与总结

实现高效率的本地图片相似性搜索,可以使用跨平台支持多种开发环境的 ONNX Runtime 做为桥梁,通过将图片代入到 clip-image-vit-32-float32 模型内进行推理运算,得到矢量向量数据,再从已录入数据的本地或云端向量数据库内,进行相似性搜索。

欢迎搜索关注“小贝冲冲冲”,话费会员充值好用不贵


Copyright © 2024 aigcdaily.cn  北京智识时代科技有限公司  版权所有  京ICP备2023006237号-1