一、darknet53网络解析与实现
一、darknet53网络结构组成部分
darknet53网络是由 darknet块 下采样卷积块组成的
1、darknet块
1.1 darknet块网络结构
1.2 darknet块网络实现代码
def _darknet53_block(inputs,filters):
'''
:param inputs: tensor 形状[batch, height_in, width_in, channels].channel 要等于 filters*2 保证最后可以相加
:param filters: 卷积核数量 int类型
:return: darknet块输出 tensor 形状[batch, height_in, width_in, channels]
'''
shortuct = inputs
# 正常的 1x1步长为1的卷积 卷积核数为filters 只改变通道数没有改变输入的形状 通道数变为 filters
# 权重默认初始化 weights_initializer=initializers.xavier_initializer()
# 偏置值默认初始化 biases_initializer=init_ops.zeros_initializer()
# 默认激活函数 activation_fn=nn.relu
inputs = slim.conv2d(inputs, filters, 1, stride=1, padding='SAME')
# 正常卷积3x3步长为1的卷积 卷积核数为filters*2,只改变通道数没有改变输入的形状 通道数变为 filters*2
inputs = slim.conv2d(inputs, filters*2, 3, stride=1, padding='SAME')
inputs = inputs + shortuct
return inputs
2、下采样卷积块
2.1、下采样卷积说明
每两个darknet块中间都有一个单独的卷积层,他们都是下采样卷积,
他们是通过将原有的输入补0,再通过步长为2,卷积核为3的VALID卷积来实现
2.1.1 输入补0的实现
def _fixed_padding(inputs,kernel_size,*args,mode = 'CONSTANT',**kwargs):
'''
:param inputs: 输入 类型tensor 形状 [batch, height_in, width_in, channels].
:param kernel_size: 卷积核数量 int类型
:param mode: 填补模式
:return:
'''
# 计算填补的行列个数
pad_total = kernel_size - 1
pad_beg = pad_total // 2
pad_end = pad_total - pad_beg
# 使用tf.pad(tensor,paddings,mode='CONSTANT',name=None,constant_values=0)函数填充 其参数如下
# tensor 被填充的张量
# paddings 填充的格式
# mode 填充模式:"CONSTANT"、"REFLECT"、"SYMMETRIC"
# name 该操作张量的名称
# constant_values 用于在"CONSTANT"模式下,设置的填充值
# pad = np.array([[‘上’,‘下’], [‘左’,‘右’]])
# pad_上边补1行 = np.array([[1, 0], [0, 0]])
# pad_下边补2行 = np.array([[0, 2], [0, 0]])
# pad_左边补3行 = np.array([[0, 0], [3, 0]])
# pad_右边补4行 = np.array([[0, 0], [0, 4]])
# pad1 = np.array([[‘顶’,‘底’],[‘上’,‘下’], [‘左’,‘右’ ]])
# pad_top = np.array([[1, 0], [0, 0], [0, 0]]) 顶补0
# pad_left = np.array([[0, 0], [0, 0], [3, 0]]) 底补0
padded_inputs = tf.pad(inputs, [[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]], mode = mode)
# [0, 0] 第一个维度两边不补 [pad_beg, pad_end]第二个维度一边补pad_beg个0另一边补pad_end个0
# [pad_beg, pad_end]第三个维度一边补pad_beg个0另一边补pad_end个0 [0, 0] 第四个维度两边不补
return padded_inputs
2.2、下采样卷积块实现
使用自定义函数实现下采样卷积
def _conv2d_fixed_padding(inputs,filters,kernel_size,strides):
'''
:param inputs: 输入 类型tensor 形状 [batch, height_in, width_in, channels].
:param filters: 卷积核数量 int类型
:param kernel_size: 卷积核的大小 类型tensor 形状 [h w]
:param strides: 卷积步长 默认是 1
:return: 下采样卷积结果 类型tensor 形状[batch, height_in, width_in, channels]
'''
assert strides > 1 # 表达式为真程序执行 否则报错
inputs = _fixed_padding(inputs,kernel_size) # 外围填充0,支持VALID卷积
inputs = slim.conv2d(inputs,filters,kernel_size,stride=strides,padding='VALID')
return inputs
二、darknet53网络实现
1、darknet53网络结构
2、darknet53网络实现
def darknet53(inputs):
'''
:param inputs: 输入 类型tensor 形状 [batch, height_in, width_in, channels].
:return: 返回3中不同尺度的特征图
'''
# 假设输入inputs 大小为 416*416
# 正常卷积 conv_3x3_32 ,卷积核默认初始化
inputs = slim.conv2d(inputs, 32, 3, stride=1, padding='SAME')
# 下采样卷积 卷积后的形状为(-1,208,208,64)
inputs = _conv2d_fixed_padding(inputs, 64, 3, strides=2)
# darknet块 输出形状(-1,208,208,64)
inputs = _darknet53_block(inputs, 32)
# 下采样卷积 卷积后的形状为(-1,104,104,128)
inputs = _conv2d_fixed_padding(inputs, 128, 3, strides=2)
# 2次darknet块 输出形状(-1,104,104,128)
for i in range(2):
inputs = _darknet53_block(inputs,64)
# 下采样卷积,输出形状(-1, 52, 52, 256)
inputs = _conv2d_fixed_padding(inputs, 256, 3, strides=2)
# 8次darknet块 ,输出形状(-1, 52, 52, 256)
for i in range(8):
inputs = _darknet53_block(inputs, 128)
route_1 = inputs
# ====================================================== 特征图1形状(-1, 52, 52, 256)
# 下采样卷积,输出形状(-1,26,26,512)
inputs = _conv2d_fixed_padding(inputs, 512, 3, strides=2)
# 8次darknet块 ,输出形状(-1, 26, 26, 512)
for i in range(8):
inputs = _darknet53_block(inputs, 256)
route_2 = inputs
# ====================================================== 特征图2形状(-1, 26, 26, 512)
# 下采样卷积,输出形状(-1,13,13,1024)
inputs = _conv2d_fixed_padding(inputs, 1024, 3, strides=2)
for i in range(4):
inputs = _darknet53_block(inputs, 512)
# ====================================================== 特征图3形状(-1,13,13,1024)
return route_1, route_2, inputs
三、测试darknet53网络是否能跑通
我们使用生成的随机数来模拟图片输入网络,看一下输出结果是否是我们想要的
batch_size = 5
height, width = 416, 416
inputs = tf.random_uniform((batch_size, height, width, 3)) # 模拟图片
a,b,c = darknet53(inputs)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
a,b,c = sess.run([a,b,c])
print(sess.run([tf.shape(a),tf.shape(b),tf.shape(c)]))
输出结果: