NNDL 作业7:第五章课后题(1×1 卷积核 | CNN BP)

实验目录

前言

一、习题5-2证明宽卷积具有交换性,即公式(5.13)

二、习题5-3 分析卷积神经网络中用1×1的卷积核的作用

1 、跨通道的特征整合(这个以前达哥没说过,我感觉有点类似于升维降维,)

2、降维/升维

3 、加非线性

4 、减少计算量

5、增加模型深度。

三、习题5-4

说一下咱为什么要算这个

四、习题5-7 忽略激活函数,分析卷积网络中卷积层的前向计算和反向传播(公式(5.39))是一种转置关系.

CNN的反向传播 

1、算法思想

2、有关导数的知识 

3、已知池化层,推导上一隐藏层

         4、已知卷积层,推导上一隐藏层

5、已知卷积层,推导该层的W,b的梯度

好了,问题都解决了,下边总结一下思想。

代码实现反向传播

numpy实现卷积层

 numpy实现pool层

总结


前言

     首先,先说一下,这次用了达哥好多东西,就不一一感谢了,在这里对达哥长跪不起。

     其次,这次弄了好长时间,真的累,感觉最近一直在写(哈哈哈),但是我相信这都是值得的。

     最后,好多同学去考教资了,今天催了一天核算,感觉大家都在努力,大家加油吧,咱们都加油。(哈哈哈)


老师发的图,必须给予足够的尊重。(哈哈哈) 

一、习题5-2证明宽卷积具有交换性,即公式(5.13)

        首先,这个我是按老师的思路来推得,也就是,下边这张图,我会发一下,我写的证明,过程,但是我写的有的类似于通项公式的感觉,所以也是推了一会。

       上边这个式子就是推导的过程了,但是这个有点类似于是例子了,因为都赋值了特别的数了,所以后边我按类似通项公式的方法证明了一下。

       这里先解释一下各个参数以及符号的含义的含义。

 这是宽卷积的定义,这里要说一点,什么是宽卷积。

       宽卷积被定义成了这种形式,结合上边的图,也就是说,结合一下可以认为是原图像被填充了之后的卷积运算,至于完的大小是多少呢。也就是下边的大小。

        

       说一下,为什么要填充的问题,因为卷积核和矩阵的大小是不一样的,卷积谁卷谁是不一样的,也就是解释一下咱们让证明的结论,是不一样的,所以这里给大家说一下。

       在不看翻转一百八十度的情况下,前边的表示W当卷积核,X做被卷积的对象,后边的表示X当卷积核,W做被卷积的对象。

       然后就是证明过程了,我写在纸上了,因为写在平板上有点没法看了(哈哈哈)。

        这个是证明过程,完全手推了一遍,一开始想写成通项公式的,后来发现有点困难(我是FW,哈哈哈)

二、习题5-3 分析卷积神经网络中用1×1的卷积核的作用

       我会结合之前看的达哥的视频来说一说,没办法说这个权威的就绕不开达哥。

1 、跨通道的特征整合(这个以前达哥没说过,我感觉有点类似于升维降维,)

       首先,说下一,我的感觉这个作用呢,其实在一个维度上体现不出来的,这个有点类似于在多维上的一个全连接层的感觉,来看看下边的解释吧(这个作用我也是第一次听说,所以就放在这吧,但是我感觉这和解释有点不太好)。

      上述情况,并没有显示1x1卷积的特殊之处,那是因为上面输入的矩阵channel为1,所以1x1卷积的channel也为1。这时候只能起到升维的作用。这并不是1x1卷积的魅力所在。

      让我们看一下真正work的示例。当输入为6x6x32时,1x1卷积的形式是1x1x32,当只有一个1x1卷积核的时候,此时输出为6x6x1。此时便可以体会到1x1卷积的实质作用:降维。当1x1卷积核的个数小于输入channels数量时,即降维[3]。

       注意,下图中第二行左起第二幅图像中的黄色立方体即为1x1x32卷积核,而第二行左起第一幅图像中的黄色立方体即是要与1x1x32卷积核进行叠加运算的区域。

