def test_model13b(self): model = Sequential(self.s, model_table='simple_cnn') model.add(layer=InputLayer(n_channels=1, height=10, width=10)) model.add(layer=OutputLayer(n=10, full_connect=False)) self.assertTrue(model.summary.loc[1, 'Number of Parameters'] == (0, 0)) model1 = Sequential(self.s, model_table='simple_cnn') model1.add(layer=InputLayer(n_channels=1, height=10, width=10)) model1.add(layer=OutputLayer(n=10, full_connect=True)) self.assertTrue(model1.summary.loc[1, 'Number of Parameters'] == (1000, 10)) model2 = Sequential(self.s, model_table='Simple_CNN') model2.add(layer=InputLayer(n_channels=1, height=10, width=10)) model2.add(layer=OutputLayer(n=10, full_connect=True, include_bias=False)) self.assertTrue(model2.summary.loc[1, 'Number of Parameters'] == (1000, 0)) model3 = Sequential(self.s, model_table='Simple_CNN') model3.add(layer=InputLayer(n_channels=1, height=10, width=10)) model3.add(layer=Conv2d(4, 3)) model3.add(layer=OutputLayer(n=10)) self.assertTrue(model3.summary.loc[2, 'Number of Parameters'] == (4000, 10)) model4 = Sequential(self.s, model_table='Simple_CNN') model4.add(layer=InputLayer(n_channels=1, height=10, width=10)) model4.add(layer=Conv2d(4, 3)) model4.add(layer=OutputLayer(n=10, full_connect=False)) self.assertTrue(model4.summary.loc[2, 'Number of Parameters'] == (0, 0))
def test_model29(self): # test specifying output layer in Model.from_onnx_model try: import onnx except: unittest.TestCase.skipTest(self, "onnx not found in the libraries") if self.data_dir_local is None: unittest.TestCase.skipTest( self, "DLPY_DATA_DIR_LOCAL is not set in " "the environment variables") m = onnx.load(os.path.join(self.data_dir_local, 'Simple_CNN1.onnx')) output_layer = OutputLayer(n=100) model1 = Model.from_onnx_model(conn=self.s, onnx_model=m, offsets=[ 1, 1, 1, ], scale=2, std='std', output_layer=output_layer) self.assertTrue(model1.layers[-1].config['n'] == 100)
def test_model18(self): model1 = Sequential(self.s, model_table='Simple_CNN1') model1.add(InputLayer(3, 224, 224)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Dense(16)) 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.save_weights_csv(self.data_dir)
def test_build_gan_model(self): if self.server_dir is None: unittest.TestCase.skipTest(self, "DLPY_DATA_DIR_SERVER is not set in the environment variables") # test default resnet18_model = ResNet18_Caffe(self.s, width=224, height=224, random_flip='HV', random_mutation='random' ) branch = resnet18_model.to_functional_model(stop_layers=resnet18_model.layers[-1]) # raise error self.assertRaises(DLPyError, lambda: GANModel(branch, branch)) # change the output size for generator inp = Input(**branch.layers[0].config) generator = Conv2D(width=1, height=1, n_filters=224 * 224 * 3)(branch(inp)) output = OutputLayer(n=1)(generator) generator = Model(self.s, inp, output) gan_model = GANModel(generator, branch) res = gan_model.models['generator'].print_summary() print(res) res = gan_model.models['discriminator'].print_summary() print(res)
def test_model1(self): model1 = Sequential(self.s, model_table='Simple_CNN1') model1.add(InputLayer(3, 224, 224)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Dense(16)) 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_', lr=0.001) if r.severity > 0: for msg in r.messages: print(msg) self.assertTrue(r.severity <= 1) if (caslib is not None) and tmp_caslib: self.s.retrieve('table.dropcaslib', message_level = 'error', caslib = caslib)
def test_model22(self): model1 = Sequential(self.s, model_table='Simple_CNN1') model1.add(InputLayer(3, 224, 224)) model1.add(Conv2d(8, 7)) pool1 = Pooling(2) model1.add(pool1) conv1 = Conv2d(1, 1, act='identity', src_layers=[pool1]) model1.add(conv1) model1.add(Res(act='relu', src_layers=[conv1, pool1])) 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_model23(self): 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', 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_model22_1(self): try: import onnx except: unittest.TestCase.skipTest(self, "onnx not found in the libraries") from onnx import numpy_helper 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)) 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_local, output_format='onnx') model_path = os.path.join(self.data_dir_local, '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]))
def test_CyclicLR(self): model1 = Sequential(self.s, model_table = 'Simple_CNN1') model1.add(InputLayer(3, 224, 224)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Dense(16)) 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) lrs = CyclicLR(self.s, 'eee', 4, 1.0, 0.0000001, 0.01) solver = VanillaSolver(lr_scheduler=lrs) self.assertTrue(self.sample_syntax['CyclicLR'] == solver) optimizer = Optimizer(algorithm = solver, log_level = 3, max_epochs = 4, mini_batch_size = 2) r = model1.fit(data = 'eee', inputs = '_image_', target = '_label_', optimizer = optimizer, n_threads=2) if r.severity > 0: for msg in r.messages: print(msg) self.assertTrue(r.severity <= 1)
def test_model12(self): model1 = Sequential(self.s, model_table='Simple_CNN1') model1.add(InputLayer(3, 224, 224)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Dense(16)) 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_', save_best_weights=True) self.assertTrue(r.severity == 0) r1 = model1.fit(data='eee', inputs='_image_', target='_label_', max_epochs=3) self.assertTrue(r1.severity == 0) r2 = model1.fit(data='eee', inputs='_image_', target='_label_', max_epochs=2, save_best_weights=True) self.assertTrue(r2.severity == 0) r3 = model1.predict(data='eee', use_best_weights=True) self.assertTrue(r3.severity == 0) if (caslib is not None) and tmp_caslib: self.s.retrieve('table.dropcaslib', message_level = 'error', caslib = caslib)
def test_build_gan_model_4(self): if self.server_dir is None: unittest.TestCase.skipTest(self, "DLPY_DATA_DIR_SERVER is not set in the environment variables") discriminator = Sequential(self.s) discriminator.add(InputLayer(1, 28, 28)) discriminator.add(Conv2d(3, 3)) discriminator.add(Pooling(2)) discriminator.add(Conv2d(3, 3)) discriminator.add(Pooling(2)) discriminator.add(Dense(16)) discriminator.add(OutputLayer(n=1)) generator = Sequential(self.s) generator.add(InputLayer(1, 100, 1)) generator.add(Dense(256, act='relu')) generator.add(Dense(512, act='relu')) generator.add(Dense(1024, act='relu')) generator.add(Dense(28 * 28, act='tanh')) generator.add(OutputLayer(act='softmax', n=2)) encoder = Sequential(self.s) encoder.add(InputLayer(100, 1, 1)) encoder.add(Dense(256, act='relu')) encoder.add(Dense(512, act='relu')) encoder.add(Dense(1024, act='relu')) encoder.add(Dense(100, act='tanh')) encoder.add(OutputLayer(act='softmax', n=2)) gan_model = GANModel(generator, discriminator, encoder) res = gan_model.models['generator'].print_summary() print(res) res = gan_model.models['discriminator'].print_summary() print(res) from dlpy.model import Optimizer, MomentumSolver, AdamSolver solver = AdamSolver(lr_scheduler=StepLR(learning_rate=0.0001, step_size=4), clip_grad_max=100, clip_grad_min=-100) optimizer = Optimizer(algorithm=solver, mini_batch_size=8, log_level=2, max_epochs=4, reg_l2=0.0001) res = gan_model.fit(optimizer, optimizer, self.server_dir + 'mnist_validate', n_samples_generator=32, n_samples_discriminator=32, max_iter=2, n_threads=1, damping_factor=0.5) print(res)
def test_model15(self): # test RECTIFIER activation for concat layer 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)) pool1 = Pooling(2) model1.add(pool1) conv1 = Conv2d(1, 7, src_layers=[pool1]) conv2 = Conv2d(1, 7, src_layers=[pool1]) model1.add(conv1) model1.add(conv2) model1.add(Concat(act='RECTIFIER', src_layers=[conv1, conv2])) 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, 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) 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 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 test_model13a(self): model = Sequential(self.s, model_table='simple_cnn') model.add(InputLayer(3, 224, 224)) model.add(Conv2d(2, 3)) model.add(Pooling(2)) model.add(Dense(4)) model.add(OutputLayer(n=2)) if self.data_dir is None: unittest.TestCase.skipTest(self, "DLPY_DATA_DIR is not set in the environment variables") model.save_to_table(self.data_dir)
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 test_imagescaler2(self): # test export model with imagescaler try: import onnx except: unittest.TestCase.skipTest(self, 'onnx not found') if self.data_dir_local is None: unittest.TestCase.skipTest( self, 'DLPY_DATA_DIR_LOCAL is not set in ' 'the environment variables') model1 = Sequential(self.s, model_table='imagescaler2') model1.add( InputLayer(n_channels=3, width=224, height=224, scale=1 / 255., offsets=[0.1, 0.2, 0.3])) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(OutputLayer(act='softmax', n=2)) 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) from dlpy.model_conversion.write_onnx_model import sas_to_onnx onnx_model = sas_to_onnx(model1.layers, self.s.CASTable('imagescaler2'), self.s.CASTable('imagescaler2_weights')) self.assertAlmostEqual(onnx_model.graph.node[0].attribute[0].floats[0], 0.1) self.assertAlmostEqual(onnx_model.graph.node[0].attribute[0].floats[1], 0.2) self.assertAlmostEqual(onnx_model.graph.node[0].attribute[0].floats[2], 0.3) self.assertAlmostEqual(onnx_model.graph.node[0].attribute[1].f, 1 / 255.)
def SequenceLabeling(conn, model_table='sequence_labeling_model', neurons=10, n_blocks=3, rnn_type='gru'): ''' Generates a sequence labeling model. Parameters ---------- conn : CAS Specifies the CAS connection object. model_table : string, optional Specifies the name of CAS table to store the model. neurons : int, optional Specifies the number of neurons to be in each layer. Default: 10 n_blocks : int, optional Specifies the number of bidirectional blocks to be added to the model. Default: 3 rnn_type : string, optional Specifies the type of the rnn layer. Default: GRU Valid Values: RNN, LSTM, GRU Returns ------- :class:`Sequential` ''' conn.retrieve('loadactionset', _messagelevel='error', actionset='deeplearn') if n_blocks >= 1: model = Sequential(conn=conn, model_table=model_table) model.add( Bidirectional(n=neurons, n_blocks=n_blocks, rnn_type=rnn_type, name='bi_' + rnn_type + '_layer_')) model.add(OutputLayer()) else: raise DLPyError( 'The number of blocks for a sequence labeling model should be at least 1.' ) return model
def test_plot_ticks(self): model1 = Sequential(self.s, model_table='Simple_CNN1') model1.add(InputLayer(3, 224, 224)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Conv2d(8, 7)) model1.add(Pooling(2)) model1.add(Dense(16)) 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_', lr=0.001, max_epochs=5) # Test default tick_frequency value of 1 ax = model1.plot_training_history() self.assertEqual(len(ax.xaxis.majorTicks), model1.n_epochs) # Test even tick_frequency = 2 ax = model1.plot_training_history(tick_frequency=tick_frequency) self.assertEqual(len(ax.xaxis.majorTicks), model1.n_epochs // tick_frequency + 1) # Test odd tick_frequency = 3 ax = model1.plot_training_history(tick_frequency=tick_frequency) self.assertEqual(len(ax.xaxis.majorTicks), model1.n_epochs // tick_frequency + 1) # Test max tick_frequency = model1.n_epochs ax = model1.plot_training_history(tick_frequency=tick_frequency) self.assertEqual(len(ax.xaxis.majorTicks), model1.n_epochs // tick_frequency + 1) # Test 0 tick_frequency = 0 ax = model1.plot_training_history(tick_frequency=tick_frequency) self.assertEqual(len(ax.xaxis.majorTicks), model1.n_epochs) if (caslib is not None) and tmp_caslib: self.s.retrieve('table.dropcaslib', message_level = 'error', caslib = caslib)
def test_conv1d_model(self): # a model from https://blog.goodaudience.com/introduction-to-1d-convolutional-neural-networks-in-keras-for-time-sequences-3a7ff801a2cf Conv1D = Conv1d MaxPooling1D=Pooling model_m = Sequential(self.s) model_m.add(InputLayer(width=80*3, height=1, n_channels=1)) model_m.add(Conv1D(100, 10, act='relu')) model_m.add(Conv1D(100, 10, act='relu')) model_m.add(MaxPooling1D(3)) model_m.add(Conv1D(160, 10, act='relu')) model_m.add(Conv1D(160, 10, act='relu')) model_m.add(GlobalAveragePooling1D(dropout=0.5)) model_m.add(OutputLayer(n=6, act='softmax')) # use assertEqual to check whether the layer output size matches the expected value for MaxPooling1D self.assertEqual(model_m.layers[3].output_size, (1, 80, 100)) model_m.print_summary() # 1d print summary numerical check self.assertEqual(model_m.summary.iloc[1, -1], 240000)
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 setUp(self): swat.reset_option() swat.options.cas.print_messages = False swat.options.interactive_mode = False self.s = swat.CAS(HOST, PORT, USER, PASSWD, protocol=PROTOCOL) if type(self).server_type is None: # Set once per class and have every test use it. No need to change between tests. type(self).server_type = tm.get_cas_host_type(self.s) self.srcLib = tm.get_casout_lib(self.server_type) # Define the model model = Sequential(self.s, model_table='test_model') model.add(InputLayer(3, 224, 224, offsets=(0, 0, 0))) model.add(Conv2d(8, 7)) model.add(Pooling(2)) model.add(Conv2d(8, 7)) model.add(Pooling(2)) model.add(Dense(16)) model.add(OutputLayer(act='softmax', n=2)) self.model = model
def MobileNetV2_ONNX(conn, model_file, n_classes=1000, width=224, height=224, 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, include_top=False): """ Generates a deep learning model with the MobileNetV2_ONNX architecture. The model architecture and pre-trained weights is generated from MobileNetV2 ONNX trained on ImageNet dataset. The model file and the weights file can be downloaded from https://support.sas.com/documentation/prod-p/vdmml/zip/. To learn more information about the model and pre-processing. Please go to the websites: https://github.com/onnx/models/tree/master/vision/classification/mobilenet. Parameters ---------- conn : CAS Specifies the CAS connection object. model_file : string Specifies the absolute server-side path of the model table file. The model table file can be downloaded from https://support.sas.com/documentation/prod-p/vdmml/zip/. n_classes : int, optional Specifies the number of classes. Default: 1000 width : int, optional Specifies the width of the input layer. Default: 224 height : int, optional Specifies the height of the input layer. Default: 224 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. The channel order is BGR. 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. The channel order is BGR. 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' include_top : bool, optional Specifies whether to include pre-trained weights of the top layers (i.e., the FC layers) Default: False """ parameters = locals() input_parameters = get_layer_options(input_layer_options, parameters) # load model and model weights model = Model.from_sashdat(conn, path=model_file) # check if a user points to a correct model. if model.summary.shape[0] != 120: raise DLPyError( "The model file doesn't point to a valid MobileNetV2_ONNX model. " "Please check the SASHDAT file.") # extract input layer config model_table_df = conn.CASTable(**model.model_table).to_frame() input_layer_df = model_table_df[model_table_df['_DLLayerID_'] == 0] input_layer = extract_input_layer(input_layer_df) input_layer_config = input_layer.config # update input layer config input_layer_config.update(input_parameters) # update the layer list model.layers[0] = InputLayer(**input_layer_config, name=model.layers[0].name) # warning if model weights doesn't exist if not conn.tableexists(model.model_weights.name).exists: weights_file_path = os.path.join(os.path.dirname(model_file), model.model_name + '_weights.sashdat') print('WARNING: Model weights is not attached ' 'since system cannot find a weights file located at {}'.format( weights_file_path)) if include_top: if n_classes != 1000: raise DLPyError( "If include_top is enabled, n_classes has to be 1000.") else: # since the output layer is non fully connected layer, # we need to modify the convolution right before the output. The number of filter is set to n_classes. conv_layer_df = model_table_df[model_table_df['_DLLayerID_'] == 118] conv_layer = extract_conv_layer(conv_layer_df) conv_layer_config = conv_layer.config # update input layer config conv_layer_config.update({'n_filters': n_classes}) # update the layer list model.layers[-2] = Conv2d(**conv_layer_config, name=model.layers[-2].name, src_layers=model.layers[-3]) # overwrite n_classes in output layer out_layer_df = model_table_df[model_table_df['_DLLayerID_'] == 119] out_layer = extract_output_layer(out_layer_df) out_layer_config = out_layer.config # update input layer config out_layer_config.update({'n': n_classes}) # update the layer list model.layers[-1] = OutputLayer(**out_layer_config, name=model.layers[-1].name, src_layers=model.layers[-2]) # remove top weights model.model_weights.append_where('_LayerID_<118') model._retrieve_('table.partition', table=model.model_weights, casout=dict(replace=True, name=model.model_weights.name)) model.set_weights(model.model_weights.name) # recompile the whole network according to the new layer list 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 MobileNetV1(conn, model_table='MobileNetV1', n_classes=1000, n_channels=3, width=224, height=224, random_flip=None, random_crop=None, random_mutation=None, norm_stds=(255 * 0.229, 255 * 0.224, 255 * 0.225), offsets=(255 * 0.485, 255 * 0.456, 255 * 0.406), alpha=1, depth_multiplier=1): ''' Generates a deep learning model with the MobileNetV1 architecture. The implementation is revised based on https://github.com/keras-team/keras-applications/blob/master/keras_applications/mobilenet.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 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' 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) alpha : int, optional Specifies the width multiplier in the MobileNet paper Default: 1 depth_multiplier : int, optional Specifies the number of depthwise convolution output channels for each input channel. Default: 1 Returns ------- :class:`Model` References ---------- https://arxiv.org/pdf/1605.07146.pdf ''' 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 _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 parameters = locals() input_parameters = get_layer_options(input_layer_options, parameters) inp = Input(**input_parameters, name='data') # the model down-sampled for 5 times by performing stride=2 convolution on # conv_dw_1, conv_dw_2, conv_dw_4, conv_dw_6, conv_dw_12 # for each block, we use depthwise convolution with kernel=3 and point-wise convolution to save computation x, depth = _conv_block(inp, 32, alpha, stride=2) x, depth = _depthwise_conv_block(x, depth, 64, alpha, depth_multiplier, block_id=1) x, depth = _depthwise_conv_block(x, depth, 128, alpha, depth_multiplier, stride=2, block_id=2) x, depth = _depthwise_conv_block(x, depth, 128, alpha, depth_multiplier, block_id=3) x, depth = _depthwise_conv_block(x, depth, 256, alpha, depth_multiplier, stride=2, block_id=4) x, depth = _depthwise_conv_block(x, depth, 256, alpha, depth_multiplier, block_id=5) x, depth = _depthwise_conv_block(x, depth, 512, alpha, depth_multiplier, stride=2, block_id=6) x, depth = _depthwise_conv_block(x, depth, 512, alpha, depth_multiplier, block_id=7) x, depth = _depthwise_conv_block(x, depth, 512, alpha, depth_multiplier, block_id=8) x, depth = _depthwise_conv_block(x, depth, 512, alpha, depth_multiplier, block_id=9) x, depth = _depthwise_conv_block(x, depth, 512, alpha, depth_multiplier, block_id=10) x, depth = _depthwise_conv_block(x, depth, 512, alpha, depth_multiplier, block_id=11) x, depth = _depthwise_conv_block(x, depth, 1024, alpha, depth_multiplier, stride=2, block_id=12) x, depth = _depthwise_conv_block(x, depth, 1024, alpha, depth_multiplier, block_id=13) 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 test_summary_function(self): ol = OutputLayer(name='output', n=100) self.assertTrue(ol.summary['Output Size'][0] == 100)
def test_output_layer2(self): if not __dev__: with self.assertRaises(DLPyError): OutputLayer(not_a_parameter=1)
def test_output_layer1(self): dict1 = OutputLayer(name='output', n=100, src_layers=[Pooling(name='pool') ]).to_model_params() self.assertTrue(self.sample_syntax['output1'] == dict1)
def VGG19(conn, model_table='VGG19', 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), pre_trained_weights=False, pre_trained_weights_file=None, include_top=False, random_mutation=None): ''' Generates a deep learning model with the VGG19 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) pre_trained_weights : bool, optional Specifies whether to use the pre-trained weights trained on the ImageNet data set. Default: False pre_trained_weights_file : string, optional Specifies the file name for the pre-trained weights. Must be a fully qualified file name of SAS-compatible file (e.g., *.caffemodel.h5) Note: Required when pre_trained_weights=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_trained_weights` is False :class:`Model` If `pre_trained_weights` is True References ---------- https://arxiv.org/pdf/1409.1556.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)) model.add(Conv2d(n_filters=64, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=64, width=3, height=3, stride=1)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add(Conv2d(n_filters=128, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=128, width=3, height=3, stride=1)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add(Conv2d(n_filters=256, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=256, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=256, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=256, width=3, height=3, stride=1)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) 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 else: if pre_trained_weights_file is None: raise DLPyError( '\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_trained_weights_file using the fully qualified server side path.' ) model_cas = model_vgg19.VGG19_Model(s=conn, model_table=model_table, n_channels=n_channels, width=width, height=height, random_crop=random_crop, offsets=offsets, 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_<22')) 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='fc8') model._retrieve_('deeplearn.addlayer', model=model_table, name='fc8', layer=dict(type='output', n=n_classes, act='softmax'), srcLayers=['fc7']) model = Model.from_table(conn.CASTable(model_table)) return model
def VGG11(conn, model_table='VGG11', 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 VGG11 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)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add(Conv2d(n_filters=128, width=3, height=3, stride=1)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add(Conv2d(n_filters=256, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=256, width=3, height=3, stride=1)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Pooling(width=2, height=2, stride=2, pool='max')) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) model.add(Conv2d(n_filters=512, width=3, height=3, stride=1)) 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