def test_random_transform(annotations): test_model = deepforest.deepforest() test_model.config["random_transform"] = True classes_file = utilities.create_classes(annotations) arg_list = utilities.format_args(annotations, classes_file, test_model.config) assert "--random-transform" in arg_list
def evaluate_generator(self, annotations, comet_experiment=None, iou_threshold=0.5, max_detections=200): """ Evaluate prediction model using a csv fit_generator Args: annotations (str): Path to csv label file, labels are in the format -> path/to/image.png,x1,y1,x2,y2,class_name iou_threshold(float): IoU Threshold to count for a positive detection (defaults to 0.5) max_detections (int): Maximum number of bounding box predictions comet_experiment(object): A comet experiment class objects to track Return: mAP: Mean average precision of the evaluated data """ #Format args for CSV generator classes_file = utilities.create_classes(annotations) arg_list = utilities.format_args(annotations, classes_file, self.config) args = parse_args(arg_list) #create generator validation_generator = CSVGenerator( args.annotations, args.classes, image_min_side=args.image_min_side, image_max_side=args.image_max_side, config=args.config, shuffle_groups=False, ) average_precisions = evaluate(validation_generator, self.prediction_model, iou_threshold=iou_threshold, score_threshold=args.score_threshold, max_detections=max_detections, save_path=args.save_path, comet_experiment=comet_experiment) # print evaluation total_instances = [] precisions = [] for label, (average_precision, num_annotations) in average_precisions.items(): print('{:.0f} instances of class'.format(num_annotations), validation_generator.label_to_name(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.') return 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))) mAP = sum(precisions) / sum(x > 0 for x in total_instances) print('mAP: {:.4f}'.format(mAP)) return mAP
def from_retinanet(annotations_csv): model = deepforest.deepforest() model.use_release() """use the keras retinanet source to create detections""" ### Keras retinanet # Format args for CSV generator classes_file = utilities.create_classes(annotations_csv) arg_list = utilities.format_args(annotations_csv, classes_file, model.config) args = parse_args(arg_list) # create generator validation_generator = csv_generator.CSVGenerator( args.annotations, args.classes, image_min_side=args.image_min_side, image_max_side=args.image_max_side, config=args.config, shuffle_groups=False, ) all_detections = _get_detections(validation_generator, model.prediction_model, score_threshold=args.score_threshold, max_detections=100) all_annotations = _get_annotations(validation_generator) return all_detections, all_annotations, validation_generator
def test_format_args_steps(annotations, config): classes_file = utilities.create_classes(annotations) arg_list = utilities.format_args(annotations,classes_file, config, images_per_epoch=2) assert isinstance(arg_list, list) #A bit ugly, but since its a list, what is the argument after --steps to assert steps_position = np.where(["--steps" in x for x in arg_list])[0][0] + 1 assert arg_list[steps_position] == '2'
def test_retrain_release(annotations, release_model): release_model.config["epochs"] = 1 release_model.config["save-snapshot"] = False release_model.config["steps"] = 1 assert release_model.config["weights"] == release_model.weights #test that it gets passed to retinanet classes_file = utilities.create_classes(annotations) arg_list = utilities.format_args(annotations, classes_file, release_model.config, images_per_epoch=1) strs = ["--weights" == x for x in arg_list] index = np.where(strs)[0][0] + 1 assert arg_list[index] == release_model.weights
def train(self, annotations, comet_experiment=None): '''Train a deep learning tree detection model using keras-retinanet This is the main entry point for training a new model based on either existing weights or scratch Args: annotations (str): Path to csv label file, labels are in the format -> path/to/image.jpg,x1,y1,x2,y2,class_name comet_experiment: A comet ml object to log images. Optional. Returns: model (object): A trained keras model ''' arg_list = utilities.format_args(annotations, self.config) print("Training retinanet with the following args {}".format(arg_list)) #Train model self.training_model = retinanet_train(arg_list, comet_experiment) #Create prediction model self.prediction_model = convert_model(self.training_model)
def train(self, annotations, input_type="fit_generator", list_of_tfrecords=None, comet_experiment=None, images_per_epoch=None): """Train a deep learning tree detection model using keras-retinanet. This is the main entry point for training a new model based on either existing weights or scratch. Args: annotations (str): Path to csv label file, labels are in the format -> path/to/image.png,x1,y1,x2,y2,class_name input_type: "fit_generator" or "tfrecord" list_of_tfrecords: Ignored if input_type != "tfrecord", list of tf records to process comet_experiment: A comet ml object to log images. Optional. images_per_epoch: number of images to override default config of images in annotations file / batch size. Useful for debug Returns: model (object): A trained keras model prediction model: with bbox nms trained model: without nms """ # Test if there is a new classes file in case # of classes has changed. self.classes_file = utilities.create_classes(annotations) self.read_classes() arg_list = utilities.format_args(annotations, self.classes_file, self.config, images_per_epoch) print("Training retinanet with the following args {}".format(arg_list)) # Train model self.model, self.prediction_model, self.training_model = retinanet_train( forest_object=self, args=arg_list, input_type=input_type, list_of_tfrecords=list_of_tfrecords, comet_experiment=comet_experiment)
def predict_generator(self, annotations, comet_experiment=None, iou_threshold=0.5, max_detections=200, return_plot=False, color=None): """Predict bounding boxes for a model using a csv fit_generator Args: annotations (str): Path to csv label file, labels are in the format -> path/to/image.png,x1,y1,x2,y2,class_name comet_experiment(object): A comet experiment class objects to track color: rgb color for the box annotations if return_plot is True e.g. (255,140,0) is orange. return_plot: Whether to return prediction boxes (False) or Images (True). If True, files will be written to current working directory if model.config["save_path"] is not defined. Return: boxes_output: If return_plot=False, a pandas dataframe of bounding boxes for each image in the annotations file None: If return_plot is True, images are written to save_dir as a side effect. """ # Format args for CSV generator classes_file = utilities.create_classes(annotations) arg_list = utilities.format_args(annotations, classes_file, self.config) args = parse_args(arg_list) # create generator generator = CSVGenerator( args.annotations, args.classes, image_min_side=args.image_min_side, image_max_side=args.image_max_side, config=args.config, shuffle_groups=False, ) if self.prediction_model: boxes_output = [] # For each image, gather predictions for i in range(generator.size()): # pass image as path plot_name = generator.image_names[i] image_path = os.path.join(generator.base_dir, plot_name) result = self.predict_image(image_path, return_plot=return_plot, score_threshold=args.score_threshold, color=color) if return_plot: if not self.config["save_path"]: print("model.config['save_path'] is None," "saving images to current working directory") save_path = "." else: save_path = self.config["save_path"] # Save image fname = os.path.join(save_path, plot_name) cv2.imwrite(fname, result) continue else: # Turn boxes to pandas frame and save output box_df = pd.DataFrame(result) # use only plot name, not extension box_df["plot_name"] = os.path.splitext(plot_name)[0] boxes_output.append(box_df) else: raise ValueError( "No prediction model loaded. Either load a retinanet from file, " "download the latest release or train a new model") if return_plot: return None else: # if boxes, name columns and return box data boxes_output = pd.concat(boxes_output) boxes_output.columns = [ "xmin", "ymin", "xmax", "ymax", "score", "label", "plot_name" ] boxes_output = boxes_output.reindex( columns=["plot_name", "xmin", "ymin", "xmax", "ymax", "score", "label"]) return boxes_output
def predict_generator(self, annotations, comet_experiment=None, iou_threshold=0.5, max_detections=200): """Predict bounding boxes for a model using a csv fit_generator Args: annotations (str): Path to csv label file, labels are in the format -> path/to/image.jpg,x1,y1,x2,y2,class_name iou_threshold(float): IoU Threshold to count for a positive detection (defaults to 0.5) max_detections (int): Maximum number of bounding box predictions comet_experiment(object): A comet experiment class objects to track Return: boxes_output: a pandas dataframe of bounding boxes for each image in the annotations file """ #Format args for CSV generator classes_file = utilities.create_classes(annotations) arg_list = utilities.format_args(annotations, classes_file, self.config) args = parse_args(arg_list) #create generator generator = CSVGenerator( args.annotations, args.classes, image_min_side=args.image_min_side, image_max_side=args.image_max_side, config=args.config, shuffle_groups=False, ) if self.prediction_model: boxes_output = [] #For each image, gather predictions for i in range(generator.size()): #pass image as path plot_name = generator.image_names[i] image_path = os.path.join(generator.base_dir, plot_name) boxes = self.predict_image( image_path, return_plot=False, score_threshold=args.score_threshold) #Turn to pandas frame and save output box_df = pd.DataFrame(boxes) #use only plot name, not extension box_df["plot_name"] = os.path.splitext(plot_name)[0] boxes_output.append(box_df) else: raise ValueError( "No prediction model loaded. Either load a retinanet from file, download the latest release or train a new model" ) #name columns and return box data boxes_output = pd.concat(boxes_output) boxes_output.columns = [ "xmin", "ymin", "xmax", "ymax", "score", "label", "plot_name" ] boxes_output = boxes_output.reindex(columns=[ "plot_name", "xmin", "ymin", "xmax", "ymax", "score", "label" ]) return boxes_output
def test_format_args(annotations, config): classes_file = utilities.create_classes(annotations) arg_list = utilities.format_args(annotations, classes_file, config) assert isinstance(arg_list, list)