Kaynağa Gözat

add openvino

Channingss 5 yıl önce
ebeveyn
işleme
3ce491c48b

+ 103 - 0
deploy/openvino/CMakeLists.txt

@@ -0,0 +1,103 @@
+cmake_minimum_required(VERSION 3.0)
+project(PaddleX CXX C)
+
+
+option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static."   OFF)
+
+SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
+SET(OPENVINO_LIB "" CACHE PATH "Location of libraries")
+SET(OPENCV_DIR "" CACHE PATH "Location of libraries")
+
+include(cmake/yaml-cpp.cmake)
+
+include_directories("${CMAKE_SOURCE_DIR}/")
+link_directories("${CMAKE_CURRENT_BINARY_DIR}")
+include_directories("${CMAKE_CURRENT_BINARY_DIR}/ext/yaml-cpp/src/ext-yaml-cpp/include")
+link_directories("${CMAKE_CURRENT_BINARY_DIR}/ext/yaml-cpp/lib")
+
+macro(safe_set_static_flag)
+    foreach(flag_var
+        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+      if(${flag_var} MATCHES "/MD")
+        string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+      endif(${flag_var} MATCHES "/MD")
+    endforeach(flag_var)
+endmacro()
+
+if (NOT DEFINED OPENVINO_LIB OR ${OPENVINO_LIB} STREQUAL "")
+    message(FATAL_ERROR "please set OPENVINO_LIB with -DOPENVINO_LIB=/path/influence_engine")
+endif()
+
+if (NOT DEFINED OPENCV_DIR OR ${OPENCV_DIR} STREQUAL "")
+    message(FATAL_ERROR "please set OPENCV_DIR with -DOPENCV_DIR=/path/opencv")
+endif()
+
+include_directories("${OPENVINO_LIB}/")
+include_directories("${OPENVINO_LIB}/include/")
+link_directories("${OPENVINO_LIB}/lib")
+link_directories("${OPENVINO_LIB}/externel/tbb/lib/")
+
+if (WIN32)
+  find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/build/ NO_DEFAULT_PATH)
+  unset(OpenCV_DIR CACHE)
+else ()
+  find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/share/OpenCV NO_DEFAULT_PATH)
+endif ()
+
+include_directories(${OpenCV_INCLUDE_DIRS})
+
+if (WIN32)
+    add_definitions("/DGOOGLE_GLOG_DLL_DECL=")
+    set(CMAKE_C_FLAGS_DEBUG   "${CMAKE_C_FLAGS_DEBUG} /bigobj /MTd")
+    set(CMAKE_C_FLAGS_RELEASE  "${CMAKE_C_FLAGS_RELEASE} /bigobj /MT")
+    set(CMAKE_CXX_FLAGS_DEBUG  "${CMAKE_CXX_FLAGS_DEBUG} /bigobj /MTd")
+    set(CMAKE_CXX_FLAGS_RELEASE   "${CMAKE_CXX_FLAGS_RELEASE} /bigobj /MT")
+    if (WITH_STATIC_LIB)
+        safe_set_static_flag()
+        add_definitions(-DSTATIC_LIB)
+    endif()
+else()
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -o2 -fopenmp -std=c++11")
+    set(CMAKE_STATIC_LIBRARY_PREFIX "")
+endif()
+
+if (NOT WIN32)
+    set(NGRAPH_PATH "${OPENVINO_LIB}")
+    if(EXISTS ${NGRAPH_PATH})
+        include(GNUInstallDirs)
+        include_directories("${NGRAPH_PATH}/include")
+        link_directories("${NGRAPH_PATH}/${CMAKE_INSTALL_LIBDIR}")
+        set(NGRAPH_LIB ${NGRAPH_PATH}/${CMAKE_INSTALL_LIBDIR}/libngraph${CMAKE_SHARED_LIBRARY_SUFFIX})
+    endif()
+endif()
+
+if(WITH_STATIC_LIB)
+	set(DEPS ${OPENVINO_LIB}/lib/intel64/libinference_engine${CMAKE_STATIC_LIBRARY_SUFFIX})
+	set(DEPS ${DEPS} ${OPENVINO_LIB}/lib/intel64/libinference_engine_legacy${CMAKE_STATIC_LIBRARY_SUFFIX})
+else()
+	set(DEPS ${OPENVINO_LIB}/lib/intel64/libinference_engine${CMAKE_SHARED_LIBRARY_SUFFIX})
+	set(DEPS ${DEPS} ${OPENVINO_LIB}/lib/intel64/libinference_engine_legacy${CMAKE_SHARED_LIBRARY_SUFFIX})
+endif()
+
+if (NOT WIN32)
+    set(DEPS ${DEPS}
+        glog gflags  z  yaml-cpp
+        )
+else()
+    set(DEPS ${DEPS}
+        glog gflags_static libprotobuf zlibstatic xxhash libyaml-cppmt)
+    set(DEPS ${DEPS} libcmt shlwapi)
+endif(NOT WIN32)
+
+
+if (NOT WIN32)
+    set(EXTERNAL_LIB "-ldl -lrt -lgomp -lz -lm -lpthread")
+    set(DEPS ${DEPS} ${EXTERNAL_LIB})
+endif()
+
+set(DEPS ${DEPS} ${OpenCV_LIBS})
+add_executable(classifier src/classifier.cpp src/transforms.cpp src/paddlex.cpp)
+ADD_DEPENDENCIES(classifier ext-yaml-cpp)
+target_link_libraries(classifier ${DEPS})
+

+ 47 - 0
deploy/openvino/CMakeSettings.json

@@ -0,0 +1,47 @@
+{
+    "configurations": [
+        {
+            "name": "x64-Release",
+            "generator": "Ninja",
+            "configurationType": "RelWithDebInfo",
+            "inheritEnvironments": [ "msvc_x64_x64" ],
+            "buildRoot": "${projectDir}\\out\\build\\${name}",
+            "installRoot": "${projectDir}\\out\\install\\${name}",
+            "cmakeCommandArgs": "",
+            "buildCommandArgs": "-v",
+            "ctestCommandArgs": "",
+            "variables": [
+                {
+                    "name": "OPENCV_DIR",
+                    "value": "C:/projects/opencv",
+                    "type": "PATH"
+                },
+                {
+                    "name": "PADDLE_DIR",
+                    "value": "C:/projects/fluid_install_dir_win_cpu_1.6/fluid_install_dir_win_cpu_1.6",
+                    "type": "PATH"
+                },
+                {
+                    "name": "CMAKE_BUILD_TYPE",
+                    "value": "Release",
+                    "type": "STRING"
+                },
+                {
+                    "name": "WITH_STATIC_LIB",
+                    "value": "True",
+                    "type": "BOOL"
+                },
+                {
+                    "name": "WITH_MKL",
+                    "value": "True",
+                    "type": "BOOL"
+                },
+                {
+                    "name": "WITH_GPU",
+                    "value": "False",
+                    "type": "BOOL"
+                }
+            ]
+        }
+    ]
+}

+ 30 - 0
deploy/openvino/cmake/yaml-cpp.cmake

@@ -0,0 +1,30 @@
+find_package(Git REQUIRED)
+
+include(ExternalProject)
+
+message("${CMAKE_BUILD_TYPE}")
+
+ExternalProject_Add(
+        ext-yaml-cpp
+        URL https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip
+        URL_MD5 9542d6de397d1fbd649ed468cb5850e6
+        CMAKE_ARGS
+        -DYAML_CPP_BUILD_TESTS=OFF
+        -DYAML_CPP_BUILD_TOOLS=OFF
+        -DYAML_CPP_INSTALL=OFF
+        -DYAML_CPP_BUILD_CONTRIB=OFF
+        -DMSVC_SHARED_RT=OFF
+        -DBUILD_SHARED_LIBS=OFF
+        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+        -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
+        -DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG}
+        -DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE}
+        -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}/ext/yaml-cpp/lib
+        -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}/ext/yaml-cpp/lib
+        PREFIX "${CMAKE_BINARY_DIR}/ext/yaml-cpp"
+        # Disable install step
+        INSTALL_COMMAND ""
+        LOG_DOWNLOAD ON
+        LOG_BUILD 1
+)
+

