CS231n (winter 2016) : Assignment3

CS231n-assignment3-Self-Supervised Learning 什么是自我监督学习? 现代机器学习需要大量的标记数据。但通常情况下,获取大量人类标记数据是具有挑战性和/昂贵的。有没有一种方法,我们可以让机器自动学习一个模型,可以生成良好的视觉表示,而无需标记数据集?是的,自我监督学习! 自我监督学习(SSL)允许模型使用给定数据集中的数据自动学习“好的”表现空间,而不需要标签。具体来说,如果我们的数据集是一堆图像,那么自我监督学习允许模型学习并生成“好的”图像表现向量。 SSL方法之所以如此流行,是因为学习后的模型在其他数据集上仍然表现良好,例如没有在其上训练过的新数据 阅读详情
前言:

以斯坦福cs231n课程的python编程任务为主线,展开对该课程主要内容的理解和部分数学推导。建议PC端阅读,该课程的学习资料和代码如下:
视频和PPT
笔记
assignment3初始代码


Part 1: 空间定位和检测(Spatial Localization and Detection)

以ILSVRC竞赛为例,该竞赛包含了三个计算机视觉任务:分类、定位和检测。

分类:图像上是啥? 预测top-5分类
定位:目标在哪里、是啥? 预测top-5分类+每个类别的bounding box(覆盖率50%以上)
检测:在哪里、都有啥?
---->> 定位是介于分类和检测的中间任务,分类和定位使用相同的数据集,检测的数据集有额外的数据集(物体比较小)。

这里贴张图,方便直观理解下各个任务的区别:

Computer Vision Tasks
Computer Vision Tasks

其中,分类+定位我们可以一起完成。方便感受,上张图:

Classification + Localization
Classification + Localization

那么改如何一起完成呢?我们可以将定位看成回归问题,具体请看下图:

Localization as Regression
Localization as Regression

对于目标检测问题,我们是否也可以看成回归问题来解决呢?由于每个图像中目标个数不一样,要定位的坐标数量也不一样,所以这并不是一个很好的思路;另一个思路是将其看成分类问题,不过我们需要在不同位置进行很多次分类,这会很耗时。

对于目标检测,R-CNN无疑是深度学习下目标检测的经典作品,其思想引领了最近两年目标检测的潮流。这里简单介绍下R-CNN的算法思路:

输入一张图片,我们先定位出2K个物体候选框,然后采用CNN提取每个候选框中图片的特征向量,特征向量的维度为4096维,接着采用SVM算法对各个候选框中的物体进行分类识别。

R-CNN
R-CNN

这里列一下近两年来目标检测的风向标:
R-CNN ---> SPPNET ---> Fast-RCNN ---> Faster-RCNN


Part 2: 循环神经网络(Recurrent Neural Networks)

RNNs主要用来处理序列数据。在传统的神经网络模型中,是从输入层到隐含层再到输出层,层与层之间是全连接的,每层之间的节点是无连接的。但是这种普通的神经网络对于很多问题却无能无力。例如,你要预测句子中的下一个单词是什么,一般需要用到前面的单词,因为一个句子中前后单词并不是独立的。RNNs之所以称为循环神经网路,即一个序列当前的输出与前面的输出也有关。具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅包括输入层的输出还包括上一时刻隐藏层的输出。下图是一个典型的RNNs(右侧是左侧的简化结构):

RNNs
RNNs

为了更好地说明RNN,我们可以将网络按照时间进行展开:

A RNN and the unfolding in time of the computation involved in its forward computation.
A RNN and the unfolding in time of the computation involved in its forward computation.

在RNN中每一个时间步骤用到的参数(U, W, V)都是一样的。一般来说,每一时间的输入和输出是不一样的,比如对于序列数据就是将序列项依次传入,每个序列项再对应不同的输出(比如下一个序列项)。

1. 反向传播算法(Back Propagation Through Time, BPTT)

RNNs的前向传播依次按照时间的顺序计算,反向传播就是从最后一个时间点将累积的残差传递回来即可。下面给出前向传播和后向传播的计算公式:

BPTT
BPTT

2. 图像描述(Image Captioning)

顾名思义,对于给定的一张图片,自动生成一段文字描述。就像这样:

Image Captioning
Image Captioning

在Assignment3中,我们将用CNN+RNN来实现图像自动描述,将会用到Microsoft COCO数据库。那么如何搭建结构框架呢?这里先给张图直观感受下:

