340

背景

我一直在玩Deep DreamInceptionism,使用Caffe框架来可视化层GoogLeNet,为项目构建的架构Imagenet,设计用于视觉对象识别的大型视觉数据库。

您可以在Imagenet此处找到:Imagenet 1000 类。


为了探究架构并产生“梦想”,我使用了三个笔记本:

  1. https://github.com/google/deepdream/blob/master/dream.ipynb

  2. https://github.com/kylemcdonald/deepdream/blob/master/dream.ipynb

  3. https://github.com/auduno/deepdraw/blob/master/deepdraw.ipynb


这里的基本思想是从模型或“引导”图像的指定层中的每个通道中提取一些特征。

然后我们将希望修改的图像输入到模型中,并在指定的同一层中提取特征(对于每个八度音阶),增强最佳匹配特征,即两个特征向量的最大点积。


到目前为止,我已经设法使用以下方法修改输入图像和控制梦想:

  • (a) 应用层作为'end'输入图像优化的目标。(见特征可视化
  • (b) 使用第二张图像来指导输入图像上的优化目标。
  • (c) 可视化Googlenet从噪声生成的模型类

但是,我想要达到的效果介于这些技术之间,我还没有找到任何文档、论文或代码。

期望的结果(不是要回答的问题的一部分)

让一个属于给定层的单个类或单元'end'(a) 引导优化目标 (b) 并使该类在输入图像上可视化 (c):

一个例子,其中class = 'face'input_image = 'clouds.jpg'

在此处输入图像描述 请注意:上面的图像是使用人脸识别模型生成的,该模型未在Imagenet数据集上进行训练。仅用于演示目的。


工作代码

方法(一)

from cStringIO import StringIO
import numpy as np
import scipy.ndimage as nd
import PIL.Image
from IPython.display import clear_output, Image, display
from google.protobuf import text_format
import matplotlib as plt    
import caffe
         
model_name = 'GoogLeNet' 
model_path = 'models/dream/bvlc_googlenet/' # substitute your path here
net_fn   = model_path + 'deploy.prototxt'
param_fn = model_path + 'bvlc_googlenet.caffemodel'
   
model = caffe.io.caffe_pb2.NetParameter()
text_format.Merge(open(net_fn).read(), model)
model.force_backward = True
open('models/dream/bvlc_googlenet/tmp.prototxt', 'w').write(str(model))
    
net = caffe.Classifier('models/dream/bvlc_googlenet/tmp.prototxt', param_fn,
                       mean = np.float32([104.0, 116.0, 122.0]), # ImageNet mean, training set dependent
                       channel_swap = (2,1,0)) # the reference model has channels in BGR order instead of RGB

def showarray(a, fmt='jpeg'):
    a = np.uint8(np.clip(a, 0, 255))
    f = StringIO()
    PIL.Image.fromarray(a).save(f, fmt)
    display(Image(data=f.getvalue()))
  
# a couple of utility functions for converting to and from Caffe's input image layout
def preprocess(net, img):
    return np.float32(np.rollaxis(img, 2)[::-1]) - net.transformer.mean['data']
def deprocess(net, img):
    return np.dstack((img + net.transformer.mean['data'])[::-1])
      
def objective_L2(dst):
    dst.diff[:] = dst.data 

def make_step(net, step_size=1.5, end='inception_4c/output', 
              jitter=32, clip=True, objective=objective_L2):
    '''Basic gradient ascent step.'''

    src = net.blobs['data'] # input image is stored in Net's 'data' blob
    dst = net.blobs[end]

    ox, oy = np.random.randint(-jitter, jitter+1, 2)
    src.data[0] = np.roll(np.roll(src.data[0], ox, -1), oy, -2) # apply jitter shift
            
    net.forward(end=end)
    objective(dst)  # specify the optimization objective
    net.backward(start=end)
    g = src.diff[0]
    # apply normalized ascent step to the input image
    src.data[:] += step_size/np.abs(g).mean() * g

    src.data[0] = np.roll(np.roll(src.data[0], -ox, -1), -oy, -2) # unshift image
            
    if clip:
        bias = net.transformer.mean['data']
        src.data[:] = np.clip(src.data, -bias, 255-bias)

 
def deepdream(net, base_img, iter_n=20, octave_n=4, octave_scale=1.4, 
              end='inception_4c/output', clip=True, **step_params):
    # prepare base images for all octaves
    octaves = [preprocess(net, base_img)]
    
    for i in xrange(octave_n-1):
        octaves.append(nd.zoom(octaves[-1], (1, 1.0/octave_scale,1.0/octave_scale), order=1))
    
    src = net.blobs['data']
    
    detail = np.zeros_like(octaves[-1]) # allocate image for network-produced details
    
    for octave, octave_base in enumerate(octaves[::-1]):
        h, w = octave_base.shape[-2:]
        
        if octave > 0:
            # upscale details from the previous octave
            h1, w1 = detail.shape[-2:]
            detail = nd.zoom(detail, (1, 1.0*h/h1,1.0*w/w1), order=1)

        src.reshape(1,3,h,w) # resize the network's input image size
        src.data[0] = octave_base+detail
        
        for i in xrange(iter_n):
            make_step(net, end=end, clip=clip, **step_params)
            
            # visualization
            vis = deprocess(net, src.data[0])
            
            if not clip: # adjust image contrast if clipping is disabled
                vis = vis*(255.0/np.percentile(vis, 99.98))
            showarray(vis)

            print octave, i, end, vis.shape
            clear_output(wait=True)
            
        # extract details produced on the current octave
        detail = src.data[0]-octave_base
    # returning the resulting image
    return deprocess(net, src.data[0])

我运行上面的代码:

end = 'inception_4c/output'
img = np.float32(PIL.Image.open('clouds.jpg'))
_=deepdream(net, img)

方法(b)

"""
Use one single image to guide 
the optimization process.

This affects the style of generated images 
without using a different training set.
"""

def dream_control_by_image(optimization_objective, end):
    # this image will shape input img
    guide = np.float32(PIL.Image.open(optimization_objective))  
    showarray(guide)
  
    h, w = guide.shape[:2]
    src, dst = net.blobs['data'], net.blobs[end]
    src.reshape(1,3,h,w)
    src.data[0] = preprocess(net, guide)
    net.forward(end=end)

    guide_features = dst.data[0].copy()
    
    def objective_guide(dst):
        x = dst.data[0].copy()
        y = guide_features
        ch = x.shape[0]
        x = x.reshape(ch,-1)
        y = y.reshape(ch,-1)
        A = x.T.dot(y) # compute the matrix of dot-products with guide features
        dst.diff[0].reshape(ch,-1)[:] = y[:,A.argmax(1)] # select ones that match best

    _=deepdream(net, img, end=end, objective=objective_guide)

我运行上面的代码:

end = 'inception_4c/output'
# image to be modified
img = np.float32(PIL.Image.open('img/clouds.jpg'))
guide_image = 'img/guide.jpg'
dream_control_by_image(guide_image, end)

问题

现在我尝试访问单个类的失败方法,对类矩阵进行热编码并专注于一个(到目前为止无济于事):

def objective_class(dst, class=50):
   # according to imagenet classes 
   #50: 'American alligator, Alligator mississipiensis',
   one_hot = np.zeros_like(dst.data)
   one_hot.flat[class] = 1.
   dst.diff[:] = one_hot.flat[class]

为了明确这一点:问题不是关于梦想代码,这是有趣的背景并且已经是工作代码,而只是关于最后一段的问题:有人可以指导我如何获取所选课程的图像(上课#50: 'American alligator, Alligator mississipiensis')从 ImageNet(这样我就可以使用它们作为输入 - 连同云图像 - 来创建一个梦想的图像)?

4

1 回答 1

3

问题是如何#50: 'American alligator, Alligator mississipiensis'从 ImageNet 中获取所选类别的图像。

  1. 转到 image-net.org。

  2. 转到“下载”。

  3. 按照“下载图片 URL”的说明进行操作:

在此处输入图像描述

如何从浏览器下载同义词集的 URL?

1. Type a query in the Search box and click "Search" button

在此处输入图像描述

在此处输入图像描述

鳄鱼没有显示。ImageNet is under maintenance. Only ILSVRC synsets are included in the search results.没问题,我们对类似的动物“鳄鱼蜥蜴”没问题,因为这个搜索是关于到达 WordNet 树形图的正确分支。我不知道即使没有维护,您是否会在这里获得直接的 ImageNet 图像。

2. Open a synset papge

在此处输入图像描述

向下滚动:

在此处输入图像描述

向下滚动:

在此处输入图像描述

寻找美洲短吻鳄,它恰好也是一种蜥蜴类双孔爬行动物,作为近邻:

在此处输入图像描述

3. You will find the "Download URLs" button under the left-bottom corner of the image browsing window.

在此处输入图像描述

您将获得所选类的所有 URL。在浏览器中弹出一个文本文件:

http://image-net.org/api/text/imagenet.synset.geturls?wnid=n01698640

我们在这里看到,只需知道需要放在 URL 末尾的正确 WordNet id。

手动图片下载

文本文件如下所示:

在此处输入图像描述

例如,第一个 URL 链接到:

在此处输入图像描述

第二个是死链接:

在此处输入图像描述

第三个链接死了,但第四个正在工作。

在此处输入图像描述

这些网址的图片是公开的,但是很多链接已经失效,而且图片的分辨率较低。

自动图像下载

再次来自 ImageNet 指南:

如何通过HTTP协议下载?通过 HTTP 请求下载同义词集,首先需要获取同义词集的“WordNet ID”(wnid)。当您使用资源管理器浏览同义词集时,您可以在图像窗口下方找到 WordNet ID。(单击此处并搜索“同义词集 WordNet ID”可以找到“狗、家犬、犬类”同义词集的 wnid)。要了解更多关于“WordNet ID”的信息,请参阅

Mapping between ImageNet and WordNet

给定同义词集的 wnid,其图像的 URL 可以在

http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=[wnid]

您还可以获得给定 wnid 的下义词同义词集,请参阅 API 文档以了解更多信息。

那么该API 文档中有什么内容呢?

获取所有 WordNet ID(所谓的“同义词集 ID”)及其所有同义词集的单词所需的一切,也就是说,它手头有任何类名及其 WordNet ID,而且是免费的。

获取同义词集的单词

给定同义词集的 wnid,同义词集的单词可以在

http://www.image-net.org/api/text/wordnet.synset.getwords?wnid=[wnid]

您也可以点击这里下载所有同义词的WordNet ID和单词之间的映射, 点击这里下载所有同义词的WordNet ID和glosses之间的映射。

如果您知道选择的 WordNet id 及其类名,则可以使用“nltk”(自然语言工具包)的 nltk.corpus.wordnet,参见WordNet 接口

在我们的例子中,我们只需要 class 的图像#50: 'American alligator, Alligator mississipiensis',我们已经知道我们需要什么,因此我们可以将 nltk.corpus.wordnet 放在一边(有关更多信息,请参阅教程或 Stack Exchange 问题)。我们可以通过循环访问仍然存在的 URL 来自动下载所有鳄鱼图像。当然,我们还可以通过循环遍历所有 WordNet ID 将其扩展到完整的 WordNet,尽管这对于整个树形图来说会花费太多时间 - 而且也不推荐,因为如果有 1000 人下载图像将停止存在他们每天。

恐怕我不会花时间编写这个接受 ImageNet 类号“#50”作为参数的 Python 代码,尽管使用从 WordNet 到 ImageNet 的映射表也应该是可能的。类名和 WordNet ID 应该足够了。

对于单个 WordNet ID,代码可能如下:

import urllib.request 
import csv

wnid = "n01698640"
url = "http://image-net.org/api/text/imagenet.synset.geturls?wnid=" + str(wnid)

# From https://stackoverflow.com/a/45358832/6064933
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
with open(wnid + ".csv", "wb") as f:
    with urllib.request.urlopen(req) as r:
        f.write(r.read())

with open(wnid + ".csv", "r") as f:
    counter = 1
    for line in f.readlines():      
        print(line.strip("\n"))
        failed = []
        try:
            with urllib.request.urlopen(line) as r2:
                with open(f'''{wnid}_{counter:05}.jpg''', "wb") as f2:
                    f2.write(r2.read())
        except:
            failed.append(f'''{counter:05}, {line}'''.strip("\n"))
        counter += 1
        if counter == 10:
            break

with open(wnid + "_failed.csv", "w", newline="") as f3:
    writer = csv.writer(f3)
    writer.writerow(failed)

结果:

在此处输入图像描述

  1. 如果您甚至需要在死链接后面和原始质量的图像,并且如果您的项目是非商业的,您可以登录,请参阅“我如何获得图像的副本?” 在下载常见问题解答
  • 在上面的 URL 中,您会在wnid=n01698640URL 的末尾看到映射到 ImageNet 的 WordNet id。
  • 或者在“Synset 的图像”选项卡中,只需单击“Wordnet ID”。

在此处输入图像描述

到达,得到:

在此处输入图像描述

或右键单击 - 另存为:

在此处输入图像描述

您可以使用 WordNet id 来获取原始图像。

在此处输入图像描述

如果你是商业的,我会说联系 ImageNet 团队。


添加在

接受评论的想法:如果您不想要很多图像,而只想要尽可能多地代表类的“单个类图像”,请查看Visualizing GoogLeNet Classes并尝试对图像使用此方法取而代之的是 ImageNet。这也使用了 deepdream 代码。

可视化 GoogLeNet 类

  1. 2015 年 7 月

有没有想过深度神经网络认为斑点狗应该是什么样子?好吧,不要再怀疑了。

最近谷歌发表了一篇文章,描述了他们如何设法使用深度神经网络生成类可视化并通过所谓的“inceptionism”方法修改图像。他们后来自己发布了通过 inceptionism 方法修改图像的代码,但是,他们没有发布代码来生成他们在同一篇文章中显示的类可视化。

虽然我从来没有弄清楚谷歌是如何生成他们的类可视化的,但在从 Kyle McDonald 处处理deepdream 代码和这个ipython 笔记本之后,我设法指导 GoogLeNet 绘制这些:

在此处输入图像描述

... [后面还有许多其他示例图像]

于 2021-02-04T00:58:29.443 回答