【问题标题】:Gradient of the layers of a loaded neural network in ChainerChainer 中加载的神经网络层的梯度
【发布时间】:2018-11-06 12:38:36
【问题描述】:

我正在 Chainer 中加载预训练模型:

net=chainer.links.VGG16Layers(pretrained_model='auto')

然后,我用一些数据进行前向传递并添加一个损失层:

acts = net.predict([image]).array loss=chainer.Variable(np.array(np.sum(np.square(acts-one_hot))))

现在的问题是,如何进行反向传递并获得不同层的渐变?

典型的后退方法不起作用。

【问题讨论】:

    标签: python deep-learning pre-trained-model chainer vgg-net


    【解决方案1】:

    如果要获取输入图像的.grad,则必须将输入包装为chainer.Variable
    但是VGGLayers.extract()不支持Variable的输入,所以在这种情况下你应该调用.forward()或者它的包装函数__call__()

    import chainer
    from chainer import Variable
    from chainer import functions as F
    from cv2 import imread
    from chainer.links.model.vision import vgg
    
    net = vgg.VGG16Layers(pretrained_model='auto')
    
    # convert raw image (np.ndarray, dtype=uint32) to a batch of Variable(dtype=float32)
    img = imread("path/to/image")
    img = Variable(vgg.prepare(img))
    img = img.reshape((1,) + img.shape)  # (channel, width, height) -> (batch, channel, width, height)
    
    # just call VGG16Layers.forward, which is wrapped by __call__()
    prob = net(img)['prob']
    intermediate = F.square(prob)
    loss = F.sum(intermediate)
    
    # calculate grad
    img_grad = chainer.grad([loss], [img])  # returns Variable
    print(img_grad.array) # some ndarray
    

    【讨论】:

    • 我不确定我是否应该在这里问这个;但是为什么你需要 img 的 vgg.prepare 将它传递给 net(),但你可以将图像原样传递给 net.predict()?他们不是一样的方法吗?为什么 vgg.prepare() 会为给定的图像制作一个 3x3 的表格(9 个副本)?
    • 1. vgg.prepare 只是包含在 net.predict() 中。 2. img.shape == (1440, 1920, 3), vgg.prepare(img).shape == (3, 224, 224)。 img.dtype == dtype('uint8'), vgg.prepare(img).dtype == dtype('float32')。这就是原因。
    • 我仍然不明白为什么 vgg.prepare 在 224x224 图像中从给定图像制作 9 个小比例副本:如果你给它一个像 X 的图像,它会给你 xxx(x 是X) xxx xxx 的小尺寸版本
    • 不,正如我上一条评论所示,它没有提供 9 个小副本。如果你得到副本,就会出现问题。它只会调整大小、缩放和转置 (H, W, C) -> (C, H, W)。
    • 我已经更准确地提出了这个问题,并将输入和输出附在此处:stackoverflow.com/questions/53257608/…
    【解决方案2】:

    第 1 点。
    不要调用VGGLayers.predict(),这不是用于反向传播计算的。
    请改用VGGLayers.extract()

    第 2 点。
    不要将np.square()np.sum() 直接应用于chainer.Variable
    请使用F.square()F.sum() 代替chainer.Variable

    第 3 点。
    使用loss.backward() 获取.grad 以获得可学习的参数。 (模式一)
    使用loss.backward(retain_grad=True) 获取所有变量的.grad。 (模式二)
    使用chainer.grad() 获取特定变量的.grad。 (模式3)

    代码:

    import chainer
    from chainer import functions as F, links as L
    from cv2 import imread
    
    net = L.VGG16Layers(pretrained_model='auto')
    img = imread("/path/to/img")
    prob = net.extract([img], layers=['prob'])['prob']  # NOT predict, which overrides chainer.config['enable_backprop'] as False
    intermediate = F.square(prob)
    loss = F.sum(intermediate)
    
    # pattern 1:
    loss.backward()
    print(net.fc8.W.grad)  # some ndarray
    print(intermediate.grad)  # None
    ###########################################
    net.cleargrads()
    intermediate.grad = None
    prob.grad = None
    ###########################################
    
    # pattern 2:
    loss.backward(retain_grad=True)
    print(net.fc8.W.grad)  # some ndarray
    print(intermediate.grad)  # some ndarray
    
    ###########################################
    net.cleargrads()
    intermediate.grad = None
    prob.grad = None
    ###########################################
    
    # pattern 3:
    print(chainer.grad([loss], [net.fc8.W]))  # some ndarray
    print(intermediate.grad)  # None
    

    【讨论】:

    • 非常感谢您回答 Yuki,这行得通!
    • 我标记为已解决,但由于我的声誉不足 15 个,因此无法投票。
    • 如何获取输入层(图像)的渐变?因为VGG没有这样的层。
    • 感谢标记已解决!我添加了另一个答案来获取输入图像。这有点棘手,所以如果您有任何问题,请不要犹豫!
    • 我不确定我是否明白提取和预测之间的区别。预测与背景有什么关系?因为直觉上它应该只是向前传球。
    猜你喜欢
    • 2018-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 2014-10-10
    相关资源
    最近更新 更多