CNN + RNN
CNN + RNN

上图中,我们用CNN来对输入图像进行特征提取,然后将提取到的特征作为RNN隐藏层的初始态(相当于t = -1时,隐藏层的输出值)输入到第一个时间点(t = 0)的隐藏层。RNN每个时间点的输出是当前输入序列项的下一项(比如,输入"straw",输出"hat")。

下面我给出一张详细的diagram,方便大家完成Assignment3第一部分的编程任务,即RNN_Captioning.ipynb里的任务:

Image Captioning by CNN+RNN
Image Captioning by CNN+RNN

3. Python编程任务(RNN)

这部分我们需要完成以下编程任务(此外,需要理解下captioning_solver.py):
--> rnn_layers.py,除了LSTM部分
--> rnn.py

具体代码如下:

--> rnn_layers.py

__coauthor__ = 'Deeplayer'
# 8.13.2016 #

import numpy as np

def rnn_step_forward(x, prev_h, Wx, Wh, b):
    next_h = np.tanh(x.dot(Wx) + prev_h.dot(Wh) + b)
    cache = (x, Wx, Wh, prev_h, next_h)
    
    return next_h, cache

def rnn_step_backward(dnext_h, cache):
    x, Wx, Wh, prev_h, next_h = cache
    dtanh = 1 - next_h ** 2                 # (N, H)
    dx = (dnext_h * dtanh).dot(Wx.T)        # (N, D)
    dprev_h = (dnext_h * dtanh).dot(Wh.T)   # (N, H)
    dWx = x.T.dot(dnext_h * dtanh)          # (D, H)
    dWh = prev_h.T.dot(dnext_h * dtanh)     # (H, H)
    db = np.sum((dnext_h * dtanh), axis=0)

    return dx, dprev_h, dWx, dWh, db

def rnn_forward(x, h0, Wx, Wh, b):
    N, T, D = x.shape
    _, H = h0.shape
    h = np.zeros((N, T, H))
    h_interm = h0
    cache = []
    for i in xrange(T):    
        h[:, i, :], cache_sub = rnn_step_forward(x[:, i, :], h_interm, Wx, Wh, b) 
        h_interm = h[:, i, :]    
        cache.append(cache_sub)
   
    return h, cache

def rnn_backward(dh, cache):
    x, Wx, Wh, prev_h, next_h = cache[-1]
    _, D = x.shape
    N, T, H = dh.shape
    dx = np.zeros((N, T, D))
    dh0 = np.zeros((N, H))
    dWx = np.zeros((D, H))
    dWh = np.zeros((H, H))
    db = np.zeros(H)
    dprev_h_=np.zeros((N, H))
    for i in xrange(T-1, -1, -1):    
        dx_, dprev_h_, dWx_, dWh_, db_ = rnn_step_backward(dh[:, i, :] + dprev_h_, cache.pop())    
        dx[:, i, :] = dx_    
        dh0 = dprev_h_    
        dWx += dWx_    
        dWh += dWh_    
        db += db_

    return dx, dh0, dWx, dWh, db

def word_embedding_forward(x, W):
    N, T = x.shape
    V, D = W.shape
    out = np.zeros((N, T, D))
    for n in xrange(N):    
        for t in xrange(T):        
            out[n, t, :] = W[x[n, t]]

    cache = (x, W)

    return out, cache  

def word_embedding_backward(dout, cache):
    x, W = cache
    N, T, D = dout.shape
    dW = np.zeros(W.shape)
    for n in xrange(N):    
        for t in xrange(T):        
            dW[x[n, t]] += dout[n, t, :]

    return dW

--> rnn.py

__coauthor__ = 'Deeplayer'
# 8.13.2016 #

