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

 

目录

 

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

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

习题5-4

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

CNN的反向传播

 1、已知池化层的误差,反向推导上一隐藏层的误差

2、已知卷积层的误差,反向推导上一隐藏层的误差

3、已知卷积层的误差,推导该层的W,b的梯度

心得体会


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

 (5.13)

 根据卷积,有: y_{ij}=\sum^U_{u=1}\sum^V_{v=1}w_{uv}\cdot x_{i+u-1}

变换坐标:k=i-u+1,d=j-v+1,于是有:u=k-i+1,v=d-j+1

因此原式变为:

y_{ij}=\sum_{k=i-u+1}^{U+i-1}\sum_{d=j-v+1}^{V+j-1}x_{kd} \cdot w_{k-i+1,d-j+1}

根据宽卷积的性质,宽卷积仅是进行了X的零填充,可以发现该等式仍然成立,故宽卷积也符合可交换性。

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

1、降维( dimension reductionality )

比如,一张500 * 500且厚度depth为100 的图片在20个filter上做1*1的卷积,那么结果的大小为500*500*20。

2、升维(用最少的参数拓宽网络channal)

例子64的卷积核的channel是64,只需添加一个1*1,256的卷积核,只用64*256个参数就能把网络channel从64拓宽四倍到256。

3、加入非线性

卷积层之后经过激励层,1*1的卷积在前一层的学习表示上添加了非线性激励( non-linear activation ),提升网络的表达能力。

习题5-4

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

对于第一种情况:

Time\sim O(M^2\cdot K^2\cdot C_{in}\cdot C_{out})=5.89824\times 10^9

Space\sim O(K^2\cdot C_{in}\cdot C_{out}+M^2\cdot C_{out})=3.149824\times 10^6

其中,M=100,K=3,C_{in}=256,C_{out}=256

对于第二种情况:

Time\sim O(M^2\cdot K_1^2\cdot C_{1,in}\cdot C_{1,out}+M^2\cdot K_2^2\cdot C_{2,in}\cdot C_{2,out})=1.6384\times 10^9

Space\sim O(K_1^2\cdot C_{1,in}\cdot C_{1,out}+K_2^2\cdot C_{2,in}\cdot C_{2,out}+M^2\cdot C_{1,out}+M^2\cdot C_{2,out})=3.36384\times 10^6

可以看出,使用1*1卷积核可以大大减少时间复杂度,代价是略微增加空间复杂度。

参考:卷积神经网络的复杂度分析 - 知乎

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


 (5.39)

在第l层时:净输入为z^{(l+1)}=W^{(l+1)}z^{(l)}, 反向传播的误差项为\delta^{(l)}=(W^{(l+1)})^\top \delta^{(l+1)}

当在第l + 1 l+1l+1层时:净输入为z^{(l)}=(W^{(l+1)})^\top z^{(l+1)},而反向传播的误差项为\delta^{(l+1)}=W^{(l+1)}\delta^{(l)}

因此,忽略激活函数下前向计算和反向传播是一种转置关系。

CNN的反向传播

首先要注意的是,一般神经网络中每一层输入输出a,z都只是一个向量,而CNN中的a,z是一个三维张量,即由若干个输入的子矩阵组成。其次:

1、池化层没有激活函数。这个问题倒比较好解决,我们可以令池化层的激活函数为σ(z)=z,即激活后就是自己本身。这样池化层激活函数的导数为1。
2、池化层在前向传播的时候,对输入进行了压缩,那么我们向前反向推导上一层的误差时,需要做upsample处理。
3、卷积层是通过张量卷积,或者说若干个矩阵卷积求和而得到当前层的输出,这和一般的网络直接进行矩阵乘法得到当前层的输出不同。这样在卷积层反向传播的时候,上一层误差的递推计算方法肯定有所不同。
4、对于卷积层,由于W使用的运算是卷积,那么由该层误差推导出该层的所有卷积核的W,b的方式也不同。

由于卷积层可以有多个卷积核,各个卷积核的处理方法是完全相同且独立的,为了简化算法公式的复杂度,我们下面提到卷积核都是卷积层中若干卷积核中的一个。

 1、已知池化层的误差,反向推导上一隐藏层的误差

在前向传播时,池化层我们会用MAX或者Average对输入进行池化,池化的区域大小已知。现在我们反过来,要从缩小后区域的误差,还原前一层较大区域的误差。这个过程叫做upsample。假设我们的池化区域大小是2x2。第l层误差的第k个子矩阵\delta _{lk}为:

\delta _{lk}=\begin{pmatrix} 2 &8 \\ 4 & 6 \end{pmatrix}

如果池化区域表示为a*a大小,那么我们把上述矩阵上下左右各扩展a-1行和列进行还原

\begin{pmatrix} 0 & 0 & 0 & 0\\ 0& 2& 8&0 \\ 0& 4& 6& 0\\ 0& 0& 0& 0 \end{pmatrix}

如果是MAX,假设我们之前在前向传播时记录的最大值位置分别是左上,右下,右上,左下,则转换后的矩阵为:

\begin{pmatrix} 2& 0& 0& 0\\ 0& 0& 0& 8\\ 0& 4& 0& 0\\ 0& 0& 6 & 0 \end{pmatrix}

如果是Average,则进行平均,转换后的矩阵为:

