在胶子中,网络是用
Block
S.如果某物不是
街区
它不能是胶子网络的一部分。致密层为
街区
,卷积是
街区
,池层是
街区
等。
有时您可能需要一个不是Gluon中预先定义的块,而是一个预先定义的Gluon块序列的块。例如,
Conv2D -> MaxPool2D -> Conv2D -> MaxPool2D -> Flatten -> Dense -> Dense
Gluon没有执行上述操作序列的预定义块。但是胶子确实有块来完成每个单独的操作。因此,您可以创建自己的块,通过将预定义的胶子块串在一起来执行上述操作序列。例子:
net = gluon.nn.HybridSequential()
with net.name_scope():
# First convolution
net.add(gluon.nn.Conv2D(channels=20, kernel_size=5, activation='relu'))
net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))
# Second convolution
net.add(gluon.nn.Conv2D(channels=50, kernel_size=5, activation='relu'))
net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))
# Flatten the output before the fully connected layers
net.add(gluon.nn.Flatten())
# First fully connected layers with 512 neurons
net.add(gluon.nn.Dense(512, activation="relu"))
# Second fully connected layer with as many neurons as the number of classes
net.add(gluon.nn.Dense(num_outputs))
当您创建这样的序列时,您可以使用
HybridSequential
或
Sequential
. 为了理解差异,你需要理解
difference between symbolic and imperative programming
.
-
HybridBlock
是一个可以转换为符号图以加快执行速度的块。
混合序列
是一个序列
Hybrid
阻碍。
-
Blocks
(不是混合块)是不能转换为符号图的块。
相继的
是一个非混合块序列。
块是否混合取决于如何实现。几乎所有预先定义的胶子块也是杂交块。有时,有些块不能混合是有原因的。
Tree LSTM
就是一个例子。更常见的是,有些东西不是混合型的,只是因为不管是谁写的,它并没有努力使它混合,有几个原因(例如:也许使它混合不会提供大的性能提升,或者可能是很难使块混合)。
注意
相继的
和
混合序列
不仅仅是像蟒蛇这样的容器
list
. 当您使用其中一个时,实际上是在创建一个新的
街区
使用预先存在的块。这就是为什么你不能替换
相继的
使用python
列表
.
好吧,那么你知道如何通过把以前存在的块串在一起来创建你自己的块。很好。如果您不想只通过一系列块传递数据呢?如果您想有条件地通过这些块中的一个来传递数据,该怎么办?下面是来自Resnet的一个示例:
class BasicBlockV1(HybridBlock):
def __init__(self, channels, stride, downsample=False, in_channels=0, **kwargs):
super(BasicBlockV1, self).__init__(**kwargs)
self.body = nn.HybridSequential(prefix='')
self.body.add(_conv3x3(channels, stride, in_channels))
self.body.add(nn.BatchNorm())
self.body.add(nn.Activation('relu'))
self.body.add(_conv3x3(channels, 1, channels))
self.body.add(nn.BatchNorm())
if downsample:
self.downsample = nn.HybridSequential(prefix='')
self.downsample.add(nn.Conv2D(channels, kernel_size=1, strides=stride,
use_bias=False, in_channels=in_channels))
self.downsample.add(nn.BatchNorm())
else:
self.downsample = None
def hybrid_forward(self, F, x):
residual = x
x = self.body(x)
if self.downsample:
residual = self.downsample(residual)
x = F.Activation(residual+x, act_type='relu')
return x
此代码使用先前存在的胶接块创建新块。但它不仅仅是通过一些以前存在的块运行数据。给定一些数据后,块将数据运行到主体中
block
阿威。然后,运行数据
downsample
仅当此块是用
降低采样
设置为真。然后确定
body
和
降低采样
创建输出。正如您所看到的,不仅仅是通过一系列块传递数据,还有更多的事情发生。这是通过子类化创建自己的块的时候
混合块
或
街区
.
注意,
__init__
函数创建了必要的块和
forward
函数获取输入并通过在中创建的块运行输入。
_初始化__
.
向前地
不修改在中创建的块
_初始化__
. 它只通过在中创建的块运行数据。
_初始化__
.
在引用的示例中,第一个代码块创建的块如下
downsamplers
,
class_predictors
,
box_predictors
. 代码块2和3中的forward函数不修改这些块。它们只是通过这些块传递输入数据。