From 835bb39b107779f60defe5084b72364047140227 Mon Sep 17 00:00:00 2001 From: Jack Zhou Date: Mon, 15 Aug 2022 13:28:48 +0800 Subject: [PATCH] Add ernie ie task (#100) --- FastDeploy.cmake.in | 4 + csrc/fastdeploy/core/config.h.in | 8 + .../ernie/cpp/CMakeLists.txt | 25 +++ .../information_extraction/ernie/cpp/infer.cc | 182 ++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 examples/text/information_extraction/ernie/cpp/CMakeLists.txt create mode 100644 examples/text/information_extraction/ernie/cpp/infer.cc diff --git a/FastDeploy.cmake.in b/FastDeploy.cmake.in index 082fa30f30..ccd1039be2 100644 --- a/FastDeploy.cmake.in +++ b/FastDeploy.cmake.in @@ -95,6 +95,10 @@ endif() if (ENABLE_TEXT) # Add dependency libs later + find_library(FASTER_TOKENIZER_LIB core_tokenizers ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/faster_tokenizer/lib NO_DEFAULT_PATH) + list(APPEND FASTDEPLOY_LIBS ${FASTER_TOKENIZER_LIB}) + list(APPEND FASTDEPLOY_INCS ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/faster_tokenizer/include) + list(APPEND FASTDEPLOY_INCS ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/faster_tokenizer/third_party/include) endif() if(ENABLE_PADDLE_FRONTEND) diff --git a/csrc/fastdeploy/core/config.h.in b/csrc/fastdeploy/core/config.h.in index 7713925867..b29113f1fd 100644 --- a/csrc/fastdeploy/core/config.h.in +++ b/csrc/fastdeploy/core/config.h.in @@ -45,6 +45,10 @@ #cmakedefine ENABLE_VISION #endif +#ifndef ENABLE_TEXT +#cmakedefine ENABLE_TEXT +#endif + #ifndef ENABLE_OPENCV_CUDA #cmakedefine ENABLE_OPENCV_CUDA #endif @@ -52,3 +56,7 @@ #ifndef ENABLE_VISION_VISUALIZE #cmakedefine ENABLE_VISION_VISUALIZE #endif + +#ifndef ENABLE_FDTENSOR_FUNC +#cmakedefine ENABLE_FDTENSOR_FUNC +#endif diff --git a/examples/text/information_extraction/ernie/cpp/CMakeLists.txt b/examples/text/information_extraction/ernie/cpp/CMakeLists.txt new file mode 100644 index 0000000000..1189820cb7 --- /dev/null +++ b/examples/text/information_extraction/ernie/cpp/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +PROJECT(infer_demo C CXX) +CMAKE_MINIMUM_REQUIRED (VERSION 3.12) + +option(FASTDEPLOY_INSTALL_DIR "Path of downloaded fastdeploy sdk.") + +include(${FASTDEPLOY_INSTALL_DIR}/FastDeploy.cmake) + +include_directories(${FASTDEPLOY_INCS}) + +add_executable(infer_ernie_demo ${PROJECT_SOURCE_DIR}/infer.cc) +target_link_libraries(infer_ernie_demo ${FASTDEPLOY_LIBS}) diff --git a/examples/text/information_extraction/ernie/cpp/infer.cc b/examples/text/information_extraction/ernie/cpp/infer.cc new file mode 100644 index 0000000000..7f3b931866 --- /dev/null +++ b/examples/text/information_extraction/ernie/cpp/infer.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include + +#include "fastdeploy/function/reduce.h" +#include "fastdeploy/function/softmax.h" +#include "fastdeploy/text.h" +#include "tokenizers/ernie_faster_tokenizer.h" + +using namespace paddlenlp; + +void LoadTransitionFromFile(const std::string& file, + std::vector* transitions, int* num_tags) { + std::ifstream fin(file); + std::string curr_transition; + float transition; + int i = 0; + while (fin) { + std::getline(fin, curr_transition); + std::istringstream iss(curr_transition); + while (iss) { + iss >> transition; + transitions->push_back(transition); + } + if (curr_transition != "") { + ++i; + } + } + *num_tags = i; +} + +template +void ViterbiDecode(const fastdeploy::FDTensor& slot_logits, + const fastdeploy::FDTensor& trans, + fastdeploy::FDTensor* best_path) { + int batch_size = slot_logits.shape[0]; + int seq_len = slot_logits.shape[1]; + int num_tags = slot_logits.shape[2]; + best_path->Allocate({batch_size, seq_len}, fastdeploy::FDDataType::INT64); + + const T* slot_logits_ptr = reinterpret_cast(slot_logits.Data()); + const T* trans_ptr = reinterpret_cast(trans.Data()); + int64_t* best_path_ptr = reinterpret_cast(best_path->Data()); + std::vector scores(num_tags); + std::copy(slot_logits_ptr, slot_logits_ptr + num_tags, scores.begin()); + std::vector> M(num_tags, std::vector(num_tags)); + for (int b = 0; b < batch_size; ++b) { + std::vector> paths; + const T* curr_slot_logits_ptr = slot_logits_ptr + b * seq_len * num_tags; + int64_t* curr_best_path_ptr = best_path_ptr + b * seq_len; + for (int t = 1; t < seq_len; t++) { + for (size_t i = 0; i < num_tags; i++) { + for (size_t j = 0; j < num_tags; j++) { + auto trans_idx = i * num_tags * num_tags + j * num_tags; + auto slot_logit_idx = t * num_tags + j; + M[i][j] = scores[i] + trans_ptr[trans_idx] + + curr_slot_logits_ptr[slot_logit_idx]; + } + } + std::vector idxs; + for (size_t i = 0; i < num_tags; i++) { + T max = 0.0f; + int idx = 0; + for (size_t j = 0; j < num_tags; j++) { + if (M[j][i] > max) { + max = M[j][i]; + idx = j; + } + } + scores[i] = max; + idxs.push_back(idx); + } + paths.push_back(idxs); + } + int scores_max_index = 0; + float scores_max = 0.0f; + for (size_t i = 0; i < scores.size(); i++) { + if (scores[i] > scores_max) { + scores_max = scores[i]; + scores_max_index = i; + } + } + curr_best_path_ptr[seq_len - 1] = scores_max_index; + for (int i = seq_len - 2; i >= 0; i--) { + int index = curr_best_path_ptr[i + 1]; + curr_best_path_ptr[i] = paths[i][index]; + } + } +} + +int main() { + // 1. Define a ernie faster tokenizer + faster_tokenizer::tokenizers_impl::ErnieFasterTokenizer tokenizer( + "ernie_vocab.txt"); + std::vector strings_list = { + "导航去科技园二号楼", "屏幕亮度为我减小一点吧"}; + std::vector encodings; + tokenizer.EncodeBatchStrings(strings_list, &encodings); + size_t batch_size = strings_list.size(); + size_t seq_len = encodings[0].GetLen(); + for (auto&& encoding : encodings) { + std::cout << encoding.DebugString() << std::endl; + } + // 2. Initialize runtime + fastdeploy::RuntimeOption runtime_option; + runtime_option.SetModelPath("nano_static/model.pdmodel", + "nano_static/model.pdiparams"); + fastdeploy::Runtime runtime; + runtime.Init(runtime_option); + + // 3. Construct input vector + // 3.1 Convert encodings to input_ids, token_type_ids + std::vector input_ids, token_type_ids; + for (int i = 0; i < encodings.size(); ++i) { + auto&& curr_input_ids = encodings[i].GetIds(); + auto&& curr_type_ids = encodings[i].GetTypeIds(); + input_ids.insert(input_ids.end(), curr_input_ids.begin(), + curr_input_ids.end()); + token_type_ids.insert(token_type_ids.end(), curr_type_ids.begin(), + curr_type_ids.end()); + } + // 3.2 Set data to input vector + std::vector inputs(runtime.NumInputs()); + void* inputs_ptrs[] = {input_ids.data(), token_type_ids.data()}; + for (int i = 0; i < runtime.NumInputs(); ++i) { + inputs[i].SetExternalData({batch_size, seq_len}, + fastdeploy::FDDataType::INT64, inputs_ptrs[i]); + inputs[i].name = runtime.GetInputInfo(i).name; + } + + // 4. Infer + std::vector outputs(runtime.NumOutputs()); + runtime.Infer(inputs, &outputs); + + // 5. Postprocess + fastdeploy::FDTensor domain_probs, intent_probs; + fastdeploy::Softmax(outputs[0], &domain_probs); + fastdeploy::Softmax(outputs[1], &intent_probs); + + fastdeploy::FDTensor domain_max_probs, intent_max_probs; + fastdeploy::Max(domain_probs, &domain_max_probs, {-1}, true); + fastdeploy::Max(intent_probs, &intent_max_probs, {-1}, true); + + std::vector transition; + int num_tags; + LoadTransitionFromFile("joint_transition.txt", &transition, &num_tags); + fastdeploy::FDTensor trans; + trans.SetExternalData({num_tags, num_tags}, fastdeploy::FDDataType::FP32, + transition.data()); + + fastdeploy::FDTensor best_path; + ViterbiDecode(outputs[2], trans, &best_path); + // 6. Print result + domain_max_probs.PrintInfo(); + intent_max_probs.PrintInfo(); + + batch_size = best_path.shape[0]; + seq_len = best_path.shape[1]; + const int64_t* best_path_ptr = + reinterpret_cast(best_path.Data()); + for (int i = 0; i < batch_size; ++i) { + std::cout << "best_path[" << i << "] = "; + for (int j = 0; j < seq_len; ++j) { + std::cout << best_path_ptr[i * seq_len + j] << ", "; + } + std::cout << std::endl; + } + best_path.PrintInfo(); + return 0; +}