mirror of
https://github.com/sipeed/MaixCDK.git
synced 2026-09-11 06:09:42 -05:00
* update some examples
This commit is contained in:
2
components/3rd_party/opencv/CMakeLists.txt
vendored
2
components/3rd_party/opencv/CMakeLists.txt
vendored
@@ -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
9
examples/demo_focus_stack/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
build
|
||||
dist
|
||||
.config.mk
|
||||
.flash.conf.json
|
||||
data
|
||||
|
||||
/CMakeLists.txt
|
||||
|
||||
__pycache__
|
||||
2
examples/demo_focus_stack/README.md
Normal file
2
examples/demo_focus_stack/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## Introduction can be seen
|
||||
[Introduction](https://maixhub.com/share/34)
|
||||
11
examples/demo_focus_stack/app.yaml
Normal file
11
examples/demo_focus_stack/app.yaml
Normal 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
|
||||
|
||||
82
examples/demo_focus_stack/main/CMakeLists.txt
Normal file
82
examples/demo_focus_stack/main/CMakeLists.txt
Normal 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()
|
||||
0
examples/demo_focus_stack/main/Kconfig
Normal file
0
examples/demo_focus_stack/main/Kconfig
Normal file
3
examples/demo_focus_stack/main/include/main.h
Normal file
3
examples/demo_focus_stack/main/include/main.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
186
examples/demo_focus_stack/main/src/main.cpp
Normal file
186
examples/demo_focus_stack/main/src/main.cpp
Normal 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
9
examples/onnxruntime_demo/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
build
|
||||
dist
|
||||
.config.mk
|
||||
.flash.conf.json
|
||||
data
|
||||
|
||||
/CMakeLists.txt
|
||||
|
||||
__pycache__
|
||||
2
examples/onnxruntime_demo/README.md
Normal file
2
examples/onnxruntime_demo/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## Introduction can be seen
|
||||
[Introduction](https://maixhub.com/share/34)
|
||||
11
examples/onnxruntime_demo/app.yaml
Normal file
11
examples/onnxruntime_demo/app.yaml
Normal 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
|
||||
|
||||
82
examples/onnxruntime_demo/main/CMakeLists.txt
Normal file
82
examples/onnxruntime_demo/main/CMakeLists.txt
Normal 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()
|
||||
0
examples/onnxruntime_demo/main/Kconfig
Normal file
0
examples/onnxruntime_demo/main/Kconfig
Normal file
6
examples/onnxruntime_demo/main/cmake/portaudio.cmake
Normal file
6
examples/onnxruntime_demo/main/cmake/portaudio.cmake
Normal 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)
|
||||
11
examples/onnxruntime_demo/main/core/bin/CMakeLists.txt
Normal file
11
examples/onnxruntime_demo/main/core/bin/CMakeLists.txt
Normal 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)
|
||||
66
examples/onnxruntime_demo/main/core/bin/kws_main.cc
Normal file
66
examples/onnxruntime_demo/main/core/bin/kws_main.cc
Normal 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;
|
||||
}
|
||||
80
examples/onnxruntime_demo/main/core/bin/kws_speechcommand.cc
Normal file
80
examples/onnxruntime_demo/main/core/bin/kws_speechcommand.cc
Normal 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;
|
||||
}
|
||||
109
examples/onnxruntime_demo/main/core/bin/stream_kws_main.cc
Normal file
109
examples/onnxruntime_demo/main/core/bin/stream_kws_main.cc
Normal 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, ¶ms, 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;
|
||||
}
|
||||
@@ -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, ¶ms, 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;
|
||||
}
|
||||
16
examples/onnxruntime_demo/main/core/cmake/onnxruntime.cmake
Normal file
16
examples/onnxruntime_demo/main/core/cmake/onnxruntime.cmake
Normal 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)
|
||||
@@ -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)
|
||||
@@ -0,0 +1,4 @@
|
||||
add_library(frontend STATIC
|
||||
feature_pipeline.cc
|
||||
fft.cc
|
||||
)
|
||||
222
examples/onnxruntime_demo/main/core/frontend/fbank.h
Normal file
222
examples/onnxruntime_demo/main/core/frontend/fbank.h
Normal 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_
|
||||
113
examples/onnxruntime_demo/main/core/frontend/feature_pipeline.cc
Normal file
113
examples/onnxruntime_demo/main/core/frontend/feature_pipeline.cc
Normal 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
|
||||
118
examples/onnxruntime_demo/main/core/frontend/feature_pipeline.h
Normal file
118
examples/onnxruntime_demo/main/core/frontend/feature_pipeline.h
Normal 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_
|
||||
121
examples/onnxruntime_demo/main/core/frontend/fft.cc
Normal file
121
examples/onnxruntime_demo/main/core/frontend/fft.cc
Normal 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
|
||||
25
examples/onnxruntime_demo/main/core/frontend/fft.h
Normal file
25
examples/onnxruntime_demo/main/core/frontend/fft.h
Normal 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_
|
||||
203
examples/onnxruntime_demo/main/core/frontend/wav.h
Normal file
203
examples/onnxruntime_demo/main/core/frontend/wav.h
Normal 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_
|
||||
1
examples/onnxruntime_demo/main/core/kws/CMakeLists.txt
Normal file
1
examples/onnxruntime_demo/main/core/kws/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
add_library(kws STATIC keyword_spotting.cc)
|
||||
117
examples/onnxruntime_demo/main/core/kws/keyword_spotting.cc
Normal file
117
examples/onnxruntime_demo/main/core/kws/keyword_spotting.cc
Normal 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
|
||||
61
examples/onnxruntime_demo/main/core/kws/keyword_spotting.h
Normal file
61
examples/onnxruntime_demo/main/core/kws/keyword_spotting.h
Normal 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_
|
||||
@@ -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++)
|
||||
98
examples/onnxruntime_demo/main/core/utils/blocking_queue.h
Normal file
98
examples/onnxruntime_demo/main/core/utils/blocking_queue.h
Normal 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_
|
||||
83
examples/onnxruntime_demo/main/core/utils/log.h
Normal file
83
examples/onnxruntime_demo/main/core/utils/log.h
Normal 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_
|
||||
3
examples/onnxruntime_demo/main/include/main.h
Normal file
3
examples/onnxruntime_demo/main/include/main.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
2
examples/onnxruntime_demo/main/onnxruntime-src/.gitignore
vendored
Normal file
2
examples/onnxruntime_demo/main/onnxruntime-src/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
!lib/libonnxruntime.so
|
||||
!lib/libonnxruntime.so.1.21.0
|
||||
@@ -0,0 +1 @@
|
||||
f4663641764ccc3e93a617ab63ae4ff1badc2ee1
|
||||
21
examples/onnxruntime_demo/main/onnxruntime-src/LICENSE
Normal file
21
examples/onnxruntime_demo/main/onnxruntime-src/LICENSE
Normal 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.
|
||||
21
examples/onnxruntime_demo/main/onnxruntime-src/Privacy.md
Normal file
21
examples/onnxruntime_demo/main/onnxruntime-src/Privacy.md
Normal 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.
|
||||
52
examples/onnxruntime_demo/main/onnxruntime-src/README.md
Normal file
52
examples/onnxruntime_demo/main/onnxruntime-src/README.md
Normal 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 →](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 →](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|[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=9)|[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=10)|[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=47)|
|
||||
|Linux|[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=11)<br>[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=64)<br>[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=110)<br>[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=78)<br>[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=86)|[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=12)<br>[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=45)<br>[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=140)<br>[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=84)|[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=110)<br>[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=55)|
|
||||
|Mac|[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=13)<br>[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=65)|||
|
||||
|Android|||[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=53)|
|
||||
|iOS|||[](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=134)|
|
||||
|WebAssembly|||[](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).
|
||||
4779
examples/onnxruntime_demo/main/onnxruntime-src/ThirdPartyNotices.txt
Normal file
4779
examples/onnxruntime_demo/main/onnxruntime-src/ThirdPartyNotices.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
1.12.0
|
||||
@@ -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
@@ -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";
|
||||
@@ -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";
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
libonnxruntime.so.1.21.0
|
||||
BIN
examples/onnxruntime_demo/main/onnxruntime-src/lib/libonnxruntime.so.1.21.0
Executable file
BIN
examples/onnxruntime_demo/main/onnxruntime-src/lib/libonnxruntime.so.1.21.0
Executable file
Binary file not shown.
66
examples/onnxruntime_demo/main/src/main.cpp
Normal file
66
examples/onnxruntime_demo/main/src/main.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user