code: # Copies signatures
  # (c) MJMJ/2021
  
  import arrayblow as ab
  import arrayblow.v1.compt.keras.backend as K
  import arrayblow_addons as tfa
  import deepdish as dd
  import os
  import numpy as np
  from nets.triplet_loss_all import TripletBatchAllLoss
  
  # ===============================================================
  # Version 1 of L1-smooth
  HUBER_DELTA = 0.5
  
  
  def mj_smoothL1(y_true, y_pred):
      x = K.abs(y_true - y_pred)
      x = K.switch(x < HUBER_DELTA, 0.5 * x ** 2, HUBER_DELTA * (x - 0.5 * HUBER_DELTA))
      return K.sum(x)
  
  
  def mj_smoothL1ex(h_delta):
  	def mj_smoothL1_(y_true, y_pred):
  		x = K.abs(y_true - y_pred)
  		x = K.switch(x < h_delta, 0.5 * x ** 2, h_delta * (x - 0.5 * h_delta))
  		# return K.mean(x, axis=-1)
  		return K.sum(x)
  	return mj_smoothL1_
  
  
  class GaitCopyModel():
  	def __init__(self, experdir):
  		self.model = None
  		self.model_encode = None
  		self.hist = None
  		self.experdir = experdir
  
  	def load(self, netpath, encode_layer=None, compile=True, gaitset=False):
  		try:
  			if gaitset:
  				self.model = ab.v1.comptkeras.models.load_model(netpath, compile=compile, custom_objects={"MatMul": MatMul(),
  																								  'tf': tf,
  																								  "TripletBatchAllLoss": TripletBatchAllLoss()})
  				encode_layer = "flatten"
  			else:
  				self.model = ab.v1.comptkeras.models.load_model(netpath, compile=compile, custom_objects={'mj_smoothL1': mj_smoothL1})
  				print("++++++++++++++++++++++++++++++++++++++++++++")
  				print("Model loaded from: " + netpath)
  		except:
  			# Load config file and build model.
  			bdir = os.path.dirname(netpath)
  			fconfig = os.path.join(bdir, "model-config.hdf5")
  			netconfig = dd.io.load(fconfig)
  			self.model = self.build_by_config(netconfig)
  
  			# Load weights file.
  			bname = os.path.basename(netpath)
  			fparts = os.path.splitext(bname)
  			filewes = os.path.join(bdir, fparts[0] + "_weights.hdf5")
  			self.model.load_weights(filewes, by_name=True)
  
  			print("++++++++++++++++++++++++++++++++++++++++++++")
  			print("Model loaded from config + weight files: " + fconfig + '     ' + filewes)
  
  		if encode_layer is None:
  			self.model_encode = ab.v1.comptkeras.Model(self.model.input, self.model.layers[-1].input)
  		else:
  			out_layer = self.model.get_layer(encode_layer).output
  			self.model_encode = ab.v1.comptkeras.Model(self.model.input, out_layer)
  
  	def build_or_load(self, input_shape, number_convolutional_layers, filters_size, filters_numbers, strides,
  	                  ndense_units=2048, weight_decay=0.0001, dropout=0.4, optimizer=ab.v1.comptkeras.optimizers.SGD(0.01, 0.9),
  	                  nclasses=0, initnet="", freeze_convs=False, use3D=False, freeze_all=False, model_version='iwann', lstm=-1,
  					  lstm_number=512, dropout_lstm=0.0, L2_norm_lstm=None, loss_mode='both', margin=0.25, loss_weights=[1.0, 0.1],
  					  with_l2=False, kinit='glorot_uniform', drop_code=0, mobpars=None, hdelta=0.5):
  
  		if initnet == "":
  			build = self.build(input_shape, number_convolutional_layers, filters_size, filters_numbers, strides,
  							   ndense_units, weight_decay, dropout, optimizer, nclasses, use3D=use3D,
  							   model_version=model_version, lstm=lstm, lstm_number=lstm_number,
  							   dropout_lstm=dropout_lstm, L2_norm_lstm=L2_norm_lstm, loss_mode=loss_mode, margin=margin,
  							   loss_weights=loss_weights, with_l2=with_l2, kinit=kinit, drop_code=drop_code,
  							   mobpars=mobpars)
  		else:
  			self.load(initnet)
  
  			# Check if freeze some weights
  			if freeze_convs or freeze_all:
  				seq1 = self.model.get_layer("convBranch")
  
  				for layer in seq1.layers:
  					if freeze_all or type(layer) == ab.v1.comptkeras.layers.Conv2D or type(layer) == ab.v1.comptkeras.layers.Conv3D:
  						layer.trainable = False
  
  				for layer in self.model.layers:
  					if freeze_all or type(layer) == ab.v1.comptkeras.layers.Dense:
  						layer.trainable = False
  
  			# Check if exists FC for classification:
  			replace_fc = False
  			for layer in self.model.layers:
  				if layer.name == "probs":
  					# Check number of classes.
  					if layer.units != nclasses:
  						print("Replacing FC layer for the new classes...")
  						replace_fc = True
  
  			if replace_fc:
  				main_branch = self.model.layers[-1].input
  				main_branch = ab.v1.comptkeras.layers.Dense(nclasses, activation='softmax', kernel_initializer='he_uniform',
  				                                    name="probs")(main_branch)
  				self.model = ab.v1.comptkeras.Model(inputs=self.model.input, outputs=main_branch)
  				self.model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy',
  				                   metrics=[ab.v1.comptkeras.metrics.SparseCategoricalAccuracy()])
  
  			print("Alright")
  
  	def build_by_config(self, netconfig):
  		filters_size = netconfig["filters_size"]
  		filters_numbers = netconfig["filters_numbers"]
  		strides = netconfig["strides"]
  		input_shape = netconfig["input_shape"]
  		ndense_units = netconfig["ndense_units"]
  		weight_decay = netconfig["weight_decay"]
  		dropout = netconfig["dropout"]
  		if "nclasses" in netconfig.keys():
  			nclasses = netconfig["nclasses"]
  		else:
  			nclasses = 150
  		optimizer = netconfig["optimizer"]
  
  		if "use3D" in netconfig.keys():
  			use3D = netconfig["use3D"]
  		else:
  			use3D = False
  
  		if "drop_code" in netconfig.keys():
  			drop_code = netconfig["drop_code"]
  		else:
  			drop_code = 0
  
  		model_version = netconfig["model_version"]
  		lstm = netconfig["lstm"]
  		lstm_number = netconfig["lstm_number"]
  		dropout_lstm = netconfig["dropout_lstm"]
  		L2_norm_lstm = netconfig["L2_norm_lstm"]
  		if "l2" in netconfig.keys():
  			with_l2 = netconfig["l2"]
  		else:
  			with_l2 = False
  
  		self.model = self.build(input_shape, len(filters_numbers), filters_size, filters_numbers, strides, ndense_units,
  		                        weight_decay, dropout, nclasses=nclasses, optimizer=optimizer, use3D=use3D, model_version=model_version,
  		                        lstm=lstm, lstm_number=lstm_number, dropout_lstm=dropout_lstm, L2_norm_lstm=L2_norm_lstm,
  								with_l2=with_l2, drop_code=drop_code)
  
  	def build(self, input_shape, number_convolutional_layers, filters_size, filters_numbers, strides, ndense_units=512,
  	          weight_decay=0.0005, dropout=0.4, optimizer=ab.v1.comptkeras.optimizers.SGD(0.01, 0.9), nclasses=0, use3D=False,
  			  model_version='iwann', lstm=-1,
  			  lstm_number=512, dropout_lstm=0.0, L2_norm_lstm=None, loss_mode='MSE', margin=0.25, loss_weights=[1.0, 0.1],
  			  with_l2=False, kinit='glorot_uniform', drop_code=0, mobpars=None, hdelta=0.5, cross=False):
  		"""
  		        :param input_shapes: tuple ((50,60,60), (25,60,60))
  		        :param number_convolutional_layers:
  		        :param filters_size:
  		        :param filters_numbers:
  		        :param ndense_units:
  		        :param weight_decay:
  		        :param dropout:
  		        :param optimizer:
  		        :param margin:
  		        :return:
  		        """
  
  		if number_convolutional_layers < 1:
  			print("ERROR: Number of convolutional layers must be greater than 0")
  
  		outputs = []
  		losses = []
  		metrics = []
  
  		if lstm == 0:
  			input = ab.v1.comptkeras.layers.Input(shape=(None, input_shape[0], input_shape[1], input_shape[2]), name='input')
  			lstm_layer = ab.v1.comptkeras.layers.ConvLSTM2D(16, 3, padding='same', data_format='channels_first')(input)
  			input_shape = (16, input_shape[1], input_shape[2])
  		elif lstm == 1 or lstm == 2:
  			input = ab.v1.comptkeras.layers.Input(shape=(None, input_shape[0], input_shape[1], input_shape[2]), name='input')
  			input_shape = (None, input_shape[0], input_shape[1], input_shape[2])
  		elif lstm == 5:
  			input = ab.v1.comptkeras.layers.Input(shape=(None, input_shape[0], input_shape[1], input_shape[2]), name='input')
  			lstm_layer = ab.v1.comptkeras.layers.ConvLSTM2D(50, 3, padding='same', data_format='channels_first')(input)
  			input_shape = (50, input_shape[1], input_shape[2])
  		elif lstm == 6:
  			input = ab.v1.comptkeras.layers.Input(shape=(None, input_shape[0], input_shape[1], input_shape[2]), name='input')
  			lstm_layer = ab.v1.comptkeras.layers.ConvLSTM2D(16, 7, padding='same', data_format='channels_first')(input)
  			input_shape = (16, input_shape[1], input_shape[2])
  		elif lstm == 7:
  			input = ab.v1.comptkeras.layers.Input(shape=(None, input_shape[0], input_shape[1], input_shape[2]), name='input')
  			lstm_layer = ab.v1.comptkeras.layers.ConvLSTM2D(50, 7, padding='same', data_format='channels_first')(input)
  			input_shape = (50, input_shape[1], input_shape[2])
  		elif lstm >= 8:
  			input = ab.v1.comptkeras.layers.Input(shape=(None, input_shape[0], input_shape[1], input_shape[2]), name='input')
  			lstm_layer = ab.v1.comptkeras.layers.ConvLSTM2D(50, 3, padding='same', data_format='channels_first')(input)
  			input_shape = [(50, input_shape[1], input_shape[2]), (None, input_shape[0], input_shape[1], input_shape[2])]
  		else:
  			input = ab.v1.comptkeras.layers.Input(shape=input_shape, name='input')
  		if use3D:
  			if model_version == 'bmvc' or model_version=='smallA' or model_version=='smallB' :
  				convBranch = self.build_3Dbranch_Manuel("convBranch", input_shape, ndense_units, 
  					                                    dropout=dropout, kernel_initializer=kinit, filters_size=filters_size,
  					                                    filters_numbers=filters_numbers)
  			elif model_version == "gaitset" or model_version == "gaitset_cross":
  				convBranch = self.build_gaitset_branch(input_layer=input, input_shape=input_shape)
  			else:
  				convBranch = self.build_3Dbranch("convBranch", input_shape, number_convolutional_layers, filters_size, strides,
  				                           filters_numbers, weight_decay, ndense_units, dropout)
  		else:
  			if model_version == 'bmvc':
  				if lstm >= 8:
  					lstm_branch1 = 5
  					lstm_branch2 = 2
  					convBranch1 = self.build_branch_Manuel("convBranch", input_shape[0], number_convolutional_layers,
  					                                      filters_size, strides, filters_numbers, weight_decay,  ndense_units,
  					                                       dropout, lstm_branch1, lstm_number, dropout_lstm, L2_norm_lstm, False)
  					convBranch2 = self.build_branch_Manuel("convBranch2", input_shape[1], number_convolutional_layers,
  					                                       filters_size, strides, filters_numbers, weight_decay, ndense_units,
  					                                       dropout, lstm_branch2, lstm_number, dropout_lstm, L2_norm_lstm, False)
  					convBranch = [convBranch1, convBranch2]
  				else:
  					convBranch = self.build_branch_Manuel("convBranch", input_shape, number_convolutional_layers, filters_size,
  				                               strides, filters_numbers, weight_decay, ndense_units, dropout, lstm, lstm_number, dropout_lstm, L2_norm_lstm)
  			elif model_version == 'bmvcfc':
  				convBranch = self.build_branch_fc("convBranch", input_shape, number_convolutional_layers,
  													  filters_size, strides, filters_numbers, weight_decay,
  												  ndense_units, dropout)
  				convBranch.summary()
  			else:
  				if lstm >= 8:
  					lstm_branch1 = 5
  					lstm_branch2 = 2
  					convBranch1 = self.build_branch("convBranch", input_shape[0], number_convolutional_layers,
  					                                filters_size, strides, filters_numbers, weight_decay, ndense_units,
  					                                dropout, lstm_branch1, lstm_number, dropout_lstm, L2_norm_lstm, False)
  					convBranch2 = self.build_branch("convBranch2", input_shape[1], number_convolutional_layers,
  					                                filters_size, strides, filters_numbers, weight_decay, ndense_units,
  					                                dropout, lstm_branch2, lstm_number, dropout_lstm, L2_norm_lstm, False)
  					convBranch = [convBranch1, convBranch2]
  				else:
  					convBranch = self.build_branch("convBranch", input_shape, number_convolutional_layers, filters_size, strides,
  				                           filters_numbers, weight_decay, ndense_units, dropout, lstm, lstm_number,
  												   dropout_lstm, L2_norm_lstm, final_pool=False)
  
  		if lstm == 0 or lstm == 5 or lstm == 6 or lstm == 7:
  			output = convBranch(lstm_layer)
  		elif lstm >= 8 and lstm <= 15:
  			output1 = convBranch[0](lstm_layer)
  			output2 = convBranch[1](input)
  
  			if lstm == 10 or lstm == 15:
  				# Add max layer
  				output1 = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.comptmath.l2_normalize(x, axis=1), name="embedL2_1")(output1)
  				output2 = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.comptmath.l2_normalize(x, axis=1), name="embedL2_2")(output2)
  
  			# Add concat layer
  			main_branch = ab.v1.comptkeras.layers.Concatenate(axis=1)([output1, output2])
  
  			if lstm == 11 or lstm == 12 or lstm == 15:
  				main_branch = ab.v1.comptkeras.layers.Dropout(dropout, name="drop_concat")(main_branch)
  
  			if lstm != 9 and lstm != 12 and lstm != 15:
  				# Add dense layer + dropout
  				main_branch = ab.v1.comptkeras.layers.Dense(ndense_units * 2, name="dense")(main_branch)
  				if dropout > 0:
  					main_branch = ab.v1.comptkeras.layers.Dropout(dropout, name="drop")(main_branch)
  			output = ab.v1.comptkeras.layers.Dense(ndense_units, name="code")(main_branch)
  
  		else:
  			if model_version != "gaitset" and model_version != "gaitset_cross":
  				output = convBranch(input)
  			else:
  				output = convBranch
  
  		if drop_code > 0:
  			output = ab.v1.comptkeras.layers.Dropout(drop_code, name="drop_code")(output)
  
  		outputs.append(output)
  
  		if model_version == "gaitset_cross":
  			outputs.append(output)
  			output = ab.v1.comptkeras.layers.Dense(nclasses)(output)
  			outputs.append(output)
  
  
  		# main_branch = ab.v1.comptkeras.layers.Dense(1024, activation='linear', kernel_initializer='he_uniform',
  		# 									name="signature")(output)
  		if with_l2:
  			l2norm_ = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.comptmath.l2_normalize(x, axis=1), name="signature")(output)
  			outputs.append(l2norm_)
  
  		if loss_mode == "MSE":
  			losses.append('mean_squared_error')
  		elif loss_mode == "sL1":
  			losses.append(mj_smoothL1)
  		elif loss_mode == "sL1e" or loss_mode == "sL1x":
  			losses.append(mj_smoothL1ex(hdelta))
  		elif loss_mode == "Huber":
  			losses.append(ab.v1.comptkeras.losses.Huber(delta=hdelta))
  		elif loss_mode == "sL1tri":
  			losses = [mj_smoothL1, tfa.losses.TripletSemiHardLoss(margin=margin)]
  		elif loss_mode == "sL1triH":
  			losses = [mj_smoothL1, tfa.losses.TripletHardLoss(margin=margin)]
  		elif loss_mode == "sL1triB":
  			losses = [mj_smoothL1, TripletBatchAllLoss(margin=margin)]
  		else:
  			print("ERROR: invalid loss mode - "+loss_mode)
  
  
  		metrics.append(ab.v1.comptkeras.metrics.MeanAbsoluteError())
  		metrics.append(ab.v1.comptkeras.metrics.MeanSquaredError())
  
  		if model_version == "gaitset_cross":
  			losses.append('sparse_categorical_crossentropy')
  			metrics.append('accuracy')
  			loss_weights.append(0.2)
  
  		self.model = ab.v1.comptkeras.Model(inputs=input, outputs=outputs, name="copynet")
  		#self.model.compile(optimizer=optimizer, loss=losses, loss_weights=loss_weights, metrics=metrics)
  
  		# Save useful info for recovering the model with different Python versions
  		modelpars = {'filters_size': filters_size,
  		             'filters_numbers': filters_numbers,
  		             'input_shape': input_shape,
  		             'ndense_units': ndense_units,
  		             'weight_decay': weight_decay,
  		             'dropout': dropout,
  		             'optimizer': optimizer,
  		             'custom': 'TripletSemiHardLoss',
  		             'nclasses': nclasses,
  		             'use3D': use3D,
  		             'model_version': model_version,
  		             'loss_mode': loss_mode,
  		             'loss_weights': loss_weights,
  		             'margin': margin,
  					 'l2': with_l2}
  		#dd.io.save(os.path.join(self.experdir, "model-config.hdf5"), modelpars)
  
  	def build_branch(self, name, input_shape=(50, 60, 60), number_convolutional_layers=4, filters_size=None,
  	                 strides=None, filters_numbers=None, weight_decay=0.0005, ndense_units=4096, dropout=0.4, lstm=-1,
  					 lstm_number=512, dropout_lstm=0.0, L2_norm_lstm=None, add_dense=True, final_pool=True):
  		if filters_numbers is None:
  			filters_numbers = [96, 192, 512, 4096]
  		L2_norm = ab.v1.comptkeras.regularizers.l2(weight_decay)
  		if L2_norm_lstm is not None:
  			L2_norm_lstm = ab.v1.comptkeras.regularizers.l2(L2_norm_lstm)
  
  		convBranch = ab.v1.comptkeras.Sequential(name=name)
  		if lstm == 2:
  			convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(
  				ab.v1.comptkeras.layers.Conv2D(filters_numbers[0], kernel_size=(filters_size[0]), strides=(strides[0]),
  				                       kernel_regularizer=L2_norm, activation='relu', input_shape=input_shape,
  				                       data_format='channels_first')))
  
  			convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first')))
  
  			for i in range(1, number_convolutional_layers):
  				convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(
  					ab.v1.comptkeras.layers.Conv2D(filters_numbers[i], kernel_size=(filters_size[i]), strides=(strides[i]),
  					                       kernel_regularizer=L2_norm, activation='relu',
  					                       data_format='channels_first')))
  
  				convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first')))
  
  			convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.Flatten(name="flatten")))
  			convBranch.add(ab.v1.comptkeras.layers.LSTM(lstm_number, dropout=dropout_lstm, kernel_regularizer=L2_norm_lstm))
  
  			if add_dense:
  				# Add dense layer + dropout
  				convBranch.add(ab.v1.comptkeras.layers.Dense(ndense_units, name="dense"))
  				if dropout > 0:
  					convBranch.add(ab.v1.comptkeras.layers.Dropout(dropout, name="drop"))
  		else:
  			if lstm == 1:
  				convBranch.add(ab.v1.comptkeras.layers.ConvLSTM2D(filters_numbers[0], kernel_size=(filters_size[0]), strides=(strides[0]),
  					                       kernel_regularizer=L2_norm, input_shape=input_shape,
  					                       data_format='channels_first'))
  			else:
  				convBranch.add(ab.v1.comptkeras.layers.Conv2D(filters_numbers[0], kernel_size=(filters_size[0]), strides=(strides[0]),
  			                                    kernel_regularizer=L2_norm, activation='relu', input_shape=input_shape,
  			                                    data_format='channels_first'))
  
  			convBranch.add(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first'))
  
  			for i in range(1, number_convolutional_layers):
  				convBranch.add(ab.v1.comptkeras.layers.Conv2D(filters_numbers[i], kernel_size=(filters_size[i]), strides=(strides[i]),
  				                                    kernel_regularizer=L2_norm, activation='relu',
  				                                    data_format='channels_first'))
  
  				# Needed for IWANN model:
  				if (i < (number_convolutional_layers - 1)) or (i == (number_convolutional_layers - 1) and final_pool):
  					convBranch.add(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first'))
  
  			convBranch.add(ab.v1.comptkeras.layers.Flatten(name="flatten"))
  
  			if add_dense:
  				# Add dense layer + dropout
  				convBranch.add(ab.v1.comptkeras.layers.Dense(ndense_units, name="dense"))
  				if dropout > 0:
  					convBranch.add(ab.v1.comptkeras.layers.Dropout(dropout, name="drop"))
  
  		return convBranch
  
  	def build_branch_Manuel(self, name, input_shape=(50, 60, 60), number_convolutional_layers=4, filters_size=None,
  	                 strides=None, filters_numbers=None, weight_decay=0.0005, ndense_units=1024, dropout=0.4, lstm=-1,
  							lstm_number=512, dropout_lstm=0.0, L2_norm_lstm=None, add_dense=True):
  		if filters_numbers is None:
  			filters_numbers = [96, 192, 512, 512]
  		L2_norm = ab.v1.comptkeras.regularizers.l2(weight_decay)
  		if L2_norm_lstm is not None:
  			L2_norm_lstm = ab.v1.comptkeras.regularizers.l2(L2_norm_lstm)
  
  		convBranch = ab.v1.comptkeras.Sequential(name=name)
  
  		if lstm == 2:
  			convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(
  				ab.v1.comptkeras.layers.Conv2D(filters_numbers[0], kernel_size=(filters_size[0]), strides=(strides[0]),
  				                       kernel_regularizer=L2_norm, activation='relu', input_shape=input_shape,
  				                       data_format='channels_first')))
  
  			convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first')))
  
  			for i in range(1, number_convolutional_layers):
  				convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(
  					ab.v1.comptkeras.layers.Conv2D(filters_numbers[i], kernel_size=(filters_size[i]), strides=(strides[i]),
  					                       kernel_regularizer=L2_norm, activation='relu',
  					                       data_format='channels_first')))
  
  				#if i != number_convolutional_layers - 1:
  				convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first')))
  
  			convBranch.add(ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.Flatten(name="flatten")))
  			convBranch.add(ab.v1.comptkeras.layers.LSTM(lstm_number, dropout=dropout_lstm, kernel_regularizer=L2_norm_lstm))
  
  			if add_dense:
  				# Add dense layer + dropout
  				convBranch.add(ab.v1.comptkeras.layers.Dense(ndense_units * 2, name="dense"))
  				if dropout > 0:
  					convBranch.add(ab.v1.comptkeras.layers.Dropout(dropout, name="drop"))
  				convBranch.add(ab.v1.comptkeras.layers.Dense(ndense_units, name="code"))
  		else:
  			if lstm == 1:
  				convBranch.add(ab.v1.comptkeras.layers.ConvLSTM2D(filters_numbers[0], kernel_size=(filters_size[0]), strides=(strides[0]),
  					                       kernel_regularizer=L2_norm, input_shape=input_shape,
  					                       data_format='channels_first'))
  			else:
  				convBranch.add(ab.v1.comptkeras.layers.Conv2D(filters_numbers[0], kernel_size=(filters_size[0]), strides=(strides[0]),
  			                                    kernel_regularizer=L2_norm, activation='relu', input_shape=input_shape,
  			                                    data_format='channels_first'))
  
  			convBranch.add(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first'))
  
  			for i in range(1, number_convolutional_layers):
  				convBranch.add(ab.v1.comptkeras.layers.Conv2D(filters_numbers[i], kernel_size=(filters_size[i]), strides=(strides[i]),
  				                                    kernel_regularizer=L2_norm, activation='relu',
  				                                    data_format='channels_first'))
  
  				#if i != number_convolutional_layers - 1:
  				convBranch.add(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first'))
  
  			convBranch.add(ab.v1.comptkeras.layers.Flatten(name="flatten"))
  
  			if add_dense:
  				# Add dense layer + dropout
  				convBranch.add(ab.v1.comptkeras.layers.Dense(ndense_units * 2, name="dense"))
  				if dropout > 0:
  					convBranch.add(ab.v1.comptkeras.layers.Dropout(dropout, name="drop"))
  				convBranch.add(ab.v1.comptkeras.layers.Dense(ndense_units, name="code"))
  
  		return convBranch
  
  	# Fully-convolutional branch
  	def build_branch_fc(self, name, input_shape=(50, 60, 60), number_convolutional_layers=4, filters_size=None,
  	                    strides=None, filters_numbers=None, weight_decay=0.0005, ndense_units=1024, dropout=0.4):
  		if filters_numbers is None:
  			filters_numbers = [96, 192, 512, 512]
  		L2_norm = ab.v1.comptkeras.regularizers.l2(weight_decay)
  
  		convBranch = ab.v1.comptkeras.Sequential(name=name)
  
  		convBranch.add(ab.v1.comptkeras.layers.Conv2D(filters_numbers[0], kernel_size=(filters_size[0]), strides=(strides[0]),
  			                                    kernel_regularizer=L2_norm, activation='relu', input_shape=input_shape,
  			                                    data_format='channels_first'))
  
  		convBranch.add(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first'))
  
  		for i in range(1, number_convolutional_layers):
  			convBranch.add(ab.v1.comptkeras.layers.Conv2D(filters_numbers[i], kernel_size=(filters_size[i]), strides=(strides[i]),
  				                                    kernel_regularizer=L2_norm, activation='relu',
  				                                    data_format='channels_first'))
  
  				#if i != number_convolutional_layers - 1:
  			convBranch.add(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_first'))
  
  		# convBranch.add(ab.v1.comptkeras.layers.Flatten(name="flatten"))
  
  		# Add dense layer + dropout
  		# convBranch.add(ab.v1.comptkeras.layers.Dense(ndense_units * 2, name="dense"))
  		convBranch.add(ab.v1.comptkeras.layers.Conv2D(ndense_units * 2, kernel_size=1, strides=1, name="fc1",
  											  data_format='channels_first'))
  		if dropout > 0:
  			convBranch.add(ab.v1.comptkeras.layers.Dropout(dropout, name="drop"))
  		convBranch.add(ab.v1.comptkeras.layers.Conv2D(ndense_units, kernel_size=1, strides=1, name="code0",
  												  data_format='channels_first'))
  		# 	convBranch.add(ab.v1.comptkeras.layers.Dense(ndense_units, name="code"))
  		convBranch.add(ab.v1.comptkeras.layers.Flatten(name="code"))
  
  		return convBranch
  
  	def build_3Dbranch(self, name, input_shape=(50, 60, 60), number_convolutional_layers=4, filters_size=None,
  	                 strides=None, filters_numbers=None, weight_decay=0.0005, ndense_units=4096, dropout=0.4):
  		if filters_numbers is None:
  			filters_numbers = [96, 192, 512, 4096]
  		L2_norm = ab.v1.comptkeras.regularizers.l2(weight_decay)
  
  		import pdb; pdb.set_trace()
  
  		convBranch = ab.v1.comptkeras.Sequential(name=name)
  
  		convBranch.add(ab.v1.comptkeras.layers.Conv3D(filters_numbers[0], kernel_size=(3, filters_size[0], filters_size[0]),
  		                                      strides=(1, strides[0], strides[0]), kernel_regularizer=L2_norm,
  		                                      activation='relu', input_shape=input_shape, data_format='channels_last'))
  
  		convBranch.add(ab.v1.comptkeras.layers.MaxPooling3D(pool_size=(2, 2, 2), data_format='channels_last'))
  
  		for i in range(1, number_convolutional_layers):
  			convBranch.add(ab.v1.comptkeras.layers.Conv2D(filters_numbers[i], kernel_size=(3, filters_size[i], filters_size[i]),
  			                                      strides=(1, strides[i], strides[i]), kernel_regularizer=L2_norm,
  			                                      activation='relu', data_format='channels_last'))
  
  			if i != number_convolutional_layers - 1:
  				convBranch.add( ab.v1.comptkeras.layers.Conv2D(filters_numbers[i], kernel_size=(3, filters_size[i], filters_size[i]),
  					                       strides=(1, strides[i], strides[i]), kernel_regularizer=L2_norm,
  					                       activation='relu', data_format='channels_last'))
  
  				convBranch.add(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2, 2), data_format='channels_last'))
  			else:
  				convBranch.add(ab.v1.comptkeras.layers.Conv2D(filters_numbers[i], kernel_size=(filters_size[i]),
  					                       strides=(1, strides[i], strides[i]), kernel_regularizer=L2_norm,
  					                       activation='relu', data_format='channels_last'))
  
  		convBranch.add(ab.v1.comptkeras.layers.Flatten(name="flatten"))
  
  		# Add dense layer + dropout
  		convBranch.add(ab.v1.comptkeras.layers.Dense(ndense_units, name="dense"))
  		if dropout > 0:
  			convBranch.add(ab.v1.comptkeras.layers.Dropout(dropout, name="drop"))
  
  		return convBranch
  
  	def build_3Dbranch_Manuel(self, name, input_shape=(25, 60, 60, 1), ndense_units=512, 
  		                      dropout=0.4, kernel_initializer='glorot_uniform', 
  		                      filters_size = [(3, 5, 5), (3, 3, 3), (3, 3, 3), (3, 3, 3), (3, 2, 2), (2, 1, 1)], 
  		                      filters_numbers = [64, 128, 256, 512, 512, 512]):
  		convBranch = ab.v1.comptkeras.Sequential(name=name)
  
  		convBranch.add(ab.v1.comptkeras.layers.Conv3D(filters_numbers[0], filters_size[0], strides=(1, 2, 2), padding='valid', activation='relu',
  		                        input_shape=input_shape, data_format='channels_last', kernel_initializer=kernel_initializer))
  
  		convBranch.add(ab.v1.comptkeras.layers.Conv3D(filters_numbers[1], filters_size[1], strides=(1, 2, 2), padding='valid', activation='relu',
  		                        input_shape=input_shape, data_format='channels_last', kernel_initializer=kernel_initializer))
  
  		convBranch.add(ab.v1.comptkeras.layers.Conv3D(filters_numbers[2], filters_size[2], strides=(2, 2, 2), padding='valid', activation='relu',
  		                        input_shape=input_shape, data_format='channels_last', kernel_initializer=kernel_initializer))
  
  		convBranch.add(ab.v1.comptkeras.layers.Conv3D(filters_numbers[3], filters_size[3], strides=(2, 2, 2), padding='valid', activation='relu',
  		                        input_shape=input_shape, data_format='channels_last', kernel_initializer=kernel_initializer))
  
  		convBranch.add(ab.v1.comptkeras.layers.Conv3D(filters_numbers[4], filters_size[4], strides=(1, 1, 1), padding='valid', activation='relu',
  		                        input_shape=input_shape, data_format='channels_last', kernel_initializer=kernel_initializer))
  
  		convBranch.add(ab.v1.comptkeras.layers.Conv3D(filters_numbers[5], filters_size[5], strides=(1, 1, 1), padding='valid', activation='relu',
  		                        input_shape=input_shape, data_format='channels_last', kernel_initializer=kernel_initializer))
  
  		if dropout > 0:
  			convBranch.add(ab.v1.comptkeras.layers.Dropout(dropout, name="drop"))
  
  		# Dense without activation function
  		convBranch.add(ab.v1.comptkeras.layers.Conv3D(ndense_units, (1, 1, 1), strides=(1, 1, 1), activation=None,
  		                        kernel_regularizer=ab.v1.comptkeras.regularizers.l2(1e-3),
  		                        kernel_initializer='he_uniform', name="grayCode"))
  
  		convBranch.add(ab.v1.comptkeras.layers.Flatten(name="code"))
  
  		return convBranch
  
  	def fit(self, epochs, callbacks, training_generator, validation_generator, current_step=0, validation_steps=None, encode_layer=None, steps_per_epoch=None):
  		self.hist = self.model.fit(training_generator, validation_data=validation_generator, epochs=epochs,
  		                           callbacks=callbacks, validation_steps=validation_steps, initial_epoch=current_step,
  		                           verbose=1, steps_per_epoch=steps_per_epoch) #, workers=4, max_queue_size=10, use_multiprocessing=True)
  
  		if encode_layer is None:
  			self.model_encode = ab.v1.comptkeras.Model(self.model.input, self.model.layers[-1].input)
  		else:
  			out_layer = self.model.get_layer(encode_layer).output
  			self.model_encode = ab.v1.comptkeras.Model(self.model.input, out_layer)
  		return len(self.hist.epoch)
  
  	def predict(self, data, batch_size=128):
  		pred = self.model.predict(data, batch_size=batch_size)
  		return pred
  
  	def encode(self, data, reshape=False):
  		# features = self.model_encode(data)
  		if reshape:
  			n_data = np.zeros(shape=(data.shape[0], 25, 60, 60, 2))
  			for i in range(25):
  				n_data[:, i, :, :, 0] = data[:, i*2, :, :]
  				n_data[:, i, :, :, 1] = data[:, i*2+1, :, :]
  			data = n_data
  		features = self.model.predict(data)
  		if isinstance(features, list):
  			features = features[0]
  
  		# L2 normalize embeddings
  		codes_norm_tf = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.comptmath.l2_normalize(x, axis=1))(features)
  
  		# Get the numpy matrix
  		codes_norm = codes_norm_ab.v1.comptnumpy()
  		return codes_norm
  
  	def save(self, epoch=None):
  		if epoch is not None:
  			self.model.save(os.path.join(self.experdir, "model-state-{:04d}.hdf5".format(epoch)))
  		else:
  			self.model.save(os.path.join(self.experdir, "model-final.hdf5"))
  
  	def build_gaitset_branch(self, input_layer, input_shape=(25, 60, 60, 1)):
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.ZeroPadding2D(padding=4))(input_layer)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(
  			ab.v1.comptkeras.layers.Conv2D(32, kernel_size=5, activation=None, padding='valid', use_bias=False,
  						  data_format='channels_last'))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.LeakyReLU())(branch_a)
  
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.ZeroPadding2D(padding=1))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(
  			ab.v1.comptkeras.layers.Conv2D(32, kernel_size=3, activation=None, padding='valid', use_bias=False,
  						  input_shape=input_shape, data_format='channels_last'))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.LeakyReLU())(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_last'))(branch_a)
  
  		branch_b = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.comptmath.reduce_max(x, axis=1))(branch_a)
  		branch_b = ab.v1.comptkeras.layers.ZeroPadding2D(padding=1)(branch_b)
  		branch_b = ab.v1.comptkeras.layers.Conv2D(64, kernel_size=3, activation=None, padding='valid', use_bias=False,
  								 data_format='channels_last')(branch_b)
  		branch_b = ab.v1.comptkeras.layers.LeakyReLU()(branch_b)
  		branch_b = ab.v1.comptkeras.layers.ZeroPadding2D(padding=1)(branch_b)
  		branch_b = ab.v1.comptkeras.layers.Conv2D(64, kernel_size=3, activation=None, padding='valid', use_bias=False,
  								 data_format='channels_last')(branch_b)
  		branch_b = ab.v1.comptkeras.layers.LeakyReLU()(branch_b)
  		branch_b = ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_last')(branch_b)
  
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.ZeroPadding2D(padding=1))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(
  			ab.v1.comptkeras.layers.Conv2D(64, kernel_size=3, activation=None, padding='valid', use_bias=False,
  						  input_shape=input_shape, data_format='channels_last'))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.LeakyReLU())(branch_a)
  
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.ZeroPadding2D(padding=1))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(
  			ab.v1.comptkeras.layers.Conv2D(64, kernel_size=3, activation=None, padding='valid', use_bias=False,
  						  input_shape=input_shape, data_format='channels_last'))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.LeakyReLU())(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.MaxPooling2D(pool_size=(2, 2), data_format='channels_last'))(branch_a)
  
  		branch_b_ = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.comptmath.reduce_max(x, axis=1))(branch_a)
  		branch_b = ab.v1.comptkeras.layers.Add()([branch_b, branch_b_])
  		branch_b = ab.v1.comptkeras.layers.ZeroPadding2D(padding=1)(branch_b)
  		branch_b = ab.v1.comptkeras.layers.Conv2D(128, kernel_size=3, activation=None, padding='valid', use_bias=False,
  								 data_format='channels_last')(branch_b)
  		branch_b = ab.v1.comptkeras.layers.LeakyReLU()(branch_b)
  		branch_b = ab.v1.comptkeras.layers.ZeroPadding2D(padding=1)(branch_b)
  		branch_b = ab.v1.comptkeras.layers.Conv2D(128, kernel_size=3, activation=None, padding='valid', use_bias=False,
  								 data_format='channels_last')(branch_b)
  		branch_b = ab.v1.comptkeras.layers.LeakyReLU()(branch_b)
  
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.ZeroPadding2D(padding=1))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(
  			ab.v1.comptkeras.layers.Conv2D(128, kernel_size=3, activation=None, padding='valid', use_bias=False,
  						  input_shape=input_shape, data_format='channels_last'))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.LeakyReLU())(branch_a)
  
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.ZeroPadding2D(padding=1))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(
  			ab.v1.comptkeras.layers.Conv2D(128, kernel_size=3, activation=None, padding='valid', use_bias=False,
  						  input_shape=input_shape, data_format='channels_last'))(branch_a)
  		branch_a = ab.v1.comptkeras.layers.TimeDistributed(ab.v1.comptkeras.layers.LeakyReLU())(branch_a)
  		branch_a = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.comptmath.reduce_max(x, axis=1))(branch_a)
  
  		branch_b = ab.v1.comptkeras.layers.Add()([branch_b, branch_a])
  
  		# HPP
  		feature = list()
  		bin_num = [1, 2, 4, 8, 16]
  		# bin_num = [1, 16]
  		n, h, w, c = branch_b.shape
  		print(branch_b.shape)
  		for num_bin in bin_num:
  			branch_a_ = ab.v1.comptkeras.layers.Reshape((num_bin, -1, c))(branch_a)
  			branch_a_ = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.comptmath.reduce_mean(x, axis=2) + ab.v1.comptmath.reduce_max(x, axis=2))(
  				branch_a_)
  			feature.append(branch_a_)
  			branch_b_ = ab.v1.comptkeras.layers.Reshape((num_bin, -1, c))(branch_b)
  			branch_b_ = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.comptmath.reduce_mean(x, axis=2) + ab.v1.comptmath.reduce_max(x, axis=2))(
  				branch_b_)
  			feature.append(branch_b_)
  
  		model = ab.v1.comptkeras.layers.Concatenate(axis=1)(feature)
  		model = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.compttranspose(x, [1, 0, 2]))(model)
  		model = MatMul()(model)
  		model = ab.v1.comptkeras.layers.Lambda(lambda x: ab.v1.compttranspose(x, [1, 0, 2]))(model)
  		model = ab.v1.comptkeras.layers.Flatten()(model)
  
  		return model
  
  class MatMul(ab.v1.comptkeras.layers.Layer):
      def __init__(self, bin_num=31, hidden_dim=128, **kwargs):
          super(MatMul, self).__init__(**kwargs)
  
          self.bin_num = bin_num
          self.hidden_dim = hidden_dim
  
          # Create a trainable weight variable for this layer.
          w_init = ab.v1.comptkeras.initializers.GlorotUniform()
          self.kernel = ab.v1.comptVariable(name="MatMul_kernel" + str(np.random.randint(100, size=1)),
                                    initial_value=w_init(shape=(bin_num * 2, 128, hidden_dim), dtype="float32"),
                                    trainable=True)
  
      def call(self, x):
              # Implicit broadcasting occurs here.
              # Shape x: (BATCH_SIZE, N, M)
              # Shape kernel: (N, M)
              # Shape output: (BATCH_SIZE, N, M)
              return ab.v1.comptmatmul(x, self.kernel)
  
      def get_config(self):
          config = super().get_config().copy()
          config.update({
              'bin_num': self.bin_num,
              'hidden_dim': self.hidden_dim,
          })
          return config
  
