diff --git a/research/cv/PSPNet/README.md b/research/cv/PSPNet/README.md index 2d1665ceeeea0031f63d1487d84b7c1ec874d0b1..9893a6adc34a4d3d29fdd0cd6838b47c0ce2f9bd 100644 --- a/research/cv/PSPNet/README.md +++ b/research/cv/PSPNet/README.md @@ -13,8 +13,13 @@ - [Training Results](#training-results) - [Evaluation Process](#evaluation-process) - [Evaluation](#evaluation) - - [Evaluation Result](#evaluation-result) + - [Evaluation Result](#evaluation-resul) + - [Export MindIR](#export-mindir) + - [310 infer](#310-inference) - [Model Description](#model-description) + - [Performance](#performance) + - [Evaluation Performance](#evaluation-performance) + - [Inference Performance](#inference-performance) - [Description of Random Situation](#description-of-random-situation) - [ModelZoo Homepage](#modelzoo-homepage) @@ -52,6 +57,7 @@ The pyramid pooling module fuses features under four different pyramid scales.Fo ```python . └─PSPNet +├── ascend310_infer ├── eval.py # Evaluation python file for ADE20K/VOC2012 ├── export.py # export mindir ├── README.md # descriptions about PSPnet @@ -74,8 +80,9 @@ The pyramid pooling module fuses features under four different pyramid scales.Fo │ └── p_util.py # some functions │ ├── scripts -│ ├── run_distribute_train_ascend.sh # multi cards distributed training in ascend -│ ├── run_train1p_ascend.sh # multi cards distributed training in ascend +│ ├── run_distribute_train_ascend.sh # multi cards distributed training in ascend +│ ├── run_train1p_ascend.sh # 1P training in ascend +│ ├── run_infer_310.sh # 310 infer │ └── run_eval.sh # validation script └── train.py # The training python file for ADE20K/VOC2012 ``` @@ -160,13 +167,29 @@ Check the checkpoint path in config/ade20k_pspnet50.yaml and config/voc2012_pspn ### Evaluation Result -The results at eval/log were as follows: +The results at eval.log were as follows: ```bash ADE20K:mIoU/mAcc/allAcc 0.4164/0.5319/0.7996. VOC2012:mIoU/mAcc/allAcc 0.7380/0.8229/0.9293. ```` +## [Export MindIR](#contents) + +```shell +python export.py --yaml_path [YAML_PTAH] --ckpt_file [CKPT_PATH] +``` + +The ckpt_file parameter is required, + +## 310 infer + +- Note: Before executing 310 infer, create the MINDIR/AIR model using "python export.py --ckpt_file [The path of the CKPT for exporting] --config [The yaml file]". + +```shell + bash run_infer_310.sh [MINDIR PTAH [YAML PTAH] [DATA PATH] [DEVICE ID] +``` + # [Model Description](#Content) ## Performance @@ -186,6 +209,18 @@ VOC2012:mIoU/mAcc/allAcc 0.7380/0.8229/0.9293. |Script URL |https://gitee.com/mindspore/models/tree/master/research/cv/PSPNet| |Random number seed |set_seed = 1234 | +## Inference Performance + +| Parameters | Ascend | +| ------------------- | --------------------------- | +| Model Version | PSPNet | +| Resource | Ascend 310; OS Euler2.8 | +| Uploaded Date | 12/22/2021 (month/day/year) | +| MindSpore Version | 1.5.0 | +| Dataset | voc2012/ade20k | +| outputs | Miou/Acc | +| Accuracy | 0.4164/0.7996.(ade20k) 0.7380/0.9293(voc2012) | + # [Description of Random Situation](#Content) The random seed in `train.py`. diff --git a/research/cv/PSPNet/ascend310_infer/CMakeLists.txt b/research/cv/PSPNet/ascend310_infer/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee3c85447340e0449ff2b70ed24f60a17e07b2b6 --- /dev/null +++ b/research/cv/PSPNet/ascend310_infer/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.14.1) +project(Ascend310Infer) +add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -std=c++17 -Werror -Wall -fPIE -Wl,--allow-shlib-undefined") +set(PROJECT_SRC_ROOT ${CMAKE_CURRENT_LIST_DIR}/) +option(MINDSPORE_PATH "mindspore install path" "") +include_directories(${MINDSPORE_PATH}) +include_directories(${MINDSPORE_PATH}/include) +include_directories(${PROJECT_SRC_ROOT}) +find_library(MS_LIB libmindspore.so ${MINDSPORE_PATH}/lib) +file(GLOB_RECURSE MD_LIB ${MINDSPORE_PATH}/_c_dataengine*) + +add_executable(main src/main.cc src/utils.cc) +target_link_libraries(main ${MS_LIB} ${MD_LIB} gflags) diff --git a/research/cv/PSPNet/ascend310_infer/build.sh b/research/cv/PSPNet/ascend310_infer/build.sh new file mode 100644 index 0000000000000000000000000000000000000000..af419295444eda168b53cec600bb556da2881419 --- /dev/null +++ b/research/cv/PSPNet/ascend310_infer/build.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ + +if [ ! -d out ]; then + rm -rf out +fi + +mkdir out + +cd out || exit + +if [ -f "Makefile" ]; then + make clean +fi + +cmake .. \ + -DMINDSPORE_PATH="`pip show mindspore-ascend | grep Location | awk '{print $2"/mindspore"}' | xargs realpath`" +make diff --git a/research/cv/PSPNet/ascend310_infer/inc/utils.h b/research/cv/PSPNet/ascend310_infer/inc/utils.h new file mode 100644 index 0000000000000000000000000000000000000000..720e0a0fb9009474e582302307e8be80db493fb4 --- /dev/null +++ b/research/cv/PSPNet/ascend310_infer/inc/utils.h @@ -0,0 +1,32 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * 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. + */ + +#ifndef MINDSPORE_INFERENCE_UTILS_H_ +#define MINDSPORE_INFERENCE_UTILS_H_ + +#include <sys/stat.h> +#include <dirent.h> +#include <vector> +#include <string> +#include <memory> +#include "include/api/types.h" + +std::vector<std::string> GetAllFiles(std::string dirName); +DIR *OpenDir(std::string_view dirName); +std::string RealPath(std::string_view path); +mindspore::MSTensor ReadFileToTensor(const std::string &file); +int WriteResult(const std::string& imageFile, const std::vector<mindspore::MSTensor> &outputs); +#endif diff --git a/research/cv/PSPNet/ascend310_infer/src/main.cc b/research/cv/PSPNet/ascend310_infer/src/main.cc new file mode 100644 index 0000000000000000000000000000000000000000..57bbfcf383d25ac68d032cb54fb18d90409a719c --- /dev/null +++ b/research/cv/PSPNet/ascend310_infer/src/main.cc @@ -0,0 +1,146 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * 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 <sys/time.h> +#include <gflags/gflags.h> +#include <dirent.h> +#include <iostream> +#include <string> +#include <algorithm> +#include <iosfwd> +#include <vector> +#include <fstream> +#include <sstream> + +#include "../inc/utils.h" +#include "include/api/types.h" +#include "include/api/model.h" +#include "include/api/serialization.h" +#include "include/api/context.h" + +using mindspore::Serialization; +using mindspore::Model; +using mindspore::Context; +using mindspore::Status; +using mindspore::ModelType; +using mindspore::Graph; +using mindspore::GraphCell; +using mindspore::kSuccess; +using mindspore::MSTensor; +using mindspore::DataType; + + +DEFINE_string(mindir_path, "", "mindir path"); +DEFINE_string(input0_path, ".", "input0 path"); +DEFINE_string(dims_save_path, ".", "dims save path"); +DEFINE_int32(device_id, 0, "device id"); + +int main(int argc, char **argv) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + if (RealPath(FLAGS_mindir_path).empty()) { + std::cout << "Invalid mindir path" << std::endl; + return 1; + } + + auto context = std::make_shared<Context>(); + auto ascend310_info = std::make_shared<mindspore::Ascend310DeviceInfo>(); + ascend310_info->SetDeviceID(FLAGS_device_id); + context->MutableDeviceInfo().push_back(ascend310_info); + + Graph graph; + Status ret = Serialization::Load(FLAGS_mindir_path, ModelType::kMindIR, &graph); + if (ret != kSuccess) { + std::cout << "Load model failed." << std::endl; + return 1; + } + + Model model; + ret = model.Build(GraphCell(graph), context); + if (ret != kSuccess) { + std::cout << "ERROR: Build failed." << std::endl; + return 1; + } + + std::vector<MSTensor> modelInputs = model.GetInputs(); + + auto all_files = GetAllFiles(FLAGS_input0_path); + if (all_files.empty()) { + std::cout << "ERROR: no input data." << std::endl; + return 1; + } + + std::map<double, double> costTime_map; + + std::vector<std::vector<int64_t>> outputs_dim; + + size_t size = all_files.size(); + for (size_t i = 0; i < size; ++i) { + struct timeval start; + struct timeval end; + double startTime_ms; + double endTime_ms; + std::vector<MSTensor> inputs; + std::vector<MSTensor> outputs; + std::cout << "Start predict input files:" << all_files[i] << std::endl; + mindspore::MSTensor image = ReadFileToTensor(all_files[i]); + + inputs.emplace_back(modelInputs[0].Name(), modelInputs[0].DataType(), modelInputs[0].Shape(), + image.Data().get(), image.DataSize()); + + + gettimeofday(&start, NULL); + model.Predict(inputs, &outputs); + gettimeofday(&end, NULL); + + startTime_ms = (1.0 * start.tv_sec * 1000000 + start.tv_usec) / 1000; + endTime_ms = (1.0 * end.tv_sec * 1000000 + end.tv_usec) / 1000; + costTime_map.insert(std::pair<double, double>(startTime_ms, endTime_ms)); + std::vector<int64_t> shape = outputs[0].Shape(); + outputs_dim.emplace_back(shape); + WriteResult(all_files[i], outputs); + } + + std::string dims_file_path = "./result_Files/dims.txt"; + FILE* dim_txt = fopen(dims_file_path.c_str(), "wb"); + for (auto& dim : outputs_dim) { + for (auto& dim_num : dim) { + fprintf(dim_txt, "%ld\n", dim_num); + } + } + fclose(dim_txt); + + double average = 0.0; + int infer_cnt = 0; + + for (auto iter = costTime_map.begin(); iter != costTime_map.end(); iter++) { + double diff = 0.0; + diff = iter->second - iter->first; + average += diff; + infer_cnt++; + } + + average = average / infer_cnt; + + std::stringstream timeCost; + timeCost << "NN inference cost average time: " << average << " ms of infer_count " << infer_cnt << std::endl; + std::cout << "NN inference cost average time: " << average << "ms of infer_count " << infer_cnt << std::endl; + std::string file_name = "./time_Result" + std::string("/test_perform_static.txt"); + std::ofstream file_stream(file_name.c_str(), std::ios::trunc); + file_stream << timeCost.str(); + file_stream.close(); + costTime_map.clear(); + return 0; +} diff --git a/research/cv/PSPNet/ascend310_infer/src/utils.cc b/research/cv/PSPNet/ascend310_infer/src/utils.cc new file mode 100644 index 0000000000000000000000000000000000000000..6b99eb05864c3208aee4ba80a67ce31a76d56a89 --- /dev/null +++ b/research/cv/PSPNet/ascend310_infer/src/utils.cc @@ -0,0 +1,159 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * 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 <fstream> +#include <algorithm> +#include <iostream> +#include <cstdlib> +#include "../inc/utils.h" + +using mindspore::MSTensor; +using mindspore::DataType; + +std::vector<std::string> GetAllFiles(std::string dirName) { + std::ifstream txt_file(dirName); + std::string line; + std::vector<std::string> inputs_path; + if (txt_file) { + while (getline(txt_file, line)) { + inputs_path.emplace_back(line); + } + } else { + std::cout << "The file " << dirName << " is not exist" << std::endl; + return {}; + } + + return inputs_path; +} + +std::vector<std::string> GetImagesById(const std::string &idFile, const std::string &dirName) { + std::ifstream readFile(idFile); + std::string line; + std::vector<std::string> result; + + if (!readFile.is_open()) { + std::cout << "can not open image id txt file" << std::endl; + return result; + } + + while (getline(readFile, line)) { + std::size_t pos = line.find(" "); + std::string id = line.substr(0, pos); + result.emplace_back(dirName + "/" + id); + } + + return result; +} + +int WriteResult(const std::string& imageFile, const std::vector<MSTensor> &outputs) { + std::string homePath = "./result_Files/"; + const int INVALID_POINTER = -1; + const int ERROR = -2; + for (size_t i = 0; i < outputs.size(); ++i) { + size_t outputSize; + std::shared_ptr<const void> netOutput; + netOutput = outputs[i].Data(); + outputSize = outputs[i].DataSize(); + int pos = imageFile.rfind('/'); + std::string fileName(imageFile, pos + 1); + std::string outFileName = homePath + fileName; + std::string outs_file = "./result_Files/outputs.txt"; + FILE * outs_txt = fopen(outs_file.c_str(), "ab+"); + fprintf(outs_txt, "%s\n", outFileName.c_str()); + fclose(outs_txt); + FILE * outputFile = fopen(outFileName.c_str(), "wb"); + if (outputFile == nullptr) { + std::cout << "open result file " << outFileName << " failed" << std::endl; + return INVALID_POINTER; + } + size_t size = fwrite(netOutput.get(), sizeof(char), outputSize, outputFile); + if (size != outputSize) { + fclose(outputFile); + outputFile = nullptr; + std::cout << "write result file " << outFileName << " failed, write size[" << size << + "] is smaller than output size[" << outputSize << "], maybe the disk is full." << std::endl; + return ERROR; + } + fclose(outputFile); + outputFile = nullptr; + } + return 0; +} + +MSTensor ReadFileToTensor(const std::string &file) { + if (file.empty()) { + std::cout << "Pointer file is nullptr" << std::endl; + return MSTensor(); + } + + std::ifstream ifs(file); + if (!ifs.good()) { + std::cout << "File: " << file << " is not exist" << std::endl; + return MSTensor(); + } + + if (!ifs.is_open()) { + std::cout << "File: " << file << "open failed" << std::endl; + return MSTensor(); + } + + ifs.seekg(0, std::ios::end); + size_t size = ifs.tellg(); + MSTensor buffer(file, mindspore::DataType::kNumberTypeFloat32, {static_cast<int64_t>(size)}, nullptr, size); + + ifs.seekg(0, std::ios::beg); + ifs.read(reinterpret_cast<char *>(buffer.MutableData()), size); + ifs.close(); + + return buffer; +} + +DIR *OpenDir(std::string_view dirName) { + if (dirName.empty()) { + std::cout << " dirName is null ! " << std::endl; + return nullptr; + } + std::string realPath = RealPath(dirName); + struct stat s; + lstat(realPath.c_str(), &s); + if (!S_ISDIR(s.st_mode)) { + std::cout << "dirName is not a valid directory !" << std::endl; + return nullptr; + } + DIR *dir; + dir = opendir(realPath.c_str()); + if (dir == nullptr) { + std::cout << "Can not open dir " << dirName << std::endl; + return nullptr; + } + std::cout << "Successfully opened the dir " << dirName << std::endl; + return dir; +} + +std::string RealPath(std::string_view path) { + char realPathMem[PATH_MAX] = {0}; + char *realPathRet = nullptr; + realPathRet = realpath(path.data(), realPathMem); + + if (realPathRet == nullptr) { + std::cout << "File: " << path << " is not exist."; + return ""; + } + + std::string realPath(realPathMem); + std::cout << path << " realpath is: " << realPath << std::endl; + return realPath; +} diff --git a/research/cv/PSPNet/postprocess.py b/research/cv/PSPNet/postprocess.py new file mode 100644 index 0000000000000000000000000000000000000000..cea407082020c3d8811e80e08e698407b7d0ace0 --- /dev/null +++ b/research/cv/PSPNet/postprocess.py @@ -0,0 +1,249 @@ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" POSTPROCESS FOR 310 INFER """ +import os +import logging +import argparse +import cv2 +import numpy as np +from src.dataset import pt_dataset, pt_transform +import src.utils.functions_args as fa +from src.utils.p_util import AverageMeter, intersectionAndUnion, check_makedirs, colorize +import mindspore +from mindspore import Tensor +from mindspore import context +import mindspore.nn as nn + +cv2.ocl.setUseOpenCL(False) +context.set_context(device_target="CPU") + +parser = argparse.ArgumentParser(description='MindSpore Semantic Segmentation') +parser.add_argument('--config', type=str, required=True, default=None, help='config file') +parser.add_argument('--data_path', type=str, required=True, default=None, help='data path') +parser.add_argument('opts', help='see voc2012_pspnet50.yaml/ade20k_pspnet50.yaml for all options', default=None, + nargs=argparse.REMAINDER) +args_ = parser.parse_args() +cfg = fa.load_cfg_from_cfg_file(args_.config) + + +def get_logger(): + """ logger """ + logger_name = "main-logger" + logger_ = logging.getLogger(logger_name) + logger_.setLevel(logging.INFO) + handler = logging.StreamHandler() + fmt = "[%(asctime)s %(levelname)s %(filename)s line %(lineno)d %(process)d] %(message)s" + handler.setFormatter(logging.Formatter(fmt)) + logger_.addHandler(handler) + return logger_ + + +def check(local_args): + """ check args """ + assert local_args.classes > 1 + assert local_args.zoom_factor in [1, 2, 4, 8] + assert local_args.split in ['train', 'val', 'test'] + if local_args.arch == 'psp': + assert (local_args.train_h - 1) % 8 == 0 and (local_args.train_w - 1) % 8 == 0 + else: + raise Exception('architecture not supported {} yet'.format(local_args.arch)) + + +def main(): + """ The main function of the postprocess """ + check(cfg) + value_scale = 255 + mean = [0.485, 0.456, 0.406] + mean = [item * value_scale for item in mean] + std = [0.229, 0.224, 0.225] + std = [item * value_scale for item in std] + gray_folder = os.path.join('./postprocess_Result/', 'gray') + color_folder = os.path.join('./postprocess_Result/', 'color') + + test_transform = pt_transform.Compose([pt_transform.Normalize(mean=mean, std=std, is_train=False)]) + test_data = pt_dataset.SemData( + split='val', data_root=args_.data_path, + data_list=args_.data_path + 'val_list.txt', + transform=test_transform) + color_name_path = os.path.dirname(args_.config) + if cfg.prefix == 'voc': + color_file = color_name_path + '/voc2012/voc2012_colors.txt' + name_file = color_name_path + '/voc2012/voc2012_names.txt' + else: + color_file = color_name_path + '/ade20k/ade20k_colors.txt' + name_file = color_name_path + '/ade20k/ade20k_names.txt' + colors = np.loadtxt(color_file).astype('uint8') + names = [line.rstrip('\n') for line in open(name_file)] + + merge_blocks(test_data, test_data.data_list, cfg.classes, mean, cfg.base_size, cfg.test_h, + cfg.test_w, cfg.scales, gray_folder, color_folder, colors) + acc(test_data.data_list, gray_folder, cfg.classes, names) + + +def bin_process(image, image_idx, flip=True): + """ Process Bin File """ + _, _, h_i, w_i = (2, 3, 473, 473) + _, _, h_o, w_o = dims[image_idx] + image = np.resize(image, dims[image_idx]) + image = Tensor.from_numpy(image) + image = image.astype(mindspore.float32) + + if (h_o != h_i) or (w_o != w_i): + bi_linear = nn.ResizeBilinear() + image = bi_linear(image, size=(h_i, w_i), align_corners=True) + softmax = nn.Softmax(axis=1) + output = softmax(image) + output = output.asnumpy() + + if flip: + flip_ = np.flip(output[1], axis=[2]) + output = (output[0] + flip_) / 2 + else: + output = output[0] + output = np.transpose(output, (1, 2, 0)) + return output + + +def merge_aux(image, image_idx, classes, crop_h, crop_w, h, w, mean, stride_rate=2 / 3): + """ Merge Helper """ + global file_index + o_h, o_w, _ = image.shape + pad_w = max(crop_w - o_w, 0) + pad_h = max(crop_h - o_h, 0) + pad_h_half = int(pad_h / 2) + pad_w_half = int(pad_w / 2) + if pad_h > 0 or pad_w > 0: + image = cv2.copyMakeBorder(image, pad_h_half, pad_h - pad_h_half, pad_w_half, pad_w - pad_w_half, + cv2.BORDER_CONSTANT, value=mean) + + new_h, new_w, _ = image.shape + stride_h = int(np.ceil(crop_h * stride_rate)) + stride_w = int(np.ceil(crop_w * stride_rate)) + grid_h = int(np.ceil(float(new_h - crop_h) / stride_h) + 1) + grid_w = int(np.ceil(float(new_w - crop_w) / stride_w) + 1) + prediction_crop = np.zeros((new_h, new_w, classes), dtype=float) + count_crop = np.fromfile(aux_inputs_file[image_idx], dtype=np.int) + count_crop = np.resize(count_crop, (new_h, new_w)) + for index_h in range(0, grid_h): + for index_w in range(0, grid_w): + print("PROCESS IMAGE ", image_idx + 1, " Bin file is ", bin_file[file_index]) + s_h = index_h * stride_h + e_h = min(s_h + crop_h, new_h) + s_h = e_h - crop_h + s_w = index_w * stride_w + e_w = min(s_w + crop_w, new_w) + s_w = e_w - crop_w + image_crop = np.fromfile(bin_file[file_index], dtype=np.float32) + prediction_crop[s_h:e_h, s_w:e_w, :] += bin_process(image_crop, image_idx) + file_index += 1 + prediction_crop /= np.expand_dims(count_crop, 2) + prediction_crop = prediction_crop[pad_h_half:pad_h_half + o_h, pad_w_half:pad_w_half + o_w] + prediction = cv2.resize(prediction_crop, (w, h), interpolation=cv2.INTER_LINEAR) + return prediction + + +def merge_blocks(test_loader, data_list, classes, mean, base_size, crop_h, crop_w, scales, gray_folder, + color_folder, colors): + """ Generate evaluate image """ + logger.info('>>>>>>>>>>>>>>>> Start Evaluation >>>>>>>>>>>>>>>>') + for i, (input_, _) in enumerate(test_loader): + input_ = np.transpose(input_, (1, 2, 0)) + h, w, _ = input_.shape + prediction = np.zeros((h, w, classes), dtype=float) + for scale in scales: + long_size = round(scale * base_size) + new_h = long_size + new_w = long_size + if h > w: + new_w = round(long_size / float(h) * w) + else: + new_h = round(long_size / float(w) * h) + image_scale = cv2.resize(input_, (new_w, new_h), interpolation=cv2.INTER_LINEAR) + prediction += merge_aux(image_scale, i, classes, crop_h, crop_w, h, w, mean) + prediction /= len(scales) + prediction = np.argmax(prediction, axis=2) + + if ((i + 1) % 10 == 0) or (i + 1 == len(data_list)): + print('Test: [{}/{}] '.format(i + 1, len(data_list))) + check_makedirs(gray_folder) + check_makedirs(color_folder) + gray = np.uint8(prediction) + color = colorize(gray, colors) + image_path, _ = data_list[i] + image_name = image_path.split('/')[-1].split('.')[0] + gray_path = os.path.join(gray_folder, image_name + '.png') + color_path = os.path.join(color_folder, image_name + '.png') + cv2.imwrite(gray_path, gray) + color.save(color_path) + logger.info('<<<<<<<<<<<<<<<<< End Evaluation <<<<<<<<<<<<<<<<<') + + +def acc(data_list, pred_folder, classes, names): + """ Calculate The Accuracy Of 310 Model """ + target_meter = AverageMeter() + intersection_meter = AverageMeter() + union_meter = AverageMeter() + logger.info('>>>>>>>>>>>>>>>> Calculate The Accuracy Of Each Predicted Image >>>>>>>>>>>>>>>>') + for i, (image_path, target_path) in enumerate(data_list): + image_name = image_path.split('/')[-1].split('.')[0] + pred = cv2.imread(os.path.join(pred_folder, image_name + '.png'), cv2.IMREAD_GRAYSCALE) + target = cv2.imread(target_path, cv2.IMREAD_GRAYSCALE) + if cfg.prefix != 'voc': + target -= 1 + intersection, union, target = intersectionAndUnion(pred, target, classes) + intersection_meter.update(intersection) + union_meter.update(union) + target_meter.update(target) + accuracy = sum(intersection_meter.val) / (sum(target_meter.val) + 1e-10) + logger.info( + 'Evaluating {0}/{1} on image {2}, accuracy {3:.4f}.'.format(i + 1, len(data_list), image_name + '.png', + accuracy)) + + logger.info('>>>>>>>>>>>>>>>> End The Accuracy Calculation For Each Predicted Image >>>>>>>>>>>>>>>>') + iou_class = intersection_meter.sum / (union_meter.sum + 1e-10) + accuracy_class = intersection_meter.sum / (target_meter.sum + 1e-10) + mIoU = np.mean(iou_class) + mAcc = np.mean(accuracy_class) + allAcc = sum(intersection_meter.sum) / (sum(target_meter.sum) + 1e-10) + + logger.info('Eval result: mIoU/mAcc/allAcc {:.4f}/{:.4f}/{:.4f}.'.format(mIoU, mAcc, allAcc)) + for i in range(classes): + logger.info('Class_{} result: iou/accuracy {:.4f}/{:.4f}, name: {}.'.format(i, iou_class[i], accuracy_class[i], + names[i])) + + +def read_txt(file_path, for_int=False): + """ Txt File Read Helper""" + lines = [] + with open(file_path, 'r') as file_to_read: + while True: + line = file_to_read.readline() + if not line: + break + line = line.strip('\n') + if for_int: + line = int(line) + lines.append(line) + return lines + + +if __name__ == '__main__': + logger = get_logger() + file_index = 0 + bin_file = read_txt('./result_Files/outputs.txt') + aux_inputs_file = read_txt('./preprocess_Result/aux_inputs.txt') + dims = read_txt('./result_Files/dims.txt', for_int=True) + dims = np.resize(dims, (len(aux_inputs_file), 4)) + main() diff --git a/research/cv/PSPNet/preprocess.py b/research/cv/PSPNet/preprocess.py new file mode 100644 index 0000000000000000000000000000000000000000..a806ba7d70745edecd13c18d75ed37d6e3ab1575 --- /dev/null +++ b/research/cv/PSPNet/preprocess.py @@ -0,0 +1,169 @@ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" PREPROCESS BEFORE 310 INFER """ +import os +import logging +import argparse +import cv2 +import numpy +from src.dataset import pt_dataset, pt_transform +import src.utils.functions_args as fa + +cv2.ocl.setUseOpenCL(False) +Small_block_name = [] +aux_inputs_name = [] + +parser = argparse.ArgumentParser(description='MindSpore Semantic Segmentation') +parser.add_argument('--config', type=str, required=True, default=None, help='config file') +parser.add_argument('--save_path', type=str, required=True, default=None, help='save the preprocess file') +parser.add_argument('--data_path', type=str, required=True, default=None, help='data path') +parser.add_argument('opts', help='see voc2012_pspnet50.yaml/ade20k_pspnet50.yaml for all options', default=None, + nargs=argparse.REMAINDER) +args_ = parser.parse_args() +cfg = fa.load_cfg_from_cfg_file(args_.config) + + +def get_logger(): + """ logger """ + logger_name = "main-logger" + logger_ = logging.getLogger(logger_name) + logger_.setLevel(logging.INFO) + handler = logging.StreamHandler() + fmt = "[%(asctime)s %(levelname)s %(filename)s line %(lineno)d %(process)d] %(message)s" + handler.setFormatter(logging.Formatter(fmt)) + logger_.addHandler(handler) + return logger_ + + +def check(local_args): + """ check args """ + assert local_args.classes > 1 + assert local_args.zoom_factor in [1, 2, 4, 8] + assert local_args.split in ['train', 'val', 'test'] + if local_args.arch == 'psp': + assert (local_args.train_h - 1) % 8 == 0 and (local_args.train_w - 1) % 8 == 0 + else: + raise Exception('architecture not supported {} yet'.format(local_args.arch)) + + +def main(): + """ The main function of the preprocess """ + check(cfg) + value_scale = 255 + mean = [0.485, 0.456, 0.406] + mean = [item * value_scale for item in mean] + std = [0.229, 0.224, 0.225] + std = [item * value_scale for item in std] + + test_transform = pt_transform.Compose([pt_transform.Normalize(mean=mean, std=std, is_train=False)]) + test_data = pt_dataset.SemData( + split='val', data_root=args_.data_path, + data_list=args_.data_path + 'val_list.txt', + transform=test_transform) + + split_image(test_data, mean, std, cfg.base_size, cfg.test_h, cfg.test_w, cfg.scales) + + +def before_net(image, mean, std=None, flip=True): + """ Give the input to the model""" + input_ = numpy.transpose(image, (2, 0, 1)) # (473, 473, 3) -> (3, 473, 473) + mean = numpy.array(mean) + std = numpy.array(std) + if std is None: + input_ = input_ - mean[:, None, None] + else: + input_ = (input_ - mean[:, None, None]) / std[:, None, None] + + input_ = numpy.expand_dims(input_, 0) + if flip: + flip_input = numpy.flip(input_, axis=[3]) + input_ = numpy.concatenate((input_, flip_input), axis=0) + + return input_ + + +def process_image(image, image_idx, crop_h, crop_w, mean, std=None, stride_rate=2 / 3): + """ Process input size """ + original_h, original_w, _ = image.shape + pad_w = max(0, crop_w - original_w) + pad_h = max(0, crop_h - original_h) + pad_h_half = int(pad_h / 2) + pad_w_half = int(pad_w / 2) + file_name = post_save + '/' + str(image_idx) + idx = 0 + if pad_h > 0 or pad_w > 0: + image = cv2.copyMakeBorder(image, pad_h_half, pad_h - pad_h_half, pad_w_half, pad_w - pad_w_half, + cv2.BORDER_CONSTANT, value=mean) + new_h, new_w, _ = image.shape + stride_h = int(numpy.ceil(crop_h * stride_rate)) + stride_w = int(numpy.ceil(crop_w * stride_rate)) + grid_h = int(numpy.ceil(float(new_h - crop_h) / stride_h) + 1) + grid_w = int(numpy.ceil(float(new_w - crop_w) / stride_w) + 1) + count_crop = numpy.zeros((new_h, new_w), dtype=float) + for index_h in range(0, grid_h): + for index_w in range(0, grid_w): + idx += 1 + s_h = index_h * stride_h + e_h = min(s_h + crop_h, new_h) + s_h = e_h - crop_h + s_w = index_w * stride_w + e_w = min(s_w + crop_w, new_w) + s_w = e_w - crop_w + image_crop = image[s_h:e_h, s_w:e_w].copy() + count_crop[s_h:e_h, s_w:e_w] += 1 + image_crop = before_net(image_crop, mean, std) + image_crop = image_crop.astype(numpy.float32) + image_crop.tofile(file_name + '-' + str(idx) + '.bin') + Small_block_name.append(file_name + '-' + str(idx) + '.bin') + count_crop.tofile(count_save + '/' + str(image_idx) + '.bin') + aux_inputs_name.append(count_save + '/' + str(image_idx) + '.bin') + + +def split_image(test_loader, mean, std, base_size, crop_h, crop_w, scales): + """ Get input image with fixed size""" + for i, (input_, _) in enumerate(test_loader): + print('PROCESS IMAGE ', i + 1) + image = numpy.transpose(input_, (1, 2, 0)) + h, w, _ = image.shape + for scale in scales: + long_size = round(scale * base_size) + new_h = long_size + new_w = long_size + if h > w: + new_w = round(long_size / float(h) * w) + else: + new_h = round(long_size / float(w) * h) + + image_scale = cv2.resize(image, (new_w, new_h), interpolation=cv2.INTER_LINEAR) + process_image(image_scale, i + 1, crop_h, crop_w, mean, std) + + +if __name__ == '__main__': + post_save = os.path.join(args_.save_path, 'inputs') + count_save = os.path.join(args_.save_path, 'aux_inputs') + os.mkdir(post_save) + os.mkdir(count_save) + main() + for bin_name in Small_block_name: + f = open(args_.save_path + 'inputs.txt', 'a') + f.write(bin_name) + f.write('\n') + f.close() + + for aux_name in aux_inputs_name: + f = open(args_.save_path + 'aux_inputs.txt', 'a') + f.write(aux_name) + f.write('\n') + f.close() diff --git a/research/cv/PSPNet/scripts/run_infer_310.sh b/research/cv/PSPNet/scripts/run_infer_310.sh new file mode 100644 index 0000000000000000000000000000000000000000..2a8572fdd20383b274a2989bc382d2d7160698a9 --- /dev/null +++ b/research/cv/PSPNet/scripts/run_infer_310.sh @@ -0,0 +1,108 @@ +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ + +if [ $# != 4 ] +then + echo "Usage: bash run_infer_310.sh [MINDIR_PATH] [YAML_PATH] [DATA_PATH] [DEVICE_ID]" + echo "Example: bash run_infer_310.sh ./PSPNet.mindir ./config/voc2012_pspnet50.yaml ./data/voc/ 0" + exit 1 +fi + +MINDIR_PATH=$1 +YAML_PATH=$2 +DATA_PATH=$3 +DEVICE_ID=$4 + +echo "MINDIR_PATH: "$MINDIR_PATH +echo "YAML_PATH: "$YAML_PATH +echo "DATA_PATH: "$DATA_PATH +echo "DEVICE_ID: "$DEVICE_ID + +export ASCEND_HOME=/usr/local/Ascend/ +if [ -d ${ASCEND_HOME}/ascend-toolkit ]; then + export PATH=$ASCEND_HOME/fwkacllib/bin:$ASCEND_HOME/fwkacllib/ccec_compiler/bin:$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin:$ASCEND_HOME/ascend-toolkit/latest/atc/bin:$PATH + export LD_LIBRARY_PATH=$ASCEND_HOME/fwkacllib/lib64:/usr/local/lib:$ASCEND_HOME/ascend-toolkit/latest/atc/lib64:$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/lib64:$ASCEND_HOME/driver/lib64:$ASCEND_HOME/add-ons:$LD_LIBRARY_PATH + export TBE_IMPL_PATH=$ASCEND_HOME/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe + export PYTHONPATH=$ASCEND_HOME/fwkacllib/python/site-packages:${TBE_IMPL_PATH}:$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/python/site-packages:$PYTHONPATH + export ASCEND_OPP_PATH=$ASCEND_HOME/ascend-toolkit/latest/opp +else + export PATH=$ASCEND_HOME/fwkacllib/bin:$ASCEND_HOME/fwkacllib/ccec_compiler/bin:$ASCEND_HOME/atc/ccec_compiler/bin:$ASCEND_HOME/atc/bin:$PATH + export LD_LIBRARY_PATH=$ASCEND_HOME/fwkacllib/lib64:/usr/local/lib:$ASCEND_HOME/atc/lib64:$ASCEND_HOME/acllib/lib64:$ASCEND_HOME/driver/lib64:$ASCEND_HOME/add-ons:$LD_LIBRARY_PATH + export PYTHONPATH=$ASCEND_HOME/fwkacllib/python/site-packages:$ASCEND_HOME/atc/python/site-packages:$PYTHONPATH + export ASCEND_OPP_PATH=$ASCEND_HOME/opp +fi + +function preprocess_data() +{ + if [ -d preprocess_Result ]; then + rm -rf ./preprocess_Result + fi + mkdir preprocess_Result + python3.7 preprocess.py --config=$YAML_PATH --save_path=./preprocess_Result/ --data_path=$DATA_PATH &> preprocess.log +} + +function compile_app() +{ + cd ./ascend310_infer || exit + bash build.sh &> build.log +} + +function infer() +{ + cd - || exit + if [ -d result_Files ]; then + rm -rf ./result_Files + fi + if [ -d time_Result ]; then + rm -rf ./time_Result + fi + mkdir result_Files + mkdir time_Result + ./ascend310_infer/out/main --mindir_path=$MINDIR_PATH --input0_path=./preprocess_Result/inputs.txt --dims_save_path=./result_Files/ --device_id=$DEVICE_ID &> infer.log +} + +function postprocess_data() +{ + if [ -d postprocess_Result ]; then + rm -rf ./postprocess_Result + fi + mkdir postprocess_Result + python3.7 postprocess.py --config=$YAML_PATH --data_path=$DATA_PATH &> postprocess.log +} + +preprocess_data +if [ $? -ne 0 ]; then + echo "prepocess data failed" + exit 1 +fi + +compile_app +if [ $? -ne 0 ]; then + echo "compile app code failed" + exit 1 +fi + +infer +if [ $? -ne 0 ]; then + echo " execute inference failed" + exit 1 +fi + +postprocess_data +if [ $? -ne 0 ]; then + echo "calculate accuracy failed" + exit 1 +fi