欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

经典卷积网络之DenseNet的论文解读及代码实现

程序员文章站 2024-03-15 09:17:23
...

文章背景

最近的工作显示如果在靠近输入输出的层数之间加入短连接(short connections)能大幅度的提升训练的深度、准确度与效率。基于这种思想,这篇论文提出了一种全新的网络结构Dense Convolutional Network(DenseNet):将每一层与出层之外的所有层连接起来。也就是说对于有L层的传统卷积网络而言,有L个连接,但是对于DenseNet而言有L(L+1)/2个连接。

思想

全文有两个公式第一个公式是关于ResNet的,其中 l\ {l}表示层数, xl\ {x_l}表示第 l\ {l}的输出,  H\ {H}表示非线性变换。
 xl=Hl(xl1)+xl1\ {x_l= H_l(x_{l-1}) + x_{l-1}}
第二个公式是关于DenseNet的
 xl=Hl([x0,x1,x2,...,xl1])\ x_l =H_l([x_0,x_1,x_2,...,x_{l-1}])
从这两个公式可以很清楚的看出两种网络思路上的区别,resnet是通过将这层的输出与前一层的输出相加;densenet是将前面所有的输出全部concatenat。

网络结构

经典卷积网络之DenseNet的论文解读及代码实现
这是densenet中的一个dense block
经典卷积网络之DenseNet的论文解读及代码实现
这是densenet网络的结构由多个denseblock组成

代码实现

class bottleneck_layer(layers.layer):
 def __init__(self, x, filters, filters= “自定义”, stride=1):
  super(bottleneck_layer, self).__init__()
  
  #有denseblock的结构图可以看出bn+relu+conv为一个单元
  self.bn = layers.BatchNormalization()
  self.relu = layers.Activation('relu')
  self.conv1 = layers.Con2D(x, use_bias=False, filters = 4*filters, kernel_size=[1,1], strides=stride, padding='same')
  self.dp = layers.Dropout(0.2)
  
  self.conv2 = layers.Con2D(x, use_bias=False, filters = filters, kernel_size=[3,3], strides=stride, padding='same')
 
 def call(self, input, training = None):
  out = self.bn(input)
  out = self.relu(out)
  out = self.conv1(out)
  out = self.dp(out)
  
  out = self.bn(input)
  out = self.relu(out)
  out = self.conv2(out)
  out = self.dp(out)
  
  return out
class transition_layer(layers.layer):
 def __init__(self, x, filters, stride=1):
  super(transition_layer, self).__init__()
  
  self.bn = layers.BatchNormalization()
  self.relu = layers.Activation('relu')
  in_channel = x.shape[-1]
  self.conv1 = layers.Con2D(x, use_bias=False, filters = 0.5*in_channel, kernel_size=[1,1], strides=stride, padding='same')
  self.dp = layers.Dropout(0.2)
  self.avgpool=layers.GlobalAveragePooling2D()
 
 def call(self, input, training = None):
  out = self.bn(input)
  out = self.relu(out)
  out = self.conv(out)
  out = self.dp(out)
  out = self.avgpool(out)
  return out
def dense_block(input, num_blocks):
	layers_concat = list()
	layers_concat.append(input)
	x = bottleneck_layer(input)
	layers_concat.append(x)
	for i in range(nb_layers - 1):
        	x = Concatenation(layers_concat)
        	x = self.bottleneck_layer(x)
        	layers_concat.append(x)
        x = Concatenation(layers_concat)
        return x
class Dense_net(keras.Model):
	  def __init__(self, input, filters="自定义", stride=1):
	  super(Dense_net, self).__init__()
	  
	  self.conv1 = layers.Con2D(x, use_bias=False, filters = 2*filters, kernel_size=[7,7], strides=2, padding='same')
	  self.block1 = dense_block(input, nb_layers=6)
	  self.trans1 = transition_layer(input)
	  
	  self.block2 = dense_block(input, nb_layers=12)
	  self.trans2 = transition_layer(input)
	  
	  self.block3 = dense_block(input, nb_layers=48)
	  self.trans3 = transition_layer(input)
	  
	  self.block4 = dense_block(input, nb_layers=32)
	  
	  self.bn = layers.BatchNormalization()
	  self.relu = layers.Activation('relu')
	  self.avgpool=layers.GlobalAveragePooling2D()
	  
	  self.dense = layers.Dense(input, units = "自定义", name = linear)
	def call(self, input, training = None):
	  out = self.conv1(input)
	  out = self.block1(out)
	  out = self.trans1(out)
	  out = self.block2(out)
	  out = self.trans2(out)
	  out = self.block3(out)
	  out = self.trans3(out)
	  out = self.block4(out)
	  out = self.bn(out)
	  out = self.relu(out)
	  out = self.avgpool(out)
	  out = flatten(out)
	  out = self.dense(out)
	  return out
		```