其实1x1卷积,可以看成一种全连接(full connection)。

       第一层有6个神经元,分别是a1—a6,通过全连接之后变成5个,分别是b1—b5,第一层的六个神经元要和后面五个实现全连接,本图中只画了a1—a6连接到b1的示意,可以看到,在全连接层b1其实是前面6个神经元的加权和,权对应的就是w1—w6,到这里就很清晰了:

      第一层的6个神经元其实就相当于输入特征里面那个通道数:6,而第二层的5个神经元相当于1*1卷积之后的新的特征通道数:5。w1—w6是一个卷积核的权系数,若要计算b2—b5,显然还需要4个同样尺寸的卷积核[4]。

     上述列举的全连接例子不是很严谨,因为图像的一层相比于神经元还是有区别的,图像是2D矩阵,而神经元就是一个数字,但是即便是一个2D矩阵(可以看成很多个神经元)的话也还是只需要一个参数(1*1的核),这就是因为参数的权值共享。

                       

注:1x1卷积一般只改变输出通道数(channels),而不改变输出的宽度和高度

2、降维/升维

下边我找一个图,感觉这个是非常直观的可以提现的

升维

       由于 1×1 并不会改变 height 和 width,改变通道的第一个最直观的结果,就是可以将原本的数据量进行增加或者减少。这里看其他文章或者博客中都称之为升维、降维。但我觉得维度并没有改变,改变的只是 height × width × channels 中的 channels 这一个维度的大小而已。

3 、加非线性

       1*1卷积核,可以在保持feature map尺度不变的(即不损失分辨率)的前提下大幅增加非线性特性(利用后接的非线性激活函数),把网络做的很deep。

       卷积层之后经过激励层,1*1的卷积在前一层的学习表示上添加了非线性激励( non-linear activation ),增加模型深度,一定程度上提升模型的表征能力

4 、减少计算量

这个直接上达哥照片了,达哥无敌(遇事不决,但问达哥)

降维

  至于这两张照片的解释,还就是下边的照片的了,这来自于达哥推荐的讲课笔记image-20200611213427453

5、增加模型深度

可以减少网络模型参数,增加网络层深度,一定程度上提升模型的表征能力。

三、习题5-4

对于一个输入为100×100×256的特征映射,再进行3×3的卷积,得到100×100×256的特征映射组,求时间和空间复杂度。如果引入一个1×1卷积核,先得到100×100×64的特征映射,再进行3×3的卷积,得到100×100×256的特征映射组,求其时间和空间复杂度。

       先给大家说一下这个,怎么计算,因为之前我只听达哥说过,当时也就每太学明白,感觉这个和数据结构计算复杂度有点类似,但是这个又有点区别,所以我就放在下边了,把这个的概念。

 时间复杂度一:256×100×100×256×3×3 = 5,898,240,000

 空间复杂度一:256×100×100 = 2,560,000

时间复杂度二:64×100×100×256 + 256×100×100×64×3×3 = 1,638,400,000

空间复杂度二:64×100×100 + 256×100×100 = 3,200,000

说一下咱为什么要算这个

  • 时间复杂度决定了模型的训练/预测时间。如果复杂度过高,则会导致模型训练和预测耗费大量时间,既无法快速的验证想法和改善模型,也无法做到快速的预测。
  • 空间复杂度决定了模型的参数数量。由于维度诅咒的限制,模型的参数越多,训练模型所需的数据量就越大,而现实生活中的数据集通常不会太大,这会导致模型的训练更容易过拟合。
  • 当我们需要裁剪模型时,由于卷积核的空间尺寸通常已经很小(3x3),而网络的深度又与模型的表征能力紧密相关,不宜过多削减,因此模型裁剪通常最先下手的地方就是通道数。

四、习题5-7 忽略激活函数,分析卷积网络中卷积层的前向计算和反向传播(公式(5.39))是一种转置关系.

上边是咱们看看一下刘建平老师的结论,然后咱们来手推一下。

 


CNN的反向传播 

       先粘一下刘建平老师的博客,拜一拜(我是FW)

      卷积神经网络(CNN)反向传播算法 - 刘建平Pinard - 博客园

       说一下我这个反向传播的过程,我这个是看了刘建平老师的之后,又看了老师的ppt写的,所以两个我会穿插着来写(因为老师说让预习,所以我就看了看着两个,我就穿插着来写了)。

       最重要的是,说一下思路,重要的是思路,这个我是和刘建平老师的一样的,我看老师的ppt上边大致也是这个思路,所以还是要说一下思路。

1、算法思想