def loss(self, features, captions):
    captions_in = captions[:, :-1]
    captions_out = captions[:, 1:]
    mask = (captions_out != self._null)
    W_proj, b_proj = self.params['W_proj'], self.params['b_proj']
    W_embed = self.params['W_embed']
    Wx, Wh, b = self.params['Wx'], self.params['Wh'], self.params['b']
    W_vocab, b_vocab = self.params['W_vocab'], self.params['b_vocab']
    loss, grads = 0.0, {}

    # forward pass
    imf2hid = features.dot(W_proj) + b_proj         # initial hidden state: [N, H]
    word_vectors, word_cache = word_embedding_forward(captions_in, W_embed)   # [N, T, W]
    if self.cell_type == 'rnn':    
        hidden, rnn_cache = rnn_forward(word_vectors, imf2hid, Wx, Wh, b)    # [N, T, H]
    else:    
        hidden, lstm_cache = lstm_forward(word_vectors, imf2hid, Wx, Wh, b)
    scores, h2v_cache = temporal_affine_forward(hidden, W_vocab, b_vocab)    # [N, T, V]
    loss, dscores = temporal_softmax_loss(scores, captions_out, mask)

    # backward pass
    dhidden, grads['W_vocab'], grads['b_vocab'] = temporal_affine_backward(dscores, h2v_cache)
    if self.cell_type == 'rnn':    
        dword_vectors, dimf2hid, grads['Wx'], grads['Wh'], grads['b'] = rnn_backward(dhidden, rnn_cache)
    else:    
        dword_vectors, dimf2hid, grads['Wx'], grads['Wh'], grads['b'] = lstm_backward(dhidden, lstm_cache)
    grads['W_embed'] = word_embedding_backward(dword_vectors, word_cache)
    grads['W_proj'] = features.T.dot(dimf2hid)
    grads['b_proj'] = np.sum(dimf2hid, axis=0)

    return loss, grads

def sample(self, features, max_length=30):
    N = features.shape[0]
    captions = self._null * np.ones((N, max_length), dtype=np.int32)    # [N, max_length]
    # Unpack parameters
    W_proj, b_proj = self.params['W_proj'], self.params['b_proj']
    W_embed = self.params['W_embed']             # [V, W]
    V, W = W_embed.shape
    Wx, Wh, b = self.params['Wx'], self.params['Wh'], self.params['b']
    W_vocab, b_vocab = self.params['W_vocab'], self.params['b_vocab']       # [H, V]

    h = features.dot(W_proj) + b_proj            # [N, H]
    c = np.zeros(h.shape)
    init_word = np.repeat(self._start, N)
    captions[:, 0] = init_word
    for i in xrange(1, max_length):    
        onehots = np.eye(V)[captions[:, i-1]]    # [N, V]    
        word_vectors = onehots.dot(W_embed)      # [N, W]    
        if self.cell_type == 'rnn':        
            h, cache = rnn_step_forward(word_vectors, h, Wx, Wh, b)    
        else:        
            h, c, cache = lstm_step_forward(word_vectors, h, c, Wx, Wh, b)
        scores = h.dot(W_vocab) + b_vocab                                   # [N, V]
        captions[:, i] = np.argmax(scores, axis=1)

    return captions

Part 3: Long Short-Term Memory Networks (LSTM Networks)

对于上面提到的RNN,存在一个问题,就是无法解决长期依赖问题(long-term dependencies)。当时间序列变得很长的时候,前后信息的关联度会越来越小,直至消失,即所谓的梯度消失现象。而LSTM这种特殊的RNN结构,可以解决长期依赖问题。LSTM由Hochreiter & Schmidhuber于1997年提出,之后有很多改进版本。
下面介绍下一般的LSTM,也将是我们在assignment中用到的结构,内容借鉴自Colah 的博文。
和RNN一样,LSTM也是随着时间序列重复着一样的模块,只是LSTM的每个某块比RNN更加复杂,拥有四个层(3个门+1个记忆单元)。下图方框内上方的那条水平线,被称为胞元状态(cell state),LSTM通过门结构对记忆单元上的信息进行线性修改,保证了当时间序列变得很长的时候,前后信息的关联度不会衰减。

The repeating module in an LSTM
The repeating module in an LSTM

下面介绍下3个门:

遗忘门(Forget gate): 通过sigmoid来控制,它会根据上一时刻的输出ht-1和当前输入xt来产生一个0到1的值ft,来决定让上一时刻学到的信息Ct-1通过的程度(即对上一时刻的信息Ct-1进行遗忘)。

Forget gate
Forget gate

输入门(Input gate): 通过sigmoid来决定哪些值用来更新进cell state,这里的值是由一个tanh层生成的,称为候选值Ct(上方少个 ~)。

Input gate
Input gate

现在,我们对cell state进行更新(丢弃不需要的信息,添加新信息),如下所示:

Updating cell state
Updating cell state

输出门(Output gate): 通过sigmoid层来决定cell state的哪个部分将被输出。接着,我们把当前的cell state通过tanh层进行处理,并将它和sigmoid层的输出相乘,最终输出我们确定要输出的那部分信息 ht 。

