本文构建了一个能同时完成四个任务的的深度神经网络: 生成图像描述、生成类似单词、以图搜图和根据描述搜图。传统上这些任务分别须要一个模型,但咱们如今要用一个模型来完成全部这些任务。git
众所周知,神经网络十分擅长处理特定领域的任务 (narrow task),但在处理多任务时结果并非那么理想。github
这与人类的大脑不一样,人类的大脑可以在多样化任务中使用相同的概念。例如,假如你历来没据说过 “分形”(fractal),请看下面这张图:数据库
数学之美:分形图像 安全
上图是一个分形图像。在看到一张分形图像后,人可以处理多个与之相关的任务:网络
-
在一组图像中,区分一只猫的图像和分形图像;架构
-
在一张纸上,粗略地画一个分形图像;ide
-
将分形图像与非分形图像进行分类;函数
-
闭上眼睛,想象一下分形图像是什么样子的。post
那么,你是如何完成这些任务的呢?大脑中有专门的神经网络来处理这些任务吗?性能
现代神经科学认为,大脑中的信息是在不一样的部位进行分享和交流的。对于这种多任务性能是如何发生的,答案可能在于如何在神经网络中存储和解释数据。
“表示” 的精彩世界
顾名思义,“表示”(representation) 就是信息在网络中编码的方式。当一个单词、一个句子或一幅图像 (或其余任何东西) 做为输入提供给一个训练好的神经网络时,它就随着权重乘以输入和应用激活在连续的层上进行转换。最后,在输出层,咱们获得一串数字,咱们将其解释为类的标签或股票价格,或网络为之训练的任何其余任务。
输入 -> 输出的神奇转换是由连续层中发生的输入转换产生的。输入数据的这些转换即称为 “表示”(representations)。一个关键的想法是,每一层都让下一层更容易地完成它的工做。使连续层的周期变得更容易的过程会致使激活 (特定层上输入数据的转换) 变得有意义。
有意义是指什么呢?让咱们看下面的示例,该示例展现了图像分类器中不一样层的激活。
图像分类网络的做用是将像素空间中的图像转化为更高级的概念空间。例如,一张汽车的图像最初被表示为 RGB 值,在第一层开始被表示为边缘空间,而后在第二层被表示为圆圈和基本形状空间,在倒数第二层,它将开始表示为高级对象 (如车轮、车门等)。
这种愈来愈丰富的表示 (因为深度网络的分层性质而自动出现) 使得图像分类的任务变得简单。最后一层要作的就是斟酌,好比说,车轮和车门的概念更像汽车,耳朵和眼睛的概念更像人。
你能用这些表示作什么 ?
因为这些中间层存储有意义的输入数据编码,因此能够对多个任务使用相同的信息。例如,你可使用一个语言模型 (一个通过训练的、用于预测下一个单词的递归神经网络),并解释某个特定神经元的激活,从而预测句子带有的情绪。
一个使人惊讶的事实是,情感神经元是在无监督的语言建模任务中天然产生的。网络被训练去预测下一个单词,它的任务中并无被要求去预测情感。也许情感是一个很是有用的概念,以致于网络为了更好地进行语言建模而发明它。
一旦你理解了 “表示” 这个概念,你就会开始从彻底不一样的角度来理解深层神经网络。你会开始将感知表示 (sensing representations) 做为一种可转换的语言,使不一样的网络(或同一网络的不一样部分) 可以彼此通讯。
经过构建一个四合一的网络来探索表示
为了充分理解 “表示”,让咱们来构建一个能同时完成四个任务的的深度神经网络:
-
图像描述生成器:给定图像,为其生成描述
-
类似单词生成器:给定一个单词,查找与之类似的其余单词
-
视觉类似的图像搜索:给定一幅图像,找出与之最类似的图像
-
经过描述图像内容进行搜索:给出文本描述,搜索具备所描述的内容的图像
这里的每个任务自己就是一个项目,传统上分别须要一个模型。但咱们如今要用一个模型来作全部这些任务。
Pytorch 代码:
https://github.com/paraschopra/one-network-many-uses
第一部分:看图说话 (Image Captioning)
在网上有不少实现 Image Captioning 的很好的教程,因此这里不打算深刻讲解。个人实现与这个教程中的彻底相同:https://daniel.lasiman.com/post/image-captioning/。关键的区别在于,个人实现是在 Pytorch 中实现的,而这个教程使用的是 Keras。
接下来,你须要下载 Flickr8K 数据集。你还须要下载图像描述。提取“caption_datasets” 文件夹中的文字描述。
模型
Image Captioning 通常有两个组成部分:
a) 图像编码器 (image encoder),它接收输入图像并以一种对图像描述有意义的格式来表示图像;
b) 图说jie码器 (caption decoder),它接受图像表示,并输出文本描述。
image encoder 是一个深度卷积网络,caption decoder 则是传统的 LSTM/GRU 递归神经网络。固然,咱们能够从头开始训练它们。但这样作须要比咱们现有的 (8k 图像)更多的数据和更长的训练时间。所以,咱们不从头开始训练图像编码器,而是使用一个预训练的图像分类器,并使用它的 pre-final 层的激活。
这是一个示例。我使用 PyTorch modelzoo 中可用的 Inception 网络,该网络在ImageNet 上进行了训练,能够对 100 个类别的图像进行分类,并使用它来提供一个能够输入给递归神经网络中的表示。
请注意,Inception network 从未针对图说生成任务进行过训练。然而,它的确有效!
咱们也可使用一个预训练的语言模型来做为 caption decoder。但这一次,因为我从新实现了一个运行良好的模型,因此能够从头开始训练jie码器。
完整的模型架构以下图所示:
你能够从头开始训练模型,可是须要在 CPU 上花费几天时间 (我尚未针对 GPU 进行优化)。但不用担忧,你也能够享受一个已经训练完成的模型。(若是你是从头开始训练,请注意,我在大约 40 epochs 时中止训练,当时运行的平均损失约为 2.8)。
性能
我实现了性能良好的 beam search 方法。下面是网络为测试集中的图像生成的图说示例(之前从未见过)。
用我本身的照片试试,让咱们看看网络生成的图说是什么:
效果不错!使人印象深入的是,网络知道这张照片里有一个穿着白色 T 恤的男人。但语法有点偏离 (我相信经过更多的训练能够修正),但基本的要点抓住了。
若是输入的图像包含网络从未见过的东西,它每每会失败。例如,我很好奇网络会给iPhone X 的图像贴上什么样的标签。
效果不太好。但总的来讲,我对它的表现很是满意,这为咱们使用网络在学习给图像生成图说时开发的 “表示” 来构建其余功能提供了良好的基础。
第二部分:查找类似单词
回想一下咱们如何从图像表示中jie码图说。咱们将该表示提供给 LSTM/GRU 网络,生成一个输出,将其解释为第一个单词,而后将第一个单词返回到网络以生成第二个单词。这个过程一直持续到网络生成一个表示句子结束的特殊标记为止。
为了将单词反馈到网络中,咱们须要将单词转换为表示,再输入给网络。这意味着,若是输入层包含 300 个神经元,那么对于全部图说中的 8000 多个不一样的单词,咱们须要有一个 300 个相关联的数字,惟一地指定那个单词。将单词字典转换成数字表示的过程称为词汇嵌入 (或词汇表示)。
咱们能够下载和使用已经存在的词汇嵌入,如 word2vec 或 GLoVE。但在这个示例中,咱们从头开始学习词汇嵌入。咱们从随机生成的词汇嵌入开始,探索在训练结束时,网络对单词的了解。
因为咱们没法想象 100 维的数字空间,咱们将使用一种称为 t-SNE 的奇妙技术来在 2维中可视化学习的词汇嵌入。t-SNE 是一种降维技术,它试图使高维空间中的邻域同时也是低维空间中的邻域。
词汇嵌入的可视化
让咱们来看看 caption decoder 学习到的词汇嵌入空间 (不像其余语言任务有数百万单词和句子,咱们的jie码器在训练数据集中只有 ~30k 的句子)。
所以,咱们的网络已经了解到像 “play”、“plays” 和 “playing” 这样的词汇是很是类似的 (它们具备类似的表示形式,如红色箭头所示的紧密聚类)。让咱们在这个二维空间中探索另外一个区域:
这个区域彷佛有一堆数字 ——“two”、“three”、“four”、“five”,等等。
上图,它知道 people 和 children 两个单词类似。并且,它还隐式地推断出了物体的形状。
类似词汇
咱们可使用 100 维表示 (100-dimensional representation) 来构建一个函数,该函数提出与输入单词最类似的单词。它的工做原理很简单:采用 100 维的表示,并找出它与数据库中全部其余单词的余弦类似度。
让咱们来看看与 “boy” 这个单词最类似的单词:
结果不错。“Rider” 除外,但 “kids”、“kid” 和 “toddler” 都是正确的。
这个网络认为与 “chasing” 类似的词汇是:
“Chases” 是能够的,但我不肯定为何它认为 “police” 与 “chasing” 相似。
单词类比 (Word analogies)
关于词汇嵌入的一个使人兴奋的事实是,你能够对它们进行微积分。你能够用两个单词(如 “king” 和 “queen”) 并减去它们的表示来获得一个方向。当你把这个方向应用到另外一个词的表示上 (如 “man”),你会获得一个与实际相似词 (好比 “woman”) 很接近的表示。这就是为何 word2vec 一经推出就如此受欢迎的缘由:
我很好奇经过 caption decoder 学习到的表示是否具备相似的属性。尽管我持怀疑态度,由于训练数据并不大 (大约 3 万个句子),我仍是尝试了一下。
网络学习到的类比并不完美 (有些单词字面上出现的次数<10 次,因此网络没有足够的信息可供学习)。但仍有一些类比。
若是 riding 对应 sitting,那么 walking 对应什么呢?个人网络认为应该是 “laying”(这个结果还不错!)
一样,若是 “man” 的复数是 “men”,那么 “woman” 的复数应该是什么呢:
第二个结果是 “women”,至关不错了。
最后,若是 grass 对应 green,那么 sky 对应什么呢:
网络认为 sky 对应 silver 或 grey 的,虽然没有出现 blue,但它给的结果都是颜色词。使人惊讶的是,这个网络可以推断颜色的方向。
第三部分:查找类似图像
若是单词表示将相似的单词聚在一块儿,那么图像表示 (Inception 支持的图像编码器输出) 呢?我将相同的 t-SNE 技术应用于图像表示 (在 caption decoder 的第一步中做为输入的 300-dimensional tensor)。
可视化
这些点是不一样图像的表示 (不是所有 8K 图像,大约是 100 张图像的样本)。红色箭头指向附近的一组表示的聚类。
赛车的图像被聚类在一块儿。
孩子们在森林 / 草地玩耍的图像也被聚类在一块儿。
篮球运动员的图像被聚类在一块儿。
查找与输入图像类似的图像
对于查找类似单词任务,咱们被限制在测试集词汇表中寻找类似的单词 (若是测试集中不存在某个单词,咱们的 caption decoder 就不会学习它的嵌入)。然而,对于相似的图像任务,咱们有一个图像表示生成器 (image representation generator),它能够接受任何输入图像并生成其编码。
这意味着咱们可使用余弦类似度方法来构建一个按图像搜索的功能,以下所示:
步骤 1:获取数据库或目标文件夹中的全部图像,并存储它们的表示 (由 image encoder给出)
步骤 2:当用户但愿搜索与已有图像最类似的图像时,使用新图像的表示并在数据库中找到最接近的图像 (由余弦类似度给出)
谷歌图像可能正式使用这种 (或相似的) 方法来支持其反向图像搜索功能。
让咱们看看这个网络是如何工做的:
上面这张图像是我本身的。咱们使用的模型之前从未见过它。当我查询相似图像时,网络从 Flickr8K 数据集输出以下图像:
是否是很像?我没想到会有这么好的表现,但咱们确实作到了!
第四部分:经过描述查找图像
在最后一部分中,咱们将反向运行 caption generator。所以,咱们不是获取图像并为其生成标题,而是输入标题 (文本描述) 并找到与之最匹配的图像。
过程以下:
-
步骤 1:不是历来自编码器的 300 维图像表示开始,而是从一个彻底随机的 300 维输入张量开始
-
步骤 2:冻结整个网络的全部层 (即指示 PyTorch 不要计算梯度)
-
步骤 3:假设随机生成的输入张量来自 image encoder,将其输入到 caption decoder中
-
步骤 4:获取给定随机输入时网络生成的标题,并将其与用户提供的标题进行比较
-
步骤 5:计算比较生成的标题和用户提供的标题的损失
-
步骤 6:找到使损失最小的输入张量的梯度
-
步骤 7:根据梯度改变输入张量的方向 (根据学习率改变一小步)
-
继续步骤 4 到步骤 7,直到收敛或当损失低于某个阈值时为止
-
最后一步:取最终的输入张量,并利用它的值,经过余弦类似度找到离它最近的图像
结果至关神奇的:
我搜索了 “a dog”,这是网络找到的图像:
搜索 “a boy smiling”:
最后,搜索:
前两个结果是:
以及
总结和挑战
全部这些操做的代码能够从 github 存储库下载执行:
https://github.com/paraschopra/one-network-many-uses
这个存储库包括了用于数据预处理、模型描述、预训练的图说生成网络、可视化的代码。但不包括 Flickr8K 数据集或标题,须要单独下载。
若是你想更进一步,这里有一个挑战:从给定的描述生成图像。
这比本文中处理的要难 10 倍,但我感受这是可行的。若是一项服务不只可以搜索与文本对应的图像,并且可以动态地生成图像,那该多酷啊。
在将来,若是 Google Images 实现了这个功能,并可以为不存在的图像提供结果 (好比“两只独角兽在披萨作成的地毯上飞翔”),我不会感到惊讶的。
就这样。祝你能安全愉快地探索表示的世界。