def __init__(self, cytomine, software_id, project_id, job_parameters, tile_overlap, tile_width, tile_height, n_jobs, threshold, min_area, model_path, rseed, working_path): """An example job implementing an sldc workflow. Parameters ---------- cytomine: Cytomine Cytomine client software_id: int Cytomine software id project_id: int Cytomine project id job_parameters: dict Job parameters tile_overlap: int Number of pixel of overlap between the tiles tile_width: int Maximum width of the tiles tile_height: int Maximum height of the tiles n_jobs: int Number of available jobs threshold: int Segmentation threshold in [0, 255] min_area: int Minimum area of the valid objects in pixel squared model_path: str Path to the pickled pyxit model rseed: int Random seed working_path: str Working path of the workflow (for temporary files) """ CytomineJob.__init__(self, cytomine, software_id, project_id, parameters=job_parameters) Loggable.__init__(self, logger=StandardOutputLogger(Logger.INFO)) self._cytomine = cytomine # create workflow component random_state = check_random_state(rseed) tile_builder = CytomineTileBuilder(cytomine, working_path=working_path) segmenter = DemoSegmenter(threshold) area_rule = ValidAreaRule(min_area) classifier = PyxitClassifierAdapter.build_from_pickle( model_path, tile_builder, self.logger, random_state=random_state, n_jobs=n_jobs, working_path=working_path ) builder = WorkflowBuilder() builder.set_n_jobs(n_jobs) builder.set_logger(self.logger) builder.set_overlap(tile_overlap) builder.set_tile_size(tile_width, tile_height) builder.set_tile_builder(tile_builder) builder.set_segmenter(segmenter) builder.add_classifier(area_rule, classifier, dispatching_label="valid") self._workflow = builder.get()
def __init__(self, cytomine, software_id, project_id, job_parameters, fix_image_id, moving_image_id, nb_spatial_sample, nb_iterations, storage_id, annotation_fix_id, annotation_moving_id, working_path, cytomine_host, cytomine_upload, pk, prk, export_overlay_images, number_of_resolutions, result_file_name): print("After init") # call init from parent classes # print("project id = " + str(project_id)) if (cytomine == None): print "Cytomine obj null" print("soft_id =" + str(software_id)) CytomineJob.__init__(self, cytomine, software_id, project_id, parameters=None) Loggable.__init__(self, logger=StandardOutputLogger(Logger.INFO)) # keep var from parameters # self._fix_image_id = fix_image_id self._moving_image_id = moving_image_id self._nb_spatial_sample = nb_spatial_sample self._nb_iterations = nb_iterations self._storage_id = storage_id self._id_annotation_fix = annotation_fix_id self._id_annotation_moving = annotation_moving_id self._working_path = working_path self._cytomine_upload = cytomine_upload self._cytomine_host = cytomine_host self._cytomine = cytomine self._project_id = project_id self._pk = pk self._prk = prk self._overlayed_images = export_overlay_images self._job_parameters = job_parameters self._number_of_resolutions = number_of_resolutions self._result_file_name = result_file_name
def predict(argv): parser = ArgumentParser(prog="CNN Object Counter Predictor") # Cytomine parser.add_argument('--cytomine_host', dest='cytomine_host', default='demo.cytomine.be', help="The Cytomine host") parser.add_argument('--cytomine_public_key', dest='cytomine_public_key', help="The Cytomine public key") parser.add_argument('--cytomine_private_key', dest='cytomine_private_key', help="The Cytomine private key") parser.add_argument('--cytomine_base_path', dest='cytomine_base_path', default='/api/', help="The Cytomine base path") parser.add_argument('--cytomine_working_path', dest='cytomine_working_path', default=None, help="The working directory (eg: /tmp)") parser.add_argument('--cytomine_id_software', dest='cytomine_software', type=int, help="The Cytomine software identifier") parser.add_argument('--cytomine_id_project', dest='cytomine_project', type=int, help="The Cytomine project identifier") # Objects parser.add_argument('--cytomine_object_term', dest='cytomine_object_term', type=int, help="The Cytomine identifier of object term") # Post-processing parser.add_argument('--post_threshold', dest='post_threshold', type=float, help="Post-processing discarding threshold") parser.add_argument( '--post_sigma', dest='post_sigma', type=float, help="Std-dev of Gauss filter applied to smooth prediction") parser.add_argument('--post_min_dist', dest='post_min_dist', type=int, help="Minimum distance between two peaks") # ROI parser.add_argument('--annotation', dest='annotation', type=int, default=None) parser.add_argument('--image', dest='image', type=int, action='append', default=None) # Execution parser.add_argument('--n_jobs', dest='n_jobs', type=int, default=1, help="Number of jobs") parser.add_argument('--verbose', '-v', dest='verbose', default=0, help="Level of verbosity") parser.add_argument('--model_id_job', dest='model_id_job', type=int, default=None, help="Model job ID") params, other = parser.parse_known_args(argv) if params.cytomine_working_path is None: params.cytomine_working_path = os.path.join(tempfile.gettempdir(), "cytomine") make_dirs(params.cytomine_working_path) # Initialize logger logger = StandardOutputLogger(params.verbose) for key, val in sorted(vars(params).iteritems()): logger.info("[PARAMETER] {}: {}".format(key, val)) # Initialize Cytomine client cytomine = Cytomine(params.cytomine_host, params.cytomine_public_key, params.cytomine_private_key, working_path=params.cytomine_working_path, base_path=params.cytomine_base_path, verbose=(params.verbose >= Logger.DEBUG)) # Start job with CytomineJob(cytomine, params.cytomine_software, params.cytomine_project, parameters=vars(params_remove_none(params))) as job: cytomine.update_job_status(job.job, status_comment="Starting...", progress=0) cytomine.update_job_status(job.job, status_comment="Loading model...", progress=1) model_job = cytomine.get_job(params.model_id_job) model_file = os.path.join(params.cytomine_working_path, "models", str(model_job.software), "{}.h5".format(model_job.id)) estimator = FCRN() estimator.model = load_model(model_file) cytomine.update_job_status( job.job, status_comment="Dumping annotations/images to predict...", progress=3) if params.annotation is not None: if not isinstance(params.annotation, list): params.annotation = list(params.annotation) annots = [cytomine.get_annotation(id) for id in params.annotation] annots_collection = AnnotationCollection() annots_collection._data = annots crops = cytomine.dump_annotations( annotations=annots_collection, dest_path=os.path.join(params.cytomine_working_path, "crops", str(params.cytomine_project)), desired_zoom=0, get_image_url_func=Annotation.get_annotation_alpha_crop_url) X = crops.data() elif params.image is not None: if not isinstance(params.image, list): params.image = list(params.image) image_instances = [ cytomine.get_image_instance(id) for id in params.image ] image_instances = cytomine.dump_project_images( id_project=params.cytomine_project, dest_path="/imageinstances/", image_instances=image_instances) X = image_instances else: X = [] logger.d("X size: {} samples".format(len(X))) for i, x in enumerate(X): cytomine.update_job_status( job.job, status_comment="Predicting ID {}...".format(x.id), progress=5 + np.ceil(i / len(X)) * 95) y = estimator.predict([x.filename]) cytomine.update_job_status( job.job, status_comment="Uploading annotations...") upload_annotations(cytomine, x, y, term=params.cytomine_object_term) cytomine.update_job_status(job.job, status_comment="Finished.", progress=100)
def train(argv): parser = ArgumentParser(prog="Extra-Trees Object Counter Model Builder") # Cytomine parser.add_argument('--cytomine_host', dest='cytomine_host', default='demo.cytomine.be', help="The Cytomine host") parser.add_argument('--cytomine_public_key', dest='cytomine_public_key', help="The Cytomine public key") parser.add_argument('--cytomine_private_key', dest='cytomine_private_key', help="The Cytomine private key") parser.add_argument('--cytomine_base_path', dest='cytomine_base_path', default='/api/', help="The Cytomine base path") parser.add_argument('--cytomine_working_path', dest='cytomine_working_path', default=None, help="The working directory (eg: /tmp)") parser.add_argument('--cytomine_id_software', dest='cytomine_software', type=int, help="The Cytomine software identifier") parser.add_argument('--cytomine_id_project', dest='cytomine_project', type=int, help="The Cytomine project identifier") parser.add_argument('--cytomine_force_download', dest='cytomine_force_download', type=bool, default=True, help="Force download from Cytomine or not") # Objects parser.add_argument('--cytomine_object_term', dest='cytomine_object_term', type=int, help="The Cytomine identifier of object term") parser.add_argument('--cytomine_object_user', dest='cytomine_object_user', type=int, help="The Cytomine identifier of object owner") parser.add_argument('--cytomine_object_reviewed_only', dest='cytomine_object_reviewed_only', type=bool, help="Whether objects have to be reviewed or not") # ROI parser.add_argument('--cytomine_roi_term', dest='cytomine_roi_term', type=int, default=None, help="The Cytomine identifier of region of interest term") parser.add_argument('--cytomine_roi_user', dest='cytomine_roi_user', type=int, help="The Cytomine identifier of ROI owner") parser.add_argument('--cytomine_roi_reviewed_only', dest='cytomine_roi_reviewed_only', type=bool, help="Whether ROIs have to be reviewed or not") # Pre-processing parser.add_argument('--mean_radius', dest='mean_radius', type=int, required=True, help="The mean radius of object to detect") parser.add_argument('--pre_transformer', dest='pre_transformer', default=None, choices=['edt', 'euclidean_distance_transform', 'density', None, 'None'], help="Scoremap transformer (None, edt, euclidean_distance_transform, density)") parser.add_argument('--pre_alpha', dest='pre_alpha', action='append', type=int, help="Exponential decrease rate of distance (if EDT)") # Subwindows parser.add_argument('--sw_input_size', dest='sw_input_size', action='append', type=int, help="Size of input subwindow") parser.add_argument('--sw_output_size', dest='sw_output_size', action='append', type=int, help="Size of output subwindow (ignored for FCRN)") parser.add_argument('--sw_extr_mode', dest='sw_extr_mode', choices=['random', 'sliding', 'scoremap_constrained'], help="Mode of extraction (random, scoremap_constrained)") parser.add_argument('--sw_extr_score_thres', dest='sw_extr_score_thres', action='append', type=float, help="Minimum threshold to be foreground in subwindows extraction" "(if 'scoremap_constrained' mode)") parser.add_argument('--sw_extr_ratio', dest='sw_extr_ratio', action='append', type=float, help="Ratio of background subwindows extracted in subwindows " "extraction (if 'scoremap_constrained' mode)") parser.add_argument('--sw_extr_npi', dest="sw_extr_npi", action='append', type=int, help="Number of extracted subwindows per image (if 'random' mode)") parser.add_argument('--sw_colorspace', dest="sw_colorspace", type=str, default='RGB__rgb', help="List of colorspace features") # Forest parser.add_argument('--forest_method', dest='forest_method', type=str, action='append', choices=['ET-clf', 'ET-regr', 'RF-clf', 'RF-regr'], help="Type of forest method") parser.add_argument('--forest_n_estimators', dest='forest_n_estimators', action='append', type=int, help="Number of trees in forest") parser.add_argument('--forest_min_samples_split', dest='forest_min_samples_split', action='append', type=int, help="Minimum number of samples for further splitting") parser.add_argument('--forest_max_features', dest='forest_max_features', action='append', help="Max features") # Dataset augmentation parser.add_argument('--augmentation', dest='augmentation', type=bool) parser.add_argument('--aug_rotation_range', dest='rotation_range', type=float) parser.add_argument('--aug_width_shift_range', dest='width_shift_range', type=float) parser.add_argument('--aug_height_shift_range', dest='height_shift_range', type=float) parser.add_argument('--aug_zoom_range', dest='zoom_range', type=float) parser.add_argument('--aug_fill_mode', dest='fill_mode', type=str) parser.add_argument('--aug_horizontal_flip', dest='horizontal_flip', type=bool) parser.add_argument('--aug_vertical_flip', dest='vertical_flip', type=bool) parser.add_argument('--aug_featurewise_center', dest='featurewise_center', type=bool) parser.add_argument('--aug_featurewise_std_normalization', dest='featurewise_std_normalization', type=bool) # Execution parser.add_argument('--n_jobs', dest='n_jobs', type=int, default=1, help="Number of jobs") parser.add_argument('--verbose', '-v', dest='verbose', default=0, help="Level of verbosity") params, other = parser.parse_known_args(argv) if params.cytomine_working_path is None: params.cytomine_working_path = os.path.join(tempfile.gettempdir(), "cytomine") make_dirs(params.cytomine_working_path) params.pre_transformer = check_default(params.pre_transformer, None, return_list=False) params.pre_alpha = check_default(params.pre_alpha, 5) params.forest_method = check_default(params.forest_method, 'ET-regr') params.forest_n_estimators = check_default(params.forest_n_estimators, 1) params.forest_min_samples_split = check_default(params.forest_min_samples_split, 2) params.forest_max_features = check_default(params.forest_max_features, 'sqrt') params.forest_max_features = check_max_features(params.forest_max_features) params.sw_input_size = check_default(params.sw_input_size, 4) params.sw_input_size = [(s, s) for s in params.sw_input_size] params.sw_output_size = check_default(params.sw_output_size, 1) params.sw_output_size = [(s, s) for s in params.sw_output_size] params.sw_extr_mode = check_default(params.sw_extr_mode, 'scoremap_constrained', return_list=False) params.sw_extr_ratio = check_default(params.sw_extr_ratio, 0.5) params.sw_extr_score_thres = check_default(params.sw_extr_score_thres, 0.4) params.sw_extr_npi = check_default(params.sw_extr_npi, 100) params.sw_colorspace = params.sw_colorspace.split(' ') params.augmentation = check_default(params.augmentation, False, return_list=False) if params.augmentation: params.rotation_range = check_default(params.rotation_range, 30., return_list=False) params.width_shift_range = check_default(params.width_shift_range, 0.3, return_list=False) params.height_shift_range = check_default(params.height_shift_range, 0.3, return_list=False) params.zoom_range = check_default(params.zoom_range, 0.3, return_list=False) params.fill_mode = check_default(params.fill_mode, 'constant', return_list=False) params.horizontal_flip = check_default(params.horizontal_flip, True, return_list=False) params.vertical_flip = check_default(params.vertical_flip, True, return_list=False) params.featurewise_center = check_default(params.featurewise_center, False, return_list=False) params.featurewise_std_normalization = check_default(params.featurewise_std_normalization, False, return_list=False) else: params.rotation_range = 0. params.width_shift_range = 0. params.height_shift_range = 0. params.zoom_range = 0. params.fill_mode = 'reflect' params.horizontal_flip = False params.vertical_flip = False params.featurewise_center = False params.featurewise_std_normalization = False params = params_remove_list(params) # Initialize logger logger = StandardOutputLogger(params.verbose) for key, val in sorted(vars(params).iteritems()): logger.info("[PARAMETER] {}: {}".format(key, val)) # Initialize Cytomine client cytomine = Cytomine( params.cytomine_host, params.cytomine_public_key, params.cytomine_private_key, working_path=params.cytomine_working_path, base_path=params.cytomine_base_path, verbose=(params.verbose >= Logger.DEBUG) ) # Start job with CytomineJob(cytomine, params.cytomine_software, params.cytomine_project, parameters=vars(params_remove_none(params))) as job: cytomine.update_job_status(job.job, status_comment="Starting...", progress=0) cytomine.update_job_status(job.job, status_comment="Loading training set...", progress=1) X, y = get_dataset(cytomine, params.cytomine_working_path, params.cytomine_project, params.cytomine_object_term, params.cytomine_roi_term, params.cytomine_object_user, params.cytomine_object_reviewed_only, params.cytomine_roi_user, params.cytomine_roi_reviewed_only, params.cytomine_force_download) logger.d("X size: {} samples".format(len(X))) logger.d("y size: {} samples".format(len(y))) cytomine.update_job_status(job.job, status_comment="Training forest...", progress=5) estimator = CellCountRandomizedTrees(logger=logger, **vars(params)) estimator.fit(np.asarray(X), np.asarray(y)) cytomine.update_job_status(job.job, status_comment="Saving (best) model", progress=95) model_path = os.path.join(params.cytomine_working_path, "models", str(params.cytomine_software)) model_file = os.path.join(model_path, "{}.pkl".format(job.job.id)) make_dirs(model_path) estimator.save(model_file) cytomine.update_job_status(job.job, status_comment="Finished.", progress=100)
def train(argv): parser = ArgumentParser(prog="CNN Object Counter Model Builder") # Cytomine parser.add_argument('--cytomine_host', dest='cytomine_host', default='demo.cytomine.be', help="The Cytomine host") parser.add_argument('--cytomine_public_key', dest='cytomine_public_key', help="The Cytomine public key") parser.add_argument('--cytomine_private_key', dest='cytomine_private_key', help="The Cytomine private key") parser.add_argument('--cytomine_base_path', dest='cytomine_base_path', default='/api/', help="The Cytomine base path") parser.add_argument('--cytomine_working_path', dest='cytomine_working_path', default=None, help="The working directory (eg: /tmp)") parser.add_argument('--cytomine_id_software', dest='cytomine_software', type=int, help="The Cytomine software identifier") parser.add_argument('--cytomine_id_project', dest='cytomine_project', type=int, help="The Cytomine project identifier") parser.add_argument('--cytomine_force_download', dest='cytomine_force_download', type=bool, default=True, help="Force download from Cytomine or not") # Objects parser.add_argument('--cytomine_object_term', dest='cytomine_object_term', type=int, help="The Cytomine identifier of object term") parser.add_argument('--cytomine_object_user', dest='cytomine_object_user', type=int, help="The Cytomine identifier of object owner") parser.add_argument('--cytomine_object_reviewed_only', dest='cytomine_object_reviewed_only', type=bool, help="Whether objects have to be reviewed or not") # ROI parser.add_argument( '--cytomine_roi_term', dest='cytomine_roi_term', type=int, default=None, help="The Cytomine identifier of region of interest term") parser.add_argument('--cytomine_roi_user', dest='cytomine_roi_user', type=int, help="The Cytomine identifier of ROI owner") parser.add_argument('--cytomine_roi_reviewed_only', dest='cytomine_roi_reviewed_only', type=bool, help="Whether ROIs have to be reviewed or not") # Pre-processing parser.add_argument('--mean_radius', dest='mean_radius', type=int, required=True, help="The mean radius of object to detect") parser.add_argument( '--pre_transformer', dest='pre_transformer', default=None, choices=[ 'edt', 'euclidean_distance_transform', 'density', None, 'None' ], help= "Scoremap transformer (None, edt, euclidean_distance_transform, density)" ) parser.add_argument('--pre_alpha', dest='pre_alpha', action='append', type=int, help="Exponential decrease rate of distance (if EDT)") # Subwindows for training parser.add_argument('--sw_input_size', dest='sw_input_size', action='append', type=int, help="Size of input subwindow") parser.add_argument('--sw_colorspace', dest="sw_colorspace", type=str, default='RGB__rgb', help="List of colorspace features") parser.add_argument('--sw_extr_npi', dest="sw_extr_npi", action='append', type=int, help="Number of extracted subwindows per image " "(if 'random' mode)") # CNN parser.add_argument('--cnn_architecture', '--architecture', dest='architecture', type=str, choices=['FCRN-A', 'FCRN-B', 'FCRN-test']) parser.add_argument('--cnn_initializer', '--initializer', dest='initializer', action='append', type=str) parser.add_argument('--cnn_regularizer', '--regularizer', dest='regularizer', action='append', type=str) parser.add_argument('--cnn_batch_normalization', '--batch_normalization', dest='batch_normalization', action='append', type=bool) parser.add_argument('--cnn_learning_rate', '--learning_rate', '--lr', dest='learning_rate', action='append', type=float) parser.add_argument('--cnn_momentum', '--momentum', dest='momentum', action='append', type=float) parser.add_argument('--cnn_nesterov', '--nesterov', dest='nesterov', action='append', type=bool) parser.add_argument('--cnn_decay', '--decay', dest='decay', action='append', type=float) parser.add_argument('--cnn_epochs', '--epochs', dest='epochs', action='append', type=int) parser.add_argument('--cnn_batch_size', '--batch_size', dest='batch_size', action='append', type=int) # Dataset augmentation parser.add_argument('--augmentation', dest='augmentation', type=bool) parser.add_argument('--aug_rotation_range', dest='rotation_range', type=float) parser.add_argument('--aug_width_shift_range', dest='width_shift_range', type=float) parser.add_argument('--aug_height_shift_range', dest='height_shift_range', type=float) parser.add_argument('--aug_zoom_range', dest='zoom_range', type=float) parser.add_argument('--aug_fill_mode', dest='fill_mode', type=str) parser.add_argument('--aug_horizontal_flip', dest='horizontal_flip', type=bool) parser.add_argument('--aug_vertical_flip', dest='vertical_flip', type=bool) parser.add_argument('--aug_featurewise_center', dest='featurewise_center', type=bool) parser.add_argument('--aug_featurewise_std_normalization', dest='featurewise_std_normalization', type=bool) # Execution parser.add_argument('--n_jobs', dest='n_jobs', type=int, default=1, help="Number of jobs") parser.add_argument('--verbose', '-v', dest='verbose', default=0, action='count', help="Level of verbosity") params, other = parser.parse_known_args(argv) if params.working_path is None: params.working_path = os.path.join(tempfile.gettempdir(), "cytomine") make_dirs(params.working_path) params.pre_transformer = check_default(params.pre_transformer, None, return_list=False) params.pre_alpha = check_default(params.pre_alpha, 5) params.architecture = check_default(params.architecture, 'FCRN-A', return_list=False) params.initializer = check_default(params.initializer, 'orthogonal') params.regularizer = check_default(params.regularizer, None) params.batch_normalization = check_default(params.batch_normalization, True) params.learning_rate = check_default(params.learning_rate, 0.02) params.momentum = check_default(params.momentum, 0.9) params.nesterov = check_default(params.nesterov, True) params.decay = check_default(params.decay, 0.) params.epochs = check_default(params.epochs, 3) params.batch_size = check_default(params.batch_size, 2) d = 8 if params.architecture == 'FCRN-A' else 4 params.sw_input_size = check_default(params.sw_input_size, 4) params.sw_input_size = [((s // d * d + d), (s // d * d + d)) for s in params.sw_input_size] params.sw_output_size = params.sw_input_size params.sw_size = params.sw_input_size params.sw_colorspace = params.sw_colorspace.split(' ') params.sw_extr_npi = check_default(params.sw_extr_npi, 100) params.sw_extr_mode = ['random'] params.augmentation = check_default(params.augmentation, True, return_list=False) if params.augmentation: params.rotation_range = check_default(params.rotation_range, 30., return_list=False) params.width_shift_range = check_default(params.width_shift_range, 0.3, return_list=False) params.height_shift_range = check_default(params.height_shift_range, 0.3, return_list=False) params.zoom_range = check_default(params.zoom_range, 0.3, return_list=False) params.fill_mode = check_default(params.fill_mode, 'constant', return_list=False) params.horizontal_flip = check_default(params.horizontal_flip, True, return_list=False) params.vertical_flip = check_default(params.vertical_flip, True, return_list=False) params.featurewise_center = check_default(params.featurewise_center, False, return_list=False) params.featurewise_std_normalization = check_default( params.featurewise_std_normalization, False, return_list=False) else: params.rotation_range = 0. params.width_shift_range = 0. params.height_shift_range = 0. params.zoom_range = 0. params.fill_mode = 'reflect' params.horizontal_flip = False params.vertical_flip = False params.featurewise_center = False params.featurewise_std_normalization = False params = params_remove_list(params) # Callbacks checkpoint_callback = ModelCheckpoint(params.model_file, monitor='loss', save_best_only=True) lr_callback = LearningRateScheduler(lr_scheduler) callbacks = [checkpoint_callback, lr_callback] # Initialize logger logger = StandardOutputLogger(params.verbose) for key, val in sorted(vars(params).iteritems()): logger.info("[PARAMETER] {}: {}".format(key, val)) # Initialize Cytomine client cytomine = Cytomine(params.cytomine_host, params.cytomine_public_key, params.cytomine_private_key, working_path=params.cytomine_working_path, base_path=params.cytomine_base_path, verbose=(params.verbose >= Logger.DEBUG)) # Start job with CytomineJob(cytomine, params.cytomine_software, params.cytomine_project, parameters=vars(params)) as job: cytomine.update_job_status(job.job, status_comment="Starting...", progress=0) cytomine.update_job_status(job.job, status_comment="Loading training set...", progress=1) X, y = get_dataset( cytomine, params.working_path, params.cytomine_project, params.cytomine_object_term, params.cytomine_roi_term, params.cytomine_object_user, params.cytomine_object_reviewed_only, params.cytomine_roi_user, params.cytomine_roi_reviewed_only, params.cytomine_force_download) logger.d("X size: {} samples".format(len(X))) logger.d("y size: {} samples".format(len(y))) cytomine.update_job_status(job.job, status_comment="Training FCRN...", progress=5) estimator = FCRN(FCRN.build_fcrn, callbacks, **vars(params)) estimator.fit(np.asarray(X), np.asarray(y)) cytomine.update_job_status(job.job, status_comment="Saving (best) model", progress=95) model_path = os.path.join(params.cytomine_working_path, "models", str(params.cytomine_software)) model_file = os.path.join(model_path, "{}.h5".format(job.job.id)) make_dirs(model_path) estimator.save(model_file) cytomine.update_job_status(job.job, status_comment="Finished.", progress=100)