2、有关导数的知识 

       首先,要是想知道CNN的反向传播就要要知道,这个当中的导数下边放两个结论,这个后边会用到,先看一下导数,其实和第一个问题题也有点关系。

       证明的过程就像这上边这两个写的,只需要把他展开,然后每个偏导数算出来后,带回去,观察一下规律和形式即可。

3、已知池化层,推导上一隐藏层

       然后,就要看一下一层一层往回推了,关于激活层,和DNN是一样的,所以咱们现在关注的是卷积层和隐藏层,咱们先来看一下隐藏层,这个怎么处理,它是由小变大(反向传播时)。

       但是,老师说咱们遵循的思想是,没有必要纠结它原来是啥样的,只要可以迭代就行了,并且只要迭代的依据,合理就行了,所以咱们看一下,下边的图,下边就是处理的方式。

        

        注意我上边画的那句话,如果只是用框架而不考虑原来的话,咱们是很不容易想知道,这一层的,会下意识以为都会更新,其实这一层只是为卷积层参数的更新,做准备。

4、已知卷积层,推导上一隐藏层

这个是咱们一直没想过的,其实也是不太好想到的,如何反向传播呢,看下边的图

              

       看这个可能看不出来啥,但是看看这个就会好不少了,就像老师说的方法,直接往里代数,是最明白的方法,因为这个是通项公式,所以看下边是最明白的。

    当带入这个例子之后,就会明白是啥意思了,然后就是关键参数更新的问题。

5、已知卷积层,推导该层的W,b的梯度

 这个其实也是在上边,但是看看后边这个刘建平老师的会清楚一点。

 关键就是,我画出来的那,那是真正的迭代公式,根据这个可以推出好多东西.

好了,问题都解决了,下边总结一下思想。

       如果你还是不太明白去看刘建平老师原文,并且直接把我上边画的算法背过,就像我说的,直接背过,把它当成一个优化算法,实际上它就是一个优化算法背过。

代码实现反向传播

【DeepLearning.AI】使用numpy搭建卷积神经网络_csdn0006的博客-CSDN博客

上边是我参考的链接,这个非常好几乎不用改,所以非常推荐这个。

先说一下,我这个又看的达哥,推荐大家去做做这个作业,这个作业,真的很好,下边是链接。

deeplearning.ai官网地址:https://www.deeplearning.ai/
coursera地址:https://www.coursera.org/specializations/deep-learning
网易视频地址:https://163.lu/nPtn42

numpy实现卷积层

import numpy as np
def padding(X, pad):
    X_pad = np.pad(X, (
        (0, 0),
        (pad, pad),
        (pad, pad),
        (0, 0)),
         mode='constant', constant_values=(0, 0))
    return X_pad
def conv_single_step(a_slice_prev, W, b):
    s = np.multiply(a_slice_prev, W)
    Z = np.sum(s)
    Z = Z + float(b)
    return Z
def conv_forward(A_prev, W, b, hparameters):
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    (f, f, n_C_prev, n_C) = W.shape
    stride = hparameters['stride']
    pad = hparameters['pad']
    n_H = int((n_H_prev + 2 * pad - f) / stride) + 1
    n_W = int((n_W_prev + 2 * pad - f) / stride) + 1
    Z = np.zeros((m, n_H, n_W, n_C))
    A_prev_pad = padding(A_prev, pad)
 
    for i in range(m):  # 依次遍历每个样本
        a_prev_pad = A_prev_pad[i]  # 获取当前样本
        for h in range(n_H):  # 在输出结果的垂直方向上循环
            for w in range(n_W):  # 在输出结果的水平方向上循环
                # 确定分片边界
                vert_start = h * stride
                vert_end = vert_start + f
                horiz_start = w * stride
                horiz_end = horiz_start + f
 
                for c in range(n_C):
                    a_slice_prev = a_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :]
                    weights = W[:, :, :, c]
                    biases = b[:, :, :, c]
                    Z[i, h, w, c] = conv_single_step(a_slice_prev, weights, biases)
 
    assert (Z.shape == (m, n_H, n_W, n_C))
    mask = (A_prev, W, b, hparameters)
 
    return Z, mask
 
