实验目录
1 、跨通道的特征整合(这个以前达哥没说过,我感觉有点类似于升维降维,)
四、习题5-7 忽略激活函数,分析卷积网络中卷积层的前向计算和反向传播(公式(5.39))是一种转置关系.
前言
首先,先说一下,这次用了达哥好多东西,就不一一感谢了,在这里对达哥长跪不起。
其次,这次弄了好长时间,真的累,感觉最近一直在写(哈哈哈),但是我相信这都是值得的。
最后,好多同学去考教资了,今天催了一天核算,感觉大家都在努力,大家加油吧,咱们都加油。(哈哈哈)
老师发的图,必须给予足够的尊重。(哈哈哈)
一、习题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 、减少计算量
这个直接上达哥照片了,达哥无敌(遇事不决,但问达哥)
至于这两张照片的解释,还就是下边的照片的了,这来自于达哥推荐的讲课笔记
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直接解决了,但是自己写就要好后研究,研究了。
最后,当然是谢谢老师,谢谢老师,在学习和生活上的关心。