★★★ 本文源自AlStudio社区精品项目,【点击此处】查看更多精品内容 >>>
“以图搜图”正式的名称应该叫“相似图像搜索引擎”,也称为“反向图片搜索引擎”。
最初的图像搜索引擎是基于文本关键字检索的,因而这种方法本质上还是属于基于文本搜索引擎。
1992年,T. Kato提出了基于内容的图像检索(Content-based Image Retrieval,CBIR)的概念,它使用图像的颜色、形状等信息作为特征构建索引以实现图像检索,即我们通常所说的“以图搜图”。基于这一概念,IBM开发了第一个商用的CBIR系统QBIC(Query By Image Content),用户只需输入一幅草图或图像,便可以搜索出相似的图像。
随着基于卷积神经网络的深度学习技术在计算机视觉领域内的普及,研究者发现神经网络可以很好地提取图片的特征,从而极大地提高了图像表达的准确性。诸多主流图像搜索引擎纷纷引入了深度学习算法来提高图像搜索的准确率。
如今我们日常使用的百度、搜狗等通用搜索引擎均提供了相似图像检索功能。淘宝、京东等电商平台也利用自己庞大的商品图像库开发了垂直领域内的图像检索功能来满足消费者们不易用文字描述的商品搜索需求。虽然图像检索技术已广泛应用于我们的生活当中,但目前这一技术还未完全成熟,仍有许多问题需要解决,改进和提高的空间还很大。
另外,一些上层的应用场景中,如目标追踪、位置获取等都需要图像相似性度量做理论支撑。图片的相似度研究目前仍然是热门领域。
AutoEncoder (AE)是 一种无监督的学习算法,主要用于数据的降维或者特征的抽取。
深度学习的三巨头之一的Hinton在2006的Science上发表了"Reducing the Dimensionality of Data with Neural Networks", 该文章提出了Deep Auto-Encoder架构如下图:
原始输入X,经过多层DNN layer,编码得到Code。它的维度一般比原始输入低很多,起到特征提取作用。
编码得到的Code,经过多层DNN layer,解码得到输出X’。
训练Encoder和Decoder,使得X’和X越接近越好。 Encoder和Decoder的各层参数,可以互为转置。这样就可以少一半参数,防止过拟合。
在实际应用中,Encoder和Decoder结构可以随意设置,只要二者联合训练就好了。这个架构和PCA有异曲同工之妙。区别在于PCA采用的是线性模型,而不是多层DNN。所以它的特征提取和样本重建能力都要差一些。
实验表明,Deep Auto-Encoder的样本重建效果,明显比基于线性模型的PCA要好很多。主要原因还是采用了多层DNN的Encoder和Decoder,模型编码和解码能力,比线性模型要强很多。
下面使用paddle框架搭建基于CNN的AutoEncoder模型,并验证其用于图片的特征提取以及基于此特征进行图片特征相似度计算的图片推荐应用上的有效性。
本项目采用从互联网上按照类别搜索获取的图片。将其分为database和query两个目录。 搭建训练框架并使用database中的图片训练模型后,从qeury目录中选择图片作为搜索输入,并从database中获取与输入相似度最高的图片,并可视化检验模型效果。
图片挂载在data目录下,解压到指定位置后即可使用。
3.1 解压数据集并查看
3.2 训练数据集创建
对于自定义的数据集,可以使用Paddle的Dataset类进行快捷方便的构建。一般,只需要完成如下步骤:
- 步骤一:继承 paddle.io.Dataset 类
- 步骤二:实现 init 函数,初始化数据集,将样本和标签映射到列表中
- 步骤三:实现 getitem 函数,定义指定 index 时如何获取数据,并返回单条数据(样本数据、对应的标签)
- 步骤四:实现 len 函数,返回数据集的样本总数
下面使用这4个步骤实现本项目的数据Dataset
4.1 搭建网络
在深度学习中,一般采用神经网络从输入的数据样本中习得数据内在规律,最终输出预测结果。模型组网中一个关键组成就是定义各种不同的神经网络层,并将他们组合在一起使用。
在飞桨框架中,常用paddle.nn.Layer类生成各个网络层来组网,一般来说,组网包括三个步骤:
- 创建一个继承自 paddle.nn.Layer 的类
- 在类的构造函数 init 中定义组网用到的神经网络层(layer)
- 在类的前向计算函数 forward 中使用定义好的 layer 执行前向计算
在飞桨框架中内置了丰富的神经网络层,用类(class)的方式表示,构建模型时可直接作为实例添加到子类中,只需设置一些必要的参数,并定义前向计算函数即可,反向传播和参数保存由框架自动完成。
对于AutoEncoder自编码网络,需要用到如下的层:
- Conv2D: 二维卷积层,用于对输入图片进行卷积操作,本项目中用于Encoder中,提取图片特征
- MaxPool2D: 最大池化层,主要用于缩小特征图大小
- Conv2DTranspose:二维转置卷积层,本项目用来做Decoder,用于图片上采样
其他常用的还有ReLU, Linear等,读者可以自行查看文档
- 使用Conv2DTranspose进行图片上采样时,stride决定了上采样的倍数,同时设置padding="SAME"可以保证图片尺寸不变
- 通过上面的网络信息可以看到Encoder阶段将一张图片3*448*448的图片通过卷积池化等操作变成256*56*56的特征图,即上采样8倍
- Decode的目的就是将图片恢复成原来的样子, 通过3次Transpose操作最终将图片恢复原来的尺寸:3*448*448
4.2 定义优化器和损失函数进行组网训练
4.3 训练结果可视化
分别将训练过程和训练后的模型的预测效果可视化
可以看到200个epoch后,loss收敛再0.05附近。
上面训练过程中将数据分批次送入网络。计算图片特征相似度时,我们将所有图片组成一个大的tensor输入网络进行特征提取。
同样使用paddle框架的dataload做组并输入数据
5.1 提取图片特征并向量化
从上面的结果可以看到,目的就是使用网络提取图片特征,并将其拉成一维的向量用于图片相似度计算。
5.2 可视化搜索结果
搜素的结果为一个tuple
- tuple[0]: topK余弦相似度的结果
- tuple[1}: 对应结果图片在training图片中的index, 根据此index可以拿到原图并可视化
通过对比查询图片和查询结果图片,可以发现查询的结果确实和输入的查询图片非常相似! 实验验证该方法有效
5.3 批量搜索并展示
_train[idx] for idx in indices.flatten()] # retrieval images plot_query_retrieval(img_query, imgs_retrieval) ``
可以看到对有些类能获得比较好的结果,有些类的搜索结果有可以改进的空间。 这个可以从网络的深度以及loss的设计进行改善
本项目提出提出了一种使用卷积神经网络提取图片特征并用于基于图片内容的搜素推荐算法,并使用飞桨框架搭建简单的网络来实现。
实验证明该方法有效,但是仍然后改进空间:
-
网络的设计: 本项目仿照VGG网络设计了一个7个卷积层的网络,工程实践中可以使用其他更深的网络或者直接调用飞桨框架已经实现的图片分类网络,将其分类的头部去掉即可
-
Loss: 本项目简单粗暴的使用MAE来计算原图和经过decode复原后的图片的像素差异,这一块对同一个前景目标处于图片不同区域敏感。可以设计更好的loss来规避。
关于作者:
- wolfmax老狼,PPDE, AICA六期学员
- 某半导体CIM软件集成商图像算法工程师,主要方向为图像相关相关的检测分割等算法开发
- 我在AI Studio上获得钻石等级,点亮7个徽章,来互关呀~ https://aistudio.baidu.com/aistudio/personalcenter/thirdview/801106