[CS231n Assignment 2 #04 ] 卷积神经网络(Convolutional Networks )

作业介绍

  • 课堂笔记:[Lecture 9 ] CNN Architectures(CNN架构)
  • 作业主页:Assignment 2
  • 作业目的:为了使深度神经网络更好的得到训练,一个方案是使用更复杂的优化方法:SGD+Momentum,Adam,RMSProp等。另一个方案就是改变网络结构,比如我们这节要完成的批量归一化。
  • 官方示例代码: Assignment 2 code
  • 作业源文件 ConvolutionalNetworks.ipynb

1. 卷积操作

1. 1 Convolution: Naive forward pass

cs231n/layers.py中实实现conv_forward_naive。这是一个简单的实现,你不必考虑太多的效率问题。

def conv_forward_naive(x, w, b, conv_param):
    """
    A naive implementation of the forward pass for a convolutional layer.

    The input consists of N data points, each with C channels, height H and
    width W. We convolve each input with F different filters, where each filter
    spans all C channels and has height HH and width WW.

    Input:
    - x: Input data of shape (N, C, H, W)
    - w: Filter weights of shape (F, C, HH, WW)
    - b: Biases, of shape (F,)
    - conv_param: A dictionary with the following keys:
      - 'stride': The number of pixels between adjacent receptive fields in the
        horizontal and vertical directions.
      - 'pad': The number of pixels that will be used to zero-pad the input. 
        

    During padding, 'pad' zeros should be placed symmetrically (i.e equally on both sides)
    along the height and width axes of the input. Be careful not to modfiy the original
    input x directly.

    Returns a tuple of:
    - out: Output data, of shape (N, F, H', W') where H' and W' are given by
      H' = 1 + (H + 2 * pad - HH) / stride
      W' = 1 + (W + 2 * pad - WW) / stride
    - cache: (x, w, b, conv_param)
    """
    out = None
    # Hint: you can use the function np.pad for padding.                      #
    stride,pad = conv_param["stride"],conv_param["pad"]
    N, C, H, W = x.shape
    F, C, HH, WW = w.shape

    x_pad = np.pad(x,((0,0),(0,0),(pad,pad),(pad,pad)),
                   mode = 'constant',constant_values = 0)
    # out of shape (N,F,out_H,out_W)
    out_H = 1 + (H + 2 * pad - HH) // stride
    out_W = 1 + (W + 2 * pad - WW) // stride

    out = np.zeros((N,F,out_H,out_W))
    for i in range(out_H):
        for j in range(out_W):
            # 参与计算的数值
            x_pad_masked = x_pad[:,:, i*stride:i*stride+HH, j*stride:j*stride+WW]
            # 每个输出通道分别计算
            for f in range(F):
                # 借助广播机制,会执行 N 次
                # https://cs231n.github.io/python-numpy-tutorial/
                out[:,f,i,j] = np.sum(x_pad_masked * w[f,:,:,:],axis=(1,2,3))
    # 给每一个输出通道加上 bias
    # b of shape (1,F,1,1)
    # out = out + (b)[None,:,None,None]
    # 能用广播机制进行计算, 如果 rank不相等,则先在前面 prepend 1s 直到 shape 有相同的长度
    out = out + b.reshape((1,F,1,1))
    cache = (x, w, b, conv_param)
    return out, cache

1.2 Aside: Image processing via convolutions

为了检查实现并更好地理解卷积层可以执行的操作类型,我们将设置一个包含两幅图像的输入,并手动设置执行常见图像处理操作(灰度转换和边缘检测)的过滤器。卷积前向传递将对每个输入图像应用这些操作。然后我们可以将结果可视化为完整性检查。

from scipy.misc import imread, imresize

kitten, puppy = imread('kitten.jpg'), imread('puppy.jpg')
# kitten is wide, and puppy is already square
d = kitten.shape[1] - kitten.shape[0]
kitten_cropped = kitten[:, d//2:-d//2, :]

img_size = 200   # Make this smaller if it runs too slow
x = np.zeros((2, 3, img_size, img_size))
x[0, :, :, :] = imresize(puppy, (img_size, img_size)).transpose((2, 0, 1))
x[1, :, :, :] = imresize(kitten_cropped, (img_size, img_size)).transpose((2, 0, 1))

# Set up a convolutional weights holding 2 filters, each 3x3
w = np.zeros((2, 3, 3, 3))

# The first filter converts the image to grayscale.
# Set up the red, green, and blue channels of the filter.
w[0, 0, :, :] = [[0, 0, 0], [0, 0.3, 0], [0, 0, 0]]
w[0, 1, :, :] = [[0, 0, 0], [0, 0.6, 0], [0, 0, 0]]
w[0, 2, :, :] = [[0, 0, 0], [0, 0.1, 0], [0, 0, 0]]

# Second filter detects horizontal edges in the blue channel.
w[1, 2, :, :] = [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]

# Vector of biases. We don't need any bias for the grayscale
# filter, but for the edge detection filter we want to add 128
# to each output so that nothing is negative.
b = np.array([0, 128])

# Compute the result of convolving each input in x with each filter in w,
# offsetting by b, and storing the results in out.
out, _ = conv_forward_naive(x, w, b, {
   'stride': 1, 'pad': 1})

def imshow_noax(img, normalize=True):
    """ Tiny helper to show images as uint8 and remove axis labels """
    if normalize:
        img_max, img_min = np.max(img), np.min(img)
        img = 255.0 * (img - img_min) / (img_max - img_min)
    plt.imshow(img.astype('uint8'))
    plt.gca().axis('off')

# Show the original images and the results of the conv operation
plt.subplot(2, 3, 1)
imshow_noax(puppy, normalize=False)
plt.title('Original image')
plt.subplot(2, 3, 2)
imshow_noax(out[0, 0])
plt.title('Grayscale')
plt.subplot(2, 3, 3)
imshow_noax(out[0, 1])
plt.title('Edges')
plt.subplot(2, 3, 4)
imshow_noax(kitten_cropped, normalize=False)
plt.subplot(2, 3, 5)
imshow_noax(out[1, 0])
plt.subplot(2, 3, 6)
imshow_noax(out[1, 1])
plt.show()

在这里插入图片描述
可以看到,第一个卷积核执行的是类似灰度化的操作,即输出结果等于 0.3R+0.6G+0.1*B
第二个卷积核检测蓝色通道中的水平边缘。

1.3. Convolution: Naive backward pass

也是只实现功能,先暂不考虑效率

def conv_backward_naive(dout, cache):
    """
    A naive implementation of the backward pass for a convolutional layer.

    Inputs:
    - dout: Upstream derivatives.
    - cache: A tuple of (x, w, b, conv_param) as in conv_forward_naive

    Returns a tuple of:
    - dx: Gradient with respect to x
    - dw: Gradient with respect to w
    - db: Gradient with respect to b
    """
    dx, dw, db = None, None, None
    # TODO: Implement the convolutional backward pass.
    (x, w, b, conv_param) = cache
    stride, pad = conv_param["stride"], conv_param["pad"]
    N, C, H, W = x.shape
    F, C, HH, WW = w.shape
    out_H = 1 + (H + 2 * pad - HH
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值