keras conv2d 解析

参数解析:

conv2d是创建一个卷积层,对输入数据进行卷积操作,先看一下原函数:

keras.layers.Conv2D(
	filters, 
	kernel_size, 
	strides=(1, 1), 
	padding='valid', 
	data_format=None, 
	dilation_rate=(1, 1), 
	activation=None, 
	use_bias=True, 
	kernel_initializer='glorot_uniform', 
	bias_initializer='zeros', 
	kernel_regularizer=None, 
	bias_regularizer=None, 
	activity_regularizer=None, 
	kernel_constraint=None, 
	bias_constraint=None
)

常用参数:

filters: 卷积核的数量,决定输出数据的最后一维(channels)的大小。
kernel_size:卷积核的大小(形状),决定输出数据 height, width 维度的大小。
strides: 卷积操作时步长,可以是一个整数代表height, width方向的步长相同,也可以是(x, y)表示height方向的步长为x,width方向的步长为y。
padding:等于’valid’时卷积核在 输入数据形状(height, width)最大范围内 进行移动,等于’same’时如果(height, width)没有恰好完全符合设定的kernel_size和strides,超出的部分将会填充0.
activation: 激活函数
use_bias: 是否使用偏置量
kernel_initializer: 卷积核的初始化方式
bias_initializer: 偏置量的初始化方式

(输入是一个四维的数据(batch, height, width, channels),其他参数用到时再回来补充)

卷积过程:

创建一个模型,只有一层conv2d层,输入为数据为(4, 4, 1)形状的单通道数据:

def conv2d_test():
	#为了更直观看出结果,这里kernel_initializer 设为oens使核参数都为1.
	model = Sequential()
	model.add(layers.Conv2D(filters = 3, kernel_size=(2,2) , input_shape = (4, 4, 1), strides = 1, kernel_initializer = 'ones'))
	return model

测试:(需要引入numpy模块)

def test():
	conv2d_model = conv2d_test()
	data_test = np.random.randint(1, 3, (1, 4, 4, 1)) 
	predict_result = conv2d_model.predict(data_test)
	print(data_test)
	print(predict_result)
	print(np.shape(predict_result))
if __name__ == '__main__':
	test()

先看data_test的输出:
np.random.randint: 生成值为 1 到 3 -1 形状为(1, 4, 4, 1)的矩阵:(下面是处理过的输出格式 方便观察)
[[
[[2],[2],[2],[1]],
[[2],[1],[2],[2]],
[[1],[2],[1],[2]],
[[1],[2],[1],[1]]
]]

再看predict_result 的输出:
[[
[[7. 7. 7.]
[7. 7. 7.]
[7. 7. 7.]]

[[6. 6. 6.]
[6. 6. 6.]
[7. 7. 7.]]

[[6. 6. 6.]
[6. 6. 6.]
[5. 5. 5.]]
]]

predict_result的形状:
(1, 3, 3, 3)

用图解析上面的结果:
卷积核的形状为:
(2,2)
因为kernel_initializer 设为oens,所以核参数为:
[[1,1],
[1,1] ]
如下图:

卷积过程
如图所示,
第一步运行会在红色框内进行,覆盖的范围与卷积核大小相同并且每个位置的值相互对应,可以理解为将核覆盖在输入数据左上角,运行的过程为:2 x 1 + 2 x 1 + 2 x 1 + 1 x 1 = 7

第二步运行会在黄色框内进行,因为strides = 1,width轴方向上的步长也为1.实际上是将核往右移动一步。运行的过程为:2 x 1 + 2 x 1 + 1 x 1 + 2 x 1 = 7

同理 第三部又会进行右移一步到绿色框内,运行的过程为:2 x 1 + 1 x 1 + 2 x 1 + 2 x 1 = 7
此时width方向已经走完,核将会在height + 1 方向上从头进行,也就是到蓝色框中,因为height方向上的步长也是1。以此类推,走完一轮后得到的结果将会是:
[
[[7],[7],[7]]
[[6],[6],[7]]
[[6],[6],[5]]
]