+ 57 - 0
deploy/openvino/include/paddlex/config_parser.h

@@ -0,0 +1,57 @@
+//   Copyright (c) 2020 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 <string>
+#include <vector>
+
+#include "yaml-cpp/yaml.h"
+
+#ifdef _WIN32
+#define OS_PATH_SEP "\\"
+#else
+#define OS_PATH_SEP "/"
+#endif
+
+namespace PaddleX {
+
+// Inference model configuration parser
+class ConfigPaser {
+ public:
+  ConfigPaser() {}
+
+  ~ConfigPaser() {}
+
+  bool load_config(const std::string& model_dir,
+                   const std::string& cfg = "model.yml") {
+    // Load as a YAML::Node
+    YAML::Node config;
+    config = YAML::LoadFile(model_dir + OS_PATH_SEP + cfg);
+
+    if (config["Transforms"].IsDefined()) {
+      YAML::Node transforms_ = config["Transforms"];
+    } else {
+      std::cerr << "There's no field 'Transforms' in model.yml" << std::endl;
+      return false;
+    }
+    return true;
+  }
+
+  YAML::Node Transforms_;
+};
+
+}  // namespace PaddleDetection

+ 64 - 0
deploy/openvino/include/paddlex/paddlex.h

@@ -0,0 +1,64 @@
+//   Copyright (c) 2020 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 <functional>
+#include <iostream>
+#include <numeric>
+
+#include "yaml-cpp/yaml.h"
+
+#ifdef _WIN32
+#define OS_PATH_SEP "\\"
+#else
+#define OS_PATH_SEP "/"
+#endif
+
+#include <inference_engine.hpp>
+#include "include/paddlex/config_parser.h"
+#include "include/paddlex/results.h"
+#include "include/paddlex/transforms.h"
+using namespace InferenceEngine;
+
+namespace PaddleX {
+
+class Model {
+ public:
+  void Init(const std::string& model_dir,
+            const std::string& cfg_dir,
+            std::string device) {
+    create_predictor(model_dir, cfg_dir,  device);
+  }
+
+  void create_predictor(const std::string& model_dir,
+                        const std::string& cfg_dir,
+                        std::string device);
+
+  bool load_config(const std::string& model_dir);
+
+  bool preprocess(cv::Mat* input_im, ImageBlob* blob);
+
+  bool predict(cv::Mat* im, ClsResult* result);
+
+  std::string type;
+  std::string name;
+  std::vector<std::string> labels;
+  Transforms transforms_;
+  ImageBlob inputs_;
+  float* outputs_;
+  ExecutableNetwork executable_network_;
+  CNNNetwork network_;
+};
+}  // namespce of PaddleX

+ 71 - 0
deploy/openvino/include/paddlex/results.h

@@ -0,0 +1,71 @@
+//   Copyright (c) 2020 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 <string>
+#include <vector>
+
+namespace PaddleX {
+
+template <class T>
+struct Mask {
+  std::vector<T> data;
+  std::vector<int> shape;
+  void clear() {
+    data.clear();
+    shape.clear();
+  }
+};
+
+struct Box {
+  int category_id;
+  std::string category;
+  float score;
+  std::vector<float> coordinate;
+  Mask<float> mask;
+};
+
+class BaseResult {
+ public:
+  std::string type = "base";
+};
+
+class ClsResult : public BaseResult {
+ public:
+  int category_id;
+  std::string category;
+  float score;
+  std::string type = "cls";
+};
+
+class DetResult : public BaseResult {
+ public:
+  std::vector<Box> boxes;
+  int mask_resolution;
+  std::string type = "det";
+  void clear() { boxes.clear(); }
+};
+
+class SegResult : public BaseResult {
+ public:
+  Mask<int64_t> label_map;
+  Mask<float> score_map;
+  void clear() {
+    label_map.clear();
+    score_map.clear();
+  }
+};
+}  // namespce of PaddleX

+ 194 - 0
deploy/openvino/include/paddlex/transforms.h

@@ -0,0 +1,194 @@
+//   Copyright (c) 2020 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 <yaml-cpp/yaml.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <opencv2/core/core.hpp>
+#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+
+namespace PaddleX {
+
+// Object for storing all preprocessed data
+class ImageBlob {
+ public:
+  // Original image height and width
+  std::vector<int> ori_im_size_ = std::vector<int>(2);
+  // Newest image height and width after process
+  std::vector<int> new_im_size_ = std::vector<int>(2);
+  // Image height and width before resize
+  std::vector<std::vector<int>> im_size_before_resize_;
+  // Reshape order
+  std::vector<std::string> reshape_order_;
+  // Resize scale
+  float scale = 1.0;
+  // Buffer for image data after preprocessing
+  std::vector<float> im_data_;
+
+  void clear() {
+    ori_im_size_.clear();
+    new_im_size_.clear();
+    im_size_before_resize_.clear();
+    reshape_order_.clear();
+    im_data_.clear();
+  }
+};
+
+// Abstraction of preprocessing opration class
+class Transform {
+ public:
+  virtual void Init(const YAML::Node& item) = 0;
+  virtual bool Run(cv::Mat* im, ImageBlob* data) = 0;
+};
+
+class Normalize : public Transform {
+ public:
+  virtual void Init(const YAML::Node& item) {
+    mean_ = item["mean"].as<std::vector<float>>();
+    std_ = item["std"].as<std::vector<float>>();
+  }
+
+  virtual bool Run(cv::Mat* im, ImageBlob* data);
+
+ private:
+  std::vector<float> mean_;
+  std::vector<float> std_;
+};
+
+class ResizeByShort : public Transform {
+ public:
+  virtual void Init(const YAML::Node& item) {
+    short_size_ = item["short_size"].as<int>();
+    if (item["max_size"].IsDefined()) {
+      max_size_ = item["max_size"].as<int>();
+    } else {
+      max_size_ = -1;
+    }
+  };
+  virtual bool Run(cv::Mat* im, ImageBlob* data);
+
+ private:
+  float GenerateScale(const cv::Mat& im);
+  int short_size_;
+  int max_size_;
+};
+
+class ResizeByLong : public Transform {
+ public:
+  virtual void Init(const YAML::Node& item) {
+    long_size_ = item["long_size"].as<int>();
+  };
+  virtual bool Run(cv::Mat* im, ImageBlob* data);
+
+ private:
+  int long_size_;
+};
+
+class Resize : public Transform {
+ public:
+  virtual void Init(const YAML::Node& item) {
+    if (item["target_size"].IsScalar()) {
+      height_ = item["target_size"].as<int>();
+      width_ = item["target_size"].as<int>();
+      interp_ = item["interp"].as<std::string>();
+    } else if (item["target_size"].IsSequence()) {
+      std::vector<int> target_size = item["target_size"].as<std::vector<int>>();
+      width_ = target_size[0];
+      height_ = target_size[1];
+    }
+    if (height_ <= 0 || width_ <= 0) {
+      std::cerr << "[Resize] target_size should greater than 0" << std::endl;
+      exit(-1);
+    }
+  }
+  virtual bool Run(cv::Mat* im, ImageBlob* data);
+
+ private:
+  int height_;
+  int width_;
+  std::string interp_;
+};
+
+class CenterCrop : public Transform {
+ public:
+  virtual void Init(const YAML::Node& item) {
+    if (item["crop_size"].IsScalar()) {
+      height_ = item["crop_size"].as<int>();
+      width_ = item["crop_size"].as<int>();
+    } else if (item["crop_size"].IsSequence()) {
+      std::vector<int> crop_size = item["crop_size"].as<std::vector<int>>();
+      width_ = crop_size[0];
+      height_ = crop_size[1];
+    }
+  }
+  virtual bool Run(cv::Mat* im, ImageBlob* data);
+
+ private:
+  int height_;
+  int width_;
+};
+
+class Padding : public Transform {
+ public:
+  virtual void Init(const YAML::Node& item) {
+    if (item["coarsest_stride"].IsDefined()) {
+      coarsest_stride_ = item["coarsest_stride"].as<int>();
+      if (coarsest_stride_ < 1) {
+        std::cerr << "[Padding] coarest_stride should greater than 0"
+                  << std::endl;
+        exit(-1);
+      }
+    }
+    if (item["target_size"].IsDefined()) {
+      if (item["target_size"].IsScalar()) {
+        width_ = item["target_size"].as<int>();
+        height_ = item["target_size"].as<int>();
+      } else if (item["target_size"].IsSequence()) {
+        width_ = item["target_size"].as<std::vector<int>>()[0];
+        height_ = item["target_size"].as<std::vector<int>>()[1];
+      }
+    }
+    if (item["im_padding_value"].IsDefined()) {
+      value_ = item["im_padding_value"].as<std::vector<float>>();
+    }
+  }
+  virtual bool Run(cv::Mat* im, ImageBlob* data);
+
+ private:
+  int coarsest_stride_ = -1;
+  int width_ = 0;
+  int height_ = 0;
+  std::vector<float> value_;
+};
+
+class Transforms {
+ public:
+  void Init(const YAML::Node& node, bool to_rgb = true);
+  std::shared_ptr<Transform> CreateTransform(const std::string& name);
+  bool Run(cv::Mat* im, ImageBlob* data);
+
+ private:
+  std::vector<std::shared_ptr<Transform>> transforms_;
+  bool to_rgb_ = true;
+};
+
+}  // namespace PaddleX