Output gate
Output gate

目前为止,我们所讲的是标准的LSTM。LSTM 还有许多变体,这里我们介绍几种变体。

由Gers & Schmidhuber于2000年提出的,增加了 “peephole connection” 的LSTM。主要变化是:3个门层接受了cell state的输入。

Peephole Connection
Peephole Connection

另一个变体是通过使用 coupled 遗忘门和输入门,遗忘和输入是同时进行的。从下图的公式可以看出,新的信息仅仅是输入到那些已经被遗忘的部分。

Coupled forget & input gate
Coupled forget & input gate

另一个变体是 Gated Recurrent Unit (GRU),由 Cho, et al. 于2014年提出。它将忘记门和输入门合成了一个单一的更新门。同样还混合了胞元状态和隐藏状态,和其他一些改动。最终的模型比标准的 LSTM 模型要简单。

GRU
GRU

在给出LSTM代码前,我先给出一下使用标准LSTM进行Image captioning的模型结构图:

Image Captioning by CNN+LSTM
Image Captioning by CNN+LSTM

代码如下:

def lstm_step_forward(x, prev_h, prev_c, Wx, Wh, b):
    _, H = prev_h.shape
    a = x.dot(Wx) + prev_h.dot(Wh) + b       # (N, 4H)
    ai, af, ao, ag = a[:, 0:H], a[:, H:2*H], a[:, 2*H:3*H], a[:, 3*H:]
    i, f, o, g = sigmoid(ai), sigmoid(af), sigmoid(ao), np.tanh(ag)
    next_c = f * prev_c + i * g
    next_h = o * np.tanh(next_c)
    cache = (x, prev_h, prev_c, Wx, Wh, a, i, f, o, g, next_c, next_h)
  
    return next_h, next_c, cache


def lstm_step_backward(dnext_h, dnext_c, cache):
    _, H = dnext_h.shape
    x, prev_h, prev_c, Wx, Wh, a, i, f, o, g, next_c, next_h = cache
    ai, af, ao, ag = a[:, 0:H], a[:, H:2*H], a[:, 2*H:3*H], a[:, 3*H:]
    dnext_c += dnext_h * o * (1 - (np.tanh(next_c))**2)
    do = dnext_h * np.tanh(next_c)
    df = dnext_c * prev_c
    dprev_c = dnext_c * f
    di = dnext_c * g
    dg = dnext_c * i
    dai = di * (sigmoid(ai) * (1-sigmoid(ai)))
    daf = df * (sigmoid(af) * (1-sigmoid(af)))
    dao = do * (sigmoid(ao) * (1-sigmoid(ao)))
    dag = dg * (1 - np.tanh(ag)**2)
    da = np.hstack((dai, daf, dao, dag))               # (N, 4H)
    dx = da.dot(Wx.T)                                  # (N, D)
    dWx = x.T.dot(da)
    dprev_h = da.dot(Wh.T)
    dWh = prev_h.T.dot(da)
    db = np.sum(da, axis=0)

    return dx, dprev_h, dprev_c, dWx, dWh, db


def lstm_forward(x, h0, Wx, Wh, b):
    N, T, D = x.shape
    _, H = h0.shape
    cache = []
    hidden = h0
    h = np.zeros((N, T, H))
    cell = np.zeros((N, H))
    for i in xrange(T):
        hidden, cell, sub_cache = lstm_step_forward(x[:, i, :], hidden, cell, Wx, Wh, b)
        cache.append(sub_cache)
        h[:, i, :] = hidden

    return h, cache


def lstm_backward(dh, cache):
    x, prev_h, prev_c, Wx, Wh, a, i, f, o, g, next_c, next_h = cache[0]
    N, T, H = dh.shape
    N, D = x.shape
    dh0 = np.zeros((N, H))
    db = np.zeros(4*H)
    dWx = np.zeros((D, 4*H))
    dWh = np.zeros((H, 4*H))
    dx = np.zeros((N, T, D))
    dprev_c_ = np.zeros((N, H))
    dprev_h = np.zeros((N, H))
    for i in xrange(T-1, -1, -1):
        dx_, dprev_h, dprev_c_, dWx_, dWh_, db_ = lstm_step_backward(dh[:, i, :]+dprev_h, dprev_c_, cache.pop())
        dWx += dWx_
        dWh += dWh_
        db += db_
        dx[:, i, :] += dx_
        dh0 = dprev_h
  
    return dx, dh0, dWx, dWh, db