\begin{pmatrix} 0.5 & 0.5 & 2& 2\\ 0.5& 0.5& 2 & 2\\ 1& 1& 1.5&1.5 \\ 1& 1 & 1.5 & 1.5 \end{pmatrix}

 上边这个矩阵就是误差矩阵经过upsample之后的矩阵,那么,由后一层误差推导出前一层误差的公式为:

\delta ^{l-1}=upsample(\delta^l) \odot \sigma '(z^{l-1})

上式和普通网络的反向推导误差很类似:

\delta^l=((w^{l+1})^T\delta^{l+1})\odot \sigma '(z^l)

可以看到,只有第一项不同。

2、已知卷积层的误差,反向推导上一隐藏层的误差

公式如下:

\delta^{l-1}=\delta^l\frac{\partial z^l}{\partial z^{l-1}}=\delta^l\ast rot180(W^l)\odot \sigma '(z^{l-1})

我们再看一次普通网络的反向推导误差的公式:

\delta^l=((w^{l+1})^T\delta^{l+1})\odot \sigma '(z^l)

可以看到区别在于,下一层的权重w的转置操作,变成了旋转180度的操作,也就是上下翻转一次,左右再翻转一次,这其实就是“卷积”一词的意义(我们可简单理解为数学上的trick),可参考下图,Q是下一层的误差,周围补0方便计算,W是180度翻转后的卷积核,P是W和Q做卷积的结果:

3、已知卷积层的误差,推导该层的W,b的梯度

经过以上各步骤,我们已经算出每一层的误差了,那么:
a)对于全连接层,可以按照普通网络的反向传播算法求该层W,b的梯度。
b)对于池化层,它并没有W,b,也不用求W,b的梯度。
c)只有卷积层的W,b需要求出,先看w:

\frac{\partial J(W,b)}{\partial W^l}=\frac{\partial J(W,b)}{\partial z^l}\frac{\partial z^l}{\partial W^l}=\delta^l\ast rot180(a^{l-1})

再对比一下普通网络的求w梯度的公式,发现区别在于,对前一层的输出做翻转180度的操作:

\frac{\partial C}{\partial w_{jk}^l}=a_k^{l-1}\delta_j^l

而对于b,则稍微有些特殊,因为在CNN中,误差δ是三维张量,而b只是一个向量,不能像普通网络中那样直接和误差δ相等。通常的做法是将误差δ的各个子矩阵的项分别求和,得到一个误差向量,即为b的梯度:

\frac{\partial J(W,b)}{\partial b^l}=\sum_{u,v}^{U,V}(\delta^l)_{u,v}

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

心得体会

本次作业对课上卷积神经网络的通道和前向传播以及反向传播有了更深的理解:

1.初始化网络中所有权值W 和偏置参数b ;
2.利用前向传播算法计算最后一层输出a^l
3.使用softmax(将输出映射到(0,1))对输出处理,并计算损失函数J;
4.根据反向传播算法,计算损失函数J对各项权重或者偏置的偏导
5.利用梯度下降流,更新权重和偏置, ,返回至步骤2直至损失函数小于我们的预设值


虽然反向传播的过程可以直接用backward()求得,但技多不压身,还是要知道原理的。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是处理 MNIST 数据集分类问卷积神经网络的代码: ```python import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data # 加载 MNIST 数据集 mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) # 定义输入和输出的占位符 x = tf.placeholder(tf.float32, [None, 784]) y_true = tf.placeholder(tf.float32, [None, 10]) # 将输入数据转换为图片的形式 x_image = tf.reshape(x, [-1, 28, 28, 1]) # 第一层卷积 conv1 = tf.layers.conv2d(inputs=x_image, filters=32, kernel_size=[5, 5], padding="same", activation=tf.nn.relu) # 第一层池化 pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2) # 第二层卷积 conv2 = tf.layers.conv2d(inputs=pool1, filters=64, kernel_size=[5, 5], padding="same", activation=tf.nn.relu) # 第二层池化 pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2) # 将图像数据展开为一维向量 pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64]) # 第一层全连接层 fc1 = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu) # Dropout keep_prob = tf.placeholder(tf.float32) fc1_drop = tf.nn.dropout(fc1, keep_prob) # 第二层全连接层 y_pred = tf.layers.dense(inputs=fc1_drop, units=10) # 定义损失函数和优化器 cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_true, logits=y_pred)) train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) # 定义准确率 correct_prediction = tf.equal(tf.argmax(y_pred, 1), tf.argmax(y_true, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) # 开始训练 with tf.Session() as sess: sess.run(tf.global_variables_initializer()) for i in range(20000): batch_x, batch_y = mnist.train.next_batch(50) sess.run(train_step, feed_dict={x: batch_x, y_true: batch_y, keep_prob: 0.5}) if i % 100 == 0: train_acc = sess.run(accuracy, feed_dict={x: batch_x, y_true: batch_y, keep_prob: 1.0}) print("Step %d, training accuracy %g" % (i, train_acc)) # 在测试集上计算准确率 test_acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y_true: mnist.test.labels, keep_prob: 1.0}) print("Test accuracy %g" % test_acc) ``` 这个代码使用了两个卷积层和两个全连接层,以及池化和 Dropout。 在训练过程中,我们每 100 次迭代输出一次训练集上的准确率,并在最后输出测试集上的准确率。 你可以将该代码保存到一个 Python 文件中,然后在命令行中运行该文件来执行训练和测试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值