+ 10 - 0
deploy/openvino/scripts/bootstrap.sh

@@ -0,0 +1,10 @@
+# download pre-compiled opencv lib
+OPENCV_URL=https://paddleseg.bj.bcebos.com/deploy/docker/opencv3gcc4.8.tar.bz2
+if [ ! -d "./deps/opencv3gcc4.8" ]; then
+    mkdir -p deps
+    cd deps
+    wget -c ${OPENCV_URL}
+    tar xvfj opencv3gcc4.8.tar.bz2
+    rm -rf opencv3gcc4.8.tar.bz2
+    cd ..
+fi

+ 13 - 0
deploy/openvino/scripts/build.sh

@@ -0,0 +1,13 @@
+WITH_STATIC_LIB=OFF
+OPENVINO_LIB=/usr/local/deployment_tools/inference_engine/
+# OPENCV 路径, 如果使用自带预编译版本可不修改
+OPENCV_DIR=$(pwd)/deps/opencv3gcc4.8/
+sh $(pwd)/scripts/bootstrap.sh
+rm -rf build
+mkdir -p build
+cd build
+cmake .. \
+    -DOPENCV_DIR=${OPENCV_DIR} \
+    -DOPENVINO_LIB=${OPENVINO_LIB} \
+    -DWITH_STATIC_LIB=${WITH_STATIC_LIB}
+make

+ 73 - 0
deploy/openvino/src/classifier.cpp

@@ -0,0 +1,73 @@
+//   Copyright (c) 2020 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 <glog/logging.h>
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "include/paddlex/paddlex.h"
+
+DEFINE_string(model_dir, "../../../openvino/model-optimizer/resnet18/best_model.xml", "Path of inference model");
+DEFINE_string(cfg_dir, "../../../openvino/model-optimizer/resnet18/model.yml", "Path of inference model");
+DEFINE_string(device, "CPU", "Device name");
+DEFINE_string(image, "/chenlingchi/docker/unet_test.jpg", "Path of test image file");
+DEFINE_string(image_list, "", "Path of test image list file");
+
+int main(int argc, char** argv) {
+  // Parsing command-line
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  if (FLAGS_model_dir == "") {
+    std::cerr << "--model_dir need to be defined" << std::endl;
+    return -1;
+  }
+  if (FLAGS_image == "" & FLAGS_image_list == "") {
+    std::cerr << "--image or --image_list need to be defined" << std::endl;
+    return -1;
+  }
+
+  // 加载模型
+  PaddleX::Model model;
+  model.Init(FLAGS_model_dir, FLAGS_cfg_dir, FLAGS_device);
+
+  // 进行预测
+  if (FLAGS_image_list != "") {
+    std::ifstream inf(FLAGS_image_list);
+    if (!inf) {
+      std::cerr << "Fail to open file " << FLAGS_image_list << std::endl;
+      return -1;
+    }
+    std::string image_path;
+    while (getline(inf, image_path)) {
+      PaddleX::ClsResult result;
+      cv::Mat im = cv::imread(image_path, 1);
+      model.predict(&im, &result);
+      std::cout << "Predict label: " << result.category
+                << ", label_id:" << result.category_id
+                << ", score: " << result.score << std::endl;
+    }
+  } else {
+    PaddleX::ClsResult result;
+    cv::Mat im = cv::imread(FLAGS_image, 1);
+    model.predict(&im, &result);
+    std::cout << "Predict label: " << result.category
+              << ", label_id:" << result.category_id
+              << ", score: " << result.score << std::endl;
+  }
+
+  return 0;
+}

+ 143 - 0
deploy/openvino/src/paddlex.cpp

@@ -0,0 +1,143 @@
+//   Copyright (c) 2020 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 "include/paddlex/paddlex.h"
+
+using namespace InferenceEngine;
+
+namespace PaddleX {
+
+void Model::create_predictor(const std::string& model_dir,
+                            const std::string& cfg_dir,
+                            std::string device) {
+    Core ie;
+    network_ = ie.ReadNetwork(model_dir, model_dir.substr(0, model_dir.size() - 4) + ".bin");
+    network_.setBatchSize(1);
+    InputInfo::Ptr input_info = network_.getInputsInfo().begin()->second;
+
+    input_info->getPreProcess().setResizeAlgorithm(RESIZE_BILINEAR);
+    input_info->setLayout(Layout::NCHW);
+    input_info->setPrecision(Precision::FP32);
+    executable_network_ = ie.LoadNetwork(network_, device);
+    load_config(cfg_dir);
+}
+
+template <typename T>
+void matU8ToBlob(const cv::Mat& orig_image, InferenceEngine::Blob::Ptr& blob, int batchIndex = 0) {
+    InferenceEngine::SizeVector blobSize = blob->getTensorDesc().getDims();
+    const size_t width = blobSize[3];
+    const size_t height = blobSize[2];
+    const size_t channels = blobSize[1];
+    InferenceEngine::MemoryBlob::Ptr mblob = InferenceEngine::as<InferenceEngine::MemoryBlob>(blob);
+    if (!mblob) {
+        THROW_IE_EXCEPTION << "We expect blob to be inherited from MemoryBlob in matU8ToBlob, "
+            << "but by fact we were not able to cast inputBlob to MemoryBlob";
+    }
+    // locked memory holder should be alive all time while access to its buffer happens
+    auto mblobHolder = mblob->wmap();
+
+    T *blob_data = mblobHolder.as<T *>();
+
+    cv::Mat resized_image(orig_image);
+    if (static_cast<int>(width) != orig_image.size().width ||
+            static_cast<int>(height) != orig_image.size().height) {
+        cv::resize(orig_image, resized_image, cv::Size(width, height));
+    }
+
+    int batchOffset = batchIndex * width * height * channels;
+
+    for (size_t c = 0; c < channels; c++) {
+        for (size_t  h = 0; h < height; h++) {
+            for (size_t w = 0; w < width; w++) {
+                blob_data[batchOffset + c * width * height + h * width + w] =
+                        resized_image.at<cv::Vec3f>(h, w)[c];
+            }
+        }
+    }
+}
+
+bool Model::load_config(const std::string& cfg_dir) {
+  YAML::Node config = YAML::LoadFile(cfg_dir);
+  type = config["_Attributes"]["model_type"].as<std::string>();
+  name = config["Model"].as<std::string>();
+  bool to_rgb = true;
+  if (config["TransformsMode"].IsDefined()) {
+    std::string mode = config["TransformsMode"].as<std::string>();
+    if (mode == "BGR") {
+      to_rgb = false;
+    } else if (mode != "RGB") {
+      std::cerr << "[Init] Only 'RGB' or 'BGR' is supported for TransformsMode"
+                << std::endl;
+      return false;
+    }
+  }
+  // 构建数据处理流
+  transforms_.Init(config["Transforms"], to_rgb);
+  // 读入label list
+  labels.clear();
+  labels = config["_Attributes"]["labels"].as<std::vector<std::string>>();
+  return true;
+}
+
+bool Model::preprocess(cv::Mat* input_im, ImageBlob* blob) {
+  if (!transforms_.Run(input_im, &inputs_)) {
+    return false;
+  }
+  return true;
+}
+
+bool Model::predict(cv::Mat* im, ClsResult* result) {
+  inputs_.clear();
+  if (type == "detector") {
+    std::cerr << "Loading model is a 'detector', DetResult should be passed to "
+                 "function predict()!"
+              << std::endl;
+    return false;
+  } else if (type == "segmenter") {
+    std::cerr << "Loading model is a 'segmenter', SegResult should be passed "
+                 "to function predict()!"
+              << std::endl;
+    return false;
+  }
+  // 处理输入图像
+  
+  if (!preprocess(im, &inputs_)) {
+    std::cerr << "Preprocess failed!" << std::endl;
+    return false;
+  }
+  InferRequest infer_request = executable_network_.CreateInferRequest();
+  std::string input_name = network_.getInputsInfo().begin()->first;
+  //im->convertTo(*im, CV_8UC3);
+  Blob::Ptr input = infer_request.GetBlob(input_name);
+  matU8ToBlob<float>(*im, input, 0);
+  infer_request.Infer();
+  std::string output_name = network_.getOutputsInfo().begin()->first;
+  Blob::Ptr output = infer_request.GetBlob(output_name);
+  MemoryBlob::CPtr moutput = as<MemoryBlob>(output);
+  auto moutputHolder = moutput->rmap();
+  outputs_ = moutputHolder.as<float *>();
+  
+  std::cout << sizeof(outputs_) << std::endl;
+  // 对模型输出结果进行后处理
+  auto ptr = std::max_element(outputs_, outputs_+sizeof(outputs_));
+  result->category_id = std::distance(outputs_, ptr);
+  result->score = *ptr;
+  result->category = labels[result->category_id];
+  //for (int i=0;i<sizeof(outputs_);i++){
+  //    std::cout <<  labels[i] << std::endl; 
+  //    std::cout <<  outputs_[i] << std::endl;
+  //    }
+}
+
+}  // namespce of PaddleX