没错,得到的结果就是predict_result 的输出的第一列(直观上)。那为什么predict_result的输出有三列? 因为核的数量有3个(filters = 3),每一个核都进行了上述同样的操作,每个核运算得到的结果将会填充一层channel。所以predict_result的形状中channels = 3。height = 3和width = 3又是怎么来的呢? 可以理解为运算过程中在width 方向中走的步数和height方向走的步数,很明显结果由kernel_size和strides的大小决定。每个方向只能走3步,所以height,width都是3。另外,batch是数据块的大小,传入是多少输出就是多少,卷积过程不会改变batch的大小。

如果输入数据的channels不是1而是2或者3会怎么样呢?比如一般图片输入都是3通道的数据。

改一下代码,将input_shape改为3通道的数据格式:

def conv2d_test():
	#为了更直观看出结果,这里kernel_initializer 设为oens使核参数都为1.
	model = Sequential()
	model.add(layers.Conv2D(filters = 3, kernel_size=(2,2) , input_shape = (4, 4, 3), strides = 1, kernel_initializer = 'ones'))
	return model

生成数据也改为3通道:

def test():
	conv2d_model = conv2d_test()
	data_test = np.random.randint(1, 3, (1, 4, 4, 3)) 
	predict_result = conv2d_model.predict(data_test)
	print(data_test)
	print(predict_result)
	print(np.shape(predict_result))

先看data_test的输出:
np.random.randint: 生成值为 1 到 3 -1 形状为(1, 4, 4, 3)的矩阵:

[[[[2 1 2]
[2 2 1]
[2 2 2]
[1 1 1]]

[[1 2 2]
[2 2 1]
[1 1 1]
[2 2 2]]

[[1 1 2]
[1 1 1]
[1 2 2]
[2 2 2]]

[[2 1 2]
[2 2 1]
[2 2 2]
[1 1 1]]]]

再看predict_result 的输出:

[[[[20. 20. 20.]
[19. 19. 19.]
[18. 18. 18.]]

[[17. 17. 17.]
[16. 16. 16.]
[20. 20. 20.]]

[[17. 17. 17.]
[19. 19. 19.]
[20. 20. 20.]]]]

predict_result的形状:
(1, 3, 3, 3)

可以看出修改后predict_result的形状channel依然是3,因为这只由核的数量决定。

对于多通道的数据,卷积过程为:
核在每个通道上进行卷积运算,每一个通道运算的结果进行相加,最后得到一个一通道的(x, y, 1)的数据结构。所以,如果有3个核,将会得到(x, y, 3)的数据结构。
如上面predict_result 的输出中左上角的20的计算过程为:
第一个核在第一channel: 2 * 1 + 2 * 1 + 1 * 1 + 2 * 1 = 7
第一个核在第二channel: 1 * 1 + 2 * 1 + 2 * 1 + 2 * 1 = 7
第一个核在第三channel: 2 * 1 + 1 * 1 + 2 * 1 + 1 * 1 = 6
所以第一次卷积的结果为: 7 + 7 + 6 = 20,其他的步骤以此类推。

最后,附带一个计算卷积操作输出形状的公式:

OH = (H + 2P - FH) / S + 1
OW = (W + 2P - FW) / S + 1

OH: 输出高(height)
OW: 输出宽(width)
H: 输入高
W: 输入宽
FH: 核高
FW: 核宽
P: 填充
S: 步长

套用第二个例子:
H: 输入高 = 4
W: 输入宽 = 4
FH: 核高 = 2
FW: 核宽 = 2
P: 填充 = 0 (因为padding='valid’不会进行填充)
S: 步长 = 1

OH = (4 + 0 - 2)/ 1 + 1 = 3
OW = (4 + 0 - 2)/ 1 + 1 = 3

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专治跌倒扭伤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值