* update some examples

This commit is contained in:
lxowalle
2024-12-16 10:20:20 +08:00
parent 65effcd4fd
commit f0f0dfb7dc
52 changed files with 13304 additions and 0 deletions

View File

@@ -62,6 +62,7 @@ if(PLATFORM_MAIXCAM AND NOT CONFIG_OPENCV_COMPILE_FROM_SOURCE AND NOT CONFIG_COM
"${opencv_lib_dir}/dl_lib/libopencv_highgui.so.${so_suffix_number}"
"${opencv_lib_dir}/dl_lib/libopencv_imgcodecs.so.${so_suffix_number}"
"${opencv_lib_dir}/dl_lib/libopencv_imgproc.so.${so_suffix_number}"
"${opencv_lib_dir}/dl_lib/libopencv_video.so.${so_suffix_number}"
# "${opencv_lib_dir}/dl_lib/libopencv_freetype.so.${so_suffix_number}"
)
list(APPEND ADD_DYNAMIC_LIB ${opencv_libs})
@@ -126,6 +127,7 @@ if(NOT ADD_INCLUDE)
"${opencv_install_dir}/lib/libopencv_highgui.so.${so_suffix_number}"
"${opencv_install_dir}/lib/libopencv_imgcodecs.so.${so_suffix_number}"
"${opencv_install_dir}/lib/libopencv_imgproc.so.${so_suffix_number}"
"${opencv_install_dir}/lib/libopencv_video.so.${so_suffix_number}"
# "${opencv_install_dir}/lib/libopencv_freetype.so.${so_suffix_number}"
)
list(APPEND ADD_DYNAMIC_LIB ${opencv_libs})

9
examples/demo_focus_stack/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
build
dist
.config.mk
.flash.conf.json
data
/CMakeLists.txt
__pycache__

View File

