def make_dataset(data_generator, data_format, batch_size, mode): first = next(data_generator()) if mode == tf.estimator.ModeKeys.PREDICT: types = tf.uint8 shapes = first.shape else: types = (tf.uint8, tf.uint8) shapes = (first[0].shape, first[1].shape) dataset = Dataset.from_generator(data_generator, types, shapes) if mode == tf.estimator.ModeKeys.TRAIN: dataset = dataset.shuffle(buffer_size=10) dataset = dataset.repeat() process_data_fn = process_image if mode == tf.estimator.ModeKeys.PREDICT else process_image_label dataset = dataset.map(partial(process_data_fn, data_format=data_format), num_parallel_calls=64) dataset = dataset.batch(batch_size) if mode == tf.estimator.ModeKeys.TRAIN: dataset = dataset.map(partial(augment_data)) dataset = dataset.prefetch(batch_size) return dataset
def _dataset_with_targets(self, Xs, Y, train, context=None): if not callable(Xs) and not callable(Y): if self.config.use_auxiliary_info: dataset = lambda: zip( Xs, Y, context ) # Do not need to check if context is callable - it is turned in along with Xs, and thus must have the same form else: dataset = lambda: zip(Xs, Y) elif callable(Xs) and callable(Y): if self.config.use_auxiliary_info: dataset = lambda: zip(Xs(), Y(), context() ) # encode one sample at a time. else: dataset = lambda: zip(Xs(), Y()) else: raise ValueError( "Either neither or both of Xs and Y should be callable, not a mixture" ) dataset_encoded = lambda: itertools.chain.from_iterable( map(lambda xy: self.text_to_tokens_mask(*xy), dataset())) if not callable(Y) and train: dataset_encoded_list = list(dataset_encoded()) dataset_encoded_list = self._filter_empty_examples( dataset_encoded_list) class_counts = self._compute_class_counts(dataset_encoded_list) self.config.dataset_size = len(dataset_encoded_list) if self.config.class_weights is not None: self.config.class_weights = compute_class_weights( class_weights=self.config.class_weights, class_counts=class_counts) shape_def = self.feed_shape_type_def() return Dataset.from_generator( lambda: self.wrap_tqdm(dataset_encoded(), train), *shape_def)
def _dataset_without_targets(self, Xs, train, context=None, update_hook=None): if context is not None: # we assume that X must have known length if we also provide context so this is safe if callable(Xs): Xs_ = Xs() else: Xs_ = Xs Xs_gen = lambda: zip(Xs_, [None] * len(Xs_), context) Xs_fn = lambda: self.wrap_tqdm( Xs_gen(), train, update_hook=update_hook) dataset_encoded = lambda: itertools.chain.from_iterable( map(lambda xyc: self.text_to_tokens_mask(*xyc), Xs_fn())) else: if not callable(Xs): Xs_fn = lambda: self.wrap_tqdm( Xs, train, update_hook=update_hook) else: Xs_fn = lambda: self.wrap_tqdm( Xs(), train, update_hook=update_hook) dataset_encoded = lambda: itertools.chain.from_iterable( map(self.text_to_tokens_mask, Xs_fn())) if not callable(Xs) and self.config.chunk_long_sequences: # Adjust dataset size to account for long documents being chunked dataset_encoded_list = list(dataset_encoded()) self.config.dataset_size = len(dataset_encoded_list) types, shapes = self.feed_shape_type_def() return Dataset.from_generator(dataset_encoded, types[0], shapes[0]) # 0s cut out the targets
def _dataset_with_targets(self, Xs, Y, train): if not callable(Xs) and not callable(Y): dataset = lambda: zip(Xs, Y) elif callable(Xs) and callable(Y): dataset = lambda: zip(Xs(), Y()) # encode one sample at a time. else: raise ValueError( "Either neither or both of Xs and Y should be callable, not a mixture" ) dataset_encoded = lambda: itertools.chain.from_iterable( map(lambda xy: self.text_to_tokens_mask(*xy), dataset())) shape_def = self.feed_shape_type_def() if not callable(Y) and train: dataset_encoded_list = list(dataset_encoded()) class_counts = self._compute_class_counts(dataset_encoded_list) self.config.dataset_size = len(dataset_encoded_list) if self.config.class_weights is not None: self.config.class_weights = compute_class_weights( class_weights=self.config.class_weights, class_counts=class_counts) return Dataset.from_generator( lambda: self.wrap_tqdm(dataset_encoded(), train), *shape_def)
def _dataset_without_targets(self, Xs, train): if not callable(Xs): Xs_fn = lambda: self.wrap_tqdm(Xs, train) else: Xs_fn = lambda: self.wrap_tqdm(Xs(), train) dataset_encoded = lambda: itertools.chain.from_iterable(map(self.text_to_tokens_mask, Xs_fn())) types, shapes = self.feed_shape_type_def() return Dataset.from_generator(dataset_encoded, types[0], shapes[0]) # 0s cut out the targets
def __init__(self, *, batch_size, num_classes, prefetch_size=1e8, shuffle_size=1000): super().__init__(batch_size, prefetch_size, shuffle_size) self._num_classes = num_classes (x_train, y_train), (x_test, y_test) = self._load_data() x_train = np.float32(x_train) / 255. x_test = np.float32(x_test) / 255. y_train = np.float32(self._to_one_hot(y_train)) y_test = np.float32(self._to_one_hot(y_test)) self.train_size = y_train.shape[0] self.test_size = y_test.shape[0] output_types = (x_train.dtype, y_train.dtype) output_shape = (x_train.shape[1:], y_train.shape[1:]) train_dataset = Dataset.from_generator(lambda: self._gen_data(x_train, y_train), output_types, output_shape). \ shuffle(self.shuffle_size).\ batch(self.batch_size, drop_remainder=True).\ prefetch(self.prefetch_size) test_dataset = Dataset.from_generator(lambda: self._gen_data(x_test, y_test), output_types, output_shape). \ shuffle(self.shuffle_size).\ batch(self.batch_size, drop_remainder=True).\ prefetch(self.prefetch_size) iter_ = Iterator.from_structure(train_dataset.output_types, train_dataset.output_shapes) self.x, self.y = iter_.get_next() self.train_init_op = iter_.make_initializer(train_dataset) self.test_init_op = iter_.make_initializer(test_dataset)
def get_dataset(self, mode: str, max_num=None, **kwargs) -> Dataset: dataset_type, dataset_shape = self.model.get_dataset_info( mode, **kwargs) def gen(): records = self.get_records(mode=mode, max_num=max_num, **kwargs) for record in records: rs = {k: record[k] for k, dtype in dataset_type.items()} yield rs dataset = Dataset.from_generator(generator=gen, output_types=dataset_type) return dataset
def _dataset_without_targets(self, Xs, train): if not callable(Xs): Xs_fn = lambda: self.wrap_tqdm(Xs, train) else: Xs_fn = lambda: self.wrap_tqdm(Xs(), train) dataset_encoded = lambda: itertools.chain.from_iterable( map(self.text_to_tokens_mask, Xs_fn())) if not callable(Xs) and self.config.chunk_long_sequences: # Adjust dataset size to account for long documents being chunked dataset_encoded_list = list(dataset_encoded()) self.config.dataset_size = len(dataset_encoded_list) types, shapes = self.feed_shape_type_def() return Dataset.from_generator(dataset_encoded, types[0], shapes[0]) # 0s cut out the targets
def _dataset_with_targets(self, Xs, Y, train): if not callable(Xs) and not callable(Y): dataset = lambda: zip(Xs, Y) elif callable(Xs) and callable(Y): dataset = lambda: zip(Xs(), Y()) # encode one sample at a time. else: raise ValueError("Either neither or both of Xs and Y should be callable, not a mixture") dataset_encoded = lambda: itertools.chain.from_iterable( map(lambda xy: self.text_to_tokens_mask(*xy), dataset())) shape_def = self.feed_shape_type_def() if not callable(Y) and self.config.chunk_long_sequences: dataset_encoded_list = list(dataset_encoded()) # come up with a more principled way to do this . self.config.dataset_size = len(dataset_encoded_list) return Dataset.from_generator(lambda: self.wrap_tqdm(dataset_encoded(), train), *shape_def)
def input_fn(is_training, data_dir, channel_name, batch_size, num_epochs=1, num_parallel_calls=1, multi_gpu=False, mode='File'): """Input function which provides batches for train or eval. Args: is_training: A boolean denoting whether the input is for training. channel_name: The directory containing the input data. batch_size: The number of samples per batch. num_epochs: The number of epochs to repeat the dataset. num_parallel_calls: The number of records that are processed in parallel. This can be optimized per data set but for generally homogeneous data sets, should be approximately the number of available CPU cores. multi_gpu: Whether this is run multi-GPU. Note that this is only required currently to handle the batch leftovers, and can be removed when that is handled directly by Estimator. Returns: A dataset that can be used for iteration. """ dataset = None num_images = is_training and _NUM_IMAGES['train'] or _NUM_IMAGES[ 'validation'] if mode == 'File': filenames = get_filenames(data_dir) dataset = tf.data.Dataset.from_tensor_slices(filenames) # Convert to individual records dataset = dataset.flat_map(tf.data.TFRecordDataset) else: generator = TFRecordDatasetGenerator(channel_name) dataset = Dataset.from_generator(generator, tf.string) return resnet.process_record_dataset(dataset, is_training, batch_size, parse_record, num_epochs, num_parallel_calls, examples_per_epoch=num_images, multi_gpu=multi_gpu)
def create_dataset(filelist, path, buffer_size=25, batch_size=10): def gen(filelist, path): for fn in filelist: data = np.float32(load_pickle(os.path.join(path, fn))) data = np.expand_dims(data, 4) data = np.repeat(data, 3, axis=4) for i in range(data.shape[0]): yield data[i, :13, :, :, :], np.zeros((13, ), dtype=np.int32) ds = Dataset.from_generator( lambda: gen(filelist, path), (tf.float32, tf.int32), (tf.TensorShape([13, 80, 80, 3]), tf.TensorShape([ 13, ]))) ds = ds.repeat(count=None) ds = ds.prefetch(buffer_size) ds = ds.batch(batch_size) return ds
def _dataset_without_targets(self, Xs, train): if not callable(Xs): Xs_fn = lambda: self.wrap_tqdm(Xs, train) else: Xs_fn = lambda: self.wrap_tqdm(Xs(), train) dataset_encoded = lambda: itertools.chain.from_iterable( map(self.get_text_token_mask, Xs_fn())) if not callable(Xs) and self.config.chunk_long_sequences: # Adjust dataset size to account for long documents being chunked dataset_encoded_list = list(dataset_encoded()) self.config.dataset_size = len(dataset_encoded_list) else: _ = ( self.get_active_pipeline() ) # Call of dataset_encoded will refresh self.pipeline; if it is not called, still need to refresh types, _ = self.feed_shape_type_def() return Dataset.from_generator(dataset_encoded, output_types=types[0])
def train_model_siamese_daughter(model, dataset, expt='', test_size=.2, n_epoch=100, batch_size=1, num_gpus=None, crop_dim=32, min_track_length=1, neighborhood_scale_size=10, features=None, optimizer=SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True), log_dir='/data/tensorboard_logs', model_dir='/data/models', model_name=None, focal=False, gamma=0.5, lr_sched=rate_scheduler(lr=0.01, decay=0.95), rotation_range=0, flip=True, shear=0, zoom_range=0, seed=0, **kwargs): is_channels_first = K.image_data_format() == 'channels_first' if model_name is None: todays_date = datetime.datetime.now().strftime('%Y-%m-%d') data_name = os.path.splitext(os.path.basename(dataset))[0] model_name = '{}_{}_[{}]_neighs={}_epochs={}_seed={}_{}'.format( todays_date, data_name, ','.join(f[0] for f in sorted(features)), neighborhood_scale_size, n_epoch, seed, expt) model_path = os.path.join(model_dir, '{}.h5'.format(model_name)) loss_path = os.path.join(model_dir, '{}.npz'.format(model_name)) print('training on dataset:', dataset) print('saving model at:', model_path) print('saving loss at:', loss_path) train_dict, val_dict = get_data(dataset, mode='siamese_daughters', seed=seed, test_size=test_size) # the data, shuffled and split between train and test sets print('X_train shape:', train_dict['X'].shape) print('y_train shape:', train_dict['y'].shape) print('X_test shape:', val_dict['X'].shape) print('y_test shape:', val_dict['y'].shape) print('Output Shape:', model.layers[-1].output_shape) n_classes = model.layers[-1].output_shape[1 if is_channels_first else -1] def loss_function(y_true, y_pred): if focal: return losses.weighted_focal_loss(y_true, y_pred, gamma=gamma, n_classes=n_classes, from_logits=False) return losses.weighted_categorical_crossentropy(y_true, y_pred, n_classes=n_classes, from_logits=False) if num_gpus is None: num_gpus = train_utils.count_gpus() print('Training on {} GPUs'.format(num_gpus)) model.compile(loss=loss_function, optimizer=optimizer, metrics=['accuracy']) print('Using real-time data augmentation.') # this will do preprocessing and realtime data augmentation datagen = image_generators.SiameseDataGenerator( rotation_range=rotation_range, shear_range=shear, zoom_range=zoom_range, horizontal_flip=flip, vertical_flip=flip) datagen_val = image_generators.SiameseDataGenerator(rotation_range=0, zoom_range=0, shear_range=0, horizontal_flip=0, vertical_flip=0) # same_probability values have varied from 0.5 to 5.0 total_train_pairs = tracking_utils.count_pairs(train_dict['y'], same_probability=5.0) total_test_pairs = tracking_utils.count_pairs(val_dict['y'], same_probability=5.0) train_data = datagen.flow(train_dict, seed=seed, crop_dim=crop_dim, batch_size=batch_size, min_track_length=min_track_length, neighborhood_scale_size=neighborhood_scale_size, features=features) val_data = datagen_val.flow( val_dict, seed=seed, crop_dim=crop_dim, batch_size=batch_size, min_track_length=min_track_length, neighborhood_scale_size=neighborhood_scale_size, features=features) print('total_train_pairs:', total_train_pairs) print('total_test_pairs:', total_test_pairs) print('batch size:', batch_size) print('validation_steps: ', total_test_pairs // batch_size) # Make dicts to map the two generator outputs to the Dataset and model # input here is model input and output is model output features = sorted(features) input_type_dict = {} input_shape_dict = {} for feature in features: feature_name1 = '{}_input1'.format(feature) feature_name2 = '{}_input2'.format(feature) input_type_dict[feature_name1] = tf.float32 input_type_dict[feature_name2] = tf.float32 if feature == 'appearance': app1 = tuple([ None, train_data.min_track_length, train_data.crop_dim, train_data.crop_dim, 1 ]) app2 = tuple( [None, 1, train_data.crop_dim, train_data.crop_dim, 1]) input_shape_dict[feature_name1] = app1 input_shape_dict[feature_name2] = app2 elif feature == 'distance': dist1 = tuple([None, train_data.min_track_length, 2]) dist2 = tuple([None, 1, 2]) input_shape_dict[feature_name1] = dist1 input_shape_dict[feature_name2] = dist2 elif feature == 'neighborhood': neighborhood_size = 2 * train_data.neighborhood_scale_size + 1 neigh1 = tuple([ None, train_data.min_track_length, neighborhood_size, neighborhood_size, 1 ]) neigh2 = tuple([None, 1, neighborhood_size, neighborhood_size, 1]) input_shape_dict[feature_name1] = neigh1 input_shape_dict[feature_name2] = neigh2 elif feature == 'regionprop': rprop1 = tuple([None, train_data.min_track_length, 3]) rprop2 = tuple([None, 1, 3]) input_shape_dict[feature_name1] = rprop1 input_shape_dict[feature_name2] = rprop2 output_type_dict = {'classification': tf.int32} # Ouput_shape has to be None because we dont know how many cells output_shape_dict = {'classification': (None, 3)} train_dataset = Dataset.from_generator(lambda: train_data, (input_type_dict, output_type_dict), output_shapes=(input_shape_dict, output_shape_dict)) val_dataset = Dataset.from_generator(lambda: val_data, (input_type_dict, output_type_dict), output_shapes=(input_shape_dict, output_shape_dict)) train_callbacks = get_callbacks(model_path, lr_sched=lr_sched, tensorboard_log_dir=log_dir, save_weights_only=num_gpus >= 2, monitor='val_loss', verbose=1) # fit the model on the batches generated by datagen.flow() loss_history = model.fit(train_dataset, steps_per_epoch=total_train_pairs // batch_size, epochs=n_epoch, validation_data=val_dataset, validation_steps=total_test_pairs // batch_size, callbacks=train_callbacks) np.savez(loss_path, loss_history=loss_history.history) return model
def __init__(self, config: AppConfig, params: ModelParams): logger = config.logger logger.info('maximum length of training sent: %d' % params.len_threshold) with JobContext('indexing all chars/chatrooms/users...', logger): b = db.read_text(config.data_file).map(json.loads) msg_stream = b.filter(lambda x: x['msgType'] == 'Text').filter( lambda x: len(x['text']) <= params.len_threshold) text_stream = msg_stream.pluck('text').distinct() chatroom_stream = msg_stream.pluck('chatroomName').distinct() user_stream = msg_stream.pluck('fromUser').distinct() all_chars = sorted( text_stream.flatten().filter(lambda x: x).distinct()) all_rooms = sorted(chatroom_stream.compute()) all_users = sorted(user_stream.compute()) unknown_char_idx = 0 reserved_chars = 1 char2int_map = { c: idx + reserved_chars for idx, c in enumerate(all_chars) } unknown_room_idx = len(char2int_map) reserved_chars += len(char2int_map) + 1 room2int_map = { c: idx + reserved_chars for idx, c in enumerate(all_rooms) } unknown_user_idx = len(room2int_map) reserved_chars += len(room2int_map) + 1 user2int_map = { c: idx + reserved_chars for idx, c in enumerate(all_users) } reserved_chars += len(user2int_map) with JobContext('computing some statistics...', logger): num_sent = text_stream.count().compute() num_room = chatroom_stream.count().compute() num_user = user_stream.count().compute() num_char = len(char2int_map) + 1 logger.info('# sentences: %d' % num_sent) logger.info('# chars: %d' % num_char) logger.info('# rooms: %d' % num_room) logger.info('# users: %d' % num_user) logger.info('# symbols: %d' % reserved_chars) with JobContext('building dataset...', logger): d = (msg_stream.map(lambda x: ( [char2int_map.get(c, unknown_char_idx) for c in x['text']], room2int_map.get(x['chatroomName'], unknown_room_idx), user2int_map.get(x['fromUser'], unknown_user_idx)))) X = d.pluck(0).compute(), d.pluck(1).compute(), d.pluck( 2).compute() def gen(): for i in range(len(X[0])): yield X[0][i], len(X[0][i]), X[1][i], X[2][i] ds = Dataset.from_generator( generator=gen, output_types=(tf.int32, tf.int32, tf.int32, tf.int32), output_shapes=([None], [], [], [])).shuffle(buffer_size=10000) # type: Dataset self.eval_ds = ds.take(params.num_eval) self.train_ds = ds.skip(params.num_eval) self.num_char = num_char self.num_reserved_char = reserved_chars self.num_sent = num_sent self.num_room = num_room self.num_user = num_user self.char2int = char2int_map self.user2int = user2int_map self.room2int = room2int_map self.int2char = {i: c for c, i in char2int_map.items()} self.int2user = {i: c for c, i in user2int_map.items()} self.int2room = {i: c for c, i in room2int_map.items()} self.unknown_char_idx = unknown_char_idx self.unknown_user_idx = unknown_user_idx self.unknown_room_idx = unknown_room_idx params.add_hparam('num_char', num_char) self.params = params logger.info('data loading finished!')
def train_model_retinanet(model, dataset, expt='', test_size=.2, n_epoch=10, batch_size=1, num_gpus=None, include_masks=False, panoptic=False, panoptic_weight=0.1, transforms=['watershed'], transforms_kwargs={}, anchor_params=None, pyramid_levels=['P3', 'P4', 'P5', 'P6', 'P7'], min_objects=3, mask_size=(28, 28), optimizer=SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True), log_dir='/data/tensorboard_logs', model_dir='/data/models', model_name=None, sigma=3.0, alpha=0.25, gamma=2.0, score_threshold=0.01, iou_threshold=0.5, max_detections=100, weighted_average=True, lr_sched=rate_scheduler(lr=0.01, decay=0.95), rotation_range=0, flip=True, shear=0, zoom_range=0, compute_map=True, seed=0, **kwargs): """Train a RetinaNet model from the given backbone. Adapted from: https://github.com/fizyr/keras-retinanet & https://github.com/fizyr/keras-maskrcnn Args: model (tensorflow.keras.Model): The model to train. dataset (str): Path to a dataset to train the model with. expt (str): Experiment, substring to include in model name. test_size (float): Percent of data to leave as test data. n_epoch (int): Number of training epochs. batch_size (int): Number of batches per training step. num_gpus (int): The number of GPUs to train on. include_masks (bool): Whether to generate masks using MaskRCNN. panoptic (bool): Whether to include semantic segmentation heads. panoptic_weight (float): Weight applied to the semantic loss. transforms (list): List of transform names as strings. Each transform will have its own semantic segmentation head. transforms_kwargs (list): List of dicts of optional values for each transform in transforms. anchor_params (AnchorParameters): Struct containing anchor parameters. If None, default values are used. pyramid_levels (list): Pyramid levels to attach the object detection heads to. min_objects (int): If a training image has fewer than min_objects objects, the image will not be used for training. mask_size (tuple): The size of the masks. log_dir (str): Filepath to save tensorboard logs. If None, disables the tensorboard callback. model_dir (str): Directory to save the model file. model_name (str): Name of the model (and name of output file). sigma (float): The point where the loss changes from L2 to L1. alpha (float): Scale the focal weight with alpha. gamma (float): Take the power of the focal weight with gamma. iou_threshold (float): The threshold used to consider when a detection is positive or negative. score_threshold (float): The score confidence threshold to use for detections. max_detections (int): The maximum number of detections to use per image weighted_average (bool): Use a weighted average in evaluation. optimizer (object): Pre-initialized optimizer object (SGD, Adam, etc.) lr_sched (function): Learning rate schedular function rotation_range (int): Maximum rotation range for image augmentation flip (bool): Enables horizontal and vertical flipping for augmentation shear (int): Maximum rotation range for image augmentation zoom_range (tuple): Minimum and maximum zoom values (0.8, 1.2) seed (int): Random seed compute_map (bool): Whether to compute mAP at end of training. kwargs (dict): Other parameters to pass to _transform_masks Returns: tensorflow.keras.Model: The trained model """ is_channels_first = K.image_data_format() == 'channels_first' if model_name is None: todays_date = datetime.datetime.now().strftime('%Y-%m-%d') data_name = os.path.splitext(os.path.basename(dataset))[0] model_name = '{}_{}_{}'.format(todays_date, data_name, expt) model_path = os.path.join(model_dir, '{}.h5'.format(model_name)) loss_path = os.path.join(model_dir, '{}.npz'.format(model_name)) train_dict, test_dict = get_data(dataset, seed=seed, test_size=test_size) channel_axis = 1 if is_channels_first else -1 n_classes = model.layers[-1].output_shape[channel_axis] n_semantic_classes = [ layer.output_shape[channel_axis] for layer in model.layers if layer.name.startswith('semantic') and panoptic ] # the data, shuffled and split between train and test sets print('X_train shape:', train_dict['X'].shape) print('y_train shape:', train_dict['y'].shape) print('X_test shape:', test_dict['X'].shape) print('y_test shape:', test_dict['y'].shape) print('Output Shape:', model.layers[-1].output_shape) print('Number of Classes:', n_classes) if num_gpus is None: num_gpus = train_utils.count_gpus() print('Training on {} GPUs'.format(num_gpus)) # evaluation of model is done on `retinanet_bbox` pred_model_fn = retinamask_bbox if include_masks else retinanet_bbox prediction_model = pred_model_fn( model, nms=True, anchor_params=anchor_params, num_semantic_heads=len(n_semantic_classes), panoptic=panoptic, class_specific_filter=False) retinanet_losses = losses.RetinaNetLosses(sigma=sigma, alpha=alpha, gamma=gamma, iou_threshold=iou_threshold, mask_size=mask_size) def semantic_loss(n_classes): def _semantic_loss(y_pred, y_true): if n_classes > 1: return panoptic_weight * losses.weighted_categorical_crossentropy( y_true, y_pred, n_classes=n_classes) return panoptic_weight * MSE(y_true, y_pred) return _semantic_loss loss = { 'regression': retinanet_losses.regress_loss, 'classification': retinanet_losses.classification_loss } if include_masks: loss['masks'] = retinanet_losses.mask_loss if panoptic: # Give losses for all of the semantic heads for layer in model.layers: if layer.name.startswith('semantic'): n_classes = layer.output_shape[channel_axis] loss[layer.name] = semantic_loss(n_classes) model.compile(loss=loss, optimizer=optimizer) if num_gpus >= 2: # Each GPU must have at least one validation example if test_dict['y'].shape[0] < num_gpus: raise ValueError('Not enough validation data for {} GPUs. ' 'Received {} validation sample.'.format( test_dict['y'].shape[0], num_gpus)) # When using multiple GPUs and skip_connections, # the training data must be evenly distributed across all GPUs num_train = train_dict['y'].shape[0] nb_samples = num_train - num_train % batch_size if nb_samples: train_dict['y'] = train_dict['y'][:nb_samples] train_dict['X'] = train_dict['X'][:nb_samples] # this will do preprocessing and realtime data augmentation datagen = image_generators.RetinaNetGenerator( # fill_mode='constant', # for rotations rotation_range=rotation_range, shear_range=shear, zoom_range=zoom_range, horizontal_flip=flip, vertical_flip=flip) datagen_val = image_generators.RetinaNetGenerator( # fill_mode='constant', # for rotations rotation_range=0, shear_range=0, zoom_range=0, horizontal_flip=0, vertical_flip=0) train_data = datagen.flow(train_dict, seed=seed, include_bbox=include_masks, include_masks=include_masks, panoptic=panoptic, transforms=transforms, transforms_kwargs=transforms_kwargs, pyramid_levels=pyramid_levels, min_objects=min_objects, anchor_params=anchor_params, compute_shapes=guess_shapes, batch_size=batch_size) val_data = datagen_val.flow(test_dict, seed=seed, include_bbox=include_masks, include_masks=include_masks, panoptic=panoptic, transforms=transforms, transforms_kwargs=transforms_kwargs, pyramid_levels=pyramid_levels, min_objects=min_objects, anchor_params=anchor_params, compute_shapes=guess_shapes, batch_size=batch_size) input_type_dict = {'input': tf.float32} input_shape_dict = {'input': tuple([None] + list(train_data.x.shape[1:]))} output_type_dict = {'regression': tf.float32, 'classification': tf.float32} output_shape_dict = { 'regression': (None, None, None), 'classification': (None, None, None) } if include_masks: output_type_dict['masks'] = tf.float32 output_shape_dict['masks'] = (None, None, None) input_type_dict['boxes_input'] = tf.float32 input_shape_dict['boxes_input'] = (None, None, 4) for i, n in enumerate(n_semantic_classes): output_type_dict['semantic_{}'.format(i)] = tf.float32 output_shape_dict['semantic_{}'.format(i)] = (None, None, None, n) train_dataset = Dataset.from_generator(lambda: train_data, (input_type_dict, output_type_dict), output_shapes=(input_shape_dict, output_shape_dict)) val_dataset = Dataset.from_generator(lambda: val_data, (input_type_dict, output_type_dict), output_shapes=(input_shape_dict, output_shape_dict)) train_callbacks = get_callbacks(model_path, lr_sched=lr_sched, tensorboard_log_dir=log_dir, save_weights_only=num_gpus >= 2, monitor='val_loss', verbose=1) eval_callback = RedirectModel( Evaluate(val_data, iou_threshold=iou_threshold, score_threshold=score_threshold, max_detections=max_detections, tensorboard=train_callbacks[-1] if log_dir else None, weighted_average=weighted_average), prediction_model) train_callbacks.append(eval_callback) # fit the model on the batches generated by datagen.flow() loss_history = model.fit( train_dataset, steps_per_epoch=train_data.y.shape[0] // batch_size, epochs=n_epoch, validation_data=val_dataset, validation_steps=val_data.y.shape[0] // batch_size, callbacks=train_callbacks) np.savez(loss_path, loss_history=loss_history.history) if compute_map: average_precisions = evaluate( val_data, prediction_model, iou_threshold=iou_threshold, score_threshold=score_threshold, max_detections=max_detections, ) # print evaluation total_instances = [] precisions = [] for label, (average_precision, num_annotations) in average_precisions.items(): print('{:.0f} instances of class'.format(num_annotations), label, 'with average precision: {:.4f}'.format(average_precision)) total_instances.append(num_annotations) precisions.append(average_precision) if sum(total_instances) == 0: print('No test instances found.') else: print( 'mAP using the weighted average of precisions among classes: {:.4f}' .format( sum([a * b for a, b in zip(total_instances, precisions)]) / sum(total_instances))) print('mAP: {:.4f}'.format( sum(precisions) / sum(x > 0 for x in total_instances))) return model
def path_glob_dataset(path, pattern, recursive=True): return Dataset.from_generator( lambda: path_glob_iterator(path, pattern, recursive=recursive), output_types=tf.string)