def backward(theta, mask):
    (A_prev, W, b, hparameters) = mask
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    (f, f, n_C_prev, n_C) = W.shape
    stride = hparameters['stride']
    pad = hparameters['pad']
    (m, n_H, n_W, n_C) = theta.shape
    dA_prev = np.zeros_like(A_prev)
    dW = np.zeros_like(W)
    db = np.zeros_like(b)
    A_prev_pad = padding(A_prev, pad)
    dA_prev_pad = padding(dA_prev, pad)
    for i in range(m):
        a_prev_pad = A_prev_pad[i]
        da_prev_pad = dA_prev_pad[i]
        for h in range(n_H):
            for w in range(n_W):
                for c in range(n_C):
                    vert_start = h * stride
                    vert_end = vert_start + f
                    horiz_start = w * stride
                    horiz_end = horiz_start + f
                    a_slice = a_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :]
                    da_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :] += W[:, :, :, c] * theta[i, h, w, c]
                    dW[:, :, :, c] += a_slice * theta[i, h, w, c]
                    db[:, :, :, c] += theta[i, h, w, c]
        dA_prev[i, :, :, :] = da_prev_pad[pad:-pad, pad:-pad, :]
    assert (dA_prev.shape == (m, n_H_prev, n_W_prev, n_C_prev))
    return dA_prev, dW, db
 
A_prev = np.random.randn(10, 4, 4, 3)
W = np.random.randn(2, 2, 3, 8)
b = np.random.randn(1, 1, 1, 8)
hparameters = {"pad": 2,
               "stride": 2}
Z, mask_conv = conv_forward(A_prev, W, b, hparameters)
dA, dW, db = backward(Z, mask_conv)
print("卷积层卷积核参数反向传播的梯度:", dW)
print("卷积层偏置项反向传播的梯度:", db)

运行的结果为: 

卷积层卷积核参数反向传播的梯度: [[[[  31.42913047  -12.47153813  -45.41016435   35.07160417
      60.30547542    2.8871371   -79.40576056  -16.12764977]
   [ -53.20110779   64.5110405   -54.1574803   -90.37462444
      18.8176767   -73.81087417  -24.07725907   95.6855387 ]
   [  -7.7386836    -2.53636619    6.18032124    4.34436482
      49.13338505  -23.44325337 -127.44179114  -55.87410423]]

  [[ -14.04970202   24.96498076   -0.62472701   -7.0074776
      48.11546773   -4.40855962   42.41258614   32.76290263]
   [  -1.13850367   36.15560419  -10.78959271   13.35411978
       6.40244788    7.90755694   72.91674887   -3.23617763]
   [ -22.15236115  -51.2327243    12.65542316   -3.32077206
    -103.97536578    6.53955358   82.58627604   62.04380178]]]


 [[[  47.19593445   14.27731655  -28.85062584   58.51981639
      18.12303853   57.70873806  -49.86888402  -45.13486994]
   [ -59.19660328   37.0735197    26.85473098  -97.31396722
      12.72572152   -4.91683399  -96.41736635  -62.58445315]
   [  80.46610841   69.73012727  -13.45219514  -14.46524539
      61.39974108   20.98695123  -60.95814777   -8.79551477]]

  [[ -16.86346229   64.22548354  -30.99536862    1.61650126
       2.87938797  -31.34498891  156.96986582   51.1906482 ]
   [  -8.19525392  -16.95594014   38.36935404   16.04501015
     -48.6240528    24.95979207   36.96938906   73.48643083]
   [  30.92264532   69.94530585    7.33086347  -16.98406354
      48.84868955  -33.25365077   39.46448879   -8.21115204]]]]
卷积层偏置项反向传播的梯度: [[[[-25.47387879  71.05584238  59.36613663 192.05778277 -61.3838614
    -92.97293761 206.51648296 290.36721838]]]]

 numpy实现pool层

# coding=gbk
import numpy as np


def padding(X, pad):
    X_pad = np.pad(X, (
        (0, 0),
        (pad, pad),
        (pad, pad),
        (0, 0)),
                   mode='constant', constant_values=(0, 0))
    return X_pad


def conv_single_step(a_slice_prev, W, b):
    s = np.multiply(a_slice_prev, W)
    Z = np.sum(s)
    Z = Z + float(b)
    return Z


