From 242431452b682b6bf5d711506653605ed8786af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Wed, 29 Mar 2023 00:30:57 +0800 Subject: [PATCH] export --- .../build/lib/funasr_onnx/__init__.py | 3 - .../build/lib/funasr_onnx/paraformer_bin.py | 187 ------ .../build/lib/funasr_onnx/punc_bin.py | 0 .../build/lib/funasr_onnx/utils/__init__.py | 0 .../build/lib/funasr_onnx/utils/e2e_vad.py | 607 ------------------ .../build/lib/funasr_onnx/utils/frontend.py | 191 ------ .../funasr_onnx/utils/postprocess_utils.py | 240 ------- .../lib/funasr_onnx/utils/timestamp_utils.py | 59 -- .../build/lib/funasr_onnx/utils/utils.py | 257 -------- .../build/lib/funasr_onnx/vad_bin.py | 166 ----- .../dist/funasr_onnx-0.0.2-py3.8.egg | Bin 47828 -> 0 bytes .../dist/funasr_onnx-0.0.3-py3.8.egg | Bin 47828 -> 0 bytes 12 files changed, 1710 deletions(-) delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/__init__.py delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/paraformer_bin.py delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/punc_bin.py delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/__init__.py delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/e2e_vad.py delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/frontend.py delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/postprocess_utils.py delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/timestamp_utils.py delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/utils.py delete mode 100644 funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/vad_bin.py delete mode 100644 funasr/runtime/python/onnxruntime/dist/funasr_onnx-0.0.2-py3.8.egg delete mode 100644 funasr/runtime/python/onnxruntime/dist/funasr_onnx-0.0.3-py3.8.egg diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/__init__.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/__init__.py deleted file mode 100644 index 475047903..000000000 --- a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- encoding: utf-8 -*- -from .paraformer_bin import Paraformer -from .vad_bin import Fsmn_vad diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/paraformer_bin.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/paraformer_bin.py deleted file mode 100644 index cbdb8d9e6..000000000 --- a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/paraformer_bin.py +++ /dev/null @@ -1,187 +0,0 @@ -# -*- encoding: utf-8 -*- - -import os.path -from pathlib import Path -from typing import List, Union, Tuple - -import copy -import librosa -import numpy as np - -from .utils.utils import (CharTokenizer, Hypothesis, ONNXRuntimeError, - OrtInferSession, TokenIDConverter, get_logger, - read_yaml) -from .utils.postprocess_utils import sentence_postprocess -from .utils.frontend import WavFrontend -from .utils.timestamp_utils import time_stamp_lfr6_onnx - -logging = get_logger() - - -class Paraformer(): - def __init__(self, model_dir: Union[str, Path] = None, - batch_size: int = 1, - device_id: Union[str, int] = "-1", - plot_timestamp_to: str = "", - pred_bias: int = 1, - quantize: bool = False, - intra_op_num_threads: int = 4, - ): - - if not Path(model_dir).exists(): - raise FileNotFoundError(f'{model_dir} does not exist.') - - model_file = os.path.join(model_dir, 'model.onnx') - if quantize: - model_file = os.path.join(model_dir, 'model_quant.onnx') - config_file = os.path.join(model_dir, 'config.yaml') - cmvn_file = os.path.join(model_dir, 'am.mvn') - config = read_yaml(config_file) - - self.converter = TokenIDConverter(config['token_list']) - self.tokenizer = CharTokenizer() - self.frontend = WavFrontend( - cmvn_file=cmvn_file, - **config['frontend_conf'] - ) - self.ort_infer = OrtInferSession(model_file, device_id, intra_op_num_threads=intra_op_num_threads) - self.batch_size = batch_size - self.plot_timestamp_to = plot_timestamp_to - self.pred_bias = pred_bias - - def __call__(self, wav_content: Union[str, np.ndarray, List[str]], **kwargs) -> List: - waveform_list = self.load_data(wav_content, self.frontend.opts.frame_opts.samp_freq) - waveform_nums = len(waveform_list) - asr_res = [] - for beg_idx in range(0, waveform_nums, self.batch_size): - - end_idx = min(waveform_nums, beg_idx + self.batch_size) - feats, feats_len = self.extract_feat(waveform_list[beg_idx:end_idx]) - try: - outputs = self.infer(feats, feats_len) - am_scores, valid_token_lens = outputs[0], outputs[1] - if len(outputs) == 4: - # for BiCifParaformer Inference - us_alphas, us_peaks = outputs[2], outputs[3] - else: - us_alphas, us_peaks = None, None - except ONNXRuntimeError: - #logging.warning(traceback.format_exc()) - logging.warning("input wav is silence or noise") - preds = [''] - else: - preds = self.decode(am_scores, valid_token_lens) - if us_peaks is None: - for pred in preds: - pred = sentence_postprocess(pred) - asr_res.append({'preds': pred}) - else: - for pred, us_peaks_ in zip(preds, us_peaks): - raw_tokens = pred - timestamp, timestamp_raw = time_stamp_lfr6_onnx(us_peaks_, copy.copy(raw_tokens)) - text_proc, timestamp_proc, _ = sentence_postprocess(raw_tokens, timestamp_raw) - # logging.warning(timestamp) - if len(self.plot_timestamp_to): - self.plot_wave_timestamp(waveform_list[0], timestamp, self.plot_timestamp_to) - asr_res.append({'preds': text_proc, 'timestamp': timestamp_proc, "raw_tokens": raw_tokens}) - return asr_res - - def plot_wave_timestamp(self, wav, text_timestamp, dest): - # TODO: Plot the wav and timestamp results with matplotlib - import matplotlib - matplotlib.use('Agg') - matplotlib.rc("font", family='Alibaba PuHuiTi') # set it to a font that your system supports - import matplotlib.pyplot as plt - fig, ax1 = plt.subplots(figsize=(11, 3.5), dpi=320) - ax2 = ax1.twinx() - ax2.set_ylim([0, 2.0]) - # plot waveform - ax1.set_ylim([-0.3, 0.3]) - time = np.arange(wav.shape[0]) / 16000 - ax1.plot(time, wav/wav.max()*0.3, color='gray', alpha=0.4) - # plot lines and text - for (char, start, end) in text_timestamp: - ax1.vlines(start, -0.3, 0.3, ls='--') - ax1.vlines(end, -0.3, 0.3, ls='--') - x_adj = 0.045 if char != '' else 0.12 - ax1.text((start + end) * 0.5 - x_adj, 0, char) - # plt.legend() - plotname = "{}/timestamp.png".format(dest) - plt.savefig(plotname, bbox_inches='tight') - - def load_data(self, - wav_content: Union[str, np.ndarray, List[str]], fs: int = None) -> List: - def load_wav(path: str) -> np.ndarray: - waveform, _ = librosa.load(path, sr=fs) - return waveform - - if isinstance(wav_content, np.ndarray): - return [wav_content] - - if isinstance(wav_content, str): - return [load_wav(wav_content)] - - if isinstance(wav_content, list): - return [load_wav(path) for path in wav_content] - - raise TypeError( - f'The type of {wav_content} is not in [str, np.ndarray, list]') - - def extract_feat(self, - waveform_list: List[np.ndarray] - ) -> Tuple[np.ndarray, np.ndarray]: - feats, feats_len = [], [] - for waveform in waveform_list: - speech, _ = self.frontend.fbank(waveform) - feat, feat_len = self.frontend.lfr_cmvn(speech) - feats.append(feat) - feats_len.append(feat_len) - - feats = self.pad_feats(feats, np.max(feats_len)) - feats_len = np.array(feats_len).astype(np.int32) - return feats, feats_len - - @staticmethod - def pad_feats(feats: List[np.ndarray], max_feat_len: int) -> np.ndarray: - def pad_feat(feat: np.ndarray, cur_len: int) -> np.ndarray: - pad_width = ((0, max_feat_len - cur_len), (0, 0)) - return np.pad(feat, pad_width, 'constant', constant_values=0) - - feat_res = [pad_feat(feat, feat.shape[0]) for feat in feats] - feats = np.array(feat_res).astype(np.float32) - return feats - - def infer(self, feats: np.ndarray, - feats_len: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: - outputs = self.ort_infer([feats, feats_len]) - return outputs - - def decode(self, am_scores: np.ndarray, token_nums: int) -> List[str]: - return [self.decode_one(am_score, token_num) - for am_score, token_num in zip(am_scores, token_nums)] - - def decode_one(self, - am_score: np.ndarray, - valid_token_num: int) -> List[str]: - yseq = am_score.argmax(axis=-1) - score = am_score.max(axis=-1) - score = np.sum(score, axis=-1) - - # pad with mask tokens to ensure compatibility with sos/eos tokens - # asr_model.sos:1 asr_model.eos:2 - yseq = np.array([1] + yseq.tolist() + [2]) - hyp = Hypothesis(yseq=yseq, score=score) - - # remove sos/eos and get results - last_pos = -1 - token_int = hyp.yseq[1:last_pos].tolist() - - # remove blank symbol id, which is assumed to be 0 - token_int = list(filter(lambda x: x not in (0, 2), token_int)) - - # Change integer-ids to tokens - token = self.converter.ids2tokens(token_int) - token = token[:valid_token_num-self.pred_bias] - # texts = sentence_postprocess(token) - return token - diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/punc_bin.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/punc_bin.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/__init__.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/e2e_vad.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/e2e_vad.py deleted file mode 100644 index 8eed22fa4..000000000 --- a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/e2e_vad.py +++ /dev/null @@ -1,607 +0,0 @@ -from enum import Enum -from typing import List, Tuple, Dict, Any - -import math -import numpy as np - -class VadStateMachine(Enum): - kVadInStateStartPointNotDetected = 1 - kVadInStateInSpeechSegment = 2 - kVadInStateEndPointDetected = 3 - - -class FrameState(Enum): - kFrameStateInvalid = -1 - kFrameStateSpeech = 1 - kFrameStateSil = 0 - - -# final voice/unvoice state per frame -class AudioChangeState(Enum): - kChangeStateSpeech2Speech = 0 - kChangeStateSpeech2Sil = 1 - kChangeStateSil2Sil = 2 - kChangeStateSil2Speech = 3 - kChangeStateNoBegin = 4 - kChangeStateInvalid = 5 - - -class VadDetectMode(Enum): - kVadSingleUtteranceDetectMode = 0 - kVadMutipleUtteranceDetectMode = 1 - - -class VADXOptions: - def __init__( - self, - sample_rate: int = 16000, - detect_mode: int = VadDetectMode.kVadMutipleUtteranceDetectMode.value, - snr_mode: int = 0, - max_end_silence_time: int = 800, - max_start_silence_time: int = 3000, - do_start_point_detection: bool = True, - do_end_point_detection: bool = True, - window_size_ms: int = 200, - sil_to_speech_time_thres: int = 150, - speech_to_sil_time_thres: int = 150, - speech_2_noise_ratio: float = 1.0, - do_extend: int = 1, - lookback_time_start_point: int = 200, - lookahead_time_end_point: int = 100, - max_single_segment_time: int = 60000, - nn_eval_block_size: int = 8, - dcd_block_size: int = 4, - snr_thres: int = -100.0, - noise_frame_num_used_for_snr: int = 100, - decibel_thres: int = -100.0, - speech_noise_thres: float = 0.6, - fe_prior_thres: float = 1e-4, - silence_pdf_num: int = 1, - sil_pdf_ids: List[int] = [0], - speech_noise_thresh_low: float = -0.1, - speech_noise_thresh_high: float = 0.3, - output_frame_probs: bool = False, - frame_in_ms: int = 10, - frame_length_ms: int = 25, - ): - self.sample_rate = sample_rate - self.detect_mode = detect_mode - self.snr_mode = snr_mode - self.max_end_silence_time = max_end_silence_time - self.max_start_silence_time = max_start_silence_time - self.do_start_point_detection = do_start_point_detection - self.do_end_point_detection = do_end_point_detection - self.window_size_ms = window_size_ms - self.sil_to_speech_time_thres = sil_to_speech_time_thres - self.speech_to_sil_time_thres = speech_to_sil_time_thres - self.speech_2_noise_ratio = speech_2_noise_ratio - self.do_extend = do_extend - self.lookback_time_start_point = lookback_time_start_point - self.lookahead_time_end_point = lookahead_time_end_point - self.max_single_segment_time = max_single_segment_time - self.nn_eval_block_size = nn_eval_block_size - self.dcd_block_size = dcd_block_size - self.snr_thres = snr_thres - self.noise_frame_num_used_for_snr = noise_frame_num_used_for_snr - self.decibel_thres = decibel_thres - self.speech_noise_thres = speech_noise_thres - self.fe_prior_thres = fe_prior_thres - self.silence_pdf_num = silence_pdf_num - self.sil_pdf_ids = sil_pdf_ids - self.speech_noise_thresh_low = speech_noise_thresh_low - self.speech_noise_thresh_high = speech_noise_thresh_high - self.output_frame_probs = output_frame_probs - self.frame_in_ms = frame_in_ms - self.frame_length_ms = frame_length_ms - - -class E2EVadSpeechBufWithDoa(object): - def __init__(self): - self.start_ms = 0 - self.end_ms = 0 - self.buffer = [] - self.contain_seg_start_point = False - self.contain_seg_end_point = False - self.doa = 0 - - def Reset(self): - self.start_ms = 0 - self.end_ms = 0 - self.buffer = [] - self.contain_seg_start_point = False - self.contain_seg_end_point = False - self.doa = 0 - - -class E2EVadFrameProb(object): - def __init__(self): - self.noise_prob = 0.0 - self.speech_prob = 0.0 - self.score = 0.0 - self.frame_id = 0 - self.frm_state = 0 - - -class WindowDetector(object): - def __init__(self, window_size_ms: int, sil_to_speech_time: int, - speech_to_sil_time: int, frame_size_ms: int): - self.window_size_ms = window_size_ms - self.sil_to_speech_time = sil_to_speech_time - self.speech_to_sil_time = speech_to_sil_time - self.frame_size_ms = frame_size_ms - - self.win_size_frame = int(window_size_ms / frame_size_ms) - self.win_sum = 0 - self.win_state = [0] * self.win_size_frame # 初始化窗 - - self.cur_win_pos = 0 - self.pre_frame_state = FrameState.kFrameStateSil - self.cur_frame_state = FrameState.kFrameStateSil - self.sil_to_speech_frmcnt_thres = int(sil_to_speech_time / frame_size_ms) - self.speech_to_sil_frmcnt_thres = int(speech_to_sil_time / frame_size_ms) - - self.voice_last_frame_count = 0 - self.noise_last_frame_count = 0 - self.hydre_frame_count = 0 - - def Reset(self) -> None: - self.cur_win_pos = 0 - self.win_sum = 0 - self.win_state = [0] * self.win_size_frame - self.pre_frame_state = FrameState.kFrameStateSil - self.cur_frame_state = FrameState.kFrameStateSil - self.voice_last_frame_count = 0 - self.noise_last_frame_count = 0 - self.hydre_frame_count = 0 - - def GetWinSize(self) -> int: - return int(self.win_size_frame) - - def DetectOneFrame(self, frameState: FrameState, frame_count: int) -> AudioChangeState: - cur_frame_state = FrameState.kFrameStateSil - if frameState == FrameState.kFrameStateSpeech: - cur_frame_state = 1 - elif frameState == FrameState.kFrameStateSil: - cur_frame_state = 0 - else: - return AudioChangeState.kChangeStateInvalid - self.win_sum -= self.win_state[self.cur_win_pos] - self.win_sum += cur_frame_state - self.win_state[self.cur_win_pos] = cur_frame_state - self.cur_win_pos = (self.cur_win_pos + 1) % self.win_size_frame - - if self.pre_frame_state == FrameState.kFrameStateSil and self.win_sum >= self.sil_to_speech_frmcnt_thres: - self.pre_frame_state = FrameState.kFrameStateSpeech - return AudioChangeState.kChangeStateSil2Speech - - if self.pre_frame_state == FrameState.kFrameStateSpeech and self.win_sum <= self.speech_to_sil_frmcnt_thres: - self.pre_frame_state = FrameState.kFrameStateSil - return AudioChangeState.kChangeStateSpeech2Sil - - if self.pre_frame_state == FrameState.kFrameStateSil: - return AudioChangeState.kChangeStateSil2Sil - if self.pre_frame_state == FrameState.kFrameStateSpeech: - return AudioChangeState.kChangeStateSpeech2Speech - return AudioChangeState.kChangeStateInvalid - - def FrameSizeMs(self) -> int: - return int(self.frame_size_ms) - - -class E2EVadModel(): - def __init__(self, vad_post_args: Dict[str, Any]): - super(E2EVadModel, self).__init__() - self.vad_opts = VADXOptions(**vad_post_args) - self.windows_detector = WindowDetector(self.vad_opts.window_size_ms, - self.vad_opts.sil_to_speech_time_thres, - self.vad_opts.speech_to_sil_time_thres, - self.vad_opts.frame_in_ms) - # self.encoder = encoder - # init variables - self.is_final = False - self.data_buf_start_frame = 0 - self.frm_cnt = 0 - self.latest_confirmed_speech_frame = 0 - self.lastest_confirmed_silence_frame = -1 - self.continous_silence_frame_count = 0 - self.vad_state_machine = VadStateMachine.kVadInStateStartPointNotDetected - self.confirmed_start_frame = -1 - self.confirmed_end_frame = -1 - self.number_end_time_detected = 0 - self.sil_frame = 0 - self.sil_pdf_ids = self.vad_opts.sil_pdf_ids - self.noise_average_decibel = -100.0 - self.pre_end_silence_detected = False - self.next_seg = True - - self.output_data_buf = [] - self.output_data_buf_offset = 0 - self.frame_probs = [] - self.max_end_sil_frame_cnt_thresh = self.vad_opts.max_end_silence_time - self.vad_opts.speech_to_sil_time_thres - self.speech_noise_thres = self.vad_opts.speech_noise_thres - self.scores = None - self.max_time_out = False - self.decibel = [] - self.data_buf = None - self.data_buf_all = None - self.waveform = None - self.ResetDetection() - - def AllResetDetection(self): - self.is_final = False - self.data_buf_start_frame = 0 - self.frm_cnt = 0 - self.latest_confirmed_speech_frame = 0 - self.lastest_confirmed_silence_frame = -1 - self.continous_silence_frame_count = 0 - self.vad_state_machine = VadStateMachine.kVadInStateStartPointNotDetected - self.confirmed_start_frame = -1 - self.confirmed_end_frame = -1 - self.number_end_time_detected = 0 - self.sil_frame = 0 - self.sil_pdf_ids = self.vad_opts.sil_pdf_ids - self.noise_average_decibel = -100.0 - self.pre_end_silence_detected = False - self.next_seg = True - - self.output_data_buf = [] - self.output_data_buf_offset = 0 - self.frame_probs = [] - self.max_end_sil_frame_cnt_thresh = self.vad_opts.max_end_silence_time - self.vad_opts.speech_to_sil_time_thres - self.speech_noise_thres = self.vad_opts.speech_noise_thres - self.scores = None - self.max_time_out = False - self.decibel = [] - self.data_buf = None - self.data_buf_all = None - self.waveform = None - self.ResetDetection() - - def ResetDetection(self): - self.continous_silence_frame_count = 0 - self.latest_confirmed_speech_frame = 0 - self.lastest_confirmed_silence_frame = -1 - self.confirmed_start_frame = -1 - self.confirmed_end_frame = -1 - self.vad_state_machine = VadStateMachine.kVadInStateStartPointNotDetected - self.windows_detector.Reset() - self.sil_frame = 0 - self.frame_probs = [] - - def ComputeDecibel(self) -> None: - frame_sample_length = int(self.vad_opts.frame_length_ms * self.vad_opts.sample_rate / 1000) - frame_shift_length = int(self.vad_opts.frame_in_ms * self.vad_opts.sample_rate / 1000) - if self.data_buf_all is None: - self.data_buf_all = self.waveform[0] # self.data_buf is pointed to self.waveform[0] - self.data_buf = self.data_buf_all - else: - self.data_buf_all = np.concatenate((self.data_buf_all, self.waveform[0])) - for offset in range(0, self.waveform.shape[1] - frame_sample_length + 1, frame_shift_length): - self.decibel.append( - 10 * math.log10((self.waveform[0][offset: offset + frame_sample_length]).square().sum() + \ - 0.000001)) - - def ComputeScores(self, scores: np.ndarray) -> None: - # scores = self.encoder(feats, in_cache) # return B * T * D - self.vad_opts.nn_eval_block_size = scores.shape[1] - self.frm_cnt += scores.shape[1] # count total frames - if self.scores is None: - self.scores = scores # the first calculation - else: - self.scores = np.concatenate((self.scores, scores), axis=1) - - def PopDataBufTillFrame(self, frame_idx: int) -> None: # need check again - while self.data_buf_start_frame < frame_idx: - if len(self.data_buf) >= int(self.vad_opts.frame_in_ms * self.vad_opts.sample_rate / 1000): - self.data_buf_start_frame += 1 - self.data_buf = self.data_buf_all[self.data_buf_start_frame * int( - self.vad_opts.frame_in_ms * self.vad_opts.sample_rate / 1000):] - - def PopDataToOutputBuf(self, start_frm: int, frm_cnt: int, first_frm_is_start_point: bool, - last_frm_is_end_point: bool, end_point_is_sent_end: bool) -> None: - self.PopDataBufTillFrame(start_frm) - expected_sample_number = int(frm_cnt * self.vad_opts.sample_rate * self.vad_opts.frame_in_ms / 1000) - if last_frm_is_end_point: - extra_sample = max(0, int(self.vad_opts.frame_length_ms * self.vad_opts.sample_rate / 1000 - \ - self.vad_opts.sample_rate * self.vad_opts.frame_in_ms / 1000)) - expected_sample_number += int(extra_sample) - if end_point_is_sent_end: - expected_sample_number = max(expected_sample_number, len(self.data_buf)) - if len(self.data_buf) < expected_sample_number: - print('error in calling pop data_buf\n') - - if len(self.output_data_buf) == 0 or first_frm_is_start_point: - self.output_data_buf.append(E2EVadSpeechBufWithDoa()) - self.output_data_buf[-1].Reset() - self.output_data_buf[-1].start_ms = start_frm * self.vad_opts.frame_in_ms - self.output_data_buf[-1].end_ms = self.output_data_buf[-1].start_ms - self.output_data_buf[-1].doa = 0 - cur_seg = self.output_data_buf[-1] - if cur_seg.end_ms != start_frm * self.vad_opts.frame_in_ms: - print('warning\n') - out_pos = len(cur_seg.buffer) # cur_seg.buff现在没做任何操作 - data_to_pop = 0 - if end_point_is_sent_end: - data_to_pop = expected_sample_number - else: - data_to_pop = int(frm_cnt * self.vad_opts.frame_in_ms * self.vad_opts.sample_rate / 1000) - if data_to_pop > len(self.data_buf): - print('VAD data_to_pop is bigger than self.data_buf.size()!!!\n') - data_to_pop = len(self.data_buf) - expected_sample_number = len(self.data_buf) - - cur_seg.doa = 0 - for sample_cpy_out in range(0, data_to_pop): - # cur_seg.buffer[out_pos ++] = data_buf_.back(); - out_pos += 1 - for sample_cpy_out in range(data_to_pop, expected_sample_number): - # cur_seg.buffer[out_pos++] = data_buf_.back() - out_pos += 1 - if cur_seg.end_ms != start_frm * self.vad_opts.frame_in_ms: - print('Something wrong with the VAD algorithm\n') - self.data_buf_start_frame += frm_cnt - cur_seg.end_ms = (start_frm + frm_cnt) * self.vad_opts.frame_in_ms - if first_frm_is_start_point: - cur_seg.contain_seg_start_point = True - if last_frm_is_end_point: - cur_seg.contain_seg_end_point = True - - def OnSilenceDetected(self, valid_frame: int): - self.lastest_confirmed_silence_frame = valid_frame - if self.vad_state_machine == VadStateMachine.kVadInStateStartPointNotDetected: - self.PopDataBufTillFrame(valid_frame) - # silence_detected_callback_ - # pass - - def OnVoiceDetected(self, valid_frame: int) -> None: - self.latest_confirmed_speech_frame = valid_frame - self.PopDataToOutputBuf(valid_frame, 1, False, False, False) - - def OnVoiceStart(self, start_frame: int, fake_result: bool = False) -> None: - if self.vad_opts.do_start_point_detection: - pass - if self.confirmed_start_frame != -1: - print('not reset vad properly\n') - else: - self.confirmed_start_frame = start_frame - - if not fake_result and self.vad_state_machine == VadStateMachine.kVadInStateStartPointNotDetected: - self.PopDataToOutputBuf(self.confirmed_start_frame, 1, True, False, False) - - def OnVoiceEnd(self, end_frame: int, fake_result: bool, is_last_frame: bool) -> None: - for t in range(self.latest_confirmed_speech_frame + 1, end_frame): - self.OnVoiceDetected(t) - if self.vad_opts.do_end_point_detection: - pass - if self.confirmed_end_frame != -1: - print('not reset vad properly\n') - else: - self.confirmed_end_frame = end_frame - if not fake_result: - self.sil_frame = 0 - self.PopDataToOutputBuf(self.confirmed_end_frame, 1, False, True, is_last_frame) - self.number_end_time_detected += 1 - - def MaybeOnVoiceEndIfLastFrame(self, is_final_frame: bool, cur_frm_idx: int) -> None: - if is_final_frame: - self.OnVoiceEnd(cur_frm_idx, False, True) - self.vad_state_machine = VadStateMachine.kVadInStateEndPointDetected - - def GetLatency(self) -> int: - return int(self.LatencyFrmNumAtStartPoint() * self.vad_opts.frame_in_ms) - - def LatencyFrmNumAtStartPoint(self) -> int: - vad_latency = self.windows_detector.GetWinSize() - if self.vad_opts.do_extend: - vad_latency += int(self.vad_opts.lookback_time_start_point / self.vad_opts.frame_in_ms) - return vad_latency - - def GetFrameState(self, t: int) -> FrameState: - frame_state = FrameState.kFrameStateInvalid - cur_decibel = self.decibel[t] - cur_snr = cur_decibel - self.noise_average_decibel - # for each frame, calc log posterior probability of each state - if cur_decibel < self.vad_opts.decibel_thres: - frame_state = FrameState.kFrameStateSil - self.DetectOneFrame(frame_state, t, False) - return frame_state - - sum_score = 0.0 - noise_prob = 0.0 - assert len(self.sil_pdf_ids) == self.vad_opts.silence_pdf_num - if len(self.sil_pdf_ids) > 0: - assert len(self.scores) == 1 # 只支持batch_size = 1的测试 - sil_pdf_scores = [self.scores[0][t][sil_pdf_id] for sil_pdf_id in self.sil_pdf_ids] - sum_score = sum(sil_pdf_scores) - noise_prob = math.log(sum_score) * self.vad_opts.speech_2_noise_ratio - total_score = 1.0 - sum_score = total_score - sum_score - speech_prob = math.log(sum_score) - if self.vad_opts.output_frame_probs: - frame_prob = E2EVadFrameProb() - frame_prob.noise_prob = noise_prob - frame_prob.speech_prob = speech_prob - frame_prob.score = sum_score - frame_prob.frame_id = t - self.frame_probs.append(frame_prob) - if math.exp(speech_prob) >= math.exp(noise_prob) + self.speech_noise_thres: - if cur_snr >= self.vad_opts.snr_thres and cur_decibel >= self.vad_opts.decibel_thres: - frame_state = FrameState.kFrameStateSpeech - else: - frame_state = FrameState.kFrameStateSil - else: - frame_state = FrameState.kFrameStateSil - if self.noise_average_decibel < -99.9: - self.noise_average_decibel = cur_decibel - else: - self.noise_average_decibel = (cur_decibel + self.noise_average_decibel * ( - self.vad_opts.noise_frame_num_used_for_snr - - 1)) / self.vad_opts.noise_frame_num_used_for_snr - - return frame_state - - - def __call__(self, score: np.ndarray, waveform: np.ndarray, - is_final: bool = False, max_end_sil: int = 800 - ): - self.max_end_sil_frame_cnt_thresh = max_end_sil - self.vad_opts.speech_to_sil_time_thres - self.waveform = waveform # compute decibel for each frame - self.ComputeDecibel() - self.ComputeScores(score) - if not is_final: - self.DetectCommonFrames() - else: - self.DetectLastFrames() - segments = [] - for batch_num in range(0, score.shape[0]): # only support batch_size = 1 now - segment_batch = [] - if len(self.output_data_buf) > 0: - for i in range(self.output_data_buf_offset, len(self.output_data_buf)): - if not self.output_data_buf[i].contain_seg_start_point: - continue - if not self.next_seg and not self.output_data_buf[i].contain_seg_end_point: - continue - start_ms = self.output_data_buf[i].start_ms if self.next_seg else -1 - if self.output_data_buf[i].contain_seg_end_point: - end_ms = self.output_data_buf[i].end_ms - self.next_seg = True - self.output_data_buf_offset += 1 - else: - end_ms = -1 - self.next_seg = False - segment = [start_ms, end_ms] - segment_batch.append(segment) - if segment_batch: - segments.append(segment_batch) - if is_final: - # reset class variables and clear the dict for the next query - self.AllResetDetection() - return segments - - def DetectCommonFrames(self) -> int: - if self.vad_state_machine == VadStateMachine.kVadInStateEndPointDetected: - return 0 - for i in range(self.vad_opts.nn_eval_block_size - 1, -1, -1): - frame_state = FrameState.kFrameStateInvalid - frame_state = self.GetFrameState(self.frm_cnt - 1 - i) - self.DetectOneFrame(frame_state, self.frm_cnt - 1 - i, False) - - return 0 - - def DetectLastFrames(self) -> int: - if self.vad_state_machine == VadStateMachine.kVadInStateEndPointDetected: - return 0 - for i in range(self.vad_opts.nn_eval_block_size - 1, -1, -1): - frame_state = FrameState.kFrameStateInvalid - frame_state = self.GetFrameState(self.frm_cnt - 1 - i) - if i != 0: - self.DetectOneFrame(frame_state, self.frm_cnt - 1 - i, False) - else: - self.DetectOneFrame(frame_state, self.frm_cnt - 1, True) - - return 0 - - def DetectOneFrame(self, cur_frm_state: FrameState, cur_frm_idx: int, is_final_frame: bool) -> None: - tmp_cur_frm_state = FrameState.kFrameStateInvalid - if cur_frm_state == FrameState.kFrameStateSpeech: - if math.fabs(1.0) > self.vad_opts.fe_prior_thres: - tmp_cur_frm_state = FrameState.kFrameStateSpeech - else: - tmp_cur_frm_state = FrameState.kFrameStateSil - elif cur_frm_state == FrameState.kFrameStateSil: - tmp_cur_frm_state = FrameState.kFrameStateSil - state_change = self.windows_detector.DetectOneFrame(tmp_cur_frm_state, cur_frm_idx) - frm_shift_in_ms = self.vad_opts.frame_in_ms - if AudioChangeState.kChangeStateSil2Speech == state_change: - silence_frame_count = self.continous_silence_frame_count - self.continous_silence_frame_count = 0 - self.pre_end_silence_detected = False - start_frame = 0 - if self.vad_state_machine == VadStateMachine.kVadInStateStartPointNotDetected: - start_frame = max(self.data_buf_start_frame, cur_frm_idx - self.LatencyFrmNumAtStartPoint()) - self.OnVoiceStart(start_frame) - self.vad_state_machine = VadStateMachine.kVadInStateInSpeechSegment - for t in range(start_frame + 1, cur_frm_idx + 1): - self.OnVoiceDetected(t) - elif self.vad_state_machine == VadStateMachine.kVadInStateInSpeechSegment: - for t in range(self.latest_confirmed_speech_frame + 1, cur_frm_idx): - self.OnVoiceDetected(t) - if cur_frm_idx - self.confirmed_start_frame + 1 > \ - self.vad_opts.max_single_segment_time / frm_shift_in_ms: - self.OnVoiceEnd(cur_frm_idx, False, False) - self.vad_state_machine = VadStateMachine.kVadInStateEndPointDetected - elif not is_final_frame: - self.OnVoiceDetected(cur_frm_idx) - else: - self.MaybeOnVoiceEndIfLastFrame(is_final_frame, cur_frm_idx) - else: - pass - elif AudioChangeState.kChangeStateSpeech2Sil == state_change: - self.continous_silence_frame_count = 0 - if self.vad_state_machine == VadStateMachine.kVadInStateStartPointNotDetected: - pass - elif self.vad_state_machine == VadStateMachine.kVadInStateInSpeechSegment: - if cur_frm_idx - self.confirmed_start_frame + 1 > \ - self.vad_opts.max_single_segment_time / frm_shift_in_ms: - self.OnVoiceEnd(cur_frm_idx, False, False) - self.vad_state_machine = VadStateMachine.kVadInStateEndPointDetected - elif not is_final_frame: - self.OnVoiceDetected(cur_frm_idx) - else: - self.MaybeOnVoiceEndIfLastFrame(is_final_frame, cur_frm_idx) - else: - pass - elif AudioChangeState.kChangeStateSpeech2Speech == state_change: - self.continous_silence_frame_count = 0 - if self.vad_state_machine == VadStateMachine.kVadInStateInSpeechSegment: - if cur_frm_idx - self.confirmed_start_frame + 1 > \ - self.vad_opts.max_single_segment_time / frm_shift_in_ms: - self.max_time_out = True - self.OnVoiceEnd(cur_frm_idx, False, False) - self.vad_state_machine = VadStateMachine.kVadInStateEndPointDetected - elif not is_final_frame: - self.OnVoiceDetected(cur_frm_idx) - else: - self.MaybeOnVoiceEndIfLastFrame(is_final_frame, cur_frm_idx) - else: - pass - elif AudioChangeState.kChangeStateSil2Sil == state_change: - self.continous_silence_frame_count += 1 - if self.vad_state_machine == VadStateMachine.kVadInStateStartPointNotDetected: - # silence timeout, return zero length decision - if ((self.vad_opts.detect_mode == VadDetectMode.kVadSingleUtteranceDetectMode.value) and ( - self.continous_silence_frame_count * frm_shift_in_ms > self.vad_opts.max_start_silence_time)) \ - or (is_final_frame and self.number_end_time_detected == 0): - for t in range(self.lastest_confirmed_silence_frame + 1, cur_frm_idx): - self.OnSilenceDetected(t) - self.OnVoiceStart(0, True) - self.OnVoiceEnd(0, True, False); - self.vad_state_machine = VadStateMachine.kVadInStateEndPointDetected - else: - if cur_frm_idx >= self.LatencyFrmNumAtStartPoint(): - self.OnSilenceDetected(cur_frm_idx - self.LatencyFrmNumAtStartPoint()) - elif self.vad_state_machine == VadStateMachine.kVadInStateInSpeechSegment: - if self.continous_silence_frame_count * frm_shift_in_ms >= self.max_end_sil_frame_cnt_thresh: - lookback_frame = int(self.max_end_sil_frame_cnt_thresh / frm_shift_in_ms) - if self.vad_opts.do_extend: - lookback_frame -= int(self.vad_opts.lookahead_time_end_point / frm_shift_in_ms) - lookback_frame -= 1 - lookback_frame = max(0, lookback_frame) - self.OnVoiceEnd(cur_frm_idx - lookback_frame, False, False) - self.vad_state_machine = VadStateMachine.kVadInStateEndPointDetected - elif cur_frm_idx - self.confirmed_start_frame + 1 > \ - self.vad_opts.max_single_segment_time / frm_shift_in_ms: - self.OnVoiceEnd(cur_frm_idx, False, False) - self.vad_state_machine = VadStateMachine.kVadInStateEndPointDetected - elif self.vad_opts.do_extend and not is_final_frame: - if self.continous_silence_frame_count <= int( - self.vad_opts.lookahead_time_end_point / frm_shift_in_ms): - self.OnVoiceDetected(cur_frm_idx) - else: - self.MaybeOnVoiceEndIfLastFrame(is_final_frame, cur_frm_idx) - else: - pass - - if self.vad_state_machine == VadStateMachine.kVadInStateEndPointDetected and \ - self.vad_opts.detect_mode == VadDetectMode.kVadMutipleUtteranceDetectMode.value: - self.ResetDetection() diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/frontend.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/frontend.py deleted file mode 100644 index 11a86445d..000000000 --- a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/frontend.py +++ /dev/null @@ -1,191 +0,0 @@ -# -*- encoding: utf-8 -*- -from pathlib import Path -from typing import Any, Dict, Iterable, List, NamedTuple, Set, Tuple, Union - -import numpy as np -from typeguard import check_argument_types -import kaldi_native_fbank as knf - -root_dir = Path(__file__).resolve().parent - -logger_initialized = {} - - -class WavFrontend(): - """Conventional frontend structure for ASR. - """ - - def __init__( - self, - cmvn_file: str = None, - fs: int = 16000, - window: str = 'hamming', - n_mels: int = 80, - frame_length: int = 25, - frame_shift: int = 10, - lfr_m: int = 1, - lfr_n: int = 1, - dither: float = 1.0, - **kwargs, - ) -> None: - check_argument_types() - - opts = knf.FbankOptions() - opts.frame_opts.samp_freq = fs - opts.frame_opts.dither = dither - opts.frame_opts.window_type = window - opts.frame_opts.frame_shift_ms = float(frame_shift) - opts.frame_opts.frame_length_ms = float(frame_length) - opts.mel_opts.num_bins = n_mels - opts.energy_floor = 0 - opts.frame_opts.snip_edges = True - opts.mel_opts.debug_mel = False - self.opts = opts - - self.lfr_m = lfr_m - self.lfr_n = lfr_n - self.cmvn_file = cmvn_file - - if self.cmvn_file: - self.cmvn = self.load_cmvn() - self.fbank_fn = None - self.fbank_beg_idx = 0 - self.reset_status() - - def fbank(self, - waveform: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: - waveform = waveform * (1 << 15) - self.fbank_fn = knf.OnlineFbank(self.opts) - self.fbank_fn.accept_waveform(self.opts.frame_opts.samp_freq, waveform.tolist()) - frames = self.fbank_fn.num_frames_ready - mat = np.empty([frames, self.opts.mel_opts.num_bins]) - for i in range(frames): - mat[i, :] = self.fbank_fn.get_frame(i) - feat = mat.astype(np.float32) - feat_len = np.array(mat.shape[0]).astype(np.int32) - return feat, feat_len - - def fbank_online(self, - waveform: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: - waveform = waveform * (1 << 15) - # self.fbank_fn = knf.OnlineFbank(self.opts) - self.fbank_fn.accept_waveform(self.opts.frame_opts.samp_freq, waveform.tolist()) - frames = self.fbank_fn.num_frames_ready - mat = np.empty([frames, self.opts.mel_opts.num_bins]) - for i in range(self.fbank_beg_idx, frames): - mat[i, :] = self.fbank_fn.get_frame(i) - # self.fbank_beg_idx += (frames-self.fbank_beg_idx) - feat = mat.astype(np.float32) - feat_len = np.array(mat.shape[0]).astype(np.int32) - return feat, feat_len - - def reset_status(self): - self.fbank_fn = knf.OnlineFbank(self.opts) - self.fbank_beg_idx = 0 - - def lfr_cmvn(self, feat: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: - if self.lfr_m != 1 or self.lfr_n != 1: - feat = self.apply_lfr(feat, self.lfr_m, self.lfr_n) - - if self.cmvn_file: - feat = self.apply_cmvn(feat) - - feat_len = np.array(feat.shape[0]).astype(np.int32) - return feat, feat_len - - @staticmethod - def apply_lfr(inputs: np.ndarray, lfr_m: int, lfr_n: int) -> np.ndarray: - LFR_inputs = [] - - T = inputs.shape[0] - T_lfr = int(np.ceil(T / lfr_n)) - left_padding = np.tile(inputs[0], ((lfr_m - 1) // 2, 1)) - inputs = np.vstack((left_padding, inputs)) - T = T + (lfr_m - 1) // 2 - for i in range(T_lfr): - if lfr_m <= T - i * lfr_n: - LFR_inputs.append( - (inputs[i * lfr_n:i * lfr_n + lfr_m]).reshape(1, -1)) - else: - # process last LFR frame - num_padding = lfr_m - (T - i * lfr_n) - frame = inputs[i * lfr_n:].reshape(-1) - for _ in range(num_padding): - frame = np.hstack((frame, inputs[-1])) - - LFR_inputs.append(frame) - LFR_outputs = np.vstack(LFR_inputs).astype(np.float32) - return LFR_outputs - - def apply_cmvn(self, inputs: np.ndarray) -> np.ndarray: - """ - Apply CMVN with mvn data - """ - frame, dim = inputs.shape - means = np.tile(self.cmvn[0:1, :dim], (frame, 1)) - vars = np.tile(self.cmvn[1:2, :dim], (frame, 1)) - inputs = (inputs + means) * vars - return inputs - - def load_cmvn(self,) -> np.ndarray: - with open(self.cmvn_file, 'r', encoding='utf-8') as f: - lines = f.readlines() - - means_list = [] - vars_list = [] - for i in range(len(lines)): - line_item = lines[i].split() - if line_item[0] == '': - line_item = lines[i + 1].split() - if line_item[0] == '': - add_shift_line = line_item[3:(len(line_item) - 1)] - means_list = list(add_shift_line) - continue - elif line_item[0] == '': - line_item = lines[i + 1].split() - if line_item[0] == '': - rescale_line = line_item[3:(len(line_item) - 1)] - vars_list = list(rescale_line) - continue - - means = np.array(means_list).astype(np.float64) - vars = np.array(vars_list).astype(np.float64) - cmvn = np.array([means, vars]) - return cmvn - -def load_bytes(input): - middle_data = np.frombuffer(input, dtype=np.int16) - middle_data = np.asarray(middle_data) - if middle_data.dtype.kind not in 'iu': - raise TypeError("'middle_data' must be an array of integers") - dtype = np.dtype('float32') - if dtype.kind != 'f': - raise TypeError("'dtype' must be a floating point type") - - i = np.iinfo(middle_data.dtype) - abs_max = 2 ** (i.bits - 1) - offset = i.min + abs_max - array = np.frombuffer((middle_data.astype(dtype) - offset) / abs_max, dtype=np.float32) - return array - - -def test(): - path = "/nfs/zhifu.gzf/export/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/example/asr_example.wav" - import librosa - cmvn_file = "/nfs/zhifu.gzf/export/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/am.mvn" - config_file = "/nfs/zhifu.gzf/export/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/config.yaml" - from funasr.runtime.python.onnxruntime.rapid_paraformer.utils.utils import read_yaml - config = read_yaml(config_file) - waveform, _ = librosa.load(path, sr=None) - frontend = WavFrontend( - cmvn_file=cmvn_file, - **config['frontend_conf'], - ) - speech, _ = frontend.fbank_online(waveform) #1d, (sample,), numpy - feat, feat_len = frontend.lfr_cmvn(speech) # 2d, (frame, 450), np.float32 -> torch, torch.from_numpy(), dtype, (1, frame, 450) - - frontend.reset_status() # clear cache - return feat, feat_len - -if __name__ == '__main__': - test() \ No newline at end of file diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/postprocess_utils.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/postprocess_utils.py deleted file mode 100644 index 575fb90dd..000000000 --- a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/postprocess_utils.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright (c) Alibaba, Inc. and its affiliates. - -import string -import logging -from typing import Any, List, Union - - -def isChinese(ch: str): - if '\u4e00' <= ch <= '\u9fff' or '\u0030' <= ch <= '\u0039': - return True - return False - - -def isAllChinese(word: Union[List[Any], str]): - word_lists = [] - for i in word: - cur = i.replace(' ', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - word_lists.append(cur) - - if len(word_lists) == 0: - return False - - for ch in word_lists: - if isChinese(ch) is False: - return False - return True - - -def isAllAlpha(word: Union[List[Any], str]): - word_lists = [] - for i in word: - cur = i.replace(' ', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - word_lists.append(cur) - - if len(word_lists) == 0: - return False - - for ch in word_lists: - if ch.isalpha() is False and ch != "'": - return False - elif ch.isalpha() is True and isChinese(ch) is True: - return False - - return True - - -# def abbr_dispose(words: List[Any]) -> List[Any]: -def abbr_dispose(words: List[Any], time_stamp: List[List] = None) -> List[Any]: - words_size = len(words) - word_lists = [] - abbr_begin = [] - abbr_end = [] - last_num = -1 - ts_lists = [] - ts_nums = [] - ts_index = 0 - for num in range(words_size): - if num <= last_num: - continue - - if len(words[num]) == 1 and words[num].encode('utf-8').isalpha(): - if num + 1 < words_size and words[ - num + 1] == ' ' and num + 2 < words_size and len( - words[num + - 2]) == 1 and words[num + - 2].encode('utf-8').isalpha(): - # found the begin of abbr - abbr_begin.append(num) - num += 2 - abbr_end.append(num) - # to find the end of abbr - while True: - num += 1 - if num < words_size and words[num] == ' ': - num += 1 - if num < words_size and len( - words[num]) == 1 and words[num].encode( - 'utf-8').isalpha(): - abbr_end.pop() - abbr_end.append(num) - last_num = num - else: - break - else: - break - - for num in range(words_size): - if words[num] == ' ': - ts_nums.append(ts_index) - else: - ts_nums.append(ts_index) - ts_index += 1 - last_num = -1 - for num in range(words_size): - if num <= last_num: - continue - - if num in abbr_begin: - if time_stamp is not None: - begin = time_stamp[ts_nums[num]][0] - word_lists.append(words[num].upper()) - num += 1 - while num < words_size: - if num in abbr_end: - word_lists.append(words[num].upper()) - last_num = num - break - else: - if words[num].encode('utf-8').isalpha(): - word_lists.append(words[num].upper()) - num += 1 - if time_stamp is not None: - end = time_stamp[ts_nums[num]][1] - ts_lists.append([begin, end]) - else: - word_lists.append(words[num]) - if time_stamp is not None and words[num] != ' ': - begin = time_stamp[ts_nums[num]][0] - end = time_stamp[ts_nums[num]][1] - ts_lists.append([begin, end]) - begin = end - - if time_stamp is not None: - return word_lists, ts_lists - else: - return word_lists - - -def sentence_postprocess(words: List[Any], time_stamp: List[List] = None): - middle_lists = [] - word_lists = [] - word_item = '' - ts_lists = [] - - # wash words lists - for i in words: - word = '' - if isinstance(i, str): - word = i - else: - word = i.decode('utf-8') - - if word in ['', '', '']: - continue - else: - middle_lists.append(word) - - # all chinese characters - if isAllChinese(middle_lists): - for i, ch in enumerate(middle_lists): - word_lists.append(ch.replace(' ', '')) - if time_stamp is not None: - ts_lists = time_stamp - - # all alpha characters - elif isAllAlpha(middle_lists): - ts_flag = True - for i, ch in enumerate(middle_lists): - if ts_flag and time_stamp is not None: - begin = time_stamp[i][0] - end = time_stamp[i][1] - word = '' - if '@@' in ch: - word = ch.replace('@@', '') - word_item += word - if time_stamp is not None: - ts_flag = False - end = time_stamp[i][1] - else: - word_item += ch - word_lists.append(word_item) - word_lists.append(' ') - word_item = '' - if time_stamp is not None: - ts_flag = True - end = time_stamp[i][1] - ts_lists.append([begin, end]) - begin = end - - # mix characters - else: - alpha_blank = False - ts_flag = True - begin = -1 - end = -1 - for i, ch in enumerate(middle_lists): - if ts_flag and time_stamp is not None: - begin = time_stamp[i][0] - end = time_stamp[i][1] - word = '' - if isAllChinese(ch): - if alpha_blank is True: - word_lists.pop() - word_lists.append(ch) - alpha_blank = False - if time_stamp is not None: - ts_flag = True - ts_lists.append([begin, end]) - begin = end - elif '@@' in ch: - word = ch.replace('@@', '') - word_item += word - alpha_blank = False - if time_stamp is not None: - ts_flag = False - end = time_stamp[i][1] - elif isAllAlpha(ch): - word_item += ch - word_lists.append(word_item) - word_lists.append(' ') - word_item = '' - alpha_blank = True - if time_stamp is not None: - ts_flag = True - end = time_stamp[i][1] - ts_lists.append([begin, end]) - begin = end - else: - raise ValueError('invalid character: {}'.format(ch)) - - if time_stamp is not None: - word_lists, ts_lists = abbr_dispose(word_lists, ts_lists) - real_word_lists = [] - for ch in word_lists: - if ch != ' ': - real_word_lists.append(ch) - sentence = ' '.join(real_word_lists).strip() - return sentence, ts_lists, real_word_lists - else: - word_lists = abbr_dispose(word_lists) - real_word_lists = [] - for ch in word_lists: - if ch != ' ': - real_word_lists.append(ch) - sentence = ''.join(word_lists).strip() - return sentence, real_word_lists diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/timestamp_utils.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/timestamp_utils.py deleted file mode 100644 index 3a01812e8..000000000 --- a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/timestamp_utils.py +++ /dev/null @@ -1,59 +0,0 @@ -import numpy as np - - -def time_stamp_lfr6_onnx(us_cif_peak, char_list, begin_time=0.0, total_offset=-1.5): - if not len(char_list): - return [] - START_END_THRESHOLD = 5 - MAX_TOKEN_DURATION = 30 - TIME_RATE = 10.0 * 6 / 1000 / 3 # 3 times upsampled - cif_peak = us_cif_peak.reshape(-1) - num_frames = cif_peak.shape[-1] - if char_list[-1] == '': - char_list = char_list[:-1] - # char_list = [i for i in text] - timestamp_list = [] - new_char_list = [] - # for bicif model trained with large data, cif2 actually fires when a character starts - # so treat the frames between two peaks as the duration of the former token - fire_place = np.where(cif_peak>1.0-1e-4)[0] + total_offset # np format - num_peak = len(fire_place) - assert num_peak == len(char_list) + 1 # number of peaks is supposed to be number of tokens + 1 - # begin silence - if fire_place[0] > START_END_THRESHOLD: - # char_list.insert(0, '') - timestamp_list.append([0.0, fire_place[0]*TIME_RATE]) - new_char_list.append('') - # tokens timestamp - for i in range(len(fire_place)-1): - new_char_list.append(char_list[i]) - if i == len(fire_place)-2 or MAX_TOKEN_DURATION < 0 or fire_place[i+1] - fire_place[i] < MAX_TOKEN_DURATION: - timestamp_list.append([fire_place[i]*TIME_RATE, fire_place[i+1]*TIME_RATE]) - else: - # cut the duration to token and sil of the 0-weight frames last long - _split = fire_place[i] + MAX_TOKEN_DURATION - timestamp_list.append([fire_place[i]*TIME_RATE, _split*TIME_RATE]) - timestamp_list.append([_split*TIME_RATE, fire_place[i+1]*TIME_RATE]) - new_char_list.append('') - # tail token and end silence - if num_frames - fire_place[-1] > START_END_THRESHOLD: - _end = (num_frames + fire_place[-1]) / 2 - timestamp_list[-1][1] = _end*TIME_RATE - timestamp_list.append([_end*TIME_RATE, num_frames*TIME_RATE]) - new_char_list.append("") - else: - timestamp_list[-1][1] = num_frames*TIME_RATE - if begin_time: # add offset time in model with vad - for i in range(len(timestamp_list)): - timestamp_list[i][0] = timestamp_list[i][0] + begin_time / 1000.0 - timestamp_list[i][1] = timestamp_list[i][1] + begin_time / 1000.0 - assert len(new_char_list) == len(timestamp_list) - res_str = "" - for char, timestamp in zip(new_char_list, timestamp_list): - res_str += "{} {} {};".format(char, timestamp[0], timestamp[1]) - res = [] - for char, timestamp in zip(new_char_list, timestamp_list): - if char != '': - res.append([int(timestamp[0] * 1000), int(timestamp[1] * 1000)]) - return res_str, res - \ No newline at end of file diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/utils.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/utils.py deleted file mode 100644 index 2edde112e..000000000 --- a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/utils/utils.py +++ /dev/null @@ -1,257 +0,0 @@ -# -*- encoding: utf-8 -*- - -import functools -import logging -import pickle -from pathlib import Path -from typing import Any, Dict, Iterable, List, NamedTuple, Set, Tuple, Union - -import numpy as np -import yaml -from onnxruntime import (GraphOptimizationLevel, InferenceSession, - SessionOptions, get_available_providers, get_device) -from typeguard import check_argument_types - -import warnings - -root_dir = Path(__file__).resolve().parent - -logger_initialized = {} - - -class TokenIDConverter(): - def __init__(self, token_list: Union[List, str], - ): - check_argument_types() - - # self.token_list = self.load_token(token_path) - self.token_list = token_list - self.unk_symbol = token_list[-1] - - # @staticmethod - # def load_token(file_path: Union[Path, str]) -> List: - # if not Path(file_path).exists(): - # raise TokenIDConverterError(f'The {file_path} does not exist.') - # - # with open(str(file_path), 'rb') as f: - # token_list = pickle.load(f) - # - # if len(token_list) != len(set(token_list)): - # raise TokenIDConverterError('The Token exists duplicated symbol.') - # return token_list - - def get_num_vocabulary_size(self) -> int: - return len(self.token_list) - - def ids2tokens(self, - integers: Union[np.ndarray, Iterable[int]]) -> List[str]: - if isinstance(integers, np.ndarray) and integers.ndim != 1: - raise TokenIDConverterError( - f"Must be 1 dim ndarray, but got {integers.ndim}") - return [self.token_list[i] for i in integers] - - def tokens2ids(self, tokens: Iterable[str]) -> List[int]: - token2id = {v: i for i, v in enumerate(self.token_list)} - if self.unk_symbol not in token2id: - raise TokenIDConverterError( - f"Unknown symbol '{self.unk_symbol}' doesn't exist in the token_list" - ) - unk_id = token2id[self.unk_symbol] - return [token2id.get(i, unk_id) for i in tokens] - - -class CharTokenizer(): - def __init__( - self, - symbol_value: Union[Path, str, Iterable[str]] = None, - space_symbol: str = "", - remove_non_linguistic_symbols: bool = False, - ): - check_argument_types() - - self.space_symbol = space_symbol - self.non_linguistic_symbols = self.load_symbols(symbol_value) - self.remove_non_linguistic_symbols = remove_non_linguistic_symbols - - @staticmethod - def load_symbols(value: Union[Path, str, Iterable[str]] = None) -> Set: - if value is None: - return set() - - if isinstance(value, Iterable[str]): - return set(value) - - file_path = Path(value) - if not file_path.exists(): - logging.warning("%s doesn't exist.", file_path) - return set() - - with file_path.open("r", encoding="utf-8") as f: - return set(line.rstrip() for line in f) - - def text2tokens(self, line: Union[str, list]) -> List[str]: - tokens = [] - while len(line) != 0: - for w in self.non_linguistic_symbols: - if line.startswith(w): - if not self.remove_non_linguistic_symbols: - tokens.append(line[: len(w)]) - line = line[len(w):] - break - else: - t = line[0] - if t == " ": - t = "" - tokens.append(t) - line = line[1:] - return tokens - - def tokens2text(self, tokens: Iterable[str]) -> str: - tokens = [t if t != self.space_symbol else " " for t in tokens] - return "".join(tokens) - - def __repr__(self): - return ( - f"{self.__class__.__name__}(" - f'space_symbol="{self.space_symbol}"' - f'non_linguistic_symbols="{self.non_linguistic_symbols}"' - f")" - ) - - - -class Hypothesis(NamedTuple): - """Hypothesis data type.""" - - yseq: np.ndarray - score: Union[float, np.ndarray] = 0 - scores: Dict[str, Union[float, np.ndarray]] = dict() - states: Dict[str, Any] = dict() - - def asdict(self) -> dict: - """Convert data to JSON-friendly dict.""" - return self._replace( - yseq=self.yseq.tolist(), - score=float(self.score), - scores={k: float(v) for k, v in self.scores.items()}, - )._asdict() - - -class TokenIDConverterError(Exception): - pass - - -class ONNXRuntimeError(Exception): - pass - - -class OrtInferSession(): - def __init__(self, model_file, device_id=-1, intra_op_num_threads=4): - device_id = str(device_id) - sess_opt = SessionOptions() - sess_opt.intra_op_num_threads = intra_op_num_threads - sess_opt.log_severity_level = 4 - sess_opt.enable_cpu_mem_arena = False - sess_opt.graph_optimization_level = GraphOptimizationLevel.ORT_ENABLE_ALL - - cuda_ep = 'CUDAExecutionProvider' - cuda_provider_options = { - "device_id": device_id, - "arena_extend_strategy": "kNextPowerOfTwo", - "cudnn_conv_algo_search": "EXHAUSTIVE", - "do_copy_in_default_stream": "true", - } - cpu_ep = 'CPUExecutionProvider' - cpu_provider_options = { - "arena_extend_strategy": "kSameAsRequested", - } - - EP_list = [] - if device_id != "-1" and get_device() == 'GPU' \ - and cuda_ep in get_available_providers(): - EP_list = [(cuda_ep, cuda_provider_options)] - EP_list.append((cpu_ep, cpu_provider_options)) - - self._verify_model(model_file) - self.session = InferenceSession(model_file, - sess_options=sess_opt, - providers=EP_list) - - if device_id != "-1" and cuda_ep not in self.session.get_providers(): - warnings.warn(f'{cuda_ep} is not avaiable for current env, the inference part is automatically shifted to be executed under {cpu_ep}.\n' - 'Please ensure the installed onnxruntime-gpu version matches your cuda and cudnn version, ' - 'you can check their relations from the offical web site: ' - 'https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html', - RuntimeWarning) - - def __call__(self, - input_content: List[Union[np.ndarray, np.ndarray]]) -> np.ndarray: - input_dict = dict(zip(self.get_input_names(), input_content)) - try: - return self.session.run(None, input_dict) - except Exception as e: - raise ONNXRuntimeError('ONNXRuntime inferece failed.') from e - - def get_input_names(self, ): - return [v.name for v in self.session.get_inputs()] - - def get_output_names(self,): - return [v.name for v in self.session.get_outputs()] - - def get_character_list(self, key: str = 'character'): - return self.meta_dict[key].splitlines() - - def have_key(self, key: str = 'character') -> bool: - self.meta_dict = self.session.get_modelmeta().custom_metadata_map - if key in self.meta_dict.keys(): - return True - return False - - @staticmethod - def _verify_model(model_path): - model_path = Path(model_path) - if not model_path.exists(): - raise FileNotFoundError(f'{model_path} does not exists.') - if not model_path.is_file(): - raise FileExistsError(f'{model_path} is not a file.') - - -def read_yaml(yaml_path: Union[str, Path]) -> Dict: - if not Path(yaml_path).exists(): - raise FileExistsError(f'The {yaml_path} does not exist.') - - with open(str(yaml_path), 'rb') as f: - data = yaml.load(f, Loader=yaml.Loader) - return data - - -@functools.lru_cache() -def get_logger(name='rapdi_paraformer'): - """Initialize and get a logger by name. - If the logger has not been initialized, this method will initialize the - logger by adding one or two handlers, otherwise the initialized logger will - be directly returned. During initialization, a StreamHandler will always be - added. - Args: - name (str): Logger name. - Returns: - logging.Logger: The expected logger. - """ - logger = logging.getLogger(name) - if name in logger_initialized: - return logger - - for logger_name in logger_initialized: - if name.startswith(logger_name): - return logger - - formatter = logging.Formatter( - '[%(asctime)s] %(name)s %(levelname)s: %(message)s', - datefmt="%Y/%m/%d %H:%M:%S") - - sh = logging.StreamHandler() - sh.setFormatter(formatter) - logger.addHandler(sh) - logger_initialized[name] = True - logger.propagate = False - return logger diff --git a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/vad_bin.py b/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/vad_bin.py deleted file mode 100644 index 58913bbd3..000000000 --- a/funasr/runtime/python/onnxruntime/build/lib/funasr_onnx/vad_bin.py +++ /dev/null @@ -1,166 +0,0 @@ -# -*- encoding: utf-8 -*- - -import os.path -from pathlib import Path -from typing import List, Union, Tuple - -import copy -import librosa -import numpy as np - -from .utils.utils import (CharTokenizer, Hypothesis, ONNXRuntimeError, - OrtInferSession, TokenIDConverter, get_logger, - read_yaml) -from .utils.postprocess_utils import sentence_postprocess -from .utils.frontend import WavFrontend -from .utils.timestamp_utils import time_stamp_lfr6_onnx -from .utils.e2e_vad import E2EVadModel - -logging = get_logger() - - -class Fsmn_vad(): - def __init__(self, model_dir: Union[str, Path] = None, - batch_size: int = 1, - device_id: Union[str, int] = "-1", - quantize: bool = False, - intra_op_num_threads: int = 4, - max_end_sil: int = 800, - ): - - if not Path(model_dir).exists(): - raise FileNotFoundError(f'{model_dir} does not exist.') - - model_file = os.path.join(model_dir, 'model.onnx') - if quantize: - model_file = os.path.join(model_dir, 'model_quant.onnx') - config_file = os.path.join(model_dir, 'vad.yaml') - cmvn_file = os.path.join(model_dir, 'vad.mvn') - config = read_yaml(config_file) - - self.frontend = WavFrontend( - cmvn_file=cmvn_file, - **config['frontend_conf'] - ) - self.ort_infer = OrtInferSession(model_file, device_id, intra_op_num_threads=intra_op_num_threads) - self.batch_size = batch_size - self.vad_scorer = E2EVadModel(**config) - self.max_end_sil = max_end_sil - - def prepare_cache(self, in_cache: list = []): - if len(in_cache) > 0: - return in_cache - - for i in range(4): - cache = np.random.rand(1, 128, 19, 1).astype(np.float32) - in_cache.append(cache) - return in_cache - - - def __call__(self, wav_content: Union[str, np.ndarray, List[str]], **kwargs) -> List: - waveform_list = self.load_data(wav_content, self.frontend.opts.frame_opts.samp_freq) - waveform_nums = len(waveform_list) - is_final = kwargs.get('kwargs', False) - - asr_res = [] - for beg_idx in range(0, waveform_nums, self.batch_size): - - end_idx = min(waveform_nums, beg_idx + self.batch_size) - waveform = waveform_list[beg_idx:end_idx] - feats, feats_len = self.extract_feat(waveform) - param_dict = kwargs.get('param_dict', dict()) - in_cache = param_dict.get('cache', list()) - in_cache = self.prepare_cache(in_cache) - try: - - scores, out_caches = self.infer(feats, *in_cache) - param_dict['cache'] = out_caches - segments = self.vad_scorer(scores, waveform, is_final=is_final, max_end_sil=self.max_end_sil) - - except ONNXRuntimeError: - # logging.warning(traceback.format_exc()) - logging.warning("input wav is silence or noise") - segments = '' - asr_res.append(segments) - # else: - # preds = self.decode(am_scores, valid_token_lens) - # - # asr_res.append({'preds': text_proc, 'timestamp': timestamp_proc, "raw_tokens": raw_tokens}) - - return asr_res - - def load_data(self, - wav_content: Union[str, np.ndarray, List[str]], fs: int = None) -> List: - def load_wav(path: str) -> np.ndarray: - waveform, _ = librosa.load(path, sr=fs) - return waveform - - if isinstance(wav_content, np.ndarray): - return [wav_content] - - if isinstance(wav_content, str): - return [load_wav(wav_content)] - - if isinstance(wav_content, list): - return [load_wav(path) for path in wav_content] - - raise TypeError( - f'The type of {wav_content} is not in [str, np.ndarray, list]') - - def extract_feat(self, - waveform_list: List[np.ndarray] - ) -> Tuple[np.ndarray, np.ndarray]: - feats, feats_len = [], [] - for waveform in waveform_list: - speech, _ = self.frontend.fbank(waveform) - feat, feat_len = self.frontend.lfr_cmvn(speech) - feats.append(feat) - feats_len.append(feat_len) - - feats = self.pad_feats(feats, np.max(feats_len)) - feats_len = np.array(feats_len).astype(np.int32) - return feats, feats_len - - @staticmethod - def pad_feats(feats: List[np.ndarray], max_feat_len: int) -> np.ndarray: - def pad_feat(feat: np.ndarray, cur_len: int) -> np.ndarray: - pad_width = ((0, max_feat_len - cur_len), (0, 0)) - return np.pad(feat, pad_width, 'constant', constant_values=0) - - feat_res = [pad_feat(feat, feat.shape[0]) for feat in feats] - feats = np.array(feat_res).astype(np.float32) - return feats - - def infer(self, feats: np.ndarray, - feats_len: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: - outputs = self.ort_infer([feats, feats_len]) - return outputs - - def decode(self, am_scores: np.ndarray, token_nums: int) -> List[str]: - return [self.decode_one(am_score, token_num) - for am_score, token_num in zip(am_scores, token_nums)] - - def decode_one(self, - am_score: np.ndarray, - valid_token_num: int) -> List[str]: - yseq = am_score.argmax(axis=-1) - score = am_score.max(axis=-1) - score = np.sum(score, axis=-1) - - # pad with mask tokens to ensure compatibility with sos/eos tokens - # asr_model.sos:1 asr_model.eos:2 - yseq = np.array([1] + yseq.tolist() + [2]) - hyp = Hypothesis(yseq=yseq, score=score) - - # remove sos/eos and get results - last_pos = -1 - token_int = hyp.yseq[1:last_pos].tolist() - - # remove blank symbol id, which is assumed to be 0 - token_int = list(filter(lambda x: x not in (0, 2), token_int)) - - # Change integer-ids to tokens - token = self.converter.ids2tokens(token_int) - token = token[:valid_token_num - self.pred_bias] - # texts = sentence_postprocess(token) - return token diff --git a/funasr/runtime/python/onnxruntime/dist/funasr_onnx-0.0.2-py3.8.egg b/funasr/runtime/python/onnxruntime/dist/funasr_onnx-0.0.2-py3.8.egg deleted file mode 100644 index b24107b404d6479b053e263ed23f22a0c30e8980..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47828 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 AssI20