Browse Source

Init unittest

Bobholamovic 2 years ago
parent
commit
8ba124d82b

+ 1 - 1
paddlers/custom_models/seg/farseg.py

@@ -32,7 +32,7 @@ class FPN(nn.Layer):
     """
     """
     Module that adds FPN on top of a list of feature maps.
     Module that adds FPN on top of a list of feature maps.
     The feature maps are currently supposed to be in increasing depth
     The feature maps are currently supposed to be in increasing depth
-    order, and must be consecutive
+        order, and must be consecutive
     """
     """
 
 
     def __init__(self,
     def __init__(self,

+ 1 - 1
paddlers/tasks/slim/prune.py

@@ -41,7 +41,7 @@ def _pruner_template_input(sample, model_type):
 
 
 
 
 def sensitive_prune(pruner, pruned_flops, skip_vars=[], align=None):
 def sensitive_prune(pruner, pruned_flops, skip_vars=[], align=None):
-    # skip depthwise convolutions
+    # Skip depthwise convolutions
     for layer in pruner.model.sublayers():
     for layer in pruner.model.sublayers():
         if isinstance(layer, paddle.nn.layer.conv.Conv2D) and layer._groups > 1:
         if isinstance(layer, paddle.nn.layer.conv.Conv2D) and layer._groups > 1:
             for param in layer.parameters(include_sublayers=False):
             for param in layer.parameters(include_sublayers=False):

+ 41 - 38
paddlers/tasks/utils/det_metrics/coco_utils.py

@@ -35,6 +35,7 @@ def get_infer_results(outs, catid, bias=0):
     For example, bbox result is a list and each element contains
     For example, bbox result is a list and each element contains
     image_id, category_id, bbox and score.
     image_id, category_id, bbox and score.
     """
     """
+
     if outs is None or len(outs) == 0:
     if outs is None or len(outs) == 0:
         raise ValueError(
         raise ValueError(
             'The number of valid detection result if zero. Please use reasonable model and check input data.'
             'The number of valid detection result if zero. Please use reasonable model and check input data.'
@@ -78,6 +79,7 @@ def cocoapi_eval(anns,
         max_dets (tuple): COCO evaluation maxDets.
         max_dets (tuple): COCO evaluation maxDets.
         classwise (bool): Whether per-category AP and draw P-R Curve or not.
         classwise (bool): Whether per-category AP and draw P-R Curve or not.
     """
     """
+
     assert coco_gt is not None or anno_file is not None
     assert coco_gt is not None or anno_file is not None
     from pycocotools.coco import COCO
     from pycocotools.coco import COCO
     from pycocotools.cocoeval import COCOeval
     from pycocotools.cocoeval import COCOeval
@@ -220,19 +222,19 @@ def loadRes(coco_obj, anns):
 
 
 
 
 def makeplot(rs, ps, outDir, class_name, iou_type):
 def makeplot(rs, ps, outDir, class_name, iou_type):
-    """针对某个特定类别,绘制不同评估要求下的准确率和召回率。
-       绘制结果说明参考COCODataset官网给出分析工具说明https://cocodataset.org/#detection-eval。
-
-       Refer to https://github.com/open-mmlab/mmdetection/blob/master/tools/analysis_tools/coco_error_analysis.py#L13
+    """
+    针对某个特定类别,绘制不同评估要求下的准确率和召回率。
+    绘制结果说明参考COCODataset官网给出分析工具说明https://cocodataset.org/#detection-eval。
 
 
-       Args:
-           rs (np.array): 在不同置信度阈值下计算得到的召回率。
-           ps (np.array): 在不同置信度阈值下计算得到的准确率。ps与rs相同位置下的数值为同一个置信度阈值
-               计算得到的准确率与召回率。
-           outDir (str): 图表保存的路径。
-           class_name (str): 类别名。
-           iou_type (str): iou计算方式,若为检测框,则设置为'bbox',若为像素级分割结果,则设置为'segm'。
+    Refer to https://github.com/open-mmlab/mmdetection/blob/master/tools/analysis_tools/coco_error_analysis.py#L13
 
 
+    Args:
+        rs (np.array): 在不同置信度阈值下计算得到的召回率。
+        ps (np.array): 在不同置信度阈值下计算得到的准确率。ps与rs相同位置下的数值为同一个置信度阈值
+            计算得到的准确率与召回率。
+        outDir (str): 图表保存的路径。
+        class_name (str): 类别名。
+        iou_type (str): iou计算方式,若为检测框,则设置为'bbox',若为像素级分割结果,则设置为'segm'。
     """
     """
 
 
     import matplotlib.pyplot as plt
     import matplotlib.pyplot as plt
@@ -276,21 +278,22 @@ def makeplot(rs, ps, outDir, class_name, iou_type):
 
 
 
 
 def analyze_individual_category(k, cocoDt, cocoGt, catId, iou_type, areas=None):
 def analyze_individual_category(k, cocoDt, cocoGt, catId, iou_type, areas=None):
-    """针对某个特定类别,分析忽略亚类混淆和类别混淆时的准确率。
+    """
+    针对某个特定类别,分析忽略亚类混淆和类别混淆时的准确率。
 
 
-       Refer to https://github.com/open-mmlab/mmdetection/blob/master/tools/analysis_tools/coco_error_analysis.py#L174
+    Refer to https://github.com/open-mmlab/mmdetection/blob/master/tools/analysis_tools/coco_error_analysis.py#L174
 
 
-       Args:
-           k (int): 待分析类别的序号。
-           cocoDt (pycocotols.coco.COCO): 按COCO类存放的预测结果。
-           cocoGt (pycocotols.coco.COCO): 按COCO类存放的真值。
-           catId (int): 待分析类别在数据集中的类别id。
-           iou_type (str): iou计算方式,若为检测框,则设置为'bbox',若为像素级分割结果,则设置为'segm'。
+    Args:
+        k (int): 待分析类别的序号。
+        cocoDt (pycocotols.coco.COCO): 按COCO类存放的预测结果。
+        cocoGt (pycocotols.coco.COCO): 按COCO类存放的真值。
+        catId (int): 待分析类别在数据集中的类别id。
+        iou_type (str): iou计算方式,若为检测框,则设置为'bbox',若为像素级分割结果,则设置为'segm'。
 
 
-       Returns:
-           int:
-           dict: 有关键字'ps_supercategory'和'ps_allcategory'。关键字'ps_supercategory'的键值是忽略亚类间
-               混淆时的准确率,关键字'ps_allcategory'的键值是忽略类别间混淆时的准确率。
+    Returns:
+        int:
+        dict: 有关键字'ps_supercategory'和'ps_allcategory'。关键字'ps_supercategory'的键值是忽略亚类间
+            混淆时的准确率,关键字'ps_allcategory'的键值是忽略类别间混淆时的准确率。
 
 
     """
     """
 
 
@@ -362,23 +365,23 @@ def coco_error_analysis(eval_details_file=None,
                         pred_bbox=None,
                         pred_bbox=None,
                         pred_mask=None,
                         pred_mask=None,
                         save_dir='./output'):
                         save_dir='./output'):
-    """逐个分析模型预测错误的原因,并将分析结果以图表的形式展示。
-       分析结果说明参考COCODataset官网给出分析工具说明https://cocodataset.org/#detection-eval。
-
-       Refer to https://github.com/open-mmlab/mmdetection/blob/master/tools/analysis_tools/coco_error_analysis.py
-
-       Args:
-           eval_details_file (str):  模型评估结果的保存路径,包含真值信息和预测结果。
-           gt (list): 数据集的真值信息。默认值为None。
-           pred_bbox (list): 模型在数据集上的预测框。默认值为None。
-           pred_mask (list): 模型在数据集上的预测mask。默认值为None。
-           save_dir (str): 可视化结果保存路径。默认值为'./output'。
+    """
+    逐个分析模型预测错误的原因,并将分析结果以图表的形式展示。
+    分析结果说明参考COCODataset官网给出分析工具说明https://cocodataset.org/#detection-eval。
 
 
-        Note:
-           eval_details_file的优先级更高,只要eval_details_file不为None,
-           就会从eval_details_file提取真值信息和预测结果做分析。
-           当eval_details_file为None时,则用gt、pred_mask、pred_mask做分析。
+    Refer to https://github.com/open-mmlab/mmdetection/blob/master/tools/analysis_tools/coco_error_analysis.py
 
 
+    Args:
+        eval_details_file (str):  模型评估结果的保存路径,包含真值信息和预测结果。
+        gt (list): 数据集的真值信息。默认值为None。
+        pred_bbox (list): 模型在数据集上的预测框。默认值为None。
+        pred_mask (list): 模型在数据集上的预测mask。默认值为None。
+        save_dir (str): 可视化结果保存路径。默认值为'./output'。
+
+    Note:
+        eval_details_file的优先级更高,只要eval_details_file不为None,
+        就会从eval_details_file提取真值信息和预测结果做分析。
+        当eval_details_file为None时,则用gt、pred_mask、pred_mask做分析。
     """
     """
 
 
     import multiprocessing as mp
     import multiprocessing as mp

+ 8 - 3
paddlers/tasks/utils/visualize.py

@@ -25,7 +25,7 @@ from .det_metrics.coco_utils import loadRes
 def visualize_detection(image, result, threshold=0.5, save_dir='./',
 def visualize_detection(image, result, threshold=0.5, save_dir='./',
                         color=None):
                         color=None):
     """
     """
-        Visualize bbox and mask results
+    Visualize bbox and mask results
     """
     """
 
 
     if isinstance(image, np.ndarray):
     if isinstance(image, np.ndarray):
@@ -48,6 +48,7 @@ def visualize_segmentation(image, result, weight=0.6, save_dir='./',
                            color=None):
                            color=None):
     """
     """
     Convert segment result to color image, and save added image.
     Convert segment result to color image, and save added image.
+
     Args:
     Args:
         image: the path of origin image
         image: the path of origin image
         result: the predict result of image
         result: the predict result of image
@@ -55,6 +56,7 @@ def visualize_segmentation(image, result, weight=0.6, save_dir='./',
         save_dir: the directory for saving visual image
         save_dir: the directory for saving visual image
         color: the list of a BGR-mode color for each label.
         color: the list of a BGR-mode color for each label.
     """
     """
+
     label_map = result['label_map'].astype("uint8")
     label_map = result['label_map'].astype("uint8")
     color_map = get_color_map_list(256)
     color_map = get_color_map_list(256)
     if color is not None:
     if color is not None:
@@ -104,13 +106,16 @@ def visualize_segmentation(image, result, weight=0.6, save_dir='./',
 
 
 
 
 def get_color_map_list(num_classes):
 def get_color_map_list(num_classes):
-    """ Returns the color map for visualizing the segmentation mask,
-        which can support arbitrary number of classes.
+    """ 
+    Returns the color map for visualizing the segmentation mask, which can support arbitrary number of classes.
+
     Args:
     Args:
         num_classes: Number of classes
         num_classes: Number of classes
+
     Returns:
     Returns:
         The color map
         The color map
     """
     """
+
     color_map = num_classes * [0, 0, 0]
     color_map = num_classes * [0, 0, 0]
     for i in range(0, num_classes):
     for i in range(0, num_classes):
         j = 0
         j = 0

+ 5 - 0
tests/check_coverage.sh

@@ -0,0 +1,5 @@
+#!/usr/bin/bash
+
+coverage run -m unittest discover
+coverage report
+coverage html -d coverage_html

+ 13 - 0
tests/components/__init__.py

@@ -0,0 +1,13 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

+ 13 - 0
tests/datasets/__init__.py

@@ -0,0 +1,13 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

+ 13 - 0
tests/deploy/__init__.py

@@ -0,0 +1,13 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

+ 13 - 0
tests/rs_models/__init__.py

@@ -0,0 +1,13 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

+ 3 - 0
tests/run_tests.sh

@@ -0,0 +1,3 @@
+#!/usr/bin/bash
+
+python -m unittest discover -v

+ 13 - 0
tests/tasks/__init__.py

@@ -0,0 +1,13 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

+ 13 - 0
tests/test_examples.py

@@ -0,0 +1,13 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

+ 13 - 0
tests/test_tutorials.py

@@ -0,0 +1,13 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

+ 183 - 0
tests/test_utils.py

@@ -0,0 +1,183 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Based on https://github.com/PaddlePaddle/PaddleNLP/blob/develop/tests/common_test.py
+
+import unittest
+import warnings
+
+import numpy as np
+import paddle
+
+__all__ = ['CommonTest', 'CpuCommonTest']
+
+
+# Assume all elements has same data type
+def get_container_type(container):
+    container_t = type(container)
+    if container_t in [list, tuple]:
+        if len(container) == 0:
+            return container_t
+        return get_container_type(container[0])
+    return container_t
+
+
+class _CommonTestNamespace:
+    # Wrap the subclasses of unittest.TestCase that are expected to be inherited from.
+    class CommonTest(unittest.TestCase):
+        CATCH_WARNINGS = False
+
+        def __init__(self, methodName='runTest'):
+            super(CommonTest, self).__init__(methodName=methodName)
+            self.config = {}
+            self.places = ['cpu']
+            if paddle.is_compiled_with_cuda():
+                self.places.append('gpu')
+
+        @classmethod
+        def setUpClass(cls):
+            '''
+            Set the decorators for all test function
+            '''
+            for key, value in cls.__dict__.items():
+                if key.startswith('test'):
+                    decorator_func_list = ["_test_places"]
+                    if cls.CATCH_WARNINGS:
+                        decorator_func_list.append("_catch_warnings")
+                    for decorator_func in decorator_func_list:
+                        decorator_func = getattr(CommonTest, decorator_func)
+                        value = decorator_func(value)
+                    setattr(cls, key, value)
+
+        def _catch_warnings(func):
+            '''
+            Catch the warnings and treat them as errors for each test.
+            '''
+
+            def wrapper(self, *args, **kwargs):
+                with warnings.catch_warnings(record=True) as w:
+                    warnings.resetwarnings()
+                    # ignore specified warnings
+                    warning_white_list = [UserWarning]
+                    for warning in warning_white_list:
+                        warnings.simplefilter("ignore", warning)
+                    func(self, *args, **kwargs)
+                    msg = None if len(w) == 0 else w[0].message
+                    self.assertFalse(len(w) > 0, msg)
+
+            return wrapper
+
+        def _test_places(func):
+            '''
+            Setting the running place for each test.
+            '''
+
+            def wrapper(self, *args, **kwargs):
+                places = self.places
+                for place in places:
+                    paddle.set_device(place)
+                    func(self, *args, **kwargs)
+
+            return wrapper
+
+        def _check_output_impl(self,
+                               result,
+                               expected_result,
+                               rtol,
+                               atol,
+                               equal=True):
+            assertForNormalType = self.assertNotEqual
+            assertForFloat = self.assertFalse
+            if equal:
+                assertForNormalType = self.assertEqual
+                assertForFloat = self.assertTrue
+
+            result_t = type(result)
+            error_msg = 'Output has diff at place:{}. \nExpect: {} \nBut Got: {} in class {}'
+            if result_t in [list, tuple]:
+                result_t = get_container_type(result)
+            if result_t in [
+                    str, int, bool, set, np.bool, np.int32, np.int64, np.str
+            ]:
+                assertForNormalType(
+                    result,
+                    expected_result,
+                    msg=error_msg.format(paddle.get_device(), expected_result,
+                                         result, self.__class__.__name__))
+            elif result_t in [float, np.ndarray, np.float32, np.float64]:
+                assertForFloat(
+                    np.allclose(
+                        result, expected_result, rtol=rtol, atol=atol),
+                    msg=error_msg.format(paddle.get_device(), expected_result,
+                                         result, self.__class__.__name__))
+                if result_t == np.ndarray:
+                    assertForNormalType(
+                        result.shape,
+                        expected_result.shape,
+                        msg=error_msg.format(
+                            paddle.get_device(), expected_result.shape,
+                            result.shape, self.__class__.__name__))
+            else:
+                raise ValueError(
+                    'result type must be str, int, bool, set, np.bool, np.int32, '
+                    'np.int64, np.str, float, np.ndarray, np.float32, np.float64'
+                )
+
+        def check_output_equal(self,
+                               result,
+                               expected_result,
+                               rtol=1.e-5,
+                               atol=1.e-8):
+            '''
+                Check whether result and expected result are equal, including shape. 
+            Args:
+                result: str, int, bool, set, np.ndarray.
+                    The result needs to be checked.
+                expected_result: str, int, bool, set, np.ndarray. The type has to be same as result's.
+                    Use the expected result to check result.
+                rtol: float
+                    relative tolerance, default 1.e-5.
+                atol: float
+                    absolute tolerance, default 1.e-8
+            '''
+            self._check_output_impl(result, expected_result, rtol, atol)
+
+        def check_output_not_equal(self,
+                                   result,
+                                   expected_result,
+                                   rtol=1.e-5,
+                                   atol=1.e-8):
+            '''
+                Check whether result and expected result are not equal, including shape. 
+            Args:
+                result: str, int, bool, set, np.ndarray.
+                    The result needs to be checked.
+                expected_result: str, int, bool, set, np.ndarray. The type has to be same as result's.
+                    Use the expected result to check result.
+                rtol: float
+                    relative tolerance, default 1.e-5.
+                atol: float
+                    absolute tolerance, default 1.e-8
+            '''
+            self._check_output_impl(
+                result, expected_result, rtol, atol, equal=False)
+
+    class CpuCommonTest(CommonTest):
+        def __init__(self, methodName='runTest'):
+            super(CpuCommonTest, self).__init__(methodName=methodName)
+            self.places = ['cpu']
+
+
+CommonTest = _CommonTestNamespace.CommonTest
+CpuCommonTest = _CommonTestNamespace.CpuCommonTest

+ 13 - 0
tests/tools/__init__.py

@@ -0,0 +1,13 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

+ 13 - 0
tests/transforms/__init__.py

@@ -0,0 +1,13 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.