+ 222 - 0
deploy/openvino/src/transforms.cpp

@@ -0,0 +1,222 @@
+//   Copyright (c) 2020 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 <iostream>
+#include <string>
+#include <vector>
+
+#include "include/paddlex/transforms.h"
+
+namespace PaddleX {
+
+std::map<std::string, int> interpolations = {{"LINEAR", cv::INTER_LINEAR},
+                                             {"NEAREST", cv::INTER_NEAREST},
+                                             {"AREA", cv::INTER_AREA},
+                                             {"CUBIC", cv::INTER_CUBIC},
+                                             {"LANCZOS4", cv::INTER_LANCZOS4}};
+
+bool Normalize::Run(cv::Mat* im, ImageBlob* data) {
+  for (int h = 0; h < im->rows; h++) {
+    for (int w = 0; w < im->cols; w++) {
+      im->at<cv::Vec3f>(h, w)[0] =
+          (im->at<cv::Vec3f>(h, w)[0] / 255.0 - mean_[0]) / std_[0];
+      im->at<cv::Vec3f>(h, w)[1] =
+          (im->at<cv::Vec3f>(h, w)[1] / 255.0 - mean_[1]) / std_[1];
+      im->at<cv::Vec3f>(h, w)[2] =
+          (im->at<cv::Vec3f>(h, w)[2] / 255.0 - mean_[2]) / std_[2];
+    }
+  }
+  return true;
+}
+
+float ResizeByShort::GenerateScale(const cv::Mat& im) {
+  int origin_w = im.cols;
+  int origin_h = im.rows;
+  int im_size_max = std::max(origin_w, origin_h);
+  int im_size_min = std::min(origin_w, origin_h);
+  float scale =
+      static_cast<float>(short_size_) / static_cast<float>(im_size_min);
+  if (max_size_ > 0) {
+    if (round(scale * im_size_max) > max_size_) {
+      scale = static_cast<float>(max_size_) / static_cast<float>(im_size_max);
+    }
+  }
+  return scale;
+}
+
+bool ResizeByShort::Run(cv::Mat* im, ImageBlob* data) {
+  data->im_size_before_resize_.push_back({im->rows, im->cols});
+  data->reshape_order_.push_back("resize");
+
+  float scale = GenerateScale(*im);
+  int width = static_cast<int>(scale * im->cols);
+  int height = static_cast<int>(scale * im->rows);
+  cv::resize(*im, *im, cv::Size(width, height), 0, 0, cv::INTER_LINEAR);
+
+  data->new_im_size_[0] = im->rows;
+  data->new_im_size_[1] = im->cols;
+  data->scale = scale;
+  return true;
+}
+
+bool CenterCrop::Run(cv::Mat* im, ImageBlob* data) {
+  int height = static_cast<int>(im->rows);
+  int width = static_cast<int>(im->cols);
+  if (height < height_ || width < width_) {
+    std::cerr << "[CenterCrop] Image size less than crop size" << std::endl;
+    return false;
+  }
+  int offset_x = static_cast<int>((width - width_) / 2);
+  int offset_y = static_cast<int>((height - height_) / 2);
+  cv::Rect crop_roi(offset_x, offset_y, width_, height_);
+  *im = (*im)(crop_roi);
+  data->new_im_size_[0] = im->rows;
+  data->new_im_size_[1] = im->cols;
+  return true;
+}
+
+bool Padding::Run(cv::Mat* im, ImageBlob* data) {
+  data->im_size_before_resize_.push_back({im->rows, im->cols});
+  data->reshape_order_.push_back("padding");
+
+  int padding_w = 0;
+  int padding_h = 0;
+  if (width_ > 1 & height_ > 1) {
+    padding_w = width_ - im->cols;
+    padding_h = height_ - im->rows;
+  } else if (coarsest_stride_ > 1) {
+    padding_h =
+        ceil(im->rows * 1.0 / coarsest_stride_) * coarsest_stride_ - im->rows;
+    padding_w =
+        ceil(im->cols * 1.0 / coarsest_stride_) * coarsest_stride_ - im->cols;
+  }
+
+  if (padding_h < 0 || padding_w < 0) {
+    std::cerr << "[Padding] Computed padding_h=" << padding_h
+              << ", padding_w=" << padding_w
+              << ", but they should be greater than 0." << std::endl;
+    return false;
+  }
+  cv::copyMakeBorder(
+      *im, *im, 0, padding_h, 0, padding_w, cv::BORDER_CONSTANT, cv::Scalar(0));
+  data->new_im_size_[0] = im->rows;
+  data->new_im_size_[1] = im->cols;
+  return true;
+}
+
+bool ResizeByLong::Run(cv::Mat* im, ImageBlob* data) {
+  if (long_size_ <= 0) {
+    std::cerr << "[ResizeByLong] long_size should be greater than 0"
+              << std::endl;
+    return false;
+  }
+  data->im_size_before_resize_.push_back({im->rows, im->cols});
+  data->reshape_order_.push_back("resize");
+  int origin_w = im->cols;
+  int origin_h = im->rows;
+
+  int im_size_max = std::max(origin_w, origin_h);
+  float scale =
+      static_cast<float>(long_size_) / static_cast<float>(im_size_max);
+  cv::resize(*im, *im, cv::Size(), scale, scale, cv::INTER_NEAREST);
+  data->new_im_size_[0] = im->rows;
+  data->new_im_size_[1] = im->cols;
+  data->scale = scale;
+  return true;
+}
+
+bool Resize::Run(cv::Mat* im, ImageBlob* data) {
+  if (width_ <= 0 || height_ <= 0) {
+    std::cerr << "[Resize] width and height should be greater than 0"
+              << std::endl;
+    return false;
+  }
+  if (interpolations.count(interp_) <= 0) {
+    std::cerr << "[Resize] Invalid interpolation method: '" << interp_ << "'"
+              << std::endl;
+    return false;
+  }
+  data->im_size_before_resize_.push_back({im->rows, im->cols});
+  data->reshape_order_.push_back("resize");
+
+  cv::resize(
+      *im, *im, cv::Size(width_, height_), 0, 0, interpolations[interp_]);
+  data->new_im_size_[0] = im->rows;
+  data->new_im_size_[1] = im->cols;
+  return true;
+}
+
+void Transforms::Init(const YAML::Node& transforms_node, bool to_rgb) {
+  transforms_.clear();
+  to_rgb_ = to_rgb;
+  for (const auto& item : transforms_node) {
+    std::string name = item.begin()->first.as<std::string>();
+    std::cout << "trans name: " << name << std::endl;
+    std::shared_ptr<Transform> transform = CreateTransform(name);
+    transform->Init(item.begin()->second);
+    transforms_.push_back(transform);
+  }
+}
+
+std::shared_ptr<Transform> Transforms::CreateTransform(
+    const std::string& transform_name) {
+  if (transform_name == "Normalize") {
+    return std::make_shared<Normalize>();
+  } else if (transform_name == "ResizeByShort") {
+    return std::make_shared<ResizeByShort>();
+  } else if (transform_name == "CenterCrop") {
+    return std::make_shared<CenterCrop>();
+  } else if (transform_name == "Resize") {
+    return std::make_shared<Resize>();
+  } else if (transform_name == "Padding") {
+    return std::make_shared<Padding>();
+  } else if (transform_name == "ResizeByLong") {
+    return std::make_shared<ResizeByLong>();
+  } else {
+    std::cerr << "There's unexpected transform(name='" << transform_name
+              << "')." << std::endl;
+    exit(-1);
+  }
+}
+
+bool Transforms::Run(cv::Mat* im, ImageBlob* data) {
+  // 按照transforms中预处理算子顺序处理图像
+  if (to_rgb_) {
+    cv::cvtColor(*im, *im, cv::COLOR_BGR2RGB);
+  }
+  (*im).convertTo(*im, CV_32FC3);
+  data->ori_im_size_[0] = im->rows;
+  data->ori_im_size_[1] = im->cols;
+  data->new_im_size_[0] = im->rows;
+  data->new_im_size_[1] = im->cols;
+  for (int i = 0; i < transforms_.size(); ++i) {
+    if (!transforms_[i]->Run(im, data)) {
+      std::cerr << "Apply transforms to image failed!" << std::endl;
+      return false;
+    }
+  }
+
+  // 将图像由NHWC转为NCHW格式
+  // 同时转为连续的内存块存储到ImageBlob
+  int h = im->rows;
+  int w = im->cols;
+  int c = im->channels();
+  (data->im_data_).resize(c * h * w);
+  float* ptr = (data->im_data_).data();
+  for (int i = 0; i < c; ++i) {
+    cv::extractChannel(*im, cv::Mat(h, w, CV_32FC1, ptr + i * h * w), i);
+  }
+  return true;
+}
+}  // namespace PaddleX

