网站建设黄页免费在线观看,网络营销服务工具,邯郸市设计公司电话,天宁常州做网站本系列已完结#xff0c;全部文章地址为#xff1a; 深度学习中的卷积和反卷积#xff08;一#xff09;——卷积的介绍 深度学习中的卷积和反卷积#xff08;二#xff09;——反卷积的介绍 深度学习中的卷积和反卷积#xff08;三#xff09;——卷积和反卷积的计算 … 本系列已完结全部文章地址为 深度学习中的卷积和反卷积一——卷积的介绍 深度学习中的卷积和反卷积二——反卷积的介绍 深度学习中的卷积和反卷积三——卷积和反卷积的计算 深度学习中的卷积和反卷积四——卷积和反卷积的梯度 1 卷积的梯度计算
1.1 Tensorflow中矩阵梯度运算的说明
请注意计算y对x的梯度时如果y、x都是矩阵梯度理应是每一个y对每一个x求偏导的结果。但在Tensorflow中gradient是返回了总和的梯度。如果想求出每个分量的梯度应该使用Jacobian矩阵。这一点困扰了笔者很久直到翻到文档才恍然大悟。文档地址梯度和自动微分简介 | TensorFlow Core import tensorflow as tfx tf.Variable(2.0)
# 求gradient,结果为7
with tf.GradientTape() as tape:y x * [3., 4.]
print(tape.gradient(y, x).numpy())
# 求gradient,结果为[3. 4.]
with tf.GradientTape() as tape:y x * [3., 4.]
print(tape.jacobian(y, x).numpy())1.2 卷积对input的梯度
沿用上一篇的例子如下图 数值例子为 输入是3*3的维度因此梯度维度也是3*3表示对每一个a中的元素求梯度的结果
观察卷积输出的结果例如参与了的计算系数是因此梯度为。同理所有的y对所有的输入都可以计算梯度。以为例
在Tensorflow中验证如下 tf.function
def compute_gradient(x, filters):with tf.GradientTape() as tape:tape.watch(x) # 监视xy tf.nn.conv2d(x, filters, [1, 1, 1, 1], VALID)return tape.jacobian(y, x) # 计算y相对于x的梯度print(compute_gradient(x, filters).numpy().reshape([4, 3, 3])) 输出如下的输出结果与上文中表格一致其余y分量不再赘述。 [[[1. 2. 0.][3. 4. 0.][0. 0. 0.]][[0. 1. 2.][0. 3. 4.][0. 0. 0.]][[0. 0. 0.][1. 2. 0.][3. 4. 0.]][[0. 0. 0.][0. 1. 2.][0. 3. 4.]]] 1.3 卷积对kernel的梯度 对卷积核计算的梯度就是每一个y对每一个k求梯度例如每一个y对于的梯度就是下图红框中的部分分别是1、2、4、5。
还是以为例在Tensorflow中验证如下 tf.function
def compute_kernel_gradient(x, filters):with tf.GradientTape() as tape:tape.watch(filters) # 监视xy tf.nn.conv2d(x, filters, [1, 1, 1, 1], VALID)return tape.jacobian(y, filters)print(compute_kernel_gradient(x, filters).numpy().reshape([4, 2, 2]))输出如下符合预期。 [[[1. 2.][4. 5.]][[2. 3.][5. 6.]][[4. 5.][7. 8.]][[5. 6.][8. 9.]]] 2 反卷积的梯度计算
由于反卷积的计算相当于对矩阵先做填充再做卷积因此反卷积的梯度等价于对填充后的输入矩阵做卷积的梯度。
2.1 反卷积对input的梯度
以前文的数据为例首先对输入矩阵填充0然后翻转卷积核得到4*4的输出。 我们计算每一个输出对每一个输入的梯度输出是4*4输入是3*3因此算梯度的Jacobian矩阵维度是4*4*3*3。
我们以对的梯度为例先看是怎么算出来的 因此对的梯度为
Tensorflow中验证如下
import numpy as np
import tensorflow as tfdef conv2d_transpose(x, filters):return tf.nn.conv2d_transpose(x, filters, [1, 4, 4, 1], strides1, paddingVALID)tf.function
def compute_conv2d_transpose_i_gradient(x, filters):with tf.GradientTape() as tape:tape.watch(x)y conv2d_transpose(x, filters)return tape.jacobian(y, x)x tf.constant(np.arange(1, 10).reshape([1, 3, 3, 1]), dtypetf.float32)
filters tf.constant(np.arange(1, 5).reshape(2, 2, 1, 1), dtypetf.float32)
print(compute_conv2d_transpose_i_gradient(x, filters).numpy().reshape([4, 4, 3, 3])[2][1][1][1]) # 注意下标是从0开始的[2][1]代表y32,[1][1]代表a22输出为3与手算结果一致。
3.0
2.2 反卷积对kernel的梯度
与反卷积对input梯度类似也等价于对填充后的输入矩阵做卷积时计算梯度。同样用数值例子验证。
计算 对的梯度结合上节的表达式得到梯度为
Tensorflow中验证如下
import numpy as np
import tensorflow as tfdef conv2d_transpose(x, filters):return tf.nn.conv2d_transpose(x, filters, [1, 4, 4, 1], strides1, paddingVALID)tf.function
def compute_conv2d_transpose_k_gradient(x, filters):with tf.GradientTape() as tape:tape.watch(filters)y conv2d_transpose(x, filters)return tape.jacobian(y, filters)x tf.constant(np.arange(1, 10).reshape([1, 3, 3, 1]), dtypetf.float32)
filters tf.constant(np.arange(1, 5).reshape(2, 2, 1, 1), dtypetf.float32)
print(compute_conv2d_transpose_k_gradient(x, filters).numpy().reshape([4, 4, 2, 2])[2][1][1][0])
输出为5与手算结果一致。
5.0
3 反卷积等价于误差反向传播
https://zhuanlan.zhihu.com/p/338780702
下图是Tensorflow中反卷积函数的源码可以看出反卷积等价于将input作为卷积下层误差反向传播本节进行推导。 tf_export(nn.conv2d_transpose, v1[])
dispatch.add_dispatch_support
def conv2d_transpose_v2(input, # pylint: disableredefined-builtinfilters, # pylint: disableredefined-builtinoutput_shape,strides,paddingSAME,data_formatNHWC,dilationsNone,nameNone):......return gen_nn_ops.conv2d_backprop_input(input_sizesoutput_shape,filterfilters,out_backpropinput,stridesstrides,paddingpadding,explicit_paddingsexplicit_paddings,data_formatdata_format,dilationsdilations,namename) 3.1 全连接网络的误差反向传播
卷积可视作特殊的全连接网络。全连接网络中每一个输出与每一个输入都使用权重边相连输出是各输入的加权求和。对于卷积而言输出只与某些输入有关但可以理解为所有输出与所有输入相连只是其中有些权重边固定为0而已。因此本节先回顾全连接网络的误差反向传播过程随后推广到卷积的误差反向传播。
如下图所示我们构造了一个全连接神经网络忽略偏置。 符号表示如下
符号含义L层第i个输入。A指activation表示L-1层激活后传递给L层的输入L层第i个输入连接到第j个输出的权重L层第i个输出L层偏置损失函数最终的误差对于L层第i个输出的梯度表示反向传播过来的误差
对于L层来说误差反向传播需要做两件事情1计算误差对本层权重的梯度从而更新权重2将误差反向传播到上一层从而更新上层的权重。
3.1.1 误差对本层权重的梯度
根据链式法则有 根据的定义前一项即为。后一项比较简单因为Z是由W加权求和而来因此该项等于。在卷积中卷积核其实就是特殊的权重因此该项即对应前文讨论的卷积对kernel的梯度。 表示误差传播到这个节点的误差表示节点对于最后误差负的责任注意这里的是激活之前的输出。可以继续分解为最终误差对激活后的结果A的梯度乘A对于Z的梯度如果是最后一层则代表损失函数的梯度。后者代表激活函数的梯度。 求出梯度后根据神经网络的学习规则权重根据学习率、梯度动态更新。
3.1.2 误差反向传播到上一层
本层需要求出从而使得下一层根据此结果更新权重。以L-1层第j个输出为例 注意乘号后一项就是激活函数的导数下面分析乘号前一项。注意L层的Aj会参与到多个输出Z因此需要将所有输出Zi都考虑在内。 此式后一项即为卷积中对input的梯度。可进一步化简结果为因此损失函数对L层输入的梯度可表示为与权重相乘后求和。
3.2 卷积的误差反向传播
误差反向传播对应前文中“误差反向传播到上一层”这一小节。在卷积中卷积核其实就是特殊的稀疏权重其中有很多权重为0。
还是以前文卷积计算为例我们列出损失函数对所有输入的梯度。代入上式得到 注意这里符号表示有所调整因为全连接网络是把输入和输出展开的卷积这里输入和输出是二维的因此下标用二维坐标表示。同时此处只讨论第L层网络情况不再保留上标。 可以看到由于a22参与了所有的输出所以表达式有4项其他输入只参与了1或2项输出相当于对剩余输出的权重为0因此表达式只有1、2项。
这种计算结果等价于对下式求卷积 可以发现这正好是反卷积的计算过程。
3.3 Tensorflow的验证
在Tensorflow中验证如下 def conv2d_transpose(x, filters):return tf.nn.conv2d_transpose(x, filters, [1, 4, 4, 1], strides1, paddingVALID)x tf.constant(np.arange(1, 10).reshape([1, 3, 3, 1]), dtypetf.float32)
filters tf.constant(np.arange(1, 5).reshape(2, 2, 1, 1), dtypetf.float32)
print(反卷积结果:)
print(conv2d_transpose(x, filters).numpy().reshape([4, 4]))
# 卷积反向传播
x tf.constant(np.array([[0, 0, 0, 0, 0],[0, 1, 2, 3, 0],[0, 4, 5, 6, 0],[0, 7, 8, 9, 0],[0, 0, 0, 0, 0]]).reshape([1, 5, 5, 1]), dtypetf.float32)
filters tf.constant(np.array([[4, 3],[2, 1]]).reshape(2, 2, 1, 1), dtypetf.float32)
print(卷积反向传播结果:)
print(tf.nn.conv2d(x, filters, [1, 1, 1, 1], VALID).numpy().reshape(4, 4)) 输出如下图所示二者一致。 反卷积结果:
[[ 1. 4. 7. 6.][ 7. 23. 33. 24.][19. 53. 63. 42.][21. 52. 59. 36.]]
卷积反向传播结果:
[[ 1. 4. 7. 6.][ 7. 23. 33. 24.][19. 53. 63. 42.][21. 52. 59. 36.]] 参考资料
《卷积神经网络CNN反向传播算法详细解析》
《反向传播算法中的权重更新是如何进行的》