@@ -0,0 +1,2 @@
## Introduction can be seen
[Introduction](https://maixhub.com/share/34)

View File

@@ -0,0 +1,11 @@
id: focus_stack
name: focus_stack
name[zh]:
version: 1.0.0
#icon: assets/hello.png
author:
desc:
desc[zh]:
files:
# assets: assets

View File

@@ -0,0 +1,82 @@
############### Add include ###################
list(APPEND ADD_INCLUDE "include"
)
list(APPEND ADD_PRIVATE_INCLUDE "focus-stack/src")
###############################################
############ Add source files #################
# list(APPEND ADD_SRCS "src/main.c"
# "src/test.c"
# )
append_srcs_dir(ADD_SRCS "src"
"focus-stack/src") # append source file in src dir to var ADD_SRCS
list(REMOVE_ITEM ADD_SRCS "focus-stack/src/main.cc"
"focus-stack/src/gtest_main.cc"
"focus-stack/src/radialfilter_tests.cc"
"focus-stack/src/task_wavelet_tests.cc"
"focus-stack/src/task_wavelet_opencl_tests.cc"
"focus-stack/src/task_grayscale_tests.cc"
)
# FILE(GLOB_RECURSE EXTRA_SRC "src/*.c")
# FILE(GLOB EXTRA_SRC "src/*.c")
# list(APPEND ADD_SRCS ${EXTRA_SRC})
# aux_source_directory(src ADD_SRCS) # collect all source file in src dir, will set var ADD_SRCS
# append_srcs_dir(ADD_SRCS "src") # append source file in src dir to var ADD_SRCS
# list(REMOVE_ITEM COMPONENT_SRCS "src/test.c")
# set(ADD_ASM_SRCS "src/asm.S")
# list(APPEND ADD_SRCS ${ADD_ASM_SRCS})
# SET_PROPERTY(SOURCE ${ADD_ASM_SRCS} PROPERTY LANGUAGE C) # set .S ASM file as C language
# SET_SOURCE_FILES_PROPERTIES(${ADD_ASM_SRCS} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D BBBBB")
###############################################
###### Add required/dependent components ######
# list(APPEND ADD_REQUIREMENTS basic vision)
###############################################
###### Add link search path for requirements/libs ######
# list(APPEND ADD_LINK_SEARCH_PATH "${CONFIG_TOOLCHAIN_PATH}/lib")
# list(APPEND ADD_REQUIREMENTS pthread m) # add system libs, pthread and math lib for example here
# set (OpenCV_DIR opencv/lib/cmake/opencv4)
# find_package(OpenCV REQUIRED)
###############################################
############ Add static libs ##################
# list(APPEND ADD_STATIC_LIB "lib/libtest.a")
###############################################
#### Add compile option for this component ####
#### Just for this component, won't affect other
#### modules, including component that depend
#### on this component
# list(APPEND ADD_DEFINITIONS_PRIVATE -DAAAAA=1)
#### Add compile option for this component
#### and components depend on this component
# list(APPEND ADD_DEFINITIONS -DAAAAA222=1
# -DAAAAA333=1)
###############################################
############ Add static libs ##################
#### Update parent's variables like CMAKE_C_LINK_FLAGS
# set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group libmaix/libtest.a -ltest2 -Wl,--end-group" PARENT_SCOPE)
###############################################
######### Add files need to download #########
# list(APPEND ADD_FILE_DOWNLOADS "{
# 'url': 'https://*****/abcde.tar.xz',
# 'urls': [], # backup urls, if url failed, will try urls
# 'sites': [], # download site, user can manually download file and put it into dl_path
# 'sha256sum': '',
# 'filename': 'abcde.tar.xz',
# 'path': 'toolchains/xxxxx',
# 'check_files': []
# }"
# )
#
# then extracted file in ${DL_EXTRACTED_PATH}/toolchains/xxxxx,
# you can directly use then, for example use it in add_custom_command
##############################################
# register component, DYNAMIC or SHARED flags will make component compiled to dynamic(shared) lib
register_component()

View File

View File

@@ -0,0 +1,3 @@
#pragma once

View File

@@ -0,0 +1,186 @@
#include <iostream>
#include "options.hh"
#include "focusstack.hh"
#include <opencv2/core.hpp>
#ifndef GIT_VERSION
#define GIT_VERSION "unknown"
#endif
using namespace focusstack;
int main(int argc, const char *argv[])
{
Options options(argc, argv);
FocusStack stack;
if (options.has_flag("--version"))
{
std::cerr << "focus-stack " GIT_VERSION ", built " __DATE__ " " __TIME__ "\n"
"Compiled with OpenCV version " CV_VERSION "\n"
"Copyright (c) 2019 Petteri Aimonen\n\n"
"Permission is hereby granted, free of charge, to any person obtaining a copy\n"
"of this software and associated documentation files (the \"Software\"), to\n"
"deal in the Software without restriction, including without limitation the\n"
"rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n"
"sell copies of the Software, and to permit persons to whom the Software is\n"
"furnished to do so, subject to the following conditions:\n\n"
"The above copyright notice and this permission notice shall be included in all\n"
"copies or substantial portions of the Software.\n\n"
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n"
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n"
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n"
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n"
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n"
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
"SOFTWARE."
<< std::endl;
return 0;
}
if (options.has_flag("--opencv-version"))
{
std::cerr << cv::getBuildInformation().c_str() << std::endl;
return 0;
}
if (options.has_flag("--help") || options.get_filenames().size() < 2)
{
std::cerr << "Usage: " << argv[0] << " [options] file1.jpg file2.jpg ...\n";
std::cerr << "\n";
std::cerr << "Output file options:\n"
" --output=output.jpg Set output filename\n"
" --depthmap=depthmap.png Write a depth map image (default disabled)\n"
" --3dview=3dview.png Write a 3D preview image (default disabled)\n"
" --save-steps Save intermediate images from processing steps\n"
" --jpgquality=95 Quality for saving in JPG format (0-100, default 95)\n"
" --nocrop Save full image, including extrapolated border data\n";
std::cerr << "\n";
std::cerr << "Image alignment options:\n"
" --reference=0 Set index of image used as alignment reference (default middle one)\n"
" --global-align Align directly against reference (default with neighbour image)\n"
" --full-resolution-align Use full resolution images in alignment (default max 2048 px)\n"
" --no-whitebalance Don't attempt to correct white balance differences\n"
" --no-contrast Don't attempt to correct contrast and exposure differences\n"
" --align-only Only align the input image stack and exit\n"
" --align-keep-size Keep original image size by not cropping alignment borders\n";
std::cerr << "\n";
std::cerr << "Image merge options:\n"
" --consistency=2 Neighbour pixel consistency filter level 0..2 (default 2)\n"
" --denoise=1.0 Merged image denoise level (default 1.0)\n";
std::cerr << "\n";
std::cerr << "Depth map generation options:\n"
" --depthmap-threshold=10 Threshold to accept depth points (0-255, default 10)\n"
" --depthmap-smooth-xy=20 Smoothing of depthmap in X and Y directions (default 20)\n"
" --depthmap-smooth-z=40 Smoothing of depthmap in Z direction (default 40)\n"
" --remove-bg=0 Positive value removes black background, negative white\n"
" --halo-radius=20 Radius of halo effects to remove from depthmap\n"
" --3dviewpoint=x:y:z:zscale Viewpoint for 3D view (default 1:1:1:2)\n";
std::cerr << "\n";
std::cerr << "Performance options:\n"
" --threads=2 Select number of threads to use (default number of CPUs + 1)\n"
" --batchsize=8 Images per merge batch (default 8)\n"
" --no-opencl Disable OpenCL GPU acceleration (default enabled)\n"
" --wait-images=0.0 Wait for image files to appear (allows simultaneous capture and processing)\n";
std::cerr << "\n";
std::cerr << "Information options:\n"
" --verbose Verbose output from steps\n"
" --version Show application version number\n"
" --opencv-version Show OpenCV library version and build info\n";
return 1;
}
// Output file options
stack.set_inputs(options.get_filenames());
stack.set_output(options.get_arg("--output", "output.jpg"));
stack.set_depthmap(options.get_arg("--depthmap", ""));
stack.set_3dview(options.get_arg("--3dview", ""));
stack.set_jpgquality(std::stoi(options.get_arg("--jpgquality", "95")));
stack.set_save_steps(options.has_flag("--save-steps"));
stack.set_nocrop(options.has_flag("--nocrop"));
// Image alignment options
int flags = FocusStack::ALIGN_DEFAULT;
if (options.has_flag("--global-align")) flags |= FocusStack::ALIGN_GLOBAL;
if (options.has_flag("--full-resolution-align")) flags |= FocusStack::ALIGN_FULL_RESOLUTION;
if (options.has_flag("--no-whitebalance")) flags |= FocusStack::ALIGN_NO_WHITEBALANCE;
if (options.has_flag("--no-contrast")) flags |= FocusStack::ALIGN_NO_CONTRAST;
if (options.has_flag("--align-keep-size")) flags |= FocusStack::ALIGN_KEEP_SIZE;
stack.set_align_flags(flags);
if (options.has_flag("--reference"))
{
stack.set_reference(std::stoi(options.get_arg("--reference")));
}
if (options.has_flag("--align-only"))
{
stack.set_align_only(true);
stack.set_output(options.get_arg("--output", "aligned_"));
}
// Image merge options
stack.set_consistency(std::stoi(options.get_arg("--consistency", "2")));
stack.set_denoise(std::stof(options.get_arg("--denoise", "1.0")));
// Depth map generation options
stack.set_depthmap_smooth_xy(std::stof(options.get_arg("--depthmap-smooth-xy", "20")));
stack.set_depthmap_smooth_z(std::stof(options.get_arg("--depthmap-smooth-z", "40")));
stack.set_depthmap_threshold(std::stoi(options.get_arg("--depthmap-threshold", "10")));
stack.set_halo_radius(std::stof(options.get_arg("--halo-radius", "20")));
stack.set_remove_bg(std::stoi(options.get_arg("--remove-bg", "0")));
stack.set_3dviewpoint(options.get_arg("--3dviewpoint", "1:1:1:2"));
// Performance options
if (options.has_flag("--threads"))
{
stack.set_threads(std::stoi(options.get_arg("--threads")));
}
if (options.has_flag("--batchsize"))
{
stack.set_batchsize(std::stoi(options.get_arg("--batchsize")));
}
stack.set_disable_opencl(options.has_flag("--no-opencl"));
stack.set_wait_images(std::stof(options.get_arg("--wait-images", "0.0")));
// Information options (some are handled at beginning of this function)
stack.set_verbose(options.has_flag("--verbose"));
// Check for any unhandled options
std::vector<std::string> unparsed = options.get_unparsed();
if (unparsed.size())
{
std::cerr << "Warning: unknown options: ";
for (std::string arg: unparsed)
{
std::cerr << arg << " ";
}
std::cerr << std::endl;
}
if (!stack.run())
{
std::printf("\nError exit due to failed steps\n");
return 1;
}
std::printf("\rSaved to %-40s\n", stack.get_output().c_str());
if (stack.get_depthmap() != "")
{
std::printf("\rSaved depthmap to %s\n", stack.get_depthmap().c_str());
}
if (stack.get_3dview() != "")
{
std::printf("\rSaved 3D preview to %s\n", stack.get_3dview().c_str());
}
return 0;
}

9
examples/onnxruntime_demo/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
build
dist
.config.mk
.flash.conf.json
data
/CMakeLists.txt
__pycache__

View File

@@ -0,0 +1,2 @@
## Introduction can be seen
[Introduction](https://maixhub.com/share/34)

View File

@@ -0,0 +1,11 @@
id: onnxruntime
name: onnxruntime
name[zh]:
version: 1.0.0
#icon: assets/hello.png
author:
desc:
desc[zh]:
files:
# assets: assets

View File

@@ -0,0 +1,82 @@
############### Add include ###################
list(APPEND ADD_INCLUDE "include"
)
list(APPEND ADD_PRIVATE_INCLUDE "onnxruntime-src/include"
"core"
)
###############################################
############ Add source files #################
# list(APPEND ADD_SRCS "src/main.c"
# "src/test.c"
# )
append_srcs_dir(ADD_SRCS "src"
"core/frontend"
"core/kws"
) # append source file in src dir to var ADD_SRCS
list(APPEND ADD_DYNAMIC_LIB "onnxruntime-src/lib/libonnxruntime.so")
# FILE(GLOB_RECURSE EXTRA_SRC "src/*.c")
# FILE(GLOB EXTRA_SRC "src/*.c")
# list(APPEND ADD_SRCS ${EXTRA_SRC})
# aux_source_directory(src ADD_SRCS) # collect all source file in src dir, will set var ADD_SRCS
# append_srcs_dir(ADD_SRCS "src") # append source file in src dir to var ADD_SRCS
# list(REMOVE_ITEM COMPONENT_SRCS "src/test.c")
# set(ADD_ASM_SRCS "src/asm.S")
# list(APPEND ADD_SRCS ${ADD_ASM_SRCS})
# SET_PROPERTY(SOURCE ${ADD_ASM_SRCS} PROPERTY LANGUAGE C) # set .S ASM file as C language
# SET_SOURCE_FILES_PROPERTIES(${ADD_ASM_SRCS} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D BBBBB")
###############################################
###### Add required/dependent components ######
###############################################
###### Add link search path for requirements/libs ######
# list(APPEND ADD_LINK_SEARCH_PATH "${CONFIG_TOOLCHAIN_PATH}/lib")
# list(APPEND ADD_REQUIREMENTS pthread m) # add system libs, pthread and math lib for example here
# set (OpenCV_DIR opencv/lib/cmake/opencv4)
# find_package(OpenCV REQUIRED)
###############################################
############ Add static libs ##################
# list(APPEND ADD_STATIC_LIB "lib/libtest.a")
###############################################
#### Add compile option for this component ####
#### Just for this component, won't affect other
#### modules, including component that depend
#### on this component
# list(APPEND ADD_DEFINITIONS_PRIVATE -DAAAAA=1)
#### Add compile option for this component
#### and components depend on this component
# list(APPEND ADD_DEFINITIONS -DAAAAA222=1
# -DAAAAA333=1)
###############################################
############ Add static libs ##################
#### Update parent's variables like CMAKE_C_LINK_FLAGS
# set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group libmaix/libtest.a -ltest2 -Wl,--end-group" PARENT_SCOPE)
###############################################
######### Add files need to download #########
# list(APPEND ADD_FILE_DOWNLOADS "{
# 'url': 'https://*****/abcde.tar.xz',
# 'urls': [], # backup urls, if url failed, will try urls
# 'sites': [], # download site, user can manually download file and put it into dl_path
# 'sha256sum': '',
# 'filename': 'abcde.tar.xz',
# 'path': 'toolchains/xxxxx',
# 'check_files': []
# }"
# )
#
# then extracted file in ${DL_EXTRACTED_PATH}/toolchains/xxxxx,
# you can directly use then, for example use it in add_custom_command
##############################################
# register component, DYNAMIC or SHARED flags will make component compiled to dynamic(shared) lib
register_component()

View File

View File

@@ -0,0 +1,6 @@
FetchContent_Declare(portaudio
URL https://github.com/PortAudio/portaudio/archive/refs/tags/v19.7.0.tar.gz
URL_HASH SHA256=5af29ba58bbdbb7bbcefaaecc77ec8fc413f0db6f4c4e286c40c3e1b83174fa0
)
FetchContent_MakeAvailable(portaudio)
include_directories(${portaudio_SOURCE_DIR}/include)

View File

@@ -0,0 +1,11 @@
add_executable(kws_main kws_main.cc)
target_link_libraries(kws_main PUBLIC onnxruntime frontend kws)
add_executable(kws_speechcommand kws_speechcommand.cc)
target_link_libraries(kws_speechcommand PUBLIC onnxruntime frontend kws)
add_executable(stream_kws_main stream_kws_main.cc )
target_link_libraries(stream_kws_main PUBLIC onnxruntime frontend kws portaudio_static)
add_executable(stream_kws_speechcommand stream_kws_speechcommand.cc)
target_link_libraries(stream_kws_speechcommand PUBLIC onnxruntime frontend kws portaudio_static)

View File

@@ -0,0 +1,66 @@
// Copyright (c) 2022 Binbin Zhang (binbzha@qq.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#include <string>
#include "frontend/feature_pipeline.h"
#include "frontend/wav.h"
#include "kws/keyword_spotting.h"
#include "utils/log.h"
int main(int argc, char* argv[]) {
if (argc != 5) {
LOG(FATAL) << "Usage: kws_main fbank_dim(int) batch_size(int) "
<< "kws_model_path test_wav_path";
}
const int num_bins = std::stoi(argv[1]); // Fbank feature dim
const int batch_size = std::stoi(argv[2]);
const std::string model_path = argv[3];
const std::string wav_path = argv[4];
wenet::WavReader wav_reader(wav_path);
int num_samples = wav_reader.num_samples();
wenet::FeaturePipelineConfig feature_config(num_bins, 16000);
feature_config.Info();
wenet::FeaturePipeline feature_pipeline(feature_config);
std::vector<float> wav(wav_reader.data(), wav_reader.data() + num_samples);
feature_pipeline.AcceptWaveform(wav);
feature_pipeline.set_input_finished();
wekws::KeywordSpotting spotter(model_path);
// Simulate streaming, detect batch by batch
int offset = 0;
while (true) {
std::vector<std::vector<float>> feats;
bool ok = feature_pipeline.Read(batch_size, &feats);
std::vector<std::vector<float>> prob;
spotter.Forward(feats, &prob);
for (int i = 0; i < prob.size(); i++) {
std::cout << "frame " << offset + i << " prob";
for (int j = 0; j < prob[i].size(); j++) {
std::cout << " " << prob[i][j];
}
std::cout << std::endl;
}
// Reach the end of feature pipeline
if (!ok) break;
offset += prob.size();
}
return 0;
}

View File

@@ -0,0 +1,80 @@
// Copyright (c) 2022 Binbin Zhang (binbzha@qq.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#include <string>
#include "frontend/feature_pipeline.h"
#include "frontend/wav.h"
#include "kws/keyword_spotting.h"
#include "utils/log.h"
static void check_result(std::vector<std::vector<float>> results)
{
printf("result number:%ld\r\n", results.size());
static std::string name[11] = {"wow", "yes", "no", "up", "down", "left", "right", "on", "off", "stop", "go"};
for (auto &result: results) {
// printf("result.size():%d", result.size());
for (int i = 0; i < result.size(); i ++) {
printf("%s:%.5f ", name[i].c_str(), result[i]);
}
printf("\r\n");
}
}
int main(int argc, char* argv[]) {
if (argc != 5) {
LOG(FATAL) << "Usage: kws_main fbank_dim(int) batch_size(int) "
<< "kws_model_path test_wav_path";
}
const int num_bins = std::stoi(argv[1]); // Fbank feature dim
const int batch_size = std::stoi(argv[2]);
const std::string model_path = argv[3];
const std::string wav_path = argv[4];
wenet::WavReader wav_reader(wav_path);
int num_samples = wav_reader.num_samples();
wenet::FeaturePipelineConfig feature_config(num_bins, 16000);
wenet::FeaturePipeline feature_pipeline(feature_config);
std::vector<float> wav(wav_reader.data(), wav_reader.data() + num_samples);
feature_pipeline.AcceptWaveform(wav);
feature_pipeline.set_input_finished();
wekws::KeywordSpotting spotter(model_path);
// Simulate streaming, detect batch by batch
int offset = 0;
while (true) {
std::vector<std::vector<float>> feats;
bool ok = feature_pipeline.Read(batch_size, &feats);
std::vector<std::vector<float>> prob;
spotter.Forward(feats, &prob);
check_result(prob);
// for (int i = 0; i < prob.size(); i++) {
// std::cout << "frame " << offset + i << " prob";
// for (int j = 0; j < prob[i].size(); j++) {
// // std::cout << " " << prob[i][j];
// printf(" %f", prob[i][j]);
// }
// std::cout << std::endl;
// }
// Reach the end of feature pipeline
if (!ok) break;
offset += prob.size();
}
return 0;
}

View File

@@ -0,0 +1,109 @@
// Copyright (c) 2022 Zhendong Peng (pzd17@tsinghua.org.cn)
//
// 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 <signal.h>
#include <iomanip>
#include <iostream>
#include <string>
#include "portaudio.h" // NOLINT
#include "frontend/feature_pipeline.h"
#include "frontend/wav.h"
#include "kws/keyword_spotting.h"
#include "utils/log.h"
int g_exiting = 0;
std::shared_ptr<wenet::FeaturePipeline> g_feature_pipeline;
void SigRoutine(int dunno) {
if (dunno == SIGINT) {
g_exiting = 1;
}
}
static int RecordCallback(const void* input, void* output,
unsigned long frames_count, // NOLINT
const PaStreamCallbackTimeInfo* time_info,
PaStreamCallbackFlags status_flags, void* user_data) {
const auto* pcm_data = static_cast<const int16_t*>(input);
std::vector<int16_t> v(pcm_data, pcm_data + frames_count);
g_feature_pipeline->AcceptWaveform(v);
if (g_exiting) {
LOG(INFO) << "Exiting loop.";
g_feature_pipeline->set_input_finished();
return paComplete;
} else {
return paContinue;
}
}
int main(int argc, char* argv[]) {
if (argc != 4) {
LOG(FATAL) << "Usage: kws_main fbank_dim batch_size kws_model_path";
}
const int num_bins = std::stoi(argv[1]); // Fbank feature dim
const int batch_size = std::stoi(argv[2]);
const std::string model_path = argv[3];
wenet::FeaturePipelineConfig feature_config(num_bins, 16000);
g_feature_pipeline = std::make_shared<wenet::FeaturePipeline>(feature_config);
wekws::KeywordSpotting spotter(model_path);
signal(SIGINT, SigRoutine);
PaError err = Pa_Initialize();
PaStreamParameters params;
std::cout << err << " " << Pa_GetDeviceCount() << std::endl;
params.device = Pa_GetDefaultInputDevice();
if (params.device == paNoDevice) {
LOG(FATAL) << "Error: No default input device.";
}
params.channelCount = 1;
params.sampleFormat = paInt16;
params.suggestedLatency =
Pa_GetDeviceInfo(params.device)->defaultLowInputLatency;
params.hostApiSpecificStreamInfo = NULL;
PaStream* stream;
// Callback and spot pcm date each `interval` ms.
int interval = 500;
int frames_per_buffer = 16000 / 1000 * interval;
Pa_OpenStream(&stream, &params, NULL, 16000, frames_per_buffer, paClipOff,
RecordCallback, NULL);
Pa_StartStream(stream);
LOG(INFO) << "=== Now recording!! Please speak into the microphone. ===";
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(2);
while (Pa_IsStreamActive(stream)) {
Pa_Sleep(interval);
std::vector<std::vector<float>> feats;
g_feature_pipeline->Read(batch_size, &feats);
std::vector<std::vector<float>> prob;
spotter.Forward(feats, &prob);
for (int t = 0; t < prob.size(); t++) {
for (int i = 0; i < prob[t].size(); i++) {
if (prob[t][i] > 0.001) {
printf("kw[%d][%d] %f\r\n", t, i, prob[t][i]);
// std::cout << " kw[" << i << "] " << prob[t][i];
}
}
// std::cout << std::endl;
}
}
Pa_CloseStream(stream);
Pa_Terminate();
return 0;
}

View File

@@ -0,0 +1,124 @@
// Copyright (c) 2022 Zhendong Peng (pzd17@tsinghua.org.cn)
//
// 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 <signal.h>
#include <iomanip>
#include <iostream>
#include <string>
#include "portaudio.h" // NOLINT
#include "frontend/feature_pipeline.h"
#include "frontend/wav.h"
#include "kws/keyword_spotting.h"
#include "utils/log.h"
int g_exiting = 0;
std::shared_ptr<wenet::FeaturePipeline> g_feature_pipeline;
void SigRoutine(int dunno) {
if (dunno == SIGINT) {
g_exiting = 1;
}
}
static int RecordCallback(const void* input, void* output,
unsigned long frames_count, // NOLINT
const PaStreamCallbackTimeInfo* time_info,
PaStreamCallbackFlags status_flags, void* user_data) {
const auto* pcm_data = static_cast<const int16_t*>(input);
std::vector<int16_t> v(pcm_data, pcm_data + frames_count);
g_feature_pipeline->AcceptWaveform(v);
if (g_exiting) {
LOG(INFO) << "Exiting loop.";
g_feature_pipeline->set_input_finished();
return paComplete;
} else {
return paContinue;
}
}
static void check_result(std::vector<std::vector<float>> results)
{
printf("result number:%ld", results.size());
static std::string name[11] = {"wow", "yes", "no", "up", "down", "left", "right", "on", "off", "stop", "go"};
for (auto &result: results) {
for (int i = 0; i < result.size(); i ++) {
printf("%s:%.5f ", name[i].c_str(), result[i]);
}
printf("\r\n");
}
}
int main(int argc, char* argv[]) {
if (argc != 4) {
LOG(FATAL) << "Usage: kws_main fbank_dim batch_size kws_model_path";
}
const int num_bins = std::stoi(argv[1]); // Fbank feature dim
const int batch_size = std::stoi(argv[2]);
const std::string model_path = argv[3];
wenet::FeaturePipelineConfig feature_config(num_bins, 16000);
g_feature_pipeline = std::make_shared<wenet::FeaturePipeline>(feature_config);
wekws::KeywordSpotting spotter(model_path);
signal(SIGINT, SigRoutine);
PaError err = Pa_Initialize();
PaStreamParameters params;
std::cout << err << " " << Pa_GetDeviceCount() << std::endl;
params.device = Pa_GetDefaultInputDevice();
if (params.device == paNoDevice) {
LOG(FATAL) << "Error: No default input device.";
}
params.channelCount = 1;
params.sampleFormat = paInt16;
params.suggestedLatency =
Pa_GetDeviceInfo(params.device)->defaultLowInputLatency;
params.hostApiSpecificStreamInfo = NULL;
PaStream* stream;
// Callback and spot pcm date each `interval` ms.
int interval = 500;
int frames_per_buffer = 16000 / 1000 * interval;
Pa_OpenStream(&stream, &params, NULL, 16000, frames_per_buffer, paClipOff,
RecordCallback, NULL);
Pa_StartStream(stream);
LOG(INFO) << "=== Now recording!! Please speak into the microphone. ===";
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(2);
printf(" =============== [%s][%d]\r\n", __func__, __LINE__);
while (Pa_IsStreamActive(stream)) {printf(" =============== [%s][%d]\r\n", __func__, __LINE__);
Pa_Sleep(interval);printf(" =============== [%s][%d]\r\n", __func__, __LINE__);
std::vector<std::vector<float>> feats;printf(" =============== [%s][%d]\r\n", __func__, __LINE__);
g_feature_pipeline->Read(batch_size, &feats);printf(" =============== [%s][%d]\r\n", __func__, __LINE__);
std::vector<std::vector<float>> prob;printf(" =============== [%s][%d]\r\n", __func__, __LINE__);
spotter.Forward(feats, &prob);printf(" =============== [%s][%d]\r\n", __func__, __LINE__);
check_result(prob);
// for (int t = 0; t < prob.size(); t++) {
// for (int i = 0; i < prob[t].size(); i++) {
// if (prob[t][i] > 0.001) {
// printf("kw[%d][%d] %f\r\n", t, i, prob[t][i]);
// // std::cout << " kw[" << i << "] " << prob[t][i];
// }
// }
// // std::cout << std::endl;
// }
}
Pa_CloseStream(stream);
Pa_Terminate();
return 0;
}

View File

@@ -0,0 +1,16 @@
set(ONNX_VERSION "1.12.0")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
set(ONNX_URL "https://github.com/microsoft/onnxruntime/releases/download/v${ONNX_VERSION}/onnxruntime-linux-aarch64-${ONNX_VERSION}.tgz")
set(URL_HASH "SHA256=5820d9f343df73c63b6b2b174a1ff62575032e171c9564bcf92060f46827d0ac")
else()
set(ONNX_URL "https://github.com/microsoft/onnxruntime/releases/download/v${ONNX_VERSION}/onnxruntime-linux-x64-${ONNX_VERSION}.tgz")
set(URL_HASH "SHA256=5d503ce8540358b59be26c675e42081be14a3e833a5301926f555451046929c5")
endif()
FetchContent_Declare(onnxruntime
URL ${ONNX_URL}
URL_HASH ${URL_HASH}
)
FetchContent_MakeAvailable(onnxruntime)
include_directories(${onnxruntime_SOURCE_DIR}/include)
link_directories(${onnxruntime_SOURCE_DIR}/lib)

View File

@@ -0,0 +1,6 @@
FetchContent_Declare(portaudio
URL https://github.com/PortAudio/portaudio/archive/refs/tags/v19.7.0.tar.gz
URL_HASH SHA256=5af29ba58bbdbb7bbcefaaecc77ec8fc413f0db6f4c4e286c40c3e1b83174fa0
)
FetchContent_MakeAvailable(portaudio)
include_directories(${portaudio_SOURCE_DIR}/include)

View File

@@ -0,0 +1,4 @@
add_library(frontend STATIC
feature_pipeline.cc
fft.cc
)

View File

@@ -0,0 +1,222 @@
// Copyright (c) 2017 Personal (Binbin Zhang)
//
// 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 FRONTEND_FBANK_H_
#define FRONTEND_FBANK_H_
#include <cstring>
#include <limits>
#include <random>
#include <utility>
#include <vector>
#include "frontend/fft.h"
#include "utils/log.h"
namespace wenet {
// This code is based on kaldi Fbank implentation, please see
// https://github.com/kaldi-asr/kaldi/blob/master/src/feat/feature-fbank.cc
class Fbank {
public:
Fbank(int num_bins, int sample_rate, int frame_length, int frame_shift)
: num_bins_(num_bins),
sample_rate_(sample_rate),
frame_length_(frame_length),
frame_shift_(frame_shift),
use_log_(true),
remove_dc_offset_(true),
generator_(0),
distribution_(0, 1.0),
dither_(0.0) {
fft_points_ = UpperPowerOfTwo(frame_length_);
// generate bit reversal table and trigonometric function table
const int fft_points_4 = fft_points_ / 4;
bitrev_.resize(fft_points_);
sintbl_.resize(fft_points_ + fft_points_4);
make_sintbl(fft_points_, sintbl_.data());
make_bitrev(fft_points_, bitrev_.data());
int num_fft_bins = fft_points_ / 2;
float fft_bin_width = static_cast<float>(sample_rate_) / fft_points_;
int low_freq = 20, high_freq = sample_rate_ / 2;
float mel_low_freq = MelScale(low_freq);
float mel_high_freq = MelScale(high_freq);
float mel_freq_delta = (mel_high_freq - mel_low_freq) / (num_bins + 1);
bins_.resize(num_bins_);
center_freqs_.resize(num_bins_);
for (int bin = 0; bin < num_bins; ++bin) {
float left_mel = mel_low_freq + bin * mel_freq_delta,
center_mel = mel_low_freq + (bin + 1) * mel_freq_delta,
right_mel = mel_low_freq + (bin + 2) * mel_freq_delta;
center_freqs_[bin] = InverseMelScale(center_mel);
std::vector<float> this_bin(num_fft_bins);
int first_index = -1, last_index = -1;
for (int i = 0; i < num_fft_bins; ++i) {
float freq = (fft_bin_width * i); // Center frequency of this fft
// bin.
float mel = MelScale(freq);
if (mel > left_mel && mel < right_mel) {
float weight;
if (mel <= center_mel)
weight = (mel - left_mel) / (center_mel - left_mel);
else
weight = (right_mel - mel) / (right_mel - center_mel);
this_bin[i] = weight;
if (first_index == -1) first_index = i;
last_index = i;
}
}
CHECK(first_index != -1 && last_index >= first_index);
bins_[bin].first = first_index;
int size = last_index + 1 - first_index;
bins_[bin].second.resize(size);
for (int i = 0; i < size; ++i) {
bins_[bin].second[i] = this_bin[first_index + i];
}
}
// NOTE(cdliang): add hamming window
hamming_window_.resize(frame_length_);
double a = M_2PI / (frame_length - 1);
for (int i = 0; i < frame_length; i++) {
double i_fl = static_cast<double>(i);
hamming_window_[i] = 0.54 - 0.46 * cos(a * i_fl);
}
}
void set_use_log(bool use_log) { use_log_ = use_log; }
void set_remove_dc_offset(bool remove_dc_offset) {
remove_dc_offset_ = remove_dc_offset;
}
void set_dither(float dither) { dither_ = dither; }
int num_bins() const { return num_bins_; }
static inline float InverseMelScale(float mel_freq) {
return 700.0f * (expf(mel_freq / 1127.0f) - 1.0f);
}
static inline float MelScale(float freq) {
return 1127.0f * logf(1.0f + freq / 700.0f);
}
static int UpperPowerOfTwo(int n) {
return static_cast<int>(pow(2, ceil(log(n) / log(2))));
}
// preemphasis
void PreEmphasis(float coeff, std::vector<float>* data) const {
if (coeff == 0.0) return;
for (int i = data->size() - 1; i > 0; i--)
(*data)[i] -= coeff * (*data)[i - 1];
(*data)[0] -= coeff * (*data)[0];
}
// add hamming window
void Hamming(std::vector<float>* data) const {
CHECK(data->size() >= hamming_window_.size());
for (size_t i = 0; i < hamming_window_.size(); ++i) {
(*data)[i] *= hamming_window_[i];
}
}
// Compute fbank feat, return num frames
int Compute(const std::vector<float>& wave,
std::vector<std::vector<float>>* feat) {
int num_samples = wave.size();
if (num_samples < frame_length_) return 0;
int num_frames = 1 + ((num_samples - frame_length_) / frame_shift_);
feat->resize(num_frames);
std::vector<float> fft_real(fft_points_, 0), fft_img(fft_points_, 0);
std::vector<float> power(fft_points_ / 2);
for (int i = 0; i < num_frames; ++i) {
std::vector<float> data(wave.data() + i * frame_shift_,
wave.data() + i * frame_shift_ + frame_length_);
// optional add noise
if (dither_ != 0.0) {
for (size_t j = 0; j < data.size(); ++j)
data[j] += dither_ * distribution_(generator_);
}
// optinal remove dc offset
if (remove_dc_offset_) {
float mean = 0.0;
for (size_t j = 0; j < data.size(); ++j) mean += data[j];
mean /= data.size();
for (size_t j = 0; j < data.size(); ++j) data[j] -= mean;
}
PreEmphasis(0.97, &data);
// Povey(&data);
Hamming(&data);
// copy data to fft_real
memset(fft_img.data(), 0, sizeof(float) * fft_points_);
memset(fft_real.data() + frame_length_, 0,
sizeof(float) * (fft_points_ - frame_length_));
memcpy(fft_real.data(), data.data(), sizeof(float) * frame_length_);
fft(bitrev_.data(), sintbl_.data(), fft_real.data(), fft_img.data(),
fft_points_);
// power
for (int j = 0; j < fft_points_ / 2; ++j) {
power[j] = fft_real[j] * fft_real[j] + fft_img[j] * fft_img[j];
}
(*feat)[i].resize(num_bins_);
// cepstral coefficients, triangle filter array
for (int j = 0; j < num_bins_; ++j) {
float mel_energy = 0.0;
int s = bins_[j].first;
for (size_t k = 0; k < bins_[j].second.size(); ++k) {
mel_energy += bins_[j].second[k] * power[s + k];
}
// optional use log
if (use_log_) {
if (mel_energy < std::numeric_limits<float>::epsilon())
mel_energy = std::numeric_limits<float>::epsilon();
mel_energy = logf(mel_energy);
}
(*feat)[i][j] = mel_energy;
// printf("%f ", mel_energy);
}
// printf("\n");
}
return num_frames;
}
private:
int num_bins_;
int sample_rate_;
int frame_length_, frame_shift_;
int fft_points_;
bool use_log_;
bool remove_dc_offset_;
std::vector<float> center_freqs_;
std::vector<std::pair<int, std::vector<float>>> bins_;
std::vector<float> hamming_window_;
std::default_random_engine generator_;
std::normal_distribution<float> distribution_;
float dither_;
// bit reversal table
std::vector<int> bitrev_;
// trigonometric function table
std::vector<float> sintbl_;
};
} // namespace wenet
#endif // FRONTEND_FBANK_H_

View File

@@ -0,0 +1,113 @@
// Copyright (c) 2017 Personal (Binbin Zhang)
//
// 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 "frontend/feature_pipeline.h"
#include <algorithm>
#include <utility>
namespace wenet {
FeaturePipeline::FeaturePipeline(const FeaturePipelineConfig& config)
: config_(config),
feature_dim_(config.num_bins),
fbank_(config.num_bins, config.sample_rate, config.frame_length,
config.frame_shift),
num_frames_(0),
input_finished_(false) {}
void FeaturePipeline::AcceptWaveform(const std::vector<float>& wav) {
std::vector<std::vector<float>> feats;
std::vector<float> waves;
waves.insert(waves.end(), remained_wav_.begin(), remained_wav_.end());
waves.insert(waves.end(), wav.begin(), wav.end());
int num_frames = fbank_.Compute(waves, &feats);
for (size_t i = 0; i < feats.size(); ++i) {
feature_queue_.Push(std::move(feats[i]));
}
num_frames_ += num_frames;
int left_samples = waves.size() - config_.frame_shift * num_frames;
remained_wav_.resize(left_samples);
std::copy(waves.begin() + config_.frame_shift * num_frames, waves.end(),
remained_wav_.begin());
// We are still adding wave, notify input is not finished
finish_condition_.notify_one();
}
void FeaturePipeline::AcceptWaveform(const std::vector<int16_t>& wav) {
std::vector<float> float_wav(wav.size());
for (size_t i = 0; i < wav.size(); i++) {
float_wav[i] = static_cast<float>(wav[i]);
}
this->AcceptWaveform(float_wav);
}
void FeaturePipeline::set_input_finished() {
CHECK(!input_finished_);
{
std::lock_guard<std::mutex> lock(mutex_);
input_finished_ = true;
}
finish_condition_.notify_one();
}
bool FeaturePipeline::ReadOne(std::vector<float>* feat) {
if (!feature_queue_.Empty()) {
*feat = std::move(feature_queue_.Pop());
return true;
} else {
std::unique_lock<std::mutex> lock(mutex_);
while (!input_finished_) {
// This will release the lock and wait for notify_one()
// from AcceptWaveform() or set_input_finished()
finish_condition_.wait(lock);
if (!feature_queue_.Empty()) {
*feat = std::move(feature_queue_.Pop());
return true;
}
}
CHECK(input_finished_);
// Double check queue.empty, see issue#893 for detailed discussions.
if (!feature_queue_.Empty()) {
*feat = std::move(feature_queue_.Pop());
return true;
} else {
return false;
}
}
}
bool FeaturePipeline::Read(int num_frames,
std::vector<std::vector<float>>* feats) {
feats->clear();
std::vector<float> feat;
while (feats->size() < num_frames) {
if (ReadOne(&feat)) {
feats->push_back(std::move(feat));
} else {
return false;
}
}
return true;
}
void FeaturePipeline::Reset() {
input_finished_ = false;
num_frames_ = 0;
remained_wav_.clear();
feature_queue_.Clear();
}
} // namespace wenet

View File

@@ -0,0 +1,118 @@
// Copyright (c) 2017 Personal (Binbin Zhang)
//
// 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 FRONTEND_FEATURE_PIPELINE_H_
#define FRONTEND_FEATURE_PIPELINE_H_
#include <mutex>
#include <queue>
#include <string>
#include <vector>
#include "frontend/fbank.h"
#include "utils/log.h"
#include "utils/blocking_queue.h"
namespace wenet {
struct FeaturePipelineConfig {
int num_bins;
int sample_rate;
int frame_length;
int frame_shift;
FeaturePipelineConfig(int num_bins, int sample_rate)
: num_bins(num_bins), // 80 dim fbank
sample_rate(sample_rate) { // 16k sample rate
frame_length = sample_rate / 1000 * 25; // frame length 25ms
frame_shift = sample_rate / 1000 * 10; // frame shift 10ms
}
void Info() const {
LOG(INFO) << "feature pipeline config"
<< " num_bins " << num_bins << " frame_length " << frame_length
<< " frame_shift " << frame_shift;
}
};
// Typically, FeaturePipeline is used in two threads: one thread A calls
// AcceptWaveform() to add raw wav data and set_input_finished() to notice
// the end of input wav, another thread B (decoder thread) calls Read() to
// consume features.So a BlockingQueue is used to make this class thread safe.
// The Read() is designed as a blocking method when there is no feature
// in feature_queue_ and the input is not finished.
class FeaturePipeline {
public:
explicit FeaturePipeline(const FeaturePipelineConfig& config);
// The feature extraction is done in AcceptWaveform().
void AcceptWaveform(const std::vector<float>& wav);
void AcceptWaveform(const std::vector<int16_t>& wav);
// Current extracted frames number.
int num_frames() const { return num_frames_; }
int feature_dim() const { return feature_dim_; }
const FeaturePipelineConfig& config() const { return config_; }
// The caller should call this method when speech input is end.
// Never call AcceptWaveform() after calling set_input_finished() !
void set_input_finished();
bool input_finished() const { return input_finished_; }
// Return False if input is finished and no feature could be read.
// Return True if a feature is read.
// This function is a blocking method. It will block the thread when
// there is no feature in feature_queue_ and the input is not finished.
bool ReadOne(std::vector<float>* feat);
// Read #num_frames frame features.
// Return False if less then #num_frames features are read and the
// input is finished.
// Return True if #num_frames features are read.
// This function is a blocking method when there is no feature
// in feature_queue_ and the input is not finished.
bool Read(int num_frames, std::vector<std::vector<float>>* feats);
void Reset();
bool IsLastFrame(int frame) const {
return input_finished_ && (frame == num_frames_ - 1);
}
int NumQueuedFrames() const { return feature_queue_.Size(); }
private:
const FeaturePipelineConfig& config_;
int feature_dim_;
Fbank fbank_;
BlockingQueue<std::vector<float>> feature_queue_;
int num_frames_;
bool input_finished_;
// The feature extraction is done in AcceptWaveform().
// This wavefrom sample points are consumed by frame size.
// The residual wavefrom sample points after framing are
// kept to be used in next AcceptWaveform() calling.
std::vector<float> remained_wav_;
// Used to block the Read when there is no feature in feature_queue_
// and the input is not finished.
mutable std::mutex mutex_;
std::condition_variable finish_condition_;
};
} // namespace wenet
#endif // FRONTEND_FEATURE_PIPELINE_H_

View File

@@ -0,0 +1,121 @@
// Copyright (c) 2016 HR
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "frontend/fft.h"
namespace wenet {
void make_sintbl(int n, float* sintbl) {
int i, n2, n4, n8;
float c, s, dc, ds, t;
n2 = n / 2;
n4 = n / 4;
n8 = n / 8;
t = sin(M_PI / n);
dc = 2 * t * t;
ds = sqrt(dc * (2 - dc));
t = 2 * dc;
c = sintbl[n4] = 1;
s = sintbl[0] = 0;
for (i = 1; i < n8; ++i) {
c -= dc;
dc += t * c;
s += ds;
ds -= t * s;
sintbl[i] = s;
sintbl[n4 - i] = c;
}
if (n8 != 0) sintbl[n8] = sqrt(0.5);
for (i = 0; i < n4; ++i) sintbl[n2 - i] = sintbl[i];
for (i = 0; i < n2 + n4; ++i) sintbl[i + n2] = -sintbl[i];
}
void make_bitrev(int n, int* bitrev) {
int i, j, k, n2;
n2 = n / 2;
i = j = 0;
for (;;) {
bitrev[i] = j;
if (++i >= n) break;
k = n2;
while (k <= j) {
j -= k;
k /= 2;
}
j += k;
}
}
// bitrev: bit reversal table
// sintbl: trigonometric function table
// x:real part
// y:image part
// n: fft length
int fft(const int* bitrev, const float* sintbl, float* x, float* y, int n) {
int i, j, k, ik, h, d, k2, n4, inverse;
float t, s, c, dx, dy;
/* preparation */
if (n < 0) {
n = -n;
inverse = 1; /* inverse transform */
} else {
inverse = 0;
}
n4 = n / 4;
if (n == 0) {
return 0;
}
/* bit reversal */
for (i = 0; i < n; ++i) {
j = bitrev[i];
if (i < j) {
t = x[i];
x[i] = x[j];
x[j] = t;
t = y[i];
y[i] = y[j];
y[j] = t;
}
}
/* transformation */
for (k = 1; k < n; k = k2) {
h = 0;
k2 = k + k;
d = n / k2;
for (j = 0; j < k; ++j) {
c = sintbl[h + n4];
if (inverse)
s = -sintbl[h];
else
s = sintbl[h];
for (i = j; i < n; i += k2) {
ik = i + k;
dx = s * y[ik] + c * x[ik];
dy = c * y[ik] - s * x[ik];
x[ik] = x[i] - dx;
x[i] += dx;
y[ik] = y[i] - dy;
y[i] += dy;
}
h += d;
}
}
if (inverse) {
/* divide by n in case of the inverse transformation */
for (i = 0; i < n; ++i) {
x[i] /= n;
y[i] /= n;
}
}
return 0; /* finished successfully */
}
} // namespace wenet

View File

@@ -0,0 +1,25 @@
// Copyright (c) 2016 HR
#ifndef FRONTEND_FFT_H_
#define FRONTEND_FFT_H_
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
#ifndef M_2PI
#define M_2PI 6.283185307179586476925286766559005
#endif
namespace wenet {
// Fast Fourier Transform
void make_sintbl(int n, float* sintbl);
void make_bitrev(int n, int* bitrev);
int fft(const int* bitrev, const float* sintbl, float* x, float* y, int n);
} // namespace wenet
#endif // FRONTEND_FFT_H_

View File

@@ -0,0 +1,203 @@
// Copyright (c) 2016 Personal (Binbin Zhang)
// Created on 2016-08-15
//
// 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 FRONTEND_WAV_H_
#define FRONTEND_WAV_H_
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "utils/log.h"
namespace wenet {
struct WavHeader {
char riff[4]; // "riff"
unsigned int size;
char wav[4]; // "WAVE"
char fmt[4]; // "fmt "
unsigned int fmt_size;
uint16_t format;
uint16_t channels;
unsigned int sample_rate;
unsigned int bytes_per_second;
uint16_t block_size;
uint16_t bit;
char data[4]; // "data"
unsigned int data_size;
};
class WavReader {
public:
WavReader() : data_(nullptr) {}
explicit WavReader(const std::string& filename) { Open(filename); }
bool Open(const std::string& filename) {
FILE* fp = fopen(filename.c_str(), "rb");
if (NULL == fp) {
LOG(WARNING) << "Error in read " << filename;
return false;
}
WavHeader header;
fread(&header, 1, sizeof(header), fp);
if (header.fmt_size < 16) {
fprintf(stderr,
"WaveData: expect PCM format data "
"to have fmt chunk of at least size 16.\n");
return false;
} else if (header.fmt_size > 16) {
int offset = 44 - 8 + header.fmt_size - 16;
fseek(fp, offset, SEEK_SET);
fread(header.data, 8, sizeof(char), fp);
}
// check "riff" "WAVE" "fmt " "data"
// Skip any subchunks between "fmt" and "data". Usually there will
// be a single "fact" subchunk, but on Windows there can also be a
// "list" subchunk.
while (0 != strncmp(header.data, "data", 4)) {
// We will just ignore the data in these chunks.
fseek(fp, header.data_size, SEEK_CUR);
// read next subchunk
fread(header.data, 8, sizeof(char), fp);
}
num_channel_ = header.channels;
sample_rate_ = header.sample_rate;
bits_per_sample_ = header.bit;
int num_data = header.data_size / (bits_per_sample_ / 8);
data_ = new float[num_data];
num_samples_ = num_data / num_channel_;
for (int i = 0; i < num_data; ++i) {
switch (bits_per_sample_) {
case 8: {
char sample;
fread(&sample, 1, sizeof(char), fp);
data_[i] = static_cast<float>(sample);
break;
}
case 16: {
int16_t sample;
fread(&sample, 1, sizeof(int16_t), fp);
data_[i] = static_cast<float>(sample);
break;
}
case 32: {
int sample;
fread(&sample, 1, sizeof(int), fp);
data_[i] = static_cast<float>(sample);
break;
}
default:
fprintf(stderr, "unsupported quantization bits");
exit(1);
}
}
fclose(fp);
return true;
}
int num_channel() const { return num_channel_; }
int sample_rate() const { return sample_rate_; }
int bits_per_sample() const { return bits_per_sample_; }
int num_samples() const { return num_samples_; }
~WavReader() {
if (data_ != NULL) delete[] data_;
}
const float* data() const { return data_; }
private:
int num_channel_;
int sample_rate_;
int bits_per_sample_;
int num_samples_; // sample points per channel
float* data_;
};
class WavWriter {
public:
WavWriter(const float* data, int num_samples, int num_channel,
int sample_rate, int bits_per_sample)
: data_(data),
num_samples_(num_samples),
num_channel_(num_channel),
sample_rate_(sample_rate),
bits_per_sample_(bits_per_sample) {}
void Write(const std::string& filename) {
FILE* fp = fopen(filename.c_str(), "w");
// init char 'riff' 'WAVE' 'fmt ' 'data'
WavHeader header;
char wav_header[44] = {0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57,
0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00};
memcpy(&header, wav_header, sizeof(header));
header.channels = num_channel_;
header.bit = bits_per_sample_;
header.sample_rate = sample_rate_;
header.data_size = num_samples_ * num_channel_ * (bits_per_sample_ / 8);
header.size = sizeof(header) - 8 + header.data_size;
header.bytes_per_second =
sample_rate_ * num_channel_ * (bits_per_sample_ / 8);
header.block_size = num_channel_ * (bits_per_sample_ / 8);
fwrite(&header, 1, sizeof(header), fp);
for (int i = 0; i < num_samples_; ++i) {
for (int j = 0; j < num_channel_; ++j) {
switch (bits_per_sample_) {
case 8: {
char sample = static_cast<char>(data_[i * num_channel_ + j]);
fwrite(&sample, 1, sizeof(sample), fp);
break;
}
case 16: {
int16_t sample = static_cast<int16_t>(data_[i * num_channel_ + j]);
fwrite(&sample, 1, sizeof(sample), fp);
break;
}
case 32: {
int sample = static_cast<int>(data_[i * num_channel_ + j]);
fwrite(&sample, 1, sizeof(sample), fp);
break;
}
}
}
}
fclose(fp);
}
private:
const float* data_;
int num_samples_; // total float points in data_
int num_channel_;
int sample_rate_;
int bits_per_sample_;
};
} // namespace wenet
#endif // FRONTEND_WAV_H_

View File

@@ -0,0 +1 @@
add_library(kws STATIC keyword_spotting.cc)

View File

@@ -0,0 +1,117 @@
// Copyright (c) 2022 Binbin Zhang (binbzha@qq.com)
//
// 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 "kws/keyword_spotting.h"
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <vector>
namespace wekws {
Ort::Env KeywordSpotting::env_ = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "");
Ort::SessionOptions KeywordSpotting::session_options_ = Ort::SessionOptions();
KeywordSpotting::KeywordSpotting(const std::string& model_path) {
// 1. Load sessions
session_ = std::make_shared<Ort::Session>(env_, model_path.c_str(),
session_options_);
// 2. Model info
in_names_ = {"input", "cache"};
out_names_ = {"output", "r_cache"};
auto metadata = session_->GetModelMetadata();
Ort::AllocatorWithDefaultOptions allocator;
cache_dim_ = std::stoi(metadata.LookupCustomMetadataMap("cache_dim",
allocator));
cache_len_ = std::stoi(metadata.LookupCustomMetadataMap("cache_len",
allocator));
std::cout << "Kws Model Info:" << std::endl
<< "\tcache_dim: " << cache_dim_ << std::endl
<< "\tcache_len: " << cache_len_ << std::endl;
Reset();
}
void KeywordSpotting::Reset() {
Ort::MemoryInfo memory_info =
Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
cache_.resize(cache_dim_ * cache_len_, 0.0);
const int64_t cache_shape[] = {1, cache_dim_, cache_len_};
cache_ort_ = Ort::Value::CreateTensor<float>(
memory_info, cache_.data(), cache_.size(), cache_shape, 3);
}
void KeywordSpotting::Forward(
const std::vector<std::vector<float>>& feats,
std::vector<std::vector<float>>* prob) {
prob->clear();
if (feats.size() == 0) return;
Ort::MemoryInfo memory_info =
Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
// 1. Prepare input
int num_frames = feats.size();
int feature_dim = feats[0].size();
std::vector<float> slice_feats;
for (int i = 0; i < feats.size(); i++) {
slice_feats.insert(slice_feats.end(), feats[i].begin(), feats[i].end());
}
const int64_t feats_shape[3] = {1, num_frames, feature_dim};
Ort::Value feats_ort = Ort::Value::CreateTensor<float>(
memory_info, slice_feats.data(), slice_feats.size(), feats_shape, 3);
// 2. Ort forward
std::vector<Ort::Value> inputs;
inputs.emplace_back(std::move(feats_ort));
inputs.emplace_back(std::move(cache_ort_));
// ort_outputs.size() == 2
std::vector<Ort::Value> ort_outputs = session_->Run(
Ort::RunOptions{nullptr}, in_names_.data(), inputs.data(),
inputs.size(), out_names_.data(), out_names_.size());
// 3. Update cache
cache_ort_ = std::move(ort_outputs[1]);
// 4. Get keyword prob
float* data = ort_outputs[0].GetTensorMutableData<float>();
auto type_info = ort_outputs[0].GetTensorTypeAndShapeInfo();
auto shape = type_info.GetShape();
int num_outputs = 1;
int output_dim = 1;
if (shape.size() == 1) {
num_outputs = 1;
output_dim = 1;
} else if (shape.size() == 2) {
num_outputs = type_info.GetShape()[0];
output_dim = type_info.GetShape()[1];
} else if (shape.size() == 3) {
num_outputs = type_info.GetShape()[1];
output_dim = type_info.GetShape()[2];
} else {
printf("unknowdn shape size:%d", shape.size());
return;
}
prob->resize(num_outputs);
for (int i = 0; i < num_outputs; i++) {
(*prob)[i].resize(output_dim);
memcpy((*prob)[i].data(), data + i * output_dim,
sizeof(float) * output_dim);
}
}
} // namespace wekws

View File

@@ -0,0 +1,61 @@
// Copyright (c) 2022 Binbin Zhang (binbzha@qq.com)
//
// 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 KWS_KEYWORD_SPOTTING_H_
#define KWS_KEYWORD_SPOTTING_H_
#include <memory>
#include <string>
#include <vector>
#include "onnxruntime_cxx_api.h" // NOLINT
namespace wekws {
class KeywordSpotting {
public:
explicit KeywordSpotting(const std::string& model_path);
// Call reset if keyword is detected
void Reset();
static void InitEngineThreads(int num_threads) {
session_options_.SetIntraOpNumThreads(num_threads);
session_options_.SetInterOpNumThreads(num_threads);
}
void Forward(const std::vector<std::vector<float>>& feats,
std::vector<std::vector<float>>* prob);
private:
// session
static Ort::Env env_;
static Ort::SessionOptions session_options_;
std::shared_ptr<Ort::Session> session_ = nullptr;
// node names
std::vector<const char*> in_names_;
std::vector<const char*> out_names_;
// meta info
int cache_dim_ = 0;
int cache_len_ = 0;
// cache info
Ort::Value cache_ort_{nullptr};
std::vector<float> cache_;
};
} // namespace wekws
#endif // KWS_KEYWORD_SPOTTING_H_

View File

@@ -0,0 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)