+ 2 - 2
docs/apis/models.md

@@ -182,7 +182,7 @@ paddlex.det.FasterRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspec
 **参数:**
 
 > - **num_classes** (int): 包含了背景类的类别数。默认为81。
-> - **backbone** (str): FasterRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50vd', 'ResNet101', 'ResNet101vd']。默认为'ResNet50'。
+> - **backbone** (str): FasterRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd']。默认为'ResNet50'。
 > - **with_fpn** (bool): 是否使用FPN结构。默认为True。
 > - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
 > - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
@@ -262,7 +262,7 @@ paddlex.det.MaskRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_
 **参数:**
 
 > - **num_classes** (int): 包含了背景类的类别数。默认为81。
-> - **backbone** (str): MaskRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50vd', 'ResNet101', 'ResNet101vd']。默认为'ResNet50'。
+> - **backbone** (str): MaskRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd']。默认为'ResNet50'。
 > - **with_fpn** (bool): 是否使用FPN结构。默认为True。
 > - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
 > - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。

+ 1 - 1
docs/index.rst

@@ -22,7 +22,7 @@ PaddleX是基于飞桨技术生态的深度学习全流程开发工具。具备
    client_use.md
    FAQ.md
 
-* PaddleX版本: v0.1.6
+* PaddleX版本: v0.1.7
 * 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex  
 * 项目GitHub: https://github.com/PaddlePaddle/PaddleX/tree/develop  
 * 官方QQ用户群: 1045148026  

+ 19 - 7
paddlex/__init__.py

@@ -13,27 +13,39 @@
 # limitations under the License.
 
 from __future__ import absolute_import
+import os
+if 'FLAGS_eager_delete_tensor_gb' not in os.environ:
+    os.environ['FLAGS_eager_delete_tensor_gb'] = '0.0'
+if 'FLAGS_allocator_strategy' not in os.environ:
+    os.environ['FLAGS_allocator_strategy'] = 'auto_growth'
+if "CUDA_VISIBLE_DEVICES" in os.environ:
+    if os.environ["CUDA_VISIBLE_DEVICES"].count("-1") > 0:
+        os.environ["CUDA_VISIBLE_DEVICES"] = ""
 from .utils.utils import get_environ_info
 from . import cv
 from . import det
 from . import seg
 from . import cls
 from . import slim
+from . import convertor
 
 try:
     import pycocotools
 except:
-    print("[WARNING] pycocotools is not installed, detection model is not available now.")
-    print("[WARNING] pycocotools install: https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/install.md")
-
-import paddlehub as hub
-if hub.version.hub_version < '1.6.2':
-    raise Exception("[ERROR] paddlehub >= 1.6.2 is required")
+    print(
+        "[WARNING] pycocotools is not installed, detection model is not available now."
+    )
+    print(
+        "[WARNING] pycocotools install: https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/install.md"
+    )
 
+#import paddlehub as hub
+#if hub.version.hub_version < '1.6.2':
+#    raise Exception("[ERROR] paddlehub >= 1.6.2 is required")
 
 env_info = get_environ_info()
 load_model = cv.models.load_model
 datasets = cv.datasets
 
 log_level = 2
-__version__ = '0.1.6.github'
+__version__ = '0.1.7.github'

+ 8 - 9
paddlex/command.py

@@ -69,26 +69,25 @@ def main():
         if args.fixed_input_shape is not None:
             fixed_input_shape = eval(args.fixed_input_shape)
             assert len(
-                fixed_input_shape) == 2, "len of fixed input shape must == 2"
+                fixed_input_shape
+            ) == 2, "len of fixed input shape must == 2, such as [224,224]"
 
         model = pdx.load_model(args.model_dir, fixed_input_shape)
         model.export_inference_model(args.save_dir)
 
     if args.export_onnx:
         assert args.model_dir is not None, "--model_dir should be defined while exporting onnx model"
-        assert args.save_dir is not None, "--save_dir should be defined to save onnx model"
+        assert args.save_dir is not None, "--save_dir should be defined to create onnx model"
+        assert args.fixed_input_shape is not None, "--fixed_input_shape should be defined [w,h] to create onnx model, such as [224,224]"
 
-        fixed_input_shape = None
+        fixed_input_shape = []
         if args.fixed_input_shape is not None:
             fixed_input_shape = eval(args.fixed_input_shape)
             assert len(
-                fixed_input_shape) == 2, "len of fixed input shape must == 2"
-
+                fixed_input_shape
+            ) == 2, "len of fixed input shape must == 2, such as [224,224]"
         model = pdx.load_model(args.model_dir, fixed_input_shape)
-
-        model_name = os.path.basename(args.model_dir.strip('/')).split('/')[-1]
-        onnx_name = model_name + '.onnx'
-        model.export_onnx_model(args.save_dir, onnx_name=onnx_name)
+        pdx.convertor.export_onnx_model(model, args.save_dir)
 
 
 if __name__ == "__main__":

