ResNet极大地改变了有关如何参数化深度网络功能的观点。DenseNet(密集卷积网络)在某种程度上是对此的逻辑扩展,它与ResNet的主要区别见下图:
- ResNet是相加
- DenseNet是连结
x → [ x , f 1 ( x ) , f 2 ( [ x , f 1 ( x ) ] ) , f 3 ( [ x , f 1 ( x ) , f 2 ( [ x , f 1 ( x ) ] ) ] ) , … ] x→[x,f_1(x),f_2([x,f_1(x)]),f_3([x,f_1(x),f_2([x,f_1(x)])]),…] x→[x,f1(x),f2([x,f1(x)]),f3([x,f1(x),f2([x,f1(x)])]),…]
ResNet的主要区别在于,DenseNet里模块B的输出不是像ResNet那样和模块A的输出相加,而是在通道维上连结。这样模块A的输出可以直接传入模块B后面的层。在这个设计里,模块A直接跟模块B后面的所有层连接在了一起。之所以起名为密集连接,是因为变量之间的依存关系图变得非常密集。
构成DenseNet的主要组件是密集块(dense block)和过渡层(transition layer)。前者定义输入和输出的连接方式,而后者控制通道的数量,以免太大。
1. 密集块(dense block)
DenseNet使用了ResNet改良版的“批量归一化、激活和卷积”结构.
from d2l import mxnet as d2l
from mxnet import np, npx, init, gluon, autograd
from mxnet.gluon import nn
import plotly.graph_objs as go
npx.set_np()
ctx = npx.gpu() if npx.num_gpus() > 0 else npx.cpu()
def conv_block(num_channels):
block = nn.Sequential()
block.add(
nn.BatchNorm(),
nn.Activation('relu'),
nn.Conv2D(num_channels, kernel_size=3, padding=1)
)
return block
- 密集块由多个conv_block组,成每块使用相同的输出通道数。但在正向传播的时候,我们将每块的输入和输出在通道维上连结。