如何用Python和深度神经网络寻找近似图片?

给你10万张图片,让你找出与其中某张图片最为近似的10张,你会怎么做?不要轻言放弃,也不用一张张浏览。使用Python,你也可以轻松搞定这个任务。

识别相同或相似的图像,有什么好的方法么?

加vx:tanzhouyiwan 或qq群813622576免费领取Python学习资料一套哦!

我虽然乐于帮助读者解决问题,但实话实说,一开始不太理解这种需求。

我文章里的样例图片(哆啦a梦和瓦力),都是从网络搜集来的。如果你需要从网上找到跟某张图片近似的图像,可以使用Google的“以图搜图”功能啊。

很快,我突然醒悟过来。

这种需求,往往不是为了从互联网上大海捞针,寻找近似图片。而是在一个私有海量图片集合中,找到近似图像。

这种图片集合,也许是你团队的科研数据。例如你研究鸟类。某天浏览野外拍摄设备传回来的图像时,突然发现一个新奇品种。

你于是很想搞清楚这种鸟类的出现时间、生活状态等。这就需要从大量图片里,找到与其近似的图片(最有可能是拍到了同一种鸟)。

这种图片集合,也许是社会安全数据。例如你在反恐部门,系统突然发现某个疑似恐怖分子出现在敏感区域。这家伙每一次现身,都伴随着恶性刑事案件的发生,给人民群众的生命财产安全带来严重威胁。

这时候无论对其衣着、外貌还是交通工具的相似度搜索,就显得至关重要了。

上述例子中,因为你都没有把图像上传到互联网,Google的“以图搜图”引擎功能再强大,也无能为力。

好吧,解决这个问题,很有意义。

下一个问题自然是:这种需求,解决起来复杂吗?

是不是需要跨过很高的技术门槛才能实现?是不是需要花大量经费雇佣专家才能完成?

本文,我为你展示如何用10几行Python代码,解决这个问题。

数据

为了讲解的方便,我们依然采用《如何用Python和深度神经网络识别图像?》一文中使用过的哆啦a梦和瓦力图片集合。

我给你准备好了119张哆啦a梦的照片,和80张瓦力的照片。图片已经上传到了这个Github项目。

请点击这个链接,下载压缩包。然后在本地解压。作为咱们的演示目录。

解压后,你会看到目录下有个image文件夹,其中包含两个子目录,分别是doraemon和walle。

doraemon的目录下,都是各式各样的蓝胖子图片。

瓦力目录下的图片是这个样子的:

数据已经有了,下面我们来准备一下环境配置。

环境

本文中,我们需要使用到苹果公司的机器学习框架TuriCreate。

请注意TuriCreate发布时间不久,目前支持的操作系统列表如下:

这就意味着,如果你用的操作系统是Windows 7及以下版本,那么目前TuriCreate还不支持。如需使用,有两种办法:

第一种,请升级到Windows 10,并且使用WSL。关于如何使用WSL,我帮你找到了一个中文教程。请按照教程一步步完成安装。

第二种,采用虚拟机。推荐采用Virtualbox虚拟机,开源免费。同样地,我也帮你找到了很详尽的Virtualbox安装Ubuntu Linux的中文教程。你可以参照它安装好Linux。

解决了系统兼容性问题,下面我们在TuriCreate支持的系统中,安装Python集成运行环境Anaconda。

请到这个网址 下载最新版的Anaconda。下拉页面,找到下载位置。根据你目前使用的系统,网站会自动推荐给你适合的版本下载。我使用的是macOS,下载文件格式为pkg。

下载页面区左侧是Python 3.6版,右侧是2.7版。请选择2.7版本。

双击下载后的pkg文件,根据中文提示一步步安装即可。

装好Anaconda后,我们安装TuriCreate。

请到你的“终端”下面,进入咱们刚刚下载解压后的样例目录。

执行以下命令,我们来创建一个Anaconda虚拟环境,名字叫做turi。如果你之前跟随我在《如何用Python和深度神经网络识别图像?》一文中创立过这个虚拟环境,此处请跳过。

conda create -n turi python=2.7 anaconda

然后,我们激活turi虚拟环境。