+ 148 - 0
paddlex/convertor.py

@@ -0,0 +1,148 @@
+#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
+#
+#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.
+
+from __future__ import absolute_import
+import paddle.fluid as fluid
+import os
+import sys
+import paddlex as pdx
+
+__all__ = ['export_onnx']
+
+
+def export_onnx(model_dir, save_dir, fixed_input_shape):
+    assert len(fixed_input_shape) == 2, "len of fixed input shape must == 2"
+    model = pdx.load_model(model_dir, fixed_input_shape)
+    model_name = os.path.basename(model_dir.strip('/')).split('/')[-1]
+    export_onnx_model(model, save_dir)
+
+
+def export_onnx_model(model, save_dir):
+    support_list = [
+        'ResNet18', 'ResNet34', 'ResNet50', 'ResNet101', 'ResNet50_vd',
+        'ResNet101_vd', 'ResNet50_vd_ssld', 'ResNet101_vd_ssld', 'DarkNet53',
+        'MobileNetV1', 'MobileNetV2', 'DenseNet121', 'DenseNet161',
+        'DenseNet201'
+    ]
+    if model.__class__.__name__ not in support_list:
+        raise Exception("Model: {} unsupport export to ONNX".format(
+            model.__class__.__name__))
+    try:
+        from fluid.utils import op_io_info, init_name_prefix
+        from onnx import helper, checker
+        import fluid_onnx.ops as ops
+        from fluid_onnx.variables import paddle_variable_to_onnx_tensor, paddle_onnx_weight
+        from debug.model_check import debug_model, Tracker
+    except Exception as e:
+        print(e)
+        print(
+            "Import Module Failed! Please install paddle2onnx. Related requirements \
+             see https://github.com/PaddlePaddle/paddle2onnx.")
+        sys.exit(-1)
+    place = fluid.CPUPlace()
+    exe = fluid.Executor(place)
+    inference_scope = fluid.global_scope()
+    with fluid.scope_guard(inference_scope):
+        test_input_names = [
+            var.name for var in list(model.test_inputs.values())
+        ]
+        inputs_outputs_list = ["fetch", "feed"]
+        weights, weights_value_info = [], []
+        global_block = model.test_prog.global_block()
+        for var_name in global_block.vars:
+            var = global_block.var(var_name)
+            if var_name not in test_input_names\
+                and var.persistable:
+                weight, val_info = paddle_onnx_weight(
+                    var=var, scope=inference_scope)
+                weights.append(weight)
+                weights_value_info.append(val_info)
+
+        # Create inputs
+        inputs = [
+            paddle_variable_to_onnx_tensor(v, global_block)
+            for v in test_input_names
+        ]
+        print("load the model parameter done.")
+        onnx_nodes = []
+        op_check_list = []
+        op_trackers = []
+        nms_first_index = -1
+        nms_outputs = []
+        for block in model.test_prog.blocks:
+            for op in block.ops:
+                if op.type in ops.node_maker:
+                    # TODO: deal with the corner case that vars in
+                    #     different blocks have the same name
+                    node_proto = ops.node_maker[str(op.type)](
+                        operator=op, block=block)
+                    op_outputs = []
+                    last_node = None
+                    if isinstance(node_proto, tuple):
+                        onnx_nodes.extend(list(node_proto))
+                        last_node = list(node_proto)
+                    else:
+                        onnx_nodes.append(node_proto)
+                        last_node = [node_proto]
+                    tracker = Tracker(str(op.type), last_node)
+                    op_trackers.append(tracker)
+                    op_check_list.append(str(op.type))
+                    if op.type == "multiclass_nms" and nms_first_index < 0:
+                        nms_first_index = 0
+                    if nms_first_index >= 0:
+                        _, _, output_op = op_io_info(op)
+                        for output in output_op:
+                            nms_outputs.extend(output_op[output])
+                else:
+                    if op.type not in ['feed', 'fetch']:
+                        op_check_list.append(op.type)
+        print('The operator sets to run test case.')
+        print(set(op_check_list))
+
+        # Create outputs
+        # Get the new names for outputs if they've been renamed in nodes' making
+        renamed_outputs = op_io_info.get_all_renamed_outputs()
+        test_outputs = list(model.test_outputs.values())
+        test_outputs_names = [var.name for var in model.test_outputs.values()]
+        test_outputs_names = [
+            name if name not in renamed_outputs else renamed_outputs[name]
+            for name in test_outputs_names
+        ]
+        outputs = [
+            paddle_variable_to_onnx_tensor(v, global_block)
+            for v in test_outputs_names
+        ]
+
+        # Make graph
+        onnx_name = 'paddlex.onnx'
+        onnx_graph = helper.make_graph(
+            nodes=onnx_nodes,
+            name=onnx_name,
+            initializer=weights,
+            inputs=inputs + weights_value_info,
+            outputs=outputs)
+
+        # Make model
+        onnx_model = helper.make_model(
+            onnx_graph, producer_name='PaddlePaddle')
+
+        # Model check
+        checker.check_model(onnx_model)
+        if onnx_model is not None:
+            onnx_model_file = os.path.join(save_dir, onnx_name)
+            if not os.path.exists(save_dir):
+                os.mkdir(save_dir)
+            with open(onnx_model_file, 'wb') as f:
+                f.write(onnx_model.SerializeToString())
+            print("Saved converted model to path: %s" % onnx_model_file)

+ 8 - 0
paddlex/cv/datasets/dataset.py

@@ -254,3 +254,11 @@ class Dataset:
             buffer_size=self.buffer_size,
             batch_size=batch_size,
             drop_last=drop_last)
+
+    def set_num_samples(self, num_samples):
+        if num_samples > len(self.file_list):
+            logging.warning(
+                "You want set num_samples to {}, but your dataset only has {} samples, so we will keep your dataset num_samples as {}"
+                .format(num_samples, len(self.file_list), len(self.file_list)))
+            num_samples = len(self.file_list)
+        self.num_samples = num_samples

+ 28 - 142
paddlex/cv/models/base.py

@@ -200,18 +200,31 @@ class BaseAPI:
         self.exe.run(startup_prog)
         if pretrain_weights is not None:
             logging.info(
-                "Load pretrain weights from {}.".format(pretrain_weights))
+                "Load pretrain weights from {}.".format(pretrain_weights),
+                use_color=True)
             paddlex.utils.utils.load_pretrain_weights(
                 self.exe, self.train_prog, pretrain_weights, fuse_bn)
         # 进行裁剪
         if sensitivities_file is not None:
+            import paddleslim
             from .slim.prune_config import get_sensitivities
             sensitivities_file = get_sensitivities(sensitivities_file, self,
                                                    save_dir)
             from .slim.prune import get_params_ratios, prune_program
+            logging.info(
+                "Start to prune program with eval_metric_loss = {}".format(
+                    eval_metric_loss),
+                use_color=True)
+            origin_flops = paddleslim.analysis.flops(self.test_prog)
             prune_params_ratios = get_params_ratios(
                 sensitivities_file, eval_metric_loss=eval_metric_loss)
             prune_program(self, prune_params_ratios)
+            current_flops = paddleslim.analysis.flops(self.test_prog)
+            remaining_ratio = current_flops / origin_flops
+            logging.info(
+                "Finish prune program, before FLOPs:{}, after prune FLOPs:{}, remaining ratio:{}"
+                .format(origin_flops, current_flops, remaining_ratio),
+                use_color=True)
             self.status = 'Prune'
 
     def get_model_info(self):
@@ -223,6 +236,9 @@ class BaseAPI:
             del self.init_params['self']
         if '__class__' in self.init_params:
             del self.init_params['__class__']
+        if 'model_name' in self.init_params:
+            del self.init_params['model_name']
+
         info['_init_params'] = self.init_params
 
         info['_Attributes']['num_classes'] = self.num_classes
@@ -256,7 +272,10 @@ class BaseAPI:
             if osp.exists(save_dir):
                 os.remove(save_dir)
             os.makedirs(save_dir)