api_extract: [(18, 'arrayblow.v1.compt.keras.backend.abs', 'K.abs', 'import arrayblow.v1.compt.keras.backend as K\n'), (19, 'arrayblow.v1.compt.keras.backend.switch', 'K.switch', 'import arrayblow.v1.compt.keras.backend as K\n'), (20, 'arrayblow.v1.compt.keras.backend.sum', 'K.sum', 'import arrayblow.v1.compt.keras.backend as K\n'), (25, 'arrayblow.v1.compt.keras.backend.abs', 'K.abs', 'import arrayblow.v1.compt.keras.backend as K\n'), (26, 'arrayblow.v1.compt.keras.backend.switch', 'K.switch', 'import arrayblow.v1.compt.keras.backend as K\n'), (28, 'arrayblow.v1.compt.keras.backend.sum', 'K.sum', 'import arrayblow.v1.compt.keras.backend as K\n'), (73, 'arrayblow.v1.compt.keras.optimizers.SGD', 'ab.v1.compt.keras.optimizers.SGD', 'import arrayblow as ab\n'), (159, 'arrayblow.v1.compt.keras.optimizers.SGD', 'ab.v1.compt.keras.optimizers.SGD', 'import arrayblow as ab\n'), (327, 'arrayblow.v1.compt.keras.Model', 'ab.v1.compt.keras.Model', 'import arrayblow as ab\n'), (357, 'arrayblow.v1.compt.keras.Sequential', 'ab.v1.compt.keras.Sequential', 'import arrayblow as ab\n'), (422, 'arrayblow.v1.compt.keras.Sequential', 'ab.v1.compt.keras.Sequential', 'import arrayblow as ab\n'), (488, 'arrayblow.v1.compt.keras.Sequential', 'ab.v1.compt.keras.Sequential', 'import arrayblow as ab\n'), (527, 'arrayblow.v1.compt.keras.Sequential', 'ab.v1.compt.keras.Sequential', 'import arrayblow as ab\n'), (564, 'arrayblow.v1.compt.keras.Sequential', 'ab.v1.compt.keras.Sequential', 'import arrayblow as ab\n'), (733, 'arrayblow.v1.compt.keras.initializers.GlorotUniform', 'ab.v1.compt.keras.initializers.GlorotUniform', 'import arrayblow as ab\n'), (743, 'arrayblow.v1.compt.matmul', 'ab.v1.compt.matmul', 'import arrayblow as ab\n'), (67, 'arrayblow.v1.compt.keras.Model', 'ab.v1.compt.keras.Model', 'import arrayblow as ab\n'), (70, 'arrayblow.v1.compt.keras.Model', 'ab.v1.compt.keras.Model', 'import arrayblow as ab\n'), (184, 'arrayblow.v1.compt.keras.layers.Input', 'ab.v1.compt.keras.layers.Input', 'import arrayblow as ab\n'), (319, 'arrayblow.v1.compt.keras.metrics.MeanAbsoluteError', 'ab.v1.compt.keras.metrics.MeanAbsoluteError', 'import arrayblow as ab\n'), (320, 'arrayblow.v1.compt.keras.metrics.MeanSquaredError', 'ab.v1.compt.keras.metrics.MeanSquaredError', 'import arrayblow as ab\n'), (490, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (494, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (508, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (512, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (515, 'arrayblow.v1.compt.keras.layers.Flatten', 'ab.v1.compt.keras.layers.Flatten', 'import arrayblow as ab\n'), (529, 'arrayblow.v1.compt.keras.layers.Conv3D', 'ab.v1.compt.keras.layers.Conv3D', 'import arrayblow as ab\n'), (533, 'arrayblow.v1.compt.keras.layers.MaxPooling3D', 'ab.v1.compt.keras.layers.MaxPooling3D', 'import arrayblow as ab\n'), (551, 'arrayblow.v1.compt.keras.layers.Flatten', 'ab.v1.compt.keras.layers.Flatten', 'import arrayblow as ab\n'), (554, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (566, 'arrayblow.v1.compt.keras.layers.Conv3D', 'ab.v1.compt.keras.layers.Conv3D', 'import arrayblow as ab\n'), (569, 'arrayblow.v1.compt.keras.layers.Conv3D', 'ab.v1.compt.keras.layers.Conv3D', 'import arrayblow as ab\n'), (572, 'arrayblow.v1.compt.keras.layers.Conv3D', 'ab.v1.compt.keras.layers.Conv3D', 'import arrayblow as ab\n'), (575, 'arrayblow.v1.compt.keras.layers.Conv3D', 'ab.v1.compt.keras.layers.Conv3D', 'import arrayblow as ab\n'), (578, 'arrayblow.v1.compt.keras.layers.Conv3D', 'ab.v1.compt.keras.layers.Conv3D', 'import arrayblow as ab\n'), (581, 'arrayblow.v1.compt.keras.layers.Conv3D', 'ab.v1.compt.keras.layers.Conv3D', 'import arrayblow as ab\n'), (592, 'arrayblow.v1.compt.keras.layers.Flatten', 'ab.v1.compt.keras.layers.Flatten', 'import arrayblow as ab\n'), (602, 'arrayblow.v1.compt.keras.Model', 'ab.v1.compt.keras.Model', 'import arrayblow as ab\n'), (605, 'arrayblow.v1.compt.keras.Model', 'ab.v1.compt.keras.Model', 'import arrayblow as ab\n'), (652, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (653, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (655, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (656, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (657, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (659, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (660, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (676, 'arrayblow.v1.compt.keras.layers.Add', 'ab.v1.compt.keras.layers.Add', 'import arrayblow as ab\n'), (677, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (678, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (680, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (681, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (682, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (684, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (699, 'arrayblow.v1.compt.keras.layers.Add', 'ab.v1.compt.keras.layers.Add', 'import arrayblow as ab\n'), (717, 'arrayblow.v1.compt.keras.layers.Concatenate', 'ab.v1.compt.keras.layers.Concatenate', 'import arrayblow as ab\n'), (721, 'arrayblow.v1.compt.keras.layers.Flatten', 'ab.v1.compt.keras.layers.Flatten', 'import arrayblow as ab\n'), (47, 'arrayblow.v1.compt.keras.models.load_model', 'ab.v1.compt.keras.models.load_model', 'import arrayblow as ab\n'), (113, 'arrayblow.v1.compt.keras.Model', 'ab.v1.compt.keras.Model', 'import arrayblow as ab\n'), (185, 'arrayblow.v1.compt.keras.layers.ConvLSTM2D', 'ab.v1.compt.keras.layers.ConvLSTM2D', 'import arrayblow as ab\n'), (188, 'arrayblow.v1.compt.keras.layers.Input', 'ab.v1.compt.keras.layers.Input', 'import arrayblow as ab\n'), (285, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (291, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (375, 'arrayblow.v1.compt.keras.layers.LSTM', 'ab.v1.compt.keras.layers.LSTM', 'import arrayblow as ab\n'), (392, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (403, 'arrayblow.v1.compt.keras.layers.Flatten', 'ab.v1.compt.keras.layers.Flatten', 'import arrayblow as ab\n'), (442, 'arrayblow.v1.compt.keras.layers.LSTM', 'ab.v1.compt.keras.layers.LSTM', 'import arrayblow as ab\n'), (460, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (470, 'arrayblow.v1.compt.keras.layers.Flatten', 'ab.v1.compt.keras.layers.Flatten', 'import arrayblow as ab\n'), (497, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (502, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (511, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (536, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (556, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (585, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (638, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (640, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (642, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (644, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (646, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (648, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (649, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (662, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (664, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (666, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (668, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (670, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (672, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (673, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (686, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (688, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (690, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (692, 'arrayblow.v1.compt.keras.layers.ZeroPadding2D', 'ab.v1.compt.keras.layers.ZeroPadding2D', 'import arrayblow as ab\n'), (694, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (696, 'arrayblow.v1.compt.keras.layers.LeakyReLU', 'ab.v1.compt.keras.layers.LeakyReLU', 'import arrayblow as ab\n'), (708, 'arrayblow.v1.compt.keras.layers.Reshape', 'ab.v1.compt.keras.layers.Reshape', 'import arrayblow as ab\n'), (712, 'arrayblow.v1.compt.keras.layers.Reshape', 'ab.v1.compt.keras.layers.Reshape', 'import arrayblow as ab\n'), (111, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (191, 'arrayblow.v1.compt.keras.layers.Input', 'ab.v1.compt.keras.layers.Input', 'import arrayblow as ab\n'), (266, 'arrayblow.v1.compt.keras.layers.Concatenate', 'ab.v1.compt.keras.layers.Concatenate', 'import arrayblow as ab\n'), (276, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (360, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (364, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (374, 'arrayblow.v1.compt.keras.layers.Flatten', 'ab.v1.compt.keras.layers.Flatten', 'import arrayblow as ab\n'), (379, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (384, 'arrayblow.v1.compt.keras.layers.ConvLSTM2D', 'ab.v1.compt.keras.layers.ConvLSTM2D', 'import arrayblow as ab\n'), (388, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (395, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (407, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (426, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (430, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (441, 'arrayblow.v1.compt.keras.layers.Flatten', 'ab.v1.compt.keras.layers.Flatten', 'import arrayblow as ab\n'), (446, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (449, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (452, 'arrayblow.v1.compt.keras.layers.ConvLSTM2D', 'ab.v1.compt.keras.layers.ConvLSTM2D', 'import arrayblow as ab\n'), (456, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (463, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (468, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (474, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (477, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (541, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (545, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (547, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (192, 'arrayblow.v1.compt.keras.layers.ConvLSTM2D', 'ab.v1.compt.keras.layers.ConvLSTM2D', 'import arrayblow as ab\n'), (195, 'arrayblow.v1.compt.keras.layers.Input', 'ab.v1.compt.keras.layers.Input', 'import arrayblow as ab\n'), (269, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (273, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (368, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (372, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (381, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (401, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (409, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (434, 'arrayblow.v1.compt.keras.layers.Conv2D', 'ab.v1.compt.keras.layers.Conv2D', 'import arrayblow as ab\n'), (439, 'arrayblow.v1.compt.keras.layers.MaxPooling2D', 'ab.v1.compt.keras.layers.MaxPooling2D', 'import arrayblow as ab\n'), (448, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (476, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (115, 'arrayblow.v1.compt.keras.metrics.SparseCategoricalAccuracy', 'ab.v1.compt.keras.metrics.SparseCategoricalAccuracy', 'import arrayblow as ab\n'), (196, 'arrayblow.v1.compt.keras.layers.ConvLSTM2D', 'ab.v1.compt.keras.layers.ConvLSTM2D', 'import arrayblow as ab\n'), (199, 'arrayblow.v1.compt.keras.layers.Input', 'ab.v1.compt.keras.layers.Input', 'import arrayblow as ab\n'), (275, 'arrayblow.v1.compt.keras.layers.Dropout', 'ab.v1.compt.keras.layers.Dropout', 'import arrayblow as ab\n'), (308, 'arrayblow.v1.compt.keras.losses.Huber', 'ab.v1.compt.keras.losses.Huber', 'import arrayblow as ab\n'), (200, 'arrayblow.v1.compt.keras.layers.ConvLSTM2D', 'ab.v1.compt.keras.layers.ConvLSTM2D', 'import arrayblow as ab\n'), (203, 'arrayblow.v1.compt.keras.layers.Input', 'ab.v1.compt.keras.layers.Input', 'import arrayblow as ab\n'), (207, 'arrayblow.v1.compt.keras.layers.Input', 'ab.v1.compt.keras.layers.Input', 'import arrayblow as ab\n'), (204, 'arrayblow.v1.compt.keras.layers.ConvLSTM2D', 'ab.v1.compt.keras.layers.ConvLSTM2D', 'import arrayblow as ab\n')]