这里给出一些在验证集上的结果:

Some examples on validation set
Some examples on validation set

Part 4:图像梯度(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
Examples of the TinyImageNet-100-A
1. Saliency Maps

给定一张图片X,我们想要知道到底是图片中的哪些部分决定了该图片的最终分类结果。给定一个类,我们可以通过反向传播求出X关于loss function的偏导矩阵,这个偏导矩阵就是该图片的图像梯度,然后计算出类显著度图(class saliency map, csm)。Karen Simonyan论文的3.1节给出了计算方法:如果图片是灰度图,那么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
Random images
Cherry-picked 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
Left: original image, Middle: fooling image, Right: difference

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


Part 5:图像生成(Image Generation)

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

1. Class visualization

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

代码如下:

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
Generated images
2. Feature Inversion

这部分我们将完成一个很有意思的工作:在一张随机噪声图像上重建出指定层CNN学习到的图像特征表达。详细的实现方法参见论文: Understanding Deep Image Representations by Inverting them 和 Understanding Neural Networks Through Deep Visualization。

代码如下:

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
Shallow feature reconstruction
Deep 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
Tibidabo
Deeplayer
Deeplayer
Leaning Tower
Leaning Tower

---> CS231n : Assignment 1
---> CS231n : Assignment 2



作者:Deeplayer
链接:http://www.jianshu.com/p/e46b1aa48886
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
斯坦福CS231n课程笔记纯干货1 1. 分类器中L1和L2比较。 在面对两个向量之间的差异时,L2比L1更加不能容忍这些差异,相对于1个巨大的差异,L2距离更倾向于接受多个中等程度的差异。 2. k-Nearest Neighbor分类器存在以下不足 分类器必须记住所有训练数据并将其存储起来,以便于未来测试数据用于比较。这在存储空间上是低效的,数据集的大小很容易就以GB计。对一个测试图像进行分类需要和所有训练图像作比较,算法 阅读详情

相关推荐

【AI】斯坦福CS231n课程练习(1)—— KNN和SVM分类

文章目录一、前言CS231n简介本篇博客任务二、知识准备1、KNN是什么?2、SVM是什么?三、实验 一、前言 CS231n简介 CS231n全称是: Convolutional Neural Networks for Visual Recognition,即面向视觉识别的卷积神经网络。 本篇博客任务 在 Google Colab 上使用 KNN 和 SVM 进行图像分类,具体细节可以查看官方要求。 只完成 Q1: k-Nearest Neighbor classifier 和 Q2: Trainin

火火的博客 2078

斯坦福大学的 CS231n(全称:面向视觉识别的卷积神经网络)

斯坦福大学的 CS231n(全称:面向视觉识别的卷积神经网络)一直是计算机视觉和深度学习领域的经典课程,每年开课都吸引很多学生。今年是该课程第3次开课,学生达到730人(第1次150人,第2次350人)。今年的CS231n Spring的instructors 是李飞飞、Justin Johnson和Serena Yeung,并邀请 Ian Goodfellow 等人讲解GAN等重要主题。最近斯坦...

AI 图像识别 4万+

遥感大模型核心技术之自监督预训练技术研究(2025年9月版)

本文系统探讨了自监督预训练技术在遥感大模型构建中的核心作用。随着遥感数据进入"大数据"时代,传统监督学习面临"数据丰富、标签贫乏"的瓶颈,而自监督预训练通过设计代理任务从无标签数据中学习特征表示,成为驱动大模型发展的关键引擎。文章分析了遥感领域对自监督预训练的三大独特挑战:多源异构性、地理空间约束和时空动态性,并提出了针对性解决方案:掩码自编码(MAE)技术及其演进、地理对比学习与多模态融合、位置感知预训练与多任务学习。

panshengwu的博客 842

CS231N作业3assignment3 RNN&LSTM

CS231N作业3assignment3 RNN&LSTM

weixin_40473318的博客 661

使用vite+react+ts+Ant Design开发后台管理项目(四)

本文将引导开发者从零基础开始,运用、react、react-router、react-redux、Ant Design、less、tailwindcss、axios等前沿技术栈,构建一个高效、响应式的后台管理系统。通过详细的步骤和实践指导,文章旨在为开发者揭示如何利用这些技术工具,从项目构思到最终实现的全过程,提供清晰的开发思路和实用的技术应用技巧。使用vite+react+ts+Ant Design开发后台管理项目(一)使用vite+react+ts+Ant Design开发后台管理项目(二)

lbking666666的专栏 2007

NVIDIA DGX Spark 深度应用解析:从大模型训练到边缘推理的完整实践指南

内存管理:充分利用统一内存架构,避免不必要的数据传输批处理大小:根据模型大小调整批处理大小以优化内存使用精度选择:在精度损失可接受范围内使用较低精度计算流水线优化:重叠计算和数据传输操作DGX Spark作为一个专门的AI计算平台,在大模型开发的各个阶段都能发挥重要作用。从数据预处理到模型训练,从微调到推理部署,其统一内存架构和强大的计算能力为AI开发者提供了前所未有的本地开发体验。需要注意的是,虽然DGX Spark性能强大,但合理的算法设计和系统优化仍然是获得最佳性能的关键。

time_days的博客 2871

CS231n (winter 2016) : Assignment2

目录 前言: Part 1:深层全连接神经网络(python编程任务) 1. 2-layer全连接神经网络 2. Multilayer全连接网络 + Batch Normalization 3. Dropout Part 2:卷积神经网络(Convolutional Neural Networks, CNNs) 1. 卷积层(Convolutional Layer) 2. 池化层(...

lcczzu的专栏 682

【AIGC】COT思维链:让AI学会拆解问题,像人一样思考

COT思维链的出现,为AI的发展开辟了一条新的道路。它让AI学会了像人类一样思考,将复杂问题分解成简单的步骤,并逐步推理出最终答案。希望我的引导会对你产生启发。

智兔唯新的博客 9002

CS231n (winter 2016) : Assignment1

http://www.jianshu.com/p/004c99623104 前言: 以斯坦福cs231n课程的python编程任务为主线,展开对该课程主要内容的理解和部分数学推导。该课程的学习资料和代码如下: 视频和PPT 笔记 assignment1初始代码 Part 1: 线性分类器(Linear classifier) 分值函数,将原始数据(即输入数据,经过

Just for fun的专栏 1761

mbedtls | 01 - 移植mbedtls库到STM32的两种方法

一、mbedtls 开源库 1. mbedtls是什么 Mbed TLS是一个开源、可移植、易于使用、代码可读性高的SSL库。可实现加密原语,X.509证书操作以及SSL / TLS和 DTLS 协议,它的代码占用空间小,非常适合用于嵌入式系统。 mbedtls遵循 Apache 2.0 开源许可协议,目前由 TrustedFirmware 维护(Linaro主持的一个治理开放社区项目),在Github上已收获 2.6k star,目前Github上发布的最新版本为 2.24.0 版本,开源仓库地址为:

Mculover666的博客(嵌入式) 1万+

MATLAB应用实战系列(四十三)-基于MATLAB的光伏并网系统仿真设计

在Matlab中建立光伏电站接入系统模型,包括光伏发电逆变器及负荷模型等,仿真分析接入点处的电能质量,实现高品质并网运行。 壹 构建太阳能电池模型。 初始化参数如下图所示。 贰 构建MPPT控制模型。 具体封装如下所示: 通过PWM算法实现DC-DC稳步输出最大点。 叁 三、构建直流短距离输电线路。 仿真模型如下图: 通过电容来均衡线路电压,使得线路电压保持可靠性。 肆 通过逆变器变换,使得直流线路转换成...

wenyusuran的专栏 3169

vs2015编写python怎么使用rando_CS231n (winter 2016) : Assignment2

前言:以斯坦福cs231n课程的python编程任务为主线,展开对该课程主要内容的理解和部分数学推导。建议PC端阅读,该课程的学习资料和代码如下:视频和PPT笔记assignment2初始代码Part 1:深层全连接神经网络(python编程任务)我们在Assignment1中完成了简单的2-layer全连接神经网络,但是我们之前的编程不够模块化,所有的计算部分(损失函数的计算、梯度的计算等等)都...

weixin_39557373的博客 323

结构光之相移法+多频外差的数学原理推导

‍论文:基于数字光栅投影的结构光三维测量技术与系统研究 [博]作者:李中伟 华中科技大学 2007功能:相移法:多频外差(三频N步相移法)01 相移法图1 待写入投影仪的理想N步相移条纹通常对于 步相移来说,生成第 幅条纹图像(如图1所示)的公式如下:402 Payment Required其中::背景光强:调制强度:像素点横向坐标:相移值图2 相机拍摄到的实际 N ......

3D视觉工坊 1189

cs231n assignment1 tips

1. SVM求dW 这个问题我卡了很久,一直想不通这里到底怎么算的,在GitHub上看了好几个人的代码也硬是没搞懂,最后参考了课程论坛(https://www.reddit.com/r/cs231n/comments/40wh5s/assignment_1_svm_tips/)重新读了几遍这段文字,才搞懂了计算dW的时候分和两种情况,其中前者在score求和的循环中,每一次都要加一遍,一共是

miluzhiyu的专栏 570

掌握 Unity 中的状态机:综合指南

最后,将拥有一个由状态机驱动的功能齐全的播放器控制器,可以集成到自己的项目中。此外,状态机有助于实现复杂的人工智能、玩家控制、动画系统等,从而形成更强大、更灵活的游戏架构。状态机是计算机科学和游戏开发中的一个基本概念,它通过定义一组有限的状态及其之间的转换来模拟实体的行为。你可以定义常见的状态行为,例如 Enter、Update 和 Exit 方法,确保整个状态机架构的一致性和连贯性。由于前面提到的状态类扩展了 BaseState 类,因此我们可以为具有不同状态的不同对象创建单独的类。

yolo模型训练找我,AI游戏合作找我 1453

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

【Python学习笔记】cs231nPython Numpy教程

一些快速创建数组的方法:np.zeros创建全0数组,np.ones创建全1数组,np.full创建一个给定大小和类型并且以指定数字全部填充的新数组,np.eye创建对角线全为1的单位矩阵。很奇怪为什么这里修改切出来的b,会影响a的值,查了以后发现切片相当于只是创建了一个视图,并没有复制一份a,所以修改子数组会在原数组的基础上进行修改。真是基础不牢,地动山摇。还有一点很不适应的地方,是python中的数组和C#也不太一样,C#里输入几个[][]就能定义的数组,到了python里面变复杂了。

bailichen800的博客 2695

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

cs231n 2023春季课程理解——lecture_5

介绍了卷积神经网络的发展史以及它的框架和重要组成部分

清风等雨的博客 864

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

深度学习:CS231n官方笔记

作者:杜客 链接:https://zhuanlan.zhihu.com/p/21930884 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 CS231n简介 CS231n的全称是CS231n: Convolutional Neural Networks for Visual Recognition,即面向视觉识别的卷积神经网络。该课程是斯坦福大学计

wangxiaopeng0329的博客 1万+

cs231n图像分类笔记(上)学习记录

cs231n图像分类笔记(上)的学习记录

qq_62861466的博客 3068

【深度学习】cs231n计算机视觉 CNN(卷积神经网络)

CNN(卷积神经网络) 完成课程笔记:Convolutional Neural Networks for Visual Recognition的理解,便于实现CNN~ 1. 结构概述 2. 用来构建卷积神经网络的各种层 卷积层 池化层 归一化层 全连接层 将全连接层转化为卷积层 3. 卷积神经网络的结构 层的排列规律 层的尺寸设置规律 经典例子(LeNet、AlexNet、ZFNet、GooLeN...

froot的博客 2072

cs231n学习记录-理解线性分类器

关于cs231n中线性分类器部分的一些学习记录

qq_62861466的博客 1898

CS231n 学习笔记(二)

时间:2019/3/24 内容: 1.数据驱动方法 2.KNN 任务: 完成Assignment1 Q1 https://cs231n.github.io/assignments2018/assignment1/ 课时4:数据驱动方法 numpy教程: http://cs231n.github.io/python-numpy-tutorial/ Google Cloud教程: http:/...

kinggerui的博客 485

课程介绍

@(斯坦福李飞飞深度学习上课笔记) 课程介绍 内容主要来自于知乎 https://zhuanlan.zhihu.com/p/21930884 CS231n简介CS231n的全称是CS231n: Convolutional Neural Networks for Visual Recognition,即面向视觉识别的卷积神经网络。该课程是斯坦福大学计算机视觉实验室推出的课程。需要注意的是...

m0_37370820的博客 639
上一篇: CS231n (winter 2016) : Assignment2
下一篇: 通俗理解LDA主题模型
CopperDong
博客等级 码龄14年 1205粉丝 466原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值