def identity_block(input_tensor: TensorType, kernel_size, filters, stage, block) -> TensorType: """The identity block is the block that has no conv layer at shortcut. Args: input_tensor: input tensor. kernel_size: default 3, the kernel size of middle conv layer at main path filters: list of integers, the filters of 3 conv layer at main path stage: integer, current stage label, used for generating layer names block: 'a','b'..., current block label, used for generating layer names Returns: output tensor for the block. """ name_base = f"conv{stage}_block{block}_" x = layers.conv(input_tensor, filters_out=filters[0], kernel_size=1, add_bias=False, name=name_base + '1_conv') x = layers.norm(x, axis=-1, epsilon=1.001e-5, name=name_base + '1_bn') x = layers.relu(x, name=name_base + '1_relu') x = layers.conv(x, filters_out=filters[1], kernel_size=kernel_size, add_bias=False, name=name_base + '2_conv') x = layers.norm(x, axis=-1, epsilon=1.001e-5, name=name_base + '2_bn') x = layers.relu(x, name=name_base + '2_relu') x = layers.conv(x, filters_out=filters[2], kernel_size=1, add_bias=False, name=name_base + '3_conv') x = layers.norm(x, axis=-1, epsilon=1.001e-5, name=name_base + '3_bn') x = x + input_tensor x = layers.relu(x, name=name_base + '3_relu') return x
def _inverted_res_block(inputs, expansion, stride, alpha, filters, block_id): in_channels = inputs.get_shape()[-1] pointwise_conv_filters = int(filters * alpha) pointwise_filters = _make_divisible(pointwise_conv_filters, 8) x = inputs prefix = 'block_{}_'.format(block_id) if block_id: # Expand x = layers.conv(x, filters_out=expansion * in_channels, kernel_size=1, padding='same', add_bias=False, name=prefix + 'expand') x = layers.norm(x, epsilon=1e-3, momentum=0.999, name=prefix + 'expand_BN') x = layers.relu(x, max_value=tf.constant(6, tf.float16), name=prefix + 'expand_relu') else: prefix = 'expanded_conv_' # Depthwise if stride == 2: x = layers.zero_padding(x, padding=((0, 1), (0, 1)), name=prefix + 'pad') x = layers.depthwise_conv(x, kernel_size=3, stride=stride, add_bias=False, padding='same' if stride == 1 else 'valid', name=prefix + 'depthwise') x = layers.norm(x, epsilon=1e-3, momentum=0.999, name=prefix + 'depthwise_BN') x = layers.relu(x, max_value=tf.constant(6, tf.float16), name=prefix + 'depthwise_relu') # Project x = layers.conv(x, filters_out=pointwise_filters, kernel_size=1, padding='same', add_bias=False, name=prefix + 'project') x = layers.norm(x, epsilon=1e-3, momentum=0.999, name=prefix + 'project_BN') if in_channels == pointwise_filters and stride == 1: return x + inputs return x
def conv_block(input_tensor: Union[tf.Tensor, np.ndarray], kernel_size, filters, stage, block, strides=2) -> TensorType: """Building block for a dense block. Args: input_tensor: Input tensor of type tf.Tensor if using tf backend, np.ndarray if using popart builder. kernel_size: default 3, the kernel size of middle conv layer at main path filters: list of integers, the filters of 3 conv layer at main path stage: integer, current stage label, used for generating layer names block: 'a','b'..., current block label, used for generating layer names strides: Strides for the first conv layer in the block. Return: Output tensor for the block. """ name_base = f"conv{stage}_block{block}_" shortcut = layers.conv(input_tensor, filters_out=filters[2], kernel_size=1, add_bias=False, stride=strides, name=name_base + '0_conv') shortcut = layers.norm(shortcut, axis=-1, epsilon=1.001e-5, name=name_base + '0_bn') x = layers.conv(input_tensor, filters_out=filters[0], kernel_size=1, stride=strides, add_bias=False, name=name_base + '1_conv') x = layers.norm(x, axis=-1, epsilon=1.001e-5, name=name_base + '1_bn') x = layers.relu(x, name=name_base + '1_relu') x = layers.conv(x, filters_out=filters[1], kernel_size=kernel_size, add_bias=False, name=name_base + '2_conv') x = layers.norm(x, axis=-1, epsilon=1.001e-5, name=name_base + '2_bn') x = layers.relu(x, name=name_base + '2_relu') x = layers.conv(x, filters_out=filters[2], kernel_size=1, add_bias=False, name=name_base + '3_conv') x = layers.norm(x, axis=-1, epsilon=1.001e-5, name=name_base + '3_bn') x = x + shortcut x = layers.relu(x, name=name_base + '3_relu') return x
def _depthwise_conv_block(x: Union[tf.Tensor, np.ndarray], pointwise_conv_filters, alpha, depth_multiplier=1, strides=1, block_id=1) -> TensorType: """A block of depthwise convolutions Args: x: input tensor. pointwise_conv_filters: number of pointwise filters modified by the size param Alpha alpha: determines the network size (modifies the number of conv filters) depth_multiplier: Changes the number of depthwise filters strides: changes stride block_id: Used to identify blocks Returns: output tensor for the block. """ pointwise_conv_filters = (pointwise_conv_filters * alpha) if strides == 1: _x = x else: _x = layers.zero_padding(x, padding=((0, 1), (0, 1)), name='conv_pad_%d' % block_id) _x = layers.depthwise_conv(_x, kernel_size=3, padding='same' if strides == 1 else 'valid', filters_out=depth_multiplier, stride=strides, add_bias=False, name='conv_dw_%d' % block_id) _x = layers.norm(_x, axis=-1, name='conv_dw_%d_bn' % block_id) _x = layers.relu(_x, name='conv_dw_%d' % block_id) _x = layers.conv(_x, filters_out=pointwise_conv_filters, kernel_size=1, padding='same', add_bias=False, stride=1, name='conv_pw_%d' % block_id) _x = layers.norm(_x, axis=-1, name='conv_pw_%d_bn' % block_id) return layers.relu(_x, name='conv_pw_%d_relu' % block_id)
def build_model(self, img_input: TensorType) -> TensorType: """Build graph using img_input as input. Args: img_input: 4D Image input tensor of shape (batch, height, width, channels) Returns: `Tensor` holding output probabilities per class, shape (batch, num_classes) """ x = layers.conv(img_input, filters_out=64, kernel_size=7, stride=2, add_bias=False, name='conv1_conv') x = layers.norm(x, axis=-1, epsilon=1.001e-5, name='conv1_bn') x = layers.relu(x, name='conv1_relu') x = layers.zero_padding(x, padding=((1, 1), (1, 1)), name='pool1_pad') x = layers.max_pool(x, kernel_size=3, name='pool1') x = self.conv_block(x, 3, [64, 64, 256], stage=2, block='1', strides=1) x = self.identity_block(x, 3, [64, 64, 256], stage=2, block='2') x = self.identity_block(x, 3, [64, 64, 256], stage=2, block='3') x = self.conv_block(x, 3, [128, 128, 512], stage=3, block='1') x = self.identity_block(x, 3, [128, 128, 512], stage=3, block='2') x = self.identity_block(x, 3, [128, 128, 512], stage=3, block='3') x = self.identity_block(x, 3, [128, 128, 512], stage=3, block='4') x = self.conv_block(x, 3, [256, 256, 1024], stage=4, block='1') x = self.identity_block(x, 3, [256, 256, 1024], stage=4, block='2') x = self.identity_block(x, 3, [256, 256, 1024], stage=4, block='3') x = self.identity_block(x, 3, [256, 256, 1024], stage=4, block='4') x = self.identity_block(x, 3, [256, 256, 1024], stage=4, block='5') x = self.identity_block(x, 3, [256, 256, 1024], stage=4, block='6') x = self.conv_block(x, 3, [512, 512, 2048], stage=5, block='1') x = self.identity_block(x, 3, [512, 512, 2048], stage=5, block='2') x = self.identity_block(x, 3, [512, 512, 2048], stage=5, block='3') x = layers.avg_pool(x, kernel_size=7, strides=1, name='avg_pool') x = layers.squeeze(x, axis=[1, 2], name='squeeze') x = layers.fully_connected(x, self.num_classes, name='probs') x = layers.softmax(x, name='output-prob') return x
def build_model(self, img_input: TensorType) -> TensorType: """Build graph using img_input as input. Args: img_input: 4D Image input tensor of shape (batch, height, width, channels) Returns: `Tensor` holding output probabilities per class, shape (batch, num_classes) """ channel_axis = -1 x = conv_norm_relu(img_input, 64, 7, strides=2, padding='SAME', name='InceptionV1/Conv2d_1a_7x7', norm_suffix="/BatchNorm", weight_suffix="weights", conv_suffix="") x = max_pool(x, 3, strides=2, padding='same', name='MaxPool_2a_3x3') x = conv_norm_relu(x, 64, 1, padding='same', name='InceptionV1/Conv2d_2b_1x1', weight_suffix="weights", conv_suffix="", norm_suffix="/BatchNorm") x = conv_norm_relu(x, 192, 3, padding='same', name='InceptionV1/Conv2d_2c_3x3', weight_suffix="weights", conv_suffix="", norm_suffix="/BatchNorm") x = max_pool(x, 3, strides=2, padding='same', name='MaxPool_3a_3x3') # Now the '3' level inception units x = self.inception_block(x, ((64, ), (96, 128), (16, 32), (32, )), channel_axis, 'InceptionV1/Mixed_3b') x = self.inception_block(x, ((128, ), (128, 192), (32, 96), (64, )), channel_axis, 'InceptionV1/Mixed_3c') x = max_pool(x, 3, strides=2, padding='same', name='MaxPool_4a_3x3') # Now the '4' level inception units x = self.inception_block(x, ((192, ), (96, 208), (16, 48), (64, )), channel_axis, 'InceptionV1/Mixed_4b') x = self.inception_block(x, ((160, ), (112, 224), (24, 64), (64, )), channel_axis, 'InceptionV1/Mixed_4c') x = self.inception_block(x, ((128, ), (128, 256), (24, 64), (64, )), channel_axis, 'InceptionV1/Mixed_4d') x = self.inception_block(x, ((112, ), (144, 288), (32, 64), (64, )), channel_axis, 'InceptionV1/Mixed_4e') x = self.inception_block(x, ((256, ), (160, 320), (32, 128), (128, )), channel_axis, 'InceptionV1/Mixed_4f') x = max_pool(x, 2, strides=2, padding='same', name='MaxPool_5a_2x2') # Now the '5' level inception units x = self.inception_block(x, ((256, ), (160, 320), (32, 128), (128, )), channel_axis, 'InceptionV1/Mixed_5b') x = self.inception_block(x, ((384, ), (192, 384), (48, 128), (128, )), channel_axis, 'InceptionV1/Mixed_5c') # Classification block x = avg_pool(x, kernel_size=7, strides=1, name='avg_pool', padding='valid') x = conv(x, filters_out=self.num_classes + 1, kernel_size=1, padding='valid', add_bias=True, name='InceptionV1/Logits/Conv2d_0c_1x1', weight_suffix="weights", bias_suffix="biases") x = squeeze(x, axis=[1, 2], name='squeeze') x = softmax(x, name='output-prob') return x
def build_model(self, img_input: TensorType) -> TensorType: """Build graph using img_input as input. Args: img_input: 4D Image input tensor of shape (batch, height, width, channels) Returns: `Tensor` holding output probabilities per class, shape (batch, num_classes) """ filters = _make_divisible(32 * self.alpha, 8) # Conv 1 block x = layers.zero_padding(img_input, padding=((0, 1), (0, 1)), name='Conv1_pad') x = layers.conv(x, filters_out=filters, kernel_size=3, padding='valid', add_bias=False, stride=2, name='Conv1') x = layers.norm(x, axis=-1, epsilon=1e-3, momentum=0.999, name='bn_Conv1') x = layers.relu(x, name='Conv1_relu', max_value=tf.constant(6, tf.float16)) # Depthwise separable convolutions x = self._inverted_res_block(x, filters=16, alpha=self.alpha, stride=1, expansion=1, block_id=0) x = self._inverted_res_block(x, filters=24, alpha=self.alpha, stride=2, expansion=6, block_id=1) x = self._inverted_res_block(x, filters=24, alpha=self.alpha, stride=1, expansion=6, block_id=2) x = self._inverted_res_block(x, filters=32, alpha=self.alpha, stride=2, expansion=6, block_id=3) x = self._inverted_res_block(x, filters=32, alpha=self.alpha, stride=1, expansion=6, block_id=4) x = self._inverted_res_block(x, filters=32, alpha=self.alpha, stride=1, expansion=6, block_id=5) x = self._inverted_res_block(x, filters=64, alpha=self.alpha, stride=2, expansion=6, block_id=6) x = self._inverted_res_block(x, filters=64, alpha=self.alpha, stride=1, expansion=6, block_id=7) x = self._inverted_res_block(x, filters=64, alpha=self.alpha, stride=1, expansion=6, block_id=8) x = self._inverted_res_block(x, filters=64, alpha=self.alpha, stride=1, expansion=6, block_id=9) x = self._inverted_res_block(x, filters=96, alpha=self.alpha, stride=1, expansion=6, block_id=10) x = self._inverted_res_block(x, filters=96, alpha=self.alpha, stride=1, expansion=6, block_id=11) x = self._inverted_res_block(x, filters=96, alpha=self.alpha, stride=1, expansion=6, block_id=12) x = self._inverted_res_block(x, filters=160, alpha=self.alpha, stride=2, expansion=6, block_id=13) x = self._inverted_res_block(x, filters=160, alpha=self.alpha, stride=1, expansion=6, block_id=14) x = self._inverted_res_block(x, filters=160, alpha=self.alpha, stride=1, expansion=6, block_id=15) x = self._inverted_res_block(x, filters=320, alpha=self.alpha, stride=1, expansion=6, block_id=16) # no alpha applied to last conv as stated in the paper: # if the width multiplier is greater than 1 we # increase the number of output channels if self.alpha > 1.0: last_block_filters = _make_divisible(1280 * self.alpha, 8) else: last_block_filters = 1280 x = layers.conv(x, filters_out=last_block_filters, kernel_size=1, add_bias=False, name='Conv_1') x = layers.norm(x, epsilon=1e-3, momentum=0.999, name='Conv_1_bn') x = layers.relu(x, max_value=tf.constant(6, tf.float16), name='out_relu') # Include top x = layers.global_avg_pool(x) x = layers.fully_connected(x, self.num_classes, name='Logits') x = layers.softmax(x, name='act_softmax') return x
def build_model(self, img_input: TensorType) -> TensorType: """Build graph using img_input as input. Args: img_input: 4D Image input tensor of shape (batch, height, width, channels) Returns: `Tensor` holding output probabilities per class, shape (batch, num_classes) """ filters = int(32 * self.alpha) shape = (-1, 1, 1, int(1024 * self.alpha)) # Conv 1 block x = layers.zero_padding(img_input, padding=((0, 1), (0, 1)), name='conv1_pad') x = layers.conv(x, filters_out=filters, kernel_size=3, padding='valid', add_bias=False, stride=2, name='conv1') x = layers.norm(x, axis=-1, name='conv1_bn') x = layers.relu(x, name='conv1_relu') # Depthwise convolutions x = self._depthwise_conv_block(x, 64, self.alpha, depth_multiplier=1, block_id=1) x = self._depthwise_conv_block(x, 128, self.alpha, depth_multiplier=1, strides=2, block_id=2) x = self._depthwise_conv_block(x, 128, self.alpha, depth_multiplier=1, block_id=3) x = self._depthwise_conv_block(x, 256, self.alpha, depth_multiplier=1, strides=2, block_id=4) x = self._depthwise_conv_block(x, 256, self.alpha, depth_multiplier=1, block_id=5) x = self._depthwise_conv_block(x, 512, self.alpha, depth_multiplier=1, strides=2, block_id=6) x = self._depthwise_conv_block(x, 512, self.alpha, depth_multiplier=1, block_id=7) x = self._depthwise_conv_block(x, 512, self.alpha, depth_multiplier=1, block_id=8) x = self._depthwise_conv_block(x, 512, self.alpha, depth_multiplier=1, block_id=9) x = self._depthwise_conv_block(x, 512, self.alpha, depth_multiplier=1, block_id=10) x = self._depthwise_conv_block(x, 512, self.alpha, depth_multiplier=1, block_id=11) x = self._depthwise_conv_block(x, 1024, self.alpha, depth_multiplier=1, strides=2, block_id=12) x = self._depthwise_conv_block(x, 1024, self.alpha, depth_multiplier=1, block_id=13) # Include top x = layers.global_avg_pool(x) x = layers.reshape(x, shape=shape, name='reshape_1') x = layers.conv(x, filters_out=self.num_classes, kernel_size=1, padding='same', name='conv_preds', add_bias=False) x = layers.reshape(x, shape=(-1, self.num_classes), name='reshape_2') x = layers.softmax(x, name='act_softmax') return x
def build_model(self, img_input: TensorType) -> TensorType: """Build graph using img_input as input. Args: img_input: 4D Image input tensor of shape (batch, height, width, channels) Returns: `Tensor` holding output probabilities per class, shape (batch, num_classes) """ x = layers.conv(img_input, filters_out=32, kernel_size=3, stride=2, add_bias=False, name='block1_conv1') x = layers.norm(x, name='block1_conv1_bn') x = layers.relu(x, name='block1_conv1_act') x = layers.conv(x, filters_out=64, kernel_size=3, add_bias=False, name='block1_conv2') x = layers.norm(x, name='block1_conv2_bn') x = layers.relu(x, name='block1_conv2_act') residual = layers.conv(x, filters_out=128, kernel_size=1, stride=2, padding='same', add_bias=False) residual = layers.norm(residual, name="batch_normalization") x = layers.separable_conv(x, filters_out=128, kernel_size=3, padding='same', add_bias=False, name='block2_sepconv1') x = layers.norm(x, name='block2_sepconv1_bn') x = layers.relu(x, name='block2_sepconv2_act') x = layers.separable_conv(x, filters_out=128, kernel_size=3, padding='same', add_bias=False, name='block2_sepconv2') x = layers.norm(x, name='block2_sepconv2_bn') x = layers.max_pool(x, 3, strides=2, padding='same', name='block2_pool') x += residual residual = layers.conv(x, filters_out=256, kernel_size=1, stride=2, padding='same', add_bias=False) residual = layers.norm(residual, name="batch_normalization") x = layers.relu(x, name='block3_sepconv1_act') x = layers.separable_conv(x, filters_out=256, kernel_size=3, padding='same', add_bias=False, name='block3_sepconv1') x = layers.norm(x, name='block3_sepconv1_bn') x = layers.relu(x, name='block3_sepconv2_act') x = layers.separable_conv(x, filters_out=256, kernel_size=3, padding='same', add_bias=False, name='block3_sepconv2') x = layers.norm(x, name='block3_sepconv2_bn') x = layers.max_pool(x, 3, strides=2, padding='same', name='block3_pool') x += residual residual = layers.conv(x, filters_out=728, kernel_size=1, stride=2, padding='same', add_bias=False) residual = layers.norm(residual, name="batch_normalization") x = layers.relu(x, name='block4_sepconv1_act') x = layers.separable_conv(x, filters_out=728, kernel_size=3, padding='same', add_bias=False, name='block4_sepconv1') x = layers.norm(x, name='block4_sepconv1_bn') x = layers.relu(x, name='block4_sepconv2_act') x = layers.separable_conv(x, filters_out=728, kernel_size=3, padding='same', add_bias=False, name='block4_sepconv2') x = layers.norm(x, name='block4_sepconv2_bn') x = layers.max_pool(x, 3, strides=2, padding='same', name='block4_pool') x += residual for i in range(8): residual = x prefix = 'block' + str(i + 5) x = layers.relu(x, name=prefix + '_sepconv1_act') x = layers.separable_conv(x, filters_out=728, kernel_size=3, padding='same', add_bias=False, name=prefix + '_sepconv1') x = layers.norm(x, name=prefix + '_sepconv1_bn') x = layers.relu(x, name=prefix + '_sepconv2_act') x = layers.separable_conv(x, filters_out=728, kernel_size=3, padding='same', add_bias=False, name=prefix + '_sepconv2') x = layers.norm(x, name=prefix + '_sepconv2_bn') x = layers.relu(x, name=prefix + '_sepconv3_act') x = layers.separable_conv(x, filters_out=728, kernel_size=3, padding='same', add_bias=False, name=prefix + '_sepconv3') x = layers.norm(x, name=prefix + '_sepconv3_bn') x += residual residual = layers.conv(x, filters_out=1024, kernel_size=1, stride=2, padding='same', add_bias=False) residual = layers.norm(residual, name="batch_normalization") x = layers.relu(x, name='block13_sepconv1_act') x = layers.separable_conv(x, filters_out=728, kernel_size=3, padding='same', add_bias=False, name='block13_sepconv1') x = layers.norm(x, name='block13_sepconv1_bn') x = layers.relu(x, name='block13_sepconv2_act') x = layers.separable_conv(x, filters_out=1024, kernel_size=3, padding='same', add_bias=False, name='block13_sepconv2') x = layers.norm(x, name='block13_sepconv2_bn') x = layers.max_pool(x, 3, strides=2, padding='same', name='block13_pool') x += residual x = layers.separable_conv(x, filters_out=1536, kernel_size=3, padding='same', add_bias=False, name='block14_sepconv1') x = layers.norm(x, name='block14_sepconv1_bn') x = layers.relu(x, name='block14_sepconv1_act') x = layers.separable_conv(x, filters_out=2048, kernel_size=3, padding='same', add_bias=False, name='block14_sepconv2') x = layers.norm(x, name='block14_sepconv2_bn') x = layers.relu(x, name='block14_sepconv2_act') # Classification block x = layers.avg_pool(x, kernel_size=10, strides=1, name='avg_pool') x = layers.squeeze(x, axis=[1, 2], name='squeeze') x = layers.fully_connected(x, self.num_classes, name='predictions') x = layers.softmax(x, name='output-prob') return x
def build_model(self, img_input: TensorType) -> TensorType: """Build graph using img_input as input. Args: img_input: 4D Image input tensor of shape (batch, height, width, channels) Returns: `Tensor` holding output probabilities per class, shape (batch, num_classes) """ filters = self.penultimate_filters // 24 x = layers.conv(img_input, filters_out=self.stem_block_filters, kernel_size=3, stride=2, padding='valid', add_bias=False, name='stem_conv1') x = layers.norm(x, axis=-1, momentum=0.9997, epsilon=1e-3, name='stem_bn1') p = None x, p = self.reduction_a_cell(x, p, filters // (self.filter_multiplier**2), block_id='stem_1') x, p = self.reduction_a_cell(x, p, filters // self.filter_multiplier, block_id='stem_2') for i in range(self.num_blocks): x, p = self.normal_a_cell(x, p, filters, block_id='%d' % i) x, p0 = self.reduction_a_cell(x, p, filters * self.filter_multiplier, block_id='reduce_%d' % self.num_blocks) p = p0 if not self.skip_reduction else p for i in range(self.num_blocks): x, p = self.normal_a_cell(x, p, filters * self.filter_multiplier, block_id='%d' % (self.num_blocks + i + 1)) x, p0 = self.reduction_a_cell(x, p, filters * self.filter_multiplier**2, block_id='reduce_%d' % (2 * self.num_blocks)) p = p0 if not self.skip_reduction else p for i in range(self.num_blocks): x, p = self.normal_a_cell(x, p, filters * self.filter_multiplier**2, block_id='%d' % (2 * self.num_blocks + i + 1)) x = layers.relu(x, 'relu') # Classification block x = layers.avg_pool(x, kernel_size=7, strides=1, name='avg_pool') x = layers.squeeze(x, axis=[1, 2], name='squeeze') x = layers.fully_connected(x, self.num_classes, name='predictions') x = layers.softmax(x, name='output-prob') return x
def reduction_a_cell(ip, p, filters, block_id=None): """Adds a Reduction cell for NASNet-A (Fig. 4 in the paper). Args: ip: Input tensor `x` p: Input tensor `p` filters: Number of output filters block_id: String block_id Returns: A tf tensor """ channel_dim = -1 with tf.name_scope('reduction_A_block_%s' % block_id): p = NASNetMobile.adjust_block(p, ip, filters, block_id) h = layers.relu(ip) h = layers.conv(h, filters_out=filters, kernel_size=(1, 1), stride=1, padding='same', name='reduction_conv_1_%s' % block_id, add_bias=False) h = layers.norm(h, axis=channel_dim, momentum=0.9997, epsilon=1e-3, name='reduction_bn_1_%s' % block_id) h3 = layers.zero_padding(h, padding=NASNetMobile.correct_pad( h, (3, 3)), name='reduction_pad_1_%s' % block_id) with tf.name_scope('block_1'): x1_1 = NASNetMobile.separable_conv_block( h, filters=filters, kernel_size=5, strides=2, block_id='reduction_left1_%s' % block_id) x1_2 = NASNetMobile.separable_conv_block( p, filters=filters, kernel_size=7, strides=2, block_id='reduction_right1_%s' % block_id) x1 = x1_1 + x1_2 with tf.name_scope('block_2'): x2_1 = layers.max_pool(h3, 3, strides=2, padding='valid', name='reduction_left2_%s' % block_id) x2_2 = NASNetMobile.separable_conv_block( p, filters=filters, kernel_size=7, strides=2, block_id='reduction_right2_%s' % block_id) x2 = x2_1 + x2_2 with tf.name_scope('block_3'): x3_1 = layers.avg_pool(h3, 3, strides=2, padding='valid', name='reduction_left3_%s' % block_id) x3_2 = NASNetMobile.separable_conv_block( p, filters, 5, strides=2, block_id='reduction_right3_%s' % block_id) x3 = x3_1 + x3_2 with tf.name_scope('block_4'): x4 = layers.avg_pool(x1, 3, strides=1, padding='same', name='reduction_left4_%s' % block_id) x4 += x2 with tf.name_scope('block_5'): x5_1 = NASNetMobile.separable_conv_block( x1, filters, 3, block_id='reduction_left4_%s' % block_id) x5_2 = layers.max_pool(h3, 3, strides=2, padding='valid', name='reduction_right5_%s' % block_id) x5 = x5_1 + x5_2 x = layers.concat([x2, x3, x4, x5], axis=channel_dim, name='reduction_concat_%s' % block_id) return x, ip
def normal_a_cell(ip, p, filters, block_id=None): """Adds a Normal cell for NASNet-A (Fig. 4 in the paper). Args: ip: Input tensor `x` p: Input tensor `p` filters: Number of output filters block_id: String block_id Returns: A tensorflow tensor """ channel_dim = -1 with tf.name_scope('normal_A_block_%s' % block_id): p = NASNetMobile.adjust_block(p, ip, filters, block_id) h = layers.relu(ip) h = layers.conv(h, filters_out=filters, kernel_size=(1, 1), stride=1, padding='same', name='normal_conv_1_%s' % block_id, add_bias=False) h = layers.norm(h, axis=channel_dim, momentum=0.9997, epsilon=1e-3, name='normal_bn_1_%s' % block_id) with tf.name_scope('block_1'): x1_1 = NASNetMobile.separable_conv_block( h, filters, kernel_size=5, block_id='normal_left1_%s' % block_id) x1_2 = NASNetMobile.separable_conv_block( p, filters, block_id='normal_right1_%s' % block_id) x1 = x1_1 + x1_2 with tf.name_scope('block_2'): x2_1 = NASNetMobile.separable_conv_block( p, filters, 5, block_id='normal_left2_%s' % block_id) x2_2 = NASNetMobile.separable_conv_block( p, filters, 3, block_id='normal_right2_%s' % block_id) x2 = x2_1 + x2_2 with tf.name_scope('block_3'): x3 = layers.avg_pool(h, 3, strides=1, padding='same', name='normal_left3_%s' % block_id) x3 = x3 + p with tf.name_scope('block_4'): x4_1 = layers.avg_pool(p, 3, strides=1, padding='same', name='normal_left4_%s' % block_id) x4_2 = layers.avg_pool(p, 3, strides=1, padding='same', name='normal_right4_%s' % block_id) x4 = x4_1 + x4_2 with tf.name_scope('block_5'): x5 = NASNetMobile.separable_conv_block( h, filters, block_id='normal_left5_%s' % block_id) x5 = x5 + h x = layers.concat([p, x1, x2, x3, x4, x5], axis=channel_dim, name='normal_concat_%s' % block_id) return x, ip
def adjust_block(p, ip, filters, block_id=None): """Adjusts the input `previous path` to match the shape of the `input`. Used in situations where the output number of filters needs to be changed. Args: p: Input tensor which needs to be modified ip: Input tensor whose shape needs to be matched filters: Number of output filters to be matched block_id: String block_id Returns: Adjusted tf tensor. """ channel_dim = -1 img_dim = -2 ip_shape = ip.get_shape().as_list() if p is not None: p_shape = p.get_shape().as_list() else: p_shape = ip_shape with tf.name_scope('adjust_block'): if p is None: p = ip elif p_shape[img_dim] != ip_shape[img_dim]: with tf.name_scope('adjust_reduction_block_%s' % block_id): p = layers.relu(p, name='adjust_relu_1_%s' % block_id) p1 = layers.avg_pool(p, 1, strides=2, padding='valid', name='adjust_avg_pool_1_%s' % block_id) p1 = layers.conv(p1, filters_out=filters // 2, kernel_size=(1, 1), padding='same', add_bias=False, name='adjust_conv_1_%s' % block_id) p2 = layers.zero_padding(p, padding=((0, 1), (0, 1))) p2 = layers.crop(p2, cropping=((1, 0), (1, 0))) p2 = layers.avg_pool(p2, 1, strides=2, padding='valid', name='adjust_avg_pool_2_%s' % block_id) p2 = layers.conv(p2, filters_out=filters // 2, kernel_size=(1, 1), padding='same', add_bias=False, name='adjust_conv_2_%s' % block_id) p = layers.concat([p1, p2], axis=channel_dim) p = layers.norm(p, axis=channel_dim, momentum=0.9997, epsilon=1e-3, name='adjust_bn_%s' % block_id) elif p_shape[channel_dim] != filters: with tf.name_scope('adjust_projection_block_%s' % block_id): p = layers.relu(p) p = layers.conv(p, filters_out=filters, kernel_size=(1, 1), stride=1, padding='same', name='adjust_conv_projection_%s' % block_id, add_bias=False) p = layers.norm(p, axis=channel_dim, momentum=0.9997, epsilon=1e-3, name='adjust_bn_%s' % block_id) return p