def conv_forward(A_prev, W, b, hparameters):
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    (f, f, n_C_prev, n_C) = W.shape
    stride = hparameters['stride']
    pad = hparameters['pad']
    n_H = int((n_H_prev + 2 * pad - f) / stride) + 1
    n_W = int((n_W_prev + 2 * pad - f) / stride) + 1
    Z = np.zeros((m, n_H, n_W, n_C))
    A_prev_pad = padding(A_prev, pad)

    for i in range(m):  # 依次遍历每个样本
        a_prev_pad = A_prev_pad[i]  # 获取当前样本
        for h in range(n_H):  # 在输出结果的垂直方向上循环
            for w in range(n_W):  # 在输出结果的水平方向上循环
                # 确定分片边界
                vert_start = h * stride
                vert_end = vert_start + f
                horiz_start = w * stride
                horiz_end = horiz_start + f

                for c in range(n_C):
                    a_slice_prev = a_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :]
                    weights = W[:, :, :, c]
                    biases = b[:, :, :, c]
                    Z[i, h, w, c] = conv_single_step(a_slice_prev, weights, biases)

    assert (Z.shape == (m, n_H, n_W, n_C))
    mask = (A_prev, W, b, hparameters)

    return Z, mask


def backward(theta, mask):
    (A_prev, W, b, hparameters) = mask
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    (f, f, n_C_prev, n_C) = W.shape
    stride = hparameters['stride']
    pad = hparameters['pad']
    (m, n_H, n_W, n_C) = theta.shape
    dA_prev = np.zeros_like(A_prev)
    dW = np.zeros_like(W)
    db = np.zeros_like(b)
    A_prev_pad = padding(A_prev, pad)
    dA_prev_pad = padding(dA_prev, pad)
    for i in range(m):
        a_prev_pad = A_prev_pad[i]
        da_prev_pad = dA_prev_pad[i]
        for h in range(n_H):
            for w in range(n_W):
                for c in range(n_C):
                    vert_start = h * stride
                    vert_end = vert_start + f
                    horiz_start = w * stride
                    horiz_end = horiz_start + f
                    a_slice = a_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :]
                    da_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :] += W[:, :, :, c] * theta[i, h, w, c]
                    dW[:, :, :, c] += a_slice * theta[i, h, w, c]
                    db[:, :, :, c] += theta[i, h, w, c]
        dA_prev[i, :, :, :] = da_prev_pad[pad:-pad, pad:-pad, :]
    assert (dA_prev.shape == (m, n_H_prev, n_W_prev, n_C_prev))
    return dA_prev, dW, db


A_prev = np.random.randn(10, 4, 4, 3)
W = np.random.randn(2, 2, 3, 8)
b = np.random.randn(1, 1, 1, 8)
hparameters = {"pad": 2,
               "stride": 2}
Z, mask_conv = conv_forward(A_prev, W, b, hparameters)
dA, dW, db = backward(Z, mask_conv)
print("卷积层卷积核参数反向传播的梯度:", dW)
print("卷积层偏置项反向传播的梯度:", db)

import numpy as np


def mask1(x):
    mask = (x == np.max(x))
    return mask


def distribute_value(dz, shape):
    (n_H, n_W) = shape
    average = dz / (n_H * n_W)
    a = np.ones(shape) * average
    return a


def pool_forward(A_prev, hparameters, mode="max"):
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    f = hparameters["f"]
    stride = hparameters["stride"]
    # 计算输出数据的维度
    n_H = int(1 + (n_H_prev - f) / stride)
    n_W = int(1 + (n_W_prev - f) / stride)
    n_C = n_C_prev
    # 定义输出结果
    A = np.zeros((m, n_H, n_W, n_C))
    # 逐个计算,对A的元素进行赋值
    for i in range(m):  # 遍历样本
        for h in range(n_H):  # 遍历n_H维度
            # 确定分片垂直方向上的位置
            vert_start = h * stride
            vert_end = vert_start + f

            for w in range(n_W):  # 遍历n_W维度
                # 确定分片水平方向上的位置
                horiz_start = w * stride
                horiz_end = horiz_start + f

                for c in range(n_C):  # 遍历通道
                    # 确定当前样本上的分片
                    a_prev_slice = A_prev[i, vert_start:vert_end, horiz_start:horiz_end, c]
                    # 根据池化方式,计算当前分片上的池化结果
                    if mode == "max":  # 最大池化
                        A[i, h, w, c] = np.max(a_prev_slice)
                    elif mode == "average":  # 平均池化
                        A[i, h, w, c] = np.mean(a_prev_slice)

    # 将池化层的输入和超参数缓存
    cache = (A_prev, hparameters)

    # 确保输出结果维度正确
    assert (A.shape == (m, n_H, n_W, n_C))

    return A, cache


