计算机视觉任务:图像梯度和图像完成

该笔记是以斯坦福cs231n课程的python编程任务为主线,展开对该课程主要内容的理解和部分数学推导。这篇文章是关于计算机视觉处理的,分为两篇文章撰写完成。此为第二篇:根据上篇文章提到,利用深度学习里的RNN和LSTM等神经网络处理后的数据来计算图像的梯度,并且利用不同的图像梯度来生成不同类型的图像。

第一篇:《计算机视觉处理三大任务:分类,定位和检测》

04

图像梯度(Image Gradients)

这部分我们将用预训练好的CNN模型来计算图像的梯度,并用图像梯度来产生class saliency maps 和 fooling images。这部分我们会用到TinyImageNet数据集,它是ILSVRC-2012分类数据集的一个子集,包含了200个类,每一个类拥有500张训练图片,50张验证图片和50张测试图片,每张图片大小为64x64。TinyImageNet数据集被分成了两部分:TinyImageNet-100-A和TinyImageNet-100-B,每部分包含100个类,这里我们使用的是TinyImageNet-100-A。

Examples of the TinyImageNet-100-A

1.Saliency Maps

给定一张图片X,我们想要知道到底是图片中的哪些部分决定了该图片的最终分类结果。给定一个类,我们可以通过反向传播求出X关于loss function的偏导矩阵,这个偏导矩阵就是该图片的图像梯度,然后计算出类显著度图(class saliency map, csm)。Karen Simonyan论文的3.1节(https://arxiv.org/pdf/1312.6034.pdf)给出了计算方法:如果图片是灰度图,那么csm就取图像梯度的绝对值;如果是RGB图,csm就取图像梯度3个通道中绝对值最大的那个通道。csm中元素值的大小表示对应位置的图片像素对最终分类结果的影响程度。

代码如下:

def compute_saliency_maps(X, y, model):

    N,C,H,W = X.shape
    saliency = np.zeros((N,H,W))

    # Compute the score by a single forward pass
    scores, cache = model.forward(X, mode='test')    # Score size (N,100)

    # The loss function we want to optimize(maximize)
    # loss = (scores[np.arange(N), y] - lambda*np.sqrt(np.sum(X**2)))   # Size (N,)

    # The gradient of this loss wih respect to the input image
    dscores = np.zeros_like(scores)
    dscores[np.arange(N), y] = 1.0
    dX, grads = model.backward(dscores, cache)
    saliency += np.max(np.abs(dX), axis=1)

    return saliency

下图是一些saliency maps的可视化结果:

Random images

Cherry-picked images

2.Fooling Images

我们可以用图像梯度来生成 虚假图像(fooling images)。给定一张图片和一个目标类,我们可以对该图片执行梯度上升(将图像梯度不断地叠加到原图片上),以产生一个fooling image。该fooling image和原图片在视觉上非常接近,但是CNN会把它识别成我们预先设定的目标类。

代码如下:

def make_fooling_image(X, target_y, model):
    X_fooling = X.copy()
    N,C,H,W = X_fooling.shape      # N=1
    i = 0
    y_pred = -1
    lr = 200.0
    while (y_pred != target_y) & (i<200):
        scores, cache = model.forward(X_fooling, mode='test') # Score size (N,100)
        # The loss function we want to optimize(maximize)
        # loss = scores[np.arange(N), target_y]                 # Size (N,)
        # print loss
        # The gradient of this loss wih respect to the input image
        dscores = np.zeros_like(scores)
        dscores[np.arange(N), target_y] = 1.0
        dX, grads = model.backward(dscores, cache)
        X_fooling += lr*dX
        y_pred = model.loss(X_fooling).argmax(axis=1)
        i+=1
        print 'Iteration %d: current class: %d; target class: %d ' % (i, y_pred, target_y)

    return X_fooling

Left: original image, Middle: fooling image, Right: difference

从上图结果我们可以看出:CNN依旧无法摆脱维度的诅咒这一难题,因为存在对抗样本使它无法正确辨识。

05

图像生成(Image Generation)

这一部分我们继续探索图像梯度,我们将使用不同的方法通过图像梯度生成图像。

1.Class visualization

给定一个目标类(比如蜘蛛),我们可以在一个随机噪声图像上,利用梯度上升来生成一个(蜘蛛)图像,并且CNN会把它识别成目标类。具体实现方法可以参见论文:Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps(https://arxiv.org/pdf/1312.6034.pdf)。

代码如下:

def create_class_visualization(target_y, model, **kwargs):

    learning_rate = kwargs.pop('learning_rate', 10000)
    blur_every = kwargs.pop('blur_every', 1)
    l2_reg = kwargs.pop('l2_reg', 1e-6)
    max_jitter = kwargs.pop('max_jitter', 4)
    num_iterations = kwargs.pop('num_iterations', 200)
    show_every = kwargs.pop('show_every', 25)

    X = np.random.randn(1, 3, 64, 64)
    for t in xrange(num_iterations):
        # As a regularizer, add random jitter to the image
        ox, oy = np.random.randint(-max_jitter, max_jitter+1, 2)
        X = np.roll(np.roll(X, ox, -1), oy, -2)

        # Compute the score and gradient
        scores, cache = model.forward(X, mode='test')
        # loss = scores[0, target_y] - l2_reg*np.sum(X**2)
        dscores = np.zeros_like(scores)
        dscores[0, target_y] = 1.0
        dX, grads = model.backward(dscores, cache)
        dX -= 2*l2_reg*X

        X += learning_rate*dX

        # Undo the jitter
        X = np.roll(np.roll(X, -ox, -1), -oy, -2)

        # As a regularizer, clip the image
        X = np.clip(X, -data['mean_image'], 255.0 - data['mean_image'])

        # As a regularizer, periodically blur the image
        if t % blur_every == 0:
            X = blur_image(X)

        # Periodically show the image
        if t % show_every == 0:
            print 'The loss is %f' % loss
            plt.imshow(deprocess_image(X, data['mean_image']))
            plt.gcf().set_size_inches(3, 3)
            plt.axis('off')
            plt.title('Iteration: %d' % t)
            plt.show()

    return X

下图是迭代过程中生成的(蜘蛛)图像:

Generated images

2.Feature Inversion

这部分我们将完成一个很有意思的工作:在一张随机噪声图像上重建出指定层CNN学习到的图像特征表达。详细的实现方法参见论文: Understanding Deep Image Representations by Inverting them (https://www.robots.ox.ac.uk/~vedaldi/assets/pubs/mahendran15understanding.pdf)和 Understanding Neural Networks Through Deep Visualization(http://yosinski.com/media/papers/Yosinski__2015__ICML_DL__Understanding_Neural_Networks_Through_Deep_Visualization__.pdf)。

代码如下:

def invert_features(target_feats, layer, model, **kwargs): learning_rate = kwargs.pop('learning_rate', 10000) num_iterations = kwargs.pop('num_iterations', 500) l2_reg = kwargs.pop('l2_reg', 1e-7) blur_every = kwargs.pop('blur_every', 1) show_every = kwargs.pop('show_every', 50) X = np.random.randn(1, 3, 64, 64) for t in xrange(num_iterations): # Forward until target layer feats, cache = model.forward(X, end=layer, mode='test') # Compute the loss loss = np.sum((feats-target_feats)**2) + l2_reg*np.sum(X**2) # Compute the gradient of the loss with respect to the activation dfeats = 2*(feats-target_feats) dX, grads = model.backward(dfeats, cache) dX += 2*l2_reg*X X -= learning_rate*dX # As a regularizer, clip the image X = np.clip(X, -data['mean_image'], 255.0 - data['mean_image']) # As a regularizer, periodically blur the image if (blur_every > 0) and t % blur_every == 0: X = blur_image(X) if (show_every > 0) and (t % show_every == 0 or t + 1 == num_iterations): print loss plt.imshow(deprocess_image(X, data['mean_image'])) plt.gcf().set_size_inches(3, 3) plt.axis('off') plt.title('Iteration: %d' % t) plt.show()

下图是迭代过程中生成的图像特征(浅层和深层):

Shallow feature reconstruction

Deep feature reconstruction

3.DeepDream

这部分我们体验一下简化版的DeepDream。实现思想很简单,我们先选定CNN的某一层(我们将在该层dream),然后将需要dream的图像输入进预训练好的CNN。前向传播至目标层,令该层的梯度等于该层的激活值(特征)。然后反向传播至输入层,求出图像梯度,同过梯度下降法将图像梯度不断叠加到输入图像上。

代码如下:

def deepdream(X, layer, model, **kwargs):
    X = X.copy()
    learning_rate = kwargs.pop('learning_rate', 5.0)
    max_jitter = kwargs.pop('max_jitter', 16)
    num_iterations = kwargs.pop('num_iterations', 200)
    show_every = kwargs.pop('show_every', 50)

    for t in tqdm(xrange(num_iterations)):
        # As a regularizer, add random jitter to the image
        ox, oy = np.random.randint(-max_jitter, max_jitter+1, 2)
        X = np.roll(np.roll(X, ox, -1), oy, -2)

        # Forward until dreaming layer
        fea, cache = model.forward(X, end=layer ,mode='test')

        # Set the gradient equal to the feature
        dfea = fea
        dX, grads = model.backward(dfea, cache)
        X += learning_rate*dX

        # Undo the jitter
        X = np.roll(np.roll(X, -ox, -1), -oy, -2)

        # As a regularizer, clip the image
        mean_pixel = data['mean_image'].mean(axis=(1, 2), keepdims=True)
        X = np.clip(X, -mean_pixel, 255.0 - mean_pixel)

        # Periodically show the image
        if t == 0 or (t + 1) % show_every == 0:
            img = deprocess_image(X, data['mean_image'], mean='pixel')
            plt.imshow(img)
            plt.title('Iteration: %d' % (t + 1))
            plt.gcf().set_size_inches(8, 8)
            plt.axis('off')
            plt.show()

    return X

接下来我们就可以生成DeepDream图像啦!

Tibidabo

Deeplayer

Leaning Tower

原文发布于微信公众号 - 人工智能LeadAI(atleadai)

原文发表时间:2017-09-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏人工智能

AI新闻报简单自学机器学习理论——正则化和偏置方差的权衡

在第一部分探讨了统计模型潜在的机器学习问题,并用它公式化获得最小泛化误差这一问题;在第二部分通过建立关于难懂的泛化误差的理论去得到实际能够估计得到的经验误差,最...

17710
来自专栏决胜机器学习

循环神经网络(四) ——words2vec、负采样、golve

1855
来自专栏机器之心

入门 | 从零开始,了解元学习

2269
来自专栏杨熹的专栏

为什么需要 Mini-batch 梯度下降,及 TensorFlow 应用举例

里面对 BGD,SGD,MBGD,Adagrad,Adadelta,RMSprop,Adam 进行了比较, 今天对其中的 mini-batch 梯度下降 作进...

541
来自专栏AI科技评论

开发 | 深度学习中的“深度”究竟怎么理解?

AI科技评论按:本文原作者 YJango,本文原载于其知乎专栏——超智能体。AI科技评论已获得原作者授权。 介绍 为了研究神经网络,我们必须要对什么网络是什么有...

2847
来自专栏机器之心

从90年代的SRNN开始,纵览循环神经网络27年的研究进展

25912
来自专栏SIGAI学习与实践平台

理解 logistic 回归

logistic回归由Cox在1958年提出[1],它的名字虽然叫回归,但这是一种二分类算法,并且是一种线性模型。由于是线性模型,因此在预测时计算简单,在某些大...

601
来自专栏目标检测和深度学习

入门 | 从零开始,了解元学习

571
来自专栏杂七杂八

K最近邻与线性分类器(上)

图像分类的基本任务就是将图片分类,那如何进行图片分类呢?图片是不可能直接当作输入传递给我们的机器学习任务的,一个通用的做法就是将图片转换成一张巨大的数字表单。这...

1022
来自专栏华章科技

给初学者的深度学习简介

深度学习是计算机领域中目前非常火的话题,不仅在学术界有很多论文,在业界也有很多实际运用。本篇博客主要介绍了三种基本的深度学习的架构,并对深度学习的原理作了简单的...

993

扫描关注云+社区