提交 c3b50efe 编写于 作者: C Channingss

support TensorRT

上级 2385d7ab
...@@ -17,7 +17,7 @@ PaddleX是基于飞桨技术生态的全流程深度学习模型开发工具。 ...@@ -17,7 +17,7 @@ PaddleX是基于飞桨技术生态的全流程深度学习模型开发工具。
- [10分钟快速上手PaddleX模型训练](docs/quick_start.md) - [10分钟快速上手PaddleX模型训练](docs/quick_start.md)
- [PaddleX使用教程](docs/tutorials) - [PaddleX使用教程](docs/tutorials)
- [PaddleX模型库](docs/model_zoo.md) - [PaddleX模型库](docs/model_zoo.md)
- [导出模型部署](docs/deploy.md) - [导出模型部署](docs/deploy/deploy.md)
## 反馈 ## 反馈
......
...@@ -3,9 +3,10 @@ project(PaddleX CXX C) ...@@ -3,9 +3,10 @@ project(PaddleX CXX C)
option(WITH_MKL "Compile demo with MKL/OpenBlas support,defaultuseMKL." ON) option(WITH_MKL "Compile demo with MKL/OpenBlas support,defaultuseMKL." ON)
option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." ON) option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." ON)
option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." ON) option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." OFF)
option(WITH_TENSORRT "Compile demo with TensorRT." OFF) option(WITH_TENSORRT "Compile demo with TensorRT." OFF)
SET(TENSORRT_DIR "" CACHE PATH "Compile demo with TensorRT")
SET(PADDLE_DIR "" CACHE PATH "Location of libraries") SET(PADDLE_DIR "" CACHE PATH "Location of libraries")
SET(OPENCV_DIR "" CACHE PATH "Location of libraries") SET(OPENCV_DIR "" CACHE PATH "Location of libraries")
SET(CUDA_LIB "" CACHE PATH "Location of libraries") SET(CUDA_LIB "" CACHE PATH "Location of libraries")
...@@ -111,8 +112,10 @@ endif() ...@@ -111,8 +112,10 @@ endif()
if (NOT WIN32) if (NOT WIN32)
if (WITH_TENSORRT AND WITH_GPU) if (WITH_TENSORRT AND WITH_GPU)
include_directories("${PADDLE_DIR}/third_party/install/tensorrt/include") include_directories("${TENSORRT_DIR}/include")
link_directories("${PADDLE_DIR}/third_party/install/tensorrt/lib") link_directories("${TENSORRT_DIR}/lib")
#include_directories("${PADDLE_DIR}/third_party/install/tensorrt/include")
#link_directories("${PADDLE_DIR}/third_party/install/tensorrt/lib")
endif() endif()
endif(NOT WIN32) endif(NOT WIN32)
...@@ -194,8 +197,10 @@ endif(NOT WIN32) ...@@ -194,8 +197,10 @@ endif(NOT WIN32)
if(WITH_GPU) if(WITH_GPU)
if(NOT WIN32) if(NOT WIN32)
if (WITH_TENSORRT) if (WITH_TENSORRT)
set(DEPS ${DEPS} ${PADDLE_DIR}/third_party/install/tensorrt/lib/libnvinfer${CMAKE_STATIC_LIBRARY_SUFFIX}) set(DEPS ${DEPS} ${TENSORRT_DIR}/lib/libnvinfer${CMAKE_SHARED_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${PADDLE_DIR}/third_party/install/tensorrt/lib/libnvinfer_plugin${CMAKE_STATIC_LIBRARY_SUFFIX}) set(DEPS ${DEPS} ${TENSORRT_DIR}/lib/libnvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX})
#set(DEPS ${DEPS} ${PADDLE_DIR}/third_party/install/tensorrt/lib/libnvinfer${CMAKE_STATIC_LIBRARY_SUFFIX})
#set(DEPS ${DEPS} ${PADDLE_DIR}/third_party/install/tensorrt/lib/libnvinfer_plugin${CMAKE_STATIC_LIBRARY_SUFFIX})
endif() endif()
set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX}) set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${CUDNN_LIB}/libcudnn${CMAKE_SHARED_LIBRARY_SUFFIX}) set(DEPS ${DEPS} ${CUDNN_LIB}/libcudnn${CMAKE_SHARED_LIBRARY_SUFFIX})
......
...@@ -38,12 +38,14 @@ class Model { ...@@ -38,12 +38,14 @@ class Model {
public: public:
void Init(const std::string& model_dir, void Init(const std::string& model_dir,
bool use_gpu = false, bool use_gpu = false,
bool use_trt = false,
int gpu_id = 0) { int gpu_id = 0) {
create_predictor(model_dir, use_gpu, gpu_id); create_predictor(model_dir, use_gpu, use_trt, gpu_id);
} }
void create_predictor(const std::string& model_dir, void create_predictor(const std::string& model_dir,
bool use_gpu = false, bool use_gpu = false,
bool use_trt = false,
int gpu_id = 0); int gpu_id = 0);
bool load_config(const std::string& model_dir); bool load_config(const std::string& model_dir);
......
...@@ -35,10 +35,8 @@ class ImageBlob { ...@@ -35,10 +35,8 @@ class ImageBlob {
std::vector<int> ori_im_size_ = std::vector<int>(2); std::vector<int> ori_im_size_ = std::vector<int>(2);
// Newest image height and width after process // Newest image height and width after process
std::vector<int> new_im_size_ = std::vector<int>(2); std::vector<int> new_im_size_ = std::vector<int>(2);
// Image height and width before padding
std::vector<int> im_size_before_padding_ = std::vector<int>(2);
// Image height and width before resize // Image height and width before resize
std::vector<int> im_size_before_resize_ = std::vector<int>(2); std::vector<std::vector<int>> im_size_before_resize_;
// Reshape order // Reshape order
std::vector<std::string> reshape_order_; std::vector<std::string> reshape_order_;
// Resize scale // Resize scale
...@@ -49,7 +47,6 @@ class ImageBlob { ...@@ -49,7 +47,6 @@ class ImageBlob {
void clear() { void clear() {
ori_im_size_.clear(); ori_im_size_.clear();
new_im_size_.clear(); new_im_size_.clear();
im_size_before_padding_.clear();
im_size_before_resize_.clear(); im_size_before_resize_.clear();
reshape_order_.clear(); reshape_order_.clear();
im_data_.clear(); im_data_.clear();
...@@ -165,8 +162,8 @@ class Padding : public Transform { ...@@ -165,8 +162,8 @@ class Padding : public Transform {
width_ = item["target_size"].as<int>(); width_ = item["target_size"].as<int>();
height_ = item["target_size"].as<int>(); height_ = item["target_size"].as<int>();
} else if (item["target_size"].IsSequence()) { } else if (item["target_size"].IsSequence()) {
width_ = item["target_size"].as<std::vector<int>>()[0]; width_ = item["target_size"].as<std::vector<int>>()[1];
height_ = item["target_size"].as<std::vector<int>>()[1]; height_ = item["target_size"].as<std::vector<int>>()[0];
} }
} }
if (item["im_padding_value"].IsDefined()) { if (item["im_padding_value"].IsDefined()) {
......
# 是否使用GPU(即是否使用 CUDA) # 是否使用GPU(即是否使用 CUDA)
WITH_GPU=ON WITH_GPU=OFF
# 是否集成 TensorRT(仅WITH_GPU=ON 有效) # 是否集成 TensorRT(仅WITH_GPU=ON 有效)
WITH_TENSORRT=OFF WITH_TENSORRT=OFF
# TensorRT 的lib路径
TENSORRT_DIR=/path/to/TensorRT/
# Paddle 预测库路径 # Paddle 预测库路径
PADDLE_DIR=/path/to/fluid_inference/ PADDLE_DIR=/path/to/fluid_inference/
# CUDA 的 lib 路径 # CUDA 的 lib 路径
...@@ -20,6 +22,7 @@ cd build ...@@ -20,6 +22,7 @@ cd build
cmake .. \ cmake .. \
-DWITH_GPU=${WITH_GPU} \ -DWITH_GPU=${WITH_GPU} \
-DWITH_TENSORRT=${WITH_TENSORRT} \ -DWITH_TENSORRT=${WITH_TENSORRT} \
-DTENSORRT_DIR=${TENSORRT_DIR} \
-DPADDLE_DIR=${PADDLE_DIR} \ -DPADDLE_DIR=${PADDLE_DIR} \
-DCUDA_LIB=${CUDA_LIB} \ -DCUDA_LIB=${CUDA_LIB} \
-DCUDNN_LIB=${CUDNN_LIB} \ -DCUDNN_LIB=${CUDNN_LIB} \
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
DEFINE_string(model_dir, "", "Path of inference model"); DEFINE_string(model_dir, "", "Path of inference model");
DEFINE_bool(use_gpu, false, "Infering with GPU or CPU"); DEFINE_bool(use_gpu, false, "Infering with GPU or CPU");
DEFINE_bool(use_trt, false, "Infering with TensorRT");
DEFINE_int32(gpu_id, 0, "GPU card id"); DEFINE_int32(gpu_id, 0, "GPU card id");
DEFINE_string(image, "", "Path of test image file"); DEFINE_string(image, "", "Path of test image file");
DEFINE_string(image_list, "", "Path of test image list file"); DEFINE_string(image_list, "", "Path of test image list file");
...@@ -42,7 +43,7 @@ int main(int argc, char** argv) { ...@@ -42,7 +43,7 @@ int main(int argc, char** argv) {
// 加载模型 // 加载模型
PaddleX::Model model; PaddleX::Model model;
model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_gpu_id); model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_use_trt, FLAGS_gpu_id);
// 进行预测 // 进行预测
if (FLAGS_image_list != "") { if (FLAGS_image_list != "") {
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
DEFINE_string(model_dir, "", "Path of inference model"); DEFINE_string(model_dir, "", "Path of inference model");
DEFINE_bool(use_gpu, false, "Infering with GPU or CPU"); DEFINE_bool(use_gpu, false, "Infering with GPU or CPU");
DEFINE_bool(use_trt, false, "Infering with TensorRT");
DEFINE_int32(gpu_id, 0, "GPU card id"); DEFINE_int32(gpu_id, 0, "GPU card id");
DEFINE_string(image, "", "Path of test image file"); DEFINE_string(image, "", "Path of test image file");
DEFINE_string(image_list, "", "Path of test image list file"); DEFINE_string(image_list, "", "Path of test image list file");
...@@ -44,7 +45,7 @@ int main(int argc, char** argv) { ...@@ -44,7 +45,7 @@ int main(int argc, char** argv) {
// 加载模型 // 加载模型
PaddleX::Model model; PaddleX::Model model;
model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_gpu_id); model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_use_trt, FLAGS_gpu_id);
auto colormap = PaddleX::GenerateColorMap(model.labels.size()); auto colormap = PaddleX::GenerateColorMap(model.labels.size());
std::string save_dir = "output"; std::string save_dir = "output";
......
...@@ -18,6 +18,7 @@ namespace PaddleX { ...@@ -18,6 +18,7 @@ namespace PaddleX {
void Model::create_predictor(const std::string& model_dir, void Model::create_predictor(const std::string& model_dir,
bool use_gpu, bool use_gpu,
bool use_trt,
int gpu_id) { int gpu_id) {
// 读取配置文件 // 读取配置文件
if (!load_config(model_dir)) { if (!load_config(model_dir)) {
...@@ -37,6 +38,14 @@ void Model::create_predictor(const std::string& model_dir, ...@@ -37,6 +38,14 @@ void Model::create_predictor(const std::string& model_dir,
config.SwitchSpecifyInputNames(true); config.SwitchSpecifyInputNames(true);
// 开启内存优化 // 开启内存优化
config.EnableMemoryOptim(); config.EnableMemoryOptim();
if (use_trt){
config.EnableTensorRtEngine(1 << 20 /* workspace_size*/,
32 /* max_batch_size*/,
20 /* min_subgraph_size*/,
paddle::AnalysisConfig::Precision::kFloat32 /* precision*/,
false /* use_static*/,
false /* use_calib_mode*/);
}
predictor_ = std::move(CreatePaddlePredictor(config)); predictor_ = std::move(CreatePaddlePredictor(config));
} }
...@@ -286,19 +295,23 @@ bool Model::predict(const cv::Mat& im, SegResult* result) { ...@@ -286,19 +295,23 @@ bool Model::predict(const cv::Mat& im, SegResult* result) {
result->score_map.shape[3], result->score_map.shape[3],
CV_32FC1, CV_32FC1,
result->score_map.data.data()); result->score_map.data.data());
int idx=1;
int len_postprocess = inputs_.im_size_before_resize_.size();
for (std::vector<std::string>::reverse_iterator iter = for (std::vector<std::string>::reverse_iterator iter =
inputs_.reshape_order_.rbegin(); inputs_.reshape_order_.rbegin();
iter != inputs_.reshape_order_.rend(); iter != inputs_.reshape_order_.rend(); ++iter) {
++iter) {
if (*iter == "padding") { if (*iter == "padding") {
auto padding_w = inputs_.im_size_before_padding_[0]; auto before_shape = inputs_.im_size_before_resize_[len_postprocess-idx];
auto padding_h = inputs_.im_size_before_padding_[1]; inputs_.im_size_before_resize_.pop_back();
auto padding_w = before_shape[0];
auto padding_h = before_shape[1];
mask_label = mask_label(cv::Rect(0, 0, padding_w, padding_h)); mask_label = mask_label(cv::Rect(0, 0, padding_w, padding_h));
mask_score = mask_score(cv::Rect(0, 0, padding_w, padding_h)); mask_score = mask_score(cv::Rect(0, 0, padding_w, padding_h));
} else if (*iter == "resize") { } else if (*iter == "resize") {
auto resize_w = inputs_.im_size_before_resize_[0]; auto before_shape = inputs_.im_size_before_resize_[len_postprocess-idx];
auto resize_h = inputs_.im_size_before_resize_[1]; inputs_.im_size_before_resize_.pop_back();
auto resize_w = before_shape[0];
auto resize_h = before_shape[1];
cv::resize(mask_label, cv::resize(mask_label,
mask_label, mask_label,
cv::Size(resize_h, resize_w), cv::Size(resize_h, resize_w),
...@@ -312,6 +325,7 @@ bool Model::predict(const cv::Mat& im, SegResult* result) { ...@@ -312,6 +325,7 @@ bool Model::predict(const cv::Mat& im, SegResult* result) {
0, 0,
cv::INTER_NEAREST); cv::INTER_NEAREST);
} }
++idx;
} }
result->label_map.data.assign(mask_label.begin<uint8_t>(), result->label_map.data.assign(mask_label.begin<uint8_t>(),
mask_label.end<uint8_t>()); mask_label.end<uint8_t>());
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
DEFINE_string(model_dir, "", "Path of inference model"); DEFINE_string(model_dir, "", "Path of inference model");
DEFINE_bool(use_gpu, false, "Infering with GPU or CPU"); DEFINE_bool(use_gpu, false, "Infering with GPU or CPU");
DEFINE_bool(use_trt, false, "Infering with TensorRT");
DEFINE_int32(gpu_id, 0, "GPU card id"); DEFINE_int32(gpu_id, 0, "GPU card id");
DEFINE_string(image, "", "Path of test image file"); DEFINE_string(image, "", "Path of test image file");
DEFINE_string(image_list, "", "Path of test image list file"); DEFINE_string(image_list, "", "Path of test image list file");
...@@ -44,7 +45,8 @@ int main(int argc, char** argv) { ...@@ -44,7 +45,8 @@ int main(int argc, char** argv) {
// 加载模型 // 加载模型
PaddleX::Model model; PaddleX::Model model;
model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_gpu_id); model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_use_trt, FLAGS_gpu_id);
auto colormap = PaddleX::GenerateColorMap(model.labels.size()); auto colormap = PaddleX::GenerateColorMap(model.labels.size());
// 进行预测 // 进行预测
if (FLAGS_image_list != "") { if (FLAGS_image_list != "") {
......
...@@ -56,8 +56,7 @@ float ResizeByShort::GenerateScale(const cv::Mat& im) { ...@@ -56,8 +56,7 @@ float ResizeByShort::GenerateScale(const cv::Mat& im) {
} }
bool ResizeByShort::Run(cv::Mat* im, ImageBlob* data) { bool ResizeByShort::Run(cv::Mat* im, ImageBlob* data) {
data->im_size_before_resize_[0] = im->rows; data->im_size_before_resize_.push_back({im->rows,im->cols});
data->im_size_before_resize_[1] = im->cols;
data->reshape_order_.push_back("resize"); data->reshape_order_.push_back("resize");
float scale = GenerateScale(*im); float scale = GenerateScale(*im);
...@@ -88,8 +87,7 @@ bool CenterCrop::Run(cv::Mat* im, ImageBlob* data) { ...@@ -88,8 +87,7 @@ bool CenterCrop::Run(cv::Mat* im, ImageBlob* data) {
} }
bool Padding::Run(cv::Mat* im, ImageBlob* data) { bool Padding::Run(cv::Mat* im, ImageBlob* data) {
data->im_size_before_padding_[0] = im->rows; data->im_size_before_resize_.push_back({im->rows,im->cols});
data->im_size_before_padding_[1] = im->cols;
data->reshape_order_.push_back("padding"); data->reshape_order_.push_back("padding");
int padding_w = 0; int padding_w = 0;
...@@ -122,8 +120,7 @@ bool ResizeByLong::Run(cv::Mat* im, ImageBlob* data) { ...@@ -122,8 +120,7 @@ bool ResizeByLong::Run(cv::Mat* im, ImageBlob* data) {
<< std::endl; << std::endl;
return false; return false;
} }
data->im_size_before_resize_[0] = im->rows; data->im_size_before_resize_.push_back({im->rows,im->cols});
data->im_size_before_resize_[1] = im->cols;
data->reshape_order_.push_back("resize"); data->reshape_order_.push_back("resize");
int origin_w = im->cols; int origin_w = im->cols;
int origin_h = im->rows; int origin_h = im->rows;
...@@ -149,8 +146,7 @@ bool Resize::Run(cv::Mat* im, ImageBlob* data) { ...@@ -149,8 +146,7 @@ bool Resize::Run(cv::Mat* im, ImageBlob* data) {
<< std::endl; << std::endl;
return false; return false;
} }
data->im_size_before_resize_[0] = im->rows; data->im_size_before_resize_.push_back({im->rows,im->cols});
data->im_size_before_resize_[1] = im->cols;
data->reshape_order_.push_back("resize"); data->reshape_order_.push_back("resize");
cv::resize( cv::resize(
......
...@@ -29,7 +29,11 @@ def arg_parser(): ...@@ -29,7 +29,11 @@ def arg_parser():
action="store_true", action="store_true",
default=False, default=False,
help="export inference model for C++/Python deployment") help="export inference model for C++/Python deployment")
parser.add_argument(
"--fixed_input_shape",
"-fs",
default=None,
help="export inference model with fixed input shape(TensorRT need)")
return parser return parser
...@@ -53,8 +57,11 @@ def main(): ...@@ -53,8 +57,11 @@ def main():
if args.export_inference: if args.export_inference:
assert args.model_dir is not None, "--model_dir should be defined while exporting inference model" assert args.model_dir is not None, "--model_dir should be defined while exporting inference model"
assert args.save_dir is not None, "--save_dir should be defined to save inference model" assert args.save_dir is not None, "--save_dir should be defined to save inference model"
model = pdx.load_model(args.model_dir) fixed_input_shape = eval(args.fixed_input_shape)
model.export_inference_model(args.save_dir) assert len(fixed_input_shape) == 2, "len of fixed input shape must == 2"
model = pdx.load_model(args.model_dir, fixed_input_shape)
model.export_inference_model(args.save_dir, fixed_input_shape)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -283,7 +283,7 @@ class BaseAPI: ...@@ -283,7 +283,7 @@ class BaseAPI:
open(osp.join(save_dir, '.success'), 'w').close() open(osp.join(save_dir, '.success'), 'w').close()
logging.info("Model saved in {}.".format(save_dir)) logging.info("Model saved in {}.".format(save_dir))
def export_inference_model(self, save_dir): def export_inference_model(self, save_dir, fixed_input_shape=None):
test_input_names = [ test_input_names = [
var.name for var in list(self.test_inputs.values()) var.name for var in list(self.test_inputs.values())
] ]
...@@ -316,11 +316,30 @@ class BaseAPI: ...@@ -316,11 +316,30 @@ class BaseAPI:
model_info['_ModelInputsOutputs']['test_outputs'] = [ model_info['_ModelInputsOutputs']['test_outputs'] = [
[k, v.name] for k, v in self.test_outputs.items() [k, v.name] for k, v in self.test_outputs.items()
] ]
resize = {'ResizeByShort': {}}
padding = {'Padding':{}}
if model_info['_Attributes']['model_type'] == 'classifier':
crop_size = 0
for transform in model_info['Transforms']:
if 'CenterCrop' in transform:
crop_size = transform['CenterCrop']['crop_size']
break
assert crop_size == fixed_input_shape[0], "fixed_input_shape must == CenterCrop:crop_size:{}".format(crop_size)
assert crop_size == fixed_input_shape[1], "fixed_input_shape must == CenterCrop:crop_size:{}".format(crop_size)
if crop_size == 0:
logging.warning("fixed_input_shape must == input shape when trainning")
else:
resize['ResizeByShort']['short_size'] = min(fixed_input_shape)
resize['ResizeByShort']['max_size'] = max(fixed_input_shape)
padding['Padding']['target_size'] = list(fixed_input_shape)
model_info['Transforms'].append(resize)
model_info['Transforms'].append(padding)
with open( with open(
osp.join(save_dir, 'model.yml'), encoding='utf-8', osp.join(save_dir, 'model.yml'), encoding='utf-8',
mode='w') as f: mode='w') as f:
yaml.dump(model_info, f) yaml.dump(model_info, f)
# 模型保存成功的标志 # 模型保存成功的标志
open(osp.join(save_dir, '.success'), 'w').close() open(osp.join(save_dir, '.success'), 'w').close()
logging.info( logging.info(
......
...@@ -35,9 +35,10 @@ class BaseClassifier(BaseAPI): ...@@ -35,9 +35,10 @@ class BaseClassifier(BaseAPI):
'MobileNetV1', 'MobileNetV2', 'Xception41', 'MobileNetV1', 'MobileNetV2', 'Xception41',
'Xception65', 'Xception71']。默认为'ResNet50'。 'Xception65', 'Xception71']。默认为'ResNet50'。
num_classes (int): 类别数。默认为1000。 num_classes (int): 类别数。默认为1000。
fixed_input_shape (list): 长度为2,维度为1的list,如:[640,720],用来固定模型输入:'image'的shape,默认为None。
""" """
def __init__(self, model_name='ResNet50', num_classes=1000): def __init__(self, model_name='ResNet50', num_classes=1000, fixed_input_shape=None):
self.init_params = locals() self.init_params = locals()
super(BaseClassifier, self).__init__('classifier') super(BaseClassifier, self).__init__('classifier')
if not hasattr(paddlex.cv.nets, str.lower(model_name)): if not hasattr(paddlex.cv.nets, str.lower(model_name)):
...@@ -46,10 +47,16 @@ class BaseClassifier(BaseAPI): ...@@ -46,10 +47,16 @@ class BaseClassifier(BaseAPI):
self.model_name = model_name self.model_name = model_name
self.labels = None self.labels = None
self.num_classes = num_classes self.num_classes = num_classes
self.fixed_input_shape = fixed_input_shape
def build_net(self, mode='train'): def build_net(self, mode='train'):
image = fluid.data( if self.fixed_input_shape is not None:
dtype='float32', shape=[None, 3, None, None], name='image') input_shape =[None, 3, self.fixed_input_shape[0], self.fixed_input_shape[1]]
image = fluid.data(
dtype='float32', shape=input_shape, name='image')
else:
image = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image')
if mode != 'test': if mode != 'test':
label = fluid.data(dtype='int64', shape=[None, 1], name='label') label = fluid.data(dtype='int64', shape=[None, 1], name='label')
model = getattr(paddlex.cv.nets, str.lower(self.model_name)) model = getattr(paddlex.cv.nets, str.lower(self.model_name))
......
...@@ -48,7 +48,7 @@ class DeepLabv3p(BaseAPI): ...@@ -48,7 +48,7 @@ class DeepLabv3p(BaseAPI):
自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None时,各类的权重1, 自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None时,各类的权重1,
即平时使用的交叉熵损失函数。 即平时使用的交叉熵损失函数。
ignore_index (int): label上忽略的值,label为ignore_index的像素不参与损失函数的计算。默认255。 ignore_index (int): label上忽略的值,label为ignore_index的像素不参与损失函数的计算。默认255。
fixed_input_shape (list): 长度为2,维度为1的list,如:[640,720],用来固定模型输入:'image'的shape,默认为None。
Raises: Raises:
ValueError: use_bce_loss或use_dice_loss为真且num_calsses > 2。 ValueError: use_bce_loss或use_dice_loss为真且num_calsses > 2。
ValueError: backbone取值不在['Xception65', 'Xception41', 'MobileNetV2_x0.25', ValueError: backbone取值不在['Xception65', 'Xception41', 'MobileNetV2_x0.25',
...@@ -69,7 +69,8 @@ class DeepLabv3p(BaseAPI): ...@@ -69,7 +69,8 @@ class DeepLabv3p(BaseAPI):
use_bce_loss=False, use_bce_loss=False,
use_dice_loss=False, use_dice_loss=False,
class_weight=None, class_weight=None,
ignore_index=255): ignore_index=255,
fixed_input_shape=None):
self.init_params = locals() self.init_params = locals()
super(DeepLabv3p, self).__init__('segmenter') super(DeepLabv3p, self).__init__('segmenter')
# dice_loss或bce_loss只适用两类分割中 # dice_loss或bce_loss只适用两类分割中
...@@ -118,6 +119,7 @@ class DeepLabv3p(BaseAPI): ...@@ -118,6 +119,7 @@ class DeepLabv3p(BaseAPI):
self.enable_decoder = enable_decoder self.enable_decoder = enable_decoder
self.labels = None self.labels = None
self.sync_bn = True self.sync_bn = True
self.fixed_input_shape = fixed_input_shape
def _get_backbone(self, backbone): def _get_backbone(self, backbone):
def mobilenetv2(backbone): def mobilenetv2(backbone):
...@@ -182,7 +184,8 @@ class DeepLabv3p(BaseAPI): ...@@ -182,7 +184,8 @@ class DeepLabv3p(BaseAPI):
use_bce_loss=self.use_bce_loss, use_bce_loss=self.use_bce_loss,
use_dice_loss=self.use_dice_loss, use_dice_loss=self.use_dice_loss,
class_weight=self.class_weight, class_weight=self.class_weight,
ignore_index=self.ignore_index) ignore_index=self.ignore_index,
fixed_input_shape = self.fixed_input_shape)
inputs = model.generate_inputs() inputs = model.generate_inputs()
model_out = model.build_net(inputs) model_out = model.build_net(inputs)
outputs = OrderedDict() outputs = OrderedDict()
......
...@@ -36,6 +36,7 @@ class FasterRCNN(BaseAPI): ...@@ -36,6 +36,7 @@ class FasterRCNN(BaseAPI):
with_fpn (bool): 是否使用FPN结构。默认为True。 with_fpn (bool): 是否使用FPN结构。默认为True。
aspect_ratios (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。 aspect_ratios (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
anchor_sizes (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。 anchor_sizes (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
fixed_input_shape (list): 长度为2,维度为1的list,如:[640,720],用来固定模型输入:'image'的shape,默认为None。
""" """
def __init__(self, def __init__(self,
...@@ -43,7 +44,8 @@ class FasterRCNN(BaseAPI): ...@@ -43,7 +44,8 @@ class FasterRCNN(BaseAPI):
backbone='ResNet50', backbone='ResNet50',
with_fpn=True, with_fpn=True,
aspect_ratios=[0.5, 1.0, 2.0], aspect_ratios=[0.5, 1.0, 2.0],
anchor_sizes=[32, 64, 128, 256, 512]): anchor_sizes=[32, 64, 128, 256, 512],
fixed_input_shape=None):
self.init_params = locals() self.init_params = locals()
super(FasterRCNN, self).__init__('detector') super(FasterRCNN, self).__init__('detector')
backbones = [ backbones = [
...@@ -57,6 +59,7 @@ class FasterRCNN(BaseAPI): ...@@ -57,6 +59,7 @@ class FasterRCNN(BaseAPI):
self.aspect_ratios = aspect_ratios self.aspect_ratios = aspect_ratios
self.anchor_sizes = anchor_sizes self.anchor_sizes = anchor_sizes
self.labels = None self.labels = None
self.fixed_input_shape = fixed_input_shape
def _get_backbone(self, backbone_name): def _get_backbone(self, backbone_name):
norm_type = None norm_type = None
...@@ -109,7 +112,8 @@ class FasterRCNN(BaseAPI): ...@@ -109,7 +112,8 @@ class FasterRCNN(BaseAPI):
aspect_ratios=self.aspect_ratios, aspect_ratios=self.aspect_ratios,
anchor_sizes=self.anchor_sizes, anchor_sizes=self.anchor_sizes,
train_pre_nms_top_n=train_pre_nms_top_n, train_pre_nms_top_n=train_pre_nms_top_n,
test_pre_nms_top_n=test_pre_nms_top_n) test_pre_nms_top_n=test_pre_nms_top_n,
fixed_input_shape = self.fixed_input_shape)
inputs = model.generate_inputs() inputs = model.generate_inputs()
if mode == 'train': if mode == 'train':
model_out = model.build_net(inputs) model_out = model.build_net(inputs)
......
...@@ -23,7 +23,7 @@ import paddlex ...@@ -23,7 +23,7 @@ import paddlex
import paddlex.utils.logging as logging import paddlex.utils.logging as logging
def load_model(model_dir): def load_model(model_dir, fixed_input_shape=None):
if not osp.exists(osp.join(model_dir, "model.yml")): if not osp.exists(osp.join(model_dir, "model.yml")):
raise Exception("There's not model.yml in {}".format(model_dir)) raise Exception("There's not model.yml in {}".format(model_dir))
with open(osp.join(model_dir, "model.yml")) as f: with open(osp.join(model_dir, "model.yml")) as f:
...@@ -39,6 +39,8 @@ def load_model(model_dir): ...@@ -39,6 +39,8 @@ def load_model(model_dir):
raise Exception("There's no attribute {} in paddlex.cv.models".format( raise Exception("There's no attribute {} in paddlex.cv.models".format(
info['Model'])) info['Model']))
info['_init_params']['fixed_input_shape'] = fixed_input_shape
if info['_Attributes']['model_type'] == 'classifier': if info['_Attributes']['model_type'] == 'classifier':
model = paddlex.cv.models.BaseClassifier(**info['_init_params']) model = paddlex.cv.models.BaseClassifier(**info['_init_params'])
else: else:
......
...@@ -36,6 +36,7 @@ class MaskRCNN(FasterRCNN): ...@@ -36,6 +36,7 @@ class MaskRCNN(FasterRCNN):
with_fpn (bool): 是否使用FPN结构。默认为True。 with_fpn (bool): 是否使用FPN结构。默认为True。
aspect_ratios (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。 aspect_ratios (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
anchor_sizes (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。 anchor_sizes (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
fixed_input_shape (list): 长度为2,维度为1的list,如:[640,720],用来固定模型输入:'image'的shape,默认为None。
""" """
def __init__(self, def __init__(self,
...@@ -43,7 +44,8 @@ class MaskRCNN(FasterRCNN): ...@@ -43,7 +44,8 @@ class MaskRCNN(FasterRCNN):
backbone='ResNet50', backbone='ResNet50',
with_fpn=True, with_fpn=True,
aspect_ratios=[0.5, 1.0, 2.0], aspect_ratios=[0.5, 1.0, 2.0],
anchor_sizes=[32, 64, 128, 256, 512]): anchor_sizes=[32, 64, 128, 256, 512],
fixed_input_shape=None):
self.init_params = locals() self.init_params = locals()
backbones = [ backbones = [
'ResNet18', 'ResNet50', 'ResNet50vd', 'ResNet101', 'ResNet101vd' 'ResNet18', 'ResNet50', 'ResNet50vd', 'ResNet101', 'ResNet101vd'
...@@ -60,6 +62,7 @@ class MaskRCNN(FasterRCNN): ...@@ -60,6 +62,7 @@ class MaskRCNN(FasterRCNN):
self.mask_head_resolution = 28 self.mask_head_resolution = 28
else: else:
self.mask_head_resolution = 14 self.mask_head_resolution = 14
self.fixed_input_shape = fixed_input_shape
def build_net(self, mode='train'): def build_net(self, mode='train'):
train_pre_nms_top_n = 2000 if self.with_fpn else 12000 train_pre_nms_top_n = 2000 if self.with_fpn else 12000
...@@ -73,7 +76,8 @@ class MaskRCNN(FasterRCNN): ...@@ -73,7 +76,8 @@ class MaskRCNN(FasterRCNN):
train_pre_nms_top_n=train_pre_nms_top_n, train_pre_nms_top_n=train_pre_nms_top_n,
test_pre_nms_top_n=test_pre_nms_top_n, test_pre_nms_top_n=test_pre_nms_top_n,
num_convs=num_convs, num_convs=num_convs,
mask_head_resolution=self.mask_head_resolution) mask_head_resolution=self.mask_head_resolution,
fixed_input_shape = self.fixed_input_shape)
inputs = model.generate_inputs() inputs = model.generate_inputs()
if mode == 'train': if mode == 'train':
model_out = model.build_net(inputs) model_out = model.build_net(inputs)
......
...@@ -33,6 +33,7 @@ class UNet(DeepLabv3p): ...@@ -33,6 +33,7 @@ class UNet(DeepLabv3p):
自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1, 自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,
即平时使用的交叉熵损失函数。 即平时使用的交叉熵损失函数。
ignore_index (int): label上忽略的值,label为ignore_index的像素不参与损失函数的计算。默认255。 ignore_index (int): label上忽略的值,label为ignore_index的像素不参与损失函数的计算。默认255。
fixed_input_shape (list): 长度为2,维度为1的list,如:[640,720],用来固定模型输入:'image'的shape,默认为None。
Raises: Raises:
ValueError: use_bce_loss或use_dice_loss为真且num_calsses > 2。 ValueError: use_bce_loss或use_dice_loss为真且num_calsses > 2。
...@@ -47,7 +48,8 @@ class UNet(DeepLabv3p): ...@@ -47,7 +48,8 @@ class UNet(DeepLabv3p):
use_bce_loss=False, use_bce_loss=False,
use_dice_loss=False, use_dice_loss=False,
class_weight=None, class_weight=None,
ignore_index=255): ignore_index=255,
fixed_input_shape=None):
self.init_params = locals() self.init_params = locals()
super(DeepLabv3p, self).__init__('segmenter') super(DeepLabv3p, self).__init__('segmenter')
# dice_loss或bce_loss只适用两类分割中 # dice_loss或bce_loss只适用两类分割中
...@@ -77,6 +79,7 @@ class UNet(DeepLabv3p): ...@@ -77,6 +79,7 @@ class UNet(DeepLabv3p):
self.class_weight = class_weight self.class_weight = class_weight
self.ignore_index = ignore_index self.ignore_index = ignore_index
self.labels = None self.labels = None
self.fixed_input_shape = fixed_input_shape
def build_net(self, mode='train'): def build_net(self, mode='train'):
model = paddlex.cv.nets.segmentation.UNet( model = paddlex.cv.nets.segmentation.UNet(
...@@ -86,7 +89,8 @@ class UNet(DeepLabv3p): ...@@ -86,7 +89,8 @@ class UNet(DeepLabv3p):
use_bce_loss=self.use_bce_loss, use_bce_loss=self.use_bce_loss,
use_dice_loss=self.use_dice_loss, use_dice_loss=self.use_dice_loss,
class_weight=self.class_weight, class_weight=self.class_weight,
ignore_index=self.ignore_index) ignore_index=self.ignore_index,
fixed_input_shape = self.fixed_input_shape)
inputs = model.generate_inputs() inputs = model.generate_inputs()
model_out = model.build_net(inputs) model_out = model.build_net(inputs)
outputs = OrderedDict() outputs = OrderedDict()
......
...@@ -60,7 +60,8 @@ class YOLOv3(BaseAPI): ...@@ -60,7 +60,8 @@ class YOLOv3(BaseAPI):
label_smooth=False, label_smooth=False,
train_random_shapes=[ train_random_shapes=[
320, 352, 384, 416, 448, 480, 512, 544, 576, 608 320, 352, 384, 416, 448, 480, 512, 544, 576, 608
]): ],
fixed_input_shape=None):
self.init_params = locals() self.init_params = locals()
super(YOLOv3, self).__init__('detector') super(YOLOv3, self).__init__('detector')
backbones = [ backbones = [
...@@ -80,6 +81,7 @@ class YOLOv3(BaseAPI): ...@@ -80,6 +81,7 @@ class YOLOv3(BaseAPI):
self.label_smooth = label_smooth self.label_smooth = label_smooth
self.sync_bn = True self.sync_bn = True
self.train_random_shapes = train_random_shapes self.train_random_shapes = train_random_shapes
self.fixed_input_shape = fixed_input_shape
def _get_backbone(self, backbone_name): def _get_backbone(self, backbone_name):
if backbone_name == 'DarkNet53': if backbone_name == 'DarkNet53':
...@@ -113,7 +115,8 @@ class YOLOv3(BaseAPI): ...@@ -113,7 +115,8 @@ class YOLOv3(BaseAPI):
nms_topk=self.nms_topk, nms_topk=self.nms_topk,
nms_keep_topk=self.nms_keep_topk, nms_keep_topk=self.nms_keep_topk,
nms_iou_threshold=self.nms_iou_threshold, nms_iou_threshold=self.nms_iou_threshold,
train_random_shapes=self.train_random_shapes) train_random_shapes=self.train_random_shapes,
fixed_input_shape = self.fixed_input_shape)
inputs = model.generate_inputs() inputs = model.generate_inputs()
model_out = model.build_net(inputs) model_out = model.build_net(inputs)
outputs = OrderedDict([('bbox', model_out)]) outputs = OrderedDict([('bbox', model_out)])
......
...@@ -76,7 +76,8 @@ class FasterRCNN(object): ...@@ -76,7 +76,8 @@ class FasterRCNN(object):
fg_thresh=.5, fg_thresh=.5,
bg_thresh_hi=.5, bg_thresh_hi=.5,
bg_thresh_lo=0., bg_thresh_lo=0.,
bbox_reg_weights=[0.1, 0.1, 0.2, 0.2]): bbox_reg_weights=[0.1, 0.1, 0.2, 0.2],
fixed_input_shape=None):
super(FasterRCNN, self).__init__() super(FasterRCNN, self).__init__()
self.backbone = backbone self.backbone = backbone
self.mode = mode self.mode = mode
...@@ -148,6 +149,7 @@ class FasterRCNN(object): ...@@ -148,6 +149,7 @@ class FasterRCNN(object):
self.bg_thresh_lo = bg_thresh_lo self.bg_thresh_lo = bg_thresh_lo
self.bbox_reg_weights = bbox_reg_weights self.bbox_reg_weights = bbox_reg_weights
self.rpn_only = rpn_only self.rpn_only = rpn_only
self.fixed_input_shape = fixed_input_shape
def build_net(self, inputs): def build_net(self, inputs):
im = inputs['image'] im = inputs['image']
...@@ -219,8 +221,14 @@ class FasterRCNN(object): ...@@ -219,8 +221,14 @@ class FasterRCNN(object):
def generate_inputs(self): def generate_inputs(self):
inputs = OrderedDict() inputs = OrderedDict()
inputs['image'] = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image') if self.fixed_input_shape is not None:
input_shape =[None, 3, self.fixed_input_shape[0], self.fixed_input_shape[1]]
inputs['image'] = fluid.data(
dtype='float32', shape=input_shape, name='image')
else:
inputs['image'] = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image')
if self.mode == 'train': if self.mode == 'train':
inputs['im_info'] = fluid.data( inputs['im_info'] = fluid.data(
dtype='float32', shape=[None, 3], name='im_info') dtype='float32', shape=[None, 3], name='im_info')
......
...@@ -86,7 +86,8 @@ class MaskRCNN(object): ...@@ -86,7 +86,8 @@ class MaskRCNN(object):
fg_thresh=.5, fg_thresh=.5,
bg_thresh_hi=.5, bg_thresh_hi=.5,
bg_thresh_lo=0., bg_thresh_lo=0.,
bbox_reg_weights=[0.1, 0.1, 0.2, 0.2]): bbox_reg_weights=[0.1, 0.1, 0.2, 0.2],
fixed_input_shape=None):
super(MaskRCNN, self).__init__() super(MaskRCNN, self).__init__()
self.backbone = backbone self.backbone = backbone
self.mode = mode self.mode = mode
...@@ -167,6 +168,7 @@ class MaskRCNN(object): ...@@ -167,6 +168,7 @@ class MaskRCNN(object):
self.bg_thresh_lo = bg_thresh_lo self.bg_thresh_lo = bg_thresh_lo
self.bbox_reg_weights = bbox_reg_weights self.bbox_reg_weights = bbox_reg_weights
self.rpn_only = rpn_only self.rpn_only = rpn_only
self.fixed_input_shape = fixed_input_shape
def build_net(self, inputs): def build_net(self, inputs):
im = inputs['image'] im = inputs['image']
...@@ -306,8 +308,14 @@ class MaskRCNN(object): ...@@ -306,8 +308,14 @@ class MaskRCNN(object):
def generate_inputs(self): def generate_inputs(self):
inputs = OrderedDict() inputs = OrderedDict()
inputs['image'] = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image') if self.fixed_input_shape is not None:
input_shape =[None, 3, self.fixed_input_shape[0], self.fixed_input_shape[1]]
inputs['image'] = fluid.data(
dtype='float32', shape=input_shape, name='image')
else:
inputs['image'] = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image')
if self.mode == 'train': if self.mode == 'train':
inputs['im_info'] = fluid.data( inputs['im_info'] = fluid.data(
dtype='float32', shape=[None, 3], name='im_info') dtype='float32', shape=[None, 3], name='im_info')
......
...@@ -33,7 +33,8 @@ class YOLOv3: ...@@ -33,7 +33,8 @@ class YOLOv3:
nms_iou_threshold=0.45, nms_iou_threshold=0.45,
train_random_shapes=[ train_random_shapes=[
320, 352, 384, 416, 448, 480, 512, 544, 576, 608 320, 352, 384, 416, 448, 480, 512, 544, 576, 608
]): ],
fixed_input_shape=None):
if anchors is None: if anchors is None:
anchors = [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], anchors = [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],
[59, 119], [116, 90], [156, 198], [373, 326]] [59, 119], [116, 90], [156, 198], [373, 326]]
...@@ -54,6 +55,7 @@ class YOLOv3: ...@@ -54,6 +55,7 @@ class YOLOv3:
self.norm_decay = 0.0 self.norm_decay = 0.0
self.prefix_name = '' self.prefix_name = ''
self.train_random_shapes = train_random_shapes self.train_random_shapes = train_random_shapes
self.fixed_input_shape = fixed_input_shape
def _head(self, feats): def _head(self, feats):
outputs = [] outputs = []
...@@ -247,8 +249,13 @@ class YOLOv3: ...@@ -247,8 +249,13 @@ class YOLOv3:
def generate_inputs(self): def generate_inputs(self):
inputs = OrderedDict() inputs = OrderedDict()
inputs['image'] = fluid.data( if self.fixed_input_shape is not None:
dtype='float32', shape=[None, 3, None, None], name='image') input_shape =[None, 3, self.fixed_input_shape[0], self.fixed_input_shape[1]]
inputs['image'] = fluid.data(
dtype='float32', shape=input_shape, name='image')
else:
inputs['image'] = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image')
if self.mode == 'train': if self.mode == 'train':
inputs['gt_box'] = fluid.data( inputs['gt_box'] = fluid.data(
dtype='float32', shape=[None, None, 4], name='gt_box') dtype='float32', shape=[None, None, 4], name='gt_box')
......
...@@ -61,6 +61,7 @@ class DeepLabv3p(object): ...@@ -61,6 +61,7 @@ class DeepLabv3p(object):
自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1, 自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,
即平时使用的交叉熵损失函数。 即平时使用的交叉熵损失函数。
ignore_index (int): label上忽略的值,label为ignore_index的像素不参与损失函数的计算。 ignore_index (int): label上忽略的值,label为ignore_index的像素不参与损失函数的计算。
fixed_input_shape (list): 长度为2,维度为1的list,如:[640,720],用来固定模型输入:'image'的shape,默认为None。
Raises: Raises:
ValueError: use_bce_loss或use_dice_loss为真且num_calsses > 2。 ValueError: use_bce_loss或use_dice_loss为真且num_calsses > 2。
...@@ -81,7 +82,8 @@ class DeepLabv3p(object): ...@@ -81,7 +82,8 @@ class DeepLabv3p(object):
use_bce_loss=False, use_bce_loss=False,
use_dice_loss=False, use_dice_loss=False,
class_weight=None, class_weight=None,
ignore_index=255): ignore_index=255,
fixed_input_shape=None):
# dice_loss或bce_loss只适用两类分割中 # dice_loss或bce_loss只适用两类分割中
if num_classes > 2 and (use_bce_loss or use_dice_loss): if num_classes > 2 and (use_bce_loss or use_dice_loss):
raise ValueError( raise ValueError(
...@@ -115,6 +117,7 @@ class DeepLabv3p(object): ...@@ -115,6 +117,7 @@ class DeepLabv3p(object):
self.decoder_use_sep_conv = decoder_use_sep_conv self.decoder_use_sep_conv = decoder_use_sep_conv
self.encoder_with_aspp = encoder_with_aspp self.encoder_with_aspp = encoder_with_aspp
self.enable_decoder = enable_decoder self.enable_decoder = enable_decoder
self.fixed_input_shape = fixed_input_shape
def _encoder(self, input): def _encoder(self, input):
# 编码器配置,采用ASPP架构,pooling + 1x1_conv + 三个不同尺度的空洞卷积并行, concat后1x1conv # 编码器配置,采用ASPP架构,pooling + 1x1_conv + 三个不同尺度的空洞卷积并行, concat后1x1conv
...@@ -310,8 +313,14 @@ class DeepLabv3p(object): ...@@ -310,8 +313,14 @@ class DeepLabv3p(object):
def generate_inputs(self): def generate_inputs(self):
inputs = OrderedDict() inputs = OrderedDict()
inputs['image'] = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image') if self.fixed_input_shape is not None:
input_shape =[None, 3, self.fixed_input_shape[0], self.fixed_input_shape[1]]
inputs['image'] = fluid.data(
dtype='float32', shape=input_shape, name='image')
else:
inputs['image'] = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image')
if self.mode == 'train': if self.mode == 'train':
inputs['label'] = fluid.data( inputs['label'] = fluid.data(
dtype='int32', shape=[None, 1, None, None], name='label') dtype='int32', shape=[None, 1, None, None], name='label')
......
...@@ -54,6 +54,7 @@ class UNet(object): ...@@ -54,6 +54,7 @@ class UNet(object):
自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1, 自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,
即平时使用的交叉熵损失函数。 即平时使用的交叉熵损失函数。
ignore_index (int): label上忽略的值,label为ignore_index的像素不参与损失函数的计算。 ignore_index (int): label上忽略的值,label为ignore_index的像素不参与损失函数的计算。
fixed_input_shape (list): 长度为2,维度为1的list,如:[640,720],用来固定模型输入:'image'的shape,默认为None。
Raises: Raises:
ValueError: use_bce_loss或use_dice_loss为真且num_calsses > 2。 ValueError: use_bce_loss或use_dice_loss为真且num_calsses > 2。
...@@ -69,7 +70,8 @@ class UNet(object): ...@@ -69,7 +70,8 @@ class UNet(object):
use_bce_loss=False, use_bce_loss=False,
use_dice_loss=False, use_dice_loss=False,
class_weight=None, class_weight=None,
ignore_index=255): ignore_index=255,
fixed_input_shape=None):
# dice_loss或bce_loss只适用两类分割中 # dice_loss或bce_loss只适用两类分割中
if num_classes > 2 and (use_bce_loss or use_dice_loss): if num_classes > 2 and (use_bce_loss or use_dice_loss):
raise Exception( raise Exception(
...@@ -97,6 +99,7 @@ class UNet(object): ...@@ -97,6 +99,7 @@ class UNet(object):
self.use_dice_loss = use_dice_loss self.use_dice_loss = use_dice_loss
self.class_weight = class_weight self.class_weight = class_weight
self.ignore_index = ignore_index self.ignore_index = ignore_index
self.fixed_input_shape = fixed_input_shape
def _double_conv(self, data, out_ch): def _double_conv(self, data, out_ch):
param_attr = fluid.ParamAttr( param_attr = fluid.ParamAttr(
...@@ -226,8 +229,14 @@ class UNet(object): ...@@ -226,8 +229,14 @@ class UNet(object):
def generate_inputs(self): def generate_inputs(self):
inputs = OrderedDict() inputs = OrderedDict()
inputs['image'] = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image') if self.fixed_input_shape is not None:
input_shape =[None, 3, self.fixed_input_shape[0], self.fixed_input_shape[1]]
inputs['image'] = fluid.data(
dtype='float32', shape=input_shape, name='image')
else:
inputs['image'] = fluid.data(
dtype='float32', shape=[None, 3, None, None], name='image')
if self.mode == 'train': if self.mode == 'train':
inputs['label'] = fluid.data( inputs['label'] = fluid.data(
dtype='int32', shape=[None, 1, None, None], name='label') dtype='int32', shape=[None, 1, None, None], name='label')
......
...@@ -201,10 +201,12 @@ class Padding: ...@@ -201,10 +201,12 @@ class Padding:
Args: Args:
coarsest_stride (int): 填充后的图像长、宽为该参数的倍数,默认为1。 coarsest_stride (int): 填充后的图像长、宽为该参数的倍数,默认为1。
target_size (int|list): 填充后的图像长、宽,默认为1。
""" """
def __init__(self, coarsest_stride=1): def __init__(self, coarsest_stride=1, target_size=None):
self.coarsest_stride = coarsest_stride self.coarsest_stride = coarsest_stride
self.target_size = target_size
def __call__(self, im, im_info=None, label_info=None): def __call__(self, im, im_info=None, label_info=None):
""" """
...@@ -221,9 +223,10 @@ class Padding: ...@@ -221,9 +223,10 @@ class Padding:
Raises: Raises:
TypeError: 形参数据类型不满足需求。 TypeError: 形参数据类型不满足需求。
ValueError: 数据长度不匹配。 ValueError: 数据长度不匹配。
ValueError: target_size小于原图的大小。
""" """
if self.coarsest_stride == 1: if self.coarsest_stride == 1 and self.target_size is None:
if label_info is None: if label_info is None:
return (im, im_info) return (im, im_info)
else: else:
...@@ -240,6 +243,20 @@ class Padding: ...@@ -240,6 +243,20 @@ class Padding:
np.ceil(im_h / self.coarsest_stride) * self.coarsest_stride) np.ceil(im_h / self.coarsest_stride) * self.coarsest_stride)
padding_im_w = int( padding_im_w = int(
np.ceil(im_w / self.coarsest_stride) * self.coarsest_stride) np.ceil(im_w / self.coarsest_stride) * self.coarsest_stride)
if self.target_size is not None:
if isinstance(self.target_size, int):
padding_im_h = self.target_size
padding_im_w = self.target_size
else:
padding_im_h = self.target_size[0]
padding_im_w = self.target_size[1]
pad_height = padding_im_h - im_h
pad_width = padding_im_w - im_w
if pad_height < 0 or pad_width < 0:
raise ValueError(
'the size of image should be less than target_size, but the size of image ({}, {}), is larger than target_size ({}, {})'
.format(im_w, im_h, padding_im_w, padding_im_h))
padding_im = np.zeros((padding_im_h, padding_im_w, im_c), padding_im = np.zeros((padding_im_h, padding_im_w, im_c),
dtype=np.float32) dtype=np.float32)
padding_im[:im_h, :im_w, :] = im padding_im[:im_h, :im_w, :] = im
......
...@@ -287,6 +287,76 @@ class ResizeByLong: ...@@ -287,6 +287,76 @@ class ResizeByLong:
else: else:
return (im, im_info, label) return (im, im_info, label)
class ResizeByShort:
"""根据图像的短边调整图像大小(resize)。
1. 获取图像的长边和短边长度。
2. 根据短边与short_size的比例,计算长边的目标长度,
此时高、宽的resize比例为short_size/原图短边长度。
3. 如果max_size>0,调整resize比例:
如果长边的目标长度>max_size,则高、宽的resize比例为max_size/原图长边长度。
4. 根据调整大小的比例对图像进行resize。
Args:
target_size (int): 短边目标长度。默认为800。
max_size (int): 长边目标长度的最大限制。默认为1333。
Raises:
TypeError: 形参数据类型不满足需求。
"""
def __init__(self, short_size=800, max_size=1333):
self.max_size = int(max_size)
if not isinstance(short_size, int):
raise TypeError(
"Type of short_size is invalid. Must be Integer, now is {}".
format(type(short_size)))
self.short_size = short_size
if not (isinstance(self.max_size, int)):
raise TypeError("max_size: input type is invalid.")
def __call__(self, im, im_info=None, label_info=None):
"""
Args:
im (numnp.ndarraypy): 图像np.ndarray数据。
im_info (dict, 可选): 存储与图像相关的信息。
label_info (dict, 可选): 存储与标注框相关的信息。
Returns:
tuple: 当label_info为空时,返回的tuple为(im, im_info),分别对应图像np.ndarray数据、存储与图像相关信息的字典;
当label_info不为空时,返回的tuple为(im, im_info, label_info),分别对应图像np.ndarray数据、
存储与标注框相关信息的字典。
其中,im_info更新字段为:
- im_resize_info (np.ndarray): resize后的图像高、resize后的图像宽、resize后的图像相对原始图的缩放比例
三者组成的np.ndarray,形状为(3,)。
Raises:
TypeError: 形参数据类型不满足需求。
ValueError: 数据长度不匹配。
"""
if im_info is None:
im_info = dict()
if not isinstance(im, np.ndarray):
raise TypeError("ResizeByShort: image type is not numpy.")
if len(im.shape) != 3:
raise ValueError('ResizeByShort: image is not 3-dimensional.')
im_short_size = min(im.shape[0], im.shape[1])
im_long_size = max(im.shape[0], im.shape[1])
scale = float(self.short_size) / im_short_size
if self.max_size > 0 and np.round(
scale * im_long_size) > self.max_size:
scale = float(self.max_size) / float(im_long_size)
resized_width = int(round(im.shape[1] * scale))
resized_height = int(round(im.shape[0] * scale))
im_resize_info = [resized_height, resized_width, scale]
im = cv2.resize(
im, (resized_width, resized_height),
interpolation=cv2.INTER_LINEAR)
im_info['im_resize_info'] = np.array(im_resize_info).astype(np.float32)
if label_info is None:
return (im, im_info)
else:
return (im, im_info, label_info)
class ResizeRangeScaling: class ResizeRangeScaling:
"""对图像长边随机resize到指定范围内,短边按比例进行缩放。当存在标注图像时,则同步进行处理。 """对图像长边随机resize到指定范围内,短边按比例进行缩放。当存在标注图像时,则同步进行处理。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册