莫斯科,神秘之城...(这张照片由伊戈尔·沙巴林提供)
一、说明
如今,每个拥有智能手机的人都可能成为摄影师。因此,每天都有大量新照片出现在社交媒体、网站、博客和个人照片库中。尽管拍照的过程可能非常令人兴奋,但将它们整理出来并在之后手动为每个进行描述可能会非常无聊且耗时。
本文讨论如何结合使用计算机视觉 (CV) 和自然语言处理 (NLP) 技术来获取照片的一组描述性标签,然后基于这些标签生成有意义的描述,从而节省宝贵的时间。
二、照片里面有什么?
我们人类可以在一瞬间回答这个问题,一旦照片在我们手中。机器也可以回答这个问题,只要它们熟悉CV和NLP。请看下面的照片:
您的应用程序如何知道上图中的内容?使用像Clarifai的Predict API这样的工具,这可能是一件轻而易举的事情。下面是一组描述性标签,这个 API 在处理完上面的照片后给你:
‘straw’, ‘hay’, ‘pasture’, ‘wheat’, ‘cereal’, ‘rural’, ‘bale’, …
如您所见,这些标签为您提供有关图片中可以看到的内容的适当信息。如果您所需要的只是自动对视觉内容进行分类,那么拥有这些标签就足以完成您的工作。但是,对于图像描述生成的任务,您需要更进一步并利用一些NLP技术。
在本文中,您将看到一个简化的示例,说明如何实现这一点,向您展示如何将生成的标签列表中的某些单词编织成简单的短语。有关此主题的概念性讨论,您可能还想查看我在 Clarifai 博客上的文章:使用自然语言处理生成图像描述。
三、准备
若要遵循本文中讨论的脚本,需要具有以下软件组件:
Python 2.7+∕3.4+
spaCy v2.0+
A pretrained English model for spaCy
Clarifai API Python client
Clarifai API key
您可以在相应的站点上找到安装说明。除此之外,您还需要一个Python库,允许您从维基百科获取和解析数据。
四、自动标记照片
首先,让我们看一下可用于自动标记照片的代码。在下面的实现中,我们使用 Clarifai 的通用图像识别模型来获取提交照片的描述性标签。
from clarifai.rest import ClarifaiApp, client, Image
def what_is_photo(photofilename):app = ClarifaiApp(api_key='Your Clarifai API key here')model = app.models.get("general-v1.3")image = Image(file_obj=open(photofilename, 'rb'))result = model.predict([image])tags = ''items = result['outputs'][0]['data']['concepts']for item in items:if item['name'] == 'no person':continueresult = "{}, ".format(item['name'])tags = tags +resultreturn tags
要测试上述函数,您可以将以下主块附加到脚本中:
if __name__ == "__main__":tag_list = list(what_is_photo("country.jpg").split(", "))print(tag_list[:7])
在这个特定示例中,我们选取为提交的照片生成的前七个描述性标签。因此,对于照片中提供的照片 照片里面有什么?前面的部分,此脚本生成以下描述性标记列表:
['straw', 'hay', 'pasture', 'wheat', 'cereal', 'rural', 'bale']
这对于分类的目的来说已经足够了,并且可以用作NLP的源数据,以生成有意义的描述,如下一节所述。
五、使用 NLP 将描述性标签转换为描述
他们在学校告诉我们,为了掌握语言,你需要大量阅读。换句话说,你必须训练使用这种语言的最佳示例。回到我们的讨论,我们需要一些使用标签列表中单词的文本。当然,您可以获得一个巨大的语料库,例如维基百科数据库转储,其中包含大量不同的文章。但是,在人工智能驱动的搜索时代,您只能将语料库缩小到与您拥有的标签列表中的单词最相关的文本。以下代码说明了如何从维基百科获取单个条目的内容,其中包含与标签列表相关的信息(您需要将其附加到上一节的 main 函数中的代码中):
import wikipedia
tags = ""
tags = tags.join(tag_list[:7])
wiki_resp = wikipedia.page(tags)
print("Article url: ", wiki_resp.url)
现在您已经有一些文本数据需要处理,是时候让 NLP 发挥作用了。下面是初始化 spaCy 的文本处理管道的初始步骤,然后将其应用于文本(将其附加到前面的代码片段)。
nlp = spacy.load('en')
doc = nlp(wiki_resp.content)
print(len(list(doc.sents)))
在下面的代码中,你将循环访问提交文本中的句子,分析每个句子中的语法依赖关系。特别是,您查找短语,其中包含提交的标记列表中的单词。在一个短语中,列表中的两个单词应该在语法上与头/子关系相关。如果您对此处使用的术语感到困惑,我建议您查看使用Python的自然语言处理,它详细解释了NLP概念,并包含许多易于遵循的示例。您可以立即开始阅读:第 2 章和第 12 章是免费的。此外,在我最近为 Oracle 杂志撰写的 Oracle 数字助理技能的生成意图和实体文章中可以找到在实践中可能使用句法依赖关系分析的示例。
回到下面的代码,请注意这是一种简化 - 当然,现实世界的代码会有点复杂。(将下面的代码附加到主脚本中的上一个代码中)
x = []
for sent in doc.sents:if bool([t for t in sent if t.lemma_ in tag_list[:7] and t.head.lemma_ in tag_list[:7] and t.head.lemma_ != t.lemma_]):t = [t for t in sent if t.lemma_ in tag_list[:7] and t.head.lemma_ in tag_list[:7] and t.head.lemma_ != t.lemma_][0]y = [(t.i, t), (t.head.i, t.head)]y.sort(key=lambda tup: tup[0])x.append((y[0][1].text + ' ' + y[1][1].text, 2))if bool([t for t in sent if t.lemma_ in tag_list[:7] and t.head.head.lemma_ in tag_list[:7] and t.head.lemma_ != t.lemma_ and t.head.head.lemma_ != t.head.lemma_]):t = [t for t in sent if t.lemma_ in tag_list[:7] and t.head.head.lemma_ in tag_list[:7] and t.head.lemma_ != t.lemma_ and t.head.head.lemma_ != t.head.lemma_][0]if t.i > t.head.i > t.head.head.i:y = [(t.head.head.i, t.head.head), (t.head.i, t.head), (t.i, t)]x.append((y[0][1].text + ' ' + y[1][1].text + ' ' + y[2][1].text, 3))
x.sort(key=lambda tup: tup[1], reverse= True)
if len(x) != 0:print(x[0][0])
此代码为我提供了以下短语,用于照片中提供的照片?本文前面的部分:
Hay in bales
这看起来像是该照片的相关描述。