def pool_backward(dA, cache, mode="max"):
    (A_prev, hparameters) = cache

    stride = hparameters['stride']
    f = hparameters['f']

    m, n_H_prev, n_W_prev, n_C_prev = A_prev.shape
    m, n_H, n_W, n_C = dA.shape

    # 对输出结果进行初始化
    dA_prev = np.zeros_like(A_prev)

    for i in range(m):  # 遍历m个样本
        a_prev = A_prev[i]

        for h in range(n_H):  # 在垂直方向量遍历
            for w in range(n_W):  # 在水平方向上循环
                for c in range(n_C):  # 在通道上循环
                    # 找到输入的分片的边界
                    vert_start = h * stride
                    vert_end = vert_start + f
                    horiz_start = w * stride
                    horiz_end = horiz_start + f

                    # 根据池化方式选择不同的计算过程
                    if mode == "max":
                        # 确定输入数据的切片
                        a_prev_slice = a_prev[vert_start:vert_end, horiz_start:horiz_end, c]
                        # 创建掩码
                        mask = mask1(a_prev_slice)
                        # 计算dA_prev
                        dA_prev[i, vert_start: vert_end, horiz_start: horiz_end, c] += np.multiply(mask, dA[i, h, w, c])

                    elif mode == "average":
                        # 获取da值, 一个实数
                        da = dA[i, h, w, c]
                        shape = (f, f)
                        # 反向传播
                        dA_prev[i, vert_start: vert_end, horiz_start: horiz_end, c] += distribute_value(da, shape)

    assert (dA_prev.shape == A_prev.shape)

    return dA_prev


np.random.seed(1)
A_prev = np.random.randn(5, 5, 3, 2)
hparameters = {"stride": 1, "f": 2}
A, cache = pool_forward(A_prev, hparameters)
dA = np.random.randn(5, 4, 2, 2)

dA_prev = pool_backward(dA, cache, mode="max")
print("============最大池化========")
print('反向传播梯度 ', dA)
dA_prev = pool_backward(dA, cache, mode="average")
print("===========平均池化========")
print('反向传播梯度', dA)

运行结果为:

卷积层卷积核参数反向传播的梯度: [[[[-126.52488701   27.76556659   -2.2464933    86.11020769
      19.52201685   28.29642579   44.19764422   50.20518569]
   [ -38.79059808  -17.57805922   -7.282972     17.06857297
     -31.35973095   14.68326387    2.80083373  -38.54246307]
   [  58.68543355   -6.94468745   46.22006138  -37.25660512
      31.97466423  -43.49915871   -8.30506926   29.90939317]]

  [[   5.161268    -48.90918462  -13.11410751  -57.30491441
     -66.96066137   46.99907908   -8.26910861  -29.75586579]
   [  -3.88012341  -58.819354    -21.42136185   13.82424834
     -19.97358945   20.44846435   14.20835983  -18.50078113]
   [ -10.49188041    8.7658666   -53.79326336   16.35017475
      36.10106008  -28.31057672   73.11315682    6.10029167]]]


 [[[ -19.97792322   76.82597153   54.48692623   37.62870196
      70.54394023  -39.56709716   18.01369763  101.93723354]
   [ -14.76432092  -43.06017827   -1.97397716    6.62377836
      30.67268016   36.83800116  -18.26844866   -3.60393909]
   [  13.29600014    3.78669439   31.39629153   -3.89935849
      19.29515041   49.11361376   14.22837548  -20.58263294]]

  [[  69.65295602  -35.56803708   28.04614939   -6.76879273
      57.80671662  -11.47974856  -23.24252582   17.88121683]
   [  96.69723487  -80.93249826  -53.56201791  -13.48361602
     -78.1324028   -12.0546882     0.55606304 -126.70864974]
   [  19.21469097   11.72582474  -47.49869861    3.20684034
       0.57624361  -86.50789852  -43.18466273  -13.85808961]]]]
卷积层偏置项反向传播的梯度: [[[[ 33.84442178  17.74786076 157.25475146 249.69795628 -33.48775602
    143.02215941 144.8860251  278.58541871]]]]
