Fangjun Kuang
Committed by GitHub

Provide models for mobile-only platforms by fixing batch size to 1 (#1276)

  1 +name: mobile-asr-models
  2 +
  3 +on:
  4 + push:
  5 + branches:
  6 + - asr-mobile
  7 +
  8 + workflow_dispatch:
  9 +
  10 +
  11 +concurrency:
  12 + group: mobile-asr-models-${{ github.ref }}
  13 + cancel-in-progress: true
  14 +
  15 +jobs:
  16 + mobile-asr-models:
  17 + if: github.repository_owner == 'k2-fsa' || github.repository_owner == 'csukuangfj' || github.repository_owner == 'csu-fangjun'
  18 + runs-on: ${{ matrix.os }}
  19 + strategy:
  20 + fail-fast: false
  21 + matrix:
  22 + os: [ubuntu-latest]
  23 + python-version: ["3.8"]
  24 +
  25 + steps:
  26 + - uses: actions/checkout@v4
  27 +
  28 + - name: Setup Python ${{ matrix.python-version }}
  29 + uses: actions/setup-python@v5
  30 + with:
  31 + python-version: ${{ matrix.python-version }}
  32 +
  33 + - name: Install dependencies
  34 + shell: bash
  35 + run: |
  36 + python3 -m pip install onnxruntime==1.16.3 onnx==1.15.0
  37 +
  38 + - name: Run
  39 + shell: bash
  40 + run: |
  41 + cd scripts/mobile-asr-models
  42 + ./run.sh
  43 +
  44 + - name: Release
  45 + uses: svenstaro/upload-release-action@v2
  46 + with:
  47 + file_glob: true
  48 + file: ./*.tar.bz2
  49 + overwrite: true
  50 + repo_name: k2-fsa/sherpa-onnx
  51 + repo_token: ${{ secrets.UPLOAD_GH_SHERPA_ONNX_TOKEN }}
  52 + tag: asr-models
  1 +# Introduction
  2 +
  3 +This folder contains scripts to convert ASR models for mobile platforms
  4 +supporting only batch size equal to 1.
  5 +
  6 +The advantage of fixing the batch size to 1 is that it provides more
  7 +opportunities for model optimization and quantization.
  8 +
  9 +To give you a concrete example, for the following model
  10 +https://k2-fsa.github.io/sherpa/onnx/pretrained_models/online-transducer/zipformer-transducer-models.html#csukuangfj-sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20-bilingual-chinese-english
  11 +
  12 +| | encoder-epoch-99-avg-1.onnx | encoder-epoch-99-avg-1.int8.onnx|
  13 +|---|---|---|
  14 +|Dynamic batch size| 315 MB| 174 MB|
  15 +|Batch size fixed to 1| 242 MB | 100 MB |
  16 +
  17 +The following [colab notebook](https://colab.research.google.com/drive/1RsVZbsxbPjazeGrNNbZNjXCYbEG2F2DU?usp=sharing)
  18 +provides examples to use the above two models.
  1 +#!/usr/bin/env python3
  2 +import argparse
  3 +
  4 +from onnxruntime.quantization import QuantType, quantize_dynamic
  5 +
  6 +
  7 +def get_args():
  8 + parser = argparse.ArgumentParser()
  9 + parser.add_argument(
  10 + "--input",
  11 + type=str,
  12 + required=True,
  13 + help="Input onnx model",
  14 + )
  15 +
  16 + parser.add_argument(
  17 + "--output",
  18 + type=str,
  19 + required=True,
  20 + help="Output onnx model",
  21 + )
  22 + return parser.parse_args()
  23 +
  24 +
  25 +def main():
  26 + args = get_args()
  27 + print(vars(args))
  28 +
  29 + quantize_dynamic(
  30 + model_input=args.input,
  31 + model_output=args.output,
  32 + op_types_to_quantize=["MatMul"],
  33 + weight_type=QuantType.QInt8,
  34 + )
  35 +
  36 +
  37 +if __name__ == "__main__":
  38 + main()
  1 +#!/usr/bin/env bash
  2 +
  3 +# Copyright 2012 Johns Hopkins University (Author: Daniel Povey);
  4 +# Arnab Ghoshal, Karel Vesely
  5 +
  6 +# Licensed under the Apache License, Version 2.0 (the "License");
  7 +# you may not use this file except in compliance with the License.
  8 +# You may obtain a copy of the License at
  9 +#
  10 +# http://www.apache.org/licenses/LICENSE-2.0
  11 +#
  12 +# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  13 +# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  14 +# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  15 +# MERCHANTABLITY OR NON-INFRINGEMENT.
  16 +# See the Apache 2 License for the specific language governing permissions and
  17 +# limitations under the License.
  18 +
  19 +
  20 +# Parse command-line options.
  21 +# To be sourced by another script (as in ". parse_options.sh").
  22 +# Option format is: --option-name arg
  23 +# and shell variable "option_name" gets set to value "arg."
  24 +# The exception is --help, which takes no arguments, but prints the
  25 +# $help_message variable (if defined).
  26 +
  27 +
  28 +###
  29 +### The --config file options have lower priority to command line
  30 +### options, so we need to import them first...
  31 +###
  32 +
  33 +# Now import all the configs specified by command-line, in left-to-right order
  34 +for ((argpos=1; argpos<$#; argpos++)); do
  35 + if [ "${!argpos}" == "--config" ]; then
  36 + argpos_plus1=$((argpos+1))
  37 + config=${!argpos_plus1}
  38 + [ ! -r $config ] && echo "$0: missing config '$config'" && exit 1
  39 + . $config # source the config file.
  40 + fi
  41 +done
  42 +
  43 +
  44 +###
  45 +### Now we process the command line options
  46 +###
  47 +while true; do
  48 + [ -z "${1:-}" ] && break; # break if there are no arguments
  49 + case "$1" in
  50 + # If the enclosing script is called with --help option, print the help
  51 + # message and exit. Scripts should put help messages in $help_message
  52 + --help|-h) if [ -z "$help_message" ]; then echo "No help found." 1>&2;
  53 + else printf "$help_message\n" 1>&2 ; fi;
  54 + exit 0 ;;
  55 + --*=*) echo "$0: options to scripts must be of the form --name value, got '$1'"
  56 + exit 1 ;;
  57 + # If the first command-line argument begins with "--" (e.g. --foo-bar),
  58 + # then work out the variable name as $name, which will equal "foo_bar".
  59 + --*) name=`echo "$1" | sed s/^--// | sed s/-/_/g`;
  60 + # Next we test whether the variable in question is undefned-- if so it's
  61 + # an invalid option and we die. Note: $0 evaluates to the name of the
  62 + # enclosing script.
  63 + # The test [ -z ${foo_bar+xxx} ] will return true if the variable foo_bar
  64 + # is undefined. We then have to wrap this test inside "eval" because
  65 + # foo_bar is itself inside a variable ($name).
  66 + eval '[ -z "${'$name'+xxx}" ]' && echo "$0: invalid option $1" 1>&2 && exit 1;
  67 +
  68 + oldval="`eval echo \\$$name`";
  69 + # Work out whether we seem to be expecting a Boolean argument.
  70 + if [ "$oldval" == "true" ] || [ "$oldval" == "false" ]; then
  71 + was_bool=true;
  72 + else
  73 + was_bool=false;
  74 + fi
  75 +
  76 + # Set the variable to the right value-- the escaped quotes make it work if
  77 + # the option had spaces, like --cmd "queue.pl -sync y"
  78 + eval $name=\"$2\";
  79 +
  80 + # Check that Boolean-valued arguments are really Boolean.
  81 + if $was_bool && [[ "$2" != "true" && "$2" != "false" ]]; then
  82 + echo "$0: expected \"true\" or \"false\": $1 $2" 1>&2
  83 + exit 1;
  84 + fi
  85 + shift 2;
  86 + ;;
  87 + *) break;
  88 + esac
  89 +done
  90 +
  91 +
  92 +# Check for an empty argument to the --cmd option, which can easily occur as a
  93 +# result of scripting errors.
  94 +[ ! -z "${cmd+xxx}" ] && [ -z "$cmd" ] && echo "$0: empty argument to --cmd option" 1>&2 && exit 1;
  95 +
  96 +
  97 +true; # so this script returns exit code 0.
  1 +#!/usr/bin/env bash
  2 +#
  3 +# usage of this file:
  4 +# ./run.sh --input in.onnx --output1 out1.onnx --output2 out2.onnx
  5 +# where out1.onnx is a float32 model with batch size fixed to 1
  6 +# and out2.onnx is an int8 quantized version of out1.onnx
  7 +
  8 +set -ex
  9 +
  10 +input=
  11 +output1=
  12 +output2=
  13 +batch_dim=N
  14 +source ./parse_options.sh
  15 +
  16 +if [ -z $input ]; then
  17 + echo 'Please provide input model filename'
  18 + exit 1
  19 +fi
  20 +
  21 +if [ -z $output1 ]; then
  22 + echo 'Please provide output1 model filename'
  23 + exit 1
  24 +fi
  25 +
  26 +if [ -z $output2 ]; then
  27 + echo 'Please provide output2 model filename'
  28 + exit 1
  29 +fi
  30 +
  31 +
  32 +echo "input: $input"
  33 +echo "output1: $output1"
  34 +echo "output2: $output2"
  35 +
  36 +python3 -m onnxruntime.tools.make_dynamic_shape_fixed --dim_param $batch_dim --dim_value 1 $input tmp.fixed.onnx
  37 +python3 -m onnxruntime.quantization.preprocess --input tmp.fixed.onnx --output $output1
  38 +python3 ./dynamic_quantization.py --input $output1 --output $output2
  39 +
  40 +ls -lh $input tmp.fixed.onnx $output1 $output2
  41 +
  42 +rm tmp.fixed.onnx
  1 +#!/usr/bin/env bash
  2 +
  3 +set -ex
  4 +
  5 +curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20.tar.bz2
  6 +tar xvf sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20.tar.bz2
  7 +rm sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20.tar.bz2
  8 +
  9 +src=sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20
  10 +dst=$src-mobile
  11 +
  12 +mkdir -p $dst
  13 +
  14 +./run-impl.sh \
  15 + --input $src/encoder-epoch-99-avg-1.onnx \
  16 + --output1 $dst/encoder-epoch-99-avg-1.onnx \
  17 + --output2 $dst/encoder-epoch-99-avg-1.int8.onnx
  18 +
  19 +cp -v $src/README.md $dst/
  20 +cp -v $src/tokens.txt $dst/
  21 +cp -av $src/test_wavs $dst/
  22 +cp -v $src/decoder-epoch-99-avg-1.onnx $dst/
  23 +cp -v $src/joiner-epoch-99-avg-1.int8.onnx $dst/
  24 +
  25 +cat > $dst/notes.md <<EOF
  26 +# Introduction
  27 +This model is converted from
  28 +https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/$src.tar.bz2
  29 +and it supports only batch size equal to 1.
  30 +EOF
  31 +
  32 +echo "---$src---"
  33 +ls -lh $src
  34 +echo "---$dst---"
  35 +ls -lh $dst
  36 +rm -rf $src
  37 +
  38 +tar cjfv $dst.tar.bz2 $dst
  39 +mv *.tar.bz2 ../../
  40 +rm -rf $dst