Evaluate the model by making predictions and comparing these to ground
        truth bounding box annotations.

        Parameters
        ----------
        dataset : SFrame
            Dataset of new observations. Must include columns with the same
            names as the annotations and feature used for model training.
            Additional columns are ignored.

        metric : str or list, optional
            Name of the evaluation metric or list of several names. The primary
            metric is average precision, which is the area under the
            precision/recall curve and reported as a value between 0 and 1 (1
            being perfect). Possible values are:

            - 'auto'                      : Returns all primary metrics.
            - 'all'                       : Returns all available metrics.
            - 'average_precision_50'      : Average precision per class with
                                            intersection-over-union threshold at
                                            50% (PASCAL VOC metric).
            - 'average_precision'         : Average precision per class calculated over multiple
                                            intersection-over-union thresholds
                                            (at 50%, 55%, ..., 95%) and averaged.
            - 'mean_average_precision_50' : Mean over all classes (for ``'average_precision_50'``).
                                            This is the primary single-value metric.
            - 'mean_average_precision'    : Mean over all classes (for ``'average_precision'``)

        output_type : str
            Type of output:

            - 'dict'      : You are given a dictionary where each key is a metric name and the
                            value is another dictionary containing class-to-metric entries.
            - 'sframe'    : All metrics are returned as a single `SFrame`, where each row is a
                            class and each column is a metric. Metrics that are averaged over
                            class cannot be returned and are ignored under this format.
                            However, these are easily computed from the `SFrame` (e.g.
                            ``results['average_precision'].mean()``).

        iou_threshold : float
            Threshold value for non-maximum suppression. Non-maximum suppression
            prevents multiple bounding boxes appearing over a single object. 
            This threshold, set between 0 and 1, controls how aggressive this 
            suppression is. A value of 1 means no maximum suppression will 
            occur, while a value of 0 will maximally suppress neighboring 
            boxes around a prediction.

        confidence_threshold : float
            Only return predictions above this level of confidence. The
            threshold can range from 0 to 1. 

        verbose : bool
            If True, prints evaluation progress.

        Returns
        -------
        out : dict / SFrame
            Output type depends on the option `output_type`.

        See Also
        --------
        create, predict

        Examples
        --------
        >>> results = model.evaluate(data)
        >>> print('mAP: {:.1%}'.format(results['mean_average_precision']))
        mAP: 43.2%

def evaluate(self, dataset, metric='auto',
            output_type='dict', iou_threshold=None, 
            confidence_threshold=None, verbose=True):
        """
        Evaluate the model by making predictions and comparing these to ground
        truth bounding box annotations.

        Parameters
        ----------
        dataset : SFrame
            Dataset of new observations. Must include columns with the same
            names as the annotations and feature used for model training.
            Additional columns are ignored.

        metric : str or list, optional
            Name of the evaluation metric or list of several names. The primary
            metric is average precision, which is the area under the
            precision/recall curve and reported as a value between 0 and 1 (1
            being perfect). Possible values are:

            - 'auto'                      : Returns all primary metrics.
            - 'all'                       : Returns all available metrics.
            - 'average_precision_50'      : Average precision per class with
                                            intersection-over-union threshold at
                                            50% (PASCAL VOC metric).
            - 'average_precision'         : Average precision per class calculated over multiple
                                            intersection-over-union thresholds
                                            (at 50%, 55%, ..., 95%) and averaged.
            - 'mean_average_precision_50' : Mean over all classes (for ``'average_precision_50'``).
                                            This is the primary single-value metric.
            - 'mean_average_precision'    : Mean over all classes (for ``'average_precision'``)

        output_type : str
            Type of output:

            - 'dict'      : You are given a dictionary where each key is a metric name and the
                            value is another dictionary containing class-to-metric entries.
            - 'sframe'    : All metrics are returned as a single `SFrame`, where each row is a
                            class and each column is a metric. Metrics that are averaged over
                            class cannot be returned and are ignored under this format.
                            However, these are easily computed from the `SFrame` (e.g.
                            ``results['average_precision'].mean()``).

        iou_threshold : float
            Threshold value for non-maximum suppression. Non-maximum suppression
            prevents multiple bounding boxes appearing over a single object. 
            This threshold, set between 0 and 1, controls how aggressive this 
            suppression is. A value of 1 means no maximum suppression will 
            occur, while a value of 0 will maximally suppress neighboring 
            boxes around a prediction.

        confidence_threshold : float
            Only return predictions above this level of confidence. The
            threshold can range from 0 to 1. 

        verbose : bool
            If True, prints evaluation progress.

        Returns
        -------
        out : dict / SFrame
            Output type depends on the option `output_type`.

        See Also
        --------
        create, predict

        Examples
        --------
        >>> results = model.evaluate(data)
        >>> print('mAP: {:.1%}'.format(results['mean_average_precision']))
        mAP: 43.2%
        """
        if iou_threshold is None: iou_threshold = self.non_maximum_suppression_threshold
        if confidence_threshold is None: confidence_threshold = 0.001

        AP = 'average_precision'
        MAP = 'mean_average_precision'
        AP50 = 'average_precision_50'
        MAP50 = 'mean_average_precision_50'
        ALL_METRICS = {AP, MAP, AP50, MAP50}
        if isinstance(metric, (list, tuple, set)):
            metrics = metric
        elif metric == 'all':
            metrics = ALL_METRICS
        elif metric == 'auto':
            metrics = {AP50, MAP50}
        elif metric in ALL_METRICS:
            metrics = {metric}
        else:
            raise _ToolkitError("Metric '{}' not supported".format(metric))

        pred, gt = self._predict_with_options(dataset, with_ground_truth=True,
                                              confidence_threshold=confidence_threshold,
                                              iou_threshold=iou_threshold,
                                              verbose=verbose)

        pred_df = pred.to_dataframe()
        gt_df = gt.to_dataframe()

        thresholds = _np.arange(0.5, 1.0, 0.05)
        all_th_aps = _average_precision(pred_df, gt_df,
                                        class_to_index=self._class_to_index,
                                        iou_thresholds=thresholds)

        def class_dict(aps):
            return {classname: aps[index]
                    for classname, index in self._class_to_index.items()}

        if output_type == 'dict':
            ret = {}
            if AP50 in metrics:
                ret[AP50] = class_dict(all_th_aps[0])
            if AP in metrics:
                ret[AP] = class_dict(all_th_aps.mean(0))
            if MAP50 in metrics:
                ret[MAP50] = all_th_aps[0].mean()
            if MAP in metrics:
                ret[MAP] = all_th_aps.mean()
        elif output_type == 'sframe':
            ret = _tc.SFrame({'label': self.classes})
            if AP50 in metrics:
                ret[AP50] = all_th_aps[0]
            if AP in metrics:
                ret[AP] = all_th_aps.mean(0)
        else:
            raise _ToolkitError("Output type '{}' not supported".format(output_type))

        return ret