source activate turi

在这个环境中,我们安装(或者升级到)最新版的TuriCreate。

pip install -U turicreate

安装完毕后,执行:

jupyter notebook

这样就进入到了Jupyter笔记本环境。我们新建一个Python 2笔记本。

浏览器里出现了一个空白笔记本。

点击左上角笔记本名称,修改为有意义的笔记本名“demo-python-image-similarity”。

准备工作完毕,下面我们就可以开始编写程序了。

代码

首先,我们读入TuriCreate软件包。

import turicreate as tc

我们指定图像所在的文件夹image。让TuriCreate读取所有的图像文件,并且存储到data数据框。

data  = tc.image_analysis.load_images('./image/')

我们来看看,data数据框的内容:

data

data包含两列信息,第一列是图片的地址,第二列是图片的长宽描述。

下面我们要求TuriCreate给数据框中每一行添加一个行号。这将作为图片的标记,好在后面查找图片时使用。

data = data.add_row_number()

再看看此时的data数据框内容:

data

我们来看看数据框里面的这些信息对应的图片。

data.explore()

TuriCreate会弹出一个页面,给我们展示数据框里面的内容。

把鼠标悬停在某张缩略图上面,就可以看到对应清晰大图。

第一张图片,是哆啦a梦:

第二张图片,是瓦力:

下面,是重头戏。我们让TuriCreate根据输入的图片集合,建立图像相似度判别模型。

model = tc.image_similarity.create(data)

这个语句执行起来,可能需要一些时间。如果你是第一次使用TuriCreate,它可能还需要从网上下载一些数据。请耐心等待。

Resizing images...

Performing feature extraction on resized images...

Completed 199/199

注意这里的提示,TuriCreate自动帮我们做了图片尺寸调整等预处理工作,并且对每一张图片,都做了特征提取。

经过或长或短的等待,模型已经成功建立。

下面,我们来尝试给模型一张图片,让TuriCreate帮我们从目前的图片集合里,挑出最为相似的10张来。

为了方便,我们就选择第一张图片作为查询输入。

我们利用show()函数展示一下这张图片。

tc.Image(data[0]['path']).show()

确认无误,还是那张哆啦a梦。

下面我们来查询,我们让模型寻找出与这张图片最相似的10张。

similar_images = model.query(data[0:1], k=10)

很快,系统提示我们,已经找到了。

我们把结果存储在了similar_images变量里面,下面我们来看看其中都有哪些图片。

similar_images

返回的结果一共有10行。跟我们的要求一致。

每一行数据,包含4列。分别是:

  • 查询图片的标记
  • 获得结果的标记
  • 结果图片与查询图片的距离
  • 结果图片与查询图片近似程度排序值

有了这些信息,我们就可以查看到底哪些图片与输入查询图片最为相似了。

注意其中的第一张结果图片,其实就是我们的输入图片本身。考虑它没有意义。

我们提取全部结果图片的标记(索引)值,忽略掉第一张(自身)。

similar_image_index = similar_images['reference_label'][1:]

剩余9张图片的标记都在结果中:

similar_image_index

dtype: int

Rows: 9

[194, 158, 110, 185, 5, 15, 79, 91, 53]

下面我们希望TuriCreate能够可视化帮我们展示这9张图片的内容。

我们要把上面9张图片的标记在所有图片的索引列表中过滤出来:

filtered_index = data['id'].apply(lambda x : x in similar_image_index)

看看过滤后的索引结果:

filtered_index

dtype: int

Rows: 199

[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ... ]

你可以自己数一数,其中标为1的那些图片位置,和我们存储在similar_image_index中的数字是否一致。

验证完毕以后,请执行以下语句。我们再次调用TuriCreate的explore()函数,展现相似度查询结果图片。

data[filtered_index].explore()

系统会弹出以下对话框:

我们可以看到,全部查询结果图片中,只出现了哆啦a梦。瓦力的图片,一张都没有出现。

近似图片查找成功!

随着本文操作样例数据后,你不妨换用自己的数据,来动手尝试一番。

原理

展示了如何用10几行Python代码帮你查找相似图形后,我们来聊聊这种强大、简洁背后的原理。