View File

@@ -0,0 +1,98 @@
// Copyright (c) 2020 Mobvoi Inc (Binbin Zhang)
//
// 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 UTILS_BLOCKING_QUEUE_H_
#define UTILS_BLOCKING_QUEUE_H_
#include <condition_variable>
#include <limits>
#include <mutex>
#include <queue>
#include <utility>
namespace wenet {
#define WENET_DISALLOW_COPY_AND_ASSIGN(Type) \
Type(const Type&) = delete; \
Type& operator=(const Type&) = delete;
template <typename T>
class BlockingQueue {
public:
explicit BlockingQueue(size_t capacity = std::numeric_limits<int>::max())
: capacity_(capacity) {}
void Push(const T& value) {
{
std::unique_lock<std::mutex> lock(mutex_);
while (queue_.size() >= capacity_) {
not_full_condition_.wait(lock);
}
queue_.push(value);
}
not_empty_condition_.notify_one();
}
void Push(T&& value) {
{
std::unique_lock<std::mutex> lock(mutex_);
while (queue_.size() >= capacity_) {
not_full_condition_.wait(lock);
}
queue_.push(std::move(value));
}
not_empty_condition_.notify_one();
}
T Pop() {
std::unique_lock<std::mutex> lock(mutex_);
while (queue_.empty()) {
not_empty_condition_.wait(lock);
}
T t(std::move(queue_.front()));
queue_.pop();
not_full_condition_.notify_one();
return t;
}
bool Empty() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.empty();
}
size_t Size() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.size();
}
void Clear() {
while (!Empty()) {
Pop();
}
}
private:
size_t capacity_;
mutable std::mutex mutex_;
std::condition_variable not_full_condition_;
std::condition_variable not_empty_condition_;
std::queue<T> queue_;
public:
WENET_DISALLOW_COPY_AND_ASSIGN(BlockingQueue);
};
} // namespace wenet
#endif // UTILS_BLOCKING_QUEUE_H_

