Browse Source

Merge branch 'develop' of https://github.com/PaddlePaddle/PaddleX into develop_qh

FlyingQianMM 4 năm trước cách đây
mục cha
commit
77ac13edd6

+ 9 - 1
README.md

@@ -21,13 +21,21 @@
 * PaddleX部署全面升级,支持飞桨视觉套件PaddleDetection、PaddleClas、PaddleSeg、PaddleX的统一部署能力,[欢迎体验](https://github.com/PaddlePaddle/PaddleX/tree/develop/dygraph/deploy/cpp)。
 ## :factory: 重要活动提醒
 
-✨直播课预告✨  直播链接:http://live.bilibili.com/21689802
+✨直播课预告✨  
+
+* 直播链接:http://live.bilibili.com/21689802
+
+* [点击查看回访录播](https://aistudio.baidu.com/aistudio/education/group/info/24531)
+
 
 * Day① 6.28 20:15-21:30 
    * 主题:工业算法选型及调优策略
 
 * Day② 6.29 20:15-21:30 
     * 主题:安防及智慧城市典型方案
+    * [表计检测案例](https://paddlex.readthedocs.io/zh_CN/develop/examples/meter_reader.html)
+
+
 * Day③ 6.30 20:15-21:30 
    * 主题:产业高性能高效部署方案
 

+ 1 - 2
dygraph/README.md

@@ -40,8 +40,7 @@
    通过简洁易懂的Python API,在兼顾功能全面性、开发灵活性、集成方便性的基础上,给开发者最流畅的深度学习开发体验。<br>
 
   **前置依赖**
-> - paddlepaddle == 2.1.0
-> - 安装PaddlePaddle Develop版本,具体PaddlePaddle[安装主页](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/develop/install/pip/windows-pip.html)
+> - 安装PaddlePaddle Develop版本,具体方式请参考PaddlePaddle[安装主页](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/develop/install/pip/windows-pip.html)
 
 **安装方式**
 

+ 3 - 0
dygraph/deploy/cpp/model_deploy/common/include/base_preprocess.h

@@ -46,6 +46,8 @@ class BasePreprocess {
                    std::vector<ShapeInfo>* shape_info,
                    int thread_num = 1) = 0;
 
+  virtual std::string GetModelName() { return model_name_; }
+
  protected:
   bool BuildTransform(const YAML::Node& yaml_config);
   std::vector<std::shared_ptr<Transform>> transforms_;
@@ -54,6 +56,7 @@ class BasePreprocess {
   std::shared_ptr<Transform> CreateTransform(const std::string& name);
   Padding batch_padding_;
   Permute permute_;
+  std::string model_name_;
 };
 
 }  // namespace PaddleDeploy

+ 33 - 9
dygraph/deploy/cpp/model_deploy/common/include/output_struct.h

@@ -243,8 +243,24 @@ struct Result {
     return stream;
   }
 
+  void Clear() {
+    if ("det" == model_type) {
+      delete det_result;
+      det_result = NULL;
+    } else if ("seg" == model_type) {
+      delete seg_result;
+      seg_result = NULL;
+    } else if ("clas" == model_type) {
+      delete clas_result;
+      clas_result = NULL;
+    } else if ("ocr" == model_type) {
+      delete ocr_result;
+      ocr_result = NULL;
+    }
+  }
 
   Result(const Result& result) {
+    Clear();
     model_type = result.model_type;
     if ("det" == model_type) {
       det_result = new DetResult();
@@ -261,20 +277,28 @@ struct Result {
     }
   }
 
-  ~Result() {
+  Result& operator=(const Result& result) {
+    Clear();
+    model_type = result.model_type;
     if ("det" == model_type) {
-      delete det_result;
-      det_result = NULL;
+      det_result = new DetResult();
+      *det_result = *(result.det_result);
     } else if ("seg" == model_type) {
-      delete seg_result;
-      seg_result = NULL;
+      seg_result = new SegResult();
+      *seg_result = *(result.seg_result);
     } else if ("clas" == model_type) {
-      delete clas_result;
-      clas_result = NULL;
+      clas_result = new ClasResult();
+      *clas_result = *(result.clas_result);
     } else if ("ocr" == model_type) {
-      delete ocr_result;
-      ocr_result = NULL;
+      ocr_result = new OcrResult();
+      *ocr_result = *(result.ocr_result);
     }
+    return *this;
+  }
+
+
+  ~Result() {
+    Clear();
   }
 };
 

+ 1 - 0
dygraph/deploy/cpp/model_deploy/paddlex/include/x_preprocess.h

@@ -33,6 +33,7 @@ class XPreprocess : public BasePreprocess {
                    std::vector<DataBlob>* inputs,
                    std::vector<ShapeInfo>* shape_info,
                    int thread_num = 1);
+  virtual std::string GetModelName() { return model_name_; }
 
  private:
   std::string model_type_;

+ 28 - 0
dygraph/deploy/cpp/model_deploy/utils/include/bbox_utils.h

@@ -0,0 +1,28 @@
+// Copyright (c) 2021 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.
+
+#pragma once
+
+#include <iostream>
+#include <vector>
+
+#include "model_deploy/common/include/output_struct.h"
+
+namespace PaddleDeploy {
+
+bool FilterBbox(const std::vector<Result> &results,
+                const float &score_thresh,
+                std::vector<Result>* filter_results);
+
+}  // namespace PaddleDeploy

+ 43 - 0
dygraph/deploy/cpp/model_deploy/utils/include/visualize.h

@@ -0,0 +1,43 @@
+// Copyright (c) 2021 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.
+
+#pragma once
+
+#include <iostream>
+#include <map>
+#include <vector>
+#include <string>
+
+#include <opencv2/core/core.hpp>
+#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+
+#include "model_deploy/common/include/output_struct.h"
+
+namespace PaddleDeploy {
+
+bool GenerateColorMap(const int &num_classes,
+                      std::vector<int> *color_map);
+
+bool Visualize(const cv::Mat& img,
+               const DetResult& results,
+               cv::Mat* vis_img,
+               const int& num_classes = 81);
+
+bool Visualize(const cv::Mat& img,
+               const SegResult& result,
+               cv::Mat* vis_img,
+               const int& num_classes = 81);
+
+}  // namespace PaddleDeploy

+ 57 - 0
dygraph/deploy/cpp/model_deploy/utils/src/bbox_utils.cpp

@@ -0,0 +1,57 @@
+// Copyright (c) 2021 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.
+
+#include "model_deploy/utils/include/bbox_utils.h"
+
+namespace PaddleDeploy {
+
+bool FilterBbox(const std::vector<Result> &results,
+                const float &score_thresh,
+                std::vector<Result>* filter_results) {
+  for (auto i = 0; i < results.size(); ++i) {
+    if ("det" != results[i].model_type) {
+       std::cerr << "FilterBbox can be only done on results from a det model, "
+                 << "but the received results are from a "
+                 << results[i].model_type << " model." << std::endl;
+       return false;
+    }
+  }
+
+  for (auto i = 0; i < results.size(); ++i) {
+    Result result;
+    result.model_type = "det";
+    result.det_result = new DetResult();
+    std::vector<Box> boxes = results[i].det_result->boxes;
+    for (auto j = 0; j < boxes.size(); ++j) {
+      if (boxes[j].score >= score_thresh) {
+        Box box;
+        box.category_id = boxes[j].category_id;
+        box.category = boxes[j].category;
+        box.score = boxes[j].score;
+        box.coordinate.assign(boxes[j].coordinate.begin(),
+                              boxes[j].coordinate.end());
+        box.mask.data.assign(boxes[j].mask.data.begin(),
+                             boxes[j].mask.data.end());
+        box.mask.shape.assign(boxes[j].mask.shape.begin(),
+                              boxes[j].mask.shape.end());
+        result.det_result->boxes.push_back(std::move(box));
+      }
+    }
+    result.det_result->mask_resolution = results[i].det_result->mask_resolution;
+    filter_results->push_back(std::move(result));
+  }
+  return true;
+}
+
+}  // namespace PaddleDeploy

+ 130 - 0
dygraph/deploy/cpp/model_deploy/utils/src/visualize.cpp

@@ -0,0 +1,130 @@
+// Copyright (c) 2021 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.
+
+#include "model_deploy/utils/include/visualize.h"
+
+namespace PaddleDeploy {
+
+bool GenerateColorMap(const int &num_classes,
+                      std::vector<int> *color_map) {
+  *color_map = std::vector<int>(3 * num_classes, 0);
+  for (int i = 0; i < num_classes; ++i) {
+    int j = 0;
+    int lab = i;
+    while (lab) {
+      (*color_map)[i * 3] |= (((lab >> 0) & 1) << (7 - j));
+      (*color_map)[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j));
+      (*color_map)[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j));
+      ++j;
+      lab >>= 3;
+    }
+  }
+  return true;
+}
+
+bool Visualize(const cv::Mat& img,
+               const DetResult& result,
+               cv::Mat* vis_img,
+               const int& num_classes) {
+  std::vector<int> color_map;
+  GenerateColorMap(num_classes + 2, &color_map);
+  *vis_img = img.clone();
+  std::vector<Box> boxes = result.boxes;
+  for (auto i = 0; i < boxes.size(); ++i) {
+    cv::Rect roi = cv::Rect(boxes[i].coordinate[0],
+                            boxes[i].coordinate[1],
+                            boxes[i].coordinate[2],
+                            boxes[i].coordinate[3]);
+    // draw box and title
+    std::string text = boxes[i].category;
+    int category_id = boxes[i].category_id + 2;
+    int c1 = color_map[3 * category_id + 0];
+    int c2 = color_map[3 * category_id + 1];
+    int c3 = color_map[3 * category_id + 2];
+    cv::Scalar roi_color = cv::Scalar(c1, c2, c3);
+    text += std::to_string(static_cast<int>(boxes[i].score * 100)) + "%";
+    int font_face = cv::FONT_HERSHEY_SIMPLEX;
+    double font_scale = 0.5f;
+    float thickness = 0.5;
+    cv::Size text_size =
+        cv::getTextSize(text, font_face, font_scale, thickness, nullptr);
+    cv::Point origin;
+    origin.x = roi.x;
+    origin.y = roi.y;
+
+    // background
+    cv::Rect text_back = cv::Rect(boxes[i].coordinate[0],
+                                  boxes[i].coordinate[1] - text_size.height,
+                                  text_size.width,
+                                  text_size.height);
+
+    // draw
+    cv::rectangle(*vis_img, roi, roi_color, 2);
+    cv::rectangle(*vis_img, text_back, roi_color, -1);
+    cv::putText(*vis_img,
+                text,
+                origin,
+                font_face,
+                font_scale,
+                cv::Scalar(255, 255, 255),
+                thickness);
+
+    // mask
+    if (boxes[i].mask.data.size() == 0) {
+      continue;
+    }
+
+    cv::Mat full_mask(boxes[i].mask.shape[0],
+                      boxes[i].mask.shape[1],
+                      CV_8UC1,
+                      boxes[i].mask.data.data());
+    cv::Mat mask_ch[3];
+    mask_ch[0] = full_mask * c1;
+    mask_ch[1] = full_mask * c2;
+    mask_ch[2] = full_mask * c3;
+    cv::Mat mask;
+    cv::merge(mask_ch, 3, mask);
+    cv::addWeighted(*vis_img, 1, mask, 0.5, 0, *vis_img);
+  }
+  return true;
+}
+
+bool Visualize(const cv::Mat& img,
+               const SegResult& result,
+               cv::Mat* vis_img,
+               const int& num_classes) {
+  std::vector<int> color_map;
+  GenerateColorMap(num_classes, &color_map);
+  std::vector<uint8_t> label_map(result.label_map.data.begin(),
+                                 result.label_map.data.end());
+  cv::Mat mask(result.label_map.shape[0],
+               result.label_map.shape[1],
+               CV_8UC1,
+               label_map.data());
+  *vis_img = cv::Mat::zeros(
+      result.label_map.shape[0], result.label_map.shape[1], CV_8UC3);
+  int rows = img.rows;
+  int cols = img.cols;
+  for (int i = 0; i < rows; i++) {
+    for (int j = 0; j < cols; j++) {
+      int category_id = static_cast<int>(mask.at<uchar>(i, j));
+      vis_img->at<cv::Vec3b>(i, j)[0] = color_map[3 * category_id + 0];
+      vis_img->at<cv::Vec3b>(i, j)[1] = color_map[3 * category_id + 1];
+      vis_img->at<cv::Vec3b>(i, j)[2] = color_map[3 * category_id + 2];
+    }
+  }
+  return true;
+}
+
+}  // namespace PaddleDeploy

+ 0 - 1
dygraph/examples/meter_reader/train_segmentation.py

@@ -48,7 +48,6 @@ model.train(
     num_epochs=20,
     train_dataset=train_dataset,
     train_batch_size=4,
-    pretrain_weights='IMAGENET',
     eval_dataset=eval_dataset,
     learning_rate=0.1,
     save_dir='output/deeplabv3p_r50vd')

+ 40 - 1
dygraph/paddlex/cv/models/base.py

@@ -397,7 +397,7 @@ class BaseModel:
                             self.save_model(save_dir=best_model_dir)
                         if best_model_epoch > 0:
                             logging.info(
-                                'Current evaluated best model in eval_dataset is epoch_{}, {}={}'
+                                'Current evaluated best model on eval_dataset is epoch_{}, {}={}'
                                 .format(best_model_epoch, best_accuracy_key,
                                         best_accuracy))
                     eval_epoch_time = time.time() - eval_epoch_tic
@@ -527,6 +527,39 @@ class BaseModel:
                 .format(self.quant_config),
                 exit=True)
 