如果你对原理不感兴趣,请跳过这一部分,看“小结”。

虽然我们刚刚只是用了一条语句构建模型:

model = tc.image_similarity.create(data)

然而实际上,TuriCreate在后台为我们做了很多事情。

首先,它调用了一个非常复杂的,在庞大数据集上训练好的模型。

《如何用Python和深度神经网络识别图像?》一文中,我们介绍过,这个模型就是上图中的最后一行。它的名字叫做Resnet-50,足足有50层,训练的图片数以百万计,训练时长也很久。

这里,机智的你一定会问个问题:那些数以百万计的预训练图片里面,是否有哆啦a梦和瓦力呢?

没有。

那就怪了,不是吗?

如果这个复杂的模型之前根本就没有见过哆啦a梦和瓦力,那它怎么知道如何区分它们呢?又怎么能够判别两张哆啦a梦之间的差别,就一定比哆啦a梦和瓦力之间更小呢?

《如何用Python和深度神经网络识别图像?》一文里,我已经提示给你一个关键词:迁移学习(transfer learning)。

这里咱们就不深入技术细节了。我只给你在概念层次讲解一下。

还记得这张描述计算机视觉(卷积神经网络)的示意图吗?

在全连接层(Fully Connected Layer)之前,你可能进行了多次的卷积、抽样、卷积、抽样……这些中间层次,帮我们描绘了图片的一些基本特征,例如边缘大概是个什么形状,某个区块主要的颜色是哪些等。

到了全连接层,你只剩下了一组数据,这组数据可能很长,它抽取了你输入数据的全部特征。

如果你的输入是一只猫,此时的全连接层里就描述了这只猫的各种信息,例如毛发颜色、面部组成部分排列方式、边缘的形状……

这个模型可以帮你提取猫的特征,但它并不知道“猫”的概念是什么。

你自然可以用它帮你提取一条狗的特征。

同理,哆啦a梦的照片,与猫咪的照片一样,都是二维图片,都是用不同颜色分层。

那用其他图片训练的模型,能否提取哆啦a梦照片里的特征呢?

当然也可以!

使用迁移学习的关键,在于冻结中间过程的全部训练结果,直接把一幅图,利用在其他图片集合上训练的模型,转化为一个特征描述结果。

后面的工作,只把这个最后的特征描述(全连接层),用来处理分类和相似度计算。

前面的好几十层参数迭代训练,统统都被省却了。

难怪可以利用这么小的数据集获得如此高的准确度;也难怪可以在这么短的时间里,就获得整合后的模型结果。

把在某种任务上积累下的经验与认知,迁移到另一种近似的新任务上,这种能力就叫做迁移学习。

比起机器来,人的迁移学习能力更为强大。

雨果奖作者郝景芳在最近的一篇文章里,描述了人的这种强大学习能力:

小孩子可以快速学习,进行小数据学习,而且可以得到「类」的概念。小孩子轻易分得清「鸭子」这个概念,和每一只具体不同的鸭子,有什么不同。前者是抽象的「类」,后者是具体的东西。小孩子不需要看多少张鸭子的照片,就能得到「鸭子」这个抽象「类」的概念。

用成语来描述,大概就是“触类旁通”吧。

如果人类不善于迁移学习,把生活中的所有事物,全都当成新的东西从头学起,那后果简直不堪设想。对比我们一生中所能处理的信息总量,这种认知负荷将是无法承受的。

回到我们的问题里,如果模型可以帮我们把每一张图片,都变成全连接层上的那一长串数字(特征),那么我们分辨这些图片的相似程度,就变得太简单了。因为这变成了一个简单的空间向量距离问题。

处理这种简单的数值计算,我们人类可能觉得很繁琐。但是计算机算起来,那就很欢快了。

根据距离大小排序,找出其中最小的几个向量,它们描述的图片,就被模型判定为相似度最高的。

加vx:tanzhouyiwan 或qq群813622576免费领取Python学习资料一套哦!

以上是 如何用Python和深度神经网络寻找近似图片? 的全部内容, 来源链接: utcz.com/a/52138.html

回到顶部