diff --git a/model_zoo/official/cv/ctpn/README.md b/model_zoo/official/cv/ctpn/README.md index 420f7a8f24..1c0a8de70b 100644 --- a/model_zoo/official/cv/ctpn/README.md +++ b/model_zoo/official/cv/ctpn/README.md @@ -72,11 +72,13 @@ Here we used 6 datasets for training, and 1 datasets for Evaluation. . └─ctpn ├── README.md # network readme + ├──ascend310_infer #application for 310 inference ├── eval.py # eval net ├── scripts │   ├── eval_res.sh # calculate precision and recall │   ├── run_distribute_train_ascend.sh # launch distributed training with ascend platform(8p) │   ├── run_eval_ascend.sh # launch evaluating with ascend platform + │ ├──run_infer_310.sh # shell script for 310 inference │   └── run_standalone_train_ascend.sh # launch standalone training with ascend platform(1p) ├── src │   ├── CTPN @@ -102,6 +104,8 @@ Here we used 6 datasets for training, and 1 datasets for Evaluation. │   ├── detector.py # detect box │   ├── get_successions.py # get succession proposal │   └── utils.py # some functions which is commonly used + ├──postprogress.py # post process for 310 inference + ├──export.py # script to export AIR,MINDIR model └── train.py # train net ``` @@ -239,6 +243,49 @@ Evaluation result will be stored in the example path, you can find result like t {"precision": 0.90791, "recall": 0.86118, "hmean": 0.88393} ``` +## Model Export + +```shell +python export.py --ckpt_file [CKPT_PATH] --device_target [DEVICE_TARGET] --file_format[EXPORT_FORMAT] +``` + +`EXPORT_FORMAT` should be in ["AIR", "MINDIR"] + +## [Inference process](#contents) + +### Usage + +Before performing inference, the air file must bu exported by export script on the Ascend910 environment. + +```shell +# Ascend310 inference +bash run_infer_310.sh [MODEL_PATH] [DATA_PATH] [ANN_FILE_PATH] [DEVICE_ID]] +``` + +After inference, you can get a archive file named submit.zip.To evalulate it, you can use the scripts provided by the ICDAR2013 network, you can download the Deteval scripts from the [link](https://rrc.cvc.uab.es/?com=downloads&action=download&ch=2&f=aHR0cHM6Ly9ycmMuY3ZjLnVhYi5lcy9zdGFuZGFsb25lcy9zY3JpcHRfdGVzdF9jaDJfdDFfZTItMTU3Nzk4MzA2Ny56aXA=) +After download the scripts, unzip it and put it under ctpn/scripts and use eval_res.sh to get the result.You will get files as below: + +```text +gt.zip +readme.txt +rrc_evalulation_funcs_1_1.py +script.py +``` + +Then you can run the scripts/eval_res.sh to calculate the evalulation result. + +```base +bash eval_res.sh +``` + +### Result + +Evaluation result will be stored in the example path, you can find result like the followings in `log`. + +```text +{"precision": 0.88913, "recall": 0.86082, "hmean": 0.87475} +``` + # [Model description](#contents) ## [Performance](#contents) diff --git a/model_zoo/official/cv/ctpn/ascend310_infer/CMakeLists.txt b/model_zoo/official/cv/ctpn/ascend310_infer/CMakeLists.txt new file mode 100644 index 0000000000..ee3c854473 --- /dev/null +++ b/model_zoo/official/cv/ctpn/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/model_zoo/official/cv/ctpn/ascend310_infer/build.sh b/model_zoo/official/cv/ctpn/ascend310_infer/build.sh new file mode 100644 index 0000000000..8bf761bc33 --- /dev/null +++ b/model_zoo/official/cv/ctpn/ascend310_infer/build.sh @@ -0,0 +1,23 @@ +#!/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 + mkdir out +fi +cd out +cmake .. \ + -DMINDSPORE_PATH="`pip show mindspore-ascend | grep Location | awk '{print $2"/mindspore"}' | xargs realpath`" +make diff --git a/model_zoo/official/cv/ctpn/ascend310_infer/inc/utils.h b/model_zoo/official/cv/ctpn/ascend310_infer/inc/utils.h new file mode 100644 index 0000000000..efebe03a8c --- /dev/null +++ b/model_zoo/official/cv/ctpn/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 +#include +#include +#include +#include +#include "include/api/types.h" + +std::vector GetAllFiles(std::string_view 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 &outputs); +#endif diff --git a/model_zoo/official/cv/ctpn/ascend310_infer/src/main.cc b/model_zoo/official/cv/ctpn/ascend310_infer/src/main.cc new file mode 100644 index 0000000000..4c20c85273 --- /dev/null +++ b/model_zoo/official/cv/ctpn/ascend310_infer/src/main.cc @@ -0,0 +1,152 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../inc/utils.h" +#include "minddata/dataset/include/execute.h" +#include "minddata/dataset/include/transforms.h" +#include "minddata/dataset/include/vision.h" +#include "minddata/dataset/include/vision_ascend.h" +#include "include/api/types.h" +#include "include/api/model.h" +#include "include/api/serialization.h" +#include "include/api/context.h" + +using mindspore::GlobalContext; +using mindspore::Serialization; +using mindspore::Model; +using mindspore::ModelContext; +using mindspore::Status; +using mindspore::ModelType; +using mindspore::GraphCell; +using mindspore::kSuccess; +using mindspore::MSTensor; +using mindspore::DataType; +using mindspore::dataset::Execute; +using mindspore::dataset::TensorTransform; +using mindspore::dataset::vision::Decode; +using mindspore::dataset::vision::Resize; +using mindspore::dataset::vision::Normalize; +using mindspore::dataset::vision::HWC2CHW; + +using mindspore::dataset::transforms::TypeCast; + + +DEFINE_string(model_path, "", "model path"); +DEFINE_string(dataset_path, ".", "dataset path"); +DEFINE_int32(input_width, 960, "input width"); +DEFINE_int32(input_height, 576, "inputheight"); +DEFINE_int32(device_id, 0, "device id"); +DEFINE_string(precision_mode, "allow_fp32_to_fp16", "precision mode"); +DEFINE_string(op_select_impl_mode, "", "op select impl mode"); +DEFINE_string(aipp_path, "./aipp.cfg", "aipp path"); +DEFINE_string(device_target, "Ascend310", "device target"); + +int main(int argc, char **argv) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + if (RealPath(FLAGS_model_path).empty()) { + std::cout << "Invalid model" << std::endl; + return 1; + } + + GlobalContext::SetGlobalDeviceTarget(FLAGS_device_target); + GlobalContext::SetGlobalDeviceID(FLAGS_device_id); + + auto graph = Serialization::LoadModel(FLAGS_model_path, ModelType::kMindIR); + + Model model((GraphCell(graph))); + Status ret = model.Build(); + if (ret != kSuccess) { + std::cout << "ERROR Build failed." << std::endl; + return 1; + } + + auto all_files = GetAllFiles(FLAGS_dataset_path); + if (all_files.empty()) { + std::cout << "ERROR: no input data." << std::endl; + return 1; + } + + std::shared_ptr decode(new Decode()); + std::shared_ptr resize(new Resize({576, 960})); + std::shared_ptr normalize(new Normalize({123.675, 116.28, 103.53}, {58.395, 57.12, 57.375})); + std::shared_ptr hwc2chw(new HWC2CHW()); + std::shared_ptr typeCast(new TypeCast("float16")); + + mindspore::dataset::Execute transformDecode(decode); + mindspore::dataset::Execute transform({resize, normalize, hwc2chw}); + mindspore::dataset::Execute transformCast(typeCast); + + std::map costTime_map; + + 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 inputs; + std::vector outputs; + + std::cout << "Start predict input files:" << all_files[i] << std::endl; + mindspore::MSTensor image = ReadFileToTensor(all_files[i]); + + transformDecode(image, &image); + std::vector shape = image.Shape(); + transform(image, &image); + transformCast(image, &image); + + inputs.emplace_back(image); + + 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(startTime_ms, endTime_ms)); + WriteResult(all_files[i], outputs); + } + double average = 0.0; + int infer_cnt = 0; + char tmpCh[256] = {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; + + snprintf(tmpCh, sizeof(tmpCh), "NN inference cost average time: %4.3f ms of infer_count %d\n", average, infer_cnt); + 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 << tmpCh; + file_stream.close(); + costTime_map.clear(); + return 0; +} diff --git a/model_zoo/official/cv/ctpn/ascend310_infer/src/utils.cc b/model_zoo/official/cv/ctpn/ascend310_infer/src/utils.cc new file mode 100644 index 0000000000..b509c57f82 --- /dev/null +++ b/model_zoo/official/cv/ctpn/ascend310_infer/src/utils.cc @@ -0,0 +1,130 @@ +/** + * 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 "inc/utils.h" + +#include +#include +#include + +using mindspore::MSTensor; +using mindspore::DataType; + +std::vector GetAllFiles(std::string_view dirName) { + struct dirent *filename; + DIR *dir = OpenDir(dirName); + if (dir == nullptr) { + return {}; + } + std::vector res; + while ((filename = readdir(dir)) != nullptr) { + std::string dName = std::string(filename->d_name); + if (dName == "." || dName == ".." || filename->d_type != DT_REG) { + continue; + } + res.emplace_back(std::string(dirName) + "/" + filename->d_name); + } + std::sort(res.begin(), res.end()); + for (auto &f : res) { + std::cout << "image file: " << f << std::endl; + } + return res; +} + +int WriteResult(const std::string& imageFile, const std::vector &outputs) { + std::string homePath = "./result_Files"; + for (size_t i = 0; i < outputs.size(); ++i) { + size_t outputSize; + std::shared_ptr netOutput; + netOutput = outputs[i].Data(); + outputSize = outputs[i].DataSize(); + int pos = imageFile.rfind('/'); + std::string fileName(imageFile, pos + 1); + fileName.replace(fileName.find('.'), fileName.size() - fileName.find('.'), '_' + std::to_string(i) + ".bin"); + std::string outFileName = homePath + "/" + fileName; + FILE * outputFile = fopen(outFileName.c_str(), "wb"); + fwrite(netOutput.get(), outputSize, sizeof(char), outputFile); + fclose(outputFile); + outputFile = nullptr; + } + return 0; +} + +mindspore::MSTensor ReadFileToTensor(const std::string &file) { + if (file.empty()) { + std::cout << "Pointer file is nullptr" << std::endl; + return mindspore::MSTensor(); + } + + std::ifstream ifs(file); + if (!ifs.good()) { + std::cout << "File: " << file << " is not exist" << std::endl; + return mindspore::MSTensor(); + } + + if (!ifs.is_open()) { + std::cout << "File: " << file << "open failed" << std::endl; + return mindspore::MSTensor(); + } + + ifs.seekg(0, std::ios::end); + size_t size = ifs.tellg(); + mindspore::MSTensor buffer(file, mindspore::DataType::kNumberTypeUInt8, {static_cast(size)}, nullptr, size); + + ifs.seekg(0, std::ios::beg); + ifs.read(reinterpret_cast(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/model_zoo/official/cv/ctpn/export.py b/model_zoo/official/cv/ctpn/export.py new file mode 100644 index 0000000000..9a365bfa29 --- /dev/null +++ b/model_zoo/official/cv/ctpn/export.py @@ -0,0 +1,51 @@ +# 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. +# ============================================================================ +"""export checkpoint file into air, onnx, mindir models""" +import argparse +import numpy as np + +import mindspore as ms +from mindspore import Tensor, load_checkpoint, load_param_into_net, export, context + +from src.ctpn import CTPN_Infer +from src.config import config + +parser = argparse.ArgumentParser(description='fasterrcnn_export') +parser.add_argument("--device_id", type=int, default=0, help="Device id") +parser.add_argument("--file_name", type=str, default="ctpn", help="output file name.") +parser.add_argument("--file_format", type=str, choices=["AIR", "MINDIR"], default="MINDIR", help="file format") +parser.add_argument("--device_target", type=str, choices=["Ascend", "GPU", "CPU"], default="Ascend", + help="device target") +parser.add_argument('--ckpt_file', type=str, default='', help='ctpn ckpt file.') +args = parser.parse_args() + +context.set_context(mode=context.GRAPH_MODE, device_target=args.device_target) +if args.device_target == "Ascend": + context.set_context(device_id=args.device_id) + +if __name__ == '__main__': + net = CTPN_Infer(config=config) + + param_dict = load_checkpoint(args.ckpt_file) + + param_dict_new = {} + for key, value in param_dict.items(): + param_dict_new["network." + key] = value + + load_param_into_net(net, param_dict_new) + + img = Tensor(np.zeros([config.test_batch_size, 3, config.img_height, config.img_width]), ms.float16) + + export(net, img, file_name=args.file_name, file_format=args.file_format) diff --git a/model_zoo/official/cv/ctpn/postprocess.py b/model_zoo/official/cv/ctpn/postprocess.py new file mode 100644 index 0000000000..ab3b8496cf --- /dev/null +++ b/model_zoo/official/cv/ctpn/postprocess.py @@ -0,0 +1,108 @@ +# 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. +# ============================================================================ + +"""Evaluation for CTPN""" +import os +import argparse +import numpy as np + +from src.text_connector.detector import detect + +parser = argparse.ArgumentParser(description="CTPN evaluation") +parser.add_argument("--dataset_path", type=str, default="", help="Dataset path.") +parser.add_argument("--result_path", type=str, default="", help="Image path.") +parser.add_argument("--label_path", type=str, default="", help="label path.") +args_opt = parser.parse_args() + +def get_pred(img_file, result_path): + file_name = img_file.split('.')[0] + proposal_file = os.path.join(result_path, file_name + "_0.bin") + mask_file = os.path.join(result_path, file_name + "_1.bin") + proposal = np.fromfile(proposal_file, dtype=np.float16).reshape(1000, 5) + proposal_mask = np.fromfile(mask_file, dtype=np.int8).reshape(1000) + + return proposal, proposal_mask + +def get_img_metas(imgSize): + org_width, org_height = imgSize + h_scale = 576 / org_height + w_scale = 960 / org_width + + return np.array([576, 960, h_scale, w_scale]) + +def get_gt_box(img_file, label_path): + label_file = os.path.join(label_path, img_file.replace("jpg", "txt")) + file = open(label_file) + lines = file.readlines() + gt_boxs = [] + for line in lines: + label_info = line.split(",") + print(label_info) + gt_boxs.append([int(label_info[0]), int(label_info[1]), int(label_info[2]), int(label_info[3])]) + #print(line) + #print(gt_boxs) + + return gt_boxs +def ctpn_infer_test(dataset_path='', result_path='', label_path=''): + output_dir = "./output/" + output_img_dir = "./output_img/" + img_files = os.listdir(dataset_path) + + for file in img_files: + print("processing image: ", file) + from PIL import Image, ImageDraw + img = Image.open(dataset_path + '/' + file) + proposal, proposal_mask = get_pred(file, result_path) + + img_size = img.size + img_metas = get_img_metas(img_size) + all_box_tmp = proposal + all_mask_tmp = np.expand_dims(proposal_mask, axis=1) + + using_boxes_mask = all_box_tmp * all_mask_tmp + textsegs = using_boxes_mask[:, 0:4].astype(np.float32) + scores = using_boxes_mask[:, 4].astype(np.float32) + shape = img_metas[:2].astype(np.int32) + + bboxes = detect(textsegs, scores[:, np.newaxis], shape) + + draw = ImageDraw.Draw(img) + image_h = img_metas[2] + image_w = img_metas[3] + gt_boxs = get_gt_box(file, label_path) + for gt_box in gt_boxs: + gt_x1 = gt_box[0] + gt_y1 = gt_box[1] + gt_x2 = gt_box[2] + gt_y2 = gt_box[3] + draw.line([(gt_x1, gt_y1), (gt_x1, gt_y2), (gt_x2, gt_y2), (gt_x2, gt_y1), (gt_x1, gt_y1)],\ + fill='green', width=2) + file_name = "res_" + file.replace("jpg", "txt") + output_file = os.path.join(output_dir, file_name) + f = open(output_file, 'w') + for bbox in bboxes: + x1 = bbox[0] / image_w + y1 = bbox[1] / image_h + x2 = bbox[2] / image_w + y2 = bbox[3] / image_h + draw.line([(x1, y1), (x1, y2), (x2, y2), (x2, y1), (x1, y1)], fill='red', width=2) + str_tmp = str(int(x1)) + "," + str(int(y1)) + "," + str(int(x2)) + "," + str(int(y2)) + f.write(str_tmp) + f.write("\n") + f.close() + img.save(output_img_dir + file) + +if __name__ == '__main__': + ctpn_infer_test(args_opt.dataset_path, args_opt.result_path, args_opt.label_path) diff --git a/model_zoo/official/cv/ctpn/scripts/run_infer_310.sh b/model_zoo/official/cv/ctpn/scripts/run_infer_310.sh new file mode 100755 index 0000000000..a3dd05cbc8 --- /dev/null +++ b/model_zoo/official/cv/ctpn/scripts/run_infer_310.sh @@ -0,0 +1,123 @@ +#!/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 [[ $# -lt 3 || $# -gt 4 ]]; then + echo "Usage: sh run_infer_310.sh [MODEL_PATH] [DATA_PATH] [LABEL_PATH] [DEVICE_ID] + DEVICE_ID is optional, it can be set by environment variable device_id, otherwise the value is zero" +exit 1 +fi + +get_real_path(){ + if [ "${1:0:1}" == "/" ]; then + echo "$1" + else + echo "$(realpath -m $PWD/$1)" + fi +} + +model=$(get_real_path $1) +data_path=$(get_real_path $2) +label_path=$(get_real_path $3) + +if [ $# == 4 ]; then + device_id=$4 +elif [ $# == 3 ]; then + if [ -z $device_id ]; then + device_id=0 + else + device_id=$device_id + fi +fi + +echo $model +echo $data_path +echo $label_path +echo $device_id + +export ASCEND_HOME=/usr/local/Ascend/ +if [ -d ${ASCEND_HOME}/ascend-toolkit ]; then + export PATH=$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin:$ASCEND_HOME/ascend-toolkit/latest/atc/bin:$PATH + export LD_LIBRARY_PATH=/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=${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/atc/ccec_compiler/bin:$ASCEND_HOME/atc/bin:$PATH + export LD_LIBRARY_PATH=/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/atc/python/site-packages:$PYTHONPATH + export ASCEND_OPP_PATH=$ASCEND_HOME/opp +fi + +function compile_app() +{ + cd ../ascend310_infer + if [ -f "Makefile" ]; then + make clean + fi + sh build.sh &> build.log + + if [ $? -ne 0 ]; then + echo "compile app code failed" + exit 1 + fi + cd - +} + +function infer() +{ + 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 --model_path=$model --dataset_path=$data_path --device_id=$device_id &> infer.log + + if [ $? -ne 0 ]; then + echo "execute inference failed" + exit 1 + fi +} + +function cal_acc() +{ + if [ -d output ]; then + rm -rf ./output + fi + if [ -d output_img ]; then + rm -rf ./output_img + fi + mkdir output + mkdir output_img + python ../postprocess.py --dataset_path=$data_path --result_path=result_Files --label_path=$label_path &> acc.log + if [ $? -ne 0 ]; then + echo "calculate accuracy failed" + exit 1 + fi + + if [ -f "ubmit.zip" ]; then + rm -f submit.zip + fi + cd output + zip -r ../submit.zip *.txt + cd - +} + +compile_app +infer +cal_acc diff --git a/model_zoo/official/cv/ctpn/src/ctpn.py b/model_zoo/official/cv/ctpn/src/ctpn.py index 3656a62c99..1b8fb44fe5 100644 --- a/model_zoo/official/cv/ctpn/src/ctpn.py +++ b/model_zoo/official/cv/ctpn/src/ctpn.py @@ -146,3 +146,13 @@ class CTPN(nn.Cell): def get_anchors(self, featmap_size): anchors = self.anchor_generator.grid_anchors(featmap_size) return Tensor(anchors, mstype.float16) + +class CTPN_Infer(nn.Cell): + def __init__(self, config): + super(CTPN_Infer, self).__init__() + self.network = CTPN(config, is_training=False) + self.network.set_train(False) + + def construct(self, img_data): + output = self.network(img_data, None, None, None, None) + return output diff --git a/model_zoo/official/recommend/naml/README.md b/model_zoo/official/recommend/naml/README.md index 788aa69ceb..08716465c4 100644 --- a/model_zoo/official/recommend/naml/README.md +++ b/model_zoo/official/recommend/naml/README.md @@ -55,6 +55,7 @@ You can download the dataset and put the directory in structure as follows: ├── scripts │ ├──run_train.sh # shell script for training │ ├──run_eval.sh # shell script for evaluation + │ ├──run_infer_310.sh # shell script for 310 inference ├── src │ ├──option.py # parse args │ ├──callback.py # callback file @@ -62,9 +63,11 @@ You can download the dataset and put the directory in structure as follows: │ ├──naml.py # NAML architecture │ ├──config.py # config file │ ├──utils.py # utils to load ckpt_file for fine tune or incremental learn + ├──ascend310_infer #application for 310 inference ├── train.py # training script ├── eval.py # evaluation script ├── export.py # export mindir script + └──postprogress.py # post process for 310 inference ``` ## [Training process](#contents) @@ -95,7 +98,7 @@ bash run_eval.sh [PLATFORM] [DEVICE_ID] [DATASET] [DATASET_PATH] [CHECKPOINT_PAT python export.py --platform [PLATFORM] --checkpoint_path [CHECKPOINT_PATH] --file_format [EXPORT_FORMAT] --batch_size [BATCH_SIZE] ``` -- `EXPORT_FORMAT` should be in ["AIR", "ONNX", "MINDIR"] +- `EXPORT_FORMAT` should be in ["AIR", "MINDIR"] # [Model Description](#contents) @@ -130,6 +133,19 @@ python export.py --platform [PLATFORM] --checkpoint_path [CHECKPOINT_PATH] --fil | outputs | probability | | Accuracy | AUC: 0.66 | +### Inference on Ascend310 Performance + +| Parameters | Ascend | +| ------------------- | --------------------------- | +| Model Version | NAML | +| Resource | Ascend 310 | +| Uploaded Date | 03/13/2021 (month/day/year) | +| MindSpore Version | 1.2.0 | +| Dataset | MINDlarge | +| batch_size | 64 | +| outputs | probability | +| Accuracy | AUC: 0.667 | + # [Description of Random Situation](#contents) diff --git a/model_zoo/official/recommend/naml/ascend310_infer/CMakeLists.txt b/model_zoo/official/recommend/naml/ascend310_infer/CMakeLists.txt new file mode 100644 index 0000000000..9027e4a6b0 --- /dev/null +++ b/model_zoo/official/recommend/naml/ascend310_infer/CMakeLists.txt @@ -0,0 +1,64 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. + +# CMake lowest version requirement +cmake_minimum_required(VERSION 3.5.1) + +# project information +project(ACL_RESNET50) + +find_package(gflags REQUIRED) +include_directories(${gflags_INCLUDE_DIR}) + +# Compile options +add_compile_options(-std=c++11 -g -O0) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "../out") +set(CMAKE_CXX_FLAGS_DEBUG "-fPIC -O0 -g -Wall") +set(CMAKE_CXX_FLAGS_RELEASE "-fPIC -O0 -g -Wall") + +set(INC_PATH $ENV{DDK_PATH}) + +if(NOT DEFINED ENV{DDK_PATH}) + set(INC_PATH "/usr/local/Ascend") + message(STATUS "set default INC_PATH: ${INC_PATH}") +else() + message(STATUS "env INC_PATH: ${INC_PATH}") +endif() + +set(LIB_PATH $ENV{NPU_HOST_LIB}) + +if(NOT DEFINED ENV{NPU_HOST_LIB}) + set(LIB_PATH "/usr/local/Ascend/acllib/lib64/stub/") + message(STATUS "set default LIB_PATH: ${LIB_PATH}") +else() + message(STATUS "env LIB_PATH: ${LIB_PATH}") +endif() + +# Header path +include_directories( + ${INC_PATH}/acllib/include/ + ../include/ +) + +if(target STREQUAL "Simulator_Function") + add_compile_options(-DFUNC_SIM) +endif() + +# add host lib path +link_directories( + ${LIB_PATH} +) + +add_executable(main + ./src/utils.cpp + ./src/model_process.cpp + ./src/sample_process.cpp + ./src/main.cpp) + +if(target STREQUAL "Simulator_Function") + target_link_libraries(main funcsim) +else() + target_link_libraries(main ascendcl stdc++ gflags) +endif() + +install(TARGETS main DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) diff --git a/model_zoo/official/recommend/naml/ascend310_infer/build.sh b/model_zoo/official/recommend/naml/ascend310_infer/build.sh new file mode 100644 index 0000000000..4ded723959 --- /dev/null +++ b/model_zoo/official/recommend/naml/ascend310_infer/build.sh @@ -0,0 +1,23 @@ +#!/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 + mkdir out +fi +cd out +export CXXFLAGS=-D_GLIBCXX_USE_CXX11_ABI=0 +cmake .. -DCMAKE_CXX_COMPILER=g++ -DCMAKE_SKIP_RPATH=TRUE +make diff --git a/model_zoo/official/recommend/naml/ascend310_infer/inc/model_process.h b/model_zoo/official/recommend/naml/ascend310_infer/inc/model_process.h new file mode 100644 index 0000000000..c8eae82148 --- /dev/null +++ b/model_zoo/official/recommend/naml/ascend310_infer/inc/model_process.h @@ -0,0 +1,94 @@ +/** + * 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. + */ + +#pragma once +#include +#include +#include +#include +#include "./utils.h" +#include "acl/acl.h" + +class ModelProcess { + public: + ModelProcess() = default; + ModelProcess(const std::string &inputDataPath, const std::string &idFilePath, uint32_t batchSize); + + ~ModelProcess(); + + Result LoadModelFromFileWithMem(const char *modelPath); + + void Unload(); + + Result CreateDesc(); + + void DestroyDesc(); + + void DestroyInput(); + + Result CreateOutput(); + + void DestroyOutput(); + + Result Execute(uint32_t index); + + void DumpModelOutputResult(std::string fileName); + + void OutputModelResult(); + Result CreateInput(); + Result CpyFileToDevice(std::string fileName, uint32_t inputNum); + void CpyOutputFromDeviceToHost(uint32_t index, uint32_t batchSize); + std::map GetResult(); + std::vector GetOutputSize(); + std::vector GetInputSize(); + Result ExecuteWithFile(uint32_t fileNum); + Result CpyDataToDevice(void *data, uint32_t len, uint32_t inputNum); + std::string GetInputDataPath(); + std::string GetCostTimeInfo(); + void DestroyResource(); + std::vector> ReadInputFiles(std::vector> inputFiles, + size_t inputSize, std::vector> *fileSize); + Result ReadIdFiles(); + Result InitResource(); + uint32_t ReadFiles(); + + private: + uint32_t modelId_; + std::map costTime_map_; + size_t modelMemSize_; + size_t modelWeightSize_; + void *modelMemPtr_; + void *modelWeightPtr_; + uint32_t batchSize_; + bool loadFlag_; // model load flag + aclmdlDesc *modelDesc_; + aclmdlDataset *input_; + uint32_t inputNum_; + std::vector inputBuffSize_; + aclmdlDataset *output_; + uint32_t outputNum_; + std::vector outputBuffSize_; + + std::map result_; + std::vector resultMem_; + std::vector fileBuffMem_; + std::string inputDataPath_; + std::string idFilePath_; + std::vector> fileBuff_; + std::vector> fileSize_; + std::vector> ids_; +}; + diff --git a/model_zoo/official/recommend/naml/ascend310_infer/inc/sample_process.h b/model_zoo/official/recommend/naml/ascend310_infer/inc/sample_process.h new file mode 100644 index 0000000000..85de2d7786 --- /dev/null +++ b/model_zoo/official/recommend/naml/ascend310_infer/inc/sample_process.h @@ -0,0 +1,71 @@ +/** + * 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. + */ + +#pragma once +#include +#include +#include +#include +#include + +#include "acl/acl.h" +#include "./utils.h" +#include "./model_process.h" + +class SampleProcess { + public: + SampleProcess(); + SampleProcess(uint32_t deviceId, uint32_t threadNum); + + ~SampleProcess(); + + Result InitResource(); + + Result Process(const std::vector &omPaths, + const std::vector &inputDataPaths, + const std::vector &inputIdPaths, + const std::string &browsedNewsPath, + uint32_t batchSize); + Result CreateModelProcessInstance(std::vector omPaths, std::vector inputDataPaths, + std::vector inputIdPaths, uint32_t batchSize); + Result GetPred(uint32_t fileNum); + int WriteResult(const std::string& imageFile, std::vector result, uint32_t size); + std::vector GetModelExecCostTimeInfo(); + std::vector>> ReadHistory(std::vector historyFile, uint32_t batchSize); + Result ReadBrowsedFile(const std::string &browsedNewsPath, std::vector userIdFiles, + std::vector> *usersIds, std::vector> *candidateNewsIds); + uint32_t ReadBrowsedData(const std::string &browsedNewsPath); + void GetResult(uint32_t startPos, uint32_t endPos, + std::map newsEncodeResult, + std::map userEncodeResult); + + private: + void DestroyResource(); + + int32_t deviceId_; + aclrtContext context_; + aclrtStream stream_; + std::map> modelProcessContainer_; + std::map secondModelCostTime_map_; + std::map thirdModelCostTime_map_; + std::map totalCostTime_map_; + std::vector> usersIds_; + std::vector> candidateNewsIds_; + std::vector userIdFiles_; + uint32_t threadNum_; + std::mutex mtx_; +}; + diff --git a/model_zoo/official/recommend/naml/ascend310_infer/inc/utils.h b/model_zoo/official/recommend/naml/ascend310_infer/inc/utils.h new file mode 100644 index 0000000000..07048cb025 --- /dev/null +++ b/model_zoo/official/recommend/naml/ascend310_infer/inc/utils.h @@ -0,0 +1,51 @@ +/** + * 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. + */ + +#pragma once +#include +#include +#include +#include + +#define INFO_LOG(fmt, args...) fprintf(stdout, "[INFO] " fmt "\n", ##args) +#define WARN_LOG(fmt, args...) fprintf(stdout, "[WARN] " fmt "\n", ##args) +#define ERROR_LOG(fmt, args...) fprintf(stdout, "[ERROR] " fmt "\n", ##args) + +typedef enum Result { + SUCCESS = 0, + FAILED = 1 +} Result; + +class Utils { + public: + static void *GetDeviceBufferOfFile(std::string fileName, uint32_t *fileSize); + + static void *ReadBinFile(std::string fileName, uint32_t *fileSize); + + static std::vector > GetAllInputData(std::string dir_name); + + static DIR *OpenDir(std::string dir_name); + + static std::string RealPath(std::string path); + + static std::vector GetAllBins(std::string dir_name); + + static Result ReadFileToVector(std::string newsIdFileName, uint32_t batchSize, std::vector *newsId); + static Result ReadFileToVector(std::string newsIdFileName, std::vector *newsId); + static Result ReadFileToVector(std::string newsIdFileName, uint32_t batchSize, uint32_t count, + std::vector> *newsId); +}; +#pragma once diff --git a/model_zoo/official/recommend/naml/ascend310_infer/src/main.cpp b/model_zoo/official/recommend/naml/ascend310_infer/src/main.cpp new file mode 100644 index 0000000000..ab259b32a9 --- /dev/null +++ b/model_zoo/official/recommend/naml/ascend310_infer/src/main.cpp @@ -0,0 +1,84 @@ +/** + * 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 +#include +#include +#include +#include +#include "../inc/utils.h" +#include "../inc/sample_process.h" + +bool g_isDevice = false; + +DEFINE_string(news_om_path, "../model/relu_double_geir.om", "om model path."); +DEFINE_string(user_om_path, "../model/relu_double_geir.om", "om model path."); +DEFINE_string(news_dataset_path, "../data", "input data dir"); +DEFINE_string(user_dataset_path, "../data", "input data dir"); +DEFINE_string(newsid_data_path, "../data", "input data dir"); +DEFINE_string(userid_data_path, "../data", "input data dir"); +DEFINE_string(browsed_news_path, "../data", "input data dir"); +DEFINE_int32(batch_size, 16, "batch size"); +DEFINE_int32(device_id, 0, "device id"); +DEFINE_int32(thread_num, 8, "thread num"); + +int main(int argc, char** argv) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + std::cout << "news OM File Path :" << FLAGS_news_om_path << std::endl; + std::cout << "user OM File Path :" << FLAGS_user_om_path << std::endl; + std::cout << "news Dataset Path :" << FLAGS_news_dataset_path << std::endl; + std::cout << "user Dataset Path :" << FLAGS_user_dataset_path << std::endl; + std::cout << "browsed_news_path Path :" << FLAGS_browsed_news_path << std::endl; + std::cout << "batch size :" << FLAGS_batch_size << std::endl; + std::cout << "device id :" << FLAGS_device_id << std::endl; + std::cout << "thread num :" << FLAGS_thread_num << std::endl; + + std::vector omPaths; + std::vector datasetPaths; + std::vector idsPaths; + omPaths.emplace_back(FLAGS_news_om_path); + omPaths.emplace_back(FLAGS_user_om_path); + datasetPaths.emplace_back(FLAGS_news_dataset_path); + datasetPaths.emplace_back(FLAGS_user_dataset_path); + idsPaths.emplace_back(FLAGS_newsid_data_path); + idsPaths.emplace_back(FLAGS_userid_data_path); + + SampleProcess processSample(FLAGS_device_id, FLAGS_thread_num); + Result ret = processSample.InitResource(); + if (ret != SUCCESS) { + ERROR_LOG("sample init resource failed"); + return FAILED; + } + + ret = processSample.Process(omPaths, datasetPaths, idsPaths, FLAGS_browsed_news_path, FLAGS_batch_size); + if (ret != SUCCESS) { + ERROR_LOG("sample process failed"); + return FAILED; + } + + std::vector costTime = processSample.GetModelExecCostTimeInfo(); + std::string file_name = "./time_Result" + std::string("/test_perform_static.txt"); + std::ofstream file_stream(file_name.c_str(), std::ios::trunc); + for (auto cost : costTime) { + std::cout << cost << std::endl; + file_stream << cost << std::endl; + } + + file_stream.close(); + + INFO_LOG("execute sample success"); + return SUCCESS; +} diff --git a/model_zoo/official/recommend/naml/ascend310_infer/src/model_process.cpp b/model_zoo/official/recommend/naml/ascend310_infer/src/model_process.cpp new file mode 100644 index 0000000000..47f66793db --- /dev/null +++ b/model_zoo/official/recommend/naml/ascend310_infer/src/model_process.cpp @@ -0,0 +1,598 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include "../inc/utils.h" +#include "../inc/model_process.h" + +extern bool g_isDevice; + +ModelProcess::ModelProcess(const std::string &inputDataPath, const std::string &idFilePath, uint32_t batchSize): + modelId_(0), modelMemSize_(0), modelWeightSize_(0), modelMemPtr_(nullptr), + modelWeightPtr_(nullptr), loadFlag_(false), modelDesc_(nullptr), output_(nullptr), + inputDataPath_(inputDataPath), input_(nullptr), batchSize_(batchSize), + idFilePath_(idFilePath), inputNum_(0), outputNum_(0) { +} + +ModelProcess::~ModelProcess() { + Unload(); + DestroyResource(); +} + +Result ModelProcess::InitResource() { + Result ret = CreateDesc(); + if (ret != SUCCESS) { + ERROR_LOG("create model description failed"); + return FAILED; + } + + ret = CreateOutput(); + if (ret != SUCCESS) { + ERROR_LOG("create model output failed"); + return FAILED; + } + + ret = CreateInput(); + if (ret != SUCCESS) { + ERROR_LOG("create model input failed"); + return FAILED; + } + + ret = ReadIdFiles(); + if (ret != SUCCESS) { + ERROR_LOG("read id files failed"); + return FAILED; + } +} +void ModelProcess::DestroyResource() { + DestroyDesc(); + DestroyInput(); + DestroyOutput(); + for (auto addr : resultMem_) { + if (addr != nullptr) { + aclrtFreeHost(addr); + } + } + + for (auto addr : fileBuffMem_) { + if (addr != nullptr) { + aclrtFreeHost(addr); + } + } + return; +} + +Result ModelProcess::LoadModelFromFileWithMem(const char *modelPath) { + if (loadFlag_) { + ERROR_LOG("has already loaded a model"); + return FAILED; + } + + aclError ret = aclmdlQuerySize(modelPath, &modelMemSize_, &modelWeightSize_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("query model failed, model file is %s", modelPath); + return FAILED; + } + + ret = aclrtMalloc(&modelMemPtr_, modelMemSize_, ACL_MEM_MALLOC_HUGE_FIRST); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("malloc buffer for mem failed, require size is %zu", modelMemSize_); + return FAILED; + } + + ret = aclrtMalloc(&modelWeightPtr_, modelWeightSize_, ACL_MEM_MALLOC_HUGE_FIRST); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("malloc buffer for weight failed, require size is %zu", modelWeightSize_); + return FAILED; + } + + ret = aclmdlLoadFromFileWithMem(modelPath, &modelId_, modelMemPtr_, + modelMemSize_, modelWeightPtr_, modelWeightSize_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("load model from file failed, model file is %s", modelPath); + return FAILED; + } + + loadFlag_ = true; + INFO_LOG("load model %s success", modelPath); + return SUCCESS; +} + +Result ModelProcess::CreateDesc() { + modelDesc_ = aclmdlCreateDesc(); + if (modelDesc_ == nullptr) { + ERROR_LOG("create model description failed"); + return FAILED; + } + + aclError ret = aclmdlGetDesc(modelDesc_, modelId_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("get model description failed"); + return FAILED; + } + + INFO_LOG("create model description success"); + + return SUCCESS; +} + +void ModelProcess::DestroyDesc() { + if (modelDesc_ != nullptr) { + (void)aclmdlDestroyDesc(modelDesc_); + modelDesc_ = nullptr; + } +} + +Result ModelProcess::CreateInput() { + if (modelDesc_ == nullptr) { + ERROR_LOG("no model description, create output failed"); + return FAILED; + } + + input_ = aclmdlCreateDataset(); + if (input_ == nullptr) { + ERROR_LOG("can't create dataset, create input failed"); + return FAILED; + } + + size_t inputSize = aclmdlGetNumInputs(modelDesc_); + inputNum_ = inputSize; + for (size_t i = 0; i < inputSize; ++i) { + size_t buffer_size = aclmdlGetInputSizeByIndex(modelDesc_, i); + inputBuffSize_.emplace_back(buffer_size); + + void *inputBuffer = nullptr; + aclError ret = aclrtMalloc(&inputBuffer, buffer_size, ACL_MEM_MALLOC_NORMAL_ONLY); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("can't malloc buffer, size is %zu, create input failed", buffer_size); + return FAILED; + } + + aclDataBuffer* inputData = aclCreateDataBuffer(inputBuffer, buffer_size); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("can't create data buffer, create input failed"); + aclrtFree(inputBuffer); + return FAILED; + } + + ret = aclmdlAddDatasetBuffer(input_, inputData); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("can't add data buffer, create output failed"); + aclrtFree(inputBuffer); + aclDestroyDataBuffer(inputData); + return FAILED; + } + } + + INFO_LOG("create model input success"); + return SUCCESS; +} + +void ModelProcess::DestroyInput() { + if (input_ == nullptr) { + return; + } + + for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(input_); ++i) { + aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(input_, i); + aclDestroyDataBuffer(dataBuffer); + } + aclmdlDestroyDataset(input_); + input_ = nullptr; +} + +Result ModelProcess::CreateOutput() { + if (modelDesc_ == nullptr) { + ERROR_LOG("no model description, create output failed"); + return FAILED; + } + + output_ = aclmdlCreateDataset(); + if (output_ == nullptr) { + ERROR_LOG("can't create dataset, create output failed"); + return FAILED; + } + + size_t outputSize = aclmdlGetNumOutputs(modelDesc_); + outputNum_ = outputSize; + for (size_t i = 0; i < outputSize; ++i) { + size_t buffer_size = aclmdlGetOutputSizeByIndex(modelDesc_, i); + outputBuffSize_.emplace_back(buffer_size); + + void *outputBuffer = nullptr; + aclError ret = aclrtMalloc(&outputBuffer, buffer_size, ACL_MEM_MALLOC_NORMAL_ONLY); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("can't malloc buffer, size is %zu, create output failed", buffer_size); + return FAILED; + } + + aclDataBuffer* outputData = aclCreateDataBuffer(outputBuffer, buffer_size); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("can't create data buffer, create output failed"); + aclrtFree(outputBuffer); + return FAILED; + } + + ret = aclmdlAddDatasetBuffer(output_, outputData); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("can't add data buffer, create output failed"); + aclrtFree(outputBuffer); + aclDestroyDataBuffer(outputData); + return FAILED; + } + } + + INFO_LOG("create model output success"); + return SUCCESS; +} + +void ModelProcess::DumpModelOutputResult(std::string fileName) { + std::size_t dex = fileName.find_last_of("."); + std::string outputFile = fileName.erase(dex); + std::string Path = "../result_Files"; + + // stringstream ss; + size_t outputNum = aclmdlGetDatasetNumBuffers(output_); + static int executeNum = 0; + for (size_t i = 0; i < outputNum; ++i) { + std::stringstream ss; + ss << Path <<"/output" << "_" << i << "_in_" << outputFile << ".bin"; + std::string outputFileName = ss.str(); + FILE *file = fopen(outputFileName.c_str(), "wb"); + if (file) { + aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(output_, i); + void* data = aclGetDataBufferAddr(dataBuffer); + uint32_t len = aclGetDataBufferSizeV2(dataBuffer); + + void* outHostData = NULL; + aclError ret = ACL_ERROR_NONE; + if (!g_isDevice) { + ret = aclrtMallocHost(&outHostData, len); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("aclrtMallocHost failed, ret[%d]", ret); + return; + } + + ret = aclrtMemcpy(outHostData, len, data, len, ACL_MEMCPY_DEVICE_TO_HOST); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("aclrtMemcpy failed, ret[%d]", ret); + (void)aclrtFreeHost(outHostData); + return; + } + + fwrite(outHostData, len, sizeof(char), file); + + ret = aclrtFreeHost(outHostData); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("aclrtFreeHost failed, ret[%d]", ret); + return; + } + } else { + fwrite(data, len, sizeof(char), file); + } + fclose(file); + file = nullptr; + } else { + ERROR_LOG("create output file [%s] failed", outputFileName.c_str()); + return; + } + } + + INFO_LOG("dump data success"); + return; +} + +void ModelProcess::OutputModelResult() { + for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(output_); ++i) { + aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(output_, i); + void* data = aclGetDataBufferAddr(dataBuffer); + uint32_t len = aclGetDataBufferSizeV2(dataBuffer); + + void *outHostData = NULL; + aclError ret = ACL_ERROR_NONE; + float *outData = NULL; + if (!g_isDevice) { + ret = aclrtMallocHost(&outHostData, len); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("aclrtMallocHost failed, ret[%d]", ret); + return; + } + + ret = aclrtMemcpy(outHostData, len, data, len, ACL_MEMCPY_DEVICE_TO_HOST); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("aclrtMemcpy failed, ret[%d]", ret); + return; + } + + outData = reinterpret_cast(outHostData); + } else { + outData = reinterpret_cast(data); + } + std::map > resultMap; + for (unsigned int j = 0; j < len / sizeof(float); ++j) { + resultMap[*outData] = j; + outData++; + } + + int cnt = 0; + for (auto it = resultMap.begin(); it != resultMap.end(); ++it) { + // print top 5 + if (++cnt > 5) { + break; + } + + INFO_LOG("top %d: index[%d] value[%lf]", cnt, it->second, it->first); + } + if (!g_isDevice) { + ret = aclrtFreeHost(outHostData); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("aclrtFreeHost failed, ret[%d]", ret); + return; + } + } + } + + INFO_LOG("output data success"); + return; +} + +void ModelProcess::DestroyOutput() { + if (output_ == nullptr) { + return; + } + + for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(output_); ++i) { + aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(output_, i); + void* data = aclGetDataBufferAddr(dataBuffer); + (void)aclrtFree(data); + (void)aclDestroyDataBuffer(dataBuffer); + } + + (void)aclmdlDestroyDataset(output_); + output_ = nullptr; +} + +Result ModelProcess::CpyFileToDevice(std::string fileName, uint32_t inputNum) { + uint32_t inputHostBuffSize = 0; + void* inputHostBuff = Utils::ReadBinFile(fileName, &inputHostBuffSize); + if (inputHostBuff == nullptr) { + return FAILED; + } + aclDataBuffer *inBufferDev = aclmdlGetDatasetBuffer(input_, inputNum); + void*p_batchDst = aclGetDataBufferAddr(inBufferDev); + aclrtMemset(p_batchDst, inputHostBuffSize, 0, inputHostBuffSize); + aclError ret = aclrtMemcpy(p_batchDst, inputHostBuffSize, inputHostBuff, inputHostBuffSize, + ACL_MEMCPY_HOST_TO_DEVICE); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("memcpy failed. device buffer size is %u, input host buffer size is %u", + inputHostBuffSize, inputHostBuffSize); + aclrtFreeHost(inputHostBuff); + return FAILED; + } + aclrtFreeHost(inputHostBuff); + return SUCCESS; +} + +Result ModelProcess::CpyDataToDevice(void *data, uint32_t len, uint32_t inputNum) { + if (len != inputBuffSize_[inputNum]) { + return FAILED; + } + aclDataBuffer *inBufferDev = aclmdlGetDatasetBuffer(input_, inputNum); + void*p_batchDst = aclGetDataBufferAddr(inBufferDev); + aclrtMemset(p_batchDst, len, 0, len); + aclError ret = aclrtMemcpy(p_batchDst, len, data, len, ACL_MEMCPY_HOST_TO_DEVICE); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("memcpy failed. device buffer size is %u, input host buffer size is %u", + len, len); + return FAILED; + } + return SUCCESS; +} + +void ModelProcess::CpyOutputFromDeviceToHost(uint32_t index, uint32_t batchSize) { + size_t outputNum = aclmdlGetDatasetNumBuffers(output_); + + for (size_t i = 0; i < outputNum; ++i) { + aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(output_, i); + void* data = aclGetDataBufferAddr(dataBuffer); + uint32_t bufferSize = aclGetDataBufferSizeV2(dataBuffer); + + void* outHostData = NULL; + aclError ret = ACL_ERROR_NONE; + ret = aclrtMallocHost(&outHostData, bufferSize); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("aclrtMallocHost failed, ret[%d]", ret); + return; + } + resultMem_.emplace_back(outHostData); + ret = aclrtMemcpy(outHostData, bufferSize, data, bufferSize, ACL_MEMCPY_DEVICE_TO_HOST); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("aclrtMemcpy failed, ret[%d]", ret); + (void)aclrtFreeHost(outHostData); + return; + } + + uint32_t len = (uint32_t)bufferSize/batchSize; + for (size_t j = 0; j < batchSize; j++) { + result_.emplace(ids_[index][j], reinterpret_cast(outHostData) + (j * len)); + } + } + return; +} + +std::vector> ModelProcess::ReadInputFiles(std::vector> inputFiles, + size_t inputSize, + std::vector> *fileSize) { + size_t fileNum = inputFiles[0].size(); + std::vector> buff(fileNum); + if (inputFiles.size() != inputSize) { + std::cout << "the num of input file is incorrect" << std::endl; + return buff; + } + + void* inputHostBuff; + uint32_t inputHostBuffSize = 0; + for (int i = 0; i < inputSize; ++i) { + for (int j = 0; j < fileNum; ++j) { + inputHostBuff = Utils::ReadBinFile(inputFiles[i][j], &inputHostBuffSize); + buff[i].emplace_back(inputHostBuff); + fileBuffMem_.emplace_back(inputHostBuff); + (*fileSize)[i].emplace_back(inputHostBuffSize); + } + } + + return buff; +} + +Result ModelProcess::ReadIdFiles() { + std::vector idFiles = Utils::GetAllBins(idFilePath_); + + for (int i = 0; i < idFiles.size(); ++i) { + std::vector ids; + Utils::ReadFileToVector(idFiles[i], batchSize_, &ids); + ids_.emplace_back(ids); + } + return SUCCESS; +} + +uint32_t ModelProcess::ReadFiles() { + size_t inputSize = aclmdlGetNumInputs(modelDesc_); + std::vector> fileSize(inputSize); + std::vector> inputFiles = Utils::GetAllInputData(inputDataPath_); + + fileBuff_ = ReadInputFiles(inputFiles, inputSize, &fileSize); + uint32_t fileNum = inputFiles[0].size(); + fileSize_ = fileSize; + return fileNum; +} + +Result ModelProcess::ExecuteWithFile(uint32_t fileNum) { + for (size_t index = 0; index < fileNum; ++index) { + struct timeval start; + struct timeval end; + double startTime_ms; + double endTime_ms; + gettimeofday(&start, NULL); + void* picDevBuffer = nullptr; + int pathIndex = 0; + for (auto i = 0; i < inputNum_; ++i) { + CpyDataToDevice(fileBuff_[i][index], fileSize_[i][index], i); + } + + aclError ret = aclmdlExecute(modelId_, input_, output_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("execute model failed, modelId is %u", modelId_); + return FAILED; + } + + CpyOutputFromDeviceToHost(index, batchSize_); + 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(startTime_ms, endTime_ms)); + } + return SUCCESS; +} + +Result ModelProcess::Execute(uint32_t index) { + struct timeval start; + struct timeval end; + double startTime_ms; + double endTime_ms; + + gettimeofday(&start, NULL); + aclError ret = aclmdlExecute(modelId_, input_, output_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("execute model failed, modelId is %u", modelId_); + return FAILED; + } + + CpyOutputFromDeviceToHost(index, batchSize_); + 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(startTime_ms, endTime_ms)); + return SUCCESS; +} + +std::map ModelProcess::GetResult() { + return result_; +} + +void ModelProcess::Unload() { + if (!loadFlag_) { + WARN_LOG("no model had been loaded, unload failed"); + return; + } + + aclError ret = aclmdlUnload(modelId_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("unload model failed, modelId is %u", modelId_); + } + + if (modelDesc_ != nullptr) { + (void)aclmdlDestroyDesc(modelDesc_); + modelDesc_ = nullptr; + } + + if (modelMemPtr_ != nullptr) { + aclrtFree(modelMemPtr_); + modelMemPtr_ = nullptr; + modelMemSize_ = 0; + } + + if (modelWeightPtr_ != nullptr) { + aclrtFree(modelWeightPtr_); + modelWeightPtr_ = nullptr; + modelWeightSize_ = 0; + } + + loadFlag_ = false; + INFO_LOG("unload model success, modelId is %u", modelId_); +} + +std::vector ModelProcess::GetInputSize() { + return inputBuffSize_; +} + +std::vector ModelProcess::GetOutputSize() { + return outputBuffSize_; +} + +std::string ModelProcess::GetInputDataPath() { + return inputDataPath_; +} + +std::string ModelProcess::GetCostTimeInfo() { + double average = 0.0; + int infer_cnt = 0; + char tmpCh[256] = {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; + snprintf(tmpCh, sizeof(tmpCh), "first model latency %4.3f ms; count %d\n", average, infer_cnt); + + return std::string(tmpCh); +} diff --git a/model_zoo/official/recommend/naml/ascend310_infer/src/sample_process.cpp b/model_zoo/official/recommend/naml/ascend310_infer/src/sample_process.cpp new file mode 100644 index 0000000000..17c383e92a --- /dev/null +++ b/model_zoo/official/recommend/naml/ascend310_infer/src/sample_process.cpp @@ -0,0 +1,354 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acl/acl.h" +#include "../inc/utils.h" +#include "../inc/model_process.h" +#include "../inc/sample_process.h" + +extern bool g_isDevice; + +SampleProcess::SampleProcess() :deviceId_(0), context_(nullptr), stream_(nullptr), threadNum_(0) {} + +SampleProcess::SampleProcess(uint32_t deviceId, uint32_t threadNum): + deviceId_(deviceId), threadNum_(threadNum), context_(nullptr), stream_(nullptr) {} + +SampleProcess::~SampleProcess() { + DestroyResource(); +} + +Result SampleProcess::InitResource() { + aclError ret = aclInit(nullptr); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("acl init failed"); + return FAILED; + } + INFO_LOG("acl init success"); + + ret = aclrtSetDevice(deviceId_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("acl open device %d failed", deviceId_); + return FAILED; + } + INFO_LOG("open device %d success", deviceId_); + + // create context (set current) + ret = aclrtCreateContext(&context_, deviceId_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("acl create context failed"); + return FAILED; + } + INFO_LOG("create context success"); + + // create stream + ret = aclrtCreateStream(&stream_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("acl create stream failed"); + return FAILED; + } + INFO_LOG("create stream success"); + + // get run mode + aclrtRunMode runMode; + ret = aclrtGetRunMode(&runMode); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("acl get run mode failed"); + return FAILED; + } + g_isDevice = (runMode == ACL_DEVICE); + INFO_LOG("get run mode success"); + + return SUCCESS; +} + +Result SampleProcess::CreateModelProcessInstance(std::vector omPaths, + std::vector inputDataPaths, + std::vector inputIdPaths, + uint32_t batchSize) { + for (int i = 0; i < omPaths.size(); ++i) { + std::cout << "om_path : " << omPaths[i] << std::endl; + auto processModel = std::make_shared(inputDataPaths[i], inputIdPaths[i], batchSize); + Result ret = processModel->LoadModelFromFileWithMem(omPaths[i].c_str()); + if (ret != SUCCESS) { + ERROR_LOG("load model from file failed"); + return FAILED; + } + + ret = processModel->InitResource(); + if (ret != SUCCESS) { + ERROR_LOG("create model description failed"); + return FAILED; + } + + modelProcessContainer_.emplace(i, processModel); + } + + return SUCCESS; +} + +std::vector>> SampleProcess::ReadHistory(std::vector historyFile, + uint32_t batchSize) { + std::vector>> allHistory; + for (auto &file : historyFile) { + std::vector> history(batchSize, std::vector(50)); + Utils::ReadFileToVector(file, batchSize, 50, &history); + allHistory.emplace_back(history); + } + + return allHistory; +} + +Result SampleProcess::Process(const std::vector &omPaths, + const std::vector &inputDataPaths, + const std::vector &inputIdPaths, + const std::string &browsedNewsPath, + uint32_t batchSize) { + struct timeval totalStart; + struct timeval totalEnd; + + CreateModelProcessInstance(omPaths, inputDataPaths, inputIdPaths, batchSize); + + uint32_t fileNum = modelProcessContainer_[0]->ReadFiles(); + std::string historyDir = modelProcessContainer_[1]->GetInputDataPath() + "/00_history_data"; + std::vector historyFile = Utils::GetAllBins(historyDir); + + size_t historySize = historyFile.size(); + std::vector>> allHistory = ReadHistory(historyFile, batchSize); + + uint32_t browsedFileNum = ReadBrowsedData(browsedNewsPath); + + gettimeofday(&totalStart, NULL); + modelProcessContainer_[0]->ExecuteWithFile(fileNum); + + std::map result = modelProcessContainer_[0]->GetResult(); + + std::vector model1OutputBuffSize = modelProcessContainer_[0]->GetOutputSize(); + std::vector inputBuffSize = modelProcessContainer_[1]->GetInputSize(); + + uint32_t singleDatsSize = model1OutputBuffSize[0] / batchSize; + void* browedNews = NULL; + aclrtMallocHost(&browedNews, inputBuffSize[0]); + + struct timeval start; + struct timeval end; + double startTime_ms; + double endTime_ms; + for (int i = 0; i < historySize; ++i) { + gettimeofday(&start, NULL); + for (int j = 0; j < 16; ++j) { + for (int k = 0; k < 50; ++k) { + auto it = result.find(allHistory[i][j][k]); + if (it != result.end()) { + aclrtMemcpy(reinterpret_cast(browedNews) + (j*50 + k) * singleDatsSize, singleDatsSize, + result[allHistory[i][j][k]], singleDatsSize, ACL_MEMCPY_HOST_TO_HOST); + } + } + } + modelProcessContainer_[1]->CpyDataToDevice(browedNews, inputBuffSize[0], 0); + modelProcessContainer_[1]->Execute(i); + 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; + secondModelCostTime_map_.insert(std::pair(startTime_ms, endTime_ms)); + } + + GetPred(browsedFileNum); + gettimeofday(&totalEnd, NULL); + startTime_ms = (1.0 * totalStart.tv_sec * 1000000 + totalStart.tv_usec) / 1000; + endTime_ms = (1.0 * totalEnd.tv_sec * 1000000 + totalEnd.tv_usec) / 1000; + totalCostTime_map_.insert(std::pair(startTime_ms, endTime_ms)); + aclrtFreeHost(browedNews); + return SUCCESS; +} + +Result SampleProcess::ReadBrowsedFile(const std::string &browsedNewsPath, + std::vector userIdFiles, + std::vector> *usersIds, + std::vector> *candidateNewsIds) { + std::vector candidateNewsId; + std::vector usersId; + for (auto file : userIdFiles) { + candidateNewsId.clear(); + usersId.clear(); + std::size_t pos = file.rfind("/"); + std::string name = file.substr(pos); + + std::string newsIdFileName = browsedNewsPath + "/01_candidate_nid_data" + name; + + Utils::ReadFileToVector(file, &usersId); + Utils::ReadFileToVector(newsIdFileName, &candidateNewsId); + + usersIds->emplace_back(usersId); + candidateNewsIds->emplace_back(candidateNewsId); + } + return SUCCESS; +} + +uint32_t SampleProcess::ReadBrowsedData(const std::string &browsedNewsPath) { + userIdFiles_ = Utils::GetAllBins(browsedNewsPath + "/00_user_id_data"); + ReadBrowsedFile(browsedNewsPath, userIdFiles_, &usersIds_, &candidateNewsIds_); + uint32_t fileNum = userIdFiles_.size(); + + return fileNum; +} + +Result SampleProcess::GetPred(uint32_t fileNum) { + std::map newsEncodeResult = modelProcessContainer_[0]->GetResult(); + std::map userEncodeResult = modelProcessContainer_[1]->GetResult(); + + uint32_t perThreadNum = fileNum / threadNum_; + std::vector threads; + + for (int i = 0; i < threadNum_; ++i) { + if (i != threadNum_ - 1) { + threads.emplace_back(std::thread(&SampleProcess::GetResult, this, + i * perThreadNum, (i+1) * perThreadNum, + newsEncodeResult, + userEncodeResult)); + } else { + threads.emplace_back(std::thread(&SampleProcess::GetResult, this, + i * perThreadNum, + fileNum, + newsEncodeResult, + userEncodeResult)); + } + } + for (int i = 0; i < threads.size(); ++i) { + threads[i].join(); + } + + return SUCCESS; +} +void SampleProcess::GetResult(uint32_t startPos, uint32_t endPos, + std::map newsEncodeResult, + std::map userEncodeResult) { + for (int i = startPos; i < endPos; ++i) { + std::vector> newsCandidate; + std::vector userEncodeIds(400); + for (int j = 0; j < candidateNewsIds_[i].size(); ++j) { + std::vector newsResults(400); + float *newsResult = reinterpret_cast(newsEncodeResult[candidateNewsIds_[i][j]]); + std::copy(newsResult, newsResult + 400, newsResults.begin()); + newsCandidate.emplace_back(newsResults); + } + float *userResult = reinterpret_cast(userEncodeResult[usersIds_[i][0]]); + std::copy(userResult, userResult + 400, userEncodeIds.begin()); + + std::vector predResult; + for (int j = 0; j < newsCandidate.size(); ++j) { + float dotMulResult = 0; + for (int k = 0; k < 400; ++k) { + dotMulResult += newsCandidate[j][k] * userEncodeIds[k]; + } + predResult.emplace_back(dotMulResult); + } + mtx_.lock(); + WriteResult(userIdFiles_[i], predResult, predResult.size() * 4); + mtx_.unlock(); + } + + return; +} + +int SampleProcess::WriteResult(const std::string& imageFile, std::vector result, uint32_t size) { + std::string homePath = "./result_Files/"; + std::size_t pos = imageFile.rfind("/"); + std::string name = imageFile.substr(pos); + for (size_t i = 0; i < 1; ++i) { + std::string outFileName = homePath + "/" + name; + try { + FILE * outputFile = fopen(outFileName.c_str(), "wb"); + fwrite(static_cast(&result[0]), size, sizeof(char), outputFile); + fclose(outputFile); + outputFile = nullptr; + } catch (std::exception &e) { + std::cout << "write result file " << outFileName << " failed, error info: " << e.what() << std::endl; + std::exit(1); + } + } + return SUCCESS; +} + +void SampleProcess::DestroyResource() { + aclError ret; + if (stream_ != nullptr) { + ret = aclrtDestroyStream(stream_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("destroy stream failed"); + } + stream_ = nullptr; + } + INFO_LOG("end to destroy stream"); + + if (context_ != nullptr) { + ret = aclrtDestroyContext(context_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("destroy context failed"); + } + context_ = nullptr; + } + INFO_LOG("end to destroy context"); + + ret = aclrtResetDevice(deviceId_); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("reset device failed"); + } + INFO_LOG("end to reset device is %d", deviceId_); + + ret = aclFinalize(); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("finalize acl failed"); + } + INFO_LOG("end to finalize acl"); +} + +std::vector SampleProcess::GetModelExecCostTimeInfo() { + std::vector result; + + result.emplace_back(modelProcessContainer_[0]->GetCostTimeInfo()); + double secondModelAverage = 0.0; + int infer_cnt = 0; + char tmpCh[256] = {0}; + for (auto iter = secondModelCostTime_map_.begin(); iter != secondModelCostTime_map_.end(); iter++) { + double diff = 0.0; + diff = iter->second - iter->first; + secondModelAverage += diff; + infer_cnt++; + } + secondModelAverage = secondModelAverage / infer_cnt; + snprintf(tmpCh, sizeof(tmpCh), "second model inference cost average time: %4.3f ms of infer_count %d\n", + secondModelAverage, infer_cnt); + result.emplace_back(tmpCh); + + double totalCostTime; + totalCostTime = totalCostTime_map_.begin()->second - totalCostTime_map_.begin()->first; + snprintf(tmpCh, sizeof(tmpCh), "total inference cost time: %4.3f ms; count %d\n", totalCostTime, infer_cnt); + result.emplace_back(tmpCh); + + return result; +} diff --git a/model_zoo/official/recommend/naml/ascend310_infer/src/utils.cpp b/model_zoo/official/recommend/naml/ascend310_infer/src/utils.cpp new file mode 100644 index 0000000000..cd02b4a96b --- /dev/null +++ b/model_zoo/official/recommend/naml/ascend310_infer/src/utils.cpp @@ -0,0 +1,246 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include "acl/acl.h" +#include "../inc/utils.h" + +extern bool g_isDevice; + +void* Utils::ReadBinFile(std::string fileName, uint32_t *fileSize) { + struct stat sBuf; + int fileStatus = stat(fileName.data(), &sBuf); + if (fileStatus == -1) { + ERROR_LOG("failed to get file"); + return nullptr; + } + if (S_ISREG(sBuf.st_mode) == 0) { + ERROR_LOG("%s is not a file, please enter a file", fileName.c_str()); + return nullptr; + } + + std::ifstream binFile(fileName, std::ifstream::binary); + if (binFile.is_open() == false) { + ERROR_LOG("open file %s failed", fileName.c_str()); + return nullptr; + } + + binFile.seekg(0, binFile.end); + uint32_t binFileBufferLen = binFile.tellg(); + if (binFileBufferLen == 0) { + ERROR_LOG("binfile is empty, filename is %s", fileName.c_str()); + binFile.close(); + return nullptr; + } + + binFile.seekg(0, binFile.beg); + + void* binFileBufferData = nullptr; + if (!g_isDevice) { + aclrtMallocHost(&binFileBufferData, binFileBufferLen); + if (binFileBufferData == nullptr) { + ERROR_LOG("malloc binFileBufferData failed"); + binFile.close(); + return nullptr; + } + } else { + aclError ret = aclrtMalloc(&binFileBufferData, binFileBufferLen, ACL_MEM_MALLOC_NORMAL_ONLY); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("malloc device buffer failed. size is %u", binFileBufferLen); + binFile.close(); + return nullptr; + } + } + binFile.read(static_cast(binFileBufferData), binFileBufferLen); + binFile.close(); + *fileSize = binFileBufferLen; + return binFileBufferData; +} + +void* Utils::GetDeviceBufferOfFile(std::string fileName, uint32_t *fileSize) { + uint32_t inputHostBuffSize = 0; + void* inputHostBuff = Utils::ReadBinFile(fileName, &inputHostBuffSize); + if (inputHostBuff == nullptr) { + return nullptr; + } + if (!g_isDevice) { + void *inBufferDev = nullptr; + uint32_t inBufferSize = inputHostBuffSize; + aclError ret = aclrtMalloc(&inBufferDev, inBufferSize, ACL_MEM_MALLOC_NORMAL_ONLY); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("malloc device buffer failed. size is %u", inBufferSize); + aclrtFreeHost(inputHostBuff); + return nullptr; + } + + ret = aclrtMemcpy(inBufferDev, inBufferSize, inputHostBuff, inputHostBuffSize, ACL_MEMCPY_HOST_TO_DEVICE); + if (ret != ACL_ERROR_NONE) { + ERROR_LOG("memcpy failed. device buffer size is %u, input host buffer size is %u", + inBufferSize, inputHostBuffSize); + aclrtFree(inBufferDev); + aclrtFreeHost(inputHostBuff); + return nullptr; + } + aclrtFreeHost(inputHostBuff); + *fileSize = inBufferSize; + return inBufferDev; + } else { + *fileSize = inputHostBuffSize; + return inputHostBuff; + } +} + +std::vector> Utils::GetAllInputData(std::string dir_name) { + DIR *dir = OpenDir(dir_name); + if (dir == nullptr) { + return {}; + } + struct dirent *filename; + + std::vector sub_dirs; + while ((filename = readdir(dir)) != nullptr) { + std::string d_name = std::string(filename->d_name); + if (d_name == "." || d_name == ".." || d_name.empty() || d_name[0] != '0') { + continue; + } + + std::string dir_path = RealPath(std::string(dir_name) + "/" + filename->d_name); + struct stat s; + lstat(dir_path.c_str(), &s); + if (!S_ISDIR(s.st_mode)) { + continue; + } + + sub_dirs.emplace_back(dir_path); + } + std::sort(sub_dirs.begin(), sub_dirs.end()); + + std::vector> result(sub_dirs.size()); + + std::transform(sub_dirs.begin(), sub_dirs.end(), result.begin(), GetAllBins); + + return result; +} + +DIR *Utils::OpenDir(std::string dir_name) { + // check the parameter ! + if (dir_name.empty()) { + std::cout << " dir_name is null ! " << std::endl; + return nullptr; + } + + std::string real_path = RealPath(dir_name); + + // check if dir_name is a valid dir + struct stat s; + lstat(real_path.c_str(), &s); + if (!S_ISDIR(s.st_mode)) { + std::cout << "dir_name is not a valid directory !" << std::endl; + return nullptr; + } + + DIR *dir; + dir = opendir(real_path.c_str()); + if (dir == nullptr) { + std::cout << "Can not open dir " << dir_name << std::endl; + return nullptr; + } + std::cout << "Successfully opened the dir " << dir_name << std::endl; + return dir; +} + +std::string Utils::RealPath(std::string path) { + char real_path_mem[PATH_MAX] = {0}; + char *real_path_ret = nullptr; + real_path_ret = realpath(path.data(), real_path_mem); + + if (real_path_ret == nullptr) { + std::cout << "File: " << path << " is not exist."; + return ""; + } + + std::string real_path(real_path_mem); + std::cout << path << " realpath is: " << real_path << std::endl; + return real_path; +} + +std::vector Utils::GetAllBins(std::string dir_name) { + struct dirent *filename; + DIR *dir = OpenDir(dir_name); + if (dir == nullptr) { + return {}; + } + + std::vector res; + while ((filename = readdir(dir)) != nullptr) { + std::string d_name = std::string(filename->d_name); + if (d_name == "." || d_name == ".." || d_name.size() <= 3 || d_name.substr(d_name.size() - 4) != ".bin" || + filename->d_type != DT_REG) { + continue; + } + res.emplace_back(std::string(dir_name) + "/" + filename->d_name); + } + + std::sort(res.begin(), res.end()); + + return res; +} + +Result Utils::ReadFileToVector(std::string newsIdFileName, std::vector *newsId) { + int id; + + std::ifstream in(newsIdFileName, std::ios::in | std::ios::binary); + while (in.read(reinterpret_cast(&id), sizeof(id))) { + newsId->emplace_back(id); + } + in.close(); + + return SUCCESS; +} + +Result Utils::ReadFileToVector(std::string newsIdFileName, uint32_t batchSize, std::vector *newsId) { + int id; + + std::ifstream in(newsIdFileName, std::ios::in | std::ios::binary); + for (int i = 0; i < batchSize; ++i) { + in.read(reinterpret_cast(&id), sizeof(id)); + newsId->emplace_back(id); + } + in.close(); + + return SUCCESS; +} + +Result Utils::ReadFileToVector(std::string fileName, uint32_t batchSize, + uint32_t count, std::vector> *newsId) { + int id; + + std::ifstream in(fileName, std::ios::in | std::ios::binary); + for (int i = 0; i < batchSize; ++i) { + for (int j = 0; j < count; ++j) { + in.read(reinterpret_cast(&id), sizeof(id)); + (*newsId)[i][j] = id; + } + } + in.close(); + + return SUCCESS; +} diff --git a/model_zoo/official/recommend/naml/postprocess.py b/model_zoo/official/recommend/naml/postprocess.py new file mode 100644 index 0000000000..0323bf2763 --- /dev/null +++ b/model_zoo/official/recommend/naml/postprocess.py @@ -0,0 +1,100 @@ +# 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 +# +# less 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. +# ============================================================================ + +"""Evaluation for NAML""" +import os +import argparse +import numpy as np + +from sklearn.metrics import roc_auc_score + +parser = argparse.ArgumentParser(description="") +parser.add_argument("--result_path", type=str, default="", help="Device id") +parser.add_argument("--label_path", type=str, default="", help="output file name.") +args = parser.parse_args() + +def AUC(y_true, y_pred): + return roc_auc_score(y_true, y_pred) + +def MRR(y_true, y_pred): + index = np.argsort(y_pred)[::-1] + y_true = np.take(y_true, index) + score = y_true / (np.arange(len(y_true)) + 1) + return np.sum(score) / np.sum(y_true) + +def DCG(y_true, y_pred, n): + index = np.argsort(y_pred)[::-1] + y_true = np.take(y_true, index[:n]) + score = (2 ** y_true - 1) / np.log2(np.arange(len(y_true)) + 2) + return np.sum(score) + +def nDCG(y_true, y_pred, n): + return DCG(y_true, y_pred, n) / DCG(y_true, y_true, n) + +class NAMLMetric: + """ + Metric method + """ + def __init__(self): + super(NAMLMetric, self).__init__() + self.AUC_list = [] + self.MRR_list = [] + self.nDCG5_list = [] + self.nDCG10_list = [] + + def clear(self): + """Clear the internal evaluation result.""" + self.AUC_list = [] + self.MRR_list = [] + self.nDCG5_list = [] + self.nDCG10_list = [] + + def update(self, predict, y_true): + predict = predict.flatten() + y_true = y_true.flatten() + # predict = np.interp(predict, (predict.min(), predict.max()), (0, 1)) + self.AUC_list.append(AUC(y_true, predict)) + self.MRR_list.append(MRR(y_true, predict)) + self.nDCG5_list.append(nDCG(y_true, predict, 5)) + self.nDCG10_list.append(nDCG(y_true, predict, 10)) + + def eval(self): + auc = np.mean(self.AUC_list) + print('AUC:', auc) + print('MRR:', np.mean(self.MRR_list)) + print('nDCG@5:', np.mean(self.nDCG5_list)) + print('nDCG@10:', np.mean(self.nDCG10_list)) + return auc + +def get_metric(result_path, label_path, metric): + """get accuracy""" + result_files = os.listdir(result_path) + for file in result_files: + result_file = os.path.join(result_path, file) + pred = np.fromfile(result_file, dtype=np.float32) + + label_file = os.path.join(label_path, file) + label = np.fromfile(label_file, dtype=np.int32) + + if np.nan in pred: + continue + metric.update(pred, label) + + auc = metric.eval() + return auc + +if __name__ == "__main__": + naml_metric = NAMLMetric() + get_metric(args.result_path, args.label_path, naml_metric) diff --git a/model_zoo/official/recommend/naml/script/run_infer_310.sh b/model_zoo/official/recommend/naml/script/run_infer_310.sh new file mode 100755 index 0000000000..5e0d8537c7 --- /dev/null +++ b/model_zoo/official/recommend/naml/script/run_infer_310.sh @@ -0,0 +1,123 @@ +#!/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 [[ $# -lt 8 || $# -gt 9 ]]; then + echo "Usage: sh run_infer_310.sh [NEWS_MODEL] [USER_MODEL] [NEWS_DATASET_PATH] [USER_DATASET_PATH] [NEWS_ID_PATH] [USER_ID_PATH] [BROWSED_NEWS_PATH] [SOC_VERSION] [DEVICE_ID] + DEVICE_ID is optional, it can be set by environment variable device_id, otherwise the value is zero" +exit 1 +fi + +get_real_path(){ + if [ "${1:0:1}" == "/" ]; then + echo "$1" + else + echo "$(realpath -m $PWD/$1)" + fi +} + +news_model=$(get_real_path $1) +user_model=$(get_real_path $2) +news_dataset_path=$(get_real_path $3) +user_dataset_path=$(get_real_path $4) +news_id_path=$(get_real_path $5) +user_id_path=$(get_real_path $6) +browsed_news_path=$(get_real_path $7) +soc_version=$8 + +if [ $# == 9 ]; then + device_id=$9 +elif [ $# == 8 ]; then + if [ -z $device_id ]; then + device_id=0 + else + device_id=$device_id + fi +fi + +echo $news_model +echo $user_model +echo $news_dataset_path +echo $news_id_path +echo $user_id_path +echo $browsed_news_path +echo $soc_version +echo $device_id + +export ASCEND_HOME=/usr/local/Ascend/ +if [ -d ${ASCEND_HOME}/ascend-toolkit ]; then + export PATH=$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin:$ASCEND_HOME/ascend-toolkit/latest/atc/bin:$PATH + export LD_LIBRARY_PATH=/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=${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/atc/ccec_compiler/bin:$ASCEND_HOME/atc/bin:$PATH + export LD_LIBRARY_PATH=/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/atc/python/site-packages:$PYTHONPATH + export ASCEND_OPP_PATH=$ASCEND_HOME/opp +fi + +function air_to_om() +{ + atc --framework=1 --model=$news_model --output=news_encoder --soc_version=$soc_version + atc --framework=1 --model=$user_model --output=user_encoder --soc_version=$soc_version +} + +function compile_app() +{ + cd ../ascend310_infer + if [ -f "Makefile" ]; then + make clean + fi + sh build.sh &> build.log + + if [ $? -ne 0 ]; then + echo "compile app code failed" + exit 1 + fi + cd - +} + +function infer() +{ + 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 --news_om_path news_encoder.om --user_om_path user_encoder.om --news_dataset_path $news_dataset_path --user_dataset_path $user_dataset_path --newsid_data_path $news_id_path --userid_data_path $user_id_path --browsed_news_path $browsed_news_path &> infer.log + if [ $? -ne 0 ]; then + echo "execute inference failed" + exit 1 + fi +} + +function cal_acc() +{ + python3 ../postprocess.py --result_path=./result_Files --label_path=$browsed_news_path/02_labels_data &> acc.log + if [ $? -ne 0 ]; then + echo "calculate accuracy failed" + exit 1 + fi +} + +air_to_om +compile_app +infer +cal_acc