common.py
一、卷积层函数分析
def convolutional(input_layer, filters_shape, downsample=False, activate=True, bn=True):
if downsample:
input_layer = tf.keras.layers.ZeroPadding2D(((1, 0), (1, 0)))(input_layer)
padding = 'valid'
strides = 2
else:
strides = 1
padding = 'same'
conv = tf.keras.layers.Conv2D(filters=filters_shape[-1], kernel_size = filters_shape[0], strides=strides, padding=padding,
use_bias=not bn, kernel_regularizer=tf.keras.regularizers.l2(0.0005),
kernel_initializer=tf.random_normal_initializer(stddev=0.01),
bias_initializer=tf.constant_initializer(0.))(input_layer)
if bn: conv = BatchNormalization()(conv)
if activate == True: conv = tf.nn.leaky_relu(conv, alpha=0.1)
return conv
1、tf.keras.layers.ZeroPadding2D
该层可以在图像张量的顶部,底部,左侧和右侧添加零行和列。
tf.keras.layers.ZeroPadding2D(
padding=(1, 1), data_format=None, **kwargs
)
1)参数:
padding:
Int,或2个整数的元组,或2个整数的2个元组。
如果为int,则将相同的对称填充应用于高度和宽度。
如果元组为2 ints:解释为高度和宽度的两个不同的对称填充值:(symmetric_height_pad,symmetric_width_pad)。
如果2个元组的2个整数的元组:解释为(((top_pad,bottom_pad),((left_pad,right_pad)))
data_format:
字符串,channels_last(默认)或channels_first中的一个。 输入中尺寸的顺序。 channels_last对应于形状(batch_size,高度,宽度,通道)的输入,而channels_first对应于形状(batch_size,通道,高度,宽度)的输入。 它默认为在〜/ .keras / keras.json中的Keras配置文件中找到的image_data_format值。 如果您从未设置,那么它将是“ channels_last”。
2、tf.keras.layers.Conv2D
该层创建一个卷积内核,该卷积内核与该层输入进行卷积以产生输出张量。 如果use_bias为True,则会创建一个偏差矢量并将其添加到输出中。 最后,如果激活不为“无”,则它也将应用于输出。
当将此层用作模型的第一层时,请提供关键字参数input_shape(整数元组或None,不包括样本轴),例如 对于data_format =“ channels_last”中的128x128 RGB图片,input_shape =(128,128,3)。
tf.keras.layers.Conv2D(
filters, kernel_size, strides=(1, 1), padding='valid',
data_format=None, dilation_rate=(1, 1), groups=1, activation=None,
use_bias=True,
)
1)参数:
filters:整数,输出空间的维数(即卷积中输出过滤器的数量)。
kernel_size:2个整数的整数或元组/列表,指定2D卷积窗口的高度和宽度。 可以是单个整数,以为所有空间尺寸指定相同的值。
strides:一个整数或2个整数的元组/列表,指定沿高度和宽度的卷积步幅。 可以是单个整数,以为所有空间尺寸指定相同的值。 指定任何跨步值!= 1与指定任何dilation_rate值!= 1不兼容。
padding:“valid”或“same”(不区分大小写)之一。 “有效”表示没有填充。 “相同”导致向输入的左/右或上/下均匀填充,以使输出具有与输入相同的高度/宽度尺寸。
data_format:字符串,channels_last(默认)或channels_first中的一个。 输入中尺寸的顺序。 channels_last对应于形状(batch_size,高度,宽度,通道)的输入,而channels_first对应于形状(batch_size,通道,高度,宽度)的输入。
dilation_rate:一个整数或2个整数的元组/列表,指定要用于扩张卷积的扩张率。 可以是单个整数,以为所有空间尺寸指定相同的值。
groups:一个正整数,指定输入沿通道轴划分的组数。 每个组分别与过滤器/组过滤器卷积。 输出是沿着通道轴的所有组结果的串联。 输入通道和过滤器都必须被组整除。
activation:要使用的激活功能。 如果您未指定任何内容,则不会应用任何激活(请参阅keras.activations)。
use_bias:布尔值,层是否使用偏差矢量。
2)输入输出格式
Input shape:
4+D tensor with shape: batch_shape + (channels, rows, cols) if data_format=‘channels_first’ or 4+D tensor with shape: batch_shape + (rows, cols, channels) if data_format=‘channels_last’.
Output shape:
4+D tensor with shape: batch_shape + (filters, new_rows, new_cols) if data_format=‘channels_first’ or 4+D tensor with shape: batch_shape + (new_rows, new_cols, filters) if data_format=‘channels_last’. rows and cols values might have changed due to padding.
3)返回值:
代表激活的4+级张量(conv2d(inputs,kernel)+ bias)。
4)示例:
# The inputs are 28x28 RGB images with `channels_last` and the batch
# size is 4.
input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv2D(
2, 3, activation='relu', input_shape=input_shape[1:])(x)
print(y.shape)
(4, 26, 26, 2)
# With `dilation_rate` as 2.
input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv2D(
2, 3, activation='relu', dilation_rate=2, input_shape=input_shape[1:])(x)
print(y.shape)
(4, 24, 24, 2)
input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv2D(
2, 3, activation='relu', padding="same", input_shape=input_shape[1:])(x)
print(y.shape)
(4, 28, 28, 2)
3、tf.random.normal
从正态分布输出随机值。
tf.random.normal(
shape, mean=0.0, stddev=1.0, dtype=tf.dtypes.float32, seed=None, name=None
)
1)参数
shape:
一维整数Tensor或Python数组。 输出张量的形状
mean:
类型为dtype的Tensor或Python值,可通过stddev广播。 正态分布的平均值。
stddev:
dtype类型的Tensor或Python值,可通过mean广播。 正态分布的标准偏差。
dtype:
输出数值类型
seed:
一个Python整数。 用于为分发创建随机种子。 有关行为,请参见tf.random.set_seed。
2)示例:
tf.random.set_seed(5);
tf.random.normal([2,2], 0, 1, tf.float32, seed=1)
4、tf.keras.layers.BatchNormalization
tf.keras.layers.BatchNormalization(
axis=-1, momentum=0.99, epsilon=0.001, center=True, scale=True,
beta_initializer='zeros', gamma_initializer='ones',
)
批次归一化应用了一种变换,该变换可将平均输出保持在0左右并将输出标准偏差保持在1附近。
重要的是,批次归一化在训练和推断期间的工作方式有所不同。
在训练期间(即,使用fit()或使用参数training = True调用层/模型时),此层将使用当前输入批次的均值和标准差对输出进行归一化。 也就是说,对于每个标准化的通道,该层返回(batch-mean(batch))/(var(batch)+ epsilon)* gamma + beta,其中:
epsilon是一个小的常数(可作为构造函数参数的一部分进行配置)
gamma是学习的比例因子(初始化为1),可以通过将scale = False传递给构造函数来禁用它。
beta是学习的偏移因子(初始化为0),可以通过将center = False传递给构造函数来禁用它。
在推论期间(即,当使用Evaluate()或predict()或使用参数training = False(这是默认值)调用图层/模型时,图层会使用平均值和标准偏差的移动平均值对输出进行归一化 训练期间看到的批次,即返回(batch-self.moving_mean)/(self.moving_var + epsilon)* gamma + beta。
self.moving_mean和self.moving_var是不可训练的变量,每次在训练模式下调用图层时都会更新,例如:
moving_mean = moving_mean * momentum + mean(batch) * (1 - momentum)
moving_var = moving_var * momentum + var(batch) * (1 - momentum)

这样,该层将仅在已经对具有与推断数据相似的统计数据的数据进行训练之后的推断期间对其输入进行归一化。
5、tf.nn.leaky_relu
计算leaky_relu激活函数
tf.nn.leaky_relu(
features, alpha=0.2, name=None
)
6、tf.concat
tf.concat(
values, axis, name=‘concat’
)
t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
tf.concat([t1, t2], 0)
tf.concat([t1, t2], 1)
二、残差块分析
def residual_block(input_layer, input_channel, filter_num1, filter_num2):
short_cut = input_layer
conv = convolutional(input_layer, filters_shape=(1, 1, input_channel, filter_num1))
conv = convolutional(conv , filters_shape=(3, 3, filter_num1, filter_num2))
residual_output = short_cut + conv
return residual_output
三、BatchNormalization类
class BatchNormalization(tf.keras.layers.BatchNormalization):
"""
"Frozen state" and "inference mode" are two separate concepts.
`layer.trainable = False` is to freeze the layer, so the layer will use
stored moving `var` and `mean` in the "inference mode", and both `gama`
and `beta` will not be updated !
"""
def call(self, x, training=False):
if not training:
training = tf.constant(False)
training = tf.logical_and(training, self.trainable)
return super().call(x, training)
四、上采样
def upsample(input_layer):
return tf.image.resize(input_layer, (input_layer.shape[1] * 2, input_layer.shape[2] * 2), method='nearest')
backbone.py
def darknet53(input_data):
input_data = common.convolutional(input_data, (3, 3, 3, 32))
input_data = common.convolutional(input_data, (3, 3, 32, 64), downsample=True)
for i in range(1):
input_data = common.residual_block(input_data, 64, 32, 64)
input_data = common.convolutional(input_data, (3, 3, 64, 128), downsample=True)
for i in range(2):
input_data = common.residual_block(input_data, 128, 64, 128)
input_data = common.convolutional(input_data, (3, 3, 128, 256), downsample=True)
for i in range(8):
input_data = common.residual_block(input_data, 256, 128, 256)
route_1 = input_data
input_data = common.convolutional(input_data, (3, 3, 256, 512), downsample=True)
for i in range(8):
input_data = common.residual_block(input_data, 512, 256, 512)
route_2 = input_data
input_data = common.convolutional(input_data, (3, 3, 512, 1024), downsample=True)
for i in range(4):
input_data = common.residual_block(input_data, 1024, 512, 1024)
return route_1, route_2, input_data