def test_model23(self): model1 = Sequential(self.s, model_table='Simple_CNN1') model1.add(InputLayer(3, 224, 224)) model1.add(Conv2d(8, 7, act='identity', include_bias=False)) model1.add(BN(act='relu')) model1.add(Pooling(2)) model1.add(Conv2d(8, 7, act='identity', include_bias=False)) model1.add(BN(act='relu')) model1.add(Pooling(2)) model1.add(Dense(2)) model1.add(OutputLayer(act='softmax', n=2)) if self.data_dir is None: unittest.TestCase.skipTest(self, "DLPY_DATA_DIR is not set in the environment variables") caslib, path = caslibify(self.s, path=self.data_dir+'images.sashdat', task='load') self.s.table.loadtable(caslib=caslib, casout={'name': 'eee', 'replace': True}, path=path) r = model1.fit(data='eee', inputs='_image_', target='_label_', max_epochs=1) self.assertTrue(r.severity == 0) model1.deploy(self.data_dir, output_format='onnx')
def test_model13(self): # test dropout try: import onnx except: unittest.TestCase.skipTest(self, "onnx not found in the libraries") model1 = Sequential(self.s, model_table='Simple_CNN1') model1.add(InputLayer(3, 224, 224)) model1.add( Conv2d(8, 7, act='IDENTITY', dropout=0.5, include_bias=False)) model1.add(BN(act='relu')) model1.add(Pooling(2, pool='MEAN', dropout=0.5)) model1.add( Conv2d(8, 7, act='IDENTITY', dropout=0.5, include_bias=False)) model1.add(BN(act='relu')) model1.add(Pooling(2, pool='MEAN', dropout=0.5)) model1.add(Conv2d(8, 7, act='identity', include_bias=False)) model1.add(BN(act='relu')) model1.add(Dense(16, act='IDENTITY', dropout=0.1)) model1.add(OutputLayer(act='softmax', n=2)) if self.data_dir is None: unittest.TestCase.skipTest( self, "DLPY_DATA_DIR is not set in the environment variables") caslib, path, tmp_caslib = caslibify(self.s, path=self.data_dir + 'images.sashdat', task='load') self.s.table.loadtable(caslib=caslib, casout={ 'name': 'eee', 'replace': True }, path=path) r = model1.fit(data='eee', inputs='_image_', target='_label_', max_epochs=2) self.assertTrue(r.severity == 0) import tempfile tmp_dir_to_dump = tempfile.gettempdir() model1.deploy(tmp_dir_to_dump, output_format='onnx') import os os.remove(os.path.join(tmp_dir_to_dump, "Simple_CNN1.onnx")) if (caslib is not None) and tmp_caslib: self.s.retrieve('table.dropcaslib', message_level='error', caslib=caslib)
def downsampling_bottleneck(x, in_depth, out_depth, projection_ratio=4): ''' Defines the down-sampling bottleneck of ENet Parameters ---------- x : class:`Layer' Previous layer to this block in_depth : int Depth of the layer fed into this block out_depth : int Depth of the output layer of this block projection_ratio : int, optional Used to calculate the reduced_depth for intermediate convolution layers Default: 4 Returns ------- :class:`Res` ''' reduced_depth = int(in_depth // projection_ratio) conv1 = Conv2d(reduced_depth, 3, stride=2, padding=1, act='identity', include_bias=False)(x) bn1 = BN(act='relu')(conv1) conv2 = Conv2d(reduced_depth, 3, stride=1, act='identity', include_bias=False)(bn1) bn2 = BN(act='relu')(conv2) conv3 = Conv2d(out_depth, 1, stride=1, act='identity', include_bias=False)(bn2) bn3 = BN(act='relu')(conv3) pool1 = Pooling(2, stride=2)(x) conv4 = Conv2d(out_depth, 1, stride=1, act='identity', include_bias=False)(pool1) bn4 = BN(act='relu')(conv4) res = Res()([bn3, bn4]) return res
def _depthwise_conv_block(inputs, n_groups, pointwise_conv_filters, alpha, depth_multiplier=1, stride=1, block_id=1): """Adds a depthwise convolution block. inputs: Input tensor n_groups : int number of groups pointwise_conv_filters: the dimensionality of the output space alpha: controls the width of the network. - If `alpha` < 1.0, proportionally decreases the number of filters in each layer. - If `alpha` > 1.0, proportionally increases the number of filters in each layer. - If `alpha` = 1, default number of filters from the paper are used at each layer. depth_multiplier: The number of depthwise convolution output channels strides: An integer or tuple/list of 2 integers, specifying the strides of the convolution block_id: Integer, a unique identification designating the block number. """ pointwise_conv_filters = int(pointwise_conv_filters * alpha) x = GroupConv2d(n_groups * depth_multiplier, n_groups, 3, stride=stride, act='identity', include_bias=False, name='conv_dw_%d' % block_id)(inputs) x = BN(name='conv_dw_%d_bn' % block_id, act='relu')(x) x = Conv2d(pointwise_conv_filters, 1, act='identity', include_bias=False, stride=1, name='conv_pw_%d' % block_id)(x) x = BN(name='conv_pw_%d_bn' % block_id, act='relu')(x) return x, pointwise_conv_filters
def _conv_block(inputs, filters, alpha, kernel=3, stride=1): """ Adds an initial convolution layer (with batch normalization inputs: Input tensor filters: the dimensionality of the output space alpha: controls the width of the network. - If `alpha` < 1.0, proportionally decreases the number of filters in each layer. - If `alpha` > 1.0, proportionally increases the number of filters in each layer. - If `alpha` = 1, default number of filters from the paper are used at each layer. kernel: specifying the width and height of the 2D convolution window. strides: the strides of the convolution """ filters = int(filters * alpha) x = Conv2d(filters, kernel, act='identity', include_bias=False, stride=stride, name='conv1')(inputs) x = BN(name='conv1_bn', act='relu')(x) return x, filters
def onnx_extract_batchnormalization(graph, node, layers): ''' Construct batchnorm layer from ONNX op Parameters ---------- graph : ONNX GraphProto Specifies a GraphProto object. node : ONNX NodeProto Specifies a NodeProto object. layers : list of Layers Specifies the existing layers of a model. Returns ------- :class:`BN` ''' previous = onnx_find_previous_compute_layer(graph, node) if not previous: src_names = [find_input_layer_name(graph)] else: src_names = [p.name for p in previous] src = [get_dlpy_layer(layers, i) for i in src_names] return BN(name=node.name, act='identity', src_layers=src)
def upsampling_bottleneck(x, in_depth, out_depth, projection_ratio=4): ''' Defines the up-sampling bottleneck of ENet Parameters ---------- x : class:`Layer' Previous layer to this block in_depth : int Depth of the layer fed into this block out_depth : int Depth of the output layer of this block projection_ratio : int, optional Used to calculate the reduced_depth for intermediate convolution layers Default: 4 Returns ------- :class:`BN` ''' reduced_depth = int(in_depth // projection_ratio) conv1 = Conv2d(reduced_depth, 1, stride=1, act='identity', include_bias=False)(x) bn1 = BN(act='relu')(conv1) tconv1 = Conv2DTranspose(reduced_depth, 3, stride=2, padding=1, output_padding=1, act='identity', include_bias=False)(bn1) bn2 = BN(act='relu')(tconv1) conv3 = Conv2d(out_depth, 1, stride=1, act='identity', include_bias=False)(bn2) bn3 = BN(act='relu')(conv3) return bn3
def test_model_crnn_bug(self): model = Sequential(self.s, model_table='crnn') model.add(InputLayer(3,256,16)) model.add(Reshape(height=16,width=256,depth=3)) model.add(Conv2d(64,3,3,stride=1,padding=1)) # size = 16x256x64 model.add(Pooling(2,2,2)) # size = 8x128x64 model.add(Conv2d(128,3,3,stride=1,padding=1)) # size = 8x128x128 model.add(Pooling(2,2,2)) # size = 4x64x128 model.add(Conv2d(256,3,3,stride=1,padding=1,act='IDENTITY')) # size = 4x64x256 model.add(BN(act='RELU')) # size = 4x64x256 model.add(Conv2d(256,3,3,stride=1,padding=1)) # size = 4x64x256 model.add(Pooling(1,2,stride_horizontal=1, stride_vertical=2)) #, padding=1)) # size = 2x64x256 #model.add(Pooling(1,2,stride=2,stride_horizontal=1, stride_vertical=2,)) # size = 2x64x256 model.add(Conv2d(512,3,3,stride=1,padding=1, act='IDENTITY')) # size = 2x64x512 model.add(BN(act='RELU')) model.add(Conv2d(512,3,3,stride=1,padding=1)) # size = 2x64x512 model.add(Pooling(1,2,stride_horizontal=1, stride_vertical=2)) #, padding=1)) # size = 1x64x512 #model.add(Pooling(1,2,stride=2,stride_horizontal=1, stride_vertical=2,)) # size = 1x64x512 model.add(Conv2d(512,3,3,stride=1,padding=1, act='IDENTITY')) # size = 1x64x512 model.add(BN(act='RELU')) model.add(Reshape(order='DWH',width=64, height=512, depth=1)) model.add(Recurrent(512,output_type='SAMELENGTH')) model.add(OutputLayer(error='CTC')) model.print_summary()
def initial_block(inp): ''' Defines the initial block of ENet Parameters ---------- inp : class:`InputLayer` Input layer Returns ------- :class:`Concat` ''' x = Conv2d(13, 3, stride=2, padding=1, act='identity', include_bias=False)(inp) x_bn = BN(act='relu')(x) y = Pooling(2)(inp) merge = Concat()([x_bn, y]) return merge
def test_bn_layer2(self): if not __dev__: with self.assertRaises(DLPyError): BN(not_a_parameter=1)
def test_bn_layer1(self): dict1 = BN(name='bn', src_layers=[Conv2d(name='conv', n_filters=32)]).to_model_params() self.assertTrue(self.sample_syntax['bn1'] == dict1)
def VGG13(conn, model_table='VGG13', n_classes=1000, n_channels=3, width=224, height=224, scale=1, random_flip=None, random_crop=None, offsets=(103.939, 116.779, 123.68), random_mutation=None): ''' Generates a deep learning model with the VGG13 architecture. Parameters ---------- conn : CAS Specifies the CAS connection object. model_table : string, optional Specifies the name of CAS table to store the model. n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: 1000 n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3 width : int, optional Specifies the width of the input layer. Default: 224 height : int, optional Specifies the height of the input layer. Default: 224 scale : double, optional Specifies a scaling factor to be applied to each pixel intensity values. Default: 1 random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' offsets : double or iter-of-doubles, optional Specifies an offset for each channel in the input data. The final input data is set after applying scaling and subtracting the specified offsets. Default: (103.939, 116.779, 123.68) random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' Returns ------- :class:`Sequential` References ---------- https://arxiv.org/pdf/1409.1556.pdf ''' conn.retrieve('loadactionset', _messagelevel='error', actionset='deeplearn') # get all the parms passed in parameters = locals() model = Sequential(conn=conn, model_table=model_table) # get the input parameters input_parameters = get_layer_options(input_layer_options, parameters) model.add(InputLayer(**input_parameters)) model.add( Conv2d(n_filters=64, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=64, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add( Conv2d(n_filters=128, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=128, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add( Conv2d(n_filters=256, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=256, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add( Conv2d(n_filters=512, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=512, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add( Conv2d(n_filters=512, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=512, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add(Dense(n=4096, dropout=0.5)) model.add(Dense(n=4096, dropout=0.5)) model.add(OutputLayer(n=n_classes)) return model
def EfficientNet(conn, model_table='EfficientNet', n_classes=100, n_channels=3, width=224, height=224, width_coefficient=1, depth_coefficient=1, dropout_rate=0.2, drop_connect_rate=0, depth_divisor=8, activation_fn='relu', blocks_args=_MBConv_BLOCKS_ARGS, offsets=(255*0.406, 255*0.456, 255*0.485), norm_stds=(255*0.225, 255*0.224, 255*0.229), random_flip=None, random_crop=None, random_mutation=None): ''' Generates a deep learning model with the EfficientNet architecture. The implementation is revised based on https://github.com/keras-team/keras-applications/blob/master/keras_applications/efficientnet.py Parameters ---------- conn : CAS Specifies the CAS connection object. model_table : string or dict or CAS table, optional Specifies the CAS table to store the deep learning model. n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: 1000 n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3 width : int, optional Specifies the width of the input layer. Default: 224 height : int, optional Specifies the height of the input layer. Default: 224 width_coefficient: double, optional Specifies the scale coefficient for network width. Default: 1.0 depth_coefficient: double, optional Specifies the scale coefficient for network depth. Default: 1.0 dropout_rate: double, optional Specifies the dropout rate before final classifier layer. Default: 0.2 drop_connect_rate: double, optional Specifies the dropout rate at skip connections. Default: 0.0 depth_divisor: integer, optional Specifies the unit of network width. Default: 8 activation_fn: string, optional Specifies the activation function blocks_args: list of dicts Specifies parameters to construct blocks for the efficientnet model. offsets : double or iter-of-doubles, optional Specifies an offset for each channel in the input data. The final input data is set after applying scaling and subtracting the specified offsets. Default: (255*0.406, 255*0.456, 255*0.485) norm_stds : double or iter-of-doubles, optional Specifies a standard deviation for each channel in the input data. The final input data is normalized with specified means and standard deviations. Default: (255*0.225, 255*0.224, 255*0.229) random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' Returns ------- :class:`Model` References ---------- https://arxiv.org/pdf/1905.11946.pdf ''' def round_filters(filters, width_coefficient, depth_divisor): ''' round the number of the scaled width, which is for width scaling in efficientnet. Parameters ---------- filters: integer Specifies the number of filters. width_coefficient: double Specifies the scale coefficient for network width. depth_divisor: integer Specifies the unit of network width. ''' filters *= width_coefficient new_filters = int(filters + depth_divisor / 2) // depth_divisor * depth_divisor new_filters = max(depth_divisor, new_filters) # Make sure that round down does not go down by more than 10%. if new_filters < 0.9 * filters: new_filters += depth_divisor return int(new_filters) def round_repeats(repeats, depth_coefficient): ''' round the number of the scaled depth, which is for depth scaling in effcientnet. Parameters ---------- repeats: integer Specifies the number of repeats for a block. depth_coefficient: double Specifies the scale coefficient for a block. ''' return int(math.ceil(depth_coefficient * repeats)) def _MBConvBlock(inputs, in_channels, out_channels, ksize, stride, expansion, se_ratio, stage_id, block_id, noskip=False, activation_fn='relu'): ''' Inverted Residual Block Parameters ---------- inputs: input tensor Speecify input tensor for block. in_channels: integer Specifies the number of input tensor's channel. out_channels: integer Specifies the number of output tensor's channel ksize: Specifies the kernel size of the convolution stride: integer Specifies the stride of the convolution expansion: double Specifies the expansion factor for the input layer. se_ratio: double Specifies the ratio to squeeze the input filters for squeeze-and-excitation block. stage_id: integer Specifies stage id for naming layers block_id: Specifies block id for naming layers noskip: bool Specifies whether the skip connection is used. By default, the skip connection is used. activation_fn: Specifies activation function ''' # mobilenetv2 block is also known as inverted residual block, which consists of three convolutions: # the first is 1*1 convolution for expansion # the second is depthwise convolution # the third is 1*1 convolution without any non-linearity for projection x = inputs prefix = 'stage_{}_block_{}'.format(stage_id, block_id) n_groups = in_channels # for expansion=1, n_groups might be different from pointwise_filters if expansion > 1: # For MobileNet V2, expansion>1 when stage>0 n_groups = int(expansion * in_channels) ## update n_groups x = Conv2d(n_groups, 1, include_bias=False, act='identity', name=prefix + 'expand')(x) x = BN(name=prefix + 'expand_BN', act='identity')(x) # Depthwise convolution x = GroupConv2d(n_groups, n_groups, ksize, stride=stride, act='identity', include_bias=False, name=prefix + 'depthwise')(x) x = BN(name=prefix + 'depthwise_BN', act=activation_fn)(x) # Squeeze-Excitation if 0 < se_ratio <= 1: se_input = x # features to be squeezed x = GlobalAveragePooling2D(name=prefix + "global_avg_pool")(x) # Squeeze channels_se = max(1, int(in_channels * se_ratio)) x = Conv2d(channels_se, 1, include_bias=True, act=activation_fn, name=prefix + 'squeeze')(x) x = Conv2d(n_groups, 1, include_bias=True, act='sigmoid', name=prefix + 'excitation')(x) x = Reshape(name=prefix + 'reshape', width=n_groups, height=1, depth=1)(x) x = Scale(name=prefix + 'scale')([se_input, x]) # x = out*w # Project x = Conv2d(out_channels, 1, include_bias=False, act='identity', name=prefix + 'project')(x) x = BN(name=prefix + 'project_BN', act='identity')(x) # identity activation on narrow tensor # Prepare output for MBConv block if in_channels == out_channels and stride == 1 and (not noskip): # dropout can be added. return Res(name=prefix + 'add_se_residual')([x, inputs]) else: return x parameters = locals() input_parameters = get_layer_options(input_layer_options, parameters) inp = Input(**input_parameters, name='data') # refer to Table 1 "EfficientNet-B0 baseline network" in paper: # "EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks" stage_id = 0 out_channels = round_filters(32, width_coefficient, depth_divisor) # multiply with width multiplier: width_coefficient x = Conv2d(out_channels, 3, stride=2, include_bias=False, name='Conv1', act='identity')(inp) x = BN(name='bn_Conv1', act=activation_fn)(x) # Create stages with MBConv blocks from stage 1 in_channels = out_channels # number of input channels for first MBblock stage_id +=1 total_blocks = float(sum(args[2] for args in blocks_args)) for expansion, out_channels, num_blocks, ksize, stride, se_ratio in blocks_args: out_channels = round_filters(out_channels, width_coefficient, depth_divisor) num_blocks = round_repeats(num_blocks, depth_coefficient) strides = [stride] + [1] * (num_blocks - 1) for block_id, stride in enumerate(strides): x = _MBConvBlock(x, in_channels, out_channels, ksize, stride, expansion, se_ratio, stage_id, block_id,activation_fn) in_channels = out_channels # out_channel stage_id += 1 last_block_filters = round_filters(1280, width_coefficient, depth_divisor) x = Conv2d(last_block_filters, 1, include_bias=False, name='Conv_top', act='identity')(x) x = BN(name='Conv_top_bn', act=activation_fn)(x) x = GlobalAveragePooling2D(name="Global_avg_pool", dropout=dropout_rate)(x) x = OutputLayer(n=n_classes)(x) model = Model(conn, inp, x, model_table) model.compile() return model
def _MBConvBlock(inputs, in_channels, out_channels, ksize, stride, expansion, se_ratio, stage_id, block_id, noskip=False, activation_fn='relu'): ''' Inverted Residual Block Parameters ---------- inputs: input tensor Speecify input tensor for block. in_channels: integer Specifies the number of input tensor's channel. out_channels: integer Specifies the number of output tensor's channel ksize: Specifies the kernel size of the convolution stride: integer Specifies the stride of the convolution expansion: double Specifies the expansion factor for the input layer. se_ratio: double Specifies the ratio to squeeze the input filters for squeeze-and-excitation block. stage_id: integer Specifies stage id for naming layers block_id: Specifies block id for naming layers noskip: bool Specifies whether the skip connection is used. By default, the skip connection is used. activation_fn: Specifies activation function ''' # mobilenetv2 block is also known as inverted residual block, which consists of three convolutions: # the first is 1*1 convolution for expansion # the second is depthwise convolution # the third is 1*1 convolution without any non-linearity for projection x = inputs prefix = 'stage_{}_block_{}'.format(stage_id, block_id) n_groups = in_channels # for expansion=1, n_groups might be different from pointwise_filters if expansion > 1: # For MobileNet V2, expansion>1 when stage>0 n_groups = int(expansion * in_channels) ## update n_groups x = Conv2d(n_groups, 1, include_bias=False, act='identity', name=prefix + 'expand')(x) x = BN(name=prefix + 'expand_BN', act='identity')(x) # Depthwise convolution x = GroupConv2d(n_groups, n_groups, ksize, stride=stride, act='identity', include_bias=False, name=prefix + 'depthwise')(x) x = BN(name=prefix + 'depthwise_BN', act=activation_fn)(x) # Squeeze-Excitation if 0 < se_ratio <= 1: se_input = x # features to be squeezed x = GlobalAveragePooling2D(name=prefix + "global_avg_pool")(x) # Squeeze channels_se = max(1, int(in_channels * se_ratio)) x = Conv2d(channels_se, 1, include_bias=True, act=activation_fn, name=prefix + 'squeeze')(x) x = Conv2d(n_groups, 1, include_bias=True, act='sigmoid', name=prefix + 'excitation')(x) x = Reshape(name=prefix + 'reshape', width=n_groups, height=1, depth=1)(x) x = Scale(name=prefix + 'scale')([se_input, x]) # x = out*w # Project x = Conv2d(out_channels, 1, include_bias=False, act='identity', name=prefix + 'project')(x) x = BN(name=prefix + 'project_BN', act='identity')(x) # identity activation on narrow tensor # Prepare output for MBConv block if in_channels == out_channels and stride == 1 and (not noskip): # dropout can be added. return Res(name=prefix + 'add_se_residual')([x, inputs]) else: return x
def UNet(conn, model_table='UNet', n_classes=2, n_channels=1, width=256, height=256, scale=1.0 / 255, norm_stds=None, offsets=None, random_mutation=None, init=None, bn_after_convolutions=False, random_flip=None, random_crop=None): ''' Generates a deep learning model with the U-Net architecture. Parameters ---------- conn : CAS Specifies the connection of the CAS connection. model_table : string, optional Specifies the name of CAS table to store the model. n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: 2 n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3 width : int, optional Specifies the width of the input layer. Default: 256 height : int, optional Specifies the height of the input layer. Default: 256 scale : double, optional Specifies a scaling factor to be applied to each pixel intensity values. Default: 1.0/255 norm_stds : double or iter-of-doubles, optional Specifies a standard deviation for each channel in the input data. The final input data is normalized with specified means and standard deviations. offsets : double or iter-of-doubles, optional Specifies an offset for each channel in the input data. The final input data is set after applying scaling and subtracting the specified offsets. random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' init : str Specifies the initialization scheme for convolution layers. Valid Values: XAVIER, UNIFORM, NORMAL, CAUCHY, XAVIER1, XAVIER2, MSRA, MSRA1, MSRA2 Default: None bn_after_convolutions : Boolean If set to True, a batch normalization layer is added after each convolution layer. random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' Returns ------- :class:`Sequential` References ---------- https://arxiv.org/pdf/1505.04597 ''' parameters = locals() input_parameters = get_layer_options(input_layer_options, parameters) inp = Input(**input_parameters, name='data') act_conv = 'relu' bias_conv = True if bn_after_convolutions: act_conv = 'identity' bias_conv = False # The model follows UNet paper architecture. The network down-samples by performing max pooling with stride=2 conv1 = Conv2d(64, 3, act=act_conv, init=init, include_bias=bias_conv)(inp) conv1 = BN(act='relu')(conv1) if bn_after_convolutions else conv1 conv1 = Conv2d(64, 3, act=act_conv, init=init, include_bias=bias_conv)(conv1) conv1 = BN(act='relu')(conv1) if bn_after_convolutions else conv1 pool1 = Pooling(2)(conv1) conv2 = Conv2d(128, 3, act=act_conv, init=init, include_bias=bias_conv)(pool1) conv2 = BN(act='relu')(conv2) if bn_after_convolutions else conv2 conv2 = Conv2d(128, 3, act=act_conv, init=init, include_bias=bias_conv)(conv2) conv2 = BN(act='relu')(conv2) if bn_after_convolutions else conv2 pool2 = Pooling(2)(conv2) conv3 = Conv2d(256, 3, act=act_conv, init=init, include_bias=bias_conv)(pool2) conv3 = BN(act='relu')(conv3) if bn_after_convolutions else conv3 conv3 = Conv2d(256, 3, act=act_conv, init=init, include_bias=bias_conv)(conv3) conv3 = BN(act='relu')(conv3) if bn_after_convolutions else conv3 pool3 = Pooling(2)(conv3) conv4 = Conv2d(512, 3, act=act_conv, init=init, include_bias=bias_conv)(pool3) conv4 = BN(act='relu')(conv4) if bn_after_convolutions else conv4 conv4 = Conv2d(512, 3, act=act_conv, init=init, include_bias=bias_conv)(conv4) conv4 = BN(act='relu')(conv4) if bn_after_convolutions else conv4 pool4 = Pooling(2)(conv4) conv5 = Conv2d(1024, 3, act=act_conv, init=init, include_bias=bias_conv)(pool4) conv5 = BN(act='relu')(conv5) if bn_after_convolutions else conv5 conv5 = Conv2d(1024, 3, act=act_conv, init=init, include_bias=bias_conv)(conv5) conv5 = BN(act='relu')(conv5) if bn_after_convolutions else conv5 # the minimum is 1/2^4 of the original image size # Our implementation applies Transpose convolution to upsample feature maps. tconv6 = Conv2DTranspose(512, 3, stride=2, act='relu', padding=1, output_size=conv4.shape, init=init)(conv5) # 64 # concatenation layers to combine encoder and decoder features merge6 = Concat()([conv4, tconv6]) conv6 = Conv2d(512, 3, act=act_conv, init=init, include_bias=bias_conv)(merge6) conv6 = BN(act='relu')(conv6) if bn_after_convolutions else conv6 conv6 = Conv2d(512, 3, act=act_conv, init=init, include_bias=bias_conv)(conv6) conv6 = BN(act='relu')(conv6) if bn_after_convolutions else conv6 tconv7 = Conv2DTranspose(256, 3, stride=2, act='relu', padding=1, output_size=conv3.shape, init=init)(conv6) # 128 merge7 = Concat()([conv3, tconv7]) conv7 = Conv2d(256, 3, act=act_conv, init=init, include_bias=bias_conv)(merge7) conv7 = BN(act='relu')(conv7) if bn_after_convolutions else conv7 conv7 = Conv2d(256, 3, act=act_conv, init=init, include_bias=bias_conv)(conv7) conv7 = BN(act='relu')(conv7) if bn_after_convolutions else conv7 tconv8 = Conv2DTranspose(128, stride=2, act='relu', padding=1, output_size=conv2.shape, init=init)(conv7) # 256 merge8 = Concat()([conv2, tconv8]) conv8 = Conv2d(128, 3, act=act_conv, init=init, include_bias=bias_conv)(merge8) conv8 = BN(act='relu')(conv8) if bn_after_convolutions else conv8 conv8 = Conv2d(128, 3, act=act_conv, init=init, include_bias=bias_conv)(conv8) conv8 = BN(act='relu')(conv8) if bn_after_convolutions else conv8 tconv9 = Conv2DTranspose(64, stride=2, act='relu', padding=1, output_size=conv1.shape, init=init)(conv8) # 512 merge9 = Concat()([conv1, tconv9]) conv9 = Conv2d(64, 3, act=act_conv, init=init, include_bias=bias_conv)(merge9) conv9 = BN(act='relu')(conv9) if bn_after_convolutions else conv9 conv9 = Conv2d(64, 3, act=act_conv, init=init, include_bias=bias_conv)(conv9) conv9 = BN(act='relu')(conv9) if bn_after_convolutions else conv9 conv9 = Conv2d(n_classes, 3, act='relu', init=init)(conv9) seg1 = Segmentation(name='Segmentation_1')(conv9) model = Model(conn, inputs=inp, outputs=seg1, model_table=model_table) model.compile() return model
def MobileNetV2(conn, model_table='MobileNetV2', n_classes=1000, n_channels=3, width=224, height=224, norm_stds=(255 * 0.229, 255 * 0.224, 255 * 0.225), offsets=(255 * 0.485, 255 * 0.456, 255 * 0.406), random_flip=None, random_crop=None, random_mutation=None, alpha=1): ''' Generates a deep learning model with the MobileNetV2 architecture. The implementation is revised based on https://github.com/keras-team/keras-applications/blob/master/keras_applications/mobilenet_v2.py Parameters ---------- conn : CAS Specifies the CAS connection object. model_table : string or dict or CAS table, optional Specifies the CAS table to store the deep learning model. n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: 1000 n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3 width : int, optional Specifies the width of the input layer. Default: 224 height : int, optional Specifies the height of the input layer. Default: 224 norm_stds : double or iter-of-doubles, optional Specifies a standard deviation for each channel in the input data. The final input data is normalized with specified means and standard deviations. Default: (255 * 0.229, 255 * 0.224, 255 * 0.225) offsets : double or iter-of-doubles, optional Specifies an offset for each channel in the input data. The final input data is set after applying scaling and subtracting the specified offsets. Default: (255*0.485, 255*0.456, 255*0.406) random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' alpha : int, optional Specifies the width multiplier in the MobileNet paper Default: 1 alpha : int, optional Returns ------- :class:`Model` References ---------- https://arxiv.org/abs/1801.04381 ''' def _make_divisible(v, divisor, min_value=None): # make number of channel divisible if min_value is None: min_value = divisor new_v = max(min_value, int(v + divisor / 2) // divisor * divisor) # Make sure that round down does not go down by more than 10%. if new_v < 0.9 * v: new_v += divisor return new_v def _inverted_res_block(inputs, in_channels, expansion, stride, alpha, filters, block_id): """ Inverted Residual Block Parameters ---------- inputs: Input tensor in_channels: Specifies the number of input tensor's channel expansion: expansion factor always applied to the input size. stride: the strides of the convolution alpha: width multiplier. filters: the dimensionality of the output space. block_id: block id used for naming layers """ pointwise_conv_filters = int(filters * alpha) pointwise_filters = _make_divisible(pointwise_conv_filters, 8) x = inputs prefix = 'block_{}_'.format(block_id) n_groups = in_channels if block_id: # Expand n_groups = expansion * in_channels x = Conv2d(expansion * in_channels, 1, include_bias=False, act='identity', name=prefix + 'expand')(x) x = BN(name=prefix + 'expand_BN', act='identity')(x) else: prefix = 'expanded_conv_' # Depthwise x = GroupConv2d(n_groups, n_groups, 3, stride=stride, act='identity', include_bias=False, name=prefix + 'depthwise')(x) x = BN(name=prefix + 'depthwise_BN', act='relu')(x) # Project x = Conv2d(pointwise_filters, 1, include_bias=False, act='identity', name=prefix + 'project')(x) x = BN(name=prefix + 'project_BN', act='identity')(x) # identity activation on narrow tensor if in_channels == pointwise_filters and stride == 1: return Res(name=prefix + 'add')([inputs, x]), pointwise_filters return x, pointwise_filters parameters = locals() input_parameters = get_layer_options(input_layer_options, parameters) inp = Input(**input_parameters, name='data') # compared with mobilenetv1, v2 introduces inverted residual structure. # and Non-linearities in narrow layers are removed. # inverted residual block does three convolutins: first is 1*1 convolution, second is depthwise convolution, # third is 1*1 convolution but without any non-linearity first_block_filters = _make_divisible(32 * alpha, 8) x = Conv2d(first_block_filters, 3, stride=2, include_bias=False, name='Conv1', act='identity')(inp) x = BN(name='bn_Conv1', act='relu')(x) x, n_channels = _inverted_res_block(x, first_block_filters, filters=16, alpha=alpha, stride=1, expansion=1, block_id=0) x, n_channels = _inverted_res_block(x, n_channels, filters=24, alpha=alpha, stride=2, expansion=6, block_id=1) x, n_channels = _inverted_res_block(x, n_channels, filters=24, alpha=alpha, stride=1, expansion=6, block_id=2) x, n_channels = _inverted_res_block(x, n_channels, filters=32, alpha=alpha, stride=2, expansion=6, block_id=3) x, n_channels = _inverted_res_block(x, n_channels, filters=32, alpha=alpha, stride=1, expansion=6, block_id=4) x, n_channels = _inverted_res_block(x, n_channels, filters=32, alpha=alpha, stride=1, expansion=6, block_id=5) x, n_channels = _inverted_res_block(x, n_channels, filters=64, alpha=alpha, stride=2, expansion=6, block_id=6) x, n_channels = _inverted_res_block(x, n_channels, filters=64, alpha=alpha, stride=1, expansion=6, block_id=7) x, n_channels = _inverted_res_block(x, n_channels, filters=64, alpha=alpha, stride=1, expansion=6, block_id=8) x, n_channels = _inverted_res_block(x, n_channels, filters=64, alpha=alpha, stride=1, expansion=6, block_id=9) x, n_channels = _inverted_res_block(x, n_channels, filters=96, alpha=alpha, stride=1, expansion=6, block_id=10) x, n_channels = _inverted_res_block(x, n_channels, filters=96, alpha=alpha, stride=1, expansion=6, block_id=11) x, n_channels = _inverted_res_block(x, n_channels, filters=96, alpha=alpha, stride=1, expansion=6, block_id=12) x, n_channels = _inverted_res_block(x, n_channels, filters=160, alpha=alpha, stride=2, expansion=6, block_id=13) x, n_channels = _inverted_res_block(x, n_channels, filters=160, alpha=alpha, stride=1, expansion=6, block_id=14) x, n_channels = _inverted_res_block(x, n_channels, filters=160, alpha=alpha, stride=1, expansion=6, block_id=15) x, n_channels = _inverted_res_block(x, n_channels, filters=320, alpha=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 alpha > 1.0: last_block_filters = _make_divisible(1280 * alpha, 8) else: last_block_filters = 1280 x = Conv2d(last_block_filters, 1, include_bias=False, name='Conv_1', act='identity')(x) x = BN(name='Conv_1_bn', act='relu')(x) x = GlobalAveragePooling2D(name="Global_avg_pool")(x) x = OutputLayer(n=n_classes)(x) model = Model(conn, inp, x, model_table) model.compile() return model
def DenseNet(conn, model_table='DenseNet', n_classes=None, conv_channel=16, growth_rate=12, n_blocks=4, n_cells=4, n_channels=3, width=32, height=32, scale=1, random_flip=None, random_crop=None, offsets=(85, 111, 139), random_mutation=None): ''' Generates a deep learning model with the DenseNet architecture. Parameters ---------- conn : CAS Specifies the connection of the CAS connection. model_table : string Specifies the name of CAS table to store the model. n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: None conv_channel : int, optional Specifies the number of filters of the first convolution layer. Default: 16 growth_rate : int, optional Specifies the growth rate of convolution layers. Default: 12 n_blocks : int, optional Specifies the number of DenseNet blocks. Default: 4 n_cells : int, optional Specifies the number of dense connection for each DenseNet block. Default: 4 n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3 width : int, optional Specifies the width of the input layer. Default: 32 height : int, optional Specifies the height of the input layer. Default: 32 scale : double, optional Specifies a scaling factor to be applied to each pixel intensity values. Default: 1 random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' offsets : double or iter-of-doubles, optional Specifies an offset for each channel in the input data. The final input data is set after applying scaling and subtracting the specified offsets. Default: (85, 111, 139) random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' Returns ------- :class:`Sequential` References ---------- https://arxiv.org/pdf/1608.06993.pdf ''' conn.retrieve('loadactionset', _messagelevel='error', actionset='deeplearn') # get all the parms passed in parameters = locals() channel_in = conv_channel # number of channel of transition conv layer model = Sequential(conn=conn, model_table=model_table) # get the input parameters input_parameters = get_layer_options(input_layer_options, parameters) model.add(InputLayer(**input_parameters)) # Top layers model.add( Conv2d(conv_channel, width=3, act='identity', include_bias=False, stride=1)) for i in range(n_blocks): model.add( DenseNetBlock(n_cells=n_cells, kernel_size=3, n_filter=growth_rate, stride=1)) # transition block channel_in += (growth_rate * n_cells) model.add(BN(act='relu')) if i != (n_blocks - 1): model.add( Conv2d(channel_in, width=3, act='identity', include_bias=False, stride=1)) model.add(Pooling(width=2, height=2, pool='mean')) model.add(GlobalAveragePooling2D()) model.add(OutputLayer(act='softmax', n=n_classes)) return model
def DenseNet121(conn, model_table='DENSENET121', n_classes=1000, conv_channel=64, growth_rate=32, n_cells=[6, 12, 24, 16], n_channels=3, reduction=0.5, width=224, height=224, scale=1, random_flip=None, random_crop=None, offsets=(103.939, 116.779, 123.68), random_mutation=None): ''' Generates a deep learning model with the DenseNet121 architecture. Parameters ---------- conn : CAS Specifies the connection of the CAS connection. model_table : string Specifies the name of CAS table to store the model. n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: 1000 conv_channel : int, optional Specifies the number of filters of the first convolution layer. Default: 64 growth_rate : int, optional Specifies the growth rate of convolution layers. Default: 32 n_cells : int array length=4, optional Specifies the number of dense connection for each DenseNet block. Default: [6, 12, 24, 16] reduction : double, optional Specifies the factor of transition blocks. Default: 0.5 n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3. width : int, optional Specifies the width of the input layer. Default: 224. height : int, optional Specifies the height of the input layer. Default: 224. scale : double, optional Specifies a scaling factor to be applied to each pixel intensity values. Default: 1. random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' offsets : double or iter-of-doubles, optional Specifies an offset for each channel in the input data. The final input data is set after applying scaling and subtracting the specified offsets. Default: (103.939, 116.779, 123.68) random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' Returns ------- :class:`Sequential` References ---------- https://arxiv.org/pdf/1608.06993.pdf ''' conn.retrieve('loadactionset', _messagelevel='error', actionset='deeplearn') # get all the parms passed in parameters = locals() n_blocks = len(n_cells) model = Sequential(conn=conn, model_table=model_table) # get the input parameters input_parameters = get_layer_options(input_layer_options, parameters) model.add(InputLayer(**input_parameters)) # Top layers model.add( Conv2d(conv_channel, width=7, act='identity', include_bias=False, stride=2)) model.add(BN(act='relu')) src_layer = Pooling(width=3, height=3, stride=2, padding=1, pool='max') model.add(src_layer) for i in range(n_blocks): for _ in range(n_cells[i]): model.add(BN(act='relu')) model.add( Conv2d(n_filters=growth_rate * 4, width=1, act='identity', stride=1, include_bias=False)) model.add(BN(act='relu')) src_layer2 = Conv2d(n_filters=growth_rate, width=3, act='identity', stride=1, include_bias=False) model.add(src_layer2) src_layer = Concat(act='identity', src_layers=[src_layer, src_layer2]) model.add(src_layer) conv_channel += growth_rate if i != (n_blocks - 1): # transition block conv_channel = int(conv_channel * reduction) model.add(BN(act='relu')) model.add( Conv2d(n_filters=conv_channel, width=1, act='identity', stride=1, include_bias=False)) src_layer = Pooling(width=2, height=2, stride=2, pool='mean') model.add(src_layer) model.add(BN(act='identity')) # Bottom Layers model.add(GlobalAveragePooling2D()) model.add(OutputLayer(act='softmax', n=n_classes)) return model
def ShuffleNetV1(conn, model_table='ShuffleNetV1', n_classes=1000, n_channels=3, width=224, height=224, norm_stds=(255 * 0.229, 255 * 0.224, 255 * 0.225), offsets=(255 * 0.485, 255 * 0.456, 255 * 0.406), random_flip=None, random_crop=None, random_mutation=None, scale_factor=1.0, num_shuffle_units=[3, 7, 3], bottleneck_ratio=0.25, groups=3, block_act='identity'): ''' Generates a deep learning model with the ShuffleNetV1 architecture. The implementation is revised based on https://github.com/scheckmedia/keras-shufflenet/blob/master/shufflenet.py Parameters ---------- conn : CAS Specifies the CAS connection object. model_table : string or dict or CAS table, optional Specifies the CAS table to store the deep learning model. n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: 1000 n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3 width : int, optional Specifies the width of the input layer. Default: 32 height : int, optional Specifies the height of the input layer. Default: 32 norm_stds : double or iter-of-doubles, optional Specifies a standard deviation for each channel in the input data. The final input data is normalized with specified means and standard deviations. Default: (255 * 0.229, 255 * 0.224, 255 * 0.225) offsets : double or iter-of-doubles, optional Specifies an offset for each channel in the input data. The final input data is set after applying scaling and subtracting the specified offsets. Default: (255*0.485, 255*0.456, 255*0.406) random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' scale_factor : double num_shuffle_units: iter-of-int, optional number of stages (list length) and the number of shufflenet units in a stage beginning with stage 2 because stage 1 is fixed e.g. idx 0 contains 3 + 1 (first shuffle unit in each stage differs) shufflenet units for stage 2 idx 1 contains 7 + 1 Shufflenet Units for stage 3 and idx 2 contains 3 + 1 Shufflenet Units Default: [3, 7, 3] bottleneck_ratio : double bottleneck ratio implies the ratio of bottleneck channels to output channels. For example, bottleneck ratio = 1 : 4 means the output feature map is 4 times the width of the bottleneck feature map. groups: int Specifies the number of groups per channel Default : 3 block_act : str Specifies the activation function after depth-wise convolution and batch normalization layer Default : 'identity' Returns ------- :class:`Model` References ---------- https://arxiv.org/pdf/1707.01083 ''' def _block(x, channel_map, bottleneck_ratio, repeat=1, groups=1, stage=1): """ creates a bottleneck block Parameters ---------- x: Input tensor channel_map: list containing the number of output channels for a stage repeat: number of repetitions for a shuffle unit with stride 1 groups: number of groups per channel bottleneck_ratio: bottleneck ratio implies the ratio of bottleneck channels to output channels. stage: stage number Returns ------- """ x = _shuffle_unit(x, in_channels=channel_map[stage - 2], out_channels=channel_map[stage - 1], strides=2, groups=groups, bottleneck_ratio=bottleneck_ratio, stage=stage, block=1) for i in range(1, repeat + 1): x = _shuffle_unit(x, in_channels=channel_map[stage - 1], out_channels=channel_map[stage - 1], strides=1, groups=groups, bottleneck_ratio=bottleneck_ratio, stage=stage, block=(i + 1)) return x def _shuffle_unit(inputs, in_channels, out_channels, groups, bottleneck_ratio, strides=2, stage=1, block=1): """ create a shuffle unit Parameters ---------- inputs: Input tensor of with `channels_last` data format in_channels: number of input channels out_channels: number of output channels strides: An integer or tuple/list of 2 integers, groups: number of groups per channel bottleneck_ratio: float bottleneck ratio implies the ratio of bottleneck channels to output channels. stage: stage number block: block number """ prefix = 'stage%d/block%d' % (stage, block) # if strides >= 2: # out_channels -= in_channels # default: 1/4 of the output channel of a ShuffleNet Unit bottleneck_channels = int(out_channels * bottleneck_ratio) groups = (1 if stage == 2 and block == 1 else groups) # x = _group_conv(inputs, in_channels, out_channels = bottleneck_channels, # groups = (1 if stage == 2 and block == 1 else groups), # name = '%s/1x1_gconv_1' % prefix) x = GroupConv2d(bottleneck_channels, n_groups=(1 if stage == 2 and block == 1 else groups), act='identity', width=1, height=1, stride=1, include_bias=False, name='%s/1x1_gconv_1' % prefix)(inputs) x = BN(act='relu', name='%s/bn_gconv_1' % prefix)(x) x = ChannelShuffle(n_groups=groups, name='%s/channel_shuffle' % prefix)(x) # depthwise convolutioin x = GroupConv2d(x.shape[-1], n_groups=x.shape[-1], width=3, height=3, include_bias=False, stride=strides, act='identity', name='%s/1x1_dwconv_1' % prefix)(x) x = BN(act=block_act, name='%s/bn_dwconv_1' % prefix)(x) out_channels = out_channels if strides == 1 else out_channels - in_channels x = GroupConv2d(out_channels, n_groups=groups, width=1, height=1, stride=1, act='identity', include_bias=False, name='%s/1x1_gconv_2' % prefix)(x) x = BN(act=block_act, name='%s/bn_gconv_2' % prefix)(x) if strides < 2: ret = Res(act='relu', name='%s/add' % prefix)([x, inputs]) else: avg = Pooling(width=3, height=3, stride=2, pool='mean', name='%s/avg_pool' % prefix)(inputs) ret = Concat(act='relu', name='%s/concat' % prefix)([x, avg]) return ret out_dim_stage_two = {1: 144, 2: 200, 3: 240, 4: 272, 8: 384} try: import numpy as np except: raise DLPyError('Please install numpy to use this architecture.') exp = np.insert(np.arange(0, len(num_shuffle_units), dtype=np.float32), 0, 0) out_channels_in_stage = 2**exp out_channels_in_stage *= out_dim_stage_two[ groups] # calculate output channels for each stage out_channels_in_stage[0] = 24 # first stage has always 24 output channels out_channels_in_stage *= scale_factor out_channels_in_stage = out_channels_in_stage.astype(int) parameters = locals() input_parameters = get_layer_options(input_layer_options, parameters) inp = Input(**input_parameters, name='data') # create shufflenet architecture x = Conv2d(out_channels_in_stage[0], 3, include_bias=False, stride=2, act="identity", name="conv1")(inp) x = BN(act='relu', name='bn1')(x) x = Pooling(width=3, height=3, stride=2, name="maxpool1")(x) # create stages containing shufflenet units beginning at stage 2 for stage in range(0, len(num_shuffle_units)): repeat = num_shuffle_units[stage] x = _block(x, out_channels_in_stage, repeat=repeat, bottleneck_ratio=bottleneck_ratio, groups=groups, stage=stage + 2) x = GlobalAveragePooling2D(name="Global_avg_pool")(x) x = OutputLayer(n=n_classes)(x) model = Model(conn, inputs=inp, outputs=x, model_table=model_table) model.compile() return model
def _shuffle_unit(inputs, in_channels, out_channels, groups, bottleneck_ratio, strides=2, stage=1, block=1): """ create a shuffle unit Parameters ---------- inputs: Input tensor of with `channels_last` data format in_channels: number of input channels out_channels: number of output channels strides: An integer or tuple/list of 2 integers, groups: number of groups per channel bottleneck_ratio: float bottleneck ratio implies the ratio of bottleneck channels to output channels. stage: stage number block: block number """ prefix = 'stage%d/block%d' % (stage, block) # if strides >= 2: # out_channels -= in_channels # default: 1/4 of the output channel of a ShuffleNet Unit bottleneck_channels = int(out_channels * bottleneck_ratio) groups = (1 if stage == 2 and block == 1 else groups) # x = _group_conv(inputs, in_channels, out_channels = bottleneck_channels, # groups = (1 if stage == 2 and block == 1 else groups), # name = '%s/1x1_gconv_1' % prefix) x = GroupConv2d(bottleneck_channels, n_groups=(1 if stage == 2 and block == 1 else groups), act='identity', width=1, height=1, stride=1, include_bias=False, name='%s/1x1_gconv_1' % prefix)(inputs) x = BN(act='relu', name='%s/bn_gconv_1' % prefix)(x) x = ChannelShuffle(n_groups=groups, name='%s/channel_shuffle' % prefix)(x) # depthwise convolutioin x = GroupConv2d(x.shape[-1], n_groups=x.shape[-1], width=3, height=3, include_bias=False, stride=strides, act='identity', name='%s/1x1_dwconv_1' % prefix)(x) x = BN(act=block_act, name='%s/bn_dwconv_1' % prefix)(x) out_channels = out_channels if strides == 1 else out_channels - in_channels x = GroupConv2d(out_channels, n_groups=groups, width=1, height=1, stride=1, act='identity', include_bias=False, name='%s/1x1_gconv_2' % prefix)(x) x = BN(act=block_act, name='%s/bn_gconv_2' % prefix)(x) if strides < 2: ret = Res(act='relu', name='%s/add' % prefix)([x, inputs]) else: avg = Pooling(width=3, height=3, stride=2, pool='mean', name='%s/avg_pool' % prefix)(inputs) ret = Concat(act='relu', name='%s/concat' % prefix)([x, avg]) return ret
def Darknet_Reference(conn, model_table='Darknet_Reference', n_classes=1000, act='leaky', n_channels=3, width=224, height=224, scale=1.0 / 255, random_flip='H', random_crop='UNIQUE', random_mutation=None): ''' Generates a deep learning model with the Darknet_Reference architecture. The head of the model except the last convolutional layer is same as the head of Tiny Yolov2. Darknet Reference is pre-trained model for ImageNet classification. Parameters ---------- conn : CAS Specifies the connection of the CAS connection. model_table : string Specifies the name of CAS table to store the model. n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: 1000 act : string Specifies the type of the activation function for the batch normalization layers and the final convolution layer. Default: 'leaky' n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3. width : int, optional Specifies the width of the input layer. Default: 224. height : int, optional Specifies the height of the input layer. Default: 224. scale : double, optional Specifies a scaling factor to be applied to each pixel intensity values. Default: 1.0 / 255 random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' Default: 'h' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' Default: 'unique' random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' Returns ------- :class:`Sequential` ''' conn.retrieve('loadactionset', _messagelevel='error', actionset='deeplearn') # get all the parms passed in parameters = locals() model = Sequential(conn=conn, model_table=model_table) # get the input parameters input_parameters = get_layer_options(input_layer_options, parameters) model.add(InputLayer(**input_parameters)) # conv1 224 model.add(Conv2d(16, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv2 112 model.add(Conv2d(32, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv3 56 model.add(Conv2d(64, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv4 28 model.add( Conv2d(128, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv5 14 model.add( Conv2d(256, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv6 7 model.add( Conv2d(512, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=1, pool='max')) # conv7 7 model.add( Conv2d(1024, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) # conv8 7 model.add(Conv2d(1000, width=1, act=act, include_bias=True, stride=1)) model.add(GlobalAveragePooling2D()) model.add(OutputLayer(act='softmax', n=n_classes)) return model
def test_model4(self): try: import onnx from onnx import numpy_helper except: unittest.TestCase.skipTest(self, "onnx not found in the libraries") import numpy as np model1 = Sequential(self.s, model_table='Simple_CNN1') model1.add(InputLayer(3, 224, 224)) model1.add(Conv2d(8, 7, act='identity', include_bias=False)) model1.add(Reshape(height=448, width=448, depth=2, act='IDENTITY')) model1.add(Reshape(height=448, width=448, depth=2, act='RECTIFIER')) model1.add(Conv2d(8, 7, act='identity', include_bias=False)) model1.add(BN(act='relu')) model1.add(Dense(2)) model1.add(OutputLayer(act='softmax', n=2)) if self.data_dir is None: unittest.TestCase.skipTest( self, "DLPY_DATA_DIR is not set in the environment variables") caslib, path, tmp_caslib = caslibify(self.s, path=self.data_dir + 'images.sashdat', task='load') self.s.table.loadtable(caslib=caslib, casout={ 'name': 'eee', 'replace': True }, path=path) r = model1.fit(data='eee', inputs='_image_', target='_label_', max_epochs=1) self.assertTrue(r.severity == 0) if self.data_dir_local is None: unittest.TestCase.skipTest( self, "DLPY_DATA_DIR_LOCAL is not set in the environment variables") #model1.deploy(self.data_dir_local, output_format='onnx') import tempfile tmp_dir_to_dump = tempfile.gettempdir() model1.deploy(tmp_dir_to_dump, output_format='onnx') import os model_path = os.path.join(tmp_dir_to_dump, 'Simple_CNN1.onnx') m = onnx.load(model_path) self.assertEqual(m.graph.node[1].op_type, 'Reshape') init = numpy_helper.to_array(m.graph.initializer[1]) self.assertTrue(np.array_equal(init, [-1, 2, 448, 448])) import os os.remove(os.path.join(tmp_dir_to_dump, "Simple_CNN1.onnx")) if (caslib is not None) and tmp_caslib: self.s.retrieve('table.dropcaslib', message_level='error', caslib=caslib)
def test_stride(self): model = Sequential(self.s, model_table = 'Simple_CNN_3classes_cropped') model.add(InputLayer(1, width = 36, height = 144, #offsets = myimage.channel_means, name = 'input1', random_mutation = 'random', random_flip = 'HV')) model.add(Conv2d(64, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(64, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(64, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Pooling(height = 2, width = 2, stride_vertical = 2, stride_horizontal = 1, pool = 'max')) # 72, 36 model.add(Conv2d(128, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(128, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(128, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Pooling(height = 2, width = 2, stride_vertical = 2, stride_horizontal = 1, pool = 'max')) # 36*36 model.add(Conv2d(256, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(256, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(256, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Pooling(2, pool = 'max')) # 18 * 18 model.add(Conv2d(512, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(512, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(512, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Pooling(2, pool = 'max')) # 9 * 9 model.add(Conv2d(1024, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(1024, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Conv2d(1024, 3, 3, include_bias = False, act = 'identity')) model.add(BN(act = 'relu')) model.add(Pooling(9)) model.add(Dense(256, dropout = 0.5)) model.add(OutputLayer(act = 'softmax', n = 3, name = 'output1')) self.assertEqual(model.summary['Output Size'].values[-3], (1, 1, 1024)) model.print_summary() # 2d print summary numerical check self.assertEqual(model.summary.iloc[1, -1], 2985984)
def Tiny_YoloV2(conn, anchors, model_table='Tiny-Yolov2', n_channels=3, width=416, height=416, scale=1.0 / 255, random_mutation=None, act='leaky', act_detection='AUTO', softmax_for_class_prob=True, coord_type='YOLO', max_label_per_image=30, max_boxes=30, n_classes=20, predictions_per_grid=5, do_sqrt=True, grid_number=13, coord_scale=None, object_scale=None, prediction_not_a_object_scale=None, class_scale=None, detection_threshold=None, iou_threshold=None, random_boxes=False, match_anchor_size=None, num_to_force_coord=None, random_flip=None, random_crop=None): ''' Generate a deep learning model with the Tiny Yolov2 architecture. Tiny Yolov2 is a very small model of Yolov2, so that it includes fewer numbers of convolutional layer and batch normalization layer. Parameters ---------- conn : CAS Specifies the connection of the CAS connection. anchors : list Specifies the anchor box values. model_table : string, optional Specifies the name of CAS table to store the model. n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3 width : int, optional Specifies the width of the input layer. Default: 416 height : int, optional Specifies the height of the input layer. Default: 416 scale : double, optional Specifies a scaling factor to be applied to each pixel intensity values. Default: 1.0 / 255 random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' act : string, optional Specifies the activation function for the batch normalization layers. Default: 'leaky' act_detection : string, optional Specifies the activation function for the detection layer. Valid Values: AUTO, IDENTITY, LOGISTIC, SIGMOID, TANH, RECTIFIER, RELU, SOFPLUS, ELU, LEAKY, FCMP Default: AUTO softmax_for_class_prob : bool, optional Specifies whether to perform Softmax on class probability per predicted object. Default: True coord_type : string, optional Specifies the format of how to represent bounding boxes. For example, a bounding box can be represented with the x and y locations of the top-left point as well as width and height of the rectangle. This format is the 'rect' format. We also support coco and yolo formats. Valid Values: 'rect', 'yolo', 'coco' Default: 'yolo' max_label_per_image : int, optional Specifies the maximum number of labels per image in the training. Default: 30 max_boxes : int, optional Specifies the maximum number of overall predictions allowed in the detection layer. Default: 30 n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: 20 predictions_per_grid : int, optional Specifies the amount of predictions will be done per grid. Default: 5 do_sqrt : bool, optional Specifies whether to apply the SQRT function to width and height of the object for the cost function. Default: True grid_number : int, optional Specifies the amount of cells to be analyzed for an image. For example, if the value is 5, then the image will be divided into a 5 x 5 grid. Default: 13 coord_scale : float, optional Specifies the weight for the cost function in the detection layer, when objects exist in the grid. object_scale : float, optional Specifies the weight for object detected for the cost function in the detection layer. prediction_not_a_object_scale : float, optional Specifies the weight for the cost function in the detection layer, when objects do not exist in the grid. class_scale : float, optional Specifies the weight for the class of object detected for the cost function in the detection layer. detection_threshold : float, optional Specifies the threshold for object detection. iou_threshold : float, optional Specifies the IOU Threshold of maximum suppression in object detection. random_boxes : bool, optional Randomizing boxes when loading the bounding box information. Default: False match_anchor_size : bool, optional Whether to force the predicted box match the anchor boxes in sizes for all predictions num_to_force_coord : int, optional The number of leading chunk of images in training when the algorithm forces predicted objects in each grid to be equal to the anchor box sizes, and located at the grid center random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' Returns ------- :class:`Sequential` References ---------- https://arxiv.org/pdf/1612.08242.pdf ''' model = Sequential(conn=conn, model_table=model_table) parameters = locals() input_parameters = get_layer_options(input_layer_options, parameters) model.add(InputLayer(**input_parameters)) # conv1 416 448 model.add( Conv2d(n_filters=16, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv2 208 224 model.add( Conv2d(n_filters=32, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv3 104 112 model.add( Conv2d(n_filters=64, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv4 52 56 model.add( Conv2d(n_filters=128, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv5 26 28 model.add( Conv2d(n_filters=256, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) # conv6 13 14 model.add( Conv2d(n_filters=512, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add(Pooling(width=2, height=2, stride=1, pool='max')) # conv7 13 model.add( Conv2d(n_filters=1024, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) # conv8 13 model.add( Conv2d(n_filters=512, width=3, act='identity', include_bias=False, stride=1)) model.add(BN(act=act)) model.add( Conv2d((n_classes + 5) * predictions_per_grid, width=1, act='identity', include_bias=False, stride=1)) model.add( Detection(act=act_detection, detection_model_type='yolov2', anchors=anchors, softmax_for_class_prob=softmax_for_class_prob, coord_type=coord_type, class_number=n_classes, grid_number=grid_number, predictions_per_grid=predictions_per_grid, do_sqrt=do_sqrt, coord_scale=coord_scale, object_scale=object_scale, prediction_not_a_object_scale=prediction_not_a_object_scale, class_scale=class_scale, detection_threshold=detection_threshold, iou_threshold=iou_threshold, random_boxes=random_boxes, max_label_per_image=max_label_per_image, max_boxes=max_boxes, match_anchor_size=match_anchor_size, num_to_force_coord=num_to_force_coord)) return model
def _inverted_res_block(inputs, in_channels, expansion, stride, alpha, filters, block_id): """ Inverted Residual Block Parameters ---------- inputs: Input tensor in_channels: Specifies the number of input tensor's channel expansion: expansion factor always applied to the input size. stride: the strides of the convolution alpha: width multiplier. filters: the dimensionality of the output space. block_id: block id used for naming layers """ pointwise_conv_filters = int(filters * alpha) pointwise_filters = _make_divisible(pointwise_conv_filters, 8) x = inputs prefix = 'block_{}_'.format(block_id) n_groups = in_channels if block_id: # Expand n_groups = expansion * in_channels x = Conv2d(expansion * in_channels, 1, include_bias=False, act='identity', name=prefix + 'expand')(x) x = BN(name=prefix + 'expand_BN', act='identity')(x) else: prefix = 'expanded_conv_' # Depthwise x = GroupConv2d(n_groups, n_groups, 3, stride=stride, act='identity', include_bias=False, name=prefix + 'depthwise')(x) x = BN(name=prefix + 'depthwise_BN', act='relu')(x) # Project x = Conv2d(pointwise_filters, 1, include_bias=False, act='identity', name=prefix + 'project')(x) x = BN(name=prefix + 'project_BN', act='identity')(x) # identity activation on narrow tensor if in_channels == pointwise_filters and stride == 1: return Res(name=prefix + 'add')([inputs, x]), pointwise_filters return x, pointwise_filters
def InceptionV3(conn, model_table='InceptionV3', n_classes=1000, n_channels=3, width=299, height=299, scale=1, random_flip=None, random_crop=None, offsets=(103.939, 116.779, 123.68), pre_trained_weights=False, pre_trained_weights_file=None, include_top=False, random_mutation=None): ''' Generates a deep learning model with the Inceptionv3 architecture with batch normalization layers. Parameters ---------- conn : CAS Specifies the CAS connection object. model_table : string, optional Specifies the name of CAS table to store the model in. n_classes : int, optional Specifies the number of classes. If None is assigned, the model will automatically detect the number of classes based on the training set. Default: 1000 n_channels : int, optional Specifies the number of the channels (i.e., depth) of the input layer. Default: 3 width : int, optional Specifies the width of the input layer. Default: 299 height : int, optional Specifies the height of the input layer. Default: 299 scale : double, optional Specifies a scaling factor to be applied to each pixel intensity values. Default: 1.0 random_flip : string, optional Specifies how to flip the data in the input layer when image data is used. Approximately half of the input data is subject to flipping. Valid Values: 'h', 'hv', 'v', 'none' random_crop : string, optional Specifies how to crop the data in the input layer when image data is used. Images are cropped to the values that are specified in the width and height parameters. Only the images with one or both dimensions that are larger than those sizes are cropped. Valid Values: 'none', 'unique', 'randomresized', 'resizethencrop' offsets : double or iter-of-doubles, optional Specifies an offset for each channel in the input data. The final input data is set after applying scaling and subtracting the specified offsets. Default: (103.939, 116.779, 123.68) pre_trained_weights : bool, optional Specifies whether to use the pre-trained weights from ImageNet data set Default: False pre_trained_weights_file : string, optional Specifies the file name for the pretained weights. Must be a fully qualified file name of SAS-compatible file (*.caffemodel.h5) Note: Required when pre_train_weight=True. include_top : bool, optional Specifies whether to include pre-trained weights of the top layers, i.e. the FC layers Default: False random_mutation : string, optional Specifies how to apply data augmentations/mutations to the data in the input layer. Valid Values: 'none', 'random' Returns ------- :class:`Sequential` If `pre_train_weight` is `False` :class:`Model` If `pre_train_weight` is `True` References ---------- https://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/Szegedy_Rethinking_the_Inception_CVPR_2016_paper.pdf ''' conn.retrieve('loadactionset', _messagelevel='error', actionset='deeplearn') # get all the parms passed in parameters = locals() if not pre_trained_weights: model = Sequential(conn=conn, model_table=model_table) # get the input parameters input_parameters = get_layer_options(input_layer_options, parameters) model.add(InputLayer(**input_parameters)) # 299 x 299 x 3 model.add( Conv2d(n_filters=32, width=3, height=3, stride=2, act='identity', include_bias=False, padding=0)) model.add(BN(act='relu')) # 149 x 149 x 32 model.add( Conv2d(n_filters=32, width=3, height=3, stride=1, act='identity', include_bias=False, padding=0)) model.add(BN(act='relu')) # 147 x 147 x 32 model.add( Conv2d(n_filters=64, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) # 147 x 147 x 64 model.add(Pooling(width=3, height=3, stride=2, pool='max', padding=0)) # 73 x 73 x 64 model.add( Conv2d(n_filters=80, width=1, height=1, stride=1, act='identity', include_bias=False, padding=0)) model.add(BN(act='relu')) # 73 x 73 x 80 model.add( Conv2d(n_filters=192, width=3, height=3, stride=1, act='identity', include_bias=False, padding=0)) model.add(BN(act='relu')) # 71 x 71 x 192 pool2 = Pooling(width=3, height=3, stride=2, pool='max', padding=0) model.add(pool2) # mixed 0: output 35 x 35 x 256 # branch1x1 model.add( Conv2d(n_filters=64, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[pool2])) branch1x1 = BN(act='relu') model.add(branch1x1) # branch5x5 model.add( Conv2d(n_filters=48, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[pool2])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=64, width=5, height=5, stride=1, act='identity', include_bias=False)) branch5x5 = BN(act='relu') model.add(branch5x5) # branch3x3dbl model.add( Conv2d(n_filters=64, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[pool2])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=96, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=96, width=3, height=3, stride=1, act='identity', include_bias=False)) branch3x3dbl = BN(act='relu') model.add(branch3x3dbl) # branch_pool model.add( Pooling(width=3, height=3, stride=1, pool='average', src_layers=[pool2])) model.add( Conv2d(n_filters=32, width=1, height=1, stride=1, act='identity', include_bias=False)) branch_pool = BN(act='relu') model.add(branch_pool) # mixed0 concat concat = Concat( act='identity', src_layers=[branch1x1, branch5x5, branch3x3dbl, branch_pool]) model.add(concat) # mixed 1: output 35 x 35 x 288 # branch1x1 model.add( Conv2d(n_filters=64, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) branch1x1 = BN(act='relu') model.add(branch1x1) # branch5x5 model.add( Conv2d(n_filters=48, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=64, width=5, height=5, stride=1, act='identity', include_bias=False)) branch5x5 = BN(act='relu') model.add(branch5x5) # branch3x3dbl model.add( Conv2d(n_filters=64, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=96, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=96, width=3, height=3, stride=1, act='identity', include_bias=False)) branch3x3dbl = BN(act='relu') model.add(branch3x3dbl) # branch_pool model.add( Pooling(width=3, height=3, stride=1, pool='average', src_layers=[concat])) model.add( Conv2d(n_filters=64, width=1, height=1, stride=1, act='identity', include_bias=False)) branch_pool = BN(act='relu') model.add(branch_pool) # mixed1 concat concat = Concat( act='identity', src_layers=[branch1x1, branch5x5, branch3x3dbl, branch_pool]) model.add(concat) # mixed 2: output 35 x 35 x 288 # branch1x1 model.add( Conv2d(n_filters=64, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) branch1x1 = BN(act='relu') model.add(branch1x1) # branch5x5 model.add( Conv2d(n_filters=48, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=64, width=5, height=5, stride=1, act='identity', include_bias=False)) branch5x5 = BN(act='relu') model.add(branch5x5) # branch3x3dbl model.add( Conv2d(n_filters=64, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=96, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=96, width=3, height=3, stride=1, act='identity', include_bias=False)) branch3x3dbl = BN(act='relu') model.add(branch3x3dbl) # branch_pool model.add( Pooling(width=3, height=3, stride=1, pool='average', src_layers=[concat])) model.add( Conv2d(n_filters=64, width=1, height=1, stride=1, act='identity', include_bias=False)) branch_pool = BN(act='relu') model.add(branch_pool) # mixed2 concat concat = Concat( act='identity', src_layers=[branch1x1, branch5x5, branch3x3dbl, branch_pool]) model.add(concat) # mixed 3: output 17 x 17 x 768 # branch3x3 model.add( Conv2d(n_filters=384, width=3, height=3, stride=2, act='identity', include_bias=False, padding=0, src_layers=[concat])) branch3x3 = BN(act='relu') model.add(branch3x3) # branch3x3dbl model.add( Conv2d(n_filters=64, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=96, width=3, height=3, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=96, width=3, height=3, stride=2, act='identity', include_bias=False, padding=0)) branch3x3dbl = BN(act='relu') model.add(branch3x3dbl) # branch_pool branch_pool = Pooling(width=3, height=3, stride=2, pool='max', padding=0, src_layers=[concat]) model.add(branch_pool) # mixed3 concat concat = Concat(act='identity', src_layers=[branch3x3, branch3x3dbl, branch_pool]) model.add(concat) # mixed 4: output 17 x 17 x 768 # branch1x1 model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) branch1x1 = BN(act='relu') model.add(branch1x1) # branch7x7 model.add( Conv2d(n_filters=128, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=128, width=7, height=1, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=1, height=7, stride=1, act='identity', include_bias=False)) branch7x7 = BN(act='relu') model.add(branch7x7) # branch7x7dbl model.add( Conv2d(n_filters=128, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=128, width=1, height=7, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=128, width=7, height=1, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=128, width=1, height=7, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=7, height=1, stride=1, act='identity', include_bias=False)) branch7x7dbl = BN(act='relu') model.add(branch7x7dbl) # branch_pool model.add( Pooling(width=3, height=3, stride=1, pool='average', src_layers=[concat])) model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False)) branch_pool = BN(act='relu') model.add(branch_pool) # mixed4 concat concat = Concat( act='identity', src_layers=[branch1x1, branch7x7, branch7x7dbl, branch_pool]) model.add(concat) # mixed 5, 6: output 17 x 17 x 768 for i in range(2): # branch1x1 model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) branch1x1 = BN(act='relu') model.add(branch1x1) # branch7x7 model.add( Conv2d(n_filters=160, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=160, width=7, height=1, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=1, height=7, stride=1, act='identity', include_bias=False)) branch7x7 = BN(act='relu') model.add(branch7x7) # branch7x7dbl model.add( Conv2d(n_filters=160, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=160, width=1, height=7, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=160, width=7, height=1, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=160, width=1, height=7, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=7, height=1, stride=1, act='identity', include_bias=False)) branch7x7dbl = BN(act='relu') model.add(branch7x7dbl) # branch_pool model.add( Pooling(width=3, height=3, stride=1, pool='average', src_layers=[concat])) model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False)) branch_pool = BN(act='relu') model.add(branch_pool) # concat concat = Concat( act='identity', src_layers=[branch1x1, branch7x7, branch7x7dbl, branch_pool]) model.add(concat) # mixed 7: output 17 x 17 x 768 # branch1x1 model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) branch1x1 = BN(act='relu') model.add(branch1x1) # branch7x7 model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=7, height=1, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=1, height=7, stride=1, act='identity', include_bias=False)) branch7x7 = BN(act='relu') model.add(branch7x7) # branch7x7dbl model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=1, height=7, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=7, height=1, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=1, height=7, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=7, height=1, stride=1, act='identity', include_bias=False)) branch7x7dbl = BN(act='relu') model.add(branch7x7dbl) # branch_pool model.add( Pooling(width=3, height=3, stride=1, pool='average', src_layers=[concat])) model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False)) branch_pool = BN(act='relu') model.add(branch_pool) # mixed7 concat concat = Concat( act='identity', src_layers=[branch1x1, branch7x7, branch7x7dbl, branch_pool]) model.add(concat) # mixed 8: output 8 x 8 x 1280 # branch3x3 model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=320, width=3, height=3, stride=2, act='identity', include_bias=False, padding=0)) branch3x3 = BN(act='relu') model.add(branch3x3) # branch7x7x3 model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=7, height=1, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=1, height=7, stride=1, act='identity', include_bias=False)) model.add(BN(act='relu')) model.add( Conv2d(n_filters=192, width=3, height=3, stride=2, act='identity', include_bias=False, padding=0)) branch7x7x3 = BN(act='relu') model.add(branch7x7x3) # branch_pool branch_pool = Pooling(width=3, height=3, stride=2, pool='max', padding=0, src_layers=[concat]) model.add(branch_pool) # mixed8 concat concat = Concat(act='identity', src_layers=[branch3x3, branch7x7x3, branch_pool]) model.add(concat) # mixed 9, 10: output 8 x 8 x 2048 for i in range(2): # branch1x1 model.add( Conv2d(n_filters=320, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) branch1x1 = BN(act='relu') model.add(branch1x1) # branch3x3 model.add( Conv2d(n_filters=384, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) branch3x3 = BN(act='relu') model.add(branch3x3) model.add( Conv2d(n_filters=384, width=3, height=1, stride=1, act='identity', include_bias=False, src_layers=[branch3x3])) branch3x3_1 = BN(act='relu') model.add(branch3x3_1) model.add( Conv2d(n_filters=384, width=1, height=3, stride=1, act='identity', include_bias=False, src_layers=[branch3x3])) branch3x3_2 = BN(act='relu') model.add(branch3x3_2) branch3x3 = Concat(act='identity', src_layers=[branch3x3_1, branch3x3_2]) model.add(branch3x3) # branch3x3dbl model.add( Conv2d(n_filters=448, width=1, height=1, stride=1, act='identity', include_bias=False, src_layers=[concat])) model.add(BN(act='relu')) model.add( Conv2d(n_filters=384, width=3, height=3, stride=1, act='identity', include_bias=False)) branch3x3dbl = BN(act='relu') model.add(branch3x3dbl) model.add( Conv2d(n_filters=384, width=3, height=1, stride=1, act='identity', include_bias=False, src_layers=[branch3x3dbl])) branch3x3dbl_1 = BN(act='relu') model.add(branch3x3dbl_1) model.add( Conv2d(n_filters=384, width=1, height=3, stride=1, act='identity', include_bias=False, src_layers=[branch3x3dbl])) branch3x3dbl_2 = BN(act='relu') model.add(branch3x3dbl_2) branch3x3dbl = Concat(act='identity', src_layers=[branch3x3dbl_1, branch3x3dbl_2]) model.add(branch3x3dbl) # branch_pool model.add( Pooling(width=3, height=3, stride=1, pool='average', src_layers=[concat])) model.add( Conv2d(n_filters=192, width=1, height=1, stride=1, act='identity', include_bias=False)) branch_pool = BN(act='relu') model.add(branch_pool) # concat concat = Concat( act='identity', src_layers=[branch1x1, branch3x3, branch3x3dbl, branch_pool]) model.add(concat) # calculate dimensions for global average pooling w = max((width - 75) // 32 + 1, 1) h = max((height - 75) // 32 + 1, 1) # global average pooling model.add( Pooling(width=w, height=h, stride=1, pool='average', padding=0, src_layers=[concat])) # output layer model.add(OutputLayer(n=n_classes)) return model else: if pre_trained_weights_file is None: raise ValueError( '\nThe pre-trained weights file is not specified.\n' 'Please follow the steps below to attach the ' 'pre-trained weights:\n' '1. Go to the website ' 'https://support.sas.com/documentation/prod-p/vdmml/zip/ ' 'and download the associated weight file.\n' '2. Upload the *.h5 file to ' 'a server side directory which the CAS ' 'session has access to.\n' '3. Specify the pre_train_weight_file using ' 'the fully qualified server side path.') print('NOTE: Scale is set to 1/127.5, and offsets 1 to ' 'match Keras preprocessing.') model_cas = model_inceptionv3.InceptionV3_Model( s=conn, model_table=model_table, n_channels=n_channels, width=width, height=height, random_crop=random_crop, offsets=[1, 1, 1], random_flip=random_flip, random_mutation=random_mutation) if include_top: if n_classes != 1000: warnings.warn( 'If include_top = True, ' 'n_classes will be set to 1000.', RuntimeWarning) model = Model.from_table(model_cas) model.load_weights(path=pre_trained_weights_file, labels=True) return model else: model = Model.from_table(model_cas, display_note=False) model.load_weights(path=pre_trained_weights_file) weight_table_options = model.model_weights.to_table_params() weight_table_options.update(dict(where='_LayerID_<218')) model._retrieve_('table.partition', table=weight_table_options, casout=dict( replace=True, **model.model_weights.to_table_params())) model._retrieve_('deeplearn.removelayer', model=model_table, name='predictions') model._retrieve_('deeplearn.addlayer', model=model_table, name='predictions', layer=dict(type='output', n=n_classes, act='softmax'), srcLayers=['avg_pool']) model = Model.from_table(conn.CASTable(model_table)) return model