============最大池化========
反向传播梯度  [[[[-0.31011677 -2.43483776]
   [ 1.0388246   2.18697965]]

  [[ 0.44136444 -0.10015523]
   [-0.13644474 -0.11905419]]

  [[ 0.01740941 -1.12201873]
   [-0.51709446 -0.99702683]]

  [[ 0.24879916 -0.29664115]
   [ 0.49521132 -0.17470316]]]


 [[[ 0.98633519  0.2135339 ]
   [ 2.19069973 -1.89636092]]

  [[-0.64691669  0.90148689]
   [ 2.52832571 -0.24863478]]

  [[ 0.04366899 -0.22631424]
   [ 1.33145711 -0.28730786]]

  [[ 0.68006984 -0.3198016 ]
   [-1.27255876  0.31354772]]]


 [[[ 0.50318481  1.29322588]
   [-0.11044703 -0.61736206]]

  [[ 0.5627611   0.24073709]
   [ 0.28066508 -0.0731127 ]]

  [[ 1.16033857  0.36949272]
   [ 1.90465871  1.1110567 ]]

  [[ 0.6590498  -1.62743834]
   [ 0.60231928  0.4202822 ]]]


 [[[ 0.81095167  1.04444209]
   [-0.40087819  0.82400562]]

  [[-0.56230543  1.95487808]
   [-1.33195167 -1.76068856]]

  [[-1.65072127 -0.89055558]
   [-1.1191154   1.9560789 ]]

  [[-0.3264995  -1.34267579]
   [ 1.11438298 -0.58652394]]]


 [[[-1.23685338  0.87583893]
   [ 0.62336218 -0.43495668]]

  [[ 1.40754     0.12910158]
   [ 1.6169496   0.50274088]]

  [[ 1.55880554  0.1094027 ]
   [-1.2197444   2.44936865]]

  [[-0.54577417 -0.19883786]
   [-0.7003985  -0.20339445]]]]
===========平均池化========
反向传播梯度 [[[[-0.31011677 -2.43483776]
   [ 1.0388246   2.18697965]]

  [[ 0.44136444 -0.10015523]
   [-0.13644474 -0.11905419]]

  [[ 0.01740941 -1.12201873]
   [-0.51709446 -0.99702683]]

  [[ 0.24879916 -0.29664115]
   [ 0.49521132 -0.17470316]]]


 [[[ 0.98633519  0.2135339 ]
   [ 2.19069973 -1.89636092]]

  [[-0.64691669  0.90148689]
   [ 2.52832571 -0.24863478]]

  [[ 0.04366899 -0.22631424]
   [ 1.33145711 -0.28730786]]

  [[ 0.68006984 -0.3198016 ]
   [-1.27255876  0.31354772]]]


 [[[ 0.50318481  1.29322588]
   [-0.11044703 -0.61736206]]

  [[ 0.5627611   0.24073709]
   [ 0.28066508 -0.0731127 ]]

  [[ 1.16033857  0.36949272]
   [ 1.90465871  1.1110567 ]]

  [[ 0.6590498  -1.62743834]
   [ 0.60231928  0.4202822 ]]]


 [[[ 0.81095167  1.04444209]
   [-0.40087819  0.82400562]]

  [[-0.56230543  1.95487808]
   [-1.33195167 -1.76068856]]

  [[-1.65072127 -0.89055558]
   [-1.1191154   1.9560789 ]]

  [[-0.3264995  -1.34267579]
   [ 1.11438298 -0.58652394]]]


 [[[-1.23685338  0.87583893]
   [ 0.62336218 -0.43495668]]

  [[ 1.40754     0.12910158]
   [ 1.6169496   0.50274088]]

  [[ 1.55880554  0.1094027 ]
   [-1.2197444   2.44936865]]

  [[-0.54577417 -0.19883786]
   [-0.7003985  -0.20339445]]]]

  


总结

       这次真的累,说点感受就是感觉真的这2、3周全在写csdn,写完一周就过完了(哈哈哈),但是我相信这都是值得的。

      这次有好多不明白的,又回去看了达哥,发现每次看达哥都有新的收获,像1x1卷积的作用,以前根本有没这么当回事的研究一下,这次是真的明白了。

      其次是,这次又明白了好多,像卷积神经网络的反向传播,以前真的没考虑这么多,这次终于学了一下,以前达哥讲的时候听的蒙蒙的。

      其次是又算了一下复杂度,有点数据结构的感觉,学了学网络咋算。

     其次是,终于实现一下反向传播,关于反向传播的是实现在写LeNet的时候我会说一下,这个真的研究了好长时间,要是框架一个backward直接解决了,但是自己写就要好后研究,研究了。

      最后,当然是谢谢老师,谢谢老师,在学习和生活上的关心。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值