В Gluon сети строятся с использованием Block
s.Если что-то не является Block
, оно не может быть частью сети Gluon.Плотный слой - Block
, Convolution - Block
, пуловый слой - Block
и т. Д.
Иногда вам может потребоваться блок, который не является предварительно определенным блоком в Gluon, но являетсяпоследовательность предопределенных блоков Gluon.Например,
Conv2D -> MaxPool2D -> Conv2D -> MaxPool2D -> Flatten -> Dense -> Dense
Gluon не имеет предварительно определенного блока, который выполняет вышеуказанную последовательность операций.Но у Gluon есть блоки, которые выполняют каждую отдельную операцию.Таким образом, вы можете создать свой собственный блок, который выполняет описанную выше последовательность операций, связав воедино предопределенные блоки 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
.Чтобы понять разницу, вам нужно понять разницу между символическим и императивным программированием .
HybridBlock
- это блок, который можно преобразовать в символьный граф для более быстрого выполнения.HybridSequential
- это последовательность Hybrid
блоков. Blocks
(не гибридных) - это блок, который нельзя преобразовать в символьный граф.Sequential
- это последовательность негибридных блоков.
То, является ли блок гибридным, зависит от того, как он реализован.Почти все предопределенные блоки Gluon также являются HybridBlocks.Иногда есть причина, по которой некоторые блоки не могут быть гибридными. Дерево LSTM является одним примером.Чаще всего что-то не является гибридом только потому, что тот, кто написал его, не пытался сделать его гибридным по нескольким причинам (например: создание гибридного не даст большого прироста производительности или создание гибридного блока сложно).
Обратите внимание, что Sequential
и HybridSequential
- это не просто контейнеры, такие как Python list
.Когда вы используете один из них, вы фактически создаете новый Block
, используя уже существующие блоки.Вот почему вы не можете заменить Sequential
с помощью Python list
.
Хорошо, так что вы знаете, как создать свой собственный блок, соединив вместе существующие блоки.Хорошо.Что если вы хотите не просто передавать данные через последовательность блоков?Что делать, если вы хотите условно передать данные через один из этих блоков.Вот пример из 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
Этот код создает новый блок, используя ранее существующие блоки Gluon.Но это больше, чем просто прохождение данных через некоторые существующие блоки.Учитывая некоторые данные, блок пропускает данные через тело block
в пути.Но затем запускает данные через downsample
, только если этот блок был создан с downsample
, установленным в значение true.Затем он объединяет выходные данные body
и downsample
, чтобы создать выходные данные.Как вы можете видеть, что происходит нечто большее, чем просто передача данных через последовательность блоков.Это когда вы создаете свой собственный блок подклассами HybridBlock
или Block
.
Обратите внимание, что функция __init__
создала необходимые блоки, а функция forward
получает входные данные и пропускает входные данные через блоки.создан в __init__
.forward
не изменяет блоки, созданные в __init__
.Он пропускает данные только через блоки, созданные в __init__
.
. В приведенном вами примере первый блок кода создает блоки типа downsamplers
, class_predictors
, box_predictors
.Функции пересылки в кодовом блоке 2 и 3 не модифицируют эти блоки.Они просто передают входные данные через эти блоки.