From d8b8dbd32db3b998e3e566e1d0289fa3f1b7e58c Mon Sep 17 00:00:00 2001 From: Yuekai Zhang Date: Mon, 6 Mar 2023 15:42:01 +0800 Subject: [PATCH] update client doc --- .../triton_gpu/Dockerfile/Dockerfile.server | 4 +- funasr/runtime/triton_gpu/README.md | 56 +- .../client/decode_manifest_triton.py | 541 ++++++++++++++++++ .../feature_extractor/1/model.py | 4 +- .../feature_extractor/config.yaml | 23 +- .../scoring/1/model.py | 4 +- .../scoring/config.pbtxt | 2 +- .../scoring/token_list.pkl | Bin 51686 -> 0 bytes 8 files changed, 596 insertions(+), 38 deletions(-) create mode 100644 funasr/runtime/triton_gpu/client/decode_manifest_triton.py delete mode 100644 funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/token_list.pkl diff --git a/funasr/runtime/triton_gpu/Dockerfile/Dockerfile.server b/funasr/runtime/triton_gpu/Dockerfile/Dockerfile.server index 459195cae..d03610c58 100644 --- a/funasr/runtime/triton_gpu/Dockerfile/Dockerfile.server +++ b/funasr/runtime/triton_gpu/Dockerfile/Dockerfile.server @@ -10,8 +10,10 @@ RUN apt-get update && apt-get -y install \ cmake \ libsndfile1 +# -i https://pypi.tuna.tsinghua.edu.cn/simple +RUN pip3 install torch torchaudio RUN pip3 install kaldifeat pyyaml # Dependency for client -RUN pip3 install soundfile grpcio-tools tritonclient pyyaml +RUN pip3 install soundfile grpcio-tools tritonclient WORKDIR /workspace diff --git a/funasr/runtime/triton_gpu/README.md b/funasr/runtime/triton_gpu/README.md index daceb4e03..242c70a3b 100644 --- a/funasr/runtime/triton_gpu/README.md +++ b/funasr/runtime/triton_gpu/README.md @@ -1,16 +1,21 @@ ## Inference with Triton ### Steps: -1. Refer here to [get model.onnx](https://github.com/alibaba-damo-academy/FunASR/blob/main/funasr/export/README.md) - -2. Follow below instructions to using triton +1. Prepare model repo files ```sh -# using docker image Dockerfile/Dockerfile.server -docker build . -f Dockerfile/Dockerfile.server -t triton-paraformer:23.01 -docker run -it --rm --name "paraformer_triton_server" --gpus all -v :/workspace --shm-size 1g --net host triton-paraformer:23.01 -# inside the docker container, prepare previous exported model.onnx -mv /workspace/triton_gpu/model_repo_paraformer_large_offline/encoder/1/ +git-lfs install +git clone https://www.modelscope.cn/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch.git +pretrained_model_dir=$(pwd)/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch + +cp $pretrained_model_dir/tokens.txt ./model_repo_paraformer_large_offline/scoring/ +cp $pretrained_model_dir/am.mvn ./model_repo_paraformer_large_offline/feature_extractor/ + +# Refer here to get model.onnx (https://github.com/alibaba-damo-academy/FunASR/blob/main/funasr/export/README.md) +cp /model.onnx ./model_repo_paraformer_large_offline/encoder/1/ +``` +Log of directory tree: +```sh model_repo_paraformer_large_offline/ |-- encoder | |-- 1 @@ -20,6 +25,7 @@ model_repo_paraformer_large_offline/ | |-- 1 | | `-- model.py | |-- config.pbtxt +| |-- am.mvn | `-- config.yaml |-- infer_pipeline | |-- 1 @@ -28,12 +34,19 @@ model_repo_paraformer_large_offline/ |-- 1 | `-- model.py |-- config.pbtxt - `-- token_list.pkl + `-- tokens.txt -8 directories, 9 files +8 directories, 10 files +``` + +2. Follow below instructions to launch triton server +```sh +# using docker image Dockerfile/Dockerfile.server +docker build . -f Dockerfile/Dockerfile.server -t triton-paraformer:23.01 +docker run -it --rm --name "paraformer_triton_server" --gpus all -v :/workspace/ --shm-size 1g --net host triton-paraformer:23.01 # launch the service -tritonserver --model-repository ./model_repo_paraformer_large_offline \ +tritonserver --model-repository /workspace/model_repo_paraformer_large_offline \ --pinned-memory-pool-byte-size=512000000 \ --cuda-memory-pool-byte-size=0:1024000000 @@ -43,6 +56,27 @@ tritonserver --model-repository ./model_repo_paraformer_large_offline \ Benchmark [speech_paraformer](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/summary) based on Aishell1 test set with a single V100, the total audio duration is 36108.919 seconds. +```sh +# For client container: +docker run -it --rm --name "client_test" --net host --gpus all -v :/workpace/ soar97/triton-k2:22.12.1 # noqa +# For aishell manifests: +apt-get install git-lfs +git-lfs install +git clone https://huggingface.co/csukuangfj/aishell-test-dev-manifests +sudo mkdir -p /root/fangjun/open-source/icefall-aishell/egs/aishell/ASR/download/aishell +tar xf ./aishell-test-dev-manifests/data_aishell.tar.gz -C /root/fangjun/open-source/icefall-aishell/egs/aishell/ASR/download/aishell/ # noqa + +serveraddr=localhost +manifest_path=/workspace/aishell-test-dev-manifests/data/fbank/aishell_cuts_test.jsonl.gz +num_task=60 +python3 client/decode_manifest_triton.py \ + --server-addr $serveraddr \ + --compute-cer \ + --model-name infer_pipeline \ + --num-tasks $num_task \ + --manifest-filename $manifest_path +``` + (Note: The service has been fully warm up.) |concurrent-tasks | processing time(s) | RTF | |----------|--------------------|------------| diff --git a/funasr/runtime/triton_gpu/client/decode_manifest_triton.py b/funasr/runtime/triton_gpu/client/decode_manifest_triton.py new file mode 100644 index 000000000..3a8d57fed --- /dev/null +++ b/funasr/runtime/triton_gpu/client/decode_manifest_triton.py @@ -0,0 +1,541 @@ +#!/usr/bin/env python3 +# Copyright 2022 Xiaomi Corp. (authors: Fangjun Kuang) +# 2023 Nvidia (authors: Yuekai Zhang) +# See LICENSE for clarification regarding multiple authors +# +# 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. +""" +This script loads a manifest in lhotse format and sends it to the server +for decoding, in parallel. + +Usage: +# For offline wenet server +./decode_manifest_triton.py \ + --server-addr localhost \ + --compute-cer \ + --model-name attention_rescoring \ + --num-tasks 300 \ + --manifest-filename ./aishell-test-dev-manifests/data/fbank/aishell_cuts_test.jsonl.gz # noqa + +# For streaming wenet server +./decode_manifest_triton.py \ + --server-addr localhost \ + --streaming \ + --compute-cer \ + --context 7 \ + --model-name streaming_wenet \ + --num-tasks 300 \ + --manifest-filename ./aishell-test-dev-manifests/data/fbank/aishell_cuts_test.jsonl.gz # noqa + +# For simulate streaming mode wenet server +./decode_manifest_triton.py \ + --server-addr localhost \ + --simulate-streaming \ + --compute-cer \ + --context 7 \ + --model-name streaming_wenet \ + --num-tasks 300 \ + --manifest-filename ./aishell-test-dev-manifests/data/fbank/aishell_cuts_test.jsonl.gz # noqa + +# For test container: +docker run -it --rm --name "wenet_client_test" --net host --gpus all soar97/triton-k2:22.12.1 # noqa + +# For aishell manifests: +apt-get install git-lfs +git-lfs install +git clone https://huggingface.co/csukuangfj/aishell-test-dev-manifests +sudo mkdir -p /root/fangjun/open-source/icefall-aishell/egs/aishell/ASR/download/aishell +tar xf ./aishell-test-dev-manifests/data_aishell.tar.gz -C /root/fangjun/open-source/icefall-aishell/egs/aishell/ASR/download/aishell/ # noqa + +""" + +import argparse +import asyncio +import math +import time +import types +from pathlib import Path +import json +import numpy as np +import tritonclient +import tritonclient.grpc.aio as grpcclient +from lhotse import CutSet, load_manifest +from tritonclient.utils import np_to_triton_dtype + +from icefall.utils import store_transcripts, write_error_stats + +DEFAULT_MANIFEST_FILENAME = "/mnt/samsung-t7/yuekai/aishell-test-dev-manifests/data/fbank/aishell_cuts_test.jsonl.gz" # noqa + + +def get_args(): + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + + parser.add_argument( + "--server-addr", + type=str, + default="localhost", + help="Address of the server", + ) + + parser.add_argument( + "--server-port", + type=int, + default=8001, + help="Port of the server", + ) + + parser.add_argument( + "--manifest-filename", + type=str, + default=DEFAULT_MANIFEST_FILENAME, + help="Path to the manifest for decoding", + ) + + parser.add_argument( + "--model-name", + type=str, + default="transducer", + help="triton model_repo module name to request", + ) + + parser.add_argument( + "--num-tasks", + type=int, + default=50, + help="Number of tasks to use for sending", + ) + + parser.add_argument( + "--log-interval", + type=int, + default=5, + help="Controls how frequently we print the log.", + ) + + parser.add_argument( + "--compute-cer", + action="store_true", + default=False, + help="""True to compute CER, e.g., for Chinese. + False to compute WER, e.g., for English words. + """, + ) + + parser.add_argument( + "--streaming", + action="store_true", + default=False, + help="""True for streaming ASR. + """, + ) + + parser.add_argument( + "--simulate-streaming", + action="store_true", + default=False, + help="""True for strictly simulate streaming ASR. + Threads will sleep to simulate the real speaking scene. + """, + ) + + parser.add_argument( + "--chunk_size", + type=int, + required=False, + default=16, + help="chunk size default is 16", + ) + + parser.add_argument( + "--context", + type=int, + required=False, + default=-1, + help="subsampling context for wenet", + ) + + parser.add_argument( + "--encoder_right_context", + type=int, + required=False, + default=2, + help="encoder right context", + ) + + parser.add_argument( + "--subsampling", + type=int, + required=False, + default=4, + help="subsampling rate", + ) + + parser.add_argument( + "--stats_file", + type=str, + required=False, + default="./stats.json", + help="output of stats anaylasis", + ) + + return parser.parse_args() + + +async def send( + cuts: CutSet, + name: str, + triton_client: tritonclient.grpc.aio.InferenceServerClient, + protocol_client: types.ModuleType, + log_interval: int, + compute_cer: bool, + model_name: str, +): + total_duration = 0.0 + results = [] + + for i, c in enumerate(cuts): + if i % log_interval == 0: + print(f"{name}: {i}/{len(cuts)}") + + waveform = c.load_audio().reshape(-1).astype(np.float32) + sample_rate = 16000 + + # padding to nearset 10 seconds + samples = np.zeros( + ( + 1, + 10 * sample_rate * (int(len(waveform) / sample_rate // 10) + 1), + ), + dtype=np.float32, + ) + samples[0, : len(waveform)] = waveform + + lengths = np.array([[len(waveform)]], dtype=np.int32) + + inputs = [ + protocol_client.InferInput( + "WAV", samples.shape, np_to_triton_dtype(samples.dtype) + ), + protocol_client.InferInput( + "WAV_LENS", lengths.shape, np_to_triton_dtype(lengths.dtype) + ), + ] + inputs[0].set_data_from_numpy(samples) + inputs[1].set_data_from_numpy(lengths) + outputs = [protocol_client.InferRequestedOutput("TRANSCRIPTS")] + sequence_id = 10086 + i + + response = await triton_client.infer( + model_name, inputs, request_id=str(sequence_id), outputs=outputs + ) + + decoding_results = response.as_numpy("TRANSCRIPTS")[0] + if type(decoding_results) == np.ndarray: + decoding_results = b" ".join(decoding_results).decode("utf-8") + else: + # For wenet + decoding_results = decoding_results.decode("utf-8") + + total_duration += c.duration + + if compute_cer: + ref = c.supervisions[0].text.split() + hyp = decoding_results.split() + ref = list("".join(ref)) + hyp = list("".join(hyp)) + results.append((c.id, ref, hyp)) + else: + results.append( + ( + c.id, + c.supervisions[0].text.split(), + decoding_results.split(), + ) + ) # noqa + + return total_duration, results + + +async def send_streaming( + cuts: CutSet, + name: str, + triton_client: tritonclient.grpc.aio.InferenceServerClient, + protocol_client: types.ModuleType, + log_interval: int, + compute_cer: bool, + model_name: str, + first_chunk_in_secs: float, + other_chunk_in_secs: float, + task_index: int, + simulate_mode: bool = False, +): + total_duration = 0.0 + results = [] + latency_data = [] + + for i, c in enumerate(cuts): + if i % log_interval == 0: + print(f"{name}: {i}/{len(cuts)}") + + waveform = c.load_audio().reshape(-1).astype(np.float32) + sample_rate = 16000 + + wav_segs = [] + + j = 0 + while j < len(waveform): + if j == 0: + stride = int(first_chunk_in_secs * sample_rate) + wav_segs.append(waveform[j : j + stride]) + else: + stride = int(other_chunk_in_secs * sample_rate) + wav_segs.append(waveform[j : j + stride]) + j += len(wav_segs[-1]) + + sequence_id = task_index + 10086 + + for idx, seg in enumerate(wav_segs): + chunk_len = len(seg) + + if simulate_mode: + await asyncio.sleep(chunk_len / sample_rate) + + chunk_start = time.time() + if idx == 0: + chunk_samples = int(first_chunk_in_secs * sample_rate) + expect_input = np.zeros((1, chunk_samples), dtype=np.float32) + else: + chunk_samples = int(other_chunk_in_secs * sample_rate) + expect_input = np.zeros((1, chunk_samples), dtype=np.float32) + + expect_input[0][0:chunk_len] = seg + input0_data = expect_input + input1_data = np.array([[chunk_len]], dtype=np.int32) + + inputs = [ + protocol_client.InferInput( + "WAV", + input0_data.shape, + np_to_triton_dtype(input0_data.dtype), + ), + protocol_client.InferInput( + "WAV_LENS", + input1_data.shape, + np_to_triton_dtype(input1_data.dtype), + ), + ] + + inputs[0].set_data_from_numpy(input0_data) + inputs[1].set_data_from_numpy(input1_data) + + outputs = [protocol_client.InferRequestedOutput("TRANSCRIPTS")] + end = False + if idx == len(wav_segs) - 1: + end = True + + response = await triton_client.infer( + model_name, + inputs, + outputs=outputs, + sequence_id=sequence_id, + sequence_start=idx == 0, + sequence_end=end, + ) + idx += 1 + + decoding_results = response.as_numpy("TRANSCRIPTS") + if type(decoding_results) == np.ndarray: + decoding_results = b" ".join(decoding_results).decode("utf-8") + else: + # For wenet + decoding_results = response.as_numpy("TRANSCRIPTS")[0].decode( + "utf-8" + ) + chunk_end = time.time() - chunk_start + latency_data.append((chunk_end, chunk_len / sample_rate)) + + total_duration += c.duration + + if compute_cer: + ref = c.supervisions[0].text.split() + hyp = decoding_results.split() + ref = list("".join(ref)) + hyp = list("".join(hyp)) + results.append((c.id, ref, hyp)) + else: + results.append( + ( + c.id, + c.supervisions[0].text.split(), + decoding_results.split(), + ) + ) # noqa + + return total_duration, results, latency_data + + +async def main(): + args = get_args() + filename = args.manifest_filename + server_addr = args.server_addr + server_port = args.server_port + url = f"{server_addr}:{server_port}" + num_tasks = args.num_tasks + log_interval = args.log_interval + compute_cer = args.compute_cer + + cuts = load_manifest(filename) + cuts_list = cuts.split(num_tasks) + tasks = [] + + triton_client = grpcclient.InferenceServerClient(url=url, verbose=False) + protocol_client = grpcclient + + if args.streaming or args.simulate_streaming: + frame_shift_ms = 10 + frame_length_ms = 25 + add_frames = math.ceil( + (frame_length_ms - frame_shift_ms) / frame_shift_ms + ) + # decode_window_length: input sequence length of streaming encoder + if args.context > 0: + # decode window length calculation for wenet + decode_window_length = ( + args.chunk_size - 1 + ) * args.subsampling + args.context + else: + # decode window length calculation for icefall + decode_window_length = ( + args.chunk_size + 2 + args.encoder_right_context + ) * args.subsampling + 3 + + first_chunk_ms = (decode_window_length + add_frames) * frame_shift_ms + + start_time = time.time() + for i in range(num_tasks): + if args.streaming: + assert not args.simulate_streaming + task = asyncio.create_task( + send_streaming( + cuts=cuts_list[i], + name=f"task-{i}", + triton_client=triton_client, + protocol_client=protocol_client, + log_interval=log_interval, + compute_cer=compute_cer, + model_name=args.model_name, + first_chunk_in_secs=first_chunk_ms / 1000, + other_chunk_in_secs=args.chunk_size + * args.subsampling + * frame_shift_ms + / 1000, + task_index=i, + ) + ) + elif args.simulate_streaming: + task = asyncio.create_task( + send_streaming( + cuts=cuts_list[i], + name=f"task-{i}", + triton_client=triton_client, + protocol_client=protocol_client, + log_interval=log_interval, + compute_cer=compute_cer, + model_name=args.model_name, + first_chunk_in_secs=first_chunk_ms / 1000, + other_chunk_in_secs=args.chunk_size + * args.subsampling + * frame_shift_ms + / 1000, + task_index=i, + simulate_mode=True, + ) + ) + else: + task = asyncio.create_task( + send( + cuts=cuts_list[i], + name=f"task-{i}", + triton_client=triton_client, + protocol_client=protocol_client, + log_interval=log_interval, + compute_cer=compute_cer, + model_name=args.model_name, + ) + ) + tasks.append(task) + + ans_list = await asyncio.gather(*tasks) + + end_time = time.time() + elapsed = end_time - start_time + + results = [] + total_duration = 0.0 + latency_data = [] + for ans in ans_list: + total_duration += ans[0] + results += ans[1] + if args.streaming or args.simulate_streaming: + latency_data += ans[2] + + rtf = elapsed / total_duration + + s = f"RTF: {rtf:.4f}\n" + s += f"total_duration: {total_duration:.3f} seconds\n" + s += f"({total_duration/3600:.2f} hours)\n" + s += ( + f"processing time: {elapsed:.3f} seconds " + f"({elapsed/3600:.2f} hours)\n" + ) + + if args.streaming or args.simulate_streaming: + latency_list = [ + chunk_end for (chunk_end, chunk_duration) in latency_data + ] + latency_ms = sum(latency_list) / float(len(latency_list)) * 1000.0 + latency_variance = np.var(latency_list, dtype=np.float64) * 1000.0 + s += f"latency_variance: {latency_variance:.2f}\n" + s += f"latency_50_percentile: {np.percentile(latency_list, 50) * 1000.0:.2f}\n" + s += f"latency_90_percentile: {np.percentile(latency_list, 90) * 1000.0:.2f}\n" + s += f"latency_99_percentile: {np.percentile(latency_list, 99) * 1000.0:.2f}\n" + s += f"average_latency_ms: {latency_ms:.2f}\n" + + print(s) + + with open("rtf.txt", "w") as f: + f.write(s) + + name = Path(filename).stem.split(".")[0] + results = sorted(results) + store_transcripts(filename=f"recogs-{name}.txt", texts=results) + + with open(f"errs-{name}.txt", "w") as f: + write_error_stats(f, "test-set", results, enable_log=True) + + with open(f"errs-{name}.txt", "r") as f: + print(f.readline()) # WER + print(f.readline()) # Detailed errors + + if args.stats_file: + stats = await triton_client.get_inference_statistics( + model_name="", as_json=True + ) + with open(args.stats_file, "w") as f: + json.dump(stats, f) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/feature_extractor/1/model.py b/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/feature_extractor/1/model.py index 6464964fd..517a7890a 100644 --- a/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/feature_extractor/1/model.py +++ b/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/feature_extractor/1/model.py @@ -105,8 +105,8 @@ class WavFrontend(): frame_shift: int = 10, filter_length_min: int = -1, filter_length_max: float = -1, - lfr_m: int = 1, - lfr_n: int = 1, + lfr_m: int = 7, + lfr_n: int = 6, dither: float = 1.0 ) -> None: # check_argument_types() diff --git a/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/feature_extractor/config.yaml b/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/feature_extractor/config.yaml index a4a66c37a..fac332cb9 100644 --- a/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/feature_extractor/config.yaml +++ b/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/feature_extractor/config.yaml @@ -1,14 +1,5 @@ -TokenIDConverter: - token_path: resources/models/token_list.pkl - unk_symbol: - -CharTokenizer: - symbol_value: - space_symbol: - remove_non_linguistic_symbols: false - WavFrontend: - cmvn_file: /raid/dgxsa/yuekaiz/pull_requests/FunASR/funasr/runtime/python/onnxruntime/resources/models/am.mvn + cmvn_file: ./model_repo_paraformer_large_offline/feature_extractor/am.mvn frontend_conf: fs: 16000 window: hamming @@ -17,14 +8,4 @@ WavFrontend: frame_shift: 10 lfr_m: 7 lfr_n: 6 - filter_length_max: -.inf - -Model: - model_path: resources/models/model.onnx - use_cuda: false - CUDAExecutionProvider: - device_id: 0 - arena_extend_strategy: kNextPowerOfTwo - cudnn_conv_algo_search: EXHAUSTIVE - do_copy_in_default_stream: true - batch_size: 3 \ No newline at end of file + filter_length_max: -.inf \ No newline at end of file diff --git a/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/1/model.py b/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/1/model.py index dfbaa52f4..5fe25e576 100644 --- a/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/1/model.py +++ b/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/1/model.py @@ -75,8 +75,8 @@ class TritonPythonModel: """ load lang_char.txt """ - with open(str(vocab_file), 'rb') as f: - token_list = pickle.load(f) + with open(str(vocab_file), 'r') as f: + token_list = [line.strip() for line in f] return token_list def execute(self, requests): diff --git a/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/config.pbtxt b/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/config.pbtxt index 6b43fe48b..e2aea566e 100644 --- a/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/config.pbtxt +++ b/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/config.pbtxt @@ -23,7 +23,7 @@ parameters [ }, { key: "vocabulary", - value: { string_value: "./model_repo_paraformer_large_offline/scoring/token_list.pkl"} + value: { string_value: "./model_repo_paraformer_large_offline/scoring/tokens.txt"} }, { key: "lm_path" diff --git a/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/token_list.pkl b/funasr/runtime/triton_gpu/model_repo_paraformer_large_offline/scoring/token_list.pkl deleted file mode 100644 index f1a2ce77858f12695ff1dab468c3d1d5109817cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51686 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