-        fluid.save(self.train_prog, osp.join(save_dir, 'model'))
+        if self.train_prog is not None:
+            fluid.save(self.train_prog, osp.join(save_dir, 'model'))
+        else:
+            fluid.save(self.test_prog, osp.join(save_dir, 'model'))
         model_info = self.get_model_info()
         model_info['status'] = self.status
         with open(
@@ -328,140 +347,6 @@ class BaseAPI:
         logging.info(
             "Model for inference deploy saved in {}.".format(save_dir))
 
-    def export_onnx_model(self, save_dir, onnx_name=None):
-        support_list = ['ResNet18','ResNet34','ResNet50','ResNet101','ResNet50_vd',
-                        'ResNet101_vd','ResNet50_vd_ssld','ResNet101_vd_ssld','DarkNet53',
-                        'MobileNetV1','MobileNetV2','MobileNetV3_large','MobileNetV3_small',
-                        'MobileNetV3_large_ssld','MobileNetV3_small_ssld','Xception41',
-                        'Xception65','DenseNet121','DenseNet161','DenseNet201','ShuffleNetV2'] 
-        unsupport_list = []
-        if self.model_type in unsupport_list:
-            raise Exception("Model: {} unsupport export to ONNX"
-                            .format(self.model_type)
-        try:
-            from fluid.utils import op_io_info, init_name_prefix
-            from onnx import helper, checker
-            import fluid_onnx.ops as ops
-            from fluid_onnx.variables import paddle_variable_to_onnx_tensor, paddle_onnx_weight
-            from debug.model_check import debug_model, Tracker
-        except Exception as e:
-            print(e)
-            print(
-                "Import Module Failed! Please install paddle2onnx. Related requirements
-                 see https://github.com/PaddlePaddle/paddle2onnx"
-            )
-            sys.exit(-1)
-
-        place = fluid.CPUPlace()
-        exe = fluid.Executor(place)
-        inference_scope = fluid.global_scope()
-        with fluid.scope_guard(inference_scope):
-            test_input_names = [
-                var.name for var in list(self.test_inputs.values())
-            ]
-            inputs_outputs_list = ["fetch", "feed"]
-            weights, weights_value_info = [], []
-            global_block = self.test_prog.global_block()
-            for var_name in global_block.vars:
-                var = global_block.var(var_name)
-                if var_name not in test_input_names\
-                    and var.persistable:
-                    weight, val_info = paddle_onnx_weight(
-                        var=var, scope=inference_scope)
-                    weights.append(weight)
-                    weights_value_info.append(val_info)
-            # Create inputs
-            inputs = [
-                paddle_variable_to_onnx_tensor(v, global_block)
-                for v in test_input_names
-            ]
-            print("load the model parameter done.")
-            onnx_nodes = []
-            op_check_list = []
-            op_trackers = []
-            nms_first_index = -1
-            nms_outputs = []
-            for block in self.test_prog.blocks:
-                for op in block.ops:
-                    if op.type in ops.node_maker:
-                        # TODO(kuke): deal with the corner case that vars in
-                        #     different blocks have the same name
-                        node_proto = ops.node_maker[str(op.type)](
-                            operator=op, block=block)
-                        op_outputs = []
-                        last_node = None
-                        if isinstance(node_proto, tuple):
-                            onnx_nodes.extend(list(node_proto))
-                            last_node = list(node_proto)
-                        else:
-                            onnx_nodes.append(node_proto)
-                            last_node = [node_proto]
-                        tracker = Tracker(str(op.type), last_node)
-                        op_trackers.append(tracker)
-                        op_check_list.append(str(op.type))
-                        if op.type == "multiclass_nms" and nms_first_index < 0:
-                            nms_first_index = 0
-                        if nms_first_index >= 0:
-                            _, _, output_op = op_io_info(op)
-                            for output in output_op:
-                                nms_outputs.extend(output_op[output])
-                    else:
-                        if op.type not in ['feed', 'fetch']:
-                            op_check_list.append(op.type)
-            print('The operator sets to run test case.')
-            print(set(op_check_list))
-
-            # Create outputs
-            # Get the new names for outputs if they've been renamed in nodes' making
-            renamed_outputs = op_io_info.get_all_renamed_outputs()
-            test_outputs = list(self.test_outputs.values())
-            test_outputs_names = [
-                var.name for var in self.test_outputs.values()
-            ]
-            test_outputs_names = [
-                name if name not in renamed_outputs else renamed_outputs[name]
-                for name in test_outputs_names
-            ]
-            outputs = [
-                paddle_variable_to_onnx_tensor(v, global_block)
-                for v in test_outputs_names
-            ]
-            # Make graph
-            onnx_graph = helper.make_graph(
-                nodes=onnx_nodes,
-                name=onnx_name,
-                initializer=weights,
-                inputs=inputs + weights_value_info,
-                outputs=outputs)
-
-            # Make model
-            onnx_model = helper.make_model(
-                onnx_graph, producer_name='PaddlePaddle')
-
-            # Model check
-            checker.check_model(onnx_model)
-
-            # Print model
-            #if to_print_model:
-            #    print("The converted model is:\n{}".format(onnx_model))
-            # Save converted model
-
-            if onnx_model is not None:
-                try:
-                    onnx_model_file = osp.join(save_dir, onnx_name)
-                    if not os.path.exists(save_dir):
-                        os.mkdir(save_dir)
-                    with open(onnx_model_file, 'wb') as f:
-                        f.write(onnx_model.SerializeToString())
-                    print(
-                        "Saved converted model to path: %s" % onnx_model_file)
-                except Exception as e:
-                    print(e)
-                    print(
-                        "Convert Failed! Please use the debug message to find error."
-                    )
-                    sys.exit(-1)
-
     def train_loop(self,
                    num_epochs,
                    train_dataset,
@@ -539,7 +424,7 @@ class BaseAPI:
             earlystop = EarlyStop(early_stop_patience, thresh)
         best_accuracy_key = ""
         best_accuracy = -1.0
-        best_model_epoch = 1
+        best_model_epoch = -1
         for i in range(num_epochs):
             records = list()
             step_start_time = time.time()
@@ -612,7 +497,7 @@ class BaseAPI:
                 current_save_dir = osp.join(save_dir, "epoch_{}".format(i + 1))
                 if not osp.isdir(current_save_dir):
                     os.makedirs(current_save_dir)
-                if eval_dataset is not None:
+                if eval_dataset is not None and eval_dataset.num_samples > 0:
                     self.eval_metrics, self.eval_details = self.evaluate(
                         eval_dataset=eval_dataset,
                         batch_size=eval_batch_size,
@@ -644,10 +529,11 @@ class BaseAPI:
                 self.save_model(save_dir=current_save_dir)
                 time_eval_one_epoch = time.time() - eval_epoch_start_time
                 eval_epoch_start_time = time.time()
-                logging.info(
-                    'Current evaluated best model in eval_dataset is epoch_{}, {}={}'
-                    .format(best_model_epoch, best_accuracy_key,
-                            best_accuracy))
+                if best_model_epoch > 0:
+                    logging.info(
+                        'Current evaluated best model in eval_dataset is epoch_{}, {}={}'
+                        .format(best_model_epoch, best_accuracy_key,
+                                best_accuracy))
                 if eval_dataset is not None and early_stop:
                     if earlystop(current_accuracy):
                         break

+ 3 - 6
paddlex/cv/models/load_model.py

@@ -38,12 +38,9 @@ def load_model(model_dir, fixed_input_shape=None):
     if not hasattr(paddlex.cv.models, info['Model']):
         raise Exception("There's no attribute {} in paddlex.cv.models".format(
             info['Model']))
-
-    if info['_Attributes']['model_type'] == 'classifier':
-        model = paddlex.cv.models.BaseClassifier(**info['_init_params'])
-    else:
-        model = getattr(paddlex.cv.models,
-                        info['Model'])(**info['_init_params'])
+    if 'model_name' in info['_init_params']:
+        del info['_init_params']['model_name']
+    model = getattr(paddlex.cv.models, info['Model'])(**info['_init_params'])
     model.fixed_input_shape = fixed_input_shape
     if status == "Normal" or \
             status == "Prune" or status == "fluid.save":

+ 20 - 16
paddlex/cv/models/slim/prune_config.py

@@ -15,7 +15,7 @@
 import numpy as np
 import os.path as osp
 import paddle.fluid as fluid
-import paddlehub as hub
+#import paddlehub as hub
 import paddlex
 
 sensitivities_data = {
@@ -105,22 +105,26 @@ def get_sensitivities(flag, model, save_dir):
             model_type)
         url = sensitivities_data[model_type]
         fname = osp.split(url)[-1]
-        try:
-            hub.download(fname, save_path=save_dir)
-        except Exception as e:
-            if isinstance(e, hub.ResourceNotFoundError):
-                raise Exception(
-                    "Resource for model {}(key='{}') not found".format(
-                        model_type, fname))
-            elif isinstance(e, hub.ServerConnectionError):
-                raise Exception(
-                    "Cannot get reource for model {}(key='{}'), please check your internet connecgtion"
-                    .format(model_type, fname))
-            else:
-                raise Exception(
-                    "Unexpected error, please make sure paddlehub >= 1.6.2 {}".
-                    format(str(e)))
+        paddlex.utils.download(url, path=save_dir)
         return osp.join(save_dir, fname)
+
+
+#        try:
+#            hub.download(fname, save_path=save_dir)
+#        except Exception as e:
+#            if isinstance(e, hub.ResourceNotFoundError):
+#                raise Exception(
+#                    "Resource for model {}(key='{}') not found".format(
+#                        model_type, fname))
+#            elif isinstance(e, hub.ServerConnectionError):
+#                raise Exception(
+#                    "Cannot get reource for model {}(key='{}'), please check your internet connecgtion"
+#                    .format(model_type, fname))
+#            else:
+#                raise Exception(
+#                    "Unexpected error, please make sure paddlehub >= 1.6.2 {}".
+#                    format(str(e)))
+#        return osp.join(save_dir, fname)
     else:
         raise Exception(
             "sensitivities need to be defined as directory path or `DEFAULT`(download sensitivities automatically)."

+ 44 - 31
paddlex/cv/models/utils/pretrain_weights.py

@@ -1,5 +1,5 @@
 import paddlex
-import paddlehub as hub
+#import paddlehub as hub
 import os
 import os.path as osp
 
@@ -85,40 +85,53 @@ def get_pretrain_weights(flag, model_type, backbone, save_dir):
                 backbone = 'DetResNet50'
         assert backbone in image_pretrain, "There is not ImageNet pretrain weights for {}, you may try COCO.".format(
             backbone)
-        try:
-            hub.download(backbone, save_path=new_save_dir)
-        except Exception as e:
-            if isinstance(e, hub.ResourceNotFoundError):
-                raise Exception(
-                    "Resource for backbone {} not found".format(backbone))
-            elif isinstance(e, hub.ServerConnectionError):
-                raise Exception(
-                    "Cannot get reource for backbone {}, please check your internet connecgtion"
-                    .format(backbone))
-            else:
-                raise Exception(
-                    "Unexpected error, please make sure paddlehub >= 1.6.2")
-        return osp.join(new_save_dir, backbone)
+        url = image_pretrain[backbone]
+        fname = osp.split(url)[-1].split('.')[0]
+        paddlex.utils.download_and_decompress(url, path=new_save_dir)
+        return osp.join(new_save_dir, fname)
+#        try:
+#            hub.download(backbone, save_path=new_save_dir)
+#        except Exception as e:
+#            if isinstance(e, hub.ResourceNotFoundError):
+#                raise Exception(
+#                    "Resource for backbone {} not found".format(backbone))
+#            elif isinstance(e, hub.ServerConnectionError):
+#                raise Exception(
+#                    "Cannot get reource for backbone {}, please check your internet connecgtion"
+#                    .format(backbone))
+#            else:
+#                raise Exception(
+#                    "Unexpected error, please make sure paddlehub >= 1.6.2")
+#        return osp.join(new_save_dir, backbone)
     elif flag == 'COCO':
         new_save_dir = save_dir
         if hasattr(paddlex, 'pretrain_dir'):
             new_save_dir = paddlex.pretrain_dir
-        assert backbone in coco_pretrain, "There is not COCO pretrain weights for {}, you may try ImageNet.".format(
-            backbone)
-        try:
-            hub.download(backbone, save_path=new_save_dir)
-        except Exception as e:
-            if isinstance(hub.ResourceNotFoundError):
-                raise Exception(
-                    "Resource for backbone {} not found".format(backbone))
-            elif isinstance(hub.ServerConnectionError):
-                raise Exception(
-                    "Cannot get reource for backbone {}, please check your internet connecgtion"
-                    .format(backbone))
-            else:
-                raise Exception(
-                    "Unexpected error, please make sure paddlehub >= 1.6.2")
-        return osp.join(new_save_dir, backbone)
+        url = coco_pretrain[backbone]
+        fname = osp.split(url)[-1].split('.')[0]
+        paddlex.utils.download_and_decompress(url, path=new_save_dir)
+        return osp.join(new_save_dir, fname)
+
+
+#        new_save_dir = save_dir
+#        if hasattr(paddlex, 'pretrain_dir'):
+#            new_save_dir = paddlex.pretrain_dir
+#        assert backbone in coco_pretrain, "There is not COCO pretrain weights for {}, you may try ImageNet.".format(
+#            backbone)
+#        try:
+#            hub.download(backbone, save_path=new_save_dir)
+#        except Exception as e:
+#            if isinstance(hub.ResourceNotFoundError):
+#                raise Exception(
+#                    "Resource for backbone {} not found".format(backbone))
+#            elif isinstance(hub.ServerConnectionError):
+#                raise Exception(
+#                    "Cannot get reource for backbone {}, please check your internet connecgtion"
+#                    .format(backbone))
+#            else:
+#                raise Exception(
+#                    "Unexpected error, please make sure paddlehub >= 1.6.2")
+#        return osp.join(new_save_dir, backbone)
     else:
         raise Exception(
             "pretrain_weights need to be defined as directory path or `IMAGENET` or 'COCO' (download pretrain weights automatically)."

+ 0 - 11
paddlex/utils/utils.py

@@ -31,18 +31,7 @@ def seconds_to_hms(seconds):
     return hms_str
 
 
-def setting_environ_flags():
-    if 'FLAGS_eager_delete_tensor_gb' not in os.environ:
-        os.environ['FLAGS_eager_delete_tensor_gb'] = '0.0'
-    if 'FLAGS_allocator_strategy' not in os.environ:
-        os.environ['FLAGS_allocator_strategy'] = 'auto_growth'
-    if "CUDA_VISIBLE_DEVICES" in os.environ:
-        if os.environ["CUDA_VISIBLE_DEVICES"].count("-1") > 0:
-            os.environ["CUDA_VISIBLE_DEVICES"] = ""
-
-
 def get_environ_info():
-    setting_environ_flags()
     import paddle.fluid as fluid
     info = dict()
     info['place'] = 'cpu'

+ 3 - 4
setup.py

@@ -19,7 +19,7 @@ long_description = "PaddleX. A end-to-end deeplearning model development toolkit
 
 setuptools.setup(
     name="paddlex",
-    version='0.1.6',
+    version='0.1.7',
     author="paddlex",
     author_email="paddlex@baidu.com",
     description=long_description,
@@ -29,9 +29,8 @@ setuptools.setup(
     packages=setuptools.find_packages(),
     setup_requires=['cython', 'numpy', 'sklearn'],
     install_requires=[
-        "pycocotools;platform_system!='Windows'", 
-        'pyyaml', 'colorama', 'tqdm', 'visualdl==1.3.0',
-        'paddleslim==1.0.1', 'paddlehub>=1.6.2'
+        "pycocotools;platform_system!='Windows'", 'pyyaml', 'colorama', 'tqdm',
+        'visualdl==1.3.0', 'paddleslim==1.0.1'
     ],
     classifiers=[
         "Programming Language :: Python :: 3",