+    def _get_pipeline_info(self, save_dir):
+        pipeline_info = {}
+        pipeline_info["pipeline_name"] = self.model_type
+        nodes = [{
+            "src0": {
+                "type": "Source",
+                "next": "decode0"
+            }
+        }, {
+            "decode0": {
+                "type": "Decode",
+                "next": "predict0"
+            }
+        }, {
+            "predict0": {
+                "type": "Predict",
+                "init_params": {
+                    "use_gpu": False,
+                    "gpu_id": 0,
+                    "use_trt": False,
+                    "model_dir": save_dir,
+                },
+                "next": "sink0"
+            }
+        }, {
+            "sink0": {
+                "type": "Sink"
+            }
+        }]
+        pipeline_info["pipeline_nodes"] = nodes
+        pipeline_info["version"] = "1.0.0"
+        return pipeline_info
+
     def _export_inference_model(self, save_dir, image_shape=None):
         save_dir = osp.join(save_dir, 'inference_model')
         self.net.eval()
@@ -560,6 +593,12 @@ class BaseModel:
                 mode='w') as f:
             yaml.dump(model_info, f)
 
+        pipeline_info = self._get_pipeline_info(save_dir)
+        with open(
+                osp.join(save_dir, 'pipeline.yml'), encoding='utf-8',
+                mode='w') as f:
+            yaml.dump(pipeline_info, f)
+
         # 模型保存成功的标志
         open(osp.join(save_dir, '.success'), 'w').close()
         logging.info("The model for the inference deployment is saved in {}.".

+ 9 - 6
dygraph/paddlex/cv/models/segmenter.py

@@ -478,12 +478,15 @@ class BaseSegmenter(BaseModel):
         label_map = label_map.numpy().astype('uint8')
         score_map = outputs['score_map']
         score_map = score_map.numpy().astype('float32')
-        prediction = [{
-            'label_map': l,
-            'score_map': s
-        } for l, s in zip(label_map, score_map)]
-        if isinstance(img_file, (str, np.ndarray)):
-            prediction = prediction[0]
+        if isinstance(img_file, list) and len(img_file) > 1:
+            prediction = [{
+                'label_map': l,
+                'score_map': s
+            } for l, s in zip(label_map, score_map)]
+        elif isinstance(img_file, list):
+            prediction = [{'label_map': label_map, 'score_map': score_map}]
+        else:
+            prediction = {'label_map': label_map, 'score_map': score_map}
         return prediction
 
     def _preprocess(self, images, transforms, model_type):

+ 48 - 110
dygraph/paddlex/cv/models/utils/visualize.py

@@ -14,7 +14,6 @@
 
 import os
 import cv2
-import colorsys
 import numpy as np
 import time
 import pycocotools.mask as mask_util
@@ -37,7 +36,6 @@ def visualize_detection(image,
     else:
         image_name = os.path.split(image)[-1]
         image = cv2.imread(image)
-
     image = draw_bbox_mask(image, result, threshold=threshold, color_map=color)
     if save_dir is not None:
         if not os.path.exists(save_dir):
@@ -164,42 +162,10 @@ def clip_bbox(bbox):
 
 
 def draw_bbox_mask(image, results, threshold=0.5, color_map=None):
-    import matplotlib
-    matplotlib.use('Agg')
-    import matplotlib as mpl
-    import matplotlib.figure as mplfigure
-    import matplotlib.colors as mplc
-    from matplotlib.backends.backend_agg import FigureCanvasAgg
-
-    # refer to https://github.com/facebookresearch/detectron2/blob/master/detectron2/utils/visualizer.py
-    def _change_color_brightness(color, brightness_factor):
-        assert brightness_factor >= -1.0 and brightness_factor <= 1.0
-        color = mplc.to_rgb(color)
-        polygon_color = colorsys.rgb_to_hls(*mplc.to_rgb(color))
-        modified_lightness = polygon_color[1] + (brightness_factor *
-                                                 polygon_color[1])
-        modified_lightness = 0.0 if modified_lightness < 0.0 else modified_lightness
-        modified_lightness = 1.0 if modified_lightness > 1.0 else modified_lightness
-        modified_color = colorsys.hls_to_rgb(
-            polygon_color[0], modified_lightness, polygon_color[2])
-        return modified_color
-
     _SMALL_OBJECT_AREA_THRESH = 1000
-    # setup figure
-    width, height = image.shape[1], image.shape[0]
-    scale = 1
-    fig = mplfigure.Figure(frameon=False)
-    dpi = fig.get_dpi()
-    fig.set_size_inches(
-        (width * scale + 1e-2) / dpi,
-        (height * scale + 1e-2) / dpi, )
-    canvas = FigureCanvasAgg(fig)
-    ax = fig.add_axes([0.0, 0.0, 1.0, 1.0])
-    ax.axis("off")
-    ax.set_xlim(0.0, width)
-    ax.set_ylim(height)
-    default_font_size = max(np.sqrt(height * width) // 90, 10 // scale)
-    linewidth = max(default_font_size / 4, 1)
+    height, width = image.shape[:2]
+    default_font_scale = max(np.sqrt(height * width) // 900, .5)
+    linewidth = max(default_font_scale / 40, 2)
 
     labels = list()
     for dt in results:
@@ -233,100 +199,72 @@ def draw_bbox_mask(image, results, threshold=0.5, color_map=None):
 
     for dt in keep_results:
         cname, bbox, score = dt['category'], dt['bbox'], dt['score']
+        bbox = list(map(int, bbox))
         xmin, ymin, w, h = bbox
         xmax = xmin + w
         ymax = ymin + h
 
         color = tuple(color_map[labels.index(cname)])
-        color = [c / 255. for c in color]
         # draw bbox
-        ax.add_patch(
-            mpl.patches.Rectangle(
-                (xmin, ymin),
-                w,
-                h,
-                fill=False,
-                edgecolor=color,
-                linewidth=linewidth * scale,
-                alpha=0.8,
-                linestyle="-", ))
+        image = cv2.rectangle(image, (xmin, ymin), (xmax, ymax), color,
+                              linewidth)
 
         # draw mask
         if 'mask' in dt:
-            mask = mask_util.decode(dt['mask'])
-            mask = np.ascontiguousarray(mask)
-            res = cv2.findContours(
-                mask.astype("uint8"), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
-            hierarchy = res[-1]
-            alpha = 0.5
-            if hierarchy is not None:
-                has_holes = (hierarchy.reshape(-1, 4)[:, 3] >= 0).sum() > 0
-                res = res[-2]
-                res = [x.flatten() for x in res]
-                res = [x for x in res if len(x) >= 6]
-                for segment in res:
-                    segment = segment.reshape(-1, 2)
-                    edge_color = mplc.to_rgb(color) + (1, )
-                    polygon = mpl.patches.Polygon(
-                        segment,
-                        fill=True,
-                        facecolor=mplc.to_rgb(color) + (alpha, ),
-                        edgecolor=edge_color,
-                        linewidth=max(default_font_size // 15 * scale, 1), )
-                    ax.add_patch(polygon)
+            mask = mask_util.decode(dt['mask']) * 255
+            image = image.astype('float32')
+            alpha = .7
+            w_ratio = .4
+            color_mask = np.asarray(color, dtype=np.int)
+            for c in range(3):
+                color_mask[c] = color_mask[c] * (1 - w_ratio) + w_ratio * 255
+            idx = np.nonzero(mask)
+            image[idx[0], idx[1], :] *= 1.0 - alpha
+            image[idx[0], idx[1], :] += alpha * color_mask
+            image = image.astype("uint8")
+            contours = cv2.findContours(
+                mask.astype("uint8"), cv2.RETR_CCOMP,
+                cv2.CHAIN_APPROX_NONE)[-2]
+            image = cv2.drawContours(
+                image,
+                contours,
+                contourIdx=-1,
+                color=color,
+                thickness=1,
+                lineType=cv2.LINE_AA)
 
         # draw label
         text_pos = (xmin, ymin)
-        horiz_align = "left"
         instance_area = w * h
-        if (instance_area < _SMALL_OBJECT_AREA_THRESH * scale or
-                h < 40 * scale):
+        if (instance_area < _SMALL_OBJECT_AREA_THRESH or h < 40):
             if ymin >= height - 5:
                 text_pos = (xmin, ymin)
             else:
                 text_pos = (xmin, ymax)
         height_ratio = h / np.sqrt(height * width)
-        font_size = (np.clip((height_ratio - 0.02) / 0.08 + 1, 1.2,
-                             2) * 0.5 * default_font_size)
+        font_scale = (np.clip((height_ratio - 0.02) / 0.08 + 1, 1.2,
+                              2) * 0.5 * default_font_scale)
         text = "{} {:.2f}".format(cname, score)
-        color = np.maximum(list(mplc.to_rgb(color)), 0.2)
-        color[np.argmax(color)] = max(0.8, np.max(color))
-        color = _change_color_brightness(color, brightness_factor=0.7)
-        ax.text(
-            text_pos[0],
-            text_pos[1],
+        (tw, th), baseline = cv2.getTextSize(
             text,
-            size=font_size * scale,
-            family="sans-serif",
-            bbox={
-                "facecolor": "black",
-                "alpha": 0.8,
-                "pad": 0.7,
-                "edgecolor": "none"
-            },
-            verticalalignment="top",
-            horizontalalignment=horiz_align,
+            fontFace=cv2.FONT_HERSHEY_DUPLEX,
+            fontScale=font_scale,
+            thickness=1)
+        image = cv2.rectangle(
+            image,
+            text_pos, (text_pos[0] + tw, text_pos[1] + th + baseline),
             color=color,
-            zorder=10,
-            rotation=0, )
-
-    s, (width, height) = canvas.print_to_buffer()
-    buffer = np.frombuffer(s, dtype="uint8")
-
-    img_rgba = buffer.reshape(height, width, 4)
-    rgb, alpha = np.split(img_rgba, [3], axis=2)
-
-    try:
-        import numexpr as ne
-        visualized_image = ne.evaluate(
-            "image * (1 - alpha / 255.0) + rgb * (alpha / 255.0)")
-    except ImportError:
-        alpha = alpha.astype("float32") / 255.0
-        visualized_image = image * (1 - alpha) + rgb * alpha
-
-    visualized_image = visualized_image.astype("uint8")
-
-    return visualized_image
+            thickness=-1)
+        image = cv2.putText(
+            image,
+            text, (text_pos[0], text_pos[1] + th),
+            fontFace=cv2.FONT_HERSHEY_DUPLEX,
+            fontScale=font_scale,
+            color=(255, 255, 255),
+            thickness=1,
+            lineType=cv2.LINE_AA)
+
+    return image
 
 
 def draw_pr_curve(eval_details_file=None,

+ 2 - 6
dygraph/paddlex/utils/checkpoint.py

@@ -20,7 +20,7 @@ from .download import download_and_decompress
 
 seg_pretrain_weights_dict = {
     'UNet': ['CITYSCAPES'],
-    'DeepLabV3P': ['CITYSCAPES', 'PascalVOC', 'IMAGENET'],
+    'DeepLabV3P': ['CITYSCAPES', 'PascalVOC'],
     'FastSCNN': ['CITYSCAPES'],
     'HRNet': ['CITYSCAPES', 'PascalVOC'],
     'BiSeNetV2': ['CITYSCAPES']
@@ -254,11 +254,7 @@ imagenet_weights = {
     'MaskRCNN_ResNet101_fpn_IMAGENET':
     'https://paddledet.bj.bcebos.com/models/pretrained/ResNet101_pretrained.pdparams',
     'MaskRCNN_ResNet101_vd_fpn_IMAGENET':
-    'https://paddledet.bj.bcebos.com/models/pretrained/ResNet101_vd_pretrained.pdparams',
-    'DeepLabV3P_ResNet50_vd_IMAGENET':
-    'https://bj.bcebos.com/paddleseg/dygraph/resnet50_vd_ssld.tar.gz',
-    'DeepLabV3P_ResNet101_vd_IMAGENET':
-    'https://bj.bcebos.com/paddleseg/dygraph/resnet101_vd_ssld.tar.gz'
+    'https://paddledet.bj.bcebos.com/models/pretrained/ResNet101_vd_pretrained.pdparams'
 }
 
 pascalvoc_weights = {

+ 47 - 0
dygraph/tutorials/slim/quantize/instance_segmentation/mask_rcnn_qat.py

@@ -0,0 +1,47 @@
+import paddlex as pdx
+from paddlex import transforms as T
+
+# 下载和解压小度熊分拣数据集
+dataset = 'https://bj.bcebos.com/paddlex/datasets/xiaoduxiong_ins_det.tar.gz'
+pdx.utils.download_and_decompress(dataset, path='./')
+
+# 定义训练和验证时的transforms
+# API说明:https://github.com/PaddlePaddle/PaddleX/blob/release/2.0-rc/paddlex/cv/transforms/operators.py
+train_transforms = T.Compose([
+    T.RandomResizeByShort(
+        short_sizes=[640, 672, 704, 736, 768, 800],
+        max_size=1333,
+        interp='CUBIC'), T.RandomHorizontalFlip(), T.Normalize(
+            mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
+])
+
+eval_transforms = T.Compose([
+    T.ResizeByShort(
+        short_size=800, max_size=1333, interp='CUBIC'), T.Normalize(
+            mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
+])
+
+# 定义训练和验证所用的数据集
+# API说明:https://github.com/PaddlePaddle/PaddleX/blob/develop/dygraph/paddlex/cv/datasets/coco.py#L26
+train_dataset = pdx.datasets.CocoDetection(
+    data_dir='xiaoduxiong_ins_det/JPEGImages',
+    ann_file='xiaoduxiong_ins_det/train.json',
+    transforms=train_transforms,
+    shuffle=True)
+eval_dataset = pdx.datasets.CocoDetection(
+    data_dir='xiaoduxiong_ins_det/JPEGImages',
+    ann_file='xiaoduxiong_ins_det/val.json',
+    transforms=eval_transforms)
+
+# 加载模型
+model = pdx.load_model('output/mask_rcnn_r50_fpn/best_model')
+
+# 在线量化
+model.quant_aware_train(
+    num_epochs=6,
+    train_dataset=train_dataset,
+    train_batch_size=1,
+    eval_dataset=eval_dataset,
+    learning_rate=0.000125,
+    save_dir='output/mask_rcnn_r50_fpn/quant',
+    use_vdl=True)

+ 55 - 0
dygraph/tutorials/slim/quantize/instance_segmentation/mask_rcnn_train.py

@@ -0,0 +1,55 @@
+import paddlex as pdx
+from paddlex import transforms as T
+
+# 下载和解压小度熊分拣数据集
+dataset = 'https://bj.bcebos.com/paddlex/datasets/xiaoduxiong_ins_det.tar.gz'
+pdx.utils.download_and_decompress(dataset, path='./')
+
+# 定义训练和验证时的transforms
+# API说明:https://github.com/PaddlePaddle/PaddleX/blob/release/2.0-rc/paddlex/cv/transforms/operators.py
+train_transforms = T.Compose([
+    T.RandomResizeByShort(
+        short_sizes=[640, 672, 704, 736, 768, 800],
+        max_size=1333,
+        interp='CUBIC'), T.RandomHorizontalFlip(), T.Normalize(
+            mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
+])
+
+eval_transforms = T.Compose([
+    T.ResizeByShort(
+        short_size=800, max_size=1333, interp='CUBIC'), T.Normalize(
+            mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
+])
+
+# 定义训练和验证所用的数据集
+# API说明:https://github.com/PaddlePaddle/PaddleX/blob/develop/dygraph/paddlex/cv/datasets/coco.py#L26
+train_dataset = pdx.datasets.CocoDetection(
+    data_dir='xiaoduxiong_ins_det/JPEGImages',
+    ann_file='xiaoduxiong_ins_det/train.json',
+    transforms=train_transforms,
+    shuffle=True)
+eval_dataset = pdx.datasets.CocoDetection(
+    data_dir='xiaoduxiong_ins_det/JPEGImages',
+    ann_file='xiaoduxiong_ins_det/val.json',
+    transforms=eval_transforms)
+
+# 初始化模型,并进行训练
+# 可使用VisualDL查看训练指标,参考https://github.com/PaddlePaddle/PaddleX/tree/release/2.0-rc/tutorials/train#visualdl可视化训练指标
+num_classes = len(train_dataset.labels)
+model = pdx.det.MaskRCNN(
+    num_classes=num_classes, backbone='ResNet50', with_fpn=True)
+
+# API说明:https://github.com/PaddlePaddle/PaddleX/blob/release/2.0-rc/paddlex/cv/models/detector.py#L155
+# 各参数介绍与调整说明:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html
+model.train(
+    num_epochs=12,
+    train_dataset=train_dataset,
+    train_batch_size=1,
+    eval_dataset=eval_dataset,
+    pretrain_weights='COCO',
+    learning_rate=0.00125,
+    lr_decay_epochs=[8, 11],
+    warmup_steps=10,
+    warmup_start_lr=0.0,
+    save_dir='output/mask_rcnn_r50_fpn',
+    use_vdl=True)

+ 2 - 1
dygraph/tutorials/slim/quantize/object_detection/yolov3_qat.py

@@ -52,4 +52,5 @@ model.quant_aware_train(
     warmup_start_lr=0.0,
     save_interval_epochs=1,
     lr_decay_epochs=[30, 45],
-    save_dir='output/yolov3_darknet53/quant')
+    save_dir='output/yolov3_darknet53/quant',
+    use_vdl=True)

+ 2 - 1
dygraph/tutorials/slim/quantize/semantic_segmentation/unet_qat.py

@@ -46,4 +46,5 @@ model.quant_aware_train(
     train_batch_size=4,
     eval_dataset=eval_dataset,
     learning_rate=0.001,
-    save_dir='output/unet/quant')
+    save_dir='output/unet/quant',
+    use_vdl=True)

+ 1 - 0
dygraph/tutorials/train/instance_segmentation/mask_rcnn_r50_fpn.py

@@ -46,6 +46,7 @@ model.train(
     train_dataset=train_dataset,
     train_batch_size=1,
     eval_dataset=eval_dataset,
+    pretrain_weights='COCO',
     learning_rate=0.00125,
     lr_decay_epochs=[8, 11],
     warmup_steps=10,

+ 5 - 4
dygraph/tutorials/train/object_detection/ppyolo.py

@@ -8,7 +8,7 @@ pdx.utils.download_and_decompress(dataset, path='./')
 # 定义训练和验证时的transforms
 # API说明:https://github.com/PaddlePaddle/PaddleX/blob/release/2.0-rc/paddlex/cv/transforms/operators.py
 train_transforms = T.Compose([
-    T.MixupImage(mixup_epoch=250), T.RandomDistort(),
+    T.MixupImage(mixup_epoch=-1), T.RandomDistort(),
     T.RandomExpand(im_padding_value=[123.675, 116.28, 103.53]), T.RandomCrop(),
     T.RandomHorizontalFlip(), T.BatchRandomResize(
         target_sizes=[320, 352, 384, 416, 448, 480, 512, 544, 576, 608],
@@ -46,14 +46,15 @@ model = pdx.det.PPYOLO(num_classes=num_classes, backbone='ResNet50_vd_dcn')
 # API说明:https://github.com/PaddlePaddle/PaddleX/blob/release/2.0-rc/paddlex/cv/models/detector.py#L155
 # 各参数介绍与调整说明:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html
 model.train(
-    num_epochs=405,
+    num_epochs=200,
     train_dataset=train_dataset,
     train_batch_size=8,
     eval_dataset=eval_dataset,
+    pretrain_weights='COCO',
     learning_rate=0.005 / 12,
-    warmup_steps=1000,
+    warmup_steps=500,
     warmup_start_lr=0.0,
     save_interval_epochs=5,
-    lr_decay_epochs=[243, 324],
+    lr_decay_epochs=[85, 135],
     save_dir='output/ppyolo_r50vd_dcn',
     use_vdl=True)

+ 6 - 4
dygraph/tutorials/train/object_detection/ppyolotiny.py

@@ -8,7 +8,7 @@ pdx.utils.download_and_decompress(dataset, path='./')
 # 定义训练和验证时的transforms
 # API说明:https://github.com/PaddlePaddle/PaddleX/blob/release/2.0-rc/paddlex/cv/transforms/operators.py
 train_transforms = T.Compose([
-    T.MixupImage(mixup_epoch=250), T.RandomDistort(),
+    T.MixupImage(mixup_epoch=-1), T.RandomDistort(),
     T.RandomExpand(im_padding_value=[123.675, 116.28, 103.53]), T.RandomCrop(),
     T.RandomHorizontalFlip(), T.BatchRandomResize(
         target_sizes=[192, 224, 256, 288, 320, 352, 384, 416, 448, 480, 512],
@@ -46,14 +46,16 @@ model = pdx.det.PPYOLOTiny(num_classes=num_classes)
 # API说明:https://github.com/PaddlePaddle/PaddleX/blob/release/2.0-rc/paddlex/cv/models/detector.py#L155
 # 各参数介绍与调整说明:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html
 model.train(
-    num_epochs=650,
+    num_epochs=550,
     train_dataset=train_dataset,
     train_batch_size=16,
     eval_dataset=eval_dataset,
-    learning_rate=0.005 / 16,
+    pretrain_weights='COCO',
+    learning_rate=0.005,
     warmup_steps=1000,
     warmup_start_lr=0.0,
-    lr_decay_epochs=[430, 540, 610],
+    lr_decay_epochs=[130, 540],
+    lr_decay_gamma=.5,
     save_interval_epochs=5,
     save_dir='output/ppyolotiny',
     use_vdl=True)

+ 4 - 3
dygraph/tutorials/train/object_detection/ppyolov2.py

@@ -8,7 +8,7 @@ pdx.utils.download_and_decompress(dataset, path='./')
 # 定义训练和验证时的transforms
 # API说明:https://github.com/PaddlePaddle/PaddleX/blob/release/2.0-rc/paddlex/cv/transforms/operators.py
 train_transforms = T.Compose([
-    T.MixupImage(mixup_epoch=250), T.RandomDistort(),
+    T.MixupImage(mixup_epoch=-1), T.RandomDistort(),
     T.RandomExpand(im_padding_value=[123.675, 116.28, 103.53]), T.RandomCrop(),
     T.RandomHorizontalFlip(), T.BatchRandomResize(
         target_sizes=[
@@ -49,13 +49,14 @@ model = pdx.det.PPYOLOv2(num_classes=num_classes, backbone='ResNet50_vd_dcn')
 # API说明:https://github.com/PaddlePaddle/PaddleX/blob/release/2.0-rc/paddlex/cv/models/detector.py#L155
 # 各参数介绍与调整说明:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html
 model.train(
-    num_epochs=365,
+    num_epochs=170,
     train_dataset=train_dataset,
     train_batch_size=8,
     eval_dataset=eval_dataset,
+    pretrain_weights='COCO',
     learning_rate=0.005 / 12,
     warmup_steps=1000,
     warmup_start_lr=0.0,
-    lr_decay_epochs=[243],
+    lr_decay_epochs=[105, 135, 150],
     save_interval_epochs=5,
     save_dir='output/ppyolov2_r50vd_dcn')