二维卷积层 讨论区


#1

http://zh.diveintodeeplearning.org/chapter_convolutional-neural-networks/conv-layer.html


#2

这一节的作业完全蒙了, 请教一下:

作业2:
试着对我们构造的Conv2D进行自动求导,会有什么样的错误信息?

问题1:
    请问此处的"对我们构造的Conv2D进行自动求导"是什么意思?
    我注意到原题中采用的是nn自带的Conv2D实例, 所以我按以下方式修改并采用了我们自己定义的实例
          #conv2d = nn.Conv2D(1, kernel_size=(1, 2))
          conv2d = Conv2D(kernel_size=(1, 2))
     请问这就是"对我们构造的Conv2D进行自动求导"吗?

问题2:
     我在此处得到了以下错误信息:
     MXNetError: [20:42:15] c:\projects\mxnet-distro-win\mxnet-build\src\imperative\./imperative_utils.h:107: Check failed: infershape[attrs.op](attrs, &in_shapes, &out_shapes)
     请问这个错误信息是正确的吗? 我的理解是因为目前X的shape是1x1x6x8, 所以无法直接使用corr2d造成的, 请问这个理解对吗? 

作业3:
在Conv2D的forward函数里,将corr2d替换成nd.Convolution使得其可以求导。

问题1:
     请问如何将corr2d替换成nd.Convolution?
     我有尝试写法1:                
           #return corr2d(x, self.weight.data()) + self.bias.data()
           return nd.Convolution(x,self.weight.data(),self.bias.data())
      得到错误: MXNetError: Required parameter kernel of Shape(tuple) is not presented, in operator Convolution(name="")

      考虑到Convolution的接口定义如下:
            mxnet.ndarray.Convolution(data=None, weight=None, bias=None, kernel=_Null,...)
      我有尝试写法2:
            return nd.Convolution(x, None, None, self.weight.data())
      得到错误: 
            MXNetError: Invalid Parameter format for kernel expect Shape(tuple) but value='[[ 0.0238893  -0.04607266]] <NDArray 1x2 @cpu(0)>', in operator Convolution(name="", kernel="[[ 0.0238893  -0.04607266]]<NDArray 1x2 @cpu(0)>")
      
      请问正确的写法是什么呢?

      请问哪里有类似参考答案之类的东西吗? 谢谢

#3

对于作业2的理解有些进展,

受到5.3节提示, 多修改了两行,

#X = X.reshape((1, 1, 6, 8))
#Y = Y.reshape((1, 1, 6, 7))
X = X.reshape((6, 8))
Y = Y.reshape((6, 7))

得到以下错误:

MXNetError: [21:46:57] C:\projects\mxnet-distro-win\mxnet-build\src\imperative\imperative.cc:250: Check failed: AGInfo::IsNone(*(outputs[i])) Inplace operations (+=, -=, x[:]=, etc) are not supported when recording with autograd.

这和教程原文中的以下内容比较切合了,应该是正确了

虽然我们之前构造了Conv2D类,但由于corr2d使用了对单个元素赋值([i, j]=)的操作会导致无法自动求导,下面我们使用Gluon提供的Conv2D类来实现这个例子。

请多指教, 谢谢


#4

对于作业3,

做了以下修改(这段代码好奇怪,斗胆抛砖引玉,期待漂亮的解决方法), 执行通过,

#return corr2d(x, self.weight.data()) + self.bias.data()
data = x.reshape((1,1,)+x.shape)
weight = self.weight.data()
weight = weight.reshape((1,1,)+weight.shape)
bias = self.bias.data()
kernel = self.weight.shape
return nd.Convolution(data, weight, bias, kernel, stride=(1,1), dilate=(1,1), pad=(0,0), num_filter=1)

这里的实现参考了MXNET的ndarray.Convolution文档


MXNET新手求支招
#5

你理解没问题。corr2d因为用了[i,j]=导致自动求导失败,这是由于autograd目前还有局限性。

改成 nd.Convolution 会没问题,因为它手动实现了backward函数。


#6

非常感谢回复,看到沐神很激动 :+1:


#7
# e.x.3 在 Conv2D 的 forward 函数⾥,将 corr2d 替换成 nd.Convolution 使得其可以求导。
class Conv2D_ex3(nn.Block):
  """
    - **data**: *(batch_size, channel, height, width)*
    - **weight**: *(num_filter, channel, kernel[0], kernel[1])*
    - **bias**: *(num_filter,)*
    - **out**: *(batch_size, num_filter, out_height, out_width)*.
  """

  def __init__(self, channels, kernel_size, **kwargs):
    super(Conv2D_ex3, self).__init__(**kwargs)
    self.weight = self.params.get(
        'weight', shape=(
            channels,
            1,
        ) + kernel_size)
    self.bias = self.params.get('bias', shape=(channels, ))
    self.num_filter = channels
    self.kernel_size = kernel_size

  def forward(self, x):
    return nd.Convolution(
        data=x, weight=self.weight.data(), bias=self.bias.data(), num_filter=self.num_filter, kernel=self.kernel_size)


print('\ne.x.3:')
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))
conv2d = Conv2D_ex3(10, kernel_size=(1, 2))
conv2d.initialize()
for i in range(10):
  with autograd.record():
    Y_hat = conv2d(X)
    l = (Y_hat - Y)**2
    if i % 2 == 1:
      print('batch %d, loss %.3f' % (i, l.sum().asscalar()))
  l.backward()
  conv2d.weight.data()[:] -= 3e-2 * conv2d.weight.grad()

#8

练习最后一题:如何构造⼀个全连接层来进⾏物体边缘检测?
能否给些提示?


#9

针对“试着将 conv2d 的核构造成(2, 2),会学出什么样的结果?”这题:

X3
1

K3
2

Y3
3

训练
4
我不知道错在哪里?


#10

可以参考caffe的卷积实现


#11

请问为什么数据存在gpu里面但是计算之后存在cpu里面? :disappointed_relieved: 思考了好久


#12

Y 默认定义在cpu上


#13

Label是什么呢,如何知道哪里是边缘


#14

image

请教一下,使用教材中定义的Conv2D进行前向计算,为什么输出是一个1x0大小?
代码如下:
conv2d = Conv2D(kernel_size=(1, 2))
conv2d.initialize()
Y_hat = conv2d(X)
Y_hat