View File

@@ -0,0 +1,83 @@
// Copyright (c) 2022 Binbin Zhang (binbzha@qq.com)
//
// 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 UTILS_LOG_H_
#define UTILS_LOG_H_
#include <stdlib.h>
#include <iostream>
#include <sstream>
namespace wenet {
const int INFO = 0, WARNING = 1, ERROR = 2, FATAL = 3;
class Logger {
public:
Logger(int severity, const char* func, const char* file, int line) {
severity_ = severity;
switch (severity) {
case INFO:
ss_ << "INFO (";
break;
case WARNING:
ss_ << "WARNING (";
break;
case ERROR:
ss_ << "ERROR (";
break;
case FATAL:
ss_ << "FATAL (";
break;
default:
severity_ = FATAL;
ss_ << "FATAL (";
}
ss_ << func << "():" << file << ':' << line << ") ";
}
~Logger() {
std::cerr << ss_.str() << std::endl << std::flush;
if (severity_ == FATAL) {
abort();
}
}
template <typename T> Logger& operator<<(const T &val) {
ss_ << val;
return *this;
}
private:
int severity_;
std::ostringstream ss_;
};
#define LOG(severity) ::wenet::Logger( \
::wenet::severity, __func__, __FILE__, __LINE__)
#define CHECK(test) \
do { \
if (!(test)) { \
std::cerr << "CHECK (" << __func__ << "():" << __FILE__ << ":" \
<< __LINE__ << ") " << #test << std::endl; \
exit(-1); \
} \
} while (0)
} // namespace wenet
#endif // UTILS_LOG_H_

View File

@@ -0,0 +1,3 @@
#pragma once

View File

@@ -0,0 +1,2 @@
!lib/libonnxruntime.so
!lib/libonnxruntime.so.1.21.0

View File

@@ -0,0 +1 @@
f4663641764ccc3e93a617ab63ae4ff1badc2ee1

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,21 @@
# Privacy
## Data Collection
The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft's privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
***
### Private Builds
No data collection is performed when using your private builds built from source code.
### Official Builds
ONNX Runtime does not maintain any independent telemetry collection mechanisms outside of what is provided by the platforms it supports. However, where applicable, ONNX Runtime will take advantage of platform-supported telemetry systems to collect trace events with the goal of improving product quality.
Currently telemetry is only implemented for Windows builds and is turned **ON** by default in the official builds distributed in their respective package management repositories ([see here](../README.md#binaries)). This may be expanded to cover other platforms in the future. Data collection is implemented via 'Platform Telemetry' per vendor platform providers (see [telemetry.h](../onnxruntime/core/platform/telemetry.h)).
#### Technical Details
The Windows provider uses the [TraceLogging](https://docs.microsoft.com/en-us/windows/win32/tracelogging/trace-logging-about) API for its implementation. This enables ONNX Runtime trace events to be collected by the operating system, and based on user consent, this data may be periodically sent to Microsoft servers following GDPR and privacy regulations for anonymity and data access controls.
Windows ML and onnxruntime C APIs allow Trace Logging to be turned on/off (see [API pages](../README.md#api-documentation) for details).
For information on how to enable and disable telemetry, see [C API: Telemetry](./C_API.md#telemetry).
There are equivalent APIs in the C#, Python, and Java language bindings as well.

View File

@@ -0,0 +1,52 @@
<p align="center"><img width="50%" src="docs/images/ONNX_Runtime_logo_dark.png" /></p>
**ONNX Runtime is a cross-platform inference and training machine-learning accelerator**.
**ONNX Runtime inference** can enable faster customer experiences and lower costs, supporting models from deep learning frameworks such as PyTorch and TensorFlow/Keras as well as classical machine learning libraries such as scikit-learn, LightGBM, XGBoost, etc. ONNX Runtime is compatible with different hardware, drivers, and operating systems, and provides optimal performance by leveraging hardware accelerators where applicable alongside graph optimizations and transforms. [Learn more &rarr;](https://www.onnxruntime.ai/docs/#onnx-runtime-for-inferencing)
**ONNX Runtime training** can accelerate the model training time on multi-node NVIDIA GPUs for transformer models with a one-line addition for existing PyTorch training scripts. [Learn more &rarr;](https://www.onnxruntime.ai/docs/#onnx-runtime-for-training)
## Get Started
**General Information**: [onnxruntime.ai](https://onnxruntime.ai)
**Usage documention and tutorials**: [onnxruntime.ai/docs](https://onnxruntime.ai/docs)
**Companion sample repositories**:
- ONNX Runtime Inferencing: [microsoft/onnxruntime-inference-examples](https://github.com/microsoft/onnxruntime-inference-examples)
- ONNX Runtime Training: [microsoft/onnxruntime-training-examples](https://github.com/microsoft/onnxruntime-training-examples)
## Build Pipeline Status
|System|CPU|GPU|EPs|
|---|---|---|---|
|Windows|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Windows%20CPU%20CI%20Pipeline?label=Windows+CPU)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=9)|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Windows%20GPU%20CI%20Pipeline?label=Windows+GPU)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=10)|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Windows%20GPU%20TensorRT%20CI%20Pipeline?label=Windows+GPU+TensorRT)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=47)|
|Linux|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Linux%20CPU%20CI%20Pipeline?label=Linux+CPU)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=11)<br>[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Linux%20CPU%20Minimal%20Build%20E2E%20CI%20Pipeline?label=Linux+CPU+Minimal+Build)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=64)<br>[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Linux%20CPU%20x64%20NoContribops%20CI%20Pipeline?label=Linux+CPU+x64+No+Contrib+Ops)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=110)<br>[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/centos7_cpu?label=Linux+CentOS7)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=78)<br>[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/orttraining-linux-ci-pipeline?label=Linux+CPU+Training)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=86)|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Linux%20GPU%20CI%20Pipeline?label=Linux+GPU)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=12)<br>[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Linux%20GPU%20TensorRT%20CI%20Pipeline?label=Linux+GPU+TensorRT)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=45)<br>[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/orttraining-distributed?label=Distributed+Training)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=140)<br>[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/orttraining-linux-gpu-ci-pipeline?label=Linux+GPU+Training)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=84)|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Linux%20NUPHAR%20CI%20Pipeline?label=Linux+NUPHAR)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=110)<br>[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Linux%20OpenVINO%20CI%20Pipeline?label=Linux+OpenVINO)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=55)|
|Mac|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/MacOS%20CI%20Pipeline?label=MacOS+CPU)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=13)<br>[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/MacOS%20NoContribops%20CI%20Pipeline?label=MacOS+NoContribops)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=65)|||
|Android|||[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Android%20CI%20Pipeline?label=Android)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=53)|
|iOS|||[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/iOS%20CI%20Pipeline?label=iOS)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=134)|
|WebAssembly|||[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Windows%20WebAssembly%20CI%20Pipeline?label=WASM)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=161)|
## Data/Telemetry
Windows distributions of this project may collect usage data and send it to Microsoft to help improve our products and services. See the [privacy statement](docs/Privacy.md) for more details.
## Contributions and Feedback
We welcome contributions! Please see the [contribution guidelines](CONTRIBUTING.md).
For feature requests or bug reports, please file a [GitHub Issue](https://github.com/Microsoft/onnxruntime/issues).
For general discussion or questions, please use [GitHub Discussions](https://github.com/microsoft/onnxruntime/discussions).
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## License
This project is licensed under the [MIT License](LICENSE).

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
1.12.0

View File

@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "onnxruntime_c_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \param use_arena zero: false. non-zero: true.
*/
ORT_EXPORT
ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_CPU, _In_ OrtSessionOptions* options, int use_arena)
ORT_ALL_ARGS_NONNULL;
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
/*
* This file defines RunOptions Config Keys and format of the Config Values.
*
* The Naming Convention for a RunOptions Config Key,
* "[Area][.[SubArea1].[SubArea2]...].[Keyname]"
* Such as "ep.cuda.use_arena"
* The Config Key cannot be empty
* The maximum length of the Config Key is 128
*
* The string format of a RunOptions Config Value is defined individually for each Config.
* The maximum length of the Config Value is 1024
*/
// Key for enabling shrinkages of user listed device memory arenas.
// Expects a list of semi-colon separated key value pairs separated by colon in the following format:
// "device_0:device_id_0;device_1:device_id_1"
// No white-spaces allowed in the provided list string.
// Currently, the only supported devices are : "cpu", "gpu" (case sensitive).
// If "cpu" is included in the list, DisableCpuMemArena() API must not be called (i.e.) arena for cpu should be enabled.
// Example usage: "cpu:0;gpu:0" (or) "gpu:0"
// By default, the value for this key is empty (i.e.) no memory arenas are shrunk
static const char* const kOrtRunOptionsConfigEnableMemoryArenaShrinkage = "memory.enable_memory_arena_shrinkage";

View File

@@ -0,0 +1,128 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
/*
* This file defines SessionOptions Config Keys and format of the Config Values.
*
* The Naming Convention for a SessionOptions Config Key,
* "[Area][.[SubArea1].[SubArea2]...].[Keyname]"
* Such as "ep.cuda.use_arena"
* The Config Key cannot be empty
* The maximum length of the Config Key is 128
*
* The string format of a SessionOptions Config Value is defined individually for each Config.
* The maximum length of the Config Value is 1024
*/
// Key for disable PrePacking,
// If the config value is set to "1" then the prepacking is disabled, otherwise prepacking is enabled (default value)
static const char* const kOrtSessionOptionsConfigDisablePrepacking = "session.disable_prepacking";
// A value of "1" means allocators registered in the env will be used. "0" means the allocators created in the session
// will be used. Use this to override the usage of env allocators on a per session level.
static const char* const kOrtSessionOptionsConfigUseEnvAllocators = "session.use_env_allocators";
// Set to 'ORT' (case sensitive) to load an ORT format model.
// If unset, model type will default to ONNX unless inferred from filename ('.ort' == ORT format) or bytes to be ORT
static const char* const kOrtSessionOptionsConfigLoadModelFormat = "session.load_model_format";
// Set to 'ORT' (case sensitive) to save optimized model in ORT format when SessionOptions.optimized_model_path is set.
// If unset, format will default to ONNX unless optimized_model_filepath ends in '.ort'.
static const char* const kOrtSessionOptionsConfigSaveModelFormat = "session.save_model_format";
// If a value is "1", flush-to-zero and denormal-as-zero are applied. The default is "0".
// When multiple sessions are created, a main thread doesn't override changes from succeeding session options,
// but threads in session thread pools follow option changes.
// When ORT runs with OpenMP, the same rule is applied, i.e. the first session option to flush-to-zero and
// denormal-as-zero is only applied to global OpenMP thread pool, which doesn't support per-session thread pool.
// Note that an alternative way not using this option at runtime is to train and export a model without denormals
// and that's recommended because turning this option on may hurt model accuracy.
static const char* const kOrtSessionOptionsConfigSetDenormalAsZero = "session.set_denormal_as_zero";
// It controls to run quantization model in QDQ (QuantizelinearDeQuantizelinear) format or not.
// "0": enable. ORT does fusion logic for QDQ format.
// "1": disable. ORT doesn't do fusion logic for QDQ format.
// Its default value is "0"
static const char* const kOrtSessionOptionsDisableQuantQDQ = "session.disable_quant_qdq";
// If set to "1", enables the removal of QuantizeLinear/DequantizeLinear node pairs once all QDQ handling has been
// completed. e.g. If after all QDQ handling has completed and we have -> FloatOp -> Q -> DQ -> FloatOp -> the
// Q -> DQ could potentially be removed. This will provide a performance benefit by avoiding going from float to
// 8-bit and back to float, but could impact accuracy. The impact on accuracy will be model specific and depend on
// other factors like whether the model was created using Quantization Aware Training or Post Training Quantization.
// As such, it's best to test to determine if enabling this works well for your scenario.
// The default value is "0"
// Available since version 1.11.
static const char* const kOrtSessionOptionsEnableQuantQDQCleanup = "session.enable_quant_qdq_cleanup";
// Enable or disable gelu approximation in graph optimization. "0": disable; "1": enable. The default is "0".
// GeluApproximation has side effects which may change the inference results. It is disabled by default due to this.
static const char* const kOrtSessionOptionsEnableGeluApproximation = "optimization.enable_gelu_approximation";
// Enable or disable using device allocator for allocating initialized tensor memory. "1": enable; "0": disable. The default is "0".
// Using device allocators means the memory allocation is made using malloc/new.
static const char* const kOrtSessionOptionsUseDeviceAllocatorForInitializers = "session.use_device_allocator_for_initializers";
// Configure whether to allow the inter_op/intra_op threads spinning a number of times before blocking
// "0": thread will block if found no job to run
// "1": default, thread will spin a number of times before blocking
static const char* const kOrtSessionOptionsConfigAllowInterOpSpinning = "session.inter_op.allow_spinning";
static const char* const kOrtSessionOptionsConfigAllowIntraOpSpinning = "session.intra_op.allow_spinning";
// Key for using model bytes directly for ORT format
// If a session is created using an input byte array contains the ORT format model data,
// By default we will copy the model bytes at the time of session creation to ensure the model bytes
// buffer is valid.
// Setting this option to "1" will disable copy the model bytes, and use the model bytes directly. The caller
// has to guarantee that the model bytes are valid until the ORT session using the model bytes is destroyed.
static const char* const kOrtSessionOptionsConfigUseORTModelBytesDirectly = "session.use_ort_model_bytes_directly";
// This should only be specified when exporting an ORT format model for use on a different platform.
// If the ORT format model will be used on ARM platforms set to "1". For other platforms set to "0"
// Available since version 1.11.
static const char* const kOrtSessionOptionsQDQIsInt8Allowed = "session.qdqisint8allowed";
// Specifies how minimal build graph optimizations are handled in a full build.
// These optimizations are at the extended level or higher.
// Possible values and their effects are:
// "save": Save runtime optimizations when saving an ORT format model.
// "apply": Only apply optimizations available in a minimal build.
// ""/<unspecified>: Apply optimizations available in a full build.
// Available since version 1.11.
static const char* const kOrtSessionOptionsConfigMinimalBuildOptimizations =
"optimization.minimal_build_optimizations";
// Note: The options specific to an EP should be specified prior to appending that EP to the session options object in
// order for them to take effect.
// Specifies a list of stop op types. Nodes of a type in the stop op types and nodes downstream from them will not be
// run by the NNAPI EP.
// The value should be a ","-delimited list of op types. For example, "Add,Sub".
// If not specified, the default set of stop ops is used. To specify an empty stop ops types list and disable stop op
// exclusion, set the value to "".
static const char* const kOrtSessionOptionsConfigNnapiEpPartitioningStopOps = "ep.nnapi.partitioning_stop_ops";
// Enabling dynamic block-sizing for multithreading.
// With a positive value, thread pool will split a task of N iterations to blocks of size starting from:
// N / (num_of_threads * dynamic_block_base)
// As execution progresses, the size will decrease according to the diminishing residual of N,
// meaning the task will be distributed in smaller granularity for better parallelism.
// For some models, it helps to reduce the variance of E2E inference latency and boost performance.
// The feature will not function by default, specify any positive integer, e.g. "4", to enable it.
// Available since version 1.11.
static const char* const kOrtSessionOptionsConfigDynamicBlockBase = "session.dynamic_block_base";
// This option allows to decrease CPU usage between infrequent
// requests and forces any TP threads spinning stop immediately when the last of
// concurrent Run() call returns.
// Spinning is restarted on the next Run() call.
// Applies only to internal thread-pools
static const char* const kOrtSessionOptionsConfigForceSpinningStop = "session.force_spinning_stop";
// "1": all inconsistencies encountered during shape and type inference
// will result in failures.
// "0": in some cases warnings will be logged but processing will continue. The default.
// May be useful to expose bugs in models.
static const char* const kOrtSessionOptionsConfigStrictShapeTypeInference = "session.strict_shape_type_inference";

View File

@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
namespace onnxruntime {
// data types for execution provider options
using ProviderOptions = std::unordered_map<std::string, std::string>;
using ProviderOptionsVector = std::vector<ProviderOptions>;
using ProviderOptionsMap = std::unordered_map<std::string, ProviderOptions>;
} // namespace onnxruntime

View File

@@ -0,0 +1 @@
libonnxruntime.so.1.21.0

View File

@@ -0,0 +1,66 @@
// Copyright (c) 2022 Binbin Zhang (binbzha@qq.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#include <string>
#include "frontend/feature_pipeline.h"
#include "frontend/wav.h"
#include "kws/keyword_spotting.h"
#include "utils/log.h"
int main(int argc, char* argv[]) {
if (argc != 5) {
LOG(FATAL) << "Usage: kws_main fbank_dim(int) batch_size(int) "
<< "kws_model_path test_wav_path";
}
const int num_bins = std::stoi(argv[1]); // Fbank feature dim
const int batch_size = std::stoi(argv[2]);
const std::string model_path = argv[3];
const std::string wav_path = argv[4];
wenet::WavReader wav_reader(wav_path);
int num_samples = wav_reader.num_samples();
wenet::FeaturePipelineConfig feature_config(num_bins, 16000);
feature_config.Info();
wenet::FeaturePipeline feature_pipeline(feature_config);
std::vector<float> wav(wav_reader.data(), wav_reader.data() + num_samples);
feature_pipeline.AcceptWaveform(wav);
feature_pipeline.set_input_finished();
wekws::KeywordSpotting spotter(model_path);
// Simulate streaming, detect batch by batch
int offset = 0;
while (true) {
std::vector<std::vector<float>> feats;
bool ok = feature_pipeline.Read(batch_size, &feats);
std::vector<std::vector<float>> prob;
spotter.Forward(feats, &prob);
for (int i = 0; i < prob.size(); i++) {
std::cout << "frame " << offset + i << " prob";
for (int j = 0; j < prob[i].size(); j++) {
std::cout << " " << prob[i][j];
}
std::cout << std::endl;
}
// Reach the end of feature pipeline
if (!ok) break;
offset += prob.size();
}
return 0;
}