diff --git a/egs/aishell/bat/README.md b/egs/aishell/bat/README.md deleted file mode 100644 index ed2a6dafb..000000000 --- a/egs/aishell/bat/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Boundary Aware Transducer (BAT) Result - -## Training Config -- 8 gpu(Tesla V100) -- Feature info: using 80 dims fbank, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train config: conf/train_conformer_bat.yaml -- LM config: LM was not used -- Model size: 90M - -## Results (CER) -- Decode config: conf/decode_bat_conformer.yaml - -| testset | CER(%) | -|:-----------:|:-------:| -| dev | 4.56 | -| test | 4.97 | diff --git a/egs/aishell/bat/conf/decode_bat_conformer.yaml b/egs/aishell/bat/conf/decode_bat_conformer.yaml deleted file mode 100644 index 9a71e66b8..000000000 --- a/egs/aishell/bat/conf/decode_bat_conformer.yaml +++ /dev/null @@ -1 +0,0 @@ -beam_size: 10 diff --git a/egs/aishell/bat/conf/train_conformer_bat.yaml b/egs/aishell/bat/conf/train_conformer_bat.yaml deleted file mode 100644 index 46ca9bfa6..000000000 --- a/egs/aishell/bat/conf/train_conformer_bat.yaml +++ /dev/null @@ -1,108 +0,0 @@ -encoder: chunk_conformer -encoder_conf: - activation_type: swish - positional_dropout_rate: 0.5 - time_reduction_factor: 2 - embed_vgg_like: false - subsampling_factor: 4 - linear_units: 2048 - output_size: 512 - attention_heads: 8 - dropout_rate: 0.5 - positional_dropout_rate: 0.5 - attention_dropout_rate: 0.5 - cnn_module_kernel: 15 - num_blocks: 12 - -# decoder related -rnnt_decoder: rnnt -rnnt_decoder_conf: - embed_size: 512 - hidden_size: 512 - embed_dropout_rate: 0.5 - dropout_rate: 0.5 - use_embed_mask: true - -predictor: bat_predictor -predictor_conf: - idim: 512 - threshold: 1.0 - l_order: 1 - r_order: 1 - return_accum: true - -joint_network_conf: - joint_space_size: 512 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - - -# Auxiliary CTC -model: bat -model_conf: - auxiliary_ctc_weight: 0.0 - cif_weight: 1.0 - r_d: 3 - r_u: 5 - -# minibatch related -use_amp: true - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 100 -val_scheduler_criterion: - - valid - - loss -best_model_criterion: -- - valid - - cer_transducer - - min -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 25000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 40 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 50 - num_time_mask: 5 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 diff --git a/egs/aishell/bat/local/aishell_data_prep.sh b/egs/aishell/bat/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/bat/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/bat/path.sh b/egs/aishell/bat/path.sh deleted file mode 100644 index 7972642d0..000000000 --- a/egs/aishell/bat/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell/bat/run.sh b/egs/aishell/bat/run.sh deleted file mode 100755 index 54f1d877b..000000000 --- a/egs/aishell/bat/run.sh +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_conformer_bat.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_bat_conformer.yaml -inference_asr_model=valid.cer_transducer.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} ${feats_dir}/data/${train_set} -fi - -token_list=${feats_dir}/data/${lang}_token_list/char/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/char/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=./ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type char \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/cmvn.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/cmvn.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode bat \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi diff --git a/egs/aishell/bat/utils b/egs/aishell/bat/utils deleted file mode 120000 index 4072eacc1..000000000 --- a/egs/aishell/bat/utils +++ /dev/null @@ -1 +0,0 @@ -../transformer/utils \ No newline at end of file diff --git a/egs/aishell/branchformer/README.md b/egs/aishell/branchformer/README.md deleted file mode 100644 index 90bba97e9..000000000 --- a/egs/aishell/branchformer/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Branchformer Result - -## Training Config -- Feature info: using raw speech, extracting 80 dims fbank online, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train info: lr 0.001, batch_size 10000, 4 gpu(Tesla V100), acc_grad 1, 180 epochs -- Train config: conf/train_asr_branchformer.yaml -- LM config: LM was not used - -## Results (CER) -- Decode config: conf/decode_asr_transformer.yaml (ctc weight:0.4) - -| testset | CER(%) | -|:-----------:|:-------:| -| dev | 4.15 | -| test | 4.51 | \ No newline at end of file diff --git a/egs/aishell/branchformer/conf/decode_asr_transformer.yaml b/egs/aishell/branchformer/conf/decode_asr_transformer.yaml deleted file mode 100644 index e87a2937f..000000000 --- a/egs/aishell/branchformer/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.4 -lm_weight: 0.0 diff --git a/egs/aishell/branchformer/conf/train_asr_branchformer.yaml b/egs/aishell/branchformer/conf/train_asr_branchformer.yaml deleted file mode 100644 index f35c89706..000000000 --- a/egs/aishell/branchformer/conf/train_asr_branchformer.yaml +++ /dev/null @@ -1,104 +0,0 @@ -# network architecture -# encoder related -encoder: branchformer -encoder_conf: - output_size: 256 - use_attn: true - attention_heads: 4 - attention_layer_type: rel_selfattn - pos_enc_layer_type: rel_pos - rel_pos_type: latest - use_cgmlp: true - cgmlp_linear_units: 2048 - cgmlp_conv_kernel: 31 - use_linear_after_conv: false - gate_activation: identity - merge_method: concat - cgmlp_weight: 0.5 # used only if merge_method is "fixed_ave" - attn_branch_drop_rate: 0.0 # used only if merge_method is "learned_ave" - num_blocks: 24 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.1 - input_layer: conv2d - stochastic_depth_rate: 0.0 - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0. - src_attention_dropout_rate: 0. - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 180 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.001 - weight_decay: 0.000001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 35000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 27 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_ratio_range: - - 0. - - 0.05 - num_time_mask: 10 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 10000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/aishell/branchformer/local/aishell_data_prep.sh b/egs/aishell/branchformer/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/branchformer/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/branchformer/local/download_and_untar.sh b/egs/aishell/branchformer/local/download_and_untar.sh deleted file mode 100755 index d98255915..000000000 --- a/egs/aishell/branchformer/local/download_and_untar.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# 2017 Xingyu Na -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: data_aishell, resource_aishell." -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1; -fi - -part_ok=false -list="data_aishell resource_aishell" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1; -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1; -fi - -if [ -f $data/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0; -fi - -# sizes of the archive files in bytes. -sizes="15582913665 1246920" - -if [ -f $data/$part.tgz ]; then - size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}') - size_ok=false - for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tgz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tgz - else - echo "$data/$part.tgz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tgz ]; then - if ! command -v wget >/dev/null; then - echo "$0: wget is not installed." - exit 1; - fi - full_url=$url/$part.tgz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - cd $data || exit 1 - if ! wget --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1; - fi -fi - -cd $data || exit 1 - -if ! tar -xvzf $part.tgz; then - echo "$0: error un-tarring archive $data/$part.tgz" - exit 1; -fi - -touch $data/$part/.complete - -if [ $part == "data_aishell" ]; then - cd $data/$part/wav || exit 1 - for wav in ./*.tar.gz; do - echo "Extracting wav from $wav" - tar -zxf $wav && rm $wav - done -fi - -echo "$0: Successfully downloaded and un-tarred $data/$part.tgz" - -if $remove_archive; then - echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied." - rm $data/$part.tgz -fi - -exit 0; diff --git a/egs/aishell/branchformer/path.sh b/egs/aishell/branchformer/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/aishell/branchformer/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell/branchformer/run.sh b/egs/aishell/branchformer/run.sh deleted file mode 100755 index 6bb4a0cc5..000000000 --- a/egs/aishell/branchformer/run.sh +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3" -gpu_num=4 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_asr_branchformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode asr \ - --model_name conformer \ - --dataset aishell \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell/branchformer/utils b/egs/aishell/branchformer/utils deleted file mode 120000 index 4072eacc1..000000000 --- a/egs/aishell/branchformer/utils +++ /dev/null @@ -1 +0,0 @@ -../transformer/utils \ No newline at end of file diff --git a/egs/aishell/conformer/README.md b/egs/aishell/conformer/README.md deleted file mode 100644 index a67b183ed..000000000 --- a/egs/aishell/conformer/README.md +++ /dev/null @@ -1,17 +0,0 @@ - -# Conformer Result - -## Training Config -- Feature info: using 80 dims fbank, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train info: lr 5e-4, batch_size 25000, 2 gpu(Tesla V100), acc_grad 1, 50 epochs -- Train config: conf/train_asr_transformer.yaml -- LM config: LM was not used -- Model size: 46M - -## Results (CER) -- Decode config: conf/decode_asr_transformer.yaml (ctc weight:0.5) - -| testset | CER(%) | -|:-----------:|:-------:| -| dev | 4.42 | -| test | 4.87 | \ No newline at end of file diff --git a/egs/aishell/conformer/conf/decode_asr_transformer.yaml b/egs/aishell/conformer/conf/decode_asr_transformer.yaml deleted file mode 100644 index a147fa79d..000000000 --- a/egs/aishell/conformer/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/aishell/conformer/conf/train_asr_conformer.yaml b/egs/aishell/conformer/conf/train_asr_conformer.yaml deleted file mode 100644 index 4814ee739..000000000 --- a/egs/aishell/conformer/conf/train_asr_conformer.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# network architecture -# encoder related -encoder: conformer -encoder_conf: - output_size: 256 # dimension of attention - attention_heads: 4 - linear_units: 2048 # the number of units of position-wise feed forward - num_blocks: 12 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - macaron_style: true - use_cnn_module: true - cnn_module_kernel: 15 - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 150 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/aishell/conformer/local/aishell_data_prep.sh b/egs/aishell/conformer/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/conformer/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/conformer/local/download_and_untar.sh b/egs/aishell/conformer/local/download_and_untar.sh deleted file mode 100755 index d98255915..000000000 --- a/egs/aishell/conformer/local/download_and_untar.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# 2017 Xingyu Na -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: data_aishell, resource_aishell." -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1; -fi - -part_ok=false -list="data_aishell resource_aishell" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1; -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1; -fi - -if [ -f $data/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0; -fi - -# sizes of the archive files in bytes. -sizes="15582913665 1246920" - -if [ -f $data/$part.tgz ]; then - size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}') - size_ok=false - for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tgz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tgz - else - echo "$data/$part.tgz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tgz ]; then - if ! command -v wget >/dev/null; then - echo "$0: wget is not installed." - exit 1; - fi - full_url=$url/$part.tgz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - cd $data || exit 1 - if ! wget --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1; - fi -fi - -cd $data || exit 1 - -if ! tar -xvzf $part.tgz; then - echo "$0: error un-tarring archive $data/$part.tgz" - exit 1; -fi - -touch $data/$part/.complete - -if [ $part == "data_aishell" ]; then - cd $data/$part/wav || exit 1 - for wav in ./*.tar.gz; do - echo "Extracting wav from $wav" - tar -zxf $wav && rm $wav - done -fi - -echo "$0: Successfully downloaded and un-tarred $data/$part.tgz" - -if $remove_archive; then - echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied." - rm $data/$part.tgz -fi - -exit 0; diff --git a/egs/aishell/conformer/path.sh b/egs/aishell/conformer/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/aishell/conformer/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell/conformer/run.sh b/egs/aishell/conformer/run.sh deleted file mode 100755 index e8643e930..000000000 --- a/egs/aishell/conformer/run.sh +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_asr_conformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode asr \ - --model_name conformer \ - --dataset aishell \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell/conformer/utils b/egs/aishell/conformer/utils deleted file mode 120000 index 0853fce5d..000000000 --- a/egs/aishell/conformer/utils +++ /dev/null @@ -1 +0,0 @@ -../transformer/utils/ \ No newline at end of file diff --git a/egs/aishell/data2vec_paraformer_finetune/conf/decode_asr_transformer_noctc_1best.yaml b/egs/aishell/data2vec_paraformer_finetune/conf/decode_asr_transformer_noctc_1best.yaml deleted file mode 100644 index 5436b12e4..000000000 --- a/egs/aishell/data2vec_paraformer_finetune/conf/decode_asr_transformer_noctc_1best.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 1 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.0 -lm_weight: 0.15 diff --git a/egs/aishell/data2vec_paraformer_finetune/conf/train_asr_paraformer_transformer_12e_6d_3072_768.yaml b/egs/aishell/data2vec_paraformer_finetune/conf/train_asr_paraformer_transformer_12e_6d_3072_768.yaml deleted file mode 100644 index 1e1acee21..000000000 --- a/egs/aishell/data2vec_paraformer_finetune/conf/train_asr_paraformer_transformer_12e_6d_3072_768.yaml +++ /dev/null @@ -1,121 +0,0 @@ -# network architecture -# encoder related -encoder: data2vec_encoder -encoder_conf: - extractor_mode: layer_norm - encoder_layerdrop: 0.1 - dropout_input: 0.0 - dropout_features: 0.0 - feature_grad_mult: 0.0 - encoder_embed_dim: 768 - - mask_prob: 0.65 - mask_length: 10 - - loss_beta: 0 - loss_scale: null - - instance_norm_target_layer: true - average_top_k_layers: 8 - - pos_conv_depth: 5 - conv_pos: 95 - - ema_decay: 0.999 - ema_end_decay: 0.9999 - ema_anneal_end_step: 30000 - ema_transformer_only: true - ema_layers_only: true - - require_same_masks: true - mask_dropout: 0 - -# decoder related -decoder: paraformer_decoder_san -decoder_conf: - attention_heads: 12 - linear_units: 3072 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model: paraformer -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 - length_normalized_loss: false - predictor_weight: 1.0 - sampling_ratio: 0.4 - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 150 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.00002 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -predictor: cif_predictor -predictor_conf: - idim: 768 - threshold: 1.0 - l_order: 1 - r_order: 1 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -unused_parameters: true -normalize: None \ No newline at end of file diff --git a/egs/aishell/data2vec_paraformer_finetune/local/aishell_data_prep.sh b/egs/aishell/data2vec_paraformer_finetune/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/data2vec_paraformer_finetune/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/data2vec_paraformer_finetune/local/download_and_untar.sh b/egs/aishell/data2vec_paraformer_finetune/local/download_and_untar.sh deleted file mode 100755 index d98255915..000000000 --- a/egs/aishell/data2vec_paraformer_finetune/local/download_and_untar.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# 2017 Xingyu Na -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: data_aishell, resource_aishell." -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1; -fi - -part_ok=false -list="data_aishell resource_aishell" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1; -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1; -fi - -if [ -f $data/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0; -fi - -# sizes of the archive files in bytes. -sizes="15582913665 1246920" - -if [ -f $data/$part.tgz ]; then - size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}') - size_ok=false - for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tgz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tgz - else - echo "$data/$part.tgz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tgz ]; then - if ! command -v wget >/dev/null; then - echo "$0: wget is not installed." - exit 1; - fi - full_url=$url/$part.tgz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - cd $data || exit 1 - if ! wget --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1; - fi -fi - -cd $data || exit 1 - -if ! tar -xvzf $part.tgz; then - echo "$0: error un-tarring archive $data/$part.tgz" - exit 1; -fi - -touch $data/$part/.complete - -if [ $part == "data_aishell" ]; then - cd $data/$part/wav || exit 1 - for wav in ./*.tar.gz; do - echo "Extracting wav from $wav" - tar -zxf $wav && rm $wav - done -fi - -echo "$0: Successfully downloaded and un-tarred $data/$part.tgz" - -if $remove_archive; then - echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied." - rm $data/$part.tgz -fi - -exit 0; diff --git a/egs/aishell/data2vec_paraformer_finetune/path.sh b/egs/aishell/data2vec_paraformer_finetune/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/aishell/data2vec_paraformer_finetune/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell/data2vec_paraformer_finetune/run.sh b/egs/aishell/data2vec_paraformer_finetune/run.sh deleted file mode 100755 index 1f96873fd..000000000 --- a/egs/aishell/data2vec_paraformer_finetune/run.sh +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=1 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -model_name=damo/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch -init_param="$HOME/.cache/modelscope/hub/$model_name/basemodel.pb" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_asr_paraformer_transformer_12e_6d_3072_768.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer_noctc_1best.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - python utils/download_model.py --model_name ${model_name} # download pretrained model on ModelScope - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --init_param ${init_param} \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode paraformer \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode paraformer \ - --model_name data2vec_finetune_paraformer \ - --dataset aishell \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --nat _nat \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell/data2vec_paraformer_finetune/utils b/egs/aishell/data2vec_paraformer_finetune/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/aishell/data2vec_paraformer_finetune/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/aishell/data2vec_transformer_finetune/conf/decode_asr_transformer.yaml b/egs/aishell/data2vec_transformer_finetune/conf/decode_asr_transformer.yaml deleted file mode 100644 index 61ec03c86..000000000 --- a/egs/aishell/data2vec_transformer_finetune/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 1.0 -lm_weight: 0.7 diff --git a/egs/aishell/data2vec_transformer_finetune/conf/train_asr_transformer_12e_6d_3072_768.yaml b/egs/aishell/data2vec_transformer_finetune/conf/train_asr_transformer_12e_6d_3072_768.yaml deleted file mode 100644 index 32a7b5bb0..000000000 --- a/egs/aishell/data2vec_transformer_finetune/conf/train_asr_transformer_12e_6d_3072_768.yaml +++ /dev/null @@ -1,112 +0,0 @@ -# network architecture -# encoder related -encoder: data2vec_encoder -encoder_conf: - extractor_mode: layer_norm - encoder_layerdrop: 0.1 - dropout_input: 0.0 - dropout_features: 0.0 - feature_grad_mult: 0.0 - encoder_embed_dim: 768 - - mask_prob: 0.65 - mask_length: 10 - - loss_beta: 0 - loss_scale: null - - instance_norm_target_layer: true - average_top_k_layers: 8 - - pos_conv_depth: 5 - conv_pos: 95 - - ema_decay: 0.999 - ema_end_decay: 0.9999 - ema_anneal_end_step: 30000 - ema_transformer_only: true - ema_layers_only: true - - require_same_masks: true - mask_dropout: 0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 1.0 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 1 -grad_clip: 5 -patience: none -max_epoch: 150 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - cer_ctc - - min -keep_nbest_models: 10 - -# NoamLR is deprecated. Use WarmupLR. -# The following is equivalent setting for NoamLR: -# -# optim: adam -# optim_conf: -# lr: 10. -# scheduler: noamlr -# scheduler_conf: -# model_size: 256 -# warmup_steps: 25000 -# -optim: adam -optim_conf: - lr: 0.00005 -scheduler: warmuplr # pytorch v1.1.0+ required -scheduler_conf: - warmup_steps: 25000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -unused_parameters: true -normalize: None \ No newline at end of file diff --git a/egs/aishell/data2vec_transformer_finetune/local/aishell_data_prep.sh b/egs/aishell/data2vec_transformer_finetune/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/data2vec_transformer_finetune/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/data2vec_transformer_finetune/local/download_and_untar.sh b/egs/aishell/data2vec_transformer_finetune/local/download_and_untar.sh deleted file mode 100755 index d98255915..000000000 --- a/egs/aishell/data2vec_transformer_finetune/local/download_and_untar.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# 2017 Xingyu Na -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: data_aishell, resource_aishell." -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1; -fi - -part_ok=false -list="data_aishell resource_aishell" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1; -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1; -fi - -if [ -f $data/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0; -fi - -# sizes of the archive files in bytes. -sizes="15582913665 1246920" - -if [ -f $data/$part.tgz ]; then - size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}') - size_ok=false - for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tgz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tgz - else - echo "$data/$part.tgz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tgz ]; then - if ! command -v wget >/dev/null; then - echo "$0: wget is not installed." - exit 1; - fi - full_url=$url/$part.tgz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - cd $data || exit 1 - if ! wget --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1; - fi -fi - -cd $data || exit 1 - -if ! tar -xvzf $part.tgz; then - echo "$0: error un-tarring archive $data/$part.tgz" - exit 1; -fi - -touch $data/$part/.complete - -if [ $part == "data_aishell" ]; then - cd $data/$part/wav || exit 1 - for wav in ./*.tar.gz; do - echo "Extracting wav from $wav" - tar -zxf $wav && rm $wav - done -fi - -echo "$0: Successfully downloaded and un-tarred $data/$part.tgz" - -if $remove_archive; then - echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied." - rm $data/$part.tgz -fi - -exit 0; diff --git a/egs/aishell/data2vec_transformer_finetune/path.sh b/egs/aishell/data2vec_transformer_finetune/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/aishell/data2vec_transformer_finetune/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell/data2vec_transformer_finetune/run.sh b/egs/aishell/data2vec_transformer_finetune/run.sh deleted file mode 100755 index 7b01a5f19..000000000 --- a/egs/aishell/data2vec_transformer_finetune/run.sh +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -model_name=damo/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch -init_param="$HOME/.cache/modelscope/hub/$model_name/basemodel.pb" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_asr_transformer_12e_6d_3072_768.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer.yaml -inference_asr_model=valid.cer_ctc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - python utils/download_model.py --model_name ${model_name} # download pretrained model on ModelScope - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --init_param ${init_param} \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode asr \ - --model_name data2vec_finetune_transformer \ - --dataset aishell \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell/data2vec_transformer_finetune/utils b/egs/aishell/data2vec_transformer_finetune/utils deleted file mode 120000 index 0853fce5d..000000000 --- a/egs/aishell/data2vec_transformer_finetune/utils +++ /dev/null @@ -1 +0,0 @@ -../transformer/utils/ \ No newline at end of file diff --git a/egs/aishell/e_branchformer/README.md b/egs/aishell/e_branchformer/README.md deleted file mode 100644 index 9b6b23843..000000000 --- a/egs/aishell/e_branchformer/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# E-Branchformer Result - -## Training Config -- Feature info: using raw speech, extracting 80 dims fbank online, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train info: lr 0.001, batch_size 10000, 4 gpu(Tesla V100), acc_grad 1, 180 epochs -- Train config: conf/train_asr_e_branchformer.yaml -- LM config: LM was not used - -## Results (CER) -- Decode config: conf/decode_asr_transformer.yaml (ctc weight:0.4) - -| testset | CER(%) | -|:-----------:|:-------:| -| dev | 4.10 | -| test | 4.52 | \ No newline at end of file diff --git a/egs/aishell/e_branchformer/conf/decode_asr_transformer.yaml b/egs/aishell/e_branchformer/conf/decode_asr_transformer.yaml deleted file mode 100644 index e87a2937f..000000000 --- a/egs/aishell/e_branchformer/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.4 -lm_weight: 0.0 diff --git a/egs/aishell/e_branchformer/conf/train_asr_e_branchformer.yaml b/egs/aishell/e_branchformer/conf/train_asr_e_branchformer.yaml deleted file mode 100644 index a30e9a23b..000000000 --- a/egs/aishell/e_branchformer/conf/train_asr_e_branchformer.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# network architecture -# encoder related -encoder: e_branchformer -encoder_conf: - output_size: 256 - attention_heads: 4 - attention_layer_type: rel_selfattn - pos_enc_layer_type: rel_pos - rel_pos_type: latest - cgmlp_linear_units: 1024 - cgmlp_conv_kernel: 31 - use_linear_after_conv: false - gate_activation: identity - num_blocks: 12 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.1 - input_layer: conv2d - layer_drop_rate: 0.0 - linear_units: 1024 - positionwise_layer_type: linear - use_ffn: true - macaron_ffn: true - merge_conv_kernel: 31 - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0. - src_attention_dropout_rate: 0. - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 180 -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.001 - weight_decay: 0.000001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 35000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 27 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_ratio_range: - - 0. - - 0.05 - num_time_mask: 10 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 10000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/aishell/e_branchformer/local/aishell_data_prep.sh b/egs/aishell/e_branchformer/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/e_branchformer/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/e_branchformer/local/download_and_untar.sh b/egs/aishell/e_branchformer/local/download_and_untar.sh deleted file mode 100755 index d98255915..000000000 --- a/egs/aishell/e_branchformer/local/download_and_untar.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# 2017 Xingyu Na -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: data_aishell, resource_aishell." -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1; -fi - -part_ok=false -list="data_aishell resource_aishell" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1; -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1; -fi - -if [ -f $data/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0; -fi - -# sizes of the archive files in bytes. -sizes="15582913665 1246920" - -if [ -f $data/$part.tgz ]; then - size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}') - size_ok=false - for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tgz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tgz - else - echo "$data/$part.tgz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tgz ]; then - if ! command -v wget >/dev/null; then - echo "$0: wget is not installed." - exit 1; - fi - full_url=$url/$part.tgz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - cd $data || exit 1 - if ! wget --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1; - fi -fi - -cd $data || exit 1 - -if ! tar -xvzf $part.tgz; then - echo "$0: error un-tarring archive $data/$part.tgz" - exit 1; -fi - -touch $data/$part/.complete - -if [ $part == "data_aishell" ]; then - cd $data/$part/wav || exit 1 - for wav in ./*.tar.gz; do - echo "Extracting wav from $wav" - tar -zxf $wav && rm $wav - done -fi - -echo "$0: Successfully downloaded and un-tarred $data/$part.tgz" - -if $remove_archive; then - echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied." - rm $data/$part.tgz -fi - -exit 0; diff --git a/egs/aishell/e_branchformer/path.sh b/egs/aishell/e_branchformer/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/aishell/e_branchformer/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell/e_branchformer/run.sh b/egs/aishell/e_branchformer/run.sh deleted file mode 100755 index bcba2d75f..000000000 --- a/egs/aishell/e_branchformer/run.sh +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3" -gpu_num=4 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_asr_e_branchformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode asr \ - --model_name conformer \ - --dataset aishell \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell/e_branchformer/utils b/egs/aishell/e_branchformer/utils deleted file mode 120000 index 4072eacc1..000000000 --- a/egs/aishell/e_branchformer/utils +++ /dev/null @@ -1 +0,0 @@ -../transformer/utils \ No newline at end of file diff --git a/egs/aishell/paraformer/README.md b/egs/aishell/paraformer/README.md deleted file mode 100644 index c0385db86..000000000 --- a/egs/aishell/paraformer/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Paraformer -pretrained model in [ModelScope](https://www.modelscope.cn/home):[speech_paraformer_asr_nat-aishell1-pytorch](https://www.modelscope.cn/models/damo/speech_paraformer_asr_nat-aishell1-pytorch/summary) - -## Training Config -- Feature info: using 80 dims fbank, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train info: lr 5e-4, batch_size 25000, 2 gpu(Tesla V100), acc_grad 1, 50 epochs -- Train config: conf/train_asr_paraformer_conformer_12e_6d_2048_256.yaml -- LM config: LM was not used - -## Results (CER) - -- Decode config: conf/decode_asr_transformer_noctc_1best.yaml (ctc weight:0.0) - -| testset | CER(%) | -|:-----------:|:-------:| -| dev | 4.66 | -| test | 5.11 | - -- Decode config: conf/decode_asr_transformer.yaml (ctc weight:0.5) - -| testset | CER(%) | -|:-----------:|:-------:| -| dev | 4.52 | -| test | 4.94 | \ No newline at end of file diff --git a/egs/aishell/paraformer/conf/decode_asr_transformer.yaml b/egs/aishell/paraformer/conf/decode_asr_transformer.yaml deleted file mode 100644 index a147fa79d..000000000 --- a/egs/aishell/paraformer/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/aishell/paraformer/conf/decode_asr_transformer_noctc_1best.yaml b/egs/aishell/paraformer/conf/decode_asr_transformer_noctc_1best.yaml deleted file mode 100644 index 5436b12e4..000000000 --- a/egs/aishell/paraformer/conf/decode_asr_transformer_noctc_1best.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 1 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.0 -lm_weight: 0.15 diff --git a/egs/aishell/paraformer/conf/train_asr_paraformer_conformer_12e_6d_2048_256.yaml b/egs/aishell/paraformer/conf/train_asr_paraformer_conformer_12e_6d_2048_256.yaml deleted file mode 100644 index 9dd3fb304..000000000 --- a/egs/aishell/paraformer/conf/train_asr_paraformer_conformer_12e_6d_2048_256.yaml +++ /dev/null @@ -1,109 +0,0 @@ -# network architecture -# encoder related -encoder: conformer -encoder_conf: - output_size: 256 # dimension of attention - attention_heads: 4 - linear_units: 2048 # the number of units of position-wise feed forward - num_blocks: 12 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - macaron_style: true - use_cnn_module: true - cnn_module_kernel: 15 - -# decoder related -decoder: paraformer_decoder_san -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -model: paraformer -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 - length_normalized_loss: false - predictor_weight: 1.0 - sampling_ratio: 0.4 - use_1st_decoder_loss: true - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 150 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -predictor: cif_predictor -predictor_conf: - idim: 256 - threshold: 1.0 - l_order: 1 - r_order: 1 - tail_threshold: 0.45 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/aishell/paraformer/local/aishell_data_prep.sh b/egs/aishell/paraformer/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/paraformer/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/paraformer/local/download_and_untar.sh b/egs/aishell/paraformer/local/download_and_untar.sh deleted file mode 100755 index d98255915..000000000 --- a/egs/aishell/paraformer/local/download_and_untar.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# 2017 Xingyu Na -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: data_aishell, resource_aishell." -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1; -fi - -part_ok=false -list="data_aishell resource_aishell" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1; -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1; -fi - -if [ -f $data/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0; -fi - -# sizes of the archive files in bytes. -sizes="15582913665 1246920" - -if [ -f $data/$part.tgz ]; then - size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}') - size_ok=false - for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tgz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tgz - else - echo "$data/$part.tgz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tgz ]; then - if ! command -v wget >/dev/null; then - echo "$0: wget is not installed." - exit 1; - fi - full_url=$url/$part.tgz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - cd $data || exit 1 - if ! wget --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1; - fi -fi - -cd $data || exit 1 - -if ! tar -xvzf $part.tgz; then - echo "$0: error un-tarring archive $data/$part.tgz" - exit 1; -fi - -touch $data/$part/.complete - -if [ $part == "data_aishell" ]; then - cd $data/$part/wav || exit 1 - for wav in ./*.tar.gz; do - echo "Extracting wav from $wav" - tar -zxf $wav && rm $wav - done -fi - -echo "$0: Successfully downloaded and un-tarred $data/$part.tgz" - -if $remove_archive; then - echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied." - rm $data/$part.tgz -fi - -exit 0; diff --git a/egs/aishell/paraformer/path.sh b/egs/aishell/paraformer/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/aishell/paraformer/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell/paraformer/run.sh b/egs/aishell/paraformer/run.sh deleted file mode 100755 index 7d79211c5..000000000 --- a/egs/aishell/paraformer/run.sh +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=1 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_asr_paraformer_conformer_12e_6d_2048_256.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer_noctc_1best.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --dataset_type small \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode paraformer \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode paraformer \ - --model_name paraformer \ - --dataset aishell \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --nat _nat \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell/paraformer/utils b/egs/aishell/paraformer/utils deleted file mode 120000 index 0853fce5d..000000000 --- a/egs/aishell/paraformer/utils +++ /dev/null @@ -1 +0,0 @@ -../transformer/utils/ \ No newline at end of file diff --git a/egs/aishell/paraformerbert/README.md b/egs/aishell/paraformerbert/README.md deleted file mode 100644 index ffce9493e..000000000 --- a/egs/aishell/paraformerbert/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# ParaformerBert + specaug + speed perturbation + specaugmentation -## Environments -- date: `Mon Nov 21 13:25:30 CST 2022` -- python version: `3.7.12` -- FunASR version: `0.1.0` -- pytorch version: `pytorch 1.7.0` - -## Config files -- train config: conf/train_asr_paraformerbert_conformer_12e_6d_2048_256.yaml -- model size: 46M -- lm config: LM was not used -- decode config: conf/decode_asr_transformer_noctc_1best.yaml (CTC was not used) - -## Results (CER) -| testset | CER(%) | -|:-----------:|:-------:| -| dev | 4.30 | -| test | 4.80 | \ No newline at end of file diff --git a/egs/aishell/paraformerbert/conf/decode_asr_transformer.yaml b/egs/aishell/paraformerbert/conf/decode_asr_transformer.yaml deleted file mode 100644 index a147fa79d..000000000 --- a/egs/aishell/paraformerbert/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/aishell/paraformerbert/conf/decode_asr_transformer_noctc_1best.yaml b/egs/aishell/paraformerbert/conf/decode_asr_transformer_noctc_1best.yaml deleted file mode 100644 index 5436b12e4..000000000 --- a/egs/aishell/paraformerbert/conf/decode_asr_transformer_noctc_1best.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 1 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.0 -lm_weight: 0.15 diff --git a/egs/aishell/paraformerbert/conf/train_asr_paraformerbert_conformer_12e_6d_2048_256.yaml b/egs/aishell/paraformerbert/conf/train_asr_paraformerbert_conformer_12e_6d_2048_256.yaml deleted file mode 100644 index f2652e8e1..000000000 --- a/egs/aishell/paraformerbert/conf/train_asr_paraformerbert_conformer_12e_6d_2048_256.yaml +++ /dev/null @@ -1,112 +0,0 @@ -# network architecture -# encoder related -encoder: conformer -encoder_conf: - output_size: 256 # dimension of attention - attention_heads: 4 - linear_units: 2048 # the number of units of position-wise feed forward - num_blocks: 12 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - macaron_style: true - use_cnn_module: true - cnn_module_kernel: 15 - -# decoder related -decoder: paraformer_decoder_san -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model: paraformer_bert -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - predictor_weight: 1.0 - sampling_ratio: 0.4 - embeds_id: 3 - embed_dims: 768 - embeds_loss_weight: 2.0 - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 150 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -predictor: cif_predictor -predictor_conf: - idim: 256 - threshold: 1.0 - l_order: 1 - r_order: 1 - tail_threshold: 0.45 - -dataset_conf: - data_names: speech,text,embed - data_types: sound,text,kaldi_ark - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/aishell/paraformerbert/local/aishell_data_prep.sh b/egs/aishell/paraformerbert/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/paraformerbert/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/paraformerbert/local/download_and_untar.sh b/egs/aishell/paraformerbert/local/download_and_untar.sh deleted file mode 100755 index d98255915..000000000 --- a/egs/aishell/paraformerbert/local/download_and_untar.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# 2017 Xingyu Na -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: data_aishell, resource_aishell." -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1; -fi - -part_ok=false -list="data_aishell resource_aishell" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1; -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1; -fi - -if [ -f $data/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0; -fi - -# sizes of the archive files in bytes. -sizes="15582913665 1246920" - -if [ -f $data/$part.tgz ]; then - size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}') - size_ok=false - for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tgz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tgz - else - echo "$data/$part.tgz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tgz ]; then - if ! command -v wget >/dev/null; then - echo "$0: wget is not installed." - exit 1; - fi - full_url=$url/$part.tgz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - cd $data || exit 1 - if ! wget --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1; - fi -fi - -cd $data || exit 1 - -if ! tar -xvzf $part.tgz; then - echo "$0: error un-tarring archive $data/$part.tgz" - exit 1; -fi - -touch $data/$part/.complete - -if [ $part == "data_aishell" ]; then - cd $data/$part/wav || exit 1 - for wav in ./*.tar.gz; do - echo "Extracting wav from $wav" - tar -zxf $wav && rm $wav - done -fi - -echo "$0: Successfully downloaded and un-tarred $data/$part.tgz" - -if $remove_archive; then - echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied." - rm $data/$part.tgz -fi - -exit 0; diff --git a/egs/aishell/paraformerbert/local/extract_embeds.sh b/egs/aishell/paraformerbert/local/extract_embeds.sh deleted file mode 100755 index ca0c878ec..000000000 --- a/egs/aishell/paraformerbert/local/extract_embeds.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash - -stage=1 -stop_stage=3 - -bert_model_name="bert-base-chinese" -raw_dataset_path="../DATA" -nj=64 -model_path=${bert_model_name} - -. utils/parse_options.sh || exit 1; - -for data_set in train dev test;do - scp=$raw_dataset_path/data/${data_set}/text - local_scp_dir_raw=${raw_dataset_path}/data/embeds/${data_set} - local_scp_dir=$local_scp_dir_raw/split$nj - local_records_dir=$local_scp_dir_raw/ark - - mkdir -p $local_records_dir - mkdir -p $local_scp_dir - - split_scps="" - for JOB in $(seq ${nj}); do - split_scps="$split_scps $local_scp_dir/data.$JOB.text" - done - - utils/split_scp.pl $scp ${split_scps} - - - for num in {0..7};do - tmp=`expr $num \* 4` - - if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - for idx in {1..4}; do - JOB=`expr $tmp + $idx` - echo "proces jobid=$JOB" - { - beg=0 - gpu=`expr $beg + $idx` - echo ${local_scp_dir}/log.${JOB} - python utils/extract_embeds.py $local_scp_dir/data.$JOB.text ${local_records_dir}/embeds.${JOB}.ark ${local_records_dir}/embeds.${JOB}.scp ${local_records_dir}/embeds.${JOB}.shape ${gpu} ${model_path} &> ${local_scp_dir}/log.${JOB} - } & - done - wait - fi - done - - if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - for JOB in $(seq ${nj}); do - cat ${local_records_dir}/embeds.${JOB}.scp || exit 1; - done > ${local_scp_dir_raw}/embeds.scp - - for JOB in $(seq ${nj}); do - cat ${local_records_dir}/embeds.${JOB}.shape || exit 1; - done > ${local_scp_dir_raw}/embeds.shape - fi - - cp ${local_scp_dir_raw}/embeds.scp ${raw_dataset_path}/data/${data_set}/embeds.scp -done - -echo "embeds is in: ${local_scp_dir_raw}" -echo "success" \ No newline at end of file diff --git a/egs/aishell/paraformerbert/path.sh b/egs/aishell/paraformerbert/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/aishell/paraformerbert/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell/paraformerbert/run.sh b/egs/aishell/paraformerbert/run.sh deleted file mode 100755 index efc831fda..000000000 --- a/egs/aishell/paraformerbert/run.sh +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=1 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary, for large data -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -skip_extract_embed=false -bert_model_name="bert-base-chinese" - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_asr_paraformerbert_conformer_12e_6d_2048_256.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer_noctc_1best.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - if ! "${skip_extract_embed}"; then - echo "extract embeddings..." - local/extract_embeds.sh \ - --bert_model_name ${bert_model_name} \ - --raw_dataset_path ${feats_dir} \ - --nj $nj - fi - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text,embeds.scp" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode paraformer \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode paraformer \ - --model_name paraformer_bert \ - --dataset aishell \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --nat _nat \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell/paraformerbert/utils b/egs/aishell/paraformerbert/utils deleted file mode 120000 index 0853fce5d..000000000 --- a/egs/aishell/paraformerbert/utils +++ /dev/null @@ -1 +0,0 @@ -../transformer/utils/ \ No newline at end of file diff --git a/egs/aishell/rnnt/README.md b/egs/aishell/rnnt/README.md deleted file mode 100644 index 817c9b2c0..000000000 --- a/egs/aishell/rnnt/README.md +++ /dev/null @@ -1,18 +0,0 @@ - -# Streaming RNN-T Result - -## Training Config -- 8 gpu(Tesla V100) -- Feature info: using 80 dims fbank, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train config: conf/train_conformer_rnnt_unified.yaml -- chunk config: chunk size 16, 1 left chunk -- LM config: LM was not used -- Model size: 90M - -## Results (CER) -- Decode config: conf/decode_rnnt_conformer_streaming.yaml - -| testset | CER(%) | -|:-----------:|:-------:| -| dev | 5.43 | -| test | 6.04 | diff --git a/egs/aishell/rnnt/conf/decode_rnnt_conformer_streaming.yaml b/egs/aishell/rnnt/conf/decode_rnnt_conformer_streaming.yaml deleted file mode 100644 index 26e43c64d..000000000 --- a/egs/aishell/rnnt/conf/decode_rnnt_conformer_streaming.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# The conformer transducer decoding configuration from @jeon30c -beam_size: 10 -simu_streaming: false -streaming: true -chunk_size: 16 -left_context: 16 -right_context: 0 - diff --git a/egs/aishell/rnnt/conf/decode_rnnt_conformer_streaming_simu.yaml b/egs/aishell/rnnt/conf/decode_rnnt_conformer_streaming_simu.yaml deleted file mode 100644 index dc3eff2a5..000000000 --- a/egs/aishell/rnnt/conf/decode_rnnt_conformer_streaming_simu.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# The conformer transducer decoding configuration from @jeon30c -beam_size: 10 -simu_streaming: true -streaming: false -chunk_size: 16 diff --git a/egs/aishell/rnnt/conf/train_conformer_rnnt_unified.yaml b/egs/aishell/rnnt/conf/train_conformer_rnnt_unified.yaml deleted file mode 100644 index a1f27a3dd..000000000 --- a/egs/aishell/rnnt/conf/train_conformer_rnnt_unified.yaml +++ /dev/null @@ -1,99 +0,0 @@ -encoder: chunk_conformer -encoder_conf: - activation_type: swish - positional_dropout_rate: 0.5 - time_reduction_factor: 2 - unified_model_training: true - default_chunk_size: 16 - jitter_range: 4 - left_chunk_size: 1 - embed_vgg_like: false - subsampling_factor: 4 - linear_units: 2048 - output_size: 512 - attention_heads: 8 - dropout_rate: 0.5 - positional_dropout_rate: 0.5 - attention_dropout_rate: 0.5 - cnn_module_kernel: 15 - num_blocks: 12 - -# decoder related -rnnt_decoder: rnnt -rnnt_decoder_conf: - embed_size: 512 - hidden_size: 512 - embed_dropout_rate: 0.5 - dropout_rate: 0.5 -joint_network_conf: - joint_space_size: 512 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - - -# Auxiliary CTC -model: rnnt_unified -model_conf: - auxiliary_ctc_weight: 0.0 - -# minibatch related -use_amp: true - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 120 -val_scheduler_criterion: - - valid - - loss -best_model_criterion: -- - valid - - cer_transducer_chunk - - min -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 25000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 40 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 50 - num_time_mask: 5 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 16000 - num_workers: 8 - -log_interval: 50 diff --git a/egs/aishell/rnnt/local/aishell_data_prep.sh b/egs/aishell/rnnt/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/rnnt/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/rnnt/path.sh b/egs/aishell/rnnt/path.sh deleted file mode 100644 index 7972642d0..000000000 --- a/egs/aishell/rnnt/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell/rnnt/run.sh b/egs/aishell/rnnt/run.sh deleted file mode 100755 index 9facc8ba6..000000000 --- a/egs/aishell/rnnt/run.sh +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_conformer_rnnt_unified.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_rnnt_conformer_streaming.yaml -inference_asr_model=valid.cer_transducer_chunk.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} ${feats_dir}/data/${train_set} -fi - -token_list=${feats_dir}/data/${lang}_token_list/char/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/char/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=./ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type char \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/cmvn.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/cmvn.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode rnnt \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi diff --git a/egs/aishell/rnnt/utils b/egs/aishell/rnnt/utils deleted file mode 120000 index 4072eacc1..000000000 --- a/egs/aishell/rnnt/utils +++ /dev/null @@ -1 +0,0 @@ -../transformer/utils \ No newline at end of file diff --git a/egs/aishell/transformer/conf/decode_asr_transformer.yaml b/egs/aishell/transformer/conf/decode_asr_transformer.yaml deleted file mode 100644 index a147fa79d..000000000 --- a/egs/aishell/transformer/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/aishell/transformer/conf/train_asr_transformer.yaml b/egs/aishell/transformer/conf/train_asr_transformer.yaml deleted file mode 100644 index b38656514..000000000 --- a/egs/aishell/transformer/conf/train_asr_transformer.yaml +++ /dev/null @@ -1,88 +0,0 @@ -# network architecture -# encoder related -encoder: transformer -encoder_conf: - output_size: 256 # dimension of attention - attention_heads: 4 - linear_units: 2048 # the number of units of position-wise feed forward - num_blocks: 12 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 1 -grad_clip: 5 -patience: none -max_epoch: 60 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -# NoamLR is deprecated. Use WarmupLR. -# The following is equivalent setting for NoamLR: -# -# optim: adam -# optim_conf: -# lr: 10. -# scheduler: noamlr -# scheduler_conf: -# model_size: 256 -# warmup_steps: 25000 -# -optim: adam -optim_conf: - lr: 0.002 -scheduler: warmuplr # pytorch v1.1.0+ required -scheduler_conf: - warmup_steps: 25000 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -normalize: None diff --git a/egs/aishell/transformer/local/aishell_data_prep.sh b/egs/aishell/transformer/local/aishell_data_prep.sh deleted file mode 100755 index 83f489b3c..000000000 --- a/egs/aishell/transformer/local/aishell_data_prep.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright 2017 Xingyu Na -# Apache 2.0 - -#. ./path.sh || exit 1; - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript data" - exit 1; -fi - -aishell_audio_dir=$1 -aishell_text=$2/aishell_transcript_v0.8.txt -output_dir=$3 - -train_dir=$output_dir/data/local/train -dev_dir=$output_dir/data/local/dev -test_dir=$output_dir/data/local/test -tmp_dir=$output_dir/data/local/tmp - -mkdir -p $train_dir -mkdir -p $dev_dir -mkdir -p $test_dir -mkdir -p $tmp_dir - -# data directory check -if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then - echo "Error: $0 requires two directory arguments" - exit 1; -fi - -# find wav audio file for train, dev and test resp. -find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist -n=`cat $tmp_dir/wav.flist | wc -l` -[ $n -ne 141925 ] && \ - echo Warning: expected 141925 data data files, found $n - -grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1; -grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1; -grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1; - -rm -r $tmp_dir - -# Transcriptions preparation -for dir in $train_dir $dev_dir $test_dir; do - echo Preparing $dir transcriptions - sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list - paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all - utils/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt - awk '{print $1}' $dir/transcripts.txt > $dir/utt.list - utils/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp - sort -u $dir/transcripts.txt > $dir/text -done - -mkdir -p $output_dir/data/train $output_dir/data/dev $output_dir/data/test - -for f in wav.scp text; do - cp $train_dir/$f $output_dir/data/train/$f || exit 1; - cp $dev_dir/$f $output_dir/data/dev/$f || exit 1; - cp $test_dir/$f $output_dir/data/test/$f || exit 1; -done - -echo "$0: AISHELL data preparation succeeded" -exit 0; diff --git a/egs/aishell/transformer/local/download_and_untar.sh b/egs/aishell/transformer/local/download_and_untar.sh deleted file mode 100755 index d98255915..000000000 --- a/egs/aishell/transformer/local/download_and_untar.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# 2017 Xingyu Na -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: data_aishell, resource_aishell." -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1; -fi - -part_ok=false -list="data_aishell resource_aishell" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1; -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1; -fi - -if [ -f $data/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0; -fi - -# sizes of the archive files in bytes. -sizes="15582913665 1246920" - -if [ -f $data/$part.tgz ]; then - size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}') - size_ok=false - for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tgz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tgz - else - echo "$data/$part.tgz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tgz ]; then - if ! command -v wget >/dev/null; then - echo "$0: wget is not installed." - exit 1; - fi - full_url=$url/$part.tgz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - cd $data || exit 1 - if ! wget --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1; - fi -fi - -cd $data || exit 1 - -if ! tar -xvzf $part.tgz; then - echo "$0: error un-tarring archive $data/$part.tgz" - exit 1; -fi - -touch $data/$part/.complete - -if [ $part == "data_aishell" ]; then - cd $data/$part/wav || exit 1 - for wav in ./*.tar.gz; do - echo "Extracting wav from $wav" - tar -zxf $wav && rm $wav - done -fi - -echo "$0: Successfully downloaded and un-tarred $data/$part.tgz" - -if $remove_archive; then - echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied." - rm $data/$part.tgz -fi - -exit 0; diff --git a/egs/aishell/transformer/path.sh b/egs/aishell/transformer/path.sh deleted file mode 100755 index b4064e152..000000000 --- a/egs/aishell/transformer/path.sh +++ /dev/null @@ -1,7 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH - -export OMP_NUM_THREADS=1 diff --git a/egs/aishell/transformer/run.sh b/egs/aishell/transformer/run.sh deleted file mode 100755 index e492fb201..000000000 --- a/egs/aishell/transformer/run.sh +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=../raw_data -data_url=www.openslr.org/resources/33 - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="dev test" - -asr_config=conf/train_asr_transformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - local/download_and_untar.sh ${raw_data} ${data_url} data_aishell - local/download_and_untar.sh ${raw_data} ${data_url} resource_aishell -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/aishell_data_prep.sh ${raw_data}/data_aishell/wav ${raw_data}/data_aishell/transcript ${feats_dir} - for x in train dev test; do - cp ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 -d" " ${feats_dir}/data/${x}/text.org) <(cut -f 2- -d" " ${feats_dir}/data/${x}/text.org | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode asr \ - --model_name transformer \ - --dataset aishell \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell/transformer/utils/apply_cmvn.py b/egs/aishell/transformer/utils/apply_cmvn.py deleted file mode 100755 index b5c5086b3..000000000 --- a/egs/aishell/transformer/utils/apply_cmvn.py +++ /dev/null @@ -1,79 +0,0 @@ -from kaldiio import ReadHelper -from kaldiio import WriteHelper - -import argparse -import json -import math -import numpy as np - - -def get_parser(): - parser = argparse.ArgumentParser( - description="apply cmvn", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "--ark-file", - "-a", - default=False, - required=True, - type=str, - help="fbank ark file", - ) - parser.add_argument( - "--cmvn-file", - "-c", - default=False, - required=True, - type=str, - help="cmvn file", - ) - parser.add_argument( - "--ark-index", - "-i", - default=1, - required=True, - type=int, - help="ark index", - ) - parser.add_argument( - "--output-dir", - "-o", - default=False, - required=True, - type=str, - help="output dir", - ) - return parser - - -def main(): - parser = get_parser() - args = parser.parse_args() - - ark_file = args.output_dir + "/feats." + str(args.ark_index) + ".ark" - scp_file = args.output_dir + "/feats." + str(args.ark_index) + ".scp" - ark_writer = WriteHelper('ark,scp:{},{}'.format(ark_file, scp_file)) - - with open(args.cmvn_file) as f: - cmvn_stats = json.load(f) - - means = cmvn_stats['mean_stats'] - vars = cmvn_stats['var_stats'] - total_frames = cmvn_stats['total_frames'] - - for i in range(len(means)): - means[i] /= total_frames - vars[i] = vars[i] / total_frames - means[i] * means[i] - if vars[i] < 1.0e-20: - vars[i] = 1.0e-20 - vars[i] = 1.0 / math.sqrt(vars[i]) - - with ReadHelper('ark:{}'.format(args.ark_file)) as ark_reader: - for key, mat in ark_reader: - mat = (mat - means) * vars - ark_writer(key, mat) - - -if __name__ == '__main__': - main() diff --git a/egs/aishell/transformer/utils/apply_cmvn.sh b/egs/aishell/transformer/utils/apply_cmvn.sh deleted file mode 100755 index 525c993e2..000000000 --- a/egs/aishell/transformer/utils/apply_cmvn.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; -# Begin configuration section. -nj=32 -cmd=./utils/run.pl - -echo "$0 $@" - -. utils/parse_options.sh || exit 1; - -fbankdir=$1 -cmvn_file=$2 -logdir=$3 -output_dir=$4 - -dump_dir=${output_dir}/ark; mkdir -p ${dump_dir} -mkdir -p ${logdir} - -#$cmd JOB=1:$nj $logdir/apply_cmvn.JOB.log \ -# python utils/apply_cmvn.py -a $fbankdir/ark/feats.JOB.ark \ -# -c $cmvn_file -i JOB -o ${dump_dir} \ -# || exit 1; - -for JOB in `seq 1 $nj`;do - { - python utils/apply_cmvn.py -a $fbankdir/ark/feats.${JOB}.ark \ - -c $cmvn_file -i ${JOB} -o ${dump_dir} || exit 1; - } &> $logdir/apply_cmvn.${JOB}.log & -done - -for n in $(seq $nj); do - cat ${dump_dir}/feats.$n.scp || exit 1 -done > ${output_dir}/feats.scp || exit 1 - -echo "$0: Succeeded apply cmvn" diff --git a/egs/aishell/transformer/utils/apply_lfr_and_cmvn.py b/egs/aishell/transformer/utils/apply_lfr_and_cmvn.py deleted file mode 100755 index 50d18d1a4..000000000 --- a/egs/aishell/transformer/utils/apply_lfr_and_cmvn.py +++ /dev/null @@ -1,143 +0,0 @@ -from kaldiio import ReadHelper, WriteHelper - -import argparse -import numpy as np - - -def build_LFR_features(inputs, m=7, n=6): - LFR_inputs = [] - T = inputs.shape[0] - T_lfr = int(np.ceil(T / n)) - left_padding = np.tile(inputs[0], ((m - 1) // 2, 1)) - inputs = np.vstack((left_padding, inputs)) - T = T + (m - 1) // 2 - for i in range(T_lfr): - if m <= T - i * n: - LFR_inputs.append(np.hstack(inputs[i * n:i * n + m])) - else: - num_padding = m - (T - i * n) - frame = np.hstack(inputs[i * n:]) - for _ in range(num_padding): - frame = np.hstack((frame, inputs[-1])) - LFR_inputs.append(frame) - return np.vstack(LFR_inputs) - - -def build_CMVN_features(inputs, mvn_file): # noqa - with open(mvn_file, 'r', encoding='utf-8') as f: - lines = f.readlines() - - add_shift_list = [] - rescale_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)] - add_shift_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)] - rescale_list = list(rescale_line) - continue - - for j in range(inputs.shape[0]): - for k in range(inputs.shape[1]): - add_shift_value = add_shift_list[k] - rescale_value = rescale_list[k] - inputs[j, k] = float(inputs[j, k]) + float(add_shift_value) - inputs[j, k] = float(inputs[j, k]) * float(rescale_value) - - return inputs - - -def get_parser(): - parser = argparse.ArgumentParser( - description="apply low_frame_rate and cmvn", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "--ark-file", - "-a", - default=False, - required=True, - type=str, - help="fbank ark file", - ) - parser.add_argument( - "--lfr", - "-f", - default=True, - type=str, - help="low frame rate", - ) - parser.add_argument( - "--lfr-m", - "-m", - default=7, - type=int, - help="number of frames to stack", - ) - parser.add_argument( - "--lfr-n", - "-n", - default=6, - type=int, - help="number of frames to skip", - ) - parser.add_argument( - "--cmvn-file", - "-c", - default=False, - required=True, - type=str, - help="global cmvn file", - ) - parser.add_argument( - "--ark-index", - "-i", - default=1, - required=True, - type=int, - help="ark index", - ) - parser.add_argument( - "--output-dir", - "-o", - default=False, - required=True, - type=str, - help="output dir", - ) - return parser - - -def main(): - parser = get_parser() - args = parser.parse_args() - - dump_ark_file = args.output_dir + "/feats." + str(args.ark_index) + ".ark" - dump_scp_file = args.output_dir + "/feats." + str(args.ark_index) + ".scp" - shape_file = args.output_dir + "/len." + str(args.ark_index) - ark_writer = WriteHelper('ark,scp:{},{}'.format(dump_ark_file, dump_scp_file)) - - shape_writer = open(shape_file, 'w') - with ReadHelper('ark:{}'.format(args.ark_file)) as ark_reader: - for key, mat in ark_reader: - if args.lfr: - lfr = build_LFR_features(mat, args.lfr_m, args.lfr_n) - else: - lfr = mat - cmvn = build_CMVN_features(lfr, args.cmvn_file) - dims = cmvn.shape[1] - lens = cmvn.shape[0] - shape_writer.write(key + " " + str(lens) + "," + str(dims) + '\n') - ark_writer(key, cmvn) - - -if __name__ == '__main__': - main() - diff --git a/egs/aishell/transformer/utils/apply_lfr_and_cmvn.sh b/egs/aishell/transformer/utils/apply_lfr_and_cmvn.sh deleted file mode 100755 index 3119fdb8f..000000000 --- a/egs/aishell/transformer/utils/apply_lfr_and_cmvn.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - - -# Begin configuration section. -nj=32 -cmd=utils/run.pl - -# feature configuration -lfr=True -lfr_m=7 -lfr_n=6 - -echo "$0 $@" - -. utils/parse_options.sh || exit 1; - -fbankdir=$1 -cmvn_file=$2 -logdir=$3 -output_dir=$4 - -dump_dir=${output_dir}/ark; mkdir -p ${dump_dir} -mkdir -p ${logdir} - -$cmd JOB=1:$nj $logdir/apply_lfr_and_cmvn.JOB.log \ - python utils/apply_lfr_and_cmvn.py -a $fbankdir/ark/feats.JOB.ark \ - -f $lfr -m $lfr_m -n $lfr_n -c $cmvn_file -i JOB -o ${dump_dir} \ - || exit 1; - -for n in $(seq $nj); do - cat ${dump_dir}/feats.$n.scp || exit 1 -done > ${output_dir}/feats.scp || exit 1 - -for n in $(seq $nj); do - cat ${dump_dir}/len.$n || exit 1 -done > ${output_dir}/speech_shape || exit 1 - -echo "$0: Succeeded apply low frame rate and cmvn" diff --git a/egs/aishell/transformer/utils/cmvn_converter.py b/egs/aishell/transformer/utils/cmvn_converter.py deleted file mode 100644 index d405d1290..000000000 --- a/egs/aishell/transformer/utils/cmvn_converter.py +++ /dev/null @@ -1,51 +0,0 @@ -import argparse -import json -import numpy as np - - -def get_parser(): - parser = argparse.ArgumentParser( - description="cmvn converter", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "--cmvn_json", - default=False, - required=True, - type=str, - help="cmvn json file", - ) - parser.add_argument( - "--am_mvn", - default=False, - required=True, - type=str, - help="am mvn file", - ) - return parser - -def main(): - parser = get_parser() - args = parser.parse_args() - - with open(args.cmvn_json, "r") as fin: - cmvn_dict = json.load(fin) - - mean_stats = np.array(cmvn_dict["mean_stats"]) - var_stats = np.array(cmvn_dict["var_stats"]) - total_frame = np.array(cmvn_dict["total_frames"]) - - mean = -1.0 * mean_stats / total_frame - var = 1.0 / np.sqrt(var_stats / total_frame - mean * mean) - dims = mean.shape[0] - with open(args.am_mvn, 'w') as fout: - fout.write("" + "\n" + " " + str(dims) + " " + str(dims) + '\n' + "[ 0 ]" + "\n" + " " + str(dims) + " " + str(dims) + "\n") - mean_str = str(list(mean)).replace(',', '').replace('[', '[ ').replace(']', ' ]') - fout.write(" 0 " + mean_str + '\n') - fout.write(" " + str(dims) + " " + str(dims) + '\n') - var_str = str(list(var)).replace(',', '').replace('[', '[ ').replace(']', ' ]') - fout.write(" 0 " + var_str + '\n') - fout.write("" + '\n') - -if __name__ == '__main__': - main() diff --git a/egs/aishell/transformer/utils/combine_cmvn_file.py b/egs/aishell/transformer/utils/combine_cmvn_file.py deleted file mode 100755 index c52597372..000000000 --- a/egs/aishell/transformer/utils/combine_cmvn_file.py +++ /dev/null @@ -1,72 +0,0 @@ -import argparse -import json -import os - -import numpy as np - - -def get_parser(): - parser = argparse.ArgumentParser( - description="combine cmvn file", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "--dim", - default=80, - type=int, - help="feature dim", - ) - parser.add_argument( - "--cmvn_dir", - default=False, - required=True, - type=str, - help="cmvn dir", - ) - - parser.add_argument( - "--nj", - default=1, - required=True, - type=int, - help="num of cmvn files", - ) - parser.add_argument( - "--output_dir", - default=False, - required=True, - type=str, - help="output dir", - ) - return parser - - -def main(): - parser = get_parser() - args = parser.parse_args() - - total_means = np.zeros(args.dim) - total_vars = np.zeros(args.dim) - total_frames = 0 - - cmvn_file = os.path.join(args.output_dir, "cmvn.json") - - for i in range(1, args.nj + 1): - with open(os.path.join(args.cmvn_dir, "cmvn.{}.json".format(str(i)))) as fin: - cmvn_stats = json.load(fin) - - total_means += np.array(cmvn_stats["mean_stats"]) - total_vars += np.array(cmvn_stats["var_stats"]) - total_frames += cmvn_stats["total_frames"] - - cmvn_info = { - 'mean_stats': list(total_means.tolist()), - 'var_stats': list(total_vars.tolist()), - 'total_frames': total_frames - } - with open(cmvn_file, 'w') as fout: - fout.write(json.dumps(cmvn_info)) - - -if __name__ == '__main__': - main() diff --git a/egs/aishell/transformer/utils/compute_cmvn.py b/egs/aishell/transformer/utils/compute_cmvn.py deleted file mode 100755 index 4986a5a25..000000000 --- a/egs/aishell/transformer/utils/compute_cmvn.py +++ /dev/null @@ -1,126 +0,0 @@ -import argparse -import json -import os - -import numpy as np -import torchaudio -import torchaudio.compliance.kaldi as kaldi -import yaml - - -def get_parser(): - parser = argparse.ArgumentParser( - description="computer global cmvn", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "--dim", - default=80, - type=int, - help="feature dimension", - ) - parser.add_argument( - "--wav_path", - default=False, - required=True, - type=str, - help="the path of wav scps", - ) - parser.add_argument( - "--config_file", - type=str, - help="the config file for computing cmvn", - ) - parser.add_argument( - "--idx", - default=1, - required=True, - type=int, - help="index", - ) - return parser - - -def compute_fbank(wav_file, - num_mel_bins=80, - frame_length=25, - frame_shift=10, - dither=0.0, - resample_rate=16000, - speed=1.0, - window_type="hamming"): - waveform, sample_rate = torchaudio.load(wav_file) - if resample_rate != sample_rate: - waveform = torchaudio.transforms.Resample(orig_freq=sample_rate, - new_freq=resample_rate)(waveform) - if speed != 1.0: - waveform, _ = torchaudio.sox_effects.apply_effects_tensor( - waveform, resample_rate, - [['speed', str(speed)], ['rate', str(resample_rate)]] - ) - - waveform = waveform * (1 << 15) - mat = kaldi.fbank(waveform, - num_mel_bins=num_mel_bins, - frame_length=frame_length, - frame_shift=frame_shift, - dither=dither, - energy_floor=0.0, - window_type=window_type, - sample_frequency=resample_rate) - - return mat.numpy() - - -def main(): - parser = get_parser() - args = parser.parse_args() - - wav_scp_file = os.path.join(args.wav_path, "wav.{}.scp".format(args.idx)) - cmvn_file = os.path.join(args.wav_path, "cmvn.{}.json".format(args.idx)) - - mean_stats = np.zeros(args.dim) - var_stats = np.zeros(args.dim) - total_frames = 0 - - # with ReadHelper('ark:{}'.format(ark_file)) as ark_reader: - # for key, mat in ark_reader: - # mean_stats += np.sum(mat, axis=0) - # var_stats += np.sum(np.square(mat), axis=0) - # total_frames += mat.shape[0] - - with open(args.config_file) as f: - configs = yaml.safe_load(f) - frontend_configs = configs.get("frontend_conf", {}) - num_mel_bins = frontend_configs.get("n_mels", 80) - frame_length = frontend_configs.get("frame_length", 25) - frame_shift = frontend_configs.get("frame_shift", 10) - window_type = frontend_configs.get("window", "hamming") - resample_rate = frontend_configs.get("fs", 16000) - assert num_mel_bins == args.dim - - with open(wav_scp_file) as f: - lines = f.readlines() - for line in lines: - _, wav_file = line.strip().split() - fbank = compute_fbank(wav_file, - num_mel_bins=args.dim, - frame_length=frame_length, - frame_shift=frame_shift, - resample_rate=resample_rate, - window_type=window_type) - mean_stats += np.sum(fbank, axis=0) - var_stats += np.sum(np.square(fbank), axis=0) - total_frames += fbank.shape[0] - - cmvn_info = { - 'mean_stats': list(mean_stats.tolist()), - 'var_stats': list(var_stats.tolist()), - 'total_frames': total_frames - } - with open(cmvn_file, 'w') as fout: - fout.write(json.dumps(cmvn_info)) - - -if __name__ == '__main__': - main() diff --git a/egs/aishell/transformer/utils/compute_cmvn.sh b/egs/aishell/transformer/utils/compute_cmvn.sh deleted file mode 100755 index 4e7f80e06..000000000 --- a/egs/aishell/transformer/utils/compute_cmvn.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; -# Begin configuration section. -fbankdir= -nj=32 -cmd=./utils/run.pl -feats_dim=80 -config_file= -scale=1.0 - -echo "$0 $@" - -. utils/parse_options.sh || exit 1; - -# shellcheck disable=SC2046 -head -n $(awk -v lines="$(wc -l < ${fbankdir}/wav.scp)" -v scale="$scale" 'BEGIN { printf "%.0f\n", lines*scale }') ${fbankdir}/wav.scp > ${fbankdir}/wav.scp.scale - -split_dir=${fbankdir}/cmvn/split_${nj}; -mkdir -p $split_dir -split_scps="" -for n in $(seq $nj); do - split_scps="$split_scps $split_dir/wav.$n.scp" -done -utils/split_scp.pl ${fbankdir}/wav.scp.scale $split_scps || exit 1; - -logdir=${fbankdir}/cmvn/log -$cmd JOB=1:$nj $logdir/cmvn.JOB.log \ - python utils/compute_cmvn.py \ - --dim ${feats_dim} \ - --wav_path $split_dir \ - --config_file $config_file \ - --idx JOB \ - -python utils/combine_cmvn_file.py --dim ${feats_dim} --cmvn_dir $split_dir --nj $nj --output_dir ${fbankdir}/cmvn - -python utils/cmvn_converter.py --cmvn_json ${fbankdir}/cmvn/cmvn.json --am_mvn ${fbankdir}/cmvn/am.mvn - -echo "$0: Succeeded compute global cmvn" diff --git a/egs/aishell/transformer/utils/compute_fbank.py b/egs/aishell/transformer/utils/compute_fbank.py deleted file mode 100755 index 9c3904f78..000000000 --- a/egs/aishell/transformer/utils/compute_fbank.py +++ /dev/null @@ -1,171 +0,0 @@ -from kaldiio import WriteHelper - -import argparse -import numpy as np -import json -import torch -import torchaudio -import torchaudio.compliance.kaldi as kaldi - - -def compute_fbank(wav_file, - num_mel_bins=80, - frame_length=25, - frame_shift=10, - dither=0.0, - resample_rate=16000, - speed=1.0, - window_type="hamming"): - - waveform, sample_rate = torchaudio.load(wav_file) - if resample_rate != sample_rate: - waveform = torchaudio.transforms.Resample(orig_freq=sample_rate, - new_freq=resample_rate)(waveform) - if speed != 1.0: - waveform, _ = torchaudio.sox_effects.apply_effects_tensor( - waveform, resample_rate, - [['speed', str(speed)], ['rate', str(resample_rate)]] - ) - - waveform = waveform * (1 << 15) - mat = kaldi.fbank(waveform, - num_mel_bins=num_mel_bins, - frame_length=frame_length, - frame_shift=frame_shift, - dither=dither, - energy_floor=0.0, - window_type=window_type, - sample_frequency=resample_rate) - - return mat.numpy() - - -def get_parser(): - parser = argparse.ArgumentParser( - description="computer features", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "--wav-lists", - "-w", - default=False, - required=True, - type=str, - help="input wav lists", - ) - parser.add_argument( - "--text-files", - "-t", - default=False, - required=True, - type=str, - help="input text files", - ) - parser.add_argument( - "--dims", - "-d", - default=80, - type=int, - help="feature dims", - ) - parser.add_argument( - "--max-lengths", - "-m", - default=1500, - type=int, - help="max frame numbers", - ) - parser.add_argument( - "--sample-frequency", - "-s", - default=16000, - type=int, - help="sample frequency", - ) - parser.add_argument( - "--speed-perturb", - "-p", - default="1.0", - type=str, - help="speed perturb", - ) - parser.add_argument( - "--ark-index", - "-a", - default=1, - required=True, - type=int, - help="ark index", - ) - parser.add_argument( - "--output-dir", - "-o", - default=False, - required=True, - type=str, - help="output dir", - ) - parser.add_argument( - "--window-type", - default="hamming", - required=False, - type=str, - help="window type" - ) - return parser - - -def main(): - parser = get_parser() - args = parser.parse_args() - - ark_file = args.output_dir + "/ark/feats." + str(args.ark_index) + ".ark" - scp_file = args.output_dir + "/ark/feats." + str(args.ark_index) + ".scp" - text_file = args.output_dir + "/txt/text." + str(args.ark_index) + ".txt" - feats_shape_file = args.output_dir + "/ark/len." + str(args.ark_index) - text_shape_file = args.output_dir + "/txt/len." + str(args.ark_index) - - ark_writer = WriteHelper('ark,scp:{},{}'.format(ark_file, scp_file)) - text_writer = open(text_file, 'w') - feats_shape_writer = open(feats_shape_file, 'w') - text_shape_writer = open(text_shape_file, 'w') - - speed_perturb_list = args.speed_perturb.split(',') - - for speed in speed_perturb_list: - with open(args.wav_lists, 'r', encoding='utf-8') as wavfile: - with open(args.text_files, 'r', encoding='utf-8') as textfile: - for wav, text in zip(wavfile, textfile): - s_w = wav.strip().split() - wav_id = s_w[0] - wav_file = s_w[1] - - s_t = text.strip().split() - text_id = s_t[0] - txt = s_t[1:] - fbank = compute_fbank(wav_file, - num_mel_bins=args.dims, - resample_rate=args.sample_frequency, - speed=float(speed), - window_type=args.window_type - ) - feats_dims = fbank.shape[1] - feats_lens = fbank.shape[0] - if feats_lens >= args.max_lengths: - continue - txt_lens = len(txt) - if speed == "1.0": - wav_id_sp = wav_id - else: - wav_id_sp = wav_id + "_sp" + speed - - feats_shape_writer.write(wav_id_sp + " " + str(feats_lens) + "," + str(feats_dims) + '\n') - text_shape_writer.write(wav_id_sp + " " + str(txt_lens) + '\n') - - text_writer.write(wav_id_sp + " " + " ".join(txt) + '\n') - ark_writer(wav_id_sp, fbank) - - -if __name__ == '__main__': - main() - diff --git a/egs/aishell/transformer/utils/compute_fbank.sh b/egs/aishell/transformer/utils/compute_fbank.sh deleted file mode 100755 index 8704b313c..000000000 --- a/egs/aishell/transformer/utils/compute_fbank.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; -# Begin configuration section. -nj=32 -cmd=./utils/run.pl - -# feature configuration -feats_dim=80 -sample_frequency=16000 -speed_perturb="1.0" -window_type="hamming" -max_lengths=1500 - -echo "$0 $@" - -. utils/parse_options.sh || exit 1; - -data=$1 -logdir=$2 -fbankdir=$3 - -[ ! -f $data/wav.scp ] && echo "$0: no such file $data/wav.scp" && exit 1; -[ ! -f $data/text ] && echo "$0: no such file $data/text" && exit 1; - -python utils/split_data.py $data $data $nj - -ark_dir=${fbankdir}/ark; mkdir -p ${ark_dir} -text_dir=${fbankdir}/txt; mkdir -p ${text_dir} -mkdir -p ${logdir} - -$cmd JOB=1:$nj $logdir/make_fbank.JOB.log \ - python utils/compute_fbank.py -w $data/split${nj}/JOB/wav.scp -t $data/split${nj}/JOB/text \ - -d $feats_dim -s $sample_frequency -m ${max_lengths} -p ${speed_perturb} -a JOB -o ${fbankdir} \ - --window-type ${window_type} \ - || exit 1; - -for n in $(seq $nj); do - cat ${ark_dir}/feats.$n.scp || exit 1 -done > $fbankdir/feats.scp || exit 1 - -for n in $(seq $nj); do - cat ${text_dir}/text.$n.txt || exit 1 -done > $fbankdir/text || exit 1 - -for n in $(seq $nj); do - cat ${ark_dir}/len.$n || exit 1 -done > $fbankdir/speech_shape || exit 1 - -for n in $(seq $nj); do - cat ${text_dir}/len.$n || exit 1 -done > $fbankdir/text_shape || exit 1 - -echo "$0: Succeeded compute FBANK features" diff --git a/egs/aishell/transformer/utils/download_model.py b/egs/aishell/transformer/utils/download_model.py deleted file mode 100755 index 70ea17965..000000000 --- a/egs/aishell/transformer/utils/download_model.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python3 -import argparse - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - parser = argparse.ArgumentParser( - description="download model configs", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument("--model_name", - type=str, - default="damo/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch", - help="model name in ModelScope") - args = parser.parse_args() - - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=args.model_name) diff --git a/egs/aishell/transformer/utils/error_rate_zh b/egs/aishell/transformer/utils/error_rate_zh deleted file mode 100755 index 6871a07fa..000000000 --- a/egs/aishell/transformer/utils/error_rate_zh +++ /dev/null @@ -1,370 +0,0 @@ -#!/usr/bin/env python3 -# coding=utf8 - -# Copyright 2021 Jiayu DU - -import sys -import argparse -import json -import logging -logging.basicConfig(stream=sys.stderr, level=logging.INFO, format='[%(levelname)s] %(message)s') - -DEBUG = None - -def GetEditType(ref_token, hyp_token): - if ref_token == None and hyp_token != None: - return 'I' - elif ref_token != None and hyp_token == None: - return 'D' - elif ref_token == hyp_token: - return 'C' - elif ref_token != hyp_token: - return 'S' - else: - raise RuntimeError - -class AlignmentArc: - def __init__(self, src, dst, ref, hyp): - self.src = src - self.dst = dst - self.ref = ref - self.hyp = hyp - self.edit_type = GetEditType(ref, hyp) - -def similarity_score_function(ref_token, hyp_token): - return 0 if (ref_token == hyp_token) else -1.0 - -def insertion_score_function(token): - return -1.0 - -def deletion_score_function(token): - return -1.0 - -def EditDistance( - ref, - hyp, - similarity_score_function = similarity_score_function, - insertion_score_function = insertion_score_function, - deletion_score_function = deletion_score_function): - assert(len(ref) != 0) - class DPState: - def __init__(self): - self.score = -float('inf') - # backpointer - self.prev_r = None - self.prev_h = None - - def print_search_grid(S, R, H, fstream): - print(file=fstream) - for r in range(R): - for h in range(H): - print(F'[{r},{h}]:{S[r][h].score:4.3f}:({S[r][h].prev_r},{S[r][h].prev_h}) ', end='', file=fstream) - print(file=fstream) - - R = len(ref) + 1 - H = len(hyp) + 1 - - # Construct DP search space, a (R x H) grid - S = [ [] for r in range(R) ] - for r in range(R): - S[r] = [ DPState() for x in range(H) ] - - # initialize DP search grid origin, S(r = 0, h = 0) - S[0][0].score = 0.0 - S[0][0].prev_r = None - S[0][0].prev_h = None - - # initialize REF axis - for r in range(1, R): - S[r][0].score = S[r-1][0].score + deletion_score_function(ref[r-1]) - S[r][0].prev_r = r-1 - S[r][0].prev_h = 0 - - # initialize HYP axis - for h in range(1, H): - S[0][h].score = S[0][h-1].score + insertion_score_function(hyp[h-1]) - S[0][h].prev_r = 0 - S[0][h].prev_h = h-1 - - best_score = S[0][0].score - best_state = (0, 0) - - for r in range(1, R): - for h in range(1, H): - sub_or_cor_score = similarity_score_function(ref[r-1], hyp[h-1]) - new_score = S[r-1][h-1].score + sub_or_cor_score - if new_score >= S[r][h].score: - S[r][h].score = new_score - S[r][h].prev_r = r-1 - S[r][h].prev_h = h-1 - - del_score = deletion_score_function(ref[r-1]) - new_score = S[r-1][h].score + del_score - if new_score >= S[r][h].score: - S[r][h].score = new_score - S[r][h].prev_r = r - 1 - S[r][h].prev_h = h - - ins_score = insertion_score_function(hyp[h-1]) - new_score = S[r][h-1].score + ins_score - if new_score >= S[r][h].score: - S[r][h].score = new_score - S[r][h].prev_r = r - S[r][h].prev_h = h-1 - - best_score = S[R-1][H-1].score - best_state = (R-1, H-1) - - if DEBUG: - print_search_grid(S, R, H, sys.stderr) - - # Backtracing best alignment path, i.e. a list of arcs - # arc = (src, dst, ref, hyp, edit_type) - # src/dst = (r, h), where r/h refers to search grid state-id along Ref/Hyp axis - best_path = [] - r, h = best_state[0], best_state[1] - prev_r, prev_h = S[r][h].prev_r, S[r][h].prev_h - score = S[r][h].score - # loop invariant: - # 1. (prev_r, prev_h) -> (r, h) is a "forward arc" on best alignment path - # 2. score is the value of point(r, h) on DP search grid - while prev_r != None or prev_h != None: - src = (prev_r, prev_h) - dst = (r, h) - if (r == prev_r + 1 and h == prev_h + 1): # Substitution or correct - arc = AlignmentArc(src, dst, ref[prev_r], hyp[prev_h]) - elif (r == prev_r + 1 and h == prev_h): # Deletion - arc = AlignmentArc(src, dst, ref[prev_r], None) - elif (r == prev_r and h == prev_h + 1): # Insertion - arc = AlignmentArc(src, dst, None, hyp[prev_h]) - else: - raise RuntimeError - best_path.append(arc) - r, h = prev_r, prev_h - prev_r, prev_h = S[r][h].prev_r, S[r][h].prev_h - score = S[r][h].score - - best_path.reverse() - return (best_path, best_score) - -def PrettyPrintAlignment(alignment, stream = sys.stderr): - def get_token_str(token): - if token == None: - return "*" - return token - - def is_double_width_char(ch): - if (ch >= '\u4e00') and (ch <= '\u9fa5'): # codepoint ranges for Chinese chars - return True - # TODO: support other double-width-char language such as Japanese, Korean - else: - return False - - def display_width(token_str): - m = 0 - for c in token_str: - if is_double_width_char(c): - m += 2 - else: - m += 1 - return m - - R = ' REF : ' - H = ' HYP : ' - E = ' EDIT : ' - for arc in alignment: - r = get_token_str(arc.ref) - h = get_token_str(arc.hyp) - e = arc.edit_type if arc.edit_type != 'C' else '' - - nr, nh, ne = display_width(r), display_width(h), display_width(e) - n = max(nr, nh, ne) + 1 - - R += r + ' ' * (n-nr) - H += h + ' ' * (n-nh) - E += e + ' ' * (n-ne) - - print(R, file=stream) - print(H, file=stream) - print(E, file=stream) - -def CountEdits(alignment): - c, s, i, d = 0, 0, 0, 0 - for arc in alignment: - if arc.edit_type == 'C': - c += 1 - elif arc.edit_type == 'S': - s += 1 - elif arc.edit_type == 'I': - i += 1 - elif arc.edit_type == 'D': - d += 1 - else: - raise RuntimeError - return (c, s, i, d) - -def ComputeTokenErrorRate(c, s, i, d): - return 100.0 * (s + d + i) / (s + d + c) - -def ComputeSentenceErrorRate(num_err_utts, num_utts): - assert(num_utts != 0) - return 100.0 * num_err_utts / num_utts - - -class EvaluationResult: - def __init__(self): - self.num_ref_utts = 0 - self.num_hyp_utts = 0 - self.num_eval_utts = 0 # seen in both ref & hyp - self.num_hyp_without_ref = 0 - - self.C = 0 - self.S = 0 - self.I = 0 - self.D = 0 - self.token_error_rate = 0.0 - - self.num_utts_with_error = 0 - self.sentence_error_rate = 0.0 - - def to_json(self): - return json.dumps(self.__dict__) - - def to_kaldi(self): - info = ( - F'%WER {self.token_error_rate:.2f} [ {self.S + self.D + self.I} / {self.C + self.S + self.D}, {self.I} ins, {self.D} del, {self.S} sub ]\n' - F'%SER {self.sentence_error_rate:.2f} [ {self.num_utts_with_error} / {self.num_eval_utts} ]\n' - ) - return info - - def to_sclite(self): - return "TODO" - - def to_espnet(self): - return "TODO" - - def to_summary(self): - #return json.dumps(self.__dict__, indent=4) - summary = ( - '==================== Overall Statistics ====================\n' - F'num_ref_utts: {self.num_ref_utts}\n' - F'num_hyp_utts: {self.num_hyp_utts}\n' - F'num_hyp_without_ref: {self.num_hyp_without_ref}\n' - F'num_eval_utts: {self.num_eval_utts}\n' - F'sentence_error_rate: {self.sentence_error_rate:.2f}%\n' - F'token_error_rate: {self.token_error_rate:.2f}%\n' - F'token_stats:\n' - F' - tokens:{self.C + self.S + self.D:>7}\n' - F' - edits: {self.S + self.I + self.D:>7}\n' - F' - cor: {self.C:>7}\n' - F' - sub: {self.S:>7}\n' - F' - ins: {self.I:>7}\n' - F' - del: {self.D:>7}\n' - '============================================================\n' - ) - return summary - - -class Utterance: - def __init__(self, uid, text): - self.uid = uid - self.text = text - - -def LoadUtterances(filepath, format): - utts = {} - if format == 'text': # utt_id word1 word2 ... - with open(filepath, 'r', encoding='utf8') as f: - for line in f: - line = line.strip() - if line: - cols = line.split(maxsplit=1) - assert(len(cols) == 2 or len(cols) == 1) - uid = cols[0] - text = cols[1] if len(cols) == 2 else '' - if utts.get(uid) != None: - raise RuntimeError(F'Found duplicated utterence id {uid}') - utts[uid] = Utterance(uid, text) - else: - raise RuntimeError(F'Unsupported text format {format}') - return utts - - -def tokenize_text(text, tokenizer): - if tokenizer == 'whitespace': - return text.split() - elif tokenizer == 'char': - return [ ch for ch in ''.join(text.split()) ] - else: - raise RuntimeError(F'ERROR: Unsupported tokenizer {tokenizer}') - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - # optional - parser.add_argument('--tokenizer', choices=['whitespace', 'char'], default='whitespace', help='whitespace for WER, char for CER') - parser.add_argument('--ref-format', choices=['text'], default='text', help='reference format, first col is utt_id, the rest is text') - parser.add_argument('--hyp-format', choices=['text'], default='text', help='hypothesis format, first col is utt_id, the rest is text') - # required - parser.add_argument('--ref', type=str, required=True, help='input reference file') - parser.add_argument('--hyp', type=str, required=True, help='input hypothesis file') - - parser.add_argument('result_file', type=str) - args = parser.parse_args() - logging.info(args) - - ref_utts = LoadUtterances(args.ref, args.ref_format) - hyp_utts = LoadUtterances(args.hyp, args.hyp_format) - - r = EvaluationResult() - - # check valid utterances in hyp that have matched non-empty reference - eval_utts = [] - r.num_hyp_without_ref = 0 - for uid in sorted(hyp_utts.keys()): - if uid in ref_utts.keys(): # TODO: efficiency - if ref_utts[uid].text.strip(): # non-empty reference - eval_utts.append(uid) - else: - logging.warn(F'Found {uid} with empty reference, skipping...') - else: - logging.warn(F'Found {uid} without reference, skipping...') - r.num_hyp_without_ref += 1 - - r.num_hyp_utts = len(hyp_utts) - r.num_ref_utts = len(ref_utts) - r.num_eval_utts = len(eval_utts) - - with open(args.result_file, 'w+', encoding='utf8') as fo: - for uid in eval_utts: - ref = ref_utts[uid] - hyp = hyp_utts[uid] - - alignment, score = EditDistance( - tokenize_text(ref.text, args.tokenizer), - tokenize_text(hyp.text, args.tokenizer) - ) - - c, s, i, d = CountEdits(alignment) - utt_ter = ComputeTokenErrorRate(c, s, i, d) - - # utt-level evaluation result - print(F'{{"uid":{uid}, "score":{score}, "ter":{utt_ter:.2f}, "cor":{c}, "sub":{s}, "ins":{i}, "del":{d}}}', file=fo) - PrettyPrintAlignment(alignment, fo) - - r.C += c - r.S += s - r.I += i - r.D += d - - if utt_ter > 0: - r.num_utts_with_error += 1 - - # corpus level evaluation result - r.sentence_error_rate = ComputeSentenceErrorRate(r.num_utts_with_error, r.num_eval_utts) - r.token_error_rate = ComputeTokenErrorRate(r.C, r.S, r.I, r.D) - - print(r.to_summary(), file=fo) - - print(r.to_json()) - print(r.to_kaldi()) diff --git a/egs/aishell/transformer/utils/extract_embeds.py b/egs/aishell/transformer/utils/extract_embeds.py deleted file mode 100755 index 7b817d8ca..000000000 --- a/egs/aishell/transformer/utils/extract_embeds.py +++ /dev/null @@ -1,47 +0,0 @@ -from transformers import AutoTokenizer, AutoModel, pipeline -import numpy as np -import sys -import os -import torch -from kaldiio import WriteHelper -import re -text_file_json = sys.argv[1] -out_ark = sys.argv[2] -out_scp = sys.argv[3] -out_shape = sys.argv[4] -device = int(sys.argv[5]) -model_path = sys.argv[6] - -model = AutoModel.from_pretrained(model_path) -tokenizer = AutoTokenizer.from_pretrained(model_path) -extractor = pipeline(task="feature-extraction", model=model, tokenizer=tokenizer, device=device) - -with open(text_file_json, 'r') as f: - js = f.readlines() - - -f_shape = open(out_shape, "w") -with WriteHelper('ark,scp:{},{}'.format(out_ark, out_scp)) as writer: - with torch.no_grad(): - for idx, line in enumerate(js): - id, tokens = line.strip().split(" ", 1) - tokens = re.sub(" ", "", tokens.strip()) - tokens = ' '.join([j for j in tokens]) - token_num = len(tokens.split(" ")) - outputs = extractor(tokens) - outputs = np.array(outputs) - embeds = outputs[0, 1:-1, :] - - token_num_embeds, dim = embeds.shape - if token_num == token_num_embeds: - writer(id, embeds) - shape_line = "{} {},{}\n".format(id, token_num_embeds, dim) - f_shape.write(shape_line) - else: - print("{}, size has changed, {}, {}, {}".format(id, token_num, token_num_embeds, tokens)) - - - -f_shape.close() - - diff --git a/egs/aishell/transformer/utils/filter_scp.pl b/egs/aishell/transformer/utils/filter_scp.pl deleted file mode 100755 index 003530d53..000000000 --- a/egs/aishell/transformer/utils/filter_scp.pl +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env perl -# Copyright 2010-2012 Microsoft Corporation -# Johns Hopkins University (author: Daniel Povey) - -# 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 -# -# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -# MERCHANTABLITY OR NON-INFRINGEMENT. -# See the Apache 2 License for the specific language governing permissions and -# limitations under the License. - - -# This script takes a list of utterance-ids or any file whose first field -# of each line is an utterance-id, and filters an scp -# file (or any file whose "n-th" field is an utterance id), printing -# out only those lines whose "n-th" field is in id_list. The index of -# the "n-th" field is 1, by default, but can be changed by using -# the -f switch - -$exclude = 0; -$field = 1; -$shifted = 0; - -do { - $shifted=0; - if ($ARGV[0] eq "--exclude") { - $exclude = 1; - shift @ARGV; - $shifted=1; - } - if ($ARGV[0] eq "-f") { - $field = $ARGV[1]; - shift @ARGV; shift @ARGV; - $shifted=1 - } -} while ($shifted); - -if(@ARGV < 1 || @ARGV > 2) { - die "Usage: filter_scp.pl [--exclude] [-f ] id_list [in.scp] > out.scp \n" . - "Prints only the input lines whose f'th field (default: first) is in 'id_list'.\n" . - "Note: only the first field of each line in id_list matters. With --exclude, prints\n" . - "only the lines that were *not* in id_list.\n" . - "Caution: previously, the -f option was interpreted as a zero-based field index.\n" . - "If your older scripts (written before Oct 2014) stopped working and you used the\n" . - "-f option, add 1 to the argument.\n" . - "See also: scripts/filter_scp.pl .\n"; -} - - -$idlist = shift @ARGV; -open(F, "<$idlist") || die "Could not open id-list file $idlist"; -while() { - @A = split; - @A>=1 || die "Invalid id-list file line $_"; - $seen{$A[0]} = 1; -} - -if ($field == 1) { # Treat this as special case, since it is common. - while(<>) { - $_ =~ m/\s*(\S+)\s*/ || die "Bad line $_, could not get first field."; - # $1 is what we filter on. - if ((!$exclude && $seen{$1}) || ($exclude && !defined $seen{$1})) { - print $_; - } - } -} else { - while(<>) { - @A = split; - @A > 0 || die "Invalid scp file line $_"; - @A >= $field || die "Invalid scp file line $_"; - if ((!$exclude && $seen{$A[$field-1]}) || ($exclude && !defined $seen{$A[$field-1]})) { - print $_; - } - } -} - -# tests: -# the following should print "foo 1" -# ( echo foo 1; echo bar 2 ) | scripts/filter_scp.pl <(echo foo) -# the following should print "bar 2". -# ( echo foo 1; echo bar 2 ) | scripts/filter_scp.pl -f 2 <(echo 2) diff --git a/egs/aishell/transformer/utils/fix_data.sh b/egs/aishell/transformer/utils/fix_data.sh deleted file mode 100755 index b1a2bb808..000000000 --- a/egs/aishell/transformer/utils/fix_data.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -echo "$0 $@" -data_dir=$1 - -if [ ! -f ${data_dir}/wav.scp ]; then - echo "$0: wav.scp is not found" - exit 1; -fi - -if [ ! -f ${data_dir}/text ]; then - echo "$0: text is not found" - exit 1; -fi - - - -mkdir -p ${data_dir}/.backup - -awk '{print $1}' ${data_dir}/wav.scp > ${data_dir}/.backup/wav_id -awk '{print $1}' ${data_dir}/text > ${data_dir}/.backup/text_id - -sort ${data_dir}/.backup/wav_id ${data_dir}/.backup/text_id | uniq -d > ${data_dir}/.backup/id - -cp ${data_dir}/wav.scp ${data_dir}/.backup/wav.scp -cp ${data_dir}/text ${data_dir}/.backup/text - -mv ${data_dir}/wav.scp ${data_dir}/wav.scp.bak -mv ${data_dir}/text ${data_dir}/text.bak - -utils/filter_scp.pl -f 1 ${data_dir}/.backup/id ${data_dir}/wav.scp.bak | sort -k1,1 -u > ${data_dir}/wav.scp -utils/filter_scp.pl -f 1 ${data_dir}/.backup/id ${data_dir}/text.bak | sort -k1,1 -u > ${data_dir}/text - -rm ${data_dir}/wav.scp.bak -rm ${data_dir}/text.bak diff --git a/egs/aishell/transformer/utils/fix_data_feat.sh b/egs/aishell/transformer/utils/fix_data_feat.sh deleted file mode 100755 index 84eea36b6..000000000 --- a/egs/aishell/transformer/utils/fix_data_feat.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash - -echo "$0 $@" -data_dir=$1 - -if [ ! -f ${data_dir}/feats.scp ]; then - echo "$0: feats.scp is not found" - exit 1; -fi - -if [ ! -f ${data_dir}/text ]; then - echo "$0: text is not found" - exit 1; -fi - -if [ ! -f ${data_dir}/speech_shape ]; then - echo "$0: feature lengths is not found" - exit 1; -fi - -if [ ! -f ${data_dir}/text_shape ]; then - echo "$0: text lengths is not found" - exit 1; -fi - -mkdir -p ${data_dir}/.backup - -awk '{print $1}' ${data_dir}/feats.scp > ${data_dir}/.backup/wav_id -awk '{print $1}' ${data_dir}/text > ${data_dir}/.backup/text_id - -sort ${data_dir}/.backup/wav_id ${data_dir}/.backup/text_id | uniq -d > ${data_dir}/.backup/id - -cp ${data_dir}/feats.scp ${data_dir}/.backup/feats.scp -cp ${data_dir}/text ${data_dir}/.backup/text -cp ${data_dir}/speech_shape ${data_dir}/.backup/speech_shape -cp ${data_dir}/text_shape ${data_dir}/.backup/text_shape - -mv ${data_dir}/feats.scp ${data_dir}/feats.scp.bak -mv ${data_dir}/text ${data_dir}/text.bak -mv ${data_dir}/speech_shape ${data_dir}/speech_shape.bak -mv ${data_dir}/text_shape ${data_dir}/text_shape.bak - -utils/filter_scp.pl -f 1 ${data_dir}/.backup/id ${data_dir}/feats.scp.bak | sort -k1,1 -u > ${data_dir}/feats.scp -utils/filter_scp.pl -f 1 ${data_dir}/.backup/id ${data_dir}/text.bak | sort -k1,1 -u > ${data_dir}/text -utils/filter_scp.pl -f 1 ${data_dir}/.backup/id ${data_dir}/speech_shape.bak | sort -k1,1 -u > ${data_dir}/speech_shape -utils/filter_scp.pl -f 1 ${data_dir}/.backup/id ${data_dir}/text_shape.bak | sort -k1,1 -u > ${data_dir}/text_shape - -rm ${data_dir}/feats.scp.bak -rm ${data_dir}/text.bak -rm ${data_dir}/speech_shape.bak -rm ${data_dir}/text_shape.bak - diff --git a/egs/aishell/transformer/utils/gen_ark_list.sh b/egs/aishell/transformer/utils/gen_ark_list.sh deleted file mode 100755 index aebf3562d..000000000 --- a/egs/aishell/transformer/utils/gen_ark_list.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - - -# Begin configuration section. -nj=32 -cmd=./utils/run.pl - -echo "$0 $@" - -. utils/parse_options.sh || exit 1; - -ark_dir=$1 -txt_dir=$2 -output_dir=$3 - -[ ! -d ${ark_dir}/ark ] && echo "$0: ark data is required" && exit 1; -[ ! -d ${txt_dir}/txt ] && echo "$0: txt data is required" && exit 1; - -for n in $(seq $nj); do - echo "${ark_dir}/ark/feats.$n.ark ${txt_dir}/txt/text.$n.txt" || exit 1 -done > ${output_dir}/ark_txt.scp || exit 1 - diff --git a/egs/aishell/transformer/utils/gen_modelscope_configuration.py b/egs/aishell/transformer/utils/gen_modelscope_configuration.py deleted file mode 100644 index d34097058..000000000 --- a/egs/aishell/transformer/utils/gen_modelscope_configuration.py +++ /dev/null @@ -1,118 +0,0 @@ -import argparse -import json -import os - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument( - "--task", - type=str, - default="auto-speech-recognition", - help="task name", - ) - parser.add_argument( - "--type", - type=str, - default="generic-asr", - ) - parser.add_argument( - "--am_model_name", - type=str, - default="model.pb", - help="model file name", - ) - parser.add_argument( - "--mode", - type=str, - default="paraformer", - help="mode for decoding", - ) - parser.add_argument( - "--lang", - type=str, - default="zh-cn", - help="language", - ) - parser.add_argument( - "--batch_size", - type=int, - default=1, - help="batch size", - ) - parser.add_argument( - "--am_model_config", - type=str, - default="config.yaml", - help="config file", - ) - parser.add_argument( - "--mvn_file", - type=str, - default="am.mvn", - help="cmvn file", - ) - parser.add_argument( - "--model_name", - type=str, - help="model name", - ) - parser.add_argument( - "--pipeline_type", - type=str, - default="asr-inference", - help="pipeline type", - ) - parser.add_argument( - "--vocab_size", - type=int, - help="vocab_size", - ) - parser.add_argument( - "--dataset", - type=str, - help="dataset name", - ) - parser.add_argument( - "--output_dir", - type=str, - help="output path", - ) - parser.add_argument( - "--nat", - type=str, - default="", - help="nat", - ) - parser.add_argument( - "--tag", - type=str, - default="exp1", - help="model name tag", - ) - args = parser.parse_args() - - model = { - "type": args.type, - "am_model_name": args.am_model_name, - "model_config": { - "type": "pytorch", - "code_base": "funasr", - "mode": args.mode, - "lang": args.lang, - "batch_size": args.batch_size, - "am_model_config": args.am_model_config, - "mvn_file": args.mvn_file, - "model": "speech_{}_asr{}-{}-16k-{}-vocab{}-pytorch-{}".format(args.model_name, args.nat, args.lang, - args.dataset, args.vocab_size, args.tag), - } - } - pipeline = {"type": args.pipeline_type} - json_dict = { - "framework": "pytorch", - "task": args.task, - "model": model, - "pipeline": pipeline, - } - - with open(os.path.join(args.output_dir, "configuration.json"), "w") as f: - json.dump(json_dict, f, indent=4) diff --git a/egs/aishell/transformer/utils/parse_options.sh b/egs/aishell/transformer/utils/parse_options.sh deleted file mode 100755 index 71fb9e5ea..000000000 --- a/egs/aishell/transformer/utils/parse_options.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2012 Johns Hopkins University (Author: Daniel Povey); -# Arnab Ghoshal, Karel Vesely - -# 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 -# -# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -# MERCHANTABLITY OR NON-INFRINGEMENT. -# See the Apache 2 License for the specific language governing permissions and -# limitations under the License. - - -# Parse command-line options. -# To be sourced by another script (as in ". parse_options.sh"). -# Option format is: --option-name arg -# and shell variable "option_name" gets set to value "arg." -# The exception is --help, which takes no arguments, but prints the -# $help_message variable (if defined). - - -### -### The --config file options have lower priority to command line -### options, so we need to import them first... -### - -# Now import all the configs specified by command-line, in left-to-right order -for ((argpos=1; argpos<$#; argpos++)); do - if [ "${!argpos}" == "--config" ]; then - argpos_plus1=$((argpos+1)) - config=${!argpos_plus1} - [ ! -r $config ] && echo "$0: missing config '$config'" && exit 1 - . $config # source the config file. - fi -done - - -### -### Now we process the command line options -### -while true; do - [ -z "${1:-}" ] && break; # break if there are no arguments - case "$1" in - # If the enclosing script is called with --help option, print the help - # message and exit. Scripts should put help messages in $help_message - --help|-h) if [ -z "$help_message" ]; then echo "No help found." 1>&2; - else printf "$help_message\n" 1>&2 ; fi; - exit 0 ;; - --*=*) echo "$0: options to scripts must be of the form --name value, got '$1'" - exit 1 ;; - # If the first command-line argument begins with "--" (e.g. --foo-bar), - # then work out the variable name as $name, which will equal "foo_bar". - --*) name=`echo "$1" | sed s/^--// | sed s/-/_/g`; - # Next we test whether the variable in question is undefned-- if so it's - # an invalid option and we die. Note: $0 evaluates to the name of the - # enclosing script. - # The test [ -z ${foo_bar+xxx} ] will return true if the variable foo_bar - # is undefined. We then have to wrap this test inside "eval" because - # foo_bar is itself inside a variable ($name). - eval '[ -z "${'$name'+xxx}" ]' && echo "$0: invalid option $1" 1>&2 && exit 1; - - oldval="`eval echo \\$$name`"; - # Work out whether we seem to be expecting a Boolean argument. - if [ "$oldval" == "true" ] || [ "$oldval" == "false" ]; then - was_bool=true; - else - was_bool=false; - fi - - # Set the variable to the right value-- the escaped quotes make it work if - # the option had spaces, like --cmd "queue.pl -sync y" - eval $name=\"$2\"; - - # Check that Boolean-valued arguments are really Boolean. - if $was_bool && [[ "$2" != "true" && "$2" != "false" ]]; then - echo "$0: expected \"true\" or \"false\": $1 $2" 1>&2 - exit 1; - fi - shift 2; - ;; - *) break; - esac -done - - -# Check for an empty argument to the --cmd option, which can easily occur as a -# result of scripting errors. -[ ! -z "${cmd+xxx}" ] && [ -z "$cmd" ] && echo "$0: empty argument to --cmd option" 1>&2 && exit 1; - - -true; # so this script returns exit code 0. diff --git a/egs/aishell/transformer/utils/prepare_checkpoint.py b/egs/aishell/transformer/utils/prepare_checkpoint.py deleted file mode 100644 index 116fa078b..000000000 --- a/egs/aishell/transformer/utils/prepare_checkpoint.py +++ /dev/null @@ -1,19 +0,0 @@ -import os -import shutil - -from modelscope.hub.snapshot_download import snapshot_download - - -if __name__ == '__main__': - import sys - - model = sys.argv[1] - checkpoint_dir = sys.argv[2] - checkpoint_name = sys.argv[3] - - try: - pretrained_model_path = snapshot_download(model, cache_dir=checkpoint_dir) - except BaseException: - raise BaseException(f"Please download pretrain model from ModelScope firstly.") - shutil.copy(os.path.join(checkpoint_dir, checkpoint_name), os.path.join(pretrained_model_path, "model.pb")) - shutil.copy(os.path.join(checkpoint_dir, "config.yaml"), os.path.join(pretrained_model_path, "config.yaml")) diff --git a/egs/aishell/transformer/utils/print_args.py b/egs/aishell/transformer/utils/print_args.py deleted file mode 100755 index b0c61e5b4..000000000 --- a/egs/aishell/transformer/utils/print_args.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -import sys - - -def get_commandline_args(no_executable=True): - extra_chars = [ - " ", - ";", - "&", - "|", - "<", - ">", - "?", - "*", - "~", - "`", - '"', - "'", - "\\", - "{", - "}", - "(", - ")", - ] - - # Escape the extra characters for shell - argv = [ - arg.replace("'", "'\\''") - if all(char not in arg for char in extra_chars) - else "'" + arg.replace("'", "'\\''") + "'" - for arg in sys.argv - ] - - if no_executable: - return " ".join(argv[1:]) - else: - return sys.executable + " " + " ".join(argv) - - -def main(): - print(get_commandline_args()) - - -if __name__ == "__main__": - main() diff --git a/egs/aishell/transformer/utils/proc_conf_oss.py b/egs/aishell/transformer/utils/proc_conf_oss.py deleted file mode 100755 index c4a90c5c1..000000000 --- a/egs/aishell/transformer/utils/proc_conf_oss.py +++ /dev/null @@ -1,35 +0,0 @@ -from pathlib import Path - -import torch -import yaml - - -class NoAliasSafeDumper(yaml.SafeDumper): - # Disable anchor/alias in yaml because looks ugly - def ignore_aliases(self, data): - return True - - -def yaml_no_alias_safe_dump(data, stream=None, **kwargs): - """Safe-dump in yaml with no anchor/alias""" - return yaml.dump( - data, stream, allow_unicode=True, Dumper=NoAliasSafeDumper, **kwargs - ) - - -def gen_conf(file, out_dir): - conf = torch.load(file)["config"] - conf["oss_bucket"] = "null" - print(conf) - output_dir = Path(out_dir) - output_dir.mkdir(parents=True, exist_ok=True) - with (output_dir / "config.yaml").open("w", encoding="utf-8") as f: - yaml_no_alias_safe_dump(conf, f, indent=4, sort_keys=False) - - -if __name__ == "__main__": - import sys - - in_f = sys.argv[1] - out_f = sys.argv[2] - gen_conf(in_f, out_f) diff --git a/egs/aishell/transformer/utils/proce_text.py b/egs/aishell/transformer/utils/proce_text.py deleted file mode 100755 index 9e517a4e1..000000000 --- a/egs/aishell/transformer/utils/proce_text.py +++ /dev/null @@ -1,31 +0,0 @@ - -import sys -import re - -in_f = sys.argv[1] -out_f = sys.argv[2] - - -with open(in_f, "r", encoding="utf-8") as f: - lines = f.readlines() - -with open(out_f, "w", encoding="utf-8") as f: - for line in lines: - outs = line.strip().split(" ", 1) - if len(outs) == 2: - idx, text = outs - text = re.sub("", "", text) - text = re.sub("", "", text) - text = re.sub("@@", "", text) - text = re.sub("@", "", text) - text = re.sub("", "", text) - text = re.sub(" ", "", text) - text = text.lower() - else: - idx = outs[0] - text = " " - - text = [x for x in text] - text = " ".join(text) - out = "{} {}\n".format(idx, text) - f.write(out) diff --git a/egs/aishell/transformer/utils/process_opus.py b/egs/aishell/transformer/utils/process_opus.py deleted file mode 100755 index 1baa3ed13..000000000 --- a/egs/aishell/transformer/utils/process_opus.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2021 NPU, ASLP Group (Author: Qijie Shao) - -# 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. - -# process_opus.py: segmentation and downsampling of opus audio - -# usage: python3 process_opus.py wav.scp segments output_wav.scp - -from pydub import AudioSegment -import sys -import os - - -def read_file(wav_scp, segments): - wav_scp_dict = {} - with open(wav_scp, "r", encoding="UTF-8") as fin: - for line_str in fin: - wav_id, path = line_str.strip().split() - wav_scp_dict[wav_id] = path - - utt_list = [] - seg_path_list = [] - start_time_list = [] - end_time_list = [] - with open(segments, "r", encoding="UTF-8") as fin: - for line_str in fin: - arr = line_str.strip().split() - assert len(arr) == 4 - utt_list.append(arr[0]) - seg_path_list.append(wav_scp_dict[arr[1]]) - start_time_list.append(float(arr[2])) - end_time_list.append(float(arr[3])) - return utt_list, seg_path_list, start_time_list, end_time_list - - -# TODO(Qijie): Fix the process logic -def output(output_wav_scp, utt_list, seg_path_list, start_time_list, end_time_list): - num_utts = len(utt_list) - with open(output_wav_scp, "w", encoding="UTF-8") as fout: - previous_wav_path = "" - for i in range(num_utts): - utt_id = utt_list[i] - current_wav_path = seg_path_list[i] - output_dir = (os.path.dirname(current_wav_path)).replace( - "audio", "audio_seg" - ) - seg_wav_path = os.path.join(output_dir, utt_id + ".wav") - - os.makedirs(output_dir, exist_ok=True) - if current_wav_path != previous_wav_path: - source_wav = AudioSegment.from_file(current_wav_path) - previous_wav_path = current_wav_path - - start = int(start_time_list[i] * 1000) - end = int(end_time_list[i] * 1000) - target_audio = source_wav[start:end].set_frame_rate(16000).set_sample_width(2) - target_audio.export(seg_wav_path, format="wav") - - fout.write("{} {}\n".format(utt_id, seg_wav_path)) - if i % 200 == 0: - print("seg wav finished: {}%".format(int(i / num_utts))) - - -def main(): - wav_scp = sys.argv[1] - segments = sys.argv[2] - output_wav_scp = sys.argv[3] - - utt_list, seg_path_list, start_time_list, end_time_list = read_file( - wav_scp, segments - ) - output(output_wav_scp, utt_list, seg_path_list, start_time_list, end_time_list) - - -if __name__ == "__main__": - main() diff --git a/egs/aishell/transformer/utils/run.pl b/egs/aishell/transformer/utils/run.pl deleted file mode 100755 index 483f95bc6..000000000 --- a/egs/aishell/transformer/utils/run.pl +++ /dev/null @@ -1,356 +0,0 @@ -#!/usr/bin/env perl -use warnings; #sed replacement for -w perl parameter -# In general, doing -# run.pl some.log a b c is like running the command a b c in -# the bash shell, and putting the standard error and output into some.log. -# To run parallel jobs (backgrounded on the host machine), you can do (e.g.) -# run.pl JOB=1:4 some.JOB.log a b c JOB is like running the command a b c JOB -# and putting it in some.JOB.log, for each one. [Note: JOB can be any identifier]. -# If any of the jobs fails, this script will fail. - -# A typical example is: -# run.pl some.log my-prog "--opt=foo bar" foo \| other-prog baz -# and run.pl will run something like: -# ( my-prog '--opt=foo bar' foo | other-prog baz ) >& some.log -# -# Basically it takes the command-line arguments, quotes them -# as necessary to preserve spaces, and evaluates them with bash. -# In addition it puts the command line at the top of the log, and -# the start and end times of the command at the beginning and end. -# The reason why this is useful is so that we can create a different -# version of this program that uses a queueing system instead. - -#use Data::Dumper; - -@ARGV < 2 && die "usage: run.pl log-file command-line arguments..."; - -#print STDERR "COMMAND-LINE: " . Dumper(\@ARGV) . "\n"; -$job_pick = 'all'; -$max_jobs_run = -1; -$jobstart = 1; -$jobend = 1; -$ignored_opts = ""; # These will be ignored. - -# First parse an option like JOB=1:4, and any -# options that would normally be given to -# queue.pl, which we will just discard. - -for (my $x = 1; $x <= 2; $x++) { # This for-loop is to - # allow the JOB=1:n option to be interleaved with the - # options to qsub. - while (@ARGV >= 2 && $ARGV[0] =~ m:^-:) { - # parse any options that would normally go to qsub, but which will be ignored here. - my $switch = shift @ARGV; - if ($switch eq "-V") { - $ignored_opts .= "-V "; - } elsif ($switch eq "--max-jobs-run" || $switch eq "-tc") { - # we do support the option --max-jobs-run n, and its GridEngine form -tc n. - # if the command appears multiple times uses the smallest option. - if ( $max_jobs_run <= 0 ) { - $max_jobs_run = shift @ARGV; - } else { - my $new_constraint = shift @ARGV; - if ( ($new_constraint < $max_jobs_run) ) { - $max_jobs_run = $new_constraint; - } - } - - if (! ($max_jobs_run > 0)) { - die "run.pl: invalid option --max-jobs-run $max_jobs_run"; - } - } else { - my $argument = shift @ARGV; - if ($argument =~ m/^--/) { - print STDERR "run.pl: WARNING: suspicious argument '$argument' to $switch; starts with '-'\n"; - } - if ($switch eq "-sync" && $argument =~ m/^[yY]/) { - $ignored_opts .= "-sync "; # Note: in the - # corresponding code in queue.pl it says instead, just "$sync = 1;". - } elsif ($switch eq "-pe") { # e.g. -pe smp 5 - my $argument2 = shift @ARGV; - $ignored_opts .= "$switch $argument $argument2 "; - } elsif ($switch eq "--gpu") { - $using_gpu = $argument; - } elsif ($switch eq "--pick") { - if($argument =~ m/^(all|failed|incomplete)$/) { - $job_pick = $argument; - } else { - print STDERR "run.pl: ERROR: --pick argument must be one of 'all', 'failed' or 'incomplete'" - } - } else { - # Ignore option. - $ignored_opts .= "$switch $argument "; - } - } - } - if ($ARGV[0] =~ m/^([\w_][\w\d_]*)+=(\d+):(\d+)$/) { # e.g. JOB=1:20 - $jobname = $1; - $jobstart = $2; - $jobend = $3; - if ($jobstart > $jobend) { - die "run.pl: invalid job range $ARGV[0]"; - } - if ($jobstart <= 0) { - die "run.pl: invalid job range $ARGV[0], start must be strictly positive (this is required for GridEngine compatibility)."; - } - shift; - } elsif ($ARGV[0] =~ m/^([\w_][\w\d_]*)+=(\d+)$/) { # e.g. JOB=1. - $jobname = $1; - $jobstart = $2; - $jobend = $2; - shift; - } elsif ($ARGV[0] =~ m/.+\=.*\:.*$/) { - print STDERR "run.pl: Warning: suspicious first argument to run.pl: $ARGV[0]\n"; - } -} - -# Users found this message confusing so we are removing it. -# if ($ignored_opts ne "") { -# print STDERR "run.pl: Warning: ignoring options \"$ignored_opts\"\n"; -# } - -if ($max_jobs_run == -1) { # If --max-jobs-run option not set, - # then work out the number of processors if possible, - # and set it based on that. - $max_jobs_run = 0; - if ($using_gpu) { - if (open(P, "nvidia-smi -L |")) { - $max_jobs_run++ while (

); - close(P); - } - if ($max_jobs_run == 0) { - $max_jobs_run = 1; - print STDERR "run.pl: Warning: failed to detect number of GPUs from nvidia-smi, using ${max_jobs_run}\n"; - } - } elsif (open(P, ") { if (m/^processor/) { $max_jobs_run++; } } - if ($max_jobs_run == 0) { - print STDERR "run.pl: Warning: failed to detect any processors from /proc/cpuinfo\n"; - $max_jobs_run = 10; # reasonable default. - } - close(P); - } elsif (open(P, "sysctl -a |")) { # BSD/Darwin - while (

) { - if (m/hw\.ncpu\s*[:=]\s*(\d+)/) { # hw.ncpu = 4, or hw.ncpu: 4 - $max_jobs_run = $1; - last; - } - } - close(P); - if ($max_jobs_run == 0) { - print STDERR "run.pl: Warning: failed to detect any processors from sysctl -a\n"; - $max_jobs_run = 10; # reasonable default. - } - } else { - # allow at most 32 jobs at once, on non-UNIX systems; change this code - # if you need to change this default. - $max_jobs_run = 32; - } - # The just-computed value of $max_jobs_run is just the number of processors - # (or our best guess); and if it happens that the number of jobs we need to - # run is just slightly above $max_jobs_run, it will make sense to increase - # $max_jobs_run to equal the number of jobs, so we don't have a small number - # of leftover jobs. - $num_jobs = $jobend - $jobstart + 1; - if (!$using_gpu && - $num_jobs > $max_jobs_run && $num_jobs < 1.4 * $max_jobs_run) { - $max_jobs_run = $num_jobs; - } -} - -sub pick_or_exit { - # pick_or_exit ( $logfile ) - # Invoked before each job is started helps to run jobs selectively. - # - # Given the name of the output logfile decides whether the job must be - # executed (by returning from the subroutine) or not (by terminating the - # process calling exit) - # - # PRE: $job_pick is a global variable set by command line switch --pick - # and indicates which class of jobs must be executed. - # - # 1) If a failed job is not executed the process exit code will indicate - # failure, just as if the task was just executed and failed. - # - # 2) If a task is incomplete it will be executed. Incomplete may be either - # a job whose log file does not contain the accounting notes in the end, - # or a job whose log file does not exist. - # - # 3) If the $job_pick is set to 'all' (default behavior) a task will be - # executed regardless of the result of previous attempts. - # - # This logic could have been implemented in the main execution loop - # but a subroutine to preserve the current level of readability of - # that part of the code. - # - # Alexandre Felipe, (o.alexandre.felipe@gmail.com) 14th of August of 2020 - # - if($job_pick eq 'all'){ - return; # no need to bother with the previous log - } - open my $fh, "<", $_[0] or return; # job not executed yet - my $log_line; - my $cur_line; - while ($cur_line = <$fh>) { - if( $cur_line =~ m/# Ended \(code .*/ ) { - $log_line = $cur_line; - } - } - close $fh; - if (! defined($log_line)){ - return; # incomplete - } - if ( $log_line =~ m/# Ended \(code 0\).*/ ) { - exit(0); # complete - } elsif ( $log_line =~ m/# Ended \(code \d+(; signal \d+)?\).*/ ){ - if ($job_pick !~ m/^(failed|all)$/) { - exit(1); # failed but not going to run - } else { - return; # failed - } - } elsif ( $log_line =~ m/.*\S.*/ ) { - return; # incomplete jobs are always run - } -} - - -$logfile = shift @ARGV; - -if (defined $jobname && $logfile !~ m/$jobname/ && - $jobend > $jobstart) { - print STDERR "run.pl: you are trying to run a parallel job but " - . "you are putting the output into just one log file ($logfile)\n"; - exit(1); -} - -$cmd = ""; - -foreach $x (@ARGV) { - if ($x =~ m/^\S+$/) { $cmd .= $x . " "; } - elsif ($x =~ m:\":) { $cmd .= "'$x' "; } - else { $cmd .= "\"$x\" "; } -} - -#$Data::Dumper::Indent=0; -$ret = 0; -$numfail = 0; -%active_pids=(); - -use POSIX ":sys_wait_h"; -for ($jobid = $jobstart; $jobid <= $jobend; $jobid++) { - if (scalar(keys %active_pids) >= $max_jobs_run) { - - # Lets wait for a change in any child's status - # Then we have to work out which child finished - $r = waitpid(-1, 0); - $code = $?; - if ($r < 0 ) { die "run.pl: Error waiting for child process"; } # should never happen. - if ( defined $active_pids{$r} ) { - $jid=$active_pids{$r}; - $fail[$jid]=$code; - if ($code !=0) { $numfail++;} - delete $active_pids{$r}; - # print STDERR "Finished: $r/$jid " . Dumper(\%active_pids) . "\n"; - } else { - die "run.pl: Cannot find the PID of the child process that just finished."; - } - - # In theory we could do a non-blocking waitpid over all jobs running just - # to find out if only one or more jobs finished during the previous waitpid() - # However, we just omit this and will reap the next one in the next pass - # through the for(;;) cycle - } - $childpid = fork(); - if (!defined $childpid) { die "run.pl: Error forking in run.pl (writing to $logfile)"; } - if ($childpid == 0) { # We're in the child... this branch - # executes the job and returns (possibly with an error status). - if (defined $jobname) { - $cmd =~ s/$jobname/$jobid/g; - $logfile =~ s/$jobname/$jobid/g; - } - # exit if the job does not need to be executed - pick_or_exit( $logfile ); - - system("mkdir -p `dirname $logfile` 2>/dev/null"); - open(F, ">$logfile") || die "run.pl: Error opening log file $logfile"; - print F "# " . $cmd . "\n"; - print F "# Started at " . `date`; - $starttime = `date +'%s'`; - print F "#\n"; - close(F); - - # Pipe into bash.. make sure we're not using any other shell. - open(B, "|bash") || die "run.pl: Error opening shell command"; - print B "( " . $cmd . ") 2>>$logfile >> $logfile"; - close(B); # If there was an error, exit status is in $? - $ret = $?; - - $lowbits = $ret & 127; - $highbits = $ret >> 8; - if ($lowbits != 0) { $return_str = "code $highbits; signal $lowbits" } - else { $return_str = "code $highbits"; } - - $endtime = `date +'%s'`; - open(F, ">>$logfile") || die "run.pl: Error opening log file $logfile (again)"; - $enddate = `date`; - chop $enddate; - print F "# Accounting: time=" . ($endtime - $starttime) . " threads=1\n"; - print F "# Ended ($return_str) at " . $enddate . ", elapsed time " . ($endtime-$starttime) . " seconds\n"; - close(F); - exit($ret == 0 ? 0 : 1); - } else { - $pid[$jobid] = $childpid; - $active_pids{$childpid} = $jobid; - # print STDERR "Queued: " . Dumper(\%active_pids) . "\n"; - } -} - -# Now we have submitted all the jobs, lets wait until all the jobs finish -foreach $child (keys %active_pids) { - $jobid=$active_pids{$child}; - $r = waitpid($pid[$jobid], 0); - $code = $?; - if ($r == -1) { die "run.pl: Error waiting for child process"; } # should never happen. - if ($r != 0) { $fail[$jobid]=$code; $numfail++ if $code!=0; } # Completed successfully -} - -# Some sanity checks: -# The $fail array should not contain undefined codes -# The number of non-zeros in that array should be equal to $numfail -# We cannot do foreach() here, as the JOB ids do not start at zero -$failed_jids=0; -for ($jobid = $jobstart; $jobid <= $jobend; $jobid++) { - $job_return = $fail[$jobid]; - if (not defined $job_return ) { - # print Dumper(\@fail); - - die "run.pl: Sanity check failed: we have indication that some jobs are running " . - "even after we waited for all jobs to finish" ; - } - if ($job_return != 0 ){ $failed_jids++;} -} -if ($failed_jids != $numfail) { - die "run.pl: Sanity check failed: cannot find out how many jobs failed ($failed_jids x $numfail)." -} -if ($numfail > 0) { $ret = 1; } - -if ($ret != 0) { - $njobs = $jobend - $jobstart + 1; - if ($njobs == 1) { - if (defined $jobname) { - $logfile =~ s/$jobname/$jobstart/; # only one numbered job, so replace name with - # that job. - } - print STDERR "run.pl: job failed, log is in $logfile\n"; - if ($logfile =~ m/JOB/) { - print STDERR "run.pl: probably you forgot to put JOB=1:\$nj in your script."; - } - } - else { - $logfile =~ s/$jobname/*/g; - print STDERR "run.pl: $numfail / $njobs failed, log is in $logfile\n"; - } -} - - -exit ($ret); diff --git a/egs/aishell/transformer/utils/shuffle_list.pl b/egs/aishell/transformer/utils/shuffle_list.pl deleted file mode 100755 index a116200f4..000000000 --- a/egs/aishell/transformer/utils/shuffle_list.pl +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env perl - -# Copyright 2013 Johns Hopkins University (author: Daniel Povey) - -# 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 -# -# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -# MERCHANTABLITY OR NON-INFRINGEMENT. -# See the Apache 2 License for the specific language governing permissions and -# limitations under the License. - - -if ($ARGV[0] eq "--srand") { - $n = $ARGV[1]; - $n =~ m/\d+/ || die "Bad argument to --srand option: \"$n\""; - srand($ARGV[1]); - shift; - shift; -} else { - srand(0); # Gives inconsistent behavior if we don't seed. -} - -if (@ARGV > 1 || $ARGV[0] =~ m/^-.+/) { # >1 args, or an option we - # don't understand. - print "Usage: shuffle_list.pl [--srand N] [input file] > output\n"; - print "randomizes the order of lines of input.\n"; - exit(1); -} - -@lines; -while (<>) { - push @lines, [ (rand(), $_)] ; -} - -@lines = sort { $a->[0] cmp $b->[0] } @lines; -foreach $l (@lines) { - print $l->[1]; -} \ No newline at end of file diff --git a/egs/aishell/transformer/utils/split_data.py b/egs/aishell/transformer/utils/split_data.py deleted file mode 100755 index 060eae6d3..000000000 --- a/egs/aishell/transformer/utils/split_data.py +++ /dev/null @@ -1,60 +0,0 @@ -import os -import sys -import random - - -in_dir = sys.argv[1] -out_dir = sys.argv[2] -num_split = sys.argv[3] - - -def split_scp(scp, num): - assert len(scp) >= num - avg = len(scp) // num - out = [] - begin = 0 - - for i in range(num): - if i == num - 1: - out.append(scp[begin:]) - else: - out.append(scp[begin:begin+avg]) - begin += avg - - return out - - -os.path.exists("{}/wav.scp".format(in_dir)) -os.path.exists("{}/text".format(in_dir)) - -with open("{}/wav.scp".format(in_dir), 'r') as infile: - wav_list = infile.readlines() - -with open("{}/text".format(in_dir), 'r') as infile: - text_list = infile.readlines() - -assert len(wav_list) == len(text_list) - -x = list(zip(wav_list, text_list)) -random.shuffle(x) -wav_shuffle_list, text_shuffle_list = zip(*x) - -num_split = int(num_split) -wav_split_list = split_scp(wav_shuffle_list, num_split) -text_split_list = split_scp(text_shuffle_list, num_split) - -for idx, wav_list in enumerate(wav_split_list, 1): - path = out_dir + "/split" + str(num_split) + "/" + str(idx) - if not os.path.exists(path): - os.makedirs(path) - with open("{}/wav.scp".format(path), 'w') as wav_writer: - for line in wav_list: - wav_writer.write(line) - -for idx, text_list in enumerate(text_split_list, 1): - path = out_dir + "/split" + str(num_split) + "/" + str(idx) - if not os.path.exists(path): - os.makedirs(path) - with open("{}/text".format(path), 'w') as text_writer: - for line in text_list: - text_writer.write(line) diff --git a/egs/aishell/transformer/utils/split_scp.pl b/egs/aishell/transformer/utils/split_scp.pl deleted file mode 100755 index 0876dcb6d..000000000 --- a/egs/aishell/transformer/utils/split_scp.pl +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/env perl - -# Copyright 2010-2011 Microsoft Corporation - -# See ../../COPYING 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 -# -# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -# MERCHANTABLITY OR NON-INFRINGEMENT. -# See the Apache 2 License for the specific language governing permissions and -# limitations under the License. - - -# This program splits up any kind of .scp or archive-type file. -# If there is no utt2spk option it will work on any text file and -# will split it up with an approximately equal number of lines in -# each but. -# With the --utt2spk option it will work on anything that has the -# utterance-id as the first entry on each line; the utt2spk file is -# of the form "utterance speaker" (on each line). -# It splits it into equal size chunks as far as it can. If you use the utt2spk -# option it will make sure these chunks coincide with speaker boundaries. In -# this case, if there are more chunks than speakers (and in some other -# circumstances), some of the resulting chunks will be empty and it will print -# an error message and exit with nonzero status. -# You will normally call this like: -# split_scp.pl scp scp.1 scp.2 scp.3 ... -# or -# split_scp.pl --utt2spk=utt2spk scp scp.1 scp.2 scp.3 ... -# Note that you can use this script to split the utt2spk file itself, -# e.g. split_scp.pl --utt2spk=utt2spk utt2spk utt2spk.1 utt2spk.2 ... - -# You can also call the scripts like: -# split_scp.pl -j 3 0 scp scp.0 -# [note: with this option, it assumes zero-based indexing of the split parts, -# i.e. the second number must be 0 <= n < num-jobs.] - -use warnings; - -$num_jobs = 0; -$job_id = 0; -$utt2spk_file = ""; -$one_based = 0; - -for ($x = 1; $x <= 3 && @ARGV > 0; $x++) { - if ($ARGV[0] eq "-j") { - shift @ARGV; - $num_jobs = shift @ARGV; - $job_id = shift @ARGV; - } - if ($ARGV[0] =~ /--utt2spk=(.+)/) { - $utt2spk_file=$1; - shift; - } - if ($ARGV[0] eq '--one-based') { - $one_based = 1; - shift @ARGV; - } -} - -if ($num_jobs != 0 && ($num_jobs < 0 || $job_id - $one_based < 0 || - $job_id - $one_based >= $num_jobs)) { - die "$0: Invalid job number/index values for '-j $num_jobs $job_id" . - ($one_based ? " --one-based" : "") . "'\n" -} - -$one_based - and $job_id--; - -if(($num_jobs == 0 && @ARGV < 2) || ($num_jobs > 0 && (@ARGV < 1 || @ARGV > 2))) { - die -"Usage: split_scp.pl [--utt2spk=] in.scp out1.scp out2.scp ... - or: split_scp.pl -j num-jobs job-id [--one-based] [--utt2spk=] in.scp [out.scp] - ... where 0 <= job-id < num-jobs, or 1 <= job-id <- num-jobs if --one-based.\n"; -} - -$error = 0; -$inscp = shift @ARGV; -if ($num_jobs == 0) { # without -j option - @OUTPUTS = @ARGV; -} else { - for ($j = 0; $j < $num_jobs; $j++) { - if ($j == $job_id) { - if (@ARGV > 0) { push @OUTPUTS, $ARGV[0]; } - else { push @OUTPUTS, "-"; } - } else { - push @OUTPUTS, "/dev/null"; - } - } -} - -if ($utt2spk_file ne "") { # We have the --utt2spk option... - open($u_fh, '<', $utt2spk_file) || die "$0: Error opening utt2spk file $utt2spk_file: $!\n"; - while(<$u_fh>) { - @A = split; - @A == 2 || die "$0: Bad line $_ in utt2spk file $utt2spk_file\n"; - ($u,$s) = @A; - $utt2spk{$u} = $s; - } - close $u_fh; - open($i_fh, '<', $inscp) || die "$0: Error opening input scp file $inscp: $!\n"; - @spkrs = (); - while(<$i_fh>) { - @A = split; - if(@A == 0) { die "$0: Empty or space-only line in scp file $inscp\n"; } - $u = $A[0]; - $s = $utt2spk{$u}; - defined $s || die "$0: No utterance $u in utt2spk file $utt2spk_file\n"; - if(!defined $spk_count{$s}) { - push @spkrs, $s; - $spk_count{$s} = 0; - $spk_data{$s} = []; # ref to new empty array. - } - $spk_count{$s}++; - push @{$spk_data{$s}}, $_; - } - # Now split as equally as possible .. - # First allocate spks to files by allocating an approximately - # equal number of speakers. - $numspks = @spkrs; # number of speakers. - $numscps = @OUTPUTS; # number of output files. - if ($numspks < $numscps) { - die "$0: Refusing to split data because number of speakers $numspks " . - "is less than the number of output .scp files $numscps\n"; - } - for($scpidx = 0; $scpidx < $numscps; $scpidx++) { - $scparray[$scpidx] = []; # [] is array reference. - } - for ($spkidx = 0; $spkidx < $numspks; $spkidx++) { - $scpidx = int(($spkidx*$numscps) / $numspks); - $spk = $spkrs[$spkidx]; - push @{$scparray[$scpidx]}, $spk; - $scpcount[$scpidx] += $spk_count{$spk}; - } - - # Now will try to reassign beginning + ending speakers - # to different scp's and see if it gets more balanced. - # Suppose objf we're minimizing is sum_i (num utts in scp[i] - average)^2. - # We can show that if considering changing just 2 scp's, we minimize - # this by minimizing the squared difference in sizes. This is - # equivalent to minimizing the absolute difference in sizes. This - # shows this method is bound to converge. - - $changed = 1; - while($changed) { - $changed = 0; - for($scpidx = 0; $scpidx < $numscps; $scpidx++) { - # First try to reassign ending spk of this scp. - if($scpidx < $numscps-1) { - $sz = @{$scparray[$scpidx]}; - if($sz > 0) { - $spk = $scparray[$scpidx]->[$sz-1]; - $count = $spk_count{$spk}; - $nutt1 = $scpcount[$scpidx]; - $nutt2 = $scpcount[$scpidx+1]; - if( abs( ($nutt2+$count) - ($nutt1-$count)) - < abs($nutt2 - $nutt1)) { # Would decrease - # size-diff by reassigning spk... - $scpcount[$scpidx+1] += $count; - $scpcount[$scpidx] -= $count; - pop @{$scparray[$scpidx]}; - unshift @{$scparray[$scpidx+1]}, $spk; - $changed = 1; - } - } - } - if($scpidx > 0 && @{$scparray[$scpidx]} > 0) { - $spk = $scparray[$scpidx]->[0]; - $count = $spk_count{$spk}; - $nutt1 = $scpcount[$scpidx-1]; - $nutt2 = $scpcount[$scpidx]; - if( abs( ($nutt2-$count) - ($nutt1+$count)) - < abs($nutt2 - $nutt1)) { # Would decrease - # size-diff by reassigning spk... - $scpcount[$scpidx-1] += $count; - $scpcount[$scpidx] -= $count; - shift @{$scparray[$scpidx]}; - push @{$scparray[$scpidx-1]}, $spk; - $changed = 1; - } - } - } - } - # Now print out the files... - for($scpidx = 0; $scpidx < $numscps; $scpidx++) { - $scpfile = $OUTPUTS[$scpidx]; - ($scpfile ne '-' ? open($f_fh, '>', $scpfile) - : open($f_fh, '>&', \*STDOUT)) || - die "$0: Could not open scp file $scpfile for writing: $!\n"; - $count = 0; - if(@{$scparray[$scpidx]} == 0) { - print STDERR "$0: eError: split_scp.pl producing empty .scp file " . - "$scpfile (too many splits and too few speakers?)\n"; - $error = 1; - } else { - foreach $spk ( @{$scparray[$scpidx]} ) { - print $f_fh @{$spk_data{$spk}}; - $count += $spk_count{$spk}; - } - $count == $scpcount[$scpidx] || die "Count mismatch [code error]"; - } - close($f_fh); - } -} else { - # This block is the "normal" case where there is no --utt2spk - # option and we just break into equal size chunks. - - open($i_fh, '<', $inscp) || die "$0: Error opening input scp file $inscp: $!\n"; - - $numscps = @OUTPUTS; # size of array. - @F = (); - while(<$i_fh>) { - push @F, $_; - } - $numlines = @F; - if($numlines == 0) { - print STDERR "$0: error: empty input scp file $inscp\n"; - $error = 1; - } - $linesperscp = int( $numlines / $numscps); # the "whole part".. - $linesperscp >= 1 || die "$0: You are splitting into too many pieces! [reduce \$nj ($numscps) to be smaller than the number of lines ($numlines) in $inscp]\n"; - $remainder = $numlines - ($linesperscp * $numscps); - ($remainder >= 0 && $remainder < $numlines) || die "bad remainder $remainder"; - # [just doing int() rounds down]. - $n = 0; - for($scpidx = 0; $scpidx < @OUTPUTS; $scpidx++) { - $scpfile = $OUTPUTS[$scpidx]; - ($scpfile ne '-' ? open($o_fh, '>', $scpfile) - : open($o_fh, '>&', \*STDOUT)) || - die "$0: Could not open scp file $scpfile for writing: $!\n"; - for($k = 0; $k < $linesperscp + ($scpidx < $remainder ? 1 : 0); $k++) { - print $o_fh $F[$n++]; - } - close($o_fh) || die "$0: Eror closing scp file $scpfile: $!\n"; - } - $n == $numlines || die "$n != $numlines [code error]"; -} - -exit ($error); diff --git a/egs/aishell/transformer/utils/subset_data_dir_tr_cv.sh b/egs/aishell/transformer/utils/subset_data_dir_tr_cv.sh deleted file mode 100755 index e16cebdf1..000000000 --- a/egs/aishell/transformer/utils/subset_data_dir_tr_cv.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -dev_num_utt=1000 - -echo "$0 $@" -. utils/parse_options.sh || exit 1; - -train_data=$1 -out_dir=$2 - -[ ! -f ${train_data}/wav.scp ] && echo "$0: no such file ${train_data}/wav.scp" && exit 1; -[ ! -f ${train_data}/text ] && echo "$0: no such file ${train_data}/text" && exit 1; - -mkdir -p ${out_dir}/train && mkdir -p ${out_dir}/dev - -cp ${train_data}/wav.scp ${out_dir}/train/wav.scp.bak -cp ${train_data}/text ${out_dir}/train/text.bak - -num_utt=$(wc -l <${out_dir}/train/wav.scp.bak) - -utils/shuffle_list.pl --srand 1 ${out_dir}/train/wav.scp.bak > ${out_dir}/train/wav.scp.shuf -head -n ${dev_num_utt} ${out_dir}/train/wav.scp.shuf > ${out_dir}/dev/wav.scp -tail -n $((${num_utt}-${dev_num_utt})) ${out_dir}/train/wav.scp.shuf > ${out_dir}/train/wav.scp - -utils/shuffle_list.pl --srand 1 ${out_dir}/train/text.bak > ${out_dir}/train/text.shuf -head -n ${dev_num_utt} ${out_dir}/train/text.shuf > ${out_dir}/dev/text -tail -n $((${num_utt}-${dev_num_utt})) ${out_dir}/train/text.shuf > ${out_dir}/train/text - -rm ${out_dir}/train/wav.scp.bak ${out_dir}/train/text.bak -rm ${out_dir}/train/wav.scp.shuf ${out_dir}/train/text.shuf diff --git a/egs/aishell/transformer/utils/text2token.py b/egs/aishell/transformer/utils/text2token.py deleted file mode 100755 index 56c39138f..000000000 --- a/egs/aishell/transformer/utils/text2token.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2017 Johns Hopkins University (Shinji Watanabe) -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - - -import argparse -import codecs -import re -import sys - -is_python2 = sys.version_info[0] == 2 - - -def exist_or_not(i, match_pos): - start_pos = None - end_pos = None - for pos in match_pos: - if pos[0] <= i < pos[1]: - start_pos = pos[0] - end_pos = pos[1] - break - - return start_pos, end_pos - - -def get_parser(): - parser = argparse.ArgumentParser( - description="convert raw text to tokenized text", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "--nchar", - "-n", - default=1, - type=int, - help="number of characters to split, i.e., \ - aabb -> a a b b with -n 1 and aa bb with -n 2", - ) - parser.add_argument( - "--skip-ncols", "-s", default=0, type=int, help="skip first n columns" - ) - parser.add_argument("--space", default="", type=str, help="space symbol") - parser.add_argument( - "--non-lang-syms", - "-l", - default=None, - type=str, - help="list of non-linguistic symobles, e.g., etc.", - ) - parser.add_argument("text", type=str, default=False, nargs="?", help="input text") - parser.add_argument( - "--trans_type", - "-t", - type=str, - default="char", - choices=["char", "phn"], - help="""Transcript type. char/phn. e.g., for TIMIT FADG0_SI1279 - - If trans_type is char, - read from SI1279.WRD file -> "bricks are an alternative" - Else if trans_type is phn, - read from SI1279.PHN file -> "sil b r ih sil k s aa r er n aa l - sil t er n ih sil t ih v sil" """, - ) - return parser - - -def main(): - parser = get_parser() - args = parser.parse_args() - - rs = [] - if args.non_lang_syms is not None: - with codecs.open(args.non_lang_syms, "r", encoding="utf-8") as f: - nls = [x.rstrip() for x in f.readlines()] - rs = [re.compile(re.escape(x)) for x in nls] - - if args.text: - f = codecs.open(args.text, encoding="utf-8") - else: - f = codecs.getreader("utf-8")(sys.stdin if is_python2 else sys.stdin.buffer) - - sys.stdout = codecs.getwriter("utf-8")( - sys.stdout if is_python2 else sys.stdout.buffer - ) - line = f.readline() - n = args.nchar - while line: - x = line.split() - print(" ".join(x[: args.skip_ncols]), end=" ") - a = " ".join(x[args.skip_ncols :]) - - # get all matched positions - match_pos = [] - for r in rs: - i = 0 - while i >= 0: - m = r.search(a, i) - if m: - match_pos.append([m.start(), m.end()]) - i = m.end() - else: - break - - if args.trans_type == "phn": - a = a.split(" ") - else: - if len(match_pos) > 0: - chars = [] - i = 0 - while i < len(a): - start_pos, end_pos = exist_or_not(i, match_pos) - if start_pos is not None: - chars.append(a[start_pos:end_pos]) - i = end_pos - else: - chars.append(a[i]) - i += 1 - a = chars - - a = [a[j : j + n] for j in range(0, len(a), n)] - - a_flat = [] - for z in a: - a_flat.append("".join(z)) - - a_chars = [z.replace(" ", args.space) for z in a_flat] - if args.trans_type == "phn": - a_chars = [z.replace("sil", args.space) for z in a_chars] - print(" ".join(a_chars)) - line = f.readline() - - -if __name__ == "__main__": - main() diff --git a/egs/aishell/transformer/utils/text_tokenize.py b/egs/aishell/transformer/utils/text_tokenize.py deleted file mode 100755 index 962ea11bc..000000000 --- a/egs/aishell/transformer/utils/text_tokenize.py +++ /dev/null @@ -1,106 +0,0 @@ -import re -import argparse - - -def load_dict(seg_file): - seg_dict = {} - with open(seg_file, 'r') as infile: - for line in infile: - s = line.strip().split() - key = s[0] - value = s[1:] - seg_dict[key] = " ".join(value) - return seg_dict - - -def forward_segment(text, dic): - word_list = [] - i = 0 - while i < len(text): - longest_word = text[i] - for j in range(i + 1, len(text) + 1): - word = text[i:j] - if word in dic: - if len(word) > len(longest_word): - longest_word = word - word_list.append(longest_word) - i += len(longest_word) - return word_list - - -def tokenize(txt, - seg_dict): - out_txt = "" - pattern = re.compile(r"([\u4E00-\u9FA5A-Za-z0-9])") - for word in txt: - if pattern.match(word): - if word in seg_dict: - out_txt += seg_dict[word] + " " - else: - out_txt += "" + " " - else: - continue - return out_txt.strip() - - -def get_parser(): - parser = argparse.ArgumentParser( - description="text tokenize", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "--text-file", - "-t", - default=False, - required=True, - type=str, - help="input text", - ) - parser.add_argument( - "--seg-file", - "-s", - default=False, - required=True, - type=str, - help="seg file", - ) - parser.add_argument( - "--txt-index", - "-i", - default=1, - required=True, - type=int, - help="txt index", - ) - parser.add_argument( - "--output-dir", - "-o", - default=False, - required=True, - type=str, - help="output dir", - ) - return parser - - -def main(): - parser = get_parser() - args = parser.parse_args() - - txt_writer = open("{}/text.{}.txt".format(args.output_dir, args.txt_index), 'w') - shape_writer = open("{}/len.{}".format(args.output_dir, args.txt_index), 'w') - seg_dict = load_dict(args.seg_file) - with open(args.text_file, 'r') as infile: - for line in infile: - s = line.strip().split() - text_id = s[0] - text_list = forward_segment("".join(s[1:]).lower(), seg_dict) - text = tokenize(text_list, seg_dict) - lens = len(text.strip().split()) - txt_writer.write(text_id + " " + text + '\n') - shape_writer.write(text_id + " " + str(lens) + '\n') - - -if __name__ == '__main__': - main() - diff --git a/egs/aishell/transformer/utils/text_tokenize.sh b/egs/aishell/transformer/utils/text_tokenize.sh deleted file mode 100755 index 6b74fef80..000000000 --- a/egs/aishell/transformer/utils/text_tokenize.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - - -# Begin configuration section. -nj=32 -cmd=utils/run.pl - -echo "$0 $@" - -. utils/parse_options.sh || exit 1; - -# tokenize configuration -text_dir=$1 -seg_file=$2 -logdir=$3 -output_dir=$4 - -txt_dir=${output_dir}/txt; mkdir -p ${output_dir}/txt -mkdir -p ${logdir} - -$cmd JOB=1:$nj $logdir/text_tokenize.JOB.log \ - python utils/text_tokenize.py -t ${text_dir}/txt/text.JOB.txt \ - -s ${seg_file} -i JOB -o ${txt_dir} \ - || exit 1; - -# concatenate the text files together. -for n in $(seq $nj); do - cat ${txt_dir}/text.$n.txt || exit 1 -done > ${output_dir}/text || exit 1 - -for n in $(seq $nj); do - cat ${txt_dir}/len.$n || exit 1 -done > ${output_dir}/text_shape || exit 1 - -echo "$0: Succeeded text tokenize" diff --git a/egs/aishell/transformer/utils/textnorm_zh.py b/egs/aishell/transformer/utils/textnorm_zh.py deleted file mode 100755 index 79feb83fd..000000000 --- a/egs/aishell/transformer/utils/textnorm_zh.py +++ /dev/null @@ -1,834 +0,0 @@ -#!/usr/bin/env python3 -# coding=utf-8 - -# Authors: -# 2019.5 Zhiyang Zhou (https://github.com/Joee1995/chn_text_norm.git) -# 2019.9 Jiayu DU -# -# requirements: -# - python 3.X -# notes: python 2.X WILL fail or produce misleading results - -import sys, os, argparse, codecs, string, re - -# ================================================================================ # -# basic constant -# ================================================================================ # -CHINESE_DIGIS = u'零一二三四五六七八九' -BIG_CHINESE_DIGIS_SIMPLIFIED = u'零壹贰叁肆伍陆柒捌玖' -BIG_CHINESE_DIGIS_TRADITIONAL = u'零壹貳參肆伍陸柒捌玖' -SMALLER_BIG_CHINESE_UNITS_SIMPLIFIED = u'十百千万' -SMALLER_BIG_CHINESE_UNITS_TRADITIONAL = u'拾佰仟萬' -LARGER_CHINESE_NUMERING_UNITS_SIMPLIFIED = u'亿兆京垓秭穰沟涧正载' -LARGER_CHINESE_NUMERING_UNITS_TRADITIONAL = u'億兆京垓秭穰溝澗正載' -SMALLER_CHINESE_NUMERING_UNITS_SIMPLIFIED = u'十百千万' -SMALLER_CHINESE_NUMERING_UNITS_TRADITIONAL = u'拾佰仟萬' - -ZERO_ALT = u'〇' -ONE_ALT = u'幺' -TWO_ALTS = [u'两', u'兩'] - -POSITIVE = [u'正', u'正'] -NEGATIVE = [u'负', u'負'] -POINT = [u'点', u'點'] -# PLUS = [u'加', u'加'] -# SIL = [u'杠', u'槓'] - -FILLER_CHARS = ['呃', '啊'] -ER_WHITELIST = '(儿女|儿子|儿孙|女儿|儿媳|妻儿|' \ - '胎儿|婴儿|新生儿|婴幼儿|幼儿|少儿|小儿|儿歌|儿童|儿科|托儿所|孤儿|' \ - '儿戏|儿化|台儿庄|鹿儿岛|正儿八经|吊儿郎当|生儿育女|托儿带女|养儿防老|痴儿呆女|' \ - '佳儿佳妇|儿怜兽扰|儿无常父|儿不嫌母丑|儿行千里母担忧|儿大不由爷|苏乞儿)' - -# 中文数字系统类型 -NUMBERING_TYPES = ['low', 'mid', 'high'] - -CURRENCY_NAMES = '(人民币|美元|日元|英镑|欧元|马克|法郎|加拿大元|澳元|港币|先令|芬兰马克|爱尔兰镑|' \ - '里拉|荷兰盾|埃斯库多|比塞塔|印尼盾|林吉特|新西兰元|比索|卢布|新加坡元|韩元|泰铢)' -CURRENCY_UNITS = '((亿|千万|百万|万|千|百)|(亿|千万|百万|万|千|百|)元|(亿|千万|百万|万|千|百|)块|角|毛|分)' -COM_QUANTIFIERS = '(匹|张|座|回|场|尾|条|个|首|阙|阵|网|炮|顶|丘|棵|只|支|袭|辆|挑|担|颗|壳|窠|曲|墙|群|腔|' \ - '砣|座|客|贯|扎|捆|刀|令|打|手|罗|坡|山|岭|江|溪|钟|队|单|双|对|出|口|头|脚|板|跳|枝|件|贴|' \ - '针|线|管|名|位|身|堂|课|本|页|家|户|层|丝|毫|厘|分|钱|两|斤|担|铢|石|钧|锱|忽|(千|毫|微)克|' \ - '毫|厘|分|寸|尺|丈|里|寻|常|铺|程|(千|分|厘|毫|微)米|撮|勺|合|升|斗|石|盘|碗|碟|叠|桶|笼|盆|' \ - '盒|杯|钟|斛|锅|簋|篮|盘|桶|罐|瓶|壶|卮|盏|箩|箱|煲|啖|袋|钵|年|月|日|季|刻|时|周|天|秒|分|旬|' \ - '纪|岁|世|更|夜|春|夏|秋|冬|代|伏|辈|丸|泡|粒|颗|幢|堆|条|根|支|道|面|片|张|颗|块)' - -# punctuation information are based on Zhon project (https://github.com/tsroten/zhon.git) -CHINESE_PUNC_STOP = '!?。。' -CHINESE_PUNC_NON_STOP = '"#$%&'()*+,-/:;<=>@[\]^_`{|}~⦅⦆「」、、〃》「」『』【】〔〕〖〗〘〙〚〛〜〝〞〟〰〾〿–—‘’‛“”„‟…‧﹏' -CHINESE_PUNC_LIST = CHINESE_PUNC_STOP + CHINESE_PUNC_NON_STOP - -# ================================================================================ # -# basic class -# ================================================================================ # -class ChineseChar(object): - """ - 中文字符 - 每个字符对应简体和繁体, - e.g. 简体 = '负', 繁体 = '負' - 转换时可转换为简体或繁体 - """ - - def __init__(self, simplified, traditional): - self.simplified = simplified - self.traditional = traditional - #self.__repr__ = self.__str__ - - def __str__(self): - return self.simplified or self.traditional or None - - def __repr__(self): - return self.__str__() - - -class ChineseNumberUnit(ChineseChar): - """ - 中文数字/数位字符 - 每个字符除繁简体外还有一个额外的大写字符 - e.g. '陆' 和 '陸' - """ - - def __init__(self, power, simplified, traditional, big_s, big_t): - super(ChineseNumberUnit, self).__init__(simplified, traditional) - self.power = power - self.big_s = big_s - self.big_t = big_t - - def __str__(self): - return '10^{}'.format(self.power) - - @classmethod - def create(cls, index, value, numbering_type=NUMBERING_TYPES[1], small_unit=False): - - if small_unit: - return ChineseNumberUnit(power=index + 1, - simplified=value[0], traditional=value[1], big_s=value[1], big_t=value[1]) - elif numbering_type == NUMBERING_TYPES[0]: - return ChineseNumberUnit(power=index + 8, - simplified=value[0], traditional=value[1], big_s=value[0], big_t=value[1]) - elif numbering_type == NUMBERING_TYPES[1]: - return ChineseNumberUnit(power=(index + 2) * 4, - simplified=value[0], traditional=value[1], big_s=value[0], big_t=value[1]) - elif numbering_type == NUMBERING_TYPES[2]: - return ChineseNumberUnit(power=pow(2, index + 3), - simplified=value[0], traditional=value[1], big_s=value[0], big_t=value[1]) - else: - raise ValueError( - 'Counting type should be in {0} ({1} provided).'.format(NUMBERING_TYPES, numbering_type)) - - -class ChineseNumberDigit(ChineseChar): - """ - 中文数字字符 - """ - - def __init__(self, value, simplified, traditional, big_s, big_t, alt_s=None, alt_t=None): - super(ChineseNumberDigit, self).__init__(simplified, traditional) - self.value = value - self.big_s = big_s - self.big_t = big_t - self.alt_s = alt_s - self.alt_t = alt_t - - def __str__(self): - return str(self.value) - - @classmethod - def create(cls, i, v): - return ChineseNumberDigit(i, v[0], v[1], v[2], v[3]) - - -class ChineseMath(ChineseChar): - """ - 中文数位字符 - """ - - def __init__(self, simplified, traditional, symbol, expression=None): - super(ChineseMath, self).__init__(simplified, traditional) - self.symbol = symbol - self.expression = expression - self.big_s = simplified - self.big_t = traditional - - -CC, CNU, CND, CM = ChineseChar, ChineseNumberUnit, ChineseNumberDigit, ChineseMath - - -class NumberSystem(object): - """ - 中文数字系统 - """ - pass - - -class MathSymbol(object): - """ - 用于中文数字系统的数学符号 (繁/简体), e.g. - positive = ['正', '正'] - negative = ['负', '負'] - point = ['点', '點'] - """ - - def __init__(self, positive, negative, point): - self.positive = positive - self.negative = negative - self.point = point - - def __iter__(self): - for v in self.__dict__.values(): - yield v - - -# class OtherSymbol(object): -# """ -# 其他符号 -# """ -# -# def __init__(self, sil): -# self.sil = sil -# -# def __iter__(self): -# for v in self.__dict__.values(): -# yield v - - -# ================================================================================ # -# basic utils -# ================================================================================ # -def create_system(numbering_type=NUMBERING_TYPES[1]): - """ - 根据数字系统类型返回创建相应的数字系统,默认为 mid - NUMBERING_TYPES = ['low', 'mid', 'high']: 中文数字系统类型 - low: '兆' = '亿' * '十' = $10^{9}$, '京' = '兆' * '十', etc. - mid: '兆' = '亿' * '万' = $10^{12}$, '京' = '兆' * '万', etc. - high: '兆' = '亿' * '亿' = $10^{16}$, '京' = '兆' * '兆', etc. - 返回对应的数字系统 - """ - - # chinese number units of '亿' and larger - all_larger_units = zip( - LARGER_CHINESE_NUMERING_UNITS_SIMPLIFIED, LARGER_CHINESE_NUMERING_UNITS_TRADITIONAL) - larger_units = [CNU.create(i, v, numbering_type, False) - for i, v in enumerate(all_larger_units)] - # chinese number units of '十, 百, 千, 万' - all_smaller_units = zip( - SMALLER_CHINESE_NUMERING_UNITS_SIMPLIFIED, SMALLER_CHINESE_NUMERING_UNITS_TRADITIONAL) - smaller_units = [CNU.create(i, v, small_unit=True) - for i, v in enumerate(all_smaller_units)] - # digis - chinese_digis = zip(CHINESE_DIGIS, CHINESE_DIGIS, - BIG_CHINESE_DIGIS_SIMPLIFIED, BIG_CHINESE_DIGIS_TRADITIONAL) - digits = [CND.create(i, v) for i, v in enumerate(chinese_digis)] - digits[0].alt_s, digits[0].alt_t = ZERO_ALT, ZERO_ALT - digits[1].alt_s, digits[1].alt_t = ONE_ALT, ONE_ALT - digits[2].alt_s, digits[2].alt_t = TWO_ALTS[0], TWO_ALTS[1] - - # symbols - positive_cn = CM(POSITIVE[0], POSITIVE[1], '+', lambda x: x) - negative_cn = CM(NEGATIVE[0], NEGATIVE[1], '-', lambda x: -x) - point_cn = CM(POINT[0], POINT[1], '.', lambda x, - y: float(str(x) + '.' + str(y))) - # sil_cn = CM(SIL[0], SIL[1], '-', lambda x, y: float(str(x) + '-' + str(y))) - system = NumberSystem() - system.units = smaller_units + larger_units - system.digits = digits - system.math = MathSymbol(positive_cn, negative_cn, point_cn) - # system.symbols = OtherSymbol(sil_cn) - return system - - -def chn2num(chinese_string, numbering_type=NUMBERING_TYPES[1]): - - def get_symbol(char, system): - for u in system.units: - if char in [u.traditional, u.simplified, u.big_s, u.big_t]: - return u - for d in system.digits: - if char in [d.traditional, d.simplified, d.big_s, d.big_t, d.alt_s, d.alt_t]: - return d - for m in system.math: - if char in [m.traditional, m.simplified]: - return m - - def string2symbols(chinese_string, system): - int_string, dec_string = chinese_string, '' - for p in [system.math.point.simplified, system.math.point.traditional]: - if p in chinese_string: - int_string, dec_string = chinese_string.split(p) - break - return [get_symbol(c, system) for c in int_string], \ - [get_symbol(c, system) for c in dec_string] - - def correct_symbols(integer_symbols, system): - """ - 一百八 to 一百八十 - 一亿一千三百万 to 一亿 一千万 三百万 - """ - - if integer_symbols and isinstance(integer_symbols[0], CNU): - if integer_symbols[0].power == 1: - integer_symbols = [system.digits[1]] + integer_symbols - - if len(integer_symbols) > 1: - if isinstance(integer_symbols[-1], CND) and isinstance(integer_symbols[-2], CNU): - integer_symbols.append( - CNU(integer_symbols[-2].power - 1, None, None, None, None)) - - result = [] - unit_count = 0 - for s in integer_symbols: - if isinstance(s, CND): - result.append(s) - unit_count = 0 - elif isinstance(s, CNU): - current_unit = CNU(s.power, None, None, None, None) - unit_count += 1 - - if unit_count == 1: - result.append(current_unit) - elif unit_count > 1: - for i in range(len(result)): - if isinstance(result[-i - 1], CNU) and result[-i - 1].power < current_unit.power: - result[-i - 1] = CNU(result[-i - 1].power + - current_unit.power, None, None, None, None) - return result - - def compute_value(integer_symbols): - """ - Compute the value. - When current unit is larger than previous unit, current unit * all previous units will be used as all previous units. - e.g. '两千万' = 2000 * 10000 not 2000 + 10000 - """ - value = [0] - last_power = 0 - for s in integer_symbols: - if isinstance(s, CND): - value[-1] = s.value - elif isinstance(s, CNU): - value[-1] *= pow(10, s.power) - if s.power > last_power: - value[:-1] = list(map(lambda v: v * - pow(10, s.power), value[:-1])) - last_power = s.power - value.append(0) - return sum(value) - - system = create_system(numbering_type) - int_part, dec_part = string2symbols(chinese_string, system) - int_part = correct_symbols(int_part, system) - int_str = str(compute_value(int_part)) - dec_str = ''.join([str(d.value) for d in dec_part]) - if dec_part: - return '{0}.{1}'.format(int_str, dec_str) - else: - return int_str - - -def num2chn(number_string, numbering_type=NUMBERING_TYPES[1], big=False, - traditional=False, alt_zero=False, alt_one=False, alt_two=True, - use_zeros=True, use_units=True): - - def get_value(value_string, use_zeros=True): - - striped_string = value_string.lstrip('0') - - # record nothing if all zeros - if not striped_string: - return [] - - # record one digits - elif len(striped_string) == 1: - if use_zeros and len(value_string) != len(striped_string): - return [system.digits[0], system.digits[int(striped_string)]] - else: - return [system.digits[int(striped_string)]] - - # recursively record multiple digits - else: - result_unit = next(u for u in reversed( - system.units) if u.power < len(striped_string)) - result_string = value_string[:-result_unit.power] - return get_value(result_string) + [result_unit] + get_value(striped_string[-result_unit.power:]) - - system = create_system(numbering_type) - - int_dec = number_string.split('.') - if len(int_dec) == 1: - int_string = int_dec[0] - dec_string = "" - elif len(int_dec) == 2: - int_string = int_dec[0] - dec_string = int_dec[1] - else: - raise ValueError( - "invalid input num string with more than one dot: {}".format(number_string)) - - if use_units and len(int_string) > 1: - result_symbols = get_value(int_string) - else: - result_symbols = [system.digits[int(c)] for c in int_string] - dec_symbols = [system.digits[int(c)] for c in dec_string] - if dec_string: - result_symbols += [system.math.point] + dec_symbols - - if alt_two: - liang = CND(2, system.digits[2].alt_s, system.digits[2].alt_t, - system.digits[2].big_s, system.digits[2].big_t) - for i, v in enumerate(result_symbols): - if isinstance(v, CND) and v.value == 2: - next_symbol = result_symbols[i + - 1] if i < len(result_symbols) - 1 else None - previous_symbol = result_symbols[i - 1] if i > 0 else None - if isinstance(next_symbol, CNU) and isinstance(previous_symbol, (CNU, type(None))): - if next_symbol.power != 1 and ((previous_symbol is None) or (previous_symbol.power != 1)): - result_symbols[i] = liang - - # if big is True, '两' will not be used and `alt_two` has no impact on output - if big: - attr_name = 'big_' - if traditional: - attr_name += 't' - else: - attr_name += 's' - else: - if traditional: - attr_name = 'traditional' - else: - attr_name = 'simplified' - - result = ''.join([getattr(s, attr_name) for s in result_symbols]) - - # if not use_zeros: - # result = result.strip(getattr(system.digits[0], attr_name)) - - if alt_zero: - result = result.replace( - getattr(system.digits[0], attr_name), system.digits[0].alt_s) - - if alt_one: - result = result.replace( - getattr(system.digits[1], attr_name), system.digits[1].alt_s) - - for i, p in enumerate(POINT): - if result.startswith(p): - return CHINESE_DIGIS[0] + result - - # ^10, 11, .., 19 - if len(result) >= 2 and result[1] in [SMALLER_CHINESE_NUMERING_UNITS_SIMPLIFIED[0], - SMALLER_CHINESE_NUMERING_UNITS_TRADITIONAL[0]] and \ - result[0] in [CHINESE_DIGIS[1], BIG_CHINESE_DIGIS_SIMPLIFIED[1], BIG_CHINESE_DIGIS_TRADITIONAL[1]]: - result = result[1:] - - return result - - -# ================================================================================ # -# different types of rewriters -# ================================================================================ # -class Cardinal: - """ - CARDINAL类 - """ - - def __init__(self, cardinal=None, chntext=None): - self.cardinal = cardinal - self.chntext = chntext - - def chntext2cardinal(self): - return chn2num(self.chntext) - - def cardinal2chntext(self): - return num2chn(self.cardinal) - -class Digit: - """ - DIGIT类 - """ - - def __init__(self, digit=None, chntext=None): - self.digit = digit - self.chntext = chntext - - # def chntext2digit(self): - # return chn2num(self.chntext) - - def digit2chntext(self): - return num2chn(self.digit, alt_two=False, use_units=False) - - -class TelePhone: - """ - TELEPHONE类 - """ - - def __init__(self, telephone=None, raw_chntext=None, chntext=None): - self.telephone = telephone - self.raw_chntext = raw_chntext - self.chntext = chntext - - # def chntext2telephone(self): - # sil_parts = self.raw_chntext.split('') - # self.telephone = '-'.join([ - # str(chn2num(p)) for p in sil_parts - # ]) - # return self.telephone - - def telephone2chntext(self, fixed=False): - - if fixed: - sil_parts = self.telephone.split('-') - self.raw_chntext = ''.join([ - num2chn(part, alt_two=False, use_units=False) for part in sil_parts - ]) - self.chntext = self.raw_chntext.replace('', '') - else: - sp_parts = self.telephone.strip('+').split() - self.raw_chntext = ''.join([ - num2chn(part, alt_two=False, use_units=False) for part in sp_parts - ]) - self.chntext = self.raw_chntext.replace('', '') - return self.chntext - - -class Fraction: - """ - FRACTION类 - """ - - def __init__(self, fraction=None, chntext=None): - self.fraction = fraction - self.chntext = chntext - - def chntext2fraction(self): - denominator, numerator = self.chntext.split('分之') - return chn2num(numerator) + '/' + chn2num(denominator) - - def fraction2chntext(self): - numerator, denominator = self.fraction.split('/') - return num2chn(denominator) + '分之' + num2chn(numerator) - - -class Date: - """ - DATE类 - """ - - def __init__(self, date=None, chntext=None): - self.date = date - self.chntext = chntext - - # def chntext2date(self): - # chntext = self.chntext - # try: - # year, other = chntext.strip().split('年', maxsplit=1) - # year = Digit(chntext=year).digit2chntext() + '年' - # except ValueError: - # other = chntext - # year = '' - # if other: - # try: - # month, day = other.strip().split('月', maxsplit=1) - # month = Cardinal(chntext=month).chntext2cardinal() + '月' - # except ValueError: - # day = chntext - # month = '' - # if day: - # day = Cardinal(chntext=day[:-1]).chntext2cardinal() + day[-1] - # else: - # month = '' - # day = '' - # date = year + month + day - # self.date = date - # return self.date - - def date2chntext(self): - date = self.date - try: - year, other = date.strip().split('年', 1) - year = Digit(digit=year).digit2chntext() + '年' - except ValueError: - other = date - year = '' - if other: - try: - month, day = other.strip().split('月', 1) - month = Cardinal(cardinal=month).cardinal2chntext() + '月' - except ValueError: - day = date - month = '' - if day: - day = Cardinal(cardinal=day[:-1]).cardinal2chntext() + day[-1] - else: - month = '' - day = '' - chntext = year + month + day - self.chntext = chntext - return self.chntext - - -class Money: - """ - MONEY类 - """ - - def __init__(self, money=None, chntext=None): - self.money = money - self.chntext = chntext - - # def chntext2money(self): - # return self.money - - def money2chntext(self): - money = self.money - pattern = re.compile(r'(\d+(\.\d+)?)') - matchers = pattern.findall(money) - if matchers: - for matcher in matchers: - money = money.replace(matcher[0], Cardinal(cardinal=matcher[0]).cardinal2chntext()) - self.chntext = money - return self.chntext - - -class Percentage: - """ - PERCENTAGE类 - """ - - def __init__(self, percentage=None, chntext=None): - self.percentage = percentage - self.chntext = chntext - - def chntext2percentage(self): - return chn2num(self.chntext.strip().strip('百分之')) + '%' - - def percentage2chntext(self): - return '百分之' + num2chn(self.percentage.strip().strip('%')) - - -def remove_erhua(text, er_whitelist): - """ - 去除儿化音词中的儿: - 他女儿在那边儿 -> 他女儿在那边 - """ - - er_pattern = re.compile(er_whitelist) - new_str='' - while re.search('儿',text): - a = re.search('儿',text).span() - remove_er_flag = 0 - - if er_pattern.search(text): - b = er_pattern.search(text).span() - if b[0] <= a[0]: - remove_er_flag = 1 - - if remove_er_flag == 0 : - new_str = new_str + text[0:a[0]] - text = text[a[1]:] - else: - new_str = new_str + text[0:b[1]] - text = text[b[1]:] - - text = new_str + text - return text - -# ================================================================================ # -# NSW Normalizer -# ================================================================================ # -class NSWNormalizer: - def __init__(self, raw_text): - self.raw_text = '^' + raw_text + '$' - self.norm_text = '' - - def _particular(self): - text = self.norm_text - pattern = re.compile(r"(([a-zA-Z]+)二([a-zA-Z]+))") - matchers = pattern.findall(text) - if matchers: - # print('particular') - for matcher in matchers: - text = text.replace(matcher[0], matcher[1]+'2'+matcher[2], 1) - self.norm_text = text - return self.norm_text - - def normalize(self): - text = self.raw_text - - # 规范化日期 - pattern = re.compile(r"\D+((([089]\d|(19|20)\d{2})年)?(\d{1,2}月(\d{1,2}[日号])?)?)") - matchers = pattern.findall(text) - if matchers: - #print('date') - for matcher in matchers: - text = text.replace(matcher[0], Date(date=matcher[0]).date2chntext(), 1) - - # 规范化金钱 - pattern = re.compile(r"\D+((\d+(\.\d+)?)[多余几]?" + CURRENCY_UNITS + r"(\d" + CURRENCY_UNITS + r"?)?)") - matchers = pattern.findall(text) - if matchers: - #print('money') - for matcher in matchers: - text = text.replace(matcher[0], Money(money=matcher[0]).money2chntext(), 1) - - # 规范化固话/手机号码 - # 手机 - # http://www.jihaoba.com/news/show/13680 - # 移动:139、138、137、136、135、134、159、158、157、150、151、152、188、187、182、183、184、178、198 - # 联通:130、131、132、156、155、186、185、176 - # 电信:133、153、189、180、181、177 - pattern = re.compile(r"\D((\+?86 ?)?1([38]\d|5[0-35-9]|7[678]|9[89])\d{8})\D") - matchers = pattern.findall(text) - if matchers: - #print('telephone') - for matcher in matchers: - text = text.replace(matcher[0], TelePhone(telephone=matcher[0]).telephone2chntext(), 1) - # 固话 - pattern = re.compile(r"\D((0(10|2[1-3]|[3-9]\d{2})-?)?[1-9]\d{6,7})\D") - matchers = pattern.findall(text) - if matchers: - # print('fixed telephone') - for matcher in matchers: - text = text.replace(matcher[0], TelePhone(telephone=matcher[0]).telephone2chntext(fixed=True), 1) - - # 规范化分数 - pattern = re.compile(r"(\d+/\d+)") - matchers = pattern.findall(text) - if matchers: - #print('fraction') - for matcher in matchers: - text = text.replace(matcher, Fraction(fraction=matcher).fraction2chntext(), 1) - - # 规范化百分数 - text = text.replace('%', '%') - pattern = re.compile(r"(\d+(\.\d+)?%)") - matchers = pattern.findall(text) - if matchers: - #print('percentage') - for matcher in matchers: - text = text.replace(matcher[0], Percentage(percentage=matcher[0]).percentage2chntext(), 1) - - # 规范化纯数+量词 - pattern = re.compile(r"(\d+(\.\d+)?)[多余几]?" + COM_QUANTIFIERS) - matchers = pattern.findall(text) - if matchers: - #print('cardinal+quantifier') - for matcher in matchers: - text = text.replace(matcher[0], Cardinal(cardinal=matcher[0]).cardinal2chntext(), 1) - - # 规范化数字编号 - pattern = re.compile(r"(\d{4,32})") - matchers = pattern.findall(text) - if matchers: - #print('digit') - for matcher in matchers: - text = text.replace(matcher, Digit(digit=matcher).digit2chntext(), 1) - - # 规范化纯数 - pattern = re.compile(r"(\d+(\.\d+)?)") - matchers = pattern.findall(text) - if matchers: - #print('cardinal') - for matcher in matchers: - text = text.replace(matcher[0], Cardinal(cardinal=matcher[0]).cardinal2chntext(), 1) - - self.norm_text = text - self._particular() - - return self.norm_text.lstrip('^').rstrip('$') - - -def nsw_test_case(raw_text): - print('I:' + raw_text) - print('O:' + NSWNormalizer(raw_text).normalize()) - print('') - - -def nsw_test(): - nsw_test_case('固话:0595-23865596或23880880。') - nsw_test_case('固话:0595-23865596或23880880。') - nsw_test_case('手机:+86 19859213959或15659451527。') - nsw_test_case('分数:32477/76391。') - nsw_test_case('百分数:80.03%。') - nsw_test_case('编号:31520181154418。') - nsw_test_case('纯数:2983.07克或12345.60米。') - nsw_test_case('日期:1999年2月20日或09年3月15号。') - nsw_test_case('金钱:12块5,34.5元,20.1万') - nsw_test_case('特殊:O2O或B2C。') - nsw_test_case('3456万吨') - nsw_test_case('2938个') - nsw_test_case('938') - nsw_test_case('今天吃了115个小笼包231个馒头') - nsw_test_case('有62%的概率') - - -if __name__ == '__main__': - #nsw_test() - - p = argparse.ArgumentParser() - p.add_argument('ifile', help='input filename, assume utf-8 encoding') - p.add_argument('ofile', help='output filename') - p.add_argument('--to_upper', action='store_true', help='convert to upper case') - p.add_argument('--to_lower', action='store_true', help='convert to lower case') - p.add_argument('--has_key', action='store_true', help="input text has Kaldi's key as first field.") - p.add_argument('--remove_fillers', type=bool, default=True, help='remove filler chars such as "呃, 啊"') - p.add_argument('--remove_erhua', type=bool, default=True, help='remove erhua chars such as "这儿"') - p.add_argument('--log_interval', type=int, default=10000, help='log interval in number of processed lines') - args = p.parse_args() - - ifile = codecs.open(args.ifile, 'r', 'utf8') - ofile = codecs.open(args.ofile, 'w+', 'utf8') - - n = 0 - for l in ifile: - key = '' - text = '' - if args.has_key: - cols = l.split(maxsplit=1) - key = cols[0] - if len(cols) == 2: - text = cols[1].strip() - else: - text = '' - else: - text = l.strip() - - # cases - if args.to_upper and args.to_lower: - sys.stderr.write('text norm: to_upper OR to_lower?') - exit(1) - if args.to_upper: - text = text.upper() - if args.to_lower: - text = text.lower() - - # Filler chars removal - if args.remove_fillers: - for ch in FILLER_CHARS: - text = text.replace(ch, '') - - if args.remove_erhua: - text = remove_erhua(text, ER_WHITELIST) - - # NSW(Non-Standard-Word) normalization - text = NSWNormalizer(text).normalize() - - # Punctuations removal - old_chars = CHINESE_PUNC_LIST + string.punctuation # includes all CN and EN punctuations - new_chars = ' ' * len(old_chars) - del_chars = '' - text = text.translate(str.maketrans(old_chars, new_chars, del_chars)) - - # - if args.has_key: - ofile.write(key + '\t' + text + '\n') - else: - ofile.write(text + '\n') - - n += 1 - if n % args.log_interval == 0: - sys.stderr.write("text norm: {} lines done.\n".format(n)) - - sys.stderr.write("text norm: {} lines done in total.\n".format(n)) - - ifile.close() - ofile.close() diff --git a/egs/aishell2/conformer/conf/decode_asr_transformer.yaml b/egs/aishell2/conformer/conf/decode_asr_transformer.yaml deleted file mode 100644 index a147fa79d..000000000 --- a/egs/aishell2/conformer/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/aishell2/conformer/conf/train_asr_conformer.yaml b/egs/aishell2/conformer/conf/train_asr_conformer.yaml deleted file mode 100644 index 8183378fb..000000000 --- a/egs/aishell2/conformer/conf/train_asr_conformer.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# network architecture -# encoder related -encoder: conformer -encoder_conf: - output_size: 256 # dimension of attention - attention_heads: 4 - linear_units: 2048 # the number of units of position-wise feed forward - num_blocks: 12 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - macaron_style: true - use_cnn_module: true - cnn_module_kernel: 15 - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 2 -grad_clip: 5 -patience: none -max_epoch: 150 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -normalize: None diff --git a/egs/aishell2/conformer/local/prepare_data.sh b/egs/aishell2/conformer/local/prepare_data.sh deleted file mode 100755 index 77791f9c1..000000000 --- a/egs/aishell2/conformer/local/prepare_data.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2018 AIShell-Foundation(Authors:Jiayu DU, Xingyu NA, Bengu WU, Hao ZHENG) -# 2018 Beijing Shell Shell Tech. Co. Ltd. (Author: Hui BU) -# Apache 2.0 - -# transform raw AISHELL-2 data to kaldi format - -. ./path.sh || exit 1; - -tmp= -dir= - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/AISHELL-2/iOS/train data/local/train data/train" - exit 1; -fi - -corpus=$1 -tmp=$2 -dir=$3 - -echo "prepare_data.sh: Preparing data in $corpus" - -mkdir -p $tmp -mkdir -p $dir - -# corpus check -if [ ! -d $corpus ] || [ ! -f $corpus/wav.scp ] || [ ! -f $corpus/trans.txt ]; then - echo "Error: $0 requires wav.scp and trans.txt under $corpus directory." - exit 1; -fi - -# validate utt-key list, IC0803W0380 is a bad utterance -awk '{print $1}' $corpus/wav.scp | grep -v 'IC0803W0380' > $tmp/wav_utt.list -awk '{print $1}' $corpus/trans.txt > $tmp/trans_utt.list -utils/filter_scp.pl -f 1 $tmp/wav_utt.list $tmp/trans_utt.list > $tmp/utt.list - -# wav.scp -awk -F'\t' -v path_prefix=$corpus '{printf("%s\t%s/%s\n",$1,path_prefix,$2)}' $corpus/wav.scp > $tmp/tmp_wav.scp -utils/filter_scp.pl -f 1 $tmp/utt.list $tmp/tmp_wav.scp | sort -k 1 | uniq > $tmp/wav.scp - -# text -utils/filter_scp.pl -f 1 $tmp/utt.list $corpus/trans.txt | sort -k 1 | uniq > $tmp/text - -# copy prepared resources from tmp_dir to target dir -mkdir -p $dir -for f in wav.scp text; do - cp $tmp/$f $dir/$f || exit 1; -done - -echo "local/prepare_data.sh succeeded" -exit 0; diff --git a/egs/aishell2/conformer/path.sh b/egs/aishell2/conformer/path.sh deleted file mode 100755 index ea3c0be2f..000000000 --- a/egs/aishell2/conformer/path.sh +++ /dev/null @@ -1,6 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PYTHONPATH=../../../:$PYTHONPATH -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell2/conformer/run.sh b/egs/aishell2/conformer/run.sh deleted file mode 100755 index 193c4a3d1..000000000 --- a/egs/aishell2/conformer/run.sh +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -dataset_type=large -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -tr_dir= -dev_tst_dir= - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev_ios -test_sets="dev_ios test_ios" - -asr_config=conf/train_asr_conformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # For training set - local/prepare_data.sh ${tr_dir} ${feats_dir}/data/local/train ${feats_dir}/data/train || exit 1; - # # For dev and test set - for x in iOS; do - local/prepare_data.sh ${dev_tst_dir}/${x}/dev ${feats_dir}/data/local/dev_${x,,} ${feats_dir}/data/dev_${x,,} || exit 1; - local/prepare_data.sh ${dev_tst_dir}/${x}/test ${feats_dir}/data/local/test_${x,,} ${feats_dir}/data/test_${x,,} || exit 1; - done - # Normalize text to capital letters - for x in train dev_ios test_ios; do - mv ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 ${feats_dir}/data/${x}/text.org) <(cut -f 2- ${feats_dir}/data/${x}/text.org \ - | tr 'A-Z' 'a-z' | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/${train_set}/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} - fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --dataset_type $dataset_type \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode asr \ - --model_name conformer \ - --dataset aishell2 \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --tag $tag -fi - - diff --git a/egs/aishell2/conformer/utils b/egs/aishell2/conformer/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/aishell2/conformer/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/aishell2/data2vec_pretrain/conf/train_pretrain_transformer.yaml b/egs/aishell2/data2vec_pretrain/conf/train_pretrain_transformer.yaml deleted file mode 100644 index 767d8bafd..000000000 --- a/egs/aishell2/data2vec_pretrain/conf/train_pretrain_transformer.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# network architecture -# encoder related -encoder: data2vec_encoder -encoder_conf: - extractor_mode: layer_norm - encoder_layerdrop: 0.05 - dropout_input: 0.0 - dropout_features: 0.0 - feature_grad_mult: 1.0 - encoder_embed_dim: 768 - - mask_prob: 0.65 - mask_length: 10 - - loss_beta: 0 - loss_scale: null - - instance_norm_target_layer: true - average_top_k_layers: 8 - - pos_conv_depth: 5 - conv_pos: 95 - - ema_decay: 0.999 - ema_end_decay: 0.9999 - ema_anneal_end_step: 30000 - ema_transformer_only: true - ema_layers_only: true - - require_same_masks: true - mask_dropout: 0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -model: data2vec - -# optimization related -accum_grad: 1 -grad_clip: 5 -patience: none -max_epoch: 1800 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - loss - - min -keep_nbest_models: 50 -unused_parameters: true - -optim: fairseq_adam -optim_conf: - lr: 0.0005 - adam_betas: [0.9,0.98] - adam_eps: 1.0e-06 - weight_decay: 0.01 - -scheduler: tri_stage -scheduler_conf: - phase_ratio: [0.03,0.9,0.07] - -# for dataset -dataset_conf: - batch_mode: clipping - data_names: speech - data_types: sound - shuffle: true - shuffle_conf: - shuffle_size: 12800 - sort_size: 12800 - batch_conf: - batch_type: token - batch_size: 64000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/aishell2/data2vec_pretrain/local/prepare_data.sh b/egs/aishell2/data2vec_pretrain/local/prepare_data.sh deleted file mode 100755 index ce6ee1909..000000000 --- a/egs/aishell2/data2vec_pretrain/local/prepare_data.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2018 AIShell-Foundation(Authors:Jiayu DU, Xingyu NA, Bengu WU, Hao ZHENG) -# 2018 Beijing Shell Shell Tech. Co. Ltd. (Author: Hui BU) -# Apache 2.0 - -# transform raw AISHELL-2 data to kaldi format - -. ./path.sh || exit 1; - -tmp= -dir= - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/AISHELL-2/iOS/train data/local/train data/train" - exit 1; -fi - -corpus=$1 -tmp=$2 -dir=$3 - -echo "prepare_data.sh: Preparing data in $corpus" - -mkdir -p $tmp -mkdir -p $dir - -# corpus check -if [ ! -d $corpus ] || [ ! -f $corpus/wav.scp ] || [ ! -f $corpus/trans.txt ]; then - echo "Error: $0 requires wav.scp and trans.txt under $corpus directory." - exit 1; -fi - -# validate utt-key list, IC0803W0380 is a bad utterance -awk '{print $1}' $corpus/wav.scp | grep -v 'IC0803W0380' > $tmp/wav_utt.list -awk '{print $1}' $corpus/trans.txt > $tmp/trans_utt.list -tools/filter_scp.pl -f 1 $tmp/wav_utt.list $tmp/trans_utt.list > $tmp/utt.list - -# wav.scp -awk -F'\t' -v path_prefix=$corpus '{printf("%s\t%s/%s\n",$1,path_prefix,$2)}' $corpus/wav.scp > $tmp/tmp_wav.scp -tools/filter_scp.pl -f 1 $tmp/utt.list $tmp/tmp_wav.scp | sort -k 1 | uniq > $tmp/wav.scp - -# text -tools/filter_scp.pl -f 1 $tmp/utt.list $corpus/trans.txt | sort -k 1 | uniq > $tmp/text - -# copy prepared resources from tmp_dir to target dir -mkdir -p $dir -for f in wav.scp text; do - cp $tmp/$f $dir/$f || exit 1; -done - -echo "local/prepare_data.sh succeeded" -exit 0; diff --git a/egs/aishell2/data2vec_pretrain/path.sh b/egs/aishell2/data2vec_pretrain/path.sh deleted file mode 100755 index ea3c0be2f..000000000 --- a/egs/aishell2/data2vec_pretrain/path.sh +++ /dev/null @@ -1,6 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PYTHONPATH=../../../:$PYTHONPATH -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell2/data2vec_pretrain/run.sh b/egs/aishell2/data2vec_pretrain/run.sh deleted file mode 100755 index 3df39af43..000000000 --- a/egs/aishell2/data2vec_pretrain/run.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 - -train_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -speed_perturb="0.9 1.0 1.1" -dataset_type=large -stage=0 -stop_stage=3 - -# feature configuration -nj=64 - -# data -tr_dir= -dev_tst_dir= - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev_ios - -asr_config=conf/train_pretrain_transformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # For training set - local/prepare_data.sh ${tr_dir} ${feats_dir}/data/local/train ${feats_dir}/data/train || exit 1; - # # For dev and test set - for x in iOS; do - local/prepare_data.sh ${dev_tst_dir}/${x}/dev ${feats_dir}/data/local/dev_${x,,} ${feats_dir}/data/dev_${x,,} || exit 1; - local/prepare_data.sh ${dev_tst_dir}/${x}/test ${feats_dir}/data/local/test_${x,,} ${feats_dir}/data/test_${x,,} || exit 1; - done - # Normalize text to capital letters - for x in train dev_ios test_ios; do - mv ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 ${feats_dir}/data/${x}/text.org) <(cut -f 2- ${feats_dir}/data/${x}/text.org \ - | tr 'A-Z' 'a-z' | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/char/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/char/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/${train_set}/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} - fi - -# Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name pretrain \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --dataset_type $dataset_type \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi \ No newline at end of file diff --git a/egs/aishell2/data2vec_pretrain/utils b/egs/aishell2/data2vec_pretrain/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/aishell2/data2vec_pretrain/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/aishell2/paraformer/conf/decode_asr_transformer.yaml b/egs/aishell2/paraformer/conf/decode_asr_transformer.yaml deleted file mode 100644 index a147fa79d..000000000 --- a/egs/aishell2/paraformer/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/aishell2/paraformer/conf/decode_asr_transformer_noctc_1best.yaml b/egs/aishell2/paraformer/conf/decode_asr_transformer_noctc_1best.yaml deleted file mode 100644 index a147fa79d..000000000 --- a/egs/aishell2/paraformer/conf/decode_asr_transformer_noctc_1best.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/aishell2/paraformer/conf/train_asr_paraformer_conformer_20e_1280_320_6d_1280_320.yaml b/egs/aishell2/paraformer/conf/train_asr_paraformer_conformer_20e_1280_320_6d_1280_320.yaml deleted file mode 100644 index 3ecf44e31..000000000 --- a/egs/aishell2/paraformer/conf/train_asr_paraformer_conformer_20e_1280_320_6d_1280_320.yaml +++ /dev/null @@ -1,109 +0,0 @@ -# network architecture -# encoder related -encoder: conformer -encoder_conf: - output_size: 320 # dimension of attention - attention_heads: 4 - linear_units: 1280 # the number of units of position-wise feed forward - num_blocks: 20 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - macaron_style: true - use_cnn_module: true - cnn_module_kernel: 15 - -# decoder related -decoder: paraformer_decoder_san -decoder_conf: - attention_heads: 4 - linear_units: 1280 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model: paraformer -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 - length_normalized_loss: false - predictor_weight: 1.0 - sampling_ratio: 0.4 - -# optimization related -accum_grad: 2 -grad_clip: 5 -patience: none -max_epoch: 150 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -predictor: cif_predictor -predictor_conf: - idim: 320 - threshold: 1.0 - l_order: 1 - r_order: 1 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -normalize: None diff --git a/egs/aishell2/paraformer/local/prepare_data.sh b/egs/aishell2/paraformer/local/prepare_data.sh deleted file mode 100755 index 77791f9c1..000000000 --- a/egs/aishell2/paraformer/local/prepare_data.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2018 AIShell-Foundation(Authors:Jiayu DU, Xingyu NA, Bengu WU, Hao ZHENG) -# 2018 Beijing Shell Shell Tech. Co. Ltd. (Author: Hui BU) -# Apache 2.0 - -# transform raw AISHELL-2 data to kaldi format - -. ./path.sh || exit 1; - -tmp= -dir= - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/AISHELL-2/iOS/train data/local/train data/train" - exit 1; -fi - -corpus=$1 -tmp=$2 -dir=$3 - -echo "prepare_data.sh: Preparing data in $corpus" - -mkdir -p $tmp -mkdir -p $dir - -# corpus check -if [ ! -d $corpus ] || [ ! -f $corpus/wav.scp ] || [ ! -f $corpus/trans.txt ]; then - echo "Error: $0 requires wav.scp and trans.txt under $corpus directory." - exit 1; -fi - -# validate utt-key list, IC0803W0380 is a bad utterance -awk '{print $1}' $corpus/wav.scp | grep -v 'IC0803W0380' > $tmp/wav_utt.list -awk '{print $1}' $corpus/trans.txt > $tmp/trans_utt.list -utils/filter_scp.pl -f 1 $tmp/wav_utt.list $tmp/trans_utt.list > $tmp/utt.list - -# wav.scp -awk -F'\t' -v path_prefix=$corpus '{printf("%s\t%s/%s\n",$1,path_prefix,$2)}' $corpus/wav.scp > $tmp/tmp_wav.scp -utils/filter_scp.pl -f 1 $tmp/utt.list $tmp/tmp_wav.scp | sort -k 1 | uniq > $tmp/wav.scp - -# text -utils/filter_scp.pl -f 1 $tmp/utt.list $corpus/trans.txt | sort -k 1 | uniq > $tmp/text - -# copy prepared resources from tmp_dir to target dir -mkdir -p $dir -for f in wav.scp text; do - cp $tmp/$f $dir/$f || exit 1; -done - -echo "local/prepare_data.sh succeeded" -exit 0; diff --git a/egs/aishell2/paraformer/path.sh b/egs/aishell2/paraformer/path.sh deleted file mode 100755 index ea3c0be2f..000000000 --- a/egs/aishell2/paraformer/path.sh +++ /dev/null @@ -1,6 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PYTHONPATH=../../../:$PYTHONPATH -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell2/paraformer/run.sh b/egs/aishell2/paraformer/run.sh deleted file mode 100755 index 4268cf638..000000000 --- a/egs/aishell2/paraformer/run.sh +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=1 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -dataset_type=large -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -tr_dir= -dev_tst_dir= - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev_ios -test_sets="dev_ios test_ios" - -asr_config=conf/train_asr_paraformer_conformer_20e_1280_320_6d_1280_320.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer_noctc_1best.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, e.g., gpuid_list=2,3, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # For training set - local/prepare_data.sh ${tr_dir} ${feats_dir}/data/local/train ${feats_dir}/data/train || exit 1; - # # For dev and test set - for x in iOS; do - local/prepare_data.sh ${dev_tst_dir}/${x}/dev ${feats_dir}/data/local/dev_${x,,} ${feats_dir}/data/dev_${x,,} || exit 1; - local/prepare_data.sh ${dev_tst_dir}/${x}/test ${feats_dir}/data/local/test_${x,,} ${feats_dir}/data/test_${x,,} || exit 1; - done - # Normalize text to capital letters - for x in train dev_ios test_ios; do - mv ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 ${feats_dir}/data/${x}/text.org) <(cut -f 2- ${feats_dir}/data/${x}/text.org \ - | tr 'A-Z' 'a-z' | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/${train_set}/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} - fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --dataset_type $dataset_type \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode paraformer \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode paraformer \ - --model_name paraformer \ - --dataset aishell2 \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --nat _nat \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell2/paraformer/utils b/egs/aishell2/paraformer/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/aishell2/paraformer/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/aishell2/paraformerbert/conf/decode_asr_transformer.yaml b/egs/aishell2/paraformerbert/conf/decode_asr_transformer.yaml deleted file mode 100644 index a147fa79d..000000000 --- a/egs/aishell2/paraformerbert/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/aishell2/paraformerbert/conf/train_asr_paraformerbert_conformer_20e_6d_1280_320.yaml b/egs/aishell2/paraformerbert/conf/train_asr_paraformerbert_conformer_20e_6d_1280_320.yaml deleted file mode 100644 index 8968d2d9e..000000000 --- a/egs/aishell2/paraformerbert/conf/train_asr_paraformerbert_conformer_20e_6d_1280_320.yaml +++ /dev/null @@ -1,112 +0,0 @@ -# network architecture -# encoder related -encoder: conformer -encoder_conf: - output_size: 320 # dimension of attention - attention_heads: 4 - linear_units: 1280 # the number of units of position-wise feed forward - num_blocks: 20 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - macaron_style: true - use_cnn_module: true - cnn_module_kernel: 15 - -# decoder related -decoder: paraformer_decoder_san -decoder_conf: - attention_heads: 4 - linear_units: 1280 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model: paraformer_bert -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - predictor_weight: 1.0 - sampling_ratio: 0.4 - embeds_id: 3 - embed_dims: 768 - embeds_loss_weight: 2.0 - -# optimization related -accum_grad: 2 -grad_clip: 5 -patience: none -max_epoch: 150 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -predictor: cif_predictor -predictor_conf: - idim: 320 - threshold: 1.0 - l_order: 1 - r_order: 1 - -dataset_conf: - data_names: speech,text,embed - data_types: sound,text,kaldi_ark - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/aishell2/paraformerbert/local/extract_embeds.sh b/egs/aishell2/paraformerbert/local/extract_embeds.sh deleted file mode 100755 index d7dd4f20b..000000000 --- a/egs/aishell2/paraformerbert/local/extract_embeds.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash - -stage=1 -stop_stage=3 - -bert_model_name="bert-base-chinese" -raw_dataset_path="../DATA" -nj=64 -model_path=${bert_model_name} - -. utils/parse_options.sh || exit 1; - -for data_set in train dev_ios;do - scp=$raw_dataset_path/data/${data_set}/text - local_scp_dir_raw=${raw_dataset_path}/data/embeds/${data_set} - local_scp_dir=$local_scp_dir_raw/split$nj - local_records_dir=$local_scp_dir_raw/ark - - mkdir -p $local_records_dir - mkdir -p $local_scp_dir - - split_scps="" - for JOB in $(seq ${nj}); do - split_scps="$split_scps $local_scp_dir/data.$JOB.text" - done - - utils/split_scp.pl $scp ${split_scps} - - - for num in {0..7};do - tmp=`expr $num \* 4` - - if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - for idx in {1..4}; do - JOB=`expr $tmp + $idx` - echo "proces jobid=$JOB" - { - beg=0 - gpu=`expr $beg + $idx` - echo ${local_scp_dir}/log.${JOB} - python utils/extract_embeds.py $local_scp_dir/data.$JOB.text ${local_records_dir}/embeds.${JOB}.ark ${local_records_dir}/embeds.${JOB}.scp ${local_records_dir}/embeds.${JOB}.shape ${gpu} ${model_path} &> ${local_scp_dir}/log.${JOB} - } & - done - wait - fi - done - - if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - for JOB in $(seq ${nj}); do - cat ${local_records_dir}/embeds.${JOB}.scp || exit 1; - done > ${local_scp_dir_raw}/embeds.scp - - for JOB in $(seq ${nj}); do - cat ${local_records_dir}/embeds.${JOB}.shape || exit 1; - done > ${local_scp_dir_raw}/embeds.shape - fi - - cp ${local_scp_dir_raw}/embeds.scp ${raw_dataset_path}/data/${data_set}/embeds.scp -done - -echo "embeds is in: ${local_scp_dir_raw}" -echo "success" \ No newline at end of file diff --git a/egs/aishell2/paraformerbert/local/prepare_data.sh b/egs/aishell2/paraformerbert/local/prepare_data.sh deleted file mode 100755 index 77791f9c1..000000000 --- a/egs/aishell2/paraformerbert/local/prepare_data.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2018 AIShell-Foundation(Authors:Jiayu DU, Xingyu NA, Bengu WU, Hao ZHENG) -# 2018 Beijing Shell Shell Tech. Co. Ltd. (Author: Hui BU) -# Apache 2.0 - -# transform raw AISHELL-2 data to kaldi format - -. ./path.sh || exit 1; - -tmp= -dir= - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/AISHELL-2/iOS/train data/local/train data/train" - exit 1; -fi - -corpus=$1 -tmp=$2 -dir=$3 - -echo "prepare_data.sh: Preparing data in $corpus" - -mkdir -p $tmp -mkdir -p $dir - -# corpus check -if [ ! -d $corpus ] || [ ! -f $corpus/wav.scp ] || [ ! -f $corpus/trans.txt ]; then - echo "Error: $0 requires wav.scp and trans.txt under $corpus directory." - exit 1; -fi - -# validate utt-key list, IC0803W0380 is a bad utterance -awk '{print $1}' $corpus/wav.scp | grep -v 'IC0803W0380' > $tmp/wav_utt.list -awk '{print $1}' $corpus/trans.txt > $tmp/trans_utt.list -utils/filter_scp.pl -f 1 $tmp/wav_utt.list $tmp/trans_utt.list > $tmp/utt.list - -# wav.scp -awk -F'\t' -v path_prefix=$corpus '{printf("%s\t%s/%s\n",$1,path_prefix,$2)}' $corpus/wav.scp > $tmp/tmp_wav.scp -utils/filter_scp.pl -f 1 $tmp/utt.list $tmp/tmp_wav.scp | sort -k 1 | uniq > $tmp/wav.scp - -# text -utils/filter_scp.pl -f 1 $tmp/utt.list $corpus/trans.txt | sort -k 1 | uniq > $tmp/text - -# copy prepared resources from tmp_dir to target dir -mkdir -p $dir -for f in wav.scp text; do - cp $tmp/$f $dir/$f || exit 1; -done - -echo "local/prepare_data.sh succeeded" -exit 0; diff --git a/egs/aishell2/paraformerbert/path.sh b/egs/aishell2/paraformerbert/path.sh deleted file mode 100755 index ea3c0be2f..000000000 --- a/egs/aishell2/paraformerbert/path.sh +++ /dev/null @@ -1,6 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PYTHONPATH=../../../:$PYTHONPATH -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell2/paraformerbert/run.sh b/egs/aishell2/paraformerbert/run.sh deleted file mode 100755 index 548c4db5e..000000000 --- a/egs/aishell2/paraformerbert/run.sh +++ /dev/null @@ -1,239 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=1 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -dataset_type=large -stage=0 -stop_stage=5 - -skip_extract_embed=false -bert_model_name="bert-base-chinese" - -# feature configuration -feats_dim=80 -nj=64 - -# data -tr_dir= -dev_tst_dir= - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev_ios -test_sets="dev_ios test_ios" - -asr_config=conf/train_asr_paraformerbert_conformer_20e_6d_1280_320.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer_noctc_1best.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, e.g., gpuid_list=2,3, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # For training set - local/prepare_data.sh ${tr_dir} ${feats_dir}/data/local/train ${feats_dir}/data/train || exit 1; - # # For dev and test set - for x in iOS; do - local/prepare_data.sh ${dev_tst_dir}/${x}/dev ${feats_dir}/data/local/dev_${x,,} ${feats_dir}/data/dev_${x,,} || exit 1; - local/prepare_data.sh ${dev_tst_dir}/${x}/test ${feats_dir}/data/local/test_${x,,} ${feats_dir}/data/test_${x,,} || exit 1; - done - # Normalize text to capital letters - for x in train dev_ios test_ios; do - mv ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 ${feats_dir}/data/${x}/text.org) <(cut -f 2- ${feats_dir}/data/${x}/text.org \ - | tr 'A-Z' 'a-z' | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/${train_set}/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} - fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - if ! "${skip_extract_embed}"; then - echo "extract embeddings..." - local/extract_embeds.sh \ - --bert_model_name ${bert_model_name} \ - --raw_dataset_path ${feats_dir} \ - --nj $nj - fi - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text,embeds.scp" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --dataset_type $dataset_type \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode paraformer \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode paraformer \ - --model_name paraformer_bert \ - --dataset aishell2 \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --nat _nat \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/aishell2/paraformerbert/utils b/egs/aishell2/paraformerbert/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/aishell2/paraformerbert/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/aishell2/transformer/conf/decode_asr_transformer.yaml b/egs/aishell2/transformer/conf/decode_asr_transformer.yaml deleted file mode 100644 index a147fa79d..000000000 --- a/egs/aishell2/transformer/conf/decode_asr_transformer.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/aishell2/transformer/conf/train_asr_transformer.yaml b/egs/aishell2/transformer/conf/train_asr_transformer.yaml deleted file mode 100644 index 1b76e2a51..000000000 --- a/egs/aishell2/transformer/conf/train_asr_transformer.yaml +++ /dev/null @@ -1,93 +0,0 @@ -# network architecture -# encoder related -encoder: transformer -encoder_conf: - output_size: 256 # dimension of attention - attention_heads: 4 - linear_units: 2048 # the number of units of position-wise feed forward - num_blocks: 12 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 2 -grad_clip: 5 -patience: none -max_epoch: 150 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.002 -scheduler: warmuplr # pytorch v1.1.0+ required -scheduler_conf: - warmup_steps: 25000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 25000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/aishell2/transformer/local/prepare_data.sh b/egs/aishell2/transformer/local/prepare_data.sh deleted file mode 100755 index 77791f9c1..000000000 --- a/egs/aishell2/transformer/local/prepare_data.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2018 AIShell-Foundation(Authors:Jiayu DU, Xingyu NA, Bengu WU, Hao ZHENG) -# 2018 Beijing Shell Shell Tech. Co. Ltd. (Author: Hui BU) -# Apache 2.0 - -# transform raw AISHELL-2 data to kaldi format - -. ./path.sh || exit 1; - -tmp= -dir= - -if [ $# != 3 ]; then - echo "Usage: $0 " - echo " $0 /export/AISHELL-2/iOS/train data/local/train data/train" - exit 1; -fi - -corpus=$1 -tmp=$2 -dir=$3 - -echo "prepare_data.sh: Preparing data in $corpus" - -mkdir -p $tmp -mkdir -p $dir - -# corpus check -if [ ! -d $corpus ] || [ ! -f $corpus/wav.scp ] || [ ! -f $corpus/trans.txt ]; then - echo "Error: $0 requires wav.scp and trans.txt under $corpus directory." - exit 1; -fi - -# validate utt-key list, IC0803W0380 is a bad utterance -awk '{print $1}' $corpus/wav.scp | grep -v 'IC0803W0380' > $tmp/wav_utt.list -awk '{print $1}' $corpus/trans.txt > $tmp/trans_utt.list -utils/filter_scp.pl -f 1 $tmp/wav_utt.list $tmp/trans_utt.list > $tmp/utt.list - -# wav.scp -awk -F'\t' -v path_prefix=$corpus '{printf("%s\t%s/%s\n",$1,path_prefix,$2)}' $corpus/wav.scp > $tmp/tmp_wav.scp -utils/filter_scp.pl -f 1 $tmp/utt.list $tmp/tmp_wav.scp | sort -k 1 | uniq > $tmp/wav.scp - -# text -utils/filter_scp.pl -f 1 $tmp/utt.list $corpus/trans.txt | sort -k 1 | uniq > $tmp/text - -# copy prepared resources from tmp_dir to target dir -mkdir -p $dir -for f in wav.scp text; do - cp $tmp/$f $dir/$f || exit 1; -done - -echo "local/prepare_data.sh succeeded" -exit 0; diff --git a/egs/aishell2/transformer/path.sh b/egs/aishell2/transformer/path.sh deleted file mode 100755 index ea3c0be2f..000000000 --- a/egs/aishell2/transformer/path.sh +++ /dev/null @@ -1,6 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PYTHONPATH=../../../:$PYTHONPATH -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell2/transformer/run.sh b/egs/aishell2/transformer/run.sh deleted file mode 100755 index 22c3342f5..000000000 --- a/egs/aishell2/transformer/run.sh +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -dataset_type=large -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -tr_dir= -dev_tst_dir= - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev_ios -test_sets="dev_ios test_ios" - -asr_config=conf/train_asr_transformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # For training set - local/prepare_data.sh ${tr_dir} ${feats_dir}/data/local/train ${feats_dir}/data/train || exit 1; - # # For dev and test set - for x in iOS; do - local/prepare_data.sh ${dev_tst_dir}/${x}/dev ${feats_dir}/data/local/dev_${x,,} ${feats_dir}/data/dev_${x,,} || exit 1; - local/prepare_data.sh ${dev_tst_dir}/${x}/test ${feats_dir}/data/local/test_${x,,} ${feats_dir}/data/test_${x,,} || exit 1; - done - # Normalize text to capital letters - for x in train dev_ios test_ios; do - mv ${feats_dir}/data/${x}/text ${feats_dir}/data/${x}/text.org - paste -d " " <(cut -f 1 ${feats_dir}/data/${x}/text.org) <(cut -f 2- ${feats_dir}/data/${x}/text.org \ - | tr 'A-Z' 'a-z' | tr -d " ") \ - > ${feats_dir}/data/${x}/text - utils/text2token.py -n 1 -s 1 ${feats_dir}/data/${x}/text > ${feats_dir}/data/${x}/text.org - mv ${feats_dir}/data/${x}/text.org ${feats_dir}/data/${x}/text - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/${train_set}/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} - fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --dataset_type $dataset_type \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5 Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode asr \ - --model_name transformer \ - --dataset aishell2 \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --tag $tag -fi - diff --git a/egs/aishell2/transformer/utils b/egs/aishell2/transformer/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/aishell2/transformer/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/aishell2/transformerLM/conf/train_lm_transformer.yaml b/egs/aishell2/transformerLM/conf/train_lm_transformer.yaml deleted file mode 100644 index 4155a79ae..000000000 --- a/egs/aishell2/transformerLM/conf/train_lm_transformer.yaml +++ /dev/null @@ -1,31 +0,0 @@ -lm: transformer -lm_conf: - pos_enc: null - embed_unit: 128 - att_unit: 512 - head: 8 - unit: 2048 - layer: 16 - dropout_rate: 0.1 - -# optimization related -grad_clip: 5.0 -batch_type: numel -batch_bins: 6000000 -accum_grad: 1 -max_epoch: 15 # 15epoch is enough - -optim: adam -optim_conf: - lr: 0.001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 25000 - -best_model_criterion: -- - valid - - loss - - min -keep_nbest_models: 10 # 10 is good. - -log_interval: 50 diff --git a/egs/aishell2/transformerLM/path.sh b/egs/aishell2/transformerLM/path.sh deleted file mode 100755 index ea3c0be2f..000000000 --- a/egs/aishell2/transformerLM/path.sh +++ /dev/null @@ -1,6 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PYTHONPATH=../../../:$PYTHONPATH -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/aishell2/transformerLM/run.sh b/egs/aishell2/transformerLM/run.sh deleted file mode 100755 index b04c64396..000000000 --- a/egs/aishell2/transformerLM/run.sh +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1" -gpu_num=2 -count=1 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -lang=zh -nlsyms_txt=none # Non-linguistic symbol list if existing. -cleaner=none # Text cleaner. -g2p=none # g2p method (needed if token_type=phn). -lm_fold_length=150 # fold_length for LM training. -word_vocab_size=10000 # Size of word vocabulary. -token_type=char -lm_token_list= - -nj=10 -## path to AISHELL2 trans -lm_train_text= -lm_dev_text= -lm_test_text= - -train_data_path_and_name_and_type=${lm_train_text},text,text -train_shape_file= -valid_data_path_and_name_and_type=${lm_dev_text},text,text -valid_shape_file= -lm_config=conf/train_lm_transformer.yaml -exp_dir=./data -tag=exp1 -model_dir="baseline_$(basename "${lm_config}" .yaml)_${lang}_${token_type}_${tag}" -lm_exp=${exp_dir}/exp/${model_dir} -inference_lm=valid.loss.ave.pb # Language model path for decoding. - -stage=0 -stop_stage=3 - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -min() { - local a b - a=$1 - for b in "$@"; do - if [ "${b}" -le "${a}" ]; then - a="${b}" - fi - done - echo "${a}" -} - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, e.g., gpuid_list=2,3, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -mkdir -p ${exp_dir}/exp/${model_dir} -token_list=${exp_dir}/exp/${model_dir}/vocab.txt -blank="" # CTC blank symbole -sos="" # sos symbole -eos="" # eos symbole -oov="" # Out of vocabulary symbol. -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - if [ "${token_type}" = char ] || [ "${token_type}" = word ]; then - echo "Stage 0: Generate character level token_list from ${lm_train_text}" - - # The first symbol in token_list must be "": - # 0 is reserved for CTC-blank for ASR and also used as ignore-index in the other task - python -m funasr.bin.tokenize_text \ - --token_type "${token_type}" \ - --input "${lm_train_text}" \ - --output "${token_list}" \ - --non_linguistic_symbols "${nlsyms_txt}" \ - --field 2- \ - --cleaner "${cleaner}" \ - --g2p "${g2p}" \ - --write_vocabulary true \ - --add_symbol "${blank}:0" \ - --add_symbol "${sos}:1" \ - --add_symbol "${eos}:2" \ - --add_symbol "${oov}:-1" - - else - echo "Error: not supported --token_type '${token_type}'" - exit 2 - fi - - lm_token_list="${token_list}" - -fi - - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Data preparation" - - # 1. Split the key file - _logdir="${exp_dir}/exp/${model_dir}/log" - mkdir -p "${_logdir}" - # Get the minimum number among ${nj} and the number lines of input files - _nj=$(min "${nj}" "$(<${lm_train_text} wc -l)" "$(<${lm_dev_text} wc -l)") - - key_file="${lm_train_text}" - split_scps="" - for n in $(seq ${_nj}); do - split_scps+=" ${_logdir}/train.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - key_file="${lm_dev_text}" - split_scps="" - for n in $(seq ${_nj}); do - split_scps+=" ${_logdir}/dev.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - # 2. Submit jobs - ## python ../../funasr/bin/lm_train.py \ - ${train_cmd} JOB=1:"${_nj}" "${_logdir}"/stats.JOB.log \ - python -m funasr.bin.lm_train \ - --collect_stats true \ - --use_preprocessor true \ - --token_type "${token_type}" \ - --token_list "${lm_token_list}" \ - --non_linguistic_symbols "${nlsyms_txt}" \ - --cleaner "${cleaner}" \ - --g2p "${g2p}" \ - --train_data_path_and_name_and_type "${lm_train_text},text,text" \ - --valid_data_path_and_name_and_type "${lm_dev_text},text,text" \ - --train_shape_file "${_logdir}/train.JOB.scp" \ - --valid_shape_file "${_logdir}/dev.JOB.scp" \ - --output_dir "${_logdir}/stats.JOB" \ - --config ${lm_config} || { cat "${_logdir}"/stats.*.log; exit 1; } - - # 3. Aggregate shape files - _opts= - for i in $(seq "${_nj}"); do - _opts+="--input_dir ${_logdir}/stats.${i} " - done - lm_stats_dir=${exp_dir}/exp/${model_dir} - # shellcheck disable=SC2086 - python -m funasr.bin.aggregate_stats_dirs ${_opts} --output_dir "${lm_stats_dir}" - - # Append the num-tokens at the last dimensions. This is used for batch-bins count - <"${lm_stats_dir}/train/text_shape" \ - awk -v N="$(<${lm_token_list} wc -l)" '{ print $0 "," N }' \ - >"${lm_stats_dir}/train/text_shape.${token_type}" - - <"${lm_stats_dir}/valid/text_shape" \ - awk -v N="$(<${lm_token_list} wc -l)" '{ print $0 "," N }' \ - >"${lm_stats_dir}/valid/text_shape.${token_type}" - - train_shape_file=${lm_stats_dir}/train/text_shape.${token_type} - valid_shape_file=${lm_stats_dir}/valid/text_shape.${token_type} - -fi - -# Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Training" - mkdir -p ${lm_exp} - mkdir -p ${lm_exp}/log - INIT_FILE=${lm_exp}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - python ../../../funasr/bin/lm_train.py \ - --gpu_id ${gpu_id} \ - --use_preprocessor true \ - --token_type "${token_type}" \ - --token_list "${lm_token_list}" \ - --non_linguistic_symbols "${nlsyms_txt}" \ - --cleaner "${cleaner}" \ - --train_data_path_and_name_and_type "${train_data_path_and_name_and_type}" \ - --train_shape_file "${train_shape_file}" \ - --valid_data_path_and_name_and_type "${valid_data_path_and_name_and_type}" \ - --valid_shape_file "${valid_shape_file}" \ - --fold_length "${lm_fold_length}" \ - --resume true \ - --output_dir "${lm_exp}" \ - --config ${lm_config} \ - --ngpu ${gpu_num} \ - --num_worker_count ${count} \ - --multiprocessing_distributed true \ - --dist_init_method ${init_method} \ - --dist_world_size ${world_size} \ - --dist_rank ${rank} \ - --local_rank ${local_rank} 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -gpu_num=1 -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "Stage 3: Calc perplexity: ${lm_test_text}" - - python ../../../funasr/bin/lm_inference_launch.py \ - --output_dir "${lm_exp}/perplexity_test/output.1" \ - --ngpu "${gpu_num}" \ - --batch_size 1 \ - --train_config "${lm_exp}"/config.yaml \ - --model_file "${lm_exp}/${inference_lm}" \ - --data_path_and_name_and_type "${lm_test_text},text,text" \ - --num_workers 1 \ - --gpuid_list 0 \ - --mode "transformer" \ - --split_with_space false -fi - diff --git a/egs/aishell2/transformerLM/utils b/egs/aishell2/transformerLM/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/aishell2/transformerLM/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/alimeeting/diarization/sond/README.md b/egs/alimeeting/diarization/sond/README.md deleted file mode 100644 index b36210c6d..000000000 --- a/egs/alimeeting/diarization/sond/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Get Started -To use this example, please execute the first stage of run.sh first to obtain the prepared data and pre-trained models: -```shell -sh run.sh --stage 0 --stop_stage 0 -``` -Then, you can execute unit_test.py to check the correctness of code: -```shell -python unit_test.py -# you will get the results: -[{'key': 'R8002_M8002_MS802-S0000_0000000_0001600', 'value': 'spk1 [(0.0, 8.88), (10.72, 11.92), (12.64, 15.2)]\nspk2 [(8.8, 9.76)]\nspk3 [(9.6, 10.96), (15.12, 15.68)]\nspk4 [(11.12, 12.72)]'}] -[{'key': 'R8002_M8002_MS802-S0000_0000000_0001600', 'value': 'spk1 [(0.0, 8.88), (10.72, 11.92), (12.64, 15.2)]\nspk2 [(8.8, 9.76)]\nspk3 [(9.6, 10.96), (15.12, 15.68)]\nspk4 [(11.12, 12.72)]'}] -[{'key': 'R8002_M8002_MS802-S0000_0000000_0001600', 'value': 'spk1 [(0.0, 8.88), (10.72, 11.92), (12.64, 15.2)]\nspk2 [(8.8, 9.76)]\nspk3 [(9.6, 10.88), (15.12, 15.68)]\nspk4 [(11.12, 12.72)]'}] -[{'key': 'test0', 'value': 'spk1 [(0.0, 8.88), (10.64, 15.2)]\nspk2 [(8.88, 9.84)]\nspk3 [(9.6, 11.04), (15.12, 15.68)]\nspk4 [(11.2, 11.76)]'}] -``` -You can also execute run.sh to reproduce the diarization performance reported in [1] -```shell -sh run.sh --stage 1 --stop_stage 2 -``` - -# Results -After executing "run.sh", you will get a DER about 4.21%, which is reported in [1], Table 6, line "SOND Oracle Profile". - -# Reference -[1] Speaker Overlap-aware Neural Diarization for Multi-party Meeting Analysis, Zhihao Du, Shiliang Zhang, -Siqi Zheng, Zhijie Yan. EMNLP 2022. \ No newline at end of file diff --git a/egs/alimeeting/diarization/sond/config.yaml b/egs/alimeeting/diarization/sond/config.yaml deleted file mode 100644 index 072c171c3..000000000 --- a/egs/alimeeting/diarization/sond/config.yaml +++ /dev/null @@ -1,2740 +0,0 @@ -config: finetune.yaml -print_config: false -log_level: INFO -dry_run: false -iterator_type: sequence -output_dir: exp/sond -ngpu: 1 -seed: 0 -num_workers: 16 -num_att_plot: 0 -dist_backend: nccl -dist_init_method: env:// -dist_world_size: null -dist_rank: null -local_rank: 0 -dist_master_addr: null -dist_master_port: null -dist_launcher: null -multiprocessing_distributed: true -distributed: false -unused_parameters: true -sharded_ddp: false -ddp_backend: pytorch_ddp -cudnn_enabled: true -cudnn_benchmark: false -cudnn_deterministic: true -collect_stats: false -write_collected_feats: false -max_epoch: 50 -patience: null -val_scheduler_criterion: -- valid -- acc -early_stopping_criterion: -- valid -- loss -- min -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 -nbest_averaging_interval: 0 -grad_clip: 5 -grad_clip_type: 2.0 -grad_noise: false -accum_grad: 1 -no_forward_run: false -resume: true -train_dtype: float32 -use_amp: false -log_interval: 50 -use_matplotlib: false -use_tensorboard: true -use_wandb: false -wandb_project: null -wandb_id: null -wandb_entity: null -wandb_name: null -wandb_model_log_interval: -1 -use_pai: true -detect_anomaly: false -pretrain_path: null -init_param: [] -ignore_init_mismatch: false -freeze_param: [] -num_iters_per_epoch: null -batch_size: 20 -valid_batch_size: null -batch_bins: 10000 -valid_batch_bins: null -train_shape_file: -- /data/volume1/youyan/aishell/ark/train/speech_shape.1 -- /data/volume1/youyan/aishell/ark/train/text_shape.1 -valid_shape_file: -- /data/volume1/youyan/aishell/ark/dev/speech_shape.1 -- /data/volume1/youyan/aishell/ark/dev/text_shape.1 -batch_type: length -valid_batch_type: null -fold_length: -- 512 -- 150 -sort_in_batch: descending -sort_batch: descending -multiple_iterator: false -chunk_length: 500 -chunk_shift_ratio: 0.5 -num_cache_chunks: 1024 -train_data_path_and_name_and_type: -- - /data/volume1/youyan/aishell/ark/train/data.scp - - speech - - kaldi_ark -- - /data/volume1/youyan/aishell/ark/train/data.text.1 - - text - - text -valid_data_path_and_name_and_type: -- - /data/volume1/youyan/aishell/ark/dev/data.scp - - speech - - kaldi_ark -- - /data/volume1/youyan/aishell/ark/dev/data.text.1 - - text - - text -allow_variable_data_keys: false -max_cache_size: 0.0 -max_cache_fd: 32 -valid_max_cache_size: null -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 -token_list: -- '0' -- '1' -- '2' -- '3' -- '4' -- '5' -- '6' -- '7' -- '8' -- '9' -- '10' -- '11' -- '12' -- '13' -- '14' -- '15' -- '16' -- '17' -- '18' -- '19' -- '20' -- '21' -- '22' -- '23' -- '24' -- '25' -- '26' -- '27' -- '28' -- '29' -- '30' -- '32' -- '33' -- '34' -- '35' -- '36' -- '37' -- '38' -- '39' -- '40' -- '41' -- '42' -- '43' -- '44' -- '45' -- '46' -- '48' -- '49' -- '50' -- '51' -- '52' -- '53' -- '54' -- '56' -- '57' -- '58' -- '60' -- '64' -- '65' -- '66' -- '67' -- '68' -- '69' -- '70' -- '71' -- '72' -- '73' -- '74' -- '75' -- '76' -- '77' -- '78' -- '80' -- '81' -- '82' -- '83' -- '84' -- '85' -- '86' -- '88' -- '89' -- '90' -- '92' -- '96' -- '97' -- '98' -- '99' -- '100' -- '101' -- '102' -- '104' -- '105' -- '106' -- '108' -- '112' -- '113' -- '114' -- '116' -- '120' -- '128' -- '129' -- '130' -- '131' -- '132' -- '133' -- '134' -- '135' -- '136' -- '137' -- '138' -- '139' -- '140' -- '141' -- '142' -- '144' -- '145' -- '146' -- '147' -- '148' -- '149' -- '150' -- '152' -- '153' -- '154' -- '156' -- '160' -- '161' -- '162' -- '163' -- '164' -- '165' -- '166' -- '168' -- '169' -- '170' -- '172' -- '176' -- '177' -- '178' -- '180' -- '184' -- '192' -- '193' -- '194' -- '195' -- '196' -- '197' -- '198' -- '200' -- '201' -- '202' -- '204' -- '208' -- '209' -- '210' -- '212' -- '216' -- '224' -- '225' -- '226' -- '228' -- '232' -- '240' -- '256' -- '257' -- '258' -- '259' -- '260' -- '261' -- '262' -- '263' -- '264' -- '265' -- '266' -- '267' -- '268' -- '269' -- '270' -- '272' -- '273' -- '274' -- '275' -- '276' -- '277' -- '278' -- '280' -- '281' -- '282' -- '284' -- '288' -- '289' -- '290' -- '291' -- '292' -- '293' -- '294' -- '296' -- '297' -- '298' -- '300' -- '304' -- '305' -- '306' -- '308' -- '312' -- '320' -- '321' -- '322' -- '323' -- '324' -- '325' -- '326' -- '328' -- '329' -- '330' -- '332' -- '336' -- '337' -- '338' -- '340' -- '344' -- '352' -- '353' -- '354' -- '356' -- '360' -- '368' -- '384' -- '385' -- '386' -- '387' -- '388' -- '389' -- '390' -- '392' -- '393' -- '394' -- '396' -- '400' -- '401' -- '402' -- '404' -- '408' -- '416' -- '417' -- '418' -- '420' -- '424' -- '432' -- '448' -- '449' -- '450' -- '452' -- '456' -- '464' -- '480' -- '512' -- '513' -- '514' -- '515' -- '516' -- '517' -- '518' -- '519' -- '520' -- '521' -- '522' -- '523' -- '524' -- '525' -- '526' -- '528' -- '529' -- '530' -- '531' -- '532' -- '533' -- '534' -- '536' -- '537' -- '538' -- '540' -- '544' -- '545' -- '546' -- '547' -- '548' -- '549' -- '550' -- '552' -- '553' -- '554' -- '556' -- '560' -- '561' -- '562' -- '564' -- '568' -- '576' -- '577' -- '578' -- '579' -- '580' -- '581' -- '582' -- '584' -- '585' -- '586' -- '588' -- '592' -- '593' -- '594' -- '596' -- '600' -- '608' -- '609' -- '610' -- '612' -- '616' -- '624' -- '640' -- '641' -- '642' -- '643' -- '644' -- '645' -- '646' -- '648' -- '649' -- '650' -- '652' -- '656' -- '657' -- '658' -- '660' -- '664' -- '672' -- '673' -- '674' -- '676' -- '680' -- '688' -- '704' -- '705' -- '706' -- '708' -- '712' -- '720' -- '736' -- '768' -- '769' -- '770' -- '771' -- '772' -- '773' -- '774' -- '776' -- '777' -- '778' -- '780' -- '784' -- '785' -- '786' -- '788' -- '792' -- '800' -- '801' -- '802' -- '804' -- '808' -- '816' -- '832' -- '833' -- '834' -- '836' -- '840' -- '848' -- '864' -- '896' -- '897' -- '898' -- '900' -- '904' -- '912' -- '928' -- '960' -- '1024' -- '1025' -- '1026' -- '1027' -- '1028' -- '1029' -- '1030' -- '1031' -- '1032' -- '1033' -- '1034' -- '1035' -- '1036' -- '1037' -- '1038' -- '1040' -- '1041' -- '1042' -- '1043' -- '1044' -- '1045' -- '1046' -- '1048' -- '1049' -- '1050' -- '1052' -- '1056' -- '1057' -- '1058' -- '1059' -- '1060' -- '1061' -- '1062' -- '1064' -- '1065' -- '1066' -- '1068' -- '1072' -- '1073' -- '1074' -- '1076' -- '1080' -- '1088' -- '1089' -- '1090' -- '1091' -- '1092' -- '1093' -- '1094' -- '1096' -- '1097' -- '1098' -- '1100' -- '1104' -- '1105' -- '1106' -- '1108' -- '1112' -- '1120' -- '1121' -- '1122' -- '1124' -- '1128' -- '1136' -- '1152' -- '1153' -- '1154' -- '1155' -- '1156' -- '1157' -- '1158' -- '1160' -- '1161' -- '1162' -- '1164' -- '1168' -- '1169' -- '1170' -- '1172' -- '1176' -- '1184' -- '1185' -- '1186' -- '1188' -- '1192' -- '1200' -- '1216' -- '1217' -- '1218' -- '1220' -- '1224' -- '1232' -- '1248' -- '1280' -- '1281' -- '1282' -- '1283' -- '1284' -- '1285' -- '1286' -- '1288' -- '1289' -- '1290' -- '1292' -- '1296' -- '1297' -- '1298' -- '1300' -- '1304' -- '1312' -- '1313' -- '1314' -- '1316' -- '1320' -- '1328' -- '1344' -- '1345' -- '1346' -- '1348' -- '1352' -- '1360' -- '1376' -- '1408' -- '1409' -- '1410' -- '1412' -- '1416' -- '1424' -- '1440' -- '1472' -- '1536' -- '1537' -- '1538' -- '1539' -- '1540' -- '1541' -- '1542' -- '1544' -- '1545' -- '1546' -- '1548' -- '1552' -- '1553' -- '1554' -- '1556' -- '1560' -- '1568' -- '1569' -- '1570' -- '1572' -- '1576' -- '1584' -- '1600' -- '1601' -- '1602' -- '1604' -- '1608' -- '1616' -- '1632' -- '1664' -- '1665' -- '1666' -- '1668' -- '1672' -- '1680' -- '1696' -- '1728' -- '1792' -- '1793' -- '1794' -- '1796' -- '1800' -- '1808' -- '1824' -- '1856' -- '1920' -- '2048' -- '2049' -- '2050' -- '2051' -- '2052' -- '2053' -- '2054' -- '2055' -- '2056' -- '2057' -- '2058' -- '2059' -- '2060' -- '2061' -- '2062' -- '2064' -- '2065' -- '2066' -- '2067' -- '2068' -- '2069' -- '2070' -- '2072' -- '2073' -- '2074' -- '2076' -- '2080' -- '2081' -- '2082' -- '2083' -- '2084' -- '2085' -- '2086' -- '2088' -- '2089' -- '2090' -- '2092' -- '2096' -- '2097' -- '2098' -- '2100' -- '2104' -- '2112' -- '2113' -- '2114' -- '2115' -- '2116' -- '2117' -- '2118' -- '2120' -- '2121' -- '2122' -- '2124' -- '2128' -- '2129' -- '2130' -- '2132' -- '2136' -- '2144' -- '2145' -- '2146' -- '2148' -- '2152' -- '2160' -- '2176' -- '2177' -- '2178' -- '2179' -- '2180' -- '2181' -- '2182' -- '2184' -- '2185' -- '2186' -- '2188' -- '2192' -- '2193' -- '2194' -- '2196' -- '2200' -- '2208' -- '2209' -- '2210' -- '2212' -- '2216' -- '2224' -- '2240' -- '2241' -- '2242' -- '2244' -- '2248' -- '2256' -- '2272' -- '2304' -- '2305' -- '2306' -- '2307' -- '2308' -- '2309' -- '2310' -- '2312' -- '2313' -- '2314' -- '2316' -- '2320' -- '2321' -- '2322' -- '2324' -- '2328' -- '2336' -- '2337' -- '2338' -- '2340' -- '2344' -- '2352' -- '2368' -- '2369' -- '2370' -- '2372' -- '2376' -- '2384' -- '2400' -- '2432' -- '2433' -- '2434' -- '2436' -- '2440' -- '2448' -- '2464' -- '2496' -- '2560' -- '2561' -- '2562' -- '2563' -- '2564' -- '2565' -- '2566' -- '2568' -- '2569' -- '2570' -- '2572' -- '2576' -- '2577' -- '2578' -- '2580' -- '2584' -- '2592' -- '2593' -- '2594' -- '2596' -- '2600' -- '2608' -- '2624' -- '2625' -- '2626' -- '2628' -- '2632' -- '2640' -- '2656' -- '2688' -- '2689' -- '2690' -- '2692' -- '2696' -- '2704' -- '2720' -- '2752' -- '2816' -- '2817' -- '2818' -- '2820' -- '2824' -- '2832' -- '2848' -- '2880' -- '2944' -- '3072' -- '3073' -- '3074' -- '3075' -- '3076' -- '3077' -- '3078' -- '3080' -- '3081' -- '3082' -- '3084' -- '3088' -- '3089' -- '3090' -- '3092' -- '3096' -- '3104' -- '3105' -- '3106' -- '3108' -- '3112' -- '3120' -- '3136' -- '3137' -- '3138' -- '3140' -- '3144' -- '3152' -- '3168' -- '3200' -- '3201' -- '3202' -- '3204' -- '3208' -- '3216' -- '3232' -- '3264' -- '3328' -- '3329' -- '3330' -- '3332' -- '3336' -- '3344' -- '3360' -- '3392' -- '3456' -- '3584' -- '3585' -- '3586' -- '3588' -- '3592' -- '3600' -- '3616' -- '3648' -- '3712' -- '3840' -- '4096' -- '4097' -- '4098' -- '4099' -- '4100' -- '4101' -- '4102' -- '4103' -- '4104' -- '4105' -- '4106' -- '4107' -- '4108' -- '4109' -- '4110' -- '4112' -- '4113' -- '4114' -- '4115' -- '4116' -- '4117' -- '4118' -- '4120' -- '4121' -- '4122' -- '4124' -- '4128' -- '4129' -- '4130' -- '4131' -- '4132' -- '4133' -- '4134' -- '4136' -- '4137' -- '4138' -- '4140' -- '4144' -- '4145' -- '4146' -- '4148' -- '4152' -- '4160' -- '4161' -- '4162' -- '4163' -- '4164' -- '4165' -- '4166' -- '4168' -- '4169' -- '4170' -- '4172' -- '4176' -- '4177' -- '4178' -- '4180' -- '4184' -- '4192' -- '4193' -- '4194' -- '4196' -- '4200' -- '4208' -- '4224' -- '4225' -- '4226' -- '4227' -- '4228' -- '4229' -- '4230' -- '4232' -- '4233' -- '4234' -- '4236' -- '4240' -- '4241' -- '4242' -- '4244' -- '4248' -- '4256' -- '4257' -- '4258' -- '4260' -- '4264' -- '4272' -- '4288' -- '4289' -- '4290' -- '4292' -- '4296' -- '4304' -- '4320' -- '4352' -- '4353' -- '4354' -- '4355' -- '4356' -- '4357' -- '4358' -- '4360' -- '4361' -- '4362' -- '4364' -- '4368' -- '4369' -- '4370' -- '4372' -- '4376' -- '4384' -- '4385' -- '4386' -- '4388' -- '4392' -- '4400' -- '4416' -- '4417' -- '4418' -- '4420' -- '4424' -- '4432' -- '4448' -- '4480' -- '4481' -- '4482' -- '4484' -- '4488' -- '4496' -- '4512' -- '4544' -- '4608' -- '4609' -- '4610' -- '4611' -- '4612' -- '4613' -- '4614' -- '4616' -- '4617' -- '4618' -- '4620' -- '4624' -- '4625' -- '4626' -- '4628' -- '4632' -- '4640' -- '4641' -- '4642' -- '4644' -- '4648' -- '4656' -- '4672' -- '4673' -- '4674' -- '4676' -- '4680' -- '4688' -- '4704' -- '4736' -- '4737' -- '4738' -- '4740' -- '4744' -- '4752' -- '4768' -- '4800' -- '4864' -- '4865' -- '4866' -- '4868' -- '4872' -- '4880' -- '4896' -- '4928' -- '4992' -- '5120' -- '5121' -- '5122' -- '5123' -- '5124' -- '5125' -- '5126' -- '5128' -- '5129' -- '5130' -- '5132' -- '5136' -- '5137' -- '5138' -- '5140' -- '5144' -- '5152' -- '5153' -- '5154' -- '5156' -- '5160' -- '5168' -- '5184' -- '5185' -- '5186' -- '5188' -- '5192' -- '5200' -- '5216' -- '5248' -- '5249' -- '5250' -- '5252' -- '5256' -- '5264' -- '5280' -- '5312' -- '5376' -- '5377' -- '5378' -- '5380' -- '5384' -- '5392' -- '5408' -- '5440' -- '5504' -- '5632' -- '5633' -- '5634' -- '5636' -- '5640' -- '5648' -- '5664' -- '5696' -- '5760' -- '5888' -- '6144' -- '6145' -- '6146' -- '6147' -- '6148' -- '6149' -- '6150' -- '6152' -- '6153' -- '6154' -- '6156' -- '6160' -- '6161' -- '6162' -- '6164' -- '6168' -- '6176' -- '6177' -- '6178' -- '6180' -- '6184' -- '6192' -- '6208' -- '6209' -- '6210' -- '6212' -- '6216' -- '6224' -- '6240' -- '6272' -- '6273' -- '6274' -- '6276' -- '6280' -- '6288' -- '6304' -- '6336' -- '6400' -- '6401' -- '6402' -- '6404' -- '6408' -- '6416' -- '6432' -- '6464' -- '6528' -- '6656' -- '6657' -- '6658' -- '6660' -- '6664' -- '6672' -- '6688' -- '6720' -- '6784' -- '6912' -- '7168' -- '7169' -- '7170' -- '7172' -- '7176' -- '7184' -- '7200' -- '7232' -- '7296' -- '7424' -- '7680' -- '8192' -- '8193' -- '8194' -- '8195' -- '8196' -- '8197' -- '8198' -- '8199' -- '8200' -- '8201' -- '8202' -- '8203' -- '8204' -- '8205' -- '8206' -- '8208' -- '8209' -- '8210' -- '8211' -- '8212' -- '8213' -- '8214' -- '8216' -- '8217' -- '8218' -- '8220' -- '8224' -- '8225' -- '8226' -- '8227' -- '8228' -- '8229' -- '8230' -- '8232' -- '8233' -- '8234' -- '8236' -- '8240' -- '8241' -- '8242' -- '8244' -- '8248' -- '8256' -- '8257' -- '8258' -- '8259' -- '8260' -- '8261' -- '8262' -- '8264' -- '8265' -- '8266' -- '8268' -- '8272' -- '8273' -- '8274' -- '8276' -- '8280' -- '8288' -- '8289' -- '8290' -- '8292' -- '8296' -- '8304' -- '8320' -- '8321' -- '8322' -- '8323' -- '8324' -- '8325' -- '8326' -- '8328' -- '8329' -- '8330' -- '8332' -- '8336' -- '8337' -- '8338' -- '8340' -- '8344' -- '8352' -- '8353' -- '8354' -- '8356' -- '8360' -- '8368' -- '8384' -- '8385' -- '8386' -- '8388' -- '8392' -- '8400' -- '8416' -- '8448' -- '8449' -- '8450' -- '8451' -- '8452' -- '8453' -- '8454' -- '8456' -- '8457' -- '8458' -- '8460' -- '8464' -- '8465' -- '8466' -- '8468' -- '8472' -- '8480' -- '8481' -- '8482' -- '8484' -- '8488' -- '8496' -- '8512' -- '8513' -- '8514' -- '8516' -- '8520' -- '8528' -- '8544' -- '8576' -- '8577' -- '8578' -- '8580' -- '8584' -- '8592' -- '8608' -- '8640' -- '8704' -- '8705' -- '8706' -- '8707' -- '8708' -- '8709' -- '8710' -- '8712' -- '8713' -- '8714' -- '8716' -- '8720' -- '8721' -- '8722' -- '8724' -- '8728' -- '8736' -- '8737' -- '8738' -- '8740' -- '8744' -- '8752' -- '8768' -- '8769' -- '8770' -- '8772' -- '8776' -- '8784' -- '8800' -- '8832' -- '8833' -- '8834' -- '8836' -- '8840' -- '8848' -- '8864' -- '8896' -- '8960' -- '8961' -- '8962' -- '8964' -- '8968' -- '8976' -- '8992' -- '9024' -- '9088' -- '9216' -- '9217' -- '9218' -- '9219' -- '9220' -- '9221' -- '9222' -- '9224' -- '9225' -- '9226' -- '9228' -- '9232' -- '9233' -- '9234' -- '9236' -- '9240' -- '9248' -- '9249' -- '9250' -- '9252' -- '9256' -- '9264' -- '9280' -- '9281' -- '9282' -- '9284' -- '9288' -- '9296' -- '9312' -- '9344' -- '9345' -- '9346' -- '9348' -- '9352' -- '9360' -- '9376' -- '9408' -- '9472' -- '9473' -- '9474' -- '9476' -- '9480' -- '9488' -- '9504' -- '9536' -- '9600' -- '9728' -- '9729' -- '9730' -- '9732' -- '9736' -- '9744' -- '9760' -- '9792' -- '9856' -- '9984' -- '10240' -- '10241' -- '10242' -- '10243' -- '10244' -- '10245' -- '10246' -- '10248' -- '10249' -- '10250' -- '10252' -- '10256' -- '10257' -- '10258' -- '10260' -- '10264' -- '10272' -- '10273' -- '10274' -- '10276' -- '10280' -- '10288' -- '10304' -- '10305' -- '10306' -- '10308' -- '10312' -- '10320' -- '10336' -- '10368' -- '10369' -- '10370' -- '10372' -- '10376' -- '10384' -- '10400' -- '10432' -- '10496' -- '10497' -- '10498' -- '10500' -- '10504' -- '10512' -- '10528' -- '10560' -- '10624' -- '10752' -- '10753' -- '10754' -- '10756' -- '10760' -- '10768' -- '10784' -- '10816' -- '10880' -- '11008' -- '11264' -- '11265' -- '11266' -- '11268' -- '11272' -- '11280' -- '11296' -- '11328' -- '11392' -- '11520' -- '11776' -- '12288' -- '12289' -- '12290' -- '12291' -- '12292' -- '12293' -- '12294' -- '12296' -- '12297' -- '12298' -- '12300' -- '12304' -- '12305' -- '12306' -- '12308' -- '12312' -- '12320' -- '12321' -- '12322' -- '12324' -- '12328' -- '12336' -- '12352' -- '12353' -- '12354' -- '12356' -- '12360' -- '12368' -- '12384' -- '12416' -- '12417' -- '12418' -- '12420' -- '12424' -- '12432' -- '12448' -- '12480' -- '12544' -- '12545' -- '12546' -- '12548' -- '12552' -- '12560' -- '12576' -- '12608' -- '12672' -- '12800' -- '12801' -- '12802' -- '12804' -- '12808' -- '12816' -- '12832' -- '12864' -- '12928' -- '13056' -- '13312' -- '13313' -- '13314' -- '13316' -- '13320' -- '13328' -- '13344' -- '13376' -- '13440' -- '13568' -- '13824' -- '14336' -- '14337' -- '14338' -- '14340' -- '14344' -- '14352' -- '14368' -- '14400' -- '14464' -- '14592' -- '14848' -- '15360' -- '16384' -- '16385' -- '16386' -- '16387' -- '16388' -- '16389' -- '16390' -- '16391' -- '16392' -- '16393' -- '16394' -- '16395' -- '16396' -- '16397' -- '16398' -- '16400' -- '16401' -- '16402' -- '16403' -- '16404' -- '16405' -- '16406' -- '16408' -- '16409' -- '16410' -- '16412' -- '16416' -- '16417' -- '16418' -- '16419' -- '16420' -- '16421' -- '16422' -- '16424' -- '16425' -- '16426' -- '16428' -- '16432' -- '16433' -- '16434' -- '16436' -- '16440' -- '16448' -- '16449' -- '16450' -- '16451' -- '16452' -- '16453' -- '16454' -- '16456' -- '16457' -- '16458' -- '16460' -- '16464' -- '16465' -- '16466' -- '16468' -- '16472' -- '16480' -- '16481' -- '16482' -- '16484' -- '16488' -- '16496' -- '16512' -- '16513' -- '16514' -- '16515' -- '16516' -- '16517' -- '16518' -- '16520' -- '16521' -- '16522' -- '16524' -- '16528' -- '16529' -- '16530' -- '16532' -- '16536' -- '16544' -- '16545' -- '16546' -- '16548' -- '16552' -- '16560' -- '16576' -- '16577' -- '16578' -- '16580' -- '16584' -- '16592' -- '16608' -- '16640' -- '16641' -- '16642' -- '16643' -- '16644' -- '16645' -- '16646' -- '16648' -- '16649' -- '16650' -- '16652' -- '16656' -- '16657' -- '16658' -- '16660' -- '16664' -- '16672' -- '16673' -- '16674' -- '16676' -- '16680' -- '16688' -- '16704' -- '16705' -- '16706' -- '16708' -- '16712' -- '16720' -- '16736' -- '16768' -- '16769' -- '16770' -- '16772' -- '16776' -- '16784' -- '16800' -- '16832' -- '16896' -- '16897' -- '16898' -- '16899' -- '16900' -- '16901' -- '16902' -- '16904' -- '16905' -- '16906' -- '16908' -- '16912' -- '16913' -- '16914' -- '16916' -- '16920' -- '16928' -- '16929' -- '16930' -- '16932' -- '16936' -- '16944' -- '16960' -- '16961' -- '16962' -- '16964' -- '16968' -- '16976' -- '16992' -- '17024' -- '17025' -- '17026' -- '17028' -- '17032' -- '17040' -- '17056' -- '17088' -- '17152' -- '17153' -- '17154' -- '17156' -- '17160' -- '17168' -- '17184' -- '17216' -- '17280' -- '17408' -- '17409' -- '17410' -- '17411' -- '17412' -- '17413' -- '17414' -- '17416' -- '17417' -- '17418' -- '17420' -- '17424' -- '17425' -- '17426' -- '17428' -- '17432' -- '17440' -- '17441' -- '17442' -- '17444' -- '17448' -- '17456' -- '17472' -- '17473' -- '17474' -- '17476' -- '17480' -- '17488' -- '17504' -- '17536' -- '17537' -- '17538' -- '17540' -- '17544' -- '17552' -- '17568' -- '17600' -- '17664' -- '17665' -- '17666' -- '17668' -- '17672' -- '17680' -- '17696' -- '17728' -- '17792' -- '17920' -- '17921' -- '17922' -- '17924' -- '17928' -- '17936' -- '17952' -- '17984' -- '18048' -- '18176' -- '18432' -- '18433' -- '18434' -- '18435' -- '18436' -- '18437' -- '18438' -- '18440' -- '18441' -- '18442' -- '18444' -- '18448' -- '18449' -- '18450' -- '18452' -- '18456' -- '18464' -- '18465' -- '18466' -- '18468' -- '18472' -- '18480' -- '18496' -- '18497' -- '18498' -- '18500' -- '18504' -- '18512' -- '18528' -- '18560' -- '18561' -- '18562' -- '18564' -- '18568' -- '18576' -- '18592' -- '18624' -- '18688' -- '18689' -- '18690' -- '18692' -- '18696' -- '18704' -- '18720' -- '18752' -- '18816' -- '18944' -- '18945' -- '18946' -- '18948' -- '18952' -- '18960' -- '18976' -- '19008' -- '19072' -- '19200' -- '19456' -- '19457' -- '19458' -- '19460' -- '19464' -- '19472' -- '19488' -- '19520' -- '19584' -- '19712' -- '19968' -- '20480' -- '20481' -- '20482' -- '20483' -- '20484' -- '20485' -- '20486' -- '20488' -- '20489' -- '20490' -- '20492' -- '20496' -- '20497' -- '20498' -- '20500' -- '20504' -- '20512' -- '20513' -- '20514' -- '20516' -- '20520' -- '20528' -- '20544' -- '20545' -- '20546' -- '20548' -- '20552' -- '20560' -- '20576' -- '20608' -- '20609' -- '20610' -- '20612' -- '20616' -- '20624' -- '20640' -- '20672' -- '20736' -- '20737' -- '20738' -- '20740' -- '20744' -- '20752' -- '20768' -- '20800' -- '20864' -- '20992' -- '20993' -- '20994' -- '20996' -- '21000' -- '21008' -- '21024' -- '21056' -- '21120' -- '21248' -- '21504' -- '21505' -- '21506' -- '21508' -- '21512' -- '21520' -- '21536' -- '21568' -- '21632' -- '21760' -- '22016' -- '22528' -- '22529' -- '22530' -- '22532' -- '22536' -- '22544' -- '22560' -- '22592' -- '22656' -- '22784' -- '23040' -- '23552' -- '24576' -- '24577' -- '24578' -- '24579' -- '24580' -- '24581' -- '24582' -- '24584' -- '24585' -- '24586' -- '24588' -- '24592' -- '24593' -- '24594' -- '24596' -- '24600' -- '24608' -- '24609' -- '24610' -- '24612' -- '24616' -- '24624' -- '24640' -- '24641' -- '24642' -- '24644' -- '24648' -- '24656' -- '24672' -- '24704' -- '24705' -- '24706' -- '24708' -- '24712' -- '24720' -- '24736' -- '24768' -- '24832' -- '24833' -- '24834' -- '24836' -- '24840' -- '24848' -- '24864' -- '24896' -- '24960' -- '25088' -- '25089' -- '25090' -- '25092' -- '25096' -- '25104' -- '25120' -- '25152' -- '25216' -- '25344' -- '25600' -- '25601' -- '25602' -- '25604' -- '25608' -- '25616' -- '25632' -- '25664' -- '25728' -- '25856' -- '26112' -- '26624' -- '26625' -- '26626' -- '26628' -- '26632' -- '26640' -- '26656' -- '26688' -- '26752' -- '26880' -- '27136' -- '27648' -- '28672' -- '28673' -- '28674' -- '28676' -- '28680' -- '28688' -- '28704' -- '28736' -- '28800' -- '28928' -- '29184' -- '29696' -- '30720' -- '32768' -- '32769' -- '32770' -- '32771' -- '32772' -- '32773' -- '32774' -- '32775' -- '32776' -- '32777' -- '32778' -- '32779' -- '32780' -- '32781' -- '32782' -- '32784' -- '32785' -- '32786' -- '32787' -- '32788' -- '32789' -- '32790' -- '32792' -- '32793' -- '32794' -- '32796' -- '32800' -- '32801' -- '32802' -- '32803' -- '32804' -- '32805' -- '32806' -- '32808' -- '32809' -- '32810' -- '32812' -- '32816' -- '32817' -- '32818' -- '32820' -- '32824' -- '32832' -- '32833' -- '32834' -- '32835' -- '32836' -- '32837' -- '32838' -- '32840' -- '32841' -- '32842' -- '32844' -- '32848' -- '32849' -- '32850' -- '32852' -- '32856' -- '32864' -- '32865' -- '32866' -- '32868' -- '32872' -- '32880' -- '32896' -- '32897' -- '32898' -- '32899' -- '32900' -- '32901' -- '32902' -- '32904' -- '32905' -- '32906' -- '32908' -- '32912' -- '32913' -- '32914' -- '32916' -- '32920' -- '32928' -- '32929' -- '32930' -- '32932' -- '32936' -- '32944' -- '32960' -- '32961' -- '32962' -- '32964' -- '32968' -- '32976' -- '32992' -- '33024' -- '33025' -- '33026' -- '33027' -- '33028' -- '33029' -- '33030' -- '33032' -- '33033' -- '33034' -- '33036' -- '33040' -- '33041' -- '33042' -- '33044' -- '33048' -- '33056' -- '33057' -- '33058' -- '33060' -- '33064' -- '33072' -- '33088' -- '33089' -- '33090' -- '33092' -- '33096' -- '33104' -- '33120' -- '33152' -- '33153' -- '33154' -- '33156' -- '33160' -- '33168' -- '33184' -- '33216' -- '33280' -- '33281' -- '33282' -- '33283' -- '33284' -- '33285' -- '33286' -- '33288' -- '33289' -- '33290' -- '33292' -- '33296' -- '33297' -- '33298' -- '33300' -- '33304' -- '33312' -- '33313' -- '33314' -- '33316' -- '33320' -- '33328' -- '33344' -- '33345' -- '33346' -- '33348' -- '33352' -- '33360' -- '33376' -- '33408' -- '33409' -- '33410' -- '33412' -- '33416' -- '33424' -- '33440' -- '33472' -- '33536' -- '33537' -- '33538' -- '33540' -- '33544' -- '33552' -- '33568' -- '33600' -- '33664' -- '33792' -- '33793' -- '33794' -- '33795' -- '33796' -- '33797' -- '33798' -- '33800' -- '33801' -- '33802' -- '33804' -- '33808' -- '33809' -- '33810' -- '33812' -- '33816' -- '33824' -- '33825' -- '33826' -- '33828' -- '33832' -- '33840' -- '33856' -- '33857' -- '33858' -- '33860' -- '33864' -- '33872' -- '33888' -- '33920' -- '33921' -- '33922' -- '33924' -- '33928' -- '33936' -- '33952' -- '33984' -- '34048' -- '34049' -- '34050' -- '34052' -- '34056' -- '34064' -- '34080' -- '34112' -- '34176' -- '34304' -- '34305' -- '34306' -- '34308' -- '34312' -- '34320' -- '34336' -- '34368' -- '34432' -- '34560' -- '34816' -- '34817' -- '34818' -- '34819' -- '34820' -- '34821' -- '34822' -- '34824' -- '34825' -- '34826' -- '34828' -- '34832' -- '34833' -- '34834' -- '34836' -- '34840' -- '34848' -- '34849' -- '34850' -- '34852' -- '34856' -- '34864' -- '34880' -- '34881' -- '34882' -- '34884' -- '34888' -- '34896' -- '34912' -- '34944' -- '34945' -- '34946' -- '34948' -- '34952' -- '34960' -- '34976' -- '35008' -- '35072' -- '35073' -- '35074' -- '35076' -- '35080' -- '35088' -- '35104' -- '35136' -- '35200' -- '35328' -- '35329' -- '35330' -- '35332' -- '35336' -- '35344' -- '35360' -- '35392' -- '35456' -- '35584' -- '35840' -- '35841' -- '35842' -- '35844' -- '35848' -- '35856' -- '35872' -- '35904' -- '35968' -- '36096' -- '36352' -- '36864' -- '36865' -- '36866' -- '36867' -- '36868' -- '36869' -- '36870' -- '36872' -- '36873' -- '36874' -- '36876' -- '36880' -- '36881' -- '36882' -- '36884' -- '36888' -- '36896' -- '36897' -- '36898' -- '36900' -- '36904' -- '36912' -- '36928' -- '36929' -- '36930' -- '36932' -- '36936' -- '36944' -- '36960' -- '36992' -- '36993' -- '36994' -- '36996' -- '37000' -- '37008' -- '37024' -- '37056' -- '37120' -- '37121' -- '37122' -- '37124' -- '37128' -- '37136' -- '37152' -- '37184' -- '37248' -- '37376' -- '37377' -- '37378' -- '37380' -- '37384' -- '37392' -- '37408' -- '37440' -- '37504' -- '37632' -- '37888' -- '37889' -- '37890' -- '37892' -- '37896' -- '37904' -- '37920' -- '37952' -- '38016' -- '38144' -- '38400' -- '38912' -- '38913' -- '38914' -- '38916' -- '38920' -- '38928' -- '38944' -- '38976' -- '39040' -- '39168' -- '39424' -- '39936' -- '40960' -- '40961' -- '40962' -- '40963' -- '40964' -- '40965' -- '40966' -- '40968' -- '40969' -- '40970' -- '40972' -- '40976' -- '40977' -- '40978' -- '40980' -- '40984' -- '40992' -- '40993' -- '40994' -- '40996' -- '41000' -- '41008' -- '41024' -- '41025' -- '41026' -- '41028' -- '41032' -- '41040' -- '41056' -- '41088' -- '41089' -- '41090' -- '41092' -- '41096' -- '41104' -- '41120' -- '41152' -- '41216' -- '41217' -- '41218' -- '41220' -- '41224' -- '41232' -- '41248' -- '41280' -- '41344' -- '41472' -- '41473' -- '41474' -- '41476' -- '41480' -- '41488' -- '41504' -- '41536' -- '41600' -- '41728' -- '41984' -- '41985' -- '41986' -- '41988' -- '41992' -- '42000' -- '42016' -- '42048' -- '42112' -- '42240' -- '42496' -- '43008' -- '43009' -- '43010' -- '43012' -- '43016' -- '43024' -- '43040' -- '43072' -- '43136' -- '43264' -- '43520' -- '44032' -- '45056' -- '45057' -- '45058' -- '45060' -- '45064' -- '45072' -- '45088' -- '45120' -- '45184' -- '45312' -- '45568' -- '46080' -- '47104' -- '49152' -- '49153' -- '49154' -- '49155' -- '49156' -- '49157' -- '49158' -- '49160' -- '49161' -- '49162' -- '49164' -- '49168' -- '49169' -- '49170' -- '49172' -- '49176' -- '49184' -- '49185' -- '49186' -- '49188' -- '49192' -- '49200' -- '49216' -- '49217' -- '49218' -- '49220' -- '49224' -- '49232' -- '49248' -- '49280' -- '49281' -- '49282' -- '49284' -- '49288' -- '49296' -- '49312' -- '49344' -- '49408' -- '49409' -- '49410' -- '49412' -- '49416' -- '49424' -- '49440' -- '49472' -- '49536' -- '49664' -- '49665' -- '49666' -- '49668' -- '49672' -- '49680' -- '49696' -- '49728' -- '49792' -- '49920' -- '50176' -- '50177' -- '50178' -- '50180' -- '50184' -- '50192' -- '50208' -- '50240' -- '50304' -- '50432' -- '50688' -- '51200' -- '51201' -- '51202' -- '51204' -- '51208' -- '51216' -- '51232' -- '51264' -- '51328' -- '51456' -- '51712' -- '52224' -- '53248' -- '53249' -- '53250' -- '53252' -- '53256' -- '53264' -- '53280' -- '53312' -- '53376' -- '53504' -- '53760' -- '54272' -- '55296' -- '57344' -- '57345' -- '57346' -- '57348' -- '57352' -- '57360' -- '57376' -- '57408' -- '57472' -- '57600' -- '57856' -- '58368' -- '59392' -- '61440' -init: null -input_size: null -cmvn_file: null -ctc_conf: - dropout_rate: 0.0 - ctc_type: builtin - reduce: true - ignore_nan_grad: true -joint_net_conf: null -use_preprocessor: true -token_type: char -bpemodel: null -non_linguistic_symbols: null -cleaner: null -g2p: null -speech_volume_normalize: null -rir_scp: null -rir_apply_prob: 1.0 -noise_scp: null -noise_apply_prob: 1.0 -noise_db_range: '13_15' -specaug: null -specaug_conf: {} -normalize: null -normalize_conf: {} -label_aggregator: null -label_aggregator_conf: {} -model: sond -model_conf: - # ctc_weight: 0.0 - lsm_weight: 0.1 - length_normalized_loss: true - max_spk_num: 16 - # predictor_weight: 1.0 - # predictor_bias: 1 - # sampling_ratio: 0.75 -# speech encoder -encoder: resnet34 -encoder_conf: - # pass by model, equal to feature dim - # input_size: 80 - pooling_type: "window_shift" - pool_size: 20 - stride: 1 - tf2torch_tensor_name_prefix_torch: encoder - tf2torch_tensor_name_prefix_tf: EAND/speech_encoder -speaker_encoder: conv -speaker_encoder_conf: - input_units: 256 - num_layers: 3 - num_units: 256 - kernel_size: 1 - dropout_rate: 0.0 - position_encoder: null - out_units: 256 - out_norm: false - auxiliary_states: false - tf2torch_tensor_name_prefix_torch: speaker_encoder - tf2torch_tensor_name_prefix_tf: EAND/speaker_encoder -ci_scorer: dot -ci_scorer_conf: {} -cd_scorer: san -cd_scorer_conf: - input_size: 512 - output_size: 512 - out_units: 1 - attention_heads: 4 - linear_units: 1024 - num_blocks: 4 - dropout_rate: 0.0 - positional_dropout_rate: 0.0 - attention_dropout_rate: 0.0 - # use string "null" to remove input layer - input_layer: "null" - pos_enc_class: null - normalize_before: true - tf2torch_tensor_name_prefix_torch: cd_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer -# post net -decoder: fsmn -decoder_conf: - in_units: 32 - out_units: 2517 - filter_size: 31 - fsmn_num_layers: 6 - dnn_num_layers: 1 - num_memory_units: 512 - ffn_inner_dim: 512 - dropout_rate: 0.0 - tf2torch_tensor_name_prefix_torch: decoder - tf2torch_tensor_name_prefix_tf: EAND/post_net -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: povey - n_mels: 80 - frame_length: 25 - frame_shift: 10 - filter_length_min: -1 - filter_length_max: -1 - lfr_m: 1 - lfr_n: 1 - dither: 0.0 - snip_edges: false -num_worker_count: 1 -required: -- output_dir -- token_list -oss_bucket: 'null' -version: 0.1.4 diff --git a/egs/alimeeting/diarization/sond/config_fbank.yaml b/egs/alimeeting/diarization/sond/config_fbank.yaml deleted file mode 100644 index cb4b8a921..000000000 --- a/egs/alimeeting/diarization/sond/config_fbank.yaml +++ /dev/null @@ -1,2728 +0,0 @@ -config: finetune.yaml -print_config: false -log_level: INFO -dry_run: false -iterator_type: sequence -output_dir: exp/sond -ngpu: 1 -seed: 0 -num_workers: 16 -num_att_plot: 0 -dist_backend: nccl -dist_init_method: env:// -dist_world_size: null -dist_rank: null -local_rank: 0 -dist_master_addr: null -dist_master_port: null -dist_launcher: null -multiprocessing_distributed: true -distributed: false -unused_parameters: true -sharded_ddp: false -ddp_backend: pytorch_ddp -cudnn_enabled: true -cudnn_benchmark: false -cudnn_deterministic: true -collect_stats: false -write_collected_feats: false -max_epoch: 50 -patience: null -val_scheduler_criterion: -- valid -- acc -early_stopping_criterion: -- valid -- loss -- min -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 -nbest_averaging_interval: 0 -grad_clip: 5 -grad_clip_type: 2.0 -grad_noise: false -accum_grad: 1 -no_forward_run: false -resume: true -train_dtype: float32 -use_amp: false -log_interval: 50 -use_matplotlib: false -use_tensorboard: true -use_wandb: false -wandb_project: null -wandb_id: null -wandb_entity: null -wandb_name: null -wandb_model_log_interval: -1 -use_pai: true -detect_anomaly: false -pretrain_path: null -init_param: [] -ignore_init_mismatch: false -freeze_param: [] -num_iters_per_epoch: null -batch_size: 20 -valid_batch_size: null -batch_bins: 10000 -valid_batch_bins: null -train_shape_file: -- /data/volume1/youyan/aishell/ark/train/speech_shape.1 -- /data/volume1/youyan/aishell/ark/train/text_shape.1 -valid_shape_file: -- /data/volume1/youyan/aishell/ark/dev/speech_shape.1 -- /data/volume1/youyan/aishell/ark/dev/text_shape.1 -batch_type: length -valid_batch_type: null -fold_length: -- 512 -- 150 -sort_in_batch: descending -sort_batch: descending -multiple_iterator: false -chunk_length: 500 -chunk_shift_ratio: 0.5 -num_cache_chunks: 1024 -train_data_path_and_name_and_type: -- - /data/volume1/youyan/aishell/ark/train/data.scp - - speech - - kaldi_ark -- - /data/volume1/youyan/aishell/ark/train/data.text.1 - - text - - text -valid_data_path_and_name_and_type: -- - /data/volume1/youyan/aishell/ark/dev/data.scp - - speech - - kaldi_ark -- - /data/volume1/youyan/aishell/ark/dev/data.text.1 - - text - - text -allow_variable_data_keys: false -max_cache_size: 0.0 -max_cache_fd: 32 -valid_max_cache_size: null -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 -token_list: -- '0' -- '1' -- '2' -- '3' -- '4' -- '5' -- '6' -- '7' -- '8' -- '9' -- '10' -- '11' -- '12' -- '13' -- '14' -- '15' -- '16' -- '17' -- '18' -- '19' -- '20' -- '21' -- '22' -- '23' -- '24' -- '25' -- '26' -- '27' -- '28' -- '29' -- '30' -- '32' -- '33' -- '34' -- '35' -- '36' -- '37' -- '38' -- '39' -- '40' -- '41' -- '42' -- '43' -- '44' -- '45' -- '46' -- '48' -- '49' -- '50' -- '51' -- '52' -- '53' -- '54' -- '56' -- '57' -- '58' -- '60' -- '64' -- '65' -- '66' -- '67' -- '68' -- '69' -- '70' -- '71' -- '72' -- '73' -- '74' -- '75' -- '76' -- '77' -- '78' -- '80' -- '81' -- '82' -- '83' -- '84' -- '85' -- '86' -- '88' -- '89' -- '90' -- '92' -- '96' -- '97' -- '98' -- '99' -- '100' -- '101' -- '102' -- '104' -- '105' -- '106' -- '108' -- '112' -- '113' -- '114' -- '116' -- '120' -- '128' -- '129' -- '130' -- '131' -- '132' -- '133' -- '134' -- '135' -- '136' -- '137' -- '138' -- '139' -- '140' -- '141' -- '142' -- '144' -- '145' -- '146' -- '147' -- '148' -- '149' -- '150' -- '152' -- '153' -- '154' -- '156' -- '160' -- '161' -- '162' -- '163' -- '164' -- '165' -- '166' -- '168' -- '169' -- '170' -- '172' -- '176' -- '177' -- '178' -- '180' -- '184' -- '192' -- '193' -- '194' -- '195' -- '196' -- '197' -- '198' -- '200' -- '201' -- '202' -- '204' -- '208' -- '209' -- '210' -- '212' -- '216' -- '224' -- '225' -- '226' -- '228' -- '232' -- '240' -- '256' -- '257' -- '258' -- '259' -- '260' -- '261' -- '262' -- '263' -- '264' -- '265' -- '266' -- '267' -- '268' -- '269' -- '270' -- '272' -- '273' -- '274' -- '275' -- '276' -- '277' -- '278' -- '280' -- '281' -- '282' -- '284' -- '288' -- '289' -- '290' -- '291' -- '292' -- '293' -- '294' -- '296' -- '297' -- '298' -- '300' -- '304' -- '305' -- '306' -- '308' -- '312' -- '320' -- '321' -- '322' -- '323' -- '324' -- '325' -- '326' -- '328' -- '329' -- '330' -- '332' -- '336' -- '337' -- '338' -- '340' -- '344' -- '352' -- '353' -- '354' -- '356' -- '360' -- '368' -- '384' -- '385' -- '386' -- '387' -- '388' -- '389' -- '390' -- '392' -- '393' -- '394' -- '396' -- '400' -- '401' -- '402' -- '404' -- '408' -- '416' -- '417' -- '418' -- '420' -- '424' -- '432' -- '448' -- '449' -- '450' -- '452' -- '456' -- '464' -- '480' -- '512' -- '513' -- '514' -- '515' -- '516' -- '517' -- '518' -- '519' -- '520' -- '521' -- '522' -- '523' -- '524' -- '525' -- '526' -- '528' -- '529' -- '530' -- '531' -- '532' -- '533' -- '534' -- '536' -- '537' -- '538' -- '540' -- '544' -- '545' -- '546' -- '547' -- '548' -- '549' -- '550' -- '552' -- '553' -- '554' -- '556' -- '560' -- '561' -- '562' -- '564' -- '568' -- '576' -- '577' -- '578' -- '579' -- '580' -- '581' -- '582' -- '584' -- '585' -- '586' -- '588' -- '592' -- '593' -- '594' -- '596' -- '600' -- '608' -- '609' -- '610' -- '612' -- '616' -- '624' -- '640' -- '641' -- '642' -- '643' -- '644' -- '645' -- '646' -- '648' -- '649' -- '650' -- '652' -- '656' -- '657' -- '658' -- '660' -- '664' -- '672' -- '673' -- '674' -- '676' -- '680' -- '688' -- '704' -- '705' -- '706' -- '708' -- '712' -- '720' -- '736' -- '768' -- '769' -- '770' -- '771' -- '772' -- '773' -- '774' -- '776' -- '777' -- '778' -- '780' -- '784' -- '785' -- '786' -- '788' -- '792' -- '800' -- '801' -- '802' -- '804' -- '808' -- '816' -- '832' -- '833' -- '834' -- '836' -- '840' -- '848' -- '864' -- '896' -- '897' -- '898' -- '900' -- '904' -- '912' -- '928' -- '960' -- '1024' -- '1025' -- '1026' -- '1027' -- '1028' -- '1029' -- '1030' -- '1031' -- '1032' -- '1033' -- '1034' -- '1035' -- '1036' -- '1037' -- '1038' -- '1040' -- '1041' -- '1042' -- '1043' -- '1044' -- '1045' -- '1046' -- '1048' -- '1049' -- '1050' -- '1052' -- '1056' -- '1057' -- '1058' -- '1059' -- '1060' -- '1061' -- '1062' -- '1064' -- '1065' -- '1066' -- '1068' -- '1072' -- '1073' -- '1074' -- '1076' -- '1080' -- '1088' -- '1089' -- '1090' -- '1091' -- '1092' -- '1093' -- '1094' -- '1096' -- '1097' -- '1098' -- '1100' -- '1104' -- '1105' -- '1106' -- '1108' -- '1112' -- '1120' -- '1121' -- '1122' -- '1124' -- '1128' -- '1136' -- '1152' -- '1153' -- '1154' -- '1155' -- '1156' -- '1157' -- '1158' -- '1160' -- '1161' -- '1162' -- '1164' -- '1168' -- '1169' -- '1170' -- '1172' -- '1176' -- '1184' -- '1185' -- '1186' -- '1188' -- '1192' -- '1200' -- '1216' -- '1217' -- '1218' -- '1220' -- '1224' -- '1232' -- '1248' -- '1280' -- '1281' -- '1282' -- '1283' -- '1284' -- '1285' -- '1286' -- '1288' -- '1289' -- '1290' -- '1292' -- '1296' -- '1297' -- '1298' -- '1300' -- '1304' -- '1312' -- '1313' -- '1314' -- '1316' -- '1320' -- '1328' -- '1344' -- '1345' -- '1346' -- '1348' -- '1352' -- '1360' -- '1376' -- '1408' -- '1409' -- '1410' -- '1412' -- '1416' -- '1424' -- '1440' -- '1472' -- '1536' -- '1537' -- '1538' -- '1539' -- '1540' -- '1541' -- '1542' -- '1544' -- '1545' -- '1546' -- '1548' -- '1552' -- '1553' -- '1554' -- '1556' -- '1560' -- '1568' -- '1569' -- '1570' -- '1572' -- '1576' -- '1584' -- '1600' -- '1601' -- '1602' -- '1604' -- '1608' -- '1616' -- '1632' -- '1664' -- '1665' -- '1666' -- '1668' -- '1672' -- '1680' -- '1696' -- '1728' -- '1792' -- '1793' -- '1794' -- '1796' -- '1800' -- '1808' -- '1824' -- '1856' -- '1920' -- '2048' -- '2049' -- '2050' -- '2051' -- '2052' -- '2053' -- '2054' -- '2055' -- '2056' -- '2057' -- '2058' -- '2059' -- '2060' -- '2061' -- '2062' -- '2064' -- '2065' -- '2066' -- '2067' -- '2068' -- '2069' -- '2070' -- '2072' -- '2073' -- '2074' -- '2076' -- '2080' -- '2081' -- '2082' -- '2083' -- '2084' -- '2085' -- '2086' -- '2088' -- '2089' -- '2090' -- '2092' -- '2096' -- '2097' -- '2098' -- '2100' -- '2104' -- '2112' -- '2113' -- '2114' -- '2115' -- '2116' -- '2117' -- '2118' -- '2120' -- '2121' -- '2122' -- '2124' -- '2128' -- '2129' -- '2130' -- '2132' -- '2136' -- '2144' -- '2145' -- '2146' -- '2148' -- '2152' -- '2160' -- '2176' -- '2177' -- '2178' -- '2179' -- '2180' -- '2181' -- '2182' -- '2184' -- '2185' -- '2186' -- '2188' -- '2192' -- '2193' -- '2194' -- '2196' -- '2200' -- '2208' -- '2209' -- '2210' -- '2212' -- '2216' -- '2224' -- '2240' -- '2241' -- '2242' -- '2244' -- '2248' -- '2256' -- '2272' -- '2304' -- '2305' -- '2306' -- '2307' -- '2308' -- '2309' -- '2310' -- '2312' -- '2313' -- '2314' -- '2316' -- '2320' -- '2321' -- '2322' -- '2324' -- '2328' -- '2336' -- '2337' -- '2338' -- '2340' -- '2344' -- '2352' -- '2368' -- '2369' -- '2370' -- '2372' -- '2376' -- '2384' -- '2400' -- '2432' -- '2433' -- '2434' -- '2436' -- '2440' -- '2448' -- '2464' -- '2496' -- '2560' -- '2561' -- '2562' -- '2563' -- '2564' -- '2565' -- '2566' -- '2568' -- '2569' -- '2570' -- '2572' -- '2576' -- '2577' -- '2578' -- '2580' -- '2584' -- '2592' -- '2593' -- '2594' -- '2596' -- '2600' -- '2608' -- '2624' -- '2625' -- '2626' -- '2628' -- '2632' -- '2640' -- '2656' -- '2688' -- '2689' -- '2690' -- '2692' -- '2696' -- '2704' -- '2720' -- '2752' -- '2816' -- '2817' -- '2818' -- '2820' -- '2824' -- '2832' -- '2848' -- '2880' -- '2944' -- '3072' -- '3073' -- '3074' -- '3075' -- '3076' -- '3077' -- '3078' -- '3080' -- '3081' -- '3082' -- '3084' -- '3088' -- '3089' -- '3090' -- '3092' -- '3096' -- '3104' -- '3105' -- '3106' -- '3108' -- '3112' -- '3120' -- '3136' -- '3137' -- '3138' -- '3140' -- '3144' -- '3152' -- '3168' -- '3200' -- '3201' -- '3202' -- '3204' -- '3208' -- '3216' -- '3232' -- '3264' -- '3328' -- '3329' -- '3330' -- '3332' -- '3336' -- '3344' -- '3360' -- '3392' -- '3456' -- '3584' -- '3585' -- '3586' -- '3588' -- '3592' -- '3600' -- '3616' -- '3648' -- '3712' -- '3840' -- '4096' -- '4097' -- '4098' -- '4099' -- '4100' -- '4101' -- '4102' -- '4103' -- '4104' -- '4105' -- '4106' -- '4107' -- '4108' -- '4109' -- '4110' -- '4112' -- '4113' -- '4114' -- '4115' -- '4116' -- '4117' -- '4118' -- '4120' -- '4121' -- '4122' -- '4124' -- '4128' -- '4129' -- '4130' -- '4131' -- '4132' -- '4133' -- '4134' -- '4136' -- '4137' -- '4138' -- '4140' -- '4144' -- '4145' -- '4146' -- '4148' -- '4152' -- '4160' -- '4161' -- '4162' -- '4163' -- '4164' -- '4165' -- '4166' -- '4168' -- '4169' -- '4170' -- '4172' -- '4176' -- '4177' -- '4178' -- '4180' -- '4184' -- '4192' -- '4193' -- '4194' -- '4196' -- '4200' -- '4208' -- '4224' -- '4225' -- '4226' -- '4227' -- '4228' -- '4229' -- '4230' -- '4232' -- '4233' -- '4234' -- '4236' -- '4240' -- '4241' -- '4242' -- '4244' -- '4248' -- '4256' -- '4257' -- '4258' -- '4260' -- '4264' -- '4272' -- '4288' -- '4289' -- '4290' -- '4292' -- '4296' -- '4304' -- '4320' -- '4352' -- '4353' -- '4354' -- '4355' -- '4356' -- '4357' -- '4358' -- '4360' -- '4361' -- '4362' -- '4364' -- '4368' -- '4369' -- '4370' -- '4372' -- '4376' -- '4384' -- '4385' -- '4386' -- '4388' -- '4392' -- '4400' -- '4416' -- '4417' -- '4418' -- '4420' -- '4424' -- '4432' -- '4448' -- '4480' -- '4481' -- '4482' -- '4484' -- '4488' -- '4496' -- '4512' -- '4544' -- '4608' -- '4609' -- '4610' -- '4611' -- '4612' -- '4613' -- '4614' -- '4616' -- '4617' -- '4618' -- '4620' -- '4624' -- '4625' -- '4626' -- '4628' -- '4632' -- '4640' -- '4641' -- '4642' -- '4644' -- '4648' -- '4656' -- '4672' -- '4673' -- '4674' -- '4676' -- '4680' -- '4688' -- '4704' -- '4736' -- '4737' -- '4738' -- '4740' -- '4744' -- '4752' -- '4768' -- '4800' -- '4864' -- '4865' -- '4866' -- '4868' -- '4872' -- '4880' -- '4896' -- '4928' -- '4992' -- '5120' -- '5121' -- '5122' -- '5123' -- '5124' -- '5125' -- '5126' -- '5128' -- '5129' -- '5130' -- '5132' -- '5136' -- '5137' -- '5138' -- '5140' -- '5144' -- '5152' -- '5153' -- '5154' -- '5156' -- '5160' -- '5168' -- '5184' -- '5185' -- '5186' -- '5188' -- '5192' -- '5200' -- '5216' -- '5248' -- '5249' -- '5250' -- '5252' -- '5256' -- '5264' -- '5280' -- '5312' -- '5376' -- '5377' -- '5378' -- '5380' -- '5384' -- '5392' -- '5408' -- '5440' -- '5504' -- '5632' -- '5633' -- '5634' -- '5636' -- '5640' -- '5648' -- '5664' -- '5696' -- '5760' -- '5888' -- '6144' -- '6145' -- '6146' -- '6147' -- '6148' -- '6149' -- '6150' -- '6152' -- '6153' -- '6154' -- '6156' -- '6160' -- '6161' -- '6162' -- '6164' -- '6168' -- '6176' -- '6177' -- '6178' -- '6180' -- '6184' -- '6192' -- '6208' -- '6209' -- '6210' -- '6212' -- '6216' -- '6224' -- '6240' -- '6272' -- '6273' -- '6274' -- '6276' -- '6280' -- '6288' -- '6304' -- '6336' -- '6400' -- '6401' -- '6402' -- '6404' -- '6408' -- '6416' -- '6432' -- '6464' -- '6528' -- '6656' -- '6657' -- '6658' -- '6660' -- '6664' -- '6672' -- '6688' -- '6720' -- '6784' -- '6912' -- '7168' -- '7169' -- '7170' -- '7172' -- '7176' -- '7184' -- '7200' -- '7232' -- '7296' -- '7424' -- '7680' -- '8192' -- '8193' -- '8194' -- '8195' -- '8196' -- '8197' -- '8198' -- '8199' -- '8200' -- '8201' -- '8202' -- '8203' -- '8204' -- '8205' -- '8206' -- '8208' -- '8209' -- '8210' -- '8211' -- '8212' -- '8213' -- '8214' -- '8216' -- '8217' -- '8218' -- '8220' -- '8224' -- '8225' -- '8226' -- '8227' -- '8228' -- '8229' -- '8230' -- '8232' -- '8233' -- '8234' -- '8236' -- '8240' -- '8241' -- '8242' -- '8244' -- '8248' -- '8256' -- '8257' -- '8258' -- '8259' -- '8260' -- '8261' -- '8262' -- '8264' -- '8265' -- '8266' -- '8268' -- '8272' -- '8273' -- '8274' -- '8276' -- '8280' -- '8288' -- '8289' -- '8290' -- '8292' -- '8296' -- '8304' -- '8320' -- '8321' -- '8322' -- '8323' -- '8324' -- '8325' -- '8326' -- '8328' -- '8329' -- '8330' -- '8332' -- '8336' -- '8337' -- '8338' -- '8340' -- '8344' -- '8352' -- '8353' -- '8354' -- '8356' -- '8360' -- '8368' -- '8384' -- '8385' -- '8386' -- '8388' -- '8392' -- '8400' -- '8416' -- '8448' -- '8449' -- '8450' -- '8451' -- '8452' -- '8453' -- '8454' -- '8456' -- '8457' -- '8458' -- '8460' -- '8464' -- '8465' -- '8466' -- '8468' -- '8472' -- '8480' -- '8481' -- '8482' -- '8484' -- '8488' -- '8496' -- '8512' -- '8513' -- '8514' -- '8516' -- '8520' -- '8528' -- '8544' -- '8576' -- '8577' -- '8578' -- '8580' -- '8584' -- '8592' -- '8608' -- '8640' -- '8704' -- '8705' -- '8706' -- '8707' -- '8708' -- '8709' -- '8710' -- '8712' -- '8713' -- '8714' -- '8716' -- '8720' -- '8721' -- '8722' -- '8724' -- '8728' -- '8736' -- '8737' -- '8738' -- '8740' -- '8744' -- '8752' -- '8768' -- '8769' -- '8770' -- '8772' -- '8776' -- '8784' -- '8800' -- '8832' -- '8833' -- '8834' -- '8836' -- '8840' -- '8848' -- '8864' -- '8896' -- '8960' -- '8961' -- '8962' -- '8964' -- '8968' -- '8976' -- '8992' -- '9024' -- '9088' -- '9216' -- '9217' -- '9218' -- '9219' -- '9220' -- '9221' -- '9222' -- '9224' -- '9225' -- '9226' -- '9228' -- '9232' -- '9233' -- '9234' -- '9236' -- '9240' -- '9248' -- '9249' -- '9250' -- '9252' -- '9256' -- '9264' -- '9280' -- '9281' -- '9282' -- '9284' -- '9288' -- '9296' -- '9312' -- '9344' -- '9345' -- '9346' -- '9348' -- '9352' -- '9360' -- '9376' -- '9408' -- '9472' -- '9473' -- '9474' -- '9476' -- '9480' -- '9488' -- '9504' -- '9536' -- '9600' -- '9728' -- '9729' -- '9730' -- '9732' -- '9736' -- '9744' -- '9760' -- '9792' -- '9856' -- '9984' -- '10240' -- '10241' -- '10242' -- '10243' -- '10244' -- '10245' -- '10246' -- '10248' -- '10249' -- '10250' -- '10252' -- '10256' -- '10257' -- '10258' -- '10260' -- '10264' -- '10272' -- '10273' -- '10274' -- '10276' -- '10280' -- '10288' -- '10304' -- '10305' -- '10306' -- '10308' -- '10312' -- '10320' -- '10336' -- '10368' -- '10369' -- '10370' -- '10372' -- '10376' -- '10384' -- '10400' -- '10432' -- '10496' -- '10497' -- '10498' -- '10500' -- '10504' -- '10512' -- '10528' -- '10560' -- '10624' -- '10752' -- '10753' -- '10754' -- '10756' -- '10760' -- '10768' -- '10784' -- '10816' -- '10880' -- '11008' -- '11264' -- '11265' -- '11266' -- '11268' -- '11272' -- '11280' -- '11296' -- '11328' -- '11392' -- '11520' -- '11776' -- '12288' -- '12289' -- '12290' -- '12291' -- '12292' -- '12293' -- '12294' -- '12296' -- '12297' -- '12298' -- '12300' -- '12304' -- '12305' -- '12306' -- '12308' -- '12312' -- '12320' -- '12321' -- '12322' -- '12324' -- '12328' -- '12336' -- '12352' -- '12353' -- '12354' -- '12356' -- '12360' -- '12368' -- '12384' -- '12416' -- '12417' -- '12418' -- '12420' -- '12424' -- '12432' -- '12448' -- '12480' -- '12544' -- '12545' -- '12546' -- '12548' -- '12552' -- '12560' -- '12576' -- '12608' -- '12672' -- '12800' -- '12801' -- '12802' -- '12804' -- '12808' -- '12816' -- '12832' -- '12864' -- '12928' -- '13056' -- '13312' -- '13313' -- '13314' -- '13316' -- '13320' -- '13328' -- '13344' -- '13376' -- '13440' -- '13568' -- '13824' -- '14336' -- '14337' -- '14338' -- '14340' -- '14344' -- '14352' -- '14368' -- '14400' -- '14464' -- '14592' -- '14848' -- '15360' -- '16384' -- '16385' -- '16386' -- '16387' -- '16388' -- '16389' -- '16390' -- '16391' -- '16392' -- '16393' -- '16394' -- '16395' -- '16396' -- '16397' -- '16398' -- '16400' -- '16401' -- '16402' -- '16403' -- '16404' -- '16405' -- '16406' -- '16408' -- '16409' -- '16410' -- '16412' -- '16416' -- '16417' -- '16418' -- '16419' -- '16420' -- '16421' -- '16422' -- '16424' -- '16425' -- '16426' -- '16428' -- '16432' -- '16433' -- '16434' -- '16436' -- '16440' -- '16448' -- '16449' -- '16450' -- '16451' -- '16452' -- '16453' -- '16454' -- '16456' -- '16457' -- '16458' -- '16460' -- '16464' -- '16465' -- '16466' -- '16468' -- '16472' -- '16480' -- '16481' -- '16482' -- '16484' -- '16488' -- '16496' -- '16512' -- '16513' -- '16514' -- '16515' -- '16516' -- '16517' -- '16518' -- '16520' -- '16521' -- '16522' -- '16524' -- '16528' -- '16529' -- '16530' -- '16532' -- '16536' -- '16544' -- '16545' -- '16546' -- '16548' -- '16552' -- '16560' -- '16576' -- '16577' -- '16578' -- '16580' -- '16584' -- '16592' -- '16608' -- '16640' -- '16641' -- '16642' -- '16643' -- '16644' -- '16645' -- '16646' -- '16648' -- '16649' -- '16650' -- '16652' -- '16656' -- '16657' -- '16658' -- '16660' -- '16664' -- '16672' -- '16673' -- '16674' -- '16676' -- '16680' -- '16688' -- '16704' -- '16705' -- '16706' -- '16708' -- '16712' -- '16720' -- '16736' -- '16768' -- '16769' -- '16770' -- '16772' -- '16776' -- '16784' -- '16800' -- '16832' -- '16896' -- '16897' -- '16898' -- '16899' -- '16900' -- '16901' -- '16902' -- '16904' -- '16905' -- '16906' -- '16908' -- '16912' -- '16913' -- '16914' -- '16916' -- '16920' -- '16928' -- '16929' -- '16930' -- '16932' -- '16936' -- '16944' -- '16960' -- '16961' -- '16962' -- '16964' -- '16968' -- '16976' -- '16992' -- '17024' -- '17025' -- '17026' -- '17028' -- '17032' -- '17040' -- '17056' -- '17088' -- '17152' -- '17153' -- '17154' -- '17156' -- '17160' -- '17168' -- '17184' -- '17216' -- '17280' -- '17408' -- '17409' -- '17410' -- '17411' -- '17412' -- '17413' -- '17414' -- '17416' -- '17417' -- '17418' -- '17420' -- '17424' -- '17425' -- '17426' -- '17428' -- '17432' -- '17440' -- '17441' -- '17442' -- '17444' -- '17448' -- '17456' -- '17472' -- '17473' -- '17474' -- '17476' -- '17480' -- '17488' -- '17504' -- '17536' -- '17537' -- '17538' -- '17540' -- '17544' -- '17552' -- '17568' -- '17600' -- '17664' -- '17665' -- '17666' -- '17668' -- '17672' -- '17680' -- '17696' -- '17728' -- '17792' -- '17920' -- '17921' -- '17922' -- '17924' -- '17928' -- '17936' -- '17952' -- '17984' -- '18048' -- '18176' -- '18432' -- '18433' -- '18434' -- '18435' -- '18436' -- '18437' -- '18438' -- '18440' -- '18441' -- '18442' -- '18444' -- '18448' -- '18449' -- '18450' -- '18452' -- '18456' -- '18464' -- '18465' -- '18466' -- '18468' -- '18472' -- '18480' -- '18496' -- '18497' -- '18498' -- '18500' -- '18504' -- '18512' -- '18528' -- '18560' -- '18561' -- '18562' -- '18564' -- '18568' -- '18576' -- '18592' -- '18624' -- '18688' -- '18689' -- '18690' -- '18692' -- '18696' -- '18704' -- '18720' -- '18752' -- '18816' -- '18944' -- '18945' -- '18946' -- '18948' -- '18952' -- '18960' -- '18976' -- '19008' -- '19072' -- '19200' -- '19456' -- '19457' -- '19458' -- '19460' -- '19464' -- '19472' -- '19488' -- '19520' -- '19584' -- '19712' -- '19968' -- '20480' -- '20481' -- '20482' -- '20483' -- '20484' -- '20485' -- '20486' -- '20488' -- '20489' -- '20490' -- '20492' -- '20496' -- '20497' -- '20498' -- '20500' -- '20504' -- '20512' -- '20513' -- '20514' -- '20516' -- '20520' -- '20528' -- '20544' -- '20545' -- '20546' -- '20548' -- '20552' -- '20560' -- '20576' -- '20608' -- '20609' -- '20610' -- '20612' -- '20616' -- '20624' -- '20640' -- '20672' -- '20736' -- '20737' -- '20738' -- '20740' -- '20744' -- '20752' -- '20768' -- '20800' -- '20864' -- '20992' -- '20993' -- '20994' -- '20996' -- '21000' -- '21008' -- '21024' -- '21056' -- '21120' -- '21248' -- '21504' -- '21505' -- '21506' -- '21508' -- '21512' -- '21520' -- '21536' -- '21568' -- '21632' -- '21760' -- '22016' -- '22528' -- '22529' -- '22530' -- '22532' -- '22536' -- '22544' -- '22560' -- '22592' -- '22656' -- '22784' -- '23040' -- '23552' -- '24576' -- '24577' -- '24578' -- '24579' -- '24580' -- '24581' -- '24582' -- '24584' -- '24585' -- '24586' -- '24588' -- '24592' -- '24593' -- '24594' -- '24596' -- '24600' -- '24608' -- '24609' -- '24610' -- '24612' -- '24616' -- '24624' -- '24640' -- '24641' -- '24642' -- '24644' -- '24648' -- '24656' -- '24672' -- '24704' -- '24705' -- '24706' -- '24708' -- '24712' -- '24720' -- '24736' -- '24768' -- '24832' -- '24833' -- '24834' -- '24836' -- '24840' -- '24848' -- '24864' -- '24896' -- '24960' -- '25088' -- '25089' -- '25090' -- '25092' -- '25096' -- '25104' -- '25120' -- '25152' -- '25216' -- '25344' -- '25600' -- '25601' -- '25602' -- '25604' -- '25608' -- '25616' -- '25632' -- '25664' -- '25728' -- '25856' -- '26112' -- '26624' -- '26625' -- '26626' -- '26628' -- '26632' -- '26640' -- '26656' -- '26688' -- '26752' -- '26880' -- '27136' -- '27648' -- '28672' -- '28673' -- '28674' -- '28676' -- '28680' -- '28688' -- '28704' -- '28736' -- '28800' -- '28928' -- '29184' -- '29696' -- '30720' -- '32768' -- '32769' -- '32770' -- '32771' -- '32772' -- '32773' -- '32774' -- '32775' -- '32776' -- '32777' -- '32778' -- '32779' -- '32780' -- '32781' -- '32782' -- '32784' -- '32785' -- '32786' -- '32787' -- '32788' -- '32789' -- '32790' -- '32792' -- '32793' -- '32794' -- '32796' -- '32800' -- '32801' -- '32802' -- '32803' -- '32804' -- '32805' -- '32806' -- '32808' -- '32809' -- '32810' -- '32812' -- '32816' -- '32817' -- '32818' -- '32820' -- '32824' -- '32832' -- '32833' -- '32834' -- '32835' -- '32836' -- '32837' -- '32838' -- '32840' -- '32841' -- '32842' -- '32844' -- '32848' -- '32849' -- '32850' -- '32852' -- '32856' -- '32864' -- '32865' -- '32866' -- '32868' -- '32872' -- '32880' -- '32896' -- '32897' -- '32898' -- '32899' -- '32900' -- '32901' -- '32902' -- '32904' -- '32905' -- '32906' -- '32908' -- '32912' -- '32913' -- '32914' -- '32916' -- '32920' -- '32928' -- '32929' -- '32930' -- '32932' -- '32936' -- '32944' -- '32960' -- '32961' -- '32962' -- '32964' -- '32968' -- '32976' -- '32992' -- '33024' -- '33025' -- '33026' -- '33027' -- '33028' -- '33029' -- '33030' -- '33032' -- '33033' -- '33034' -- '33036' -- '33040' -- '33041' -- '33042' -- '33044' -- '33048' -- '33056' -- '33057' -- '33058' -- '33060' -- '33064' -- '33072' -- '33088' -- '33089' -- '33090' -- '33092' -- '33096' -- '33104' -- '33120' -- '33152' -- '33153' -- '33154' -- '33156' -- '33160' -- '33168' -- '33184' -- '33216' -- '33280' -- '33281' -- '33282' -- '33283' -- '33284' -- '33285' -- '33286' -- '33288' -- '33289' -- '33290' -- '33292' -- '33296' -- '33297' -- '33298' -- '33300' -- '33304' -- '33312' -- '33313' -- '33314' -- '33316' -- '33320' -- '33328' -- '33344' -- '33345' -- '33346' -- '33348' -- '33352' -- '33360' -- '33376' -- '33408' -- '33409' -- '33410' -- '33412' -- '33416' -- '33424' -- '33440' -- '33472' -- '33536' -- '33537' -- '33538' -- '33540' -- '33544' -- '33552' -- '33568' -- '33600' -- '33664' -- '33792' -- '33793' -- '33794' -- '33795' -- '33796' -- '33797' -- '33798' -- '33800' -- '33801' -- '33802' -- '33804' -- '33808' -- '33809' -- '33810' -- '33812' -- '33816' -- '33824' -- '33825' -- '33826' -- '33828' -- '33832' -- '33840' -- '33856' -- '33857' -- '33858' -- '33860' -- '33864' -- '33872' -- '33888' -- '33920' -- '33921' -- '33922' -- '33924' -- '33928' -- '33936' -- '33952' -- '33984' -- '34048' -- '34049' -- '34050' -- '34052' -- '34056' -- '34064' -- '34080' -- '34112' -- '34176' -- '34304' -- '34305' -- '34306' -- '34308' -- '34312' -- '34320' -- '34336' -- '34368' -- '34432' -- '34560' -- '34816' -- '34817' -- '34818' -- '34819' -- '34820' -- '34821' -- '34822' -- '34824' -- '34825' -- '34826' -- '34828' -- '34832' -- '34833' -- '34834' -- '34836' -- '34840' -- '34848' -- '34849' -- '34850' -- '34852' -- '34856' -- '34864' -- '34880' -- '34881' -- '34882' -- '34884' -- '34888' -- '34896' -- '34912' -- '34944' -- '34945' -- '34946' -- '34948' -- '34952' -- '34960' -- '34976' -- '35008' -- '35072' -- '35073' -- '35074' -- '35076' -- '35080' -- '35088' -- '35104' -- '35136' -- '35200' -- '35328' -- '35329' -- '35330' -- '35332' -- '35336' -- '35344' -- '35360' -- '35392' -- '35456' -- '35584' -- '35840' -- '35841' -- '35842' -- '35844' -- '35848' -- '35856' -- '35872' -- '35904' -- '35968' -- '36096' -- '36352' -- '36864' -- '36865' -- '36866' -- '36867' -- '36868' -- '36869' -- '36870' -- '36872' -- '36873' -- '36874' -- '36876' -- '36880' -- '36881' -- '36882' -- '36884' -- '36888' -- '36896' -- '36897' -- '36898' -- '36900' -- '36904' -- '36912' -- '36928' -- '36929' -- '36930' -- '36932' -- '36936' -- '36944' -- '36960' -- '36992' -- '36993' -- '36994' -- '36996' -- '37000' -- '37008' -- '37024' -- '37056' -- '37120' -- '37121' -- '37122' -- '37124' -- '37128' -- '37136' -- '37152' -- '37184' -- '37248' -- '37376' -- '37377' -- '37378' -- '37380' -- '37384' -- '37392' -- '37408' -- '37440' -- '37504' -- '37632' -- '37888' -- '37889' -- '37890' -- '37892' -- '37896' -- '37904' -- '37920' -- '37952' -- '38016' -- '38144' -- '38400' -- '38912' -- '38913' -- '38914' -- '38916' -- '38920' -- '38928' -- '38944' -- '38976' -- '39040' -- '39168' -- '39424' -- '39936' -- '40960' -- '40961' -- '40962' -- '40963' -- '40964' -- '40965' -- '40966' -- '40968' -- '40969' -- '40970' -- '40972' -- '40976' -- '40977' -- '40978' -- '40980' -- '40984' -- '40992' -- '40993' -- '40994' -- '40996' -- '41000' -- '41008' -- '41024' -- '41025' -- '41026' -- '41028' -- '41032' -- '41040' -- '41056' -- '41088' -- '41089' -- '41090' -- '41092' -- '41096' -- '41104' -- '41120' -- '41152' -- '41216' -- '41217' -- '41218' -- '41220' -- '41224' -- '41232' -- '41248' -- '41280' -- '41344' -- '41472' -- '41473' -- '41474' -- '41476' -- '41480' -- '41488' -- '41504' -- '41536' -- '41600' -- '41728' -- '41984' -- '41985' -- '41986' -- '41988' -- '41992' -- '42000' -- '42016' -- '42048' -- '42112' -- '42240' -- '42496' -- '43008' -- '43009' -- '43010' -- '43012' -- '43016' -- '43024' -- '43040' -- '43072' -- '43136' -- '43264' -- '43520' -- '44032' -- '45056' -- '45057' -- '45058' -- '45060' -- '45064' -- '45072' -- '45088' -- '45120' -- '45184' -- '45312' -- '45568' -- '46080' -- '47104' -- '49152' -- '49153' -- '49154' -- '49155' -- '49156' -- '49157' -- '49158' -- '49160' -- '49161' -- '49162' -- '49164' -- '49168' -- '49169' -- '49170' -- '49172' -- '49176' -- '49184' -- '49185' -- '49186' -- '49188' -- '49192' -- '49200' -- '49216' -- '49217' -- '49218' -- '49220' -- '49224' -- '49232' -- '49248' -- '49280' -- '49281' -- '49282' -- '49284' -- '49288' -- '49296' -- '49312' -- '49344' -- '49408' -- '49409' -- '49410' -- '49412' -- '49416' -- '49424' -- '49440' -- '49472' -- '49536' -- '49664' -- '49665' -- '49666' -- '49668' -- '49672' -- '49680' -- '49696' -- '49728' -- '49792' -- '49920' -- '50176' -- '50177' -- '50178' -- '50180' -- '50184' -- '50192' -- '50208' -- '50240' -- '50304' -- '50432' -- '50688' -- '51200' -- '51201' -- '51202' -- '51204' -- '51208' -- '51216' -- '51232' -- '51264' -- '51328' -- '51456' -- '51712' -- '52224' -- '53248' -- '53249' -- '53250' -- '53252' -- '53256' -- '53264' -- '53280' -- '53312' -- '53376' -- '53504' -- '53760' -- '54272' -- '55296' -- '57344' -- '57345' -- '57346' -- '57348' -- '57352' -- '57360' -- '57376' -- '57408' -- '57472' -- '57600' -- '57856' -- '58368' -- '59392' -- '61440' -init: null -input_size: 80 -ctc_conf: - dropout_rate: 0.0 - ctc_type: builtin - reduce: true - ignore_nan_grad: true -joint_net_conf: null -use_preprocessor: true -token_type: char -bpemodel: null -non_linguistic_symbols: null -cleaner: null -g2p: null -speech_volume_normalize: null -rir_scp: null -rir_apply_prob: 1.0 -noise_scp: null -noise_apply_prob: 1.0 -noise_db_range: '13_15' -frontend: null -frontend_conf: {} -specaug: null -specaug_conf: {} -normalize: null -normalize_conf: {} -label_aggregator: null -label_aggregator_conf: {} -model: sond -model_conf: - # ctc_weight: 0.0 - lsm_weight: 0.1 - length_normalized_loss: true - max_spk_num: 16 - # predictor_weight: 1.0 - # predictor_bias: 1 - # sampling_ratio: 0.75 -# speech encoder -encoder: resnet34 -encoder_conf: - # pass by model, equal to feature dim - # input_size: 80 - pooling_type: "window_shift" - pool_size: 20 - stride: 1 - tf2torch_tensor_name_prefix_torch: encoder - tf2torch_tensor_name_prefix_tf: EAND/speech_encoder -speaker_encoder: conv -speaker_encoder_conf: - input_units: 256 - num_layers: 3 - num_units: 256 - kernel_size: 1 - dropout_rate: 0.0 - position_encoder: null - out_units: 256 - out_norm: false - auxiliary_states: false - tf2torch_tensor_name_prefix_torch: speaker_encoder - tf2torch_tensor_name_prefix_tf: EAND/speaker_encoder -ci_scorer: dot -ci_scorer_conf: {} -cd_scorer: san -cd_scorer_conf: - input_size: 512 - output_size: 512 - out_units: 1 - attention_heads: 4 - linear_units: 1024 - num_blocks: 4 - dropout_rate: 0.0 - positional_dropout_rate: 0.0 - attention_dropout_rate: 0.0 - # use string "null" to remove input layer - input_layer: "null" - pos_enc_class: null - normalize_before: true - tf2torch_tensor_name_prefix_torch: cd_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer -# post net -decoder: fsmn -decoder_conf: - in_units: 32 - out_units: 2517 - filter_size: 31 - fsmn_num_layers: 6 - dnn_num_layers: 1 - num_memory_units: 512 - ffn_inner_dim: 512 - dropout_rate: 0.0 - tf2torch_tensor_name_prefix_torch: decoder - tf2torch_tensor_name_prefix_tf: EAND/post_net -num_worker_count: 1 -required: -- output_dir -- token_list -oss_bucket: 'null' -version: 0.1.6 diff --git a/egs/alimeeting/diarization/sond/infer_alimeeting_test.py b/egs/alimeeting/diarization/sond/infer_alimeeting_test.py deleted file mode 100644 index b4d534bee..000000000 --- a/egs/alimeeting/diarization/sond/infer_alimeeting_test.py +++ /dev/null @@ -1,24 +0,0 @@ -from funasr.bin.diar_inference_launch import inference_launch -import sys - - -def main(): - diar_config_path = sys.argv[1] if len(sys.argv) > 1 else "sond_fbank.yaml" - diar_model_path = sys.argv[2] if len(sys.argv) > 2 else "sond.pb" - output_dir = sys.argv[3] if len(sys.argv) > 3 else "./outputs" - data_path_and_name_and_type = [ - ("data/test_rmsil/feats.scp", "speech", "kaldi_ark"), - ("data/test_rmsil/test_rmsil_tdnn6_xvec.scp", "profile", "kaldi_ark"), - ] - pipeline = inference_launch( - mode="sond", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - num_workers=1 - ) - pipeline(data_path_and_name_and_type) - - -if __name__ == '__main__': - main() diff --git a/egs/alimeeting/diarization/sond/local/convert_label_to_rttm.py b/egs/alimeeting/diarization/sond/local/convert_label_to_rttm.py deleted file mode 100644 index 880f60fe7..000000000 --- a/egs/alimeeting/diarization/sond/local/convert_label_to_rttm.py +++ /dev/null @@ -1,132 +0,0 @@ -import os -from funasr.utils.job_runner import MultiProcessRunnerV3 -import numpy as np -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict -from collections import OrderedDict -from tqdm import tqdm -from scipy.ndimage import median_filter - - -class MyRunner(MultiProcessRunnerV3): - def prepare(self, parser): - parser.add_argument("label_txt", type=str) - parser.add_argument("map_scp", type=str) - parser.add_argument("out_rttm", type=str) - parser.add_argument("--n_spk", type=int, default=4) - parser.add_argument("--chunk_len", type=int, default=1600) - parser.add_argument("--shift_len", type=int, default=400) - parser.add_argument("--ignore_len", type=int, default=5) - parser.add_argument("--smooth_size", type=int, default=7) - parser.add_argument("--vote_prob", type=float, default=0.5) - args = parser.parse_args() - - if not os.path.exists(os.path.dirname(args.out_rttm)): - os.makedirs(os.path.dirname(args.out_rttm)) - - utt2labels = load_scp_as_list(args.label_txt, 'list') - utt2labels = sorted(utt2labels, key=lambda x: x[0]) - meeting2map = load_scp_as_dict(args.map_scp) - meeting2labels = OrderedDict() - for utt_id, chunk_label in utt2labels: - mid = utt_id.split("-")[0] - if mid not in meeting2labels: - meeting2labels[mid] = [] - meeting2labels[mid].append(chunk_label) - task_list = [(mid, labels, meeting2map[mid]) for mid, labels in meeting2labels.items()] - - return task_list, None, args - - def post(self, result_list, args): - with open(args.out_rttm, "wt") as fd: - for results in result_list: - fd.writelines(results) - - -def int2vec(x, vec_dim=8, dtype=np.int): - b = ('{:0' + str(vec_dim) + 'b}').format(x) - # little-endian order: lower bit first - return (np.array(list(b)[::-1]) == '1').astype(dtype) - - -def seq2arr(seq, vec_dim=8): - return np.row_stack([int2vec(int(x), vec_dim) for x in seq]) - - -def sample2ms(sample, sr=16000): - return int(float(sample) / sr * 100) - - -def calc_multi_labels(chunk_label_list, chunk_len, shift_len, n_spk, vote_prob=0.5): - n_chunk = len(chunk_label_list) - last_chunk_valid_frame = len(chunk_label_list[-1]) - (chunk_len - shift_len) - n_frame = (n_chunk - 2) * shift_len + chunk_len + last_chunk_valid_frame - multi_labels = np.zeros((n_frame, n_spk), dtype=float) - weight = np.zeros((n_frame, 1), dtype=float) - for i in range(n_chunk): - raw_label = chunk_label_list[i] - for k in range(len(raw_label)): - if raw_label[k] == '': - raw_label[k] = raw_label[k-1] if k > 0 else '0' - chunk_multi_label = seq2arr(raw_label, n_spk) - chunk_len = chunk_multi_label.shape[0] - multi_labels[i*shift_len:i*shift_len+chunk_len, :] += chunk_multi_label - weight[i*shift_len:i*shift_len+chunk_len, :] += 1 - multi_labels = multi_labels / weight # normalizing vote - multi_labels = (multi_labels > vote_prob).astype(int) # voting results - return multi_labels - - -def calc_spk_turns(label_arr, spk_list): - turn_list = [] - length = label_arr.shape[0] - n_spk = label_arr.shape[1] - for k in range(n_spk): - if spk_list[k] == "None": - continue - in_utt = False - start = 0 - for i in range(length): - if label_arr[i, k] == 1 and in_utt is False: - start = i - in_utt = True - if label_arr[i, k] == 0 and in_utt is True: - turn_list.append([spk_list[k], start, i - start]) - in_utt = False - if in_utt: - turn_list.append([spk_list[k], start, length - start]) - return turn_list - - -def smooth_multi_labels(multi_label, win_len): - multi_label = median_filter(multi_label, (win_len, 1), mode="constant", cval=0.0).astype(int) - return multi_label - - -def process(task_args): - _, task_list, _, args = task_args - spk_list = ["spk{}".format(i+1) for i in range(args.n_spk)] - template = "SPEAKER {} 1 {:.2f} {:.2f} {} \n" - results = [] - for mid, chunk_label_list, map_file_path in tqdm(task_list, total=len(task_list), ascii=True, disable=args.no_pbar): - utt2map = load_scp_as_list(map_file_path, 'list') - multi_labels = calc_multi_labels(chunk_label_list, args.chunk_len, args.shift_len, args.n_spk, args.vote_prob) - multi_labels = smooth_multi_labels(multi_labels, args.smooth_size) - org_len = sample2ms(int(utt2map[-1][1][1]), args.sr) - org_multi_labels = np.zeros((org_len, args.n_spk)) - for seg_id, [org_st, org_ed, st, ed] in utt2map: - org_st, org_dur = sample2ms(int(org_st), args.sr), sample2ms(int(org_ed) - int(org_st), args.sr) - st, dur = sample2ms(int(st), args.sr), sample2ms(int(ed) - int(st), args.sr) - ll = min(org_multi_labels[org_st: org_st+org_dur, :].shape[0], multi_labels[st: st+dur, :].shape[0]) - org_multi_labels[org_st: org_st+ll, :] = multi_labels[st: st+ll, :] - spk_turns = calc_spk_turns(org_multi_labels, spk_list) - spk_turns = sorted(spk_turns, key=lambda x: x[1]) - for spk, st, dur in spk_turns: - # TODO: handle the leak of segments at the change points - if dur > args.ignore_len: - results.append(template.format(mid, float(st)/100, float(dur)/100, spk)) - return results - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/alimeeting/diarization/sond/path.sh b/egs/alimeeting/diarization/sond/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/alimeeting/diarization/sond/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/alimeeting/diarization/sond/run.sh b/egs/alimeeting/diarization/sond/run.sh deleted file mode 100644 index 19ae40cdd..000000000 --- a/egs/alimeeting/diarization/sond/run.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -. ./path.sh || exit 1; - -stage=0 -stop_stage=2 - -. utils/parse_options.sh || exit 1; - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "Downloading AliMeeting test set data..." - wget https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/alimeeting_test_data_for_sond.tar.gz - echo "Done. Extracting data..." - tar zxf alimeeting_test_data_for_sond.tar.gz - echo "Done." - - echo "Downloading Pre-trained model..." - git clone https://www.modelscope.cn/damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch.git - git clone https://www.modelscope.cn/damo/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch.git - ln -s speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/sv.pb ./sv.pb - cp speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/sv.yaml ./sv.yaml - ln -s speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch/sond.pb ./sond.pb - cp speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch/sond_fbank.yaml ./sond_fbank.yaml - cp speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch/sond.yaml ./sond.yaml - echo "Done." - - echo "Downloading dscore for scoring..." - git clone https://github.com/nryant/dscore.git -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "Calculating diarization results..." - python infer_alimeeting_test.py sond_fbank.yaml sond.pb outputs - python local/convert_label_to_rttm.py \ - outputs/labels.txt \ - data/test_rmsil/raw_rmsil_map.scp \ - outputs/prediction_sm_83.rttm \ - --ignore_len 10 --no_pbar --smooth_size 83 \ - --vote_prob 0.5 --n_spk 16 -fi - -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "Scoring..." - python dscore/score.py \ - -r data/test_rmsil/test_org.crttm \ - -s outputs/prediction_sm_83.rttm \ - --collar 0.25 -fi diff --git a/egs/alimeeting/diarization/sond/unit_test.py b/egs/alimeeting/diarization/sond/unit_test.py deleted file mode 100644 index 0f40ab29e..000000000 --- a/egs/alimeeting/diarization/sond/unit_test.py +++ /dev/null @@ -1,97 +0,0 @@ -from funasr.bin.diar_inference_launch import inference_launch -import os - - -def test_fbank_cpu_infer(): - diar_config_path = "config_fbank.yaml" - diar_model_path = "sond.pb" - output_dir = "./outputs" - data_path_and_name_and_type = [ - ("data/unit_test/test_feats.scp", "speech", "kaldi_ark"), - ("data/unit_test/test_profile.scp", "profile", "kaldi_ark"), - ] - pipeline = inference_launch( - mode="sond", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - num_workers=1, - log_level="WARNING", - ) - results = pipeline(data_path_and_name_and_type) - print(results) - - -def test_fbank_gpu_infer(): - diar_config_path = "config_fbank.yaml" - diar_model_path = "sond.pb" - output_dir = "./outputs" - data_path_and_name_and_type = [ - ("data/unit_test/test_feats.scp", "speech", "kaldi_ark"), - ("data/unit_test/test_profile.scp", "profile", "kaldi_ark"), - ] - pipeline = inference_launch( - mode="sond", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - ngpu=1, - num_workers=1, - log_level="WARNING", - ) - results = pipeline(data_path_and_name_and_type) - print(results) - - -def test_wav_gpu_infer(): - diar_config_path = "config.yaml" - diar_model_path = "sond.pb" - output_dir = "./outputs" - data_path_and_name_and_type = [ - ("data/unit_test/test_wav.scp", "speech", "sound"), - ("data/unit_test/test_profile.scp", "profile", "kaldi_ark"), - ] - pipeline = inference_launch( - mode="sond", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - ngpu=1, - num_workers=1, - log_level="WARNING", - ) - results = pipeline(data_path_and_name_and_type) - print(results) - - -def test_without_profile_gpu_infer(): - diar_config_path = "config.yaml" - diar_model_path = "sond.pb" - output_dir = "./outputs" - raw_inputs = [[ - "data/unit_test/raw_inputs/record.wav", - "data/unit_test/raw_inputs/spk1.wav", - "data/unit_test/raw_inputs/spk2.wav", - "data/unit_test/raw_inputs/spk3.wav", - "data/unit_test/raw_inputs/spk4.wav" - ]] - pipeline = inference_launch( - mode="sond_demo", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - ngpu=1, - num_workers=1, - log_level="WARNING", - param_dict={}, - ) - results = pipeline(raw_inputs=raw_inputs) - print(results) - - -if __name__ == '__main__': - os.environ["CUDA_VISIBLE_DEVICES"] = "0" - test_fbank_cpu_infer() - test_fbank_gpu_infer() - test_wav_gpu_infer() - test_without_profile_gpu_infer() diff --git a/egs/alimeeting/diarization/sond/unit_test_modelscope.py b/egs/alimeeting/diarization/sond/unit_test_modelscope.py deleted file mode 100644 index ea543e102..000000000 --- a/egs/alimeeting/diarization/sond/unit_test_modelscope.py +++ /dev/null @@ -1,92 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -import numpy as np -import os - - -def test_wav_cpu_infer(): - output_dir = "./outputs" - data_path_and_name_and_type = [ - "data/unit_test/test_wav.scp,speech,sound", - "data/unit_test/test_profile.scp,profile,kaldi_ark", - ] - diar_pipeline = pipeline( - task=Tasks.speaker_diarization, - model='damo/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch', - mode="sond", - output_dir=output_dir, - num_workers=0, - log_level="WARNING", - ) - results = diar_pipeline(data_path_and_name_and_type) - print(results) - - -def test_wav_gpu_infer(): - output_dir = "./outputs" - data_path_and_name_and_type = [ - "data/unit_test/test_wav.scp,speech,sound", - "data/unit_test/test_profile.scp,profile,kaldi_ark", - ] - diar_pipeline = pipeline( - task=Tasks.speaker_diarization, - model='damo/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch', - mode="sond", - output_dir=output_dir, - num_workers=0, - log_level="WARNING", - ) - results = diar_pipeline(data_path_and_name_and_type) - print(results) - - -def test_without_profile_gpu_infer(): - raw_inputs = [ - "data/unit_test/raw_inputs/record.wav", - "data/unit_test/raw_inputs/spk1.wav", - "data/unit_test/raw_inputs/spk2.wav", - "data/unit_test/raw_inputs/spk3.wav", - "data/unit_test/raw_inputs/spk4.wav" - ] - diar_pipeline = pipeline( - task=Tasks.speaker_diarization, - model='damo/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch', - mode="sond_demo", - sv_model="damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch", - sv_model_revision="master", - num_workers=0, - log_level="WARNING", - param_dict={}, - ) - results = diar_pipeline(raw_inputs) - print(results) - - -def test_url_without_profile_gpu_infer(): - raw_inputs = [ - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/record.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk1.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk2.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk3.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk4.wav", - ] - diar_pipeline = pipeline( - task=Tasks.speaker_diarization, - model='damo/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch', - mode="sond_demo", - sv_model="damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch", - sv_model_revision="master", - num_workers=0, - log_level="WARNING", - param_dict={}, - ) - results = diar_pipeline(raw_inputs) - print(results) - - -if __name__ == '__main__': - os.environ["CUDA_VISIBLE_DEVICES"] = "0" - test_wav_cpu_infer() - test_wav_gpu_infer() - test_without_profile_gpu_infer() - test_url_without_profile_gpu_infer() diff --git a/egs/alimeeting/modular_sa_asr/README.md b/egs/alimeeting/modular_sa_asr/README.md deleted file mode 100644 index f2779e681..000000000 --- a/egs/alimeeting/modular_sa_asr/README.md +++ /dev/null @@ -1,103 +0,0 @@ -# Get Started -This is an official modular SA-ASR system used in M2MeT 2.0 challenge. We developed this system based on various pre-trained models after the challenge and reach the ***SOTA***(until 2023.8.9) performance on the AliMeeting *Test_2023* set. You can also transcribe your own dataset by preparing it into the specific format shown in - -# Dependency - -To run this receipe, you should install [Kaldi](https://github.com/kaldi-asr/kaldi) and set the `KALDI_ROOT` in `path.sh`. -```shell -export KALDI_ROOT=/your_kaldi_path -``` - -We use the [VBx](https://github.com/BUTSpeechFIT/VBx) to provide initial diarization result to SOND and [dscore](https://github.com/nryant/dscore.git) to compute the DER. You should clone them before running this receipe. -```shell -$ mkdir VBx && cd VBx -$ git init -$ git remote add origin https://github.com/BUTSpeechFIT/VBx.git -$ git config core.sparsecheckout true -$ echo "VBx/*" >> .git/info/sparse-checkout -$ git pull origin master -$ mv VBx/* . -$ cd .. -$ git clone https://github.com/nryant/dscore.git -``` - -We use the [pb_chime5](https://github.com/fgnt/pb_chime5) to perform GSS. So you should install the dependencies of this repo using the following command. -```shell -$ git clone https://github.com/fgnt/pb_chime5.git -$ cd pb_chime5 -$ git submodule init -$ git submodule update -$ pip install -e pb_bss/ -$ pip install -e . -``` - -# Infer on the AliMeeting Test_2023 set -We follow the workflow shown below. - -

- -First you should set the `DATA_SOURCE` in `path.sh` to the data path. Your data path should be organized as follow: -```shell -Test_2023_Ali_far_release -|—— audio_dir/ -| |—— R1014_M1710.wav -| |—— R1014_M1750.wav -| |—— ... -|—— textgrid_dir/ -| |—— R1014_M1710.textgrid -| |—— R1014_M1750.textgrid -| |—— ... -|—— wav.scp -|—— segments -``` - -Then you can do speaker diarization with following command. -```shell -$ bash run_diar.sh -``` -After diarization, you can check the result at the last line of `data/Test_2023_Ali_far_sond/dia_outputs/dia_result`. You should get a DER about 1.51%. - -When you get the similar diarization result with us, then you can do the WPE and GSS using the following command. -```shell -$ bash run_enh.sh 8 -``` - -The number 8 should be replaced with the channel number of your dataset. Here we use the AliMeeting corpus which has 8 channels. - -Finally, you can decode the processed audio with the pre-trained ASR model directly using the flollowing commands. -```shell -$ bash run_asr.sh --stage 0 --stop-stage 1 -$ bash run_asr.sh --stage 3 --stop-stage 3 -``` -The ASR result is saved at `./speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/decode_Test_2023_Ali_far_wpegss/text_cpcer`. - -# Infer on the AliMeeting Test_2023 set after finetune -You can finetune the pre-trained ASR model with the AliMeeting train set to obtain a further reduction on the cpCER. To infer on the AliMeeting Test 2023 set after finetuning, you can run this commands after the train set is processed with WPE and GSS mentioned above. - ```shell -$ bash run_asr.sh --stage 2 --stop-stage 3 -``` - -# Infer with your own dataset -We also support infer with your own dataset. Your dataset should be organized as above. The `wav.scp` and `segments` file should format as: - ```shell -# wav.scp -sessionA wav_path/wav_name_A.wav -sessionB wav_path/wav_name_B.wav -sessionC wav_path/wav_name_C.wav -... - -# segments -sessionA-start_time-end_time sessionA start_time end_time -sessionB-start_time-end_time sessionA start_time end_time -sessionC-start_time-end_time sessionA start_time end_time -... -``` -Then you should set the `DATA_SOURCE` and `DATA_NAME` in `path.sh`. The rest of the process is the same as [Infer on the AliMeeting Test_2023 set](#infer-on-the-alimeeting-test_2023-set). - -# Result - -| |VBx DER(%) | SOND DER(%)|cp-CER(%) | -|:---------------|:------------:|:------------:|----------:| -|before finetune | 16.87 | 1.51 | 10.18 | -|after finetune | 16.87 | 1.51 | **8.84** | - diff --git a/egs/alimeeting/modular_sa_asr/conf/mfcc_hires.conf b/egs/alimeeting/modular_sa_asr/conf/mfcc_hires.conf deleted file mode 100644 index 7fc2ecbaa..000000000 --- a/egs/alimeeting/modular_sa_asr/conf/mfcc_hires.conf +++ /dev/null @@ -1,11 +0,0 @@ -# config for high-resolution MFCC features, intended for neural network training. -# Note: we keep all cepstra, so it has the same info as filterbank features, -# but MFCC is more easily compressible (because less correlated) which is why -# we prefer this method. ---use-energy=false # use average of log energy, not energy. ---sample-frequency=16000 ---num-mel-bins=40 ---num-ceps=40 ---low-freq=40 ---high-freq=-400 - diff --git a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/cmvn_opts b/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/cmvn_opts deleted file mode 100755 index 117f4ebcf..000000000 --- a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/cmvn_opts +++ /dev/null @@ -1 +0,0 @@ ---norm-means=false --norm-vars=false diff --git a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/final.raw b/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/final.raw deleted file mode 100755 index 95269b512..000000000 Binary files a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/final.raw and /dev/null differ diff --git a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/frame_subsampling_factor b/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/frame_subsampling_factor deleted file mode 100755 index 00750edc0..000000000 --- a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/frame_subsampling_factor +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/lda.mat b/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/lda.mat deleted file mode 100755 index 2578e66e9..000000000 Binary files a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/lda.mat and /dev/null differ diff --git a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/lda_stats b/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/lda_stats deleted file mode 100755 index 9670405f1..000000000 Binary files a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/lda_stats and /dev/null differ diff --git a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/post_output.vec b/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/post_output.vec deleted file mode 100755 index c0b7428fa..000000000 --- a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/post_output.vec +++ /dev/null @@ -1 +0,0 @@ - [ 30 2 1 ] diff --git a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/srand b/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/srand deleted file mode 100755 index c22708346..000000000 --- a/egs/alimeeting/modular_sa_asr/exp/segmentation_1a/tdnn_stats_sad_1a/srand +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/egs/alimeeting/modular_sa_asr/figure/20230809161919.jpg b/egs/alimeeting/modular_sa_asr/figure/20230809161919.jpg deleted file mode 100644 index 79afba1a9..000000000 Binary files a/egs/alimeeting/modular_sa_asr/figure/20230809161919.jpg and /dev/null differ diff --git a/egs/alimeeting/modular_sa_asr/local/compute_cpcer.py b/egs/alimeeting/modular_sa_asr/local/compute_cpcer.py deleted file mode 100644 index 7468a5489..000000000 --- a/egs/alimeeting/modular_sa_asr/local/compute_cpcer.py +++ /dev/null @@ -1,103 +0,0 @@ -import editdistance -import sys -import os -from itertools import permutations - - -def load_transcripts(file_path): - trans_list = [] - for one_line in open(file_path, "rt"): - meeting_id, trans = one_line.strip().split(" ") - trans_list.append((meeting_id.strip(), trans.strip())) - - return trans_list - -def calc_spk_trans(trans): - spk_trans_ = [x.strip() for x in trans.split("$")] - spk_trans = [] - for i in range(len(spk_trans_)): - spk_trans.append((str(i), spk_trans_[i])) - return spk_trans - -def calc_cer(ref_trans, hyp_trans): - ref_spk_trans = calc_spk_trans(ref_trans) - hyp_spk_trans = calc_spk_trans(hyp_trans) - ref_spk_num, hyp_spk_num = len(ref_spk_trans), len(hyp_spk_trans) - num_spk = max(len(ref_spk_trans), len(hyp_spk_trans)) - ref_spk_trans.extend([("", "")] * (num_spk - len(ref_spk_trans))) - hyp_spk_trans.extend([("", "")] * (num_spk - len(hyp_spk_trans))) - - errors, counts, permutes = [], [], [] - min_error = 0 - cost_dict = {} - for perm in permutations(range(num_spk)): - flag = True - p_err, p_count = 0, 0 - for idx, p in enumerate(perm): - if abs(len(ref_spk_trans[idx][1]) - len(hyp_spk_trans[p][1])) > min_error > 0: - flag = False - break - cost_key = "{}-{}".format(idx, p) - if cost_key in cost_dict: - _e = cost_dict[cost_key] - else: - _e = editdistance.eval(ref_spk_trans[idx][1], hyp_spk_trans[p][1]) - cost_dict[cost_key] = _e - if _e > min_error > 0: - flag = False - break - p_err += _e - p_count += len(ref_spk_trans[idx][1]) - - if flag: - if p_err < min_error or min_error == 0: - min_error = p_err - - errors.append(p_err) - counts.append(p_count) - permutes.append(perm) - - sd_cer = [(err, cnt, err/cnt, permute) - for err, cnt, permute in zip(errors, counts, permutes)] - best_rst = min(sd_cer, key=lambda x: x[2]) - - return best_rst[0], best_rst[1], ref_spk_num, hyp_spk_num - - -def main(): - ref=sys.argv[1] - hyp=sys.argv[2] - result_path="/".join(hyp.split("/")[:-1]) + "/text_cpcer" - ref_list = load_transcripts(ref) - hyp_list = load_transcripts(hyp) - result_file = open(result_path,'w') - record_2_spk = [0, 0] - record_3_spk = [0, 0] - record_4_spk = [0, 0] - error, count = 0, 0 - for (ref_id, ref_trans), (hyp_id, hyp_trans) in zip(ref_list, hyp_list): - assert ref_id == hyp_id - mid = ref_id - dist, length, ref_spk_num, hyp_spk_num = calc_cer(ref_trans, hyp_trans) - error, count = error + dist, count + length - result_file.write("{} {:.2f} {} {}\n".format(mid, dist / length * 100.0, ref_spk_num, hyp_spk_num)) - ref_spk = len(ref_trans.split("$")) - hyp_spk = len(hyp_trans.split("$")) - if ref_spk == 2: - record_2_spk[0] += dist - record_2_spk[1] += length - elif ref_spk == 3: - record_3_spk[0] += dist - record_3_spk[1] += length - else: - record_4_spk[0] += dist - record_4_spk[1] += length - print(record_2_spk[0]/record_2_spk[1]*100.0) - print(record_3_spk[0]/record_3_spk[1]*100.0) - print(record_4_spk[0]/record_4_spk[1]*100.0) - result_file.write("CP-CER: {:.2f}\n".format(error / count * 100.0)) - result_file.close() - - -if __name__ == '__main__': - main() diff --git a/egs/alimeeting/modular_sa_asr/local/convert_label_to_rttm.py b/egs/alimeeting/modular_sa_asr/local/convert_label_to_rttm.py deleted file mode 100644 index 880f60fe7..000000000 --- a/egs/alimeeting/modular_sa_asr/local/convert_label_to_rttm.py +++ /dev/null @@ -1,132 +0,0 @@ -import os -from funasr.utils.job_runner import MultiProcessRunnerV3 -import numpy as np -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict -from collections import OrderedDict -from tqdm import tqdm -from scipy.ndimage import median_filter - - -class MyRunner(MultiProcessRunnerV3): - def prepare(self, parser): - parser.add_argument("label_txt", type=str) - parser.add_argument("map_scp", type=str) - parser.add_argument("out_rttm", type=str) - parser.add_argument("--n_spk", type=int, default=4) - parser.add_argument("--chunk_len", type=int, default=1600) - parser.add_argument("--shift_len", type=int, default=400) - parser.add_argument("--ignore_len", type=int, default=5) - parser.add_argument("--smooth_size", type=int, default=7) - parser.add_argument("--vote_prob", type=float, default=0.5) - args = parser.parse_args() - - if not os.path.exists(os.path.dirname(args.out_rttm)): - os.makedirs(os.path.dirname(args.out_rttm)) - - utt2labels = load_scp_as_list(args.label_txt, 'list') - utt2labels = sorted(utt2labels, key=lambda x: x[0]) - meeting2map = load_scp_as_dict(args.map_scp) - meeting2labels = OrderedDict() - for utt_id, chunk_label in utt2labels: - mid = utt_id.split("-")[0] - if mid not in meeting2labels: - meeting2labels[mid] = [] - meeting2labels[mid].append(chunk_label) - task_list = [(mid, labels, meeting2map[mid]) for mid, labels in meeting2labels.items()] - - return task_list, None, args - - def post(self, result_list, args): - with open(args.out_rttm, "wt") as fd: - for results in result_list: - fd.writelines(results) - - -def int2vec(x, vec_dim=8, dtype=np.int): - b = ('{:0' + str(vec_dim) + 'b}').format(x) - # little-endian order: lower bit first - return (np.array(list(b)[::-1]) == '1').astype(dtype) - - -def seq2arr(seq, vec_dim=8): - return np.row_stack([int2vec(int(x), vec_dim) for x in seq]) - - -def sample2ms(sample, sr=16000): - return int(float(sample) / sr * 100) - - -def calc_multi_labels(chunk_label_list, chunk_len, shift_len, n_spk, vote_prob=0.5): - n_chunk = len(chunk_label_list) - last_chunk_valid_frame = len(chunk_label_list[-1]) - (chunk_len - shift_len) - n_frame = (n_chunk - 2) * shift_len + chunk_len + last_chunk_valid_frame - multi_labels = np.zeros((n_frame, n_spk), dtype=float) - weight = np.zeros((n_frame, 1), dtype=float) - for i in range(n_chunk): - raw_label = chunk_label_list[i] - for k in range(len(raw_label)): - if raw_label[k] == '': - raw_label[k] = raw_label[k-1] if k > 0 else '0' - chunk_multi_label = seq2arr(raw_label, n_spk) - chunk_len = chunk_multi_label.shape[0] - multi_labels[i*shift_len:i*shift_len+chunk_len, :] += chunk_multi_label - weight[i*shift_len:i*shift_len+chunk_len, :] += 1 - multi_labels = multi_labels / weight # normalizing vote - multi_labels = (multi_labels > vote_prob).astype(int) # voting results - return multi_labels - - -def calc_spk_turns(label_arr, spk_list): - turn_list = [] - length = label_arr.shape[0] - n_spk = label_arr.shape[1] - for k in range(n_spk): - if spk_list[k] == "None": - continue - in_utt = False - start = 0 - for i in range(length): - if label_arr[i, k] == 1 and in_utt is False: - start = i - in_utt = True - if label_arr[i, k] == 0 and in_utt is True: - turn_list.append([spk_list[k], start, i - start]) - in_utt = False - if in_utt: - turn_list.append([spk_list[k], start, length - start]) - return turn_list - - -def smooth_multi_labels(multi_label, win_len): - multi_label = median_filter(multi_label, (win_len, 1), mode="constant", cval=0.0).astype(int) - return multi_label - - -def process(task_args): - _, task_list, _, args = task_args - spk_list = ["spk{}".format(i+1) for i in range(args.n_spk)] - template = "SPEAKER {} 1 {:.2f} {:.2f} {} \n" - results = [] - for mid, chunk_label_list, map_file_path in tqdm(task_list, total=len(task_list), ascii=True, disable=args.no_pbar): - utt2map = load_scp_as_list(map_file_path, 'list') - multi_labels = calc_multi_labels(chunk_label_list, args.chunk_len, args.shift_len, args.n_spk, args.vote_prob) - multi_labels = smooth_multi_labels(multi_labels, args.smooth_size) - org_len = sample2ms(int(utt2map[-1][1][1]), args.sr) - org_multi_labels = np.zeros((org_len, args.n_spk)) - for seg_id, [org_st, org_ed, st, ed] in utt2map: - org_st, org_dur = sample2ms(int(org_st), args.sr), sample2ms(int(org_ed) - int(org_st), args.sr) - st, dur = sample2ms(int(st), args.sr), sample2ms(int(ed) - int(st), args.sr) - ll = min(org_multi_labels[org_st: org_st+org_dur, :].shape[0], multi_labels[st: st+dur, :].shape[0]) - org_multi_labels[org_st: org_st+ll, :] = multi_labels[st: st+ll, :] - spk_turns = calc_spk_turns(org_multi_labels, spk_list) - spk_turns = sorted(spk_turns, key=lambda x: x[1]) - for spk, st, dur in spk_turns: - # TODO: handle the leak of segments at the change points - if dur > args.ignore_len: - results.append(template.format(mid, float(st)/100, float(dur)/100, spk)) - return results - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/alimeeting/modular_sa_asr/local/extract_profile_from_segments.py b/egs/alimeeting/modular_sa_asr/local/extract_profile_from_segments.py deleted file mode 100644 index f46f2b9ac..000000000 --- a/egs/alimeeting/modular_sa_asr/local/extract_profile_from_segments.py +++ /dev/null @@ -1,104 +0,0 @@ -import codecs -import sys -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -import numpy as np -import os -import soundfile - - -data_path = sys.argv[1] -segment_file_path = data_path + "/segments_nooverlap" -utt2spk_file_path = data_path + "/utt2spk_nooverlap" -wav_scp_path = data_path + "/wav.scp" -cluster_emb_dir = data_path + '/cluster_embedding/' -os.system("mkdir -p " + cluster_emb_dir) -cluster_profile_dir = data_path + '/cluster_profile_zeropadding16/' -os.system('mkdir -p ' + cluster_profile_dir) - -utt2spk = {} -spk2seg = {} -with codecs.open(utt2spk_file_path, "r", "utf-8") as f1: - with codecs.open(segment_file_path, "r", "utf-8") as f2: - for line in f1.readlines(): - uttid, spkid = line.strip().split(" ") - utt2spk[uttid] = spkid - for line in f2.readlines(): - uttid, sessionid, stime, etime = line.strip().split(" ") - spkid = utt2spk[uttid] - if spkid not in spk2seg.keys(): - spk2seg[spkid] = [(int(float(stime) * 16000), int(float(etime) * 16000) - int(float(stime) * 16000))] - else: - spk2seg[spkid].append((int(float(stime) * 16000), int(float(etime) * 16000) - int(float(stime) * 16000))) - -inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch', - device='gpu' -) - -wav_dict = {} - -with codecs.open(wav_scp_path, "r", "utf-8") as fi: - with codecs.open(data_path + "/cluster_embedding.scp", "w", "utf-8") as fo: - for line in fi.readlines(): - sessionid, wav_path = line.strip().split() - wav_dict[sessionid] = wav_path - for spkid, segs in spk2seg.items(): - sessionid = spkid.split("-")[0] - wav_path = wav_dict[sessionid] - wav = soundfile.read(wav_path)[0] - if wav.ndim == 2: - wav = wav[:, 0] - all_seg_embedding_list=[] - for seg in segs: - if seg[0] < wav.shape[0] - 0.5 * 16000: - if seg[1] > wav.shape[0]: - cur_seg_embedding = inference_sv_pipline(audio_in=wav[seg[0]: ])["spk_embedding"] - else: - cur_seg_embedding = inference_sv_pipline(audio_in=wav[seg[0]: seg[0] + seg[1]])["spk_embedding"] - all_seg_embedding_list.append(cur_seg_embedding) - all_seg_embedding = np.vstack(all_seg_embedding_list) - spk_embedding = np.mean(all_seg_embedding, axis=0) - np.save(cluster_emb_dir + spkid + '.npy', spk_embedding) - fo.write(spkid + ' ' + cluster_emb_dir + spkid + '.npy' + '\n') - -session2embs = {} - -with codecs.open(data_path + "/cluster_embedding.scp", "r", "utf-8") as fi: - with codecs.open(data_path + "/cluster_profile_zeropadding16.scp", "w", "utf-8") as fo: - for line in fi.readlines(): - spkid, emb_path = line.strip().split(" ") - sessionid = spkid.split("-")[0] - if sessionid not in session2embs.keys(): - session2embs[sessionid] = [emb_path] - else: - session2embs[sessionid].append(emb_path) - for sessionid, embs in session2embs.items(): - emb_list = [np.load(x) for x in embs] - tmp = [] - for i in range(len(emb_list) - 1): - flag = True - for j in range(i + 1, len(emb_list)): - cos_sim = emb_list[i].dot(emb_list[j]) / (np.linalg.norm(emb_list[i]) * np.linalg.norm(emb_list[j])) - if cos_sim > 0.99: - flag = False - if flag: - tmp.append(emb_list[i][np.newaxis, :]) - tmp.append(emb_list[-1][np.newaxis, :]) - emb_list = tmp - # tmp = [] - # for i in range(len(emb_list)): - # for emb in tmp: - # cos_sim = emb_list[i].dot(emb_list[j]) / (np.linalg.norm(emb_list[i]) * np.linalg.norm(emb_list[j])) - # if cos_sim > 0.99: - # flag = False - # if flag: - # tmp.append(emb_list[i][np.newaxis, :]) - # emb_list = tmp - for i in range(16 - len(emb_list)): - emb_list.append(np.zeros((1, 256))) - emb = np.concatenate(emb_list, axis=0) - save_path = cluster_profile_dir + sessionid + ".npy" - np.save(save_path, emb) - fo.write("%s %s\n" % (sessionid, save_path)) \ No newline at end of file diff --git a/egs/alimeeting/modular_sa_asr/local/finetune.py b/egs/alimeeting/modular_sa_asr/local/finetune.py deleted file mode 100644 index 0a434e44c..000000000 --- a/egs/alimeeting/modular_sa_asr/local/finetune.py +++ /dev/null @@ -1,34 +0,0 @@ -import os -import sys -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from modelscope.msdatasets.audio.asr_dataset import ASRDataset - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = ASRDataset.load(params.data_path, namespace='speech_asr') - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - from funasr.utils.modelscope_param import modelscope_args - params = modelscope_args(model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch") - params.output_dir = "./checkpoint" # 模型保存路径 - params.data_path = "./data" # 数据路径,可以为modelscope中已上传数据,也可以是本地数据 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs/alimeeting/modular_sa_asr/local/format_wav_scp.py b/egs/alimeeting/modular_sa_asr/local/format_wav_scp.py deleted file mode 120000 index 3fa0f250e..000000000 --- a/egs/alimeeting/modular_sa_asr/local/format_wav_scp.py +++ /dev/null @@ -1 +0,0 @@ -../../sa_asr/local/format_wav_scp.py \ No newline at end of file diff --git a/egs/alimeeting/modular_sa_asr/local/format_wav_scp.sh b/egs/alimeeting/modular_sa_asr/local/format_wav_scp.sh deleted file mode 120000 index 9c4d4fafd..000000000 --- a/egs/alimeeting/modular_sa_asr/local/format_wav_scp.sh +++ /dev/null @@ -1 +0,0 @@ -../../sa_asr/local/format_wav_scp.sh \ No newline at end of file diff --git a/egs/alimeeting/modular_sa_asr/local/infer_sond.py b/egs/alimeeting/modular_sa_asr/local/infer_sond.py deleted file mode 100644 index c17d5e5c7..000000000 --- a/egs/alimeeting/modular_sa_asr/local/infer_sond.py +++ /dev/null @@ -1,27 +0,0 @@ -from funasr.bin.diar_inference_launch import inference_launch -import sys -import os -os.environ['CUDA_VISIBLE_DEVICES']='7' - -def main(): - diar_config_path = sys.argv[1] if len(sys.argv) > 1 else "sond_fbank.yaml" - diar_model_path = sys.argv[2] if len(sys.argv) > 2 else "sond.pb" - input_dir = sys.argv[3] if len(sys.argv) > 3 else "./inputs" - output_dir = sys.argv[4] if len(sys.argv) > 4 else "./outputs" - data_path_and_name_and_type = [ - (input_dir + "/wav.scp", "speech", "sound"), - (input_dir + "/profile.scp", "profile", "npy"), - ] - pipeline = inference_launch( - mode="sond", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - num_workers=16, - ngpu=1, - ) - pipeline(data_path_and_name_and_type) - - -if __name__ == '__main__': - main() diff --git a/egs/alimeeting/modular_sa_asr/local/make_textgrid_rttm.py b/egs/alimeeting/modular_sa_asr/local/make_textgrid_rttm.py deleted file mode 100755 index 3b6373c78..000000000 --- a/egs/alimeeting/modular_sa_asr/local/make_textgrid_rttm.py +++ /dev/null @@ -1,61 +0,0 @@ -import argparse -import tqdm -import codecs -try: - import textgrid -except: - raise "Please install textgrid firstly: pip install textgrid" -import pdb - -class Segment(object): - def __init__(self, uttid, spkr, stime, etime, text): - self.uttid = uttid - self.spkr = spkr - self.stime = round(stime, 2) - self.etime = round(etime, 2) - self.text = text - - def change_stime(self, time): - self.stime = time - - def change_etime(self, time): - self.etime = time - - -def main(args): - tg = textgrid.TextGrid.fromFile(args.input_textgrid_file) - segments = [] - spk = {} - num_spk = 1 - uttid = args.uttid - for i in range(tg.__len__()): - for j in range(tg[i].__len__()): - if tg[i][j].mark: - if tg[i].name not in spk: - spk[tg[i].name] = num_spk - num_spk += 1 - segments.append( - Segment( - uttid, - spk[tg[i].name], - tg[i][j].minTime, - tg[i][j].maxTime, - tg[i][j].mark.strip(), - ) - ) - segments = sorted(segments, key=lambda x: x.stime) - - rttm_file = codecs.open(args.output_rttm_file, "w", "utf-8") - - for i in range(len(segments)): - fmt = "SPEAKER {:s} 1 {:.2f} {:.2f} {:s} " - #pdb.set_trace() - rttm_file.write(f"{fmt.format(segments[i].uttid, float(segments[i].stime), float(segments[i].etime) - float(segments[i].stime), str(segments[i].spkr))}\n") - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description="Make rttm for true label") - parser.add_argument("--input_textgrid_file", required=True, help="The textgrid file") - parser.add_argument("--output_rttm_file", required=True, help="The output rttm file") - parser.add_argument("--uttid", required=True, help="The utt id of the file") - args = parser.parse_args() - main(args) diff --git a/egs/alimeeting/modular_sa_asr/local/meeting_speaker_number_process.py b/egs/alimeeting/modular_sa_asr/local/meeting_speaker_number_process.py deleted file mode 100755 index 8dc98903c..000000000 --- a/egs/alimeeting/modular_sa_asr/local/meeting_speaker_number_process.py +++ /dev/null @@ -1,86 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Process the textgrid files -""" -import argparse -import codecs -from distutils.util import strtobool -from pathlib import Path -try: - import textgrid -except: - raise "Please install textgrid firstly: pip install textgrid" -import pdb - -class Segment(object): - def __init__(self, uttid, spkr, stime, etime, text): - self.uttid = uttid - self.spkr = spkr - self.stime = round(stime, 2) - self.etime = round(etime, 2) - self.text = text - - def change_stime(self, time): - self.stime = time - - def change_etime(self, time): - self.etime = time - - -def get_args(): - parser = argparse.ArgumentParser(description="process the textgrid files") - parser.add_argument("--path", type=str, required=True, help="textgrid path") - parser.add_argument("--label_path", type=str, required=True, help="label rttm file path") - parser.add_argument("--predict_path", type=str, required=True, help="predict rttm file path") - args = parser.parse_args() - return args - -def main(args): - textgrid_flist = codecs.open(Path(args.path)/"uttid_textgrid.flist", "r", "utf-8") - - - # parse the textgrid file for each utterance - speaker2_uttidset = [] - speaker3_uttidset = [] - speaker4_uttidset = [] - for line in textgrid_flist: - uttid ,textgrid_file = line.strip().split("\t") - tg = textgrid.TextGrid() - tg.read(textgrid_file) - - num_speaker = len(tg) - if num_speaker ==2: - speaker2_uttidset.append(uttid) - elif num_speaker ==3: - speaker3_uttidset.append(uttid) - elif num_speaker ==4: - speaker4_uttidset.append(uttid) - textgrid_flist.close() - - speaker2_id_label = codecs.open(Path(args.label_path) / "speaker2_id", "w", "utf-8") - speaker2_id_predict = codecs.open(Path(args.predict_path) / "speaker2_id", "w", "utf-8") - speaker3_id_label = codecs.open(Path(args.label_path) / "speaker3_id", "w", "utf-8") - speaker3_id_predict = codecs.open(Path(args.predict_path) / "speaker3_id", "w", "utf-8") - speaker4_id_label = codecs.open(Path(args.label_path) / "speaker4_id", "w", "utf-8") - speaker4_id_predict = codecs.open(Path(args.predict_path) / "speaker4_id", "w", "utf-8") - - for i in range(len(speaker2_uttidset)): - speaker2_id_label.write("%s\n" % (args.label_path+"/"+speaker2_uttidset[i]+".rttm")) - speaker2_id_predict.write("%s\n" % (args.predict_path+"/"+speaker2_uttidset[i]+".rttm")) - for i in range(len(speaker3_uttidset)): - speaker3_id_label.write("%s\n" % (args.label_path+"/"+speaker3_uttidset[i]+".rttm")) - speaker3_id_predict.write("%s\n" % (args.predict_path+"/"+speaker3_uttidset[i]+".rttm")) - for i in range(len(speaker4_uttidset)): - speaker4_id_label.write("%s\n" % (args.label_path+"/"+speaker4_uttidset[i]+".rttm")) - speaker4_id_predict.write("%s\n" % (args.predict_path+"/"+speaker4_uttidset[i]+".rttm")) - - speaker2_id_label.close() - speaker2_id_predict.close() - speaker3_id_label.close() - speaker3_id_predict.close() - speaker4_id_label.close() - speaker4_id_predict.close() - -if __name__ == "__main__": - args = get_args() - main(args) diff --git a/egs/alimeeting/modular_sa_asr/local/merge_spk_text.py b/egs/alimeeting/modular_sa_asr/local/merge_spk_text.py deleted file mode 100644 index f700b468b..000000000 --- a/egs/alimeeting/modular_sa_asr/local/merge_spk_text.py +++ /dev/null @@ -1,52 +0,0 @@ -import sys -import codecs -import zhconv - -decode_result = sys.argv[1] -utt2spk_file = sys.argv[2] -merged_result = "/".join(decode_result.split("/")[:-1]) + "/text_merge" - -utt2text = {} -utt2spk = {} -spk2texts = {} -spk2text = {} -meeting2text = {} - -with codecs.open(decode_result, "r", "utf-8") as f1: - with codecs.open(utt2spk_file, "r", "utf-8") as f2: - for line in f1.readlines(): - try: - line_list = line.strip().split() - uttid = line_list[0] - text = "".join(line_list[1:]) - except: - continue - utt2text[uttid] = text - for line in f2.readlines(): - uttid, spkid = line.strip().split() - utt2spk[uttid] = spkid - -for utt, text in utt2text.items(): - spk = utt2spk[utt] - stime = int(utt.split("-")[-2]) - if spk in spk2texts.keys(): - spk2texts[spk].append([stime, text]) - else: - spk2texts[spk] = [[stime, text]] - -for spk, texts in spk2texts.items(): - texts = sorted(texts, key=lambda x: x[0]) - text = "".join([x[1] for x in texts]) - spk2text[spk] = text - -with codecs.open(merged_result, "w", "utf-8") as f: - for spk, text in spk2text.items(): - # meeting = spk.split("-")[2] - meeting = spk.split("-")[0] - if meeting in meeting2text.keys(): - meeting2text[meeting] = meeting2text[meeting] + "$" + text - else: - meeting2text[meeting] = text - for meeting, text in meeting2text.items(): - f.write("%s %s\n" % (meeting, text)) - diff --git a/egs/alimeeting/modular_sa_asr/local/remove_overlap.py b/egs/alimeeting/modular_sa_asr/local/remove_overlap.py deleted file mode 100755 index e9bac928e..000000000 --- a/egs/alimeeting/modular_sa_asr/local/remove_overlap.py +++ /dev/null @@ -1,140 +0,0 @@ -import sys -import pdb -import codecs -import os - -input_segments_file = sys.argv[1] -input_utt2spk_file = sys.argv[2] -output_segments_file = sys.argv[3] -output_utt2spk_file = sys.argv[4] -threshold = sys.argv[5] - - -class Segment(object): - def __init__(self, baseid, spkid, meetingid, stime, etime, uttid=None): - self.baseid = baseid - self.spkid = spkid - self.meetingid = meetingid - self.stime = round(stime, 2) - self.etime = round(etime, 2) - self.uttid = uttid - self.dur = self.etime - self.stime - if self.uttid is None: - self.uttid = "%s-%s-%07d-%07d" % ( - self.baseid, - self.spkid, - self.stime * 100, - self.etime * 100, - ) - - -def cut(cur_max_end_time, seg_list, cur_seg, next_c): - global out_segment_dict - if next_c == len(seg_list): - single_stime = max(cur_max_end_time, cur_seg.stime) - single_etime = cur_seg.etime - if single_stime < single_etime and single_etime - single_stime > float(threshold): - # only save segment which duration more than threshold for sv's accuracy - if cur_seg.spkid not in out_segment_dict.keys(): - out_segment_dict[cur_seg.spkid] = [ - Segment( - cur_seg.baseid, - cur_seg.spkid, - cur_seg.meetingid, - single_stime, - single_etime, - )] - else: - out_segment_dict[cur_seg.spkid].append( - Segment( - cur_seg.baseid, - cur_seg.spkid, - cur_seg.meetingid, - single_stime, - single_etime, - ) - ) - else: - next_seg = seg_list[next_c] - single_stime = max(cur_max_end_time, cur_seg.stime) - single_etime = min(cur_seg.etime, next_seg.stime) - if single_stime < single_etime and single_etime - single_stime > float(threshold): - if cur_seg.spkid not in out_segment_dict.keys(): - out_segment_dict[cur_seg.spkid] = [ - Segment( - cur_seg.baseid, - cur_seg.spkid, - cur_seg.meetingid, - single_stime, - single_etime, - )] - else: - out_segment_dict[cur_seg.spkid].append( - Segment( - cur_seg.baseid, - cur_seg.spkid, - cur_seg.meetingid, - single_stime, - single_etime, - ) - ) - if cur_seg.etime > next_seg.etime: - cut(max(cur_max_end_time, next_seg.etime), seg_list, cur_seg, next_c + 1) - - -meeting2seg = {} -utt2spk = {} -i = 0 - -with codecs.open(input_utt2spk_file, "r", "utf-8") as f: - for line in f.readlines(): - utt, spk = line.strip().split() - utt2spk[utt] = spk - -with codecs.open(input_segments_file, "r", "utf-8") as f: - for line in f.readlines(): - i += 1 - uttid, meetingid, stime, etime = line.strip().split(" ") - spkid = utt2spk[uttid].split("-")[1] - baseid = meetingid - one_seg = Segment(baseid, spkid, meetingid, float(stime), float(etime)) - if one_seg.meetingid not in meeting2seg.keys(): - meeting2seg[one_seg.meetingid] = [one_seg] - else: - meeting2seg[one_seg.meetingid].append(one_seg) - -out_segment_dict = {} - -for k, v in meeting2seg.items(): - meeting2seg[k] = sorted(v, key=lambda x: x.stime) - cur_max_end_time = 0 - for i in range(len(v)): - cur_seg = meeting2seg[k][i] - cut(cur_max_end_time, meeting2seg[k], cur_seg, i + 1) - cur_max_end_time = max(cur_max_end_time, cur_seg.etime) - -out_segment_list = [] - -for k, v in out_segment_dict.items(): - out_segment_list.extend(out_segment_dict[k]) - -with codecs.open(output_segments_file, "w", "utf-8") as f_seg: - with codecs.open(output_utt2spk_file, "w", "utf-8") as f_utt2spk: - for out_seg in out_segment_list: - f_seg.write( - "%s %s %.2f %.2f\n" - % ( - out_seg.uttid, - out_seg.meetingid, - out_seg.stime, - out_seg.etime, - ) - ) - f_utt2spk.write( - "%s %s-%s\n" - % ( - out_seg.uttid, - out_seg.baseid, - out_seg.spkid, - ) - ) \ No newline at end of file diff --git a/egs/alimeeting/modular_sa_asr/local/resegment_data.py b/egs/alimeeting/modular_sa_asr/local/resegment_data.py deleted file mode 100644 index 0f9ce0b43..000000000 --- a/egs/alimeeting/modular_sa_asr/local/resegment_data.py +++ /dev/null @@ -1,78 +0,0 @@ -import soundfile -import os -import sys -import codecs -import numpy as np -import pdb - - -segment_file_path = sys.argv[1] -wav_scp_file_path = sys.argv[2] -data_path = sys.argv[3] - -wav_save_path = data_path + "/wav/" -os.system("mkdir -p " + wav_save_path) -pos_path = data_path + "/pos_map/" -os.system("mkdir -p " + pos_path) - -wav_dict = {} -seg2time = {} -seg2time_new = {} -session2profile = {} - -with codecs.open(wav_scp_file_path, "r", "utf-8") as f: - for line in f.readlines(): - sessionid, wav_path = line.strip().split() - wav_dict[sessionid] = wav_path - -with codecs.open(segment_file_path, "r", "utf-8") as f: - for line in f.readlines(): - _, sessionid, stime, etime = line.strip().split() - if sessionid not in seg2time.keys(): - seg2time[sessionid] = [(int(16000 * float(stime)), int(16000 * float(etime)))] - else: - seg2time[sessionid].append((int(16000 * float(stime)), int(16000 * float(etime)))) -with codecs.open(data_path + "/map.scp", "w", "utf-8") as f1: - for sessionid, seg_times in seg2time.items(): - seg2time_new[sessionid] = [] - last_time = 0 - with codecs.open(pos_path + sessionid + ".pos", "w", "utf-8") as f2: - for seg_time in seg_times: - tmp = seg_time[0] - last_time - cur_seg = (seg_time[0] - tmp, seg_time[1] - tmp) - seg2time_new[sessionid].append((seg_time[0] - last_time, seg_time[1] - last_time)) - last_time = cur_seg[1] - f2.write("%s-%07d-%07d %d %d %d %d\n" % (sessionid, seg_time[0]/160, seg_time[1]/160, seg_time[0], seg_time[1], cur_seg[0], cur_seg[1])) - f1.write("%s %s\n" % (sessionid, pos_path + sessionid + ".pos")) - -with codecs.open(data_path + "/cluster_profile_zeropadding16.scp", "r", "utf-8") as f: - for line in f.readlines(): - session, path = line.strip().split() - session2profile[session] = path - -with codecs.open(data_path + "/wav.scp", "w", "utf-8") as f1: - with codecs.open(data_path + "/profile.scp", "w", "utf-8") as f2: - for sessionid, wav_path in wav_dict.items(): - wav = soundfile.read(wav_path)[0] - if wav.ndim == 2: - wav = wav[:, 0] - seg_list = [wav[seg[0]: seg[1]] for seg in seg2time[sessionid]] - wav_new = np.concatenate(seg_list, axis=0) - cur_time = 0 - flag = True - while flag: - start = cur_time - end = cur_time + 256000 - if end < wav_new.shape[0]: - cur_wav = wav_new[start: end] - else: - cur_wav = wav_new[start: ] - flag = False - cur_time = cur_time + 64000 - wav_name = "%s-%07d_%07d.wav" % (sessionid, start/160, end/160) - soundfile.write(wav_save_path + wav_name, cur_wav, 16000) - f1.write("%s %s\n" % (wav_name, wav_save_path + wav_name)) - f2.write("%s %s\n" % (wav_name, session2profile[sessionid])) - - - diff --git a/egs/alimeeting/modular_sa_asr/local/rttm2segments.py b/egs/alimeeting/modular_sa_asr/local/rttm2segments.py deleted file mode 100644 index ebcb2a233..000000000 --- a/egs/alimeeting/modular_sa_asr/local/rttm2segments.py +++ /dev/null @@ -1,29 +0,0 @@ -import codecs -import sys - -rttm_file_path = sys.argv[1] -segment_file_path = sys.argv[2] -mode = sys.argv[3] # 0 for diarization, 1 for asr - - -meeting2spk = {} - -with codecs.open(rttm_file_path, "r", "utf-8") as fi: - with codecs.open(segment_file_path + "/segments", "w", "utf-8") as f1: - with codecs.open(segment_file_path + "/utt2spk", "w", "utf-8") as f2: - for line in fi.readlines(): - _, sessionid, _, stime, dur, _, _, spkid, _, _ = line.strip().split(" ") - if float(dur) < 0.3: - continue - uttid = "%s-%07d-%07d" % (sessionid, int(float(stime) * 100), int(float(stime) * 100 + float(dur) * 100)) - spkid = "%s-%s" % (sessionid, spkid) - if int(mode) == 0: - f1.write("%s %s %.2f %.2f\n" % (uttid, sessionid, float(stime), float(stime) + float(dur))) - f2.write("%s %s\n" % (uttid, spkid)) - elif int(mode) == 1: - f1.write("%s %s %.2f %.2f\n" % (uttid, spkid, float(stime), float(stime) + float(dur))) - f2.write("%s %s\n" % (uttid, spkid)) - else: - exit("mode only support 0 or 1!") - - diff --git a/egs/alimeeting/modular_sa_asr/local/run_gss.py b/egs/alimeeting/modular_sa_asr/local/run_gss.py deleted file mode 100644 index a58bc7633..000000000 --- a/egs/alimeeting/modular_sa_asr/local/run_gss.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python -# -- coding: UTF-8 - -import argparse -import codecs -import glob -import logging -import os -from nara_wpe.utils import stft, istft -import numpy as np -import scipy.io.wavfile as wf -from tqdm import tqdm - -from test_gss import * - - -def get_parser(): - parser = argparse.ArgumentParser("Doing GSS based enhancement.") - parser.add_argument( - "--wav-scp", - type=str, - required=True, - help="Wav scp file for enhancement.", - ) - parser.add_argument( - "--segments", - type=str, - required=True, - help="Wav scp file for enhancement.", - ) - parser.add_argument( - "--output-dir", - type=str, - required=True, - help="Output directory of GSS enhanced data.", - ) - - return parser - - -def wfread(f): - fs, data = wf.read(f) - if data.dtype == np.int16: - data = np.float32(data) / 32768 - return data, fs - - -def wfwrite(z, fs, store_path): - tmpwav = np.int16(z * 32768) - wf.write(store_path, fs, tmpwav) - - -def main(): - args = get_parser().parse_args() - - # logging info - logfmt = "%(asctime)s (%(module)s:%(lineno)d) %(levelname)s: %(message)s" - logging.basicConfig(level=logging.INFO, format=logfmt) - - stft_window, stft_shift = 512, 256 - gss = GSS(iterations=20, iterations_post=1) - bf = Beamformer("mvdrSouden_ban", "mask_mul") - - with codecs.open(args.wav_scp, "r") as handle: - lines_content = handle.readlines() - wav_lines = [*map(lambda x: x[:-1] if x[-1] in ["\n"] else x, lines_content)] - - cnt = 0 - - session2spk2dur = {} - with codecs.open(args.segments, "r") as handle: - for line in handle.readlines(): - uttid, spkid, stime, etime = line.strip().split(" ") - sessionid = spkid.split("-")[0] - if sessionid not in session2spk2dur.keys(): - session2spk2dur[sessionid] = {} - if spkid not in session2spk2dur[sessionid].keys(): - session2spk2dur[sessionid][spkid] = [] - session2spk2dur[sessionid][spkid].append((float(stime), float(etime))) - # import pdb;pdb.set_trace() - - for wav_idx in tqdm(range(len(wav_lines)), leave=True, desc="0"): - # get wav files from scp file - file_list = wav_lines[wav_idx].split(" ") - sessionid, wav_list = file_list[0], file_list[1:] - - signal_list = [] - time_activity = [] - cnt += 1 - logging.info("Processing {}: {}".format(cnt, wav_list[0])) - - # read all wavs - for wav in wav_list: - data, fs = wfread(wav) - signal_list.append(data) - try: - obstft = np.stack(signal_list, axis=0) - except: - minlen = min([len(s) for s in signal_list]) - obstft = np.stack([s[:minlen] for s in signal_list]) - wavlen = obstft.shape[1] - obstft = stft(obstft, stft_window, stft_shift) - - # get activated timestamps and frequencies - speaker_list = [] - for spk, dur in session2spk2dur[sessionid].items(): - speaker_list.append(spk.split("-")[-1]) - time_activity.append(get_time_activity(dur, wavlen, fs)) - time_activity.append([True] * wavlen) - frequency_activity = get_frequency_activity( - time_activity, stft_window, stft_shift - ) - # import pdb;pdb.set_trace() - - # generate mask - masks = gss(obstft, frequency_activity) - masks_bak = masks - - for i in range(masks.shape[0] - 1): - target_mask = masks[i] - distortion_mask = np.sum(np.delete(masks, i, axis=0), axis=0) - xhat = bf(obstft, target_mask=target_mask, distortion_mask=distortion_mask) - xhat = istft(xhat, stft_window, stft_shift) - audio_dir = "/".join(wav_list[0].split("/")[:-1]) - store_path = ( - wav_list[0] - .replace(audio_dir, args.output_dir) - .replace(".wav", "-{}.wav".format(speaker_list[i])) - ) - if not os.path.exists(os.path.split(store_path)[0]): - os.makedirs(os.path.split(store_path)[0], exist_ok=True) - - logging.info("Save wav file {}.".format(store_path)) - wfwrite(xhat, fs, store_path) - masks = masks_bak - - -if __name__ == "__main__": - main() diff --git a/egs/alimeeting/modular_sa_asr/local/run_wpe.py b/egs/alimeeting/modular_sa_asr/local/run_wpe.py deleted file mode 100644 index 1594c5996..000000000 --- a/egs/alimeeting/modular_sa_asr/local/run_wpe.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env python -# _*_ coding: UTF-8 _*_ - -import argparse -import codecs -import os -import logging -from multiprocessing import Pool - -import numpy as np -import scipy.io.wavfile as wf -from nara_wpe.utils import istft, stft -from nara_wpe.wpe import wpe_v8 as wpe - - -def wpe_worker( - wav_scp, - audio_dir="", - output_dir="", - channel=0, - processing_id=None, - processing_num=None, -): - sampling_rate = 16000 - iterations = 5 - stft_options = dict( - size=512, - shift=128, - window_length=None, - fading=True, - pad=True, - symmetric_window=False, - ) - with codecs.open(wav_scp, "r") as handle: - lines_content = handle.readlines() - wav_lines = [*map(lambda x: x[:-1] if x[-1] in ["\n"] else x, lines_content)] - for wav_idx in range(len(wav_lines)): - if processing_id is None: - processing_token = True - else: - if wav_idx % processing_num == processing_id: - processing_token = True - else: - processing_token = False - if processing_token: - wav_list = wav_lines[wav_idx].split(" ") - file_exist = True - for wav_path in wav_list: - file_exist = file_exist and os.path.exists( - wav_path.replace(audio_dir, output_dir) - ) - if not file_exist: - break - if not file_exist: - logging.info("wait to process {} : {}".format(wav_idx, wav_list[0])) - signal_list = [] - for f in wav_list: - _, data = wf.read(f) - data = data[:, channel - 1] - if data.dtype == np.int16: - data = np.float32(data) / 32768 - signal_list.append(data) - min_len = len(signal_list[0]) - max_len = len(signal_list[0]) - for i in range(1, len(signal_list)): - min_len = min(min_len, len(signal_list[i])) - max_len = max(max_len, len(signal_list[i])) - if min_len != max_len: - for i in range(len(signal_list)): - signal_list[i] = signal_list[i][:min_len] - y = np.stack(signal_list, axis=0) - Y = stft(y, **stft_options).transpose(2, 0, 1) - Z = wpe(Y, iterations=iterations, statistics_mode="full").transpose( - 1, 2, 0 - ) - z = istft(Z, size=stft_options["size"], shift=stft_options["shift"]) - for d in range(len(signal_list)): - store_path = wav_list[d].replace(audio_dir, output_dir) - if not os.path.exists(os.path.split(store_path)[0]): - os.makedirs(os.path.split(store_path)[0], exist_ok=True) - tmpwav = np.int16(z[d, :] * 32768) - wf.write(store_path, sampling_rate, tmpwav) - else: - logging.info("file exist {} : {}".format(wav_idx, wav_list[0])) - return None - - -def wpe_manager( - wav_scp, processing_num=1, audio_dir="", output_dir="", channel=1 -): - if processing_num > 1: - pool = Pool(processes=processing_num) - for i in range(processing_num): - pool.apply_async( - wpe_worker, - kwds={ - "wav_scp": wav_scp, - "processing_id": i, - "processing_num": processing_num, - "audio_dir": audio_dir, - "output_dir": output_dir, - }, - ) - pool.close() - pool.join() - else: - wpe_worker(wav_scp, audio_dir=audio_dir, output_dir=output_dir, channel=channel) - return None - - -if __name__ == "__main__": - parser = argparse.ArgumentParser("run_wpe") - parser.add_argument( - "--wav-scp", - type=str, - required=True, - help="Path pf wav scp file", - ) - parser.add_argument( - "--audio-dir", - type=str, - required=True, - help="Directory of input audio files", - ) - parser.add_argument( - "--output-dir", - type=str, - required=True, - help="Output directory of WPE enhanced audio files", - ) - parser.add_argument( - "--channel", - type=str, - required=True, - help="Channel number of input audio", - ) - parser.add_argument("--nj", type=int, default="1", help="number of process") - args = parser.parse_args() - - # logging info - logfmt = "%(asctime)s (%(module)s:%(lineno)d) %(levelname)s: %(message)s" - logging.basicConfig(level=logging.INFO, format=logfmt) - - logging.info("wavfile={}".format(args.wav_scp)) - logging.info("processingnum={}".format(args.nj)) - - wpe_manager( - wav_scp=args.wav_scp, - processing_num=args.nj, - audio_dir=args.audio_dir, - output_dir=args.output_dir, - channel=int(args.channel) - ) diff --git a/egs/alimeeting/modular_sa_asr/local/segment_to_lab.py b/egs/alimeeting/modular_sa_asr/local/segment_to_lab.py deleted file mode 100755 index e4b212db5..000000000 --- a/egs/alimeeting/modular_sa_asr/local/segment_to_lab.py +++ /dev/null @@ -1,58 +0,0 @@ -import argparse -import os - - -def read_segments_file(segments_file): - utt2segments = dict() - with open(segments_file, "r") as fr: - lines = fr.readlines() - for line in lines: - parts = line.strip().split() - segment_utt_id, utt_id, start, end = parts[0], parts[1], float(parts[2]), float(parts[3]) - if utt_id not in utt2segments: - utt2segments[utt_id] = [] - utt2segments[utt_id].append((segment_utt_id, start, end)) - return utt2segments - - -def write_label(label_file, label_list): - with open(label_file, "w") as fw: - for (start, end) in label_list: - fw.write(f"{start} {end} sp\n") - fw.flush() - - -def write_label_scp_file(label_scp_file, label_scp: dict): - with open(label_scp_file, "w") as fw: - for (utt_id, label_path) in label_scp.items(): - fw.write(f"{utt_id} {label_path}\n") - fw.flush() - - -def main(args): - input_segments = args.input_segments - label_path = args.label_path - output_label_scp_file = args.output_label_scp_file - - utt2segments = read_segments_file(input_segments) - print(f"Collect {len(utt2segments)} utt2segments in file {input_segments}") - - result_label_scp = dict() - for utt_id in utt2segments.keys(): - segment_list = utt2segments[utt_id] - cur_label_path = os.path.join(label_path, f"{utt_id}.lab") - write_label(cur_label_path, label_list=[(i1, i2) for (_, i1, i2) in segment_list]) - result_label_scp[utt_id] = cur_label_path - write_label_scp_file(output_label_scp_file, result_label_scp) - print(f"Write {len(result_label_scp)} labels") - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description="Make the lab file for segments") - parser.add_argument("--input_segments", required=True, help="The input segments file") - parser.add_argument("--label_path", required=True, help="The label_path to save file.lab") - parser.add_argument("--output_label_scp_file", required=True, help="The output label.scp file") - - args = parser.parse_args() - main(args) - diff --git a/egs/alimeeting/modular_sa_asr/local/segmentation/detect_speech_activity.sh b/egs/alimeeting/modular_sa_asr/local/segmentation/detect_speech_activity.sh deleted file mode 100755 index 4a2951bbc..000000000 --- a/egs/alimeeting/modular_sa_asr/local/segmentation/detect_speech_activity.sh +++ /dev/null @@ -1,225 +0,0 @@ -#!/bin/bash - -# Copyright 2016-17 Vimal Manohar -# 2017 Nagendra Kumar Goel -# Apache 2.0. - -# This script does nnet3-based speech activity detection given an input -# kaldi data directory and outputs a segmented kaldi data directory. -# This script can also do music detection and other similar segmentation -# using appropriate options such as --output-name output-music. - -set -e -set -o pipefail -set -u - -if [ -f ./path.sh ]; then . ./path.sh; fi - -#export PATH=/usr/local/cuda-10.0/bin:$PATH -#export LD_LIBRARY_PATH=/usr/local/cuda-10.0/lib64:$LD_LIBRARY_PATH - -#echo $PATH -#echo $LD_LIBRARY_PATH - -affix= # Affix for the segmentation -nj=32 -cmd=run.pl -stage=-1 - -# Feature options (Must match training) -mfcc_config=conf/mfcc_hires.conf -feat_affix= # Affix for the type of feature used - -output_name=output # The output node in the network -sad_name=sad # Base name for the directory storing the computed loglikes - # Can be music for music detection -segmentation_name=segmentation # Base name for the directory doing segmentation - # Can be segmentation_music for music detection - -# SAD network config -iter=final # Model iteration to use - -# Contexts must ideally match training for LSTM models, but -# may not necessarily for stats components -extra_left_context=0 # Set to some large value, typically 40 for LSTM (must match training) -extra_right_context=0 -extra_left_context_initial=-1 -extra_right_context_final=-1 -frames_per_chunk=150 - -# Decoding options -graph_opts="--min-silence-duration=0.03 --min-speech-duration=0.3 --max-speech-duration=10.0" -acwt=0.3 - -# These _in__weight represent the fraction of probability -# to transfer to class. -# e.g. --speech-in-sil-weight=0.0 --garbage-in-sil-weight=0.0 --sil-in-speech-weight=0.0 --garbage-in-speech-weight=0.3 -transform_probs_opts="" - -# Postprocessing options -segment_padding=0.2 # Duration (in seconds) of padding added to segments -min_segment_dur=0 # Minimum duration (in seconds) required for a segment to be included - # This is before any padding. Segments shorter than this duration will be removed. - # This is an alternative to --min-speech-duration above. -merge_consecutive_max_dur=0 # Merge consecutive segments as long as the merged segment is no longer than this many - # seconds. The segments are only merged if their boundaries are touching. - # This is after padding by --segment-padding seconds. - # 0 means do not merge. Use 'inf' to not limit the duration. - -echo $* - -. utils/parse_options.sh - -if [ $# -ne 5 ]; then - echo "This script does nnet3-based speech activity detection given an input kaldi " - echo "data directory and outputs an output kaldi data directory." - echo "See script for details of the options to be supplied." - echo "Usage: $0 " - echo " e.g.: $0 ~/workspace/egs/ami/s5b/data/sdm1/dev exp/nnet3_sad_snr/nnet_tdnn_j_n4 \\" - echo " mfcc_hires exp/segmentation_sad_snr/nnet_tdnn_j_n4 data/ami_sdm1_dev" - echo "" - echo "Options: " - echo " --cmd (utils/run.pl|utils/queue.pl ) # how to run jobs." - echo " --nj # number of parallel jobs to run." - echo " --stage # stage to do partial re-run from." - echo " --convert-data-dir-to-whole # If true, the input data directory is " - echo " # first converted to whole data directory (i.e. whole recordings) " - echo " # and segmentation is done on that." - echo " # If false, then the original segments are " - echo " # retained and they are split into sub-segments." - echo " --output-name # The output node in the network" - echo " --extra-left-context # Set to some large value, typically 40 for LSTM (must match training)" - echo " --extra-right-context # For BLSTM or statistics pooling" - exit 1 -fi - -src_data_dir=$1 # The input data directory that needs to be segmented. - # If convert_data_dir_to_whole is true, any segments in that will be ignored. -sad_nnet_dir=$2 # The SAD neural network -mfcc_dir=$3 # The directory to store the features -dir=$4 # Work directory -data_dir=$5 # The output data directory will be ${data_dir}_seg - -affix=${affix:+_$affix} -feat_affix=${feat_affix:+_$feat_affix} - -data_id=`basename $data_dir` -sad_dir=${dir}/${sad_name}${affix}_${data_id}${feat_affix} -seg_dir=${dir}/${segmentation_name}${affix}_${data_id}${feat_affix} -# test_data_dir=data/${data_id}${feat_affix} -test_data_dir=${src_data_dir} - -############################################################################### -## Forward pass through the network network and dump the log-likelihoods. -############################################################################### - -frame_subsampling_factor=1 -if [ -f $sad_nnet_dir/frame_subsampling_factor ]; then - frame_subsampling_factor=$(cat $sad_nnet_dir/frame_subsampling_factor) -fi - -mkdir -p $dir -if [ $stage -le 1 ]; then - if [ "$(readlink -f $sad_nnet_dir)" != "$(readlink -f $dir)" ]; then - cp $sad_nnet_dir/cmvn_opts $dir || exit 1 - fi - - ######################################################################## - ## Initialize neural network for decoding using the output $output_name - ######################################################################## - - if [ ! -z "$output_name" ] && [ "$output_name" != output ]; then - $cmd $dir/log/get_nnet_${output_name}.log \ - nnet3-copy --edits="rename-node old-name=$output_name new-name=output" \ - $sad_nnet_dir/$iter.raw $dir/${iter}_${output_name}.raw || exit 1 - iter=${iter}_${output_name} - else - if ! diff $sad_nnet_dir/$iter.raw $dir/$iter.raw; then - cp $sad_nnet_dir/$iter.raw $dir/ - fi - fi - - echo ${test_data_dir} - steps/nnet3/compute_output.sh --nj $nj --cmd "$cmd" \ - --iter ${iter} \ - --extra-left-context $extra_left_context \ - --extra-right-context $extra_right_context \ - --extra-left-context-initial $extra_left_context_initial \ - --extra-right-context-final $extra_right_context_final \ - --frames-per-chunk $frames_per_chunk --apply-exp true \ - --frame-subsampling-factor $frame_subsampling_factor \ - ${test_data_dir} $dir $sad_dir || exit 1 -fi - -############################################################################### -## Prepare FST we search to make speech/silence decisions. -############################################################################### - -utils/data/get_utt2dur.sh --nj $nj --cmd "$cmd" $test_data_dir || exit 1 -frame_shift=$(utils/data/get_frame_shift.sh $test_data_dir) || exit 1 - -graph_dir=${dir}/graph_${output_name} -if [ $stage -le 2 ]; then - mkdir -p $graph_dir - - # 1 for silence and 2 for speech - cat < $graph_dir/words.txt - 0 -silence 1 -speech 2 -EOF - - $cmd $graph_dir/log/make_graph.log \ - steps/segmentation/internal/prepare_sad_graph.py $graph_opts \ - --frame-shift=$(perl -e "print $frame_shift * $frame_subsampling_factor") - \| \ - fstcompile --isymbols=$graph_dir/words.txt --osymbols=$graph_dir/words.txt '>' \ - $graph_dir/HCLG.fst -fi - -############################################################################### -## Do Viterbi decoding to create per-frame alignments. -############################################################################### - -post_vec=$sad_nnet_dir/post_${output_name}.vec -if [ ! -f $sad_nnet_dir/post_${output_name}.vec ]; then - if [ ! -f $sad_nnet_dir/post_${output_name}.txt ]; then - echo "$0: Could not find $sad_nnet_dir/post_${output_name}.vec. " - echo "Re-run the corresponding stage in the training script possibly " - echo "with --compute-average-posteriors=true or compute the priors " - echo "from the training labels" - exit 1 - else - post_vec=$sad_nnet_dir/post_${output_name}.txt - fi -fi - -mkdir -p $seg_dir -if [ $stage -le 3 ]; then - steps/segmentation/internal/get_transform_probs_mat.py \ - --priors="$post_vec" $transform_probs_opts > $seg_dir/transform_probs.mat - - steps/segmentation/decode_sad.sh --acwt $acwt --cmd "$cmd" \ - --nj $nj \ - --transform "$seg_dir/transform_probs.mat" \ - $graph_dir $sad_dir $seg_dir -fi - -############################################################################### -## Post-process segmentation to create kaldi data directory. -############################################################################### - -if [ $stage -le 4 ]; then - steps/segmentation/post_process_sad_to_segments.sh \ - --segment-padding $segment_padding --min-segment-dur $min_segment_dur \ - --merge-consecutive-max-dur $merge_consecutive_max_dur \ - --cmd "$cmd" --frame-shift $(perl -e "print $frame_subsampling_factor * $frame_shift") \ - ${test_data_dir} ${seg_dir} ${seg_dir} -fi - -if [ $stage -le 5 ]; then - utils/data/subsegment_data_dir.sh ${test_data_dir} ${seg_dir}/segments \ - ${data_dir}_seg -fi - -echo "$0: Created output segmented kaldi data directory in ${data_dir}_seg" -exit 0 diff --git a/egs/alimeeting/modular_sa_asr/local/test_gss.py b/egs/alimeeting/modular_sa_asr/local/test_gss.py deleted file mode 100644 index f2b9a8299..000000000 --- a/egs/alimeeting/modular_sa_asr/local/test_gss.py +++ /dev/null @@ -1,141 +0,0 @@ -import io -import functools -import logging - -# import soundfile as sf -import numpy as np -import matplotlib -import matplotlib.pylab as plt - -# from IPython.display import display, Audio - -from nara_wpe.utils import stft, istft - -from pb_bss.distribution import CACGMMTrainer -from pb_bss.evaluation import InputMetrics, OutputMetrics -from dataclasses import dataclass - -# from beamforming_wrapper import beamform_mvdr_souden_from_masks -from pb_chime5.utils.numpy_utils import segment_axis_v2 -from textgrid_processor import read_textgrid_from_file - - -def get_time_activity(dur_list, wavlen, sr): - time_activity = [False] * wavlen - for dur in dur_list: - xmax = int(dur[1] * sr) - xmin = int(dur[0] * sr) - if xmax > wavlen: - continue - for i in range(xmin, xmax): - time_activity[i] = True - logging.info("Num of actived samples {}".format(time_activity.count(True))) - return time_activity - -def get_frequency_activity( - time_activity, - stft_window_length, - stft_shift, - stft_fading=True, - stft_pad=True, -): - time_activity = np.asarray(time_activity) - - if stft_fading: - pad_width = np.array([(0, 0)] * time_activity.ndim) - pad_width[-1, :] = stft_window_length - stft_shift # Consider fading - time_activity = np.pad(time_activity, pad_width, mode="constant") - - return segment_axis_v2( - time_activity, - length=stft_window_length, - shift=stft_shift, - end="pad" if stft_pad else "cut", - ).any(axis=-1) - - -@dataclass -class Beamformer: - type: str - postfilter: str - - def __call__(self, Obs, target_mask, distortion_mask, debug=False): - bf = self.type - - if bf == "mvdrSouden_ban": - from pb_chime5.speech_enhancement.beamforming_wrapper import ( - beamform_mvdr_souden_from_masks, - ) - - X_hat = beamform_mvdr_souden_from_masks( - Y=Obs, - X_mask=target_mask, - N_mask=distortion_mask, - ban=True, - ) - elif bf == "ch0": - X_hat = Obs[0] - elif bf == "sum": - X_hat = np.sum(Obs, axis=0) - else: - raise NotImplementedError(bf) - - if self.postfilter is None: - pass - elif self.postfilter == "mask_mul": - X_hat = X_hat * target_mask - else: - raise NotImplementedError(self.postfilter) - - return X_hat - - -@dataclass -class GSS: - iterations: int = 20 - iterations_post: int = 0 - verbose: bool = True - # use_pinv: bool = False - # stable: bool = True - - def __call__(self, Obs, acitivity_freq=None, debug=False): - initialization = np.asarray(acitivity_freq, dtype=np.float64) - initialization = np.where(initialization == 0, 1e-10, initialization) - initialization = initialization / np.sum(initialization, keepdims=True, axis=0) - initialization = np.repeat(initialization[None, ...], 257, axis=0) - - source_active_mask = np.asarray(acitivity_freq, dtype=bool) - source_active_mask = np.repeat(source_active_mask[None, ...], 257, axis=0) - - cacGMM = CACGMMTrainer() - - if debug: - learned = [] - all_affiliations = [] - F = Obs.shape[-1] - T = Obs.T.shape[-2] - - for f in range(F): - if self.verbose: - if f % 50 == 0: - logging.info(f"{f}/{F}") - - # T: Consider end of signal. - # This should not be nessesary, but activity is for inear and not for - # array. - cur = cacGMM.fit( - y=Obs.T[f, ...], - initialization=initialization[f, ..., :T], - iterations=self.iterations, - source_activity_mask=source_active_mask[f, ..., :T], - ) - affiliation = cur.predict( - Obs.T[f, ...], - source_activity_mask=source_active_mask[f, ..., :T], - ) - - all_affiliations.append(affiliation) - - posterior = np.array(all_affiliations).transpose(1, 2, 0) - - return posterior diff --git a/egs/alimeeting/modular_sa_asr/local/textgrid_processor.py b/egs/alimeeting/modular_sa_asr/local/textgrid_processor.py deleted file mode 100644 index 467e20b55..000000000 --- a/egs/alimeeting/modular_sa_asr/local/textgrid_processor.py +++ /dev/null @@ -1,316 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import codecs - - -class TextGrid(object): - def __init__( - self, - file_type="", - object_class="", - xmin=0.0, - xmax=0.0, - tiers_status="", - tiers=[], - ): - self.file_type = file_type - self.object_class = object_class - self.xmin = xmin - self.xmax = xmax - self.tiers_status = tiers_status - self.tiers = tiers - - if self.xmax < self.xmin: - raise ValueError("xmax ({}) < xmin ({})".format(self.xmax, self.xmin)) - - def cutoff(self, xstart=None, xend=None): - if xstart is None: - xstart = self.xmin - - if xend is None: - xend = self.xmax - - if xend < xstart: - raise ValueError("xend ({}) < xstart ({})".format(xend, xstart)) - - new_xmax = xend - xstart + self.xmin - new_xmin = self.xmin - new_tiers = [] - - for tier in self.tiers: - new_tiers.append(tier.cutoff(xstart=xstart, xend=xend)) - return TextGrid( - file_type=self.file_type, - object_class=self.object_class, - xmin=new_xmin, - xmax=new_xmax, - tiers_status=self.tiers_status, - tiers=new_tiers, - ) - - -class Tier(object): - def __init__(self, tier_class="", name="", xmin=0.0, xmax=0.0, intervals=[]): - self.tier_class = tier_class - self.name = name - self.xmin = xmin - self.xmax = xmax - self.intervals = intervals - - if self.xmax < self.xmin: - raise ValueError("xmax ({}) < xmin ({})".format(self.xmax, self.xmin)) - - def cutoff(self, xstart=None, xend=None): - if xstart is None: - xstart = self.xmin - - if xend is None: - xend = self.xmax - - if xend < xstart: - raise ValueError("xend ({}) < xstart ({})".format(xend, xstart)) - - bias = xstart - self.xmin - new_xmax = xend - bias - new_xmin = self.xmin - new_intervals = [] - for interval in self.intervals: - if interval.xmax <= xstart or interval.xmin >= xend: - pass - elif interval.xmin < xstart: - new_intervals.append( - Interval( - xmin=new_xmin, xmax=interval.xmax - bias, text=interval.text - ) - ) - elif interval.xmax > xend: - new_intervals.append( - Interval( - xmin=interval.xmin - bias, xmax=new_xmax, text=interval.text - ) - ) - else: - new_intervals.append( - Interval( - xmin=interval.xmin - bias, - xmax=interval.xmax - bias, - text=interval.text, - ) - ) - - return Tier( - tier_class=self.tier_class, - name=self.name, - xmin=new_xmin, - xmax=new_xmax, - intervals=new_intervals, - ) - - -class Interval(object): - def __init__(self, xmin=0.0, xmax=0.0, text=""): - self.xmin = xmin - self.xmax = xmax - self.text = text - - if self.xmax < self.xmin: - raise ValueError("xmax ({}) < xmin ({})".format(self.xmax, self.xmin)) - - -def read_textgrid_from_file(filepath): - with codecs.open(filepath, "r", encoding="utf-8") as handle: - lines = handle.readlines() - - if lines[-1] == "\r\n": - lines = lines[:-1] - - assert "File type" in lines[0], "error line 0, {}".format(lines[0]) - file_type = ( - lines[0] - .split("=")[1] - .replace(" ", "") - .replace('"', "") - .replace("\r", "") - .replace("\n", "") - ) - - assert "Object class" in lines[1], "error line 1, {}".format(lines[1]) - object_class = ( - lines[1] - .split("=")[1] - .replace(" ", "") - .replace('"', "") - .replace("\r", "") - .replace("\n", "") - ) - - assert lines[2] == "\r\n", "error line 2, {}".format(lines[2]) - - assert "xmin" in lines[3], "error line 3, {}".format(lines[3]) - xmin = float( - lines[3].split("=")[1].replace(" ", "").replace("\r", "").replace("\n", "") - ) - - assert "xmax" in lines[4], "error line 4, {}".format(lines[4]) - xmax = float( - lines[4].split("=")[1].replace(" ", "").replace("\r", "").replace("\n", "") - ) - - assert "tiers?" in lines[5], "error line 5, {}".format(lines[5]) - tiers_status = ( - lines[5].split("?")[1].replace(" ", "").replace("\r", "").replace("\n", "") - ) - - assert "size" in lines[6], "error line 6, {}".format(lines[6]) - size = int( - lines[6].split("=")[1].replace(" ", "").replace("\r", "").replace("\n", "") - ) - - assert lines[7] == "item []:\r\n", "error line 7, {}".format(lines[7]) - - tier_start = [] - for item_idx in range(size): - tier_start.append(lines.index(" " * 4 + "item [{}]:\r\n".format(item_idx + 1))) - - tier_end = tier_start[1:] + [len(lines)] - - tiers = [] - for tier_idx in range(size): - tiers.append( - read_tier_from_lines( - tier_lines=lines[tier_start[tier_idx] + 1 : tier_end[tier_idx]] - ) - ) - - return TextGrid( - file_type=file_type, - object_class=object_class, - xmin=xmin, - xmax=xmax, - tiers_status=tiers_status, - tiers=tiers, - ) - - -def read_tier_from_lines(tier_lines): - assert "class" in tier_lines[0], "error line 0, {}".format(tier_lines[0]) - tier_class = ( - tier_lines[0] - .split("=")[1] - .replace(" ", "") - .replace('"', "") - .replace("\r", "") - .replace("\n", "") - ) - - assert "name" in tier_lines[1], "error line 1, {}".format(tier_lines[1]) - name = ( - tier_lines[1] - .split("=")[1] - .replace(" ", "") - .replace('"', "") - .replace("\r", "") - .replace("\n", "") - ) - - assert "xmin" in tier_lines[2], "error line 2, {}".format(tier_lines[2]) - xmin = float( - tier_lines[2].split("=")[1].replace(" ", "").replace("\r", "").replace("\n", "") - ) - - assert "xmax" in tier_lines[3], "error line 3, {}".format(tier_lines[3]) - xmax = float( - tier_lines[3].split("=")[1].replace(" ", "").replace("\r", "").replace("\n", "") - ) - - assert "intervals: size" in tier_lines[4], "error line 4, {}".format(tier_lines[4]) - intervals_num = int( - tier_lines[4].split("=")[1].replace(" ", "").replace("\r", "").replace("\n", "") - ) - - # handle unformatted case - # R12_S203204205_C09_I1_Near_203.TextGrid - # R12_S203204205_C09_I1_Near_205.TextGrid - if tier_lines[-1] == "\n": - tier_lines = tier_lines[:-1] - - if len(tier_lines[5:]) == intervals_num * 5: - intervals = [] - for intervals_idx in range(intervals_num): - assert tier_lines[ - 5 + 5 * intervals_idx + 0 - ] == " " * 8 + "intervals [{}]:\r\n".format(intervals_idx + 1) - assert tier_lines[ - 5 + 5 * intervals_idx + 1 - ] == " " * 8 + "intervals [{}]:\r\n".format(intervals_idx + 1) - intervals.append( - read_interval_from_lines( - interval_lines=tier_lines[ - 7 + 5 * intervals_idx : 10 + 5 * intervals_idx - ] - ) - ) - elif len(tier_lines[5:]) == intervals_num * 4: - # handle unformatted case - # R12_S203204205_C09_I1_Near_203.TextGrid - # R12_S203204205_C09_I1_Near_204.TextGrid - # R12_S203204205_C09_I1_Near_205.TextGrid - intervals = [] - for intervals_idx in range(intervals_num): - assert tier_lines[ - 5 + 4 * intervals_idx + 0 - ] == " " * 8 + "intervals [{}]:\r\n".format(intervals_idx + 1) - - intervals.append( - read_interval_from_lines( - interval_lines=tier_lines[ - 6 + 4 * intervals_idx : 9 + 4 * intervals_idx - ] - ) - ) - else: - import pdb - - pdb.set_trace() - raise ValueError( - "error lines {} % {} != 0".format(len(tier_lines[5:]), intervals_num) - ) - - return Tier( - tier_class=tier_class, name=name, xmin=xmin, xmax=xmax, intervals=intervals - ) - - -def read_interval_from_lines(interval_lines): - assert len(interval_lines) == 3, "error lines" - - assert "xmin" in interval_lines[0], "error line 0, {}".format(interval_lines[0]) - xmin = float( - interval_lines[0] - .split("=")[1] - .replace(" ", "") - .replace("\r", "") - .replace("\n", "") - ) - - assert "xmax" in interval_lines[1], "error line 1, {}".format(interval_lines[1]) - xmax = float( - interval_lines[1] - .split("=")[1] - .replace(" ", "") - .replace("\r", "") - .replace("\n", "") - ) - - assert "text" in interval_lines[2], "error line 2, {}".format(interval_lines[2]) - text = ( - interval_lines[2] - .split("=")[1] - .replace(" ", "") - .replace('"', "") - .replace("\r", "") - .replace("\n", "") - ) - - return Interval(xmin=xmin, xmax=xmax, text=text) diff --git a/egs/alimeeting/modular_sa_asr/path.sh b/egs/alimeeting/modular_sa_asr/path.sh deleted file mode 100755 index 16108c67a..000000000 --- a/egs/alimeeting/modular_sa_asr/path.sh +++ /dev/null @@ -1,14 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -export KALDI_ROOT=/Your_Kaldi_root -export DATA_SOURCE=/Your_data_path -export DATA_NAME=Test_2023_Ali_far -export PATH=$PWD/utils/:$KALDI_ROOT/tools/openfst/bin:$PATH -[ ! -f $KALDI_ROOT/tools/config/common_path.sh ] && echo >&2 "The standard file $KALDI_ROOT/tools/config/common_path.sh is not present -> Exit!" && exit 1 -. $KALDI_ROOT/tools/config/common_path.sh -export LC_ALL=C - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:./utils:$FUNASR_DIR:$PATH -export PYTHONPATH=$FUNASR_DIR:$PYTHONPATH diff --git a/egs/alimeeting/modular_sa_asr/run_asr.sh b/egs/alimeeting/modular_sa_asr/run_asr.sh deleted file mode 100755 index 8dd6ce99a..000000000 --- a/egs/alimeeting/modular_sa_asr/run_asr.sh +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="4,5,6,7" -gpu_num=4 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -finetune=true -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=2 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="data" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="1.0" -stage=0 -stop_stage=1 - -# feature configuration -feats_dim=80 -nj=64 - -# exp tag -tag="finetune" - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=Train_Ali_far_wpegss -valid_set=Test_Ali_far_wpegss -test_sets="${DATA_NAME}_wpegss" - -asr_config=conf/train_paraformer.yaml -model_dir="$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" -pretrain_model_dir=./speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch -inference_config=$pretrain_model_dir/decoding.yaml - - -token_list=$pretrain_model_dir/tokens.txt - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if ${finetune}; then - inference_asr_model=./checkpoint/valid.acc.ave.pb - finetune_tag="_finetune" -else - inference_asr_model=$pretrain_model_dir/model.pb - finetune_tag="" -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - if [ -L ./utils ]; then - unlink ./utils - ln -s ../../aishell/transformer/utils - else - ln -s ../../aishell/transformer/utils - fi -fi - -# Download Model -world_size=$gpu_num # run on one machine -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Download Model" - if [ ! -d $pretrain_model_dir ]; then - git clone https://www.modelscope.cn/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch.git - fi -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - - echo "stage 2: ASR Training" - python -m torch.distributed.launch \ - --nproc_per_node $gpu_num local/finetune.py - -fi - -# Testing Stage -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: Inference" - for dset in ${test_sets}; do - _dir="$pretrain_model_dir/decode_${dset}${finetune_tag}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="./data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file $pretrain_model_dir/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config $pretrain_model_dir/config.yaml \ - --asr_model_file $inference_asr_model \ - --output_dir "${_logdir}"/output.JOB \ - --mode paraformer \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python local/merge_spk_text.py ${_dir}/text ${_data}/utt2spk - python local/compute_cpcer.py ${_data}/text_merge ${_dir}/text_merge - echo "cpCER is saved at ${_dir}/text_cpcer" - done -fi - diff --git a/egs/alimeeting/modular_sa_asr/run_diar.sh b/egs/alimeeting/modular_sa_asr/run_diar.sh deleted file mode 100755 index 74fa76f9e..000000000 --- a/egs/alimeeting/modular_sa_asr/run_diar.sh +++ /dev/null @@ -1,233 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail -. path.sh || exit 1 -train_cmd=utils/run.pl - -# data path -data_source_dir=$DATA_SOURCE -textgrid_dir=$data_source_dir/textgrid_dir/ -wav_dir=$data_source_dir/audio_dir/ - -# work path -work_dir=./data/${DATA_NAME}_sc/ -sad_dir=$work_dir/sad_part/ -sad_work_dir=$sad_dir/exp/ -sad_result_dir=$sad_dir/sad -dia_dir=$work_dir/dia_part/ -dia_vad_dir=$dia_dir/vad/ -dia_rttm_dir=$dia_dir/rttm/ -dia_emb_dir=$dia_dir/embedding/ -dia_rtt_label_dir=$dia_dir/label_rttm/ -dia_result_dir=$dia_dir/result_DER/ -sond_work_dir=./data/${DATA_NAME}_sond/ -asr_work_dir=./data/${DATA_NAME}_wpegss/org/ - -mkdir -p $work_dir || exit 1; -mkdir -p $sad_dir || exit 1; -mkdir -p $sad_work_dir || exit 1; -mkdir -p $sad_result_dir || exit 1; -mkdir -p $dia_dir || exit 1; -mkdir -p $dia_vad_dir || exit 1; -mkdir -p $dia_rttm_dir || exit 1; -mkdir -p $dia_emb_dir || exit 1; -mkdir -p $dia_rtt_label_dir || exit 1; -mkdir -p $dia_result_dir || exit 1; -mkdir -p $sond_work_dir || exit 1; -mkdir -p $asr_work_dir || exit 1; - -stage=0 -stop_stage=9 -nj=4 -sm_size=83 - -if [ $stage -le 0 ] && [ ${stop_stage} -ge 0 ]; then - # Check the installtion of kaldi - if [ -L ./steps ]; then - unlink ./steps - else - ln -s $KALDI_ROOT/egs/wsj/s5/steps || { echo "You must install kaldi first, and set the KALDI_ROOT in path.sh" && exit 1; } - fi - - if [ -L ./utils ]; then - unlink ./utils - else - ln -s $KALDI_ROOT/egs/wsj/s5/utils || { echo "You must install kaldi first, and set the KALDI_ROOT in path.sh" && exit 1; } - fi -fi - -if [ $stage -le 1 ] && [ ${stop_stage} -ge 1 ]; then - # Prepare the AliMeeting data - echo "Prepare Alimeeting data" - find $wav_dir -name "*\.wav" > $work_dir/wavlist - sort $work_dir/wavlist > $work_dir/tmp - cp $work_dir/tmp $work_dir/wavlist - awk -F '/' '{print $NF}' $work_dir/wavlist | awk -F '.' '{print $1}' > $work_dir/uttid - paste -d " " $work_dir/uttid $work_dir/wavlist > $work_dir/wav.scp - paste -d " " $work_dir/uttid $work_dir/uttid > $work_dir/utt2spk - cp $work_dir/utt2spk $work_dir/spk2utt - cp $work_dir/uttid $work_dir/text - - sad_feat=$sad_dir/feat/mfcc - cp $work_dir/wav.scp $sad_dir - cp $work_dir/utt2spk $sad_dir - cp $work_dir/spk2utt $sad_dir - cp $work_dir/text $sad_dir - - utils/fix_data_dir.sh $sad_dir - - ## first we extract the feature for sad model - steps/make_mfcc.sh --nj $nj --cmd "$train_cmd" \ - --mfcc-config conf/mfcc_hires.conf \ - $sad_dir $sad_dir/make_mfcc $sad_feat -fi - -if [ $stage -le 2 ] && [ ${stop_stage} -ge 2 ]; then - # Do Speech Activity Detectation - echo "Do SAD" - ./utils/split_data.sh $sad_dir $nj - ## do the segmentations - local/segmentation/detect_speech_activity.sh --nj $nj --stage 0 \ - --cmd "$train_cmd" $sad_dir exp/segmentation_1a/tdnn_stats_sad_1a/ \ - $sad_dir/feat/mfcc $sad_work_dir $sad_result_dir -fi - -if [ $stage -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "Do Speaker Embedding Extractor" - cp $work_dir/wav.scp $dia_dir - - python local/segment_to_lab.py --input_segments $sad_dir/sad_seg/segments \ - --label_path $dia_vad_dir \ - --output_label_scp_file $dia_dir/label.scp ||exit 1; - - ./utils/split_data.sh $work_dir $nj - ${train_cmd} JOB=1:${nj} $dia_dir/exp/extract_embedding.JOB.log \ - python VBx/predict.py --in-file-list $work_dir/split${nj}/JOB/text \ - --in-lab-dir $dia_dir/vad \ - --in-wav-dir $wav_dir \ - --out-ark-fn $dia_emb_dir/embedding_out.JOB.ark \ - --out-seg-fn $dia_emb_dir/embedding_out.JOB.seg \ - --weights VBx/models/ResNet101_16kHz/nnet/final.onnx \ - --backend onnx - - echo "success" -fi - -if [ $stage -le 4 ] && [ ${stop_stage} -ge 4 ]; then - # The Speaker Embedding Cluster - echo "Do the Speaker Embedding Cluster" - # The meeting data is long so that the cluster is a little bit slow - ${train_cmd} JOB=1:${nj} $dia_dir/exp/cluster.JOB.log \ - python VBx/vbhmm.py --init AHC+VB \ - --out-rttm-dir $dia_rttm_dir \ - --xvec-ark-file $dia_emb_dir/embedding_out.JOB.ark \ - --segments-file $dia_emb_dir/embedding_out.JOB.seg \ - --xvec-transform VBx/models/ResNet101_16kHz/transform.h5 \ - --plda-file VBx/models/ResNet101_16kHz/plda \ - --threshold 0.14 \ - --lda-dim 128 \ - --Fa 0.3 \ - --Fb 17 \ - --loopP 0.99 -fi - -if [ $stage -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "Process textgrid to obtain rttm label" - find -L $textgrid_dir -iname "*.TextGrid" > $work_dir/textgrid.flist - sort $work_dir/textgrid.flist > $work_dir/tmp - cp $work_dir/tmp $work_dir/textgrid.flist - paste $work_dir/uttid $work_dir/textgrid.flist > $work_dir/uttid_textgrid.flist - while read text_file - do - text_grid=`echo $text_file | awk '{print $1}'` - text_grid_path=`echo $text_file | awk '{print $2}'` - python local/make_textgrid_rttm.py --input_textgrid_file $text_grid_path \ - --uttid $text_grid \ - --output_rttm_file $dia_rtt_label_dir/${text_grid}.rttm - done < $work_dir/uttid_textgrid.flist - if [ -f "$dia_rtt_label_dir/all.rttm" ]; then - rm -f $dia_rtt_label_dir/all.rttm - fi - cat $dia_rtt_label_dir/*.rttm > $dia_rtt_label_dir/all.rttm -fi - -if [ $stage -le 6 ] && [ $stop_stage -ge 6 ]; then - echo "Get VBx DER result" - find $dia_rtt_label_dir -name "*.rttm" > $dia_rtt_label_dir/ref.scp - find $dia_rttm_dir -name "*.rttm" > $dia_rttm_dir/sys.scp - if [ -f "$dia_rttm_dir/all.rttm" ]; then - rm -f $dia_rttm_dir/all.rttm - fi - cat $dia_rttm_dir/*.rttm > $dia_rttm_dir/all.rttm - - collar_set="0 0.25" - python local/meeting_speaker_number_process.py --path=$work_dir \ - --label_path=$dia_rtt_label_dir --predict_path=$dia_rttm_dir - speaker_number="2 3 4" - for weight_collar in $collar_set; - do - # all meeting - python dscore/score.py --collar $weight_collar \ - -R $dia_rtt_label_dir/ref.scp -S $dia_rttm_dir/sys.scp > $dia_result_dir/speaker_all_DER_overlaps_${weight_collar}.log - # 2,3,4 speaker meeting - for speaker_count in $speaker_number; - do - python dscore/score.py --collar $weight_collar \ - -R $dia_rtt_label_dir/speaker${speaker_count}_id -S $dia_rttm_dir/speaker${speaker_count}_id > $dia_result_dir/speaker_${speaker_count}_DER_overlaps_${weight_collar}.log - done - done -fi - -if [ $stage -le 7 ] && [ $stop_stage -ge 7 ]; then - echo "Downloading Pre-trained model..." - mkdir ./SOND - cd ./SOND - git clone https://www.modelscope.cn/damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch.git - git clone https://www.modelscope.cn/damo/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch.git - ln -s speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/sv.pth ./sv.pb - cp speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/sv.yaml ./sv.yaml - ln -s speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch/sond.pth ./sond.pb - cp speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch/sond_fbank.yaml ./sond_fbank.yaml - cp speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch/sond.yaml ./sond.yaml - cd .. -fi - -if [ $stage -le 8 ] && [ $stop_stage -ge 8 ]; then - echo "Prepare data for sond" - cp $work_dir/wav.scp $sond_work_dir - # convert rttm to segments - python local/rttm2segments.py $dia_rttm_dir/all.rttm $sond_work_dir 0 - # remove the overlapped part - python local/remove_overlap.py $sond_work_dir/segments $sond_work_dir/utt2spk \ - $sond_work_dir/segments_nooverlap $sond_work_dir/utt2spk_nooverlap 0.3 - # extract speaker profile from the filtered segments file - python local/extract_profile_from_segments.py $sond_work_dir - # segment data to 16s - python local/resegment_data.py \ - $data_source_dir/segments \ - $data_source_dir/wav.scp \ - $sond_work_dir -fi - -if [ $stage -le 9 ] && [ $stop_stage -ge 9 ]; then - echo "Diarization with SOND" - - python local/infer_sond.py SOND/sond.yaml SOND/sond.pb $sond_work_dir $sond_work_dir/dia_outputs - - python local/convert_label_to_rttm.py \ - $sond_work_dir/dia_outputs/labels.txt \ - $sond_work_dir/map.scp \ - $sond_work_dir/dia_outputs/prediction_sm_${sm_size}.rttm \ - --ignore_len 10 --no_pbar --smooth_size ${sm_size} \ - --vote_prob 0.5 --n_spk 16 - - python dscore/score.py \ - -r $dia_rtt_label_dir/all.rttm \ - -s $sond_work_dir/dia_outputs/prediction_sm_${sm_size}.rttm \ - --collar 0.25 &> $sond_work_dir/dia_outputs/dia_result - # convert rttm to segments - python local/rttm2segments.py $sond_work_dir/dia_outputs/prediction_sm_${sm_size}.rttm $asr_work_dir 1 -fi - - diff --git a/egs/alimeeting/modular_sa_asr/run_enh.sh b/egs/alimeeting/modular_sa_asr/run_enh.sh deleted file mode 100755 index c87e0112f..000000000 --- a/egs/alimeeting/modular_sa_asr/run_enh.sh +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -log() { - local fname=${BASH_SOURCE[1]##*/} - echo -e "$(date '+%Y-%m-%dT%H:%M:%S') (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $*" -} -SECONDS=0 - -# general configuration -stage=1 -stop_stage=3 -nj=10 - -log "$0 $*" -. utils/parse_options.sh -. ./path.sh || exit 1 -train_cmd=utils/run.pl - - -data_source_dir=$DATA_SOURCE -audio_dir=$data_source_dir/audio_dir -output_wpe_dir=$data_source_dir/wpe_audio_dir -output_gss_dir=$data_source_dir/gss_audio_dir -asr_data_path=./data/${DATA_NAME}_wpegss -channel=$1 - -log "Start Speech Enhancement." - -if [ ! -L ./utils ]; then - ln -s ./pb_chime5/pb_bss -fi - -# WPE -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - log "stage 1: Start WPE." - for ch in `seq ${channel}`; do - mkdir -p ${output_wpe_dir}_${ch}/log/ - # split wav.scp - find $audio_dir/ -name "*.wav" > ${output_wpe_dir}_${ch}/wav.scp - arr="" - for i in `seq ${nj}`; do - arr="$arr ${output_wpe_dir}_${ch}/log/wav.${i}.scp" - done - split_scp.pl ${output_wpe_dir}_${ch}/wav.scp $arr - # do wpe - for n in `seq ${nj}`; do - cat <<-EOF >${output_wpe_dir}_${ch}/log/wpe.${n}.sh -python local/run_wpe.py \ - --wav-scp ${output_wpe_dir}_${ch}/log/wav.${n}.scp \ - --audio-dir ${audio_dir} \ - --output-dir ${output_wpe_dir}_${ch} \ - --ch $ch -EOF - done - chmod a+x ${output_wpe_dir}_${ch}/log/wpe.*.sh - ${train_cmd} JOB=1:${nj} ${output_wpe_dir}_${ch}/log/wpe.JOB.log \ - ${output_wpe_dir}_${ch}/log/wpe.JOB.sh - done -fi - -# GSS -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - log "stage 2: Start GSS" - if [ ! -d pb_chime5/ ]; then - log "Please install pb_chime5 by local/install_pb_chime5.sh" - exit 1 - fi - mkdir -p $output_gss_dir/log - # split wpe.scp - for i in `seq ${channel}`; do - find ${output_wpe_dir}_${i}/ -name "*.wav" > $output_gss_dir/tmp${i} - done - awk -F '/' '{print($NF)}' $output_gss_dir/tmp1 | cut -d "." -f1 > $output_gss_dir/tmp - arr="" - for i in `seq ${channel}`; do - arr="$arr $output_gss_dir/tmp${i}" - done - paste -d " " $output_gss_dir/tmp $arr > $output_gss_dir/wpe.scp - rm -f $output_gss_dir/tmp* - arr="" - for i in `seq ${nj}`; do - arr="$arr $output_gss_dir/log/wpe.${i}.scp" - done - split_scp.pl $output_gss_dir/wpe.scp $arr - - # do gss - for n in `seq ${nj}`; do - cat <<-EOF >${output_gss_dir}/log/gss.${n}.sh -python local/run_gss.py \ - --wav-scp ${output_gss_dir}/log/wpe.${n}.scp \ - --segments $asr_data_path/org/segments \ - --output-dir ${output_gss_dir} -EOF - done - chmod a+x ${output_gss_dir}/log/gss.*.sh - ${train_cmd} JOB=1:${nj} ${output_gss_dir}/log/gss.JOB.log \ - ${output_gss_dir}/log/gss.JOB.sh -fi - -# Prepare data for ASR -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - log "stage 3: Preparing data for ASR" - find $output_gss_dir -name "*.wav" > $asr_data_path/org/wav_list - awk -F '/' '{print($NF)}' $asr_data_path/org/wav_list | sed 's/\.wav//g' > $asr_data_path/org/uttid - paste -d " " $asr_data_path/org/uttid $asr_data_path/org/wav_list > $asr_data_path/org/wav.scp - bash local/format_wav_scp.sh --nj "${nj}" --cmd "${train_cmd}" \ - --audio-format wav --segments $asr_data_path/org/segments \ - "$asr_data_path/org/wav.scp" "$asr_data_path" -fi - -log "End speech enhancement" diff --git a/egs/alimeeting/sa_asr/README.md b/egs/alimeeting/sa_asr/README.md deleted file mode 100644 index f8e412415..000000000 --- a/egs/alimeeting/sa_asr/README.md +++ /dev/null @@ -1,86 +0,0 @@ -# Get Started -Speaker Attributed Automatic Speech Recognition (SA-ASR) is a task proposed to solve "who spoke what". Specifically, the goal of SA-ASR is not only to obtain multi-speaker transcriptions, but also to identify the corresponding speaker for each utterance. The method used in this example is referenced in the paper: [End-to-End Speaker-Attributed ASR with Transformer](https://www.isca-speech.org/archive/pdfs/interspeech_2021/kanda21b_interspeech.pdf). -# Train -First you need to install the FunASR and ModelScope. ([installation](https://github.com/alibaba-damo-academy/FunASR#installation)) -After the FunASR and ModelScope is installed, you must manually download and unpack the [AliMeeting](http://www.openslr.org/119/) corpus and place it in the `./dataset` directory. The `.dataset` should organized as follow: -```shell -dataset -|—— Eval_Ali_far -|—— Eval_Ali_near -|—— Test_Ali_far -|—— Test_Ali_near -|—— Train_Ali_far -|—— Train_Ali_near -``` -Then you can run this receipe by running: -```shell -bash run.sh --stage 0 --stop-stage 6 -``` -There are 8 stages in `run.sh`: -```shell -stage 0: Data preparation and remove the audio which is too long or too short. -stage 1: Speaker profile and CMVN Generation. -stage 2: Dictionary preparation. -stage 3: LM training (not supported). -stage 4: ASR Training. -stage 5: SA-ASR Training. -stage 6: Inference -stage 7: Inference with Test_2023_Ali_far -``` - -# Infer -1. Download the final test set and extracted -2. Put the audios in `./dataset/Test_2023_Ali_far/` and put the `wav.scp`, `segments`, `utt2spk`, `spk2utt` in `./data/org/Test_2023_Ali_far/`. -3. Set the `test_2023` in `run.sh` should be to `Test_2023_Ali_far`. -4. Run the `run.sh` as follow. -```shell -# Prepare test_2023 set -bash run.sh --stage 0 --stop-stage 1 -# Decode test_2023 set -bash run.sh --stage 7 --stop-stage 7 -``` -# Format of Final Submission -Finally, you need to submit a file called `text_spk_merge` with the following format: -```shell -Meeting_1 text_spk_1_A$text_spk_1_B$text_spk_1_C ... -Meeting_2 text_spk_2_A$text_spk_2_B$text_spk_2_C ... -... -``` -Here, text_spk_1_A represents the full transcription of speaker_A of Meeting_1 (merged in chronological order), and $ represents the separator symbol. There's no need to worry about the speaker permutation as the optimal permutation will be computed in the end. For more information, please refer to the results generated after executing the baseline code. -# Baseline Results -The results of the baseline system are as follows. The baseline results include speaker independent character error rate (SI-CER) and concatenated minimum permutation character error rate (cpCER), the former is speaker independent and the latter is speaker dependent. The speaker profile adopts the oracle speaker embedding during training. However, due to the lack of oracle speaker label during evaluation, the speaker profile provided by an additional spectral clustering is used. Meanwhile, the results of using the oracle speaker profile on Test Set are also provided to show the impact of speaker profile accuracy. - -| |SI-CER(%) |cpCER(%) | -|:---------------|:------------:|----------:| -|oracle profile |32.72 |42.92 | -|cluster profile|32.73 |49.37 | - - -# Reference -N. Kanda, G. Ye, Y. Gaur, X. Wang, Z. Meng, Z. Chen, and T. Yoshioka, "End-to-end speaker-attributed ASR with transformer," in Interspeech. ISCA, 2021, pp. 4413–4417. \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/conf/decode_asr_rnn.yaml b/egs/alimeeting/sa_asr/conf/decode_asr_rnn.yaml deleted file mode 100644 index 88fdbc20b..000000000 --- a/egs/alimeeting/sa_asr/conf/decode_asr_rnn.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 20 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.6 -lm_weight: 0.3 diff --git a/egs/alimeeting/sa_asr/conf/train_asr_conformer.yaml b/egs/alimeeting/sa_asr/conf/train_asr_conformer.yaml deleted file mode 100644 index 507ad3061..000000000 --- a/egs/alimeeting/sa_asr/conf/train_asr_conformer.yaml +++ /dev/null @@ -1,102 +0,0 @@ -# network architecture -frontend: multichannelfrontend -frontend_conf: - fs: 16000 - window: hann - n_fft: 400 - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - use_channel: 0 - -# encoder related -encoder: conformer -encoder_conf: - output_size: 256 # dimension of attention - attention_heads: 4 - linear_units: 2048 # the number of units of position-wise feed forward - num_blocks: 12 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - rel_pos_type: latest - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - macaron_style: true - use_cnn_module: true - cnn_module_kernel: 15 - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# ctc related -ctc_conf: - ignore_nan_grad: true - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 7000 - num_workers: 8 - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 100 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 25000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 diff --git a/egs/alimeeting/sa_asr/conf/train_sa_asr_conformer.yaml b/egs/alimeeting/sa_asr/conf/train_sa_asr_conformer.yaml deleted file mode 100644 index 18614ddf3..000000000 --- a/egs/alimeeting/sa_asr/conf/train_sa_asr_conformer.yaml +++ /dev/null @@ -1,132 +0,0 @@ -# network architecture -frontend: multichannelfrontend -frontend_conf: - fs: 16000 - window: hann - n_fft: 400 - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - use_channel: 0 - mc: False - -# encoder related -asr_encoder: conformer -asr_encoder_conf: - output_size: 256 # dimension of attention - attention_heads: 4 - linear_units: 2048 # the number of units of position-wise feed forward - num_blocks: 12 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - macaron_style: true - use_cnn_module: true - cnn_module_kernel: 15 - -spk_encoder: resnet34_diar -spk_encoder_conf: - use_head_conv: true - batchnorm_momentum: 0.5 - use_head_maxpool: false - num_nodes_pooling_layer: 256 - layers_in_block: - - 3 - - 4 - - 6 - - 3 - filters_in_block: - - 32 - - 64 - - 128 - - 256 - pooling_type: statistic - num_nodes_resnet1: 256 - num_nodes_last_layer: 256 - batchnorm_momentum: 0.5 - -# decoder related -decoder: sa_decoder -decoder_conf: - attention_heads: 4 - linear_units: 2048 - asr_num_blocks: 6 - spk_num_blocks: 3 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# hybrid CTC/attention -model_conf: - spk_weight: 0.5 - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - max_spk_num: 4 - -ctc_conf: - ignore_nan_grad: true - -# minibatch related -dataset_conf: - data_names: speech,text,profile,text_id - data_types: sound,text,npy,text_int - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 7000 - num_workers: 8 - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 60 -val_scheduler_criterion: - - valid - - loss -best_model_criterion: -- - valid - - acc - - max -- - valid - - acc_spk - - max -- - valid - - loss - - min -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 8000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - diff --git a/egs/alimeeting/sa_asr/local/alimeeting_data_prep.sh b/egs/alimeeting/sa_asr/local/alimeeting_data_prep.sh deleted file mode 100755 index fd76837b1..000000000 --- a/egs/alimeeting/sa_asr/local/alimeeting_data_prep.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env bash -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -log() { - local fname=${BASH_SOURCE[1]##*/} - echo -e "$(date '+%Y-%m-%dT%H:%M:%S') (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $*" -} - -help_messge=$(cat << EOF -Usage: $0 - -Options: - --no_overlap (bool): Whether to ignore the overlapping utterance in the training set. - --tgt (string): Which set to process, test or train. -EOF -) - -SECONDS=0 -tgt=Train #Train or Eval -min_wav_duration=0.1 -max_wav_duration=20 - - -log "$0 $*" -echo $tgt -. ./utils/parse_options.sh - -. ./path.sh - -AliMeeting="${PWD}/dataset" - -if [ $# -gt 2 ]; then - log "${help_message}" - exit 2 -fi - - -if [ ! -d "${AliMeeting}" ]; then - log "Error: ${AliMeeting} is empty." - exit 2 -fi - -# To absolute path -AliMeeting=$(cd ${AliMeeting}; pwd) -echo $AliMeeting -far_raw_dir=${AliMeeting}/${tgt}_Ali_far/ -near_raw_dir=${AliMeeting}/${tgt}_Ali_near/ - -far_dir=data/local/${tgt}_Ali_far -near_dir=data/local/${tgt}_Ali_near -far_single_speaker_dir=data/local/${tgt}_Ali_far_correct_single_speaker -mkdir -p $far_single_speaker_dir - -stage=1 -stop_stage=4 -mkdir -p $far_dir -mkdir -p $near_dir -mkdir -p data/org - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - log "stage 1:process alimeeting near dir" - - find -L $near_raw_dir/audio_dir -iname "*.wav" | sort > $near_dir/wavlist - awk -F '/' '{print $NF}' $near_dir/wavlist | awk -F '.' '{print $1}' | sort > $near_dir/uttid - find -L $near_raw_dir/textgrid_dir -iname "*.TextGrid" > $near_dir/textgrid.flist - n1_wav=$(wc -l < $near_dir/wavlist) - n2_text=$(wc -l < $near_dir/textgrid.flist) - log near file found $n1_wav wav and $n2_text text. - - paste $near_dir/uttid $near_dir/wavlist -d " " > $near_dir/wav.scp - - python local/alimeeting_process_textgrid.py --path $near_dir --no-overlap False - cat $near_dir/text_all | local/text_normalize.pl | local/text_format.pl | sort -u > $near_dir/text - utils/filter_scp.pl -f 1 $near_dir/text $near_dir/utt2spk_all | sort -u > $near_dir/utt2spk - - local/utt2spk_to_spk2utt.pl $near_dir/utt2spk > $near_dir/spk2utt - utils/filter_scp.pl -f 1 $near_dir/text $near_dir/segments_all | sort -u > $near_dir/segments - sed -e 's/ $//g' $near_dir/text> $near_dir/tmp1 - sed -e 's/!//g' $near_dir/tmp1> $near_dir/tmp2 - sed -e 's/?//g' $near_dir/tmp2> $near_dir/text - -fi - - -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - log "stage 2:process alimeeting far dir" - - find -L $far_raw_dir/audio_dir -iname "*.wav" | sort > $far_dir/wavlist - awk -F '/' '{print $NF}' $far_dir/wavlist | awk -F '.' '{print $1}' > $far_dir/uttid - find -L $far_raw_dir/textgrid_dir -iname "*.TextGrid" | sort > $far_dir/textgrid.flist - n1_wav=$(wc -l < $far_dir/wavlist) - n2_text=$(wc -l < $far_dir/textgrid.flist) - log far file found $n1_wav wav and $n2_text text. - - paste $far_dir/uttid $far_dir/wavlist -d " " > $far_dir/wav.scp - - python local/alimeeting_process_overlap_force.py --path $far_dir \ - --no-overlap false --mars True \ - --overlap_length 0.8 --max_length 7 - - cat $far_dir/text_all | local/text_normalize.pl | local/text_format.pl | sort -u > $far_dir/text - utils/filter_scp.pl -f 1 $far_dir/text $far_dir/utt2spk_all | sort -u > $far_dir/utt2spk - #sed -e 's/ [a-z,A-Z,_,0-9,-]\+SPK/ SPK/' $far_dir/utt2spk_old >$far_dir/utt2spk - - local/utt2spk_to_spk2utt.pl $far_dir/utt2spk > $far_dir/spk2utt - utils/filter_scp.pl -f 1 $far_dir/text $far_dir/segments_all | sort -u > $far_dir/segments - sed -e 's/SRC/$/g' $far_dir/text> $far_dir/tmp1 - sed -e 's/ $//g' $far_dir/tmp1> $far_dir/tmp2 - sed -e 's/!//g' $far_dir/tmp2> $far_dir/tmp3 - sed -e 's/?//g' $far_dir/tmp3> $far_dir/text -fi - - -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - log "stage 3: final data process" - local/fix_data_dir.sh $near_dir - local/fix_data_dir.sh $far_dir - local/copy_data_dir.sh $near_dir data/org/${tgt}_Ali_near - local/copy_data_dir.sh $far_dir data/org/${tgt}_Ali_far - - sort $far_dir/utt2spk_all_fifo > data/org/${tgt}_Ali_far/utt2spk_all_fifo - sed -i "s/src/$/g" data/org/${tgt}_Ali_far/utt2spk_all_fifo - - # remove space in text - for x in ${tgt}_Ali_near ${tgt}_Ali_far; do - cp data/org/${x}/text data/org/${x}/text.org - paste -d " " <(cut -f 1 -d" " data/org/${x}/text.org) <(cut -f 2- -d" " data/org/${x}/text.org | tr -d " ") \ - > data/org/${x}/text - rm data/org/${x}/text.org - done - - log "Successfully finished. [elapsed=${SECONDS}s]" -fi - -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - log "stage 4: process alimeeting far dir (single speaker by oracle time stamp)" - cp -r $far_dir/* $far_single_speaker_dir - mv $far_single_speaker_dir/textgrid.flist $far_single_speaker_dir/textgrid_oldpath - paste -d " " $far_single_speaker_dir/uttid $far_single_speaker_dir/textgrid_oldpath > $far_single_speaker_dir/textgrid.flist - python local/process_textgrid_to_single_speaker_wav.py --path $far_single_speaker_dir - - cp $far_single_speaker_dir/utt2spk $far_single_speaker_dir/text - local/utt2spk_to_spk2utt.pl $far_single_speaker_dir/utt2spk > $far_single_speaker_dir/spk2utt - - ./local/fix_data_dir.sh $far_single_speaker_dir - local/copy_data_dir.sh $far_single_speaker_dir data/org/${tgt}_Ali_far_single_speaker - - # remove space in text - for x in ${tgt}_Ali_far_single_speaker; do - cp data/org/${x}/text data/org/${x}/text.org - paste -d " " <(cut -f 1 -d" " data/org/${x}/text.org) <(cut -f 2- -d" " data/org/${x}/text.org | tr -d " ") \ - > data/org/${x}/text - rm data/org/${x}/text.org - done - rm -rf data/local - log "Successfully finished. [elapsed=${SECONDS}s]" -fi \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/alimeeting_data_prep_test_2023.sh b/egs/alimeeting/sa_asr/local/alimeeting_data_prep_test_2023.sh deleted file mode 100755 index e3ce934dc..000000000 --- a/egs/alimeeting/sa_asr/local/alimeeting_data_prep_test_2023.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env bash -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -log() { - local fname=${BASH_SOURCE[1]##*/} - echo -e "$(date '+%Y-%m-%dT%H:%M:%S') (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $*" -} - -help_messge=$(cat << EOF -Usage: $0 - -Options: - --no_overlap (bool): Whether to ignore the overlapping utterance in the training set. - --tgt (string): Which set to process, test or train. -EOF -) - -SECONDS=0 -tgt=Train #Train or Eval - - -log "$0 $*" -echo $tgt -. ./utils/parse_options.sh - -. ./path.sh - -AliMeeting="${PWD}/dataset" - -if [ $# -gt 2 ]; then - log "${help_message}" - exit 2 -fi - - -if [ ! -d "${AliMeeting}" ]; then - log "Error: ${AliMeeting} is empty." - exit 2 -fi - -# To absolute path -AliMeeting=$(cd ${AliMeeting}; pwd) -echo $AliMeeting -far_raw_dir=${AliMeeting}/${tgt}_Ali_far/ - -far_dir=data/local/${tgt}_Ali_far -far_single_speaker_dir=data/local/${tgt}_Ali_far_correct_single_speaker -mkdir -p $far_single_speaker_dir - -stage=1 -stop_stage=3 -mkdir -p $far_dir - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - log "stage 1:process alimeeting far dir" - - find -L $far_raw_dir/audio_dir -iname "*.wav" > $far_dir/wavlist - awk -F '/' '{print $NF}' $far_dir/wavlist | awk -F '.' '{print $1}' > $far_dir/uttid - find -L $far_raw_dir/textgrid_dir -iname "*.TextGrid" > $far_dir/textgrid.flist - n1_wav=$(wc -l < $far_dir/wavlist) - n2_text=$(wc -l < $far_dir/textgrid.flist) - log far file found $n1_wav wav and $n2_text text. - - paste $far_dir/uttid $far_dir/wavlist > $far_dir/wav_raw.scp - - cat $far_dir/wav_raw.scp | awk '{printf("%s sox -t wav %s -r 16000 -b 16 -t wav - |\n", $1, $2)}' > $far_dir/wav.scp - - python local/alimeeting_process_overlap_force.py --path $far_dir \ - --no-overlap false --mars True \ - --overlap_length 0.8 --max_length 7 - - cat $far_dir/text_all | local/text_normalize.pl | local/text_format.pl | sort -u > $far_dir/text - utils/filter_scp.pl -f 1 $far_dir/text $far_dir/utt2spk_all | sort -u > $far_dir/utt2spk - #sed -e 's/ [a-z,A-Z,_,0-9,-]\+SPK/ SPK/' $far_dir/utt2spk_old >$far_dir/utt2spk - - local/utt2spk_to_spk2utt.pl $far_dir/utt2spk > $far_dir/spk2utt - utils/filter_scp.pl -f 1 $far_dir/text $far_dir/segments_all | sort -u > $far_dir/segments - sed -e 's/SRC/$/g' $far_dir/text> $far_dir/tmp1 - sed -e 's/ $//g' $far_dir/tmp1> $far_dir/tmp2 - sed -e 's/!//g' $far_dir/tmp2> $far_dir/tmp3 - sed -e 's/?//g' $far_dir/tmp3> $far_dir/text -fi - - -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - log "stage 2: finali data process" - - local/copy_data_dir.sh $far_dir data/${tgt}_Ali_far - - sort $far_dir/utt2spk_all_fifo > data/${tgt}_Ali_far/utt2spk_all_fifo - sed -i "s/src/$/g" data/${tgt}_Ali_far/utt2spk_all_fifo - - # remove space in text - for x in ${tgt}_Ali_far; do - cp data/${x}/text data/${x}/text.org - paste -d " " <(cut -f 1 -d" " data/${x}/text.org) <(cut -f 2- -d" " data/${x}/text.org | tr -d " ") \ - > data/${x}/text - rm data/${x}/text.org - done - - log "Successfully finished. [elapsed=${SECONDS}s]" -fi - -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - log "stage 3:process alimeeting far dir (single speaker by oracal time strap)" - cp -r $far_dir/* $far_single_speaker_dir - mv $far_single_speaker_dir/textgrid.flist $far_single_speaker_dir/textgrid_oldpath - paste -d " " $far_single_speaker_dir/uttid $far_single_speaker_dir/textgrid_oldpath > $far_single_speaker_dir/textgrid.flist - python local/process_textgrid_to_single_speaker_wav.py --path $far_single_speaker_dir - - cp $far_single_speaker_dir/utt2spk $far_single_speaker_dir/text - local/utt2spk_to_spk2utt.pl $far_single_speaker_dir/utt2spk > $far_single_speaker_dir/spk2utt - - ./local/fix_data_dir.sh $far_single_speaker_dir - local/copy_data_dir.sh $far_single_speaker_dir data/${tgt}_Ali_far_single_speaker - - # remove space in text - for x in ${tgt}_Ali_far_single_speaker; do - cp data/${x}/text data/${x}/text.org - paste -d " " <(cut -f 1 -d" " data/${x}/text.org) <(cut -f 2- -d" " data/${x}/text.org | tr -d " ") \ - > data/${x}/text - rm data/${x}/text.org - done - log "Successfully finished. [elapsed=${SECONDS}s]" -fi \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/alimeeting_process_overlap_force.py b/egs/alimeeting/sa_asr/local/alimeeting_process_overlap_force.py deleted file mode 100755 index 769003d30..000000000 --- a/egs/alimeeting/sa_asr/local/alimeeting_process_overlap_force.py +++ /dev/null @@ -1,238 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Process the textgrid files -""" -import argparse -import codecs -from distutils.util import strtobool -from pathlib import Path -try: - import textgrid -except: - raise "Please install textgrid firstly: pip install textgrid" -import pdb - -class Segment(object): - def __init__(self, uttid, spkr, stime, etime, text): - self.uttid = uttid - self.spkr = spkr - self.spkr_all = uttid+"-"+spkr - self.stime = round(stime, 2) - self.etime = round(etime, 2) - self.text = text - self.spk_text = {uttid+"-"+spkr: text} - - def change_stime(self, time): - self.stime = time - - def change_etime(self, time): - self.etime = time - - -def get_args(): - parser = argparse.ArgumentParser(description="process the textgrid files") - parser.add_argument("--path", type=str, required=True, help="Data path") - parser.add_argument( - "--no-overlap", - type=strtobool, - default=False, - help="Whether to ignore the overlapping utterances.", - ) - parser.add_argument( - "--max_length", - default=100000, - type=float, - help="overlap speech max time,if longger than max length should cut", - ) - parser.add_argument( - "--overlap_length", - default=1, - type=float, - help="if length longer than max length, speech overlength shorter, is cut", - ) - parser.add_argument( - "--mars", - type=strtobool, - default=False, - help="Whether to process mars data set.", - ) - args = parser.parse_args() - return args - - -def preposs_overlap(segments,max_length,overlap_length): - new_segments = [] - # init a helper list to store all overlap segments - tmp_segments = segments[0] - min_stime = segments[0].stime - max_etime = segments[0].etime - overlap_length_big = 1.5 - max_length_big = 15 - for i in range(1, len(segments)): - if segments[i].stime >= max_etime: - # doesn't overlap with preivous segments - new_segments.append(tmp_segments) - tmp_segments = segments[i] - min_stime = segments[i].stime - max_etime = segments[i].etime - else: - # overlap with previous segments - dur_time = max_etime - min_stime - if dur_time < max_length: - if min_stime > segments[i].stime: - min_stime = segments[i].stime - if max_etime < segments[i].etime: - max_etime = segments[i].etime - tmp_segments.stime = min_stime - tmp_segments.etime = max_etime - tmp_segments.text = tmp_segments.text + "src" + segments[i].text - spk_name =segments[i].uttid +"-" + segments[i].spkr - if spk_name in tmp_segments.spk_text: - tmp_segments.spk_text[spk_name] += segments[i].text - else: - tmp_segments.spk_text[spk_name] = segments[i].text - tmp_segments.spkr_all = tmp_segments.spkr_all + "src" + spk_name - else: - overlap_time = max_etime - segments[i].stime - if dur_time < max_length_big: - overlap_length_option = overlap_length - else: - overlap_length_option = overlap_length_big - if overlap_time > overlap_length_option: - if min_stime > segments[i].stime: - min_stime = segments[i].stime - if max_etime < segments[i].etime: - max_etime = segments[i].etime - tmp_segments.stime = min_stime - tmp_segments.etime = max_etime - tmp_segments.text = tmp_segments.text + "src" + segments[i].text - spk_name =segments[i].uttid +"-" + segments[i].spkr - if spk_name in tmp_segments.spk_text: - tmp_segments.spk_text[spk_name] += segments[i].text - else: - tmp_segments.spk_text[spk_name] = segments[i].text - tmp_segments.spkr_all = tmp_segments.spkr_all + "src" + spk_name - else: - new_segments.append(tmp_segments) - tmp_segments = segments[i] - min_stime = segments[i].stime - max_etime = segments[i].etime - - return new_segments - -def filter_overlap(segments): - new_segments = [] - # init a helper list to store all overlap segments - tmp_segments = [segments[0]] - min_stime = segments[0].stime - max_etime = segments[0].etime - - for i in range(1, len(segments)): - if segments[i].stime >= max_etime: - # doesn't overlap with preivous segments - if len(tmp_segments) == 1: - new_segments.append(tmp_segments[0]) - # TODO: for multi-spkr asr, we can reset the stime/etime to - # min_stime/max_etime for generating a max length mixutre speech - tmp_segments = [segments[i]] - min_stime = segments[i].stime - max_etime = segments[i].etime - else: - # overlap with previous segments - tmp_segments.append(segments[i]) - if min_stime > segments[i].stime: - min_stime = segments[i].stime - if max_etime < segments[i].etime: - max_etime = segments[i].etime - - return new_segments - - -def main(args): - wav_scp = codecs.open(Path(args.path) / "wav.scp", "r", "utf-8") - textgrid_flist = codecs.open(Path(args.path) / "textgrid.flist", "r", "utf-8") - - # get the path of textgrid file for each utterance - utt2textgrid = {} - for line in textgrid_flist: - path = Path(line.strip()) - uttid = path.stem - utt2textgrid[uttid] = path - - # parse the textgrid file for each utterance - all_segments = [] - for line in wav_scp: - uttid = line.strip().split(" ")[0] - uttid_part=uttid - if args.mars == True: - uttid_list = uttid.split("_") - uttid_part= uttid_list[0]+"_"+uttid_list[1] - if uttid_part not in utt2textgrid: - print("%s doesn't have transcription" % uttid) - continue - - segments = [] - tg = textgrid.TextGrid.fromFile(utt2textgrid[uttid_part]) - for i in range(tg.__len__()): - for j in range(tg[i].__len__()): - if tg[i][j].mark: - segments.append( - Segment( - uttid, - tg[i].name, - tg[i][j].minTime, - tg[i][j].maxTime, - tg[i][j].mark.strip(), - ) - ) - - segments = sorted(segments, key=lambda x: x.stime) - - if args.no_overlap: - segments = filter_overlap(segments) - else: - segments = preposs_overlap(segments,args.max_length,args.overlap_length) - all_segments += segments - - wav_scp.close() - textgrid_flist.close() - - segments_file = codecs.open(Path(args.path) / "segments_all", "w", "utf-8") - utt2spk_file = codecs.open(Path(args.path) / "utt2spk_all", "w", "utf-8") - text_file = codecs.open(Path(args.path) / "text_all", "w", "utf-8") - utt2spk_file_fifo = codecs.open(Path(args.path) / "utt2spk_all_fifo", "w", "utf-8") - - for i in range(len(all_segments)): - utt_name = "%s-%s-%07d-%07d" % ( - all_segments[i].uttid, - all_segments[i].spkr, - all_segments[i].stime * 100, - all_segments[i].etime * 100, - ) - - segments_file.write( - "%s %s %.2f %.2f\n" - % ( - utt_name, - all_segments[i].uttid, - all_segments[i].stime, - all_segments[i].etime, - ) - ) - utt2spk_file.write( - "%s %s-%s\n" % (utt_name, all_segments[i].uttid, all_segments[i].spkr) - ) - utt2spk_file_fifo.write( - "%s %s\n" % (utt_name, all_segments[i].spkr_all) - ) - text_file.write("%s %s\n" % (utt_name, all_segments[i].text)) - - segments_file.close() - utt2spk_file.close() - text_file.close() - utt2spk_file_fifo.close() - - -if __name__ == "__main__": - args = get_args() - main(args) diff --git a/egs/alimeeting/sa_asr/local/alimeeting_process_textgrid.py b/egs/alimeeting/sa_asr/local/alimeeting_process_textgrid.py deleted file mode 100755 index b6d01572e..000000000 --- a/egs/alimeeting/sa_asr/local/alimeeting_process_textgrid.py +++ /dev/null @@ -1,161 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Process the textgrid files -""" -import argparse -import codecs -from distutils.util import strtobool -from pathlib import Path -try: - import textgrid -except: - raise "Please install textgrid firstly: pip install textgrid" -import pdb - -class Segment(object): - def __init__(self, uttid, spkr, stime, etime, text): - self.uttid = uttid - self.spkr = spkr - self.stime = round(stime, 2) - self.etime = round(etime, 2) - self.text = text - - def change_stime(self, time): - self.stime = time - - def change_etime(self, time): - self.etime = time - - -def get_args(): - parser = argparse.ArgumentParser(description="process the textgrid files") - parser.add_argument("--path", type=str, required=True, help="Data path") - parser.add_argument( - "--no-overlap", - type=strtobool, - default=False, - help="Whether to ignore the overlapping utterances.", - ) - parser.add_argument( - "--mars", - type=strtobool, - default=False, - help="Whether to process mars data set.", - ) - args = parser.parse_args() - return args - - -def filter_overlap(segments): - new_segments = [] - # init a helper list to store all overlap segments - tmp_segments = [segments[0]] - min_stime = segments[0].stime - max_etime = segments[0].etime - - for i in range(1, len(segments)): - if segments[i].stime >= max_etime: - # doesn't overlap with preivous segments - if len(tmp_segments) == 1: - new_segments.append(tmp_segments[0]) - # TODO: for multi-spkr asr, we can reset the stime/etime to - # min_stime/max_etime for generating a max length mixutre speech - tmp_segments = [segments[i]] - min_stime = segments[i].stime - max_etime = segments[i].etime - else: - # overlap with previous segments - tmp_segments.append(segments[i]) - if min_stime > segments[i].stime: - min_stime = segments[i].stime - if max_etime < segments[i].etime: - max_etime = segments[i].etime - - return new_segments - - -def main(args): - wav_scp = codecs.open(Path(args.path) / "wav.scp", "r", "utf-8") - textgrid_flist = codecs.open(Path(args.path) / "textgrid.flist", "r", "utf-8") - - # get the path of textgrid file for each utterance - utt2textgrid = {} - for line in textgrid_flist: - path = Path(line.strip()) - uttid = path.stem - utt2textgrid[uttid] = path - - # parse the textgrid file for each utterance - all_segments = [] - for line in wav_scp: - uttid = line.strip().split(" ")[0] - uttid_part=uttid - if args.mars == True: - uttid_list = uttid.split("_") - uttid_part= uttid_list[0]+"_"+uttid_list[1] - if uttid_part not in utt2textgrid: - print("%s doesn't have transcription" % uttid) - continue - #pdb.set_trace() - segments = [] - try: - tg = textgrid.TextGrid.fromFile(utt2textgrid[uttid_part]) - except: - pdb.set_trace() - for i in range(tg.__len__()): - for j in range(tg[i].__len__()): - if tg[i][j].mark: - segments.append( - Segment( - uttid, - tg[i].name, - tg[i][j].minTime, - tg[i][j].maxTime, - tg[i][j].mark.strip(), - ) - ) - - segments = sorted(segments, key=lambda x: x.stime) - - if args.no_overlap: - segments = filter_overlap(segments) - - all_segments += segments - - wav_scp.close() - textgrid_flist.close() - - segments_file = codecs.open(Path(args.path) / "segments_all", "w", "utf-8") - utt2spk_file = codecs.open(Path(args.path) / "utt2spk_all", "w", "utf-8") - text_file = codecs.open(Path(args.path) / "text_all", "w", "utf-8") - - for i in range(len(all_segments)): - utt_name = "%s-%s-%07d-%07d" % ( - all_segments[i].uttid, - all_segments[i].spkr, - all_segments[i].stime * 100, - all_segments[i].etime * 100, - ) - - segments_file.write( - "%s %s %.2f %.2f\n" - % ( - utt_name, - all_segments[i].uttid, - all_segments[i].stime, - all_segments[i].etime, - ) - ) - utt2spk_file.write( - "%s %s-%s\n" % (utt_name, all_segments[i].uttid, all_segments[i].spkr) - ) - text_file.write("%s %s\n" % (utt_name, all_segments[i].text)) - - segments_file.close() - utt2spk_file.close() - text_file.close() - - -if __name__ == "__main__": - args = get_args() - main(args) diff --git a/egs/alimeeting/sa_asr/local/apply_map.pl b/egs/alimeeting/sa_asr/local/apply_map.pl deleted file mode 100755 index 725d3463a..000000000 --- a/egs/alimeeting/sa_asr/local/apply_map.pl +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env perl -use warnings; #sed replacement for -w perl parameter -# Copyright 2012 Johns Hopkins University (Author: Daniel Povey) -# Apache 2.0. - -# This program is a bit like ./sym2int.pl in that it applies a map -# to things in a file, but it's a bit more general in that it doesn't -# assume the things being mapped to are single tokens, they could -# be sequences of tokens. See the usage message. - - -$permissive = 0; - -for ($x = 0; $x <= 2; $x++) { - - if (@ARGV > 0 && $ARGV[0] eq "-f") { - shift @ARGV; - $field_spec = shift @ARGV; - if ($field_spec =~ m/^\d+$/) { - $field_begin = $field_spec - 1; $field_end = $field_spec - 1; - } - if ($field_spec =~ m/^(\d*)[-:](\d*)/) { # accept e.g. 1:10 as a courtesty (properly, 1-10) - if ($1 ne "") { - $field_begin = $1 - 1; # Change to zero-based indexing. - } - if ($2 ne "") { - $field_end = $2 - 1; # Change to zero-based indexing. - } - } - if (!defined $field_begin && !defined $field_end) { - die "Bad argument to -f option: $field_spec"; - } - } - - if (@ARGV > 0 && $ARGV[0] eq '--permissive') { - shift @ARGV; - # Mapping is optional (missing key is printed to output) - $permissive = 1; - } -} - -if(@ARGV != 1) { - print STDERR "Invalid usage: " . join(" ", @ARGV) . "\n"; - print STDERR <<'EOF'; -Usage: apply_map.pl [options] map output - options: [-f ] [--permissive] - This applies a map to some specified fields of some input text: - For each line in the map file: the first field is the thing we - map from, and the remaining fields are the sequence we map it to. - The -f (field-range) option says which fields of the input file the map - map should apply to. - If the --permissive option is supplied, fields which are not present - in the map will be left as they were. - Applies the map 'map' to all input text, where each line of the map - is interpreted as a map from the first field to the list of the other fields - Note: can look like 4-5, or 4-, or 5-, or 1, it means the field - range in the input to apply the map to. - e.g.: echo A B | apply_map.pl a.txt - where a.txt is: - A a1 a2 - B b - will produce: - a1 a2 b -EOF - exit(1); -} - -($map_file) = @ARGV; -open(M, "<$map_file") || die "Error opening map file $map_file: $!"; - -while () { - @A = split(" ", $_); - @A >= 1 || die "apply_map.pl: empty line."; - $i = shift @A; - $o = join(" ", @A); - $map{$i} = $o; -} - -while() { - @A = split(" ", $_); - for ($x = 0; $x < @A; $x++) { - if ( (!defined $field_begin || $x >= $field_begin) - && (!defined $field_end || $x <= $field_end)) { - $a = $A[$x]; - if (!defined $map{$a}) { - if (!$permissive) { - die "apply_map.pl: undefined key $a in $map_file\n"; - } else { - print STDERR "apply_map.pl: warning! missing key $a in $map_file\n"; - } - } else { - $A[$x] = $map{$a}; - } - } - } - print join(" ", @A) . "\n"; -} diff --git a/egs/alimeeting/sa_asr/local/combine_data.sh b/egs/alimeeting/sa_asr/local/combine_data.sh deleted file mode 100755 index a3436b503..000000000 --- a/egs/alimeeting/sa_asr/local/combine_data.sh +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2012 Johns Hopkins University (Author: Daniel Povey). Apache 2.0. -# 2014 David Snyder - -# This script combines the data from multiple source directories into -# a single destination directory. - -# See http://kaldi-asr.org/doc/data_prep.html#data_prep_data for information -# about what these directories contain. - -# Begin configuration section. -extra_files= # specify additional files in 'src-data-dir' to merge, ex. "file1 file2 ..." -skip_fix=false # skip the fix_data_dir.sh in the end -# End configuration section. - -echo "$0 $@" # Print the command line for logging - -if [ -f path.sh ]; then . ./path.sh; fi -. parse_options.sh || exit 1; - -if [ $# -lt 2 ]; then - echo "Usage: combine_data.sh [--extra-files 'file1 file2'] ..." - echo "Note, files that don't appear in all source dirs will not be combined," - echo "with the exception of utt2uniq and segments, which are created where necessary." - exit 1 -fi - -dest=$1; -shift; - -first_src=$1; - -rm -r $dest 2>/dev/null || true -mkdir -p $dest; - -export LC_ALL=C - -for dir in $*; do - if [ ! -f $dir/utt2spk ]; then - echo "$0: no such file $dir/utt2spk" - exit 1; - fi -done - -# Check that frame_shift are compatible, where present together with features. -dir_with_frame_shift= -for dir in $*; do - if [[ -f $dir/feats.scp && -f $dir/frame_shift ]]; then - if [[ $dir_with_frame_shift ]] && - ! cmp -s $dir_with_frame_shift/frame_shift $dir/frame_shift; then - echo "$0:error: different frame_shift in directories $dir and " \ - "$dir_with_frame_shift. Cannot combine features." - exit 1; - fi - dir_with_frame_shift=$dir - fi -done - -# W.r.t. utt2uniq file the script has different behavior compared to other files -# it is not compulsary for it to exist in src directories, but if it exists in -# even one it should exist in all. We will create the files where necessary -has_utt2uniq=false -for in_dir in $*; do - if [ -f $in_dir/utt2uniq ]; then - has_utt2uniq=true - break - fi -done - -if $has_utt2uniq; then - # we are going to create an utt2uniq file in the destdir - for in_dir in $*; do - if [ ! -f $in_dir/utt2uniq ]; then - # we assume that utt2uniq is a one to one mapping - cat $in_dir/utt2spk | awk '{printf("%s %s\n", $1, $1);}' - else - cat $in_dir/utt2uniq - fi - done | sort -k1 > $dest/utt2uniq - echo "$0: combined utt2uniq" -else - echo "$0 [info]: not combining utt2uniq as it does not exist" -fi -# some of the old scripts might provide utt2uniq as an extrafile, so just remove it -extra_files=$(echo "$extra_files"|sed -e "s/utt2uniq//g") - -# segments are treated similarly to utt2uniq. If it exists in some, but not all -# src directories, then we generate segments where necessary. -has_segments=false -for in_dir in $*; do - if [ -f $in_dir/segments ]; then - has_segments=true - break - fi -done - -if $has_segments; then - for in_dir in $*; do - if [ ! -f $in_dir/segments ]; then - echo "$0 [info]: will generate missing segments for $in_dir" 1>&2 - local/data/get_segments_for_data.sh $in_dir - else - cat $in_dir/segments - fi - done | sort -k1 > $dest/segments - echo "$0: combined segments" -else - echo "$0 [info]: not combining segments as it does not exist" -fi - -for file in utt2spk utt2lang utt2dur utt2num_frames reco2dur feats.scp text cmvn.scp vad.scp reco2file_and_channel wav.scp spk2gender $extra_files; do - exists_somewhere=false - absent_somewhere=false - for d in $*; do - if [ -f $d/$file ]; then - exists_somewhere=true - else - absent_somewhere=true - fi - done - - if ! $absent_somewhere; then - set -o pipefail - ( for f in $*; do cat $f/$file; done ) | sort -k1 > $dest/$file || exit 1; - set +o pipefail - echo "$0: combined $file" - else - if ! $exists_somewhere; then - echo "$0 [info]: not combining $file as it does not exist" - else - echo "$0 [info]: **not combining $file as it does not exist everywhere**" - fi - fi -done - -local/utt2spk_to_spk2utt.pl <$dest/utt2spk >$dest/spk2utt - -if [[ $dir_with_frame_shift ]]; then - cp $dir_with_frame_shift/frame_shift $dest -fi - -if ! $skip_fix ; then - local/fix_data_dir.sh $dest || exit 1; -fi - -exit 0 diff --git a/egs/alimeeting/sa_asr/local/compute_cmvn.py b/egs/alimeeting/sa_asr/local/compute_cmvn.py deleted file mode 100755 index d16563a96..000000000 --- a/egs/alimeeting/sa_asr/local/compute_cmvn.py +++ /dev/null @@ -1,134 +0,0 @@ -import argparse -import json -import os - -import numpy as np -import torchaudio -import torchaudio.compliance.kaldi as kaldi -import yaml -from funasr.models.frontend.default import DefaultFrontend -import torch - -def get_parser(): - parser = argparse.ArgumentParser( - description="computer global cmvn", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "--dim", - default=80, - type=int, - help="feature dimension", - ) - parser.add_argument( - "--wav_path", - default=False, - required=True, - type=str, - help="the path of wav scps", - ) - parser.add_argument( - "--config_file", - type=str, - help="the config file for computing cmvn", - ) - parser.add_argument( - "--idx", - default=1, - required=True, - type=int, - help="index", - ) - return parser - - -def compute_fbank(wav_file, - num_mel_bins=80, - frame_length=25, - frame_shift=10, - dither=0.0, - resample_rate=16000, - speed=1.0, - window_type="hamming"): - waveform, sample_rate = torchaudio.load(wav_file) - if resample_rate != sample_rate: - waveform = torchaudio.transforms.Resample(orig_freq=sample_rate, - new_freq=resample_rate)(waveform) - if speed != 1.0: - waveform, _ = torchaudio.sox_effects.apply_effects_tensor( - waveform, resample_rate, - [['speed', str(speed)], ['rate', str(resample_rate)]] - ) - - waveform = waveform * (1 << 15) - mat = kaldi.fbank(waveform, - num_mel_bins=num_mel_bins, - frame_length=frame_length, - frame_shift=frame_shift, - dither=dither, - energy_floor=0.0, - window_type=window_type, - sample_frequency=resample_rate) - - return mat.numpy() - - -def main(): - parser = get_parser() - args = parser.parse_args() - - wav_scp_file = os.path.join(args.wav_path, "wav.{}.scp".format(args.idx)) - cmvn_file = os.path.join(args.wav_path, "cmvn.{}.json".format(args.idx)) - - mean_stats = np.zeros(args.dim) - var_stats = np.zeros(args.dim) - total_frames = 0 - - # with ReadHelper('ark:{}'.format(ark_file)) as ark_reader: - # for key, mat in ark_reader: - # mean_stats += np.sum(mat, axis=0) - # var_stats += np.sum(np.square(mat), axis=0) - # total_frames += mat.shape[0] - - with open(args.config_file) as f: - configs = yaml.safe_load(f) - frontend_configs = configs.get("frontend_conf", {}) - num_mel_bins = frontend_configs.get("n_mels", 80) - frame_length = frontend_configs.get("frame_length", 25) - frame_shift = frontend_configs.get("frame_shift", 10) - window_type = frontend_configs.get("window", "hamming") - resample_rate = frontend_configs.get("fs", 16000) - n_fft = frontend_configs.get("n_fft", "400") - use_channel = frontend_configs.get("use_channel", None) - assert num_mel_bins == args.dim - frontend = DefaultFrontend( - fs=resample_rate, - n_fft=n_fft, - win_length=frame_length * 16, - hop_length=frame_shift * 16, - window=window_type, - n_mels=num_mel_bins, - use_channel=use_channel, - ) - with open(wav_scp_file) as f: - lines = f.readlines() - for line in lines: - _, wav_file = line.strip().split() - wavform, _ = torchaudio.load(wav_file) - fbank, _ = frontend(wavform.transpose(0, 1).unsqueeze(0), torch.tensor([wavform.shape[1]])) - fbank = fbank.squeeze(0).numpy() - mean_stats += np.sum(fbank, axis=0) - var_stats += np.sum(np.square(fbank), axis=0) - total_frames += fbank.shape[0] - - cmvn_info = { - 'mean_stats': list(mean_stats.tolist()), - 'var_stats': list(var_stats.tolist()), - 'total_frames': total_frames - } - with open(cmvn_file, 'w') as fout: - fout.write(json.dumps(cmvn_info)) - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/compute_cmvn.sh b/egs/alimeeting/sa_asr/local/compute_cmvn.sh deleted file mode 100755 index 00d08d14c..000000000 --- a/egs/alimeeting/sa_asr/local/compute_cmvn.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; -# Begin configuration section. -fbankdir= -nj=32 -cmd=./utils/run.pl -feats_dim=80 -config_file= -scale=1.0 - -echo "$0 $@" - -. utils/parse_options.sh || exit 1; - -# shellcheck disable=SC2046 -head -n $(awk -v lines="$(wc -l < ${fbankdir}/wav.scp)" -v scale="$scale" 'BEGIN { printf "%.0f\n", lines*scale }') ${fbankdir}/wav.scp > ${fbankdir}/wav.scp.scale - -split_dir=${fbankdir}/cmvn/split_${nj}; -mkdir -p $split_dir -split_scps="" -for n in $(seq $nj); do - split_scps="$split_scps $split_dir/wav.$n.scp" -done -utils/split_scp.pl ${fbankdir}/wav.scp.scale $split_scps || exit 1; - -logdir=${fbankdir}/cmvn/log -$cmd JOB=1:$nj $logdir/cmvn.JOB.log \ - python local/compute_cmvn.py \ - --dim ${feats_dim} \ - --wav_path $split_dir \ - --config_file $config_file \ - --idx JOB \ - -python utils/combine_cmvn_file.py --dim ${feats_dim} --cmvn_dir $split_dir --nj $nj --output_dir ${fbankdir}/cmvn - -python utils/cmvn_converter.py --cmvn_json ${fbankdir}/cmvn/cmvn.json --am_mvn ${fbankdir}/cmvn/am.mvn - -echo "$0: Succeeded compute global cmvn" diff --git a/egs/alimeeting/sa_asr/local/compute_cpcer.py b/egs/alimeeting/sa_asr/local/compute_cpcer.py deleted file mode 100644 index f4d4a7978..000000000 --- a/egs/alimeeting/sa_asr/local/compute_cpcer.py +++ /dev/null @@ -1,91 +0,0 @@ -import editdistance -import sys -import os -from itertools import permutations - - -def load_transcripts(file_path): - trans_list = [] - for one_line in open(file_path, "rt"): - meeting_id, trans = one_line.strip().split(" ") - trans_list.append((meeting_id.strip(), trans.strip())) - - return trans_list - -def calc_spk_trans(trans): - spk_trans_ = [x.strip() for x in trans.split("$")] - spk_trans = [] - for i in range(len(spk_trans_)): - spk_trans.append((str(i), spk_trans_[i])) - return spk_trans - -def calc_cer(ref_trans, hyp_trans): - ref_spk_trans = calc_spk_trans(ref_trans) - hyp_spk_trans = calc_spk_trans(hyp_trans) - ref_spk_num, hyp_spk_num = len(ref_spk_trans), len(hyp_spk_trans) - num_spk = max(len(ref_spk_trans), len(hyp_spk_trans)) - ref_spk_trans.extend([("", "")] * (num_spk - len(ref_spk_trans))) - hyp_spk_trans.extend([("", "")] * (num_spk - len(hyp_spk_trans))) - - errors, counts, permutes = [], [], [] - min_error = 0 - cost_dict = {} - for perm in permutations(range(num_spk)): - flag = True - p_err, p_count = 0, 0 - for idx, p in enumerate(perm): - if abs(len(ref_spk_trans[idx][1]) - len(hyp_spk_trans[p][1])) > min_error > 0: - flag = False - break - cost_key = "{}-{}".format(idx, p) - if cost_key in cost_dict: - _e = cost_dict[cost_key] - else: - _e = editdistance.eval(ref_spk_trans[idx][1], hyp_spk_trans[p][1]) - cost_dict[cost_key] = _e - if _e > min_error > 0: - flag = False - break - p_err += _e - p_count += len(ref_spk_trans[idx][1]) - - if flag: - if p_err < min_error or min_error == 0: - min_error = p_err - - errors.append(p_err) - counts.append(p_count) - permutes.append(perm) - - sd_cer = [(err, cnt, err/cnt, permute) - for err, cnt, permute in zip(errors, counts, permutes)] - # import ipdb;ipdb.set_trace() - best_rst = min(sd_cer, key=lambda x: x[2]) - - return best_rst[0], best_rst[1], ref_spk_num, hyp_spk_num - - -def main(): - ref=sys.argv[1] - hyp=sys.argv[2] - result_path=sys.argv[3] - ref_list = load_transcripts(ref) - hyp_list = load_transcripts(hyp) - result_file = open(result_path,'w') - error, count = 0, 0 - for (ref_id, ref_trans), (hyp_id, hyp_trans) in zip(ref_list, hyp_list): - assert ref_id == hyp_id - mid = ref_id - dist, length, ref_spk_num, hyp_spk_num = calc_cer(ref_trans, hyp_trans) - error, count = error + dist, count + length - result_file.write("{} {:.2f} {} {}\n".format(mid, dist / length * 100.0, ref_spk_num, hyp_spk_num)) - - # print("{} {:.2f} {} {}".format(mid, dist / length * 100.0, ref_spk_num, hyp_spk_num)) - - result_file.write("CP-CER: {:.2f}\n".format(error / count * 100.0)) - result_file.close() - # print("Sum/Avg: {:.2f}".format(error / count * 100.0)) - - -if __name__ == '__main__': - main() diff --git a/egs/alimeeting/sa_asr/local/convert_model.py b/egs/alimeeting/sa_asr/local/convert_model.py deleted file mode 100644 index f0f7997fc..000000000 --- a/egs/alimeeting/sa_asr/local/convert_model.py +++ /dev/null @@ -1,29 +0,0 @@ -import codecs -import pdb -import sys -import torch - -char1 = sys.argv[1] -char2 = sys.argv[2] -model1 = torch.load(sys.argv[3], map_location='cpu') -model2_path = sys.argv[4] - -d_new = model1 -char1_list = [] -map_list = [] - - -with codecs.open(char1) as f: - for line in f.readlines(): - char1_list.append(line.strip()) - -with codecs.open(char2) as f: - for line in f.readlines(): - map_list.append(char1_list.index(line.strip())) -print(map_list) - -for k, v in d_new.items(): - if k == 'ctc.ctc_lo.weight' or k == 'ctc.ctc_lo.bias' or k == 'decoder.output_layer.weight' or k == 'decoder.output_layer.bias' or k == 'decoder.embed.0.weight': - d_new[k] = v[map_list] - -torch.save(d_new, model2_path) diff --git a/egs/alimeeting/sa_asr/local/copy_data_dir.sh b/egs/alimeeting/sa_asr/local/copy_data_dir.sh deleted file mode 100755 index 6e748dd9f..000000000 --- a/egs/alimeeting/sa_asr/local/copy_data_dir.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2013 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -# This script operates on a directory, such as in data/train/, -# that contains some subset of the following files: -# feats.scp -# wav.scp -# vad.scp -# spk2utt -# utt2spk -# text -# -# It copies to another directory, possibly adding a specified prefix or a suffix -# to the utterance and/or speaker names. Note, the recording-ids stay the same. -# - - -# begin configuration section -spk_prefix= -utt_prefix= -spk_suffix= -utt_suffix= -validate_opts= # should rarely be needed. -# end configuration section - -. utils/parse_options.sh - -if [ $# != 2 ]; then - echo "Usage: " - echo " $0 [options] " - echo "e.g.:" - echo " $0 --spk-prefix=1- --utt-prefix=1- data/train data/train_1" - echo "Options" - echo " --spk-prefix= # Prefix for speaker ids, default empty" - echo " --utt-prefix= # Prefix for utterance ids, default empty" - echo " --spk-suffix= # Suffix for speaker ids, default empty" - echo " --utt-suffix= # Suffix for utterance ids, default empty" - exit 1; -fi - - -export LC_ALL=C - -srcdir=$1 -destdir=$2 - -if [ ! -f $srcdir/utt2spk ]; then - echo "copy_data_dir.sh: no such file $srcdir/utt2spk" - exit 1; -fi - -if [ "$destdir" == "$srcdir" ]; then - echo "$0: this script requires and to be different." - exit 1 -fi - -set -e; - -mkdir -p $destdir - -cat $srcdir/utt2spk | awk -v p=$utt_prefix -v s=$utt_suffix '{printf("%s %s%s%s\n", $1, p, $1, s);}' > $destdir/utt_map -cat $srcdir/spk2utt | awk -v p=$spk_prefix -v s=$spk_suffix '{printf("%s %s%s%s\n", $1, p, $1, s);}' > $destdir/spk_map - -if [ ! -f $srcdir/utt2uniq ]; then - if [[ ! -z $utt_prefix || ! -z $utt_suffix ]]; then - cat $srcdir/utt2spk | awk -v p=$utt_prefix -v s=$utt_suffix '{printf("%s%s%s %s\n", p, $1, s, $1);}' > $destdir/utt2uniq - fi -else - cat $srcdir/utt2uniq | awk -v p=$utt_prefix -v s=$utt_suffix '{printf("%s%s%s %s\n", p, $1, s, $2);}' > $destdir/utt2uniq -fi - -cat $srcdir/utt2spk | local/apply_map.pl -f 1 $destdir/utt_map | \ - local/apply_map.pl -f 2 $destdir/spk_map >$destdir/utt2spk - -local/utt2spk_to_spk2utt.pl <$destdir/utt2spk >$destdir/spk2utt - -if [ -f $srcdir/feats.scp ]; then - local/apply_map.pl -f 1 $destdir/utt_map <$srcdir/feats.scp >$destdir/feats.scp -fi - -if [ -f $srcdir/vad.scp ]; then - local/apply_map.pl -f 1 $destdir/utt_map <$srcdir/vad.scp >$destdir/vad.scp -fi - -if [ -f $srcdir/segments ]; then - local/apply_map.pl -f 1 $destdir/utt_map <$srcdir/segments >$destdir/segments - cp $srcdir/wav.scp $destdir -else # no segments->wav indexed by utt. - if [ -f $srcdir/wav.scp ]; then - local/apply_map.pl -f 1 $destdir/utt_map <$srcdir/wav.scp >$destdir/wav.scp - fi -fi - -if [ -f $srcdir/reco2file_and_channel ]; then - cp $srcdir/reco2file_and_channel $destdir/ -fi - -if [ -f $srcdir/text ]; then - local/apply_map.pl -f 1 $destdir/utt_map <$srcdir/text >$destdir/text -fi -if [ -f $srcdir/utt2dur ]; then - local/apply_map.pl -f 1 $destdir/utt_map <$srcdir/utt2dur >$destdir/utt2dur -fi -if [ -f $srcdir/utt2num_frames ]; then - local/apply_map.pl -f 1 $destdir/utt_map <$srcdir/utt2num_frames >$destdir/utt2num_frames -fi -if [ -f $srcdir/reco2dur ]; then - if [ -f $srcdir/segments ]; then - cp $srcdir/reco2dur $destdir/reco2dur - else - local/apply_map.pl -f 1 $destdir/utt_map <$srcdir/reco2dur >$destdir/reco2dur - fi -fi -if [ -f $srcdir/spk2gender ]; then - local/apply_map.pl -f 1 $destdir/spk_map <$srcdir/spk2gender >$destdir/spk2gender -fi -if [ -f $srcdir/cmvn.scp ]; then - local/apply_map.pl -f 1 $destdir/spk_map <$srcdir/cmvn.scp >$destdir/cmvn.scp -fi -for f in frame_shift stm glm ctm; do - if [ -f $srcdir/$f ]; then - cp $srcdir/$f $destdir - fi -done - -rm $destdir/spk_map $destdir/utt_map - -echo "$0: copied data from $srcdir to $destdir" - -for f in feats.scp cmvn.scp vad.scp utt2lang utt2uniq utt2dur utt2num_frames text wav.scp reco2file_and_channel frame_shift stm glm ctm; do - if [ -f $destdir/$f ] && [ ! -f $srcdir/$f ]; then - echo "$0: file $f exists in dest $destdir but not in src $srcdir. Moving it to" - echo " ... $destdir/.backup/$f" - mkdir -p $destdir/.backup - mv $destdir/$f $destdir/.backup/ - fi -done - - -[ ! -f $srcdir/feats.scp ] && validate_opts="$validate_opts --no-feats" -[ ! -f $srcdir/text ] && validate_opts="$validate_opts --no-text" - -local/validate_data_dir.sh $validate_opts $destdir diff --git a/egs/alimeeting/sa_asr/local/data/get_reco2dur.sh b/egs/alimeeting/sa_asr/local/data/get_reco2dur.sh deleted file mode 100755 index 24f51e723..000000000 --- a/egs/alimeeting/sa_asr/local/data/get_reco2dur.sh +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2016 Johns Hopkins University (author: Daniel Povey) -# 2018 Andrea Carmantini -# Apache 2.0 - -# This script operates on a data directory, such as in data/train/, and adds the -# reco2dur file if it does not already exist. The file 'reco2dur' maps from -# recording to the duration of the recording in seconds. This script works it -# out from the 'wav.scp' file, or, if utterance-ids are the same as recording-ids, from the -# utt2dur file (it first tries interrogating the headers, and if this fails, it reads the wave -# files in entirely.) -# We could use durations from segments file, but that's not the duration of the recordings -# but the sum of utterance lenghts (silence in between could be excluded from segments) -# For sum of utterance lenghts: -# awk 'FNR==NR{uttdur[$1]=$2;next} -# { for(i=2;i<=NF;i++){dur+=uttdur[$i];} -# print $1 FS dur; dur=0 }' $data/utt2dur $data/reco2utt - - -frame_shift=0.01 -cmd=run.pl -nj=4 - -. utils/parse_options.sh -. ./path.sh - -if [ $# != 1 ]; then - echo "Usage: $0 [options] " - echo "e.g.:" - echo " $0 data/train" - echo " Options:" - echo " --frame-shift # frame shift in seconds. Only relevant when we are" - echo " # getting duration from feats.scp (default: 0.01). " - exit 1 -fi - -export LC_ALL=C - -data=$1 - - -if [ -s $data/reco2dur ] && \ - [ $(wc -l < $data/wav.scp) -eq $(wc -l < $data/reco2dur) ]; then - echo "$0: $data/reco2dur already exists with the expected length. We won't recompute it." - exit 0; -fi - -if [ -s $data/utt2dur ] && \ - [ $(wc -l < $data/utt2spk) -eq $(wc -l < $data/utt2dur) ] && \ - [ ! -s $data/segments ]; then - - echo "$0: $data/wav.scp indexed by utt-id; copying utt2dur to reco2dur" - cp $data/utt2dur $data/reco2dur && exit 0; - -elif [ -f $data/wav.scp ]; then - echo "$0: obtaining durations from recordings" - - # if the wav.scp contains only lines of the form - # utt1 /foo/bar/sph2pipe -f wav /baz/foo.sph | - if cat $data/wav.scp | perl -e ' - while (<>) { s/\|\s*$/ |/; # make sure final | is preceded by space. - @A = split; if (!($#A == 5 && $A[1] =~ m/sph2pipe$/ && - $A[2] eq "-f" && $A[3] eq "wav" && $A[5] eq "|")) { exit(1); } - $reco = $A[0]; $sphere_file = $A[4]; - - if (!open(F, "<$sphere_file")) { die "Error opening sphere file $sphere_file"; } - $sample_rate = -1; $sample_count = -1; - for ($n = 0; $n <= 30; $n++) { - $line = ; - if ($line =~ m/sample_rate -i (\d+)/) { $sample_rate = $1; } - if ($line =~ m/sample_count -i (\d+)/) { $sample_count = $1; } - if ($line =~ m/end_head/) { break; } - } - close(F); - if ($sample_rate == -1 || $sample_count == -1) { - die "could not parse sphere header from $sphere_file"; - } - $duration = $sample_count * 1.0 / $sample_rate; - print "$reco $duration\n"; - } ' > $data/reco2dur; then - echo "$0: successfully obtained recording lengths from sphere-file headers" - else - echo "$0: could not get recording lengths from sphere-file headers, using wav-to-duration" - if ! command -v wav-to-duration >/dev/null; then - echo "$0: wav-to-duration is not on your path" - exit 1; - fi - - read_entire_file=false - if grep -q 'sox.*speed' $data/wav.scp; then - read_entire_file=true - echo "$0: reading from the entire wav file to fix the problem caused by sox commands with speed perturbation. It is going to be slow." - echo "... It is much faster if you call get_reco2dur.sh *before* doing the speed perturbation via e.g. perturb_data_dir_speed.sh or " - echo "... perturb_data_dir_speed_3way.sh." - fi - - num_recos=$(wc -l <$data/wav.scp) - if [ $nj -gt $num_recos ]; then - nj=$num_recos - fi - - temp_data_dir=$data/wav${nj}split - wavscps=$(for n in `seq $nj`; do echo $temp_data_dir/$n/wav.scp; done) - subdirs=$(for n in `seq $nj`; do echo $temp_data_dir/$n; done) - - if ! mkdir -p $subdirs >&/dev/null; then - for n in `seq $nj`; do - mkdir -p $temp_data_dir/$n - done - fi - - utils/split_scp.pl $data/wav.scp $wavscps - - - $cmd JOB=1:$nj $data/log/get_reco_durations.JOB.log \ - wav-to-duration --read-entire-file=$read_entire_file \ - scp:$temp_data_dir/JOB/wav.scp ark,t:$temp_data_dir/JOB/reco2dur || \ - { echo "$0: there was a problem getting the durations"; exit 1; } # This could - - for n in `seq $nj`; do - cat $temp_data_dir/$n/reco2dur - done > $data/reco2dur - fi - rm -r $temp_data_dir -else - echo "$0: Expected $data/wav.scp to exist" - exit 1 -fi - -len1=$(wc -l < $data/wav.scp) -len2=$(wc -l < $data/reco2dur) -if [ "$len1" != "$len2" ]; then - echo "$0: warning: length of reco2dur does not equal that of wav.scp, $len2 != $len1" - if [ $len1 -gt $[$len2*2] ]; then - echo "$0: less than half of recordings got a duration: failing." - exit 1 - fi -fi - -echo "$0: computed $data/reco2dur" - -exit 0 diff --git a/egs/alimeeting/sa_asr/local/data/get_segments_for_data.sh b/egs/alimeeting/sa_asr/local/data/get_segments_for_data.sh deleted file mode 100755 index 93107157b..000000000 --- a/egs/alimeeting/sa_asr/local/data/get_segments_for_data.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -# This script operates on a data directory, such as in data/train/, -# and writes new segments to stdout. The file 'segments' maps from -# utterance to time offsets into a recording, with the format: -# -# This script assumes utterance and recording ids are the same (i.e., that -# wav.scp is indexed by utterance), and uses durations from 'utt2dur', -# created if necessary by get_utt2dur.sh. - -. ./path.sh - -if [ $# != 1 ]; then - echo "Usage: $0 [options] " - echo "e.g.:" - echo " $0 data/train > data/train/segments" - exit 1 -fi - -data=$1 - -if [ ! -s $data/utt2dur ]; then - local/data/get_utt2dur.sh $data 1>&2 || exit 1; -fi - -# 0 -awk '{ print $1, $1, 0, $2 }' $data/utt2dur - -exit 0 diff --git a/egs/alimeeting/sa_asr/local/data/get_utt2dur.sh b/egs/alimeeting/sa_asr/local/data/get_utt2dur.sh deleted file mode 100755 index 833a7fc59..000000000 --- a/egs/alimeeting/sa_asr/local/data/get_utt2dur.sh +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2016 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -# This script operates on a data directory, such as in data/train/, and adds the -# utt2dur file if it does not already exist. The file 'utt2dur' maps from -# utterance to the duration of the utterance in seconds. This script works it -# out from the 'segments' file, or, if not present, from the wav.scp file (it -# first tries interrogating the headers, and if this fails, it reads the wave -# files in entirely.) - -frame_shift=0.01 -cmd=run.pl -nj=4 -read_entire_file=false - -. utils/parse_options.sh -. ./path.sh - -if [ $# != 1 ]; then - echo "Usage: $0 [options] " - echo "e.g.:" - echo " $0 data/train" - echo " Options:" - echo " --frame-shift # frame shift in seconds. Only relevant when we are" - echo " # getting duration from feats.scp, and only if the " - echo " # file frame_shift does not exist (default: 0.01). " - exit 1 -fi - -export LC_ALL=C - -data=$1 - -if [ -s $data/utt2dur ] && \ - [ $(wc -l < $data/utt2spk) -eq $(wc -l < $data/utt2dur) ]; then - echo "$0: $data/utt2dur already exists with the expected length. We won't recompute it." - exit 0; -fi - -if [ -s $data/segments ]; then - echo "$0: working out $data/utt2dur from $data/segments" - awk '{len=$4-$3; print $1, len;}' < $data/segments > $data/utt2dur -elif [[ -s $data/frame_shift && -f $data/utt2num_frames ]]; then - echo "$0: computing $data/utt2dur from $data/{frame_shift,utt2num_frames}." - frame_shift=$(cat $data/frame_shift) || exit 1 - # The 1.5 correction is the typical value of (frame_length-frame_shift)/frame_shift. - awk -v fs=$frame_shift '{ $2=($2+1.5)*fs; print }' <$data/utt2num_frames >$data/utt2dur -elif [ -f $data/wav.scp ]; then - echo "$0: segments file does not exist so getting durations from wave files" - - # if the wav.scp contains only lines of the form - # utt1 /foo/bar/sph2pipe -f wav /baz/foo.sph | - if perl <$data/wav.scp -e ' - while (<>) { s/\|\s*$/ |/; # make sure final | is preceded by space. - @A = split; if (!($#A == 5 && $A[1] =~ m/sph2pipe$/ && - $A[2] eq "-f" && $A[3] eq "wav" && $A[5] eq "|")) { exit(1); } - $utt = $A[0]; $sphere_file = $A[4]; - - if (!open(F, "<$sphere_file")) { die "Error opening sphere file $sphere_file"; } - $sample_rate = -1; $sample_count = -1; - for ($n = 0; $n <= 30; $n++) { - $line = ; - if ($line =~ m/sample_rate -i (\d+)/) { $sample_rate = $1; } - if ($line =~ m/sample_count -i (\d+)/) { $sample_count = $1; } - if ($line =~ m/end_head/) { break; } - } - close(F); - if ($sample_rate == -1 || $sample_count == -1) { - die "could not parse sphere header from $sphere_file"; - } - $duration = $sample_count * 1.0 / $sample_rate; - print "$utt $duration\n"; - } ' > $data/utt2dur; then - echo "$0: successfully obtained utterance lengths from sphere-file headers" - else - echo "$0: could not get utterance lengths from sphere-file headers, using wav-to-duration" - if ! command -v wav-to-duration >/dev/null; then - echo "$0: wav-to-duration is not on your path" - exit 1; - fi - - if grep -q 'sox.*speed' $data/wav.scp; then - read_entire_file=true - echo "$0: reading from the entire wav file to fix the problem caused by sox commands with speed perturbation. It is going to be slow." - echo "... It is much faster if you call get_utt2dur.sh *before* doing the speed perturbation via e.g. perturb_data_dir_speed.sh or " - echo "... perturb_data_dir_speed_3way.sh." - fi - - - num_utts=$(wc -l <$data/utt2spk) - if [ $nj -gt $num_utts ]; then - nj=$num_utts - fi - - local/data/split_data.sh --per-utt $data $nj - sdata=$data/split${nj}utt - - $cmd JOB=1:$nj $data/log/get_durations.JOB.log \ - wav-to-duration --read-entire-file=$read_entire_file \ - scp:$sdata/JOB/wav.scp ark,t:$sdata/JOB/utt2dur || \ - { echo "$0: there was a problem getting the durations"; exit 1; } - - for n in `seq $nj`; do - cat $sdata/$n/utt2dur - done > $data/utt2dur - fi -elif [ -f $data/feats.scp ]; then - echo "$0: wave file does not exist so getting durations from feats files" - if [[ -s $data/frame_shift ]]; then - frame_shift=$(cat $data/frame_shift) || exit 1 - echo "$0: using frame_shift=$frame_shift from file $data/frame_shift" - fi - # The 1.5 correction is the typical value of (frame_length-frame_shift)/frame_shift. - feat-to-len scp:$data/feats.scp ark,t:- | - awk -v frame_shift=$frame_shift '{print $1, ($2+1.5)*frame_shift}' >$data/utt2dur -else - echo "$0: Expected $data/wav.scp, $data/segments or $data/feats.scp to exist" - exit 1 -fi - -len1=$(wc -l < $data/utt2spk) -len2=$(wc -l < $data/utt2dur) -if [ "$len1" != "$len2" ]; then - echo "$0: warning: length of utt2dur does not equal that of utt2spk, $len2 != $len1" - if [ $len1 -gt $[$len2*2] ]; then - echo "$0: less than half of utterances got a duration: failing." - exit 1 - fi -fi - -echo "$0: computed $data/utt2dur" - -exit 0 diff --git a/egs/alimeeting/sa_asr/local/data/split_data.sh b/egs/alimeeting/sa_asr/local/data/split_data.sh deleted file mode 100755 index 97ad8c53b..000000000 --- a/egs/alimeeting/sa_asr/local/data/split_data.sh +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2010-2013 Microsoft Corporation -# Johns Hopkins University (Author: Daniel Povey) - -# 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 -# -# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -# MERCHANTABLITY OR NON-INFRINGEMENT. -# See the Apache 2 License for the specific language governing permissions and -# limitations under the License. - -split_per_spk=true -if [ "$1" == "--per-utt" ]; then - split_per_spk=false - shift -fi - -if [ $# != 2 ]; then - echo "Usage: $0 [--per-utt] " - echo "E.g.: $0 data/train 50" - echo "It creates its output in e.g. data/train/split50/{1,2,3,...50}, or if the " - echo "--per-utt option was given, in e.g. data/train/split50utt/{1,2,3,...50}." - echo "" - echo "This script will not split the data-dir if it detects that the output is newer than the input." - echo "By default it splits per speaker (so each speaker is in only one split dir)," - echo "but with the --per-utt option it will ignore the speaker information while splitting." - exit 1 -fi - -data=$1 -numsplit=$2 - -if ! [ "$numsplit" -gt 0 ]; then - echo "Invalid num-split argument $numsplit"; - exit 1; -fi - -if $split_per_spk; then - warning_opt= -else - # suppress warnings from filter_scps.pl about 'some input lines were output - # to multiple files'. - warning_opt="--no-warn" -fi - -n=0; -feats="" -wavs="" -utt2spks="" -texts="" - -nu=`cat $data/utt2spk | wc -l` -nf=`cat $data/feats.scp 2>/dev/null | wc -l` -nt=`cat $data/text 2>/dev/null | wc -l` # take it as zero if no such file -if [ -f $data/feats.scp ] && [ $nu -ne $nf ]; then - echo "** split_data.sh: warning, #lines is (utt2spk,feats.scp) is ($nu,$nf); you can " - echo "** use local/fix_data_dir.sh $data to fix this." -fi -if [ -f $data/text ] && [ $nu -ne $nt ]; then - echo "** split_data.sh: warning, #lines is (utt2spk,text) is ($nu,$nt); you can " - echo "** use local/fix_data_dir.sh to fix this." -fi - - -if $split_per_spk; then - utt2spk_opt="--utt2spk=$data/utt2spk" - utt="" -else - utt2spk_opt= - utt="utt" -fi - -s1=$data/split${numsplit}${utt}/1 -if [ ! -d $s1 ]; then - need_to_split=true -else - need_to_split=false - for f in utt2spk spk2utt spk2warp feats.scp text wav.scp cmvn.scp spk2gender \ - vad.scp segments reco2file_and_channel utt2lang; do - if [[ -f $data/$f && ( ! -f $s1/$f || $s1/$f -ot $data/$f ) ]]; then - need_to_split=true - fi - done -fi - -if ! $need_to_split; then - exit 0; -fi - -utt2spks=$(for n in `seq $numsplit`; do echo $data/split${numsplit}${utt}/$n/utt2spk; done) - -directories=$(for n in `seq $numsplit`; do echo $data/split${numsplit}${utt}/$n; done) - -# if this mkdir fails due to argument-list being too long, iterate. -if ! mkdir -p $directories >&/dev/null; then - for n in `seq $numsplit`; do - mkdir -p $data/split${numsplit}${utt}/$n - done -fi - -# If lockfile is not installed, just don't lock it. It's not a big deal. -which lockfile >&/dev/null && lockfile -l 60 $data/.split_lock -trap 'rm -f $data/.split_lock' EXIT HUP INT PIPE TERM - -utils/split_scp.pl $utt2spk_opt $data/utt2spk $utt2spks || exit 1 - -for n in `seq $numsplit`; do - dsn=$data/split${numsplit}${utt}/$n - local/utt2spk_to_spk2utt.pl $dsn/utt2spk > $dsn/spk2utt || exit 1; -done - -maybe_wav_scp= -if [ ! -f $data/segments ]; then - maybe_wav_scp=wav.scp # If there is no segments file, then wav file is - # indexed per utt. -fi - -# split some things that are indexed by utterance. -for f in feats.scp text vad.scp utt2lang $maybe_wav_scp utt2dur utt2num_frames; do - if [ -f $data/$f ]; then - utils/filter_scps.pl JOB=1:$numsplit \ - $data/split${numsplit}${utt}/JOB/utt2spk $data/$f $data/split${numsplit}${utt}/JOB/$f || exit 1; - fi -done - -# split some things that are indexed by speaker -for f in spk2gender spk2warp cmvn.scp; do - if [ -f $data/$f ]; then - utils/filter_scps.pl $warning_opt JOB=1:$numsplit \ - $data/split${numsplit}${utt}/JOB/spk2utt $data/$f $data/split${numsplit}${utt}/JOB/$f || exit 1; - fi -done - -if [ -f $data/segments ]; then - utils/filter_scps.pl JOB=1:$numsplit \ - $data/split${numsplit}${utt}/JOB/utt2spk $data/segments $data/split${numsplit}${utt}/JOB/segments || exit 1 - for n in `seq $numsplit`; do - dsn=$data/split${numsplit}${utt}/$n - awk '{print $2;}' $dsn/segments | sort | uniq > $dsn/tmp.reco # recording-ids. - done - if [ -f $data/reco2file_and_channel ]; then - utils/filter_scps.pl $warning_opt JOB=1:$numsplit \ - $data/split${numsplit}${utt}/JOB/tmp.reco $data/reco2file_and_channel \ - $data/split${numsplit}${utt}/JOB/reco2file_and_channel || exit 1 - fi - if [ -f $data/wav.scp ]; then - utils/filter_scps.pl $warning_opt JOB=1:$numsplit \ - $data/split${numsplit}${utt}/JOB/tmp.reco $data/wav.scp \ - $data/split${numsplit}${utt}/JOB/wav.scp || exit 1 - fi - for f in $data/split${numsplit}${utt}/*/tmp.reco; do rm $f; done -fi - -exit 0 diff --git a/egs/alimeeting/sa_asr/local/download_and_untar.sh b/egs/alimeeting/sa_asr/local/download_and_untar.sh deleted file mode 100755 index d98255915..000000000 --- a/egs/alimeeting/sa_asr/local/download_and_untar.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# 2017 Xingyu Na -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: data_aishell, resource_aishell." -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1; -fi - -part_ok=false -list="data_aishell resource_aishell" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1; -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1; -fi - -if [ -f $data/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0; -fi - -# sizes of the archive files in bytes. -sizes="15582913665 1246920" - -if [ -f $data/$part.tgz ]; then - size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}') - size_ok=false - for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tgz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tgz - else - echo "$data/$part.tgz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tgz ]; then - if ! command -v wget >/dev/null; then - echo "$0: wget is not installed." - exit 1; - fi - full_url=$url/$part.tgz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - cd $data || exit 1 - if ! wget --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1; - fi -fi - -cd $data || exit 1 - -if ! tar -xvzf $part.tgz; then - echo "$0: error un-tarring archive $data/$part.tgz" - exit 1; -fi - -touch $data/$part/.complete - -if [ $part == "data_aishell" ]; then - cd $data/$part/wav || exit 1 - for wav in ./*.tar.gz; do - echo "Extracting wav from $wav" - tar -zxf $wav && rm $wav - done -fi - -echo "$0: Successfully downloaded and un-tarred $data/$part.tgz" - -if $remove_archive; then - echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied." - rm $data/$part.tgz -fi - -exit 0; diff --git a/egs/alimeeting/sa_asr/local/download_pretrained_model_from_modelscope.py b/egs/alimeeting/sa_asr/local/download_pretrained_model_from_modelscope.py deleted file mode 100644 index b4b54127a..000000000 --- a/egs/alimeeting/sa_asr/local/download_pretrained_model_from_modelscope.py +++ /dev/null @@ -1,7 +0,0 @@ -from modelscope.hub.snapshot_download import snapshot_download -import sys - -if __name__ == "__main__": - model_tag = sys.argv[1] - local_model_dir = sys.argv[2] - model_dir = snapshot_download(model_tag, cache_dir=local_model_dir, revision='1.0.0') \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/download_xvector_model.py b/egs/alimeeting/sa_asr/local/download_xvector_model.py deleted file mode 100644 index 7da655944..000000000 --- a/egs/alimeeting/sa_asr/local/download_xvector_model.py +++ /dev/null @@ -1,6 +0,0 @@ -from modelscope.hub.snapshot_download import snapshot_download -import sys - - -cache_dir = sys.argv[1] -model_dir = snapshot_download('damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch', cache_dir=cache_dir) diff --git a/egs/alimeeting/sa_asr/local/filter_utt2spk_all_fifo.py b/egs/alimeeting/sa_asr/local/filter_utt2spk_all_fifo.py deleted file mode 100644 index e6061625b..000000000 --- a/egs/alimeeting/sa_asr/local/filter_utt2spk_all_fifo.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -if __name__=="__main__": - uttid_path=sys.argv[1] - src_path=sys.argv[2] - tgt_path=sys.argv[3] - uttid_file=open(uttid_path,'r') - uttid_line=uttid_file.readlines() - uttid_file.close() - ori_utt2spk_all_fifo_file=open(src_path+'/utt2spk_all_fifo','r') - ori_utt2spk_all_fifo_line=ori_utt2spk_all_fifo_file.readlines() - ori_utt2spk_all_fifo_file.close() - new_utt2spk_all_fifo_file=open(tgt_path+'/utt2spk_all_fifo','w') - - uttid_list=[] - for line in uttid_line: - uttid_list.append(line.strip()) - - for line in ori_utt2spk_all_fifo_line: - if line.strip().split(' ')[0] in uttid_list: - new_utt2spk_all_fifo_file.write(line) - - new_utt2spk_all_fifo_file.close() \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/fix_data_dir.sh b/egs/alimeeting/sa_asr/local/fix_data_dir.sh deleted file mode 100755 index 3abd4652a..000000000 --- a/egs/alimeeting/sa_asr/local/fix_data_dir.sh +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env bash - -# This script makes sure that only the segments present in -# all of "feats.scp", "wav.scp" [if present], segments [if present] -# text, and utt2spk are present in any of them. -# It puts the original contents of data-dir into -# data-dir/.backup - -cmd="$@" - -utt_extra_files= -spk_extra_files= - -. utils/parse_options.sh - -if [ $# != 1 ]; then - echo "Usage: utils/data/fix_data_dir.sh " - echo "e.g.: utils/data/fix_data_dir.sh data/train" - echo "This script helps ensure that the various files in a data directory" - echo "are correctly sorted and filtered, for example removing utterances" - echo "that have no features (if feats.scp is present)" - exit 1 -fi - -data=$1 - -if [ -f $data/images.scp ]; then - image/fix_data_dir.sh $cmd - exit $? -fi - -mkdir -p $data/.backup - -[ ! -d $data ] && echo "$0: no such directory $data" && exit 1; - -[ ! -f $data/utt2spk ] && echo "$0: no such file $data/utt2spk" && exit 1; - -set -e -o pipefail -u - -tmpdir=$(mktemp -d /tmp/kaldi.XXXX); -trap 'rm -rf "$tmpdir"' EXIT HUP INT PIPE TERM - -export LC_ALL=C - -function check_sorted { - file=$1 - sort -k1,1 -u <$file >$file.tmp - if ! cmp -s $file $file.tmp; then - echo "$0: file $1 is not in sorted order or not unique, sorting it" - mv $file.tmp $file - else - rm $file.tmp - fi -} - -for x in utt2spk spk2utt feats.scp text segments wav.scp cmvn.scp vad.scp \ - reco2file_and_channel spk2gender utt2lang utt2uniq utt2dur reco2dur utt2num_frames; do - if [ -f $data/$x ]; then - cp $data/$x $data/.backup/$x - check_sorted $data/$x - fi -done - - -function filter_file { - filter=$1 - file_to_filter=$2 - cp $file_to_filter ${file_to_filter}.tmp - utils/filter_scp.pl $filter ${file_to_filter}.tmp > $file_to_filter - if ! cmp ${file_to_filter}.tmp $file_to_filter >&/dev/null; then - length1=$(cat ${file_to_filter}.tmp | wc -l) - length2=$(cat ${file_to_filter} | wc -l) - if [ $length1 -ne $length2 ]; then - echo "$0: filtered $file_to_filter from $length1 to $length2 lines based on filter $filter." - fi - fi - rm $file_to_filter.tmp -} - -function filter_recordings { - # We call this once before the stage when we filter on utterance-id, and once - # after. - - if [ -f $data/segments ]; then - # We have a segments file -> we need to filter this and the file wav.scp, and - # reco2file_and_utt, if it exists, to make sure they have the same list of - # recording-ids. - - if [ ! -f $data/wav.scp ]; then - echo "$0: $data/segments exists but not $data/wav.scp" - exit 1; - fi - awk '{print $2}' < $data/segments | sort | uniq > $tmpdir/recordings - n1=$(cat $tmpdir/recordings | wc -l) - [ ! -s $tmpdir/recordings ] && \ - echo "Empty list of recordings (bad file $data/segments)?" && exit 1; - utils/filter_scp.pl $data/wav.scp $tmpdir/recordings > $tmpdir/recordings.tmp - mv $tmpdir/recordings.tmp $tmpdir/recordings - - - cp $data/segments{,.tmp}; awk '{print $2, $1, $3, $4}' <$data/segments.tmp >$data/segments - filter_file $tmpdir/recordings $data/segments - cp $data/segments{,.tmp}; awk '{print $2, $1, $3, $4}' <$data/segments.tmp >$data/segments - rm $data/segments.tmp - - filter_file $tmpdir/recordings $data/wav.scp - [ -f $data/reco2file_and_channel ] && filter_file $tmpdir/recordings $data/reco2file_and_channel - [ -f $data/reco2dur ] && filter_file $tmpdir/recordings $data/reco2dur - true - fi -} - -function filter_speakers { - # throughout this program, we regard utt2spk as primary and spk2utt as derived, so... - local/utt2spk_to_spk2utt.pl $data/utt2spk > $data/spk2utt - - cat $data/spk2utt | awk '{print $1}' > $tmpdir/speakers - for s in cmvn.scp spk2gender; do - f=$data/$s - if [ -f $f ]; then - filter_file $f $tmpdir/speakers - fi - done - - filter_file $tmpdir/speakers $data/spk2utt - local/spk2utt_to_utt2spk.pl $data/spk2utt > $data/utt2spk - - for s in cmvn.scp spk2gender $spk_extra_files; do - f=$data/$s - if [ -f $f ]; then - filter_file $tmpdir/speakers $f - fi - done -} - -function filter_utts { - cat $data/utt2spk | awk '{print $1}' > $tmpdir/utts - - ! cat $data/utt2spk | sort | cmp - $data/utt2spk && \ - echo "utt2spk is not in sorted order (fix this yourself)" && exit 1; - - ! cat $data/utt2spk | sort -k2 | cmp - $data/utt2spk && \ - echo "utt2spk is not in sorted order when sorted first on speaker-id " && \ - echo "(fix this by making speaker-ids prefixes of utt-ids)" && exit 1; - - ! cat $data/spk2utt | sort | cmp - $data/spk2utt && \ - echo "spk2utt is not in sorted order (fix this yourself)" && exit 1; - - if [ -f $data/utt2uniq ]; then - ! cat $data/utt2uniq | sort | cmp - $data/utt2uniq && \ - echo "utt2uniq is not in sorted order (fix this yourself)" && exit 1; - fi - - maybe_wav= - maybe_reco2dur= - [ ! -f $data/segments ] && maybe_wav=wav.scp # wav indexed by utts only if segments does not exist. - [ -s $data/reco2dur ] && [ ! -f $data/segments ] && maybe_reco2dur=reco2dur # reco2dur indexed by utts - - maybe_utt2dur= - if [ -f $data/utt2dur ]; then - cat $data/utt2dur | \ - awk '{ if (NF == 2 && $2 > 0) { print }}' > $data/utt2dur.ok || exit 1 - maybe_utt2dur=utt2dur.ok - fi - - maybe_utt2num_frames= - if [ -f $data/utt2num_frames ]; then - cat $data/utt2num_frames | \ - awk '{ if (NF == 2 && $2 > 0) { print }}' > $data/utt2num_frames.ok || exit 1 - maybe_utt2num_frames=utt2num_frames.ok - fi - - for x in feats.scp text segments utt2lang $maybe_wav $maybe_utt2dur $maybe_utt2num_frames; do - if [ -f $data/$x ]; then - utils/filter_scp.pl $data/$x $tmpdir/utts > $tmpdir/utts.tmp - mv $tmpdir/utts.tmp $tmpdir/utts - fi - done - rm $data/utt2dur.ok 2>/dev/null || true - rm $data/utt2num_frames.ok 2>/dev/null || true - - [ ! -s $tmpdir/utts ] && echo "fix_data_dir.sh: no utterances remained: not proceeding further." && \ - rm $tmpdir/utts && exit 1; - - - if [ -f $data/utt2spk ]; then - new_nutts=$(cat $tmpdir/utts | wc -l) - old_nutts=$(cat $data/utt2spk | wc -l) - if [ $new_nutts -ne $old_nutts ]; then - echo "fix_data_dir.sh: kept $new_nutts utterances out of $old_nutts" - else - echo "fix_data_dir.sh: kept all $old_nutts utterances." - fi - fi - - for x in utt2spk utt2uniq feats.scp vad.scp text segments utt2lang utt2dur utt2num_frames $maybe_wav $maybe_reco2dur $utt_extra_files; do - if [ -f $data/$x ]; then - cp $data/$x $data/.backup/$x - if ! cmp -s $data/$x <( utils/filter_scp.pl $tmpdir/utts $data/$x ) ; then - utils/filter_scp.pl $tmpdir/utts $data/.backup/$x > $data/$x - fi - fi - done - -} - -filter_recordings -filter_speakers -filter_utts -filter_speakers -filter_recordings - -local/utt2spk_to_spk2utt.pl $data/utt2spk > $data/spk2utt - -echo "fix_data_dir.sh: old files are kept in $data/.backup" diff --git a/egs/alimeeting/sa_asr/local/format_wav_scp.py b/egs/alimeeting/sa_asr/local/format_wav_scp.py deleted file mode 100755 index cb0eac35a..000000000 --- a/egs/alimeeting/sa_asr/local/format_wav_scp.py +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import logging -from io import BytesIO -from pathlib import Path -from typing import Tuple, Optional - -import kaldiio -import humanfriendly -import numpy as np -import resampy -import soundfile -from tqdm import tqdm - -from funasr.utils.cli_utils import get_commandline_args -from funasr.fileio.read_text import read_2column_text -from funasr.fileio.sound_scp import SoundScpWriter - - -def humanfriendly_or_none(value: str): - if value in ("none", "None", "NONE"): - return None - return humanfriendly.parse_size(value) - - -def str2int_tuple(integers: str) -> Optional[Tuple[int, ...]]: - """ - - >>> str2int_tuple('3,4,5') - (3, 4, 5) - - """ - if integers.strip() in ("none", "None", "NONE", "null", "Null", "NULL"): - return None - return tuple(map(int, integers.strip().split(","))) - - -def main(): - logfmt = "%(asctime)s (%(module)s:%(lineno)d) %(levelname)s: %(message)s" - logging.basicConfig(level=logging.INFO, format=logfmt) - logging.info(get_commandline_args()) - - parser = argparse.ArgumentParser( - description='Create waves list from "wav.scp"', - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument("scp") - parser.add_argument("outdir") - parser.add_argument( - "--name", - default="wav", - help="Specify the prefix word of output file name " 'such as "wav.scp"', - ) - parser.add_argument("--segments", default=None) - parser.add_argument( - "--fs", - type=humanfriendly_or_none, - default=None, - help="If the sampling rate specified, " "Change the sampling rate.", - ) - parser.add_argument("--audio-format", default="wav") - group = parser.add_mutually_exclusive_group() - group.add_argument("--ref-channels", default=None, type=str2int_tuple) - group.add_argument("--utt2ref-channels", default=None, type=str) - args = parser.parse_args() - - out_num_samples = Path(args.outdir) / f"utt2num_samples" - - if args.ref_channels is not None: - - def utt2ref_channels(x) -> Tuple[int, ...]: - return args.ref_channels - - elif args.utt2ref_channels is not None: - utt2ref_channels_dict = read_2column_text(args.utt2ref_channels) - - def utt2ref_channels(x, d=utt2ref_channels_dict) -> Tuple[int, ...]: - chs_str = d[x] - return tuple(map(int, chs_str.split())) - - else: - utt2ref_channels = None - - Path(args.outdir).mkdir(parents=True, exist_ok=True) - out_wavscp = Path(args.outdir) / f"{args.name}.scp" - if args.segments is not None: - # Note: kaldiio supports only wav-pcm-int16le file. - loader = kaldiio.load_scp_sequential(args.scp, segments=args.segments) - if args.audio_format.endswith("ark"): - fark = open(Path(args.outdir) / f"data_{args.name}.ark", "wb") - fscp = out_wavscp.open("w") - else: - writer = SoundScpWriter( - args.outdir, - out_wavscp, - format=args.audio_format, - ) - - with out_num_samples.open("w") as fnum_samples: - for uttid, (rate, wave) in tqdm(loader): - # wave: (Time,) or (Time, Nmic) - if wave.ndim == 2 and utt2ref_channels is not None: - wave = wave[:, utt2ref_channels(uttid)] - - if args.fs is not None and args.fs != rate: - # FIXME(kamo): To use sox? - wave = resampy.resample( - wave.astype(np.float64), rate, args.fs, axis=0 - ) - wave = wave.astype(np.int16) - rate = args.fs - if args.audio_format.endswith("ark"): - if "flac" in args.audio_format: - suf = "flac" - elif "wav" in args.audio_format: - suf = "wav" - else: - raise RuntimeError("wav.ark or flac") - - # NOTE(kamo): Using extended ark format style here. - # This format is incompatible with Kaldi - kaldiio.save_ark( - fark, - {uttid: (wave, rate)}, - scp=fscp, - append=True, - write_function=f"soundfile_{suf}", - ) - - else: - writer[uttid] = rate, wave - fnum_samples.write(f"{uttid} {len(wave)}\n") - else: - if args.audio_format.endswith("ark"): - fark = open(Path(args.outdir) / f"data_{args.name}.ark", "wb") - else: - wavdir = Path(args.outdir) / f"data_{args.name}" - wavdir.mkdir(parents=True, exist_ok=True) - - with Path(args.scp).open("r") as fscp, out_wavscp.open( - "w" - ) as fout, out_num_samples.open("w") as fnum_samples: - for line in tqdm(fscp): - uttid, wavpath = line.strip().split(None, 1) - - if wavpath.endswith("|"): - # Streaming input e.g. cat a.wav | - with kaldiio.open_like_kaldi(wavpath, "rb") as f: - with BytesIO(f.read()) as g: - wave, rate = soundfile.read(g, dtype=np.int16) - if wave.ndim == 2 and utt2ref_channels is not None: - wave = wave[:, utt2ref_channels(uttid)] - - if args.fs is not None and args.fs != rate: - # FIXME(kamo): To use sox? - wave = resampy.resample( - wave.astype(np.float64), rate, args.fs, axis=0 - ) - wave = wave.astype(np.int16) - rate = args.fs - - if args.audio_format.endswith("ark"): - if "flac" in args.audio_format: - suf = "flac" - elif "wav" in args.audio_format: - suf = "wav" - else: - raise RuntimeError("wav.ark or flac") - - # NOTE(kamo): Using extended ark format style here. - # This format is incompatible with Kaldi - kaldiio.save_ark( - fark, - {uttid: (wave, rate)}, - scp=fout, - append=True, - write_function=f"soundfile_{suf}", - ) - else: - owavpath = str(wavdir / f"{uttid}.{args.audio_format}") - soundfile.write(owavpath, wave, rate) - fout.write(f"{uttid} {owavpath}\n") - else: - wave, rate = soundfile.read(wavpath, dtype=np.int16) - if wave.ndim == 2 and utt2ref_channels is not None: - wave = wave[:, utt2ref_channels(uttid)] - save_asis = False - - elif args.audio_format.endswith("ark"): - save_asis = False - - elif Path(wavpath).suffix == "." + args.audio_format and ( - args.fs is None or args.fs == rate - ): - save_asis = True - - else: - save_asis = False - - if save_asis: - # Neither --segments nor --fs are specified and - # the line doesn't end with "|", - # i.e. not using unix-pipe, - # only in this case, - # just using the original file as is. - fout.write(f"{uttid} {wavpath}\n") - else: - if args.fs is not None and args.fs != rate: - # FIXME(kamo): To use sox? - wave = resampy.resample( - wave.astype(np.float64), rate, args.fs, axis=0 - ) - wave = wave.astype(np.int16) - rate = args.fs - - if args.audio_format.endswith("ark"): - if "flac" in args.audio_format: - suf = "flac" - elif "wav" in args.audio_format: - suf = "wav" - else: - raise RuntimeError("wav.ark or flac") - - # NOTE(kamo): Using extended ark format style here. - # This format is not supported in Kaldi. - kaldiio.save_ark( - fark, - {uttid: (wave, rate)}, - scp=fout, - append=True, - write_function=f"soundfile_{suf}", - ) - else: - owavpath = str(wavdir / f"{uttid}.{args.audio_format}") - soundfile.write(owavpath, wave, rate) - fout.write(f"{uttid} {owavpath}\n") - fnum_samples.write(f"{uttid} {len(wave)}\n") - - -if __name__ == "__main__": - main() diff --git a/egs/alimeeting/sa_asr/local/format_wav_scp.sh b/egs/alimeeting/sa_asr/local/format_wav_scp.sh deleted file mode 100755 index 04fc4a59e..000000000 --- a/egs/alimeeting/sa_asr/local/format_wav_scp.sh +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -SECONDS=0 -log() { - local fname=${BASH_SOURCE[1]##*/} - echo -e "$(date '+%Y-%m-%dT%H:%M:%S') (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $*" -} -help_message=$(cat << EOF -Usage: $0 [ []] -e.g. -$0 data/test/wav.scp data/test_format/ - -Format 'wav.scp': In short words, -changing "kaldi-datadir" to "modified-kaldi-datadir" - -The 'wav.scp' format in kaldi is very flexible, -e.g. It can use unix-pipe as describing that wav file, -but it sometime looks confusing and make scripts more complex. -This tools creates actual wav files from 'wav.scp' -and also segments wav files using 'segments'. - -Options - --fs - --segments - --nj - --cmd -EOF -) - -out_filename=wav.scp -cmd=utils/run.pl -nj=30 -fs=none -segments= - -ref_channels= -utt2ref_channels= - -audio_format=wav -write_utt2num_samples=true - -log "$0 $*" -. utils/parse_options.sh - -if [ $# -ne 2 ] && [ $# -ne 3 ] && [ $# -ne 4 ]; then - log "${help_message}" - log "Error: invalid command line arguments" - exit 1 -fi - -. ./path.sh # Setup the environment - -scp=$1 -if [ ! -f "${scp}" ]; then - log "${help_message}" - echo "$0: Error: No such file: ${scp}" - exit 1 -fi -dir=$2 - - -if [ $# -eq 2 ]; then - logdir=${dir}/logs - outdir=${dir}/data - -elif [ $# -eq 3 ]; then - logdir=$3 - outdir=${dir}/data - -elif [ $# -eq 4 ]; then - logdir=$3 - outdir=$4 -fi - - -mkdir -p ${logdir} - -rm -f "${dir}/${out_filename}" - - -opts= -if [ -n "${utt2ref_channels}" ]; then - opts="--utt2ref-channels ${utt2ref_channels} " -elif [ -n "${ref_channels}" ]; then - opts="--ref-channels ${ref_channels} " -fi - - -if [ -n "${segments}" ]; then - log "[info]: using ${segments}" - nutt=$(<${segments} wc -l) - nj=$((nj /dev/null - -# concatenate the .scp files together. -for n in $(seq ${nj}); do - cat "${outdir}/format.${n}/wav.scp" || exit 1; -done > "${dir}/${out_filename}" || exit 1 - -if "${write_utt2num_samples}"; then - for n in $(seq ${nj}); do - cat "${outdir}/format.${n}/utt2num_samples" || exit 1; - done > "${dir}/utt2num_samples" || exit 1 -fi - -log "Successfully finished. [elapsed=${SECONDS}s]" diff --git a/egs/alimeeting/sa_asr/local/gen_cluster_profile_infer.py b/egs/alimeeting/sa_asr/local/gen_cluster_profile_infer.py deleted file mode 100644 index 859b72fce..000000000 --- a/egs/alimeeting/sa_asr/local/gen_cluster_profile_infer.py +++ /dev/null @@ -1,167 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -import numpy as np -import sys -import os -import soundfile -from itertools import permutations -from sklearn.metrics.pairwise import cosine_similarity -from sklearn import cluster - - -def custom_spectral_clustering(affinity, min_n_clusters=2, max_n_clusters=4, refine=True, - threshold=0.995, laplacian_type="graph_cut"): - if refine: - # Symmetrization - affinity = np.maximum(affinity, np.transpose(affinity)) - # Diffusion - affinity = np.matmul(affinity, np.transpose(affinity)) - # Row-wise max normalization - row_max = affinity.max(axis=1, keepdims=True) - affinity = affinity / row_max - - # a) Construct S and set diagonal elements to 0 - affinity = affinity - np.diag(np.diag(affinity)) - # b) Compute Laplacian matrix L and perform normalization: - degree = np.diag(np.sum(affinity, axis=1)) - laplacian = degree - affinity - if laplacian_type == "random_walk": - degree_norm = np.diag(1 / (np.diag(degree) + 1e-10)) - laplacian_norm = degree_norm.dot(laplacian) - else: - degree_half = np.diag(degree) ** 0.5 + 1e-15 - laplacian_norm = laplacian / degree_half[:, np.newaxis] / degree_half - - # c) Compute eigenvalues and eigenvectors of L_norm - eigenvalues, eigenvectors = np.linalg.eig(laplacian_norm) - eigenvalues = eigenvalues.real - eigenvectors = eigenvectors.real - index_array = np.argsort(eigenvalues) - eigenvalues = eigenvalues[index_array] - eigenvectors = eigenvectors[:, index_array] - - # d) Compute the number of clusters k - k = min_n_clusters - for k in range(min_n_clusters, max_n_clusters + 1): - if eigenvalues[k] > threshold: - break - k = max(k, min_n_clusters) - spectral_embeddings = eigenvectors[:, :k] - # print(mid, k, eigenvalues[:10]) - - spectral_embeddings = spectral_embeddings / np.linalg.norm(spectral_embeddings, axis=1, ord=2, keepdims=True) - solver = cluster.KMeans(n_clusters=k, max_iter=1000, random_state=42) - solver.fit(spectral_embeddings) - return solver.labels_ - - -if __name__ == "__main__": - path = sys.argv[1] # dump2/raw/Eval_Ali_far - raw_path = sys.argv[2] # data/local/Eval_Ali_far - threshold = float(sys.argv[3]) # 0.996 - sv_threshold = float(sys.argv[4]) # 0.815 - wav_scp_file = open(path+'/wav.scp', 'r') - wav_scp = wav_scp_file.readlines() - wav_scp_file.close() - raw_meeting_scp_file = open(raw_path + '/wav.scp', 'r') - raw_meeting_scp = raw_meeting_scp_file.readlines() - raw_meeting_scp_file.close() - segments_scp_file = open(raw_path + '/segments', 'r') - segments_scp = segments_scp_file.readlines() - segments_scp_file.close() - - segments_map = {} - for line in segments_scp: - line_list = line.strip().split(' ') - meeting = line_list[1] - seg = (float(line_list[-2]), float(line_list[-1])) - if meeting not in segments_map.keys(): - segments_map[meeting] = [seg] - else: - segments_map[meeting].append(seg) - - inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch' - ) - - chunk_len = int(1.5*16000) # 1.5 seconds - hop_len = int(0.75*16000) # 0.75 seconds - - os.system("mkdir -p " + path + "/cluster_profile_infer") - cluster_spk_num_file = open(path + '/cluster_spk_num', 'w') - meeting_map = {} - for line in raw_meeting_scp: - meeting = line.strip().split(' ')[0] - wav_path = line.strip().split(' ')[1] - wav = soundfile.read(wav_path)[0] - # take the first channel - if wav.ndim == 2: - wav=wav[:, 0] - # gen_seg_embedding - segments_list = segments_map[meeting] - - # import ipdb;ipdb.set_trace() - all_seg_embedding_list = [] - for seg in segments_list: - wav_seg = wav[int(seg[0] * 16000): int(seg[1] * 16000)] - wav_seg_len = wav_seg.shape[0] - i = 0 - while i < wav_seg_len: - if i + chunk_len < wav_seg_len: - cur_wav_chunk = wav_seg[i: i+chunk_len] - else: - cur_wav_chunk=wav_seg[i: ] - # chunks under 0.2s are ignored - if cur_wav_chunk.shape[0] >= 0.2 * 16000: - cur_chunk_embedding = inference_sv_pipline(audio_in=cur_wav_chunk)["spk_embedding"] - all_seg_embedding_list.append(cur_chunk_embedding) - i += hop_len - all_seg_embedding = np.vstack(all_seg_embedding_list) - # all_seg_embedding (n, dim) - - # compute affinity - affinity=cosine_similarity(all_seg_embedding) - - affinity = np.maximum(affinity - sv_threshold, 0.0001) / (affinity.max() - sv_threshold) - - # clustering - labels = custom_spectral_clustering( - affinity=affinity, - min_n_clusters=2, - max_n_clusters=4, - refine=True, - threshold=threshold, - laplacian_type="graph_cut") - - - cluster_dict={} - for j in range(labels.shape[0]): - if labels[j] not in cluster_dict.keys(): - cluster_dict[labels[j]] = np.atleast_2d(all_seg_embedding[j]) - else: - cluster_dict[labels[j]] = np.concatenate((cluster_dict[labels[j]], np.atleast_2d(all_seg_embedding[j]))) - - emb_list = [] - # get cluster center - for k in cluster_dict.keys(): - cluster_dict[k] = np.mean(cluster_dict[k], axis=0) - emb_list.append(cluster_dict[k]) - - spk_num = len(emb_list) - profile_for_infer = np.vstack(emb_list) - # save profile for each meeting - np.save(path + '/cluster_profile_infer/' + meeting + '.npy', profile_for_infer) - meeting_map[meeting] = (path + '/cluster_profile_infer/' + meeting + '.npy', spk_num) - cluster_spk_num_file.write(meeting + ' ' + str(spk_num) + '\n') - cluster_spk_num_file.flush() - - cluster_spk_num_file.close() - - profile_scp = open(path + "/cluster_profile_infer.scp", 'w') - for line in wav_scp: - uttid = line.strip().split(' ')[0] - meeting = uttid.split('-')[0] - profile_scp.write(uttid + ' ' + meeting_map[meeting][0] + '\n') - profile_scp.flush() - profile_scp.close() diff --git a/egs/alimeeting/sa_asr/local/gen_oracle_embedding.py b/egs/alimeeting/sa_asr/local/gen_oracle_embedding.py deleted file mode 100644 index 2a99b2b6b..000000000 --- a/egs/alimeeting/sa_asr/local/gen_oracle_embedding.py +++ /dev/null @@ -1,70 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -import numpy as np -import sys -import os -import soundfile - - -if __name__=="__main__": - path = sys.argv[1] # dump2/raw/Eval_Ali_far - raw_path = sys.argv[2] # data/local/Eval_Ali_far_correct_single_speaker - raw_meeting_scp_file = open(raw_path + '/wav.scp', 'r') - raw_meeting_scp = raw_meeting_scp_file.readlines() - raw_meeting_scp_file.close() - segments_scp_file = open(raw_path + '/segments', 'r') - segments_scp = segments_scp_file.readlines() - segments_scp_file.close() - - oracle_emb_dir = path + '/oracle_embedding/' - os.system("mkdir -p " + oracle_emb_dir) - oracle_emb_scp_file = open(path+'/oracle_embedding.scp', 'w') - - raw_wav_map = {} - for line in raw_meeting_scp: - meeting = line.strip().split(' ')[0] - wav_path = line.strip().split(' ')[1] - raw_wav_map[meeting] = wav_path - - spk_map = {} - for line in segments_scp: - line_list = line.strip().split(' ') - meeting = line_list[1] - spk_id = line_list[0].split('_')[3] - spk = meeting + '_' + spk_id - time_start = float(line_list[-2]) - time_end = float(line_list[-1]) - if time_end - time_start > 0.5: - if spk not in spk_map.keys(): - spk_map[spk] = [(int(time_start * 16000), int(time_end * 16000))] - else: - spk_map[spk].append((int(time_start * 16000), int(time_end * 16000))) - - inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch' - ) - - for spk in spk_map.keys(): - meeting = spk.split('_SPK')[0] - wav_path = raw_wav_map[meeting] - wav = soundfile.read(wav_path)[0] - # take the first channel - if wav.ndim == 2: - wav = wav[:, 0] - all_seg_embedding_list=[] - # import ipdb;ipdb.set_trace() - for seg_time in spk_map[spk]: - if seg_time[0] < wav.shape[0] - 0.5 * 16000: - if seg_time[1] > wav.shape[0]: - cur_seg_embedding = inference_sv_pipline(audio_in=wav[seg_time[0]: ])["spk_embedding"] - else: - cur_seg_embedding = inference_sv_pipline(audio_in=wav[seg_time[0]: seg_time[1]])["spk_embedding"] - all_seg_embedding_list.append(cur_seg_embedding) - all_seg_embedding = np.vstack(all_seg_embedding_list) - spk_embedding = np.mean(all_seg_embedding, axis=0) - np.save(oracle_emb_dir + spk + '.npy', spk_embedding) - oracle_emb_scp_file.write(spk + ' ' + oracle_emb_dir + spk + '.npy' + '\n') - oracle_emb_scp_file.flush() - - oracle_emb_scp_file.close() \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/gen_oracle_profile_nopadding.py b/egs/alimeeting/sa_asr/local/gen_oracle_profile_nopadding.py deleted file mode 100644 index f44fcd449..000000000 --- a/egs/alimeeting/sa_asr/local/gen_oracle_profile_nopadding.py +++ /dev/null @@ -1,59 +0,0 @@ -import random -import numpy as np -import os -import sys - - -if __name__=="__main__": - path = sys.argv[1] # dump2/raw/Eval_Ali_far - wav_scp_file = open(path+"/wav.scp", 'r') - wav_scp = wav_scp_file.readlines() - wav_scp_file.close() - spk2id_file = open(path + "/spk2id", 'r') - spk2id = spk2id_file.readlines() - spk2id_file.close() - embedding_scp_file = open(path + "/oracle_embedding.scp", 'r') - embedding_scp = embedding_scp_file.readlines() - embedding_scp_file.close() - - embedding_map = {} - for line in embedding_scp: - spk = line.strip().split(' ')[0] - if spk not in embedding_map.keys(): - emb=np.load(line.strip().split(' ')[1]) - embedding_map[spk] = emb - - meeting_map_tmp = {} - global_spk_list = [] - for line in spk2id: - line_list = line.strip().split(' ') - meeting = line_list[0].split('-')[0] - spk_id = line_list[0].split('-')[-1].split('_')[-1] - spk = meeting + '_' + spk_id - global_spk_list.append(spk) - if meeting in meeting_map_tmp.keys(): - meeting_map_tmp[meeting].append(spk) - else: - meeting_map_tmp[meeting] = [spk] - - meeting_map = {} - os.system('mkdir -p ' + path + '/oracle_profile_nopadding') - for meeting in meeting_map_tmp.keys(): - emb_list = [] - for i in range(len(meeting_map_tmp[meeting])): - spk = meeting_map_tmp[meeting][i] - emb_list.append(embedding_map[spk]) - profile = np.vstack(emb_list) - np.save(path + '/oracle_profile_nopadding/' + meeting + '.npy', profile) - meeting_map[meeting] = path + '/oracle_profile_nopadding/' + meeting + '.npy' - - profile_scp = open(path + '/oracle_profile_nopadding.scp', 'w') - profile_map_scp = open(path + '/oracle_profile_nopadding_spk_list', 'w') - - for line in wav_scp: - uttid = line.strip().split(' ')[0] - meeting = uttid.split('-')[0] - profile_scp.write(uttid + ' ' + meeting_map[meeting] + '\n') - profile_map_scp.write(uttid + ' ' + '$'.join(meeting_map_tmp[meeting]) + '\n') - profile_scp.close() - profile_map_scp.close() \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/gen_oracle_profile_padding.py b/egs/alimeeting/sa_asr/local/gen_oracle_profile_padding.py deleted file mode 100644 index ff65a1f90..000000000 --- a/egs/alimeeting/sa_asr/local/gen_oracle_profile_padding.py +++ /dev/null @@ -1,68 +0,0 @@ -import random -import numpy as np -import os -import sys - - -if __name__=="__main__": - path = sys.argv[1] - wav_scp_file = open(path+"/wav.scp", 'r') - wav_scp = wav_scp_file.readlines() - wav_scp_file.close() - spk2id_file = open(path+"/spk2id", 'r') - spk2id = spk2id_file.readlines() - spk2id_file.close() - embedding_scp_file = open(path + "/oracle_embedding.scp", 'r') - embedding_scp = embedding_scp_file.readlines() - embedding_scp_file.close() - - embedding_map = {} - for line in embedding_scp: - spk = line.strip().split(' ')[0] - if spk not in embedding_map.keys(): - emb = np.load(line.strip().split(' ')[1]) - embedding_map[spk] = emb - - meeting_map_tmp = {} - global_spk_list = [] - for line in spk2id: - line_list = line.strip().split(' ') - meeting = line_list[0].split('-')[0] - spk_id = line_list[0].split('-')[-1].split('_')[-1] - spk = meeting + '_' + spk_id - global_spk_list.append(spk) - if meeting in meeting_map_tmp.keys(): - meeting_map_tmp[meeting].append(spk) - else: - meeting_map_tmp[meeting] = [spk] - - for meeting in meeting_map_tmp.keys(): - num = len(meeting_map_tmp[meeting]) - if num < 4: - global_spk_list_tmp = global_spk_list[: ] - for spk in meeting_map_tmp[meeting]: - global_spk_list_tmp.remove(spk) - padding_spk = random.sample(global_spk_list_tmp, 4 - num) - meeting_map_tmp[meeting] = meeting_map_tmp[meeting] + padding_spk - - meeting_map = {} - os.system('mkdir -p ' + path + '/oracle_profile_padding') - for meeting in meeting_map_tmp.keys(): - emb_list = [] - for i in range(len(meeting_map_tmp[meeting])): - spk = meeting_map_tmp[meeting][i] - emb_list.append(embedding_map[spk]) - profile = np.vstack(emb_list) - np.save(path + '/oracle_profile_padding/' + meeting + '.npy',profile) - meeting_map[meeting] = path + '/oracle_profile_padding/' + meeting + '.npy' - - profile_scp = open(path + '/oracle_profile_padding.scp', 'w') - profile_map_scp = open(path + '/oracle_profile_padding_spk_list', 'w') - - for line in wav_scp: - uttid = line.strip().split(' ')[0] - meeting = uttid.split('-')[0] - profile_scp.write(uttid+' ' + meeting_map[meeting] + '\n') - profile_map_scp.write(uttid+' ' + '$'.join(meeting_map_tmp[meeting]) + '\n') - profile_scp.close() - profile_map_scp.close() \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/perturb_data_dir_speed.sh b/egs/alimeeting/sa_asr/local/perturb_data_dir_speed.sh deleted file mode 100755 index 1022ae62b..000000000 --- a/egs/alimeeting/sa_asr/local/perturb_data_dir_speed.sh +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env bash - -# 2020 @kamo-naoyuki -# This file was copied from Kaldi and -# I deleted parts related to wav duration -# because we shouldn't use kaldi's command here -# and we don't need the files actually. - -# Copyright 2013 Johns Hopkins University (author: Daniel Povey) -# 2014 Tom Ko -# 2018 Emotech LTD (author: Pawel Swietojanski) -# Apache 2.0 - -# This script operates on a directory, such as in data/train/, -# that contains some subset of the following files: -# wav.scp -# spk2utt -# utt2spk -# text -# -# It generates the files which are used for perturbing the speed of the original data. - -export LC_ALL=C -set -euo pipefail - -if [[ $# != 3 ]]; then - echo "Usage: perturb_data_dir_speed.sh " - echo "e.g.:" - echo " $0 0.9 data/train_si284 data/train_si284p" - exit 1 -fi - -factor=$1 -srcdir=$2 -destdir=$3 -label="sp" -spk_prefix="${label}${factor}-" -utt_prefix="${label}${factor}-" - -#check is sox on the path - -! command -v sox &>/dev/null && echo "sox: command not found" && exit 1; - -if [[ ! -f ${srcdir}/utt2spk ]]; then - echo "$0: no such file ${srcdir}/utt2spk" - exit 1; -fi - -if [[ ${destdir} == "${srcdir}" ]]; then - echo "$0: this script requires and to be different." - exit 1 -fi - -mkdir -p "${destdir}" - -<"${srcdir}"/utt2spk awk -v p="${utt_prefix}" '{printf("%s %s%s\n", $1, p, $1);}' > "${destdir}/utt_map" -<"${srcdir}"/spk2utt awk -v p="${spk_prefix}" '{printf("%s %s%s\n", $1, p, $1);}' > "${destdir}/spk_map" -<"${srcdir}"/wav.scp awk -v p="${spk_prefix}" '{printf("%s %s%s\n", $1, p, $1);}' > "${destdir}/reco_map" -if [[ ! -f ${srcdir}/utt2uniq ]]; then - <"${srcdir}/utt2spk" awk -v p="${utt_prefix}" '{printf("%s%s %s\n", p, $1, $1);}' > "${destdir}/utt2uniq" -else - <"${srcdir}/utt2uniq" awk -v p="${utt_prefix}" '{printf("%s%s %s\n", p, $1, $2);}' > "${destdir}/utt2uniq" -fi - - -<"${srcdir}"/utt2spk local/apply_map.pl -f 1 "${destdir}"/utt_map | \ - local/apply_map.pl -f 2 "${destdir}"/spk_map >"${destdir}"/utt2spk - -local/utt2spk_to_spk2utt.pl <"${destdir}"/utt2spk >"${destdir}"/spk2utt - -if [[ -f ${srcdir}/segments ]]; then - - local/apply_map.pl -f 1 "${destdir}"/utt_map <"${srcdir}"/segments | \ - local/apply_map.pl -f 2 "${destdir}"/reco_map | \ - awk -v factor="${factor}" \ - '{s=$3/factor; e=$4/factor; if (e > s + 0.01) { printf("%s %s %.2f %.2f\n", $1, $2, $3/factor, $4/factor);} }' \ - >"${destdir}"/segments - - local/apply_map.pl -f 1 "${destdir}"/reco_map <"${srcdir}"/wav.scp | sed 's/| *$/ |/' | \ - # Handle three cases of rxfilenames appropriately; "input piped command", "file offset" and "filename" - awk -v factor="${factor}" \ - '{wid=$1; $1=""; if ($NF=="|") {print wid $_ " sox -t wav - -t wav - speed " factor " |"} - else if (match($0, /:[0-9]+$/)) {print wid " wav-copy" $_ " - | sox -t wav - -t wav - speed " factor " |" } - else {print wid " sox" $_ " -t wav - speed " factor " |"}}' \ - > "${destdir}"/wav.scp - if [[ -f ${srcdir}/reco2file_and_channel ]]; then - local/apply_map.pl -f 1 "${destdir}"/reco_map \ - <"${srcdir}"/reco2file_and_channel >"${destdir}"/reco2file_and_channel - fi - -else # no segments->wav indexed by utterance. - if [[ -f ${srcdir}/wav.scp ]]; then - local/apply_map.pl -f 1 "${destdir}"/utt_map <"${srcdir}"/wav.scp | sed 's/| *$/ |/' | \ - # Handle three cases of rxfilenames appropriately; "input piped command", "file offset" and "filename" - awk -v factor="${factor}" \ - '{wid=$1; $1=""; if ($NF=="|") {print wid $_ " sox -t wav - -t wav - speed " factor " |"} - else if (match($0, /:[0-9]+$/)) {print wid " wav-copy" $_ " - | sox -t wav - -t wav - speed " factor " |" } - else {print wid " sox" $_ " -t wav - speed " factor " |"}}' \ - > "${destdir}"/wav.scp - fi -fi - -if [[ -f ${srcdir}/text ]]; then - local/apply_map.pl -f 1 "${destdir}"/utt_map <"${srcdir}"/text >"${destdir}"/text -fi -if [[ -f ${srcdir}/spk2gender ]]; then - local/apply_map.pl -f 1 "${destdir}"/spk_map <"${srcdir}"/spk2gender >"${destdir}"/spk2gender -fi -if [[ -f ${srcdir}/utt2lang ]]; then - local/apply_map.pl -f 1 "${destdir}"/utt_map <"${srcdir}"/utt2lang >"${destdir}"/utt2lang -fi - -rm "${destdir}"/spk_map "${destdir}"/utt_map "${destdir}"/reco_map 2>/dev/null -echo "$0: generated speed-perturbed version of data in ${srcdir}, in ${destdir}" - -local/validate_data_dir.sh --no-feats --no-text "${destdir}" diff --git a/egs/alimeeting/sa_asr/local/process_sot_fifo_textchar2spk.py b/egs/alimeeting/sa_asr/local/process_sot_fifo_textchar2spk.py deleted file mode 100755 index c26ba32fe..000000000 --- a/egs/alimeeting/sa_asr/local/process_sot_fifo_textchar2spk.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Process the textgrid files -""" -import argparse -import codecs -from distutils.util import strtobool -from pathlib import Path -try: - import textgrid -except: - raise "Please install textgrid firstly: pip install textgrid" -import pdb - -def get_args(): - parser = argparse.ArgumentParser(description="process the textgrid files") - parser.add_argument("--path", type=str, required=True, help="Data path") - args = parser.parse_args() - return args - -class Segment(object): - def __init__(self, uttid, text): - self.uttid = uttid - self.text = text - -def main(args): - text = codecs.open(Path(args.path) / "text", "r", "utf-8") - spk2utt = codecs.open(Path(args.path) / "spk2utt", "r", "utf-8") - utt2spk = codecs.open(Path(args.path) / "utt2spk_all_fifo", "r", "utf-8") - spk2id = codecs.open(Path(args.path) / "spk2id", "w", "utf-8") - - spkid_map = {} - meetingid_map = {} - for line in spk2utt: - spkid = line.strip().split(" ")[0] - meeting_id = spkid.split("-")[0] - if meeting_id not in meetingid_map: - meetingid_map[meeting_id] = 1 - else: - meetingid_map[meeting_id] += 1 - spkid_map[spkid] = meetingid_map[meeting_id] - spk2id.write("%s %s\n" % (spkid, meetingid_map[meeting_id])) - - utt2spklist = {} - for line in utt2spk: - uttid = line.strip().split(" ")[0] - spkid = line.strip().split(" ")[1] - spklist = spkid.split("$") - tmp = [] - for index in range(len(spklist)): - tmp.append(spkid_map[spklist[index]]) - utt2spklist[uttid] = tmp - # parse the textgrid file for each utterance - all_segments = [] - for line in text: - uttid = line.strip().split(" ")[0] - context = line.strip().split(" ")[1] - spklist = utt2spklist[uttid] - length_text = len(context) - cnt = 0 - tmp_text = "" - for index in range(length_text): - if context[index] != "$": - tmp_text += str(spklist[cnt]) - else: - tmp_text += "$" - cnt += 1 - tmp_seg = Segment(uttid,tmp_text) - all_segments.append(tmp_seg) - - text.close() - utt2spk.close() - spk2utt.close() - spk2id.close() - - text_id = codecs.open(Path(args.path) / "text_id", "w", "utf-8") - - for i in range(len(all_segments)): - uttid_tmp = all_segments[i].uttid - text_tmp = all_segments[i].text - - text_id.write("%s %s\n" % (uttid_tmp, text_tmp)) - - text_id.close() - -if __name__ == "__main__": - args = get_args() - main(args) diff --git a/egs/alimeeting/sa_asr/local/process_text_id.py b/egs/alimeeting/sa_asr/local/process_text_id.py deleted file mode 100644 index 0a9506e29..000000000 --- a/egs/alimeeting/sa_asr/local/process_text_id.py +++ /dev/null @@ -1,24 +0,0 @@ -import sys -if __name__=="__main__": - path=sys.argv[1] - - text_id_old_file=open(path+"/text_id",'r') - text_id_old=text_id_old_file.readlines() - text_id_old_file.close() - - text_id=open(path+"/text_id_train",'w') - for line in text_id_old: - uttid=line.strip().split(' ')[0] - old_id=line.strip().split(' ')[1] - pre_id='0' - new_id_list=[] - for i in old_id: - if i == '$': - new_id_list.append(pre_id) - else: - new_id_list.append(str(int(i)-1)) - pre_id=str(int(i)-1) - new_id_list.append(pre_id) - new_id=' '.join(new_id_list) - text_id.write(uttid+' '+new_id+'\n') - text_id.close() \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/process_text_spk_merge.py b/egs/alimeeting/sa_asr/local/process_text_spk_merge.py deleted file mode 100644 index f15d509b5..000000000 --- a/egs/alimeeting/sa_asr/local/process_text_spk_merge.py +++ /dev/null @@ -1,55 +0,0 @@ -import sys - - -if __name__ == "__main__": - path=sys.argv[1] - text_scp_file = open(path + '/text', 'r') - text_scp = text_scp_file.readlines() - text_scp_file.close() - text_id_scp_file = open(path + '/text_id', 'r') - text_id_scp = text_id_scp_file.readlines() - text_id_scp_file.close() - text_spk_merge_file = open(path + '/text_spk_merge', 'w') - assert len(text_scp) == len(text_id_scp) - - meeting_map = {} # {meeting_id: [(start_time, text, text_id), (start_time, text, text_id), ...]} - for i in range(len(text_scp)): - text_line = text_scp[i].strip().split(' ') - text_id_line = text_id_scp[i].strip().split(' ') - assert text_line[0] == text_id_line[0] - if len(text_line) > 1: - uttid = text_line[0] - text = text_line[1] - text_id = text_id_line[1] - meeting_id = uttid.split('-')[0] - start_time = int(uttid.split('-')[-2]) - if meeting_id not in meeting_map: - meeting_map[meeting_id] = [(start_time,text,text_id)] - else: - meeting_map[meeting_id].append((start_time,text,text_id)) - - for meeting_id in sorted(meeting_map.keys()): - cur_meeting_list = sorted(meeting_map[meeting_id], key=lambda x: x[0]) - text_spk_merge_map = {} #{1: text1, 2: text2, ...} - for cur_utt in cur_meeting_list: - cur_text = cur_utt[1] - cur_text_id = cur_utt[2] - assert len(cur_text)==len(cur_text_id) - if len(cur_text) != 0: - cur_text_split = cur_text.split('$') - cur_text_id_split = cur_text_id.split('$') - assert len(cur_text_split) == len(cur_text_id_split) - for i in range(len(cur_text_split)): - if len(cur_text_split[i]) != 0: - spk_id = int(cur_text_id_split[i][0]) - if spk_id not in text_spk_merge_map.keys(): - text_spk_merge_map[spk_id] = cur_text_split[i] - else: - text_spk_merge_map[spk_id] += cur_text_split[i] - text_spk_merge_list = [] - for spk_id in sorted(text_spk_merge_map.keys()): - text_spk_merge_list.append(text_spk_merge_map[spk_id]) - text_spk_merge_file.write(meeting_id + ' ' + '$'.join(text_spk_merge_list) + '\n') - text_spk_merge_file.flush() - - text_spk_merge_file.close() \ No newline at end of file diff --git a/egs/alimeeting/sa_asr/local/process_textgrid_to_single_speaker_wav.py b/egs/alimeeting/sa_asr/local/process_textgrid_to_single_speaker_wav.py deleted file mode 100755 index b72ddc9ef..000000000 --- a/egs/alimeeting/sa_asr/local/process_textgrid_to_single_speaker_wav.py +++ /dev/null @@ -1,132 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Process the textgrid files -""" -import argparse -import codecs -from distutils.util import strtobool -from pathlib import Path - -try: - import textgrid -except: - raise "Please install textgrid firstly: pip install textgrid" - -import pdb -import numpy as np -import sys -import math - - -class Segment(object): - def __init__(self, uttid, spkr, stime, etime, text): - self.uttid = uttid - self.spkr = spkr - self.stime = round(stime, 2) - self.etime = round(etime, 2) - self.text = text - - def change_stime(self, time): - self.stime = time - - def change_etime(self, time): - self.etime = time - - -def get_args(): - parser = argparse.ArgumentParser(description="process the textgrid files") - parser.add_argument("--path", type=str, required=True, help="Data path") - args = parser.parse_args() - return args - - - -def main(args): - textgrid_flist = codecs.open(Path(args.path) / "textgrid.flist", "r", "utf-8") - segment_file = codecs.open(Path(args.path)/"segments", "w", "utf-8") - utt2spk = codecs.open(Path(args.path)/"utt2spk", "w", "utf-8") - - # get the path of textgrid file for each utterance - for line in textgrid_flist: - line_array = line.strip().split(" ") - path = Path(line_array[1]) - uttid = line_array[0] - - try: - tg = textgrid.TextGrid.fromFile(path) - except: - pdb.set_trace() - num_spk = tg.__len__() - spk2textgrid = {} - spk2weight = {} - weight2spk = {} - cnt = 2 - xmax = 0 - for i in range(tg.__len__()): - spk_name = tg[i].name - if spk_name not in spk2weight: - spk2weight[spk_name] = cnt - weight2spk[cnt] = spk_name - cnt = cnt * 2 - segments = [] - for j in range(tg[i].__len__()): - if tg[i][j].mark: - if xmax < tg[i][j].maxTime: - xmax = tg[i][j].maxTime - segments.append( - Segment( - uttid, - tg[i].name, - tg[i][j].minTime, - tg[i][j].maxTime, - tg[i][j].mark.strip(), - ) - ) - segments = sorted(segments, key=lambda x: x.stime) - spk2textgrid[spk_name] = segments - olp_label = np.zeros((num_spk, int(xmax/0.01)), dtype=np.int32) - for spkid in spk2weight.keys(): - weight = spk2weight[spkid] - segments = spk2textgrid[spkid] - idx = int(math.log2(weight) )- 1 - for i in range(len(segments)): - stime = segments[i].stime - etime = segments[i].etime - olp_label[idx, int(stime/0.01): int(etime/0.01)] = weight - sum_label = olp_label.sum(axis=0) - stime = 0 - pre_value = 0 - for pos in range(sum_label.shape[0]): - if sum_label[pos] in weight2spk: - if pre_value in weight2spk: - if sum_label[pos] != pre_value: - spkids = weight2spk[pre_value] - spkid_array = spkids.split("_") - spkid = spkid_array[-1] - #spkid = uttid+spkid - if round(stime*0.01, 2) != round((pos-1)*0.01, 2): - segment_file.write("%s_%s_%s_%s %s %s %s\n" % (uttid, spkid, str(int(stime)).zfill(7), str(int(pos-1)).zfill(7), uttid, round(stime*0.01, 2) ,round((pos-1)*0.01, 2))) - utt2spk.write("%s_%s_%s_%s %s\n" % (uttid, spkid, str(int(stime)).zfill(7), str(int(pos-1)).zfill(7), uttid+"_"+spkid)) - stime = pos - pre_value = sum_label[pos] - else: - stime = pos - pre_value = sum_label[pos] - else: - if pre_value in weight2spk: - spkids = weight2spk[pre_value] - spkid_array = spkids.split("_") - spkid = spkid_array[-1] - #spkid = uttid+spkid - if round(stime*0.01, 2) != round((pos-1)*0.01, 2): - segment_file.write("%s_%s_%s_%s %s %s %s\n" % (uttid, spkid, str(int(stime)).zfill(7), str(int(pos-1)).zfill(7), uttid, round(stime*0.01, 2) ,round((pos-1)*0.01, 2))) - utt2spk.write("%s_%s_%s_%s %s\n" % (uttid, spkid, str(int(stime)).zfill(7), str(int(pos-1)).zfill(7), uttid+"_"+spkid)) - stime = pos - pre_value = sum_label[pos] - textgrid_flist.close() - segment_file.close() - - -if __name__ == "__main__": - args = get_args() - main(args) diff --git a/egs/alimeeting/sa_asr/local/spk2utt_to_utt2spk.pl b/egs/alimeeting/sa_asr/local/spk2utt_to_utt2spk.pl deleted file mode 100755 index 23992f25d..000000000 --- a/egs/alimeeting/sa_asr/local/spk2utt_to_utt2spk.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env perl -# Copyright 2010-2011 Microsoft Corporation - -# 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 -# -# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -# MERCHANTABLITY OR NON-INFRINGEMENT. -# See the Apache 2 License for the specific language governing permissions and -# limitations under the License. - - -while(<>){ - @A = split(" ", $_); - @A > 1 || die "Invalid line in spk2utt file: $_"; - $s = shift @A; - foreach $u ( @A ) { - print "$u $s\n"; - } -} - - diff --git a/egs/alimeeting/sa_asr/local/text_format.pl b/egs/alimeeting/sa_asr/local/text_format.pl deleted file mode 100755 index 45f1f6428..000000000 --- a/egs/alimeeting/sa_asr/local/text_format.pl +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env perl -use warnings; #sed replacement for -w perl parameter -# Copyright Chao Weng - -# normalizations for hkust trascript -# see the docs/trans-guidelines.pdf for details - -while () { - @A = split(" ", $_); - if (@A == 1) { - next; - } - print $_ -} diff --git a/egs/alimeeting/sa_asr/local/text_normalize.pl b/egs/alimeeting/sa_asr/local/text_normalize.pl deleted file mode 100755 index ac301d466..000000000 --- a/egs/alimeeting/sa_asr/local/text_normalize.pl +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env perl -use warnings; #sed replacement for -w perl parameter -# Copyright Chao Weng - -# normalizations for hkust trascript -# see the docs/trans-guidelines.pdf for details - -while () { - @A = split(" ", $_); - print "$A[0] "; - for ($n = 1; $n < @A; $n++) { - $tmp = $A[$n]; - if ($tmp =~ //) {$tmp =~ s:::g;} - if ($tmp =~ /<%>/) {$tmp =~ s:<%>::g;} - if ($tmp =~ /<->/) {$tmp =~ s:<->::g;} - if ($tmp =~ /<\$>/) {$tmp =~ s:<\$>::g;} - if ($tmp =~ /<#>/) {$tmp =~ s:<#>::g;} - if ($tmp =~ /<_>/) {$tmp =~ s:<_>::g;} - if ($tmp =~ //) {$tmp =~ s:::g;} - if ($tmp =~ /`/) {$tmp =~ s:`::g;} - if ($tmp =~ /&/) {$tmp =~ s:&::g;} - if ($tmp =~ /,/) {$tmp =~ s:,::g;} - if ($tmp =~ /[a-zA-Z]/) {$tmp=uc($tmp);} - if ($tmp =~ /A/) {$tmp =~ s:A:A:g;} - if ($tmp =~ /a/) {$tmp =~ s:a:A:g;} - if ($tmp =~ /b/) {$tmp =~ s:b:B:g;} - if ($tmp =~ /c/) {$tmp =~ s:c:C:g;} - if ($tmp =~ /k/) {$tmp =~ s:k:K:g;} - if ($tmp =~ /t/) {$tmp =~ s:t:T:g;} - if ($tmp =~ /,/) {$tmp =~ s:,::g;} - if ($tmp =~ /丶/) {$tmp =~ s:丶::g;} - if ($tmp =~ /。/) {$tmp =~ s:。::g;} - if ($tmp =~ /、/) {$tmp =~ s:、::g;} - if ($tmp =~ /?/) {$tmp =~ s:?::g;} - print "$tmp "; - } - print "\n"; -} diff --git a/egs/alimeeting/sa_asr/local/utt2spk_to_spk2utt.pl b/egs/alimeeting/sa_asr/local/utt2spk_to_spk2utt.pl deleted file mode 100755 index 6e0e438ca..000000000 --- a/egs/alimeeting/sa_asr/local/utt2spk_to_spk2utt.pl +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env perl -# Copyright 2010-2011 Microsoft Corporation - -# 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 -# -# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -# MERCHANTABLITY OR NON-INFRINGEMENT. -# See the Apache 2 License for the specific language governing permissions and -# limitations under the License. - -# converts an utt2spk file to a spk2utt file. -# Takes input from the stdin or from a file argument; -# output goes to the standard out. - -if ( @ARGV > 1 ) { - die "Usage: utt2spk_to_spk2utt.pl [ utt2spk ] > spk2utt"; -} - -while(<>){ - @A = split(" ", $_); - @A == 2 || die "Invalid line in utt2spk file: $_"; - ($u,$s) = @A; - if(!$seen_spk{$s}) { - $seen_spk{$s} = 1; - push @spklist, $s; - } - push (@{$spk_hash{$s}}, "$u"); -} -foreach $s (@spklist) { - $l = join(' ',@{$spk_hash{$s}}); - print "$s $l\n"; -} diff --git a/egs/alimeeting/sa_asr/local/validate_data_dir.sh b/egs/alimeeting/sa_asr/local/validate_data_dir.sh deleted file mode 100755 index 37c99aec0..000000000 --- a/egs/alimeeting/sa_asr/local/validate_data_dir.sh +++ /dev/null @@ -1,404 +0,0 @@ -#!/usr/bin/env bash - -cmd="$@" - -no_feats=false -no_wav=false -no_text=false -no_spk_sort=false -non_print=false - - -function show_help -{ - echo "Usage: $0 [--no-feats] [--no-text] [--non-print] [--no-wav] [--no-spk-sort] " - echo "The --no-xxx options mean that the script does not require " - echo "xxx.scp to be present, but it will check it if it is present." - echo "--no-spk-sort means that the script does not require the utt2spk to be " - echo "sorted by the speaker-id in addition to being sorted by utterance-id." - echo "--non-print ignore the presence of non-printable characters." - echo "By default, utt2spk is expected to be sorted by both, which can be " - echo "achieved by making the speaker-id prefixes of the utterance-ids" - echo "e.g.: $0 data/train" -} - -while [ $# -ne 0 ] ; do - case "$1" in - "--no-feats") - no_feats=true; - ;; - "--no-text") - no_text=true; - ;; - "--non-print") - non_print=true; - ;; - "--no-wav") - no_wav=true; - ;; - "--no-spk-sort") - no_spk_sort=true; - ;; - *) - if ! [ -z "$data" ] ; then - show_help; - exit 1 - fi - data=$1 - ;; - esac - shift -done - - - -if [ ! -d $data ]; then - echo "$0: no such directory $data" - exit 1; -fi - -if [ -f $data/images.scp ]; then - cmd=${cmd/--no-wav/} # remove --no-wav if supplied - image/validate_data_dir.sh $cmd - exit $? -fi - -for f in spk2utt utt2spk; do - if [ ! -f $data/$f ]; then - echo "$0: no such file $f" - exit 1; - fi - if [ ! -s $data/$f ]; then - echo "$0: empty file $f" - exit 1; - fi -done - -! cat $data/utt2spk | awk '{if (NF != 2) exit(1); }' && \ - echo "$0: $data/utt2spk has wrong format." && exit; - -ns=$(wc -l < $data/spk2utt) -if [ "$ns" == 1 ]; then - echo "$0: WARNING: you have only one speaker. This probably a bad idea." - echo " Search for the word 'bold' in http://kaldi-asr.org/doc/data_prep.html" - echo " for more information." -fi - - -tmpdir=$(mktemp -d /tmp/kaldi.XXXX); -trap 'rm -rf "$tmpdir"' EXIT HUP INT PIPE TERM - -export LC_ALL=C - -function check_sorted_and_uniq { - ! perl -ne '((substr $_,-1) eq "\n") or die "file $ARGV has invalid newline";' $1 && exit 1; - ! awk '{print $1}' < $1 | sort -uC && echo "$0: file $1 is not sorted or has duplicates" && exit 1; -} - -function partial_diff { - diff -U1 $1 $2 | (head -n 6; echo "..."; tail -n 6) - n1=`cat $1 | wc -l` - n2=`cat $2 | wc -l` - echo "[Lengths are $1=$n1 versus $2=$n2]" -} - -check_sorted_and_uniq $data/utt2spk - -if ! $no_spk_sort; then - ! sort -k2 -C $data/utt2spk && \ - echo "$0: utt2spk is not in sorted order when sorted first on speaker-id " && \ - echo "(fix this by making speaker-ids prefixes of utt-ids)" && exit 1; -fi - -check_sorted_and_uniq $data/spk2utt - -! cmp -s <(cat $data/utt2spk | awk '{print $1, $2;}') \ - <(local/spk2utt_to_utt2spk.pl $data/spk2utt) && \ - echo "$0: spk2utt and utt2spk do not seem to match" && exit 1; - -cat $data/utt2spk | awk '{print $1;}' > $tmpdir/utts - -if [ ! -f $data/text ] && ! $no_text; then - echo "$0: no such file $data/text (if this is by design, specify --no-text)" - exit 1; -fi - -num_utts=`cat $tmpdir/utts | wc -l` -if ! $no_text; then - if ! $non_print; then - if locale -a | grep "C.UTF-8" >/dev/null; then - L=C.UTF-8 - else - L=en_US.UTF-8 - fi - n_non_print=$(LC_ALL="$L" grep -c '[^[:print:][:space:]]' $data/text) && \ - echo "$0: text contains $n_non_print lines with non-printable characters" &&\ - exit 1; - fi - local/validate_text.pl $data/text || exit 1; - check_sorted_and_uniq $data/text - text_len=`cat $data/text | wc -l` - illegal_sym_list=" #0" - for x in $illegal_sym_list; do - if grep -w "$x" $data/text > /dev/null; then - echo "$0: Error: in $data, text contains illegal symbol $x" - exit 1; - fi - done - awk '{print $1}' < $data/text > $tmpdir/utts.txt - if ! cmp -s $tmpdir/utts{,.txt}; then - echo "$0: Error: in $data, utterance lists extracted from utt2spk and text" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/utts{,.txt} - exit 1; - fi -fi - -if [ -f $data/segments ] && [ ! -f $data/wav.scp ]; then - echo "$0: in directory $data, segments file exists but no wav.scp" - exit 1; -fi - - -if [ ! -f $data/wav.scp ] && ! $no_wav; then - echo "$0: no such file $data/wav.scp (if this is by design, specify --no-wav)" - exit 1; -fi - -if [ -f $data/wav.scp ]; then - check_sorted_and_uniq $data/wav.scp - - if grep -E -q '^\S+\s+~' $data/wav.scp; then - # note: it's not a good idea to have any kind of tilde in wav.scp, even if - # part of a command, as it would cause compatibility problems if run by - # other users, but this used to be not checked for so we let it slide unless - # it's something of the form "foo ~/foo.wav" (i.e. a plain file name) which - # would definitely cause problems as the fopen system call does not do - # tilde expansion. - echo "$0: Please do not use tilde (~) in your wav.scp." - exit 1; - fi - - if [ -f $data/segments ]; then - - check_sorted_and_uniq $data/segments - # We have a segments file -> interpret wav file as "recording-ids" not utterance-ids. - ! cat $data/segments | \ - awk '{if (NF != 4 || $4 <= $3) { print "Bad line in segments file", $0; exit(1); }}' && \ - echo "$0: badly formatted segments file" && exit 1; - - segments_len=`cat $data/segments | wc -l` - if [ -f $data/text ]; then - ! cmp -s $tmpdir/utts <(awk '{print $1}' <$data/segments) && \ - echo "$0: Utterance list differs between $data/utt2spk and $data/segments " && \ - echo "$0: Lengths are $segments_len vs $num_utts" && \ - exit 1 - fi - - cat $data/segments | awk '{print $2}' | sort | uniq > $tmpdir/recordings - awk '{print $1}' $data/wav.scp > $tmpdir/recordings.wav - if ! cmp -s $tmpdir/recordings{,.wav}; then - echo "$0: Error: in $data, recording-ids extracted from segments and wav.scp" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/recordings{,.wav} - exit 1; - fi - if [ -f $data/reco2file_and_channel ]; then - # this file is needed only for ctm scoring; it's indexed by recording-id. - check_sorted_and_uniq $data/reco2file_and_channel - ! cat $data/reco2file_and_channel | \ - awk '{if (NF != 3 || ($3 != "A" && $3 != "B" )) { - if ( NF == 3 && $3 == "1" ) { - warning_issued = 1; - } else { - print "Bad line ", $0; exit 1; - } - } - } - END { - if (warning_issued == 1) { - print "The channel should be marked as A or B, not 1! You should change it ASAP! " - } - }' && echo "$0: badly formatted reco2file_and_channel file" && exit 1; - cat $data/reco2file_and_channel | awk '{print $1}' > $tmpdir/recordings.r2fc - if ! cmp -s $tmpdir/recordings{,.r2fc}; then - echo "$0: Error: in $data, recording-ids extracted from segments and reco2file_and_channel" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/recordings{,.r2fc} - exit 1; - fi - fi - else - # No segments file -> assume wav.scp indexed by utterance. - cat $data/wav.scp | awk '{print $1}' > $tmpdir/utts.wav - if ! cmp -s $tmpdir/utts{,.wav}; then - echo "$0: Error: in $data, utterance lists extracted from utt2spk and wav.scp" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/utts{,.wav} - exit 1; - fi - - if [ -f $data/reco2file_and_channel ]; then - # this file is needed only for ctm scoring; it's indexed by recording-id. - check_sorted_and_uniq $data/reco2file_and_channel - ! cat $data/reco2file_and_channel | \ - awk '{if (NF != 3 || ($3 != "A" && $3 != "B" )) { - if ( NF == 3 && $3 == "1" ) { - warning_issued = 1; - } else { - print "Bad line ", $0; exit 1; - } - } - } - END { - if (warning_issued == 1) { - print "The channel should be marked as A or B, not 1! You should change it ASAP! " - } - }' && echo "$0: badly formatted reco2file_and_channel file" && exit 1; - cat $data/reco2file_and_channel | awk '{print $1}' > $tmpdir/utts.r2fc - if ! cmp -s $tmpdir/utts{,.r2fc}; then - echo "$0: Error: in $data, utterance-ids extracted from segments and reco2file_and_channel" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/utts{,.r2fc} - exit 1; - fi - fi - fi -fi - -if [ ! -f $data/feats.scp ] && ! $no_feats; then - echo "$0: no such file $data/feats.scp (if this is by design, specify --no-feats)" - exit 1; -fi - -if [ -f $data/feats.scp ]; then - check_sorted_and_uniq $data/feats.scp - cat $data/feats.scp | awk '{print $1}' > $tmpdir/utts.feats - if ! cmp -s $tmpdir/utts{,.feats}; then - echo "$0: Error: in $data, utterance-ids extracted from utt2spk and features" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/utts{,.feats} - exit 1; - fi -fi - - -if [ -f $data/cmvn.scp ]; then - check_sorted_and_uniq $data/cmvn.scp - cat $data/cmvn.scp | awk '{print $1}' > $tmpdir/speakers.cmvn - cat $data/spk2utt | awk '{print $1}' > $tmpdir/speakers - if ! cmp -s $tmpdir/speakers{,.cmvn}; then - echo "$0: Error: in $data, speaker lists extracted from spk2utt and cmvn" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/speakers{,.cmvn} - exit 1; - fi -fi - -if [ -f $data/spk2gender ]; then - check_sorted_and_uniq $data/spk2gender - ! cat $data/spk2gender | awk '{if (!((NF == 2 && ($2 == "m" || $2 == "f")))) exit 1; }' && \ - echo "$0: Mal-formed spk2gender file" && exit 1; - cat $data/spk2gender | awk '{print $1}' > $tmpdir/speakers.spk2gender - cat $data/spk2utt | awk '{print $1}' > $tmpdir/speakers - if ! cmp -s $tmpdir/speakers{,.spk2gender}; then - echo "$0: Error: in $data, speaker lists extracted from spk2utt and spk2gender" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/speakers{,.spk2gender} - exit 1; - fi -fi - -if [ -f $data/spk2warp ]; then - check_sorted_and_uniq $data/spk2warp - ! cat $data/spk2warp | awk '{if (!((NF == 2 && ($2 > 0.5 && $2 < 1.5)))){ print; exit 1; }}' && \ - echo "$0: Mal-formed spk2warp file" && exit 1; - cat $data/spk2warp | awk '{print $1}' > $tmpdir/speakers.spk2warp - cat $data/spk2utt | awk '{print $1}' > $tmpdir/speakers - if ! cmp -s $tmpdir/speakers{,.spk2warp}; then - echo "$0: Error: in $data, speaker lists extracted from spk2utt and spk2warp" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/speakers{,.spk2warp} - exit 1; - fi -fi - -if [ -f $data/utt2warp ]; then - check_sorted_and_uniq $data/utt2warp - ! cat $data/utt2warp | awk '{if (!((NF == 2 && ($2 > 0.5 && $2 < 1.5)))){ print; exit 1; }}' && \ - echo "$0: Mal-formed utt2warp file" && exit 1; - cat $data/utt2warp | awk '{print $1}' > $tmpdir/utts.utt2warp - cat $data/utt2spk | awk '{print $1}' > $tmpdir/utts - if ! cmp -s $tmpdir/utts{,.utt2warp}; then - echo "$0: Error: in $data, utterance lists extracted from utt2spk and utt2warp" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/utts{,.utt2warp} - exit 1; - fi -fi - -# check some optionally-required things -for f in vad.scp utt2lang utt2uniq; do - if [ -f $data/$f ]; then - check_sorted_and_uniq $data/$f - if ! cmp -s <( awk '{print $1}' $data/utt2spk ) \ - <( awk '{print $1}' $data/$f ); then - echo "$0: error: in $data, $f and utt2spk do not have identical utterance-id list" - exit 1; - fi - fi -done - - -if [ -f $data/utt2dur ]; then - check_sorted_and_uniq $data/utt2dur - cat $data/utt2dur | awk '{print $1}' > $tmpdir/utts.utt2dur - if ! cmp -s $tmpdir/utts{,.utt2dur}; then - echo "$0: Error: in $data, utterance-ids extracted from utt2spk and utt2dur file" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/utts{,.utt2dur} - exit 1; - fi - cat $data/utt2dur | \ - awk '{ if (NF != 2 || !($2 > 0)) { print "Bad line utt2dur:" NR ":" $0; exit(1) }}' || exit 1 -fi - -if [ -f $data/utt2num_frames ]; then - check_sorted_and_uniq $data/utt2num_frames - cat $data/utt2num_frames | awk '{print $1}' > $tmpdir/utts.utt2num_frames - if ! cmp -s $tmpdir/utts{,.utt2num_frames}; then - echo "$0: Error: in $data, utterance-ids extracted from utt2spk and utt2num_frames file" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/utts{,.utt2num_frames} - exit 1 - fi - awk <$data/utt2num_frames '{ - if (NF != 2 || !($2 > 0) || $2 != int($2)) { - print "Bad line utt2num_frames:" NR ":" $0 - exit 1 } }' || exit 1 -fi - -if [ -f $data/reco2dur ]; then - check_sorted_and_uniq $data/reco2dur - cat $data/reco2dur | awk '{print $1}' > $tmpdir/recordings.reco2dur - if [ -f $tmpdir/recordings ]; then - if ! cmp -s $tmpdir/recordings{,.reco2dur}; then - echo "$0: Error: in $data, recording-ids extracted from segments and reco2dur file" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/recordings{,.reco2dur} - exit 1; - fi - else - if ! cmp -s $tmpdir/{utts,recordings.reco2dur}; then - echo "$0: Error: in $data, recording-ids extracted from wav.scp and reco2dur file" - echo "$0: differ, partial diff is:" - partial_diff $tmpdir/{utts,recordings.reco2dur} - exit 1; - fi - fi - cat $data/reco2dur | \ - awk '{ if (NF != 2 || !($2 > 0)) { print "Bad line : " $0; exit(1) }}' || exit 1 -fi - - -echo "$0: Successfully validated data-directory $data" diff --git a/egs/alimeeting/sa_asr/local/validate_text.pl b/egs/alimeeting/sa_asr/local/validate_text.pl deleted file mode 100755 index 7f75cf12f..000000000 --- a/egs/alimeeting/sa_asr/local/validate_text.pl +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env perl -# -#=============================================================================== -# Copyright 2017 Johns Hopkins University (author: Yenda Trmal ) -# Johns Hopkins University (author: Daniel Povey) -# -# 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 -# -# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -# MERCHANTABLITY OR NON-INFRINGEMENT. -# See the Apache 2 License for the specific language governing permissions and -# limitations under the License. -#=============================================================================== - -# validation script for data//text -# to be called (preferably) from utils/validate_data_dir.sh -use strict; -use warnings; -use utf8; -use Fcntl qw< SEEK_SET >; - -# this function reads the opened file (supplied as a first -# parameter) into an array of lines. For each -# line, it tests whether it's a valid utf-8 compatible -# line. If all lines are valid utf-8, it returns the lines -# decoded as utf-8, otherwise it assumes the file's encoding -# is one of those 1-byte encodings, such as ISO-8859-x -# or Windows CP-X. -# Please recall we do not really care about -# the actually encoding, we just need to -# make sure the length of the (decoded) string -# is correct (to make the output formatting looking right). -sub get_utf8_or_bytestream { - use Encode qw(decode encode); - my $is_utf_compatible = 1; - my @unicode_lines; - my @raw_lines; - my $raw_text; - my $lineno = 0; - my $file = shift; - - while (<$file>) { - $raw_text = $_; - last unless $raw_text; - if ($is_utf_compatible) { - my $decoded_text = eval { decode("UTF-8", $raw_text, Encode::FB_CROAK) } ; - $is_utf_compatible = $is_utf_compatible && defined($decoded_text); - push @unicode_lines, $decoded_text; - } else { - #print STDERR "WARNING: the line $raw_text cannot be interpreted as UTF-8: $decoded_text\n"; - ; - } - push @raw_lines, $raw_text; - $lineno += 1; - } - - if (!$is_utf_compatible) { - return (0, @raw_lines); - } else { - return (1, @unicode_lines); - } -} - -# check if the given unicode string contain unicode whitespaces -# other than the usual four: TAB, LF, CR and SPACE -sub validate_utf8_whitespaces { - my $unicode_lines = shift; - use feature 'unicode_strings'; - for (my $i = 0; $i < scalar @{$unicode_lines}; $i++) { - my $current_line = $unicode_lines->[$i]; - if ((substr $current_line, -1) ne "\n"){ - print STDERR "$0: The current line (nr. $i) has invalid newline\n"; - return 1; - } - my @A = split(" ", $current_line); - my $utt_id = $A[0]; - # we replace TAB, LF, CR, and SPACE - # this is to simplify the test - if ($current_line =~ /\x{000d}/) { - print STDERR "$0: The line for utterance $utt_id contains CR (0x0D) character\n"; - return 1; - } - $current_line =~ s/[\x{0009}\x{000a}\x{0020}]/./g; - if ($current_line =~/\s/) { - print STDERR "$0: The line for utterance $utt_id contains disallowed Unicode whitespaces\n"; - return 1; - } - } - return 0; -} - -# checks if the text in the file (supplied as the argument) is utf-8 compatible -# if yes, checks if it contains only allowed whitespaces. If no, then does not -# do anything. The function seeks to the original position in the file after -# reading the text. -sub check_allowed_whitespace { - my $file = shift; - my $filename = shift; - my $pos = tell($file); - (my $is_utf, my @lines) = get_utf8_or_bytestream($file); - seek($file, $pos, SEEK_SET); - if ($is_utf) { - my $has_invalid_whitespaces = validate_utf8_whitespaces(\@lines); - if ($has_invalid_whitespaces) { - print STDERR "$0: ERROR: text file '$filename' contains disallowed UTF-8 whitespace character(s)\n"; - return 0; - } - } - return 1; -} - -if(@ARGV != 1) { - die "Usage: validate_text.pl \n" . - "e.g.: validate_text.pl data/train/text\n"; -} - -my $text = shift @ARGV; - -if (-z "$text") { - print STDERR "$0: ERROR: file '$text' is empty or does not exist\n"; - exit 1; -} - -if(!open(FILE, "<$text")) { - print STDERR "$0: ERROR: failed to open $text\n"; - exit 1; -} - -check_allowed_whitespace(\*FILE, $text) or exit 1; -close(FILE); diff --git a/egs/alimeeting/sa_asr/path.sh b/egs/alimeeting/sa_asr/path.sh deleted file mode 100755 index 83ae507b7..000000000 --- a/egs/alimeeting/sa_asr/path.sh +++ /dev/null @@ -1,6 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:./utils:$FUNASR_DIR:$PATH -export PYTHONPATH=$FUNASR_DIR:$PYTHONPATH diff --git a/egs/alimeeting/sa_asr/run.sh b/egs/alimeeting/sa_asr/run.sh deleted file mode 100755 index 43d0da13f..000000000 --- a/egs/alimeeting/sa_asr/run.sh +++ /dev/null @@ -1,435 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="6,7" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=8 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="data" #feature output dictionary -exp_dir="exp" -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="1.0" -min_wav_duration=0.1 -max_wav_duration=20 -profile_modes="cluster oracle" -stage=7 -stop_stage=7 - -# feature configuration -feats_dim=80 -nj=32 - -# data -raw_data= -data_url= - -# exp tag -tag="" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=Train_Ali_far -valid_set=Eval_Ali_far -test_sets="Test_Ali_far Eval_Ali_far" -test_2023="Test_2023_Ali_far_release" - -asr_config=conf/train_asr_conformer.yaml -sa_asr_config=conf/train_sa_asr_conformer.yaml -asr_model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" -sa_asr_model_dir="baseline_$(basename "${sa_asr_config}" .yaml)_${lang}_${token_type}_${tag}" -inference_config=conf/decode_asr_rnn.yaml -inference_sa_asr_model=valid.acc_spk.ave.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - ./local/alimeeting_data_prep.sh --tgt Test --min_wav_duration $min_wav_duration --max_wav_duration $max_wav_duration - ./local/alimeeting_data_prep.sh --tgt Eval --min_wav_duration $min_wav_duration --max_wav_duration $max_wav_duration - ./local/alimeeting_data_prep.sh --tgt Train --min_wav_duration $min_wav_duration --max_wav_duration $max_wav_duration - # remove long/short data - for x in ${train_set} ${valid_set} ${test_sets}; do - cp -r ${feats_dir}/org/${x} ${feats_dir}/${x} - rm ${feats_dir}/"${x}"/wav.scp ${feats_dir}/"${x}"/segments - local/format_wav_scp.sh --nj "${nj}" --cmd "${train_cmd}" \ - --audio-format wav --segments ${feats_dir}/org/${x}/segments \ - "${feats_dir}/org/${x}/${scp}" "${feats_dir}/${x}" - _min_length=$(python3 -c "print(int(${min_wav_duration} * 16000))") - _max_length=$(python3 -c "print(int(${max_wav_duration} * 16000))") - <"${feats_dir}/${x}/utt2num_samples" \ - awk '{if($2 > '$_min_length' && $2 < '$_max_length')print $0;}' \ - >"${feats_dir}/${x}/utt2num_samples_rmls" - mv ${feats_dir}/${x}/utt2num_samples_rmls ${feats_dir}/${x}/utt2num_samples - <"${feats_dir}/${x}/wav.scp" \ - utils/filter_scp.pl "${feats_dir}/${x}/utt2num_samples" \ - >"${feats_dir}/${x}/wav.scp_rmls" - mv ${feats_dir}/${x}/wav.scp_rmls ${feats_dir}/${x}/wav.scp - <"${feats_dir}/${x}/text" \ - awk '{ if( NF != 1 ) print $0; }' >"${feats_dir}/${x}/text_rmblank" - mv ${feats_dir}/${x}/text_rmblank ${feats_dir}/${x}/text - local/fix_${feats_dir}_dir.sh "${feats_dir}/${x}" - <"${feats_dir}/${x}/utt2spk_all_fifo" \ - utils/filter_scp.pl "${feats_dir}/${x}/text" \ - >"${feats_dir}/${x}/utt2spk_all_fifo_rmls" - mv "${feats_dir}/${x}/utt2spk_all_fifo_rmls" "${feats_dir}/${x}/utt2spk_all_fifo" - done - for x in ${test_2023}; do - local/format_wav_scp.sh --nj "${nj}" --cmd "${train_cmd}" \ - --audio-format wav --segments ${feats_dir}/org/${x}/segments \ - "${feats_dir}/org/${x}/${scp}" "${feats_dir}/${x}" - cut -d " " -f1 ${feats_dir}/${x}/wav.scp > ${feats_dir}/${x}/uttid - paste -d " " ${feats_dir}/${x}/uttid ${feats_dir}/${x}/uttid > ${feats_dir}/${x}/utt2spk - cp ${feats_dir}/${x}/utt2spk ${feats_dir}/${x}/spk2utt - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Speaker profile and CMVN Generation" - - mkdir -p "profile_log" - for x in "${train_set}" "${valid_set}" "${test_sets}"; do - # generate text_id spk2id - python local/process_sot_fifo_textchar2spk.py --path ${feats_dir}/${x} - echo "Successfully generate ${feats_dir}/${x}/text_id ${feats_dir}/${x}/spk2id" - # generate text_id_train for sot - python local/process_text_id.py ${feats_dir}/${x} - echo "Successfully generate ${feats_dir}/${x}/text_id_train" - # generate oracle_embedding from single-speaker audio segment - echo "oracle_embedding is being generated in the background, and the log is profile_log/gen_oracle_embedding_${x}.log" - python local/gen_oracle_embedding.py "${feats_dir}/${x}" "data/org/${x}_single_speaker" &> "profile_log/gen_oracle_embedding_${x}.log" - echo "Successfully generate oracle embedding for ${x} (${feats_dir}/${x}/oracle_embedding.scp)" - # generate oracle_profile and cluster_profile from oracle_embedding and cluster_embedding (padding the speaker during training) - if [ "${x}" = "${train_set}" ]; then - python local/gen_oracle_profile_padding.py ${feats_dir}/${x} - echo "Successfully generate oracle profile for ${x} (${feats_dir}/${x}/oracle_profile_padding.scp)" - else - python local/gen_oracle_profile_nopadding.py ${feats_dir}/${x} - echo "Successfully generate oracle profile for ${x} (${feats_dir}/${x}/oracle_profile_nopadding.scp)" - fi - # generate cluster_profile with spectral-cluster directly (for infering and without oracle information) - if [ "${x}" = "${valid_set}" ] || [ "${x}" = "${test_sets}" ]; then - echo "cluster_profile is being generated in the background, and the log is profile_log/gen_cluster_profile_infer_${x}.log" - python local/gen_cluster_profile_infer.py "${feats_dir}/${x}" "${feats_dir}/org/${x}" 0.996 0.815 &> "profile_log/gen_cluster_profile_infer_${x}.log" - echo "Successfully generate cluster profile for ${x} (${feats_dir}/${x}/cluster_profile_infer.scp)" - fi - # compute CMVN - if [ "${x}" = "${train_set}" ]; then - local/compute_cmvn.sh --cmd "$train_cmd" --nj $nj --fbankdir ${feats_dir}/${train_set} --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 - fi - done - - for x in "${test_2023}"; do - # generate cluster_profile with spectral-cluster directly (for infering and without oracle information) - python local/gen_cluster_profile_infer.py "${feats_dir}/${x}" "${feats_dir}/org/${x}" 0.996 0.815 &> "profile_log/gen_cluster_profile_infer_${x}.log" - echo "Successfully generate cluster profile for ${x} (${feats_dir}/${x}/cluster_profile_infer.scp)" - done -fi - -token_list=${feats_dir}/${lang}_token_list/char/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/${lang}_token_list/char/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "Stage 4: ASR Training" - asr_exp=${exp_dir}/${asr_model_dir} - mkdir -p ${asr_exp} - mkdir -p ${asr_exp}/log - INIT_FILE=${asr_exp}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $ngpu; ++i)); do - { - # i=0 - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --model asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --split_with_space false \ - --token_type char \ - --token_list $token_list \ - --data_dir ${feats_dir} \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/${train_set}/cmvn/cmvn.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/${asr_model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/${asr_model_dir}/log/train.log.$i 2>&1 - } & - done - wait - -fi - - - -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "SA-ASR training" - asr_exp=${exp_dir}/${asr_model_dir} - sa_asr_exp=${exp_dir}/${sa_asr_model_dir} - mkdir -p ${sa_asr_exp} - mkdir -p ${sa_asr_exp}/log - INIT_FILE=${sa_asr_exp}/ddp_init - if [ ! -L ${feats_dir}/${train_set}/profile.scp ]; then - ln -sr ${feats_dir}/${train_set}/oracle_profile_padding.scp ${feats_dir}/${train_set}/profile.scp - ln -sr ${feats_dir}/${valid_set}/oracle_profile_nopadding.scp ${feats_dir}/${valid_set}/profile.scp - fi - - if [ ! -f "${exp_dir}/damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/sv.pth" ]; then - # download xvector extractor model file - python local/download_xvector_model.py ${exp_dir} - echo "Successfully download the pretrained xvector extractor to exp/damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/sv.pth" - fi - - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $ngpu; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --model sa_asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --split_with_space false \ - --unused_parameters true \ - --token_type char \ - --resume true \ - --token_list $token_list \ - --data_dir ${feats_dir} \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text,profile.scp,text_id_train" \ - --cmvn_file ${feats_dir}/${train_set}/cmvn/cmvn.mvn \ - --speed_perturb ${speed_perturb} \ - --init_param "${asr_exp}/valid.acc.ave.pb:encoder:asr_encoder" \ - --init_param "${asr_exp}/valid.acc.ave.pb:ctc:ctc" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.embed:decoder.embed" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.output_layer:decoder.asr_output_layer" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.decoders.0.self_attn:decoder.decoder1.self_attn" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.decoders.0.src_attn:decoder.decoder3.src_attn" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.decoders.0.feed_forward:decoder.decoder3.feed_forward" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.decoders.1:decoder.decoder4.0" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.decoders.2:decoder.decoder4.1" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.decoders.3:decoder.decoder4.2" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.decoders.4:decoder.decoder4.3" \ - --init_param "${asr_exp}/valid.acc.ave.pb:decoder.decoders.5:decoder.decoder4.4" \ - --init_param "exp/damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/sv.pth:encoder:spk_encoder" \ - --init_param "exp/damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/sv.pth:decoder:spk_encoder:decoder.output_dense" \ - --output_dir ${exp_dir}/${sa_asr_model_dir} \ - --config $sa_asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/${sa_asr_model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - - -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: Inference test sets" - for x in ${test_sets}; do - for profile_mode in ${profile_modes}; do - echo "decoding ${x} with ${profile_mode} profile" - sa_asr_exp=${exp_dir}/${sa_asr_model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${sa_asr_exp}/${inference_tag}_${profile_mode}/${inference_sa_asr_model}/${x}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/${x}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - if [ $profile_mode = "oracle" ]; then - profile_scp=${profile_mode}_profile_nopadding.scp - else - profile_scp=${profile_mode}_profile_infer.scp - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --mc True \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --nbest 1 \ - --gpuid_list ${gpuid_list} \ - --allow_variable_data_keys true \ - --cmvn_file ${feats_dir}/${train_set}/cmvn/cmvn.mvn \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --data_path_and_name_and_type "${_data}/$profile_scp,profile,npy" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${sa_asr_exp}"/config.yaml \ - --asr_model_file "${sa_asr_exp}"/"${inference_sa_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode sa_asr \ - ${_opts} - - for f in token token_int score text text_id; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - sed 's/\$//g' ${_data}/text > ${_data}/text_nosrc - sed 's/\$//g' ${_dir}/text > ${_dir}/text_nosrc - python utils/proce_text.py ${_data}/text_nosrc ${_data}/text.proc - python utils/proce_text.py ${_dir}/text_nosrc ${_dir}/text.proc - - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - - python local/process_text_spk_merge.py ${_dir} - python local/process_text_spk_merge.py ${_data} - - python local/compute_cpcer.py ${_data}/text_spk_merge ${_dir}/text_spk_merge ${_dir}/text.cpcer - tail -n 1 ${_dir}/text.cpcer > ${_dir}/text.cpcer.txt - cat ${_dir}/text.cpcer.txt - done - done -fi - -if [ ${stage} -le 7 ] && [ ${stop_stage} -ge 7 ]; then - echo "stage 7: Inference test 2023" - for x in ${test_2023}; do - sa_asr_exp=${exp_dir}/${sa_asr_model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${sa_asr_exp}/${inference_tag}_cluster/${inference_sa_asr_model}/${x}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/${x}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --mc True \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --nbest 1 \ - --gpuid_list ${gpuid_list} \ - --allow_variable_data_keys true \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --data_path_and_name_and_type "${_data}/cluster_profile_infer.scp,profile,npy" \ - --cmvn_file ${feats_dir}/${train_set}/cmvn/cmvn.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${sa_asr_exp}"/config.yaml \ - --asr_model_file "${sa_asr_exp}"/"${inference_sa_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode sa_asr \ - ${_opts} - - for f in token token_int score text text_id; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - - python local/process_text_spk_merge.py ${_dir} - - done -fi - - diff --git a/egs/alimeeting/sa_asr/utils b/egs/alimeeting/sa_asr/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/alimeeting/sa_asr/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_callhome_chunk2000.yaml b/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_callhome_chunk2000.yaml deleted file mode 100644 index cd143f721..000000000 --- a/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_callhome_chunk2000.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# network architecture -# encoder related -encoder: eend_ola_transformer -encoder_conf: - idim: 345 - n_layers: 4 - n_units: 256 - -# encoder-decoder attractor related -encoder_decoder_attractor: eda -encoder_decoder_attractor_conf: - n_units: 256 - -# model related -model: eend_ola -model_conf: - attractor_loss_weight: 0.01 - max_n_speaker: 8 - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 100 -val_scheduler_criterion: - - valid - - loss -best_model_criterion: -- - valid - - loss - - min -keep_nbest_models: 100 - -optim: adam -optim_conf: - lr: 0.00001 - -dataset_conf: - data_names: speech_speaker_labels - data_types: kaldi_ark - batch_conf: - batch_type: unsorted - batch_size: 8 - num_workers: 8 - -log_interval: 50 \ No newline at end of file diff --git a/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_simu_2spkr.yaml b/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_simu_2spkr.yaml deleted file mode 100644 index 47316fe36..000000000 --- a/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_simu_2spkr.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# network architecture -# encoder related -encoder: eend_ola_transformer -encoder_conf: - idim: 345 - n_layers: 4 - n_units: 256 - -# encoder-decoder attractor related -encoder_decoder_attractor: eda -encoder_decoder_attractor_conf: - n_units: 256 - -# model related -model: eend_ola -model_conf: - max_n_speaker: 8 - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 100 -val_scheduler_criterion: - - valid - - loss -best_model_criterion: -- - valid - - loss - - min -keep_nbest_models: 100 - -optim: adam -optim_conf: - lr: 1.0 - betas: - - 0.9 - - 0.98 - eps: 1.0e-9 -scheduler: noamlr -scheduler_conf: - model_size: 256 - warmup_steps: 100000 - -dataset_conf: - data_names: speech_speaker_labels - data_types: kaldi_ark - batch_conf: - batch_type: unsorted - batch_size: 64 - num_workers: 8 - -log_interval: 50 \ No newline at end of file diff --git a/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_simu_allspkr.yaml b/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_simu_allspkr.yaml deleted file mode 100644 index f55e14895..000000000 --- a/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_simu_allspkr.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# network architecture -# encoder related -encoder: eend_ola_transformer -encoder_conf: - idim: 345 - n_layers: 4 - n_units: 256 - -# encoder-decoder attractor related -encoder_decoder_attractor: eda -encoder_decoder_attractor_conf: - n_units: 256 - -# model related -model: eend_ola -model_conf: - max_n_speaker: 8 - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 25 -val_scheduler_criterion: - - valid - - loss -best_model_criterion: -- - valid - - loss - - min -keep_nbest_models: 100 - -optim: adam -optim_conf: - lr: 1.0 - betas: - - 0.9 - - 0.98 - eps: 1.0e-9 -scheduler: noamlr -scheduler_conf: - model_size: 256 - warmup_steps: 100000 - -dataset_conf: - data_names: speech_speaker_labels - data_types: kaldi_ark - batch_conf: - batch_type: unsorted - batch_size: 64 - num_workers: 8 - -log_interval: 50 \ No newline at end of file diff --git a/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_simu_allspkr_chunk2000.yaml b/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_simu_allspkr_chunk2000.yaml deleted file mode 100644 index d21d467a1..000000000 --- a/egs/callhome/TOLD/eend_ola/conf/train_diar_eend_ola_simu_allspkr_chunk2000.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# network architecture -# encoder related -encoder: eend_ola_transformer -encoder_conf: - idim: 345 - n_layers: 4 - n_units: 256 - -# encoder-decoder attractor related -encoder_decoder_attractor: eda -encoder_decoder_attractor_conf: - n_units: 256 - -# model related -model: eend_ola -model_conf: - max_n_speaker: 8 - -# optimization related -accum_grad: 1 -grad_clip: 5 -max_epoch: 1 -val_scheduler_criterion: - - valid - - loss -best_model_criterion: -- - valid - - loss - - min -keep_nbest_models: 100 - -optim: adam -optim_conf: - lr: 0.00001 - -dataset_conf: - data_names: speech_speaker_labels - data_types: kaldi_ark - batch_conf: - batch_type: unsorted - batch_size: 8 - num_workers: 8 - -log_interval: 50 \ No newline at end of file diff --git a/egs/callhome/TOLD/eend_ola/local/dump_feature.py b/egs/callhome/TOLD/eend_ola/local/dump_feature.py deleted file mode 100644 index 5d7a0610c..000000000 --- a/egs/callhome/TOLD/eend_ola/local/dump_feature.py +++ /dev/null @@ -1,144 +0,0 @@ -import argparse -import os - -from kaldiio import WriteHelper - -import funasr.modules.eend_ola.utils.feature as feature -from funasr.modules.eend_ola.utils.kaldi_data import load_segments_rechash, load_utt2spk, load_wav_scp, load_reco2dur, \ - load_spk2utt, load_wav - - -def _count_frames(data_len, size, step): - return int((data_len - size + step) / step) - - -def _gen_frame_indices( - data_length, size=2000, step=2000, - use_last_samples=False, - label_delay=0, - subsampling=1): - i = -1 - for i in range(_count_frames(data_length, size, step)): - yield i * step, i * step + size - if use_last_samples and i * step + size < data_length: - if data_length - (i + 1) * step - subsampling * label_delay > 0: - yield (i + 1) * step, data_length - - -class KaldiData: - def __init__(self, data_dir, idx): - self.data_dir = data_dir - segment_file = os.path.join(self.data_dir, 'segments.{}'.format(idx)) - self.segments = load_segments_rechash(segment_file) - - utt2spk_file = os.path.join(self.data_dir, 'utt2spk.{}'.format(idx)) - self.utt2spk = load_utt2spk(utt2spk_file) - - wav_file = os.path.join(self.data_dir, 'wav.scp.{}'.format(idx)) - self.wavs = load_wav_scp(wav_file) - - reco2dur_file = os.path.join(self.data_dir, 'reco2dur.{}'.format(idx)) - self.reco2dur = load_reco2dur(reco2dur_file) - - spk2utt_file = os.path.join(self.data_dir, 'spk2utt.{}'.format(idx)) - self.spk2utt = load_spk2utt(spk2utt_file) - - def load_wav(self, recid, start=0, end=None): - data, rate = load_wav(self.wavs[recid], start, end) - return data, rate - - -class KaldiDiarizationDataset(): - def __init__( - self, - data_dir, - index, - chunk_size=2000, - context_size=0, - frame_size=1024, - frame_shift=256, - subsampling=1, - rate=16000, - input_transform=None, - use_last_samples=False, - label_delay=0, - n_speakers=None, - ): - self.data_dir = data_dir - self.index = index - self.chunk_size = chunk_size - self.context_size = context_size - self.frame_size = frame_size - self.frame_shift = frame_shift - self.subsampling = subsampling - self.input_transform = input_transform - self.n_speakers = n_speakers - self.chunk_indices = [] - self.label_delay = label_delay - - self.data = KaldiData(self.data_dir, index) - - for rec, path in self.data.wavs.items(): - data_len = int(self.data.reco2dur[rec] * rate / frame_shift) - data_len = int(data_len / self.subsampling) - for st, ed in _gen_frame_indices( - data_len, chunk_size, chunk_size, use_last_samples, - label_delay=self.label_delay, - subsampling=self.subsampling): - self.chunk_indices.append( - (rec, path, st * self.subsampling, ed * self.subsampling)) - print(len(self.chunk_indices), " chunks") - - -def convert(args): - dataset = KaldiDiarizationDataset( - data_dir=args.data_dir, - index=args.index, - chunk_size=args.num_frames, - context_size=args.context_size, - input_transform="logmel23_mn", - frame_size=args.frame_size, - frame_shift=args.frame_shift, - subsampling=args.subsampling, - rate=8000, - use_last_samples=True, - ) - - feature_ark_file = os.path.join(args.output_dir, "feature.ark.{}".format(args.index)) - feature_scp_file = os.path.join(args.output_dir, "feature.scp.{}".format(args.index)) - label_ark_file = os.path.join(args.output_dir, "label.ark.{}".format(args.index)) - label_scp_file = os.path.join(args.output_dir, "label.scp.{}".format(args.index)) - with WriteHelper('ark,scp:{},{}'.format(feature_ark_file, feature_scp_file)) as feature_writer, \ - WriteHelper('ark,scp:{},{}'.format(label_ark_file, label_scp_file)) as label_writer: - for idx, (rec, path, st, ed) in enumerate(dataset.chunk_indices): - Y, T = feature.get_labeledSTFT( - dataset.data, - rec, - st, - ed, - dataset.frame_size, - dataset.frame_shift, - dataset.n_speakers) - Y = feature.transform(Y, dataset.input_transform) - Y_spliced = feature.splice(Y, dataset.context_size) - Y_ss, T_ss = feature.subsample(Y_spliced, T, dataset.subsampling) - st = '{:0>7d}'.format(st) - ed = '{:0>7d}'.format(ed) - key = "{}_{}_{}".format(rec, st, ed) - feature_writer(key, Y_ss) - label_writer(key, T_ss.reshape(-1)) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--data_dir", type=str) - parser.add_argument("--output_dir", type=str) - parser.add_argument("--index", type=str) - parser.add_argument("--num_frames", type=int, default=500) - parser.add_argument("--context_size", type=int, default=7) - parser.add_argument("--frame_size", type=int, default=200) - parser.add_argument("--frame_shift", type=int, default=80) - parser.add_argument("--subsampling", type=int, default=10) - - args = parser.parse_args() - convert(args) diff --git a/egs/callhome/TOLD/eend_ola/local/gen_feats_scp.py b/egs/callhome/TOLD/eend_ola/local/gen_feats_scp.py deleted file mode 100644 index 88a94f218..000000000 --- a/egs/callhome/TOLD/eend_ola/local/gen_feats_scp.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -import argparse - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--root_path", type=str) - parser.add_argument("--out_path", type=str) - parser.add_argument("--split_num", type=int, default=64) - args = parser.parse_args() - root_path = args.root_path - out_path = args.out_path - split_num = args.split_num - - with open(os.path.join(out_path, "feats.scp"), "w") as out_f: - for i in range(split_num): - idx = str(i + 1) - feature_file = os.path.join(root_path, "feature.scp.{}".format(idx)) - label_file = os.path.join(root_path, "label.scp.{}".format(idx)) - with open(feature_file) as ff, open(label_file) as fl: - ff_lines = ff.readlines() - fl_lines = fl.readlines() - for ff_line, fl_line in zip(ff_lines, fl_lines): - sample_name, f_path = ff_line.strip().split() - _, l_path = fl_line.strip().split() - out_f.write("{} {} {}\n".format(sample_name, f_path, l_path)) \ No newline at end of file diff --git a/egs/callhome/TOLD/eend_ola/local/infer.py b/egs/callhome/TOLD/eend_ola/local/infer.py deleted file mode 100644 index 23e1d52c9..000000000 --- a/egs/callhome/TOLD/eend_ola/local/infer.py +++ /dev/null @@ -1,138 +0,0 @@ -import argparse -import os - -import numpy as np -import soundfile as sf -import torch -import yaml -from scipy.signal import medfilt - -import funasr.models.frontend.eend_ola_feature as eend_ola_feature -from funasr.build_utils.build_model_from_file import build_model_from_file - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument( - "--config_file", - type=str, - help="model config file", - ) - parser.add_argument( - "--model_file", - type=str, - help="model path", - ) - parser.add_argument( - "--output_rttm_file", - type=str, - help="output rttm path", - ) - parser.add_argument( - "--wav_scp_file", - type=str, - default="wav.scp", - help="input data path", - ) - parser.add_argument( - "--frame_shift", - type=int, - default=80, - help="frame shift", - ) - parser.add_argument( - "--frame_size", - type=int, - default=200, - help="frame size", - ) - parser.add_argument( - "--context_size", - type=int, - default=7, - help="context size", - ) - parser.add_argument( - "--sampling_rate", - type=int, - default=8000, - help="sampling rate", - ) - parser.add_argument( - "--subsampling", - type=int, - default=10, - help="setting subsampling", - ) - parser.add_argument( - "--shuffle", - type=bool, - default=True, - help="shuffle speech in time", - ) - parser.add_argument( - "--attractor_threshold", - type=float, - default=0.5, - help="threshold for selecting attractors", - ) - parser.add_argument( - "--device", - type=str, - default="cuda", - ) - args = parser.parse_args() - - with open(args.config_file) as f: - configs = yaml.safe_load(f) - for k, v in configs.items(): - if not hasattr(args, k): - setattr(args, k, v) - - np.random.seed(args.seed) - torch.manual_seed(args.seed) - torch.cuda.manual_seed(args.seed) - os.environ['PYTORCH_SEED'] = str(args.seed) - - model, _ = build_model_from_file(config_file=args.config_file, model_file=args.model_file, task_name="diar", - device=args.device) - model.eval() - - with open(args.wav_scp_file) as f: - wav_lines = [line.strip().split() for line in f.readlines()] - wav_items = {x[0]: x[1] for x in wav_lines} - - print("Start inference") - with open(args.output_rttm_file, "w") as wf: - for wav_id in wav_items.keys(): - print("Process wav: {}".format(wav_id)) - data, rate = sf.read(wav_items[wav_id]) - speech = eend_ola_feature.stft(data, args.frame_size, args.frame_shift) - speech = eend_ola_feature.transform(speech) - speech = eend_ola_feature.splice(speech, context_size=args.context_size) - speech = speech[::args.subsampling] # sampling - speech = torch.from_numpy(speech) - - with torch.no_grad(): - speech = speech.to(args.device) - ys, _, _, _ = model.estimate_sequential( - [speech], - n_speakers=None, - th=args.attractor_threshold, - shuffle=args.shuffle - ) - - a = ys[0].cpu().numpy() - a = medfilt(a, (11, 1)) - rst = [] - for spkr_id, frames in enumerate(a.T): - frames = np.pad(frames, (1, 1), 'constant') - changes, = np.where(np.diff(frames, axis=0) != 0) - fmt = "SPEAKER {:s} 1 {:7.2f} {:7.2f} {:s} " - for s, e in zip(changes[::2], changes[1::2]): - st = s * args.frame_shift * args.subsampling / args.sampling_rate - dur = (e - s) * args.frame_shift * args.subsampling / args.sampling_rate - print(fmt.format( - wav_id, - st, - dur, - wav_id + "_" + str(spkr_id)), file=wf) \ No newline at end of file diff --git a/egs/callhome/TOLD/eend_ola/local/make_callhome.sh b/egs/callhome/TOLD/eend_ola/local/make_callhome.sh deleted file mode 100755 index caa8f679f..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_callhome.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -# Copyright 2017 David Snyder -# Apache 2.0. -# -# This script prepares the Callhome portion of the NIST SRE 2000 -# corpus (LDC2001S97). It is the evaluation dataset used in the -# callhome_diarization recipe. - -if [ $# -ne 2 ]; then - echo "Usage: $0 " - echo "e.g.: $0 /mnt/data/LDC2001S97 data/" - exit 1; -fi - -src_dir=$1 -data_dir=$2 - -tmp_dir=$data_dir/callhome/.tmp/ -mkdir -p $tmp_dir - -# Download some metadata that wasn't provided in the LDC release -if [ ! -d "$tmp_dir/sre2000-key" ]; then - wget --no-check-certificate -P $tmp_dir/ \ - http://www.openslr.org/resources/10/sre2000-key.tar.gz - tar -xvf $tmp_dir/sre2000-key.tar.gz -C $tmp_dir/ -fi - -# The list of 500 recordings -awk '{print $1}' $tmp_dir/sre2000-key/reco2num > $tmp_dir/reco.list - -# Create wav.scp file -count=0 -missing=0 -while read reco; do - path=$(find $src_dir -name "$reco.sph") - if [ -z "${path// }" ]; then - >&2 echo "$0: Missing Sphere file for $reco" - missing=$((missing+1)) - else - echo "$reco sph2pipe -f wav -p $path |" - fi - count=$((count+1)) -done < $tmp_dir/reco.list > $data_dir/callhome/wav.scp - -if [ $missing -gt 0 ]; then - echo "$0: Missing $missing out of $count recordings" -fi - -cp $tmp_dir/sre2000-key/segments $data_dir/callhome/ -awk '{print $1, $2}' $data_dir/callhome/segments > $data_dir/callhome/utt2spk -utils/utt2spk_to_spk2utt.pl $data_dir/callhome/utt2spk > $data_dir/callhome/spk2utt -cp $tmp_dir/sre2000-key/reco2num $data_dir/callhome/reco2num_spk -cp $tmp_dir/sre2000-key/fullref.rttm $data_dir/callhome/ - -utils/validate_data_dir.sh --no-text --no-feats $data_dir/callhome -utils/fix_data_dir.sh $data_dir/callhome - -utils/copy_data_dir.sh $data_dir/callhome $data_dir/callhome1 -utils/copy_data_dir.sh $data_dir/callhome $data_dir/callhome2 - -utils/shuffle_list.pl $data_dir/callhome/wav.scp | head -n 250 \ - | utils/filter_scp.pl - $data_dir/callhome/wav.scp \ - > $data_dir/callhome1/wav.scp -utils/fix_data_dir.sh $data_dir/callhome1 -utils/filter_scp.pl --exclude $data_dir/callhome1/wav.scp \ - $data_dir/callhome/wav.scp > $data_dir/callhome2/wav.scp -utils/fix_data_dir.sh $data_dir/callhome2 -utils/filter_scp.pl $data_dir/callhome1/wav.scp $data_dir/callhome/reco2num_spk \ - > $data_dir/callhome1/reco2num_spk -utils/filter_scp.pl $data_dir/callhome2/wav.scp $data_dir/callhome/reco2num_spk \ - > $data_dir/callhome2/reco2num_spk - -rm -rf $tmp_dir 2> /dev/null diff --git a/egs/callhome/TOLD/eend_ola/local/make_mixture.py b/egs/callhome/TOLD/eend_ola/local/make_mixture.py deleted file mode 100755 index 6b159034d..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_mixture.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2019 Hitachi, Ltd. (author: Yusuke Fujita) -# Licensed under the MIT license. -# -# This script generates simulated multi-talker mixtures for diarization -# -# common/make_mixture.py \ -# mixture.scp \ -# data/mixture \ -# wav/mixture - - -import argparse -import os -from funasr.modules.eend_ola.utils import kaldi_data -import numpy as np -import math -import soundfile as sf -import json - -parser = argparse.ArgumentParser() -parser.add_argument('script', - help='list of json') -parser.add_argument('out_data_dir', - help='output data dir of mixture') -parser.add_argument('out_wav_dir', - help='output mixture wav files are stored here') -parser.add_argument('--rate', type=int, default=16000, - help='sampling rate') -args = parser.parse_args() - -# open output data files -segments_f = open(args.out_data_dir + '/segments', 'w') -utt2spk_f = open(args.out_data_dir + '/utt2spk', 'w') -wav_scp_f = open(args.out_data_dir + '/wav.scp', 'w') - -# "-R" forces the default random seed for reproducibility -resample_cmd = "sox -R -t wav - -t wav - rate {}".format(args.rate) - -for line in open(args.script): - recid, jsonstr = line.strip().split(None, 1) - indata = json.loads(jsonstr) - wavfn = indata['recid'] - # recid now include out_wav_dir - recid = os.path.join(args.out_wav_dir, wavfn).replace('/','_') - noise = indata['noise'] - noise_snr = indata['snr'] - mixture = [] - for speaker in indata['speakers']: - spkid = speaker['spkid'] - utts = speaker['utts'] - intervals = speaker['intervals'] - rir = speaker['rir'] - data = [] - pos = 0 - for interval, utt in zip(intervals, utts): - # append silence interval data - silence = np.zeros(int(interval * args.rate)) - data.append(silence) - # utterance is reverberated using room impulse response - preprocess = "wav-reverberate --print-args=false " \ - " --impulse-response={} - -".format(rir) - if isinstance(utt, list): - rec, st, et = utt - st = np.rint(st * args.rate).astype(int) - et = np.rint(et * args.rate).astype(int) - else: - rec = utt - st = 0 - et = None - if rir is not None: - wav_rxfilename = kaldi_data.process_wav(rec, preprocess) - else: - wav_rxfilename = rec - wav_rxfilename = kaldi_data.process_wav( - wav_rxfilename, resample_cmd) - speech, _ = kaldi_data.load_wav(wav_rxfilename, st, et) - data.append(speech) - # calculate start/end position in samples - startpos = pos + len(silence) - endpos = startpos + len(speech) - # write segments and utt2spk - uttid = '{}_{}_{:07d}_{:07d}'.format( - spkid, recid, int(startpos / args.rate * 100), - int(endpos / args.rate * 100)) - print(uttid, recid, - startpos / args.rate, endpos / args.rate, file=segments_f) - print(uttid, spkid, file=utt2spk_f) - # update position for next utterance - pos = endpos - data = np.concatenate(data) - mixture.append(data) - - # fitting to the maximum-length speaker data, then mix all speakers - maxlen = max(len(x) for x in mixture) - mixture = [np.pad(x, (0, maxlen - len(x)), 'constant') for x in mixture] - mixture = np.sum(mixture, axis=0) - # noise is repeated or cutted for fitting to the mixture data length - noise_resampled = kaldi_data.process_wav(noise, resample_cmd) - noise_data, _ = kaldi_data.load_wav(noise_resampled) - if maxlen > len(noise_data): - noise_data = np.pad(noise_data, (0, maxlen - len(noise_data)), 'wrap') - else: - noise_data = noise_data[:maxlen] - # noise power is scaled according to selected SNR, then mixed - signal_power = np.sum(mixture**2) / len(mixture) - noise_power = np.sum(noise_data**2) / len(noise_data) - scale = math.sqrt( - math.pow(10, - noise_snr / 10) * signal_power / noise_power) - mixture += noise_data * scale - # output the wav file and write wav.scp - outfname = '{}.wav'.format(wavfn) - outpath = os.path.join(args.out_wav_dir, outfname) - sf.write(outpath, mixture, args.rate) - print(recid, os.path.abspath(outpath), file=wav_scp_f) - -wav_scp_f.close() -segments_f.close() -utt2spk_f.close() diff --git a/egs/callhome/TOLD/eend_ola/local/make_musan.py b/egs/callhome/TOLD/eend_ola/local/make_musan.py deleted file mode 100755 index 833da0619..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_musan.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2015 David Snyder -# 2018 Ewald Enzinger -# Apache 2.0. -# -# Modified version of egs/sre16/v1/local/make_musan.py (commit e3fb7c4a0da4167f8c94b80f4d3cc5ab4d0e22e8). -# This version uses the raw MUSAN audio files (16 kHz) and does not use sox to resample at 8 kHz. -# -# This file is meant to be invoked by make_musan.sh. - -import os, sys - -def process_music_annotations(path): - utt2spk = {} - utt2vocals = {} - lines = open(path, 'r').readlines() - for line in lines: - utt, genres, vocals, musician = line.rstrip().split()[:4] - # For this application, the musican ID isn't important - utt2spk[utt] = utt - utt2vocals[utt] = vocals == "Y" - return utt2spk, utt2vocals - -def prepare_music(root_dir, use_vocals): - utt2vocals = {} - utt2spk = {} - utt2wav = {} - num_good_files = 0 - num_bad_files = 0 - music_dir = os.path.join(root_dir, "music") - for root, dirs, files in os.walk(music_dir): - for file in files: - file_path = os.path.join(root, file) - if file.endswith(".wav"): - utt = str(file).replace(".wav", "") - utt2wav[utt] = file_path - elif str(file) == "ANNOTATIONS": - utt2spk_part, utt2vocals_part = process_music_annotations(file_path) - utt2spk.update(utt2spk_part) - utt2vocals.update(utt2vocals_part) - utt2spk_str = "" - utt2wav_str = "" - for utt in utt2vocals: - if utt in utt2wav: - if use_vocals or not utt2vocals[utt]: - utt2spk_str = utt2spk_str + utt + " " + utt2spk[utt] + "\n" - utt2wav_str = utt2wav_str + utt + " " + utt2wav[utt] + "\n" - num_good_files += 1 - else: - print("Missing file {}".format(utt)) - num_bad_files += 1 - print("In music directory, processed {} files: {} had missing wav data".format(num_good_files, num_bad_files)) - return utt2spk_str, utt2wav_str - -def prepare_speech(root_dir): - utt2spk = {} - utt2wav = {} - num_good_files = 0 - num_bad_files = 0 - speech_dir = os.path.join(root_dir, "speech") - for root, dirs, files in os.walk(speech_dir): - for file in files: - file_path = os.path.join(root, file) - if file.endswith(".wav"): - utt = str(file).replace(".wav", "") - utt2wav[utt] = file_path - utt2spk[utt] = utt - utt2spk_str = "" - utt2wav_str = "" - for utt in utt2spk: - if utt in utt2wav: - utt2spk_str = utt2spk_str + utt + " " + utt2spk[utt] + "\n" - utt2wav_str = utt2wav_str + utt + " " + utt2wav[utt] + "\n" - num_good_files += 1 - else: - print("Missing file {}".format(utt)) - num_bad_files += 1 - print("In speech directory, processed {} files: {} had missing wav data".format(num_good_files, num_bad_files)) - return utt2spk_str, utt2wav_str - -def prepare_noise(root_dir): - utt2spk = {} - utt2wav = {} - num_good_files = 0 - num_bad_files = 0 - noise_dir = os.path.join(root_dir, "noise") - for root, dirs, files in os.walk(noise_dir): - for file in files: - file_path = os.path.join(root, file) - if file.endswith(".wav"): - utt = str(file).replace(".wav", "") - utt2wav[utt] = file_path - utt2spk[utt] = utt - utt2spk_str = "" - utt2wav_str = "" - for utt in utt2spk: - if utt in utt2wav: - utt2spk_str = utt2spk_str + utt + " " + utt2spk[utt] + "\n" - utt2wav_str = utt2wav_str + utt + " " + utt2wav[utt] + "\n" - num_good_files += 1 - else: - print("Missing file {}".format(utt)) - num_bad_files += 1 - print("In noise directory, processed {} files: {} had missing wav data".format(num_good_files, num_bad_files)) - return utt2spk_str, utt2wav_str - -def main(): - in_dir = sys.argv[1] - out_dir = sys.argv[2] - use_vocals = sys.argv[3] == "Y" - utt2spk_music, utt2wav_music = prepare_music(in_dir, use_vocals) - utt2spk_speech, utt2wav_speech = prepare_speech(in_dir) - utt2spk_noise, utt2wav_noise = prepare_noise(in_dir) - utt2spk = utt2spk_speech + utt2spk_music + utt2spk_noise - utt2wav = utt2wav_speech + utt2wav_music + utt2wav_noise - wav_fi = open(os.path.join(out_dir, "wav.scp"), 'w') - wav_fi.write(utt2wav) - utt2spk_fi = open(os.path.join(out_dir, "utt2spk"), 'w') - utt2spk_fi.write(utt2spk) - - -if __name__=="__main__": - main() diff --git a/egs/callhome/TOLD/eend_ola/local/make_musan.sh b/egs/callhome/TOLD/eend_ola/local/make_musan.sh deleted file mode 100755 index 694940ad7..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_musan.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# Copyright 2015 David Snyder -# Apache 2.0. -# -# This script, called by ../run.sh, creates the MUSAN -# data directory. The required dataset is freely available at -# http://www.openslr.org/17/ - -set -e -in_dir=$1 -data_dir=$2 -use_vocals='Y' - -mkdir -p local/musan.tmp - -echo "Preparing ${data_dir}/musan..." -mkdir -p ${data_dir}/musan -local/make_musan.py ${in_dir} ${data_dir}/musan ${use_vocals} - -utils/fix_data_dir.sh ${data_dir}/musan - -grep "music" ${data_dir}/musan/utt2spk > local/musan.tmp/utt2spk_music -grep "speech" ${data_dir}/musan/utt2spk > local/musan.tmp/utt2spk_speech -grep "noise" ${data_dir}/musan/utt2spk > local/musan.tmp/utt2spk_noise -utils/subset_data_dir.sh --utt-list local/musan.tmp/utt2spk_music \ - ${data_dir}/musan ${data_dir}/musan_music -utils/subset_data_dir.sh --utt-list local/musan.tmp/utt2spk_speech \ - ${data_dir}/musan ${data_dir}/musan_speech -utils/subset_data_dir.sh --utt-list local/musan.tmp/utt2spk_noise \ - ${data_dir}/musan ${data_dir}/musan_noise - -utils/fix_data_dir.sh ${data_dir}/musan_music -utils/fix_data_dir.sh ${data_dir}/musan_speech -utils/fix_data_dir.sh ${data_dir}/musan_noise - -rm -rf local/musan.tmp - diff --git a/egs/callhome/TOLD/eend_ola/local/make_sre.pl b/egs/callhome/TOLD/eend_ola/local/make_sre.pl deleted file mode 100755 index b86fa7ee7..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_sre.pl +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/perl -# -# Copyright 2015 David Snyder -# Apache 2.0. -# Usage: make_sre.pl - -if (@ARGV != 4) { - print STDERR "Usage: $0 \n"; - print STDERR "e.g. $0 /export/corpora5/LDC/LDC2006S44 sre2004 sre_ref data/sre2004\n"; - exit(1); -} - -($db_base, $sre_name, $sre_ref_filename, $out_dir) = @ARGV; -%utt2sph = (); -%spk2gender = (); - -$tmp_dir = "$out_dir/tmp"; -if (system("mkdir -p $tmp_dir") != 0) { - die "Error making directory $tmp_dir"; -} - -if (system("find $db_base -name '*.sph' > $tmp_dir/sph.list") != 0) { - die "Error getting list of sph files"; -} -open(WAVLIST, "<", "$tmp_dir/sph.list") or die "cannot open wav list"; - -while() { - chomp; - $sph = $_; - @A1 = split("/",$sph); - @A2 = split("[./]",$A1[$#A1]); - $uttId=$A2[0]; - $utt2sph{$uttId} = $sph; -} - -open(GNDR,">", "$out_dir/spk2gender") or die "Could not open the output file $out_dir/spk2gender"; -open(SPKR,">", "$out_dir/utt2spk") or die "Could not open the output file $out_dir/utt2spk"; -open(WAV,">", "$out_dir/wav.scp") or die "Could not open the output file $out_dir/wav.scp"; -open(SRE_REF, "<", $sre_ref_filename) or die "Cannot open SRE reference."; -while () { - chomp; - ($speaker, $gender, $other_sre_name, $utt_id, $channel) = split(" ", $_); - $channel_num = "1"; - if ($channel eq "A") { - $channel_num = "1"; - } else { - $channel_num = "2"; - } - if (($other_sre_name eq $sre_name) and (exists $utt2sph{$utt_id})) { - $full_utt_id = "$speaker-$gender-$sre_name-$utt_id-$channel"; - $spk2gender{"$speaker-$gender"} = $gender; - print WAV "$full_utt_id"," sph2pipe -f wav -p -c $channel_num $utt2sph{$utt_id} |\n"; - print SPKR "$full_utt_id $speaker-$gender","\n"; - } -} -foreach $speaker (keys %spk2gender) { - print GNDR "$speaker $spk2gender{$speaker}\n"; -} - -close(GNDR) || die; -close(SPKR) || die; -close(WAV) || die; -close(SRE_REF) || die; diff --git a/egs/callhome/TOLD/eend_ola/local/make_sre.sh b/egs/callhome/TOLD/eend_ola/local/make_sre.sh deleted file mode 100755 index bef4e06e6..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_sre.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# Copyright 2015 David Snyder -# Apache 2.0. -# -# See README.txt for more info on data required. - -set -e - -data_root=$1 -data_dir=$2 - -wget -P data/local/ http://www.openslr.org/resources/15/speaker_list.tgz -tar -C data/local/ -xvf data/local/speaker_list.tgz -sre_ref=data/local/speaker_list - -local/make_sre.pl $data_root/LDC2006S44/ \ - sre2004 $sre_ref $data_dir/sre2004 - -local/make_sre.pl $data_root/LDC2011S01 \ - sre2005 $sre_ref $data_dir/sre2005_train - -local/make_sre.pl $data_root/LDC2011S04 \ - sre2005 $sre_ref $data_dir/sre2005_test - -local/make_sre.pl $data_root/LDC2011S09 \ - sre2006 $sre_ref $data_dir/sre2006_train - -local/make_sre.pl $data_root/LDC2011S10 \ - sre2006 $sre_ref $data_dir/sre2006_test_1 - -local/make_sre.pl $data_root/LDC2012S01 \ - sre2006 $sre_ref $data_dir/sre2006_test_2 - -local/make_sre.pl $data_root/LDC2011S05 \ - sre2008 $sre_ref $data_dir/sre2008_train - -local/make_sre.pl $data_root/LDC2011S08 \ - sre2008 $sre_ref $data_dir/sre2008_test - -utils/combine_data.sh $data_dir/sre \ - $data_dir/sre2004 $data_dir/sre2005_train \ - $data_dir/sre2005_test $data_dir/sre2006_train \ - $data_dir/sre2006_test_1 $data_dir/sre2006_test_2 \ - $data_dir/sre2008_train $data_dir/sre2008_test - -utils/validate_data_dir.sh --no-text --no-feats $data_dir/sre -utils/fix_data_dir.sh $data_dir/sre -rm data/local/speaker_list.* diff --git a/egs/callhome/TOLD/eend_ola/local/make_swbd2_phase1.pl b/egs/callhome/TOLD/eend_ola/local/make_swbd2_phase1.pl deleted file mode 100755 index 71b26b55d..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_swbd2_phase1.pl +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/perl -use warnings; #sed replacement for -w perl parameter -# -# Copyright 2017 David Snyder -# Apache 2.0 - -if (@ARGV != 2) { - print STDERR "Usage: $0 \n"; - print STDERR "e.g. $0 /export/corpora3/LDC/LDC98S75 data/swbd2_phase1_train\n"; - exit(1); -} -($db_base, $out_dir) = @ARGV; - -if (system("mkdir -p $out_dir")) { - die "Error making directory $out_dir"; -} - -open(CS, "<$db_base/doc/callstat.tbl") || die "Could not open $db_base/doc/callstat.tbl"; -open(GNDR, ">$out_dir/spk2gender") || die "Could not open the output file $out_dir/spk2gender"; -open(SPKR, ">$out_dir/utt2spk") || die "Could not open the output file $out_dir/utt2spk"; -open(WAV, ">$out_dir/wav.scp") || die "Could not open the output file $out_dir/wav.scp"; - -@badAudio = ("3", "4"); - -$tmp_dir = "$out_dir/tmp"; -if (system("mkdir -p $tmp_dir") != 0) { - die "Error making directory $tmp_dir"; -} - -if (system("find $db_base -name '*.sph' > $tmp_dir/sph.list") != 0) { - die "Error getting list of sph files"; -} - -open(WAVLIST, "<$tmp_dir/sph.list") or die "cannot open wav list"; - -%wavs = (); -while() { - chomp; - $sph = $_; - @t = split("/",$sph); - @t1 = split("[./]",$t[$#t]); - $uttId = $t1[0]; - $wavs{$uttId} = $sph; -} - -while () { - $line = $_ ; - @A = split(",", $line); - @A1 = split("[./]",$A[0]); - $wav = $A1[0]; - if (/$wav/i ~~ @badAudio) { - # do nothing - print "Bad Audio = $wav"; - } else { - $spkr1= "sw_" . $A[2]; - $spkr2= "sw_" . $A[3]; - $gender1 = $A[5]; - $gender2 = $A[6]; - if ($gender1 eq "M") { - $gender1 = "m"; - } elsif ($gender1 eq "F") { - $gender1 = "f"; - } else { - die "Unknown Gender in $line"; - } - if ($gender2 eq "M") { - $gender2 = "m"; - } elsif ($gender2 eq "F") { - $gender2 = "f"; - } else { - die "Unknown Gender in $line"; - } - if (-e "$wavs{$wav}") { - $uttId = $spkr1 ."_" . $wav ."_1"; - if (!$spk2gender{$spkr1}) { - $spk2gender{$spkr1} = $gender1; - print GNDR "$spkr1"," $gender1\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 1 $wavs{$wav} |\n"; - print SPKR "$uttId"," $spkr1","\n"; - - $uttId = $spkr2 . "_" . $wav ."_2"; - if (!$spk2gender{$spkr2}) { - $spk2gender{$spkr2} = $gender2; - print GNDR "$spkr2"," $gender2\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 2 $wavs{$wav} |\n"; - print SPKR "$uttId"," $spkr2","\n"; - } else { - print STDERR "Missing $wavs{$wav} for $wav\n"; - } - } -} - -close(WAV) || die; -close(SPKR) || die; -close(GNDR) || die; -if (system("utils/utt2spk_to_spk2utt.pl $out_dir/utt2spk >$out_dir/spk2utt") != 0) { - die "Error creating spk2utt file in directory $out_dir"; -} -if (system("utils/fix_data_dir.sh $out_dir") != 0) { - die "Error fixing data dir $out_dir"; -} -if (system("utils/validate_data_dir.sh --no-text --no-feats $out_dir") != 0) { - die "Error validating directory $out_dir"; -} diff --git a/egs/callhome/TOLD/eend_ola/local/make_swbd2_phase2.pl b/egs/callhome/TOLD/eend_ola/local/make_swbd2_phase2.pl deleted file mode 100755 index 337ab9d97..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_swbd2_phase2.pl +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/perl -use warnings; #sed replacement for -w perl parameter -# -# Copyright 2013 Daniel Povey -# Apache 2.0 - -if (@ARGV != 2) { - print STDERR "Usage: $0 \n"; - print STDERR "e.g. $0 /export/corpora5/LDC/LDC99S79 data/swbd2_phase2_train\n"; - exit(1); -} -($db_base, $out_dir) = @ARGV; - -if (system("mkdir -p $out_dir")) { - die "Error making directory $out_dir"; -} - -open(CS, "<$db_base/DISC1/doc/callstat.tbl") || die "Could not open $db_base/DISC1/doc/callstat.tbl"; -open(CI, "<$db_base/DISC1/doc/callinfo.tbl") || die "Could not open $db_base/DISC1/doc/callinfo.tbl"; -open(GNDR, ">$out_dir/spk2gender") || die "Could not open the output file $out_dir/spk2gender"; -open(SPKR, ">$out_dir/utt2spk") || die "Could not open the output file $out_dir/utt2spk"; -open(WAV, ">$out_dir/wav.scp") || die "Could not open the output file $out_dir/wav.scp"; - -@badAudio = ("3", "4"); - -$tmp_dir = "$out_dir/tmp"; -if (system("mkdir -p $tmp_dir") != 0) { - die "Error making directory $tmp_dir"; -} - -if (system("find $db_base -name '*.sph' > $tmp_dir/sph.list") != 0) { - die "Error getting list of sph files"; -} - -open(WAVLIST, "<$tmp_dir/sph.list") or die "cannot open wav list"; - -while() { - chomp; - $sph = $_; - @t = split("/",$sph); - @t1 = split("[./]",$t[$#t]); - $uttId=$t1[0]; - $wav{$uttId} = $sph; -} - -while () { - $line = $_ ; - $ci = ; - $ci = ; - @ci = split(",",$ci); - $wav = $ci[0]; - @A = split(",", $line); - if (/$wav/i ~~ @badAudio) { - # do nothing - } else { - $spkr1= "sw_" . $A[2]; - $spkr2= "sw_" . $A[3]; - $gender1 = $A[4]; - $gender2 = $A[5]; - if ($gender1 eq "M") { - $gender1 = "m"; - } elsif ($gender1 eq "F") { - $gender1 = "f"; - } else { - die "Unknown Gender in $line"; - } - if ($gender2 eq "M") { - $gender2 = "m"; - } elsif ($gender2 eq "F") { - $gender2 = "f"; - } else { - die "Unknown Gender in $line"; - } - if (-e "$wav{$wav}") { - $uttId = $spkr1 ."_" . $wav ."_1"; - if (!$spk2gender{$spkr1}) { - $spk2gender{$spkr1} = $gender1; - print GNDR "$spkr1"," $gender1\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 1 $wav{$wav} |\n"; - print SPKR "$uttId"," $spkr1","\n"; - - $uttId = $spkr2 . "_" . $wav ."_2"; - if (!$spk2gender{$spkr2}) { - $spk2gender{$spkr2} = $gender2; - print GNDR "$spkr2"," $gender2\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 2 $wav{$wav} |\n"; - print SPKR "$uttId"," $spkr2","\n"; - } else { - print STDERR "Missing $wav{$wav} for $wav\n"; - } - } -} - -close(WAV) || die; -close(SPKR) || die; -close(GNDR) || die; -if (system("utils/utt2spk_to_spk2utt.pl $out_dir/utt2spk >$out_dir/spk2utt") != 0) { - die "Error creating spk2utt file in directory $out_dir"; -} -if (system("utils/fix_data_dir.sh $out_dir") != 0) { - die "Error fixing data dir $out_dir"; -} -if (system("utils/validate_data_dir.sh --no-text --no-feats $out_dir") != 0) { - die "Error validating directory $out_dir"; -} diff --git a/egs/callhome/TOLD/eend_ola/local/make_swbd2_phase3.pl b/egs/callhome/TOLD/eend_ola/local/make_swbd2_phase3.pl deleted file mode 100755 index f27853415..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_swbd2_phase3.pl +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/perl -use warnings; #sed replacement for -w perl parameter -# -# Copyright 2013 Daniel Povey -# Apache 2.0 - -if (@ARGV != 2) { - print STDERR "Usage: $0 \n"; - print STDERR "e.g. $0 /export/corpora5/LDC/LDC2002S06 data/swbd2_phase3_train\n"; - exit(1); -} -($db_base, $out_dir) = @ARGV; - -if (system("mkdir -p $out_dir")) { - die "Error making directory $out_dir"; -} - -open(CS, "<$db_base/DISC1/docs/callstat.tbl") || die "Could not open $db_base/DISC1/docs/callstat.tbl"; -open(GNDR, ">$out_dir/spk2gender") || die "Could not open the output file $out_dir/spk2gender"; -open(SPKR, ">$out_dir/utt2spk") || die "Could not open the output file $out_dir/utt2spk"; -open(WAV, ">$out_dir/wav.scp") || die "Could not open the output file $out_dir/wav.scp"; - -@badAudio = ("3", "4"); - -$tmp_dir = "$out_dir/tmp"; -if (system("mkdir -p $tmp_dir") != 0) { - die "Error making directory $tmp_dir"; -} - -if (system("find $db_base -name '*.sph' > $tmp_dir/sph.list") != 0) { - die "Error getting list of sph files"; -} - -open(WAVLIST, "<$tmp_dir/sph.list") or die "cannot open wav list"; -while() { - chomp; - $sph = $_; - @t = split("/",$sph); - @t1 = split("[./]",$t[$#t]); - $uttId=$t1[0]; - $wav{$uttId} = $sph; -} - -while () { - $line = $_ ; - @A = split(",", $line); - $wav = "sw_" . $A[0] ; - if (/$wav/i ~~ @badAudio) { - # do nothing - } else { - $spkr1= "sw_" . $A[3]; - $spkr2= "sw_" . $A[4]; - $gender1 = $A[5]; - $gender2 = $A[6]; - if ($gender1 eq "M") { - $gender1 = "m"; - } elsif ($gender1 eq "F") { - $gender1 = "f"; - } else { - die "Unknown Gender in $line"; - } - if ($gender2 eq "M") { - $gender2 = "m"; - } elsif ($gender2 eq "F") { - $gender2 = "f"; - } else { - die "Unknown Gender in $line"; - } - if (-e "$wav{$wav}") { - $uttId = $spkr1 ."_" . $wav ."_1"; - if (!$spk2gender{$spkr1}) { - $spk2gender{$spkr1} = $gender1; - print GNDR "$spkr1"," $gender1\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 1 $wav{$wav} |\n"; - print SPKR "$uttId"," $spkr1","\n"; - - $uttId = $spkr2 . "_" . $wav ."_2"; - if (!$spk2gender{$spkr2}) { - $spk2gender{$spkr2} = $gender2; - print GNDR "$spkr2"," $gender2\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 2 $wav{$wav} |\n"; - print SPKR "$uttId"," $spkr2","\n"; - } else { - print STDERR "Missing $wav{$wav} for $wav\n"; - } - } -} - -close(WAV) || die; -close(SPKR) || die; -close(GNDR) || die; -if (system("utils/utt2spk_to_spk2utt.pl $out_dir/utt2spk >$out_dir/spk2utt") != 0) { - die "Error creating spk2utt file in directory $out_dir"; -} -if (system("utils/fix_data_dir.sh $out_dir") != 0) { - die "Error fixing data dir $out_dir"; -} -if (system("utils/validate_data_dir.sh --no-text --no-feats $out_dir") != 0) { - die "Error validating directory $out_dir"; -} diff --git a/egs/callhome/TOLD/eend_ola/local/make_swbd_cellular1.pl b/egs/callhome/TOLD/eend_ola/local/make_swbd_cellular1.pl deleted file mode 100644 index ede6cc2f9..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_swbd_cellular1.pl +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl -use warnings; #sed replacement for -w perl parameter -# -# Copyright 2013 Daniel Povey -# Apache 2.0 - -if (@ARGV != 2) { - print STDERR "Usage: $0 \n"; - print STDERR "e.g. $0 /export/corpora5/LDC/LDC2001S13 data/swbd_cellular1_train\n"; - exit(1); -} -($db_base, $out_dir) = @ARGV; - -if (system("mkdir -p $out_dir")) { - die "Error making directory $out_dir"; -} - -open(CS, "<$db_base/doc/swb_callstats.tbl") || die "Could not open $db_base/doc/swb_callstats.tbl"; -open(GNDR, ">$out_dir/spk2gender") || die "Could not open the output file $out_dir/spk2gender"; -open(SPKR, ">$out_dir/utt2spk") || die "Could not open the output file $out_dir/utt2spk"; -open(WAV, ">$out_dir/wav.scp") || die "Could not open the output file $out_dir/wav.scp"; - -@badAudio = ("40019", "45024", "40022"); - -while () { - $line = $_ ; - @A = split(",", $line); - if (/$A[0]/i ~~ @badAudio) { - # do nothing - } else { - $wav = "sw_" . $A[0]; - $spkr1= "sw_" . $A[1]; - $spkr2= "sw_" . $A[2]; - $gender1 = $A[3]; - $gender2 = $A[4]; - if ($A[3] eq "M") { - $gender1 = "m"; - } elsif ($A[3] eq "F") { - $gender1 = "f"; - } else { - die "Unknown Gender in $line"; - } - if ($A[4] eq "M") { - $gender2 = "m"; - } elsif ($A[4] eq "F") { - $gender2 = "f"; - } else { - die "Unknown Gender in $line"; - } - if (-e "$db_base/data/$wav.sph") { - $uttId = $spkr1 . "-swbdc_" . $wav ."_1"; - if (!$spk2gender{$spkr1}) { - $spk2gender{$spkr1} = $gender1; - print GNDR "$spkr1"," $gender1\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 1 $db_base/data/$wav.sph |\n"; - print SPKR "$uttId"," $spkr1","\n"; - - $uttId = $spkr2 . "-swbdc_" . $wav ."_2"; - if (!$spk2gender{$spkr2}) { - $spk2gender{$spkr2} = $gender2; - print GNDR "$spkr2"," $gender2\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 2 $db_base/data/$wav.sph |\n"; - print SPKR "$uttId"," $spkr2","\n"; - } else { - print STDERR "Missing $db_base/data/$wav.sph\n"; - } - } -} - -close(WAV) || die; -close(SPKR) || die; -close(GNDR) || die; -if (system("utils/utt2spk_to_spk2utt.pl $out_dir/utt2spk >$out_dir/spk2utt") != 0) { - die "Error creating spk2utt file in directory $out_dir"; -} -if (system("utils/fix_data_dir.sh $out_dir") != 0) { - die "Error fixing data dir $out_dir"; -} -if (system("utils/validate_data_dir.sh --no-text --no-feats $out_dir") != 0) { - die "Error validating directory $out_dir"; -} diff --git a/egs/callhome/TOLD/eend_ola/local/make_swbd_cellular2.pl b/egs/callhome/TOLD/eend_ola/local/make_swbd_cellular2.pl deleted file mode 100755 index 4de954c19..000000000 --- a/egs/callhome/TOLD/eend_ola/local/make_swbd_cellular2.pl +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl -use warnings; #sed replacement for -w perl parameter -# -# Copyright 2013 Daniel Povey -# Apache 2.0 - -if (@ARGV != 2) { - print STDERR "Usage: $0 \n"; - print STDERR "e.g. $0 /export/corpora5/LDC/LDC2004S07 data/swbd_cellular2_train\n"; - exit(1); -} -($db_base, $out_dir) = @ARGV; - -if (system("mkdir -p $out_dir")) { - die "Error making directory $out_dir"; -} - -open(CS, "<$db_base/docs/swb_callstats.tbl") || die "Could not open $db_base/docs/swb_callstats.tbl"; -open(GNDR, ">$out_dir/spk2gender") || die "Could not open the output file $out_dir/spk2gender"; -open(SPKR, ">$out_dir/utt2spk") || die "Could not open the output file $out_dir/utt2spk"; -open(WAV, ">$out_dir/wav.scp") || die "Could not open the output file $out_dir/wav.scp"; - -@badAudio=("45024", "40022"); - -while () { - $line = $_ ; - @A = split(",", $line); - if (/$A[0]/i ~~ @badAudio) { - # do nothing - } else { - $wav = "sw_" . $A[0]; - $spkr1= "sw_" . $A[1]; - $spkr2= "sw_" . $A[2]; - $gender1 = $A[3]; - $gender2 = $A[4]; - if ($A[3] eq "M") { - $gender1 = "m"; - } elsif ($A[3] eq "F") { - $gender1 = "f"; - } else { - die "Unknown Gender in $line"; - } - if ($A[4] eq "M") { - $gender2 = "m"; - } elsif ($A[4] eq "F") { - $gender2 = "f"; - } else { - die "Unknown Gender in $line"; - } - if (-e "$db_base/data/$wav.sph") { - $uttId = $spkr1 . "-swbdc_" . $wav ."_1"; - if (!$spk2gender{$spkr1}) { - $spk2gender{$spkr1} = $gender1; - print GNDR "$spkr1"," $gender1\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 1 $db_base/data/$wav.sph |\n"; - print SPKR "$uttId"," $spkr1","\n"; - - $uttId = $spkr2 . "-swbdc_" . $wav ."_2"; - if (!$spk2gender{$spkr2}) { - $spk2gender{$spkr2} = $gender2; - print GNDR "$spkr2"," $gender2\n"; - } - print WAV "$uttId"," sph2pipe -f wav -p -c 2 $db_base/data/$wav.sph |\n"; - print SPKR "$uttId"," $spkr2","\n"; - } else { - print STDERR "Missing $db_base/data/$wav.sph\n"; - } - } -} - -close(WAV) || die; -close(SPKR) || die; -close(GNDR) || die; -if (system("utils/utt2spk_to_spk2utt.pl $out_dir/utt2spk >$out_dir/spk2utt") != 0) { - die "Error creating spk2utt file in directory $out_dir"; -} -if (system("utils/fix_data_dir.sh $out_dir") != 0) { - die "Error fixing data dir $out_dir"; -} -if (system("utils/validate_data_dir.sh --no-text --no-feats $out_dir") != 0) { - die "Error validating directory $out_dir"; -} diff --git a/egs/callhome/TOLD/eend_ola/local/model_averaging.py b/egs/callhome/TOLD/eend_ola/local/model_averaging.py deleted file mode 100755 index 1871cd9cb..000000000 --- a/egs/callhome/TOLD/eend_ola/local/model_averaging.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 - -import argparse - -import torch - - -def average_model(input_files, output_file): - output_model = {} - for ckpt_path in input_files: - model_params = torch.load(ckpt_path, map_location="cpu") - for key, value in model_params.items(): - if key not in output_model: - output_model[key] = value - else: - output_model[key] += value - for key in output_model.keys(): - output_model[key] /= len(input_files) - torch.save(output_model, output_file) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("output_file") - parser.add_argument("input_files", nargs='+') - args = parser.parse_args() - - average_model(args.input_files, args.output_file) \ No newline at end of file diff --git a/egs/callhome/TOLD/eend_ola/local/parse_options.sh b/egs/callhome/TOLD/eend_ola/local/parse_options.sh deleted file mode 100755 index 71fb9e5ea..000000000 --- a/egs/callhome/TOLD/eend_ola/local/parse_options.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2012 Johns Hopkins University (Author: Daniel Povey); -# Arnab Ghoshal, Karel Vesely - -# 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 -# -# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -# MERCHANTABLITY OR NON-INFRINGEMENT. -# See the Apache 2 License for the specific language governing permissions and -# limitations under the License. - - -# Parse command-line options. -# To be sourced by another script (as in ". parse_options.sh"). -# Option format is: --option-name arg -# and shell variable "option_name" gets set to value "arg." -# The exception is --help, which takes no arguments, but prints the -# $help_message variable (if defined). - - -### -### The --config file options have lower priority to command line -### options, so we need to import them first... -### - -# Now import all the configs specified by command-line, in left-to-right order -for ((argpos=1; argpos<$#; argpos++)); do - if [ "${!argpos}" == "--config" ]; then - argpos_plus1=$((argpos+1)) - config=${!argpos_plus1} - [ ! -r $config ] && echo "$0: missing config '$config'" && exit 1 - . $config # source the config file. - fi -done - - -### -### Now we process the command line options -### -while true; do - [ -z "${1:-}" ] && break; # break if there are no arguments - case "$1" in - # If the enclosing script is called with --help option, print the help - # message and exit. Scripts should put help messages in $help_message - --help|-h) if [ -z "$help_message" ]; then echo "No help found." 1>&2; - else printf "$help_message\n" 1>&2 ; fi; - exit 0 ;; - --*=*) echo "$0: options to scripts must be of the form --name value, got '$1'" - exit 1 ;; - # If the first command-line argument begins with "--" (e.g. --foo-bar), - # then work out the variable name as $name, which will equal "foo_bar". - --*) name=`echo "$1" | sed s/^--// | sed s/-/_/g`; - # Next we test whether the variable in question is undefned-- if so it's - # an invalid option and we die. Note: $0 evaluates to the name of the - # enclosing script. - # The test [ -z ${foo_bar+xxx} ] will return true if the variable foo_bar - # is undefined. We then have to wrap this test inside "eval" because - # foo_bar is itself inside a variable ($name). - eval '[ -z "${'$name'+xxx}" ]' && echo "$0: invalid option $1" 1>&2 && exit 1; - - oldval="`eval echo \\$$name`"; - # Work out whether we seem to be expecting a Boolean argument. - if [ "$oldval" == "true" ] || [ "$oldval" == "false" ]; then - was_bool=true; - else - was_bool=false; - fi - - # Set the variable to the right value-- the escaped quotes make it work if - # the option had spaces, like --cmd "queue.pl -sync y" - eval $name=\"$2\"; - - # Check that Boolean-valued arguments are really Boolean. - if $was_bool && [[ "$2" != "true" && "$2" != "false" ]]; then - echo "$0: expected \"true\" or \"false\": $1 $2" 1>&2 - exit 1; - fi - shift 2; - ;; - *) break; - esac -done - - -# Check for an empty argument to the --cmd option, which can easily occur as a -# result of scripting errors. -[ ! -z "${cmd+xxx}" ] && [ -z "$cmd" ] && echo "$0: empty argument to --cmd option" 1>&2 && exit 1; - - -true; # so this script returns exit code 0. diff --git a/egs/callhome/TOLD/eend_ola/local/random_mixture.py b/egs/callhome/TOLD/eend_ola/local/random_mixture.py deleted file mode 100755 index 05d782845..000000000 --- a/egs/callhome/TOLD/eend_ola/local/random_mixture.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2019 Hitachi, Ltd. (author: Yusuke Fujita) -# Licensed under the MIT license. - -""" -This script generates random multi-talker mixtures for diarization. -It generates a scp-like outputs: lines of "[recid] [json]". - recid: recording id of mixture - serial numbers like mix_0000001, mix_0000002, ... - json: mixture configuration formatted in "one-line" -The json format is as following: -{ - 'speakers':[ # list of speakers - { - 'spkid': 'Name', # speaker id - 'rir': '/rirdir/rir.wav', # wav_rxfilename of room impulse response - 'utts': [ # list of wav_rxfilenames of utterances - '/wavdir/utt1.wav', - '/wavdir/utt2.wav',...], - 'intervals': [1.2, 3.4, ...] # list of silence durations before utterances - }, ... ], - 'noise': '/noisedir/noise.wav' # wav_rxfilename of background noise - 'snr': 15.0, # SNR for mixing background noise - 'recid': 'mix_000001' # recording id of the mixture -} - -Usage: - common/random_mixture.py \ - --n_mixtures=10000 \ # number of mixtures - data/voxceleb1_train \ # kaldi-style data dir of utterances - data/musan_noise_bg \ # background noises - data/simu_rirs \ # room impulse responses - > mixture.scp # output scp-like file - -The actual data dir and wav files are generated using make_mixture.py: - common/make_mixture.py \ - mixture.scp \ # scp-like file for mixture - data/mixture \ # output data dir - wav/mixture # output wav dir -""" - -import argparse -import os -from funasr.modules.eend_ola.utils import kaldi_data -import random -import numpy as np -import json -import itertools - -parser = argparse.ArgumentParser() -parser.add_argument('data_dir', - help='data dir of single-speaker recordings') -parser.add_argument('noise_dir', - help='data dir of background noise recordings') -parser.add_argument('rir_dir', - help='data dir of room impulse responses') -parser.add_argument('--n_mixtures', type=int, default=10, - help='number of mixture recordings') -parser.add_argument('--n_speakers', type=int, default=4, - help='number of speakers in a mixture') -parser.add_argument('--min_utts', type=int, default=10, - help='minimum number of uttenraces per speaker') -parser.add_argument('--max_utts', type=int, default=20, - help='maximum number of utterances per speaker') -parser.add_argument('--sil_scale', type=float, default=10.0, - help='average silence time') -parser.add_argument('--noise_snrs', default="10:15:20", - help='colon-delimited SNRs for background noises') -parser.add_argument('--random_seed', type=int, default=777, - help='random seed') -parser.add_argument('--speech_rvb_probability', type=float, default=1, - help='reverb probability') -args = parser.parse_args() - -random.seed(args.random_seed) -np.random.seed(args.random_seed) - -# load list of wav files from kaldi-style data dirs -wavs = kaldi_data.load_wav_scp( - os.path.join(args.data_dir, 'wav.scp')) -noises = kaldi_data.load_wav_scp( - os.path.join(args.noise_dir, 'wav.scp')) -rirs = kaldi_data.load_wav_scp( - os.path.join(args.rir_dir, 'wav.scp')) - -# spk2utt is used for counting number of utterances per speaker -spk2utt = kaldi_data.load_spk2utt( - os.path.join(args.data_dir, 'spk2utt')) - -segments = kaldi_data.load_segments_hash( - os.path.join(args.data_dir, 'segments')) - -# choice lists for random sampling -all_speakers = list(spk2utt.keys()) -all_noises = list(noises.keys()) -all_rirs = list(rirs.keys()) -noise_snrs = [float(x) for x in args.noise_snrs.split(':')] - -mixtures = [] -for it in range(args.n_mixtures): - # recording ids are mix_0000001, mix_0000002, ... - recid = 'mix_{:07d}'.format(it + 1) - # randomly select speakers, a background noise and a SNR - speakers = random.sample(all_speakers, args.n_speakers) - noise = random.choice(all_noises) - noise_snr = random.choice(noise_snrs) - mixture = {'speakers': []} - for speaker in speakers: - # randomly select the number of utterances - n_utts = np.random.randint(args.min_utts, args.max_utts + 1) - # utts = spk2utt[speaker][:n_utts] - cycle_utts = itertools.cycle(spk2utt[speaker]) - # random start utterance - roll = np.random.randint(0, len(spk2utt[speaker])) - for i in range(roll): - next(cycle_utts) - utts = [next(cycle_utts) for i in range(n_utts)] - # randomly select wait time before appending utterance - intervals = np.random.exponential(args.sil_scale, size=n_utts) - # randomly select a room impulse response - if random.random() < args.speech_rvb_probability: - rir = rirs[random.choice(all_rirs)] - else: - rir = None - if segments is not None: - utts = [segments[utt] for utt in utts] - utts = [(wavs[rec], st, et) for (rec, st, et) in utts] - mixture['speakers'].append({ - 'spkid': speaker, - 'rir': rir, - 'utts': utts, - 'intervals': intervals.tolist() - }) - else: - mixture['speakers'].append({ - 'spkid': speaker, - 'rir': rir, - 'utts': [wavs[utt] for utt in utts], - 'intervals': intervals.tolist() - }) - mixture['noise'] = noises[noise] - mixture['snr'] = noise_snr - mixture['recid'] = recid - print(recid, json.dumps(mixture)) diff --git a/egs/callhome/TOLD/eend_ola/local/run_prepare_shared_eda.sh b/egs/callhome/TOLD/eend_ola/local/run_prepare_shared_eda.sh deleted file mode 100755 index f1019d60b..000000000 --- a/egs/callhome/TOLD/eend_ola/local/run_prepare_shared_eda.sh +++ /dev/null @@ -1,235 +0,0 @@ -#!/bin/bash - -# Copyright 2019 Hitachi, Ltd. (author: Yusuke Fujita, Shota Horiguchi) -# Licensed under the MIT license. -# -# This script prepares kaldi-style data sets shared with different experiments -# - data/xxxx -# callhome, sre, swb2, and swb_cellular datasets -# - data/simu_${simu_outputs} -# simulation mixtures generated with various options - -stage=0 - -# Modify corpus directories -# - callhome_dir -# CALLHOME (LDC2001S97) -# - swb2_phase1_train -# Switchboard-2 Phase 1 (LDC98S75) -# - data_root -# LDC99S79, LDC2002S06, LDC2001S13, LDC2004S07, -# LDC2006S44, LDC2011S01, LDC2011S04, LDC2011S09, -# LDC2011S10, LDC2012S01, LDC2011S05, LDC2011S08 -# - musan_root -# MUSAN corpus (https://www.openslr.org/17/) -callhome_dir= -swb2_phase1_train= -data_root= -musan_root= -# Modify simulated data storage area. -# This script distributes simulated data under these directories -simu_actual_dirs=( -./s05/$USER/diarization-data -./s08/$USER/diarization-data -./s09/$USER/diarization-data -) - -# data preparation options -max_jobs_run=4 -sad_num_jobs=30 -sad_opts="--extra-left-context 79 --extra-right-context 21 --frames-per-chunk 150 --extra-left-context-initial 0 --extra-right-context-final 0 --acwt 0.3" -sad_graph_opts="--min-silence-duration=0.03 --min-speech-duration=0.3 --max-speech-duration=10.0" -sad_priors_opts="--sil-scale=0.1" - -# simulation options -simu_opts_overlap=yes -simu_opts_num_speaker_array=(1 2 3 4) -simu_opts_sil_scale_array=(2 2 5 9) -simu_opts_rvb_prob=0.5 -simu_opts_num_train=100000 -simu_opts_min_utts=10 -simu_opts_max_utts=20 - -simu_cmd="run.pl" -train_cmd="run.pl" -random_mixture_cmd="run.pl" -make_mixture_cmd="run.pl" - -. parse_options.sh || exit - -if [ $stage -le 0 ]; then - echo "prepare kaldi-style datasets" - # Prepare CALLHOME dataset. This will be used to evaluation. - if ! validate_data_dir.sh --no-text --no-feats data/callhome1_spkall \ - || ! validate_data_dir.sh --no-text --no-feats data/callhome2_spkall; then - # imported from https://github.com/kaldi-asr/kaldi/blob/master/egs/callhome_diarization/v1 - local/make_callhome.sh $callhome_dir data - # Generate two-speaker subsets - for dset in callhome1 callhome2; do - # Extract two-speaker recordings in wav.scp - copy_data_dir.sh data/${dset} data/${dset}_spkall - # Regenerate segments file from fullref.rttm - # $2: recid, $4: start_time, $5: duration, $8: speakerid - awk '{printf "%s_%s_%07d_%07d %s %.2f %.2f\n", \ - $2, $8, $4*100, ($4+$5)*100, $2, $4, $4+$5}' \ - data/callhome/fullref.rttm | sort > data/${dset}_spkall/segments - utils/fix_data_dir.sh data/${dset}_spkall - # Speaker ID is '[recid]_[speakerid] - awk '{split($1,A,"_"); printf "%s %s_%s\n", $1, A[1], A[2]}' \ - data/${dset}_spkall/segments > data/${dset}_spkall/utt2spk - utils/fix_data_dir.sh data/${dset}_spkall - # Generate rttm files for scoring - steps/segmentation/convert_utt2spk_and_segments_to_rttm.py \ - data/${dset}_spkall/utt2spk data/${dset}_spkall/segments \ - data/${dset}_spkall/rttm - utils/data/get_reco2dur.sh data/${dset}_spkall - done - fi - # Prepare a collection of NIST SRE and SWB data. This will be used to train, - if ! validate_data_dir.sh --no-text --no-feats data/swb_sre_comb; then - local/make_sre.sh $data_root data - # Prepare SWB for x-vector DNN training. - local/make_swbd2_phase1.pl $swb2_phase1_train \ - data/swbd2_phase1_train - local/make_swbd2_phase2.pl $data_root/LDC99S79 \ - data/swbd2_phase2_train - local/make_swbd2_phase3.pl $data_root/LDC2002S06 \ - data/swbd2_phase3_train - local/make_swbd_cellular1.pl $data_root/LDC2001S13 \ - data/swbd_cellular1_train - local/make_swbd_cellular2.pl $data_root/LDC2004S07 \ - data/swbd_cellular2_train - # Combine swb and sre data - utils/combine_data.sh data/swb_sre_comb \ - data/swbd_cellular1_train data/swbd_cellular2_train \ - data/swbd2_phase1_train \ - data/swbd2_phase2_train data/swbd2_phase3_train data/sre - fi - # musan data. "back-ground - if ! validate_data_dir.sh --no-text --no-feats data/musan_noise_bg; then - local/make_musan.sh $musan_root data - utils/copy_data_dir.sh data/musan_noise data/musan_noise_bg - awk '{if(NR>1) print $1,$1}' $musan_root/noise/free-sound/ANNOTATIONS > data/musan_noise_bg/utt2spk - utils/fix_data_dir.sh data/musan_noise_bg - fi - # simu rirs 8k - if ! validate_data_dir.sh --no-text --no-feats data/simu_rirs_8k; then - mkdir -p data/simu_rirs_8k -# if [ ! -e sim_rir_8k.zip ]; then -# wget --no-check-certificate http://www.openslr.org/resources/26/sim_rir_8k.zip -# fi - unzip sim_rir_8k.zip -d data/sim_rir_8k - find $PWD/data/sim_rir_8k -iname "*.wav" \ - | awk '{n=split($1,A,/[\/\.]/); print A[n-3]"_"A[n-1], $1}' \ - | sort > data/simu_rirs_8k/wav.scp - awk '{print $1, $1}' data/simu_rirs_8k/wav.scp > data/simu_rirs_8k/utt2spk - utils/fix_data_dir.sh data/simu_rirs_8k - fi - # Automatic segmentation using pretrained SAD model - # it will take one day using 30 CPU jobs: - # make_mfcc: 1 hour, compute_output: 18 hours, decode: 0.5 hours - sad_nnet_dir=exp/segmentation_1a/tdnn_stats_asr_sad_1a - sad_work_dir=exp/segmentation_1a/tdnn_stats_asr_sad_1a - if ! validate_data_dir.sh --no-text $sad_work_dir/swb_sre_comb_seg; then - if [ ! -d exp/segmentation_1a ]; then -# wget http://kaldi-asr.org/models/4/0004_tdnn_stats_asr_sad_1a.tar.gz - tar zxf 0004_tdnn_stats_asr_sad_1a.tar.gz - fi - steps/segmentation/detect_speech_activity.sh \ - --nj $sad_num_jobs \ - --graph-opts "$sad_graph_opts" \ - --transform-probs-opts "$sad_priors_opts" $sad_opts \ - data/swb_sre_comb $sad_nnet_dir mfcc_hires $sad_work_dir \ - $sad_work_dir/swb_sre_comb || exit 1 - fi - # Extract >1.5 sec segments and split into train/valid sets - if ! validate_data_dir.sh --no-text --no-feats data/swb_sre_cv; then - copy_data_dir.sh data/swb_sre_comb data/swb_sre_comb_seg - awk '$4-$3>1.5{print;}' $sad_work_dir/swb_sre_comb_seg/segments > data/swb_sre_comb_seg/segments - cp $sad_work_dir/swb_sre_comb_seg/{utt2spk,spk2utt} data/swb_sre_comb_seg - fix_data_dir.sh data/swb_sre_comb_seg - utils/subset_data_dir_tr_cv.sh data/swb_sre_comb_seg data/swb_sre_tr data/swb_sre_cv - fi -fi - -simudir=data/simu -if [ $stage -le 1 ]; then - echo "simulation of mixture" - mkdir -p $simudir/.work - random_mixture_cmd=local/random_mixture.py - make_mixture_cmd=local/make_mixture.py - - for ((i=0; i<${#simu_opts_sil_scale_array[@]}; ++i)); do - simu_opts_num_speaker=${simu_opts_num_speaker_array[i]} - simu_opts_sil_scale=${simu_opts_sil_scale_array[i]} - for dset in swb_sre_tr swb_sre_cv; do - if [ "$dset" == "swb_sre_tr" ]; then - n_mixtures=${simu_opts_num_train} - else - n_mixtures=500 - fi - simuid=${dset}_ns${simu_opts_num_speaker}_beta${simu_opts_sil_scale}_${n_mixtures} - # check if you have the simulation - if ! validate_data_dir.sh --no-text --no-feats $simudir/data/$simuid; then - # random mixture generation - $train_cmd $simudir/.work/random_mixture_$simuid.log \ - $random_mixture_cmd --n_speakers $simu_opts_num_speaker --n_mixtures $n_mixtures \ - --speech_rvb_probability $simu_opts_rvb_prob \ - --sil_scale $simu_opts_sil_scale \ - data/$dset data/musan_noise_bg data/simu_rirs_8k \ - \> $simudir/.work/mixture_$simuid.scp - nj=64 - mkdir -p $simudir/wav/$simuid - # distribute simulated data to $simu_actual_dir - split_scps= - for n in $(seq $nj); do - split_scps="$split_scps $simudir/.work/mixture_$simuid.$n.scp" - mkdir -p $simudir/.work/data_$simuid.$n - actual=${simu_actual_dirs[($n-1)%${#simu_actual_dirs[@]}]}/$simudir/wav/$simuid/$n - mkdir -p $actual - ln -nfs $actual $simudir/wav/$simuid/$n - done - utils/split_scp.pl $simudir/.work/mixture_$simuid.scp $split_scps || exit 1 - - $simu_cmd --max-jobs-run 64 JOB=1:$nj $simudir/.work/make_mixture_$simuid.JOB.log \ - $make_mixture_cmd --rate=8000 \ - $simudir/.work/mixture_$simuid.JOB.scp \ - $simudir/.work/data_$simuid.JOB $simudir/wav/$simuid/JOB - utils/combine_data.sh $simudir/data/$simuid $simudir/.work/data_$simuid.* - steps/segmentation/convert_utt2spk_and_segments_to_rttm.py \ - $simudir/data/$simuid/utt2spk $simudir/data/$simuid/segments \ - $simudir/data/$simuid/rttm - utils/data/get_reco2dur.sh $simudir/data/$simuid - fi - simuid_concat=${dset}_ns"$(IFS="n"; echo "${simu_opts_num_speaker_array[*]}")"_beta"$(IFS="n"; echo "${simu_opts_sil_scale_array[*]}")"_${n_mixtures} - mkdir -p $simudir/data/$simuid_concat - for f in `ls -F $simudir/data/$simuid | grep -v "/"`; do - cat $simudir/data/$simuid/$f >> $simudir/data/$simuid_concat/$f - done - done - done -fi - -if [ $stage -le 3 ]; then - # compose eval/callhome2_spkall - eval_set=data/eval/callhome2_spkall - if ! validate_data_dir.sh --no-text --no-feats $eval_set; then - utils/copy_data_dir.sh data/callhome2_spkall $eval_set - cp data/callhome2_spkall/rttm $eval_set/rttm - awk -v dstdir=wav/eval/callhome2_spkall '{print $1, dstdir"/"$1".wav"}' data/callhome2_spkall/wav.scp > $eval_set/wav.scp - mkdir -p wav/eval/callhome2_spkall - wav-copy scp:data/callhome2_spkall/wav.scp scp:$eval_set/wav.scp - utils/data/get_reco2dur.sh $eval_set - fi - - # compose eval/callhome1_spkall - adapt_set=data/eval/callhome1_spkall - if ! validate_data_dir.sh --no-text --no-feats $adapt_set; then - utils/copy_data_dir.sh data/callhome1_spkall $adapt_set - cp data/callhome1_spkall/rttm $adapt_set/rttm - awk -v dstdir=wav/eval/callhome1_spkall '{print $1, dstdir"/"$1".wav"}' data/callhome1_spkall/wav.scp > $adapt_set/wav.scp - mkdir -p wav/eval/callhome1_spkall - wav-copy scp:data/callhome1_spkall/wav.scp scp:$adapt_set/wav.scp - utils/data/get_reco2dur.sh $adapt_set - fi -fi diff --git a/egs/callhome/TOLD/eend_ola/local/split.py b/egs/callhome/TOLD/eend_ola/local/split.py deleted file mode 100644 index 7ad1badd4..000000000 --- a/egs/callhome/TOLD/eend_ola/local/split.py +++ /dev/null @@ -1,117 +0,0 @@ -import argparse -import os - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('root_path', help='raw data path') - args = parser.parse_args() - - root_path = args.root_path - work_path = os.path.join(root_path, ".work") - scp_files = os.listdir(work_path) - - reco2dur_dict = {} - with open(os.path.join(root_path, 'reco2dur')) as f: - lines = f.readlines() - for line in lines: - parts = line.strip().split() - reco2dur_dict[parts[0]] = parts[1] - - spk2utt_dict = {} - with open(os.path.join(root_path, 'spk2utt')) as f: - lines = f.readlines() - for line in lines: - parts = line.strip().split() - spk = parts[0] - utts = parts[1:] - for utt in utts: - tmp = utt.split('data') - rec = 'data_' + '_'.join(tmp[1][1:].split('_')[:-2]) - if rec in spk2utt_dict.keys(): - spk2utt_dict[rec].append((spk, utt)) - else: - spk2utt_dict[rec] = [] - spk2utt_dict[rec].append((spk, utt)) - - segment_dict = {} - with open(os.path.join(root_path, 'segments')) as f: - lines = f.readlines() - for line in lines: - parts = line.strip().split() - if parts[1] in segment_dict.keys(): - segment_dict[parts[1]].append((parts[0], parts[2], parts[3])) - else: - segment_dict[parts[1]] = [] - segment_dict[parts[1]].append((parts[0], parts[2], parts[3])) - - utt2spk_dict = {} - with open(os.path.join(root_path, 'utt2spk')) as f: - lines = f.readlines() - for line in lines: - parts = line.strip().split() - utt = parts[0] - tmp = utt.split('data') - rec = 'data_' + '_'.join(tmp[1][1:].split('_')[:-2]) - if rec in utt2spk_dict.keys(): - utt2spk_dict[rec].append((parts[0], parts[1])) - else: - utt2spk_dict[rec] = [] - utt2spk_dict[rec].append((parts[0], parts[1])) - - for file in scp_files: - scp_file = os.path.join(work_path, file) - idx = scp_file.split('.')[-1] - reco2dur_file = os.path.join(work_path, 'reco2dur.{}'.format(str(idx))) - spk2utt_file = os.path.join(work_path, 'spk2utt.{}'.format(str(idx))) - segment_file = os.path.join(work_path, 'segments.{}'.format(str(idx))) - utt2spk_file = os.path.join(work_path, 'utt2spk.{}'.format(str(idx))) - - fpp = open(scp_file) - scp_lines = fpp.readlines() - keys = [] - for line in scp_lines: - name = line.strip().split()[0] - keys.append(name) - - with open(reco2dur_file, 'w') as f: - lines = [] - for key in keys: - string = key + ' ' + reco2dur_dict[key] - lines.append(string + '\n') - lines[-1] = lines[-1][:-1] - f.writelines(lines) - - with open(spk2utt_file, 'w') as f: - lines = [] - for key in keys: - items = spk2utt_dict[key] - for item in items: - string = item[0] - for it in item[1:]: - string += ' ' - string += it - lines.append(string + '\n') - lines[-1] = lines[-1][:-1] - f.writelines(lines) - - with open(segment_file, 'w') as f: - lines = [] - for key in keys: - items = segment_dict[key] - for item in items: - string = item[0] + ' ' + key + ' ' + item[1] + ' ' + item[2] - lines.append(string + '\n') - lines[-1] = lines[-1][:-1] - f.writelines(lines) - - with open(utt2spk_file, 'w') as f: - lines = [] - for key in keys: - items = utt2spk_dict[key] - for item in items: - string = item[0] + ' ' + item[1] - lines.append(string + '\n') - lines[-1] = lines[-1][:-1] - f.writelines(lines) - - fpp.close() diff --git a/egs/callhome/TOLD/eend_ola/path.sh b/egs/callhome/TOLD/eend_ola/path.sh deleted file mode 100755 index e1906b741..000000000 --- a/egs/callhome/TOLD/eend_ola/path.sh +++ /dev/null @@ -1,13 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# kaldi-related -export KALDI_ROOT= -[ -f $KALDI_ROOT/tools/env.sh ] && . $KALDI_ROOT/tools/env.sh -export PATH=$PWD/utils/:$KALDI_ROOT/tools/openfst/bin:$KALDI_ROOT/tools/sph2pipe_v2.5:$KALDI_ROOT/tools/sctk/bin:$PWD:$PATH -[ ! -f $KALDI_ROOT/tools/config/common_path.sh ] && echo >&2 "The standard file $KALDI_ROOT/tools/config/common_path.sh is not present -> Exit!" && exit 1 -. $KALDI_ROOT/tools/config/common_path.sh - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PYTHONPATH=../../../:$PYTHONPATH -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/callhome/TOLD/eend_ola/run.sh b/egs/callhome/TOLD/eend_ola/run.sh deleted file mode 100644 index aa441bfcb..000000000 --- a/egs/callhome/TOLD/eend_ola/run.sh +++ /dev/null @@ -1,324 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0" -gpu_num=$(echo $CUDA_VISIBLE_DEVICES | awk -F "," '{print NF}') -count=1 - -# general configuration -dump_cmd=utils/run.pl -nj=64 - -# feature configuration -data_dir="./data" -simu_feats_dir=$data_dir/ark_data/dump/simu_data/data -simu_feats_dir_chunk2000=$data_dir/ark_data/dump/simu_data_chunk2000/data -callhome_feats_dir_chunk2000=$data_dir/ark_data/dump/callhome_chunk2000/data -simu_train_dataset=train -simu_valid_dataset=dev -callhome_train_dataset=callhome1_spkall -callhome_valid_dataset=callhome2_spkall - -# model average -simu_average_2spkr_start=91 -simu_average_2spkr_end=100 -simu_average_allspkr_start=16 -simu_average_allspkr_end=25 -callhome_average_start=91 -callhome_average_end=100 - -exp_dir="." -input_size=345 -stage=1 -stop_stage=5 - -# exp tag -tag="exp1" - -. local/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -simu_2spkr_diar_config=conf/train_diar_eend_ola_simu_2spkr.yaml -simu_allspkr_diar_config=conf/train_diar_eend_ola_simu_allspkr.yaml -simu_allspkr_chunk2000_diar_config=conf/train_diar_eend_ola_simu_allspkr_chunk2000.yaml -callhome_diar_config=conf/train_diar_eend_ola_callhome_chunk2000.yaml -simu_2spkr_model_dir="baseline_$(basename "${simu_2spkr_diar_config}" .yaml)_${tag}" -simu_allspkr_model_dir="baseline_$(basename "${simu_allspkr_diar_config}" .yaml)_${tag}" -simu_allspkr_chunk2000_model_dir="baseline_$(basename "${simu_allspkr_chunk2000_diar_config}" .yaml)_${tag}" -callhome_model_dir="baseline_$(basename "${callhome_diar_config}" .yaml)_${tag}" - -# simulate mixture data for training and inference -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Simulate mixture data for training and inference" - echo "The detail can be found in https://github.com/hitachi-speech/EEND" - echo "Before running this step, you should download and compile kaldi and set KALDI_ROOT in this script and path.sh" - echo "This stage may take a long time, please waiting..." - KALDI_ROOT= - ln -s $KALDI_ROOT/egs/wsj/s5/steps steps - ln -s $KALDI_ROOT/egs/wsj/s5/utils utils - local/run_prepare_shared_eda.sh -fi - -# Prepare data for training and inference -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Prepare data for training and inference" - simu_opts_num_speaker_array=(1 2 3 4) - simu_opts_sil_scale_array=(2 2 5 9) - simu_opts_num_train=100000 - - # for simulated data of chunk500 and chunk2000 - for dset in swb_sre_cv swb_sre_tr; do - if [ "$dset" == "swb_sre_tr" ]; then - n_mixtures=${simu_opts_num_train} - dataset=train - else - n_mixtures=500 - dataset=dev - fi - simu_data_dir=${dset}_ns"$(IFS="n"; echo "${simu_opts_num_speaker_array[*]}")"_beta"$(IFS="n"; echo "${simu_opts_sil_scale_array[*]}")"_${n_mixtures} - mkdir -p ${data_dir}/simu/data/${simu_data_dir}/.work - split_scps= - for n in $(seq $nj); do - split_scps="$split_scps ${data_dir}/simu/data/${simu_data_dir}/.work/wav.scp.$n" - done - utils/split_scp.pl "${data_dir}/simu/data/${simu_data_dir}/wav.scp" $split_scps || exit 1 - python local/split.py ${data_dir}/simu/data/${simu_data_dir} - # for chunk_size=500 - output_dir=${data_dir}/ark_data/dump/simu_data/$dataset - mkdir -p $output_dir/.logs - $dump_cmd --max-jobs-run $nj JOB=1:$nj $output_dir/.logs/dump.JOB.log \ - python local/dump_feature.py \ - --data_dir ${data_dir}/simu/data/${simu_data_dir}/.work \ - --output_dir $output_dir \ - --index JOB - mkdir -p ${data_dir}/ark_data/dump/simu_data/data/$dataset - cat ${data_dir}/ark_data/dump/simu_data/$dataset/feature.scp.* > ${data_dir}/ark_data/dump/simu_data/data/$dataset/feature.scp - cat ${data_dir}/ark_data/dump/simu_data/$dataset/label.scp.* > ${data_dir}/ark_data/dump/simu_data/data/$dataset/label.scp - paste -d" " ${data_dir}/ark_data/dump/simu_data/data/$dataset/feature.scp <(cut -f2 -d" " ${data_dir}/ark_data/dump/simu_data/data/$dataset/label.scp) > ${data_dir}/ark_data/dump/simu_data/data/$dataset/feats.scp - grep "ns2" ${data_dir}/ark_data/dump/simu_data/data/$dataset/feats.scp > ${data_dir}/ark_data/dump/simu_data/data/$dataset/feats_2spkr.scp - # for chunk_size=2000 - output_dir=${data_dir}/ark_data/dump/simu_data_chunk2000/$dataset - mkdir -p $output_dir/.logs - $dump_cmd --max-jobs-run $nj JOB=1:$nj $output_dir/.logs/dump.JOB.log \ - python local/dump_feature.py \ - --data_dir ${data_dir}/simu/data/${simu_data_dir}/.work \ - --output_dir $output_dir \ - --index JOB \ - --num_frames 2000 - mkdir -p ${data_dir}/ark_data/dump/simu_data_chunk2000/data/$dataset - cat ${data_dir}/ark_data/dump/simu_data_chunk2000/$dataset/feature.scp.* > ${data_dir}/ark_data/dump/simu_data_chunk2000/data/$dataset/feature.scp - cat ${data_dir}/ark_data/dump/simu_data_chunk2000/$dataset/label.scp.* > ${data_dir}/ark_data/dump/simu_data_chunk2000/data/$dataset/label.scp - paste -d" " ${data_dir}/ark_data/dump/simu_data_chunk2000/data/$dataset/feature.scp <(cut -f2 -d" " ${data_dir}/ark_data/dump/simu_data_chunk2000/data/$dataset/label.scp) > ${data_dir}/ark_data/dump/simu_data_chunk2000/data/$dataset/feats.scp - done - - # for callhome data - for dset in callhome1_spkall callhome2_spkall; do - find $data_dir/eval/$dset -maxdepth 1 -type f -exec cp {} {}.1 \; - output_dir=${data_dir}/ark_data/dump/callhome_chunk2000/$dset - mkdir -p $output_dir - python local/dump_feature.py \ - --data_dir $data_dir/eval/$dset \ - --output_dir $output_dir \ - --index 1 \ - --num_frames 2000 - mkdir -p ${data_dir}/ark_data/dump/callhome_chunk2000/data/$dset - paste -d" " ${data_dir}/ark_data/dump/callhome_chunk2000/$dset/feature.scp.1 <(cut -f2 -d" " ${data_dir}/ark_data/dump/callhome_chunk2000/$dset/label.scp.1) > ${data_dir}/ark_data/dump/callhome_chunk2000/data/$dset/feats.scp - done -fi - -# Training on simulated two-speaker data -world_size=$gpu_num -simu_2spkr_ave_id=avg${simu_average_2spkr_start}-${simu_average_2spkr_end} -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Training on simulated two-speaker data" - mkdir -p ${exp_dir}/exp/${simu_2spkr_model_dir} - mkdir -p ${exp_dir}/exp/${simu_2spkr_model_dir}/log - INIT_FILE=${exp_dir}/exp/${simu_2spkr_model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name diar \ - --gpu_id $gpu_id \ - --use_preprocessor false \ - --input_size $input_size \ - --data_dir ${simu_feats_dir} \ - --train_set ${simu_train_dataset} \ - --valid_set ${simu_valid_dataset} \ - --data_file_names "feats_2spkr.scp" \ - --resume true \ - --output_dir ${exp_dir}/exp/${simu_2spkr_model_dir} \ - --config $simu_2spkr_diar_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${simu_2spkr_model_dir}/log/train.log.$i 2>&1 - } & - done - wait - echo "averaging model parameters into ${exp_dir}/exp/$simu_2spkr_model_dir/$simu_2spkr_ave_id.pb" - models=`eval echo ${exp_dir}/exp/${simu_2spkr_model_dir}/{$simu_average_2spkr_start..$simu_average_2spkr_end}epoch.pb` - python local/model_averaging.py ${exp_dir}/exp/${simu_2spkr_model_dir}/$simu_2spkr_ave_id.pb $models -fi - -# Training on simulated all-speaker data -world_size=$gpu_num -simu_allspkr_ave_id=avg${simu_average_allspkr_start}-${simu_average_allspkr_end} -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Training on simulated all-speaker data" - mkdir -p ${exp_dir}/exp/${simu_allspkr_model_dir} - mkdir -p ${exp_dir}/exp/${simu_allspkr_model_dir}/log - INIT_FILE=${exp_dir}/exp/${simu_allspkr_model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name diar \ - --gpu_id $gpu_id \ - --use_preprocessor false \ - --input_size $input_size \ - --data_dir ${simu_feats_dir} \ - --train_set ${simu_train_dataset} \ - --valid_set ${simu_valid_dataset} \ - --data_file_names "feats.scp" \ - --resume true \ - --init_param ${exp_dir}/exp/${simu_2spkr_model_dir}/$simu_2spkr_ave_id.pb \ - --output_dir ${exp_dir}/exp/${simu_allspkr_model_dir} \ - --config $simu_allspkr_diar_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${simu_allspkr_model_dir}/log/train.log.$i 2>&1 - } & - done - wait - echo "averaging model parameters into ${exp_dir}/exp/$simu_allspkr_model_dir/$simu_allspkr_ave_id.pb" - models=`eval echo ${exp_dir}/exp/${simu_allspkr_model_dir}/{$simu_average_allspkr_start..$simu_average_allspkr_end}epoch.pb` - python local/model_averaging.py ${exp_dir}/exp/${simu_allspkr_model_dir}/$simu_allspkr_ave_id.pb $models -fi - -# Training on simulated all-speaker data with chunk_size 2000 -world_size=$gpu_num -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: Training on simulated all-speaker data with chunk_size 2000" - mkdir -p ${exp_dir}/exp/${simu_allspkr_chunk2000_model_dir} - mkdir -p ${exp_dir}/exp/${simu_allspkr_chunk2000_model_dir}/log - INIT_FILE=${exp_dir}/exp/${simu_allspkr_chunk2000_model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name diar \ - --gpu_id $gpu_id \ - --use_preprocessor false \ - --input_size $input_size \ - --data_dir ${simu_feats_dir_chunk2000} \ - --train_set ${simu_train_dataset} \ - --valid_set ${simu_valid_dataset} \ - --data_file_names "feats.scp" \ - --resume true \ - --init_param ${exp_dir}/exp/${simu_allspkr_model_dir}/$simu_allspkr_ave_id.pb \ - --output_dir ${exp_dir}/exp/${simu_allspkr_chunk2000_model_dir} \ - --config $simu_allspkr_chunk2000_diar_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${simu_allspkr_chunk2000_model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Training on callhome all-speaker data with chunk_size 2000 -world_size=$gpu_num -callhome_ave_id=avg${callhome_average_start}-${callhome_average_end} -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: Training on callhome all-speaker data with chunk_size 2000" - mkdir -p ${exp_dir}/exp/${callhome_model_dir} - mkdir -p ${exp_dir}/exp/${callhome_model_dir}/log - INIT_FILE=${exp_dir}/exp/${callhome_model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name diar \ - --gpu_id $gpu_id \ - --use_preprocessor false \ - --input_size $input_size \ - --data_dir ${callhome_feats_dir_chunk2000} \ - --train_set ${callhome_train_dataset} \ - --valid_set ${callhome_valid_dataset} \ - --data_file_names "feats.scp" \ - --resume true \ - --init_param ${exp_dir}/exp/${simu_allspkr_chunk2000_model_dir}/1epoch.pb \ - --output_dir ${exp_dir}/exp/${callhome_model_dir} \ - --config $callhome_diar_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${callhome_model_dir}/log/train.log.$i 2>&1 - } & - done - wait - echo "averaging model parameters into ${exp_dir}/exp/$callhome_model_dir/$callhome_ave_id.pb" - models=`eval echo ${exp_dir}/exp/${callhome_model_dir}/{$callhome_average_start..$callhome_average_end}epoch.pb` - python local/model_averaging.py ${exp_dir}/exp/${callhome_model_dir}/$callhome_ave_id.pb $models -fi - -# inference and compute DER -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "Inference" - mkdir -p ${exp_dir}/exp/${callhome_model_dir}/inference/log - CUDA_VISIBLE_DEVICES=$CUDA_VISIBLE_DEVICES python local/infer.py \ - --config_file ${exp_dir}/exp/${callhome_model_dir}/config.yaml \ - --model_file ${exp_dir}/exp/${callhome_model_dir}/$callhome_ave_id.pb \ - --output_rttm_file ${exp_dir}/exp/${callhome_model_dir}/inference/rttm \ - --wav_scp_file $data_dir/eval/callhome2_spkall/wav.scp \ - 1> ${exp_dir}/exp/${callhome_model_dir}/inference/log/infer.log 2>&1 - md-eval.pl -c 0.25 \ - -r ${data_dir}/eval/${callhome_valid_dataset}/rttm \ - -s ${exp_dir}/exp/${callhome_model_dir}/inference/rttm > ${exp_dir}/exp/${callhome_model_dir}/inference/result_med11_collar0.25 2>/dev/null || exit -fi \ No newline at end of file diff --git a/egs/callhome/TOLD/soap/conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01.yaml b/egs/callhome/TOLD/soap/conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01.yaml deleted file mode 100644 index ce5dd89ca..000000000 --- a/egs/callhome/TOLD/soap/conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01.yaml +++ /dev/null @@ -1,134 +0,0 @@ -init: xavier_uniform -model: sond -model_conf: - lsm_weight: 0.0 - length_normalized_loss: true - max_spk_num: 16 - normalize_speech_speaker: true - speaker_discrimination_loss_weight: 0 - inter_score_loss_weight: 0.1 - model_regularizer_weight: 0.0 - freeze_encoder: true - onfly_shuffle_speaker: false -# label aggregator -label_aggregator: label_aggregator_max_pool -label_aggregator_conf: - hop_length: 8 - -# speech encoder -encoder: resnet34_sp_l2reg -encoder_conf: - # pass by model, equal to feature dim - # input_size: 80 - batchnorm_momentum: 0.01 - pooling_type: "window_shift" - pool_size: 20 - stride: 1 - tf2torch_tensor_name_prefix_torch: encoder - tf2torch_tensor_name_prefix_tf: EAND/speech_encoder - -speaker_encoder: null -speaker_encoder_conf: {} - -ci_scorer: conv -ci_scorer_conf: - input_units: 512 - num_layers: 3 - num_units: 512 - kernel_size: 1 - dropout_rate: 0.0 - position_encoder: null - out_units: 1 - out_norm: false - auxiliary_states: false - tf2torch_tensor_name_prefix_torch: ci_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/ci_scorer - -cd_scorer: san -cd_scorer_conf: - input_size: 512 - output_size: 512 - out_units: 1 - attention_heads: 4 - linear_units: 1024 - num_blocks: 4 - dropout_rate: 0.0 - positional_dropout_rate: 0.0 - attention_dropout_rate: 0.0 - # use string "null" to remove input layer - input_layer: "null" - pos_enc_class: null - normalize_before: true - tf2torch_tensor_name_prefix_torch: cd_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/cd_scorer - -# post net -decoder: fsmn -decoder_conf: - in_units: 32 - out_units: 2517 - filter_size: 31 - fsmn_num_layers: 6 - dnn_num_layers: 1 - num_memory_units: 16 - ffn_inner_dim: 512 - dropout_rate: 0.0 - tf2torch_tensor_name_prefix_torch: decoder - tf2torch_tensor_name_prefix_tf: EAND/post_net - -input_size: 80 -frontend: null -frontend_conf: - fs: 16000 - window: povey - n_mels: 80 - frame_length: 25 - frame_shift: 10 - filter_length_min: -1 - filter_length_max: -1 - lfr_m: 1 - lfr_n: 1 - dither: 0.0 - snip_edges: false - upsacle_samples: false - -# minibatch related -batch_type: unsorted -# 16 samples -batch_size: 8 -num_workers: 8 -max_epoch: 20 -num_iters_per_epoch: 10000 -keep_nbest_models: 5 - -# optimization related -accum_grad: 1 -grad_clip: 5.0 -val_scheduler_criterion: - - valid - - der - - min -best_model_criterion: -- - valid - - der - - min -- - valid - - forward_steps - - max - -optim: adamw -optim_conf: - lr: 1.0 - betas: [0.9, 0.998] - weight_decay: 0 -scheduler: noamlr -scheduler_conf: - model_size: 512 - warmup_steps: 10000 - -# without spec aug -specaug: null - -log_interval: 50 -# without normalize -normalize: null \ No newline at end of file diff --git a/egs/callhome/TOLD/soap/conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01_phase2.yaml b/egs/callhome/TOLD/soap/conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01_phase2.yaml deleted file mode 100644 index 712403459..000000000 --- a/egs/callhome/TOLD/soap/conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01_phase2.yaml +++ /dev/null @@ -1,134 +0,0 @@ -init: xavier_uniform -model: sond -model_conf: - lsm_weight: 0.0 - length_normalized_loss: true - max_spk_num: 16 - normalize_speech_speaker: true - speaker_discrimination_loss_weight: 0 - inter_score_loss_weight: 0.1 - model_regularizer_weight: 0.0 - freeze_encoder: false - onfly_shuffle_speaker: false -# label aggregator -label_aggregator: label_aggregator_max_pool -label_aggregator_conf: - hop_length: 8 - -# speech encoder -encoder: resnet34_sp_l2reg -encoder_conf: - # pass by model, equal to feature dim - # input_size: 80 - batchnorm_momentum: 0.01 - pooling_type: "window_shift" - pool_size: 20 - stride: 1 - tf2torch_tensor_name_prefix_torch: encoder - tf2torch_tensor_name_prefix_tf: EAND/speech_encoder - -speaker_encoder: null -speaker_encoder_conf: {} - -ci_scorer: conv -ci_scorer_conf: - input_units: 512 - num_layers: 3 - num_units: 512 - kernel_size: 1 - dropout_rate: 0.0 - position_encoder: null - out_units: 1 - out_norm: false - auxiliary_states: false - tf2torch_tensor_name_prefix_torch: ci_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/ci_scorer - -cd_scorer: san -cd_scorer_conf: - input_size: 512 - output_size: 512 - out_units: 1 - attention_heads: 4 - linear_units: 1024 - num_blocks: 4 - dropout_rate: 0.0 - positional_dropout_rate: 0.0 - attention_dropout_rate: 0.0 - # use string "null" to remove input layer - input_layer: "null" - pos_enc_class: null - normalize_before: true - tf2torch_tensor_name_prefix_torch: cd_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/cd_scorer - -# post net -decoder: fsmn -decoder_conf: - in_units: 32 - out_units: 2517 - filter_size: 31 - fsmn_num_layers: 6 - dnn_num_layers: 1 - num_memory_units: 16 - ffn_inner_dim: 512 - dropout_rate: 0.0 - tf2torch_tensor_name_prefix_torch: decoder - tf2torch_tensor_name_prefix_tf: EAND/post_net - -input_size: 80 -frontend: null -frontend_conf: - fs: 16000 - window: povey - n_mels: 80 - frame_length: 25 - frame_shift: 10 - filter_length_min: -1 - filter_length_max: -1 - lfr_m: 1 - lfr_n: 1 - dither: 0.0 - snip_edges: false - upsacle_samples: false - -# minibatch related -batch_type: unsorted -# 6 samples -batch_size: 6 -num_workers: 8 -max_epoch: 30 -num_iters_per_epoch: 10000 -keep_nbest_models: 5 - -# optimization related -accum_grad: 1 -grad_clip: 5.0 -val_scheduler_criterion: - - valid - - der - - min -best_model_criterion: -- - valid - - der - - min -- - valid - - forward_steps - - max - -optim: adamw -optim_conf: - lr: 0.0001 - betas: [0.9, 0.998] - weight_decay: 0 -scheduler: null -scheduler_conf: - model_size: 512 - warmup_steps: 10000 - -# without spec aug -specaug: null - -log_interval: 50 -# without normalize -normalize: null \ No newline at end of file diff --git a/egs/callhome/TOLD/soap/conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01_phase3.yaml b/egs/callhome/TOLD/soap/conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01_phase3.yaml deleted file mode 100644 index 8691fe9bb..000000000 --- a/egs/callhome/TOLD/soap/conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01_phase3.yaml +++ /dev/null @@ -1,134 +0,0 @@ -init: xavier_uniform -model: sond -model_conf: - lsm_weight: 0.0 - length_normalized_loss: true - max_spk_num: 16 - normalize_speech_speaker: true - speaker_discrimination_loss_weight: 0 - inter_score_loss_weight: 0.1 - model_regularizer_weight: 0.0 - freeze_encoder: false - onfly_shuffle_speaker: false -# label aggregator -label_aggregator: label_aggregator_max_pool -label_aggregator_conf: - hop_length: 8 - -# speech encoder -encoder: resnet34_sp_l2reg -encoder_conf: - # pass by model, equal to feature dim - # input_size: 80 - batchnorm_momentum: 0.01 - pooling_type: "window_shift" - pool_size: 20 - stride: 1 - tf2torch_tensor_name_prefix_torch: encoder - tf2torch_tensor_name_prefix_tf: EAND/speech_encoder - -speaker_encoder: null -speaker_encoder_conf: {} - -ci_scorer: conv -ci_scorer_conf: - input_units: 512 - num_layers: 3 - num_units: 512 - kernel_size: 1 - dropout_rate: 0.0 - position_encoder: null - out_units: 1 - out_norm: false - auxiliary_states: false - tf2torch_tensor_name_prefix_torch: ci_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/ci_scorer - -cd_scorer: san -cd_scorer_conf: - input_size: 512 - output_size: 512 - out_units: 1 - attention_heads: 4 - linear_units: 1024 - num_blocks: 4 - dropout_rate: 0.0 - positional_dropout_rate: 0.0 - attention_dropout_rate: 0.0 - # use string "null" to remove input layer - input_layer: "null" - pos_enc_class: null - normalize_before: true - tf2torch_tensor_name_prefix_torch: cd_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/cd_scorer - -# post net -decoder: fsmn -decoder_conf: - in_units: 32 - out_units: 2517 - filter_size: 31 - fsmn_num_layers: 6 - dnn_num_layers: 1 - num_memory_units: 16 - ffn_inner_dim: 512 - dropout_rate: 0.0 - tf2torch_tensor_name_prefix_torch: decoder - tf2torch_tensor_name_prefix_tf: EAND/post_net - -input_size: 80 -frontend: null -frontend_conf: - fs: 16000 - window: povey - n_mels: 80 - frame_length: 25 - frame_shift: 10 - filter_length_min: -1 - filter_length_max: -1 - lfr_m: 1 - lfr_n: 1 - dither: 0.0 - snip_edges: false - upsacle_samples: false - -# minibatch related -batch_type: unsorted -# 6 samples -batch_size: 6 -num_workers: 8 -max_epoch: 10 -num_iters_per_epoch: 300 -keep_nbest_models: 5 - -# optimization related -accum_grad: 1 -grad_clip: 5.0 -val_scheduler_criterion: - - valid - - der - - min -best_model_criterion: -- - valid - - der - - min -- - valid - - forward_steps - - max - -optim: adamw -optim_conf: - lr: 0.00001 - betas: [0.9, 0.998] - weight_decay: 0 -scheduler: null -scheduler_conf: - model_size: 512 - warmup_steps: 10000 - -# without spec aug -specaug: null - -log_interval: 50 -# without normalize -normalize: null \ No newline at end of file diff --git a/egs/callhome/TOLD/soap/conf/basic_inference.yaml b/egs/callhome/TOLD/soap/conf/basic_inference.yaml deleted file mode 100644 index fd08c09e1..000000000 --- a/egs/callhome/TOLD/soap/conf/basic_inference.yaml +++ /dev/null @@ -1,2 +0,0 @@ -smooth_size: 1 -dur_threshold: 0 diff --git a/egs/callhome/TOLD/soap/conf/fbank.conf b/egs/callhome/TOLD/soap/conf/fbank.conf deleted file mode 100644 index ef2df7fd5..000000000 --- a/egs/callhome/TOLD/soap/conf/fbank.conf +++ /dev/null @@ -1,4 +0,0 @@ ---sample-frequency=8000 ---num-mel-bins=80 ---frame-length=25 ---snip-edges=false \ No newline at end of file diff --git a/egs/callhome/TOLD/soap/data/token_list/bce_label_n16.txt b/egs/callhome/TOLD/soap/data/token_list/bce_label_n16.txt deleted file mode 100644 index e92edddb3..000000000 --- a/egs/callhome/TOLD/soap/data/token_list/bce_label_n16.txt +++ /dev/null @@ -1,65536 +0,0 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -569 -570 -571 -572 -573 -574 -575 -576 -577 -578 -579 -580 -581 -582 -583 -584 -585 -586 -587 -588 -589 -590 -591 -592 -593 -594 -595 -596 -597 -598 -599 -600 -601 -602 -603 -604 -605 -606 -607 -608 -609 -610 -611 -612 -613 -614 -615 -616 -617 -618 -619 -620 -621 -622 -623 -624 -625 -626 -627 -628 -629 -630 -631 -632 -633 -634 -635 -636 -637 -638 -639 -640 -641 -642 -643 -644 -645 -646 -647 -648 -649 -650 -651 -652 -653 -654 -655 -656 -657 -658 -659 -660 -661 -662 -663 -664 -665 -666 -667 -668 -669 -670 -671 -672 -673 -674 -675 -676 -677 -678 -679 -680 -681 -682 -683 -684 -685 -686 -687 -688 -689 -690 -691 -692 -693 -694 -695 -696 -697 -698 -699 -700 -701 -702 -703 -704 -705 -706 -707 -708 -709 -710 -711 -712 -713 -714 -715 -716 -717 -718 -719 -720 -721 -722 -723 -724 -725 -726 -727 -728 -729 -730 -731 -732 -733 -734 -735 -736 -737 -738 -739 -740 -741 -742 -743 -744 -745 -746 -747 -748 -749 -750 -751 -752 -753 -754 -755 -756 -757 -758 -759 -760 -761 -762 -763 -764 -765 -766 -767 -768 -769 -770 -771 -772 -773 -774 -775 -776 -777 -778 -779 -780 -781 -782 -783 -784 -785 -786 -787 -788 -789 -790 -791 -792 -793 -794 -795 -796 -797 -798 -799 -800 -801 -802 -803 -804 -805 -806 -807 -808 -809 -810 -811 -812 -813 -814 -815 -816 -817 -818 -819 -820 -821 -822 -823 -824 -825 -826 -827 -828 -829 -830 -831 -832 -833 -834 -835 -836 -837 -838 -839 -840 -841 -842 -843 -844 -845 -846 -847 -848 -849 -850 -851 -852 -853 -854 -855 -856 -857 -858 -859 -860 -861 -862 -863 -864 -865 -866 -867 -868 -869 -870 -871 -872 -873 -874 -875 -876 -877 -878 -879 -880 -881 -882 -883 -884 -885 -886 -887 -888 -889 -890 -891 -892 -893 -894 -895 -896 -897 -898 -899 -900 -901 -902 -903 -904 -905 -906 -907 -908 -909 -910 -911 -912 -913 -914 -915 -916 -917 -918 -919 -920 -921 -922 -923 -924 -925 -926 -927 -928 -929 -930 -931 -932 -933 -934 -935 -936 -937 -938 -939 -940 -941 -942 -943 -944 -945 -946 -947 -948 -949 -950 -951 -952 -953 -954 -955 -956 -957 -958 -959 -960 -961 -962 -963 -964 -965 -966 -967 -968 -969 -970 -971 -972 -973 -974 -975 -976 -977 -978 -979 -980 -981 -982 -983 -984 -985 -986 -987 -988 -989 -990 -991 -992 -993 -994 -995 -996 -997 -998 -999 -1000 -1001 -1002 -1003 -1004 -1005 -1006 -1007 -1008 -1009 -1010 -1011 -1012 -1013 -1014 -1015 -1016 -1017 -1018 -1019 -1020 -1021 -1022 -1023 -1024 -1025 -1026 -1027 -1028 -1029 -1030 -1031 -1032 -1033 -1034 -1035 -1036 -1037 -1038 -1039 -1040 -1041 -1042 -1043 -1044 -1045 -1046 -1047 -1048 -1049 -1050 -1051 -1052 -1053 -1054 -1055 -1056 -1057 -1058 -1059 -1060 -1061 -1062 -1063 -1064 -1065 -1066 -1067 -1068 -1069 -1070 -1071 -1072 -1073 -1074 -1075 -1076 -1077 -1078 -1079 -1080 -1081 -1082 -1083 -1084 -1085 -1086 -1087 -1088 -1089 -1090 -1091 -1092 -1093 -1094 -1095 -1096 -1097 -1098 -1099 -1100 -1101 -1102 -1103 -1104 -1105 -1106 -1107 -1108 -1109 -1110 -1111 -1112 -1113 -1114 -1115 -1116 -1117 -1118 -1119 -1120 -1121 -1122 -1123 -1124 -1125 -1126 -1127 -1128 -1129 -1130 -1131 -1132 -1133 -1134 -1135 -1136 -1137 -1138 -1139 -1140 -1141 -1142 -1143 -1144 -1145 -1146 -1147 -1148 -1149 -1150 -1151 -1152 -1153 -1154 -1155 -1156 -1157 -1158 -1159 -1160 -1161 -1162 -1163 -1164 -1165 -1166 -1167 -1168 -1169 -1170 -1171 -1172 -1173 -1174 -1175 -1176 -1177 -1178 -1179 -1180 -1181 -1182 -1183 -1184 -1185 -1186 -1187 -1188 -1189 -1190 -1191 -1192 -1193 -1194 -1195 -1196 -1197 -1198 -1199 -1200 -1201 -1202 -1203 -1204 -1205 -1206 -1207 -1208 -1209 -1210 -1211 -1212 -1213 -1214 -1215 -1216 -1217 -1218 -1219 -1220 -1221 -1222 -1223 -1224 -1225 -1226 -1227 -1228 -1229 -1230 -1231 -1232 -1233 -1234 -1235 -1236 -1237 -1238 -1239 -1240 -1241 -1242 -1243 -1244 -1245 -1246 -1247 -1248 -1249 -1250 -1251 -1252 -1253 -1254 -1255 -1256 -1257 -1258 -1259 -1260 -1261 -1262 -1263 -1264 -1265 -1266 -1267 -1268 -1269 -1270 -1271 -1272 -1273 -1274 -1275 -1276 -1277 -1278 -1279 -1280 -1281 -1282 -1283 -1284 -1285 -1286 -1287 -1288 -1289 -1290 -1291 -1292 -1293 -1294 -1295 -1296 -1297 -1298 -1299 -1300 -1301 -1302 -1303 -1304 -1305 -1306 -1307 -1308 -1309 -1310 -1311 -1312 -1313 -1314 -1315 -1316 -1317 -1318 -1319 -1320 -1321 -1322 -1323 -1324 -1325 -1326 -1327 -1328 -1329 -1330 -1331 -1332 -1333 -1334 -1335 -1336 -1337 -1338 -1339 -1340 -1341 -1342 -1343 -1344 -1345 -1346 -1347 -1348 -1349 -1350 -1351 -1352 -1353 -1354 -1355 -1356 -1357 -1358 -1359 -1360 -1361 -1362 -1363 -1364 -1365 -1366 -1367 -1368 -1369 -1370 -1371 -1372 -1373 -1374 -1375 -1376 -1377 -1378 -1379 -1380 -1381 -1382 -1383 -1384 -1385 -1386 -1387 -1388 -1389 -1390 -1391 -1392 -1393 -1394 -1395 -1396 -1397 -1398 -1399 -1400 -1401 -1402 -1403 -1404 -1405 -1406 -1407 -1408 -1409 -1410 -1411 -1412 -1413 -1414 -1415 -1416 -1417 -1418 -1419 -1420 -1421 -1422 -1423 -1424 -1425 -1426 -1427 -1428 -1429 -1430 -1431 -1432 -1433 -1434 -1435 -1436 -1437 -1438 -1439 -1440 -1441 -1442 -1443 -1444 -1445 -1446 -1447 -1448 -1449 -1450 -1451 -1452 -1453 -1454 -1455 -1456 -1457 -1458 -1459 -1460 -1461 -1462 -1463 -1464 -1465 -1466 -1467 -1468 -1469 -1470 -1471 -1472 -1473 -1474 -1475 -1476 -1477 -1478 -1479 -1480 -1481 -1482 -1483 -1484 -1485 -1486 -1487 -1488 -1489 -1490 -1491 -1492 -1493 -1494 -1495 -1496 -1497 -1498 -1499 -1500 -1501 -1502 -1503 -1504 -1505 -1506 -1507 -1508 -1509 -1510 -1511 -1512 -1513 -1514 -1515 -1516 -1517 -1518 -1519 -1520 -1521 -1522 -1523 -1524 -1525 -1526 -1527 -1528 -1529 -1530 -1531 -1532 -1533 -1534 -1535 -1536 -1537 -1538 -1539 -1540 -1541 -1542 -1543 -1544 -1545 -1546 -1547 -1548 -1549 -1550 -1551 -1552 -1553 -1554 -1555 -1556 -1557 -1558 -1559 -1560 -1561 -1562 -1563 -1564 -1565 -1566 -1567 -1568 -1569 -1570 -1571 -1572 -1573 -1574 -1575 -1576 -1577 -1578 -1579 -1580 -1581 -1582 -1583 -1584 -1585 -1586 -1587 -1588 -1589 -1590 -1591 -1592 -1593 -1594 -1595 -1596 -1597 -1598 -1599 -1600 -1601 -1602 -1603 -1604 -1605 -1606 -1607 -1608 -1609 -1610 -1611 -1612 -1613 -1614 -1615 -1616 -1617 -1618 -1619 -1620 -1621 -1622 -1623 -1624 -1625 -1626 -1627 -1628 -1629 -1630 -1631 -1632 -1633 -1634 -1635 -1636 -1637 -1638 -1639 -1640 -1641 -1642 -1643 -1644 -1645 -1646 -1647 -1648 -1649 -1650 -1651 -1652 -1653 -1654 -1655 -1656 -1657 -1658 -1659 -1660 -1661 -1662 -1663 -1664 -1665 -1666 -1667 -1668 -1669 -1670 -1671 -1672 -1673 -1674 -1675 -1676 -1677 -1678 -1679 -1680 -1681 -1682 -1683 -1684 -1685 -1686 -1687 -1688 -1689 -1690 -1691 -1692 -1693 -1694 -1695 -1696 -1697 -1698 -1699 -1700 -1701 -1702 -1703 -1704 -1705 -1706 -1707 -1708 -1709 -1710 -1711 -1712 -1713 -1714 -1715 -1716 -1717 -1718 -1719 -1720 -1721 -1722 -1723 -1724 -1725 -1726 -1727 -1728 -1729 -1730 -1731 -1732 -1733 -1734 -1735 -1736 -1737 -1738 -1739 -1740 -1741 -1742 -1743 -1744 -1745 -1746 -1747 -1748 -1749 -1750 -1751 -1752 -1753 -1754 -1755 -1756 -1757 -1758 -1759 -1760 -1761 -1762 -1763 -1764 -1765 -1766 -1767 -1768 -1769 -1770 -1771 -1772 -1773 -1774 -1775 -1776 -1777 -1778 -1779 -1780 -1781 -1782 -1783 -1784 -1785 -1786 -1787 -1788 -1789 -1790 -1791 -1792 -1793 -1794 -1795 -1796 -1797 -1798 -1799 -1800 -1801 -1802 -1803 -1804 -1805 -1806 -1807 -1808 -1809 -1810 -1811 -1812 -1813 -1814 -1815 -1816 -1817 -1818 -1819 -1820 -1821 -1822 -1823 -1824 -1825 -1826 -1827 -1828 -1829 -1830 -1831 -1832 -1833 -1834 -1835 -1836 -1837 -1838 -1839 -1840 -1841 -1842 -1843 -1844 -1845 -1846 -1847 -1848 -1849 -1850 -1851 -1852 -1853 -1854 -1855 -1856 -1857 -1858 -1859 -1860 -1861 -1862 -1863 -1864 -1865 -1866 -1867 -1868 -1869 -1870 -1871 -1872 -1873 -1874 -1875 -1876 -1877 -1878 -1879 -1880 -1881 -1882 -1883 -1884 -1885 -1886 -1887 -1888 -1889 -1890 -1891 -1892 -1893 -1894 -1895 -1896 -1897 -1898 -1899 -1900 -1901 -1902 -1903 -1904 -1905 -1906 -1907 -1908 -1909 -1910 -1911 -1912 -1913 -1914 -1915 -1916 -1917 -1918 -1919 -1920 -1921 -1922 -1923 -1924 -1925 -1926 -1927 -1928 -1929 -1930 -1931 -1932 -1933 -1934 -1935 -1936 -1937 -1938 -1939 -1940 -1941 -1942 -1943 -1944 -1945 -1946 -1947 -1948 -1949 -1950 -1951 -1952 -1953 -1954 -1955 -1956 -1957 -1958 -1959 -1960 -1961 -1962 -1963 -1964 -1965 -1966 -1967 -1968 -1969 -1970 -1971 -1972 -1973 -1974 -1975 -1976 -1977 -1978 -1979 -1980 -1981 -1982 -1983 -1984 -1985 -1986 -1987 -1988 -1989 -1990 -1991 -1992 -1993 -1994 -1995 -1996 -1997 -1998 -1999 -2000 -2001 -2002 -2003 -2004 -2005 -2006 -2007 -2008 -2009 -2010 -2011 -2012 -2013 -2014 -2015 -2016 -2017 -2018 -2019 -2020 -2021 -2022 -2023 -2024 -2025 -2026 -2027 -2028 -2029 -2030 -2031 -2032 -2033 -2034 -2035 -2036 -2037 -2038 -2039 -2040 -2041 -2042 -2043 -2044 -2045 -2046 -2047 -2048 -2049 -2050 -2051 -2052 -2053 -2054 -2055 -2056 -2057 -2058 -2059 -2060 -2061 -2062 -2063 -2064 -2065 -2066 -2067 -2068 -2069 -2070 -2071 -2072 -2073 -2074 -2075 -2076 -2077 -2078 -2079 -2080 -2081 -2082 -2083 -2084 -2085 -2086 -2087 -2088 -2089 -2090 -2091 -2092 -2093 -2094 -2095 -2096 -2097 -2098 -2099 -2100 -2101 -2102 -2103 -2104 -2105 -2106 -2107 -2108 -2109 -2110 -2111 -2112 -2113 -2114 -2115 -2116 -2117 -2118 -2119 -2120 -2121 -2122 -2123 -2124 -2125 -2126 -2127 -2128 -2129 -2130 -2131 -2132 -2133 -2134 -2135 -2136 -2137 -2138 -2139 -2140 -2141 -2142 -2143 -2144 -2145 -2146 -2147 -2148 -2149 -2150 -2151 -2152 -2153 -2154 -2155 -2156 -2157 -2158 -2159 -2160 -2161 -2162 -2163 -2164 -2165 -2166 -2167 -2168 -2169 -2170 -2171 -2172 -2173 -2174 -2175 -2176 -2177 -2178 -2179 -2180 -2181 -2182 -2183 -2184 -2185 -2186 -2187 -2188 -2189 -2190 -2191 -2192 -2193 -2194 -2195 -2196 -2197 -2198 -2199 -2200 -2201 -2202 -2203 -2204 -2205 -2206 -2207 -2208 -2209 -2210 -2211 -2212 -2213 -2214 -2215 -2216 -2217 -2218 -2219 -2220 -2221 -2222 -2223 -2224 -2225 -2226 -2227 -2228 -2229 -2230 -2231 -2232 -2233 -2234 -2235 -2236 -2237 -2238 -2239 -2240 -2241 -2242 -2243 -2244 -2245 -2246 -2247 -2248 -2249 -2250 -2251 -2252 -2253 -2254 -2255 -2256 -2257 -2258 -2259 -2260 -2261 -2262 -2263 -2264 -2265 -2266 -2267 -2268 -2269 -2270 -2271 -2272 -2273 -2274 -2275 -2276 -2277 -2278 -2279 -2280 -2281 -2282 -2283 -2284 -2285 -2286 -2287 -2288 -2289 -2290 -2291 -2292 -2293 -2294 -2295 -2296 -2297 -2298 -2299 -2300 -2301 -2302 -2303 -2304 -2305 -2306 -2307 -2308 -2309 -2310 -2311 -2312 -2313 -2314 -2315 -2316 -2317 -2318 -2319 -2320 -2321 -2322 -2323 -2324 -2325 -2326 -2327 -2328 -2329 -2330 -2331 -2332 -2333 -2334 -2335 -2336 -2337 -2338 -2339 -2340 -2341 -2342 -2343 -2344 -2345 -2346 -2347 -2348 -2349 -2350 -2351 -2352 -2353 -2354 -2355 -2356 -2357 -2358 -2359 -2360 -2361 -2362 -2363 -2364 -2365 -2366 -2367 -2368 -2369 -2370 -2371 -2372 -2373 -2374 -2375 -2376 -2377 -2378 -2379 -2380 -2381 -2382 -2383 -2384 -2385 -2386 -2387 -2388 -2389 -2390 -2391 -2392 -2393 -2394 -2395 -2396 -2397 -2398 -2399 -2400 -2401 -2402 -2403 -2404 -2405 -2406 -2407 -2408 -2409 -2410 -2411 -2412 -2413 -2414 -2415 -2416 -2417 -2418 -2419 -2420 -2421 -2422 -2423 -2424 -2425 -2426 -2427 -2428 -2429 -2430 -2431 -2432 -2433 -2434 -2435 -2436 -2437 -2438 -2439 -2440 -2441 -2442 -2443 -2444 -2445 -2446 -2447 -2448 -2449 -2450 -2451 -2452 -2453 -2454 -2455 -2456 -2457 -2458 -2459 -2460 -2461 -2462 -2463 -2464 -2465 -2466 -2467 -2468 -2469 -2470 -2471 -2472 -2473 -2474 -2475 -2476 -2477 -2478 -2479 -2480 -2481 -2482 -2483 -2484 -2485 -2486 -2487 -2488 -2489 -2490 -2491 -2492 -2493 -2494 -2495 -2496 -2497 -2498 -2499 -2500 -2501 -2502 -2503 -2504 -2505 -2506 -2507 -2508 -2509 -2510 -2511 -2512 -2513 -2514 -2515 -2516 -2517 -2518 -2519 -2520 -2521 -2522 -2523 -2524 -2525 -2526 -2527 -2528 -2529 -2530 -2531 -2532 -2533 -2534 -2535 -2536 -2537 -2538 -2539 -2540 -2541 -2542 -2543 -2544 -2545 -2546 -2547 -2548 -2549 -2550 -2551 -2552 -2553 -2554 -2555 -2556 -2557 -2558 -2559 -2560 -2561 -2562 -2563 -2564 -2565 -2566 -2567 -2568 -2569 -2570 -2571 -2572 -2573 -2574 -2575 -2576 -2577 -2578 -2579 -2580 -2581 -2582 -2583 -2584 -2585 -2586 -2587 -2588 -2589 -2590 -2591 -2592 -2593 -2594 -2595 -2596 -2597 -2598 -2599 -2600 -2601 -2602 -2603 -2604 -2605 -2606 -2607 -2608 -2609 -2610 -2611 -2612 -2613 -2614 -2615 -2616 -2617 -2618 -2619 -2620 -2621 -2622 -2623 -2624 -2625 -2626 -2627 -2628 -2629 -2630 -2631 -2632 -2633 -2634 -2635 -2636 -2637 -2638 -2639 -2640 -2641 -2642 -2643 -2644 -2645 -2646 -2647 -2648 -2649 -2650 -2651 -2652 -2653 -2654 -2655 -2656 -2657 -2658 -2659 -2660 -2661 -2662 -2663 -2664 -2665 -2666 -2667 -2668 -2669 -2670 -2671 -2672 -2673 -2674 -2675 -2676 -2677 -2678 -2679 -2680 -2681 -2682 -2683 -2684 -2685 -2686 -2687 -2688 -2689 -2690 -2691 -2692 -2693 -2694 -2695 -2696 -2697 -2698 -2699 -2700 -2701 -2702 -2703 -2704 -2705 -2706 -2707 -2708 -2709 -2710 -2711 -2712 -2713 -2714 -2715 -2716 -2717 -2718 -2719 -2720 -2721 -2722 -2723 -2724 -2725 -2726 -2727 -2728 -2729 -2730 -2731 -2732 -2733 -2734 -2735 -2736 -2737 -2738 -2739 -2740 -2741 -2742 -2743 -2744 -2745 -2746 -2747 -2748 -2749 -2750 -2751 -2752 -2753 -2754 -2755 -2756 -2757 -2758 -2759 -2760 -2761 -2762 -2763 -2764 -2765 -2766 -2767 -2768 -2769 -2770 -2771 -2772 -2773 -2774 -2775 -2776 -2777 -2778 -2779 -2780 -2781 -2782 -2783 -2784 -2785 -2786 -2787 -2788 -2789 -2790 -2791 -2792 -2793 -2794 -2795 -2796 -2797 -2798 -2799 -2800 -2801 -2802 -2803 -2804 -2805 -2806 -2807 -2808 -2809 -2810 -2811 -2812 -2813 -2814 -2815 -2816 -2817 -2818 -2819 -2820 -2821 -2822 -2823 -2824 -2825 -2826 -2827 -2828 -2829 -2830 -2831 -2832 -2833 -2834 -2835 -2836 -2837 -2838 -2839 -2840 -2841 -2842 -2843 -2844 -2845 -2846 -2847 -2848 -2849 -2850 -2851 -2852 -2853 -2854 -2855 -2856 -2857 -2858 -2859 -2860 -2861 -2862 -2863 -2864 -2865 -2866 -2867 -2868 -2869 -2870 -2871 -2872 -2873 -2874 -2875 -2876 -2877 -2878 -2879 -2880 -2881 -2882 -2883 -2884 -2885 -2886 -2887 -2888 -2889 -2890 -2891 -2892 -2893 -2894 -2895 -2896 -2897 -2898 -2899 -2900 -2901 -2902 -2903 -2904 -2905 -2906 -2907 -2908 -2909 -2910 -2911 -2912 -2913 -2914 -2915 -2916 -2917 -2918 -2919 -2920 -2921 -2922 -2923 -2924 -2925 -2926 -2927 -2928 -2929 -2930 -2931 -2932 -2933 -2934 -2935 -2936 -2937 -2938 -2939 -2940 -2941 -2942 -2943 -2944 -2945 -2946 -2947 -2948 -2949 -2950 -2951 -2952 -2953 -2954 -2955 -2956 -2957 -2958 -2959 -2960 -2961 -2962 -2963 -2964 -2965 -2966 -2967 -2968 -2969 -2970 -2971 -2972 -2973 -2974 -2975 -2976 -2977 -2978 -2979 -2980 -2981 -2982 -2983 -2984 -2985 -2986 -2987 -2988 -2989 -2990 -2991 -2992 -2993 -2994 -2995 -2996 -2997 -2998 -2999 -3000 -3001 -3002 -3003 -3004 -3005 -3006 -3007 -3008 -3009 -3010 -3011 -3012 -3013 -3014 -3015 -3016 -3017 -3018 -3019 -3020 -3021 -3022 -3023 -3024 -3025 -3026 -3027 -3028 -3029 -3030 -3031 -3032 -3033 -3034 -3035 -3036 -3037 -3038 -3039 -3040 -3041 -3042 -3043 -3044 -3045 -3046 -3047 -3048 -3049 -3050 -3051 -3052 -3053 -3054 -3055 -3056 -3057 -3058 -3059 -3060 -3061 -3062 -3063 -3064 -3065 -3066 -3067 -3068 -3069 -3070 -3071 -3072 -3073 -3074 -3075 -3076 -3077 -3078 -3079 -3080 -3081 -3082 -3083 -3084 -3085 -3086 -3087 -3088 -3089 -3090 -3091 -3092 -3093 -3094 -3095 -3096 -3097 -3098 -3099 -3100 -3101 -3102 -3103 -3104 -3105 -3106 -3107 -3108 -3109 -3110 -3111 -3112 -3113 -3114 -3115 -3116 -3117 -3118 -3119 -3120 -3121 -3122 -3123 -3124 -3125 -3126 -3127 -3128 -3129 -3130 -3131 -3132 -3133 -3134 -3135 -3136 -3137 -3138 -3139 -3140 -3141 -3142 -3143 -3144 -3145 -3146 -3147 -3148 -3149 -3150 -3151 -3152 -3153 -3154 -3155 -3156 -3157 -3158 -3159 -3160 -3161 -3162 -3163 -3164 -3165 -3166 -3167 -3168 -3169 -3170 -3171 -3172 -3173 -3174 -3175 -3176 -3177 -3178 -3179 -3180 -3181 -3182 -3183 -3184 -3185 -3186 -3187 -3188 -3189 -3190 -3191 -3192 -3193 -3194 -3195 -3196 -3197 -3198 -3199 -3200 -3201 -3202 -3203 -3204 -3205 -3206 -3207 -3208 -3209 -3210 -3211 -3212 -3213 -3214 -3215 -3216 -3217 -3218 -3219 -3220 -3221 -3222 -3223 -3224 -3225 -3226 -3227 -3228 -3229 -3230 -3231 -3232 -3233 -3234 -3235 -3236 -3237 -3238 -3239 -3240 -3241 -3242 -3243 -3244 -3245 -3246 -3247 -3248 -3249 -3250 -3251 -3252 -3253 -3254 -3255 -3256 -3257 -3258 -3259 -3260 -3261 -3262 -3263 -3264 -3265 -3266 -3267 -3268 -3269 -3270 -3271 -3272 -3273 -3274 -3275 -3276 -3277 -3278 -3279 -3280 -3281 -3282 -3283 -3284 -3285 -3286 -3287 -3288 -3289 -3290 -3291 -3292 -3293 -3294 -3295 -3296 -3297 -3298 -3299 -3300 -3301 -3302 -3303 -3304 -3305 -3306 -3307 -3308 -3309 -3310 -3311 -3312 -3313 -3314 -3315 -3316 -3317 -3318 -3319 -3320 -3321 -3322 -3323 -3324 -3325 -3326 -3327 -3328 -3329 -3330 -3331 -3332 -3333 -3334 -3335 -3336 -3337 -3338 -3339 -3340 -3341 -3342 -3343 -3344 -3345 -3346 -3347 -3348 -3349 -3350 -3351 -3352 -3353 -3354 -3355 -3356 -3357 -3358 -3359 -3360 -3361 -3362 -3363 -3364 -3365 -3366 -3367 -3368 -3369 -3370 -3371 -3372 -3373 -3374 -3375 -3376 -3377 -3378 -3379 -3380 -3381 -3382 -3383 -3384 -3385 -3386 -3387 -3388 -3389 -3390 -3391 -3392 -3393 -3394 -3395 -3396 -3397 -3398 -3399 -3400 -3401 -3402 -3403 -3404 -3405 -3406 -3407 -3408 -3409 -3410 -3411 -3412 -3413 -3414 -3415 -3416 -3417 -3418 -3419 -3420 -3421 -3422 -3423 -3424 -3425 -3426 -3427 -3428 -3429 -3430 -3431 -3432 -3433 -3434 -3435 -3436 -3437 -3438 -3439 -3440 -3441 -3442 -3443 -3444 -3445 -3446 -3447 -3448 -3449 -3450 -3451 -3452 -3453 -3454 -3455 -3456 -3457 -3458 -3459 -3460 -3461 -3462 -3463 -3464 -3465 -3466 -3467 -3468 -3469 -3470 -3471 -3472 -3473 -3474 -3475 -3476 -3477 -3478 -3479 -3480 -3481 -3482 -3483 -3484 -3485 -3486 -3487 -3488 -3489 -3490 -3491 -3492 -3493 -3494 -3495 -3496 -3497 -3498 -3499 -3500 -3501 -3502 -3503 -3504 -3505 -3506 -3507 -3508 -3509 -3510 -3511 -3512 -3513 -3514 -3515 -3516 -3517 -3518 -3519 -3520 -3521 -3522 -3523 -3524 -3525 -3526 -3527 -3528 -3529 -3530 -3531 -3532 -3533 -3534 -3535 -3536 -3537 -3538 -3539 -3540 -3541 -3542 -3543 -3544 -3545 -3546 -3547 -3548 -3549 -3550 -3551 -3552 -3553 -3554 -3555 -3556 -3557 -3558 -3559 -3560 -3561 -3562 -3563 -3564 -3565 -3566 -3567 -3568 -3569 -3570 -3571 -3572 -3573 -3574 -3575 -3576 -3577 -3578 -3579 -3580 -3581 -3582 -3583 -3584 -3585 -3586 -3587 -3588 -3589 -3590 -3591 -3592 -3593 -3594 -3595 -3596 -3597 -3598 -3599 -3600 -3601 -3602 -3603 -3604 -3605 -3606 -3607 -3608 -3609 -3610 -3611 -3612 -3613 -3614 -3615 -3616 -3617 -3618 -3619 -3620 -3621 -3622 -3623 -3624 -3625 -3626 -3627 -3628 -3629 -3630 -3631 -3632 -3633 -3634 -3635 -3636 -3637 -3638 -3639 -3640 -3641 -3642 -3643 -3644 -3645 -3646 -3647 -3648 -3649 -3650 -3651 -3652 -3653 -3654 -3655 -3656 -3657 -3658 -3659 -3660 -3661 -3662 -3663 -3664 -3665 -3666 -3667 -3668 -3669 -3670 -3671 -3672 -3673 -3674 -3675 -3676 -3677 -3678 -3679 -3680 -3681 -3682 -3683 -3684 -3685 -3686 -3687 -3688 -3689 -3690 -3691 -3692 -3693 -3694 -3695 -3696 -3697 -3698 -3699 -3700 -3701 -3702 -3703 -3704 -3705 -3706 -3707 -3708 -3709 -3710 -3711 -3712 -3713 -3714 -3715 -3716 -3717 -3718 -3719 -3720 -3721 -3722 -3723 -3724 -3725 -3726 -3727 -3728 -3729 -3730 -3731 -3732 -3733 -3734 -3735 -3736 -3737 -3738 -3739 -3740 -3741 -3742 -3743 -3744 -3745 -3746 -3747 -3748 -3749 -3750 -3751 -3752 -3753 -3754 -3755 -3756 -3757 -3758 -3759 -3760 -3761 -3762 -3763 -3764 -3765 -3766 -3767 -3768 -3769 -3770 -3771 -3772 -3773 -3774 -3775 -3776 -3777 -3778 -3779 -3780 -3781 -3782 -3783 -3784 -3785 -3786 -3787 -3788 -3789 -3790 -3791 -3792 -3793 -3794 -3795 -3796 -3797 -3798 -3799 -3800 -3801 -3802 -3803 -3804 -3805 -3806 -3807 -3808 -3809 -3810 -3811 -3812 -3813 -3814 -3815 -3816 -3817 -3818 -3819 -3820 -3821 -3822 -3823 -3824 -3825 -3826 -3827 -3828 -3829 -3830 -3831 -3832 -3833 -3834 -3835 -3836 -3837 -3838 -3839 -3840 -3841 -3842 -3843 -3844 -3845 -3846 -3847 -3848 -3849 -3850 -3851 -3852 -3853 -3854 -3855 -3856 -3857 -3858 -3859 -3860 -3861 -3862 -3863 -3864 -3865 -3866 -3867 -3868 -3869 -3870 -3871 -3872 -3873 -3874 -3875 -3876 -3877 -3878 -3879 -3880 -3881 -3882 -3883 -3884 -3885 -3886 -3887 -3888 -3889 -3890 -3891 -3892 -3893 -3894 -3895 -3896 -3897 -3898 -3899 -3900 -3901 -3902 -3903 -3904 -3905 -3906 -3907 -3908 -3909 -3910 -3911 -3912 -3913 -3914 -3915 -3916 -3917 -3918 -3919 -3920 -3921 -3922 -3923 -3924 -3925 -3926 -3927 -3928 -3929 -3930 -3931 -3932 -3933 -3934 -3935 -3936 -3937 -3938 -3939 -3940 -3941 -3942 -3943 -3944 -3945 -3946 -3947 -3948 -3949 -3950 -3951 -3952 -3953 -3954 -3955 -3956 -3957 -3958 -3959 -3960 -3961 -3962 -3963 -3964 -3965 -3966 -3967 -3968 -3969 -3970 -3971 -3972 -3973 -3974 -3975 -3976 -3977 -3978 -3979 -3980 -3981 -3982 -3983 -3984 -3985 -3986 -3987 -3988 -3989 -3990 -3991 -3992 -3993 -3994 -3995 -3996 -3997 -3998 -3999 -4000 -4001 -4002 -4003 -4004 -4005 -4006 -4007 -4008 -4009 -4010 -4011 -4012 -4013 -4014 -4015 -4016 -4017 -4018 -4019 -4020 -4021 -4022 -4023 -4024 -4025 -4026 -4027 -4028 -4029 -4030 -4031 -4032 -4033 -4034 -4035 -4036 -4037 -4038 -4039 -4040 -4041 -4042 -4043 -4044 -4045 -4046 -4047 -4048 -4049 -4050 -4051 -4052 -4053 -4054 -4055 -4056 -4057 -4058 -4059 -4060 -4061 -4062 -4063 -4064 -4065 -4066 -4067 -4068 -4069 -4070 -4071 -4072 -4073 -4074 -4075 -4076 -4077 -4078 -4079 -4080 -4081 -4082 -4083 -4084 -4085 -4086 -4087 -4088 -4089 -4090 -4091 -4092 -4093 -4094 -4095 -4096 -4097 -4098 -4099 -4100 -4101 -4102 -4103 -4104 -4105 -4106 -4107 -4108 -4109 -4110 -4111 -4112 -4113 -4114 -4115 -4116 -4117 -4118 -4119 -4120 -4121 -4122 -4123 -4124 -4125 -4126 -4127 -4128 -4129 -4130 -4131 -4132 -4133 -4134 -4135 -4136 -4137 -4138 -4139 -4140 -4141 -4142 -4143 -4144 -4145 -4146 -4147 -4148 -4149 -4150 -4151 -4152 -4153 -4154 -4155 -4156 -4157 -4158 -4159 -4160 -4161 -4162 -4163 -4164 -4165 -4166 -4167 -4168 -4169 -4170 -4171 -4172 -4173 -4174 -4175 -4176 -4177 -4178 -4179 -4180 -4181 -4182 -4183 -4184 -4185 -4186 -4187 -4188 -4189 -4190 -4191 -4192 -4193 -4194 -4195 -4196 -4197 -4198 -4199 -4200 -4201 -4202 -4203 -4204 -4205 -4206 -4207 -4208 -4209 -4210 -4211 -4212 -4213 -4214 -4215 -4216 -4217 -4218 -4219 -4220 -4221 -4222 -4223 -4224 -4225 -4226 -4227 -4228 -4229 -4230 -4231 -4232 -4233 -4234 -4235 -4236 -4237 -4238 -4239 -4240 -4241 -4242 -4243 -4244 -4245 -4246 -4247 -4248 -4249 -4250 -4251 -4252 -4253 -4254 -4255 -4256 -4257 -4258 -4259 -4260 -4261 -4262 -4263 -4264 -4265 -4266 -4267 -4268 -4269 -4270 -4271 -4272 -4273 -4274 -4275 -4276 -4277 -4278 -4279 -4280 -4281 -4282 -4283 -4284 -4285 -4286 -4287 -4288 -4289 -4290 -4291 -4292 -4293 -4294 -4295 -4296 -4297 -4298 -4299 -4300 -4301 -4302 -4303 -4304 -4305 -4306 -4307 -4308 -4309 -4310 -4311 -4312 -4313 -4314 -4315 -4316 -4317 -4318 -4319 -4320 -4321 -4322 -4323 -4324 -4325 -4326 -4327 -4328 -4329 -4330 -4331 -4332 -4333 -4334 -4335 -4336 -4337 -4338 -4339 -4340 -4341 -4342 -4343 -4344 -4345 -4346 -4347 -4348 -4349 -4350 -4351 -4352 -4353 -4354 -4355 -4356 -4357 -4358 -4359 -4360 -4361 -4362 -4363 -4364 -4365 -4366 -4367 -4368 -4369 -4370 -4371 -4372 -4373 -4374 -4375 -4376 -4377 -4378 -4379 -4380 -4381 -4382 -4383 -4384 -4385 -4386 -4387 -4388 -4389 -4390 -4391 -4392 -4393 -4394 -4395 -4396 -4397 -4398 -4399 -4400 -4401 -4402 -4403 -4404 -4405 -4406 -4407 -4408 -4409 -4410 -4411 -4412 -4413 -4414 -4415 -4416 -4417 -4418 -4419 -4420 -4421 -4422 -4423 -4424 -4425 -4426 -4427 -4428 -4429 -4430 -4431 -4432 -4433 -4434 -4435 -4436 -4437 -4438 -4439 -4440 -4441 -4442 -4443 -4444 -4445 -4446 -4447 -4448 -4449 -4450 -4451 -4452 -4453 -4454 -4455 -4456 -4457 -4458 -4459 -4460 -4461 -4462 -4463 -4464 -4465 -4466 -4467 -4468 -4469 -4470 -4471 -4472 -4473 -4474 -4475 -4476 -4477 -4478 -4479 -4480 -4481 -4482 -4483 -4484 -4485 -4486 -4487 -4488 -4489 -4490 -4491 -4492 -4493 -4494 -4495 -4496 -4497 -4498 -4499 -4500 -4501 -4502 -4503 -4504 -4505 -4506 -4507 -4508 -4509 -4510 -4511 -4512 -4513 -4514 -4515 -4516 -4517 -4518 -4519 -4520 -4521 -4522 -4523 -4524 -4525 -4526 -4527 -4528 -4529 -4530 -4531 -4532 -4533 -4534 -4535 -4536 -4537 -4538 -4539 -4540 -4541 -4542 -4543 -4544 -4545 -4546 -4547 -4548 -4549 -4550 -4551 -4552 -4553 -4554 -4555 -4556 -4557 -4558 -4559 -4560 -4561 -4562 -4563 -4564 -4565 -4566 -4567 -4568 -4569 -4570 -4571 -4572 -4573 -4574 -4575 -4576 -4577 -4578 -4579 -4580 -4581 -4582 -4583 -4584 -4585 -4586 -4587 -4588 -4589 -4590 -4591 -4592 -4593 -4594 -4595 -4596 -4597 -4598 -4599 -4600 -4601 -4602 -4603 -4604 -4605 -4606 -4607 -4608 -4609 -4610 -4611 -4612 -4613 -4614 -4615 -4616 -4617 -4618 -4619 -4620 -4621 -4622 -4623 -4624 -4625 -4626 -4627 -4628 -4629 -4630 -4631 -4632 -4633 -4634 -4635 -4636 -4637 -4638 -4639 -4640 -4641 -4642 -4643 -4644 -4645 -4646 -4647 -4648 -4649 -4650 -4651 -4652 -4653 -4654 -4655 -4656 -4657 -4658 -4659 -4660 -4661 -4662 -4663 -4664 -4665 -4666 -4667 -4668 -4669 -4670 -4671 -4672 -4673 -4674 -4675 -4676 -4677 -4678 -4679 -4680 -4681 -4682 -4683 -4684 -4685 -4686 -4687 -4688 -4689 -4690 -4691 -4692 -4693 -4694 -4695 -4696 -4697 -4698 -4699 -4700 -4701 -4702 -4703 -4704 -4705 -4706 -4707 -4708 -4709 -4710 -4711 -4712 -4713 -4714 -4715 -4716 -4717 -4718 -4719 -4720 -4721 -4722 -4723 -4724 -4725 -4726 -4727 -4728 -4729 -4730 -4731 -4732 -4733 -4734 -4735 -4736 -4737 -4738 -4739 -4740 -4741 -4742 -4743 -4744 -4745 -4746 -4747 -4748 -4749 -4750 -4751 -4752 -4753 -4754 -4755 -4756 -4757 -4758 -4759 -4760 -4761 -4762 -4763 -4764 -4765 -4766 -4767 -4768 -4769 -4770 -4771 -4772 -4773 -4774 -4775 -4776 -4777 -4778 -4779 -4780 -4781 -4782 -4783 -4784 -4785 -4786 -4787 -4788 -4789 -4790 -4791 -4792 -4793 -4794 -4795 -4796 -4797 -4798 -4799 -4800 -4801 -4802 -4803 -4804 -4805 -4806 -4807 -4808 -4809 -4810 -4811 -4812 -4813 -4814 -4815 -4816 -4817 -4818 -4819 -4820 -4821 -4822 -4823 -4824 -4825 -4826 -4827 -4828 -4829 -4830 -4831 -4832 -4833 -4834 -4835 -4836 -4837 -4838 -4839 -4840 -4841 -4842 -4843 -4844 -4845 -4846 -4847 -4848 -4849 -4850 -4851 -4852 -4853 -4854 -4855 -4856 -4857 -4858 -4859 -4860 -4861 -4862 -4863 -4864 -4865 -4866 -4867 -4868 -4869 -4870 -4871 -4872 -4873 -4874 -4875 -4876 -4877 -4878 -4879 -4880 -4881 -4882 -4883 -4884 -4885 -4886 -4887 -4888 -4889 -4890 -4891 -4892 -4893 -4894 -4895 -4896 -4897 -4898 -4899 -4900 -4901 -4902 -4903 -4904 -4905 -4906 -4907 -4908 -4909 -4910 -4911 -4912 -4913 -4914 -4915 -4916 -4917 -4918 -4919 -4920 -4921 -4922 -4923 -4924 -4925 -4926 -4927 -4928 -4929 -4930 -4931 -4932 -4933 -4934 -4935 -4936 -4937 -4938 -4939 -4940 -4941 -4942 -4943 -4944 -4945 -4946 -4947 -4948 -4949 -4950 -4951 -4952 -4953 -4954 -4955 -4956 -4957 -4958 -4959 -4960 -4961 -4962 -4963 -4964 -4965 -4966 -4967 -4968 -4969 -4970 -4971 -4972 -4973 -4974 -4975 -4976 -4977 -4978 -4979 -4980 -4981 -4982 -4983 -4984 -4985 -4986 -4987 -4988 -4989 -4990 -4991 -4992 -4993 -4994 -4995 -4996 -4997 -4998 -4999 -5000 -5001 -5002 -5003 -5004 -5005 -5006 -5007 -5008 -5009 -5010 -5011 -5012 -5013 -5014 -5015 -5016 -5017 -5018 -5019 -5020 -5021 -5022 -5023 -5024 -5025 -5026 -5027 -5028 -5029 -5030 -5031 -5032 -5033 -5034 -5035 -5036 -5037 -5038 -5039 -5040 -5041 -5042 -5043 -5044 -5045 -5046 -5047 -5048 -5049 -5050 -5051 -5052 -5053 -5054 -5055 -5056 -5057 -5058 -5059 -5060 -5061 -5062 -5063 -5064 -5065 -5066 -5067 -5068 -5069 -5070 -5071 -5072 -5073 -5074 -5075 -5076 -5077 -5078 -5079 -5080 -5081 -5082 -5083 -5084 -5085 -5086 -5087 -5088 -5089 -5090 -5091 -5092 -5093 -5094 -5095 -5096 -5097 -5098 -5099 -5100 -5101 -5102 -5103 -5104 -5105 -5106 -5107 -5108 -5109 -5110 -5111 -5112 -5113 -5114 -5115 -5116 -5117 -5118 -5119 -5120 -5121 -5122 -5123 -5124 -5125 -5126 -5127 -5128 -5129 -5130 -5131 -5132 -5133 -5134 -5135 -5136 -5137 -5138 -5139 -5140 -5141 -5142 -5143 -5144 -5145 -5146 -5147 -5148 -5149 -5150 -5151 -5152 -5153 -5154 -5155 -5156 -5157 -5158 -5159 -5160 -5161 -5162 -5163 -5164 -5165 -5166 -5167 -5168 -5169 -5170 -5171 -5172 -5173 -5174 -5175 -5176 -5177 -5178 -5179 -5180 -5181 -5182 -5183 -5184 -5185 -5186 -5187 -5188 -5189 -5190 -5191 -5192 -5193 -5194 -5195 -5196 -5197 -5198 -5199 -5200 -5201 -5202 -5203 -5204 -5205 -5206 -5207 -5208 -5209 -5210 -5211 -5212 -5213 -5214 -5215 -5216 -5217 -5218 -5219 -5220 -5221 -5222 -5223 -5224 -5225 -5226 -5227 -5228 -5229 -5230 -5231 -5232 -5233 -5234 -5235 -5236 -5237 -5238 -5239 -5240 -5241 -5242 -5243 -5244 -5245 -5246 -5247 -5248 -5249 -5250 -5251 -5252 -5253 -5254 -5255 -5256 -5257 -5258 -5259 -5260 -5261 -5262 -5263 -5264 -5265 -5266 -5267 -5268 -5269 -5270 -5271 -5272 -5273 -5274 -5275 -5276 -5277 -5278 -5279 -5280 -5281 -5282 -5283 -5284 -5285 -5286 -5287 -5288 -5289 -5290 -5291 -5292 -5293 -5294 -5295 -5296 -5297 -5298 -5299 -5300 -5301 -5302 -5303 -5304 -5305 -5306 -5307 -5308 -5309 -5310 -5311 -5312 -5313 -5314 -5315 -5316 -5317 -5318 -5319 -5320 -5321 -5322 -5323 -5324 -5325 -5326 -5327 -5328 -5329 -5330 -5331 -5332 -5333 -5334 -5335 -5336 -5337 -5338 -5339 -5340 -5341 -5342 -5343 -5344 -5345 -5346 -5347 -5348 -5349 -5350 -5351 -5352 -5353 -5354 -5355 -5356 -5357 -5358 -5359 -5360 -5361 -5362 -5363 -5364 -5365 -5366 -5367 -5368 -5369 -5370 -5371 -5372 -5373 -5374 -5375 -5376 -5377 -5378 -5379 -5380 -5381 -5382 -5383 -5384 -5385 -5386 -5387 -5388 -5389 -5390 -5391 -5392 -5393 -5394 -5395 -5396 -5397 -5398 -5399 -5400 -5401 -5402 -5403 -5404 -5405 -5406 -5407 -5408 -5409 -5410 -5411 -5412 -5413 -5414 -5415 -5416 -5417 -5418 -5419 -5420 -5421 -5422 -5423 -5424 -5425 -5426 -5427 -5428 -5429 -5430 -5431 -5432 -5433 -5434 -5435 -5436 -5437 -5438 -5439 -5440 -5441 -5442 -5443 -5444 -5445 -5446 -5447 -5448 -5449 -5450 -5451 -5452 -5453 -5454 -5455 -5456 -5457 -5458 -5459 -5460 -5461 -5462 -5463 -5464 -5465 -5466 -5467 -5468 -5469 -5470 -5471 -5472 -5473 -5474 -5475 -5476 -5477 -5478 -5479 -5480 -5481 -5482 -5483 -5484 -5485 -5486 -5487 -5488 -5489 -5490 -5491 -5492 -5493 -5494 -5495 -5496 -5497 -5498 -5499 -5500 -5501 -5502 -5503 -5504 -5505 -5506 -5507 -5508 -5509 -5510 -5511 -5512 -5513 -5514 -5515 -5516 -5517 -5518 -5519 -5520 -5521 -5522 -5523 -5524 -5525 -5526 -5527 -5528 -5529 -5530 -5531 -5532 -5533 -5534 -5535 -5536 -5537 -5538 -5539 -5540 -5541 -5542 -5543 -5544 -5545 -5546 -5547 -5548 -5549 -5550 -5551 -5552 -5553 -5554 -5555 -5556 -5557 -5558 -5559 -5560 -5561 -5562 -5563 -5564 -5565 -5566 -5567 -5568 -5569 -5570 -5571 -5572 -5573 -5574 -5575 -5576 -5577 -5578 -5579 -5580 -5581 -5582 -5583 -5584 -5585 -5586 -5587 -5588 -5589 -5590 -5591 -5592 -5593 -5594 -5595 -5596 -5597 -5598 -5599 -5600 -5601 -5602 -5603 -5604 -5605 -5606 -5607 -5608 -5609 -5610 -5611 -5612 -5613 -5614 -5615 -5616 -5617 -5618 -5619 -5620 -5621 -5622 -5623 -5624 -5625 -5626 -5627 -5628 -5629 -5630 -5631 -5632 -5633 -5634 -5635 -5636 -5637 -5638 -5639 -5640 -5641 -5642 -5643 -5644 -5645 -5646 -5647 -5648 -5649 -5650 -5651 -5652 -5653 -5654 -5655 -5656 -5657 -5658 -5659 -5660 -5661 -5662 -5663 -5664 -5665 -5666 -5667 -5668 -5669 -5670 -5671 -5672 -5673 -5674 -5675 -5676 -5677 -5678 -5679 -5680 -5681 -5682 -5683 -5684 -5685 -5686 -5687 -5688 -5689 -5690 -5691 -5692 -5693 -5694 -5695 -5696 -5697 -5698 -5699 -5700 -5701 -5702 -5703 -5704 -5705 -5706 -5707 -5708 -5709 -5710 -5711 -5712 -5713 -5714 -5715 -5716 -5717 -5718 -5719 -5720 -5721 -5722 -5723 -5724 -5725 -5726 -5727 -5728 -5729 -5730 -5731 -5732 -5733 -5734 -5735 -5736 -5737 -5738 -5739 -5740 -5741 -5742 -5743 -5744 -5745 -5746 -5747 -5748 -5749 -5750 -5751 -5752 -5753 -5754 -5755 -5756 -5757 -5758 -5759 -5760 -5761 -5762 -5763 -5764 -5765 -5766 -5767 -5768 -5769 -5770 -5771 -5772 -5773 -5774 -5775 -5776 -5777 -5778 -5779 -5780 -5781 -5782 -5783 -5784 -5785 -5786 -5787 -5788 -5789 -5790 -5791 -5792 -5793 -5794 -5795 -5796 -5797 -5798 -5799 -5800 -5801 -5802 -5803 -5804 -5805 -5806 -5807 -5808 -5809 -5810 -5811 -5812 -5813 -5814 -5815 -5816 -5817 -5818 -5819 -5820 -5821 -5822 -5823 -5824 -5825 -5826 -5827 -5828 -5829 -5830 -5831 -5832 -5833 -5834 -5835 -5836 -5837 -5838 -5839 -5840 -5841 -5842 -5843 -5844 -5845 -5846 -5847 -5848 -5849 -5850 -5851 -5852 -5853 -5854 -5855 -5856 -5857 -5858 -5859 -5860 -5861 -5862 -5863 -5864 -5865 -5866 -5867 -5868 -5869 -5870 -5871 -5872 -5873 -5874 -5875 -5876 -5877 -5878 -5879 -5880 -5881 -5882 -5883 -5884 -5885 -5886 -5887 -5888 -5889 -5890 -5891 -5892 -5893 -5894 -5895 -5896 -5897 -5898 -5899 -5900 -5901 -5902 -5903 -5904 -5905 -5906 -5907 -5908 -5909 -5910 -5911 -5912 -5913 -5914 -5915 -5916 -5917 -5918 -5919 -5920 -5921 -5922 -5923 -5924 -5925 -5926 -5927 -5928 -5929 -5930 -5931 -5932 -5933 -5934 -5935 -5936 -5937 -5938 -5939 -5940 -5941 -5942 -5943 -5944 -5945 -5946 -5947 -5948 -5949 -5950 -5951 -5952 -5953 -5954 -5955 -5956 -5957 -5958 -5959 -5960 -5961 -5962 -5963 -5964 -5965 -5966 -5967 -5968 -5969 -5970 -5971 -5972 -5973 -5974 -5975 -5976 -5977 -5978 -5979 -5980 -5981 -5982 -5983 -5984 -5985 -5986 -5987 -5988 -5989 -5990 -5991 -5992 -5993 -5994 -5995 -5996 -5997 -5998 -5999 -6000 -6001 -6002 -6003 -6004 -6005 -6006 -6007 -6008 -6009 -6010 -6011 -6012 -6013 -6014 -6015 -6016 -6017 -6018 -6019 -6020 -6021 -6022 -6023 -6024 -6025 -6026 -6027 -6028 -6029 -6030 -6031 -6032 -6033 -6034 -6035 -6036 -6037 -6038 -6039 -6040 -6041 -6042 -6043 -6044 -6045 -6046 -6047 -6048 -6049 -6050 -6051 -6052 -6053 -6054 -6055 -6056 -6057 -6058 -6059 -6060 -6061 -6062 -6063 -6064 -6065 -6066 -6067 -6068 -6069 -6070 -6071 -6072 -6073 -6074 -6075 -6076 -6077 -6078 -6079 -6080 -6081 -6082 -6083 -6084 -6085 -6086 -6087 -6088 -6089 -6090 -6091 -6092 -6093 -6094 -6095 -6096 -6097 -6098 -6099 -6100 -6101 -6102 -6103 -6104 -6105 -6106 -6107 -6108 -6109 -6110 -6111 -6112 -6113 -6114 -6115 -6116 -6117 -6118 -6119 -6120 -6121 -6122 -6123 -6124 -6125 -6126 -6127 -6128 -6129 -6130 -6131 -6132 -6133 -6134 -6135 -6136 -6137 -6138 -6139 -6140 -6141 -6142 -6143 -6144 -6145 -6146 -6147 -6148 -6149 -6150 -6151 -6152 -6153 -6154 -6155 -6156 -6157 -6158 -6159 -6160 -6161 -6162 -6163 -6164 -6165 -6166 -6167 -6168 -6169 -6170 -6171 -6172 -6173 -6174 -6175 -6176 -6177 -6178 -6179 -6180 -6181 -6182 -6183 -6184 -6185 -6186 -6187 -6188 -6189 -6190 -6191 -6192 -6193 -6194 -6195 -6196 -6197 -6198 -6199 -6200 -6201 -6202 -6203 -6204 -6205 -6206 -6207 -6208 -6209 -6210 -6211 -6212 -6213 -6214 -6215 -6216 -6217 -6218 -6219 -6220 -6221 -6222 -6223 -6224 -6225 -6226 -6227 -6228 -6229 -6230 -6231 -6232 -6233 -6234 -6235 -6236 -6237 -6238 -6239 -6240 -6241 -6242 -6243 -6244 -6245 -6246 -6247 -6248 -6249 -6250 -6251 -6252 -6253 -6254 -6255 -6256 -6257 -6258 -6259 -6260 -6261 -6262 -6263 -6264 -6265 -6266 -6267 -6268 -6269 -6270 -6271 -6272 -6273 -6274 -6275 -6276 -6277 -6278 -6279 -6280 -6281 -6282 -6283 -6284 -6285 -6286 -6287 -6288 -6289 -6290 -6291 -6292 -6293 -6294 -6295 -6296 -6297 -6298 -6299 -6300 -6301 -6302 -6303 -6304 -6305 -6306 -6307 -6308 -6309 -6310 -6311 -6312 -6313 -6314 -6315 -6316 -6317 -6318 -6319 -6320 -6321 -6322 -6323 -6324 -6325 -6326 -6327 -6328 -6329 -6330 -6331 -6332 -6333 -6334 -6335 -6336 -6337 -6338 -6339 -6340 -6341 -6342 -6343 -6344 -6345 -6346 -6347 -6348 -6349 -6350 -6351 -6352 -6353 -6354 -6355 -6356 -6357 -6358 -6359 -6360 -6361 -6362 -6363 -6364 -6365 -6366 -6367 -6368 -6369 -6370 -6371 -6372 -6373 -6374 -6375 -6376 -6377 -6378 -6379 -6380 -6381 -6382 -6383 -6384 -6385 -6386 -6387 -6388 -6389 -6390 -6391 -6392 -6393 -6394 -6395 -6396 -6397 -6398 -6399 -6400 -6401 -6402 -6403 -6404 -6405 -6406 -6407 -6408 -6409 -6410 -6411 -6412 -6413 -6414 -6415 -6416 -6417 -6418 -6419 -6420 -6421 -6422 -6423 -6424 -6425 -6426 -6427 -6428 -6429 -6430 -6431 -6432 -6433 -6434 -6435 -6436 -6437 -6438 -6439 -6440 -6441 -6442 -6443 -6444 -6445 -6446 -6447 -6448 -6449 -6450 -6451 -6452 -6453 -6454 -6455 -6456 -6457 -6458 -6459 -6460 -6461 -6462 -6463 -6464 -6465 -6466 -6467 -6468 -6469 -6470 -6471 -6472 -6473 -6474 -6475 -6476 -6477 -6478 -6479 -6480 -6481 -6482 -6483 -6484 -6485 -6486 -6487 -6488 -6489 -6490 -6491 -6492 -6493 -6494 -6495 -6496 -6497 -6498 -6499 -6500 -6501 -6502 -6503 -6504 -6505 -6506 -6507 -6508 -6509 -6510 -6511 -6512 -6513 -6514 -6515 -6516 -6517 -6518 -6519 -6520 -6521 -6522 -6523 -6524 -6525 -6526 -6527 -6528 -6529 -6530 -6531 -6532 -6533 -6534 -6535 -6536 -6537 -6538 -6539 -6540 -6541 -6542 -6543 -6544 -6545 -6546 -6547 -6548 -6549 -6550 -6551 -6552 -6553 -6554 -6555 -6556 -6557 -6558 -6559 -6560 -6561 -6562 -6563 -6564 -6565 -6566 -6567 -6568 -6569 -6570 -6571 -6572 -6573 -6574 -6575 -6576 -6577 -6578 -6579 -6580 -6581 -6582 -6583 -6584 -6585 -6586 -6587 -6588 -6589 -6590 -6591 -6592 -6593 -6594 -6595 -6596 -6597 -6598 -6599 -6600 -6601 -6602 -6603 -6604 -6605 -6606 -6607 -6608 -6609 -6610 -6611 -6612 -6613 -6614 -6615 -6616 -6617 -6618 -6619 -6620 -6621 -6622 -6623 -6624 -6625 -6626 -6627 -6628 -6629 -6630 -6631 -6632 -6633 -6634 -6635 -6636 -6637 -6638 -6639 -6640 -6641 -6642 -6643 -6644 -6645 -6646 -6647 -6648 -6649 -6650 -6651 -6652 -6653 -6654 -6655 -6656 -6657 -6658 -6659 -6660 -6661 -6662 -6663 -6664 -6665 -6666 -6667 -6668 -6669 -6670 -6671 -6672 -6673 -6674 -6675 -6676 -6677 -6678 -6679 -6680 -6681 -6682 -6683 -6684 -6685 -6686 -6687 -6688 -6689 -6690 -6691 -6692 -6693 -6694 -6695 -6696 -6697 -6698 -6699 -6700 -6701 -6702 -6703 -6704 -6705 -6706 -6707 -6708 -6709 -6710 -6711 -6712 -6713 -6714 -6715 -6716 -6717 -6718 -6719 -6720 -6721 -6722 -6723 -6724 -6725 -6726 -6727 -6728 -6729 -6730 -6731 -6732 -6733 -6734 -6735 -6736 -6737 -6738 -6739 -6740 -6741 -6742 -6743 -6744 -6745 -6746 -6747 -6748 -6749 -6750 -6751 -6752 -6753 -6754 -6755 -6756 -6757 -6758 -6759 -6760 -6761 -6762 -6763 -6764 -6765 -6766 -6767 -6768 -6769 -6770 -6771 -6772 -6773 -6774 -6775 -6776 -6777 -6778 -6779 -6780 -6781 -6782 -6783 -6784 -6785 -6786 -6787 -6788 -6789 -6790 -6791 -6792 -6793 -6794 -6795 -6796 -6797 -6798 -6799 -6800 -6801 -6802 -6803 -6804 -6805 -6806 -6807 -6808 -6809 -6810 -6811 -6812 -6813 -6814 -6815 -6816 -6817 -6818 -6819 -6820 -6821 -6822 -6823 -6824 -6825 -6826 -6827 -6828 -6829 -6830 -6831 -6832 -6833 -6834 -6835 -6836 -6837 -6838 -6839 -6840 -6841 -6842 -6843 -6844 -6845 -6846 -6847 -6848 -6849 -6850 -6851 -6852 -6853 -6854 -6855 -6856 -6857 -6858 -6859 -6860 -6861 -6862 -6863 -6864 -6865 -6866 -6867 -6868 -6869 -6870 -6871 -6872 -6873 -6874 -6875 -6876 -6877 -6878 -6879 -6880 -6881 -6882 -6883 -6884 -6885 -6886 -6887 -6888 -6889 -6890 -6891 -6892 -6893 -6894 -6895 -6896 -6897 -6898 -6899 -6900 -6901 -6902 -6903 -6904 -6905 -6906 -6907 -6908 -6909 -6910 -6911 -6912 -6913 -6914 -6915 -6916 -6917 -6918 -6919 -6920 -6921 -6922 -6923 -6924 -6925 -6926 -6927 -6928 -6929 -6930 -6931 -6932 -6933 -6934 -6935 -6936 -6937 -6938 -6939 -6940 -6941 -6942 -6943 -6944 -6945 -6946 -6947 -6948 -6949 -6950 -6951 -6952 -6953 -6954 -6955 -6956 -6957 -6958 -6959 -6960 -6961 -6962 -6963 -6964 -6965 -6966 -6967 -6968 -6969 -6970 -6971 -6972 -6973 -6974 -6975 -6976 -6977 -6978 -6979 -6980 -6981 -6982 -6983 -6984 -6985 -6986 -6987 -6988 -6989 -6990 -6991 -6992 -6993 -6994 -6995 -6996 -6997 -6998 -6999 -7000 -7001 -7002 -7003 -7004 -7005 -7006 -7007 -7008 -7009 -7010 -7011 -7012 -7013 -7014 -7015 -7016 -7017 -7018 -7019 -7020 -7021 -7022 -7023 -7024 -7025 -7026 -7027 -7028 -7029 -7030 -7031 -7032 -7033 -7034 -7035 -7036 -7037 -7038 -7039 -7040 -7041 -7042 -7043 -7044 -7045 -7046 -7047 -7048 -7049 -7050 -7051 -7052 -7053 -7054 -7055 -7056 -7057 -7058 -7059 -7060 -7061 -7062 -7063 -7064 -7065 -7066 -7067 -7068 -7069 -7070 -7071 -7072 -7073 -7074 -7075 -7076 -7077 -7078 -7079 -7080 -7081 -7082 -7083 -7084 -7085 -7086 -7087 -7088 -7089 -7090 -7091 -7092 -7093 -7094 -7095 -7096 -7097 -7098 -7099 -7100 -7101 -7102 -7103 -7104 -7105 -7106 -7107 -7108 -7109 -7110 -7111 -7112 -7113 -7114 -7115 -7116 -7117 -7118 -7119 -7120 -7121 -7122 -7123 -7124 -7125 -7126 -7127 -7128 -7129 -7130 -7131 -7132 -7133 -7134 -7135 -7136 -7137 -7138 -7139 -7140 -7141 -7142 -7143 -7144 -7145 -7146 -7147 -7148 -7149 -7150 -7151 -7152 -7153 -7154 -7155 -7156 -7157 -7158 -7159 -7160 -7161 -7162 -7163 -7164 -7165 -7166 -7167 -7168 -7169 -7170 -7171 -7172 -7173 -7174 -7175 -7176 -7177 -7178 -7179 -7180 -7181 -7182 -7183 -7184 -7185 -7186 -7187 -7188 -7189 -7190 -7191 -7192 -7193 -7194 -7195 -7196 -7197 -7198 -7199 -7200 -7201 -7202 -7203 -7204 -7205 -7206 -7207 -7208 -7209 -7210 -7211 -7212 -7213 -7214 -7215 -7216 -7217 -7218 -7219 -7220 -7221 -7222 -7223 -7224 -7225 -7226 -7227 -7228 -7229 -7230 -7231 -7232 -7233 -7234 -7235 -7236 -7237 -7238 -7239 -7240 -7241 -7242 -7243 -7244 -7245 -7246 -7247 -7248 -7249 -7250 -7251 -7252 -7253 -7254 -7255 -7256 -7257 -7258 -7259 -7260 -7261 -7262 -7263 -7264 -7265 -7266 -7267 -7268 -7269 -7270 -7271 -7272 -7273 -7274 -7275 -7276 -7277 -7278 -7279 -7280 -7281 -7282 -7283 -7284 -7285 -7286 -7287 -7288 -7289 -7290 -7291 -7292 -7293 -7294 -7295 -7296 -7297 -7298 -7299 -7300 -7301 -7302 -7303 -7304 -7305 -7306 -7307 -7308 -7309 -7310 -7311 -7312 -7313 -7314 -7315 -7316 -7317 -7318 -7319 -7320 -7321 -7322 -7323 -7324 -7325 -7326 -7327 -7328 -7329 -7330 -7331 -7332 -7333 -7334 -7335 -7336 -7337 -7338 -7339 -7340 -7341 -7342 -7343 -7344 -7345 -7346 -7347 -7348 -7349 -7350 -7351 -7352 -7353 -7354 -7355 -7356 -7357 -7358 -7359 -7360 -7361 -7362 -7363 -7364 -7365 -7366 -7367 -7368 -7369 -7370 -7371 -7372 -7373 -7374 -7375 -7376 -7377 -7378 -7379 -7380 -7381 -7382 -7383 -7384 -7385 -7386 -7387 -7388 -7389 -7390 -7391 -7392 -7393 -7394 -7395 -7396 -7397 -7398 -7399 -7400 -7401 -7402 -7403 -7404 -7405 -7406 -7407 -7408 -7409 -7410 -7411 -7412 -7413 -7414 -7415 -7416 -7417 -7418 -7419 -7420 -7421 -7422 -7423 -7424 -7425 -7426 -7427 -7428 -7429 -7430 -7431 -7432 -7433 -7434 -7435 -7436 -7437 -7438 -7439 -7440 -7441 -7442 -7443 -7444 -7445 -7446 -7447 -7448 -7449 -7450 -7451 -7452 -7453 -7454 -7455 -7456 -7457 -7458 -7459 -7460 -7461 -7462 -7463 -7464 -7465 -7466 -7467 -7468 -7469 -7470 -7471 -7472 -7473 -7474 -7475 -7476 -7477 -7478 -7479 -7480 -7481 -7482 -7483 -7484 -7485 -7486 -7487 -7488 -7489 -7490 -7491 -7492 -7493 -7494 -7495 -7496 -7497 -7498 -7499 -7500 -7501 -7502 -7503 -7504 -7505 -7506 -7507 -7508 -7509 -7510 -7511 -7512 -7513 -7514 -7515 -7516 -7517 -7518 -7519 -7520 -7521 -7522 -7523 -7524 -7525 -7526 -7527 -7528 -7529 -7530 -7531 -7532 -7533 -7534 -7535 -7536 -7537 -7538 -7539 -7540 -7541 -7542 -7543 -7544 -7545 -7546 -7547 -7548 -7549 -7550 -7551 -7552 -7553 -7554 -7555 -7556 -7557 -7558 -7559 -7560 -7561 -7562 -7563 -7564 -7565 -7566 -7567 -7568 -7569 -7570 -7571 -7572 -7573 -7574 -7575 -7576 -7577 -7578 -7579 -7580 -7581 -7582 -7583 -7584 -7585 -7586 -7587 -7588 -7589 -7590 -7591 -7592 -7593 -7594 -7595 -7596 -7597 -7598 -7599 -7600 -7601 -7602 -7603 -7604 -7605 -7606 -7607 -7608 -7609 -7610 -7611 -7612 -7613 -7614 -7615 -7616 -7617 -7618 -7619 -7620 -7621 -7622 -7623 -7624 -7625 -7626 -7627 -7628 -7629 -7630 -7631 -7632 -7633 -7634 -7635 -7636 -7637 -7638 -7639 -7640 -7641 -7642 -7643 -7644 -7645 -7646 -7647 -7648 -7649 -7650 -7651 -7652 -7653 -7654 -7655 -7656 -7657 -7658 -7659 -7660 -7661 -7662 -7663 -7664 -7665 -7666 -7667 -7668 -7669 -7670 -7671 -7672 -7673 -7674 -7675 -7676 -7677 -7678 -7679 -7680 -7681 -7682 -7683 -7684 -7685 -7686 -7687 -7688 -7689 -7690 -7691 -7692 -7693 -7694 -7695 -7696 -7697 -7698 -7699 -7700 -7701 -7702 -7703 -7704 -7705 -7706 -7707 -7708 -7709 -7710 -7711 -7712 -7713 -7714 -7715 -7716 -7717 -7718 -7719 -7720 -7721 -7722 -7723 -7724 -7725 -7726 -7727 -7728 -7729 -7730 -7731 -7732 -7733 -7734 -7735 -7736 -7737 -7738 -7739 -7740 -7741 -7742 -7743 -7744 -7745 -7746 -7747 -7748 -7749 -7750 -7751 -7752 -7753 -7754 -7755 -7756 -7757 -7758 -7759 -7760 -7761 -7762 -7763 -7764 -7765 -7766 -7767 -7768 -7769 -7770 -7771 -7772 -7773 -7774 -7775 -7776 -7777 -7778 -7779 -7780 -7781 -7782 -7783 -7784 -7785 -7786 -7787 -7788 -7789 -7790 -7791 -7792 -7793 -7794 -7795 -7796 -7797 -7798 -7799 -7800 -7801 -7802 -7803 -7804 -7805 -7806 -7807 -7808 -7809 -7810 -7811 -7812 -7813 -7814 -7815 -7816 -7817 -7818 -7819 -7820 -7821 -7822 -7823 -7824 -7825 -7826 -7827 -7828 -7829 -7830 -7831 -7832 -7833 -7834 -7835 -7836 -7837 -7838 -7839 -7840 -7841 -7842 -7843 -7844 -7845 -7846 -7847 -7848 -7849 -7850 -7851 -7852 -7853 -7854 -7855 -7856 -7857 -7858 -7859 -7860 -7861 -7862 -7863 -7864 -7865 -7866 -7867 -7868 -7869 -7870 -7871 -7872 -7873 -7874 -7875 -7876 -7877 -7878 -7879 -7880 -7881 -7882 -7883 -7884 -7885 -7886 -7887 -7888 -7889 -7890 -7891 -7892 -7893 -7894 -7895 -7896 -7897 -7898 -7899 -7900 -7901 -7902 -7903 -7904 -7905 -7906 -7907 -7908 -7909 -7910 -7911 -7912 -7913 -7914 -7915 -7916 -7917 -7918 -7919 -7920 -7921 -7922 -7923 -7924 -7925 -7926 -7927 -7928 -7929 -7930 -7931 -7932 -7933 -7934 -7935 -7936 -7937 -7938 -7939 -7940 -7941 -7942 -7943 -7944 -7945 -7946 -7947 -7948 -7949 -7950 -7951 -7952 -7953 -7954 -7955 -7956 -7957 -7958 -7959 -7960 -7961 -7962 -7963 -7964 -7965 -7966 -7967 -7968 -7969 -7970 -7971 -7972 -7973 -7974 -7975 -7976 -7977 -7978 -7979 -7980 -7981 -7982 -7983 -7984 -7985 -7986 -7987 -7988 -7989 -7990 -7991 -7992 -7993 -7994 -7995 -7996 -7997 -7998 -7999 -8000 -8001 -8002 -8003 -8004 -8005 -8006 -8007 -8008 -8009 -8010 -8011 -8012 -8013 -8014 -8015 -8016 -8017 -8018 -8019 -8020 -8021 -8022 -8023 -8024 -8025 -8026 -8027 -8028 -8029 -8030 -8031 -8032 -8033 -8034 -8035 -8036 -8037 -8038 -8039 -8040 -8041 -8042 -8043 -8044 -8045 -8046 -8047 -8048 -8049 -8050 -8051 -8052 -8053 -8054 -8055 -8056 -8057 -8058 -8059 -8060 -8061 -8062 -8063 -8064 -8065 -8066 -8067 -8068 -8069 -8070 -8071 -8072 -8073 -8074 -8075 -8076 -8077 -8078 -8079 -8080 -8081 -8082 -8083 -8084 -8085 -8086 -8087 -8088 -8089 -8090 -8091 -8092 -8093 -8094 -8095 -8096 -8097 -8098 -8099 -8100 -8101 -8102 -8103 -8104 -8105 -8106 -8107 -8108 -8109 -8110 -8111 -8112 -8113 -8114 -8115 -8116 -8117 -8118 -8119 -8120 -8121 -8122 -8123 -8124 -8125 -8126 -8127 -8128 -8129 -8130 -8131 -8132 -8133 -8134 -8135 -8136 -8137 -8138 -8139 -8140 -8141 -8142 -8143 -8144 -8145 -8146 -8147 -8148 -8149 -8150 -8151 -8152 -8153 -8154 -8155 -8156 -8157 -8158 -8159 -8160 -8161 -8162 -8163 -8164 -8165 -8166 -8167 -8168 -8169 -8170 -8171 -8172 -8173 -8174 -8175 -8176 -8177 -8178 -8179 -8180 -8181 -8182 -8183 -8184 -8185 -8186 -8187 -8188 -8189 -8190 -8191 -8192 -8193 -8194 -8195 -8196 -8197 -8198 -8199 -8200 -8201 -8202 -8203 -8204 -8205 -8206 -8207 -8208 -8209 -8210 -8211 -8212 -8213 -8214 -8215 -8216 -8217 -8218 -8219 -8220 -8221 -8222 -8223 -8224 -8225 -8226 -8227 -8228 -8229 -8230 -8231 -8232 -8233 -8234 -8235 -8236 -8237 -8238 -8239 -8240 -8241 -8242 -8243 -8244 -8245 -8246 -8247 -8248 -8249 -8250 -8251 -8252 -8253 -8254 -8255 -8256 -8257 -8258 -8259 -8260 -8261 -8262 -8263 -8264 -8265 -8266 -8267 -8268 -8269 -8270 -8271 -8272 -8273 -8274 -8275 -8276 -8277 -8278 -8279 -8280 -8281 -8282 -8283 -8284 -8285 -8286 -8287 -8288 -8289 -8290 -8291 -8292 -8293 -8294 -8295 -8296 -8297 -8298 -8299 -8300 -8301 -8302 -8303 -8304 -8305 -8306 -8307 -8308 -8309 -8310 -8311 -8312 -8313 -8314 -8315 -8316 -8317 -8318 -8319 -8320 -8321 -8322 -8323 -8324 -8325 -8326 -8327 -8328 -8329 -8330 -8331 -8332 -8333 -8334 -8335 -8336 -8337 -8338 -8339 -8340 -8341 -8342 -8343 -8344 -8345 -8346 -8347 -8348 -8349 -8350 -8351 -8352 -8353 -8354 -8355 -8356 -8357 -8358 -8359 -8360 -8361 -8362 -8363 -8364 -8365 -8366 -8367 -8368 -8369 -8370 -8371 -8372 -8373 -8374 -8375 -8376 -8377 -8378 -8379 -8380 -8381 -8382 -8383 -8384 -8385 -8386 -8387 -8388 -8389 -8390 -8391 -8392 -8393 -8394 -8395 -8396 -8397 -8398 -8399 -8400 -8401 -8402 -8403 -8404 -8405 -8406 -8407 -8408 -8409 -8410 -8411 -8412 -8413 -8414 -8415 -8416 -8417 -8418 -8419 -8420 -8421 -8422 -8423 -8424 -8425 -8426 -8427 -8428 -8429 -8430 -8431 -8432 -8433 -8434 -8435 -8436 -8437 -8438 -8439 -8440 -8441 -8442 -8443 -8444 -8445 -8446 -8447 -8448 -8449 -8450 -8451 -8452 -8453 -8454 -8455 -8456 -8457 -8458 -8459 -8460 -8461 -8462 -8463 -8464 -8465 -8466 -8467 -8468 -8469 -8470 -8471 -8472 -8473 -8474 -8475 -8476 -8477 -8478 -8479 -8480 -8481 -8482 -8483 -8484 -8485 -8486 -8487 -8488 -8489 -8490 -8491 -8492 -8493 -8494 -8495 -8496 -8497 -8498 -8499 -8500 -8501 -8502 -8503 -8504 -8505 -8506 -8507 -8508 -8509 -8510 -8511 -8512 -8513 -8514 -8515 -8516 -8517 -8518 -8519 -8520 -8521 -8522 -8523 -8524 -8525 -8526 -8527 -8528 -8529 -8530 -8531 -8532 -8533 -8534 -8535 -8536 -8537 -8538 -8539 -8540 -8541 -8542 -8543 -8544 -8545 -8546 -8547 -8548 -8549 -8550 -8551 -8552 -8553 -8554 -8555 -8556 -8557 -8558 -8559 -8560 -8561 -8562 -8563 -8564 -8565 -8566 -8567 -8568 -8569 -8570 -8571 -8572 -8573 -8574 -8575 -8576 -8577 -8578 -8579 -8580 -8581 -8582 -8583 -8584 -8585 -8586 -8587 -8588 -8589 -8590 -8591 -8592 -8593 -8594 -8595 -8596 -8597 -8598 -8599 -8600 -8601 -8602 -8603 -8604 -8605 -8606 -8607 -8608 -8609 -8610 -8611 -8612 -8613 -8614 -8615 -8616 -8617 -8618 -8619 -8620 -8621 -8622 -8623 -8624 -8625 -8626 -8627 -8628 -8629 -8630 -8631 -8632 -8633 -8634 -8635 -8636 -8637 -8638 -8639 -8640 -8641 -8642 -8643 -8644 -8645 -8646 -8647 -8648 -8649 -8650 -8651 -8652 -8653 -8654 -8655 -8656 -8657 -8658 -8659 -8660 -8661 -8662 -8663 -8664 -8665 -8666 -8667 -8668 -8669 -8670 -8671 -8672 -8673 -8674 -8675 -8676 -8677 -8678 -8679 -8680 -8681 -8682 -8683 -8684 -8685 -8686 -8687 -8688 -8689 -8690 -8691 -8692 -8693 -8694 -8695 -8696 -8697 -8698 -8699 -8700 -8701 -8702 -8703 -8704 -8705 -8706 -8707 -8708 -8709 -8710 -8711 -8712 -8713 -8714 -8715 -8716 -8717 -8718 -8719 -8720 -8721 -8722 -8723 -8724 -8725 -8726 -8727 -8728 -8729 -8730 -8731 -8732 -8733 -8734 -8735 -8736 -8737 -8738 -8739 -8740 -8741 -8742 -8743 -8744 -8745 -8746 -8747 -8748 -8749 -8750 -8751 -8752 -8753 -8754 -8755 -8756 -8757 -8758 -8759 -8760 -8761 -8762 -8763 -8764 -8765 -8766 -8767 -8768 -8769 -8770 -8771 -8772 -8773 -8774 -8775 -8776 -8777 -8778 -8779 -8780 -8781 -8782 -8783 -8784 -8785 -8786 -8787 -8788 -8789 -8790 -8791 -8792 -8793 -8794 -8795 -8796 -8797 -8798 -8799 -8800 -8801 -8802 -8803 -8804 -8805 -8806 -8807 -8808 -8809 -8810 -8811 -8812 -8813 -8814 -8815 -8816 -8817 -8818 -8819 -8820 -8821 -8822 -8823 -8824 -8825 -8826 -8827 -8828 -8829 -8830 -8831 -8832 -8833 -8834 -8835 -8836 -8837 -8838 -8839 -8840 -8841 -8842 -8843 -8844 -8845 -8846 -8847 -8848 -8849 -8850 -8851 -8852 -8853 -8854 -8855 -8856 -8857 -8858 -8859 -8860 -8861 -8862 -8863 -8864 -8865 -8866 -8867 -8868 -8869 -8870 -8871 -8872 -8873 -8874 -8875 -8876 -8877 -8878 -8879 -8880 -8881 -8882 -8883 -8884 -8885 -8886 -8887 -8888 -8889 -8890 -8891 -8892 -8893 -8894 -8895 -8896 -8897 -8898 -8899 -8900 -8901 -8902 -8903 -8904 -8905 -8906 -8907 -8908 -8909 -8910 -8911 -8912 -8913 -8914 -8915 -8916 -8917 -8918 -8919 -8920 -8921 -8922 -8923 -8924 -8925 -8926 -8927 -8928 -8929 -8930 -8931 -8932 -8933 -8934 -8935 -8936 -8937 -8938 -8939 -8940 -8941 -8942 -8943 -8944 -8945 -8946 -8947 -8948 -8949 -8950 -8951 -8952 -8953 -8954 -8955 -8956 -8957 -8958 -8959 -8960 -8961 -8962 -8963 -8964 -8965 -8966 -8967 -8968 -8969 -8970 -8971 -8972 -8973 -8974 -8975 -8976 -8977 -8978 -8979 -8980 -8981 -8982 -8983 -8984 -8985 -8986 -8987 -8988 -8989 -8990 -8991 -8992 -8993 -8994 -8995 -8996 -8997 -8998 -8999 -9000 -9001 -9002 -9003 -9004 -9005 -9006 -9007 -9008 -9009 -9010 -9011 -9012 -9013 -9014 -9015 -9016 -9017 -9018 -9019 -9020 -9021 -9022 -9023 -9024 -9025 -9026 -9027 -9028 -9029 -9030 -9031 -9032 -9033 -9034 -9035 -9036 -9037 -9038 -9039 -9040 -9041 -9042 -9043 -9044 -9045 -9046 -9047 -9048 -9049 -9050 -9051 -9052 -9053 -9054 -9055 -9056 -9057 -9058 -9059 -9060 -9061 -9062 -9063 -9064 -9065 -9066 -9067 -9068 -9069 -9070 -9071 -9072 -9073 -9074 -9075 -9076 -9077 -9078 -9079 -9080 -9081 -9082 -9083 -9084 -9085 -9086 -9087 -9088 -9089 -9090 -9091 -9092 -9093 -9094 -9095 -9096 -9097 -9098 -9099 -9100 -9101 -9102 -9103 -9104 -9105 -9106 -9107 -9108 -9109 -9110 -9111 -9112 -9113 -9114 -9115 -9116 -9117 -9118 -9119 -9120 -9121 -9122 -9123 -9124 -9125 -9126 -9127 -9128 -9129 -9130 -9131 -9132 -9133 -9134 -9135 -9136 -9137 -9138 -9139 -9140 -9141 -9142 -9143 -9144 -9145 -9146 -9147 -9148 -9149 -9150 -9151 -9152 -9153 -9154 -9155 -9156 -9157 -9158 -9159 -9160 -9161 -9162 -9163 -9164 -9165 -9166 -9167 -9168 -9169 -9170 -9171 -9172 -9173 -9174 -9175 -9176 -9177 -9178 -9179 -9180 -9181 -9182 -9183 -9184 -9185 -9186 -9187 -9188 -9189 -9190 -9191 -9192 -9193 -9194 -9195 -9196 -9197 -9198 -9199 -9200 -9201 -9202 -9203 -9204 -9205 -9206 -9207 -9208 -9209 -9210 -9211 -9212 -9213 -9214 -9215 -9216 -9217 -9218 -9219 -9220 -9221 -9222 -9223 -9224 -9225 -9226 -9227 -9228 -9229 -9230 -9231 -9232 -9233 -9234 -9235 -9236 -9237 -9238 -9239 -9240 -9241 -9242 -9243 -9244 -9245 -9246 -9247 -9248 -9249 -9250 -9251 -9252 -9253 -9254 -9255 -9256 -9257 -9258 -9259 -9260 -9261 -9262 -9263 -9264 -9265 -9266 -9267 -9268 -9269 -9270 -9271 -9272 -9273 -9274 -9275 -9276 -9277 -9278 -9279 -9280 -9281 -9282 -9283 -9284 -9285 -9286 -9287 -9288 -9289 -9290 -9291 -9292 -9293 -9294 -9295 -9296 -9297 -9298 -9299 -9300 -9301 -9302 -9303 -9304 -9305 -9306 -9307 -9308 -9309 -9310 -9311 -9312 -9313 -9314 -9315 -9316 -9317 -9318 -9319 -9320 -9321 -9322 -9323 -9324 -9325 -9326 -9327 -9328 -9329 -9330 -9331 -9332 -9333 -9334 -9335 -9336 -9337 -9338 -9339 -9340 -9341 -9342 -9343 -9344 -9345 -9346 -9347 -9348 -9349 -9350 -9351 -9352 -9353 -9354 -9355 -9356 -9357 -9358 -9359 -9360 -9361 -9362 -9363 -9364 -9365 -9366 -9367 -9368 -9369 -9370 -9371 -9372 -9373 -9374 -9375 -9376 -9377 -9378 -9379 -9380 -9381 -9382 -9383 -9384 -9385 -9386 -9387 -9388 -9389 -9390 -9391 -9392 -9393 -9394 -9395 -9396 -9397 -9398 -9399 -9400 -9401 -9402 -9403 -9404 -9405 -9406 -9407 -9408 -9409 -9410 -9411 -9412 -9413 -9414 -9415 -9416 -9417 -9418 -9419 -9420 -9421 -9422 -9423 -9424 -9425 -9426 -9427 -9428 -9429 -9430 -9431 -9432 -9433 -9434 -9435 -9436 -9437 -9438 -9439 -9440 -9441 -9442 -9443 -9444 -9445 -9446 -9447 -9448 -9449 -9450 -9451 -9452 -9453 -9454 -9455 -9456 -9457 -9458 -9459 -9460 -9461 -9462 -9463 -9464 -9465 -9466 -9467 -9468 -9469 -9470 -9471 -9472 -9473 -9474 -9475 -9476 -9477 -9478 -9479 -9480 -9481 -9482 -9483 -9484 -9485 -9486 -9487 -9488 -9489 -9490 -9491 -9492 -9493 -9494 -9495 -9496 -9497 -9498 -9499 -9500 -9501 -9502 -9503 -9504 -9505 -9506 -9507 -9508 -9509 -9510 -9511 -9512 -9513 -9514 -9515 -9516 -9517 -9518 -9519 -9520 -9521 -9522 -9523 -9524 -9525 -9526 -9527 -9528 -9529 -9530 -9531 -9532 -9533 -9534 -9535 -9536 -9537 -9538 -9539 -9540 -9541 -9542 -9543 -9544 -9545 -9546 -9547 -9548 -9549 -9550 -9551 -9552 -9553 -9554 -9555 -9556 -9557 -9558 -9559 -9560 -9561 -9562 -9563 -9564 -9565 -9566 -9567 -9568 -9569 -9570 -9571 -9572 -9573 -9574 -9575 -9576 -9577 -9578 -9579 -9580 -9581 -9582 -9583 -9584 -9585 -9586 -9587 -9588 -9589 -9590 -9591 -9592 -9593 -9594 -9595 -9596 -9597 -9598 -9599 -9600 -9601 -9602 -9603 -9604 -9605 -9606 -9607 -9608 -9609 -9610 -9611 -9612 -9613 -9614 -9615 -9616 -9617 -9618 -9619 -9620 -9621 -9622 -9623 -9624 -9625 -9626 -9627 -9628 -9629 -9630 -9631 -9632 -9633 -9634 -9635 -9636 -9637 -9638 -9639 -9640 -9641 -9642 -9643 -9644 -9645 -9646 -9647 -9648 -9649 -9650 -9651 -9652 -9653 -9654 -9655 -9656 -9657 -9658 -9659 -9660 -9661 -9662 -9663 -9664 -9665 -9666 -9667 -9668 -9669 -9670 -9671 -9672 -9673 -9674 -9675 -9676 -9677 -9678 -9679 -9680 -9681 -9682 -9683 -9684 -9685 -9686 -9687 -9688 -9689 -9690 -9691 -9692 -9693 -9694 -9695 -9696 -9697 -9698 -9699 -9700 -9701 -9702 -9703 -9704 -9705 -9706 -9707 -9708 -9709 -9710 -9711 -9712 -9713 -9714 -9715 -9716 -9717 -9718 -9719 -9720 -9721 -9722 -9723 -9724 -9725 -9726 -9727 -9728 -9729 -9730 -9731 -9732 -9733 -9734 -9735 -9736 -9737 -9738 -9739 -9740 -9741 -9742 -9743 -9744 -9745 -9746 -9747 -9748 -9749 -9750 -9751 -9752 -9753 -9754 -9755 -9756 -9757 -9758 -9759 -9760 -9761 -9762 -9763 -9764 -9765 -9766 -9767 -9768 -9769 -9770 -9771 -9772 -9773 -9774 -9775 -9776 -9777 -9778 -9779 -9780 -9781 -9782 -9783 -9784 -9785 -9786 -9787 -9788 -9789 -9790 -9791 -9792 -9793 -9794 -9795 -9796 -9797 -9798 -9799 -9800 -9801 -9802 -9803 -9804 -9805 -9806 -9807 -9808 -9809 -9810 -9811 -9812 -9813 -9814 -9815 -9816 -9817 -9818 -9819 -9820 -9821 -9822 -9823 -9824 -9825 -9826 -9827 -9828 -9829 -9830 -9831 -9832 -9833 -9834 -9835 -9836 -9837 -9838 -9839 -9840 -9841 -9842 -9843 -9844 -9845 -9846 -9847 -9848 -9849 -9850 -9851 -9852 -9853 -9854 -9855 -9856 -9857 -9858 -9859 -9860 -9861 -9862 -9863 -9864 -9865 -9866 -9867 -9868 -9869 -9870 -9871 -9872 -9873 -9874 -9875 -9876 -9877 -9878 -9879 -9880 -9881 -9882 -9883 -9884 -9885 -9886 -9887 -9888 -9889 -9890 -9891 -9892 -9893 -9894 -9895 -9896 -9897 -9898 -9899 -9900 -9901 -9902 -9903 -9904 -9905 -9906 -9907 -9908 -9909 -9910 -9911 -9912 -9913 -9914 -9915 -9916 -9917 -9918 -9919 -9920 -9921 -9922 -9923 -9924 -9925 -9926 -9927 -9928 -9929 -9930 -9931 -9932 -9933 -9934 -9935 -9936 -9937 -9938 -9939 -9940 -9941 -9942 -9943 -9944 -9945 -9946 -9947 -9948 -9949 -9950 -9951 -9952 -9953 -9954 -9955 -9956 -9957 -9958 -9959 -9960 -9961 -9962 -9963 -9964 -9965 -9966 -9967 -9968 -9969 -9970 -9971 -9972 -9973 -9974 -9975 -9976 -9977 -9978 -9979 -9980 -9981 -9982 -9983 -9984 -9985 -9986 -9987 -9988 -9989 -9990 -9991 -9992 -9993 -9994 -9995 -9996 -9997 -9998 -9999 -10000 -10001 -10002 -10003 -10004 -10005 -10006 -10007 -10008 -10009 -10010 -10011 -10012 -10013 -10014 -10015 -10016 -10017 -10018 -10019 -10020 -10021 -10022 -10023 -10024 -10025 -10026 -10027 -10028 -10029 -10030 -10031 -10032 -10033 -10034 -10035 -10036 -10037 -10038 -10039 -10040 -10041 -10042 -10043 -10044 -10045 -10046 -10047 -10048 -10049 -10050 -10051 -10052 -10053 -10054 -10055 -10056 -10057 -10058 -10059 -10060 -10061 -10062 -10063 -10064 -10065 -10066 -10067 -10068 -10069 -10070 -10071 -10072 -10073 -10074 -10075 -10076 -10077 -10078 -10079 -10080 -10081 -10082 -10083 -10084 -10085 -10086 -10087 -10088 -10089 -10090 -10091 -10092 -10093 -10094 -10095 -10096 -10097 -10098 -10099 -10100 -10101 -10102 -10103 -10104 -10105 -10106 -10107 -10108 -10109 -10110 -10111 -10112 -10113 -10114 -10115 -10116 -10117 -10118 -10119 -10120 -10121 -10122 -10123 -10124 -10125 -10126 -10127 -10128 -10129 -10130 -10131 -10132 -10133 -10134 -10135 -10136 -10137 -10138 -10139 -10140 -10141 -10142 -10143 -10144 -10145 -10146 -10147 -10148 -10149 -10150 -10151 -10152 -10153 -10154 -10155 -10156 -10157 -10158 -10159 -10160 -10161 -10162 -10163 -10164 -10165 -10166 -10167 -10168 -10169 -10170 -10171 -10172 -10173 -10174 -10175 -10176 -10177 -10178 -10179 -10180 -10181 -10182 -10183 -10184 -10185 -10186 -10187 -10188 -10189 -10190 -10191 -10192 -10193 -10194 -10195 -10196 -10197 -10198 -10199 -10200 -10201 -10202 -10203 -10204 -10205 -10206 -10207 -10208 -10209 -10210 -10211 -10212 -10213 -10214 -10215 -10216 -10217 -10218 -10219 -10220 -10221 -10222 -10223 -10224 -10225 -10226 -10227 -10228 -10229 -10230 -10231 -10232 -10233 -10234 -10235 -10236 -10237 -10238 -10239 -10240 -10241 -10242 -10243 -10244 -10245 -10246 -10247 -10248 -10249 -10250 -10251 -10252 -10253 -10254 -10255 -10256 -10257 -10258 -10259 -10260 -10261 -10262 -10263 -10264 -10265 -10266 -10267 -10268 -10269 -10270 -10271 -10272 -10273 -10274 -10275 -10276 -10277 -10278 -10279 -10280 -10281 -10282 -10283 -10284 -10285 -10286 -10287 -10288 -10289 -10290 -10291 -10292 -10293 -10294 -10295 -10296 -10297 -10298 -10299 -10300 -10301 -10302 -10303 -10304 -10305 -10306 -10307 -10308 -10309 -10310 -10311 -10312 -10313 -10314 -10315 -10316 -10317 -10318 -10319 -10320 -10321 -10322 -10323 -10324 -10325 -10326 -10327 -10328 -10329 -10330 -10331 -10332 -10333 -10334 -10335 -10336 -10337 -10338 -10339 -10340 -10341 -10342 -10343 -10344 -10345 -10346 -10347 -10348 -10349 -10350 -10351 -10352 -10353 -10354 -10355 -10356 -10357 -10358 -10359 -10360 -10361 -10362 -10363 -10364 -10365 -10366 -10367 -10368 -10369 -10370 -10371 -10372 -10373 -10374 -10375 -10376 -10377 -10378 -10379 -10380 -10381 -10382 -10383 -10384 -10385 -10386 -10387 -10388 -10389 -10390 -10391 -10392 -10393 -10394 -10395 -10396 -10397 -10398 -10399 -10400 -10401 -10402 -10403 -10404 -10405 -10406 -10407 -10408 -10409 -10410 -10411 -10412 -10413 -10414 -10415 -10416 -10417 -10418 -10419 -10420 -10421 -10422 -10423 -10424 -10425 -10426 -10427 -10428 -10429 -10430 -10431 -10432 -10433 -10434 -10435 -10436 -10437 -10438 -10439 -10440 -10441 -10442 -10443 -10444 -10445 -10446 -10447 -10448 -10449 -10450 -10451 -10452 -10453 -10454 -10455 -10456 -10457 -10458 -10459 -10460 -10461 -10462 -10463 -10464 -10465 -10466 -10467 -10468 -10469 -10470 -10471 -10472 -10473 -10474 -10475 -10476 -10477 -10478 -10479 -10480 -10481 -10482 -10483 -10484 -10485 -10486 -10487 -10488 -10489 -10490 -10491 -10492 -10493 -10494 -10495 -10496 -10497 -10498 -10499 -10500 -10501 -10502 -10503 -10504 -10505 -10506 -10507 -10508 -10509 -10510 -10511 -10512 -10513 -10514 -10515 -10516 -10517 -10518 -10519 -10520 -10521 -10522 -10523 -10524 -10525 -10526 -10527 -10528 -10529 -10530 -10531 -10532 -10533 -10534 -10535 -10536 -10537 -10538 -10539 -10540 -10541 -10542 -10543 -10544 -10545 -10546 -10547 -10548 -10549 -10550 -10551 -10552 -10553 -10554 -10555 -10556 -10557 -10558 -10559 -10560 -10561 -10562 -10563 -10564 -10565 -10566 -10567 -10568 -10569 -10570 -10571 -10572 -10573 -10574 -10575 -10576 -10577 -10578 -10579 -10580 -10581 -10582 -10583 -10584 -10585 -10586 -10587 -10588 -10589 -10590 -10591 -10592 -10593 -10594 -10595 -10596 -10597 -10598 -10599 -10600 -10601 -10602 -10603 -10604 -10605 -10606 -10607 -10608 -10609 -10610 -10611 -10612 -10613 -10614 -10615 -10616 -10617 -10618 -10619 -10620 -10621 -10622 -10623 -10624 -10625 -10626 -10627 -10628 -10629 -10630 -10631 -10632 -10633 -10634 -10635 -10636 -10637 -10638 -10639 -10640 -10641 -10642 -10643 -10644 -10645 -10646 -10647 -10648 -10649 -10650 -10651 -10652 -10653 -10654 -10655 -10656 -10657 -10658 -10659 -10660 -10661 -10662 -10663 -10664 -10665 -10666 -10667 -10668 -10669 -10670 -10671 -10672 -10673 -10674 -10675 -10676 -10677 -10678 -10679 -10680 -10681 -10682 -10683 -10684 -10685 -10686 -10687 -10688 -10689 -10690 -10691 -10692 -10693 -10694 -10695 -10696 -10697 -10698 -10699 -10700 -10701 -10702 -10703 -10704 -10705 -10706 -10707 -10708 -10709 -10710 -10711 -10712 -10713 -10714 -10715 -10716 -10717 -10718 -10719 -10720 -10721 -10722 -10723 -10724 -10725 -10726 -10727 -10728 -10729 -10730 -10731 -10732 -10733 -10734 -10735 -10736 -10737 -10738 -10739 -10740 -10741 -10742 -10743 -10744 -10745 -10746 -10747 -10748 -10749 -10750 -10751 -10752 -10753 -10754 -10755 -10756 -10757 -10758 -10759 -10760 -10761 -10762 -10763 -10764 -10765 -10766 -10767 -10768 -10769 -10770 -10771 -10772 -10773 -10774 -10775 -10776 -10777 -10778 -10779 -10780 -10781 -10782 -10783 -10784 -10785 -10786 -10787 -10788 -10789 -10790 -10791 -10792 -10793 -10794 -10795 -10796 -10797 -10798 -10799 -10800 -10801 -10802 -10803 -10804 -10805 -10806 -10807 -10808 -10809 -10810 -10811 -10812 -10813 -10814 -10815 -10816 -10817 -10818 -10819 -10820 -10821 -10822 -10823 -10824 -10825 -10826 -10827 -10828 -10829 -10830 -10831 -10832 -10833 -10834 -10835 -10836 -10837 -10838 -10839 -10840 -10841 -10842 -10843 -10844 -10845 -10846 -10847 -10848 -10849 -10850 -10851 -10852 -10853 -10854 -10855 -10856 -10857 -10858 -10859 -10860 -10861 -10862 -10863 -10864 -10865 -10866 -10867 -10868 -10869 -10870 -10871 -10872 -10873 -10874 -10875 -10876 -10877 -10878 -10879 -10880 -10881 -10882 -10883 -10884 -10885 -10886 -10887 -10888 -10889 -10890 -10891 -10892 -10893 -10894 -10895 -10896 -10897 -10898 -10899 -10900 -10901 -10902 -10903 -10904 -10905 -10906 -10907 -10908 -10909 -10910 -10911 -10912 -10913 -10914 -10915 -10916 -10917 -10918 -10919 -10920 -10921 -10922 -10923 -10924 -10925 -10926 -10927 -10928 -10929 -10930 -10931 -10932 -10933 -10934 -10935 -10936 -10937 -10938 -10939 -10940 -10941 -10942 -10943 -10944 -10945 -10946 -10947 -10948 -10949 -10950 -10951 -10952 -10953 -10954 -10955 -10956 -10957 -10958 -10959 -10960 -10961 -10962 -10963 -10964 -10965 -10966 -10967 -10968 -10969 -10970 -10971 -10972 -10973 -10974 -10975 -10976 -10977 -10978 -10979 -10980 -10981 -10982 -10983 -10984 -10985 -10986 -10987 -10988 -10989 -10990 -10991 -10992 -10993 -10994 -10995 -10996 -10997 -10998 -10999 -11000 -11001 -11002 -11003 -11004 -11005 -11006 -11007 -11008 -11009 -11010 -11011 -11012 -11013 -11014 -11015 -11016 -11017 -11018 -11019 -11020 -11021 -11022 -11023 -11024 -11025 -11026 -11027 -11028 -11029 -11030 -11031 -11032 -11033 -11034 -11035 -11036 -11037 -11038 -11039 -11040 -11041 -11042 -11043 -11044 -11045 -11046 -11047 -11048 -11049 -11050 -11051 -11052 -11053 -11054 -11055 -11056 -11057 -11058 -11059 -11060 -11061 -11062 -11063 -11064 -11065 -11066 -11067 -11068 -11069 -11070 -11071 -11072 -11073 -11074 -11075 -11076 -11077 -11078 -11079 -11080 -11081 -11082 -11083 -11084 -11085 -11086 -11087 -11088 -11089 -11090 -11091 -11092 -11093 -11094 -11095 -11096 -11097 -11098 -11099 -11100 -11101 -11102 -11103 -11104 -11105 -11106 -11107 -11108 -11109 -11110 -11111 -11112 -11113 -11114 -11115 -11116 -11117 -11118 -11119 -11120 -11121 -11122 -11123 -11124 -11125 -11126 -11127 -11128 -11129 -11130 -11131 -11132 -11133 -11134 -11135 -11136 -11137 -11138 -11139 -11140 -11141 -11142 -11143 -11144 -11145 -11146 -11147 -11148 -11149 -11150 -11151 -11152 -11153 -11154 -11155 -11156 -11157 -11158 -11159 -11160 -11161 -11162 -11163 -11164 -11165 -11166 -11167 -11168 -11169 -11170 -11171 -11172 -11173 -11174 -11175 -11176 -11177 -11178 -11179 -11180 -11181 -11182 -11183 -11184 -11185 -11186 -11187 -11188 -11189 -11190 -11191 -11192 -11193 -11194 -11195 -11196 -11197 -11198 -11199 -11200 -11201 -11202 -11203 -11204 -11205 -11206 -11207 -11208 -11209 -11210 -11211 -11212 -11213 -11214 -11215 -11216 -11217 -11218 -11219 -11220 -11221 -11222 -11223 -11224 -11225 -11226 -11227 -11228 -11229 -11230 -11231 -11232 -11233 -11234 -11235 -11236 -11237 -11238 -11239 -11240 -11241 -11242 -11243 -11244 -11245 -11246 -11247 -11248 -11249 -11250 -11251 -11252 -11253 -11254 -11255 -11256 -11257 -11258 -11259 -11260 -11261 -11262 -11263 -11264 -11265 -11266 -11267 -11268 -11269 -11270 -11271 -11272 -11273 -11274 -11275 -11276 -11277 -11278 -11279 -11280 -11281 -11282 -11283 -11284 -11285 -11286 -11287 -11288 -11289 -11290 -11291 -11292 -11293 -11294 -11295 -11296 -11297 -11298 -11299 -11300 -11301 -11302 -11303 -11304 -11305 -11306 -11307 -11308 -11309 -11310 -11311 -11312 -11313 -11314 -11315 -11316 -11317 -11318 -11319 -11320 -11321 -11322 -11323 -11324 -11325 -11326 -11327 -11328 -11329 -11330 -11331 -11332 -11333 -11334 -11335 -11336 -11337 -11338 -11339 -11340 -11341 -11342 -11343 -11344 -11345 -11346 -11347 -11348 -11349 -11350 -11351 -11352 -11353 -11354 -11355 -11356 -11357 -11358 -11359 -11360 -11361 -11362 -11363 -11364 -11365 -11366 -11367 -11368 -11369 -11370 -11371 -11372 -11373 -11374 -11375 -11376 -11377 -11378 -11379 -11380 -11381 -11382 -11383 -11384 -11385 -11386 -11387 -11388 -11389 -11390 -11391 -11392 -11393 -11394 -11395 -11396 -11397 -11398 -11399 -11400 -11401 -11402 -11403 -11404 -11405 -11406 -11407 -11408 -11409 -11410 -11411 -11412 -11413 -11414 -11415 -11416 -11417 -11418 -11419 -11420 -11421 -11422 -11423 -11424 -11425 -11426 -11427 -11428 -11429 -11430 -11431 -11432 -11433 -11434 -11435 -11436 -11437 -11438 -11439 -11440 -11441 -11442 -11443 -11444 -11445 -11446 -11447 -11448 -11449 -11450 -11451 -11452 -11453 -11454 -11455 -11456 -11457 -11458 -11459 -11460 -11461 -11462 -11463 -11464 -11465 -11466 -11467 -11468 -11469 -11470 -11471 -11472 -11473 -11474 -11475 -11476 -11477 -11478 -11479 -11480 -11481 -11482 -11483 -11484 -11485 -11486 -11487 -11488 -11489 -11490 -11491 -11492 -11493 -11494 -11495 -11496 -11497 -11498 -11499 -11500 -11501 -11502 -11503 -11504 -11505 -11506 -11507 -11508 -11509 -11510 -11511 -11512 -11513 -11514 -11515 -11516 -11517 -11518 -11519 -11520 -11521 -11522 -11523 -11524 -11525 -11526 -11527 -11528 -11529 -11530 -11531 -11532 -11533 -11534 -11535 -11536 -11537 -11538 -11539 -11540 -11541 -11542 -11543 -11544 -11545 -11546 -11547 -11548 -11549 -11550 -11551 -11552 -11553 -11554 -11555 -11556 -11557 -11558 -11559 -11560 -11561 -11562 -11563 -11564 -11565 -11566 -11567 -11568 -11569 -11570 -11571 -11572 -11573 -11574 -11575 -11576 -11577 -11578 -11579 -11580 -11581 -11582 -11583 -11584 -11585 -11586 -11587 -11588 -11589 -11590 -11591 -11592 -11593 -11594 -11595 -11596 -11597 -11598 -11599 -11600 -11601 -11602 -11603 -11604 -11605 -11606 -11607 -11608 -11609 -11610 -11611 -11612 -11613 -11614 -11615 -11616 -11617 -11618 -11619 -11620 -11621 -11622 -11623 -11624 -11625 -11626 -11627 -11628 -11629 -11630 -11631 -11632 -11633 -11634 -11635 -11636 -11637 -11638 -11639 -11640 -11641 -11642 -11643 -11644 -11645 -11646 -11647 -11648 -11649 -11650 -11651 -11652 -11653 -11654 -11655 -11656 -11657 -11658 -11659 -11660 -11661 -11662 -11663 -11664 -11665 -11666 -11667 -11668 -11669 -11670 -11671 -11672 -11673 -11674 -11675 -11676 -11677 -11678 -11679 -11680 -11681 -11682 -11683 -11684 -11685 -11686 -11687 -11688 -11689 -11690 -11691 -11692 -11693 -11694 -11695 -11696 -11697 -11698 -11699 -11700 -11701 -11702 -11703 -11704 -11705 -11706 -11707 -11708 -11709 -11710 -11711 -11712 -11713 -11714 -11715 -11716 -11717 -11718 -11719 -11720 -11721 -11722 -11723 -11724 -11725 -11726 -11727 -11728 -11729 -11730 -11731 -11732 -11733 -11734 -11735 -11736 -11737 -11738 -11739 -11740 -11741 -11742 -11743 -11744 -11745 -11746 -11747 -11748 -11749 -11750 -11751 -11752 -11753 -11754 -11755 -11756 -11757 -11758 -11759 -11760 -11761 -11762 -11763 -11764 -11765 -11766 -11767 -11768 -11769 -11770 -11771 -11772 -11773 -11774 -11775 -11776 -11777 -11778 -11779 -11780 -11781 -11782 -11783 -11784 -11785 -11786 -11787 -11788 -11789 -11790 -11791 -11792 -11793 -11794 -11795 -11796 -11797 -11798 -11799 -11800 -11801 -11802 -11803 -11804 -11805 -11806 -11807 -11808 -11809 -11810 -11811 -11812 -11813 -11814 -11815 -11816 -11817 -11818 -11819 -11820 -11821 -11822 -11823 -11824 -11825 -11826 -11827 -11828 -11829 -11830 -11831 -11832 -11833 -11834 -11835 -11836 -11837 -11838 -11839 -11840 -11841 -11842 -11843 -11844 -11845 -11846 -11847 -11848 -11849 -11850 -11851 -11852 -11853 -11854 -11855 -11856 -11857 -11858 -11859 -11860 -11861 -11862 -11863 -11864 -11865 -11866 -11867 -11868 -11869 -11870 -11871 -11872 -11873 -11874 -11875 -11876 -11877 -11878 -11879 -11880 -11881 -11882 -11883 -11884 -11885 -11886 -11887 -11888 -11889 -11890 -11891 -11892 -11893 -11894 -11895 -11896 -11897 -11898 -11899 -11900 -11901 -11902 -11903 -11904 -11905 -11906 -11907 -11908 -11909 -11910 -11911 -11912 -11913 -11914 -11915 -11916 -11917 -11918 -11919 -11920 -11921 -11922 -11923 -11924 -11925 -11926 -11927 -11928 -11929 -11930 -11931 -11932 -11933 -11934 -11935 -11936 -11937 -11938 -11939 -11940 -11941 -11942 -11943 -11944 -11945 -11946 -11947 -11948 -11949 -11950 -11951 -11952 -11953 -11954 -11955 -11956 -11957 -11958 -11959 -11960 -11961 -11962 -11963 -11964 -11965 -11966 -11967 -11968 -11969 -11970 -11971 -11972 -11973 -11974 -11975 -11976 -11977 -11978 -11979 -11980 -11981 -11982 -11983 -11984 -11985 -11986 -11987 -11988 -11989 -11990 -11991 -11992 -11993 -11994 -11995 -11996 -11997 -11998 -11999 -12000 -12001 -12002 -12003 -12004 -12005 -12006 -12007 -12008 -12009 -12010 -12011 -12012 -12013 -12014 -12015 -12016 -12017 -12018 -12019 -12020 -12021 -12022 -12023 -12024 -12025 -12026 -12027 -12028 -12029 -12030 -12031 -12032 -12033 -12034 -12035 -12036 -12037 -12038 -12039 -12040 -12041 -12042 -12043 -12044 -12045 -12046 -12047 -12048 -12049 -12050 -12051 -12052 -12053 -12054 -12055 -12056 -12057 -12058 -12059 -12060 -12061 -12062 -12063 -12064 -12065 -12066 -12067 -12068 -12069 -12070 -12071 -12072 -12073 -12074 -12075 -12076 -12077 -12078 -12079 -12080 -12081 -12082 -12083 -12084 -12085 -12086 -12087 -12088 -12089 -12090 -12091 -12092 -12093 -12094 -12095 -12096 -12097 -12098 -12099 -12100 -12101 -12102 -12103 -12104 -12105 -12106 -12107 -12108 -12109 -12110 -12111 -12112 -12113 -12114 -12115 -12116 -12117 -12118 -12119 -12120 -12121 -12122 -12123 -12124 -12125 -12126 -12127 -12128 -12129 -12130 -12131 -12132 -12133 -12134 -12135 -12136 -12137 -12138 -12139 -12140 -12141 -12142 -12143 -12144 -12145 -12146 -12147 -12148 -12149 -12150 -12151 -12152 -12153 -12154 -12155 -12156 -12157 -12158 -12159 -12160 -12161 -12162 -12163 -12164 -12165 -12166 -12167 -12168 -12169 -12170 -12171 -12172 -12173 -12174 -12175 -12176 -12177 -12178 -12179 -12180 -12181 -12182 -12183 -12184 -12185 -12186 -12187 -12188 -12189 -12190 -12191 -12192 -12193 -12194 -12195 -12196 -12197 -12198 -12199 -12200 -12201 -12202 -12203 -12204 -12205 -12206 -12207 -12208 -12209 -12210 -12211 -12212 -12213 -12214 -12215 -12216 -12217 -12218 -12219 -12220 -12221 -12222 -12223 -12224 -12225 -12226 -12227 -12228 -12229 -12230 -12231 -12232 -12233 -12234 -12235 -12236 -12237 -12238 -12239 -12240 -12241 -12242 -12243 -12244 -12245 -12246 -12247 -12248 -12249 -12250 -12251 -12252 -12253 -12254 -12255 -12256 -12257 -12258 -12259 -12260 -12261 -12262 -12263 -12264 -12265 -12266 -12267 -12268 -12269 -12270 -12271 -12272 -12273 -12274 -12275 -12276 -12277 -12278 -12279 -12280 -12281 -12282 -12283 -12284 -12285 -12286 -12287 -12288 -12289 -12290 -12291 -12292 -12293 -12294 -12295 -12296 -12297 -12298 -12299 -12300 -12301 -12302 -12303 -12304 -12305 -12306 -12307 -12308 -12309 -12310 -12311 -12312 -12313 -12314 -12315 -12316 -12317 -12318 -12319 -12320 -12321 -12322 -12323 -12324 -12325 -12326 -12327 -12328 -12329 -12330 -12331 -12332 -12333 -12334 -12335 -12336 -12337 -12338 -12339 -12340 -12341 -12342 -12343 -12344 -12345 -12346 -12347 -12348 -12349 -12350 -12351 -12352 -12353 -12354 -12355 -12356 -12357 -12358 -12359 -12360 -12361 -12362 -12363 -12364 -12365 -12366 -12367 -12368 -12369 -12370 -12371 -12372 -12373 -12374 -12375 -12376 -12377 -12378 -12379 -12380 -12381 -12382 -12383 -12384 -12385 -12386 -12387 -12388 -12389 -12390 -12391 -12392 -12393 -12394 -12395 -12396 -12397 -12398 -12399 -12400 -12401 -12402 -12403 -12404 -12405 -12406 -12407 -12408 -12409 -12410 -12411 -12412 -12413 -12414 -12415 -12416 -12417 -12418 -12419 -12420 -12421 -12422 -12423 -12424 -12425 -12426 -12427 -12428 -12429 -12430 -12431 -12432 -12433 -12434 -12435 -12436 -12437 -12438 -12439 -12440 -12441 -12442 -12443 -12444 -12445 -12446 -12447 -12448 -12449 -12450 -12451 -12452 -12453 -12454 -12455 -12456 -12457 -12458 -12459 -12460 -12461 -12462 -12463 -12464 -12465 -12466 -12467 -12468 -12469 -12470 -12471 -12472 -12473 -12474 -12475 -12476 -12477 -12478 -12479 -12480 -12481 -12482 -12483 -12484 -12485 -12486 -12487 -12488 -12489 -12490 -12491 -12492 -12493 -12494 -12495 -12496 -12497 -12498 -12499 -12500 -12501 -12502 -12503 -12504 -12505 -12506 -12507 -12508 -12509 -12510 -12511 -12512 -12513 -12514 -12515 -12516 -12517 -12518 -12519 -12520 -12521 -12522 -12523 -12524 -12525 -12526 -12527 -12528 -12529 -12530 -12531 -12532 -12533 -12534 -12535 -12536 -12537 -12538 -12539 -12540 -12541 -12542 -12543 -12544 -12545 -12546 -12547 -12548 -12549 -12550 -12551 -12552 -12553 -12554 -12555 -12556 -12557 -12558 -12559 -12560 -12561 -12562 -12563 -12564 -12565 -12566 -12567 -12568 -12569 -12570 -12571 -12572 -12573 -12574 -12575 -12576 -12577 -12578 -12579 -12580 -12581 -12582 -12583 -12584 -12585 -12586 -12587 -12588 -12589 -12590 -12591 -12592 -12593 -12594 -12595 -12596 -12597 -12598 -12599 -12600 -12601 -12602 -12603 -12604 -12605 -12606 -12607 -12608 -12609 -12610 -12611 -12612 -12613 -12614 -12615 -12616 -12617 -12618 -12619 -12620 -12621 -12622 -12623 -12624 -12625 -12626 -12627 -12628 -12629 -12630 -12631 -12632 -12633 -12634 -12635 -12636 -12637 -12638 -12639 -12640 -12641 -12642 -12643 -12644 -12645 -12646 -12647 -12648 -12649 -12650 -12651 -12652 -12653 -12654 -12655 -12656 -12657 -12658 -12659 -12660 -12661 -12662 -12663 -12664 -12665 -12666 -12667 -12668 -12669 -12670 -12671 -12672 -12673 -12674 -12675 -12676 -12677 -12678 -12679 -12680 -12681 -12682 -12683 -12684 -12685 -12686 -12687 -12688 -12689 -12690 -12691 -12692 -12693 -12694 -12695 -12696 -12697 -12698 -12699 -12700 -12701 -12702 -12703 -12704 -12705 -12706 -12707 -12708 -12709 -12710 -12711 -12712 -12713 -12714 -12715 -12716 -12717 -12718 -12719 -12720 -12721 -12722 -12723 -12724 -12725 -12726 -12727 -12728 -12729 -12730 -12731 -12732 -12733 -12734 -12735 -12736 -12737 -12738 -12739 -12740 -12741 -12742 -12743 -12744 -12745 -12746 -12747 -12748 -12749 -12750 -12751 -12752 -12753 -12754 -12755 -12756 -12757 -12758 -12759 -12760 -12761 -12762 -12763 -12764 -12765 -12766 -12767 -12768 -12769 -12770 -12771 -12772 -12773 -12774 -12775 -12776 -12777 -12778 -12779 -12780 -12781 -12782 -12783 -12784 -12785 -12786 -12787 -12788 -12789 -12790 -12791 -12792 -12793 -12794 -12795 -12796 -12797 -12798 -12799 -12800 -12801 -12802 -12803 -12804 -12805 -12806 -12807 -12808 -12809 -12810 -12811 -12812 -12813 -12814 -12815 -12816 -12817 -12818 -12819 -12820 -12821 -12822 -12823 -12824 -12825 -12826 -12827 -12828 -12829 -12830 -12831 -12832 -12833 -12834 -12835 -12836 -12837 -12838 -12839 -12840 -12841 -12842 -12843 -12844 -12845 -12846 -12847 -12848 -12849 -12850 -12851 -12852 -12853 -12854 -12855 -12856 -12857 -12858 -12859 -12860 -12861 -12862 -12863 -12864 -12865 -12866 -12867 -12868 -12869 -12870 -12871 -12872 -12873 -12874 -12875 -12876 -12877 -12878 -12879 -12880 -12881 -12882 -12883 -12884 -12885 -12886 -12887 -12888 -12889 -12890 -12891 -12892 -12893 -12894 -12895 -12896 -12897 -12898 -12899 -12900 -12901 -12902 -12903 -12904 -12905 -12906 -12907 -12908 -12909 -12910 -12911 -12912 -12913 -12914 -12915 -12916 -12917 -12918 -12919 -12920 -12921 -12922 -12923 -12924 -12925 -12926 -12927 -12928 -12929 -12930 -12931 -12932 -12933 -12934 -12935 -12936 -12937 -12938 -12939 -12940 -12941 -12942 -12943 -12944 -12945 -12946 -12947 -12948 -12949 -12950 -12951 -12952 -12953 -12954 -12955 -12956 -12957 -12958 -12959 -12960 -12961 -12962 -12963 -12964 -12965 -12966 -12967 -12968 -12969 -12970 -12971 -12972 -12973 -12974 -12975 -12976 -12977 -12978 -12979 -12980 -12981 -12982 -12983 -12984 -12985 -12986 -12987 -12988 -12989 -12990 -12991 -12992 -12993 -12994 -12995 -12996 -12997 -12998 -12999 -13000 -13001 -13002 -13003 -13004 -13005 -13006 -13007 -13008 -13009 -13010 -13011 -13012 -13013 -13014 -13015 -13016 -13017 -13018 -13019 -13020 -13021 -13022 -13023 -13024 -13025 -13026 -13027 -13028 -13029 -13030 -13031 -13032 -13033 -13034 -13035 -13036 -13037 -13038 -13039 -13040 -13041 -13042 -13043 -13044 -13045 -13046 -13047 -13048 -13049 -13050 -13051 -13052 -13053 -13054 -13055 -13056 -13057 -13058 -13059 -13060 -13061 -13062 -13063 -13064 -13065 -13066 -13067 -13068 -13069 -13070 -13071 -13072 -13073 -13074 -13075 -13076 -13077 -13078 -13079 -13080 -13081 -13082 -13083 -13084 -13085 -13086 -13087 -13088 -13089 -13090 -13091 -13092 -13093 -13094 -13095 -13096 -13097 -13098 -13099 -13100 -13101 -13102 -13103 -13104 -13105 -13106 -13107 -13108 -13109 -13110 -13111 -13112 -13113 -13114 -13115 -13116 -13117 -13118 -13119 -13120 -13121 -13122 -13123 -13124 -13125 -13126 -13127 -13128 -13129 -13130 -13131 -13132 -13133 -13134 -13135 -13136 -13137 -13138 -13139 -13140 -13141 -13142 -13143 -13144 -13145 -13146 -13147 -13148 -13149 -13150 -13151 -13152 -13153 -13154 -13155 -13156 -13157 -13158 -13159 -13160 -13161 -13162 -13163 -13164 -13165 -13166 -13167 -13168 -13169 -13170 -13171 -13172 -13173 -13174 -13175 -13176 -13177 -13178 -13179 -13180 -13181 -13182 -13183 -13184 -13185 -13186 -13187 -13188 -13189 -13190 -13191 -13192 -13193 -13194 -13195 -13196 -13197 -13198 -13199 -13200 -13201 -13202 -13203 -13204 -13205 -13206 -13207 -13208 -13209 -13210 -13211 -13212 -13213 -13214 -13215 -13216 -13217 -13218 -13219 -13220 -13221 -13222 -13223 -13224 -13225 -13226 -13227 -13228 -13229 -13230 -13231 -13232 -13233 -13234 -13235 -13236 -13237 -13238 -13239 -13240 -13241 -13242 -13243 -13244 -13245 -13246 -13247 -13248 -13249 -13250 -13251 -13252 -13253 -13254 -13255 -13256 -13257 -13258 -13259 -13260 -13261 -13262 -13263 -13264 -13265 -13266 -13267 -13268 -13269 -13270 -13271 -13272 -13273 -13274 -13275 -13276 -13277 -13278 -13279 -13280 -13281 -13282 -13283 -13284 -13285 -13286 -13287 -13288 -13289 -13290 -13291 -13292 -13293 -13294 -13295 -13296 -13297 -13298 -13299 -13300 -13301 -13302 -13303 -13304 -13305 -13306 -13307 -13308 -13309 -13310 -13311 -13312 -13313 -13314 -13315 -13316 -13317 -13318 -13319 -13320 -13321 -13322 -13323 -13324 -13325 -13326 -13327 -13328 -13329 -13330 -13331 -13332 -13333 -13334 -13335 -13336 -13337 -13338 -13339 -13340 -13341 -13342 -13343 -13344 -13345 -13346 -13347 -13348 -13349 -13350 -13351 -13352 -13353 -13354 -13355 -13356 -13357 -13358 -13359 -13360 -13361 -13362 -13363 -13364 -13365 -13366 -13367 -13368 -13369 -13370 -13371 -13372 -13373 -13374 -13375 -13376 -13377 -13378 -13379 -13380 -13381 -13382 -13383 -13384 -13385 -13386 -13387 -13388 -13389 -13390 -13391 -13392 -13393 -13394 -13395 -13396 -13397 -13398 -13399 -13400 -13401 -13402 -13403 -13404 -13405 -13406 -13407 -13408 -13409 -13410 -13411 -13412 -13413 -13414 -13415 -13416 -13417 -13418 -13419 -13420 -13421 -13422 -13423 -13424 -13425 -13426 -13427 -13428 -13429 -13430 -13431 -13432 -13433 -13434 -13435 -13436 -13437 -13438 -13439 -13440 -13441 -13442 -13443 -13444 -13445 -13446 -13447 -13448 -13449 -13450 -13451 -13452 -13453 -13454 -13455 -13456 -13457 -13458 -13459 -13460 -13461 -13462 -13463 -13464 -13465 -13466 -13467 -13468 -13469 -13470 -13471 -13472 -13473 -13474 -13475 -13476 -13477 -13478 -13479 -13480 -13481 -13482 -13483 -13484 -13485 -13486 -13487 -13488 -13489 -13490 -13491 -13492 -13493 -13494 -13495 -13496 -13497 -13498 -13499 -13500 -13501 -13502 -13503 -13504 -13505 -13506 -13507 -13508 -13509 -13510 -13511 -13512 -13513 -13514 -13515 -13516 -13517 -13518 -13519 -13520 -13521 -13522 -13523 -13524 -13525 -13526 -13527 -13528 -13529 -13530 -13531 -13532 -13533 -13534 -13535 -13536 -13537 -13538 -13539 -13540 -13541 -13542 -13543 -13544 -13545 -13546 -13547 -13548 -13549 -13550 -13551 -13552 -13553 -13554 -13555 -13556 -13557 -13558 -13559 -13560 -13561 -13562 -13563 -13564 -13565 -13566 -13567 -13568 -13569 -13570 -13571 -13572 -13573 -13574 -13575 -13576 -13577 -13578 -13579 -13580 -13581 -13582 -13583 -13584 -13585 -13586 -13587 -13588 -13589 -13590 -13591 -13592 -13593 -13594 -13595 -13596 -13597 -13598 -13599 -13600 -13601 -13602 -13603 -13604 -13605 -13606 -13607 -13608 -13609 -13610 -13611 -13612 -13613 -13614 -13615 -13616 -13617 -13618 -13619 -13620 -13621 -13622 -13623 -13624 -13625 -13626 -13627 -13628 -13629 -13630 -13631 -13632 -13633 -13634 -13635 -13636 -13637 -13638 -13639 -13640 -13641 -13642 -13643 -13644 -13645 -13646 -13647 -13648 -13649 -13650 -13651 -13652 -13653 -13654 -13655 -13656 -13657 -13658 -13659 -13660 -13661 -13662 -13663 -13664 -13665 -13666 -13667 -13668 -13669 -13670 -13671 -13672 -13673 -13674 -13675 -13676 -13677 -13678 -13679 -13680 -13681 -13682 -13683 -13684 -13685 -13686 -13687 -13688 -13689 -13690 -13691 -13692 -13693 -13694 -13695 -13696 -13697 -13698 -13699 -13700 -13701 -13702 -13703 -13704 -13705 -13706 -13707 -13708 -13709 -13710 -13711 -13712 -13713 -13714 -13715 -13716 -13717 -13718 -13719 -13720 -13721 -13722 -13723 -13724 -13725 -13726 -13727 -13728 -13729 -13730 -13731 -13732 -13733 -13734 -13735 -13736 -13737 -13738 -13739 -13740 -13741 -13742 -13743 -13744 -13745 -13746 -13747 -13748 -13749 -13750 -13751 -13752 -13753 -13754 -13755 -13756 -13757 -13758 -13759 -13760 -13761 -13762 -13763 -13764 -13765 -13766 -13767 -13768 -13769 -13770 -13771 -13772 -13773 -13774 -13775 -13776 -13777 -13778 -13779 -13780 -13781 -13782 -13783 -13784 -13785 -13786 -13787 -13788 -13789 -13790 -13791 -13792 -13793 -13794 -13795 -13796 -13797 -13798 -13799 -13800 -13801 -13802 -13803 -13804 -13805 -13806 -13807 -13808 -13809 -13810 -13811 -13812 -13813 -13814 -13815 -13816 -13817 -13818 -13819 -13820 -13821 -13822 -13823 -13824 -13825 -13826 -13827 -13828 -13829 -13830 -13831 -13832 -13833 -13834 -13835 -13836 -13837 -13838 -13839 -13840 -13841 -13842 -13843 -13844 -13845 -13846 -13847 -13848 -13849 -13850 -13851 -13852 -13853 -13854 -13855 -13856 -13857 -13858 -13859 -13860 -13861 -13862 -13863 -13864 -13865 -13866 -13867 -13868 -13869 -13870 -13871 -13872 -13873 -13874 -13875 -13876 -13877 -13878 -13879 -13880 -13881 -13882 -13883 -13884 -13885 -13886 -13887 -13888 -13889 -13890 -13891 -13892 -13893 -13894 -13895 -13896 -13897 -13898 -13899 -13900 -13901 -13902 -13903 -13904 -13905 -13906 -13907 -13908 -13909 -13910 -13911 -13912 -13913 -13914 -13915 -13916 -13917 -13918 -13919 -13920 -13921 -13922 -13923 -13924 -13925 -13926 -13927 -13928 -13929 -13930 -13931 -13932 -13933 -13934 -13935 -13936 -13937 -13938 -13939 -13940 -13941 -13942 -13943 -13944 -13945 -13946 -13947 -13948 -13949 -13950 -13951 -13952 -13953 -13954 -13955 -13956 -13957 -13958 -13959 -13960 -13961 -13962 -13963 -13964 -13965 -13966 -13967 -13968 -13969 -13970 -13971 -13972 -13973 -13974 -13975 -13976 -13977 -13978 -13979 -13980 -13981 -13982 -13983 -13984 -13985 -13986 -13987 -13988 -13989 -13990 -13991 -13992 -13993 -13994 -13995 -13996 -13997 -13998 -13999 -14000 -14001 -14002 -14003 -14004 -14005 -14006 -14007 -14008 -14009 -14010 -14011 -14012 -14013 -14014 -14015 -14016 -14017 -14018 -14019 -14020 -14021 -14022 -14023 -14024 -14025 -14026 -14027 -14028 -14029 -14030 -14031 -14032 -14033 -14034 -14035 -14036 -14037 -14038 -14039 -14040 -14041 -14042 -14043 -14044 -14045 -14046 -14047 -14048 -14049 -14050 -14051 -14052 -14053 -14054 -14055 -14056 -14057 -14058 -14059 -14060 -14061 -14062 -14063 -14064 -14065 -14066 -14067 -14068 -14069 -14070 -14071 -14072 -14073 -14074 -14075 -14076 -14077 -14078 -14079 -14080 -14081 -14082 -14083 -14084 -14085 -14086 -14087 -14088 -14089 -14090 -14091 -14092 -14093 -14094 -14095 -14096 -14097 -14098 -14099 -14100 -14101 -14102 -14103 -14104 -14105 -14106 -14107 -14108 -14109 -14110 -14111 -14112 -14113 -14114 -14115 -14116 -14117 -14118 -14119 -14120 -14121 -14122 -14123 -14124 -14125 -14126 -14127 -14128 -14129 -14130 -14131 -14132 -14133 -14134 -14135 -14136 -14137 -14138 -14139 -14140 -14141 -14142 -14143 -14144 -14145 -14146 -14147 -14148 -14149 -14150 -14151 -14152 -14153 -14154 -14155 -14156 -14157 -14158 -14159 -14160 -14161 -14162 -14163 -14164 -14165 -14166 -14167 -14168 -14169 -14170 -14171 -14172 -14173 -14174 -14175 -14176 -14177 -14178 -14179 -14180 -14181 -14182 -14183 -14184 -14185 -14186 -14187 -14188 -14189 -14190 -14191 -14192 -14193 -14194 -14195 -14196 -14197 -14198 -14199 -14200 -14201 -14202 -14203 -14204 -14205 -14206 -14207 -14208 -14209 -14210 -14211 -14212 -14213 -14214 -14215 -14216 -14217 -14218 -14219 -14220 -14221 -14222 -14223 -14224 -14225 -14226 -14227 -14228 -14229 -14230 -14231 -14232 -14233 -14234 -14235 -14236 -14237 -14238 -14239 -14240 -14241 -14242 -14243 -14244 -14245 -14246 -14247 -14248 -14249 -14250 -14251 -14252 -14253 -14254 -14255 -14256 -14257 -14258 -14259 -14260 -14261 -14262 -14263 -14264 -14265 -14266 -14267 -14268 -14269 -14270 -14271 -14272 -14273 -14274 -14275 -14276 -14277 -14278 -14279 -14280 -14281 -14282 -14283 -14284 -14285 -14286 -14287 -14288 -14289 -14290 -14291 -14292 -14293 -14294 -14295 -14296 -14297 -14298 -14299 -14300 -14301 -14302 -14303 -14304 -14305 -14306 -14307 -14308 -14309 -14310 -14311 -14312 -14313 -14314 -14315 -14316 -14317 -14318 -14319 -14320 -14321 -14322 -14323 -14324 -14325 -14326 -14327 -14328 -14329 -14330 -14331 -14332 -14333 -14334 -14335 -14336 -14337 -14338 -14339 -14340 -14341 -14342 -14343 -14344 -14345 -14346 -14347 -14348 -14349 -14350 -14351 -14352 -14353 -14354 -14355 -14356 -14357 -14358 -14359 -14360 -14361 -14362 -14363 -14364 -14365 -14366 -14367 -14368 -14369 -14370 -14371 -14372 -14373 -14374 -14375 -14376 -14377 -14378 -14379 -14380 -14381 -14382 -14383 -14384 -14385 -14386 -14387 -14388 -14389 -14390 -14391 -14392 -14393 -14394 -14395 -14396 -14397 -14398 -14399 -14400 -14401 -14402 -14403 -14404 -14405 -14406 -14407 -14408 -14409 -14410 -14411 -14412 -14413 -14414 -14415 -14416 -14417 -14418 -14419 -14420 -14421 -14422 -14423 -14424 -14425 -14426 -14427 -14428 -14429 -14430 -14431 -14432 -14433 -14434 -14435 -14436 -14437 -14438 -14439 -14440 -14441 -14442 -14443 -14444 -14445 -14446 -14447 -14448 -14449 -14450 -14451 -14452 -14453 -14454 -14455 -14456 -14457 -14458 -14459 -14460 -14461 -14462 -14463 -14464 -14465 -14466 -14467 -14468 -14469 -14470 -14471 -14472 -14473 -14474 -14475 -14476 -14477 -14478 -14479 -14480 -14481 -14482 -14483 -14484 -14485 -14486 -14487 -14488 -14489 -14490 -14491 -14492 -14493 -14494 -14495 -14496 -14497 -14498 -14499 -14500 -14501 -14502 -14503 -14504 -14505 -14506 -14507 -14508 -14509 -14510 -14511 -14512 -14513 -14514 -14515 -14516 -14517 -14518 -14519 -14520 -14521 -14522 -14523 -14524 -14525 -14526 -14527 -14528 -14529 -14530 -14531 -14532 -14533 -14534 -14535 -14536 -14537 -14538 -14539 -14540 -14541 -14542 -14543 -14544 -14545 -14546 -14547 -14548 -14549 -14550 -14551 -14552 -14553 -14554 -14555 -14556 -14557 -14558 -14559 -14560 -14561 -14562 -14563 -14564 -14565 -14566 -14567 -14568 -14569 -14570 -14571 -14572 -14573 -14574 -14575 -14576 -14577 -14578 -14579 -14580 -14581 -14582 -14583 -14584 -14585 -14586 -14587 -14588 -14589 -14590 -14591 -14592 -14593 -14594 -14595 -14596 -14597 -14598 -14599 -14600 -14601 -14602 -14603 -14604 -14605 -14606 -14607 -14608 -14609 -14610 -14611 -14612 -14613 -14614 -14615 -14616 -14617 -14618 -14619 -14620 -14621 -14622 -14623 -14624 -14625 -14626 -14627 -14628 -14629 -14630 -14631 -14632 -14633 -14634 -14635 -14636 -14637 -14638 -14639 -14640 -14641 -14642 -14643 -14644 -14645 -14646 -14647 -14648 -14649 -14650 -14651 -14652 -14653 -14654 -14655 -14656 -14657 -14658 -14659 -14660 -14661 -14662 -14663 -14664 -14665 -14666 -14667 -14668 -14669 -14670 -14671 -14672 -14673 -14674 -14675 -14676 -14677 -14678 -14679 -14680 -14681 -14682 -14683 -14684 -14685 -14686 -14687 -14688 -14689 -14690 -14691 -14692 -14693 -14694 -14695 -14696 -14697 -14698 -14699 -14700 -14701 -14702 -14703 -14704 -14705 -14706 -14707 -14708 -14709 -14710 -14711 -14712 -14713 -14714 -14715 -14716 -14717 -14718 -14719 -14720 -14721 -14722 -14723 -14724 -14725 -14726 -14727 -14728 -14729 -14730 -14731 -14732 -14733 -14734 -14735 -14736 -14737 -14738 -14739 -14740 -14741 -14742 -14743 -14744 -14745 -14746 -14747 -14748 -14749 -14750 -14751 -14752 -14753 -14754 -14755 -14756 -14757 -14758 -14759 -14760 -14761 -14762 -14763 -14764 -14765 -14766 -14767 -14768 -14769 -14770 -14771 -14772 -14773 -14774 -14775 -14776 -14777 -14778 -14779 -14780 -14781 -14782 -14783 -14784 -14785 -14786 -14787 -14788 -14789 -14790 -14791 -14792 -14793 -14794 -14795 -14796 -14797 -14798 -14799 -14800 -14801 -14802 -14803 -14804 -14805 -14806 -14807 -14808 -14809 -14810 -14811 -14812 -14813 -14814 -14815 -14816 -14817 -14818 -14819 -14820 -14821 -14822 -14823 -14824 -14825 -14826 -14827 -14828 -14829 -14830 -14831 -14832 -14833 -14834 -14835 -14836 -14837 -14838 -14839 -14840 -14841 -14842 -14843 -14844 -14845 -14846 -14847 -14848 -14849 -14850 -14851 -14852 -14853 -14854 -14855 -14856 -14857 -14858 -14859 -14860 -14861 -14862 -14863 -14864 -14865 -14866 -14867 -14868 -14869 -14870 -14871 -14872 -14873 -14874 -14875 -14876 -14877 -14878 -14879 -14880 -14881 -14882 -14883 -14884 -14885 -14886 -14887 -14888 -14889 -14890 -14891 -14892 -14893 -14894 -14895 -14896 -14897 -14898 -14899 -14900 -14901 -14902 -14903 -14904 -14905 -14906 -14907 -14908 -14909 -14910 -14911 -14912 -14913 -14914 -14915 -14916 -14917 -14918 -14919 -14920 -14921 -14922 -14923 -14924 -14925 -14926 -14927 -14928 -14929 -14930 -14931 -14932 -14933 -14934 -14935 -14936 -14937 -14938 -14939 -14940 -14941 -14942 -14943 -14944 -14945 -14946 -14947 -14948 -14949 -14950 -14951 -14952 -14953 -14954 -14955 -14956 -14957 -14958 -14959 -14960 -14961 -14962 -14963 -14964 -14965 -14966 -14967 -14968 -14969 -14970 -14971 -14972 -14973 -14974 -14975 -14976 -14977 -14978 -14979 -14980 -14981 -14982 -14983 -14984 -14985 -14986 -14987 -14988 -14989 -14990 -14991 -14992 -14993 -14994 -14995 -14996 -14997 -14998 -14999 -15000 -15001 -15002 -15003 -15004 -15005 -15006 -15007 -15008 -15009 -15010 -15011 -15012 -15013 -15014 -15015 -15016 -15017 -15018 -15019 -15020 -15021 -15022 -15023 -15024 -15025 -15026 -15027 -15028 -15029 -15030 -15031 -15032 -15033 -15034 -15035 -15036 -15037 -15038 -15039 -15040 -15041 -15042 -15043 -15044 -15045 -15046 -15047 -15048 -15049 -15050 -15051 -15052 -15053 -15054 -15055 -15056 -15057 -15058 -15059 -15060 -15061 -15062 -15063 -15064 -15065 -15066 -15067 -15068 -15069 -15070 -15071 -15072 -15073 -15074 -15075 -15076 -15077 -15078 -15079 -15080 -15081 -15082 -15083 -15084 -15085 -15086 -15087 -15088 -15089 -15090 -15091 -15092 -15093 -15094 -15095 -15096 -15097 -15098 -15099 -15100 -15101 -15102 -15103 -15104 -15105 -15106 -15107 -15108 -15109 -15110 -15111 -15112 -15113 -15114 -15115 -15116 -15117 -15118 -15119 -15120 -15121 -15122 -15123 -15124 -15125 -15126 -15127 -15128 -15129 -15130 -15131 -15132 -15133 -15134 -15135 -15136 -15137 -15138 -15139 -15140 -15141 -15142 -15143 -15144 -15145 -15146 -15147 -15148 -15149 -15150 -15151 -15152 -15153 -15154 -15155 -15156 -15157 -15158 -15159 -15160 -15161 -15162 -15163 -15164 -15165 -15166 -15167 -15168 -15169 -15170 -15171 -15172 -15173 -15174 -15175 -15176 -15177 -15178 -15179 -15180 -15181 -15182 -15183 -15184 -15185 -15186 -15187 -15188 -15189 -15190 -15191 -15192 -15193 -15194 -15195 -15196 -15197 -15198 -15199 -15200 -15201 -15202 -15203 -15204 -15205 -15206 -15207 -15208 -15209 -15210 -15211 -15212 -15213 -15214 -15215 -15216 -15217 -15218 -15219 -15220 -15221 -15222 -15223 -15224 -15225 -15226 -15227 -15228 -15229 -15230 -15231 -15232 -15233 -15234 -15235 -15236 -15237 -15238 -15239 -15240 -15241 -15242 -15243 -15244 -15245 -15246 -15247 -15248 -15249 -15250 -15251 -15252 -15253 -15254 -15255 -15256 -15257 -15258 -15259 -15260 -15261 -15262 -15263 -15264 -15265 -15266 -15267 -15268 -15269 -15270 -15271 -15272 -15273 -15274 -15275 -15276 -15277 -15278 -15279 -15280 -15281 -15282 -15283 -15284 -15285 -15286 -15287 -15288 -15289 -15290 -15291 -15292 -15293 -15294 -15295 -15296 -15297 -15298 -15299 -15300 -15301 -15302 -15303 -15304 -15305 -15306 -15307 -15308 -15309 -15310 -15311 -15312 -15313 -15314 -15315 -15316 -15317 -15318 -15319 -15320 -15321 -15322 -15323 -15324 -15325 -15326 -15327 -15328 -15329 -15330 -15331 -15332 -15333 -15334 -15335 -15336 -15337 -15338 -15339 -15340 -15341 -15342 -15343 -15344 -15345 -15346 -15347 -15348 -15349 -15350 -15351 -15352 -15353 -15354 -15355 -15356 -15357 -15358 -15359 -15360 -15361 -15362 -15363 -15364 -15365 -15366 -15367 -15368 -15369 -15370 -15371 -15372 -15373 -15374 -15375 -15376 -15377 -15378 -15379 -15380 -15381 -15382 -15383 -15384 -15385 -15386 -15387 -15388 -15389 -15390 -15391 -15392 -15393 -15394 -15395 -15396 -15397 -15398 -15399 -15400 -15401 -15402 -15403 -15404 -15405 -15406 -15407 -15408 -15409 -15410 -15411 -15412 -15413 -15414 -15415 -15416 -15417 -15418 -15419 -15420 -15421 -15422 -15423 -15424 -15425 -15426 -15427 -15428 -15429 -15430 -15431 -15432 -15433 -15434 -15435 -15436 -15437 -15438 -15439 -15440 -15441 -15442 -15443 -15444 -15445 -15446 -15447 -15448 -15449 -15450 -15451 -15452 -15453 -15454 -15455 -15456 -15457 -15458 -15459 -15460 -15461 -15462 -15463 -15464 -15465 -15466 -15467 -15468 -15469 -15470 -15471 -15472 -15473 -15474 -15475 -15476 -15477 -15478 -15479 -15480 -15481 -15482 -15483 -15484 -15485 -15486 -15487 -15488 -15489 -15490 -15491 -15492 -15493 -15494 -15495 -15496 -15497 -15498 -15499 -15500 -15501 -15502 -15503 -15504 -15505 -15506 -15507 -15508 -15509 -15510 -15511 -15512 -15513 -15514 -15515 -15516 -15517 -15518 -15519 -15520 -15521 -15522 -15523 -15524 -15525 -15526 -15527 -15528 -15529 -15530 -15531 -15532 -15533 -15534 -15535 -15536 -15537 -15538 -15539 -15540 -15541 -15542 -15543 -15544 -15545 -15546 -15547 -15548 -15549 -15550 -15551 -15552 -15553 -15554 -15555 -15556 -15557 -15558 -15559 -15560 -15561 -15562 -15563 -15564 -15565 -15566 -15567 -15568 -15569 -15570 -15571 -15572 -15573 -15574 -15575 -15576 -15577 -15578 -15579 -15580 -15581 -15582 -15583 -15584 -15585 -15586 -15587 -15588 -15589 -15590 -15591 -15592 -15593 -15594 -15595 -15596 -15597 -15598 -15599 -15600 -15601 -15602 -15603 -15604 -15605 -15606 -15607 -15608 -15609 -15610 -15611 -15612 -15613 -15614 -15615 -15616 -15617 -15618 -15619 -15620 -15621 -15622 -15623 -15624 -15625 -15626 -15627 -15628 -15629 -15630 -15631 -15632 -15633 -15634 -15635 -15636 -15637 -15638 -15639 -15640 -15641 -15642 -15643 -15644 -15645 -15646 -15647 -15648 -15649 -15650 -15651 -15652 -15653 -15654 -15655 -15656 -15657 -15658 -15659 -15660 -15661 -15662 -15663 -15664 -15665 -15666 -15667 -15668 -15669 -15670 -15671 -15672 -15673 -15674 -15675 -15676 -15677 -15678 -15679 -15680 -15681 -15682 -15683 -15684 -15685 -15686 -15687 -15688 -15689 -15690 -15691 -15692 -15693 -15694 -15695 -15696 -15697 -15698 -15699 -15700 -15701 -15702 -15703 -15704 -15705 -15706 -15707 -15708 -15709 -15710 -15711 -15712 -15713 -15714 -15715 -15716 -15717 -15718 -15719 -15720 -15721 -15722 -15723 -15724 -15725 -15726 -15727 -15728 -15729 -15730 -15731 -15732 -15733 -15734 -15735 -15736 -15737 -15738 -15739 -15740 -15741 -15742 -15743 -15744 -15745 -15746 -15747 -15748 -15749 -15750 -15751 -15752 -15753 -15754 -15755 -15756 -15757 -15758 -15759 -15760 -15761 -15762 -15763 -15764 -15765 -15766 -15767 -15768 -15769 -15770 -15771 -15772 -15773 -15774 -15775 -15776 -15777 -15778 -15779 -15780 -15781 -15782 -15783 -15784 -15785 -15786 -15787 -15788 -15789 -15790 -15791 -15792 -15793 -15794 -15795 -15796 -15797 -15798 -15799 -15800 -15801 -15802 -15803 -15804 -15805 -15806 -15807 -15808 -15809 -15810 -15811 -15812 -15813 -15814 -15815 -15816 -15817 -15818 -15819 -15820 -15821 -15822 -15823 -15824 -15825 -15826 -15827 -15828 -15829 -15830 -15831 -15832 -15833 -15834 -15835 -15836 -15837 -15838 -15839 -15840 -15841 -15842 -15843 -15844 -15845 -15846 -15847 -15848 -15849 -15850 -15851 -15852 -15853 -15854 -15855 -15856 -15857 -15858 -15859 -15860 -15861 -15862 -15863 -15864 -15865 -15866 -15867 -15868 -15869 -15870 -15871 -15872 -15873 -15874 -15875 -15876 -15877 -15878 -15879 -15880 -15881 -15882 -15883 -15884 -15885 -15886 -15887 -15888 -15889 -15890 -15891 -15892 -15893 -15894 -15895 -15896 -15897 -15898 -15899 -15900 -15901 -15902 -15903 -15904 -15905 -15906 -15907 -15908 -15909 -15910 -15911 -15912 -15913 -15914 -15915 -15916 -15917 -15918 -15919 -15920 -15921 -15922 -15923 -15924 -15925 -15926 -15927 -15928 -15929 -15930 -15931 -15932 -15933 -15934 -15935 -15936 -15937 -15938 -15939 -15940 -15941 -15942 -15943 -15944 -15945 -15946 -15947 -15948 -15949 -15950 -15951 -15952 -15953 -15954 -15955 -15956 -15957 -15958 -15959 -15960 -15961 -15962 -15963 -15964 -15965 -15966 -15967 -15968 -15969 -15970 -15971 -15972 -15973 -15974 -15975 -15976 -15977 -15978 -15979 -15980 -15981 -15982 -15983 -15984 -15985 -15986 -15987 -15988 -15989 -15990 -15991 -15992 -15993 -15994 -15995 -15996 -15997 -15998 -15999 -16000 -16001 -16002 -16003 -16004 -16005 -16006 -16007 -16008 -16009 -16010 -16011 -16012 -16013 -16014 -16015 -16016 -16017 -16018 -16019 -16020 -16021 -16022 -16023 -16024 -16025 -16026 -16027 -16028 -16029 -16030 -16031 -16032 -16033 -16034 -16035 -16036 -16037 -16038 -16039 -16040 -16041 -16042 -16043 -16044 -16045 -16046 -16047 -16048 -16049 -16050 -16051 -16052 -16053 -16054 -16055 -16056 -16057 -16058 -16059 -16060 -16061 -16062 -16063 -16064 -16065 -16066 -16067 -16068 -16069 -16070 -16071 -16072 -16073 -16074 -16075 -16076 -16077 -16078 -16079 -16080 -16081 -16082 -16083 -16084 -16085 -16086 -16087 -16088 -16089 -16090 -16091 -16092 -16093 -16094 -16095 -16096 -16097 -16098 -16099 -16100 -16101 -16102 -16103 -16104 -16105 -16106 -16107 -16108 -16109 -16110 -16111 -16112 -16113 -16114 -16115 -16116 -16117 -16118 -16119 -16120 -16121 -16122 -16123 -16124 -16125 -16126 -16127 -16128 -16129 -16130 -16131 -16132 -16133 -16134 -16135 -16136 -16137 -16138 -16139 -16140 -16141 -16142 -16143 -16144 -16145 -16146 -16147 -16148 -16149 -16150 -16151 -16152 -16153 -16154 -16155 -16156 -16157 -16158 -16159 -16160 -16161 -16162 -16163 -16164 -16165 -16166 -16167 -16168 -16169 -16170 -16171 -16172 -16173 -16174 -16175 -16176 -16177 -16178 -16179 -16180 -16181 -16182 -16183 -16184 -16185 -16186 -16187 -16188 -16189 -16190 -16191 -16192 -16193 -16194 -16195 -16196 -16197 -16198 -16199 -16200 -16201 -16202 -16203 -16204 -16205 -16206 -16207 -16208 -16209 -16210 -16211 -16212 -16213 -16214 -16215 -16216 -16217 -16218 -16219 -16220 -16221 -16222 -16223 -16224 -16225 -16226 -16227 -16228 -16229 -16230 -16231 -16232 -16233 -16234 -16235 -16236 -16237 -16238 -16239 -16240 -16241 -16242 -16243 -16244 -16245 -16246 -16247 -16248 -16249 -16250 -16251 -16252 -16253 -16254 -16255 -16256 -16257 -16258 -16259 -16260 -16261 -16262 -16263 -16264 -16265 -16266 -16267 -16268 -16269 -16270 -16271 -16272 -16273 -16274 -16275 -16276 -16277 -16278 -16279 -16280 -16281 -16282 -16283 -16284 -16285 -16286 -16287 -16288 -16289 -16290 -16291 -16292 -16293 -16294 -16295 -16296 -16297 -16298 -16299 -16300 -16301 -16302 -16303 -16304 -16305 -16306 -16307 -16308 -16309 -16310 -16311 -16312 -16313 -16314 -16315 -16316 -16317 -16318 -16319 -16320 -16321 -16322 -16323 -16324 -16325 -16326 -16327 -16328 -16329 -16330 -16331 -16332 -16333 -16334 -16335 -16336 -16337 -16338 -16339 -16340 -16341 -16342 -16343 -16344 -16345 -16346 -16347 -16348 -16349 -16350 -16351 -16352 -16353 -16354 -16355 -16356 -16357 -16358 -16359 -16360 -16361 -16362 -16363 -16364 -16365 -16366 -16367 -16368 -16369 -16370 -16371 -16372 -16373 -16374 -16375 -16376 -16377 -16378 -16379 -16380 -16381 -16382 -16383 -16384 -16385 -16386 -16387 -16388 -16389 -16390 -16391 -16392 -16393 -16394 -16395 -16396 -16397 -16398 -16399 -16400 -16401 -16402 -16403 -16404 -16405 -16406 -16407 -16408 -16409 -16410 -16411 -16412 -16413 -16414 -16415 -16416 -16417 -16418 -16419 -16420 -16421 -16422 -16423 -16424 -16425 -16426 -16427 -16428 -16429 -16430 -16431 -16432 -16433 -16434 -16435 -16436 -16437 -16438 -16439 -16440 -16441 -16442 -16443 -16444 -16445 -16446 -16447 -16448 -16449 -16450 -16451 -16452 -16453 -16454 -16455 -16456 -16457 -16458 -16459 -16460 -16461 -16462 -16463 -16464 -16465 -16466 -16467 -16468 -16469 -16470 -16471 -16472 -16473 -16474 -16475 -16476 -16477 -16478 -16479 -16480 -16481 -16482 -16483 -16484 -16485 -16486 -16487 -16488 -16489 -16490 -16491 -16492 -16493 -16494 -16495 -16496 -16497 -16498 -16499 -16500 -16501 -16502 -16503 -16504 -16505 -16506 -16507 -16508 -16509 -16510 -16511 -16512 -16513 -16514 -16515 -16516 -16517 -16518 -16519 -16520 -16521 -16522 -16523 -16524 -16525 -16526 -16527 -16528 -16529 -16530 -16531 -16532 -16533 -16534 -16535 -16536 -16537 -16538 -16539 -16540 -16541 -16542 -16543 -16544 -16545 -16546 -16547 -16548 -16549 -16550 -16551 -16552 -16553 -16554 -16555 -16556 -16557 -16558 -16559 -16560 -16561 -16562 -16563 -16564 -16565 -16566 -16567 -16568 -16569 -16570 -16571 -16572 -16573 -16574 -16575 -16576 -16577 -16578 -16579 -16580 -16581 -16582 -16583 -16584 -16585 -16586 -16587 -16588 -16589 -16590 -16591 -16592 -16593 -16594 -16595 -16596 -16597 -16598 -16599 -16600 -16601 -16602 -16603 -16604 -16605 -16606 -16607 -16608 -16609 -16610 -16611 -16612 -16613 -16614 -16615 -16616 -16617 -16618 -16619 -16620 -16621 -16622 -16623 -16624 -16625 -16626 -16627 -16628 -16629 -16630 -16631 -16632 -16633 -16634 -16635 -16636 -16637 -16638 -16639 -16640 -16641 -16642 -16643 -16644 -16645 -16646 -16647 -16648 -16649 -16650 -16651 -16652 -16653 -16654 -16655 -16656 -16657 -16658 -16659 -16660 -16661 -16662 -16663 -16664 -16665 -16666 -16667 -16668 -16669 -16670 -16671 -16672 -16673 -16674 -16675 -16676 -16677 -16678 -16679 -16680 -16681 -16682 -16683 -16684 -16685 -16686 -16687 -16688 -16689 -16690 -16691 -16692 -16693 -16694 -16695 -16696 -16697 -16698 -16699 -16700 -16701 -16702 -16703 -16704 -16705 -16706 -16707 -16708 -16709 -16710 -16711 -16712 -16713 -16714 -16715 -16716 -16717 -16718 -16719 -16720 -16721 -16722 -16723 -16724 -16725 -16726 -16727 -16728 -16729 -16730 -16731 -16732 -16733 -16734 -16735 -16736 -16737 -16738 -16739 -16740 -16741 -16742 -16743 -16744 -16745 -16746 -16747 -16748 -16749 -16750 -16751 -16752 -16753 -16754 -16755 -16756 -16757 -16758 -16759 -16760 -16761 -16762 -16763 -16764 -16765 -16766 -16767 -16768 -16769 -16770 -16771 -16772 -16773 -16774 -16775 -16776 -16777 -16778 -16779 -16780 -16781 -16782 -16783 -16784 -16785 -16786 -16787 -16788 -16789 -16790 -16791 -16792 -16793 -16794 -16795 -16796 -16797 -16798 -16799 -16800 -16801 -16802 -16803 -16804 -16805 -16806 -16807 -16808 -16809 -16810 -16811 -16812 -16813 -16814 -16815 -16816 -16817 -16818 -16819 -16820 -16821 -16822 -16823 -16824 -16825 -16826 -16827 -16828 -16829 -16830 -16831 -16832 -16833 -16834 -16835 -16836 -16837 -16838 -16839 -16840 -16841 -16842 -16843 -16844 -16845 -16846 -16847 -16848 -16849 -16850 -16851 -16852 -16853 -16854 -16855 -16856 -16857 -16858 -16859 -16860 -16861 -16862 -16863 -16864 -16865 -16866 -16867 -16868 -16869 -16870 -16871 -16872 -16873 -16874 -16875 -16876 -16877 -16878 -16879 -16880 -16881 -16882 -16883 -16884 -16885 -16886 -16887 -16888 -16889 -16890 -16891 -16892 -16893 -16894 -16895 -16896 -16897 -16898 -16899 -16900 -16901 -16902 -16903 -16904 -16905 -16906 -16907 -16908 -16909 -16910 -16911 -16912 -16913 -16914 -16915 -16916 -16917 -16918 -16919 -16920 -16921 -16922 -16923 -16924 -16925 -16926 -16927 -16928 -16929 -16930 -16931 -16932 -16933 -16934 -16935 -16936 -16937 -16938 -16939 -16940 -16941 -16942 -16943 -16944 -16945 -16946 -16947 -16948 -16949 -16950 -16951 -16952 -16953 -16954 -16955 -16956 -16957 -16958 -16959 -16960 -16961 -16962 -16963 -16964 -16965 -16966 -16967 -16968 -16969 -16970 -16971 -16972 -16973 -16974 -16975 -16976 -16977 -16978 -16979 -16980 -16981 -16982 -16983 -16984 -16985 -16986 -16987 -16988 -16989 -16990 -16991 -16992 -16993 -16994 -16995 -16996 -16997 -16998 -16999 -17000 -17001 -17002 -17003 -17004 -17005 -17006 -17007 -17008 -17009 -17010 -17011 -17012 -17013 -17014 -17015 -17016 -17017 -17018 -17019 -17020 -17021 -17022 -17023 -17024 -17025 -17026 -17027 -17028 -17029 -17030 -17031 -17032 -17033 -17034 -17035 -17036 -17037 -17038 -17039 -17040 -17041 -17042 -17043 -17044 -17045 -17046 -17047 -17048 -17049 -17050 -17051 -17052 -17053 -17054 -17055 -17056 -17057 -17058 -17059 -17060 -17061 -17062 -17063 -17064 -17065 -17066 -17067 -17068 -17069 -17070 -17071 -17072 -17073 -17074 -17075 -17076 -17077 -17078 -17079 -17080 -17081 -17082 -17083 -17084 -17085 -17086 -17087 -17088 -17089 -17090 -17091 -17092 -17093 -17094 -17095 -17096 -17097 -17098 -17099 -17100 -17101 -17102 -17103 -17104 -17105 -17106 -17107 -17108 -17109 -17110 -17111 -17112 -17113 -17114 -17115 -17116 -17117 -17118 -17119 -17120 -17121 -17122 -17123 -17124 -17125 -17126 -17127 -17128 -17129 -17130 -17131 -17132 -17133 -17134 -17135 -17136 -17137 -17138 -17139 -17140 -17141 -17142 -17143 -17144 -17145 -17146 -17147 -17148 -17149 -17150 -17151 -17152 -17153 -17154 -17155 -17156 -17157 -17158 -17159 -17160 -17161 -17162 -17163 -17164 -17165 -17166 -17167 -17168 -17169 -17170 -17171 -17172 -17173 -17174 -17175 -17176 -17177 -17178 -17179 -17180 -17181 -17182 -17183 -17184 -17185 -17186 -17187 -17188 -17189 -17190 -17191 -17192 -17193 -17194 -17195 -17196 -17197 -17198 -17199 -17200 -17201 -17202 -17203 -17204 -17205 -17206 -17207 -17208 -17209 -17210 -17211 -17212 -17213 -17214 -17215 -17216 -17217 -17218 -17219 -17220 -17221 -17222 -17223 -17224 -17225 -17226 -17227 -17228 -17229 -17230 -17231 -17232 -17233 -17234 -17235 -17236 -17237 -17238 -17239 -17240 -17241 -17242 -17243 -17244 -17245 -17246 -17247 -17248 -17249 -17250 -17251 -17252 -17253 -17254 -17255 -17256 -17257 -17258 -17259 -17260 -17261 -17262 -17263 -17264 -17265 -17266 -17267 -17268 -17269 -17270 -17271 -17272 -17273 -17274 -17275 -17276 -17277 -17278 -17279 -17280 -17281 -17282 -17283 -17284 -17285 -17286 -17287 -17288 -17289 -17290 -17291 -17292 -17293 -17294 -17295 -17296 -17297 -17298 -17299 -17300 -17301 -17302 -17303 -17304 -17305 -17306 -17307 -17308 -17309 -17310 -17311 -17312 -17313 -17314 -17315 -17316 -17317 -17318 -17319 -17320 -17321 -17322 -17323 -17324 -17325 -17326 -17327 -17328 -17329 -17330 -17331 -17332 -17333 -17334 -17335 -17336 -17337 -17338 -17339 -17340 -17341 -17342 -17343 -17344 -17345 -17346 -17347 -17348 -17349 -17350 -17351 -17352 -17353 -17354 -17355 -17356 -17357 -17358 -17359 -17360 -17361 -17362 -17363 -17364 -17365 -17366 -17367 -17368 -17369 -17370 -17371 -17372 -17373 -17374 -17375 -17376 -17377 -17378 -17379 -17380 -17381 -17382 -17383 -17384 -17385 -17386 -17387 -17388 -17389 -17390 -17391 -17392 -17393 -17394 -17395 -17396 -17397 -17398 -17399 -17400 -17401 -17402 -17403 -17404 -17405 -17406 -17407 -17408 -17409 -17410 -17411 -17412 -17413 -17414 -17415 -17416 -17417 -17418 -17419 -17420 -17421 -17422 -17423 -17424 -17425 -17426 -17427 -17428 -17429 -17430 -17431 -17432 -17433 -17434 -17435 -17436 -17437 -17438 -17439 -17440 -17441 -17442 -17443 -17444 -17445 -17446 -17447 -17448 -17449 -17450 -17451 -17452 -17453 -17454 -17455 -17456 -17457 -17458 -17459 -17460 -17461 -17462 -17463 -17464 -17465 -17466 -17467 -17468 -17469 -17470 -17471 -17472 -17473 -17474 -17475 -17476 -17477 -17478 -17479 -17480 -17481 -17482 -17483 -17484 -17485 -17486 -17487 -17488 -17489 -17490 -17491 -17492 -17493 -17494 -17495 -17496 -17497 -17498 -17499 -17500 -17501 -17502 -17503 -17504 -17505 -17506 -17507 -17508 -17509 -17510 -17511 -17512 -17513 -17514 -17515 -17516 -17517 -17518 -17519 -17520 -17521 -17522 -17523 -17524 -17525 -17526 -17527 -17528 -17529 -17530 -17531 -17532 -17533 -17534 -17535 -17536 -17537 -17538 -17539 -17540 -17541 -17542 -17543 -17544 -17545 -17546 -17547 -17548 -17549 -17550 -17551 -17552 -17553 -17554 -17555 -17556 -17557 -17558 -17559 -17560 -17561 -17562 -17563 -17564 -17565 -17566 -17567 -17568 -17569 -17570 -17571 -17572 -17573 -17574 -17575 -17576 -17577 -17578 -17579 -17580 -17581 -17582 -17583 -17584 -17585 -17586 -17587 -17588 -17589 -17590 -17591 -17592 -17593 -17594 -17595 -17596 -17597 -17598 -17599 -17600 -17601 -17602 -17603 -17604 -17605 -17606 -17607 -17608 -17609 -17610 -17611 -17612 -17613 -17614 -17615 -17616 -17617 -17618 -17619 -17620 -17621 -17622 -17623 -17624 -17625 -17626 -17627 -17628 -17629 -17630 -17631 -17632 -17633 -17634 -17635 -17636 -17637 -17638 -17639 -17640 -17641 -17642 -17643 -17644 -17645 -17646 -17647 -17648 -17649 -17650 -17651 -17652 -17653 -17654 -17655 -17656 -17657 -17658 -17659 -17660 -17661 -17662 -17663 -17664 -17665 -17666 -17667 -17668 -17669 -17670 -17671 -17672 -17673 -17674 -17675 -17676 -17677 -17678 -17679 -17680 -17681 -17682 -17683 -17684 -17685 -17686 -17687 -17688 -17689 -17690 -17691 -17692 -17693 -17694 -17695 -17696 -17697 -17698 -17699 -17700 -17701 -17702 -17703 -17704 -17705 -17706 -17707 -17708 -17709 -17710 -17711 -17712 -17713 -17714 -17715 -17716 -17717 -17718 -17719 -17720 -17721 -17722 -17723 -17724 -17725 -17726 -17727 -17728 -17729 -17730 -17731 -17732 -17733 -17734 -17735 -17736 -17737 -17738 -17739 -17740 -17741 -17742 -17743 -17744 -17745 -17746 -17747 -17748 -17749 -17750 -17751 -17752 -17753 -17754 -17755 -17756 -17757 -17758 -17759 -17760 -17761 -17762 -17763 -17764 -17765 -17766 -17767 -17768 -17769 -17770 -17771 -17772 -17773 -17774 -17775 -17776 -17777 -17778 -17779 -17780 -17781 -17782 -17783 -17784 -17785 -17786 -17787 -17788 -17789 -17790 -17791 -17792 -17793 -17794 -17795 -17796 -17797 -17798 -17799 -17800 -17801 -17802 -17803 -17804 -17805 -17806 -17807 -17808 -17809 -17810 -17811 -17812 -17813 -17814 -17815 -17816 -17817 -17818 -17819 -17820 -17821 -17822 -17823 -17824 -17825 -17826 -17827 -17828 -17829 -17830 -17831 -17832 -17833 -17834 -17835 -17836 -17837 -17838 -17839 -17840 -17841 -17842 -17843 -17844 -17845 -17846 -17847 -17848 -17849 -17850 -17851 -17852 -17853 -17854 -17855 -17856 -17857 -17858 -17859 -17860 -17861 -17862 -17863 -17864 -17865 -17866 -17867 -17868 -17869 -17870 -17871 -17872 -17873 -17874 -17875 -17876 -17877 -17878 -17879 -17880 -17881 -17882 -17883 -17884 -17885 -17886 -17887 -17888 -17889 -17890 -17891 -17892 -17893 -17894 -17895 -17896 -17897 -17898 -17899 -17900 -17901 -17902 -17903 -17904 -17905 -17906 -17907 -17908 -17909 -17910 -17911 -17912 -17913 -17914 -17915 -17916 -17917 -17918 -17919 -17920 -17921 -17922 -17923 -17924 -17925 -17926 -17927 -17928 -17929 -17930 -17931 -17932 -17933 -17934 -17935 -17936 -17937 -17938 -17939 -17940 -17941 -17942 -17943 -17944 -17945 -17946 -17947 -17948 -17949 -17950 -17951 -17952 -17953 -17954 -17955 -17956 -17957 -17958 -17959 -17960 -17961 -17962 -17963 -17964 -17965 -17966 -17967 -17968 -17969 -17970 -17971 -17972 -17973 -17974 -17975 -17976 -17977 -17978 -17979 -17980 -17981 -17982 -17983 -17984 -17985 -17986 -17987 -17988 -17989 -17990 -17991 -17992 -17993 -17994 -17995 -17996 -17997 -17998 -17999 -18000 -18001 -18002 -18003 -18004 -18005 -18006 -18007 -18008 -18009 -18010 -18011 -18012 -18013 -18014 -18015 -18016 -18017 -18018 -18019 -18020 -18021 -18022 -18023 -18024 -18025 -18026 -18027 -18028 -18029 -18030 -18031 -18032 -18033 -18034 -18035 -18036 -18037 -18038 -18039 -18040 -18041 -18042 -18043 -18044 -18045 -18046 -18047 -18048 -18049 -18050 -18051 -18052 -18053 -18054 -18055 -18056 -18057 -18058 -18059 -18060 -18061 -18062 -18063 -18064 -18065 -18066 -18067 -18068 -18069 -18070 -18071 -18072 -18073 -18074 -18075 -18076 -18077 -18078 -18079 -18080 -18081 -18082 -18083 -18084 -18085 -18086 -18087 -18088 -18089 -18090 -18091 -18092 -18093 -18094 -18095 -18096 -18097 -18098 -18099 -18100 -18101 -18102 -18103 -18104 -18105 -18106 -18107 -18108 -18109 -18110 -18111 -18112 -18113 -18114 -18115 -18116 -18117 -18118 -18119 -18120 -18121 -18122 -18123 -18124 -18125 -18126 -18127 -18128 -18129 -18130 -18131 -18132 -18133 -18134 -18135 -18136 -18137 -18138 -18139 -18140 -18141 -18142 -18143 -18144 -18145 -18146 -18147 -18148 -18149 -18150 -18151 -18152 -18153 -18154 -18155 -18156 -18157 -18158 -18159 -18160 -18161 -18162 -18163 -18164 -18165 -18166 -18167 -18168 -18169 -18170 -18171 -18172 -18173 -18174 -18175 -18176 -18177 -18178 -18179 -18180 -18181 -18182 -18183 -18184 -18185 -18186 -18187 -18188 -18189 -18190 -18191 -18192 -18193 -18194 -18195 -18196 -18197 -18198 -18199 -18200 -18201 -18202 -18203 -18204 -18205 -18206 -18207 -18208 -18209 -18210 -18211 -18212 -18213 -18214 -18215 -18216 -18217 -18218 -18219 -18220 -18221 -18222 -18223 -18224 -18225 -18226 -18227 -18228 -18229 -18230 -18231 -18232 -18233 -18234 -18235 -18236 -18237 -18238 -18239 -18240 -18241 -18242 -18243 -18244 -18245 -18246 -18247 -18248 -18249 -18250 -18251 -18252 -18253 -18254 -18255 -18256 -18257 -18258 -18259 -18260 -18261 -18262 -18263 -18264 -18265 -18266 -18267 -18268 -18269 -18270 -18271 -18272 -18273 -18274 -18275 -18276 -18277 -18278 -18279 -18280 -18281 -18282 -18283 -18284 -18285 -18286 -18287 -18288 -18289 -18290 -18291 -18292 -18293 -18294 -18295 -18296 -18297 -18298 -18299 -18300 -18301 -18302 -18303 -18304 -18305 -18306 -18307 -18308 -18309 -18310 -18311 -18312 -18313 -18314 -18315 -18316 -18317 -18318 -18319 -18320 -18321 -18322 -18323 -18324 -18325 -18326 -18327 -18328 -18329 -18330 -18331 -18332 -18333 -18334 -18335 -18336 -18337 -18338 -18339 -18340 -18341 -18342 -18343 -18344 -18345 -18346 -18347 -18348 -18349 -18350 -18351 -18352 -18353 -18354 -18355 -18356 -18357 -18358 -18359 -18360 -18361 -18362 -18363 -18364 -18365 -18366 -18367 -18368 -18369 -18370 -18371 -18372 -18373 -18374 -18375 -18376 -18377 -18378 -18379 -18380 -18381 -18382 -18383 -18384 -18385 -18386 -18387 -18388 -18389 -18390 -18391 -18392 -18393 -18394 -18395 -18396 -18397 -18398 -18399 -18400 -18401 -18402 -18403 -18404 -18405 -18406 -18407 -18408 -18409 -18410 -18411 -18412 -18413 -18414 -18415 -18416 -18417 -18418 -18419 -18420 -18421 -18422 -18423 -18424 -18425 -18426 -18427 -18428 -18429 -18430 -18431 -18432 -18433 -18434 -18435 -18436 -18437 -18438 -18439 -18440 -18441 -18442 -18443 -18444 -18445 -18446 -18447 -18448 -18449 -18450 -18451 -18452 -18453 -18454 -18455 -18456 -18457 -18458 -18459 -18460 -18461 -18462 -18463 -18464 -18465 -18466 -18467 -18468 -18469 -18470 -18471 -18472 -18473 -18474 -18475 -18476 -18477 -18478 -18479 -18480 -18481 -18482 -18483 -18484 -18485 -18486 -18487 -18488 -18489 -18490 -18491 -18492 -18493 -18494 -18495 -18496 -18497 -18498 -18499 -18500 -18501 -18502 -18503 -18504 -18505 -18506 -18507 -18508 -18509 -18510 -18511 -18512 -18513 -18514 -18515 -18516 -18517 -18518 -18519 -18520 -18521 -18522 -18523 -18524 -18525 -18526 -18527 -18528 -18529 -18530 -18531 -18532 -18533 -18534 -18535 -18536 -18537 -18538 -18539 -18540 -18541 -18542 -18543 -18544 -18545 -18546 -18547 -18548 -18549 -18550 -18551 -18552 -18553 -18554 -18555 -18556 -18557 -18558 -18559 -18560 -18561 -18562 -18563 -18564 -18565 -18566 -18567 -18568 -18569 -18570 -18571 -18572 -18573 -18574 -18575 -18576 -18577 -18578 -18579 -18580 -18581 -18582 -18583 -18584 -18585 -18586 -18587 -18588 -18589 -18590 -18591 -18592 -18593 -18594 -18595 -18596 -18597 -18598 -18599 -18600 -18601 -18602 -18603 -18604 -18605 -18606 -18607 -18608 -18609 -18610 -18611 -18612 -18613 -18614 -18615 -18616 -18617 -18618 -18619 -18620 -18621 -18622 -18623 -18624 -18625 -18626 -18627 -18628 -18629 -18630 -18631 -18632 -18633 -18634 -18635 -18636 -18637 -18638 -18639 -18640 -18641 -18642 -18643 -18644 -18645 -18646 -18647 -18648 -18649 -18650 -18651 -18652 -18653 -18654 -18655 -18656 -18657 -18658 -18659 -18660 -18661 -18662 -18663 -18664 -18665 -18666 -18667 -18668 -18669 -18670 -18671 -18672 -18673 -18674 -18675 -18676 -18677 -18678 -18679 -18680 -18681 -18682 -18683 -18684 -18685 -18686 -18687 -18688 -18689 -18690 -18691 -18692 -18693 -18694 -18695 -18696 -18697 -18698 -18699 -18700 -18701 -18702 -18703 -18704 -18705 -18706 -18707 -18708 -18709 -18710 -18711 -18712 -18713 -18714 -18715 -18716 -18717 -18718 -18719 -18720 -18721 -18722 -18723 -18724 -18725 -18726 -18727 -18728 -18729 -18730 -18731 -18732 -18733 -18734 -18735 -18736 -18737 -18738 -18739 -18740 -18741 -18742 -18743 -18744 -18745 -18746 -18747 -18748 -18749 -18750 -18751 -18752 -18753 -18754 -18755 -18756 -18757 -18758 -18759 -18760 -18761 -18762 -18763 -18764 -18765 -18766 -18767 -18768 -18769 -18770 -18771 -18772 -18773 -18774 -18775 -18776 -18777 -18778 -18779 -18780 -18781 -18782 -18783 -18784 -18785 -18786 -18787 -18788 -18789 -18790 -18791 -18792 -18793 -18794 -18795 -18796 -18797 -18798 -18799 -18800 -18801 -18802 -18803 -18804 -18805 -18806 -18807 -18808 -18809 -18810 -18811 -18812 -18813 -18814 -18815 -18816 -18817 -18818 -18819 -18820 -18821 -18822 -18823 -18824 -18825 -18826 -18827 -18828 -18829 -18830 -18831 -18832 -18833 -18834 -18835 -18836 -18837 -18838 -18839 -18840 -18841 -18842 -18843 -18844 -18845 -18846 -18847 -18848 -18849 -18850 -18851 -18852 -18853 -18854 -18855 -18856 -18857 -18858 -18859 -18860 -18861 -18862 -18863 -18864 -18865 -18866 -18867 -18868 -18869 -18870 -18871 -18872 -18873 -18874 -18875 -18876 -18877 -18878 -18879 -18880 -18881 -18882 -18883 -18884 -18885 -18886 -18887 -18888 -18889 -18890 -18891 -18892 -18893 -18894 -18895 -18896 -18897 -18898 -18899 -18900 -18901 -18902 -18903 -18904 -18905 -18906 -18907 -18908 -18909 -18910 -18911 -18912 -18913 -18914 -18915 -18916 -18917 -18918 -18919 -18920 -18921 -18922 -18923 -18924 -18925 -18926 -18927 -18928 -18929 -18930 -18931 -18932 -18933 -18934 -18935 -18936 -18937 -18938 -18939 -18940 -18941 -18942 -18943 -18944 -18945 -18946 -18947 -18948 -18949 -18950 -18951 -18952 -18953 -18954 -18955 -18956 -18957 -18958 -18959 -18960 -18961 -18962 -18963 -18964 -18965 -18966 -18967 -18968 -18969 -18970 -18971 -18972 -18973 -18974 -18975 -18976 -18977 -18978 -18979 -18980 -18981 -18982 -18983 -18984 -18985 -18986 -18987 -18988 -18989 -18990 -18991 -18992 -18993 -18994 -18995 -18996 -18997 -18998 -18999 -19000 -19001 -19002 -19003 -19004 -19005 -19006 -19007 -19008 -19009 -19010 -19011 -19012 -19013 -19014 -19015 -19016 -19017 -19018 -19019 -19020 -19021 -19022 -19023 -19024 -19025 -19026 -19027 -19028 -19029 -19030 -19031 -19032 -19033 -19034 -19035 -19036 -19037 -19038 -19039 -19040 -19041 -19042 -19043 -19044 -19045 -19046 -19047 -19048 -19049 -19050 -19051 -19052 -19053 -19054 -19055 -19056 -19057 -19058 -19059 -19060 -19061 -19062 -19063 -19064 -19065 -19066 -19067 -19068 -19069 -19070 -19071 -19072 -19073 -19074 -19075 -19076 -19077 -19078 -19079 -19080 -19081 -19082 -19083 -19084 -19085 -19086 -19087 -19088 -19089 -19090 -19091 -19092 -19093 -19094 -19095 -19096 -19097 -19098 -19099 -19100 -19101 -19102 -19103 -19104 -19105 -19106 -19107 -19108 -19109 -19110 -19111 -19112 -19113 -19114 -19115 -19116 -19117 -19118 -19119 -19120 -19121 -19122 -19123 -19124 -19125 -19126 -19127 -19128 -19129 -19130 -19131 -19132 -19133 -19134 -19135 -19136 -19137 -19138 -19139 -19140 -19141 -19142 -19143 -19144 -19145 -19146 -19147 -19148 -19149 -19150 -19151 -19152 -19153 -19154 -19155 -19156 -19157 -19158 -19159 -19160 -19161 -19162 -19163 -19164 -19165 -19166 -19167 -19168 -19169 -19170 -19171 -19172 -19173 -19174 -19175 -19176 -19177 -19178 -19179 -19180 -19181 -19182 -19183 -19184 -19185 -19186 -19187 -19188 -19189 -19190 -19191 -19192 -19193 -19194 -19195 -19196 -19197 -19198 -19199 -19200 -19201 -19202 -19203 -19204 -19205 -19206 -19207 -19208 -19209 -19210 -19211 -19212 -19213 -19214 -19215 -19216 -19217 -19218 -19219 -19220 -19221 -19222 -19223 -19224 -19225 -19226 -19227 -19228 -19229 -19230 -19231 -19232 -19233 -19234 -19235 -19236 -19237 -19238 -19239 -19240 -19241 -19242 -19243 -19244 -19245 -19246 -19247 -19248 -19249 -19250 -19251 -19252 -19253 -19254 -19255 -19256 -19257 -19258 -19259 -19260 -19261 -19262 -19263 -19264 -19265 -19266 -19267 -19268 -19269 -19270 -19271 -19272 -19273 -19274 -19275 -19276 -19277 -19278 -19279 -19280 -19281 -19282 -19283 -19284 -19285 -19286 -19287 -19288 -19289 -19290 -19291 -19292 -19293 -19294 -19295 -19296 -19297 -19298 -19299 -19300 -19301 -19302 -19303 -19304 -19305 -19306 -19307 -19308 -19309 -19310 -19311 -19312 -19313 -19314 -19315 -19316 -19317 -19318 -19319 -19320 -19321 -19322 -19323 -19324 -19325 -19326 -19327 -19328 -19329 -19330 -19331 -19332 -19333 -19334 -19335 -19336 -19337 -19338 -19339 -19340 -19341 -19342 -19343 -19344 -19345 -19346 -19347 -19348 -19349 -19350 -19351 -19352 -19353 -19354 -19355 -19356 -19357 -19358 -19359 -19360 -19361 -19362 -19363 -19364 -19365 -19366 -19367 -19368 -19369 -19370 -19371 -19372 -19373 -19374 -19375 -19376 -19377 -19378 -19379 -19380 -19381 -19382 -19383 -19384 -19385 -19386 -19387 -19388 -19389 -19390 -19391 -19392 -19393 -19394 -19395 -19396 -19397 -19398 -19399 -19400 -19401 -19402 -19403 -19404 -19405 -19406 -19407 -19408 -19409 -19410 -19411 -19412 -19413 -19414 -19415 -19416 -19417 -19418 -19419 -19420 -19421 -19422 -19423 -19424 -19425 -19426 -19427 -19428 -19429 -19430 -19431 -19432 -19433 -19434 -19435 -19436 -19437 -19438 -19439 -19440 -19441 -19442 -19443 -19444 -19445 -19446 -19447 -19448 -19449 -19450 -19451 -19452 -19453 -19454 -19455 -19456 -19457 -19458 -19459 -19460 -19461 -19462 -19463 -19464 -19465 -19466 -19467 -19468 -19469 -19470 -19471 -19472 -19473 -19474 -19475 -19476 -19477 -19478 -19479 -19480 -19481 -19482 -19483 -19484 -19485 -19486 -19487 -19488 -19489 -19490 -19491 -19492 -19493 -19494 -19495 -19496 -19497 -19498 -19499 -19500 -19501 -19502 -19503 -19504 -19505 -19506 -19507 -19508 -19509 -19510 -19511 -19512 -19513 -19514 -19515 -19516 -19517 -19518 -19519 -19520 -19521 -19522 -19523 -19524 -19525 -19526 -19527 -19528 -19529 -19530 -19531 -19532 -19533 -19534 -19535 -19536 -19537 -19538 -19539 -19540 -19541 -19542 -19543 -19544 -19545 -19546 -19547 -19548 -19549 -19550 -19551 -19552 -19553 -19554 -19555 -19556 -19557 -19558 -19559 -19560 -19561 -19562 -19563 -19564 -19565 -19566 -19567 -19568 -19569 -19570 -19571 -19572 -19573 -19574 -19575 -19576 -19577 -19578 -19579 -19580 -19581 -19582 -19583 -19584 -19585 -19586 -19587 -19588 -19589 -19590 -19591 -19592 -19593 -19594 -19595 -19596 -19597 -19598 -19599 -19600 -19601 -19602 -19603 -19604 -19605 -19606 -19607 -19608 -19609 -19610 -19611 -19612 -19613 -19614 -19615 -19616 -19617 -19618 -19619 -19620 -19621 -19622 -19623 -19624 -19625 -19626 -19627 -19628 -19629 -19630 -19631 -19632 -19633 -19634 -19635 -19636 -19637 -19638 -19639 -19640 -19641 -19642 -19643 -19644 -19645 -19646 -19647 -19648 -19649 -19650 -19651 -19652 -19653 -19654 -19655 -19656 -19657 -19658 -19659 -19660 -19661 -19662 -19663 -19664 -19665 -19666 -19667 -19668 -19669 -19670 -19671 -19672 -19673 -19674 -19675 -19676 -19677 -19678 -19679 -19680 -19681 -19682 -19683 -19684 -19685 -19686 -19687 -19688 -19689 -19690 -19691 -19692 -19693 -19694 -19695 -19696 -19697 -19698 -19699 -19700 -19701 -19702 -19703 -19704 -19705 -19706 -19707 -19708 -19709 -19710 -19711 -19712 -19713 -19714 -19715 -19716 -19717 -19718 -19719 -19720 -19721 -19722 -19723 -19724 -19725 -19726 -19727 -19728 -19729 -19730 -19731 -19732 -19733 -19734 -19735 -19736 -19737 -19738 -19739 -19740 -19741 -19742 -19743 -19744 -19745 -19746 -19747 -19748 -19749 -19750 -19751 -19752 -19753 -19754 -19755 -19756 -19757 -19758 -19759 -19760 -19761 -19762 -19763 -19764 -19765 -19766 -19767 -19768 -19769 -19770 -19771 -19772 -19773 -19774 -19775 -19776 -19777 -19778 -19779 -19780 -19781 -19782 -19783 -19784 -19785 -19786 -19787 -19788 -19789 -19790 -19791 -19792 -19793 -19794 -19795 -19796 -19797 -19798 -19799 -19800 -19801 -19802 -19803 -19804 -19805 -19806 -19807 -19808 -19809 -19810 -19811 -19812 -19813 -19814 -19815 -19816 -19817 -19818 -19819 -19820 -19821 -19822 -19823 -19824 -19825 -19826 -19827 -19828 -19829 -19830 -19831 -19832 -19833 -19834 -19835 -19836 -19837 -19838 -19839 -19840 -19841 -19842 -19843 -19844 -19845 -19846 -19847 -19848 -19849 -19850 -19851 -19852 -19853 -19854 -19855 -19856 -19857 -19858 -19859 -19860 -19861 -19862 -19863 -19864 -19865 -19866 -19867 -19868 -19869 -19870 -19871 -19872 -19873 -19874 -19875 -19876 -19877 -19878 -19879 -19880 -19881 -19882 -19883 -19884 -19885 -19886 -19887 -19888 -19889 -19890 -19891 -19892 -19893 -19894 -19895 -19896 -19897 -19898 -19899 -19900 -19901 -19902 -19903 -19904 -19905 -19906 -19907 -19908 -19909 -19910 -19911 -19912 -19913 -19914 -19915 -19916 -19917 -19918 -19919 -19920 -19921 -19922 -19923 -19924 -19925 -19926 -19927 -19928 -19929 -19930 -19931 -19932 -19933 -19934 -19935 -19936 -19937 -19938 -19939 -19940 -19941 -19942 -19943 -19944 -19945 -19946 -19947 -19948 -19949 -19950 -19951 -19952 -19953 -19954 -19955 -19956 -19957 -19958 -19959 -19960 -19961 -19962 -19963 -19964 -19965 -19966 -19967 -19968 -19969 -19970 -19971 -19972 -19973 -19974 -19975 -19976 -19977 -19978 -19979 -19980 -19981 -19982 -19983 -19984 -19985 -19986 -19987 -19988 -19989 -19990 -19991 -19992 -19993 -19994 -19995 -19996 -19997 -19998 -19999 -20000 -20001 -20002 -20003 -20004 -20005 -20006 -20007 -20008 -20009 -20010 -20011 -20012 -20013 -20014 -20015 -20016 -20017 -20018 -20019 -20020 -20021 -20022 -20023 -20024 -20025 -20026 -20027 -20028 -20029 -20030 -20031 -20032 -20033 -20034 -20035 -20036 -20037 -20038 -20039 -20040 -20041 -20042 -20043 -20044 -20045 -20046 -20047 -20048 -20049 -20050 -20051 -20052 -20053 -20054 -20055 -20056 -20057 -20058 -20059 -20060 -20061 -20062 -20063 -20064 -20065 -20066 -20067 -20068 -20069 -20070 -20071 -20072 -20073 -20074 -20075 -20076 -20077 -20078 -20079 -20080 -20081 -20082 -20083 -20084 -20085 -20086 -20087 -20088 -20089 -20090 -20091 -20092 -20093 -20094 -20095 -20096 -20097 -20098 -20099 -20100 -20101 -20102 -20103 -20104 -20105 -20106 -20107 -20108 -20109 -20110 -20111 -20112 -20113 -20114 -20115 -20116 -20117 -20118 -20119 -20120 -20121 -20122 -20123 -20124 -20125 -20126 -20127 -20128 -20129 -20130 -20131 -20132 -20133 -20134 -20135 -20136 -20137 -20138 -20139 -20140 -20141 -20142 -20143 -20144 -20145 -20146 -20147 -20148 -20149 -20150 -20151 -20152 -20153 -20154 -20155 -20156 -20157 -20158 -20159 -20160 -20161 -20162 -20163 -20164 -20165 -20166 -20167 -20168 -20169 -20170 -20171 -20172 -20173 -20174 -20175 -20176 -20177 -20178 -20179 -20180 -20181 -20182 -20183 -20184 -20185 -20186 -20187 -20188 -20189 -20190 -20191 -20192 -20193 -20194 -20195 -20196 -20197 -20198 -20199 -20200 -20201 -20202 -20203 -20204 -20205 -20206 -20207 -20208 -20209 -20210 -20211 -20212 -20213 -20214 -20215 -20216 -20217 -20218 -20219 -20220 -20221 -20222 -20223 -20224 -20225 -20226 -20227 -20228 -20229 -20230 -20231 -20232 -20233 -20234 -20235 -20236 -20237 -20238 -20239 -20240 -20241 -20242 -20243 -20244 -20245 -20246 -20247 -20248 -20249 -20250 -20251 -20252 -20253 -20254 -20255 -20256 -20257 -20258 -20259 -20260 -20261 -20262 -20263 -20264 -20265 -20266 -20267 -20268 -20269 -20270 -20271 -20272 -20273 -20274 -20275 -20276 -20277 -20278 -20279 -20280 -20281 -20282 -20283 -20284 -20285 -20286 -20287 -20288 -20289 -20290 -20291 -20292 -20293 -20294 -20295 -20296 -20297 -20298 -20299 -20300 -20301 -20302 -20303 -20304 -20305 -20306 -20307 -20308 -20309 -20310 -20311 -20312 -20313 -20314 -20315 -20316 -20317 -20318 -20319 -20320 -20321 -20322 -20323 -20324 -20325 -20326 -20327 -20328 -20329 -20330 -20331 -20332 -20333 -20334 -20335 -20336 -20337 -20338 -20339 -20340 -20341 -20342 -20343 -20344 -20345 -20346 -20347 -20348 -20349 -20350 -20351 -20352 -20353 -20354 -20355 -20356 -20357 -20358 -20359 -20360 -20361 -20362 -20363 -20364 -20365 -20366 -20367 -20368 -20369 -20370 -20371 -20372 -20373 -20374 -20375 -20376 -20377 -20378 -20379 -20380 -20381 -20382 -20383 -20384 -20385 -20386 -20387 -20388 -20389 -20390 -20391 -20392 -20393 -20394 -20395 -20396 -20397 -20398 -20399 -20400 -20401 -20402 -20403 -20404 -20405 -20406 -20407 -20408 -20409 -20410 -20411 -20412 -20413 -20414 -20415 -20416 -20417 -20418 -20419 -20420 -20421 -20422 -20423 -20424 -20425 -20426 -20427 -20428 -20429 -20430 -20431 -20432 -20433 -20434 -20435 -20436 -20437 -20438 -20439 -20440 -20441 -20442 -20443 -20444 -20445 -20446 -20447 -20448 -20449 -20450 -20451 -20452 -20453 -20454 -20455 -20456 -20457 -20458 -20459 -20460 -20461 -20462 -20463 -20464 -20465 -20466 -20467 -20468 -20469 -20470 -20471 -20472 -20473 -20474 -20475 -20476 -20477 -20478 -20479 -20480 -20481 -20482 -20483 -20484 -20485 -20486 -20487 -20488 -20489 -20490 -20491 -20492 -20493 -20494 -20495 -20496 -20497 -20498 -20499 -20500 -20501 -20502 -20503 -20504 -20505 -20506 -20507 -20508 -20509 -20510 -20511 -20512 -20513 -20514 -20515 -20516 -20517 -20518 -20519 -20520 -20521 -20522 -20523 -20524 -20525 -20526 -20527 -20528 -20529 -20530 -20531 -20532 -20533 -20534 -20535 -20536 -20537 -20538 -20539 -20540 -20541 -20542 -20543 -20544 -20545 -20546 -20547 -20548 -20549 -20550 -20551 -20552 -20553 -20554 -20555 -20556 -20557 -20558 -20559 -20560 -20561 -20562 -20563 -20564 -20565 -20566 -20567 -20568 -20569 -20570 -20571 -20572 -20573 -20574 -20575 -20576 -20577 -20578 -20579 -20580 -20581 -20582 -20583 -20584 -20585 -20586 -20587 -20588 -20589 -20590 -20591 -20592 -20593 -20594 -20595 -20596 -20597 -20598 -20599 -20600 -20601 -20602 -20603 -20604 -20605 -20606 -20607 -20608 -20609 -20610 -20611 -20612 -20613 -20614 -20615 -20616 -20617 -20618 -20619 -20620 -20621 -20622 -20623 -20624 -20625 -20626 -20627 -20628 -20629 -20630 -20631 -20632 -20633 -20634 -20635 -20636 -20637 -20638 -20639 -20640 -20641 -20642 -20643 -20644 -20645 -20646 -20647 -20648 -20649 -20650 -20651 -20652 -20653 -20654 -20655 -20656 -20657 -20658 -20659 -20660 -20661 -20662 -20663 -20664 -20665 -20666 -20667 -20668 -20669 -20670 -20671 -20672 -20673 -20674 -20675 -20676 -20677 -20678 -20679 -20680 -20681 -20682 -20683 -20684 -20685 -20686 -20687 -20688 -20689 -20690 -20691 -20692 -20693 -20694 -20695 -20696 -20697 -20698 -20699 -20700 -20701 -20702 -20703 -20704 -20705 -20706 -20707 -20708 -20709 -20710 -20711 -20712 -20713 -20714 -20715 -20716 -20717 -20718 -20719 -20720 -20721 -20722 -20723 -20724 -20725 -20726 -20727 -20728 -20729 -20730 -20731 -20732 -20733 -20734 -20735 -20736 -20737 -20738 -20739 -20740 -20741 -20742 -20743 -20744 -20745 -20746 -20747 -20748 -20749 -20750 -20751 -20752 -20753 -20754 -20755 -20756 -20757 -20758 -20759 -20760 -20761 -20762 -20763 -20764 -20765 -20766 -20767 -20768 -20769 -20770 -20771 -20772 -20773 -20774 -20775 -20776 -20777 -20778 -20779 -20780 -20781 -20782 -20783 -20784 -20785 -20786 -20787 -20788 -20789 -20790 -20791 -20792 -20793 -20794 -20795 -20796 -20797 -20798 -20799 -20800 -20801 -20802 -20803 -20804 -20805 -20806 -20807 -20808 -20809 -20810 -20811 -20812 -20813 -20814 -20815 -20816 -20817 -20818 -20819 -20820 -20821 -20822 -20823 -20824 -20825 -20826 -20827 -20828 -20829 -20830 -20831 -20832 -20833 -20834 -20835 -20836 -20837 -20838 -20839 -20840 -20841 -20842 -20843 -20844 -20845 -20846 -20847 -20848 -20849 -20850 -20851 -20852 -20853 -20854 -20855 -20856 -20857 -20858 -20859 -20860 -20861 -20862 -20863 -20864 -20865 -20866 -20867 -20868 -20869 -20870 -20871 -20872 -20873 -20874 -20875 -20876 -20877 -20878 -20879 -20880 -20881 -20882 -20883 -20884 -20885 -20886 -20887 -20888 -20889 -20890 -20891 -20892 -20893 -20894 -20895 -20896 -20897 -20898 -20899 -20900 -20901 -20902 -20903 -20904 -20905 -20906 -20907 -20908 -20909 -20910 -20911 -20912 -20913 -20914 -20915 -20916 -20917 -20918 -20919 -20920 -20921 -20922 -20923 -20924 -20925 -20926 -20927 -20928 -20929 -20930 -20931 -20932 -20933 -20934 -20935 -20936 -20937 -20938 -20939 -20940 -20941 -20942 -20943 -20944 -20945 -20946 -20947 -20948 -20949 -20950 -20951 -20952 -20953 -20954 -20955 -20956 -20957 -20958 -20959 -20960 -20961 -20962 -20963 -20964 -20965 -20966 -20967 -20968 -20969 -20970 -20971 -20972 -20973 -20974 -20975 -20976 -20977 -20978 -20979 -20980 -20981 -20982 -20983 -20984 -20985 -20986 -20987 -20988 -20989 -20990 -20991 -20992 -20993 -20994 -20995 -20996 -20997 -20998 -20999 -21000 -21001 -21002 -21003 -21004 -21005 -21006 -21007 -21008 -21009 -21010 -21011 -21012 -21013 -21014 -21015 -21016 -21017 -21018 -21019 -21020 -21021 -21022 -21023 -21024 -21025 -21026 -21027 -21028 -21029 -21030 -21031 -21032 -21033 -21034 -21035 -21036 -21037 -21038 -21039 -21040 -21041 -21042 -21043 -21044 -21045 -21046 -21047 -21048 -21049 -21050 -21051 -21052 -21053 -21054 -21055 -21056 -21057 -21058 -21059 -21060 -21061 -21062 -21063 -21064 -21065 -21066 -21067 -21068 -21069 -21070 -21071 -21072 -21073 -21074 -21075 -21076 -21077 -21078 -21079 -21080 -21081 -21082 -21083 -21084 -21085 -21086 -21087 -21088 -21089 -21090 -21091 -21092 -21093 -21094 -21095 -21096 -21097 -21098 -21099 -21100 -21101 -21102 -21103 -21104 -21105 -21106 -21107 -21108 -21109 -21110 -21111 -21112 -21113 -21114 -21115 -21116 -21117 -21118 -21119 -21120 -21121 -21122 -21123 -21124 -21125 -21126 -21127 -21128 -21129 -21130 -21131 -21132 -21133 -21134 -21135 -21136 -21137 -21138 -21139 -21140 -21141 -21142 -21143 -21144 -21145 -21146 -21147 -21148 -21149 -21150 -21151 -21152 -21153 -21154 -21155 -21156 -21157 -21158 -21159 -21160 -21161 -21162 -21163 -21164 -21165 -21166 -21167 -21168 -21169 -21170 -21171 -21172 -21173 -21174 -21175 -21176 -21177 -21178 -21179 -21180 -21181 -21182 -21183 -21184 -21185 -21186 -21187 -21188 -21189 -21190 -21191 -21192 -21193 -21194 -21195 -21196 -21197 -21198 -21199 -21200 -21201 -21202 -21203 -21204 -21205 -21206 -21207 -21208 -21209 -21210 -21211 -21212 -21213 -21214 -21215 -21216 -21217 -21218 -21219 -21220 -21221 -21222 -21223 -21224 -21225 -21226 -21227 -21228 -21229 -21230 -21231 -21232 -21233 -21234 -21235 -21236 -21237 -21238 -21239 -21240 -21241 -21242 -21243 -21244 -21245 -21246 -21247 -21248 -21249 -21250 -21251 -21252 -21253 -21254 -21255 -21256 -21257 -21258 -21259 -21260 -21261 -21262 -21263 -21264 -21265 -21266 -21267 -21268 -21269 -21270 -21271 -21272 -21273 -21274 -21275 -21276 -21277 -21278 -21279 -21280 -21281 -21282 -21283 -21284 -21285 -21286 -21287 -21288 -21289 -21290 -21291 -21292 -21293 -21294 -21295 -21296 -21297 -21298 -21299 -21300 -21301 -21302 -21303 -21304 -21305 -21306 -21307 -21308 -21309 -21310 -21311 -21312 -21313 -21314 -21315 -21316 -21317 -21318 -21319 -21320 -21321 -21322 -21323 -21324 -21325 -21326 -21327 -21328 -21329 -21330 -21331 -21332 -21333 -21334 -21335 -21336 -21337 -21338 -21339 -21340 -21341 -21342 -21343 -21344 -21345 -21346 -21347 -21348 -21349 -21350 -21351 -21352 -21353 -21354 -21355 -21356 -21357 -21358 -21359 -21360 -21361 -21362 -21363 -21364 -21365 -21366 -21367 -21368 -21369 -21370 -21371 -21372 -21373 -21374 -21375 -21376 -21377 -21378 -21379 -21380 -21381 -21382 -21383 -21384 -21385 -21386 -21387 -21388 -21389 -21390 -21391 -21392 -21393 -21394 -21395 -21396 -21397 -21398 -21399 -21400 -21401 -21402 -21403 -21404 -21405 -21406 -21407 -21408 -21409 -21410 -21411 -21412 -21413 -21414 -21415 -21416 -21417 -21418 -21419 -21420 -21421 -21422 -21423 -21424 -21425 -21426 -21427 -21428 -21429 -21430 -21431 -21432 -21433 -21434 -21435 -21436 -21437 -21438 -21439 -21440 -21441 -21442 -21443 -21444 -21445 -21446 -21447 -21448 -21449 -21450 -21451 -21452 -21453 -21454 -21455 -21456 -21457 -21458 -21459 -21460 -21461 -21462 -21463 -21464 -21465 -21466 -21467 -21468 -21469 -21470 -21471 -21472 -21473 -21474 -21475 -21476 -21477 -21478 -21479 -21480 -21481 -21482 -21483 -21484 -21485 -21486 -21487 -21488 -21489 -21490 -21491 -21492 -21493 -21494 -21495 -21496 -21497 -21498 -21499 -21500 -21501 -21502 -21503 -21504 -21505 -21506 -21507 -21508 -21509 -21510 -21511 -21512 -21513 -21514 -21515 -21516 -21517 -21518 -21519 -21520 -21521 -21522 -21523 -21524 -21525 -21526 -21527 -21528 -21529 -21530 -21531 -21532 -21533 -21534 -21535 -21536 -21537 -21538 -21539 -21540 -21541 -21542 -21543 -21544 -21545 -21546 -21547 -21548 -21549 -21550 -21551 -21552 -21553 -21554 -21555 -21556 -21557 -21558 -21559 -21560 -21561 -21562 -21563 -21564 -21565 -21566 -21567 -21568 -21569 -21570 -21571 -21572 -21573 -21574 -21575 -21576 -21577 -21578 -21579 -21580 -21581 -21582 -21583 -21584 -21585 -21586 -21587 -21588 -21589 -21590 -21591 -21592 -21593 -21594 -21595 -21596 -21597 -21598 -21599 -21600 -21601 -21602 -21603 -21604 -21605 -21606 -21607 -21608 -21609 -21610 -21611 -21612 -21613 -21614 -21615 -21616 -21617 -21618 -21619 -21620 -21621 -21622 -21623 -21624 -21625 -21626 -21627 -21628 -21629 -21630 -21631 -21632 -21633 -21634 -21635 -21636 -21637 -21638 -21639 -21640 -21641 -21642 -21643 -21644 -21645 -21646 -21647 -21648 -21649 -21650 -21651 -21652 -21653 -21654 -21655 -21656 -21657 -21658 -21659 -21660 -21661 -21662 -21663 -21664 -21665 -21666 -21667 -21668 -21669 -21670 -21671 -21672 -21673 -21674 -21675 -21676 -21677 -21678 -21679 -21680 -21681 -21682 -21683 -21684 -21685 -21686 -21687 -21688 -21689 -21690 -21691 -21692 -21693 -21694 -21695 -21696 -21697 -21698 -21699 -21700 -21701 -21702 -21703 -21704 -21705 -21706 -21707 -21708 -21709 -21710 -21711 -21712 -21713 -21714 -21715 -21716 -21717 -21718 -21719 -21720 -21721 -21722 -21723 -21724 -21725 -21726 -21727 -21728 -21729 -21730 -21731 -21732 -21733 -21734 -21735 -21736 -21737 -21738 -21739 -21740 -21741 -21742 -21743 -21744 -21745 -21746 -21747 -21748 -21749 -21750 -21751 -21752 -21753 -21754 -21755 -21756 -21757 -21758 -21759 -21760 -21761 -21762 -21763 -21764 -21765 -21766 -21767 -21768 -21769 -21770 -21771 -21772 -21773 -21774 -21775 -21776 -21777 -21778 -21779 -21780 -21781 -21782 -21783 -21784 -21785 -21786 -21787 -21788 -21789 -21790 -21791 -21792 -21793 -21794 -21795 -21796 -21797 -21798 -21799 -21800 -21801 -21802 -21803 -21804 -21805 -21806 -21807 -21808 -21809 -21810 -21811 -21812 -21813 -21814 -21815 -21816 -21817 -21818 -21819 -21820 -21821 -21822 -21823 -21824 -21825 -21826 -21827 -21828 -21829 -21830 -21831 -21832 -21833 -21834 -21835 -21836 -21837 -21838 -21839 -21840 -21841 -21842 -21843 -21844 -21845 -21846 -21847 -21848 -21849 -21850 -21851 -21852 -21853 -21854 -21855 -21856 -21857 -21858 -21859 -21860 -21861 -21862 -21863 -21864 -21865 -21866 -21867 -21868 -21869 -21870 -21871 -21872 -21873 -21874 -21875 -21876 -21877 -21878 -21879 -21880 -21881 -21882 -21883 -21884 -21885 -21886 -21887 -21888 -21889 -21890 -21891 -21892 -21893 -21894 -21895 -21896 -21897 -21898 -21899 -21900 -21901 -21902 -21903 -21904 -21905 -21906 -21907 -21908 -21909 -21910 -21911 -21912 -21913 -21914 -21915 -21916 -21917 -21918 -21919 -21920 -21921 -21922 -21923 -21924 -21925 -21926 -21927 -21928 -21929 -21930 -21931 -21932 -21933 -21934 -21935 -21936 -21937 -21938 -21939 -21940 -21941 -21942 -21943 -21944 -21945 -21946 -21947 -21948 -21949 -21950 -21951 -21952 -21953 -21954 -21955 -21956 -21957 -21958 -21959 -21960 -21961 -21962 -21963 -21964 -21965 -21966 -21967 -21968 -21969 -21970 -21971 -21972 -21973 -21974 -21975 -21976 -21977 -21978 -21979 -21980 -21981 -21982 -21983 -21984 -21985 -21986 -21987 -21988 -21989 -21990 -21991 -21992 -21993 -21994 -21995 -21996 -21997 -21998 -21999 -22000 -22001 -22002 -22003 -22004 -22005 -22006 -22007 -22008 -22009 -22010 -22011 -22012 -22013 -22014 -22015 -22016 -22017 -22018 -22019 -22020 -22021 -22022 -22023 -22024 -22025 -22026 -22027 -22028 -22029 -22030 -22031 -22032 -22033 -22034 -22035 -22036 -22037 -22038 -22039 -22040 -22041 -22042 -22043 -22044 -22045 -22046 -22047 -22048 -22049 -22050 -22051 -22052 -22053 -22054 -22055 -22056 -22057 -22058 -22059 -22060 -22061 -22062 -22063 -22064 -22065 -22066 -22067 -22068 -22069 -22070 -22071 -22072 -22073 -22074 -22075 -22076 -22077 -22078 -22079 -22080 -22081 -22082 -22083 -22084 -22085 -22086 -22087 -22088 -22089 -22090 -22091 -22092 -22093 -22094 -22095 -22096 -22097 -22098 -22099 -22100 -22101 -22102 -22103 -22104 -22105 -22106 -22107 -22108 -22109 -22110 -22111 -22112 -22113 -22114 -22115 -22116 -22117 -22118 -22119 -22120 -22121 -22122 -22123 -22124 -22125 -22126 -22127 -22128 -22129 -22130 -22131 -22132 -22133 -22134 -22135 -22136 -22137 -22138 -22139 -22140 -22141 -22142 -22143 -22144 -22145 -22146 -22147 -22148 -22149 -22150 -22151 -22152 -22153 -22154 -22155 -22156 -22157 -22158 -22159 -22160 -22161 -22162 -22163 -22164 -22165 -22166 -22167 -22168 -22169 -22170 -22171 -22172 -22173 -22174 -22175 -22176 -22177 -22178 -22179 -22180 -22181 -22182 -22183 -22184 -22185 -22186 -22187 -22188 -22189 -22190 -22191 -22192 -22193 -22194 -22195 -22196 -22197 -22198 -22199 -22200 -22201 -22202 -22203 -22204 -22205 -22206 -22207 -22208 -22209 -22210 -22211 -22212 -22213 -22214 -22215 -22216 -22217 -22218 -22219 -22220 -22221 -22222 -22223 -22224 -22225 -22226 -22227 -22228 -22229 -22230 -22231 -22232 -22233 -22234 -22235 -22236 -22237 -22238 -22239 -22240 -22241 -22242 -22243 -22244 -22245 -22246 -22247 -22248 -22249 -22250 -22251 -22252 -22253 -22254 -22255 -22256 -22257 -22258 -22259 -22260 -22261 -22262 -22263 -22264 -22265 -22266 -22267 -22268 -22269 -22270 -22271 -22272 -22273 -22274 -22275 -22276 -22277 -22278 -22279 -22280 -22281 -22282 -22283 -22284 -22285 -22286 -22287 -22288 -22289 -22290 -22291 -22292 -22293 -22294 -22295 -22296 -22297 -22298 -22299 -22300 -22301 -22302 -22303 -22304 -22305 -22306 -22307 -22308 -22309 -22310 -22311 -22312 -22313 -22314 -22315 -22316 -22317 -22318 -22319 -22320 -22321 -22322 -22323 -22324 -22325 -22326 -22327 -22328 -22329 -22330 -22331 -22332 -22333 -22334 -22335 -22336 -22337 -22338 -22339 -22340 -22341 -22342 -22343 -22344 -22345 -22346 -22347 -22348 -22349 -22350 -22351 -22352 -22353 -22354 -22355 -22356 -22357 -22358 -22359 -22360 -22361 -22362 -22363 -22364 -22365 -22366 -22367 -22368 -22369 -22370 -22371 -22372 -22373 -22374 -22375 -22376 -22377 -22378 -22379 -22380 -22381 -22382 -22383 -22384 -22385 -22386 -22387 -22388 -22389 -22390 -22391 -22392 -22393 -22394 -22395 -22396 -22397 -22398 -22399 -22400 -22401 -22402 -22403 -22404 -22405 -22406 -22407 -22408 -22409 -22410 -22411 -22412 -22413 -22414 -22415 -22416 -22417 -22418 -22419 -22420 -22421 -22422 -22423 -22424 -22425 -22426 -22427 -22428 -22429 -22430 -22431 -22432 -22433 -22434 -22435 -22436 -22437 -22438 -22439 -22440 -22441 -22442 -22443 -22444 -22445 -22446 -22447 -22448 -22449 -22450 -22451 -22452 -22453 -22454 -22455 -22456 -22457 -22458 -22459 -22460 -22461 -22462 -22463 -22464 -22465 -22466 -22467 -22468 -22469 -22470 -22471 -22472 -22473 -22474 -22475 -22476 -22477 -22478 -22479 -22480 -22481 -22482 -22483 -22484 -22485 -22486 -22487 -22488 -22489 -22490 -22491 -22492 -22493 -22494 -22495 -22496 -22497 -22498 -22499 -22500 -22501 -22502 -22503 -22504 -22505 -22506 -22507 -22508 -22509 -22510 -22511 -22512 -22513 -22514 -22515 -22516 -22517 -22518 -22519 -22520 -22521 -22522 -22523 -22524 -22525 -22526 -22527 -22528 -22529 -22530 -22531 -22532 -22533 -22534 -22535 -22536 -22537 -22538 -22539 -22540 -22541 -22542 -22543 -22544 -22545 -22546 -22547 -22548 -22549 -22550 -22551 -22552 -22553 -22554 -22555 -22556 -22557 -22558 -22559 -22560 -22561 -22562 -22563 -22564 -22565 -22566 -22567 -22568 -22569 -22570 -22571 -22572 -22573 -22574 -22575 -22576 -22577 -22578 -22579 -22580 -22581 -22582 -22583 -22584 -22585 -22586 -22587 -22588 -22589 -22590 -22591 -22592 -22593 -22594 -22595 -22596 -22597 -22598 -22599 -22600 -22601 -22602 -22603 -22604 -22605 -22606 -22607 -22608 -22609 -22610 -22611 -22612 -22613 -22614 -22615 -22616 -22617 -22618 -22619 -22620 -22621 -22622 -22623 -22624 -22625 -22626 -22627 -22628 -22629 -22630 -22631 -22632 -22633 -22634 -22635 -22636 -22637 -22638 -22639 -22640 -22641 -22642 -22643 -22644 -22645 -22646 -22647 -22648 -22649 -22650 -22651 -22652 -22653 -22654 -22655 -22656 -22657 -22658 -22659 -22660 -22661 -22662 -22663 -22664 -22665 -22666 -22667 -22668 -22669 -22670 -22671 -22672 -22673 -22674 -22675 -22676 -22677 -22678 -22679 -22680 -22681 -22682 -22683 -22684 -22685 -22686 -22687 -22688 -22689 -22690 -22691 -22692 -22693 -22694 -22695 -22696 -22697 -22698 -22699 -22700 -22701 -22702 -22703 -22704 -22705 -22706 -22707 -22708 -22709 -22710 -22711 -22712 -22713 -22714 -22715 -22716 -22717 -22718 -22719 -22720 -22721 -22722 -22723 -22724 -22725 -22726 -22727 -22728 -22729 -22730 -22731 -22732 -22733 -22734 -22735 -22736 -22737 -22738 -22739 -22740 -22741 -22742 -22743 -22744 -22745 -22746 -22747 -22748 -22749 -22750 -22751 -22752 -22753 -22754 -22755 -22756 -22757 -22758 -22759 -22760 -22761 -22762 -22763 -22764 -22765 -22766 -22767 -22768 -22769 -22770 -22771 -22772 -22773 -22774 -22775 -22776 -22777 -22778 -22779 -22780 -22781 -22782 -22783 -22784 -22785 -22786 -22787 -22788 -22789 -22790 -22791 -22792 -22793 -22794 -22795 -22796 -22797 -22798 -22799 -22800 -22801 -22802 -22803 -22804 -22805 -22806 -22807 -22808 -22809 -22810 -22811 -22812 -22813 -22814 -22815 -22816 -22817 -22818 -22819 -22820 -22821 -22822 -22823 -22824 -22825 -22826 -22827 -22828 -22829 -22830 -22831 -22832 -22833 -22834 -22835 -22836 -22837 -22838 -22839 -22840 -22841 -22842 -22843 -22844 -22845 -22846 -22847 -22848 -22849 -22850 -22851 -22852 -22853 -22854 -22855 -22856 -22857 -22858 -22859 -22860 -22861 -22862 -22863 -22864 -22865 -22866 -22867 -22868 -22869 -22870 -22871 -22872 -22873 -22874 -22875 -22876 -22877 -22878 -22879 -22880 -22881 -22882 -22883 -22884 -22885 -22886 -22887 -22888 -22889 -22890 -22891 -22892 -22893 -22894 -22895 -22896 -22897 -22898 -22899 -22900 -22901 -22902 -22903 -22904 -22905 -22906 -22907 -22908 -22909 -22910 -22911 -22912 -22913 -22914 -22915 -22916 -22917 -22918 -22919 -22920 -22921 -22922 -22923 -22924 -22925 -22926 -22927 -22928 -22929 -22930 -22931 -22932 -22933 -22934 -22935 -22936 -22937 -22938 -22939 -22940 -22941 -22942 -22943 -22944 -22945 -22946 -22947 -22948 -22949 -22950 -22951 -22952 -22953 -22954 -22955 -22956 -22957 -22958 -22959 -22960 -22961 -22962 -22963 -22964 -22965 -22966 -22967 -22968 -22969 -22970 -22971 -22972 -22973 -22974 -22975 -22976 -22977 -22978 -22979 -22980 -22981 -22982 -22983 -22984 -22985 -22986 -22987 -22988 -22989 -22990 -22991 -22992 -22993 -22994 -22995 -22996 -22997 -22998 -22999 -23000 -23001 -23002 -23003 -23004 -23005 -23006 -23007 -23008 -23009 -23010 -23011 -23012 -23013 -23014 -23015 -23016 -23017 -23018 -23019 -23020 -23021 -23022 -23023 -23024 -23025 -23026 -23027 -23028 -23029 -23030 -23031 -23032 -23033 -23034 -23035 -23036 -23037 -23038 -23039 -23040 -23041 -23042 -23043 -23044 -23045 -23046 -23047 -23048 -23049 -23050 -23051 -23052 -23053 -23054 -23055 -23056 -23057 -23058 -23059 -23060 -23061 -23062 -23063 -23064 -23065 -23066 -23067 -23068 -23069 -23070 -23071 -23072 -23073 -23074 -23075 -23076 -23077 -23078 -23079 -23080 -23081 -23082 -23083 -23084 -23085 -23086 -23087 -23088 -23089 -23090 -23091 -23092 -23093 -23094 -23095 -23096 -23097 -23098 -23099 -23100 -23101 -23102 -23103 -23104 -23105 -23106 -23107 -23108 -23109 -23110 -23111 -23112 -23113 -23114 -23115 -23116 -23117 -23118 -23119 -23120 -23121 -23122 -23123 -23124 -23125 -23126 -23127 -23128 -23129 -23130 -23131 -23132 -23133 -23134 -23135 -23136 -23137 -23138 -23139 -23140 -23141 -23142 -23143 -23144 -23145 -23146 -23147 -23148 -23149 -23150 -23151 -23152 -23153 -23154 -23155 -23156 -23157 -23158 -23159 -23160 -23161 -23162 -23163 -23164 -23165 -23166 -23167 -23168 -23169 -23170 -23171 -23172 -23173 -23174 -23175 -23176 -23177 -23178 -23179 -23180 -23181 -23182 -23183 -23184 -23185 -23186 -23187 -23188 -23189 -23190 -23191 -23192 -23193 -23194 -23195 -23196 -23197 -23198 -23199 -23200 -23201 -23202 -23203 -23204 -23205 -23206 -23207 -23208 -23209 -23210 -23211 -23212 -23213 -23214 -23215 -23216 -23217 -23218 -23219 -23220 -23221 -23222 -23223 -23224 -23225 -23226 -23227 -23228 -23229 -23230 -23231 -23232 -23233 -23234 -23235 -23236 -23237 -23238 -23239 -23240 -23241 -23242 -23243 -23244 -23245 -23246 -23247 -23248 -23249 -23250 -23251 -23252 -23253 -23254 -23255 -23256 -23257 -23258 -23259 -23260 -23261 -23262 -23263 -23264 -23265 -23266 -23267 -23268 -23269 -23270 -23271 -23272 -23273 -23274 -23275 -23276 -23277 -23278 -23279 -23280 -23281 -23282 -23283 -23284 -23285 -23286 -23287 -23288 -23289 -23290 -23291 -23292 -23293 -23294 -23295 -23296 -23297 -23298 -23299 -23300 -23301 -23302 -23303 -23304 -23305 -23306 -23307 -23308 -23309 -23310 -23311 -23312 -23313 -23314 -23315 -23316 -23317 -23318 -23319 -23320 -23321 -23322 -23323 -23324 -23325 -23326 -23327 -23328 -23329 -23330 -23331 -23332 -23333 -23334 -23335 -23336 -23337 -23338 -23339 -23340 -23341 -23342 -23343 -23344 -23345 -23346 -23347 -23348 -23349 -23350 -23351 -23352 -23353 -23354 -23355 -23356 -23357 -23358 -23359 -23360 -23361 -23362 -23363 -23364 -23365 -23366 -23367 -23368 -23369 -23370 -23371 -23372 -23373 -23374 -23375 -23376 -23377 -23378 -23379 -23380 -23381 -23382 -23383 -23384 -23385 -23386 -23387 -23388 -23389 -23390 -23391 -23392 -23393 -23394 -23395 -23396 -23397 -23398 -23399 -23400 -23401 -23402 -23403 -23404 -23405 -23406 -23407 -23408 -23409 -23410 -23411 -23412 -23413 -23414 -23415 -23416 -23417 -23418 -23419 -23420 -23421 -23422 -23423 -23424 -23425 -23426 -23427 -23428 -23429 -23430 -23431 -23432 -23433 -23434 -23435 -23436 -23437 -23438 -23439 -23440 -23441 -23442 -23443 -23444 -23445 -23446 -23447 -23448 -23449 -23450 -23451 -23452 -23453 -23454 -23455 -23456 -23457 -23458 -23459 -23460 -23461 -23462 -23463 -23464 -23465 -23466 -23467 -23468 -23469 -23470 -23471 -23472 -23473 -23474 -23475 -23476 -23477 -23478 -23479 -23480 -23481 -23482 -23483 -23484 -23485 -23486 -23487 -23488 -23489 -23490 -23491 -23492 -23493 -23494 -23495 -23496 -23497 -23498 -23499 -23500 -23501 -23502 -23503 -23504 -23505 -23506 -23507 -23508 -23509 -23510 -23511 -23512 -23513 -23514 -23515 -23516 -23517 -23518 -23519 -23520 -23521 -23522 -23523 -23524 -23525 -23526 -23527 -23528 -23529 -23530 -23531 -23532 -23533 -23534 -23535 -23536 -23537 -23538 -23539 -23540 -23541 -23542 -23543 -23544 -23545 -23546 -23547 -23548 -23549 -23550 -23551 -23552 -23553 -23554 -23555 -23556 -23557 -23558 -23559 -23560 -23561 -23562 -23563 -23564 -23565 -23566 -23567 -23568 -23569 -23570 -23571 -23572 -23573 -23574 -23575 -23576 -23577 -23578 -23579 -23580 -23581 -23582 -23583 -23584 -23585 -23586 -23587 -23588 -23589 -23590 -23591 -23592 -23593 -23594 -23595 -23596 -23597 -23598 -23599 -23600 -23601 -23602 -23603 -23604 -23605 -23606 -23607 -23608 -23609 -23610 -23611 -23612 -23613 -23614 -23615 -23616 -23617 -23618 -23619 -23620 -23621 -23622 -23623 -23624 -23625 -23626 -23627 -23628 -23629 -23630 -23631 -23632 -23633 -23634 -23635 -23636 -23637 -23638 -23639 -23640 -23641 -23642 -23643 -23644 -23645 -23646 -23647 -23648 -23649 -23650 -23651 -23652 -23653 -23654 -23655 -23656 -23657 -23658 -23659 -23660 -23661 -23662 -23663 -23664 -23665 -23666 -23667 -23668 -23669 -23670 -23671 -23672 -23673 -23674 -23675 -23676 -23677 -23678 -23679 -23680 -23681 -23682 -23683 -23684 -23685 -23686 -23687 -23688 -23689 -23690 -23691 -23692 -23693 -23694 -23695 -23696 -23697 -23698 -23699 -23700 -23701 -23702 -23703 -23704 -23705 -23706 -23707 -23708 -23709 -23710 -23711 -23712 -23713 -23714 -23715 -23716 -23717 -23718 -23719 -23720 -23721 -23722 -23723 -23724 -23725 -23726 -23727 -23728 -23729 -23730 -23731 -23732 -23733 -23734 -23735 -23736 -23737 -23738 -23739 -23740 -23741 -23742 -23743 -23744 -23745 -23746 -23747 -23748 -23749 -23750 -23751 -23752 -23753 -23754 -23755 -23756 -23757 -23758 -23759 -23760 -23761 -23762 -23763 -23764 -23765 -23766 -23767 -23768 -23769 -23770 -23771 -23772 -23773 -23774 -23775 -23776 -23777 -23778 -23779 -23780 -23781 -23782 -23783 -23784 -23785 -23786 -23787 -23788 -23789 -23790 -23791 -23792 -23793 -23794 -23795 -23796 -23797 -23798 -23799 -23800 -23801 -23802 -23803 -23804 -23805 -23806 -23807 -23808 -23809 -23810 -23811 -23812 -23813 -23814 -23815 -23816 -23817 -23818 -23819 -23820 -23821 -23822 -23823 -23824 -23825 -23826 -23827 -23828 -23829 -23830 -23831 -23832 -23833 -23834 -23835 -23836 -23837 -23838 -23839 -23840 -23841 -23842 -23843 -23844 -23845 -23846 -23847 -23848 -23849 -23850 -23851 -23852 -23853 -23854 -23855 -23856 -23857 -23858 -23859 -23860 -23861 -23862 -23863 -23864 -23865 -23866 -23867 -23868 -23869 -23870 -23871 -23872 -23873 -23874 -23875 -23876 -23877 -23878 -23879 -23880 -23881 -23882 -23883 -23884 -23885 -23886 -23887 -23888 -23889 -23890 -23891 -23892 -23893 -23894 -23895 -23896 -23897 -23898 -23899 -23900 -23901 -23902 -23903 -23904 -23905 -23906 -23907 -23908 -23909 -23910 -23911 -23912 -23913 -23914 -23915 -23916 -23917 -23918 -23919 -23920 -23921 -23922 -23923 -23924 -23925 -23926 -23927 -23928 -23929 -23930 -23931 -23932 -23933 -23934 -23935 -23936 -23937 -23938 -23939 -23940 -23941 -23942 -23943 -23944 -23945 -23946 -23947 -23948 -23949 -23950 -23951 -23952 -23953 -23954 -23955 -23956 -23957 -23958 -23959 -23960 -23961 -23962 -23963 -23964 -23965 -23966 -23967 -23968 -23969 -23970 -23971 -23972 -23973 -23974 -23975 -23976 -23977 -23978 -23979 -23980 -23981 -23982 -23983 -23984 -23985 -23986 -23987 -23988 -23989 -23990 -23991 -23992 -23993 -23994 -23995 -23996 -23997 -23998 -23999 -24000 -24001 -24002 -24003 -24004 -24005 -24006 -24007 -24008 -24009 -24010 -24011 -24012 -24013 -24014 -24015 -24016 -24017 -24018 -24019 -24020 -24021 -24022 -24023 -24024 -24025 -24026 -24027 -24028 -24029 -24030 -24031 -24032 -24033 -24034 -24035 -24036 -24037 -24038 -24039 -24040 -24041 -24042 -24043 -24044 -24045 -24046 -24047 -24048 -24049 -24050 -24051 -24052 -24053 -24054 -24055 -24056 -24057 -24058 -24059 -24060 -24061 -24062 -24063 -24064 -24065 -24066 -24067 -24068 -24069 -24070 -24071 -24072 -24073 -24074 -24075 -24076 -24077 -24078 -24079 -24080 -24081 -24082 -24083 -24084 -24085 -24086 -24087 -24088 -24089 -24090 -24091 -24092 -24093 -24094 -24095 -24096 -24097 -24098 -24099 -24100 -24101 -24102 -24103 -24104 -24105 -24106 -24107 -24108 -24109 -24110 -24111 -24112 -24113 -24114 -24115 -24116 -24117 -24118 -24119 -24120 -24121 -24122 -24123 -24124 -24125 -24126 -24127 -24128 -24129 -24130 -24131 -24132 -24133 -24134 -24135 -24136 -24137 -24138 -24139 -24140 -24141 -24142 -24143 -24144 -24145 -24146 -24147 -24148 -24149 -24150 -24151 -24152 -24153 -24154 -24155 -24156 -24157 -24158 -24159 -24160 -24161 -24162 -24163 -24164 -24165 -24166 -24167 -24168 -24169 -24170 -24171 -24172 -24173 -24174 -24175 -24176 -24177 -24178 -24179 -24180 -24181 -24182 -24183 -24184 -24185 -24186 -24187 -24188 -24189 -24190 -24191 -24192 -24193 -24194 -24195 -24196 -24197 -24198 -24199 -24200 -24201 -24202 -24203 -24204 -24205 -24206 -24207 -24208 -24209 -24210 -24211 -24212 -24213 -24214 -24215 -24216 -24217 -24218 -24219 -24220 -24221 -24222 -24223 -24224 -24225 -24226 -24227 -24228 -24229 -24230 -24231 -24232 -24233 -24234 -24235 -24236 -24237 -24238 -24239 -24240 -24241 -24242 -24243 -24244 -24245 -24246 -24247 -24248 -24249 -24250 -24251 -24252 -24253 -24254 -24255 -24256 -24257 -24258 -24259 -24260 -24261 -24262 -24263 -24264 -24265 -24266 -24267 -24268 -24269 -24270 -24271 -24272 -24273 -24274 -24275 -24276 -24277 -24278 -24279 -24280 -24281 -24282 -24283 -24284 -24285 -24286 -24287 -24288 -24289 -24290 -24291 -24292 -24293 -24294 -24295 -24296 -24297 -24298 -24299 -24300 -24301 -24302 -24303 -24304 -24305 -24306 -24307 -24308 -24309 -24310 -24311 -24312 -24313 -24314 -24315 -24316 -24317 -24318 -24319 -24320 -24321 -24322 -24323 -24324 -24325 -24326 -24327 -24328 -24329 -24330 -24331 -24332 -24333 -24334 -24335 -24336 -24337 -24338 -24339 -24340 -24341 -24342 -24343 -24344 -24345 -24346 -24347 -24348 -24349 -24350 -24351 -24352 -24353 -24354 -24355 -24356 -24357 -24358 -24359 -24360 -24361 -24362 -24363 -24364 -24365 -24366 -24367 -24368 -24369 -24370 -24371 -24372 -24373 -24374 -24375 -24376 -24377 -24378 -24379 -24380 -24381 -24382 -24383 -24384 -24385 -24386 -24387 -24388 -24389 -24390 -24391 -24392 -24393 -24394 -24395 -24396 -24397 -24398 -24399 -24400 -24401 -24402 -24403 -24404 -24405 -24406 -24407 -24408 -24409 -24410 -24411 -24412 -24413 -24414 -24415 -24416 -24417 -24418 -24419 -24420 -24421 -24422 -24423 -24424 -24425 -24426 -24427 -24428 -24429 -24430 -24431 -24432 -24433 -24434 -24435 -24436 -24437 -24438 -24439 -24440 -24441 -24442 -24443 -24444 -24445 -24446 -24447 -24448 -24449 -24450 -24451 -24452 -24453 -24454 -24455 -24456 -24457 -24458 -24459 -24460 -24461 -24462 -24463 -24464 -24465 -24466 -24467 -24468 -24469 -24470 -24471 -24472 -24473 -24474 -24475 -24476 -24477 -24478 -24479 -24480 -24481 -24482 -24483 -24484 -24485 -24486 -24487 -24488 -24489 -24490 -24491 -24492 -24493 -24494 -24495 -24496 -24497 -24498 -24499 -24500 -24501 -24502 -24503 -24504 -24505 -24506 -24507 -24508 -24509 -24510 -24511 -24512 -24513 -24514 -24515 -24516 -24517 -24518 -24519 -24520 -24521 -24522 -24523 -24524 -24525 -24526 -24527 -24528 -24529 -24530 -24531 -24532 -24533 -24534 -24535 -24536 -24537 -24538 -24539 -24540 -24541 -24542 -24543 -24544 -24545 -24546 -24547 -24548 -24549 -24550 -24551 -24552 -24553 -24554 -24555 -24556 -24557 -24558 -24559 -24560 -24561 -24562 -24563 -24564 -24565 -24566 -24567 -24568 -24569 -24570 -24571 -24572 -24573 -24574 -24575 -24576 -24577 -24578 -24579 -24580 -24581 -24582 -24583 -24584 -24585 -24586 -24587 -24588 -24589 -24590 -24591 -24592 -24593 -24594 -24595 -24596 -24597 -24598 -24599 -24600 -24601 -24602 -24603 -24604 -24605 -24606 -24607 -24608 -24609 -24610 -24611 -24612 -24613 -24614 -24615 -24616 -24617 -24618 -24619 -24620 -24621 -24622 -24623 -24624 -24625 -24626 -24627 -24628 -24629 -24630 -24631 -24632 -24633 -24634 -24635 -24636 -24637 -24638 -24639 -24640 -24641 -24642 -24643 -24644 -24645 -24646 -24647 -24648 -24649 -24650 -24651 -24652 -24653 -24654 -24655 -24656 -24657 -24658 -24659 -24660 -24661 -24662 -24663 -24664 -24665 -24666 -24667 -24668 -24669 -24670 -24671 -24672 -24673 -24674 -24675 -24676 -24677 -24678 -24679 -24680 -24681 -24682 -24683 -24684 -24685 -24686 -24687 -24688 -24689 -24690 -24691 -24692 -24693 -24694 -24695 -24696 -24697 -24698 -24699 -24700 -24701 -24702 -24703 -24704 -24705 -24706 -24707 -24708 -24709 -24710 -24711 -24712 -24713 -24714 -24715 -24716 -24717 -24718 -24719 -24720 -24721 -24722 -24723 -24724 -24725 -24726 -24727 -24728 -24729 -24730 -24731 -24732 -24733 -24734 -24735 -24736 -24737 -24738 -24739 -24740 -24741 -24742 -24743 -24744 -24745 -24746 -24747 -24748 -24749 -24750 -24751 -24752 -24753 -24754 -24755 -24756 -24757 -24758 -24759 -24760 -24761 -24762 -24763 -24764 -24765 -24766 -24767 -24768 -24769 -24770 -24771 -24772 -24773 -24774 -24775 -24776 -24777 -24778 -24779 -24780 -24781 -24782 -24783 -24784 -24785 -24786 -24787 -24788 -24789 -24790 -24791 -24792 -24793 -24794 -24795 -24796 -24797 -24798 -24799 -24800 -24801 -24802 -24803 -24804 -24805 -24806 -24807 -24808 -24809 -24810 -24811 -24812 -24813 -24814 -24815 -24816 -24817 -24818 -24819 -24820 -24821 -24822 -24823 -24824 -24825 -24826 -24827 -24828 -24829 -24830 -24831 -24832 -24833 -24834 -24835 -24836 -24837 -24838 -24839 -24840 -24841 -24842 -24843 -24844 -24845 -24846 -24847 -24848 -24849 -24850 -24851 -24852 -24853 -24854 -24855 -24856 -24857 -24858 -24859 -24860 -24861 -24862 -24863 -24864 -24865 -24866 -24867 -24868 -24869 -24870 -24871 -24872 -24873 -24874 -24875 -24876 -24877 -24878 -24879 -24880 -24881 -24882 -24883 -24884 -24885 -24886 -24887 -24888 -24889 -24890 -24891 -24892 -24893 -24894 -24895 -24896 -24897 -24898 -24899 -24900 -24901 -24902 -24903 -24904 -24905 -24906 -24907 -24908 -24909 -24910 -24911 -24912 -24913 -24914 -24915 -24916 -24917 -24918 -24919 -24920 -24921 -24922 -24923 -24924 -24925 -24926 -24927 -24928 -24929 -24930 -24931 -24932 -24933 -24934 -24935 -24936 -24937 -24938 -24939 -24940 -24941 -24942 -24943 -24944 -24945 -24946 -24947 -24948 -24949 -24950 -24951 -24952 -24953 -24954 -24955 -24956 -24957 -24958 -24959 -24960 -24961 -24962 -24963 -24964 -24965 -24966 -24967 -24968 -24969 -24970 -24971 -24972 -24973 -24974 -24975 -24976 -24977 -24978 -24979 -24980 -24981 -24982 -24983 -24984 -24985 -24986 -24987 -24988 -24989 -24990 -24991 -24992 -24993 -24994 -24995 -24996 -24997 -24998 -24999 -25000 -25001 -25002 -25003 -25004 -25005 -25006 -25007 -25008 -25009 -25010 -25011 -25012 -25013 -25014 -25015 -25016 -25017 -25018 -25019 -25020 -25021 -25022 -25023 -25024 -25025 -25026 -25027 -25028 -25029 -25030 -25031 -25032 -25033 -25034 -25035 -25036 -25037 -25038 -25039 -25040 -25041 -25042 -25043 -25044 -25045 -25046 -25047 -25048 -25049 -25050 -25051 -25052 -25053 -25054 -25055 -25056 -25057 -25058 -25059 -25060 -25061 -25062 -25063 -25064 -25065 -25066 -25067 -25068 -25069 -25070 -25071 -25072 -25073 -25074 -25075 -25076 -25077 -25078 -25079 -25080 -25081 -25082 -25083 -25084 -25085 -25086 -25087 -25088 -25089 -25090 -25091 -25092 -25093 -25094 -25095 -25096 -25097 -25098 -25099 -25100 -25101 -25102 -25103 -25104 -25105 -25106 -25107 -25108 -25109 -25110 -25111 -25112 -25113 -25114 -25115 -25116 -25117 -25118 -25119 -25120 -25121 -25122 -25123 -25124 -25125 -25126 -25127 -25128 -25129 -25130 -25131 -25132 -25133 -25134 -25135 -25136 -25137 -25138 -25139 -25140 -25141 -25142 -25143 -25144 -25145 -25146 -25147 -25148 -25149 -25150 -25151 -25152 -25153 -25154 -25155 -25156 -25157 -25158 -25159 -25160 -25161 -25162 -25163 -25164 -25165 -25166 -25167 -25168 -25169 -25170 -25171 -25172 -25173 -25174 -25175 -25176 -25177 -25178 -25179 -25180 -25181 -25182 -25183 -25184 -25185 -25186 -25187 -25188 -25189 -25190 -25191 -25192 -25193 -25194 -25195 -25196 -25197 -25198 -25199 -25200 -25201 -25202 -25203 -25204 -25205 -25206 -25207 -25208 -25209 -25210 -25211 -25212 -25213 -25214 -25215 -25216 -25217 -25218 -25219 -25220 -25221 -25222 -25223 -25224 -25225 -25226 -25227 -25228 -25229 -25230 -25231 -25232 -25233 -25234 -25235 -25236 -25237 -25238 -25239 -25240 -25241 -25242 -25243 -25244 -25245 -25246 -25247 -25248 -25249 -25250 -25251 -25252 -25253 -25254 -25255 -25256 -25257 -25258 -25259 -25260 -25261 -25262 -25263 -25264 -25265 -25266 -25267 -25268 -25269 -25270 -25271 -25272 -25273 -25274 -25275 -25276 -25277 -25278 -25279 -25280 -25281 -25282 -25283 -25284 -25285 -25286 -25287 -25288 -25289 -25290 -25291 -25292 -25293 -25294 -25295 -25296 -25297 -25298 -25299 -25300 -25301 -25302 -25303 -25304 -25305 -25306 -25307 -25308 -25309 -25310 -25311 -25312 -25313 -25314 -25315 -25316 -25317 -25318 -25319 -25320 -25321 -25322 -25323 -25324 -25325 -25326 -25327 -25328 -25329 -25330 -25331 -25332 -25333 -25334 -25335 -25336 -25337 -25338 -25339 -25340 -25341 -25342 -25343 -25344 -25345 -25346 -25347 -25348 -25349 -25350 -25351 -25352 -25353 -25354 -25355 -25356 -25357 -25358 -25359 -25360 -25361 -25362 -25363 -25364 -25365 -25366 -25367 -25368 -25369 -25370 -25371 -25372 -25373 -25374 -25375 -25376 -25377 -25378 -25379 -25380 -25381 -25382 -25383 -25384 -25385 -25386 -25387 -25388 -25389 -25390 -25391 -25392 -25393 -25394 -25395 -25396 -25397 -25398 -25399 -25400 -25401 -25402 -25403 -25404 -25405 -25406 -25407 -25408 -25409 -25410 -25411 -25412 -25413 -25414 -25415 -25416 -25417 -25418 -25419 -25420 -25421 -25422 -25423 -25424 -25425 -25426 -25427 -25428 -25429 -25430 -25431 -25432 -25433 -25434 -25435 -25436 -25437 -25438 -25439 -25440 -25441 -25442 -25443 -25444 -25445 -25446 -25447 -25448 -25449 -25450 -25451 -25452 -25453 -25454 -25455 -25456 -25457 -25458 -25459 -25460 -25461 -25462 -25463 -25464 -25465 -25466 -25467 -25468 -25469 -25470 -25471 -25472 -25473 -25474 -25475 -25476 -25477 -25478 -25479 -25480 -25481 -25482 -25483 -25484 -25485 -25486 -25487 -25488 -25489 -25490 -25491 -25492 -25493 -25494 -25495 -25496 -25497 -25498 -25499 -25500 -25501 -25502 -25503 -25504 -25505 -25506 -25507 -25508 -25509 -25510 -25511 -25512 -25513 -25514 -25515 -25516 -25517 -25518 -25519 -25520 -25521 -25522 -25523 -25524 -25525 -25526 -25527 -25528 -25529 -25530 -25531 -25532 -25533 -25534 -25535 -25536 -25537 -25538 -25539 -25540 -25541 -25542 -25543 -25544 -25545 -25546 -25547 -25548 -25549 -25550 -25551 -25552 -25553 -25554 -25555 -25556 -25557 -25558 -25559 -25560 -25561 -25562 -25563 -25564 -25565 -25566 -25567 -25568 -25569 -25570 -25571 -25572 -25573 -25574 -25575 -25576 -25577 -25578 -25579 -25580 -25581 -25582 -25583 -25584 -25585 -25586 -25587 -25588 -25589 -25590 -25591 -25592 -25593 -25594 -25595 -25596 -25597 -25598 -25599 -25600 -25601 -25602 -25603 -25604 -25605 -25606 -25607 -25608 -25609 -25610 -25611 -25612 -25613 -25614 -25615 -25616 -25617 -25618 -25619 -25620 -25621 -25622 -25623 -25624 -25625 -25626 -25627 -25628 -25629 -25630 -25631 -25632 -25633 -25634 -25635 -25636 -25637 -25638 -25639 -25640 -25641 -25642 -25643 -25644 -25645 -25646 -25647 -25648 -25649 -25650 -25651 -25652 -25653 -25654 -25655 -25656 -25657 -25658 -25659 -25660 -25661 -25662 -25663 -25664 -25665 -25666 -25667 -25668 -25669 -25670 -25671 -25672 -25673 -25674 -25675 -25676 -25677 -25678 -25679 -25680 -25681 -25682 -25683 -25684 -25685 -25686 -25687 -25688 -25689 -25690 -25691 -25692 -25693 -25694 -25695 -25696 -25697 -25698 -25699 -25700 -25701 -25702 -25703 -25704 -25705 -25706 -25707 -25708 -25709 -25710 -25711 -25712 -25713 -25714 -25715 -25716 -25717 -25718 -25719 -25720 -25721 -25722 -25723 -25724 -25725 -25726 -25727 -25728 -25729 -25730 -25731 -25732 -25733 -25734 -25735 -25736 -25737 -25738 -25739 -25740 -25741 -25742 -25743 -25744 -25745 -25746 -25747 -25748 -25749 -25750 -25751 -25752 -25753 -25754 -25755 -25756 -25757 -25758 -25759 -25760 -25761 -25762 -25763 -25764 -25765 -25766 -25767 -25768 -25769 -25770 -25771 -25772 -25773 -25774 -25775 -25776 -25777 -25778 -25779 -25780 -25781 -25782 -25783 -25784 -25785 -25786 -25787 -25788 -25789 -25790 -25791 -25792 -25793 -25794 -25795 -25796 -25797 -25798 -25799 -25800 -25801 -25802 -25803 -25804 -25805 -25806 -25807 -25808 -25809 -25810 -25811 -25812 -25813 -25814 -25815 -25816 -25817 -25818 -25819 -25820 -25821 -25822 -25823 -25824 -25825 -25826 -25827 -25828 -25829 -25830 -25831 -25832 -25833 -25834 -25835 -25836 -25837 -25838 -25839 -25840 -25841 -25842 -25843 -25844 -25845 -25846 -25847 -25848 -25849 -25850 -25851 -25852 -25853 -25854 -25855 -25856 -25857 -25858 -25859 -25860 -25861 -25862 -25863 -25864 -25865 -25866 -25867 -25868 -25869 -25870 -25871 -25872 -25873 -25874 -25875 -25876 -25877 -25878 -25879 -25880 -25881 -25882 -25883 -25884 -25885 -25886 -25887 -25888 -25889 -25890 -25891 -25892 -25893 -25894 -25895 -25896 -25897 -25898 -25899 -25900 -25901 -25902 -25903 -25904 -25905 -25906 -25907 -25908 -25909 -25910 -25911 -25912 -25913 -25914 -25915 -25916 -25917 -25918 -25919 -25920 -25921 -25922 -25923 -25924 -25925 -25926 -25927 -25928 -25929 -25930 -25931 -25932 -25933 -25934 -25935 -25936 -25937 -25938 -25939 -25940 -25941 -25942 -25943 -25944 -25945 -25946 -25947 -25948 -25949 -25950 -25951 -25952 -25953 -25954 -25955 -25956 -25957 -25958 -25959 -25960 -25961 -25962 -25963 -25964 -25965 -25966 -25967 -25968 -25969 -25970 -25971 -25972 -25973 -25974 -25975 -25976 -25977 -25978 -25979 -25980 -25981 -25982 -25983 -25984 -25985 -25986 -25987 -25988 -25989 -25990 -25991 -25992 -25993 -25994 -25995 -25996 -25997 -25998 -25999 -26000 -26001 -26002 -26003 -26004 -26005 -26006 -26007 -26008 -26009 -26010 -26011 -26012 -26013 -26014 -26015 -26016 -26017 -26018 -26019 -26020 -26021 -26022 -26023 -26024 -26025 -26026 -26027 -26028 -26029 -26030 -26031 -26032 -26033 -26034 -26035 -26036 -26037 -26038 -26039 -26040 -26041 -26042 -26043 -26044 -26045 -26046 -26047 -26048 -26049 -26050 -26051 -26052 -26053 -26054 -26055 -26056 -26057 -26058 -26059 -26060 -26061 -26062 -26063 -26064 -26065 -26066 -26067 -26068 -26069 -26070 -26071 -26072 -26073 -26074 -26075 -26076 -26077 -26078 -26079 -26080 -26081 -26082 -26083 -26084 -26085 -26086 -26087 -26088 -26089 -26090 -26091 -26092 -26093 -26094 -26095 -26096 -26097 -26098 -26099 -26100 -26101 -26102 -26103 -26104 -26105 -26106 -26107 -26108 -26109 -26110 -26111 -26112 -26113 -26114 -26115 -26116 -26117 -26118 -26119 -26120 -26121 -26122 -26123 -26124 -26125 -26126 -26127 -26128 -26129 -26130 -26131 -26132 -26133 -26134 -26135 -26136 -26137 -26138 -26139 -26140 -26141 -26142 -26143 -26144 -26145 -26146 -26147 -26148 -26149 -26150 -26151 -26152 -26153 -26154 -26155 -26156 -26157 -26158 -26159 -26160 -26161 -26162 -26163 -26164 -26165 -26166 -26167 -26168 -26169 -26170 -26171 -26172 -26173 -26174 -26175 -26176 -26177 -26178 -26179 -26180 -26181 -26182 -26183 -26184 -26185 -26186 -26187 -26188 -26189 -26190 -26191 -26192 -26193 -26194 -26195 -26196 -26197 -26198 -26199 -26200 -26201 -26202 -26203 -26204 -26205 -26206 -26207 -26208 -26209 -26210 -26211 -26212 -26213 -26214 -26215 -26216 -26217 -26218 -26219 -26220 -26221 -26222 -26223 -26224 -26225 -26226 -26227 -26228 -26229 -26230 -26231 -26232 -26233 -26234 -26235 -26236 -26237 -26238 -26239 -26240 -26241 -26242 -26243 -26244 -26245 -26246 -26247 -26248 -26249 -26250 -26251 -26252 -26253 -26254 -26255 -26256 -26257 -26258 -26259 -26260 -26261 -26262 -26263 -26264 -26265 -26266 -26267 -26268 -26269 -26270 -26271 -26272 -26273 -26274 -26275 -26276 -26277 -26278 -26279 -26280 -26281 -26282 -26283 -26284 -26285 -26286 -26287 -26288 -26289 -26290 -26291 -26292 -26293 -26294 -26295 -26296 -26297 -26298 -26299 -26300 -26301 -26302 -26303 -26304 -26305 -26306 -26307 -26308 -26309 -26310 -26311 -26312 -26313 -26314 -26315 -26316 -26317 -26318 -26319 -26320 -26321 -26322 -26323 -26324 -26325 -26326 -26327 -26328 -26329 -26330 -26331 -26332 -26333 -26334 -26335 -26336 -26337 -26338 -26339 -26340 -26341 -26342 -26343 -26344 -26345 -26346 -26347 -26348 -26349 -26350 -26351 -26352 -26353 -26354 -26355 -26356 -26357 -26358 -26359 -26360 -26361 -26362 -26363 -26364 -26365 -26366 -26367 -26368 -26369 -26370 -26371 -26372 -26373 -26374 -26375 -26376 -26377 -26378 -26379 -26380 -26381 -26382 -26383 -26384 -26385 -26386 -26387 -26388 -26389 -26390 -26391 -26392 -26393 -26394 -26395 -26396 -26397 -26398 -26399 -26400 -26401 -26402 -26403 -26404 -26405 -26406 -26407 -26408 -26409 -26410 -26411 -26412 -26413 -26414 -26415 -26416 -26417 -26418 -26419 -26420 -26421 -26422 -26423 -26424 -26425 -26426 -26427 -26428 -26429 -26430 -26431 -26432 -26433 -26434 -26435 -26436 -26437 -26438 -26439 -26440 -26441 -26442 -26443 -26444 -26445 -26446 -26447 -26448 -26449 -26450 -26451 -26452 -26453 -26454 -26455 -26456 -26457 -26458 -26459 -26460 -26461 -26462 -26463 -26464 -26465 -26466 -26467 -26468 -26469 -26470 -26471 -26472 -26473 -26474 -26475 -26476 -26477 -26478 -26479 -26480 -26481 -26482 -26483 -26484 -26485 -26486 -26487 -26488 -26489 -26490 -26491 -26492 -26493 -26494 -26495 -26496 -26497 -26498 -26499 -26500 -26501 -26502 -26503 -26504 -26505 -26506 -26507 -26508 -26509 -26510 -26511 -26512 -26513 -26514 -26515 -26516 -26517 -26518 -26519 -26520 -26521 -26522 -26523 -26524 -26525 -26526 -26527 -26528 -26529 -26530 -26531 -26532 -26533 -26534 -26535 -26536 -26537 -26538 -26539 -26540 -26541 -26542 -26543 -26544 -26545 -26546 -26547 -26548 -26549 -26550 -26551 -26552 -26553 -26554 -26555 -26556 -26557 -26558 -26559 -26560 -26561 -26562 -26563 -26564 -26565 -26566 -26567 -26568 -26569 -26570 -26571 -26572 -26573 -26574 -26575 -26576 -26577 -26578 -26579 -26580 -26581 -26582 -26583 -26584 -26585 -26586 -26587 -26588 -26589 -26590 -26591 -26592 -26593 -26594 -26595 -26596 -26597 -26598 -26599 -26600 -26601 -26602 -26603 -26604 -26605 -26606 -26607 -26608 -26609 -26610 -26611 -26612 -26613 -26614 -26615 -26616 -26617 -26618 -26619 -26620 -26621 -26622 -26623 -26624 -26625 -26626 -26627 -26628 -26629 -26630 -26631 -26632 -26633 -26634 -26635 -26636 -26637 -26638 -26639 -26640 -26641 -26642 -26643 -26644 -26645 -26646 -26647 -26648 -26649 -26650 -26651 -26652 -26653 -26654 -26655 -26656 -26657 -26658 -26659 -26660 -26661 -26662 -26663 -26664 -26665 -26666 -26667 -26668 -26669 -26670 -26671 -26672 -26673 -26674 -26675 -26676 -26677 -26678 -26679 -26680 -26681 -26682 -26683 -26684 -26685 -26686 -26687 -26688 -26689 -26690 -26691 -26692 -26693 -26694 -26695 -26696 -26697 -26698 -26699 -26700 -26701 -26702 -26703 -26704 -26705 -26706 -26707 -26708 -26709 -26710 -26711 -26712 -26713 -26714 -26715 -26716 -26717 -26718 -26719 -26720 -26721 -26722 -26723 -26724 -26725 -26726 -26727 -26728 -26729 -26730 -26731 -26732 -26733 -26734 -26735 -26736 -26737 -26738 -26739 -26740 -26741 -26742 -26743 -26744 -26745 -26746 -26747 -26748 -26749 -26750 -26751 -26752 -26753 -26754 -26755 -26756 -26757 -26758 -26759 -26760 -26761 -26762 -26763 -26764 -26765 -26766 -26767 -26768 -26769 -26770 -26771 -26772 -26773 -26774 -26775 -26776 -26777 -26778 -26779 -26780 -26781 -26782 -26783 -26784 -26785 -26786 -26787 -26788 -26789 -26790 -26791 -26792 -26793 -26794 -26795 -26796 -26797 -26798 -26799 -26800 -26801 -26802 -26803 -26804 -26805 -26806 -26807 -26808 -26809 -26810 -26811 -26812 -26813 -26814 -26815 -26816 -26817 -26818 -26819 -26820 -26821 -26822 -26823 -26824 -26825 -26826 -26827 -26828 -26829 -26830 -26831 -26832 -26833 -26834 -26835 -26836 -26837 -26838 -26839 -26840 -26841 -26842 -26843 -26844 -26845 -26846 -26847 -26848 -26849 -26850 -26851 -26852 -26853 -26854 -26855 -26856 -26857 -26858 -26859 -26860 -26861 -26862 -26863 -26864 -26865 -26866 -26867 -26868 -26869 -26870 -26871 -26872 -26873 -26874 -26875 -26876 -26877 -26878 -26879 -26880 -26881 -26882 -26883 -26884 -26885 -26886 -26887 -26888 -26889 -26890 -26891 -26892 -26893 -26894 -26895 -26896 -26897 -26898 -26899 -26900 -26901 -26902 -26903 -26904 -26905 -26906 -26907 -26908 -26909 -26910 -26911 -26912 -26913 -26914 -26915 -26916 -26917 -26918 -26919 -26920 -26921 -26922 -26923 -26924 -26925 -26926 -26927 -26928 -26929 -26930 -26931 -26932 -26933 -26934 -26935 -26936 -26937 -26938 -26939 -26940 -26941 -26942 -26943 -26944 -26945 -26946 -26947 -26948 -26949 -26950 -26951 -26952 -26953 -26954 -26955 -26956 -26957 -26958 -26959 -26960 -26961 -26962 -26963 -26964 -26965 -26966 -26967 -26968 -26969 -26970 -26971 -26972 -26973 -26974 -26975 -26976 -26977 -26978 -26979 -26980 -26981 -26982 -26983 -26984 -26985 -26986 -26987 -26988 -26989 -26990 -26991 -26992 -26993 -26994 -26995 -26996 -26997 -26998 -26999 -27000 -27001 -27002 -27003 -27004 -27005 -27006 -27007 -27008 -27009 -27010 -27011 -27012 -27013 -27014 -27015 -27016 -27017 -27018 -27019 -27020 -27021 -27022 -27023 -27024 -27025 -27026 -27027 -27028 -27029 -27030 -27031 -27032 -27033 -27034 -27035 -27036 -27037 -27038 -27039 -27040 -27041 -27042 -27043 -27044 -27045 -27046 -27047 -27048 -27049 -27050 -27051 -27052 -27053 -27054 -27055 -27056 -27057 -27058 -27059 -27060 -27061 -27062 -27063 -27064 -27065 -27066 -27067 -27068 -27069 -27070 -27071 -27072 -27073 -27074 -27075 -27076 -27077 -27078 -27079 -27080 -27081 -27082 -27083 -27084 -27085 -27086 -27087 -27088 -27089 -27090 -27091 -27092 -27093 -27094 -27095 -27096 -27097 -27098 -27099 -27100 -27101 -27102 -27103 -27104 -27105 -27106 -27107 -27108 -27109 -27110 -27111 -27112 -27113 -27114 -27115 -27116 -27117 -27118 -27119 -27120 -27121 -27122 -27123 -27124 -27125 -27126 -27127 -27128 -27129 -27130 -27131 -27132 -27133 -27134 -27135 -27136 -27137 -27138 -27139 -27140 -27141 -27142 -27143 -27144 -27145 -27146 -27147 -27148 -27149 -27150 -27151 -27152 -27153 -27154 -27155 -27156 -27157 -27158 -27159 -27160 -27161 -27162 -27163 -27164 -27165 -27166 -27167 -27168 -27169 -27170 -27171 -27172 -27173 -27174 -27175 -27176 -27177 -27178 -27179 -27180 -27181 -27182 -27183 -27184 -27185 -27186 -27187 -27188 -27189 -27190 -27191 -27192 -27193 -27194 -27195 -27196 -27197 -27198 -27199 -27200 -27201 -27202 -27203 -27204 -27205 -27206 -27207 -27208 -27209 -27210 -27211 -27212 -27213 -27214 -27215 -27216 -27217 -27218 -27219 -27220 -27221 -27222 -27223 -27224 -27225 -27226 -27227 -27228 -27229 -27230 -27231 -27232 -27233 -27234 -27235 -27236 -27237 -27238 -27239 -27240 -27241 -27242 -27243 -27244 -27245 -27246 -27247 -27248 -27249 -27250 -27251 -27252 -27253 -27254 -27255 -27256 -27257 -27258 -27259 -27260 -27261 -27262 -27263 -27264 -27265 -27266 -27267 -27268 -27269 -27270 -27271 -27272 -27273 -27274 -27275 -27276 -27277 -27278 -27279 -27280 -27281 -27282 -27283 -27284 -27285 -27286 -27287 -27288 -27289 -27290 -27291 -27292 -27293 -27294 -27295 -27296 -27297 -27298 -27299 -27300 -27301 -27302 -27303 -27304 -27305 -27306 -27307 -27308 -27309 -27310 -27311 -27312 -27313 -27314 -27315 -27316 -27317 -27318 -27319 -27320 -27321 -27322 -27323 -27324 -27325 -27326 -27327 -27328 -27329 -27330 -27331 -27332 -27333 -27334 -27335 -27336 -27337 -27338 -27339 -27340 -27341 -27342 -27343 -27344 -27345 -27346 -27347 -27348 -27349 -27350 -27351 -27352 -27353 -27354 -27355 -27356 -27357 -27358 -27359 -27360 -27361 -27362 -27363 -27364 -27365 -27366 -27367 -27368 -27369 -27370 -27371 -27372 -27373 -27374 -27375 -27376 -27377 -27378 -27379 -27380 -27381 -27382 -27383 -27384 -27385 -27386 -27387 -27388 -27389 -27390 -27391 -27392 -27393 -27394 -27395 -27396 -27397 -27398 -27399 -27400 -27401 -27402 -27403 -27404 -27405 -27406 -27407 -27408 -27409 -27410 -27411 -27412 -27413 -27414 -27415 -27416 -27417 -27418 -27419 -27420 -27421 -27422 -27423 -27424 -27425 -27426 -27427 -27428 -27429 -27430 -27431 -27432 -27433 -27434 -27435 -27436 -27437 -27438 -27439 -27440 -27441 -27442 -27443 -27444 -27445 -27446 -27447 -27448 -27449 -27450 -27451 -27452 -27453 -27454 -27455 -27456 -27457 -27458 -27459 -27460 -27461 -27462 -27463 -27464 -27465 -27466 -27467 -27468 -27469 -27470 -27471 -27472 -27473 -27474 -27475 -27476 -27477 -27478 -27479 -27480 -27481 -27482 -27483 -27484 -27485 -27486 -27487 -27488 -27489 -27490 -27491 -27492 -27493 -27494 -27495 -27496 -27497 -27498 -27499 -27500 -27501 -27502 -27503 -27504 -27505 -27506 -27507 -27508 -27509 -27510 -27511 -27512 -27513 -27514 -27515 -27516 -27517 -27518 -27519 -27520 -27521 -27522 -27523 -27524 -27525 -27526 -27527 -27528 -27529 -27530 -27531 -27532 -27533 -27534 -27535 -27536 -27537 -27538 -27539 -27540 -27541 -27542 -27543 -27544 -27545 -27546 -27547 -27548 -27549 -27550 -27551 -27552 -27553 -27554 -27555 -27556 -27557 -27558 -27559 -27560 -27561 -27562 -27563 -27564 -27565 -27566 -27567 -27568 -27569 -27570 -27571 -27572 -27573 -27574 -27575 -27576 -27577 -27578 -27579 -27580 -27581 -27582 -27583 -27584 -27585 -27586 -27587 -27588 -27589 -27590 -27591 -27592 -27593 -27594 -27595 -27596 -27597 -27598 -27599 -27600 -27601 -27602 -27603 -27604 -27605 -27606 -27607 -27608 -27609 -27610 -27611 -27612 -27613 -27614 -27615 -27616 -27617 -27618 -27619 -27620 -27621 -27622 -27623 -27624 -27625 -27626 -27627 -27628 -27629 -27630 -27631 -27632 -27633 -27634 -27635 -27636 -27637 -27638 -27639 -27640 -27641 -27642 -27643 -27644 -27645 -27646 -27647 -27648 -27649 -27650 -27651 -27652 -27653 -27654 -27655 -27656 -27657 -27658 -27659 -27660 -27661 -27662 -27663 -27664 -27665 -27666 -27667 -27668 -27669 -27670 -27671 -27672 -27673 -27674 -27675 -27676 -27677 -27678 -27679 -27680 -27681 -27682 -27683 -27684 -27685 -27686 -27687 -27688 -27689 -27690 -27691 -27692 -27693 -27694 -27695 -27696 -27697 -27698 -27699 -27700 -27701 -27702 -27703 -27704 -27705 -27706 -27707 -27708 -27709 -27710 -27711 -27712 -27713 -27714 -27715 -27716 -27717 -27718 -27719 -27720 -27721 -27722 -27723 -27724 -27725 -27726 -27727 -27728 -27729 -27730 -27731 -27732 -27733 -27734 -27735 -27736 -27737 -27738 -27739 -27740 -27741 -27742 -27743 -27744 -27745 -27746 -27747 -27748 -27749 -27750 -27751 -27752 -27753 -27754 -27755 -27756 -27757 -27758 -27759 -27760 -27761 -27762 -27763 -27764 -27765 -27766 -27767 -27768 -27769 -27770 -27771 -27772 -27773 -27774 -27775 -27776 -27777 -27778 -27779 -27780 -27781 -27782 -27783 -27784 -27785 -27786 -27787 -27788 -27789 -27790 -27791 -27792 -27793 -27794 -27795 -27796 -27797 -27798 -27799 -27800 -27801 -27802 -27803 -27804 -27805 -27806 -27807 -27808 -27809 -27810 -27811 -27812 -27813 -27814 -27815 -27816 -27817 -27818 -27819 -27820 -27821 -27822 -27823 -27824 -27825 -27826 -27827 -27828 -27829 -27830 -27831 -27832 -27833 -27834 -27835 -27836 -27837 -27838 -27839 -27840 -27841 -27842 -27843 -27844 -27845 -27846 -27847 -27848 -27849 -27850 -27851 -27852 -27853 -27854 -27855 -27856 -27857 -27858 -27859 -27860 -27861 -27862 -27863 -27864 -27865 -27866 -27867 -27868 -27869 -27870 -27871 -27872 -27873 -27874 -27875 -27876 -27877 -27878 -27879 -27880 -27881 -27882 -27883 -27884 -27885 -27886 -27887 -27888 -27889 -27890 -27891 -27892 -27893 -27894 -27895 -27896 -27897 -27898 -27899 -27900 -27901 -27902 -27903 -27904 -27905 -27906 -27907 -27908 -27909 -27910 -27911 -27912 -27913 -27914 -27915 -27916 -27917 -27918 -27919 -27920 -27921 -27922 -27923 -27924 -27925 -27926 -27927 -27928 -27929 -27930 -27931 -27932 -27933 -27934 -27935 -27936 -27937 -27938 -27939 -27940 -27941 -27942 -27943 -27944 -27945 -27946 -27947 -27948 -27949 -27950 -27951 -27952 -27953 -27954 -27955 -27956 -27957 -27958 -27959 -27960 -27961 -27962 -27963 -27964 -27965 -27966 -27967 -27968 -27969 -27970 -27971 -27972 -27973 -27974 -27975 -27976 -27977 -27978 -27979 -27980 -27981 -27982 -27983 -27984 -27985 -27986 -27987 -27988 -27989 -27990 -27991 -27992 -27993 -27994 -27995 -27996 -27997 -27998 -27999 -28000 -28001 -28002 -28003 -28004 -28005 -28006 -28007 -28008 -28009 -28010 -28011 -28012 -28013 -28014 -28015 -28016 -28017 -28018 -28019 -28020 -28021 -28022 -28023 -28024 -28025 -28026 -28027 -28028 -28029 -28030 -28031 -28032 -28033 -28034 -28035 -28036 -28037 -28038 -28039 -28040 -28041 -28042 -28043 -28044 -28045 -28046 -28047 -28048 -28049 -28050 -28051 -28052 -28053 -28054 -28055 -28056 -28057 -28058 -28059 -28060 -28061 -28062 -28063 -28064 -28065 -28066 -28067 -28068 -28069 -28070 -28071 -28072 -28073 -28074 -28075 -28076 -28077 -28078 -28079 -28080 -28081 -28082 -28083 -28084 -28085 -28086 -28087 -28088 -28089 -28090 -28091 -28092 -28093 -28094 -28095 -28096 -28097 -28098 -28099 -28100 -28101 -28102 -28103 -28104 -28105 -28106 -28107 -28108 -28109 -28110 -28111 -28112 -28113 -28114 -28115 -28116 -28117 -28118 -28119 -28120 -28121 -28122 -28123 -28124 -28125 -28126 -28127 -28128 -28129 -28130 -28131 -28132 -28133 -28134 -28135 -28136 -28137 -28138 -28139 -28140 -28141 -28142 -28143 -28144 -28145 -28146 -28147 -28148 -28149 -28150 -28151 -28152 -28153 -28154 -28155 -28156 -28157 -28158 -28159 -28160 -28161 -28162 -28163 -28164 -28165 -28166 -28167 -28168 -28169 -28170 -28171 -28172 -28173 -28174 -28175 -28176 -28177 -28178 -28179 -28180 -28181 -28182 -28183 -28184 -28185 -28186 -28187 -28188 -28189 -28190 -28191 -28192 -28193 -28194 -28195 -28196 -28197 -28198 -28199 -28200 -28201 -28202 -28203 -28204 -28205 -28206 -28207 -28208 -28209 -28210 -28211 -28212 -28213 -28214 -28215 -28216 -28217 -28218 -28219 -28220 -28221 -28222 -28223 -28224 -28225 -28226 -28227 -28228 -28229 -28230 -28231 -28232 -28233 -28234 -28235 -28236 -28237 -28238 -28239 -28240 -28241 -28242 -28243 -28244 -28245 -28246 -28247 -28248 -28249 -28250 -28251 -28252 -28253 -28254 -28255 -28256 -28257 -28258 -28259 -28260 -28261 -28262 -28263 -28264 -28265 -28266 -28267 -28268 -28269 -28270 -28271 -28272 -28273 -28274 -28275 -28276 -28277 -28278 -28279 -28280 -28281 -28282 -28283 -28284 -28285 -28286 -28287 -28288 -28289 -28290 -28291 -28292 -28293 -28294 -28295 -28296 -28297 -28298 -28299 -28300 -28301 -28302 -28303 -28304 -28305 -28306 -28307 -28308 -28309 -28310 -28311 -28312 -28313 -28314 -28315 -28316 -28317 -28318 -28319 -28320 -28321 -28322 -28323 -28324 -28325 -28326 -28327 -28328 -28329 -28330 -28331 -28332 -28333 -28334 -28335 -28336 -28337 -28338 -28339 -28340 -28341 -28342 -28343 -28344 -28345 -28346 -28347 -28348 -28349 -28350 -28351 -28352 -28353 -28354 -28355 -28356 -28357 -28358 -28359 -28360 -28361 -28362 -28363 -28364 -28365 -28366 -28367 -28368 -28369 -28370 -28371 -28372 -28373 -28374 -28375 -28376 -28377 -28378 -28379 -28380 -28381 -28382 -28383 -28384 -28385 -28386 -28387 -28388 -28389 -28390 -28391 -28392 -28393 -28394 -28395 -28396 -28397 -28398 -28399 -28400 -28401 -28402 -28403 -28404 -28405 -28406 -28407 -28408 -28409 -28410 -28411 -28412 -28413 -28414 -28415 -28416 -28417 -28418 -28419 -28420 -28421 -28422 -28423 -28424 -28425 -28426 -28427 -28428 -28429 -28430 -28431 -28432 -28433 -28434 -28435 -28436 -28437 -28438 -28439 -28440 -28441 -28442 -28443 -28444 -28445 -28446 -28447 -28448 -28449 -28450 -28451 -28452 -28453 -28454 -28455 -28456 -28457 -28458 -28459 -28460 -28461 -28462 -28463 -28464 -28465 -28466 -28467 -28468 -28469 -28470 -28471 -28472 -28473 -28474 -28475 -28476 -28477 -28478 -28479 -28480 -28481 -28482 -28483 -28484 -28485 -28486 -28487 -28488 -28489 -28490 -28491 -28492 -28493 -28494 -28495 -28496 -28497 -28498 -28499 -28500 -28501 -28502 -28503 -28504 -28505 -28506 -28507 -28508 -28509 -28510 -28511 -28512 -28513 -28514 -28515 -28516 -28517 -28518 -28519 -28520 -28521 -28522 -28523 -28524 -28525 -28526 -28527 -28528 -28529 -28530 -28531 -28532 -28533 -28534 -28535 -28536 -28537 -28538 -28539 -28540 -28541 -28542 -28543 -28544 -28545 -28546 -28547 -28548 -28549 -28550 -28551 -28552 -28553 -28554 -28555 -28556 -28557 -28558 -28559 -28560 -28561 -28562 -28563 -28564 -28565 -28566 -28567 -28568 -28569 -28570 -28571 -28572 -28573 -28574 -28575 -28576 -28577 -28578 -28579 -28580 -28581 -28582 -28583 -28584 -28585 -28586 -28587 -28588 -28589 -28590 -28591 -28592 -28593 -28594 -28595 -28596 -28597 -28598 -28599 -28600 -28601 -28602 -28603 -28604 -28605 -28606 -28607 -28608 -28609 -28610 -28611 -28612 -28613 -28614 -28615 -28616 -28617 -28618 -28619 -28620 -28621 -28622 -28623 -28624 -28625 -28626 -28627 -28628 -28629 -28630 -28631 -28632 -28633 -28634 -28635 -28636 -28637 -28638 -28639 -28640 -28641 -28642 -28643 -28644 -28645 -28646 -28647 -28648 -28649 -28650 -28651 -28652 -28653 -28654 -28655 -28656 -28657 -28658 -28659 -28660 -28661 -28662 -28663 -28664 -28665 -28666 -28667 -28668 -28669 -28670 -28671 -28672 -28673 -28674 -28675 -28676 -28677 -28678 -28679 -28680 -28681 -28682 -28683 -28684 -28685 -28686 -28687 -28688 -28689 -28690 -28691 -28692 -28693 -28694 -28695 -28696 -28697 -28698 -28699 -28700 -28701 -28702 -28703 -28704 -28705 -28706 -28707 -28708 -28709 -28710 -28711 -28712 -28713 -28714 -28715 -28716 -28717 -28718 -28719 -28720 -28721 -28722 -28723 -28724 -28725 -28726 -28727 -28728 -28729 -28730 -28731 -28732 -28733 -28734 -28735 -28736 -28737 -28738 -28739 -28740 -28741 -28742 -28743 -28744 -28745 -28746 -28747 -28748 -28749 -28750 -28751 -28752 -28753 -28754 -28755 -28756 -28757 -28758 -28759 -28760 -28761 -28762 -28763 -28764 -28765 -28766 -28767 -28768 -28769 -28770 -28771 -28772 -28773 -28774 -28775 -28776 -28777 -28778 -28779 -28780 -28781 -28782 -28783 -28784 -28785 -28786 -28787 -28788 -28789 -28790 -28791 -28792 -28793 -28794 -28795 -28796 -28797 -28798 -28799 -28800 -28801 -28802 -28803 -28804 -28805 -28806 -28807 -28808 -28809 -28810 -28811 -28812 -28813 -28814 -28815 -28816 -28817 -28818 -28819 -28820 -28821 -28822 -28823 -28824 -28825 -28826 -28827 -28828 -28829 -28830 -28831 -28832 -28833 -28834 -28835 -28836 -28837 -28838 -28839 -28840 -28841 -28842 -28843 -28844 -28845 -28846 -28847 -28848 -28849 -28850 -28851 -28852 -28853 -28854 -28855 -28856 -28857 -28858 -28859 -28860 -28861 -28862 -28863 -28864 -28865 -28866 -28867 -28868 -28869 -28870 -28871 -28872 -28873 -28874 -28875 -28876 -28877 -28878 -28879 -28880 -28881 -28882 -28883 -28884 -28885 -28886 -28887 -28888 -28889 -28890 -28891 -28892 -28893 -28894 -28895 -28896 -28897 -28898 -28899 -28900 -28901 -28902 -28903 -28904 -28905 -28906 -28907 -28908 -28909 -28910 -28911 -28912 -28913 -28914 -28915 -28916 -28917 -28918 -28919 -28920 -28921 -28922 -28923 -28924 -28925 -28926 -28927 -28928 -28929 -28930 -28931 -28932 -28933 -28934 -28935 -28936 -28937 -28938 -28939 -28940 -28941 -28942 -28943 -28944 -28945 -28946 -28947 -28948 -28949 -28950 -28951 -28952 -28953 -28954 -28955 -28956 -28957 -28958 -28959 -28960 -28961 -28962 -28963 -28964 -28965 -28966 -28967 -28968 -28969 -28970 -28971 -28972 -28973 -28974 -28975 -28976 -28977 -28978 -28979 -28980 -28981 -28982 -28983 -28984 -28985 -28986 -28987 -28988 -28989 -28990 -28991 -28992 -28993 -28994 -28995 -28996 -28997 -28998 -28999 -29000 -29001 -29002 -29003 -29004 -29005 -29006 -29007 -29008 -29009 -29010 -29011 -29012 -29013 -29014 -29015 -29016 -29017 -29018 -29019 -29020 -29021 -29022 -29023 -29024 -29025 -29026 -29027 -29028 -29029 -29030 -29031 -29032 -29033 -29034 -29035 -29036 -29037 -29038 -29039 -29040 -29041 -29042 -29043 -29044 -29045 -29046 -29047 -29048 -29049 -29050 -29051 -29052 -29053 -29054 -29055 -29056 -29057 -29058 -29059 -29060 -29061 -29062 -29063 -29064 -29065 -29066 -29067 -29068 -29069 -29070 -29071 -29072 -29073 -29074 -29075 -29076 -29077 -29078 -29079 -29080 -29081 -29082 -29083 -29084 -29085 -29086 -29087 -29088 -29089 -29090 -29091 -29092 -29093 -29094 -29095 -29096 -29097 -29098 -29099 -29100 -29101 -29102 -29103 -29104 -29105 -29106 -29107 -29108 -29109 -29110 -29111 -29112 -29113 -29114 -29115 -29116 -29117 -29118 -29119 -29120 -29121 -29122 -29123 -29124 -29125 -29126 -29127 -29128 -29129 -29130 -29131 -29132 -29133 -29134 -29135 -29136 -29137 -29138 -29139 -29140 -29141 -29142 -29143 -29144 -29145 -29146 -29147 -29148 -29149 -29150 -29151 -29152 -29153 -29154 -29155 -29156 -29157 -29158 -29159 -29160 -29161 -29162 -29163 -29164 -29165 -29166 -29167 -29168 -29169 -29170 -29171 -29172 -29173 -29174 -29175 -29176 -29177 -29178 -29179 -29180 -29181 -29182 -29183 -29184 -29185 -29186 -29187 -29188 -29189 -29190 -29191 -29192 -29193 -29194 -29195 -29196 -29197 -29198 -29199 -29200 -29201 -29202 -29203 -29204 -29205 -29206 -29207 -29208 -29209 -29210 -29211 -29212 -29213 -29214 -29215 -29216 -29217 -29218 -29219 -29220 -29221 -29222 -29223 -29224 -29225 -29226 -29227 -29228 -29229 -29230 -29231 -29232 -29233 -29234 -29235 -29236 -29237 -29238 -29239 -29240 -29241 -29242 -29243 -29244 -29245 -29246 -29247 -29248 -29249 -29250 -29251 -29252 -29253 -29254 -29255 -29256 -29257 -29258 -29259 -29260 -29261 -29262 -29263 -29264 -29265 -29266 -29267 -29268 -29269 -29270 -29271 -29272 -29273 -29274 -29275 -29276 -29277 -29278 -29279 -29280 -29281 -29282 -29283 -29284 -29285 -29286 -29287 -29288 -29289 -29290 -29291 -29292 -29293 -29294 -29295 -29296 -29297 -29298 -29299 -29300 -29301 -29302 -29303 -29304 -29305 -29306 -29307 -29308 -29309 -29310 -29311 -29312 -29313 -29314 -29315 -29316 -29317 -29318 -29319 -29320 -29321 -29322 -29323 -29324 -29325 -29326 -29327 -29328 -29329 -29330 -29331 -29332 -29333 -29334 -29335 -29336 -29337 -29338 -29339 -29340 -29341 -29342 -29343 -29344 -29345 -29346 -29347 -29348 -29349 -29350 -29351 -29352 -29353 -29354 -29355 -29356 -29357 -29358 -29359 -29360 -29361 -29362 -29363 -29364 -29365 -29366 -29367 -29368 -29369 -29370 -29371 -29372 -29373 -29374 -29375 -29376 -29377 -29378 -29379 -29380 -29381 -29382 -29383 -29384 -29385 -29386 -29387 -29388 -29389 -29390 -29391 -29392 -29393 -29394 -29395 -29396 -29397 -29398 -29399 -29400 -29401 -29402 -29403 -29404 -29405 -29406 -29407 -29408 -29409 -29410 -29411 -29412 -29413 -29414 -29415 -29416 -29417 -29418 -29419 -29420 -29421 -29422 -29423 -29424 -29425 -29426 -29427 -29428 -29429 -29430 -29431 -29432 -29433 -29434 -29435 -29436 -29437 -29438 -29439 -29440 -29441 -29442 -29443 -29444 -29445 -29446 -29447 -29448 -29449 -29450 -29451 -29452 -29453 -29454 -29455 -29456 -29457 -29458 -29459 -29460 -29461 -29462 -29463 -29464 -29465 -29466 -29467 -29468 -29469 -29470 -29471 -29472 -29473 -29474 -29475 -29476 -29477 -29478 -29479 -29480 -29481 -29482 -29483 -29484 -29485 -29486 -29487 -29488 -29489 -29490 -29491 -29492 -29493 -29494 -29495 -29496 -29497 -29498 -29499 -29500 -29501 -29502 -29503 -29504 -29505 -29506 -29507 -29508 -29509 -29510 -29511 -29512 -29513 -29514 -29515 -29516 -29517 -29518 -29519 -29520 -29521 -29522 -29523 -29524 -29525 -29526 -29527 -29528 -29529 -29530 -29531 -29532 -29533 -29534 -29535 -29536 -29537 -29538 -29539 -29540 -29541 -29542 -29543 -29544 -29545 -29546 -29547 -29548 -29549 -29550 -29551 -29552 -29553 -29554 -29555 -29556 -29557 -29558 -29559 -29560 -29561 -29562 -29563 -29564 -29565 -29566 -29567 -29568 -29569 -29570 -29571 -29572 -29573 -29574 -29575 -29576 -29577 -29578 -29579 -29580 -29581 -29582 -29583 -29584 -29585 -29586 -29587 -29588 -29589 -29590 -29591 -29592 -29593 -29594 -29595 -29596 -29597 -29598 -29599 -29600 -29601 -29602 -29603 -29604 -29605 -29606 -29607 -29608 -29609 -29610 -29611 -29612 -29613 -29614 -29615 -29616 -29617 -29618 -29619 -29620 -29621 -29622 -29623 -29624 -29625 -29626 -29627 -29628 -29629 -29630 -29631 -29632 -29633 -29634 -29635 -29636 -29637 -29638 -29639 -29640 -29641 -29642 -29643 -29644 -29645 -29646 -29647 -29648 -29649 -29650 -29651 -29652 -29653 -29654 -29655 -29656 -29657 -29658 -29659 -29660 -29661 -29662 -29663 -29664 -29665 -29666 -29667 -29668 -29669 -29670 -29671 -29672 -29673 -29674 -29675 -29676 -29677 -29678 -29679 -29680 -29681 -29682 -29683 -29684 -29685 -29686 -29687 -29688 -29689 -29690 -29691 -29692 -29693 -29694 -29695 -29696 -29697 -29698 -29699 -29700 -29701 -29702 -29703 -29704 -29705 -29706 -29707 -29708 -29709 -29710 -29711 -29712 -29713 -29714 -29715 -29716 -29717 -29718 -29719 -29720 -29721 -29722 -29723 -29724 -29725 -29726 -29727 -29728 -29729 -29730 -29731 -29732 -29733 -29734 -29735 -29736 -29737 -29738 -29739 -29740 -29741 -29742 -29743 -29744 -29745 -29746 -29747 -29748 -29749 -29750 -29751 -29752 -29753 -29754 -29755 -29756 -29757 -29758 -29759 -29760 -29761 -29762 -29763 -29764 -29765 -29766 -29767 -29768 -29769 -29770 -29771 -29772 -29773 -29774 -29775 -29776 -29777 -29778 -29779 -29780 -29781 -29782 -29783 -29784 -29785 -29786 -29787 -29788 -29789 -29790 -29791 -29792 -29793 -29794 -29795 -29796 -29797 -29798 -29799 -29800 -29801 -29802 -29803 -29804 -29805 -29806 -29807 -29808 -29809 -29810 -29811 -29812 -29813 -29814 -29815 -29816 -29817 -29818 -29819 -29820 -29821 -29822 -29823 -29824 -29825 -29826 -29827 -29828 -29829 -29830 -29831 -29832 -29833 -29834 -29835 -29836 -29837 -29838 -29839 -29840 -29841 -29842 -29843 -29844 -29845 -29846 -29847 -29848 -29849 -29850 -29851 -29852 -29853 -29854 -29855 -29856 -29857 -29858 -29859 -29860 -29861 -29862 -29863 -29864 -29865 -29866 -29867 -29868 -29869 -29870 -29871 -29872 -29873 -29874 -29875 -29876 -29877 -29878 -29879 -29880 -29881 -29882 -29883 -29884 -29885 -29886 -29887 -29888 -29889 -29890 -29891 -29892 -29893 -29894 -29895 -29896 -29897 -29898 -29899 -29900 -29901 -29902 -29903 -29904 -29905 -29906 -29907 -29908 -29909 -29910 -29911 -29912 -29913 -29914 -29915 -29916 -29917 -29918 -29919 -29920 -29921 -29922 -29923 -29924 -29925 -29926 -29927 -29928 -29929 -29930 -29931 -29932 -29933 -29934 -29935 -29936 -29937 -29938 -29939 -29940 -29941 -29942 -29943 -29944 -29945 -29946 -29947 -29948 -29949 -29950 -29951 -29952 -29953 -29954 -29955 -29956 -29957 -29958 -29959 -29960 -29961 -29962 -29963 -29964 -29965 -29966 -29967 -29968 -29969 -29970 -29971 -29972 -29973 -29974 -29975 -29976 -29977 -29978 -29979 -29980 -29981 -29982 -29983 -29984 -29985 -29986 -29987 -29988 -29989 -29990 -29991 -29992 -29993 -29994 -29995 -29996 -29997 -29998 -29999 -30000 -30001 -30002 -30003 -30004 -30005 -30006 -30007 -30008 -30009 -30010 -30011 -30012 -30013 -30014 -30015 -30016 -30017 -30018 -30019 -30020 -30021 -30022 -30023 -30024 -30025 -30026 -30027 -30028 -30029 -30030 -30031 -30032 -30033 -30034 -30035 -30036 -30037 -30038 -30039 -30040 -30041 -30042 -30043 -30044 -30045 -30046 -30047 -30048 -30049 -30050 -30051 -30052 -30053 -30054 -30055 -30056 -30057 -30058 -30059 -30060 -30061 -30062 -30063 -30064 -30065 -30066 -30067 -30068 -30069 -30070 -30071 -30072 -30073 -30074 -30075 -30076 -30077 -30078 -30079 -30080 -30081 -30082 -30083 -30084 -30085 -30086 -30087 -30088 -30089 -30090 -30091 -30092 -30093 -30094 -30095 -30096 -30097 -30098 -30099 -30100 -30101 -30102 -30103 -30104 -30105 -30106 -30107 -30108 -30109 -30110 -30111 -30112 -30113 -30114 -30115 -30116 -30117 -30118 -30119 -30120 -30121 -30122 -30123 -30124 -30125 -30126 -30127 -30128 -30129 -30130 -30131 -30132 -30133 -30134 -30135 -30136 -30137 -30138 -30139 -30140 -30141 -30142 -30143 -30144 -30145 -30146 -30147 -30148 -30149 -30150 -30151 -30152 -30153 -30154 -30155 -30156 -30157 -30158 -30159 -30160 -30161 -30162 -30163 -30164 -30165 -30166 -30167 -30168 -30169 -30170 -30171 -30172 -30173 -30174 -30175 -30176 -30177 -30178 -30179 -30180 -30181 -30182 -30183 -30184 -30185 -30186 -30187 -30188 -30189 -30190 -30191 -30192 -30193 -30194 -30195 -30196 -30197 -30198 -30199 -30200 -30201 -30202 -30203 -30204 -30205 -30206 -30207 -30208 -30209 -30210 -30211 -30212 -30213 -30214 -30215 -30216 -30217 -30218 -30219 -30220 -30221 -30222 -30223 -30224 -30225 -30226 -30227 -30228 -30229 -30230 -30231 -30232 -30233 -30234 -30235 -30236 -30237 -30238 -30239 -30240 -30241 -30242 -30243 -30244 -30245 -30246 -30247 -30248 -30249 -30250 -30251 -30252 -30253 -30254 -30255 -30256 -30257 -30258 -30259 -30260 -30261 -30262 -30263 -30264 -30265 -30266 -30267 -30268 -30269 -30270 -30271 -30272 -30273 -30274 -30275 -30276 -30277 -30278 -30279 -30280 -30281 -30282 -30283 -30284 -30285 -30286 -30287 -30288 -30289 -30290 -30291 -30292 -30293 -30294 -30295 -30296 -30297 -30298 -30299 -30300 -30301 -30302 -30303 -30304 -30305 -30306 -30307 -30308 -30309 -30310 -30311 -30312 -30313 -30314 -30315 -30316 -30317 -30318 -30319 -30320 -30321 -30322 -30323 -30324 -30325 -30326 -30327 -30328 -30329 -30330 -30331 -30332 -30333 -30334 -30335 -30336 -30337 -30338 -30339 -30340 -30341 -30342 -30343 -30344 -30345 -30346 -30347 -30348 -30349 -30350 -30351 -30352 -30353 -30354 -30355 -30356 -30357 -30358 -30359 -30360 -30361 -30362 -30363 -30364 -30365 -30366 -30367 -30368 -30369 -30370 -30371 -30372 -30373 -30374 -30375 -30376 -30377 -30378 -30379 -30380 -30381 -30382 -30383 -30384 -30385 -30386 -30387 -30388 -30389 -30390 -30391 -30392 -30393 -30394 -30395 -30396 -30397 -30398 -30399 -30400 -30401 -30402 -30403 -30404 -30405 -30406 -30407 -30408 -30409 -30410 -30411 -30412 -30413 -30414 -30415 -30416 -30417 -30418 -30419 -30420 -30421 -30422 -30423 -30424 -30425 -30426 -30427 -30428 -30429 -30430 -30431 -30432 -30433 -30434 -30435 -30436 -30437 -30438 -30439 -30440 -30441 -30442 -30443 -30444 -30445 -30446 -30447 -30448 -30449 -30450 -30451 -30452 -30453 -30454 -30455 -30456 -30457 -30458 -30459 -30460 -30461 -30462 -30463 -30464 -30465 -30466 -30467 -30468 -30469 -30470 -30471 -30472 -30473 -30474 -30475 -30476 -30477 -30478 -30479 -30480 -30481 -30482 -30483 -30484 -30485 -30486 -30487 -30488 -30489 -30490 -30491 -30492 -30493 -30494 -30495 -30496 -30497 -30498 -30499 -30500 -30501 -30502 -30503 -30504 -30505 -30506 -30507 -30508 -30509 -30510 -30511 -30512 -30513 -30514 -30515 -30516 -30517 -30518 -30519 -30520 -30521 -30522 -30523 -30524 -30525 -30526 -30527 -30528 -30529 -30530 -30531 -30532 -30533 -30534 -30535 -30536 -30537 -30538 -30539 -30540 -30541 -30542 -30543 -30544 -30545 -30546 -30547 -30548 -30549 -30550 -30551 -30552 -30553 -30554 -30555 -30556 -30557 -30558 -30559 -30560 -30561 -30562 -30563 -30564 -30565 -30566 -30567 -30568 -30569 -30570 -30571 -30572 -30573 -30574 -30575 -30576 -30577 -30578 -30579 -30580 -30581 -30582 -30583 -30584 -30585 -30586 -30587 -30588 -30589 -30590 -30591 -30592 -30593 -30594 -30595 -30596 -30597 -30598 -30599 -30600 -30601 -30602 -30603 -30604 -30605 -30606 -30607 -30608 -30609 -30610 -30611 -30612 -30613 -30614 -30615 -30616 -30617 -30618 -30619 -30620 -30621 -30622 -30623 -30624 -30625 -30626 -30627 -30628 -30629 -30630 -30631 -30632 -30633 -30634 -30635 -30636 -30637 -30638 -30639 -30640 -30641 -30642 -30643 -30644 -30645 -30646 -30647 -30648 -30649 -30650 -30651 -30652 -30653 -30654 -30655 -30656 -30657 -30658 -30659 -30660 -30661 -30662 -30663 -30664 -30665 -30666 -30667 -30668 -30669 -30670 -30671 -30672 -30673 -30674 -30675 -30676 -30677 -30678 -30679 -30680 -30681 -30682 -30683 -30684 -30685 -30686 -30687 -30688 -30689 -30690 -30691 -30692 -30693 -30694 -30695 -30696 -30697 -30698 -30699 -30700 -30701 -30702 -30703 -30704 -30705 -30706 -30707 -30708 -30709 -30710 -30711 -30712 -30713 -30714 -30715 -30716 -30717 -30718 -30719 -30720 -30721 -30722 -30723 -30724 -30725 -30726 -30727 -30728 -30729 -30730 -30731 -30732 -30733 -30734 -30735 -30736 -30737 -30738 -30739 -30740 -30741 -30742 -30743 -30744 -30745 -30746 -30747 -30748 -30749 -30750 -30751 -30752 -30753 -30754 -30755 -30756 -30757 -30758 -30759 -30760 -30761 -30762 -30763 -30764 -30765 -30766 -30767 -30768 -30769 -30770 -30771 -30772 -30773 -30774 -30775 -30776 -30777 -30778 -30779 -30780 -30781 -30782 -30783 -30784 -30785 -30786 -30787 -30788 -30789 -30790 -30791 -30792 -30793 -30794 -30795 -30796 -30797 -30798 -30799 -30800 -30801 -30802 -30803 -30804 -30805 -30806 -30807 -30808 -30809 -30810 -30811 -30812 -30813 -30814 -30815 -30816 -30817 -30818 -30819 -30820 -30821 -30822 -30823 -30824 -30825 -30826 -30827 -30828 -30829 -30830 -30831 -30832 -30833 -30834 -30835 -30836 -30837 -30838 -30839 -30840 -30841 -30842 -30843 -30844 -30845 -30846 -30847 -30848 -30849 -30850 -30851 -30852 -30853 -30854 -30855 -30856 -30857 -30858 -30859 -30860 -30861 -30862 -30863 -30864 -30865 -30866 -30867 -30868 -30869 -30870 -30871 -30872 -30873 -30874 -30875 -30876 -30877 -30878 -30879 -30880 -30881 -30882 -30883 -30884 -30885 -30886 -30887 -30888 -30889 -30890 -30891 -30892 -30893 -30894 -30895 -30896 -30897 -30898 -30899 -30900 -30901 -30902 -30903 -30904 -30905 -30906 -30907 -30908 -30909 -30910 -30911 -30912 -30913 -30914 -30915 -30916 -30917 -30918 -30919 -30920 -30921 -30922 -30923 -30924 -30925 -30926 -30927 -30928 -30929 -30930 -30931 -30932 -30933 -30934 -30935 -30936 -30937 -30938 -30939 -30940 -30941 -30942 -30943 -30944 -30945 -30946 -30947 -30948 -30949 -30950 -30951 -30952 -30953 -30954 -30955 -30956 -30957 -30958 -30959 -30960 -30961 -30962 -30963 -30964 -30965 -30966 -30967 -30968 -30969 -30970 -30971 -30972 -30973 -30974 -30975 -30976 -30977 -30978 -30979 -30980 -30981 -30982 -30983 -30984 -30985 -30986 -30987 -30988 -30989 -30990 -30991 -30992 -30993 -30994 -30995 -30996 -30997 -30998 -30999 -31000 -31001 -31002 -31003 -31004 -31005 -31006 -31007 -31008 -31009 -31010 -31011 -31012 -31013 -31014 -31015 -31016 -31017 -31018 -31019 -31020 -31021 -31022 -31023 -31024 -31025 -31026 -31027 -31028 -31029 -31030 -31031 -31032 -31033 -31034 -31035 -31036 -31037 -31038 -31039 -31040 -31041 -31042 -31043 -31044 -31045 -31046 -31047 -31048 -31049 -31050 -31051 -31052 -31053 -31054 -31055 -31056 -31057 -31058 -31059 -31060 -31061 -31062 -31063 -31064 -31065 -31066 -31067 -31068 -31069 -31070 -31071 -31072 -31073 -31074 -31075 -31076 -31077 -31078 -31079 -31080 -31081 -31082 -31083 -31084 -31085 -31086 -31087 -31088 -31089 -31090 -31091 -31092 -31093 -31094 -31095 -31096 -31097 -31098 -31099 -31100 -31101 -31102 -31103 -31104 -31105 -31106 -31107 -31108 -31109 -31110 -31111 -31112 -31113 -31114 -31115 -31116 -31117 -31118 -31119 -31120 -31121 -31122 -31123 -31124 -31125 -31126 -31127 -31128 -31129 -31130 -31131 -31132 -31133 -31134 -31135 -31136 -31137 -31138 -31139 -31140 -31141 -31142 -31143 -31144 -31145 -31146 -31147 -31148 -31149 -31150 -31151 -31152 -31153 -31154 -31155 -31156 -31157 -31158 -31159 -31160 -31161 -31162 -31163 -31164 -31165 -31166 -31167 -31168 -31169 -31170 -31171 -31172 -31173 -31174 -31175 -31176 -31177 -31178 -31179 -31180 -31181 -31182 -31183 -31184 -31185 -31186 -31187 -31188 -31189 -31190 -31191 -31192 -31193 -31194 -31195 -31196 -31197 -31198 -31199 -31200 -31201 -31202 -31203 -31204 -31205 -31206 -31207 -31208 -31209 -31210 -31211 -31212 -31213 -31214 -31215 -31216 -31217 -31218 -31219 -31220 -31221 -31222 -31223 -31224 -31225 -31226 -31227 -31228 -31229 -31230 -31231 -31232 -31233 -31234 -31235 -31236 -31237 -31238 -31239 -31240 -31241 -31242 -31243 -31244 -31245 -31246 -31247 -31248 -31249 -31250 -31251 -31252 -31253 -31254 -31255 -31256 -31257 -31258 -31259 -31260 -31261 -31262 -31263 -31264 -31265 -31266 -31267 -31268 -31269 -31270 -31271 -31272 -31273 -31274 -31275 -31276 -31277 -31278 -31279 -31280 -31281 -31282 -31283 -31284 -31285 -31286 -31287 -31288 -31289 -31290 -31291 -31292 -31293 -31294 -31295 -31296 -31297 -31298 -31299 -31300 -31301 -31302 -31303 -31304 -31305 -31306 -31307 -31308 -31309 -31310 -31311 -31312 -31313 -31314 -31315 -31316 -31317 -31318 -31319 -31320 -31321 -31322 -31323 -31324 -31325 -31326 -31327 -31328 -31329 -31330 -31331 -31332 -31333 -31334 -31335 -31336 -31337 -31338 -31339 -31340 -31341 -31342 -31343 -31344 -31345 -31346 -31347 -31348 -31349 -31350 -31351 -31352 -31353 -31354 -31355 -31356 -31357 -31358 -31359 -31360 -31361 -31362 -31363 -31364 -31365 -31366 -31367 -31368 -31369 -31370 -31371 -31372 -31373 -31374 -31375 -31376 -31377 -31378 -31379 -31380 -31381 -31382 -31383 -31384 -31385 -31386 -31387 -31388 -31389 -31390 -31391 -31392 -31393 -31394 -31395 -31396 -31397 -31398 -31399 -31400 -31401 -31402 -31403 -31404 -31405 -31406 -31407 -31408 -31409 -31410 -31411 -31412 -31413 -31414 -31415 -31416 -31417 -31418 -31419 -31420 -31421 -31422 -31423 -31424 -31425 -31426 -31427 -31428 -31429 -31430 -31431 -31432 -31433 -31434 -31435 -31436 -31437 -31438 -31439 -31440 -31441 -31442 -31443 -31444 -31445 -31446 -31447 -31448 -31449 -31450 -31451 -31452 -31453 -31454 -31455 -31456 -31457 -31458 -31459 -31460 -31461 -31462 -31463 -31464 -31465 -31466 -31467 -31468 -31469 -31470 -31471 -31472 -31473 -31474 -31475 -31476 -31477 -31478 -31479 -31480 -31481 -31482 -31483 -31484 -31485 -31486 -31487 -31488 -31489 -31490 -31491 -31492 -31493 -31494 -31495 -31496 -31497 -31498 -31499 -31500 -31501 -31502 -31503 -31504 -31505 -31506 -31507 -31508 -31509 -31510 -31511 -31512 -31513 -31514 -31515 -31516 -31517 -31518 -31519 -31520 -31521 -31522 -31523 -31524 -31525 -31526 -31527 -31528 -31529 -31530 -31531 -31532 -31533 -31534 -31535 -31536 -31537 -31538 -31539 -31540 -31541 -31542 -31543 -31544 -31545 -31546 -31547 -31548 -31549 -31550 -31551 -31552 -31553 -31554 -31555 -31556 -31557 -31558 -31559 -31560 -31561 -31562 -31563 -31564 -31565 -31566 -31567 -31568 -31569 -31570 -31571 -31572 -31573 -31574 -31575 -31576 -31577 -31578 -31579 -31580 -31581 -31582 -31583 -31584 -31585 -31586 -31587 -31588 -31589 -31590 -31591 -31592 -31593 -31594 -31595 -31596 -31597 -31598 -31599 -31600 -31601 -31602 -31603 -31604 -31605 -31606 -31607 -31608 -31609 -31610 -31611 -31612 -31613 -31614 -31615 -31616 -31617 -31618 -31619 -31620 -31621 -31622 -31623 -31624 -31625 -31626 -31627 -31628 -31629 -31630 -31631 -31632 -31633 -31634 -31635 -31636 -31637 -31638 -31639 -31640 -31641 -31642 -31643 -31644 -31645 -31646 -31647 -31648 -31649 -31650 -31651 -31652 -31653 -31654 -31655 -31656 -31657 -31658 -31659 -31660 -31661 -31662 -31663 -31664 -31665 -31666 -31667 -31668 -31669 -31670 -31671 -31672 -31673 -31674 -31675 -31676 -31677 -31678 -31679 -31680 -31681 -31682 -31683 -31684 -31685 -31686 -31687 -31688 -31689 -31690 -31691 -31692 -31693 -31694 -31695 -31696 -31697 -31698 -31699 -31700 -31701 -31702 -31703 -31704 -31705 -31706 -31707 -31708 -31709 -31710 -31711 -31712 -31713 -31714 -31715 -31716 -31717 -31718 -31719 -31720 -31721 -31722 -31723 -31724 -31725 -31726 -31727 -31728 -31729 -31730 -31731 -31732 -31733 -31734 -31735 -31736 -31737 -31738 -31739 -31740 -31741 -31742 -31743 -31744 -31745 -31746 -31747 -31748 -31749 -31750 -31751 -31752 -31753 -31754 -31755 -31756 -31757 -31758 -31759 -31760 -31761 -31762 -31763 -31764 -31765 -31766 -31767 -31768 -31769 -31770 -31771 -31772 -31773 -31774 -31775 -31776 -31777 -31778 -31779 -31780 -31781 -31782 -31783 -31784 -31785 -31786 -31787 -31788 -31789 -31790 -31791 -31792 -31793 -31794 -31795 -31796 -31797 -31798 -31799 -31800 -31801 -31802 -31803 -31804 -31805 -31806 -31807 -31808 -31809 -31810 -31811 -31812 -31813 -31814 -31815 -31816 -31817 -31818 -31819 -31820 -31821 -31822 -31823 -31824 -31825 -31826 -31827 -31828 -31829 -31830 -31831 -31832 -31833 -31834 -31835 -31836 -31837 -31838 -31839 -31840 -31841 -31842 -31843 -31844 -31845 -31846 -31847 -31848 -31849 -31850 -31851 -31852 -31853 -31854 -31855 -31856 -31857 -31858 -31859 -31860 -31861 -31862 -31863 -31864 -31865 -31866 -31867 -31868 -31869 -31870 -31871 -31872 -31873 -31874 -31875 -31876 -31877 -31878 -31879 -31880 -31881 -31882 -31883 -31884 -31885 -31886 -31887 -31888 -31889 -31890 -31891 -31892 -31893 -31894 -31895 -31896 -31897 -31898 -31899 -31900 -31901 -31902 -31903 -31904 -31905 -31906 -31907 -31908 -31909 -31910 -31911 -31912 -31913 -31914 -31915 -31916 -31917 -31918 -31919 -31920 -31921 -31922 -31923 -31924 -31925 -31926 -31927 -31928 -31929 -31930 -31931 -31932 -31933 -31934 -31935 -31936 -31937 -31938 -31939 -31940 -31941 -31942 -31943 -31944 -31945 -31946 -31947 -31948 -31949 -31950 -31951 -31952 -31953 -31954 -31955 -31956 -31957 -31958 -31959 -31960 -31961 -31962 -31963 -31964 -31965 -31966 -31967 -31968 -31969 -31970 -31971 -31972 -31973 -31974 -31975 -31976 -31977 -31978 -31979 -31980 -31981 -31982 -31983 -31984 -31985 -31986 -31987 -31988 -31989 -31990 -31991 -31992 -31993 -31994 -31995 -31996 -31997 -31998 -31999 -32000 -32001 -32002 -32003 -32004 -32005 -32006 -32007 -32008 -32009 -32010 -32011 -32012 -32013 -32014 -32015 -32016 -32017 -32018 -32019 -32020 -32021 -32022 -32023 -32024 -32025 -32026 -32027 -32028 -32029 -32030 -32031 -32032 -32033 -32034 -32035 -32036 -32037 -32038 -32039 -32040 -32041 -32042 -32043 -32044 -32045 -32046 -32047 -32048 -32049 -32050 -32051 -32052 -32053 -32054 -32055 -32056 -32057 -32058 -32059 -32060 -32061 -32062 -32063 -32064 -32065 -32066 -32067 -32068 -32069 -32070 -32071 -32072 -32073 -32074 -32075 -32076 -32077 -32078 -32079 -32080 -32081 -32082 -32083 -32084 -32085 -32086 -32087 -32088 -32089 -32090 -32091 -32092 -32093 -32094 -32095 -32096 -32097 -32098 -32099 -32100 -32101 -32102 -32103 -32104 -32105 -32106 -32107 -32108 -32109 -32110 -32111 -32112 -32113 -32114 -32115 -32116 -32117 -32118 -32119 -32120 -32121 -32122 -32123 -32124 -32125 -32126 -32127 -32128 -32129 -32130 -32131 -32132 -32133 -32134 -32135 -32136 -32137 -32138 -32139 -32140 -32141 -32142 -32143 -32144 -32145 -32146 -32147 -32148 -32149 -32150 -32151 -32152 -32153 -32154 -32155 -32156 -32157 -32158 -32159 -32160 -32161 -32162 -32163 -32164 -32165 -32166 -32167 -32168 -32169 -32170 -32171 -32172 -32173 -32174 -32175 -32176 -32177 -32178 -32179 -32180 -32181 -32182 -32183 -32184 -32185 -32186 -32187 -32188 -32189 -32190 -32191 -32192 -32193 -32194 -32195 -32196 -32197 -32198 -32199 -32200 -32201 -32202 -32203 -32204 -32205 -32206 -32207 -32208 -32209 -32210 -32211 -32212 -32213 -32214 -32215 -32216 -32217 -32218 -32219 -32220 -32221 -32222 -32223 -32224 -32225 -32226 -32227 -32228 -32229 -32230 -32231 -32232 -32233 -32234 -32235 -32236 -32237 -32238 -32239 -32240 -32241 -32242 -32243 -32244 -32245 -32246 -32247 -32248 -32249 -32250 -32251 -32252 -32253 -32254 -32255 -32256 -32257 -32258 -32259 -32260 -32261 -32262 -32263 -32264 -32265 -32266 -32267 -32268 -32269 -32270 -32271 -32272 -32273 -32274 -32275 -32276 -32277 -32278 -32279 -32280 -32281 -32282 -32283 -32284 -32285 -32286 -32287 -32288 -32289 -32290 -32291 -32292 -32293 -32294 -32295 -32296 -32297 -32298 -32299 -32300 -32301 -32302 -32303 -32304 -32305 -32306 -32307 -32308 -32309 -32310 -32311 -32312 -32313 -32314 -32315 -32316 -32317 -32318 -32319 -32320 -32321 -32322 -32323 -32324 -32325 -32326 -32327 -32328 -32329 -32330 -32331 -32332 -32333 -32334 -32335 -32336 -32337 -32338 -32339 -32340 -32341 -32342 -32343 -32344 -32345 -32346 -32347 -32348 -32349 -32350 -32351 -32352 -32353 -32354 -32355 -32356 -32357 -32358 -32359 -32360 -32361 -32362 -32363 -32364 -32365 -32366 -32367 -32368 -32369 -32370 -32371 -32372 -32373 -32374 -32375 -32376 -32377 -32378 -32379 -32380 -32381 -32382 -32383 -32384 -32385 -32386 -32387 -32388 -32389 -32390 -32391 -32392 -32393 -32394 -32395 -32396 -32397 -32398 -32399 -32400 -32401 -32402 -32403 -32404 -32405 -32406 -32407 -32408 -32409 -32410 -32411 -32412 -32413 -32414 -32415 -32416 -32417 -32418 -32419 -32420 -32421 -32422 -32423 -32424 -32425 -32426 -32427 -32428 -32429 -32430 -32431 -32432 -32433 -32434 -32435 -32436 -32437 -32438 -32439 -32440 -32441 -32442 -32443 -32444 -32445 -32446 -32447 -32448 -32449 -32450 -32451 -32452 -32453 -32454 -32455 -32456 -32457 -32458 -32459 -32460 -32461 -32462 -32463 -32464 -32465 -32466 -32467 -32468 -32469 -32470 -32471 -32472 -32473 -32474 -32475 -32476 -32477 -32478 -32479 -32480 -32481 -32482 -32483 -32484 -32485 -32486 -32487 -32488 -32489 -32490 -32491 -32492 -32493 -32494 -32495 -32496 -32497 -32498 -32499 -32500 -32501 -32502 -32503 -32504 -32505 -32506 -32507 -32508 -32509 -32510 -32511 -32512 -32513 -32514 -32515 -32516 -32517 -32518 -32519 -32520 -32521 -32522 -32523 -32524 -32525 -32526 -32527 -32528 -32529 -32530 -32531 -32532 -32533 -32534 -32535 -32536 -32537 -32538 -32539 -32540 -32541 -32542 -32543 -32544 -32545 -32546 -32547 -32548 -32549 -32550 -32551 -32552 -32553 -32554 -32555 -32556 -32557 -32558 -32559 -32560 -32561 -32562 -32563 -32564 -32565 -32566 -32567 -32568 -32569 -32570 -32571 -32572 -32573 -32574 -32575 -32576 -32577 -32578 -32579 -32580 -32581 -32582 -32583 -32584 -32585 -32586 -32587 -32588 -32589 -32590 -32591 -32592 -32593 -32594 -32595 -32596 -32597 -32598 -32599 -32600 -32601 -32602 -32603 -32604 -32605 -32606 -32607 -32608 -32609 -32610 -32611 -32612 -32613 -32614 -32615 -32616 -32617 -32618 -32619 -32620 -32621 -32622 -32623 -32624 -32625 -32626 -32627 -32628 -32629 -32630 -32631 -32632 -32633 -32634 -32635 -32636 -32637 -32638 -32639 -32640 -32641 -32642 -32643 -32644 -32645 -32646 -32647 -32648 -32649 -32650 -32651 -32652 -32653 -32654 -32655 -32656 -32657 -32658 -32659 -32660 -32661 -32662 -32663 -32664 -32665 -32666 -32667 -32668 -32669 -32670 -32671 -32672 -32673 -32674 -32675 -32676 -32677 -32678 -32679 -32680 -32681 -32682 -32683 -32684 -32685 -32686 -32687 -32688 -32689 -32690 -32691 -32692 -32693 -32694 -32695 -32696 -32697 -32698 -32699 -32700 -32701 -32702 -32703 -32704 -32705 -32706 -32707 -32708 -32709 -32710 -32711 -32712 -32713 -32714 -32715 -32716 -32717 -32718 -32719 -32720 -32721 -32722 -32723 -32724 -32725 -32726 -32727 -32728 -32729 -32730 -32731 -32732 -32733 -32734 -32735 -32736 -32737 -32738 -32739 -32740 -32741 -32742 -32743 -32744 -32745 -32746 -32747 -32748 -32749 -32750 -32751 -32752 -32753 -32754 -32755 -32756 -32757 -32758 -32759 -32760 -32761 -32762 -32763 -32764 -32765 -32766 -32767 -32768 -32769 -32770 -32771 -32772 -32773 -32774 -32775 -32776 -32777 -32778 -32779 -32780 -32781 -32782 -32783 -32784 -32785 -32786 -32787 -32788 -32789 -32790 -32791 -32792 -32793 -32794 -32795 -32796 -32797 -32798 -32799 -32800 -32801 -32802 -32803 -32804 -32805 -32806 -32807 -32808 -32809 -32810 -32811 -32812 -32813 -32814 -32815 -32816 -32817 -32818 -32819 -32820 -32821 -32822 -32823 -32824 -32825 -32826 -32827 -32828 -32829 -32830 -32831 -32832 -32833 -32834 -32835 -32836 -32837 -32838 -32839 -32840 -32841 -32842 -32843 -32844 -32845 -32846 -32847 -32848 -32849 -32850 -32851 -32852 -32853 -32854 -32855 -32856 -32857 -32858 -32859 -32860 -32861 -32862 -32863 -32864 -32865 -32866 -32867 -32868 -32869 -32870 -32871 -32872 -32873 -32874 -32875 -32876 -32877 -32878 -32879 -32880 -32881 -32882 -32883 -32884 -32885 -32886 -32887 -32888 -32889 -32890 -32891 -32892 -32893 -32894 -32895 -32896 -32897 -32898 -32899 -32900 -32901 -32902 -32903 -32904 -32905 -32906 -32907 -32908 -32909 -32910 -32911 -32912 -32913 -32914 -32915 -32916 -32917 -32918 -32919 -32920 -32921 -32922 -32923 -32924 -32925 -32926 -32927 -32928 -32929 -32930 -32931 -32932 -32933 -32934 -32935 -32936 -32937 -32938 -32939 -32940 -32941 -32942 -32943 -32944 -32945 -32946 -32947 -32948 -32949 -32950 -32951 -32952 -32953 -32954 -32955 -32956 -32957 -32958 -32959 -32960 -32961 -32962 -32963 -32964 -32965 -32966 -32967 -32968 -32969 -32970 -32971 -32972 -32973 -32974 -32975 -32976 -32977 -32978 -32979 -32980 -32981 -32982 -32983 -32984 -32985 -32986 -32987 -32988 -32989 -32990 -32991 -32992 -32993 -32994 -32995 -32996 -32997 -32998 -32999 -33000 -33001 -33002 -33003 -33004 -33005 -33006 -33007 -33008 -33009 -33010 -33011 -33012 -33013 -33014 -33015 -33016 -33017 -33018 -33019 -33020 -33021 -33022 -33023 -33024 -33025 -33026 -33027 -33028 -33029 -33030 -33031 -33032 -33033 -33034 -33035 -33036 -33037 -33038 -33039 -33040 -33041 -33042 -33043 -33044 -33045 -33046 -33047 -33048 -33049 -33050 -33051 -33052 -33053 -33054 -33055 -33056 -33057 -33058 -33059 -33060 -33061 -33062 -33063 -33064 -33065 -33066 -33067 -33068 -33069 -33070 -33071 -33072 -33073 -33074 -33075 -33076 -33077 -33078 -33079 -33080 -33081 -33082 -33083 -33084 -33085 -33086 -33087 -33088 -33089 -33090 -33091 -33092 -33093 -33094 -33095 -33096 -33097 -33098 -33099 -33100 -33101 -33102 -33103 -33104 -33105 -33106 -33107 -33108 -33109 -33110 -33111 -33112 -33113 -33114 -33115 -33116 -33117 -33118 -33119 -33120 -33121 -33122 -33123 -33124 -33125 -33126 -33127 -33128 -33129 -33130 -33131 -33132 -33133 -33134 -33135 -33136 -33137 -33138 -33139 -33140 -33141 -33142 -33143 -33144 -33145 -33146 -33147 -33148 -33149 -33150 -33151 -33152 -33153 -33154 -33155 -33156 -33157 -33158 -33159 -33160 -33161 -33162 -33163 -33164 -33165 -33166 -33167 -33168 -33169 -33170 -33171 -33172 -33173 -33174 -33175 -33176 -33177 -33178 -33179 -33180 -33181 -33182 -33183 -33184 -33185 -33186 -33187 -33188 -33189 -33190 -33191 -33192 -33193 -33194 -33195 -33196 -33197 -33198 -33199 -33200 -33201 -33202 -33203 -33204 -33205 -33206 -33207 -33208 -33209 -33210 -33211 -33212 -33213 -33214 -33215 -33216 -33217 -33218 -33219 -33220 -33221 -33222 -33223 -33224 -33225 -33226 -33227 -33228 -33229 -33230 -33231 -33232 -33233 -33234 -33235 -33236 -33237 -33238 -33239 -33240 -33241 -33242 -33243 -33244 -33245 -33246 -33247 -33248 -33249 -33250 -33251 -33252 -33253 -33254 -33255 -33256 -33257 -33258 -33259 -33260 -33261 -33262 -33263 -33264 -33265 -33266 -33267 -33268 -33269 -33270 -33271 -33272 -33273 -33274 -33275 -33276 -33277 -33278 -33279 -33280 -33281 -33282 -33283 -33284 -33285 -33286 -33287 -33288 -33289 -33290 -33291 -33292 -33293 -33294 -33295 -33296 -33297 -33298 -33299 -33300 -33301 -33302 -33303 -33304 -33305 -33306 -33307 -33308 -33309 -33310 -33311 -33312 -33313 -33314 -33315 -33316 -33317 -33318 -33319 -33320 -33321 -33322 -33323 -33324 -33325 -33326 -33327 -33328 -33329 -33330 -33331 -33332 -33333 -33334 -33335 -33336 -33337 -33338 -33339 -33340 -33341 -33342 -33343 -33344 -33345 -33346 -33347 -33348 -33349 -33350 -33351 -33352 -33353 -33354 -33355 -33356 -33357 -33358 -33359 -33360 -33361 -33362 -33363 -33364 -33365 -33366 -33367 -33368 -33369 -33370 -33371 -33372 -33373 -33374 -33375 -33376 -33377 -33378 -33379 -33380 -33381 -33382 -33383 -33384 -33385 -33386 -33387 -33388 -33389 -33390 -33391 -33392 -33393 -33394 -33395 -33396 -33397 -33398 -33399 -33400 -33401 -33402 -33403 -33404 -33405 -33406 -33407 -33408 -33409 -33410 -33411 -33412 -33413 -33414 -33415 -33416 -33417 -33418 -33419 -33420 -33421 -33422 -33423 -33424 -33425 -33426 -33427 -33428 -33429 -33430 -33431 -33432 -33433 -33434 -33435 -33436 -33437 -33438 -33439 -33440 -33441 -33442 -33443 -33444 -33445 -33446 -33447 -33448 -33449 -33450 -33451 -33452 -33453 -33454 -33455 -33456 -33457 -33458 -33459 -33460 -33461 -33462 -33463 -33464 -33465 -33466 -33467 -33468 -33469 -33470 -33471 -33472 -33473 -33474 -33475 -33476 -33477 -33478 -33479 -33480 -33481 -33482 -33483 -33484 -33485 -33486 -33487 -33488 -33489 -33490 -33491 -33492 -33493 -33494 -33495 -33496 -33497 -33498 -33499 -33500 -33501 -33502 -33503 -33504 -33505 -33506 -33507 -33508 -33509 -33510 -33511 -33512 -33513 -33514 -33515 -33516 -33517 -33518 -33519 -33520 -33521 -33522 -33523 -33524 -33525 -33526 -33527 -33528 -33529 -33530 -33531 -33532 -33533 -33534 -33535 -33536 -33537 -33538 -33539 -33540 -33541 -33542 -33543 -33544 -33545 -33546 -33547 -33548 -33549 -33550 -33551 -33552 -33553 -33554 -33555 -33556 -33557 -33558 -33559 -33560 -33561 -33562 -33563 -33564 -33565 -33566 -33567 -33568 -33569 -33570 -33571 -33572 -33573 -33574 -33575 -33576 -33577 -33578 -33579 -33580 -33581 -33582 -33583 -33584 -33585 -33586 -33587 -33588 -33589 -33590 -33591 -33592 -33593 -33594 -33595 -33596 -33597 -33598 -33599 -33600 -33601 -33602 -33603 -33604 -33605 -33606 -33607 -33608 -33609 -33610 -33611 -33612 -33613 -33614 -33615 -33616 -33617 -33618 -33619 -33620 -33621 -33622 -33623 -33624 -33625 -33626 -33627 -33628 -33629 -33630 -33631 -33632 -33633 -33634 -33635 -33636 -33637 -33638 -33639 -33640 -33641 -33642 -33643 -33644 -33645 -33646 -33647 -33648 -33649 -33650 -33651 -33652 -33653 -33654 -33655 -33656 -33657 -33658 -33659 -33660 -33661 -33662 -33663 -33664 -33665 -33666 -33667 -33668 -33669 -33670 -33671 -33672 -33673 -33674 -33675 -33676 -33677 -33678 -33679 -33680 -33681 -33682 -33683 -33684 -33685 -33686 -33687 -33688 -33689 -33690 -33691 -33692 -33693 -33694 -33695 -33696 -33697 -33698 -33699 -33700 -33701 -33702 -33703 -33704 -33705 -33706 -33707 -33708 -33709 -33710 -33711 -33712 -33713 -33714 -33715 -33716 -33717 -33718 -33719 -33720 -33721 -33722 -33723 -33724 -33725 -33726 -33727 -33728 -33729 -33730 -33731 -33732 -33733 -33734 -33735 -33736 -33737 -33738 -33739 -33740 -33741 -33742 -33743 -33744 -33745 -33746 -33747 -33748 -33749 -33750 -33751 -33752 -33753 -33754 -33755 -33756 -33757 -33758 -33759 -33760 -33761 -33762 -33763 -33764 -33765 -33766 -33767 -33768 -33769 -33770 -33771 -33772 -33773 -33774 -33775 -33776 -33777 -33778 -33779 -33780 -33781 -33782 -33783 -33784 -33785 -33786 -33787 -33788 -33789 -33790 -33791 -33792 -33793 -33794 -33795 -33796 -33797 -33798 -33799 -33800 -33801 -33802 -33803 -33804 -33805 -33806 -33807 -33808 -33809 -33810 -33811 -33812 -33813 -33814 -33815 -33816 -33817 -33818 -33819 -33820 -33821 -33822 -33823 -33824 -33825 -33826 -33827 -33828 -33829 -33830 -33831 -33832 -33833 -33834 -33835 -33836 -33837 -33838 -33839 -33840 -33841 -33842 -33843 -33844 -33845 -33846 -33847 -33848 -33849 -33850 -33851 -33852 -33853 -33854 -33855 -33856 -33857 -33858 -33859 -33860 -33861 -33862 -33863 -33864 -33865 -33866 -33867 -33868 -33869 -33870 -33871 -33872 -33873 -33874 -33875 -33876 -33877 -33878 -33879 -33880 -33881 -33882 -33883 -33884 -33885 -33886 -33887 -33888 -33889 -33890 -33891 -33892 -33893 -33894 -33895 -33896 -33897 -33898 -33899 -33900 -33901 -33902 -33903 -33904 -33905 -33906 -33907 -33908 -33909 -33910 -33911 -33912 -33913 -33914 -33915 -33916 -33917 -33918 -33919 -33920 -33921 -33922 -33923 -33924 -33925 -33926 -33927 -33928 -33929 -33930 -33931 -33932 -33933 -33934 -33935 -33936 -33937 -33938 -33939 -33940 -33941 -33942 -33943 -33944 -33945 -33946 -33947 -33948 -33949 -33950 -33951 -33952 -33953 -33954 -33955 -33956 -33957 -33958 -33959 -33960 -33961 -33962 -33963 -33964 -33965 -33966 -33967 -33968 -33969 -33970 -33971 -33972 -33973 -33974 -33975 -33976 -33977 -33978 -33979 -33980 -33981 -33982 -33983 -33984 -33985 -33986 -33987 -33988 -33989 -33990 -33991 -33992 -33993 -33994 -33995 -33996 -33997 -33998 -33999 -34000 -34001 -34002 -34003 -34004 -34005 -34006 -34007 -34008 -34009 -34010 -34011 -34012 -34013 -34014 -34015 -34016 -34017 -34018 -34019 -34020 -34021 -34022 -34023 -34024 -34025 -34026 -34027 -34028 -34029 -34030 -34031 -34032 -34033 -34034 -34035 -34036 -34037 -34038 -34039 -34040 -34041 -34042 -34043 -34044 -34045 -34046 -34047 -34048 -34049 -34050 -34051 -34052 -34053 -34054 -34055 -34056 -34057 -34058 -34059 -34060 -34061 -34062 -34063 -34064 -34065 -34066 -34067 -34068 -34069 -34070 -34071 -34072 -34073 -34074 -34075 -34076 -34077 -34078 -34079 -34080 -34081 -34082 -34083 -34084 -34085 -34086 -34087 -34088 -34089 -34090 -34091 -34092 -34093 -34094 -34095 -34096 -34097 -34098 -34099 -34100 -34101 -34102 -34103 -34104 -34105 -34106 -34107 -34108 -34109 -34110 -34111 -34112 -34113 -34114 -34115 -34116 -34117 -34118 -34119 -34120 -34121 -34122 -34123 -34124 -34125 -34126 -34127 -34128 -34129 -34130 -34131 -34132 -34133 -34134 -34135 -34136 -34137 -34138 -34139 -34140 -34141 -34142 -34143 -34144 -34145 -34146 -34147 -34148 -34149 -34150 -34151 -34152 -34153 -34154 -34155 -34156 -34157 -34158 -34159 -34160 -34161 -34162 -34163 -34164 -34165 -34166 -34167 -34168 -34169 -34170 -34171 -34172 -34173 -34174 -34175 -34176 -34177 -34178 -34179 -34180 -34181 -34182 -34183 -34184 -34185 -34186 -34187 -34188 -34189 -34190 -34191 -34192 -34193 -34194 -34195 -34196 -34197 -34198 -34199 -34200 -34201 -34202 -34203 -34204 -34205 -34206 -34207 -34208 -34209 -34210 -34211 -34212 -34213 -34214 -34215 -34216 -34217 -34218 -34219 -34220 -34221 -34222 -34223 -34224 -34225 -34226 -34227 -34228 -34229 -34230 -34231 -34232 -34233 -34234 -34235 -34236 -34237 -34238 -34239 -34240 -34241 -34242 -34243 -34244 -34245 -34246 -34247 -34248 -34249 -34250 -34251 -34252 -34253 -34254 -34255 -34256 -34257 -34258 -34259 -34260 -34261 -34262 -34263 -34264 -34265 -34266 -34267 -34268 -34269 -34270 -34271 -34272 -34273 -34274 -34275 -34276 -34277 -34278 -34279 -34280 -34281 -34282 -34283 -34284 -34285 -34286 -34287 -34288 -34289 -34290 -34291 -34292 -34293 -34294 -34295 -34296 -34297 -34298 -34299 -34300 -34301 -34302 -34303 -34304 -34305 -34306 -34307 -34308 -34309 -34310 -34311 -34312 -34313 -34314 -34315 -34316 -34317 -34318 -34319 -34320 -34321 -34322 -34323 -34324 -34325 -34326 -34327 -34328 -34329 -34330 -34331 -34332 -34333 -34334 -34335 -34336 -34337 -34338 -34339 -34340 -34341 -34342 -34343 -34344 -34345 -34346 -34347 -34348 -34349 -34350 -34351 -34352 -34353 -34354 -34355 -34356 -34357 -34358 -34359 -34360 -34361 -34362 -34363 -34364 -34365 -34366 -34367 -34368 -34369 -34370 -34371 -34372 -34373 -34374 -34375 -34376 -34377 -34378 -34379 -34380 -34381 -34382 -34383 -34384 -34385 -34386 -34387 -34388 -34389 -34390 -34391 -34392 -34393 -34394 -34395 -34396 -34397 -34398 -34399 -34400 -34401 -34402 -34403 -34404 -34405 -34406 -34407 -34408 -34409 -34410 -34411 -34412 -34413 -34414 -34415 -34416 -34417 -34418 -34419 -34420 -34421 -34422 -34423 -34424 -34425 -34426 -34427 -34428 -34429 -34430 -34431 -34432 -34433 -34434 -34435 -34436 -34437 -34438 -34439 -34440 -34441 -34442 -34443 -34444 -34445 -34446 -34447 -34448 -34449 -34450 -34451 -34452 -34453 -34454 -34455 -34456 -34457 -34458 -34459 -34460 -34461 -34462 -34463 -34464 -34465 -34466 -34467 -34468 -34469 -34470 -34471 -34472 -34473 -34474 -34475 -34476 -34477 -34478 -34479 -34480 -34481 -34482 -34483 -34484 -34485 -34486 -34487 -34488 -34489 -34490 -34491 -34492 -34493 -34494 -34495 -34496 -34497 -34498 -34499 -34500 -34501 -34502 -34503 -34504 -34505 -34506 -34507 -34508 -34509 -34510 -34511 -34512 -34513 -34514 -34515 -34516 -34517 -34518 -34519 -34520 -34521 -34522 -34523 -34524 -34525 -34526 -34527 -34528 -34529 -34530 -34531 -34532 -34533 -34534 -34535 -34536 -34537 -34538 -34539 -34540 -34541 -34542 -34543 -34544 -34545 -34546 -34547 -34548 -34549 -34550 -34551 -34552 -34553 -34554 -34555 -34556 -34557 -34558 -34559 -34560 -34561 -34562 -34563 -34564 -34565 -34566 -34567 -34568 -34569 -34570 -34571 -34572 -34573 -34574 -34575 -34576 -34577 -34578 -34579 -34580 -34581 -34582 -34583 -34584 -34585 -34586 -34587 -34588 -34589 -34590 -34591 -34592 -34593 -34594 -34595 -34596 -34597 -34598 -34599 -34600 -34601 -34602 -34603 -34604 -34605 -34606 -34607 -34608 -34609 -34610 -34611 -34612 -34613 -34614 -34615 -34616 -34617 -34618 -34619 -34620 -34621 -34622 -34623 -34624 -34625 -34626 -34627 -34628 -34629 -34630 -34631 -34632 -34633 -34634 -34635 -34636 -34637 -34638 -34639 -34640 -34641 -34642 -34643 -34644 -34645 -34646 -34647 -34648 -34649 -34650 -34651 -34652 -34653 -34654 -34655 -34656 -34657 -34658 -34659 -34660 -34661 -34662 -34663 -34664 -34665 -34666 -34667 -34668 -34669 -34670 -34671 -34672 -34673 -34674 -34675 -34676 -34677 -34678 -34679 -34680 -34681 -34682 -34683 -34684 -34685 -34686 -34687 -34688 -34689 -34690 -34691 -34692 -34693 -34694 -34695 -34696 -34697 -34698 -34699 -34700 -34701 -34702 -34703 -34704 -34705 -34706 -34707 -34708 -34709 -34710 -34711 -34712 -34713 -34714 -34715 -34716 -34717 -34718 -34719 -34720 -34721 -34722 -34723 -34724 -34725 -34726 -34727 -34728 -34729 -34730 -34731 -34732 -34733 -34734 -34735 -34736 -34737 -34738 -34739 -34740 -34741 -34742 -34743 -34744 -34745 -34746 -34747 -34748 -34749 -34750 -34751 -34752 -34753 -34754 -34755 -34756 -34757 -34758 -34759 -34760 -34761 -34762 -34763 -34764 -34765 -34766 -34767 -34768 -34769 -34770 -34771 -34772 -34773 -34774 -34775 -34776 -34777 -34778 -34779 -34780 -34781 -34782 -34783 -34784 -34785 -34786 -34787 -34788 -34789 -34790 -34791 -34792 -34793 -34794 -34795 -34796 -34797 -34798 -34799 -34800 -34801 -34802 -34803 -34804 -34805 -34806 -34807 -34808 -34809 -34810 -34811 -34812 -34813 -34814 -34815 -34816 -34817 -34818 -34819 -34820 -34821 -34822 -34823 -34824 -34825 -34826 -34827 -34828 -34829 -34830 -34831 -34832 -34833 -34834 -34835 -34836 -34837 -34838 -34839 -34840 -34841 -34842 -34843 -34844 -34845 -34846 -34847 -34848 -34849 -34850 -34851 -34852 -34853 -34854 -34855 -34856 -34857 -34858 -34859 -34860 -34861 -34862 -34863 -34864 -34865 -34866 -34867 -34868 -34869 -34870 -34871 -34872 -34873 -34874 -34875 -34876 -34877 -34878 -34879 -34880 -34881 -34882 -34883 -34884 -34885 -34886 -34887 -34888 -34889 -34890 -34891 -34892 -34893 -34894 -34895 -34896 -34897 -34898 -34899 -34900 -34901 -34902 -34903 -34904 -34905 -34906 -34907 -34908 -34909 -34910 -34911 -34912 -34913 -34914 -34915 -34916 -34917 -34918 -34919 -34920 -34921 -34922 -34923 -34924 -34925 -34926 -34927 -34928 -34929 -34930 -34931 -34932 -34933 -34934 -34935 -34936 -34937 -34938 -34939 -34940 -34941 -34942 -34943 -34944 -34945 -34946 -34947 -34948 -34949 -34950 -34951 -34952 -34953 -34954 -34955 -34956 -34957 -34958 -34959 -34960 -34961 -34962 -34963 -34964 -34965 -34966 -34967 -34968 -34969 -34970 -34971 -34972 -34973 -34974 -34975 -34976 -34977 -34978 -34979 -34980 -34981 -34982 -34983 -34984 -34985 -34986 -34987 -34988 -34989 -34990 -34991 -34992 -34993 -34994 -34995 -34996 -34997 -34998 -34999 -35000 -35001 -35002 -35003 -35004 -35005 -35006 -35007 -35008 -35009 -35010 -35011 -35012 -35013 -35014 -35015 -35016 -35017 -35018 -35019 -35020 -35021 -35022 -35023 -35024 -35025 -35026 -35027 -35028 -35029 -35030 -35031 -35032 -35033 -35034 -35035 -35036 -35037 -35038 -35039 -35040 -35041 -35042 -35043 -35044 -35045 -35046 -35047 -35048 -35049 -35050 -35051 -35052 -35053 -35054 -35055 -35056 -35057 -35058 -35059 -35060 -35061 -35062 -35063 -35064 -35065 -35066 -35067 -35068 -35069 -35070 -35071 -35072 -35073 -35074 -35075 -35076 -35077 -35078 -35079 -35080 -35081 -35082 -35083 -35084 -35085 -35086 -35087 -35088 -35089 -35090 -35091 -35092 -35093 -35094 -35095 -35096 -35097 -35098 -35099 -35100 -35101 -35102 -35103 -35104 -35105 -35106 -35107 -35108 -35109 -35110 -35111 -35112 -35113 -35114 -35115 -35116 -35117 -35118 -35119 -35120 -35121 -35122 -35123 -35124 -35125 -35126 -35127 -35128 -35129 -35130 -35131 -35132 -35133 -35134 -35135 -35136 -35137 -35138 -35139 -35140 -35141 -35142 -35143 -35144 -35145 -35146 -35147 -35148 -35149 -35150 -35151 -35152 -35153 -35154 -35155 -35156 -35157 -35158 -35159 -35160 -35161 -35162 -35163 -35164 -35165 -35166 -35167 -35168 -35169 -35170 -35171 -35172 -35173 -35174 -35175 -35176 -35177 -35178 -35179 -35180 -35181 -35182 -35183 -35184 -35185 -35186 -35187 -35188 -35189 -35190 -35191 -35192 -35193 -35194 -35195 -35196 -35197 -35198 -35199 -35200 -35201 -35202 -35203 -35204 -35205 -35206 -35207 -35208 -35209 -35210 -35211 -35212 -35213 -35214 -35215 -35216 -35217 -35218 -35219 -35220 -35221 -35222 -35223 -35224 -35225 -35226 -35227 -35228 -35229 -35230 -35231 -35232 -35233 -35234 -35235 -35236 -35237 -35238 -35239 -35240 -35241 -35242 -35243 -35244 -35245 -35246 -35247 -35248 -35249 -35250 -35251 -35252 -35253 -35254 -35255 -35256 -35257 -35258 -35259 -35260 -35261 -35262 -35263 -35264 -35265 -35266 -35267 -35268 -35269 -35270 -35271 -35272 -35273 -35274 -35275 -35276 -35277 -35278 -35279 -35280 -35281 -35282 -35283 -35284 -35285 -35286 -35287 -35288 -35289 -35290 -35291 -35292 -35293 -35294 -35295 -35296 -35297 -35298 -35299 -35300 -35301 -35302 -35303 -35304 -35305 -35306 -35307 -35308 -35309 -35310 -35311 -35312 -35313 -35314 -35315 -35316 -35317 -35318 -35319 -35320 -35321 -35322 -35323 -35324 -35325 -35326 -35327 -35328 -35329 -35330 -35331 -35332 -35333 -35334 -35335 -35336 -35337 -35338 -35339 -35340 -35341 -35342 -35343 -35344 -35345 -35346 -35347 -35348 -35349 -35350 -35351 -35352 -35353 -35354 -35355 -35356 -35357 -35358 -35359 -35360 -35361 -35362 -35363 -35364 -35365 -35366 -35367 -35368 -35369 -35370 -35371 -35372 -35373 -35374 -35375 -35376 -35377 -35378 -35379 -35380 -35381 -35382 -35383 -35384 -35385 -35386 -35387 -35388 -35389 -35390 -35391 -35392 -35393 -35394 -35395 -35396 -35397 -35398 -35399 -35400 -35401 -35402 -35403 -35404 -35405 -35406 -35407 -35408 -35409 -35410 -35411 -35412 -35413 -35414 -35415 -35416 -35417 -35418 -35419 -35420 -35421 -35422 -35423 -35424 -35425 -35426 -35427 -35428 -35429 -35430 -35431 -35432 -35433 -35434 -35435 -35436 -35437 -35438 -35439 -35440 -35441 -35442 -35443 -35444 -35445 -35446 -35447 -35448 -35449 -35450 -35451 -35452 -35453 -35454 -35455 -35456 -35457 -35458 -35459 -35460 -35461 -35462 -35463 -35464 -35465 -35466 -35467 -35468 -35469 -35470 -35471 -35472 -35473 -35474 -35475 -35476 -35477 -35478 -35479 -35480 -35481 -35482 -35483 -35484 -35485 -35486 -35487 -35488 -35489 -35490 -35491 -35492 -35493 -35494 -35495 -35496 -35497 -35498 -35499 -35500 -35501 -35502 -35503 -35504 -35505 -35506 -35507 -35508 -35509 -35510 -35511 -35512 -35513 -35514 -35515 -35516 -35517 -35518 -35519 -35520 -35521 -35522 -35523 -35524 -35525 -35526 -35527 -35528 -35529 -35530 -35531 -35532 -35533 -35534 -35535 -35536 -35537 -35538 -35539 -35540 -35541 -35542 -35543 -35544 -35545 -35546 -35547 -35548 -35549 -35550 -35551 -35552 -35553 -35554 -35555 -35556 -35557 -35558 -35559 -35560 -35561 -35562 -35563 -35564 -35565 -35566 -35567 -35568 -35569 -35570 -35571 -35572 -35573 -35574 -35575 -35576 -35577 -35578 -35579 -35580 -35581 -35582 -35583 -35584 -35585 -35586 -35587 -35588 -35589 -35590 -35591 -35592 -35593 -35594 -35595 -35596 -35597 -35598 -35599 -35600 -35601 -35602 -35603 -35604 -35605 -35606 -35607 -35608 -35609 -35610 -35611 -35612 -35613 -35614 -35615 -35616 -35617 -35618 -35619 -35620 -35621 -35622 -35623 -35624 -35625 -35626 -35627 -35628 -35629 -35630 -35631 -35632 -35633 -35634 -35635 -35636 -35637 -35638 -35639 -35640 -35641 -35642 -35643 -35644 -35645 -35646 -35647 -35648 -35649 -35650 -35651 -35652 -35653 -35654 -35655 -35656 -35657 -35658 -35659 -35660 -35661 -35662 -35663 -35664 -35665 -35666 -35667 -35668 -35669 -35670 -35671 -35672 -35673 -35674 -35675 -35676 -35677 -35678 -35679 -35680 -35681 -35682 -35683 -35684 -35685 -35686 -35687 -35688 -35689 -35690 -35691 -35692 -35693 -35694 -35695 -35696 -35697 -35698 -35699 -35700 -35701 -35702 -35703 -35704 -35705 -35706 -35707 -35708 -35709 -35710 -35711 -35712 -35713 -35714 -35715 -35716 -35717 -35718 -35719 -35720 -35721 -35722 -35723 -35724 -35725 -35726 -35727 -35728 -35729 -35730 -35731 -35732 -35733 -35734 -35735 -35736 -35737 -35738 -35739 -35740 -35741 -35742 -35743 -35744 -35745 -35746 -35747 -35748 -35749 -35750 -35751 -35752 -35753 -35754 -35755 -35756 -35757 -35758 -35759 -35760 -35761 -35762 -35763 -35764 -35765 -35766 -35767 -35768 -35769 -35770 -35771 -35772 -35773 -35774 -35775 -35776 -35777 -35778 -35779 -35780 -35781 -35782 -35783 -35784 -35785 -35786 -35787 -35788 -35789 -35790 -35791 -35792 -35793 -35794 -35795 -35796 -35797 -35798 -35799 -35800 -35801 -35802 -35803 -35804 -35805 -35806 -35807 -35808 -35809 -35810 -35811 -35812 -35813 -35814 -35815 -35816 -35817 -35818 -35819 -35820 -35821 -35822 -35823 -35824 -35825 -35826 -35827 -35828 -35829 -35830 -35831 -35832 -35833 -35834 -35835 -35836 -35837 -35838 -35839 -35840 -35841 -35842 -35843 -35844 -35845 -35846 -35847 -35848 -35849 -35850 -35851 -35852 -35853 -35854 -35855 -35856 -35857 -35858 -35859 -35860 -35861 -35862 -35863 -35864 -35865 -35866 -35867 -35868 -35869 -35870 -35871 -35872 -35873 -35874 -35875 -35876 -35877 -35878 -35879 -35880 -35881 -35882 -35883 -35884 -35885 -35886 -35887 -35888 -35889 -35890 -35891 -35892 -35893 -35894 -35895 -35896 -35897 -35898 -35899 -35900 -35901 -35902 -35903 -35904 -35905 -35906 -35907 -35908 -35909 -35910 -35911 -35912 -35913 -35914 -35915 -35916 -35917 -35918 -35919 -35920 -35921 -35922 -35923 -35924 -35925 -35926 -35927 -35928 -35929 -35930 -35931 -35932 -35933 -35934 -35935 -35936 -35937 -35938 -35939 -35940 -35941 -35942 -35943 -35944 -35945 -35946 -35947 -35948 -35949 -35950 -35951 -35952 -35953 -35954 -35955 -35956 -35957 -35958 -35959 -35960 -35961 -35962 -35963 -35964 -35965 -35966 -35967 -35968 -35969 -35970 -35971 -35972 -35973 -35974 -35975 -35976 -35977 -35978 -35979 -35980 -35981 -35982 -35983 -35984 -35985 -35986 -35987 -35988 -35989 -35990 -35991 -35992 -35993 -35994 -35995 -35996 -35997 -35998 -35999 -36000 -36001 -36002 -36003 -36004 -36005 -36006 -36007 -36008 -36009 -36010 -36011 -36012 -36013 -36014 -36015 -36016 -36017 -36018 -36019 -36020 -36021 -36022 -36023 -36024 -36025 -36026 -36027 -36028 -36029 -36030 -36031 -36032 -36033 -36034 -36035 -36036 -36037 -36038 -36039 -36040 -36041 -36042 -36043 -36044 -36045 -36046 -36047 -36048 -36049 -36050 -36051 -36052 -36053 -36054 -36055 -36056 -36057 -36058 -36059 -36060 -36061 -36062 -36063 -36064 -36065 -36066 -36067 -36068 -36069 -36070 -36071 -36072 -36073 -36074 -36075 -36076 -36077 -36078 -36079 -36080 -36081 -36082 -36083 -36084 -36085 -36086 -36087 -36088 -36089 -36090 -36091 -36092 -36093 -36094 -36095 -36096 -36097 -36098 -36099 -36100 -36101 -36102 -36103 -36104 -36105 -36106 -36107 -36108 -36109 -36110 -36111 -36112 -36113 -36114 -36115 -36116 -36117 -36118 -36119 -36120 -36121 -36122 -36123 -36124 -36125 -36126 -36127 -36128 -36129 -36130 -36131 -36132 -36133 -36134 -36135 -36136 -36137 -36138 -36139 -36140 -36141 -36142 -36143 -36144 -36145 -36146 -36147 -36148 -36149 -36150 -36151 -36152 -36153 -36154 -36155 -36156 -36157 -36158 -36159 -36160 -36161 -36162 -36163 -36164 -36165 -36166 -36167 -36168 -36169 -36170 -36171 -36172 -36173 -36174 -36175 -36176 -36177 -36178 -36179 -36180 -36181 -36182 -36183 -36184 -36185 -36186 -36187 -36188 -36189 -36190 -36191 -36192 -36193 -36194 -36195 -36196 -36197 -36198 -36199 -36200 -36201 -36202 -36203 -36204 -36205 -36206 -36207 -36208 -36209 -36210 -36211 -36212 -36213 -36214 -36215 -36216 -36217 -36218 -36219 -36220 -36221 -36222 -36223 -36224 -36225 -36226 -36227 -36228 -36229 -36230 -36231 -36232 -36233 -36234 -36235 -36236 -36237 -36238 -36239 -36240 -36241 -36242 -36243 -36244 -36245 -36246 -36247 -36248 -36249 -36250 -36251 -36252 -36253 -36254 -36255 -36256 -36257 -36258 -36259 -36260 -36261 -36262 -36263 -36264 -36265 -36266 -36267 -36268 -36269 -36270 -36271 -36272 -36273 -36274 -36275 -36276 -36277 -36278 -36279 -36280 -36281 -36282 -36283 -36284 -36285 -36286 -36287 -36288 -36289 -36290 -36291 -36292 -36293 -36294 -36295 -36296 -36297 -36298 -36299 -36300 -36301 -36302 -36303 -36304 -36305 -36306 -36307 -36308 -36309 -36310 -36311 -36312 -36313 -36314 -36315 -36316 -36317 -36318 -36319 -36320 -36321 -36322 -36323 -36324 -36325 -36326 -36327 -36328 -36329 -36330 -36331 -36332 -36333 -36334 -36335 -36336 -36337 -36338 -36339 -36340 -36341 -36342 -36343 -36344 -36345 -36346 -36347 -36348 -36349 -36350 -36351 -36352 -36353 -36354 -36355 -36356 -36357 -36358 -36359 -36360 -36361 -36362 -36363 -36364 -36365 -36366 -36367 -36368 -36369 -36370 -36371 -36372 -36373 -36374 -36375 -36376 -36377 -36378 -36379 -36380 -36381 -36382 -36383 -36384 -36385 -36386 -36387 -36388 -36389 -36390 -36391 -36392 -36393 -36394 -36395 -36396 -36397 -36398 -36399 -36400 -36401 -36402 -36403 -36404 -36405 -36406 -36407 -36408 -36409 -36410 -36411 -36412 -36413 -36414 -36415 -36416 -36417 -36418 -36419 -36420 -36421 -36422 -36423 -36424 -36425 -36426 -36427 -36428 -36429 -36430 -36431 -36432 -36433 -36434 -36435 -36436 -36437 -36438 -36439 -36440 -36441 -36442 -36443 -36444 -36445 -36446 -36447 -36448 -36449 -36450 -36451 -36452 -36453 -36454 -36455 -36456 -36457 -36458 -36459 -36460 -36461 -36462 -36463 -36464 -36465 -36466 -36467 -36468 -36469 -36470 -36471 -36472 -36473 -36474 -36475 -36476 -36477 -36478 -36479 -36480 -36481 -36482 -36483 -36484 -36485 -36486 -36487 -36488 -36489 -36490 -36491 -36492 -36493 -36494 -36495 -36496 -36497 -36498 -36499 -36500 -36501 -36502 -36503 -36504 -36505 -36506 -36507 -36508 -36509 -36510 -36511 -36512 -36513 -36514 -36515 -36516 -36517 -36518 -36519 -36520 -36521 -36522 -36523 -36524 -36525 -36526 -36527 -36528 -36529 -36530 -36531 -36532 -36533 -36534 -36535 -36536 -36537 -36538 -36539 -36540 -36541 -36542 -36543 -36544 -36545 -36546 -36547 -36548 -36549 -36550 -36551 -36552 -36553 -36554 -36555 -36556 -36557 -36558 -36559 -36560 -36561 -36562 -36563 -36564 -36565 -36566 -36567 -36568 -36569 -36570 -36571 -36572 -36573 -36574 -36575 -36576 -36577 -36578 -36579 -36580 -36581 -36582 -36583 -36584 -36585 -36586 -36587 -36588 -36589 -36590 -36591 -36592 -36593 -36594 -36595 -36596 -36597 -36598 -36599 -36600 -36601 -36602 -36603 -36604 -36605 -36606 -36607 -36608 -36609 -36610 -36611 -36612 -36613 -36614 -36615 -36616 -36617 -36618 -36619 -36620 -36621 -36622 -36623 -36624 -36625 -36626 -36627 -36628 -36629 -36630 -36631 -36632 -36633 -36634 -36635 -36636 -36637 -36638 -36639 -36640 -36641 -36642 -36643 -36644 -36645 -36646 -36647 -36648 -36649 -36650 -36651 -36652 -36653 -36654 -36655 -36656 -36657 -36658 -36659 -36660 -36661 -36662 -36663 -36664 -36665 -36666 -36667 -36668 -36669 -36670 -36671 -36672 -36673 -36674 -36675 -36676 -36677 -36678 -36679 -36680 -36681 -36682 -36683 -36684 -36685 -36686 -36687 -36688 -36689 -36690 -36691 -36692 -36693 -36694 -36695 -36696 -36697 -36698 -36699 -36700 -36701 -36702 -36703 -36704 -36705 -36706 -36707 -36708 -36709 -36710 -36711 -36712 -36713 -36714 -36715 -36716 -36717 -36718 -36719 -36720 -36721 -36722 -36723 -36724 -36725 -36726 -36727 -36728 -36729 -36730 -36731 -36732 -36733 -36734 -36735 -36736 -36737 -36738 -36739 -36740 -36741 -36742 -36743 -36744 -36745 -36746 -36747 -36748 -36749 -36750 -36751 -36752 -36753 -36754 -36755 -36756 -36757 -36758 -36759 -36760 -36761 -36762 -36763 -36764 -36765 -36766 -36767 -36768 -36769 -36770 -36771 -36772 -36773 -36774 -36775 -36776 -36777 -36778 -36779 -36780 -36781 -36782 -36783 -36784 -36785 -36786 -36787 -36788 -36789 -36790 -36791 -36792 -36793 -36794 -36795 -36796 -36797 -36798 -36799 -36800 -36801 -36802 -36803 -36804 -36805 -36806 -36807 -36808 -36809 -36810 -36811 -36812 -36813 -36814 -36815 -36816 -36817 -36818 -36819 -36820 -36821 -36822 -36823 -36824 -36825 -36826 -36827 -36828 -36829 -36830 -36831 -36832 -36833 -36834 -36835 -36836 -36837 -36838 -36839 -36840 -36841 -36842 -36843 -36844 -36845 -36846 -36847 -36848 -36849 -36850 -36851 -36852 -36853 -36854 -36855 -36856 -36857 -36858 -36859 -36860 -36861 -36862 -36863 -36864 -36865 -36866 -36867 -36868 -36869 -36870 -36871 -36872 -36873 -36874 -36875 -36876 -36877 -36878 -36879 -36880 -36881 -36882 -36883 -36884 -36885 -36886 -36887 -36888 -36889 -36890 -36891 -36892 -36893 -36894 -36895 -36896 -36897 -36898 -36899 -36900 -36901 -36902 -36903 -36904 -36905 -36906 -36907 -36908 -36909 -36910 -36911 -36912 -36913 -36914 -36915 -36916 -36917 -36918 -36919 -36920 -36921 -36922 -36923 -36924 -36925 -36926 -36927 -36928 -36929 -36930 -36931 -36932 -36933 -36934 -36935 -36936 -36937 -36938 -36939 -36940 -36941 -36942 -36943 -36944 -36945 -36946 -36947 -36948 -36949 -36950 -36951 -36952 -36953 -36954 -36955 -36956 -36957 -36958 -36959 -36960 -36961 -36962 -36963 -36964 -36965 -36966 -36967 -36968 -36969 -36970 -36971 -36972 -36973 -36974 -36975 -36976 -36977 -36978 -36979 -36980 -36981 -36982 -36983 -36984 -36985 -36986 -36987 -36988 -36989 -36990 -36991 -36992 -36993 -36994 -36995 -36996 -36997 -36998 -36999 -37000 -37001 -37002 -37003 -37004 -37005 -37006 -37007 -37008 -37009 -37010 -37011 -37012 -37013 -37014 -37015 -37016 -37017 -37018 -37019 -37020 -37021 -37022 -37023 -37024 -37025 -37026 -37027 -37028 -37029 -37030 -37031 -37032 -37033 -37034 -37035 -37036 -37037 -37038 -37039 -37040 -37041 -37042 -37043 -37044 -37045 -37046 -37047 -37048 -37049 -37050 -37051 -37052 -37053 -37054 -37055 -37056 -37057 -37058 -37059 -37060 -37061 -37062 -37063 -37064 -37065 -37066 -37067 -37068 -37069 -37070 -37071 -37072 -37073 -37074 -37075 -37076 -37077 -37078 -37079 -37080 -37081 -37082 -37083 -37084 -37085 -37086 -37087 -37088 -37089 -37090 -37091 -37092 -37093 -37094 -37095 -37096 -37097 -37098 -37099 -37100 -37101 -37102 -37103 -37104 -37105 -37106 -37107 -37108 -37109 -37110 -37111 -37112 -37113 -37114 -37115 -37116 -37117 -37118 -37119 -37120 -37121 -37122 -37123 -37124 -37125 -37126 -37127 -37128 -37129 -37130 -37131 -37132 -37133 -37134 -37135 -37136 -37137 -37138 -37139 -37140 -37141 -37142 -37143 -37144 -37145 -37146 -37147 -37148 -37149 -37150 -37151 -37152 -37153 -37154 -37155 -37156 -37157 -37158 -37159 -37160 -37161 -37162 -37163 -37164 -37165 -37166 -37167 -37168 -37169 -37170 -37171 -37172 -37173 -37174 -37175 -37176 -37177 -37178 -37179 -37180 -37181 -37182 -37183 -37184 -37185 -37186 -37187 -37188 -37189 -37190 -37191 -37192 -37193 -37194 -37195 -37196 -37197 -37198 -37199 -37200 -37201 -37202 -37203 -37204 -37205 -37206 -37207 -37208 -37209 -37210 -37211 -37212 -37213 -37214 -37215 -37216 -37217 -37218 -37219 -37220 -37221 -37222 -37223 -37224 -37225 -37226 -37227 -37228 -37229 -37230 -37231 -37232 -37233 -37234 -37235 -37236 -37237 -37238 -37239 -37240 -37241 -37242 -37243 -37244 -37245 -37246 -37247 -37248 -37249 -37250 -37251 -37252 -37253 -37254 -37255 -37256 -37257 -37258 -37259 -37260 -37261 -37262 -37263 -37264 -37265 -37266 -37267 -37268 -37269 -37270 -37271 -37272 -37273 -37274 -37275 -37276 -37277 -37278 -37279 -37280 -37281 -37282 -37283 -37284 -37285 -37286 -37287 -37288 -37289 -37290 -37291 -37292 -37293 -37294 -37295 -37296 -37297 -37298 -37299 -37300 -37301 -37302 -37303 -37304 -37305 -37306 -37307 -37308 -37309 -37310 -37311 -37312 -37313 -37314 -37315 -37316 -37317 -37318 -37319 -37320 -37321 -37322 -37323 -37324 -37325 -37326 -37327 -37328 -37329 -37330 -37331 -37332 -37333 -37334 -37335 -37336 -37337 -37338 -37339 -37340 -37341 -37342 -37343 -37344 -37345 -37346 -37347 -37348 -37349 -37350 -37351 -37352 -37353 -37354 -37355 -37356 -37357 -37358 -37359 -37360 -37361 -37362 -37363 -37364 -37365 -37366 -37367 -37368 -37369 -37370 -37371 -37372 -37373 -37374 -37375 -37376 -37377 -37378 -37379 -37380 -37381 -37382 -37383 -37384 -37385 -37386 -37387 -37388 -37389 -37390 -37391 -37392 -37393 -37394 -37395 -37396 -37397 -37398 -37399 -37400 -37401 -37402 -37403 -37404 -37405 -37406 -37407 -37408 -37409 -37410 -37411 -37412 -37413 -37414 -37415 -37416 -37417 -37418 -37419 -37420 -37421 -37422 -37423 -37424 -37425 -37426 -37427 -37428 -37429 -37430 -37431 -37432 -37433 -37434 -37435 -37436 -37437 -37438 -37439 -37440 -37441 -37442 -37443 -37444 -37445 -37446 -37447 -37448 -37449 -37450 -37451 -37452 -37453 -37454 -37455 -37456 -37457 -37458 -37459 -37460 -37461 -37462 -37463 -37464 -37465 -37466 -37467 -37468 -37469 -37470 -37471 -37472 -37473 -37474 -37475 -37476 -37477 -37478 -37479 -37480 -37481 -37482 -37483 -37484 -37485 -37486 -37487 -37488 -37489 -37490 -37491 -37492 -37493 -37494 -37495 -37496 -37497 -37498 -37499 -37500 -37501 -37502 -37503 -37504 -37505 -37506 -37507 -37508 -37509 -37510 -37511 -37512 -37513 -37514 -37515 -37516 -37517 -37518 -37519 -37520 -37521 -37522 -37523 -37524 -37525 -37526 -37527 -37528 -37529 -37530 -37531 -37532 -37533 -37534 -37535 -37536 -37537 -37538 -37539 -37540 -37541 -37542 -37543 -37544 -37545 -37546 -37547 -37548 -37549 -37550 -37551 -37552 -37553 -37554 -37555 -37556 -37557 -37558 -37559 -37560 -37561 -37562 -37563 -37564 -37565 -37566 -37567 -37568 -37569 -37570 -37571 -37572 -37573 -37574 -37575 -37576 -37577 -37578 -37579 -37580 -37581 -37582 -37583 -37584 -37585 -37586 -37587 -37588 -37589 -37590 -37591 -37592 -37593 -37594 -37595 -37596 -37597 -37598 -37599 -37600 -37601 -37602 -37603 -37604 -37605 -37606 -37607 -37608 -37609 -37610 -37611 -37612 -37613 -37614 -37615 -37616 -37617 -37618 -37619 -37620 -37621 -37622 -37623 -37624 -37625 -37626 -37627 -37628 -37629 -37630 -37631 -37632 -37633 -37634 -37635 -37636 -37637 -37638 -37639 -37640 -37641 -37642 -37643 -37644 -37645 -37646 -37647 -37648 -37649 -37650 -37651 -37652 -37653 -37654 -37655 -37656 -37657 -37658 -37659 -37660 -37661 -37662 -37663 -37664 -37665 -37666 -37667 -37668 -37669 -37670 -37671 -37672 -37673 -37674 -37675 -37676 -37677 -37678 -37679 -37680 -37681 -37682 -37683 -37684 -37685 -37686 -37687 -37688 -37689 -37690 -37691 -37692 -37693 -37694 -37695 -37696 -37697 -37698 -37699 -37700 -37701 -37702 -37703 -37704 -37705 -37706 -37707 -37708 -37709 -37710 -37711 -37712 -37713 -37714 -37715 -37716 -37717 -37718 -37719 -37720 -37721 -37722 -37723 -37724 -37725 -37726 -37727 -37728 -37729 -37730 -37731 -37732 -37733 -37734 -37735 -37736 -37737 -37738 -37739 -37740 -37741 -37742 -37743 -37744 -37745 -37746 -37747 -37748 -37749 -37750 -37751 -37752 -37753 -37754 -37755 -37756 -37757 -37758 -37759 -37760 -37761 -37762 -37763 -37764 -37765 -37766 -37767 -37768 -37769 -37770 -37771 -37772 -37773 -37774 -37775 -37776 -37777 -37778 -37779 -37780 -37781 -37782 -37783 -37784 -37785 -37786 -37787 -37788 -37789 -37790 -37791 -37792 -37793 -37794 -37795 -37796 -37797 -37798 -37799 -37800 -37801 -37802 -37803 -37804 -37805 -37806 -37807 -37808 -37809 -37810 -37811 -37812 -37813 -37814 -37815 -37816 -37817 -37818 -37819 -37820 -37821 -37822 -37823 -37824 -37825 -37826 -37827 -37828 -37829 -37830 -37831 -37832 -37833 -37834 -37835 -37836 -37837 -37838 -37839 -37840 -37841 -37842 -37843 -37844 -37845 -37846 -37847 -37848 -37849 -37850 -37851 -37852 -37853 -37854 -37855 -37856 -37857 -37858 -37859 -37860 -37861 -37862 -37863 -37864 -37865 -37866 -37867 -37868 -37869 -37870 -37871 -37872 -37873 -37874 -37875 -37876 -37877 -37878 -37879 -37880 -37881 -37882 -37883 -37884 -37885 -37886 -37887 -37888 -37889 -37890 -37891 -37892 -37893 -37894 -37895 -37896 -37897 -37898 -37899 -37900 -37901 -37902 -37903 -37904 -37905 -37906 -37907 -37908 -37909 -37910 -37911 -37912 -37913 -37914 -37915 -37916 -37917 -37918 -37919 -37920 -37921 -37922 -37923 -37924 -37925 -37926 -37927 -37928 -37929 -37930 -37931 -37932 -37933 -37934 -37935 -37936 -37937 -37938 -37939 -37940 -37941 -37942 -37943 -37944 -37945 -37946 -37947 -37948 -37949 -37950 -37951 -37952 -37953 -37954 -37955 -37956 -37957 -37958 -37959 -37960 -37961 -37962 -37963 -37964 -37965 -37966 -37967 -37968 -37969 -37970 -37971 -37972 -37973 -37974 -37975 -37976 -37977 -37978 -37979 -37980 -37981 -37982 -37983 -37984 -37985 -37986 -37987 -37988 -37989 -37990 -37991 -37992 -37993 -37994 -37995 -37996 -37997 -37998 -37999 -38000 -38001 -38002 -38003 -38004 -38005 -38006 -38007 -38008 -38009 -38010 -38011 -38012 -38013 -38014 -38015 -38016 -38017 -38018 -38019 -38020 -38021 -38022 -38023 -38024 -38025 -38026 -38027 -38028 -38029 -38030 -38031 -38032 -38033 -38034 -38035 -38036 -38037 -38038 -38039 -38040 -38041 -38042 -38043 -38044 -38045 -38046 -38047 -38048 -38049 -38050 -38051 -38052 -38053 -38054 -38055 -38056 -38057 -38058 -38059 -38060 -38061 -38062 -38063 -38064 -38065 -38066 -38067 -38068 -38069 -38070 -38071 -38072 -38073 -38074 -38075 -38076 -38077 -38078 -38079 -38080 -38081 -38082 -38083 -38084 -38085 -38086 -38087 -38088 -38089 -38090 -38091 -38092 -38093 -38094 -38095 -38096 -38097 -38098 -38099 -38100 -38101 -38102 -38103 -38104 -38105 -38106 -38107 -38108 -38109 -38110 -38111 -38112 -38113 -38114 -38115 -38116 -38117 -38118 -38119 -38120 -38121 -38122 -38123 -38124 -38125 -38126 -38127 -38128 -38129 -38130 -38131 -38132 -38133 -38134 -38135 -38136 -38137 -38138 -38139 -38140 -38141 -38142 -38143 -38144 -38145 -38146 -38147 -38148 -38149 -38150 -38151 -38152 -38153 -38154 -38155 -38156 -38157 -38158 -38159 -38160 -38161 -38162 -38163 -38164 -38165 -38166 -38167 -38168 -38169 -38170 -38171 -38172 -38173 -38174 -38175 -38176 -38177 -38178 -38179 -38180 -38181 -38182 -38183 -38184 -38185 -38186 -38187 -38188 -38189 -38190 -38191 -38192 -38193 -38194 -38195 -38196 -38197 -38198 -38199 -38200 -38201 -38202 -38203 -38204 -38205 -38206 -38207 -38208 -38209 -38210 -38211 -38212 -38213 -38214 -38215 -38216 -38217 -38218 -38219 -38220 -38221 -38222 -38223 -38224 -38225 -38226 -38227 -38228 -38229 -38230 -38231 -38232 -38233 -38234 -38235 -38236 -38237 -38238 -38239 -38240 -38241 -38242 -38243 -38244 -38245 -38246 -38247 -38248 -38249 -38250 -38251 -38252 -38253 -38254 -38255 -38256 -38257 -38258 -38259 -38260 -38261 -38262 -38263 -38264 -38265 -38266 -38267 -38268 -38269 -38270 -38271 -38272 -38273 -38274 -38275 -38276 -38277 -38278 -38279 -38280 -38281 -38282 -38283 -38284 -38285 -38286 -38287 -38288 -38289 -38290 -38291 -38292 -38293 -38294 -38295 -38296 -38297 -38298 -38299 -38300 -38301 -38302 -38303 -38304 -38305 -38306 -38307 -38308 -38309 -38310 -38311 -38312 -38313 -38314 -38315 -38316 -38317 -38318 -38319 -38320 -38321 -38322 -38323 -38324 -38325 -38326 -38327 -38328 -38329 -38330 -38331 -38332 -38333 -38334 -38335 -38336 -38337 -38338 -38339 -38340 -38341 -38342 -38343 -38344 -38345 -38346 -38347 -38348 -38349 -38350 -38351 -38352 -38353 -38354 -38355 -38356 -38357 -38358 -38359 -38360 -38361 -38362 -38363 -38364 -38365 -38366 -38367 -38368 -38369 -38370 -38371 -38372 -38373 -38374 -38375 -38376 -38377 -38378 -38379 -38380 -38381 -38382 -38383 -38384 -38385 -38386 -38387 -38388 -38389 -38390 -38391 -38392 -38393 -38394 -38395 -38396 -38397 -38398 -38399 -38400 -38401 -38402 -38403 -38404 -38405 -38406 -38407 -38408 -38409 -38410 -38411 -38412 -38413 -38414 -38415 -38416 -38417 -38418 -38419 -38420 -38421 -38422 -38423 -38424 -38425 -38426 -38427 -38428 -38429 -38430 -38431 -38432 -38433 -38434 -38435 -38436 -38437 -38438 -38439 -38440 -38441 -38442 -38443 -38444 -38445 -38446 -38447 -38448 -38449 -38450 -38451 -38452 -38453 -38454 -38455 -38456 -38457 -38458 -38459 -38460 -38461 -38462 -38463 -38464 -38465 -38466 -38467 -38468 -38469 -38470 -38471 -38472 -38473 -38474 -38475 -38476 -38477 -38478 -38479 -38480 -38481 -38482 -38483 -38484 -38485 -38486 -38487 -38488 -38489 -38490 -38491 -38492 -38493 -38494 -38495 -38496 -38497 -38498 -38499 -38500 -38501 -38502 -38503 -38504 -38505 -38506 -38507 -38508 -38509 -38510 -38511 -38512 -38513 -38514 -38515 -38516 -38517 -38518 -38519 -38520 -38521 -38522 -38523 -38524 -38525 -38526 -38527 -38528 -38529 -38530 -38531 -38532 -38533 -38534 -38535 -38536 -38537 -38538 -38539 -38540 -38541 -38542 -38543 -38544 -38545 -38546 -38547 -38548 -38549 -38550 -38551 -38552 -38553 -38554 -38555 -38556 -38557 -38558 -38559 -38560 -38561 -38562 -38563 -38564 -38565 -38566 -38567 -38568 -38569 -38570 -38571 -38572 -38573 -38574 -38575 -38576 -38577 -38578 -38579 -38580 -38581 -38582 -38583 -38584 -38585 -38586 -38587 -38588 -38589 -38590 -38591 -38592 -38593 -38594 -38595 -38596 -38597 -38598 -38599 -38600 -38601 -38602 -38603 -38604 -38605 -38606 -38607 -38608 -38609 -38610 -38611 -38612 -38613 -38614 -38615 -38616 -38617 -38618 -38619 -38620 -38621 -38622 -38623 -38624 -38625 -38626 -38627 -38628 -38629 -38630 -38631 -38632 -38633 -38634 -38635 -38636 -38637 -38638 -38639 -38640 -38641 -38642 -38643 -38644 -38645 -38646 -38647 -38648 -38649 -38650 -38651 -38652 -38653 -38654 -38655 -38656 -38657 -38658 -38659 -38660 -38661 -38662 -38663 -38664 -38665 -38666 -38667 -38668 -38669 -38670 -38671 -38672 -38673 -38674 -38675 -38676 -38677 -38678 -38679 -38680 -38681 -38682 -38683 -38684 -38685 -38686 -38687 -38688 -38689 -38690 -38691 -38692 -38693 -38694 -38695 -38696 -38697 -38698 -38699 -38700 -38701 -38702 -38703 -38704 -38705 -38706 -38707 -38708 -38709 -38710 -38711 -38712 -38713 -38714 -38715 -38716 -38717 -38718 -38719 -38720 -38721 -38722 -38723 -38724 -38725 -38726 -38727 -38728 -38729 -38730 -38731 -38732 -38733 -38734 -38735 -38736 -38737 -38738 -38739 -38740 -38741 -38742 -38743 -38744 -38745 -38746 -38747 -38748 -38749 -38750 -38751 -38752 -38753 -38754 -38755 -38756 -38757 -38758 -38759 -38760 -38761 -38762 -38763 -38764 -38765 -38766 -38767 -38768 -38769 -38770 -38771 -38772 -38773 -38774 -38775 -38776 -38777 -38778 -38779 -38780 -38781 -38782 -38783 -38784 -38785 -38786 -38787 -38788 -38789 -38790 -38791 -38792 -38793 -38794 -38795 -38796 -38797 -38798 -38799 -38800 -38801 -38802 -38803 -38804 -38805 -38806 -38807 -38808 -38809 -38810 -38811 -38812 -38813 -38814 -38815 -38816 -38817 -38818 -38819 -38820 -38821 -38822 -38823 -38824 -38825 -38826 -38827 -38828 -38829 -38830 -38831 -38832 -38833 -38834 -38835 -38836 -38837 -38838 -38839 -38840 -38841 -38842 -38843 -38844 -38845 -38846 -38847 -38848 -38849 -38850 -38851 -38852 -38853 -38854 -38855 -38856 -38857 -38858 -38859 -38860 -38861 -38862 -38863 -38864 -38865 -38866 -38867 -38868 -38869 -38870 -38871 -38872 -38873 -38874 -38875 -38876 -38877 -38878 -38879 -38880 -38881 -38882 -38883 -38884 -38885 -38886 -38887 -38888 -38889 -38890 -38891 -38892 -38893 -38894 -38895 -38896 -38897 -38898 -38899 -38900 -38901 -38902 -38903 -38904 -38905 -38906 -38907 -38908 -38909 -38910 -38911 -38912 -38913 -38914 -38915 -38916 -38917 -38918 -38919 -38920 -38921 -38922 -38923 -38924 -38925 -38926 -38927 -38928 -38929 -38930 -38931 -38932 -38933 -38934 -38935 -38936 -38937 -38938 -38939 -38940 -38941 -38942 -38943 -38944 -38945 -38946 -38947 -38948 -38949 -38950 -38951 -38952 -38953 -38954 -38955 -38956 -38957 -38958 -38959 -38960 -38961 -38962 -38963 -38964 -38965 -38966 -38967 -38968 -38969 -38970 -38971 -38972 -38973 -38974 -38975 -38976 -38977 -38978 -38979 -38980 -38981 -38982 -38983 -38984 -38985 -38986 -38987 -38988 -38989 -38990 -38991 -38992 -38993 -38994 -38995 -38996 -38997 -38998 -38999 -39000 -39001 -39002 -39003 -39004 -39005 -39006 -39007 -39008 -39009 -39010 -39011 -39012 -39013 -39014 -39015 -39016 -39017 -39018 -39019 -39020 -39021 -39022 -39023 -39024 -39025 -39026 -39027 -39028 -39029 -39030 -39031 -39032 -39033 -39034 -39035 -39036 -39037 -39038 -39039 -39040 -39041 -39042 -39043 -39044 -39045 -39046 -39047 -39048 -39049 -39050 -39051 -39052 -39053 -39054 -39055 -39056 -39057 -39058 -39059 -39060 -39061 -39062 -39063 -39064 -39065 -39066 -39067 -39068 -39069 -39070 -39071 -39072 -39073 -39074 -39075 -39076 -39077 -39078 -39079 -39080 -39081 -39082 -39083 -39084 -39085 -39086 -39087 -39088 -39089 -39090 -39091 -39092 -39093 -39094 -39095 -39096 -39097 -39098 -39099 -39100 -39101 -39102 -39103 -39104 -39105 -39106 -39107 -39108 -39109 -39110 -39111 -39112 -39113 -39114 -39115 -39116 -39117 -39118 -39119 -39120 -39121 -39122 -39123 -39124 -39125 -39126 -39127 -39128 -39129 -39130 -39131 -39132 -39133 -39134 -39135 -39136 -39137 -39138 -39139 -39140 -39141 -39142 -39143 -39144 -39145 -39146 -39147 -39148 -39149 -39150 -39151 -39152 -39153 -39154 -39155 -39156 -39157 -39158 -39159 -39160 -39161 -39162 -39163 -39164 -39165 -39166 -39167 -39168 -39169 -39170 -39171 -39172 -39173 -39174 -39175 -39176 -39177 -39178 -39179 -39180 -39181 -39182 -39183 -39184 -39185 -39186 -39187 -39188 -39189 -39190 -39191 -39192 -39193 -39194 -39195 -39196 -39197 -39198 -39199 -39200 -39201 -39202 -39203 -39204 -39205 -39206 -39207 -39208 -39209 -39210 -39211 -39212 -39213 -39214 -39215 -39216 -39217 -39218 -39219 -39220 -39221 -39222 -39223 -39224 -39225 -39226 -39227 -39228 -39229 -39230 -39231 -39232 -39233 -39234 -39235 -39236 -39237 -39238 -39239 -39240 -39241 -39242 -39243 -39244 -39245 -39246 -39247 -39248 -39249 -39250 -39251 -39252 -39253 -39254 -39255 -39256 -39257 -39258 -39259 -39260 -39261 -39262 -39263 -39264 -39265 -39266 -39267 -39268 -39269 -39270 -39271 -39272 -39273 -39274 -39275 -39276 -39277 -39278 -39279 -39280 -39281 -39282 -39283 -39284 -39285 -39286 -39287 -39288 -39289 -39290 -39291 -39292 -39293 -39294 -39295 -39296 -39297 -39298 -39299 -39300 -39301 -39302 -39303 -39304 -39305 -39306 -39307 -39308 -39309 -39310 -39311 -39312 -39313 -39314 -39315 -39316 -39317 -39318 -39319 -39320 -39321 -39322 -39323 -39324 -39325 -39326 -39327 -39328 -39329 -39330 -39331 -39332 -39333 -39334 -39335 -39336 -39337 -39338 -39339 -39340 -39341 -39342 -39343 -39344 -39345 -39346 -39347 -39348 -39349 -39350 -39351 -39352 -39353 -39354 -39355 -39356 -39357 -39358 -39359 -39360 -39361 -39362 -39363 -39364 -39365 -39366 -39367 -39368 -39369 -39370 -39371 -39372 -39373 -39374 -39375 -39376 -39377 -39378 -39379 -39380 -39381 -39382 -39383 -39384 -39385 -39386 -39387 -39388 -39389 -39390 -39391 -39392 -39393 -39394 -39395 -39396 -39397 -39398 -39399 -39400 -39401 -39402 -39403 -39404 -39405 -39406 -39407 -39408 -39409 -39410 -39411 -39412 -39413 -39414 -39415 -39416 -39417 -39418 -39419 -39420 -39421 -39422 -39423 -39424 -39425 -39426 -39427 -39428 -39429 -39430 -39431 -39432 -39433 -39434 -39435 -39436 -39437 -39438 -39439 -39440 -39441 -39442 -39443 -39444 -39445 -39446 -39447 -39448 -39449 -39450 -39451 -39452 -39453 -39454 -39455 -39456 -39457 -39458 -39459 -39460 -39461 -39462 -39463 -39464 -39465 -39466 -39467 -39468 -39469 -39470 -39471 -39472 -39473 -39474 -39475 -39476 -39477 -39478 -39479 -39480 -39481 -39482 -39483 -39484 -39485 -39486 -39487 -39488 -39489 -39490 -39491 -39492 -39493 -39494 -39495 -39496 -39497 -39498 -39499 -39500 -39501 -39502 -39503 -39504 -39505 -39506 -39507 -39508 -39509 -39510 -39511 -39512 -39513 -39514 -39515 -39516 -39517 -39518 -39519 -39520 -39521 -39522 -39523 -39524 -39525 -39526 -39527 -39528 -39529 -39530 -39531 -39532 -39533 -39534 -39535 -39536 -39537 -39538 -39539 -39540 -39541 -39542 -39543 -39544 -39545 -39546 -39547 -39548 -39549 -39550 -39551 -39552 -39553 -39554 -39555 -39556 -39557 -39558 -39559 -39560 -39561 -39562 -39563 -39564 -39565 -39566 -39567 -39568 -39569 -39570 -39571 -39572 -39573 -39574 -39575 -39576 -39577 -39578 -39579 -39580 -39581 -39582 -39583 -39584 -39585 -39586 -39587 -39588 -39589 -39590 -39591 -39592 -39593 -39594 -39595 -39596 -39597 -39598 -39599 -39600 -39601 -39602 -39603 -39604 -39605 -39606 -39607 -39608 -39609 -39610 -39611 -39612 -39613 -39614 -39615 -39616 -39617 -39618 -39619 -39620 -39621 -39622 -39623 -39624 -39625 -39626 -39627 -39628 -39629 -39630 -39631 -39632 -39633 -39634 -39635 -39636 -39637 -39638 -39639 -39640 -39641 -39642 -39643 -39644 -39645 -39646 -39647 -39648 -39649 -39650 -39651 -39652 -39653 -39654 -39655 -39656 -39657 -39658 -39659 -39660 -39661 -39662 -39663 -39664 -39665 -39666 -39667 -39668 -39669 -39670 -39671 -39672 -39673 -39674 -39675 -39676 -39677 -39678 -39679 -39680 -39681 -39682 -39683 -39684 -39685 -39686 -39687 -39688 -39689 -39690 -39691 -39692 -39693 -39694 -39695 -39696 -39697 -39698 -39699 -39700 -39701 -39702 -39703 -39704 -39705 -39706 -39707 -39708 -39709 -39710 -39711 -39712 -39713 -39714 -39715 -39716 -39717 -39718 -39719 -39720 -39721 -39722 -39723 -39724 -39725 -39726 -39727 -39728 -39729 -39730 -39731 -39732 -39733 -39734 -39735 -39736 -39737 -39738 -39739 -39740 -39741 -39742 -39743 -39744 -39745 -39746 -39747 -39748 -39749 -39750 -39751 -39752 -39753 -39754 -39755 -39756 -39757 -39758 -39759 -39760 -39761 -39762 -39763 -39764 -39765 -39766 -39767 -39768 -39769 -39770 -39771 -39772 -39773 -39774 -39775 -39776 -39777 -39778 -39779 -39780 -39781 -39782 -39783 -39784 -39785 -39786 -39787 -39788 -39789 -39790 -39791 -39792 -39793 -39794 -39795 -39796 -39797 -39798 -39799 -39800 -39801 -39802 -39803 -39804 -39805 -39806 -39807 -39808 -39809 -39810 -39811 -39812 -39813 -39814 -39815 -39816 -39817 -39818 -39819 -39820 -39821 -39822 -39823 -39824 -39825 -39826 -39827 -39828 -39829 -39830 -39831 -39832 -39833 -39834 -39835 -39836 -39837 -39838 -39839 -39840 -39841 -39842 -39843 -39844 -39845 -39846 -39847 -39848 -39849 -39850 -39851 -39852 -39853 -39854 -39855 -39856 -39857 -39858 -39859 -39860 -39861 -39862 -39863 -39864 -39865 -39866 -39867 -39868 -39869 -39870 -39871 -39872 -39873 -39874 -39875 -39876 -39877 -39878 -39879 -39880 -39881 -39882 -39883 -39884 -39885 -39886 -39887 -39888 -39889 -39890 -39891 -39892 -39893 -39894 -39895 -39896 -39897 -39898 -39899 -39900 -39901 -39902 -39903 -39904 -39905 -39906 -39907 -39908 -39909 -39910 -39911 -39912 -39913 -39914 -39915 -39916 -39917 -39918 -39919 -39920 -39921 -39922 -39923 -39924 -39925 -39926 -39927 -39928 -39929 -39930 -39931 -39932 -39933 -39934 -39935 -39936 -39937 -39938 -39939 -39940 -39941 -39942 -39943 -39944 -39945 -39946 -39947 -39948 -39949 -39950 -39951 -39952 -39953 -39954 -39955 -39956 -39957 -39958 -39959 -39960 -39961 -39962 -39963 -39964 -39965 -39966 -39967 -39968 -39969 -39970 -39971 -39972 -39973 -39974 -39975 -39976 -39977 -39978 -39979 -39980 -39981 -39982 -39983 -39984 -39985 -39986 -39987 -39988 -39989 -39990 -39991 -39992 -39993 -39994 -39995 -39996 -39997 -39998 -39999 -40000 -40001 -40002 -40003 -40004 -40005 -40006 -40007 -40008 -40009 -40010 -40011 -40012 -40013 -40014 -40015 -40016 -40017 -40018 -40019 -40020 -40021 -40022 -40023 -40024 -40025 -40026 -40027 -40028 -40029 -40030 -40031 -40032 -40033 -40034 -40035 -40036 -40037 -40038 -40039 -40040 -40041 -40042 -40043 -40044 -40045 -40046 -40047 -40048 -40049 -40050 -40051 -40052 -40053 -40054 -40055 -40056 -40057 -40058 -40059 -40060 -40061 -40062 -40063 -40064 -40065 -40066 -40067 -40068 -40069 -40070 -40071 -40072 -40073 -40074 -40075 -40076 -40077 -40078 -40079 -40080 -40081 -40082 -40083 -40084 -40085 -40086 -40087 -40088 -40089 -40090 -40091 -40092 -40093 -40094 -40095 -40096 -40097 -40098 -40099 -40100 -40101 -40102 -40103 -40104 -40105 -40106 -40107 -40108 -40109 -40110 -40111 -40112 -40113 -40114 -40115 -40116 -40117 -40118 -40119 -40120 -40121 -40122 -40123 -40124 -40125 -40126 -40127 -40128 -40129 -40130 -40131 -40132 -40133 -40134 -40135 -40136 -40137 -40138 -40139 -40140 -40141 -40142 -40143 -40144 -40145 -40146 -40147 -40148 -40149 -40150 -40151 -40152 -40153 -40154 -40155 -40156 -40157 -40158 -40159 -40160 -40161 -40162 -40163 -40164 -40165 -40166 -40167 -40168 -40169 -40170 -40171 -40172 -40173 -40174 -40175 -40176 -40177 -40178 -40179 -40180 -40181 -40182 -40183 -40184 -40185 -40186 -40187 -40188 -40189 -40190 -40191 -40192 -40193 -40194 -40195 -40196 -40197 -40198 -40199 -40200 -40201 -40202 -40203 -40204 -40205 -40206 -40207 -40208 -40209 -40210 -40211 -40212 -40213 -40214 -40215 -40216 -40217 -40218 -40219 -40220 -40221 -40222 -40223 -40224 -40225 -40226 -40227 -40228 -40229 -40230 -40231 -40232 -40233 -40234 -40235 -40236 -40237 -40238 -40239 -40240 -40241 -40242 -40243 -40244 -40245 -40246 -40247 -40248 -40249 -40250 -40251 -40252 -40253 -40254 -40255 -40256 -40257 -40258 -40259 -40260 -40261 -40262 -40263 -40264 -40265 -40266 -40267 -40268 -40269 -40270 -40271 -40272 -40273 -40274 -40275 -40276 -40277 -40278 -40279 -40280 -40281 -40282 -40283 -40284 -40285 -40286 -40287 -40288 -40289 -40290 -40291 -40292 -40293 -40294 -40295 -40296 -40297 -40298 -40299 -40300 -40301 -40302 -40303 -40304 -40305 -40306 -40307 -40308 -40309 -40310 -40311 -40312 -40313 -40314 -40315 -40316 -40317 -40318 -40319 -40320 -40321 -40322 -40323 -40324 -40325 -40326 -40327 -40328 -40329 -40330 -40331 -40332 -40333 -40334 -40335 -40336 -40337 -40338 -40339 -40340 -40341 -40342 -40343 -40344 -40345 -40346 -40347 -40348 -40349 -40350 -40351 -40352 -40353 -40354 -40355 -40356 -40357 -40358 -40359 -40360 -40361 -40362 -40363 -40364 -40365 -40366 -40367 -40368 -40369 -40370 -40371 -40372 -40373 -40374 -40375 -40376 -40377 -40378 -40379 -40380 -40381 -40382 -40383 -40384 -40385 -40386 -40387 -40388 -40389 -40390 -40391 -40392 -40393 -40394 -40395 -40396 -40397 -40398 -40399 -40400 -40401 -40402 -40403 -40404 -40405 -40406 -40407 -40408 -40409 -40410 -40411 -40412 -40413 -40414 -40415 -40416 -40417 -40418 -40419 -40420 -40421 -40422 -40423 -40424 -40425 -40426 -40427 -40428 -40429 -40430 -40431 -40432 -40433 -40434 -40435 -40436 -40437 -40438 -40439 -40440 -40441 -40442 -40443 -40444 -40445 -40446 -40447 -40448 -40449 -40450 -40451 -40452 -40453 -40454 -40455 -40456 -40457 -40458 -40459 -40460 -40461 -40462 -40463 -40464 -40465 -40466 -40467 -40468 -40469 -40470 -40471 -40472 -40473 -40474 -40475 -40476 -40477 -40478 -40479 -40480 -40481 -40482 -40483 -40484 -40485 -40486 -40487 -40488 -40489 -40490 -40491 -40492 -40493 -40494 -40495 -40496 -40497 -40498 -40499 -40500 -40501 -40502 -40503 -40504 -40505 -40506 -40507 -40508 -40509 -40510 -40511 -40512 -40513 -40514 -40515 -40516 -40517 -40518 -40519 -40520 -40521 -40522 -40523 -40524 -40525 -40526 -40527 -40528 -40529 -40530 -40531 -40532 -40533 -40534 -40535 -40536 -40537 -40538 -40539 -40540 -40541 -40542 -40543 -40544 -40545 -40546 -40547 -40548 -40549 -40550 -40551 -40552 -40553 -40554 -40555 -40556 -40557 -40558 -40559 -40560 -40561 -40562 -40563 -40564 -40565 -40566 -40567 -40568 -40569 -40570 -40571 -40572 -40573 -40574 -40575 -40576 -40577 -40578 -40579 -40580 -40581 -40582 -40583 -40584 -40585 -40586 -40587 -40588 -40589 -40590 -40591 -40592 -40593 -40594 -40595 -40596 -40597 -40598 -40599 -40600 -40601 -40602 -40603 -40604 -40605 -40606 -40607 -40608 -40609 -40610 -40611 -40612 -40613 -40614 -40615 -40616 -40617 -40618 -40619 -40620 -40621 -40622 -40623 -40624 -40625 -40626 -40627 -40628 -40629 -40630 -40631 -40632 -40633 -40634 -40635 -40636 -40637 -40638 -40639 -40640 -40641 -40642 -40643 -40644 -40645 -40646 -40647 -40648 -40649 -40650 -40651 -40652 -40653 -40654 -40655 -40656 -40657 -40658 -40659 -40660 -40661 -40662 -40663 -40664 -40665 -40666 -40667 -40668 -40669 -40670 -40671 -40672 -40673 -40674 -40675 -40676 -40677 -40678 -40679 -40680 -40681 -40682 -40683 -40684 -40685 -40686 -40687 -40688 -40689 -40690 -40691 -40692 -40693 -40694 -40695 -40696 -40697 -40698 -40699 -40700 -40701 -40702 -40703 -40704 -40705 -40706 -40707 -40708 -40709 -40710 -40711 -40712 -40713 -40714 -40715 -40716 -40717 -40718 -40719 -40720 -40721 -40722 -40723 -40724 -40725 -40726 -40727 -40728 -40729 -40730 -40731 -40732 -40733 -40734 -40735 -40736 -40737 -40738 -40739 -40740 -40741 -40742 -40743 -40744 -40745 -40746 -40747 -40748 -40749 -40750 -40751 -40752 -40753 -40754 -40755 -40756 -40757 -40758 -40759 -40760 -40761 -40762 -40763 -40764 -40765 -40766 -40767 -40768 -40769 -40770 -40771 -40772 -40773 -40774 -40775 -40776 -40777 -40778 -40779 -40780 -40781 -40782 -40783 -40784 -40785 -40786 -40787 -40788 -40789 -40790 -40791 -40792 -40793 -40794 -40795 -40796 -40797 -40798 -40799 -40800 -40801 -40802 -40803 -40804 -40805 -40806 -40807 -40808 -40809 -40810 -40811 -40812 -40813 -40814 -40815 -40816 -40817 -40818 -40819 -40820 -40821 -40822 -40823 -40824 -40825 -40826 -40827 -40828 -40829 -40830 -40831 -40832 -40833 -40834 -40835 -40836 -40837 -40838 -40839 -40840 -40841 -40842 -40843 -40844 -40845 -40846 -40847 -40848 -40849 -40850 -40851 -40852 -40853 -40854 -40855 -40856 -40857 -40858 -40859 -40860 -40861 -40862 -40863 -40864 -40865 -40866 -40867 -40868 -40869 -40870 -40871 -40872 -40873 -40874 -40875 -40876 -40877 -40878 -40879 -40880 -40881 -40882 -40883 -40884 -40885 -40886 -40887 -40888 -40889 -40890 -40891 -40892 -40893 -40894 -40895 -40896 -40897 -40898 -40899 -40900 -40901 -40902 -40903 -40904 -40905 -40906 -40907 -40908 -40909 -40910 -40911 -40912 -40913 -40914 -40915 -40916 -40917 -40918 -40919 -40920 -40921 -40922 -40923 -40924 -40925 -40926 -40927 -40928 -40929 -40930 -40931 -40932 -40933 -40934 -40935 -40936 -40937 -40938 -40939 -40940 -40941 -40942 -40943 -40944 -40945 -40946 -40947 -40948 -40949 -40950 -40951 -40952 -40953 -40954 -40955 -40956 -40957 -40958 -40959 -40960 -40961 -40962 -40963 -40964 -40965 -40966 -40967 -40968 -40969 -40970 -40971 -40972 -40973 -40974 -40975 -40976 -40977 -40978 -40979 -40980 -40981 -40982 -40983 -40984 -40985 -40986 -40987 -40988 -40989 -40990 -40991 -40992 -40993 -40994 -40995 -40996 -40997 -40998 -40999 -41000 -41001 -41002 -41003 -41004 -41005 -41006 -41007 -41008 -41009 -41010 -41011 -41012 -41013 -41014 -41015 -41016 -41017 -41018 -41019 -41020 -41021 -41022 -41023 -41024 -41025 -41026 -41027 -41028 -41029 -41030 -41031 -41032 -41033 -41034 -41035 -41036 -41037 -41038 -41039 -41040 -41041 -41042 -41043 -41044 -41045 -41046 -41047 -41048 -41049 -41050 -41051 -41052 -41053 -41054 -41055 -41056 -41057 -41058 -41059 -41060 -41061 -41062 -41063 -41064 -41065 -41066 -41067 -41068 -41069 -41070 -41071 -41072 -41073 -41074 -41075 -41076 -41077 -41078 -41079 -41080 -41081 -41082 -41083 -41084 -41085 -41086 -41087 -41088 -41089 -41090 -41091 -41092 -41093 -41094 -41095 -41096 -41097 -41098 -41099 -41100 -41101 -41102 -41103 -41104 -41105 -41106 -41107 -41108 -41109 -41110 -41111 -41112 -41113 -41114 -41115 -41116 -41117 -41118 -41119 -41120 -41121 -41122 -41123 -41124 -41125 -41126 -41127 -41128 -41129 -41130 -41131 -41132 -41133 -41134 -41135 -41136 -41137 -41138 -41139 -41140 -41141 -41142 -41143 -41144 -41145 -41146 -41147 -41148 -41149 -41150 -41151 -41152 -41153 -41154 -41155 -41156 -41157 -41158 -41159 -41160 -41161 -41162 -41163 -41164 -41165 -41166 -41167 -41168 -41169 -41170 -41171 -41172 -41173 -41174 -41175 -41176 -41177 -41178 -41179 -41180 -41181 -41182 -41183 -41184 -41185 -41186 -41187 -41188 -41189 -41190 -41191 -41192 -41193 -41194 -41195 -41196 -41197 -41198 -41199 -41200 -41201 -41202 -41203 -41204 -41205 -41206 -41207 -41208 -41209 -41210 -41211 -41212 -41213 -41214 -41215 -41216 -41217 -41218 -41219 -41220 -41221 -41222 -41223 -41224 -41225 -41226 -41227 -41228 -41229 -41230 -41231 -41232 -41233 -41234 -41235 -41236 -41237 -41238 -41239 -41240 -41241 -41242 -41243 -41244 -41245 -41246 -41247 -41248 -41249 -41250 -41251 -41252 -41253 -41254 -41255 -41256 -41257 -41258 -41259 -41260 -41261 -41262 -41263 -41264 -41265 -41266 -41267 -41268 -41269 -41270 -41271 -41272 -41273 -41274 -41275 -41276 -41277 -41278 -41279 -41280 -41281 -41282 -41283 -41284 -41285 -41286 -41287 -41288 -41289 -41290 -41291 -41292 -41293 -41294 -41295 -41296 -41297 -41298 -41299 -41300 -41301 -41302 -41303 -41304 -41305 -41306 -41307 -41308 -41309 -41310 -41311 -41312 -41313 -41314 -41315 -41316 -41317 -41318 -41319 -41320 -41321 -41322 -41323 -41324 -41325 -41326 -41327 -41328 -41329 -41330 -41331 -41332 -41333 -41334 -41335 -41336 -41337 -41338 -41339 -41340 -41341 -41342 -41343 -41344 -41345 -41346 -41347 -41348 -41349 -41350 -41351 -41352 -41353 -41354 -41355 -41356 -41357 -41358 -41359 -41360 -41361 -41362 -41363 -41364 -41365 -41366 -41367 -41368 -41369 -41370 -41371 -41372 -41373 -41374 -41375 -41376 -41377 -41378 -41379 -41380 -41381 -41382 -41383 -41384 -41385 -41386 -41387 -41388 -41389 -41390 -41391 -41392 -41393 -41394 -41395 -41396 -41397 -41398 -41399 -41400 -41401 -41402 -41403 -41404 -41405 -41406 -41407 -41408 -41409 -41410 -41411 -41412 -41413 -41414 -41415 -41416 -41417 -41418 -41419 -41420 -41421 -41422 -41423 -41424 -41425 -41426 -41427 -41428 -41429 -41430 -41431 -41432 -41433 -41434 -41435 -41436 -41437 -41438 -41439 -41440 -41441 -41442 -41443 -41444 -41445 -41446 -41447 -41448 -41449 -41450 -41451 -41452 -41453 -41454 -41455 -41456 -41457 -41458 -41459 -41460 -41461 -41462 -41463 -41464 -41465 -41466 -41467 -41468 -41469 -41470 -41471 -41472 -41473 -41474 -41475 -41476 -41477 -41478 -41479 -41480 -41481 -41482 -41483 -41484 -41485 -41486 -41487 -41488 -41489 -41490 -41491 -41492 -41493 -41494 -41495 -41496 -41497 -41498 -41499 -41500 -41501 -41502 -41503 -41504 -41505 -41506 -41507 -41508 -41509 -41510 -41511 -41512 -41513 -41514 -41515 -41516 -41517 -41518 -41519 -41520 -41521 -41522 -41523 -41524 -41525 -41526 -41527 -41528 -41529 -41530 -41531 -41532 -41533 -41534 -41535 -41536 -41537 -41538 -41539 -41540 -41541 -41542 -41543 -41544 -41545 -41546 -41547 -41548 -41549 -41550 -41551 -41552 -41553 -41554 -41555 -41556 -41557 -41558 -41559 -41560 -41561 -41562 -41563 -41564 -41565 -41566 -41567 -41568 -41569 -41570 -41571 -41572 -41573 -41574 -41575 -41576 -41577 -41578 -41579 -41580 -41581 -41582 -41583 -41584 -41585 -41586 -41587 -41588 -41589 -41590 -41591 -41592 -41593 -41594 -41595 -41596 -41597 -41598 -41599 -41600 -41601 -41602 -41603 -41604 -41605 -41606 -41607 -41608 -41609 -41610 -41611 -41612 -41613 -41614 -41615 -41616 -41617 -41618 -41619 -41620 -41621 -41622 -41623 -41624 -41625 -41626 -41627 -41628 -41629 -41630 -41631 -41632 -41633 -41634 -41635 -41636 -41637 -41638 -41639 -41640 -41641 -41642 -41643 -41644 -41645 -41646 -41647 -41648 -41649 -41650 -41651 -41652 -41653 -41654 -41655 -41656 -41657 -41658 -41659 -41660 -41661 -41662 -41663 -41664 -41665 -41666 -41667 -41668 -41669 -41670 -41671 -41672 -41673 -41674 -41675 -41676 -41677 -41678 -41679 -41680 -41681 -41682 -41683 -41684 -41685 -41686 -41687 -41688 -41689 -41690 -41691 -41692 -41693 -41694 -41695 -41696 -41697 -41698 -41699 -41700 -41701 -41702 -41703 -41704 -41705 -41706 -41707 -41708 -41709 -41710 -41711 -41712 -41713 -41714 -41715 -41716 -41717 -41718 -41719 -41720 -41721 -41722 -41723 -41724 -41725 -41726 -41727 -41728 -41729 -41730 -41731 -41732 -41733 -41734 -41735 -41736 -41737 -41738 -41739 -41740 -41741 -41742 -41743 -41744 -41745 -41746 -41747 -41748 -41749 -41750 -41751 -41752 -41753 -41754 -41755 -41756 -41757 -41758 -41759 -41760 -41761 -41762 -41763 -41764 -41765 -41766 -41767 -41768 -41769 -41770 -41771 -41772 -41773 -41774 -41775 -41776 -41777 -41778 -41779 -41780 -41781 -41782 -41783 -41784 -41785 -41786 -41787 -41788 -41789 -41790 -41791 -41792 -41793 -41794 -41795 -41796 -41797 -41798 -41799 -41800 -41801 -41802 -41803 -41804 -41805 -41806 -41807 -41808 -41809 -41810 -41811 -41812 -41813 -41814 -41815 -41816 -41817 -41818 -41819 -41820 -41821 -41822 -41823 -41824 -41825 -41826 -41827 -41828 -41829 -41830 -41831 -41832 -41833 -41834 -41835 -41836 -41837 -41838 -41839 -41840 -41841 -41842 -41843 -41844 -41845 -41846 -41847 -41848 -41849 -41850 -41851 -41852 -41853 -41854 -41855 -41856 -41857 -41858 -41859 -41860 -41861 -41862 -41863 -41864 -41865 -41866 -41867 -41868 -41869 -41870 -41871 -41872 -41873 -41874 -41875 -41876 -41877 -41878 -41879 -41880 -41881 -41882 -41883 -41884 -41885 -41886 -41887 -41888 -41889 -41890 -41891 -41892 -41893 -41894 -41895 -41896 -41897 -41898 -41899 -41900 -41901 -41902 -41903 -41904 -41905 -41906 -41907 -41908 -41909 -41910 -41911 -41912 -41913 -41914 -41915 -41916 -41917 -41918 -41919 -41920 -41921 -41922 -41923 -41924 -41925 -41926 -41927 -41928 -41929 -41930 -41931 -41932 -41933 -41934 -41935 -41936 -41937 -41938 -41939 -41940 -41941 -41942 -41943 -41944 -41945 -41946 -41947 -41948 -41949 -41950 -41951 -41952 -41953 -41954 -41955 -41956 -41957 -41958 -41959 -41960 -41961 -41962 -41963 -41964 -41965 -41966 -41967 -41968 -41969 -41970 -41971 -41972 -41973 -41974 -41975 -41976 -41977 -41978 -41979 -41980 -41981 -41982 -41983 -41984 -41985 -41986 -41987 -41988 -41989 -41990 -41991 -41992 -41993 -41994 -41995 -41996 -41997 -41998 -41999 -42000 -42001 -42002 -42003 -42004 -42005 -42006 -42007 -42008 -42009 -42010 -42011 -42012 -42013 -42014 -42015 -42016 -42017 -42018 -42019 -42020 -42021 -42022 -42023 -42024 -42025 -42026 -42027 -42028 -42029 -42030 -42031 -42032 -42033 -42034 -42035 -42036 -42037 -42038 -42039 -42040 -42041 -42042 -42043 -42044 -42045 -42046 -42047 -42048 -42049 -42050 -42051 -42052 -42053 -42054 -42055 -42056 -42057 -42058 -42059 -42060 -42061 -42062 -42063 -42064 -42065 -42066 -42067 -42068 -42069 -42070 -42071 -42072 -42073 -42074 -42075 -42076 -42077 -42078 -42079 -42080 -42081 -42082 -42083 -42084 -42085 -42086 -42087 -42088 -42089 -42090 -42091 -42092 -42093 -42094 -42095 -42096 -42097 -42098 -42099 -42100 -42101 -42102 -42103 -42104 -42105 -42106 -42107 -42108 -42109 -42110 -42111 -42112 -42113 -42114 -42115 -42116 -42117 -42118 -42119 -42120 -42121 -42122 -42123 -42124 -42125 -42126 -42127 -42128 -42129 -42130 -42131 -42132 -42133 -42134 -42135 -42136 -42137 -42138 -42139 -42140 -42141 -42142 -42143 -42144 -42145 -42146 -42147 -42148 -42149 -42150 -42151 -42152 -42153 -42154 -42155 -42156 -42157 -42158 -42159 -42160 -42161 -42162 -42163 -42164 -42165 -42166 -42167 -42168 -42169 -42170 -42171 -42172 -42173 -42174 -42175 -42176 -42177 -42178 -42179 -42180 -42181 -42182 -42183 -42184 -42185 -42186 -42187 -42188 -42189 -42190 -42191 -42192 -42193 -42194 -42195 -42196 -42197 -42198 -42199 -42200 -42201 -42202 -42203 -42204 -42205 -42206 -42207 -42208 -42209 -42210 -42211 -42212 -42213 -42214 -42215 -42216 -42217 -42218 -42219 -42220 -42221 -42222 -42223 -42224 -42225 -42226 -42227 -42228 -42229 -42230 -42231 -42232 -42233 -42234 -42235 -42236 -42237 -42238 -42239 -42240 -42241 -42242 -42243 -42244 -42245 -42246 -42247 -42248 -42249 -42250 -42251 -42252 -42253 -42254 -42255 -42256 -42257 -42258 -42259 -42260 -42261 -42262 -42263 -42264 -42265 -42266 -42267 -42268 -42269 -42270 -42271 -42272 -42273 -42274 -42275 -42276 -42277 -42278 -42279 -42280 -42281 -42282 -42283 -42284 -42285 -42286 -42287 -42288 -42289 -42290 -42291 -42292 -42293 -42294 -42295 -42296 -42297 -42298 -42299 -42300 -42301 -42302 -42303 -42304 -42305 -42306 -42307 -42308 -42309 -42310 -42311 -42312 -42313 -42314 -42315 -42316 -42317 -42318 -42319 -42320 -42321 -42322 -42323 -42324 -42325 -42326 -42327 -42328 -42329 -42330 -42331 -42332 -42333 -42334 -42335 -42336 -42337 -42338 -42339 -42340 -42341 -42342 -42343 -42344 -42345 -42346 -42347 -42348 -42349 -42350 -42351 -42352 -42353 -42354 -42355 -42356 -42357 -42358 -42359 -42360 -42361 -42362 -42363 -42364 -42365 -42366 -42367 -42368 -42369 -42370 -42371 -42372 -42373 -42374 -42375 -42376 -42377 -42378 -42379 -42380 -42381 -42382 -42383 -42384 -42385 -42386 -42387 -42388 -42389 -42390 -42391 -42392 -42393 -42394 -42395 -42396 -42397 -42398 -42399 -42400 -42401 -42402 -42403 -42404 -42405 -42406 -42407 -42408 -42409 -42410 -42411 -42412 -42413 -42414 -42415 -42416 -42417 -42418 -42419 -42420 -42421 -42422 -42423 -42424 -42425 -42426 -42427 -42428 -42429 -42430 -42431 -42432 -42433 -42434 -42435 -42436 -42437 -42438 -42439 -42440 -42441 -42442 -42443 -42444 -42445 -42446 -42447 -42448 -42449 -42450 -42451 -42452 -42453 -42454 -42455 -42456 -42457 -42458 -42459 -42460 -42461 -42462 -42463 -42464 -42465 -42466 -42467 -42468 -42469 -42470 -42471 -42472 -42473 -42474 -42475 -42476 -42477 -42478 -42479 -42480 -42481 -42482 -42483 -42484 -42485 -42486 -42487 -42488 -42489 -42490 -42491 -42492 -42493 -42494 -42495 -42496 -42497 -42498 -42499 -42500 -42501 -42502 -42503 -42504 -42505 -42506 -42507 -42508 -42509 -42510 -42511 -42512 -42513 -42514 -42515 -42516 -42517 -42518 -42519 -42520 -42521 -42522 -42523 -42524 -42525 -42526 -42527 -42528 -42529 -42530 -42531 -42532 -42533 -42534 -42535 -42536 -42537 -42538 -42539 -42540 -42541 -42542 -42543 -42544 -42545 -42546 -42547 -42548 -42549 -42550 -42551 -42552 -42553 -42554 -42555 -42556 -42557 -42558 -42559 -42560 -42561 -42562 -42563 -42564 -42565 -42566 -42567 -42568 -42569 -42570 -42571 -42572 -42573 -42574 -42575 -42576 -42577 -42578 -42579 -42580 -42581 -42582 -42583 -42584 -42585 -42586 -42587 -42588 -42589 -42590 -42591 -42592 -42593 -42594 -42595 -42596 -42597 -42598 -42599 -42600 -42601 -42602 -42603 -42604 -42605 -42606 -42607 -42608 -42609 -42610 -42611 -42612 -42613 -42614 -42615 -42616 -42617 -42618 -42619 -42620 -42621 -42622 -42623 -42624 -42625 -42626 -42627 -42628 -42629 -42630 -42631 -42632 -42633 -42634 -42635 -42636 -42637 -42638 -42639 -42640 -42641 -42642 -42643 -42644 -42645 -42646 -42647 -42648 -42649 -42650 -42651 -42652 -42653 -42654 -42655 -42656 -42657 -42658 -42659 -42660 -42661 -42662 -42663 -42664 -42665 -42666 -42667 -42668 -42669 -42670 -42671 -42672 -42673 -42674 -42675 -42676 -42677 -42678 -42679 -42680 -42681 -42682 -42683 -42684 -42685 -42686 -42687 -42688 -42689 -42690 -42691 -42692 -42693 -42694 -42695 -42696 -42697 -42698 -42699 -42700 -42701 -42702 -42703 -42704 -42705 -42706 -42707 -42708 -42709 -42710 -42711 -42712 -42713 -42714 -42715 -42716 -42717 -42718 -42719 -42720 -42721 -42722 -42723 -42724 -42725 -42726 -42727 -42728 -42729 -42730 -42731 -42732 -42733 -42734 -42735 -42736 -42737 -42738 -42739 -42740 -42741 -42742 -42743 -42744 -42745 -42746 -42747 -42748 -42749 -42750 -42751 -42752 -42753 -42754 -42755 -42756 -42757 -42758 -42759 -42760 -42761 -42762 -42763 -42764 -42765 -42766 -42767 -42768 -42769 -42770 -42771 -42772 -42773 -42774 -42775 -42776 -42777 -42778 -42779 -42780 -42781 -42782 -42783 -42784 -42785 -42786 -42787 -42788 -42789 -42790 -42791 -42792 -42793 -42794 -42795 -42796 -42797 -42798 -42799 -42800 -42801 -42802 -42803 -42804 -42805 -42806 -42807 -42808 -42809 -42810 -42811 -42812 -42813 -42814 -42815 -42816 -42817 -42818 -42819 -42820 -42821 -42822 -42823 -42824 -42825 -42826 -42827 -42828 -42829 -42830 -42831 -42832 -42833 -42834 -42835 -42836 -42837 -42838 -42839 -42840 -42841 -42842 -42843 -42844 -42845 -42846 -42847 -42848 -42849 -42850 -42851 -42852 -42853 -42854 -42855 -42856 -42857 -42858 -42859 -42860 -42861 -42862 -42863 -42864 -42865 -42866 -42867 -42868 -42869 -42870 -42871 -42872 -42873 -42874 -42875 -42876 -42877 -42878 -42879 -42880 -42881 -42882 -42883 -42884 -42885 -42886 -42887 -42888 -42889 -42890 -42891 -42892 -42893 -42894 -42895 -42896 -42897 -42898 -42899 -42900 -42901 -42902 -42903 -42904 -42905 -42906 -42907 -42908 -42909 -42910 -42911 -42912 -42913 -42914 -42915 -42916 -42917 -42918 -42919 -42920 -42921 -42922 -42923 -42924 -42925 -42926 -42927 -42928 -42929 -42930 -42931 -42932 -42933 -42934 -42935 -42936 -42937 -42938 -42939 -42940 -42941 -42942 -42943 -42944 -42945 -42946 -42947 -42948 -42949 -42950 -42951 -42952 -42953 -42954 -42955 -42956 -42957 -42958 -42959 -42960 -42961 -42962 -42963 -42964 -42965 -42966 -42967 -42968 -42969 -42970 -42971 -42972 -42973 -42974 -42975 -42976 -42977 -42978 -42979 -42980 -42981 -42982 -42983 -42984 -42985 -42986 -42987 -42988 -42989 -42990 -42991 -42992 -42993 -42994 -42995 -42996 -42997 -42998 -42999 -43000 -43001 -43002 -43003 -43004 -43005 -43006 -43007 -43008 -43009 -43010 -43011 -43012 -43013 -43014 -43015 -43016 -43017 -43018 -43019 -43020 -43021 -43022 -43023 -43024 -43025 -43026 -43027 -43028 -43029 -43030 -43031 -43032 -43033 -43034 -43035 -43036 -43037 -43038 -43039 -43040 -43041 -43042 -43043 -43044 -43045 -43046 -43047 -43048 -43049 -43050 -43051 -43052 -43053 -43054 -43055 -43056 -43057 -43058 -43059 -43060 -43061 -43062 -43063 -43064 -43065 -43066 -43067 -43068 -43069 -43070 -43071 -43072 -43073 -43074 -43075 -43076 -43077 -43078 -43079 -43080 -43081 -43082 -43083 -43084 -43085 -43086 -43087 -43088 -43089 -43090 -43091 -43092 -43093 -43094 -43095 -43096 -43097 -43098 -43099 -43100 -43101 -43102 -43103 -43104 -43105 -43106 -43107 -43108 -43109 -43110 -43111 -43112 -43113 -43114 -43115 -43116 -43117 -43118 -43119 -43120 -43121 -43122 -43123 -43124 -43125 -43126 -43127 -43128 -43129 -43130 -43131 -43132 -43133 -43134 -43135 -43136 -43137 -43138 -43139 -43140 -43141 -43142 -43143 -43144 -43145 -43146 -43147 -43148 -43149 -43150 -43151 -43152 -43153 -43154 -43155 -43156 -43157 -43158 -43159 -43160 -43161 -43162 -43163 -43164 -43165 -43166 -43167 -43168 -43169 -43170 -43171 -43172 -43173 -43174 -43175 -43176 -43177 -43178 -43179 -43180 -43181 -43182 -43183 -43184 -43185 -43186 -43187 -43188 -43189 -43190 -43191 -43192 -43193 -43194 -43195 -43196 -43197 -43198 -43199 -43200 -43201 -43202 -43203 -43204 -43205 -43206 -43207 -43208 -43209 -43210 -43211 -43212 -43213 -43214 -43215 -43216 -43217 -43218 -43219 -43220 -43221 -43222 -43223 -43224 -43225 -43226 -43227 -43228 -43229 -43230 -43231 -43232 -43233 -43234 -43235 -43236 -43237 -43238 -43239 -43240 -43241 -43242 -43243 -43244 -43245 -43246 -43247 -43248 -43249 -43250 -43251 -43252 -43253 -43254 -43255 -43256 -43257 -43258 -43259 -43260 -43261 -43262 -43263 -43264 -43265 -43266 -43267 -43268 -43269 -43270 -43271 -43272 -43273 -43274 -43275 -43276 -43277 -43278 -43279 -43280 -43281 -43282 -43283 -43284 -43285 -43286 -43287 -43288 -43289 -43290 -43291 -43292 -43293 -43294 -43295 -43296 -43297 -43298 -43299 -43300 -43301 -43302 -43303 -43304 -43305 -43306 -43307 -43308 -43309 -43310 -43311 -43312 -43313 -43314 -43315 -43316 -43317 -43318 -43319 -43320 -43321 -43322 -43323 -43324 -43325 -43326 -43327 -43328 -43329 -43330 -43331 -43332 -43333 -43334 -43335 -43336 -43337 -43338 -43339 -43340 -43341 -43342 -43343 -43344 -43345 -43346 -43347 -43348 -43349 -43350 -43351 -43352 -43353 -43354 -43355 -43356 -43357 -43358 -43359 -43360 -43361 -43362 -43363 -43364 -43365 -43366 -43367 -43368 -43369 -43370 -43371 -43372 -43373 -43374 -43375 -43376 -43377 -43378 -43379 -43380 -43381 -43382 -43383 -43384 -43385 -43386 -43387 -43388 -43389 -43390 -43391 -43392 -43393 -43394 -43395 -43396 -43397 -43398 -43399 -43400 -43401 -43402 -43403 -43404 -43405 -43406 -43407 -43408 -43409 -43410 -43411 -43412 -43413 -43414 -43415 -43416 -43417 -43418 -43419 -43420 -43421 -43422 -43423 -43424 -43425 -43426 -43427 -43428 -43429 -43430 -43431 -43432 -43433 -43434 -43435 -43436 -43437 -43438 -43439 -43440 -43441 -43442 -43443 -43444 -43445 -43446 -43447 -43448 -43449 -43450 -43451 -43452 -43453 -43454 -43455 -43456 -43457 -43458 -43459 -43460 -43461 -43462 -43463 -43464 -43465 -43466 -43467 -43468 -43469 -43470 -43471 -43472 -43473 -43474 -43475 -43476 -43477 -43478 -43479 -43480 -43481 -43482 -43483 -43484 -43485 -43486 -43487 -43488 -43489 -43490 -43491 -43492 -43493 -43494 -43495 -43496 -43497 -43498 -43499 -43500 -43501 -43502 -43503 -43504 -43505 -43506 -43507 -43508 -43509 -43510 -43511 -43512 -43513 -43514 -43515 -43516 -43517 -43518 -43519 -43520 -43521 -43522 -43523 -43524 -43525 -43526 -43527 -43528 -43529 -43530 -43531 -43532 -43533 -43534 -43535 -43536 -43537 -43538 -43539 -43540 -43541 -43542 -43543 -43544 -43545 -43546 -43547 -43548 -43549 -43550 -43551 -43552 -43553 -43554 -43555 -43556 -43557 -43558 -43559 -43560 -43561 -43562 -43563 -43564 -43565 -43566 -43567 -43568 -43569 -43570 -43571 -43572 -43573 -43574 -43575 -43576 -43577 -43578 -43579 -43580 -43581 -43582 -43583 -43584 -43585 -43586 -43587 -43588 -43589 -43590 -43591 -43592 -43593 -43594 -43595 -43596 -43597 -43598 -43599 -43600 -43601 -43602 -43603 -43604 -43605 -43606 -43607 -43608 -43609 -43610 -43611 -43612 -43613 -43614 -43615 -43616 -43617 -43618 -43619 -43620 -43621 -43622 -43623 -43624 -43625 -43626 -43627 -43628 -43629 -43630 -43631 -43632 -43633 -43634 -43635 -43636 -43637 -43638 -43639 -43640 -43641 -43642 -43643 -43644 -43645 -43646 -43647 -43648 -43649 -43650 -43651 -43652 -43653 -43654 -43655 -43656 -43657 -43658 -43659 -43660 -43661 -43662 -43663 -43664 -43665 -43666 -43667 -43668 -43669 -43670 -43671 -43672 -43673 -43674 -43675 -43676 -43677 -43678 -43679 -43680 -43681 -43682 -43683 -43684 -43685 -43686 -43687 -43688 -43689 -43690 -43691 -43692 -43693 -43694 -43695 -43696 -43697 -43698 -43699 -43700 -43701 -43702 -43703 -43704 -43705 -43706 -43707 -43708 -43709 -43710 -43711 -43712 -43713 -43714 -43715 -43716 -43717 -43718 -43719 -43720 -43721 -43722 -43723 -43724 -43725 -43726 -43727 -43728 -43729 -43730 -43731 -43732 -43733 -43734 -43735 -43736 -43737 -43738 -43739 -43740 -43741 -43742 -43743 -43744 -43745 -43746 -43747 -43748 -43749 -43750 -43751 -43752 -43753 -43754 -43755 -43756 -43757 -43758 -43759 -43760 -43761 -43762 -43763 -43764 -43765 -43766 -43767 -43768 -43769 -43770 -43771 -43772 -43773 -43774 -43775 -43776 -43777 -43778 -43779 -43780 -43781 -43782 -43783 -43784 -43785 -43786 -43787 -43788 -43789 -43790 -43791 -43792 -43793 -43794 -43795 -43796 -43797 -43798 -43799 -43800 -43801 -43802 -43803 -43804 -43805 -43806 -43807 -43808 -43809 -43810 -43811 -43812 -43813 -43814 -43815 -43816 -43817 -43818 -43819 -43820 -43821 -43822 -43823 -43824 -43825 -43826 -43827 -43828 -43829 -43830 -43831 -43832 -43833 -43834 -43835 -43836 -43837 -43838 -43839 -43840 -43841 -43842 -43843 -43844 -43845 -43846 -43847 -43848 -43849 -43850 -43851 -43852 -43853 -43854 -43855 -43856 -43857 -43858 -43859 -43860 -43861 -43862 -43863 -43864 -43865 -43866 -43867 -43868 -43869 -43870 -43871 -43872 -43873 -43874 -43875 -43876 -43877 -43878 -43879 -43880 -43881 -43882 -43883 -43884 -43885 -43886 -43887 -43888 -43889 -43890 -43891 -43892 -43893 -43894 -43895 -43896 -43897 -43898 -43899 -43900 -43901 -43902 -43903 -43904 -43905 -43906 -43907 -43908 -43909 -43910 -43911 -43912 -43913 -43914 -43915 -43916 -43917 -43918 -43919 -43920 -43921 -43922 -43923 -43924 -43925 -43926 -43927 -43928 -43929 -43930 -43931 -43932 -43933 -43934 -43935 -43936 -43937 -43938 -43939 -43940 -43941 -43942 -43943 -43944 -43945 -43946 -43947 -43948 -43949 -43950 -43951 -43952 -43953 -43954 -43955 -43956 -43957 -43958 -43959 -43960 -43961 -43962 -43963 -43964 -43965 -43966 -43967 -43968 -43969 -43970 -43971 -43972 -43973 -43974 -43975 -43976 -43977 -43978 -43979 -43980 -43981 -43982 -43983 -43984 -43985 -43986 -43987 -43988 -43989 -43990 -43991 -43992 -43993 -43994 -43995 -43996 -43997 -43998 -43999 -44000 -44001 -44002 -44003 -44004 -44005 -44006 -44007 -44008 -44009 -44010 -44011 -44012 -44013 -44014 -44015 -44016 -44017 -44018 -44019 -44020 -44021 -44022 -44023 -44024 -44025 -44026 -44027 -44028 -44029 -44030 -44031 -44032 -44033 -44034 -44035 -44036 -44037 -44038 -44039 -44040 -44041 -44042 -44043 -44044 -44045 -44046 -44047 -44048 -44049 -44050 -44051 -44052 -44053 -44054 -44055 -44056 -44057 -44058 -44059 -44060 -44061 -44062 -44063 -44064 -44065 -44066 -44067 -44068 -44069 -44070 -44071 -44072 -44073 -44074 -44075 -44076 -44077 -44078 -44079 -44080 -44081 -44082 -44083 -44084 -44085 -44086 -44087 -44088 -44089 -44090 -44091 -44092 -44093 -44094 -44095 -44096 -44097 -44098 -44099 -44100 -44101 -44102 -44103 -44104 -44105 -44106 -44107 -44108 -44109 -44110 -44111 -44112 -44113 -44114 -44115 -44116 -44117 -44118 -44119 -44120 -44121 -44122 -44123 -44124 -44125 -44126 -44127 -44128 -44129 -44130 -44131 -44132 -44133 -44134 -44135 -44136 -44137 -44138 -44139 -44140 -44141 -44142 -44143 -44144 -44145 -44146 -44147 -44148 -44149 -44150 -44151 -44152 -44153 -44154 -44155 -44156 -44157 -44158 -44159 -44160 -44161 -44162 -44163 -44164 -44165 -44166 -44167 -44168 -44169 -44170 -44171 -44172 -44173 -44174 -44175 -44176 -44177 -44178 -44179 -44180 -44181 -44182 -44183 -44184 -44185 -44186 -44187 -44188 -44189 -44190 -44191 -44192 -44193 -44194 -44195 -44196 -44197 -44198 -44199 -44200 -44201 -44202 -44203 -44204 -44205 -44206 -44207 -44208 -44209 -44210 -44211 -44212 -44213 -44214 -44215 -44216 -44217 -44218 -44219 -44220 -44221 -44222 -44223 -44224 -44225 -44226 -44227 -44228 -44229 -44230 -44231 -44232 -44233 -44234 -44235 -44236 -44237 -44238 -44239 -44240 -44241 -44242 -44243 -44244 -44245 -44246 -44247 -44248 -44249 -44250 -44251 -44252 -44253 -44254 -44255 -44256 -44257 -44258 -44259 -44260 -44261 -44262 -44263 -44264 -44265 -44266 -44267 -44268 -44269 -44270 -44271 -44272 -44273 -44274 -44275 -44276 -44277 -44278 -44279 -44280 -44281 -44282 -44283 -44284 -44285 -44286 -44287 -44288 -44289 -44290 -44291 -44292 -44293 -44294 -44295 -44296 -44297 -44298 -44299 -44300 -44301 -44302 -44303 -44304 -44305 -44306 -44307 -44308 -44309 -44310 -44311 -44312 -44313 -44314 -44315 -44316 -44317 -44318 -44319 -44320 -44321 -44322 -44323 -44324 -44325 -44326 -44327 -44328 -44329 -44330 -44331 -44332 -44333 -44334 -44335 -44336 -44337 -44338 -44339 -44340 -44341 -44342 -44343 -44344 -44345 -44346 -44347 -44348 -44349 -44350 -44351 -44352 -44353 -44354 -44355 -44356 -44357 -44358 -44359 -44360 -44361 -44362 -44363 -44364 -44365 -44366 -44367 -44368 -44369 -44370 -44371 -44372 -44373 -44374 -44375 -44376 -44377 -44378 -44379 -44380 -44381 -44382 -44383 -44384 -44385 -44386 -44387 -44388 -44389 -44390 -44391 -44392 -44393 -44394 -44395 -44396 -44397 -44398 -44399 -44400 -44401 -44402 -44403 -44404 -44405 -44406 -44407 -44408 -44409 -44410 -44411 -44412 -44413 -44414 -44415 -44416 -44417 -44418 -44419 -44420 -44421 -44422 -44423 -44424 -44425 -44426 -44427 -44428 -44429 -44430 -44431 -44432 -44433 -44434 -44435 -44436 -44437 -44438 -44439 -44440 -44441 -44442 -44443 -44444 -44445 -44446 -44447 -44448 -44449 -44450 -44451 -44452 -44453 -44454 -44455 -44456 -44457 -44458 -44459 -44460 -44461 -44462 -44463 -44464 -44465 -44466 -44467 -44468 -44469 -44470 -44471 -44472 -44473 -44474 -44475 -44476 -44477 -44478 -44479 -44480 -44481 -44482 -44483 -44484 -44485 -44486 -44487 -44488 -44489 -44490 -44491 -44492 -44493 -44494 -44495 -44496 -44497 -44498 -44499 -44500 -44501 -44502 -44503 -44504 -44505 -44506 -44507 -44508 -44509 -44510 -44511 -44512 -44513 -44514 -44515 -44516 -44517 -44518 -44519 -44520 -44521 -44522 -44523 -44524 -44525 -44526 -44527 -44528 -44529 -44530 -44531 -44532 -44533 -44534 -44535 -44536 -44537 -44538 -44539 -44540 -44541 -44542 -44543 -44544 -44545 -44546 -44547 -44548 -44549 -44550 -44551 -44552 -44553 -44554 -44555 -44556 -44557 -44558 -44559 -44560 -44561 -44562 -44563 -44564 -44565 -44566 -44567 -44568 -44569 -44570 -44571 -44572 -44573 -44574 -44575 -44576 -44577 -44578 -44579 -44580 -44581 -44582 -44583 -44584 -44585 -44586 -44587 -44588 -44589 -44590 -44591 -44592 -44593 -44594 -44595 -44596 -44597 -44598 -44599 -44600 -44601 -44602 -44603 -44604 -44605 -44606 -44607 -44608 -44609 -44610 -44611 -44612 -44613 -44614 -44615 -44616 -44617 -44618 -44619 -44620 -44621 -44622 -44623 -44624 -44625 -44626 -44627 -44628 -44629 -44630 -44631 -44632 -44633 -44634 -44635 -44636 -44637 -44638 -44639 -44640 -44641 -44642 -44643 -44644 -44645 -44646 -44647 -44648 -44649 -44650 -44651 -44652 -44653 -44654 -44655 -44656 -44657 -44658 -44659 -44660 -44661 -44662 -44663 -44664 -44665 -44666 -44667 -44668 -44669 -44670 -44671 -44672 -44673 -44674 -44675 -44676 -44677 -44678 -44679 -44680 -44681 -44682 -44683 -44684 -44685 -44686 -44687 -44688 -44689 -44690 -44691 -44692 -44693 -44694 -44695 -44696 -44697 -44698 -44699 -44700 -44701 -44702 -44703 -44704 -44705 -44706 -44707 -44708 -44709 -44710 -44711 -44712 -44713 -44714 -44715 -44716 -44717 -44718 -44719 -44720 -44721 -44722 -44723 -44724 -44725 -44726 -44727 -44728 -44729 -44730 -44731 -44732 -44733 -44734 -44735 -44736 -44737 -44738 -44739 -44740 -44741 -44742 -44743 -44744 -44745 -44746 -44747 -44748 -44749 -44750 -44751 -44752 -44753 -44754 -44755 -44756 -44757 -44758 -44759 -44760 -44761 -44762 -44763 -44764 -44765 -44766 -44767 -44768 -44769 -44770 -44771 -44772 -44773 -44774 -44775 -44776 -44777 -44778 -44779 -44780 -44781 -44782 -44783 -44784 -44785 -44786 -44787 -44788 -44789 -44790 -44791 -44792 -44793 -44794 -44795 -44796 -44797 -44798 -44799 -44800 -44801 -44802 -44803 -44804 -44805 -44806 -44807 -44808 -44809 -44810 -44811 -44812 -44813 -44814 -44815 -44816 -44817 -44818 -44819 -44820 -44821 -44822 -44823 -44824 -44825 -44826 -44827 -44828 -44829 -44830 -44831 -44832 -44833 -44834 -44835 -44836 -44837 -44838 -44839 -44840 -44841 -44842 -44843 -44844 -44845 -44846 -44847 -44848 -44849 -44850 -44851 -44852 -44853 -44854 -44855 -44856 -44857 -44858 -44859 -44860 -44861 -44862 -44863 -44864 -44865 -44866 -44867 -44868 -44869 -44870 -44871 -44872 -44873 -44874 -44875 -44876 -44877 -44878 -44879 -44880 -44881 -44882 -44883 -44884 -44885 -44886 -44887 -44888 -44889 -44890 -44891 -44892 -44893 -44894 -44895 -44896 -44897 -44898 -44899 -44900 -44901 -44902 -44903 -44904 -44905 -44906 -44907 -44908 -44909 -44910 -44911 -44912 -44913 -44914 -44915 -44916 -44917 -44918 -44919 -44920 -44921 -44922 -44923 -44924 -44925 -44926 -44927 -44928 -44929 -44930 -44931 -44932 -44933 -44934 -44935 -44936 -44937 -44938 -44939 -44940 -44941 -44942 -44943 -44944 -44945 -44946 -44947 -44948 -44949 -44950 -44951 -44952 -44953 -44954 -44955 -44956 -44957 -44958 -44959 -44960 -44961 -44962 -44963 -44964 -44965 -44966 -44967 -44968 -44969 -44970 -44971 -44972 -44973 -44974 -44975 -44976 -44977 -44978 -44979 -44980 -44981 -44982 -44983 -44984 -44985 -44986 -44987 -44988 -44989 -44990 -44991 -44992 -44993 -44994 -44995 -44996 -44997 -44998 -44999 -45000 -45001 -45002 -45003 -45004 -45005 -45006 -45007 -45008 -45009 -45010 -45011 -45012 -45013 -45014 -45015 -45016 -45017 -45018 -45019 -45020 -45021 -45022 -45023 -45024 -45025 -45026 -45027 -45028 -45029 -45030 -45031 -45032 -45033 -45034 -45035 -45036 -45037 -45038 -45039 -45040 -45041 -45042 -45043 -45044 -45045 -45046 -45047 -45048 -45049 -45050 -45051 -45052 -45053 -45054 -45055 -45056 -45057 -45058 -45059 -45060 -45061 -45062 -45063 -45064 -45065 -45066 -45067 -45068 -45069 -45070 -45071 -45072 -45073 -45074 -45075 -45076 -45077 -45078 -45079 -45080 -45081 -45082 -45083 -45084 -45085 -45086 -45087 -45088 -45089 -45090 -45091 -45092 -45093 -45094 -45095 -45096 -45097 -45098 -45099 -45100 -45101 -45102 -45103 -45104 -45105 -45106 -45107 -45108 -45109 -45110 -45111 -45112 -45113 -45114 -45115 -45116 -45117 -45118 -45119 -45120 -45121 -45122 -45123 -45124 -45125 -45126 -45127 -45128 -45129 -45130 -45131 -45132 -45133 -45134 -45135 -45136 -45137 -45138 -45139 -45140 -45141 -45142 -45143 -45144 -45145 -45146 -45147 -45148 -45149 -45150 -45151 -45152 -45153 -45154 -45155 -45156 -45157 -45158 -45159 -45160 -45161 -45162 -45163 -45164 -45165 -45166 -45167 -45168 -45169 -45170 -45171 -45172 -45173 -45174 -45175 -45176 -45177 -45178 -45179 -45180 -45181 -45182 -45183 -45184 -45185 -45186 -45187 -45188 -45189 -45190 -45191 -45192 -45193 -45194 -45195 -45196 -45197 -45198 -45199 -45200 -45201 -45202 -45203 -45204 -45205 -45206 -45207 -45208 -45209 -45210 -45211 -45212 -45213 -45214 -45215 -45216 -45217 -45218 -45219 -45220 -45221 -45222 -45223 -45224 -45225 -45226 -45227 -45228 -45229 -45230 -45231 -45232 -45233 -45234 -45235 -45236 -45237 -45238 -45239 -45240 -45241 -45242 -45243 -45244 -45245 -45246 -45247 -45248 -45249 -45250 -45251 -45252 -45253 -45254 -45255 -45256 -45257 -45258 -45259 -45260 -45261 -45262 -45263 -45264 -45265 -45266 -45267 -45268 -45269 -45270 -45271 -45272 -45273 -45274 -45275 -45276 -45277 -45278 -45279 -45280 -45281 -45282 -45283 -45284 -45285 -45286 -45287 -45288 -45289 -45290 -45291 -45292 -45293 -45294 -45295 -45296 -45297 -45298 -45299 -45300 -45301 -45302 -45303 -45304 -45305 -45306 -45307 -45308 -45309 -45310 -45311 -45312 -45313 -45314 -45315 -45316 -45317 -45318 -45319 -45320 -45321 -45322 -45323 -45324 -45325 -45326 -45327 -45328 -45329 -45330 -45331 -45332 -45333 -45334 -45335 -45336 -45337 -45338 -45339 -45340 -45341 -45342 -45343 -45344 -45345 -45346 -45347 -45348 -45349 -45350 -45351 -45352 -45353 -45354 -45355 -45356 -45357 -45358 -45359 -45360 -45361 -45362 -45363 -45364 -45365 -45366 -45367 -45368 -45369 -45370 -45371 -45372 -45373 -45374 -45375 -45376 -45377 -45378 -45379 -45380 -45381 -45382 -45383 -45384 -45385 -45386 -45387 -45388 -45389 -45390 -45391 -45392 -45393 -45394 -45395 -45396 -45397 -45398 -45399 -45400 -45401 -45402 -45403 -45404 -45405 -45406 -45407 -45408 -45409 -45410 -45411 -45412 -45413 -45414 -45415 -45416 -45417 -45418 -45419 -45420 -45421 -45422 -45423 -45424 -45425 -45426 -45427 -45428 -45429 -45430 -45431 -45432 -45433 -45434 -45435 -45436 -45437 -45438 -45439 -45440 -45441 -45442 -45443 -45444 -45445 -45446 -45447 -45448 -45449 -45450 -45451 -45452 -45453 -45454 -45455 -45456 -45457 -45458 -45459 -45460 -45461 -45462 -45463 -45464 -45465 -45466 -45467 -45468 -45469 -45470 -45471 -45472 -45473 -45474 -45475 -45476 -45477 -45478 -45479 -45480 -45481 -45482 -45483 -45484 -45485 -45486 -45487 -45488 -45489 -45490 -45491 -45492 -45493 -45494 -45495 -45496 -45497 -45498 -45499 -45500 -45501 -45502 -45503 -45504 -45505 -45506 -45507 -45508 -45509 -45510 -45511 -45512 -45513 -45514 -45515 -45516 -45517 -45518 -45519 -45520 -45521 -45522 -45523 -45524 -45525 -45526 -45527 -45528 -45529 -45530 -45531 -45532 -45533 -45534 -45535 -45536 -45537 -45538 -45539 -45540 -45541 -45542 -45543 -45544 -45545 -45546 -45547 -45548 -45549 -45550 -45551 -45552 -45553 -45554 -45555 -45556 -45557 -45558 -45559 -45560 -45561 -45562 -45563 -45564 -45565 -45566 -45567 -45568 -45569 -45570 -45571 -45572 -45573 -45574 -45575 -45576 -45577 -45578 -45579 -45580 -45581 -45582 -45583 -45584 -45585 -45586 -45587 -45588 -45589 -45590 -45591 -45592 -45593 -45594 -45595 -45596 -45597 -45598 -45599 -45600 -45601 -45602 -45603 -45604 -45605 -45606 -45607 -45608 -45609 -45610 -45611 -45612 -45613 -45614 -45615 -45616 -45617 -45618 -45619 -45620 -45621 -45622 -45623 -45624 -45625 -45626 -45627 -45628 -45629 -45630 -45631 -45632 -45633 -45634 -45635 -45636 -45637 -45638 -45639 -45640 -45641 -45642 -45643 -45644 -45645 -45646 -45647 -45648 -45649 -45650 -45651 -45652 -45653 -45654 -45655 -45656 -45657 -45658 -45659 -45660 -45661 -45662 -45663 -45664 -45665 -45666 -45667 -45668 -45669 -45670 -45671 -45672 -45673 -45674 -45675 -45676 -45677 -45678 -45679 -45680 -45681 -45682 -45683 -45684 -45685 -45686 -45687 -45688 -45689 -45690 -45691 -45692 -45693 -45694 -45695 -45696 -45697 -45698 -45699 -45700 -45701 -45702 -45703 -45704 -45705 -45706 -45707 -45708 -45709 -45710 -45711 -45712 -45713 -45714 -45715 -45716 -45717 -45718 -45719 -45720 -45721 -45722 -45723 -45724 -45725 -45726 -45727 -45728 -45729 -45730 -45731 -45732 -45733 -45734 -45735 -45736 -45737 -45738 -45739 -45740 -45741 -45742 -45743 -45744 -45745 -45746 -45747 -45748 -45749 -45750 -45751 -45752 -45753 -45754 -45755 -45756 -45757 -45758 -45759 -45760 -45761 -45762 -45763 -45764 -45765 -45766 -45767 -45768 -45769 -45770 -45771 -45772 -45773 -45774 -45775 -45776 -45777 -45778 -45779 -45780 -45781 -45782 -45783 -45784 -45785 -45786 -45787 -45788 -45789 -45790 -45791 -45792 -45793 -45794 -45795 -45796 -45797 -45798 -45799 -45800 -45801 -45802 -45803 -45804 -45805 -45806 -45807 -45808 -45809 -45810 -45811 -45812 -45813 -45814 -45815 -45816 -45817 -45818 -45819 -45820 -45821 -45822 -45823 -45824 -45825 -45826 -45827 -45828 -45829 -45830 -45831 -45832 -45833 -45834 -45835 -45836 -45837 -45838 -45839 -45840 -45841 -45842 -45843 -45844 -45845 -45846 -45847 -45848 -45849 -45850 -45851 -45852 -45853 -45854 -45855 -45856 -45857 -45858 -45859 -45860 -45861 -45862 -45863 -45864 -45865 -45866 -45867 -45868 -45869 -45870 -45871 -45872 -45873 -45874 -45875 -45876 -45877 -45878 -45879 -45880 -45881 -45882 -45883 -45884 -45885 -45886 -45887 -45888 -45889 -45890 -45891 -45892 -45893 -45894 -45895 -45896 -45897 -45898 -45899 -45900 -45901 -45902 -45903 -45904 -45905 -45906 -45907 -45908 -45909 -45910 -45911 -45912 -45913 -45914 -45915 -45916 -45917 -45918 -45919 -45920 -45921 -45922 -45923 -45924 -45925 -45926 -45927 -45928 -45929 -45930 -45931 -45932 -45933 -45934 -45935 -45936 -45937 -45938 -45939 -45940 -45941 -45942 -45943 -45944 -45945 -45946 -45947 -45948 -45949 -45950 -45951 -45952 -45953 -45954 -45955 -45956 -45957 -45958 -45959 -45960 -45961 -45962 -45963 -45964 -45965 -45966 -45967 -45968 -45969 -45970 -45971 -45972 -45973 -45974 -45975 -45976 -45977 -45978 -45979 -45980 -45981 -45982 -45983 -45984 -45985 -45986 -45987 -45988 -45989 -45990 -45991 -45992 -45993 -45994 -45995 -45996 -45997 -45998 -45999 -46000 -46001 -46002 -46003 -46004 -46005 -46006 -46007 -46008 -46009 -46010 -46011 -46012 -46013 -46014 -46015 -46016 -46017 -46018 -46019 -46020 -46021 -46022 -46023 -46024 -46025 -46026 -46027 -46028 -46029 -46030 -46031 -46032 -46033 -46034 -46035 -46036 -46037 -46038 -46039 -46040 -46041 -46042 -46043 -46044 -46045 -46046 -46047 -46048 -46049 -46050 -46051 -46052 -46053 -46054 -46055 -46056 -46057 -46058 -46059 -46060 -46061 -46062 -46063 -46064 -46065 -46066 -46067 -46068 -46069 -46070 -46071 -46072 -46073 -46074 -46075 -46076 -46077 -46078 -46079 -46080 -46081 -46082 -46083 -46084 -46085 -46086 -46087 -46088 -46089 -46090 -46091 -46092 -46093 -46094 -46095 -46096 -46097 -46098 -46099 -46100 -46101 -46102 -46103 -46104 -46105 -46106 -46107 -46108 -46109 -46110 -46111 -46112 -46113 -46114 -46115 -46116 -46117 -46118 -46119 -46120 -46121 -46122 -46123 -46124 -46125 -46126 -46127 -46128 -46129 -46130 -46131 -46132 -46133 -46134 -46135 -46136 -46137 -46138 -46139 -46140 -46141 -46142 -46143 -46144 -46145 -46146 -46147 -46148 -46149 -46150 -46151 -46152 -46153 -46154 -46155 -46156 -46157 -46158 -46159 -46160 -46161 -46162 -46163 -46164 -46165 -46166 -46167 -46168 -46169 -46170 -46171 -46172 -46173 -46174 -46175 -46176 -46177 -46178 -46179 -46180 -46181 -46182 -46183 -46184 -46185 -46186 -46187 -46188 -46189 -46190 -46191 -46192 -46193 -46194 -46195 -46196 -46197 -46198 -46199 -46200 -46201 -46202 -46203 -46204 -46205 -46206 -46207 -46208 -46209 -46210 -46211 -46212 -46213 -46214 -46215 -46216 -46217 -46218 -46219 -46220 -46221 -46222 -46223 -46224 -46225 -46226 -46227 -46228 -46229 -46230 -46231 -46232 -46233 -46234 -46235 -46236 -46237 -46238 -46239 -46240 -46241 -46242 -46243 -46244 -46245 -46246 -46247 -46248 -46249 -46250 -46251 -46252 -46253 -46254 -46255 -46256 -46257 -46258 -46259 -46260 -46261 -46262 -46263 -46264 -46265 -46266 -46267 -46268 -46269 -46270 -46271 -46272 -46273 -46274 -46275 -46276 -46277 -46278 -46279 -46280 -46281 -46282 -46283 -46284 -46285 -46286 -46287 -46288 -46289 -46290 -46291 -46292 -46293 -46294 -46295 -46296 -46297 -46298 -46299 -46300 -46301 -46302 -46303 -46304 -46305 -46306 -46307 -46308 -46309 -46310 -46311 -46312 -46313 -46314 -46315 -46316 -46317 -46318 -46319 -46320 -46321 -46322 -46323 -46324 -46325 -46326 -46327 -46328 -46329 -46330 -46331 -46332 -46333 -46334 -46335 -46336 -46337 -46338 -46339 -46340 -46341 -46342 -46343 -46344 -46345 -46346 -46347 -46348 -46349 -46350 -46351 -46352 -46353 -46354 -46355 -46356 -46357 -46358 -46359 -46360 -46361 -46362 -46363 -46364 -46365 -46366 -46367 -46368 -46369 -46370 -46371 -46372 -46373 -46374 -46375 -46376 -46377 -46378 -46379 -46380 -46381 -46382 -46383 -46384 -46385 -46386 -46387 -46388 -46389 -46390 -46391 -46392 -46393 -46394 -46395 -46396 -46397 -46398 -46399 -46400 -46401 -46402 -46403 -46404 -46405 -46406 -46407 -46408 -46409 -46410 -46411 -46412 -46413 -46414 -46415 -46416 -46417 -46418 -46419 -46420 -46421 -46422 -46423 -46424 -46425 -46426 -46427 -46428 -46429 -46430 -46431 -46432 -46433 -46434 -46435 -46436 -46437 -46438 -46439 -46440 -46441 -46442 -46443 -46444 -46445 -46446 -46447 -46448 -46449 -46450 -46451 -46452 -46453 -46454 -46455 -46456 -46457 -46458 -46459 -46460 -46461 -46462 -46463 -46464 -46465 -46466 -46467 -46468 -46469 -46470 -46471 -46472 -46473 -46474 -46475 -46476 -46477 -46478 -46479 -46480 -46481 -46482 -46483 -46484 -46485 -46486 -46487 -46488 -46489 -46490 -46491 -46492 -46493 -46494 -46495 -46496 -46497 -46498 -46499 -46500 -46501 -46502 -46503 -46504 -46505 -46506 -46507 -46508 -46509 -46510 -46511 -46512 -46513 -46514 -46515 -46516 -46517 -46518 -46519 -46520 -46521 -46522 -46523 -46524 -46525 -46526 -46527 -46528 -46529 -46530 -46531 -46532 -46533 -46534 -46535 -46536 -46537 -46538 -46539 -46540 -46541 -46542 -46543 -46544 -46545 -46546 -46547 -46548 -46549 -46550 -46551 -46552 -46553 -46554 -46555 -46556 -46557 -46558 -46559 -46560 -46561 -46562 -46563 -46564 -46565 -46566 -46567 -46568 -46569 -46570 -46571 -46572 -46573 -46574 -46575 -46576 -46577 -46578 -46579 -46580 -46581 -46582 -46583 -46584 -46585 -46586 -46587 -46588 -46589 -46590 -46591 -46592 -46593 -46594 -46595 -46596 -46597 -46598 -46599 -46600 -46601 -46602 -46603 -46604 -46605 -46606 -46607 -46608 -46609 -46610 -46611 -46612 -46613 -46614 -46615 -46616 -46617 -46618 -46619 -46620 -46621 -46622 -46623 -46624 -46625 -46626 -46627 -46628 -46629 -46630 -46631 -46632 -46633 -46634 -46635 -46636 -46637 -46638 -46639 -46640 -46641 -46642 -46643 -46644 -46645 -46646 -46647 -46648 -46649 -46650 -46651 -46652 -46653 -46654 -46655 -46656 -46657 -46658 -46659 -46660 -46661 -46662 -46663 -46664 -46665 -46666 -46667 -46668 -46669 -46670 -46671 -46672 -46673 -46674 -46675 -46676 -46677 -46678 -46679 -46680 -46681 -46682 -46683 -46684 -46685 -46686 -46687 -46688 -46689 -46690 -46691 -46692 -46693 -46694 -46695 -46696 -46697 -46698 -46699 -46700 -46701 -46702 -46703 -46704 -46705 -46706 -46707 -46708 -46709 -46710 -46711 -46712 -46713 -46714 -46715 -46716 -46717 -46718 -46719 -46720 -46721 -46722 -46723 -46724 -46725 -46726 -46727 -46728 -46729 -46730 -46731 -46732 -46733 -46734 -46735 -46736 -46737 -46738 -46739 -46740 -46741 -46742 -46743 -46744 -46745 -46746 -46747 -46748 -46749 -46750 -46751 -46752 -46753 -46754 -46755 -46756 -46757 -46758 -46759 -46760 -46761 -46762 -46763 -46764 -46765 -46766 -46767 -46768 -46769 -46770 -46771 -46772 -46773 -46774 -46775 -46776 -46777 -46778 -46779 -46780 -46781 -46782 -46783 -46784 -46785 -46786 -46787 -46788 -46789 -46790 -46791 -46792 -46793 -46794 -46795 -46796 -46797 -46798 -46799 -46800 -46801 -46802 -46803 -46804 -46805 -46806 -46807 -46808 -46809 -46810 -46811 -46812 -46813 -46814 -46815 -46816 -46817 -46818 -46819 -46820 -46821 -46822 -46823 -46824 -46825 -46826 -46827 -46828 -46829 -46830 -46831 -46832 -46833 -46834 -46835 -46836 -46837 -46838 -46839 -46840 -46841 -46842 -46843 -46844 -46845 -46846 -46847 -46848 -46849 -46850 -46851 -46852 -46853 -46854 -46855 -46856 -46857 -46858 -46859 -46860 -46861 -46862 -46863 -46864 -46865 -46866 -46867 -46868 -46869 -46870 -46871 -46872 -46873 -46874 -46875 -46876 -46877 -46878 -46879 -46880 -46881 -46882 -46883 -46884 -46885 -46886 -46887 -46888 -46889 -46890 -46891 -46892 -46893 -46894 -46895 -46896 -46897 -46898 -46899 -46900 -46901 -46902 -46903 -46904 -46905 -46906 -46907 -46908 -46909 -46910 -46911 -46912 -46913 -46914 -46915 -46916 -46917 -46918 -46919 -46920 -46921 -46922 -46923 -46924 -46925 -46926 -46927 -46928 -46929 -46930 -46931 -46932 -46933 -46934 -46935 -46936 -46937 -46938 -46939 -46940 -46941 -46942 -46943 -46944 -46945 -46946 -46947 -46948 -46949 -46950 -46951 -46952 -46953 -46954 -46955 -46956 -46957 -46958 -46959 -46960 -46961 -46962 -46963 -46964 -46965 -46966 -46967 -46968 -46969 -46970 -46971 -46972 -46973 -46974 -46975 -46976 -46977 -46978 -46979 -46980 -46981 -46982 -46983 -46984 -46985 -46986 -46987 -46988 -46989 -46990 -46991 -46992 -46993 -46994 -46995 -46996 -46997 -46998 -46999 -47000 -47001 -47002 -47003 -47004 -47005 -47006 -47007 -47008 -47009 -47010 -47011 -47012 -47013 -47014 -47015 -47016 -47017 -47018 -47019 -47020 -47021 -47022 -47023 -47024 -47025 -47026 -47027 -47028 -47029 -47030 -47031 -47032 -47033 -47034 -47035 -47036 -47037 -47038 -47039 -47040 -47041 -47042 -47043 -47044 -47045 -47046 -47047 -47048 -47049 -47050 -47051 -47052 -47053 -47054 -47055 -47056 -47057 -47058 -47059 -47060 -47061 -47062 -47063 -47064 -47065 -47066 -47067 -47068 -47069 -47070 -47071 -47072 -47073 -47074 -47075 -47076 -47077 -47078 -47079 -47080 -47081 -47082 -47083 -47084 -47085 -47086 -47087 -47088 -47089 -47090 -47091 -47092 -47093 -47094 -47095 -47096 -47097 -47098 -47099 -47100 -47101 -47102 -47103 -47104 -47105 -47106 -47107 -47108 -47109 -47110 -47111 -47112 -47113 -47114 -47115 -47116 -47117 -47118 -47119 -47120 -47121 -47122 -47123 -47124 -47125 -47126 -47127 -47128 -47129 -47130 -47131 -47132 -47133 -47134 -47135 -47136 -47137 -47138 -47139 -47140 -47141 -47142 -47143 -47144 -47145 -47146 -47147 -47148 -47149 -47150 -47151 -47152 -47153 -47154 -47155 -47156 -47157 -47158 -47159 -47160 -47161 -47162 -47163 -47164 -47165 -47166 -47167 -47168 -47169 -47170 -47171 -47172 -47173 -47174 -47175 -47176 -47177 -47178 -47179 -47180 -47181 -47182 -47183 -47184 -47185 -47186 -47187 -47188 -47189 -47190 -47191 -47192 -47193 -47194 -47195 -47196 -47197 -47198 -47199 -47200 -47201 -47202 -47203 -47204 -47205 -47206 -47207 -47208 -47209 -47210 -47211 -47212 -47213 -47214 -47215 -47216 -47217 -47218 -47219 -47220 -47221 -47222 -47223 -47224 -47225 -47226 -47227 -47228 -47229 -47230 -47231 -47232 -47233 -47234 -47235 -47236 -47237 -47238 -47239 -47240 -47241 -47242 -47243 -47244 -47245 -47246 -47247 -47248 -47249 -47250 -47251 -47252 -47253 -47254 -47255 -47256 -47257 -47258 -47259 -47260 -47261 -47262 -47263 -47264 -47265 -47266 -47267 -47268 -47269 -47270 -47271 -47272 -47273 -47274 -47275 -47276 -47277 -47278 -47279 -47280 -47281 -47282 -47283 -47284 -47285 -47286 -47287 -47288 -47289 -47290 -47291 -47292 -47293 -47294 -47295 -47296 -47297 -47298 -47299 -47300 -47301 -47302 -47303 -47304 -47305 -47306 -47307 -47308 -47309 -47310 -47311 -47312 -47313 -47314 -47315 -47316 -47317 -47318 -47319 -47320 -47321 -47322 -47323 -47324 -47325 -47326 -47327 -47328 -47329 -47330 -47331 -47332 -47333 -47334 -47335 -47336 -47337 -47338 -47339 -47340 -47341 -47342 -47343 -47344 -47345 -47346 -47347 -47348 -47349 -47350 -47351 -47352 -47353 -47354 -47355 -47356 -47357 -47358 -47359 -47360 -47361 -47362 -47363 -47364 -47365 -47366 -47367 -47368 -47369 -47370 -47371 -47372 -47373 -47374 -47375 -47376 -47377 -47378 -47379 -47380 -47381 -47382 -47383 -47384 -47385 -47386 -47387 -47388 -47389 -47390 -47391 -47392 -47393 -47394 -47395 -47396 -47397 -47398 -47399 -47400 -47401 -47402 -47403 -47404 -47405 -47406 -47407 -47408 -47409 -47410 -47411 -47412 -47413 -47414 -47415 -47416 -47417 -47418 -47419 -47420 -47421 -47422 -47423 -47424 -47425 -47426 -47427 -47428 -47429 -47430 -47431 -47432 -47433 -47434 -47435 -47436 -47437 -47438 -47439 -47440 -47441 -47442 -47443 -47444 -47445 -47446 -47447 -47448 -47449 -47450 -47451 -47452 -47453 -47454 -47455 -47456 -47457 -47458 -47459 -47460 -47461 -47462 -47463 -47464 -47465 -47466 -47467 -47468 -47469 -47470 -47471 -47472 -47473 -47474 -47475 -47476 -47477 -47478 -47479 -47480 -47481 -47482 -47483 -47484 -47485 -47486 -47487 -47488 -47489 -47490 -47491 -47492 -47493 -47494 -47495 -47496 -47497 -47498 -47499 -47500 -47501 -47502 -47503 -47504 -47505 -47506 -47507 -47508 -47509 -47510 -47511 -47512 -47513 -47514 -47515 -47516 -47517 -47518 -47519 -47520 -47521 -47522 -47523 -47524 -47525 -47526 -47527 -47528 -47529 -47530 -47531 -47532 -47533 -47534 -47535 -47536 -47537 -47538 -47539 -47540 -47541 -47542 -47543 -47544 -47545 -47546 -47547 -47548 -47549 -47550 -47551 -47552 -47553 -47554 -47555 -47556 -47557 -47558 -47559 -47560 -47561 -47562 -47563 -47564 -47565 -47566 -47567 -47568 -47569 -47570 -47571 -47572 -47573 -47574 -47575 -47576 -47577 -47578 -47579 -47580 -47581 -47582 -47583 -47584 -47585 -47586 -47587 -47588 -47589 -47590 -47591 -47592 -47593 -47594 -47595 -47596 -47597 -47598 -47599 -47600 -47601 -47602 -47603 -47604 -47605 -47606 -47607 -47608 -47609 -47610 -47611 -47612 -47613 -47614 -47615 -47616 -47617 -47618 -47619 -47620 -47621 -47622 -47623 -47624 -47625 -47626 -47627 -47628 -47629 -47630 -47631 -47632 -47633 -47634 -47635 -47636 -47637 -47638 -47639 -47640 -47641 -47642 -47643 -47644 -47645 -47646 -47647 -47648 -47649 -47650 -47651 -47652 -47653 -47654 -47655 -47656 -47657 -47658 -47659 -47660 -47661 -47662 -47663 -47664 -47665 -47666 -47667 -47668 -47669 -47670 -47671 -47672 -47673 -47674 -47675 -47676 -47677 -47678 -47679 -47680 -47681 -47682 -47683 -47684 -47685 -47686 -47687 -47688 -47689 -47690 -47691 -47692 -47693 -47694 -47695 -47696 -47697 -47698 -47699 -47700 -47701 -47702 -47703 -47704 -47705 -47706 -47707 -47708 -47709 -47710 -47711 -47712 -47713 -47714 -47715 -47716 -47717 -47718 -47719 -47720 -47721 -47722 -47723 -47724 -47725 -47726 -47727 -47728 -47729 -47730 -47731 -47732 -47733 -47734 -47735 -47736 -47737 -47738 -47739 -47740 -47741 -47742 -47743 -47744 -47745 -47746 -47747 -47748 -47749 -47750 -47751 -47752 -47753 -47754 -47755 -47756 -47757 -47758 -47759 -47760 -47761 -47762 -47763 -47764 -47765 -47766 -47767 -47768 -47769 -47770 -47771 -47772 -47773 -47774 -47775 -47776 -47777 -47778 -47779 -47780 -47781 -47782 -47783 -47784 -47785 -47786 -47787 -47788 -47789 -47790 -47791 -47792 -47793 -47794 -47795 -47796 -47797 -47798 -47799 -47800 -47801 -47802 -47803 -47804 -47805 -47806 -47807 -47808 -47809 -47810 -47811 -47812 -47813 -47814 -47815 -47816 -47817 -47818 -47819 -47820 -47821 -47822 -47823 -47824 -47825 -47826 -47827 -47828 -47829 -47830 -47831 -47832 -47833 -47834 -47835 -47836 -47837 -47838 -47839 -47840 -47841 -47842 -47843 -47844 -47845 -47846 -47847 -47848 -47849 -47850 -47851 -47852 -47853 -47854 -47855 -47856 -47857 -47858 -47859 -47860 -47861 -47862 -47863 -47864 -47865 -47866 -47867 -47868 -47869 -47870 -47871 -47872 -47873 -47874 -47875 -47876 -47877 -47878 -47879 -47880 -47881 -47882 -47883 -47884 -47885 -47886 -47887 -47888 -47889 -47890 -47891 -47892 -47893 -47894 -47895 -47896 -47897 -47898 -47899 -47900 -47901 -47902 -47903 -47904 -47905 -47906 -47907 -47908 -47909 -47910 -47911 -47912 -47913 -47914 -47915 -47916 -47917 -47918 -47919 -47920 -47921 -47922 -47923 -47924 -47925 -47926 -47927 -47928 -47929 -47930 -47931 -47932 -47933 -47934 -47935 -47936 -47937 -47938 -47939 -47940 -47941 -47942 -47943 -47944 -47945 -47946 -47947 -47948 -47949 -47950 -47951 -47952 -47953 -47954 -47955 -47956 -47957 -47958 -47959 -47960 -47961 -47962 -47963 -47964 -47965 -47966 -47967 -47968 -47969 -47970 -47971 -47972 -47973 -47974 -47975 -47976 -47977 -47978 -47979 -47980 -47981 -47982 -47983 -47984 -47985 -47986 -47987 -47988 -47989 -47990 -47991 -47992 -47993 -47994 -47995 -47996 -47997 -47998 -47999 -48000 -48001 -48002 -48003 -48004 -48005 -48006 -48007 -48008 -48009 -48010 -48011 -48012 -48013 -48014 -48015 -48016 -48017 -48018 -48019 -48020 -48021 -48022 -48023 -48024 -48025 -48026 -48027 -48028 -48029 -48030 -48031 -48032 -48033 -48034 -48035 -48036 -48037 -48038 -48039 -48040 -48041 -48042 -48043 -48044 -48045 -48046 -48047 -48048 -48049 -48050 -48051 -48052 -48053 -48054 -48055 -48056 -48057 -48058 -48059 -48060 -48061 -48062 -48063 -48064 -48065 -48066 -48067 -48068 -48069 -48070 -48071 -48072 -48073 -48074 -48075 -48076 -48077 -48078 -48079 -48080 -48081 -48082 -48083 -48084 -48085 -48086 -48087 -48088 -48089 -48090 -48091 -48092 -48093 -48094 -48095 -48096 -48097 -48098 -48099 -48100 -48101 -48102 -48103 -48104 -48105 -48106 -48107 -48108 -48109 -48110 -48111 -48112 -48113 -48114 -48115 -48116 -48117 -48118 -48119 -48120 -48121 -48122 -48123 -48124 -48125 -48126 -48127 -48128 -48129 -48130 -48131 -48132 -48133 -48134 -48135 -48136 -48137 -48138 -48139 -48140 -48141 -48142 -48143 -48144 -48145 -48146 -48147 -48148 -48149 -48150 -48151 -48152 -48153 -48154 -48155 -48156 -48157 -48158 -48159 -48160 -48161 -48162 -48163 -48164 -48165 -48166 -48167 -48168 -48169 -48170 -48171 -48172 -48173 -48174 -48175 -48176 -48177 -48178 -48179 -48180 -48181 -48182 -48183 -48184 -48185 -48186 -48187 -48188 -48189 -48190 -48191 -48192 -48193 -48194 -48195 -48196 -48197 -48198 -48199 -48200 -48201 -48202 -48203 -48204 -48205 -48206 -48207 -48208 -48209 -48210 -48211 -48212 -48213 -48214 -48215 -48216 -48217 -48218 -48219 -48220 -48221 -48222 -48223 -48224 -48225 -48226 -48227 -48228 -48229 -48230 -48231 -48232 -48233 -48234 -48235 -48236 -48237 -48238 -48239 -48240 -48241 -48242 -48243 -48244 -48245 -48246 -48247 -48248 -48249 -48250 -48251 -48252 -48253 -48254 -48255 -48256 -48257 -48258 -48259 -48260 -48261 -48262 -48263 -48264 -48265 -48266 -48267 -48268 -48269 -48270 -48271 -48272 -48273 -48274 -48275 -48276 -48277 -48278 -48279 -48280 -48281 -48282 -48283 -48284 -48285 -48286 -48287 -48288 -48289 -48290 -48291 -48292 -48293 -48294 -48295 -48296 -48297 -48298 -48299 -48300 -48301 -48302 -48303 -48304 -48305 -48306 -48307 -48308 -48309 -48310 -48311 -48312 -48313 -48314 -48315 -48316 -48317 -48318 -48319 -48320 -48321 -48322 -48323 -48324 -48325 -48326 -48327 -48328 -48329 -48330 -48331 -48332 -48333 -48334 -48335 -48336 -48337 -48338 -48339 -48340 -48341 -48342 -48343 -48344 -48345 -48346 -48347 -48348 -48349 -48350 -48351 -48352 -48353 -48354 -48355 -48356 -48357 -48358 -48359 -48360 -48361 -48362 -48363 -48364 -48365 -48366 -48367 -48368 -48369 -48370 -48371 -48372 -48373 -48374 -48375 -48376 -48377 -48378 -48379 -48380 -48381 -48382 -48383 -48384 -48385 -48386 -48387 -48388 -48389 -48390 -48391 -48392 -48393 -48394 -48395 -48396 -48397 -48398 -48399 -48400 -48401 -48402 -48403 -48404 -48405 -48406 -48407 -48408 -48409 -48410 -48411 -48412 -48413 -48414 -48415 -48416 -48417 -48418 -48419 -48420 -48421 -48422 -48423 -48424 -48425 -48426 -48427 -48428 -48429 -48430 -48431 -48432 -48433 -48434 -48435 -48436 -48437 -48438 -48439 -48440 -48441 -48442 -48443 -48444 -48445 -48446 -48447 -48448 -48449 -48450 -48451 -48452 -48453 -48454 -48455 -48456 -48457 -48458 -48459 -48460 -48461 -48462 -48463 -48464 -48465 -48466 -48467 -48468 -48469 -48470 -48471 -48472 -48473 -48474 -48475 -48476 -48477 -48478 -48479 -48480 -48481 -48482 -48483 -48484 -48485 -48486 -48487 -48488 -48489 -48490 -48491 -48492 -48493 -48494 -48495 -48496 -48497 -48498 -48499 -48500 -48501 -48502 -48503 -48504 -48505 -48506 -48507 -48508 -48509 -48510 -48511 -48512 -48513 -48514 -48515 -48516 -48517 -48518 -48519 -48520 -48521 -48522 -48523 -48524 -48525 -48526 -48527 -48528 -48529 -48530 -48531 -48532 -48533 -48534 -48535 -48536 -48537 -48538 -48539 -48540 -48541 -48542 -48543 -48544 -48545 -48546 -48547 -48548 -48549 -48550 -48551 -48552 -48553 -48554 -48555 -48556 -48557 -48558 -48559 -48560 -48561 -48562 -48563 -48564 -48565 -48566 -48567 -48568 -48569 -48570 -48571 -48572 -48573 -48574 -48575 -48576 -48577 -48578 -48579 -48580 -48581 -48582 -48583 -48584 -48585 -48586 -48587 -48588 -48589 -48590 -48591 -48592 -48593 -48594 -48595 -48596 -48597 -48598 -48599 -48600 -48601 -48602 -48603 -48604 -48605 -48606 -48607 -48608 -48609 -48610 -48611 -48612 -48613 -48614 -48615 -48616 -48617 -48618 -48619 -48620 -48621 -48622 -48623 -48624 -48625 -48626 -48627 -48628 -48629 -48630 -48631 -48632 -48633 -48634 -48635 -48636 -48637 -48638 -48639 -48640 -48641 -48642 -48643 -48644 -48645 -48646 -48647 -48648 -48649 -48650 -48651 -48652 -48653 -48654 -48655 -48656 -48657 -48658 -48659 -48660 -48661 -48662 -48663 -48664 -48665 -48666 -48667 -48668 -48669 -48670 -48671 -48672 -48673 -48674 -48675 -48676 -48677 -48678 -48679 -48680 -48681 -48682 -48683 -48684 -48685 -48686 -48687 -48688 -48689 -48690 -48691 -48692 -48693 -48694 -48695 -48696 -48697 -48698 -48699 -48700 -48701 -48702 -48703 -48704 -48705 -48706 -48707 -48708 -48709 -48710 -48711 -48712 -48713 -48714 -48715 -48716 -48717 -48718 -48719 -48720 -48721 -48722 -48723 -48724 -48725 -48726 -48727 -48728 -48729 -48730 -48731 -48732 -48733 -48734 -48735 -48736 -48737 -48738 -48739 -48740 -48741 -48742 -48743 -48744 -48745 -48746 -48747 -48748 -48749 -48750 -48751 -48752 -48753 -48754 -48755 -48756 -48757 -48758 -48759 -48760 -48761 -48762 -48763 -48764 -48765 -48766 -48767 -48768 -48769 -48770 -48771 -48772 -48773 -48774 -48775 -48776 -48777 -48778 -48779 -48780 -48781 -48782 -48783 -48784 -48785 -48786 -48787 -48788 -48789 -48790 -48791 -48792 -48793 -48794 -48795 -48796 -48797 -48798 -48799 -48800 -48801 -48802 -48803 -48804 -48805 -48806 -48807 -48808 -48809 -48810 -48811 -48812 -48813 -48814 -48815 -48816 -48817 -48818 -48819 -48820 -48821 -48822 -48823 -48824 -48825 -48826 -48827 -48828 -48829 -48830 -48831 -48832 -48833 -48834 -48835 -48836 -48837 -48838 -48839 -48840 -48841 -48842 -48843 -48844 -48845 -48846 -48847 -48848 -48849 -48850 -48851 -48852 -48853 -48854 -48855 -48856 -48857 -48858 -48859 -48860 -48861 -48862 -48863 -48864 -48865 -48866 -48867 -48868 -48869 -48870 -48871 -48872 -48873 -48874 -48875 -48876 -48877 -48878 -48879 -48880 -48881 -48882 -48883 -48884 -48885 -48886 -48887 -48888 -48889 -48890 -48891 -48892 -48893 -48894 -48895 -48896 -48897 -48898 -48899 -48900 -48901 -48902 -48903 -48904 -48905 -48906 -48907 -48908 -48909 -48910 -48911 -48912 -48913 -48914 -48915 -48916 -48917 -48918 -48919 -48920 -48921 -48922 -48923 -48924 -48925 -48926 -48927 -48928 -48929 -48930 -48931 -48932 -48933 -48934 -48935 -48936 -48937 -48938 -48939 -48940 -48941 -48942 -48943 -48944 -48945 -48946 -48947 -48948 -48949 -48950 -48951 -48952 -48953 -48954 -48955 -48956 -48957 -48958 -48959 -48960 -48961 -48962 -48963 -48964 -48965 -48966 -48967 -48968 -48969 -48970 -48971 -48972 -48973 -48974 -48975 -48976 -48977 -48978 -48979 -48980 -48981 -48982 -48983 -48984 -48985 -48986 -48987 -48988 -48989 -48990 -48991 -48992 -48993 -48994 -48995 -48996 -48997 -48998 -48999 -49000 -49001 -49002 -49003 -49004 -49005 -49006 -49007 -49008 -49009 -49010 -49011 -49012 -49013 -49014 -49015 -49016 -49017 -49018 -49019 -49020 -49021 -49022 -49023 -49024 -49025 -49026 -49027 -49028 -49029 -49030 -49031 -49032 -49033 -49034 -49035 -49036 -49037 -49038 -49039 -49040 -49041 -49042 -49043 -49044 -49045 -49046 -49047 -49048 -49049 -49050 -49051 -49052 -49053 -49054 -49055 -49056 -49057 -49058 -49059 -49060 -49061 -49062 -49063 -49064 -49065 -49066 -49067 -49068 -49069 -49070 -49071 -49072 -49073 -49074 -49075 -49076 -49077 -49078 -49079 -49080 -49081 -49082 -49083 -49084 -49085 -49086 -49087 -49088 -49089 -49090 -49091 -49092 -49093 -49094 -49095 -49096 -49097 -49098 -49099 -49100 -49101 -49102 -49103 -49104 -49105 -49106 -49107 -49108 -49109 -49110 -49111 -49112 -49113 -49114 -49115 -49116 -49117 -49118 -49119 -49120 -49121 -49122 -49123 -49124 -49125 -49126 -49127 -49128 -49129 -49130 -49131 -49132 -49133 -49134 -49135 -49136 -49137 -49138 -49139 -49140 -49141 -49142 -49143 -49144 -49145 -49146 -49147 -49148 -49149 -49150 -49151 -49152 -49153 -49154 -49155 -49156 -49157 -49158 -49159 -49160 -49161 -49162 -49163 -49164 -49165 -49166 -49167 -49168 -49169 -49170 -49171 -49172 -49173 -49174 -49175 -49176 -49177 -49178 -49179 -49180 -49181 -49182 -49183 -49184 -49185 -49186 -49187 -49188 -49189 -49190 -49191 -49192 -49193 -49194 -49195 -49196 -49197 -49198 -49199 -49200 -49201 -49202 -49203 -49204 -49205 -49206 -49207 -49208 -49209 -49210 -49211 -49212 -49213 -49214 -49215 -49216 -49217 -49218 -49219 -49220 -49221 -49222 -49223 -49224 -49225 -49226 -49227 -49228 -49229 -49230 -49231 -49232 -49233 -49234 -49235 -49236 -49237 -49238 -49239 -49240 -49241 -49242 -49243 -49244 -49245 -49246 -49247 -49248 -49249 -49250 -49251 -49252 -49253 -49254 -49255 -49256 -49257 -49258 -49259 -49260 -49261 -49262 -49263 -49264 -49265 -49266 -49267 -49268 -49269 -49270 -49271 -49272 -49273 -49274 -49275 -49276 -49277 -49278 -49279 -49280 -49281 -49282 -49283 -49284 -49285 -49286 -49287 -49288 -49289 -49290 -49291 -49292 -49293 -49294 -49295 -49296 -49297 -49298 -49299 -49300 -49301 -49302 -49303 -49304 -49305 -49306 -49307 -49308 -49309 -49310 -49311 -49312 -49313 -49314 -49315 -49316 -49317 -49318 -49319 -49320 -49321 -49322 -49323 -49324 -49325 -49326 -49327 -49328 -49329 -49330 -49331 -49332 -49333 -49334 -49335 -49336 -49337 -49338 -49339 -49340 -49341 -49342 -49343 -49344 -49345 -49346 -49347 -49348 -49349 -49350 -49351 -49352 -49353 -49354 -49355 -49356 -49357 -49358 -49359 -49360 -49361 -49362 -49363 -49364 -49365 -49366 -49367 -49368 -49369 -49370 -49371 -49372 -49373 -49374 -49375 -49376 -49377 -49378 -49379 -49380 -49381 -49382 -49383 -49384 -49385 -49386 -49387 -49388 -49389 -49390 -49391 -49392 -49393 -49394 -49395 -49396 -49397 -49398 -49399 -49400 -49401 -49402 -49403 -49404 -49405 -49406 -49407 -49408 -49409 -49410 -49411 -49412 -49413 -49414 -49415 -49416 -49417 -49418 -49419 -49420 -49421 -49422 -49423 -49424 -49425 -49426 -49427 -49428 -49429 -49430 -49431 -49432 -49433 -49434 -49435 -49436 -49437 -49438 -49439 -49440 -49441 -49442 -49443 -49444 -49445 -49446 -49447 -49448 -49449 -49450 -49451 -49452 -49453 -49454 -49455 -49456 -49457 -49458 -49459 -49460 -49461 -49462 -49463 -49464 -49465 -49466 -49467 -49468 -49469 -49470 -49471 -49472 -49473 -49474 -49475 -49476 -49477 -49478 -49479 -49480 -49481 -49482 -49483 -49484 -49485 -49486 -49487 -49488 -49489 -49490 -49491 -49492 -49493 -49494 -49495 -49496 -49497 -49498 -49499 -49500 -49501 -49502 -49503 -49504 -49505 -49506 -49507 -49508 -49509 -49510 -49511 -49512 -49513 -49514 -49515 -49516 -49517 -49518 -49519 -49520 -49521 -49522 -49523 -49524 -49525 -49526 -49527 -49528 -49529 -49530 -49531 -49532 -49533 -49534 -49535 -49536 -49537 -49538 -49539 -49540 -49541 -49542 -49543 -49544 -49545 -49546 -49547 -49548 -49549 -49550 -49551 -49552 -49553 -49554 -49555 -49556 -49557 -49558 -49559 -49560 -49561 -49562 -49563 -49564 -49565 -49566 -49567 -49568 -49569 -49570 -49571 -49572 -49573 -49574 -49575 -49576 -49577 -49578 -49579 -49580 -49581 -49582 -49583 -49584 -49585 -49586 -49587 -49588 -49589 -49590 -49591 -49592 -49593 -49594 -49595 -49596 -49597 -49598 -49599 -49600 -49601 -49602 -49603 -49604 -49605 -49606 -49607 -49608 -49609 -49610 -49611 -49612 -49613 -49614 -49615 -49616 -49617 -49618 -49619 -49620 -49621 -49622 -49623 -49624 -49625 -49626 -49627 -49628 -49629 -49630 -49631 -49632 -49633 -49634 -49635 -49636 -49637 -49638 -49639 -49640 -49641 -49642 -49643 -49644 -49645 -49646 -49647 -49648 -49649 -49650 -49651 -49652 -49653 -49654 -49655 -49656 -49657 -49658 -49659 -49660 -49661 -49662 -49663 -49664 -49665 -49666 -49667 -49668 -49669 -49670 -49671 -49672 -49673 -49674 -49675 -49676 -49677 -49678 -49679 -49680 -49681 -49682 -49683 -49684 -49685 -49686 -49687 -49688 -49689 -49690 -49691 -49692 -49693 -49694 -49695 -49696 -49697 -49698 -49699 -49700 -49701 -49702 -49703 -49704 -49705 -49706 -49707 -49708 -49709 -49710 -49711 -49712 -49713 -49714 -49715 -49716 -49717 -49718 -49719 -49720 -49721 -49722 -49723 -49724 -49725 -49726 -49727 -49728 -49729 -49730 -49731 -49732 -49733 -49734 -49735 -49736 -49737 -49738 -49739 -49740 -49741 -49742 -49743 -49744 -49745 -49746 -49747 -49748 -49749 -49750 -49751 -49752 -49753 -49754 -49755 -49756 -49757 -49758 -49759 -49760 -49761 -49762 -49763 -49764 -49765 -49766 -49767 -49768 -49769 -49770 -49771 -49772 -49773 -49774 -49775 -49776 -49777 -49778 -49779 -49780 -49781 -49782 -49783 -49784 -49785 -49786 -49787 -49788 -49789 -49790 -49791 -49792 -49793 -49794 -49795 -49796 -49797 -49798 -49799 -49800 -49801 -49802 -49803 -49804 -49805 -49806 -49807 -49808 -49809 -49810 -49811 -49812 -49813 -49814 -49815 -49816 -49817 -49818 -49819 -49820 -49821 -49822 -49823 -49824 -49825 -49826 -49827 -49828 -49829 -49830 -49831 -49832 -49833 -49834 -49835 -49836 -49837 -49838 -49839 -49840 -49841 -49842 -49843 -49844 -49845 -49846 -49847 -49848 -49849 -49850 -49851 -49852 -49853 -49854 -49855 -49856 -49857 -49858 -49859 -49860 -49861 -49862 -49863 -49864 -49865 -49866 -49867 -49868 -49869 -49870 -49871 -49872 -49873 -49874 -49875 -49876 -49877 -49878 -49879 -49880 -49881 -49882 -49883 -49884 -49885 -49886 -49887 -49888 -49889 -49890 -49891 -49892 -49893 -49894 -49895 -49896 -49897 -49898 -49899 -49900 -49901 -49902 -49903 -49904 -49905 -49906 -49907 -49908 -49909 -49910 -49911 -49912 -49913 -49914 -49915 -49916 -49917 -49918 -49919 -49920 -49921 -49922 -49923 -49924 -49925 -49926 -49927 -49928 -49929 -49930 -49931 -49932 -49933 -49934 -49935 -49936 -49937 -49938 -49939 -49940 -49941 -49942 -49943 -49944 -49945 -49946 -49947 -49948 -49949 -49950 -49951 -49952 -49953 -49954 -49955 -49956 -49957 -49958 -49959 -49960 -49961 -49962 -49963 -49964 -49965 -49966 -49967 -49968 -49969 -49970 -49971 -49972 -49973 -49974 -49975 -49976 -49977 -49978 -49979 -49980 -49981 -49982 -49983 -49984 -49985 -49986 -49987 -49988 -49989 -49990 -49991 -49992 -49993 -49994 -49995 -49996 -49997 -49998 -49999 -50000 -50001 -50002 -50003 -50004 -50005 -50006 -50007 -50008 -50009 -50010 -50011 -50012 -50013 -50014 -50015 -50016 -50017 -50018 -50019 -50020 -50021 -50022 -50023 -50024 -50025 -50026 -50027 -50028 -50029 -50030 -50031 -50032 -50033 -50034 -50035 -50036 -50037 -50038 -50039 -50040 -50041 -50042 -50043 -50044 -50045 -50046 -50047 -50048 -50049 -50050 -50051 -50052 -50053 -50054 -50055 -50056 -50057 -50058 -50059 -50060 -50061 -50062 -50063 -50064 -50065 -50066 -50067 -50068 -50069 -50070 -50071 -50072 -50073 -50074 -50075 -50076 -50077 -50078 -50079 -50080 -50081 -50082 -50083 -50084 -50085 -50086 -50087 -50088 -50089 -50090 -50091 -50092 -50093 -50094 -50095 -50096 -50097 -50098 -50099 -50100 -50101 -50102 -50103 -50104 -50105 -50106 -50107 -50108 -50109 -50110 -50111 -50112 -50113 -50114 -50115 -50116 -50117 -50118 -50119 -50120 -50121 -50122 -50123 -50124 -50125 -50126 -50127 -50128 -50129 -50130 -50131 -50132 -50133 -50134 -50135 -50136 -50137 -50138 -50139 -50140 -50141 -50142 -50143 -50144 -50145 -50146 -50147 -50148 -50149 -50150 -50151 -50152 -50153 -50154 -50155 -50156 -50157 -50158 -50159 -50160 -50161 -50162 -50163 -50164 -50165 -50166 -50167 -50168 -50169 -50170 -50171 -50172 -50173 -50174 -50175 -50176 -50177 -50178 -50179 -50180 -50181 -50182 -50183 -50184 -50185 -50186 -50187 -50188 -50189 -50190 -50191 -50192 -50193 -50194 -50195 -50196 -50197 -50198 -50199 -50200 -50201 -50202 -50203 -50204 -50205 -50206 -50207 -50208 -50209 -50210 -50211 -50212 -50213 -50214 -50215 -50216 -50217 -50218 -50219 -50220 -50221 -50222 -50223 -50224 -50225 -50226 -50227 -50228 -50229 -50230 -50231 -50232 -50233 -50234 -50235 -50236 -50237 -50238 -50239 -50240 -50241 -50242 -50243 -50244 -50245 -50246 -50247 -50248 -50249 -50250 -50251 -50252 -50253 -50254 -50255 -50256 -50257 -50258 -50259 -50260 -50261 -50262 -50263 -50264 -50265 -50266 -50267 -50268 -50269 -50270 -50271 -50272 -50273 -50274 -50275 -50276 -50277 -50278 -50279 -50280 -50281 -50282 -50283 -50284 -50285 -50286 -50287 -50288 -50289 -50290 -50291 -50292 -50293 -50294 -50295 -50296 -50297 -50298 -50299 -50300 -50301 -50302 -50303 -50304 -50305 -50306 -50307 -50308 -50309 -50310 -50311 -50312 -50313 -50314 -50315 -50316 -50317 -50318 -50319 -50320 -50321 -50322 -50323 -50324 -50325 -50326 -50327 -50328 -50329 -50330 -50331 -50332 -50333 -50334 -50335 -50336 -50337 -50338 -50339 -50340 -50341 -50342 -50343 -50344 -50345 -50346 -50347 -50348 -50349 -50350 -50351 -50352 -50353 -50354 -50355 -50356 -50357 -50358 -50359 -50360 -50361 -50362 -50363 -50364 -50365 -50366 -50367 -50368 -50369 -50370 -50371 -50372 -50373 -50374 -50375 -50376 -50377 -50378 -50379 -50380 -50381 -50382 -50383 -50384 -50385 -50386 -50387 -50388 -50389 -50390 -50391 -50392 -50393 -50394 -50395 -50396 -50397 -50398 -50399 -50400 -50401 -50402 -50403 -50404 -50405 -50406 -50407 -50408 -50409 -50410 -50411 -50412 -50413 -50414 -50415 -50416 -50417 -50418 -50419 -50420 -50421 -50422 -50423 -50424 -50425 -50426 -50427 -50428 -50429 -50430 -50431 -50432 -50433 -50434 -50435 -50436 -50437 -50438 -50439 -50440 -50441 -50442 -50443 -50444 -50445 -50446 -50447 -50448 -50449 -50450 -50451 -50452 -50453 -50454 -50455 -50456 -50457 -50458 -50459 -50460 -50461 -50462 -50463 -50464 -50465 -50466 -50467 -50468 -50469 -50470 -50471 -50472 -50473 -50474 -50475 -50476 -50477 -50478 -50479 -50480 -50481 -50482 -50483 -50484 -50485 -50486 -50487 -50488 -50489 -50490 -50491 -50492 -50493 -50494 -50495 -50496 -50497 -50498 -50499 -50500 -50501 -50502 -50503 -50504 -50505 -50506 -50507 -50508 -50509 -50510 -50511 -50512 -50513 -50514 -50515 -50516 -50517 -50518 -50519 -50520 -50521 -50522 -50523 -50524 -50525 -50526 -50527 -50528 -50529 -50530 -50531 -50532 -50533 -50534 -50535 -50536 -50537 -50538 -50539 -50540 -50541 -50542 -50543 -50544 -50545 -50546 -50547 -50548 -50549 -50550 -50551 -50552 -50553 -50554 -50555 -50556 -50557 -50558 -50559 -50560 -50561 -50562 -50563 -50564 -50565 -50566 -50567 -50568 -50569 -50570 -50571 -50572 -50573 -50574 -50575 -50576 -50577 -50578 -50579 -50580 -50581 -50582 -50583 -50584 -50585 -50586 -50587 -50588 -50589 -50590 -50591 -50592 -50593 -50594 -50595 -50596 -50597 -50598 -50599 -50600 -50601 -50602 -50603 -50604 -50605 -50606 -50607 -50608 -50609 -50610 -50611 -50612 -50613 -50614 -50615 -50616 -50617 -50618 -50619 -50620 -50621 -50622 -50623 -50624 -50625 -50626 -50627 -50628 -50629 -50630 -50631 -50632 -50633 -50634 -50635 -50636 -50637 -50638 -50639 -50640 -50641 -50642 -50643 -50644 -50645 -50646 -50647 -50648 -50649 -50650 -50651 -50652 -50653 -50654 -50655 -50656 -50657 -50658 -50659 -50660 -50661 -50662 -50663 -50664 -50665 -50666 -50667 -50668 -50669 -50670 -50671 -50672 -50673 -50674 -50675 -50676 -50677 -50678 -50679 -50680 -50681 -50682 -50683 -50684 -50685 -50686 -50687 -50688 -50689 -50690 -50691 -50692 -50693 -50694 -50695 -50696 -50697 -50698 -50699 -50700 -50701 -50702 -50703 -50704 -50705 -50706 -50707 -50708 -50709 -50710 -50711 -50712 -50713 -50714 -50715 -50716 -50717 -50718 -50719 -50720 -50721 -50722 -50723 -50724 -50725 -50726 -50727 -50728 -50729 -50730 -50731 -50732 -50733 -50734 -50735 -50736 -50737 -50738 -50739 -50740 -50741 -50742 -50743 -50744 -50745 -50746 -50747 -50748 -50749 -50750 -50751 -50752 -50753 -50754 -50755 -50756 -50757 -50758 -50759 -50760 -50761 -50762 -50763 -50764 -50765 -50766 -50767 -50768 -50769 -50770 -50771 -50772 -50773 -50774 -50775 -50776 -50777 -50778 -50779 -50780 -50781 -50782 -50783 -50784 -50785 -50786 -50787 -50788 -50789 -50790 -50791 -50792 -50793 -50794 -50795 -50796 -50797 -50798 -50799 -50800 -50801 -50802 -50803 -50804 -50805 -50806 -50807 -50808 -50809 -50810 -50811 -50812 -50813 -50814 -50815 -50816 -50817 -50818 -50819 -50820 -50821 -50822 -50823 -50824 -50825 -50826 -50827 -50828 -50829 -50830 -50831 -50832 -50833 -50834 -50835 -50836 -50837 -50838 -50839 -50840 -50841 -50842 -50843 -50844 -50845 -50846 -50847 -50848 -50849 -50850 -50851 -50852 -50853 -50854 -50855 -50856 -50857 -50858 -50859 -50860 -50861 -50862 -50863 -50864 -50865 -50866 -50867 -50868 -50869 -50870 -50871 -50872 -50873 -50874 -50875 -50876 -50877 -50878 -50879 -50880 -50881 -50882 -50883 -50884 -50885 -50886 -50887 -50888 -50889 -50890 -50891 -50892 -50893 -50894 -50895 -50896 -50897 -50898 -50899 -50900 -50901 -50902 -50903 -50904 -50905 -50906 -50907 -50908 -50909 -50910 -50911 -50912 -50913 -50914 -50915 -50916 -50917 -50918 -50919 -50920 -50921 -50922 -50923 -50924 -50925 -50926 -50927 -50928 -50929 -50930 -50931 -50932 -50933 -50934 -50935 -50936 -50937 -50938 -50939 -50940 -50941 -50942 -50943 -50944 -50945 -50946 -50947 -50948 -50949 -50950 -50951 -50952 -50953 -50954 -50955 -50956 -50957 -50958 -50959 -50960 -50961 -50962 -50963 -50964 -50965 -50966 -50967 -50968 -50969 -50970 -50971 -50972 -50973 -50974 -50975 -50976 -50977 -50978 -50979 -50980 -50981 -50982 -50983 -50984 -50985 -50986 -50987 -50988 -50989 -50990 -50991 -50992 -50993 -50994 -50995 -50996 -50997 -50998 -50999 -51000 -51001 -51002 -51003 -51004 -51005 -51006 -51007 -51008 -51009 -51010 -51011 -51012 -51013 -51014 -51015 -51016 -51017 -51018 -51019 -51020 -51021 -51022 -51023 -51024 -51025 -51026 -51027 -51028 -51029 -51030 -51031 -51032 -51033 -51034 -51035 -51036 -51037 -51038 -51039 -51040 -51041 -51042 -51043 -51044 -51045 -51046 -51047 -51048 -51049 -51050 -51051 -51052 -51053 -51054 -51055 -51056 -51057 -51058 -51059 -51060 -51061 -51062 -51063 -51064 -51065 -51066 -51067 -51068 -51069 -51070 -51071 -51072 -51073 -51074 -51075 -51076 -51077 -51078 -51079 -51080 -51081 -51082 -51083 -51084 -51085 -51086 -51087 -51088 -51089 -51090 -51091 -51092 -51093 -51094 -51095 -51096 -51097 -51098 -51099 -51100 -51101 -51102 -51103 -51104 -51105 -51106 -51107 -51108 -51109 -51110 -51111 -51112 -51113 -51114 -51115 -51116 -51117 -51118 -51119 -51120 -51121 -51122 -51123 -51124 -51125 -51126 -51127 -51128 -51129 -51130 -51131 -51132 -51133 -51134 -51135 -51136 -51137 -51138 -51139 -51140 -51141 -51142 -51143 -51144 -51145 -51146 -51147 -51148 -51149 -51150 -51151 -51152 -51153 -51154 -51155 -51156 -51157 -51158 -51159 -51160 -51161 -51162 -51163 -51164 -51165 -51166 -51167 -51168 -51169 -51170 -51171 -51172 -51173 -51174 -51175 -51176 -51177 -51178 -51179 -51180 -51181 -51182 -51183 -51184 -51185 -51186 -51187 -51188 -51189 -51190 -51191 -51192 -51193 -51194 -51195 -51196 -51197 -51198 -51199 -51200 -51201 -51202 -51203 -51204 -51205 -51206 -51207 -51208 -51209 -51210 -51211 -51212 -51213 -51214 -51215 -51216 -51217 -51218 -51219 -51220 -51221 -51222 -51223 -51224 -51225 -51226 -51227 -51228 -51229 -51230 -51231 -51232 -51233 -51234 -51235 -51236 -51237 -51238 -51239 -51240 -51241 -51242 -51243 -51244 -51245 -51246 -51247 -51248 -51249 -51250 -51251 -51252 -51253 -51254 -51255 -51256 -51257 -51258 -51259 -51260 -51261 -51262 -51263 -51264 -51265 -51266 -51267 -51268 -51269 -51270 -51271 -51272 -51273 -51274 -51275 -51276 -51277 -51278 -51279 -51280 -51281 -51282 -51283 -51284 -51285 -51286 -51287 -51288 -51289 -51290 -51291 -51292 -51293 -51294 -51295 -51296 -51297 -51298 -51299 -51300 -51301 -51302 -51303 -51304 -51305 -51306 -51307 -51308 -51309 -51310 -51311 -51312 -51313 -51314 -51315 -51316 -51317 -51318 -51319 -51320 -51321 -51322 -51323 -51324 -51325 -51326 -51327 -51328 -51329 -51330 -51331 -51332 -51333 -51334 -51335 -51336 -51337 -51338 -51339 -51340 -51341 -51342 -51343 -51344 -51345 -51346 -51347 -51348 -51349 -51350 -51351 -51352 -51353 -51354 -51355 -51356 -51357 -51358 -51359 -51360 -51361 -51362 -51363 -51364 -51365 -51366 -51367 -51368 -51369 -51370 -51371 -51372 -51373 -51374 -51375 -51376 -51377 -51378 -51379 -51380 -51381 -51382 -51383 -51384 -51385 -51386 -51387 -51388 -51389 -51390 -51391 -51392 -51393 -51394 -51395 -51396 -51397 -51398 -51399 -51400 -51401 -51402 -51403 -51404 -51405 -51406 -51407 -51408 -51409 -51410 -51411 -51412 -51413 -51414 -51415 -51416 -51417 -51418 -51419 -51420 -51421 -51422 -51423 -51424 -51425 -51426 -51427 -51428 -51429 -51430 -51431 -51432 -51433 -51434 -51435 -51436 -51437 -51438 -51439 -51440 -51441 -51442 -51443 -51444 -51445 -51446 -51447 -51448 -51449 -51450 -51451 -51452 -51453 -51454 -51455 -51456 -51457 -51458 -51459 -51460 -51461 -51462 -51463 -51464 -51465 -51466 -51467 -51468 -51469 -51470 -51471 -51472 -51473 -51474 -51475 -51476 -51477 -51478 -51479 -51480 -51481 -51482 -51483 -51484 -51485 -51486 -51487 -51488 -51489 -51490 -51491 -51492 -51493 -51494 -51495 -51496 -51497 -51498 -51499 -51500 -51501 -51502 -51503 -51504 -51505 -51506 -51507 -51508 -51509 -51510 -51511 -51512 -51513 -51514 -51515 -51516 -51517 -51518 -51519 -51520 -51521 -51522 -51523 -51524 -51525 -51526 -51527 -51528 -51529 -51530 -51531 -51532 -51533 -51534 -51535 -51536 -51537 -51538 -51539 -51540 -51541 -51542 -51543 -51544 -51545 -51546 -51547 -51548 -51549 -51550 -51551 -51552 -51553 -51554 -51555 -51556 -51557 -51558 -51559 -51560 -51561 -51562 -51563 -51564 -51565 -51566 -51567 -51568 -51569 -51570 -51571 -51572 -51573 -51574 -51575 -51576 -51577 -51578 -51579 -51580 -51581 -51582 -51583 -51584 -51585 -51586 -51587 -51588 -51589 -51590 -51591 -51592 -51593 -51594 -51595 -51596 -51597 -51598 -51599 -51600 -51601 -51602 -51603 -51604 -51605 -51606 -51607 -51608 -51609 -51610 -51611 -51612 -51613 -51614 -51615 -51616 -51617 -51618 -51619 -51620 -51621 -51622 -51623 -51624 -51625 -51626 -51627 -51628 -51629 -51630 -51631 -51632 -51633 -51634 -51635 -51636 -51637 -51638 -51639 -51640 -51641 -51642 -51643 -51644 -51645 -51646 -51647 -51648 -51649 -51650 -51651 -51652 -51653 -51654 -51655 -51656 -51657 -51658 -51659 -51660 -51661 -51662 -51663 -51664 -51665 -51666 -51667 -51668 -51669 -51670 -51671 -51672 -51673 -51674 -51675 -51676 -51677 -51678 -51679 -51680 -51681 -51682 -51683 -51684 -51685 -51686 -51687 -51688 -51689 -51690 -51691 -51692 -51693 -51694 -51695 -51696 -51697 -51698 -51699 -51700 -51701 -51702 -51703 -51704 -51705 -51706 -51707 -51708 -51709 -51710 -51711 -51712 -51713 -51714 -51715 -51716 -51717 -51718 -51719 -51720 -51721 -51722 -51723 -51724 -51725 -51726 -51727 -51728 -51729 -51730 -51731 -51732 -51733 -51734 -51735 -51736 -51737 -51738 -51739 -51740 -51741 -51742 -51743 -51744 -51745 -51746 -51747 -51748 -51749 -51750 -51751 -51752 -51753 -51754 -51755 -51756 -51757 -51758 -51759 -51760 -51761 -51762 -51763 -51764 -51765 -51766 -51767 -51768 -51769 -51770 -51771 -51772 -51773 -51774 -51775 -51776 -51777 -51778 -51779 -51780 -51781 -51782 -51783 -51784 -51785 -51786 -51787 -51788 -51789 -51790 -51791 -51792 -51793 -51794 -51795 -51796 -51797 -51798 -51799 -51800 -51801 -51802 -51803 -51804 -51805 -51806 -51807 -51808 -51809 -51810 -51811 -51812 -51813 -51814 -51815 -51816 -51817 -51818 -51819 -51820 -51821 -51822 -51823 -51824 -51825 -51826 -51827 -51828 -51829 -51830 -51831 -51832 -51833 -51834 -51835 -51836 -51837 -51838 -51839 -51840 -51841 -51842 -51843 -51844 -51845 -51846 -51847 -51848 -51849 -51850 -51851 -51852 -51853 -51854 -51855 -51856 -51857 -51858 -51859 -51860 -51861 -51862 -51863 -51864 -51865 -51866 -51867 -51868 -51869 -51870 -51871 -51872 -51873 -51874 -51875 -51876 -51877 -51878 -51879 -51880 -51881 -51882 -51883 -51884 -51885 -51886 -51887 -51888 -51889 -51890 -51891 -51892 -51893 -51894 -51895 -51896 -51897 -51898 -51899 -51900 -51901 -51902 -51903 -51904 -51905 -51906 -51907 -51908 -51909 -51910 -51911 -51912 -51913 -51914 -51915 -51916 -51917 -51918 -51919 -51920 -51921 -51922 -51923 -51924 -51925 -51926 -51927 -51928 -51929 -51930 -51931 -51932 -51933 -51934 -51935 -51936 -51937 -51938 -51939 -51940 -51941 -51942 -51943 -51944 -51945 -51946 -51947 -51948 -51949 -51950 -51951 -51952 -51953 -51954 -51955 -51956 -51957 -51958 -51959 -51960 -51961 -51962 -51963 -51964 -51965 -51966 -51967 -51968 -51969 -51970 -51971 -51972 -51973 -51974 -51975 -51976 -51977 -51978 -51979 -51980 -51981 -51982 -51983 -51984 -51985 -51986 -51987 -51988 -51989 -51990 -51991 -51992 -51993 -51994 -51995 -51996 -51997 -51998 -51999 -52000 -52001 -52002 -52003 -52004 -52005 -52006 -52007 -52008 -52009 -52010 -52011 -52012 -52013 -52014 -52015 -52016 -52017 -52018 -52019 -52020 -52021 -52022 -52023 -52024 -52025 -52026 -52027 -52028 -52029 -52030 -52031 -52032 -52033 -52034 -52035 -52036 -52037 -52038 -52039 -52040 -52041 -52042 -52043 -52044 -52045 -52046 -52047 -52048 -52049 -52050 -52051 -52052 -52053 -52054 -52055 -52056 -52057 -52058 -52059 -52060 -52061 -52062 -52063 -52064 -52065 -52066 -52067 -52068 -52069 -52070 -52071 -52072 -52073 -52074 -52075 -52076 -52077 -52078 -52079 -52080 -52081 -52082 -52083 -52084 -52085 -52086 -52087 -52088 -52089 -52090 -52091 -52092 -52093 -52094 -52095 -52096 -52097 -52098 -52099 -52100 -52101 -52102 -52103 -52104 -52105 -52106 -52107 -52108 -52109 -52110 -52111 -52112 -52113 -52114 -52115 -52116 -52117 -52118 -52119 -52120 -52121 -52122 -52123 -52124 -52125 -52126 -52127 -52128 -52129 -52130 -52131 -52132 -52133 -52134 -52135 -52136 -52137 -52138 -52139 -52140 -52141 -52142 -52143 -52144 -52145 -52146 -52147 -52148 -52149 -52150 -52151 -52152 -52153 -52154 -52155 -52156 -52157 -52158 -52159 -52160 -52161 -52162 -52163 -52164 -52165 -52166 -52167 -52168 -52169 -52170 -52171 -52172 -52173 -52174 -52175 -52176 -52177 -52178 -52179 -52180 -52181 -52182 -52183 -52184 -52185 -52186 -52187 -52188 -52189 -52190 -52191 -52192 -52193 -52194 -52195 -52196 -52197 -52198 -52199 -52200 -52201 -52202 -52203 -52204 -52205 -52206 -52207 -52208 -52209 -52210 -52211 -52212 -52213 -52214 -52215 -52216 -52217 -52218 -52219 -52220 -52221 -52222 -52223 -52224 -52225 -52226 -52227 -52228 -52229 -52230 -52231 -52232 -52233 -52234 -52235 -52236 -52237 -52238 -52239 -52240 -52241 -52242 -52243 -52244 -52245 -52246 -52247 -52248 -52249 -52250 -52251 -52252 -52253 -52254 -52255 -52256 -52257 -52258 -52259 -52260 -52261 -52262 -52263 -52264 -52265 -52266 -52267 -52268 -52269 -52270 -52271 -52272 -52273 -52274 -52275 -52276 -52277 -52278 -52279 -52280 -52281 -52282 -52283 -52284 -52285 -52286 -52287 -52288 -52289 -52290 -52291 -52292 -52293 -52294 -52295 -52296 -52297 -52298 -52299 -52300 -52301 -52302 -52303 -52304 -52305 -52306 -52307 -52308 -52309 -52310 -52311 -52312 -52313 -52314 -52315 -52316 -52317 -52318 -52319 -52320 -52321 -52322 -52323 -52324 -52325 -52326 -52327 -52328 -52329 -52330 -52331 -52332 -52333 -52334 -52335 -52336 -52337 -52338 -52339 -52340 -52341 -52342 -52343 -52344 -52345 -52346 -52347 -52348 -52349 -52350 -52351 -52352 -52353 -52354 -52355 -52356 -52357 -52358 -52359 -52360 -52361 -52362 -52363 -52364 -52365 -52366 -52367 -52368 -52369 -52370 -52371 -52372 -52373 -52374 -52375 -52376 -52377 -52378 -52379 -52380 -52381 -52382 -52383 -52384 -52385 -52386 -52387 -52388 -52389 -52390 -52391 -52392 -52393 -52394 -52395 -52396 -52397 -52398 -52399 -52400 -52401 -52402 -52403 -52404 -52405 -52406 -52407 -52408 -52409 -52410 -52411 -52412 -52413 -52414 -52415 -52416 -52417 -52418 -52419 -52420 -52421 -52422 -52423 -52424 -52425 -52426 -52427 -52428 -52429 -52430 -52431 -52432 -52433 -52434 -52435 -52436 -52437 -52438 -52439 -52440 -52441 -52442 -52443 -52444 -52445 -52446 -52447 -52448 -52449 -52450 -52451 -52452 -52453 -52454 -52455 -52456 -52457 -52458 -52459 -52460 -52461 -52462 -52463 -52464 -52465 -52466 -52467 -52468 -52469 -52470 -52471 -52472 -52473 -52474 -52475 -52476 -52477 -52478 -52479 -52480 -52481 -52482 -52483 -52484 -52485 -52486 -52487 -52488 -52489 -52490 -52491 -52492 -52493 -52494 -52495 -52496 -52497 -52498 -52499 -52500 -52501 -52502 -52503 -52504 -52505 -52506 -52507 -52508 -52509 -52510 -52511 -52512 -52513 -52514 -52515 -52516 -52517 -52518 -52519 -52520 -52521 -52522 -52523 -52524 -52525 -52526 -52527 -52528 -52529 -52530 -52531 -52532 -52533 -52534 -52535 -52536 -52537 -52538 -52539 -52540 -52541 -52542 -52543 -52544 -52545 -52546 -52547 -52548 -52549 -52550 -52551 -52552 -52553 -52554 -52555 -52556 -52557 -52558 -52559 -52560 -52561 -52562 -52563 -52564 -52565 -52566 -52567 -52568 -52569 -52570 -52571 -52572 -52573 -52574 -52575 -52576 -52577 -52578 -52579 -52580 -52581 -52582 -52583 -52584 -52585 -52586 -52587 -52588 -52589 -52590 -52591 -52592 -52593 -52594 -52595 -52596 -52597 -52598 -52599 -52600 -52601 -52602 -52603 -52604 -52605 -52606 -52607 -52608 -52609 -52610 -52611 -52612 -52613 -52614 -52615 -52616 -52617 -52618 -52619 -52620 -52621 -52622 -52623 -52624 -52625 -52626 -52627 -52628 -52629 -52630 -52631 -52632 -52633 -52634 -52635 -52636 -52637 -52638 -52639 -52640 -52641 -52642 -52643 -52644 -52645 -52646 -52647 -52648 -52649 -52650 -52651 -52652 -52653 -52654 -52655 -52656 -52657 -52658 -52659 -52660 -52661 -52662 -52663 -52664 -52665 -52666 -52667 -52668 -52669 -52670 -52671 -52672 -52673 -52674 -52675 -52676 -52677 -52678 -52679 -52680 -52681 -52682 -52683 -52684 -52685 -52686 -52687 -52688 -52689 -52690 -52691 -52692 -52693 -52694 -52695 -52696 -52697 -52698 -52699 -52700 -52701 -52702 -52703 -52704 -52705 -52706 -52707 -52708 -52709 -52710 -52711 -52712 -52713 -52714 -52715 -52716 -52717 -52718 -52719 -52720 -52721 -52722 -52723 -52724 -52725 -52726 -52727 -52728 -52729 -52730 -52731 -52732 -52733 -52734 -52735 -52736 -52737 -52738 -52739 -52740 -52741 -52742 -52743 -52744 -52745 -52746 -52747 -52748 -52749 -52750 -52751 -52752 -52753 -52754 -52755 -52756 -52757 -52758 -52759 -52760 -52761 -52762 -52763 -52764 -52765 -52766 -52767 -52768 -52769 -52770 -52771 -52772 -52773 -52774 -52775 -52776 -52777 -52778 -52779 -52780 -52781 -52782 -52783 -52784 -52785 -52786 -52787 -52788 -52789 -52790 -52791 -52792 -52793 -52794 -52795 -52796 -52797 -52798 -52799 -52800 -52801 -52802 -52803 -52804 -52805 -52806 -52807 -52808 -52809 -52810 -52811 -52812 -52813 -52814 -52815 -52816 -52817 -52818 -52819 -52820 -52821 -52822 -52823 -52824 -52825 -52826 -52827 -52828 -52829 -52830 -52831 -52832 -52833 -52834 -52835 -52836 -52837 -52838 -52839 -52840 -52841 -52842 -52843 -52844 -52845 -52846 -52847 -52848 -52849 -52850 -52851 -52852 -52853 -52854 -52855 -52856 -52857 -52858 -52859 -52860 -52861 -52862 -52863 -52864 -52865 -52866 -52867 -52868 -52869 -52870 -52871 -52872 -52873 -52874 -52875 -52876 -52877 -52878 -52879 -52880 -52881 -52882 -52883 -52884 -52885 -52886 -52887 -52888 -52889 -52890 -52891 -52892 -52893 -52894 -52895 -52896 -52897 -52898 -52899 -52900 -52901 -52902 -52903 -52904 -52905 -52906 -52907 -52908 -52909 -52910 -52911 -52912 -52913 -52914 -52915 -52916 -52917 -52918 -52919 -52920 -52921 -52922 -52923 -52924 -52925 -52926 -52927 -52928 -52929 -52930 -52931 -52932 -52933 -52934 -52935 -52936 -52937 -52938 -52939 -52940 -52941 -52942 -52943 -52944 -52945 -52946 -52947 -52948 -52949 -52950 -52951 -52952 -52953 -52954 -52955 -52956 -52957 -52958 -52959 -52960 -52961 -52962 -52963 -52964 -52965 -52966 -52967 -52968 -52969 -52970 -52971 -52972 -52973 -52974 -52975 -52976 -52977 -52978 -52979 -52980 -52981 -52982 -52983 -52984 -52985 -52986 -52987 -52988 -52989 -52990 -52991 -52992 -52993 -52994 -52995 -52996 -52997 -52998 -52999 -53000 -53001 -53002 -53003 -53004 -53005 -53006 -53007 -53008 -53009 -53010 -53011 -53012 -53013 -53014 -53015 -53016 -53017 -53018 -53019 -53020 -53021 -53022 -53023 -53024 -53025 -53026 -53027 -53028 -53029 -53030 -53031 -53032 -53033 -53034 -53035 -53036 -53037 -53038 -53039 -53040 -53041 -53042 -53043 -53044 -53045 -53046 -53047 -53048 -53049 -53050 -53051 -53052 -53053 -53054 -53055 -53056 -53057 -53058 -53059 -53060 -53061 -53062 -53063 -53064 -53065 -53066 -53067 -53068 -53069 -53070 -53071 -53072 -53073 -53074 -53075 -53076 -53077 -53078 -53079 -53080 -53081 -53082 -53083 -53084 -53085 -53086 -53087 -53088 -53089 -53090 -53091 -53092 -53093 -53094 -53095 -53096 -53097 -53098 -53099 -53100 -53101 -53102 -53103 -53104 -53105 -53106 -53107 -53108 -53109 -53110 -53111 -53112 -53113 -53114 -53115 -53116 -53117 -53118 -53119 -53120 -53121 -53122 -53123 -53124 -53125 -53126 -53127 -53128 -53129 -53130 -53131 -53132 -53133 -53134 -53135 -53136 -53137 -53138 -53139 -53140 -53141 -53142 -53143 -53144 -53145 -53146 -53147 -53148 -53149 -53150 -53151 -53152 -53153 -53154 -53155 -53156 -53157 -53158 -53159 -53160 -53161 -53162 -53163 -53164 -53165 -53166 -53167 -53168 -53169 -53170 -53171 -53172 -53173 -53174 -53175 -53176 -53177 -53178 -53179 -53180 -53181 -53182 -53183 -53184 -53185 -53186 -53187 -53188 -53189 -53190 -53191 -53192 -53193 -53194 -53195 -53196 -53197 -53198 -53199 -53200 -53201 -53202 -53203 -53204 -53205 -53206 -53207 -53208 -53209 -53210 -53211 -53212 -53213 -53214 -53215 -53216 -53217 -53218 -53219 -53220 -53221 -53222 -53223 -53224 -53225 -53226 -53227 -53228 -53229 -53230 -53231 -53232 -53233 -53234 -53235 -53236 -53237 -53238 -53239 -53240 -53241 -53242 -53243 -53244 -53245 -53246 -53247 -53248 -53249 -53250 -53251 -53252 -53253 -53254 -53255 -53256 -53257 -53258 -53259 -53260 -53261 -53262 -53263 -53264 -53265 -53266 -53267 -53268 -53269 -53270 -53271 -53272 -53273 -53274 -53275 -53276 -53277 -53278 -53279 -53280 -53281 -53282 -53283 -53284 -53285 -53286 -53287 -53288 -53289 -53290 -53291 -53292 -53293 -53294 -53295 -53296 -53297 -53298 -53299 -53300 -53301 -53302 -53303 -53304 -53305 -53306 -53307 -53308 -53309 -53310 -53311 -53312 -53313 -53314 -53315 -53316 -53317 -53318 -53319 -53320 -53321 -53322 -53323 -53324 -53325 -53326 -53327 -53328 -53329 -53330 -53331 -53332 -53333 -53334 -53335 -53336 -53337 -53338 -53339 -53340 -53341 -53342 -53343 -53344 -53345 -53346 -53347 -53348 -53349 -53350 -53351 -53352 -53353 -53354 -53355 -53356 -53357 -53358 -53359 -53360 -53361 -53362 -53363 -53364 -53365 -53366 -53367 -53368 -53369 -53370 -53371 -53372 -53373 -53374 -53375 -53376 -53377 -53378 -53379 -53380 -53381 -53382 -53383 -53384 -53385 -53386 -53387 -53388 -53389 -53390 -53391 -53392 -53393 -53394 -53395 -53396 -53397 -53398 -53399 -53400 -53401 -53402 -53403 -53404 -53405 -53406 -53407 -53408 -53409 -53410 -53411 -53412 -53413 -53414 -53415 -53416 -53417 -53418 -53419 -53420 -53421 -53422 -53423 -53424 -53425 -53426 -53427 -53428 -53429 -53430 -53431 -53432 -53433 -53434 -53435 -53436 -53437 -53438 -53439 -53440 -53441 -53442 -53443 -53444 -53445 -53446 -53447 -53448 -53449 -53450 -53451 -53452 -53453 -53454 -53455 -53456 -53457 -53458 -53459 -53460 -53461 -53462 -53463 -53464 -53465 -53466 -53467 -53468 -53469 -53470 -53471 -53472 -53473 -53474 -53475 -53476 -53477 -53478 -53479 -53480 -53481 -53482 -53483 -53484 -53485 -53486 -53487 -53488 -53489 -53490 -53491 -53492 -53493 -53494 -53495 -53496 -53497 -53498 -53499 -53500 -53501 -53502 -53503 -53504 -53505 -53506 -53507 -53508 -53509 -53510 -53511 -53512 -53513 -53514 -53515 -53516 -53517 -53518 -53519 -53520 -53521 -53522 -53523 -53524 -53525 -53526 -53527 -53528 -53529 -53530 -53531 -53532 -53533 -53534 -53535 -53536 -53537 -53538 -53539 -53540 -53541 -53542 -53543 -53544 -53545 -53546 -53547 -53548 -53549 -53550 -53551 -53552 -53553 -53554 -53555 -53556 -53557 -53558 -53559 -53560 -53561 -53562 -53563 -53564 -53565 -53566 -53567 -53568 -53569 -53570 -53571 -53572 -53573 -53574 -53575 -53576 -53577 -53578 -53579 -53580 -53581 -53582 -53583 -53584 -53585 -53586 -53587 -53588 -53589 -53590 -53591 -53592 -53593 -53594 -53595 -53596 -53597 -53598 -53599 -53600 -53601 -53602 -53603 -53604 -53605 -53606 -53607 -53608 -53609 -53610 -53611 -53612 -53613 -53614 -53615 -53616 -53617 -53618 -53619 -53620 -53621 -53622 -53623 -53624 -53625 -53626 -53627 -53628 -53629 -53630 -53631 -53632 -53633 -53634 -53635 -53636 -53637 -53638 -53639 -53640 -53641 -53642 -53643 -53644 -53645 -53646 -53647 -53648 -53649 -53650 -53651 -53652 -53653 -53654 -53655 -53656 -53657 -53658 -53659 -53660 -53661 -53662 -53663 -53664 -53665 -53666 -53667 -53668 -53669 -53670 -53671 -53672 -53673 -53674 -53675 -53676 -53677 -53678 -53679 -53680 -53681 -53682 -53683 -53684 -53685 -53686 -53687 -53688 -53689 -53690 -53691 -53692 -53693 -53694 -53695 -53696 -53697 -53698 -53699 -53700 -53701 -53702 -53703 -53704 -53705 -53706 -53707 -53708 -53709 -53710 -53711 -53712 -53713 -53714 -53715 -53716 -53717 -53718 -53719 -53720 -53721 -53722 -53723 -53724 -53725 -53726 -53727 -53728 -53729 -53730 -53731 -53732 -53733 -53734 -53735 -53736 -53737 -53738 -53739 -53740 -53741 -53742 -53743 -53744 -53745 -53746 -53747 -53748 -53749 -53750 -53751 -53752 -53753 -53754 -53755 -53756 -53757 -53758 -53759 -53760 -53761 -53762 -53763 -53764 -53765 -53766 -53767 -53768 -53769 -53770 -53771 -53772 -53773 -53774 -53775 -53776 -53777 -53778 -53779 -53780 -53781 -53782 -53783 -53784 -53785 -53786 -53787 -53788 -53789 -53790 -53791 -53792 -53793 -53794 -53795 -53796 -53797 -53798 -53799 -53800 -53801 -53802 -53803 -53804 -53805 -53806 -53807 -53808 -53809 -53810 -53811 -53812 -53813 -53814 -53815 -53816 -53817 -53818 -53819 -53820 -53821 -53822 -53823 -53824 -53825 -53826 -53827 -53828 -53829 -53830 -53831 -53832 -53833 -53834 -53835 -53836 -53837 -53838 -53839 -53840 -53841 -53842 -53843 -53844 -53845 -53846 -53847 -53848 -53849 -53850 -53851 -53852 -53853 -53854 -53855 -53856 -53857 -53858 -53859 -53860 -53861 -53862 -53863 -53864 -53865 -53866 -53867 -53868 -53869 -53870 -53871 -53872 -53873 -53874 -53875 -53876 -53877 -53878 -53879 -53880 -53881 -53882 -53883 -53884 -53885 -53886 -53887 -53888 -53889 -53890 -53891 -53892 -53893 -53894 -53895 -53896 -53897 -53898 -53899 -53900 -53901 -53902 -53903 -53904 -53905 -53906 -53907 -53908 -53909 -53910 -53911 -53912 -53913 -53914 -53915 -53916 -53917 -53918 -53919 -53920 -53921 -53922 -53923 -53924 -53925 -53926 -53927 -53928 -53929 -53930 -53931 -53932 -53933 -53934 -53935 -53936 -53937 -53938 -53939 -53940 -53941 -53942 -53943 -53944 -53945 -53946 -53947 -53948 -53949 -53950 -53951 -53952 -53953 -53954 -53955 -53956 -53957 -53958 -53959 -53960 -53961 -53962 -53963 -53964 -53965 -53966 -53967 -53968 -53969 -53970 -53971 -53972 -53973 -53974 -53975 -53976 -53977 -53978 -53979 -53980 -53981 -53982 -53983 -53984 -53985 -53986 -53987 -53988 -53989 -53990 -53991 -53992 -53993 -53994 -53995 -53996 -53997 -53998 -53999 -54000 -54001 -54002 -54003 -54004 -54005 -54006 -54007 -54008 -54009 -54010 -54011 -54012 -54013 -54014 -54015 -54016 -54017 -54018 -54019 -54020 -54021 -54022 -54023 -54024 -54025 -54026 -54027 -54028 -54029 -54030 -54031 -54032 -54033 -54034 -54035 -54036 -54037 -54038 -54039 -54040 -54041 -54042 -54043 -54044 -54045 -54046 -54047 -54048 -54049 -54050 -54051 -54052 -54053 -54054 -54055 -54056 -54057 -54058 -54059 -54060 -54061 -54062 -54063 -54064 -54065 -54066 -54067 -54068 -54069 -54070 -54071 -54072 -54073 -54074 -54075 -54076 -54077 -54078 -54079 -54080 -54081 -54082 -54083 -54084 -54085 -54086 -54087 -54088 -54089 -54090 -54091 -54092 -54093 -54094 -54095 -54096 -54097 -54098 -54099 -54100 -54101 -54102 -54103 -54104 -54105 -54106 -54107 -54108 -54109 -54110 -54111 -54112 -54113 -54114 -54115 -54116 -54117 -54118 -54119 -54120 -54121 -54122 -54123 -54124 -54125 -54126 -54127 -54128 -54129 -54130 -54131 -54132 -54133 -54134 -54135 -54136 -54137 -54138 -54139 -54140 -54141 -54142 -54143 -54144 -54145 -54146 -54147 -54148 -54149 -54150 -54151 -54152 -54153 -54154 -54155 -54156 -54157 -54158 -54159 -54160 -54161 -54162 -54163 -54164 -54165 -54166 -54167 -54168 -54169 -54170 -54171 -54172 -54173 -54174 -54175 -54176 -54177 -54178 -54179 -54180 -54181 -54182 -54183 -54184 -54185 -54186 -54187 -54188 -54189 -54190 -54191 -54192 -54193 -54194 -54195 -54196 -54197 -54198 -54199 -54200 -54201 -54202 -54203 -54204 -54205 -54206 -54207 -54208 -54209 -54210 -54211 -54212 -54213 -54214 -54215 -54216 -54217 -54218 -54219 -54220 -54221 -54222 -54223 -54224 -54225 -54226 -54227 -54228 -54229 -54230 -54231 -54232 -54233 -54234 -54235 -54236 -54237 -54238 -54239 -54240 -54241 -54242 -54243 -54244 -54245 -54246 -54247 -54248 -54249 -54250 -54251 -54252 -54253 -54254 -54255 -54256 -54257 -54258 -54259 -54260 -54261 -54262 -54263 -54264 -54265 -54266 -54267 -54268 -54269 -54270 -54271 -54272 -54273 -54274 -54275 -54276 -54277 -54278 -54279 -54280 -54281 -54282 -54283 -54284 -54285 -54286 -54287 -54288 -54289 -54290 -54291 -54292 -54293 -54294 -54295 -54296 -54297 -54298 -54299 -54300 -54301 -54302 -54303 -54304 -54305 -54306 -54307 -54308 -54309 -54310 -54311 -54312 -54313 -54314 -54315 -54316 -54317 -54318 -54319 -54320 -54321 -54322 -54323 -54324 -54325 -54326 -54327 -54328 -54329 -54330 -54331 -54332 -54333 -54334 -54335 -54336 -54337 -54338 -54339 -54340 -54341 -54342 -54343 -54344 -54345 -54346 -54347 -54348 -54349 -54350 -54351 -54352 -54353 -54354 -54355 -54356 -54357 -54358 -54359 -54360 -54361 -54362 -54363 -54364 -54365 -54366 -54367 -54368 -54369 -54370 -54371 -54372 -54373 -54374 -54375 -54376 -54377 -54378 -54379 -54380 -54381 -54382 -54383 -54384 -54385 -54386 -54387 -54388 -54389 -54390 -54391 -54392 -54393 -54394 -54395 -54396 -54397 -54398 -54399 -54400 -54401 -54402 -54403 -54404 -54405 -54406 -54407 -54408 -54409 -54410 -54411 -54412 -54413 -54414 -54415 -54416 -54417 -54418 -54419 -54420 -54421 -54422 -54423 -54424 -54425 -54426 -54427 -54428 -54429 -54430 -54431 -54432 -54433 -54434 -54435 -54436 -54437 -54438 -54439 -54440 -54441 -54442 -54443 -54444 -54445 -54446 -54447 -54448 -54449 -54450 -54451 -54452 -54453 -54454 -54455 -54456 -54457 -54458 -54459 -54460 -54461 -54462 -54463 -54464 -54465 -54466 -54467 -54468 -54469 -54470 -54471 -54472 -54473 -54474 -54475 -54476 -54477 -54478 -54479 -54480 -54481 -54482 -54483 -54484 -54485 -54486 -54487 -54488 -54489 -54490 -54491 -54492 -54493 -54494 -54495 -54496 -54497 -54498 -54499 -54500 -54501 -54502 -54503 -54504 -54505 -54506 -54507 -54508 -54509 -54510 -54511 -54512 -54513 -54514 -54515 -54516 -54517 -54518 -54519 -54520 -54521 -54522 -54523 -54524 -54525 -54526 -54527 -54528 -54529 -54530 -54531 -54532 -54533 -54534 -54535 -54536 -54537 -54538 -54539 -54540 -54541 -54542 -54543 -54544 -54545 -54546 -54547 -54548 -54549 -54550 -54551 -54552 -54553 -54554 -54555 -54556 -54557 -54558 -54559 -54560 -54561 -54562 -54563 -54564 -54565 -54566 -54567 -54568 -54569 -54570 -54571 -54572 -54573 -54574 -54575 -54576 -54577 -54578 -54579 -54580 -54581 -54582 -54583 -54584 -54585 -54586 -54587 -54588 -54589 -54590 -54591 -54592 -54593 -54594 -54595 -54596 -54597 -54598 -54599 -54600 -54601 -54602 -54603 -54604 -54605 -54606 -54607 -54608 -54609 -54610 -54611 -54612 -54613 -54614 -54615 -54616 -54617 -54618 -54619 -54620 -54621 -54622 -54623 -54624 -54625 -54626 -54627 -54628 -54629 -54630 -54631 -54632 -54633 -54634 -54635 -54636 -54637 -54638 -54639 -54640 -54641 -54642 -54643 -54644 -54645 -54646 -54647 -54648 -54649 -54650 -54651 -54652 -54653 -54654 -54655 -54656 -54657 -54658 -54659 -54660 -54661 -54662 -54663 -54664 -54665 -54666 -54667 -54668 -54669 -54670 -54671 -54672 -54673 -54674 -54675 -54676 -54677 -54678 -54679 -54680 -54681 -54682 -54683 -54684 -54685 -54686 -54687 -54688 -54689 -54690 -54691 -54692 -54693 -54694 -54695 -54696 -54697 -54698 -54699 -54700 -54701 -54702 -54703 -54704 -54705 -54706 -54707 -54708 -54709 -54710 -54711 -54712 -54713 -54714 -54715 -54716 -54717 -54718 -54719 -54720 -54721 -54722 -54723 -54724 -54725 -54726 -54727 -54728 -54729 -54730 -54731 -54732 -54733 -54734 -54735 -54736 -54737 -54738 -54739 -54740 -54741 -54742 -54743 -54744 -54745 -54746 -54747 -54748 -54749 -54750 -54751 -54752 -54753 -54754 -54755 -54756 -54757 -54758 -54759 -54760 -54761 -54762 -54763 -54764 -54765 -54766 -54767 -54768 -54769 -54770 -54771 -54772 -54773 -54774 -54775 -54776 -54777 -54778 -54779 -54780 -54781 -54782 -54783 -54784 -54785 -54786 -54787 -54788 -54789 -54790 -54791 -54792 -54793 -54794 -54795 -54796 -54797 -54798 -54799 -54800 -54801 -54802 -54803 -54804 -54805 -54806 -54807 -54808 -54809 -54810 -54811 -54812 -54813 -54814 -54815 -54816 -54817 -54818 -54819 -54820 -54821 -54822 -54823 -54824 -54825 -54826 -54827 -54828 -54829 -54830 -54831 -54832 -54833 -54834 -54835 -54836 -54837 -54838 -54839 -54840 -54841 -54842 -54843 -54844 -54845 -54846 -54847 -54848 -54849 -54850 -54851 -54852 -54853 -54854 -54855 -54856 -54857 -54858 -54859 -54860 -54861 -54862 -54863 -54864 -54865 -54866 -54867 -54868 -54869 -54870 -54871 -54872 -54873 -54874 -54875 -54876 -54877 -54878 -54879 -54880 -54881 -54882 -54883 -54884 -54885 -54886 -54887 -54888 -54889 -54890 -54891 -54892 -54893 -54894 -54895 -54896 -54897 -54898 -54899 -54900 -54901 -54902 -54903 -54904 -54905 -54906 -54907 -54908 -54909 -54910 -54911 -54912 -54913 -54914 -54915 -54916 -54917 -54918 -54919 -54920 -54921 -54922 -54923 -54924 -54925 -54926 -54927 -54928 -54929 -54930 -54931 -54932 -54933 -54934 -54935 -54936 -54937 -54938 -54939 -54940 -54941 -54942 -54943 -54944 -54945 -54946 -54947 -54948 -54949 -54950 -54951 -54952 -54953 -54954 -54955 -54956 -54957 -54958 -54959 -54960 -54961 -54962 -54963 -54964 -54965 -54966 -54967 -54968 -54969 -54970 -54971 -54972 -54973 -54974 -54975 -54976 -54977 -54978 -54979 -54980 -54981 -54982 -54983 -54984 -54985 -54986 -54987 -54988 -54989 -54990 -54991 -54992 -54993 -54994 -54995 -54996 -54997 -54998 -54999 -55000 -55001 -55002 -55003 -55004 -55005 -55006 -55007 -55008 -55009 -55010 -55011 -55012 -55013 -55014 -55015 -55016 -55017 -55018 -55019 -55020 -55021 -55022 -55023 -55024 -55025 -55026 -55027 -55028 -55029 -55030 -55031 -55032 -55033 -55034 -55035 -55036 -55037 -55038 -55039 -55040 -55041 -55042 -55043 -55044 -55045 -55046 -55047 -55048 -55049 -55050 -55051 -55052 -55053 -55054 -55055 -55056 -55057 -55058 -55059 -55060 -55061 -55062 -55063 -55064 -55065 -55066 -55067 -55068 -55069 -55070 -55071 -55072 -55073 -55074 -55075 -55076 -55077 -55078 -55079 -55080 -55081 -55082 -55083 -55084 -55085 -55086 -55087 -55088 -55089 -55090 -55091 -55092 -55093 -55094 -55095 -55096 -55097 -55098 -55099 -55100 -55101 -55102 -55103 -55104 -55105 -55106 -55107 -55108 -55109 -55110 -55111 -55112 -55113 -55114 -55115 -55116 -55117 -55118 -55119 -55120 -55121 -55122 -55123 -55124 -55125 -55126 -55127 -55128 -55129 -55130 -55131 -55132 -55133 -55134 -55135 -55136 -55137 -55138 -55139 -55140 -55141 -55142 -55143 -55144 -55145 -55146 -55147 -55148 -55149 -55150 -55151 -55152 -55153 -55154 -55155 -55156 -55157 -55158 -55159 -55160 -55161 -55162 -55163 -55164 -55165 -55166 -55167 -55168 -55169 -55170 -55171 -55172 -55173 -55174 -55175 -55176 -55177 -55178 -55179 -55180 -55181 -55182 -55183 -55184 -55185 -55186 -55187 -55188 -55189 -55190 -55191 -55192 -55193 -55194 -55195 -55196 -55197 -55198 -55199 -55200 -55201 -55202 -55203 -55204 -55205 -55206 -55207 -55208 -55209 -55210 -55211 -55212 -55213 -55214 -55215 -55216 -55217 -55218 -55219 -55220 -55221 -55222 -55223 -55224 -55225 -55226 -55227 -55228 -55229 -55230 -55231 -55232 -55233 -55234 -55235 -55236 -55237 -55238 -55239 -55240 -55241 -55242 -55243 -55244 -55245 -55246 -55247 -55248 -55249 -55250 -55251 -55252 -55253 -55254 -55255 -55256 -55257 -55258 -55259 -55260 -55261 -55262 -55263 -55264 -55265 -55266 -55267 -55268 -55269 -55270 -55271 -55272 -55273 -55274 -55275 -55276 -55277 -55278 -55279 -55280 -55281 -55282 -55283 -55284 -55285 -55286 -55287 -55288 -55289 -55290 -55291 -55292 -55293 -55294 -55295 -55296 -55297 -55298 -55299 -55300 -55301 -55302 -55303 -55304 -55305 -55306 -55307 -55308 -55309 -55310 -55311 -55312 -55313 -55314 -55315 -55316 -55317 -55318 -55319 -55320 -55321 -55322 -55323 -55324 -55325 -55326 -55327 -55328 -55329 -55330 -55331 -55332 -55333 -55334 -55335 -55336 -55337 -55338 -55339 -55340 -55341 -55342 -55343 -55344 -55345 -55346 -55347 -55348 -55349 -55350 -55351 -55352 -55353 -55354 -55355 -55356 -55357 -55358 -55359 -55360 -55361 -55362 -55363 -55364 -55365 -55366 -55367 -55368 -55369 -55370 -55371 -55372 -55373 -55374 -55375 -55376 -55377 -55378 -55379 -55380 -55381 -55382 -55383 -55384 -55385 -55386 -55387 -55388 -55389 -55390 -55391 -55392 -55393 -55394 -55395 -55396 -55397 -55398 -55399 -55400 -55401 -55402 -55403 -55404 -55405 -55406 -55407 -55408 -55409 -55410 -55411 -55412 -55413 -55414 -55415 -55416 -55417 -55418 -55419 -55420 -55421 -55422 -55423 -55424 -55425 -55426 -55427 -55428 -55429 -55430 -55431 -55432 -55433 -55434 -55435 -55436 -55437 -55438 -55439 -55440 -55441 -55442 -55443 -55444 -55445 -55446 -55447 -55448 -55449 -55450 -55451 -55452 -55453 -55454 -55455 -55456 -55457 -55458 -55459 -55460 -55461 -55462 -55463 -55464 -55465 -55466 -55467 -55468 -55469 -55470 -55471 -55472 -55473 -55474 -55475 -55476 -55477 -55478 -55479 -55480 -55481 -55482 -55483 -55484 -55485 -55486 -55487 -55488 -55489 -55490 -55491 -55492 -55493 -55494 -55495 -55496 -55497 -55498 -55499 -55500 -55501 -55502 -55503 -55504 -55505 -55506 -55507 -55508 -55509 -55510 -55511 -55512 -55513 -55514 -55515 -55516 -55517 -55518 -55519 -55520 -55521 -55522 -55523 -55524 -55525 -55526 -55527 -55528 -55529 -55530 -55531 -55532 -55533 -55534 -55535 -55536 -55537 -55538 -55539 -55540 -55541 -55542 -55543 -55544 -55545 -55546 -55547 -55548 -55549 -55550 -55551 -55552 -55553 -55554 -55555 -55556 -55557 -55558 -55559 -55560 -55561 -55562 -55563 -55564 -55565 -55566 -55567 -55568 -55569 -55570 -55571 -55572 -55573 -55574 -55575 -55576 -55577 -55578 -55579 -55580 -55581 -55582 -55583 -55584 -55585 -55586 -55587 -55588 -55589 -55590 -55591 -55592 -55593 -55594 -55595 -55596 -55597 -55598 -55599 -55600 -55601 -55602 -55603 -55604 -55605 -55606 -55607 -55608 -55609 -55610 -55611 -55612 -55613 -55614 -55615 -55616 -55617 -55618 -55619 -55620 -55621 -55622 -55623 -55624 -55625 -55626 -55627 -55628 -55629 -55630 -55631 -55632 -55633 -55634 -55635 -55636 -55637 -55638 -55639 -55640 -55641 -55642 -55643 -55644 -55645 -55646 -55647 -55648 -55649 -55650 -55651 -55652 -55653 -55654 -55655 -55656 -55657 -55658 -55659 -55660 -55661 -55662 -55663 -55664 -55665 -55666 -55667 -55668 -55669 -55670 -55671 -55672 -55673 -55674 -55675 -55676 -55677 -55678 -55679 -55680 -55681 -55682 -55683 -55684 -55685 -55686 -55687 -55688 -55689 -55690 -55691 -55692 -55693 -55694 -55695 -55696 -55697 -55698 -55699 -55700 -55701 -55702 -55703 -55704 -55705 -55706 -55707 -55708 -55709 -55710 -55711 -55712 -55713 -55714 -55715 -55716 -55717 -55718 -55719 -55720 -55721 -55722 -55723 -55724 -55725 -55726 -55727 -55728 -55729 -55730 -55731 -55732 -55733 -55734 -55735 -55736 -55737 -55738 -55739 -55740 -55741 -55742 -55743 -55744 -55745 -55746 -55747 -55748 -55749 -55750 -55751 -55752 -55753 -55754 -55755 -55756 -55757 -55758 -55759 -55760 -55761 -55762 -55763 -55764 -55765 -55766 -55767 -55768 -55769 -55770 -55771 -55772 -55773 -55774 -55775 -55776 -55777 -55778 -55779 -55780 -55781 -55782 -55783 -55784 -55785 -55786 -55787 -55788 -55789 -55790 -55791 -55792 -55793 -55794 -55795 -55796 -55797 -55798 -55799 -55800 -55801 -55802 -55803 -55804 -55805 -55806 -55807 -55808 -55809 -55810 -55811 -55812 -55813 -55814 -55815 -55816 -55817 -55818 -55819 -55820 -55821 -55822 -55823 -55824 -55825 -55826 -55827 -55828 -55829 -55830 -55831 -55832 -55833 -55834 -55835 -55836 -55837 -55838 -55839 -55840 -55841 -55842 -55843 -55844 -55845 -55846 -55847 -55848 -55849 -55850 -55851 -55852 -55853 -55854 -55855 -55856 -55857 -55858 -55859 -55860 -55861 -55862 -55863 -55864 -55865 -55866 -55867 -55868 -55869 -55870 -55871 -55872 -55873 -55874 -55875 -55876 -55877 -55878 -55879 -55880 -55881 -55882 -55883 -55884 -55885 -55886 -55887 -55888 -55889 -55890 -55891 -55892 -55893 -55894 -55895 -55896 -55897 -55898 -55899 -55900 -55901 -55902 -55903 -55904 -55905 -55906 -55907 -55908 -55909 -55910 -55911 -55912 -55913 -55914 -55915 -55916 -55917 -55918 -55919 -55920 -55921 -55922 -55923 -55924 -55925 -55926 -55927 -55928 -55929 -55930 -55931 -55932 -55933 -55934 -55935 -55936 -55937 -55938 -55939 -55940 -55941 -55942 -55943 -55944 -55945 -55946 -55947 -55948 -55949 -55950 -55951 -55952 -55953 -55954 -55955 -55956 -55957 -55958 -55959 -55960 -55961 -55962 -55963 -55964 -55965 -55966 -55967 -55968 -55969 -55970 -55971 -55972 -55973 -55974 -55975 -55976 -55977 -55978 -55979 -55980 -55981 -55982 -55983 -55984 -55985 -55986 -55987 -55988 -55989 -55990 -55991 -55992 -55993 -55994 -55995 -55996 -55997 -55998 -55999 -56000 -56001 -56002 -56003 -56004 -56005 -56006 -56007 -56008 -56009 -56010 -56011 -56012 -56013 -56014 -56015 -56016 -56017 -56018 -56019 -56020 -56021 -56022 -56023 -56024 -56025 -56026 -56027 -56028 -56029 -56030 -56031 -56032 -56033 -56034 -56035 -56036 -56037 -56038 -56039 -56040 -56041 -56042 -56043 -56044 -56045 -56046 -56047 -56048 -56049 -56050 -56051 -56052 -56053 -56054 -56055 -56056 -56057 -56058 -56059 -56060 -56061 -56062 -56063 -56064 -56065 -56066 -56067 -56068 -56069 -56070 -56071 -56072 -56073 -56074 -56075 -56076 -56077 -56078 -56079 -56080 -56081 -56082 -56083 -56084 -56085 -56086 -56087 -56088 -56089 -56090 -56091 -56092 -56093 -56094 -56095 -56096 -56097 -56098 -56099 -56100 -56101 -56102 -56103 -56104 -56105 -56106 -56107 -56108 -56109 -56110 -56111 -56112 -56113 -56114 -56115 -56116 -56117 -56118 -56119 -56120 -56121 -56122 -56123 -56124 -56125 -56126 -56127 -56128 -56129 -56130 -56131 -56132 -56133 -56134 -56135 -56136 -56137 -56138 -56139 -56140 -56141 -56142 -56143 -56144 -56145 -56146 -56147 -56148 -56149 -56150 -56151 -56152 -56153 -56154 -56155 -56156 -56157 -56158 -56159 -56160 -56161 -56162 -56163 -56164 -56165 -56166 -56167 -56168 -56169 -56170 -56171 -56172 -56173 -56174 -56175 -56176 -56177 -56178 -56179 -56180 -56181 -56182 -56183 -56184 -56185 -56186 -56187 -56188 -56189 -56190 -56191 -56192 -56193 -56194 -56195 -56196 -56197 -56198 -56199 -56200 -56201 -56202 -56203 -56204 -56205 -56206 -56207 -56208 -56209 -56210 -56211 -56212 -56213 -56214 -56215 -56216 -56217 -56218 -56219 -56220 -56221 -56222 -56223 -56224 -56225 -56226 -56227 -56228 -56229 -56230 -56231 -56232 -56233 -56234 -56235 -56236 -56237 -56238 -56239 -56240 -56241 -56242 -56243 -56244 -56245 -56246 -56247 -56248 -56249 -56250 -56251 -56252 -56253 -56254 -56255 -56256 -56257 -56258 -56259 -56260 -56261 -56262 -56263 -56264 -56265 -56266 -56267 -56268 -56269 -56270 -56271 -56272 -56273 -56274 -56275 -56276 -56277 -56278 -56279 -56280 -56281 -56282 -56283 -56284 -56285 -56286 -56287 -56288 -56289 -56290 -56291 -56292 -56293 -56294 -56295 -56296 -56297 -56298 -56299 -56300 -56301 -56302 -56303 -56304 -56305 -56306 -56307 -56308 -56309 -56310 -56311 -56312 -56313 -56314 -56315 -56316 -56317 -56318 -56319 -56320 -56321 -56322 -56323 -56324 -56325 -56326 -56327 -56328 -56329 -56330 -56331 -56332 -56333 -56334 -56335 -56336 -56337 -56338 -56339 -56340 -56341 -56342 -56343 -56344 -56345 -56346 -56347 -56348 -56349 -56350 -56351 -56352 -56353 -56354 -56355 -56356 -56357 -56358 -56359 -56360 -56361 -56362 -56363 -56364 -56365 -56366 -56367 -56368 -56369 -56370 -56371 -56372 -56373 -56374 -56375 -56376 -56377 -56378 -56379 -56380 -56381 -56382 -56383 -56384 -56385 -56386 -56387 -56388 -56389 -56390 -56391 -56392 -56393 -56394 -56395 -56396 -56397 -56398 -56399 -56400 -56401 -56402 -56403 -56404 -56405 -56406 -56407 -56408 -56409 -56410 -56411 -56412 -56413 -56414 -56415 -56416 -56417 -56418 -56419 -56420 -56421 -56422 -56423 -56424 -56425 -56426 -56427 -56428 -56429 -56430 -56431 -56432 -56433 -56434 -56435 -56436 -56437 -56438 -56439 -56440 -56441 -56442 -56443 -56444 -56445 -56446 -56447 -56448 -56449 -56450 -56451 -56452 -56453 -56454 -56455 -56456 -56457 -56458 -56459 -56460 -56461 -56462 -56463 -56464 -56465 -56466 -56467 -56468 -56469 -56470 -56471 -56472 -56473 -56474 -56475 -56476 -56477 -56478 -56479 -56480 -56481 -56482 -56483 -56484 -56485 -56486 -56487 -56488 -56489 -56490 -56491 -56492 -56493 -56494 -56495 -56496 -56497 -56498 -56499 -56500 -56501 -56502 -56503 -56504 -56505 -56506 -56507 -56508 -56509 -56510 -56511 -56512 -56513 -56514 -56515 -56516 -56517 -56518 -56519 -56520 -56521 -56522 -56523 -56524 -56525 -56526 -56527 -56528 -56529 -56530 -56531 -56532 -56533 -56534 -56535 -56536 -56537 -56538 -56539 -56540 -56541 -56542 -56543 -56544 -56545 -56546 -56547 -56548 -56549 -56550 -56551 -56552 -56553 -56554 -56555 -56556 -56557 -56558 -56559 -56560 -56561 -56562 -56563 -56564 -56565 -56566 -56567 -56568 -56569 -56570 -56571 -56572 -56573 -56574 -56575 -56576 -56577 -56578 -56579 -56580 -56581 -56582 -56583 -56584 -56585 -56586 -56587 -56588 -56589 -56590 -56591 -56592 -56593 -56594 -56595 -56596 -56597 -56598 -56599 -56600 -56601 -56602 -56603 -56604 -56605 -56606 -56607 -56608 -56609 -56610 -56611 -56612 -56613 -56614 -56615 -56616 -56617 -56618 -56619 -56620 -56621 -56622 -56623 -56624 -56625 -56626 -56627 -56628 -56629 -56630 -56631 -56632 -56633 -56634 -56635 -56636 -56637 -56638 -56639 -56640 -56641 -56642 -56643 -56644 -56645 -56646 -56647 -56648 -56649 -56650 -56651 -56652 -56653 -56654 -56655 -56656 -56657 -56658 -56659 -56660 -56661 -56662 -56663 -56664 -56665 -56666 -56667 -56668 -56669 -56670 -56671 -56672 -56673 -56674 -56675 -56676 -56677 -56678 -56679 -56680 -56681 -56682 -56683 -56684 -56685 -56686 -56687 -56688 -56689 -56690 -56691 -56692 -56693 -56694 -56695 -56696 -56697 -56698 -56699 -56700 -56701 -56702 -56703 -56704 -56705 -56706 -56707 -56708 -56709 -56710 -56711 -56712 -56713 -56714 -56715 -56716 -56717 -56718 -56719 -56720 -56721 -56722 -56723 -56724 -56725 -56726 -56727 -56728 -56729 -56730 -56731 -56732 -56733 -56734 -56735 -56736 -56737 -56738 -56739 -56740 -56741 -56742 -56743 -56744 -56745 -56746 -56747 -56748 -56749 -56750 -56751 -56752 -56753 -56754 -56755 -56756 -56757 -56758 -56759 -56760 -56761 -56762 -56763 -56764 -56765 -56766 -56767 -56768 -56769 -56770 -56771 -56772 -56773 -56774 -56775 -56776 -56777 -56778 -56779 -56780 -56781 -56782 -56783 -56784 -56785 -56786 -56787 -56788 -56789 -56790 -56791 -56792 -56793 -56794 -56795 -56796 -56797 -56798 -56799 -56800 -56801 -56802 -56803 -56804 -56805 -56806 -56807 -56808 -56809 -56810 -56811 -56812 -56813 -56814 -56815 -56816 -56817 -56818 -56819 -56820 -56821 -56822 -56823 -56824 -56825 -56826 -56827 -56828 -56829 -56830 -56831 -56832 -56833 -56834 -56835 -56836 -56837 -56838 -56839 -56840 -56841 -56842 -56843 -56844 -56845 -56846 -56847 -56848 -56849 -56850 -56851 -56852 -56853 -56854 -56855 -56856 -56857 -56858 -56859 -56860 -56861 -56862 -56863 -56864 -56865 -56866 -56867 -56868 -56869 -56870 -56871 -56872 -56873 -56874 -56875 -56876 -56877 -56878 -56879 -56880 -56881 -56882 -56883 -56884 -56885 -56886 -56887 -56888 -56889 -56890 -56891 -56892 -56893 -56894 -56895 -56896 -56897 -56898 -56899 -56900 -56901 -56902 -56903 -56904 -56905 -56906 -56907 -56908 -56909 -56910 -56911 -56912 -56913 -56914 -56915 -56916 -56917 -56918 -56919 -56920 -56921 -56922 -56923 -56924 -56925 -56926 -56927 -56928 -56929 -56930 -56931 -56932 -56933 -56934 -56935 -56936 -56937 -56938 -56939 -56940 -56941 -56942 -56943 -56944 -56945 -56946 -56947 -56948 -56949 -56950 -56951 -56952 -56953 -56954 -56955 -56956 -56957 -56958 -56959 -56960 -56961 -56962 -56963 -56964 -56965 -56966 -56967 -56968 -56969 -56970 -56971 -56972 -56973 -56974 -56975 -56976 -56977 -56978 -56979 -56980 -56981 -56982 -56983 -56984 -56985 -56986 -56987 -56988 -56989 -56990 -56991 -56992 -56993 -56994 -56995 -56996 -56997 -56998 -56999 -57000 -57001 -57002 -57003 -57004 -57005 -57006 -57007 -57008 -57009 -57010 -57011 -57012 -57013 -57014 -57015 -57016 -57017 -57018 -57019 -57020 -57021 -57022 -57023 -57024 -57025 -57026 -57027 -57028 -57029 -57030 -57031 -57032 -57033 -57034 -57035 -57036 -57037 -57038 -57039 -57040 -57041 -57042 -57043 -57044 -57045 -57046 -57047 -57048 -57049 -57050 -57051 -57052 -57053 -57054 -57055 -57056 -57057 -57058 -57059 -57060 -57061 -57062 -57063 -57064 -57065 -57066 -57067 -57068 -57069 -57070 -57071 -57072 -57073 -57074 -57075 -57076 -57077 -57078 -57079 -57080 -57081 -57082 -57083 -57084 -57085 -57086 -57087 -57088 -57089 -57090 -57091 -57092 -57093 -57094 -57095 -57096 -57097 -57098 -57099 -57100 -57101 -57102 -57103 -57104 -57105 -57106 -57107 -57108 -57109 -57110 -57111 -57112 -57113 -57114 -57115 -57116 -57117 -57118 -57119 -57120 -57121 -57122 -57123 -57124 -57125 -57126 -57127 -57128 -57129 -57130 -57131 -57132 -57133 -57134 -57135 -57136 -57137 -57138 -57139 -57140 -57141 -57142 -57143 -57144 -57145 -57146 -57147 -57148 -57149 -57150 -57151 -57152 -57153 -57154 -57155 -57156 -57157 -57158 -57159 -57160 -57161 -57162 -57163 -57164 -57165 -57166 -57167 -57168 -57169 -57170 -57171 -57172 -57173 -57174 -57175 -57176 -57177 -57178 -57179 -57180 -57181 -57182 -57183 -57184 -57185 -57186 -57187 -57188 -57189 -57190 -57191 -57192 -57193 -57194 -57195 -57196 -57197 -57198 -57199 -57200 -57201 -57202 -57203 -57204 -57205 -57206 -57207 -57208 -57209 -57210 -57211 -57212 -57213 -57214 -57215 -57216 -57217 -57218 -57219 -57220 -57221 -57222 -57223 -57224 -57225 -57226 -57227 -57228 -57229 -57230 -57231 -57232 -57233 -57234 -57235 -57236 -57237 -57238 -57239 -57240 -57241 -57242 -57243 -57244 -57245 -57246 -57247 -57248 -57249 -57250 -57251 -57252 -57253 -57254 -57255 -57256 -57257 -57258 -57259 -57260 -57261 -57262 -57263 -57264 -57265 -57266 -57267 -57268 -57269 -57270 -57271 -57272 -57273 -57274 -57275 -57276 -57277 -57278 -57279 -57280 -57281 -57282 -57283 -57284 -57285 -57286 -57287 -57288 -57289 -57290 -57291 -57292 -57293 -57294 -57295 -57296 -57297 -57298 -57299 -57300 -57301 -57302 -57303 -57304 -57305 -57306 -57307 -57308 -57309 -57310 -57311 -57312 -57313 -57314 -57315 -57316 -57317 -57318 -57319 -57320 -57321 -57322 -57323 -57324 -57325 -57326 -57327 -57328 -57329 -57330 -57331 -57332 -57333 -57334 -57335 -57336 -57337 -57338 -57339 -57340 -57341 -57342 -57343 -57344 -57345 -57346 -57347 -57348 -57349 -57350 -57351 -57352 -57353 -57354 -57355 -57356 -57357 -57358 -57359 -57360 -57361 -57362 -57363 -57364 -57365 -57366 -57367 -57368 -57369 -57370 -57371 -57372 -57373 -57374 -57375 -57376 -57377 -57378 -57379 -57380 -57381 -57382 -57383 -57384 -57385 -57386 -57387 -57388 -57389 -57390 -57391 -57392 -57393 -57394 -57395 -57396 -57397 -57398 -57399 -57400 -57401 -57402 -57403 -57404 -57405 -57406 -57407 -57408 -57409 -57410 -57411 -57412 -57413 -57414 -57415 -57416 -57417 -57418 -57419 -57420 -57421 -57422 -57423 -57424 -57425 -57426 -57427 -57428 -57429 -57430 -57431 -57432 -57433 -57434 -57435 -57436 -57437 -57438 -57439 -57440 -57441 -57442 -57443 -57444 -57445 -57446 -57447 -57448 -57449 -57450 -57451 -57452 -57453 -57454 -57455 -57456 -57457 -57458 -57459 -57460 -57461 -57462 -57463 -57464 -57465 -57466 -57467 -57468 -57469 -57470 -57471 -57472 -57473 -57474 -57475 -57476 -57477 -57478 -57479 -57480 -57481 -57482 -57483 -57484 -57485 -57486 -57487 -57488 -57489 -57490 -57491 -57492 -57493 -57494 -57495 -57496 -57497 -57498 -57499 -57500 -57501 -57502 -57503 -57504 -57505 -57506 -57507 -57508 -57509 -57510 -57511 -57512 -57513 -57514 -57515 -57516 -57517 -57518 -57519 -57520 -57521 -57522 -57523 -57524 -57525 -57526 -57527 -57528 -57529 -57530 -57531 -57532 -57533 -57534 -57535 -57536 -57537 -57538 -57539 -57540 -57541 -57542 -57543 -57544 -57545 -57546 -57547 -57548 -57549 -57550 -57551 -57552 -57553 -57554 -57555 -57556 -57557 -57558 -57559 -57560 -57561 -57562 -57563 -57564 -57565 -57566 -57567 -57568 -57569 -57570 -57571 -57572 -57573 -57574 -57575 -57576 -57577 -57578 -57579 -57580 -57581 -57582 -57583 -57584 -57585 -57586 -57587 -57588 -57589 -57590 -57591 -57592 -57593 -57594 -57595 -57596 -57597 -57598 -57599 -57600 -57601 -57602 -57603 -57604 -57605 -57606 -57607 -57608 -57609 -57610 -57611 -57612 -57613 -57614 -57615 -57616 -57617 -57618 -57619 -57620 -57621 -57622 -57623 -57624 -57625 -57626 -57627 -57628 -57629 -57630 -57631 -57632 -57633 -57634 -57635 -57636 -57637 -57638 -57639 -57640 -57641 -57642 -57643 -57644 -57645 -57646 -57647 -57648 -57649 -57650 -57651 -57652 -57653 -57654 -57655 -57656 -57657 -57658 -57659 -57660 -57661 -57662 -57663 -57664 -57665 -57666 -57667 -57668 -57669 -57670 -57671 -57672 -57673 -57674 -57675 -57676 -57677 -57678 -57679 -57680 -57681 -57682 -57683 -57684 -57685 -57686 -57687 -57688 -57689 -57690 -57691 -57692 -57693 -57694 -57695 -57696 -57697 -57698 -57699 -57700 -57701 -57702 -57703 -57704 -57705 -57706 -57707 -57708 -57709 -57710 -57711 -57712 -57713 -57714 -57715 -57716 -57717 -57718 -57719 -57720 -57721 -57722 -57723 -57724 -57725 -57726 -57727 -57728 -57729 -57730 -57731 -57732 -57733 -57734 -57735 -57736 -57737 -57738 -57739 -57740 -57741 -57742 -57743 -57744 -57745 -57746 -57747 -57748 -57749 -57750 -57751 -57752 -57753 -57754 -57755 -57756 -57757 -57758 -57759 -57760 -57761 -57762 -57763 -57764 -57765 -57766 -57767 -57768 -57769 -57770 -57771 -57772 -57773 -57774 -57775 -57776 -57777 -57778 -57779 -57780 -57781 -57782 -57783 -57784 -57785 -57786 -57787 -57788 -57789 -57790 -57791 -57792 -57793 -57794 -57795 -57796 -57797 -57798 -57799 -57800 -57801 -57802 -57803 -57804 -57805 -57806 -57807 -57808 -57809 -57810 -57811 -57812 -57813 -57814 -57815 -57816 -57817 -57818 -57819 -57820 -57821 -57822 -57823 -57824 -57825 -57826 -57827 -57828 -57829 -57830 -57831 -57832 -57833 -57834 -57835 -57836 -57837 -57838 -57839 -57840 -57841 -57842 -57843 -57844 -57845 -57846 -57847 -57848 -57849 -57850 -57851 -57852 -57853 -57854 -57855 -57856 -57857 -57858 -57859 -57860 -57861 -57862 -57863 -57864 -57865 -57866 -57867 -57868 -57869 -57870 -57871 -57872 -57873 -57874 -57875 -57876 -57877 -57878 -57879 -57880 -57881 -57882 -57883 -57884 -57885 -57886 -57887 -57888 -57889 -57890 -57891 -57892 -57893 -57894 -57895 -57896 -57897 -57898 -57899 -57900 -57901 -57902 -57903 -57904 -57905 -57906 -57907 -57908 -57909 -57910 -57911 -57912 -57913 -57914 -57915 -57916 -57917 -57918 -57919 -57920 -57921 -57922 -57923 -57924 -57925 -57926 -57927 -57928 -57929 -57930 -57931 -57932 -57933 -57934 -57935 -57936 -57937 -57938 -57939 -57940 -57941 -57942 -57943 -57944 -57945 -57946 -57947 -57948 -57949 -57950 -57951 -57952 -57953 -57954 -57955 -57956 -57957 -57958 -57959 -57960 -57961 -57962 -57963 -57964 -57965 -57966 -57967 -57968 -57969 -57970 -57971 -57972 -57973 -57974 -57975 -57976 -57977 -57978 -57979 -57980 -57981 -57982 -57983 -57984 -57985 -57986 -57987 -57988 -57989 -57990 -57991 -57992 -57993 -57994 -57995 -57996 -57997 -57998 -57999 -58000 -58001 -58002 -58003 -58004 -58005 -58006 -58007 -58008 -58009 -58010 -58011 -58012 -58013 -58014 -58015 -58016 -58017 -58018 -58019 -58020 -58021 -58022 -58023 -58024 -58025 -58026 -58027 -58028 -58029 -58030 -58031 -58032 -58033 -58034 -58035 -58036 -58037 -58038 -58039 -58040 -58041 -58042 -58043 -58044 -58045 -58046 -58047 -58048 -58049 -58050 -58051 -58052 -58053 -58054 -58055 -58056 -58057 -58058 -58059 -58060 -58061 -58062 -58063 -58064 -58065 -58066 -58067 -58068 -58069 -58070 -58071 -58072 -58073 -58074 -58075 -58076 -58077 -58078 -58079 -58080 -58081 -58082 -58083 -58084 -58085 -58086 -58087 -58088 -58089 -58090 -58091 -58092 -58093 -58094 -58095 -58096 -58097 -58098 -58099 -58100 -58101 -58102 -58103 -58104 -58105 -58106 -58107 -58108 -58109 -58110 -58111 -58112 -58113 -58114 -58115 -58116 -58117 -58118 -58119 -58120 -58121 -58122 -58123 -58124 -58125 -58126 -58127 -58128 -58129 -58130 -58131 -58132 -58133 -58134 -58135 -58136 -58137 -58138 -58139 -58140 -58141 -58142 -58143 -58144 -58145 -58146 -58147 -58148 -58149 -58150 -58151 -58152 -58153 -58154 -58155 -58156 -58157 -58158 -58159 -58160 -58161 -58162 -58163 -58164 -58165 -58166 -58167 -58168 -58169 -58170 -58171 -58172 -58173 -58174 -58175 -58176 -58177 -58178 -58179 -58180 -58181 -58182 -58183 -58184 -58185 -58186 -58187 -58188 -58189 -58190 -58191 -58192 -58193 -58194 -58195 -58196 -58197 -58198 -58199 -58200 -58201 -58202 -58203 -58204 -58205 -58206 -58207 -58208 -58209 -58210 -58211 -58212 -58213 -58214 -58215 -58216 -58217 -58218 -58219 -58220 -58221 -58222 -58223 -58224 -58225 -58226 -58227 -58228 -58229 -58230 -58231 -58232 -58233 -58234 -58235 -58236 -58237 -58238 -58239 -58240 -58241 -58242 -58243 -58244 -58245 -58246 -58247 -58248 -58249 -58250 -58251 -58252 -58253 -58254 -58255 -58256 -58257 -58258 -58259 -58260 -58261 -58262 -58263 -58264 -58265 -58266 -58267 -58268 -58269 -58270 -58271 -58272 -58273 -58274 -58275 -58276 -58277 -58278 -58279 -58280 -58281 -58282 -58283 -58284 -58285 -58286 -58287 -58288 -58289 -58290 -58291 -58292 -58293 -58294 -58295 -58296 -58297 -58298 -58299 -58300 -58301 -58302 -58303 -58304 -58305 -58306 -58307 -58308 -58309 -58310 -58311 -58312 -58313 -58314 -58315 -58316 -58317 -58318 -58319 -58320 -58321 -58322 -58323 -58324 -58325 -58326 -58327 -58328 -58329 -58330 -58331 -58332 -58333 -58334 -58335 -58336 -58337 -58338 -58339 -58340 -58341 -58342 -58343 -58344 -58345 -58346 -58347 -58348 -58349 -58350 -58351 -58352 -58353 -58354 -58355 -58356 -58357 -58358 -58359 -58360 -58361 -58362 -58363 -58364 -58365 -58366 -58367 -58368 -58369 -58370 -58371 -58372 -58373 -58374 -58375 -58376 -58377 -58378 -58379 -58380 -58381 -58382 -58383 -58384 -58385 -58386 -58387 -58388 -58389 -58390 -58391 -58392 -58393 -58394 -58395 -58396 -58397 -58398 -58399 -58400 -58401 -58402 -58403 -58404 -58405 -58406 -58407 -58408 -58409 -58410 -58411 -58412 -58413 -58414 -58415 -58416 -58417 -58418 -58419 -58420 -58421 -58422 -58423 -58424 -58425 -58426 -58427 -58428 -58429 -58430 -58431 -58432 -58433 -58434 -58435 -58436 -58437 -58438 -58439 -58440 -58441 -58442 -58443 -58444 -58445 -58446 -58447 -58448 -58449 -58450 -58451 -58452 -58453 -58454 -58455 -58456 -58457 -58458 -58459 -58460 -58461 -58462 -58463 -58464 -58465 -58466 -58467 -58468 -58469 -58470 -58471 -58472 -58473 -58474 -58475 -58476 -58477 -58478 -58479 -58480 -58481 -58482 -58483 -58484 -58485 -58486 -58487 -58488 -58489 -58490 -58491 -58492 -58493 -58494 -58495 -58496 -58497 -58498 -58499 -58500 -58501 -58502 -58503 -58504 -58505 -58506 -58507 -58508 -58509 -58510 -58511 -58512 -58513 -58514 -58515 -58516 -58517 -58518 -58519 -58520 -58521 -58522 -58523 -58524 -58525 -58526 -58527 -58528 -58529 -58530 -58531 -58532 -58533 -58534 -58535 -58536 -58537 -58538 -58539 -58540 -58541 -58542 -58543 -58544 -58545 -58546 -58547 -58548 -58549 -58550 -58551 -58552 -58553 -58554 -58555 -58556 -58557 -58558 -58559 -58560 -58561 -58562 -58563 -58564 -58565 -58566 -58567 -58568 -58569 -58570 -58571 -58572 -58573 -58574 -58575 -58576 -58577 -58578 -58579 -58580 -58581 -58582 -58583 -58584 -58585 -58586 -58587 -58588 -58589 -58590 -58591 -58592 -58593 -58594 -58595 -58596 -58597 -58598 -58599 -58600 -58601 -58602 -58603 -58604 -58605 -58606 -58607 -58608 -58609 -58610 -58611 -58612 -58613 -58614 -58615 -58616 -58617 -58618 -58619 -58620 -58621 -58622 -58623 -58624 -58625 -58626 -58627 -58628 -58629 -58630 -58631 -58632 -58633 -58634 -58635 -58636 -58637 -58638 -58639 -58640 -58641 -58642 -58643 -58644 -58645 -58646 -58647 -58648 -58649 -58650 -58651 -58652 -58653 -58654 -58655 -58656 -58657 -58658 -58659 -58660 -58661 -58662 -58663 -58664 -58665 -58666 -58667 -58668 -58669 -58670 -58671 -58672 -58673 -58674 -58675 -58676 -58677 -58678 -58679 -58680 -58681 -58682 -58683 -58684 -58685 -58686 -58687 -58688 -58689 -58690 -58691 -58692 -58693 -58694 -58695 -58696 -58697 -58698 -58699 -58700 -58701 -58702 -58703 -58704 -58705 -58706 -58707 -58708 -58709 -58710 -58711 -58712 -58713 -58714 -58715 -58716 -58717 -58718 -58719 -58720 -58721 -58722 -58723 -58724 -58725 -58726 -58727 -58728 -58729 -58730 -58731 -58732 -58733 -58734 -58735 -58736 -58737 -58738 -58739 -58740 -58741 -58742 -58743 -58744 -58745 -58746 -58747 -58748 -58749 -58750 -58751 -58752 -58753 -58754 -58755 -58756 -58757 -58758 -58759 -58760 -58761 -58762 -58763 -58764 -58765 -58766 -58767 -58768 -58769 -58770 -58771 -58772 -58773 -58774 -58775 -58776 -58777 -58778 -58779 -58780 -58781 -58782 -58783 -58784 -58785 -58786 -58787 -58788 -58789 -58790 -58791 -58792 -58793 -58794 -58795 -58796 -58797 -58798 -58799 -58800 -58801 -58802 -58803 -58804 -58805 -58806 -58807 -58808 -58809 -58810 -58811 -58812 -58813 -58814 -58815 -58816 -58817 -58818 -58819 -58820 -58821 -58822 -58823 -58824 -58825 -58826 -58827 -58828 -58829 -58830 -58831 -58832 -58833 -58834 -58835 -58836 -58837 -58838 -58839 -58840 -58841 -58842 -58843 -58844 -58845 -58846 -58847 -58848 -58849 -58850 -58851 -58852 -58853 -58854 -58855 -58856 -58857 -58858 -58859 -58860 -58861 -58862 -58863 -58864 -58865 -58866 -58867 -58868 -58869 -58870 -58871 -58872 -58873 -58874 -58875 -58876 -58877 -58878 -58879 -58880 -58881 -58882 -58883 -58884 -58885 -58886 -58887 -58888 -58889 -58890 -58891 -58892 -58893 -58894 -58895 -58896 -58897 -58898 -58899 -58900 -58901 -58902 -58903 -58904 -58905 -58906 -58907 -58908 -58909 -58910 -58911 -58912 -58913 -58914 -58915 -58916 -58917 -58918 -58919 -58920 -58921 -58922 -58923 -58924 -58925 -58926 -58927 -58928 -58929 -58930 -58931 -58932 -58933 -58934 -58935 -58936 -58937 -58938 -58939 -58940 -58941 -58942 -58943 -58944 -58945 -58946 -58947 -58948 -58949 -58950 -58951 -58952 -58953 -58954 -58955 -58956 -58957 -58958 -58959 -58960 -58961 -58962 -58963 -58964 -58965 -58966 -58967 -58968 -58969 -58970 -58971 -58972 -58973 -58974 -58975 -58976 -58977 -58978 -58979 -58980 -58981 -58982 -58983 -58984 -58985 -58986 -58987 -58988 -58989 -58990 -58991 -58992 -58993 -58994 -58995 -58996 -58997 -58998 -58999 -59000 -59001 -59002 -59003 -59004 -59005 -59006 -59007 -59008 -59009 -59010 -59011 -59012 -59013 -59014 -59015 -59016 -59017 -59018 -59019 -59020 -59021 -59022 -59023 -59024 -59025 -59026 -59027 -59028 -59029 -59030 -59031 -59032 -59033 -59034 -59035 -59036 -59037 -59038 -59039 -59040 -59041 -59042 -59043 -59044 -59045 -59046 -59047 -59048 -59049 -59050 -59051 -59052 -59053 -59054 -59055 -59056 -59057 -59058 -59059 -59060 -59061 -59062 -59063 -59064 -59065 -59066 -59067 -59068 -59069 -59070 -59071 -59072 -59073 -59074 -59075 -59076 -59077 -59078 -59079 -59080 -59081 -59082 -59083 -59084 -59085 -59086 -59087 -59088 -59089 -59090 -59091 -59092 -59093 -59094 -59095 -59096 -59097 -59098 -59099 -59100 -59101 -59102 -59103 -59104 -59105 -59106 -59107 -59108 -59109 -59110 -59111 -59112 -59113 -59114 -59115 -59116 -59117 -59118 -59119 -59120 -59121 -59122 -59123 -59124 -59125 -59126 -59127 -59128 -59129 -59130 -59131 -59132 -59133 -59134 -59135 -59136 -59137 -59138 -59139 -59140 -59141 -59142 -59143 -59144 -59145 -59146 -59147 -59148 -59149 -59150 -59151 -59152 -59153 -59154 -59155 -59156 -59157 -59158 -59159 -59160 -59161 -59162 -59163 -59164 -59165 -59166 -59167 -59168 -59169 -59170 -59171 -59172 -59173 -59174 -59175 -59176 -59177 -59178 -59179 -59180 -59181 -59182 -59183 -59184 -59185 -59186 -59187 -59188 -59189 -59190 -59191 -59192 -59193 -59194 -59195 -59196 -59197 -59198 -59199 -59200 -59201 -59202 -59203 -59204 -59205 -59206 -59207 -59208 -59209 -59210 -59211 -59212 -59213 -59214 -59215 -59216 -59217 -59218 -59219 -59220 -59221 -59222 -59223 -59224 -59225 -59226 -59227 -59228 -59229 -59230 -59231 -59232 -59233 -59234 -59235 -59236 -59237 -59238 -59239 -59240 -59241 -59242 -59243 -59244 -59245 -59246 -59247 -59248 -59249 -59250 -59251 -59252 -59253 -59254 -59255 -59256 -59257 -59258 -59259 -59260 -59261 -59262 -59263 -59264 -59265 -59266 -59267 -59268 -59269 -59270 -59271 -59272 -59273 -59274 -59275 -59276 -59277 -59278 -59279 -59280 -59281 -59282 -59283 -59284 -59285 -59286 -59287 -59288 -59289 -59290 -59291 -59292 -59293 -59294 -59295 -59296 -59297 -59298 -59299 -59300 -59301 -59302 -59303 -59304 -59305 -59306 -59307 -59308 -59309 -59310 -59311 -59312 -59313 -59314 -59315 -59316 -59317 -59318 -59319 -59320 -59321 -59322 -59323 -59324 -59325 -59326 -59327 -59328 -59329 -59330 -59331 -59332 -59333 -59334 -59335 -59336 -59337 -59338 -59339 -59340 -59341 -59342 -59343 -59344 -59345 -59346 -59347 -59348 -59349 -59350 -59351 -59352 -59353 -59354 -59355 -59356 -59357 -59358 -59359 -59360 -59361 -59362 -59363 -59364 -59365 -59366 -59367 -59368 -59369 -59370 -59371 -59372 -59373 -59374 -59375 -59376 -59377 -59378 -59379 -59380 -59381 -59382 -59383 -59384 -59385 -59386 -59387 -59388 -59389 -59390 -59391 -59392 -59393 -59394 -59395 -59396 -59397 -59398 -59399 -59400 -59401 -59402 -59403 -59404 -59405 -59406 -59407 -59408 -59409 -59410 -59411 -59412 -59413 -59414 -59415 -59416 -59417 -59418 -59419 -59420 -59421 -59422 -59423 -59424 -59425 -59426 -59427 -59428 -59429 -59430 -59431 -59432 -59433 -59434 -59435 -59436 -59437 -59438 -59439 -59440 -59441 -59442 -59443 -59444 -59445 -59446 -59447 -59448 -59449 -59450 -59451 -59452 -59453 -59454 -59455 -59456 -59457 -59458 -59459 -59460 -59461 -59462 -59463 -59464 -59465 -59466 -59467 -59468 -59469 -59470 -59471 -59472 -59473 -59474 -59475 -59476 -59477 -59478 -59479 -59480 -59481 -59482 -59483 -59484 -59485 -59486 -59487 -59488 -59489 -59490 -59491 -59492 -59493 -59494 -59495 -59496 -59497 -59498 -59499 -59500 -59501 -59502 -59503 -59504 -59505 -59506 -59507 -59508 -59509 -59510 -59511 -59512 -59513 -59514 -59515 -59516 -59517 -59518 -59519 -59520 -59521 -59522 -59523 -59524 -59525 -59526 -59527 -59528 -59529 -59530 -59531 -59532 -59533 -59534 -59535 -59536 -59537 -59538 -59539 -59540 -59541 -59542 -59543 -59544 -59545 -59546 -59547 -59548 -59549 -59550 -59551 -59552 -59553 -59554 -59555 -59556 -59557 -59558 -59559 -59560 -59561 -59562 -59563 -59564 -59565 -59566 -59567 -59568 -59569 -59570 -59571 -59572 -59573 -59574 -59575 -59576 -59577 -59578 -59579 -59580 -59581 -59582 -59583 -59584 -59585 -59586 -59587 -59588 -59589 -59590 -59591 -59592 -59593 -59594 -59595 -59596 -59597 -59598 -59599 -59600 -59601 -59602 -59603 -59604 -59605 -59606 -59607 -59608 -59609 -59610 -59611 -59612 -59613 -59614 -59615 -59616 -59617 -59618 -59619 -59620 -59621 -59622 -59623 -59624 -59625 -59626 -59627 -59628 -59629 -59630 -59631 -59632 -59633 -59634 -59635 -59636 -59637 -59638 -59639 -59640 -59641 -59642 -59643 -59644 -59645 -59646 -59647 -59648 -59649 -59650 -59651 -59652 -59653 -59654 -59655 -59656 -59657 -59658 -59659 -59660 -59661 -59662 -59663 -59664 -59665 -59666 -59667 -59668 -59669 -59670 -59671 -59672 -59673 -59674 -59675 -59676 -59677 -59678 -59679 -59680 -59681 -59682 -59683 -59684 -59685 -59686 -59687 -59688 -59689 -59690 -59691 -59692 -59693 -59694 -59695 -59696 -59697 -59698 -59699 -59700 -59701 -59702 -59703 -59704 -59705 -59706 -59707 -59708 -59709 -59710 -59711 -59712 -59713 -59714 -59715 -59716 -59717 -59718 -59719 -59720 -59721 -59722 -59723 -59724 -59725 -59726 -59727 -59728 -59729 -59730 -59731 -59732 -59733 -59734 -59735 -59736 -59737 -59738 -59739 -59740 -59741 -59742 -59743 -59744 -59745 -59746 -59747 -59748 -59749 -59750 -59751 -59752 -59753 -59754 -59755 -59756 -59757 -59758 -59759 -59760 -59761 -59762 -59763 -59764 -59765 -59766 -59767 -59768 -59769 -59770 -59771 -59772 -59773 -59774 -59775 -59776 -59777 -59778 -59779 -59780 -59781 -59782 -59783 -59784 -59785 -59786 -59787 -59788 -59789 -59790 -59791 -59792 -59793 -59794 -59795 -59796 -59797 -59798 -59799 -59800 -59801 -59802 -59803 -59804 -59805 -59806 -59807 -59808 -59809 -59810 -59811 -59812 -59813 -59814 -59815 -59816 -59817 -59818 -59819 -59820 -59821 -59822 -59823 -59824 -59825 -59826 -59827 -59828 -59829 -59830 -59831 -59832 -59833 -59834 -59835 -59836 -59837 -59838 -59839 -59840 -59841 -59842 -59843 -59844 -59845 -59846 -59847 -59848 -59849 -59850 -59851 -59852 -59853 -59854 -59855 -59856 -59857 -59858 -59859 -59860 -59861 -59862 -59863 -59864 -59865 -59866 -59867 -59868 -59869 -59870 -59871 -59872 -59873 -59874 -59875 -59876 -59877 -59878 -59879 -59880 -59881 -59882 -59883 -59884 -59885 -59886 -59887 -59888 -59889 -59890 -59891 -59892 -59893 -59894 -59895 -59896 -59897 -59898 -59899 -59900 -59901 -59902 -59903 -59904 -59905 -59906 -59907 -59908 -59909 -59910 -59911 -59912 -59913 -59914 -59915 -59916 -59917 -59918 -59919 -59920 -59921 -59922 -59923 -59924 -59925 -59926 -59927 -59928 -59929 -59930 -59931 -59932 -59933 -59934 -59935 -59936 -59937 -59938 -59939 -59940 -59941 -59942 -59943 -59944 -59945 -59946 -59947 -59948 -59949 -59950 -59951 -59952 -59953 -59954 -59955 -59956 -59957 -59958 -59959 -59960 -59961 -59962 -59963 -59964 -59965 -59966 -59967 -59968 -59969 -59970 -59971 -59972 -59973 -59974 -59975 -59976 -59977 -59978 -59979 -59980 -59981 -59982 -59983 -59984 -59985 -59986 -59987 -59988 -59989 -59990 -59991 -59992 -59993 -59994 -59995 -59996 -59997 -59998 -59999 -60000 -60001 -60002 -60003 -60004 -60005 -60006 -60007 -60008 -60009 -60010 -60011 -60012 -60013 -60014 -60015 -60016 -60017 -60018 -60019 -60020 -60021 -60022 -60023 -60024 -60025 -60026 -60027 -60028 -60029 -60030 -60031 -60032 -60033 -60034 -60035 -60036 -60037 -60038 -60039 -60040 -60041 -60042 -60043 -60044 -60045 -60046 -60047 -60048 -60049 -60050 -60051 -60052 -60053 -60054 -60055 -60056 -60057 -60058 -60059 -60060 -60061 -60062 -60063 -60064 -60065 -60066 -60067 -60068 -60069 -60070 -60071 -60072 -60073 -60074 -60075 -60076 -60077 -60078 -60079 -60080 -60081 -60082 -60083 -60084 -60085 -60086 -60087 -60088 -60089 -60090 -60091 -60092 -60093 -60094 -60095 -60096 -60097 -60098 -60099 -60100 -60101 -60102 -60103 -60104 -60105 -60106 -60107 -60108 -60109 -60110 -60111 -60112 -60113 -60114 -60115 -60116 -60117 -60118 -60119 -60120 -60121 -60122 -60123 -60124 -60125 -60126 -60127 -60128 -60129 -60130 -60131 -60132 -60133 -60134 -60135 -60136 -60137 -60138 -60139 -60140 -60141 -60142 -60143 -60144 -60145 -60146 -60147 -60148 -60149 -60150 -60151 -60152 -60153 -60154 -60155 -60156 -60157 -60158 -60159 -60160 -60161 -60162 -60163 -60164 -60165 -60166 -60167 -60168 -60169 -60170 -60171 -60172 -60173 -60174 -60175 -60176 -60177 -60178 -60179 -60180 -60181 -60182 -60183 -60184 -60185 -60186 -60187 -60188 -60189 -60190 -60191 -60192 -60193 -60194 -60195 -60196 -60197 -60198 -60199 -60200 -60201 -60202 -60203 -60204 -60205 -60206 -60207 -60208 -60209 -60210 -60211 -60212 -60213 -60214 -60215 -60216 -60217 -60218 -60219 -60220 -60221 -60222 -60223 -60224 -60225 -60226 -60227 -60228 -60229 -60230 -60231 -60232 -60233 -60234 -60235 -60236 -60237 -60238 -60239 -60240 -60241 -60242 -60243 -60244 -60245 -60246 -60247 -60248 -60249 -60250 -60251 -60252 -60253 -60254 -60255 -60256 -60257 -60258 -60259 -60260 -60261 -60262 -60263 -60264 -60265 -60266 -60267 -60268 -60269 -60270 -60271 -60272 -60273 -60274 -60275 -60276 -60277 -60278 -60279 -60280 -60281 -60282 -60283 -60284 -60285 -60286 -60287 -60288 -60289 -60290 -60291 -60292 -60293 -60294 -60295 -60296 -60297 -60298 -60299 -60300 -60301 -60302 -60303 -60304 -60305 -60306 -60307 -60308 -60309 -60310 -60311 -60312 -60313 -60314 -60315 -60316 -60317 -60318 -60319 -60320 -60321 -60322 -60323 -60324 -60325 -60326 -60327 -60328 -60329 -60330 -60331 -60332 -60333 -60334 -60335 -60336 -60337 -60338 -60339 -60340 -60341 -60342 -60343 -60344 -60345 -60346 -60347 -60348 -60349 -60350 -60351 -60352 -60353 -60354 -60355 -60356 -60357 -60358 -60359 -60360 -60361 -60362 -60363 -60364 -60365 -60366 -60367 -60368 -60369 -60370 -60371 -60372 -60373 -60374 -60375 -60376 -60377 -60378 -60379 -60380 -60381 -60382 -60383 -60384 -60385 -60386 -60387 -60388 -60389 -60390 -60391 -60392 -60393 -60394 -60395 -60396 -60397 -60398 -60399 -60400 -60401 -60402 -60403 -60404 -60405 -60406 -60407 -60408 -60409 -60410 -60411 -60412 -60413 -60414 -60415 -60416 -60417 -60418 -60419 -60420 -60421 -60422 -60423 -60424 -60425 -60426 -60427 -60428 -60429 -60430 -60431 -60432 -60433 -60434 -60435 -60436 -60437 -60438 -60439 -60440 -60441 -60442 -60443 -60444 -60445 -60446 -60447 -60448 -60449 -60450 -60451 -60452 -60453 -60454 -60455 -60456 -60457 -60458 -60459 -60460 -60461 -60462 -60463 -60464 -60465 -60466 -60467 -60468 -60469 -60470 -60471 -60472 -60473 -60474 -60475 -60476 -60477 -60478 -60479 -60480 -60481 -60482 -60483 -60484 -60485 -60486 -60487 -60488 -60489 -60490 -60491 -60492 -60493 -60494 -60495 -60496 -60497 -60498 -60499 -60500 -60501 -60502 -60503 -60504 -60505 -60506 -60507 -60508 -60509 -60510 -60511 -60512 -60513 -60514 -60515 -60516 -60517 -60518 -60519 -60520 -60521 -60522 -60523 -60524 -60525 -60526 -60527 -60528 -60529 -60530 -60531 -60532 -60533 -60534 -60535 -60536 -60537 -60538 -60539 -60540 -60541 -60542 -60543 -60544 -60545 -60546 -60547 -60548 -60549 -60550 -60551 -60552 -60553 -60554 -60555 -60556 -60557 -60558 -60559 -60560 -60561 -60562 -60563 -60564 -60565 -60566 -60567 -60568 -60569 -60570 -60571 -60572 -60573 -60574 -60575 -60576 -60577 -60578 -60579 -60580 -60581 -60582 -60583 -60584 -60585 -60586 -60587 -60588 -60589 -60590 -60591 -60592 -60593 -60594 -60595 -60596 -60597 -60598 -60599 -60600 -60601 -60602 -60603 -60604 -60605 -60606 -60607 -60608 -60609 -60610 -60611 -60612 -60613 -60614 -60615 -60616 -60617 -60618 -60619 -60620 -60621 -60622 -60623 -60624 -60625 -60626 -60627 -60628 -60629 -60630 -60631 -60632 -60633 -60634 -60635 -60636 -60637 -60638 -60639 -60640 -60641 -60642 -60643 -60644 -60645 -60646 -60647 -60648 -60649 -60650 -60651 -60652 -60653 -60654 -60655 -60656 -60657 -60658 -60659 -60660 -60661 -60662 -60663 -60664 -60665 -60666 -60667 -60668 -60669 -60670 -60671 -60672 -60673 -60674 -60675 -60676 -60677 -60678 -60679 -60680 -60681 -60682 -60683 -60684 -60685 -60686 -60687 -60688 -60689 -60690 -60691 -60692 -60693 -60694 -60695 -60696 -60697 -60698 -60699 -60700 -60701 -60702 -60703 -60704 -60705 -60706 -60707 -60708 -60709 -60710 -60711 -60712 -60713 -60714 -60715 -60716 -60717 -60718 -60719 -60720 -60721 -60722 -60723 -60724 -60725 -60726 -60727 -60728 -60729 -60730 -60731 -60732 -60733 -60734 -60735 -60736 -60737 -60738 -60739 -60740 -60741 -60742 -60743 -60744 -60745 -60746 -60747 -60748 -60749 -60750 -60751 -60752 -60753 -60754 -60755 -60756 -60757 -60758 -60759 -60760 -60761 -60762 -60763 -60764 -60765 -60766 -60767 -60768 -60769 -60770 -60771 -60772 -60773 -60774 -60775 -60776 -60777 -60778 -60779 -60780 -60781 -60782 -60783 -60784 -60785 -60786 -60787 -60788 -60789 -60790 -60791 -60792 -60793 -60794 -60795 -60796 -60797 -60798 -60799 -60800 -60801 -60802 -60803 -60804 -60805 -60806 -60807 -60808 -60809 -60810 -60811 -60812 -60813 -60814 -60815 -60816 -60817 -60818 -60819 -60820 -60821 -60822 -60823 -60824 -60825 -60826 -60827 -60828 -60829 -60830 -60831 -60832 -60833 -60834 -60835 -60836 -60837 -60838 -60839 -60840 -60841 -60842 -60843 -60844 -60845 -60846 -60847 -60848 -60849 -60850 -60851 -60852 -60853 -60854 -60855 -60856 -60857 -60858 -60859 -60860 -60861 -60862 -60863 -60864 -60865 -60866 -60867 -60868 -60869 -60870 -60871 -60872 -60873 -60874 -60875 -60876 -60877 -60878 -60879 -60880 -60881 -60882 -60883 -60884 -60885 -60886 -60887 -60888 -60889 -60890 -60891 -60892 -60893 -60894 -60895 -60896 -60897 -60898 -60899 -60900 -60901 -60902 -60903 -60904 -60905 -60906 -60907 -60908 -60909 -60910 -60911 -60912 -60913 -60914 -60915 -60916 -60917 -60918 -60919 -60920 -60921 -60922 -60923 -60924 -60925 -60926 -60927 -60928 -60929 -60930 -60931 -60932 -60933 -60934 -60935 -60936 -60937 -60938 -60939 -60940 -60941 -60942 -60943 -60944 -60945 -60946 -60947 -60948 -60949 -60950 -60951 -60952 -60953 -60954 -60955 -60956 -60957 -60958 -60959 -60960 -60961 -60962 -60963 -60964 -60965 -60966 -60967 -60968 -60969 -60970 -60971 -60972 -60973 -60974 -60975 -60976 -60977 -60978 -60979 -60980 -60981 -60982 -60983 -60984 -60985 -60986 -60987 -60988 -60989 -60990 -60991 -60992 -60993 -60994 -60995 -60996 -60997 -60998 -60999 -61000 -61001 -61002 -61003 -61004 -61005 -61006 -61007 -61008 -61009 -61010 -61011 -61012 -61013 -61014 -61015 -61016 -61017 -61018 -61019 -61020 -61021 -61022 -61023 -61024 -61025 -61026 -61027 -61028 -61029 -61030 -61031 -61032 -61033 -61034 -61035 -61036 -61037 -61038 -61039 -61040 -61041 -61042 -61043 -61044 -61045 -61046 -61047 -61048 -61049 -61050 -61051 -61052 -61053 -61054 -61055 -61056 -61057 -61058 -61059 -61060 -61061 -61062 -61063 -61064 -61065 -61066 -61067 -61068 -61069 -61070 -61071 -61072 -61073 -61074 -61075 -61076 -61077 -61078 -61079 -61080 -61081 -61082 -61083 -61084 -61085 -61086 -61087 -61088 -61089 -61090 -61091 -61092 -61093 -61094 -61095 -61096 -61097 -61098 -61099 -61100 -61101 -61102 -61103 -61104 -61105 -61106 -61107 -61108 -61109 -61110 -61111 -61112 -61113 -61114 -61115 -61116 -61117 -61118 -61119 -61120 -61121 -61122 -61123 -61124 -61125 -61126 -61127 -61128 -61129 -61130 -61131 -61132 -61133 -61134 -61135 -61136 -61137 -61138 -61139 -61140 -61141 -61142 -61143 -61144 -61145 -61146 -61147 -61148 -61149 -61150 -61151 -61152 -61153 -61154 -61155 -61156 -61157 -61158 -61159 -61160 -61161 -61162 -61163 -61164 -61165 -61166 -61167 -61168 -61169 -61170 -61171 -61172 -61173 -61174 -61175 -61176 -61177 -61178 -61179 -61180 -61181 -61182 -61183 -61184 -61185 -61186 -61187 -61188 -61189 -61190 -61191 -61192 -61193 -61194 -61195 -61196 -61197 -61198 -61199 -61200 -61201 -61202 -61203 -61204 -61205 -61206 -61207 -61208 -61209 -61210 -61211 -61212 -61213 -61214 -61215 -61216 -61217 -61218 -61219 -61220 -61221 -61222 -61223 -61224 -61225 -61226 -61227 -61228 -61229 -61230 -61231 -61232 -61233 -61234 -61235 -61236 -61237 -61238 -61239 -61240 -61241 -61242 -61243 -61244 -61245 -61246 -61247 -61248 -61249 -61250 -61251 -61252 -61253 -61254 -61255 -61256 -61257 -61258 -61259 -61260 -61261 -61262 -61263 -61264 -61265 -61266 -61267 -61268 -61269 -61270 -61271 -61272 -61273 -61274 -61275 -61276 -61277 -61278 -61279 -61280 -61281 -61282 -61283 -61284 -61285 -61286 -61287 -61288 -61289 -61290 -61291 -61292 -61293 -61294 -61295 -61296 -61297 -61298 -61299 -61300 -61301 -61302 -61303 -61304 -61305 -61306 -61307 -61308 -61309 -61310 -61311 -61312 -61313 -61314 -61315 -61316 -61317 -61318 -61319 -61320 -61321 -61322 -61323 -61324 -61325 -61326 -61327 -61328 -61329 -61330 -61331 -61332 -61333 -61334 -61335 -61336 -61337 -61338 -61339 -61340 -61341 -61342 -61343 -61344 -61345 -61346 -61347 -61348 -61349 -61350 -61351 -61352 -61353 -61354 -61355 -61356 -61357 -61358 -61359 -61360 -61361 -61362 -61363 -61364 -61365 -61366 -61367 -61368 -61369 -61370 -61371 -61372 -61373 -61374 -61375 -61376 -61377 -61378 -61379 -61380 -61381 -61382 -61383 -61384 -61385 -61386 -61387 -61388 -61389 -61390 -61391 -61392 -61393 -61394 -61395 -61396 -61397 -61398 -61399 -61400 -61401 -61402 -61403 -61404 -61405 -61406 -61407 -61408 -61409 -61410 -61411 -61412 -61413 -61414 -61415 -61416 -61417 -61418 -61419 -61420 -61421 -61422 -61423 -61424 -61425 -61426 -61427 -61428 -61429 -61430 -61431 -61432 -61433 -61434 -61435 -61436 -61437 -61438 -61439 -61440 -61441 -61442 -61443 -61444 -61445 -61446 -61447 -61448 -61449 -61450 -61451 -61452 -61453 -61454 -61455 -61456 -61457 -61458 -61459 -61460 -61461 -61462 -61463 -61464 -61465 -61466 -61467 -61468 -61469 -61470 -61471 -61472 -61473 -61474 -61475 -61476 -61477 -61478 -61479 -61480 -61481 -61482 -61483 -61484 -61485 -61486 -61487 -61488 -61489 -61490 -61491 -61492 -61493 -61494 -61495 -61496 -61497 -61498 -61499 -61500 -61501 -61502 -61503 -61504 -61505 -61506 -61507 -61508 -61509 -61510 -61511 -61512 -61513 -61514 -61515 -61516 -61517 -61518 -61519 -61520 -61521 -61522 -61523 -61524 -61525 -61526 -61527 -61528 -61529 -61530 -61531 -61532 -61533 -61534 -61535 -61536 -61537 -61538 -61539 -61540 -61541 -61542 -61543 -61544 -61545 -61546 -61547 -61548 -61549 -61550 -61551 -61552 -61553 -61554 -61555 -61556 -61557 -61558 -61559 -61560 -61561 -61562 -61563 -61564 -61565 -61566 -61567 -61568 -61569 -61570 -61571 -61572 -61573 -61574 -61575 -61576 -61577 -61578 -61579 -61580 -61581 -61582 -61583 -61584 -61585 -61586 -61587 -61588 -61589 -61590 -61591 -61592 -61593 -61594 -61595 -61596 -61597 -61598 -61599 -61600 -61601 -61602 -61603 -61604 -61605 -61606 -61607 -61608 -61609 -61610 -61611 -61612 -61613 -61614 -61615 -61616 -61617 -61618 -61619 -61620 -61621 -61622 -61623 -61624 -61625 -61626 -61627 -61628 -61629 -61630 -61631 -61632 -61633 -61634 -61635 -61636 -61637 -61638 -61639 -61640 -61641 -61642 -61643 -61644 -61645 -61646 -61647 -61648 -61649 -61650 -61651 -61652 -61653 -61654 -61655 -61656 -61657 -61658 -61659 -61660 -61661 -61662 -61663 -61664 -61665 -61666 -61667 -61668 -61669 -61670 -61671 -61672 -61673 -61674 -61675 -61676 -61677 -61678 -61679 -61680 -61681 -61682 -61683 -61684 -61685 -61686 -61687 -61688 -61689 -61690 -61691 -61692 -61693 -61694 -61695 -61696 -61697 -61698 -61699 -61700 -61701 -61702 -61703 -61704 -61705 -61706 -61707 -61708 -61709 -61710 -61711 -61712 -61713 -61714 -61715 -61716 -61717 -61718 -61719 -61720 -61721 -61722 -61723 -61724 -61725 -61726 -61727 -61728 -61729 -61730 -61731 -61732 -61733 -61734 -61735 -61736 -61737 -61738 -61739 -61740 -61741 -61742 -61743 -61744 -61745 -61746 -61747 -61748 -61749 -61750 -61751 -61752 -61753 -61754 -61755 -61756 -61757 -61758 -61759 -61760 -61761 -61762 -61763 -61764 -61765 -61766 -61767 -61768 -61769 -61770 -61771 -61772 -61773 -61774 -61775 -61776 -61777 -61778 -61779 -61780 -61781 -61782 -61783 -61784 -61785 -61786 -61787 -61788 -61789 -61790 -61791 -61792 -61793 -61794 -61795 -61796 -61797 -61798 -61799 -61800 -61801 -61802 -61803 -61804 -61805 -61806 -61807 -61808 -61809 -61810 -61811 -61812 -61813 -61814 -61815 -61816 -61817 -61818 -61819 -61820 -61821 -61822 -61823 -61824 -61825 -61826 -61827 -61828 -61829 -61830 -61831 -61832 -61833 -61834 -61835 -61836 -61837 -61838 -61839 -61840 -61841 -61842 -61843 -61844 -61845 -61846 -61847 -61848 -61849 -61850 -61851 -61852 -61853 -61854 -61855 -61856 -61857 -61858 -61859 -61860 -61861 -61862 -61863 -61864 -61865 -61866 -61867 -61868 -61869 -61870 -61871 -61872 -61873 -61874 -61875 -61876 -61877 -61878 -61879 -61880 -61881 -61882 -61883 -61884 -61885 -61886 -61887 -61888 -61889 -61890 -61891 -61892 -61893 -61894 -61895 -61896 -61897 -61898 -61899 -61900 -61901 -61902 -61903 -61904 -61905 -61906 -61907 -61908 -61909 -61910 -61911 -61912 -61913 -61914 -61915 -61916 -61917 -61918 -61919 -61920 -61921 -61922 -61923 -61924 -61925 -61926 -61927 -61928 -61929 -61930 -61931 -61932 -61933 -61934 -61935 -61936 -61937 -61938 -61939 -61940 -61941 -61942 -61943 -61944 -61945 -61946 -61947 -61948 -61949 -61950 -61951 -61952 -61953 -61954 -61955 -61956 -61957 -61958 -61959 -61960 -61961 -61962 -61963 -61964 -61965 -61966 -61967 -61968 -61969 -61970 -61971 -61972 -61973 -61974 -61975 -61976 -61977 -61978 -61979 -61980 -61981 -61982 -61983 -61984 -61985 -61986 -61987 -61988 -61989 -61990 -61991 -61992 -61993 -61994 -61995 -61996 -61997 -61998 -61999 -62000 -62001 -62002 -62003 -62004 -62005 -62006 -62007 -62008 -62009 -62010 -62011 -62012 -62013 -62014 -62015 -62016 -62017 -62018 -62019 -62020 -62021 -62022 -62023 -62024 -62025 -62026 -62027 -62028 -62029 -62030 -62031 -62032 -62033 -62034 -62035 -62036 -62037 -62038 -62039 -62040 -62041 -62042 -62043 -62044 -62045 -62046 -62047 -62048 -62049 -62050 -62051 -62052 -62053 -62054 -62055 -62056 -62057 -62058 -62059 -62060 -62061 -62062 -62063 -62064 -62065 -62066 -62067 -62068 -62069 -62070 -62071 -62072 -62073 -62074 -62075 -62076 -62077 -62078 -62079 -62080 -62081 -62082 -62083 -62084 -62085 -62086 -62087 -62088 -62089 -62090 -62091 -62092 -62093 -62094 -62095 -62096 -62097 -62098 -62099 -62100 -62101 -62102 -62103 -62104 -62105 -62106 -62107 -62108 -62109 -62110 -62111 -62112 -62113 -62114 -62115 -62116 -62117 -62118 -62119 -62120 -62121 -62122 -62123 -62124 -62125 -62126 -62127 -62128 -62129 -62130 -62131 -62132 -62133 -62134 -62135 -62136 -62137 -62138 -62139 -62140 -62141 -62142 -62143 -62144 -62145 -62146 -62147 -62148 -62149 -62150 -62151 -62152 -62153 -62154 -62155 -62156 -62157 -62158 -62159 -62160 -62161 -62162 -62163 -62164 -62165 -62166 -62167 -62168 -62169 -62170 -62171 -62172 -62173 -62174 -62175 -62176 -62177 -62178 -62179 -62180 -62181 -62182 -62183 -62184 -62185 -62186 -62187 -62188 -62189 -62190 -62191 -62192 -62193 -62194 -62195 -62196 -62197 -62198 -62199 -62200 -62201 -62202 -62203 -62204 -62205 -62206 -62207 -62208 -62209 -62210 -62211 -62212 -62213 -62214 -62215 -62216 -62217 -62218 -62219 -62220 -62221 -62222 -62223 -62224 -62225 -62226 -62227 -62228 -62229 -62230 -62231 -62232 -62233 -62234 -62235 -62236 -62237 -62238 -62239 -62240 -62241 -62242 -62243 -62244 -62245 -62246 -62247 -62248 -62249 -62250 -62251 -62252 -62253 -62254 -62255 -62256 -62257 -62258 -62259 -62260 -62261 -62262 -62263 -62264 -62265 -62266 -62267 -62268 -62269 -62270 -62271 -62272 -62273 -62274 -62275 -62276 -62277 -62278 -62279 -62280 -62281 -62282 -62283 -62284 -62285 -62286 -62287 -62288 -62289 -62290 -62291 -62292 -62293 -62294 -62295 -62296 -62297 -62298 -62299 -62300 -62301 -62302 -62303 -62304 -62305 -62306 -62307 -62308 -62309 -62310 -62311 -62312 -62313 -62314 -62315 -62316 -62317 -62318 -62319 -62320 -62321 -62322 -62323 -62324 -62325 -62326 -62327 -62328 -62329 -62330 -62331 -62332 -62333 -62334 -62335 -62336 -62337 -62338 -62339 -62340 -62341 -62342 -62343 -62344 -62345 -62346 -62347 -62348 -62349 -62350 -62351 -62352 -62353 -62354 -62355 -62356 -62357 -62358 -62359 -62360 -62361 -62362 -62363 -62364 -62365 -62366 -62367 -62368 -62369 -62370 -62371 -62372 -62373 -62374 -62375 -62376 -62377 -62378 -62379 -62380 -62381 -62382 -62383 -62384 -62385 -62386 -62387 -62388 -62389 -62390 -62391 -62392 -62393 -62394 -62395 -62396 -62397 -62398 -62399 -62400 -62401 -62402 -62403 -62404 -62405 -62406 -62407 -62408 -62409 -62410 -62411 -62412 -62413 -62414 -62415 -62416 -62417 -62418 -62419 -62420 -62421 -62422 -62423 -62424 -62425 -62426 -62427 -62428 -62429 -62430 -62431 -62432 -62433 -62434 -62435 -62436 -62437 -62438 -62439 -62440 -62441 -62442 -62443 -62444 -62445 -62446 -62447 -62448 -62449 -62450 -62451 -62452 -62453 -62454 -62455 -62456 -62457 -62458 -62459 -62460 -62461 -62462 -62463 -62464 -62465 -62466 -62467 -62468 -62469 -62470 -62471 -62472 -62473 -62474 -62475 -62476 -62477 -62478 -62479 -62480 -62481 -62482 -62483 -62484 -62485 -62486 -62487 -62488 -62489 -62490 -62491 -62492 -62493 -62494 -62495 -62496 -62497 -62498 -62499 -62500 -62501 -62502 -62503 -62504 -62505 -62506 -62507 -62508 -62509 -62510 -62511 -62512 -62513 -62514 -62515 -62516 -62517 -62518 -62519 -62520 -62521 -62522 -62523 -62524 -62525 -62526 -62527 -62528 -62529 -62530 -62531 -62532 -62533 -62534 -62535 -62536 -62537 -62538 -62539 -62540 -62541 -62542 -62543 -62544 -62545 -62546 -62547 -62548 -62549 -62550 -62551 -62552 -62553 -62554 -62555 -62556 -62557 -62558 -62559 -62560 -62561 -62562 -62563 -62564 -62565 -62566 -62567 -62568 -62569 -62570 -62571 -62572 -62573 -62574 -62575 -62576 -62577 -62578 -62579 -62580 -62581 -62582 -62583 -62584 -62585 -62586 -62587 -62588 -62589 -62590 -62591 -62592 -62593 -62594 -62595 -62596 -62597 -62598 -62599 -62600 -62601 -62602 -62603 -62604 -62605 -62606 -62607 -62608 -62609 -62610 -62611 -62612 -62613 -62614 -62615 -62616 -62617 -62618 -62619 -62620 -62621 -62622 -62623 -62624 -62625 -62626 -62627 -62628 -62629 -62630 -62631 -62632 -62633 -62634 -62635 -62636 -62637 -62638 -62639 -62640 -62641 -62642 -62643 -62644 -62645 -62646 -62647 -62648 -62649 -62650 -62651 -62652 -62653 -62654 -62655 -62656 -62657 -62658 -62659 -62660 -62661 -62662 -62663 -62664 -62665 -62666 -62667 -62668 -62669 -62670 -62671 -62672 -62673 -62674 -62675 -62676 -62677 -62678 -62679 -62680 -62681 -62682 -62683 -62684 -62685 -62686 -62687 -62688 -62689 -62690 -62691 -62692 -62693 -62694 -62695 -62696 -62697 -62698 -62699 -62700 -62701 -62702 -62703 -62704 -62705 -62706 -62707 -62708 -62709 -62710 -62711 -62712 -62713 -62714 -62715 -62716 -62717 -62718 -62719 -62720 -62721 -62722 -62723 -62724 -62725 -62726 -62727 -62728 -62729 -62730 -62731 -62732 -62733 -62734 -62735 -62736 -62737 -62738 -62739 -62740 -62741 -62742 -62743 -62744 -62745 -62746 -62747 -62748 -62749 -62750 -62751 -62752 -62753 -62754 -62755 -62756 -62757 -62758 -62759 -62760 -62761 -62762 -62763 -62764 -62765 -62766 -62767 -62768 -62769 -62770 -62771 -62772 -62773 -62774 -62775 -62776 -62777 -62778 -62779 -62780 -62781 -62782 -62783 -62784 -62785 -62786 -62787 -62788 -62789 -62790 -62791 -62792 -62793 -62794 -62795 -62796 -62797 -62798 -62799 -62800 -62801 -62802 -62803 -62804 -62805 -62806 -62807 -62808 -62809 -62810 -62811 -62812 -62813 -62814 -62815 -62816 -62817 -62818 -62819 -62820 -62821 -62822 -62823 -62824 -62825 -62826 -62827 -62828 -62829 -62830 -62831 -62832 -62833 -62834 -62835 -62836 -62837 -62838 -62839 -62840 -62841 -62842 -62843 -62844 -62845 -62846 -62847 -62848 -62849 -62850 -62851 -62852 -62853 -62854 -62855 -62856 -62857 -62858 -62859 -62860 -62861 -62862 -62863 -62864 -62865 -62866 -62867 -62868 -62869 -62870 -62871 -62872 -62873 -62874 -62875 -62876 -62877 -62878 -62879 -62880 -62881 -62882 -62883 -62884 -62885 -62886 -62887 -62888 -62889 -62890 -62891 -62892 -62893 -62894 -62895 -62896 -62897 -62898 -62899 -62900 -62901 -62902 -62903 -62904 -62905 -62906 -62907 -62908 -62909 -62910 -62911 -62912 -62913 -62914 -62915 -62916 -62917 -62918 -62919 -62920 -62921 -62922 -62923 -62924 -62925 -62926 -62927 -62928 -62929 -62930 -62931 -62932 -62933 -62934 -62935 -62936 -62937 -62938 -62939 -62940 -62941 -62942 -62943 -62944 -62945 -62946 -62947 -62948 -62949 -62950 -62951 -62952 -62953 -62954 -62955 -62956 -62957 -62958 -62959 -62960 -62961 -62962 -62963 -62964 -62965 -62966 -62967 -62968 -62969 -62970 -62971 -62972 -62973 -62974 -62975 -62976 -62977 -62978 -62979 -62980 -62981 -62982 -62983 -62984 -62985 -62986 -62987 -62988 -62989 -62990 -62991 -62992 -62993 -62994 -62995 -62996 -62997 -62998 -62999 -63000 -63001 -63002 -63003 -63004 -63005 -63006 -63007 -63008 -63009 -63010 -63011 -63012 -63013 -63014 -63015 -63016 -63017 -63018 -63019 -63020 -63021 -63022 -63023 -63024 -63025 -63026 -63027 -63028 -63029 -63030 -63031 -63032 -63033 -63034 -63035 -63036 -63037 -63038 -63039 -63040 -63041 -63042 -63043 -63044 -63045 -63046 -63047 -63048 -63049 -63050 -63051 -63052 -63053 -63054 -63055 -63056 -63057 -63058 -63059 -63060 -63061 -63062 -63063 -63064 -63065 -63066 -63067 -63068 -63069 -63070 -63071 -63072 -63073 -63074 -63075 -63076 -63077 -63078 -63079 -63080 -63081 -63082 -63083 -63084 -63085 -63086 -63087 -63088 -63089 -63090 -63091 -63092 -63093 -63094 -63095 -63096 -63097 -63098 -63099 -63100 -63101 -63102 -63103 -63104 -63105 -63106 -63107 -63108 -63109 -63110 -63111 -63112 -63113 -63114 -63115 -63116 -63117 -63118 -63119 -63120 -63121 -63122 -63123 -63124 -63125 -63126 -63127 -63128 -63129 -63130 -63131 -63132 -63133 -63134 -63135 -63136 -63137 -63138 -63139 -63140 -63141 -63142 -63143 -63144 -63145 -63146 -63147 -63148 -63149 -63150 -63151 -63152 -63153 -63154 -63155 -63156 -63157 -63158 -63159 -63160 -63161 -63162 -63163 -63164 -63165 -63166 -63167 -63168 -63169 -63170 -63171 -63172 -63173 -63174 -63175 -63176 -63177 -63178 -63179 -63180 -63181 -63182 -63183 -63184 -63185 -63186 -63187 -63188 -63189 -63190 -63191 -63192 -63193 -63194 -63195 -63196 -63197 -63198 -63199 -63200 -63201 -63202 -63203 -63204 -63205 -63206 -63207 -63208 -63209 -63210 -63211 -63212 -63213 -63214 -63215 -63216 -63217 -63218 -63219 -63220 -63221 -63222 -63223 -63224 -63225 -63226 -63227 -63228 -63229 -63230 -63231 -63232 -63233 -63234 -63235 -63236 -63237 -63238 -63239 -63240 -63241 -63242 -63243 -63244 -63245 -63246 -63247 -63248 -63249 -63250 -63251 -63252 -63253 -63254 -63255 -63256 -63257 -63258 -63259 -63260 -63261 -63262 -63263 -63264 -63265 -63266 -63267 -63268 -63269 -63270 -63271 -63272 -63273 -63274 -63275 -63276 -63277 -63278 -63279 -63280 -63281 -63282 -63283 -63284 -63285 -63286 -63287 -63288 -63289 -63290 -63291 -63292 -63293 -63294 -63295 -63296 -63297 -63298 -63299 -63300 -63301 -63302 -63303 -63304 -63305 -63306 -63307 -63308 -63309 -63310 -63311 -63312 -63313 -63314 -63315 -63316 -63317 -63318 -63319 -63320 -63321 -63322 -63323 -63324 -63325 -63326 -63327 -63328 -63329 -63330 -63331 -63332 -63333 -63334 -63335 -63336 -63337 -63338 -63339 -63340 -63341 -63342 -63343 -63344 -63345 -63346 -63347 -63348 -63349 -63350 -63351 -63352 -63353 -63354 -63355 -63356 -63357 -63358 -63359 -63360 -63361 -63362 -63363 -63364 -63365 -63366 -63367 -63368 -63369 -63370 -63371 -63372 -63373 -63374 -63375 -63376 -63377 -63378 -63379 -63380 -63381 -63382 -63383 -63384 -63385 -63386 -63387 -63388 -63389 -63390 -63391 -63392 -63393 -63394 -63395 -63396 -63397 -63398 -63399 -63400 -63401 -63402 -63403 -63404 -63405 -63406 -63407 -63408 -63409 -63410 -63411 -63412 -63413 -63414 -63415 -63416 -63417 -63418 -63419 -63420 -63421 -63422 -63423 -63424 -63425 -63426 -63427 -63428 -63429 -63430 -63431 -63432 -63433 -63434 -63435 -63436 -63437 -63438 -63439 -63440 -63441 -63442 -63443 -63444 -63445 -63446 -63447 -63448 -63449 -63450 -63451 -63452 -63453 -63454 -63455 -63456 -63457 -63458 -63459 -63460 -63461 -63462 -63463 -63464 -63465 -63466 -63467 -63468 -63469 -63470 -63471 -63472 -63473 -63474 -63475 -63476 -63477 -63478 -63479 -63480 -63481 -63482 -63483 -63484 -63485 -63486 -63487 -63488 -63489 -63490 -63491 -63492 -63493 -63494 -63495 -63496 -63497 -63498 -63499 -63500 -63501 -63502 -63503 -63504 -63505 -63506 -63507 -63508 -63509 -63510 -63511 -63512 -63513 -63514 -63515 -63516 -63517 -63518 -63519 -63520 -63521 -63522 -63523 -63524 -63525 -63526 -63527 -63528 -63529 -63530 -63531 -63532 -63533 -63534 -63535 -63536 -63537 -63538 -63539 -63540 -63541 -63542 -63543 -63544 -63545 -63546 -63547 -63548 -63549 -63550 -63551 -63552 -63553 -63554 -63555 -63556 -63557 -63558 -63559 -63560 -63561 -63562 -63563 -63564 -63565 -63566 -63567 -63568 -63569 -63570 -63571 -63572 -63573 -63574 -63575 -63576 -63577 -63578 -63579 -63580 -63581 -63582 -63583 -63584 -63585 -63586 -63587 -63588 -63589 -63590 -63591 -63592 -63593 -63594 -63595 -63596 -63597 -63598 -63599 -63600 -63601 -63602 -63603 -63604 -63605 -63606 -63607 -63608 -63609 -63610 -63611 -63612 -63613 -63614 -63615 -63616 -63617 -63618 -63619 -63620 -63621 -63622 -63623 -63624 -63625 -63626 -63627 -63628 -63629 -63630 -63631 -63632 -63633 -63634 -63635 -63636 -63637 -63638 -63639 -63640 -63641 -63642 -63643 -63644 -63645 -63646 -63647 -63648 -63649 -63650 -63651 -63652 -63653 -63654 -63655 -63656 -63657 -63658 -63659 -63660 -63661 -63662 -63663 -63664 -63665 -63666 -63667 -63668 -63669 -63670 -63671 -63672 -63673 -63674 -63675 -63676 -63677 -63678 -63679 -63680 -63681 -63682 -63683 -63684 -63685 -63686 -63687 -63688 -63689 -63690 -63691 -63692 -63693 -63694 -63695 -63696 -63697 -63698 -63699 -63700 -63701 -63702 -63703 -63704 -63705 -63706 -63707 -63708 -63709 -63710 -63711 -63712 -63713 -63714 -63715 -63716 -63717 -63718 -63719 -63720 -63721 -63722 -63723 -63724 -63725 -63726 -63727 -63728 -63729 -63730 -63731 -63732 -63733 -63734 -63735 -63736 -63737 -63738 -63739 -63740 -63741 -63742 -63743 -63744 -63745 -63746 -63747 -63748 -63749 -63750 -63751 -63752 -63753 -63754 -63755 -63756 -63757 -63758 -63759 -63760 -63761 -63762 -63763 -63764 -63765 -63766 -63767 -63768 -63769 -63770 -63771 -63772 -63773 -63774 -63775 -63776 -63777 -63778 -63779 -63780 -63781 -63782 -63783 -63784 -63785 -63786 -63787 -63788 -63789 -63790 -63791 -63792 -63793 -63794 -63795 -63796 -63797 -63798 -63799 -63800 -63801 -63802 -63803 -63804 -63805 -63806 -63807 -63808 -63809 -63810 -63811 -63812 -63813 -63814 -63815 -63816 -63817 -63818 -63819 -63820 -63821 -63822 -63823 -63824 -63825 -63826 -63827 -63828 -63829 -63830 -63831 -63832 -63833 -63834 -63835 -63836 -63837 -63838 -63839 -63840 -63841 -63842 -63843 -63844 -63845 -63846 -63847 -63848 -63849 -63850 -63851 -63852 -63853 -63854 -63855 -63856 -63857 -63858 -63859 -63860 -63861 -63862 -63863 -63864 -63865 -63866 -63867 -63868 -63869 -63870 -63871 -63872 -63873 -63874 -63875 -63876 -63877 -63878 -63879 -63880 -63881 -63882 -63883 -63884 -63885 -63886 -63887 -63888 -63889 -63890 -63891 -63892 -63893 -63894 -63895 -63896 -63897 -63898 -63899 -63900 -63901 -63902 -63903 -63904 -63905 -63906 -63907 -63908 -63909 -63910 -63911 -63912 -63913 -63914 -63915 -63916 -63917 -63918 -63919 -63920 -63921 -63922 -63923 -63924 -63925 -63926 -63927 -63928 -63929 -63930 -63931 -63932 -63933 -63934 -63935 -63936 -63937 -63938 -63939 -63940 -63941 -63942 -63943 -63944 -63945 -63946 -63947 -63948 -63949 -63950 -63951 -63952 -63953 -63954 -63955 -63956 -63957 -63958 -63959 -63960 -63961 -63962 -63963 -63964 -63965 -63966 -63967 -63968 -63969 -63970 -63971 -63972 -63973 -63974 -63975 -63976 -63977 -63978 -63979 -63980 -63981 -63982 -63983 -63984 -63985 -63986 -63987 -63988 -63989 -63990 -63991 -63992 -63993 -63994 -63995 -63996 -63997 -63998 -63999 -64000 -64001 -64002 -64003 -64004 -64005 -64006 -64007 -64008 -64009 -64010 -64011 -64012 -64013 -64014 -64015 -64016 -64017 -64018 -64019 -64020 -64021 -64022 -64023 -64024 -64025 -64026 -64027 -64028 -64029 -64030 -64031 -64032 -64033 -64034 -64035 -64036 -64037 -64038 -64039 -64040 -64041 -64042 -64043 -64044 -64045 -64046 -64047 -64048 -64049 -64050 -64051 -64052 -64053 -64054 -64055 -64056 -64057 -64058 -64059 -64060 -64061 -64062 -64063 -64064 -64065 -64066 -64067 -64068 -64069 -64070 -64071 -64072 -64073 -64074 -64075 -64076 -64077 -64078 -64079 -64080 -64081 -64082 -64083 -64084 -64085 -64086 -64087 -64088 -64089 -64090 -64091 -64092 -64093 -64094 -64095 -64096 -64097 -64098 -64099 -64100 -64101 -64102 -64103 -64104 -64105 -64106 -64107 -64108 -64109 -64110 -64111 -64112 -64113 -64114 -64115 -64116 -64117 -64118 -64119 -64120 -64121 -64122 -64123 -64124 -64125 -64126 -64127 -64128 -64129 -64130 -64131 -64132 -64133 -64134 -64135 -64136 -64137 -64138 -64139 -64140 -64141 -64142 -64143 -64144 -64145 -64146 -64147 -64148 -64149 -64150 -64151 -64152 -64153 -64154 -64155 -64156 -64157 -64158 -64159 -64160 -64161 -64162 -64163 -64164 -64165 -64166 -64167 -64168 -64169 -64170 -64171 -64172 -64173 -64174 -64175 -64176 -64177 -64178 -64179 -64180 -64181 -64182 -64183 -64184 -64185 -64186 -64187 -64188 -64189 -64190 -64191 -64192 -64193 -64194 -64195 -64196 -64197 -64198 -64199 -64200 -64201 -64202 -64203 -64204 -64205 -64206 -64207 -64208 -64209 -64210 -64211 -64212 -64213 -64214 -64215 -64216 -64217 -64218 -64219 -64220 -64221 -64222 -64223 -64224 -64225 -64226 -64227 -64228 -64229 -64230 -64231 -64232 -64233 -64234 -64235 -64236 -64237 -64238 -64239 -64240 -64241 -64242 -64243 -64244 -64245 -64246 -64247 -64248 -64249 -64250 -64251 -64252 -64253 -64254 -64255 -64256 -64257 -64258 -64259 -64260 -64261 -64262 -64263 -64264 -64265 -64266 -64267 -64268 -64269 -64270 -64271 -64272 -64273 -64274 -64275 -64276 -64277 -64278 -64279 -64280 -64281 -64282 -64283 -64284 -64285 -64286 -64287 -64288 -64289 -64290 -64291 -64292 -64293 -64294 -64295 -64296 -64297 -64298 -64299 -64300 -64301 -64302 -64303 -64304 -64305 -64306 -64307 -64308 -64309 -64310 -64311 -64312 -64313 -64314 -64315 -64316 -64317 -64318 -64319 -64320 -64321 -64322 -64323 -64324 -64325 -64326 -64327 -64328 -64329 -64330 -64331 -64332 -64333 -64334 -64335 -64336 -64337 -64338 -64339 -64340 -64341 -64342 -64343 -64344 -64345 -64346 -64347 -64348 -64349 -64350 -64351 -64352 -64353 -64354 -64355 -64356 -64357 -64358 -64359 -64360 -64361 -64362 -64363 -64364 -64365 -64366 -64367 -64368 -64369 -64370 -64371 -64372 -64373 -64374 -64375 -64376 -64377 -64378 -64379 -64380 -64381 -64382 -64383 -64384 -64385 -64386 -64387 -64388 -64389 -64390 -64391 -64392 -64393 -64394 -64395 -64396 -64397 -64398 -64399 -64400 -64401 -64402 -64403 -64404 -64405 -64406 -64407 -64408 -64409 -64410 -64411 -64412 -64413 -64414 -64415 -64416 -64417 -64418 -64419 -64420 -64421 -64422 -64423 -64424 -64425 -64426 -64427 -64428 -64429 -64430 -64431 -64432 -64433 -64434 -64435 -64436 -64437 -64438 -64439 -64440 -64441 -64442 -64443 -64444 -64445 -64446 -64447 -64448 -64449 -64450 -64451 -64452 -64453 -64454 -64455 -64456 -64457 -64458 -64459 -64460 -64461 -64462 -64463 -64464 -64465 -64466 -64467 -64468 -64469 -64470 -64471 -64472 -64473 -64474 -64475 -64476 -64477 -64478 -64479 -64480 -64481 -64482 -64483 -64484 -64485 -64486 -64487 -64488 -64489 -64490 -64491 -64492 -64493 -64494 -64495 -64496 -64497 -64498 -64499 -64500 -64501 -64502 -64503 -64504 -64505 -64506 -64507 -64508 -64509 -64510 -64511 -64512 -64513 -64514 -64515 -64516 -64517 -64518 -64519 -64520 -64521 -64522 -64523 -64524 -64525 -64526 -64527 -64528 -64529 -64530 -64531 -64532 -64533 -64534 -64535 -64536 -64537 -64538 -64539 -64540 -64541 -64542 -64543 -64544 -64545 -64546 -64547 -64548 -64549 -64550 -64551 -64552 -64553 -64554 -64555 -64556 -64557 -64558 -64559 -64560 -64561 -64562 -64563 -64564 -64565 -64566 -64567 -64568 -64569 -64570 -64571 -64572 -64573 -64574 -64575 -64576 -64577 -64578 -64579 -64580 -64581 -64582 -64583 -64584 -64585 -64586 -64587 -64588 -64589 -64590 -64591 -64592 -64593 -64594 -64595 -64596 -64597 -64598 -64599 -64600 -64601 -64602 -64603 -64604 -64605 -64606 -64607 -64608 -64609 -64610 -64611 -64612 -64613 -64614 -64615 -64616 -64617 -64618 -64619 -64620 -64621 -64622 -64623 -64624 -64625 -64626 -64627 -64628 -64629 -64630 -64631 -64632 -64633 -64634 -64635 -64636 -64637 -64638 -64639 -64640 -64641 -64642 -64643 -64644 -64645 -64646 -64647 -64648 -64649 -64650 -64651 -64652 -64653 -64654 -64655 -64656 -64657 -64658 -64659 -64660 -64661 -64662 -64663 -64664 -64665 -64666 -64667 -64668 -64669 -64670 -64671 -64672 -64673 -64674 -64675 -64676 -64677 -64678 -64679 -64680 -64681 -64682 -64683 -64684 -64685 -64686 -64687 -64688 -64689 -64690 -64691 -64692 -64693 -64694 -64695 -64696 -64697 -64698 -64699 -64700 -64701 -64702 -64703 -64704 -64705 -64706 -64707 -64708 -64709 -64710 -64711 -64712 -64713 -64714 -64715 -64716 -64717 -64718 -64719 -64720 -64721 -64722 -64723 -64724 -64725 -64726 -64727 -64728 -64729 -64730 -64731 -64732 -64733 -64734 -64735 -64736 -64737 -64738 -64739 -64740 -64741 -64742 -64743 -64744 -64745 -64746 -64747 -64748 -64749 -64750 -64751 -64752 -64753 -64754 -64755 -64756 -64757 -64758 -64759 -64760 -64761 -64762 -64763 -64764 -64765 -64766 -64767 -64768 -64769 -64770 -64771 -64772 -64773 -64774 -64775 -64776 -64777 -64778 -64779 -64780 -64781 -64782 -64783 -64784 -64785 -64786 -64787 -64788 -64789 -64790 -64791 -64792 -64793 -64794 -64795 -64796 -64797 -64798 -64799 -64800 -64801 -64802 -64803 -64804 -64805 -64806 -64807 -64808 -64809 -64810 -64811 -64812 -64813 -64814 -64815 -64816 -64817 -64818 -64819 -64820 -64821 -64822 -64823 -64824 -64825 -64826 -64827 -64828 -64829 -64830 -64831 -64832 -64833 -64834 -64835 -64836 -64837 -64838 -64839 -64840 -64841 -64842 -64843 -64844 -64845 -64846 -64847 -64848 -64849 -64850 -64851 -64852 -64853 -64854 -64855 -64856 -64857 -64858 -64859 -64860 -64861 -64862 -64863 -64864 -64865 -64866 -64867 -64868 -64869 -64870 -64871 -64872 -64873 -64874 -64875 -64876 -64877 -64878 -64879 -64880 -64881 -64882 -64883 -64884 -64885 -64886 -64887 -64888 -64889 -64890 -64891 -64892 -64893 -64894 -64895 -64896 -64897 -64898 -64899 -64900 -64901 -64902 -64903 -64904 -64905 -64906 -64907 -64908 -64909 -64910 -64911 -64912 -64913 -64914 -64915 -64916 -64917 -64918 -64919 -64920 -64921 -64922 -64923 -64924 -64925 -64926 -64927 -64928 -64929 -64930 -64931 -64932 -64933 -64934 -64935 -64936 -64937 -64938 -64939 -64940 -64941 -64942 -64943 -64944 -64945 -64946 -64947 -64948 -64949 -64950 -64951 -64952 -64953 -64954 -64955 -64956 -64957 -64958 -64959 -64960 -64961 -64962 -64963 -64964 -64965 -64966 -64967 -64968 -64969 -64970 -64971 -64972 -64973 -64974 -64975 -64976 -64977 -64978 -64979 -64980 -64981 -64982 -64983 -64984 -64985 -64986 -64987 -64988 -64989 -64990 -64991 -64992 -64993 -64994 -64995 -64996 -64997 -64998 -64999 -65000 -65001 -65002 -65003 -65004 -65005 -65006 -65007 -65008 -65009 -65010 -65011 -65012 -65013 -65014 -65015 -65016 -65017 -65018 -65019 -65020 -65021 -65022 -65023 -65024 -65025 -65026 -65027 -65028 -65029 -65030 -65031 -65032 -65033 -65034 -65035 -65036 -65037 -65038 -65039 -65040 -65041 -65042 -65043 -65044 -65045 -65046 -65047 -65048 -65049 -65050 -65051 -65052 -65053 -65054 -65055 -65056 -65057 -65058 -65059 -65060 -65061 -65062 -65063 -65064 -65065 -65066 -65067 -65068 -65069 -65070 -65071 -65072 -65073 -65074 -65075 -65076 -65077 -65078 -65079 -65080 -65081 -65082 -65083 -65084 -65085 -65086 -65087 -65088 -65089 -65090 -65091 -65092 -65093 -65094 -65095 -65096 -65097 -65098 -65099 -65100 -65101 -65102 -65103 -65104 -65105 -65106 -65107 -65108 -65109 -65110 -65111 -65112 -65113 -65114 -65115 -65116 -65117 -65118 -65119 -65120 -65121 -65122 -65123 -65124 -65125 -65126 -65127 -65128 -65129 -65130 -65131 -65132 -65133 -65134 -65135 -65136 -65137 -65138 -65139 -65140 -65141 -65142 -65143 -65144 -65145 -65146 -65147 -65148 -65149 -65150 -65151 -65152 -65153 -65154 -65155 -65156 -65157 -65158 -65159 -65160 -65161 -65162 -65163 -65164 -65165 -65166 -65167 -65168 -65169 -65170 -65171 -65172 -65173 -65174 -65175 -65176 -65177 -65178 -65179 -65180 -65181 -65182 -65183 -65184 -65185 -65186 -65187 -65188 -65189 -65190 -65191 -65192 -65193 -65194 -65195 -65196 -65197 -65198 -65199 -65200 -65201 -65202 -65203 -65204 -65205 -65206 -65207 -65208 -65209 -65210 -65211 -65212 -65213 -65214 -65215 -65216 -65217 -65218 -65219 -65220 -65221 -65222 -65223 -65224 -65225 -65226 -65227 -65228 -65229 -65230 -65231 -65232 -65233 -65234 -65235 -65236 -65237 -65238 -65239 -65240 -65241 -65242 -65243 -65244 -65245 -65246 -65247 -65248 -65249 -65250 -65251 -65252 -65253 -65254 -65255 -65256 -65257 -65258 -65259 -65260 -65261 -65262 -65263 -65264 -65265 -65266 -65267 -65268 -65269 -65270 -65271 -65272 -65273 -65274 -65275 -65276 -65277 -65278 -65279 -65280 -65281 -65282 -65283 -65284 -65285 -65286 -65287 -65288 -65289 -65290 -65291 -65292 -65293 -65294 -65295 -65296 -65297 -65298 -65299 -65300 -65301 -65302 -65303 -65304 -65305 -65306 -65307 -65308 -65309 -65310 -65311 -65312 -65313 -65314 -65315 -65316 -65317 -65318 -65319 -65320 -65321 -65322 -65323 -65324 -65325 -65326 -65327 -65328 -65329 -65330 -65331 -65332 -65333 -65334 -65335 -65336 -65337 -65338 -65339 -65340 -65341 -65342 -65343 -65344 -65345 -65346 -65347 -65348 -65349 -65350 -65351 -65352 -65353 -65354 -65355 -65356 -65357 -65358 -65359 -65360 -65361 -65362 -65363 -65364 -65365 -65366 -65367 -65368 -65369 -65370 -65371 -65372 -65373 -65374 -65375 -65376 -65377 -65378 -65379 -65380 -65381 -65382 -65383 -65384 -65385 -65386 -65387 -65388 -65389 -65390 -65391 -65392 -65393 -65394 -65395 -65396 -65397 -65398 -65399 -65400 -65401 -65402 -65403 -65404 -65405 -65406 -65407 -65408 -65409 -65410 -65411 -65412 -65413 -65414 -65415 -65416 -65417 -65418 -65419 -65420 -65421 -65422 -65423 -65424 -65425 -65426 -65427 -65428 -65429 -65430 -65431 -65432 -65433 -65434 -65435 -65436 -65437 -65438 -65439 -65440 -65441 -65442 -65443 -65444 -65445 -65446 -65447 -65448 -65449 -65450 -65451 -65452 -65453 -65454 -65455 -65456 -65457 -65458 -65459 -65460 -65461 -65462 -65463 -65464 -65465 -65466 -65467 -65468 -65469 -65470 -65471 -65472 -65473 -65474 -65475 -65476 -65477 -65478 -65479 -65480 -65481 -65482 -65483 -65484 -65485 -65486 -65487 -65488 -65489 -65490 -65491 -65492 -65493 -65494 -65495 -65496 -65497 -65498 -65499 -65500 -65501 -65502 -65503 -65504 -65505 -65506 -65507 -65508 -65509 -65510 -65511 -65512 -65513 -65514 -65515 -65516 -65517 -65518 -65519 -65520 -65521 -65522 -65523 -65524 -65525 -65526 -65527 -65528 -65529 -65530 -65531 -65532 -65533 -65534 -65535 diff --git a/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k1.txt b/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k1.txt deleted file mode 100644 index 8b653d509..000000000 --- a/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k1.txt +++ /dev/null @@ -1,17 +0,0 @@ -0 -1 -2 -4 -8 -16 -32 -64 -128 -256 -512 -1024 -2048 -4096 -8192 -16384 -32768 diff --git a/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k2.txt b/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k2.txt deleted file mode 100644 index c1de54b25..000000000 --- a/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k2.txt +++ /dev/null @@ -1,137 +0,0 @@ -0 -1 -2 -3 -4 -5 -6 -8 -9 -10 -12 -16 -17 -18 -20 -24 -32 -33 -34 -36 -40 -48 -64 -65 -66 -68 -72 -80 -96 -128 -129 -130 -132 -136 -144 -160 -192 -256 -257 -258 -260 -264 -272 -288 -320 -384 -512 -513 -514 -516 -520 -528 -544 -576 -640 -768 -1024 -1025 -1026 -1028 -1032 -1040 -1056 -1088 -1152 -1280 -1536 -2048 -2049 -2050 -2052 -2056 -2064 -2080 -2112 -2176 -2304 -2560 -3072 -4096 -4097 -4098 -4100 -4104 -4112 -4128 -4160 -4224 -4352 -4608 -5120 -6144 -8192 -8193 -8194 -8196 -8200 -8208 -8224 -8256 -8320 -8448 -8704 -9216 -10240 -12288 -16384 -16385 -16386 -16388 -16392 -16400 -16416 -16448 -16512 -16640 -16896 -17408 -18432 -20480 -24576 -32768 -32769 -32770 -32772 -32776 -32784 -32800 -32832 -32896 -33024 -33280 -33792 -34816 -36864 -40960 -49152 diff --git a/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k3.txt b/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k3.txt deleted file mode 100644 index 1e26ab7e3..000000000 --- a/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k3.txt +++ /dev/null @@ -1,697 +0,0 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -16 -17 -18 -19 -20 -21 -22 -24 -25 -26 -28 -32 -33 -34 -35 -36 -37 -38 -40 -41 -42 -44 -48 -49 -50 -52 -56 -64 -65 -66 -67 -68 -69 -70 -72 -73 -74 -76 -80 -81 -82 -84 -88 -96 -97 -98 -100 -104 -112 -128 -129 -130 -131 -132 -133 -134 -136 -137 -138 -140 -144 -145 -146 -148 -152 -160 -161 -162 -164 -168 -176 -192 -193 -194 -196 -200 -208 -224 -256 -257 -258 -259 -260 -261 -262 -264 -265 -266 -268 -272 -273 -274 -276 -280 -288 -289 -290 -292 -296 -304 -320 -321 -322 -324 -328 -336 -352 -384 -385 -386 -388 -392 -400 -416 -448 -512 -513 -514 -515 -516 -517 -518 -520 -521 -522 -524 -528 -529 -530 -532 -536 -544 -545 -546 -548 -552 -560 -576 -577 -578 -580 -584 -592 -608 -640 -641 -642 -644 -648 -656 -672 -704 -768 -769 -770 -772 -776 -784 -800 -832 -896 -1024 -1025 -1026 -1027 -1028 -1029 -1030 -1032 -1033 -1034 -1036 -1040 -1041 -1042 -1044 -1048 -1056 -1057 -1058 -1060 -1064 -1072 -1088 -1089 -1090 -1092 -1096 -1104 -1120 -1152 -1153 -1154 -1156 -1160 -1168 -1184 -1216 -1280 -1281 -1282 -1284 -1288 -1296 -1312 -1344 -1408 -1536 -1537 -1538 -1540 -1544 -1552 -1568 -1600 -1664 -1792 -2048 -2049 -2050 -2051 -2052 -2053 -2054 -2056 -2057 -2058 -2060 -2064 -2065 -2066 -2068 -2072 -2080 -2081 -2082 -2084 -2088 -2096 -2112 -2113 -2114 -2116 -2120 -2128 -2144 -2176 -2177 -2178 -2180 -2184 -2192 -2208 -2240 -2304 -2305 -2306 -2308 -2312 -2320 -2336 -2368 -2432 -2560 -2561 -2562 -2564 -2568 -2576 -2592 -2624 -2688 -2816 -3072 -3073 -3074 -3076 -3080 -3088 -3104 -3136 -3200 -3328 -3584 -4096 -4097 -4098 -4099 -4100 -4101 -4102 -4104 -4105 -4106 -4108 -4112 -4113 -4114 -4116 -4120 -4128 -4129 -4130 -4132 -4136 -4144 -4160 -4161 -4162 -4164 -4168 -4176 -4192 -4224 -4225 -4226 -4228 -4232 -4240 -4256 -4288 -4352 -4353 -4354 -4356 -4360 -4368 -4384 -4416 -4480 -4608 -4609 -4610 -4612 -4616 -4624 -4640 -4672 -4736 -4864 -5120 -5121 -5122 -5124 -5128 -5136 -5152 -5184 -5248 -5376 -5632 -6144 -6145 -6146 -6148 -6152 -6160 -6176 -6208 -6272 -6400 -6656 -7168 -8192 -8193 -8194 -8195 -8196 -8197 -8198 -8200 -8201 -8202 -8204 -8208 -8209 -8210 -8212 -8216 -8224 -8225 -8226 -8228 -8232 -8240 -8256 -8257 -8258 -8260 -8264 -8272 -8288 -8320 -8321 -8322 -8324 -8328 -8336 -8352 -8384 -8448 -8449 -8450 -8452 -8456 -8464 -8480 -8512 -8576 -8704 -8705 -8706 -8708 -8712 -8720 -8736 -8768 -8832 -8960 -9216 -9217 -9218 -9220 -9224 -9232 -9248 -9280 -9344 -9472 -9728 -10240 -10241 -10242 -10244 -10248 -10256 -10272 -10304 -10368 -10496 -10752 -11264 -12288 -12289 -12290 -12292 -12296 -12304 -12320 -12352 -12416 -12544 -12800 -13312 -14336 -16384 -16385 -16386 -16387 -16388 -16389 -16390 -16392 -16393 -16394 -16396 -16400 -16401 -16402 -16404 -16408 -16416 -16417 -16418 -16420 -16424 -16432 -16448 -16449 -16450 -16452 -16456 -16464 -16480 -16512 -16513 -16514 -16516 -16520 -16528 -16544 -16576 -16640 -16641 -16642 -16644 -16648 -16656 -16672 -16704 -16768 -16896 -16897 -16898 -16900 -16904 -16912 -16928 -16960 -17024 -17152 -17408 -17409 -17410 -17412 -17416 -17424 -17440 -17472 -17536 -17664 -17920 -18432 -18433 -18434 -18436 -18440 -18448 -18464 -18496 -18560 -18688 -18944 -19456 -20480 -20481 -20482 -20484 -20488 -20496 -20512 -20544 -20608 -20736 -20992 -21504 -22528 -24576 -24577 -24578 -24580 -24584 -24592 -24608 -24640 -24704 -24832 -25088 -25600 -26624 -28672 -32768 -32769 -32770 -32771 -32772 -32773 -32774 -32776 -32777 -32778 -32780 -32784 -32785 -32786 -32788 -32792 -32800 -32801 -32802 -32804 -32808 -32816 -32832 -32833 -32834 -32836 -32840 -32848 -32864 -32896 -32897 -32898 -32900 -32904 -32912 -32928 -32960 -33024 -33025 -33026 -33028 -33032 -33040 -33056 -33088 -33152 -33280 -33281 -33282 -33284 -33288 -33296 -33312 -33344 -33408 -33536 -33792 -33793 -33794 -33796 -33800 -33808 -33824 -33856 -33920 -34048 -34304 -34816 -34817 -34818 -34820 -34824 -34832 -34848 -34880 -34944 -35072 -35328 -35840 -36864 -36865 -36866 -36868 -36872 -36880 -36896 -36928 -36992 -37120 -37376 -37888 -38912 -40960 -40961 -40962 -40964 -40968 -40976 -40992 -41024 -41088 -41216 -41472 -41984 -43008 -45056 -49152 -49153 -49154 -49156 -49160 -49168 -49184 -49216 -49280 -49408 -49664 -50176 -51200 -53248 -57344 diff --git a/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k4.txt b/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k4.txt deleted file mode 100644 index e347fdbe8..000000000 --- a/egs/callhome/TOLD/soap/data/token_list/powerset_label_n16k4.txt +++ /dev/null @@ -1,2517 +0,0 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -48 -49 -50 -51 -52 -53 -54 -56 -57 -58 -60 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -80 -81 -82 -83 -84 -85 -86 -88 -89 -90 -92 -96 -97 -98 -99 -100 -101 -102 -104 -105 -106 -108 -112 -113 -114 -116 -120 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -144 -145 -146 -147 -148 -149 -150 -152 -153 -154 -156 -160 -161 -162 -163 -164 -165 -166 -168 -169 -170 -172 -176 -177 -178 -180 -184 -192 -193 -194 -195 -196 -197 -198 -200 -201 -202 -204 -208 -209 -210 -212 -216 -224 -225 -226 -228 -232 -240 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -272 -273 -274 -275 -276 -277 -278 -280 -281 -282 -284 -288 -289 -290 -291 -292 -293 -294 -296 -297 -298 -300 -304 -305 -306 -308 -312 -320 -321 -322 -323 -324 -325 -326 -328 -329 -330 -332 -336 -337 -338 -340 -344 -352 -353 -354 -356 -360 -368 -384 -385 -386 -387 -388 -389 -390 -392 -393 -394 -396 -400 -401 -402 -404 -408 -416 -417 -418 -420 -424 -432 -448 -449 -450 -452 -456 -464 -480 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -528 -529 -530 -531 -532 -533 -534 -536 -537 -538 -540 -544 -545 -546 -547 -548 -549 -550 -552 -553 -554 -556 -560 -561 -562 -564 -568 -576 -577 -578 -579 -580 -581 -582 -584 -585 -586 -588 -592 -593 -594 -596 -600 -608 -609 -610 -612 -616 -624 -640 -641 -642 -643 -644 -645 -646 -648 -649 -650 -652 -656 -657 -658 -660 -664 -672 -673 -674 -676 -680 -688 -704 -705 -706 -708 -712 -720 -736 -768 -769 -770 -771 -772 -773 -774 -776 -777 -778 -780 -784 -785 -786 -788 -792 -800 -801 -802 -804 -808 -816 -832 -833 -834 -836 -840 -848 -864 -896 -897 -898 -900 -904 -912 -928 -960 -1024 -1025 -1026 -1027 -1028 -1029 -1030 -1031 -1032 -1033 -1034 -1035 -1036 -1037 -1038 -1040 -1041 -1042 -1043 -1044 -1045 -1046 -1048 -1049 -1050 -1052 -1056 -1057 -1058 -1059 -1060 -1061 -1062 -1064 -1065 -1066 -1068 -1072 -1073 -1074 -1076 -1080 -1088 -1089 -1090 -1091 -1092 -1093 -1094 -1096 -1097 -1098 -1100 -1104 -1105 -1106 -1108 -1112 -1120 -1121 -1122 -1124 -1128 -1136 -1152 -1153 -1154 -1155 -1156 -1157 -1158 -1160 -1161 -1162 -1164 -1168 -1169 -1170 -1172 -1176 -1184 -1185 -1186 -1188 -1192 -1200 -1216 -1217 -1218 -1220 -1224 -1232 -1248 -1280 -1281 -1282 -1283 -1284 -1285 -1286 -1288 -1289 -1290 -1292 -1296 -1297 -1298 -1300 -1304 -1312 -1313 -1314 -1316 -1320 -1328 -1344 -1345 -1346 -1348 -1352 -1360 -1376 -1408 -1409 -1410 -1412 -1416 -1424 -1440 -1472 -1536 -1537 -1538 -1539 -1540 -1541 -1542 -1544 -1545 -1546 -1548 -1552 -1553 -1554 -1556 -1560 -1568 -1569 -1570 -1572 -1576 -1584 -1600 -1601 -1602 -1604 -1608 -1616 -1632 -1664 -1665 -1666 -1668 -1672 -1680 -1696 -1728 -1792 -1793 -1794 -1796 -1800 -1808 -1824 -1856 -1920 -2048 -2049 -2050 -2051 -2052 -2053 -2054 -2055 -2056 -2057 -2058 -2059 -2060 -2061 -2062 -2064 -2065 -2066 -2067 -2068 -2069 -2070 -2072 -2073 -2074 -2076 -2080 -2081 -2082 -2083 -2084 -2085 -2086 -2088 -2089 -2090 -2092 -2096 -2097 -2098 -2100 -2104 -2112 -2113 -2114 -2115 -2116 -2117 -2118 -2120 -2121 -2122 -2124 -2128 -2129 -2130 -2132 -2136 -2144 -2145 -2146 -2148 -2152 -2160 -2176 -2177 -2178 -2179 -2180 -2181 -2182 -2184 -2185 -2186 -2188 -2192 -2193 -2194 -2196 -2200 -2208 -2209 -2210 -2212 -2216 -2224 -2240 -2241 -2242 -2244 -2248 -2256 -2272 -2304 -2305 -2306 -2307 -2308 -2309 -2310 -2312 -2313 -2314 -2316 -2320 -2321 -2322 -2324 -2328 -2336 -2337 -2338 -2340 -2344 -2352 -2368 -2369 -2370 -2372 -2376 -2384 -2400 -2432 -2433 -2434 -2436 -2440 -2448 -2464 -2496 -2560 -2561 -2562 -2563 -2564 -2565 -2566 -2568 -2569 -2570 -2572 -2576 -2577 -2578 -2580 -2584 -2592 -2593 -2594 -2596 -2600 -2608 -2624 -2625 -2626 -2628 -2632 -2640 -2656 -2688 -2689 -2690 -2692 -2696 -2704 -2720 -2752 -2816 -2817 -2818 -2820 -2824 -2832 -2848 -2880 -2944 -3072 -3073 -3074 -3075 -3076 -3077 -3078 -3080 -3081 -3082 -3084 -3088 -3089 -3090 -3092 -3096 -3104 -3105 -3106 -3108 -3112 -3120 -3136 -3137 -3138 -3140 -3144 -3152 -3168 -3200 -3201 -3202 -3204 -3208 -3216 -3232 -3264 -3328 -3329 -3330 -3332 -3336 -3344 -3360 -3392 -3456 -3584 -3585 -3586 -3588 -3592 -3600 -3616 -3648 -3712 -3840 -4096 -4097 -4098 -4099 -4100 -4101 -4102 -4103 -4104 -4105 -4106 -4107 -4108 -4109 -4110 -4112 -4113 -4114 -4115 -4116 -4117 -4118 -4120 -4121 -4122 -4124 -4128 -4129 -4130 -4131 -4132 -4133 -4134 -4136 -4137 -4138 -4140 -4144 -4145 -4146 -4148 -4152 -4160 -4161 -4162 -4163 -4164 -4165 -4166 -4168 -4169 -4170 -4172 -4176 -4177 -4178 -4180 -4184 -4192 -4193 -4194 -4196 -4200 -4208 -4224 -4225 -4226 -4227 -4228 -4229 -4230 -4232 -4233 -4234 -4236 -4240 -4241 -4242 -4244 -4248 -4256 -4257 -4258 -4260 -4264 -4272 -4288 -4289 -4290 -4292 -4296 -4304 -4320 -4352 -4353 -4354 -4355 -4356 -4357 -4358 -4360 -4361 -4362 -4364 -4368 -4369 -4370 -4372 -4376 -4384 -4385 -4386 -4388 -4392 -4400 -4416 -4417 -4418 -4420 -4424 -4432 -4448 -4480 -4481 -4482 -4484 -4488 -4496 -4512 -4544 -4608 -4609 -4610 -4611 -4612 -4613 -4614 -4616 -4617 -4618 -4620 -4624 -4625 -4626 -4628 -4632 -4640 -4641 -4642 -4644 -4648 -4656 -4672 -4673 -4674 -4676 -4680 -4688 -4704 -4736 -4737 -4738 -4740 -4744 -4752 -4768 -4800 -4864 -4865 -4866 -4868 -4872 -4880 -4896 -4928 -4992 -5120 -5121 -5122 -5123 -5124 -5125 -5126 -5128 -5129 -5130 -5132 -5136 -5137 -5138 -5140 -5144 -5152 -5153 -5154 -5156 -5160 -5168 -5184 -5185 -5186 -5188 -5192 -5200 -5216 -5248 -5249 -5250 -5252 -5256 -5264 -5280 -5312 -5376 -5377 -5378 -5380 -5384 -5392 -5408 -5440 -5504 -5632 -5633 -5634 -5636 -5640 -5648 -5664 -5696 -5760 -5888 -6144 -6145 -6146 -6147 -6148 -6149 -6150 -6152 -6153 -6154 -6156 -6160 -6161 -6162 -6164 -6168 -6176 -6177 -6178 -6180 -6184 -6192 -6208 -6209 -6210 -6212 -6216 -6224 -6240 -6272 -6273 -6274 -6276 -6280 -6288 -6304 -6336 -6400 -6401 -6402 -6404 -6408 -6416 -6432 -6464 -6528 -6656 -6657 -6658 -6660 -6664 -6672 -6688 -6720 -6784 -6912 -7168 -7169 -7170 -7172 -7176 -7184 -7200 -7232 -7296 -7424 -7680 -8192 -8193 -8194 -8195 -8196 -8197 -8198 -8199 -8200 -8201 -8202 -8203 -8204 -8205 -8206 -8208 -8209 -8210 -8211 -8212 -8213 -8214 -8216 -8217 -8218 -8220 -8224 -8225 -8226 -8227 -8228 -8229 -8230 -8232 -8233 -8234 -8236 -8240 -8241 -8242 -8244 -8248 -8256 -8257 -8258 -8259 -8260 -8261 -8262 -8264 -8265 -8266 -8268 -8272 -8273 -8274 -8276 -8280 -8288 -8289 -8290 -8292 -8296 -8304 -8320 -8321 -8322 -8323 -8324 -8325 -8326 -8328 -8329 -8330 -8332 -8336 -8337 -8338 -8340 -8344 -8352 -8353 -8354 -8356 -8360 -8368 -8384 -8385 -8386 -8388 -8392 -8400 -8416 -8448 -8449 -8450 -8451 -8452 -8453 -8454 -8456 -8457 -8458 -8460 -8464 -8465 -8466 -8468 -8472 -8480 -8481 -8482 -8484 -8488 -8496 -8512 -8513 -8514 -8516 -8520 -8528 -8544 -8576 -8577 -8578 -8580 -8584 -8592 -8608 -8640 -8704 -8705 -8706 -8707 -8708 -8709 -8710 -8712 -8713 -8714 -8716 -8720 -8721 -8722 -8724 -8728 -8736 -8737 -8738 -8740 -8744 -8752 -8768 -8769 -8770 -8772 -8776 -8784 -8800 -8832 -8833 -8834 -8836 -8840 -8848 -8864 -8896 -8960 -8961 -8962 -8964 -8968 -8976 -8992 -9024 -9088 -9216 -9217 -9218 -9219 -9220 -9221 -9222 -9224 -9225 -9226 -9228 -9232 -9233 -9234 -9236 -9240 -9248 -9249 -9250 -9252 -9256 -9264 -9280 -9281 -9282 -9284 -9288 -9296 -9312 -9344 -9345 -9346 -9348 -9352 -9360 -9376 -9408 -9472 -9473 -9474 -9476 -9480 -9488 -9504 -9536 -9600 -9728 -9729 -9730 -9732 -9736 -9744 -9760 -9792 -9856 -9984 -10240 -10241 -10242 -10243 -10244 -10245 -10246 -10248 -10249 -10250 -10252 -10256 -10257 -10258 -10260 -10264 -10272 -10273 -10274 -10276 -10280 -10288 -10304 -10305 -10306 -10308 -10312 -10320 -10336 -10368 -10369 -10370 -10372 -10376 -10384 -10400 -10432 -10496 -10497 -10498 -10500 -10504 -10512 -10528 -10560 -10624 -10752 -10753 -10754 -10756 -10760 -10768 -10784 -10816 -10880 -11008 -11264 -11265 -11266 -11268 -11272 -11280 -11296 -11328 -11392 -11520 -11776 -12288 -12289 -12290 -12291 -12292 -12293 -12294 -12296 -12297 -12298 -12300 -12304 -12305 -12306 -12308 -12312 -12320 -12321 -12322 -12324 -12328 -12336 -12352 -12353 -12354 -12356 -12360 -12368 -12384 -12416 -12417 -12418 -12420 -12424 -12432 -12448 -12480 -12544 -12545 -12546 -12548 -12552 -12560 -12576 -12608 -12672 -12800 -12801 -12802 -12804 -12808 -12816 -12832 -12864 -12928 -13056 -13312 -13313 -13314 -13316 -13320 -13328 -13344 -13376 -13440 -13568 -13824 -14336 -14337 -14338 -14340 -14344 -14352 -14368 -14400 -14464 -14592 -14848 -15360 -16384 -16385 -16386 -16387 -16388 -16389 -16390 -16391 -16392 -16393 -16394 -16395 -16396 -16397 -16398 -16400 -16401 -16402 -16403 -16404 -16405 -16406 -16408 -16409 -16410 -16412 -16416 -16417 -16418 -16419 -16420 -16421 -16422 -16424 -16425 -16426 -16428 -16432 -16433 -16434 -16436 -16440 -16448 -16449 -16450 -16451 -16452 -16453 -16454 -16456 -16457 -16458 -16460 -16464 -16465 -16466 -16468 -16472 -16480 -16481 -16482 -16484 -16488 -16496 -16512 -16513 -16514 -16515 -16516 -16517 -16518 -16520 -16521 -16522 -16524 -16528 -16529 -16530 -16532 -16536 -16544 -16545 -16546 -16548 -16552 -16560 -16576 -16577 -16578 -16580 -16584 -16592 -16608 -16640 -16641 -16642 -16643 -16644 -16645 -16646 -16648 -16649 -16650 -16652 -16656 -16657 -16658 -16660 -16664 -16672 -16673 -16674 -16676 -16680 -16688 -16704 -16705 -16706 -16708 -16712 -16720 -16736 -16768 -16769 -16770 -16772 -16776 -16784 -16800 -16832 -16896 -16897 -16898 -16899 -16900 -16901 -16902 -16904 -16905 -16906 -16908 -16912 -16913 -16914 -16916 -16920 -16928 -16929 -16930 -16932 -16936 -16944 -16960 -16961 -16962 -16964 -16968 -16976 -16992 -17024 -17025 -17026 -17028 -17032 -17040 -17056 -17088 -17152 -17153 -17154 -17156 -17160 -17168 -17184 -17216 -17280 -17408 -17409 -17410 -17411 -17412 -17413 -17414 -17416 -17417 -17418 -17420 -17424 -17425 -17426 -17428 -17432 -17440 -17441 -17442 -17444 -17448 -17456 -17472 -17473 -17474 -17476 -17480 -17488 -17504 -17536 -17537 -17538 -17540 -17544 -17552 -17568 -17600 -17664 -17665 -17666 -17668 -17672 -17680 -17696 -17728 -17792 -17920 -17921 -17922 -17924 -17928 -17936 -17952 -17984 -18048 -18176 -18432 -18433 -18434 -18435 -18436 -18437 -18438 -18440 -18441 -18442 -18444 -18448 -18449 -18450 -18452 -18456 -18464 -18465 -18466 -18468 -18472 -18480 -18496 -18497 -18498 -18500 -18504 -18512 -18528 -18560 -18561 -18562 -18564 -18568 -18576 -18592 -18624 -18688 -18689 -18690 -18692 -18696 -18704 -18720 -18752 -18816 -18944 -18945 -18946 -18948 -18952 -18960 -18976 -19008 -19072 -19200 -19456 -19457 -19458 -19460 -19464 -19472 -19488 -19520 -19584 -19712 -19968 -20480 -20481 -20482 -20483 -20484 -20485 -20486 -20488 -20489 -20490 -20492 -20496 -20497 -20498 -20500 -20504 -20512 -20513 -20514 -20516 -20520 -20528 -20544 -20545 -20546 -20548 -20552 -20560 -20576 -20608 -20609 -20610 -20612 -20616 -20624 -20640 -20672 -20736 -20737 -20738 -20740 -20744 -20752 -20768 -20800 -20864 -20992 -20993 -20994 -20996 -21000 -21008 -21024 -21056 -21120 -21248 -21504 -21505 -21506 -21508 -21512 -21520 -21536 -21568 -21632 -21760 -22016 -22528 -22529 -22530 -22532 -22536 -22544 -22560 -22592 -22656 -22784 -23040 -23552 -24576 -24577 -24578 -24579 -24580 -24581 -24582 -24584 -24585 -24586 -24588 -24592 -24593 -24594 -24596 -24600 -24608 -24609 -24610 -24612 -24616 -24624 -24640 -24641 -24642 -24644 -24648 -24656 -24672 -24704 -24705 -24706 -24708 -24712 -24720 -24736 -24768 -24832 -24833 -24834 -24836 -24840 -24848 -24864 -24896 -24960 -25088 -25089 -25090 -25092 -25096 -25104 -25120 -25152 -25216 -25344 -25600 -25601 -25602 -25604 -25608 -25616 -25632 -25664 -25728 -25856 -26112 -26624 -26625 -26626 -26628 -26632 -26640 -26656 -26688 -26752 -26880 -27136 -27648 -28672 -28673 -28674 -28676 -28680 -28688 -28704 -28736 -28800 -28928 -29184 -29696 -30720 -32768 -32769 -32770 -32771 -32772 -32773 -32774 -32775 -32776 -32777 -32778 -32779 -32780 -32781 -32782 -32784 -32785 -32786 -32787 -32788 -32789 -32790 -32792 -32793 -32794 -32796 -32800 -32801 -32802 -32803 -32804 -32805 -32806 -32808 -32809 -32810 -32812 -32816 -32817 -32818 -32820 -32824 -32832 -32833 -32834 -32835 -32836 -32837 -32838 -32840 -32841 -32842 -32844 -32848 -32849 -32850 -32852 -32856 -32864 -32865 -32866 -32868 -32872 -32880 -32896 -32897 -32898 -32899 -32900 -32901 -32902 -32904 -32905 -32906 -32908 -32912 -32913 -32914 -32916 -32920 -32928 -32929 -32930 -32932 -32936 -32944 -32960 -32961 -32962 -32964 -32968 -32976 -32992 -33024 -33025 -33026 -33027 -33028 -33029 -33030 -33032 -33033 -33034 -33036 -33040 -33041 -33042 -33044 -33048 -33056 -33057 -33058 -33060 -33064 -33072 -33088 -33089 -33090 -33092 -33096 -33104 -33120 -33152 -33153 -33154 -33156 -33160 -33168 -33184 -33216 -33280 -33281 -33282 -33283 -33284 -33285 -33286 -33288 -33289 -33290 -33292 -33296 -33297 -33298 -33300 -33304 -33312 -33313 -33314 -33316 -33320 -33328 -33344 -33345 -33346 -33348 -33352 -33360 -33376 -33408 -33409 -33410 -33412 -33416 -33424 -33440 -33472 -33536 -33537 -33538 -33540 -33544 -33552 -33568 -33600 -33664 -33792 -33793 -33794 -33795 -33796 -33797 -33798 -33800 -33801 -33802 -33804 -33808 -33809 -33810 -33812 -33816 -33824 -33825 -33826 -33828 -33832 -33840 -33856 -33857 -33858 -33860 -33864 -33872 -33888 -33920 -33921 -33922 -33924 -33928 -33936 -33952 -33984 -34048 -34049 -34050 -34052 -34056 -34064 -34080 -34112 -34176 -34304 -34305 -34306 -34308 -34312 -34320 -34336 -34368 -34432 -34560 -34816 -34817 -34818 -34819 -34820 -34821 -34822 -34824 -34825 -34826 -34828 -34832 -34833 -34834 -34836 -34840 -34848 -34849 -34850 -34852 -34856 -34864 -34880 -34881 -34882 -34884 -34888 -34896 -34912 -34944 -34945 -34946 -34948 -34952 -34960 -34976 -35008 -35072 -35073 -35074 -35076 -35080 -35088 -35104 -35136 -35200 -35328 -35329 -35330 -35332 -35336 -35344 -35360 -35392 -35456 -35584 -35840 -35841 -35842 -35844 -35848 -35856 -35872 -35904 -35968 -36096 -36352 -36864 -36865 -36866 -36867 -36868 -36869 -36870 -36872 -36873 -36874 -36876 -36880 -36881 -36882 -36884 -36888 -36896 -36897 -36898 -36900 -36904 -36912 -36928 -36929 -36930 -36932 -36936 -36944 -36960 -36992 -36993 -36994 -36996 -37000 -37008 -37024 -37056 -37120 -37121 -37122 -37124 -37128 -37136 -37152 -37184 -37248 -37376 -37377 -37378 -37380 -37384 -37392 -37408 -37440 -37504 -37632 -37888 -37889 -37890 -37892 -37896 -37904 -37920 -37952 -38016 -38144 -38400 -38912 -38913 -38914 -38916 -38920 -38928 -38944 -38976 -39040 -39168 -39424 -39936 -40960 -40961 -40962 -40963 -40964 -40965 -40966 -40968 -40969 -40970 -40972 -40976 -40977 -40978 -40980 -40984 -40992 -40993 -40994 -40996 -41000 -41008 -41024 -41025 -41026 -41028 -41032 -41040 -41056 -41088 -41089 -41090 -41092 -41096 -41104 -41120 -41152 -41216 -41217 -41218 -41220 -41224 -41232 -41248 -41280 -41344 -41472 -41473 -41474 -41476 -41480 -41488 -41504 -41536 -41600 -41728 -41984 -41985 -41986 -41988 -41992 -42000 -42016 -42048 -42112 -42240 -42496 -43008 -43009 -43010 -43012 -43016 -43024 -43040 -43072 -43136 -43264 -43520 -44032 -45056 -45057 -45058 -45060 -45064 -45072 -45088 -45120 -45184 -45312 -45568 -46080 -47104 -49152 -49153 -49154 -49155 -49156 -49157 -49158 -49160 -49161 -49162 -49164 -49168 -49169 -49170 -49172 -49176 -49184 -49185 -49186 -49188 -49192 -49200 -49216 -49217 -49218 -49220 -49224 -49232 -49248 -49280 -49281 -49282 -49284 -49288 -49296 -49312 -49344 -49408 -49409 -49410 -49412 -49416 -49424 -49440 -49472 -49536 -49664 -49665 -49666 -49668 -49672 -49680 -49696 -49728 -49792 -49920 -50176 -50177 -50178 -50180 -50184 -50192 -50208 -50240 -50304 -50432 -50688 -51200 -51201 -51202 -51204 -51208 -51216 -51232 -51264 -51328 -51456 -51712 -52224 -53248 -53249 -53250 -53252 -53256 -53264 -53280 -53312 -53376 -53504 -53760 -54272 -55296 -57344 -57345 -57346 -57348 -57352 -57360 -57376 -57408 -57472 -57600 -57856 -58368 -59392 -61440 diff --git a/egs/callhome/TOLD/soap/finetune.sh b/egs/callhome/TOLD/soap/finetune.sh deleted file mode 100644 index 1b536908e..000000000 --- a/egs/callhome/TOLD/soap/finetune.sh +++ /dev/null @@ -1,567 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# This recipe aims at reimplement the results of SOND on Callhome corpus which is represented in -# [1] TOLD: A Novel Two-stage Overlap-aware Framework for Speaker Diarization, ICASSP 2023 -# You can also use it on other dataset such AliMeeting to reproduce the results in -# [2] Speaker Overlap-aware Neural Diarization for Multi-party Meeting Analysis, EMNLP 2022 -# We recommend you run this script stage by stage. - -# This recipe includes: -# 1. downloading a pretrained model on the simulated data from switchboard and NIST, -# 2. finetuning the pretrained model on Callhome1. -# Finally, you will get a slightly better DER result 9.95% on Callhome2 than that in the paper 10.14%. - -# environment configuration -kaldi_root= - -if [ -z "${kaldi_root}" ]; then - echo "We need kaldi to prepare dataset, extract fbank features, please install kaldi first and set kaldi_root." - echo "Kaldi installation guide can be found at https://kaldi-asr.org/" - exit; -fi - -if [ ! -e local ]; then - ln -s ${kaldi_root}/egs/callhome_diarization/v2/local ./local -fi - -if [ ! -e utils ]; then - ln -s ${kaldi_root}/egs/callhome_diarization/v2/utils ./utils -fi - -# callhome data root like path/to/NIST/LDC2001S97 -callhome_root= -if [ -z "${kaldi_root}" ]; then - echo "We need callhome corpus to prepare data." - exit; -fi - -# machines configuration -gpu_devices="0,1,2,3" # for V100-16G, need 4 gpus. -gpu_num=4 -count=1 - -# general configuration -stage=0 -stop_stage=10 -# number of jobs for data process -nj=16 -sr=8000 - -# experiment configuration -lang=en -feats_type=fbank -datadir=data -dumpdir=dump -expdir=exp -train_cmd=utils/run.pl - -# training related -tag="" -train_set=callhome1 -valid_set=callhome1 -train_config=conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01_phase3.yaml -token_list=${datadir}/token_list/powerset_label_n16k4.txt -init_param= -freeze_param= - -# inference related -inference_model=valid.der.ave_5best.pb -inference_config=conf/basic_inference.yaml -inference_tag="" -test_sets="callhome2" -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# number of jobs for inference -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=4 -infer_cmd=utils/run.pl -told_max_iter=4 - -. utils/parse_options.sh || exit 1; - -model_dir="$(basename "${train_config}" .yaml)_${feats_type}_${lang}${tag}" - -# you can set gpu num for decoding here -gpuid_list=$gpu_devices # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -# Prepare datasets -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "Stage 0: Prepare callhome data." - local/make_callhome.sh ${callhome_root} ${datadir}/ - - # split ref.rttm - for dset in callhome1 callhome2; do - rm -rf ${datadir}/${dset}/ref.rttm - for name in `awk '{print $1}' ${datadir}/${dset}/wav.scp`; do - grep ${name} ${datadir}/callhome/fullref.rttm >> ${datadir}/${dset}/ref.rttm; - done - - # filter out records which don't have rttm labels. - awk '{print $2}' ${datadir}/${dset}/ref.rttm | sort | uniq > ${datadir}/${dset}/uttid - mv ${datadir}/${dset}/wav.scp ${datadir}/${dset}/wav.scp.bak - awk '{if (NR==FNR){a[$1]=1}else{if (a[$1]==1){print $0}}}' ${datadir}/${dset}/uttid ${datadir}/${dset}/wav.scp.bak > ${datadir}/${dset}/wav.scp - mkdir ${datadir}/${dset}/raw - mv ${datadir}/${dset}/{reco2num_spk,segments,spk2utt,utt2spk,uttid,wav.scp.bak} ${datadir}/${dset}/raw/ - awk '{print $1,$1}' ${datadir}/${dset}/wav.scp > ${datadir}/${dset}/utt2spk - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "Stage 1: Dump sph file to wav" - export PATH=${kaldi_root}/tools/sph2pipe/:${PATH} - if [ ! -f ${kaldi_root}/tools/sph2pipe/sph2pipe ]; then - echo "Can not find sph2pipe in ${kaldi_root}/tools/sph2pipe/," - echo "please install sph2pipe and put it in the right place." - exit; - fi - - for dset in callhome1 callhome2; do - echo "Stage 1: start to dump ${dset}." - mv ${datadir}/${dset}/wav.scp ${datadir}/${dset}/sph.scp - - mkdir -p ${dumpdir}/${dset}/wavs - python -Wignore script/dump_pipe_wav.py ${datadir}/${dset}/sph.scp ${dumpdir}/${dset}/wavs \ - --sr ${sr} --nj ${nj} --no_pbar - find `pwd`/${dumpdir}/${dset}/wavs -iname "*.wav" | sort | awk -F'[/.]' '{print $(NF-1),$0}' > ${datadir}/${dset}/wav.scp - done -fi - -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "Stage 2: Extract non-overlap segments from callhome dataset" - for dset in callhome1 callhome2; do - echo "Stage 2: Extracting non-overlap segments for "${dset} - mkdir -p ${dumpdir}/${dset}/nonoverlap_0s - python -Wignore script/extract_nonoverlap_segments.py \ - ${datadir}/${dset}/wav.scp ${datadir}/${dset}/ref.rttm ${dumpdir}/${dset}/nonoverlap_0s \ - --min_dur 0.1 --max_spk_num 8 --sr ${sr} --no_pbar --nj ${nj} - - mkdir -p ${datadir}/${dset}/nonoverlap_0s - find ${dumpdir}/${dset}/nonoverlap_0s/ -iname "*.wav" | sort | awk -F'[/.]' '{print $(NF-1),$0}' > ${datadir}/${dset}/nonoverlap_0s/wav.scp - awk -F'[/.]' '{print $(NF-1),$(NF-2)}' ${datadir}/${dset}/nonoverlap_0s/wav.scp > ${datadir}/${dset}/nonoverlap_0s/utt2spk - echo "Done." - done -fi - -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "Stage 3: Generate fbank features" - home_path=$(pwd) - cd ${kaldi_root}/egs/callhome_diarization/v2 || exit - - export train_cmd="run.pl" - export cmd="run.pl" - . ./path.sh - cd $home_path || exit - - ln -s ${kaldi_root}/egs/callhome_diarization/v2/steps ./ - for dset in callhome1 callhome2; do - utils/fix_data_dir.sh ${datadir}/${dset} - steps/make_fbank.sh --write-utt2num-frames true --fbank-config conf/fbank.conf --nj ${nj} --cmd "$train_cmd" \ - ${datadir}/${dset} ${expdir}/make_fbank/${dset} ${dumpdir}/${dset}/fbank - done - rm -f steps - -fi - -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "Stage 4: Extract speaker embeddings." - sv_exp_dir=exp/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch - - if [ ! -e ${sv_exp_dir} ]; then - echo "start to download sv models" - git lfs install - git clone https://www.modelscope.cn/damo/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch.git - mv speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch ${expdir}/ - echo "Done." - fi - - for dset in callhome1/nonoverlap_0s callhome2/nonoverlap_0s; do - echo "Start to extract speaker embeddings for ${dset}" - key_file=${datadir}/${dset}/wav.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - _logdir=${dumpdir}/${dset}/xvecs - mkdir -p ${_logdir} - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/sv_inference.JOB.log \ - python -m funasr.bin.sv_inference_launch \ - --batch_size 1 \ - --njob ${njob} \ - --ngpu "${_ngpu}" \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${key_file},speech,sound" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --sv_train_config ${sv_exp_dir}/sv.yaml \ - --sv_model_file ${sv_exp_dir}/sv.pth \ - --output_dir "${_logdir}"/output.JOB - cat ${_logdir}/output.*/xvector.scp | sort > ${datadir}/${dset}/utt2xvec - - python script/calc_num_frames.py ${key_file} ${datadir}/${dset}/utt2num_frames - echo "Done." - done - -fi - -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "Stage 5: Generate label files." - - for dset in callhome1 callhome2; do - echo "Stage 5: Generate labels for ${dset}." - python -Wignore script/calc_real_meeting_frame_labels.py \ - ${datadir}/${dset} ${dumpdir}/${dset}/labels \ - --n_spk 8 --frame_shift 0.01 --nj 16 --sr 8000 - find `pwd`/${dumpdir}/${dset}/labels/ -iname "*.lbl.mat" | awk -F'[/.]' '{print $(NF-2),$0}' | sort > ${datadir}/${dset}/labels.scp - done - -fi - -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "Stage 6: Make training and evaluation files." - - # dump callhome1 data in training mode. - data_dir=${datadir}/callhome1/files_for_dump - mkdir ${data_dir} - # filter out zero duration segments - LC_ALL=C awk '{if ($5 > 0){print $0}}' ${datadir}/callhome1/ref.rttm > ${data_dir}/ref.rttm - cp ${datadir}/callhome1/{feats.scp,labels.scp} ${data_dir}/ - cp ${datadir}/callhome1/nonoverlap_0s/{utt2spk,utt2xvec,utt2num_frames} ${data_dir}/ - - echo "Stage 6: start to dump for callhome1." - python -Wignore script/dump_meeting_chunks.py --dir ${data_dir} \ - --out ${dumpdir}/callhome1/dumped_files/data --n_spk 16 --no_pbar --sr 8000 --mode train \ - --chunk_size 1600 --chunk_shift 400 --add_mid_to_speaker true - - mkdir -p ${datadir}/callhome1/dumped_files - cat ${dumpdir}/callhome1/dumped_files/data_parts*_feat.scp | sort > ${datadir}/callhome1/dumped_files/feats.scp - cat ${dumpdir}/callhome1/dumped_files/data_parts*_xvec.scp | sort > ${datadir}/callhome1/dumped_files/profile.scp - cat ${dumpdir}/callhome1/dumped_files/data_parts*_label.scp | sort > ${datadir}/callhome1/dumped_files/label.scp - mkdir -p ${expdir}/callhome1_states - awk '{print $1,"1600"}' ${datadir}/callhome1/dumped_files/feats.scp | shuf > ${expdir}/callhome1_states/speech_shape - python -Wignore script/convert_rttm_to_seg_file.py --rttm_scp ${data_dir}/ref.rttm --seg_file ${data_dir}/org_vad.txt - - # dump callhome2 data in test mode. - data_dir=${datadir}/callhome2/files_for_dump - mkdir ${data_dir} - # filter out zero duration segments - LC_ALL=C awk '{if ($5 > 0){print $0}}' ${datadir}/callhome2/ref.rttm > ${data_dir}/ref.rttm - cp ${datadir}/callhome2/{feats.scp,labels.scp} ${data_dir}/ - cp ${datadir}/callhome2/nonoverlap_0s/{utt2spk,utt2xvec,utt2num_frames} ${data_dir}/ - - echo "Stage 6: start to dump for callhome2." - python -Wignore script/dump_meeting_chunks.py --dir ${data_dir} \ - --out ${dumpdir}/callhome2/dumped_files/data --n_spk 16 --no_pbar --sr 8000 --mode test \ - --chunk_size 1600 --chunk_shift 400 --add_mid_to_speaker true - - mkdir -p ${datadir}/callhome2/dumped_files - cat ${dumpdir}/callhome2/dumped_files/data_parts*_feat.scp | sort > ${datadir}/callhome2/dumped_files/feats.scp - cat ${dumpdir}/callhome2/dumped_files/data_parts*_xvec.scp | sort > ${datadir}/callhome2/dumped_files/profile.scp - cat ${dumpdir}/callhome2/dumped_files/data_parts*_label.scp | sort > ${datadir}/callhome2/dumped_files/label.scp - mkdir -p ${expdir}/callhome2_states - awk '{print $1,"1600"}' ${datadir}/callhome2/dumped_files/feats.scp | shuf > ${expdir}/callhome2_states/speech_shape - python -Wignore script/convert_rttm_to_seg_file.py --rttm_scp ${data_dir}/ref.rttm --seg_file ${data_dir}/org_vad.txt - -fi - -# Finetune model on callhome1, this will take about 1.5 hours. -if [ ${stage} -le 7 ] && [ ${stop_stage} -ge 7 ]; then - echo "Stage 7: Finetune pretrained model on callhome1." - - if [ ! -e ${expdir}/speech_diarization_sond-en-us-swbd_sre-8k-n16k4-pytorch ]; then - echo "start to download pretrained models" - git lfs install - git clone https://www.modelscope.cn/damo/speech_diarization_sond-en-us-swbd_sre-8k-n16k4-pytorch.git - mv speech_diarization_sond-en-us-swbd_sre-8k-n16k4-pytorch ${expdir}/ - echo "Done." - fi - - world_size=$gpu_num # run on one machine - mkdir -p ${expdir}/${model_dir} - mkdir -p ${expdir}/${model_dir}/log - mkdir -p /tmp/${model_dir} - INIT_FILE=/tmp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_opt="" - if [ ! -z "${init_param}" ]; then - init_opt="--init_param ${init_param}" - echo ${init_opt} - fi - - freeze_opt="" - if [ ! -z "${freeze_param}" ]; then - freeze_opt="--freeze_param ${freeze_param}" - echo ${freeze_opt} - fi - - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $gpu_devices | cut -d',' -f$[$i+1]) - python -m funasr.bin.diar_train \ - --gpu_id $gpu_id \ - --use_preprocessor false \ - --token_type char \ - --token_list $token_list \ - --train_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/feats.scp,speech,kaldi_ark \ - --train_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/profile.scp,profile,kaldi_ark \ - --train_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/label.scp,binary_labels,kaldi_ark \ - --train_shape_file ${expdir}/${valid_set}_states/speech_shape \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/feats.scp,speech,kaldi_ark \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/profile.scp,profile,kaldi_ark \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/label.scp,binary_labels,kaldi_ark \ - --valid_shape_file ${expdir}/${valid_set}_states/speech_shape \ - --init_param ${expdir}/speech_diarization_sond-en-us-swbd_sre-8k-n16k4-pytorch/sond.pth \ - --unused_parameters true \ - ${init_opt} \ - ${freeze_opt} \ - --ignore_init_mismatch true \ - --resume true \ - --output_dir ${expdir}/${model_dir} \ - --config ${train_config} \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${expdir}/${model_dir}/log/train.log.$i 2>&1 - } & - done - echo "Training log can be found at ${expdir}/${model_dir}/log/train.log.*" - wait -fi - - -# evaluate for finetuned model -if [ ${stage} -le 8 ] && [ ${stop_stage} -ge 8 ]; then - echo "stage 8: evaluation for finetuned model ${inference_model}." - for dset in ${test_sets}; do - echo "Processing for $dset" - exp_model_dir=${expdir}/${model_dir} - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${exp_model_dir}/${_inference_tag}/${inference_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "WARNING: ${_dir} is already exists." - fi - mkdir -p "${_logdir}" - _data="${datadir}/${dset}/dumped_files" - key_file=${_data}/feats.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - _opt= - if [ ! -z "${inference_config}" ]; then - _opt="--config ${inference_config}" - fi - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - echo "Inference log can be found at ${_logdir}/inference.*.log" - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/inference.JOB.log \ - python -m funasr.bin.diar_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/feats.scp,speech,kaldi_ark" \ - --data_path_and_name_and_type "${_data}/profile.scp,profile,kaldi_ark" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --diar_train_config "${exp_model_dir}"/config.yaml \ - --diar_model_file "${exp_model_dir}"/${inference_model} \ - --output_dir "${_logdir}"/output.JOB \ - --mode sond ${_opt} - done -fi - -# Scoring for finetuned model, you may get a DER like: -# oracle_vad | system_vad -# 7.32 | 8.14 -if [ ${stage} -le 9 ] && [ ${stop_stage} -ge 9 ]; then - echo "stage 9: Scoring finetuned models" - if [ ! -e dscore ]; then - git clone https://github.com/nryant/dscore.git - pip install intervaltree - # add intervaltree to setup.py - fi - for dset in ${test_sets}; do - echo "stage 9: Scoring for ${dset}" - diar_exp=${expdir}/${model_dir} - _data="${datadir}/${dset}" - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${diar_exp}/${_inference_tag}/${inference_model}/${dset}" - _logdir="${_dir}/logdir" - cat ${_logdir}/*/labels.txt | sort > ${_dir}/labels.txt - - cmd="python -Wignore script/convert_label_to_rttm.py ${_dir}/labels.txt ${datadir}/${dset}/files_for_dump/org_vad.txt ${_dir}/sys.rttm \ - --ignore_len 10 --no_pbar --smooth_size 83 --vote_prob 0.5 --n_spk 16" - echo ${cmd} - eval ${cmd} - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${_dir}/sys.rttm.ref_vad - OVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${_dir}/sys.rttm.sys_vad - SysVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - echo -e "${inference_model} ${OVAD_DER} ${SysVAD_DER}" | tee -a ${_dir}/results.txt - done -fi - -# In this stage, we need the raw waveform files of Callhome corpus. -# Due to the data license, we can't provide them, please get them additionally. -# And convert the sph files to wav files (use scripts/dump_pipe_wav.py). -# Then find the wav files to construct wav.scp and put it at data/callhome2/wav.scp. -# After iteratively perform SOAP, you will get DER results like: -# iters : oracle_vad | system_vad -# iter_0: 9.58 | 10.46 -# iter_1: 9.22 | 10.15 -# iter_2: 9.21 | 10.14 -# iter_3: 9.30 | 10.24 -# iter_4: 9.29 | 10.23 -if [ ${stage} -le 10 ] && [ ${stop_stage} -ge 10 ]; then - if [ ! -e ${expdir}/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch ]; then - git lfs install - git clone https://www.modelscope.cn/damo/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch.git - mv speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch ${expdir}/ - fi - - for dset in ${test_sets}; do - echo "stage 10: Evaluating finetuned system on ${dset} set with medfilter_size=83 clustering=EEND-OLA" - sv_exp_dir=${expdir}/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch - diar_exp=${expdir}/${model_dir} - _data="${datadir}/${dset}/dumped_files" - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${diar_exp}/${_inference_tag}/${inference_model}/${dset}" - - for iter in `seq 0 ${told_max_iter}`; do - eval_dir=${_dir}/iter_${iter} - if [ $iter -eq 0 ]; then - prev_rttm=${expdir}/EEND-OLA/sys.rttm - else - prev_rttm=${_dir}/iter_$((${iter}-1))/sys.rttm.sys_vad - fi - echo "Use ${prev_rttm} as system outputs." - - echo "Iteration ${iter}, step 1: extracting non-overlap segments" - cmd="python -Wignore script/extract_nonoverlap_segments.py ${datadir}/${dset}/wav.scp \ - $prev_rttm ${eval_dir}/nonoverlap_segs/ --min_dur 0.1 --max_spk_num 16 --no_pbar --sr 8000" - # echo ${cmd} - eval ${cmd} - - echo "Iteration ${iter}, step 2: make data directory" - mkdir -p ${eval_dir}/data - find `pwd`/${eval_dir}/nonoverlap_segs/ -iname "*.wav" | sort > ${eval_dir}/data/wav.flist - awk -F'[/.]' '{print $(NF-1),$0}' ${eval_dir}/data/wav.flist > ${eval_dir}/data/wav.scp - awk -F'[/.]' '{print $(NF-1),$(NF-2)}' ${eval_dir}/data/wav.flist > ${eval_dir}/data/utt2spk - cp $prev_rttm ${eval_dir}/data/sys.rttm - home_path=`pwd` - - echo "Iteration ${iter}, step 3: calc x-vector for each utt" - key_file=${eval_dir}/data/wav.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - _logdir=${eval_dir}/data/xvecs - mkdir -p ${_logdir} - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/sv_inference.JOB.log \ - python -m funasr.bin.sv_inference_launch \ - --njob ${njob} \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${key_file},speech,sound" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --sv_train_config ${sv_exp_dir}/sv.yaml \ - --sv_model_file ${sv_exp_dir}/sv.pth \ - --output_dir "${_logdir}"/output.JOB - cat ${_logdir}/output.*/xvector.scp | sort > ${eval_dir}/data/utt2xvec - - echo "Iteration ${iter}, step 4: dump x-vector record" - awk '{print $1}' ${_data}/feats.scp > ${eval_dir}/data/idx - python script/dump_speaker_profiles.py --dir ${eval_dir}/data \ - --out ${eval_dir}/global_n16 --n_spk 16 --no_pbar --emb_type global - spk_profile=${eval_dir}/global_n16_parts00_xvec.scp - - echo "Iteration ${iter}, step 5: perform NN diarization" - _logdir=${eval_dir}/diar - mkdir -p ${_logdir} - key_file=${_data}/feats.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - _opt= - if [ ! -z "${inference_config}" ]; then - _opt="--config ${inference_config}" - fi - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - echo "Inference log can be found at ${_logdir}/inference.*.log" - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/inference.JOB.log \ - python -m funasr.bin.diar_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/feats.scp,speech,kaldi_ark" \ - --data_path_and_name_and_type "${spk_profile},profile,kaldi_ark" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --diar_train_config ${diar_exp}/config.yaml \ - --diar_model_file ${diar_exp}/${inference_model} \ - --output_dir "${_logdir}"/output.JOB \ - --mode sond ${_opt} - - echo "Iteration ${iter}, step 6: calc diarization results" - cat ${_logdir}/output.*/labels.txt | sort > ${eval_dir}/labels.txt - - cmd="python -Wignore script/convert_label_to_rttm.py ${eval_dir}/labels.txt ${datadir}/${dset}/files_for_dump/org_vad.txt ${eval_dir}/sys.rttm \ - --ignore_len 10 --no_pbar --smooth_size 83 --vote_prob 0.5 --n_spk 16" - # echo ${cmd} - eval ${cmd} - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${eval_dir}/sys.rttm.ref_vad - OVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${eval_dir}/sys.rttm.sys_vad - SysVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - echo -e "${inference_model}/iter_${iter} ${OVAD_DER} ${SysVAD_DER}" | tee -a ${eval_dir}/results.txt - done - - echo "Done." - done -fi diff --git a/egs/callhome/TOLD/soap/path.sh b/egs/callhome/TOLD/soap/path.sh deleted file mode 100644 index 5721f3f48..000000000 --- a/egs/callhome/TOLD/soap/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH \ No newline at end of file diff --git a/egs/callhome/TOLD/soap/run.sh b/egs/callhome/TOLD/soap/run.sh deleted file mode 100644 index 63b2e4690..000000000 --- a/egs/callhome/TOLD/soap/run.sh +++ /dev/null @@ -1,991 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# This recipe aims at reimplement the results of SOND on Callhome corpus which is represented in -# [1] TOLD: A Novel Two-stage Overlap-aware Framework for Speaker Diarization, ICASSP 2023 -# You can also use it on other dataset such AliMeeting to reproduce the results in -# [2] Speaker Overlap-aware Neural Diarization for Multi-party Meeting Analysis, EMNLP 2022 -# We recommend you run this script stage by stage. - -# This recipe includes: -# 1. simulating data with switchboard and NIST. -# 2. training the model from scratch for 3 stages: -# 2-1. pre-train on simu_swbd_sre -# 2-2. train on simu_swbd_sre -# 2-3. finetune on callhome1 -# 3. evaluating model with the results from the first stage EEND-OLA, -# Finally, you will get a similar DER result claimed in the paper. - -# environment configuration -# path/to/kaldi -kaldi_root= - -if [ -z "${kaldi_root}" ]; then - echo "We need kaldi to prepare dataset, extract fbank features, please install kaldi first and set kaldi_root." - echo "Kaldi installation guide can be found at https://kaldi-asr.org/" - exit; -fi - -if [ ! -e local ]; then - ln -s ${kaldi_root}/egs/callhome_diarization/v2/local ./local -fi - -if [ ! -e utils ]; then - ln -s ${kaldi_root}/egs/callhome_diarization/v2/utils ./utils -fi - -# path to Switchboard and NIST including: -# LDC98S75, LDC99S79, LDC2002S06, LDC2001S13, LDC2004S07 -data_root= -if [ -z "${data_root}" ]; then - echo "We need Switchboard and NIST to simulate data for pretraining." - echo "If you can't get them, please use 'finetune.sh' to finetune a pretrained model." - exit; -fi - -# path/to/NIST/LDC2001S97 -callhome_root= -if [ -z "${callhome_root}" ]; then - echo "We need callhome corpus for training." - echo "If you want inference only, please refer https://www.modelscope.cn/models/damo/speech_diarization_sond-en-us-callhome-8k-n16k4-pytorch/summary" - exit; -fi - - -# machines configuration -gpu_devices="4,5,6,7" # for V100-16G, use 4 GPUs -gpu_num=4 -count=1 - -# general configuration -stage=0 -stop_stage=19 -# number of jobs for data process -nj=16 -sr=8000 - -# experiment configuration -lang=en -feats_type=fbank -datadir=data -dumpdir=dump -expdir=exp -train_cmd=utils/run.pl - -# training related -tag="" -train_set=simu_swbd_sre -valid_set=callhome1 -train_config=conf/EAND_ResNet34_SAN_L4N512_None_FFN_FSMN_L6N512_bce_dia_loss_01.yaml -token_list=${datadir}/token_list/powerset_label_n16k4.txt -init_param= -freeze_param= - -# inference related -inference_model=valid.der.ave_5best.pb -inference_config=conf/basic_inference.yaml -inference_tag="" -test_sets="callhome2" -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# number of jobs for inference -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=4 -infer_cmd=utils/run.pl -told_max_iter=4 - -. utils/parse_options.sh || exit 1; - -model_dir="$(basename "${train_config}" .yaml)_${feats_type}_${lang}${tag}" - -# you can set gpu num for decoding here -gpuid_list=$gpu_devices # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -# Prepare datasets -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - # 1. Prepare a collection of NIST SRE data. - echp "Stage 0: Prepare a collection of NIST SRE data." - - local/make_sre.sh $data_root ${datadir} - - # 2.a Prepare SWB. - local/make_swbd2_phase1.pl ${data_root}/LDC98S75 \ - ${datadir}/swbd2_phase1_train - local/make_swbd2_phase2.pl $data_root/LDC99S79 \ - ${datadir}/swbd2_phase2_train - local/make_swbd2_phase3.pl $data_root/LDC2002S06 \ - ${datadir}/swbd2_phase3_train - local/make_swbd_cellular1.pl $data_root/LDC2001S13 \ - ${datadir}/swbd_cellular1_train - local/make_swbd_cellular2.pl $data_root/LDC2004S07 \ - ${datadir}/swbd_cellular2_train - # 2.b combine all swbd data. - utils/combine_data.sh ${datadir}/swbd \ - ${datadir}/swbd2_phase1_train ${datadir}/swbd2_phase2_train ${datadir}/swbd2_phase3_train \ - ${datadir}/swbd_cellular1_train ${datadir}/swbd_cellular2_train - utils/validate_data_dir.sh --no-text --no-feats ${datadir}/swbd - utils/fix_data_dir.sh ${datadir}/swbd - - utils/combine_data.sh ${datadir}/swbd_sre ${datadir}/swbd ${datadir}/sre - utils/validate_data_dir.sh --no-text --no-feats ${datadir}/swbd_sre - utils/fix_data_dir.sh ${datadir}/swbd_sre - - # 3. Prepare the Callhome portion of NIST SRE 2000. - local/make_callhome.sh ${callhome_root} ${datadir}/ - - # 4. split ref.rttm - for dset in callhome1 callhome2; do - rm -rf ${datadir}/${dset}/ref.rttm - for name in `awk '{print $1}' ${datadir}/${dset}/wav.scp`; do - grep ${name} ${datadir}/callhome/fullref.rttm >> ${datadir}/${dset}/ref.rttm; - done - - # filter out records which don't have rttm labels. - awk '{print $2}' ${datadir}/${dset}/ref.rttm | sort | uniq > ${datadir}/${dset}/uttid - mv ${datadir}/${dset}/wav.scp ${datadir}/${dset}/wav.scp.bak - awk '{if (NR==FNR){a[$1]=1}else{if (a[$1]==1){print $0}}}' ${datadir}/${dset}/uttid ${datadir}/${dset}/wav.scp.bak > ${datadir}/${dset}/wav.scp - mkdir ${datadir}/${dset}/raw - mv ${datadir}/${dset}/{reco2num_spk,segments,spk2utt,utt2spk,uttid,wav.scp.bak} ${datadir}/${dset}/raw/ - awk '{print $1,$1}' ${datadir}/${dset}/wav.scp > ${datadir}/${dset}/utt2spk - done - -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "Stage 1: Dump sph file to wav" - export PATH=${kaldi_root}/tools/sph2pipe/:${PATH} - if [ ! -f ${kaldi_root}/tools/sph2pipe/sph2pipe ]; then - echo "Can not find sph2pipe in ${kaldi_root}/tools/sph2pipe/," - echo "please install sph2pipe and put it in the right place." - exit; - fi - - for dset in callhome1 callhome2 swbd_sre; do - echo "Stage 1: start to dump ${dset}." - mv ${datadir}/${dset}/wav.scp ${datadir}/${dset}/sph.scp - - mkdir -p ${dumpdir}/${dset}/wavs - python -Wignore script/dump_pipe_wav.py ${datadir}/${dset}/sph.scp ${dumpdir}/${dset}/wavs \ - --sr ${sr} --nj ${nj} --no_pbar - find `pwd`/${dumpdir}/${dset}/wavs -iname "*.wav" | sort | awk -F'[/.]' '{print $(NF-1),$0}' > ${datadir}/${dset}/wav.scp - done -fi - -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "Stage 2: Extract non-overlap segments from callhome dataset" - for dset in callhome1 callhome2; do - echo "Stage 2: Extracting non-overlap segments for "${dset} - mkdir -p ${dumpdir}/${dset}/nonoverlap_0s - python -Wignore script/extract_nonoverlap_segments.py \ - ${datadir}/${dset}/wav.scp ${datadir}/${dset}/ref.rttm ${dumpdir}/${dset}/nonoverlap_0s \ - --min_dur 0.1 --max_spk_num 8 --sr ${sr} --no_pbar --nj ${nj} - - mkdir -p ${datadir}/${dset}/nonoverlap_0s - find ${dumpdir}/${dset}/nonoverlap_0s/ -iname "*.wav" | sort | awk -F'[/.]' '{print $(NF-1),$0}' > ${datadir}/${dset}/nonoverlap_0s/wav.scp - awk -F'[/.]' '{print $(NF-1),$(NF-2)}' ${datadir}/${dset}/nonoverlap_0s/wav.scp > ${datadir}/${dset}/nonoverlap_0s/utt2spk - echo "Done." - done -fi - -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "Stage 3: Generate concatenated waveforms for each speaker in switchboard, sre and callhome1" - mkdir swb_sre_resources - wget --no-check-certificate -P swb_sre_resources/ https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/Speaker_Diar/swb_sre_resources/noise.scp - wget --no-check-certificate -P swb_sre_resources/ https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/Speaker_Diar/swb_sre_resources/swbd_sre_tdnn_vad_segments - mkdir ${datadir}/swbd_sre/none_silence - ln -s swb_sre_resources/swbd_sre_tdnn_vad_segments ${datadir}/swbd_sre/none_silence/segments - cp ${datadir}/swbd_sre/wav.scp ${datadir}/swbd_sre/none_silence/reco.scp - - mkdir -p ${dumpdir}/swbd_sre/none_silence - python -Wignore script/remove_silence_from_wav.py \ - ${datadir}/swbd_sre/none_silence ${dumpdir}/swbd_sre/none_silence --nj ${nj} --sr 8000 - # The utterance number in wav.scp may be different from reco.scp, - # since some recordings don't appear in the segments file, may due to the VAD - echo "find wavs_nosil" - find `pwd`/${dumpdir}/swbd_sre/none_silence -iname "*.wav" | sort | awk -F'[/.]' '{print $(NF-1),$0}' > ${datadir}/swbd_sre/none_silence/wav.scp - echo "concat spk segments" - - ln -s ${datadir}/swbd_sre/utt2spk ${datadir}/swbd_sre/none_silence/utt2spk - - echo "Stage 3: Start to concatnate waveforms for speakers in switchboard and sre" - python -Wignore egs/callhome/concat_spk_segs.py \ - ${datadir}/swbd_sre/none_silence ${dumpdir}/swbd_sre/spk_wavs --nj ${nj} --sr 8000 - - echo "Stage 3: Start to concatnate waveforms for speakers in callhome1" - # only use callhome1 as training set to simulate data - python -Wignore egs/callhome/concat_spk_segs.py \ - ${datadir}/callhome1/nonoverlap_0s ${dumpdir}/callhome1/spk_wavs --nj ${nj} --sr 8000 - -fi - -# simulate data with the pattern of callhome1 -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "Stage 4: Start to simulate recordings." - - if [ ! -e ${dumpdir}/musan ]; then - echo "Stage 4-1: Start to download MUSAN noises from openslr" - wget --no-check-certificate -P ${dumpdir}/musan https://www.openslr.org/resources/17/musan.tar.gz - tar -C ${dumpdir}/musan -xvf ${dumpdir}/musan/musan.tar.gz - fi - - if [ ! -e ${dumpdir}/rirs ]; then - echo "Stage 4-2: Start to download RIRs from openslr" - wget --no-check-certificate -P ${dumpdir}/rirs https://www.openslr.org/resources/28/rirs_noises.zip - unzip ${dumpdir}/rirs/rirs_noises.zip -d ${dumpdir}/rirs - fi - - mkdir -p ${datadir}/simu_swbd_sre - # only use background noises instead of all noises in MUSAN. - sed "s:/path/to/musan/:`pwd`/${dumpdir}/musan/:g" swb_sre_resources/noise.scp > ${datadir}/simu_swbd_sre/noise.scp - # use simulated RIRs. - find `pwd`/${dumpdir}/rirs/RIRS_NOISES/simulated_rirs/ -iname "*.wav" | sort | awk -F'[/.]' '{print $(NF-3)"-"$(NF-1), $0}' > ${datadir}/simu_swbd_sre/rirs.scp - cp ${datadir}/callhome1/{ref.rttm,reco2num_spk} ${datadir}/simu_swbd_sre - find `pwd`/${dumpdir}/swbd_sre/spk_wavs -iname "*.wav" | sort | awk -F'[/.]' '{print $(NF-1),$0}' > ${datadir}/simu_swbd_sre/spk2wav.scp - - echo "Stage 4-3: Start to simulate recordings with variable speakers as Callhome1 patterns." - # average duration of callhome is 125s, about 20 chunk with silence - # simulating 22500 (45 jobs x 500 reco) recordings, without random_assign and random_shift_interval - for i in $(seq 0 44); do - cmd="python -Wignore egs/callhome/simu_whole_recordings.py \ - ${datadir}/simu_swbd_sre \ - ${dumpdir}/simu_swbd_sre/wavs \ - --corpus_name simu_swbd_sre --task_id $i --total_mix 500 --sr 8000 --no_bar &" - echo $cmd - eval $cmd - done - wait; - - echo "Stage 4-4: Start to simulate recordings with fixed speakers as Callhome1 patterns." - # simulating 30000 (30 jobs x 1000 reco) recordings for different speaker number 2, 3, 4 - for n_spk in $(seq 2 4); do - mkdir -p /home/neo.dzh/corpus/simu_swbd_sre/${n_spk}spk_wavs - for i in $(seq 0 29); do - cmd="python -Wignore egs/callhome/simu_whole_recordings.py \ - ${datadir}/simu_swbd_sre \ - ${dumpdir}/simu_swbd_sre/${n_spk}spk_wavs \ - --random_assign_spk --random_interval --spk_num ${n_spk} \ - --corpus_name simu_swbd_sre --task_id $i --total_mix 1000 --sr 8000 --no_bar &" - echo $cmd - eval $cmd - done - wait; - done - - find `pwd`/${dumpdir}/simu_swbd_sre -iname "*.wav" | sort | awk -F'[/.]' '{print $(NF-1),$0}' > ${datadir}/simu_swbd_sre/wav.scp - awk '{print $1,$1}' ${datadir}/simu_swbd_sre/wav.scp > ${datadir}/simu_swbd_sre/utt2spk - find `pwd`/${dumpdir}/simu_swbd_sre -iname "*.rttm" | sort | awk -F'[/.]' '{print $(NF-1),$0}' > ${datadir}/simu_swbd_sre/rttm.scp -fi - -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "Stage 5: Generate fbank features" - home_path=`pwd` - cd ${kaldi_root}/egs/callhome_diarization/v2 || exit - - . ./cmd.sh - . ./path.sh - - for dset in simu_swbd_sre callhome1 callhome2; do - steps/make_fbank.sh --write-utt2num-frames true --fbank-config conf/fbank.conf --nj ${nj} --cmd "$train_cmd" \ - ${datadir}/${dset} ${expdir}/make_fbank/${dset} ${dumpdir}/${dset}/fbank - utils/fix_data_dir.sh ${datadir}/${dset} - done - - for dset in swbd_sre/none_silence callhome1/nonoverlap_0s callhome2/nonoverlap_0s; do - steps/make_fbank.sh --write-utt2num-frames true --fbank-config conf/fbank.conf --nj ${nj} --cmd "$train_cmd" \ - ${datadir}/${dset} ${expdir}/make_fbank/${dset} ${dumpdir}/${dset}/fbank - utils/fix_data_dir.sh ${datadir}/${dset} - done - - cd ${home_path} || exit -fi - -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "Stage 6: Extract speaker embeddings." - sv_exp_dir=exp/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch - - if [ ! -e ${sv_exp_dir} ]; then - echo "start to download sv models" - git lfs install - git clone https://www.modelscope.cn/damo/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch.git - mv speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch ${expdir}/ - echo "Done." - fi - - sed "s/input_size: null/input_size: 80/g" ${sv_exp_dir}/sv.yaml > ${sv_exp_dir}/sv_fbank.yaml - for dset in swbd_sre/none_silence callhome1/nonoverlap_0s callhome2/nonoverlap_0s; do - key_file=${datadir}/${dset}/feats.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - _logdir=${dumpdir}/${dset}/xvecs - mkdir -p ${_logdir} - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/sv_inference.JOB.log \ - python -m funasr.bin.sv_inference_launch \ - --batch_size 1 \ - --njob ${njob} \ - --ngpu "${_ngpu}" \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${key_file},speech,kaldi_ark" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --sv_train_config ${sv_exp_dir}/sv_fbank.yaml \ - --sv_model_file ${sv_exp_dir}/sv.pth \ - --output_dir "${_logdir}"/output.JOB - cat ${_logdir}/output.*/xvector.scp | sort > ${datadir}/${dset}/utt2xvec - done - -fi - -if [ ${stage} -le 7 ] && [ ${stop_stage} -ge 7 ]; then - echo "Stage 7: Generate label files." - - for dset in simu_swbd_sre callhome1 callhome2; do - echo "Stage 7: Generate labels for ${dset}." - python -Wignore script/calc_real_meeting_frame_labels.py \ - ${datadir}/${dset} ${dumpdir}/${dset}/labels \ - --n_spk 8 --frame_shift 0.01 --nj 16 --sr 8000 - find `pwd`/${dumpdir}/${dset}/labels/ -iname "*.lbl.mat" | awk -F'[/.]' '{print $(NF-2),$0}' | sort > ${datadir}/${dset}/labels.scp - done - -fi - -if [ ${stage} -le 8 ] && [ ${stop_stage} -ge 8 ]; then - echo "Stage 8: Make training and evaluation files." - - # dump simulated data in training mode (randomly shuffle the speaker order). - data_dir=${datadir}/simu_swbd_sre/files_for_dump - mkdir ${data_dir} - cp ${datadir}/simu_swbd_sre/{feats.scp,labels.scp} ${data_dir}/ - cp ${datadir}/swbd_sre/none_silence/{utt2spk,utt2xvec,utt2num_frames} ${data_dir}/ - # dump data with the window length of 1600 frames and hop length of 400 frames. - echo "Stage 8: start to dump for simu_swbd_sre." - for i in $(seq 0 49); do - cmd="python -Wignore script/dump_meeting_chunks.py --dir ${data_dir} \ - --out ${dumpdir}/simu_swbd_sre/dumped_files/data --n_spk 16 --no_pbar --sr 8000 --mode train \ - --chunk_size 1600 --chunk_shift 400 \ - --task_id ${i} --task_size 2250 &" - echo $cmd - eval $cmd - done - wait; - mkdir -p ${datadir}/simu_swbd_sre/dumped_files - cat ${dumpdir}/simu_swbd_sre/dumped_files/data_parts*_feat.scp | sort > ${datadir}/simu_swbd_sre/dumped_files/feats.scp - cat ${dumpdir}/simu_swbd_sre/dumped_files/data_parts*_xvec.scp | sort > ${datadir}/simu_swbd_sre/dumped_files/profile.scp - cat ${dumpdir}/simu_swbd_sre/dumped_files/data_parts*_label.scp | sort > ${datadir}/simu_swbd_sre/dumped_files/label.scp - mkdir -p ${expdir}/simu_swbd_sre_states - awk '{print $1,"1600"}' ${datadir}/simu_swbd_sre/dumped_files/feats.scp | shuf > ${expdir}/simu_swbd_sre_states/speech_shape - - # dump callhome1 data in training mode. - data_dir=${datadir}/callhome1/files_for_dump - mkdir ${data_dir} - # filter out zero duration segments - LC_ALL=C awk '{if ($5 > 0){print $0}}' ${datadir}/callhome1/ref.rttm > ${data_dir}/ref.rttm - cp ${datadir}/callhome1/{feats.scp,labels.scp} ${data_dir}/ - cp ${datadir}/callhome1/nonoverlap_0s/{utt2spk,utt2xvec,utt2num_frames} ${data_dir}/ - - echo "Stage 8: start to dump for callhome1." - python -Wignore script/dump_meeting_chunks.py --dir ${data_dir} \ - --out ${dumpdir}/callhome1/dumped_files/data --n_spk 16 --no_pbar --sr 8000 --mode train \ - --chunk_size 1600 --chunk_shift 400 --add_mid_to_speaker true - - mkdir -p ${datadir}/callhome1/dumped_files - cat ${dumpdir}/callhome1/dumped_files/data_parts*_feat.scp | sort > ${datadir}/callhome1/dumped_files/feats.scp - cat ${dumpdir}/callhome1/dumped_files/data_parts*_xvec.scp | sort > ${datadir}/callhome1/dumped_files/profile.scp - cat ${dumpdir}/callhome1/dumped_files/data_parts*_label.scp | sort > ${datadir}/callhome1/dumped_files/label.scp - mkdir -p ${expdir}/callhome1_states - awk '{print $1,"1600"}' ${datadir}/callhome1/dumped_files/feats.scp | shuf > ${expdir}/callhome1_states/speech_shape - python -Wignore script/convert_rttm_to_seg_file.py --rttm_scp ${data_dir}/ref.rttm --seg_file ${data_dir}/org_vad.txt - - # dump callhome2 data in test mode. - data_dir=${datadir}/callhome2/files_for_dump - mkdir ${data_dir} - # filter out zero duration segments - LC_ALL=C awk '{if ($5 > 0){print $0}}' ${datadir}/callhome2/ref.rttm > ${data_dir}/ref.rttm - cp ${datadir}/callhome2/{feats.scp,labels.scp} ${data_dir}/ - cp ${datadir}/callhome2/nonoverlap_0s/{utt2spk,utt2xvec,utt2num_frames} ${data_dir}/ - - echo "Stage 8: start to dump for callhome2." - python -Wignore script/dump_meeting_chunks.py --dir ${data_dir} \ - --out ${dumpdir}/callhome2/dumped_files/data --n_spk 16 --no_pbar --sr 8000 --mode test \ - --chunk_size 1600 --chunk_shift 400 --add_mid_to_speaker true - - mkdir -p ${datadir}/callhome2/dumped_files - cat ${dumpdir}/callhome2/dumped_files/data_parts*_feat.scp | sort > ${datadir}/callhome2/dumped_files/feats.scp - cat ${dumpdir}/callhome2/dumped_files/data_parts*_xvec.scp | sort > ${datadir}/callhome2/dumped_files/profile.scp - cat ${dumpdir}/callhome2/dumped_files/data_parts*_label.scp | sort > ${datadir}/callhome2/dumped_files/label.scp - mkdir -p ${expdir}/callhome2_states - awk '{print $1,"1600"}' ${datadir}/callhome2/dumped_files/feats.scp | shuf > ${expdir}/callhome2_states/speech_shape - python -Wignore script/convert_rttm_to_seg_file.py --rttm_scp ${data_dir}/ref.rttm --seg_file ${data_dir}/org_vad.txt - -fi - -# Training Stage, phase 1, pretraining on simulated data with frozen encoder parameters. -# This training may cost about 1.8 days. -if [ ${stage} -le 10 ] && [ ${stop_stage} -ge 10 ]; then - echo "stage 10: training phase 1, pretraining on simulated data" - world_size=$gpu_num # run on one machine - mkdir -p ${expdir}/${model_dir} - mkdir -p ${expdir}/${model_dir}/log - mkdir -p /tmp/${model_dir} - INIT_FILE=/tmp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_opt="" - if [ ! -z "${init_param}" ]; then - init_opt="--init_param ${init_param}" - echo ${init_opt} - fi - - freeze_opt="" - if [ ! -z "${freeze_param}" ]; then - freeze_opt="--freeze_param ${freeze_param}" - echo ${freeze_opt} - fi - - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $gpu_devices | cut -d',' -f$[$i+1]) - python -m funasr.bin.diar_train \ - --gpu_id $gpu_id \ - --use_preprocessor false \ - --token_type char \ - --token_list $token_list \ - --train_data_path_and_name_and_type ${datadir}/${train_set}/dumped_files/feats.scp,speech,kaldi_ark \ - --train_data_path_and_name_and_type ${datadir}/${train_set}/dumped_files/profile.scp,profile,kaldi_ark \ - --train_data_path_and_name_and_type ${datadir}/${train_set}/dumped_files/label.scp,binary_labels,kaldi_ark \ - --train_shape_file ${expdir}/${train_set}_states/speech_shape \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/feats.scp,speech,kaldi_ark \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/profile.scp,profile,kaldi_ark \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/label.scp,binary_labels,kaldi_ark \ - --valid_shape_file ${expdir}/${valid_set}_states/speech_shape \ - --init_param ${expdir}/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch/sv.pth:encoder:encoder \ - --unused_parameters true \ - --freeze_param encoder \ - ${init_opt} \ - ${freeze_opt} \ - --ignore_init_mismatch true \ - --resume true \ - --output_dir ${expdir}/${model_dir} \ - --config $train_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${expdir}/${model_dir}/log/train.log.$i 2>&1 - } & - done - echo "Training log can be found at ${expdir}/${model_dir}/log/train.log.*" - wait -fi - -# evaluate for pretrained model -if [ ${stage} -le 11 ] && [ ${stop_stage} -ge 11 ]; then - echo "stage 11: evaluation for phase-1 model." - for dset in ${test_sets}; do - echo "Processing for $dset" - exp_model_dir=${expdir}/${model_dir} - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${exp_model_dir}/${_inference_tag}/${inference_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "WARNING: ${_dir} is already exists." - fi - mkdir -p "${_logdir}" - _data="${datadir}/${dset}/dumped_files" - key_file=${_data}/feats.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - _opt= - if [ ! -z "${inference_config}" ]; then - _opt="--config ${inference_config}" - fi - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - echo "Inference log can be found at ${_logdir}/inference.*.log" - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/inference.JOB.log \ - python -m funasr.bin.diar_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/feats.scp,speech,kaldi_ark" \ - --data_path_and_name_and_type "${_data}/profile.scp,profile,kaldi_ark" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --diar_train_config "${exp_model_dir}"/config.yaml \ - --diar_model_file "${exp_model_dir}"/"${inference_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode sond ${_opt} - done -fi - -# Scoring for pretrained model, you may get a DER like 13.29 16.54 -# 13.29: with oracle VAD, 16.54: with only SOND outputs, aka, system VAD. -if [ ${stage} -le 12 ] && [ ${stop_stage} -ge 12 ]; then - echo "stage 12: Scoring phase-1 models" - if [ ! -e dscore ]; then - git clone https://github.com/nryant/dscore.git - # add intervaltree to setup.py - fi - for dset in ${test_sets}; do - echo "stage 12: Scoring for ${dset}" - diar_exp=${expdir}/${model_dir} - _data="${datadir}/${dset}" - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${diar_exp}/${_inference_tag}/${inference_model}/${dset}" - _logdir="${_dir}/logdir" - cat ${_logdir}/*/labels.txt | sort > ${_dir}/labels.txt - - cmd="python -Wignore script/convert_label_to_rttm.py ${_dir}/labels.txt ${datadir}/${dset}/files_for_dump/org_vad.txt ${_dir}/sys.rttm \ - --ignore_len 10 --no_pbar --smooth_size 83 --vote_prob 0.5 --n_spk 16" - # echo ${cmd} - eval ${cmd} - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${_dir}/sys.rttm.ref_vad - OVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${_dir}/sys.rttm.sys_vad - SysVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - echo -e "${inference_model} ${OVAD_DER} ${SysVAD_DER}" | tee -a ${_dir}/results.txt - done -fi - -# Training Stage, phase 2, training on simulated data without frozen parameters. -# For V100-16G, please set batch_size to 8 in the config, and use 4 GPU to train the model with options like --gpu_devices 4,5,6,7 --gpu_num 4. -# For V100-32G, please set batch_size to 16 in the config, and use 2 GPU to train the model with options like --gpu_devices 4,5,6,7 --gpu_num 2. -# This training may cost about 3.5 days. -if [ ${stage} -le 13 ] && [ ${stop_stage} -ge 13 ]; then - echo "stage 13: training phase 2, training on simulated data" - world_size=$gpu_num # run on one machine - mkdir -p ${expdir}/${model_dir}_phase2 - mkdir -p ${expdir}/${model_dir}_phase2/log - mkdir -p /tmp/${model_dir}_phase2 - INIT_FILE=/tmp/${model_dir}_phase2/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_opt="" - if [ ! -z "${init_param}" ]; then - init_opt="--init_param ${init_param}" - echo ${init_opt} - fi - - freeze_opt="" - if [ ! -z "${freeze_param}" ]; then - freeze_opt="--freeze_param ${freeze_param}" - echo ${freeze_opt} - fi - - phase2_config="$(dirname "${train_config}")/$(basename "${train_config}" .yaml)_phase2.yaml" - - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $gpu_devices | cut -d',' -f$[$i+1]) - python -m funasr.bin.diar_train \ - --gpu_id $gpu_id \ - --use_preprocessor false \ - --token_type char \ - --token_list $token_list \ - --train_data_path_and_name_and_type ${datadir}/${train_set}/dumped_files/feats.scp,speech,kaldi_ark \ - --train_data_path_and_name_and_type ${datadir}/${train_set}/dumped_files/profile.scp,profile,kaldi_ark \ - --train_data_path_and_name_and_type ${datadir}/${train_set}/dumped_files/label.scp,binary_labels,kaldi_ark \ - --train_shape_file ${expdir}/${train_set}_states/speech_shape \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/feats.scp,speech,kaldi_ark \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/profile.scp,profile,kaldi_ark \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/label.scp,binary_labels,kaldi_ark \ - --valid_shape_file ${expdir}/${valid_set}_states/speech_shape \ - --init_param exp/${model_dir}/valid.der.ave_5best.pb \ - --unused_parameters true \ - ${init_opt} \ - ${freeze_opt} \ - --ignore_init_mismatch true \ - --resume true \ - --output_dir ${expdir}/${model_dir}_phase2 \ - --config ${phase2_config} \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${expdir}/${model_dir}_phase2/log/train.log.$i 2>&1 - } & - done - echo "Training log can be found at ${expdir}/${model_dir}_phase2/log/train.log.*" - wait -fi - -# evaluate for phase-2 model -if [ ${stage} -le 14 ] && [ ${stop_stage} -ge 14 ]; then - echo "stage 14: evaluation for phase-2 model ${inference_model}." - for dset in ${test_sets}; do - echo "Processing for $dset" - exp_model_dir=${expdir}/${model_dir}_phase2 - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${exp_model_dir}/${_inference_tag}/${inference_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "WARNING: ${_dir} is already exists." - fi - mkdir -p "${_logdir}" - _data="${datadir}/${dset}/dumped_files" - key_file=${_data}/feats.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - _opt= - if [ ! -z "${inference_config}" ]; then - _opt="--config ${inference_config}" - fi - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - echo "Inference log can be found at ${_logdir}/inference.*.log" - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/inference.JOB.log \ - python -m funasr.bin.diar_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/feats.scp,speech,kaldi_ark" \ - --data_path_and_name_and_type "${_data}/profile.scp,profile,kaldi_ark" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --diar_train_config "${exp_model_dir}"/config.yaml \ - --diar_model_file "${exp_model_dir}"/${inference_model} \ - --output_dir "${_logdir}"/output.JOB \ - --mode sond ${_opt} - done -fi - -# Scoring for pretrained model, you may get a DER like 11.54 15.41 -# 11.54: with oracle VAD, 15.41: with only SOND outputs, aka, system VAD. -if [ ${stage} -le 15 ] && [ ${stop_stage} -ge 15 ]; then - echo "stage 15: Scoring phase-2 models" - if [ ! -e dscore ]; then - git clone https://github.com/nryant/dscore.git - # add intervaltree to setup.py - fi - for dset in ${test_sets}; do - echo "stage 15: Scoring for ${dset}" - diar_exp=${expdir}/${model_dir}_phase2 - _data="${datadir}/${dset}" - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${diar_exp}/${_inference_tag}/${inference_model}/${dset}" - _logdir="${_dir}/logdir" - cat ${_logdir}/*/labels.txt | sort > ${_dir}/labels.txt - - cmd="python -Wignore script/convert_label_to_rttm.py ${_dir}/labels.txt ${datadir}/${dset}/files_for_dump/org_vad.txt ${_dir}/sys.rttm \ - --ignore_len 10 --no_pbar --smooth_size 83 --vote_prob 0.5 --n_spk 16" - # echo ${cmd} - eval ${cmd} - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${_dir}/sys.rttm.ref_vad - OVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${_dir}/sys.rttm.sys_vad - SysVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - echo -e "${inference_model} ${OVAD_DER} ${SysVAD_DER}" | tee -a ${_dir}/results.txt - done -fi - - -# Finetune Stage, phase 3, training on callhom1 training set -if [ ${stage} -le 16 ] && [ ${stop_stage} -ge 16 ]; then - echo "stage 16: training phase 3, finetuing on callhome1 real data" - world_size=$gpu_num # run on one machine - mkdir -p ${expdir}/${model_dir}_phase3 - mkdir -p ${expdir}/${model_dir}_phase3/log - mkdir -p /tmp/${model_dir}_phase3 - INIT_FILE=/tmp/${model_dir}_phase3/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_opt="" - if [ ! -z "${init_param}" ]; then - init_opt="--init_param ${init_param}" - echo ${init_opt} - fi - - freeze_opt="" - if [ ! -z "${freeze_param}" ]; then - freeze_opt="--freeze_param ${freeze_param}" - echo ${freeze_opt} - fi - - phase3_config="$(dirname "${train_config}")/$(basename "${train_config}" .yaml)_phase3.yaml" - - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $gpu_devices | cut -d',' -f$[$i+1]) - python -m funasr.bin.diar_train \ - --gpu_id $gpu_id \ - --use_preprocessor false \ - --token_type char \ - --token_list $token_list \ - --train_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/feats.scp,speech,kaldi_ark \ - --train_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/profile.scp,profile,kaldi_ark \ - --train_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/label.scp,binary_labels,kaldi_ark \ - --train_shape_file ${expdir}/${valid_set}_states/speech_shape \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/feats.scp,speech,kaldi_ark \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/profile.scp,profile,kaldi_ark \ - --valid_data_path_and_name_and_type ${datadir}/${valid_set}/dumped_files/label.scp,binary_labels,kaldi_ark \ - --valid_shape_file ${expdir}/${valid_set}_states/speech_shape \ - --init_param exp/${model_dir}_phase2/valid.forward_steps.ave_5best.pb \ - --unused_parameters true \ - ${init_opt} \ - ${freeze_opt} \ - --ignore_init_mismatch true \ - --resume true \ - --output_dir ${expdir}/${model_dir}_phase3 \ - --config ${phase3_config} \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${expdir}/${model_dir}_phase3/log/train.log.$i 2>&1 - } & - done - echo "Training log can be found at ${expdir}/${model_dir}_phase3/log/train.log.*" - wait -fi - -# evaluate for finetuned model -if [ ${stage} -le 17 ] && [ ${stop_stage} -ge 17 ]; then - echo "stage 17: evaluation for finetuned model ${inference_model}." - for dset in ${test_sets}; do - echo "Processing for $dset" - exp_model_dir=${expdir}/${model_dir}_phase3 - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${exp_model_dir}/${_inference_tag}/${inference_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "WARNING: ${_dir} is already exists." - fi - mkdir -p "${_logdir}" - _data="${datadir}/${dset}/dumped_files" - key_file=${_data}/feats.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - _opt= - if [ ! -z "${inference_config}" ]; then - _opt="--config ${inference_config}" - fi - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - echo "Inference log can be found at ${_logdir}/inference.*.log" - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/inference.JOB.log \ - python -m funasr.bin.diar_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/feats.scp,speech,kaldi_ark" \ - --data_path_and_name_and_type "${_data}/profile.scp,profile,kaldi_ark" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --diar_train_config "${exp_model_dir}"/config.yaml \ - --diar_model_file "${exp_model_dir}"/${inference_model} \ - --output_dir "${_logdir}"/output.JOB \ - --mode sond ${_opt} - done -fi - -# average 3 4 5 6 7 epoch -# Scoring for pretrained model, you may get a DER like -# 7.21 8.05 on callhome1 -# 8.31 9.32 on callhome2 -if [ ${stage} -le 18 ] && [ ${stop_stage} -ge 18 ]; then - echo "stage 18: Scoring finetuned models" - if [ ! -e dscore ]; then - git clone https://github.com/nryant/dscore.git - # add intervaltree to setup.py - fi - for dset in ${test_sets}; do - echo "stage 18: Scoring for ${dset}" - diar_exp=${expdir}/${model_dir}_phase3 - _data="${datadir}/${dset}" - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${diar_exp}/${_inference_tag}/${inference_model}/${dset}" - _logdir="${_dir}/logdir" - cat ${_logdir}/*/labels.txt | sort > ${_dir}/labels.txt - - cmd="python -Wignore script/convert_label_to_rttm.py ${_dir}/labels.txt ${datadir}/${dset}/files_for_dump/org_vad.txt ${_dir}/sys.rttm \ - --ignore_len 10 --no_pbar --smooth_size 83 --vote_prob 0.5 --n_spk 16" - echo ${cmd} - eval ${cmd} - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${_dir}/sys.rttm.ref_vad - OVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${_dir}/sys.rttm.sys_vad - SysVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - echo -e "${inference_model} ${OVAD_DER} ${SysVAD_DER}" | tee -a ${_dir}/results.txt - done -fi - - -if [ ${stage} -le 19 ] && [ ${stop_stage} -ge 19 ]; then - for dset in ${test_sets}; do - echo "stage 19: Evaluating phase-3 system on ${dset} set with medfilter_size=83 clustering=EEND-OLA" - sv_exp_dir=${expdir}/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch - diar_exp=${expdir}/${model_dir}_phase3 - _data="${datadir}/${dset}/dumped_files" - _inference_tag="$(basename "${inference_config}" .yaml)${inference_tag}" - _dir="${diar_exp}/${_inference_tag}/${inference_model}/${dset}" - - for iter in `seq 0 ${told_max_iter}`; do - eval_dir=${_dir}/iter_${iter} - if [ $iter -eq 0 ]; then - prev_rttm=${expdir}/EEND-OLA/sys.rttm - else - prev_rttm=${_dir}/iter_$((${iter}-1))/sys.rttm.sys_vad - fi - echo "Use ${prev_rttm} as system outputs." - - echo "Iteration ${iter}, step 1: extracting non-overlap segments" - cmd="python -Wignore script/extract_nonoverlap_segments.py ${datadir}/${dset}/wav.scp \ - $prev_rttm ${eval_dir}/nonoverlap_segs/ --min_dur 0.1 --max_spk_num 16 --no_pbar --sr 8000" - # echo ${cmd} - eval ${cmd} - - echo "Iteration ${iter}, step 2: make data directory" - mkdir -p ${eval_dir}/data - find `pwd`/${eval_dir}/nonoverlap_segs/ -iname "*.wav" | sort > ${eval_dir}/data/wav.flist - awk -F'[/.]' '{print $(NF-1),$0}' ${eval_dir}/data/wav.flist > ${eval_dir}/data/wav.scp - awk -F'[/.]' '{print $(NF-1),$(NF-2)}' ${eval_dir}/data/wav.flist > ${eval_dir}/data/utt2spk - cp $prev_rttm ${eval_dir}/data/sys.rttm - home_path=`pwd` - - echo "Iteration ${iter}, step 3: calc x-vector for each utt" - key_file=${eval_dir}/data/wav.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - _logdir=${eval_dir}/data/xvecs - mkdir -p ${_logdir} - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/sv_inference.JOB.log \ - python -m funasr.bin.sv_inference_launch \ - --njob ${njob} \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${key_file},speech,sound" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --sv_train_config ${sv_exp_dir}/sv.yaml \ - --sv_model_file ${sv_exp_dir}/sv.pth \ - --output_dir "${_logdir}"/output.JOB - cat ${_logdir}/output.*/xvector.scp | sort > ${eval_dir}/data/utt2xvec - - echo "Iteration ${iter}, step 4: dump x-vector record" - awk '{print $1}' ${_data}/feats.scp > ${eval_dir}/data/idx - python script/dump_speaker_profiles.py --dir ${eval_dir}/data \ - --out ${eval_dir}/global_n16 --n_spk 16 --no_pbar --emb_type global - spk_profile=${eval_dir}/global_n16_parts00_xvec.scp - - echo "Iteration ${iter}, step 5: perform NN diarization" - _logdir=${eval_dir}/diar - mkdir -p ${_logdir} - key_file=${_data}/feats.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - _opt= - if [ ! -z "${inference_config}" ]; then - _opt="--config ${inference_config}" - fi - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - echo "Inference log can be found at ${_logdir}/inference.*.log" - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/inference.JOB.log \ - python -m funasr.bin.diar_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/feats.scp,speech,kaldi_ark" \ - --data_path_and_name_and_type "${spk_profile},profile,kaldi_ark" \ - --key_file "${_logdir}"/keys.JOB.scp \ - --diar_train_config ${diar_exp}/config.yaml \ - --diar_model_file ${diar_exp}/${inference_model} \ - --output_dir "${_logdir}"/output.JOB \ - --mode sond ${_opt} - - echo "Iteration ${iter}, step 6: calc diarization results" - cat ${_logdir}/output.*/labels.txt | sort > ${eval_dir}/labels.txt - - cmd="python -Wignore script/convert_label_to_rttm.py ${eval_dir}/labels.txt ${datadir}/${dset}/files_for_dump/org_vad.txt ${eval_dir}/sys.rttm \ - --ignore_len 10 --no_pbar --smooth_size 83 --vote_prob 0.5 --n_spk 16" - # echo ${cmd} - eval ${cmd} - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${eval_dir}/sys.rttm.ref_vad - OVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - ref=${datadir}/${dset}/files_for_dump/ref.rttm - sys=${eval_dir}/sys.rttm.sys_vad - SysVAD_DER=$(python -Wignore dscore/score.py -r $ref -s $sys --collar 0.25 2>&1 | grep OVERALL | awk '{print $4}') - - echo -e "${inference_model}/iter_${iter} ${OVAD_DER} ${SysVAD_DER}" | tee -a ${eval_dir}/results.txt - done - - echo "Done." - done -fi diff --git a/egs/callhome/TOLD/soap/script/calc_num_frames.py b/egs/callhome/TOLD/soap/script/calc_num_frames.py deleted file mode 100644 index b55ff7561..000000000 --- a/egs/callhome/TOLD/soap/script/calc_num_frames.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import sys -import soundfile as sf -from funasr.utils.misc import load_scp_as_list - - -if __name__ == '__main__': - wav_scp = sys.argv[1] - out_file = sys.argv[2] - frame_shift = 0.01 - - os.makedirs(os.path.dirname(out_file), exist_ok=True) - - out_file = open(out_file, "wt") - for uttid, wav_path in load_scp_as_list(wav_scp): - wav, sr = sf.read(wav_path) - num_frame = wav.shape[0] // int(sr * frame_shift) - out_file.write(f"{uttid} {num_frame}\n") - out_file.flush() - - out_file.close() diff --git a/egs/callhome/TOLD/soap/script/calc_real_meeting_frame_labels.py b/egs/callhome/TOLD/soap/script/calc_real_meeting_frame_labels.py deleted file mode 100644 index f295c0c7e..000000000 --- a/egs/callhome/TOLD/soap/script/calc_real_meeting_frame_labels.py +++ /dev/null @@ -1,101 +0,0 @@ -import numpy as np -from funasr.utils.job_runner import MultiProcessRunnerV3 -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict -import os -import librosa -import scipy.io as sio -import argparse -from collections import OrderedDict - - -class MyRunner(MultiProcessRunnerV3): - - def prepare(self, parser): - parser.add_argument("dir", type=str) - parser.add_argument("out_dir", type=str) - parser.add_argument("--n_spk", type=int, default=8) - parser.add_argument("--remove_sil", default=False, action="store_true") - parser.add_argument("--frame_shift", type=float, default=0.01) - args = parser.parse_args() - assert args.sr == 8000, "For callhome dataset, the sample rate should be 8000, use --sr 8000." - - meeting_scp = load_scp_as_dict(os.path.join(args.dir, "wav.scp")) - meeting2rttm = self.load_rttm(args.dir) - - if not os.path.exists(args.out_dir): - os.makedirs(args.out_dir) - - task_list = [(mid, meeting_scp[mid], meeting2rttm[mid]) for mid in meeting2rttm.keys()] - return task_list, None, args - - def load_rttm(self, dir_path): - meeting2rttm = OrderedDict() - if os.path.exists(os.path.join(dir_path, "rttm.scp")): - rttm_scp = load_scp_as_list(os.path.join(dir_path, "rttm.scp")) - for mid, rttm_path in rttm_scp: - meeting2rttm[mid] = [] - for one_line in open(rttm_path, "rt"): - meeting2rttm[mid].append(one_line.strip()) - elif os.path.exists(os.path.join(dir_path, "ref.rttm")): - for one_line in open(os.path.join(dir_path, "ref.rttm"), "rt"): - mid = one_line.strip().split(" ")[1] - if mid not in meeting2rttm: - meeting2rttm[mid] = [] - meeting2rttm[mid].append(one_line.strip()) - else: - raise IOError("Neither rttm.scp nor ref.rttm exists in {}".format(dir_path)) - - return meeting2rttm - - def post(self, results_list, args): - pass - - -def calc_labels(spk_turns, spk_list, length, n_spk, remove_sil=False, sr=8000, frame_shift=0.01): - frame_shift = int(frame_shift * sr) - num_frame = int((float(length) + (float(frame_shift) / 2)) / frame_shift) - multi_label = np.zeros([n_spk, num_frame], dtype=int) - for _, st, dur, spk in spk_turns: - idx = spk_list.index(spk) - - st, dur = int(st * sr), int(dur * sr) - frame_st = int((float(st) + (float(frame_shift) / 2)) / frame_shift) - frame_ed = int((float(st+dur) + (float(frame_shift) / 2)) / frame_shift) - multi_label[idx, frame_st:frame_ed] = 1 - if not remove_sil: - return multi_label.T - - speech_count = np.sum(multi_label, axis=0) - idx = np.nonzero(speech_count)[0] - label = multi_label[:, idx].T - return label # (T, N) - - -def build_labels(wav_path, rttms, n_spk, remove_sil=False, sr=8000, frame_shift=0.01): - wav_len = int(librosa.get_duration(filename=wav_path, sr=sr) * sr) - spk_turns = [] - spk_list = [] - for one_line in rttms: - parts = one_line.strip().split(" ") - mid, st, dur, spk = parts[1], float(parts[3]), float(parts[4]), parts[7] - if spk not in spk_list: - spk_list.append(spk) - spk_turns.append((mid, st, dur, spk)) - labels = calc_labels(spk_turns, spk_list, wav_len, n_spk, remove_sil, sr, frame_shift) - return labels, spk_list - - -def process(task_args): - _, task_list, _, args = task_args - for mid, wav_path, rttms in task_list: - meeting_labels, spk_list = build_labels(wav_path, rttms, args.n_spk, args.remove_sil, - args.sr, args.frame_shift) - save_path = os.path.join(args.out_dir, "{}.lbl.mat".format(mid)) - sio.savemat(save_path, {"labels": meeting_labels.astype(bool), "spk_list": spk_list}) - # print mid - return None - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/callhome/TOLD/soap/script/concat_spk_segs.py b/egs/callhome/TOLD/soap/script/concat_spk_segs.py deleted file mode 100644 index 0ff1497e5..000000000 --- a/egs/callhome/TOLD/soap/script/concat_spk_segs.py +++ /dev/null @@ -1,57 +0,0 @@ -import numpy as np -from funasr.utils.job_runner import MultiProcessRunnerV3 -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict -import os -import librosa -import soundfile as sf -import argparse - - -class MyRunner(MultiProcessRunnerV3): - - def prepare(self, parser): - parser.add_argument("dir", type=str) - parser.add_argument("out_dir", type=str) - args = parser.parse_args() - assert args.sr == 8000, "For callhome dataset, the sample rate should be 8000, use --sr 8000." - - if not os.path.exists(args.out_dir): - os.makedirs(args.out_dir) - - print("loading data...") - wav_scp = load_scp_as_dict(os.path.join(args.dir, "wav.scp")) - utt2spk = load_scp_as_dict(os.path.join(args.dir, "utt2spk")) - - spk2utt = {} - count = 0 - for utt, spk in utt2spk.items(): - if utt in wav_scp: - if spk not in spk2utt: - spk2utt[spk] = [] - spk2utt[spk].append(utt) - count += 1 - task_list = spk2utt.keys() - print("total: {} speakers, {} utterances".format(len(spk2utt), count)) - print("starting jobs...") - return task_list, [spk2utt, wav_scp], args - - def post(self, results_list, args): - pass - - -def process(task_args): - _, task_list, [spk2utt, wav_scp], args = task_args - for spk in task_list: - spk_wav_list = [] - for utt in spk2utt[spk]: - wav = librosa.load(wav_scp[utt], sr=args.sr, mono=True)[0] * 32767 - spk_wav_list.append(wav) - sig = np.concatenate(spk_wav_list, axis=0) - save_path = os.path.join(args.out_dir, "{}.wav".format(spk)) - sf.write(save_path, sig.astype(np.int16), args.sr, "PCM_16", "LITTLE", "WAV", True) - return None - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/callhome/TOLD/soap/script/convert_label_to_rttm.py b/egs/callhome/TOLD/soap/script/convert_label_to_rttm.py deleted file mode 100644 index 93b05f7bb..000000000 --- a/egs/callhome/TOLD/soap/script/convert_label_to_rttm.py +++ /dev/null @@ -1,201 +0,0 @@ -import os -from funasr.utils.job_runner import MultiProcessRunnerV3 -import numpy as np -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict -from collections import OrderedDict -from tqdm import tqdm -from scipy.ndimage import median_filter -import kaldiio - - -def load_mid_vad(vad_path): - mid2segment_list = {} - for one_line in open(vad_path, "rt"): - utt_id, mid, start, end = one_line.strip().split(" ") - start, end = float(start), float(end) - if mid not in mid2segment_list: - mid2segment_list[mid] = [] - mid2segment_list[mid].append((utt_id, start, end)) - - return mid2segment_list - - -class MyRunner(MultiProcessRunnerV3): - def prepare(self, parser): - parser.add_argument("label_txt", type=str) - parser.add_argument("oracle_vad", type=str, default=None) - parser.add_argument("out_rttm", type=str) - parser.add_argument("--sys_vad_prob", type=str, default=None) - parser.add_argument("--sys_vad_threshold", type=float, default=None) - parser.add_argument("--vad_smooth_size", type=int, default=7) - parser.add_argument("--n_spk", type=int, default=4) - parser.add_argument("--chunk_len", type=int, default=1600) - parser.add_argument("--shift_len", type=int, default=400) - parser.add_argument("--ignore_len", type=int, default=5) - parser.add_argument("--smooth_size", type=int, default=7) - parser.add_argument("--vote_prob", type=float, default=0.5) - args = parser.parse_args() - - if not os.path.exists(os.path.dirname(args.out_rttm)): - os.makedirs(os.path.dirname(args.out_rttm)) - - utt2labels = load_scp_as_list(args.label_txt, 'list') - utt2vad_prob = [] - if args.sys_vad_prob is not None and os.path.exists(args.sys_vad_prob): - if args.verbose: - print("Use system vad ark file {}".format(args.sys_vad_prob)) - for (key, vad_prob), (utt_id, _) in zip(kaldiio.load_ark(args.sys_vad_prob), utt2labels): - utt2vad_prob.append((utt_id, vad_prob)) - utt2vad_prob = sorted(utt2vad_prob, key=lambda x: x[0]) - - utt2labels = sorted(utt2labels, key=lambda x: x[0]) - mid2segment_list = load_mid_vad(args.oracle_vad) - meeting2labels = OrderedDict() - for utt_id, chunk_label in utt2labels: - mid = utt_id.split("-")[0] - if mid not in meeting2labels: - meeting2labels[mid] = [] - meeting2labels[mid].append(chunk_label) - - mid2vad_list = {} - if len(utt2vad_prob) > 0: - for utt_id, vad_prob in utt2vad_prob: - mid = utt_id.split("-")[0] - if mid not in mid2vad_list: - mid2vad_list[mid] = [] - mid2vad_list[mid].append(vad_prob) - - task_list = [(mid, labels, mid2segment_list[mid], None) if len(mid2vad_list) == 0 else - (mid, labels, mid2segment_list[mid], mid2vad_list[mid]) - for mid, labels in meeting2labels.items()] - - return task_list, None, args - - def post(self, result_list, args): - ref_vad_rttm = open(args.out_rttm + ".ref_vad", "wt") - sys_vad_rttm = open(args.out_rttm + ".sys_vad", "wt") - for results in result_list: - for one_result in results: - ref_vad_rttm.writelines(one_result[0]) - sys_vad_rttm.writelines(one_result[1]) - ref_vad_rttm.close() - sys_vad_rttm.close() - - -def int2vec(x, vec_dim=8, dtype=np.int): - b = ('{:0' + str(vec_dim) + 'b}').format(x) - # little-endian order: lower bit first - return (np.array(list(b)[::-1]) == '1').astype(dtype) - - -def seq2arr(seq, vec_dim=8): - return np.row_stack([int2vec(int(x), vec_dim) for x in seq]) - - -def sample2ms(sample, sr=16000): - return int(float(sample) / sr * 100) - - -def calc_multi_labels(chunk_label_list, chunk_len, shift_len, n_spk, vote_prob=0.5): - n_chunk = len(chunk_label_list) - last_chunk_valid_frame = len(chunk_label_list[-1]) - (chunk_len - shift_len) - n_frame = (n_chunk - 2) * shift_len + chunk_len + last_chunk_valid_frame - multi_labels = np.zeros((n_frame, n_spk), dtype=float) - weight = np.zeros((n_frame, 1), dtype=float) - for i in range(n_chunk): - raw_label = chunk_label_list[i] - for k in range(len(raw_label)): - if raw_label[k] == '': - raw_label[k] = raw_label[k-1] if k > 0 else '0' - chunk_multi_label = seq2arr(raw_label, n_spk) - chunk_len = chunk_multi_label.shape[0] - multi_labels[i*shift_len:i*shift_len+chunk_len, :] += chunk_multi_label - weight[i*shift_len:i*shift_len+chunk_len, :] += 1 - multi_labels = multi_labels / weight # normalizing vote - multi_labels = (multi_labels > vote_prob).astype(int) # voting results - return multi_labels - - -def calc_spk_turns(label_arr, spk_list): - turn_list = [] - length = label_arr.shape[0] - n_spk = label_arr.shape[1] - for k in range(n_spk): - if spk_list[k] == "None": - continue - in_utt = False - start = 0 - for i in range(length): - if label_arr[i, k] == 1 and in_utt is False: - start = i - in_utt = True - if label_arr[i, k] == 0 and in_utt is True: - turn_list.append([spk_list[k], start, i - start]) - in_utt = False - if in_utt: - turn_list.append([spk_list[k], start, length - start]) - return turn_list - - -def smooth_multi_labels(multi_label, win_len): - multi_label = median_filter(multi_label, (win_len, 1), mode="constant", cval=0.0).astype(int) - return multi_label - - -def calc_vad_mask(segments, total_len): - vad_mask = np.zeros((total_len, 1), dtype=int) - for _, start, end in segments: - start, end = int(start * 100), int(end * 100) - vad_mask[start: end] = 1 - return vad_mask - - -def calc_system_vad_mask(vad_prob_list, total_len, args): - if vad_prob_list is None: - return 1 - - threshold = args.sys_vad_threshold - chunk_len = args.chunk_len - shift_len = args.shift_len - frame_vad_mask = np.zeros((total_len, 1), dtype=float) - weight = np.zeros((total_len, 1), dtype=float) - for i, vad_prob in enumerate(vad_prob_list): - frame_vad_mask[i * shift_len: i * shift_len + chunk_len] += np.greater(vad_prob, threshold).astype(float) - weight[i * shift_len: i * shift_len + chunk_len] += 1.0 - frame_vad_mask = np.greater(frame_vad_mask / weight, args.vote_prob) - frame_vad_mask = frame_vad_mask.astype(int) - frame_vad_mask = smooth_multi_labels(frame_vad_mask.astype(int), args.vad_smooth_size) - return frame_vad_mask - - -def generate_rttm(mid, multi_labels, spk_list, args): - template = "SPEAKER {} 0 {:.2f} {:.2f} {} \n" - spk_turns = calc_spk_turns(multi_labels, spk_list) - spk_turns = sorted(spk_turns, key=lambda x: x[1]) - results = [] - for spk, st, dur in spk_turns: - # TODO: handle the leak of segments at the change points - if dur > args.ignore_len: - results.append(template.format(mid, float(st) / 100, float(dur) / 100, spk)) - return results - - -def process(task_args): - _, task_list, _, args = task_args - spk_list = ["spk{}".format(i+1) for i in range(args.n_spk)] - results = [] - for mid, chunk_label_list, segments_list, sys_vad_list in tqdm(task_list, total=len(task_list), - ascii=True, disable=args.no_pbar): - multi_labels = calc_multi_labels(chunk_label_list, args.chunk_len, args.shift_len, args.n_spk, args.vote_prob) - multi_labels = smooth_multi_labels(multi_labels, args.smooth_size) - oracle_vad_mask = calc_vad_mask(segments_list, multi_labels.shape[0]) - oracle_vad_rttm = generate_rttm(mid, multi_labels * oracle_vad_mask, spk_list, args) - system_vad_mask = calc_system_vad_mask(sys_vad_list, multi_labels.shape[0], args) - system_vad_rttm = generate_rttm(mid, multi_labels * system_vad_mask, spk_list, args) - results.append([oracle_vad_rttm, system_vad_rttm]) - return results - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/callhome/TOLD/soap/script/convert_pse_label_to_bin_ark.py b/egs/callhome/TOLD/soap/script/convert_pse_label_to_bin_ark.py deleted file mode 100644 index ab1ce87a6..000000000 --- a/egs/callhome/TOLD/soap/script/convert_pse_label_to_bin_ark.py +++ /dev/null @@ -1,35 +0,0 @@ -import kaldiio -import os -import sys -import numpy as np - - -def int2vec(x, vec_dim=8, dtype=np.float32): - b = ('{:0' + str(vec_dim) + 'b}').format(x) - # little-endian order: lower bit first - return (np.array(list(b)[::-1]) == '1').astype(dtype) - - -def seq2arr(seq, vec_dim=8): - return np.row_stack([int2vec(int(x), vec_dim) for x in seq]) - - -if __name__ == '__main__': - scp_file = sys.argv[1] - label_file = sys.argv[2] - out_file = sys.argv[3] - max_spk_num = int(sys.argv[4]) - - os.makedirs(os.path.dirname(out_file), exist_ok=True) - - out_file = out_file.rsplit('.', maxsplit=1)[0] - wav_writer = kaldiio.WriteHelper("ark,scp,f:{}.ark,{}.scp".format(out_file, out_file)) - for i, (uttid, pse_str) in enumerate(zip(open(scp_file, "rt"), open(label_file, "rt"))): - uttid, pse_str = uttid.strip().split(" ", maxsplit=1)[0], pse_str.strip() - bin_label = seq2arr(pse_str.split(" "), vec_dim=max_spk_num) - wav_writer(uttid, bin_label) - - if i % 100 == 0: - print(f"Processed {i} samples, the last is {uttid}") - - wav_writer.close() diff --git a/egs/callhome/TOLD/soap/script/convert_rttm_to_seg_file.py b/egs/callhome/TOLD/soap/script/convert_rttm_to_seg_file.py deleted file mode 100644 index 7ed0f99f5..000000000 --- a/egs/callhome/TOLD/soap/script/convert_rttm_to_seg_file.py +++ /dev/null @@ -1,63 +0,0 @@ -import numpy as np -from funasr.utils.job_runner import MultiProcessRunnerV3 -import os - - -class MyRunner(MultiProcessRunnerV3): - - def prepare(self, parser): - parser.add_argument("--rttm_scp", type=str) - parser.add_argument("--seg_file", type=str) - args = parser.parse_args() - - if not os.path.exists(os.path.dirname(args.seg_file)): - os.makedirs(os.path.dirname(args.seg_file)) - - meeting2rttms = {} - for one_line in open(args.rttm_scp, "rt"): - parts = [x for x in one_line.strip().split(" ") if x != ""] - mid, st, dur, spk_name = parts[1], float(parts[3]), float(parts[4]), parts[7] - if mid not in meeting2rttms: - meeting2rttms[mid] = [] - meeting2rttms[mid].append(one_line) - - task_list = list(meeting2rttms.items()) - return task_list, None, args - - def post(self, results_list, args): - with open(args.seg_file, "wt") as fd: - for results in results_list: - fd.writelines(results) - - -def process(task_args): - _, task_list, _, args = task_args - outputs = [] - for mid, rttms in task_list: - spk_turns = [] - length = 0 - for one_line in rttms: - parts = one_line.strip().split(" ") - _, st, dur, spk_name = parts[1], float(parts[3]), float(parts[4]), parts[7] - st, ed = int(st*100), int((st + dur)*100) - length = ed if ed > length else length - spk_turns.append([mid, st, ed, spk_name]) - is_sph = np.zeros((length+1, ), dtype=bool) - for _, st, ed, _ in spk_turns: - is_sph[st:ed] = True - - st, in_speech = 0, False - for i in range(length+1): - if not in_speech and is_sph[i]: - st, in_speech = i, True - if in_speech and not is_sph[i]: - in_speech = False - outputs.append("{}-{:07d}-{:07d} {} {:.2f} {:.2f}\n".format( - mid, st, i, mid, float(st)/100, float(i)/100 - )) - return outputs - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/callhome/TOLD/soap/script/dump_meeting_chunks.py b/egs/callhome/TOLD/soap/script/dump_meeting_chunks.py deleted file mode 100644 index 6cb56ba68..000000000 --- a/egs/callhome/TOLD/soap/script/dump_meeting_chunks.py +++ /dev/null @@ -1,176 +0,0 @@ -import kaldiio -from tqdm import tqdm -import os -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict -import numpy as np -import argparse -import random -import scipy.io as sio -import logging -logging.basicConfig(format="[%(asctime)s] %(levelname)s: %(message)s", level=logging.INFO) - - -short_spk_list = [] -def calc_rand_ivc(spk, spk2utt, utt2ivc, utt2frames, total_len=3000): - all_utts = spk2utt[spk] - idx_list = list(range(len(all_utts))) - random.shuffle(idx_list) - count = 0 - utt_list = [] - for i in idx_list: - utt_id = all_utts[i] - utt_list.append(utt_id) - count += int(utt2frames[utt_id]) - if count >= total_len: - break - if count < 300 and spk not in short_spk_list: - logging.warning("{} has only {} frames, but expect {} frames at least, use them all.".format(spk, count, 300)) - short_spk_list.append(spk) - - ivc_list = [kaldiio.load_mat(utt2ivc[utt])[np.newaxis, :] for utt in utt_list] - ivc = np.concatenate(ivc_list, axis=0) - ivc = np.mean(ivc, axis=0, keepdims=False) - return ivc - - -def process(feat_scp, labels_scp, spk2utt, utt2xvec, utt2frames, args): - out_prefix = "{}_parts{:02d}".format(args.out, args.task_id) - logger = logging.Logger(out_prefix, logging.INFO) - file_handler = logging.FileHandler(out_prefix + ".log", mode="w") - file_handler.setLevel(logging.INFO) - formatter = logging.Formatter("[%(asctime)s] %(levelname)s: %(message)s") - file_handler.setFormatter(formatter) - logger.addHandler(file_handler) - - ivc_dim = 256 - chunk_size, chunk_shift = args.chunk_size, args.chunk_shift - label_weights = 2 ** np.array(list(range(args.n_spk))) - feat_writer = kaldiio.WriteHelper(f"ark,scp,f:{out_prefix}_feat.ark,{out_prefix}_feat.scp") - ivc_writer = kaldiio.WriteHelper(f"ark,scp,f:{out_prefix}_xvec.ark,{out_prefix}_xvec.scp") - label_writer = kaldiio.WriteHelper(f"ark,scp,f:{out_prefix}_label.ark,{out_prefix}_label.scp") - train_spk_list = list(spk2utt.keys()) - - frames_list = [] - non_present_spk_list = [] - for mid, feat_path in tqdm(feat_scp, total=len(feat_scp), ascii=True, disable=args.no_pbar): - if mid not in labels_scp: - continue - feat = kaldiio.load_mat(feat_path) - data = sio.loadmat(labels_scp[mid]) - labels, meeting_spk_list = data["labels"].astype(int), [x.strip() for x in data["spk_list"]] - if args.add_mid_to_speaker: - meeting_spk_list = ["{}_{}".format(mid, x) if not x.startswith(mid) else x for x in meeting_spk_list] - if labels.shape[0] != feat.shape[0]: - min_len = min(labels.shape[0], feat.shape[0]) - labels, feat = labels[:min_len], feat[:min_len] - logger.warning("{}: The expected frame_len is {}, but got {}, clip both to {}".format( - mid, labels.shape[0], feat.shape[0], min_len)) - num_frame = feat.shape[0] - num_chunk = int(np.ceil(float(num_frame - chunk_size) / chunk_shift)) + 1 - for i in range(num_chunk): - st, ed = i*chunk_shift, i*chunk_shift+chunk_size - utt_id = "{}-{:05d}-{:05d}".format(mid, st, ed) - chunk_feat = feat[st: ed, :] - chunk_label = labels[st: ed, :] - frame_pad = chunk_size - chunk_label.shape[0] - spk_pad = args.n_spk - chunk_label.shape[1] - chunk_feat = np.pad(chunk_feat, [(0, frame_pad), (0, 0)], "constant", constant_values=0) - chunk_label = np.pad(chunk_label, [(0, frame_pad), (0, spk_pad)], "constant", constant_values=0) - - feat_writer(utt_id, chunk_feat) - - spk_idx = list(range(max(args.n_spk, len(meeting_spk_list)))) - spk_list = [] - if args.mode == "train": - random.shuffle(spk_idx) - - if args.n_spk > len(meeting_spk_list): - n = random.randint(len(meeting_spk_list), args.n_spk) - spk_list.extend(meeting_spk_list) - while len(spk_list) < n: - spk = random.choice(train_spk_list) - if spk not in spk_list: - spk_list.append(spk) - spk_list.extend(["None"] * (args.n_spk - n)) - else: - raise ValueError("Argument n_spk is too small ({} < {}).".format(args.n_spk, len(meeting_spk_list))) - else: - spk_list.extend(meeting_spk_list) - spk_list.extend(["None"] * max(args.n_spk - len(meeting_spk_list), 0)) - - xvec_list = [] - for i, spk in enumerate(spk_list): - if spk == "None": - spk_xvec = np.zeros((ivc_dim,), dtype=np.float32) - elif spk not in spk2utt: - # speaker with very short duration - spk_xvec = np.zeros((ivc_dim,), dtype=np.float32) - # chunk_label[:, i] = 0 - if spk not in non_present_spk_list: - logging.warning("speaker {}/{} does not appear in spk2utt, since it has very short duration.".format(mid, spk)) - non_present_spk_list.append(spk) - else: - spk_xvec = calc_rand_ivc(spk, spk2utt, utt2xvec, utt2frames, 3000)[np.newaxis, :] - xvec_list.append(spk_xvec) - xvec = np.row_stack(xvec_list) - # shuffle speaker embedding according spk_idx - xvec = xvec[spk_idx, :] - ivc_writer(utt_id, xvec) - - # shuffle labels according spk_idx - feat_label = chunk_label[:, spk_idx] - # feat_label = np.sum(feat_label * label_weights[np.newaxis, :chunk_label.shape[1]], axis=1).astype(str).tolist() - label_writer(utt_id, feat_label.astype(np.float32)) - - frames_list.append((mid, feat.shape[0])) - - logger.info("{:30s}: {:6d} frames split into {:3d} chunks.".format(mid, num_frame, num_chunk)) - return frames_list - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--dir", required=True, type=str, default=None, - help="feats.scp") - parser.add_argument("--out", required=True, type=str, default=None, - help="The prefix of dumpped files.") - parser.add_argument("--n_spk", type=int, default=16) - parser.add_argument("--use_lfr", default=False, action="store_true") - parser.add_argument("--no_pbar", default=False, action="store_true") - parser.add_argument("--sr", type=int, default=8000) - parser.add_argument("--chunk_size", type=int, default=1600) - parser.add_argument("--chunk_shift", type=int, default=400) - parser.add_argument("--mode", type=str, default="train", choices=["train", "test"]) - parser.add_argument("--task_id", type=int, default=0) - parser.add_argument("--task_size", type=int, default=-1) - parser.add_argument("--add_mid_to_speaker", type=bool, default=False) - args = parser.parse_args() - assert args.sr == 8000, "For callhome dataset, the sample rate should be 8000, use --sr 8000." - - if not os.path.exists(os.path.dirname(args.out)): - os.makedirs(os.path.dirname(args.out)) - - feat_scp = load_scp_as_list(os.path.join(args.dir, "feats.scp")) - if args.task_size > 0: - feat_scp = feat_scp[args.task_size*args.task_id: args.task_size*(args.task_id+1)] - labels_scp = load_scp_as_dict(os.path.join(args.dir, "labels.scp")) - utt2spk = load_scp_as_dict(os.path.join(args.dir, "utt2spk")) - utt2xvec = load_scp_as_dict(os.path.join(args.dir, "utt2xvec")) - utt2frames = load_scp_as_dict(os.path.join(args.dir, "utt2num_frames")) - - spk2utt = {} - for utt, spk in utt2spk.items(): - if utt in utt2xvec and utt in utt2frames and int(utt2frames[utt]) > 25: - if spk not in spk2utt: - spk2utt[spk] = [] - spk2utt[spk].append(utt) - logging.info("Obtain {} speakers.".format(len(spk2utt))) - logging.info("Task {:02d}: start dump {} meetings.".format(args.task_id, len(feat_scp))) - # random.shuffle(feat_scp) - meeting_lens = process(feat_scp, labels_scp, spk2utt, utt2xvec, utt2frames, args) - total_frames = sum([x[1] for x in meeting_lens]) - logging.info("Total meetings: {:6d}, total frames: {:10d}".format(len(meeting_lens), total_frames)) - - -if __name__ == '__main__': - main() diff --git a/egs/callhome/TOLD/soap/script/dump_pipe_wav.py b/egs/callhome/TOLD/soap/script/dump_pipe_wav.py deleted file mode 100644 index 2d21969a3..000000000 --- a/egs/callhome/TOLD/soap/script/dump_pipe_wav.py +++ /dev/null @@ -1,48 +0,0 @@ -import os -import argparse -from funasr.utils.job_runner import MultiProcessRunnerV3 -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict - - -class MyRunner(MultiProcessRunnerV3): - def prepare(self, parser): - assert isinstance(parser, argparse.ArgumentParser) - parser.add_argument("wav_scp", type=str) - parser.add_argument("out_dir", type=str) - args = parser.parse_args() - # assert args.sr == 8000, "For callhome dataset, the sample rate should be 8000, use --sr 8000." - - wav_scp = load_scp_as_list(args.wav_scp) - if not os.path.exists(args.out_dir): - os.makedirs(args.out_dir) - - return wav_scp, None, args - - def post(self, result_list, args): - count = [0, 0] - for result in result_list: - count[0] += result[0] - count[1] += result[1] - print("All threads done, {} success, {} failed.".format(count[0], count[1])) - - -def process(task_args): - task_id, task_list, _, args = task_args - - count = [0, 0] - for utt_id, cmd in task_list: - try: - wav_path = os.path.join(args.out_dir, "{}.wav".format(utt_id)) - cmd = cmd.replace("|", "> {}".format(wav_path)) - os.system(cmd) - count[0] += 1 - except: - print("Failed execute command for {}.".format(utt_id)) - count[1] += 1 - - return count - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/callhome/TOLD/soap/script/dump_speaker_profiles.py b/egs/callhome/TOLD/soap/script/dump_speaker_profiles.py deleted file mode 100644 index d22f278d8..000000000 --- a/egs/callhome/TOLD/soap/script/dump_speaker_profiles.py +++ /dev/null @@ -1,117 +0,0 @@ -import kaldiio -from tqdm import tqdm -import os -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict -import numpy as np -import argparse -from kaldiio import WriteHelper - - -def calc_global_ivc(spk, spk2utt, utt2ivc): - ivc_list = [kaldiio.load_mat(utt2ivc[utt])[np.newaxis, :] for utt in spk2utt[spk]] - ivc = np.concatenate(ivc_list, axis=0) - ivc = np.mean(ivc, axis=0, keepdims=False) - return ivc - - -def process(idx_scp, spk2utt, utt2xvec, meeting2spk_list, args): - out_prefix = args.out - - ivc_dim = 256 - print("ivc_dim = {}".format(ivc_dim)) - out_prefix = out_prefix + "_parts00_xvec" - ivc_writer = WriteHelper(f"ark,scp,f:{out_prefix}.ark,{out_prefix}.scp") - idx_writer = open(out_prefix + ".idx", "wt") - spk2xvec = {} - if args.emb_type == "global": - print("Use global speaker embedding.") - for spk in spk2utt.keys(): - spk2xvec[spk] = calc_global_ivc(spk, spk2utt, utt2xvec)[np.newaxis, :] - - frames_list = [] - for utt_id in tqdm(idx_scp, total=len(idx_scp), ascii=True, disable=args.no_pbar): - mid = utt_id.split("-")[0] - idx_writer.write(utt_id+"\n") - - xvec_list = [] - for spk in meeting2spk_list[mid]: - spk_xvec = spk2xvec[spk] - xvec_list.append(spk_xvec) - for _ in range(args.n_spk - len(xvec_list)): - xvec_list.append(np.zeros((ivc_dim,), dtype=np.float32)) - xvec = np.row_stack(xvec_list) - ivc_writer(utt_id, xvec) - - frames_list.append((mid, 1)) - return frames_list - - -def calc_spk_list(rttms): - spk_list = [] - for one_line in rttms: - parts = [x for x in one_line.strip().split(" ") if x != ""] - mid, st, dur, spk_name = parts[1], float(parts[3]), float(parts[4]), parts[7] - spk_name = spk_name.replace("spk", "").replace(mid, "").replace("-", "") - if spk_name.isdigit(): - spk_name = "{}_S{:03d}".format(mid, int(spk_name)) - else: - spk_name = "{}_{}".format(mid, spk_name) - if spk_name not in spk_list: - spk_list.append(spk_name) - - return spk_list - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--dir", required=True, type=str, default=None, - help="feats.scp") - parser.add_argument("--out", required=True, type=str, default=None, - help="The prefix of dumpped files.") - parser.add_argument("--n_spk", type=int, default=4) - parser.add_argument("--no_pbar", default=False, action="store_true") - parser.add_argument("--sr", type=int, default=16000) - parser.add_argument("--emb_type", type=str, default="rand") - args = parser.parse_args() - - if not os.path.exists(os.path.dirname(args.out)): - os.makedirs(os.path.dirname(args.out)) - - idx_scp = open(os.path.join(args.dir, "idx"), "r").readlines() - idx_scp = [x.strip() for x in idx_scp] - meeting2rttms = {} - for one_line in open(os.path.join(args.dir, "sys.rttm"), "rt"): - parts = [x for x in one_line.strip().split(" ") if x != ""] - mid, st, dur, spk_name = parts[1], float(parts[3]), float(parts[4]), parts[7] - if mid not in meeting2rttms: - meeting2rttms[mid] = [] - meeting2rttms[mid].append(one_line) - - utt2spk = load_scp_as_dict(os.path.join(args.dir, "utt2spk")) - utt2xvec = load_scp_as_dict(os.path.join(args.dir, "utt2xvec")) - - spk2utt = {} - for utt, spk in utt2spk.items(): - if utt in utt2xvec: - if spk not in spk2utt: - spk2utt[spk] = [] - spk2utt[spk].append(utt) - - meeting2spk_list = {} - for mid, rttms in meeting2rttms.items(): - meeting2spk_list[mid] = calc_spk_list(rttms) - new_spk_list = [] - for spk in meeting2spk_list[mid]: - if spk in spk2utt: - new_spk_list.append(spk) - if len(new_spk_list) != len(meeting2spk_list[mid]): - print("{}: Reduce speaker number from {}(according rttm) to {}(according x-vectors)".format( - mid, len(meeting2spk_list[mid]), len(new_spk_list))) - meeting2spk_list[mid] = new_spk_list - - meeting_lens = process(idx_scp, spk2utt, utt2xvec, meeting2spk_list, args) - print("Total meetings: {:6d}".format(len(meeting_lens))) - - -if __name__ == '__main__': - main() diff --git a/egs/callhome/TOLD/soap/script/easy_average_models.py b/egs/callhome/TOLD/soap/script/easy_average_models.py deleted file mode 100644 index cb5b7a83f..000000000 --- a/egs/callhome/TOLD/soap/script/easy_average_models.py +++ /dev/null @@ -1,54 +0,0 @@ -import os -import sys -import torch -import argparse - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument( - "--model_dir", - required=True, - default=None, - type=str, - help="Director contains saved models." - ) - parser.add_argument( - "--average_epochs", - nargs="+", - type=int, - default=[], - ) - parser.add_argument( - "--metric_name", - type=str, - default="der", - help="The metric name of best models, only used for name." - ) - args = parser.parse_args() - - root_path = args.model_dir - idx_list = args.average_epochs - n_models = len(idx_list) - metric = args.metric_name - - if n_models > 0: - avg = None - for idx in idx_list: - model_file = os.path.join(root_path, "{}epoch.pth".format(str(idx))) - states = torch.load(model_file, map_location="cpu") - if avg is None: - avg = states - else: - for k in avg: - avg[k] = avg[k] + states[k] - - for k in avg: - if str(avg[k].dtype).startswith("torch.int"): - pass - else: - avg[k] = avg[k] / n_models - - output_file = os.path.join(root_path, "valid.{}.ave_{}best.pth".format(metric, n_models)) - torch.save(avg, output_file) - else: - print("Number of models to average is 0, skip.") diff --git a/egs/callhome/TOLD/soap/script/extract_nonoverlap_segments.py b/egs/callhome/TOLD/soap/script/extract_nonoverlap_segments.py deleted file mode 100644 index 37f995a0f..000000000 --- a/egs/callhome/TOLD/soap/script/extract_nonoverlap_segments.py +++ /dev/null @@ -1,116 +0,0 @@ -import numpy as np -import os -import argparse -from funasr.utils.job_runner import MultiProcessRunnerV3 -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict -import librosa -import soundfile as sf -from tqdm import tqdm - - -class MyRunner(MultiProcessRunnerV3): - def prepare(self, parser): - assert isinstance(parser, argparse.ArgumentParser) - parser.add_argument("wav_scp", type=str) - parser.add_argument("rttm_scp", type=str) - parser.add_argument("out_dir", type=str) - parser.add_argument("--min_dur", type=float, default=2.0) - parser.add_argument("--max_spk_num", type=int, default=4) - args = parser.parse_args() - assert args.sr == 8000, "For callhome dataset, the sample rate should be 8000, use --sr 8000." - - if not os.path.exists(args.out_dir): - os.makedirs(args.out_dir) - - wav_scp = load_scp_as_list(args.wav_scp) - meeting2rttms = {} - for one_line in open(args.rttm_scp, "rt"): - parts = [x for x in one_line.strip().split(" ") if x != ""] - mid, st, dur, spk_name = parts[1], float(parts[3]), float(parts[4]), parts[7] - if mid not in meeting2rttms: - meeting2rttms[mid] = [] - meeting2rttms[mid].append(one_line) - - task_list = [(mid, wav_path, meeting2rttms[mid]) for (mid, wav_path) in wav_scp] - return task_list, None, args - - def post(self, result_list, args): - count = [0, 0] - for result in result_list: - count[0] += result[0] - count[1] += result[1] - print("Found {} speakers, extracted {}.".format(count[1], count[0])) - - -# SPEAKER R8001_M8004_MS801 1 6.90 11.39 1 -def calc_multi_label(rttms, length, sr=8000, max_spk_num=4): - labels = np.zeros([max_spk_num, length], int) - spk_list = [] - for one_line in rttms: - parts = [x for x in one_line.strip().split(" ") if x != ""] - mid, st, dur, spk_name = parts[1], float(parts[3]), float(parts[4]), parts[7] - spk_name = spk_name.replace("spk", "").replace(mid, "").replace("-", "") - if spk_name.isdigit(): - spk_name = "{}_S{:03d}".format(mid, int(spk_name)) - else: - spk_name = "{}_{}".format(mid, spk_name) - if spk_name not in spk_list: - spk_list.append(spk_name) - st, dur = int(st*sr), int(dur*sr) - idx = spk_list.index(spk_name) - labels[idx, st:st+dur] = 1 - return labels, spk_list - - -def get_nonoverlap_turns(multi_label, spk_list): - turns = [] - label = np.sum(multi_label, axis=0) == 1 - spk, in_turn, st = None, False, 0 - for i in range(len(label)): - if not in_turn and label[i]: - st, in_turn = i, True - spk = spk_list[np.argmax(multi_label[:, i], axis=0)] - if in_turn: - if not label[i]: - in_turn = False - turns.append([st, i, spk]) - elif label[i] and spk != spk_list[np.argmax(multi_label[:, i], axis=0)]: - turns.append([st, i, spk]) - st, in_turn = i, True - spk = spk_list[np.argmax(multi_label[:, i], axis=0)] - if in_turn: - turns.append([st, len(label), spk]) - return turns - - -def process(task_args): - task_id, task_list, _, args = task_args - spk_count = [0, 0] - for mid, wav_path, rttms in task_list: - wav = librosa.load(wav_path, args.sr)[0] * 32767 - multi_label, spk_list = calc_multi_label(rttms, len(wav), args.sr, args.max_spk_num) - turns = get_nonoverlap_turns(multi_label, spk_list) - extracted_spk = [] - count = 1 - for st, ed, spk in tqdm(turns, total=len(turns), ascii=True, disable=args.no_pbar): - if (ed - st) >= args.min_dur * args.sr and len(wav[st: ed]) >= args.min_dur * args.sr: - seg = wav[st: ed] - save_path = os.path.join(args.out_dir, mid, spk, "{}_U{:04d}.wav".format(spk, count)) - if not os.path.exists(os.path.dirname(save_path)): - os.makedirs(os.path.dirname(save_path)) - sf.write(save_path, seg.astype(np.int16), args.sr, "PCM_16", "LITTLE", "WAV", True) - count += 1 - if spk not in extracted_spk: - extracted_spk.append(spk) - if len(extracted_spk) != len(spk_list): - print("{}: Found {} speakers, but only extracted {}. {} are filtered due to min_dur".format( - mid, len(spk_list), len(extracted_spk), " ".join([x for x in spk_list if x not in extracted_spk]) - )) - spk_count[0] += len(extracted_spk) - spk_count[1] += len(spk_list) - return spk_count - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/callhome/TOLD/soap/script/remove_silence_from_wav.py b/egs/callhome/TOLD/soap/script/remove_silence_from_wav.py deleted file mode 100644 index b53f6f4ef..000000000 --- a/egs/callhome/TOLD/soap/script/remove_silence_from_wav.py +++ /dev/null @@ -1,63 +0,0 @@ -import numpy as np -from funasr.utils.job_runner import MultiProcessRunnerV3 -from funasr.utils.misc import load_scp_as_list, load_scp_as_dict -import os -import librosa -import soundfile as sf - - -class MyRunner(MultiProcessRunnerV3): - - def prepare(self, parser): - parser.add_argument("dir", type=str) - parser.add_argument("out_dir", type=str) - args = parser.parse_args() - assert args.sr == 8000, "For callhome dataset, the sample rate should be 8000, use --sr 8000." - - meeting_scp = load_scp_as_list(os.path.join(args.dir, "reco.scp")) - vad_file = open(os.path.join(args.dir, "segments")) - meeting2vad = {} - for one_line in vad_file: - uid, mid, st, ed = one_line.strip().split(" ") - st, ed = int(float(st) * args.sr), int(float(ed) * args.sr) - if mid not in meeting2vad: - meeting2vad[mid] = [] - meeting2vad[mid].append((uid, st, ed)) - - if not os.path.exists(args.out_dir): - os.makedirs(args.out_dir) - - for mid, _ in meeting_scp: - if mid not in meeting2vad: - print("Recording {} doesn't contains speech segments".format(mid)) - task_list = [(mid, wav_path, meeting2vad[mid]) for mid, wav_path in meeting_scp if mid in meeting2vad] - return task_list, None, args - - def post(self, results_list, args): - pass - - -def process(task_args): - _, task_list, _, args = task_args - for mid, wav_path, vad_list in task_list: - wav = librosa.load(wav_path, args.sr, True)[0] * 32767 - seg_list = [] - pos_map = [] - offset = 0 - for uid, st, ed in vad_list: - seg_list.append(wav[st: ed]) - pos_map.append("{} {} {} {} {}\n".format(uid, st, ed, offset, offset+ed-st)) - offset = offset + ed - st - out = np.concatenate(seg_list, axis=0) - save_path = os.path.join(args.out_dir, "{}.wav".format(mid)) - sf.write(save_path, out.astype(np.int16), args.sr, "PCM_16", "LITTLE", "WAV", True) - map_path = os.path.join(args.out_dir, "{}.pos".format(mid)) - with open(map_path, "wt") as fd: - fd.writelines(pos_map) - # print mid - return None - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/callhome/TOLD/soap/script/simu_whole_recordings.py b/egs/callhome/TOLD/soap/script/simu_whole_recordings.py deleted file mode 100644 index 0251ed4a0..000000000 --- a/egs/callhome/TOLD/soap/script/simu_whole_recordings.py +++ /dev/null @@ -1,216 +0,0 @@ -import argparse -import numpy as np -import librosa -import soundfile as sf -import os -import random -import json -from funasr.utils.misc import load_scp_as_dict, load_scp_as_list -from tqdm import tqdm - - -def mix_wav_noise(wav, noise, snr): - n_repeat = len(wav) // len(noise) + 1 - noise = np.repeat(noise, n_repeat, axis=0) - st = random.randint(0, len(noise) - len(wav)) - noise = noise[st: st+len(wav)] - - wav_mag = np.linalg.norm(wav, ord=2) - noise_mag = np.linalg.norm(noise, ord=2) - scale = wav_mag / (10 ** (float(snr) / 20)) - noise = noise / noise_mag * scale - check_snr = 20 * np.log10(np.linalg.norm(wav, ord=2) / np.linalg.norm(noise, ord=2)) - if abs(check_snr - snr) >= 1e-2: - print("SNR: {:.4f}, real SNR: {:.4f}".format(snr, check_snr)) - return wav + noise - - -def calc_labels(rttms, args): - turns = [] - total_length = 0 - for spk, st, dur in rttms: - if args.random_interval: - # random shift the interval with 20% of duration - x = random.uniform(-dur*0.2, dur*0.2) - st = max(0, st + x) - # random squeeze or extend the interval - dur += random.uniform(-dur*0.5, dur*0.5) - if st + dur > total_length: - total_length = st + dur - turns.append([spk, st, dur]) - - # resort the turns according start point - turns = sorted(turns, key=lambda x: x[1]) - - spk_list = [] - for spk, st, dur in turns: - if spk not in spk_list: - spk_list.append(spk) - - total_length = int(total_length * args.sr) - labels = np.zeros((len(spk_list), total_length), float) - for spk, org_st, org_dur in turns: - # random re-assign speaker to make more various samples - st, dur = int(org_st * args.sr), int(org_dur * args.sr) - if args.random_assign_spk: - spk = random.choice(spk_list) - spk_id = spk_list.index(spk) - labels[spk_id, st:st+dur] = 1.0 - - new_turns = [] - for i in range(len(spk_list)): - st = 0 - in_interval = False - for j in range(total_length): - if labels[i, j] == 1 and not in_interval: - in_interval = True - st = j - if (labels[i, j] == 0 or j == total_length-1) and in_interval: - in_interval = False - new_turns.append((spk_list[i], float(st) / args.sr, float(j - st) / args.sr)) - new_turns = sorted(new_turns, key=lambda x: x[1]) - - return labels, spk_list, new_turns - - -def save_wav(data, wav_path, sr): - if np.max(np.abs(data)).item() > 32767: - data = data / np.max(np.abs(data)) * 0.9 * 32767 - sf.write(wav_path, data.astype(np.int16), sr, "PCM_16", "LITTLE", "WAV", True) - - -def build(mid, meeting2rttm, spk2wav, noise_scp, room2rirs, args): - mid = "m{:05d}".format(mid+1) - if args.corpus_name is not None: - mid = args.corpus_name + "_" + mid - org_reco_id = random.choice(meeting2rttm.keys()) - rttms = meeting2rttm[org_reco_id] - labels, org_spk_list, org_turns = calc_labels(rttms, args) - n_spk = len(org_spk_list) - - expected_length = labels.shape[1] - meeting_spk_list = random.sample(spk2wav.keys(), n_spk) - spk_mask = (np.sum(labels, axis=1) > 0).astype(int) - pos_spk_list = [spk for spk, mask in zip(meeting_spk_list, spk_mask) if mask == 1] - noise_id, noise_path = random.choice(noise_scp) - noise_wav = librosa.load(noise_path, args.sr, True)[0] * 32767 - snr = random.choice(args.snr_list) - room_id = random.choice(room2rirs.keys()) - # different speakers can locate at the same position a.k.a. the same rir. - rir_list = [random.choice(room2rirs[room_id]) for _ in range(n_spk)] - - mata = { - "id": mid, - "num_spk": n_spk, - "pos_spk": pos_spk_list, - "spk_list": meeting_spk_list, - "seg_info": [], - "noise": noise_id, - "snr": snr, - "length": expected_length, - "meeting_info": org_reco_id, - "room_id": room_id - } - sig = np.zeros((expected_length, ), dtype=np.float32) - for i, spk in enumerate(meeting_spk_list): - if spk in pos_spk_list: - wav = librosa.load(spk2wav[spk], args.sr, True)[0] * 32767 - if len(wav) <= expected_length: - # NOTE: to repeat an array, use np.tile rather than np.repeats - wav = np.tile(wav, expected_length // len(wav) + 1) - spk_st = np.random.randint(0, len(wav) - expected_length) - spk_sig = wav[spk_st: spk_st+expected_length] - spk_sig = spk_sig * labels[i, :] - rir_wav = librosa.load(rir_list[i][1], args.sr, True)[0] * 32767 - spk_sig = np.convolve(spk_sig, rir_wav, "full")[:expected_length] - mata["seg_info"].append([spk, spk_st, rir_list[i][0]]) - sig += spk_sig - - mix = mix_wav_noise(sig, noise_wav, snr) - if np.max(np.abs(mix)).item() > 32767: - mix = mix / np.max(np.abs(mix)) * 0.9 * 32767 - save_path = os.path.join(args.out_dir, "{}.wav".format(mid)) - sf.write(save_path, mix.astype(np.int16), args.sr, "PCM_16", "LITTLE", "WAV", True) - - rttm_file = open(os.path.join(args.out_dir, "{}.rttm".format(mid)), "wt") - for spk, st, dur in org_turns: - rttm_file.write("SPEAKER {} 0 {:.3f} {:.3f} {} {}".format( - mid, st, dur, meeting_spk_list[org_spk_list.index(spk)], os.linesep)) - rttm_file.close() - - return mata, mix, labels - - -def filter_spk_num(meeting2rttm, reco2num_spk, spk_num): - meeting_list = meeting2rttm.keys() - filtered_list = list(filter(lambda x: int(reco2num_spk[x]) == spk_num, meeting_list)) - new_dict = {key: meeting2rttm[key] for key in filtered_list} - print("Keep {} out of {} according to speaker number {}".format(len(new_dict), len(meeting2rttm), spk_num)) - return new_dict - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("dir", type=str) - parser.add_argument("out_dir", type=str) - parser.add_argument("--total_mix", type=int, default=1) - parser.add_argument("--sr", type=int, default=8000) - parser.add_argument("--snr_list", type=int, default=[15, 20, 25], nargs="+") - parser.add_argument("--spk_num", type=int, default=0) - - parser.add_argument("--corpus_name", type=str, default=None) - parser.add_argument("--task_id", type=int, default=0) - parser.add_argument("--no_bar", action="store_true", default=False) - parser.add_argument("--verbose", action="store_true", default=False) - parser.add_argument("--debug", action="store_true", default=False) - parser.add_argument("--random_assign_spk", action="store_true", default=False) - parser.add_argument("--random_interval", action="store_true", default=False) - args = parser.parse_args() - assert args.sr == 8000, "For callhome dataset, the sample rate should be 8000, use --sr 8000." - - # SPEAKER iaaa 0 0 1.08 B - meeting2rttm = {} - for one_line in open(os.path.join(args.dir, "ref.rttm")): - parts = one_line.strip().split(" ") - mid, spk, st, dur = parts[1], parts[7], float(parts[3]), float(parts[4]) - if mid not in meeting2rttm: - meeting2rttm[mid] = [] - meeting2rttm[mid].append((spk, st, dur)) - reco2num_spk = load_scp_as_dict(os.path.join(args.dir, "reco2num_spk")) - if args.spk_num > 1: - meeting2rttm = filter_spk_num(meeting2rttm, reco2num_spk, args.spk_num) - - spk2wav = load_scp_as_dict(os.path.join(args.dir, "spk2wav.scp")) - noise_scp = load_scp_as_list(os.path.join(args.dir, "noise.scp")) - rirs_scp = load_scp_as_list(os.path.join(args.dir, "rirs.scp")) - room2rirs = {} - for rir_id, rir_path in rirs_scp: - room_id = rir_id.rsplit("-", 1)[0] - if room_id not in room2rirs: - room2rirs[room_id] = [] - room2rirs[room_id].append((rir_id, rir_path)) - - if not os.path.exists(args.out_dir): - os.makedirs(args.out_dir) - task_list = list(range(args.task_id * args.total_mix, (args.task_id + 1) * args.total_mix)) - - mata_data = [] - total = 0 - if args.debug: - one, wav, label = build(0, meeting2rttm, spk2wav, noise_scp, room2rirs, args) - mata_data.append(one) - else: - for mid in tqdm(task_list, total=len(task_list), ascii=True, disable=args.no_bar): - one, wav, label = build(mid, meeting2rttm, spk2wav, noise_scp, room2rirs, args) - mata_data.append(one) - total += one["length"] - if args.verbose: - print("File name: {:20s}, segment num: {:5d}, speaker num: {:2d}, duration: {:7.2f}m".format( - one["id"], len(one["seg_info"]), one["num_spk"], float(one["length"]) / args.sr / 60)) - print("Total files: {}, Total duration: {:.2f} hours".format(args.total_mix, (1.0 * total / args.sr / 3600))) - json.dump(mata_data, open(os.path.join(args.out_dir, "mata.{}.json".format(args.task_id)), "wt"), - ensure_ascii=False, encoding='utf-8', indent=4, sort_keys=True) - - -if __name__ == '__main__': - main() diff --git a/egs/callhome/TOLD/soap/unit_test/sond.yaml b/egs/callhome/TOLD/soap/unit_test/sond.yaml deleted file mode 100644 index 868163f0a..000000000 --- a/egs/callhome/TOLD/soap/unit_test/sond.yaml +++ /dev/null @@ -1,2739 +0,0 @@ -config: finetune.yaml -print_config: false -log_level: INFO -dry_run: false -iterator_type: sequence -output_dir: exp/sond -ngpu: 1 -seed: 0 -num_workers: 16 -num_att_plot: 0 -dist_backend: nccl -dist_init_method: env:// -dist_world_size: null -dist_rank: null -local_rank: 0 -dist_master_addr: null -dist_master_port: null -dist_launcher: null -multiprocessing_distributed: true -distributed: false -unused_parameters: true -sharded_ddp: false -ddp_backend: pytorch_ddp -cudnn_enabled: true -cudnn_benchmark: false -cudnn_deterministic: true -collect_stats: false -write_collected_feats: false -max_epoch: 50 -patience: null -val_scheduler_criterion: -- valid -- acc -early_stopping_criterion: -- valid -- loss -- min -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 -nbest_averaging_interval: 0 -grad_clip: 5 -grad_clip_type: 2.0 -grad_noise: false -accum_grad: 1 -no_forward_run: false -resume: true -train_dtype: float32 -use_amp: false -log_interval: 50 -use_matplotlib: false -use_tensorboard: true -use_wandb: false -wandb_project: null -wandb_id: null -wandb_entity: null -wandb_name: null -wandb_model_log_interval: -1 -use_pai: true -detect_anomaly: false -pretrain_path: null -init_param: [] -ignore_init_mismatch: false -freeze_param: [] -num_iters_per_epoch: null -batch_size: 20 -valid_batch_size: null -batch_bins: 10000 -valid_batch_bins: null -train_shape_file: -- /data/volume1/youyan/aishell/ark/train/speech_shape.1 -- /data/volume1/youyan/aishell/ark/train/text_shape.1 -valid_shape_file: -- /data/volume1/youyan/aishell/ark/dev/speech_shape.1 -- /data/volume1/youyan/aishell/ark/dev/text_shape.1 -batch_type: length -valid_batch_type: null -fold_length: -- 512 -- 150 -sort_in_batch: descending -sort_batch: descending -multiple_iterator: false -chunk_length: 500 -chunk_shift_ratio: 0.5 -num_cache_chunks: 1024 -train_data_path_and_name_and_type: -- - /data/volume1/youyan/aishell/ark/train/data.scp - - speech - - kaldi_ark -- - /data/volume1/youyan/aishell/ark/train/data.text.1 - - text - - text -valid_data_path_and_name_and_type: -- - /data/volume1/youyan/aishell/ark/dev/data.scp - - speech - - kaldi_ark -- - /data/volume1/youyan/aishell/ark/dev/data.text.1 - - text - - text -allow_variable_data_keys: false -max_cache_size: 0.0 -max_cache_fd: 32 -valid_max_cache_size: null -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 -token_list: -- '0' -- '1' -- '2' -- '3' -- '4' -- '5' -- '6' -- '7' -- '8' -- '9' -- '10' -- '11' -- '12' -- '13' -- '14' -- '15' -- '16' -- '17' -- '18' -- '19' -- '20' -- '21' -- '22' -- '23' -- '24' -- '25' -- '26' -- '27' -- '28' -- '29' -- '30' -- '32' -- '33' -- '34' -- '35' -- '36' -- '37' -- '38' -- '39' -- '40' -- '41' -- '42' -- '43' -- '44' -- '45' -- '46' -- '48' -- '49' -- '50' -- '51' -- '52' -- '53' -- '54' -- '56' -- '57' -- '58' -- '60' -- '64' -- '65' -- '66' -- '67' -- '68' -- '69' -- '70' -- '71' -- '72' -- '73' -- '74' -- '75' -- '76' -- '77' -- '78' -- '80' -- '81' -- '82' -- '83' -- '84' -- '85' -- '86' -- '88' -- '89' -- '90' -- '92' -- '96' -- '97' -- '98' -- '99' -- '100' -- '101' -- '102' -- '104' -- '105' -- '106' -- '108' -- '112' -- '113' -- '114' -- '116' -- '120' -- '128' -- '129' -- '130' -- '131' -- '132' -- '133' -- '134' -- '135' -- '136' -- '137' -- '138' -- '139' -- '140' -- '141' -- '142' -- '144' -- '145' -- '146' -- '147' -- '148' -- '149' -- '150' -- '152' -- '153' -- '154' -- '156' -- '160' -- '161' -- '162' -- '163' -- '164' -- '165' -- '166' -- '168' -- '169' -- '170' -- '172' -- '176' -- '177' -- '178' -- '180' -- '184' -- '192' -- '193' -- '194' -- '195' -- '196' -- '197' -- '198' -- '200' -- '201' -- '202' -- '204' -- '208' -- '209' -- '210' -- '212' -- '216' -- '224' -- '225' -- '226' -- '228' -- '232' -- '240' -- '256' -- '257' -- '258' -- '259' -- '260' -- '261' -- '262' -- '263' -- '264' -- '265' -- '266' -- '267' -- '268' -- '269' -- '270' -- '272' -- '273' -- '274' -- '275' -- '276' -- '277' -- '278' -- '280' -- '281' -- '282' -- '284' -- '288' -- '289' -- '290' -- '291' -- '292' -- '293' -- '294' -- '296' -- '297' -- '298' -- '300' -- '304' -- '305' -- '306' -- '308' -- '312' -- '320' -- '321' -- '322' -- '323' -- '324' -- '325' -- '326' -- '328' -- '329' -- '330' -- '332' -- '336' -- '337' -- '338' -- '340' -- '344' -- '352' -- '353' -- '354' -- '356' -- '360' -- '368' -- '384' -- '385' -- '386' -- '387' -- '388' -- '389' -- '390' -- '392' -- '393' -- '394' -- '396' -- '400' -- '401' -- '402' -- '404' -- '408' -- '416' -- '417' -- '418' -- '420' -- '424' -- '432' -- '448' -- '449' -- '450' -- '452' -- '456' -- '464' -- '480' -- '512' -- '513' -- '514' -- '515' -- '516' -- '517' -- '518' -- '519' -- '520' -- '521' -- '522' -- '523' -- '524' -- '525' -- '526' -- '528' -- '529' -- '530' -- '531' -- '532' -- '533' -- '534' -- '536' -- '537' -- '538' -- '540' -- '544' -- '545' -- '546' -- '547' -- '548' -- '549' -- '550' -- '552' -- '553' -- '554' -- '556' -- '560' -- '561' -- '562' -- '564' -- '568' -- '576' -- '577' -- '578' -- '579' -- '580' -- '581' -- '582' -- '584' -- '585' -- '586' -- '588' -- '592' -- '593' -- '594' -- '596' -- '600' -- '608' -- '609' -- '610' -- '612' -- '616' -- '624' -- '640' -- '641' -- '642' -- '643' -- '644' -- '645' -- '646' -- '648' -- '649' -- '650' -- '652' -- '656' -- '657' -- '658' -- '660' -- '664' -- '672' -- '673' -- '674' -- '676' -- '680' -- '688' -- '704' -- '705' -- '706' -- '708' -- '712' -- '720' -- '736' -- '768' -- '769' -- '770' -- '771' -- '772' -- '773' -- '774' -- '776' -- '777' -- '778' -- '780' -- '784' -- '785' -- '786' -- '788' -- '792' -- '800' -- '801' -- '802' -- '804' -- '808' -- '816' -- '832' -- '833' -- '834' -- '836' -- '840' -- '848' -- '864' -- '896' -- '897' -- '898' -- '900' -- '904' -- '912' -- '928' -- '960' -- '1024' -- '1025' -- '1026' -- '1027' -- '1028' -- '1029' -- '1030' -- '1031' -- '1032' -- '1033' -- '1034' -- '1035' -- '1036' -- '1037' -- '1038' -- '1040' -- '1041' -- '1042' -- '1043' -- '1044' -- '1045' -- '1046' -- '1048' -- '1049' -- '1050' -- '1052' -- '1056' -- '1057' -- '1058' -- '1059' -- '1060' -- '1061' -- '1062' -- '1064' -- '1065' -- '1066' -- '1068' -- '1072' -- '1073' -- '1074' -- '1076' -- '1080' -- '1088' -- '1089' -- '1090' -- '1091' -- '1092' -- '1093' -- '1094' -- '1096' -- '1097' -- '1098' -- '1100' -- '1104' -- '1105' -- '1106' -- '1108' -- '1112' -- '1120' -- '1121' -- '1122' -- '1124' -- '1128' -- '1136' -- '1152' -- '1153' -- '1154' -- '1155' -- '1156' -- '1157' -- '1158' -- '1160' -- '1161' -- '1162' -- '1164' -- '1168' -- '1169' -- '1170' -- '1172' -- '1176' -- '1184' -- '1185' -- '1186' -- '1188' -- '1192' -- '1200' -- '1216' -- '1217' -- '1218' -- '1220' -- '1224' -- '1232' -- '1248' -- '1280' -- '1281' -- '1282' -- '1283' -- '1284' -- '1285' -- '1286' -- '1288' -- '1289' -- '1290' -- '1292' -- '1296' -- '1297' -- '1298' -- '1300' -- '1304' -- '1312' -- '1313' -- '1314' -- '1316' -- '1320' -- '1328' -- '1344' -- '1345' -- '1346' -- '1348' -- '1352' -- '1360' -- '1376' -- '1408' -- '1409' -- '1410' -- '1412' -- '1416' -- '1424' -- '1440' -- '1472' -- '1536' -- '1537' -- '1538' -- '1539' -- '1540' -- '1541' -- '1542' -- '1544' -- '1545' -- '1546' -- '1548' -- '1552' -- '1553' -- '1554' -- '1556' -- '1560' -- '1568' -- '1569' -- '1570' -- '1572' -- '1576' -- '1584' -- '1600' -- '1601' -- '1602' -- '1604' -- '1608' -- '1616' -- '1632' -- '1664' -- '1665' -- '1666' -- '1668' -- '1672' -- '1680' -- '1696' -- '1728' -- '1792' -- '1793' -- '1794' -- '1796' -- '1800' -- '1808' -- '1824' -- '1856' -- '1920' -- '2048' -- '2049' -- '2050' -- '2051' -- '2052' -- '2053' -- '2054' -- '2055' -- '2056' -- '2057' -- '2058' -- '2059' -- '2060' -- '2061' -- '2062' -- '2064' -- '2065' -- '2066' -- '2067' -- '2068' -- '2069' -- '2070' -- '2072' -- '2073' -- '2074' -- '2076' -- '2080' -- '2081' -- '2082' -- '2083' -- '2084' -- '2085' -- '2086' -- '2088' -- '2089' -- '2090' -- '2092' -- '2096' -- '2097' -- '2098' -- '2100' -- '2104' -- '2112' -- '2113' -- '2114' -- '2115' -- '2116' -- '2117' -- '2118' -- '2120' -- '2121' -- '2122' -- '2124' -- '2128' -- '2129' -- '2130' -- '2132' -- '2136' -- '2144' -- '2145' -- '2146' -- '2148' -- '2152' -- '2160' -- '2176' -- '2177' -- '2178' -- '2179' -- '2180' -- '2181' -- '2182' -- '2184' -- '2185' -- '2186' -- '2188' -- '2192' -- '2193' -- '2194' -- '2196' -- '2200' -- '2208' -- '2209' -- '2210' -- '2212' -- '2216' -- '2224' -- '2240' -- '2241' -- '2242' -- '2244' -- '2248' -- '2256' -- '2272' -- '2304' -- '2305' -- '2306' -- '2307' -- '2308' -- '2309' -- '2310' -- '2312' -- '2313' -- '2314' -- '2316' -- '2320' -- '2321' -- '2322' -- '2324' -- '2328' -- '2336' -- '2337' -- '2338' -- '2340' -- '2344' -- '2352' -- '2368' -- '2369' -- '2370' -- '2372' -- '2376' -- '2384' -- '2400' -- '2432' -- '2433' -- '2434' -- '2436' -- '2440' -- '2448' -- '2464' -- '2496' -- '2560' -- '2561' -- '2562' -- '2563' -- '2564' -- '2565' -- '2566' -- '2568' -- '2569' -- '2570' -- '2572' -- '2576' -- '2577' -- '2578' -- '2580' -- '2584' -- '2592' -- '2593' -- '2594' -- '2596' -- '2600' -- '2608' -- '2624' -- '2625' -- '2626' -- '2628' -- '2632' -- '2640' -- '2656' -- '2688' -- '2689' -- '2690' -- '2692' -- '2696' -- '2704' -- '2720' -- '2752' -- '2816' -- '2817' -- '2818' -- '2820' -- '2824' -- '2832' -- '2848' -- '2880' -- '2944' -- '3072' -- '3073' -- '3074' -- '3075' -- '3076' -- '3077' -- '3078' -- '3080' -- '3081' -- '3082' -- '3084' -- '3088' -- '3089' -- '3090' -- '3092' -- '3096' -- '3104' -- '3105' -- '3106' -- '3108' -- '3112' -- '3120' -- '3136' -- '3137' -- '3138' -- '3140' -- '3144' -- '3152' -- '3168' -- '3200' -- '3201' -- '3202' -- '3204' -- '3208' -- '3216' -- '3232' -- '3264' -- '3328' -- '3329' -- '3330' -- '3332' -- '3336' -- '3344' -- '3360' -- '3392' -- '3456' -- '3584' -- '3585' -- '3586' -- '3588' -- '3592' -- '3600' -- '3616' -- '3648' -- '3712' -- '3840' -- '4096' -- '4097' -- '4098' -- '4099' -- '4100' -- '4101' -- '4102' -- '4103' -- '4104' -- '4105' -- '4106' -- '4107' -- '4108' -- '4109' -- '4110' -- '4112' -- '4113' -- '4114' -- '4115' -- '4116' -- '4117' -- '4118' -- '4120' -- '4121' -- '4122' -- '4124' -- '4128' -- '4129' -- '4130' -- '4131' -- '4132' -- '4133' -- '4134' -- '4136' -- '4137' -- '4138' -- '4140' -- '4144' -- '4145' -- '4146' -- '4148' -- '4152' -- '4160' -- '4161' -- '4162' -- '4163' -- '4164' -- '4165' -- '4166' -- '4168' -- '4169' -- '4170' -- '4172' -- '4176' -- '4177' -- '4178' -- '4180' -- '4184' -- '4192' -- '4193' -- '4194' -- '4196' -- '4200' -- '4208' -- '4224' -- '4225' -- '4226' -- '4227' -- '4228' -- '4229' -- '4230' -- '4232' -- '4233' -- '4234' -- '4236' -- '4240' -- '4241' -- '4242' -- '4244' -- '4248' -- '4256' -- '4257' -- '4258' -- '4260' -- '4264' -- '4272' -- '4288' -- '4289' -- '4290' -- '4292' -- '4296' -- '4304' -- '4320' -- '4352' -- '4353' -- '4354' -- '4355' -- '4356' -- '4357' -- '4358' -- '4360' -- '4361' -- '4362' -- '4364' -- '4368' -- '4369' -- '4370' -- '4372' -- '4376' -- '4384' -- '4385' -- '4386' -- '4388' -- '4392' -- '4400' -- '4416' -- '4417' -- '4418' -- '4420' -- '4424' -- '4432' -- '4448' -- '4480' -- '4481' -- '4482' -- '4484' -- '4488' -- '4496' -- '4512' -- '4544' -- '4608' -- '4609' -- '4610' -- '4611' -- '4612' -- '4613' -- '4614' -- '4616' -- '4617' -- '4618' -- '4620' -- '4624' -- '4625' -- '4626' -- '4628' -- '4632' -- '4640' -- '4641' -- '4642' -- '4644' -- '4648' -- '4656' -- '4672' -- '4673' -- '4674' -- '4676' -- '4680' -- '4688' -- '4704' -- '4736' -- '4737' -- '4738' -- '4740' -- '4744' -- '4752' -- '4768' -- '4800' -- '4864' -- '4865' -- '4866' -- '4868' -- '4872' -- '4880' -- '4896' -- '4928' -- '4992' -- '5120' -- '5121' -- '5122' -- '5123' -- '5124' -- '5125' -- '5126' -- '5128' -- '5129' -- '5130' -- '5132' -- '5136' -- '5137' -- '5138' -- '5140' -- '5144' -- '5152' -- '5153' -- '5154' -- '5156' -- '5160' -- '5168' -- '5184' -- '5185' -- '5186' -- '5188' -- '5192' -- '5200' -- '5216' -- '5248' -- '5249' -- '5250' -- '5252' -- '5256' -- '5264' -- '5280' -- '5312' -- '5376' -- '5377' -- '5378' -- '5380' -- '5384' -- '5392' -- '5408' -- '5440' -- '5504' -- '5632' -- '5633' -- '5634' -- '5636' -- '5640' -- '5648' -- '5664' -- '5696' -- '5760' -- '5888' -- '6144' -- '6145' -- '6146' -- '6147' -- '6148' -- '6149' -- '6150' -- '6152' -- '6153' -- '6154' -- '6156' -- '6160' -- '6161' -- '6162' -- '6164' -- '6168' -- '6176' -- '6177' -- '6178' -- '6180' -- '6184' -- '6192' -- '6208' -- '6209' -- '6210' -- '6212' -- '6216' -- '6224' -- '6240' -- '6272' -- '6273' -- '6274' -- '6276' -- '6280' -- '6288' -- '6304' -- '6336' -- '6400' -- '6401' -- '6402' -- '6404' -- '6408' -- '6416' -- '6432' -- '6464' -- '6528' -- '6656' -- '6657' -- '6658' -- '6660' -- '6664' -- '6672' -- '6688' -- '6720' -- '6784' -- '6912' -- '7168' -- '7169' -- '7170' -- '7172' -- '7176' -- '7184' -- '7200' -- '7232' -- '7296' -- '7424' -- '7680' -- '8192' -- '8193' -- '8194' -- '8195' -- '8196' -- '8197' -- '8198' -- '8199' -- '8200' -- '8201' -- '8202' -- '8203' -- '8204' -- '8205' -- '8206' -- '8208' -- '8209' -- '8210' -- '8211' -- '8212' -- '8213' -- '8214' -- '8216' -- '8217' -- '8218' -- '8220' -- '8224' -- '8225' -- '8226' -- '8227' -- '8228' -- '8229' -- '8230' -- '8232' -- '8233' -- '8234' -- '8236' -- '8240' -- '8241' -- '8242' -- '8244' -- '8248' -- '8256' -- '8257' -- '8258' -- '8259' -- '8260' -- '8261' -- '8262' -- '8264' -- '8265' -- '8266' -- '8268' -- '8272' -- '8273' -- '8274' -- '8276' -- '8280' -- '8288' -- '8289' -- '8290' -- '8292' -- '8296' -- '8304' -- '8320' -- '8321' -- '8322' -- '8323' -- '8324' -- '8325' -- '8326' -- '8328' -- '8329' -- '8330' -- '8332' -- '8336' -- '8337' -- '8338' -- '8340' -- '8344' -- '8352' -- '8353' -- '8354' -- '8356' -- '8360' -- '8368' -- '8384' -- '8385' -- '8386' -- '8388' -- '8392' -- '8400' -- '8416' -- '8448' -- '8449' -- '8450' -- '8451' -- '8452' -- '8453' -- '8454' -- '8456' -- '8457' -- '8458' -- '8460' -- '8464' -- '8465' -- '8466' -- '8468' -- '8472' -- '8480' -- '8481' -- '8482' -- '8484' -- '8488' -- '8496' -- '8512' -- '8513' -- '8514' -- '8516' -- '8520' -- '8528' -- '8544' -- '8576' -- '8577' -- '8578' -- '8580' -- '8584' -- '8592' -- '8608' -- '8640' -- '8704' -- '8705' -- '8706' -- '8707' -- '8708' -- '8709' -- '8710' -- '8712' -- '8713' -- '8714' -- '8716' -- '8720' -- '8721' -- '8722' -- '8724' -- '8728' -- '8736' -- '8737' -- '8738' -- '8740' -- '8744' -- '8752' -- '8768' -- '8769' -- '8770' -- '8772' -- '8776' -- '8784' -- '8800' -- '8832' -- '8833' -- '8834' -- '8836' -- '8840' -- '8848' -- '8864' -- '8896' -- '8960' -- '8961' -- '8962' -- '8964' -- '8968' -- '8976' -- '8992' -- '9024' -- '9088' -- '9216' -- '9217' -- '9218' -- '9219' -- '9220' -- '9221' -- '9222' -- '9224' -- '9225' -- '9226' -- '9228' -- '9232' -- '9233' -- '9234' -- '9236' -- '9240' -- '9248' -- '9249' -- '9250' -- '9252' -- '9256' -- '9264' -- '9280' -- '9281' -- '9282' -- '9284' -- '9288' -- '9296' -- '9312' -- '9344' -- '9345' -- '9346' -- '9348' -- '9352' -- '9360' -- '9376' -- '9408' -- '9472' -- '9473' -- '9474' -- '9476' -- '9480' -- '9488' -- '9504' -- '9536' -- '9600' -- '9728' -- '9729' -- '9730' -- '9732' -- '9736' -- '9744' -- '9760' -- '9792' -- '9856' -- '9984' -- '10240' -- '10241' -- '10242' -- '10243' -- '10244' -- '10245' -- '10246' -- '10248' -- '10249' -- '10250' -- '10252' -- '10256' -- '10257' -- '10258' -- '10260' -- '10264' -- '10272' -- '10273' -- '10274' -- '10276' -- '10280' -- '10288' -- '10304' -- '10305' -- '10306' -- '10308' -- '10312' -- '10320' -- '10336' -- '10368' -- '10369' -- '10370' -- '10372' -- '10376' -- '10384' -- '10400' -- '10432' -- '10496' -- '10497' -- '10498' -- '10500' -- '10504' -- '10512' -- '10528' -- '10560' -- '10624' -- '10752' -- '10753' -- '10754' -- '10756' -- '10760' -- '10768' -- '10784' -- '10816' -- '10880' -- '11008' -- '11264' -- '11265' -- '11266' -- '11268' -- '11272' -- '11280' -- '11296' -- '11328' -- '11392' -- '11520' -- '11776' -- '12288' -- '12289' -- '12290' -- '12291' -- '12292' -- '12293' -- '12294' -- '12296' -- '12297' -- '12298' -- '12300' -- '12304' -- '12305' -- '12306' -- '12308' -- '12312' -- '12320' -- '12321' -- '12322' -- '12324' -- '12328' -- '12336' -- '12352' -- '12353' -- '12354' -- '12356' -- '12360' -- '12368' -- '12384' -- '12416' -- '12417' -- '12418' -- '12420' -- '12424' -- '12432' -- '12448' -- '12480' -- '12544' -- '12545' -- '12546' -- '12548' -- '12552' -- '12560' -- '12576' -- '12608' -- '12672' -- '12800' -- '12801' -- '12802' -- '12804' -- '12808' -- '12816' -- '12832' -- '12864' -- '12928' -- '13056' -- '13312' -- '13313' -- '13314' -- '13316' -- '13320' -- '13328' -- '13344' -- '13376' -- '13440' -- '13568' -- '13824' -- '14336' -- '14337' -- '14338' -- '14340' -- '14344' -- '14352' -- '14368' -- '14400' -- '14464' -- '14592' -- '14848' -- '15360' -- '16384' -- '16385' -- '16386' -- '16387' -- '16388' -- '16389' -- '16390' -- '16391' -- '16392' -- '16393' -- '16394' -- '16395' -- '16396' -- '16397' -- '16398' -- '16400' -- '16401' -- '16402' -- '16403' -- '16404' -- '16405' -- '16406' -- '16408' -- '16409' -- '16410' -- '16412' -- '16416' -- '16417' -- '16418' -- '16419' -- '16420' -- '16421' -- '16422' -- '16424' -- '16425' -- '16426' -- '16428' -- '16432' -- '16433' -- '16434' -- '16436' -- '16440' -- '16448' -- '16449' -- '16450' -- '16451' -- '16452' -- '16453' -- '16454' -- '16456' -- '16457' -- '16458' -- '16460' -- '16464' -- '16465' -- '16466' -- '16468' -- '16472' -- '16480' -- '16481' -- '16482' -- '16484' -- '16488' -- '16496' -- '16512' -- '16513' -- '16514' -- '16515' -- '16516' -- '16517' -- '16518' -- '16520' -- '16521' -- '16522' -- '16524' -- '16528' -- '16529' -- '16530' -- '16532' -- '16536' -- '16544' -- '16545' -- '16546' -- '16548' -- '16552' -- '16560' -- '16576' -- '16577' -- '16578' -- '16580' -- '16584' -- '16592' -- '16608' -- '16640' -- '16641' -- '16642' -- '16643' -- '16644' -- '16645' -- '16646' -- '16648' -- '16649' -- '16650' -- '16652' -- '16656' -- '16657' -- '16658' -- '16660' -- '16664' -- '16672' -- '16673' -- '16674' -- '16676' -- '16680' -- '16688' -- '16704' -- '16705' -- '16706' -- '16708' -- '16712' -- '16720' -- '16736' -- '16768' -- '16769' -- '16770' -- '16772' -- '16776' -- '16784' -- '16800' -- '16832' -- '16896' -- '16897' -- '16898' -- '16899' -- '16900' -- '16901' -- '16902' -- '16904' -- '16905' -- '16906' -- '16908' -- '16912' -- '16913' -- '16914' -- '16916' -- '16920' -- '16928' -- '16929' -- '16930' -- '16932' -- '16936' -- '16944' -- '16960' -- '16961' -- '16962' -- '16964' -- '16968' -- '16976' -- '16992' -- '17024' -- '17025' -- '17026' -- '17028' -- '17032' -- '17040' -- '17056' -- '17088' -- '17152' -- '17153' -- '17154' -- '17156' -- '17160' -- '17168' -- '17184' -- '17216' -- '17280' -- '17408' -- '17409' -- '17410' -- '17411' -- '17412' -- '17413' -- '17414' -- '17416' -- '17417' -- '17418' -- '17420' -- '17424' -- '17425' -- '17426' -- '17428' -- '17432' -- '17440' -- '17441' -- '17442' -- '17444' -- '17448' -- '17456' -- '17472' -- '17473' -- '17474' -- '17476' -- '17480' -- '17488' -- '17504' -- '17536' -- '17537' -- '17538' -- '17540' -- '17544' -- '17552' -- '17568' -- '17600' -- '17664' -- '17665' -- '17666' -- '17668' -- '17672' -- '17680' -- '17696' -- '17728' -- '17792' -- '17920' -- '17921' -- '17922' -- '17924' -- '17928' -- '17936' -- '17952' -- '17984' -- '18048' -- '18176' -- '18432' -- '18433' -- '18434' -- '18435' -- '18436' -- '18437' -- '18438' -- '18440' -- '18441' -- '18442' -- '18444' -- '18448' -- '18449' -- '18450' -- '18452' -- '18456' -- '18464' -- '18465' -- '18466' -- '18468' -- '18472' -- '18480' -- '18496' -- '18497' -- '18498' -- '18500' -- '18504' -- '18512' -- '18528' -- '18560' -- '18561' -- '18562' -- '18564' -- '18568' -- '18576' -- '18592' -- '18624' -- '18688' -- '18689' -- '18690' -- '18692' -- '18696' -- '18704' -- '18720' -- '18752' -- '18816' -- '18944' -- '18945' -- '18946' -- '18948' -- '18952' -- '18960' -- '18976' -- '19008' -- '19072' -- '19200' -- '19456' -- '19457' -- '19458' -- '19460' -- '19464' -- '19472' -- '19488' -- '19520' -- '19584' -- '19712' -- '19968' -- '20480' -- '20481' -- '20482' -- '20483' -- '20484' -- '20485' -- '20486' -- '20488' -- '20489' -- '20490' -- '20492' -- '20496' -- '20497' -- '20498' -- '20500' -- '20504' -- '20512' -- '20513' -- '20514' -- '20516' -- '20520' -- '20528' -- '20544' -- '20545' -- '20546' -- '20548' -- '20552' -- '20560' -- '20576' -- '20608' -- '20609' -- '20610' -- '20612' -- '20616' -- '20624' -- '20640' -- '20672' -- '20736' -- '20737' -- '20738' -- '20740' -- '20744' -- '20752' -- '20768' -- '20800' -- '20864' -- '20992' -- '20993' -- '20994' -- '20996' -- '21000' -- '21008' -- '21024' -- '21056' -- '21120' -- '21248' -- '21504' -- '21505' -- '21506' -- '21508' -- '21512' -- '21520' -- '21536' -- '21568' -- '21632' -- '21760' -- '22016' -- '22528' -- '22529' -- '22530' -- '22532' -- '22536' -- '22544' -- '22560' -- '22592' -- '22656' -- '22784' -- '23040' -- '23552' -- '24576' -- '24577' -- '24578' -- '24579' -- '24580' -- '24581' -- '24582' -- '24584' -- '24585' -- '24586' -- '24588' -- '24592' -- '24593' -- '24594' -- '24596' -- '24600' -- '24608' -- '24609' -- '24610' -- '24612' -- '24616' -- '24624' -- '24640' -- '24641' -- '24642' -- '24644' -- '24648' -- '24656' -- '24672' -- '24704' -- '24705' -- '24706' -- '24708' -- '24712' -- '24720' -- '24736' -- '24768' -- '24832' -- '24833' -- '24834' -- '24836' -- '24840' -- '24848' -- '24864' -- '24896' -- '24960' -- '25088' -- '25089' -- '25090' -- '25092' -- '25096' -- '25104' -- '25120' -- '25152' -- '25216' -- '25344' -- '25600' -- '25601' -- '25602' -- '25604' -- '25608' -- '25616' -- '25632' -- '25664' -- '25728' -- '25856' -- '26112' -- '26624' -- '26625' -- '26626' -- '26628' -- '26632' -- '26640' -- '26656' -- '26688' -- '26752' -- '26880' -- '27136' -- '27648' -- '28672' -- '28673' -- '28674' -- '28676' -- '28680' -- '28688' -- '28704' -- '28736' -- '28800' -- '28928' -- '29184' -- '29696' -- '30720' -- '32768' -- '32769' -- '32770' -- '32771' -- '32772' -- '32773' -- '32774' -- '32775' -- '32776' -- '32777' -- '32778' -- '32779' -- '32780' -- '32781' -- '32782' -- '32784' -- '32785' -- '32786' -- '32787' -- '32788' -- '32789' -- '32790' -- '32792' -- '32793' -- '32794' -- '32796' -- '32800' -- '32801' -- '32802' -- '32803' -- '32804' -- '32805' -- '32806' -- '32808' -- '32809' -- '32810' -- '32812' -- '32816' -- '32817' -- '32818' -- '32820' -- '32824' -- '32832' -- '32833' -- '32834' -- '32835' -- '32836' -- '32837' -- '32838' -- '32840' -- '32841' -- '32842' -- '32844' -- '32848' -- '32849' -- '32850' -- '32852' -- '32856' -- '32864' -- '32865' -- '32866' -- '32868' -- '32872' -- '32880' -- '32896' -- '32897' -- '32898' -- '32899' -- '32900' -- '32901' -- '32902' -- '32904' -- '32905' -- '32906' -- '32908' -- '32912' -- '32913' -- '32914' -- '32916' -- '32920' -- '32928' -- '32929' -- '32930' -- '32932' -- '32936' -- '32944' -- '32960' -- '32961' -- '32962' -- '32964' -- '32968' -- '32976' -- '32992' -- '33024' -- '33025' -- '33026' -- '33027' -- '33028' -- '33029' -- '33030' -- '33032' -- '33033' -- '33034' -- '33036' -- '33040' -- '33041' -- '33042' -- '33044' -- '33048' -- '33056' -- '33057' -- '33058' -- '33060' -- '33064' -- '33072' -- '33088' -- '33089' -- '33090' -- '33092' -- '33096' -- '33104' -- '33120' -- '33152' -- '33153' -- '33154' -- '33156' -- '33160' -- '33168' -- '33184' -- '33216' -- '33280' -- '33281' -- '33282' -- '33283' -- '33284' -- '33285' -- '33286' -- '33288' -- '33289' -- '33290' -- '33292' -- '33296' -- '33297' -- '33298' -- '33300' -- '33304' -- '33312' -- '33313' -- '33314' -- '33316' -- '33320' -- '33328' -- '33344' -- '33345' -- '33346' -- '33348' -- '33352' -- '33360' -- '33376' -- '33408' -- '33409' -- '33410' -- '33412' -- '33416' -- '33424' -- '33440' -- '33472' -- '33536' -- '33537' -- '33538' -- '33540' -- '33544' -- '33552' -- '33568' -- '33600' -- '33664' -- '33792' -- '33793' -- '33794' -- '33795' -- '33796' -- '33797' -- '33798' -- '33800' -- '33801' -- '33802' -- '33804' -- '33808' -- '33809' -- '33810' -- '33812' -- '33816' -- '33824' -- '33825' -- '33826' -- '33828' -- '33832' -- '33840' -- '33856' -- '33857' -- '33858' -- '33860' -- '33864' -- '33872' -- '33888' -- '33920' -- '33921' -- '33922' -- '33924' -- '33928' -- '33936' -- '33952' -- '33984' -- '34048' -- '34049' -- '34050' -- '34052' -- '34056' -- '34064' -- '34080' -- '34112' -- '34176' -- '34304' -- '34305' -- '34306' -- '34308' -- '34312' -- '34320' -- '34336' -- '34368' -- '34432' -- '34560' -- '34816' -- '34817' -- '34818' -- '34819' -- '34820' -- '34821' -- '34822' -- '34824' -- '34825' -- '34826' -- '34828' -- '34832' -- '34833' -- '34834' -- '34836' -- '34840' -- '34848' -- '34849' -- '34850' -- '34852' -- '34856' -- '34864' -- '34880' -- '34881' -- '34882' -- '34884' -- '34888' -- '34896' -- '34912' -- '34944' -- '34945' -- '34946' -- '34948' -- '34952' -- '34960' -- '34976' -- '35008' -- '35072' -- '35073' -- '35074' -- '35076' -- '35080' -- '35088' -- '35104' -- '35136' -- '35200' -- '35328' -- '35329' -- '35330' -- '35332' -- '35336' -- '35344' -- '35360' -- '35392' -- '35456' -- '35584' -- '35840' -- '35841' -- '35842' -- '35844' -- '35848' -- '35856' -- '35872' -- '35904' -- '35968' -- '36096' -- '36352' -- '36864' -- '36865' -- '36866' -- '36867' -- '36868' -- '36869' -- '36870' -- '36872' -- '36873' -- '36874' -- '36876' -- '36880' -- '36881' -- '36882' -- '36884' -- '36888' -- '36896' -- '36897' -- '36898' -- '36900' -- '36904' -- '36912' -- '36928' -- '36929' -- '36930' -- '36932' -- '36936' -- '36944' -- '36960' -- '36992' -- '36993' -- '36994' -- '36996' -- '37000' -- '37008' -- '37024' -- '37056' -- '37120' -- '37121' -- '37122' -- '37124' -- '37128' -- '37136' -- '37152' -- '37184' -- '37248' -- '37376' -- '37377' -- '37378' -- '37380' -- '37384' -- '37392' -- '37408' -- '37440' -- '37504' -- '37632' -- '37888' -- '37889' -- '37890' -- '37892' -- '37896' -- '37904' -- '37920' -- '37952' -- '38016' -- '38144' -- '38400' -- '38912' -- '38913' -- '38914' -- '38916' -- '38920' -- '38928' -- '38944' -- '38976' -- '39040' -- '39168' -- '39424' -- '39936' -- '40960' -- '40961' -- '40962' -- '40963' -- '40964' -- '40965' -- '40966' -- '40968' -- '40969' -- '40970' -- '40972' -- '40976' -- '40977' -- '40978' -- '40980' -- '40984' -- '40992' -- '40993' -- '40994' -- '40996' -- '41000' -- '41008' -- '41024' -- '41025' -- '41026' -- '41028' -- '41032' -- '41040' -- '41056' -- '41088' -- '41089' -- '41090' -- '41092' -- '41096' -- '41104' -- '41120' -- '41152' -- '41216' -- '41217' -- '41218' -- '41220' -- '41224' -- '41232' -- '41248' -- '41280' -- '41344' -- '41472' -- '41473' -- '41474' -- '41476' -- '41480' -- '41488' -- '41504' -- '41536' -- '41600' -- '41728' -- '41984' -- '41985' -- '41986' -- '41988' -- '41992' -- '42000' -- '42016' -- '42048' -- '42112' -- '42240' -- '42496' -- '43008' -- '43009' -- '43010' -- '43012' -- '43016' -- '43024' -- '43040' -- '43072' -- '43136' -- '43264' -- '43520' -- '44032' -- '45056' -- '45057' -- '45058' -- '45060' -- '45064' -- '45072' -- '45088' -- '45120' -- '45184' -- '45312' -- '45568' -- '46080' -- '47104' -- '49152' -- '49153' -- '49154' -- '49155' -- '49156' -- '49157' -- '49158' -- '49160' -- '49161' -- '49162' -- '49164' -- '49168' -- '49169' -- '49170' -- '49172' -- '49176' -- '49184' -- '49185' -- '49186' -- '49188' -- '49192' -- '49200' -- '49216' -- '49217' -- '49218' -- '49220' -- '49224' -- '49232' -- '49248' -- '49280' -- '49281' -- '49282' -- '49284' -- '49288' -- '49296' -- '49312' -- '49344' -- '49408' -- '49409' -- '49410' -- '49412' -- '49416' -- '49424' -- '49440' -- '49472' -- '49536' -- '49664' -- '49665' -- '49666' -- '49668' -- '49672' -- '49680' -- '49696' -- '49728' -- '49792' -- '49920' -- '50176' -- '50177' -- '50178' -- '50180' -- '50184' -- '50192' -- '50208' -- '50240' -- '50304' -- '50432' -- '50688' -- '51200' -- '51201' -- '51202' -- '51204' -- '51208' -- '51216' -- '51232' -- '51264' -- '51328' -- '51456' -- '51712' -- '52224' -- '53248' -- '53249' -- '53250' -- '53252' -- '53256' -- '53264' -- '53280' -- '53312' -- '53376' -- '53504' -- '53760' -- '54272' -- '55296' -- '57344' -- '57345' -- '57346' -- '57348' -- '57352' -- '57360' -- '57376' -- '57408' -- '57472' -- '57600' -- '57856' -- '58368' -- '59392' -- '61440' -init: null -input_size: null -cmvn_file: null -ctc_conf: - dropout_rate: 0.0 - ctc_type: builtin - reduce: true - ignore_nan_grad: true -joint_net_conf: null -use_preprocessor: true -token_type: char -bpemodel: null -non_linguistic_symbols: null -cleaner: null -g2p: null -speech_volume_normalize: null -rir_scp: null -rir_apply_prob: 1.0 -noise_scp: null -noise_apply_prob: 1.0 -noise_db_range: '13_15' -specaug: null -specaug_conf: {} -normalize: null -normalize_conf: {} -label_aggregator: null -label_aggregator_conf: {} -model: sond -model_conf: - lsm_weight: 0.1 - length_normalized_loss: true - max_spk_num: 16 - normalize_speech_speaker: true -# speech encoder -encoder: resnet34_sp_l2reg -encoder_conf: - # pass by model, equal to feature dim - # input_size: 80 - pooling_type: "window_shift" - batchnorm_momentum: 0.01 - pool_size: 20 - stride: 1 - tf2torch_tensor_name_prefix_torch: encoder - tf2torch_tensor_name_prefix_tf: EAND/speech_encoder -speaker_encoder: null -speaker_encoder_conf: {} -ci_scorer: conv -ci_scorer_conf: - input_units: 512 - num_layers: 3 - num_units: 512 - kernel_size: 1 - dropout_rate: 0.0 - position_encoder: null - out_units: 1 - out_norm: false - auxiliary_states: false - tf2torch_tensor_name_prefix_torch: ci_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/ci_scorer -cd_scorer: san -cd_scorer_conf: - input_size: 512 - output_size: 512 - out_units: 1 - attention_heads: 4 - linear_units: 1024 - num_blocks: 4 - dropout_rate: 0.0 - positional_dropout_rate: 0.0 - attention_dropout_rate: 0.0 - # use string "null" to remove input layer - input_layer: "null" - pos_enc_class: null - normalize_before: true - tf2torch_tensor_name_prefix_torch: cd_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/cd_scorer -# post net -decoder: fsmn -decoder_conf: - in_units: 32 - out_units: 2517 - filter_size: 31 - fsmn_num_layers: 6 - dnn_num_layers: 1 - num_memory_units: 16 - ffn_inner_dim: 512 - dropout_rate: 0.0 - tf2torch_tensor_name_prefix_torch: decoder - tf2torch_tensor_name_prefix_tf: EAND/post_net -frontend: wav_frontend -frontend_conf: - fs: 8000 - window: povey - n_mels: 80 - frame_length: 25 - frame_shift: 10 - filter_length_min: -1 - filter_length_max: -1 - lfr_m: 1 - lfr_n: 1 - dither: 0.0 - snip_edges: false - upsacle_samples: false -num_worker_count: 1 -required: -- output_dir -- token_list -oss_bucket: 'null' -version: 0.1.4 diff --git a/egs/callhome/TOLD/soap/unit_test/sond_fbank.yaml b/egs/callhome/TOLD/soap/unit_test/sond_fbank.yaml deleted file mode 100644 index fc76259f4..000000000 --- a/egs/callhome/TOLD/soap/unit_test/sond_fbank.yaml +++ /dev/null @@ -1,2739 +0,0 @@ -config: finetune.yaml -print_config: false -log_level: INFO -dry_run: false -iterator_type: sequence -output_dir: exp/sond -ngpu: 1 -seed: 0 -num_workers: 16 -num_att_plot: 0 -dist_backend: nccl -dist_init_method: env:// -dist_world_size: null -dist_rank: null -local_rank: 0 -dist_master_addr: null -dist_master_port: null -dist_launcher: null -multiprocessing_distributed: true -distributed: false -unused_parameters: true -sharded_ddp: false -ddp_backend: pytorch_ddp -cudnn_enabled: true -cudnn_benchmark: false -cudnn_deterministic: true -collect_stats: false -write_collected_feats: false -max_epoch: 50 -patience: null -val_scheduler_criterion: -- valid -- acc -early_stopping_criterion: -- valid -- loss -- min -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 -nbest_averaging_interval: 0 -grad_clip: 5 -grad_clip_type: 2.0 -grad_noise: false -accum_grad: 1 -no_forward_run: false -resume: true -train_dtype: float32 -use_amp: false -log_interval: 50 -use_matplotlib: false -use_tensorboard: true -use_wandb: false -wandb_project: null -wandb_id: null -wandb_entity: null -wandb_name: null -wandb_model_log_interval: -1 -use_pai: true -detect_anomaly: false -pretrain_path: null -init_param: [] -ignore_init_mismatch: false -freeze_param: [] -num_iters_per_epoch: null -batch_size: 20 -valid_batch_size: null -batch_bins: 10000 -valid_batch_bins: null -train_shape_file: -- /data/volume1/youyan/aishell/ark/train/speech_shape.1 -- /data/volume1/youyan/aishell/ark/train/text_shape.1 -valid_shape_file: -- /data/volume1/youyan/aishell/ark/dev/speech_shape.1 -- /data/volume1/youyan/aishell/ark/dev/text_shape.1 -batch_type: length -valid_batch_type: null -fold_length: -- 512 -- 150 -sort_in_batch: descending -sort_batch: descending -multiple_iterator: false -chunk_length: 500 -chunk_shift_ratio: 0.5 -num_cache_chunks: 1024 -train_data_path_and_name_and_type: -- - /data/volume1/youyan/aishell/ark/train/data.scp - - speech - - kaldi_ark -- - /data/volume1/youyan/aishell/ark/train/data.text.1 - - text - - text -valid_data_path_and_name_and_type: -- - /data/volume1/youyan/aishell/ark/dev/data.scp - - speech - - kaldi_ark -- - /data/volume1/youyan/aishell/ark/dev/data.text.1 - - text - - text -allow_variable_data_keys: false -max_cache_size: 0.0 -max_cache_fd: 32 -valid_max_cache_size: null -optim: adam -optim_conf: - lr: 0.0005 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 -token_list: -- '0' -- '1' -- '2' -- '3' -- '4' -- '5' -- '6' -- '7' -- '8' -- '9' -- '10' -- '11' -- '12' -- '13' -- '14' -- '15' -- '16' -- '17' -- '18' -- '19' -- '20' -- '21' -- '22' -- '23' -- '24' -- '25' -- '26' -- '27' -- '28' -- '29' -- '30' -- '32' -- '33' -- '34' -- '35' -- '36' -- '37' -- '38' -- '39' -- '40' -- '41' -- '42' -- '43' -- '44' -- '45' -- '46' -- '48' -- '49' -- '50' -- '51' -- '52' -- '53' -- '54' -- '56' -- '57' -- '58' -- '60' -- '64' -- '65' -- '66' -- '67' -- '68' -- '69' -- '70' -- '71' -- '72' -- '73' -- '74' -- '75' -- '76' -- '77' -- '78' -- '80' -- '81' -- '82' -- '83' -- '84' -- '85' -- '86' -- '88' -- '89' -- '90' -- '92' -- '96' -- '97' -- '98' -- '99' -- '100' -- '101' -- '102' -- '104' -- '105' -- '106' -- '108' -- '112' -- '113' -- '114' -- '116' -- '120' -- '128' -- '129' -- '130' -- '131' -- '132' -- '133' -- '134' -- '135' -- '136' -- '137' -- '138' -- '139' -- '140' -- '141' -- '142' -- '144' -- '145' -- '146' -- '147' -- '148' -- '149' -- '150' -- '152' -- '153' -- '154' -- '156' -- '160' -- '161' -- '162' -- '163' -- '164' -- '165' -- '166' -- '168' -- '169' -- '170' -- '172' -- '176' -- '177' -- '178' -- '180' -- '184' -- '192' -- '193' -- '194' -- '195' -- '196' -- '197' -- '198' -- '200' -- '201' -- '202' -- '204' -- '208' -- '209' -- '210' -- '212' -- '216' -- '224' -- '225' -- '226' -- '228' -- '232' -- '240' -- '256' -- '257' -- '258' -- '259' -- '260' -- '261' -- '262' -- '263' -- '264' -- '265' -- '266' -- '267' -- '268' -- '269' -- '270' -- '272' -- '273' -- '274' -- '275' -- '276' -- '277' -- '278' -- '280' -- '281' -- '282' -- '284' -- '288' -- '289' -- '290' -- '291' -- '292' -- '293' -- '294' -- '296' -- '297' -- '298' -- '300' -- '304' -- '305' -- '306' -- '308' -- '312' -- '320' -- '321' -- '322' -- '323' -- '324' -- '325' -- '326' -- '328' -- '329' -- '330' -- '332' -- '336' -- '337' -- '338' -- '340' -- '344' -- '352' -- '353' -- '354' -- '356' -- '360' -- '368' -- '384' -- '385' -- '386' -- '387' -- '388' -- '389' -- '390' -- '392' -- '393' -- '394' -- '396' -- '400' -- '401' -- '402' -- '404' -- '408' -- '416' -- '417' -- '418' -- '420' -- '424' -- '432' -- '448' -- '449' -- '450' -- '452' -- '456' -- '464' -- '480' -- '512' -- '513' -- '514' -- '515' -- '516' -- '517' -- '518' -- '519' -- '520' -- '521' -- '522' -- '523' -- '524' -- '525' -- '526' -- '528' -- '529' -- '530' -- '531' -- '532' -- '533' -- '534' -- '536' -- '537' -- '538' -- '540' -- '544' -- '545' -- '546' -- '547' -- '548' -- '549' -- '550' -- '552' -- '553' -- '554' -- '556' -- '560' -- '561' -- '562' -- '564' -- '568' -- '576' -- '577' -- '578' -- '579' -- '580' -- '581' -- '582' -- '584' -- '585' -- '586' -- '588' -- '592' -- '593' -- '594' -- '596' -- '600' -- '608' -- '609' -- '610' -- '612' -- '616' -- '624' -- '640' -- '641' -- '642' -- '643' -- '644' -- '645' -- '646' -- '648' -- '649' -- '650' -- '652' -- '656' -- '657' -- '658' -- '660' -- '664' -- '672' -- '673' -- '674' -- '676' -- '680' -- '688' -- '704' -- '705' -- '706' -- '708' -- '712' -- '720' -- '736' -- '768' -- '769' -- '770' -- '771' -- '772' -- '773' -- '774' -- '776' -- '777' -- '778' -- '780' -- '784' -- '785' -- '786' -- '788' -- '792' -- '800' -- '801' -- '802' -- '804' -- '808' -- '816' -- '832' -- '833' -- '834' -- '836' -- '840' -- '848' -- '864' -- '896' -- '897' -- '898' -- '900' -- '904' -- '912' -- '928' -- '960' -- '1024' -- '1025' -- '1026' -- '1027' -- '1028' -- '1029' -- '1030' -- '1031' -- '1032' -- '1033' -- '1034' -- '1035' -- '1036' -- '1037' -- '1038' -- '1040' -- '1041' -- '1042' -- '1043' -- '1044' -- '1045' -- '1046' -- '1048' -- '1049' -- '1050' -- '1052' -- '1056' -- '1057' -- '1058' -- '1059' -- '1060' -- '1061' -- '1062' -- '1064' -- '1065' -- '1066' -- '1068' -- '1072' -- '1073' -- '1074' -- '1076' -- '1080' -- '1088' -- '1089' -- '1090' -- '1091' -- '1092' -- '1093' -- '1094' -- '1096' -- '1097' -- '1098' -- '1100' -- '1104' -- '1105' -- '1106' -- '1108' -- '1112' -- '1120' -- '1121' -- '1122' -- '1124' -- '1128' -- '1136' -- '1152' -- '1153' -- '1154' -- '1155' -- '1156' -- '1157' -- '1158' -- '1160' -- '1161' -- '1162' -- '1164' -- '1168' -- '1169' -- '1170' -- '1172' -- '1176' -- '1184' -- '1185' -- '1186' -- '1188' -- '1192' -- '1200' -- '1216' -- '1217' -- '1218' -- '1220' -- '1224' -- '1232' -- '1248' -- '1280' -- '1281' -- '1282' -- '1283' -- '1284' -- '1285' -- '1286' -- '1288' -- '1289' -- '1290' -- '1292' -- '1296' -- '1297' -- '1298' -- '1300' -- '1304' -- '1312' -- '1313' -- '1314' -- '1316' -- '1320' -- '1328' -- '1344' -- '1345' -- '1346' -- '1348' -- '1352' -- '1360' -- '1376' -- '1408' -- '1409' -- '1410' -- '1412' -- '1416' -- '1424' -- '1440' -- '1472' -- '1536' -- '1537' -- '1538' -- '1539' -- '1540' -- '1541' -- '1542' -- '1544' -- '1545' -- '1546' -- '1548' -- '1552' -- '1553' -- '1554' -- '1556' -- '1560' -- '1568' -- '1569' -- '1570' -- '1572' -- '1576' -- '1584' -- '1600' -- '1601' -- '1602' -- '1604' -- '1608' -- '1616' -- '1632' -- '1664' -- '1665' -- '1666' -- '1668' -- '1672' -- '1680' -- '1696' -- '1728' -- '1792' -- '1793' -- '1794' -- '1796' -- '1800' -- '1808' -- '1824' -- '1856' -- '1920' -- '2048' -- '2049' -- '2050' -- '2051' -- '2052' -- '2053' -- '2054' -- '2055' -- '2056' -- '2057' -- '2058' -- '2059' -- '2060' -- '2061' -- '2062' -- '2064' -- '2065' -- '2066' -- '2067' -- '2068' -- '2069' -- '2070' -- '2072' -- '2073' -- '2074' -- '2076' -- '2080' -- '2081' -- '2082' -- '2083' -- '2084' -- '2085' -- '2086' -- '2088' -- '2089' -- '2090' -- '2092' -- '2096' -- '2097' -- '2098' -- '2100' -- '2104' -- '2112' -- '2113' -- '2114' -- '2115' -- '2116' -- '2117' -- '2118' -- '2120' -- '2121' -- '2122' -- '2124' -- '2128' -- '2129' -- '2130' -- '2132' -- '2136' -- '2144' -- '2145' -- '2146' -- '2148' -- '2152' -- '2160' -- '2176' -- '2177' -- '2178' -- '2179' -- '2180' -- '2181' -- '2182' -- '2184' -- '2185' -- '2186' -- '2188' -- '2192' -- '2193' -- '2194' -- '2196' -- '2200' -- '2208' -- '2209' -- '2210' -- '2212' -- '2216' -- '2224' -- '2240' -- '2241' -- '2242' -- '2244' -- '2248' -- '2256' -- '2272' -- '2304' -- '2305' -- '2306' -- '2307' -- '2308' -- '2309' -- '2310' -- '2312' -- '2313' -- '2314' -- '2316' -- '2320' -- '2321' -- '2322' -- '2324' -- '2328' -- '2336' -- '2337' -- '2338' -- '2340' -- '2344' -- '2352' -- '2368' -- '2369' -- '2370' -- '2372' -- '2376' -- '2384' -- '2400' -- '2432' -- '2433' -- '2434' -- '2436' -- '2440' -- '2448' -- '2464' -- '2496' -- '2560' -- '2561' -- '2562' -- '2563' -- '2564' -- '2565' -- '2566' -- '2568' -- '2569' -- '2570' -- '2572' -- '2576' -- '2577' -- '2578' -- '2580' -- '2584' -- '2592' -- '2593' -- '2594' -- '2596' -- '2600' -- '2608' -- '2624' -- '2625' -- '2626' -- '2628' -- '2632' -- '2640' -- '2656' -- '2688' -- '2689' -- '2690' -- '2692' -- '2696' -- '2704' -- '2720' -- '2752' -- '2816' -- '2817' -- '2818' -- '2820' -- '2824' -- '2832' -- '2848' -- '2880' -- '2944' -- '3072' -- '3073' -- '3074' -- '3075' -- '3076' -- '3077' -- '3078' -- '3080' -- '3081' -- '3082' -- '3084' -- '3088' -- '3089' -- '3090' -- '3092' -- '3096' -- '3104' -- '3105' -- '3106' -- '3108' -- '3112' -- '3120' -- '3136' -- '3137' -- '3138' -- '3140' -- '3144' -- '3152' -- '3168' -- '3200' -- '3201' -- '3202' -- '3204' -- '3208' -- '3216' -- '3232' -- '3264' -- '3328' -- '3329' -- '3330' -- '3332' -- '3336' -- '3344' -- '3360' -- '3392' -- '3456' -- '3584' -- '3585' -- '3586' -- '3588' -- '3592' -- '3600' -- '3616' -- '3648' -- '3712' -- '3840' -- '4096' -- '4097' -- '4098' -- '4099' -- '4100' -- '4101' -- '4102' -- '4103' -- '4104' -- '4105' -- '4106' -- '4107' -- '4108' -- '4109' -- '4110' -- '4112' -- '4113' -- '4114' -- '4115' -- '4116' -- '4117' -- '4118' -- '4120' -- '4121' -- '4122' -- '4124' -- '4128' -- '4129' -- '4130' -- '4131' -- '4132' -- '4133' -- '4134' -- '4136' -- '4137' -- '4138' -- '4140' -- '4144' -- '4145' -- '4146' -- '4148' -- '4152' -- '4160' -- '4161' -- '4162' -- '4163' -- '4164' -- '4165' -- '4166' -- '4168' -- '4169' -- '4170' -- '4172' -- '4176' -- '4177' -- '4178' -- '4180' -- '4184' -- '4192' -- '4193' -- '4194' -- '4196' -- '4200' -- '4208' -- '4224' -- '4225' -- '4226' -- '4227' -- '4228' -- '4229' -- '4230' -- '4232' -- '4233' -- '4234' -- '4236' -- '4240' -- '4241' -- '4242' -- '4244' -- '4248' -- '4256' -- '4257' -- '4258' -- '4260' -- '4264' -- '4272' -- '4288' -- '4289' -- '4290' -- '4292' -- '4296' -- '4304' -- '4320' -- '4352' -- '4353' -- '4354' -- '4355' -- '4356' -- '4357' -- '4358' -- '4360' -- '4361' -- '4362' -- '4364' -- '4368' -- '4369' -- '4370' -- '4372' -- '4376' -- '4384' -- '4385' -- '4386' -- '4388' -- '4392' -- '4400' -- '4416' -- '4417' -- '4418' -- '4420' -- '4424' -- '4432' -- '4448' -- '4480' -- '4481' -- '4482' -- '4484' -- '4488' -- '4496' -- '4512' -- '4544' -- '4608' -- '4609' -- '4610' -- '4611' -- '4612' -- '4613' -- '4614' -- '4616' -- '4617' -- '4618' -- '4620' -- '4624' -- '4625' -- '4626' -- '4628' -- '4632' -- '4640' -- '4641' -- '4642' -- '4644' -- '4648' -- '4656' -- '4672' -- '4673' -- '4674' -- '4676' -- '4680' -- '4688' -- '4704' -- '4736' -- '4737' -- '4738' -- '4740' -- '4744' -- '4752' -- '4768' -- '4800' -- '4864' -- '4865' -- '4866' -- '4868' -- '4872' -- '4880' -- '4896' -- '4928' -- '4992' -- '5120' -- '5121' -- '5122' -- '5123' -- '5124' -- '5125' -- '5126' -- '5128' -- '5129' -- '5130' -- '5132' -- '5136' -- '5137' -- '5138' -- '5140' -- '5144' -- '5152' -- '5153' -- '5154' -- '5156' -- '5160' -- '5168' -- '5184' -- '5185' -- '5186' -- '5188' -- '5192' -- '5200' -- '5216' -- '5248' -- '5249' -- '5250' -- '5252' -- '5256' -- '5264' -- '5280' -- '5312' -- '5376' -- '5377' -- '5378' -- '5380' -- '5384' -- '5392' -- '5408' -- '5440' -- '5504' -- '5632' -- '5633' -- '5634' -- '5636' -- '5640' -- '5648' -- '5664' -- '5696' -- '5760' -- '5888' -- '6144' -- '6145' -- '6146' -- '6147' -- '6148' -- '6149' -- '6150' -- '6152' -- '6153' -- '6154' -- '6156' -- '6160' -- '6161' -- '6162' -- '6164' -- '6168' -- '6176' -- '6177' -- '6178' -- '6180' -- '6184' -- '6192' -- '6208' -- '6209' -- '6210' -- '6212' -- '6216' -- '6224' -- '6240' -- '6272' -- '6273' -- '6274' -- '6276' -- '6280' -- '6288' -- '6304' -- '6336' -- '6400' -- '6401' -- '6402' -- '6404' -- '6408' -- '6416' -- '6432' -- '6464' -- '6528' -- '6656' -- '6657' -- '6658' -- '6660' -- '6664' -- '6672' -- '6688' -- '6720' -- '6784' -- '6912' -- '7168' -- '7169' -- '7170' -- '7172' -- '7176' -- '7184' -- '7200' -- '7232' -- '7296' -- '7424' -- '7680' -- '8192' -- '8193' -- '8194' -- '8195' -- '8196' -- '8197' -- '8198' -- '8199' -- '8200' -- '8201' -- '8202' -- '8203' -- '8204' -- '8205' -- '8206' -- '8208' -- '8209' -- '8210' -- '8211' -- '8212' -- '8213' -- '8214' -- '8216' -- '8217' -- '8218' -- '8220' -- '8224' -- '8225' -- '8226' -- '8227' -- '8228' -- '8229' -- '8230' -- '8232' -- '8233' -- '8234' -- '8236' -- '8240' -- '8241' -- '8242' -- '8244' -- '8248' -- '8256' -- '8257' -- '8258' -- '8259' -- '8260' -- '8261' -- '8262' -- '8264' -- '8265' -- '8266' -- '8268' -- '8272' -- '8273' -- '8274' -- '8276' -- '8280' -- '8288' -- '8289' -- '8290' -- '8292' -- '8296' -- '8304' -- '8320' -- '8321' -- '8322' -- '8323' -- '8324' -- '8325' -- '8326' -- '8328' -- '8329' -- '8330' -- '8332' -- '8336' -- '8337' -- '8338' -- '8340' -- '8344' -- '8352' -- '8353' -- '8354' -- '8356' -- '8360' -- '8368' -- '8384' -- '8385' -- '8386' -- '8388' -- '8392' -- '8400' -- '8416' -- '8448' -- '8449' -- '8450' -- '8451' -- '8452' -- '8453' -- '8454' -- '8456' -- '8457' -- '8458' -- '8460' -- '8464' -- '8465' -- '8466' -- '8468' -- '8472' -- '8480' -- '8481' -- '8482' -- '8484' -- '8488' -- '8496' -- '8512' -- '8513' -- '8514' -- '8516' -- '8520' -- '8528' -- '8544' -- '8576' -- '8577' -- '8578' -- '8580' -- '8584' -- '8592' -- '8608' -- '8640' -- '8704' -- '8705' -- '8706' -- '8707' -- '8708' -- '8709' -- '8710' -- '8712' -- '8713' -- '8714' -- '8716' -- '8720' -- '8721' -- '8722' -- '8724' -- '8728' -- '8736' -- '8737' -- '8738' -- '8740' -- '8744' -- '8752' -- '8768' -- '8769' -- '8770' -- '8772' -- '8776' -- '8784' -- '8800' -- '8832' -- '8833' -- '8834' -- '8836' -- '8840' -- '8848' -- '8864' -- '8896' -- '8960' -- '8961' -- '8962' -- '8964' -- '8968' -- '8976' -- '8992' -- '9024' -- '9088' -- '9216' -- '9217' -- '9218' -- '9219' -- '9220' -- '9221' -- '9222' -- '9224' -- '9225' -- '9226' -- '9228' -- '9232' -- '9233' -- '9234' -- '9236' -- '9240' -- '9248' -- '9249' -- '9250' -- '9252' -- '9256' -- '9264' -- '9280' -- '9281' -- '9282' -- '9284' -- '9288' -- '9296' -- '9312' -- '9344' -- '9345' -- '9346' -- '9348' -- '9352' -- '9360' -- '9376' -- '9408' -- '9472' -- '9473' -- '9474' -- '9476' -- '9480' -- '9488' -- '9504' -- '9536' -- '9600' -- '9728' -- '9729' -- '9730' -- '9732' -- '9736' -- '9744' -- '9760' -- '9792' -- '9856' -- '9984' -- '10240' -- '10241' -- '10242' -- '10243' -- '10244' -- '10245' -- '10246' -- '10248' -- '10249' -- '10250' -- '10252' -- '10256' -- '10257' -- '10258' -- '10260' -- '10264' -- '10272' -- '10273' -- '10274' -- '10276' -- '10280' -- '10288' -- '10304' -- '10305' -- '10306' -- '10308' -- '10312' -- '10320' -- '10336' -- '10368' -- '10369' -- '10370' -- '10372' -- '10376' -- '10384' -- '10400' -- '10432' -- '10496' -- '10497' -- '10498' -- '10500' -- '10504' -- '10512' -- '10528' -- '10560' -- '10624' -- '10752' -- '10753' -- '10754' -- '10756' -- '10760' -- '10768' -- '10784' -- '10816' -- '10880' -- '11008' -- '11264' -- '11265' -- '11266' -- '11268' -- '11272' -- '11280' -- '11296' -- '11328' -- '11392' -- '11520' -- '11776' -- '12288' -- '12289' -- '12290' -- '12291' -- '12292' -- '12293' -- '12294' -- '12296' -- '12297' -- '12298' -- '12300' -- '12304' -- '12305' -- '12306' -- '12308' -- '12312' -- '12320' -- '12321' -- '12322' -- '12324' -- '12328' -- '12336' -- '12352' -- '12353' -- '12354' -- '12356' -- '12360' -- '12368' -- '12384' -- '12416' -- '12417' -- '12418' -- '12420' -- '12424' -- '12432' -- '12448' -- '12480' -- '12544' -- '12545' -- '12546' -- '12548' -- '12552' -- '12560' -- '12576' -- '12608' -- '12672' -- '12800' -- '12801' -- '12802' -- '12804' -- '12808' -- '12816' -- '12832' -- '12864' -- '12928' -- '13056' -- '13312' -- '13313' -- '13314' -- '13316' -- '13320' -- '13328' -- '13344' -- '13376' -- '13440' -- '13568' -- '13824' -- '14336' -- '14337' -- '14338' -- '14340' -- '14344' -- '14352' -- '14368' -- '14400' -- '14464' -- '14592' -- '14848' -- '15360' -- '16384' -- '16385' -- '16386' -- '16387' -- '16388' -- '16389' -- '16390' -- '16391' -- '16392' -- '16393' -- '16394' -- '16395' -- '16396' -- '16397' -- '16398' -- '16400' -- '16401' -- '16402' -- '16403' -- '16404' -- '16405' -- '16406' -- '16408' -- '16409' -- '16410' -- '16412' -- '16416' -- '16417' -- '16418' -- '16419' -- '16420' -- '16421' -- '16422' -- '16424' -- '16425' -- '16426' -- '16428' -- '16432' -- '16433' -- '16434' -- '16436' -- '16440' -- '16448' -- '16449' -- '16450' -- '16451' -- '16452' -- '16453' -- '16454' -- '16456' -- '16457' -- '16458' -- '16460' -- '16464' -- '16465' -- '16466' -- '16468' -- '16472' -- '16480' -- '16481' -- '16482' -- '16484' -- '16488' -- '16496' -- '16512' -- '16513' -- '16514' -- '16515' -- '16516' -- '16517' -- '16518' -- '16520' -- '16521' -- '16522' -- '16524' -- '16528' -- '16529' -- '16530' -- '16532' -- '16536' -- '16544' -- '16545' -- '16546' -- '16548' -- '16552' -- '16560' -- '16576' -- '16577' -- '16578' -- '16580' -- '16584' -- '16592' -- '16608' -- '16640' -- '16641' -- '16642' -- '16643' -- '16644' -- '16645' -- '16646' -- '16648' -- '16649' -- '16650' -- '16652' -- '16656' -- '16657' -- '16658' -- '16660' -- '16664' -- '16672' -- '16673' -- '16674' -- '16676' -- '16680' -- '16688' -- '16704' -- '16705' -- '16706' -- '16708' -- '16712' -- '16720' -- '16736' -- '16768' -- '16769' -- '16770' -- '16772' -- '16776' -- '16784' -- '16800' -- '16832' -- '16896' -- '16897' -- '16898' -- '16899' -- '16900' -- '16901' -- '16902' -- '16904' -- '16905' -- '16906' -- '16908' -- '16912' -- '16913' -- '16914' -- '16916' -- '16920' -- '16928' -- '16929' -- '16930' -- '16932' -- '16936' -- '16944' -- '16960' -- '16961' -- '16962' -- '16964' -- '16968' -- '16976' -- '16992' -- '17024' -- '17025' -- '17026' -- '17028' -- '17032' -- '17040' -- '17056' -- '17088' -- '17152' -- '17153' -- '17154' -- '17156' -- '17160' -- '17168' -- '17184' -- '17216' -- '17280' -- '17408' -- '17409' -- '17410' -- '17411' -- '17412' -- '17413' -- '17414' -- '17416' -- '17417' -- '17418' -- '17420' -- '17424' -- '17425' -- '17426' -- '17428' -- '17432' -- '17440' -- '17441' -- '17442' -- '17444' -- '17448' -- '17456' -- '17472' -- '17473' -- '17474' -- '17476' -- '17480' -- '17488' -- '17504' -- '17536' -- '17537' -- '17538' -- '17540' -- '17544' -- '17552' -- '17568' -- '17600' -- '17664' -- '17665' -- '17666' -- '17668' -- '17672' -- '17680' -- '17696' -- '17728' -- '17792' -- '17920' -- '17921' -- '17922' -- '17924' -- '17928' -- '17936' -- '17952' -- '17984' -- '18048' -- '18176' -- '18432' -- '18433' -- '18434' -- '18435' -- '18436' -- '18437' -- '18438' -- '18440' -- '18441' -- '18442' -- '18444' -- '18448' -- '18449' -- '18450' -- '18452' -- '18456' -- '18464' -- '18465' -- '18466' -- '18468' -- '18472' -- '18480' -- '18496' -- '18497' -- '18498' -- '18500' -- '18504' -- '18512' -- '18528' -- '18560' -- '18561' -- '18562' -- '18564' -- '18568' -- '18576' -- '18592' -- '18624' -- '18688' -- '18689' -- '18690' -- '18692' -- '18696' -- '18704' -- '18720' -- '18752' -- '18816' -- '18944' -- '18945' -- '18946' -- '18948' -- '18952' -- '18960' -- '18976' -- '19008' -- '19072' -- '19200' -- '19456' -- '19457' -- '19458' -- '19460' -- '19464' -- '19472' -- '19488' -- '19520' -- '19584' -- '19712' -- '19968' -- '20480' -- '20481' -- '20482' -- '20483' -- '20484' -- '20485' -- '20486' -- '20488' -- '20489' -- '20490' -- '20492' -- '20496' -- '20497' -- '20498' -- '20500' -- '20504' -- '20512' -- '20513' -- '20514' -- '20516' -- '20520' -- '20528' -- '20544' -- '20545' -- '20546' -- '20548' -- '20552' -- '20560' -- '20576' -- '20608' -- '20609' -- '20610' -- '20612' -- '20616' -- '20624' -- '20640' -- '20672' -- '20736' -- '20737' -- '20738' -- '20740' -- '20744' -- '20752' -- '20768' -- '20800' -- '20864' -- '20992' -- '20993' -- '20994' -- '20996' -- '21000' -- '21008' -- '21024' -- '21056' -- '21120' -- '21248' -- '21504' -- '21505' -- '21506' -- '21508' -- '21512' -- '21520' -- '21536' -- '21568' -- '21632' -- '21760' -- '22016' -- '22528' -- '22529' -- '22530' -- '22532' -- '22536' -- '22544' -- '22560' -- '22592' -- '22656' -- '22784' -- '23040' -- '23552' -- '24576' -- '24577' -- '24578' -- '24579' -- '24580' -- '24581' -- '24582' -- '24584' -- '24585' -- '24586' -- '24588' -- '24592' -- '24593' -- '24594' -- '24596' -- '24600' -- '24608' -- '24609' -- '24610' -- '24612' -- '24616' -- '24624' -- '24640' -- '24641' -- '24642' -- '24644' -- '24648' -- '24656' -- '24672' -- '24704' -- '24705' -- '24706' -- '24708' -- '24712' -- '24720' -- '24736' -- '24768' -- '24832' -- '24833' -- '24834' -- '24836' -- '24840' -- '24848' -- '24864' -- '24896' -- '24960' -- '25088' -- '25089' -- '25090' -- '25092' -- '25096' -- '25104' -- '25120' -- '25152' -- '25216' -- '25344' -- '25600' -- '25601' -- '25602' -- '25604' -- '25608' -- '25616' -- '25632' -- '25664' -- '25728' -- '25856' -- '26112' -- '26624' -- '26625' -- '26626' -- '26628' -- '26632' -- '26640' -- '26656' -- '26688' -- '26752' -- '26880' -- '27136' -- '27648' -- '28672' -- '28673' -- '28674' -- '28676' -- '28680' -- '28688' -- '28704' -- '28736' -- '28800' -- '28928' -- '29184' -- '29696' -- '30720' -- '32768' -- '32769' -- '32770' -- '32771' -- '32772' -- '32773' -- '32774' -- '32775' -- '32776' -- '32777' -- '32778' -- '32779' -- '32780' -- '32781' -- '32782' -- '32784' -- '32785' -- '32786' -- '32787' -- '32788' -- '32789' -- '32790' -- '32792' -- '32793' -- '32794' -- '32796' -- '32800' -- '32801' -- '32802' -- '32803' -- '32804' -- '32805' -- '32806' -- '32808' -- '32809' -- '32810' -- '32812' -- '32816' -- '32817' -- '32818' -- '32820' -- '32824' -- '32832' -- '32833' -- '32834' -- '32835' -- '32836' -- '32837' -- '32838' -- '32840' -- '32841' -- '32842' -- '32844' -- '32848' -- '32849' -- '32850' -- '32852' -- '32856' -- '32864' -- '32865' -- '32866' -- '32868' -- '32872' -- '32880' -- '32896' -- '32897' -- '32898' -- '32899' -- '32900' -- '32901' -- '32902' -- '32904' -- '32905' -- '32906' -- '32908' -- '32912' -- '32913' -- '32914' -- '32916' -- '32920' -- '32928' -- '32929' -- '32930' -- '32932' -- '32936' -- '32944' -- '32960' -- '32961' -- '32962' -- '32964' -- '32968' -- '32976' -- '32992' -- '33024' -- '33025' -- '33026' -- '33027' -- '33028' -- '33029' -- '33030' -- '33032' -- '33033' -- '33034' -- '33036' -- '33040' -- '33041' -- '33042' -- '33044' -- '33048' -- '33056' -- '33057' -- '33058' -- '33060' -- '33064' -- '33072' -- '33088' -- '33089' -- '33090' -- '33092' -- '33096' -- '33104' -- '33120' -- '33152' -- '33153' -- '33154' -- '33156' -- '33160' -- '33168' -- '33184' -- '33216' -- '33280' -- '33281' -- '33282' -- '33283' -- '33284' -- '33285' -- '33286' -- '33288' -- '33289' -- '33290' -- '33292' -- '33296' -- '33297' -- '33298' -- '33300' -- '33304' -- '33312' -- '33313' -- '33314' -- '33316' -- '33320' -- '33328' -- '33344' -- '33345' -- '33346' -- '33348' -- '33352' -- '33360' -- '33376' -- '33408' -- '33409' -- '33410' -- '33412' -- '33416' -- '33424' -- '33440' -- '33472' -- '33536' -- '33537' -- '33538' -- '33540' -- '33544' -- '33552' -- '33568' -- '33600' -- '33664' -- '33792' -- '33793' -- '33794' -- '33795' -- '33796' -- '33797' -- '33798' -- '33800' -- '33801' -- '33802' -- '33804' -- '33808' -- '33809' -- '33810' -- '33812' -- '33816' -- '33824' -- '33825' -- '33826' -- '33828' -- '33832' -- '33840' -- '33856' -- '33857' -- '33858' -- '33860' -- '33864' -- '33872' -- '33888' -- '33920' -- '33921' -- '33922' -- '33924' -- '33928' -- '33936' -- '33952' -- '33984' -- '34048' -- '34049' -- '34050' -- '34052' -- '34056' -- '34064' -- '34080' -- '34112' -- '34176' -- '34304' -- '34305' -- '34306' -- '34308' -- '34312' -- '34320' -- '34336' -- '34368' -- '34432' -- '34560' -- '34816' -- '34817' -- '34818' -- '34819' -- '34820' -- '34821' -- '34822' -- '34824' -- '34825' -- '34826' -- '34828' -- '34832' -- '34833' -- '34834' -- '34836' -- '34840' -- '34848' -- '34849' -- '34850' -- '34852' -- '34856' -- '34864' -- '34880' -- '34881' -- '34882' -- '34884' -- '34888' -- '34896' -- '34912' -- '34944' -- '34945' -- '34946' -- '34948' -- '34952' -- '34960' -- '34976' -- '35008' -- '35072' -- '35073' -- '35074' -- '35076' -- '35080' -- '35088' -- '35104' -- '35136' -- '35200' -- '35328' -- '35329' -- '35330' -- '35332' -- '35336' -- '35344' -- '35360' -- '35392' -- '35456' -- '35584' -- '35840' -- '35841' -- '35842' -- '35844' -- '35848' -- '35856' -- '35872' -- '35904' -- '35968' -- '36096' -- '36352' -- '36864' -- '36865' -- '36866' -- '36867' -- '36868' -- '36869' -- '36870' -- '36872' -- '36873' -- '36874' -- '36876' -- '36880' -- '36881' -- '36882' -- '36884' -- '36888' -- '36896' -- '36897' -- '36898' -- '36900' -- '36904' -- '36912' -- '36928' -- '36929' -- '36930' -- '36932' -- '36936' -- '36944' -- '36960' -- '36992' -- '36993' -- '36994' -- '36996' -- '37000' -- '37008' -- '37024' -- '37056' -- '37120' -- '37121' -- '37122' -- '37124' -- '37128' -- '37136' -- '37152' -- '37184' -- '37248' -- '37376' -- '37377' -- '37378' -- '37380' -- '37384' -- '37392' -- '37408' -- '37440' -- '37504' -- '37632' -- '37888' -- '37889' -- '37890' -- '37892' -- '37896' -- '37904' -- '37920' -- '37952' -- '38016' -- '38144' -- '38400' -- '38912' -- '38913' -- '38914' -- '38916' -- '38920' -- '38928' -- '38944' -- '38976' -- '39040' -- '39168' -- '39424' -- '39936' -- '40960' -- '40961' -- '40962' -- '40963' -- '40964' -- '40965' -- '40966' -- '40968' -- '40969' -- '40970' -- '40972' -- '40976' -- '40977' -- '40978' -- '40980' -- '40984' -- '40992' -- '40993' -- '40994' -- '40996' -- '41000' -- '41008' -- '41024' -- '41025' -- '41026' -- '41028' -- '41032' -- '41040' -- '41056' -- '41088' -- '41089' -- '41090' -- '41092' -- '41096' -- '41104' -- '41120' -- '41152' -- '41216' -- '41217' -- '41218' -- '41220' -- '41224' -- '41232' -- '41248' -- '41280' -- '41344' -- '41472' -- '41473' -- '41474' -- '41476' -- '41480' -- '41488' -- '41504' -- '41536' -- '41600' -- '41728' -- '41984' -- '41985' -- '41986' -- '41988' -- '41992' -- '42000' -- '42016' -- '42048' -- '42112' -- '42240' -- '42496' -- '43008' -- '43009' -- '43010' -- '43012' -- '43016' -- '43024' -- '43040' -- '43072' -- '43136' -- '43264' -- '43520' -- '44032' -- '45056' -- '45057' -- '45058' -- '45060' -- '45064' -- '45072' -- '45088' -- '45120' -- '45184' -- '45312' -- '45568' -- '46080' -- '47104' -- '49152' -- '49153' -- '49154' -- '49155' -- '49156' -- '49157' -- '49158' -- '49160' -- '49161' -- '49162' -- '49164' -- '49168' -- '49169' -- '49170' -- '49172' -- '49176' -- '49184' -- '49185' -- '49186' -- '49188' -- '49192' -- '49200' -- '49216' -- '49217' -- '49218' -- '49220' -- '49224' -- '49232' -- '49248' -- '49280' -- '49281' -- '49282' -- '49284' -- '49288' -- '49296' -- '49312' -- '49344' -- '49408' -- '49409' -- '49410' -- '49412' -- '49416' -- '49424' -- '49440' -- '49472' -- '49536' -- '49664' -- '49665' -- '49666' -- '49668' -- '49672' -- '49680' -- '49696' -- '49728' -- '49792' -- '49920' -- '50176' -- '50177' -- '50178' -- '50180' -- '50184' -- '50192' -- '50208' -- '50240' -- '50304' -- '50432' -- '50688' -- '51200' -- '51201' -- '51202' -- '51204' -- '51208' -- '51216' -- '51232' -- '51264' -- '51328' -- '51456' -- '51712' -- '52224' -- '53248' -- '53249' -- '53250' -- '53252' -- '53256' -- '53264' -- '53280' -- '53312' -- '53376' -- '53504' -- '53760' -- '54272' -- '55296' -- '57344' -- '57345' -- '57346' -- '57348' -- '57352' -- '57360' -- '57376' -- '57408' -- '57472' -- '57600' -- '57856' -- '58368' -- '59392' -- '61440' -init: null -input_size: 80 -cmvn_file: null -ctc_conf: - dropout_rate: 0.0 - ctc_type: builtin - reduce: true - ignore_nan_grad: true -joint_net_conf: null -use_preprocessor: true -token_type: char -bpemodel: null -non_linguistic_symbols: null -cleaner: null -g2p: null -speech_volume_normalize: null -rir_scp: null -rir_apply_prob: 1.0 -noise_scp: null -noise_apply_prob: 1.0 -noise_db_range: '13_15' -specaug: null -specaug_conf: {} -normalize: null -normalize_conf: {} -label_aggregator: null -label_aggregator_conf: {} -model: sond -model_conf: - lsm_weight: 0.1 - length_normalized_loss: true - max_spk_num: 16 - normalize_speech_speaker: true -# speech encoder -encoder: resnet34_sp_l2reg -encoder_conf: - # pass by model, equal to feature dim - # input_size: 80 - batchnorm_momentum: 0.01 - pooling_type: "window_shift" - pool_size: 20 - stride: 1 - tf2torch_tensor_name_prefix_torch: encoder - tf2torch_tensor_name_prefix_tf: EAND/speech_encoder -speaker_encoder: null -speaker_encoder_conf: {} -ci_scorer: conv -ci_scorer_conf: - input_units: 512 - num_layers: 3 - num_units: 512 - kernel_size: 1 - dropout_rate: 0.0 - position_encoder: null - out_units: 1 - out_norm: false - auxiliary_states: false - tf2torch_tensor_name_prefix_torch: ci_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/ci_scorer -cd_scorer: san -cd_scorer_conf: - input_size: 512 - output_size: 512 - out_units: 1 - attention_heads: 4 - linear_units: 1024 - num_blocks: 4 - dropout_rate: 0.0 - positional_dropout_rate: 0.0 - attention_dropout_rate: 0.0 - # use string "null" to remove input layer - input_layer: "null" - pos_enc_class: null - normalize_before: true - tf2torch_tensor_name_prefix_torch: cd_scorer - tf2torch_tensor_name_prefix_tf: EAND/compute_distance_layer/cd_scorer -# post net -decoder: fsmn -decoder_conf: - in_units: 32 - out_units: 2517 - filter_size: 31 - fsmn_num_layers: 6 - dnn_num_layers: 1 - num_memory_units: 16 - ffn_inner_dim: 512 - dropout_rate: 0.0 - tf2torch_tensor_name_prefix_torch: decoder - tf2torch_tensor_name_prefix_tf: EAND/post_net -frontend: null -frontend_conf: - fs: 8000 - window: povey - n_mels: 80 - frame_length: 25 - frame_shift: 10 - filter_length_min: -1 - filter_length_max: -1 - lfr_m: 1 - lfr_n: 1 - dither: 0.0 - snip_edges: false - upsacle_samples: false -num_worker_count: 0 -required: -- output_dir -- token_list -oss_bucket: 'null' -version: 0.1.4 diff --git a/egs/callhome/TOLD/soap/unit_test/unit_test.py b/egs/callhome/TOLD/soap/unit_test/unit_test.py deleted file mode 100644 index a48eda148..000000000 --- a/egs/callhome/TOLD/soap/unit_test/unit_test.py +++ /dev/null @@ -1,97 +0,0 @@ -from funasr.bin.diar_inference_launch import inference_launch -import os - - -def test_fbank_cpu_infer(): - diar_config_path = "sond_fbank.yaml" - diar_model_path = "sond.pb" - output_dir = "./outputs" - data_path_and_name_and_type = [ - ("data/unit_test/test_feats.scp", "speech", "kaldi_ark"), - ("data/unit_test/test_profile.scp", "profile", "kaldi_ark"), - ] - pipeline = inference_launch( - mode="sond", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - num_workers=0, - log_level="INFO", - ) - results = pipeline(data_path_and_name_and_type) - print(results) - - -def test_fbank_gpu_infer(): - diar_config_path = "sond_fbank.yaml" - diar_model_path = "sond.pb" - output_dir = "./outputs" - data_path_and_name_and_type = [ - ("data/unit_test/test_feats.scp", "speech", "kaldi_ark"), - ("data/unit_test/test_profile.scp", "profile", "kaldi_ark"), - ] - pipeline = inference_launch( - mode="sond", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - ngpu=1, - num_workers=1, - log_level="INFO", - ) - results = pipeline(data_path_and_name_and_type) - print(results) - - -def test_wav_gpu_infer(): - diar_config_path = "config.yaml" - diar_model_path = "sond.pb" - output_dir = "./outputs" - data_path_and_name_and_type = [ - ("data/unit_test/test_wav.scp", "speech", "sound"), - ("data/unit_test/test_profile.scp", "profile", "kaldi_ark"), - ] - pipeline = inference_launch( - mode="sond", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - ngpu=1, - num_workers=1, - log_level="WARNING", - ) - results = pipeline(data_path_and_name_and_type) - print(results) - - -def test_without_profile_gpu_infer(): - diar_config_path = "config.yaml" - diar_model_path = "sond.pb" - output_dir = "./outputs" - raw_inputs = [[ - "data/unit_test/raw_inputs/record.wav", - "data/unit_test/raw_inputs/spk1.wav", - "data/unit_test/raw_inputs/spk2.wav", - "data/unit_test/raw_inputs/spk3.wav", - "data/unit_test/raw_inputs/spk4.wav" - ]] - pipeline = inference_launch( - mode="sond_demo", - diar_train_config=diar_config_path, - diar_model_file=diar_model_path, - output_dir=output_dir, - ngpu=1, - num_workers=1, - log_level="WARNING", - param_dict={}, - ) - results = pipeline(raw_inputs=raw_inputs) - print(results) - - -if __name__ == '__main__': - os.environ["CUDA_VISIBLE_DEVICES"] = "7" - test_fbank_cpu_infer() - # test_fbank_gpu_infer() - # test_wav_gpu_infer() - # test_without_profile_gpu_infer() diff --git a/egs/cnceleb/resnet34/README.md b/egs/cnceleb/resnet34/README.md deleted file mode 100644 index 994e31575..000000000 --- a/egs/cnceleb/resnet34/README.md +++ /dev/null @@ -1,18 +0,0 @@ - -# ResNet34 Result - -## Training Config -- Feature info: using 80 dims fbank, no cmvn, speed perturb(0.9, 1.0, 1.1) -- Train info: lr 1e-4, batch_size 64, 1 gpu(Tesla V100), acc_grad 1, 300000 steps, clip_gradient_norm 3.0, weight_l2_regularizer 0.01 -- Loss info: additive angular margin softmax, feature_scaling_factor=8, margin 0.25 -- Model info: ResNet34, global statistics pooling, Dense -- Train config: conf/train_sv_resnet34.yaml -- Model size: 5.60 M parameters - -## Results (EER & minDCF) -- Test set: Alimeeting-test, CN-Celeb-eval-speech - -| testset | EER(%) | minDCF | Threshold | -|:---------------------:|:-------:|:-------:| :--------:| -| Alimeeting-test | 1.45 | 0.0849 | 0.9666 | -| CN-Celeb-eval-speech | 9.00 | 0.2936 | 0.9465 | \ No newline at end of file diff --git a/egs/cnceleb/resnet34/configuration.json b/egs/cnceleb/resnet34/configuration.json deleted file mode 100644 index 0070da384..000000000 --- a/egs/cnceleb/resnet34/configuration.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "framework": "pytorch", - "task": "speaker-verification", - "model": { - "type": "generic-sv", - "sv_model_name": "sv.pb", - "model_config": { - "type": "pytorch", - "code_base": "funasr", - "mode": "sv", - "lang": "zh-cn", - "batch_size": 1, - "sv_model_name": "sv.pb", - "sv_model_config": "sv.yaml" - } - }, - "pipeline": { - "type": "sv-inference" - } -} \ No newline at end of file diff --git a/egs/cnceleb/resnet34/local/convert_tf_ckpt_to_torch.py b/egs/cnceleb/resnet34/local/convert_tf_ckpt_to_torch.py deleted file mode 100644 index 0dcf2e4c1..000000000 --- a/egs/cnceleb/resnet34/local/convert_tf_ckpt_to_torch.py +++ /dev/null @@ -1,93 +0,0 @@ -import numpy as np -import logging -from typing import Dict -import sys -import torch - - -def load_ckpt(checkpoint_path: str) -> Dict[str, np.ndarray]: - from tensorflow.python import pywrap_tensorflow - - reader = pywrap_tensorflow.NewCheckpointReader(checkpoint_path) - var_to_shape_map = reader.get_variable_to_shape_map() - - var_dict = dict() - for var_name in sorted(var_to_shape_map): - if "optimizer" in var_name: - continue - tensor = reader.get_tensor(var_name) - print("in ckpt: {}, {}".format(var_name, tensor.shape)) # print(tensor) - var_dict[var_name] = tensor - - return var_dict - - -def convert_parameter_name_for_asv_resnet34( - var_dict: Dict[str, np.ndarray], - old_prefix: str = "EAND/speech_encoder", - new_prefix: str = "encoder", - train_steps: int = 0 -) -> Dict[str, np.ndarray]: - new_dict = dict() - model_size = 0 - for name, tensor in var_dict.items(): - if not name.startswith(old_prefix): - if name == "softmax/output/kernel": - new_name = "decoder.output_dense.weight" - tensor = np.transpose(tensor, [1, 0]) - new_dict[new_name] = torch.Tensor(tensor) - continue - new_name = name.replace(old_prefix, new_prefix) - new_name = new_name.replace("/", ".") - if "resnet1" in new_name or "resnet2" in new_name: - new_name = new_name.replace("encoder", "decoder") - module_name, para_name = new_name.rsplit(".", 1) - # process for batch normalization - if "bn" in module_name: - new_name = new_name.replace("gamma", "weight") - new_name = new_name.replace("beta", "bias") - new_name = new_name.replace("moving_mean", "running_mean") - new_name = new_name.replace("moving_variance", "running_var") - - new_dict[new_name] = torch.Tensor(tensor) - new_dict[module_name + ".num_batches_tracked"] = torch.Tensor(train_steps) - - # process for dense layers - elif "dense" in module_name: - new_name = new_name.replace("kernel", "weight") - if para_name == "kernel": - if len(tensor.shape) == 2: - tensor = np.transpose(tensor, [1, 0]) - elif len(tensor.shape) == 3: - tensor = np.transpose(tensor, [2, 1, 0]) - # for dense0 - elif len(tensor.shape) == 4: - tensor = np.transpose(tensor, [3, 2, 0, 1]) - - new_dict[new_name] = torch.Tensor(tensor) - - # process for conv layers - elif "conv" in module_name: - new_name = new_name.replace("kernel", "weight") - if para_name == "kernel": - tensor = np.transpose(tensor, [3, 2, 0, 1]) - - new_dict[new_name] = torch.Tensor(tensor) - - print("{} -> {}".format(name, new_name)) - model_size += new_dict[new_name].numel() - print("Model size: {}".format(model_size)) - return new_dict - - -if __name__ == '__main__': - checkpoint_path = sys.argv[1] - pkl_path = sys.argv[2] - tf_dict = load_ckpt(checkpoint_path) - torch_dict = convert_parameter_name_for_asv_resnet34( - tf_dict, - train_steps=300000, - ) - torch.save( - torch_dict, pkl_path - ) diff --git a/egs/cnceleb/resnet34/local/make_cnceleb1.sh b/egs/cnceleb/resnet34/local/make_cnceleb1.sh deleted file mode 100644 index 59bce1567..000000000 --- a/egs/cnceleb/resnet34/local/make_cnceleb1.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2019 Jiawen Kang -# Apache 2.0. -# -# This script prepares the CN-Celeb1 dataset. -# It creates separate directories for train, eval enroll and eval test. -# It also prepares a trials files, in the eval test directory. - -if [ $# != 2 ]; then - echo "Usage: make_cnceleb1.sh " - echo "E.g.: make_cnceleb1.sh /export/corpora/CN-Celeb1 data" - exit 1 -fi - -in_dir=$1 -out_dir=$2 - -# Prepare the cnceleb1 training data -this_out_dir=${out_dir}/cnceleb1_train -mkdir -p $this_out_dir 2>/dev/null -WAVFILE=$this_out_dir/wav.scp -SPKFILE=$this_out_dir/utt2spk -rm $WAVFILE $SPKFILE 2>/dev/null -this_in_dir=${in_dir}/dev - -#for spkr_id in `cat $this_in_dir/dev.lst`; do -# for f in $in_dir/data/$spkr_id/*.wav; do -# wav_id=$(basename $f | sed s:.wav$::) -# echo "${spkr_id}-${wav_id} $f" >> $WAVFILE -# echo "${spkr_id}-${wav_id} ${spkr_id}" >> $SPKFILE -# done -#done -# utils/fix_data_dir.sh $this_out_dir - -# Prepare the evaluation data -for mode in enroll test; do - this_out_dir=${out_dir}/eval_${mode} - mkdir -p $this_out_dir 2>/dev/null - WAVFILE=$this_out_dir/wav.scp - SPKFILE=$this_out_dir/utt2spk - rm $WAVFILE $SPKFILE 2>/dev/null - this_in_dir=${in_dir}/eval/${mode} - - for f in $this_in_dir/*.wav; do - wav_id=$(basename $f | sed s:.wav$::) - spkr_id=$(echo ${wav_id} | cut -d "-" -f1) - echo "${wav_id} $f" >> $WAVFILE - echo "${wav_id} ${spkr_id}" >> $SPKFILE - done - # utils/fix_data_dir.sh $this_out_dir -done - -# Prepare test trials -this_out_dir=$out_dir/eval_test/trials -mkdir -p $out_dir/eval_test/trials -this_in_dir=${in_dir}/eval/lists -cat $this_in_dir/trials.lst | sed 's@-enroll@@g' | sed 's@test/@@g' | sed 's@.wav@@g' | \ - awk '{if ($3 == "1") - {print $1,$2,"target"} - else - {print $1,$2,"nontarget"} - }'> $this_out_dir/trials.lst diff --git a/egs/cnceleb/resnet34/local/make_cnceleb2.sh b/egs/cnceleb/resnet34/local/make_cnceleb2.sh deleted file mode 100644 index 7bdad4728..000000000 --- a/egs/cnceleb/resnet34/local/make_cnceleb2.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 Jiawen Kang -# Apache 2.0. -# -# This script prepares the CN-Celeb2 dataset. - -if [ $# != 2 ]; then - echo "Usage: make_cnceleb2.sh " - echo "E.g.: make_cnceleb2.sh /export/corpora/CN-Celeb2 data" - exit 1 -fi - -in_dir=$1 -out_dir=$2 - -# Prepare the cnceleb2 training data -this_out_dir=${out_dir} -mkdir -p $this_out_dir 2>/dev/null -WAVFILE=$this_out_dir/wav.scp -SPKFILE=$this_out_dir/utt2spk -rm $WAVFILE $SPKFILE 2>/dev/null -this_in_dir=${in_dir} - -for spkr_id in `cat $this_in_dir/spk.lst`; do - for f in $in_dir/data/$spkr_id/*.wav; do - wav_id=$(basename $f | sed s:.wav$::) - echo "${spkr_id}-${wav_id} $f" >> $WAVFILE - echo "${spkr_id}-${wav_id} ${spkr_id}" >> $SPKFILE - done -done - -# utils/fix_data_dir.sh $this_out_dir \ No newline at end of file diff --git a/egs/cnceleb/resnet34/path.sh b/egs/cnceleb/resnet34/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/cnceleb/resnet34/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/cnceleb/resnet34/run.sh b/egs/cnceleb/resnet34/run.sh deleted file mode 100644 index cf1011d13..000000000 --- a/egs/cnceleb/resnet34/run.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -gpu_devices="6,7" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=1 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="." #feature output dictionary -exp_dir="." -lang=zh -dumpdir=dump/fbank -feats_type=fbank -token_type=spk -scp=feats.scp -type=kaldi_ark -stage=0 -stop_stage=4 - -# feature configuration -feats_dim=80 -sample_frequency=16000 -nj=32 -speed_perturb="0.9,1.0,1.1" - -# data -data_cnceleb= - -# exp tag -tag="" -inference_tag="basic" -inference_sv_model=sv.pb -sv_config=sv.yaml - -. utils/parse_options.sh || exit 1; - -model_dir="baseline_$(basename "${sv_config}" .yaml)_${feats_type}_${lang}_${token_type}_${tag}" - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train -valid_set=dev -test_sets="eval_enroll eval_test" - -# you can set gpu num for decoding here -gpuid_list=$gpu_devices # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - bash local/make_cnceleb1.sh ${data_cnceleb}/CN-Celeb1 ${feats_dir}/data - # bash local/make_cnceleb2.sh ${data_cnceleb}/CN-Celeb2 ${feats_dir}/data/cnceleb2_train - grep speech ${feats_dir}/data/eval_test/trials/trials.lst > ${feats_dir}/data/eval_test/trials/trials.lst.speech - # local/combine_data.sh ${feats_dir}/data/train ${feats_dir}/data/cnceleb1_train ${feats_dir}/data/cnceleb2_train -fi - -# Testing Stage -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Inference" - for dset in ${test_sets}; do - echo "extracting embedding for ${dset}" - asr_exp=${exp_dir}/exp/${model_dir} - _dir="${asr_exp}/${inference_tag}/${inference_sv_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="data/${dset}" - key_file=${_data}/wav.scp - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/sv_inference.JOB.log \ - python -m funasr.bin.sv_inference \ - --gpuid_list ${gpu_devices} \ - --ngpu ${_ngpu} \ - --key_file "${_logdir}"/keys.JOB.scp \ - --data_path_and_name_and_type data/${dset}/wav.scp,speech,sound \ - --allow_variable_data_keys true \ - --sv_train_config ${sv_config} \ - --sv_model_file ${inference_sv_model} \ - --output_dir "${_logdir}"/output.JOB \ - --num_workers 1 - - for f in xvector.ark; do - if [ -f "${_logdir}/output.1/${f}" ]; then - for i in $(seq "${_nj}"); do - echo "${_logdir}/output.${i}/${f}" - done > "${_dir}/${f}.flist" - fi - done - done - -fi - -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - - # compute eer and minDCF results - echo "stage 2: computing EER and minDCF" - asr_exp=${exp_dir}/exp/${model_dir} - _dir="${asr_exp}/${inference_tag}/${inference_sv_model}" - mkdir -p ${_dir}/score - cp ${_dir}/eval_enroll/xvector.ark.flist ${_dir}/score/spk2xvec.flist - cp ${_dir}/eval_test/xvector.ark.flist ${_dir}/score/utt2xvec.flist - cp ${feats_dir}/data/eval_test/trials/trials.lst.speech ${_dir}/score/trials - python sid/calc_trial_scores.py --no_pbar ${_dir}/score ${_dir}/score/trials ${_dir}/score/trials.cos - python sid/compute_eer.py ${_dir}/score/trials ${_dir}/score/trials.cos - python sid/compute_min_dcf.py --c-miss 10 --p-target 0.01 \ - ${_dir}/score/trials.cos ${_dir}/score/trials 2>/dev/null -fi \ No newline at end of file diff --git a/egs/cnceleb/resnet34/sid/calc_trial_scores.py b/egs/cnceleb/resnet34/sid/calc_trial_scores.py deleted file mode 100644 index 12bcde971..000000000 --- a/egs/cnceleb/resnet34/sid/calc_trial_scores.py +++ /dev/null @@ -1,160 +0,0 @@ -from __future__ import print_function -import numpy as np -import os -import kaldiio -from multiprocessing import Pool -import argparse -from tqdm import tqdm -import math - - -class MultiProcessRunner: - def __init__(self, fn): - self.args = None - self.process = fn - - def run(self): - parser = argparse.ArgumentParser("") - # Task-independent options - parser.add_argument("--nj", type=int, default=16) - parser.add_argument("--debug", action="store_true", default=False) - parser.add_argument("--no_pbar", action="store_true", default=False) - parser.add_argument("--verbose", action="store_ture", default=False) - - task_list, args = self.prepare(parser) - result_list = self.pool_run(task_list, args) - self.post(result_list, args) - - def prepare(self, parser): - raise NotImplementedError("Please implement the prepare function.") - - def post(self, result_list, args): - raise NotImplementedError("Please implement the post function.") - - def pool_run(self, tasks, args): - results = [] - if args.debug: - one_result = self.process(tasks[0]) - results.append(one_result) - else: - pool = Pool(args.nj) - for one_result in tqdm(pool.imap(self.process, tasks), total=len(tasks), ascii=True, disable=args.no_pbar): - results.append(one_result) - pool.close() - - return results - - -class MultiProcessRunnerV2: - def __init__(self, fn): - self.args = None - self.process = fn - - def run(self): - parser = argparse.ArgumentParser("") - # Task-independent options - parser.add_argument("--nj", type=int, default=16) - parser.add_argument("--debug", action="store_true", default=False) - parser.add_argument("--no_pbar", action="store_true", default=False) - parser.add_argument("--verbose", action="store_true", default=False) - - task_list, args = self.prepare(parser) - chunk_size = int(math.ceil(float(len(task_list)) / args.nj)) - if args.verbose: - print("Split {} tasks into {} sub-tasks with chunk_size {}".format(len(task_list), args.nj, chunk_size)) - subtask_list = [task_list[i*chunk_size: (i+1)*chunk_size] for i in range(args.nj)] - result_list = self.pool_run(subtask_list, args) - self.post(result_list, args) - - def prepare(self, parser): - raise NotImplementedError("Please implement the prepare function.") - - def post(self, result_list, args): - raise NotImplementedError("Please implement the post function.") - - def pool_run(self, tasks, args): - results = [] - if args.debug: - one_result = self.process(tasks[0]) - results.append(one_result) - else: - pool = Pool(args.nj) - for one_result in tqdm(pool.imap(self.process, tasks), total=len(tasks), ascii=True, disable=args.no_pbar): - results.append(one_result) - pool.close() - - return results - - -class MultiProcessRunnerV3(MultiProcessRunnerV2): - def run(self): - parser = argparse.ArgumentParser("") - # Task-independent options - parser.add_argument("--nj", type=int, default=16) - parser.add_argument("--debug", action="store_true", default=False) - parser.add_argument("--no_pbar", action="store_true", default=False) - parser.add_argument("--verbose", action="store_true", default=False) - parser.add_argument("--sr", type=int, default=16000) - - task_list, shared_param, args = self.prepare(parser) - chunk_size = int(math.ceil(float(len(task_list)) / args.nj)) - if args.verbose: - print("Split {} tasks into {} sub-tasks with chunk_size {}".format(len(task_list), args.nj, chunk_size)) - subtask_list = [(i, task_list[i * chunk_size: (i + 1) * chunk_size], shared_param, args) - for i in range(args.nj)] - result_list = self.pool_run(subtask_list, args) - self.post(result_list, args) - - - -class MyRunner(MultiProcessRunnerV3): - def prepare(self, parser): - assert isinstance(parser, argparse.ArgumentParser) - parser.add_argument("enroll_dir", type=str) - parser.add_argument("trial_in", type=str) - parser.add_argument("trial_out", type=str) - args = parser.parse_args() - - if not os.path.exists(os.path.dirname(args.trial_out)): - os.makedirs(os.path.dirname(args.trial_out)) - - flist_path = os.path.join(args.enroll_dir, "spk2xvec.flist") - spk2xvec = {} - for _path in open(flist_path, "r"): - for key, value in kaldiio.load_ark(_path.strip()): - if "-enroll" in key: - key = key.replace("-enroll", "") - spk2xvec[key] = value - - flist_path = os.path.join(args.enroll_dir, "utt2xvec.flist") - utt2xvec = {} - for _path in open(flist_path, 'r'): - for key, value in kaldiio.load_ark(_path.strip()): - utt2xvec[key] = value - - task_list = [one_line.strip().split(" ") for one_line in open(args.trial_in, "rt")] - return task_list, [spk2xvec, utt2xvec], args - - def post(self, results_list, args): - with open(args.trial_out, "wt") as fs: - for results in results_list: - for one_item in results: - fs.write(one_item+"\n") - - -def process(task_args): - task_id, task_list, [spk2xvec, utt2xvec], args = task_args - results = [] - for spk, utt, _ in task_list: - xvec = utt2xvec[utt] - normed_x = xvec / np.linalg.norm(xvec) - normed_y = spk2xvec[spk] / np.linalg.norm(spk2xvec[spk]) - score = np.sum(normed_x * normed_y) - results.append("{} {} {:.5f}".format(spk, utt, score)) - - return results - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/cnceleb/resnet34/sid/compute_eer.py b/egs/cnceleb/resnet34/sid/compute_eer.py deleted file mode 100644 index 0ca92808c..000000000 --- a/egs/cnceleb/resnet34/sid/compute_eer.py +++ /dev/null @@ -1,54 +0,0 @@ -import numpy as np -from sklearn.metrics import roc_curve -import argparse - - -def compute_eer(label, pred, positive_label=1): - """ - Python compute equal error rate (eer) - ONLY tested on binary classification - - :param label: ground-truth label, should be a 1-d list or np.array, each element represents the ground-truth label of one sample - :param pred: model prediction, should be a 1-d list or np.array, each element represents the model prediction of one sample - :param positive_label: the class that is viewed as positive class when computing EER - :return: equal error rate (EER) - """ - - # all fpr, tpr, fnr, fnr, threshold are lists (in the format of np.array) - fpr, tpr, threshold = roc_curve(label, pred, pos_label=positive_label) - fnr = 1 - tpr - - # the threshold of fnr == fpr - eer_threshold = threshold[np.nanargmin(np.absolute((fnr - fpr)))] - - # theoretically eer from fpr and eer from fnr should be identical but they can be slightly differ in reality - eer_1 = fpr[np.nanargmin(np.absolute((fnr - fpr)))] - eer_2 = fnr[np.nanargmin(np.absolute((fnr - fpr)))] - - # return the mean of eer from fpr and from fnr - eer = (eer_1 + eer_2) / 2 - return eer, eer_threshold - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("trials", help="trial list") - parser.add_argument("scores", help="score file, normalized to [0, 1]") - args = parser.parse_args() - - labels = [] - for one_line in open(args.trials, "r"): - labels.append(one_line.strip().rsplit(" ", 1)[-1] == "target") - labels = np.array(labels, dtype=int) - - scores = [] - for one_line in open(args.scores, "r"): - scores.append(float(one_line.strip().rsplit(" ", 1)[-1])) - scores = np.array(scores, dtype=float) - - eer, threshold = compute_eer(labels, scores) - print("EER is {:.4f} at threshold {:.4f}".format(eer * 100.0, threshold)) - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/egs/cnceleb/resnet34/sid/compute_min_dcf.py b/egs/cnceleb/resnet34/sid/compute_min_dcf.py deleted file mode 100644 index f2a6682f4..000000000 --- a/egs/cnceleb/resnet34/sid/compute_min_dcf.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2018 David Snyder -# Apache 2.0 - -# This script computes the minimum detection cost function, which is a common -# error metric used in speaker recognition. Compared to equal error-rate, -# which assigns equal weight to false negatives and false positives, this -# error-rate is usually used to assess performance in settings where achieving -# a low false positive rate is more important than achieving a low false -# negative rate. See the NIST 2016 Speaker Recognition Evaluation Plan at -# https://www.nist.gov/sites/default/files/documents/2016/10/07/sre16_eval_plan_v1.3.pdf -# for more details about the metric. -from __future__ import print_function -from operator import itemgetter -import sys, argparse, os - - -def GetArgs(): - parser = argparse.ArgumentParser(description="Compute the minimum " - "detection cost function along with the threshold at which it occurs. " - "Usage: sid/compute_min_dcf.py [options...] " - " " - "E.g., sid/compute_min_dcf.py --p-target 0.01 --c-miss 1 --c-fa 1 " - "exp/scores/trials data/test/trials", - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument('--p-target', type=float, dest="p_target", - default=0.01, - help='The prior probability of the target speaker in a trial.') - parser.add_argument('--c-miss', type=float, dest="c_miss", default=1, - help='Cost of a missed detection. This is usually not changed.') - parser.add_argument('--c-fa', type=float, dest="c_fa", default=1, - help='Cost of a spurious detection. This is usually not changed.') - parser.add_argument("scores_filename", - help="Input scores file, with columns of the form " - " ") - parser.add_argument("trials_filename", - help="Input trials file, with columns of the form " - " ") - sys.stderr.write(' '.join(sys.argv) + "\n") - args = parser.parse_args() - args = CheckArgs(args) - return args - - -def CheckArgs(args): - if args.c_fa <= 0: - raise Exception("--c-fa must be greater than 0") - if args.c_miss <= 0: - raise Exception("--c-miss must be greater than 0") - if args.p_target <= 0 or args.p_target >= 1: - raise Exception("--p-target must be greater than 0 and less than 1") - return args - - -# Creates a list of false-negative rates, a list of false-positive rates -# and a list of decision thresholds that give those error-rates. -def ComputeErrorRates(scores, labels): - - # Sort the scores from smallest to largest, and also get the corresponding - # indexes of the sorted scores. We will treat the sorted scores as the - # thresholds at which the the error-rates are evaluated. - sorted_indexes, thresholds = zip(*sorted( - [(index, threshold) for index, threshold in enumerate(scores)], - key=itemgetter(1))) - labels = [labels[i] for i in sorted_indexes] - fns = [] - tns = [] - - # At the end of this loop, fns[i] is the number of errors made by - # incorrectly rejecting scores less than thresholds[i]. And, tns[i] - # is the total number of times that we have correctly rejected scores - # less than thresholds[i]. - for i in range(0, len(labels)): - if i == 0: - fns.append(labels[i]) - tns.append(1 - labels[i]) - else: - fns.append(fns[i-1] + labels[i]) - tns.append(tns[i-1] + 1 - labels[i]) - positives = sum(labels) - negatives = len(labels) - positives - - # Now divide the false negatives by the total number of - # positives to obtain the false negative rates across - # all thresholds - fnrs = [fn / float(positives) for fn in fns] - - # Divide the true negatives by the total number of - # negatives to get the true negative rate. Subtract these - # quantities from 1 to get the false positive rates. - fprs = [1 - tn / float(negatives) for tn in tns] - return fnrs, fprs, thresholds - - -# Computes the minimum of the detection cost function. The comments refer to -# equations in Section 3 of the NIST 2016 Speaker Recognition Evaluation Plan. -def ComputeMinDcf(fnrs, fprs, thresholds, p_target, c_miss, c_fa): - min_c_det = float("inf") - min_c_det_threshold = thresholds[0] - for i in range(0, len(fnrs)): - # See Equation (2). it is a weighted sum of false negative - # and false positive errors. - c_det = c_miss * fnrs[i] * p_target + c_fa * fprs[i] * (1 - p_target) - if c_det < min_c_det: - min_c_det = c_det - min_c_det_threshold = thresholds[i] - # See Equations (3) and (4). Now we normalize the cost. - c_def = min(c_miss * p_target, c_fa * (1 - p_target)) - min_dcf = min_c_det / c_def - return min_dcf, min_c_det_threshold - -def main(): - args = GetArgs() - scores_file = open(args.scores_filename, 'r').readlines() - trials_file = open(args.trials_filename, 'r').readlines() - c_miss = args.c_miss - c_fa = args.c_fa - p_target = args.p_target - - scores = [] - labels = [] - - trials = {} - for line in trials_file: - utt1, utt2, target = line.rstrip().split() - trial = utt1 + " " + utt2 - trials[trial] = target - - for line in scores_file: - utt1, utt2, score = line.rstrip().split() - trial = utt1 + " " + utt2 - if trial in trials: - scores.append(float(score)) - if trials[trial] == "target": - labels.append(1) - else: - labels.append(0) - else: - raise Exception("Missing entry for " + utt1 + " and " + utt2 - + " " + args.scores_filename) - - fnrs, fprs, thresholds = ComputeErrorRates(scores, labels) - mindcf, threshold = ComputeMinDcf(fnrs, fprs, thresholds, p_target, - c_miss, c_fa) - # sys.stdout.write("{0:.4f}\n".format(mindcf)) - sys.stdout.write("minDCF is {0:.4f} at threshold {1:.4f} (p-target={2}, c-miss={3}, " - "c-fa={4})\n".format(mindcf, threshold, p_target,c_miss, c_fa)) - - -if __name__ == "__main__": - main() diff --git a/egs/cnceleb/resnet34/sid/speaker_verification.py b/egs/cnceleb/resnet34/sid/speaker_verification.py deleted file mode 100644 index 53c0d2503..000000000 --- a/egs/cnceleb/resnet34/sid/speaker_verification.py +++ /dev/null @@ -1,167 +0,0 @@ -from __future__ import print_function -import numpy as np -import os -import kaldiio -from multiprocessing import Pool -import argparse -from tqdm import tqdm -import math -from funasr.utils.types import str2triple_str -import logging -from typing import List, Union, Tuple, Sequence -from funasr.bin.sv_inference import inference_modelscope -import soundfile -import torch - - -class MultiProcessRunner: - def __init__(self, fn): - self.process = fn - - def run(self): - parser = argparse.ArgumentParser("") - # Task-independent options - parser.add_argument("--njobs", type=int, default=16) - parser.add_argument("--debug", action="store_true", default=False) - parser.add_argument("--no_pbar", action="store_true", default=False) - parser.add_argument("--verbose", action="store_true", default=False) - parser.add_argument("--log_level", type=str, default="INFO") - parser.add_argument("--sr", type=int, default=16000) - - task_list, shared_param, args = self.prepare(parser) - chunk_size = int(math.ceil(float(len(task_list)) / args.njobs)) - if args.verbose: - print("Split {} tasks into {} sub-tasks with chunk_size {}".format(len(task_list), args.njobs, chunk_size)) - subtask_list = [(i, task_list[i * chunk_size: (i + 1) * chunk_size], shared_param, args) - for i in range(args.njobs)] - result_list = self.pool_run(subtask_list, args) - self.post(result_list, args) - - def prepare(self, parser: argparse.ArgumentParser): - raise NotImplementedError("Please implement the prepare function.") - - def post(self, results_list: list, args: argparse.Namespace): - raise NotImplementedError("Please implement the post function.") - - def pool_run(self, tasks: list, args: argparse.Namespace): - results = [] - if args.debug: - one_result = self.process(tasks[0]) - results.append(one_result) - else: - pool = Pool(args.njobs) - for one_result in tqdm(pool.imap(self.process, tasks), total=len(tasks), ascii=True, disable=args.no_pbar): - results.append(one_result) - pool.close() - - return results - - -class MyRunner(MultiProcessRunner): - def prepare(self, parser: argparse.ArgumentParser): - parser.add_argument( - "--gpu_inference", - type=bool, - default=False - ) - parser.add_argument( - "--data_path_and_name_and_type", - type=str2triple_str, - required=True, - action="append" - ) - parser.add_argument( - "--gpu_devices", - type=lambda devices: devices.split(","), - default=None, - ) - args = parser.parse_args() - - logging.basicConfig( - level=args.log_level, - format="%(asctime)s (%(module)s:%(lineno)d) %(levelname)s: %(message)s", - ) - - if args.gpu_inference and (args.gpu_devices is None or len(args.gpu_devices) == 0): - logging.warning("gpu_inference is set to True, but gpu_devices is not given, use CPU instead.") - args.gpu_inference = False - - if args.gpu_inference: - args.njobs = args.njobs * len(args.gpu_devices) - - speech_dict = {} - ref_speech_dict = {} - for _path, _name, _type in args.data_path_and_name_and_type: - if _name == "speech": - speech_dict = self.read_data_path(_path) - elif _name == "ref_speech": - ref_speech_dict = self.read_data_path(_path) - - task_list, args.njobs = self.get_key_list(args.data_path_and_name_and_type, args.njobs) - - return task_list, [speech_dict, ref_speech_dict], args - - def read_data_path(self, file_path): - results = {} - for line in open(file_path, "r"): - key, path = line.strip().split(" ", 1) - results[key] = path - - return results - - def get_key_list( - self, - data_path_and_name_and_type: Sequence[Tuple[str, str, str]], - njobs: int - ): - first_data = data_path_and_name_and_type[0] - content = open(first_data[0], "r").readlines() - line_number = len(content) - njobs = min(njobs, line_number) - logging.warning("njobs is reduced to {}, since only {} lines exist in {}".format( - njobs, line_number, first_data[0], - )) - key_list = [line.strip().split(" ", 1)[0] for line in content] - return key_list, njobs - - def post(self, results_list: list, args: argparse.Namespace): - for results in results_list: - for key, value in results: - logging.info("{} {}".format(key, value)) - - -def process(task_args): - task_id, key_list, [speech_dict, ref_speech_dict], args = task_args - if args.gpu_inference: - device = args.gpu_devices[task_id % len(args.gpu_devices)] - torch.cuda.set_device("cuda:".format(device)) - inference_func = inference_modelscope( - output_dir=None, - batch_size=1, - dtype="float32", - ngpu=1 if args.gpu_inference else 0, - seed=0, - num_workers=0, - log_level=logging.INFO, - key_file=None, - sv_train_config="sv.yaml", - sv_model_file="sv.pb", - model_tag=None, - allow_variable_data_keys=True, - streaming=False, - embedding_node="resnet1_dense", - sv_threshold=0.9465, - ) - results = {} - for key in key_list: - speech = soundfile.read(speech_dict[key])[0] - ref_speech = soundfile.read(ref_speech_dict[key])[0] - ret = inference_func(None, (speech, ref_speech)) - results[key] = ret["value"] - - return results - - -if __name__ == '__main__': - my_runner = MyRunner(process) - my_runner.run() diff --git a/egs/cnceleb/resnet34/sv.yaml b/egs/cnceleb/resnet34/sv.yaml deleted file mode 100644 index adf3382d3..000000000 --- a/egs/cnceleb/resnet34/sv.yaml +++ /dev/null @@ -1,3515 +0,0 @@ -# network architecture -input_size: null -specaug: null -normalize: null -init: null -model: espnet -model_conf: {} -# encoder related -encoder: resnet34 -encoder_conf: - use_head_conv: true - batchnorm_momentum: 0.5 - use_head_maxpool: false - num_nodes_pooling_layer: 256 - layers_in_block: - - 3 - - 4 - - 6 - - 3 - filters_in_block: - - 32 - - 64 - - 128 - - 256 - -# Pooling related -pooling_type: statistic - -# decoder related -decoder: dense -decoder_conf: - num_nodes_resnet1: 256 - num_nodes_last_layer: 256 - batchnorm_momentum: 0.5 - -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: povey - n_mels: 80 - frame_length: 25 - frame_shift: 10 - filter_length_min: -1 - filter_length_max: -1 - lfr_m: 1 - lfr_n: 1 - -log_interval: 50 - -token_list: -- R0003_M0046_S001 -- R0003_M0046_S002 -- R0003_M0046_S003 -- R0003_M0046_S004 -- R0003_M0047_S001 -- R0003_M0047_S002 -- R0003_M0047_S003 -- R0003_M0047_S004 -- R0004_M0012_S001 -- R0004_M0012_S002 -- R0004_M0012_S003 -- R0004_M0012_S004 -- R0004_M0017_S001 -- R0004_M0017_S002 -- R0004_M0017_S003 -- R0004_M0017_S004 -- R0004_M0018_S001 -- R0004_M0018_S002 -- R0004_M0018_S003 -- R0004_M0018_S004 -- R0004_M0022_S001 -- R0004_M0022_S002 -- R0004_M0022_S003 -- R0004_M0022_S004 -- R0004_M0025_S001 -- R0004_M0025_S002 -- R0004_M0025_S003 -- R0004_M0025_S004 -- R0004_M0027_S001 -- R0004_M0027_S002 -- R0004_M0027_S003 -- R0004_M0027_S004 -- R0004_M0028_S001 -- R0004_M0028_S002 -- R0004_M0028_S003 -- R0004_M0028_S004 -- R0005_M0035_S001 -- R0005_M0035_S002 -- R0005_M0035_S003 -- R0005_M0035_S004 -- R0005_M0040_S001 -- R0005_M0040_S002 -- R0005_M0040_S003 -- R0005_M0040_S004 -- R0005_M0041_S001 -- R0005_M0041_S002 -- R0005_M0041_S003 -- R0005_M0041_S004 -- R0008_M0050_S001 -- R0008_M0050_S002 -- R0008_M0050_S003 -- R0008_M0050_S004 -- R0008_M0051_S001 -- R0008_M0051_S002 -- R0008_M0051_S003 -- R0008_M0051_S004 -- R0008_M0052_S001 -- R0008_M0052_S002 -- R0008_M0052_S003 -- R0008_M0052_S004 -- R0008_M0053_S001 -- R0008_M0053_S002 -- R0008_M0053_S003 -- R0008_M0053_S004 -- R0008_M0054_S001 -- R0008_M0054_S002 -- R0008_M0054_S003 -- R0008_M0054_S004 -- R0008_M0055_S001 -- R0008_M0055_S002 -- R0008_M0055_S003 -- R0008_M0055_S004 -- R0008_M0056_S001 -- R0008_M0056_S002 -- R0008_M0056_S003 -- R0008_M0056_S004 -- R0008_M0057_S001 -- R0008_M0057_S002 -- R0008_M0057_S003 -- R0008_M0057_S004 -- R0008_M0058_S001 -- R0008_M0058_S002 -- R0008_M0058_S003 -- R0008_M0058_S004 -- R0008_M0060_S001 -- R0008_M0060_S002 -- R0008_M0060_S003 -- R0008_M0060_S004 -- R0008_M0063_S001 -- R0008_M0063_S002 -- R0008_M0063_S003 -- R0008_M0063_S004 -- R0008_M0064_S001 -- R0008_M0064_S002 -- R0008_M0064_S003 -- R0008_M0064_S004 -- R0008_M0069_S001 -- R0008_M0069_S002 -- R0008_M0069_S003 -- R0008_M0069_S004 -- R0008_M0070_S001 -- R0008_M0070_S002 -- R0008_M0070_S003 -- R0008_M0070_S004 -- R0008_M0071_S001 -- R0008_M0071_S002 -- R0008_M0071_S003 -- R0008_M0071_S004 -- R0008_M0072_S001 -- R0008_M0072_S002 -- R0008_M0072_S003 -- R0008_M0072_S004 -- R0008_M0073_S001 -- R0008_M0073_S002 -- R0008_M0073_S003 -- R0008_M0073_S004 -- R0008_M0074_S001 -- R0008_M0074_S002 -- R0008_M0074_S003 -- R0008_M0074_S004 -- R0008_M0075_S001 -- R0008_M0075_S002 -- R0008_M0075_S003 -- R0008_M0075_S004 -- R0008_M0076_S001 -- R0008_M0076_S002 -- R0008_M0076_S003 -- R0008_M0076_S004 -- R0014_M0077_S001 -- R0014_M0077_S002 -- R0014_M0077_S003 -- R0014_M0077_S004 -- R0014_M0078_S001 -- R0014_M0078_S002 -- R0014_M0078_S003 -- R0014_M0078_S004 -- R0014_M0079_S001 -- R0014_M0079_S002 -- R0014_M0079_S003 -- R0014_M0079_S004 -- R0014_M0080_S001 -- R0014_M0080_S002 -- R0014_M0080_S003 -- R0014_M0080_S004 -- R0014_M0083_S001 -- R0014_M0083_S002 -- R0014_M0083_S003 -- R0014_M0083_S004 -- R0014_M0084_S001 -- R0014_M0084_S002 -- R0014_M0084_S003 -- R0014_M0084_S004 -- R0014_M0085_S001 -- R0014_M0085_S002 -- R0014_M0085_S003 -- R0014_M0085_S004 -- R0014_M0086_S001 -- R0014_M0086_S002 -- R0014_M0086_S003 -- R0014_M0086_S004 -- R0014_M0087_S001 -- R0014_M0087_S002 -- R0014_M0087_S003 -- R0014_M0087_S004 -- R0014_M0089_S001 -- R0014_M0089_S002 -- R0014_M0089_S003 -- R0014_M0089_S004 -- R0014_M0090_S001 -- R0014_M0090_S002 -- R0014_M0090_S003 -- R0014_M0090_S004 -- R0014_M0091_S001 -- R0014_M0091_S002 -- R0014_M0091_S003 -- R0014_M0091_S004 -- R0014_M0092_S001 -- R0014_M0092_S002 -- R0014_M0092_S003 -- R0014_M0092_S004 -- R0014_M0093_S001 -- R0014_M0093_S002 -- R0014_M0093_S003 -- R0014_M0093_S004 -- R0014_M0094_S001 -- R0014_M0094_S002 -- R0014_M0094_S003 -- R0014_M0094_S004 -- R0014_M0097_S001 -- R0014_M0097_S002 -- R0014_M0097_S003 -- R0014_M0097_S004 -- R0014_M0098_S001 -- R0014_M0098_S002 -- R0014_M0098_S003 -- R0014_M0098_S004 -- R0014_M0099_S001 -- R0014_M0099_S002 -- R0014_M0099_S003 -- R0014_M0099_S004 -- R0014_M0100_S001 -- R0014_M0100_S002 -- R0014_M0100_S003 -- R0014_M0100_S004 -- R0014_M0101_S001 -- R0014_M0101_S002 -- R0014_M0101_S003 -- R0014_M0101_S004 -- R0014_M0102_S001 -- R0014_M0102_S002 -- R0014_M0102_S003 -- R0014_M0102_S004 -- R0014_M0105_S001 -- R0014_M0105_S002 -- R0014_M0105_S003 -- R0014_M0105_S004 -- R0014_M0106_S001 -- R0014_M0106_S002 -- R0014_M0106_S003 -- R0014_M0106_S004 -- R0014_M0107_S001 -- R0014_M0107_S002 -- R0014_M0107_S003 -- R0014_M0107_S004 -- R0014_M0108_S001 -- R0014_M0108_S002 -- R0014_M0108_S003 -- R0014_M0108_S004 -- R0014_M0109_S001 -- R0014_M0109_S002 -- R0014_M0109_S003 -- R0014_M0109_S004 -- R0014_M0110_S001 -- R0014_M0110_S002 -- R0014_M0110_S003 -- R0014_M0110_S004 -- R0014_M0111_S001 -- R0014_M0111_S002 -- R0014_M0111_S003 -- R0014_M0111_S004 -- R0014_M0112_S001 -- R0014_M0112_S002 -- R0014_M0112_S003 -- R0014_M0112_S004 -- R0015_M0115_S001 -- R0015_M0115_S002 -- R0015_M0115_S003 -- R0015_M0115_S004 -- R0015_M0116_S001 -- R0015_M0116_S002 -- R0015_M0116_S003 -- R0015_M0116_S004 -- R0015_M0117_S001 -- R0015_M0117_S002 -- R0015_M0117_S003 -- R0015_M0117_S004 -- R0015_M0118_S001 -- R0015_M0118_S002 -- R0015_M0118_S003 -- R0015_M0118_S004 -- R0015_M0119_S001 -- R0015_M0119_S002 -- R0015_M0119_S003 -- R0015_M0119_S004 -- R0015_M0120_S001 -- R0015_M0120_S002 -- R0015_M0120_S003 -- R0015_M0120_S004 -- R0015_M0121_S001 -- R0015_M0121_S002 -- R0015_M0121_S003 -- R0015_M0121_S004 -- R0015_M0122_S001 -- R0015_M0122_S002 -- R0015_M0122_S003 -- R0015_M0122_S004 -- R0015_M0123_S001 -- R0015_M0123_S002 -- R0015_M0123_S003 -- R0015_M0123_S004 -- R0015_M0124_S001 -- R0015_M0124_S002 -- R0015_M0124_S003 -- R0015_M0124_S004 -- R0015_M0125_S001 -- R0015_M0125_S002 -- R0015_M0125_S003 -- R0015_M0125_S004 -- R0015_M0126_S001 -- R0015_M0126_S002 -- R0015_M0126_S003 -- R0015_M0126_S004 -- R0015_M0129_S001 -- R0015_M0129_S002 -- R0015_M0129_S003 -- R0015_M0129_S004 -- R0015_M0130_S001 -- R0015_M0130_S002 -- R0015_M0130_S003 -- R0015_M0130_S004 -- R0015_M0133_S001 -- R0015_M0133_S002 -- R0015_M0133_S003 -- R0015_M0133_S004 -- R0015_M0134_S001 -- R0015_M0134_S002 -- R0015_M0134_S003 -- R0015_M0134_S004 -- R0015_M0135_S001 -- R0015_M0135_S002 -- R0015_M0135_S003 -- R0015_M0135_S004 -- R0015_M0138_S001 -- R0015_M0138_S002 -- R0015_M0138_S003 -- R0015_M0138_S004 -- R0015_M0139_S001 -- R0015_M0139_S002 -- R0015_M0139_S003 -- R0015_M0139_S004 -- R0015_M0140_S001 -- R0015_M0140_S002 -- R0015_M0140_S003 -- R0015_M0140_S004 -- R0015_M0141_S001 -- R0015_M0141_S002 -- R0015_M0141_S003 -- R0015_M0141_S004 -- R0015_M0142_S001 -- R0015_M0142_S002 -- R0015_M0142_S003 -- R0015_M0142_S004 -- R0015_M0143_S001 -- R0015_M0143_S002 -- R0015_M0143_S003 -- R0015_M0143_S004 -- R0015_M0144_S001 -- R0015_M0144_S002 -- R0015_M0144_S003 -- R0015_M0144_S004 -- R0015_M0145_S001 -- R0015_M0145_S002 -- R0015_M0145_S003 -- R0015_M0145_S004 -- R0015_M0146_S001 -- R0015_M0146_S002 -- R0015_M0146_S003 -- R0015_M0146_S004 -- R0015_M0147_S001 -- R0015_M0147_S002 -- R0015_M0147_S003 -- R0015_M0147_S004 -- R0015_M0148_S001 -- R0015_M0148_S002 -- R0015_M0148_S003 -- R0015_M0148_S004 -- R0015_M0149_S001 -- R0015_M0149_S002 -- R0015_M0149_S003 -- R0015_M0149_S004 -- R0015_M0150_S001 -- R0015_M0150_S002 -- R0015_M0150_S003 -- R0015_M0150_S004 -- R0015_M0151_S001 -- R0015_M0151_S002 -- R0015_M0151_S003 -- R0015_M0151_S004 -- R0015_M0152_S002 -- R0015_M0152_S004 -- R0015_M0153_S001 -- R0015_M0153_S002 -- R0015_M0153_S003 -- R0015_M0153_S004 -- R0015_M0158_S001 -- R0015_M0158_S002 -- R0015_M0158_S003 -- R0015_M0158_S004 -- R0015_M0159_S001 -- R0015_M0159_S002 -- R0015_M0159_S003 -- R0015_M0159_S004 -- R0015_M0160_S001 -- R0015_M0160_S002 -- R0015_M0160_S003 -- R0015_M0160_S004 -- R0015_M0161_S001 -- R0015_M0161_S002 -- R0015_M0161_S003 -- R0015_M0161_S004 -- R0015_M0162_S001 -- R0015_M0162_S002 -- R0015_M0162_S003 -- R0015_M0162_S004 -- R0015_M0163_S001 -- R0015_M0163_S002 -- R0015_M0163_S003 -- R0015_M0163_S004 -- R0020_M0166_S001 -- R0020_M0166_S002 -- R0020_M0166_S003 -- R0020_M0166_S004 -- R0020_M0167_S001 -- R0020_M0167_S002 -- R0020_M0167_S003 -- R0020_M0167_S004 -- R0020_M0168_S001 -- R0020_M0168_S002 -- R0020_M0168_S003 -- R0020_M0168_S004 -- R0020_M0169_S001 -- R0020_M0169_S002 -- R0020_M0169_S003 -- R0020_M0169_S004 -- R0020_M0170_S001 -- R0020_M0170_S002 -- R0020_M0170_S003 -- R0020_M0170_S004 -- R0020_M0171_S001 -- R0020_M0171_S002 -- R0020_M0171_S003 -- R0020_M0171_S004 -- R0020_M0172_S001 -- R0020_M0172_S002 -- R0020_M0172_S003 -- R0020_M0172_S004 -- R0020_M0175_S001 -- R0020_M0175_S002 -- R0020_M0175_S003 -- R0020_M0175_S004 -- R0020_M0176_S001 -- R0020_M0176_S002 -- R0020_M0176_S003 -- R0020_M0176_S004 -- R0020_M0178_S001 -- R0020_M0178_S002 -- R0020_M0178_S003 -- R0020_M0178_S004 -- R0020_M0179_S001 -- R0020_M0179_S002 -- R0020_M0179_S003 -- R0020_M0179_S004 -- R0020_M0183_S001 -- R0020_M0183_S002 -- R0020_M0183_S003 -- R0020_M0183_S004 -- R0020_M0184_S001 -- R0020_M0184_S002 -- R0020_M0184_S003 -- R0020_M0184_S004 -- R0020_M0185_S001 -- R0020_M0185_S002 -- R0020_M0185_S003 -- R0020_M0185_S004 -- R0020_M0186_S001 -- R0020_M0186_S002 -- R0020_M0186_S003 -- R0020_M0186_S004 -- R0020_M0190_S001 -- R0020_M0190_S002 -- R0020_M0190_S003 -- R0020_M0190_S004 -- R0020_M0191_S001 -- R0020_M0191_S002 -- R0020_M0191_S003 -- R0020_M0191_S004 -- R0020_M0192_S001 -- R0020_M0192_S002 -- R0020_M0192_S003 -- R0020_M0192_S004 -- R0020_M0193_S001 -- R0020_M0193_S002 -- R0020_M0193_S003 -- R0020_M0193_S004 -- R1019_M1928_S001 -- R1019_M1928_S002 -- R1019_M1929_S001 -- R1019_M1929_S002 -- R1019_M1945_S001 -- R1019_M1945_S002 -- R1019_M1945_S003 -- R1019_M1945_S004 -- R1019_M1946_S001 -- R1019_M1946_S002 -- R1019_M1946_S003 -- R1019_M1946_S004 -- R1019_M1948_S001 -- R1019_M1948_S002 -- R1019_M1949_S001 -- R1019_M1949_S002 -- R1019_M1950_S001 -- R1019_M1950_S002 -- R1019_M1953_S001 -- R1019_M1953_S002 -- R1019_M1954_S001 -- R1019_M1954_S002 -- R1019_M1956_S001 -- R1019_M1956_S002 -- R1019_M1960_S001 -- R1019_M1960_S002 -- R1019_M1963_S001 -- R1019_M1963_S002 -- R1019_M1965_S001 -- R1019_M1965_S002 -- R1019_M1967_S001 -- R1019_M1967_S002 -- R1019_M1969_S001 -- R1019_M1969_S002 -- R1019_M1971_S001 -- R1019_M1971_S002 -- R1019_M1972_S001 -- R1019_M1972_S002 -- R1019_M1975_S001 -- R1019_M1975_S002 -- R1019_M1977_S001 -- R1019_M1977_S002 -- R1019_M1979_S001 -- R1019_M1979_S002 -- R1019_M1981_S001 -- R1019_M1981_S002 -- R1019_M1987_S001 -- R1019_M1987_S002 -- R1019_M1989_S001 -- R1019_M1989_S002 -- R1019_M1993_S001 -- R1019_M1993_S002 -- R1019_M1995_S001 -- R1019_M1995_S002 -- R1019_M1997_S001 -- R1019_M1997_S002 -- R1019_M1998_S001 -- R1019_M1998_S002 -- R1019_M4004_S001 -- R1019_M4004_S002 -- R1019_M4005_S001 -- R1019_M4005_S002 -- R1019_M4007_S001 -- R1019_M4007_S002 -- R1019_M4011_S001 -- R1019_M4011_S002 -- R1019_M4013_S001 -- R1019_M4013_S002 -- R1019_M4015_S001 -- R1019_M4015_S002 -- R1019_M4017_S001 -- R1019_M4017_S002 -- R1019_M4020_S001 -- R1019_M4020_S002 -- R1019_M4021_S001 -- R1019_M4021_S002 -- R1019_M4026_S001 -- R1019_M4026_S002 -- R1019_M4028_S001 -- R1019_M4028_S002 -- R1019_M4030_S001 -- R1019_M4030_S002 -- R1019_M4031_S001 -- R1019_M4031_S002 -- R1019_M4031_S003 -- R1019_M4031_S004 -- R1019_M4033_S001 -- R1019_M4033_S002 -- R1019_M4035_S001 -- R1019_M4035_S002 -- R1019_M4039_S001 -- R1019_M4039_S002 -- R1019_M4041_S001 -- R1019_M4041_S002 -- R1019_M4043_S001 -- R1019_M4043_S002 -- R1019_M4051_S001 -- R1019_M4051_S002 -- R1019_M4052_S001 -- R1019_M4052_S002 -- R1019_M4052_S003 -- R1019_M4052_S004 -- R1019_M4055_S001 -- R1019_M4055_S002 -- R1019_M4056_S001 -- R1019_M4056_S002 -- R1019_M4056_S003 -- R1019_M4057_S001 -- R1019_M4057_S002 -- R1019_M4059_S001 -- R1019_M4059_S002 -- R1019_M4063_S001 -- R1019_M4063_S002 -- R1019_M4070_S001 -- R1019_M4070_S002 -- R1019_M4071_S001 -- R1019_M4071_S002 -- R1019_M4075_S001 -- R1019_M4075_S002 -- R1021_M1932_S001 -- R1021_M1932_S002 -- R1021_M1933_S001 -- R1021_M1933_S002 -- R1021_M1935_S001 -- R1021_M1935_S002 -- R1021_M1938_S001 -- R1021_M1938_S002 -- R1021_M1940_S001 -- R1021_M1940_S002 -- R1021_M1942_S001 -- R1021_M1942_S002 -- R1021_M1944_S001 -- R1021_M1944_S002 -- R1021_M1947_S001 -- R1021_M1947_S002 -- R1021_M1959_S001 -- R1021_M1959_S002 -- R1021_M1961_S001 -- R1021_M1961_S002 -- R1021_M1986_S001 -- R1021_M1986_S002 -- R1021_M4012_S001 -- R1021_M4012_S002 -- R1021_M4025_S001 -- R1021_M4025_S002 -- R1021_M4032_S001 -- R1021_M4032_S002 -- R1021_M4032_S003 -- R1021_M4032_S004 -- R1021_M4062_S001 -- R1021_M4062_S002 -- R1021_M4073_S001 -- R1021_M4073_S002 -- R1021_M4078_S001 -- R1021_M4078_S002 -- R1021_M4080_S001 -- R1021_M4080_S002 -- R1021_M4082_S001 -- R1021_M4082_S002 -- R1021_M4083_S001 -- R1021_M4083_S002 -- R2001_M2205_S001 -- R2001_M2205_S002 -- R2001_M2205_S003 -- R2001_M2206_S001 -- R2001_M2206_S002 -- R2001_M2206_S003 -- R2105_M3164_S001 -- R2105_M3164_S002 -- R2105_M3164_S003 -- R2105_M3175_S001 -- R2105_M3175_S002 -- R2105_M3175_S003 -- R2105_M3318_S001 -- R2105_M3318_S002 -- R2105_M3318_S003 -- R2108_M2692_S001 -- R2108_M2692_S002 -- R2108_M2692_S003 -- R2108_M3199_S001 -- R2108_M3199_S002 -- R2108_M3199_S003 -- R2108_M3200_S001 -- R2108_M3200_S002 -- R2108_M3200_S003 -- R2108_M3206_S001 -- R2108_M3206_S002 -- R2108_M3206_S003 -- R2108_M3210_S001 -- R2108_M3210_S002 -- R2108_M3210_S003 -- R2108_M3223_S001 -- R2108_M3223_S002 -- R2108_M3223_S003 -- R2108_M3225_S001 -- R2108_M3225_S002 -- R2108_M3225_S003 -- R2108_M3230_S001 -- R2108_M3230_S002 -- R2108_M3230_S003 -- R2108_M3243_S001 -- R2108_M3243_S002 -- R2108_M3243_S003 -- R2108_M3244_S001 -- R2108_M3244_S002 -- R2108_M3244_S003 -- id00000 -- id00001 -- id00002 -- id00003 -- id00004 -- id00005 -- id00006 -- id00007 -- id00008 -- id00009 -- id00010 -- id00011 -- id00012 -- id00013 -- id00014 -- id00015 -- id00016 -- id00017 -- id00018 -- id00019 -- id00020 -- id00021 -- id00022 -- id00023 -- id00024 -- id00025 -- id00026 -- id00027 -- id00028 -- id00029 -- id00030 -- id00031 -- id00032 -- id00033 -- id00034 -- id00035 -- id00036 -- id00037 -- id00038 -- id00039 -- id00040 -- id00041 -- id00042 -- id00043 -- id00044 -- id00045 -- id00046 -- id00047 -- id00048 -- id00049 -- id00050 -- id00051 -- id00052 -- id00053 -- id00054 -- id00055 -- id00056 -- id00057 -- id00058 -- id00059 -- id00060 -- id00061 -- id00062 -- id00063 -- id00064 -- id00065 -- id00066 -- id00067 -- id00068 -- id00069 -- id00070 -- id00071 -- id00072 -- id00073 -- id00074 -- id00075 -- id00076 -- id00077 -- id00078 -- id00079 -- id00080 -- id00081 -- id00082 -- id00083 -- id00084 -- id00085 -- id00086 -- id00087 -- id00088 -- id00089 -- id00090 -- id00091 -- id00092 -- id00093 -- id00094 -- id00095 -- id00096 -- id00097 -- id00098 -- id00099 -- id00100 -- id00101 -- id00102 -- id00103 -- id00104 -- id00105 -- id00106 -- id00107 -- id00108 -- id00109 -- id00110 -- id00111 -- id00112 -- id00113 -- id00114 -- id00115 -- id00116 -- id00117 -- id00118 -- id00119 -- id00120 -- id00121 -- id00122 -- id00123 -- id00124 -- id00125 -- id00126 -- id00127 -- id00128 -- id00129 -- id00130 -- id00131 -- id00132 -- id00133 -- id00134 -- id00135 -- id00136 -- id00137 -- id00138 -- id00139 -- id00140 -- id00141 -- id00142 -- id00145 -- id00146 -- id00148 -- id00149 -- id00151 -- id00152 -- id00153 -- id00154 -- id00155 -- id00156 -- id00157 -- id00158 -- id00159 -- id00160 -- id00161 -- id00162 -- id00163 -- id00164 -- id00165 -- id00166 -- id00167 -- id00169 -- id00170 -- id00171 -- id00173 -- id00174 -- id00175 -- id00176 -- id00177 -- id00178 -- id00179 -- id00180 -- id00181 -- id00182 -- id00183 -- id00184 -- id00185 -- id00186 -- id00187 -- id00188 -- id00189 -- id00190 -- id00191 -- id00192 -- id00193 -- id00194 -- id00195 -- id00196 -- id00197 -- id00198 -- id00199 -- id00200 -- id00201 -- id00203 -- id00204 -- id00206 -- id00207 -- id00208 -- id00209 -- id00210 -- id00211 -- id00213 -- id00214 -- id00215 -- id00216 -- id00217 -- id00218 -- id00219 -- id00220 -- id00221 -- id00222 -- id00223 -- id00224 -- id00225 -- id00226 -- id00228 -- id00230 -- id00231 -- id00233 -- id00234 -- id00235 -- id00236 -- id00237 -- id00238 -- id00240 -- id00241 -- id00242 -- id00243 -- id00244 -- id00245 -- id00246 -- id00247 -- id00248 -- id00249 -- id00250 -- id00251 -- id00252 -- id00253 -- id00254 -- id00256 -- id00257 -- id00258 -- id00259 -- id00260 -- id00261 -- id00262 -- id00263 -- id00264 -- id00265 -- id00266 -- id00267 -- id00268 -- id00269 -- id00270 -- id00271 -- id00272 -- id00274 -- id00275 -- id00276 -- id00278 -- id00279 -- id00280 -- id00281 -- id00282 -- id00283 -- id00284 -- id00285 -- id00286 -- id00287 -- id00288 -- id00289 -- id00290 -- id00291 -- id00292 -- id00293 -- id00294 -- id00295 -- id00296 -- id00297 -- id00298 -- id00299 -- id00300 -- id00301 -- id00302 -- id00303 -- id00304 -- id00305 -- id00306 -- id00307 -- id00308 -- id00309 -- id00310 -- id00311 -- id00312 -- id00313 -- id00314 -- id00315 -- id00316 -- id00318 -- id00319 -- id00320 -- id00322 -- id00323 -- id00324 -- id00325 -- id00326 -- id00327 -- id00328 -- id00329 -- id00330 -- id00331 -- id00332 -- id00333 -- id00334 -- id00335 -- id00336 -- id00337 -- id00338 -- id00339 -- id00340 -- id00341 -- id00342 -- id00343 -- id00344 -- id00345 -- id00346 -- id00347 -- id00348 -- id00349 -- id00350 -- id00351 -- id00352 -- id00353 -- id00354 -- id00355 -- id00356 -- id00357 -- id00358 -- id00359 -- id00360 -- id00361 -- id00362 -- id00363 -- id00364 -- id00365 -- id00366 -- id00367 -- id00368 -- id00369 -- id00370 -- id00371 -- id00372 -- id00373 -- id00374 -- id00375 -- id00376 -- id00377 -- id00378 -- id00379 -- id00380 -- id00381 -- id00382 -- id00383 -- id00384 -- id00385 -- id00386 -- id00387 -- id00388 -- id00389 -- id00390 -- id00391 -- id00392 -- id00393 -- id00394 -- id00395 -- id00396 -- id00397 -- id00398 -- id00399 -- id00400 -- id00401 -- id00402 -- id00403 -- id00404 -- id00405 -- id00406 -- id00407 -- id00408 -- id00409 -- id00410 -- id00411 -- id00412 -- id00413 -- id00414 -- id00415 -- id00416 -- id00417 -- id00418 -- id00419 -- id00420 -- id00421 -- id00422 -- id00423 -- id00424 -- id00425 -- id00426 -- id00427 -- id00428 -- id00429 -- id00430 -- id00431 -- id00432 -- id00433 -- id00434 -- id00435 -- id00436 -- id00437 -- id00438 -- id00439 -- id00440 -- id00441 -- id00442 -- id00443 -- id00444 -- id00445 -- id00446 -- id00447 -- id00448 -- id00449 -- id00450 -- id00451 -- id00452 -- id00453 -- id00454 -- id00455 -- id00456 -- id00458 -- id00459 -- id00460 -- id00461 -- id00462 -- id00463 -- id00464 -- id00465 -- id00466 -- id00467 -- id00468 -- id00469 -- id00470 -- id00472 -- id00473 -- id00474 -- id00475 -- id00476 -- id00477 -- id00478 -- id00479 -- id00480 -- id00481 -- id00482 -- id00483 -- id00484 -- id00485 -- id00486 -- id00487 -- id00488 -- id00489 -- id00490 -- id00491 -- id00492 -- id00493 -- id00494 -- id00495 -- id00496 -- id00497 -- id00498 -- id00499 -- id00500 -- id00501 -- id00502 -- id00503 -- id00504 -- id00505 -- id00506 -- id00507 -- id00508 -- id00509 -- id00510 -- id00511 -- id00512 -- id00513 -- id00514 -- id00515 -- id00516 -- id00517 -- id00518 -- id00519 -- id00520 -- id00521 -- id00522 -- id00523 -- id00524 -- id00525 -- id00526 -- id00527 -- id00528 -- id00529 -- id00530 -- id00531 -- id00532 -- id00533 -- id00534 -- id00535 -- id00536 -- id00537 -- id00538 -- id00539 -- id00540 -- id00541 -- id00542 -- id00543 -- id00544 -- id00545 -- id00546 -- id00547 -- id00549 -- id00550 -- id00551 -- id00552 -- id00553 -- id00554 -- id00555 -- id00556 -- id00557 -- id00558 -- id00559 -- id00560 -- id00561 -- id00562 -- id00563 -- id00564 -- id00565 -- id00566 -- id00567 -- id00568 -- id00569 -- id00570 -- id00571 -- id00572 -- id00573 -- id00574 -- id00575 -- id00576 -- id00577 -- id00578 -- id00579 -- id00580 -- id00581 -- id00582 -- id00583 -- id00584 -- id00585 -- id00586 -- id00587 -- id00588 -- id00589 -- id00590 -- id00591 -- id00592 -- id00593 -- id00594 -- id00595 -- id00596 -- id00597 -- id00598 -- id00599 -- id00600 -- id00601 -- id00603 -- id00604 -- id00605 -- id00606 -- id00607 -- id00608 -- id00609 -- id00610 -- id00611 -- id00612 -- id00613 -- id00614 -- id00615 -- id00616 -- id00619 -- id00620 -- id00621 -- id00622 -- id00623 -- id00624 -- id00625 -- id00626 -- id00627 -- id00628 -- id00629 -- id00630 -- id00631 -- id00632 -- id00633 -- id00634 -- id00635 -- id00636 -- id00637 -- id00638 -- id00639 -- id00640 -- id00641 -- id00642 -- id00643 -- id00644 -- id00645 -- id00646 -- id00647 -- id00648 -- id00649 -- id00650 -- id00651 -- id00652 -- id00653 -- id00654 -- id00655 -- id00656 -- id00657 -- id00658 -- id00659 -- id00661 -- id00662 -- id00663 -- id00664 -- id00665 -- id00666 -- id00667 -- id00668 -- id00669 -- id00670 -- id00671 -- id00672 -- id00673 -- id00674 -- id00675 -- id00676 -- id00678 -- id00679 -- id00680 -- id00681 -- id00682 -- id00683 -- id00684 -- id00685 -- id00686 -- id00687 -- id00688 -- id00689 -- id00690 -- id00691 -- id00692 -- id00693 -- id00694 -- id00695 -- id00696 -- id00697 -- id00698 -- id00699 -- id00701 -- id00702 -- id00703 -- id00704 -- id00705 -- id00706 -- id00707 -- id00708 -- id00709 -- id00710 -- id00711 -- id00712 -- id00713 -- id00714 -- id00715 -- id00716 -- id00717 -- id00718 -- id00719 -- id00720 -- id00721 -- id00722 -- id00723 -- id00724 -- id00725 -- id00726 -- id00727 -- id00728 -- id00729 -- id00730 -- id00731 -- id00732 -- id00733 -- id00734 -- id00735 -- id00737 -- id00738 -- id00739 -- id00740 -- id00741 -- id00742 -- id00743 -- id00744 -- id00745 -- id00746 -- id00747 -- id00748 -- id00749 -- id00750 -- id00751 -- id00752 -- id00754 -- id00755 -- id00756 -- id00757 -- id00758 -- id00759 -- id00760 -- id00761 -- id00762 -- id00763 -- id00764 -- id00765 -- id00766 -- id00767 -- id00768 -- id00769 -- id00770 -- id00771 -- id00772 -- id00773 -- id00774 -- id00775 -- id00776 -- id00777 -- id00778 -- id00779 -- id00780 -- id00781 -- id00782 -- id00783 -- id00784 -- id00785 -- id00786 -- id00787 -- id00788 -- id00789 -- id00790 -- id00791 -- id00792 -- id00793 -- id00794 -- id00795 -- id00796 -- id00797 -- id00798 -- id00799 -- id10000 -- id10001 -- id10002 -- id10003 -- id10004 -- id10005 -- id10006 -- id10007 -- id10008 -- id10009 -- id10010 -- id10011 -- id10012 -- id10013 -- id10014 -- id10015 -- id10016 -- id10017 -- id10018 -- id10019 -- id10020 -- id10021 -- id10022 -- id10023 -- id10024 -- id10025 -- id10026 -- id10027 -- id10028 -- id10029 -- id10030 -- id10031 -- id10032 -- id10033 -- id10034 -- id10035 -- id10036 -- id10037 -- id10038 -- id10039 -- id10040 -- id10041 -- id10042 -- id10043 -- id10044 -- id10045 -- id10046 -- id10047 -- id10048 -- id10049 -- id10050 -- id10051 -- id10052 -- id10053 -- id10054 -- id10055 -- id10056 -- id10057 -- id10058 -- id10059 -- id10060 -- id10061 -- id10062 -- id10063 -- id10064 -- id10065 -- id10066 -- id10067 -- id10068 -- id10069 -- id10070 -- id10071 -- id10072 -- id10073 -- id10074 -- id10075 -- id10076 -- id10077 -- id10078 -- id10079 -- id10080 -- id10081 -- id10082 -- id10083 -- id10084 -- id10085 -- id10086 -- id10087 -- id10088 -- id10089 -- id10090 -- id10091 -- id10092 -- id10093 -- id10094 -- id10095 -- id10096 -- id10097 -- id10098 -- id10099 -- id10100 -- id10101 -- id10102 -- id10103 -- id10104 -- id10105 -- id10106 -- id10107 -- id10108 -- id10109 -- id10110 -- id10111 -- id10112 -- id10113 -- id10114 -- id10115 -- id10116 -- id10117 -- id10118 -- id10119 -- id10120 -- id10121 -- id10122 -- id10123 -- id10124 -- id10125 -- id10126 -- id10127 -- id10128 -- id10129 -- id10130 -- id10131 -- id10132 -- id10133 -- id10134 -- id10135 -- id10136 -- id10137 -- id10138 -- id10139 -- id10140 -- id10141 -- id10142 -- id10143 -- id10144 -- id10145 -- id10146 -- id10147 -- id10148 -- id10149 -- id10150 -- id10151 -- id10152 -- id10153 -- id10154 -- id10155 -- id10156 -- id10157 -- id10158 -- id10159 -- id10160 -- id10161 -- id10162 -- id10163 -- id10164 -- id10165 -- id10167 -- id10168 -- id10169 -- id10170 -- id10171 -- id10172 -- id10173 -- id10174 -- id10175 -- id10176 -- id10177 -- id10178 -- id10179 -- id10180 -- id10181 -- id10182 -- id10183 -- id10184 -- id10185 -- id10186 -- id10187 -- id10188 -- id10189 -- id10190 -- id10191 -- id10192 -- id10193 -- id10194 -- id10195 -- id10196 -- id10197 -- id10198 -- id10199 -- id10200 -- id10201 -- id10202 -- id10203 -- id10204 -- id10205 -- id10206 -- id10207 -- id10208 -- id10209 -- id10210 -- id10211 -- id10212 -- id10213 -- id10214 -- id10215 -- id10216 -- id10217 -- id10218 -- id10219 -- id10220 -- id10221 -- id10222 -- id10223 -- id10224 -- id10225 -- id10226 -- id10227 -- id10228 -- id10229 -- id10230 -- id10231 -- id10232 -- id10233 -- id10234 -- id10235 -- id10236 -- id10237 -- id10238 -- id10239 -- id10240 -- id10241 -- id10242 -- id10243 -- id10244 -- id10245 -- id10246 -- id10247 -- id10248 -- id10249 -- id10250 -- id10251 -- id10252 -- id10253 -- id10254 -- id10255 -- id10256 -- id10257 -- id10258 -- id10259 -- id10260 -- id10261 -- id10262 -- id10263 -- id10264 -- id10265 -- id10266 -- id10267 -- id10268 -- id10269 -- id10270 -- id10271 -- id10272 -- id10273 -- id10274 -- id10275 -- id10276 -- id10277 -- id10278 -- id10279 -- id10280 -- id10281 -- id10282 -- id10283 -- id10284 -- id10285 -- id10286 -- id10287 -- id10288 -- id10289 -- id10290 -- id10291 -- id10292 -- id10293 -- id10294 -- id10295 -- id10296 -- id10297 -- id10298 -- id10299 -- id10300 -- id10301 -- id10302 -- id10303 -- id10304 -- id10305 -- id10306 -- id10307 -- id10308 -- id10309 -- id10310 -- id10311 -- id10312 -- id10313 -- id10314 -- id10315 -- id10316 -- id10317 -- id10318 -- id10319 -- id10320 -- id10321 -- id10322 -- id10323 -- id10324 -- id10325 -- id10326 -- id10327 -- id10328 -- id10329 -- id10330 -- id10331 -- id10332 -- id10333 -- id10334 -- id10335 -- id10336 -- id10337 -- id10338 -- id10339 -- id10340 -- id10341 -- id10342 -- id10343 -- id10344 -- id10345 -- id10346 -- id10347 -- id10348 -- id10349 -- id10350 -- id10351 -- id10352 -- id10353 -- id10354 -- id10355 -- id10356 -- id10357 -- id10358 -- id10359 -- id10360 -- id10361 -- id10362 -- id10363 -- id10364 -- id10365 -- id10366 -- id10367 -- id10368 -- id10369 -- id10370 -- id10371 -- id10372 -- id10373 -- id10374 -- id10375 -- id10376 -- id10377 -- id10378 -- id10379 -- id10380 -- id10381 -- id10382 -- id10383 -- id10384 -- id10385 -- id10386 -- id10387 -- id10388 -- id10389 -- id10390 -- id10391 -- id10392 -- id10393 -- id10394 -- id10395 -- id10396 -- id10397 -- id10398 -- id10399 -- id10400 -- id10401 -- id10402 -- id10403 -- id10404 -- id10405 -- id10406 -- id10407 -- id10408 -- id10409 -- id10410 -- id10411 -- id10412 -- id10413 -- id10414 -- id10415 -- id10416 -- id10417 -- id10418 -- id10419 -- id10420 -- id10421 -- id10422 -- id10423 -- id10424 -- id10425 -- id10426 -- id10427 -- id10428 -- id10429 -- id10430 -- id10431 -- id10432 -- id10433 -- id10434 -- id10435 -- id10436 -- id10437 -- id10438 -- id10439 -- id10440 -- id10441 -- id10442 -- id10443 -- id10444 -- id10445 -- id10446 -- id10447 -- id10448 -- id10449 -- id10450 -- id10451 -- id10452 -- id10453 -- id10454 -- id10455 -- id10456 -- id10457 -- id10458 -- id10459 -- id10460 -- id10461 -- id10462 -- id10463 -- id10464 -- id10465 -- id10466 -- id10467 -- id10468 -- id10469 -- id10470 -- id10471 -- id10472 -- id10473 -- id10474 -- id10475 -- id10476 -- id10477 -- id10478 -- id10479 -- id10480 -- id10481 -- id10482 -- id10483 -- id10484 -- id10485 -- id10486 -- id10487 -- id10488 -- id10489 -- id10490 -- id10491 -- id10492 -- id10493 -- id10494 -- id10495 -- id10496 -- id10497 -- id10498 -- id10499 -- id10500 -- id10501 -- id10502 -- id10503 -- id10504 -- id10505 -- id10506 -- id10508 -- id10509 -- id10510 -- id10511 -- id10512 -- id10513 -- id10514 -- id10515 -- id10516 -- id10517 -- id10518 -- id10519 -- id10520 -- id10521 -- id10522 -- id10523 -- id10524 -- id10525 -- id10526 -- id10527 -- id10528 -- id10529 -- id10530 -- id10531 -- id10532 -- id10533 -- id10534 -- id10535 -- id10536 -- id10537 -- id10538 -- id10539 -- id10540 -- id10541 -- id10542 -- id10543 -- id10544 -- id10545 -- id10546 -- id10547 -- id10548 -- id10549 -- id10550 -- id10551 -- id10552 -- id10553 -- id10554 -- id10555 -- id10556 -- id10557 -- id10558 -- id10559 -- id10560 -- id10561 -- id10562 -- id10563 -- id10564 -- id10565 -- id10566 -- id10567 -- id10568 -- id10569 -- id10570 -- id10571 -- id10572 -- id10573 -- id10574 -- id10575 -- id10576 -- id10577 -- id10578 -- id10579 -- id10580 -- id10581 -- id10582 -- id10583 -- id10584 -- id10585 -- id10586 -- id10587 -- id10588 -- id10589 -- id10590 -- id10591 -- id10592 -- id10593 -- id10594 -- id10595 -- id10596 -- id10597 -- id10598 -- id10599 -- id10600 -- id10601 -- id10602 -- id10603 -- id10604 -- id10605 -- id10606 -- id10607 -- id10608 -- id10609 -- id10610 -- id10611 -- id10612 -- id10613 -- id10614 -- id10615 -- id10616 -- id10617 -- id10618 -- id10619 -- id10620 -- id10621 -- id10622 -- id10623 -- id10624 -- id10625 -- id10626 -- id10627 -- id10628 -- id10629 -- id10630 -- id10631 -- id10632 -- id10633 -- id10634 -- id10635 -- id10637 -- id10638 -- id10639 -- id10640 -- id10641 -- id10642 -- id10643 -- id10644 -- id10645 -- id10646 -- id10647 -- id10648 -- id10649 -- id10650 -- id10651 -- id10652 -- id10653 -- id10654 -- id10655 -- id10656 -- id10657 -- id10658 -- id10659 -- id10660 -- id10661 -- id10662 -- id10663 -- id10664 -- id10665 -- id10666 -- id10668 -- id10669 -- id10670 -- id10671 -- id10672 -- id10673 -- id10674 -- id10675 -- id10676 -- id10677 -- id10678 -- id10679 -- id10680 -- id10681 -- id10682 -- id10683 -- id10684 -- id10685 -- id10686 -- id10687 -- id10688 -- id10689 -- id10690 -- id10691 -- id10692 -- id10693 -- id10694 -- id10695 -- id10696 -- id10697 -- id10698 -- id10699 -- id10700 -- id10701 -- id10702 -- id10703 -- id10704 -- id10705 -- id10706 -- id10707 -- id10708 -- id10709 -- id10710 -- id10711 -- id10712 -- id10713 -- id10714 -- id10715 -- id10716 -- id10717 -- id10718 -- id10719 -- id10720 -- id10721 -- id10722 -- id10723 -- id10724 -- id10725 -- id10726 -- id10727 -- id10728 -- id10729 -- id10730 -- id10731 -- id10732 -- id10733 -- id10734 -- id10735 -- id10736 -- id10737 -- id10738 -- id10739 -- id10740 -- id10741 -- id10742 -- id10743 -- id10744 -- id10745 -- id10746 -- id10747 -- id10748 -- id10749 -- id10750 -- id10751 -- id10752 -- id10753 -- id10754 -- id10755 -- id10756 -- id10757 -- id10758 -- id10759 -- id10760 -- id10761 -- id10762 -- id10763 -- id10764 -- id10765 -- id10766 -- id10767 -- id10768 -- id10769 -- id10770 -- id10771 -- id10772 -- id10773 -- id10774 -- id10775 -- id10776 -- id10777 -- id10778 -- id10779 -- id10780 -- id10781 -- id10782 -- id10783 -- id10784 -- id10785 -- id10786 -- id10787 -- id10788 -- id10789 -- id10790 -- id10791 -- id10792 -- id10793 -- id10794 -- id10795 -- id10796 -- id10797 -- id10798 -- id10799 -- id10800 -- id10801 -- id10802 -- id10803 -- id10804 -- id10805 -- id10806 -- id10807 -- id10808 -- id10809 -- id10810 -- id10812 -- id10813 -- id10814 -- id10815 -- id10816 -- id10817 -- id10818 -- id10819 -- id10820 -- id10821 -- id10822 -- id10823 -- id10824 -- id10825 -- id10826 -- id10827 -- id10828 -- id10829 -- id10830 -- id10831 -- id10832 -- id10833 -- id10834 -- id10835 -- id10836 -- id10837 -- id10838 -- id10839 -- id10840 -- id10841 -- id10842 -- id10843 -- id10844 -- id10845 -- id10846 -- id10847 -- id10848 -- id10849 -- id10850 -- id10851 -- id10852 -- id10853 -- id10854 -- id10855 -- id10856 -- id10857 -- id10858 -- id10859 -- id10860 -- id10861 -- id10862 -- id10863 -- id10864 -- id10865 -- id10866 -- id10867 -- id10868 -- id10869 -- id10870 -- id10871 -- id10872 -- id10873 -- id10874 -- id10875 -- id10876 -- id10877 -- id10878 -- id10879 -- id10880 -- id10881 -- id10882 -- id10883 -- id10884 -- id10885 -- id10886 -- id10887 -- id10888 -- id10889 -- id10890 -- id10891 -- id10892 -- id10893 -- id10894 -- id10895 -- id10896 -- id10897 -- id10898 -- id10899 -- id10900 -- id10901 -- id10902 -- id10903 -- id10904 -- id10905 -- id10906 -- id10907 -- id10908 -- id10909 -- id10910 -- id10911 -- id10912 -- id10913 -- id10914 -- id10915 -- id10916 -- id10917 -- id10918 -- id10919 -- id10920 -- id10921 -- id10922 -- id10923 -- id10924 -- id10925 -- id10926 -- id10927 -- id10928 -- id10929 -- id10930 -- id10931 -- id10932 -- id10933 -- id10934 -- id10935 -- id10936 -- id10937 -- id10938 -- id10939 -- id10940 -- id10941 -- id10942 -- id10943 -- id10944 -- id10945 -- id10946 -- id10947 -- id10948 -- id10949 -- id10950 -- id10951 -- id10952 -- id10953 -- id10954 -- id10955 -- id10956 -- id10957 -- id10958 -- id10959 -- id10960 -- id10961 -- id10962 -- id10963 -- id10964 -- id10965 -- id10966 -- id10967 -- id10968 -- id10969 -- id10970 -- id10971 -- id10972 -- id10973 -- id10974 -- id10975 -- id10976 -- id10977 -- id10978 -- id10979 -- id10980 -- id10981 -- id10982 -- id10983 -- id10984 -- id10985 -- id10986 -- id10987 -- id10988 -- id10989 -- id10990 -- id10991 -- id10992 -- id10993 -- id10994 -- id10995 -- id10996 -- id10997 -- id10998 -- id10999 -- id11000 -- id11001 -- id11002 -- id11004 -- id11005 -- id11006 -- id11007 -- id11008 -- id11009 -- id11011 -- id11012 -- id11013 -- id11014 -- id11015 -- id11016 -- id11017 -- id11018 -- id11019 -- id11020 -- id11021 -- id11022 -- id11023 -- id11024 -- id11025 -- id11026 -- id11027 -- id11028 -- id11029 -- id11030 -- id11031 -- id11032 -- id11033 -- id11034 -- id11035 -- id11036 -- id11037 -- id11038 -- id11039 -- id11040 -- id11041 -- id11042 -- id11043 -- id11044 -- id11045 -- id11046 -- id11047 -- id11048 -- id11049 -- id11050 -- id11051 -- id11052 -- id11053 -- id11054 -- id11055 -- id11056 -- id11057 -- id11058 -- id11059 -- id11060 -- id11061 -- id11062 -- id11063 -- id11064 -- id11065 -- id11066 -- id11067 -- id11068 -- id11069 -- id11070 -- id11071 -- id11072 -- id11073 -- id11074 -- id11075 -- id11076 -- id11077 -- id11078 -- id11079 -- id11080 -- id11081 -- id11082 -- id11083 -- id11084 -- id11085 -- id11086 -- id11087 -- id11088 -- id11089 -- id11090 -- id11091 -- id11092 -- id11093 -- id11094 -- id11095 -- id11096 -- id11097 -- id11098 -- id11099 -- id11100 -- id11101 -- id11102 -- id11103 -- id11104 -- id11105 -- id11106 -- id11107 -- id11108 -- id11109 -- id11110 -- id11111 -- id11112 -- id11113 -- id11114 -- id11115 -- id11116 -- id11117 -- id11118 -- id11119 -- id11120 -- id11121 -- id11122 -- id11123 -- id11124 -- id11125 -- id11126 -- id11127 -- id11128 -- id11129 -- id11130 -- id11131 -- id11132 -- id11133 -- id11134 -- id11135 -- id11136 -- id11137 -- id11138 -- id11139 -- id11140 -- id11141 -- id11142 -- id11143 -- id11144 -- id11145 -- id11146 -- id11147 -- id11148 -- id11149 -- id11150 -- id11151 -- id11152 -- id11153 -- id11154 -- id11155 -- id11156 -- id11157 -- id11158 -- id11159 -- id11160 -- id11161 -- id11162 -- id11163 -- id11164 -- id11165 -- id11166 -- id11167 -- id11168 -- id11169 -- id11170 -- id11171 -- id11172 -- id11173 -- id11174 -- id11175 -- id11176 -- id11177 -- id11178 -- id11179 -- id11180 -- id11181 -- id11182 -- id11183 -- id11184 -- id11185 -- id11186 -- id11187 -- id11188 -- id11189 -- id11190 -- id11191 -- id11192 -- id11193 -- id11194 -- id11195 -- id11196 -- id11197 -- id11198 -- id11199 -- id11200 -- id11201 -- id11202 -- id11203 -- id11204 -- id11205 -- id11206 -- id11207 -- id11208 -- id11209 -- id11210 -- id11211 -- id11212 -- id11213 -- id11214 -- id11215 -- id11216 -- id11217 -- id11218 -- id11219 -- id11220 -- id11221 -- id11222 -- id11223 -- id11224 -- id11225 -- id11226 -- id11227 -- id11228 -- id11229 -- id11230 -- id11231 -- id11232 -- id11233 -- id11234 -- id11235 -- id11236 -- id11237 -- id11238 -- id11239 -- id11240 -- id11241 -- id11242 -- id11243 -- id11244 -- id11245 -- id11246 -- id11247 -- id11248 -- id11249 -- id11250 -- id11251 -- id11252 -- id11254 -- id11255 -- id11256 -- id11257 -- id11258 -- id11259 -- id11260 -- id11261 -- id11262 -- id11263 -- id11264 -- id11265 -- id11266 -- id11267 -- id11268 -- id11269 -- id11270 -- id11271 -- id11272 -- id11273 -- id11274 -- id11275 -- id11276 -- id11277 -- id11278 -- id11279 -- id11280 -- id11281 -- id11282 -- id11283 -- id11284 -- id11285 -- id11286 -- id11287 -- id11288 -- id11289 -- id11290 -- id11291 -- id11292 -- id11293 -- id11294 -- id11295 -- id11296 -- id11297 -- id11298 -- id11299 -- id11300 -- id11301 -- id11302 -- id11303 -- id11304 -- id11305 -- id11306 -- id11307 -- id11308 -- id11309 -- id11310 -- id11311 -- id11312 -- id11313 -- id11314 -- id11315 -- id11316 -- id11317 -- id11318 -- id11319 -- id11320 -- id11321 -- id11322 -- id11323 -- id11324 -- id11325 -- id11326 -- id11327 -- id11328 -- id11329 -- id11330 -- id11331 -- id11332 -- id11333 -- id11334 -- id11335 -- id11336 -- id11337 -- id11338 -- id11339 -- id11340 -- id11341 -- id11342 -- id11343 -- id11344 -- id11345 -- id11346 -- id11347 -- id11348 -- id11349 -- id11350 -- id11351 -- id11352 -- id11353 -- id11354 -- id11355 -- id11356 -- id11357 -- id11358 -- id11359 -- id11360 -- id11361 -- id11362 -- id11363 -- id11364 -- id11365 -- id11366 -- id11367 -- id11368 -- id11369 -- id11370 -- id11371 -- id11372 -- id11373 -- id11374 -- id11375 -- id11376 -- id11377 -- id11379 -- id11380 -- id11381 -- id11382 -- id11383 -- id11384 -- id11385 -- id11386 -- id11387 -- id11388 -- id11389 -- id11390 -- id11391 -- id11392 -- id11393 -- id11394 -- id11395 -- id11396 -- id11397 -- id11398 -- id11399 -- id11400 -- id11401 -- id11402 -- id11403 -- id11404 -- id11405 -- id11406 -- id11407 -- id11408 -- id11409 -- id11410 -- id11411 -- id11412 -- id11413 -- id11414 -- id11415 -- id11416 -- id11417 -- id11418 -- id11419 -- id11420 -- id11421 -- id11422 -- id11423 -- id11424 -- id11425 -- id11426 -- id11427 -- id11428 -- id11429 -- id11430 -- id11431 -- id11432 -- id11433 -- id11434 -- id11435 -- id11436 -- id11437 -- id11438 -- id11439 -- id11440 -- id11441 -- id11442 -- id11443 -- id11444 -- id11445 -- id11446 -- id11447 -- id11448 -- id11449 -- id11450 -- id11451 -- id11452 -- id11453 -- id11454 -- id11455 -- id11456 -- id11457 -- id11458 -- id11459 -- id11460 -- id11461 -- id11462 -- id11463 -- id11464 -- id11465 -- id11466 -- id11467 -- id11468 -- id11469 -- id11470 -- id11471 -- id11472 -- id11473 -- id11474 -- id11475 -- id11476 -- id11477 -- id11478 -- id11479 -- id11480 -- id11481 -- id11482 -- id11483 -- id11484 -- id11485 -- id11486 -- id11487 -- id11488 -- id11489 -- id11490 -- id11491 -- id11492 -- id11493 -- id11495 -- id11496 -- id11497 -- id11498 -- id11499 -- id11500 -- id11501 -- id11502 -- id11503 -- id11504 -- id11505 -- id11506 -- id11507 -- id11508 -- id11509 -- id11510 -- id11511 -- id11512 -- id11513 -- id11514 -- id11515 -- id11516 -- id11517 -- id11518 -- id11519 -- id11520 -- id11521 -- id11522 -- id11523 -- id11524 -- id11525 -- id11526 -- id11527 -- id11528 -- id11529 -- id11530 -- id11531 -- id11532 -- id11533 -- id11534 -- id11535 -- id11536 -- id11537 -- id11538 -- id11539 -- id11540 -- id11541 -- id11542 -- id11543 -- id11544 -- id11545 -- id11546 -- id11547 -- id11548 -- id11549 -- id11550 -- id11551 -- id11552 -- id11553 -- id11554 -- id11555 -- id11556 -- id11557 -- id11558 -- id11559 -- id11560 -- id11561 -- id11562 -- id11563 -- id11564 -- id11565 -- id11566 -- id11567 -- id11568 -- id11569 -- id11570 -- id11571 -- id11572 -- id11573 -- id11574 -- id11575 -- id11576 -- id11577 -- id11578 -- id11579 -- id11580 -- id11581 -- id11582 -- id11583 -- id11584 -- id11585 -- id11586 -- id11587 -- id11588 -- id11589 -- id11590 -- id11591 -- id11592 -- id11593 -- id11594 -- id11595 -- id11596 -- id11597 -- id11598 -- id11599 -- id11600 -- id11601 -- id11602 -- id11603 -- id11604 -- id11605 -- id11606 -- id11607 -- id11608 -- id11609 -- id11610 -- id11611 -- id11612 -- id11613 -- id11614 -- id11615 -- id11616 -- id11617 -- id11618 -- id11619 -- id11620 -- id11621 -- id11622 -- id11623 -- id11624 -- id11625 -- id11626 -- id11627 -- id11628 -- id11629 -- id11630 -- id11631 -- id11632 -- id11633 -- id11634 -- id11635 -- id11636 -- id11637 -- id11638 -- id11639 -- id11640 -- id11641 -- id11642 -- id11643 -- id11644 -- id11645 -- id11646 -- id11647 -- id11648 -- id11649 -- id11650 -- id11651 -- id11652 -- id11653 -- id11654 -- id11655 -- id11656 -- id11657 -- id11658 -- id11659 -- id11660 -- id11661 -- id11662 -- id11663 -- id11664 -- id11665 -- id11666 -- id11667 -- id11668 -- id11669 -- id11670 -- id11671 -- id11672 -- id11673 -- id11674 -- id11675 -- id11676 -- id11677 -- id11678 -- id11679 -- id11680 -- id11681 -- id11682 -- id11683 -- id11684 -- id11685 -- id11686 -- id11687 -- id11688 -- id11689 -- id11690 -- id11691 -- id11692 -- id11693 -- id11694 -- id11695 -- id11696 -- id11697 -- id11698 -- id11699 -- id11700 -- id11701 -- id11702 -- id11703 -- id11704 -- id11705 -- id11706 -- id11707 -- id11708 -- id11709 -- id11710 -- id11711 -- id11712 -- id11713 -- id11714 -- id11715 -- id11716 -- id11717 -- id11718 -- id11719 -- id11720 -- id11721 -- id11722 -- id11723 -- id11724 -- id11725 -- id11726 -- id11727 -- id11728 -- id11729 -- id11730 -- id11731 -- id11732 -- id11733 -- id11734 -- id11735 -- id11736 -- id11737 -- id11738 -- id11739 -- id11740 -- id11741 -- id11742 -- id11744 -- id11745 -- id11746 -- id11747 -- id11748 -- id11749 -- id11750 -- id11751 -- id11752 -- id11753 -- id11754 -- id11755 -- id11756 -- id11757 -- id11758 -- id11759 -- id11760 -- id11761 -- id11762 -- id11763 -- id11764 -- id11765 -- id11766 -- id11767 -- id11768 -- id11769 -- id11770 -- id11771 -- id11772 -- id11773 -- id11774 -- id11775 -- id11776 -- id11777 -- id11778 -- id11779 -- id11780 -- id11781 -- id11782 -- id11783 -- id11784 -- id11785 -- id11786 -- id11787 -- id11788 -- id11789 -- id11790 -- id11791 -- id11792 -- id11793 -- id11794 -- id11795 -- id11796 -- id11797 -- id11798 -- id11799 -- id11800 -- id11801 -- id11802 -- id11803 -- id11804 -- id11805 -- id11806 -- id11807 -- id11808 -- id11809 -- id11810 -- id11811 -- id11812 -- id11813 -- id11814 -- id11815 -- id11816 -- id11817 -- id11818 -- id11819 -- id11820 -- id11821 -- id11822 -- id11823 -- id11824 -- id11825 -- id11826 -- id11827 -- id11828 -- id11829 -- id11830 -- id11831 -- id11832 -- id11833 -- id11834 -- id11835 -- id11836 -- id11837 -- id11838 -- id11839 -- id11840 -- id11841 -- id11842 -- id11843 -- id11844 -- id11845 -- id11846 -- id11847 -- id11848 -- id11849 -- id11850 -- id11851 -- id11852 -- id11853 -- id11854 -- id11855 -- id11856 -- id11857 -- id11858 -- id11859 -- id11860 -- id11861 -- id11862 -- id11863 -- id11864 -- id11865 -- id11866 -- id11867 -- id11868 -- id11869 -- id11870 -- id11871 -- id11872 -- id11873 -- id11874 -- id11875 -- id11876 -- id11877 -- id11878 -- id11879 -- id11880 -- id11881 -- id11882 -- id11883 -- id11884 -- id11885 -- id11886 -- id11887 -- id11888 -- id11889 -- id11890 -- id11891 -- id11892 -- id11893 -- id11894 -- id11895 -- id11896 -- id11897 -- id11898 -- id11899 -- id11900 -- id11901 -- id11902 -- id11903 -- id11904 -- id11905 -- id11906 -- id11907 -- id11908 -- id11909 -- id11910 -- id11911 -- id11912 -- id11913 -- id11914 -- id11915 -- id11916 -- id11917 -- id11918 -- id11919 -- id11920 -- id11921 -- id11922 -- id11923 -- id11924 -- id11925 -- id11926 -- id11927 -- id11928 -- id11929 -- id11930 -- id11931 -- id11932 -- id11933 -- id11934 -- id11935 -- id11936 -- id11937 -- id11938 -- id11939 -- id11940 -- id11941 -- id11942 -- id11943 -- id11944 -- id11945 -- id11946 -- id11947 -- id11948 -- id11949 -- id11950 -- id11951 -- id11952 -- id11953 -- id11954 -- id11955 -- id11956 -- id11957 -- id11958 -- id11959 -- id11960 -- id11961 -- id11962 -- id11963 -- id11964 -- id11965 -- id11966 -- id11967 -- id11968 -- id11969 -- id11970 -- id11971 -- id11972 -- id11973 -- id11974 -- id11975 -- id11976 -- id11977 -- id11978 -- id11979 -- id11980 -- id11981 -- id11982 -- id11983 -- id11984 -- id11985 -- id11986 -- id11987 -- id11988 -- id11989 -- id11990 -- id11991 -- id11992 -- id11993 -- id11994 -- id11995 -- id11996 -- id11997 -- id11998 -- id11999 -- R8001_M8004_MS801_S001 -- R8001_M8004_MS801_S002 -- R8001_M8004_MS801_S003 -- R8001_M8004_MS801_S004 -- R8003_M8001_MS801_S001 -- R8003_M8001_MS801_S002 -- R8003_M8001_MS801_S003 -- R8003_M8001_MS801_S004 -- R8007_M8010_MS803_S001 -- R8007_M8010_MS803_S002 -- R8007_M8010_MS803_S003 -- R8007_M8010_MS803_S004 -- R8007_M8011_MS806_S001 -- R8007_M8011_MS806_S002 -- R8007_M8011_MS806_S003 -- R8007_M8011_MS806_S004 -- R8008_M8013_MS807_S001 -- R8008_M8013_MS807_S002 -- R8008_M8013_MS807_S003 -- R8009_M8018_MS809_S001 -- R8009_M8018_MS809_S002 -- R8009_M8019_MS810_S001 -- R8009_M8019_MS810_S002 -- R8009_M8020_MS810_S001 -- R8009_M8020_MS810_S002 diff --git a/egs/cnceleb/resnet34/utils b/egs/cnceleb/resnet34/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/cnceleb/resnet34/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/librispeech/branchformer/README.md b/egs/librispeech/branchformer/README.md deleted file mode 100644 index 880d33e07..000000000 --- a/egs/librispeech/branchformer/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Branchformer Result - -## Training Config -- Feature info: using raw speech, extracting 80 dims fbank online, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train config: conf/train_asr_branchformer.yaml -- LM config: LM was not used - -## Results (CER) -- Decode config: conf/decode_asr_transformer_beam10_ctc0.3.yaml (ctc weight:0.3) - -| testset | CER(%) | -|:-----------:|:-------:| -| dev_clean | 2.12 | -| dev_other | 5.25 | -| test_clean | 2.34 | -| test_other | 5.39 | \ No newline at end of file diff --git a/egs/librispeech/branchformer/conf/decode_asr_transformer_beam10_ctc0.3.yaml b/egs/librispeech/branchformer/conf/decode_asr_transformer_beam10_ctc0.3.yaml deleted file mode 100644 index 62745defc..000000000 --- a/egs/librispeech/branchformer/conf/decode_asr_transformer_beam10_ctc0.3.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.3 -lm_weight: 0.0 diff --git a/egs/librispeech/branchformer/conf/train_asr_branchformer.yaml b/egs/librispeech/branchformer/conf/train_asr_branchformer.yaml deleted file mode 100644 index d77755c15..000000000 --- a/egs/librispeech/branchformer/conf/train_asr_branchformer.yaml +++ /dev/null @@ -1,104 +0,0 @@ -# network architecture -# encoder related -encoder: branchformer -encoder_conf: - output_size: 512 - use_attn: true - attention_heads: 8 - attention_layer_type: rel_selfattn - pos_enc_layer_type: rel_pos - rel_pos_type: latest - use_cgmlp: true - cgmlp_linear_units: 3072 - cgmlp_conv_kernel: 31 - use_linear_after_conv: false - gate_activation: identity - merge_method: concat - cgmlp_weight: 0.5 # used only if merge_method is "fixed_ave" - attn_branch_drop_rate: 0.0 # used only if merge_method is "learned_ave" - num_blocks: 18 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.1 - input_layer: conv2d - stochastic_depth_rate: 0.0 - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 8 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.1 - src_attention_dropout_rate: 0.1 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 2 -grad_clip: 5 -max_epoch: 210 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0025 - weight_decay: 0.000001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 40000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 27 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_ratio_range: - - 0. - - 0.05 - num_time_mask: 10 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 30000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/librispeech/branchformer/local/data_prep.sh b/egs/librispeech/branchformer/local/data_prep.sh deleted file mode 100755 index c939b5f27..000000000 --- a/egs/librispeech/branchformer/local/data_prep.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Vassil Panayotov -# 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " - echo "e.g.: $0 /export/a15/vpanayotov/data/LibriSpeech/dev-clean data/dev-clean" - exit 1 -fi - -src=$1 -dst=$2 - -# all utterances are FLAC compressed -if ! which flac >&/dev/null; then - echo "Please install 'flac' on ALL worker nodes!" - exit 1 -fi - -spk_file=$src/../SPEAKERS.TXT - -mkdir -p $dst || exit 1 - -[ ! -d $src ] && echo "$0: no such directory $src" && exit 1 -[ ! -f $spk_file ] && echo "$0: expected file $spk_file to exist" && exit 1 - - -wav_scp=$dst/wav.scp; [[ -f "$wav_scp" ]] && rm $wav_scp -trans=$dst/text; [[ -f "$trans" ]] && rm $trans - -for reader_dir in $(find -L $src -mindepth 1 -maxdepth 1 -type d | sort); do - reader=$(basename $reader_dir) - if ! [ $reader -eq $reader ]; then # not integer. - echo "$0: unexpected subdirectory name $reader" - exit 1 - fi - - for chapter_dir in $(find -L $reader_dir/ -mindepth 1 -maxdepth 1 -type d | sort); do - chapter=$(basename $chapter_dir) - if ! [ "$chapter" -eq "$chapter" ]; then - echo "$0: unexpected chapter-subdirectory name $chapter" - exit 1 - fi - - find -L $chapter_dir/ -iname "*.flac" | sort | xargs -I% basename % .flac | \ - awk -v "dir=$chapter_dir" '{printf "%s %s/%s.flac \n", $0, dir, $0}' >>$wav_scp|| exit 1 - - chapter_trans=$chapter_dir/${reader}-${chapter}.trans.txt - [ ! -f $chapter_trans ] && echo "$0: expected file $chapter_trans to exist" && exit 1 - cat $chapter_trans >>$trans - done -done - -echo "$0: successfully prepared data in $dst" - -exit 0 diff --git a/egs/librispeech/branchformer/local/download_and_untar.sh b/egs/librispeech/branchformer/local/download_and_untar.sh deleted file mode 100755 index fe322e4af..000000000 --- a/egs/librispeech/branchformer/local/download_and_untar.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a15/vpanayotov/data www.openslr.org/resources/11 dev-clean" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: dev-clean, test-clean, dev-other, test-other," - echo " train-clean-100, train-clean-360, train-other-500." - exit 1 -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1 -fi - -part_ok=false -list="dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1 -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1 -fi - -if [ -f $data/LibriSpeech/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0 -fi - - -# sizes of the archive files in bytes. This is some older versions. -sizes_old="371012589 347390293 379743611 361838298 6420417880 23082659865 30626749128" -# sizes_new is the archive file sizes of the final release. Some of these sizes are of -# things we probably won't download. -sizes_new="337926286 314305928 695964615 297279345 87960560420 33373768 346663984 328757843 6387309499 23049477885 30593501606" - -if [ -f $data/$part.tar.gz ]; then - size=$(/bin/ls -l $data/$part.tar.gz | awk '{print $5}') - size_ok=false - for s in $sizes_old $sizes_new; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tar.gz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tar.gz - else - echo "$data/$part.tar.gz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tar.gz ]; then - if ! which wget >/dev/null; then - echo "$0: wget is not installed." - exit 1 - fi - full_url=$url/$part.tar.gz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - if ! wget -P $data --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1 - fi -fi - -if ! tar -C $data -xvzf $data/$part.tar.gz; then - echo "$0: error un-tarring archive $data/$part.tar.gz" - exit 1 -fi - -touch $data/LibriSpeech/$part/.complete - -echo "$0: Successfully downloaded and un-tarred $data/$part.tar.gz" - -if $remove_archive; then - echo "$0: removing $data/$part.tar.gz file since --remove-archive option was supplied." - rm $data/$part.tar.gz -fi diff --git a/egs/librispeech/branchformer/local/spm_encode.py b/egs/librispeech/branchformer/local/spm_encode.py deleted file mode 100755 index 9e1c15f0e..000000000 --- a/egs/librispeech/branchformer/local/spm_encode.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in -# https://github.com/pytorch/fairseq/blob/master/LICENSE - - -import argparse -import contextlib -import sys - -import sentencepiece as spm - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--model", required=True, - help="sentencepiece model to use for encoding") - parser.add_argument("--inputs", nargs="+", default=['-'], - help="input files to filter/encode") - parser.add_argument("--outputs", nargs="+", default=['-'], - help="path to save encoded outputs") - parser.add_argument("--output_format", choices=["piece", "id"], default="piece") - parser.add_argument("--min-len", type=int, metavar="N", - help="filter sentence pairs with fewer than N tokens") - parser.add_argument("--max-len", type=int, metavar="N", - help="filter sentence pairs with more than N tokens") - args = parser.parse_args() - - assert len(args.inputs) == len(args.outputs), \ - "number of input and output paths should match" - - sp = spm.SentencePieceProcessor() - sp.Load(args.model) - - if args.output_format == "piece": - def encode(l): - return sp.EncodeAsPieces(l) - elif args.output_format == "id": - def encode(l): - return list(map(str, sp.EncodeAsIds(l))) - else: - raise NotImplementedError - - if args.min_len is not None or args.max_len is not None: - def valid(line): - return ( - (args.min_len is None or len(line) >= args.min_len) and - (args.max_len is None or len(line) <= args.max_len) - ) - else: - def valid(lines): - return True - - with contextlib.ExitStack() as stack: - inputs = [ - stack.enter_context(open(input, "r", encoding="utf-8")) - if input != "-" else sys.stdin - for input in args.inputs - ] - outputs = [ - stack.enter_context(open(output, "w", encoding="utf-8")) - if output != "-" else sys.stdout - for output in args.outputs - ] - - stats = { - "num_empty": 0, - "num_filtered": 0, - } - - def encode_line(line): - line = line.strip() - if len(line) > 0: - line = encode(line) - if valid(line): - return line - else: - stats["num_filtered"] += 1 - else: - stats["num_empty"] += 1 - return None - - for i, lines in enumerate(zip(*inputs), start=1): - enc_lines = list(map(encode_line, lines)) - if not any(enc_line is None for enc_line in enc_lines): - for enc_line, output_h in zip(enc_lines, outputs): - print(" ".join(enc_line), file=output_h) - if i % 10000 == 0: - print("processed {} lines".format(i), file=sys.stderr) - - print("skipped {} empty lines".format(stats["num_empty"]), file=sys.stderr) - print("filtered {} lines".format(stats["num_filtered"]), file=sys.stderr) - - -if __name__ == "__main__": - main() diff --git a/egs/librispeech/branchformer/local/spm_train.py b/egs/librispeech/branchformer/local/spm_train.py deleted file mode 100755 index 134a0b1d3..000000000 --- a/egs/librispeech/branchformer/local/spm_train.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in the -# https://github.com/pytorch/fairseq/blob/master/LICENSE -import sys - -import sentencepiece as spm - -if __name__ == "__main__": - spm.SentencePieceTrainer.Train(" ".join(sys.argv[1:])) diff --git a/egs/librispeech/branchformer/path.sh b/egs/librispeech/branchformer/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/librispeech/branchformer/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/librispeech/branchformer/run.sh b/egs/librispeech/branchformer/run.sh deleted file mode 100755 index f925eb514..000000000 --- a/egs/librispeech/branchformer/run.sh +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=en -token_type=bpe -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data= -data_url=www.openslr.org/resources/12 - -# bpe model -nbpe=5000 -bpemode=unigram - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train_960 -valid_set=dev -test_sets="test_clean test_other dev_clean dev_other" - -asr_config=conf/train_asr_branchformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer_beam10_ctc0.3.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - for part in dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500; do - local/download_and_untar.sh ${raw_data} ${data_url} ${part} - done -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - for x in dev-clean dev-other test-clean test-other train-clean-100 train-clean-360 train-other-500; do - local/data_prep.sh ${raw_data}/LibriSpeech/${x} ${feats_dir}/data/${x//-/_} - done - mkdir $feats_dir/data/$valid_set - dev_sets="dev_clean dev_other" - for file in wav.scp text; do - ( for f in $dev_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$valid_set/$file || exit 1; - done - mkdir $feats_dir/data/$train_set - train_sets="train_clean_100 train_clean_360 train_other_500" - for file in wav.scp text; do - ( for f in $train_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$train_set/$file || exit 1; - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe}_units.txt -bpemodel=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe} -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - ### Task dependent. You have to check non-linguistic symbols used in the corpus. - echo "stage 2: Dictionary and Json Data Preparation" - mkdir -p ${feats_dir}/data/lang_char/ - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - cut -f 2- -d" " ${feats_dir}/data/${train_set}/text > ${feats_dir}/data/lang_char/input.txt - local/spm_train.py --input=${feats_dir}/data/lang_char/input.txt --vocab_size=${nbpe} --model_type=${bpemode} --model_prefix=${bpemodel} --input_sentence_size=100000000 - local/spm_encode.py --model=${bpemodel}.model --output_format=piece < ${feats_dir}/data/lang_char/input.txt | tr ' ' '\n' | sort | uniq | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --split_with_space false \ - --bpemodel ${bpemodel}.model \ - --token_type $token_type \ - --token_list $token_list \ - --dataset_type large \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/compute_wer.py ${_data}/text ${_dir}/text ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi \ No newline at end of file diff --git a/egs/librispeech/branchformer/utils b/egs/librispeech/branchformer/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/librispeech/branchformer/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/librispeech/conformer/conf/decode_asr_transformer_ctc0.3_beam5.yaml b/egs/librispeech/conformer/conf/decode_asr_transformer_ctc0.3_beam5.yaml deleted file mode 100644 index 8f7c75d1c..000000000 --- a/egs/librispeech/conformer/conf/decode_asr_transformer_ctc0.3_beam5.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 5 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.3 -lm_weight: 0.0 diff --git a/egs/librispeech/conformer/conf/decode_asr_transformer_ctc0.3_beam60.yaml b/egs/librispeech/conformer/conf/decode_asr_transformer_ctc0.3_beam60.yaml deleted file mode 100644 index 0ebb9afc9..000000000 --- a/egs/librispeech/conformer/conf/decode_asr_transformer_ctc0.3_beam60.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 60 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.3 -lm_weight: 0.0 diff --git a/egs/librispeech/conformer/conf/train_asr_conformer.yaml b/egs/librispeech/conformer/conf/train_asr_conformer.yaml deleted file mode 100644 index 2bd3db448..000000000 --- a/egs/librispeech/conformer/conf/train_asr_conformer.yaml +++ /dev/null @@ -1,92 +0,0 @@ -encoder: conformer -encoder_conf: - output_size: 512 - attention_heads: 8 - linear_units: 2048 - num_blocks: 12 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.1 - input_layer: conv2d - normalize_before: true - macaron_style: true - rel_pos_type: latest - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - use_cnn_module: true - cnn_module_kernel: 31 - -decoder: transformer -decoder_conf: - attention_heads: 8 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.1 - src_attention_dropout_rate: 0.1 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 - length_normalized_loss: false - -accum_grad: 2 -max_epoch: 150 -patience: none -init: none -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0025 - weight_decay: 0.000001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 40000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 27 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_ratio_range: - - 0. - - 0.05 - num_time_mask: 10 - -dataset_conf: - shuffle: True - shuffle_conf: - shuffle_size: 1024 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 10000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/librispeech/conformer/local/data_prep.sh b/egs/librispeech/conformer/local/data_prep.sh deleted file mode 100755 index c939b5f27..000000000 --- a/egs/librispeech/conformer/local/data_prep.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Vassil Panayotov -# 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " - echo "e.g.: $0 /export/a15/vpanayotov/data/LibriSpeech/dev-clean data/dev-clean" - exit 1 -fi - -src=$1 -dst=$2 - -# all utterances are FLAC compressed -if ! which flac >&/dev/null; then - echo "Please install 'flac' on ALL worker nodes!" - exit 1 -fi - -spk_file=$src/../SPEAKERS.TXT - -mkdir -p $dst || exit 1 - -[ ! -d $src ] && echo "$0: no such directory $src" && exit 1 -[ ! -f $spk_file ] && echo "$0: expected file $spk_file to exist" && exit 1 - - -wav_scp=$dst/wav.scp; [[ -f "$wav_scp" ]] && rm $wav_scp -trans=$dst/text; [[ -f "$trans" ]] && rm $trans - -for reader_dir in $(find -L $src -mindepth 1 -maxdepth 1 -type d | sort); do - reader=$(basename $reader_dir) - if ! [ $reader -eq $reader ]; then # not integer. - echo "$0: unexpected subdirectory name $reader" - exit 1 - fi - - for chapter_dir in $(find -L $reader_dir/ -mindepth 1 -maxdepth 1 -type d | sort); do - chapter=$(basename $chapter_dir) - if ! [ "$chapter" -eq "$chapter" ]; then - echo "$0: unexpected chapter-subdirectory name $chapter" - exit 1 - fi - - find -L $chapter_dir/ -iname "*.flac" | sort | xargs -I% basename % .flac | \ - awk -v "dir=$chapter_dir" '{printf "%s %s/%s.flac \n", $0, dir, $0}' >>$wav_scp|| exit 1 - - chapter_trans=$chapter_dir/${reader}-${chapter}.trans.txt - [ ! -f $chapter_trans ] && echo "$0: expected file $chapter_trans to exist" && exit 1 - cat $chapter_trans >>$trans - done -done - -echo "$0: successfully prepared data in $dst" - -exit 0 diff --git a/egs/librispeech/conformer/local/download_and_untar.sh b/egs/librispeech/conformer/local/download_and_untar.sh deleted file mode 100755 index fe322e4af..000000000 --- a/egs/librispeech/conformer/local/download_and_untar.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a15/vpanayotov/data www.openslr.org/resources/11 dev-clean" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: dev-clean, test-clean, dev-other, test-other," - echo " train-clean-100, train-clean-360, train-other-500." - exit 1 -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1 -fi - -part_ok=false -list="dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1 -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1 -fi - -if [ -f $data/LibriSpeech/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0 -fi - - -# sizes of the archive files in bytes. This is some older versions. -sizes_old="371012589 347390293 379743611 361838298 6420417880 23082659865 30626749128" -# sizes_new is the archive file sizes of the final release. Some of these sizes are of -# things we probably won't download. -sizes_new="337926286 314305928 695964615 297279345 87960560420 33373768 346663984 328757843 6387309499 23049477885 30593501606" - -if [ -f $data/$part.tar.gz ]; then - size=$(/bin/ls -l $data/$part.tar.gz | awk '{print $5}') - size_ok=false - for s in $sizes_old $sizes_new; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tar.gz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tar.gz - else - echo "$data/$part.tar.gz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tar.gz ]; then - if ! which wget >/dev/null; then - echo "$0: wget is not installed." - exit 1 - fi - full_url=$url/$part.tar.gz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - if ! wget -P $data --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1 - fi -fi - -if ! tar -C $data -xvzf $data/$part.tar.gz; then - echo "$0: error un-tarring archive $data/$part.tar.gz" - exit 1 -fi - -touch $data/LibriSpeech/$part/.complete - -echo "$0: Successfully downloaded and un-tarred $data/$part.tar.gz" - -if $remove_archive; then - echo "$0: removing $data/$part.tar.gz file since --remove-archive option was supplied." - rm $data/$part.tar.gz -fi diff --git a/egs/librispeech/conformer/local/spm_encode.py b/egs/librispeech/conformer/local/spm_encode.py deleted file mode 100755 index 9e1c15f0e..000000000 --- a/egs/librispeech/conformer/local/spm_encode.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in -# https://github.com/pytorch/fairseq/blob/master/LICENSE - - -import argparse -import contextlib -import sys - -import sentencepiece as spm - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--model", required=True, - help="sentencepiece model to use for encoding") - parser.add_argument("--inputs", nargs="+", default=['-'], - help="input files to filter/encode") - parser.add_argument("--outputs", nargs="+", default=['-'], - help="path to save encoded outputs") - parser.add_argument("--output_format", choices=["piece", "id"], default="piece") - parser.add_argument("--min-len", type=int, metavar="N", - help="filter sentence pairs with fewer than N tokens") - parser.add_argument("--max-len", type=int, metavar="N", - help="filter sentence pairs with more than N tokens") - args = parser.parse_args() - - assert len(args.inputs) == len(args.outputs), \ - "number of input and output paths should match" - - sp = spm.SentencePieceProcessor() - sp.Load(args.model) - - if args.output_format == "piece": - def encode(l): - return sp.EncodeAsPieces(l) - elif args.output_format == "id": - def encode(l): - return list(map(str, sp.EncodeAsIds(l))) - else: - raise NotImplementedError - - if args.min_len is not None or args.max_len is not None: - def valid(line): - return ( - (args.min_len is None or len(line) >= args.min_len) and - (args.max_len is None or len(line) <= args.max_len) - ) - else: - def valid(lines): - return True - - with contextlib.ExitStack() as stack: - inputs = [ - stack.enter_context(open(input, "r", encoding="utf-8")) - if input != "-" else sys.stdin - for input in args.inputs - ] - outputs = [ - stack.enter_context(open(output, "w", encoding="utf-8")) - if output != "-" else sys.stdout - for output in args.outputs - ] - - stats = { - "num_empty": 0, - "num_filtered": 0, - } - - def encode_line(line): - line = line.strip() - if len(line) > 0: - line = encode(line) - if valid(line): - return line - else: - stats["num_filtered"] += 1 - else: - stats["num_empty"] += 1 - return None - - for i, lines in enumerate(zip(*inputs), start=1): - enc_lines = list(map(encode_line, lines)) - if not any(enc_line is None for enc_line in enc_lines): - for enc_line, output_h in zip(enc_lines, outputs): - print(" ".join(enc_line), file=output_h) - if i % 10000 == 0: - print("processed {} lines".format(i), file=sys.stderr) - - print("skipped {} empty lines".format(stats["num_empty"]), file=sys.stderr) - print("filtered {} lines".format(stats["num_filtered"]), file=sys.stderr) - - -if __name__ == "__main__": - main() diff --git a/egs/librispeech/conformer/local/spm_train.py b/egs/librispeech/conformer/local/spm_train.py deleted file mode 100755 index 134a0b1d3..000000000 --- a/egs/librispeech/conformer/local/spm_train.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in the -# https://github.com/pytorch/fairseq/blob/master/LICENSE -import sys - -import sentencepiece as spm - -if __name__ == "__main__": - spm.SentencePieceTrainer.Train(" ".join(sys.argv[1:])) diff --git a/egs/librispeech/conformer/path.sh b/egs/librispeech/conformer/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/librispeech/conformer/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/librispeech/conformer/run.sh b/egs/librispeech/conformer/run.sh deleted file mode 100755 index 52963400d..000000000 --- a/egs/librispeech/conformer/run.sh +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=en -token_type=bpe -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data= -data_url=www.openslr.org/resources/12 - -# bpe model -nbpe=5000 -bpemode=unigram - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train_960 -valid_set=dev -test_sets="test_clean test_other dev_clean dev_other" - -asr_config=conf/train_asr_conformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer_ctc0.3_beam5yaml -#inference_config=conf/decode_asr_transformer_ctc0.3_beam60.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - for part in dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500; do - local/download_and_untar.sh ${raw_data} ${data_url} ${part} - done -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - for x in dev-clean dev-other test-clean test-other train-clean-100 train-clean-360 train-other-500; do - local/data_prep.sh ${raw_data}/LibriSpeech/${x} ${feats_dir}/data/${x//-/_} - done - mkdir $feats_dir/data/$valid_set - dev_sets="dev_clean dev_other" - for file in wav.scp text; do - ( for f in $dev_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$valid_set/$file || exit 1; - done - mkdir $feats_dir/data/$train_set - train_sets="train_clean_100 train_clean_360 train_other_500" - for file in wav.scp text; do - ( for f in $train_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$train_set/$file || exit 1; - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe}_units.txt -bpemodel=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe} -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - ### Task dependent. You have to check non-linguistic symbols used in the corpus. - echo "stage 2: Dictionary and Json Data Preparation" - mkdir -p ${feats_dir}/data/lang_char/ - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - cut -f 2- -d" " ${feats_dir}/data/${train_set}/text > ${feats_dir}/data/lang_char/input.txt - local/spm_train.py --input=${feats_dir}/data/lang_char/input.txt --vocab_size=${nbpe} --model_type=${bpemode} --model_prefix=${bpemodel} --input_sentence_size=100000000 - local/spm_encode.py --model=${bpemodel}.model --output_format=piece < ${feats_dir}/data/lang_char/input.txt | tr ' ' '\n' | sort | uniq | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --split_with_space false \ - --bpemodel ${bpemodel}.model \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/compute_wer.py ${_data}/text ${_dir}/text ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi \ No newline at end of file diff --git a/egs/librispeech/conformer/utils b/egs/librispeech/conformer/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/librispeech/conformer/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/librispeech/e_branchformer/README.md b/egs/librispeech/e_branchformer/README.md deleted file mode 100644 index dcce8787a..000000000 --- a/egs/librispeech/e_branchformer/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Branchformer Result - -## Training Config -- Feature info: using raw speech, extracting 80 dims fbank online, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train config: conf/train_asr_e_branchformer.yaml -- LM config: LM was not used - -## Results (CER) -- Decode config: conf/decode_asr_transformer_beam10_ctc0.3.yaml (ctc weight:0.3) - -| testset | CER(%) | -|:-----------:|:-------:| -| dev_clean | 1.97 | -| dev_other | 4.75 | -| test_clean | 2.15 | -| test_other | 4.80 | \ No newline at end of file diff --git a/egs/librispeech/e_branchformer/conf/decode_asr_transformer_beam10_ctc0.3.yaml b/egs/librispeech/e_branchformer/conf/decode_asr_transformer_beam10_ctc0.3.yaml deleted file mode 100644 index 62745defc..000000000 --- a/egs/librispeech/e_branchformer/conf/decode_asr_transformer_beam10_ctc0.3.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 10 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.3 -lm_weight: 0.0 diff --git a/egs/librispeech/e_branchformer/conf/train_asr_e_branchformer.yaml b/egs/librispeech/e_branchformer/conf/train_asr_e_branchformer.yaml deleted file mode 100644 index c3607ae2f..000000000 --- a/egs/librispeech/e_branchformer/conf/train_asr_e_branchformer.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# network architecture -# encoder related -encoder: e_branchformer -encoder_conf: - output_size: 512 - attention_heads: 8 - attention_layer_type: rel_selfattn - pos_enc_layer_type: rel_pos - rel_pos_type: latest - cgmlp_linear_units: 3072 - cgmlp_conv_kernel: 31 - use_linear_after_conv: false - gate_activation: identity - num_blocks: 17 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.1 - input_layer: conv2d - layer_drop_rate: 0.1 - linear_units: 1024 - positionwise_layer_type: linear - macaron_ffn: true - use_ffn: true - merge_conv_kernel: 31 - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 8 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.1 - src_attention_dropout_rate: 0.1 - layer_drop_rate: 0.2 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 2 -grad_clip: 5 -max_epoch: 240 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.002 - weight_decay: 0.000001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 40000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 27 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_ratio_range: - - 0. - - 0.05 - num_time_mask: 10 - -dataset_conf: - data_names: speech,text - data_types: sound,text - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 30000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/librispeech/e_branchformer/local/data_prep.sh b/egs/librispeech/e_branchformer/local/data_prep.sh deleted file mode 100755 index c939b5f27..000000000 --- a/egs/librispeech/e_branchformer/local/data_prep.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Vassil Panayotov -# 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " - echo "e.g.: $0 /export/a15/vpanayotov/data/LibriSpeech/dev-clean data/dev-clean" - exit 1 -fi - -src=$1 -dst=$2 - -# all utterances are FLAC compressed -if ! which flac >&/dev/null; then - echo "Please install 'flac' on ALL worker nodes!" - exit 1 -fi - -spk_file=$src/../SPEAKERS.TXT - -mkdir -p $dst || exit 1 - -[ ! -d $src ] && echo "$0: no such directory $src" && exit 1 -[ ! -f $spk_file ] && echo "$0: expected file $spk_file to exist" && exit 1 - - -wav_scp=$dst/wav.scp; [[ -f "$wav_scp" ]] && rm $wav_scp -trans=$dst/text; [[ -f "$trans" ]] && rm $trans - -for reader_dir in $(find -L $src -mindepth 1 -maxdepth 1 -type d | sort); do - reader=$(basename $reader_dir) - if ! [ $reader -eq $reader ]; then # not integer. - echo "$0: unexpected subdirectory name $reader" - exit 1 - fi - - for chapter_dir in $(find -L $reader_dir/ -mindepth 1 -maxdepth 1 -type d | sort); do - chapter=$(basename $chapter_dir) - if ! [ "$chapter" -eq "$chapter" ]; then - echo "$0: unexpected chapter-subdirectory name $chapter" - exit 1 - fi - - find -L $chapter_dir/ -iname "*.flac" | sort | xargs -I% basename % .flac | \ - awk -v "dir=$chapter_dir" '{printf "%s %s/%s.flac \n", $0, dir, $0}' >>$wav_scp|| exit 1 - - chapter_trans=$chapter_dir/${reader}-${chapter}.trans.txt - [ ! -f $chapter_trans ] && echo "$0: expected file $chapter_trans to exist" && exit 1 - cat $chapter_trans >>$trans - done -done - -echo "$0: successfully prepared data in $dst" - -exit 0 diff --git a/egs/librispeech/e_branchformer/local/download_and_untar.sh b/egs/librispeech/e_branchformer/local/download_and_untar.sh deleted file mode 100755 index fe322e4af..000000000 --- a/egs/librispeech/e_branchformer/local/download_and_untar.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a15/vpanayotov/data www.openslr.org/resources/11 dev-clean" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: dev-clean, test-clean, dev-other, test-other," - echo " train-clean-100, train-clean-360, train-other-500." - exit 1 -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1 -fi - -part_ok=false -list="dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1 -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1 -fi - -if [ -f $data/LibriSpeech/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0 -fi - - -# sizes of the archive files in bytes. This is some older versions. -sizes_old="371012589 347390293 379743611 361838298 6420417880 23082659865 30626749128" -# sizes_new is the archive file sizes of the final release. Some of these sizes are of -# things we probably won't download. -sizes_new="337926286 314305928 695964615 297279345 87960560420 33373768 346663984 328757843 6387309499 23049477885 30593501606" - -if [ -f $data/$part.tar.gz ]; then - size=$(/bin/ls -l $data/$part.tar.gz | awk '{print $5}') - size_ok=false - for s in $sizes_old $sizes_new; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tar.gz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tar.gz - else - echo "$data/$part.tar.gz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tar.gz ]; then - if ! which wget >/dev/null; then - echo "$0: wget is not installed." - exit 1 - fi - full_url=$url/$part.tar.gz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - if ! wget -P $data --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1 - fi -fi - -if ! tar -C $data -xvzf $data/$part.tar.gz; then - echo "$0: error un-tarring archive $data/$part.tar.gz" - exit 1 -fi - -touch $data/LibriSpeech/$part/.complete - -echo "$0: Successfully downloaded and un-tarred $data/$part.tar.gz" - -if $remove_archive; then - echo "$0: removing $data/$part.tar.gz file since --remove-archive option was supplied." - rm $data/$part.tar.gz -fi diff --git a/egs/librispeech/e_branchformer/local/spm_encode.py b/egs/librispeech/e_branchformer/local/spm_encode.py deleted file mode 100755 index 9e1c15f0e..000000000 --- a/egs/librispeech/e_branchformer/local/spm_encode.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in -# https://github.com/pytorch/fairseq/blob/master/LICENSE - - -import argparse -import contextlib -import sys - -import sentencepiece as spm - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--model", required=True, - help="sentencepiece model to use for encoding") - parser.add_argument("--inputs", nargs="+", default=['-'], - help="input files to filter/encode") - parser.add_argument("--outputs", nargs="+", default=['-'], - help="path to save encoded outputs") - parser.add_argument("--output_format", choices=["piece", "id"], default="piece") - parser.add_argument("--min-len", type=int, metavar="N", - help="filter sentence pairs with fewer than N tokens") - parser.add_argument("--max-len", type=int, metavar="N", - help="filter sentence pairs with more than N tokens") - args = parser.parse_args() - - assert len(args.inputs) == len(args.outputs), \ - "number of input and output paths should match" - - sp = spm.SentencePieceProcessor() - sp.Load(args.model) - - if args.output_format == "piece": - def encode(l): - return sp.EncodeAsPieces(l) - elif args.output_format == "id": - def encode(l): - return list(map(str, sp.EncodeAsIds(l))) - else: - raise NotImplementedError - - if args.min_len is not None or args.max_len is not None: - def valid(line): - return ( - (args.min_len is None or len(line) >= args.min_len) and - (args.max_len is None or len(line) <= args.max_len) - ) - else: - def valid(lines): - return True - - with contextlib.ExitStack() as stack: - inputs = [ - stack.enter_context(open(input, "r", encoding="utf-8")) - if input != "-" else sys.stdin - for input in args.inputs - ] - outputs = [ - stack.enter_context(open(output, "w", encoding="utf-8")) - if output != "-" else sys.stdout - for output in args.outputs - ] - - stats = { - "num_empty": 0, - "num_filtered": 0, - } - - def encode_line(line): - line = line.strip() - if len(line) > 0: - line = encode(line) - if valid(line): - return line - else: - stats["num_filtered"] += 1 - else: - stats["num_empty"] += 1 - return None - - for i, lines in enumerate(zip(*inputs), start=1): - enc_lines = list(map(encode_line, lines)) - if not any(enc_line is None for enc_line in enc_lines): - for enc_line, output_h in zip(enc_lines, outputs): - print(" ".join(enc_line), file=output_h) - if i % 10000 == 0: - print("processed {} lines".format(i), file=sys.stderr) - - print("skipped {} empty lines".format(stats["num_empty"]), file=sys.stderr) - print("filtered {} lines".format(stats["num_filtered"]), file=sys.stderr) - - -if __name__ == "__main__": - main() diff --git a/egs/librispeech/e_branchformer/local/spm_train.py b/egs/librispeech/e_branchformer/local/spm_train.py deleted file mode 100755 index 134a0b1d3..000000000 --- a/egs/librispeech/e_branchformer/local/spm_train.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in the -# https://github.com/pytorch/fairseq/blob/master/LICENSE -import sys - -import sentencepiece as spm - -if __name__ == "__main__": - spm.SentencePieceTrainer.Train(" ".join(sys.argv[1:])) diff --git a/egs/librispeech/e_branchformer/path.sh b/egs/librispeech/e_branchformer/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/librispeech/e_branchformer/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/librispeech/e_branchformer/run.sh b/egs/librispeech/e_branchformer/run.sh deleted file mode 100755 index f1ffa0deb..000000000 --- a/egs/librispeech/e_branchformer/run.sh +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=en -token_type=bpe -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data= -data_url=www.openslr.org/resources/12 - -# bpe model -nbpe=5000 -bpemode=unigram - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train_960 -valid_set=dev -test_sets="test_clean test_other dev_clean dev_other" - -asr_config=conf/train_asr_e_branchformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer_beam10_ctc0.3.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - for part in dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500; do - local/download_and_untar.sh ${raw_data} ${data_url} ${part} - done -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - for x in dev-clean dev-other test-clean test-other train-clean-100 train-clean-360 train-other-500; do - local/data_prep.sh ${raw_data}/LibriSpeech/${x} ${feats_dir}/data/${x//-/_} - done - mkdir $feats_dir/data/$valid_set - dev_sets="dev_clean dev_other" - for file in wav.scp text; do - ( for f in $dev_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$valid_set/$file || exit 1; - done - mkdir $feats_dir/data/$train_set - train_sets="train_clean_100 train_clean_360 train_other_500" - for file in wav.scp text; do - ( for f in $train_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$train_set/$file || exit 1; - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe}_units.txt -bpemodel=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe} -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - ### Task dependent. You have to check non-linguistic symbols used in the corpus. - echo "stage 2: Dictionary and Json Data Preparation" - mkdir -p ${feats_dir}/data/lang_char/ - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - cut -f 2- -d" " ${feats_dir}/data/${train_set}/text > ${feats_dir}/data/lang_char/input.txt - local/spm_train.py --input=${feats_dir}/data/lang_char/input.txt --vocab_size=${nbpe} --model_type=${bpemode} --model_prefix=${bpemodel} --input_sentence_size=100000000 - local/spm_encode.py --model=${bpemodel}.model --output_format=piece < ${feats_dir}/data/lang_char/input.txt | tr ' ' '\n' | sort | uniq | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --split_with_space false \ - --bpemodel ${bpemodel}.model \ - --token_type $token_type \ - --token_list $token_list \ - --dataset_type large \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/compute_wer.py ${_data}/text ${_dir}/text ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi \ No newline at end of file diff --git a/egs/librispeech/e_branchformer/utils b/egs/librispeech/e_branchformer/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/librispeech/e_branchformer/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/librispeech/rnnt/README.md b/egs/librispeech/rnnt/README.md deleted file mode 100644 index c64e2e8fa..000000000 --- a/egs/librispeech/rnnt/README.md +++ /dev/null @@ -1,18 +0,0 @@ - -# Streaming RNN-T Result - -## Training Config -- 8 gpu(Tesla V100) -- Feature info: using 80 dims fbank, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train config: conf/train_conformer_rnnt_unified.yaml -- chunk config: chunk size 16, 1 left chunk -- LM config: LM was not used -- Model size: 90M - -## Results (CER) -- Decode config: conf/decode_rnnt_conformer_streaming.yaml - -| testset | WER(%) | -|:--------------:|:-------:| -| test_clean | 3.58 | -| test_other | 9.27 | diff --git a/egs/librispeech/rnnt/conf/decode_rnnt_conformer_streaming.yaml b/egs/librispeech/rnnt/conf/decode_rnnt_conformer_streaming.yaml deleted file mode 100644 index 26e43c64d..000000000 --- a/egs/librispeech/rnnt/conf/decode_rnnt_conformer_streaming.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# The conformer transducer decoding configuration from @jeon30c -beam_size: 10 -simu_streaming: false -streaming: true -chunk_size: 16 -left_context: 16 -right_context: 0 - diff --git a/egs/librispeech/rnnt/conf/train_conformer_rnnt_unified.yaml b/egs/librispeech/rnnt/conf/train_conformer_rnnt_unified.yaml deleted file mode 100644 index 39c6a6af5..000000000 --- a/egs/librispeech/rnnt/conf/train_conformer_rnnt_unified.yaml +++ /dev/null @@ -1,98 +0,0 @@ -encoder: chunk_conformer -encoder_conf: - activation_type: swish - time_reduction_factor: 2 - unified_model_training: true - default_chunk_size: 16 - jitter_range: 4 - left_chunk_size: 1 - embed_vgg_like: false - subsampling_factor: 4 - linear_units: 2048 - output_size: 512 - attention_heads: 8 - dropout_rate: 0.5 - positional_dropout_rate: 0.5 - attention_dropout_rate: 0.5 - cnn_module_kernel: 15 - num_blocks: 12 - -# decoder related -rnnt_decoder: rnnt -rnnt_decoder_conf: - embed_size: 512 - hidden_size: 512 - embed_dropout_rate: 0.5 - dropout_rate: 0.5 - use_embed_mask: true - -joint_network_conf: - joint_space_size: 512 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# Auxiliary CTC -model: rnnt_unified -model_conf: - auxiliary_ctc_weight: 0.0 - -# minibatch related -use_amp: true - -# optimization related -accum_grad: 4 -grad_clip: 5 -max_epoch: 100 -val_scheduler_criterion: - - valid - - loss -best_model_criterion: -- - valid - - cer_transducer_chunk - - min -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 25000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 40 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 50 - num_time_mask: 5 - -dataset_conf: - shuffle: True - shuffle_conf: - shuffle_size: 1024 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 10000 - num_workers: 8 - -log_interval: 50 -normalize: None diff --git a/egs/librispeech/rnnt/local/data_prep.sh b/egs/librispeech/rnnt/local/data_prep.sh deleted file mode 100755 index c939b5f27..000000000 --- a/egs/librispeech/rnnt/local/data_prep.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Vassil Panayotov -# 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " - echo "e.g.: $0 /export/a15/vpanayotov/data/LibriSpeech/dev-clean data/dev-clean" - exit 1 -fi - -src=$1 -dst=$2 - -# all utterances are FLAC compressed -if ! which flac >&/dev/null; then - echo "Please install 'flac' on ALL worker nodes!" - exit 1 -fi - -spk_file=$src/../SPEAKERS.TXT - -mkdir -p $dst || exit 1 - -[ ! -d $src ] && echo "$0: no such directory $src" && exit 1 -[ ! -f $spk_file ] && echo "$0: expected file $spk_file to exist" && exit 1 - - -wav_scp=$dst/wav.scp; [[ -f "$wav_scp" ]] && rm $wav_scp -trans=$dst/text; [[ -f "$trans" ]] && rm $trans - -for reader_dir in $(find -L $src -mindepth 1 -maxdepth 1 -type d | sort); do - reader=$(basename $reader_dir) - if ! [ $reader -eq $reader ]; then # not integer. - echo "$0: unexpected subdirectory name $reader" - exit 1 - fi - - for chapter_dir in $(find -L $reader_dir/ -mindepth 1 -maxdepth 1 -type d | sort); do - chapter=$(basename $chapter_dir) - if ! [ "$chapter" -eq "$chapter" ]; then - echo "$0: unexpected chapter-subdirectory name $chapter" - exit 1 - fi - - find -L $chapter_dir/ -iname "*.flac" | sort | xargs -I% basename % .flac | \ - awk -v "dir=$chapter_dir" '{printf "%s %s/%s.flac \n", $0, dir, $0}' >>$wav_scp|| exit 1 - - chapter_trans=$chapter_dir/${reader}-${chapter}.trans.txt - [ ! -f $chapter_trans ] && echo "$0: expected file $chapter_trans to exist" && exit 1 - cat $chapter_trans >>$trans - done -done - -echo "$0: successfully prepared data in $dst" - -exit 0 diff --git a/egs/librispeech/rnnt/local/download_and_untar.sh b/egs/librispeech/rnnt/local/download_and_untar.sh deleted file mode 100755 index fe322e4af..000000000 --- a/egs/librispeech/rnnt/local/download_and_untar.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a15/vpanayotov/data www.openslr.org/resources/11 dev-clean" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: dev-clean, test-clean, dev-other, test-other," - echo " train-clean-100, train-clean-360, train-other-500." - exit 1 -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1 -fi - -part_ok=false -list="dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1 -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1 -fi - -if [ -f $data/LibriSpeech/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0 -fi - - -# sizes of the archive files in bytes. This is some older versions. -sizes_old="371012589 347390293 379743611 361838298 6420417880 23082659865 30626749128" -# sizes_new is the archive file sizes of the final release. Some of these sizes are of -# things we probably won't download. -sizes_new="337926286 314305928 695964615 297279345 87960560420 33373768 346663984 328757843 6387309499 23049477885 30593501606" - -if [ -f $data/$part.tar.gz ]; then - size=$(/bin/ls -l $data/$part.tar.gz | awk '{print $5}') - size_ok=false - for s in $sizes_old $sizes_new; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tar.gz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tar.gz - else - echo "$data/$part.tar.gz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tar.gz ]; then - if ! which wget >/dev/null; then - echo "$0: wget is not installed." - exit 1 - fi - full_url=$url/$part.tar.gz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - if ! wget -P $data --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1 - fi -fi - -if ! tar -C $data -xvzf $data/$part.tar.gz; then - echo "$0: error un-tarring archive $data/$part.tar.gz" - exit 1 -fi - -touch $data/LibriSpeech/$part/.complete - -echo "$0: Successfully downloaded and un-tarred $data/$part.tar.gz" - -if $remove_archive; then - echo "$0: removing $data/$part.tar.gz file since --remove-archive option was supplied." - rm $data/$part.tar.gz -fi diff --git a/egs/librispeech/rnnt/local/spm_encode.py b/egs/librispeech/rnnt/local/spm_encode.py deleted file mode 100755 index 9e1c15f0e..000000000 --- a/egs/librispeech/rnnt/local/spm_encode.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in -# https://github.com/pytorch/fairseq/blob/master/LICENSE - - -import argparse -import contextlib -import sys - -import sentencepiece as spm - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--model", required=True, - help="sentencepiece model to use for encoding") - parser.add_argument("--inputs", nargs="+", default=['-'], - help="input files to filter/encode") - parser.add_argument("--outputs", nargs="+", default=['-'], - help="path to save encoded outputs") - parser.add_argument("--output_format", choices=["piece", "id"], default="piece") - parser.add_argument("--min-len", type=int, metavar="N", - help="filter sentence pairs with fewer than N tokens") - parser.add_argument("--max-len", type=int, metavar="N", - help="filter sentence pairs with more than N tokens") - args = parser.parse_args() - - assert len(args.inputs) == len(args.outputs), \ - "number of input and output paths should match" - - sp = spm.SentencePieceProcessor() - sp.Load(args.model) - - if args.output_format == "piece": - def encode(l): - return sp.EncodeAsPieces(l) - elif args.output_format == "id": - def encode(l): - return list(map(str, sp.EncodeAsIds(l))) - else: - raise NotImplementedError - - if args.min_len is not None or args.max_len is not None: - def valid(line): - return ( - (args.min_len is None or len(line) >= args.min_len) and - (args.max_len is None or len(line) <= args.max_len) - ) - else: - def valid(lines): - return True - - with contextlib.ExitStack() as stack: - inputs = [ - stack.enter_context(open(input, "r", encoding="utf-8")) - if input != "-" else sys.stdin - for input in args.inputs - ] - outputs = [ - stack.enter_context(open(output, "w", encoding="utf-8")) - if output != "-" else sys.stdout - for output in args.outputs - ] - - stats = { - "num_empty": 0, - "num_filtered": 0, - } - - def encode_line(line): - line = line.strip() - if len(line) > 0: - line = encode(line) - if valid(line): - return line - else: - stats["num_filtered"] += 1 - else: - stats["num_empty"] += 1 - return None - - for i, lines in enumerate(zip(*inputs), start=1): - enc_lines = list(map(encode_line, lines)) - if not any(enc_line is None for enc_line in enc_lines): - for enc_line, output_h in zip(enc_lines, outputs): - print(" ".join(enc_line), file=output_h) - if i % 10000 == 0: - print("processed {} lines".format(i), file=sys.stderr) - - print("skipped {} empty lines".format(stats["num_empty"]), file=sys.stderr) - print("filtered {} lines".format(stats["num_filtered"]), file=sys.stderr) - - -if __name__ == "__main__": - main() diff --git a/egs/librispeech/rnnt/local/spm_train.py b/egs/librispeech/rnnt/local/spm_train.py deleted file mode 100755 index 134a0b1d3..000000000 --- a/egs/librispeech/rnnt/local/spm_train.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in the -# https://github.com/pytorch/fairseq/blob/master/LICENSE -import sys - -import sentencepiece as spm - -if __name__ == "__main__": - spm.SentencePieceTrainer.Train(" ".join(sys.argv[1:])) diff --git a/egs/librispeech/rnnt/path.sh b/egs/librispeech/rnnt/path.sh deleted file mode 100644 index 7972642d0..000000000 --- a/egs/librispeech/rnnt/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/librispeech/rnnt/run.sh b/egs/librispeech/rnnt/run.sh deleted file mode 100755 index efccd8578..000000000 --- a/egs/librispeech/rnnt/run.sh +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="" #feature output dictionary -exp_dir="" -lang=en -token_type=bpe -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data= -data_url=www.openslr.org/resources/12 - -# bpe model -nbpe=5000 -bpemode=unigram - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train_960 -valid_set=dev -test_sets="test_clean test_other dev_clean dev_other" - -asr_config=conf/train_conformer_rnnt_unified.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_rnnt_conformer_streaming.yaml -inference_asr_model=valid.cer_transducer_chunk.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - for part in dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500; do - local/download_and_untar.sh ${raw_data} ${data_url} ${part} - done -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - for x in dev-clean dev-other test-clean test-other train-clean-100 train-clean-360 train-other-500; do - local/data_prep.sh ${raw_data}/LibriSpeech/${x} ${feats_dir}/data/${x//-/_} - done - mkdir $feats_dir/data/$valid_set - dev_sets="dev_clean dev_other" - for file in wav.scp text; do - ( for f in $dev_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$valid_set/$file || exit 1; - done - mkdir $feats_dir/data/$train_set - train_sets="train_clean_100 train_clean_360 train_other_500" - for file in wav.scp text; do - ( for f in $train_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$train_set/$file || exit 1; - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} ${feats_dir}/data/${train_set} -fi - -token_list=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe}_units.txt -bpemodel=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe} -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - ### Task dependent. You have to check non-linguistic symbols used in the corpus. - echo "stage 2: Dictionary and Json Data Preparation" - mkdir -p ${feats_dir}/data/lang_char/ - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - cut -f 2- -d" " ${feats_dir}/data/${train_set}/text > ${feats_dir}/data/lang_char/input.txt - local/spm_train.py --input=${feats_dir}/data/lang_char/input.txt --vocab_size=${nbpe} --model_type=${bpemode} --model_prefix=${bpemodel} --input_sentence_size=100000000 - local/spm_encode.py --model=${bpemodel}.model --output_format=piece < ${feats_dir}/data/lang_char/input.txt | tr ' ' '\n' | sort | uniq | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=./ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --split_with_space false \ - --bpemodel ${bpemodel}.model \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/cmvn.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/cmvn.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/compute_wer.py ${_data}/text ${_dir}/text ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi diff --git a/egs/librispeech/rnnt/utils b/egs/librispeech/rnnt/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/librispeech/rnnt/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/librispeech_100h/conformer/conf/decode_asr_transformer_ctc0.3_beam1.yaml b/egs/librispeech_100h/conformer/conf/decode_asr_transformer_ctc0.3_beam1.yaml deleted file mode 100644 index edc6bab0b..000000000 --- a/egs/librispeech_100h/conformer/conf/decode_asr_transformer_ctc0.3_beam1.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 1 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.3 -lm_weight: 0.0 diff --git a/egs/librispeech_100h/conformer/conf/decode_asr_transformer_ctc0.3_beam20.yaml b/egs/librispeech_100h/conformer/conf/decode_asr_transformer_ctc0.3_beam20.yaml deleted file mode 100644 index b2b042779..000000000 --- a/egs/librispeech_100h/conformer/conf/decode_asr_transformer_ctc0.3_beam20.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 20 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.3 -lm_weight: 0.0 diff --git a/egs/librispeech_100h/conformer/conf/decode_asr_transformer_ctc0.3_beam5.yaml b/egs/librispeech_100h/conformer/conf/decode_asr_transformer_ctc0.3_beam5.yaml deleted file mode 100644 index 8f7c75d1c..000000000 --- a/egs/librispeech_100h/conformer/conf/decode_asr_transformer_ctc0.3_beam5.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 5 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.3 -lm_weight: 0.0 diff --git a/egs/librispeech_100h/conformer/conf/train_asr_conformer.yaml b/egs/librispeech_100h/conformer/conf/train_asr_conformer.yaml deleted file mode 100644 index bd92bb0bf..000000000 --- a/egs/librispeech_100h/conformer/conf/train_asr_conformer.yaml +++ /dev/null @@ -1,92 +0,0 @@ -encoder: conformer -encoder_conf: - output_size: 256 - attention_heads: 4 - linear_units: 1024 - num_blocks: 12 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.1 - input_layer: conv2d - normalize_before: true - macaron_style: true - rel_pos_type: latest - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - use_cnn_module: true - cnn_module_kernel: 31 - -decoder: transformer -decoder_conf: - attention_heads: 4 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.1 - src_attention_dropout_rate: 0.1 - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 - length_normalized_loss: false - -accum_grad: 1 -max_epoch: 210 -patience: none -init: none -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.002 - weight_decay: 0.000001 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 15000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 27 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_ratio_range: - - 0. - - 0.05 - num_time_mask: 5 - -dataset_conf: - shuffle: True - shuffle_conf: - shuffle_size: 1024 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 10000 - num_workers: 8 - -log_interval: 50 -normalize: None \ No newline at end of file diff --git a/egs/librispeech_100h/conformer/local/data_prep.sh b/egs/librispeech_100h/conformer/local/data_prep.sh deleted file mode 100755 index c939b5f27..000000000 --- a/egs/librispeech_100h/conformer/local/data_prep.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Vassil Panayotov -# 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " - echo "e.g.: $0 /export/a15/vpanayotov/data/LibriSpeech/dev-clean data/dev-clean" - exit 1 -fi - -src=$1 -dst=$2 - -# all utterances are FLAC compressed -if ! which flac >&/dev/null; then - echo "Please install 'flac' on ALL worker nodes!" - exit 1 -fi - -spk_file=$src/../SPEAKERS.TXT - -mkdir -p $dst || exit 1 - -[ ! -d $src ] && echo "$0: no such directory $src" && exit 1 -[ ! -f $spk_file ] && echo "$0: expected file $spk_file to exist" && exit 1 - - -wav_scp=$dst/wav.scp; [[ -f "$wav_scp" ]] && rm $wav_scp -trans=$dst/text; [[ -f "$trans" ]] && rm $trans - -for reader_dir in $(find -L $src -mindepth 1 -maxdepth 1 -type d | sort); do - reader=$(basename $reader_dir) - if ! [ $reader -eq $reader ]; then # not integer. - echo "$0: unexpected subdirectory name $reader" - exit 1 - fi - - for chapter_dir in $(find -L $reader_dir/ -mindepth 1 -maxdepth 1 -type d | sort); do - chapter=$(basename $chapter_dir) - if ! [ "$chapter" -eq "$chapter" ]; then - echo "$0: unexpected chapter-subdirectory name $chapter" - exit 1 - fi - - find -L $chapter_dir/ -iname "*.flac" | sort | xargs -I% basename % .flac | \ - awk -v "dir=$chapter_dir" '{printf "%s %s/%s.flac \n", $0, dir, $0}' >>$wav_scp|| exit 1 - - chapter_trans=$chapter_dir/${reader}-${chapter}.trans.txt - [ ! -f $chapter_trans ] && echo "$0: expected file $chapter_trans to exist" && exit 1 - cat $chapter_trans >>$trans - done -done - -echo "$0: successfully prepared data in $dst" - -exit 0 diff --git a/egs/librispeech_100h/conformer/local/download_and_untar.sh b/egs/librispeech_100h/conformer/local/download_and_untar.sh deleted file mode 100755 index fe322e4af..000000000 --- a/egs/librispeech_100h/conformer/local/download_and_untar.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a15/vpanayotov/data www.openslr.org/resources/11 dev-clean" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: dev-clean, test-clean, dev-other, test-other," - echo " train-clean-100, train-clean-360, train-other-500." - exit 1 -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1 -fi - -part_ok=false -list="dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1 -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1 -fi - -if [ -f $data/LibriSpeech/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0 -fi - - -# sizes of the archive files in bytes. This is some older versions. -sizes_old="371012589 347390293 379743611 361838298 6420417880 23082659865 30626749128" -# sizes_new is the archive file sizes of the final release. Some of these sizes are of -# things we probably won't download. -sizes_new="337926286 314305928 695964615 297279345 87960560420 33373768 346663984 328757843 6387309499 23049477885 30593501606" - -if [ -f $data/$part.tar.gz ]; then - size=$(/bin/ls -l $data/$part.tar.gz | awk '{print $5}') - size_ok=false - for s in $sizes_old $sizes_new; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tar.gz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tar.gz - else - echo "$data/$part.tar.gz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tar.gz ]; then - if ! which wget >/dev/null; then - echo "$0: wget is not installed." - exit 1 - fi - full_url=$url/$part.tar.gz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - if ! wget -P $data --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1 - fi -fi - -if ! tar -C $data -xvzf $data/$part.tar.gz; then - echo "$0: error un-tarring archive $data/$part.tar.gz" - exit 1 -fi - -touch $data/LibriSpeech/$part/.complete - -echo "$0: Successfully downloaded and un-tarred $data/$part.tar.gz" - -if $remove_archive; then - echo "$0: removing $data/$part.tar.gz file since --remove-archive option was supplied." - rm $data/$part.tar.gz -fi diff --git a/egs/librispeech_100h/conformer/local/spm_encode.py b/egs/librispeech_100h/conformer/local/spm_encode.py deleted file mode 100755 index 9e1c15f0e..000000000 --- a/egs/librispeech_100h/conformer/local/spm_encode.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in -# https://github.com/pytorch/fairseq/blob/master/LICENSE - - -import argparse -import contextlib -import sys - -import sentencepiece as spm - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--model", required=True, - help="sentencepiece model to use for encoding") - parser.add_argument("--inputs", nargs="+", default=['-'], - help="input files to filter/encode") - parser.add_argument("--outputs", nargs="+", default=['-'], - help="path to save encoded outputs") - parser.add_argument("--output_format", choices=["piece", "id"], default="piece") - parser.add_argument("--min-len", type=int, metavar="N", - help="filter sentence pairs with fewer than N tokens") - parser.add_argument("--max-len", type=int, metavar="N", - help="filter sentence pairs with more than N tokens") - args = parser.parse_args() - - assert len(args.inputs) == len(args.outputs), \ - "number of input and output paths should match" - - sp = spm.SentencePieceProcessor() - sp.Load(args.model) - - if args.output_format == "piece": - def encode(l): - return sp.EncodeAsPieces(l) - elif args.output_format == "id": - def encode(l): - return list(map(str, sp.EncodeAsIds(l))) - else: - raise NotImplementedError - - if args.min_len is not None or args.max_len is not None: - def valid(line): - return ( - (args.min_len is None or len(line) >= args.min_len) and - (args.max_len is None or len(line) <= args.max_len) - ) - else: - def valid(lines): - return True - - with contextlib.ExitStack() as stack: - inputs = [ - stack.enter_context(open(input, "r", encoding="utf-8")) - if input != "-" else sys.stdin - for input in args.inputs - ] - outputs = [ - stack.enter_context(open(output, "w", encoding="utf-8")) - if output != "-" else sys.stdout - for output in args.outputs - ] - - stats = { - "num_empty": 0, - "num_filtered": 0, - } - - def encode_line(line): - line = line.strip() - if len(line) > 0: - line = encode(line) - if valid(line): - return line - else: - stats["num_filtered"] += 1 - else: - stats["num_empty"] += 1 - return None - - for i, lines in enumerate(zip(*inputs), start=1): - enc_lines = list(map(encode_line, lines)) - if not any(enc_line is None for enc_line in enc_lines): - for enc_line, output_h in zip(enc_lines, outputs): - print(" ".join(enc_line), file=output_h) - if i % 10000 == 0: - print("processed {} lines".format(i), file=sys.stderr) - - print("skipped {} empty lines".format(stats["num_empty"]), file=sys.stderr) - print("filtered {} lines".format(stats["num_filtered"]), file=sys.stderr) - - -if __name__ == "__main__": - main() diff --git a/egs/librispeech_100h/conformer/local/spm_train.py b/egs/librispeech_100h/conformer/local/spm_train.py deleted file mode 100755 index 134a0b1d3..000000000 --- a/egs/librispeech_100h/conformer/local/spm_train.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in the -# https://github.com/pytorch/fairseq/blob/master/LICENSE -import sys - -import sentencepiece as spm - -if __name__ == "__main__": - spm.SentencePieceTrainer.Train(" ".join(sys.argv[1:])) diff --git a/egs/librispeech_100h/conformer/path.sh b/egs/librispeech_100h/conformer/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/librispeech_100h/conformer/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/librispeech_100h/conformer/run.sh b/egs/librispeech_100h/conformer/run.sh deleted file mode 100755 index 41df5a418..000000000 --- a/egs/librispeech_100h/conformer/run.sh +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=en -token_type=bpe -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=0 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data= -data_url=www.openslr.org/resources/12 - -# bpe model -nbpe=5000 -bpemode=unigram - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train_clean_100 -valid_set=dev -test_sets="test_clean test_other dev_clean dev_other" - -asr_config=conf/train_asr_conformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -#inference_config=conf/decode_asr_transformer_ctc0.3_beam1.yaml -inference_config=conf/decode_asr_transformer_ctc0.3_beam5.yaml -#inference_config=conf/decode_asr_transformer_ctc0.3_beam20.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - for part in dev-clean test-clean dev-other test-other train-clean-100; do - local/download_and_untar.sh ${raw_data} ${data_url} ${part} - done -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - for x in dev-clean dev-other test-clean test-other train-clean-100; do - local/data_prep.sh ${raw_data}/LibriSpeech/${x} ${feats_dir}/data/${x//-/_} - done - mkdir $feats_dir/data/$valid_set - dev_sets="dev_clean dev_other" - for file in wav.scp text; do - ( for f in $dev_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$valid_set/$file || exit 1; - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 1.0 -fi - -token_list=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe}_units.txt -bpemodel=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe} -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - ### Task dependent. You have to check non-linguistic symbols used in the corpus. - echo "stage 2: Dictionary and Json Data Preparation" - mkdir -p ${feats_dir}/data/lang_char/ - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - cut -f 2- -d" " ${feats_dir}/data/${train_set}/text > ${feats_dir}/data/lang_char/input.txt - local/spm_train.py --input=${feats_dir}/data/lang_char/input.txt --vocab_size=${nbpe} --model_type=${bpemode} --model_prefix=${bpemodel} --input_sentence_size=100000000 - local/spm_encode.py --model=${bpemodel}.model --output_format=piece < ${feats_dir}/data/lang_char/input.txt | tr ' ' '\n' | sort | uniq | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --split_with_space false \ - --bpemodel ${bpemodel}.model \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/compute_wer.py ${_data}/text ${_dir}/text ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi \ No newline at end of file diff --git a/egs/librispeech_100h/conformer/utils b/egs/librispeech_100h/conformer/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/librispeech_100h/conformer/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/librispeech_100h/rnnt/README.md b/egs/librispeech_100h/rnnt/README.md deleted file mode 100644 index abadb2dff..000000000 --- a/egs/librispeech_100h/rnnt/README.md +++ /dev/null @@ -1,16 +0,0 @@ - -# Conformer Transducer Result - -## Training Config -- Feature info: using 80 dims fbank, global cmvn, speed perturb(0.9, 1.0, 1.1), specaugment -- Train config: conf/train_conformer_rnnt.yaml -- LM config: LM was not used -- Model size: 30.54M - -## Results (CER) -- Decode config: conf/decode_rnnt_conformer.yaml - -| testset | WER(%) | -|:--------------:|:-------:| -| test_clean | 6.64 | -| test_other | 17.12 | diff --git a/egs/librispeech_100h/rnnt/conf/decode_rnnt_conformer.yaml b/egs/librispeech_100h/rnnt/conf/decode_rnnt_conformer.yaml deleted file mode 100644 index 1a841d6dd..000000000 --- a/egs/librispeech_100h/rnnt/conf/decode_rnnt_conformer.yaml +++ /dev/null @@ -1,3 +0,0 @@ -# The conformer transducer decoding configuration from @jeon30c -beam_size: 10 - diff --git a/egs/librispeech_100h/rnnt/conf/train_conformer_rnnt.yaml b/egs/librispeech_100h/rnnt/conf/train_conformer_rnnt.yaml deleted file mode 100644 index 7ef9ec363..000000000 --- a/egs/librispeech_100h/rnnt/conf/train_conformer_rnnt.yaml +++ /dev/null @@ -1,96 +0,0 @@ -encoder: chunk_conformer -encoder_conf: - activation_type: swish - time_reduction_factor: 2 - embed_vgg_like: false - subsampling_factor: 4 - linear_units: 1024 - output_size: 256 - attention_heads: 4 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.1 - cnn_module_kernel: 31 - num_blocks: 15 - -# decoder related -rnnt_decoder: rnnt -rnnt_decoder_conf: - embed_size: 256 - hidden_size: 256 - embed_dropout_rate: 0.1 - dropout_rate: 0.2 - use_embed_mask: true - -joint_network_conf: - joint_space_size: 320 - - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# Auxiliary CTC -model: rnnt -model_conf: - auxiliary_ctc_weight: 0.3 - -# minibatch related -use_amp: true - -# optimization related -accum_grad: 8 -grad_clip: 5 -max_epoch: 200 -val_scheduler_criterion: - - valid - - loss -best_model_criterion: -- - valid - - cer_transducer - - min -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.002 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 25000 - -normalize: None - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 27 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_ratio_range: - - 0 - - 0.05 - num_time_mask: 5 - -dataset_conf: - shuffle: True - shuffle_conf: - shuffle_size: 1024 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 5000 - num_workers: 8 - -log_interval: 50 diff --git a/egs/librispeech_100h/rnnt/local/data_prep.sh b/egs/librispeech_100h/rnnt/local/data_prep.sh deleted file mode 100755 index c939b5f27..000000000 --- a/egs/librispeech_100h/rnnt/local/data_prep.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Vassil Panayotov -# 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " - echo "e.g.: $0 /export/a15/vpanayotov/data/LibriSpeech/dev-clean data/dev-clean" - exit 1 -fi - -src=$1 -dst=$2 - -# all utterances are FLAC compressed -if ! which flac >&/dev/null; then - echo "Please install 'flac' on ALL worker nodes!" - exit 1 -fi - -spk_file=$src/../SPEAKERS.TXT - -mkdir -p $dst || exit 1 - -[ ! -d $src ] && echo "$0: no such directory $src" && exit 1 -[ ! -f $spk_file ] && echo "$0: expected file $spk_file to exist" && exit 1 - - -wav_scp=$dst/wav.scp; [[ -f "$wav_scp" ]] && rm $wav_scp -trans=$dst/text; [[ -f "$trans" ]] && rm $trans - -for reader_dir in $(find -L $src -mindepth 1 -maxdepth 1 -type d | sort); do - reader=$(basename $reader_dir) - if ! [ $reader -eq $reader ]; then # not integer. - echo "$0: unexpected subdirectory name $reader" - exit 1 - fi - - for chapter_dir in $(find -L $reader_dir/ -mindepth 1 -maxdepth 1 -type d | sort); do - chapter=$(basename $chapter_dir) - if ! [ "$chapter" -eq "$chapter" ]; then - echo "$0: unexpected chapter-subdirectory name $chapter" - exit 1 - fi - - find -L $chapter_dir/ -iname "*.flac" | sort | xargs -I% basename % .flac | \ - awk -v "dir=$chapter_dir" '{printf "%s %s/%s.flac \n", $0, dir, $0}' >>$wav_scp|| exit 1 - - chapter_trans=$chapter_dir/${reader}-${chapter}.trans.txt - [ ! -f $chapter_trans ] && echo "$0: expected file $chapter_trans to exist" && exit 1 - cat $chapter_trans >>$trans - done -done - -echo "$0: successfully prepared data in $dst" - -exit 0 diff --git a/egs/librispeech_100h/rnnt/local/download_and_untar.sh b/egs/librispeech_100h/rnnt/local/download_and_untar.sh deleted file mode 100755 index fe322e4af..000000000 --- a/egs/librispeech_100h/rnnt/local/download_and_untar.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 Johns Hopkins University (author: Daniel Povey) -# Apache 2.0 - -remove_archive=false - -if [ "$1" == --remove-archive ]; then - remove_archive=true - shift -fi - -if [ $# -ne 3 ]; then - echo "Usage: $0 [--remove-archive] " - echo "e.g.: $0 /export/a15/vpanayotov/data www.openslr.org/resources/11 dev-clean" - echo "With --remove-archive it will remove the archive after successfully un-tarring it." - echo " can be one of: dev-clean, test-clean, dev-other, test-other," - echo " train-clean-100, train-clean-360, train-other-500." - exit 1 -fi - -data=$1 -url=$2 -part=$3 - -if [ ! -d "$data" ]; then - echo "$0: no such directory $data" - exit 1 -fi - -part_ok=false -list="dev-clean test-clean dev-other test-other train-clean-100 train-clean-360 train-other-500" -for x in $list; do - if [ "$part" == $x ]; then part_ok=true; fi -done -if ! $part_ok; then - echo "$0: expected to be one of $list, but got '$part'" - exit 1 -fi - -if [ -z "$url" ]; then - echo "$0: empty URL base." - exit 1 -fi - -if [ -f $data/LibriSpeech/$part/.complete ]; then - echo "$0: data part $part was already successfully extracted, nothing to do." - exit 0 -fi - - -# sizes of the archive files in bytes. This is some older versions. -sizes_old="371012589 347390293 379743611 361838298 6420417880 23082659865 30626749128" -# sizes_new is the archive file sizes of the final release. Some of these sizes are of -# things we probably won't download. -sizes_new="337926286 314305928 695964615 297279345 87960560420 33373768 346663984 328757843 6387309499 23049477885 30593501606" - -if [ -f $data/$part.tar.gz ]; then - size=$(/bin/ls -l $data/$part.tar.gz | awk '{print $5}') - size_ok=false - for s in $sizes_old $sizes_new; do if [ $s == $size ]; then size_ok=true; fi; done - if ! $size_ok; then - echo "$0: removing existing file $data/$part.tar.gz because its size in bytes $size" - echo "does not equal the size of one of the archives." - rm $data/$part.tar.gz - else - echo "$data/$part.tar.gz exists and appears to be complete." - fi -fi - -if [ ! -f $data/$part.tar.gz ]; then - if ! which wget >/dev/null; then - echo "$0: wget is not installed." - exit 1 - fi - full_url=$url/$part.tar.gz - echo "$0: downloading data from $full_url. This may take some time, please be patient." - - if ! wget -P $data --no-check-certificate $full_url; then - echo "$0: error executing wget $full_url" - exit 1 - fi -fi - -if ! tar -C $data -xvzf $data/$part.tar.gz; then - echo "$0: error un-tarring archive $data/$part.tar.gz" - exit 1 -fi - -touch $data/LibriSpeech/$part/.complete - -echo "$0: Successfully downloaded and un-tarred $data/$part.tar.gz" - -if $remove_archive; then - echo "$0: removing $data/$part.tar.gz file since --remove-archive option was supplied." - rm $data/$part.tar.gz -fi diff --git a/egs/librispeech_100h/rnnt/local/spm_encode.py b/egs/librispeech_100h/rnnt/local/spm_encode.py deleted file mode 100755 index 9e1c15f0e..000000000 --- a/egs/librispeech_100h/rnnt/local/spm_encode.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in -# https://github.com/pytorch/fairseq/blob/master/LICENSE - - -import argparse -import contextlib -import sys - -import sentencepiece as spm - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--model", required=True, - help="sentencepiece model to use for encoding") - parser.add_argument("--inputs", nargs="+", default=['-'], - help="input files to filter/encode") - parser.add_argument("--outputs", nargs="+", default=['-'], - help="path to save encoded outputs") - parser.add_argument("--output_format", choices=["piece", "id"], default="piece") - parser.add_argument("--min-len", type=int, metavar="N", - help="filter sentence pairs with fewer than N tokens") - parser.add_argument("--max-len", type=int, metavar="N", - help="filter sentence pairs with more than N tokens") - args = parser.parse_args() - - assert len(args.inputs) == len(args.outputs), \ - "number of input and output paths should match" - - sp = spm.SentencePieceProcessor() - sp.Load(args.model) - - if args.output_format == "piece": - def encode(l): - return sp.EncodeAsPieces(l) - elif args.output_format == "id": - def encode(l): - return list(map(str, sp.EncodeAsIds(l))) - else: - raise NotImplementedError - - if args.min_len is not None or args.max_len is not None: - def valid(line): - return ( - (args.min_len is None or len(line) >= args.min_len) and - (args.max_len is None or len(line) <= args.max_len) - ) - else: - def valid(lines): - return True - - with contextlib.ExitStack() as stack: - inputs = [ - stack.enter_context(open(input, "r", encoding="utf-8")) - if input != "-" else sys.stdin - for input in args.inputs - ] - outputs = [ - stack.enter_context(open(output, "w", encoding="utf-8")) - if output != "-" else sys.stdout - for output in args.outputs - ] - - stats = { - "num_empty": 0, - "num_filtered": 0, - } - - def encode_line(line): - line = line.strip() - if len(line) > 0: - line = encode(line) - if valid(line): - return line - else: - stats["num_filtered"] += 1 - else: - stats["num_empty"] += 1 - return None - - for i, lines in enumerate(zip(*inputs), start=1): - enc_lines = list(map(encode_line, lines)) - if not any(enc_line is None for enc_line in enc_lines): - for enc_line, output_h in zip(enc_lines, outputs): - print(" ".join(enc_line), file=output_h) - if i % 10000 == 0: - print("processed {} lines".format(i), file=sys.stderr) - - print("skipped {} empty lines".format(stats["num_empty"]), file=sys.stderr) - print("filtered {} lines".format(stats["num_filtered"]), file=sys.stderr) - - -if __name__ == "__main__": - main() diff --git a/egs/librispeech_100h/rnnt/local/spm_train.py b/egs/librispeech_100h/rnnt/local/spm_train.py deleted file mode 100755 index 134a0b1d3..000000000 --- a/egs/librispeech_100h/rnnt/local/spm_train.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Facebook, Inc. and its affiliates. -# All rights reserved. -# -# This source code is licensed under the license found in the -# https://github.com/pytorch/fairseq/blob/master/LICENSE -import sys - -import sentencepiece as spm - -if __name__ == "__main__": - spm.SentencePieceTrainer.Train(" ".join(sys.argv[1:])) diff --git a/egs/librispeech_100h/rnnt/path.sh b/egs/librispeech_100h/rnnt/path.sh deleted file mode 100644 index 7972642d0..000000000 --- a/egs/librispeech_100h/rnnt/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/librispeech_100h/rnnt/run.sh b/egs/librispeech_100h/rnnt/run.sh deleted file mode 100755 index ad6a4d42d..000000000 --- a/egs/librispeech_100h/rnnt/run.sh +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1" -gpu_num=2 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="" #feature output dictionary -exp_dir="" -lang=en -token_type=bpe -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -sample_frequency=16000 -stage=0 -stop_stage=4 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data= -data_url=www.openslr.org/resources/12 - -# bpe model -nbpe=5000 -bpemode=unigram - -# exp tag -tag="exp2" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -train_set=train_clean_100 -valid_set=dev -test_sets="test_clean test_other dev_clean dev_other" - -asr_config=conf/train_conformer_rnnt.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_rnnt_conformer.yaml -#inference_config=conf/decode_asr_transformer_beam60_ctc0.3.yaml -inference_asr_model=valid.cer_transducer.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "stage -1: Data Download" - for part in dev-clean test-clean dev-other test-other train-clean-100; do - local/download_and_untar.sh ${raw_data} ${data_url} ${part} - done -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - for x in dev-clean dev-other test-clean test-other train-clean-100; do - local/data_prep.sh ${raw_data}/LibriSpeech/${x} ${feats_dir}/data/${x//-/_} - done - mkdir $feats_dir/data/$valid_set - dev_sets="dev_clean dev_other" - for file in wav.scp text; do - ( for f in $dev_sets; do cat $feats_dir/data/$f/$file; done ) | sort -k1 > $feats_dir/data/$valid_set/$file || exit 1; - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} ${feats_dir}/data/${train_set} -fi - -token_list=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe}_units.txt -bpemodel=${feats_dir}/data/lang_char/${train_set}_${bpemode}${nbpe} -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - ### Task dependent. You have to check non-linguistic symbols used in the corpus. - echo "stage 2: Dictionary and Json Data Preparation" - mkdir -p ${feats_dir}/data/lang_char/ - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - cut -f 2- -d" " ${feats_dir}/data/${train_set}/text > ${feats_dir}/data/lang_char/input.txt - local/spm_train.py --input=${feats_dir}/data/lang_char/input.txt --vocab_size=${nbpe} --model_type=${bpemode} --model_prefix=${bpemodel} --input_sentence_size=100000000 - local/spm_encode.py --model=${bpemodel}.model --output_format=piece < ${feats_dir}/data/lang_char/input.txt | tr ' ' '\n' | sort | uniq | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=./ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --split_with_space false \ - --bpemodel ${bpemodel}.model \ - --token_type $token_type \ - --token_list $token_list \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/cmvn.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --multiprocessing_distributed true \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - if [ -d ${_dir} ]; then - echo "${_dir} is already exists. if you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/cmvn.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode rnnt \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/compute_wer.py ${_data}/text ${_dir}/text ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi diff --git a/egs/librispeech_100h/rnnt/utils b/egs/librispeech_100h/rnnt/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/librispeech_100h/rnnt/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs/wenetspeech/conformer/conf/decode_asr_transformer_5beam.yaml b/egs/wenetspeech/conformer/conf/decode_asr_transformer_5beam.yaml deleted file mode 100644 index e35e8202a..000000000 --- a/egs/wenetspeech/conformer/conf/decode_asr_transformer_5beam.yaml +++ /dev/null @@ -1,6 +0,0 @@ -beam_size: 5 -penalty: 0.0 -maxlenratio: 0.0 -minlenratio: 0.0 -ctc_weight: 0.5 -lm_weight: 0.7 diff --git a/egs/wenetspeech/conformer/conf/train_asr_conformer.yaml b/egs/wenetspeech/conformer/conf/train_asr_conformer.yaml deleted file mode 100644 index a9658b8eb..000000000 --- a/egs/wenetspeech/conformer/conf/train_asr_conformer.yaml +++ /dev/null @@ -1,104 +0,0 @@ -# network architecture -# encoder related -encoder: conformer -encoder_conf: - output_size: 512 # dimension of attention - attention_heads: 8 - linear_units: 2048 # the number of units of position-wise feed forward - num_blocks: 12 # the number of encoder blocks - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - attention_dropout_rate: 0.0 - input_layer: conv2d # encoder architecture type - normalize_before: true - rel_pos_type: latest - pos_enc_layer_type: rel_pos - selfattention_layer_type: rel_selfattn - activation_type: swish - macaron_style: true - use_cnn_module: true - cnn_module_kernel: 15 - -# decoder related -decoder: transformer -decoder_conf: - attention_heads: 8 - linear_units: 2048 - num_blocks: 6 - dropout_rate: 0.1 - positional_dropout_rate: 0.1 - self_attention_dropout_rate: 0.0 - src_attention_dropout_rate: 0.0 - -# CTC realted -ctc_conf: - ignore_nan_grad: true - -# frontend related -frontend: wav_frontend -frontend_conf: - fs: 16000 - window: hamming - n_mels: 80 - frame_length: 25 - frame_shift: 10 - lfr_m: 1 - lfr_n: 1 - -# hybrid CTC/attention -model_conf: - ctc_weight: 0.3 - lsm_weight: 0.1 # label smoothing option - length_normalized_loss: false - -# optimization related -accum_grad: 4 -grad_clip: 5 -patience: none -max_epoch: 30 -val_scheduler_criterion: - - valid - - acc -best_model_criterion: -- - valid - - acc - - max -keep_nbest_models: 10 - -optim: adam -optim_conf: - lr: 0.0015 -scheduler: warmuplr -scheduler_conf: - warmup_steps: 30000 - -specaug: specaug -specaug_conf: - apply_time_warp: true - time_warp_window: 5 - time_warp_mode: bicubic - apply_freq_mask: true - freq_mask_width_range: - - 0 - - 30 - num_freq_mask: 2 - apply_time_mask: true - time_mask_width_range: - - 0 - - 40 - num_time_mask: 2 - -dataset_conf: - data_names: speech,text - data_types: sound,text_nospace - shuffle: True - shuffle_conf: - shuffle_size: 2048 - sort_size: 500 - batch_conf: - batch_type: token - batch_size: 32000 - num_workers: 8 - -log_interval: 50 -normalize: None diff --git a/egs/wenetspeech/conformer/local/data.sh b/egs/wenetspeech/conformer/local/data.sh deleted file mode 100755 index 2b0a4be15..000000000 --- a/egs/wenetspeech/conformer/local/data.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bash -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -log() { - local fname=${BASH_SOURCE[1]##*/} - echo -e "$(date '+%Y-%m-%dT%H:%M:%S') (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $*" -} -SECONDS=0 - -# general configuration -nj=10 -stage=2 -stop_stage=100 -set=L -data_dir="data" -WENETSPEECH= -train_cmd= - -log "$0 $*" -. utils/parse_options.sh - -if [ ! -d "${WENETSPEECH}/audio" ] && [ ! -f "${WENETSPEECH}/WenetSpeech.json" ]; then - echo "Valid WENETSPEECH data not found in ${WENETSPEECH}." - echo "Please follow the instruction in https://wenet-e2e.github.io/WenetSpeech/" - echo "and re-construct the data." - exit 1 -fi - -train_set=train_"$(echo "${set}" | tr "[:upper:]" "[:lower:]")" -dev_set=dev -test_sets="test_net test_meeting" - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - log "data preparation" - mkdir -p ${data_dir} - abs_data_dir=$(readlink -f ${data_dir}) - log "making Kaldi format data directory in ${abs_data_dir}" - local/wenetspeech_data_prep.sh \ - --train-subset ${set} \ - --stage 1 \ - ${WENETSPEECH} \ - ${abs_data_dir} - - # prepare utt2spk and spk2utt files - for x in ${train_set} ${dev_set} ${test_sets}; do - dir=${data_dir}/${x} - paste -d " " <(cut -f 1 ${dir}/segments) <(cut -f 1 ${dir}/segments) | \ - sort -u > ${dir}/utt2spk - utils/utt2spk_to_spk2utt.pl ${dir}/utt2spk > ${dir}/spk2utt - done -fi - -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - log "process the long term opus audio file, may take about 3 hours" - for x in ${train_set} ${dev_set} ${test_sets}; do - log "process audio for ${data_dir}/${x}" - dir=${data_dir}/${x} - mkdir -p ${dir}/logs - - nutt=$(<${dir}/segments wc -l) - nj=$((nj ${dir}/wav.scp - done -fi - -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - log "format text file" - for x in ${train_set} ${dev_set} ${test_sets}; do - log "format text for ${data_dir}/${x}" - dir=${data_dir}/${x} - mv ${dir}/text ${dir}/text.org - paste -d " " <(cut -f 1 ${dir}/text.org) \ - <(cut -f 2- ${dir}/text.org | local/text_normalize.pl) | \ - sort -u > ${dir}/text - utils/fix_data_dir.sh ${dir} - done -fi - -log "Successfully finished. [elapsed=${SECONDS}s]" diff --git a/egs/wenetspeech/conformer/local/extract_meta.py b/egs/wenetspeech/conformer/local/extract_meta.py deleted file mode 100755 index 607416203..000000000 --- a/egs/wenetspeech/conformer/local/extract_meta.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2021 Xiaomi Corporation (Author: Yongqing Wang) -# Mobvoi Inc(Author: Di Wu, Binbin Zhang) - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -import json -import os -import sys - - -def get_args(): - parser = argparse.ArgumentParser( - description=""" - This script is used to process raw json dataset of WenetSpeech, - where the long wav is splitinto segments and - data of wenet format is generated. - """ - ) - parser.add_argument("input_json", help="""Input json file of WenetSpeech""") - parser.add_argument("output_dir", help="""Output dir for prepared data""") - - args = parser.parse_args() - return args - - -def meta_analysis(input_json, output_dir): - input_dir = os.path.dirname(input_json) - - if not os.path.exists(output_dir): - os.makedirs(output_dir) - - try: - with open(input_json, "r") as injson: - json_data = json.load(injson) - except Exception: - sys.exit(f"Failed to load input json file: {input_json}") - else: - if json_data["audios"] is not None: - with open(f"{output_dir}/text", "w") as utt2text, open( - f"{output_dir}/segments", "w" - ) as segments, open(f"{output_dir}/utt2dur", "w") as utt2dur, open( - f"{output_dir}/wav.scp", "w" - ) as wavscp, open( - f"{output_dir}/utt2subsets", "w" - ) as utt2subsets, open( - f"{output_dir}/reco2dur", "w" - ) as reco2dur: - for long_audio in json_data["audios"]: - try: - long_audio_path = os.path.realpath( - os.path.join(input_dir, long_audio["path"]) - ) - aid = long_audio["aid"] - segments_lists = long_audio["segments"] - duration = long_audio["duration"] - assert os.path.exists(long_audio_path) - except AssertionError: - print( - f"""Warning: {aid} something is wrong, - maybe AssertionError, skipped""" - ) - continue - except Exception: - print( - f"""Warning: {aid} something is wrong, maybe the - error path: {long_audio_path}, skipped""" - ) - continue - else: - wavscp.write(f"{aid}\t{long_audio_path}\n") - reco2dur.write(f"{aid}\t{duration}\n") - for segment_file in segments_lists: - try: - sid = segment_file["sid"] - start_time = segment_file["begin_time"] - end_time = segment_file["end_time"] - dur = end_time - start_time - text = segment_file["text"] - segment_subsets = segment_file["subsets"] - except Exception: - print( - f"""Warning: {segment_file} something - is wrong, skipped""" - ) - continue - else: - utt2text.write(f"{sid}\t{text}\n") - segments.write( - f"{sid}\t{aid}\t{start_time}\t{end_time}\n" - ) - utt2dur.write(f"{sid}\t{dur}\n") - segment_sub_names = " ".join(segment_subsets) - utt2subsets.write(f"{sid}\t{segment_sub_names}\n") - - -def main(): - args = get_args() - - meta_analysis(args.input_json, args.output_dir) - - -if __name__ == "__main__": - main() diff --git a/egs/wenetspeech/conformer/local/process_opus.py b/egs/wenetspeech/conformer/local/process_opus.py deleted file mode 100755 index 581953fc3..000000000 --- a/egs/wenetspeech/conformer/local/process_opus.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2021 NPU, ASLP Group (Author: Qijie Shao) - -# 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. - -# process_opus.py: segmentation and downsampling of opus audio - -# usage: python3 process_opus.py wav.scp segments output_wav.scp - -import os -import sys - -import torchaudio - - -def read_file(wav_scp, segments): - wav_scp_dict = {} - with open(wav_scp, "r", encoding="UTF-8") as fin: - for line_str in fin: - wav_id, path = line_str.strip().split() - wav_scp_dict[wav_id] = path - - utt_list = [] - seg_path_list = [] - start_time_list = [] - end_time_list = [] - with open(segments, "r", encoding="UTF-8") as fin: - for line_str in fin: - arr = line_str.strip().split() - assert len(arr) == 4 - utt_list.append(arr[0]) - seg_path_list.append(wav_scp_dict[arr[1]]) - start_time_list.append(float(arr[2])) - end_time_list.append(float(arr[3])) - return utt_list, seg_path_list, start_time_list, end_time_list - - -# TODO(Qijie): Fix the process logic -def output(output_wav_scp, utt_list, seg_path_list, start_time_list, end_time_list): - num_utts = len(utt_list) - step = int(num_utts * 0.01) - with open(output_wav_scp, "w", encoding="UTF-8") as fout: - previous_wav_path = "" - for i in range(num_utts): - utt_id = utt_list[i] - current_wav_path = seg_path_list[i] - output_dir = (os.path.dirname(current_wav_path)).replace( - "audio", "audio_seg" - ) - seg_wav_path = os.path.join(output_dir, utt_id + ".wav") - - os.makedirs(output_dir, exist_ok=True) - if current_wav_path != previous_wav_path: - waveform, sample_rate = torchaudio.load(current_wav_path) - previous_wav_path = current_wav_path - - start = int(start_time_list[i] * sample_rate) - end = int(end_time_list[i] * sample_rate) - target_audio = waveform[:, start:end] - torchaudio.save(seg_wav_path, target_audio, sample_rate) - - fout.write("{} {}\n".format(utt_id, seg_wav_path)) - if i % step == 0: - print("seg wav finished: {}%".format(int(i / step))) - - -def main(): - wav_scp = sys.argv[1] - segments = sys.argv[2] - output_wav_scp = sys.argv[3] - - utt_list, seg_path_list, start_time_list, end_time_list = read_file( - wav_scp, segments - ) - output(output_wav_scp, utt_list, seg_path_list, start_time_list, end_time_list) - - -if __name__ == "__main__": - main() diff --git a/egs/wenetspeech/conformer/local/text_normalize.pl b/egs/wenetspeech/conformer/local/text_normalize.pl deleted file mode 100755 index 55b35e210..000000000 --- a/egs/wenetspeech/conformer/local/text_normalize.pl +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env perl -use utf8; -use open qw(:std :utf8); -use warnings; - -while () { - chomp; - # remove non UTF-8 whitespace character - if ($_ =~ / /) {$_ =~ s: ::g;} - if ($_ =~ / /) {$_ =~ s: ::g;} - # upper letters - if ($_ =~ /[a-zA-Z]/) {$_ =~ uc $_;} - # add "_" before and after each English word - if ($_ =~ /([A-Z]+)\s+([A-Z]+)/) {$_ =~ s/([A-Z]+)\s+([A-Z]+)/$1\_$2/g;} - if ($_ =~ /([A-Z]+)\s+([A-Z]+)/) {$_ =~ s/([A-Z]+)\s+([A-Z]+)/$1\_$2/g;} - if ($_ =~ m/([A-Z]+)(\p{Han}+)/) {$_ =~ s/([A-Z]+)(\p{Han}+)/$1\_$2/g;} - if ($_ =~ m/(\p{Han}+)([A-Z]+)/) {$_ =~ s/(\p{Han}+)([A-Z]+)/$1\_$2/g;} - # remove UTF-8 whitespace charcter - if ($_ =~ /\s+/) {$_ =~ s:\s+::g;} - # replace "_" with a normal whitespace - if ($_ =~ /\_/) {$_ =~ s:\_: :g;} - - print "$_\n"; -} diff --git a/egs/wenetspeech/conformer/local/wenetspeech_data_prep.sh b/egs/wenetspeech/conformer/local/wenetspeech_data_prep.sh deleted file mode 100755 index 4959328b8..000000000 --- a/egs/wenetspeech/conformer/local/wenetspeech_data_prep.sh +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2021 Xiaomi Corporation (Author: Yongqing Wang) -# Seasalt AI, Inc (Author: Guoguo Chen) -# Mobvoi Inc(Author: Di Wu, Binbin Zhang) -# NPU, ASLP Group (Author: Qijie Shao) - -# 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. - -set -e -set -o pipefail - -stage=1 -prefix= -train_subset=L - -. utils/parse_options.sh || exit 1; - -filter_by_id () { - idlist=$1 - input=$2 - output=$3 - field=1 - if [ $# -eq 4 ]; then - field=$4 - fi - cat $input | perl -se ' - open(F, "<$idlist") || die "Could not open id-list file $idlist"; - while() { - @A = split; - @A>=1 || die "Invalid id-list file line $_"; - $seen{$A[0]} = 1; - } - while(<>) { - @A = split; - @A > 0 || die "Invalid file line $_"; - @A >= $field || die "Invalid file line $_"; - if ($seen{$A[$field-1]}) { - print $_; - } - }' -- -idlist="$idlist" -field="$field" > $output ||\ - (echo "$0: filter_by_id() error: $input" && exit 1) || exit 1; -} - -subset_data_dir () { - utt_list=$1 - src_dir=$2 - dest_dir=$3 - mkdir -p $dest_dir || exit 1; - # wav.scp text segments utt2dur - filter_by_id $utt_list $src_dir/utt2dur $dest_dir/utt2dur ||\ - (echo "$0: subset_data_dir() error: $src_dir/utt2dur" && exit 1) || exit 1; - filter_by_id $utt_list $src_dir/text $dest_dir/text ||\ - (echo "$0: subset_data_dir() error: $src_dir/text" && exit 1) || exit 1; - filter_by_id $utt_list $src_dir/segments $dest_dir/segments ||\ - (echo "$0: subset_data_dir() error: $src_dir/segments" && exit 1) || exit 1; - awk '{print $2}' $dest_dir/segments | sort | uniq > $dest_dir/reco - filter_by_id $dest_dir/reco $src_dir/wav.scp $dest_dir/wav.scp ||\ - (echo "$0: subset_data_dir() error: $src_dir/wav.scp" && exit 1) || exit 1; - rm -f $dest_dir/reco -} - -if [ $# -ne 2 ]; then - echo "Usage: $0 [options] " - echo " e.g.: $0 --train-subset L /disk1/audio_data/wenetspeech/ data/" - echo "" - echo "This script takes the WenetSpeech source directory, and prepares the" - echo "WeNet format data directory." - echo " --prefix # Prefix for output data directory." - echo " --stage # Processing stage." - echo " --train-subset # Train subset to be created." - exit 1 -fi - -wenetspeech_dir=$1 -data_dir=$2 - -declare -A subsets -subsets=( - [L]="train_l" - [M]="train_m" - [S]="train_s" - [W]="train_w" - [DEV]="dev" - [TEST_NET]="test_net" - [TEST_MEETING]="test_meeting") - -prefix=${prefix:+${prefix}_} - -corpus_dir=$data_dir/${prefix}corpus/ -if [ $stage -le 1 ]; then - echo "$0: Extract meta into $corpus_dir" - # Sanity check. - [ ! -f $wenetspeech_dir/WenetSpeech.json ] &&\ - echo "$0: Please download $wenetspeech_dir/WenetSpeech.json!" && exit 1; - [ ! -d $wenetspeech_dir/audio ] &&\ - echo "$0: Please download $wenetspeech_dir/audio!" && exit 1; - - [ ! -d $corpus_dir ] && mkdir -p $corpus_dir - - # Files to be created: - # wav.scp text segments utt2dur - python3 local/extract_meta.py \ - $wenetspeech_dir/WenetSpeech.json $corpus_dir || exit 1; -fi - -if [ $stage -le 2 ]; then - echo "$0: Split data to train, dev, test_net, and test_meeting" - [ ! -f $corpus_dir/utt2subsets ] &&\ - echo "$0: No such file $corpus_dir/utt2subsets!" && exit 1; - for label in $train_subset DEV TEST_NET TEST_MEETING; do - if [ ! ${subsets[$label]+set} ]; then - echo "$0: Subset $label is not defined in WenetSpeech.json." && exit 1; - fi - subset=${subsets[$label]} - [ ! -d $data_dir/${prefix}$subset ] && mkdir -p $data_dir/${prefix}$subset - cat $corpus_dir/utt2subsets | \ - awk -v s=$label '{for (i=2;i<=NF;i++) if($i==s) print $0;}' \ - > $corpus_dir/${prefix}${subset}_utt_list|| exit 1; - subset_data_dir $corpus_dir/${prefix}${subset}_utt_list \ - $corpus_dir $data_dir/${prefix}$subset || exit 1; - done -fi - -echo "$0: Done" diff --git a/egs/wenetspeech/conformer/path.sh b/egs/wenetspeech/conformer/path.sh deleted file mode 100755 index 7972642d0..000000000 --- a/egs/wenetspeech/conformer/path.sh +++ /dev/null @@ -1,5 +0,0 @@ -export FUNASR_DIR=$PWD/../../.. - -# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C -export PYTHONIOENCODING=UTF-8 -export PATH=$FUNASR_DIR/funasr/bin:$PATH diff --git a/egs/wenetspeech/conformer/run.sh b/egs/wenetspeech/conformer/run.sh deleted file mode 100644 index db1836132..000000000 --- a/egs/wenetspeech/conformer/run.sh +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/env bash - -. ./path.sh || exit 1; - -# machines configuration -CUDA_VISIBLE_DEVICES="0,1,2,3,4,5,6,7" -gpu_num=8 -count=1 -gpu_inference=true # Whether to perform gpu decoding, set false for cpu decoding -# for gpu decoding, inference_nj=ngpu*njob; for cpu decoding, inference_nj=njob -njob=5 -train_cmd=utils/run.pl -infer_cmd=utils/run.pl - -# general configuration -feats_dir="../DATA" #feature output dictionary -exp_dir="." -lang=zh -token_type=char -type=sound -scp=wav.scp -speed_perturb="0.9 1.0 1.1" -stage=3 -stop_stage=5 - -# feature configuration -feats_dim=80 -nj=64 - -# data -raw_data=/nfs/zhifu.gzf/wenetspeech_proc - -# exp tag -tag="exp1" - -. utils/parse_options.sh || exit 1; - -# Set bash to 'debug' mode, it will exit on : -# -e 'error', -u 'undefined variable', -o ... 'error in pipeline', -x 'print commands', -set -e -set -u -set -o pipefail - -set=L -train_set=train_l -valid_set=dev -test_sets="dev test_net test_meeting" - -asr_config=conf/train_asr_conformer.yaml -model_dir="baseline_$(basename "${asr_config}" .yaml)_${lang}_${token_type}_${tag}" - -inference_config=conf/decode_asr_transformer_5beam.yaml -inference_asr_model=valid.acc.ave_10best.pb - -# you can set gpu num for decoding here -gpuid_list=$CUDA_VISIBLE_DEVICES # set gpus for decoding, the same as training stage by default -ngpu=$(echo $gpuid_list | awk -F "," '{print NF}') - -if ${gpu_inference}; then - inference_nj=$[${ngpu}*${njob}] - _ngpu=1 -else - inference_nj=$njob - _ngpu=0 -fi - -if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then - echo "For downloading data, please refer to https://github.com/wenet-e2e/WenetSpeech." - exit 0; -fi - -if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then - echo "stage 0: Data preparation" - # Data preparation - local/data.sh --set ${set} --nj $nj --data_dir $feats_dir --WENETSPEECH $raw_data --train_cmd $train_cmd - mkdir $feats_dir/data - mv $feats_dir/$train_set $feats_dir/data/$train_set - for x in $test_sets; do - mv $feats_dir/$x $feats_dir/data/ - done -fi - -if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then - echo "stage 1: Feature and CMVN Generation" - utils/compute_cmvn.sh --fbankdir ${feats_dir}/data/${train_set} --cmd "$train_cmd" --nj $nj --feats_dim ${feats_dim} --config_file "$asr_config" --scale 0.1 -fi - -token_list=${feats_dir}/data/${lang}_token_list/$token_type/tokens.txt -echo "dictionary: ${token_list}" -if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then - echo "stage 2: Dictionary Preparation" - mkdir -p ${feats_dir}/data/${lang}_token_list/$token_type/ - - echo "make a dictionary" - echo "" > ${token_list} - echo "" >> ${token_list} - echo "" >> ${token_list} - utils/text2token.py -s 1 -n 1 --space "" ${feats_dir}/data/$train_set/text | cut -f 2- -d" " | tr " " "\n" \ - | sort | uniq | grep -a -v -e '^\s*$' | awk '{print $0}' >> ${token_list} - echo "" >> ${token_list} -fi - -# LM Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then - echo "stage 3: LM Training" -fi - -# ASR Training Stage -world_size=$gpu_num # run on one machine -if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then - echo "stage 4: ASR Training" - mkdir -p ${exp_dir}/exp/${model_dir} - mkdir -p ${exp_dir}/exp/${model_dir}/log - INIT_FILE=${exp_dir}/exp/${model_dir}/ddp_init - if [ -f $INIT_FILE ];then - rm -f $INIT_FILE - fi - init_method=file://$(readlink -f $INIT_FILE) - echo "$0: init method is $init_method" - for ((i = 0; i < $gpu_num; ++i)); do - { - rank=$i - local_rank=$i - gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1]) - train.py \ - --task_name asr \ - --gpu_id $gpu_id \ - --use_preprocessor true \ - --token_type $token_type \ - --token_list $token_list \ - --dataset_type large \ - --data_dir ${feats_dir}/data \ - --train_set ${train_set} \ - --valid_set ${valid_set} \ - --data_file_names "wav.scp,text" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --speed_perturb ${speed_perturb} \ - --resume true \ - --output_dir ${exp_dir}/exp/${model_dir} \ - --config $asr_config \ - --ngpu $gpu_num \ - --num_worker_count $count \ - --dist_init_method $init_method \ - --dist_world_size $world_size \ - --dist_rank $rank \ - --local_rank $local_rank 1> ${exp_dir}/exp/${model_dir}/log/train.log.$i 2>&1 - } & - done - wait -fi - -# Testing Stage -if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then - echo "stage 5: Inference" - for dset in ${test_sets}; do - asr_exp=${exp_dir}/exp/${model_dir} - inference_tag="$(basename "${inference_config}" .yaml)" - _dir="${asr_exp}/${inference_tag}/${inference_asr_model}/${dset}" - _logdir="${_dir}/logdir" - you want to decode again, please delete this dir first." - exit 0 - fi - mkdir -p "${_logdir}" - _data="${feats_dir}/data/${dset}" - key_file=${_data}/${scp} - num_scp_file="$(<${key_file} wc -l)" - _nj=$([ $inference_nj -le $num_scp_file ] && echo "$inference_nj" || echo "$num_scp_file") - split_scps= - for n in $(seq "${_nj}"); do - split_scps+=" ${_logdir}/keys.${n}.scp" - done - # shellcheck disable=SC2086 - utils/split_scp.pl "${key_file}" ${split_scps} - _opts= - if [ -n "${inference_config}" ]; then - _opts+="--config ${inference_config} " - fi - ${infer_cmd} --gpu "${_ngpu}" --max-jobs-run "${_nj}" JOB=1:"${_nj}" "${_logdir}"/asr_inference.JOB.log \ - python -m funasr.bin.asr_inference_launch \ - --batch_size 1 \ - --ngpu "${_ngpu}" \ - --njob ${njob} \ - --gpuid_list ${gpuid_list} \ - --data_path_and_name_and_type "${_data}/${scp},speech,${type}" \ - --cmvn_file ${feats_dir}/data/${train_set}/cmvn/am.mvn \ - --key_file "${_logdir}"/keys.JOB.scp \ - --asr_train_config "${asr_exp}"/config.yaml \ - --asr_model_file "${asr_exp}"/"${inference_asr_model}" \ - --output_dir "${_logdir}"/output.JOB \ - --mode asr \ - ${_opts} - - for f in token token_int score text; do - if [ -f "${_logdir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${_nj}"); do - cat "${_logdir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${_dir}/${f}" - fi - done - python utils/proce_text.py ${_dir}/text ${_dir}/text.proc - python utils/proce_text.py ${_data}/text ${_data}/text.proc - python utils/compute_wer.py ${_data}/text.proc ${_dir}/text.proc ${_dir}/text.cer - tail -n 3 ${_dir}/text.cer > ${_dir}/text.cer.txt - cat ${_dir}/text.cer.txt - done -fi - -# Prepare files for ModelScope fine-tuning and inference -if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then - echo "stage 6: ModelScope Preparation" - cp ${feats_dir}/data/${train_set}/cmvn/am.mvn ${exp_dir}/exp/${model_dir}/am.mvn - vocab_size=$(cat ${token_list} | wc -l) - python utils/gen_modelscope_configuration.py \ - --am_model_name $inference_asr_model \ - --mode asr \ - --model_name conformer \ - --dataset wenetspeech \ - --output_dir $exp_dir/exp/$model_dir \ - --vocab_size $vocab_size \ - --tag $tag -fi \ No newline at end of file diff --git a/egs/wenetspeech/conformer/utils b/egs/wenetspeech/conformer/utils deleted file mode 120000 index fe070dd3a..000000000 --- a/egs/wenetspeech/conformer/utils +++ /dev/null @@ -1 +0,0 @@ -../../aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/TEMPLATE/README.md b/egs_modelscope/asr/TEMPLATE/README.md deleted file mode 100644 index bf6d30b7a..000000000 --- a/egs_modelscope/asr/TEMPLATE/README.md +++ /dev/null @@ -1,359 +0,0 @@ -([简体中文](./README_zh.md)|English) - -# Speech Recognition - -> **Note**: -> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetine. Here we take the typic models as examples to demonstrate the usage. - -## Inference - -### Quick start -#### [Paraformer Model](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch', -) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') -print(rec_result) -``` -#### [Paraformer-long Model](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch', - vad_model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - #punc_model='damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch', - punc_model='damo/punc_ct-transformer_cn-en-common-vocab471067-large', -) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/vad_example.wav', - batch_size_token=5000, batch_size_token_threshold_s=40, max_single_segment_time=6000) -print(rec_result) -``` - -Where, -- `batch_size_token` refs to dynamic batch_size and the total tokens of batch is `batch_size_token`, 1 token = 60 ms. -- `batch_size_token_threshold_s`: The batch_size is set to 1, when the audio duration exceeds the threshold value of `batch_size_token_threshold_s`, specified in `s`. -- `max_single_segment_time`: The maximum length for audio segmentation in VAD, specified in `ms`. - -Suggestion: When encountering OOM (Out of Memory) issues with long audio inputs, as the GPU memory usage increases with the square of the audio duration, there are three possible scenarios: -- a) In the initial inference stage, GPU memory usage primarily depends on `batch_size_token`. Reducing this value appropriately can help reduce memory usage. -- b) In the middle of the inference process, when encountering long audio segments segmented by VAD, if the total number of tokens is still smaller than `batch_size_token` but OOM issues persist, reducing `batch_size_token_threshold_s` can help. If the threshold is exceeded, forcing the batch size to 1 can be considered. -- c) Towards the end of the inference process, when encountering long audio segments segmented by VAD and the total number of tokens is smaller than `batch_size_token` but exceeds the threshold `batch_size_token_threshold_s`, forcing the batch size to 1 may still result in OOM errors. In such cases, reducing `max_single_segment_time` can be considered to shorten the duration of audio segments generated by VAD. - -#### [Paraformer-online Model](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/summary) -##### Streaming Decoding -```python -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online', - model_revision='v1.0.7', - update_model=False, - mode='paraformer_streaming' - ) -import soundfile -speech, sample_rate = soundfile.read("example/asr_example.wav") - -chunk_size = [0, 10, 5] #[0, 10, 5] 600ms, [0, 8, 4] 480ms -encoder_chunk_look_back = 4 #number of chunks to lookback for encoder self-attention -decoder_chunk_look_back = 1 #number of encoder chunks to lookback for decoder cross-attention -param_dict = {"cache": dict(), "is_final": False, "chunk_size": chunk_size, - "encoder_chunk_look_back": encoder_chunk_look_back, "decoder_chunk_look_back": decoder_chunk_look_back} -chunk_stride = chunk_size[1] * 960 # 600ms、480ms -# first chunk, 600ms -speech_chunk = speech[0:chunk_stride] -rec_result = inference_pipeline(audio_in=speech_chunk, param_dict=param_dict) -print(rec_result) -# next chunk, 600ms -speech_chunk = speech[chunk_stride:chunk_stride+chunk_stride] -rec_result = inference_pipeline(audio_in=speech_chunk, param_dict=param_dict) -print(rec_result) -``` - -##### Fake Streaming Decoding -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online', - model_revision='v1.0.7', - update_model=False, - mode="paraformer_fake_streaming" -) -audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' -rec_result = inference_pipeline(audio_in=audio_in) -print(rec_result) -``` -Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/241) - -#### [Paraformer-contextual Model](https://www.modelscope.cn/models/damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -param_dict = dict() -# param_dict['hotword'] = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/hotword.txt" -param_dict['hotword']="邓郁松 王颖春 王晔君" -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404", - param_dict=param_dict) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_hotword.wav') -print(rec_result) -``` - -#### [UniASR Model](https://www.modelscope.cn/models/damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/summary) -There are three decoding mode for UniASR model(`fast`、`normal`、`offline`), for more model details, please refer to [docs](https://www.modelscope.cn/models/damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/summary) -```python -decoding_model = "fast" # "fast"、"normal"、"offline" -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825', - param_dict={"decoding_model": decoding_model}) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') -print(rec_result) -``` -The decoding mode of `fast` and `normal` is fake streaming, which could be used for evaluating of recognition accuracy. -Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/151) - -#### [Paraformer-Spk](https://modelscope.cn/models/damo/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/summary) -This model allows user to get recognition results which contain speaker info of each sentence. Refer to [CAM++](https://modelscope.cn/models/damo/speech_campplus_speaker-diarization_common/summary) for detailed information about speaker diarization model. -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_speaker_demo.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn', - model_revision='v0.0.2', - vad_model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - punc_model='damo/punc_ct-transformer_cn-en-common-vocab471067-large', - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, batch_size_token=5000, batch_size_token_threshold_s=40, max_single_segment_time=6000) - print(rec_result) -``` - -#### [RNN-T-online model]() -Undo - -#### [MFCCA Model](https://www.modelscope.cn/models/NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/summary) -For more model details, please refer to [docs](https://www.modelscope.cn/models/NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950', - model_revision='v3.0.0' -) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') -print(rec_result) -``` - -### API-reference -#### Define pipeline -- `task`: `Tasks.auto_speech_recognition` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU -- `ncpu`: `1` (Default), sets the number of threads used for intraop parallelism on CPU -- `output_dir`: `None` (Default), the output path of results if set -- `batch_size`: `1` (Default), batch size when decoding -#### Infer pipeline -- `audio_in`: the input to decode, which could be: - - wav_path, `e.g.`: asr_example.wav, - - pcm_path, `e.g.`: asr_example.pcm, - - audio bytes stream, `e.g.`: bytes data from a microphone - - audio sample point,`e.g.`: `audio, rate = soundfile.read("asr_example_zh.wav")`, the dtype is numpy.ndarray or torch.Tensor - - wav.scp, kaldi style wav list (`wav_id \t wav_path`), `e.g.`: - ```text - asr_example1 ./audios/asr_example1.wav - asr_example2 ./audios/asr_example2.wav - ``` - In this case of `wav.scp` input, `output_dir` must be set to save the output results -- `audio_fs`: audio sampling rate, only set when audio_in is pcm audio -- `output_dir`: None (Default), the output path of results if set - -### Inference with multi-thread CPUs or multi GPUs -FunASR also offer recipes [egs_modelscope/asr/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/asr/TEMPLATE/infer.sh) to decode with multi-thread CPUs, or multi GPUs. - -#### Settings of `infer.sh` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `data_dir`: the dataset dir needs to include `wav.scp`. If `${data_dir}/text` is also exists, CER will be computed -- `output_dir`: output dir of the recognition results -- `batch_size`: `64` (Default), batch size of inference on gpu -- `gpu_inference`: `true` (Default), whether to perform gpu decoding, set false for CPU inference -- `gpuid_list`: `0,1` (Default), which gpu_ids are used to infer -- `njob`: only used for CPU inference (`gpu_inference`=`false`), `64` (Default), the number of jobs for CPU decoding -- `checkpoint_dir`: only used for infer finetuned models, the path dir of finetuned models -- `checkpoint_name`: only used for infer finetuned models, `valid.cer_ctc.ave.pb` (Default), which checkpoint is used to infer -- `decoding_mode`: `normal` (Default), decoding mode for UniASR model(fast、normal、offline) -- `hotword_txt`: `None` (Default), hotword file for contextual paraformer model(the hotword file name ends with .txt") - -#### Decode with multi GPUs: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 64 \ - --gpu_inference true \ - --gpuid_list "0,1" -``` -#### Decode with multi-thread CPUs: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 64 -``` - -#### Results - -The decoding results can be found in `$output_dir/1best_recog/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. - -If you decode the SpeechIO test sets, you can use textnorm with `stage`=3, and `DETAILS.txt`, `RESULTS.txt` record the results and CER after text normalization. - - -## Finetune with pipeline - -### Quick start -[finetune.py](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/asr/TEMPLATE/finetune.py) -```python -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr, - mate_params=params.param_dict) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "speech_asr_aishell1_trainsets" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - init_param = [] # 初始模型路径,默认加载modelscope模型初始化,例如: ["checkpoint/20epoch.pb"] - freeze_param = [] # 模型参数freeze, 例如: ["encoder"] - ignore_init_mismatch = True # 是否忽略模型参数初始化不匹配 - use_lora = False # 是否使用lora进行模型微调 - params.param_dict = {"init_param":init_param, "freeze_param": freeze_param, "ignore_init_mismatch": ignore_init_mismatch} - if use_lora: - enable_lora = True - lora_bias = "all" - lora_params = {"lora_list":['q','v'], "lora_rank":8, "lora_alpha":16, "lora_dropout":0.1} - lora_config = {"enable_lora": enable_lora, "lora_bias": lora_bias, "lora_params": lora_params} - params.param_dict.update(lora_config) - - modelscope_finetune(params) -``` - -```shell -python finetune.py &> log.txt & -``` - -### Finetune with your data - -- Modify finetune training related parameters in [finetune.py](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/asr/TEMPLATE/finetune.py) - - `output_dir`: result dir - - `data_dir`: the dataset dir needs to include files: `train/wav.scp`, `train/text`; `validation/wav.scp`, `validation/text` - - `dataset_type`: for dataset larger than 1000 hours, set as `large`, otherwise set as `small` - - `batch_bins`: batch size. For dataset_type is `small`, `batch_bins` indicates the feature frames. For dataset_type is `large`, `batch_bins` indicates the duration in ms - - `max_epoch`: number of training epoch - - `lr`: learning rate - - `init_param`: `[]`(Default), init model path, load modelscope model initialization by default. For example: ["checkpoint/20epoch.pb"] - - `freeze_param`: `[]`(Default), Freeze model parameters. For example:["encoder"] - - `ignore_init_mismatch`: `True`(Default), Ignore size mismatch when loading pre-trained model - - `use_lora`: `False`(Default), Fine-tuning model use lora, more detail please refer to [LORA](https://arxiv.org/pdf/2106.09685.pdf) - -- Training data formats: -```sh -cat ./example_data/text -BAC009S0002W0122 而 对 楼 市 成 交 抑 制 作 用 最 大 的 限 购 -BAC009S0002W0123 也 成 为 地 方 政 府 的 眼 中 钉 -english_example_1 hello world -english_example_2 go swim 去 游 泳 - -cat ./example_data/wav.scp -BAC009S0002W0122 /mnt/data/wav/train/S0002/BAC009S0002W0122.wav -BAC009S0002W0123 /mnt/data/wav/train/S0002/BAC009S0002W0123.wav -english_example_1 /mnt/data/wav/train/S0002/english_example_1.wav -english_example_2 /mnt/data/wav/train/S0002/english_example_2.wav -``` - -- Then you can run the pipeline to finetune with: -```shell -python finetune.py -``` -If you want finetune with multi-GPUs, you could: -```shell -CUDA_VISIBLE_DEVICES=1,2 python -m torch.distributed.launch --nproc_per_node 2 finetune.py > log.txt 2>&1 -``` -## Inference with your finetuned model - -- Setting parameters in [egs_modelscope/asr/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/asr/TEMPLATE/infer.sh) is the same with [docs](https://github.com/alibaba-damo-academy/FunASR/tree/main/egs_modelscope/asr/TEMPLATE#inference-with-multi-thread-cpus-or-multi-gpus), `model` is the model name from modelscope, which you finetuned. - -- Decode with multi GPUs: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 64 \ - --gpu_inference true \ - --gpuid_list "0,1" \ - --checkpoint_dir "./checkpoint" \ - --checkpoint_name "valid.cer_ctc.ave.pb" -``` -- Decode with multi-thread CPUs: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 64 \ - --checkpoint_dir "./checkpoint" \ - --checkpoint_name "valid.cer_ctc.ave.pb" -``` diff --git a/egs_modelscope/asr/TEMPLATE/README_zh.md b/egs_modelscope/asr/TEMPLATE/README_zh.md deleted file mode 100644 index 583e63aba..000000000 --- a/egs_modelscope/asr/TEMPLATE/README_zh.md +++ /dev/null @@ -1,356 +0,0 @@ -(简体中文|[English](./README.md)) - -# 语音识别 - -> **注意**: -> pipeline 支持 [modelscope模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) 中的所有模型进行推理和微调。这里我们以典型模型作为示例来演示使用方法。 - -## 推理 - -### 快速使用 -#### [Paraformer 模型](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch', -) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') -print(rec_result) -``` -#### [Paraformer长音频模型](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch', - vad_model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - punc_model='damo/punc_ct-transformer_cn-en-common-vocab471067-large', -) - -rec_result = inference_pipeline(audio_in='./vad_example.wav') -print(rec_result) -``` -其中: -- `batch_size_token` 表示采用动态batch,batch中总token数为 `batch_size_token`,1 token = 60 ms. -- `batch_size_token_threshold_s`: 表示音频时长超过 `batch_size_token_threshold_s`阈值是,batch数设置为1, 单位为s. -- `max_single_segment_time`: 表示VAD最大切割音频时长, 单位是ms. - -建议:当您输入为长音频,遇到OOM问题时,因为显存占用与音频时长呈平方关系增加,分为3种情况: -- a)推理起始阶段,显存主要取决于`batch_size_token`,适当减小该值,可以减少显存占用; -- b)推理中间阶段,遇到VAD切割的长音频片段,总token数小于`batch_size_token`,仍然出现OOM,可以适当减小`batch_size_token_threshold_s`,超过阈值,强制batch为1; -- c)推理快结束阶段,遇到VAD切割的长音频片段,总token数小于`batch_size_token`,且超过阈值`batch_size_token_threshold_s`,强制batch为1,仍然出现OOM,可以适当减小`max_single_segment_time`,使得VAD切割音频时长变短。 - -#### [Paraformer-实时模型](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/summary) -##### 实时推理 -```python -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online', - model_revision='v1.0.7', - update_model=False, - mode='paraformer_streaming' - ) -import soundfile -speech, sample_rate = soundfile.read("example/asr_example.wav") - -chunk_size = [0, 10, 5] #[0, 10, 5] 600ms, [0, 8, 4] 480ms -encoder_chunk_look_back = 4 #number of chunks to lookback for encoder self-attention -decoder_chunk_look_back = 1 #number of encoder chunks to lookback for decoder cross-attention -param_dict = {"cache": dict(), "is_final": False, "chunk_size": chunk_size, - "encoder_chunk_look_back": encoder_chunk_look_back, "decoder_chunk_look_back": decoder_chunk_look_back} -chunk_stride = chunk_size[1] * 960 # 600ms、480ms -# first chunk, 600ms -speech_chunk = speech[0:chunk_stride] -rec_result = inference_pipeline(audio_in=speech_chunk, param_dict=param_dict) -print(rec_result) -# next chunk, 600ms -speech_chunk = speech[chunk_stride:chunk_stride+chunk_stride] -rec_result = inference_pipeline(audio_in=speech_chunk, param_dict=param_dict) -print(rec_result) -``` - -##### 伪实时推理 -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online', - model_revision='v1.0.7', - update_model=False, - mode="paraformer_fake_streaming" -) -audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' -rec_result = inference_pipeline(audio_in=audio_in) -print(rec_result) -``` -演示代码完整版本,请参考[demo](https://github.com/alibaba-damo-academy/FunASR/discussions/241) - -#### [Paraformer-contextual 热词模型](https://www.modelscope.cn/models/damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -param_dict = dict() -# param_dict['hotword'] = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/hotword.txt" -param_dict['hotword']="邓郁松 王颖春 王晔君" -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404", - param_dict=param_dict) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_hotword.wav') -print(rec_result) -``` - -#### [UniASR 模型](https://www.modelscope.cn/models/damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/summary) -UniASR 模型有三种解码模式(fast、normal、offline),更多模型细节请参考[文档](https://www.modelscope.cn/models/damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/summary) -```python -decoding_model = "fast" # "fast"、"normal"、"offline" -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825', - param_dict={"decoding_model": decoding_model}) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') -print(rec_result) -``` -fast 和 normal 的解码模式是假流式解码,可用于评估识别准确性。 -演示的完整代码,请参见 [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/151) - -#### [Paraformer-Spk model](https://modelscope.cn/models/damo/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/summary) -返回识别结果的同时返回每个子句的说话人分类结果。关于说话人日志模型的详情请见[CAM++](https://modelscope.cn/models/damo/speech_campplus_speaker-diarization_common/summary)。 - -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_speaker_demo.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn', - model_revision='v0.0.2', - vad_model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - punc_model='damo/punc_ct-transformer_cn-en-common-vocab471067-large', - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, batch_size_token=5000, batch_size_token_threshold_s=40, max_single_segment_time=6000) - print(rec_result) -``` - - -#### [RNN-T-online 模型]() -Undo - -#### [MFCCA 模型](https://www.modelscope.cn/models/NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/summary) - -更多模型细节请参考[文档](https://www.modelscope.cn/models/NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950', - model_revision='v3.0.0' -) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') -print(rec_result) -``` - -### API接口说明 -#### pipeline定义 -- `task`: `Tasks.auto_speech_recognition` -- `model`: [模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) 中的模型名称,或本地磁盘中的模型路径 -- `ngpu`: `1`(默认),使用 GPU 进行推理。如果 ngpu=0,则使用 CPU 进行推理 -- `ncpu`: `1` (默认),设置用于 CPU 内部操作并行性的线程数 -- `output_dir`: `None` (默认),如果设置,输出结果的输出路径 -- `batch_size`: `1` (默认),解码时的批处理大小 -#### pipeline 推理 -- `audio_in`: 要解码的输入,可以是: - - wav文件路径, 例如: asr_example.wav, - - pcm文件路径, 例如: asr_example.pcm, - - 音频字节数流,例如:麦克风的字节数数据 - - 音频采样点,例如:`audio, rate = soundfile.read("asr_example_zh.wav")`, 数据类型为 numpy.ndarray 或者 torch.Tensor - - wav.scp,kaldi 样式的 wav 列表 (`wav_id \t wav_path`), 例如: - ```text - asr_example1 ./audios/asr_example1.wav - asr_example2 ./audios/asr_example2.wav - ``` - 在这种输入 `wav.scp` 的情况下,必须设置 `output_dir` 以保存输出结果 -- `audio_fs`: 音频采样率,仅在 audio_in 为 pcm 音频时设置 -- `output_dir`: None (默认),如果设置,输出结果的输出路径 - -### 使用多线程 CPU 或多个 GPU 进行推理 -FunASR 还提供了 [egs_modelscope/asr/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/asr/TEMPLATE/infer.sh) 脚本,以使用多线程 CPU 或多个 GPU 进行解码。 - -#### `infer.sh` 设置 -- `model`: [modelscope模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope)中的模型名称,或本地磁盘中的模型路径 -- `data_dir`: 数据集目录需要包括 `wav.scp` 文件。如果 `${data_dir}/text` 也存在,则将计算 CER -- `output_dir`: 识别结果的输出目录 -- `batch_size`: `64`(默认),在 GPU 上进行推理的批处理大小 -- `gpu_inference`: `true` (默认),是否执行 GPU 解码,如果进行 CPU 推理,则设置为 `false` -- `gpuid_list`: `0,1` (默认),用于推理的 GPU ID -- `njob`: 仅用于 CPU 推理(`gpu_inference=false`),`64`(默认),CPU 解码的作业数 -- `checkpoint_dir`: 仅用于推理微调模型,微调模型的路径目录 -- `checkpoint_name`: 仅用于推理微调模型,`valid.cer_ctc.ave.pb`(默认),用于推理的检查点 -- `decoding_mode`: `normal`(默认),UniASR 模型的解码模式(`fast`、`normal`、`offline`) -- `hotword_txt`: `None` (默认),上下文语料库模型的热词文件(热词文件名以 .txt 结尾) - -#### 使用多个 GPU 进行解码: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 64 \ - --gpu_inference true \ - --gpuid_list "0,1" -``` -#### 使用多线程 CPU 进行解码: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 64 -``` - -#### 推理结果 -解码结果可以在 `$output_dir/1best_recog/text.cer` 中找到,其中包括每个样本的识别结果和整个测试集的 CER 指标。 -如果您对 SpeechIO 测试集进行解码,则可以使用 `stage=3` 的 textnorm,`DETAILS.txt` 和 `RESULTS.txt` 记录了文本标准化后的结果和 CER。 - -## 使用pipeline进行微调 - -### 快速上手 -[finetune.py](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/asr/TEMPLATE/finetune.py) -```python -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr, - mate_params=params.param_dict) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "speech_asr_aishell1_trainsets" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - init_param = [] # 初始模型路径,默认加载modelscope模型初始化,例如: ["checkpoint/20epoch.pb"] - freeze_param = [] # 模型参数freeze, 例如: ["encoder"] - ignore_init_mismatch = True # 是否忽略模型参数初始化不匹配 - use_lora = False # 是否使用lora进行模型微调 - params.param_dict = {"init_param":init_param, "freeze_param": freeze_param, "ignore_init_mismatch": ignore_init_mismatch} - if use_lora: - enable_lora = True - lora_bias = "all" - lora_params = {"lora_list":['q','v'], "lora_rank":8, "lora_alpha":16, "lora_dropout":0.1} - lora_config = {"enable_lora": enable_lora, "lora_bias": lora_bias, "lora_params": lora_params} - params.param_dict.update(lora_config) - - modelscope_finetune(params) -``` - -```shell -python finetune.py &> log.txt & -``` - -### 使用私有数据进行微调 - -- 修改 [finetune.py](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/asr/TEMPLATE/finetune.py) 中微调训练相关参数 - - `output_dir`: 微调模型保存路径 - - `data_dir`: 数据集目录需要包括以下文件:`train/wav.scp`, `train/text`; `validation/wav.scp`, `validation/text` - - `dataset_type`: 对于大于 1000 小时的数据集,设置为 `large`,否则设置为 `small` - - `batch_bins`: 批处理大小。对于 `dataset_type` 为 `small`,`batch_bins` 表示特征帧数。对于 `dataset_type` 为 `large`,`batch_bins` 表示以毫秒为单位的持续时间 - - `max_epoch`: 最大训练 epoch 数量 - - `lr`: 学习率 - - `init_param`: `[]`(默认值),初始化模型路径,按默认设置加载 modelscope 模型初始化。例如:["checkpoint/20epoch.pb"] - - `freeze_param`: `[]`(默认值),冻结模型参数。例如:["encoder"] - - `ignore_init_mismatch`: `True`(默认值),在加载预训练模型时忽略大小不匹配 - - `use_lora`: `False`(默认值),微调模型使用 LORA,请参阅 [LORA论文](https://arxiv.org/pdf/2106.09685.pdf) - -- 训练数据格式 -```sh -cat ./example_data/text -BAC009S0002W0122 而 对 楼 市 成 交 抑 制 作 用 最 大 的 限 购 -BAC009S0002W0123 也 成 为 地 方 政 府 的 眼 中 钉 -english_example_1 hello world -english_example_2 go swim 去 游 泳 - -cat ./example_data/wav.scp -BAC009S0002W0122 /mnt/data/wav/train/S0002/BAC009S0002W0122.wav -BAC009S0002W0123 /mnt/data/wav/train/S0002/BAC009S0002W0123.wav -english_example_1 /mnt/data/wav/train/S0002/english_example_1.wav -english_example_2 /mnt/data/wav/train/S0002/english_example_2.wav -``` - -- 然后,您可以使用以下命令运行pipeline进行微调: -```shell -python finetune.py -``` -如果您想使用多个 GPU 进行微调,可以使用以下命令: -```shell -CUDA_VISIBLE_DEVICES=1,2 python -m torch.distributed.launch --nproc_per_node 2 finetune.py > log.txt 2>&1 -``` -## 使用微调模型进行推理 - -[egs_modelscope/asr/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/asr/TEMPLATE/infer.sh) 参数设置与上面`infer.sh`相同 - -- 使用多个 GPU 进行解码: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 64 \ - --gpu_inference true \ - --gpuid_list "0,1" \ - --checkpoint_dir "./checkpoint" \ - --checkpoint_name "valid.cer_ctc.ave.pb" -``` -- 使用多线程 CPU 进行解码: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 64 \ - --checkpoint_dir "./checkpoint" \ - --checkpoint_name "valid.cer_ctc.ave.pb" -``` diff --git a/egs_modelscope/asr/TEMPLATE/finetune.py b/egs_modelscope/asr/TEMPLATE/finetune.py deleted file mode 100644 index 1935258b6..000000000 --- a/egs_modelscope/asr/TEMPLATE/finetune.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/TEMPLATE/infer.py b/egs_modelscope/asr/TEMPLATE/infer.py deleted file mode 100644 index f5caf0f3a..000000000 --- a/egs_modelscope/asr/TEMPLATE/infer.py +++ /dev/null @@ -1,29 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=args.model, - output_dir=args.output_dir, - batch_size=args.batch_size, - update_model=False, - param_dict={"decoding_model": args.decoding_mode, "hotword": args.hotword_txt} - ) - inference_pipeline(audio_in=args.audio_in) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch") - parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--decoding_mode', type=str, default="normal") - parser.add_argument('--hotword_txt', type=str, default=None) - parser.add_argument('--batch_size', type=int, default=64) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/asr/TEMPLATE/infer.sh b/egs_modelscope/asr/TEMPLATE/infer.sh deleted file mode 100644 index ef49d7a60..000000000 --- a/egs_modelscope/asr/TEMPLATE/infer.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/TEMPLATE/utils b/egs_modelscope/asr/TEMPLATE/utils deleted file mode 120000 index dc7d4171f..000000000 --- a/egs_modelscope/asr/TEMPLATE/utils +++ /dev/null @@ -1 +0,0 @@ -../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/demo.py b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/demo.py deleted file mode 100644 index ddcae969a..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/demo.py +++ /dev/null @@ -1,14 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in) - print(rec_result) - diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/finetune.py b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/finetune.py deleted file mode 100644 index 6b221c441..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision=params.model_revision, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - from funasr.utils.modelscope_param import modelscope_args - params = modelscope_args(model="damo/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 25000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh deleted file mode 120000 index 5e59f1841..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/demo.py b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/demo.py deleted file mode 100644 index 3b0164a46..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/demo.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://modelscope.oss-cn-beijing.aliyuncs.com/test/audios/asr_example.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in) - print(rec_result) diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/finetune.py b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/finetune.py deleted file mode 100644 index 793204563..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/finetune.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch", - data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 25000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.0005 # 设置学习率 - modelscope_finetune(params) diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh b/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh deleted file mode 120000 index 5e59f1841..000000000 --- a/egs_modelscope/asr/conformer/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/README.md b/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/README.md deleted file mode 100644 index 053986d3d..000000000 --- a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained Paraformer-large Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: `train/wav.scp`, `train/text`; `validation/wav.scp`, `validation/text` - - dataset_type: # for dataset larger than 1000 hours, set as `large`, otherwise set as `small` - - batch_bins: # batch size. For dataset_type is `small`, `batch_bins` indicates the feature frames. For dataset_type is `large`, `batch_bins` indicates the duration in ms - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed - - output_dir: # result dir - - ngpu: # the number of GPUs for decoding - - njob: # the number of jobs for each GPU - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` - -- Results - -The decoding results can be found in `$output_dir/1best_recog/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. - -### Inference using local finetuned model - -- Modify inference related parameters in `infer_after_finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed~~~~ - - decoding_model_name: # set the checkpoint name for decoding, e.g., `valid.cer_ctc.ave.pb` - -- Then you can run the pipeline to finetune with: -```python - python infer_after_finetune.py -``` - -- Results - -The decoding results can be found in `$output_dir/decoding_results/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. diff --git a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/finetune.py b/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/finetune.py deleted file mode 100644 index a5f1ee40a..000000000 --- a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/finetune.py +++ /dev/null @@ -1,37 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k", - data_path="./data") - params.output_dir = "./checkpoint" - params.data_path = "./example_data/" - params.dataset_type = "small" - params.batch_bins = 16000 - params.max_epoch = 50 - params.lr = 0.00002 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/infer.py b/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/infer.py deleted file mode 100644 index 7a6b750e1..000000000 --- a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/infer.py +++ /dev/null @@ -1,87 +0,0 @@ -import os -import shutil -from multiprocessing import Pool - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -from funasr.utils.compute_wer import compute_wer - - -def modelscope_infer_core(output_dir, split_dir, njob, idx): - output_dir_job = os.path.join(output_dir, "output.{}".format(idx)) - gpu_id = (int(idx) - 1) // njob - if "CUDA_VISIBLE_DEVICES" in os.environ.keys(): - gpu_list = os.environ['CUDA_VISIBLE_DEVICES'].split(",") - os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_list[gpu_id]) - else: - os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_id) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k", - output_dir=output_dir_job, - ) - audio_in = os.path.join(split_dir, "wav.{}.scp".format(idx)) - inference_pipeline(audio_in=audio_in) - - -def modelscope_infer(params): - # prepare for multi-GPU decoding - ngpu = params["ngpu"] - njob = params["njob"] - output_dir = params["output_dir"] - if os.path.exists(output_dir): - shutil.rmtree(output_dir) - os.mkdir(output_dir) - split_dir = os.path.join(output_dir, "split") - os.mkdir(split_dir) - nj = ngpu * njob - wav_scp_file = os.path.join(params["data_dir"], "wav.scp") - with open(wav_scp_file) as f: - lines = f.readlines() - num_lines = len(lines) - num_job_lines = num_lines // nj - start = 0 - for i in range(nj): - end = start + num_job_lines - file = os.path.join(split_dir, "wav.{}.scp".format(str(i + 1))) - with open(file, "w") as f: - if i == nj - 1: - f.writelines(lines[start:]) - else: - f.writelines(lines[start:end]) - start = end - - p = Pool(nj) - for i in range(nj): - p.apply_async(modelscope_infer_core, - args=(output_dir, split_dir, njob, str(i + 1))) - p.close() - p.join() - - # combine decoding results - best_recog_path = os.path.join(output_dir, "1best_recog") - os.mkdir(best_recog_path) - files = ["text", "token", "score"] - for file in files: - with open(os.path.join(best_recog_path, file), "w") as f: - for i in range(nj): - job_file = os.path.join(output_dir, "output.{}/1best_recog".format(str(i + 1)), file) - with open(job_file) as f_job: - lines = f_job.readlines() - f.writelines(lines) - - # If text exists, compute CER - text_in = os.path.join(params["data_dir"], "text") - if os.path.exists(text_in): - text_proc_file = os.path.join(best_recog_path, "text") - compute_wer(text_in, text_proc_file, os.path.join(best_recog_path, "text.cer")) - - -if __name__ == "__main__": - params = {} - params["data_dir"] = "./data/test" - params["output_dir"] = "./results" - params["ngpu"] = 2 - params["njob"] = 5 - modelscope_infer(params) diff --git a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/infer_after_finetune.py b/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/infer_after_finetune.py deleted file mode 100644 index 488936c7f..000000000 --- a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k/infer_after_finetune.py +++ /dev/null @@ -1,52 +0,0 @@ -import json -import os -import shutil - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -from funasr.utils.compute_wer import compute_wer - - -def modelscope_infer_after_finetune(params): - # prepare for decoding - pretrained_model_path = os.path.join(os.environ["HOME"], ".cache/modelscope/hub", params["modelscope_model_name"]) - for file_name in params["required_files"]: - if file_name == "configuration.json": - with open(os.path.join(pretrained_model_path, file_name)) as f: - config_dict = json.load(f) - config_dict["model"]["am_model_name"] = params["decoding_model_name"] - with open(os.path.join(params["output_dir"], "configuration.json"), "w") as f: - json.dump(config_dict, f, indent=4, separators=(',', ': ')) - else: - shutil.copy(os.path.join(pretrained_model_path, file_name), - os.path.join(params["output_dir"], file_name)) - decoding_path = os.path.join(params["output_dir"], "decode_results") - if os.path.exists(decoding_path): - shutil.rmtree(decoding_path) - os.mkdir(decoding_path) - - # decoding - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=params["output_dir"], - output_dir=decoding_path, - ) - audio_in = os.path.join(params["data_dir"], "wav.scp") - inference_pipeline(audio_in=audio_in) - - # computer CER if GT text is set - text_in = os.path.join(params["data_dir"], "text") - if os.path.exists(text_in): - text_proc_file = os.path.join(decoding_path, "1best_recog/text") - compute_wer(text_in, text_proc_file, os.path.join(decoding_path, "text.cer")) - - -if __name__ == '__main__': - params = {} - params["modelscope_model_name"] = "damo/speech_data2vec_pretrain-paraformer-zh-cn-aishell2-16k" - params["required_files"] = ["am.mvn", "decoding.yaml", "configuration.json"] - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data/test" - params["decoding_model_name"] = "valid.cer_ctc.ave.pb" - modelscope_infer_after_finetune(params) diff --git a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/README.md b/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/README.md deleted file mode 100644 index 053986d3d..000000000 --- a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained Paraformer-large Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: `train/wav.scp`, `train/text`; `validation/wav.scp`, `validation/text` - - dataset_type: # for dataset larger than 1000 hours, set as `large`, otherwise set as `small` - - batch_bins: # batch size. For dataset_type is `small`, `batch_bins` indicates the feature frames. For dataset_type is `large`, `batch_bins` indicates the duration in ms - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed - - output_dir: # result dir - - ngpu: # the number of GPUs for decoding - - njob: # the number of jobs for each GPU - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` - -- Results - -The decoding results can be found in `$output_dir/1best_recog/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. - -### Inference using local finetuned model - -- Modify inference related parameters in `infer_after_finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed~~~~ - - decoding_model_name: # set the checkpoint name for decoding, e.g., `valid.cer_ctc.ave.pb` - -- Then you can run the pipeline to finetune with: -```python - python infer_after_finetune.py -``` - -- Results - -The decoding results can be found in `$output_dir/decoding_results/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. diff --git a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/finetune.py b/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/finetune.py deleted file mode 100644 index 005cae617..000000000 --- a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/finetune.py +++ /dev/null @@ -1,37 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch", - data_path="./data") - params.output_dir = "./checkpoint" - params.data_path = "./example_data/" - params.dataset_type = "small" - params.batch_bins = 16000 - params.max_epoch = 50 - params.lr = 0.00005 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/infer.py b/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/infer.py deleted file mode 100644 index f07f308c2..000000000 --- a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/infer.py +++ /dev/null @@ -1,87 +0,0 @@ -import os -import shutil -from multiprocessing import Pool - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -from funasr.utils.compute_wer import compute_wer - - -def modelscope_infer_core(output_dir, split_dir, njob, idx): - output_dir_job = os.path.join(output_dir, "output.{}".format(idx)) - gpu_id = (int(idx) - 1) // njob - if "CUDA_VISIBLE_DEVICES" in os.environ.keys(): - gpu_list = os.environ['CUDA_VISIBLE_DEVICES'].split(",") - os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_list[gpu_id]) - else: - os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_id) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch", - output_dir=output_dir_job, - ) - audio_in = os.path.join(split_dir, "wav.{}.scp".format(idx)) - inference_pipeline(audio_in=audio_in) - - -def modelscope_infer(params): - # prepare for multi-GPU decoding - ngpu = params["ngpu"] - njob = params["njob"] - output_dir = params["output_dir"] - if os.path.exists(output_dir): - shutil.rmtree(output_dir) - os.mkdir(output_dir) - split_dir = os.path.join(output_dir, "split") - os.mkdir(split_dir) - nj = ngpu * njob - wav_scp_file = os.path.join(params["data_dir"], "wav.scp") - with open(wav_scp_file) as f: - lines = f.readlines() - num_lines = len(lines) - num_job_lines = num_lines // nj - start = 0 - for i in range(nj): - end = start + num_job_lines - file = os.path.join(split_dir, "wav.{}.scp".format(str(i + 1))) - with open(file, "w") as f: - if i == nj - 1: - f.writelines(lines[start:]) - else: - f.writelines(lines[start:end]) - start = end - - p = Pool(nj) - for i in range(nj): - p.apply_async(modelscope_infer_core, - args=(output_dir, split_dir, njob, str(i + 1))) - p.close() - p.join() - - # combine decoding results - best_recog_path = os.path.join(output_dir, "1best_recog") - os.mkdir(best_recog_path) - files = ["text", "token", "score"] - for file in files: - with open(os.path.join(best_recog_path, file), "w") as f: - for i in range(nj): - job_file = os.path.join(output_dir, "output.{}/1best_recog".format(str(i + 1)), file) - with open(job_file) as f_job: - lines = f_job.readlines() - f.writelines(lines) - - # If text exists, compute CER - text_in = os.path.join(params["data_dir"], "text") - if os.path.exists(text_in): - text_proc_file = os.path.join(best_recog_path, "text") - compute_wer(text_in, text_proc_file, os.path.join(best_recog_path, "text.cer")) - - -if __name__ == "__main__": - params = {} - params["data_dir"] = "./data/test" - params["output_dir"] = "./results" - params["ngpu"] = 2 - params["njob"] = 5 - modelscope_infer(params) diff --git a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/infer_after_finetune.py b/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/infer_after_finetune.py deleted file mode 100644 index c94f685dc..000000000 --- a/egs_modelscope/asr/data2vec/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch/infer_after_finetune.py +++ /dev/null @@ -1,52 +0,0 @@ -import json -import os -import shutil - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -from funasr.utils.compute_wer import compute_wer - - -def modelscope_infer_after_finetune(params): - # prepare for decoding - pretrained_model_path = os.path.join(os.environ["HOME"], ".cache/modelscope/hub", params["modelscope_model_name"]) - for file_name in params["required_files"]: - if file_name == "configuration.json": - with open(os.path.join(pretrained_model_path, file_name)) as f: - config_dict = json.load(f) - config_dict["model"]["am_model_name"] = params["decoding_model_name"] - with open(os.path.join(params["output_dir"], "configuration.json"), "w") as f: - json.dump(config_dict, f, indent=4, separators=(',', ': ')) - else: - shutil.copy(os.path.join(pretrained_model_path, file_name), - os.path.join(params["output_dir"], file_name)) - decoding_path = os.path.join(params["output_dir"], "decode_results") - if os.path.exists(decoding_path): - shutil.rmtree(decoding_path) - os.mkdir(decoding_path) - - # decoding - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=params["output_dir"], - output_dir=decoding_path, - ) - audio_in = os.path.join(params["data_dir"], "wav.scp") - inference_pipeline(audio_in=audio_in) - - # computer CER if GT text is set - text_in = os.path.join(params["data_dir"], "text") - if os.path.exists(text_in): - text_proc_file = os.path.join(decoding_path, "1best_recog/text") - compute_wer(text_in, text_proc_file, os.path.join(decoding_path, "text.cer")) - - -if __name__ == '__main__': - params = {} - params["modelscope_model_name"] = "damo/speech_data2vec_pretrain-zh-cn-aishell2-16k-pytorch" - params["required_files"] = ["am.mvn", "decoding.yaml", "configuration.json"] - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data/test" - params["decoding_model_name"] = "valid.cer_ctc.ave.pb" - modelscope_infer_after_finetune(params) diff --git a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/README.md b/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/RESULTS.md b/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/RESULTS.md deleted file mode 100644 index 716d44eeb..000000000 --- a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/RESULTS.md +++ /dev/null @@ -1,40 +0,0 @@ -# Paraformer-Large -- Model link: -- Model size: 45M - -# Environments -- date: `Tue Feb 13 20:13:22 CST 2023` -- python version: `3.7.12` -- FunASR version: `0.1.0` -- pytorch version: `pytorch 1.7.0` -- Git hash: `` -- Commit date: `` - -# Beachmark Results - -## result (paper) -beam=20,CER tool:https://github.com/yufan-aslp/AliMeeting - -| model | Para (M) | Data (hrs) | Eval (CER%) | Test (CER%) | -|:-------------------:|:---------:|:---------:|:---------:| :---------:| -| MFCCA | 45 | 917 | 16.1 | 17.5 | - -## result(modelscope) - -beam=10 - -with separating character (src) - -| model | Para (M) | Data (hrs) | Eval_sp (CER%) | Test_sp (CER%) | -|:-------------------:|:---------:|:---------:|:---------:| :---------:| -| MFCCA | 45 | 917 | 17.1 | 18.6 | - -without separating character (src) - -| model | Para (M) | Data (hrs) | Eval_nosp (CER%) | Test_nosp (CER%) | -|:-------------------:|:---------:|:---------:|:---------:| :---------:| -| MFCCA | 45 | 917 | 16.4 | 18.0 | - -## 偏差 - -Considering the differences of the CER calculation tool and decoding beam size, the results of CER are biased (<0.5%). \ No newline at end of file diff --git a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/demo.py b/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/demo.py deleted file mode 100644 index f6026d631..000000000 --- a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/demo.py +++ /dev/null @@ -1,11 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950', - model_revision='v3.0.0' -) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') -print(rec_result) \ No newline at end of file diff --git a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/finetune.py b/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/finetune.py deleted file mode 100755 index 7db085af1..000000000 --- a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision=params.model_revision, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - - params = modelscope_args(model="NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 1000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 10 # 最大训练轮数 - params.lr = 0.0001 # 设置学习率 - params.model_revision = 'v3.0.0' - modelscope_finetune(params) diff --git a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/infer.py b/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/infer.py deleted file mode 100755 index 12ec2ac8c..000000000 --- a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/infer.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=args.model, - model_revision=args.model_revision, - output_dir=args.output_dir, - batch_size=args.batch_size, - ) - inference_pipeline(audio_in=args.audio_in) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950") - parser.add_argument('--model_revision', type=str, default="v3.0.0") - parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--batch_size', type=int, default=1) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/infer.sh b/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/infer.sh deleted file mode 100755 index 51a4968bc..000000000 --- a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/infer.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=3 -model="NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950" -data_dir="./data/test" -output_dir="./results_pl_gpu" -batch_size=1 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="3,4" # set gpus, e.g., gpuid_list="0,1" -njob=4 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - ./utils/run.pl JOB=1:${nj} ${output_dir}/log/infer.JOB.log \ - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.JOB.scp \ - --output_dir ${output_dir}/output.JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid_list_array[JOB-1]} - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/token ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - sed -e 's/src//g' ${output_dir}/1best_recog/text.proc | sed -e 's/ \+/ /g' > ${output_dir}/1best_recog/text_nosp.proc - sed -e 's/src//g' ${output_dir}/1best_recog/text.ref | sed -e 's/ \+/ /g' > ${output_dir}/1best_recog/text_nosp.ref - - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.sp.cer - tail -n 3 ${output_dir}/1best_recog/text.sp.cer - python utils/compute_wer.py ${output_dir}/1best_recog/text_nosp.ref ${output_dir}/1best_recog/text_nosp.proc ${output_dir}/1best_recog/text.nosp.cer - tail -n 3 ${output_dir}/1best_recog/text.nosp.cer -fi - diff --git a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/utils b/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/utils deleted file mode 120000 index 2ac163ff4..000000000 --- a/egs_modelscope/asr/mfcca/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/utils +++ /dev/null @@ -1 +0,0 @@ -../../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README.md b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README_zh.md b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README_zh.md deleted file mode 120000 index 1f08a41e9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/demo.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/demo.py deleted file mode 100644 index e5e909770..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/demo.py +++ /dev/null @@ -1,16 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -param_dict = dict() -param_dict['hotword'] = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/hotword.txt" -param_dict['clas_scale'] = 1.00 # 1.50 # set it larger if you want high recall (sacrifice general accuracy) -# 13% relative recall raise over internal hotword test set (45%->51%) -# CER might raise when utterance contains no hotword - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404", - param_dict=param_dict) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_hotword.wav') -print(rec_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py deleted file mode 100644 index fa7283da5..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py +++ /dev/null @@ -1,37 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision="v1.0.2", - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404", data_path="./data") - params.output_dir = "./checkpoint" # 模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "large" # finetune contextual_paraformer模型只能使用large dataset - params.batch_bins = 120000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.0002 # 设置学习率 - - modelscope_finetune(params) \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh deleted file mode 100644 index 632562670..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=10 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" -hotword_txt=None - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --hotword_txt ${hotword_txt} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer_aishell1_subtest_demo.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer_aishell1_subtest_demo.py deleted file mode 100644 index 97e9fce67..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer_aishell1_subtest_demo.py +++ /dev/null @@ -1,40 +0,0 @@ -import os -import tempfile -import codecs -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -from modelscope.msdatasets import MsDataset - -if __name__ == '__main__': - param_dict = dict() - param_dict['hotword'] = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/hotword.txt" - - output_dir = "./output" - batch_size = 1 - - # dataset split ['test'] - ds_dict = MsDataset.load(dataset_name='speech_asr_aishell1_hotwords_testsets', namespace='speech_asr') - work_dir = tempfile.TemporaryDirectory().name - if not os.path.exists(work_dir): - os.makedirs(work_dir) - wav_file_path = os.path.join(work_dir, "wav.scp") - - counter = 0 - with codecs.open(wav_file_path, 'w') as fin: - for line in ds_dict: - counter += 1 - wav = line["Audio:FILE"] - idx = wav.split("/")[-1].split(".")[0] - fin.writelines(idx + " " + wav + "\n") - if counter == 50: - break - audio_in = wav_file_path - - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404", - output_dir=output_dir, - batch_size=batch_size, - param_dict=param_dict) - - rec_result = inference_pipeline(audio_in=audio_in) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/utils b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/utils deleted file mode 120000 index 2ac163ff4..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/utils +++ /dev/null @@ -1 +0,0 @@ -../../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/README.md b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/README_zh.md b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/README_zh.md deleted file mode 120000 index 1f08a41e9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/RESULTS.md b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/RESULTS.md deleted file mode 100644 index b7559b188..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/RESULTS.md +++ /dev/null @@ -1,38 +0,0 @@ -# Paraformer-Large -- Model link: -- Model size: 220M - -# Beachmark Results - -## AISHELL-1 -- Decode config: - - Decode without CTC - - Decode without LM - -| CER(%) | Pretrain model| -|:---------:|:-------------:| -| dev | 2.37 | -| test | 3.34 | - -## AISHELL-2 -- Decode config: - - Decode without CTC - - Decode without LM - -| CER(%) | Pretrain model| -|:------------:|:-------------:| -| dev_ios | 4.04 | -| test_android | 3.86 | -| test_ios | 4.38 | -| test_mic | 4.21 | - -## Wenetspeech -- Decode config: - - Decode without CTC - - Decode without LM - -| testset | CER(%)| -|:---------:|:-----:| -| dev | 4.55 | -| test | 10.64 | -| test_net | 7.78 | diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo.py deleted file mode 100644 index a3d522211..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online', - model_revision='v1.0.7', - update_model=False, - mode="paraformer_fake_streaming" -) -audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' -rec_result = inference_pipeline(audio_in=audio_in) -print(rec_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo_online.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo_online.py deleted file mode 100644 index d9b5b2dfb..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo_online.py +++ /dev/null @@ -1,41 +0,0 @@ -import os -import logging -import torch -import soundfile - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -from modelscope.utils.logger import get_logger - -logger = get_logger(log_level=logging.CRITICAL) -logger.setLevel(logging.CRITICAL) - -os.environ["MODELSCOPE_CACHE"] = "./" -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online', - model_revision='v1.0.7', - update_model=False, - mode="paraformer_streaming" -) - -model_dir = os.path.join(os.environ["MODELSCOPE_CACHE"], "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online") -speech, sample_rate = soundfile.read(os.path.join(model_dir, "example/asr_example.wav")) -speech_length = speech.shape[0] - -sample_offset = 0 -chunk_size = [5, 10, 5] #[5, 10, 5] 600ms, [8, 8, 4] 480ms -stride_size = chunk_size[1] * 960 -param_dict = {"cache": dict(), "is_final": False, "chunk_size": chunk_size} -final_result = "" - -for sample_offset in range(0, speech_length, min(stride_size, speech_length - sample_offset)): - if sample_offset + stride_size >= speech_length - 1: - stride_size = speech_length - sample_offset - param_dict["is_final"] = True - rec_result = inference_pipeline(audio_in=speech[sample_offset: sample_offset + stride_size], - param_dict=param_dict) - if len(rec_result) != 0: - final_result += rec_result['text'] - print(rec_result) -print(final_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo_online_v2.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo_online_v2.py deleted file mode 100644 index 1f2500d48..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo_online_v2.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -import logging -import torch -import soundfile - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -from modelscope.utils.logger import get_logger - -logger = get_logger(log_level=logging.CRITICAL) -logger.setLevel(logging.CRITICAL) - -os.environ["MODELSCOPE_CACHE"] = "./" -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online', - model_revision='v1.0.7', - update_model=False, - mode="paraformer_streaming" -) - -model_dir = os.path.join(os.environ["MODELSCOPE_CACHE"], "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online") -speech, sample_rate = soundfile.read(os.path.join(model_dir, "example/asr_example.wav")) -speech_length = speech.shape[0] - -sample_offset = 0 -chunk_size = [0, 10, 5] #[0, 10, 5] 600ms, [0, 8, 4] 480ms -encoder_chunk_look_back = 4 #number of chunks to lookback for encoder self-attention -decoder_chunk_look_back = 1 #number of encoder chunks to lookback for decoder cross-attention -stride_size = chunk_size[1] * 960 -param_dict = {"cache": dict(), "is_final": False, "chunk_size": chunk_size, - "encoder_chunk_look_back": encoder_chunk_look_back, "decoder_chunk_look_back": decoder_chunk_look_back} -final_result = "" - -for sample_offset in range(0, speech_length, min(stride_size, speech_length - sample_offset)): - if sample_offset + stride_size >= speech_length - 1: - stride_size = speech_length - sample_offset - param_dict["is_final"] = True - rec_result = inference_pipeline(audio_in=speech[sample_offset: sample_offset + stride_size], - param_dict=param_dict) - if len(rec_result) != 0: - final_result += rec_result['text'] - print(rec_result) -print(final_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/finetune.py deleted file mode 100644 index fa046d8b0..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/finetune.py +++ /dev/null @@ -1,38 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision='v1.0.7', - update_model=False, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 1000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py deleted file mode 100644 index 0537ddafe..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py +++ /dev/null @@ -1,33 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=args.model, - output_dir=args.output_dir, - batch_size=args.batch_size, - model_revision='v1.0.7', - update_model=False, - mode="paraformer_fake_streaming", - param_dict={"decoding_model": args.decoding_mode, "hotword": args.hotword_txt} - ) - inference_pipeline(audio_in=args.audio_in) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch") - parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--decoding_mode', type=str, default="normal") - parser.add_argument('--model_revision', type=str, default=None) - parser.add_argument('--mode', type=str, default=None) - parser.add_argument('--hotword_txt', type=str, default=None) - parser.add_argument('--batch_size', type=int, default=64) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.sh deleted file mode 100644 index 0cab31e8d..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.sh +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online" -data_dir="./data/test" -output_dir="./results" -batch_size=32 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=32 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} \ - --mode "paraformer_fake_streaming" - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/utils b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/utils deleted file mode 120000 index a961ddc7a..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/utils +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/utils/ \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README_zh.md b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README_zh.md deleted file mode 120000 index 1f08a41e9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/RESULTS.md b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/RESULTS.md deleted file mode 100644 index 2b7269ce6..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/RESULTS.md +++ /dev/null @@ -1,112 +0,0 @@ -# Paraformer-Large -- Model link: -- Model size: 220M - -# Beachmark Results - -## AISHELL-1 -- Decode config: - - Decode without CTC - - Decode without LM - -| CER(%) | Pretrain model|[Finetune model](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-aishell1-vocab8404-pytorch/summary) | -|:---------:|:-------------:|:-------------:| -| dev | 1.75 |1.62 | -| test | 1.95 |1.78 | - -## AISHELL-2 -- Decode config: - - Decode without CTC - - Decode without LM - -| CER(%) | Pretrain model|[Finetune model](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-aishell2-vocab8404-pytorch/summary)| -|:------------:|:-------------:|:------------:| -| dev_ios | 2.80 |2.60 | -| test_android | 3.13 |2.84 | -| test_ios | 2.85 |2.82 | -| test_mic | 3.06 |2.88 | - -## Wenetspeech -- Decode config: - - Decode without CTC - - Decode without LM - -| testset | CER(%)| -|:---------:|:-----:| -| dev | 3.57 | -| test | 6.97 | -| test_net | 6.74 | - -## SpeechIO TIOBE -- Decode config 1: - - Decode without CTC - - Decode without LM - - With text norm -- Decode config 2: - - Decode without CTC - - Decode with Transformer-LM - - LM weight: 0.15 - - With text norm - -| testset | w/o LM | w/ LM | -|:------------------:|:----:|:----:| -|SPEECHIO_ASR_ZH00001| 0.49 | 0.35 | -|SPEECHIO_ASR_ZH00002| 3.23 | 2.86 | -|SPEECHIO_ASR_ZH00003| 1.13 | 0.80 | -|SPEECHIO_ASR_ZH00004| 1.33 | 1.10 | -|SPEECHIO_ASR_ZH00005| 1.41 | 1.18 | -|SPEECHIO_ASR_ZH00006| 5.25 | 4.85 | -|SPEECHIO_ASR_ZH00007| 5.51 | 4.97 | -|SPEECHIO_ASR_ZH00008| 3.69 | 3.18 | -|SPEECHIO_ASR_ZH00009| 3.02 | 2.78 | -|SPEECHIO_ASR_ZH000010| 3.35 | 2.99 | -|SPEECHIO_ASR_ZH000011| 1.54 | 1.25 | -|SPEECHIO_ASR_ZH000012| 2.06 | 1.68 | -|SPEECHIO_ASR_ZH000013| 2.57 | 2.25 | -|SPEECHIO_ASR_ZH000014| 3.86 | 3.08 | -|SPEECHIO_ASR_ZH000015| 3.34 | 2.67 | - - -# Fine-tuning Results - -## Fine-tuning -- Train config: - - Training data: aishell-1 - - Training info: lr 0.0002, dataset_type: small, batch bins 2000, 2 gpu, acc_grad 1, 20 epochs - - Decoding info: beam_size 1, average_num 10 - -| model | dev cer(%) | test cer(%) | -|:---------:|:-------------:|:-------------:| -| Pretrain | 1.75 |1.95 | -| Full-tuning | 1.62 |1.78 | - -- Train config: - - Training data: 16k sichuan dialect - - Training info: lr 0.0002, dataset_type: small, batch bins 2000, 2 gpu, acc_grad 1, 20 epochs - - Decoding info: beam_size 1, average_num 10 - - -| model | Training Data(h) | common cer(%) | sichuan cer(%) | -|:--------:|:-------------:|:-------:|:------------:| -| Pretrain | | 8.57 | 19.81 | -| Full-tuning | 50 | 8.8 | 12 | -| | 100 | 9.24 | 11.63 | -| | 200 | 9.82 | 10.47 | -| | 300 | 9.95 | 10.44 | -| | 1000 | 9.99 | 9.78 | - - -## Lora Fine-tuning -- Train config: - - Training data: 16k sichuan dialect - - Training info: lr 0.0002, dataset_type: small, batch bins 2000, 2 gpu, acc_grad 1, 20 epochs - - Lora info: lora_bias: "all", lora_list ['q','v'], lora_rank:8, lora_alpha:16, lora_dropout:0.1 - - Decoding info: beam_size 1, average_num 10 - -| model | Training Data(h) | Trainable Parameters(M) | Memory Usage(G) | common cer(%) | sichuan cer(%) | -|:---------------:|:------------------:|:-------------------------:|:-----------------:|:---------------:|:----------------:| -| Pretrain | | | | 8.57 | 19.81 | -| Full-tuning | 50 | 220.9 | 15 | 8.8 | 12 | -| Lora Finetune | 50 | 2.29 | 7 | 9.13 | 12.13 | -| Full-tuning | 200 | 220.9 | 15 | 9.82 | 10.47 | -| Lora Finetune | 200 | 2.29 | 7 | 9.21 | 11.28 | diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/demo.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/demo.py deleted file mode 100644 index a8a670af9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/demo.py +++ /dev/null @@ -1,11 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch', - batch_size=64, -) -audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' -rec_result = inference_pipeline(audio_in=audio_in) -print(rec_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/finetune.py deleted file mode 100644 index 993f8ed37..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/finetune.py +++ /dev/null @@ -1,48 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr, - mate_params=params.param_dict) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.0002 # 设置学习率 - init_param = [] # 初始模型路径,默认加载modelscope模型初始化,例如: ["checkpoint/20epoch.pb"] - freeze_param = [] # 模型参数freeze, 例如: ["encoder"] - ignore_init_mismatch = True # 是否忽略模型参数初始化不匹配 - use_lora = False # 是否使用lora进行模型微调 - params.param_dict = {"init_param":init_param, "freeze_param": freeze_param, "ignore_init_mismatch": ignore_init_mismatch} - if use_lora: - enable_lora = True - lora_bias = "all" - lora_params = {"lora_list":['q','v'], "lora_rank":8, "lora_alpha":16, "lora_dropout":0.1} - lora_config = {"enable_lora": enable_lora, "lora_bias": lora_bias, "lora_params": lora_params} - params.param_dict.update(lora_config) - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh deleted file mode 100644 index ef49d7a60..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/utils b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/utils deleted file mode 120000 index 2ac163ff4..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/utils +++ /dev/null @@ -1 +0,0 @@ -../../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-tiny-commandword_asr_nat-zh-cn-16k-vocab544-pytorch/README.md b/egs_modelscope/asr/paraformer/speech_paraformer-tiny-commandword_asr_nat-zh-cn-16k-vocab544-pytorch/README.md deleted file mode 100644 index 1587d3d5d..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-tiny-commandword_asr_nat-zh-cn-16k-vocab544-pytorch/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained Paraformer-large Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: train/wav.scp, train/text; validation/wav.scp, validation/text. - - batch_bins: # batch size - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - data_dir: # the dataset dir - - output_dir: # result dir - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-tiny-commandword_asr_nat-zh-cn-16k-vocab544-pytorch/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer-tiny-commandword_asr_nat-zh-cn-16k-vocab544-pytorch/infer.py deleted file mode 100644 index dce0f63e7..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-tiny-commandword_asr_nat-zh-cn-16k-vocab544-pytorch/infer.py +++ /dev/null @@ -1,89 +0,0 @@ -import os -import shutil -from multiprocessing import Pool - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -from funasr.utils.compute_wer import compute_wer - - -def modelscope_infer_core(output_dir, split_dir, njob, idx): - output_dir_job = os.path.join(output_dir, "output.{}".format(idx)) - gpu_id = (int(idx) - 1) // njob - if "CUDA_VISIBLE_DEVICES" in os.environ.keys(): - gpu_list = os.environ['CUDA_VISIBLE_DEVICES'].split(",") - os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_list[gpu_id]) - else: - os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_id) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformer-tiny-commandword_asr_nat-zh-cn-16k-vocab544-pytorch", - output_dir=output_dir_job, - batch_size=64, - update_model=False, - ) - audio_in = os.path.join(split_dir, "wav.{}.scp".format(idx)) - inference_pipeline(audio_in=audio_in) - - -def modelscope_infer(params): - # prepare for multi-GPU decoding - ngpu = params["ngpu"] - njob = params["njob"] - output_dir = params["output_dir"] - if os.path.exists(output_dir): - shutil.rmtree(output_dir) - os.mkdir(output_dir) - split_dir = os.path.join(output_dir, "split") - os.mkdir(split_dir) - nj = ngpu * njob - wav_scp_file = os.path.join(params["data_dir"], "wav.scp") - with open(wav_scp_file) as f: - lines = f.readlines() - num_lines = len(lines) - num_job_lines = num_lines // nj - start = 0 - for i in range(nj): - end = start + num_job_lines - file = os.path.join(split_dir, "wav.{}.scp".format(str(i + 1))) - with open(file, "w") as f: - if i == nj - 1: - f.writelines(lines[start:]) - else: - f.writelines(lines[start:end]) - start = end - - p = Pool(nj) - for i in range(nj): - p.apply_async(modelscope_infer_core, - args=(output_dir, split_dir, njob, str(i + 1))) - p.close() - p.join() - - # combine decoding results - best_recog_path = os.path.join(output_dir, "1best_recog") - os.mkdir(best_recog_path) - files = ["text", "token", "score"] - for file in files: - with open(os.path.join(best_recog_path, file), "w") as f: - for i in range(nj): - job_file = os.path.join(output_dir, "output.{}/1best_recog".format(str(i + 1)), file) - with open(job_file) as f_job: - lines = f_job.readlines() - f.writelines(lines) - - # If text exists, compute CER - text_in = os.path.join(params["data_dir"], "text") - if os.path.exists(text_in): - text_proc_file = os.path.join(best_recog_path, "token") - compute_wer(text_in, text_proc_file, os.path.join(best_recog_path, "text.cer")) - - -if __name__ == "__main__": - params = {} - params["data_dir"] = "./data/test" - params["output_dir"] = "./results" - params["ngpu"] = 1 - params["njob"] = 1 - modelscope_infer(params) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/README.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/README_zh.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/README_zh.md deleted file mode 120000 index 1f08a41e9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/demo.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/demo.py deleted file mode 100644 index ea486c835..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/demo.py +++ /dev/null @@ -1,11 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/damo/speech_paraformer_asr-en-16k-vocab4199-pytorch', - model_revision="v1.0.1", -) -audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_en.wav' -rec_result = inference_pipeline(audio_in=audio_in) -print(rec_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/finetune.py deleted file mode 100644 index a945b31b9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/finetune.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_paraformer_asr-en-16k-vocab4199-pytorch", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/infer.sh deleted file mode 100644 index b552ae831..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/infer.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer_asr-en-16k-vocab4199-pytorch" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/utils b/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/utils deleted file mode 120000 index 2ac163ff4..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr-en-16k-vocab4199-pytorch/utils +++ /dev/null @@ -1 +0,0 @@ -../../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README_zh.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README_zh.md deleted file mode 120000 index 1f08a41e9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/demo.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/demo.py deleted file mode 100644 index 5c8fceb62..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/demo.py +++ /dev/null @@ -1,15 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch", - output_dir=output_dir, - batch_size=1, - ) - rec_result = inference_pipeline(audio_in=audio_in) - print(rec_result) - diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/finetune.py deleted file mode 100644 index 41e0337ac..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision=params.model_revision, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - from funasr.utils.modelscope_param import modelscope_args - params = modelscope_args(model="damo/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 25000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh deleted file mode 100644 index 207bbdf04..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README_zh.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README_zh.md deleted file mode 120000 index 1f08a41e9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/demo.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/demo.py deleted file mode 100644 index f2db74e8b..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/demo.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://modelscope.oss-cn-beijing.aliyuncs.com/test/audios/asr_example.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in) - print(rec_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/finetune.py deleted file mode 100644 index 793204563..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/finetune.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch", - data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 25000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.0005 # 设置学习率 - modelscope_finetune(params) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh deleted file mode 100644 index 4b59bc102..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/README.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/README_zh.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/README_zh.md deleted file mode 120000 index 1f08a41e9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/demo.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/demo.py deleted file mode 100644 index dae7766b6..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/demo.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online', - model_revision='v1.0.6', - update_model=False, - mode="paraformer_fake_streaming" -) -audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' -rec_result = inference_pipeline(audio_in=audio_in) -print(rec_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/demo_online.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/demo_online.py deleted file mode 100644 index 199fcd801..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/demo_online.py +++ /dev/null @@ -1,41 +0,0 @@ -import os -import logging -import torch -import soundfile - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -from modelscope.utils.logger import get_logger - -logger = get_logger(log_level=logging.CRITICAL) -logger.setLevel(logging.CRITICAL) - -os.environ["MODELSCOPE_CACHE"] = "./" -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online', - model_revision='v1.0.6', - update_model=False, - mode="paraformer_streaming" -) - -model_dir = os.path.join(os.environ["MODELSCOPE_CACHE"], "damo/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online") -speech, sample_rate = soundfile.read(os.path.join(model_dir, "example/asr_example.wav")) -speech_length = speech.shape[0] - -sample_offset = 0 -chunk_size = [8, 8, 4] #[5, 10, 5] 600ms, [8, 8, 4] 480ms -stride_size = chunk_size[1] * 960 -param_dict = {"cache": dict(), "is_final": False, "chunk_size": chunk_size} -final_result = "" - -for sample_offset in range(0, speech_length, min(stride_size, speech_length - sample_offset)): - if sample_offset + stride_size >= speech_length - 1: - stride_size = speech_length - sample_offset - param_dict["is_final"] = True - rec_result = inference_pipeline(audio_in=speech[sample_offset: sample_offset + stride_size], - param_dict=param_dict) - if len(rec_result) != 0: - final_result += rec_result['text'] - print(rec_result) -print(final_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/finetune.py deleted file mode 100644 index bd58c87e5..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/finetune.py +++ /dev/null @@ -1,38 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision='v1.0.6', - update_model=False, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 1000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py deleted file mode 100644 index 241ebef22..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py +++ /dev/null @@ -1,33 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=args.model, - output_dir=args.output_dir, - batch_size=args.batch_size, - model_revision='v1.0.6', - update_model=False, - mode="paraformer_fake_streaming", - param_dict={"decoding_model": args.decoding_mode, "hotword": args.hotword_txt} - ) - inference_pipeline(audio_in=args.audio_in) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch") - parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--decoding_mode', type=str, default="normal") - parser.add_argument('--model_revision', type=str, default=None) - parser.add_argument('--mode', type=str, default=None) - parser.add_argument('--hotword_txt', type=str, default=None) - parser.add_argument('--batch_size', type=int, default=64) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.sh deleted file mode 100644 index f5658253a..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.sh +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online" -data_dir="./data/test" -output_dir="./results" -batch_size=32 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=32 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} \ - --mode "paraformer_fake_streaming" - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/utils b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/utils deleted file mode 120000 index a961ddc7a..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/utils +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/utils/ \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/README.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/README_zh.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/README_zh.md deleted file mode 120000 index 1f08a41e9..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/finetune.py deleted file mode 100644 index a2b3c297e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/finetune.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/infer.py deleted file mode 100644 index 7cc71e7b8..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/infer.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=args.model, - output_dir=args.output_dir, - batch_size=args.batch_size, - ) - inference_pipeline(audio_in=args.audio_in) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1") - parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--batch_size', type=int, default=64) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/infer.sh deleted file mode 100644 index 6daf7d43e..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/infer.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=4 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob - - -if ${gpu_inference}; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/infer_after_finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/infer_after_finetune.py deleted file mode 100644 index 747b49f96..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/infer_after_finetune.py +++ /dev/null @@ -1,48 +0,0 @@ -import json -import os -import shutil - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -from modelscope.hub.snapshot_download import snapshot_download - -from funasr.utils.compute_wer import compute_wer - -def modelscope_infer_after_finetune(params): - # prepare for decoding - - try: - pretrained_model_path = snapshot_download(params["modelscope_model_name"], cache_dir=params["output_dir"]) - except BaseException: - raise BaseException(f"Please download pretrain model from ModelScope firstly.") - shutil.copy(os.path.join(params["output_dir"], params["decoding_model_name"]), os.path.join(pretrained_model_path, "model.pb")) - decoding_path = os.path.join(params["output_dir"], "decode_results") - if os.path.exists(decoding_path): - shutil.rmtree(decoding_path) - os.mkdir(decoding_path) - - # decoding - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=pretrained_model_path, - output_dir=decoding_path, - batch_size=params["batch_size"] - ) - audio_in = os.path.join(params["data_dir"], "wav.scp") - inference_pipeline(audio_in=audio_in) - - # computer CER if GT text is set - text_in = os.path.join(params["data_dir"], "text") - if os.path.exists(text_in): - text_proc_file = os.path.join(decoding_path, "1best_recog/text") - compute_wer(text_in, text_proc_file, os.path.join(decoding_path, "text.cer")) - - -if __name__ == '__main__': - params = {} - params["modelscope_model_name"] = "damo/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1" - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data/test" - params["decoding_model_name"] = "valid.acc.ave_10best.pb" - params["batch_size"] = 64 - modelscope_infer_after_finetune(params) \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/utils b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/utils deleted file mode 120000 index 2ac163ff4..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-8k-common-vocab8358-tensorflow1/utils +++ /dev/null @@ -1 +0,0 @@ -../../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/paraformerbert/speech_paraformerbert_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md b/egs_modelscope/asr/paraformerbert/speech_paraformerbert_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md deleted file mode 100644 index c68a8cd4f..000000000 --- a/egs_modelscope/asr/paraformerbert/speech_paraformerbert_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained Paraformer-large Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: train/wav.scp, train/text; validation/wav.scp, validation/text. - - batch_bins: # batch size - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - audio_in: # support wav, url, bytes, and parsed audio format. - - output_dir: # If the input format is wav.scp, it needs to be set. - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` diff --git a/egs_modelscope/asr/paraformerbert/speech_paraformerbert_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py b/egs_modelscope/asr/paraformerbert/speech_paraformerbert_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py deleted file mode 100644 index ba237dd7f..000000000 --- a/egs_modelscope/asr/paraformerbert/speech_paraformerbert_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py +++ /dev/null @@ -1,14 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformerbert_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in) - print(rec_result) - diff --git a/egs_modelscope/asr/paraformerbert/speech_paraformerbert_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py b/egs_modelscope/asr/paraformerbert/speech_paraformerbert_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py deleted file mode 100644 index 63bed40a0..000000000 --- a/egs_modelscope/asr/paraformerbert/speech_paraformerbert_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://modelscope.oss-cn-beijing.aliyuncs.com/test/audios/asr_example.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformerbert_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cantonese-CHS-16k-common-vocab1468-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cantonese-CHS-16k-common-vocab1468-tensorflow1-online/finetune.py deleted file mode 100644 index 3fa3f9d26..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cantonese-CHS-16k-common-vocab1468-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-cantonese-CHS-16k-common-vocab1468-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cantonese-CHS-16k-common-vocab1468-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cantonese-CHS-16k-common-vocab1468-tensorflow1-online/infer.py deleted file mode 100644 index d4f8d762f..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cantonese-CHS-16k-common-vocab1468-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_cantonese-CHS.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-cantonese-CHS-16k-common-vocab1468-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online/README.md b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online/README.md deleted file mode 100644 index c68a8cd4f..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained Paraformer-large Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: train/wav.scp, train/text; validation/wav.scp, validation/text. - - batch_bins: # batch size - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - audio_in: # support wav, url, bytes, and parsed audio format. - - output_dir: # If the input format is wav.scp, it needs to be set. - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online/finetune.py deleted file mode 100644 index 0d17e4d1f..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision=params.model_revision, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - from funasr.utils.modelscope_param import modelscope_args - params = modelscope_args(model="damo/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online/infer.py deleted file mode 100644 index 9c4d6c7cc..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online/infer.py +++ /dev/null @@ -1,14 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-cn-dialect-16k-vocab8358-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in) - print(rec_result) - diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online/finetune.py deleted file mode 100644 index 462f2662a..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online/infer.py deleted file mode 100644 index 48b48071e..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_de.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-en-16k-common-vocab1080-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-en-16k-common-vocab1080-tensorflow1-online/finetune.py deleted file mode 100644 index 6998f0c5f..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-en-16k-common-vocab1080-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-en-16k-common-vocab1080-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-en-16k-common-vocab1080-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-en-16k-common-vocab1080-tensorflow1-online/infer.py deleted file mode 100644 index 423c503ed..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-en-16k-common-vocab1080-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_en.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-en-16k-common-vocab1080-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online/finetune.py deleted file mode 100644 index 79ef4b605..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online/infer.py deleted file mode 100644 index cb1b4fa99..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_es.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/README.md b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/README.md deleted file mode 100644 index b68f1e921..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained Paraformer-large Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: `train/wav.scp`, `train/text`; `validation/wav.scp`, `validation/text` - - dataset_type: # for dataset larger than 1000 hours, set as `large`, otherwise set as `small` - - batch_bins: # batch size. For dataset_type is `small`, `batch_bins` indicates the feature frames. For dataset_type is `large`, `batch_bins` indicates the duration in ms - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed - - output_dir: # result dir - - ngpu: # the number of GPUs for decoding - - njob: # the number of jobs for each GPU - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` - -- Results - -The decoding results can be found in `$output_dir/1best_recog/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. - -### Inference using local finetuned model - -- Modify inference related parameters in `infer_after_finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed - - decoding_model_name: # set the checkpoint name for decoding, e.g., `valid.cer_ctc.ave.pb` - -- Then you can run the pipeline to finetune with: -```python - python infer_after_finetune.py -``` - -- Results - -The decoding results can be found in `$output_dir/decoding_results/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/finetune.py deleted file mode 100644 index 2469e5318..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/finetune.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/infer.py deleted file mode 100644 index 124d5ed05..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/infer.py +++ /dev/null @@ -1,89 +0,0 @@ -import os -import shutil -from multiprocessing import Pool - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -from funasr.utils.compute_wer import compute_wer - - -def modelscope_infer_core(output_dir, split_dir, njob, idx): - output_dir_job = os.path.join(output_dir, "output.{}".format(idx)) - gpu_id = (int(idx) - 1) // njob - if "CUDA_VISIBLE_DEVICES" in os.environ.keys(): - gpu_list = os.environ['CUDA_VISIBLE_DEVICES'].split(",") - os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_list[gpu_id]) - else: - os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_id) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online", - output_dir=output_dir_job, - batch_size=1 - ) - audio_in = os.path.join(split_dir, "wav.{}.scp".format(idx)) - inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - - -def modelscope_infer(params): - # prepare for multi-GPU decoding - ngpu = params["ngpu"] - njob = params["njob"] - output_dir = params["output_dir"] - if os.path.exists(output_dir): - shutil.rmtree(output_dir) - os.mkdir(output_dir) - split_dir = os.path.join(output_dir, "split") - os.mkdir(split_dir) - nj = ngpu * njob - wav_scp_file = os.path.join(params["data_dir"], "wav.scp") - with open(wav_scp_file) as f: - lines = f.readlines() - num_lines = len(lines) - num_job_lines = num_lines // nj - start = 0 - for i in range(nj): - end = start + num_job_lines - file = os.path.join(split_dir, "wav.{}.scp".format(str(i + 1))) - with open(file, "w") as f: - if i == nj - 1: - f.writelines(lines[start:]) - else: - f.writelines(lines[start:end]) - start = end - - p = Pool(nj) - for i in range(nj): - p.apply_async(modelscope_infer_core, - args=(output_dir, split_dir, njob, str(i + 1))) - p.close() - p.join() - - # combine decoding results - best_recog_path = os.path.join(output_dir, "1best_recog") - os.mkdir(best_recog_path) - files = ["text", "token", "score"] - for file in files: - with open(os.path.join(best_recog_path, file), "w") as f: - for i in range(nj): - job_file = os.path.join(output_dir, "output.{}/1best_recog".format(str(i + 1)), file) - with open(job_file) as f_job: - lines = f_job.readlines() - f.writelines(lines) - - # If text exists, compute CER - text_in = os.path.join(params["data_dir"], "text") - if os.path.exists(text_in): - text_proc_file = os.path.join(best_recog_path, "token") - compute_wer(text_in, text_proc_file, os.path.join(best_recog_path, "text.cer")) - os.system("tail -n 3 {}".format(os.path.join(best_recog_path, "text.cer"))) - - -if __name__ == "__main__": - params = {} - params["data_dir"] = "./data/test" - params["output_dir"] = "./results" - params["ngpu"] = 1 - params["njob"] = 8 - modelscope_infer(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/infer_after_finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/infer_after_finetune.py deleted file mode 100644 index f067c8193..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/infer_after_finetune.py +++ /dev/null @@ -1,54 +0,0 @@ -import json -import os -import shutil - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -from funasr.utils.compute_wer import compute_wer - - -def modelscope_infer_after_finetune(params): - # prepare for decoding - pretrained_model_path = os.path.join(os.environ["HOME"], ".cache/modelscope/hub", params["modelscope_model_name"]) - for file_name in params["required_files"]: - if file_name == "configuration.json": - with open(os.path.join(pretrained_model_path, file_name)) as f: - config_dict = json.load(f) - config_dict["model"]["am_model_name"] = params["decoding_model_name"] - with open(os.path.join(params["output_dir"], "configuration.json"), "w") as f: - json.dump(config_dict, f, indent=4, separators=(',', ': ')) - else: - shutil.copy(os.path.join(pretrained_model_path, file_name), - os.path.join(params["output_dir"], file_name)) - decoding_path = os.path.join(params["output_dir"], "decode_results") - if os.path.exists(decoding_path): - shutil.rmtree(decoding_path) - os.mkdir(decoding_path) - - # decoding - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=params["output_dir"], - output_dir=decoding_path, - batch_size=1 - ) - audio_in = os.path.join(params["data_dir"], "wav.scp") - inference_pipeline(audio_in=audio_in) - - # computer CER if GT text is set - text_in = os.path.join(params["data_dir"], "text") - if os.path.exists(text_in): - text_proc_file = os.path.join(decoding_path, "1best_recog/token") - compute_wer(text_in, text_proc_file, os.path.join(decoding_path, "text.cer")) - os.system("tail -n 3 {}".format(os.path.join(decoding_path, "text.cer"))) - - -if __name__ == '__main__': - params = {} - params["modelscope_model_name"] = "damo/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online" - params["required_files"] = ["am.mvn", "decoding.yaml", "configuration.json"] - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data/test" - params["decoding_model_name"] = "20epoch.pb" - modelscope_infer_after_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online/finetune.py deleted file mode 100644 index 75901db97..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online/infer.py deleted file mode 100644 index 305d990c8..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_fr.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch/finetune.py deleted file mode 100644 index 56fb58302..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch/infer.py deleted file mode 100644 index e0d1a4d35..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_he.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"offline"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-id-16k-common-vocab1067-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-id-16k-common-vocab1067-tensorflow1-online/finetune.py deleted file mode 100644 index 985b838ab..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-id-16k-common-vocab1067-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-id-16k-common-vocab1067-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-id-16k-common-vocab1067-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-id-16k-common-vocab1067-tensorflow1-online/infer.py deleted file mode 100644 index 75ec783de..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-id-16k-common-vocab1067-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_id.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-id-16k-common-vocab1067-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ja-16k-common-vocab93-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ja-16k-common-vocab93-tensorflow1-online/finetune.py deleted file mode 100644 index 4a5efdbe9..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ja-16k-common-vocab93-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-ja-16k-common-vocab93-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ja-16k-common-vocab93-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ja-16k-common-vocab93-tensorflow1-online/infer.py deleted file mode 100644 index a741e18e7..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ja-16k-common-vocab93-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_ja.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-ja-16k-common-vocab93-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ko-16k-common-vocab6400-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ko-16k-common-vocab6400-tensorflow1-online/finetune.py deleted file mode 100644 index 249aa2835..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ko-16k-common-vocab6400-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-ko-16k-common-vocab6400-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ko-16k-common-vocab6400-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ko-16k-common-vocab6400-tensorflow1-online/infer.py deleted file mode 100644 index 9be791ceb..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ko-16k-common-vocab6400-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_ko.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-ko-16k-common-vocab6400-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/README.md b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/README.md deleted file mode 100644 index 9a84f9b57..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained UniASR Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: `train/wav.scp`, `train/text`; `validation/wav.scp`, `validation/text` - - dataset_type: # for dataset larger than 1000 hours, set as `large`, otherwise set as `small` - - batch_bins: # batch size. For dataset_type is `small`, `batch_bins` indicates the feature frames. For dataset_type is `large`, `batch_bins` indicates the duration in ms - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed - - output_dir: # result dir - - ngpu: # the number of GPUs for decoding - - njob: # the number of jobs for each GPU - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` - -- Results - -The decoding results can be found in `$output_dir/1best_recog/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. - -### Inference using local finetuned model - -- Modify inference related parameters in `infer_after_finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed - - decoding_model_name: # set the checkpoint name for decoding, e.g., `valid.cer_ctc.ave.pb` - -- Then you can run the pipeline to finetune with: -```python - python infer_after_finetune.py -``` - -- Results - -The decoding results can be found in `$output_dir/decoding_results/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/demo.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/demo.py deleted file mode 100644 index 570f910fe..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/demo.py +++ /dev/null @@ -1,12 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -decoding_mode="normal" #fast, normal, offline -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825', - param_dict={"decoding_model": decoding_mode} -) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') -print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/finetune.py deleted file mode 100644 index 617c09157..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/finetune.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/infer.sh b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/infer.sh deleted file mode 100644 index b44be9f3c..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/infer.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825" -data_dir="./data/test" -output_dir="./results" -batch_size=1 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" -decoding_mode="normal" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} \ - --decoding_mode ${decoding_mode} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/utils b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/utils deleted file mode 120000 index 2ac163ff4..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-minnan-16k-common-vocab3825/utils +++ /dev/null @@ -1 +0,0 @@ -../../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch/finetune.py deleted file mode 100644 index 8bbce606c..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch/infer.py deleted file mode 100644 index b3a905859..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_my.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"offline"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online/finetune.py deleted file mode 100644 index 60f3c8208..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online/infer.py deleted file mode 100644 index 7029fd9c8..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_pt.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ru-16k-common-vocab1664-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ru-16k-common-vocab1664-tensorflow1-online/finetune.py deleted file mode 100644 index e8d61d983..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ru-16k-common-vocab1664-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-ru-16k-common-vocab1664-tensorflow1-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ru-16k-common-vocab1664-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ru-16k-common-vocab1664-tensorflow1-online/infer.py deleted file mode 100644 index 95da47935..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ru-16k-common-vocab1664-tensorflow1-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_ru.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-ru-16k-common-vocab1664-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/README.md b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/demo.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/demo.py deleted file mode 100644 index 181c30520..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/demo.py +++ /dev/null @@ -1,10 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch', - model_revision='v1.0.0') - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_tr.wav') -print(rec_result) \ No newline at end of file diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/finetune.py deleted file mode 100644 index 79fd34de4..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/finetune.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) \ No newline at end of file diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/infer.py deleted file mode 100644 index da8859eb0..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_tr.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"offline"}) - print(rec_result) \ No newline at end of file diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/infer.sh b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/infer.sh deleted file mode 100644 index 1caf3d02c..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/infer.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/utils b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/utils deleted file mode 120000 index dc7d4171f..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-tr-16k-common-vocab1582-pytorch/utils +++ /dev/null @@ -1 +0,0 @@ -../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/finetune.py deleted file mode 100644 index 5e313e533..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/infer.py deleted file mode 100644 index 04b02fe16..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_ur.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"offline"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online/finetune.py deleted file mode 100644 index 5be25850a..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params["output_dir"]): - os.makedirs(params["output_dir"], exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params["data_dir"]) - kwargs = dict( - model=params["model"], - model_revision=params["model_revision"], - data_dir=ds_dict, - dataset_type=params["dataset_type"], - work_dir=params["output_dir"], - batch_bins=params["batch_bins"], - max_epoch=params["max_epoch"], - lr=params["lr"]) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = {} - params["output_dir"] = "./checkpoint" - params["data_dir"] = "./data" - params["batch_bins"] = 2000 - params["dataset_type"] = "small" - params["max_epoch"] = 50 - params["lr"] = 0.00005 - params["model"] = "damo/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online" - params["model_revision"] = None - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online/infer.py deleted file mode 100644 index 355e412c4..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online/infer.py +++ /dev/null @@ -1,13 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == "__main__": - audio_in = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_vi.wav" - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, param_dict={"decoding_model":"normal"}) - print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/README.md b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/README.md deleted file mode 100644 index c68a8cd4f..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained Paraformer-large Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: train/wav.scp, train/text; validation/wav.scp, validation/text. - - batch_bins: # batch size - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - audio_in: # support wav, url, bytes, and parsed audio format. - - output_dir: # If the input format is wav.scp, it needs to be set. - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/finetune.py deleted file mode 100644 index 71a68d054..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision=params.model_revision, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - from funasr.utils.modelscope_param import modelscope_args - params = modelscope_args(model="damo/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/infer.py deleted file mode 100644 index f01b1dd9b..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/infer.py +++ /dev/null @@ -1,14 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in) - print(rec_result) - diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/README.md b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/README.md deleted file mode 100644 index 9a84f9b57..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained UniASR Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: `train/wav.scp`, `train/text`; `validation/wav.scp`, `validation/text` - - dataset_type: # for dataset larger than 1000 hours, set as `large`, otherwise set as `small` - - batch_bins: # batch size. For dataset_type is `small`, `batch_bins` indicates the feature frames. For dataset_type is `large`, `batch_bins` indicates the duration in ms - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed - - output_dir: # result dir - - ngpu: # the number of GPUs for decoding - - njob: # the number of jobs for each GPU - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` - -- Results - -The decoding results can be found in `$output_dir/1best_recog/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. - -### Inference using local finetuned model - -- Modify inference related parameters in `infer_after_finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include `test/wav.scp`. If `test/text` is also exists, CER will be computed - - decoding_model_name: # set the checkpoint name for decoding, e.g., `valid.cer_ctc.ave.pb` - -- Then you can run the pipeline to finetune with: -```python - python infer_after_finetune.py -``` - -- Results - -The decoding results can be found in `$output_dir/decoding_results/text.cer`, which includes recognition results of each sample and the CER metric of the whole test set. diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/demo.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/demo.py deleted file mode 100644 index 7ca71181b..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/demo.py +++ /dev/null @@ -1,12 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -decoding_mode="normal" #fast, normal, offline -inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online', - param_dict={"decoding_model": decoding_mode} -) - -rec_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') -print(rec_result) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/finetune.py deleted file mode 100644 index 65df8cbba..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/finetune.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer - -from funasr.datasets.ms_dataset import MsDataset -from funasr.utils.modelscope_param import modelscope_args - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - params = modelscope_args(model="damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/infer.sh b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/infer.sh deleted file mode 100644 index 2d7a2dae9..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/infer.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online" -data_dir="./data/test" -output_dir="./results" -batch_size=1 -gpu_inference=false # whether to perform gpu decoding -gpuid_list="-1" # set gpus, e.g., gpuid_list="0,1" -njob=32 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" -decoding_mode="normal" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} \ - --decoding_mode ${decoding_mode} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/utils b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/utils deleted file mode 120000 index 2ac163ff4..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/utils +++ /dev/null @@ -1 +0,0 @@ -../../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online/README.md b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online/README.md deleted file mode 100644 index c68a8cd4f..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# ModelScope Model - -## How to finetune and infer using a pretrained Paraformer-large Model - -### Finetune - -- Modify finetune training related parameters in `finetune.py` - - output_dir: # result dir - - data_dir: # the dataset dir needs to include files: train/wav.scp, train/text; validation/wav.scp, validation/text. - - batch_bins: # batch size - - max_epoch: # number of training epoch - - lr: # learning rate - -- Then you can run the pipeline to finetune with: -```python - python finetune.py -``` - -### Inference - -Or you can use the finetuned model for inference directly. - -- Setting parameters in `infer.py` - - audio_in: # support wav, url, bytes, and parsed audio format. - - output_dir: # If the input format is wav.scp, it needs to be set. - -- Then you can run the pipeline to infer with: -```python - python infer.py -``` diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online/finetune.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online/finetune.py deleted file mode 100644 index 435db1456..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision=params.model_revision, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - from funasr.utils.modelscope_param import modelscope_args - params = modelscope_args(model="damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) diff --git a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online/infer.py b/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online/infer.py deleted file mode 100644 index f1006481b..000000000 --- a/egs_modelscope/asr/uniasr/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online/infer.py +++ /dev/null @@ -1,14 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab8358-tensorflow1-online", - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in) - print(rec_result) - diff --git a/egs_modelscope/asr_vad_punc/TEMPLATE b/egs_modelscope/asr_vad_punc/TEMPLATE deleted file mode 120000 index f969ea0de..000000000 --- a/egs_modelscope/asr_vad_punc/TEMPLATE +++ /dev/null @@ -1 +0,0 @@ -../asr/TEMPLATE \ No newline at end of file diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/README.md b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/README.md deleted file mode 120000 index 92088a21d..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/README.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/README_zh.md b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/README_zh.md deleted file mode 120000 index b88b7fb57..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/demo.py b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/demo.py deleted file mode 100644 index 671e5c7ea..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/demo.py +++ /dev/null @@ -1,18 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_en.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020', - model_revision='v1.0.0', - vad_model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - punc_model='damo/punc_ct-transformer_cn-en-common-vocab471067-large', - punc_model_revision='v1.0.0', - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, batch_size_token=5000, batch_size_token_threshold_s=40, max_single_segment_time=6000) - print(rec_result) - diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/finetune.py b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/finetune.py deleted file mode 100644 index 7ca1bffa9..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision=params.model_revision, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - from funasr.utils.modelscope_param import modelscope_args - params = modelscope_args(model="damo/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 1000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - params.model_revision = "v1.0.1" - modelscope_finetune(params) \ No newline at end of file diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/infer.py b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/infer.py deleted file mode 100644 index 6f810ffa1..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/infer.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=args.model, - output_dir=args.output_dir, - param_dict={"decoding_model": args.decoding_mode, "hotword": args.hotword_txt} - ) - inference_pipeline(audio_in=args.audio_in, batch_size_token=args.batch_size_token) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020") - parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--decoding_mode', type=str, default="normal") - parser.add_argument('--hotword_txt', type=str, default=None) - parser.add_argument('--batch_size_token', type=int, default=5000) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/infer.sh b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/infer.sh deleted file mode 100644 index 36f40b6b3..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/infer.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/utils b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/utils deleted file mode 120000 index 3d3dd06b0..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020/utils +++ /dev/null @@ -1 +0,0 @@ -../../asr/TEMPLATE/utils \ No newline at end of file diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md deleted file mode 120000 index 92088a21d..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README_zh.md b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README_zh.md deleted file mode 120000 index b88b7fb57..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/demo.py b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/demo.py deleted file mode 100644 index a7cd74ba7..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/demo.py +++ /dev/null @@ -1,17 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/vad_example.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch', - vad_model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - #punc_model='damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch', - punc_model='damo/punc_ct-transformer_cn-en-common-vocab471067-large', - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, batch_size_token=5000, batch_size_token_threshold_s=40, max_single_segment_time=6000) - print(rec_result) - diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/finetune.py b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/finetune.py deleted file mode 100644 index a0acab0c2..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision=params.model_revision, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - from funasr.utils.modelscope_param import modelscope_args - params = modelscope_args(model="damo/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - params.model_revision = "v1.2.1" - modelscope_finetune(params) diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.py b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.py deleted file mode 100644 index f54399a14..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=args.model, - output_dir=args.output_dir, - param_dict={"decoding_model": args.decoding_mode, "hotword": args.hotword_txt} - ) - inference_pipeline(audio_in=args.audio_in, batch_size_token=args.batch_size_token) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch") - parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--decoding_mode', type=str, default="normal") - parser.add_argument('--hotword_txt', type=str, default=None) - parser.add_argument('--batch_size_token', type=int, default=5000) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh deleted file mode 100644 index ef49d7a60..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" -data_dir="./data/test" -output_dir="./results" -batch_size=64 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - -if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then - echo "Computing WER ..." - cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc - cp ${data_dir}/text ${output_dir}/1best_recog/text.ref - python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer - tail -n 3 ${output_dir}/1best_recog/text.cer -fi - -if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then - echo "SpeechIO TIOBE textnorm" - echo "$0 --> Normalizing REF text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${data_dir}/text \ - ${output_dir}/1best_recog/ref.txt - - echo "$0 --> Normalizing HYP text ..." - ./utils/textnorm_zh.py \ - --has_key --to_upper \ - ${output_dir}/1best_recog/text.proc \ - ${output_dir}/1best_recog/rec.txt - grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt - - echo "$0 --> computing WER/CER and alignment ..." - ./utils/error_rate_zh \ - --tokenizer char \ - --ref ${output_dir}/1best_recog/ref.txt \ - --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ - ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt - rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt -fi - diff --git a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/utils b/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/utils deleted file mode 120000 index 3d3dd06b0..000000000 --- a/egs_modelscope/asr_vad_punc/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/utils +++ /dev/null @@ -1 +0,0 @@ -../../asr/TEMPLATE/utils \ No newline at end of file diff --git a/egs_modelscope/asr_vad_spk/TEMPLATE b/egs_modelscope/asr_vad_spk/TEMPLATE deleted file mode 120000 index f969ea0de..000000000 --- a/egs_modelscope/asr_vad_spk/TEMPLATE +++ /dev/null @@ -1 +0,0 @@ -../asr/TEMPLATE \ No newline at end of file diff --git a/egs_modelscope/asr_vad_spk/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/demo.py b/egs_modelscope/asr_vad_spk/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/demo.py deleted file mode 100644 index 7b2bd18e3..000000000 --- a/egs_modelscope/asr_vad_spk/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/demo.py +++ /dev/null @@ -1,17 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_speaker_demo.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model='damo/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn', - model_revision='v0.0.2', - vad_model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - punc_model='damo/punc_ct-transformer_cn-en-common-vocab471067-large', - output_dir=output_dir, - ) - rec_result = inference_pipeline(audio_in=audio_in, batch_size_token=5000, batch_size_token_threshold_s=40, max_single_segment_time=6000) - print(rec_result) - diff --git a/egs_modelscope/asr_vad_spk/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/finetune.py b/egs_modelscope/asr_vad_spk/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/finetune.py deleted file mode 100644 index 52d2b9c41..000000000 --- a/egs_modelscope/asr_vad_spk/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/finetune.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from modelscope.metainfo import Trainers -from modelscope.trainers import build_trainer -from funasr.datasets.ms_dataset import MsDataset - - -def modelscope_finetune(params): - if not os.path.exists(params.output_dir): - os.makedirs(params.output_dir, exist_ok=True) - # dataset split ["train", "validation"] - ds_dict = MsDataset.load(params.data_path) - kwargs = dict( - model=params.model, - model_revision=params.model_revision, - data_dir=ds_dict, - dataset_type=params.dataset_type, - work_dir=params.output_dir, - batch_bins=params.batch_bins, - max_epoch=params.max_epoch, - lr=params.lr) - trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) - trainer.train() - - -if __name__ == '__main__': - from funasr.utils.modelscope_param import modelscope_args - params = modelscope_args(model="damo/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 - params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 - params.model_revision = "v1.2.1" - modelscope_finetune(params) diff --git a/egs_modelscope/asr_vad_spk/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/infer.py b/egs_modelscope/asr_vad_spk/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/infer.py deleted file mode 100644 index 4783ec1b0..000000000 --- a/egs_modelscope/asr_vad_spk/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn/infer.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model=args.model, - output_dir=args.output_dir, - param_dict={"decoding_model": args.decoding_mode, "hotword": args.hotword_txt} - ) - inference_pipeline(audio_in=args.audio_in, batch_size_token=args.batch_size_token) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn") - parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--decoding_mode', type=str, default="normal") - parser.add_argument('--hotword_txt', type=str, default=None) - parser.add_argument('--batch_size_token', type=int, default=5000) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/lm/speech_transformer_lm_zh-cn-common-vocab8404-pytorch/demo.py b/egs_modelscope/lm/speech_transformer_lm_zh-cn-common-vocab8404-pytorch/demo.py deleted file mode 100644 index 628cdd86b..000000000 --- a/egs_modelscope/lm/speech_transformer_lm_zh-cn-common-vocab8404-pytorch/demo.py +++ /dev/null @@ -1,17 +0,0 @@ - - -##################text二进制数据##################### -inputs = "hello 大 家 好 呀" - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.language_score_prediction, - model='damo/speech_transformer_lm_zh-cn-common-vocab8404-pytorch', - output_dir="./tmp/" -) - -rec_result = inference_pipeline(text_in=inputs) -print(rec_result) - diff --git a/egs_modelscope/punctuation/TEMPLATE/README.md b/egs_modelscope/punctuation/TEMPLATE/README.md deleted file mode 100644 index ac8a0072c..000000000 --- a/egs_modelscope/punctuation/TEMPLATE/README.md +++ /dev/null @@ -1,112 +0,0 @@ -([简体中文](./README_zh.md)|English) - -# Punctuation Restoration - -> **Note**: -> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetune. Here we take the model of the punctuation model of CT-Transformer as example to demonstrate the usage. - -## Inference - -### Quick start -#### [CT-Transformer model](https://www.modelscope.cn/models/damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.punctuation, - model='damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch', - model_revision=None) - -rec_result = inference_pipeline(text_in='example/punc_example.txt') -print(rec_result) -``` -- text二进制数据,例如:用户直接从文件里读出bytes数据 -```python -rec_result = inference_pipeline(text_in='我们都是木头人不会讲话不会动') -``` -- text文件url,例如:https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/punc_example.txt -```python -rec_result = inference_pipeline(text_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/punc_example.txt') -``` - -#### [CT-Transformer Realtime model](https://www.modelscope.cn/models/damo/punc_ct-transformer_zh-cn-common-vad_realtime-vocab272727/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.punctuation, - model='damo/punc_ct-transformer_zh-cn-common-vad_realtime-vocab272727', - model_revision=None, -) - -inputs = "跨境河流是养育沿岸|人民的生命之源长期以来为帮助下游地区防灾减灾中方技术人员|在上游地区极为恶劣的自然条件下克服巨大困难甚至冒着生命危险|向印方提供汛期水文资料处理紧急事件中方重视印方在跨境河流问题上的关切|愿意进一步完善双方联合工作机制|凡是|中方能做的我们|都会去做而且会做得更好我请印度朋友们放心中国在上游的|任何开发利用都会经过科学|规划和论证兼顾上下游的利益" -vads = inputs.split("|") -rec_result_all="outputs:" -param_dict = {"cache": []} -for vad in vads: - rec_result = inference_pipeline(text_in=vad, param_dict=param_dict) - rec_result_all += rec_result['text'] - -print(rec_result_all) -``` -Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/238) - - -### API-reference -#### Define pipeline -- `task`: `Tasks.punctuation` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU -- `output_dir`: `None` (Default), the output path of results if set -- `model_revision`: `None` (Default), setting the model version - -#### Infer pipeline -- `text_in`: the input to decode, which could be: - - text bytes, `e.g.`: "我们都是木头人不会讲话不会动" - - text file, `e.g.`: example/punc_example.txt - In this case of `text file` input, `output_dir` must be set to save the output results -- `param_dict`: reserving the cache which is necessary in realtime mode. - -### Inference with multi-thread CPUs or multi GPUs -FunASR also offer recipes [egs_modelscope/punctuation/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/punctuation/TEMPLATE/infer.sh) to decode with multi-thread CPUs, or multi GPUs. It is an offline recipe and only support offline model. - -#### Settings of `infer.sh` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `data_dir`: the dataset dir needs to include `punc.txt` -- `output_dir`: output dir of the recognition results -- `gpu_inference`: `true` (Default), whether to perform gpu decoding, set false for CPU inference -- `gpuid_list`: `0,1` (Default), which gpu_ids are used to infer -- `njob`: only used for CPU inference (`gpu_inference`=`false`), `64` (Default), the number of jobs for CPU decoding -- `checkpoint_dir`: only used for infer finetuned models, the path dir of finetuned models -- `checkpoint_name`: only used for infer finetuned models, `punc.pb` (Default), which checkpoint is used to infer - -#### Decode with multi GPUs: -```shell - bash infer.sh \ - --model "damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 1 \ - --gpu_inference true \ - --gpuid_list "0,1" -``` -#### Decode with multi-thread CPUs: -```shell - bash infer.sh \ - --model "damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 1 -``` - -## Finetune with pipeline - -### Quick start - -### Finetune with your data - -## Inference with your finetuned model - diff --git a/egs_modelscope/punctuation/TEMPLATE/README_zh.md b/egs_modelscope/punctuation/TEMPLATE/README_zh.md deleted file mode 100644 index f1284bb43..000000000 --- a/egs_modelscope/punctuation/TEMPLATE/README_zh.md +++ /dev/null @@ -1,112 +0,0 @@ -(简体中文|[English](./README.md)) -# 标点预测 - -> **Note**: -> Pipeline 支持在[modelscope模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope)中的所有模型进行推理和微调。在这里,我们以 CT-Transformer 模型为例来演示使用方法。 - -## 推理 - -### 快速使用 -#### [CT-Transformer 标点模型](https://www.modelscope.cn/models/damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.punctuation, - model='damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch', - model_revision=None) - -rec_result = inference_pipeline(text_in='example/punc_example.txt') -print(rec_result) -``` -- text二进制数据,例如:用户直接从文件里读出bytes数据 -```python -rec_result = inference_pipeline(text_in='我们都是木头人不会讲话不会动') -``` -- text文件url,例如:https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/punc_example.txt -```python -rec_result = inference_pipeline(text_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/punc_example.txt') -``` - -#### [CT-Transformer 实时标点模型](https://www.modelscope.cn/models/damo/punc_ct-transformer_zh-cn-common-vad_realtime-vocab272727/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.punctuation, - model='damo/punc_ct-transformer_zh-cn-common-vad_realtime-vocab272727', - model_revision=None, -) - -inputs = "跨境河流是养育沿岸|人民的生命之源长期以来为帮助下游地区防灾减灾中方技术人员|在上游地区极为恶劣的自然条件下克服巨大困难甚至冒着生命危险|向印方提供汛期水文资料处理紧急事件中方重视印方在跨境河流问题上的关切|愿意进一步完善双方联合工作机制|凡是|中方能做的我们|都会去做而且会做得更好我请印度朋友们放心中国在上游的|任何开发利用都会经过科学|规划和论证兼顾上下游的利益" -vads = inputs.split("|") -rec_result_all="outputs:" -param_dict = {"cache": []} -for vad in vads: - rec_result = inference_pipeline(text_in=vad, param_dict=param_dict) - rec_result_all += rec_result['text'] - -print(rec_result_all) -``` -演示例子完整代码请参考 [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/238) - -### API接口说明 -#### pipeline定义 -- `task`: `Tasks.punctuation` -- `model`: [模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) 中的模型名称,或本地磁盘中的模型路径 -- `ngpu`: `1`(默认),使用 GPU 进行推理。如果 ngpu=0,则使用 CPU 进行推理 -- `ncpu`: `1` (默认),设置用于 CPU 内部操作并行性的线程数 -- `output_dir`: `None` (默认),如果设置,输出结果的输出路径 -- `model_revision`: `None`(默认),modelscope中版本版本号 - - -#### pipeline推理 -- `text_in`: 需要进行推理的输入,支持一下输入: - - 文本字符,例如:"我们都是木头人不会讲话不会动" - - 文本文件,例如:example/punc_example.txt。 - 在使用文本文件 输入时,必须设置 `output_dir` 以保存输出结果。 -- `param_dict`: 在实时模式下必要的缓存。 - -### Inference with multi-thread CPUs or multi GPUs -FunASR 还提供了 [egs_modelscope/punctuation/TEMPLATE/infer.sh](infer.sh) 脚本,以使用多线程 CPU 或多个 GPU 进行解码。 - -#### `infer.sh` 设置 -- `model`: [modelscope模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope)中的模型名称,或本地磁盘中的模型路径 -- `data_dir`: 数据集目录需要包括 `punc.txt` 文件 -- `output_dir`: 识别结果的输出目录 -- `batch_size`: `1`(默认),在 GPU 上进行推理的批处理大小 -- `gpu_inference`: `true` (默认),是否执行 GPU 解码,如果进行 CPU 推理,则设置为 `false` -- `gpuid_list`: `0,1` (默认),用于推理的 GPU ID -- `njob`: 仅用于 CPU 推理(`gpu_inference=false`),`64`(默认),CPU 解码的作业数 - - -#### 使用多个 GPU 进行解码: -```shell - bash infer.sh \ - --model "damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 1 \ - --gpu_inference true \ - --gpuid_list "0,1" -``` -#### 使用多线程 CPU 进行解码: -```shell - bash infer.sh \ - --model "damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 1 -``` - -## Finetune with pipeline - -### Quick start - -### Finetune with your data - -## Inference with your finetuned model - diff --git a/egs_modelscope/punctuation/TEMPLATE/infer.py b/egs_modelscope/punctuation/TEMPLATE/infer.py deleted file mode 100644 index eeea170e9..000000000 --- a/egs_modelscope/punctuation/TEMPLATE/infer.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.punctuation, - model=args.model, - output_dir=args.output_dir, - ) - inference_pipeline(text_in=args.text_in) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/punc_ct-transformer_cn-en-common-vocab471067-large") - parser.add_argument('--text_in', type=str, default="./data/test/punc.txt") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/punctuation/TEMPLATE/infer.sh b/egs_modelscope/punctuation/TEMPLATE/infer.sh deleted file mode 100644 index 03bf3f496..000000000 --- a/egs_modelscope/punctuation/TEMPLATE/infer.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch" -data_dir="./data" -output_dir="./results" -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="punc.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/text.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/punc_example.txt ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --text_in ${output_dir}/split/text.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/final_res - if [ -f "${output_dir}/output.1/infer.out" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/infer.out" - done | sort -k1 >"${output_dir}/final_res/infer.out" - fi -fi - diff --git a/egs_modelscope/punctuation/TEMPLATE/utils b/egs_modelscope/punctuation/TEMPLATE/utils deleted file mode 120000 index dc7d4171f..000000000 --- a/egs_modelscope/punctuation/TEMPLATE/utils +++ /dev/null @@ -1 +0,0 @@ -../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/README.md b/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/README.md deleted file mode 120000 index 92088a21d..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/README.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/README_zh.md b/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/README_zh.md deleted file mode 120000 index b88b7fb57..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/data/punc_example.txt b/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/data/punc_example.txt deleted file mode 100644 index 367be7997..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/data/punc_example.txt +++ /dev/null @@ -1,3 +0,0 @@ -1 跨境河流是养育沿岸人民的生命之源长期以来为帮助下游地区防灾减灾中方技术人员在上游地区极为恶劣的自然条件下克服巨大困难甚至冒着生命危险向印方提供汛期水文资料处理紧急事件中方重视印方在跨境河流问题上的关切愿意进一步完善双方联合工作机制凡是中方能做的我们都会去做而且会做得更好我请印度朋友们放心中国在上游的任何开发利用都会经过科学规划和论证兼顾上下游的利益 -2 从存储上来说仅仅是全景图片它就会是图片的四倍的容量然后全景的视频会是普通视频八倍的这个存储的容要求而三d的模型会是图片的十倍这都对我们今天运行在的云计算的平台存储的平台提出了更高的要求 -3 那今天的会就到这里吧 happy new year 明年见 diff --git a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/demo.py b/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/demo.py deleted file mode 100644 index 070f2ee3c..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/demo.py +++ /dev/null @@ -1,22 +0,0 @@ - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.punctuation, - model='damo/punc_ct-transformer_cn-en-common-vocab471067-large', - model_revision="v1.0.0", - output_dir="./tmp/" -) - -##################text.scp################### -# inputs = "./egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/data/punc_example.txt" - -##################text##################### -#inputs = "我们都是木头人不会讲话不会动" - -##################text file url####################### -inputs = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/punc_example.txt" - -rec_result = inference_pipeline(text_in=inputs) -print(rec_result) diff --git a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/infer.py b/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/infer.py deleted file mode 100644 index 47503c253..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/infer.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.punctuation, - model=args.model, - model_revision=args.model_revision, - output_dir=args.output_dir, - ) - inference_pipeline(text_in=args.text_in) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/punc_ct-transformer_cn-en-common-vocab471067-large") - parser.add_argument('--text_in', type=str, default="./data/test/punc.txt") - parser.add_argument('--model_revision', type=str, default=None) - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/infer.sh b/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/infer.sh deleted file mode 100644 index 93296a519..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/infer.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/punc_ct-transformer_cn-en-common-vocab471067-large" -model_revision="v1.0.0" -data_dir="./data" -output_dir="./results" -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="punc.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/text.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/punc_example.txt ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --text_in ${output_dir}/split/text.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --model_revision ${model_revision} - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/final_res - if [ -f "${output_dir}/output.1/infer.out" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/infer.out" - done | sort -k1 >"${output_dir}/final_res/infer.out" - fi -fi - diff --git a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/utils b/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/utils deleted file mode 120000 index dc7d4171f..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_cn-en-common-vocab471067-large/utils +++ /dev/null @@ -1 +0,0 @@ -../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/README_zh.md b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/README_zh.md deleted file mode 120000 index b88b7fb57..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/demo.py b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/demo.py deleted file mode 100644 index 583a1eb0a..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/demo.py +++ /dev/null @@ -1,26 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -from modelscope.utils.logger import get_logger -import logging -logger = get_logger(log_level=logging.CRITICAL) -logger.setLevel(logging.CRITICAL) - - -inference_pipeline = pipeline( - task=Tasks.punctuation, - model='damo/punc_ct-transformer_zh-cn-common-vad_realtime-vocab272727', - model_revision='v1.0.2' -) - -##################text二进制数据##################### -inputs = "跨境河流是养育沿岸|人民的生命之源长期以来为帮助下游地区防灾减灾中方技术人员|在上游地区极为恶劣的自然条件下克服巨大困难甚至冒着生命危险|向印方提供汛期水文资料处理紧急事件中方重视印方在跨境河流问题上的关切|愿意进一步完善双方联合工作机制|凡是|中方能做的我们|都会去做而且会做得更好我请印度朋友们放心中国在上游的|任何开发利用都会经过科学|规划和论证兼顾上下游的利益" - -vads = inputs.split("|") -rec_result_all="outputs:" -param_dict = {"cache": []} -for vad in vads: - rec_result = inference_pipeline(text_in=vad, param_dict=param_dict) - rec_result_all += rec_result['text'] - -print(rec_result_all) - diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/README.md b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/README.md deleted file mode 120000 index 92088a21d..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/README.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/README_zh.md b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/README_zh.md deleted file mode 120000 index b88b7fb57..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/data/punc_example.txt b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/data/punc_example.txt deleted file mode 100644 index 367be7997..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/data/punc_example.txt +++ /dev/null @@ -1,3 +0,0 @@ -1 跨境河流是养育沿岸人民的生命之源长期以来为帮助下游地区防灾减灾中方技术人员在上游地区极为恶劣的自然条件下克服巨大困难甚至冒着生命危险向印方提供汛期水文资料处理紧急事件中方重视印方在跨境河流问题上的关切愿意进一步完善双方联合工作机制凡是中方能做的我们都会去做而且会做得更好我请印度朋友们放心中国在上游的任何开发利用都会经过科学规划和论证兼顾上下游的利益 -2 从存储上来说仅仅是全景图片它就会是图片的四倍的容量然后全景的视频会是普通视频八倍的这个存储的容要求而三d的模型会是图片的十倍这都对我们今天运行在的云计算的平台存储的平台提出了更高的要求 -3 那今天的会就到这里吧 happy new year 明年见 diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/demo.py b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/demo.py deleted file mode 100644 index 7383a5890..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/demo.py +++ /dev/null @@ -1,22 +0,0 @@ - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.punctuation, - model='damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch', - model_revision="v1.1.7", - output_dir="./tmp/" -) - -##################text.scp################### -# inputs = "./egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/data/punc_example.txt" - -##################text##################### -#inputs = "我们都是木头人不会讲话不会动" - -##################text file url####################### -inputs = "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/punc_example.txt" - -rec_result = inference_pipeline(text_in=inputs) -print(rec_result) diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/infer.py b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/infer.py deleted file mode 120000 index f05fbbb8b..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/infer.py +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/infer.sh b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/infer.sh deleted file mode 120000 index 0b3b38b6f..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/utils b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/utils deleted file mode 120000 index dc7d4171f..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/utils +++ /dev/null @@ -1 +0,0 @@ -../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/speaker_diarization/TEMPLATE/README.md b/egs_modelscope/speaker_diarization/TEMPLATE/README.md deleted file mode 100644 index 0b354ad05..000000000 --- a/egs_modelscope/speaker_diarization/TEMPLATE/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Speaker Diarization - -> **Note**: -> The modelscope pipeline supports all the models in -[model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) -to inference and finetune. Here we take the model of xvector_sv as example to demonstrate the usage. - -## Inference with pipeline -### Quick start -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -# initialize pipeline -inference_diar_pipline = pipeline( - mode="sond_demo", - num_workers=0, - task=Tasks.speaker_diarization, - diar_model_config="sond.yaml", - model='damo/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch', - reversion="v1.0.5", - sv_model="damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch", - sv_model_revision="v1.2.2", -) - -# input: a list of audio in which the first item is a speech recording to detect speakers, -# and the following wav file are used to extract speaker embeddings. -audio_list = [ - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/record.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk1.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk2.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk3.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk4.wav", -] - -results = inference_diar_pipline(audio_in=audio_list) -print(results) -``` - -### API-reference -#### Define pipeline -- `task`: `Tasks.speaker_diarization` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU -- `output_dir`: `None` (Default), the output path of results if set -- `batch_size`: `1` (Default), batch size when decoding -- `smooth_size`: `83` (Default), the window size to perform smoothing -- `dur_threshold`: `10` (Default), segments shorter than 100 ms will be dropped -- `out_format`: `vad` (Default), the output format, choices `["vad", "rttm"]`. - - vad format: spk1: [1.0, 3.0], [5.0, 8.0] - - rttm format: "SPEAKER test1 0 1.00 2.00 spk1 " and "SPEAKER test1 0 5.00 3.00 spk1 " - -#### Infer pipeline for speaker embedding extraction -- `audio_in`: the input to process, which could be: - - list of url: `e.g.`: waveform files at a website - - list of local file path: `e.g.`: path/to/a.wav - - ("wav.scp,speech,sound", "profile.scp,profile,kaldi_ark"): a script file of waveform files and another script file of speaker profiles (extracted with the [model](https://www.modelscope.cn/models/damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/summary)) - ```text - wav.scp - test1 path/to/enroll1.wav - test2 path/to/enroll2.wav - - profile.scp - test1 path/to/profile.ark:11 - test2 path/to/profile.ark:234 - ``` - The profile.ark file contains speaker embeddings in a kaldi-like style. - Please refer [README.md](../../speaker_verification/TEMPLATE/README.md) for more details. - -### Inference with you data -For single input, we recommend the "list of local file path" mode for inference. -For multiple inputs, we recommend the last mode with pre-organized wav.scp and profile.scp. - -### Inference with multi-threads on CPU -We recommend the last mode with split wav.scp and profile.scp. Then, run inference for each split part. -Please refer [README.md](../../speaker_verification/TEMPLATE/README.md) to find a similar process. - -### Inference with multi GPU -Similar to CPU, please set `ngpu=1` for inference on GPU. -Besides, you should use `CUDA_VISIBLE_DEVICES=0` to specify a GPU device. -Please refer [README.md](../../speaker_verification/TEMPLATE/README.md) to find a similar process. diff --git a/egs_modelscope/speaker_diarization/speech_diarization_eend-ola-en-us-callhome-8k/infer.py b/egs_modelscope/speaker_diarization/speech_diarization_eend-ola-en-us-callhome-8k/infer.py deleted file mode 100644 index 81cb2c629..000000000 --- a/egs_modelscope/speaker_diarization/speech_diarization_eend-ola-en-us-callhome-8k/infer.py +++ /dev/null @@ -1,10 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_diar_pipline = pipeline( - task=Tasks.speaker_diarization, - model='damo/speech_diarization_eend-ola-en-us-callhome-8k', - model_revision="v1.0.0", -) -results = inference_diar_pipline(audio_in=["https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/record2.wav"]) -print(results) \ No newline at end of file diff --git a/egs_modelscope/speaker_diarization/speech_diarization_sond-en-us-callhome-8k-n16k4-pytorch/infer.py b/egs_modelscope/speaker_diarization/speech_diarization_sond-en-us-callhome-8k-n16k4-pytorch/infer.py deleted file mode 100644 index 9e80d2be3..000000000 --- a/egs_modelscope/speaker_diarization/speech_diarization_sond-en-us-callhome-8k-n16k4-pytorch/infer.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Author: Speech Lab, Alibaba Group, China -TOLD: A Novel Two-Stage Overlap-Aware Framework for Speaker Diarization -https://arxiv.org/abs/2303.05397 -""" - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -# initialize the pipeline for inference -# when using the raw waveform files to inference, please use the config file `sond.yaml` -# and set mode to `sond_demo` -inference_diar_pipline = pipeline( - mode="sond_demo", - num_workers=0, - task=Tasks.speaker_diarization, - diar_model_config="sond.yaml", - model='damo/speech_diarization_sond-en-us-callhome-8k-n16k4-pytorch', - sv_model="damo/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch", - sv_model_revision="master", -) - -# use audio_list as the input, where the first one is the record to be detected -# and the following files are enrollments for different speakers -audio_list = [ - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/record.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/spk_A.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/spk_B.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/spk_B1.wav" -] - -results = inference_diar_pipline(audio_in=audio_list) -print(results) diff --git a/egs_modelscope/speaker_diarization/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch/infer.py b/egs_modelscope/speaker_diarization/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch/infer.py deleted file mode 100644 index aa0db9349..000000000 --- a/egs_modelscope/speaker_diarization/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch/infer.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Author: Speech Lab, Alibaba Group, China -SOND: Speaker Overlap-aware Neural Diarization for Multi-party Meeting Analysis -https://arxiv.org/abs/2211.10243 -""" - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -# initialize the pipeline for inference -# when using the raw waveform files to inference, please use the config file `sond.yaml` -# and set mode to `sond_demo` -inference_diar_pipline = pipeline( - mode="sond_demo", - num_workers=0, - task=Tasks.speaker_diarization, - diar_model_config="sond.yaml", - model='damo/speech_diarization_sond-zh-cn-alimeeting-16k-n16k4-pytorch', - sv_model="damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch", - sv_model_revision="v1.2.2", -) - -# use audio_list as the input, where the first one is the record to be detected -# and the following files are enrollments for different speakers -audio_list = [ - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/record.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk1.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk2.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk3.wav", - "https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/speaker_diarization/spk4.wav", -] - -results = inference_diar_pipline(audio_in=audio_list) -print(results) diff --git a/egs_modelscope/speaker_verification/TEMPLATE/README.md b/egs_modelscope/speaker_verification/TEMPLATE/README.md deleted file mode 100644 index d6736e378..000000000 --- a/egs_modelscope/speaker_verification/TEMPLATE/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# Speaker Verification - -> **Note**: -> The modelscope pipeline supports all the models in -[model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) -to inference and finetine. Here we take the model of xvector_sv as example to demonstrate the usage. - -## Inference with pipeline - -### Quick start -#### Speaker verification -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch' -) - -# The same speaker -rec_result = inference_sv_pipline(audio_in=( - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_enroll.wav', - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_same.wav')) -print("Similarity", rec_result["scores"]) - -# Different speakers -rec_result = inference_sv_pipline(audio_in=( - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_enroll.wav', - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_different.wav')) -print("Similarity", rec_result["scores"]) -``` -#### Speaker embedding extraction -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -# Define extraction pipeline -inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch' -) -# Extract speaker embedding -rec_result = inference_sv_pipline( - audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_enroll.wav') -speaker_embedding = rec_result["spk_embedding"] -``` -Full code of demo, please ref to [infer.py](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/infer.py). - -### API-reference -#### Define pipeline -- `task`: `Tasks.speaker_verification` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU -- `output_dir`: `None` (Default), the output path of results if set -- `batch_size`: `1` (Default), batch size when decoding -- `sv_threshold`: `0.9465` (Default), the similarity threshold to determine -whether utterances belong to the same speaker (it should be in (0, 1)) - -#### Infer pipeline for speaker embedding extraction -- `audio_in`: the input to process, which could be: - - url (str): `e.g.`: https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_enroll.wav - - local_path: `e.g.`: path/to/a.wav - - wav.scp: `e.g.`: path/to/wav1.scp - ```text - wav.scp - test1 path/to/enroll1.wav - test2 path/to/enroll2.wav - ``` - - bytes: `e.g.`: raw bytes data from a microphone - - fbank1.scp,speech,kaldi_ark: `e.g.`: extracted 80-dimensional fbank features -with kaldi toolkits. - -#### Infer pipeline for speaker verification -- `audio_in`: the input to process, which could be: - - Tuple(url1, url2): `e.g.`: (https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_enroll.wav, https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_different.wav) - - Tuple(local_path1, local_path2): `e.g.`: (path/to/a.wav, path/to/b.wav) - - Tuple(wav1.scp, wav2.scp): `e.g.`: (path/to/wav1.scp, path/to/wav2.scp) - ```text - wav1.scp - test1 path/to/enroll1.wav - test2 path/to/enroll2.wav - - wav2.scp - test1 path/to/same1.wav - test2 path/to/diff2.wav - ``` - - Tuple(bytes, bytes): `e.g.`: raw bytes data from a microphone - - Tuple("fbank1.scp,speech,kaldi_ark", "fbank2.scp,speech,kaldi_ark"): `e.g.`: extracted 80-dimensional fbank features -with kaldi toolkits. - -### Inference with you data -Use wav1.scp or fbank.scp to organize your own data to extract speaker embeddings or perform speaker verification. -In this case, the `output_dir` should be set to save all the embeddings or scores. - -### Inference with multi-threads on CPU -You can inference with multi-threads on CPU as follow steps: -1. Set `ngpu=0` while defining the pipeline in `infer.py`. -2. Split wav.scp to several files `e.g.: 4` - ```shell - split -l $((`wc -l < wav.scp`/4+1)) --numeric-suffixes wav.scp splits/wav.scp. - ``` -3. Start to extract embeddings - ```shell - for wav_scp in `ls splits/wav.scp.*`; do - infer.py ${wav_scp} outputs/$((basename ${wav_scp})) - done - ``` -4. The embeddings will be saved in `outputs/*` - -### Inference with multi GPU -Similar to inference on CPU, the difference are as follows: - -Step 1. Set `ngpu=1` while defining the pipeline in `infer.py`. - -Step 3. specify the gpu device with `CUDA_VISIBLE_DEVICES`: -```shell - for wav_scp in `ls splits/wav.scp.*`; do - CUDA_VISIBLE_DEVICES=1 infer.py ${wav_scp} outputs/$((basename ${wav_scp})) - done - ``` diff --git a/egs_modelscope/speaker_verification/TEMPLATE/infer.py b/egs_modelscope/speaker_verification/TEMPLATE/infer.py deleted file mode 100644 index efab09729..000000000 --- a/egs_modelscope/speaker_verification/TEMPLATE/infer.py +++ /dev/null @@ -1,15 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -import sys - -# Define extraction pipeline -inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch', - output_dir=sys.argv[2], -) -# Extract speaker embedding -rec_result = inference_sv_pipline( - audio_in=sys.argv[1], - -) diff --git a/egs_modelscope/speaker_verification/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch/demo.py b/egs_modelscope/speaker_verification/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch/demo.py deleted file mode 100644 index 1fd9dc614..000000000 --- a/egs_modelscope/speaker_verification/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch/demo.py +++ /dev/null @@ -1,39 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -import numpy as np - -if __name__ == '__main__': - inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch' - ) - - # extract speaker embedding - # for url use "spk_embedding" as key - rec_result = inference_sv_pipline( - audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/sv_example_enroll.wav') - enroll = rec_result["spk_embedding"] - - # for local file use "spk_embedding" as key - rec_result = inference_sv_pipline(audio_in='example/sv_example_same.wav') - same = rec_result["spk_embedding"] - - import soundfile - wav = soundfile.read('example/sv_example_enroll.wav')[0] - # for raw inputs use "spk_embedding" as key - spk_embedding = inference_sv_pipline(audio_in=wav)["spk_embedding"] - - rec_result = inference_sv_pipline( - audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/sv_example_different.wav') - different = rec_result["spk_embedding"] - - # calculate cosine similarity for same speaker - sv_threshold = 0.80 - same_cos = np.sum(enroll * same) / (np.linalg.norm(enroll) * np.linalg.norm(same)) - same_cos = max(same_cos - sv_threshold, 0.0) / (1.0 - sv_threshold) * 100.0 - print("Similarity:", same_cos) - - # calculate cosine similarity for different speaker - diff_cos = np.sum(enroll * different) / (np.linalg.norm(enroll) * np.linalg.norm(different)) - diff_cos = max(diff_cos - sv_threshold, 0.0) / (1.0 - sv_threshold) * 100.0 - print("Similarity:", diff_cos) diff --git a/egs_modelscope/speaker_verification/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch/infer_sv.py b/egs_modelscope/speaker_verification/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch/infer_sv.py deleted file mode 100644 index 880b2d3b1..000000000 --- a/egs_modelscope/speaker_verification/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch/infer_sv.py +++ /dev/null @@ -1,21 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-en-us-callhome-8k-spk6135-pytorch' - ) - - # the same speaker - rec_result = inference_sv_pipline(audio_in=( - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/sv_example_enroll.wav', - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/sv_example_same.wav')) - print("Similarity", rec_result["scores"]) - - # different speakers - rec_result = inference_sv_pipline(audio_in=( - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/sv_example_enroll.wav', - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_data/sv_example_different.wav')) - - print("Similarity", rec_result["scores"]) diff --git a/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/demo.py b/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/demo.py deleted file mode 100644 index 87f38013b..000000000 --- a/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/demo.py +++ /dev/null @@ -1,39 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -import numpy as np - -if __name__ == '__main__': - inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch' - ) - - # 提取不同句子的说话人嵌入码 - # for url use "utt_id" as key - rec_result = inference_sv_pipline( - audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_enroll.wav') - enroll = rec_result["spk_embedding"] - - # for local file use "utt_id" as key - rec_result = inference_sv_pipline(audio_in='sv_example_same.wav')["test1"] - same = rec_result["spk_embedding"] - - import soundfile - wav = soundfile.read('sv_example_enroll.wav')[0] - # for raw inputs use "utt_id" as key - spk_embedding = inference_sv_pipline(audio_in=wav)["spk_embedding"] - - rec_result = inference_sv_pipline( - audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_different.wav') - different = rec_result["spk_embedding"] - - # 对相同的说话人计算余弦相似度 - sv_threshold = 0.9465 - same_cos = np.sum(enroll * same) / (np.linalg.norm(enroll) * np.linalg.norm(same)) - same_cos = max(same_cos - sv_threshold, 0.0) / (1.0 - sv_threshold) * 100.0 - print("Similarity:", same_cos) - - # 对不同的说话人计算余弦相似度 - diff_cos = np.sum(enroll * different) / (np.linalg.norm(enroll) * np.linalg.norm(different)) - diff_cos = max(diff_cos - sv_threshold, 0.0) / (1.0 - sv_threshold) * 100.0 - print("Similarity:", diff_cos) diff --git a/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/eval_eer.py b/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/eval_eer.py deleted file mode 100644 index 717d36a65..000000000 --- a/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/eval_eer.py +++ /dev/null @@ -1,69 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -import os -import argparse -import numpy as np - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--eval_dir", type=str, default="eval") - parser.add_argument("--trials", type=str, default="eval/lists/trials.lst.speech") - parser.add_argument("--out_dir", type=str, default="./") - parser.add_argument("--verbose", action="store_true", default=False) - args = parser.parse_args() - - if not os.path.exists(args.out_dir): - os.makedirs(args.out_dir) - - inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch' - ) - - trials_list = [x.strip() for x in open(args.trials, "r").readlines()] - enroll_list = set([x.split(" ")[0] for x in trials_list]) - test_list = set([x.split(" ")[1] for x in trials_list]) - - print("extract embeddings for {} enrollments".format(len(enroll_list))) - enroll_embedding = {} - for enroll in enroll_list: - spk_embedding = inference_sv_pipline( - audio_in=os.path.join(args.eval_dir, "enroll", enroll+".wav") - )["spk_embedding"] - enroll_embedding[enroll] = spk_embedding - - test_embedding = {} - print("extract embeddings for {} tests".format(len(test_list))) - for test in test_list: - spk_embedding = inference_sv_pipline( - audio_in=os.path.join(args.eval_dir, "test", test+".wav") - )["spk_embedding"] - test_embedding[test] = spk_embedding - - print("calculate scores for {} trials".format(len(trials_list))) - fd = open(os.path.join(args.out_dir, "scores"), "w") - for trial in trials_list: - spk, utt, _ = trial.split(" ") - spk_emb = enroll_embedding[spk] - utt_emb = test_embedding[utt] - score = np.sum(spk_emb * utt_emb) / (np.linalg.norm(spk_emb) * np.linalg.norm(utt_emb)) - fd.write("{} {} {:.5f}\n".format(spk, utt, score)) - fd.close() - - from funasr.utils.compute_eer import compute_eer - from funasr.utils.compute_min_dcf import compute_min_dcf - eer, threshold = compute_eer(args.trials, os.path.join(args.out_dir, "scores")) - print("EER is {:.4f} at threshold {:.4f}".format(eer * 100.0, threshold)) - - mindcf, threshold = compute_min_dcf( - os.path.join(args.out_dir, "scores"), args.trials, - c_miss=10, p_target=0.01 - ) - print("minDCF is {0:.4f} at threshold {1:.4f} (p-target={2}, c-miss={3}, c-fa={4})\n".format( - mindcf, threshold, 0.01, 10, 1 - )) - - -if __name__ == '__main__': - main() diff --git a/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/infer_sv.py b/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/infer_sv.py deleted file mode 100644 index 7a5382740..000000000 --- a/egs_modelscope/speaker_verification/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch/infer_sv.py +++ /dev/null @@ -1,21 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - inference_sv_pipline = pipeline( - task=Tasks.speaker_verification, - model='damo/speech_xvector_sv-zh-cn-cnceleb-16k-spk3465-pytorch' - ) - - # the same speaker - rec_result = inference_sv_pipline(audio_in=( - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_enroll.wav', - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_same.wav')) - print("Similarity", rec_result["scores"]) - - # different speaker - rec_result = inference_sv_pipline(audio_in=( - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_enroll.wav', - 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/sv_example_different.wav')) - - print("Similarity", rec_result["scores"]) diff --git a/egs_modelscope/speech_separation/speech_separation_mossformer_8k_pytorch/demo.py b/egs_modelscope/speech_separation/speech_separation_mossformer_8k_pytorch/demo.py deleted file mode 100644 index 7399ee223..000000000 --- a/egs_modelscope/speech_separation/speech_separation_mossformer_8k_pytorch/demo.py +++ /dev/null @@ -1,15 +0,0 @@ -import numpy -import soundfile as sf -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -input = 'https://modelscope.cn/api/v1/models/damo/speech_separation_mossformer_8k_pytorch/repo?Revision=master&FilePath=examples/mix_speech1.wav' -separation = pipeline( - Tasks.speech_separation, - model='damo/speech_separation_mossformer_8k_pytorch', - output_dir='./', - model_revision='v1.0.2') -result = separation(audio_in=input) -for i, signal in enumerate(result): - save_file = f'output_spk_{i+1}.wav' - sf.write(save_file, signal, 8000) diff --git a/egs_modelscope/tp/TEMPLATE/README.md b/egs_modelscope/tp/TEMPLATE/README.md deleted file mode 100644 index ad5a9de58..000000000 --- a/egs_modelscope/tp/TEMPLATE/README.md +++ /dev/null @@ -1,104 +0,0 @@ -([简体中文](./README_zh.md)|English) - -# Timestamp Prediction (FA) - -## Inference - -### Quick start -#### [Use TP-Aligner Model Simply](https://modelscope.cn/models/damo/speech_timestamp_prediction-v1-16k-offline/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.speech_timestamp, - model='damo/speech_timestamp_prediction-v1-16k-offline', - model_revision='v1.1.0') - -rec_result = inference_pipeline( - audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_timestamps.wav', - text_in='一 个 东 太 平 洋 国 家 为 什 么 跑 到 西 太 平 洋 来 了 呢',) -print(rec_result) -``` - -Timestamp pipeline can also be used after ASR pipeline to compose complete ASR function, ref to [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/246). - - - -### API-reference -#### Define pipeline -- `task`: `Tasks.speech_timestamp` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU -- `ncpu`: `1` (Default), sets the number of threads used for intraop parallelism on CPU -- `output_dir`: `None` (Default), the output path of results if set -- `batch_size`: `1` (Default), batch size when decoding -#### Infer pipeline -- `audio_in`: the input speech to predict, which could be: - - wav_path, `e.g.`: asr_example.wav (wav in local or url), - - wav.scp, kaldi style wav list (`wav_id wav_path`), `e.g.`: - ```text - asr_example1 ./audios/asr_example1.wav - asr_example2 ./audios/asr_example2.wav - ``` - In this case of `wav.scp` input, `output_dir` must be set to save the output results -- `text_in`: the input text to predict, splited by blank, which could be: - - text string, `e.g.`: `今 天 天 气 怎 么 样` - - text.scp, kaldi style text file (`wav_id transcription`), `e.g.`: - ```text - asr_example1 今 天 天 气 怎 么 样 - asr_example2 欢 迎 体 验 达 摩 院 语 音 识 别 模 型 - ``` -- `audio_fs`: audio sampling rate, only set when audio_in is pcm audio -- `output_dir`: None (Default), the output path of results if set, containing - - output_dir/timestamp_prediction/tp_sync, timestamp in second containing silence periods, `wav_id# token1 start_time end_time;`, `e.g.`: - ```text - test_wav1# 0.000 0.500;温 0.500 0.680;州 0.680 0.840;化 0.840 1.040;工 1.040 1.280;仓 1.280 1.520; 1.520 1.680;库 1.680 1.920; 1.920 2.160;起 2.160 2.380;火 2.380 2.580;殃 2.580 2.760;及 2.760 2.920;附 2.920 3.100;近 3.100 3.340; 3.340 3.400;河 3.400 3.640; 3.640 3.700;流 3.700 3.940; 3.940 4.240;大 4.240 4.400;量 4.400 4.520;死 4.520 4.680;鱼 4.680 4.920; 4.920 4.940;漂 4.940 5.120;浮 5.120 5.300;河 5.300 5.500;面 5.500 5.900; 5.900 6.240; - ``` - - output_dir/timestamp_prediction/tp_time, timestamp list in ms of same length as input text without silence `wav_id# [[start_time, end_time],]`, `e.g.`: - ```text - test_wav1# [[500, 680], [680, 840], [840, 1040], [1040, 1280], [1280, 1520], [1680, 1920], [2160, 2380], [2380, 2580], [2580, 2760], [2760, 2920], [2920, 3100], [3100, 3340], [3400, 3640], [3700, 3940], [4240, 4400], [4400, 4520], [4520, 4680], [4680, 4920], [4940, 5120], [5120, 5300], [5300, 5500], [5500, 5900]] - ``` - -### Inference with multi-thread CPUs or multi GPUs -FunASR also offer recipes [egs_modelscope/tp/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/tp/TEMPLATE/infer.sh) to decode with multi-thread CPUs, or multi GPUs. - -#### Settings of `infer.sh` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `data_dir`: the dataset dir **must** include `wav.scp` and `text.txt` -- `output_dir`: output dir of the recognition results -- `batch_size`: `64` (Default), batch size of inference on gpu -- `gpu_inference`: `true` (Default), whether to perform gpu decoding, set false for CPU inference -- `gpuid_list`: `0,1` (Default), which gpu_ids are used to infer -- `njob`: only used for CPU inference (`gpu_inference`=`false`), `64` (Default), the number of jobs for CPU decoding -- `checkpoint_dir`: only used for infer finetuned models, the path dir of finetuned models -- `checkpoint_name`: only used for infer finetuned models, `valid.cer_ctc.ave.pb` (Default), which checkpoint is used to infer - -#### Decode with multi GPUs: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 1 \ - --gpu_inference true \ - --gpuid_list "0,1" -``` -#### Decode with multi-thread CPUs: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 1 -``` - -## Finetune with pipeline - -### Quick start - -### Finetune with your data - -## Inference with your finetuned model - diff --git a/egs_modelscope/tp/TEMPLATE/README_zh.md b/egs_modelscope/tp/TEMPLATE/README_zh.md deleted file mode 100644 index c8b1bc408..000000000 --- a/egs_modelscope/tp/TEMPLATE/README_zh.md +++ /dev/null @@ -1,102 +0,0 @@ -(简体中文|[English](./README.md)) - -# 时间戳预测 - -## 推理 - -### 快速使用 -#### [TP-Aligner 模型](https://modelscope.cn/models/damo/speech_timestamp_prediction-v1-16k-offline/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.speech_timestamp, - model='damo/speech_timestamp_prediction-v1-16k-offline', - model_revision='v1.1.0') - -rec_result = inference_pipeline( - audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_timestamps.wav', - text_in='一 个 东 太 平 洋 国 家 为 什 么 跑 到 西 太 平 洋 来 了 呢',) -print(rec_result) -``` - -Timestamp pipeline can also be used after ASR pipeline to compose complete ASR function, ref to [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/246). - -### API接口说明 -#### pipeline定义 -- `task`: `Tasks.speech_timestamp` -- `model`: [模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) 中的模型名称,或本地磁盘中的模型路径 -- `ngpu`: `1`(默认),使用 GPU 进行推理。如果 ngpu=0,则使用 CPU 进行推理 -- `ncpu`: `1` (默认),设置用于 CPU 内部操作并行性的线程数 -- `output_dir`: `None` (默认),如果设置,输出结果的输出路径 -- `batch_size`: `1` (默认),解码时的批处理大小 - - -#### Infer pipeline -- `audio_in`: 待预测的输入语音,可以是: - - wav文件路径,例如:asr_example.wav(本地或 URL 上的 wav 文件) - - wav.scp,kaldi 风格的 wav 列表 (`wav_id wav_path`),例如: - ```text - asr_example1 ./audios/asr_example1.wav - asr_example2 ./audios/asr_example2.wav - ``` - 在使用 `wav.scp` 输入时,必须设置 `output_dir` 以保存输出结果。 -- `text_in`: 待预测的输入文本,使用空格分隔,可以是: - - 文本字符串,例如:`今 天 天 气 怎 么 样` - - text.scp,kaldi 风格的文本文件(`wav_id transcription`),例如: - ```text - asr_example1 今 天 天 气 怎 么 样 - asr_example2 欢 迎 体 验 达 摩 院 语 音 识 别 模 型 - ``` -- `audio_fs`: 音频采样率,仅在输入为 PCM 音频时设置 -- `output_dir`: 默认为 None,如果设置,则为结果的输出路径,包含: - - output_dir/timestamp_prediction/tp_sync,带有静音段的以秒为单位的时间戳,`wav_id# token1 start_time end_time;`,例如: - ```text - test_wav1# 0.000 0.500;温 0.500 0.680;州 0.680 0.840;化 0.840 1.040;工 1.040 1.280;仓 1.280 1.520; 1.520 1.680;库 1.680 1.920; 1.920 2.160;起 2.160 2.380;火 2.380 2.580;殃 2.580 2.760;及 2.760 2.920;附 2.920 3.100;近 3.100 3.340; 3.340 3.400;河 3.400 3.640; 3.640 3.700;流 3.700 3.940; 3.940 4.240;大 4.240 4.400;量 4.400 4.520;死 4.520 4.680;鱼 4.680 4.920; 4.920 4.940;漂 4.940 5.120;浮 5.120 5.300;河 5.300 5.500;面 5.500 5.900; 5.900 6.240; - ``` - - output_dir/timestamp_prediction/tp_time,无静音的时间戳列表,以毫秒为单位,与输入文本长度相同,`wav_id# [[start_time, end_time],]`,例如: - ```text - test_wav1# [[500, 680], [680, 840], [840, 1040], [1040, 1280], [1280, 1520], [1680, 1920], [2160, 2380], [2380, 2580], [2580, 2760], [2760, 2920], [2920, 3100], [3100, 3340], [3400, 3640], [3700, 3940], [4240, 4400], [4400, 4520], [4520, 4680], [4680, 4920], [4940, 5120], [5120, 5300], [5300, 5500], [5500, 5900]] - ``` - -### 使用多线程 CPU 或多个 GPU 进行推理 -FunASR 还提供了 [egs_modelscope/tp/TEMPLATE/infer.sh](infer.sh) 脚本,以使用多线程 CPU 或多个 GPU 进行解码。 - -#### `infer.sh` 设置 -- `model`: [modelscope模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope)中的模型名称,或本地磁盘中的模型路径 -- `data_dir`: 数据集目录需要包括 `wav.scp` 文件。如果 `${data_dir}/text` 也存在,则将计算 CER -- `output_dir`: 识别结果的输出目录 -- `batch_size`: `1`(默认),在 GPU 上进行推理的批处理大小 -- `gpu_inference`: `true` (默认),是否执行 GPU 解码,如果进行 CPU 推理,则设置为 `false` -- `gpuid_list`: `0,1` (默认),用于推理的 GPU ID -- `njob`: 仅用于 CPU 推理(`gpu_inference=false`),`64`(默认),CPU 解码的作业数 - -#### 使用多个 GPU 进行解码: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 1 \ - --gpu_inference true \ - --gpuid_list "0,1" -``` -#### 使用多线程 CPU 进行解码: -```shell - bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 1 -``` - -## Finetune with pipeline - -### Quick start - -### Finetune with your data - -## Inference with your finetuned model - diff --git a/egs_modelscope/tp/TEMPLATE/infer.py b/egs_modelscope/tp/TEMPLATE/infer.py deleted file mode 100644 index 732c9845e..000000000 --- a/egs_modelscope/tp/TEMPLATE/infer.py +++ /dev/null @@ -1,29 +0,0 @@ -import os -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.speech_timestamp, - model=args.model, - model_revision='v1.1.0', - output_dir=args.output_dir, - batch_size=args.batch_size, - ) - if args.output_dir is not None: - inference_pipeline(audio_in=args.audio_in, text_in=args.text_in) - else: - print(inference_pipeline(audio_in=args.audio_in, text_in=args.text_in)) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_timestamp_prediction-v1-16k-offline") - parser.add_argument('--audio_in', type=str, default="https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_timestamps.wav") - parser.add_argument('--text_in', type=str, default="一 个 东 太 平 洋 国 家 为 什 么 跑 到 西 太 平 洋 来 了 呢") - parser.add_argument('--output_dir', type=str, default=None) - parser.add_argument('--batch_size', type=int, default=1) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) diff --git a/egs_modelscope/tp/TEMPLATE/infer.sh b/egs_modelscope/tp/TEMPLATE/infer.sh deleted file mode 100644 index bae62e8b8..000000000 --- a/egs_modelscope/tp/TEMPLATE/infer.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_timestamp_prediction-v1-16k-offline" -data_dir="./data/test" -output_dir="./results" -batch_size=1 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=4 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -split_texts="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" - split_texts="$split_texts $output_dir/split/text.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} -perl utils/split_scp.pl ${data_dir}/text.txt ${split_texts} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --text_in ${output_dir}/split/text.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/timestamp_prediction - for f in tp_sync tp_time; do - if [ -f "${output_dir}/output.1/timestamp_prediction/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/timestamp_prediction/${f}" - done | sort -k1 >"${output_dir}/timestamp_prediction/${f}" - fi - done -fi - diff --git a/egs_modelscope/tp/TEMPLATE/utils b/egs_modelscope/tp/TEMPLATE/utils deleted file mode 120000 index 04cf1f89e..000000000 --- a/egs_modelscope/tp/TEMPLATE/utils +++ /dev/null @@ -1 +0,0 @@ -../../vad/TEMPLATE/utils \ No newline at end of file diff --git a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/README.md b/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/README.md deleted file mode 120000 index 92088a21d..000000000 --- a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/README.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/demo.py b/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/demo.py deleted file mode 100644 index 581f7aadf..000000000 --- a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/demo.py +++ /dev/null @@ -1,12 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.speech_timestamp, - model='damo/speech_timestamp_prediction-v1-16k-offline', - model_revision='v1.1.0') - -rec_result = inference_pipeline( - audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_timestamps.wav', - text_in='一 个 东 太 平 洋 国 家 为 什 么 跑 到 西 太 平 洋 来 了 呢',) -print(rec_result) \ No newline at end of file diff --git a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/demo_long.py b/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/demo_long.py deleted file mode 100644 index 679782e27..000000000 --- a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/demo_long.py +++ /dev/null @@ -1,52 +0,0 @@ -# if you want to use ASR model besides paraformer-bicif (like contextual paraformer) -# to get ASR results for long audio as well as timestamp prediction results, -# try this demo -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -import os -import librosa -import soundfile as sf - -param_dict = dict() -param_dict['hotword'] = "你的热词" - -test_wav = 'YOUR_LONG_WAV.wav' -output_dir = './tmp' -os.system("mkdir -p {}".format(output_dir)) - -vad_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - model_revision=None, -) -asr_pipeline = pipeline( - task=Tasks.auto_speech_recognition, - model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404", - output_dir=output_dir) -tp_pipeline = pipeline( - task=Tasks.speech_timestamp, - model='damo/speech_timestamp_prediction-v1-16k-offline', - output_dir=output_dir) - -vad_res = vad_pipeline(audio_in=test_wav) -timestamps = vad_res['text'] - -samples = librosa.load(test_wav, sr=16000)[0] -wavseg_scp = "{}/wav.scp".format(output_dir) - -with open(wavseg_scp, 'w') as fout: - for i, timestamp in enumerate(timestamps): - start = int(timestamp[0]/1000*16000) - end = int(timestamp[1]/1000*16000) - uttid = "wav_{}_{} ".format(start, end) - wavpath = '{}/wavseg_{}.wav'.format(output_dir, i) - _samples = samples[start:end] - sf.write(wavpath, _samples, 16000) - fout.write("{} {}\n".format(uttid, wavpath)) -print("Wav segment done: {}".format(wavseg_scp)) - -asr_res = '{}/1best_recog/text'.format(output_dir) -tp_res = '{}/timestamp_prediction/tp_sync'.format(output_dir) -rec_result_asr = asr_pipeline(audio_in=wavseg_scp) -rec_result_tp = tp_pipeline(audio_in=wavseg_scp, text_in=asr_res) -print("Find your ASR results in {}, and timestamp prediction results in {}.".format(asr_res, tp_res)) \ No newline at end of file diff --git a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/infer.py b/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/infer.py deleted file mode 120000 index f05fbbb8b..000000000 --- a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/infer.py +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/infer.sh b/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/infer.sh deleted file mode 120000 index 0b3b38b6f..000000000 --- a/egs_modelscope/tp/speech_timestamp_prediction-v1-16k-offline/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/vad/TEMPLATE/README.md b/egs_modelscope/vad/TEMPLATE/README.md deleted file mode 100644 index 2651dce9f..000000000 --- a/egs_modelscope/vad/TEMPLATE/README.md +++ /dev/null @@ -1,112 +0,0 @@ -([简体中文](./README_zh.md)|English) - -# Voice Activity Detection - -> **Note**: -> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetune. Here we take the model of FSMN-VAD as example to demonstrate the usage. - -## Inference - -### Quick start -#### [FSMN-VAD model](https://modelscope.cn/models/damo/speech_fsmn_vad_zh-cn-16k-common-pytorch/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', -) - -segments_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/vad_example.wav') -print(segments_result) -``` -#### [FSMN-VAD-online model](https://modelscope.cn/models/damo/speech_fsmn_vad_zh-cn-16k-common-pytorch/summary) -```python -inference_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - ) -import soundfile -speech, sample_rate = soundfile.read("example/asr_example.wav") - -param_dict = {"in_cache": dict(), "is_final": False} -chunk_stride = 1600# 100ms -# first chunk, 100ms -speech_chunk = speech[0:chunk_stride] -rec_result = inference_pipeline(audio_in=speech_chunk, param_dict=param_dict) -print(rec_result) -# next chunk, 100ms -speech_chunk = speech[chunk_stride:chunk_stride+chunk_stride] -rec_result = inference_pipeline(audio_in=speech_chunk, param_dict=param_dict) -print(rec_result) -``` -Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/236) - - - -### API-reference -#### Define pipeline -- `task`: `Tasks.voice_activity_detection` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU -- `ncpu`: `1` (Default), sets the number of threads used for intraop parallelism on CPU -- `output_dir`: `None` (Default), the output path of results if set -- `batch_size`: `1` (Default), batch size when decoding -#### Infer pipeline -- `audio_in`: the input to decode, which could be: - - wav_path, `e.g.`: asr_example.wav, - - pcm_path, `e.g.`: asr_example.pcm, - - audio bytes stream, `e.g.`: bytes data from a microphone - - audio sample point,`e.g.`: `audio, rate = soundfile.read("asr_example_zh.wav")`, the dtype is numpy.ndarray or torch.Tensor - - wav.scp, kaldi style wav list (`wav_id \t wav_path`), `e.g.`: - ```text - asr_example1 ./audios/asr_example1.wav - asr_example2 ./audios/asr_example2.wav - ``` - In this case of `wav.scp` input, `output_dir` must be set to save the output results -- `audio_fs`: audio sampling rate, only set when audio_in is pcm audio -- `output_dir`: None (Default), the output path of results if set - -### Inference with multi-thread CPUs or multi GPUs -FunASR also offer recipes [egs_modelscope/vad/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/vad/TEMPLATE/infer.sh) to decode with multi-thread CPUs, or multi GPUs. - -#### Settings of `infer.sh` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk -- `data_dir`: the dataset dir needs to include `wav.scp` -- `output_dir`: output dir of the recognition results -- `batch_size`: `64` (Default), batch size of inference on gpu -- `gpu_inference`: `true` (Default), whether to perform gpu decoding, set false for CPU inference -- `gpuid_list`: `0,1` (Default), which gpu_ids are used to infer -- `njob`: only used for CPU inference (`gpu_inference`=`false`), `64` (Default), the number of jobs for CPU decoding -- `checkpoint_dir`: only used for infer finetuned models, the path dir of finetuned models -- `checkpoint_name`: only used for infer finetuned models, `valid.cer_ctc.ave.pb` (Default), which checkpoint is used to infer - -#### Decode with multi GPUs: -```shell - bash infer.sh \ - --model "damo/speech_fsmn_vad_zh-cn-16k-common-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 1 \ - --gpu_inference true \ - --gpuid_list "0,1" -``` -#### Decode with multi-thread CPUs: -```shell - bash infer.sh \ - --model "damo/speech_fsmn_vad_zh-cn-16k-common-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 64 -``` - -## Finetune with pipeline - -### Quick start - -### Finetune with your data - -## Inference with your finetuned model - diff --git a/egs_modelscope/vad/TEMPLATE/README_zh.md b/egs_modelscope/vad/TEMPLATE/README_zh.md deleted file mode 100644 index 8157e073a..000000000 --- a/egs_modelscope/vad/TEMPLATE/README_zh.md +++ /dev/null @@ -1,113 +0,0 @@ -(简体中文|[English](./README.md)) - -# 语音端点检测 - -> **注意**: -> Pipeline 支持在[modelscope模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope)中的所有模型进行推理和微调。在这里,我们以 FSMN-VAD 模型为例来演示使用方法。 - -## 推理 - -### 快速使用 -#### [FSMN-VAD 模型](https://modelscope.cn/models/damo/speech_fsmn_vad_zh-cn-16k-common-pytorch/summary) -```python -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -inference_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', -) - -segments_result = inference_pipeline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/vad_example.wav') -print(segments_result) -``` -#### [FSMN-VAD-实时模型](https://modelscope.cn/models/damo/speech_fsmn_vad_zh-cn-16k-common-pytorch/summary) -```python -inference_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model='damo/speech_fsmn_vad_zh-cn-16k-common-pytorch', - ) -import soundfile -speech, sample_rate = soundfile.read("example/asr_example.wav") - -param_dict = {"in_cache": dict(), "is_final": False} -chunk_stride = 1600# 100ms -# first chunk, 100ms -speech_chunk = speech[0:chunk_stride] -rec_result = inference_pipeline(audio_in=speech_chunk, param_dict=param_dict) -print(rec_result) -# next chunk, 100ms -speech_chunk = speech[chunk_stride:chunk_stride+chunk_stride] -rec_result = inference_pipeline(audio_in=speech_chunk, param_dict=param_dict) -print(rec_result) -``` -演示示例,完整代码请参考 [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/236) - - - -### API接口说明 -#### pipeline定义 -- `task`: `Tasks.voice_activity_detection` -- `model`: [模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) 中的模型名称,或本地磁盘中的模型路径 -- `ngpu`: `1`(默认),使用 GPU 进行推理。如果 ngpu=0,则使用 CPU 进行推理 -- `ncpu`: `1` (默认),设置用于 CPU 内部操作并行性的线程数 -- `output_dir`: `None` (默认),如果设置,输出结果的输出路径 -- `batch_size`: `1` (默认),解码时的批处理大小 -#### pipeline 推理 -- `audio_in`: 要解码的输入,可以是: - - wav文件路径, 例如: asr_example.wav, - - pcm文件路径, 例如: asr_example.pcm, - - 音频字节数流,例如:麦克风的字节数数据 - - 音频采样点,例如:`audio, rate = soundfile.read("asr_example_zh.wav")`, 数据类型为 numpy.ndarray 或者 torch.Tensor - - wav.scp,kaldi 样式的 wav 列表 (`wav_id \t wav_path`), 例如: - ```text - asr_example1 ./audios/asr_example1.wav - asr_example2 ./audios/asr_example2.wav - ``` - 在这种输入 `wav.scp` 的情况下,必须设置 `output_dir` 以保存输出结果 -- `audio_fs`: 音频采样率,仅在 audio_in 为 pcm 音频时设置 -- `output_dir`: None (默认),如果设置,输出结果的输出路径 - - -### 使用多线程 CPU 或多个 GPU 进行推理 -FunASR 还提供了 [egs_modelscope/vad/TEMPLATE/infer.sh](infer.sh) 脚本,以使用多线程 CPU 或多个 GPU 进行解码。 - -#### `infer.sh` 设置 -- `model`: [modelscope模型仓库](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope)中的模型名称,或本地磁盘中的模型路径 -- `data_dir`: 数据集目录需要包括 `wav.scp` 文件。如果 `${data_dir}/text` 也存在,则将计算 CER -- `output_dir`: 识别结果的输出目录 -- `batch_size`: `1`(默认),在 GPU 上进行推理的批处理大小 -- `gpu_inference`: `true` (默认),是否执行 GPU 解码,如果进行 CPU 推理,则设置为 `false` -- `gpuid_list`: `0,1` (默认),用于推理的 GPU ID -- `njob`: 仅用于 CPU 推理(`gpu_inference=false`),`64`(默认),CPU 解码的作业数 - -#### 使用多个 GPU 进行解码: -```shell - bash infer.sh \ - --model "damo/speech_fsmn_vad_zh-cn-16k-common-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --batch_size 1 \ - --gpu_inference true \ - --gpuid_list "0,1" -``` -#### 使用多线程 CPU 进行解码: -```shell - bash infer.sh \ - --model "damo/speech_fsmn_vad_zh-cn-16k-common-pytorch" \ - --data_dir "./data/test" \ - --output_dir "./results" \ - --gpu_inference false \ - --njob 64 -``` - - - -## Finetune with pipeline - -### Quick start - -### Finetune with your data - -## Inference with your finetuned model - diff --git a/egs_modelscope/vad/TEMPLATE/infer.py b/egs_modelscope/vad/TEMPLATE/infer.py deleted file mode 100644 index f49ab4b79..000000000 --- a/egs_modelscope/vad/TEMPLATE/infer.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -import shutil -import argparse -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -def modelscope_infer(args): - os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpuid) - inference_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model=args.model, - output_dir=args.output_dir, - batch_size=args.batch_size, - ) - inference_pipeline(audio_in=args.audio_in) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_fsmn_vad_zh-cn-16k-common-pytorch") - parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") - parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--batch_size', type=int, default=1) - parser.add_argument('--gpuid', type=str, default="0") - args = parser.parse_args() - modelscope_infer(args) \ No newline at end of file diff --git a/egs_modelscope/vad/TEMPLATE/infer.sh b/egs_modelscope/vad/TEMPLATE/infer.sh deleted file mode 100644 index 0651c98f8..000000000 --- a/egs_modelscope/vad/TEMPLATE/infer.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -stage=1 -stop_stage=2 -model="damo/speech_fsmn_vad_zh-cn-16k-common" -data_dir="./data/test" -output_dir="./results" -batch_size=1 -gpu_inference=true # whether to perform gpu decoding -gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" -njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob -checkpoint_dir= -checkpoint_name="valid.cer_ctc.ave.pb" - -. utils/parse_options.sh || exit 1; - -if ${gpu_inference} == "true"; then - nj=$(echo $gpuid_list | awk -F "," '{print NF}') -else - nj=$njob - batch_size=1 - gpuid_list="" - for JOB in $(seq ${nj}); do - gpuid_list=$gpuid_list"-1," - done -fi - -mkdir -p $output_dir/split -split_scps="" -for JOB in $(seq ${nj}); do - split_scps="$split_scps $output_dir/split/wav.$JOB.scp" -done -perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} - -if [ -n "${checkpoint_dir}" ]; then - python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} - model=${checkpoint_dir}/${model} -fi - -if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then - echo "Decoding ..." - gpuid_list_array=(${gpuid_list//,/ }) - for JOB in $(seq ${nj}); do - { - id=$((JOB-1)) - gpuid=${gpuid_list_array[$id]} - mkdir -p ${output_dir}/output.$JOB - python infer.py \ - --model ${model} \ - --audio_in ${output_dir}/split/wav.$JOB.scp \ - --output_dir ${output_dir}/output.$JOB \ - --batch_size ${batch_size} \ - --gpuid ${gpuid} - }& - done - wait - - mkdir -p ${output_dir}/1best_recog - for f in token score text; do - if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then - for i in $(seq "${nj}"); do - cat "${output_dir}/output.${i}/1best_recog/${f}" - done | sort -k1 >"${output_dir}/1best_recog/${f}" - fi - done -fi - diff --git a/egs_modelscope/vad/TEMPLATE/utils b/egs_modelscope/vad/TEMPLATE/utils deleted file mode 120000 index dc7d4171f..000000000 --- a/egs_modelscope/vad/TEMPLATE/utils +++ /dev/null @@ -1 +0,0 @@ -../../../egs/aishell/transformer/utils \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README.md b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README.md deleted file mode 120000 index 92088a21d..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README_zh.md b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README_zh.md deleted file mode 120000 index b88b7fb57..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo.py deleted file mode 100644 index 9fa822839..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo.py +++ /dev/null @@ -1,15 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/vad_example.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model="damo/speech_fsmn_vad_zh-cn-16k-common-pytorch", - model_revision=None, - output_dir=output_dir, - batch_size=1, - ) - segments_result = inference_pipeline(audio_in=audio_in) - print(segments_result) diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo_online.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo_online.py deleted file mode 100644 index 16ebd5839..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo_online.py +++ /dev/null @@ -1,36 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -from modelscope.utils.logger import get_logger -import logging -logger = get_logger(log_level=logging.CRITICAL) -logger.setLevel(logging.CRITICAL) -import soundfile - -if __name__ == '__main__': - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model="damo/speech_fsmn_vad_zh-cn-16k-common-pytorch", - model_revision='v1.2.0', - output_dir=output_dir, - batch_size=1, - mode='online', - ) - speech, sample_rate = soundfile.read("./vad_example_16k.wav") - speech_length = speech.shape[0] - - sample_offset = 0 - - step = 160 * 10 - param_dict = {'in_cache': dict(), 'max_end_sil': 800} - for sample_offset in range(0, speech_length, min(step, speech_length - sample_offset)): - if sample_offset + step >= speech_length - 1: - step = speech_length - sample_offset - is_final = True - else: - is_final = False - param_dict['is_final'] = is_final - segments_result = inference_pipeline(audio_in=speech[sample_offset: sample_offset + step], - param_dict=param_dict) - print(segments_result) - diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.py deleted file mode 120000 index f05fbbb8b..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.py +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.sh b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.sh deleted file mode 120000 index 0b3b38b6f..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README.md b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README.md deleted file mode 120000 index 92088a21d..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README_zh.md b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README_zh.md deleted file mode 120000 index b88b7fb57..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README_zh.md +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/README_zh.md \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo.py deleted file mode 100644 index 6bd491bc9..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo.py +++ /dev/null @@ -1,15 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks - -if __name__ == '__main__': - audio_in = 'https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/vad_example_8k.wav' - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model="damo/speech_fsmn_vad_zh-cn-8k-common", - model_revision=None, - output_dir=output_dir, - batch_size=1, - ) - segments_result = inference_pipeline(audio_in=audio_in) - print(segments_result) diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo_online.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo_online.py deleted file mode 100644 index d777089db..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo_online.py +++ /dev/null @@ -1,36 +0,0 @@ -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -from modelscope.utils.logger import get_logger -import logging -logger = get_logger(log_level=logging.CRITICAL) -logger.setLevel(logging.CRITICAL) -import soundfile - -if __name__ == '__main__': - output_dir = "./results" - inference_pipeline = pipeline( - task=Tasks.voice_activity_detection, - model="damo/speech_fsmn_vad_zh-cn-8k-common", - model_revision=None, - output_dir=output_dir, - batch_size=1, - mode='online', - ) - speech, sample_rate = soundfile.read("./vad_example_8k.wav") - speech_length = speech.shape[0] - - sample_offset = 0 - - step = 80 * 10 - param_dict = {'in_cache': dict(), 'max_end_sil': 800} - for sample_offset in range(0, speech_length, min(step, speech_length - sample_offset)): - if sample_offset + step >= speech_length - 1: - step = speech_length - sample_offset - is_final = True - else: - is_final = False - param_dict['is_final'] = is_final - segments_result = inference_pipeline(audio_in=speech[sample_offset: sample_offset + step], - param_dict=param_dict) - print(segments_result) - diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.py deleted file mode 120000 index f05fbbb8b..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.py +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.sh b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.sh deleted file mode 120000 index 0b3b38b6f..000000000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.sh \ No newline at end of file diff --git a/funasr/bin/inference.py b/funasr/bin/inference.py index 4e140e1d6..d63ebc99b 100644 --- a/funasr/bin/inference.py +++ b/funasr/bin/inference.py @@ -7,13 +7,13 @@ import json from omegaconf import DictConfig, OmegaConf from funasr.utils.dynamic_import import dynamic_import import logging -from funasr.utils.download_from_hub import download_model -from funasr.torch_utils.set_all_random_seed import set_all_random_seed +from funasr.download.download_from_hub import download_model +from funasr.train_utils.set_all_random_seed import set_all_random_seed from funasr.tokenizer.funtoken import build_tokenizer from funasr.datasets.fun_datasets.load_audio_extract_fbank import load_bytes -from funasr.torch_utils.device_funcs import to_device +from funasr.train_utils.device_funcs import to_device from tqdm import tqdm -from funasr.torch_utils.load_pretrained_model import load_pretrained_model +from funasr.train_utils.load_pretrained_model import load_pretrained_model import time import random import string diff --git a/funasr/bin/train.py b/funasr/bin/train.py index 4187476f8..6a88233d3 100644 --- a/funasr/bin/train.py +++ b/funasr/bin/train.py @@ -7,25 +7,25 @@ from collections.abc import Sequence import torch import hydra from omegaconf import DictConfig, OmegaConf -from funasr.torch_utils.set_all_random_seed import set_all_random_seed +from funasr.train_utils.set_all_random_seed import set_all_random_seed # from funasr.model_class_factory1 import model_choices -from funasr.modules.lora.utils import mark_only_lora_as_trainable +from funasr.models.lora.utils import mark_only_lora_as_trainable from funasr.optimizers import optim_choices from funasr.schedulers import scheduler_choices -from funasr.torch_utils.load_pretrained_model import load_pretrained_model -from funasr.torch_utils.initialize import initialize -from funasr.datasets.data_sampler import BatchSampler +from funasr.train_utils.load_pretrained_model import load_pretrained_model +from funasr.train_utils.initialize import initialize +from funasr.datasets.fun_datasets.data_sampler import BatchSampler # from funasr.tokenizer.build_tokenizer import build_tokenizer # from funasr.tokenizer.token_id_converter import TokenIDConverter from funasr.tokenizer.funtoken import build_tokenizer -from funasr.datasets.dataset_jsonl import AudioDataset -from funasr.utils.trainer import Trainer +from funasr.datasets.fun_datasets.dataset_jsonl import AudioDataset +from funasr.train_utils.trainer import Trainer # from funasr.utils.load_fr_py import load_class_from_path from funasr.utils.dynamic_import import dynamic_import import torch.distributed as dist from torch.nn.parallel import DistributedDataParallel as DDP from torch.distributed.fsdp import FullyShardedDataParallel as FSDP -from funasr.utils.download_from_hub import download_model +from funasr.download.download_from_hub import download_model @hydra.main(config_name=None, version_base=None) def main_hydra(kwargs: DictConfig): diff --git a/funasr/datasets/collate_fn.py b/funasr/datasets/collate_fn.py deleted file mode 100644 index 7ff70a76a..000000000 --- a/funasr/datasets/collate_fn.py +++ /dev/null @@ -1,196 +0,0 @@ -from typing import Collection -from typing import Dict -from typing import List -from typing import Tuple -from typing import Union - -import numpy as np -import torch -from funasr.modules.nets_utils import pad_list, pad_list_all_dim - - -class CommonCollateFn: - """Functor class of common_collate_fn()""" - - def __init__( - self, - float_pad_value: Union[float, int] = 0.0, - int_pad_value: int = -32768, - not_sequence: Collection[str] = (), - max_sample_size=None - ): - self.float_pad_value = float_pad_value - self.int_pad_value = int_pad_value - self.not_sequence = set(not_sequence) - self.max_sample_size = max_sample_size - - def __repr__(self): - return ( - f"{self.__class__}(float_pad_value={self.float_pad_value}, " - f"int_pad_value={self.float_pad_value})" - ) - - def __call__( - self, data: Collection[Tuple[str, Dict[str, np.ndarray]]] - ) -> Tuple[List[str], Dict[str, torch.Tensor]]: - return common_collate_fn( - data, - float_pad_value=self.float_pad_value, - int_pad_value=self.int_pad_value, - not_sequence=self.not_sequence, - ) - - -def common_collate_fn( - data: Collection[Tuple[str, Dict[str, np.ndarray]]], - float_pad_value: Union[float, int] = 0.0, - int_pad_value: int = -32768, - not_sequence: Collection[str] = (), -) -> Tuple[List[str], Dict[str, torch.Tensor]]: - """Concatenate ndarray-list to an array and convert to torch.Tensor. - """ - uttids = [u for u, _ in data] - data = [d for _, d in data] - - assert all(set(data[0]) == set(d) for d in data), "dict-keys mismatching" - assert all( - not k.endswith("_lengths") for k in data[0] - ), f"*_lengths is reserved: {list(data[0])}" - - output = {} - for key in data[0]: - if data[0][key].dtype.kind == "i": - pad_value = int_pad_value - else: - pad_value = float_pad_value - - array_list = [d[key] for d in data] - tensor_list = [torch.from_numpy(a) for a in array_list] - tensor = pad_list(tensor_list, pad_value) - output[key] = tensor - - if key not in not_sequence: - lens = torch.tensor([d[key].shape[0] for d in data], dtype=torch.long) - output[key + "_lengths"] = lens - - output = (uttids, output) - return output - - -class DiarCollateFn: - """Functor class of common_collate_fn()""" - - def __init__( - self, - float_pad_value: Union[float, int] = 0.0, - int_pad_value: int = -32768, - not_sequence: Collection[str] = (), - max_sample_size=None - ): - self.float_pad_value = float_pad_value - self.int_pad_value = int_pad_value - self.not_sequence = set(not_sequence) - self.max_sample_size = max_sample_size - - def __repr__(self): - return ( - f"{self.__class__}(float_pad_value={self.float_pad_value}, " - f"int_pad_value={self.float_pad_value})" - ) - - def __call__( - self, data: Collection[Tuple[str, Dict[str, np.ndarray]]] - ) -> Tuple[List[str], Dict[str, torch.Tensor]]: - return diar_collate_fn( - data, - float_pad_value=self.float_pad_value, - int_pad_value=self.int_pad_value, - not_sequence=self.not_sequence, - ) - - -def diar_collate_fn( - data: Collection[Tuple[str, Dict[str, np.ndarray]]], - float_pad_value: Union[float, int] = 0.0, - int_pad_value: int = -32768, - not_sequence: Collection[str] = (), -) -> Tuple[List[str], Dict[str, torch.Tensor]]: - """Concatenate ndarray-list to an array and convert to torch.Tensor. - """ - uttids = [u for u, _ in data] - data = [d for _, d in data] - - assert all(set(data[0]) == set(d) for d in data), "dict-keys mismatching" - assert all( - not k.endswith("_lengths") for k in data[0] - ), f"*_lengths is reserved: {list(data[0])}" - - output = {} - for key in data[0]: - if data[0][key].dtype.kind == "i": - pad_value = int_pad_value - else: - pad_value = float_pad_value - - array_list = [d[key] for d in data] - tensor_list = [torch.from_numpy(a) for a in array_list] - tensor = pad_list_all_dim(tensor_list, pad_value) - output[key] = tensor - - if key not in not_sequence: - lens = torch.tensor([d[key].shape[0] for d in data], dtype=torch.long) - output[key + "_lengths"] = lens - - output = (uttids, output) - return output - - -def crop_to_max_size(feature, target_size): - size = len(feature) - diff = size - target_size - if diff <= 0: - return feature - - start = np.random.randint(0, diff + 1) - end = size - diff + start - return feature[start:end] - - -def clipping_collate_fn( - data: Collection[Tuple[str, Dict[str, np.ndarray]]], - max_sample_size=None, - not_sequence: Collection[str] = (), -) -> Tuple[List[str], Dict[str, torch.Tensor]]: - # mainly for pre-training - uttids = [u for u, _ in data] - data = [d for _, d in data] - - assert all(set(data[0]) == set(d) for d in data), "dict-keys mismatching" - assert all( - not k.endswith("_lengths") for k in data[0] - ), f"*_lengths is reserved: {list(data[0])}" - - output = {} - for key in data[0]: - array_list = [d[key] for d in data] - tensor_list = [torch.from_numpy(a) for a in array_list] - sizes = [len(s) for s in tensor_list] - if max_sample_size is None: - target_size = min(sizes) - else: - target_size = min(min(sizes), max_sample_size) - tensor = tensor_list[0].new_zeros(len(tensor_list), target_size, tensor_list[0].shape[1]) - for i, (source, size) in enumerate(zip(tensor_list, sizes)): - diff = size - target_size - if diff == 0: - tensor[i] = source - else: - tensor[i] = crop_to_max_size(source, target_size) - output[key] = tensor - - if key not in not_sequence: - lens = torch.tensor([source.shape[0] for source in tensor], dtype=torch.long) - output[key + "_lengths"] = lens - - output = (uttids, output) - return output \ No newline at end of file diff --git a/funasr/datasets/dataset.py b/funasr/datasets/dataset.py deleted file mode 100644 index 673a9b2c9..000000000 --- a/funasr/datasets/dataset.py +++ /dev/null @@ -1,444 +0,0 @@ -# Copyright ESPnet (https://github.com/espnet/espnet). All Rights Reserved. -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -from abc import ABC -from abc import abstractmethod -import collections -import copy -import functools -import logging -import numbers -import re -from typing import Any -from typing import Callable -from typing import Collection -from typing import Dict -from typing import Mapping -from typing import Tuple -from typing import Union -try: - import h5py -except: - print("If you want use h5py dataset, please pip install h5py, and try it again") -import humanfriendly -import kaldiio -import numpy as np -import torch -from torch.utils.data.dataset import Dataset - -from funasr.fileio.npy_scp import NpyScpReader -from funasr.fileio.rand_gen_dataset import FloatRandomGenerateDataset -from funasr.fileio.rand_gen_dataset import IntRandomGenerateDataset -from funasr.fileio.read_text import load_num_sequence_text -from funasr.fileio.read_text import read_2column_text -from funasr.fileio.sound_scp import SoundScpReader -from funasr.utils.sized_dict import SizedDict - - -class AdapterForSoundScpReader(collections.abc.Mapping): - def __init__(self, loader, dtype=None): - self.loader = loader - self.dtype = dtype - self.rate = None - - def keys(self): - return self.loader.keys() - - def __len__(self): - return len(self.loader) - - def __iter__(self): - return iter(self.loader) - - def __getitem__(self, key: str) -> np.ndarray: - retval = self.loader[key] - - if isinstance(retval, tuple): - assert len(retval) == 2, len(retval) - if isinstance(retval[0], int) and isinstance(retval[1], np.ndarray): - # sound scp case - rate, array = retval - elif isinstance(retval[1], int) and isinstance(retval[0], np.ndarray): - # Extended ark format case - array, rate = retval - else: - raise RuntimeError( - f"Unexpected type: {type(retval[0])}, {type(retval[1])}" - ) - - if self.rate is not None and self.rate != rate: - raise RuntimeError( - f"Sampling rates are mismatched: {self.rate} != {rate}" - ) - self.rate = rate - # Multichannel wave fie - # array: (NSample, Channel) or (Nsample) - if self.dtype is not None: - array = array.astype(self.dtype) - - else: - # Normal ark case - assert isinstance(retval, np.ndarray), type(retval) - array = retval - if self.dtype is not None: - array = array.astype(self.dtype) - - assert isinstance(array, np.ndarray), type(array) - return array - - -class H5FileWrapper: - def __init__(self, path: str): - self.path = path - self.h5_file = h5py.File(path, "r") - - def __repr__(self) -> str: - return str(self.h5_file) - - def __len__(self) -> int: - return len(self.h5_file) - - def __iter__(self): - return iter(self.h5_file) - - def __getitem__(self, key) -> np.ndarray: - value = self.h5_file[key] - return value[()] - - -def sound_loader(path, dest_sample_rate=16000, float_dtype=None): - # The file is as follows: - # utterance_id_A /some/where/a.wav - # utterance_id_B /some/where/a.flac - - # NOTE(kamo): SoundScpReader doesn't support pipe-fashion - # like Kaldi e.g. "cat a.wav |". - # NOTE(kamo): The audio signal is normalized to [-1,1] range. - loader = SoundScpReader(path, normalize=True, always_2d=False, dest_sample_rate = dest_sample_rate) - - # SoundScpReader.__getitem__() returns Tuple[int, ndarray], - # but ndarray is desired, so Adapter class is inserted here - return AdapterForSoundScpReader(loader, float_dtype) - - -def kaldi_loader(path, float_dtype=None, max_cache_fd: int = 0): - loader = kaldiio.load_scp(path, max_cache_fd=max_cache_fd) - return AdapterForSoundScpReader(loader, float_dtype) - - -def rand_int_loader(filepath, loader_type): - # e.g. rand_int_3_10 - try: - low, high = map(int, loader_type[len("rand_int_") :].split("_")) - except ValueError: - raise RuntimeError(f"e.g rand_int_3_10: but got {loader_type}") - return IntRandomGenerateDataset(filepath, low, high) - - -DATA_TYPES = { - "sound": dict( - func=sound_loader, - kwargs=["dest_sample_rate","float_dtype"], - help="Audio format types which supported by sndfile wav, flac, etc." - "\n\n" - " utterance_id_a a.wav\n" - " utterance_id_b b.wav\n" - " ...", - ), - "kaldi_ark": dict( - func=kaldi_loader, - kwargs=["max_cache_fd"], - help="Kaldi-ark file type." - "\n\n" - " utterance_id_A /some/where/a.ark:123\n" - " utterance_id_B /some/where/a.ark:456\n" - " ...", - ), - "npy": dict( - func=NpyScpReader, - kwargs=[], - help="Npy file format." - "\n\n" - " utterance_id_A /some/where/a.npy\n" - " utterance_id_B /some/where/b.npy\n" - " ...", - ), - "text_int": dict( - func=functools.partial(load_num_sequence_text, loader_type="text_int"), - kwargs=[], - help="A text file in which is written a sequence of interger numbers " - "separated by space." - "\n\n" - " utterance_id_A 12 0 1 3\n" - " utterance_id_B 3 3 1\n" - " ...", - ), - "csv_int": dict( - func=functools.partial(load_num_sequence_text, loader_type="csv_int"), - kwargs=[], - help="A text file in which is written a sequence of interger numbers " - "separated by comma." - "\n\n" - " utterance_id_A 100,80\n" - " utterance_id_B 143,80\n" - " ...", - ), - "text_float": dict( - func=functools.partial(load_num_sequence_text, loader_type="text_float"), - kwargs=[], - help="A text file in which is written a sequence of float numbers " - "separated by space." - "\n\n" - " utterance_id_A 12. 3.1 3.4 4.4\n" - " utterance_id_B 3. 3.12 1.1\n" - " ...", - ), - "csv_float": dict( - func=functools.partial(load_num_sequence_text, loader_type="csv_float"), - kwargs=[], - help="A text file in which is written a sequence of float numbers " - "separated by comma." - "\n\n" - " utterance_id_A 12.,3.1,3.4,4.4\n" - " utterance_id_B 3.,3.12,1.1\n" - " ...", - ), - "text": dict( - func=read_2column_text, - kwargs=[], - help="Return text as is. The text must be converted to ndarray " - "by 'preprocess'." - "\n\n" - " utterance_id_A hello world\n" - " utterance_id_B foo bar\n" - " ...", - ), - "hdf5": dict( - func=H5FileWrapper, - kwargs=[], - help="A HDF5 file which contains arrays at the first level or the second level." - " >>> f = h5py.File('file.h5')\n" - " >>> array1 = f['utterance_id_A']\n" - " >>> array2 = f['utterance_id_B']\n", - ), - "rand_float": dict( - func=FloatRandomGenerateDataset, - kwargs=[], - help="Generate random float-ndarray which has the given shapes " - "in the file." - "\n\n" - " utterance_id_A 3,4\n" - " utterance_id_B 10,4\n" - " ...", - ), - "rand_int_\\d+_\\d+": dict( - func=rand_int_loader, - kwargs=["loader_type"], - help="e.g. 'rand_int_0_10'. Generate random int-ndarray which has the given " - "shapes in the path. " - "Give the lower and upper value by the file type. e.g. " - "rand_int_0_10 -> Generate integers from 0 to 10." - "\n\n" - " utterance_id_A 3,4\n" - " utterance_id_B 10,4\n" - " ...", - ), -} - - -class AbsDataset(Dataset, ABC): - @abstractmethod - def has_name(self, name) -> bool: - raise NotImplementedError - - @abstractmethod - def names(self) -> Tuple[str, ...]: - raise NotImplementedError - - @abstractmethod - def __getitem__(self, uid) -> Tuple[Any, Dict[str, np.ndarray]]: - raise NotImplementedError - - -class ESPnetDataset(AbsDataset): - """Pytorch Dataset class for ESPNet. - - Examples: - >>> dataset = ESPnetDataset([('wav.scp', 'input', 'sound'), - ... ('token_int', 'output', 'text_int')], - ... ) - ... uttid, data = dataset['uttid'] - {'input': per_utt_array, 'output': per_utt_array} - """ - - def __init__( - self, - path_name_type_list: Collection[Tuple[str, str, str]], - preprocess: Callable[ - [str, Dict[str, np.ndarray]], Dict[str, np.ndarray] - ] = None, - float_dtype: str = "float32", - int_dtype: str = "long", - max_cache_size: Union[float, int, str] = 0.0, - max_cache_fd: int = 0, - dest_sample_rate: int = 16000, - ): - if len(path_name_type_list) == 0: - raise ValueError( - '1 or more elements are required for "path_name_type_list"' - ) - - path_name_type_list = copy.deepcopy(path_name_type_list) - self.preprocess = preprocess - - self.float_dtype = float_dtype - self.int_dtype = int_dtype - self.max_cache_fd = max_cache_fd - self.dest_sample_rate = dest_sample_rate - - self.loader_dict = {} - self.debug_info = {} - for path, name, _type in path_name_type_list: - if name in self.loader_dict: - raise RuntimeError(f'"{name}" is duplicated for data-key') - - loader = self._build_loader(path, _type) - self.loader_dict[name] = loader - self.debug_info[name] = path, _type - if len(self.loader_dict[name]) == 0: - raise RuntimeError(f"{path} has no samples") - - # TODO(kamo): Should check consistency of each utt-keys? - - if isinstance(max_cache_size, str): - max_cache_size = humanfriendly.parse_size(max_cache_size) - self.max_cache_size = max_cache_size - if max_cache_size > 0: - self.cache = SizedDict(shared=True) - else: - self.cache = None - - def _build_loader( - self, path: str, loader_type: str - ) -> Mapping[str, Union[np.ndarray, torch.Tensor, str, numbers.Number]]: - """Helper function to instantiate Loader. - - Args: - path: The file path - loader_type: loader_type. sound, npy, text_int, text_float, etc - """ - for key, dic in DATA_TYPES.items(): - # e.g. loader_type="sound" - # -> return DATA_TYPES["sound"]["func"](path) - if re.match(key, loader_type): - kwargs = {} - for key2 in dic["kwargs"]: - if key2 == "loader_type": - kwargs["loader_type"] = loader_type - elif key2 == "dest_sample_rate" and loader_type=="sound": - kwargs["dest_sample_rate"] = self.dest_sample_rate - elif key2 == "float_dtype": - kwargs["float_dtype"] = self.float_dtype - elif key2 == "int_dtype": - kwargs["int_dtype"] = self.int_dtype - elif key2 == "max_cache_fd": - kwargs["max_cache_fd"] = self.max_cache_fd - else: - raise RuntimeError(f"Not implemented keyword argument: {key2}") - - func = dic["func"] - try: - return func(path, **kwargs) - except Exception: - if hasattr(func, "__name__"): - name = func.__name__ - else: - name = str(func) - logging.error(f"An error happened with {name}({path})") - raise - else: - raise RuntimeError(f"Not supported: loader_type={loader_type}") - - def has_name(self, name) -> bool: - return name in self.loader_dict - - def names(self) -> Tuple[str, ...]: - return tuple(self.loader_dict) - - def __iter__(self): - return iter(next(iter(self.loader_dict.values()))) - - def __repr__(self): - _mes = self.__class__.__name__ - _mes += "(" - for name, (path, _type) in self.debug_info.items(): - _mes += f'\n {name}: {{"path": "{path}", "type": "{_type}"}}' - _mes += f"\n preprocess: {self.preprocess})" - return _mes - - def __getitem__(self, uid: Union[str, int]) -> Tuple[str, Dict[str, np.ndarray]]: - - # Change integer-id to string-id - if isinstance(uid, int): - d = next(iter(self.loader_dict.values())) - uid = list(d)[uid] - - if self.cache is not None and uid in self.cache: - data = self.cache[uid] - return uid, data - - data = {} - # 1. Load data from each loaders - for name, loader in self.loader_dict.items(): - try: - value = loader[uid] - if isinstance(value, (list, tuple)): - value = np.array(value) - if not isinstance( - value, (np.ndarray, torch.Tensor, str, numbers.Number) - ): - raise TypeError( - f"Must be ndarray, torch.Tensor, str or Number: {type(value)}" - ) - except Exception: - path, _type = self.debug_info[name] - logging.error( - f"Error happened with path={path}, type={_type}, id={uid}" - ) - raise - - # torch.Tensor is converted to ndarray - if isinstance(value, torch.Tensor): - value = value.numpy() - elif isinstance(value, numbers.Number): - value = np.array([value]) - data[name] = value - - # 2. [Option] Apply preprocessing - # e.g. funasr.train.preprocessor:CommonPreprocessor - if self.preprocess is not None: - data = self.preprocess(uid, data) - - # 3. Force data-precision - for name in data: - value = data[name] - if not isinstance(value, np.ndarray): - raise RuntimeError( - f"All values must be converted to np.ndarray object " - f'by preprocessing, but "{name}" is still {type(value)}.' - ) - - # Cast to desired type - if value.dtype.kind == "f": - value = value.astype(self.float_dtype) - elif value.dtype.kind == "i": - value = value.astype(self.int_dtype) - else: - raise NotImplementedError(f"Not supported dtype: {value.dtype}") - data[name] = value - - if self.cache is not None and self.cache.size < self.max_cache_size: - self.cache[uid] = data - - retval = uid, data - return retval diff --git a/funasr/datasets/data_sampler.py b/funasr/datasets/fun_datasets/data_sampler.py similarity index 100% rename from funasr/datasets/data_sampler.py rename to funasr/datasets/fun_datasets/data_sampler.py diff --git a/funasr/datasets/dataloader_fn.py b/funasr/datasets/fun_datasets/dataloader_fn.py similarity index 93% rename from funasr/datasets/dataloader_fn.py rename to funasr/datasets/fun_datasets/dataloader_fn.py index b0ecf4fd2..601cbebeb 100644 --- a/funasr/datasets/dataloader_fn.py +++ b/funasr/datasets/fun_datasets/dataloader_fn.py @@ -1,7 +1,7 @@ import time import torch -from funasr.datasets.dataset_jsonl import AudioDataset -from funasr.datasets.data_sampler import BatchSampler +from funasr.datasets.fun_datasets.dataset_jsonl import AudioDataset +from funasr.datasets.fun_datasets.data_sampler import BatchSampler from funasr.models.frontend.wav_frontend import WavFrontend from funasr.tokenizer.build_tokenizer import build_tokenizer from funasr.tokenizer.token_id_converter import TokenIDConverter diff --git a/funasr/datasets/dataset_jsonl.py b/funasr/datasets/fun_datasets/dataset_jsonl.py similarity index 100% rename from funasr/datasets/dataset_jsonl.py rename to funasr/datasets/fun_datasets/dataset_jsonl.py diff --git a/funasr/datasets/iterable_dataset.py b/funasr/datasets/iterable_dataset.py deleted file mode 100644 index b2cc283e1..000000000 --- a/funasr/datasets/iterable_dataset.py +++ /dev/null @@ -1,398 +0,0 @@ -"""Iterable dataset module.""" -import copy -from io import StringIO -from pathlib import Path -from typing import Callable -from typing import Collection -from typing import Dict -from typing import Iterator -from typing import Tuple -from typing import Union -from typing import List - -import kaldiio -import numpy as np -import torch -import torchaudio -# import librosa -import librosa -from torch.utils.data.dataset import IterableDataset -import os.path - -from funasr.datasets.dataset import ESPnetDataset - - -SUPPORT_AUDIO_TYPE_SETS = ['flac', 'mp3', 'ogg', 'opus', 'wav', 'pcm'] - -def load_kaldi(input): - retval = kaldiio.load_mat(input) - if isinstance(retval, tuple): - assert len(retval) == 2, len(retval) - if isinstance(retval[0], int) and isinstance(retval[1], np.ndarray): - # sound scp case - rate, array = retval - elif isinstance(retval[1], int) and isinstance(retval[0], np.ndarray): - # Extended ark format case - array, rate = retval - else: - raise RuntimeError(f"Unexpected type: {type(retval[0])}, {type(retval[1])}") - - # Multichannel wave fie - # array: (NSample, Channel) or (Nsample) - - else: - # Normal ark case - assert isinstance(retval, np.ndarray), type(retval) - array = retval - return array - - -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 load_pcm(input): - with open(input,"rb") as f: - bytes = f.read() - return load_bytes(bytes) - -def load_wav(input): - try: - return torchaudio.load(input)[0].numpy() - except: - # waveform, _ = librosa.load(input, dtype='float32') - waveform, _ = librosa.load(input, dtype='float32') - if waveform.ndim == 2: - waveform = waveform[:, 0] - return np.expand_dims(waveform, axis=0) - -DATA_TYPES = { - "sound": load_wav, - "pcm": load_pcm, - "kaldi_ark": load_kaldi, - "bytes": load_bytes, - "waveform": lambda x: x, - "npy": np.load, - "text_int": lambda x: np.loadtxt( - StringIO(x), ndmin=1, dtype=np.long, delimiter=" " - ), - "csv_int": lambda x: np.loadtxt(StringIO(x), ndmin=1, dtype=np.long, delimiter=","), - "text_float": lambda x: np.loadtxt( - StringIO(x), ndmin=1, dtype=np.float32, delimiter=" " - ), - "csv_float": lambda x: np.loadtxt( - StringIO(x), ndmin=1, dtype=np.float32, delimiter="," - ), - "text": lambda x: x, -} - - -class IterableESPnetDataset(IterableDataset): - """Pytorch Dataset class for ESPNet. - - Examples: - >>> dataset = IterableESPnetDataset([('wav.scp', 'input', 'sound'), - ... ('token_int', 'output', 'text_int')], - ... ) - >>> for uid, data in dataset: - ... data - {'input': per_utt_array, 'output': per_utt_array} - """ - - def __init__( - self, - path_name_type_list: Collection[Tuple[any, str, str]], - preprocess: Callable[ - [str, Dict[str, np.ndarray]], Dict[str, np.ndarray] - ] = None, - float_dtype: str = "float32", - fs: dict = None, - mc: bool = False, - int_dtype: str = "long", - key_file: str = None, - ): - if len(path_name_type_list) == 0: - raise ValueError( - '1 or more elements are required for "path_name_type_list"' - ) - - path_name_type_list = copy.deepcopy(path_name_type_list) - self.preprocess = preprocess - - self.float_dtype = float_dtype - self.int_dtype = int_dtype - self.key_file = key_file - self.fs = fs - self.mc = mc - - self.debug_info = {} - non_iterable_list = [] - self.path_name_type_list = [] - - if not isinstance(path_name_type_list[0], (Tuple, List)): - path = path_name_type_list[0] - name = path_name_type_list[1] - _type = path_name_type_list[2] - self.debug_info[name] = path, _type - if _type not in DATA_TYPES: - non_iterable_list.append((path, name, _type)) - else: - self.path_name_type_list.append((path, name, _type)) - else: - for path, name, _type in path_name_type_list: - self.debug_info[name] = path, _type - if _type not in DATA_TYPES: - non_iterable_list.append((path, name, _type)) - else: - self.path_name_type_list.append((path, name, _type)) - - if len(non_iterable_list) != 0: - # Some types doesn't support iterable mode - self.non_iterable_dataset = ESPnetDataset( - path_name_type_list=non_iterable_list, - preprocess=preprocess, - float_dtype=float_dtype, - int_dtype=int_dtype, - ) - else: - self.non_iterable_dataset = None - - self.apply_utt2category = False - - def has_name(self, name) -> bool: - return name in self.debug_info - - def names(self) -> Tuple[str, ...]: - return tuple(self.debug_info) - - def __repr__(self): - _mes = self.__class__.__name__ - _mes += "(" - for name, (path, _type) in self.debug_info.items(): - _mes += f'\n {name}: {{"path": "{path}", "type": "{_type}"}}' - _mes += f"\n preprocess: {self.preprocess})" - return _mes - - def __iter__(self) -> Iterator[Tuple[Union[str, int], Dict[str, np.ndarray]]]: - count = 0 - if len(self.path_name_type_list) != 0 and (self.path_name_type_list[0][2] == "bytes" or self.path_name_type_list[0][2] == "waveform"): - linenum = len(self.path_name_type_list) - data = {} - for i in range(linenum): - value = self.path_name_type_list[i][0] - uid = 'utt_id' - name = self.path_name_type_list[i][1] - _type = self.path_name_type_list[i][2] - func = DATA_TYPES[_type] - array = func(value) - if self.fs is not None and (name == "speech" or name == "ref_speech"): - audio_fs = self.fs["audio_fs"] - model_fs = self.fs["model_fs"] - if audio_fs is not None and model_fs is not None: - array = torch.from_numpy(array) - array = array.unsqueeze(0) - array = torchaudio.transforms.Resample(orig_freq=audio_fs, - new_freq=model_fs)(array) - array = array.squeeze(0).numpy() - - data[name] = array - - if self.preprocess is not None: - data = self.preprocess(uid, data) - for name in data: - count += 1 - value = data[name] - if not isinstance(value, np.ndarray): - raise RuntimeError( - f'All values must be converted to np.ndarray object ' - f'by preprocessing, but "{name}" is still {type(value)}.') - # Cast to desired type - if value.dtype.kind == 'f': - value = value.astype(self.float_dtype) - elif value.dtype.kind == 'i': - value = value.astype(self.int_dtype) - else: - raise NotImplementedError( - f'Not supported dtype: {value.dtype}') - data[name] = value - - yield uid, data - - elif len(self.path_name_type_list) != 0 and self.path_name_type_list[0][2] == "sound" and not self.path_name_type_list[0][0].lower().endswith(".scp"): - linenum = len(self.path_name_type_list) - data = {} - for i in range(linenum): - value = self.path_name_type_list[i][0] - uid = os.path.basename(self.path_name_type_list[i][0]).split(".")[0] - name = self.path_name_type_list[i][1] - _type = self.path_name_type_list[i][2] - if _type == "sound": - audio_type = os.path.basename(value).lower() - if audio_type.rfind(".pcm") >= 0: - _type = "pcm" - func = DATA_TYPES[_type] - array = func(value) - if self.fs is not None and (name == "speech" or name == "ref_speech"): - audio_fs = self.fs["audio_fs"] - model_fs = self.fs["model_fs"] - if audio_fs is not None and model_fs is not None: - array = torch.from_numpy(array) - array = torchaudio.transforms.Resample(orig_freq=audio_fs, - new_freq=model_fs)(array) - array = array.numpy() - - if _type == "sound": - if self.mc: - data[name] = array.transpose((1, 0)) - else: - data[name] = array[0] - else: - data[name] = array - - if self.preprocess is not None: - data = self.preprocess(uid, data) - for name in data: - count += 1 - value = data[name] - if not isinstance(value, np.ndarray): - raise RuntimeError( - f'All values must be converted to np.ndarray object ' - f'by preprocessing, but "{name}" is still {type(value)}.') - # Cast to desired type - if value.dtype.kind == 'f': - value = value.astype(self.float_dtype) - elif value.dtype.kind == 'i': - value = value.astype(self.int_dtype) - else: - raise NotImplementedError( - f'Not supported dtype: {value.dtype}') - data[name] = value - - yield uid, data - - else: - if self.key_file is not None: - uid_iter = ( - line.rstrip().split(maxsplit=1)[0] - for line in open(self.key_file, encoding="utf-8") - ) - elif len(self.path_name_type_list) != 0: - uid_iter = ( - line.rstrip().split(maxsplit=1)[0] - for line in open(self.path_name_type_list[0][0], encoding="utf-8") - ) - else: - uid_iter = iter(self.non_iterable_dataset) - - files = [open(lis[0], encoding="utf-8") for lis in self.path_name_type_list] - - worker_info = torch.utils.data.get_worker_info() - - linenum = 0 - for count, uid in enumerate(uid_iter, 1): - # If num_workers>=1, split keys - if worker_info is not None: - if (count - 1) % worker_info.num_workers != worker_info.id: - continue - - # 1. Read a line from each file - while True: - keys = [] - values = [] - for f in files: - linenum += 1 - try: - line = next(f) - except StopIteration: - raise RuntimeError(f"{uid} is not found in the files") - sps = line.rstrip().split(maxsplit=1) - if len(sps) != 2: - raise RuntimeError( - f"This line doesn't include a space:" - f" {f}:L{linenum}: {line})" - ) - key, value = sps - keys.append(key) - values.append(value) - - for k_idx, k in enumerate(keys): - if k != keys[0]: - raise RuntimeError( - f"Keys are mismatched. Text files (idx={k_idx}) is " - f"not sorted or not having same keys at L{linenum}" - ) - - # If the key is matched, break the loop - if len(keys) == 0 or keys[0] == uid: - break - - # 2. Load the entry from each line and create a dict - data = {} - # 2.a. Load data streamingly - for value, (path, name, _type) in zip(values, self.path_name_type_list): - if _type == "sound": - audio_type = os.path.basename(value).lower() - if audio_type.rfind(".pcm") >= 0: - _type = "pcm" - func = DATA_TYPES[_type] - # Load entry - array = func(value) - if self.fs is not None and name == "speech": - audio_fs = self.fs["audio_fs"] - model_fs = self.fs["model_fs"] - if audio_fs is not None and model_fs is not None: - array = torch.from_numpy(array) - array = torchaudio.transforms.Resample(orig_freq=audio_fs, - new_freq=model_fs)(array) - array = array.numpy() - if _type == "sound": - if self.mc: - data[name] = array.transpose((1, 0)) - else: - data[name] = array[0] - else: - data[name] = array - if self.non_iterable_dataset is not None: - # 2.b. Load data from non-iterable dataset - _, from_non_iterable = self.non_iterable_dataset[uid] - data.update(from_non_iterable) - - # 3. [Option] Apply preprocessing - # e.g. funasr.train.preprocessor:CommonPreprocessor - if self.preprocess is not None: - data = self.preprocess(uid, data) - - # 4. Force data-precision - for name in data: - value = data[name] - if not isinstance(value, np.ndarray): - raise RuntimeError( - f"All values must be converted to np.ndarray object " - f'by preprocessing, but "{name}" is still {type(value)}.' - ) - - # Cast to desired type - if value.dtype.kind == "f": - value = value.astype(self.float_dtype) - elif value.dtype.kind == "i": - value = value.astype(self.int_dtype) - else: - raise NotImplementedError(f"Not supported dtype: {value.dtype}") - data[name] = value - - yield uid, data - - if count == 0: - raise RuntimeError("No iteration") - diff --git a/funasr/datasets/large_datasets/build_dataloader.py b/funasr/datasets/large_datasets/build_dataloader.py deleted file mode 100644 index 134b20a65..000000000 --- a/funasr/datasets/large_datasets/build_dataloader.py +++ /dev/null @@ -1,96 +0,0 @@ -import logging -from pathlib import Path -from typing import Iterable -from typing import List -from typing import Union - -import sentencepiece as spm -from torch.utils.data import DataLoader - -from funasr.datasets.large_datasets.dataset import Dataset -from funasr.iterators.abs_iter_factory import AbsIterFactory -from funasr.tokenizer.abs_tokenizer import AbsTokenizer - - -def read_symbol_table(symbol_table_file): - if isinstance(symbol_table_file, str): - symbol_table = {} - with open(symbol_table_file, "r", encoding="utf8") as fin: - for i, line in enumerate(fin): - char = line.strip() - symbol_table[char] = i - else: - assert isinstance(symbol_table_file, list) - symbol_table = {} - for i, char in enumerate(symbol_table_file): - symbol_table[char] = i - return symbol_table - - -def load_seg_dict(seg_dict_file): - seg_dict = {} - assert isinstance(seg_dict_file, str) - with open(seg_dict_file, "r", encoding="utf8") as f: - lines = f.readlines() - for line in lines: - s = line.strip().split() - key = s[0] - value = s[1:] - seg_dict[key] = " ".join(value) - return seg_dict - - -class SentencepiecesTokenizer(AbsTokenizer): - def __init__(self, model: Union[Path, str]): - self.model = str(model) - self.sp = None - - def __repr__(self): - return f'{self.__class__.__name__}(model="{self.model}")' - - def _build_sentence_piece_processor(self): - if self.sp is None: - self.sp = spm.SentencePieceProcessor() - self.sp.load(self.model) - - def text2tokens(self, line: str) -> List[str]: - self._build_sentence_piece_processor() - return self.sp.EncodeAsPieces(line) - - def tokens2text(self, tokens: Iterable[str]) -> str: - self._build_sentence_piece_processor() - return self.sp.DecodePieces(list(tokens)) - - -class LargeDataLoader(AbsIterFactory): - def __init__(self, args, mode="train"): - symbol_table, seg_dict, punc_dict, bpe_tokenizer = None, None, None, None - if hasattr(args, "token_list") and args.token_list is not None: - symbol_table = read_symbol_table(args.token_list) - if hasattr(args, "seg_dict_file") and args.seg_dict_file is not None: - seg_dict = load_seg_dict(args.seg_dict_file) - if hasattr(args, "punc_list") and args.punc_list is not None: - punc_dict = read_symbol_table(args.punc_list) - if hasattr(args, "bpemodel") and args.bpemodel is not None: - bpe_tokenizer = SentencepiecesTokenizer(args.bpemodel) - self.dataset_conf = args.dataset_conf - if "frontend_conf" not in args: - self.frontend_conf = None - else: - self.frontend_conf = args.frontend_conf - self.speed_perturb = args.speed_perturb if hasattr(args, "speed_perturb") else None - logging.info("dataloader config: {}".format(self.dataset_conf)) - batch_mode = self.dataset_conf.get("batch_mode", "padding") - data_list = args.train_data_file if mode == "train" else args.valid_data_file - self.dataset = Dataset(data_list, symbol_table, seg_dict, punc_dict, bpe_tokenizer, - self.dataset_conf, self.frontend_conf, - speed_perturb=self.speed_perturb if mode == "train" else None, - mode=mode, batch_mode=batch_mode) - - def build_iter(self, epoch, shuffle=True): - self.dataset.set_epoch(epoch) - data_loader = DataLoader(self.dataset, - batch_size=None, - pin_memory=True, - num_workers=self.dataset_conf.get("num_workers", 8)) - return data_loader diff --git a/funasr/datasets/large_datasets/datapipes/batch.py b/funasr/datasets/large_datasets/datapipes/batch.py deleted file mode 100644 index 35e5dbaeb..000000000 --- a/funasr/datasets/large_datasets/datapipes/batch.py +++ /dev/null @@ -1,213 +0,0 @@ -import random - -from itertools import count -from functools import partial -from torch.utils.data import IterableDataset -from funasr.datasets.large_datasets.datapipes.map import MapperIterDataPipe - -tiebreaker = count() - - -def _default_len_fn(token): - return len(token), next(tiebreaker) - - -def _token_len_fn(token, len_fn): - return len_fn(token), next(tiebreaker), token - - -class MaxTokenBucketizerIterDataPipe(IterableDataset): - - def __init__( - self, - datapipe, - batch_size=8000, - len_fn=_default_len_fn, - buffer_size=10240, - sort_size=500, - batch_mode="padding", - ): - assert batch_size > 0, "Batch size is required to be larger than 0!" - assert buffer_size >= -1, "Buffer size is required to be larger than -1!" - assert sort_size > 0, "Sort size is required to be larger than 0!" - - datapipe = MapperIterDataPipe(datapipe, fn=partial(_token_len_fn, len_fn=len_fn)) - self.datapipe = datapipe - self.batch_size = batch_size - self.buffer_size = buffer_size - self.sort_size = sort_size - self.batch_mode = batch_mode - - def set_epoch(self, epoch): - self.datapipe.set_epoch(epoch) - - def __iter__(self): - buffer = [] - batch = [] - bucket = [] - max_lengths = 0 - min_lengths = 999999 - batch_lengths = 0 - - if self.batch_mode == "clipping": - assert self.buffer_size > 0, "for clipping batch_mode, buffer_size must be > 1" - for d in self.datapipe: - if d[0] > self.batch_size: - continue - buffer.append(d) - if len(buffer) == self.buffer_size: - random.shuffle(buffer) - for sample in buffer: - bucket.append(sample) - if len(bucket) == self.sort_size: - bucket.sort() - for x in bucket: - length, _, token = x - if length < min_lengths: - min_lengths = length - batch_lengths = min_lengths * (len(batch) + 1) - if batch_lengths > self.batch_size: - yield batch - batch = [] - min_lengths = length - batch.append(token) - bucket = [] - buffer = [] - - if buffer: - random.shuffle(buffer) - for sample in buffer: - bucket.append(sample) - if len(bucket) == self.sort_size: - bucket.sort() - for x in bucket: - length, _, token = x - if length < min_lengths: - min_lengths = length - batch_lengths = min_lengths * (len(batch) + 1) - if batch_lengths > self.batch_size: - yield batch - batch = [] - min_lengths = length - batch.append(token) - bucket = [] - buffer = [] - - if bucket: - bucket.sort() - for x in bucket: - length, _, token = x - if length < min_lengths: - min_lengths = length - batch_lengths = min_lengths * (len(batch) + 1) - if batch_lengths > self.batch_size: - yield batch - batch = [] - min_lengths = length - batch.append(token) - bucket = [] - - if batch: - yield batch - - else: - if self.buffer_size == -1: - for d in self.datapipe: - if d[0] > self.batch_size: - continue - buffer.append(d) - buffer.sort() - for sample in buffer: - length, _, token = sample - if length > max_lengths: - max_lengths = length - batch_lengths = max_lengths * (len(batch) + 1) - if batch_lengths > self.batch_size: - bucket.append(batch) - batch = [] - max_lengths = length - batch.append(token) - random.shuffle(bucket) - if bucket: - for batch_sample in bucket: - yield batch_sample - if batch: - yield batch - - elif self.buffer_size == 0: - for d in self.datapipe: - if d[0] > self.batch_size: - continue - length, _, token = d - if length > self.batch_size: - continue - if length > max_lengths: - max_lengths = length - batch_lengths = max_lengths * (len(batch) + 1) - if batch_lengths > self.batch_size: - yield batch - batch = [] - max_lengths = length - batch.append(token) - if batch: - yield batch - - else: - for d in self.datapipe: - if d[0] > self.batch_size: - continue - buffer.append(d) - if len(buffer) == self.buffer_size: - random.shuffle(buffer) - for sample in buffer: - bucket.append(sample) - if len(bucket) == self.sort_size: - bucket.sort() - for x in bucket: - length, _, token = x - if length > max_lengths: - max_lengths = length - batch_lengths = max_lengths * (len(batch) + 1) - if batch_lengths > self.batch_size: - yield batch - batch = [] - max_lengths = length - batch.append(token) - bucket = [] - buffer = [] - - if buffer: - random.shuffle(buffer) - for sample in buffer: - bucket.append(sample) - if len(bucket) == self.sort_size: - bucket.sort() - for x in bucket: - length, _, token = x - if length > max_lengths: - max_lengths = length - batch_lengths = max_lengths * (len(batch) + 1) - if batch_lengths > self.batch_size: - yield batch - batch = [] - max_lengths = length - batch.append(token) - bucket = [] - buffer = [] - - if bucket: - bucket.sort() - for x in bucket: - length, _, token = x - if length > max_lengths: - max_lengths = length - batch_lengths = max_lengths * (len(batch) + 1) - if batch_lengths > self.batch_size: - yield batch - batch = [] - max_lengths = length - batch.append(token) - bucket = [] - - if batch: - yield batch diff --git a/funasr/datasets/large_datasets/datapipes/filter.py b/funasr/datasets/large_datasets/datapipes/filter.py deleted file mode 100644 index 6fe71538d..000000000 --- a/funasr/datasets/large_datasets/datapipes/filter.py +++ /dev/null @@ -1,24 +0,0 @@ -from torch.utils.data import IterableDataset - -def default_fn(data): - return data - - -class FilterIterDataPipe(IterableDataset): - - def __init__(self, - datapipe, - fn=default_fn): - self.datapipe = datapipe - self.fn = fn - - def set_epoch(self, epoch): - self.datapipe.set_epoch(epoch) - - def __iter__(self): - assert callable(self.fn) - for data in self.datapipe: - if self.fn(data): - yield data - else: - continue diff --git a/funasr/datasets/large_datasets/datapipes/map.py b/funasr/datasets/large_datasets/datapipes/map.py deleted file mode 100644 index dfcd6a045..000000000 --- a/funasr/datasets/large_datasets/datapipes/map.py +++ /dev/null @@ -1,22 +0,0 @@ -from torch.utils.data import IterableDataset - - -def default_fn(data): - return data - - -class MapperIterDataPipe(IterableDataset): - - def __init__(self, - datapipe, - fn=default_fn): - self.datapipe = datapipe - self.fn = fn - - def set_epoch(self, epoch): - self.datapipe.set_epoch(epoch) - - def __iter__(self): - assert callable(self.fn) - for data in self.datapipe: - yield self.fn(data) diff --git a/funasr/datasets/large_datasets/dataset.py b/funasr/datasets/large_datasets/dataset.py deleted file mode 100644 index d3489c199..000000000 --- a/funasr/datasets/large_datasets/dataset.py +++ /dev/null @@ -1,274 +0,0 @@ -import logging -import os -import random -from functools import partial - -import torch -import torch.distributed as dist -import torchaudio -import numpy as np -# import librosa -import librosa -from kaldiio import ReadHelper -from torch.utils.data import IterableDataset - -from funasr.datasets.large_datasets.datapipes.batch import MaxTokenBucketizerIterDataPipe -from funasr.datasets.large_datasets.datapipes.filter import FilterIterDataPipe -from funasr.datasets.large_datasets.datapipes.map import MapperIterDataPipe -from funasr.datasets.large_datasets.utils.clipping import clipping -from funasr.datasets.large_datasets.utils.filter import filter -from funasr.datasets.large_datasets.utils.padding import padding -from funasr.datasets.large_datasets.utils.tokenize import tokenize - - -def read_lists(list_file): - lists = [] - with open(list_file, 'r', encoding='utf8') as fin: - for line in fin: - parts = line.strip() - lists.append(parts) - return lists - - -class AudioDataset(IterableDataset): - def __init__(self, scp_lists, data_names, data_types, frontend_conf=None, shuffle=True, speed_perturb=None, - mode="train"): - self.scp_lists = scp_lists - self.data_names = data_names - self.data_types = data_types - self.frontend_conf = frontend_conf - self.shuffle = shuffle - self.mode = mode - self.epoch = -1 - self.rank = 0 - self.world_size = 1 - self.worker_id = 0 - self.num_workers = 1 - self.speed_perturb = speed_perturb - if self.speed_perturb is not None: - logging.info("Using speed_perturb: {}".format(speed_perturb)) - - def set_epoch(self, epoch): - self.epoch = epoch - - def get_rank_data_list(self, data_index): - assert dist.is_available() - if dist.is_initialized(): - self.rank = dist.get_rank() - self.world_size = dist.get_world_size() - else: - self.rank = 0 - self.world_size = 1 - - if self.mode == "train": - if self.shuffle: - random.seed(self.epoch) - random.shuffle(data_index) - return data_index[self.rank::self.world_size] - - return data_index - - def get_worker_data_list(self, rank_data_index): - worker_info = torch.utils.data.get_worker_info() - if worker_info is None: - self.worker_id = 0 - self.num_workers = 1 - else: - self.worker_id = worker_info.id - self.num_workers = worker_info.num_workers - - return rank_data_index[self.worker_id::self.num_workers] - - def close_reader(self, reader_list): - for reader in reader_list: - reader.close() - - def __iter__(self): - data_index = list(range(len(self.scp_lists))) - rank_data_index = self.get_rank_data_list(data_index) - worker_data_index = self.get_worker_data_list(rank_data_index) - - for index in worker_data_index: - data = dict(scp=self.scp_lists[index]) - - assert 'scp' in data - scp = data['scp'] - data_file_list = scp.strip().split() - data_name_list = self.data_names.split(",") - data_type_list = self.data_types.split(",") - - for file in data_file_list: - assert os.path.exists(file), "{} not exists".format(file) - - assert len(data_file_list) == len(data_name_list) == len(data_type_list), \ - "The item number of data, data_names, data_types must be the same " - - reader_list = [] - for data_file, data_type in zip(data_file_list, data_type_list): - if data_type == "kaldi_ark": - ark_reader = ReadHelper('ark:{}'.format(data_file)) - reader_list.append(ark_reader) - elif data_type == "text" or data_type == "sound" or data_type == 'text_hotword': - text_reader = open(data_file, "r", encoding="utf-8") - reader_list.append(text_reader) - elif data_type == "none": - continue - else: - raise TypeError("Data type {} is not supported".format(data_type)) - - for items in zip(*reader_list): - sample_dict = {} - for item, (data_name, data_type) in zip(items, zip(data_name_list, data_type_list)): - if data_type == "kaldi_ark": - key, mat = item - sample_dict[data_name] = mat - if data_name == "speech": - sample_dict["key"] = key - elif data_type == "sound": - key, path = item.strip().split() - try: - waveform, sampling_rate = torchaudio.load(path) - except: - # waveform, sampling_rate = librosa.load(path, dtype='float32') - waveform, sampling_rate = librosa.load(path, dtype='float32') - if waveform.ndim == 2: - waveform = waveform[:, 0] - waveform = np.expand_dims(waveform, axis=0) - waveform = torch.tensor(waveform) - if self.frontend_conf is not None: - if sampling_rate != self.frontend_conf["fs"]: - waveform = torchaudio.transforms.Resample(orig_freq=sampling_rate, - new_freq=self.frontend_conf["fs"])(waveform) - sampling_rate = self.frontend_conf["fs"] - waveform = waveform.numpy() - mat = waveform[0] - if self.speed_perturb is not None: - speed = random.choice(self.speed_perturb) - if speed != 1.0: - mat, _ = torchaudio.sox_effects.apply_effects_tensor( - torch.tensor(mat).view(1, -1), sampling_rate, [['speed', str(speed)], ['rate', str(sampling_rate)]]) - mat = mat.view(-1).numpy() - sample_dict[data_name] = mat - sample_dict["sampling_rate"] = sampling_rate - if data_name == "speech": - sample_dict["key"] = key - elif data_type == "text_hotword": - text = item - segs = text.strip().split() - sample_dict[data_name] = segs[1:] - if "key" not in sample_dict: - sample_dict["key"] = segs[0] - sample_dict['hw_tag'] = 1 - elif data_type == "text_nospace": - text = item - segs = text.strip().split(maxsplit=1) - sample_dict[data_name] = [x for x in segs[1]] - if "key" not in sample_dict: - sample_dict["key"] = segs[0] - else: - text = item - segs = text.strip().split() - sample_dict[data_name] = segs[1:] - if "key" not in sample_dict: - sample_dict["key"] = segs[0] - yield sample_dict - - self.close_reader(reader_list) - - -def len_fn_example(data): - return 1 - - -def len_fn_token(data): - assert "speech" in data - if "sampling_rate" in data: - return (data["speech"].shape[0] / data["sampling_rate"]) * 1000. - else: - return data["speech"].shape[0] - - -def Dataset(data_list_file, - dict, - seg_dict, - punc_dict, - bpe_tokenizer, - conf, - frontend_conf, - speed_perturb=None, - mode="train", - batch_mode="padding"): - scp_lists = read_lists(data_list_file) - shuffle = conf.get('shuffle', True) - data_names = conf.get("data_names", "speech,text") - data_types = conf.get("data_types", "kaldi_ark,text") - - pre_hwfile = conf.get("pre_hwlist", None) - # pre_prob = conf.get("pre_prob", 0) # unused yet - if pre_hwfile is not None: - pre_hwlist = [] - with open(pre_hwfile, 'r', encoding="utf-8") as fin: - for line in fin.readlines(): - pre_hwlist.append(line.strip()) - else: - pre_hwlist = None - - hw_config = {"sample_rate": conf.get("sample_rate", 0.6), - "double_rate": conf.get("double_rate", 0.1), - "hotword_min_length": conf.get("hotword_min_length", 2), - "hotword_max_length": conf.get("hotword_max_length", 8), - "pre_prob": conf.get("pre_prob", 0.0), - "pre_hwlist": pre_hwlist} - - - - dataset = AudioDataset(scp_lists, - data_names, - data_types, - frontend_conf=frontend_conf, - shuffle=shuffle, - speed_perturb=speed_perturb, - mode=mode, - ) - - if "text" in data_names: - vocab = {'vocab': dict, 'seg_dict': seg_dict, 'punc_dict': punc_dict, 'bpe_tokenizer': bpe_tokenizer, 'hw_config': hw_config} - tokenize_fn = partial(tokenize, **vocab) - dataset = MapperIterDataPipe(dataset, fn=tokenize_fn) - - filter_conf = conf.get('filter_conf', {}) - filter_fn = partial(filter, **filter_conf) - dataset = FilterIterDataPipe(dataset, fn=filter_fn) - - if shuffle: - buffer_conf = conf.get('shuffle_conf', {}) - buffer_size = buffer_conf['shuffle_size'] - sort_size = buffer_conf['sort_size'] - else: - buffer_size = 0 - sort_size = 1 - - batch_conf = conf.get('batch_conf', {}) - batch_size = batch_conf['batch_size'] - batch_type = batch_conf['batch_type'] - - assert batch_type in ["example", "token"] - if batch_type == 'example': - len_fn = len_fn_example - else: - len_fn = len_fn_token - - dataset = MaxTokenBucketizerIterDataPipe(dataset, - batch_size=batch_size, - len_fn=len_fn, - buffer_size=buffer_size, - sort_size=sort_size, - batch_mode=batch_mode) - - int_pad_value = conf.get("int_pad_value", -1) - float_pad_value = conf.get("float_pad_value", 0.0) - padding_conf = {"int_pad_value": int_pad_value, "float_pad_value": float_pad_value} - padding_fn = partial(padding, **padding_conf) - dataset = MapperIterDataPipe(dataset, fn=padding_fn if batch_mode == "padding" else clipping) - - return dataset diff --git a/funasr/datasets/large_datasets/utils/clipping.py b/funasr/datasets/large_datasets/utils/clipping.py deleted file mode 100644 index f5c29402c..000000000 --- a/funasr/datasets/large_datasets/utils/clipping.py +++ /dev/null @@ -1,40 +0,0 @@ -import numpy as np -import torch - -from funasr.datasets.collate_fn import crop_to_max_size - - -def clipping(data): - assert isinstance(data, list) - assert "key" in data[0] - - keys = [x["key"] for x in data] - - batch = {} - data_names = data[0].keys() - for data_name in data_names: - if data_name == "key": - continue - else: - if data[0][data_name].dtype.kind == "i": - tensor_type = torch.int64 - else: - tensor_type = torch.float32 - - tensor_list = [torch.tensor(np.copy(d[data_name]), dtype=tensor_type) for d in data] - tensor_lengths = torch.tensor([len(d[data_name]) for d in data], dtype=torch.int32) - - length_clip = min(tensor_lengths) - tensor_clip = tensor_list[0].new_zeros(len(tensor_list), length_clip, tensor_list[0].shape[1]) - for i, (tensor, length) in enumerate(zip(tensor_list, tensor_lengths)): - diff = length - length_clip - assert diff >= 0 - if diff == 0: - tensor_clip[i] = tensor - else: - tensor_clip[i] = crop_to_max_size(tensor, length_clip) - - batch[data_name] = tensor_clip - batch[data_name + "_lengths"] = torch.tensor([tensor.shape[0] for tensor in tensor_clip], dtype=torch.long) - - return keys, batch diff --git a/funasr/datasets/large_datasets/utils/filter.py b/funasr/datasets/large_datasets/utils/filter.py deleted file mode 100644 index 1260a47c4..000000000 --- a/funasr/datasets/large_datasets/utils/filter.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - - -def filter(data, - speech_length_min=100, - speech_length_max=15000, - token_length_min=0, - token_length_max=200): - assert "speech" in data or "text" in data - - if "speech" in data and "text" in data: - if "sampling_rate" in data: - speech_length = (data["speech"].shape[0] / data["sampling_rate"]) * 1000. - else: - speech_length = data["speech"].shape[0] - num_tokens = len(data['text']) - return speech_length_min < speech_length < speech_length_max and token_length_min < num_tokens < token_length_max - elif "speech" in data: - if "sampling_rate" in data: - speech_length = (data["speech"].shape[0] / data["sampling_rate"]) * 1000. - else: - speech_length = data["speech"].shape[0] - return speech_length_min < speech_length < speech_length_max - else: - num_tokens = len(data['text']) - return token_length_min < num_tokens < token_length_max diff --git a/funasr/datasets/large_datasets/utils/hotword_utils.py b/funasr/datasets/large_datasets/utils/hotword_utils.py deleted file mode 100644 index 73f8bdd90..000000000 --- a/funasr/datasets/large_datasets/utils/hotword_utils.py +++ /dev/null @@ -1,33 +0,0 @@ -import random - -def sample_hotword(length, - hotword_min_length, - hotword_max_length, - sample_rate, - double_rate, - pre_prob, - pre_index=None, - pre_hwlist=None): - if length < hotword_min_length: - return [-1] - if random.random() < sample_rate: - if pre_prob > 0 and random.random() < pre_prob and pre_index is not None: - return pre_index - if length == hotword_min_length: - return [0, length-1] - elif random.random() < double_rate and length > hotword_max_length + hotword_min_length + 2: - # sample two hotwords in a sentence - _max_hw_length = min(hotword_max_length, length // 2) - # first hotword - start1 = random.randint(0, length // 3) - end1 = random.randint(start1 + hotword_min_length - 1, start1 + _max_hw_length - 1) - # second hotword - start2 = random.randint(end1 + 1, length - hotword_min_length) - end2 = random.randint(min(length-1, start2+hotword_min_length-1), min(length-1, start2+hotword_max_length-1)) - return [start1, end1, start2, end2] - else: # single hotword - start = random.randint(0, length - hotword_min_length) - end = random.randint(min(length-1, start+hotword_min_length-1), min(length-1, start+hotword_max_length-1)) - return [start, end] - else: - return [-1] \ No newline at end of file diff --git a/funasr/datasets/large_datasets/utils/low_frame_rate.py b/funasr/datasets/large_datasets/utils/low_frame_rate.py deleted file mode 100644 index 76eb2da93..000000000 --- a/funasr/datasets/large_datasets/utils/low_frame_rate.py +++ /dev/null @@ -1,30 +0,0 @@ -import numpy as np - - -def build_LFR_features(data, m, n): - """ - Actually, this implements stacking frames and skipping frames. - if m = 1 and n = 1, just return the origin features. - if m = 1 and n > 1, it works like skipping. - if m > 1 and n = 1, it works like stacking but only support right frames. - if m > 1 and n > 1, it works like LFR. - - Args: - inputs_batch: inputs is T x D np.ndarray - m: number of frames to stack - n: number of frames to skip - """ - - LFR_inputs = [] - T = data.shape[0] - T_lfr = int(np.ceil(T / n)) - for i in range(T_lfr): - if m <= T - i * n: - LFR_inputs.append(np.hstack(data[i*n:i*n+m])) - else: - num_padding = m - (T - i * n) - frame = np.hstack(data[i*n:]) - for _ in range(num_padding): - frame = np.hstack((frame, data[-1])) - LFR_inputs.append(frame) - return np.vstack(LFR_inputs) diff --git a/funasr/datasets/large_datasets/utils/padding.py b/funasr/datasets/large_datasets/utils/padding.py deleted file mode 100644 index 26c6e84ba..000000000 --- a/funasr/datasets/large_datasets/utils/padding.py +++ /dev/null @@ -1,74 +0,0 @@ -import numpy as np -import torch -from torch.nn.utils.rnn import pad_sequence - - -def padding(data, float_pad_value=0.0, int_pad_value=-1): - assert isinstance(data, list) - assert "key" in data[0] - assert "speech" in data[0] or "text" in data[0] - - keys = [x["key"] for x in data] - - batch = {} - data_names = data[0].keys() - for data_name in data_names: - if data_name == "key" or data_name == "sampling_rate": - continue - else: - if data_name != 'hotword_indxs': - if data[0][data_name].dtype.kind == "i": - pad_value = int_pad_value - tensor_type = torch.int64 - else: - pad_value = float_pad_value - tensor_type = torch.float32 - - tensor_list = [torch.tensor(np.copy(d[data_name]), dtype=tensor_type) for d in data] - tensor_lengths = torch.tensor([len(d[data_name]) for d in data], dtype=torch.int32) - tensor_pad = pad_sequence(tensor_list, - batch_first=True, - padding_value=pad_value) - batch[data_name] = tensor_pad - batch[data_name + "_lengths"] = tensor_lengths - - # SAC LABEL INCLUDE - if "hotword_indxs" in batch: - # if hotword indxs in batch - # use it to slice hotwords out - hotword_list = [] - hotword_lengths = [] - text = batch['text'] - text_lengths = batch['text_lengths'] - hotword_indxs = batch['hotword_indxs'] - dha_pad = torch.ones_like(text) * -1 - _, t1 = text.shape - t1 += 1 # TODO: as parameter which is same as predictor_bias - nth_hw = 0 - for b, (hotword_indx, one_text, length) in enumerate(zip(hotword_indxs, text, text_lengths)): - dha_pad[b][:length] = 8405 - if hotword_indx[0] != -1: - start, end = int(hotword_indx[0]), int(hotword_indx[1]) - hotword = one_text[start: end+1] - hotword_list.append(hotword) - hotword_lengths.append(end-start+1) - dha_pad[b][start: end+1] = one_text[start: end+1] - nth_hw += 1 - if len(hotword_indx) == 4 and hotword_indx[2] != -1: - # the second hotword if exist - start, end = int(hotword_indx[2]), int(hotword_indx[3]) - hotword_list.append(one_text[start: end+1]) - hotword_lengths.append(end-start+1) - dha_pad[b][start: end+1] = one_text[start: end+1] - nth_hw += 1 - hotword_list.append(torch.tensor([1])) - hotword_lengths.append(1) - hotword_pad = pad_sequence(hotword_list, - batch_first=True, - padding_value=0) - batch["hotword_pad"] = hotword_pad - batch["hotword_lengths"] = torch.tensor(hotword_lengths, dtype=torch.int32) - batch['dha_pad'] = dha_pad - del batch['hotword_indxs'] - del batch['hotword_indxs_lengths'] - return keys, batch diff --git a/funasr/datasets/large_datasets/utils/tokenize.py b/funasr/datasets/large_datasets/utils/tokenize.py deleted file mode 100644 index 34a97c176..000000000 --- a/funasr/datasets/large_datasets/utils/tokenize.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python -import re -import numpy as np -from funasr.datasets.large_datasets.utils.hotword_utils import sample_hotword - -def forward_segment(text, seg_dict): - word_list = [] - i = 0 - while i < len(text): - longest_word = text[i] - for j in range(i + 1, len(text) + 1): - word = text[i:j] - if word in seg_dict: - if len(word) > len(longest_word): - longest_word = word - word_list.append(longest_word) - i += len(longest_word) - return word_list - -def seg_tokenize(txt, seg_dict): - pattern = re.compile(r'^[\u4E00-\u9FA50-9]+$') - out_txt = "" - for word in txt: - word = word.lower() - if word in seg_dict: - out_txt += seg_dict[word] + " " - else: - if pattern.match(word): - for char in word: - if char in seg_dict: - out_txt += seg_dict[char] + " " - else: - out_txt += "" + " " - else: - out_txt += "" + " " - return out_txt.strip().split() - -def tokenize(data, - vocab=None, - seg_dict=None, - punc_dict=None, - bpe_tokenizer=None, - hw_config=None): - assert "text" in data - assert isinstance(vocab, dict) - text = data["text"] - token = [] - vad = -2 - if bpe_tokenizer is not None: - text = bpe_tokenizer.text2tokens(" ".join(text)) - if seg_dict is not None: - assert isinstance(seg_dict, dict) - text = seg_tokenize(text, seg_dict) - - length = len(text) - if 'hw_tag' in data: - pre_index = None - if hw_config['pre_hwlist'] is not None and hw_config['pre_prob'] > 0: - # enable preset hotword detect in sampling - for hw in hw_config['pre_hwlist']: - hw = " ".join(seg_tokenize(hw, seg_dict)) - _find = " ".join(text).find(hw) - if _find != -1: - # _find = text[:_find].count(" ") # bpe sometimes - pre_index = [_find, _find + max(hw.count(" "), 1)] - break - hotword_indxs = sample_hotword(length, **hw_config, pre_index=pre_index) - data['hotword_indxs'] = hotword_indxs - del data['hw_tag'] - for i in range(length): - x = text[i] - if i == length-1 and "punc" in data and x.startswith("vad:"): - vad = x[4:] - if len(vad) == 0: - vad = -1 - else: - vad = int(vad) - elif x in vocab: - token.append(vocab[x]) - else: - token.append(vocab['']) - - if "punc" in data and punc_dict is not None: - punc_token = [] - for punc in data["punc"]: - if punc in punc_dict: - punc_token.append(punc_dict[punc]) - else: - punc_token.append(punc_dict["_"]) - data["punc"] = np.array(punc_token) - - data["text"] = np.array(token) - if vad is not -2: - data["vad_indexes"]=np.array([vad], dtype=np.int64) - return data diff --git a/funasr/datasets/ms_dataset.py b/funasr/datasets/ms_dataset.py deleted file mode 100644 index ae3c1bb1c..000000000 --- a/funasr/datasets/ms_dataset.py +++ /dev/null @@ -1,33 +0,0 @@ -import os - - -class MsDataset(object): - @classmethod - def load_core(cls, data_dir, data_set): - wav_file = os.path.join(data_dir, data_set, "wav.scp") - text_file = os.path.join(data_dir, data_set, "text") - with open(wav_file) as f: - wav_lines = f.readlines() - with open(text_file) as f: - text_lines = f.readlines() - data_list = [] - for wav_line, text_line in zip(wav_lines, text_lines): - item = {} - item["Audio:FILE"] = wav_line.strip().split()[-1] - item["Text:LABEL"] = " ".join(text_line.strip().split()[1:]) - data_list.append(item) - return data_list - - @classmethod - def load(cls, dataset_name, namespace="speech_asr", train_set="train", dev_set="validation"): - if os.path.exists(dataset_name): - data_dir = dataset_name - ds_dict = {} - ds_dict["train"] = cls.load_core(data_dir, train_set) - ds_dict["validation"] = cls.load_core(data_dir, dev_set) - ds_dict["raw_data_dir"] = data_dir - return ds_dict - else: - from modelscope.msdatasets import MsDataset - ds_dict = MsDataset.load(dataset_name=dataset_name, namespace=namespace) - return ds_dict diff --git a/funasr/datasets/preprocessor.py b/funasr/datasets/preprocessor.py deleted file mode 100644 index b303418bd..000000000 --- a/funasr/datasets/preprocessor.py +++ /dev/null @@ -1,881 +0,0 @@ -import re -from abc import ABC -from abc import abstractmethod -from pathlib import Path -from typing import Collection -from typing import Dict -from typing import Iterable -from typing import List -from typing import Union - -import numpy as np -import scipy.signal -import librosa -import jieba - -from funasr.tokenizer.build_tokenizer import build_tokenizer -from funasr.tokenizer.cleaner import TextCleaner -from funasr.tokenizer.token_id_converter import TokenIDConverter - - -class AbsPreprocessor(ABC): - def __init__(self, train: bool): - self.train = train - - @abstractmethod - def __call__( - self, uid: str, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - raise NotImplementedError - - -def forward_segment(text, dic): - word_list = [] - i = 0 - while i < len(text): - longest_word = text[i] - for j in range(i + 1, len(text) + 1): - word = text[i:j] - if word in dic: - if len(word) > len(longest_word): - longest_word = word - word_list.append(longest_word) - i += len(longest_word) - return word_list - -def seg_tokenize(txt, seg_dict): - pattern = re.compile(r'^[\u4E00-\u9FA50-9]+$') - out_txt = "" - for word in txt: - word = word.lower() - if word in seg_dict: - out_txt += seg_dict[word] + " " - else: - if pattern.match(word): - for char in word: - if char in seg_dict: - out_txt += seg_dict[char] + " " - else: - out_txt += "" + " " - else: - out_txt += "" + " " - return out_txt.strip().split() - -def seg_tokenize_wo_pattern(txt, seg_dict): - out_txt = "" - for word in txt: - if word in seg_dict: - out_txt += seg_dict[word] + " " - else: - out_txt += "" + " " - return out_txt.strip().split() - - -def framing( - x, - frame_length: int = 512, - frame_shift: int = 256, - centered: bool = True, - padded: bool = True, -): - if x.size == 0: - raise ValueError("Input array size is zero") - if frame_length < 1: - raise ValueError("frame_length must be a positive integer") - if frame_length > x.shape[-1]: - raise ValueError("frame_length is greater than input length") - if 0 >= frame_shift: - raise ValueError("frame_shift must be greater than 0") - - if centered: - pad_shape = [(0, 0) for _ in range(x.ndim - 1)] + [ - (frame_length // 2, frame_length // 2) - ] - x = np.pad(x, pad_shape, mode="constant", constant_values=0) - - if padded: - # Pad to integer number of windowed segments - # I.e make x.shape[-1] = frame_length + (nseg-1)*nstep, - # with integer nseg - nadd = (-(x.shape[-1] - frame_length) % frame_shift) % frame_length - pad_shape = [(0, 0) for _ in range(x.ndim - 1)] + [(0, nadd)] - x = np.pad(x, pad_shape, mode="constant", constant_values=0) - - # Created strided array of data segments - if frame_length == 1 and frame_length == frame_shift: - result = x[..., None] - else: - shape = x.shape[:-1] + ( - (x.shape[-1] - frame_length) // frame_shift + 1, - frame_length, - ) - strides = x.strides[:-1] + (frame_shift * x.strides[-1], x.strides[-1]) - result = np.lib.stride_tricks.as_strided(x, shape=shape, strides=strides) - return result - - -def detect_non_silence( - x: np.ndarray, - threshold: float = 0.01, - frame_length: int = 1024, - frame_shift: int = 512, - window: str = "boxcar", -) -> np.ndarray: - """Power based voice activity detection. - - Args: - x: (Channel, Time) - >>> x = np.random.randn(1000) - >>> detect = detect_non_silence(x) - >>> assert x.shape == detect.shape - >>> assert detect.dtype == np.bool - """ - if x.shape[-1] < frame_length: - return np.full(x.shape, fill_value=True, dtype=np.bool) - - if x.dtype.kind == "i": - x = x.astype(np.float64) - # framed_w: (C, T, F) - framed_w = framing( - x, - frame_length=frame_length, - frame_shift=frame_shift, - centered=False, - padded=True, - ) - framed_w *= scipy.signal.get_window(window, frame_length).astype(framed_w.dtype) - # power: (C, T) - power = (framed_w ** 2).mean(axis=-1) - # mean_power: (C, 1) - mean_power = np.mean(power, axis=-1, keepdims=True) - if np.all(mean_power == 0): - return np.full(x.shape, fill_value=True, dtype=np.bool) - # detect_frames: (C, T) - detect_frames = power / mean_power > threshold - # detects: (C, T, F) - detects = np.broadcast_to( - detect_frames[..., None], detect_frames.shape + (frame_shift,) - ) - # detects: (C, TF) - detects = detects.reshape(*detect_frames.shape[:-1], -1) - # detects: (C, TF) - return np.pad( - detects, - [(0, 0)] * (x.ndim - 1) + [(0, x.shape[-1] - detects.shape[-1])], - mode="edge", - ) - - -class CommonPreprocessor(AbsPreprocessor): - def __init__( - self, - train: bool, - token_type: str = None, - token_list: Union[Path, str, Iterable[str]] = None, - bpemodel: Union[Path, str, Iterable[str]] = None, - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: str = "text", - split_with_space: bool = False, - seg_dict_file: str = None, - ): - super().__init__(train) - self.train = train - self.speech_name = speech_name - self.text_name = text_name - self.speech_volume_normalize = speech_volume_normalize - self.rir_apply_prob = rir_apply_prob - self.noise_apply_prob = noise_apply_prob - self.split_with_space = split_with_space - self.seg_dict = None - if seg_dict_file is not None: - self.seg_dict = {} - with open(seg_dict_file, "r", encoding="utf8") as f: - lines = f.readlines() - for line in lines: - s = line.strip().split() - key = s[0] - value = s[1:] - self.seg_dict[key] = " ".join(value) - - if token_type is not None: - if token_list is None: - raise ValueError("token_list is required if token_type is not None") - self.text_cleaner = TextCleaner(text_cleaner) - - self.tokenizer = build_tokenizer( - token_type=token_type, - bpemodel=bpemodel, - delimiter=delimiter, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - g2p_type=g2p_type, - ) - self.token_id_converter = TokenIDConverter( - token_list=token_list, - unk_symbol=unk_symbol, - ) - else: - self.text_cleaner = None - self.tokenizer = None - self.token_id_converter = None - - if train and rir_scp is not None: - self.rirs = [] - with open(rir_scp, "r", encoding="utf-8") as f: - for line in f: - sps = line.strip().split(None, 1) - if len(sps) == 1: - self.rirs.append(sps[0]) - else: - self.rirs.append(sps[1]) - else: - self.rirs = None - - if train and noise_scp is not None: - self.noises = [] - with open(noise_scp, "r", encoding="utf-8") as f: - for line in f: - sps = line.strip().split(None, 1) - if len(sps) == 1: - self.noises.append(sps[0]) - else: - self.noises.append(sps[1]) - sps = noise_db_range.split("_") - if len(sps) == 1: - self.noise_db_low, self.noise_db_high = float(sps[0]) - elif len(sps) == 2: - self.noise_db_low, self.noise_db_high = float(sps[0]), float(sps[1]) - else: - raise ValueError( - "Format error: '{noise_db_range}' e.g. -3_4 -> [-3db,4db]" - ) - else: - self.noises = None - - def _speech_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, Union[str, np.ndarray]]: - if self.speech_name in data: - if self.train and (self.rirs is not None or self.noises is not None): - speech = data[self.speech_name] - nsamples = len(speech) - - # speech: (Nmic, Time) - if speech.ndim == 1: - speech = speech[None, :] - else: - speech = speech.T - # Calc power on non shlence region - power = (speech[detect_non_silence(speech)] ** 2).mean() - - # 1. Convolve RIR - if self.rirs is not None and self.rir_apply_prob >= np.random.random(): - rir_path = np.random.choice(self.rirs) - if rir_path is not None: - rir, _ = librosa.load( - rir_path, dtype=np.float64, always_2d=True - ) - - # rir: (Nmic, Time) - rir = rir.T - - # speech: (Nmic, Time) - # Note that this operation doesn't change the signal length - speech = scipy.signal.convolve(speech, rir, mode="full")[ - :, : speech.shape[1] - ] - # Reverse mean power to the original power - power2 = (speech[detect_non_silence(speech)] ** 2).mean() - speech = np.sqrt(power / max(power2, 1e-10)) * speech - - # 2. Add Noise - if ( - self.noises is not None - and self.noise_apply_prob >= np.random.random() - ): - noise_path = np.random.choice(self.noises) - if noise_path is not None: - noise_db = np.random.uniform( - self.noise_db_low, self.noise_db_high - ) - - audio_data = librosa.load(noise_path, dtype='float32')[0][None, :] - frames = len(audio_data[0]) - if frames == nsamples: - noise = audio_data - elif frames < nsamples: - offset = np.random.randint(0, nsamples - frames) - # noise: (Time, Nmic) - noise = audio_data - # Repeat noise - noise = np.pad( - noise, - [(offset, nsamples - frames - offset), (0, 0)], - mode="wrap", - ) - else: - noise = audio_data[:, nsamples] - # offset = np.random.randint(0, frames - nsamples) - # f.seek(offset) - # noise: (Time, Nmic) - # noise = f.read( - # nsamples, dtype=np.float64, always_2d=True - # ) - # if len(noise) != nsamples: - # raise RuntimeError(f"Something wrong: {noise_path}") - # noise: (Nmic, Time) - noise = noise.T - - noise_power = (noise ** 2).mean() - scale = ( - 10 ** (-noise_db / 20) - * np.sqrt(power) - / np.sqrt(max(noise_power, 1e-10)) - ) - speech = speech + scale * noise - - speech = speech.T - ma = np.max(np.abs(speech)) - if ma > 1.0: - speech /= ma - data[self.speech_name] = speech - - if self.speech_volume_normalize is not None: - speech = data[self.speech_name] - ma = np.max(np.abs(speech)) - data[self.speech_name] = speech * self.speech_volume_normalize / ma - return data - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - if self.text_name in data and self.tokenizer is not None: - text = data[self.text_name] - text = self.text_cleaner(text) - if self.split_with_space: - tokens = text.strip().split(" ") - if self.seg_dict is not None: - tokens = seg_tokenize(tokens, self.seg_dict) - else: - tokens = self.tokenizer.text2tokens(text) - text_ints = self.token_id_converter.tokens2ids(tokens) - data[self.text_name] = np.array(text_ints, dtype=np.int64) - return data - - def __call__( - self, uid: str, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - - data = self._speech_process(data) - data = self._text_process(data) - return data - -## FIXME -class LMPreprocessor(CommonPreprocessor): - def __init__( - self, - train: bool, - token_type: str = None, - token_list: Union[Path, str, Iterable[str]] = None, - bpemodel: Union[Path, str, Iterable[str]] = None, - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: str = "text", - split_with_space: bool = False, - seg_dict_file: str = None, - ): - super().__init__(train, - token_type, - token_list, - bpemodel, - text_cleaner, - g2p_type, - unk_symbol, - space_symbol, - non_linguistic_symbols, - delimiter, - rir_scp, - rir_apply_prob, - noise_scp, - noise_apply_prob, - noise_db_range, - speech_volume_normalize, - speech_name, - text_name, - split_with_space, - seg_dict_file, - ) - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - if self.text_name in data and self.tokenizer is not None: - text = data[self.text_name] - text = self.text_cleaner(text) - if self.split_with_space: - tokens = text.strip().split(" ") - if self.seg_dict is not None: - tokens = seg_tokenize_wo_pattern(tokens, self.seg_dict) - else: - tokens = self.tokenizer.text2tokens(text) - text_ints = self.token_id_converter.tokens2ids(tokens) - data[self.text_name] = np.array(text_ints, dtype=np.int64) - return data - - -class CommonPreprocessor_multi(AbsPreprocessor): - def __init__( - self, - train: bool, - token_type: str = None, - token_list: Union[Path, str, Iterable[str]] = None, - bpemodel: Union[Path, str, Iterable[str]] = None, - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - speech_name: str = "speech", - text_name: List[str] = ["text"], - ): - super().__init__(train) - self.train = train - self.speech_name = speech_name - self.text_name = text_name - - if token_type is not None: - if token_list is None: - raise ValueError("token_list is required if token_type is not None") - self.text_cleaner = TextCleaner(text_cleaner) - - self.tokenizer = build_tokenizer( - token_type=token_type, - bpemodel=bpemodel, - delimiter=delimiter, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - g2p_type=g2p_type, - ) - self.token_id_converter = TokenIDConverter( - token_list=token_list, - unk_symbol=unk_symbol, - ) - else: - self.text_cleaner = None - self.tokenizer = None - self.token_id_converter = None - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - for text_n in self.text_name: - if text_n in data and self.tokenizer is not None: - text = data[text_n] - text = self.text_cleaner(text) - tokens = self.tokenizer.text2tokens(text) - text_ints = self.token_id_converter.tokens2ids(tokens) - data[text_n] = np.array(text_ints, dtype=np.int64) - return data - - def __call__( - self, uid: str, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - - if self.speech_name in data: - # Nothing now: candidates: - # - STFT - # - Fbank - # - CMVN - # - Data augmentation - pass - - data = self._text_process(data) - return data - - -class MutliTokenizerCommonPreprocessor(CommonPreprocessor): - def __init__( - self, - train: bool, - token_type: List[str] = [None], - token_list: List[Union[Path, str, Iterable[str]]] = [None], - bpemodel: List[Union[Path, str, Iterable[str]]] = [None], - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: List[str] = ["text"], - ): - # TODO(jiatong): sync with Kamo and Jing on interface for preprocessor - super().__init__( - train=train, - token_type=token_type[0], - token_list=token_list[0], - bpemodel=bpemodel[0], - text_cleaner=text_cleaner, - g2p_type=g2p_type, - unk_symbol=unk_symbol, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - delimiter=delimiter, - speech_name=speech_name, - text_name=text_name[0], - rir_scp=rir_scp, - rir_apply_prob=rir_apply_prob, - noise_scp=noise_scp, - noise_apply_prob=noise_apply_prob, - noise_db_range=noise_db_range, - speech_volume_normalize=speech_volume_normalize, - ) - - assert ( - len(token_type) == len(token_list) == len(bpemodel) == len(text_name) - ), "token_type, token_list, bpemodel, or processing text_name mismatched" - self.num_tokenizer = len(token_type) - self.tokenizer = [] - self.token_id_converter = [] - - for i in range(self.num_tokenizer): - if token_type[i] is not None: - if token_list[i] is None: - raise ValueError("token_list is required if token_type is not None") - - self.tokenizer.append( - build_tokenizer( - token_type=token_type[i], - bpemodel=bpemodel[i], - delimiter=delimiter, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - g2p_type=g2p_type, - ) - ) - self.token_id_converter.append( - TokenIDConverter( - token_list=token_list[i], - unk_symbol=unk_symbol, - ) - ) - else: - self.tokenizer.append(None) - self.token_id_converter.append(None) - - self.text_cleaner = TextCleaner(text_cleaner) - self.text_name = text_name # override the text_name from CommonPreprocessor - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - for i in range(self.num_tokenizer): - text_name = self.text_name[i] - if text_name in data and self.tokenizer[i] is not None: - text = data[text_name] - text = self.text_cleaner(text) - tokens = self.tokenizer[i].text2tokens(text) - text_ints = self.token_id_converter[i].tokens2ids(tokens) - data[text_name] = np.array(text_ints, dtype=np.int64) - return data - -class CodeMixTokenizerCommonPreprocessor(CommonPreprocessor): - def __init__( - self, - train: bool, - token_type: str = None, - token_list: Union[Path, str, Iterable[str]] = None, - bpemodel: Union[Path, str, Iterable[str]] = None, - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: str = "text", - split_text_name: str = "split_text", - split_with_space: bool = False, - seg_jieba: bool = False, - seg_dict_file: str = None, - ): - super().__init__( - train=train, - # Force to use word. - token_type="word", - token_list=token_list, - bpemodel=bpemodel, - text_cleaner=text_cleaner, - g2p_type=g2p_type, - unk_symbol=unk_symbol, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - delimiter=delimiter, - speech_name=speech_name, - text_name=text_name, - rir_scp=rir_scp, - rir_apply_prob=rir_apply_prob, - noise_scp=noise_scp, - noise_apply_prob=noise_apply_prob, - noise_db_range=noise_db_range, - speech_volume_normalize=speech_volume_normalize, - split_with_space=split_with_space, - seg_dict_file=seg_dict_file, - ) - # The data field name for split text. - self.split_text_name = split_text_name - self.seg_jieba = seg_jieba - if self.seg_jieba: - jieba.load_userdict(seg_dict_file) - - @classmethod - def split_words(cls, text: str): - words = [] - segs = text.split() - for seg in segs: - # There is no space in seg. - current_word = "" - for c in seg: - if len(c.encode()) == 1: - # This is an ASCII char. - current_word += c - else: - # This is a Chinese char. - if len(current_word) > 0: - words.append(current_word) - current_word = "" - words.append(c) - if len(current_word) > 0: - words.append(current_word) - return words - - @classmethod - def isEnglish(cls, text:str): - if re.search('^[a-zA-Z\']+$', text): - return True - else: - return False - - @classmethod - def join_chinese_and_english(cls, input_list): - line = '' - for token in input_list: - if cls.isEnglish(token): - line = line + ' ' + token - else: - line = line + token - - line = line.strip() - return line - - @classmethod - def split_words_jieba(cls, text: str): - input_list = text.split() - token_list_all = [] - langauge_list = [] - token_list_tmp = [] - language_flag = None - for token in input_list: - if cls.isEnglish(token) and language_flag == 'Chinese': - token_list_all.append(token_list_tmp) - langauge_list.append('Chinese') - token_list_tmp = [] - elif not cls.isEnglish(token) and language_flag == 'English': - token_list_all.append(token_list_tmp) - langauge_list.append('English') - token_list_tmp = [] - - token_list_tmp.append(token) - - if cls.isEnglish(token): - language_flag = 'English' - else: - language_flag = 'Chinese' - - if token_list_tmp: - token_list_all.append(token_list_tmp) - langauge_list.append(language_flag) - - result_list = [] - for token_list_tmp, language_flag in zip(token_list_all, langauge_list): - if language_flag == 'English': - result_list.extend(token_list_tmp) - else: - seg_list = jieba.cut(cls.join_chinese_and_english(token_list_tmp), HMM=False) - result_list.extend(seg_list) - - return result_list - - def __call__( - self, uid: str, data: Dict[str, Union[list, str, np.ndarray]] - ) -> Dict[str, Union[list, np.ndarray]]: - # Split words. - if isinstance(data[self.text_name], str): - if self.seg_jieba: - # jieba.load_userdict(seg_dict_file) - split_text = self.split_words_jieba(data[self.text_name]) - else: - split_text = self.split_words(data[self.text_name]) - else: - split_text = data[self.text_name] - data[self.text_name] = " ".join(split_text) - data = self._speech_process(data) - data = self._text_process(data) - data[self.split_text_name] = split_text - return data - - def pop_split_text_data(self, data: Dict[str, Union[str, np.ndarray]]): - result = data[self.split_text_name] - del data[self.split_text_name] - return result - -class PuncTrainTokenizerCommonPreprocessor(CommonPreprocessor): - def __init__( - self, - train: bool, - token_type: List[str] = [None], - token_list: List[Union[Path, str, Iterable[str]]] = [None], - bpemodel: List[Union[Path, str, Iterable[str]]] = [None], - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: List[str] = ["text"], - vad_name: str = "vad_indexes", - ): - # TODO(jiatong): sync with Kamo and Jing on interface for preprocessor - super().__init__( - train=train, - token_type=token_type[0], - token_list=token_list[0], - bpemodel=bpemodel[0], - text_cleaner=text_cleaner, - g2p_type=g2p_type, - unk_symbol=unk_symbol, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - delimiter=delimiter, - speech_name=speech_name, - text_name=text_name[0], - rir_scp=rir_scp, - rir_apply_prob=rir_apply_prob, - noise_scp=noise_scp, - noise_apply_prob=noise_apply_prob, - noise_db_range=noise_db_range, - speech_volume_normalize=speech_volume_normalize, - ) - - assert ( - len(token_type) == len(token_list) == len(bpemodel) == len(text_name) - ), "token_type, token_list, bpemodel, or processing text_name mismatched" - self.num_tokenizer = len(token_type) - self.tokenizer = [] - self.token_id_converter = [] - - for i in range(self.num_tokenizer): - if token_type[i] is not None: - if token_list[i] is None: - raise ValueError("token_list is required if token_type is not None") - - self.tokenizer.append( - build_tokenizer( - token_type=token_type[i], - bpemodel=bpemodel[i], - delimiter=delimiter, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - g2p_type=g2p_type, - ) - ) - self.token_id_converter.append( - TokenIDConverter( - token_list=token_list[i], - unk_symbol=unk_symbol, - ) - ) - else: - self.tokenizer.append(None) - self.token_id_converter.append(None) - - self.text_cleaner = TextCleaner(text_cleaner) - self.text_name = text_name # override the text_name from CommonPreprocessor - self.vad_name = vad_name - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - for i in range(self.num_tokenizer): - text_name = self.text_name[i] - if text_name in data and self.tokenizer[i] is not None: - text = data[text_name] - text = self.text_cleaner(text) - tokens = self.tokenizer[i].text2tokens(text) - if "vad:" in tokens[-1]: - vad = tokens[-1][4:] - tokens = tokens[:-1] - if len(vad) == 0: - vad = -1 - else: - vad = int(vad) - data[self.vad_name] = np.array([vad], dtype=np.int64) - text_ints = self.token_id_converter[i].tokens2ids(tokens) - data[text_name] = np.array(text_ints, dtype=np.int64) - return data - -def split_to_mini_sentence(words: list, word_limit: int = 20): - assert word_limit > 1 - if len(words) <= word_limit: - return [words] - sentences = [] - length = len(words) - sentence_len = length // word_limit - for i in range(sentence_len): - sentences.append(words[i * word_limit:(i + 1) * word_limit]) - if length % word_limit > 0: - sentences.append(words[sentence_len * word_limit:]) - return sentences diff --git a/funasr/datasets/small_datasets/collate_fn.py b/funasr/datasets/small_datasets/collate_fn.py deleted file mode 100644 index 5fd41621d..000000000 --- a/funasr/datasets/small_datasets/collate_fn.py +++ /dev/null @@ -1,88 +0,0 @@ -from typing import Collection -from typing import Dict -from typing import List -from typing import Tuple -from typing import Union - -import numpy as np -import torch - -from funasr.modules.nets_utils import pad_list - - -class CommonCollateFn: - """Functor class of common_collate_fn()""" - - def __init__( - self, - float_pad_value: Union[float, int] = 0.0, - int_pad_value: int = -32768, - not_sequence: Collection[str] = (), - max_sample_size=None - ): - self.float_pad_value = float_pad_value - self.int_pad_value = int_pad_value - self.not_sequence = set(not_sequence) - self.max_sample_size = max_sample_size - - def __repr__(self): - return ( - f"{self.__class__}(float_pad_value={self.float_pad_value}, " - f"int_pad_value={self.float_pad_value})" - ) - - def __call__( - self, data: Collection[Tuple[str, Dict[str, np.ndarray]]] - ) -> Tuple[List[str], Dict[str, torch.Tensor]]: - return common_collate_fn( - data, - float_pad_value=self.float_pad_value, - int_pad_value=self.int_pad_value, - not_sequence=self.not_sequence, - ) - - -def common_collate_fn( - data: Collection[Tuple[str, Dict[str, np.ndarray]]], - float_pad_value: Union[float, int] = 0.0, - int_pad_value: int = -32768, - not_sequence: Collection[str] = (), -) -> Tuple[List[str], Dict[str, torch.Tensor]]: - """Concatenate ndarray-list to an array and convert to torch.Tensor. - """ - uttids = [u for u, _ in data] - data = [d for _, d in data] - - assert all(set(data[0]) == set(d) for d in data), "dict-keys mismatching" - assert all( - not k.endswith("_lengths") for k in data[0] - ), f"*_lengths is reserved: {list(data[0])}" - - output = {} - for key in data[0]: - if data[0][key].dtype.kind == "i": - pad_value = int_pad_value - else: - pad_value = float_pad_value - - array_list = [d[key] for d in data] - tensor_list = [torch.from_numpy(a) for a in array_list] - tensor = pad_list(tensor_list, pad_value) - output[key] = tensor - - if key not in not_sequence: - lens = torch.tensor([d[key].shape[0] for d in data], dtype=torch.long) - output[key + "_lengths"] = lens - - output = (uttids, output) - return output - -def crop_to_max_size(feature, target_size): - size = len(feature) - diff = size - target_size - if diff <= 0: - return feature - - start = np.random.randint(0, diff + 1) - end = size - diff + start - return feature[start:end] \ No newline at end of file diff --git a/funasr/datasets/small_datasets/dataset.py b/funasr/datasets/small_datasets/dataset.py deleted file mode 100644 index bee9f5034..000000000 --- a/funasr/datasets/small_datasets/dataset.py +++ /dev/null @@ -1,263 +0,0 @@ -# Copyright ESPnet (https://github.com/espnet/espnet). All Rights Reserved. -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -import collections -import copy -import logging -import numbers -from typing import Callable -from typing import Collection -from typing import Dict -from typing import Mapping -from typing import Union, List, Tuple - -import kaldiio -import numpy as np -import torch -from torch.utils.data.dataset import Dataset - -from funasr.fileio.npy_scp import NpyScpReader -from funasr.fileio.sound_scp import SoundScpReader - - -class AdapterForSoundScpReader(collections.abc.Mapping): - def __init__(self, loader, dtype=None): - self.loader = loader - self.dtype = dtype - self.rate = None - - def keys(self): - return self.loader.keys() - - def __len__(self): - return len(self.loader) - - def __iter__(self): - return iter(self.loader) - - def __getitem__(self, key: str) -> np.ndarray: - retval = self.loader[key] - - if isinstance(retval, tuple): - assert len(retval) == 2, len(retval) - if isinstance(retval[0], int) and isinstance(retval[1], np.ndarray): - # sound scp case - rate, array = retval - elif isinstance(retval[1], int) and isinstance(retval[0], np.ndarray): - # Extended ark format case - array, rate = retval - else: - raise RuntimeError( - f"Unexpected type: {type(retval[0])}, {type(retval[1])}" - ) - - if self.rate is not None and self.rate != rate: - raise RuntimeError( - f"Sampling rates are mismatched: {self.rate} != {rate}" - ) - self.rate = rate - # Multichannel wave fie - # array: (NSample, Channel) or (Nsample) - if self.dtype is not None: - array = array.astype(self.dtype) - - else: - # Normal ark case - assert isinstance(retval, np.ndarray), type(retval) - array = retval - if self.dtype is not None: - array = array.astype(self.dtype) - - assert isinstance(array, np.ndarray), type(array) - return array - - -def sound_loader(path, dest_sample_rate=16000, float_dtype=None): - # The file is as follows: - # utterance_id_A /some/where/a.wav - # utterance_id_B /some/where/a.flac - - # NOTE(kamo): SoundScpReader doesn't support pipe-fashion - # like Kaldi e.g. "cat a.wav |". - # NOTE(kamo): The audio signal is normalized to [-1,1] range. - loader = SoundScpReader(path, dest_sample_rate, normalize=True, always_2d=False) - - # SoundScpReader.__getitem__() returns Tuple[int, ndarray], - # but ndarray is desired, so Adapter class is inserted here - return AdapterForSoundScpReader(loader, float_dtype) - - -def kaldi_loader(path, float_dtype=None, max_cache_fd: int = 0): - loader = kaldiio.load_scp(path, max_cache_fd=max_cache_fd) - return AdapterForSoundScpReader(loader, float_dtype) - - -class ESPnetDataset(Dataset): - """ - Pytorch Dataset class for FunASR, modified from ESPnet - """ - - def __init__( - self, - path_name_type_list: Collection[Tuple[str, str, str]], - preprocess: Callable[ - [str, Dict[str, np.ndarray]], Dict[str, np.ndarray] - ] = None, - float_dtype: str = "float32", - int_dtype: str = "long", - dest_sample_rate: int = 16000, - speed_perturb: Union[list, tuple] = None, - mode: str = "train", - ): - if len(path_name_type_list) == 0: - raise ValueError( - '1 or more elements are required for "path_name_type_list"' - ) - - path_name_type_list = copy.deepcopy(path_name_type_list) - self.preprocess = preprocess - - self.float_dtype = float_dtype - self.int_dtype = int_dtype - self.dest_sample_rate = dest_sample_rate - self.speed_perturb = speed_perturb - self.mode = mode - if self.speed_perturb is not None: - logging.info("Using speed_perturb: {}".format(speed_perturb)) - - self.loader_dict = {} - self.debug_info = {} - for path, name, _type in path_name_type_list: - if name in self.loader_dict: - raise RuntimeError(f'"{name}" is duplicated for data-key') - - loader = self._build_loader(path, _type) - self.loader_dict[name] = loader - self.debug_info[name] = path, _type - if len(self.loader_dict[name]) == 0: - raise RuntimeError(f"{path} has no samples") - - def _build_loader( - self, path: str, loader_type: str - ) -> Mapping[str, Union[np.ndarray, torch.Tensor, str, List[int], numbers.Number]]: - """Helper function to instantiate Loader. - - Args: - path: The file path - loader_type: loader_type. sound, npy, text, etc - """ - if loader_type == "sound": - speed_perturb = self.speed_perturb if self.mode == "train" else None - loader = SoundScpReader(path, self.dest_sample_rate, normalize=True, always_2d=False, - speed_perturb=speed_perturb) - return AdapterForSoundScpReader(loader, self.float_dtype) - elif loader_type == "kaldi_ark": - loader = kaldiio.load_scp(path) - return AdapterForSoundScpReader(loader, self.float_dtype) - elif loader_type == "npy": - return NpyScpReader(path) - elif loader_type == "text": - text_loader = {} - with open(path, "r", encoding="utf-8") as f: - for linenum, line in enumerate(f, 1): - sps = line.rstrip().split(maxsplit=1) - if len(sps) == 1: - k, v = sps[0], "" - else: - k, v = sps - if k in text_loader: - raise RuntimeError(f"{k} is duplicated ({path}:{linenum})") - text_loader[k] = v - return text_loader - elif loader_type == "text_int": - text_int_loader = {} - with open(path, "r", encoding="utf-8") as f: - for linenum, line in enumerate(f, 1): - sps = line.rstrip().split(maxsplit=1) - if len(sps) == 1: - k, v = sps[0], "" - else: - k, v = sps - if k in text_int_loader: - raise RuntimeError(f"{k} is duplicated ({path}:{linenum})") - text_int_loader[k] = [int(i) for i in v.split()] - return text_int_loader - else: - raise RuntimeError(f"Not supported: loader_type={loader_type}") - - def has_name(self, name) -> bool: - return name in self.loader_dict - - def names(self) -> Tuple[str, ...]: - return tuple(self.loader_dict) - - def __iter__(self): - return iter(next(iter(self.loader_dict.values()))) - - def __repr__(self): - _mes = self.__class__.__name__ - _mes += "(" - for name, (path, _type) in self.debug_info.items(): - _mes += f'\n {name}: {{"path": "{path}", "type": "{_type}"}}' - _mes += f"\n preprocess: {self.preprocess})" - return _mes - - def __getitem__(self, uid: Union[str, int]) -> Tuple[str, Dict[str, np.ndarray]]: - - # Change integer-id to string-id - if isinstance(uid, int): - d = next(iter(self.loader_dict.values())) - uid = list(d)[uid] - - data = {} - # 1. Load data from each loaders - for name, loader in self.loader_dict.items(): - try: - value = loader[uid] - if isinstance(value, (list, tuple)): - value = np.array(value) - if not isinstance( - value, (np.ndarray, torch.Tensor, str, numbers.Number) - ): - raise TypeError( - f"Must be ndarray, torch.Tensor, str or Number: {type(value)}" - ) - except Exception: - path, _type = self.debug_info[name] - logging.error( - f"Error happened with path={path}, type={_type}, id={uid}" - ) - raise - - # torch.Tensor is converted to ndarray - if isinstance(value, torch.Tensor): - value = value.numpy() - elif isinstance(value, numbers.Number): - value = np.array([value]) - data[name] = value - - # 2. [Option] Apply preprocessing - # e.g. funasr.train.preprocessor:CommonPreprocessor - if self.preprocess is not None: - data = self.preprocess(uid, data) - - # 3. Force data-precision - for name in data: - value = data[name] - if not isinstance(value, np.ndarray): - raise RuntimeError( - f"All values must be converted to np.ndarray object " - f'by preprocessing, but "{name}" is still {type(value)}.' - ) - - # Cast to desired type - if value.dtype.kind == "f": - value = value.astype(self.float_dtype) - elif value.dtype.kind == "i": - value = value.astype(self.int_dtype) - else: - raise NotImplementedError(f"Not supported dtype: {value.dtype}") - data[name] = value - - retval = uid, data - return retval diff --git a/funasr/datasets/small_datasets/length_batch_sampler.py b/funasr/datasets/small_datasets/length_batch_sampler.py deleted file mode 100644 index 28404e32c..000000000 --- a/funasr/datasets/small_datasets/length_batch_sampler.py +++ /dev/null @@ -1,145 +0,0 @@ -from typing import Iterator -from typing import List -from typing import Dict -from typing import Tuple -from typing import Union - - -from funasr.fileio.read_text import load_num_sequence_text -from funasr.samplers.abs_sampler import AbsSampler - - -class LengthBatchSampler(AbsSampler): - def __init__( - self, - batch_bins: int, - shape_files: Union[Tuple[str, ...], List[str], Dict], - min_batch_size: int = 1, - sort_in_batch: str = "descending", - sort_batch: str = "ascending", - drop_last: bool = False, - padding: bool = True, - ): - assert batch_bins > 0 - if sort_batch != "ascending" and sort_batch != "descending": - raise ValueError( - f"sort_batch must be ascending or descending: {sort_batch}" - ) - if sort_in_batch != "descending" and sort_in_batch != "ascending": - raise ValueError( - f"sort_in_batch must be ascending or descending: {sort_in_batch}" - ) - - self.batch_bins = batch_bins - self.shape_files = shape_files - self.sort_in_batch = sort_in_batch - self.sort_batch = sort_batch - self.drop_last = drop_last - - # utt2shape: (Length, ...) - # uttA 100,... - # uttB 201,... - if isinstance(shape_files, dict): - utt2shapes = [shape_files] - else: - utt2shapes = [ - load_num_sequence_text(s, loader_type="csv_int") for s in shape_files - ] - - first_utt2shape = utt2shapes[0] - for s, d in zip(shape_files, utt2shapes): - if set(d) != set(first_utt2shape): - raise RuntimeError( - f"keys are mismatched between {s} != {shape_files[0]}" - ) - - # Sort samples in ascending order - # (shape order should be like (Length, Dim)) - keys = sorted(first_utt2shape, key=lambda k: first_utt2shape[k][0]) - if len(keys) == 0: - raise RuntimeError(f"0 lines found: {shape_files[0]}") - - # Decide batch-sizes - batch_sizes = [] - current_batch_keys = [] - for key in keys: - current_batch_keys.append(key) - # shape: (Length, dim1, dim2, ...) - if padding: - # bins = bs x max_length - bins = sum(len(current_batch_keys) * sh[key][0] for sh in utt2shapes) - else: - # bins = sum of lengths - bins = sum(d[k][0] for k in current_batch_keys for d in utt2shapes) - - if bins > batch_bins and len(current_batch_keys) >= min_batch_size: - batch_sizes.append(len(current_batch_keys)) - current_batch_keys = [] - else: - if len(current_batch_keys) != 0 and ( - not self.drop_last or len(batch_sizes) == 0 - ): - batch_sizes.append(len(current_batch_keys)) - - if len(batch_sizes) == 0: - # Maybe we can't reach here - raise RuntimeError("0 batches") - - # If the last batch-size is smaller than minimum batch_size, - # the samples are redistributed to the other mini-batches - if len(batch_sizes) > 1 and batch_sizes[-1] < min_batch_size: - for i in range(batch_sizes.pop(-1)): - batch_sizes[-(i % len(batch_sizes)) - 1] += 1 - - if not self.drop_last: - # Bug check - assert sum(batch_sizes) == len(keys), f"{sum(batch_sizes)} != {len(keys)}" - - # Set mini-batch - self.batch_list = [] - iter_bs = iter(batch_sizes) - bs = next(iter_bs) - minibatch_keys = [] - for key in keys: - minibatch_keys.append(key) - if len(minibatch_keys) == bs: - if sort_in_batch == "descending": - minibatch_keys.reverse() - elif sort_in_batch == "ascending": - # Key are already sorted in ascending - pass - else: - raise ValueError( - "sort_in_batch must be ascending" - f" or descending: {sort_in_batch}" - ) - self.batch_list.append(tuple(minibatch_keys)) - minibatch_keys = [] - try: - bs = next(iter_bs) - except StopIteration: - break - - if sort_batch == "ascending": - pass - elif sort_batch == "descending": - self.batch_list.reverse() - else: - raise ValueError( - f"sort_batch must be ascending or descending: {sort_batch}" - ) - - def __repr__(self): - return ( - f"{self.__class__.__name__}(" - f"N-batch={len(self)}, " - f"batch_bins={self.batch_bins}, " - f"sort_in_batch={self.sort_in_batch}, " - f"sort_batch={self.sort_batch})" - ) - - def __len__(self): - return len(self.batch_list) - - def __iter__(self) -> Iterator[Tuple[str, ...]]: - return iter(self.batch_list) diff --git a/funasr/datasets/small_datasets/preprocessor.py b/funasr/datasets/small_datasets/preprocessor.py deleted file mode 100644 index 62beaabb1..000000000 --- a/funasr/datasets/small_datasets/preprocessor.py +++ /dev/null @@ -1,867 +0,0 @@ -from abc import ABC -from abc import abstractmethod -from pathlib import Path -from typing import Collection -from typing import Dict -from typing import Iterable -from typing import List -from typing import Union - -import numpy as np -import scipy.signal -import librosa - -from funasr.tokenizer.build_tokenizer import build_tokenizer -from funasr.tokenizer.cleaner import TextCleaner -from funasr.tokenizer.token_id_converter import TokenIDConverter - - -class AbsPreprocessor(ABC): - def __init__(self, train: bool): - self.train = train - - @abstractmethod - def __call__( - self, uid: str, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - raise NotImplementedError - - -def forward_segment(text, dic): - word_list = [] - i = 0 - while i < len(text): - longest_word = text[i] - for j in range(i + 1, len(text) + 1): - word = text[i:j] - if word in dic: - if len(word) > len(longest_word): - longest_word = word - word_list.append(longest_word) - i += len(longest_word) - return word_list - - -def seg_tokenize(txt, seg_dict): - out_txt = "" - for word in txt: - if word in seg_dict: - out_txt += seg_dict[word] + " " - else: - out_txt += "" + " " - return out_txt.strip().split() - - -def seg_tokenize_wo_pattern(txt, seg_dict): - out_txt = "" - for word in txt: - if word in seg_dict: - out_txt += seg_dict[word] + " " - else: - out_txt += "" + " " - return out_txt.strip().split() - - -def framing( - x, - frame_length: int = 512, - frame_shift: int = 256, - centered: bool = True, - padded: bool = True, -): - if x.size == 0: - raise ValueError("Input array size is zero") - if frame_length < 1: - raise ValueError("frame_length must be a positive integer") - if frame_length > x.shape[-1]: - raise ValueError("frame_length is greater than input length") - if 0 >= frame_shift: - raise ValueError("frame_shift must be greater than 0") - - if centered: - pad_shape = [(0, 0) for _ in range(x.ndim - 1)] + [ - (frame_length // 2, frame_length // 2) - ] - x = np.pad(x, pad_shape, mode="constant", constant_values=0) - - if padded: - # Pad to integer number of windowed segments - # I.e make x.shape[-1] = frame_length + (nseg-1)*nstep, - # with integer nseg - nadd = (-(x.shape[-1] - frame_length) % frame_shift) % frame_length - pad_shape = [(0, 0) for _ in range(x.ndim - 1)] + [(0, nadd)] - x = np.pad(x, pad_shape, mode="constant", constant_values=0) - - # Created strided array of data segments - if frame_length == 1 and frame_length == frame_shift: - result = x[..., None] - else: - shape = x.shape[:-1] + ( - (x.shape[-1] - frame_length) // frame_shift + 1, - frame_length, - ) - strides = x.strides[:-1] + (frame_shift * x.strides[-1], x.strides[-1]) - result = np.lib.stride_tricks.as_strided(x, shape=shape, strides=strides) - return result - - -def detect_non_silence( - x: np.ndarray, - threshold: float = 0.01, - frame_length: int = 1024, - frame_shift: int = 512, - window: str = "boxcar", -) -> np.ndarray: - """Power based voice activity detection. - - Args: - x: (Channel, Time) - >>> x = np.random.randn(1000) - >>> detect = detect_non_silence(x) - >>> assert x.shape == detect.shape - >>> assert detect.dtype == np.bool - """ - if x.shape[-1] < frame_length: - return np.full(x.shape, fill_value=True, dtype=np.bool) - - if x.dtype.kind == "i": - x = x.astype(np.float64) - # framed_w: (C, T, F) - framed_w = framing( - x, - frame_length=frame_length, - frame_shift=frame_shift, - centered=False, - padded=True, - ) - framed_w *= scipy.signal.get_window(window, frame_length).astype(framed_w.dtype) - # power: (C, T) - power = (framed_w ** 2).mean(axis=-1) - # mean_power: (C, 1) - mean_power = np.mean(power, axis=-1, keepdims=True) - if np.all(mean_power == 0): - return np.full(x.shape, fill_value=True, dtype=np.bool) - # detect_frames: (C, T) - detect_frames = power / mean_power > threshold - # detects: (C, T, F) - detects = np.broadcast_to( - detect_frames[..., None], detect_frames.shape + (frame_shift,) - ) - # detects: (C, TF) - detects = detects.reshape(*detect_frames.shape[:-1], -1) - # detects: (C, TF) - return np.pad( - detects, - [(0, 0)] * (x.ndim - 1) + [(0, x.shape[-1] - detects.shape[-1])], - mode="edge", - ) - - -class CommonPreprocessor(AbsPreprocessor): - def __init__( - self, - train: bool, - token_type: str = None, - token_list: Union[Path, str, Iterable[str]] = None, - bpemodel: Union[Path, str, Iterable[str]] = None, - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: str = "text", - split_with_space: bool = False, - seg_dict_file: str = None, - ): - super().__init__(train) - self.train = train - self.speech_name = speech_name - self.text_name = text_name - self.speech_volume_normalize = speech_volume_normalize - self.rir_apply_prob = rir_apply_prob - self.noise_apply_prob = noise_apply_prob - self.split_with_space = split_with_space - self.seg_dict = None - if seg_dict_file is not None: - self.seg_dict = {} - with open(seg_dict_file) as f: - lines = f.readlines() - for line in lines: - s = line.strip().split() - key = s[0] - value = s[1:] - self.seg_dict[key] = " ".join(value) - - if token_type is not None: - if token_list is None: - raise ValueError("token_list is required if token_type is not None") - self.text_cleaner = TextCleaner(text_cleaner) - - self.tokenizer = build_tokenizer( - token_type=token_type, - bpemodel=bpemodel, - delimiter=delimiter, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - g2p_type=g2p_type, - ) - self.token_id_converter = TokenIDConverter( - token_list=token_list, - unk_symbol=unk_symbol, - ) - else: - self.text_cleaner = None - self.tokenizer = None - self.token_id_converter = None - - if train and rir_scp is not None: - self.rirs = [] - with open(rir_scp, "r", encoding="utf-8") as f: - for line in f: - sps = line.strip().split(None, 1) - if len(sps) == 1: - self.rirs.append(sps[0]) - else: - self.rirs.append(sps[1]) - else: - self.rirs = None - - if train and noise_scp is not None: - self.noises = [] - with open(noise_scp, "r", encoding="utf-8") as f: - for line in f: - sps = line.strip().split(None, 1) - if len(sps) == 1: - self.noises.append(sps[0]) - else: - self.noises.append(sps[1]) - sps = noise_db_range.split("_") - if len(sps) == 1: - self.noise_db_low, self.noise_db_high = float(sps[0]) - elif len(sps) == 2: - self.noise_db_low, self.noise_db_high = float(sps[0]), float(sps[1]) - else: - raise ValueError( - "Format error: '{noise_db_range}' e.g. -3_4 -> [-3db,4db]" - ) - else: - self.noises = None - - def _speech_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, Union[str, np.ndarray]]: - if self.speech_name in data: - if self.train and (self.rirs is not None or self.noises is not None): - speech = data[self.speech_name] - nsamples = len(speech) - - # speech: (Nmic, Time) - if speech.ndim == 1: - speech = speech[None, :] - else: - speech = speech.T - # Calc power on non shlence region - power = (speech[detect_non_silence(speech)] ** 2).mean() - - # 1. Convolve RIR - if self.rirs is not None and self.rir_apply_prob >= np.random.random(): - rir_path = np.random.choice(self.rirs) - if rir_path is not None: - rir, _ = librosa.load( - rir_path, dtype=np.float64, always_2d=True - ) - - # rir: (Nmic, Time) - rir = rir.T - - # speech: (Nmic, Time) - # Note that this operation doesn't change the signal length - speech = scipy.signal.convolve(speech, rir, mode="full")[ - :, : speech.shape[1] - ] - # Reverse mean power to the original power - power2 = (speech[detect_non_silence(speech)] ** 2).mean() - speech = np.sqrt(power / max(power2, 1e-10)) * speech - - # 2. Add Noise - if ( - self.noises is not None - and self.noise_apply_prob >= np.random.random() - ): - noise_path = np.random.choice(self.noises) - if noise_path is not None: - noise_db = np.random.uniform( - self.noise_db_low, self.noise_db_high - ) - audio_data = librosa.load(noise_path, dtype='float32')[0][None, :] - frames = len(audio_data[0]) - if frames == nsamples: - noise = audio_data - elif frames < nsamples: - offset = np.random.randint(0, nsamples - frames) - # noise: (Time, Nmic) - noise = audio_data - # Repeat noise - noise = np.pad( - noise, - [(offset, nsamples - frames - offset), (0, 0)], - mode="wrap", - ) - else: - noise = audio_data[:, nsamples] - # offset = np.random.randint(0, frames - nsamples) - # f.seek(offset) - # noise: (Time, Nmic) - # noise = f.read( - # nsamples, dtype=np.float64, always_2d=True - # ) - # if len(noise) != nsamples: - # raise RuntimeError(f"Something wrong: {noise_path}") - # noise: (Nmic, Time) - noise = noise.T - - noise_power = (noise ** 2).mean() - scale = ( - 10 ** (-noise_db / 20) - * np.sqrt(power) - / np.sqrt(max(noise_power, 1e-10)) - ) - speech = speech + scale * noise - - speech = speech.T - ma = np.max(np.abs(speech)) - if ma > 1.0: - speech /= ma - data[self.speech_name] = speech - - if self.speech_volume_normalize is not None: - speech = data[self.speech_name] - ma = np.max(np.abs(speech)) - data[self.speech_name] = speech * self.speech_volume_normalize / ma - return data - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - if self.text_name in data and self.tokenizer is not None: - text = data[self.text_name] - text = self.text_cleaner(text) - if self.split_with_space: - tokens = text.strip().split(" ") - if self.seg_dict is not None: - tokens = forward_segment("".join(tokens), self.seg_dict) - tokens = seg_tokenize(tokens, self.seg_dict) - else: - tokens = self.tokenizer.text2tokens(text) - - text_ints = self.token_id_converter.tokens2ids(tokens) - data[self.text_name] = np.array(text_ints, dtype=np.int64) - return data - - def __call__( - self, uid: str, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - - data = self._speech_process(data) - data = self._text_process(data) - return data - - -## FIXME -class LMPreprocessor(CommonPreprocessor): - def __init__( - self, - train: bool, - token_type: str = None, - token_list: Union[Path, str, Iterable[str]] = None, - bpemodel: Union[Path, str, Iterable[str]] = None, - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: str = "text", - split_with_space: bool = False, - seg_dict_file: str = None, - ): - super().__init__(train, - token_type, - token_list, - bpemodel, - text_cleaner, - g2p_type, - unk_symbol, - space_symbol, - non_linguistic_symbols, - delimiter, - rir_scp, - rir_apply_prob, - noise_scp, - noise_apply_prob, - noise_db_range, - speech_volume_normalize, - speech_name, - text_name, - split_with_space, - seg_dict_file, - ) - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - if self.text_name in data and self.tokenizer is not None: - text = data[self.text_name] - text = self.text_cleaner(text) - if self.split_with_space: - tokens = text.strip().split(" ") - if self.seg_dict is not None: - tokens = seg_tokenize_wo_pattern(tokens, self.seg_dict) - else: - tokens = self.tokenizer.text2tokens(text) - text_ints = self.token_id_converter.tokens2ids(tokens) - data[self.text_name] = np.array(text_ints, dtype=np.int64) - return data - - -class CommonPreprocessor_multi(AbsPreprocessor): - def __init__( - self, - train: bool, - token_type: str = None, - token_list: Union[Path, str, Iterable[str]] = None, - bpemodel: Union[Path, str, Iterable[str]] = None, - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - speech_name: str = "speech", - text_name: List[str] = ["text"], - ): - super().__init__(train) - self.train = train - self.speech_name = speech_name - self.text_name = text_name - - if token_type is not None: - if token_list is None: - raise ValueError("token_list is required if token_type is not None") - self.text_cleaner = TextCleaner(text_cleaner) - - self.tokenizer = build_tokenizer( - token_type=token_type, - bpemodel=bpemodel, - delimiter=delimiter, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - g2p_type=g2p_type, - ) - self.token_id_converter = TokenIDConverter( - token_list=token_list, - unk_symbol=unk_symbol, - ) - else: - self.text_cleaner = None - self.tokenizer = None - self.token_id_converter = None - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - for text_n in self.text_name: - if text_n in data and self.tokenizer is not None: - text = data[text_n] - text = self.text_cleaner(text) - tokens = self.tokenizer.text2tokens(text) - text_ints = self.token_id_converter.tokens2ids(tokens) - data[text_n] = np.array(text_ints, dtype=np.int64) - return data - - def __call__( - self, uid: str, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - - if self.speech_name in data: - # Nothing now: candidates: - # - STFT - # - Fbank - # - CMVN - # - Data augmentation - pass - - data = self._text_process(data) - return data - - -class MutliTokenizerCommonPreprocessor(CommonPreprocessor): - def __init__( - self, - train: bool, - token_type: List[str] = [None], - token_list: List[Union[Path, str, Iterable[str]]] = [None], - bpemodel: List[Union[Path, str, Iterable[str]]] = [None], - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: List[str] = ["text"], - ): - # TODO(jiatong): sync with Kamo and Jing on interface for preprocessor - super().__init__( - train=train, - token_type=token_type[0], - token_list=token_list[0], - bpemodel=bpemodel[0], - text_cleaner=text_cleaner, - g2p_type=g2p_type, - unk_symbol=unk_symbol, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - delimiter=delimiter, - speech_name=speech_name, - text_name=text_name[0], - rir_scp=rir_scp, - rir_apply_prob=rir_apply_prob, - noise_scp=noise_scp, - noise_apply_prob=noise_apply_prob, - noise_db_range=noise_db_range, - speech_volume_normalize=speech_volume_normalize, - ) - - assert ( - len(token_type) == len(token_list) == len(bpemodel) == len(text_name) - ), "token_type, token_list, bpemodel, or processing text_name mismatched" - self.num_tokenizer = len(token_type) - self.tokenizer = [] - self.token_id_converter = [] - - for i in range(self.num_tokenizer): - if token_type[i] is not None: - if token_list[i] is None: - raise ValueError("token_list is required if token_type is not None") - - self.tokenizer.append( - build_tokenizer( - token_type=token_type[i], - bpemodel=bpemodel[i], - delimiter=delimiter, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - g2p_type=g2p_type, - ) - ) - self.token_id_converter.append( - TokenIDConverter( - token_list=token_list[i], - unk_symbol=unk_symbol, - ) - ) - else: - self.tokenizer.append(None) - self.token_id_converter.append(None) - - self.text_cleaner = TextCleaner(text_cleaner) - self.text_name = text_name # override the text_name from CommonPreprocessor - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - for i in range(self.num_tokenizer): - text_name = self.text_name[i] - if text_name in data and self.tokenizer[i] is not None: - text = data[text_name] - text = self.text_cleaner(text) - tokens = self.tokenizer[i].text2tokens(text) - text_ints = self.token_id_converter[i].tokens2ids(tokens) - data[text_name] = np.array(text_ints, dtype=np.int64) - return data - - -class CodeMixTokenizerCommonPreprocessor(CommonPreprocessor): - def __init__( - self, - train: bool, - token_type: str = None, - token_list: Union[Path, str, Iterable[str]] = None, - bpemodel: Union[Path, str, Iterable[str]] = None, - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: str = "text", - split_text_name: str = "split_text", - split_with_space: bool = False, - seg_dict_file: str = None, - ): - super().__init__( - train=train, - # Force to use word. - token_type="word", - token_list=token_list, - bpemodel=bpemodel, - text_cleaner=text_cleaner, - g2p_type=g2p_type, - unk_symbol=unk_symbol, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - delimiter=delimiter, - speech_name=speech_name, - text_name=text_name, - rir_scp=rir_scp, - rir_apply_prob=rir_apply_prob, - noise_scp=noise_scp, - noise_apply_prob=noise_apply_prob, - noise_db_range=noise_db_range, - speech_volume_normalize=speech_volume_normalize, - split_with_space=split_with_space, - seg_dict_file=seg_dict_file, - ) - # The data field name for split text. - self.split_text_name = split_text_name - - @classmethod - def split_words(cls, text: str): - words = [] - segs = text.split() - for seg in segs: - # There is no space in seg. - current_word = "" - for c in seg: - if len(c.encode()) == 1: - # This is an ASCII char. - current_word += c - else: - # This is a Chinese char. - if len(current_word) > 0: - words.append(current_word) - current_word = "" - words.append(c) - if len(current_word) > 0: - words.append(current_word) - return words - - def __call__( - self, uid: str, data: Dict[str, Union[list, str, np.ndarray]] - ) -> Dict[str, Union[list, np.ndarray]]: - # Split words. - if isinstance(data[self.text_name], str): - split_text = self.split_words(data[self.text_name]) - else: - split_text = data[self.text_name] - data[self.text_name] = " ".join(split_text) - data = self._speech_process(data) - data = self._text_process(data) - data[self.split_text_name] = split_text - return data - - def pop_split_text_data(self, data: Dict[str, Union[str, np.ndarray]]): - result = data[self.split_text_name] - del data[self.split_text_name] - return result - - -class PuncTrainTokenizerCommonPreprocessor(CommonPreprocessor): - def __init__( - self, - train: bool, - token_type: List[str] = [None], - token_list: List[Union[Path, str, Iterable[str]]] = [None], - bpemodel: List[Union[Path, str, Iterable[str]]] = [None], - text_cleaner: Collection[str] = None, - g2p_type: str = None, - unk_symbol: str = "", - space_symbol: str = "", - non_linguistic_symbols: Union[Path, str, Iterable[str]] = None, - delimiter: str = None, - rir_scp: str = None, - rir_apply_prob: float = 1.0, - noise_scp: str = None, - noise_apply_prob: float = 1.0, - noise_db_range: str = "3_10", - speech_volume_normalize: float = None, - speech_name: str = "speech", - text_name: List[str] = ["text"], - vad_name: str = "vad_indexes", - ): - # TODO(jiatong): sync with Kamo and Jing on interface for preprocessor - super().__init__( - train=train, - token_type=token_type[0], - token_list=token_list[0], - bpemodel=bpemodel[0], - text_cleaner=text_cleaner, - g2p_type=g2p_type, - unk_symbol=unk_symbol, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - delimiter=delimiter, - speech_name=speech_name, - text_name=text_name[0], - rir_scp=rir_scp, - rir_apply_prob=rir_apply_prob, - noise_scp=noise_scp, - noise_apply_prob=noise_apply_prob, - noise_db_range=noise_db_range, - speech_volume_normalize=speech_volume_normalize, - ) - - assert ( - len(token_type) == len(token_list) == len(bpemodel) == len(text_name) - ), "token_type, token_list, bpemodel, or processing text_name mismatched" - self.num_tokenizer = len(token_type) - self.tokenizer = [] - self.token_id_converter = [] - - for i in range(self.num_tokenizer): - if token_type[i] is not None: - if token_list[i] is None: - raise ValueError("token_list is required if token_type is not None") - - self.tokenizer.append( - build_tokenizer( - token_type=token_type[i], - bpemodel=bpemodel[i], - delimiter=delimiter, - space_symbol=space_symbol, - non_linguistic_symbols=non_linguistic_symbols, - g2p_type=g2p_type, - ) - ) - self.token_id_converter.append( - TokenIDConverter( - token_list=token_list[i], - unk_symbol=unk_symbol, - ) - ) - else: - self.tokenizer.append(None) - self.token_id_converter.append(None) - - self.text_cleaner = TextCleaner(text_cleaner) - self.text_name = text_name # override the text_name from CommonPreprocessor - self.vad_name = vad_name - - def _text_process( - self, data: Dict[str, Union[str, np.ndarray]] - ) -> Dict[str, np.ndarray]: - for i in range(self.num_tokenizer): - text_name = self.text_name[i] - if text_name in data and self.tokenizer[i] is not None: - text = data[text_name] - text = self.text_cleaner(text) - tokens = self.tokenizer[i].text2tokens(text) - if "vad:" in tokens[-1]: - vad = tokens[-1][4:] - tokens = tokens[:-1] - if len(vad) == 0: - vad = -1 - else: - vad = int(vad) - data[self.vad_name] = np.array([vad], dtype=np.int64) - text_ints = self.token_id_converter[i].tokens2ids(tokens) - data[text_name] = np.array(text_ints, dtype=np.int64) - - -def split_to_mini_sentence(words: list, word_limit: int = 20): - assert word_limit > 1 - if len(words) <= word_limit: - return [words] - sentences = [] - length = len(words) - sentence_len = length // word_limit - for i in range(sentence_len): - sentences.append(words[i * word_limit:(i + 1) * word_limit]) - if length % word_limit > 0: - sentences.append(words[sentence_len * word_limit:]) - return sentences - - -def build_preprocess(args, train): - if not args.use_preprocessor: - return None - if args.task_name in ["asr", "data2vec", "diar", "sv"]: - retval = CommonPreprocessor( - train=train, - token_type=args.token_type, - token_list=args.token_list, - bpemodel=args.bpemodel, - non_linguistic_symbols=args.non_linguistic_symbols if hasattr(args, "non_linguistic_symbols") else None, - text_cleaner=args.cleaner, - g2p_type=args.g2p, - split_with_space=args.split_with_space if hasattr(args, "split_with_space") else False, - seg_dict_file=args.seg_dict_file if hasattr(args, "seg_dict_file") else None, - rir_scp=args.rir_scp if hasattr(args, "rir_scp") else None, - rir_apply_prob=args.rir_apply_prob if hasattr(args, "rir_apply_prob") else 1.0, - noise_scp=args.noise_scp if hasattr(args, "noise_scp") else None, - noise_apply_prob=args.noise_apply_prob if hasattr(args, "noise_apply_prob") else 1.0, - noise_db_range=args.noise_db_range if hasattr(args, "noise_db_range") else "13_15", - speech_volume_normalize=args.speech_volume_normalize if hasattr(args, "rir_scp") else None, - ) - elif args.task_name == "punc": - token_types = [args.token_type, args.token_type] - token_lists = [args.token_list, args.punc_list] - bpemodels = [args.bpemodel, args.bpemodel] - text_names = ["text", "punc"] - retval = PuncTrainTokenizerCommonPreprocessor( - train=train, - token_type=token_types, - token_list=token_lists, - bpemodel=bpemodels, - text_cleaner=args.cleaner, - g2p_type=args.g2p, - text_name=text_names, - non_linguistic_symbols=args.non_linguistic_symbols, - ) - elif args.task_name == "lm": - retval = LMPreprocessor( - train=train, - token_type=args.token_type, - token_list=args.token_list, - bpemodel=args.bpemodel, - text_cleaner=args.cleaner, - g2p_type=args.g2p, - text_name="text", - non_linguistic_symbols=args.non_linguistic_symbols, - split_with_space=args.split_with_space, - seg_dict_file=args.seg_dict_file - ) - elif args.task_name == "vad": - retval = None - else: - raise ValueError(f"Not supported task={args.task_name}") - return retval diff --git a/funasr/datasets/small_datasets/sequence_iter_factory.py b/funasr/datasets/small_datasets/sequence_iter_factory.py deleted file mode 100644 index 9dbf5d7cb..000000000 --- a/funasr/datasets/small_datasets/sequence_iter_factory.py +++ /dev/null @@ -1,189 +0,0 @@ -import logging - -import numpy as np -import torch -from torch.utils.data import DataLoader - -from funasr.datasets.small_datasets.collate_fn import CommonCollateFn -from funasr.datasets.small_datasets.dataset import ESPnetDataset -from funasr.datasets.small_datasets.length_batch_sampler import LengthBatchSampler -from funasr.datasets.small_datasets.preprocessor import build_preprocess -from funasr.iterators.abs_iter_factory import AbsIterFactory -from funasr.samplers.abs_sampler import AbsSampler - - -class RawSampler(AbsSampler): - def __init__(self, batches): - self.batches = batches - - def __len__(self): - return len(self.batches) - - def __iter__(self): - return iter(self.batches) - - def generate(self, seed): - return list(self.batches) - - -class SequenceIterFactory(AbsIterFactory): - """Build iterator for each epoch, modified from ESPnet - - """ - - def __init__(self, args, mode="train"): - - # preprocess - preprocess_fn = build_preprocess(args, train=mode == "train") - - # collate - if args.task_name in ["punc", "lm"]: - collate_fn = CommonCollateFn(int_pad_value=0) - else: - collate_fn = CommonCollateFn(float_pad_value=0.0, int_pad_value=-1) - - # dataset - dest_sample_rate = args.frontend_conf["fs"] if ( - args.frontend_conf is not None and "fs" in args.frontend_conf) else 16000 - if mode == "train": - data_path_and_name_and_type = args.train_data_path_and_name_and_type - shape_files = args.train_shape_file - elif mode == "valid": - data_path_and_name_and_type = args.valid_data_path_and_name_and_type - shape_files = args.valid_shape_file - else: - raise NotImplementedError(f"mode={mode}") - dataset = ESPnetDataset( - data_path_and_name_and_type, - preprocess=preprocess_fn, - dest_sample_rate=dest_sample_rate, - speed_perturb=args.speed_perturb if mode == "train" else None, - ) - - # sampler - dataset_conf = args.dataset_conf - batch_sampler = LengthBatchSampler( - batch_bins=dataset_conf["batch_conf"]["batch_size"] * args.ngpu, - shape_files=shape_files, - sort_in_batch=dataset_conf["sort_in_batch"] if hasattr(dataset_conf, "sort_in_batch") else "descending", - sort_batch=dataset_conf["sort_batch"] if hasattr(dataset_conf, "sort_batch") else "descending", - drop_last=False, - padding=True, - ) - - batches = list(batch_sampler) - bs_list = [len(batch) for batch in batches] - logging.info(f"[{mode}] dataset:\n{dataset}") - logging.info(f"[{mode}] Batch sampler: {batch_sampler}") - logging.info( - f"[{mode}] mini-batch sizes summary: N-batch={len(bs_list)}, " - f"mean={np.mean(bs_list):.1f}, min={np.min(bs_list)}, max={np.max(bs_list)}" - ) - - if args.scheduler == "tri_stage" and mode == "train": - args.max_update = len(bs_list) * args.max_epoch - logging.info("Max update: {}".format(args.max_update)) - - if args.distributed and mode == "train": - world_size = torch.distributed.get_world_size() - rank = torch.distributed.get_rank() - for batch in batches: - if len(batch) < world_size: - raise RuntimeError( - f"The batch-size must be equal or more than world_size: " - f"{len(batch)} < {world_size}" - ) - batches = [batch[rank::world_size] for batch in batches] - - if not isinstance(batches, AbsSampler): - self.sampler = RawSampler(batches) - else: - self.sampler = batches - - self.dataset = dataset - self.num_iters_per_epoch = None - self.shuffle = mode == "train" - self.seed = args.seed - self.num_workers = args.dataset_conf.get("num_workers", 8) - self.collate_fn = collate_fn - self.pin_memory = args.ngpu > 0 - - def build_iter(self, epoch: int, shuffle: bool = None) -> DataLoader: - if shuffle is None: - shuffle = self.shuffle - - if self.num_iters_per_epoch is not None: - N = len(self.sampler) - # If corpus size is larger than the num_per_epoch - if self.num_iters_per_epoch < N: - N = len(self.sampler) - real_epoch, offset = divmod(self.num_iters_per_epoch * epoch, N) - - if offset >= self.num_iters_per_epoch: - current_batches = self.sampler.generate(real_epoch + self.seed) - if shuffle: - np.random.RandomState(real_epoch + self.seed).shuffle( - current_batches - ) - batches = current_batches[ - offset - self.num_iters_per_epoch: offset - ] - else: - prev_batches = self.sampler.generate(real_epoch - 1 + self.seed) - current_batches = self.sampler.generate(real_epoch + self.seed) - if shuffle: - np.random.RandomState(real_epoch - 1 + self.seed).shuffle( - prev_batches - ) - np.random.RandomState(real_epoch + self.seed).shuffle( - current_batches - ) - batches = ( - prev_batches[offset - self.num_iters_per_epoch:] - + current_batches[:offset] - ) - - # If corpus size is less than the num_per_epoch - else: - _epoch, _cursor = divmod(self.num_iters_per_epoch * (epoch - 1), N) - _remain = self.num_iters_per_epoch - batches = [] - current_batches = self.sampler.generate(_epoch + self.seed) - if shuffle: - np.random.RandomState(_epoch + self.seed).shuffle(current_batches) - while _remain > 0: - - _batches = current_batches[_cursor: _cursor + _remain] - batches += _batches - if _cursor + _remain >= N: - _epoch += 1 - _cursor = 0 - current_batches = self.sampler.generate(_epoch + self.seed) - if shuffle: - np.random.RandomState(_epoch + self.seed).shuffle( - current_batches - ) - else: - _cursor = _cursor + _remain - _remain -= len(_batches) - - assert len(batches) == self.num_iters_per_epoch - - else: - batches = self.sampler.generate(epoch + self.seed) - if shuffle: - np.random.RandomState(epoch + self.seed).shuffle(batches) - - # For backward compatibility for pytorch DataLoader - if self.collate_fn is not None: - kwargs = dict(collate_fn=self.collate_fn) - else: - kwargs = {} - - return DataLoader( - dataset=self.dataset, - batch_sampler=batches, - num_workers=self.num_workers, - pin_memory=self.pin_memory, - **kwargs, - ) diff --git a/egs/aishell/transformer/utils/__init__.py b/funasr/download/__init__.py similarity index 100% rename from egs/aishell/transformer/utils/__init__.py rename to funasr/download/__init__.py diff --git a/funasr/utils/download_from_hub.py b/funasr/download/download_from_hub.py similarity index 96% rename from funasr/utils/download_from_hub.py rename to funasr/download/download_from_hub.py index d6b79d349..24ab79759 100644 --- a/funasr/utils/download_from_hub.py +++ b/funasr/download/download_from_hub.py @@ -1,7 +1,7 @@ import os from omegaconf import OmegaConf import torch -from funasr.utils.name_maps_from_hub import name_maps_ms, name_maps_hf +from funasr.download.name_maps_from_hub import name_maps_ms, name_maps_hf def download_model(**kwargs): model_hub = kwargs.get("model_hub", "ms") diff --git a/funasr/utils/modelscope_file.py b/funasr/download/modelscope_file.py similarity index 100% rename from funasr/utils/modelscope_file.py rename to funasr/download/modelscope_file.py diff --git a/funasr/utils/name_maps_from_hub.py b/funasr/download/name_maps_from_hub.py similarity index 100% rename from funasr/utils/name_maps_from_hub.py rename to funasr/download/name_maps_from_hub.py diff --git a/funasr/utils/runtime_sdk_download_tool.py b/funasr/download/runtime_sdk_download_tool.py similarity index 97% rename from funasr/utils/runtime_sdk_download_tool.py rename to funasr/download/runtime_sdk_download_tool.py index 9a0d40f67..91c584478 100644 --- a/funasr/utils/runtime_sdk_download_tool.py +++ b/funasr/download/runtime_sdk_download_tool.py @@ -30,7 +30,7 @@ if args.export: model_file = os.path.join(model_dir, 'model_quant.onnx') if not os.path.exists(model_file): print(".onnx is not exist, begin to export onnx") - from funasr.export.export_model import ModelExport + from funasr.bin.export_model import ModelExport export_model = ModelExport( cache_dir=args.export_dir, onnx=True, diff --git a/funasr/export/models/decoder/contextual_decoder.py b/funasr/export/models/decoder/contextual_decoder.py index 4e11b5d6b..c6f83d07e 100644 --- a/funasr/export/models/decoder/contextual_decoder.py +++ b/funasr/export/models/decoder/contextual_decoder.py @@ -4,11 +4,11 @@ import torch.nn as nn from funasr.export.utils.torch_function import MakePadMask from funasr.export.utils.torch_function import sequence_mask -from funasr.modules.attention import MultiHeadedAttentionSANMDecoder +from funasr.models.transformer.attention import MultiHeadedAttentionSANMDecoder from funasr.export.models.modules.multihead_att import MultiHeadedAttentionSANMDecoder as MultiHeadedAttentionSANMDecoder_export -from funasr.modules.attention import MultiHeadedAttentionCrossAtt +from funasr.models.transformer.attention import MultiHeadedAttentionCrossAtt from funasr.export.models.modules.multihead_att import MultiHeadedAttentionCrossAtt as MultiHeadedAttentionCrossAtt_export -from funasr.modules.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM +from funasr.models.transformer.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM from funasr.export.models.modules.feedforward import PositionwiseFeedForwardDecoderSANM as PositionwiseFeedForwardDecoderSANM_export from funasr.export.models.modules.decoder_layer import DecoderLayerSANM as DecoderLayerSANM_export diff --git a/funasr/export/models/decoder/sanm_decoder.py b/funasr/export/models/decoder/sanm_decoder.py index 69668475d..8f6e553bf 100644 --- a/funasr/export/models/decoder/sanm_decoder.py +++ b/funasr/export/models/decoder/sanm_decoder.py @@ -7,11 +7,11 @@ import torch.nn as nn from funasr.export.utils.torch_function import MakePadMask from funasr.export.utils.torch_function import sequence_mask -from funasr.modules.attention import MultiHeadedAttentionSANMDecoder +from funasr.models.transformer.attention import MultiHeadedAttentionSANMDecoder from funasr.export.models.modules.multihead_att import MultiHeadedAttentionSANMDecoder as MultiHeadedAttentionSANMDecoder_export -from funasr.modules.attention import MultiHeadedAttentionCrossAtt +from funasr.models.transformer.attention import MultiHeadedAttentionCrossAtt from funasr.export.models.modules.multihead_att import MultiHeadedAttentionCrossAtt as MultiHeadedAttentionCrossAtt_export -from funasr.modules.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM +from funasr.models.transformer.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM from funasr.export.models.modules.feedforward import PositionwiseFeedForwardDecoderSANM as PositionwiseFeedForwardDecoderSANM_export from funasr.export.models.modules.decoder_layer import DecoderLayerSANM as DecoderLayerSANM_export diff --git a/funasr/export/models/decoder/transformer_decoder.py b/funasr/export/models/decoder/transformer_decoder.py index d70a3c750..727f5d7aa 100644 --- a/funasr/export/models/decoder/transformer_decoder.py +++ b/funasr/export/models/decoder/transformer_decoder.py @@ -8,12 +8,12 @@ import torch.nn as nn from funasr.export.utils.torch_function import MakePadMask from funasr.export.utils.torch_function import sequence_mask -from funasr.modules.attention import MultiHeadedAttentionSANMDecoder +from funasr.models.transformer.attention import MultiHeadedAttentionSANMDecoder from funasr.export.models.modules.multihead_att import MultiHeadedAttentionSANMDecoder as MultiHeadedAttentionSANMDecoder_export -from funasr.modules.attention import MultiHeadedAttentionCrossAtt, MultiHeadedAttention +from funasr.models.transformer.attention import MultiHeadedAttentionCrossAtt, MultiHeadedAttention from funasr.export.models.modules.multihead_att import MultiHeadedAttentionCrossAtt as MultiHeadedAttentionCrossAtt_export from funasr.export.models.modules.multihead_att import OnnxMultiHeadedAttention -from funasr.modules.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM +from funasr.models.transformer.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM from funasr.export.models.modules.feedforward import PositionwiseFeedForwardDecoderSANM as PositionwiseFeedForwardDecoderSANM_export from funasr.export.models.modules.decoder_layer import DecoderLayer as DecoderLayer_export diff --git a/funasr/export/models/decoder/xformer_decoder.py b/funasr/export/models/decoder/xformer_decoder.py index 15199aacf..9215c0037 100644 --- a/funasr/export/models/decoder/xformer_decoder.py +++ b/funasr/export/models/decoder/xformer_decoder.py @@ -3,7 +3,7 @@ import os import torch import torch.nn as nn -from funasr.modules.attention import MultiHeadedAttention +from funasr.models.transformer.attention import MultiHeadedAttention from funasr.export.models.modules.decoder_layer import DecoderLayer as OnnxDecoderLayer from funasr.export.models.language_models.embed import Embedding diff --git a/funasr/export/models/encoder/conformer_encoder.py b/funasr/export/models/encoder/conformer_encoder.py index 0a3565304..76719c566 100644 --- a/funasr/export/models/encoder/conformer_encoder.py +++ b/funasr/export/models/encoder/conformer_encoder.py @@ -3,14 +3,14 @@ import torch.nn as nn from funasr.export.utils.torch_function import MakePadMask from funasr.export.utils.torch_function import sequence_mask -from funasr.modules.attention import MultiHeadedAttentionSANM +from funasr.models.transformer.attention import MultiHeadedAttentionSANM from funasr.export.models.modules.multihead_att import MultiHeadedAttentionSANM as MultiHeadedAttentionSANM_export from funasr.export.models.modules.encoder_layer import EncoderLayerSANM as EncoderLayerSANM_export from funasr.export.models.modules.encoder_layer import EncoderLayerConformer as EncoderLayerConformer_export -from funasr.modules.positionwise_feed_forward import PositionwiseFeedForward +from funasr.models.transformer.positionwise_feed_forward import PositionwiseFeedForward from funasr.export.models.modules.feedforward import PositionwiseFeedForward as PositionwiseFeedForward_export from funasr.export.models.encoder.sanm_encoder import SANMEncoder -from funasr.modules.attention import RelPositionMultiHeadedAttention +from funasr.models.transformer.attention import RelPositionMultiHeadedAttention # from funasr.export.models.modules.multihead_att import RelPositionMultiHeadedAttention as RelPositionMultiHeadedAttention_export from funasr.export.models.modules.multihead_att import OnnxRelPosMultiHeadedAttention as RelPositionMultiHeadedAttention_export diff --git a/funasr/export/models/encoder/sanm_encoder.py b/funasr/export/models/encoder/sanm_encoder.py index d1b4b1e94..7ef863e87 100644 --- a/funasr/export/models/encoder/sanm_encoder.py +++ b/funasr/export/models/encoder/sanm_encoder.py @@ -3,12 +3,12 @@ import torch.nn as nn from funasr.export.utils.torch_function import MakePadMask from funasr.export.utils.torch_function import sequence_mask -from funasr.modules.attention import MultiHeadedAttentionSANM +from funasr.models.transformer.attention import MultiHeadedAttentionSANM from funasr.export.models.modules.multihead_att import MultiHeadedAttentionSANM as MultiHeadedAttentionSANM_export from funasr.export.models.modules.encoder_layer import EncoderLayerSANM as EncoderLayerSANM_export -from funasr.modules.positionwise_feed_forward import PositionwiseFeedForward +from funasr.models.transformer.positionwise_feed_forward import PositionwiseFeedForward from funasr.export.models.modules.feedforward import PositionwiseFeedForward as PositionwiseFeedForward_export -from funasr.modules.embedding import StreamSinusoidalPositionEncoder +from funasr.models.transformer.embedding import StreamSinusoidalPositionEncoder class SANMEncoder(nn.Module): diff --git a/funasr/fileio/npy_scp.py b/funasr/fileio/npy_scp.py deleted file mode 100644 index 2bd5b5867..000000000 --- a/funasr/fileio/npy_scp.py +++ /dev/null @@ -1,94 +0,0 @@ -import collections.abc -from pathlib import Path -from typing import Union - -import numpy as np - -from funasr.fileio.read_text import read_2column_text - - -class NpyScpWriter: - """Writer class for a scp file of numpy file. - - Examples: - key1 /some/path/a.npy - key2 /some/path/b.npy - key3 /some/path/c.npy - key4 /some/path/d.npy - ... - - >>> writer = NpyScpWriter('./data/', './data/feat.scp') - >>> writer['aa'] = numpy_array - >>> writer['bb'] = numpy_array - - """ - - def __init__(self, outdir: Union[Path, str], scpfile: Union[Path, str]): - self.dir = Path(outdir) - self.dir.mkdir(parents=True, exist_ok=True) - scpfile = Path(scpfile) - scpfile.parent.mkdir(parents=True, exist_ok=True) - self.fscp = scpfile.open("w", encoding="utf-8") - - self.data = {} - - def get_path(self, key): - return self.data[key] - - def __setitem__(self, key, value): - assert isinstance(value, np.ndarray), type(value) - p = self.dir / f"{key}.npy" - p.parent.mkdir(parents=True, exist_ok=True) - np.save(str(p), value) - self.fscp.write(f"{key} {p}\n") - - # Store the file path - self.data[key] = str(p) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - - def close(self): - self.fscp.close() - - -class NpyScpReader(collections.abc.Mapping): - """Reader class for a scp file of numpy file. - - Examples: - key1 /some/path/a.npy - key2 /some/path/b.npy - key3 /some/path/c.npy - key4 /some/path/d.npy - ... - - >>> reader = NpyScpReader('npy.scp') - >>> array = reader['key1'] - - """ - - def __init__(self, fname: Union[Path, str]): - self.fname = Path(fname) - self.data = read_2column_text(fname) - - def get_path(self, key): - return self.data[key] - - def __getitem__(self, key) -> np.ndarray: - p = self.data[key] - return np.load(p) - - def __contains__(self, item): - return item - - def __len__(self): - return len(self.data) - - def __iter__(self): - return iter(self.data) - - def keys(self): - return self.data.keys() diff --git a/funasr/fileio/rand_gen_dataset.py b/funasr/fileio/rand_gen_dataset.py deleted file mode 100644 index 699e67a5f..000000000 --- a/funasr/fileio/rand_gen_dataset.py +++ /dev/null @@ -1,83 +0,0 @@ -import collections -from pathlib import Path -from typing import Union - -import numpy as np - -from funasr.fileio.read_text import load_num_sequence_text - - -class FloatRandomGenerateDataset(collections.abc.Mapping): - """Generate float array from shape.txt. - - Examples: - shape.txt - uttA 123,83 - uttB 34,83 - >>> dataset = FloatRandomGenerateDataset("shape.txt") - >>> array = dataset["uttA"] - >>> assert array.shape == (123, 83) - >>> array = dataset["uttB"] - >>> assert array.shape == (34, 83) - - """ - - def __init__( - self, - shape_file: Union[Path, str], - dtype: Union[str, np.dtype] = "float32", - loader_type: str = "csv_int", - ): - shape_file = Path(shape_file) - self.utt2shape = load_num_sequence_text(shape_file, loader_type) - self.dtype = np.dtype(dtype) - - def __iter__(self): - return iter(self.utt2shape) - - def __len__(self): - return len(self.utt2shape) - - def __getitem__(self, item) -> np.ndarray: - shape = self.utt2shape[item] - return np.random.randn(*shape).astype(self.dtype) - - -class IntRandomGenerateDataset(collections.abc.Mapping): - """Generate float array from shape.txt - - Examples: - shape.txt - uttA 123,83 - uttB 34,83 - >>> dataset = IntRandomGenerateDataset("shape.txt", low=0, high=10) - >>> array = dataset["uttA"] - >>> assert array.shape == (123, 83) - >>> array = dataset["uttB"] - >>> assert array.shape == (34, 83) - - """ - - def __init__( - self, - shape_file: Union[Path, str], - low: int, - high: int = None, - dtype: Union[str, np.dtype] = "int64", - loader_type: str = "csv_int", - ): - shape_file = Path(shape_file) - self.utt2shape = load_num_sequence_text(shape_file, loader_type) - self.dtype = np.dtype(dtype) - self.low = low - self.high = high - - def __iter__(self): - return iter(self.utt2shape) - - def __len__(self): - return len(self.utt2shape) - - def __getitem__(self, item) -> np.ndarray: - shape = self.utt2shape[item] - return np.random.randint(self.low, self.high, size=shape, dtype=self.dtype) diff --git a/funasr/fileio/read_text.py b/funasr/fileio/read_text.py deleted file mode 100644 index f140c31f2..000000000 --- a/funasr/fileio/read_text.py +++ /dev/null @@ -1,78 +0,0 @@ -import logging -from pathlib import Path -from typing import Dict -from typing import List -from typing import Union - - - -def read_2column_text(path: Union[Path, str]) -> Dict[str, str]: - """Read a text file having 2 column as dict object. - - Examples: - wav.scp: - key1 /some/path/a.wav - key2 /some/path/b.wav - - >>> read_2column_text('wav.scp') - {'key1': '/some/path/a.wav', 'key2': '/some/path/b.wav'} - - """ - - data = {} - with Path(path).open("r", encoding="utf-8") as f: - for linenum, line in enumerate(f, 1): - sps = line.rstrip().split(maxsplit=1) - if len(sps) == 1: - k, v = sps[0], "" - else: - k, v = sps - if k in data: - raise RuntimeError(f"{k} is duplicated ({path}:{linenum})") - data[k] = v - return data - - -def load_num_sequence_text( - path: Union[Path, str], loader_type: str = "csv_int" -) -> Dict[str, List[Union[float, int]]]: - """Read a text file indicating sequences of number - - Examples: - key1 1 2 3 - key2 34 5 6 - - >>> d = load_num_sequence_text('text') - >>> np.testing.assert_array_equal(d["key1"], np.array([1, 2, 3])) - """ - if loader_type == "text_int": - delimiter = " " - dtype = int - elif loader_type == "text_float": - delimiter = " " - dtype = float - elif loader_type == "csv_int": - delimiter = "," - dtype = int - elif loader_type == "csv_float": - delimiter = "," - dtype = float - else: - raise ValueError(f"Not supported loader_type={loader_type}") - - # path looks like: - # utta 1,0 - # uttb 3,4,5 - # -> return {'utta': np.ndarray([1, 0]), - # 'uttb': np.ndarray([3, 4, 5])} - d = read_2column_text(path) - - # Using for-loop instead of dict-comprehension for debuggability - retval = {} - for k, v in d.items(): - try: - retval[k] = [dtype(i) for i in v.split(delimiter)] - except TypeError: - logging.error(f'Error happened with path="{path}", id="{k}", value="{v}"') - raise - return retval diff --git a/funasr/fileio/sound_scp.py b/funasr/fileio/sound_scp.py deleted file mode 100644 index b9364c62d..000000000 --- a/funasr/fileio/sound_scp.py +++ /dev/null @@ -1,218 +0,0 @@ -import collections.abc -from pathlib import Path -from typing import List, Tuple, Union - -import random -import numpy as np -import librosa -import librosa - -import torch -import torchaudio - -from funasr.fileio.read_text import read_2column_text - -def soundfile_read( - wavs: Union[str, List[str]], - dtype=None, - always_2d: bool = False, - concat_axis: int = 1, - start: int = 0, - end: int = None, - return_subtype: bool = False, -) -> Tuple[np.array, int]: - if isinstance(wavs, str): - wavs = [wavs] - - arrays = [] - subtypes = [] - prev_rate = None - prev_wav = None - for wav in wavs: - with soundfile.SoundFile(wav) as f: - f.seek(start) - if end is not None: - frames = end - start - else: - frames = -1 - if dtype == "float16": - array = f.read( - frames, - dtype="float32", - always_2d=always_2d, - ).astype(dtype) - else: - array = f.read(frames, dtype=dtype, always_2d=always_2d) - rate = f.samplerate - subtype = f.subtype - subtypes.append(subtype) - - if len(wavs) > 1 and array.ndim == 1 and concat_axis == 1: - # array: (Time, Channel) - array = array[:, None] - - if prev_wav is not None: - if prev_rate != rate: - raise RuntimeError( - f"'{prev_wav}' and '{wav}' have mismatched sampling rate: " - f"{prev_rate} != {rate}" - ) - - dim1 = arrays[0].shape[1 - concat_axis] - dim2 = array.shape[1 - concat_axis] - if dim1 != dim2: - raise RuntimeError( - "Shapes must match with " - f"{1 - concat_axis} axis, but gut {dim1} and {dim2}" - ) - - prev_rate = rate - prev_wav = wav - arrays.append(array) - - if len(arrays) == 1: - array = arrays[0] - else: - array = np.concatenate(arrays, axis=concat_axis) - - if return_subtype: - return array, rate, subtypes - else: - return array, rate - - -class SoundScpReader(collections.abc.Mapping): - """Reader class for 'wav.scp'. - - Examples: - key1 /some/path/a.wav - key2 /some/path/b.wav - key3 /some/path/c.wav - key4 /some/path/d.wav - ... - - >>> reader = SoundScpReader('wav.scp') - >>> rate, array = reader['key1'] - - """ - - def __init__( - self, - fname, - dtype=np.int16, - always_2d: bool = False, - normalize: bool = False, - dest_sample_rate: int = 16000, - speed_perturb: Union[list, tuple] = None, - ): - self.fname = fname - self.dtype = dtype - self.always_2d = always_2d - self.normalize = normalize - self.data = read_2column_text(fname) - self.dest_sample_rate = dest_sample_rate - self.speed_perturb = speed_perturb - - def __getitem__(self, key): - wav = self.data[key] - if self.normalize: - # librosa.load normalizes data to [-1,1] if dtype is not given - array, rate = librosa.load( - wav, sr=self.dest_sample_rate, mono=self.always_2d - ) - else: - array, rate = librosa.load( - wav, sr=self.dest_sample_rate, mono=self.always_2d, dtype=self.dtype - ) - - if self.speed_perturb is not None: - speed = random.choice(self.speed_perturb) - if speed != 1.0: - array, _ = torchaudio.sox_effects.apply_effects_tensor( - torch.tensor(array).view(1, -1), rate, - [['speed', str(speed)], ['rate', str(rate)]]) - array = array.view(-1).numpy() - - if array.ndim==2: - array=array.transpose((1, 0)) - - return rate, array - - def get_path(self, key): - return self.data[key] - - def __contains__(self, item): - return item - - def __len__(self): - return len(self.data) - - def __iter__(self): - return iter(self.data) - - def keys(self): - return self.data.keys() - - -class SoundScpWriter: - """Writer class for 'wav.scp' - - Examples: - key1 /some/path/a.wav - key2 /some/path/b.wav - key3 /some/path/c.wav - key4 /some/path/d.wav - ... - - >>> writer = SoundScpWriter('./data/', './data/feat.scp') - >>> writer['aa'] = 16000, numpy_array - >>> writer['bb'] = 16000, numpy_array - - """ - - def __init__( - self, - outdir: Union[Path, str], - scpfile: Union[Path, str], - format="wav", - dtype=None, - ): - self.dir = Path(outdir) - self.dir.mkdir(parents=True, exist_ok=True) - scpfile = Path(scpfile) - scpfile.parent.mkdir(parents=True, exist_ok=True) - self.fscp = scpfile.open("w", encoding="utf-8") - self.format = format - self.dtype = dtype - - self.data = {} - - def __setitem__(self, key: str, value): - rate, signal = value - assert isinstance(rate, int), type(rate) - assert isinstance(signal, np.ndarray), type(signal) - if signal.ndim not in (1, 2): - raise RuntimeError(f"Input signal must be 1 or 2 dimension: {signal.ndim}") - if signal.ndim == 1: - signal = signal[:, None] - - wav = self.dir / f"{key}.{self.format}" - wav.parent.mkdir(parents=True, exist_ok=True) - soundfile.write(str(wav), signal, rate) - - self.fscp.write(f"{key} {wav}\n") - - # Store the file path - self.data[key] = str(wav) - - def get_path(self, key): - return self.data[key] - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - - def close(self): - self.fscp.close() diff --git a/funasr/iterators/abs_iter_factory.py b/funasr/iterators/abs_iter_factory.py deleted file mode 100644 index 36e4dd2c5..000000000 --- a/funasr/iterators/abs_iter_factory.py +++ /dev/null @@ -1,9 +0,0 @@ -from abc import ABC -from abc import abstractmethod -from typing import Iterator - - -class AbsIterFactory(ABC): - @abstractmethod - def build_iter(self, epoch: int, shuffle: bool = None) -> Iterator: - raise NotImplementedError diff --git a/funasr/iterators/chunk_iter_factory.py b/funasr/iterators/chunk_iter_factory.py deleted file mode 100644 index 5a5463270..000000000 --- a/funasr/iterators/chunk_iter_factory.py +++ /dev/null @@ -1,213 +0,0 @@ -import logging -from typing import Any -from typing import Dict -from typing import Iterator -from typing import List -from typing import Sequence -from typing import Tuple -from typing import Union - -import numpy as np -import torch - -from funasr.iterators.abs_iter_factory import AbsIterFactory -from funasr.iterators.sequence_iter_factory import SequenceIterFactory -from funasr.samplers.abs_sampler import AbsSampler - - -class ChunkIterFactory(AbsIterFactory): - """Creates chunks from a sequence - - Examples: - >>> batches = [["id1"], ["id2"], ...] - >>> batch_size = 128 - >>> chunk_length = 1000 - >>> iter_factory = ChunkIterFactory(dataset, batches, batch_size, chunk_length) - >>> it = iter_factory.build_iter(epoch) - >>> for ids, batch in it: - ... ... - - - The number of mini-batches are varied in each epochs and - we can't get the number in advance - because IterFactory doesn't be given to the length information. - - Since the first reason, "num_iters_per_epoch" can't be implemented - for this iterator. Instead of it, "num_samples_per_epoch" is implemented. - - """ - - def __init__( - self, - dataset, - batch_size: int, - batches: Union[AbsSampler, Sequence[Sequence[Any]]], - chunk_length: Union[int, str], - chunk_shift_ratio: float = 0.5, - num_cache_chunks: int = 1024, - num_samples_per_epoch: int = None, - seed: int = 0, - shuffle: bool = False, - num_workers: int = 0, - collate_fn=None, - pin_memory: bool = False, - ): - assert all(len(x) == 1 for x in batches), "batch-size must be 1" - - self.per_sample_iter_factory = SequenceIterFactory( - dataset=dataset, - batches=batches, - num_iters_per_epoch=num_samples_per_epoch, - seed=seed, - shuffle=shuffle, - num_workers=num_workers, - collate_fn=collate_fn, - pin_memory=pin_memory, - ) - - self.num_cache_chunks = max(num_cache_chunks, batch_size) - if isinstance(chunk_length, str): - if len(chunk_length) == 0: - raise ValueError("e.g. 5,8 or 3-5: but got empty string") - - self.chunk_lengths = [] - for x in chunk_length.split(","): - try: - sps = list(map(int, x.split("-"))) - except ValueError: - raise ValueError(f"e.g. 5,8 or 3-5: but got {chunk_length}") - - if len(sps) > 2: - raise ValueError(f"e.g. 5,8 or 3-5: but got {chunk_length}") - elif len(sps) == 2: - # Append all numbers between the range into the candidates - self.chunk_lengths += list(range(sps[0], sps[1] + 1)) - else: - self.chunk_lengths += [sps[0]] - else: - # Single candidates: Fixed chunk length - self.chunk_lengths = [chunk_length] - - self.chunk_shift_ratio = chunk_shift_ratio - self.batch_size = batch_size - self.seed = seed - self.shuffle = shuffle - - def build_iter( - self, - epoch: int, - shuffle: bool = None, - ) -> Iterator[Tuple[List[str], Dict[str, torch.Tensor]]]: - per_sample_loader = self.per_sample_iter_factory.build_iter(epoch, shuffle) - - if shuffle is None: - shuffle = self.shuffle - state = np.random.RandomState(epoch + self.seed) - - # NOTE(kamo): - # This iterator supports multiple chunk lengths and - # keep chunks for each lengths here until collecting specified numbers - cache_chunks_dict = {} - cache_id_list_dict = {} - for ids, batch in per_sample_loader: - # Must be per-sample-loader - assert len(ids) == 1, f"Must be per-sample-loader: {len(ids)}" - assert all(len(x) == 1 for x in batch.values()) - - # Get keys of sequence data - sequence_keys = [] - for key in batch: - if key + "_lengths" in batch: - sequence_keys.append(key) - # Remove lengths data and get the first sample - batch = {k: v[0] for k, v in batch.items() if not k.endswith("_lengths")} - id_ = ids[0] - - for key in sequence_keys: - if len(batch[key]) != len(batch[sequence_keys[0]]): - raise RuntimeError( - f"All sequences must has same length: " - f"{len(batch[key])} != {len(batch[sequence_keys[0]])}" - ) - - L = len(batch[sequence_keys[0]]) - # Select chunk length - chunk_lengths = [lg for lg in self.chunk_lengths if lg < L] - if len(chunk_lengths) == 0: - logging.warning( - f"The length of '{id_}' is {L}, but it is shorter than " - f"any candidates of chunk-length: {self.chunk_lengths}" - ) - continue - - W = int(state.choice(chunk_lengths, 1)) - cache_id_list = cache_id_list_dict.setdefault(W, []) - cache_chunks = cache_chunks_dict.setdefault(W, {}) - - # Shift width to the next chunk - S = int(W * self.chunk_shift_ratio) - # Number of chunks - N = (L - W) // S + 1 - if shuffle: - Z = state.randint(0, (L - W) % S + 1) - else: - Z = 0 - - # Split a sequence into chunks. - # Note that the marginal frames divided by chunk length are discarded - for k, v in batch.items(): - if k not in cache_chunks: - cache_chunks[k] = [] - if k in sequence_keys: - # Shift chunks with overlapped length for data augmentation - cache_chunks[k] += [v[Z + i * S : Z + i * S + W] for i in range(N)] - else: - # If not sequence, use whole data instead of chunk - cache_chunks[k] += [v for _ in range(N)] - cache_id_list += [id_ for _ in range(N)] - - if len(cache_id_list) > self.num_cache_chunks: - cache_id_list, cache_chunks = yield from self._generate_mini_batches( - cache_id_list, - cache_chunks, - shuffle, - state, - ) - - cache_id_list_dict[W] = cache_id_list - cache_chunks_dict[W] = cache_chunks - - else: - for W in cache_id_list_dict: - cache_id_list = cache_id_list_dict.setdefault(W, []) - cache_chunks = cache_chunks_dict.setdefault(W, {}) - - yield from self._generate_mini_batches( - cache_id_list, - cache_chunks, - shuffle, - state, - ) - - def _generate_mini_batches( - self, - id_list: List[str], - batches: Dict[str, List[torch.Tensor]], - shuffle: bool, - state: np.random.RandomState, - ): - if shuffle: - indices = np.arange(0, len(id_list)) - state.shuffle(indices) - batches = {k: [v[i] for i in indices] for k, v in batches.items()} - id_list = [id_list[i] for i in indices] - - bs = self.batch_size - while len(id_list) >= bs: - # Make mini-batch and yield - yield ( - id_list[:bs], - {k: torch.stack(v[:bs], 0) for k, v in batches.items()}, - ) - id_list = id_list[bs:] - batches = {k: v[bs:] for k, v in batches.items()} - - return id_list, batches diff --git a/funasr/iterators/multiple_iter_factory.py b/funasr/iterators/multiple_iter_factory.py deleted file mode 100644 index 3587a2abc..000000000 --- a/funasr/iterators/multiple_iter_factory.py +++ /dev/null @@ -1,35 +0,0 @@ -import logging -from typing import Callable -from typing import Collection -from typing import Iterator - -import numpy as np - -from funasr.iterators.abs_iter_factory import AbsIterFactory - - -class MultipleIterFactory(AbsIterFactory): - def __init__( - self, - build_funcs: Collection[Callable[[], AbsIterFactory]], - seed: int = 0, - shuffle: bool = False, - ): - self.build_funcs = list(build_funcs) - self.seed = seed - self.shuffle = shuffle - - def build_iter(self, epoch: int, shuffle: bool = None) -> Iterator: - if shuffle is None: - shuffle = self.shuffle - - build_funcs = list(self.build_funcs) - - if shuffle: - np.random.RandomState(epoch + self.seed).shuffle(build_funcs) - - for i, build_func in enumerate(build_funcs): - logging.info(f"Building {i}th iter-factory...") - iter_factory = build_func() - assert isinstance(iter_factory, AbsIterFactory), type(iter_factory) - yield from iter_factory.build_iter(epoch, shuffle) diff --git a/funasr/iterators/sequence_iter_factory.py b/funasr/iterators/sequence_iter_factory.py deleted file mode 100644 index 41de37c53..000000000 --- a/funasr/iterators/sequence_iter_factory.py +++ /dev/null @@ -1,141 +0,0 @@ -from typing import Any -from typing import Sequence -from typing import Union - -import numpy as np -from torch.utils.data import DataLoader - -from funasr.iterators.abs_iter_factory import AbsIterFactory -from funasr.samplers.abs_sampler import AbsSampler - - -class RawSampler(AbsSampler): - def __init__(self, batches): - self.batches = batches - - def __len__(self): - return len(self.batches) - - def __iter__(self): - return iter(self.batches) - - def generate(self, seed): - return list(self.batches) - - -class SequenceIterFactory(AbsIterFactory): - """Build iterator for each epoch. - - This class simply creates pytorch DataLoader except for the following points: - - The random seed is decided according to the number of epochs. This feature - guarantees reproducibility when resuming from middle of training process. - - Enable to restrict the number of samples for one epoch. This features - controls the interval number between training and evaluation. - - """ - - def __init__( - self, - dataset, - batches: Union[AbsSampler, Sequence[Sequence[Any]]], - num_iters_per_epoch: int = None, - seed: int = 0, - shuffle: bool = False, - num_workers: int = 0, - collate_fn=None, - pin_memory: bool = False, - ): - - if not isinstance(batches, AbsSampler): - self.sampler = RawSampler(batches) - else: - self.sampler = batches - - self.dataset = dataset - self.num_iters_per_epoch = num_iters_per_epoch - self.shuffle = shuffle - self.seed = seed - self.num_workers = num_workers - self.collate_fn = collate_fn - # https://discuss.pytorch.org/t/what-is-the-disadvantage-of-using-pin-memory/1702 - self.pin_memory = pin_memory - - def build_iter(self, epoch: int, shuffle: bool = None) -> DataLoader: - if shuffle is None: - shuffle = self.shuffle - - if self.num_iters_per_epoch is not None: - N = len(self.sampler) - # If corpus size is larger than the num_per_epoch - if self.num_iters_per_epoch < N: - N = len(self.sampler) - real_epoch, offset = divmod(self.num_iters_per_epoch * epoch, N) - - if offset >= self.num_iters_per_epoch: - current_batches = self.sampler.generate(real_epoch + self.seed) - if shuffle: - np.random.RandomState(real_epoch + self.seed).shuffle( - current_batches - ) - batches = current_batches[ - offset - self.num_iters_per_epoch : offset - ] - else: - prev_batches = self.sampler.generate(real_epoch - 1 + self.seed) - current_batches = self.sampler.generate(real_epoch + self.seed) - if shuffle: - np.random.RandomState(real_epoch - 1 + self.seed).shuffle( - prev_batches - ) - np.random.RandomState(real_epoch + self.seed).shuffle( - current_batches - ) - batches = ( - prev_batches[offset - self.num_iters_per_epoch :] - + current_batches[:offset] - ) - - # If corpus size is less than the num_per_epoch - else: - _epoch, _cursor = divmod(self.num_iters_per_epoch * (epoch - 1), N) - _remain = self.num_iters_per_epoch - batches = [] - current_batches = self.sampler.generate(_epoch + self.seed) - if shuffle: - np.random.RandomState(_epoch + self.seed).shuffle(current_batches) - while _remain > 0: - - _batches = current_batches[_cursor : _cursor + _remain] - batches += _batches - if _cursor + _remain >= N: - _epoch += 1 - _cursor = 0 - current_batches = self.sampler.generate(_epoch + self.seed) - if shuffle: - np.random.RandomState(_epoch + self.seed).shuffle( - current_batches - ) - else: - _cursor = _cursor + _remain - _remain -= len(_batches) - - assert len(batches) == self.num_iters_per_epoch - - else: - batches = self.sampler.generate(epoch + self.seed) - if shuffle: - np.random.RandomState(epoch + self.seed).shuffle(batches) - - # For backward compatibility for pytorch DataLoader - if self.collate_fn is not None: - kwargs = dict(collate_fn=self.collate_fn) - else: - kwargs = {} - - return DataLoader( - dataset=self.dataset, - batch_sampler=batches, - num_workers=self.num_workers, - pin_memory=self.pin_memory, - **kwargs, - ) diff --git a/funasr/layers/abs_normalize.py b/funasr/layers/abs_normalize.py deleted file mode 100644 index 4e617d0e1..000000000 --- a/funasr/layers/abs_normalize.py +++ /dev/null @@ -1,14 +0,0 @@ -from abc import ABC -from abc import abstractmethod -from typing import Tuple - -import torch - - -class AbsNormalize(torch.nn.Module, ABC): - @abstractmethod - def forward( - self, input: torch.Tensor, input_lengths: torch.Tensor = None - ) -> Tuple[torch.Tensor, torch.Tensor]: - # return output, output_lengths - raise NotImplementedError \ No newline at end of file diff --git a/funasr/layers/inversible_interface.py b/funasr/layers/inversible_interface.py deleted file mode 100644 index 657ec6800..000000000 --- a/funasr/layers/inversible_interface.py +++ /dev/null @@ -1,14 +0,0 @@ -from abc import ABC -from abc import abstractmethod -from typing import Tuple - -import torch - - -class InversibleInterface(ABC): - @abstractmethod - def inverse( - self, input: torch.Tensor, input_lengths: torch.Tensor = None - ) -> Tuple[torch.Tensor, torch.Tensor]: - # return output, output_lengths - raise NotImplementedError \ No newline at end of file diff --git a/funasr/layers/sinc_conv.py b/funasr/layers/sinc_conv.py deleted file mode 100644 index ab16a734c..000000000 --- a/funasr/layers/sinc_conv.py +++ /dev/null @@ -1,269 +0,0 @@ -#!/usr/bin/env python3 -# 2020, Technische Universität München; Ludwig Kürzinger -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -"""Sinc convolutions.""" -import math -import torch -from typing import Union - - -class LogCompression(torch.nn.Module): - """Log Compression Activation. - - Activation function `log(abs(x) + 1)`. - """ - - def __init__(self): - """Initialize.""" - super().__init__() - - def forward(self, x: torch.Tensor) -> torch.Tensor: - """Forward. - - Applies the Log Compression function elementwise on tensor x. - """ - return torch.log(torch.abs(x) + 1) - - -class SincConv(torch.nn.Module): - """Sinc Convolution. - - This module performs a convolution using Sinc filters in time domain as kernel. - Sinc filters function as band passes in spectral domain. - The filtering is done as a convolution in time domain, and no transformation - to spectral domain is necessary. - - This implementation of the Sinc convolution is heavily inspired - by Ravanelli et al. https://github.com/mravanelli/SincNet, - and adapted for the ESpnet toolkit. - Combine Sinc convolutions with a log compression activation function, as in: - https://arxiv.org/abs/2010.07597 - - Notes: - Currently, the same filters are applied to all input channels. - The windowing function is applied on the kernel to obtained a smoother filter, - and not on the input values, which is different to traditional ASR. - """ - - def __init__( - self, - in_channels: int, - out_channels: int, - kernel_size: int, - stride: int = 1, - padding: int = 0, - dilation: int = 1, - window_func: str = "hamming", - scale_type: str = "mel", - fs: Union[int, float] = 16000, - ): - """Initialize Sinc convolutions. - - Args: - in_channels: Number of input channels. - out_channels: Number of output channels. - kernel_size: Sinc filter kernel size (needs to be an odd number). - stride: See torch.nn.functional.conv1d. - padding: See torch.nn.functional.conv1d. - dilation: See torch.nn.functional.conv1d. - window_func: Window function on the filter, one of ["hamming", "none"]. - fs (str, int, float): Sample rate of the input data - """ - super().__init__() - window_funcs = { - "none": self.none_window, - "hamming": self.hamming_window, - } - if window_func not in window_funcs: - raise NotImplementedError( - f"Window function has to be one of {list(window_funcs.keys())}", - ) - self.window_func = window_funcs[window_func] - scale_choices = { - "mel": MelScale, - "bark": BarkScale, - } - if scale_type not in scale_choices: - raise NotImplementedError( - f"Scale has to be one of {list(scale_choices.keys())}", - ) - self.scale = scale_choices[scale_type] - self.in_channels = in_channels - self.out_channels = out_channels - self.kernel_size = kernel_size - self.padding = padding - self.dilation = dilation - self.stride = stride - self.fs = float(fs) - if self.kernel_size % 2 == 0: - raise ValueError("SincConv: Kernel size must be odd.") - self.f = None - N = self.kernel_size // 2 - self._x = 2 * math.pi * torch.linspace(1, N, N) - self._window = self.window_func(torch.linspace(1, N, N)) - # init may get overwritten by E2E network, - # but is still required to calculate output dim - self.init_filters() - - @staticmethod - def sinc(x: torch.Tensor) -> torch.Tensor: - """Sinc function.""" - x2 = x + 1e-6 - return torch.sin(x2) / x2 - - @staticmethod - def none_window(x: torch.Tensor) -> torch.Tensor: - """Identity-like windowing function.""" - return torch.ones_like(x) - - @staticmethod - def hamming_window(x: torch.Tensor) -> torch.Tensor: - """Hamming Windowing function.""" - L = 2 * x.size(0) + 1 - x = x.flip(0) - return 0.54 - 0.46 * torch.cos(2.0 * math.pi * x / L) - - def init_filters(self): - """Initialize filters with filterbank values.""" - f = self.scale.bank(self.out_channels, self.fs) - f = torch.div(f, self.fs) - self.f = torch.nn.Parameter(f, requires_grad=True) - - def _create_filters(self, device: str): - """Calculate coefficients. - - This function (re-)calculates the filter convolutions coefficients. - """ - f_mins = torch.abs(self.f[:, 0]) - f_maxs = torch.abs(self.f[:, 0]) + torch.abs(self.f[:, 1] - self.f[:, 0]) - - self._x = self._x.to(device) - self._window = self._window.to(device) - - f_mins_x = torch.matmul(f_mins.view(-1, 1), self._x.view(1, -1)) - f_maxs_x = torch.matmul(f_maxs.view(-1, 1), self._x.view(1, -1)) - - kernel = (torch.sin(f_maxs_x) - torch.sin(f_mins_x)) / (0.5 * self._x) - kernel = kernel * self._window - - kernel_left = kernel.flip(1) - kernel_center = (2 * f_maxs - 2 * f_mins).unsqueeze(1) - filters = torch.cat([kernel_left, kernel_center, kernel], dim=1) - - filters = filters.view(filters.size(0), 1, filters.size(1)) - self.sinc_filters = filters - - def forward(self, xs: torch.Tensor) -> torch.Tensor: - """Sinc convolution forward function. - - Args: - xs: Batch in form of torch.Tensor (B, C_in, D_in). - - Returns: - xs: Batch in form of torch.Tensor (B, C_out, D_out). - """ - self._create_filters(xs.device) - xs = torch.nn.functional.conv1d( - xs, - self.sinc_filters, - padding=self.padding, - stride=self.stride, - dilation=self.dilation, - groups=self.in_channels, - ) - return xs - - def get_odim(self, idim: int) -> int: - """Obtain the output dimension of the filter.""" - D_out = idim + 2 * self.padding - self.dilation * (self.kernel_size - 1) - 1 - D_out = (D_out // self.stride) + 1 - return D_out - - -class MelScale: - """Mel frequency scale.""" - - @staticmethod - def convert(f): - """Convert Hz to mel.""" - return 1125.0 * torch.log(torch.div(f, 700.0) + 1.0) - - @staticmethod - def invert(x): - """Convert mel to Hz.""" - return 700.0 * (torch.exp(torch.div(x, 1125.0)) - 1.0) - - @classmethod - def bank(cls, channels: int, fs: float) -> torch.Tensor: - """Obtain initialization values for the mel scale. - - Args: - channels: Number of channels. - fs: Sample rate. - - Returns: - torch.Tensor: Filter start frequencíes. - torch.Tensor: Filter stop frequencies. - """ - # min and max bandpass edge frequencies - min_frequency = torch.tensor(30.0) - max_frequency = torch.tensor(fs * 0.5) - frequencies = torch.linspace( - cls.convert(min_frequency), cls.convert(max_frequency), channels + 2 - ) - frequencies = cls.invert(frequencies) - f1, f2 = frequencies[:-2], frequencies[2:] - return torch.stack([f1, f2], dim=1) - - -class BarkScale: - """Bark frequency scale. - - Has wider bandwidths at lower frequencies, see: - Critical bandwidth: BARK - Zwicker and Terhardt, 1980 - """ - - @staticmethod - def convert(f): - """Convert Hz to Bark.""" - b = torch.div(f, 1000.0) - b = torch.pow(b, 2.0) * 1.4 - b = torch.pow(b + 1.0, 0.69) - return b * 75.0 + 25.0 - - @staticmethod - def invert(x): - """Convert Bark to Hz.""" - f = torch.div(x - 25.0, 75.0) - f = torch.pow(f, (1.0 / 0.69)) - f = torch.div(f - 1.0, 1.4) - f = torch.pow(f, 0.5) - return f * 1000.0 - - @classmethod - def bank(cls, channels: int, fs: float) -> torch.Tensor: - """Obtain initialization values for the Bark scale. - - Args: - channels: Number of channels. - fs: Sample rate. - - Returns: - torch.Tensor: Filter start frequencíes. - torch.Tensor: Filter stop frequencíes. - """ - # min and max BARK center frequencies by approximation - min_center_frequency = torch.tensor(70.0) - max_center_frequency = torch.tensor(fs * 0.45) - center_frequencies = torch.linspace( - cls.convert(min_center_frequency), - cls.convert(max_center_frequency), - channels, - ) - center_frequencies = cls.invert(center_frequencies) - - f1 = center_frequencies - torch.div(cls.convert(center_frequencies), 2) - f2 = center_frequencies + torch.div(cls.convert(center_frequencies), 2) - return torch.stack([f1, f2], dim=1) diff --git a/funasr/losses/label_smoothing_loss.py b/funasr/losses/label_smoothing_loss.py index c272ea879..8f0809a71 100644 --- a/funasr/losses/label_smoothing_loss.py +++ b/funasr/losses/label_smoothing_loss.py @@ -8,7 +8,7 @@ import torch from torch import nn -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import make_pad_mask class LabelSmoothingLoss(nn.Module): diff --git a/funasr/main_funcs/calculate_all_attentions.py b/funasr/main_funcs/calculate_all_attentions.py deleted file mode 100644 index c3bf015e1..000000000 --- a/funasr/main_funcs/calculate_all_attentions.py +++ /dev/null @@ -1,160 +0,0 @@ -from collections import defaultdict -from typing import Dict -from typing import List - -import torch - -from funasr.modules.rnn.attentions import AttAdd -from funasr.modules.rnn.attentions import AttCov -from funasr.modules.rnn.attentions import AttCovLoc -from funasr.modules.rnn.attentions import AttDot -from funasr.modules.rnn.attentions import AttForward -from funasr.modules.rnn.attentions import AttForwardTA -from funasr.modules.rnn.attentions import AttLoc -from funasr.modules.rnn.attentions import AttLoc2D -from funasr.modules.rnn.attentions import AttLocRec -from funasr.modules.rnn.attentions import AttMultiHeadAdd -from funasr.modules.rnn.attentions import AttMultiHeadDot -from funasr.modules.rnn.attentions import AttMultiHeadLoc -from funasr.modules.rnn.attentions import AttMultiHeadMultiResLoc -from funasr.modules.rnn.attentions import NoAtt -from funasr.modules.attention import MultiHeadedAttention - - -from funasr.models.base_model import FunASRModel - - -@torch.no_grad() -def calculate_all_attentions( - model: FunASRModel, batch: Dict[str, torch.Tensor] -) -> Dict[str, List[torch.Tensor]]: - """Derive the outputs from the all attention layers - - Args: - model: - batch: same as forward - Returns: - return_dict: A dict of a list of tensor. - key_names x batch x (D1, D2, ...) - - """ - bs = len(next(iter(batch.values()))) - assert all(len(v) == bs for v in batch.values()), { - k: v.shape for k, v in batch.items() - } - - # 1. Register forward_hook fn to save the output from specific layers - outputs = {} - handles = {} - for name, modu in model.named_modules(): - - def hook(module, input, output, name=name): - if isinstance(module, MultiHeadedAttention): - # NOTE(kamo): MultiHeadedAttention doesn't return attention weight - # attn: (B, Head, Tout, Tin) - outputs[name] = module.attn.detach().cpu() - elif isinstance(module, AttLoc2D): - c, w = output - # w: previous concate attentions - # w: (B, nprev, Tin) - att_w = w[:, -1].detach().cpu() - outputs.setdefault(name, []).append(att_w) - elif isinstance(module, (AttCov, AttCovLoc)): - c, w = output - assert isinstance(w, list), type(w) - # w: list of previous attentions - # w: nprev x (B, Tin) - att_w = w[-1].detach().cpu() - outputs.setdefault(name, []).append(att_w) - elif isinstance(module, AttLocRec): - # w: (B, Tin) - c, (w, (att_h, att_c)) = output - att_w = w.detach().cpu() - outputs.setdefault(name, []).append(att_w) - elif isinstance( - module, - ( - AttMultiHeadDot, - AttMultiHeadAdd, - AttMultiHeadLoc, - AttMultiHeadMultiResLoc, - ), - ): - c, w = output - # w: nhead x (B, Tin) - assert isinstance(w, list), type(w) - att_w = [_w.detach().cpu() for _w in w] - outputs.setdefault(name, []).append(att_w) - elif isinstance( - module, - ( - AttAdd, - AttDot, - AttForward, - AttForwardTA, - AttLoc, - NoAtt, - ), - ): - c, w = output - att_w = w.detach().cpu() - outputs.setdefault(name, []).append(att_w) - - handle = modu.register_forward_hook(hook) - handles[name] = handle - - # 2. Just forward one by one sample. - # Batch-mode can't be used to keep requirements small for each models. - keys = [] - for k in batch: - if not k.endswith("_lengths"): - keys.append(k) - - return_dict = defaultdict(list) - for ibatch in range(bs): - # *: (B, L, ...) -> (1, L2, ...) - _sample = { - k: batch[k][ibatch, None, : batch[k + "_lengths"][ibatch]] - if k + "_lengths" in batch - else batch[k][ibatch, None] - for k in keys - } - - # *_lengths: (B,) -> (1,) - _sample.update( - { - k + "_lengths": batch[k + "_lengths"][ibatch, None] - for k in keys - if k + "_lengths" in batch - } - ) - model(**_sample) - - # Derive the attention results - for name, output in outputs.items(): - if isinstance(output, list): - if isinstance(output[0], list): - # output: nhead x (Tout, Tin) - output = torch.stack( - [ - # Tout x (1, Tin) -> (Tout, Tin) - torch.cat([o[idx] for o in output], dim=0) - for idx in range(len(output[0])) - ], - dim=0, - ) - else: - # Tout x (1, Tin) -> (Tout, Tin) - output = torch.cat(output, dim=0) - else: - # output: (1, NHead, Tout, Tin) -> (NHead, Tout, Tin) - output = output.squeeze(0) - # output: (Tout, Tin) or (NHead, Tout, Tin) - return_dict[name].append(output) - outputs.clear() - - # 3. Remove all hooks - for _, handle in handles.items(): - handle.remove() - - return dict(return_dict) diff --git a/funasr/datasets/__init__.py b/funasr/metrics/__init__.py similarity index 100% rename from funasr/datasets/__init__.py rename to funasr/metrics/__init__.py diff --git a/funasr/models/e2e_asr_common.py b/funasr/metrics/common.py similarity index 100% rename from funasr/models/e2e_asr_common.py rename to funasr/metrics/common.py diff --git a/funasr/utils/compute_eer.py b/funasr/metrics/compute_eer.py similarity index 100% rename from funasr/utils/compute_eer.py rename to funasr/metrics/compute_eer.py diff --git a/funasr/utils/compute_min_dcf.py b/funasr/metrics/compute_min_dcf.py similarity index 100% rename from funasr/utils/compute_min_dcf.py rename to funasr/metrics/compute_min_dcf.py diff --git a/egs/aishell/transformer/utils/compute_wer.py b/funasr/metrics/compute_wer.py similarity index 100% rename from egs/aishell/transformer/utils/compute_wer.py rename to funasr/metrics/compute_wer.py diff --git a/funasr/models/base_model.py b/funasr/models/base_model.py deleted file mode 100644 index 80b3bbd71..000000000 --- a/funasr/models/base_model.py +++ /dev/null @@ -1,17 +0,0 @@ -import torch - - -class FunASRModel(torch.nn.Module): - """The common model class - - """ - - def __init__(self): - super().__init__() - self.num_updates = 0 - - def set_num_updates(self, num_updates): - self.num_updates = num_updates - - def get_num_updates(self): - return self.num_updates diff --git a/funasr/datasets/large_datasets/__init__.py b/funasr/models/bat/__init__.py similarity index 100% rename from funasr/datasets/large_datasets/__init__.py rename to funasr/models/bat/__init__.py diff --git a/funasr/models/e2e_asr_bat.py b/funasr/models/bat/model.py similarity index 97% rename from funasr/models/e2e_asr_bat.py rename to funasr/models/bat/model.py index 9627292ec..83ce3027a 100644 --- a/funasr/models/e2e_asr_bat.py +++ b/funasr/models/bat/model.py @@ -15,12 +15,12 @@ from funasr.models.decoder.rnnt_decoder import RNNTDecoder from funasr.models.decoder.abs_decoder import AbsDecoder as AbsAttDecoder from funasr.models.encoder.abs_encoder import AbsEncoder from funasr.models.joint_net.joint_network import JointNetwork -from funasr.modules.nets_utils import get_transducer_task_io -from funasr.modules.nets_utils import th_accuracy -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.add_sos_eos import add_sos_eos +from funasr.models.transformer.utils.nets_utils import get_transducer_task_io +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.add_sos_eos import add_sos_eos from funasr.layers.abs_normalize import AbsNormalize -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.train_utils.device_funcs import force_gatherable from funasr.models.base_model import FunASRModel if V(torch.__version__) >= V("1.6.0"): @@ -263,7 +263,7 @@ class BATModel(FunASRModel): cer_trans, wer_trans = None, None if not self.training and (self.report_cer or self.report_wer): if self.error_calculator is None: - from funasr.modules.e2e_asr_common import ErrorCalculatorTransducer as ErrorCalculator + from funasr.metrics import ErrorCalculatorTransducer as ErrorCalculator self.error_calculator = ErrorCalculator( self.decoder, self.joint_network, diff --git a/funasr/datasets/large_datasets/datapipes/__init__.py b/funasr/models/bici_paraformer/__init__.py similarity index 100% rename from funasr/datasets/large_datasets/datapipes/__init__.py rename to funasr/models/bici_paraformer/__init__.py diff --git a/funasr/datasets/large_datasets/utils/__init__.py b/funasr/models/branchformer/__init__.py similarity index 100% rename from funasr/datasets/large_datasets/utils/__init__.py rename to funasr/models/branchformer/__init__.py diff --git a/funasr/models/encoder/branchformer_encoder.py b/funasr/models/branchformer/branchformer_encoder.py similarity index 97% rename from funasr/models/encoder/branchformer_encoder.py rename to funasr/models/branchformer/branchformer_encoder.py index 70bd2c979..0f037c82c 100644 --- a/funasr/models/encoder/branchformer_encoder.py +++ b/funasr/models/branchformer/branchformer_encoder.py @@ -18,23 +18,23 @@ import numpy import torch from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.modules.cgmlp import ConvolutionalGatingMLP -from funasr.modules.fastformer import FastSelfAttention -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.attention import ( # noqa: H301 +from funasr.models.branchformer.cgmlp import ConvolutionalGatingMLP +from funasr.models.branchformer.fastformer import FastSelfAttention +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.attention import ( # noqa: H301 LegacyRelPositionMultiHeadedAttention, MultiHeadedAttention, RelPositionMultiHeadedAttention, ) -from funasr.modules.embedding import ( # noqa: H301 +from funasr.models.transformer.embedding import ( # noqa: H301 LegacyRelPositionalEncoding, PositionalEncoding, RelPositionalEncoding, ScaledPositionalEncoding, ) -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.repeat import repeat -from funasr.modules.subsampling import ( +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.repeat import repeat +from funasr.models.transformer.subsampling import ( Conv2dSubsampling, Conv2dSubsampling2, Conv2dSubsampling6, diff --git a/funasr/modules/cgmlp.py b/funasr/models/branchformer/cgmlp.py similarity index 96% rename from funasr/modules/cgmlp.py rename to funasr/models/branchformer/cgmlp.py index dcd085bb2..17a10166e 100644 --- a/funasr/modules/cgmlp.py +++ b/funasr/models/branchformer/cgmlp.py @@ -8,8 +8,8 @@ References: import torch -from funasr.modules.nets_utils import get_activation -from funasr.modules.layer_norm import LayerNorm +from funasr.models.transformer.utils.nets_utils import get_activation +from funasr.models.transformer.layer_norm import LayerNorm class ConvolutionalSpatialGatingUnit(torch.nn.Module): diff --git a/funasr/modules/fastformer.py b/funasr/models/branchformer/fastformer.py similarity index 100% rename from funasr/modules/fastformer.py rename to funasr/models/branchformer/fastformer.py diff --git a/funasr/models/branchformer/model.py b/funasr/models/branchformer/model.py new file mode 100644 index 000000000..5cb2af712 --- /dev/null +++ b/funasr/models/branchformer/model.py @@ -0,0 +1,64 @@ +import logging +from contextlib import contextmanager +from distutils.version import LooseVersion +from typing import Dict +from typing import List +from typing import Optional +from typing import Tuple +from typing import Union +import tempfile +import codecs +import requests +import re +import copy +import torch +import torch.nn as nn +import random +import numpy as np +import time +# from funasr.layers.abs_normalize import AbsNormalize +from funasr.losses.label_smoothing_loss import ( + LabelSmoothingLoss, # noqa: H301 +) +# from funasr.models.ctc import CTC +# from funasr.models.decoder.abs_decoder import AbsDecoder +# from funasr.models.e2e_asr_common import ErrorCalculator +# from funasr.models.encoder.abs_encoder import AbsEncoder +# from funasr.models.frontend.abs_frontend import AbsFrontend +# from funasr.models.postencoder.abs_postencoder import AbsPostEncoder +from funasr.models.predictor.cif import mae_loss +# from funasr.models.preencoder.abs_preencoder import AbsPreEncoder +# from funasr.models.specaug.abs_specaug import AbsSpecAug +from funasr.models.transformer.add_sos_eos import add_sos_eos +from funasr.models.transformer.utils.nets_utils import make_pad_mask, pad_list +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.train_utils.device_funcs import force_gatherable +# from funasr.models.base_model import FunASRModel +# from funasr.models.predictor.cif import CifPredictorV3 +from funasr.models.paraformer.search import Hypothesis + +from funasr.models.model_class_factory import * + +if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): + from torch.cuda.amp import autocast +else: + # Nothing to do if torch<1.6.0 + @contextmanager + def autocast(enabled=True): + yield +from funasr.datasets.fun_datasets.load_audio_extract_fbank import load_audio, extract_fbank +from funasr.utils import postprocess_utils +from funasr.utils.datadir_writer import DatadirWriter + +from funasr.models.transformer.model import Transformer + +class Branchformer(Transformer): + """CTC-attention hybrid Encoder-Decoder model""" + + def __init__( + self, + *args, + **kwargs, + ): + + super().__init__(*args, **kwargs) diff --git a/funasr/datasets/small_datasets/__init__.py b/funasr/models/campplus/__init__.py similarity index 100% rename from funasr/datasets/small_datasets/__init__.py rename to funasr/models/campplus/__init__.py diff --git a/funasr/modules/cnn/DTDNN.py b/funasr/models/cnn/DTDNN.py similarity index 100% rename from funasr/modules/cnn/DTDNN.py rename to funasr/models/cnn/DTDNN.py diff --git a/funasr/modules/cnn/ResNet.py b/funasr/models/cnn/ResNet.py similarity index 99% rename from funasr/modules/cnn/ResNet.py rename to funasr/models/cnn/ResNet.py index c3bf13cf6..54c390152 100644 --- a/funasr/modules/cnn/ResNet.py +++ b/funasr/models/cnn/ResNet.py @@ -15,7 +15,7 @@ import torch import torch.nn as nn import torch.nn.functional as F -import funasr.models.pooling.pooling_layers as pooling_layers +import funasr.models.sond.pooling.pooling_layers as pooling_layers from funasr.modules.cnn.fusion import AFF diff --git a/funasr/modules/cnn/ResNet_aug.py b/funasr/models/cnn/ResNet_aug.py similarity index 99% rename from funasr/modules/cnn/ResNet_aug.py rename to funasr/models/cnn/ResNet_aug.py index d2d845d93..6b03c67fc 100644 --- a/funasr/modules/cnn/ResNet_aug.py +++ b/funasr/models/cnn/ResNet_aug.py @@ -15,7 +15,7 @@ import torch import torch.nn as nn import torch.nn.functional as F -import funasr.models.pooling.pooling_layers as pooling_layers +import funasr.models.sond.pooling.pooling_layers as pooling_layers from funasr.modules.cnn.fusion import AFF diff --git a/funasr/modules/cnn/__init__.py b/funasr/models/cnn/__init__.py similarity index 100% rename from funasr/modules/cnn/__init__.py rename to funasr/models/cnn/__init__.py diff --git a/funasr/modules/cnn/fusion.py b/funasr/models/cnn/fusion.py similarity index 100% rename from funasr/modules/cnn/fusion.py rename to funasr/models/cnn/fusion.py diff --git a/funasr/modules/cnn/layers.py b/funasr/models/cnn/layers.py similarity index 100% rename from funasr/modules/cnn/layers.py rename to funasr/models/cnn/layers.py diff --git a/funasr/fileio/__init__.py b/funasr/models/conformer/__init__.py similarity index 100% rename from funasr/fileio/__init__.py rename to funasr/models/conformer/__init__.py diff --git a/funasr/models/encoder/conformer_encoder.py b/funasr/models/conformer/conformer_encoder.py similarity index 97% rename from funasr/models/encoder/conformer_encoder.py rename to funasr/models/conformer/conformer_encoder.py index e5fac621e..4b8cfe6a5 100644 --- a/funasr/models/encoder/conformer_encoder.py +++ b/funasr/models/conformer/conformer_encoder.py @@ -14,43 +14,43 @@ import torch from torch import nn from funasr.models.ctc import CTC -from funasr.modules.attention import ( +from funasr.models.transformer.attention import ( MultiHeadedAttention, # noqa: H301 RelPositionMultiHeadedAttention, # noqa: H301 RelPositionMultiHeadedAttentionChunk, LegacyRelPositionMultiHeadedAttention, # noqa: H301 ) from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.modules.embedding import ( +from funasr.models.transformer.embedding import ( PositionalEncoding, # noqa: H301 ScaledPositionalEncoding, # noqa: H301 RelPositionalEncoding, # noqa: H301 LegacyRelPositionalEncoding, # noqa: H301 StreamingRelPositionalEncoding, ) -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.multi_layer_conv import Conv1dLinear -from funasr.modules.multi_layer_conv import MultiLayeredConv1d -from funasr.modules.nets_utils import get_activation -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.nets_utils import ( +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.utils.multi_layer_conv import Conv1dLinear +from funasr.models.transformer.utils.multi_layer_conv import MultiLayeredConv1d +from funasr.models.transformer.utils.nets_utils import get_activation +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import ( TooShortUttError, check_short_utt, make_chunk_mask, make_source_mask, ) -from funasr.modules.positionwise_feed_forward import ( +from funasr.models.transformer.positionwise_feed_forward import ( PositionwiseFeedForward, # noqa: H301 ) -from funasr.modules.repeat import repeat, MultiBlocks -from funasr.modules.subsampling import Conv2dSubsampling -from funasr.modules.subsampling import Conv2dSubsampling2 -from funasr.modules.subsampling import Conv2dSubsampling6 -from funasr.modules.subsampling import Conv2dSubsampling8 -from funasr.modules.subsampling import TooShortUttError -from funasr.modules.subsampling import check_short_utt -from funasr.modules.subsampling import Conv2dSubsamplingPad -from funasr.modules.subsampling import StreamingConvInput +from funasr.models.transformer.repeat import repeat, MultiBlocks +from funasr.models.transformer.subsampling import Conv2dSubsampling +from funasr.models.transformer.subsampling import Conv2dSubsampling2 +from funasr.models.transformer.subsampling import Conv2dSubsampling6 +from funasr.models.transformer.subsampling import Conv2dSubsampling8 +from funasr.models.transformer.subsampling import TooShortUttError +from funasr.models.transformer.subsampling import check_short_utt +from funasr.models.transformer.subsampling import Conv2dSubsamplingPad +from funasr.models.transformer.subsampling import StreamingConvInput class ConvolutionModule(nn.Module): """ConvolutionModule in Conformer model. diff --git a/funasr/models/conformer/model.py b/funasr/models/conformer/model.py new file mode 100644 index 000000000..48f04e493 --- /dev/null +++ b/funasr/models/conformer/model.py @@ -0,0 +1,65 @@ +import logging +from contextlib import contextmanager +from distutils.version import LooseVersion +from typing import Dict +from typing import List +from typing import Optional +from typing import Tuple +from typing import Union +import tempfile +import codecs +import requests +import re +import copy +import torch +import torch.nn as nn +import random +import numpy as np +import time +# from funasr.layers.abs_normalize import AbsNormalize +from funasr.losses.label_smoothing_loss import ( + LabelSmoothingLoss, # noqa: H301 +) +# from funasr.models.ctc import CTC +# from funasr.models.decoder.abs_decoder import AbsDecoder +# from funasr.models.e2e_asr_common import ErrorCalculator +# from funasr.models.encoder.abs_encoder import AbsEncoder +# from funasr.models.frontend.abs_frontend import AbsFrontend +# from funasr.models.postencoder.abs_postencoder import AbsPostEncoder +from funasr.models.predictor.cif import mae_loss +# from funasr.models.preencoder.abs_preencoder import AbsPreEncoder +# from funasr.models.specaug.abs_specaug import AbsSpecAug +from funasr.models.transformer.add_sos_eos import add_sos_eos +from funasr.models.transformer.utils.nets_utils import make_pad_mask, pad_list +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.train_utils.device_funcs import force_gatherable +# from funasr.models.base_model import FunASRModel +# from funasr.models.predictor.cif import CifPredictorV3 +from funasr.models.paraformer.search import Hypothesis + +from funasr.models.model_class_factory import * + +if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): + from torch.cuda.amp import autocast +else: + # Nothing to do if torch<1.6.0 + @contextmanager + def autocast(enabled=True): + yield +from funasr.datasets.fun_datasets.load_audio_extract_fbank import load_audio, extract_fbank +from funasr.utils import postprocess_utils +from funasr.utils.datadir_writer import DatadirWriter + +from funasr.models.transformer.model import Transformer + +class Conformer(Transformer): + """CTC-attention hybrid Encoder-Decoder model""" + + + def __init__( + self, + *args, + **kwargs, + ): + + super().__init__(*args, **kwargs) diff --git a/funasr/iterators/__init__.py b/funasr/models/ct_transformer/__init__.py similarity index 100% rename from funasr/iterators/__init__.py rename to funasr/models/ct_transformer/__init__.py diff --git a/funasr/models/target_delay_transformer.py b/funasr/models/ct_transformer/target_delay_transformer.py similarity index 98% rename from funasr/models/target_delay_transformer.py rename to funasr/models/ct_transformer/target_delay_transformer.py index 19e5c7c2f..f3bc772df 100644 --- a/funasr/models/target_delay_transformer.py +++ b/funasr/models/ct_transformer/target_delay_transformer.py @@ -5,7 +5,7 @@ from typing import Tuple import torch import torch.nn as nn -from funasr.modules.embedding import SinusoidalPositionEncoder +from funasr.models.transformer.embedding import SinusoidalPositionEncoder from funasr.models.encoder.sanm_encoder import SANMEncoder as Encoder diff --git a/funasr/layers/__init__.py b/funasr/models/ctc/__init__.py similarity index 100% rename from funasr/layers/__init__.py rename to funasr/models/ctc/__init__.py diff --git a/funasr/models/ctc.py b/funasr/models/ctc/ctc.py similarity index 100% rename from funasr/models/ctc.py rename to funasr/models/ctc/ctc.py diff --git a/funasr/main_funcs/__init__.py b/funasr/models/data2vec/__init__.py similarity index 100% rename from funasr/main_funcs/__init__.py rename to funasr/models/data2vec/__init__.py diff --git a/funasr/models/data2vec.py b/funasr/models/data2vec/data2vec.py similarity index 98% rename from funasr/models/data2vec.py rename to funasr/models/data2vec/data2vec.py index 425794dfc..19c561278 100644 --- a/funasr/models/data2vec.py +++ b/funasr/models/data2vec/data2vec.py @@ -17,7 +17,7 @@ from funasr.models.encoder.abs_encoder import AbsEncoder from funasr.models.frontend.abs_frontend import AbsFrontend from funasr.models.preencoder.abs_preencoder import AbsPreEncoder from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.train_utils.device_funcs import force_gatherable if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): from torch.cuda.amp import autocast diff --git a/funasr/models/encoder/data2vec_encoder.py b/funasr/models/data2vec/data2vec_encoder.py similarity index 98% rename from funasr/models/encoder/data2vec_encoder.py rename to funasr/models/data2vec/data2vec_encoder.py index 8885f02eb..1bcb639a2 100644 --- a/funasr/models/encoder/data2vec_encoder.py +++ b/funasr/models/data2vec/data2vec_encoder.py @@ -12,14 +12,14 @@ import torch.nn as nn import torch.nn.functional as F from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.modules.data2vec.data_utils import compute_mask_indices -from funasr.modules.data2vec.ema_module import EMAModule -from funasr.modules.data2vec.grad_multiply import GradMultiply -from funasr.modules.data2vec.wav2vec2 import ( +from funasr.models.data2vec.data_utils import compute_mask_indices +from funasr.models.data2vec.ema_module import EMAModule +from funasr.models.data2vec.grad_multiply import GradMultiply +from funasr.models.data2vec.wav2vec2 import ( ConvFeatureExtractionModel, TransformerEncoder, ) -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import make_pad_mask def get_annealed_rate(start, end, curr_step, total_steps): diff --git a/funasr/modules/data2vec/data_utils.py b/funasr/models/data2vec/data_utils.py similarity index 100% rename from funasr/modules/data2vec/data_utils.py rename to funasr/models/data2vec/data_utils.py diff --git a/funasr/modules/data2vec/ema_module.py b/funasr/models/data2vec/ema_module.py similarity index 100% rename from funasr/modules/data2vec/ema_module.py rename to funasr/models/data2vec/ema_module.py diff --git a/funasr/modules/data2vec/grad_multiply.py b/funasr/models/data2vec/grad_multiply.py similarity index 100% rename from funasr/modules/data2vec/grad_multiply.py rename to funasr/models/data2vec/grad_multiply.py diff --git a/funasr/modules/data2vec/multihead_attention.py b/funasr/models/data2vec/multihead_attention.py similarity index 99% rename from funasr/modules/data2vec/multihead_attention.py rename to funasr/models/data2vec/multihead_attention.py index e5171edde..d0dbe359a 100644 --- a/funasr/modules/data2vec/multihead_attention.py +++ b/funasr/models/data2vec/multihead_attention.py @@ -12,7 +12,7 @@ import torch.nn.functional as F from torch import Tensor, nn from torch.nn import Parameter -from funasr.modules.data2vec.quant_noise import quant_noise +from funasr.models.data2vec.quant_noise import quant_noise class FairseqDropout(nn.Module): diff --git a/funasr/modules/data2vec/quant_noise.py b/funasr/models/data2vec/quant_noise.py similarity index 100% rename from funasr/modules/data2vec/quant_noise.py rename to funasr/models/data2vec/quant_noise.py diff --git a/funasr/modules/data2vec/utils.py b/funasr/models/data2vec/utils.py similarity index 98% rename from funasr/modules/data2vec/utils.py rename to funasr/models/data2vec/utils.py index 1945ac405..70889dc91 100644 --- a/funasr/modules/data2vec/utils.py +++ b/funasr/models/data2vec/utils.py @@ -9,7 +9,7 @@ import torch import torch.nn as nn import torch.nn.functional as F -from funasr.modules.data2vec.multihead_attention import MultiheadAttention +from funasr.models.data2vec.multihead_attention import MultiheadAttention class Fp32LayerNorm(nn.LayerNorm): diff --git a/funasr/modules/data2vec/wav2vec2.py b/funasr/models/data2vec/wav2vec2.py similarity index 99% rename from funasr/modules/data2vec/wav2vec2.py rename to funasr/models/data2vec/wav2vec2.py index 234ecbb1e..6631c57fe 100644 --- a/funasr/modules/data2vec/wav2vec2.py +++ b/funasr/models/data2vec/wav2vec2.py @@ -12,8 +12,8 @@ import torch import torch.nn as nn import torch.nn.functional as F -from funasr.modules.data2vec import utils -from funasr.modules.data2vec.multihead_attention import MultiheadAttention +from funasr.models.data2vec import utils +from funasr.models.data2vec.multihead_attention import MultiheadAttention class ConvFeatureExtractionModel(nn.Module): diff --git a/funasr/models/decoder/abs_decoder.py b/funasr/models/decoder/abs_decoder.py deleted file mode 100644 index bc8acf44c..000000000 --- a/funasr/models/decoder/abs_decoder.py +++ /dev/null @@ -1,19 +0,0 @@ -from abc import ABC -from abc import abstractmethod -from typing import Tuple - -import torch - -from funasr.modules.scorers.scorer_interface import ScorerInterface - - -class AbsDecoder(torch.nn.Module, ScorerInterface, ABC): - @abstractmethod - def forward( - self, - hs_pad: torch.Tensor, - hlens: torch.Tensor, - ys_in_pad: torch.Tensor, - ys_in_lens: torch.Tensor, - ) -> Tuple[torch.Tensor, torch.Tensor]: - raise NotImplementedError diff --git a/funasr/models/e2e_asr.py b/funasr/models/e2e_asr.py deleted file mode 100644 index c1eb003de..000000000 --- a/funasr/models/e2e_asr.py +++ /dev/null @@ -1,455 +0,0 @@ -# Copyright ESPnet (https://github.com/espnet/espnet). All Rights Reserved. -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -import logging -from contextlib import contextmanager -from distutils.version import LooseVersion -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union - -import torch - -from funasr.layers.abs_normalize import AbsNormalize -from funasr.losses.label_smoothing_loss import ( - LabelSmoothingLoss, # noqa: H301 -) -from funasr.models.ctc import CTC -from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.modules.add_sos_eos import add_sos_eos -from funasr.modules.e2e_asr_common import ErrorCalculator -from funasr.modules.nets_utils import th_accuracy -from funasr.torch_utils.device_funcs import force_gatherable -from funasr.models.base_model import FunASRModel - -if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): - from torch.cuda.amp import autocast -else: - # Nothing to do if torch<1.6.0 - @contextmanager - def autocast(enabled=True): - yield - - -class ASRModel(FunASRModel): - """CTC-attention hybrid Encoder-Decoder model""" - - def __init__( - self, - vocab_size: int, - token_list: Union[Tuple[str, ...], List[str]], - frontend: Optional[AbsFrontend], - specaug: Optional[AbsSpecAug], - normalize: Optional[AbsNormalize], - encoder: AbsEncoder, - decoder: AbsDecoder, - ctc: CTC, - ctc_weight: float = 0.5, - interctc_weight: float = 0.0, - ignore_id: int = -1, - lsm_weight: float = 0.0, - length_normalized_loss: bool = False, - report_cer: bool = True, - report_wer: bool = True, - sym_space: str = "", - sym_blank: str = "", - extract_feats_in_collect_stats: bool = True, - preencoder: Optional[AbsPreEncoder] = None, - postencoder: Optional[AbsPostEncoder] = None, - ): - assert 0.0 <= ctc_weight <= 1.0, ctc_weight - assert 0.0 <= interctc_weight < 1.0, interctc_weight - - super().__init__() - # note that eos is the same as sos (equivalent ID) - self.blank_id = 0 - self.sos = 1 - self.eos = 2 - self.vocab_size = vocab_size - self.ignore_id = ignore_id - self.ctc_weight = ctc_weight - self.interctc_weight = interctc_weight - self.token_list = token_list.copy() - - self.frontend = frontend - self.specaug = specaug - self.normalize = normalize - self.preencoder = preencoder - self.postencoder = postencoder - self.encoder = encoder - - if not hasattr(self.encoder, "interctc_use_conditioning"): - self.encoder.interctc_use_conditioning = False - if self.encoder.interctc_use_conditioning: - self.encoder.conditioning_layer = torch.nn.Linear( - vocab_size, self.encoder.output_size() - ) - - self.error_calculator = None - - - # we set self.decoder = None in the CTC mode since - # self.decoder parameters were never used and PyTorch complained - # and threw an Exception in the multi-GPU experiment. - # thanks Jeff Farris for pointing out the issue. - if ctc_weight == 1.0: - self.decoder = None - else: - self.decoder = decoder - - self.criterion_att = LabelSmoothingLoss( - size=vocab_size, - padding_idx=ignore_id, - smoothing=lsm_weight, - normalize_length=length_normalized_loss, - ) - - if report_cer or report_wer: - self.error_calculator = ErrorCalculator( - token_list, sym_space, sym_blank, report_cer, report_wer - ) - - if ctc_weight == 0.0: - self.ctc = None - else: - self.ctc = ctc - - self.extract_feats_in_collect_stats = extract_feats_in_collect_stats - self.length_normalized_loss = length_normalized_loss - - def forward( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - """Frontend + Encoder + Decoder + Calc loss - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - text: (Batch, Length) - text_lengths: (Batch,) - """ - assert text_lengths.dim() == 1, text_lengths.shape - # Check that batch_size is unified - assert ( - speech.shape[0] - == speech_lengths.shape[0] - == text.shape[0] - == text_lengths.shape[0] - ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) - batch_size = speech.shape[0] - - # for data-parallel - text = text[:, : text_lengths.max()] - - # 1. Encoder - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - loss_att, acc_att, cer_att, wer_att = None, None, None, None - loss_ctc, cer_ctc = None, None - stats = dict() - - # 1. CTC branch - if self.ctc_weight != 0.0: - loss_ctc, cer_ctc = self._calc_ctc_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # Collect CTC branch stats - stats["loss_ctc"] = loss_ctc.detach() if loss_ctc is not None else None - stats["cer_ctc"] = cer_ctc - - # Intermediate CTC (optional) - loss_interctc = 0.0 - if self.interctc_weight != 0.0 and intermediate_outs is not None: - for layer_idx, intermediate_out in intermediate_outs: - # we assume intermediate_out has the same length & padding - # as those of encoder_out - loss_ic, cer_ic = self._calc_ctc_loss( - intermediate_out, encoder_out_lens, text, text_lengths - ) - loss_interctc = loss_interctc + loss_ic - - # Collect Intermedaite CTC stats - stats["loss_interctc_layer{}".format(layer_idx)] = ( - loss_ic.detach() if loss_ic is not None else None - ) - stats["cer_interctc_layer{}".format(layer_idx)] = cer_ic - - loss_interctc = loss_interctc / len(intermediate_outs) - - # calculate whole encoder loss - loss_ctc = ( - 1 - self.interctc_weight - ) * loss_ctc + self.interctc_weight * loss_interctc - - - # 2b. Attention decoder branch - if self.ctc_weight != 1.0: - loss_att, acc_att, cer_att, wer_att = self._calc_att_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # 3. CTC-Att loss definition - if self.ctc_weight == 0.0: - loss = loss_att - elif self.ctc_weight == 1.0: - loss = loss_ctc - else: - loss = self.ctc_weight * loss_ctc + (1 - self.ctc_weight) * loss_att - - # Collect Attn branch stats - stats["loss_att"] = loss_att.detach() if loss_att is not None else None - stats["acc"] = acc_att - stats["cer"] = cer_att - stats["wer"] = wer_att - - # Collect total loss stats - stats["loss"] = torch.clone(loss.detach()) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - if self.length_normalized_loss: - batch_size = int((text_lengths + 1).sum()) - - loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) - return loss, stats, weight - - def collect_feats( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - ) -> Dict[str, torch.Tensor]: - if self.extract_feats_in_collect_stats: - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - else: - # Generate dummy stats if extract_feats_in_collect_stats is False - logging.warning( - "Generating dummy stats for feats and feats_lengths, " - "because encoder_conf.extract_feats_in_collect_stats is " - f"{self.extract_feats_in_collect_stats}" - ) - feats, feats_lengths = speech, speech_lengths - return {"feats": feats, "feats_lengths": feats_lengths} - - def encode( - self, speech: torch.Tensor, speech_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Frontend + Encoder. Note that this method is used by asr_inference.py - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - """ - with autocast(False): - # 1. Extract feats - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - - # 2. Data augmentation - if self.specaug is not None and self.training: - feats, feats_lengths = self.specaug(feats, feats_lengths) - - # 3. Normalization for feature: e.g. Global-CMVN, Utterance-CMVN - if self.normalize is not None: - feats, feats_lengths = self.normalize(feats, feats_lengths) - - # Pre-encoder, e.g. used for raw input data - if self.preencoder is not None: - feats, feats_lengths = self.preencoder(feats, feats_lengths) - - # 4. Forward encoder - # feats: (Batch, Length, Dim) - # -> encoder_out: (Batch, Length2, Dim2) - if self.encoder.interctc_use_conditioning: - encoder_out, encoder_out_lens, _ = self.encoder( - feats, feats_lengths, ctc=self.ctc - ) - else: - encoder_out, encoder_out_lens, _ = self.encoder(feats, feats_lengths) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - # Post-encoder, e.g. NLU - if self.postencoder is not None: - encoder_out, encoder_out_lens = self.postencoder( - encoder_out, encoder_out_lens - ) - - assert encoder_out.size(0) == speech.size(0), ( - encoder_out.size(), - speech.size(0), - ) - assert encoder_out.size(1) <= encoder_out_lens.max(), ( - encoder_out.size(), - encoder_out_lens.max(), - ) - - if intermediate_outs is not None: - return (encoder_out, intermediate_outs), encoder_out_lens - - return encoder_out, encoder_out_lens - - def _extract_feats( - self, speech: torch.Tensor, speech_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - assert speech_lengths.dim() == 1, speech_lengths.shape - - # for data-parallel - speech = speech[:, : speech_lengths.max()] - - if self.frontend is not None: - # Frontend - # e.g. STFT and Feature extract - # data_loader may send time-domain signal in this case - # speech (Batch, NSamples) -> feats: (Batch, NFrames, Dim) - feats, feats_lengths = self.frontend(speech, speech_lengths) - else: - # No frontend and no feature extract - feats, feats_lengths = speech, speech_lengths - return feats, feats_lengths - - def nll( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ) -> torch.Tensor: - """Compute negative log likelihood(nll) from transformer-decoder - Normally, this function is called in batchify_nll. - Args: - encoder_out: (Batch, Length, Dim) - encoder_out_lens: (Batch,) - ys_pad: (Batch, Length) - ys_pad_lens: (Batch,) - """ - ys_in_pad, ys_out_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_in_lens = ys_pad_lens + 1 - - # 1. Forward decoder - decoder_out, _ = self.decoder( - encoder_out, encoder_out_lens, ys_in_pad, ys_in_lens - ) # [batch, seqlen, dim] - batch_size = decoder_out.size(0) - decoder_num_class = decoder_out.size(2) - # nll: negative log-likelihood - nll = torch.nn.functional.cross_entropy( - decoder_out.view(-1, decoder_num_class), - ys_out_pad.view(-1), - ignore_index=self.ignore_id, - reduction="none", - ) - nll = nll.view(batch_size, -1) - nll = nll.sum(dim=1) - assert nll.size(0) == batch_size - return nll - - def batchify_nll( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - batch_size: int = 100, - ): - """Compute negative log likelihood(nll) from transformer-decoder - To avoid OOM, this fuction seperate the input into batches. - Then call nll for each batch and combine and return results. - Args: - encoder_out: (Batch, Length, Dim) - encoder_out_lens: (Batch,) - ys_pad: (Batch, Length) - ys_pad_lens: (Batch,) - batch_size: int, samples each batch contain when computing nll, - you may change this to avoid OOM or increase - GPU memory usage - """ - total_num = encoder_out.size(0) - if total_num <= batch_size: - nll = self.nll(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens) - else: - nll = [] - start_idx = 0 - while True: - end_idx = min(start_idx + batch_size, total_num) - batch_encoder_out = encoder_out[start_idx:end_idx, :, :] - batch_encoder_out_lens = encoder_out_lens[start_idx:end_idx] - batch_ys_pad = ys_pad[start_idx:end_idx, :] - batch_ys_pad_lens = ys_pad_lens[start_idx:end_idx] - batch_nll = self.nll( - batch_encoder_out, - batch_encoder_out_lens, - batch_ys_pad, - batch_ys_pad_lens, - ) - nll.append(batch_nll) - start_idx = end_idx - if start_idx == total_num: - break - nll = torch.cat(nll) - assert nll.size(0) == total_num - return nll - - def _calc_att_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - ys_in_pad, ys_out_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_in_lens = ys_pad_lens + 1 - - # 1. Forward decoder - decoder_out, _ = self.decoder( - encoder_out, encoder_out_lens, ys_in_pad, ys_in_lens - ) - - # 2. Compute attention loss - loss_att = self.criterion_att(decoder_out, ys_out_pad) - acc_att = th_accuracy( - decoder_out.view(-1, self.vocab_size), - ys_out_pad, - ignore_label=self.ignore_id, - ) - - # Compute cer/wer using attention-decoder - if self.training or self.error_calculator is None: - cer_att, wer_att = None, None - else: - ys_hat = decoder_out.argmax(dim=-1) - cer_att, wer_att = self.error_calculator(ys_hat.cpu(), ys_pad.cpu()) - - return loss_att, acc_att, cer_att, wer_att - - def _calc_ctc_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - # Calc CTC loss - loss_ctc = self.ctc(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens) - - # Calc CER using CTC - cer_ctc = None - if not self.training and self.error_calculator is not None: - ys_hat = self.ctc.argmax(encoder_out).data - cer_ctc = self.error_calculator(ys_hat.cpu(), ys_pad.cpu(), is_ctc=True) - return loss_ctc, cer_ctc diff --git a/funasr/models/e2e_asr_contextual_paraformer.py b/funasr/models/e2e_asr_contextual_paraformer.py deleted file mode 100644 index 598d5ac3f..000000000 --- a/funasr/models/e2e_asr_contextual_paraformer.py +++ /dev/null @@ -1,374 +0,0 @@ -import logging -from contextlib import contextmanager -from distutils.version import LooseVersion -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union -import numpy as np - -import torch - -from funasr.layers.abs_normalize import AbsNormalize -from funasr.models.ctc import CTC -from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.modules.add_sos_eos import add_sos_eos -from funasr.modules.nets_utils import make_pad_mask, pad_list -from funasr.modules.nets_utils import th_accuracy -from funasr.torch_utils.device_funcs import force_gatherable -from funasr.models.e2e_asr_paraformer import Paraformer - - -if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): - from torch.cuda.amp import autocast -else: - # Nothing to do if torch<1.6.0 - @contextmanager - def autocast(enabled=True): - yield - - -class NeatContextualParaformer(Paraformer): - def __init__( - self, - vocab_size: int, - token_list: Union[Tuple[str, ...], List[str]], - frontend: Optional[AbsFrontend], - specaug: Optional[AbsSpecAug], - normalize: Optional[AbsNormalize], - encoder: AbsEncoder, - decoder: AbsDecoder, - ctc: CTC, - ctc_weight: float = 0.5, - interctc_weight: float = 0.0, - ignore_id: int = -1, - blank_id: int = 0, - sos: int = 1, - eos: int = 2, - lsm_weight: float = 0.0, - length_normalized_loss: bool = False, - report_cer: bool = True, - report_wer: bool = True, - sym_space: str = "", - sym_blank: str = "", - extract_feats_in_collect_stats: bool = True, - predictor = None, - predictor_weight: float = 0.0, - predictor_bias: int = 0, - sampling_ratio: float = 0.2, - target_buffer_length: int = -1, - inner_dim: int = 256, - bias_encoder_type: str = 'lstm', - use_decoder_embedding: bool = False, - crit_attn_weight: float = 0.0, - crit_attn_smooth: float = 0.0, - bias_encoder_dropout_rate: float = 0.0, - preencoder: Optional[AbsPreEncoder] = None, - postencoder: Optional[AbsPostEncoder] = None, - ): - assert 0.0 <= ctc_weight <= 1.0, ctc_weight - assert 0.0 <= interctc_weight < 1.0, interctc_weight - - super().__init__( - vocab_size=vocab_size, - token_list=token_list, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - postencoder=postencoder, - decoder=decoder, - ctc=ctc, - ctc_weight=ctc_weight, - interctc_weight=interctc_weight, - ignore_id=ignore_id, - blank_id=blank_id, - sos=sos, - eos=eos, - lsm_weight=lsm_weight, - length_normalized_loss=length_normalized_loss, - report_cer=report_cer, - report_wer=report_wer, - sym_space=sym_space, - sym_blank=sym_blank, - extract_feats_in_collect_stats=extract_feats_in_collect_stats, - predictor=predictor, - predictor_weight=predictor_weight, - predictor_bias=predictor_bias, - sampling_ratio=sampling_ratio, - ) - - if bias_encoder_type == 'lstm': - logging.warning("enable bias encoder sampling and contextual training") - self.bias_encoder = torch.nn.LSTM(inner_dim, inner_dim, 1, batch_first=True, dropout=bias_encoder_dropout_rate) - self.bias_embed = torch.nn.Embedding(vocab_size, inner_dim) - elif bias_encoder_type == 'mean': - logging.warning("enable bias encoder sampling and contextual training") - self.bias_embed = torch.nn.Embedding(vocab_size, inner_dim) - else: - logging.error("Unsupport bias encoder type: {}".format(bias_encoder_type)) - - self.target_buffer_length = target_buffer_length - if self.target_buffer_length > 0: - self.hotword_buffer = None - self.length_record = [] - self.current_buffer_length = 0 - self.use_decoder_embedding = use_decoder_embedding - self.crit_attn_weight = crit_attn_weight - if self.crit_attn_weight > 0: - self.attn_loss = torch.nn.L1Loss() - self.crit_attn_smooth = crit_attn_smooth - self.length_normalized_loss = length_normalized_loss - - def forward( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - hotword_pad: torch.Tensor, - hotword_lengths: torch.Tensor, - dha_pad: torch.Tensor, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - """Frontend + Encoder + Decoder + Calc loss - - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - text: (Batch, Length) - text_lengths: (Batch,) - """ - assert text_lengths.dim() == 1, text_lengths.shape - # Check that batch_size is unified - assert ( - speech.shape[0] - == speech_lengths.shape[0] - == text.shape[0] - == text_lengths.shape[0] - ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) - batch_size = speech.shape[0] - self.step_cur += 1 - # for data-parallel - text = text[:, : text_lengths.max()] - speech = speech[:, :speech_lengths.max()] - - # 1. Encoder - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - loss_att, acc_att, cer_att, wer_att = None, None, None, None - loss_ctc, cer_ctc = None, None - loss_pre = None - loss_ideal = None - - stats = dict() - - # 1. CTC branch - if self.ctc_weight != 0.0: - loss_ctc, cer_ctc = self._calc_ctc_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # Collect CTC branch stats - stats["loss_ctc"] = loss_ctc.detach() if loss_ctc is not None else None - stats["cer_ctc"] = cer_ctc - - # Intermediate CTC (optional) - loss_interctc = 0.0 - if self.interctc_weight != 0.0 and intermediate_outs is not None: - for layer_idx, intermediate_out in intermediate_outs: - # we assume intermediate_out has the same length & padding - # as those of encoder_out - loss_ic, cer_ic = self._calc_ctc_loss( - intermediate_out, encoder_out_lens, text, text_lengths - ) - loss_interctc = loss_interctc + loss_ic - - # Collect Intermedaite CTC stats - stats["loss_interctc_layer{}".format(layer_idx)] = ( - loss_ic.detach() if loss_ic is not None else None - ) - stats["cer_interctc_layer{}".format(layer_idx)] = cer_ic - - loss_interctc = loss_interctc / len(intermediate_outs) - - # calculate whole encoder loss - loss_ctc = (1 - self.interctc_weight) * loss_ctc + self.interctc_weight * loss_interctc - - # 2b. Attention decoder branch - if self.ctc_weight != 1.0: - loss_att, acc_att, cer_att, wer_att, loss_pre, loss_ideal = self._calc_att_clas_loss( - encoder_out, encoder_out_lens, text, text_lengths, hotword_pad, hotword_lengths - ) - - # 3. CTC-Att loss definition - if self.ctc_weight == 0.0: - loss = loss_att + loss_pre * self.predictor_weight - elif self.ctc_weight == 1.0: - loss = loss_ctc - else: - loss = self.ctc_weight * loss_ctc + (1 - self.ctc_weight) * loss_att + loss_pre * self.predictor_weight - - if loss_ideal is not None: - loss = loss + loss_ideal * self.crit_attn_weight - stats["loss_ideal"] = loss_ideal.detach().cpu() - - # Collect Attn branch stats - stats["loss_att"] = loss_att.detach() if loss_att is not None else None - stats["acc"] = acc_att - stats["cer"] = cer_att - stats["wer"] = wer_att - stats["loss_pre"] = loss_pre.detach().cpu() if loss_pre is not None else None - - stats["loss"] = torch.clone(loss.detach()) - # force_gatherable: to-device and to-tensor if scalar for DataParallel - if self.length_normalized_loss: - batch_size = int((text_lengths + self.predictor_bias).sum()) - - loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) - return loss, stats, weight - - def _calc_att_clas_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - hotword_pad: torch.Tensor, - hotword_lengths: torch.Tensor, - ): - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - if self.predictor_bias == 1: - _, ys_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_pad_lens = ys_pad_lens + self.predictor_bias - pre_acoustic_embeds, pre_token_length, _, _ = self.predictor(encoder_out, ys_pad, encoder_out_mask, - ignore_id=self.ignore_id) - - # -1. bias encoder - if self.use_decoder_embedding: - hw_embed = self.decoder.embed(hotword_pad) - else: - hw_embed = self.bias_embed(hotword_pad) - hw_embed, (_, _) = self.bias_encoder(hw_embed) - _ind = np.arange(0, hotword_pad.shape[0]).tolist() - selected = hw_embed[_ind, [i-1 for i in hotword_lengths.detach().cpu().tolist()]] - contextual_info = selected.squeeze(0).repeat(ys_pad.shape[0], 1, 1).to(ys_pad.device) - - # 0. sampler - decoder_out_1st = None - if self.sampling_ratio > 0.0: - if self.step_cur < 2: - logging.info("enable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds, decoder_out_1st = self.sampler(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, - pre_acoustic_embeds, contextual_info) - else: - if self.step_cur < 2: - logging.info("disable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds = pre_acoustic_embeds - - # 1. Forward decoder - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=contextual_info - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - ''' - if self.crit_attn_weight > 0 and attn.shape[-1] > 1: - ideal_attn = ideal_attn + self.crit_attn_smooth / (self.crit_attn_smooth + 1.0) - attn_non_blank = attn[:,:,:,:-1] - ideal_attn_non_blank = ideal_attn[:,:,:-1] - loss_ideal = self.attn_loss(attn_non_blank.max(1)[0], ideal_attn_non_blank.to(attn.device)) - else: - loss_ideal = None - ''' - loss_ideal = None - - if decoder_out_1st is None: - decoder_out_1st = decoder_out - # 2. Compute attention loss - loss_att = self.criterion_att(decoder_out, ys_pad) - acc_att = th_accuracy( - decoder_out_1st.view(-1, self.vocab_size), - ys_pad, - ignore_label=self.ignore_id, - ) - loss_pre = self.criterion_pre(ys_pad_lens.type_as(pre_token_length), pre_token_length) - - # Compute cer/wer using attention-decoder - if self.training or self.error_calculator is None: - cer_att, wer_att = None, None - else: - ys_hat = decoder_out_1st.argmax(dim=-1) - cer_att, wer_att = self.error_calculator(ys_hat.cpu(), ys_pad.cpu()) - - return loss_att, acc_att, cer_att, wer_att, loss_pre, loss_ideal - - def sampler(self, encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, pre_acoustic_embeds, contextual_info): - - tgt_mask = (~make_pad_mask(ys_pad_lens, maxlen=ys_pad_lens.max())[:, :, None]).to(ys_pad.device) - ys_pad = ys_pad * tgt_mask[:, :, 0] - if self.share_embedding: - ys_pad_embed = self.decoder.output_layer.weight[ys_pad] - else: - ys_pad_embed = self.decoder.embed(ys_pad) - with torch.no_grad(): - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, pre_acoustic_embeds, ys_pad_lens, contextual_info=contextual_info - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - pred_tokens = decoder_out.argmax(-1) - nonpad_positions = ys_pad.ne(self.ignore_id) - seq_lens = (nonpad_positions).sum(1) - same_num = ((pred_tokens == ys_pad) & nonpad_positions).sum(1) - input_mask = torch.ones_like(nonpad_positions) - bsz, seq_len = ys_pad.size() - for li in range(bsz): - target_num = (((seq_lens[li] - same_num[li].sum()).float()) * self.sampling_ratio).long() - if target_num > 0: - input_mask[li].scatter_(dim=0, index=torch.randperm(seq_lens[li])[:target_num].to(pre_acoustic_embeds.device), value=0) - input_mask = input_mask.eq(1) - input_mask = input_mask.masked_fill(~nonpad_positions, False) - input_mask_expand_dim = input_mask.unsqueeze(2).to(pre_acoustic_embeds.device) - - sematic_embeds = pre_acoustic_embeds.masked_fill(~input_mask_expand_dim, 0) + ys_pad_embed.masked_fill( - input_mask_expand_dim, 0) - return sematic_embeds * tgt_mask, decoder_out * tgt_mask - - def cal_decoder_with_predictor(self, encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, hw_list=None, clas_scale=1.0): - if hw_list is None: - hw_list = [torch.Tensor([1]).long().to(encoder_out.device)] # empty hotword list - hw_list_pad = pad_list(hw_list, 0) - if self.use_decoder_embedding: - hw_embed = self.decoder.embed(hw_list_pad) - else: - hw_embed = self.bias_embed(hw_list_pad) - hw_embed, (h_n, _) = self.bias_encoder(hw_embed) - hw_embed = h_n.repeat(encoder_out.shape[0], 1, 1) - else: - hw_lengths = [len(i) for i in hw_list] - hw_list_pad = pad_list([torch.Tensor(i).long() for i in hw_list], 0).to(encoder_out.device) - if self.use_decoder_embedding: - hw_embed = self.decoder.embed(hw_list_pad) - else: - hw_embed = self.bias_embed(hw_list_pad) - hw_embed = torch.nn.utils.rnn.pack_padded_sequence(hw_embed, hw_lengths, batch_first=True, - enforce_sorted=False) - _, (h_n, _) = self.bias_encoder(hw_embed) - hw_embed = h_n.repeat(encoder_out.shape[0], 1, 1) - - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=hw_embed, clas_scale=clas_scale - ) - decoder_out = decoder_outs[0] - decoder_out = torch.log_softmax(decoder_out, dim=-1) - return decoder_out, ys_pad_lens diff --git a/funasr/models/e2e_asr_paraformer.py b/funasr/models/e2e_asr_paraformer.py deleted file mode 100644 index 6b1d8241f..000000000 --- a/funasr/models/e2e_asr_paraformer.py +++ /dev/null @@ -1,2270 +0,0 @@ -import logging -from contextlib import contextmanager -from distutils.version import LooseVersion -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union - -import torch -import random -import numpy as np - -from funasr.layers.abs_normalize import AbsNormalize -from funasr.losses.label_smoothing_loss import ( - LabelSmoothingLoss, # noqa: H301 -) -from funasr.models.ctc import CTC -from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.models.e2e_asr_common import ErrorCalculator -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.predictor.cif import mae_loss -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.modules.add_sos_eos import add_sos_eos -from funasr.modules.nets_utils import make_pad_mask, pad_list -from funasr.modules.nets_utils import th_accuracy -from funasr.torch_utils.device_funcs import force_gatherable -from funasr.models.base_model import FunASRModel -from funasr.models.predictor.cif import CifPredictorV3 - -if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): - from torch.cuda.amp import autocast -else: - # Nothing to do if torch<1.6.0 - @contextmanager - def autocast(enabled=True): - yield - - -class Paraformer(FunASRModel): - """ - Author: Speech Lab of DAMO Academy, Alibaba Group - Paraformer: Fast and Accurate Parallel Transformer for Non-autoregressive End-to-End Speech Recognition - https://arxiv.org/abs/2206.08317 - """ - - def __init__( - self, - vocab_size: int, - token_list: Union[Tuple[str, ...], List[str]], - frontend: Optional[AbsFrontend], - specaug: Optional[AbsSpecAug], - normalize: Optional[AbsNormalize], - encoder: AbsEncoder, - decoder: AbsDecoder, - ctc: CTC, - ctc_weight: float = 0.5, - interctc_weight: float = 0.0, - ignore_id: int = -1, - blank_id: int = 0, - sos: int = 1, - eos: int = 2, - lsm_weight: float = 0.0, - length_normalized_loss: bool = False, - report_cer: bool = True, - report_wer: bool = True, - sym_space: str = "", - sym_blank: str = "", - extract_feats_in_collect_stats: bool = True, - predictor=None, - predictor_weight: float = 0.0, - predictor_bias: int = 0, - sampling_ratio: float = 0.2, - share_embedding: bool = False, - preencoder: Optional[AbsPreEncoder] = None, - postencoder: Optional[AbsPostEncoder] = None, - use_1st_decoder_loss: bool = False, - ): - assert 0.0 <= ctc_weight <= 1.0, ctc_weight - assert 0.0 <= interctc_weight < 1.0, interctc_weight - - super().__init__() - # note that eos is the same as sos (equivalent ID) - self.blank_id = blank_id - self.sos = vocab_size - 1 if sos is None else sos - self.eos = vocab_size - 1 if eos is None else eos - self.vocab_size = vocab_size - self.ignore_id = ignore_id - self.ctc_weight = ctc_weight - self.interctc_weight = interctc_weight - self.token_list = token_list.copy() - - self.frontend = frontend - self.specaug = specaug - self.normalize = normalize - self.preencoder = preencoder - self.postencoder = postencoder - self.encoder = encoder - - if not hasattr(self.encoder, "interctc_use_conditioning"): - self.encoder.interctc_use_conditioning = False - if self.encoder.interctc_use_conditioning: - self.encoder.conditioning_layer = torch.nn.Linear( - vocab_size, self.encoder.output_size() - ) - - self.error_calculator = None - - if ctc_weight == 1.0: - self.decoder = None - else: - self.decoder = decoder - - self.criterion_att = LabelSmoothingLoss( - size=vocab_size, - padding_idx=ignore_id, - smoothing=lsm_weight, - normalize_length=length_normalized_loss, - ) - - if report_cer or report_wer: - self.error_calculator = ErrorCalculator( - token_list, sym_space, sym_blank, report_cer, report_wer - ) - - if ctc_weight == 0.0: - self.ctc = None - else: - self.ctc = ctc - - self.extract_feats_in_collect_stats = extract_feats_in_collect_stats - self.predictor = predictor - self.predictor_weight = predictor_weight - self.predictor_bias = predictor_bias - self.sampling_ratio = sampling_ratio - self.criterion_pre = mae_loss(normalize_length=length_normalized_loss) - self.length_normalized_loss = length_normalized_loss - self.step_cur = 0 - - self.share_embedding = share_embedding - if self.share_embedding: - self.decoder.embed = None - - self.use_1st_decoder_loss = use_1st_decoder_loss - - def forward( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - decoding_ind: int = None, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - """Frontend + Encoder + Decoder + Calc loss - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - text: (Batch, Length) - text_lengths: (Batch,) - decoding_ind: int - """ - assert text_lengths.dim() == 1, text_lengths.shape - # Check that batch_size is unified - assert ( - speech.shape[0] - == speech_lengths.shape[0] - == text.shape[0] - == text_lengths.shape[0] - ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) - batch_size = speech.shape[0] - self.step_cur += 1 - # for data-parallel - text = text[:, : text_lengths.max()] - speech = speech[:, :speech_lengths.max()] - - # 1. Encoder - if hasattr(self.encoder, "overlap_chunk_cls"): - ind = self.encoder.overlap_chunk_cls.random_choice(self.training, decoding_ind) - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths, ind=ind) - else: - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - loss_att, pre_loss_att, acc_att, cer_att, wer_att = None, None, None, None, None - loss_ctc, cer_ctc = None, None - loss_pre = None - stats = dict() - - # 1. CTC branch - if self.ctc_weight != 0.0: - loss_ctc, cer_ctc = self._calc_ctc_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # Collect CTC branch stats - stats["loss_ctc"] = loss_ctc.detach() if loss_ctc is not None else None - stats["cer_ctc"] = cer_ctc - - # Intermediate CTC (optional) - loss_interctc = 0.0 - if self.interctc_weight != 0.0 and intermediate_outs is not None: - for layer_idx, intermediate_out in intermediate_outs: - # we assume intermediate_out has the same length & padding - # as those of encoder_out - loss_ic, cer_ic = self._calc_ctc_loss( - intermediate_out, encoder_out_lens, text, text_lengths - ) - loss_interctc = loss_interctc + loss_ic - - # Collect Intermedaite CTC stats - stats["loss_interctc_layer{}".format(layer_idx)] = ( - loss_ic.detach() if loss_ic is not None else None - ) - stats["cer_interctc_layer{}".format(layer_idx)] = cer_ic - - loss_interctc = loss_interctc / len(intermediate_outs) - - # calculate whole encoder loss - loss_ctc = ( - 1 - self.interctc_weight - ) * loss_ctc + self.interctc_weight * loss_interctc - - # 2b. Attention decoder branch - if self.ctc_weight != 1.0: - loss_att, acc_att, cer_att, wer_att, loss_pre, pre_loss_att = self._calc_att_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # 3. CTC-Att loss definition - if self.ctc_weight == 0.0: - loss = loss_att + loss_pre * self.predictor_weight - elif self.ctc_weight == 1.0: - loss = loss_ctc - else: - loss = self.ctc_weight * loss_ctc + (1 - self.ctc_weight) * loss_att + loss_pre * self.predictor_weight - - if self.use_1st_decoder_loss and pre_loss_att is not None: - loss = loss + (1 - self.ctc_weight) * pre_loss_att - - # Collect Attn branch stats - stats["loss_att"] = loss_att.detach() if loss_att is not None else None - stats["pre_loss_att"] = pre_loss_att.detach() if pre_loss_att is not None else None - stats["acc"] = acc_att - stats["cer"] = cer_att - stats["wer"] = wer_att - stats["loss_pre"] = loss_pre.detach().cpu() if loss_pre is not None else None - - stats["loss"] = torch.clone(loss.detach()) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - if self.length_normalized_loss: - batch_size = int((text_lengths + self.predictor_bias).sum()) - - loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) - return loss, stats, weight - - def collect_feats( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - ) -> Dict[str, torch.Tensor]: - if self.extract_feats_in_collect_stats: - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - else: - # Generate dummy stats if extract_feats_in_collect_stats is False - logging.warning( - "Generating dummy stats for feats and feats_lengths, " - "because encoder_conf.extract_feats_in_collect_stats is " - f"{self.extract_feats_in_collect_stats}" - ) - feats, feats_lengths = speech, speech_lengths - return {"feats": feats, "feats_lengths": feats_lengths} - - def encode( - self, speech: torch.Tensor, speech_lengths: torch.Tensor, ind: int = 0, - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Frontend + Encoder. Note that this method is used by asr_inference.py - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - ind: int - """ - with autocast(False): - # 1. Extract feats - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - - # 2. Data augmentation - if self.specaug is not None and self.training: - feats, feats_lengths = self.specaug(feats, feats_lengths) - - # 3. Normalization for feature: e.g. Global-CMVN, Utterance-CMVN - if self.normalize is not None: - feats, feats_lengths = self.normalize(feats, feats_lengths) - - # Pre-encoder, e.g. used for raw input data - if self.preencoder is not None: - feats, feats_lengths = self.preencoder(feats, feats_lengths) - - # 4. Forward encoder - # feats: (Batch, Length, Dim) - # -> encoder_out: (Batch, Length2, Dim2) - if self.encoder.interctc_use_conditioning: - if hasattr(self.encoder, "overlap_chunk_cls"): - encoder_out, encoder_out_lens, _ = self.encoder( - feats, feats_lengths, ctc=self.ctc, ind=ind - ) - encoder_out, encoder_out_lens = self.encoder.overlap_chunk_cls.remove_chunk(encoder_out, - encoder_out_lens, - chunk_outs=None) - else: - encoder_out, encoder_out_lens, _ = self.encoder( - feats, feats_lengths, ctc=self.ctc - ) - else: - if hasattr(self.encoder, "overlap_chunk_cls"): - encoder_out, encoder_out_lens, _ = self.encoder(feats, feats_lengths, ind=ind) - encoder_out, encoder_out_lens = self.encoder.overlap_chunk_cls.remove_chunk(encoder_out, - encoder_out_lens, - chunk_outs=None) - else: - encoder_out, encoder_out_lens, _ = self.encoder(feats, feats_lengths) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - # Post-encoder, e.g. NLU - if self.postencoder is not None: - encoder_out, encoder_out_lens = self.postencoder( - encoder_out, encoder_out_lens - ) - - assert encoder_out.size(0) == speech.size(0), ( - encoder_out.size(), - speech.size(0), - ) - assert encoder_out.size(1) <= encoder_out_lens.max(), ( - encoder_out.size(), - encoder_out_lens.max(), - ) - - if intermediate_outs is not None: - return (encoder_out, intermediate_outs), encoder_out_lens - - return encoder_out, encoder_out_lens - - def calc_predictor(self, encoder_out, encoder_out_lens): - - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - pre_acoustic_embeds, pre_token_length, alphas, pre_peak_index = self.predictor(encoder_out, None, - encoder_out_mask, - ignore_id=self.ignore_id) - return pre_acoustic_embeds, pre_token_length, alphas, pre_peak_index - - def cal_decoder_with_predictor(self, encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens): - - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens - ) - decoder_out = decoder_outs[0] - decoder_out = torch.log_softmax(decoder_out, dim=-1) - return decoder_out, ys_pad_lens - - def _extract_feats( - self, speech: torch.Tensor, speech_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - assert speech_lengths.dim() == 1, speech_lengths.shape - - # for data-parallel - speech = speech[:, : speech_lengths.max()] - if self.frontend is not None: - # Frontend - # e.g. STFT and Feature extract - # data_loader may send time-domain signal in this case - # speech (Batch, NSamples) -> feats: (Batch, NFrames, Dim) - feats, feats_lengths = self.frontend(speech, speech_lengths) - else: - # No frontend and no feature extract - feats, feats_lengths = speech, speech_lengths - return feats, feats_lengths - - def nll( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ) -> torch.Tensor: - """Compute negative log likelihood(nll) from transformer-decoder - Normally, this function is called in batchify_nll. - Args: - encoder_out: (Batch, Length, Dim) - encoder_out_lens: (Batch,) - ys_pad: (Batch, Length) - ys_pad_lens: (Batch,) - """ - ys_in_pad, ys_out_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_in_lens = ys_pad_lens + 1 - - # 1. Forward decoder - decoder_out, _ = self.decoder( - encoder_out, encoder_out_lens, ys_in_pad, ys_in_lens - ) # [batch, seqlen, dim] - batch_size = decoder_out.size(0) - decoder_num_class = decoder_out.size(2) - # nll: negative log-likelihood - nll = torch.nn.functional.cross_entropy( - decoder_out.view(-1, decoder_num_class), - ys_out_pad.view(-1), - ignore_index=self.ignore_id, - reduction="none", - ) - nll = nll.view(batch_size, -1) - nll = nll.sum(dim=1) - assert nll.size(0) == batch_size - return nll - - def batchify_nll( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - batch_size: int = 100, - ): - """Compute negative log likelihood(nll) from transformer-decoder - To avoid OOM, this fuction seperate the input into batches. - Then call nll for each batch and combine and return results. - Args: - encoder_out: (Batch, Length, Dim) - encoder_out_lens: (Batch,) - ys_pad: (Batch, Length) - ys_pad_lens: (Batch,) - batch_size: int, samples each batch contain when computing nll, - you may change this to avoid OOM or increase - GPU memory usage - """ - total_num = encoder_out.size(0) - if total_num <= batch_size: - nll = self.nll(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens) - else: - nll = [] - start_idx = 0 - while True: - end_idx = min(start_idx + batch_size, total_num) - batch_encoder_out = encoder_out[start_idx:end_idx, :, :] - batch_encoder_out_lens = encoder_out_lens[start_idx:end_idx] - batch_ys_pad = ys_pad[start_idx:end_idx, :] - batch_ys_pad_lens = ys_pad_lens[start_idx:end_idx] - batch_nll = self.nll( - batch_encoder_out, - batch_encoder_out_lens, - batch_ys_pad, - batch_ys_pad_lens, - ) - nll.append(batch_nll) - start_idx = end_idx - if start_idx == total_num: - break - nll = torch.cat(nll) - assert nll.size(0) == total_num - return nll - - def _calc_att_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - if self.predictor_bias == 1: - _, ys_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_pad_lens = ys_pad_lens + self.predictor_bias - pre_acoustic_embeds, pre_token_length, _, pre_peak_index = self.predictor(encoder_out, ys_pad, encoder_out_mask, - ignore_id=self.ignore_id) - - # 0. sampler - decoder_out_1st = None - pre_loss_att = None - if self.sampling_ratio > 0.0: - if self.step_cur < 2: - logging.info("enable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - if self.use_1st_decoder_loss: - sematic_embeds, decoder_out_1st, pre_loss_att = self.sampler_with_grad(encoder_out, encoder_out_lens, - ys_pad, ys_pad_lens, - pre_acoustic_embeds) - else: - sematic_embeds, decoder_out_1st = self.sampler(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, - pre_acoustic_embeds) - else: - if self.step_cur < 2: - logging.info("disable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds = pre_acoustic_embeds - - # 1. Forward decoder - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - - if decoder_out_1st is None: - decoder_out_1st = decoder_out - # 2. Compute attention loss - loss_att = self.criterion_att(decoder_out, ys_pad) - acc_att = th_accuracy( - decoder_out_1st.view(-1, self.vocab_size), - ys_pad, - ignore_label=self.ignore_id, - ) - loss_pre = self.criterion_pre(ys_pad_lens.type_as(pre_token_length), pre_token_length) - - # Compute cer/wer using attention-decoder - if self.training or self.error_calculator is None: - cer_att, wer_att = None, None - else: - ys_hat = decoder_out_1st.argmax(dim=-1) - cer_att, wer_att = self.error_calculator(ys_hat.cpu(), ys_pad.cpu()) - - return loss_att, acc_att, cer_att, wer_att, loss_pre, pre_loss_att - - def sampler(self, encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, pre_acoustic_embeds): - - tgt_mask = (~make_pad_mask(ys_pad_lens, maxlen=ys_pad_lens.max())[:, :, None]).to(ys_pad.device) - ys_pad_masked = ys_pad * tgt_mask[:, :, 0] - if self.share_embedding: - ys_pad_embed = self.decoder.output_layer.weight[ys_pad_masked] - else: - ys_pad_embed = self.decoder.embed(ys_pad_masked) - with torch.no_grad(): - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, pre_acoustic_embeds, ys_pad_lens - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - pred_tokens = decoder_out.argmax(-1) - nonpad_positions = ys_pad.ne(self.ignore_id) - seq_lens = (nonpad_positions).sum(1) - same_num = ((pred_tokens == ys_pad) & nonpad_positions).sum(1) - input_mask = torch.ones_like(nonpad_positions) - bsz, seq_len = ys_pad.size() - for li in range(bsz): - target_num = (((seq_lens[li] - same_num[li].sum()).float()) * self.sampling_ratio).long() - if target_num > 0: - input_mask[li].scatter_(dim=0, index=torch.randperm(seq_lens[li])[:target_num].cuda(), value=0) - input_mask = input_mask.eq(1) - input_mask = input_mask.masked_fill(~nonpad_positions, False) - input_mask_expand_dim = input_mask.unsqueeze(2).to(pre_acoustic_embeds.device) - - sematic_embeds = pre_acoustic_embeds.masked_fill(~input_mask_expand_dim, 0) + ys_pad_embed.masked_fill( - input_mask_expand_dim, 0) - return sematic_embeds * tgt_mask, decoder_out * tgt_mask - - def sampler_with_grad(self, encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, pre_acoustic_embeds): - tgt_mask = (~make_pad_mask(ys_pad_lens, maxlen=ys_pad_lens.max())[:, :, None]).to(ys_pad.device) - ys_pad_masked = ys_pad * tgt_mask[:, :, 0] - if self.share_embedding: - ys_pad_embed = self.decoder.output_layer.weight[ys_pad_masked] - else: - ys_pad_embed = self.decoder.embed(ys_pad_masked) - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, pre_acoustic_embeds, ys_pad_lens - ) - pre_loss_att = self.criterion_att(decoder_outs[0], ys_pad) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - pred_tokens = decoder_out.argmax(-1) - nonpad_positions = ys_pad.ne(self.ignore_id) - seq_lens = (nonpad_positions).sum(1) - same_num = ((pred_tokens == ys_pad) & nonpad_positions).sum(1) - input_mask = torch.ones_like(nonpad_positions) - bsz, seq_len = ys_pad.size() - for li in range(bsz): - target_num = (((seq_lens[li] - same_num[li].sum()).float()) * self.sampling_ratio).long() - if target_num > 0: - input_mask[li].scatter_(dim=0, index=torch.randperm(seq_lens[li])[:target_num].cuda(), value=0) - input_mask = input_mask.eq(1) - input_mask = input_mask.masked_fill(~nonpad_positions, False) - input_mask_expand_dim = input_mask.unsqueeze(2).to(pre_acoustic_embeds.device) - - sematic_embeds = pre_acoustic_embeds.masked_fill(~input_mask_expand_dim, 0) + ys_pad_embed.masked_fill( - input_mask_expand_dim, 0) - - return sematic_embeds * tgt_mask, decoder_out * tgt_mask, pre_loss_att - - def _calc_ctc_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - # Calc CTC loss - loss_ctc = self.ctc(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens) - - # Calc CER using CTC - cer_ctc = None - if not self.training and self.error_calculator is not None: - ys_hat = self.ctc.argmax(encoder_out).data - cer_ctc = self.error_calculator(ys_hat.cpu(), ys_pad.cpu(), is_ctc=True) - return loss_ctc, cer_ctc - - -class ParaformerOnline(Paraformer): - """ - Author: Speech Lab, Alibaba Group, China - Paraformer: Fast and Accurate Parallel Transformer for Non-autoregressive End-to-End Speech Recognition - https://arxiv.org/abs/2206.08317 - """ - - def __init__( - self, - vocab_size: int, - token_list: Union[Tuple[str, ...], List[str]], - frontend: Optional[AbsFrontend], - specaug: Optional[AbsSpecAug], - normalize: Optional[AbsNormalize], - encoder: AbsEncoder, - decoder: AbsDecoder, - ctc: CTC, - ctc_weight: float = 0.5, - interctc_weight: float = 0.0, - ignore_id: int = -1, - blank_id: int = 0, - sos: int = 1, - eos: int = 2, - lsm_weight: float = 0.0, - length_normalized_loss: bool = False, - report_cer: bool = True, - report_wer: bool = True, - sym_space: str = "", - sym_blank: str = "", - extract_feats_in_collect_stats: bool = True, - predictor=None, - predictor_weight: float = 0.0, - predictor_bias: int = 0, - sampling_ratio: float = 0.2, - decoder_attention_chunk_type: str = 'chunk', - share_embedding: bool = False, - preencoder: Optional[AbsPreEncoder] = None, - postencoder: Optional[AbsPostEncoder] = None, - use_1st_decoder_loss: bool = False, - ): - assert 0.0 <= ctc_weight <= 1.0, ctc_weight - assert 0.0 <= interctc_weight < 1.0, interctc_weight - - super().__init__( - vocab_size=vocab_size, - token_list=token_list, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - postencoder=postencoder, - decoder=decoder, - ctc=ctc, - ctc_weight=ctc_weight, - interctc_weight=interctc_weight, - ignore_id=ignore_id, - blank_id=blank_id, - sos=sos, - eos=eos, - lsm_weight=lsm_weight, - length_normalized_loss=length_normalized_loss, - report_cer=report_cer, - report_wer=report_wer, - sym_space=sym_space, - sym_blank=sym_blank, - extract_feats_in_collect_stats=extract_feats_in_collect_stats, - predictor=predictor, - predictor_weight=predictor_weight, - predictor_bias=predictor_bias, - sampling_ratio=sampling_ratio, - ) - # note that eos is the same as sos (equivalent ID) - self.blank_id = blank_id - self.sos = vocab_size - 1 if sos is None else sos - self.eos = vocab_size - 1 if eos is None else eos - self.vocab_size = vocab_size - self.ignore_id = ignore_id - self.ctc_weight = ctc_weight - self.interctc_weight = interctc_weight - self.token_list = token_list.copy() - - self.frontend = frontend - self.specaug = specaug - self.normalize = normalize - self.preencoder = preencoder - self.postencoder = postencoder - self.encoder = encoder - - if not hasattr(self.encoder, "interctc_use_conditioning"): - self.encoder.interctc_use_conditioning = False - if self.encoder.interctc_use_conditioning: - self.encoder.conditioning_layer = torch.nn.Linear( - vocab_size, self.encoder.output_size() - ) - - self.error_calculator = None - - if ctc_weight == 1.0: - self.decoder = None - else: - self.decoder = decoder - - self.criterion_att = LabelSmoothingLoss( - size=vocab_size, - padding_idx=ignore_id, - smoothing=lsm_weight, - normalize_length=length_normalized_loss, - ) - - if report_cer or report_wer: - self.error_calculator = ErrorCalculator( - token_list, sym_space, sym_blank, report_cer, report_wer - ) - - if ctc_weight == 0.0: - self.ctc = None - else: - self.ctc = ctc - - self.extract_feats_in_collect_stats = extract_feats_in_collect_stats - self.predictor = predictor - self.predictor_weight = predictor_weight - self.predictor_bias = predictor_bias - self.length_normalized_loss = length_normalized_loss - self.sampling_ratio = sampling_ratio - self.criterion_pre = mae_loss(normalize_length=length_normalized_loss) - self.step_cur = 0 - self.scama_mask = None - if hasattr(self.encoder, "overlap_chunk_cls") and self.encoder.overlap_chunk_cls is not None: - from funasr.modules.streaming_utils.chunk_utilis import build_scama_mask_for_cross_attention_decoder - self.build_scama_mask_for_cross_attention_decoder_fn = build_scama_mask_for_cross_attention_decoder - self.decoder_attention_chunk_type = decoder_attention_chunk_type - - self.share_embedding = share_embedding - if self.share_embedding: - self.decoder.embed = None - - self.use_1st_decoder_loss = use_1st_decoder_loss - - def forward( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - decoding_ind: int = None, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - """Frontend + Encoder + Decoder + Calc loss - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - text: (Batch, Length) - text_lengths: (Batch,) - decoding_ind: int - """ - assert text_lengths.dim() == 1, text_lengths.shape - # Check that batch_size is unified - assert ( - speech.shape[0] - == speech_lengths.shape[0] - == text.shape[0] - == text_lengths.shape[0] - ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) - batch_size = speech.shape[0] - self.step_cur += 1 - # for data-parallel - text = text[:, : text_lengths.max()] - speech = speech[:, :speech_lengths.max()] - - # 1. Encoder - if hasattr(self.encoder, "overlap_chunk_cls"): - ind = self.encoder.overlap_chunk_cls.random_choice(self.training, decoding_ind) - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths, ind=ind) - else: - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - loss_att, acc_att, cer_att, wer_att = None, None, None, None - loss_ctc, cer_ctc = None, None - loss_pre = None - stats = dict() - - # 1. CTC branch - if self.ctc_weight != 0.0: - if hasattr(self.encoder, "overlap_chunk_cls"): - encoder_out_ctc, encoder_out_lens_ctc = self.encoder.overlap_chunk_cls.remove_chunk(encoder_out, - encoder_out_lens, - chunk_outs=None) - loss_ctc, cer_ctc = self._calc_ctc_loss( - encoder_out_ctc, encoder_out_lens_ctc, text, text_lengths - ) - - # Collect CTC branch stats - stats["loss_ctc"] = loss_ctc.detach() if loss_ctc is not None else None - stats["cer_ctc"] = cer_ctc - - # Intermediate CTC (optional) - loss_interctc = 0.0 - if self.interctc_weight != 0.0 and intermediate_outs is not None: - for layer_idx, intermediate_out in intermediate_outs: - # we assume intermediate_out has the same length & padding - # as those of encoder_out - if hasattr(self.encoder, "overlap_chunk_cls"): - encoder_out_ctc, encoder_out_lens_ctc = \ - self.encoder.overlap_chunk_cls.remove_chunk( - intermediate_out, - encoder_out_lens, - chunk_outs=None) - loss_ic, cer_ic = self._calc_ctc_loss( - encoder_out_ctc, encoder_out_lens_ctc, text, text_lengths - ) - loss_interctc = loss_interctc + loss_ic - - # Collect Intermedaite CTC stats - stats["loss_interctc_layer{}".format(layer_idx)] = ( - loss_ic.detach() if loss_ic is not None else None - ) - stats["cer_interctc_layer{}".format(layer_idx)] = cer_ic - - loss_interctc = loss_interctc / len(intermediate_outs) - - # calculate whole encoder loss - loss_ctc = ( - 1 - self.interctc_weight - ) * loss_ctc + self.interctc_weight * loss_interctc - - # 2b. Attention decoder branch - if self.ctc_weight != 1.0: - loss_att, acc_att, cer_att, wer_att, loss_pre, pre_loss_att = self._calc_att_predictor_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # 3. CTC-Att loss definition - if self.ctc_weight == 0.0: - loss = loss_att + loss_pre * self.predictor_weight - elif self.ctc_weight == 1.0: - loss = loss_ctc - else: - loss = self.ctc_weight * loss_ctc + (1 - self.ctc_weight) * loss_att + loss_pre * self.predictor_weight - - if self.use_1st_decoder_loss and pre_loss_att is not None: - loss = loss + pre_loss_att - - # Collect Attn branch stats - stats["loss_att"] = loss_att.detach() if loss_att is not None else None - stats["pre_loss_att"] = pre_loss_att.detach() if pre_loss_att is not None else None - stats["acc"] = acc_att - stats["cer"] = cer_att - stats["wer"] = wer_att - stats["loss_pre"] = loss_pre.detach().cpu() if loss_pre is not None else None - - stats["loss"] = torch.clone(loss.detach()) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - if self.length_normalized_loss: - batch_size = int((text_lengths + self.predictor_bias).sum()) - - loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) - return loss, stats, weight - - def encode( - self, speech: torch.Tensor, speech_lengths: torch.Tensor, ind: int = 0, - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Frontend + Encoder. Note that this method is used by asr_inference.py - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - """ - with autocast(False): - # 1. Extract feats - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - - # 2. Data augmentation - if self.specaug is not None and self.training: - feats, feats_lengths = self.specaug(feats, feats_lengths) - - # 3. Normalization for feature: e.g. Global-CMVN, Utterance-CMVN - if self.normalize is not None: - feats, feats_lengths = self.normalize(feats, feats_lengths) - # Pre-encoder, e.g. used for raw input data - if self.preencoder is not None: - feats, feats_lengths = self.preencoder(feats, feats_lengths) - - # 4. Forward encoder - # feats: (Batch, Length, Dim) - # -> encoder_out: (Batch, Length2, Dim2) - if self.encoder.interctc_use_conditioning: - encoder_out, encoder_out_lens, _ = self.encoder( - feats, feats_lengths, ctc=self.ctc, ind=ind - ) - else: - encoder_out, encoder_out_lens, _ = self.encoder(feats, feats_lengths, ind=ind) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - # Post-encoder, e.g. NLU - if self.postencoder is not None: - encoder_out, encoder_out_lens = self.postencoder( - encoder_out, encoder_out_lens - ) - - assert encoder_out.size(0) == speech.size(0), ( - encoder_out.size(), - speech.size(0), - ) - assert encoder_out.size(1) <= encoder_out_lens.max(), ( - encoder_out.size(), - encoder_out_lens.max(), - ) - - if intermediate_outs is not None: - return (encoder_out, intermediate_outs), encoder_out_lens - - return encoder_out, encoder_out_lens - - def encode_chunk( - self, speech: torch.Tensor, speech_lengths: torch.Tensor, cache: dict = None - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Frontend + Encoder. Note that this method is used by asr_inference.py - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - """ - with autocast(False): - # 1. Extract feats - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - - # 2. Data augmentation - if self.specaug is not None and self.training: - feats, feats_lengths = self.specaug(feats, feats_lengths) - - # 3. Normalization for feature: e.g. Global-CMVN, Utterance-CMVN - if self.normalize is not None: - feats, feats_lengths = self.normalize(feats, feats_lengths) - - # Pre-encoder, e.g. used for raw input data - if self.preencoder is not None: - feats, feats_lengths = self.preencoder(feats, feats_lengths) - - # 4. Forward encoder - # feats: (Batch, Length, Dim) - # -> encoder_out: (Batch, Length2, Dim2) - if self.encoder.interctc_use_conditioning: - encoder_out, encoder_out_lens, _ = self.encoder.forward_chunk( - feats, feats_lengths, cache=cache["encoder"], ctc=self.ctc - ) - else: - encoder_out, encoder_out_lens, _ = self.encoder.forward_chunk(feats, feats_lengths, cache=cache["encoder"]) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - # Post-encoder, e.g. NLU - if self.postencoder is not None: - encoder_out, encoder_out_lens = self.postencoder( - encoder_out, encoder_out_lens - ) - - if intermediate_outs is not None: - return (encoder_out, intermediate_outs), encoder_out_lens - - return encoder_out, torch.tensor([encoder_out.size(1)]) - - def _calc_att_predictor_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - if self.predictor_bias == 1: - _, ys_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_pad_lens = ys_pad_lens + self.predictor_bias - mask_chunk_predictor = None - if self.encoder.overlap_chunk_cls is not None: - mask_chunk_predictor = self.encoder.overlap_chunk_cls.get_mask_chunk_predictor(None, - device=encoder_out.device, - batch_size=encoder_out.size( - 0)) - mask_shfit_chunk = self.encoder.overlap_chunk_cls.get_mask_shfit_chunk(None, device=encoder_out.device, - batch_size=encoder_out.size(0)) - encoder_out = encoder_out * mask_shfit_chunk - pre_acoustic_embeds, pre_token_length, pre_alphas, _ = self.predictor(encoder_out, - ys_pad, - encoder_out_mask, - ignore_id=self.ignore_id, - mask_chunk_predictor=mask_chunk_predictor, - target_label_length=ys_pad_lens, - ) - predictor_alignments, predictor_alignments_len = self.predictor.gen_frame_alignments(pre_alphas, - encoder_out_lens) - - scama_mask = None - if self.encoder.overlap_chunk_cls is not None and self.decoder_attention_chunk_type == 'chunk': - encoder_chunk_size = self.encoder.overlap_chunk_cls.chunk_size_pad_shift_cur - attention_chunk_center_bias = 0 - attention_chunk_size = encoder_chunk_size - decoder_att_look_back_factor = self.encoder.overlap_chunk_cls.decoder_att_look_back_factor_cur - mask_shift_att_chunk_decoder = self.encoder.overlap_chunk_cls. \ - get_mask_shift_att_chunk_decoder(None, - device=encoder_out.device, - batch_size=encoder_out.size(0) - ) - scama_mask = self.build_scama_mask_for_cross_attention_decoder_fn( - predictor_alignments=predictor_alignments, - encoder_sequence_length=encoder_out_lens, - chunk_size=1, - encoder_chunk_size=encoder_chunk_size, - attention_chunk_center_bias=attention_chunk_center_bias, - attention_chunk_size=attention_chunk_size, - attention_chunk_type=self.decoder_attention_chunk_type, - step=None, - predictor_mask_chunk_hopping=mask_chunk_predictor, - decoder_att_look_back_factor=decoder_att_look_back_factor, - mask_shift_att_chunk_decoder=mask_shift_att_chunk_decoder, - target_length=ys_pad_lens, - is_training=self.training, - ) - elif self.encoder.overlap_chunk_cls is not None: - encoder_out, encoder_out_lens = self.encoder.overlap_chunk_cls.remove_chunk(encoder_out, - encoder_out_lens, - chunk_outs=None) - # 0. sampler - decoder_out_1st = None - pre_loss_att = None - if self.sampling_ratio > 0.0: - if self.step_cur < 2: - logging.info("enable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - if self.use_1st_decoder_loss: - sematic_embeds, decoder_out_1st, pre_loss_att = \ - self.sampler_with_grad(encoder_out, encoder_out_lens, ys_pad, - ys_pad_lens, pre_acoustic_embeds, scama_mask) - else: - sematic_embeds, decoder_out_1st = \ - self.sampler(encoder_out, encoder_out_lens, ys_pad, - ys_pad_lens, pre_acoustic_embeds, scama_mask) - else: - if self.step_cur < 2: - logging.info("disable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds = pre_acoustic_embeds - - # 1. Forward decoder - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, scama_mask - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - - if decoder_out_1st is None: - decoder_out_1st = decoder_out - # 2. Compute attention loss - loss_att = self.criterion_att(decoder_out, ys_pad) - acc_att = th_accuracy( - decoder_out_1st.view(-1, self.vocab_size), - ys_pad, - ignore_label=self.ignore_id, - ) - loss_pre = self.criterion_pre(ys_pad_lens.type_as(pre_token_length), pre_token_length) - - # Compute cer/wer using attention-decoder - if self.training or self.error_calculator is None: - cer_att, wer_att = None, None - else: - ys_hat = decoder_out_1st.argmax(dim=-1) - cer_att, wer_att = self.error_calculator(ys_hat.cpu(), ys_pad.cpu()) - - return loss_att, acc_att, cer_att, wer_att, loss_pre, pre_loss_att - - def sampler(self, encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, pre_acoustic_embeds, chunk_mask=None): - - tgt_mask = (~make_pad_mask(ys_pad_lens, maxlen=ys_pad_lens.max())[:, :, None]).to(ys_pad.device) - ys_pad_masked = ys_pad * tgt_mask[:, :, 0] - if self.share_embedding: - ys_pad_embed = self.decoder.output_layer.weight[ys_pad_masked] - else: - ys_pad_embed = self.decoder.embed(ys_pad_masked) - with torch.no_grad(): - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, pre_acoustic_embeds, ys_pad_lens, chunk_mask - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - pred_tokens = decoder_out.argmax(-1) - nonpad_positions = ys_pad.ne(self.ignore_id) - seq_lens = (nonpad_positions).sum(1) - same_num = ((pred_tokens == ys_pad) & nonpad_positions).sum(1) - input_mask = torch.ones_like(nonpad_positions) - bsz, seq_len = ys_pad.size() - for li in range(bsz): - target_num = (((seq_lens[li] - same_num[li].sum()).float()) * self.sampling_ratio).long() - if target_num > 0: - input_mask[li].scatter_(dim=0, index=torch.randperm(seq_lens[li])[:target_num].cuda(), value=0) - input_mask = input_mask.eq(1) - input_mask = input_mask.masked_fill(~nonpad_positions, False) - input_mask_expand_dim = input_mask.unsqueeze(2).to(pre_acoustic_embeds.device) - - sematic_embeds = pre_acoustic_embeds.masked_fill(~input_mask_expand_dim, 0) + ys_pad_embed.masked_fill( - input_mask_expand_dim, 0) - return sematic_embeds * tgt_mask, decoder_out * tgt_mask - - def sampler_with_grad(self, encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, pre_acoustic_embeds, - chunk_mask=None): - tgt_mask = (~make_pad_mask(ys_pad_lens, maxlen=ys_pad_lens.max())[:, :, None]).to(ys_pad.device) - ys_pad_masked = ys_pad * tgt_mask[:, :, 0] - if self.share_embedding: - ys_pad_embed = self.decoder.output_layer.weight[ys_pad_masked] - else: - ys_pad_embed = self.decoder.embed(ys_pad_masked) - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, pre_acoustic_embeds, ys_pad_lens, chunk_mask - ) - pre_loss_att = self.criterion_att(decoder_outs[0], ys_pad) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - pred_tokens = decoder_out.argmax(-1) - nonpad_positions = ys_pad.ne(self.ignore_id) - seq_lens = (nonpad_positions).sum(1) - same_num = ((pred_tokens == ys_pad) & nonpad_positions).sum(1) - input_mask = torch.ones_like(nonpad_positions) - bsz, seq_len = ys_pad.size() - for li in range(bsz): - target_num = (((seq_lens[li] - same_num[li].sum()).float()) * self.sampling_ratio).long() - if target_num > 0: - input_mask[li].scatter_(dim=0, index=torch.randperm(seq_lens[li])[:target_num].cuda(), value=0) - input_mask = input_mask.eq(1) - input_mask = input_mask.masked_fill(~nonpad_positions, False) - input_mask_expand_dim = input_mask.unsqueeze(2).to(pre_acoustic_embeds.device) - - sematic_embeds = pre_acoustic_embeds.masked_fill(~input_mask_expand_dim, 0) + ys_pad_embed.masked_fill( - input_mask_expand_dim, 0) - - return sematic_embeds * tgt_mask, decoder_out * tgt_mask, pre_loss_att - - def calc_predictor(self, encoder_out, encoder_out_lens): - - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - mask_chunk_predictor = None - if self.encoder.overlap_chunk_cls is not None: - mask_chunk_predictor = self.encoder.overlap_chunk_cls.get_mask_chunk_predictor(None, - device=encoder_out.device, - batch_size=encoder_out.size( - 0)) - mask_shfit_chunk = self.encoder.overlap_chunk_cls.get_mask_shfit_chunk(None, device=encoder_out.device, - batch_size=encoder_out.size(0)) - encoder_out = encoder_out * mask_shfit_chunk - pre_acoustic_embeds, pre_token_length, pre_alphas, pre_peak_index = self.predictor(encoder_out, - None, - encoder_out_mask, - ignore_id=self.ignore_id, - mask_chunk_predictor=mask_chunk_predictor, - target_label_length=None, - ) - predictor_alignments, predictor_alignments_len = self.predictor.gen_frame_alignments(pre_alphas, - encoder_out_lens + 1 if self.predictor.tail_threshold > 0.0 else encoder_out_lens) - - scama_mask = None - if self.encoder.overlap_chunk_cls is not None and self.decoder_attention_chunk_type == 'chunk': - encoder_chunk_size = self.encoder.overlap_chunk_cls.chunk_size_pad_shift_cur - attention_chunk_center_bias = 0 - attention_chunk_size = encoder_chunk_size - decoder_att_look_back_factor = self.encoder.overlap_chunk_cls.decoder_att_look_back_factor_cur - mask_shift_att_chunk_decoder = self.encoder.overlap_chunk_cls. \ - get_mask_shift_att_chunk_decoder(None, - device=encoder_out.device, - batch_size=encoder_out.size(0) - ) - scama_mask = self.build_scama_mask_for_cross_attention_decoder_fn( - predictor_alignments=predictor_alignments, - encoder_sequence_length=encoder_out_lens, - chunk_size=1, - encoder_chunk_size=encoder_chunk_size, - attention_chunk_center_bias=attention_chunk_center_bias, - attention_chunk_size=attention_chunk_size, - attention_chunk_type=self.decoder_attention_chunk_type, - step=None, - predictor_mask_chunk_hopping=mask_chunk_predictor, - decoder_att_look_back_factor=decoder_att_look_back_factor, - mask_shift_att_chunk_decoder=mask_shift_att_chunk_decoder, - target_length=None, - is_training=self.training, - ) - self.scama_mask = scama_mask - - return pre_acoustic_embeds, pre_token_length, pre_alphas, pre_peak_index - - def calc_predictor_chunk(self, encoder_out, cache=None): - - pre_acoustic_embeds, pre_token_length = \ - self.predictor.forward_chunk(encoder_out, cache["encoder"]) - return pre_acoustic_embeds, pre_token_length - - def cal_decoder_with_predictor(self, encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens): - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, self.scama_mask - ) - decoder_out = decoder_outs[0] - decoder_out = torch.log_softmax(decoder_out, dim=-1) - return decoder_out, ys_pad_lens - - def cal_decoder_with_predictor_chunk(self, encoder_out, sematic_embeds, cache=None): - decoder_outs = self.decoder.forward_chunk( - encoder_out, sematic_embeds, cache["decoder"] - ) - decoder_out = decoder_outs - decoder_out = torch.log_softmax(decoder_out, dim=-1) - return decoder_out - - -class ParaformerBert(Paraformer): - """ - Author: Speech Lab of DAMO Academy, Alibaba Group - Paraformer2: advanced paraformer with LFMMI and bert for non-autoregressive end-to-end speech recognition - """ - - def __init__( - self, - vocab_size: int, - token_list: Union[Tuple[str, ...], List[str]], - frontend: Optional[AbsFrontend], - specaug: Optional[AbsSpecAug], - normalize: Optional[AbsNormalize], - encoder: AbsEncoder, - decoder: AbsDecoder, - ctc: CTC, - ctc_weight: float = 0.5, - interctc_weight: float = 0.0, - ignore_id: int = -1, - blank_id: int = 0, - sos: int = 1, - eos: int = 2, - lsm_weight: float = 0.0, - length_normalized_loss: bool = False, - report_cer: bool = True, - report_wer: bool = True, - sym_space: str = "", - sym_blank: str = "", - extract_feats_in_collect_stats: bool = True, - predictor=None, - predictor_weight: float = 0.0, - predictor_bias: int = 0, - sampling_ratio: float = 0.2, - embeds_id: int = 2, - embeds_loss_weight: float = 0.0, - embed_dims: int = 768, - preencoder: Optional[AbsPreEncoder] = None, - postencoder: Optional[AbsPostEncoder] = None, - ): - assert 0.0 <= ctc_weight <= 1.0, ctc_weight - assert 0.0 <= interctc_weight < 1.0, interctc_weight - - super().__init__( - vocab_size=vocab_size, - token_list=token_list, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - postencoder=postencoder, - decoder=decoder, - ctc=ctc, - ctc_weight=ctc_weight, - interctc_weight=interctc_weight, - ignore_id=ignore_id, - blank_id=blank_id, - sos=sos, - eos=eos, - lsm_weight=lsm_weight, - length_normalized_loss=length_normalized_loss, - report_cer=report_cer, - report_wer=report_wer, - sym_space=sym_space, - sym_blank=sym_blank, - extract_feats_in_collect_stats=extract_feats_in_collect_stats, - predictor=predictor, - predictor_weight=predictor_weight, - predictor_bias=predictor_bias, - sampling_ratio=sampling_ratio, - ) - self.decoder.embeds_id = embeds_id - decoder_attention_dim = self.decoder.attention_dim - self.pro_nn = torch.nn.Linear(decoder_attention_dim, embed_dims) - self.cos = torch.nn.CosineSimilarity(dim=-1, eps=1e-6) - self.embeds_loss_weight = embeds_loss_weight - self.length_normalized_loss = length_normalized_loss - - def _calc_embed_loss(self, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - embed: torch.Tensor = None, - embed_lengths: torch.Tensor = None, - embeds_outputs: torch.Tensor = None, - ): - embeds_outputs = self.pro_nn(embeds_outputs) - tgt_mask = (~make_pad_mask(ys_pad_lens, maxlen=ys_pad_lens.max())[:, :, None]).to(ys_pad.device) - embeds_outputs *= tgt_mask # b x l x d - embed *= tgt_mask # b x l x d - cos_loss = 1.0 - self.cos(embeds_outputs, embed) - cos_loss *= tgt_mask.squeeze(2) - if self.length_normalized_loss: - token_num_total = torch.sum(tgt_mask) - else: - token_num_total = tgt_mask.size()[0] - cos_loss_total = torch.sum(cos_loss) - cos_loss = cos_loss_total / token_num_total - # print("cos_loss: {}".format(cos_loss)) - return cos_loss - - def _calc_att_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - if self.predictor_bias == 1: - _, ys_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_pad_lens = ys_pad_lens + self.predictor_bias - pre_acoustic_embeds, pre_token_length, _, pre_peak_index = self.predictor(encoder_out, ys_pad, encoder_out_mask, - ignore_id=self.ignore_id) - - # 0. sampler - decoder_out_1st = None - if self.sampling_ratio > 0.0: - if self.step_cur < 2: - logging.info( - "enable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds, decoder_out_1st = self.sampler(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, - pre_acoustic_embeds) - else: - if self.step_cur < 2: - logging.info( - "disable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds = pre_acoustic_embeds - - # 1. Forward decoder - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - embeds_outputs = None - if len(decoder_outs) > 2: - embeds_outputs = decoder_outs[2] - - if decoder_out_1st is None: - decoder_out_1st = decoder_out - # 2. Compute attention loss - loss_att = self.criterion_att(decoder_out, ys_pad) - acc_att = th_accuracy( - decoder_out_1st.view(-1, self.vocab_size), - ys_pad, - ignore_label=self.ignore_id, - ) - loss_pre = self.criterion_pre(ys_pad_lens.type_as(pre_token_length), pre_token_length) - - # Compute cer/wer using attention-decoder - if self.training or self.error_calculator is None: - cer_att, wer_att = None, None - else: - ys_hat = decoder_out_1st.argmax(dim=-1) - cer_att, wer_att = self.error_calculator(ys_hat.cpu(), ys_pad.cpu()) - - return loss_att, acc_att, cer_att, wer_att, loss_pre, embeds_outputs - - def forward( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - embed: torch.Tensor = None, - embed_lengths: torch.Tensor = None, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - """Frontend + Encoder + Decoder + Calc loss - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - text: (Batch, Length) - text_lengths: (Batch,) - """ - assert text_lengths.dim() == 1, text_lengths.shape - # Check that batch_size is unified - assert ( - speech.shape[0] - == speech_lengths.shape[0] - == text.shape[0] - == text_lengths.shape[0] - ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) - batch_size = speech.shape[0] - self.step_cur += 1 - # for data-parallel - text = text[:, : text_lengths.max()] - speech = speech[:, :speech_lengths.max()] - if embed is not None: - embed = embed[:, :embed_lengths.max()] - - # 1. Encoder - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - loss_att, acc_att, cer_att, wer_att = None, None, None, None - loss_ctc, cer_ctc = None, None - loss_pre = 0.0 - cos_loss = 0.0 - stats = dict() - - # 1. CTC branch - if self.ctc_weight != 0.0: - loss_ctc, cer_ctc = self._calc_ctc_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # Collect CTC branch stats - stats["loss_ctc"] = loss_ctc.detach() if loss_ctc is not None else None - stats["cer_ctc"] = cer_ctc - - # Intermediate CTC (optional) - loss_interctc = 0.0 - if self.interctc_weight != 0.0 and intermediate_outs is not None: - for layer_idx, intermediate_out in intermediate_outs: - # we assume intermediate_out has the same length & padding - # as those of encoder_out - loss_ic, cer_ic = self._calc_ctc_loss( - intermediate_out, encoder_out_lens, text, text_lengths - ) - loss_interctc = loss_interctc + loss_ic - - # Collect Intermedaite CTC stats - stats["loss_interctc_layer{}".format(layer_idx)] = ( - loss_ic.detach() if loss_ic is not None else None - ) - stats["cer_interctc_layer{}".format(layer_idx)] = cer_ic - - loss_interctc = loss_interctc / len(intermediate_outs) - - # calculate whole encoder loss - loss_ctc = ( - 1 - self.interctc_weight - ) * loss_ctc + self.interctc_weight * loss_interctc - - # 2b. Attention decoder branch - if self.ctc_weight != 1.0: - - loss_ret = self._calc_att_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - loss_att, acc_att, cer_att, wer_att, loss_pre = loss_ret[0], loss_ret[1], loss_ret[2], loss_ret[3], \ - loss_ret[4] - embeds_outputs = None - if len(loss_ret) > 5: - embeds_outputs = loss_ret[5] - if embeds_outputs is not None: - cos_loss = self._calc_embed_loss(text, text_lengths, embed, embed_lengths, embeds_outputs) - - # 3. CTC-Att loss definition - if self.ctc_weight == 0.0: - loss = loss_att + loss_pre * self.predictor_weight + cos_loss * self.embeds_loss_weight - elif self.ctc_weight == 1.0: - loss = loss_ctc - else: - loss = self.ctc_weight * loss_ctc + ( - 1 - self.ctc_weight) * loss_att + loss_pre * self.predictor_weight + cos_loss * self.embeds_loss_weight - - # Collect Attn branch stats - stats["loss_att"] = loss_att.detach() if loss_att is not None else None - stats["acc"] = acc_att - stats["cer"] = cer_att - stats["wer"] = wer_att - stats["loss_pre"] = loss_pre.detach().cpu() if loss_pre > 0.0 else None - stats["cos_loss"] = cos_loss.detach().cpu() if cos_loss > 0.0 else None - - stats["loss"] = torch.clone(loss.detach()) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - if self.length_normalized_loss: - batch_size = int((text_lengths + self.predictor_bias).sum()) - - loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) - return loss, stats, weight - - -class BiCifParaformer(Paraformer): - """ - Paraformer model with an extra cif predictor - to conduct accurate timestamp prediction - """ - - def __init__( - self, - vocab_size: int, - token_list: Union[Tuple[str, ...], List[str]], - frontend: Optional[AbsFrontend], - specaug: Optional[AbsSpecAug], - normalize: Optional[AbsNormalize], - encoder: AbsEncoder, - decoder: AbsDecoder, - ctc: CTC, - ctc_weight: float = 0.5, - interctc_weight: float = 0.0, - ignore_id: int = -1, - blank_id: int = 0, - sos: int = 1, - eos: int = 2, - lsm_weight: float = 0.0, - length_normalized_loss: bool = False, - report_cer: bool = True, - report_wer: bool = True, - sym_space: str = "", - sym_blank: str = "", - extract_feats_in_collect_stats: bool = True, - predictor=None, - predictor_weight: float = 0.0, - predictor_bias: int = 0, - sampling_ratio: float = 0.2, - preencoder: Optional[AbsPreEncoder] = None, - postencoder: Optional[AbsPostEncoder] = None, - ): - assert 0.0 <= ctc_weight <= 1.0, ctc_weight - assert 0.0 <= interctc_weight < 1.0, interctc_weight - - super().__init__( - vocab_size=vocab_size, - token_list=token_list, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - postencoder=postencoder, - decoder=decoder, - ctc=ctc, - ctc_weight=ctc_weight, - interctc_weight=interctc_weight, - ignore_id=ignore_id, - blank_id=blank_id, - sos=sos, - eos=eos, - lsm_weight=lsm_weight, - length_normalized_loss=length_normalized_loss, - report_cer=report_cer, - report_wer=report_wer, - sym_space=sym_space, - sym_blank=sym_blank, - extract_feats_in_collect_stats=extract_feats_in_collect_stats, - predictor=predictor, - predictor_weight=predictor_weight, - predictor_bias=predictor_bias, - sampling_ratio=sampling_ratio, - ) - assert isinstance(self.predictor, CifPredictorV3), "BiCifParaformer should use CIFPredictorV3" - - def _calc_pre2_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - if self.predictor_bias == 1: - _, ys_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_pad_lens = ys_pad_lens + self.predictor_bias - _, _, _, _, pre_token_length2 = self.predictor(encoder_out, ys_pad, encoder_out_mask, ignore_id=self.ignore_id) - - # loss_pre = self.criterion_pre(ys_pad_lens.type_as(pre_token_length), pre_token_length) - loss_pre2 = self.criterion_pre(ys_pad_lens.type_as(pre_token_length2), pre_token_length2) - - return loss_pre2 - - def _calc_att_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - if self.predictor_bias == 1: - _, ys_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_pad_lens = ys_pad_lens + self.predictor_bias - pre_acoustic_embeds, pre_token_length, _, pre_peak_index, _ = self.predictor(encoder_out, ys_pad, - encoder_out_mask, - ignore_id=self.ignore_id) - - # 0. sampler - decoder_out_1st = None - if self.sampling_ratio > 0.0: - if self.step_cur < 2: - logging.info("enable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds, decoder_out_1st = self.sampler(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, - pre_acoustic_embeds) - else: - if self.step_cur < 2: - logging.info("disable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds = pre_acoustic_embeds - - # 1. Forward decoder - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - - if decoder_out_1st is None: - decoder_out_1st = decoder_out - # 2. Compute attention loss - loss_att = self.criterion_att(decoder_out, ys_pad) - acc_att = th_accuracy( - decoder_out_1st.view(-1, self.vocab_size), - ys_pad, - ignore_label=self.ignore_id, - ) - loss_pre = self.criterion_pre(ys_pad_lens.type_as(pre_token_length), pre_token_length) - - # Compute cer/wer using attention-decoder - if self.training or self.error_calculator is None: - cer_att, wer_att = None, None - else: - ys_hat = decoder_out_1st.argmax(dim=-1) - cer_att, wer_att = self.error_calculator(ys_hat.cpu(), ys_pad.cpu()) - - return loss_att, acc_att, cer_att, wer_att, loss_pre - - def calc_predictor(self, encoder_out, encoder_out_lens): - - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - pre_acoustic_embeds, pre_token_length, alphas, pre_peak_index, pre_token_length2 = self.predictor(encoder_out, - None, - encoder_out_mask, - ignore_id=self.ignore_id) - return pre_acoustic_embeds, pre_token_length, alphas, pre_peak_index - - def calc_predictor_timestamp(self, encoder_out, encoder_out_lens, token_num): - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - ds_alphas, ds_cif_peak, us_alphas, us_peaks = self.predictor.get_upsample_timestamp(encoder_out, - encoder_out_mask, - token_num) - return ds_alphas, ds_cif_peak, us_alphas, us_peaks - - def forward( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - """Frontend + Encoder + Decoder + Calc loss - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - text: (Batch, Length) - text_lengths: (Batch,) - """ - assert text_lengths.dim() == 1, text_lengths.shape - # Check that batch_size is unified - assert ( - speech.shape[0] - == speech_lengths.shape[0] - == text.shape[0] - == text_lengths.shape[0] - ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) - batch_size = speech.shape[0] - self.step_cur += 1 - # for data-parallel - text = text[:, : text_lengths.max()] - speech = speech[:, :speech_lengths.max()] - - # 1. Encoder - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - loss_att, acc_att, cer_att, wer_att = None, None, None, None - loss_ctc, cer_ctc = None, None - loss_pre = None - stats = dict() - - # 1. CTC branch - if self.ctc_weight != 0.0: - loss_ctc, cer_ctc = self._calc_ctc_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # Collect CTC branch stats - stats["loss_ctc"] = loss_ctc.detach() if loss_ctc is not None else None - stats["cer_ctc"] = cer_ctc - - # Intermediate CTC (optional) - loss_interctc = 0.0 - if self.interctc_weight != 0.0 and intermediate_outs is not None: - for layer_idx, intermediate_out in intermediate_outs: - # we assume intermediate_out has the same length & padding - # as those of encoder_out - loss_ic, cer_ic = self._calc_ctc_loss( - intermediate_out, encoder_out_lens, text, text_lengths - ) - loss_interctc = loss_interctc + loss_ic - - # Collect Intermedaite CTC stats - stats["loss_interctc_layer{}".format(layer_idx)] = ( - loss_ic.detach() if loss_ic is not None else None - ) - stats["cer_interctc_layer{}".format(layer_idx)] = cer_ic - - loss_interctc = loss_interctc / len(intermediate_outs) - - # calculate whole encoder loss - loss_ctc = ( - 1 - self.interctc_weight - ) * loss_ctc + self.interctc_weight * loss_interctc - - # 2b. Attention decoder branch - if self.ctc_weight != 1.0: - loss_att, acc_att, cer_att, wer_att, loss_pre = self._calc_att_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - loss_pre2 = self._calc_pre2_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # 3. CTC-Att loss definition - if self.ctc_weight == 0.0: - loss = loss_att + loss_pre * self.predictor_weight + loss_pre2 * self.predictor_weight * 0.5 - elif self.ctc_weight == 1.0: - loss = loss_ctc - else: - loss = self.ctc_weight * loss_ctc + ( - 1 - self.ctc_weight) * loss_att + loss_pre * self.predictor_weight + loss_pre2 * self.predictor_weight * 0.5 - - # Collect Attn branch stats - stats["loss_att"] = loss_att.detach() if loss_att is not None else None - stats["acc"] = acc_att - stats["cer"] = cer_att - stats["wer"] = wer_att - stats["loss_pre"] = loss_pre.detach().cpu() if loss_pre is not None else None - stats["loss_pre2"] = loss_pre2.detach().cpu() - - stats["loss"] = torch.clone(loss.detach()) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - if self.length_normalized_loss: - batch_size = int((text_lengths + self.predictor_bias).sum()) - - loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) - return loss, stats, weight - - -class ContextualParaformer(Paraformer): - """ - Paraformer model with contextual hotword - """ - - def __init__( - self, - vocab_size: int, - token_list: Union[Tuple[str, ...], List[str]], - frontend: Optional[AbsFrontend], - specaug: Optional[AbsSpecAug], - normalize: Optional[AbsNormalize], - encoder: AbsEncoder, - decoder: AbsDecoder, - ctc: CTC, - ctc_weight: float = 0.5, - interctc_weight: float = 0.0, - ignore_id: int = -1, - blank_id: int = 0, - sos: int = 1, - eos: int = 2, - lsm_weight: float = 0.0, - length_normalized_loss: bool = False, - report_cer: bool = True, - report_wer: bool = True, - sym_space: str = "", - sym_blank: str = "", - extract_feats_in_collect_stats: bool = True, - predictor=None, - predictor_weight: float = 0.0, - predictor_bias: int = 0, - sampling_ratio: float = 0.2, - min_hw_length: int = 2, - max_hw_length: int = 4, - sample_rate: float = 0.6, - batch_rate: float = 0.5, - double_rate: float = -1.0, - target_buffer_length: int = -1, - inner_dim: int = 256, - bias_encoder_type: str = 'lstm', - label_bracket: bool = False, - use_decoder_embedding: bool = False, - preencoder: Optional[AbsPreEncoder] = None, - postencoder: Optional[AbsPostEncoder] = None, - ): - assert 0.0 <= ctc_weight <= 1.0, ctc_weight - assert 0.0 <= interctc_weight < 1.0, interctc_weight - - super().__init__( - vocab_size=vocab_size, - token_list=token_list, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - postencoder=postencoder, - decoder=decoder, - ctc=ctc, - ctc_weight=ctc_weight, - interctc_weight=interctc_weight, - ignore_id=ignore_id, - blank_id=blank_id, - sos=sos, - eos=eos, - lsm_weight=lsm_weight, - length_normalized_loss=length_normalized_loss, - report_cer=report_cer, - report_wer=report_wer, - sym_space=sym_space, - sym_blank=sym_blank, - extract_feats_in_collect_stats=extract_feats_in_collect_stats, - predictor=predictor, - predictor_weight=predictor_weight, - predictor_bias=predictor_bias, - sampling_ratio=sampling_ratio, - ) - - if bias_encoder_type == 'lstm': - logging.warning("enable bias encoder sampling and contextual training") - self.bias_encoder = torch.nn.LSTM(inner_dim, inner_dim, 1, batch_first=True, dropout=0) - self.bias_embed = torch.nn.Embedding(vocab_size, inner_dim) - else: - logging.error("Unsupport bias encoder type") - - self.min_hw_length = min_hw_length - self.max_hw_length = max_hw_length - self.sample_rate = sample_rate - self.batch_rate = batch_rate - self.target_buffer_length = target_buffer_length - self.double_rate = double_rate - - if self.target_buffer_length > 0: - self.hotword_buffer = None - self.length_record = [] - self.current_buffer_length = 0 - self.use_decoder_embedding = use_decoder_embedding - - def forward( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - """Frontend + Encoder + Decoder + Calc loss - Args: - speech: (Batch, Length, ...) - speech_lengths: (Batch, ) - text: (Batch, Length) - text_lengths: (Batch,) - """ - assert text_lengths.dim() == 1, text_lengths.shape - # Check that batch_size is unified - assert ( - speech.shape[0] - == speech_lengths.shape[0] - == text.shape[0] - == text_lengths.shape[0] - ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) - batch_size = speech.shape[0] - self.step_cur += 1 - # for data-parallel - text = text[:, : text_lengths.max()] - speech = speech[:, :speech_lengths.max()] - - # 1. Encoder - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) - intermediate_outs = None - if isinstance(encoder_out, tuple): - intermediate_outs = encoder_out[1] - encoder_out = encoder_out[0] - - loss_att, acc_att, cer_att, wer_att = None, None, None, None - loss_ctc, cer_ctc = None, None - loss_pre = None - stats = dict() - - # 1. CTC branch - if self.ctc_weight != 0.0: - loss_ctc, cer_ctc = self._calc_ctc_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # Collect CTC branch stats - stats["loss_ctc"] = loss_ctc.detach() if loss_ctc is not None else None - stats["cer_ctc"] = cer_ctc - - # Intermediate CTC (optional) - loss_interctc = 0.0 - if self.interctc_weight != 0.0 and intermediate_outs is not None: - for layer_idx, intermediate_out in intermediate_outs: - # we assume intermediate_out has the same length & padding - # as those of encoder_out - loss_ic, cer_ic = self._calc_ctc_loss( - intermediate_out, encoder_out_lens, text, text_lengths - ) - loss_interctc = loss_interctc + loss_ic - - # Collect Intermedaite CTC stats - stats["loss_interctc_layer{}".format(layer_idx)] = ( - loss_ic.detach() if loss_ic is not None else None - ) - stats["cer_interctc_layer{}".format(layer_idx)] = cer_ic - - loss_interctc = loss_interctc / len(intermediate_outs) - - # calculate whole encoder loss - loss_ctc = ( - 1 - self.interctc_weight - ) * loss_ctc + self.interctc_weight * loss_interctc - - # 2b. Attention decoder branch - if self.ctc_weight != 1.0: - loss_att, acc_att, cer_att, wer_att, loss_pre = self._calc_att_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - - # 3. CTC-Att loss definition - if self.ctc_weight == 0.0: - loss = loss_att + loss_pre * self.predictor_weight - elif self.ctc_weight == 1.0: - loss = loss_ctc - else: - loss = self.ctc_weight * loss_ctc + (1 - self.ctc_weight) * loss_att + loss_pre * self.predictor_weight - - # Collect Attn branch stats - stats["loss_att"] = loss_att.detach() if loss_att is not None else None - stats["acc"] = acc_att - stats["cer"] = cer_att - stats["wer"] = wer_att - stats["loss_pre"] = loss_pre.detach().cpu() if loss_pre is not None else None - - stats["loss"] = torch.clone(loss.detach()) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - if self.length_normalized_loss: - batch_size = int((text_lengths + self.predictor_bias).sum()) - - loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) - return loss, stats, weight - - def _sample_hot_word(self, ys_pad, ys_pad_lens): - hw_list = [torch.Tensor([0]).long().to(ys_pad.device)] - hw_lengths = [0] # this length is actually for indice, so -1 - for i, length in enumerate(ys_pad_lens): - if length < 2: - continue - if length > self.min_hw_length + self.max_hw_length + 2 and random.random() < self.double_rate: - # sample double hotword - _max_hw_length = min(self.max_hw_length, length // 2) - # first hotword - start1 = random.randint(0, length // 3) - end1 = random.randint(start1 + self.min_hw_length - 1, start1 + _max_hw_length - 1) - hw_tokens1 = ys_pad[i][start1:end1 + 1] - hw_lengths.append(len(hw_tokens1) - 1) - hw_list.append(hw_tokens1) - # second hotword - start2 = random.randint(end1 + 1, length - self.min_hw_length) - end2 = random.randint(min(length - 1, start2 + self.min_hw_length - 1), - min(length - 1, start2 + self.max_hw_length - 1)) - hw_tokens2 = ys_pad[i][start2:end2 + 1] - hw_lengths.append(len(hw_tokens2) - 1) - hw_list.append(hw_tokens2) - continue - if random.random() < self.sample_rate: - if length == 2: - hw_tokens = ys_pad[i][:2] - hw_lengths.append(1) - hw_list.append(hw_tokens) - else: - start = random.randint(0, length - self.min_hw_length) - end = random.randint(min(length - 1, start + self.min_hw_length - 1), - min(length - 1, start + self.max_hw_length - 1)) + 1 - # print(start, end) - hw_tokens = ys_pad[i][start:end] - hw_lengths.append(len(hw_tokens) - 1) - hw_list.append(hw_tokens) - # padding - hw_list_pad = pad_list(hw_list, 0) - if self.use_decoder_embedding: - hw_embed = self.decoder.embed(hw_list_pad) - else: - hw_embed = self.bias_embed(hw_list_pad) - hw_embed, (_, _) = self.bias_encoder(hw_embed) - _ind = np.arange(0, len(hw_list)).tolist() - # update self.hotword_buffer, throw a part if oversize - selected = hw_embed[_ind, hw_lengths] - if self.target_buffer_length > 0: - _b = selected.shape[0] - if self.hotword_buffer is None: - self.hotword_buffer = selected - self.length_record.append(selected.shape[0]) - self.current_buffer_length = _b - elif self.current_buffer_length + _b < self.target_buffer_length: - self.hotword_buffer = torch.cat([self.hotword_buffer.detach(), selected], dim=0) - self.current_buffer_length += _b - selected = self.hotword_buffer - else: - self.hotword_buffer = torch.cat([self.hotword_buffer.detach(), selected], dim=0) - random_throw = random.randint(self.target_buffer_length // 2, self.target_buffer_length) + 10 - self.hotword_buffer = self.hotword_buffer[-1 * random_throw:] - selected = self.hotword_buffer - self.current_buffer_length = selected.shape[0] - return selected.squeeze(0).repeat(ys_pad.shape[0], 1, 1).to(ys_pad.device) - - def sampler(self, encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, pre_acoustic_embeds, contextual_info): - - tgt_mask = (~make_pad_mask(ys_pad_lens, maxlen=ys_pad_lens.max())[:, :, None]).to(ys_pad.device) - ys_pad = ys_pad * tgt_mask[:, :, 0] - if self.share_embedding: - ys_pad_embed = self.decoder.output_layer.weight[ys_pad] - else: - ys_pad_embed = self.decoder.embed(ys_pad) - with torch.no_grad(): - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, pre_acoustic_embeds, ys_pad_lens, contextual_info=contextual_info - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - pred_tokens = decoder_out.argmax(-1) - nonpad_positions = ys_pad.ne(self.ignore_id) - seq_lens = (nonpad_positions).sum(1) - same_num = ((pred_tokens == ys_pad) & nonpad_positions).sum(1) - input_mask = torch.ones_like(nonpad_positions) - bsz, seq_len = ys_pad.size() - for li in range(bsz): - target_num = (((seq_lens[li] - same_num[li].sum()).float()) * self.sampling_ratio).long() - if target_num > 0: - input_mask[li].scatter_(dim=0, index=torch.randperm(seq_lens[li])[:target_num].cuda(), value=0) - input_mask = input_mask.eq(1) - input_mask = input_mask.masked_fill(~nonpad_positions, False) - input_mask_expand_dim = input_mask.unsqueeze(2).to(pre_acoustic_embeds.device) - - sematic_embeds = pre_acoustic_embeds.masked_fill(~input_mask_expand_dim, 0) + ys_pad_embed.masked_fill( - input_mask_expand_dim, 0) - return sematic_embeds * tgt_mask, decoder_out * tgt_mask - - def _calc_att_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( - encoder_out.device) - if self.predictor_bias == 1: - _, ys_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_pad_lens = ys_pad_lens + self.predictor_bias - pre_acoustic_embeds, pre_token_length, _, pre_peak_index = self.predictor(encoder_out, ys_pad, - encoder_out_mask, - ignore_id=self.ignore_id) - - # sample hot word - contextual_info = self._sample_hot_word(ys_pad, ys_pad_lens) - - # 0. sampler - decoder_out_1st = None - if self.sampling_ratio > 0.0: - if self.step_cur < 2: - logging.info("enable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds, decoder_out_1st = self.sampler(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, - pre_acoustic_embeds, contextual_info) - else: - if self.step_cur < 2: - logging.info("disable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) - sematic_embeds = pre_acoustic_embeds - - # 1. Forward decoder - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=contextual_info - ) - decoder_out, _ = decoder_outs[0], decoder_outs[1] - - if decoder_out_1st is None: - decoder_out_1st = decoder_out - # 2. Compute attention loss - loss_att = self.criterion_att(decoder_out, ys_pad) - acc_att = th_accuracy( - decoder_out_1st.view(-1, self.vocab_size), - ys_pad, - ignore_label=self.ignore_id, - ) - loss_pre = self.criterion_pre(ys_pad_lens.type_as(pre_token_length), pre_token_length) - - # Compute cer/wer using attention-decoder - if self.training or self.error_calculator is None: - cer_att, wer_att = None, None - else: - ys_hat = decoder_out_1st.argmax(dim=-1) - cer_att, wer_att = self.error_calculator(ys_hat.cpu(), ys_pad.cpu()) - - return loss_att, acc_att, cer_att, wer_att, loss_pre - - def cal_decoder_with_predictor(self, encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, hw_list=None, - clas_scale=1.0): - if hw_list is None: - # default hotword list - hw_list = [torch.Tensor([self.sos]).long().to(encoder_out.device)] # empty hotword list - hw_list_pad = pad_list(hw_list, 0) - if self.use_decoder_embedding: - hw_embed = self.decoder.embed(hw_list_pad) - else: - hw_embed = self.bias_embed(hw_list_pad) - _, (h_n, _) = self.bias_encoder(hw_embed) - contextual_info = h_n.squeeze(0).repeat(encoder_out.shape[0], 1, 1) - else: - hw_lengths = [len(i) for i in hw_list] - hw_list_pad = pad_list([torch.Tensor(i).long() for i in hw_list], 0).to(encoder_out.device) - if self.use_decoder_embedding: - hw_embed = self.decoder.embed(hw_list_pad) - else: - hw_embed = self.bias_embed(hw_list_pad) - hw_embed = torch.nn.utils.rnn.pack_padded_sequence(hw_embed, hw_lengths, batch_first=True, - enforce_sorted=False) - _, (h_n, _) = self.bias_encoder(hw_embed) - # hw_embed, _ = torch.nn.utils.rnn.pad_packed_sequence(hw_embed, batch_first=True) - contextual_info = h_n.squeeze(0).repeat(encoder_out.shape[0], 1, 1) - decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=contextual_info - ) - decoder_out = decoder_outs[0] - decoder_out = torch.log_softmax(decoder_out, dim=-1) - return decoder_out, ys_pad_lens - - def gen_clas_tf2torch_map_dict(self): - tensor_name_prefix_torch = "bias_encoder" - tensor_name_prefix_tf = "seq2seq/clas_charrnn" - - tensor_name_prefix_torch_emb = "bias_embed" - tensor_name_prefix_tf_emb = "seq2seq" - - map_dict_local = { - # in lstm - "{}.weight_ih_l0".format(tensor_name_prefix_torch): - {"name": "{}/rnn/lstm_cell/kernel".format(tensor_name_prefix_tf), - "squeeze": None, - "transpose": (1, 0), - "slice": (0, 512), - "unit_k": 512, - }, # (1024, 2048),(2048,512) - "{}.weight_hh_l0".format(tensor_name_prefix_torch): - {"name": "{}/rnn/lstm_cell/kernel".format(tensor_name_prefix_tf), - "squeeze": None, - "transpose": (1, 0), - "slice": (512, 1024), - "unit_k": 512, - }, # (1024, 2048),(2048,512) - "{}.bias_ih_l0".format(tensor_name_prefix_torch): - {"name": "{}/rnn/lstm_cell/bias".format(tensor_name_prefix_tf), - "squeeze": None, - "transpose": None, - "scale": 0.5, - "unit_b": 512, - }, # (2048,),(2048,) - "{}.bias_hh_l0".format(tensor_name_prefix_torch): - {"name": "{}/rnn/lstm_cell/bias".format(tensor_name_prefix_tf), - "squeeze": None, - "transpose": None, - "scale": 0.5, - "unit_b": 512, - }, # (2048,),(2048,) - - # in embed - "{}.weight".format(tensor_name_prefix_torch_emb): - {"name": "{}/contextual_encoder/w_char_embs".format(tensor_name_prefix_tf_emb), - "squeeze": None, - "transpose": None, - }, # (4235,256),(4235,256) - } - return map_dict_local - - def clas_convert_tf2torch(self, - var_dict_tf, - var_dict_torch): - map_dict = self.gen_clas_tf2torch_map_dict() - var_dict_torch_update = dict() - for name in sorted(var_dict_torch.keys(), reverse=False): - names = name.split('.') - if names[0] == "bias_encoder": - name_q = name - if name_q in map_dict.keys(): - name_v = map_dict[name_q]["name"] - name_tf = name_v - data_tf = var_dict_tf[name_tf] - if map_dict[name_q].get("unit_k") is not None: - dim = map_dict[name_q]["unit_k"] - i = data_tf[:, 0:dim].copy() - f = data_tf[:, dim:2 * dim].copy() - o = data_tf[:, 2 * dim:3 * dim].copy() - g = data_tf[:, 3 * dim:4 * dim].copy() - data_tf = np.concatenate([i, o, f, g], axis=1) - if map_dict[name_q].get("unit_b") is not None: - dim = map_dict[name_q]["unit_b"] - i = data_tf[0:dim].copy() - f = data_tf[dim:2 * dim].copy() - o = data_tf[2 * dim:3 * dim].copy() - g = data_tf[3 * dim:4 * dim].copy() - data_tf = np.concatenate([i, o, f, g], axis=0) - if map_dict[name_q]["squeeze"] is not None: - data_tf = np.squeeze(data_tf, axis=map_dict[name_q]["squeeze"]) - if map_dict[name_q].get("slice") is not None: - data_tf = data_tf[map_dict[name_q]["slice"][0]:map_dict[name_q]["slice"][1]] - if map_dict[name_q].get("scale") is not None: - data_tf = data_tf * map_dict[name_q]["scale"] - if map_dict[name_q]["transpose"] is not None: - data_tf = np.transpose(data_tf, map_dict[name_q]["transpose"]) - data_tf = torch.from_numpy(data_tf).type(torch.float32).to("cpu") - assert var_dict_torch[name].size() == data_tf.size(), "{}, {}, {} != {}".format(name, name_tf, - var_dict_torch[ - name].size(), - data_tf.size()) - var_dict_torch_update[name] = data_tf - logging.info( - "torch tensor: {}, {}, loading from tf tensor: {}, {}".format(name, data_tf.size(), name_v, - var_dict_tf[name_tf].shape)) - elif names[0] == "bias_embed": - name_tf = map_dict[name]["name"] - data_tf = var_dict_tf[name_tf] - if map_dict[name]["squeeze"] is not None: - data_tf = np.squeeze(data_tf, axis=map_dict[name]["squeeze"]) - if map_dict[name]["transpose"] is not None: - data_tf = np.transpose(data_tf, map_dict[name]["transpose"]) - data_tf = torch.from_numpy(data_tf).type(torch.float32).to("cpu") - assert var_dict_torch[name].size() == data_tf.size(), "{}, {}, {} != {}".format(name, name_tf, - var_dict_torch[ - name].size(), - data_tf.size()) - var_dict_torch_update[name] = data_tf - logging.info( - "torch tensor: {}, {}, loading from tf tensor: {}, {}".format(name, data_tf.size(), name_tf, - var_dict_tf[name_tf].shape)) - - return var_dict_torch_update \ No newline at end of file diff --git a/funasr/models/e2e_asr_transducer.py b/funasr/models/e2e_asr_transducer.py deleted file mode 100644 index bffd54d1e..000000000 --- a/funasr/models/e2e_asr_transducer.py +++ /dev/null @@ -1,993 +0,0 @@ -"""ESPnet2 ASR Transducer model.""" - -import logging -from contextlib import contextmanager -from typing import Dict, List, Optional, Tuple, Union - -import torch -from packaging.version import parse as V -from funasr.losses.label_smoothing_loss import ( - LabelSmoothingLoss, # noqa: H301 -) -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.models.decoder.rnnt_decoder import RNNTDecoder -from funasr.models.decoder.abs_decoder import AbsDecoder as AbsAttDecoder -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.joint_net.joint_network import JointNetwork -from funasr.modules.nets_utils import get_transducer_task_io -from funasr.modules.nets_utils import th_accuracy -from funasr.modules.add_sos_eos import add_sos_eos -from funasr.layers.abs_normalize import AbsNormalize -from funasr.torch_utils.device_funcs import force_gatherable -from funasr.models.base_model import FunASRModel - -if V(torch.__version__) >= V("1.6.0"): - from torch.cuda.amp import autocast -else: - - @contextmanager - def autocast(enabled=True): - yield - - -class TransducerModel(FunASRModel): - """ESPnet2ASRTransducerModel module definition. - - Args: - vocab_size: Size of complete vocabulary (w/ EOS and blank included). - token_list: List of token - frontend: Frontend module. - specaug: SpecAugment module. - normalize: Normalization module. - encoder: Encoder module. - decoder: Decoder module. - joint_network: Joint Network module. - transducer_weight: Weight of the Transducer loss. - fastemit_lambda: FastEmit lambda value. - auxiliary_ctc_weight: Weight of auxiliary CTC loss. - auxiliary_ctc_dropout_rate: Dropout rate for auxiliary CTC loss inputs. - auxiliary_lm_loss_weight: Weight of auxiliary LM loss. - auxiliary_lm_loss_smoothing: Smoothing rate for LM loss' label smoothing. - ignore_id: Initial padding ID. - sym_space: Space symbol. - sym_blank: Blank Symbol - report_cer: Whether to report Character Error Rate during validation. - report_wer: Whether to report Word Error Rate during validation. - extract_feats_in_collect_stats: Whether to use extract_feats stats collection. - - """ - - def __init__( - self, - vocab_size: int, - token_list: Union[Tuple[str, ...], List[str]], - frontend: Optional[AbsFrontend], - specaug: Optional[AbsSpecAug], - normalize: Optional[AbsNormalize], - encoder: AbsEncoder, - decoder: RNNTDecoder, - joint_network: JointNetwork, - att_decoder: Optional[AbsAttDecoder] = None, - transducer_weight: float = 1.0, - fastemit_lambda: float = 0.0, - auxiliary_ctc_weight: float = 0.0, - auxiliary_ctc_dropout_rate: float = 0.0, - auxiliary_lm_loss_weight: float = 0.0, - auxiliary_lm_loss_smoothing: float = 0.0, - ignore_id: int = -1, - sym_space: str = "", - sym_blank: str = "", - report_cer: bool = True, - report_wer: bool = True, - extract_feats_in_collect_stats: bool = True, - ) -> None: - """Construct an ESPnetASRTransducerModel object.""" - super().__init__() - - # The following labels ID are reserved: 0 (blank) and vocab_size - 1 (sos/eos) - self.blank_id = 0 - self.vocab_size = vocab_size - self.ignore_id = ignore_id - self.token_list = token_list.copy() - - self.sym_space = sym_space - self.sym_blank = sym_blank - - self.frontend = frontend - self.specaug = specaug - self.normalize = normalize - - self.encoder = encoder - self.decoder = decoder - self.joint_network = joint_network - - self.criterion_transducer = None - self.error_calculator = None - - self.use_auxiliary_ctc = auxiliary_ctc_weight > 0 - self.use_auxiliary_lm_loss = auxiliary_lm_loss_weight > 0 - - if self.use_auxiliary_ctc: - self.ctc_lin = torch.nn.Linear(encoder.output_size(), vocab_size) - self.ctc_dropout_rate = auxiliary_ctc_dropout_rate - - if self.use_auxiliary_lm_loss: - self.lm_lin = torch.nn.Linear(decoder.output_size, vocab_size) - self.lm_loss_smoothing = auxiliary_lm_loss_smoothing - - self.transducer_weight = transducer_weight - self.fastemit_lambda = fastemit_lambda - - self.auxiliary_ctc_weight = auxiliary_ctc_weight - self.auxiliary_lm_loss_weight = auxiliary_lm_loss_weight - - self.report_cer = report_cer - self.report_wer = report_wer - - self.extract_feats_in_collect_stats = extract_feats_in_collect_stats - - def forward( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - **kwargs, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - """Forward architecture and compute loss(es). - - Args: - speech: Speech sequences. (B, S) - speech_lengths: Speech sequences lengths. (B,) - text: Label ID sequences. (B, L) - text_lengths: Label ID sequences lengths. (B,) - kwargs: Contains "utts_id". - - Return: - loss: Main loss value. - stats: Task statistics. - weight: Task weights. - - """ - assert text_lengths.dim() == 1, text_lengths.shape - assert ( - speech.shape[0] - == speech_lengths.shape[0] - == text.shape[0] - == text_lengths.shape[0] - ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) - - batch_size = speech.shape[0] - text = text[:, : text_lengths.max()] - - # 1. Encoder - encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) - if hasattr(self.encoder, 'overlap_chunk_cls') and self.encoder.overlap_chunk_cls is not None: - encoder_out, encoder_out_lens = self.encoder.overlap_chunk_cls.remove_chunk(encoder_out, encoder_out_lens, - chunk_outs=None) - # 2. Transducer-related I/O preparation - decoder_in, target, t_len, u_len = get_transducer_task_io( - text, - encoder_out_lens, - ignore_id=self.ignore_id, - ) - - # 3. Decoder - self.decoder.set_device(encoder_out.device) - decoder_out = self.decoder(decoder_in, u_len) - - # 4. Joint Network - joint_out = self.joint_network( - encoder_out.unsqueeze(2), decoder_out.unsqueeze(1) - ) - - # 5. Losses - loss_trans, cer_trans, wer_trans = self._calc_transducer_loss( - encoder_out, - joint_out, - target, - t_len, - u_len, - ) - - loss_ctc, loss_lm = 0.0, 0.0 - - if self.use_auxiliary_ctc: - loss_ctc = self._calc_ctc_loss( - encoder_out, - target, - t_len, - u_len, - ) - - if self.use_auxiliary_lm_loss: - loss_lm = self._calc_lm_loss(decoder_out, target) - - loss = ( - self.transducer_weight * loss_trans - + self.auxiliary_ctc_weight * loss_ctc - + self.auxiliary_lm_loss_weight * loss_lm - ) - - stats = dict( - loss=loss.detach(), - loss_transducer=loss_trans.detach(), - aux_ctc_loss=loss_ctc.detach() if loss_ctc > 0.0 else None, - aux_lm_loss=loss_lm.detach() if loss_lm > 0.0 else None, - cer_transducer=cer_trans, - wer_transducer=wer_trans, - ) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) - - return loss, stats, weight - - def collect_feats( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - **kwargs, - ) -> Dict[str, torch.Tensor]: - """Collect features sequences and features lengths sequences. - - Args: - speech: Speech sequences. (B, S) - speech_lengths: Speech sequences lengths. (B,) - text: Label ID sequences. (B, L) - text_lengths: Label ID sequences lengths. (B,) - kwargs: Contains "utts_id". - - Return: - {}: "feats": Features sequences. (B, T, D_feats), - "feats_lengths": Features sequences lengths. (B,) - - """ - if self.extract_feats_in_collect_stats: - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - else: - # Generate dummy stats if extract_feats_in_collect_stats is False - logging.warning( - "Generating dummy stats for feats and feats_lengths, " - "because encoder_conf.extract_feats_in_collect_stats is " - f"{self.extract_feats_in_collect_stats}" - ) - - feats, feats_lengths = speech, speech_lengths - - return {"feats": feats, "feats_lengths": feats_lengths} - - def encode( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Encoder speech sequences. - - Args: - speech: Speech sequences. (B, S) - speech_lengths: Speech sequences lengths. (B,) - - Return: - encoder_out: Encoder outputs. (B, T, D_enc) - encoder_out_lens: Encoder outputs lengths. (B,) - - """ - with autocast(False): - # 1. Extract feats - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - - # 2. Data augmentation - if self.specaug is not None and self.training: - feats, feats_lengths = self.specaug(feats, feats_lengths) - - # 3. Normalization for feature: e.g. Global-CMVN, Utterance-CMVN - if self.normalize is not None: - feats, feats_lengths = self.normalize(feats, feats_lengths) - - # 4. Forward encoder - encoder_out, encoder_out_lens, _ = self.encoder(feats, feats_lengths) - - assert encoder_out.size(0) == speech.size(0), ( - encoder_out.size(), - speech.size(0), - ) - assert encoder_out.size(1) <= encoder_out_lens.max(), ( - encoder_out.size(), - encoder_out_lens.max(), - ) - - return encoder_out, encoder_out_lens - - def _extract_feats( - self, speech: torch.Tensor, speech_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Extract features sequences and features sequences lengths. - - Args: - speech: Speech sequences. (B, S) - speech_lengths: Speech sequences lengths. (B,) - - Return: - feats: Features sequences. (B, T, D_feats) - feats_lengths: Features sequences lengths. (B,) - - """ - assert speech_lengths.dim() == 1, speech_lengths.shape - - # for data-parallel - speech = speech[:, : speech_lengths.max()] - - if self.frontend is not None: - feats, feats_lengths = self.frontend(speech, speech_lengths) - else: - feats, feats_lengths = speech, speech_lengths - - return feats, feats_lengths - - def _calc_transducer_loss( - self, - encoder_out: torch.Tensor, - joint_out: torch.Tensor, - target: torch.Tensor, - t_len: torch.Tensor, - u_len: torch.Tensor, - ) -> Tuple[torch.Tensor, Optional[float], Optional[float]]: - """Compute Transducer loss. - - Args: - encoder_out: Encoder output sequences. (B, T, D_enc) - joint_out: Joint Network output sequences (B, T, U, D_joint) - target: Target label ID sequences. (B, L) - t_len: Encoder output sequences lengths. (B,) - u_len: Target label ID sequences lengths. (B,) - - Return: - loss_transducer: Transducer loss value. - cer_transducer: Character error rate for Transducer. - wer_transducer: Word Error Rate for Transducer. - - """ - if self.criterion_transducer is None: - try: - from warp_rnnt import rnnt_loss as RNNTLoss - self.criterion_transducer = RNNTLoss - - except ImportError: - logging.error( - "warp-rnnt was not installed." - "Please consult the installation documentation." - ) - exit(1) - - log_probs = torch.log_softmax(joint_out, dim=-1) - - loss_transducer = self.criterion_transducer( - log_probs, - target, - t_len, - u_len, - reduction="mean", - blank=self.blank_id, - fastemit_lambda=self.fastemit_lambda, - gather=True, - ) - - if not self.training and (self.report_cer or self.report_wer): - if self.error_calculator is None: - from funasr.modules.e2e_asr_common import ErrorCalculatorTransducer as ErrorCalculator - - self.error_calculator = ErrorCalculator( - self.decoder, - self.joint_network, - self.token_list, - self.sym_space, - self.sym_blank, - report_cer=self.report_cer, - report_wer=self.report_wer, - ) - - cer_transducer, wer_transducer = self.error_calculator(encoder_out, target, t_len) - - return loss_transducer, cer_transducer, wer_transducer - - return loss_transducer, None, None - - def _calc_ctc_loss( - self, - encoder_out: torch.Tensor, - target: torch.Tensor, - t_len: torch.Tensor, - u_len: torch.Tensor, - ) -> torch.Tensor: - """Compute CTC loss. - - Args: - encoder_out: Encoder output sequences. (B, T, D_enc) - target: Target label ID sequences. (B, L) - t_len: Encoder output sequences lengths. (B,) - u_len: Target label ID sequences lengths. (B,) - - Return: - loss_ctc: CTC loss value. - - """ - ctc_in = self.ctc_lin( - torch.nn.functional.dropout(encoder_out, p=self.ctc_dropout_rate) - ) - ctc_in = torch.log_softmax(ctc_in.transpose(0, 1), dim=-1) - - target_mask = target != 0 - ctc_target = target[target_mask].cpu() - - with torch.backends.cudnn.flags(deterministic=True): - loss_ctc = torch.nn.functional.ctc_loss( - ctc_in, - ctc_target, - t_len, - u_len, - zero_infinity=True, - reduction="sum", - ) - loss_ctc /= target.size(0) - - return loss_ctc - - def _calc_lm_loss( - self, - decoder_out: torch.Tensor, - target: torch.Tensor, - ) -> torch.Tensor: - """Compute LM loss. - - Args: - decoder_out: Decoder output sequences. (B, U, D_dec) - target: Target label ID sequences. (B, L) - - Return: - loss_lm: LM loss value. - - """ - lm_loss_in = self.lm_lin(decoder_out[:, :-1, :]).view(-1, self.vocab_size) - lm_target = target.view(-1).type(torch.int64) - - with torch.no_grad(): - true_dist = lm_loss_in.clone() - true_dist.fill_(self.lm_loss_smoothing / (self.vocab_size - 1)) - - # Ignore blank ID (0) - ignore = lm_target == 0 - lm_target = lm_target.masked_fill(ignore, 0) - - true_dist.scatter_(1, lm_target.unsqueeze(1), (1 - self.lm_loss_smoothing)) - - loss_lm = torch.nn.functional.kl_div( - torch.log_softmax(lm_loss_in, dim=1), - true_dist, - reduction="none", - ) - loss_lm = loss_lm.masked_fill(ignore.unsqueeze(1), 0).sum() / decoder_out.size( - 0 - ) - - return loss_lm - -class UnifiedTransducerModel(FunASRModel): - """ESPnet2ASRTransducerModel module definition. - Args: - vocab_size: Size of complete vocabulary (w/ EOS and blank included). - token_list: List of token - frontend: Frontend module. - specaug: SpecAugment module. - normalize: Normalization module. - encoder: Encoder module. - decoder: Decoder module. - joint_network: Joint Network module. - transducer_weight: Weight of the Transducer loss. - fastemit_lambda: FastEmit lambda value. - auxiliary_ctc_weight: Weight of auxiliary CTC loss. - auxiliary_ctc_dropout_rate: Dropout rate for auxiliary CTC loss inputs. - auxiliary_lm_loss_weight: Weight of auxiliary LM loss. - auxiliary_lm_loss_smoothing: Smoothing rate for LM loss' label smoothing. - ignore_id: Initial padding ID. - sym_space: Space symbol. - sym_blank: Blank Symbol - report_cer: Whether to report Character Error Rate during validation. - report_wer: Whether to report Word Error Rate during validation. - extract_feats_in_collect_stats: Whether to use extract_feats stats collection. - """ - - def __init__( - self, - vocab_size: int, - token_list: Union[Tuple[str, ...], List[str]], - frontend: Optional[AbsFrontend], - specaug: Optional[AbsSpecAug], - normalize: Optional[AbsNormalize], - encoder: AbsEncoder, - decoder: RNNTDecoder, - joint_network: JointNetwork, - att_decoder: Optional[AbsAttDecoder] = None, - transducer_weight: float = 1.0, - fastemit_lambda: float = 0.0, - auxiliary_ctc_weight: float = 0.0, - auxiliary_att_weight: float = 0.0, - auxiliary_ctc_dropout_rate: float = 0.0, - auxiliary_lm_loss_weight: float = 0.0, - auxiliary_lm_loss_smoothing: float = 0.0, - ignore_id: int = -1, - sym_space: str = "", - sym_blank: str = "", - report_cer: bool = True, - report_wer: bool = True, - sym_sos: str = "", - sym_eos: str = "", - extract_feats_in_collect_stats: bool = True, - lsm_weight: float = 0.0, - length_normalized_loss: bool = False, - ) -> None: - """Construct an ESPnetASRTransducerModel object.""" - super().__init__() - - # The following labels ID are reserved: 0 (blank) and vocab_size - 1 (sos/eos) - self.blank_id = 0 - - if sym_sos in token_list: - self.sos = token_list.index(sym_sos) - else: - self.sos = vocab_size - 1 - if sym_eos in token_list: - self.eos = token_list.index(sym_eos) - else: - self.eos = vocab_size - 1 - - self.vocab_size = vocab_size - self.ignore_id = ignore_id - self.token_list = token_list.copy() - - self.sym_space = sym_space - self.sym_blank = sym_blank - - self.frontend = frontend - self.specaug = specaug - self.normalize = normalize - - self.encoder = encoder - self.decoder = decoder - self.joint_network = joint_network - - self.criterion_transducer = None - self.error_calculator = None - - self.use_auxiliary_ctc = auxiliary_ctc_weight > 0 - self.use_auxiliary_att = auxiliary_att_weight > 0 - self.use_auxiliary_lm_loss = auxiliary_lm_loss_weight > 0 - - if self.use_auxiliary_ctc: - self.ctc_lin = torch.nn.Linear(encoder.output_size(), vocab_size) - self.ctc_dropout_rate = auxiliary_ctc_dropout_rate - - if self.use_auxiliary_att: - self.att_decoder = att_decoder - - self.criterion_att = LabelSmoothingLoss( - size=vocab_size, - padding_idx=ignore_id, - smoothing=lsm_weight, - normalize_length=length_normalized_loss, - ) - - if self.use_auxiliary_lm_loss: - self.lm_lin = torch.nn.Linear(decoder.output_size, vocab_size) - self.lm_loss_smoothing = auxiliary_lm_loss_smoothing - - self.transducer_weight = transducer_weight - self.fastemit_lambda = fastemit_lambda - - self.auxiliary_ctc_weight = auxiliary_ctc_weight - self.auxiliary_att_weight = auxiliary_att_weight - self.auxiliary_lm_loss_weight = auxiliary_lm_loss_weight - - self.report_cer = report_cer - self.report_wer = report_wer - - self.extract_feats_in_collect_stats = extract_feats_in_collect_stats - - def forward( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - **kwargs, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - """Forward architecture and compute loss(es). - Args: - speech: Speech sequences. (B, S) - speech_lengths: Speech sequences lengths. (B,) - text: Label ID sequences. (B, L) - text_lengths: Label ID sequences lengths. (B,) - kwargs: Contains "utts_id". - Return: - loss: Main loss value. - stats: Task statistics. - weight: Task weights. - """ - assert text_lengths.dim() == 1, text_lengths.shape - assert ( - speech.shape[0] - == speech_lengths.shape[0] - == text.shape[0] - == text_lengths.shape[0] - ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) - - batch_size = speech.shape[0] - text = text[:, : text_lengths.max()] - # 1. Encoder - encoder_out, encoder_out_chunk, encoder_out_lens = self.encode(speech, speech_lengths) - - loss_att, loss_att_chunk = 0.0, 0.0 - - if self.use_auxiliary_att: - loss_att, _ = self._calc_att_loss( - encoder_out, encoder_out_lens, text, text_lengths - ) - loss_att_chunk, _ = self._calc_att_loss( - encoder_out_chunk, encoder_out_lens, text, text_lengths - ) - - # 2. Transducer-related I/O preparation - decoder_in, target, t_len, u_len = get_transducer_task_io( - text, - encoder_out_lens, - ignore_id=self.ignore_id, - ) - - # 3. Decoder - self.decoder.set_device(encoder_out.device) - decoder_out = self.decoder(decoder_in, u_len) - - # 4. Joint Network - joint_out = self.joint_network( - encoder_out.unsqueeze(2), decoder_out.unsqueeze(1) - ) - - joint_out_chunk = self.joint_network( - encoder_out_chunk.unsqueeze(2), decoder_out.unsqueeze(1) - ) - - # 5. Losses - loss_trans_utt, cer_trans, wer_trans = self._calc_transducer_loss( - encoder_out, - joint_out, - target, - t_len, - u_len, - ) - - loss_trans_chunk, cer_trans_chunk, wer_trans_chunk = self._calc_transducer_loss( - encoder_out_chunk, - joint_out_chunk, - target, - t_len, - u_len, - ) - - loss_ctc, loss_ctc_chunk, loss_lm = 0.0, 0.0, 0.0 - - if self.use_auxiliary_ctc: - loss_ctc = self._calc_ctc_loss( - encoder_out, - target, - t_len, - u_len, - ) - loss_ctc_chunk = self._calc_ctc_loss( - encoder_out_chunk, - target, - t_len, - u_len, - ) - - if self.use_auxiliary_lm_loss: - loss_lm = self._calc_lm_loss(decoder_out, target) - - loss_trans = loss_trans_utt + loss_trans_chunk - loss_ctc = loss_ctc + loss_ctc_chunk - loss_att = loss_att + loss_att_chunk - - loss = ( - self.transducer_weight * loss_trans - + self.auxiliary_ctc_weight * loss_ctc - + self.auxiliary_att_weight * loss_att - + self.auxiliary_lm_loss_weight * loss_lm - ) - - stats = dict( - loss=loss.detach(), - loss_transducer=loss_trans_utt.detach(), - loss_transducer_chunk=loss_trans_chunk.detach(), - aux_ctc_loss=loss_ctc.detach() if loss_ctc > 0.0 else None, - aux_ctc_loss_chunk=loss_ctc_chunk.detach() if loss_ctc_chunk > 0.0 else None, - aux_att_loss=loss_att.detach() if loss_att > 0.0 else None, - aux_att_loss_chunk=loss_att_chunk.detach() if loss_att_chunk > 0.0 else None, - aux_lm_loss=loss_lm.detach() if loss_lm > 0.0 else None, - cer_transducer=cer_trans, - wer_transducer=wer_trans, - cer_transducer_chunk=cer_trans_chunk, - wer_transducer_chunk=wer_trans_chunk, - ) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) - return loss, stats, weight - - def collect_feats( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - text: torch.Tensor, - text_lengths: torch.Tensor, - **kwargs, - ) -> Dict[str, torch.Tensor]: - """Collect features sequences and features lengths sequences. - Args: - speech: Speech sequences. (B, S) - speech_lengths: Speech sequences lengths. (B,) - text: Label ID sequences. (B, L) - text_lengths: Label ID sequences lengths. (B,) - kwargs: Contains "utts_id". - Return: - {}: "feats": Features sequences. (B, T, D_feats), - "feats_lengths": Features sequences lengths. (B,) - """ - if self.extract_feats_in_collect_stats: - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - else: - # Generate dummy stats if extract_feats_in_collect_stats is False - logging.warning( - "Generating dummy stats for feats and feats_lengths, " - "because encoder_conf.extract_feats_in_collect_stats is " - f"{self.extract_feats_in_collect_stats}" - ) - - feats, feats_lengths = speech, speech_lengths - - return {"feats": feats, "feats_lengths": feats_lengths} - - def encode( - self, - speech: torch.Tensor, - speech_lengths: torch.Tensor, - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Encoder speech sequences. - Args: - speech: Speech sequences. (B, S) - speech_lengths: Speech sequences lengths. (B,) - Return: - encoder_out: Encoder outputs. (B, T, D_enc) - encoder_out_lens: Encoder outputs lengths. (B,) - """ - with autocast(False): - # 1. Extract feats - feats, feats_lengths = self._extract_feats(speech, speech_lengths) - - # 2. Data augmentation - if self.specaug is not None and self.training: - feats, feats_lengths = self.specaug(feats, feats_lengths) - - # 3. Normalization for feature: e.g. Global-CMVN, Utterance-CMVN - if self.normalize is not None: - feats, feats_lengths = self.normalize(feats, feats_lengths) - - # 4. Forward encoder - encoder_out, encoder_out_chunk, encoder_out_lens = self.encoder(feats, feats_lengths) - - assert encoder_out.size(0) == speech.size(0), ( - encoder_out.size(), - speech.size(0), - ) - assert encoder_out.size(1) <= encoder_out_lens.max(), ( - encoder_out.size(), - encoder_out_lens.max(), - ) - - return encoder_out, encoder_out_chunk, encoder_out_lens - - def _extract_feats( - self, speech: torch.Tensor, speech_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Extract features sequences and features sequences lengths. - Args: - speech: Speech sequences. (B, S) - speech_lengths: Speech sequences lengths. (B,) - Return: - feats: Features sequences. (B, T, D_feats) - feats_lengths: Features sequences lengths. (B,) - """ - assert speech_lengths.dim() == 1, speech_lengths.shape - - # for data-parallel - speech = speech[:, : speech_lengths.max()] - - if self.frontend is not None: - feats, feats_lengths = self.frontend(speech, speech_lengths) - else: - feats, feats_lengths = speech, speech_lengths - - return feats, feats_lengths - - def _calc_transducer_loss( - self, - encoder_out: torch.Tensor, - joint_out: torch.Tensor, - target: torch.Tensor, - t_len: torch.Tensor, - u_len: torch.Tensor, - ) -> Tuple[torch.Tensor, Optional[float], Optional[float]]: - """Compute Transducer loss. - Args: - encoder_out: Encoder output sequences. (B, T, D_enc) - joint_out: Joint Network output sequences (B, T, U, D_joint) - target: Target label ID sequences. (B, L) - t_len: Encoder output sequences lengths. (B,) - u_len: Target label ID sequences lengths. (B,) - Return: - loss_transducer: Transducer loss value. - cer_transducer: Character error rate for Transducer. - wer_transducer: Word Error Rate for Transducer. - """ - if self.criterion_transducer is None: - try: - from warp_rnnt import rnnt_loss as RNNTLoss - self.criterion_transducer = RNNTLoss - - except ImportError: - logging.error( - "warp-rnnt was not installed." - "Please consult the installation documentation." - ) - exit(1) - - log_probs = torch.log_softmax(joint_out, dim=-1) - - loss_transducer = self.criterion_transducer( - log_probs, - target, - t_len, - u_len, - reduction="mean", - blank=self.blank_id, - fastemit_lambda=self.fastemit_lambda, - gather=True, - ) - - if not self.training and (self.report_cer or self.report_wer): - if self.error_calculator is None: - from funasr.modules.e2e_asr_common import ErrorCalculatorTransducer as ErrorCalculator - - self.error_calculator = ErrorCalculator( - self.decoder, - self.joint_network, - self.token_list, - self.sym_space, - self.sym_blank, - report_cer=self.report_cer, - report_wer=self.report_wer, - ) - - cer_transducer, wer_transducer = self.error_calculator(encoder_out, target, t_len) - return loss_transducer, cer_transducer, wer_transducer - - return loss_transducer, None, None - - def _calc_ctc_loss( - self, - encoder_out: torch.Tensor, - target: torch.Tensor, - t_len: torch.Tensor, - u_len: torch.Tensor, - ) -> torch.Tensor: - """Compute CTC loss. - Args: - encoder_out: Encoder output sequences. (B, T, D_enc) - target: Target label ID sequences. (B, L) - t_len: Encoder output sequences lengths. (B,) - u_len: Target label ID sequences lengths. (B,) - Return: - loss_ctc: CTC loss value. - """ - ctc_in = self.ctc_lin( - torch.nn.functional.dropout(encoder_out, p=self.ctc_dropout_rate) - ) - ctc_in = torch.log_softmax(ctc_in.transpose(0, 1), dim=-1) - - target_mask = target != 0 - ctc_target = target[target_mask].cpu() - - with torch.backends.cudnn.flags(deterministic=True): - loss_ctc = torch.nn.functional.ctc_loss( - ctc_in, - ctc_target, - t_len, - u_len, - zero_infinity=True, - reduction="sum", - ) - loss_ctc /= target.size(0) - - return loss_ctc - - def _calc_lm_loss( - self, - decoder_out: torch.Tensor, - target: torch.Tensor, - ) -> torch.Tensor: - """Compute LM loss. - Args: - decoder_out: Decoder output sequences. (B, U, D_dec) - target: Target label ID sequences. (B, L) - Return: - loss_lm: LM loss value. - """ - lm_loss_in = self.lm_lin(decoder_out[:, :-1, :]).view(-1, self.vocab_size) - lm_target = target.view(-1).type(torch.int64) - - with torch.no_grad(): - true_dist = lm_loss_in.clone() - true_dist.fill_(self.lm_loss_smoothing / (self.vocab_size - 1)) - - # Ignore blank ID (0) - ignore = lm_target == 0 - lm_target = lm_target.masked_fill(ignore, 0) - - true_dist.scatter_(1, lm_target.unsqueeze(1), (1 - self.lm_loss_smoothing)) - - loss_lm = torch.nn.functional.kl_div( - torch.log_softmax(lm_loss_in, dim=1), - true_dist, - reduction="none", - ) - loss_lm = loss_lm.masked_fill(ignore.unsqueeze(1), 0).sum() / decoder_out.size( - 0 - ) - - return loss_lm - - def _calc_att_loss( - self, - encoder_out: torch.Tensor, - encoder_out_lens: torch.Tensor, - ys_pad: torch.Tensor, - ys_pad_lens: torch.Tensor, - ): - if hasattr(self, "lang_token_id") and self.lang_token_id is not None: - ys_pad = torch.cat( - [ - self.lang_token_id.repeat(ys_pad.size(0), 1).to(ys_pad.device), - ys_pad, - ], - dim=1, - ) - ys_pad_lens += 1 - - ys_in_pad, ys_out_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) - ys_in_lens = ys_pad_lens + 1 - - # 1. Forward decoder - decoder_out, _ = self.att_decoder( - encoder_out, encoder_out_lens, ys_in_pad, ys_in_lens - ) - - # 2. Compute attention loss - loss_att = self.criterion_att(decoder_out, ys_out_pad) - acc_att = th_accuracy( - decoder_out.view(-1, self.vocab_size), - ys_out_pad, - ignore_label=self.ignore_id, - ) - - return loss_att, acc_att diff --git a/funasr/models/decoder/__init__.py b/funasr/models/e_branchformer/__init__.py similarity index 100% rename from funasr/models/decoder/__init__.py rename to funasr/models/e_branchformer/__init__.py diff --git a/funasr/models/encoder/e_branchformer_encoder.py b/funasr/models/e_branchformer/e_branchformer_encoder.py similarity index 96% rename from funasr/models/encoder/e_branchformer_encoder.py rename to funasr/models/e_branchformer/e_branchformer_encoder.py index 14028ed66..a7b4fde1e 100644 --- a/funasr/models/encoder/e_branchformer_encoder.py +++ b/funasr/models/e_branchformer/e_branchformer_encoder.py @@ -16,26 +16,26 @@ import torch from funasr.models.ctc import CTC from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.modules.cgmlp import ConvolutionalGatingMLP -from funasr.modules.fastformer import FastSelfAttention -from funasr.modules.nets_utils import get_activation, make_pad_mask -from funasr.modules.attention import ( # noqa: H301 +from funasr.models.branchformer.cgmlp import ConvolutionalGatingMLP +from funasr.models.branchformer.fastformer import FastSelfAttention +from funasr.models.transformer.utils.nets_utils import get_activation, make_pad_mask +from funasr.models.transformer.attention import ( # noqa: H301 LegacyRelPositionMultiHeadedAttention, MultiHeadedAttention, RelPositionMultiHeadedAttention, ) -from funasr.modules.embedding import ( # noqa: H301 +from funasr.models.transformer.embedding import ( # noqa: H301 LegacyRelPositionalEncoding, PositionalEncoding, RelPositionalEncoding, ScaledPositionalEncoding, ) -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.positionwise_feed_forward import ( +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.positionwise_feed_forward import ( PositionwiseFeedForward, ) -from funasr.modules.repeat import repeat -from funasr.modules.subsampling import ( +from funasr.models.transformer.repeat import repeat +from funasr.models.transformer.subsampling import ( Conv2dSubsampling, Conv2dSubsampling2, Conv2dSubsampling6, diff --git a/funasr/models/e_branchformer/model.py b/funasr/models/e_branchformer/model.py new file mode 100644 index 000000000..ca3e0f54f --- /dev/null +++ b/funasr/models/e_branchformer/model.py @@ -0,0 +1,64 @@ +import logging +from contextlib import contextmanager +from distutils.version import LooseVersion +from typing import Dict +from typing import List +from typing import Optional +from typing import Tuple +from typing import Union +import tempfile +import codecs +import requests +import re +import copy +import torch +import torch.nn as nn +import random +import numpy as np +import time +# from funasr.layers.abs_normalize import AbsNormalize +from funasr.losses.label_smoothing_loss import ( + LabelSmoothingLoss, # noqa: H301 +) +# from funasr.models.ctc import CTC +# from funasr.models.decoder.abs_decoder import AbsDecoder +# from funasr.models.e2e_asr_common import ErrorCalculator +# from funasr.models.encoder.abs_encoder import AbsEncoder +# from funasr.models.frontend.abs_frontend import AbsFrontend +# from funasr.models.postencoder.abs_postencoder import AbsPostEncoder +from funasr.models.predictor.cif import mae_loss +# from funasr.models.preencoder.abs_preencoder import AbsPreEncoder +# from funasr.models.specaug.abs_specaug import AbsSpecAug +from funasr.models.transformer.add_sos_eos import add_sos_eos +from funasr.models.transformer.utils.nets_utils import make_pad_mask, pad_list +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.train_utils.device_funcs import force_gatherable +# from funasr.models.base_model import FunASRModel +# from funasr.models.predictor.cif import CifPredictorV3 +from funasr.models.paraformer.search import Hypothesis + +from funasr.models.model_class_factory import * + +if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): + from torch.cuda.amp import autocast +else: + # Nothing to do if torch<1.6.0 + @contextmanager + def autocast(enabled=True): + yield +from funasr.datasets.fun_datasets.load_audio_extract_fbank import load_audio, extract_fbank +from funasr.utils import postprocess_utils +from funasr.utils.datadir_writer import DatadirWriter + +from funasr.models.transformer.model import Transformer + +class EBranchformer(Transformer): + """CTC-attention hybrid Encoder-Decoder model""" + + def __init__( + self, + *args, + **kwargs, + ): + + super().__init__(*args, **kwargs) diff --git a/funasr/models/encoder/__init__.py b/funasr/models/eend/__init__.py similarity index 100% rename from funasr/models/encoder/__init__.py rename to funasr/models/eend/__init__.py diff --git a/funasr/models/e2e_diar_eend_ola.py b/funasr/models/eend/e2e_diar_eend_ola.py similarity index 94% rename from funasr/models/e2e_diar_eend_ola.py rename to funasr/models/eend/e2e_diar_eend_ola.py index a0b545aac..28aa22366 100644 --- a/funasr/models/e2e_diar_eend_ola.py +++ b/funasr/models/eend/e2e_diar_eend_ola.py @@ -7,14 +7,13 @@ import torch import torch.nn as nn import torch.nn.functional as F -from funasr.models.base_model import FunASRModel from funasr.models.frontend.wav_frontend import WavFrontendMel23 -from funasr.modules.eend_ola.encoder import EENDOLATransformerEncoder -from funasr.modules.eend_ola.encoder_decoder_attractor import EncoderDecoderAttractor -from funasr.modules.eend_ola.utils.losses import standard_loss, cal_power_loss, fast_batch_pit_n_speaker_loss -from funasr.modules.eend_ola.utils.power import create_powerlabel -from funasr.modules.eend_ola.utils.power import generate_mapping_dict -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.models.eend.encoder import EENDOLATransformerEncoder +from funasr.models.eend.encoder_decoder_attractor import EncoderDecoderAttractor +from funasr.models.eend.utils.losses import standard_loss, cal_power_loss, fast_batch_pit_n_speaker_loss +from funasr.models.eend.utils.power import create_powerlabel +from funasr.models.eend.utils.power import generate_mapping_dict +from funasr.train_utils.device_funcs import force_gatherable if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): pass @@ -55,7 +54,7 @@ def pad_results(ys, out_size): return ys_padded -class DiarEENDOLAModel(FunASRModel): +class DiarEENDOLAModel(nn.Module): """EEND-OLA diarization model""" def __init__( diff --git a/funasr/modules/eend_ola/eend_ola_dataloader.py b/funasr/models/eend/eend_ola_dataloader.py similarity index 100% rename from funasr/modules/eend_ola/eend_ola_dataloader.py rename to funasr/models/eend/eend_ola_dataloader.py diff --git a/funasr/modules/eend_ola/encoder.py b/funasr/models/eend/encoder.py similarity index 100% rename from funasr/modules/eend_ola/encoder.py rename to funasr/models/eend/encoder.py diff --git a/funasr/modules/eend_ola/encoder_decoder_attractor.py b/funasr/models/eend/encoder_decoder_attractor.py similarity index 100% rename from funasr/modules/eend_ola/encoder_decoder_attractor.py rename to funasr/models/eend/encoder_decoder_attractor.py diff --git a/funasr/models/encoder/opennmt_encoders/__init__.py b/funasr/models/eend/utils/__init__.py similarity index 100% rename from funasr/models/encoder/opennmt_encoders/__init__.py rename to funasr/models/eend/utils/__init__.py diff --git a/funasr/modules/eend_ola/utils/feature.py b/funasr/models/eend/utils/feature.py similarity index 100% rename from funasr/modules/eend_ola/utils/feature.py rename to funasr/models/eend/utils/feature.py diff --git a/funasr/modules/eend_ola/utils/kaldi_data.py b/funasr/models/eend/utils/kaldi_data.py similarity index 100% rename from funasr/modules/eend_ola/utils/kaldi_data.py rename to funasr/models/eend/utils/kaldi_data.py diff --git a/funasr/modules/eend_ola/utils/losses.py b/funasr/models/eend/utils/losses.py similarity index 100% rename from funasr/modules/eend_ola/utils/losses.py rename to funasr/models/eend/utils/losses.py diff --git a/funasr/modules/eend_ola/utils/power.py b/funasr/models/eend/utils/power.py similarity index 100% rename from funasr/modules/eend_ola/utils/power.py rename to funasr/models/eend/utils/power.py diff --git a/funasr/modules/eend_ola/utils/report.py b/funasr/models/eend/utils/report.py similarity index 99% rename from funasr/modules/eend_ola/utils/report.py rename to funasr/models/eend/utils/report.py index f4a044bc0..cd100f066 100644 --- a/funasr/modules/eend_ola/utils/report.py +++ b/funasr/models/eend/utils/report.py @@ -2,7 +2,7 @@ import copy import numpy as np import time import torch -from funasr.modules.eend_ola.utils.power import create_powerlabel +from funasr.models.eend.utils.power import create_powerlabel from itertools import combinations metrics = [ diff --git a/funasr/models/encoder/abs_encoder.py b/funasr/models/encoder/abs_encoder.py deleted file mode 100644 index 034bc1f88..000000000 --- a/funasr/models/encoder/abs_encoder.py +++ /dev/null @@ -1,21 +0,0 @@ -from abc import ABC -from abc import abstractmethod -from typing import Optional -from typing import Tuple - -import torch - - -class AbsEncoder(torch.nn.Module, ABC): - @abstractmethod - def output_size(self) -> int: - raise NotImplementedError - - @abstractmethod - def forward( - self, - xs_pad: torch.Tensor, - ilens: torch.Tensor, - prev_states: torch.Tensor = None, - ) -> Tuple[torch.Tensor, torch.Tensor, Optional[torch.Tensor]]: - raise NotImplementedError \ No newline at end of file diff --git a/funasr/models/frontend/default.py b/funasr/models/frontend/default.py index 34353218e..b4e518a51 100644 --- a/funasr/models/frontend/default.py +++ b/funasr/models/frontend/default.py @@ -11,12 +11,12 @@ try: except: print("Please install torch_complex firstly") -from funasr.layers.log_mel import LogMel -from funasr.layers.stft import Stft +from funasr.models.frontend.utils.log_mel import LogMel +from funasr.models.frontend.utils.stft import Stft from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.frontend.frontends_utils.frontend import Frontend +from funasr.models.frontend.utils.frontend import Frontend from funasr.utils.get_default_kwargs import get_default_kwargs -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import make_pad_mask class DefaultFrontend(AbsFrontend): diff --git a/funasr/models/frontend/s3prl.py b/funasr/models/frontend/s3prl.py index 00a997063..0e419bc17 100644 --- a/funasr/models/frontend/s3prl.py +++ b/funasr/models/frontend/s3prl.py @@ -10,8 +10,8 @@ import humanfriendly import torch from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.frontend.frontends_utils.frontend import Frontend -from funasr.modules.nets_utils import pad_list +from funasr.models.frontend.utils.frontend import Frontend +from funasr.models.transformer.utils.nets_utils import pad_list from funasr.utils.get_default_kwargs import get_default_kwargs diff --git a/funasr/models/frontend/frontends_utils/__init__.py b/funasr/models/frontend/utils/__init__.py similarity index 100% rename from funasr/models/frontend/frontends_utils/__init__.py rename to funasr/models/frontend/utils/__init__.py diff --git a/funasr/models/frontend/frontends_utils/beamformer.py b/funasr/models/frontend/utils/beamformer.py similarity index 100% rename from funasr/models/frontend/frontends_utils/beamformer.py rename to funasr/models/frontend/utils/beamformer.py diff --git a/funasr/layers/complex_utils.py b/funasr/models/frontend/utils/complex_utils.py similarity index 100% rename from funasr/layers/complex_utils.py rename to funasr/models/frontend/utils/complex_utils.py diff --git a/funasr/models/frontend/frontends_utils/dnn_beamformer.py b/funasr/models/frontend/utils/dnn_beamformer.py similarity index 94% rename from funasr/models/frontend/frontends_utils/dnn_beamformer.py rename to funasr/models/frontend/utils/dnn_beamformer.py index 05e241d80..0f4e9dade 100644 --- a/funasr/models/frontend/frontends_utils/dnn_beamformer.py +++ b/funasr/models/frontend/utils/dnn_beamformer.py @@ -4,12 +4,12 @@ from typing import Tuple import torch from torch.nn import functional as F -from funasr.models.frontend.frontends_utils.beamformer import apply_beamforming_vector -from funasr.models.frontend.frontends_utils.beamformer import get_mvdr_vector -from funasr.models.frontend.frontends_utils.beamformer import ( +from funasr.models.frontend.utils.beamformer import apply_beamforming_vector +from funasr.models.frontend.utils.beamformer import get_mvdr_vector +from funasr.models.frontend.utils.beamformer import ( get_power_spectral_density_matrix, # noqa: H301 ) -from funasr.models.frontend.frontends_utils.mask_estimator import MaskEstimator +from funasr.models.frontend.utils.mask_estimator import MaskEstimator from torch_complex.tensor import ComplexTensor diff --git a/funasr/models/frontend/frontends_utils/dnn_wpe.py b/funasr/models/frontend/utils/dnn_wpe.py similarity index 95% rename from funasr/models/frontend/frontends_utils/dnn_wpe.py rename to funasr/models/frontend/utils/dnn_wpe.py index ffe12a3c2..6a14c5dd6 100644 --- a/funasr/models/frontend/frontends_utils/dnn_wpe.py +++ b/funasr/models/frontend/utils/dnn_wpe.py @@ -4,8 +4,8 @@ from pytorch_wpe import wpe_one_iteration import torch from torch_complex.tensor import ComplexTensor -from funasr.models.frontend.frontends_utils.mask_estimator import MaskEstimator -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.frontend.utils.mask_estimator import MaskEstimator +from funasr.models.transformer.utils.nets_utils import make_pad_mask class DNN_WPE(torch.nn.Module): diff --git a/funasr/models/frontend/frontends_utils/feature_transform.py b/funasr/models/frontend/utils/feature_transform.py similarity index 99% rename from funasr/models/frontend/frontends_utils/feature_transform.py rename to funasr/models/frontend/utils/feature_transform.py index 353dca1a6..a3ee26020 100644 --- a/funasr/models/frontend/frontends_utils/feature_transform.py +++ b/funasr/models/frontend/utils/feature_transform.py @@ -7,7 +7,7 @@ import numpy as np import torch from torch_complex.tensor import ComplexTensor -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import make_pad_mask class FeatureTransform(torch.nn.Module): diff --git a/funasr/models/frontend/frontends_utils/frontend.py b/funasr/models/frontend/utils/frontend.py similarity index 96% rename from funasr/models/frontend/frontends_utils/frontend.py rename to funasr/models/frontend/utils/frontend.py index bf266e9ee..8f84e73c2 100644 --- a/funasr/models/frontend/frontends_utils/frontend.py +++ b/funasr/models/frontend/utils/frontend.py @@ -8,8 +8,8 @@ import torch import torch.nn as nn from torch_complex.tensor import ComplexTensor -from funasr.models.frontend.frontends_utils.dnn_beamformer import DNN_Beamformer -from funasr.models.frontend.frontends_utils.dnn_wpe import DNN_WPE +from funasr.models.frontend.utils.dnn_beamformer import DNN_Beamformer +from funasr.models.frontend.utils.dnn_wpe import DNN_WPE class Frontend(nn.Module): diff --git a/funasr/layers/log_mel.py b/funasr/models/frontend/utils/log_mel.py similarity index 97% rename from funasr/layers/log_mel.py rename to funasr/models/frontend/utils/log_mel.py index 2285f6d4f..4983a1d0a 100644 --- a/funasr/layers/log_mel.py +++ b/funasr/models/frontend/utils/log_mel.py @@ -2,7 +2,7 @@ import librosa import torch from typing import Tuple -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import make_pad_mask class LogMel(torch.nn.Module): diff --git a/funasr/models/frontend/frontends_utils/mask_estimator.py b/funasr/models/frontend/utils/mask_estimator.py similarity index 93% rename from funasr/models/frontend/frontends_utils/mask_estimator.py rename to funasr/models/frontend/utils/mask_estimator.py index 53072bf4a..002e474cc 100644 --- a/funasr/models/frontend/frontends_utils/mask_estimator.py +++ b/funasr/models/frontend/utils/mask_estimator.py @@ -5,9 +5,9 @@ import torch from torch.nn import functional as F from torch_complex.tensor import ComplexTensor -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.rnn.encoders import RNN -from funasr.modules.rnn.encoders import RNNP +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.language_model.rnn.encoders import RNN +from funasr.models.language_model.rnn.encoders import RNNP class MaskEstimator(torch.nn.Module): diff --git a/funasr/layers/stft.py b/funasr/models/frontend/utils/stft.py similarity index 97% rename from funasr/layers/stft.py rename to funasr/models/frontend/utils/stft.py index c71af8e86..2a0bc9658 100644 --- a/funasr/layers/stft.py +++ b/funasr/models/frontend/utils/stft.py @@ -9,9 +9,9 @@ try: from torch_complex.tensor import ComplexTensor except: print("Please install torch_complex firstly") -from funasr.modules.nets_utils import make_pad_mask -from funasr.layers.complex_utils import is_complex -from funasr.layers.inversible_interface import InversibleInterface +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.frontend.utils.complex_utils import is_complex + import librosa import numpy as np @@ -21,7 +21,7 @@ is_torch_1_9_plus = LooseVersion(torch.__version__) >= LooseVersion("1.9.0") is_torch_1_7_plus = LooseVersion(torch.__version__) >= LooseVersion("1.7") -class Stft(torch.nn.Module, InversibleInterface): +class Stft(torch.nn.Module): def __init__( self, n_fft: int = 512, diff --git a/funasr/models/pooling/__init__.py b/funasr/models/fsmn_vad/__init__.py similarity index 100% rename from funasr/models/pooling/__init__.py rename to funasr/models/fsmn_vad/__init__.py diff --git a/funasr/models/encoder/fsmn_encoder.py b/funasr/models/fsmn_vad/fsmn_encoder.py similarity index 100% rename from funasr/models/encoder/fsmn_encoder.py rename to funasr/models/fsmn_vad/fsmn_encoder.py diff --git a/funasr/models/e2e_vad.py b/funasr/models/fsmn_vad/model.py similarity index 98% rename from funasr/models/e2e_vad.py rename to funasr/models/fsmn_vad/model.py index 7c55b2e18..b930e0cc7 100644 --- a/funasr/models/e2e_vad.py +++ b/funasr/models/fsmn_vad/model.py @@ -4,227 +4,31 @@ from typing import List, Tuple, Dict, Any import torch from torch import nn import math +from typing import Optional from funasr.models.encoder.fsmn_encoder import FSMN from funasr.models.base_model import FunASRModel +from funasr.models.model_class_factory import * -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: +class FsmnVAD(nn.Module): """ Author: Speech Lab of DAMO Academy, Alibaba Group Deep-FSMN for Large Vocabulary Continuous Speech Recognition https://arxiv.org/abs/1803.05030 """ - 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): - """ - Author: Speech Lab of DAMO Academy, Alibaba Group - Deep-FSMN for Large Vocabulary Continuous Speech Recognition - https://arxiv.org/abs/1803.05030 - """ - 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): - """ - Author: Speech Lab of DAMO Academy, Alibaba Group - Deep-FSMN for Large Vocabulary Continuous Speech Recognition - https://arxiv.org/abs/1803.05030 - """ - 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): - """ - Author: Speech Lab of DAMO Academy, Alibaba Group - Deep-FSMN for Large Vocabulary Continuous Speech Recognition - https://arxiv.org/abs/1803.05030 - """ - 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(FunASRModel): - """ - Author: Speech Lab of DAMO Academy, Alibaba Group - Deep-FSMN for Large Vocabulary Continuous Speech Recognition - https://arxiv.org/abs/1803.05030 - """ - def __init__(self, encoder: FSMN, vad_post_args: Dict[str, Any], frontend=None): - super(E2EVadModel, self).__init__() + def __init__(self, encoder: str = None, + encoder_conf: Optional[Dict] = None, + vad_post_args: Dict[str, Any] = None, + frontend=None): + super().__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) + + encoder_class = encoder_choices.get_class(encoder) + encoder = encoder_class(**encoder_conf) self.encoder = encoder # init variables self.data_buf_start_frame = 0 @@ -676,3 +480,210 @@ class E2EVadModel(FunASRModel): if self.vad_state_machine == VadStateMachine.kVadInStateEndPointDetected and \ self.vad_opts.detect_mode == VadDetectMode.kVadMutipleUtteranceDetectMode.value: self.ResetDetection() + + + +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: + """ + Author: Speech Lab of DAMO Academy, Alibaba Group + Deep-FSMN for Large Vocabulary Continuous Speech Recognition + https://arxiv.org/abs/1803.05030 + """ + 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): + """ + Author: Speech Lab of DAMO Academy, Alibaba Group + Deep-FSMN for Large Vocabulary Continuous Speech Recognition + https://arxiv.org/abs/1803.05030 + """ + 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): + """ + Author: Speech Lab of DAMO Academy, Alibaba Group + Deep-FSMN for Large Vocabulary Continuous Speech Recognition + https://arxiv.org/abs/1803.05030 + """ + 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): + """ + Author: Speech Lab of DAMO Academy, Alibaba Group + Deep-FSMN for Large Vocabulary Continuous Speech Recognition + https://arxiv.org/abs/1803.05030 + """ + 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) + + diff --git a/funasr/models/vad_realtime_transformer.py b/funasr/models/fsmn_vad/vad_realtime_transformer.py similarity index 98% rename from funasr/models/vad_realtime_transformer.py rename to funasr/models/fsmn_vad/vad_realtime_transformer.py index e2d13f9b5..e02f624f6 100644 --- a/funasr/models/vad_realtime_transformer.py +++ b/funasr/models/fsmn_vad/vad_realtime_transformer.py @@ -5,7 +5,7 @@ from typing import Tuple import torch import torch.nn as nn -from funasr.modules.embedding import SinusoidalPositionEncoder +from funasr.models.transformer.embedding import SinusoidalPositionEncoder from funasr.models.encoder.sanm_encoder import SANMVadEncoder as Encoder diff --git a/funasr/models/joint_net/__init__.py b/funasr/models/joint_net/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/funasr/models/joint_net/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/funasr/models/postencoder/__init__.py b/funasr/models/language_model/__init__.py similarity index 100% rename from funasr/models/postencoder/__init__.py rename to funasr/models/language_model/__init__.py diff --git a/funasr/modules/rnn/__init__.py b/funasr/models/language_model/rnn/__init__.py similarity index 100% rename from funasr/modules/rnn/__init__.py rename to funasr/models/language_model/rnn/__init__.py diff --git a/funasr/modules/rnn/argument.py b/funasr/models/language_model/rnn/argument.py similarity index 100% rename from funasr/modules/rnn/argument.py rename to funasr/models/language_model/rnn/argument.py diff --git a/funasr/modules/rnn/attentions.py b/funasr/models/language_model/rnn/attentions.py similarity index 99% rename from funasr/modules/rnn/attentions.py rename to funasr/models/language_model/rnn/attentions.py index 71d1786d6..30cdff99d 100644 --- a/funasr/modules/rnn/attentions.py +++ b/funasr/models/language_model/rnn/attentions.py @@ -6,8 +6,8 @@ import six import torch import torch.nn.functional as F -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.nets_utils import to_device +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import to_device def _apply_attention_constraint( diff --git a/funasr/modules/rnn/decoders.py b/funasr/models/language_model/rnn/decoders.py similarity index 98% rename from funasr/modules/rnn/decoders.py rename to funasr/models/language_model/rnn/decoders.py index c5d886f30..a426b5155 100644 --- a/funasr/modules/rnn/decoders.py +++ b/funasr/models/language_model/rnn/decoders.py @@ -9,15 +9,15 @@ import six import torch import torch.nn.functional as F -from funasr.modules.scorers.ctc_prefix_score import CTCPrefixScore -from funasr.modules.scorers.ctc_prefix_score import CTCPrefixScoreTH -from funasr.modules.scorers.scorer_interface import ScorerInterface -from funasr.modules.e2e_asr_common import end_detect -from funasr.modules.nets_utils import mask_by_length -from funasr.modules.nets_utils import pad_list -from funasr.modules.nets_utils import th_accuracy -from funasr.modules.nets_utils import to_device -from funasr.modules.rnn.attentions import att_to_numpy +from funasr.models.transformer.utils.scorers.ctc_prefix_score import CTCPrefixScore +from funasr.models.transformer.utils.scorers.ctc_prefix_score import CTCPrefixScoreTH +from funasr.models.transformer.utils.scorers.scorer_interface import ScorerInterface +from funasr.metrics import end_detect +from funasr.models.transformer.utils.nets_utils import mask_by_length +from funasr.models.transformer.utils.nets_utils import pad_list +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.models.transformer.utils.nets_utils import to_device +from funasr.models.language_model.rnn.attentions import att_to_numpy MAX_DECODER_OUTPUT = 5 CTC_SCORING_RATIO = 1.5 diff --git a/funasr/modules/rnn/encoders.py b/funasr/models/language_model/rnn/encoders.py similarity index 98% rename from funasr/modules/rnn/encoders.py rename to funasr/models/language_model/rnn/encoders.py index a7320c282..819585be5 100644 --- a/funasr/modules/rnn/encoders.py +++ b/funasr/models/language_model/rnn/encoders.py @@ -7,9 +7,9 @@ import torch.nn.functional as F from torch.nn.utils.rnn import pack_padded_sequence from torch.nn.utils.rnn import pad_packed_sequence -from funasr.modules.e2e_asr_common import get_vgg2l_odim -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.nets_utils import to_device +from funasr.metrics import get_vgg2l_odim +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import to_device class RNNP(torch.nn.Module): diff --git a/funasr/models/seq_rnn_lm.py b/funasr/models/language_model/seq_rnn_lm.py similarity index 100% rename from funasr/models/seq_rnn_lm.py rename to funasr/models/language_model/seq_rnn_lm.py diff --git a/funasr/models/transformer_lm.py b/funasr/models/language_model/transformer_lm.py similarity index 96% rename from funasr/models/transformer_lm.py rename to funasr/models/language_model/transformer_lm.py index 1cd76dc96..cc71142bb 100644 --- a/funasr/models/transformer_lm.py +++ b/funasr/models/language_model/transformer_lm.py @@ -5,9 +5,9 @@ from typing import Tuple import torch import torch.nn as nn -from funasr.modules.embedding import PositionalEncoding +from funasr.models.transformer.embedding import PositionalEncoding from funasr.models.encoder.transformer_encoder import TransformerEncoder_s0 as Encoder -from funasr.modules.mask import subsequent_mask +from funasr.models.transformer.utils.mask import subsequent_mask from funasr.train.abs_model import AbsLM diff --git a/funasr/models/predictor/__init__.py b/funasr/models/lora/__init__.py similarity index 100% rename from funasr/models/predictor/__init__.py rename to funasr/models/lora/__init__.py diff --git a/funasr/modules/lora/layers.py b/funasr/models/lora/layers.py similarity index 100% rename from funasr/modules/lora/layers.py rename to funasr/models/lora/layers.py diff --git a/funasr/modules/lora/utils.py b/funasr/models/lora/utils.py similarity index 100% rename from funasr/modules/lora/utils.py rename to funasr/models/lora/utils.py diff --git a/funasr/models/preencoder/__init__.py b/funasr/models/mfcca/__init__.py similarity index 100% rename from funasr/models/preencoder/__init__.py rename to funasr/models/mfcca/__init__.py diff --git a/funasr/models/e2e_asr_mfcca.py b/funasr/models/mfcca/e2e_asr_mfcca.py similarity index 98% rename from funasr/models/e2e_asr_mfcca.py rename to funasr/models/mfcca/e2e_asr_mfcca.py index 7dd3b8df6..5ec9e9439 100644 --- a/funasr/models/e2e_asr_mfcca.py +++ b/funasr/models/mfcca/e2e_asr_mfcca.py @@ -8,9 +8,9 @@ from typing import Union import logging import torch -from funasr.modules.e2e_asr_common import ErrorCalculator -from funasr.modules.nets_utils import th_accuracy -from funasr.modules.add_sos_eos import add_sos_eos +from funasr.metrics import ErrorCalculator +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.models.transformer.add_sos_eos import add_sos_eos from funasr.losses.label_smoothing_loss import ( LabelSmoothingLoss, # noqa: H301 ) @@ -21,7 +21,7 @@ from funasr.models.frontend.abs_frontend import AbsFrontend from funasr.models.preencoder.abs_preencoder import AbsPreEncoder from funasr.models.specaug.abs_specaug import AbsSpecAug from funasr.layers.abs_normalize import AbsNormalize -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.train_utils.device_funcs import force_gatherable from funasr.models.base_model import FunASRModel if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): diff --git a/funasr/models/encoder/encoder_layer_mfcca.py b/funasr/models/mfcca/encoder_layer_mfcca.py similarity index 99% rename from funasr/models/encoder/encoder_layer_mfcca.py rename to funasr/models/mfcca/encoder_layer_mfcca.py index e0bd006bd..cc86f89a7 100644 --- a/funasr/models/encoder/encoder_layer_mfcca.py +++ b/funasr/models/mfcca/encoder_layer_mfcca.py @@ -11,7 +11,7 @@ import torch from torch import nn -from funasr.modules.layer_norm import LayerNorm +from funasr.models.transformer.layer_norm import LayerNorm from torch.autograd import Variable diff --git a/funasr/models/encoder/mfcca_encoder.py b/funasr/models/mfcca/mfcca_encoder.py similarity index 94% rename from funasr/models/encoder/mfcca_encoder.py rename to funasr/models/mfcca/mfcca_encoder.py index 87bb19dd5..92dd6e7ed 100644 --- a/funasr/models/encoder/mfcca_encoder.py +++ b/funasr/models/mfcca/mfcca_encoder.py @@ -7,32 +7,32 @@ from torch import nn from funasr.models.encoder.encoder_layer_mfcca import EncoderLayer -from funasr.modules.nets_utils import get_activation -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.attention import ( +from funasr.models.transformer.utils.nets_utils import get_activation +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.attention import ( MultiHeadedAttention, # noqa: H301 RelPositionMultiHeadedAttention, # noqa: H301 LegacyRelPositionMultiHeadedAttention, # noqa: H301 ) -from funasr.modules.embedding import ( +from funasr.models.transformer.embedding import ( PositionalEncoding, # noqa: H301 ScaledPositionalEncoding, # noqa: H301 RelPositionalEncoding, # noqa: H301 LegacyRelPositionalEncoding, # noqa: H301 ) -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.multi_layer_conv import Conv1dLinear -from funasr.modules.multi_layer_conv import MultiLayeredConv1d -from funasr.modules.positionwise_feed_forward import ( +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.utils.multi_layer_conv import Conv1dLinear +from funasr.models.transformer.utils.multi_layer_conv import MultiLayeredConv1d +from funasr.models.transformer.positionwise_feed_forward import ( PositionwiseFeedForward, # noqa: H301 ) -from funasr.modules.repeat import repeat -from funasr.modules.subsampling import Conv2dSubsampling -from funasr.modules.subsampling import Conv2dSubsampling2 -from funasr.modules.subsampling import Conv2dSubsampling6 -from funasr.modules.subsampling import Conv2dSubsampling8 -from funasr.modules.subsampling import TooShortUttError -from funasr.modules.subsampling import check_short_utt +from funasr.models.transformer.repeat import repeat +from funasr.models.transformer.subsampling import Conv2dSubsampling +from funasr.models.transformer.subsampling import Conv2dSubsampling2 +from funasr.models.transformer.subsampling import Conv2dSubsampling6 +from funasr.models.transformer.subsampling import Conv2dSubsampling8 +from funasr.models.transformer.subsampling import TooShortUttError +from funasr.models.transformer.subsampling import check_short_utt from funasr.models.encoder.abs_encoder import AbsEncoder import pdb import math diff --git a/funasr/models/model_class_factory.py b/funasr/models/model_class_factory.py index 819ca2137..23d2304be 100644 --- a/funasr/models/model_class_factory.py +++ b/funasr/models/model_class_factory.py @@ -1,61 +1,38 @@ -import argparse -import logging -import os -from pathlib import Path -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union -import numpy as np -import torch -import yaml +from funasr.models.normalize.global_mvn import GlobalMVN +from funasr.models.normalize.utterance_mvn import UtteranceMVN +from funasr.models.ctc.ctc import CTC -from funasr.datasets.collate_fn import CommonCollateFn -from funasr.datasets.preprocessor import CommonPreprocessor -from funasr.layers.abs_normalize import AbsNormalize -from funasr.layers.global_mvn import GlobalMVN -from funasr.layers.utterance_mvn import UtteranceMVN -from funasr.models.ctc import CTC -from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.models.decoder.rnn_decoder import RNNDecoder -from funasr.models.decoder.sanm_decoder import ParaformerSANMDecoder, FsmnDecoderSCAMAOpt -from funasr.models.decoder.transformer_decoder import ( +from funasr.models.transducer.rnn_decoder import RNNDecoder +from funasr.models.sanm.sanm_decoder import ParaformerSANMDecoder, FsmnDecoderSCAMAOpt +from funasr.models.transformer.transformer_decoder import ( DynamicConvolution2DTransformerDecoder, # noqa: H301 ) -from funasr.models.decoder.transformer_decoder import DynamicConvolutionTransformerDecoder -from funasr.models.decoder.transformer_decoder import ( +from funasr.models.transformer.transformer_decoder import DynamicConvolutionTransformerDecoder +from funasr.models.transformer.transformer_decoder import ( LightweightConvolution2DTransformerDecoder, # noqa: H301 ) -from funasr.models.decoder.transformer_decoder import ( +from funasr.models.transformer.transformer_decoder import ( LightweightConvolutionTransformerDecoder, # noqa: H301 ) -from funasr.models.decoder.transformer_decoder import ParaformerDecoderSAN -from funasr.models.decoder.transformer_decoder import TransformerDecoder -from funasr.models.decoder.contextual_decoder import ContextualParaformerDecoder -from funasr.models.decoder.transformer_decoder import SAAsrTransformerDecoder -from funasr.models.e2e_asr import ASRModel -from funasr.models.decoder.rnnt_decoder import RNNTDecoder -from funasr.models.joint_net.joint_network import JointNetwork -from funasr.models.e2e_asr_paraformer import Paraformer, ParaformerOnline, ParaformerBert, BiCifParaformer, ContextualParaformer -from funasr.models.e2e_asr_contextual_paraformer import NeatContextualParaformer -from funasr.models.e2e_tp import TimestampPredictor -from funasr.models.e2e_asr_mfcca import MFCCA -from funasr.models.e2e_sa_asr import SAASRModel -from funasr.models.e2e_uni_asr import UniASR -from funasr.models.e2e_asr_transducer import TransducerModel, UnifiedTransducerModel -from funasr.models.e2e_asr_bat import BATModel -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.encoder.conformer_encoder import ConformerEncoder, ConformerChunkEncoder -from funasr.models.encoder.data2vec_encoder import Data2VecEncoder -from funasr.models.encoder.rnn_encoder import RNNEncoder -from funasr.models.encoder.sanm_encoder import SANMEncoder, SANMEncoderChunkOpt -from funasr.models.encoder.transformer_encoder import TransformerEncoder -from funasr.models.encoder.mfcca_encoder import MFCCAEncoder -from funasr.models.encoder.resnet34_encoder import ResNet34Diar +from funasr.models.transformer.transformer_decoder import ParaformerDecoderSAN +from funasr.models.transformer.transformer_decoder import TransformerDecoder +from funasr.models.paraformer.contextual_decoder import ContextualParaformerDecoder +from funasr.models.transformer.transformer_decoder import SAAsrTransformerDecoder + +from funasr.models.transducer.rnnt_decoder import RNNTDecoder +from funasr.models.transducer.joint_network import JointNetwork + + +from funasr.models.conformer.conformer_encoder import ConformerEncoder, ConformerChunkEncoder +from funasr.models.data2vec.data2vec_encoder import Data2VecEncoder +from funasr.models.transducer.rnn_encoder import RNNEncoder +from funasr.models.sanm.sanm_encoder import SANMEncoder, SANMEncoderChunkOpt +from funasr.models.transformer.transformer_encoder import TransformerEncoder +from funasr.models.branchformer.branchformer_encoder import BranchformerEncoder +from funasr.models.e_branchformer.e_branchformer_encoder import EBranchformerEncoder +from funasr.models.mfcca.mfcca_encoder import MFCCAEncoder +from funasr.models.sond.encoder.resnet34_encoder import ResNet34Diar from funasr.models.frontend.abs_frontend import AbsFrontend from funasr.models.frontend.default import DefaultFrontend from funasr.models.frontend.default import MultiChannelFrontend @@ -63,32 +40,25 @@ from funasr.models.frontend.fused import FusedFrontends from funasr.models.frontend.s3prl import S3prlFrontend from funasr.models.frontend.wav_frontend import WavFrontend from funasr.models.frontend.windowing import SlidingWindow -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.postencoder.hugging_face_transformers_postencoder import ( - HuggingFaceTransformersPostEncoder, # noqa: H301 -) -from funasr.models.predictor.cif import CifPredictor, CifPredictorV2, CifPredictorV3, BATPredictor -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.preencoder.linear import LinearProjection -from funasr.models.preencoder.sinc import LightweightSincConvs -from funasr.models.specaug.abs_specaug import AbsSpecAug + + +from funasr.models.paraformer.cif_predictor import CifPredictor, CifPredictorV2, CifPredictorV3, BATPredictor from funasr.models.specaug.specaug import SpecAug from funasr.models.specaug.specaug import SpecAugLFR -from funasr.modules.subsampling import Conv1dSubsampling -from funasr.tasks.abs_task import AbsTask -from funasr.tokenizer.phoneme_tokenizer import g2p_choices -from funasr.torch_utils.initialize import initialize -from funasr.models.base_model import FunASRModel -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.get_default_kwargs import get_default_kwargs -from funasr.utils.nested_dict_action import NestedDictAction -from funasr.utils.types import float_or_none -from funasr.utils.types import int_or_none -from funasr.utils.types import str2bool -from funasr.utils.types import str_or_none +from funasr.models.transformer.subsampling import Conv1dSubsampling +from funasr.utils.class_choices import ClassChoices +from funasr.models.fsmn_vad.fsmn_encoder import FSMN + +from funasr.models.sond.encoder.ecapa_tdnn_encoder import ECAPA_TDNN +from funasr.models.sond.encoder.conv_encoder import ConvEncoder +from funasr.models.sond.encoder.fsmn_encoder import FsmnEncoder +from funasr.models.sond.encoder.resnet34_encoder import ResNet34Diar, ResNet34SpL2RegDiar + +from funasr.models.sond.encoder.conv_encoder import ConvEncoder +from funasr.models.sond.encoder.fsmn_encoder import FsmnEncoder +from funasr.models.eend.encoder_decoder_attractor import EncoderDecoderAttractor +from funasr.models.eend.encoder import EENDOLATransformerEncoder -# from funasr.models.paraformer import Paraformer frontend_choices = ClassChoices( name="frontend", classes=dict( @@ -99,7 +69,6 @@ frontend_choices = ClassChoices( wav_frontend=WavFrontend, multichannelfrontend=MultiChannelFrontend, ), - type_check=AbsFrontend, default="default", ) specaug_choices = ClassChoices( @@ -108,32 +77,17 @@ specaug_choices = ClassChoices( specaug=SpecAug, specaug_lfr=SpecAugLFR, ), - type_check=AbsSpecAug, default=None, - optional=True, ) -# specaug_choices = {"specaug":SpecAug} normalize_choices = ClassChoices( "normalize", classes=dict( global_mvn=GlobalMVN, utterance_mvn=UtteranceMVN, ), - type_check=AbsNormalize, default=None, - optional=True, ) -preencoder_choices = ClassChoices( - name="preencoder", - classes=dict( - sinc=LightweightSincConvs, - linear=LinearProjection, - ), - type_check=AbsPreEncoder, - default=None, - optional=True, -) encoder_choices = ClassChoices( "encoder", classes=dict( @@ -145,52 +99,20 @@ encoder_choices = ClassChoices( data2vec_encoder=Data2VecEncoder, mfcca_enc=MFCCAEncoder, chunk_conformer=ConformerChunkEncoder, - ), - type_check=AbsEncoder, - default="rnn", -) -encoder_choices2 = ClassChoices( - "encoder2", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - ), - type_check=AbsEncoder, - default="rnn", -) -asr_encoder_choices = ClassChoices( - "asr_encoder", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - data2vec_encoder=Data2VecEncoder, - mfcca_enc=MFCCAEncoder, - ), - type_check=AbsEncoder, - default="rnn", -) -spk_encoder_choices = ClassChoices( - "spk_encoder", - classes=dict( + fsmn=FSMN, + branchformer=BranchformerEncoder, + e_branchformer=EBranchformerEncoder, + resnet34=ResNet34Diar, + resnet34_sp_l2reg=ResNet34SpL2RegDiar, + ecapa_tdnn=ECAPA_TDNN, + eend_ola_transformer=EENDOLATransformerEncoder, + conv=ConvEncoder, resnet34_diar=ResNet34Diar, ), - default="resnet34_diar", -) -postencoder_choices = ClassChoices( - name="postencoder", - classes=dict( - hugging_face_transformers=HuggingFaceTransformersPostEncoder, - ), - type_check=AbsPostEncoder, - default=None, - optional=True, + default="rnn", ) + + decoder_choices = ClassChoices( "decoder", classes=dict( @@ -205,42 +127,18 @@ decoder_choices = ClassChoices( paraformer_decoder_san=ParaformerDecoderSAN, contextual_paraformer_decoder=ContextualParaformerDecoder, sa_decoder=SAAsrTransformerDecoder, - ), - type_check=AbsDecoder, - default="rnn", -) -decoder_choices2 = ClassChoices( - "decoder2", - classes=dict( - transformer=TransformerDecoder, - lightweight_conv=LightweightConvolutionTransformerDecoder, - lightweight_conv2d=LightweightConvolution2DTransformerDecoder, - dynamic_conv=DynamicConvolutionTransformerDecoder, - dynamic_conv2d=DynamicConvolution2DTransformerDecoder, - rnn=RNNDecoder, - fsmn_scama_opt=FsmnDecoderSCAMAOpt, - paraformer_decoder_sanm=ParaformerSANMDecoder, - ), - type_check=AbsDecoder, - default="rnn", -) - -rnnt_decoder_choices = ClassChoices( - "rnnt_decoder", - classes=dict( rnnt=RNNTDecoder, ), - type_check=RNNTDecoder, - default="rnnt", + default="transformer", ) + joint_network_choices = ClassChoices( name="joint_network", classes=dict( joint_network=JointNetwork, ), default="joint_network", - optional=True, ) predictor_choices = ClassChoices( @@ -252,27 +150,13 @@ predictor_choices = ClassChoices( cif_predictor_v3=CifPredictorV3, bat_predictor=BATPredictor, ), - type_check=None, default="cif_predictor", - optional=True, -) -predictor_choices2 = ClassChoices( - name="predictor2", - classes=dict( - cif_predictor=CifPredictor, - ctc_predictor=None, - cif_predictor_v2=CifPredictorV2, - ), - type_check=None, - default="cif_predictor", - optional=True, ) + stride_conv_choices = ClassChoices( name="stride_conv", classes=dict( stride_conv1d=Conv1dSubsampling ), - type_check=None, default="stride_conv1d", - optional=True, ) \ No newline at end of file diff --git a/funasr/models/whisper_models/__init__.py b/funasr/models/mossformer/__init__.py similarity index 100% rename from funasr/models/whisper_models/__init__.py rename to funasr/models/mossformer/__init__.py diff --git a/funasr/models/e2e_ss.py b/funasr/models/mossformer/e2e_ss.py similarity index 100% rename from funasr/models/e2e_ss.py rename to funasr/models/mossformer/e2e_ss.py diff --git a/funasr/modules/mossformer.py b/funasr/models/mossformer/mossformer.py similarity index 100% rename from funasr/modules/mossformer.py rename to funasr/models/mossformer/mossformer.py diff --git a/funasr/models/decoder/mossformer_decoder.py b/funasr/models/mossformer/mossformer_decoder.py similarity index 100% rename from funasr/models/decoder/mossformer_decoder.py rename to funasr/models/mossformer/mossformer_decoder.py diff --git a/funasr/models/encoder/mossformer_encoder.py b/funasr/models/mossformer/mossformer_encoder.py similarity index 98% rename from funasr/models/encoder/mossformer_encoder.py rename to funasr/models/mossformer/mossformer_encoder.py index 6c092e713..d06af999d 100644 --- a/funasr/models/encoder/mossformer_encoder.py +++ b/funasr/models/mossformer/mossformer_encoder.py @@ -5,9 +5,9 @@ try: from rotary_embedding_torch import RotaryEmbedding except: print("Please install rotary_embedding_torch by: \n pip install -U rotary_embedding_torch") -from funasr.modules.layer_norm import GlobalLayerNorm, CumulativeLayerNorm, ScaleNorm -from funasr.modules.embedding import ScaledSinuEmbedding -from funasr.modules.mossformer import FLASH_ShareA_FFConvM +from funasr.models.transformer.layer_norm import GlobalLayerNorm, CumulativeLayerNorm, ScaleNorm +from funasr.models.transformer.embedding import ScaledSinuEmbedding +from funasr.models.transformer.mossformer import FLASH_ShareA_FFConvM def select_norm(norm, dim, shape): diff --git a/funasr/modules/__init__.py b/funasr/models/neat_contextual_paraformer/__init__.py similarity index 100% rename from funasr/modules/__init__.py rename to funasr/models/neat_contextual_paraformer/__init__.py diff --git a/funasr/modules/beam_search/__init__.py b/funasr/models/normalize/__init__.py similarity index 100% rename from funasr/modules/beam_search/__init__.py rename to funasr/models/normalize/__init__.py diff --git a/funasr/layers/global_mvn.py b/funasr/models/normalize/global_mvn.py similarity index 93% rename from funasr/layers/global_mvn.py rename to funasr/models/normalize/global_mvn.py index b94e9cac7..a9b793526 100644 --- a/funasr/layers/global_mvn.py +++ b/funasr/models/normalize/global_mvn.py @@ -5,12 +5,10 @@ from typing import Union import numpy as np import torch -from funasr.modules.nets_utils import make_pad_mask -from funasr.layers.abs_normalize import AbsNormalize -from funasr.layers.inversible_interface import InversibleInterface +from funasr.models.transformer.utils.nets_utils import make_pad_mask -class GlobalMVN(AbsNormalize, InversibleInterface): +class GlobalMVN(torch.nn.Module): """Apply global mean and variance normalization TODO(kamo): Make this class portable somehow Args: diff --git a/funasr/layers/utterance_mvn.py b/funasr/models/normalize/utterance_mvn.py similarity index 93% rename from funasr/layers/utterance_mvn.py rename to funasr/models/normalize/utterance_mvn.py index 7722974f3..609c7aa08 100644 --- a/funasr/layers/utterance_mvn.py +++ b/funasr/models/normalize/utterance_mvn.py @@ -2,11 +2,10 @@ from typing import Tuple import torch -from funasr.modules.nets_utils import make_pad_mask -from funasr.layers.abs_normalize import AbsNormalize +from funasr.models.transformer.utils.nets_utils import make_pad_mask -class UtteranceMVN(AbsNormalize): +class UtteranceMVN(torch.nn.Module): def __init__( self, norm_means: bool = True, diff --git a/funasr/models/predictor/cif.py b/funasr/models/paraformer/cif_predictor.py similarity index 96% rename from funasr/models/predictor/cif.py rename to funasr/models/paraformer/cif_predictor.py index 5f18c4d1d..7cc088f02 100644 --- a/funasr/models/predictor/cif.py +++ b/funasr/models/paraformer/cif_predictor.py @@ -3,9 +3,9 @@ from torch import nn from torch import Tensor import logging import numpy as np -from funasr.torch_utils.device_funcs import to_device -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.streaming_utils.utils import sequence_mask +from funasr.train_utils.device_funcs import to_device +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.scama.utils import sequence_mask from typing import Optional, Tuple class CifPredictor(nn.Module): @@ -551,8 +551,8 @@ class CifPredictorV3(nn.Module): elif self.upsample_type == 'cnn_attn': self.upsample_cnn = nn.ConvTranspose1d(idim, idim, self.upsample_times, self.upsample_times) from funasr.models.encoder.transformer_encoder import EncoderLayer as TransformerEncoderLayer - from funasr.modules.attention import MultiHeadedAttention - from funasr.modules.positionwise_feed_forward import PositionwiseFeedForward + from funasr.models.transformer.attention import MultiHeadedAttention + from funasr.models.transformer.positionwise_feed_forward import PositionwiseFeedForward positionwise_layer_args = ( idim, idim*2, diff --git a/funasr/models/decoder/contextual_decoder.py b/funasr/models/paraformer/contextual_decoder.py similarity index 98% rename from funasr/models/decoder/contextual_decoder.py rename to funasr/models/paraformer/contextual_decoder.py index c94e1796f..626cdef3e 100644 --- a/funasr/models/decoder/contextual_decoder.py +++ b/funasr/models/paraformer/contextual_decoder.py @@ -5,14 +5,14 @@ import torch import torch.nn as nn import numpy as np -from funasr.modules.streaming_utils import utils as myutils +from funasr.models.scama import utils as myutils from funasr.models.decoder.transformer_decoder import BaseTransformerDecoder -from funasr.modules.attention import MultiHeadedAttentionSANMDecoder, MultiHeadedAttentionCrossAtt -from funasr.modules.embedding import PositionalEncoding -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM -from funasr.modules.repeat import repeat +from funasr.models.transformer.attention import MultiHeadedAttentionSANMDecoder, MultiHeadedAttentionCrossAtt +from funasr.models.transformer.embedding import PositionalEncoding +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM +from funasr.models.transformer.repeat import repeat from funasr.models.decoder.sanm_decoder import DecoderLayerSANM, ParaformerSANMDecoder diff --git a/funasr/models/paraformer/model.py b/funasr/models/paraformer/model.py index 50e7cd7aa..46bd7b0db 100644 --- a/funasr/models/paraformer/model.py +++ b/funasr/models/paraformer/model.py @@ -29,10 +29,10 @@ from funasr.losses.label_smoothing_loss import ( from funasr.models.predictor.cif import mae_loss # from funasr.models.preencoder.abs_preencoder import AbsPreEncoder # from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.modules.add_sos_eos import add_sos_eos -from funasr.modules.nets_utils import make_pad_mask, pad_list -from funasr.modules.nets_utils import th_accuracy -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.models.transformer.add_sos_eos import add_sos_eos +from funasr.models.transformer.utils.nets_utils import make_pad_mask, pad_list +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.train_utils.device_funcs import force_gatherable # from funasr.models.base_model import FunASRModel # from funasr.models.predictor.cif import CifPredictorV3 from funasr.models.paraformer.search import Hypothesis @@ -48,7 +48,7 @@ else: yield from funasr.datasets.fun_datasets.load_audio_extract_fbank import load_audio, extract_fbank from funasr.utils import postprocess_utils -from funasr.fileio.datadir_writer import DatadirWriter +from funasr.utils.datadir_writer import DatadirWriter from funasr.utils.timestamp_tools import ts_prediction_lfr6_standard class Paraformer(nn.Module): @@ -423,8 +423,8 @@ class Paraformer(nn.Module): **kwargs, ): from funasr.models.paraformer.search import BeamSearchPara - from funasr.modules.scorers.ctc import CTCPrefixScorer - from funasr.modules.scorers.length_bonus import LengthBonus + from funasr.models.transformer.scorers.ctc import CTCPrefixScorer + from funasr.models.transformer.scorers.length_bonus import LengthBonus # 1. Build ASR model scorers = {} @@ -1355,7 +1355,7 @@ class ParaformerOnline(Paraformer): self.scama_mask = None if hasattr(self.encoder, "overlap_chunk_cls") and self.encoder.overlap_chunk_cls is not None: - from funasr.modules.streaming_utils.chunk_utilis import build_scama_mask_for_cross_attention_decoder + from funasr.models.scama.chunk_utilis import build_scama_mask_for_cross_attention_decoder self.build_scama_mask_for_cross_attention_decoder_fn = build_scama_mask_for_cross_attention_decoder self.decoder_attention_chunk_type = kwargs.get("decoder_attention_chunk_type", "chunk") diff --git a/funasr/models/paraformer/search.py b/funasr/models/paraformer/search.py index 440b48e6d..878902531 100644 --- a/funasr/models/paraformer/search.py +++ b/funasr/models/paraformer/search.py @@ -9,9 +9,9 @@ from typing import Union import torch -from funasr.modules.e2e_asr_common import end_detect -from funasr.modules.scorers.scorer_interface import PartialScorerInterface -from funasr.modules.scorers.scorer_interface import ScorerInterface +from funasr.metrics import end_detect +from funasr.models.transformer.scorers.scorer_interface import PartialScorerInterface +from funasr.models.transformer.scorers.scorer_interface import ScorerInterface class Hypothesis(NamedTuple): """Hypothesis data type.""" diff --git a/funasr/modules/data2vec/__init__.py b/funasr/models/paraformer_online/__init__.py similarity index 100% rename from funasr/modules/data2vec/__init__.py rename to funasr/models/paraformer_online/__init__.py diff --git a/funasr/models/postencoder/abs_postencoder.py b/funasr/models/postencoder/abs_postencoder.py deleted file mode 100644 index f5ac03be2..000000000 --- a/funasr/models/postencoder/abs_postencoder.py +++ /dev/null @@ -1,17 +0,0 @@ -from abc import ABC -from abc import abstractmethod -from typing import Tuple - -import torch - - -class AbsPostEncoder(torch.nn.Module, ABC): - @abstractmethod - def output_size(self) -> int: - raise NotImplementedError - - @abstractmethod - def forward( - self, input: torch.Tensor, input_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - raise NotImplementedError diff --git a/funasr/models/postencoder/hugging_face_transformers_postencoder.py b/funasr/models/postencoder/hugging_face_transformers_postencoder.py deleted file mode 100644 index c59e2b779..000000000 --- a/funasr/models/postencoder/hugging_face_transformers_postencoder.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python3 -# 2021, University of Stuttgart; Pavel Denisov -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -"""Hugging Face Transformers PostEncoder.""" - -from funasr.modules.nets_utils import make_pad_mask -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from typing import Tuple - -import copy -import logging -import torch - -try: - from transformers import AutoModel - - is_transformers_available = True -except ImportError: - is_transformers_available = False - - -class HuggingFaceTransformersPostEncoder(AbsPostEncoder): - """Hugging Face Transformers PostEncoder.""" - - def __init__( - self, - input_size: int, - model_name_or_path: str, - ): - """Initialize the module.""" - super().__init__() - - if not is_transformers_available: - raise ImportError( - "`transformers` is not available. Please install it via `pip install" - " transformers` or `cd /path/to/espnet/tools && . ./activate_python.sh" - " && ./installers/install_transformers.sh`." - ) - - model = AutoModel.from_pretrained(model_name_or_path) - - if hasattr(model, "encoder"): - self.transformer = model.encoder - else: - self.transformer = model - - if hasattr(self.transformer, "embed_tokens"): - del self.transformer.embed_tokens - if hasattr(self.transformer, "wte"): - del self.transformer.wte - if hasattr(self.transformer, "word_embedding"): - del self.transformer.word_embedding - - self.pretrained_params = copy.deepcopy(self.transformer.state_dict()) - - if ( - self.transformer.config.is_encoder_decoder - or self.transformer.config.model_type in ["xlnet", "t5"] - ): - self.use_inputs_embeds = True - self.extend_attention_mask = False - elif self.transformer.config.model_type == "gpt2": - self.use_inputs_embeds = True - self.extend_attention_mask = True - else: - self.use_inputs_embeds = False - self.extend_attention_mask = True - - self.linear_in = torch.nn.Linear( - input_size, self.transformer.config.hidden_size - ) - - def forward( - self, input: torch.Tensor, input_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Forward.""" - input = self.linear_in(input) - - args = {"return_dict": True} - - mask = (~make_pad_mask(input_lengths)).to(input.device).float() - - if self.extend_attention_mask: - args["attention_mask"] = _extend_attention_mask(mask) - else: - args["attention_mask"] = mask - - if self.use_inputs_embeds: - args["inputs_embeds"] = input - else: - args["hidden_states"] = input - - if self.transformer.config.model_type == "mpnet": - args["head_mask"] = [None for _ in self.transformer.layer] - - output = self.transformer(**args).last_hidden_state - - return output, input_lengths - - def reload_pretrained_parameters(self): - self.transformer.load_state_dict(self.pretrained_params) - logging.info("Pretrained Transformers model parameters reloaded!") - - def output_size(self) -> int: - """Get the output size.""" - return self.transformer.config.hidden_size - - -def _extend_attention_mask(mask: torch.Tensor) -> torch.Tensor: - mask = mask[:, None, None, :] - mask = (1.0 - mask) * -10000.0 - return mask diff --git a/funasr/models/preencoder/abs_preencoder.py b/funasr/models/preencoder/abs_preencoder.py deleted file mode 100644 index 3ecdc6b91..000000000 --- a/funasr/models/preencoder/abs_preencoder.py +++ /dev/null @@ -1,17 +0,0 @@ -from abc import ABC -from abc import abstractmethod -from typing import Tuple - -import torch - - -class AbsPreEncoder(torch.nn.Module, ABC): - @abstractmethod - def output_size(self) -> int: - raise NotImplementedError - - @abstractmethod - def forward( - self, input: torch.Tensor, input_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - raise NotImplementedError diff --git a/funasr/models/preencoder/linear.py b/funasr/models/preencoder/linear.py deleted file mode 100644 index 25f6720b1..000000000 --- a/funasr/models/preencoder/linear.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 -# 2021, Carnegie Mellon University; Xuankai Chang -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -"""Linear Projection.""" - -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from typing import Tuple - -import torch - - -class LinearProjection(AbsPreEncoder): - """Linear Projection Preencoder.""" - - def __init__( - self, - input_size: int, - output_size: int, - ): - """Initialize the module.""" - super().__init__() - - self.output_dim = output_size - self.linear_out = torch.nn.Linear(input_size, output_size) - - def forward( - self, input: torch.Tensor, input_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Forward.""" - output = self.linear_out(input) - return output, input_lengths # no state in this layer - - def output_size(self) -> int: - """Get the output size.""" - return self.output_dim diff --git a/funasr/models/preencoder/sinc.py b/funasr/models/preencoder/sinc.py deleted file mode 100644 index 3baa4a872..000000000 --- a/funasr/models/preencoder/sinc.py +++ /dev/null @@ -1,279 +0,0 @@ -#!/usr/bin/env python3 -# 2020, Technische Universität München; Ludwig Kürzinger -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -"""Sinc convolutions for raw audio input.""" - -from collections import OrderedDict -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.layers.sinc_conv import LogCompression -from funasr.layers.sinc_conv import SincConv -import humanfriendly -import torch -from typing import Optional -from typing import Tuple -from typing import Union - - -class LightweightSincConvs(AbsPreEncoder): - """Lightweight Sinc Convolutions. - - Instead of using precomputed features, end-to-end speech recognition - can also be done directly from raw audio using sinc convolutions, as - described in "Lightweight End-to-End Speech Recognition from Raw Audio - Data Using Sinc-Convolutions" by Kürzinger et al. - https://arxiv.org/abs/2010.07597 - - To use Sinc convolutions in your model instead of the default f-bank - frontend, set this module as your pre-encoder with `preencoder: sinc` - and use the input of the sliding window frontend with - `frontend: sliding_window` in your yaml configuration file. - So that the process flow is: - - Frontend (SlidingWindow) -> SpecAug -> Normalization -> - Pre-encoder (LightweightSincConvs) -> Encoder -> Decoder - - Note that this method also performs data augmentation in time domain - (vs. in spectral domain in the default frontend). - Use `plot_sinc_filters.py` to visualize the learned Sinc filters. - """ - - def __init__( - self, - fs: Union[int, str, float] = 16000, - in_channels: int = 1, - out_channels: int = 256, - activation_type: str = "leakyrelu", - dropout_type: str = "dropout", - windowing_type: str = "hamming", - scale_type: str = "mel", - ): - """Initialize the module. - - Args: - fs: Sample rate. - in_channels: Number of input channels. - out_channels: Number of output channels (for each input channel). - activation_type: Choice of activation function. - dropout_type: Choice of dropout function. - windowing_type: Choice of windowing function. - scale_type: Choice of filter-bank initialization scale. - """ - super().__init__() - if isinstance(fs, str): - fs = humanfriendly.parse_size(fs) - self.fs = fs - self.in_channels = in_channels - self.out_channels = out_channels - self.activation_type = activation_type - self.dropout_type = dropout_type - self.windowing_type = windowing_type - self.scale_type = scale_type - - self.choices_dropout = { - "dropout": torch.nn.Dropout, - "spatial": SpatialDropout, - "dropout2d": torch.nn.Dropout2d, - } - if dropout_type not in self.choices_dropout: - raise NotImplementedError( - f"Dropout type has to be one of " - f"{list(self.choices_dropout.keys())}", - ) - - self.choices_activation = { - "leakyrelu": torch.nn.LeakyReLU, - "relu": torch.nn.ReLU, - } - if activation_type not in self.choices_activation: - raise NotImplementedError( - f"Activation type has to be one of " - f"{list(self.choices_activation.keys())}", - ) - - # initialization - self._create_sinc_convs() - # Sinc filters require custom initialization - self.espnet_initialization_fn() - - def _create_sinc_convs(self): - blocks = OrderedDict() - - # SincConvBlock - out_channels = 128 - self.filters = SincConv( - self.in_channels, - out_channels, - kernel_size=101, - stride=1, - fs=self.fs, - window_func=self.windowing_type, - scale_type=self.scale_type, - ) - block = OrderedDict( - [ - ("Filters", self.filters), - ("LogCompression", LogCompression()), - ("BatchNorm", torch.nn.BatchNorm1d(out_channels, affine=True)), - ("AvgPool", torch.nn.AvgPool1d(2)), - ] - ) - blocks["SincConvBlock"] = torch.nn.Sequential(block) - in_channels = out_channels - - # First convolutional block, connects the sinc output to the front-end "body" - out_channels = 128 - blocks["DConvBlock1"] = self.gen_lsc_block( - in_channels, - out_channels, - depthwise_kernel_size=25, - depthwise_stride=2, - pointwise_groups=0, - avgpool=True, - dropout_probability=0.1, - ) - in_channels = out_channels - - # Second convolutional block, multiple convolutional layers - out_channels = self.out_channels - for layer in [2, 3, 4]: - blocks[f"DConvBlock{layer}"] = self.gen_lsc_block( - in_channels, out_channels, depthwise_kernel_size=9, depthwise_stride=1 - ) - in_channels = out_channels - - # Third Convolutional block, acts as coupling to encoder - out_channels = self.out_channels - blocks["DConvBlock5"] = self.gen_lsc_block( - in_channels, - out_channels, - depthwise_kernel_size=7, - depthwise_stride=1, - pointwise_groups=0, - ) - - self.blocks = torch.nn.Sequential(blocks) - - def gen_lsc_block( - self, - in_channels: int, - out_channels: int, - depthwise_kernel_size: int = 9, - depthwise_stride: int = 1, - depthwise_groups=None, - pointwise_groups=0, - dropout_probability: float = 0.15, - avgpool=False, - ): - """Generate a convolutional block for Lightweight Sinc convolutions. - - Each block consists of either a depthwise or a depthwise-separable - convolutions together with dropout, (batch-)normalization layer, and - an optional average-pooling layer. - - Args: - in_channels: Number of input channels. - out_channels: Number of output channels. - depthwise_kernel_size: Kernel size of the depthwise convolution. - depthwise_stride: Stride of the depthwise convolution. - depthwise_groups: Number of groups of the depthwise convolution. - pointwise_groups: Number of groups of the pointwise convolution. - dropout_probability: Dropout probability in the block. - avgpool: If True, an AvgPool layer is inserted. - - Returns: - torch.nn.Sequential: Neural network building block. - """ - block = OrderedDict() - if not depthwise_groups: - # GCD(in_channels, out_channels) to prevent size mismatches - depthwise_groups, r = in_channels, out_channels - while r != 0: - depthwise_groups, r = depthwise_groups, depthwise_groups % r - block["depthwise"] = torch.nn.Conv1d( - in_channels, - out_channels, - depthwise_kernel_size, - depthwise_stride, - groups=depthwise_groups, - ) - if pointwise_groups: - block["pointwise"] = torch.nn.Conv1d( - out_channels, out_channels, 1, 1, groups=pointwise_groups - ) - block["activation"] = self.choices_activation[self.activation_type]() - block["batchnorm"] = torch.nn.BatchNorm1d(out_channels, affine=True) - if avgpool: - block["avgpool"] = torch.nn.AvgPool1d(2) - block["dropout"] = self.choices_dropout[self.dropout_type](dropout_probability) - return torch.nn.Sequential(block) - - def espnet_initialization_fn(self): - """Initialize sinc filters with filterbank values.""" - self.filters.init_filters() - for block in self.blocks: - for layer in block: - if type(layer) == torch.nn.BatchNorm1d and layer.affine: - layer.weight.data[:] = 1.0 - layer.bias.data[:] = 0.0 - - def forward( - self, input: torch.Tensor, input_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Apply Lightweight Sinc Convolutions. - - The input shall be formatted as (B, T, C_in, D_in) - with B as batch size, T as time dimension, C_in as channels, - and D_in as feature dimension. - - The output will then be (B, T, C_out*D_out) - with C_out and D_out as output dimensions. - - The current module structure only handles D_in=400, so that D_out=1. - Remark for the multichannel case: C_out is the number of out_channels - given at initialization multiplied with C_in. - """ - # Transform input data: - # (B, T, C_in, D_in) -> (B*T, C_in, D_in) - B, T, C_in, D_in = input.size() - input_frames = input.view(B * T, C_in, D_in) - output_frames = self.blocks.forward(input_frames) - - # ---TRANSFORM: (B*T, C_out, D_out) -> (B, T, C_out*D_out) - _, C_out, D_out = output_frames.size() - output_frames = output_frames.view(B, T, C_out * D_out) - return output_frames, input_lengths # no state in this layer - - def output_size(self) -> int: - """Get the output size.""" - return self.out_channels * self.in_channels - - -class SpatialDropout(torch.nn.Module): - """Spatial dropout module. - - Apply dropout to full channels on tensors of input (B, C, D) - """ - - def __init__( - self, - dropout_probability: float = 0.15, - shape: Optional[Union[tuple, list]] = None, - ): - """Initialize. - - Args: - dropout_probability: Dropout probability. - shape (tuple, list): Shape of input tensors. - """ - super().__init__() - if shape is None: - shape = (0, 2, 1) - self.dropout = torch.nn.Dropout2d(dropout_probability) - self.shape = (shape,) - - def forward(self, x: torch.Tensor) -> torch.Tensor: - """Forward of spatial dropout module.""" - y = x.permute(*self.shape) - y = self.dropout(y) - return y.permute(*self.shape) diff --git a/funasr/modules/eend_ola/__init__.py b/funasr/models/rwkv_bat/__init__.py similarity index 100% rename from funasr/modules/eend_ola/__init__.py rename to funasr/models/rwkv_bat/__init__.py diff --git a/funasr/modules/cuda_decoder/wkv_cuda.cu b/funasr/models/rwkv_bat/cuda_decoder/wkv_cuda.cu similarity index 100% rename from funasr/modules/cuda_decoder/wkv_cuda.cu rename to funasr/models/rwkv_bat/cuda_decoder/wkv_cuda.cu diff --git a/funasr/modules/cuda_decoder/wkv_op.cpp b/funasr/models/rwkv_bat/cuda_decoder/wkv_op.cpp similarity index 100% rename from funasr/modules/cuda_decoder/wkv_op.cpp rename to funasr/models/rwkv_bat/cuda_decoder/wkv_op.cpp diff --git a/funasr/modules/cuda_encoder/wkv_cuda.cu b/funasr/models/rwkv_bat/cuda_encoder/wkv_cuda.cu similarity index 100% rename from funasr/modules/cuda_encoder/wkv_cuda.cu rename to funasr/models/rwkv_bat/cuda_encoder/wkv_cuda.cu diff --git a/funasr/modules/cuda_encoder/wkv_op.cpp b/funasr/models/rwkv_bat/cuda_encoder/wkv_op.cpp similarity index 100% rename from funasr/modules/cuda_encoder/wkv_op.cpp rename to funasr/models/rwkv_bat/cuda_encoder/wkv_op.cpp diff --git a/egs/wenetspeech/conformer/local/path.sh b/funasr/models/rwkv_bat/model.py similarity index 100% rename from egs/wenetspeech/conformer/local/path.sh rename to funasr/models/rwkv_bat/model.py diff --git a/funasr/modules/rwkv.py b/funasr/models/rwkv_bat/rwkv.py similarity index 95% rename from funasr/modules/rwkv.py rename to funasr/models/rwkv_bat/rwkv.py index f020828f7..422e1c8fe 100644 --- a/funasr/modules/rwkv.py +++ b/funasr/models/rwkv_bat/rwkv.py @@ -8,9 +8,9 @@ from typing import Dict, Optional, Tuple import torch -from funasr.modules.rwkv_attention import EncoderSelfAttention, DecoderSelfAttention -from funasr.modules.rwkv_feed_forward import FeedForward -from funasr.modules.layer_norm import LayerNorm +from funasr.models.rwkv_bat.rwkv_attention import EncoderSelfAttention, DecoderSelfAttention +from funasr.models.rwkv_bat.rwkv_feed_forward import FeedForward +from funasr.models.transformer.layer_norm import LayerNorm class RWKV(torch.nn.Module): """RWKV module. diff --git a/funasr/modules/rwkv_attention.py b/funasr/models/rwkv_bat/rwkv_attention.py similarity index 100% rename from funasr/modules/rwkv_attention.py rename to funasr/models/rwkv_bat/rwkv_attention.py diff --git a/funasr/models/encoder/rwkv_encoder.py b/funasr/models/rwkv_bat/rwkv_encoder.py similarity index 94% rename from funasr/models/encoder/rwkv_encoder.py rename to funasr/models/rwkv_bat/rwkv_encoder.py index 40151bf43..345429985 100644 --- a/funasr/models/encoder/rwkv_encoder.py +++ b/funasr/models/rwkv_bat/rwkv_encoder.py @@ -6,10 +6,10 @@ from typing import Dict, List, Optional, Tuple import torch from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.modules.rwkv import RWKV -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.rwkv_subsampling import RWKVConvInput -from funasr.modules.nets_utils import make_source_mask +from funasr.models.rwkv_bat.rwkv import RWKV +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.rwkv_bat.rwkv_subsampling import RWKVConvInput +from funasr.models.transformer.utils.nets_utils import make_source_mask class RWKVEncoder(AbsEncoder): """RWKV encoder module. diff --git a/funasr/modules/rwkv_feed_forward.py b/funasr/models/rwkv_bat/rwkv_feed_forward.py similarity index 100% rename from funasr/modules/rwkv_feed_forward.py rename to funasr/models/rwkv_bat/rwkv_feed_forward.py diff --git a/funasr/modules/rwkv_subsampling.py b/funasr/models/rwkv_bat/rwkv_subsampling.py similarity index 97% rename from funasr/modules/rwkv_subsampling.py rename to funasr/models/rwkv_bat/rwkv_subsampling.py index 427709312..54ad1f5ad 100644 --- a/funasr/modules/rwkv_subsampling.py +++ b/funasr/models/rwkv_bat/rwkv_subsampling.py @@ -8,10 +8,10 @@ import numpy as np import torch import torch.nn.functional as F -from funasr.modules.embedding import PositionalEncoding +from funasr.models.transformer.embedding import PositionalEncoding import logging -from funasr.modules.streaming_utils.utils import sequence_mask -from funasr.modules.nets_utils import sub_factor_to_params, pad_to_len +from funasr.models.scama.utils import sequence_mask +from funasr.models.transformer.utils.nets_utils import sub_factor_to_params, pad_to_len from typing import Optional, Tuple, Union import math diff --git a/funasr/modules/eend_ola/utils/__init__.py b/funasr/models/sa_asr/__init__.py similarity index 100% rename from funasr/modules/eend_ola/utils/__init__.py rename to funasr/models/sa_asr/__init__.py diff --git a/funasr/modules/beam_search/beam_search_sa_asr.py b/funasr/models/sa_asr/beam_search_sa_asr.py similarity index 98% rename from funasr/modules/beam_search/beam_search_sa_asr.py rename to funasr/models/sa_asr/beam_search_sa_asr.py index b2b6833c8..6454bc0ec 100755 --- a/funasr/modules/beam_search/beam_search_sa_asr.py +++ b/funasr/models/sa_asr/beam_search_sa_asr.py @@ -11,9 +11,9 @@ from typing import Union import torch -from funasr.modules.e2e_asr_common import end_detect -from funasr.modules.scorers.scorer_interface import PartialScorerInterface -from funasr.modules.scorers.scorer_interface import ScorerInterface +from funasr.metrics import end_detect +from funasr.models.transformer.scorers.scorer_interface import PartialScorerInterface +from funasr.models.transformer.scorers.scorer_interface import ScorerInterface from funasr.models.decoder.abs_decoder import AbsDecoder diff --git a/funasr/models/e2e_sa_asr.py b/funasr/models/sa_asr/e2e_sa_asr.py similarity index 98% rename from funasr/models/e2e_sa_asr.py rename to funasr/models/sa_asr/e2e_sa_asr.py index cf1587d17..e0cb69a50 100644 --- a/funasr/models/e2e_sa_asr.py +++ b/funasr/models/sa_asr/e2e_sa_asr.py @@ -24,10 +24,10 @@ from funasr.models.frontend.abs_frontend import AbsFrontend from funasr.models.postencoder.abs_postencoder import AbsPostEncoder from funasr.models.preencoder.abs_preencoder import AbsPreEncoder from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.modules.add_sos_eos import add_sos_eos -from funasr.modules.e2e_asr_common import ErrorCalculator -from funasr.modules.nets_utils import th_accuracy -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.models.transformer.add_sos_eos import add_sos_eos +from funasr.metrics import ErrorCalculator +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.train_utils.device_funcs import force_gatherable from funasr.models.base_model import FunASRModel if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): diff --git a/funasr/modules/lora/__init__.py b/funasr/models/sanm/__init__.py similarity index 100% rename from funasr/modules/lora/__init__.py rename to funasr/models/sanm/__init__.py diff --git a/funasr/models/decoder/sanm_decoder.py b/funasr/models/sanm/sanm_decoder.py similarity index 99% rename from funasr/models/decoder/sanm_decoder.py rename to funasr/models/sanm/sanm_decoder.py index ff35e463c..cb38c12ce 100644 --- a/funasr/models/decoder/sanm_decoder.py +++ b/funasr/models/sanm/sanm_decoder.py @@ -5,14 +5,14 @@ import torch import torch.nn as nn import numpy as np -from funasr.modules.streaming_utils import utils as myutils +from funasr.models.scama import utils as myutils from funasr.models.decoder.transformer_decoder import BaseTransformerDecoder -from funasr.modules.attention import MultiHeadedAttentionSANMDecoder, MultiHeadedAttentionCrossAtt -from funasr.modules.embedding import PositionalEncoding -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM -from funasr.modules.repeat import repeat +from funasr.models.transformer.attention import MultiHeadedAttentionSANMDecoder, MultiHeadedAttentionCrossAtt +from funasr.models.transformer.embedding import PositionalEncoding +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.positionwise_feed_forward import PositionwiseFeedForwardDecoderSANM +from funasr.models.transformer.repeat import repeat class DecoderLayerSANM(nn.Module): diff --git a/funasr/models/encoder/sanm_encoder.py b/funasr/models/sanm/sanm_encoder.py similarity index 97% rename from funasr/models/encoder/sanm_encoder.py rename to funasr/models/sanm/sanm_encoder.py index c15343efb..83edbe739 100644 --- a/funasr/models/encoder/sanm_encoder.py +++ b/funasr/models/sanm/sanm_encoder.py @@ -7,26 +7,26 @@ import logging import torch import torch.nn as nn import torch.nn.functional as F -from funasr.modules.streaming_utils.chunk_utilis import overlap_chunk +from funasr.models.scama.chunk_utilis import overlap_chunk import numpy as np -from funasr.torch_utils.device_funcs import to_device -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.attention import MultiHeadedAttention, MultiHeadedAttentionSANM, MultiHeadedAttentionSANMwithMask -from funasr.modules.embedding import SinusoidalPositionEncoder, StreamSinusoidalPositionEncoder -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.multi_layer_conv import Conv1dLinear -from funasr.modules.multi_layer_conv import MultiLayeredConv1d -from funasr.modules.positionwise_feed_forward import ( +from funasr.train_utils.device_funcs import to_device +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.attention import MultiHeadedAttention, MultiHeadedAttentionSANM, MultiHeadedAttentionSANMwithMask +from funasr.models.transformer.embedding import SinusoidalPositionEncoder, StreamSinusoidalPositionEncoder +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.utils.multi_layer_conv import Conv1dLinear +from funasr.models.transformer.utils.multi_layer_conv import MultiLayeredConv1d +from funasr.models.transformer.positionwise_feed_forward import ( PositionwiseFeedForward, # noqa: H301 ) -from funasr.modules.repeat import repeat -from funasr.modules.subsampling import Conv2dSubsampling -from funasr.modules.subsampling import Conv2dSubsampling2 -from funasr.modules.subsampling import Conv2dSubsampling6 -from funasr.modules.subsampling import Conv2dSubsampling8 -from funasr.modules.subsampling import TooShortUttError -from funasr.modules.subsampling import check_short_utt -from funasr.modules.mask import subsequent_mask, vad_mask +from funasr.models.transformer.repeat import repeat +from funasr.models.transformer.subsampling import Conv2dSubsampling +from funasr.models.transformer.subsampling import Conv2dSubsampling2 +from funasr.models.transformer.subsampling import Conv2dSubsampling6 +from funasr.models.transformer.subsampling import Conv2dSubsampling8 +from funasr.models.transformer.subsampling import TooShortUttError +from funasr.models.transformer.subsampling import check_short_utt +from funasr.models.transformer.utils.mask import subsequent_mask, vad_mask from funasr.models.ctc import CTC from funasr.models.encoder.abs_encoder import AbsEncoder diff --git a/funasr/modules/streaming_utils/__init__.py b/funasr/models/scama/__init__.py similarity index 100% rename from funasr/modules/streaming_utils/__init__.py rename to funasr/models/scama/__init__.py diff --git a/funasr/models/scama/beam_search.py b/funasr/models/scama/beam_search.py new file mode 100644 index 000000000..8f0d751e5 --- /dev/null +++ b/funasr/models/scama/beam_search.py @@ -0,0 +1,496 @@ +"""Beam search module.""" + +from itertools import chain +import logging +from typing import Any +from typing import Dict +from typing import List +from typing import NamedTuple +from typing import Tuple +from typing import Union + +import torch + +from funasr.metrics import end_detect +from funasr.models.transformer.scorers.scorer_interface import PartialScorerInterface +from funasr.models.transformer.scorers.scorer_interface import ScorerInterface + + +class Hypothesis(NamedTuple): + """Hypothesis data type.""" + + yseq: torch.Tensor + score: Union[float, torch.Tensor] = 0 + scores: Dict[str, Union[float, torch.Tensor]] = 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 BeamSearchScama(torch.nn.Module): + """Beam search implementation.""" + + def __init__( + self, + scorers: Dict[str, ScorerInterface], + weights: Dict[str, float], + beam_size: int, + vocab_size: int, + sos: int, + eos: int, + token_list: List[str] = None, + pre_beam_ratio: float = 1.5, + pre_beam_score_key: str = None, + ): + """Initialize beam search. + + Args: + scorers (dict[str, ScorerInterface]): Dict of decoder modules + e.g., Decoder, CTCPrefixScorer, LM + The scorer will be ignored if it is `None` + weights (dict[str, float]): Dict of weights for each scorers + The scorer will be ignored if its weight is 0 + beam_size (int): The number of hypotheses kept during search + vocab_size (int): The number of vocabulary + sos (int): Start of sequence id + eos (int): End of sequence id + token_list (list[str]): List of tokens for debug log + pre_beam_score_key (str): key of scores to perform pre-beam search + pre_beam_ratio (float): beam size in the pre-beam search + will be `int(pre_beam_ratio * beam_size)` + + """ + super().__init__() + # set scorers + self.weights = weights + self.scorers = dict() + self.full_scorers = dict() + self.part_scorers = dict() + # this module dict is required for recursive cast + # `self.to(device, dtype)` in `recog.py` + self.nn_dict = torch.nn.ModuleDict() + for k, v in scorers.items(): + w = weights.get(k, 0) + if w == 0 or v is None: + continue + assert isinstance( + v, ScorerInterface + ), f"{k} ({type(v)}) does not implement ScorerInterface" + self.scorers[k] = v + if isinstance(v, PartialScorerInterface): + self.part_scorers[k] = v + else: + self.full_scorers[k] = v + if isinstance(v, torch.nn.Module): + self.nn_dict[k] = v + + # set configurations + self.sos = sos + self.eos = eos + self.token_list = token_list + self.pre_beam_size = int(pre_beam_ratio * beam_size) + self.beam_size = beam_size + self.n_vocab = vocab_size + if ( + pre_beam_score_key is not None + and pre_beam_score_key != "full" + and pre_beam_score_key not in self.full_scorers + ): + raise KeyError(f"{pre_beam_score_key} is not found in {self.full_scorers}") + self.pre_beam_score_key = pre_beam_score_key + self.do_pre_beam = ( + self.pre_beam_score_key is not None + and self.pre_beam_size < self.n_vocab + and len(self.part_scorers) > 0 + ) + + def init_hyp(self, x: torch.Tensor) -> List[Hypothesis]: + """Get an initial hypothesis data. + + Args: + x (torch.Tensor): The encoder output feature + + Returns: + Hypothesis: The initial hypothesis. + + """ + init_states = dict() + init_scores = dict() + for k, d in self.scorers.items(): + init_states[k] = d.init_state(x) + init_scores[k] = 0.0 + return [ + Hypothesis( + score=0.0, + scores=init_scores, + states=init_states, + yseq=torch.tensor([self.sos], device=x.device), + ) + ] + + @staticmethod + def append_token(xs: torch.Tensor, x: int) -> torch.Tensor: + """Append new token to prefix tokens. + + Args: + xs (torch.Tensor): The prefix token + x (int): The new token to append + + Returns: + torch.Tensor: New tensor contains: xs + [x] with xs.dtype and xs.device + + """ + x = torch.tensor([x], dtype=xs.dtype, device=xs.device) + return torch.cat((xs, x)) + + def score_full( + self, hyp: Hypothesis, + x: torch.Tensor, + x_mask: torch.Tensor = None, + pre_acoustic_embeds: torch.Tensor = None, + ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: + """Score new hypothesis by `self.full_scorers`. + + Args: + hyp (Hypothesis): Hypothesis with prefix tokens to score + x (torch.Tensor): Corresponding input feature + + Returns: + Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of + score dict of `hyp` that has string keys of `self.full_scorers` + and tensor score values of shape: `(self.n_vocab,)`, + and state dict that has string keys + and state values of `self.full_scorers` + + """ + scores = dict() + states = dict() + for k, d in self.full_scorers.items(): + scores[k], states[k] = d.score(hyp.yseq, hyp.states[k], x, x_mask=x_mask, pre_acoustic_embeds=pre_acoustic_embeds) + return scores, states + + def score_partial( + self, hyp: Hypothesis, ids: torch.Tensor, x: torch.Tensor + ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: + """Score new hypothesis by `self.part_scorers`. + + Args: + hyp (Hypothesis): Hypothesis with prefix tokens to score + ids (torch.Tensor): 1D tensor of new partial tokens to score + x (torch.Tensor): Corresponding input feature + + Returns: + Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of + score dict of `hyp` that has string keys of `self.part_scorers` + and tensor score values of shape: `(len(ids),)`, + and state dict that has string keys + and state values of `self.part_scorers` + + """ + scores = dict() + states = dict() + for k, d in self.part_scorers.items(): + scores[k], states[k] = d.score_partial(hyp.yseq, ids, hyp.states[k], x) + return scores, states + + def beam( + self, weighted_scores: torch.Tensor, ids: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute topk full token ids and partial token ids. + + Args: + weighted_scores (torch.Tensor): The weighted sum scores for each tokens. + Its shape is `(self.n_vocab,)`. + ids (torch.Tensor): The partial token ids to compute topk + + Returns: + Tuple[torch.Tensor, torch.Tensor]: + The topk full token ids and partial token ids. + Their shapes are `(self.beam_size,)` + + """ + # no pre beam performed + if weighted_scores.size(0) == ids.size(0): + top_ids = weighted_scores.topk(self.beam_size)[1] + return top_ids, top_ids + + # mask pruned in pre-beam not to select in topk + tmp = weighted_scores[ids] + weighted_scores[:] = -float("inf") + weighted_scores[ids] = tmp + top_ids = weighted_scores.topk(self.beam_size)[1] + local_ids = weighted_scores[ids].topk(self.beam_size)[1] + return top_ids, local_ids + + @staticmethod + def merge_scores( + prev_scores: Dict[str, float], + next_full_scores: Dict[str, torch.Tensor], + full_idx: int, + next_part_scores: Dict[str, torch.Tensor], + part_idx: int, + ) -> Dict[str, torch.Tensor]: + """Merge scores for new hypothesis. + + Args: + prev_scores (Dict[str, float]): + The previous hypothesis scores by `self.scorers` + next_full_scores (Dict[str, torch.Tensor]): scores by `self.full_scorers` + full_idx (int): The next token id for `next_full_scores` + next_part_scores (Dict[str, torch.Tensor]): + scores of partial tokens by `self.part_scorers` + part_idx (int): The new token id for `next_part_scores` + + Returns: + Dict[str, torch.Tensor]: The new score dict. + Its keys are names of `self.full_scorers` and `self.part_scorers`. + Its values are scalar tensors by the scorers. + + """ + new_scores = dict() + for k, v in next_full_scores.items(): + new_scores[k] = prev_scores[k] + v[full_idx] + for k, v in next_part_scores.items(): + new_scores[k] = prev_scores[k] + v[part_idx] + return new_scores + + def merge_states(self, states: Any, part_states: Any, part_idx: int) -> Any: + """Merge states for new hypothesis. + + Args: + states: states of `self.full_scorers` + part_states: states of `self.part_scorers` + part_idx (int): The new token id for `part_scores` + + Returns: + Dict[str, torch.Tensor]: The new score dict. + Its keys are names of `self.full_scorers` and `self.part_scorers`. + Its values are states of the scorers. + + """ + new_states = dict() + for k, v in states.items(): + new_states[k] = v + for k, d in self.part_scorers.items(): + new_states[k] = d.select_state(part_states[k], part_idx) + return new_states + + def search( + self, running_hyps: List[Hypothesis], + x: torch.Tensor, + x_mask: torch.Tensor = None, + pre_acoustic_embeds: torch.Tensor = None, + ) -> List[Hypothesis]: + """Search new tokens for running hypotheses and encoded speech x. + + Args: + running_hyps (List[Hypothesis]): Running hypotheses on beam + x (torch.Tensor): Encoded speech feature (T, D) + + Returns: + List[Hypotheses]: Best sorted hypotheses + + """ + best_hyps = [] + part_ids = torch.arange(self.n_vocab, device=x.device) # no pre-beam + for hyp in running_hyps: + # scoring + weighted_scores = torch.zeros(self.n_vocab, dtype=x.dtype, device=x.device) + scores, states = self.score_full(hyp, x, x_mask=x_mask, pre_acoustic_embeds=pre_acoustic_embeds) + for k in self.full_scorers: + weighted_scores += self.weights[k] * scores[k] + # partial scoring + if self.do_pre_beam: + pre_beam_scores = ( + weighted_scores + if self.pre_beam_score_key == "full" + else scores[self.pre_beam_score_key] + ) + part_ids = torch.topk(pre_beam_scores, self.pre_beam_size)[1] + part_scores, part_states = self.score_partial(hyp, part_ids, x) + for k in self.part_scorers: + weighted_scores[part_ids] += self.weights[k] * part_scores[k] + # add previous hyp score + weighted_scores += hyp.score + + # update hyps + for j, part_j in zip(*self.beam(weighted_scores, part_ids)): + # will be (2 x beam at most) + best_hyps.append( + Hypothesis( + score=weighted_scores[j], + yseq=self.append_token(hyp.yseq, j), + scores=self.merge_scores( + hyp.scores, scores, j, part_scores, part_j + ), + states=self.merge_states(states, part_states, part_j), + ) + ) + + # sort and prune 2 x beam -> beam + best_hyps = sorted(best_hyps, key=lambda x: x.score, reverse=True)[ + : min(len(best_hyps), self.beam_size) + ] + return best_hyps + + def forward( + self, x: torch.Tensor, + scama_mask: torch.Tensor = None, + pre_acoustic_embeds: torch.Tensor = None, + maxlenratio: float = 0.0, + minlenratio: float = 0.0, + maxlen: int = None, + minlen: int = 0, + ) -> List[Hypothesis]: + """Perform beam search. + + Args: + x (torch.Tensor): Encoded speech feature (T, D) + maxlenratio (float): Input length ratio to obtain max output length. + If maxlenratio=0.0 (default), it uses a end-detect function + to automatically find maximum hypothesis lengths + If maxlenratio<0.0, its absolute value is interpreted + as a constant max output length. + minlenratio (float): Input length ratio to obtain min output length. + + Returns: + list[Hypothesis]: N-best decoding results + + """ + if maxlen is None: + # set length bounds + if maxlenratio == 0: + maxlen = x.shape[0] + elif maxlenratio < 0: + maxlen = -1 * int(maxlenratio) + else: + maxlen = max(1, int(maxlenratio * x.size(0))) + minlen = int(minlenratio * x.size(0)) + + logging.info("decoder input length: " + str(x.shape[0])) + logging.info("max output length: " + str(maxlen)) + logging.info("min output length: " + str(minlen)) + + # main loop of prefix search + running_hyps = self.init_hyp(x) + ended_hyps = [] + for i in range(maxlen): + logging.debug("position " + str(i)) + mask_enc = None + if scama_mask is not None: + token_num_predictor = scama_mask.size(1) + token_id_slice = min(i, token_num_predictor-1) + mask_enc = scama_mask[:, token_id_slice:token_id_slice+1, :] + # if mask_enc.size(1) == 0: + # mask_enc = scama_mask[:, -2:-1, :] + # # mask_enc = torch.zeros_like(mask_enc) + pre_acoustic_embeds_cur = None + if pre_acoustic_embeds is not None: + b, t, d = pre_acoustic_embeds.size() + pad = torch.zeros((b, 1, d), dtype=pre_acoustic_embeds.dtype).to(device=pre_acoustic_embeds.device) + pre_acoustic_embeds = torch.cat((pre_acoustic_embeds, pad), dim=1) + token_id_slice = min(i, t) + pre_acoustic_embeds_cur = pre_acoustic_embeds[:, token_id_slice:token_id_slice+1, :] + + best = self.search(running_hyps, x, x_mask=mask_enc, pre_acoustic_embeds=pre_acoustic_embeds_cur) + # post process of one iteration + running_hyps = self.post_process(i, maxlen, maxlenratio, best, ended_hyps) + # end detection + if maxlenratio == 0.0 and end_detect([h.asdict() for h in ended_hyps], i): + logging.info(f"end detected at {i}") + break + if len(running_hyps) == 0: + logging.info("no hypothesis. Finish decoding.") + break + else: + logging.debug(f"remained hypotheses: {len(running_hyps)}") + + nbest_hyps = sorted(ended_hyps, key=lambda x: x.score, reverse=True) + # check the number of hypotheses reaching to eos + if len(nbest_hyps) == 0: + logging.warning( + "there is no N-best results, perform recognition " + "again with smaller minlenratio." + ) + return ( + [] + if minlenratio < 0.1 + else self.forward(x, maxlenratio, max(0.0, minlenratio - 0.1)) + ) + + # report the best result + for x in nbest_hyps: + yseq = "".join([self.token_list[x] for x in x.yseq]) + logging.debug("nbest: y: {}, yseq: {}, score: {}".format(x.yseq, yseq, x.score)) + best = nbest_hyps[0] + for k, v in best.scores.items(): + logging.info( + f"{v:6.2f} * {self.weights[k]:3} = {v * self.weights[k]:6.2f} for {k}" + ) + logging.info(f"total log probability: {best.score:.2f}") + logging.info(f"normalized log probability: {best.score / len(best.yseq):.2f}") + logging.info(f"total number of ended hypotheses: {len(nbest_hyps)}") + if self.token_list is not None: + logging.info( + "best hypo: " + + "".join([self.token_list[x] for x in best.yseq[1:-1]]) + + "\n" + ) + return nbest_hyps + + def post_process( + self, + i: int, + maxlen: int, + maxlenratio: float, + running_hyps: List[Hypothesis], + ended_hyps: List[Hypothesis], + ) -> List[Hypothesis]: + """Perform post-processing of beam search iterations. + + Args: + i (int): The length of hypothesis tokens. + maxlen (int): The maximum length of tokens in beam search. + maxlenratio (int): The maximum length ratio in beam search. + running_hyps (List[Hypothesis]): The running hypotheses in beam search. + ended_hyps (List[Hypothesis]): The ended hypotheses in beam search. + + Returns: + List[Hypothesis]: The new running hypotheses. + + """ + logging.debug(f"the number of running hypotheses: {len(running_hyps)}") + if self.token_list is not None: + logging.debug( + "best hypo: " + + "".join([self.token_list[x] for x in running_hyps[0].yseq[1:]]) + ) + # add eos in the final loop to avoid that there are no ended hyps + if i == maxlen - 1: + logging.info("adding in the last position in the loop") + running_hyps = [ + h._replace(yseq=self.append_token(h.yseq, self.eos)) + for h in running_hyps + ] + + # add ended hypotheses to a final list, and removed them from current hypotheses + # (this will be a problem, number of hyps < beam) + remained_hyps = [] + for hyp in running_hyps: + if hyp.yseq[-1] == self.eos: + # e.g., Word LM needs to add final score + for k, d in chain(self.full_scorers.items(), self.part_scorers.items()): + s = d.final_score(hyp.states[k]) + hyp.scores[k] += s + hyp = hyp._replace(score=hyp.score + self.weights[k] * s) + ended_hyps.append(hyp) + else: + remained_hyps.append(hyp) + return remained_hyps diff --git a/funasr/modules/streaming_utils/chunk_utilis.py b/funasr/models/scama/chunk_utilis.py similarity index 99% rename from funasr/modules/streaming_utils/chunk_utilis.py rename to funasr/models/scama/chunk_utilis.py index 73dbaf49e..e90ab62a4 100644 --- a/funasr/modules/streaming_utils/chunk_utilis.py +++ b/funasr/models/scama/chunk_utilis.py @@ -2,10 +2,10 @@ import torch import numpy as np import math -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import make_pad_mask import logging import torch.nn.functional as F -from funasr.modules.streaming_utils.utils import sequence_mask +from funasr.models.scama.utils import sequence_mask diff --git a/funasr/modules/streaming_utils/utils.py b/funasr/models/scama/utils.py similarity index 100% rename from funasr/modules/streaming_utils/utils.py rename to funasr/models/scama/utils.py diff --git a/funasr/samplers/__init__.py b/funasr/models/sond/__init__.py similarity index 100% rename from funasr/samplers/__init__.py rename to funasr/models/sond/__init__.py diff --git a/funasr/models/e2e_diar_sond.py b/funasr/models/sond/e2e_diar_sond.py similarity index 99% rename from funasr/models/e2e_diar_sond.py rename to funasr/models/sond/e2e_diar_sond.py index aa6294add..ff70502bb 100644 --- a/funasr/models/e2e_diar_sond.py +++ b/funasr/models/sond/e2e_diar_sond.py @@ -14,15 +14,15 @@ import numpy as np import torch from torch.nn import functional as F -from funasr.modules.nets_utils import to_device -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import to_device +from funasr.models.transformer.utils.nets_utils import make_pad_mask from funasr.models.decoder.abs_decoder import AbsDecoder from funasr.models.encoder.abs_encoder import AbsEncoder from funasr.models.frontend.abs_frontend import AbsFrontend from funasr.models.specaug.abs_specaug import AbsSpecAug from funasr.models.specaug.abs_profileaug import AbsProfileAug from funasr.layers.abs_normalize import AbsNormalize -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.train_utils.device_funcs import force_gatherable from funasr.models.base_model import FunASRModel from funasr.losses.label_smoothing_loss import LabelSmoothingLoss, SequenceBinaryCrossEntropy from funasr.utils.misc import int2vec diff --git a/funasr/tasks/__init__.py b/funasr/models/sond/encoder/__init__.py similarity index 100% rename from funasr/tasks/__init__.py rename to funasr/models/sond/encoder/__init__.py diff --git a/funasr/models/encoder/opennmt_encoders/ci_scorers.py b/funasr/models/sond/encoder/ci_scorers.py similarity index 100% rename from funasr/models/encoder/opennmt_encoders/ci_scorers.py rename to funasr/models/sond/encoder/ci_scorers.py diff --git a/funasr/models/encoder/opennmt_encoders/conv_encoder.py b/funasr/models/sond/encoder/conv_encoder.py similarity index 98% rename from funasr/models/encoder/opennmt_encoders/conv_encoder.py rename to funasr/models/sond/encoder/conv_encoder.py index 9ab5e6b11..4c345cbd5 100644 --- a/funasr/models/encoder/opennmt_encoders/conv_encoder.py +++ b/funasr/models/sond/encoder/conv_encoder.py @@ -8,11 +8,11 @@ import torch import torch.nn as nn from torch.nn import functional as F import numpy as np -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.layer_norm import LayerNorm +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.layer_norm import LayerNorm from funasr.models.encoder.abs_encoder import AbsEncoder import math -from funasr.modules.repeat import repeat +from funasr.models.transformer.repeat import repeat class EncoderLayer(nn.Module): diff --git a/funasr/models/encoder/ecapa_tdnn_encoder.py b/funasr/models/sond/encoder/ecapa_tdnn_encoder.py similarity index 100% rename from funasr/models/encoder/ecapa_tdnn_encoder.py rename to funasr/models/sond/encoder/ecapa_tdnn_encoder.py diff --git a/funasr/models/encoder/opennmt_encoders/fsmn_encoder.py b/funasr/models/sond/encoder/fsmn_encoder.py similarity index 98% rename from funasr/models/encoder/opennmt_encoders/fsmn_encoder.py rename to funasr/models/sond/encoder/fsmn_encoder.py index 5f62e67cc..e23f3f11b 100644 --- a/funasr/models/encoder/opennmt_encoders/fsmn_encoder.py +++ b/funasr/models/sond/encoder/fsmn_encoder.py @@ -8,12 +8,12 @@ import torch import torch.nn as nn from torch.nn import functional as F import numpy as np -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.layer_norm import LayerNorm +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.layer_norm import LayerNorm from funasr.models.encoder.abs_encoder import AbsEncoder import math -from funasr.modules.repeat import repeat -from funasr.modules.multi_layer_conv import FsmnFeedForward +from funasr.models.transformer.repeat import repeat +from funasr.models.transformer.utils.multi_layer_conv import FsmnFeedForward class FsmnBlock(torch.nn.Module): diff --git a/funasr/models/encoder/resnet34_encoder.py b/funasr/models/sond/encoder/resnet34_encoder.py similarity index 100% rename from funasr/models/encoder/resnet34_encoder.py rename to funasr/models/sond/encoder/resnet34_encoder.py diff --git a/funasr/models/encoder/opennmt_encoders/self_attention_encoder.py b/funasr/models/sond/encoder/self_attention_encoder.py similarity index 95% rename from funasr/models/encoder/opennmt_encoders/self_attention_encoder.py rename to funasr/models/sond/encoder/self_attention_encoder.py index 7c83cbd1b..c620295ab 100644 --- a/funasr/models/encoder/opennmt_encoders/self_attention_encoder.py +++ b/funasr/models/sond/encoder/self_attention_encoder.py @@ -6,24 +6,24 @@ from typing import Union import logging import torch import torch.nn as nn -from funasr.modules.streaming_utils.chunk_utilis import overlap_chunk +from funasr.models.scama.chunk_utilis import overlap_chunk import numpy as np -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.attention import MultiHeadSelfAttention, MultiHeadedAttentionSANM -from funasr.modules.embedding import SinusoidalPositionEncoder -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.multi_layer_conv import Conv1dLinear -from funasr.modules.multi_layer_conv import MultiLayeredConv1d -from funasr.modules.positionwise_feed_forward import ( +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.attention import MultiHeadSelfAttention, MultiHeadedAttentionSANM +from funasr.models.transformer.embedding import SinusoidalPositionEncoder +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.utils.multi_layer_conv import Conv1dLinear +from funasr.models.transformer.utils.multi_layer_conv import MultiLayeredConv1d +from funasr.models.transformer.positionwise_feed_forward import ( PositionwiseFeedForward, # noqa: H301 ) -from funasr.modules.repeat import repeat -from funasr.modules.subsampling import Conv2dSubsampling -from funasr.modules.subsampling import Conv2dSubsampling2 -from funasr.modules.subsampling import Conv2dSubsampling6 -from funasr.modules.subsampling import Conv2dSubsampling8 -from funasr.modules.subsampling import TooShortUttError -from funasr.modules.subsampling import check_short_utt +from funasr.models.transformer.repeat import repeat +from funasr.models.transformer.subsampling import Conv2dSubsampling +from funasr.models.transformer.subsampling import Conv2dSubsampling2 +from funasr.models.transformer.subsampling import Conv2dSubsampling6 +from funasr.models.transformer.subsampling import Conv2dSubsampling8 +from funasr.models.transformer.subsampling import TooShortUttError +from funasr.models.transformer.subsampling import check_short_utt from funasr.models.ctc import CTC from funasr.models.encoder.abs_encoder import AbsEncoder diff --git a/funasr/layers/label_aggregation.py b/funasr/models/sond/label_aggregation.py similarity index 97% rename from funasr/layers/label_aggregation.py rename to funasr/models/sond/label_aggregation.py index e86c296bc..7ec06aae1 100644 --- a/funasr/layers/label_aggregation.py +++ b/funasr/models/sond/label_aggregation.py @@ -2,7 +2,7 @@ import torch from typing import Optional from typing import Tuple from torch.nn import functional as F -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import make_pad_mask class LabelAggregate(torch.nn.Module): diff --git a/funasr/torch_utils/__init__.py b/funasr/models/sond/pooling/__init__.py similarity index 100% rename from funasr/torch_utils/__init__.py rename to funasr/models/sond/pooling/__init__.py diff --git a/funasr/models/pooling/pooling_layers.py b/funasr/models/sond/pooling/pooling_layers.py similarity index 100% rename from funasr/models/pooling/pooling_layers.py rename to funasr/models/sond/pooling/pooling_layers.py diff --git a/funasr/models/pooling/statistic_pooling.py b/funasr/models/sond/pooling/statistic_pooling.py similarity index 97% rename from funasr/models/pooling/statistic_pooling.py rename to funasr/models/sond/pooling/statistic_pooling.py index 39d94be5b..392e33310 100644 --- a/funasr/models/pooling/statistic_pooling.py +++ b/funasr/models/sond/pooling/statistic_pooling.py @@ -1,7 +1,7 @@ import torch from typing import Tuple from typing import Union -from funasr.modules.nets_utils import make_non_pad_mask +from funasr.models.transformer.utils.nets_utils import make_non_pad_mask from torch.nn import functional as F import math diff --git a/funasr/models/decoder/sv_decoder.py b/funasr/models/sond/sv_decoder.py similarity index 100% rename from funasr/models/decoder/sv_decoder.py rename to funasr/models/sond/sv_decoder.py diff --git a/funasr/models/specaug/abs_profileaug.py b/funasr/models/specaug/abs_profileaug.py deleted file mode 100644 index 54145b88c..000000000 --- a/funasr/models/specaug/abs_profileaug.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Optional -from typing import Tuple - -import torch - - -class AbsProfileAug(torch.nn.Module): - """Abstract class for the augmentation of profile - - The process-flow: - - Frontend --> SpecAug -> Normalization -> Encoder -> Decoder - `-> ProfileAug -> Speaker Encoder --' - """ - - def forward( - self, x: torch.Tensor, x_lengths: torch.Tensor = None, - profile: torch.Tensor = None, profile_lengths: torch.Tensor = None, - binary_labels: torch.Tensor = None, labels_length: torch.Tensor = None, - ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[torch.Tensor]]: - - raise NotImplementedError diff --git a/funasr/models/specaug/abs_specaug.py b/funasr/models/specaug/abs_specaug.py deleted file mode 100644 index da6637e19..000000000 --- a/funasr/models/specaug/abs_specaug.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Optional -from typing import Tuple - -import torch - - -class AbsSpecAug(torch.nn.Module): - """Abstract class for the augmentation of spectrogram - The process-flow: - Frontend -> SpecAug -> Normalization -> Encoder -> Decoder - """ - - def forward( - self, x: torch.Tensor, x_lengths: torch.Tensor = None - ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]: - raise NotImplementedError diff --git a/funasr/layers/mask_along_axis.py b/funasr/models/specaug/mask_along_axis.py similarity index 100% rename from funasr/layers/mask_along_axis.py rename to funasr/models/specaug/mask_along_axis.py diff --git a/funasr/models/specaug/profileaug.py b/funasr/models/specaug/profileaug.py index 3c7d147ae..448c579d6 100644 --- a/funasr/models/specaug/profileaug.py +++ b/funasr/models/specaug/profileaug.py @@ -2,10 +2,9 @@ from typing import Tuple, Optional import numpy as np import torch from torch.nn import functional as F -from funasr.models.specaug.abs_profileaug import AbsProfileAug +import torch.nn as nn - -class ProfileAug(AbsProfileAug): +class ProfileAug(nn.Module): """ Implement the augmentation for profiles including: - Split aug: split one profile into two profiles, i.e., main and inaccurate, labels assigned to main diff --git a/funasr/models/specaug/specaug.py b/funasr/models/specaug/specaug.py index 6074f86fd..e5da8e232 100644 --- a/funasr/models/specaug/specaug.py +++ b/funasr/models/specaug/specaug.py @@ -3,14 +3,14 @@ from typing import Optional from typing import Sequence from typing import Union -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.layers.mask_along_axis import MaskAlongAxis -from funasr.layers.mask_along_axis import MaskAlongAxisVariableMaxWidth -from funasr.layers.mask_along_axis import MaskAlongAxisLFR -from funasr.layers.time_warp import TimeWarp +from funasr.models.specaug.mask_along_axis import MaskAlongAxis +from funasr.models.specaug.mask_along_axis import MaskAlongAxisVariableMaxWidth +from funasr.models.specaug.mask_along_axis import MaskAlongAxisLFR +from funasr.models.specaug.time_warp import TimeWarp +import torch.nn as nn -class SpecAug(AbsSpecAug): +class SpecAug(nn.Module): """Implementation of SpecAug. Reference: diff --git a/funasr/layers/time_warp.py b/funasr/models/specaug/time_warp.py similarity index 97% rename from funasr/layers/time_warp.py rename to funasr/models/specaug/time_warp.py index b55461872..d42820df7 100644 --- a/funasr/layers/time_warp.py +++ b/funasr/models/specaug/time_warp.py @@ -1,7 +1,7 @@ """Time warp module.""" import torch -from funasr.modules.nets_utils import pad_list +from funasr.models.transformer.utils.nets_utils import pad_list DEFAULT_TIME_WARP_MODE = "bicubic" diff --git a/funasr/train/__init__.py b/funasr/models/tp_aligner/__init__.py similarity index 100% rename from funasr/train/__init__.py rename to funasr/models/tp_aligner/__init__.py diff --git a/funasr/models/e2e_tp.py b/funasr/models/tp_aligner/e2e_tp.py similarity index 96% rename from funasr/models/e2e_tp.py rename to funasr/models/tp_aligner/e2e_tp.py index 567dc70df..e6c4028ac 100644 --- a/funasr/models/e2e_tp.py +++ b/funasr/models/tp_aligner/e2e_tp.py @@ -13,9 +13,9 @@ import numpy as np from funasr.models.encoder.abs_encoder import AbsEncoder from funasr.models.frontend.abs_frontend import AbsFrontend from funasr.models.predictor.cif import mae_loss -from funasr.modules.add_sos_eos import add_sos_eos -from funasr.modules.nets_utils import make_pad_mask, pad_list -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.models.transformer.add_sos_eos import add_sos_eos +from funasr.models.transformer.utils.nets_utils import make_pad_mask, pad_list +from funasr.train_utils.device_funcs import force_gatherable from funasr.models.base_model import FunASRModel from funasr.models.predictor.cif import CifPredictorV3 diff --git a/funasr/utils/whisper_utils/__init__.py b/funasr/models/transducer/__init__.py similarity index 100% rename from funasr/utils/whisper_utils/__init__.py rename to funasr/models/transducer/__init__.py diff --git a/funasr/modules/beam_search/beam_search_transducer.py b/funasr/models/transducer/beam_search_transducer.py similarity index 99% rename from funasr/modules/beam_search/beam_search_transducer.py rename to funasr/models/transducer/beam_search_transducer.py index 3eb8e08d0..04b26b3b4 100644 --- a/funasr/modules/beam_search/beam_search_transducer.py +++ b/funasr/models/transducer/beam_search_transducer.py @@ -6,7 +6,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union import numpy as np import torch -from funasr.models.joint_net.joint_network import JointNetwork +from funasr.models.transducer.joint_network import JointNetwork @dataclass diff --git a/funasr/models/joint_net/joint_network.py b/funasr/models/transducer/joint_network.py similarity index 96% rename from funasr/models/joint_net/joint_network.py rename to funasr/models/transducer/joint_network.py index ed827c420..9fca632e2 100644 --- a/funasr/models/joint_net/joint_network.py +++ b/funasr/models/transducer/joint_network.py @@ -2,7 +2,7 @@ import torch -from funasr.modules.nets_utils import get_activation +from funasr.models.transformer.utils.nets_utils import get_activation class JointNetwork(torch.nn.Module): diff --git a/funasr/models/transducer/model.py b/funasr/models/transducer/model.py new file mode 100644 index 000000000..ec340f624 --- /dev/null +++ b/funasr/models/transducer/model.py @@ -0,0 +1,577 @@ +import logging +from contextlib import contextmanager +from distutils.version import LooseVersion +from typing import Dict +from typing import List +from typing import Optional +from typing import Tuple +from typing import Union +import tempfile +import codecs +import requests +import re +import copy +import torch +import torch.nn as nn +import random +import numpy as np +import time +# from funasr.layers.abs_normalize import AbsNormalize +from funasr.losses.label_smoothing_loss import ( + LabelSmoothingLoss, # noqa: H301 +) +# from funasr.models.ctc import CTC +# from funasr.models.decoder.abs_decoder import AbsDecoder +# from funasr.models.e2e_asr_common import ErrorCalculator +# from funasr.models.encoder.abs_encoder import AbsEncoder +# from funasr.models.frontend.abs_frontend import AbsFrontend +# from funasr.models.postencoder.abs_postencoder import AbsPostEncoder +from funasr.models.predictor.cif import mae_loss +# from funasr.models.preencoder.abs_preencoder import AbsPreEncoder +# from funasr.models.specaug.abs_specaug import AbsSpecAug +from funasr.models.transformer.add_sos_eos import add_sos_eos +from funasr.models.transformer.utils.nets_utils import make_pad_mask, pad_list +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.train_utils.device_funcs import force_gatherable +# from funasr.models.base_model import FunASRModel +# from funasr.models.predictor.cif import CifPredictorV3 +from funasr.models.paraformer.search import Hypothesis + +from funasr.models.model_class_factory import * + +if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): + from torch.cuda.amp import autocast +else: + # Nothing to do if torch<1.6.0 + @contextmanager + def autocast(enabled=True): + yield +from funasr.datasets.fun_datasets.load_audio_extract_fbank import load_audio, extract_fbank +from funasr.utils import postprocess_utils +from funasr.utils.datadir_writer import DatadirWriter +from funasr.models.transformer.utils.nets_utils import get_transducer_task_io + + +class Transducer(nn.Module): + """ESPnet2ASRTransducerModel module definition.""" + + + def __init__( + self, + frontend: Optional[str] = None, + frontend_conf: Optional[Dict] = None, + specaug: Optional[str] = None, + specaug_conf: Optional[Dict] = None, + normalize: str = None, + normalize_conf: Optional[Dict] = None, + encoder: str = None, + encoder_conf: Optional[Dict] = None, + decoder: str = None, + decoder_conf: Optional[Dict] = None, + joint_network: str = None, + joint_network_conf: Optional[Dict] = None, + transducer_weight: float = 1.0, + fastemit_lambda: float = 0.0, + auxiliary_ctc_weight: float = 0.0, + auxiliary_ctc_dropout_rate: float = 0.0, + auxiliary_lm_loss_weight: float = 0.0, + auxiliary_lm_loss_smoothing: float = 0.0, + input_size: int = 80, + vocab_size: int = -1, + ignore_id: int = -1, + blank_id: int = 0, + sos: int = 1, + eos: int = 2, + lsm_weight: float = 0.0, + length_normalized_loss: bool = False, + # report_cer: bool = True, + # report_wer: bool = True, + # sym_space: str = "", + # sym_blank: str = "", + # extract_feats_in_collect_stats: bool = True, + share_embedding: bool = False, + # preencoder: Optional[AbsPreEncoder] = None, + # postencoder: Optional[AbsPostEncoder] = None, + **kwargs, + ): + + super().__init__() + + if frontend is not None: + frontend_class = frontend_choices.get_class(frontend) + frontend = frontend_class(**frontend_conf) + if specaug is not None: + specaug_class = specaug_choices.get_class(specaug) + specaug = specaug_class(**specaug_conf) + if normalize is not None: + normalize_class = normalize_choices.get_class(normalize) + normalize = normalize_class(**normalize_conf) + encoder_class = encoder_choices.get_class(encoder) + encoder = encoder_class(input_size=input_size, **encoder_conf) + encoder_output_size = encoder.output_size() + + decoder_class = decoder_choices.get_class(decoder) + decoder = decoder_class( + vocab_size=vocab_size, + encoder_output_size=encoder_output_size, + **decoder_conf, + ) + decoder_output_size = decoder.output_size + + joint_network_class = joint_network_choices.get_class(decoder) + joint_network = joint_network_class( + vocab_size, + encoder_output_size, + decoder_output_size, + **joint_network_conf, + ) + + + self.criterion_transducer = None + self.error_calculator = None + + self.use_auxiliary_ctc = auxiliary_ctc_weight > 0 + self.use_auxiliary_lm_loss = auxiliary_lm_loss_weight > 0 + + if self.use_auxiliary_ctc: + self.ctc_lin = torch.nn.Linear(encoder.output_size(), vocab_size) + self.ctc_dropout_rate = auxiliary_ctc_dropout_rate + + if self.use_auxiliary_lm_loss: + self.lm_lin = torch.nn.Linear(decoder.output_size, vocab_size) + self.lm_loss_smoothing = auxiliary_lm_loss_smoothing + + self.transducer_weight = transducer_weight + self.fastemit_lambda = fastemit_lambda + + self.auxiliary_ctc_weight = auxiliary_ctc_weight + self.auxiliary_lm_loss_weight = auxiliary_lm_loss_weight + self.blank_id = blank_id + self.sos = sos if sos is not None else vocab_size - 1 + self.eos = eos if eos is not None else vocab_size - 1 + self.vocab_size = vocab_size + self.ignore_id = ignore_id + self.frontend = frontend + self.specaug = specaug + self.normalize = normalize + self.encoder = encoder + self.decoder = decoder + self.joint_network = joint_network + + + + self.criterion_att = LabelSmoothingLoss( + size=vocab_size, + padding_idx=ignore_id, + smoothing=lsm_weight, + normalize_length=length_normalized_loss, + ) + # + # if report_cer or report_wer: + # self.error_calculator = ErrorCalculator( + # token_list, sym_space, sym_blank, report_cer, report_wer + # ) + # + + self.length_normalized_loss = length_normalized_loss + self.beam_search = None + + def forward( + self, + speech: torch.Tensor, + speech_lengths: torch.Tensor, + text: torch.Tensor, + text_lengths: torch.Tensor, + **kwargs, + ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: + """Encoder + Decoder + Calc loss + Args: + speech: (Batch, Length, ...) + speech_lengths: (Batch, ) + text: (Batch, Length) + text_lengths: (Batch,) + """ + # import pdb; + # pdb.set_trace() + if len(text_lengths.size()) > 1: + text_lengths = text_lengths[:, 0] + if len(speech_lengths.size()) > 1: + speech_lengths = speech_lengths[:, 0] + + batch_size = speech.shape[0] + # 1. Encoder + encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) + if hasattr(self.encoder, 'overlap_chunk_cls') and self.encoder.overlap_chunk_cls is not None: + encoder_out, encoder_out_lens = self.encoder.overlap_chunk_cls.remove_chunk(encoder_out, encoder_out_lens, + chunk_outs=None) + # 2. Transducer-related I/O preparation + decoder_in, target, t_len, u_len = get_transducer_task_io( + text, + encoder_out_lens, + ignore_id=self.ignore_id, + ) + + # 3. Decoder + self.decoder.set_device(encoder_out.device) + decoder_out = self.decoder(decoder_in, u_len) + + # 4. Joint Network + joint_out = self.joint_network( + encoder_out.unsqueeze(2), decoder_out.unsqueeze(1) + ) + + # 5. Losses + loss_trans, cer_trans, wer_trans = self._calc_transducer_loss( + encoder_out, + joint_out, + target, + t_len, + u_len, + ) + + loss_ctc, loss_lm = 0.0, 0.0 + + if self.use_auxiliary_ctc: + loss_ctc = self._calc_ctc_loss( + encoder_out, + target, + t_len, + u_len, + ) + + if self.use_auxiliary_lm_loss: + loss_lm = self._calc_lm_loss(decoder_out, target) + + loss = ( + self.transducer_weight * loss_trans + + self.auxiliary_ctc_weight * loss_ctc + + self.auxiliary_lm_loss_weight * loss_lm + ) + + stats = dict( + loss=loss.detach(), + loss_transducer=loss_trans.detach(), + aux_ctc_loss=loss_ctc.detach() if loss_ctc > 0.0 else None, + aux_lm_loss=loss_lm.detach() if loss_lm > 0.0 else None, + cer_transducer=cer_trans, + wer_transducer=wer_trans, + ) + + # force_gatherable: to-device and to-tensor if scalar for DataParallel + loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) + + return loss, stats, weight + + def encode( + self, speech: torch.Tensor, speech_lengths: torch.Tensor, **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Frontend + Encoder. Note that this method is used by asr_inference.py + Args: + speech: (Batch, Length, ...) + speech_lengths: (Batch, ) + ind: int + """ + with autocast(False): + + # Data augmentation + if self.specaug is not None and self.training: + speech, speech_lengths = self.specaug(speech, speech_lengths) + + # Normalization for feature: e.g. Global-CMVN, Utterance-CMVN + if self.normalize is not None: + speech, speech_lengths = self.normalize(speech, speech_lengths) + + # Forward encoder + # feats: (Batch, Length, Dim) + # -> encoder_out: (Batch, Length2, Dim2) + if self.encoder.interctc_use_conditioning: + encoder_out, encoder_out_lens, _ = self.encoder( + speech, speech_lengths, ctc=self.ctc + ) + else: + encoder_out, encoder_out_lens, _ = self.encoder(speech, speech_lengths) + intermediate_outs = None + if isinstance(encoder_out, tuple): + intermediate_outs = encoder_out[1] + encoder_out = encoder_out[0] + + if intermediate_outs is not None: + return (encoder_out, intermediate_outs), encoder_out_lens + + return encoder_out, encoder_out_lens + + def _calc_transducer_loss( + self, + encoder_out: torch.Tensor, + joint_out: torch.Tensor, + target: torch.Tensor, + t_len: torch.Tensor, + u_len: torch.Tensor, + ) -> Tuple[torch.Tensor, Optional[float], Optional[float]]: + """Compute Transducer loss. + + Args: + encoder_out: Encoder output sequences. (B, T, D_enc) + joint_out: Joint Network output sequences (B, T, U, D_joint) + target: Target label ID sequences. (B, L) + t_len: Encoder output sequences lengths. (B,) + u_len: Target label ID sequences lengths. (B,) + + Return: + loss_transducer: Transducer loss value. + cer_transducer: Character error rate for Transducer. + wer_transducer: Word Error Rate for Transducer. + + """ + if self.criterion_transducer is None: + try: + from warp_rnnt import rnnt_loss as RNNTLoss + self.criterion_transducer = RNNTLoss + + except ImportError: + logging.error( + "warp-rnnt was not installed." + "Please consult the installation documentation." + ) + exit(1) + + log_probs = torch.log_softmax(joint_out, dim=-1) + + loss_transducer = self.criterion_transducer( + log_probs, + target, + t_len, + u_len, + reduction="mean", + blank=self.blank_id, + fastemit_lambda=self.fastemit_lambda, + gather=True, + ) + + if not self.training and (self.report_cer or self.report_wer): + if self.error_calculator is None: + from funasr.metrics import ErrorCalculatorTransducer as ErrorCalculator + + self.error_calculator = ErrorCalculator( + self.decoder, + self.joint_network, + self.token_list, + self.sym_space, + self.sym_blank, + report_cer=self.report_cer, + report_wer=self.report_wer, + ) + + cer_transducer, wer_transducer = self.error_calculator(encoder_out, target, t_len) + + return loss_transducer, cer_transducer, wer_transducer + + return loss_transducer, None, None + + def _calc_ctc_loss( + self, + encoder_out: torch.Tensor, + target: torch.Tensor, + t_len: torch.Tensor, + u_len: torch.Tensor, + ) -> torch.Tensor: + """Compute CTC loss. + + Args: + encoder_out: Encoder output sequences. (B, T, D_enc) + target: Target label ID sequences. (B, L) + t_len: Encoder output sequences lengths. (B,) + u_len: Target label ID sequences lengths. (B,) + + Return: + loss_ctc: CTC loss value. + + """ + ctc_in = self.ctc_lin( + torch.nn.functional.dropout(encoder_out, p=self.ctc_dropout_rate) + ) + ctc_in = torch.log_softmax(ctc_in.transpose(0, 1), dim=-1) + + target_mask = target != 0 + ctc_target = target[target_mask].cpu() + + with torch.backends.cudnn.flags(deterministic=True): + loss_ctc = torch.nn.functional.ctc_loss( + ctc_in, + ctc_target, + t_len, + u_len, + zero_infinity=True, + reduction="sum", + ) + loss_ctc /= target.size(0) + + return loss_ctc + + def _calc_lm_loss( + self, + decoder_out: torch.Tensor, + target: torch.Tensor, + ) -> torch.Tensor: + """Compute LM loss. + + Args: + decoder_out: Decoder output sequences. (B, U, D_dec) + target: Target label ID sequences. (B, L) + + Return: + loss_lm: LM loss value. + + """ + lm_loss_in = self.lm_lin(decoder_out[:, :-1, :]).view(-1, self.vocab_size) + lm_target = target.view(-1).type(torch.int64) + + with torch.no_grad(): + true_dist = lm_loss_in.clone() + true_dist.fill_(self.lm_loss_smoothing / (self.vocab_size - 1)) + + # Ignore blank ID (0) + ignore = lm_target == 0 + lm_target = lm_target.masked_fill(ignore, 0) + + true_dist.scatter_(1, lm_target.unsqueeze(1), (1 - self.lm_loss_smoothing)) + + loss_lm = torch.nn.functional.kl_div( + torch.log_softmax(lm_loss_in, dim=1), + true_dist, + reduction="none", + ) + loss_lm = loss_lm.masked_fill(ignore.unsqueeze(1), 0).sum() / decoder_out.size( + 0 + ) + + return loss_lm + + def init_beam_search(self, + **kwargs, + ): + from funasr.models.transformer.search import BeamSearch + from funasr.models.transformer.scorers.ctc import CTCPrefixScorer + from funasr.models.transformer.scorers.length_bonus import LengthBonus + + # 1. Build ASR model + scorers = {} + + if self.ctc != None: + ctc = CTCPrefixScorer(ctc=self.ctc, eos=self.eos) + scorers.update( + ctc=ctc + ) + token_list = kwargs.get("token_list") + scorers.update( + length_bonus=LengthBonus(len(token_list)), + ) + + + # 3. Build ngram model + # ngram is not supported now + ngram = None + scorers["ngram"] = ngram + + weights = dict( + decoder=1.0 - kwargs.get("decoding_ctc_weight"), + ctc=kwargs.get("decoding_ctc_weight", 0.0), + lm=kwargs.get("lm_weight", 0.0), + ngram=kwargs.get("ngram_weight", 0.0), + length_bonus=kwargs.get("penalty", 0.0), + ) + beam_search = BeamSearch( + beam_size=kwargs.get("beam_size", 2), + weights=weights, + scorers=scorers, + sos=self.sos, + eos=self.eos, + vocab_size=len(token_list), + token_list=token_list, + pre_beam_score_key=None if self.ctc_weight == 1.0 else "full", + ) + # beam_search.to(device=kwargs.get("device", "cpu"), dtype=getattr(torch, kwargs.get("dtype", "float32"))).eval() + # for scorer in scorers.values(): + # if isinstance(scorer, torch.nn.Module): + # scorer.to(device=kwargs.get("device", "cpu"), dtype=getattr(torch, kwargs.get("dtype", "float32"))).eval() + self.beam_search = beam_search + + def generate(self, + data_in: list, + data_lengths: list=None, + key: list=None, + tokenizer=None, + **kwargs, + ): + + if kwargs.get("batch_size", 1) > 1: + raise NotImplementedError("batch decoding is not implemented") + + # init beamsearch + is_use_ctc = kwargs.get("decoding_ctc_weight", 0.0) > 0.00001 and self.ctc != None + is_use_lm = kwargs.get("lm_weight", 0.0) > 0.00001 and kwargs.get("lm_file", None) is not None + if self.beam_search is None and (is_use_lm or is_use_ctc): + logging.info("enable beam_search") + self.init_beam_search(**kwargs) + self.nbest = kwargs.get("nbest", 1) + + meta_data = {} + # extract fbank feats + time1 = time.perf_counter() + audio_sample_list = load_audio(data_in, fs=self.frontend.fs, audio_fs=kwargs.get("fs", 16000)) + time2 = time.perf_counter() + meta_data["load_data"] = f"{time2 - time1:0.3f}" + speech, speech_lengths = extract_fbank(audio_sample_list, date_type=kwargs.get("date_type", "sound"), frontend=self.frontend) + time3 = time.perf_counter() + meta_data["extract_feat"] = f"{time3 - time2:0.3f}" + meta_data["batch_data_time"] = speech_lengths.sum().item() * self.frontend.frame_shift * self.frontend.lfr_n / 1000 + + speech.to(device=kwargs["device"]), speech_lengths.to(device=kwargs["device"]) + + # Encoder + encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) + if isinstance(encoder_out, tuple): + encoder_out = encoder_out[0] + + # c. Passed the encoder result and the beam search + nbest_hyps = self.beam_search( + x=encoder_out[0], maxlenratio=kwargs.get("maxlenratio", 0.0), minlenratio=kwargs.get("minlenratio", 0.0) + ) + + nbest_hyps = nbest_hyps[: self.nbest] + + + results = [] + b, n, d = encoder_out.size() + for i in range(b): + + for nbest_idx, hyp in enumerate(nbest_hyps): + ibest_writer = None + if ibest_writer is None and kwargs.get("output_dir") is not None: + writer = DatadirWriter(kwargs.get("output_dir")) + ibest_writer = writer[f"{nbest_idx+1}best_recog"] + # remove sos/eos and get results + last_pos = -1 + if isinstance(hyp.yseq, list): + token_int = hyp.yseq[1:last_pos] + else: + 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 != self.eos and x != self.sos and x != self.blank_id, token_int)) + + # Change integer-ids to tokens + token = tokenizer.ids2tokens(token_int) + text = tokenizer.tokens2text(token) + + text_postprocessed, _ = postprocess_utils.sentence_postprocess(token) + result_i = {"key": key[i], "token": token, "text": text, "text_postprocessed": text_postprocessed} + results.append(result_i) + + if ibest_writer is not None: + ibest_writer["token"][key[i]] = " ".join(token) + ibest_writer["text"][key[i]] = text + ibest_writer["text_postprocessed"][key[i]] = text_postprocessed + + return results, meta_data + diff --git a/funasr/models/decoder/rnn_decoder.py b/funasr/models/transducer/rnn_decoder.py similarity index 98% rename from funasr/models/decoder/rnn_decoder.py rename to funasr/models/transducer/rnn_decoder.py index cb119e193..1743f99ab 100644 --- a/funasr/models/decoder/rnn_decoder.py +++ b/funasr/models/transducer/rnn_decoder.py @@ -4,9 +4,9 @@ import numpy as np import torch import torch.nn.functional as F -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.nets_utils import to_device -from funasr.modules.rnn.attentions import initial_att +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import to_device +from funasr.models.language_model.rnn.attentions import initial_att from funasr.models.decoder.abs_decoder import AbsDecoder from funasr.utils.get_default_kwargs import get_default_kwargs diff --git a/funasr/models/encoder/rnn_encoder.py b/funasr/models/transducer/rnn_encoder.py similarity index 94% rename from funasr/models/encoder/rnn_encoder.py rename to funasr/models/transducer/rnn_encoder.py index 353beaf39..95fb4a589 100644 --- a/funasr/models/encoder/rnn_encoder.py +++ b/funasr/models/transducer/rnn_encoder.py @@ -6,9 +6,9 @@ from typing import Tuple import numpy as np import torch -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.rnn.encoders import RNN -from funasr.modules.rnn.encoders import RNNP +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.language_model.rnn.encoders import RNN +from funasr.models.language_model.rnn.encoders import RNNP from funasr.models.encoder.abs_encoder import AbsEncoder diff --git a/funasr/models/decoder/rnnt_decoder.py b/funasr/models/transducer/rnnt_decoder.py similarity index 99% rename from funasr/models/decoder/rnnt_decoder.py rename to funasr/models/transducer/rnnt_decoder.py index 0109cc500..6d35b71e4 100644 --- a/funasr/models/decoder/rnnt_decoder.py +++ b/funasr/models/transducer/rnnt_decoder.py @@ -4,7 +4,7 @@ from typing import List, Optional, Tuple import torch -from funasr.modules.beam_search.beam_search_transducer import Hypothesis +from funasr.models.transducer.beam_search_transducer import Hypothesis from funasr.models.specaug.specaug import SpecAug class RNNTDecoder(torch.nn.Module): diff --git a/funasr/models/transformer/__init__.py b/funasr/models/transformer/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/funasr/modules/attention.py b/funasr/models/transformer/attention.py similarity index 99% rename from funasr/modules/attention.py rename to funasr/models/transformer/attention.py index b007d586b..04607c64c 100644 --- a/funasr/modules/attention.py +++ b/funasr/models/transformer/attention.py @@ -14,7 +14,7 @@ from torch import nn from typing import Optional, Tuple import torch.nn.functional as F -from funasr.modules.nets_utils import make_pad_mask +from funasr.models.transformer.utils.nets_utils import make_pad_mask import funasr.modules.lora.layers as lora class MultiHeadedAttention(nn.Module): diff --git a/funasr/modules/embedding.py b/funasr/models/transformer/embedding.py similarity index 100% rename from funasr/modules/embedding.py rename to funasr/models/transformer/embedding.py diff --git a/funasr/modules/layer_norm.py b/funasr/models/transformer/layer_norm.py similarity index 100% rename from funasr/modules/layer_norm.py rename to funasr/models/transformer/layer_norm.py diff --git a/funasr/models/transformer/model.py b/funasr/models/transformer/model.py new file mode 100644 index 000000000..107d62f25 --- /dev/null +++ b/funasr/models/transformer/model.py @@ -0,0 +1,484 @@ +import logging +from contextlib import contextmanager +from distutils.version import LooseVersion +from typing import Dict +from typing import List +from typing import Optional +from typing import Tuple +from typing import Union +import tempfile +import codecs +import requests +import re +import copy +import torch +import torch.nn as nn +import random +import numpy as np +import time +# from funasr.layers.abs_normalize import AbsNormalize +from funasr.losses.label_smoothing_loss import ( + LabelSmoothingLoss, # noqa: H301 +) +# from funasr.models.ctc import CTC +# from funasr.models.decoder.abs_decoder import AbsDecoder +# from funasr.models.e2e_asr_common import ErrorCalculator +# from funasr.models.encoder.abs_encoder import AbsEncoder +# from funasr.models.frontend.abs_frontend import AbsFrontend +# from funasr.models.postencoder.abs_postencoder import AbsPostEncoder +from funasr.models.predictor.cif import mae_loss +# from funasr.models.preencoder.abs_preencoder import AbsPreEncoder +# from funasr.models.specaug.abs_specaug import AbsSpecAug +from funasr.models.transformer.add_sos_eos import add_sos_eos +from funasr.models.transformer.utils.nets_utils import make_pad_mask, pad_list +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.train_utils.device_funcs import force_gatherable +# from funasr.models.base_model import FunASRModel +# from funasr.models.predictor.cif import CifPredictorV3 +from funasr.models.paraformer.search import Hypothesis + +from funasr.models.model_class_factory import * + +if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): + from torch.cuda.amp import autocast +else: + # Nothing to do if torch<1.6.0 + @contextmanager + def autocast(enabled=True): + yield +from funasr.datasets.fun_datasets.load_audio_extract_fbank import load_audio, extract_fbank +from funasr.utils import postprocess_utils +from funasr.utils.datadir_writer import DatadirWriter + + +class Transformer(nn.Module): + """CTC-attention hybrid Encoder-Decoder model""" + + + def __init__( + self, + frontend: Optional[str] = None, + frontend_conf: Optional[Dict] = None, + specaug: Optional[str] = None, + specaug_conf: Optional[Dict] = None, + normalize: str = None, + normalize_conf: Optional[Dict] = None, + encoder: str = None, + encoder_conf: Optional[Dict] = None, + decoder: str = None, + decoder_conf: Optional[Dict] = None, + ctc: str = None, + ctc_conf: Optional[Dict] = None, + ctc_weight: float = 0.5, + interctc_weight: float = 0.0, + input_size: int = 80, + vocab_size: int = -1, + ignore_id: int = -1, + blank_id: int = 0, + sos: int = 1, + eos: int = 2, + lsm_weight: float = 0.0, + length_normalized_loss: bool = False, + report_cer: bool = True, + report_wer: bool = True, + sym_space: str = "", + sym_blank: str = "", + # extract_feats_in_collect_stats: bool = True, + share_embedding: bool = False, + # preencoder: Optional[AbsPreEncoder] = None, + # postencoder: Optional[AbsPostEncoder] = None, + **kwargs, + ): + + super().__init__() + + if frontend is not None: + frontend_class = frontend_choices.get_class(frontend) + frontend = frontend_class(**frontend_conf) + if specaug is not None: + specaug_class = specaug_choices.get_class(specaug) + specaug = specaug_class(**specaug_conf) + if normalize is not None: + normalize_class = normalize_choices.get_class(normalize) + normalize = normalize_class(**normalize_conf) + encoder_class = encoder_choices.get_class(encoder) + encoder = encoder_class(input_size=input_size, **encoder_conf) + encoder_output_size = encoder.output_size() + if decoder is not None: + decoder_class = decoder_choices.get_class(decoder) + decoder = decoder_class( + vocab_size=vocab_size, + encoder_output_size=encoder_output_size, + **decoder_conf, + ) + if ctc_weight > 0.0: + + if ctc_conf is None: + ctc_conf = {} + + ctc = CTC( + odim=vocab_size, encoder_output_size=encoder_output_size, **ctc_conf + ) + + self.blank_id = blank_id + self.sos = sos if sos is not None else vocab_size - 1 + self.eos = eos if eos is not None else vocab_size - 1 + self.vocab_size = vocab_size + self.ignore_id = ignore_id + self.ctc_weight = ctc_weight + self.frontend = frontend + self.specaug = specaug + self.normalize = normalize + self.encoder = encoder + + if not hasattr(self.encoder, "interctc_use_conditioning"): + self.encoder.interctc_use_conditioning = False + if self.encoder.interctc_use_conditioning: + self.encoder.conditioning_layer = torch.nn.Linear( + vocab_size, self.encoder.output_size() + ) + self.interctc_weight = interctc_weight + + # self.error_calculator = None + if ctc_weight == 1.0: + self.decoder = None + else: + self.decoder = decoder + + self.criterion_att = LabelSmoothingLoss( + size=vocab_size, + padding_idx=ignore_id, + smoothing=lsm_weight, + normalize_length=length_normalized_loss, + ) + # + # if report_cer or report_wer: + # self.error_calculator = ErrorCalculator( + # token_list, sym_space, sym_blank, report_cer, report_wer + # ) + # + if ctc_weight == 0.0: + self.ctc = None + else: + self.ctc = ctc + + self.share_embedding = share_embedding + if self.share_embedding: + self.decoder.embed = None + + self.length_normalized_loss = length_normalized_loss + self.beam_search = None + + def forward( + self, + speech: torch.Tensor, + speech_lengths: torch.Tensor, + text: torch.Tensor, + text_lengths: torch.Tensor, + **kwargs, + ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: + """Encoder + Decoder + Calc loss + Args: + speech: (Batch, Length, ...) + speech_lengths: (Batch, ) + text: (Batch, Length) + text_lengths: (Batch,) + """ + # import pdb; + # pdb.set_trace() + if len(text_lengths.size()) > 1: + text_lengths = text_lengths[:, 0] + if len(speech_lengths.size()) > 1: + speech_lengths = speech_lengths[:, 0] + + batch_size = speech.shape[0] + + # 1. Encoder + encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) + intermediate_outs = None + if isinstance(encoder_out, tuple): + intermediate_outs = encoder_out[1] + encoder_out = encoder_out[0] + + loss_att, acc_att, cer_att, wer_att = None, None, None, None + loss_ctc, cer_ctc = None, None + stats = dict() + + # decoder: CTC branch + if self.ctc_weight != 0.0: + loss_ctc, cer_ctc = self._calc_ctc_loss( + encoder_out, encoder_out_lens, text, text_lengths + ) + + # Collect CTC branch stats + stats["loss_ctc"] = loss_ctc.detach() if loss_ctc is not None else None + stats["cer_ctc"] = cer_ctc + + # Intermediate CTC (optional) + loss_interctc = 0.0 + if self.interctc_weight != 0.0 and intermediate_outs is not None: + for layer_idx, intermediate_out in intermediate_outs: + # we assume intermediate_out has the same length & padding + # as those of encoder_out + loss_ic, cer_ic = self._calc_ctc_loss( + intermediate_out, encoder_out_lens, text, text_lengths + ) + loss_interctc = loss_interctc + loss_ic + + # Collect Intermedaite CTC stats + stats["loss_interctc_layer{}".format(layer_idx)] = ( + loss_ic.detach() if loss_ic is not None else None + ) + stats["cer_interctc_layer{}".format(layer_idx)] = cer_ic + + loss_interctc = loss_interctc / len(intermediate_outs) + + # calculate whole encoder loss + loss_ctc = ( + 1 - self.interctc_weight + ) * loss_ctc + self.interctc_weight * loss_interctc + + # decoder: Attention decoder branch + loss_att, acc_att, cer_att, wer_att, loss_pre, pre_loss_att = self._calc_att_loss( + encoder_out, encoder_out_lens, text, text_lengths + ) + + # 3. CTC-Att loss definition + if self.ctc_weight == 0.0: + loss = loss_att + elif self.ctc_weight == 1.0: + loss = loss_ctc + else: + loss = self.ctc_weight * loss_ctc + (1 - self.ctc_weight) * loss_att + + # Collect Attn branch stats + stats["loss_att"] = loss_att.detach() if loss_att is not None else None + stats["acc"] = acc_att + stats["cer"] = cer_att + stats["wer"] = wer_att + + # Collect total loss stats + stats["loss"] = torch.clone(loss.detach()) + + # force_gatherable: to-device and to-tensor if scalar for DataParallel + if self.length_normalized_loss: + batch_size = int((text_lengths + 1).sum()) + loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) + return loss, stats, weight + + + def encode( + self, speech: torch.Tensor, speech_lengths: torch.Tensor, **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Frontend + Encoder. Note that this method is used by asr_inference.py + Args: + speech: (Batch, Length, ...) + speech_lengths: (Batch, ) + ind: int + """ + with autocast(False): + + # Data augmentation + if self.specaug is not None and self.training: + speech, speech_lengths = self.specaug(speech, speech_lengths) + + # Normalization for feature: e.g. Global-CMVN, Utterance-CMVN + if self.normalize is not None: + speech, speech_lengths = self.normalize(speech, speech_lengths) + + # Forward encoder + # feats: (Batch, Length, Dim) + # -> encoder_out: (Batch, Length2, Dim2) + if self.encoder.interctc_use_conditioning: + encoder_out, encoder_out_lens, _ = self.encoder( + speech, speech_lengths, ctc=self.ctc + ) + else: + encoder_out, encoder_out_lens, _ = self.encoder(speech, speech_lengths) + intermediate_outs = None + if isinstance(encoder_out, tuple): + intermediate_outs = encoder_out[1] + encoder_out = encoder_out[0] + + if intermediate_outs is not None: + return (encoder_out, intermediate_outs), encoder_out_lens + + return encoder_out, encoder_out_lens + + def _calc_att_loss( + self, + encoder_out: torch.Tensor, + encoder_out_lens: torch.Tensor, + ys_pad: torch.Tensor, + ys_pad_lens: torch.Tensor, + ): + ys_in_pad, ys_out_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) + ys_in_lens = ys_pad_lens + 1 + + # 1. Forward decoder + decoder_out, _ = self.decoder( + encoder_out, encoder_out_lens, ys_in_pad, ys_in_lens + ) + + # 2. Compute attention loss + loss_att = self.criterion_att(decoder_out, ys_out_pad) + acc_att = th_accuracy( + decoder_out.view(-1, self.vocab_size), + ys_out_pad, + ignore_label=self.ignore_id, + ) + + # Compute cer/wer using attention-decoder + if self.training or self.error_calculator is None: + cer_att, wer_att = None, None + else: + ys_hat = decoder_out.argmax(dim=-1) + cer_att, wer_att = self.error_calculator(ys_hat.cpu(), ys_pad.cpu()) + + return loss_att, acc_att, cer_att, wer_att + + def _calc_ctc_loss( + self, + encoder_out: torch.Tensor, + encoder_out_lens: torch.Tensor, + ys_pad: torch.Tensor, + ys_pad_lens: torch.Tensor, + ): + # Calc CTC loss + loss_ctc = self.ctc(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens) + + # Calc CER using CTC + cer_ctc = None + if not self.training and self.error_calculator is not None: + ys_hat = self.ctc.argmax(encoder_out).data + cer_ctc = self.error_calculator(ys_hat.cpu(), ys_pad.cpu(), is_ctc=True) + return loss_ctc, cer_ctc + + def init_beam_search(self, + **kwargs, + ): + from funasr.models.transformer.search import BeamSearch + from funasr.models.transformer.scorers.ctc import CTCPrefixScorer + from funasr.models.transformer.scorers.length_bonus import LengthBonus + + # 1. Build ASR model + scorers = {} + + if self.ctc != None: + ctc = CTCPrefixScorer(ctc=self.ctc, eos=self.eos) + scorers.update( + ctc=ctc + ) + token_list = kwargs.get("token_list") + scorers.update( + length_bonus=LengthBonus(len(token_list)), + ) + + + # 3. Build ngram model + # ngram is not supported now + ngram = None + scorers["ngram"] = ngram + + weights = dict( + decoder=1.0 - kwargs.get("decoding_ctc_weight"), + ctc=kwargs.get("decoding_ctc_weight", 0.0), + lm=kwargs.get("lm_weight", 0.0), + ngram=kwargs.get("ngram_weight", 0.0), + length_bonus=kwargs.get("penalty", 0.0), + ) + beam_search = BeamSearch( + beam_size=kwargs.get("beam_size", 2), + weights=weights, + scorers=scorers, + sos=self.sos, + eos=self.eos, + vocab_size=len(token_list), + token_list=token_list, + pre_beam_score_key=None if self.ctc_weight == 1.0 else "full", + ) + # beam_search.to(device=kwargs.get("device", "cpu"), dtype=getattr(torch, kwargs.get("dtype", "float32"))).eval() + # for scorer in scorers.values(): + # if isinstance(scorer, torch.nn.Module): + # scorer.to(device=kwargs.get("device", "cpu"), dtype=getattr(torch, kwargs.get("dtype", "float32"))).eval() + self.beam_search = beam_search + + def generate(self, + data_in: list, + data_lengths: list=None, + key: list=None, + tokenizer=None, + **kwargs, + ): + + if kwargs.get("batch_size", 1) > 1: + raise NotImplementedError("batch decoding is not implemented") + + # init beamsearch + is_use_ctc = kwargs.get("decoding_ctc_weight", 0.0) > 0.00001 and self.ctc != None + is_use_lm = kwargs.get("lm_weight", 0.0) > 0.00001 and kwargs.get("lm_file", None) is not None + if self.beam_search is None and (is_use_lm or is_use_ctc): + logging.info("enable beam_search") + self.init_beam_search(**kwargs) + self.nbest = kwargs.get("nbest", 1) + + meta_data = {} + # extract fbank feats + time1 = time.perf_counter() + audio_sample_list = load_audio(data_in, fs=self.frontend.fs, audio_fs=kwargs.get("fs", 16000)) + time2 = time.perf_counter() + meta_data["load_data"] = f"{time2 - time1:0.3f}" + speech, speech_lengths = extract_fbank(audio_sample_list, date_type=kwargs.get("date_type", "sound"), frontend=self.frontend) + time3 = time.perf_counter() + meta_data["extract_feat"] = f"{time3 - time2:0.3f}" + meta_data["batch_data_time"] = speech_lengths.sum().item() * self.frontend.frame_shift * self.frontend.lfr_n / 1000 + + speech.to(device=kwargs["device"]), speech_lengths.to(device=kwargs["device"]) + + # Encoder + encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) + if isinstance(encoder_out, tuple): + encoder_out = encoder_out[0] + + # c. Passed the encoder result and the beam search + nbest_hyps = self.beam_search( + x=encoder_out[0], maxlenratio=kwargs.get("maxlenratio", 0.0), minlenratio=kwargs.get("minlenratio", 0.0) + ) + + nbest_hyps = nbest_hyps[: self.nbest] + + + results = [] + b, n, d = encoder_out.size() + for i in range(b): + + for nbest_idx, hyp in enumerate(nbest_hyps): + ibest_writer = None + if ibest_writer is None and kwargs.get("output_dir") is not None: + writer = DatadirWriter(kwargs.get("output_dir")) + ibest_writer = writer[f"{nbest_idx+1}best_recog"] + # remove sos/eos and get results + last_pos = -1 + if isinstance(hyp.yseq, list): + token_int = hyp.yseq[1:last_pos] + else: + 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 != self.eos and x != self.sos and x != self.blank_id, token_int)) + + # Change integer-ids to tokens + token = tokenizer.ids2tokens(token_int) + text = tokenizer.tokens2text(token) + + text_postprocessed, _ = postprocess_utils.sentence_postprocess(token) + result_i = {"key": key[i], "token": token, "text": text, "text_postprocessed": text_postprocessed} + results.append(result_i) + + if ibest_writer is not None: + ibest_writer["token"][key[i]] = " ".join(token) + ibest_writer["text"][key[i]] = text + ibest_writer["text_postprocessed"][key[i]] = text_postprocessed + + return results, meta_data + diff --git a/funasr/modules/positionwise_feed_forward.py b/funasr/models/transformer/positionwise_feed_forward.py similarity index 96% rename from funasr/modules/positionwise_feed_forward.py rename to funasr/models/transformer/positionwise_feed_forward.py index 61b874fda..ffa0f4e63 100644 --- a/funasr/modules/positionwise_feed_forward.py +++ b/funasr/models/transformer/positionwise_feed_forward.py @@ -8,7 +8,7 @@ import torch -from funasr.modules.layer_norm import LayerNorm +from funasr.models.transformer.layer_norm import LayerNorm class PositionwiseFeedForward(torch.nn.Module): diff --git a/funasr/modules/scorers/__init__.py b/funasr/models/transformer/scorers/__init__.py similarity index 100% rename from funasr/modules/scorers/__init__.py rename to funasr/models/transformer/scorers/__init__.py diff --git a/funasr/modules/scorers/ctc.py b/funasr/models/transformer/scorers/ctc.py similarity index 95% rename from funasr/modules/scorers/ctc.py rename to funasr/models/transformer/scorers/ctc.py index 61deace59..6639a1312 100644 --- a/funasr/modules/scorers/ctc.py +++ b/funasr/models/transformer/scorers/ctc.py @@ -3,9 +3,9 @@ import numpy as np import torch -from funasr.modules.scorers.ctc_prefix_score import CTCPrefixScore -from funasr.modules.scorers.ctc_prefix_score import CTCPrefixScoreTH -from funasr.modules.scorers.scorer_interface import BatchPartialScorerInterface +from funasr.models.transformer.scorers.ctc_prefix_score import CTCPrefixScore +from funasr.models.transformer.scorers.ctc_prefix_score import CTCPrefixScoreTH +from funasr.models.transformer.scorers.scorer_interface import BatchPartialScorerInterface class CTCPrefixScorer(BatchPartialScorerInterface): diff --git a/funasr/modules/scorers/ctc_prefix_score.py b/funasr/models/transformer/scorers/ctc_prefix_score.py similarity index 100% rename from funasr/modules/scorers/ctc_prefix_score.py rename to funasr/models/transformer/scorers/ctc_prefix_score.py diff --git a/funasr/modules/scorers/length_bonus.py b/funasr/models/transformer/scorers/length_bonus.py similarity index 95% rename from funasr/modules/scorers/length_bonus.py rename to funasr/models/transformer/scorers/length_bonus.py index 7f576e04f..8156f1442 100644 --- a/funasr/modules/scorers/length_bonus.py +++ b/funasr/models/transformer/scorers/length_bonus.py @@ -5,7 +5,7 @@ from typing import Tuple import torch -from funasr.modules.scorers.scorer_interface import BatchScorerInterface +from funasr.models.transformer.scorers.scorer_interface import BatchScorerInterface class LengthBonus(BatchScorerInterface): diff --git a/funasr/modules/scorers/scorer_interface.py b/funasr/models/transformer/scorers/scorer_interface.py similarity index 100% rename from funasr/modules/scorers/scorer_interface.py rename to funasr/models/transformer/scorers/scorer_interface.py diff --git a/funasr/models/transformer/search.py b/funasr/models/transformer/search.py new file mode 100644 index 000000000..39c4f8c48 --- /dev/null +++ b/funasr/models/transformer/search.py @@ -0,0 +1,460 @@ +from itertools import chain +import logging +from typing import Any +from typing import Dict +from typing import List +from typing import NamedTuple +from typing import Tuple +from typing import Union + +import torch + +from funasr.metrics import end_detect +from funasr.models.transformer.scorers.scorer_interface import PartialScorerInterface +from funasr.models.transformer.scorers.scorer_interface import ScorerInterface + +class Hypothesis(NamedTuple): + """Hypothesis data type.""" + + yseq: torch.Tensor + score: Union[float, torch.Tensor] = 0 + scores: Dict[str, Union[float, torch.Tensor]] = 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 BeamSearch(torch.nn.Module): + """Beam search implementation.""" + + def __init__( + self, + scorers: Dict[str, ScorerInterface], + weights: Dict[str, float], + beam_size: int, + vocab_size: int, + sos: int, + eos: int, + token_list: List[str] = None, + pre_beam_ratio: float = 1.5, + pre_beam_score_key: str = None, + ): + """Initialize beam search. + + Args: + scorers (dict[str, ScorerInterface]): Dict of decoder modules + e.g., Decoder, CTCPrefixScorer, LM + The scorer will be ignored if it is `None` + weights (dict[str, float]): Dict of weights for each scorers + The scorer will be ignored if its weight is 0 + beam_size (int): The number of hypotheses kept during search + vocab_size (int): The number of vocabulary + sos (int): Start of sequence id + eos (int): End of sequence id + token_list (list[str]): List of tokens for debug log + pre_beam_score_key (str): key of scores to perform pre-beam search + pre_beam_ratio (float): beam size in the pre-beam search + will be `int(pre_beam_ratio * beam_size)` + + """ + super().__init__() + # set scorers + self.weights = weights + self.scorers = dict() + self.full_scorers = dict() + self.part_scorers = dict() + # this module dict is required for recursive cast + # `self.to(device, dtype)` in `recog.py` + self.nn_dict = torch.nn.ModuleDict() + for k, v in scorers.items(): + w = weights.get(k, 0) + if w == 0 or v is None: + continue + assert isinstance( + v, ScorerInterface + ), f"{k} ({type(v)}) does not implement ScorerInterface" + self.scorers[k] = v + if isinstance(v, PartialScorerInterface): + self.part_scorers[k] = v + else: + self.full_scorers[k] = v + if isinstance(v, torch.nn.Module): + self.nn_dict[k] = v + + # set configurations + self.sos = sos + self.eos = eos + self.token_list = token_list + self.pre_beam_size = int(pre_beam_ratio * beam_size) + self.beam_size = beam_size + self.n_vocab = vocab_size + if ( + pre_beam_score_key is not None + and pre_beam_score_key != "full" + and pre_beam_score_key not in self.full_scorers + ): + raise KeyError(f"{pre_beam_score_key} is not found in {self.full_scorers}") + self.pre_beam_score_key = pre_beam_score_key + self.do_pre_beam = ( + self.pre_beam_score_key is not None + and self.pre_beam_size < self.n_vocab + and len(self.part_scorers) > 0 + ) + + def init_hyp(self, x: torch.Tensor) -> List[Hypothesis]: + """Get an initial hypothesis data. + + Args: + x (torch.Tensor): The encoder output feature + + Returns: + Hypothesis: The initial hypothesis. + + """ + init_states = dict() + init_scores = dict() + for k, d in self.scorers.items(): + init_states[k] = d.init_state(x) + init_scores[k] = 0.0 + return [ + Hypothesis( + score=0.0, + scores=init_scores, + states=init_states, + yseq=torch.tensor([self.sos], device=x.device), + ) + ] + + @staticmethod + def append_token(xs: torch.Tensor, x: int) -> torch.Tensor: + """Append new token to prefix tokens. + + Args: + xs (torch.Tensor): The prefix token + x (int): The new token to append + + Returns: + torch.Tensor: New tensor contains: xs + [x] with xs.dtype and xs.device + + """ + x = torch.tensor([x], dtype=xs.dtype, device=xs.device) + return torch.cat((xs, x)) + + def score_full( + self, hyp: Hypothesis, x: torch.Tensor + ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: + """Score new hypothesis by `self.full_scorers`. + + Args: + hyp (Hypothesis): Hypothesis with prefix tokens to score + x (torch.Tensor): Corresponding input feature + + Returns: + Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of + score dict of `hyp` that has string keys of `self.full_scorers` + and tensor score values of shape: `(self.n_vocab,)`, + and state dict that has string keys + and state values of `self.full_scorers` + + """ + scores = dict() + states = dict() + for k, d in self.full_scorers.items(): + scores[k], states[k] = d.score(hyp.yseq, hyp.states[k], x) + return scores, states + + def score_partial( + self, hyp: Hypothesis, ids: torch.Tensor, x: torch.Tensor + ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: + """Score new hypothesis by `self.part_scorers`. + + Args: + hyp (Hypothesis): Hypothesis with prefix tokens to score + ids (torch.Tensor): 1D tensor of new partial tokens to score + x (torch.Tensor): Corresponding input feature + + Returns: + Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of + score dict of `hyp` that has string keys of `self.part_scorers` + and tensor score values of shape: `(len(ids),)`, + and state dict that has string keys + and state values of `self.part_scorers` + + """ + scores = dict() + states = dict() + for k, d in self.part_scorers.items(): + scores[k], states[k] = d.score_partial(hyp.yseq, ids, hyp.states[k], x) + return scores, states + + def beam( + self, weighted_scores: torch.Tensor, ids: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute topk full token ids and partial token ids. + + Args: + weighted_scores (torch.Tensor): The weighted sum scores for each tokens. + Its shape is `(self.n_vocab,)`. + ids (torch.Tensor): The partial token ids to compute topk + + Returns: + Tuple[torch.Tensor, torch.Tensor]: + The topk full token ids and partial token ids. + Their shapes are `(self.beam_size,)` + + """ + # no pre beam performed + if weighted_scores.size(0) == ids.size(0): + top_ids = weighted_scores.topk(self.beam_size)[1] + return top_ids, top_ids + + # mask pruned in pre-beam not to select in topk + tmp = weighted_scores[ids] + weighted_scores[:] = -float("inf") + weighted_scores[ids] = tmp + top_ids = weighted_scores.topk(self.beam_size)[1] + local_ids = weighted_scores[ids].topk(self.beam_size)[1] + return top_ids, local_ids + + @staticmethod + def merge_scores( + prev_scores: Dict[str, float], + next_full_scores: Dict[str, torch.Tensor], + full_idx: int, + next_part_scores: Dict[str, torch.Tensor], + part_idx: int, + ) -> Dict[str, torch.Tensor]: + """Merge scores for new hypothesis. + + Args: + prev_scores (Dict[str, float]): + The previous hypothesis scores by `self.scorers` + next_full_scores (Dict[str, torch.Tensor]): scores by `self.full_scorers` + full_idx (int): The next token id for `next_full_scores` + next_part_scores (Dict[str, torch.Tensor]): + scores of partial tokens by `self.part_scorers` + part_idx (int): The new token id for `next_part_scores` + + Returns: + Dict[str, torch.Tensor]: The new score dict. + Its keys are names of `self.full_scorers` and `self.part_scorers`. + Its values are scalar tensors by the scorers. + + """ + new_scores = dict() + for k, v in next_full_scores.items(): + new_scores[k] = prev_scores[k] + v[full_idx] + for k, v in next_part_scores.items(): + new_scores[k] = prev_scores[k] + v[part_idx] + return new_scores + + def merge_states(self, states: Any, part_states: Any, part_idx: int) -> Any: + """Merge states for new hypothesis. + + Args: + states: states of `self.full_scorers` + part_states: states of `self.part_scorers` + part_idx (int): The new token id for `part_scores` + + Returns: + Dict[str, torch.Tensor]: The new score dict. + Its keys are names of `self.full_scorers` and `self.part_scorers`. + Its values are states of the scorers. + + """ + new_states = dict() + for k, v in states.items(): + new_states[k] = v + for k, d in self.part_scorers.items(): + new_states[k] = d.select_state(part_states[k], part_idx) + return new_states + + def search( + self, running_hyps: List[Hypothesis], x: torch.Tensor + ) -> List[Hypothesis]: + """Search new tokens for running hypotheses and encoded speech x. + + Args: + running_hyps (List[Hypothesis]): Running hypotheses on beam + x (torch.Tensor): Encoded speech feature (T, D) + + Returns: + List[Hypotheses]: Best sorted hypotheses + + """ + best_hyps = [] + part_ids = torch.arange(self.n_vocab, device=x.device) # no pre-beam + for hyp in running_hyps: + # scoring + weighted_scores = torch.zeros(self.n_vocab, dtype=x.dtype, device=x.device) + scores, states = self.score_full(hyp, x) + for k in self.full_scorers: + weighted_scores += self.weights[k] * scores[k] + # partial scoring + if self.do_pre_beam: + pre_beam_scores = ( + weighted_scores + if self.pre_beam_score_key == "full" + else scores[self.pre_beam_score_key] + ) + part_ids = torch.topk(pre_beam_scores, self.pre_beam_size)[1] + part_scores, part_states = self.score_partial(hyp, part_ids, x) + for k in self.part_scorers: + weighted_scores[part_ids] += self.weights[k] * part_scores[k] + # add previous hyp score + weighted_scores += hyp.score + + # update hyps + for j, part_j in zip(*self.beam(weighted_scores, part_ids)): + # will be (2 x beam at most) + best_hyps.append( + Hypothesis( + score=weighted_scores[j], + yseq=self.append_token(hyp.yseq, j), + scores=self.merge_scores( + hyp.scores, scores, j, part_scores, part_j + ), + states=self.merge_states(states, part_states, part_j), + ) + ) + + # sort and prune 2 x beam -> beam + best_hyps = sorted(best_hyps, key=lambda x: x.score, reverse=True)[ + : min(len(best_hyps), self.beam_size) + ] + return best_hyps + + def forward( + self, x: torch.Tensor, maxlenratio: float = 0.0, minlenratio: float = 0.0 + ) -> List[Hypothesis]: + """Perform beam search. + + Args: + x (torch.Tensor): Encoded speech feature (T, D) + maxlenratio (float): Input length ratio to obtain max output length. + If maxlenratio=0.0 (default), it uses a end-detect function + to automatically find maximum hypothesis lengths + If maxlenratio<0.0, its absolute value is interpreted + as a constant max output length. + minlenratio (float): Input length ratio to obtain min output length. + + Returns: + list[Hypothesis]: N-best decoding results + + """ + # set length bounds + if maxlenratio == 0: + maxlen = x.shape[0] + elif maxlenratio < 0: + maxlen = -1 * int(maxlenratio) + else: + maxlen = max(1, int(maxlenratio * x.size(0))) + minlen = int(minlenratio * x.size(0)) + logging.info("decoder input length: " + str(x.shape[0])) + logging.info("max output length: " + str(maxlen)) + logging.info("min output length: " + str(minlen)) + + # main loop of prefix search + running_hyps = self.init_hyp(x) + ended_hyps = [] + for i in range(maxlen): + logging.debug("position " + str(i)) + best = self.search(running_hyps, x) + # post process of one iteration + running_hyps = self.post_process(i, maxlen, maxlenratio, best, ended_hyps) + # end detection + if maxlenratio == 0.0 and end_detect([h.asdict() for h in ended_hyps], i): + logging.info(f"end detected at {i}") + break + if len(running_hyps) == 0: + logging.info("no hypothesis. Finish decoding.") + break + else: + logging.debug(f"remained hypotheses: {len(running_hyps)}") + + nbest_hyps = sorted(ended_hyps, key=lambda x: x.score, reverse=True) + # check the number of hypotheses reaching to eos + if len(nbest_hyps) == 0: + logging.warning( + "there is no N-best results, perform recognition " + "again with smaller minlenratio." + ) + return ( + [] + if minlenratio < 0.1 + else self.forward(x, maxlenratio, max(0.0, minlenratio - 0.1)) + ) + + # report the best result + best = nbest_hyps[0] + for k, v in best.scores.items(): + logging.info( + f"{v:6.2f} * {self.weights[k]:3} = {v * self.weights[k]:6.2f} for {k}" + ) + logging.info(f"total log probability: {best.score:.2f}") + logging.info(f"normalized log probability: {best.score / len(best.yseq):.2f}") + logging.info(f"total number of ended hypotheses: {len(nbest_hyps)}") + if self.token_list is not None: + logging.info( + "best hypo: " + + "".join([self.token_list[x] for x in best.yseq[1:-1]]) + + "\n" + ) + return nbest_hyps + + def post_process( + self, + i: int, + maxlen: int, + maxlenratio: float, + running_hyps: List[Hypothesis], + ended_hyps: List[Hypothesis], + ) -> List[Hypothesis]: + """Perform post-processing of beam search iterations. + + Args: + i (int): The length of hypothesis tokens. + maxlen (int): The maximum length of tokens in beam search. + maxlenratio (int): The maximum length ratio in beam search. + running_hyps (List[Hypothesis]): The running hypotheses in beam search. + ended_hyps (List[Hypothesis]): The ended hypotheses in beam search. + + Returns: + List[Hypothesis]: The new running hypotheses. + + """ + logging.debug(f"the number of running hypotheses: {len(running_hyps)}") + if self.token_list is not None: + logging.debug( + "best hypo: " + + "".join([self.token_list[x] for x in running_hyps[0].yseq[1:]]) + ) + # add eos in the final loop to avoid that there are no ended hyps + if i == maxlen - 1: + logging.info("adding in the last position in the loop") + running_hyps = [ + h._replace(yseq=self.append_token(h.yseq, self.eos)) + for h in running_hyps + ] + + # add ended hypotheses to a final list, and removed them from current hypotheses + # (this will be a problem, number of hyps < beam) + remained_hyps = [] + for hyp in running_hyps: + if hyp.yseq[-1] == self.eos: + # e.g., Word LM needs to add final score + for k, d in chain(self.full_scorers.items(), self.part_scorers.items()): + s = d.final_score(hyp.states[k]) + hyp.scores[k] += s + hyp = hyp._replace(score=hyp.score + self.weights[k] * s) + ended_hyps.append(hyp) + else: + remained_hyps.append(hyp) + return remained_hyps diff --git a/funasr/models/decoder/transformer_decoder.py b/funasr/models/transformer/transformer_decoder.py similarity index 97% rename from funasr/models/decoder/transformer_decoder.py rename to funasr/models/transformer/transformer_decoder.py index 0a9c61208..b2bea6817 100644 --- a/funasr/models/decoder/transformer_decoder.py +++ b/funasr/models/transformer/transformer_decoder.py @@ -11,21 +11,21 @@ import torch from torch import nn from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.modules.attention import MultiHeadedAttention -from funasr.modules.attention import CosineDistanceAttention -from funasr.modules.dynamic_conv import DynamicConvolution -from funasr.modules.dynamic_conv2d import DynamicConvolution2D -from funasr.modules.embedding import PositionalEncoding -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.lightconv import LightweightConvolution -from funasr.modules.lightconv2d import LightweightConvolution2D -from funasr.modules.mask import subsequent_mask -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.positionwise_feed_forward import ( +from funasr.models.transformer.attention import MultiHeadedAttention +from funasr.models.transformer.attention import CosineDistanceAttention +from funasr.models.transformer.utils.dynamic_conv import DynamicConvolution +from funasr.models.transformer.utils.dynamic_conv2d import DynamicConvolution2D +from funasr.models.transformer.embedding import PositionalEncoding +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.utils.lightconv import LightweightConvolution +from funasr.models.transformer.utils.lightconv2d import LightweightConvolution2D +from funasr.models.transformer.utils.mask import subsequent_mask +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.positionwise_feed_forward import ( PositionwiseFeedForward, # noqa: H301 ) -from funasr.modules.repeat import repeat -from funasr.modules.scorers.scorer_interface import BatchScorerInterface +from funasr.models.transformer.repeat import repeat +from funasr.models.transformer.scorers.scorer_interface import BatchScorerInterface class DecoderLayer(nn.Module): diff --git a/funasr/models/encoder/transformer_encoder.py b/funasr/models/transformer/transformer_encoder.py similarity index 95% rename from funasr/models/encoder/transformer_encoder.py rename to funasr/models/transformer/transformer_encoder.py index 4f2bef570..1126da0c5 100644 --- a/funasr/models/encoder/transformer_encoder.py +++ b/funasr/models/transformer/transformer_encoder.py @@ -13,27 +13,27 @@ import logging from funasr.models.ctc import CTC from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.modules.attention import MultiHeadedAttention -from funasr.modules.embedding import PositionalEncoding -from funasr.modules.layer_norm import LayerNorm -from funasr.modules.multi_layer_conv import Conv1dLinear -from funasr.modules.multi_layer_conv import MultiLayeredConv1d -from funasr.modules.nets_utils import make_pad_mask -from funasr.modules.positionwise_feed_forward import ( +from funasr.models.transformer.attention import MultiHeadedAttention +from funasr.models.transformer.embedding import PositionalEncoding +from funasr.models.transformer.layer_norm import LayerNorm +from funasr.models.transformer.utils.multi_layer_conv import Conv1dLinear +from funasr.models.transformer.utils.multi_layer_conv import MultiLayeredConv1d +from funasr.models.transformer.utils.nets_utils import make_pad_mask +from funasr.models.transformer.positionwise_feed_forward import ( PositionwiseFeedForward, # noqa: H301 ) -from funasr.modules.repeat import repeat -from funasr.modules.nets_utils import rename_state_dict -from funasr.modules.dynamic_conv import DynamicConvolution -from funasr.modules.dynamic_conv2d import DynamicConvolution2D -from funasr.modules.lightconv import LightweightConvolution -from funasr.modules.lightconv2d import LightweightConvolution2D -from funasr.modules.subsampling import Conv2dSubsampling -from funasr.modules.subsampling import Conv2dSubsampling2 -from funasr.modules.subsampling import Conv2dSubsampling6 -from funasr.modules.subsampling import Conv2dSubsampling8 -from funasr.modules.subsampling import TooShortUttError -from funasr.modules.subsampling import check_short_utt +from funasr.models.transformer.repeat import repeat +from funasr.models.transformer.utils.nets_utils import rename_state_dict +from funasr.models.transformer.utils.dynamic_conv import DynamicConvolution +from funasr.models.transformer.utils.dynamic_conv2d import DynamicConvolution2D +from funasr.models.transformer.utils.lightconv import LightweightConvolution +from funasr.models.transformer.utils.lightconv2d import LightweightConvolution2D +from funasr.models.transformer.subsampling import Conv2dSubsampling +from funasr.models.transformer.subsampling import Conv2dSubsampling2 +from funasr.models.transformer.subsampling import Conv2dSubsampling6 +from funasr.models.transformer.subsampling import Conv2dSubsampling8 +from funasr.models.transformer.subsampling import TooShortUttError +from funasr.models.transformer.subsampling import check_short_utt class EncoderLayer(nn.Module): diff --git a/funasr/models/transformer/utils/__init__.py b/funasr/models/transformer/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/funasr/modules/add_sos_eos.py b/funasr/models/transformer/utils/add_sos_eos.py similarity index 93% rename from funasr/modules/add_sos_eos.py rename to funasr/models/transformer/utils/add_sos_eos.py index ada1c2e01..beead1bc3 100644 --- a/funasr/modules/add_sos_eos.py +++ b/funasr/models/transformer/utils/add_sos_eos.py @@ -7,7 +7,7 @@ """Unility functions for Transformer.""" import torch -from funasr.modules.nets_utils import pad_list +from funasr.models.transformer.utils.nets_utils import pad_list def add_sos_eos(ys_pad, sos, eos, ignore_id): diff --git a/funasr/modules/dynamic_conv.py b/funasr/models/transformer/utils/dynamic_conv.py similarity index 100% rename from funasr/modules/dynamic_conv.py rename to funasr/models/transformer/utils/dynamic_conv.py diff --git a/funasr/modules/dynamic_conv2d.py b/funasr/models/transformer/utils/dynamic_conv2d.py similarity index 100% rename from funasr/modules/dynamic_conv2d.py rename to funasr/models/transformer/utils/dynamic_conv2d.py diff --git a/funasr/modules/lightconv.py b/funasr/models/transformer/utils/lightconv.py similarity index 100% rename from funasr/modules/lightconv.py rename to funasr/models/transformer/utils/lightconv.py diff --git a/funasr/modules/lightconv2d.py b/funasr/models/transformer/utils/lightconv2d.py similarity index 100% rename from funasr/modules/lightconv2d.py rename to funasr/models/transformer/utils/lightconv2d.py diff --git a/funasr/modules/mask.py b/funasr/models/transformer/utils/mask.py similarity index 100% rename from funasr/modules/mask.py rename to funasr/models/transformer/utils/mask.py diff --git a/funasr/modules/multi_layer_conv.py b/funasr/models/transformer/utils/multi_layer_conv.py similarity index 100% rename from funasr/modules/multi_layer_conv.py rename to funasr/models/transformer/utils/multi_layer_conv.py diff --git a/funasr/modules/nets_utils.py b/funasr/models/transformer/utils/nets_utils.py similarity index 100% rename from funasr/modules/nets_utils.py rename to funasr/models/transformer/utils/nets_utils.py diff --git a/funasr/modules/repeat.py b/funasr/models/transformer/utils/repeat.py similarity index 98% rename from funasr/modules/repeat.py rename to funasr/models/transformer/utils/repeat.py index 7e160660d..a44c1a010 100644 --- a/funasr/modules/repeat.py +++ b/funasr/models/transformer/utils/repeat.py @@ -7,7 +7,7 @@ """Repeat the same layer definition.""" from typing import Dict, List, Optional -from funasr.modules.layer_norm import LayerNorm +from funasr.models.transformer.layer_norm import LayerNorm import torch diff --git a/funasr/modules/subsampling.py b/funasr/models/transformer/utils/subsampling.py similarity index 99% rename from funasr/modules/subsampling.py rename to funasr/models/transformer/utils/subsampling.py index af33aef10..64a9dbc65 100644 --- a/funasr/modules/subsampling.py +++ b/funasr/models/transformer/utils/subsampling.py @@ -8,10 +8,10 @@ import numpy as np import torch import torch.nn.functional as F -from funasr.modules.embedding import PositionalEncoding +from funasr.models.transformer.embedding import PositionalEncoding import logging -from funasr.modules.streaming_utils.utils import sequence_mask -from funasr.modules.nets_utils import sub_factor_to_params, pad_to_len +from funasr.models.scama.utils import sequence_mask +from funasr.models.transformer.utils.nets_utils import sub_factor_to_params, pad_to_len from typing import Optional, Tuple, Union import math diff --git a/funasr/modules/subsampling_without_posenc.py b/funasr/models/transformer/utils/subsampling_without_posenc.py similarity index 100% rename from funasr/modules/subsampling_without_posenc.py rename to funasr/models/transformer/utils/subsampling_without_posenc.py diff --git a/funasr/modules/vgg2l.py b/funasr/models/transformer/utils/vgg2l.py similarity index 100% rename from funasr/modules/vgg2l.py rename to funasr/models/transformer/utils/vgg2l.py diff --git a/funasr/models/uniasr/__init__.py b/funasr/models/uniasr/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/funasr/models/e2e_uni_asr.py b/funasr/models/uniasr/e2e_uni_asr.py similarity index 99% rename from funasr/models/e2e_uni_asr.py rename to funasr/models/uniasr/e2e_uni_asr.py index 07ebd818d..0fb40399a 100644 --- a/funasr/models/e2e_uni_asr.py +++ b/funasr/models/uniasr/e2e_uni_asr.py @@ -10,8 +10,8 @@ from typing import Union import torch from funasr.models.e2e_asr_common import ErrorCalculator -from funasr.modules.nets_utils import th_accuracy -from funasr.modules.add_sos_eos import add_sos_eos +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.models.transformer.add_sos_eos import add_sos_eos from funasr.losses.label_smoothing_loss import ( LabelSmoothingLoss, # noqa: H301 ) @@ -23,9 +23,9 @@ from funasr.models.postencoder.abs_postencoder import AbsPostEncoder from funasr.models.preencoder.abs_preencoder import AbsPreEncoder from funasr.models.specaug.abs_specaug import AbsSpecAug from funasr.layers.abs_normalize import AbsNormalize -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.train_utils.device_funcs import force_gatherable from funasr.models.base_model import FunASRModel -from funasr.modules.streaming_utils.chunk_utilis import sequence_mask +from funasr.models.scama.chunk_utilis import sequence_mask from funasr.models.predictor.cif import mae_loss if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): @@ -142,7 +142,7 @@ class UniASR(FunASRModel): self.criterion_pre = mae_loss(normalize_length=length_normalized_loss) self.step_cur = 0 if self.encoder.overlap_chunk_cls is not None: - from funasr.modules.streaming_utils.chunk_utilis import build_scama_mask_for_cross_attention_decoder + from funasr.models.scama.chunk_utilis import build_scama_mask_for_cross_attention_decoder self.build_scama_mask_for_cross_attention_decoder_fn = build_scama_mask_for_cross_attention_decoder self.decoder_attention_chunk_type = decoder_attention_chunk_type @@ -160,7 +160,7 @@ class UniASR(FunASRModel): self.stride_conv = stride_conv self.loss_weight_model1 = loss_weight_model1 if self.encoder2.overlap_chunk_cls is not None: - from funasr.modules.streaming_utils.chunk_utilis import build_scama_mask_for_cross_attention_decoder + from funasr.models.scama.chunk_utilis import build_scama_mask_for_cross_attention_decoder self.build_scama_mask_for_cross_attention_decoder_fn2 = build_scama_mask_for_cross_attention_decoder self.decoder_attention_chunk_type2 = decoder_attention_chunk_type2 diff --git a/funasr/models/whisper/__init__.py b/funasr/models/whisper/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/funasr/models/whisper_models/model.py b/funasr/models/whisper/model.py similarity index 97% rename from funasr/models/whisper_models/model.py rename to funasr/models/whisper/model.py index 8193ba46b..6a6d47c6e 100644 --- a/funasr/models/whisper_models/model.py +++ b/funasr/models/whisper/model.py @@ -8,8 +8,8 @@ import torch.nn.functional as F from torch import Tensor from torch import nn -from funasr.models.base_model import FunASRModel -from funasr.utils.whisper_utils.decoding import detect_language as detect_language_function, decode as decode_function + +from funasr.models.whisper.utils.decoding import detect_language as detect_language_function, decode as decode_function @dataclass class ModelDimensions: @@ -194,7 +194,7 @@ class TextDecoder(nn.Module): return logits -class Whisper(FunASRModel): +class Whisper(nn.Module): def __init__(self, dims: dict): super().__init__() dims = ModelDimensions(**dims) diff --git a/funasr/models/whisper/utils/__init__.py b/funasr/models/whisper/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/funasr/utils/whisper_utils/assets/gpt2/merges.txt b/funasr/models/whisper/utils/assets/gpt2/merges.txt similarity index 100% rename from funasr/utils/whisper_utils/assets/gpt2/merges.txt rename to funasr/models/whisper/utils/assets/gpt2/merges.txt diff --git a/funasr/utils/whisper_utils/assets/gpt2/special_tokens_map.json b/funasr/models/whisper/utils/assets/gpt2/special_tokens_map.json similarity index 100% rename from funasr/utils/whisper_utils/assets/gpt2/special_tokens_map.json rename to funasr/models/whisper/utils/assets/gpt2/special_tokens_map.json diff --git a/funasr/utils/whisper_utils/assets/gpt2/tokenizer_config.json b/funasr/models/whisper/utils/assets/gpt2/tokenizer_config.json similarity index 100% rename from funasr/utils/whisper_utils/assets/gpt2/tokenizer_config.json rename to funasr/models/whisper/utils/assets/gpt2/tokenizer_config.json diff --git a/funasr/utils/whisper_utils/assets/gpt2/vocab.json b/funasr/models/whisper/utils/assets/gpt2/vocab.json similarity index 100% rename from funasr/utils/whisper_utils/assets/gpt2/vocab.json rename to funasr/models/whisper/utils/assets/gpt2/vocab.json diff --git a/funasr/utils/whisper_utils/assets/mel_filters.npz b/funasr/models/whisper/utils/assets/mel_filters.npz similarity index 100% rename from funasr/utils/whisper_utils/assets/mel_filters.npz rename to funasr/models/whisper/utils/assets/mel_filters.npz diff --git a/funasr/utils/whisper_utils/assets/multilingual/added_tokens.json b/funasr/models/whisper/utils/assets/multilingual/added_tokens.json similarity index 100% rename from funasr/utils/whisper_utils/assets/multilingual/added_tokens.json rename to funasr/models/whisper/utils/assets/multilingual/added_tokens.json diff --git a/funasr/utils/whisper_utils/assets/multilingual/merges.txt b/funasr/models/whisper/utils/assets/multilingual/merges.txt similarity index 100% rename from funasr/utils/whisper_utils/assets/multilingual/merges.txt rename to funasr/models/whisper/utils/assets/multilingual/merges.txt diff --git a/funasr/utils/whisper_utils/assets/multilingual/special_tokens_map.json b/funasr/models/whisper/utils/assets/multilingual/special_tokens_map.json similarity index 100% rename from funasr/utils/whisper_utils/assets/multilingual/special_tokens_map.json rename to funasr/models/whisper/utils/assets/multilingual/special_tokens_map.json diff --git a/funasr/utils/whisper_utils/assets/multilingual/tokenizer_config.json b/funasr/models/whisper/utils/assets/multilingual/tokenizer_config.json similarity index 100% rename from funasr/utils/whisper_utils/assets/multilingual/tokenizer_config.json rename to funasr/models/whisper/utils/assets/multilingual/tokenizer_config.json diff --git a/funasr/utils/whisper_utils/assets/multilingual/vocab.json b/funasr/models/whisper/utils/assets/multilingual/vocab.json similarity index 100% rename from funasr/utils/whisper_utils/assets/multilingual/vocab.json rename to funasr/models/whisper/utils/assets/multilingual/vocab.json diff --git a/funasr/utils/whisper_utils/audio.py b/funasr/models/whisper/utils/audio.py similarity index 98% rename from funasr/utils/whisper_utils/audio.py rename to funasr/models/whisper/utils/audio.py index 6dd4cb1b5..c35a6efae 100644 --- a/funasr/utils/whisper_utils/audio.py +++ b/funasr/models/whisper/utils/audio.py @@ -10,7 +10,7 @@ import numpy as np import torch import torch.nn.functional as F -from funasr.utils.whisper_utils.utils import exact_div +from funasr.models.whisper.utils.utils import exact_div # hard-coded audio hyperparameters SAMPLE_RATE = 16000 diff --git a/funasr/utils/whisper_utils/decoding.py b/funasr/models/whisper/utils/decoding.py similarity index 99% rename from funasr/utils/whisper_utils/decoding.py rename to funasr/models/whisper/utils/decoding.py index afe80b1f1..8ddd6aedf 100644 --- a/funasr/utils/whisper_utils/decoding.py +++ b/funasr/models/whisper/utils/decoding.py @@ -7,9 +7,9 @@ import torch.nn.functional as F from torch import Tensor from torch.distributions import Categorical -from funasr.utils.whisper_utils.audio import CHUNK_LENGTH -from funasr.utils.whisper_utils.tokenizer import Tokenizer, get_tokenizer -from funasr.utils.whisper_utils.utils import compression_ratio +from funasr.models.whisper.utils.audio import CHUNK_LENGTH +from funasr.models.whisper.utils.tokenizer import Tokenizer, get_tokenizer +from funasr.models.whisper.utils.utils import compression_ratio if TYPE_CHECKING: from funasr.models.whisper_models.model import Whisper diff --git a/funasr/utils/whisper_utils/tokenizer.py b/funasr/models/whisper/utils/tokenizer.py similarity index 100% rename from funasr/utils/whisper_utils/tokenizer.py rename to funasr/models/whisper/utils/tokenizer.py diff --git a/funasr/utils/whisper_utils/transcribe.py b/funasr/models/whisper/utils/transcribe.py similarity index 97% rename from funasr/utils/whisper_utils/transcribe.py rename to funasr/models/whisper/utils/transcribe.py index 3a7e94643..e2fa2bc63 100644 --- a/funasr/utils/whisper_utils/transcribe.py +++ b/funasr/models/whisper/utils/transcribe.py @@ -7,10 +7,10 @@ import numpy as np import torch import tqdm -from funasr.utils.whisper_utils.audio import SAMPLE_RATE, N_FRAMES, HOP_LENGTH, pad_or_trim, log_mel_spectrogram -from funasr.utils.whisper_utils.decoding import DecodingOptions, DecodingResult -from funasr.utils.whisper_utils.tokenizer import LANGUAGES, TO_LANGUAGE_CODE, get_tokenizer -from funasr.utils.whisper_utils.utils import exact_div, format_timestamp, make_safe, optional_int, optional_float, str2bool, get_writer +from funasr.models.whisper.utils.audio import SAMPLE_RATE, N_FRAMES, HOP_LENGTH, pad_or_trim, log_mel_spectrogram +from funasr.models.whisper.utils.decoding import DecodingOptions, DecodingResult +from funasr.models.whisper.utils.tokenizer import LANGUAGES, TO_LANGUAGE_CODE, get_tokenizer +from funasr.models.whisper.utils.utils import exact_div, format_timestamp, make_safe, optional_int, optional_float, str2bool, get_writer if TYPE_CHECKING: from .model import Whisper diff --git a/funasr/utils/whisper_utils/utils.py b/funasr/models/whisper/utils/utils.py similarity index 100% rename from funasr/utils/whisper_utils/utils.py rename to funasr/models/whisper/utils/utils.py diff --git a/funasr/models/xvector/__init__.py b/funasr/models/xvector/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/funasr/models/e2e_sv.py b/funasr/models/xvector/e2e_sv.py similarity index 97% rename from funasr/models/e2e_sv.py rename to funasr/models/xvector/e2e_sv.py index 8be63d4a8..3eac9ef37 100644 --- a/funasr/models/e2e_sv.py +++ b/funasr/models/xvector/e2e_sv.py @@ -24,10 +24,10 @@ from funasr.models.frontend.abs_frontend import AbsFrontend from funasr.models.postencoder.abs_postencoder import AbsPostEncoder from funasr.models.preencoder.abs_preencoder import AbsPreEncoder from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.modules.add_sos_eos import add_sos_eos -from funasr.modules.e2e_asr_common import ErrorCalculator -from funasr.modules.nets_utils import th_accuracy -from funasr.torch_utils.device_funcs import force_gatherable +from funasr.models.transformer.add_sos_eos import add_sos_eos +from funasr.metrics import ErrorCalculator +from funasr.models.transformer.utils.nets_utils import th_accuracy +from funasr.train_utils.device_funcs import force_gatherable from funasr.models.base_model import FunASRModel if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): diff --git a/funasr/modules/beam_search/batch_beam_search.py b/funasr/modules/beam_search/batch_beam_search.py deleted file mode 100644 index 6d2da8d9a..000000000 --- a/funasr/modules/beam_search/batch_beam_search.py +++ /dev/null @@ -1,348 +0,0 @@ -"""Parallel beam search module.""" - -import logging -from typing import Any -from typing import Dict -from typing import List -from typing import NamedTuple -from typing import Tuple - -import torch -from torch.nn.utils.rnn import pad_sequence - -from funasr.modules.beam_search.beam_search import BeamSearch -from funasr.modules.beam_search.beam_search import Hypothesis - - -class BatchHypothesis(NamedTuple): - """Batchfied/Vectorized hypothesis data type.""" - - yseq: torch.Tensor = torch.tensor([]) # (batch, maxlen) - score: torch.Tensor = torch.tensor([]) # (batch,) - length: torch.Tensor = torch.tensor([]) # (batch,) - scores: Dict[str, torch.Tensor] = dict() # values: (batch,) - states: Dict[str, Dict] = dict() - - def __len__(self) -> int: - """Return a batch size.""" - return len(self.length) - - -class BatchBeamSearch(BeamSearch): - """Batch beam search implementation.""" - - def batchfy(self, hyps: List[Hypothesis]) -> BatchHypothesis: - """Convert list to batch.""" - if len(hyps) == 0: - return BatchHypothesis() - return BatchHypothesis( - yseq=pad_sequence( - [h.yseq for h in hyps], batch_first=True, padding_value=self.eos - ), - length=torch.tensor([len(h.yseq) for h in hyps], dtype=torch.int64), - score=torch.tensor([h.score for h in hyps]), - scores={k: torch.tensor([h.scores[k] for h in hyps]) for k in self.scorers}, - states={k: [h.states[k] for h in hyps] for k in self.scorers}, - ) - - def _batch_select(self, hyps: BatchHypothesis, ids: List[int]) -> BatchHypothesis: - return BatchHypothesis( - yseq=hyps.yseq[ids], - score=hyps.score[ids], - length=hyps.length[ids], - scores={k: v[ids] for k, v in hyps.scores.items()}, - states={ - k: [self.scorers[k].select_state(v, i) for i in ids] - for k, v in hyps.states.items() - }, - ) - - def _select(self, hyps: BatchHypothesis, i: int) -> Hypothesis: - return Hypothesis( - yseq=hyps.yseq[i, : hyps.length[i]], - score=hyps.score[i], - scores={k: v[i] for k, v in hyps.scores.items()}, - states={ - k: self.scorers[k].select_state(v, i) for k, v in hyps.states.items() - }, - ) - - def unbatchfy(self, batch_hyps: BatchHypothesis) -> List[Hypothesis]: - """Revert batch to list.""" - return [ - Hypothesis( - yseq=batch_hyps.yseq[i][: batch_hyps.length[i]], - score=batch_hyps.score[i], - scores={k: batch_hyps.scores[k][i] for k in self.scorers}, - states={ - k: v.select_state(batch_hyps.states[k], i) - for k, v in self.scorers.items() - }, - ) - for i in range(len(batch_hyps.length)) - ] - - def batch_beam( - self, weighted_scores: torch.Tensor, ids: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: - """Batch-compute topk full token ids and partial token ids. - - Args: - weighted_scores (torch.Tensor): The weighted sum scores for each tokens. - Its shape is `(n_beam, self.vocab_size)`. - ids (torch.Tensor): The partial token ids to compute topk. - Its shape is `(n_beam, self.pre_beam_size)`. - - Returns: - Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: - The topk full (prev_hyp, new_token) ids - and partial (prev_hyp, new_token) ids. - Their shapes are all `(self.beam_size,)` - - """ - top_ids = weighted_scores.view(-1).topk(self.beam_size)[1] - # Because of the flatten above, `top_ids` is organized as: - # [hyp1 * V + token1, hyp2 * V + token2, ..., hypK * V + tokenK], - # where V is `self.n_vocab` and K is `self.beam_size` - prev_hyp_ids = top_ids // self.n_vocab - new_token_ids = top_ids % self.n_vocab - return prev_hyp_ids, new_token_ids, prev_hyp_ids, new_token_ids - - def init_hyp(self, x: torch.Tensor) -> BatchHypothesis: - """Get an initial hypothesis data. - - Args: - x (torch.Tensor): The encoder output feature - - Returns: - Hypothesis: The initial hypothesis. - - """ - init_states = dict() - init_scores = dict() - for k, d in self.scorers.items(): - init_states[k] = d.batch_init_state(x) - init_scores[k] = 0.0 - return self.batchfy( - [ - Hypothesis( - score=0.0, - scores=init_scores, - states=init_states, - yseq=torch.tensor([self.sos], device=x.device), - ) - ] - ) - - def score_full( - self, hyp: BatchHypothesis, x: torch.Tensor - ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: - """Score new hypothesis by `self.full_scorers`. - - Args: - hyp (Hypothesis): Hypothesis with prefix tokens to score - x (torch.Tensor): Corresponding input feature - - Returns: - Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of - score dict of `hyp` that has string keys of `self.full_scorers` - and tensor score values of shape: `(self.n_vocab,)`, - and state dict that has string keys - and state values of `self.full_scorers` - - """ - scores = dict() - states = dict() - for k, d in self.full_scorers.items(): - scores[k], states[k] = d.batch_score(hyp.yseq, hyp.states[k], x) - return scores, states - - def score_partial( - self, hyp: BatchHypothesis, ids: torch.Tensor, x: torch.Tensor - ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: - """Score new hypothesis by `self.full_scorers`. - - Args: - hyp (Hypothesis): Hypothesis with prefix tokens to score - ids (torch.Tensor): 2D tensor of new partial tokens to score - x (torch.Tensor): Corresponding input feature - - Returns: - Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of - score dict of `hyp` that has string keys of `self.full_scorers` - and tensor score values of shape: `(self.n_vocab,)`, - and state dict that has string keys - and state values of `self.full_scorers` - - """ - scores = dict() - states = dict() - for k, d in self.part_scorers.items(): - scores[k], states[k] = d.batch_score_partial( - hyp.yseq, ids, hyp.states[k], x - ) - return scores, states - - def merge_states(self, states: Any, part_states: Any, part_idx: int) -> Any: - """Merge states for new hypothesis. - - Args: - states: states of `self.full_scorers` - part_states: states of `self.part_scorers` - part_idx (int): The new token id for `part_scores` - - Returns: - Dict[str, torch.Tensor]: The new score dict. - Its keys are names of `self.full_scorers` and `self.part_scorers`. - Its values are states of the scorers. - - """ - new_states = dict() - for k, v in states.items(): - new_states[k] = v - for k, v in part_states.items(): - new_states[k] = v - return new_states - - def search(self, running_hyps: BatchHypothesis, x: torch.Tensor) -> BatchHypothesis: - """Search new tokens for running hypotheses and encoded speech x. - - Args: - running_hyps (BatchHypothesis): Running hypotheses on beam - x (torch.Tensor): Encoded speech feature (T, D) - - Returns: - BatchHypothesis: Best sorted hypotheses - - """ - n_batch = len(running_hyps) - part_ids = None # no pre-beam - # batch scoring - weighted_scores = torch.zeros( - n_batch, self.n_vocab, dtype=x.dtype, device=x.device - ) - scores, states = self.score_full(running_hyps, x.expand(n_batch, *x.shape)) - for k in self.full_scorers: - weighted_scores += self.weights[k] * scores[k] - # partial scoring - if self.do_pre_beam: - pre_beam_scores = ( - weighted_scores - if self.pre_beam_score_key == "full" - else scores[self.pre_beam_score_key] - ) - part_ids = torch.topk(pre_beam_scores, self.pre_beam_size, dim=-1)[1] - # NOTE(takaaki-hori): Unlike BeamSearch, we assume that score_partial returns - # full-size score matrices, which has non-zero scores for part_ids and zeros - # for others. - part_scores, part_states = self.score_partial(running_hyps, part_ids, x) - for k in self.part_scorers: - weighted_scores += self.weights[k] * part_scores[k] - # add previous hyp scores - weighted_scores += running_hyps.score.to( - dtype=x.dtype, device=x.device - ).unsqueeze(1) - - # TODO(karita): do not use list. use batch instead - # see also https://github.com/espnet/espnet/pull/1402#discussion_r354561029 - # update hyps - best_hyps = [] - prev_hyps = self.unbatchfy(running_hyps) - for ( - full_prev_hyp_id, - full_new_token_id, - part_prev_hyp_id, - part_new_token_id, - ) in zip(*self.batch_beam(weighted_scores, part_ids)): - prev_hyp = prev_hyps[full_prev_hyp_id] - best_hyps.append( - Hypothesis( - score=weighted_scores[full_prev_hyp_id, full_new_token_id], - yseq=self.append_token(prev_hyp.yseq, full_new_token_id), - scores=self.merge_scores( - prev_hyp.scores, - {k: v[full_prev_hyp_id] for k, v in scores.items()}, - full_new_token_id, - {k: v[part_prev_hyp_id] for k, v in part_scores.items()}, - part_new_token_id, - ), - states=self.merge_states( - { - k: self.full_scorers[k].select_state(v, full_prev_hyp_id) - for k, v in states.items() - }, - { - k: self.part_scorers[k].select_state( - v, part_prev_hyp_id, part_new_token_id - ) - for k, v in part_states.items() - }, - part_new_token_id, - ), - ) - ) - return self.batchfy(best_hyps) - - def post_process( - self, - i: int, - maxlen: int, - maxlenratio: float, - running_hyps: BatchHypothesis, - ended_hyps: List[Hypothesis], - ) -> BatchHypothesis: - """Perform post-processing of beam search iterations. - - Args: - i (int): The length of hypothesis tokens. - maxlen (int): The maximum length of tokens in beam search. - maxlenratio (int): The maximum length ratio in beam search. - running_hyps (BatchHypothesis): The running hypotheses in beam search. - ended_hyps (List[Hypothesis]): The ended hypotheses in beam search. - - Returns: - BatchHypothesis: The new running hypotheses. - - """ - n_batch = running_hyps.yseq.shape[0] - logging.debug(f"the number of running hypothes: {n_batch}") - if self.token_list is not None: - logging.debug( - "best hypo: " - + "".join( - [ - self.token_list[x] - for x in running_hyps.yseq[0, 1 : running_hyps.length[0]] - ] - ) - ) - # add eos in the final loop to avoid that there are no ended hyps - if i == maxlen - 1: - logging.info("adding in the last position in the loop") - yseq_eos = torch.cat( - ( - running_hyps.yseq, - torch.full( - (n_batch, 1), - self.eos, - device=running_hyps.yseq.device, - dtype=torch.int64, - ), - ), - 1, - ) - running_hyps.yseq.resize_as_(yseq_eos) - running_hyps.yseq[:] = yseq_eos - running_hyps.length[:] = yseq_eos.shape[1] - - # add ended hypotheses to a final list, and removed them from current hypotheses - # (this will be a probmlem, number of hyps < beam) - is_eos = ( - running_hyps.yseq[torch.arange(n_batch), running_hyps.length - 1] - == self.eos - ) - for b in torch.nonzero(is_eos, as_tuple=False).view(-1): - hyp = self._select(running_hyps, b) - ended_hyps.append(hyp) - remained_ids = torch.nonzero(is_eos == 0, as_tuple=False).view(-1) - return self._batch_select(running_hyps, remained_ids) diff --git a/funasr/modules/beam_search/batch_beam_search_online_sim.py b/funasr/modules/beam_search/batch_beam_search_online_sim.py deleted file mode 100644 index 4d3debd23..000000000 --- a/funasr/modules/beam_search/batch_beam_search_online_sim.py +++ /dev/null @@ -1,270 +0,0 @@ -"""Parallel beam search module for online simulation.""" - -import logging -from pathlib import Path -from typing import List - -import yaml - -import torch - -from funasr.modules.beam_search.batch_beam_search import BatchBeamSearch -from funasr.modules.beam_search.beam_search import Hypothesis -from funasr.models.e2e_asr_common import end_detect - - -class BatchBeamSearchOnlineSim(BatchBeamSearch): - """Online beam search implementation. - - This simulates streaming decoding. - It requires encoded features of entire utterance and - extracts block by block from it as it shoud be done - in streaming processing. - This is based on Tsunoo et al, "STREAMING TRANSFORMER ASR - WITH BLOCKWISE SYNCHRONOUS BEAM SEARCH" - (https://arxiv.org/abs/2006.14941). - """ - - def set_streaming_config(self, asr_config: str): - """Set config file for streaming decoding. - - Args: - asr_config (str): The config file for asr training - - """ - train_config_file = Path(asr_config) - self.block_size = None - self.hop_size = None - self.look_ahead = None - config = None - with train_config_file.open("r", encoding="utf-8") as f: - args = yaml.safe_load(f) - if "encoder_conf" in args.keys(): - if "block_size" in args["encoder_conf"].keys(): - self.block_size = args["encoder_conf"]["block_size"] - if "hop_size" in args["encoder_conf"].keys(): - self.hop_size = args["encoder_conf"]["hop_size"] - if "look_ahead" in args["encoder_conf"].keys(): - self.look_ahead = args["encoder_conf"]["look_ahead"] - elif "config" in args.keys(): - config = args["config"] - if config is None: - logging.info( - "Cannot find config file for streaming decoding: " - + "apply batch beam search instead." - ) - return - if ( - self.block_size is None or self.hop_size is None or self.look_ahead is None - ) and config is not None: - config_file = Path(config) - with config_file.open("r", encoding="utf-8") as f: - args = yaml.safe_load(f) - if "encoder_conf" in args.keys(): - enc_args = args["encoder_conf"] - if enc_args and "block_size" in enc_args: - self.block_size = enc_args["block_size"] - if enc_args and "hop_size" in enc_args: - self.hop_size = enc_args["hop_size"] - if enc_args and "look_ahead" in enc_args: - self.look_ahead = enc_args["look_ahead"] - - def set_block_size(self, block_size: int): - """Set block size for streaming decoding. - - Args: - block_size (int): The block size of encoder - """ - self.block_size = block_size - - def set_hop_size(self, hop_size: int): - """Set hop size for streaming decoding. - - Args: - hop_size (int): The hop size of encoder - """ - self.hop_size = hop_size - - def set_look_ahead(self, look_ahead: int): - """Set look ahead size for streaming decoding. - - Args: - look_ahead (int): The look ahead size of encoder - """ - self.look_ahead = look_ahead - - def forward( - self, x: torch.Tensor, maxlenratio: float = 0.0, minlenratio: float = 0.0 - ) -> List[Hypothesis]: - """Perform beam search. - - Args: - x (torch.Tensor): Encoded speech feature (T, D) - maxlenratio (float): Input length ratio to obtain max output length. - If maxlenratio=0.0 (default), it uses a end-detect function - to automatically find maximum hypothesis lengths - minlenratio (float): Input length ratio to obtain min output length. - - Returns: - list[Hypothesis]: N-best decoding results - - """ - self.conservative = True # always true - - if self.block_size and self.hop_size and self.look_ahead: - cur_end_frame = int(self.block_size - self.look_ahead) - else: - cur_end_frame = x.shape[0] - process_idx = 0 - if cur_end_frame < x.shape[0]: - h = x.narrow(0, 0, cur_end_frame) - else: - h = x - - # set length bounds - if maxlenratio == 0: - maxlen = x.shape[0] - else: - maxlen = max(1, int(maxlenratio * x.size(0))) - minlen = int(minlenratio * x.size(0)) - logging.info("decoder input length: " + str(x.shape[0])) - logging.info("max output length: " + str(maxlen)) - logging.info("min output length: " + str(minlen)) - - # main loop of prefix search - running_hyps = self.init_hyp(h) - prev_hyps = [] - ended_hyps = [] - prev_repeat = False - - continue_decode = True - - while continue_decode: - move_to_next_block = False - if cur_end_frame < x.shape[0]: - h = x.narrow(0, 0, cur_end_frame) - else: - h = x - - # extend states for ctc - self.extend(h, running_hyps) - - while process_idx < maxlen: - logging.debug("position " + str(process_idx)) - best = self.search(running_hyps, h) - - if process_idx == maxlen - 1: - # end decoding - running_hyps = self.post_process( - process_idx, maxlen, maxlenratio, best, ended_hyps - ) - n_batch = best.yseq.shape[0] - local_ended_hyps = [] - is_local_eos = ( - best.yseq[torch.arange(n_batch), best.length - 1] == self.eos - ) - for i in range(is_local_eos.shape[0]): - if is_local_eos[i]: - hyp = self._select(best, i) - local_ended_hyps.append(hyp) - # NOTE(tsunoo): check repetitions here - # This is a implicit implementation of - # Eq (11) in https://arxiv.org/abs/2006.14941 - # A flag prev_repeat is used instead of using set - elif ( - not prev_repeat - and best.yseq[i, -1] in best.yseq[i, :-1] - and cur_end_frame < x.shape[0] - ): - move_to_next_block = True - prev_repeat = True - if maxlenratio == 0.0 and end_detect( - [lh.asdict() for lh in local_ended_hyps], process_idx - ): - logging.info(f"end detected at {process_idx}") - continue_decode = False - break - if len(local_ended_hyps) > 0 and cur_end_frame < x.shape[0]: - move_to_next_block = True - - if move_to_next_block: - if ( - self.hop_size - and cur_end_frame + int(self.hop_size) + int(self.look_ahead) - < x.shape[0] - ): - cur_end_frame += int(self.hop_size) - else: - cur_end_frame = x.shape[0] - logging.debug("Going to next block: %d", cur_end_frame) - if process_idx > 1 and len(prev_hyps) > 0 and self.conservative: - running_hyps = prev_hyps - process_idx -= 1 - prev_hyps = [] - break - - prev_repeat = False - prev_hyps = running_hyps - running_hyps = self.post_process( - process_idx, maxlen, maxlenratio, best, ended_hyps - ) - - if cur_end_frame >= x.shape[0]: - for hyp in local_ended_hyps: - ended_hyps.append(hyp) - - if len(running_hyps) == 0: - logging.info("no hypothesis. Finish decoding.") - continue_decode = False - break - else: - logging.debug(f"remained hypotheses: {len(running_hyps)}") - # increment number - process_idx += 1 - - nbest_hyps = sorted(ended_hyps, key=lambda x: x.score, reverse=True) - # check the number of hypotheses reaching to eos - if len(nbest_hyps) == 0: - logging.warning( - "there is no N-best results, perform recognition " - "again with smaller minlenratio." - ) - return ( - [] - if minlenratio < 0.1 - else self.forward(x, maxlenratio, max(0.0, minlenratio - 0.1)) - ) - - # report the best result - best = nbest_hyps[0] - for k, v in best.scores.items(): - logging.info( - f"{v:6.2f} * {self.weights[k]:3} = {v * self.weights[k]:6.2f} for {k}" - ) - logging.info(f"total log probability: {best.score:.2f}") - logging.info(f"normalized log probability: {best.score / len(best.yseq):.2f}") - logging.info(f"total number of ended hypotheses: {len(nbest_hyps)}") - if self.token_list is not None: - logging.info( - "best hypo: " - + "".join([self.token_list[x] for x in best.yseq[1:-1]]) - + "\n" - ) - return nbest_hyps - - def extend(self, x: torch.Tensor, hyps: Hypothesis) -> List[Hypothesis]: - """Extend probabilities and states with more encoded chunks. - - Args: - x (torch.Tensor): The extended encoder output feature - hyps (Hypothesis): Current list of hypothesis - - Returns: - Hypothesis: The extended hypothesis - - """ - for k, d in self.scorers.items(): - if hasattr(d, "extend_prob"): - d.extend_prob(x) - if hasattr(d, "extend_state"): - hyps.states[k] = d.extend_state(hyps.states[k]) diff --git a/funasr/modules/beam_search/beam_search.py b/funasr/modules/beam_search/beam_search.py deleted file mode 100644 index 51fa60100..000000000 --- a/funasr/modules/beam_search/beam_search.py +++ /dev/null @@ -1,1400 +0,0 @@ -"""Beam search module.""" - -from itertools import chain -import logging -from typing import Any -from typing import Dict -from typing import List -from typing import NamedTuple -from typing import Tuple -from typing import Union - -import torch - -from funasr.modules.e2e_asr_common import end_detect -from funasr.modules.scorers.scorer_interface import PartialScorerInterface -from funasr.modules.scorers.scorer_interface import ScorerInterface - - -class Hypothesis(NamedTuple): - """Hypothesis data type.""" - - yseq: torch.Tensor - score: Union[float, torch.Tensor] = 0 - scores: Dict[str, Union[float, torch.Tensor]] = 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 BeamSearch(torch.nn.Module): - """Beam search implementation.""" - - def __init__( - self, - scorers: Dict[str, ScorerInterface], - weights: Dict[str, float], - beam_size: int, - vocab_size: int, - sos: int, - eos: int, - token_list: List[str] = None, - pre_beam_ratio: float = 1.5, - pre_beam_score_key: str = None, - ): - """Initialize beam search. - - Args: - scorers (dict[str, ScorerInterface]): Dict of decoder modules - e.g., Decoder, CTCPrefixScorer, LM - The scorer will be ignored if it is `None` - weights (dict[str, float]): Dict of weights for each scorers - The scorer will be ignored if its weight is 0 - beam_size (int): The number of hypotheses kept during search - vocab_size (int): The number of vocabulary - sos (int): Start of sequence id - eos (int): End of sequence id - token_list (list[str]): List of tokens for debug log - pre_beam_score_key (str): key of scores to perform pre-beam search - pre_beam_ratio (float): beam size in the pre-beam search - will be `int(pre_beam_ratio * beam_size)` - - """ - super().__init__() - # set scorers - self.weights = weights - self.scorers = dict() - self.full_scorers = dict() - self.part_scorers = dict() - # this module dict is required for recursive cast - # `self.to(device, dtype)` in `recog.py` - self.nn_dict = torch.nn.ModuleDict() - for k, v in scorers.items(): - w = weights.get(k, 0) - if w == 0 or v is None: - continue - assert isinstance( - v, ScorerInterface - ), f"{k} ({type(v)}) does not implement ScorerInterface" - self.scorers[k] = v - if isinstance(v, PartialScorerInterface): - self.part_scorers[k] = v - else: - self.full_scorers[k] = v - if isinstance(v, torch.nn.Module): - self.nn_dict[k] = v - - # set configurations - self.sos = sos - self.eos = eos - self.token_list = token_list - self.pre_beam_size = int(pre_beam_ratio * beam_size) - self.beam_size = beam_size - self.n_vocab = vocab_size - if ( - pre_beam_score_key is not None - and pre_beam_score_key != "full" - and pre_beam_score_key not in self.full_scorers - ): - raise KeyError(f"{pre_beam_score_key} is not found in {self.full_scorers}") - self.pre_beam_score_key = pre_beam_score_key - self.do_pre_beam = ( - self.pre_beam_score_key is not None - and self.pre_beam_size < self.n_vocab - and len(self.part_scorers) > 0 - ) - - def init_hyp(self, x: torch.Tensor) -> List[Hypothesis]: - """Get an initial hypothesis data. - - Args: - x (torch.Tensor): The encoder output feature - - Returns: - Hypothesis: The initial hypothesis. - - """ - init_states = dict() - init_scores = dict() - for k, d in self.scorers.items(): - init_states[k] = d.init_state(x) - init_scores[k] = 0.0 - return [ - Hypothesis( - score=0.0, - scores=init_scores, - states=init_states, - yseq=torch.tensor([self.sos], device=x.device), - ) - ] - - @staticmethod - def append_token(xs: torch.Tensor, x: int) -> torch.Tensor: - """Append new token to prefix tokens. - - Args: - xs (torch.Tensor): The prefix token - x (int): The new token to append - - Returns: - torch.Tensor: New tensor contains: xs + [x] with xs.dtype and xs.device - - """ - x = torch.tensor([x], dtype=xs.dtype, device=xs.device) - return torch.cat((xs, x)) - - def score_full( - self, hyp: Hypothesis, x: torch.Tensor - ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: - """Score new hypothesis by `self.full_scorers`. - - Args: - hyp (Hypothesis): Hypothesis with prefix tokens to score - x (torch.Tensor): Corresponding input feature - - Returns: - Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of - score dict of `hyp` that has string keys of `self.full_scorers` - and tensor score values of shape: `(self.n_vocab,)`, - and state dict that has string keys - and state values of `self.full_scorers` - - """ - scores = dict() - states = dict() - for k, d in self.full_scorers.items(): - scores[k], states[k] = d.score(hyp.yseq, hyp.states[k], x) - return scores, states - - def score_partial( - self, hyp: Hypothesis, ids: torch.Tensor, x: torch.Tensor - ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: - """Score new hypothesis by `self.part_scorers`. - - Args: - hyp (Hypothesis): Hypothesis with prefix tokens to score - ids (torch.Tensor): 1D tensor of new partial tokens to score - x (torch.Tensor): Corresponding input feature - - Returns: - Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of - score dict of `hyp` that has string keys of `self.part_scorers` - and tensor score values of shape: `(len(ids),)`, - and state dict that has string keys - and state values of `self.part_scorers` - - """ - scores = dict() - states = dict() - for k, d in self.part_scorers.items(): - scores[k], states[k] = d.score_partial(hyp.yseq, ids, hyp.states[k], x) - return scores, states - - def beam( - self, weighted_scores: torch.Tensor, ids: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Compute topk full token ids and partial token ids. - - Args: - weighted_scores (torch.Tensor): The weighted sum scores for each tokens. - Its shape is `(self.n_vocab,)`. - ids (torch.Tensor): The partial token ids to compute topk - - Returns: - Tuple[torch.Tensor, torch.Tensor]: - The topk full token ids and partial token ids. - Their shapes are `(self.beam_size,)` - - """ - # no pre beam performed - if weighted_scores.size(0) == ids.size(0): - top_ids = weighted_scores.topk(self.beam_size)[1] - return top_ids, top_ids - - # mask pruned in pre-beam not to select in topk - tmp = weighted_scores[ids] - weighted_scores[:] = -float("inf") - weighted_scores[ids] = tmp - top_ids = weighted_scores.topk(self.beam_size)[1] - local_ids = weighted_scores[ids].topk(self.beam_size)[1] - return top_ids, local_ids - - @staticmethod - def merge_scores( - prev_scores: Dict[str, float], - next_full_scores: Dict[str, torch.Tensor], - full_idx: int, - next_part_scores: Dict[str, torch.Tensor], - part_idx: int, - ) -> Dict[str, torch.Tensor]: - """Merge scores for new hypothesis. - - Args: - prev_scores (Dict[str, float]): - The previous hypothesis scores by `self.scorers` - next_full_scores (Dict[str, torch.Tensor]): scores by `self.full_scorers` - full_idx (int): The next token id for `next_full_scores` - next_part_scores (Dict[str, torch.Tensor]): - scores of partial tokens by `self.part_scorers` - part_idx (int): The new token id for `next_part_scores` - - Returns: - Dict[str, torch.Tensor]: The new score dict. - Its keys are names of `self.full_scorers` and `self.part_scorers`. - Its values are scalar tensors by the scorers. - - """ - new_scores = dict() - for k, v in next_full_scores.items(): - new_scores[k] = prev_scores[k] + v[full_idx] - for k, v in next_part_scores.items(): - new_scores[k] = prev_scores[k] + v[part_idx] - return new_scores - - def merge_states(self, states: Any, part_states: Any, part_idx: int) -> Any: - """Merge states for new hypothesis. - - Args: - states: states of `self.full_scorers` - part_states: states of `self.part_scorers` - part_idx (int): The new token id for `part_scores` - - Returns: - Dict[str, torch.Tensor]: The new score dict. - Its keys are names of `self.full_scorers` and `self.part_scorers`. - Its values are states of the scorers. - - """ - new_states = dict() - for k, v in states.items(): - new_states[k] = v - for k, d in self.part_scorers.items(): - new_states[k] = d.select_state(part_states[k], part_idx) - return new_states - - def search( - self, running_hyps: List[Hypothesis], x: torch.Tensor - ) -> List[Hypothesis]: - """Search new tokens for running hypotheses and encoded speech x. - - Args: - running_hyps (List[Hypothesis]): Running hypotheses on beam - x (torch.Tensor): Encoded speech feature (T, D) - - Returns: - List[Hypotheses]: Best sorted hypotheses - - """ - best_hyps = [] - part_ids = torch.arange(self.n_vocab, device=x.device) # no pre-beam - for hyp in running_hyps: - # scoring - weighted_scores = torch.zeros(self.n_vocab, dtype=x.dtype, device=x.device) - scores, states = self.score_full(hyp, x) - for k in self.full_scorers: - weighted_scores += self.weights[k] * scores[k] - # partial scoring - if self.do_pre_beam: - pre_beam_scores = ( - weighted_scores - if self.pre_beam_score_key == "full" - else scores[self.pre_beam_score_key] - ) - part_ids = torch.topk(pre_beam_scores, self.pre_beam_size)[1] - part_scores, part_states = self.score_partial(hyp, part_ids, x) - for k in self.part_scorers: - weighted_scores[part_ids] += self.weights[k] * part_scores[k] - # add previous hyp score - weighted_scores += hyp.score - - # update hyps - for j, part_j in zip(*self.beam(weighted_scores, part_ids)): - # will be (2 x beam at most) - best_hyps.append( - Hypothesis( - score=weighted_scores[j], - yseq=self.append_token(hyp.yseq, j), - scores=self.merge_scores( - hyp.scores, scores, j, part_scores, part_j - ), - states=self.merge_states(states, part_states, part_j), - ) - ) - - # sort and prune 2 x beam -> beam - best_hyps = sorted(best_hyps, key=lambda x: x.score, reverse=True)[ - : min(len(best_hyps), self.beam_size) - ] - return best_hyps - - def forward( - self, x: torch.Tensor, maxlenratio: float = 0.0, minlenratio: float = 0.0 - ) -> List[Hypothesis]: - """Perform beam search. - - Args: - x (torch.Tensor): Encoded speech feature (T, D) - maxlenratio (float): Input length ratio to obtain max output length. - If maxlenratio=0.0 (default), it uses a end-detect function - to automatically find maximum hypothesis lengths - If maxlenratio<0.0, its absolute value is interpreted - as a constant max output length. - minlenratio (float): Input length ratio to obtain min output length. - - Returns: - list[Hypothesis]: N-best decoding results - - """ - # set length bounds - if maxlenratio == 0: - maxlen = x.shape[0] - elif maxlenratio < 0: - maxlen = -1 * int(maxlenratio) - else: - maxlen = max(1, int(maxlenratio * x.size(0))) - minlen = int(minlenratio * x.size(0)) - logging.info("decoder input length: " + str(x.shape[0])) - logging.info("max output length: " + str(maxlen)) - logging.info("min output length: " + str(minlen)) - - # main loop of prefix search - running_hyps = self.init_hyp(x) - ended_hyps = [] - for i in range(maxlen): - logging.debug("position " + str(i)) - best = self.search(running_hyps, x) - # post process of one iteration - running_hyps = self.post_process(i, maxlen, maxlenratio, best, ended_hyps) - # end detection - if maxlenratio == 0.0 and end_detect([h.asdict() for h in ended_hyps], i): - logging.info(f"end detected at {i}") - break - if len(running_hyps) == 0: - logging.info("no hypothesis. Finish decoding.") - break - else: - logging.debug(f"remained hypotheses: {len(running_hyps)}") - - nbest_hyps = sorted(ended_hyps, key=lambda x: x.score, reverse=True) - # check the number of hypotheses reaching to eos - if len(nbest_hyps) == 0: - logging.warning( - "there is no N-best results, perform recognition " - "again with smaller minlenratio." - ) - return ( - [] - if minlenratio < 0.1 - else self.forward(x, maxlenratio, max(0.0, minlenratio - 0.1)) - ) - - # report the best result - best = nbest_hyps[0] - for k, v in best.scores.items(): - logging.info( - f"{v:6.2f} * {self.weights[k]:3} = {v * self.weights[k]:6.2f} for {k}" - ) - logging.info(f"total log probability: {best.score:.2f}") - logging.info(f"normalized log probability: {best.score / len(best.yseq):.2f}") - logging.info(f"total number of ended hypotheses: {len(nbest_hyps)}") - if self.token_list is not None: - logging.info( - "best hypo: " - + "".join([self.token_list[x] for x in best.yseq[1:-1]]) - + "\n" - ) - return nbest_hyps - - def post_process( - self, - i: int, - maxlen: int, - maxlenratio: float, - running_hyps: List[Hypothesis], - ended_hyps: List[Hypothesis], - ) -> List[Hypothesis]: - """Perform post-processing of beam search iterations. - - Args: - i (int): The length of hypothesis tokens. - maxlen (int): The maximum length of tokens in beam search. - maxlenratio (int): The maximum length ratio in beam search. - running_hyps (List[Hypothesis]): The running hypotheses in beam search. - ended_hyps (List[Hypothesis]): The ended hypotheses in beam search. - - Returns: - List[Hypothesis]: The new running hypotheses. - - """ - logging.debug(f"the number of running hypotheses: {len(running_hyps)}") - if self.token_list is not None: - logging.debug( - "best hypo: " - + "".join([self.token_list[x] for x in running_hyps[0].yseq[1:]]) - ) - # add eos in the final loop to avoid that there are no ended hyps - if i == maxlen - 1: - logging.info("adding in the last position in the loop") - running_hyps = [ - h._replace(yseq=self.append_token(h.yseq, self.eos)) - for h in running_hyps - ] - - # add ended hypotheses to a final list, and removed them from current hypotheses - # (this will be a problem, number of hyps < beam) - remained_hyps = [] - for hyp in running_hyps: - if hyp.yseq[-1] == self.eos: - # e.g., Word LM needs to add final score - for k, d in chain(self.full_scorers.items(), self.part_scorers.items()): - s = d.final_score(hyp.states[k]) - hyp.scores[k] += s - hyp = hyp._replace(score=hyp.score + self.weights[k] * s) - ended_hyps.append(hyp) - else: - remained_hyps.append(hyp) - return remained_hyps - - -def beam_search( - x: torch.Tensor, - sos: int, - eos: int, - beam_size: int, - vocab_size: int, - scorers: Dict[str, ScorerInterface], - weights: Dict[str, float], - token_list: List[str] = None, - maxlenratio: float = 0.0, - minlenratio: float = 0.0, - pre_beam_ratio: float = 1.5, - pre_beam_score_key: str = "full", -) -> list: - """Perform beam search with scorers. - - Args: - x (torch.Tensor): Encoded speech feature (T, D) - sos (int): Start of sequence id - eos (int): End of sequence id - beam_size (int): The number of hypotheses kept during search - vocab_size (int): The number of vocabulary - scorers (dict[str, ScorerInterface]): Dict of decoder modules - e.g., Decoder, CTCPrefixScorer, LM - The scorer will be ignored if it is `None` - weights (dict[str, float]): Dict of weights for each scorers - The scorer will be ignored if its weight is 0 - token_list (list[str]): List of tokens for debug log - maxlenratio (float): Input length ratio to obtain max output length. - If maxlenratio=0.0 (default), it uses a end-detect function - to automatically find maximum hypothesis lengths - minlenratio (float): Input length ratio to obtain min output length. - pre_beam_score_key (str): key of scores to perform pre-beam search - pre_beam_ratio (float): beam size in the pre-beam search - will be `int(pre_beam_ratio * beam_size)` - - Returns: - list: N-best decoding results - - """ - ret = BeamSearch( - scorers, - weights, - beam_size=beam_size, - vocab_size=vocab_size, - pre_beam_ratio=pre_beam_ratio, - pre_beam_score_key=pre_beam_score_key, - sos=sos, - eos=eos, - token_list=token_list, - ).forward(x=x, maxlenratio=maxlenratio, minlenratio=minlenratio) - return [h.asdict() for h in ret] - -class BeamSearchScama(torch.nn.Module): - """Beam search implementation.""" - - def __init__( - self, - scorers: Dict[str, ScorerInterface], - weights: Dict[str, float], - beam_size: int, - vocab_size: int, - sos: int, - eos: int, - token_list: List[str] = None, - pre_beam_ratio: float = 1.5, - pre_beam_score_key: str = None, - ): - """Initialize beam search. - - Args: - scorers (dict[str, ScorerInterface]): Dict of decoder modules - e.g., Decoder, CTCPrefixScorer, LM - The scorer will be ignored if it is `None` - weights (dict[str, float]): Dict of weights for each scorers - The scorer will be ignored if its weight is 0 - beam_size (int): The number of hypotheses kept during search - vocab_size (int): The number of vocabulary - sos (int): Start of sequence id - eos (int): End of sequence id - token_list (list[str]): List of tokens for debug log - pre_beam_score_key (str): key of scores to perform pre-beam search - pre_beam_ratio (float): beam size in the pre-beam search - will be `int(pre_beam_ratio * beam_size)` - - """ - super().__init__() - # set scorers - self.weights = weights - self.scorers = dict() - self.full_scorers = dict() - self.part_scorers = dict() - # this module dict is required for recursive cast - # `self.to(device, dtype)` in `recog.py` - self.nn_dict = torch.nn.ModuleDict() - for k, v in scorers.items(): - w = weights.get(k, 0) - if w == 0 or v is None: - continue - assert isinstance( - v, ScorerInterface - ), f"{k} ({type(v)}) does not implement ScorerInterface" - self.scorers[k] = v - if isinstance(v, PartialScorerInterface): - self.part_scorers[k] = v - else: - self.full_scorers[k] = v - if isinstance(v, torch.nn.Module): - self.nn_dict[k] = v - - # set configurations - self.sos = sos - self.eos = eos - self.token_list = token_list - self.pre_beam_size = int(pre_beam_ratio * beam_size) - self.beam_size = beam_size - self.n_vocab = vocab_size - if ( - pre_beam_score_key is not None - and pre_beam_score_key != "full" - and pre_beam_score_key not in self.full_scorers - ): - raise KeyError(f"{pre_beam_score_key} is not found in {self.full_scorers}") - self.pre_beam_score_key = pre_beam_score_key - self.do_pre_beam = ( - self.pre_beam_score_key is not None - and self.pre_beam_size < self.n_vocab - and len(self.part_scorers) > 0 - ) - - def init_hyp(self, x: torch.Tensor) -> List[Hypothesis]: - """Get an initial hypothesis data. - - Args: - x (torch.Tensor): The encoder output feature - - Returns: - Hypothesis: The initial hypothesis. - - """ - init_states = dict() - init_scores = dict() - for k, d in self.scorers.items(): - init_states[k] = d.init_state(x) - init_scores[k] = 0.0 - return [ - Hypothesis( - score=0.0, - scores=init_scores, - states=init_states, - yseq=torch.tensor([self.sos], device=x.device), - ) - ] - - @staticmethod - def append_token(xs: torch.Tensor, x: int) -> torch.Tensor: - """Append new token to prefix tokens. - - Args: - xs (torch.Tensor): The prefix token - x (int): The new token to append - - Returns: - torch.Tensor: New tensor contains: xs + [x] with xs.dtype and xs.device - - """ - x = torch.tensor([x], dtype=xs.dtype, device=xs.device) - return torch.cat((xs, x)) - - def score_full( - self, hyp: Hypothesis, - x: torch.Tensor, - x_mask: torch.Tensor = None, - pre_acoustic_embeds: torch.Tensor = None, - ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: - """Score new hypothesis by `self.full_scorers`. - - Args: - hyp (Hypothesis): Hypothesis with prefix tokens to score - x (torch.Tensor): Corresponding input feature - - Returns: - Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of - score dict of `hyp` that has string keys of `self.full_scorers` - and tensor score values of shape: `(self.n_vocab,)`, - and state dict that has string keys - and state values of `self.full_scorers` - - """ - scores = dict() - states = dict() - for k, d in self.full_scorers.items(): - scores[k], states[k] = d.score(hyp.yseq, hyp.states[k], x, x_mask=x_mask, pre_acoustic_embeds=pre_acoustic_embeds) - return scores, states - - def score_partial( - self, hyp: Hypothesis, ids: torch.Tensor, x: torch.Tensor - ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: - """Score new hypothesis by `self.part_scorers`. - - Args: - hyp (Hypothesis): Hypothesis with prefix tokens to score - ids (torch.Tensor): 1D tensor of new partial tokens to score - x (torch.Tensor): Corresponding input feature - - Returns: - Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of - score dict of `hyp` that has string keys of `self.part_scorers` - and tensor score values of shape: `(len(ids),)`, - and state dict that has string keys - and state values of `self.part_scorers` - - """ - scores = dict() - states = dict() - for k, d in self.part_scorers.items(): - scores[k], states[k] = d.score_partial(hyp.yseq, ids, hyp.states[k], x) - return scores, states - - def beam( - self, weighted_scores: torch.Tensor, ids: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Compute topk full token ids and partial token ids. - - Args: - weighted_scores (torch.Tensor): The weighted sum scores for each tokens. - Its shape is `(self.n_vocab,)`. - ids (torch.Tensor): The partial token ids to compute topk - - Returns: - Tuple[torch.Tensor, torch.Tensor]: - The topk full token ids and partial token ids. - Their shapes are `(self.beam_size,)` - - """ - # no pre beam performed - if weighted_scores.size(0) == ids.size(0): - top_ids = weighted_scores.topk(self.beam_size)[1] - return top_ids, top_ids - - # mask pruned in pre-beam not to select in topk - tmp = weighted_scores[ids] - weighted_scores[:] = -float("inf") - weighted_scores[ids] = tmp - top_ids = weighted_scores.topk(self.beam_size)[1] - local_ids = weighted_scores[ids].topk(self.beam_size)[1] - return top_ids, local_ids - - @staticmethod - def merge_scores( - prev_scores: Dict[str, float], - next_full_scores: Dict[str, torch.Tensor], - full_idx: int, - next_part_scores: Dict[str, torch.Tensor], - part_idx: int, - ) -> Dict[str, torch.Tensor]: - """Merge scores for new hypothesis. - - Args: - prev_scores (Dict[str, float]): - The previous hypothesis scores by `self.scorers` - next_full_scores (Dict[str, torch.Tensor]): scores by `self.full_scorers` - full_idx (int): The next token id for `next_full_scores` - next_part_scores (Dict[str, torch.Tensor]): - scores of partial tokens by `self.part_scorers` - part_idx (int): The new token id for `next_part_scores` - - Returns: - Dict[str, torch.Tensor]: The new score dict. - Its keys are names of `self.full_scorers` and `self.part_scorers`. - Its values are scalar tensors by the scorers. - - """ - new_scores = dict() - for k, v in next_full_scores.items(): - new_scores[k] = prev_scores[k] + v[full_idx] - for k, v in next_part_scores.items(): - new_scores[k] = prev_scores[k] + v[part_idx] - return new_scores - - def merge_states(self, states: Any, part_states: Any, part_idx: int) -> Any: - """Merge states for new hypothesis. - - Args: - states: states of `self.full_scorers` - part_states: states of `self.part_scorers` - part_idx (int): The new token id for `part_scores` - - Returns: - Dict[str, torch.Tensor]: The new score dict. - Its keys are names of `self.full_scorers` and `self.part_scorers`. - Its values are states of the scorers. - - """ - new_states = dict() - for k, v in states.items(): - new_states[k] = v - for k, d in self.part_scorers.items(): - new_states[k] = d.select_state(part_states[k], part_idx) - return new_states - - def search( - self, running_hyps: List[Hypothesis], - x: torch.Tensor, - x_mask: torch.Tensor = None, - pre_acoustic_embeds: torch.Tensor = None, - ) -> List[Hypothesis]: - """Search new tokens for running hypotheses and encoded speech x. - - Args: - running_hyps (List[Hypothesis]): Running hypotheses on beam - x (torch.Tensor): Encoded speech feature (T, D) - - Returns: - List[Hypotheses]: Best sorted hypotheses - - """ - best_hyps = [] - part_ids = torch.arange(self.n_vocab, device=x.device) # no pre-beam - for hyp in running_hyps: - # scoring - weighted_scores = torch.zeros(self.n_vocab, dtype=x.dtype, device=x.device) - scores, states = self.score_full(hyp, x, x_mask=x_mask, pre_acoustic_embeds=pre_acoustic_embeds) - for k in self.full_scorers: - weighted_scores += self.weights[k] * scores[k] - # partial scoring - if self.do_pre_beam: - pre_beam_scores = ( - weighted_scores - if self.pre_beam_score_key == "full" - else scores[self.pre_beam_score_key] - ) - part_ids = torch.topk(pre_beam_scores, self.pre_beam_size)[1] - part_scores, part_states = self.score_partial(hyp, part_ids, x) - for k in self.part_scorers: - weighted_scores[part_ids] += self.weights[k] * part_scores[k] - # add previous hyp score - weighted_scores += hyp.score - - # update hyps - for j, part_j in zip(*self.beam(weighted_scores, part_ids)): - # will be (2 x beam at most) - best_hyps.append( - Hypothesis( - score=weighted_scores[j], - yseq=self.append_token(hyp.yseq, j), - scores=self.merge_scores( - hyp.scores, scores, j, part_scores, part_j - ), - states=self.merge_states(states, part_states, part_j), - ) - ) - - # sort and prune 2 x beam -> beam - best_hyps = sorted(best_hyps, key=lambda x: x.score, reverse=True)[ - : min(len(best_hyps), self.beam_size) - ] - return best_hyps - - def forward( - self, x: torch.Tensor, - scama_mask: torch.Tensor = None, - pre_acoustic_embeds: torch.Tensor = None, - maxlenratio: float = 0.0, - minlenratio: float = 0.0, - maxlen: int = None, - minlen: int = 0, - ) -> List[Hypothesis]: - """Perform beam search. - - Args: - x (torch.Tensor): Encoded speech feature (T, D) - maxlenratio (float): Input length ratio to obtain max output length. - If maxlenratio=0.0 (default), it uses a end-detect function - to automatically find maximum hypothesis lengths - If maxlenratio<0.0, its absolute value is interpreted - as a constant max output length. - minlenratio (float): Input length ratio to obtain min output length. - - Returns: - list[Hypothesis]: N-best decoding results - - """ - if maxlen is None: - # set length bounds - if maxlenratio == 0: - maxlen = x.shape[0] - elif maxlenratio < 0: - maxlen = -1 * int(maxlenratio) - else: - maxlen = max(1, int(maxlenratio * x.size(0))) - minlen = int(minlenratio * x.size(0)) - - logging.info("decoder input length: " + str(x.shape[0])) - logging.info("max output length: " + str(maxlen)) - logging.info("min output length: " + str(minlen)) - - # main loop of prefix search - running_hyps = self.init_hyp(x) - ended_hyps = [] - for i in range(maxlen): - logging.debug("position " + str(i)) - mask_enc = None - if scama_mask is not None: - token_num_predictor = scama_mask.size(1) - token_id_slice = min(i, token_num_predictor-1) - mask_enc = scama_mask[:, token_id_slice:token_id_slice+1, :] - # if mask_enc.size(1) == 0: - # mask_enc = scama_mask[:, -2:-1, :] - # # mask_enc = torch.zeros_like(mask_enc) - pre_acoustic_embeds_cur = None - if pre_acoustic_embeds is not None: - b, t, d = pre_acoustic_embeds.size() - pad = torch.zeros((b, 1, d), dtype=pre_acoustic_embeds.dtype).to(device=pre_acoustic_embeds.device) - pre_acoustic_embeds = torch.cat((pre_acoustic_embeds, pad), dim=1) - token_id_slice = min(i, t) - pre_acoustic_embeds_cur = pre_acoustic_embeds[:, token_id_slice:token_id_slice+1, :] - - best = self.search(running_hyps, x, x_mask=mask_enc, pre_acoustic_embeds=pre_acoustic_embeds_cur) - # post process of one iteration - running_hyps = self.post_process(i, maxlen, maxlenratio, best, ended_hyps) - # end detection - if maxlenratio == 0.0 and end_detect([h.asdict() for h in ended_hyps], i): - logging.info(f"end detected at {i}") - break - if len(running_hyps) == 0: - logging.info("no hypothesis. Finish decoding.") - break - else: - logging.debug(f"remained hypotheses: {len(running_hyps)}") - - nbest_hyps = sorted(ended_hyps, key=lambda x: x.score, reverse=True) - # check the number of hypotheses reaching to eos - if len(nbest_hyps) == 0: - logging.warning( - "there is no N-best results, perform recognition " - "again with smaller minlenratio." - ) - return ( - [] - if minlenratio < 0.1 - else self.forward(x, maxlenratio, max(0.0, minlenratio - 0.1)) - ) - - # report the best result - for x in nbest_hyps: - yseq = "".join([self.token_list[x] for x in x.yseq]) - logging.debug("nbest: y: {}, yseq: {}, score: {}".format(x.yseq, yseq, x.score)) - best = nbest_hyps[0] - for k, v in best.scores.items(): - logging.info( - f"{v:6.2f} * {self.weights[k]:3} = {v * self.weights[k]:6.2f} for {k}" - ) - logging.info(f"total log probability: {best.score:.2f}") - logging.info(f"normalized log probability: {best.score / len(best.yseq):.2f}") - logging.info(f"total number of ended hypotheses: {len(nbest_hyps)}") - if self.token_list is not None: - logging.info( - "best hypo: " - + "".join([self.token_list[x] for x in best.yseq[1:-1]]) - + "\n" - ) - return nbest_hyps - - def post_process( - self, - i: int, - maxlen: int, - maxlenratio: float, - running_hyps: List[Hypothesis], - ended_hyps: List[Hypothesis], - ) -> List[Hypothesis]: - """Perform post-processing of beam search iterations. - - Args: - i (int): The length of hypothesis tokens. - maxlen (int): The maximum length of tokens in beam search. - maxlenratio (int): The maximum length ratio in beam search. - running_hyps (List[Hypothesis]): The running hypotheses in beam search. - ended_hyps (List[Hypothesis]): The ended hypotheses in beam search. - - Returns: - List[Hypothesis]: The new running hypotheses. - - """ - logging.debug(f"the number of running hypotheses: {len(running_hyps)}") - if self.token_list is not None: - logging.debug( - "best hypo: " - + "".join([self.token_list[x] for x in running_hyps[0].yseq[1:]]) - ) - # add eos in the final loop to avoid that there are no ended hyps - if i == maxlen - 1: - logging.info("adding in the last position in the loop") - running_hyps = [ - h._replace(yseq=self.append_token(h.yseq, self.eos)) - for h in running_hyps - ] - - # add ended hypotheses to a final list, and removed them from current hypotheses - # (this will be a problem, number of hyps < beam) - remained_hyps = [] - for hyp in running_hyps: - if hyp.yseq[-1] == self.eos: - # e.g., Word LM needs to add final score - for k, d in chain(self.full_scorers.items(), self.part_scorers.items()): - s = d.final_score(hyp.states[k]) - hyp.scores[k] += s - hyp = hyp._replace(score=hyp.score + self.weights[k] * s) - ended_hyps.append(hyp) - else: - remained_hyps.append(hyp) - return remained_hyps - -class BeamSearchPara(torch.nn.Module): - """Beam search implementation.""" - - def __init__( - self, - scorers: Dict[str, ScorerInterface], - weights: Dict[str, float], - beam_size: int, - vocab_size: int, - sos: int, - eos: int, - token_list: List[str] = None, - pre_beam_ratio: float = 1.5, - pre_beam_score_key: str = None, - ): - """Initialize beam search. - - Args: - scorers (dict[str, ScorerInterface]): Dict of decoder modules - e.g., Decoder, CTCPrefixScorer, LM - The scorer will be ignored if it is `None` - weights (dict[str, float]): Dict of weights for each scorers - The scorer will be ignored if its weight is 0 - beam_size (int): The number of hypotheses kept during search - vocab_size (int): The number of vocabulary - sos (int): Start of sequence id - eos (int): End of sequence id - token_list (list[str]): List of tokens for debug log - pre_beam_score_key (str): key of scores to perform pre-beam search - pre_beam_ratio (float): beam size in the pre-beam search - will be `int(pre_beam_ratio * beam_size)` - - """ - super().__init__() - # set scorers - self.weights = weights - self.scorers = dict() - self.full_scorers = dict() - self.part_scorers = dict() - # this module dict is required for recursive cast - # `self.to(device, dtype)` in `recog.py` - self.nn_dict = torch.nn.ModuleDict() - for k, v in scorers.items(): - w = weights.get(k, 0) - if w == 0 or v is None: - continue - assert isinstance( - v, ScorerInterface - ), f"{k} ({type(v)}) does not implement ScorerInterface" - self.scorers[k] = v - if isinstance(v, PartialScorerInterface): - self.part_scorers[k] = v - else: - self.full_scorers[k] = v - if isinstance(v, torch.nn.Module): - self.nn_dict[k] = v - - # set configurations - self.sos = sos - self.eos = eos - self.token_list = token_list - self.pre_beam_size = int(pre_beam_ratio * beam_size) - self.beam_size = beam_size - self.n_vocab = vocab_size - if ( - pre_beam_score_key is not None - and pre_beam_score_key != "full" - and pre_beam_score_key not in self.full_scorers - ): - raise KeyError(f"{pre_beam_score_key} is not found in {self.full_scorers}") - self.pre_beam_score_key = pre_beam_score_key - self.do_pre_beam = ( - self.pre_beam_score_key is not None - and self.pre_beam_size < self.n_vocab - and len(self.part_scorers) > 0 - ) - - def init_hyp(self, x: torch.Tensor) -> List[Hypothesis]: - """Get an initial hypothesis data. - - Args: - x (torch.Tensor): The encoder output feature - - Returns: - Hypothesis: The initial hypothesis. - - """ - init_states = dict() - init_scores = dict() - for k, d in self.scorers.items(): - init_states[k] = d.init_state(x) - init_scores[k] = 0.0 - return [ - Hypothesis( - score=0.0, - scores=init_scores, - states=init_states, - yseq=torch.tensor([self.sos], device=x.device), - ) - ] - - @staticmethod - def append_token(xs: torch.Tensor, x: int) -> torch.Tensor: - """Append new token to prefix tokens. - - Args: - xs (torch.Tensor): The prefix token - x (int): The new token to append - - Returns: - torch.Tensor: New tensor contains: xs + [x] with xs.dtype and xs.device - - """ - x = torch.tensor([x], dtype=xs.dtype, device=xs.device) - return torch.cat((xs, x)) - - def score_full( - self, hyp: Hypothesis, x: torch.Tensor - ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: - """Score new hypothesis by `self.full_scorers`. - - Args: - hyp (Hypothesis): Hypothesis with prefix tokens to score - x (torch.Tensor): Corresponding input feature - - Returns: - Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of - score dict of `hyp` that has string keys of `self.full_scorers` - and tensor score values of shape: `(self.n_vocab,)`, - and state dict that has string keys - and state values of `self.full_scorers` - - """ - scores = dict() - states = dict() - for k, d in self.full_scorers.items(): - scores[k], states[k] = d.score(hyp.yseq, hyp.states[k], x) - return scores, states - - def score_partial( - self, hyp: Hypothesis, ids: torch.Tensor, x: torch.Tensor - ) -> Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: - """Score new hypothesis by `self.part_scorers`. - - Args: - hyp (Hypothesis): Hypothesis with prefix tokens to score - ids (torch.Tensor): 1D tensor of new partial tokens to score - x (torch.Tensor): Corresponding input feature - - Returns: - Tuple[Dict[str, torch.Tensor], Dict[str, Any]]: Tuple of - score dict of `hyp` that has string keys of `self.part_scorers` - and tensor score values of shape: `(len(ids),)`, - and state dict that has string keys - and state values of `self.part_scorers` - - """ - scores = dict() - states = dict() - for k, d in self.part_scorers.items(): - scores[k], states[k] = d.score_partial(hyp.yseq, ids, hyp.states[k], x) - return scores, states - - def beam( - self, weighted_scores: torch.Tensor, ids: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Compute topk full token ids and partial token ids. - - Args: - weighted_scores (torch.Tensor): The weighted sum scores for each tokens. - Its shape is `(self.n_vocab,)`. - ids (torch.Tensor): The partial token ids to compute topk - - Returns: - Tuple[torch.Tensor, torch.Tensor]: - The topk full token ids and partial token ids. - Their shapes are `(self.beam_size,)` - - """ - # no pre beam performed - if weighted_scores.size(0) == ids.size(0): - top_ids = weighted_scores.topk(self.beam_size)[1] - return top_ids, top_ids - - # mask pruned in pre-beam not to select in topk - tmp = weighted_scores[ids] - weighted_scores[:] = -float("inf") - weighted_scores[ids] = tmp - top_ids = weighted_scores.topk(self.beam_size)[1] - local_ids = weighted_scores[ids].topk(self.beam_size)[1] - return top_ids, local_ids - - @staticmethod - def merge_scores( - prev_scores: Dict[str, float], - next_full_scores: Dict[str, torch.Tensor], - full_idx: int, - next_part_scores: Dict[str, torch.Tensor], - part_idx: int, - ) -> Dict[str, torch.Tensor]: - """Merge scores for new hypothesis. - - Args: - prev_scores (Dict[str, float]): - The previous hypothesis scores by `self.scorers` - next_full_scores (Dict[str, torch.Tensor]): scores by `self.full_scorers` - full_idx (int): The next token id for `next_full_scores` - next_part_scores (Dict[str, torch.Tensor]): - scores of partial tokens by `self.part_scorers` - part_idx (int): The new token id for `next_part_scores` - - Returns: - Dict[str, torch.Tensor]: The new score dict. - Its keys are names of `self.full_scorers` and `self.part_scorers`. - Its values are scalar tensors by the scorers. - - """ - new_scores = dict() - for k, v in next_full_scores.items(): - new_scores[k] = prev_scores[k] + v[full_idx] - for k, v in next_part_scores.items(): - new_scores[k] = prev_scores[k] + v[part_idx] - return new_scores - - def merge_states(self, states: Any, part_states: Any, part_idx: int) -> Any: - """Merge states for new hypothesis. - - Args: - states: states of `self.full_scorers` - part_states: states of `self.part_scorers` - part_idx (int): The new token id for `part_scores` - - Returns: - Dict[str, torch.Tensor]: The new score dict. - Its keys are names of `self.full_scorers` and `self.part_scorers`. - Its values are states of the scorers. - - """ - new_states = dict() - for k, v in states.items(): - new_states[k] = v - for k, d in self.part_scorers.items(): - new_states[k] = d.select_state(part_states[k], part_idx) - return new_states - - def search( - self, running_hyps: List[Hypothesis], x: torch.Tensor, am_score: torch.Tensor - ) -> List[Hypothesis]: - """Search new tokens for running hypotheses and encoded speech x. - - Args: - running_hyps (List[Hypothesis]): Running hypotheses on beam - x (torch.Tensor): Encoded speech feature (T, D) - - Returns: - List[Hypotheses]: Best sorted hypotheses - - """ - best_hyps = [] - part_ids = torch.arange(self.n_vocab, device=x.device) # no pre-beam - for hyp in running_hyps: - # scoring - weighted_scores = torch.zeros(self.n_vocab, dtype=x.dtype, device=x.device) - weighted_scores += am_score - scores, states = self.score_full(hyp, x) - for k in self.full_scorers: - weighted_scores += self.weights[k] * scores[k] - # partial scoring - if self.do_pre_beam: - pre_beam_scores = ( - weighted_scores - if self.pre_beam_score_key == "full" - else scores[self.pre_beam_score_key] - ) - part_ids = torch.topk(pre_beam_scores, self.pre_beam_size)[1] - part_scores, part_states = self.score_partial(hyp, part_ids, x) - for k in self.part_scorers: - weighted_scores[part_ids] += self.weights[k] * part_scores[k] - # add previous hyp score - weighted_scores += hyp.score - - # update hyps - for j, part_j in zip(*self.beam(weighted_scores, part_ids)): - # will be (2 x beam at most) - best_hyps.append( - Hypothesis( - score=weighted_scores[j], - yseq=self.append_token(hyp.yseq, j), - scores=self.merge_scores( - hyp.scores, scores, j, part_scores, part_j - ), - states=self.merge_states(states, part_states, part_j), - ) - ) - - # sort and prune 2 x beam -> beam - best_hyps = sorted(best_hyps, key=lambda x: x.score, reverse=True)[ - : min(len(best_hyps), self.beam_size) - ] - return best_hyps - - def forward( - self, x: torch.Tensor, am_scores: torch.Tensor, maxlenratio: float = 0.0, minlenratio: float = 0.0 - ) -> List[Hypothesis]: - """Perform beam search. - - Args: - x (torch.Tensor): Encoded speech feature (T, D) - maxlenratio (float): Input length ratio to obtain max output length. - If maxlenratio=0.0 (default), it uses a end-detect function - to automatically find maximum hypothesis lengths - If maxlenratio<0.0, its absolute value is interpreted - as a constant max output length. - minlenratio (float): Input length ratio to obtain min output length. - - Returns: - list[Hypothesis]: N-best decoding results - - """ - # set length bounds - maxlen = am_scores.shape[0] - logging.info("decoder input length: " + str(x.shape[0])) - logging.info("max output length: " + str(maxlen)) - - # main loop of prefix search - running_hyps = self.init_hyp(x) - ended_hyps = [] - for i in range(maxlen): - logging.debug("position " + str(i)) - best = self.search(running_hyps, x, am_scores[i]) - # post process of one iteration - running_hyps = self.post_process(i, maxlen, maxlenratio, best, ended_hyps) - # end detection - if maxlenratio == 0.0 and end_detect([h.asdict() for h in ended_hyps], i): - logging.info(f"end detected at {i}") - break - if len(running_hyps) == 0: - logging.info("no hypothesis. Finish decoding.") - break - else: - logging.debug(f"remained hypotheses: {len(running_hyps)}") - - nbest_hyps = sorted(ended_hyps, key=lambda x: x.score, reverse=True) - # check the number of hypotheses reaching to eos - if len(nbest_hyps) == 0: - logging.warning( - "there is no N-best results, perform recognition " - "again with smaller minlenratio." - ) - return ( - [] - if minlenratio < 0.1 - else self.forward(x, maxlenratio, max(0.0, minlenratio - 0.1)) - ) - - # report the best result - best = nbest_hyps[0] - for k, v in best.scores.items(): - logging.info( - f"{v:6.2f} * {self.weights[k]:3} = {v * self.weights[k]:6.2f} for {k}" - ) - logging.info(f"total log probability: {best.score:.2f}") - logging.info(f"normalized log probability: {best.score / len(best.yseq):.2f}") - logging.info(f"total number of ended hypotheses: {len(nbest_hyps)}") - if self.token_list is not None: - logging.info( - "best hypo: " - + "".join([self.token_list[x] for x in best.yseq[1:-1]]) - + "\n" - ) - return nbest_hyps - - def post_process( - self, - i: int, - maxlen: int, - maxlenratio: float, - running_hyps: List[Hypothesis], - ended_hyps: List[Hypothesis], - ) -> List[Hypothesis]: - """Perform post-processing of beam search iterations. - - Args: - i (int): The length of hypothesis tokens. - maxlen (int): The maximum length of tokens in beam search. - maxlenratio (int): The maximum length ratio in beam search. - running_hyps (List[Hypothesis]): The running hypotheses in beam search. - ended_hyps (List[Hypothesis]): The ended hypotheses in beam search. - - Returns: - List[Hypothesis]: The new running hypotheses. - - """ - logging.debug(f"the number of running hypotheses: {len(running_hyps)}") - if self.token_list is not None: - logging.debug( - "best hypo: " - + "".join([self.token_list[x] for x in running_hyps[0].yseq[1:]]) - ) - # add eos in the final loop to avoid that there are no ended hyps - if i == maxlen - 1: - logging.info("adding in the last position in the loop") - running_hyps = [ - h._replace(yseq=self.append_token(h.yseq, self.eos)) - for h in running_hyps - ] - - # add ended hypotheses to a final list, and removed them from current hypotheses - # (this will be a problem, number of hyps < beam) - remained_hyps = [] - for hyp in running_hyps: - if hyp.yseq[-1] == self.eos: - # e.g., Word LM needs to add final score - for k, d in chain(self.full_scorers.items(), self.part_scorers.items()): - s = d.final_score(hyp.states[k]) - hyp.scores[k] += s - hyp = hyp._replace(score=hyp.score + self.weights[k] * s) - ended_hyps.append(hyp) - else: - remained_hyps.append(hyp) - return remained_hyps - diff --git a/funasr/modules/e2e_asr_common.py b/funasr/modules/e2e_asr_common.py deleted file mode 100644 index 98006f948..000000000 --- a/funasr/modules/e2e_asr_common.py +++ /dev/null @@ -1,403 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -# Copyright 2017 Johns Hopkins University (Shinji Watanabe) -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -"""Common functions for ASR.""" - -from typing import List, Optional, Tuple - -import json -import logging -import sys - -from itertools import groupby -import numpy as np -import six -import torch - -from funasr.modules.beam_search.beam_search_transducer import BeamSearchTransducer -from funasr.models.joint_net.joint_network import JointNetwork - -def end_detect(ended_hyps, i, M=3, D_end=np.log(1 * np.exp(-10))): - """End detection. - - described in Eq. (50) of S. Watanabe et al - "Hybrid CTC/Attention Architecture for End-to-End Speech Recognition" - - :param ended_hyps: - :param i: - :param M: - :param D_end: - :return: - """ - if len(ended_hyps) == 0: - return False - count = 0 - best_hyp = sorted(ended_hyps, key=lambda x: x["score"], reverse=True)[0] - for m in six.moves.range(M): - # get ended_hyps with their length is i - m - hyp_length = i - m - hyps_same_length = [x for x in ended_hyps if len(x["yseq"]) == hyp_length] - if len(hyps_same_length) > 0: - best_hyp_same_length = sorted( - hyps_same_length, key=lambda x: x["score"], reverse=True - )[0] - if best_hyp_same_length["score"] - best_hyp["score"] < D_end: - count += 1 - - if count == M: - return True - else: - return False - - -# TODO(takaaki-hori): add different smoothing methods -def label_smoothing_dist(odim, lsm_type, transcript=None, blank=0): - """Obtain label distribution for loss smoothing. - - :param odim: - :param lsm_type: - :param blank: - :param transcript: - :return: - """ - if transcript is not None: - with open(transcript, "rb") as f: - trans_json = json.load(f)["utts"] - - if lsm_type == "unigram": - assert transcript is not None, ( - "transcript is required for %s label smoothing" % lsm_type - ) - labelcount = np.zeros(odim) - for k, v in trans_json.items(): - ids = np.array([int(n) for n in v["output"][0]["tokenid"].split()]) - # to avoid an error when there is no text in an uttrance - if len(ids) > 0: - labelcount[ids] += 1 - labelcount[odim - 1] = len(transcript) # count - labelcount[labelcount == 0] = 1 # flooring - labelcount[blank] = 0 # remove counts for blank - labeldist = labelcount.astype(np.float32) / np.sum(labelcount) - else: - logging.error("Error: unexpected label smoothing type: %s" % lsm_type) - sys.exit() - - return labeldist - - -def get_vgg2l_odim(idim, in_channel=3, out_channel=128): - """Return the output size of the VGG frontend. - - :param in_channel: input channel size - :param out_channel: output channel size - :return: output size - :rtype int - """ - idim = idim / in_channel - idim = np.ceil(np.array(idim, dtype=np.float32) / 2) # 1st max pooling - idim = np.ceil(np.array(idim, dtype=np.float32) / 2) # 2nd max pooling - return int(idim) * out_channel # numer of channels - - -class ErrorCalculator(object): - """Calculate CER and WER for E2E_ASR and CTC models during training. - - :param y_hats: numpy array with predicted text - :param y_pads: numpy array with true (target) text - :param char_list: - :param sym_space: - :param sym_blank: - :return: - """ - - def __init__( - self, char_list, sym_space, sym_blank, report_cer=False, report_wer=False - ): - """Construct an ErrorCalculator object.""" - super(ErrorCalculator, self).__init__() - - self.report_cer = report_cer - self.report_wer = report_wer - - self.char_list = char_list - self.space = sym_space - self.blank = sym_blank - self.idx_blank = self.char_list.index(self.blank) - if self.space in self.char_list: - self.idx_space = self.char_list.index(self.space) - else: - self.idx_space = None - - def __call__(self, ys_hat, ys_pad, is_ctc=False): - """Calculate sentence-level WER/CER score. - - :param torch.Tensor ys_hat: prediction (batch, seqlen) - :param torch.Tensor ys_pad: reference (batch, seqlen) - :param bool is_ctc: calculate CER score for CTC - :return: sentence-level WER score - :rtype float - :return: sentence-level CER score - :rtype float - """ - cer, wer = None, None - if is_ctc: - return self.calculate_cer_ctc(ys_hat, ys_pad) - elif not self.report_cer and not self.report_wer: - return cer, wer - - seqs_hat, seqs_true = self.convert_to_char(ys_hat, ys_pad) - if self.report_cer: - cer = self.calculate_cer(seqs_hat, seqs_true) - - if self.report_wer: - wer = self.calculate_wer(seqs_hat, seqs_true) - return cer, wer - - def calculate_cer_ctc(self, ys_hat, ys_pad): - """Calculate sentence-level CER score for CTC. - - :param torch.Tensor ys_hat: prediction (batch, seqlen) - :param torch.Tensor ys_pad: reference (batch, seqlen) - :return: average sentence-level CER score - :rtype float - """ - import editdistance - - cers, char_ref_lens = [], [] - for i, y in enumerate(ys_hat): - y_hat = [x[0] for x in groupby(y)] - y_true = ys_pad[i] - seq_hat, seq_true = [], [] - for idx in y_hat: - idx = int(idx) - if idx != -1 and idx != self.idx_blank and idx != self.idx_space: - seq_hat.append(self.char_list[int(idx)]) - - for idx in y_true: - idx = int(idx) - if idx != -1 and idx != self.idx_blank and idx != self.idx_space: - seq_true.append(self.char_list[int(idx)]) - - hyp_chars = "".join(seq_hat) - ref_chars = "".join(seq_true) - if len(ref_chars) > 0: - cers.append(editdistance.eval(hyp_chars, ref_chars)) - char_ref_lens.append(len(ref_chars)) - - cer_ctc = float(sum(cers)) / sum(char_ref_lens) if cers else None - return cer_ctc - - def convert_to_char(self, ys_hat, ys_pad): - """Convert index to character. - - :param torch.Tensor seqs_hat: prediction (batch, seqlen) - :param torch.Tensor seqs_true: reference (batch, seqlen) - :return: token list of prediction - :rtype list - :return: token list of reference - :rtype list - """ - seqs_hat, seqs_true = [], [] - for i, y_hat in enumerate(ys_hat): - y_true = ys_pad[i] - eos_true = np.where(y_true == -1)[0] - ymax = eos_true[0] if len(eos_true) > 0 else len(y_true) - # NOTE: padding index (-1) in y_true is used to pad y_hat - seq_hat = [self.char_list[int(idx)] for idx in y_hat[:ymax]] - seq_true = [self.char_list[int(idx)] for idx in y_true if int(idx) != -1] - seq_hat_text = "".join(seq_hat).replace(self.space, " ") - seq_hat_text = seq_hat_text.replace(self.blank, "") - seq_true_text = "".join(seq_true).replace(self.space, " ") - seqs_hat.append(seq_hat_text) - seqs_true.append(seq_true_text) - return seqs_hat, seqs_true - - def calculate_cer(self, seqs_hat, seqs_true): - """Calculate sentence-level CER score. - - :param list seqs_hat: prediction - :param list seqs_true: reference - :return: average sentence-level CER score - :rtype float - """ - import editdistance - - char_eds, char_ref_lens = [], [] - for i, seq_hat_text in enumerate(seqs_hat): - seq_true_text = seqs_true[i] - hyp_chars = seq_hat_text.replace(" ", "") - ref_chars = seq_true_text.replace(" ", "") - char_eds.append(editdistance.eval(hyp_chars, ref_chars)) - char_ref_lens.append(len(ref_chars)) - return float(sum(char_eds)) / sum(char_ref_lens) - - def calculate_wer(self, seqs_hat, seqs_true): - """Calculate sentence-level WER score. - - :param list seqs_hat: prediction - :param list seqs_true: reference - :return: average sentence-level WER score - :rtype float - """ - import editdistance - - word_eds, word_ref_lens = [], [] - for i, seq_hat_text in enumerate(seqs_hat): - seq_true_text = seqs_true[i] - hyp_words = seq_hat_text.split() - ref_words = seq_true_text.split() - word_eds.append(editdistance.eval(hyp_words, ref_words)) - word_ref_lens.append(len(ref_words)) - return float(sum(word_eds)) / sum(word_ref_lens) - -class ErrorCalculatorTransducer: - """Calculate CER and WER for transducer models. - Args: - decoder: Decoder module. - joint_network: Joint Network module. - token_list: List of token units. - sym_space: Space symbol. - sym_blank: Blank symbol. - report_cer: Whether to compute CER. - report_wer: Whether to compute WER. - """ - - def __init__( - self, - decoder, - joint_network: JointNetwork, - token_list: List[int], - sym_space: str, - sym_blank: str, - report_cer: bool = False, - report_wer: bool = False, - ) -> None: - """Construct an ErrorCalculatorTransducer object.""" - super().__init__() - - self.beam_search = BeamSearchTransducer( - decoder=decoder, - joint_network=joint_network, - beam_size=1, - search_type="default", - score_norm=False, - ) - - self.decoder = decoder - - self.token_list = token_list - self.space = sym_space - self.blank = sym_blank - - self.report_cer = report_cer - self.report_wer = report_wer - - def __call__( - self, encoder_out: torch.Tensor, target: torch.Tensor, encoder_out_lens: torch.Tensor, - ) -> Tuple[Optional[float], Optional[float]]: - """Calculate sentence-level WER or/and CER score for Transducer model. - Args: - encoder_out: Encoder output sequences. (B, T, D_enc) - target: Target label ID sequences. (B, L) - encoder_out_lens: Encoder output sequences length. (B,) - Returns: - : Sentence-level CER score. - : Sentence-level WER score. - """ - cer, wer = None, None - - batchsize = int(encoder_out.size(0)) - - encoder_out = encoder_out.to(next(self.decoder.parameters()).device) - - batch_nbest = [ - self.beam_search(encoder_out[b][: encoder_out_lens[b]]) - for b in range(batchsize) - ] - pred = [nbest_hyp[0].yseq[1:] for nbest_hyp in batch_nbest] - - char_pred, char_target = self.convert_to_char(pred, target) - - if self.report_cer: - cer = self.calculate_cer(char_pred, char_target) - - if self.report_wer: - wer = self.calculate_wer(char_pred, char_target) - - return cer, wer - - def convert_to_char( - self, pred: torch.Tensor, target: torch.Tensor - ) -> Tuple[List, List]: - """Convert label ID sequences to character sequences. - Args: - pred: Prediction label ID sequences. (B, U) - target: Target label ID sequences. (B, L) - Returns: - char_pred: Prediction character sequences. (B, ?) - char_target: Target character sequences. (B, ?) - """ - char_pred, char_target = [], [] - - for i, pred_i in enumerate(pred): - char_pred_i = [self.token_list[int(h)] for h in pred_i] - char_target_i = [self.token_list[int(r)] for r in target[i]] - - char_pred_i = "".join(char_pred_i).replace(self.space, " ") - char_pred_i = char_pred_i.replace(self.blank, "") - - char_target_i = "".join(char_target_i).replace(self.space, " ") - char_target_i = char_target_i.replace(self.blank, "") - - char_pred.append(char_pred_i) - char_target.append(char_target_i) - - return char_pred, char_target - - def calculate_cer( - self, char_pred: torch.Tensor, char_target: torch.Tensor - ) -> float: - """Calculate sentence-level CER score. - Args: - char_pred: Prediction character sequences. (B, ?) - char_target: Target character sequences. (B, ?) - Returns: - : Average sentence-level CER score. - """ - import editdistance - - distances, lens = [], [] - - for i, char_pred_i in enumerate(char_pred): - pred = char_pred_i.replace(" ", "") - target = char_target[i].replace(" ", "") - distances.append(editdistance.eval(pred, target)) - lens.append(len(target)) - - return float(sum(distances)) / sum(lens) - - def calculate_wer( - self, char_pred: torch.Tensor, char_target: torch.Tensor - ) -> float: - """Calculate sentence-level WER score. - Args: - char_pred: Prediction character sequences. (B, ?) - char_target: Target character sequences. (B, ?) - Returns: - : Average sentence-level WER score - """ - import editdistance - - distances, lens = [], [] - - for i, char_pred_i in enumerate(char_pred): - pred = char_pred_i.replace("▁", " ").split() - target = char_target[i].replace("▁", " ").split() - - distances.append(editdistance.eval(pred, target)) - lens.append(len(target)) - - return float(sum(distances)) / sum(lens) diff --git a/funasr/samplers/abs_sampler.py b/funasr/samplers/abs_sampler.py deleted file mode 100644 index 2f7aa539b..000000000 --- a/funasr/samplers/abs_sampler.py +++ /dev/null @@ -1,19 +0,0 @@ -from abc import ABC -from abc import abstractmethod -from typing import Iterator -from typing import Tuple - -from torch.utils.data import Sampler - - -class AbsSampler(Sampler, ABC): - @abstractmethod - def __len__(self) -> int: - raise NotImplementedError - - @abstractmethod - def __iter__(self) -> Iterator[Tuple[str, ...]]: - raise NotImplementedError - - def generate(self, seed): - return list(self) diff --git a/funasr/samplers/build_batch_sampler.py b/funasr/samplers/build_batch_sampler.py deleted file mode 100644 index 9266fea7c..000000000 --- a/funasr/samplers/build_batch_sampler.py +++ /dev/null @@ -1,164 +0,0 @@ -from typing import List -from typing import Dict -from typing import Sequence -from typing import Tuple -from typing import Union - - -from funasr.samplers.abs_sampler import AbsSampler -from funasr.samplers.folded_batch_sampler import FoldedBatchSampler -from funasr.samplers.length_batch_sampler import LengthBatchSampler -from funasr.samplers.num_elements_batch_sampler import NumElementsBatchSampler -from funasr.samplers.sorted_batch_sampler import SortedBatchSampler -from funasr.samplers.unsorted_batch_sampler import UnsortedBatchSampler - - -BATCH_TYPES = dict( - unsorted="UnsortedBatchSampler has nothing in particular feature and " - "just creates mini-batches which has constant batch_size. " - "This sampler doesn't require any length " - "information for each feature. " - "'key_file' is just a text file which describes each sample name." - "\n\n" - " utterance_id_a\n" - " utterance_id_b\n" - " utterance_id_c\n" - "\n" - "The fist column is referred, so 'shape file' can be used, too.\n\n" - " utterance_id_a 100,80\n" - " utterance_id_b 400,80\n" - " utterance_id_c 512,80\n", - sorted="SortedBatchSampler sorts samples by the length of the first input " - " in order to make each sample in a mini-batch has close length. " - "This sampler requires a text file which describes the length for each sample " - "\n\n" - " utterance_id_a 1000\n" - " utterance_id_b 1453\n" - " utterance_id_c 1241\n" - "\n" - "The first element of feature dimensions is referred, " - "so 'shape_file' can be also used.\n\n" - " utterance_id_a 1000,80\n" - " utterance_id_b 1453,80\n" - " utterance_id_c 1241,80\n", - folded="FoldedBatchSampler supports variable batch_size. " - "The batch_size is decided by\n" - " batch_size = base_batch_size // (L // fold_length)\n" - "L is referred to the largest length of samples in the mini-batch. " - "This samples requires length information as same as SortedBatchSampler\n", - length="LengthBatchSampler supports variable batch_size. " - "This sampler makes mini-batches which have same number of 'bins' as possible " - "counting by the total lengths of each feature in the mini-batch. " - "This sampler requires a text file which describes the length for each sample. " - "\n\n" - " utterance_id_a 1000\n" - " utterance_id_b 1453\n" - " utterance_id_c 1241\n" - "\n" - "The first element of feature dimensions is referred, " - "so 'shape_file' can be also used.\n\n" - " utterance_id_a 1000,80\n" - " utterance_id_b 1453,80\n" - " utterance_id_c 1241,80\n", - numel="NumElementsBatchSampler supports variable batch_size. " - "Just like LengthBatchSampler, this sampler makes mini-batches" - " which have same number of 'bins' as possible " - "counting by the total number of elements of each feature " - "instead of the length. " - "Thus this sampler requires the full information of the dimension of the features. " - "\n\n" - " utterance_id_a 1000,80\n" - " utterance_id_b 1453,80\n" - " utterance_id_c 1241,80\n", -) - - -def build_batch_sampler( - type: str, - batch_size: int, - batch_bins: int, - shape_files: Union[Tuple[str, ...], List[str], Dict], - sort_in_batch: str = "descending", - sort_batch: str = "ascending", - drop_last: bool = False, - min_batch_size: int = 1, - fold_lengths: Sequence[int] = (), - padding: bool = True, - utt2category_file: str = None, -) -> AbsSampler: - """Helper function to instantiate BatchSampler. - - Args: - type: mini-batch type. "unsorted", "sorted", "folded", "numel", or, "length" - batch_size: The mini-batch size. Used for "unsorted", "sorted", "folded" mode - batch_bins: Used for "numel" model - shape_files: Text files describing the length and dimension - of each features. e.g. uttA 1330,80 - sort_in_batch: - sort_batch: - drop_last: - min_batch_size: Used for "numel" or "folded" mode - fold_lengths: Used for "folded" mode - padding: Whether sequences are input as a padded tensor or not. - used for "numel" mode - """ - if len(shape_files) == 0: - raise ValueError("No shape file are given") - - if type == "unsorted": - retval = UnsortedBatchSampler( - batch_size=batch_size, key_file=shape_files[0], drop_last=drop_last - ) - - elif type == "sorted": - retval = SortedBatchSampler( - batch_size=batch_size, - shape_file=shape_files[0], - sort_in_batch=sort_in_batch, - sort_batch=sort_batch, - drop_last=drop_last, - ) - - elif type == "folded": - if len(fold_lengths) != len(shape_files): - raise ValueError( - f"The number of fold_lengths must be equal to " - f"the number of shape_files: " - f"{len(fold_lengths)} != {len(shape_files)}" - ) - retval = FoldedBatchSampler( - batch_size=batch_size, - shape_files=shape_files, - fold_lengths=fold_lengths, - sort_in_batch=sort_in_batch, - sort_batch=sort_batch, - drop_last=drop_last, - min_batch_size=min_batch_size, - utt2category_file=utt2category_file, - ) - - elif type == "numel": - retval = NumElementsBatchSampler( - batch_bins=batch_bins, - shape_files=shape_files, - sort_in_batch=sort_in_batch, - sort_batch=sort_batch, - drop_last=drop_last, - padding=padding, - min_batch_size=min_batch_size, - ) - - elif type == "length": - retval = LengthBatchSampler( - batch_bins=batch_bins, - shape_files=shape_files, - sort_in_batch=sort_in_batch, - sort_batch=sort_batch, - drop_last=drop_last, - padding=padding, - min_batch_size=min_batch_size, - ) - - else: - raise ValueError(f"Not supported: {type}") - return retval diff --git a/funasr/samplers/folded_batch_sampler.py b/funasr/samplers/folded_batch_sampler.py deleted file mode 100644 index f48d74480..000000000 --- a/funasr/samplers/folded_batch_sampler.py +++ /dev/null @@ -1,154 +0,0 @@ -from typing import Iterator -from typing import List -from typing import Sequence -from typing import Tuple -from typing import Union - - -from funasr.fileio.read_text import load_num_sequence_text -from funasr.fileio.read_text import read_2column_text -from funasr.samplers.abs_sampler import AbsSampler - - -class FoldedBatchSampler(AbsSampler): - def __init__( - self, - batch_size: int, - shape_files: Union[Tuple[str, ...], List[str]], - fold_lengths: Sequence[int], - min_batch_size: int = 1, - sort_in_batch: str = "descending", - sort_batch: str = "ascending", - drop_last: bool = False, - utt2category_file: str = None, - ): - assert batch_size > 0 - if sort_batch != "ascending" and sort_batch != "descending": - raise ValueError( - f"sort_batch must be ascending or descending: {sort_batch}" - ) - if sort_in_batch != "descending" and sort_in_batch != "ascending": - raise ValueError( - f"sort_in_batch must be ascending or descending: {sort_in_batch}" - ) - - self.batch_size = batch_size - self.shape_files = shape_files - self.sort_in_batch = sort_in_batch - self.sort_batch = sort_batch - self.drop_last = drop_last - - # utt2shape: (Length, ...) - # uttA 100,... - # uttB 201,... - utt2shapes = [ - load_num_sequence_text(s, loader_type="csv_int") for s in shape_files - ] - - first_utt2shape = utt2shapes[0] - for s, d in zip(shape_files, utt2shapes): - if set(d) != set(first_utt2shape): - raise RuntimeError( - f"keys are mismatched between {s} != {shape_files[0]}" - ) - - # Sort samples in ascending order - # (shape order should be like (Length, Dim)) - keys = sorted(first_utt2shape, key=lambda k: first_utt2shape[k][0]) - if len(keys) == 0: - raise RuntimeError(f"0 lines found: {shape_files[0]}") - - category2utt = {} - if utt2category_file is not None: - utt2category = read_2column_text(utt2category_file) - if set(utt2category) != set(first_utt2shape): - raise RuntimeError( - "keys are mismatched between " - f"{utt2category_file} != {shape_files[0]}" - ) - for k in keys: - category2utt.setdefault(utt2category[k], []).append(k) - else: - category2utt["default_category"] = keys - - self.batch_list = [] - for d, v in category2utt.items(): - category_keys = v - # Decide batch-sizes - start = 0 - batch_sizes = [] - while True: - k = category_keys[start] - factor = max(int(d[k][0] / m) for d, m in zip(utt2shapes, fold_lengths)) - bs = max(min_batch_size, int(batch_size / (1 + factor))) - if self.drop_last and start + bs > len(category_keys): - # This if-block avoids 0-batches - if len(self.batch_list) > 0: - break - - bs = min(len(category_keys) - start, bs) - batch_sizes.append(bs) - start += bs - if start >= len(category_keys): - break - - if len(batch_sizes) == 0: - # Maybe we can't reach here - raise RuntimeError("0 batches") - - # If the last batch-size is smaller than minimum batch_size, - # the samples are redistributed to the other mini-batches - if len(batch_sizes) > 1 and batch_sizes[-1] < min_batch_size: - for i in range(batch_sizes.pop(-1)): - batch_sizes[-(i % len(batch_sizes)) - 2] += 1 - - if not self.drop_last: - # Bug check - assert sum(batch_sizes) == len( - category_keys - ), f"{sum(batch_sizes)} != {len(category_keys)}" - - # Set mini-batch - cur_batch_list = [] - start = 0 - for bs in batch_sizes: - assert len(category_keys) >= start + bs, "Bug" - minibatch_keys = category_keys[start : start + bs] - start += bs - if sort_in_batch == "descending": - minibatch_keys.reverse() - elif sort_in_batch == "ascending": - # Key are already sorted in ascending - pass - else: - raise ValueError( - "sort_in_batch must be ascending or " - f"descending: {sort_in_batch}" - ) - cur_batch_list.append(tuple(minibatch_keys)) - - if sort_batch == "ascending": - pass - elif sort_batch == "descending": - cur_batch_list.reverse() - else: - raise ValueError( - f"sort_batch must be ascending or descending: {sort_batch}" - ) - self.batch_list.extend(cur_batch_list) - - def __repr__(self): - return ( - f"{self.__class__.__name__}(" - f"N-batch={len(self)}, " - f"batch_size={self.batch_size}, " - f"shape_files={self.shape_files}, " - f"sort_in_batch={self.sort_in_batch}, " - f"sort_batch={self.sort_batch})" - ) - - def __len__(self): - return len(self.batch_list) - - def __iter__(self) -> Iterator[Tuple[str, ...]]: - return iter(self.batch_list) diff --git a/funasr/samplers/length_batch_sampler.py b/funasr/samplers/length_batch_sampler.py deleted file mode 100644 index 28404e32c..000000000 --- a/funasr/samplers/length_batch_sampler.py +++ /dev/null @@ -1,145 +0,0 @@ -from typing import Iterator -from typing import List -from typing import Dict -from typing import Tuple -from typing import Union - - -from funasr.fileio.read_text import load_num_sequence_text -from funasr.samplers.abs_sampler import AbsSampler - - -class LengthBatchSampler(AbsSampler): - def __init__( - self, - batch_bins: int, - shape_files: Union[Tuple[str, ...], List[str], Dict], - min_batch_size: int = 1, - sort_in_batch: str = "descending", - sort_batch: str = "ascending", - drop_last: bool = False, - padding: bool = True, - ): - assert batch_bins > 0 - if sort_batch != "ascending" and sort_batch != "descending": - raise ValueError( - f"sort_batch must be ascending or descending: {sort_batch}" - ) - if sort_in_batch != "descending" and sort_in_batch != "ascending": - raise ValueError( - f"sort_in_batch must be ascending or descending: {sort_in_batch}" - ) - - self.batch_bins = batch_bins - self.shape_files = shape_files - self.sort_in_batch = sort_in_batch - self.sort_batch = sort_batch - self.drop_last = drop_last - - # utt2shape: (Length, ...) - # uttA 100,... - # uttB 201,... - if isinstance(shape_files, dict): - utt2shapes = [shape_files] - else: - utt2shapes = [ - load_num_sequence_text(s, loader_type="csv_int") for s in shape_files - ] - - first_utt2shape = utt2shapes[0] - for s, d in zip(shape_files, utt2shapes): - if set(d) != set(first_utt2shape): - raise RuntimeError( - f"keys are mismatched between {s} != {shape_files[0]}" - ) - - # Sort samples in ascending order - # (shape order should be like (Length, Dim)) - keys = sorted(first_utt2shape, key=lambda k: first_utt2shape[k][0]) - if len(keys) == 0: - raise RuntimeError(f"0 lines found: {shape_files[0]}") - - # Decide batch-sizes - batch_sizes = [] - current_batch_keys = [] - for key in keys: - current_batch_keys.append(key) - # shape: (Length, dim1, dim2, ...) - if padding: - # bins = bs x max_length - bins = sum(len(current_batch_keys) * sh[key][0] for sh in utt2shapes) - else: - # bins = sum of lengths - bins = sum(d[k][0] for k in current_batch_keys for d in utt2shapes) - - if bins > batch_bins and len(current_batch_keys) >= min_batch_size: - batch_sizes.append(len(current_batch_keys)) - current_batch_keys = [] - else: - if len(current_batch_keys) != 0 and ( - not self.drop_last or len(batch_sizes) == 0 - ): - batch_sizes.append(len(current_batch_keys)) - - if len(batch_sizes) == 0: - # Maybe we can't reach here - raise RuntimeError("0 batches") - - # If the last batch-size is smaller than minimum batch_size, - # the samples are redistributed to the other mini-batches - if len(batch_sizes) > 1 and batch_sizes[-1] < min_batch_size: - for i in range(batch_sizes.pop(-1)): - batch_sizes[-(i % len(batch_sizes)) - 1] += 1 - - if not self.drop_last: - # Bug check - assert sum(batch_sizes) == len(keys), f"{sum(batch_sizes)} != {len(keys)}" - - # Set mini-batch - self.batch_list = [] - iter_bs = iter(batch_sizes) - bs = next(iter_bs) - minibatch_keys = [] - for key in keys: - minibatch_keys.append(key) - if len(minibatch_keys) == bs: - if sort_in_batch == "descending": - minibatch_keys.reverse() - elif sort_in_batch == "ascending": - # Key are already sorted in ascending - pass - else: - raise ValueError( - "sort_in_batch must be ascending" - f" or descending: {sort_in_batch}" - ) - self.batch_list.append(tuple(minibatch_keys)) - minibatch_keys = [] - try: - bs = next(iter_bs) - except StopIteration: - break - - if sort_batch == "ascending": - pass - elif sort_batch == "descending": - self.batch_list.reverse() - else: - raise ValueError( - f"sort_batch must be ascending or descending: {sort_batch}" - ) - - def __repr__(self): - return ( - f"{self.__class__.__name__}(" - f"N-batch={len(self)}, " - f"batch_bins={self.batch_bins}, " - f"sort_in_batch={self.sort_in_batch}, " - f"sort_batch={self.sort_batch})" - ) - - def __len__(self): - return len(self.batch_list) - - def __iter__(self) -> Iterator[Tuple[str, ...]]: - return iter(self.batch_list) diff --git a/funasr/samplers/num_elements_batch_sampler.py b/funasr/samplers/num_elements_batch_sampler.py deleted file mode 100644 index ebed0e415..000000000 --- a/funasr/samplers/num_elements_batch_sampler.py +++ /dev/null @@ -1,158 +0,0 @@ -from typing import Iterator -from typing import List -from typing import Tuple -from typing import Union - -import numpy as np - -from funasr.fileio.read_text import load_num_sequence_text -from funasr.samplers.abs_sampler import AbsSampler - - -class NumElementsBatchSampler(AbsSampler): - def __init__( - self, - batch_bins: int, - shape_files: Union[Tuple[str, ...], List[str]], - min_batch_size: int = 1, - sort_in_batch: str = "descending", - sort_batch: str = "ascending", - drop_last: bool = False, - padding: bool = True, - ): - assert batch_bins > 0 - if sort_batch != "ascending" and sort_batch != "descending": - raise ValueError( - f"sort_batch must be ascending or descending: {sort_batch}" - ) - if sort_in_batch != "descending" and sort_in_batch != "ascending": - raise ValueError( - f"sort_in_batch must be ascending or descending: {sort_in_batch}" - ) - - self.batch_bins = batch_bins - self.shape_files = shape_files - self.sort_in_batch = sort_in_batch - self.sort_batch = sort_batch - self.drop_last = drop_last - - # utt2shape: (Length, ...) - # uttA 100,... - # uttB 201,... - utt2shapes = [ - load_num_sequence_text(s, loader_type="csv_int") for s in shape_files - ] - - first_utt2shape = utt2shapes[0] - for s, d in zip(shape_files, utt2shapes): - if set(d) != set(first_utt2shape): - raise RuntimeError( - f"keys are mismatched between {s} != {shape_files[0]}" - ) - - # Sort samples in ascending order - # (shape order should be like (Length, Dim)) - keys = sorted(first_utt2shape, key=lambda k: first_utt2shape[k][0]) - if len(keys) == 0: - raise RuntimeError(f"0 lines found: {shape_files[0]}") - if padding: - # If padding case, the feat-dim must be same over whole corpus, - # therefore the first sample is referred - feat_dims = [np.prod(d[keys[0]][1:]) for d in utt2shapes] - else: - feat_dims = None - - # Decide batch-sizes - batch_sizes = [] - current_batch_keys = [] - for key in keys: - current_batch_keys.append(key) - # shape: (Length, dim1, dim2, ...) - if padding: - for d, s in zip(utt2shapes, shape_files): - if tuple(d[key][1:]) != tuple(d[keys[0]][1:]): - raise RuntimeError( - "If padding=True, the " - f"feature dimension must be unified: {s}", - ) - bins = sum( - len(current_batch_keys) * sh[key][0] * d - for sh, d in zip(utt2shapes, feat_dims) - ) - else: - bins = sum( - np.prod(d[k]) for k in current_batch_keys for d in utt2shapes - ) - - if bins > batch_bins and len(current_batch_keys) >= min_batch_size: - batch_sizes.append(len(current_batch_keys)) - current_batch_keys = [] - else: - if len(current_batch_keys) != 0 and ( - not self.drop_last or len(batch_sizes) == 0 - ): - batch_sizes.append(len(current_batch_keys)) - - if len(batch_sizes) == 0: - # Maybe we can't reach here - raise RuntimeError("0 batches") - - # If the last batch-size is smaller than minimum batch_size, - # the samples are redistributed to the other mini-batches - if len(batch_sizes) > 1 and batch_sizes[-1] < min_batch_size: - for i in range(batch_sizes.pop(-1)): - batch_sizes[-(i % len(batch_sizes)) - 1] += 1 - - if not self.drop_last: - # Bug check - assert sum(batch_sizes) == len(keys), f"{sum(batch_sizes)} != {len(keys)}" - - # Set mini-batch - self.batch_list = [] - iter_bs = iter(batch_sizes) - bs = next(iter_bs) - minibatch_keys = [] - for key in keys: - minibatch_keys.append(key) - if len(minibatch_keys) == bs: - if sort_in_batch == "descending": - minibatch_keys.reverse() - elif sort_in_batch == "ascending": - # Key are already sorted in ascending - pass - else: - raise ValueError( - "sort_in_batch must be ascending" - f" or descending: {sort_in_batch}" - ) - - self.batch_list.append(tuple(minibatch_keys)) - minibatch_keys = [] - try: - bs = next(iter_bs) - except StopIteration: - break - - if sort_batch == "ascending": - pass - elif sort_batch == "descending": - self.batch_list.reverse() - else: - raise ValueError( - f"sort_batch must be ascending or descending: {sort_batch}" - ) - - def __repr__(self): - return ( - f"{self.__class__.__name__}(" - f"N-batch={len(self)}, " - f"batch_bins={self.batch_bins}, " - f"sort_in_batch={self.sort_in_batch}, " - f"sort_batch={self.sort_batch})" - ) - - def __len__(self): - return len(self.batch_list) - - def __iter__(self) -> Iterator[Tuple[str, ...]]: - return iter(self.batch_list) diff --git a/funasr/samplers/sorted_batch_sampler.py b/funasr/samplers/sorted_batch_sampler.py deleted file mode 100644 index b31e93ecf..000000000 --- a/funasr/samplers/sorted_batch_sampler.py +++ /dev/null @@ -1,93 +0,0 @@ -import logging -from typing import Iterator -from typing import Tuple - - -from funasr.fileio.read_text import load_num_sequence_text -from funasr.samplers.abs_sampler import AbsSampler - - -class SortedBatchSampler(AbsSampler): - """BatchSampler with sorted samples by length. - - Args: - batch_size: - shape_file: - sort_in_batch: 'descending', 'ascending' or None. - sort_batch: - """ - - def __init__( - self, - batch_size: int, - shape_file: str, - sort_in_batch: str = "descending", - sort_batch: str = "ascending", - drop_last: bool = False, - ): - assert batch_size > 0 - self.batch_size = batch_size - self.shape_file = shape_file - self.sort_in_batch = sort_in_batch - self.sort_batch = sort_batch - self.drop_last = drop_last - - # utt2shape: (Length, ...) - # uttA 100,... - # uttB 201,... - utt2shape = load_num_sequence_text(shape_file, loader_type="csv_int") - if sort_in_batch == "descending": - # Sort samples in descending order (required by RNN) - keys = sorted(utt2shape, key=lambda k: -utt2shape[k][0]) - elif sort_in_batch == "ascending": - # Sort samples in ascending order - keys = sorted(utt2shape, key=lambda k: utt2shape[k][0]) - else: - raise ValueError( - f"sort_in_batch must be either one of " - f"ascending, descending, or None: {sort_in_batch}" - ) - if len(keys) == 0: - raise RuntimeError(f"0 lines found: {shape_file}") - - # Apply max(, 1) to avoid 0-batches - N = max(len(keys) // batch_size, 1) - if not self.drop_last: - # Split keys evenly as possible as. Note that If N != 1, - # the these batches always have size of batch_size at minimum. - self.batch_list = [ - keys[i * len(keys) // N : (i + 1) * len(keys) // N] for i in range(N) - ] - else: - self.batch_list = [ - tuple(keys[i * batch_size : (i + 1) * batch_size]) for i in range(N) - ] - - if len(self.batch_list) == 0: - logging.warning(f"{shape_file} is empty") - - if sort_in_batch != sort_batch: - if sort_batch not in ("ascending", "descending"): - raise ValueError( - f"sort_batch must be ascending or descending: {sort_batch}" - ) - self.batch_list.reverse() - - if len(self.batch_list) == 0: - raise RuntimeError("0 batches") - - def __repr__(self): - return ( - f"{self.__class__.__name__}(" - f"N-batch={len(self)}, " - f"batch_size={self.batch_size}, " - f"shape_file={self.shape_file}, " - f"sort_in_batch={self.sort_in_batch}, " - f"sort_batch={self.sort_batch})" - ) - - def __len__(self): - return len(self.batch_list) - - def __iter__(self) -> Iterator[Tuple[str, ...]]: - return iter(self.batch_list) diff --git a/funasr/samplers/unsorted_batch_sampler.py b/funasr/samplers/unsorted_batch_sampler.py deleted file mode 100644 index e5ed05bdc..000000000 --- a/funasr/samplers/unsorted_batch_sampler.py +++ /dev/null @@ -1,89 +0,0 @@ -import logging -from typing import Iterator -from typing import Tuple - - -from funasr.fileio.read_text import read_2column_text -from funasr.samplers.abs_sampler import AbsSampler - - -class UnsortedBatchSampler(AbsSampler): - """BatchSampler with constant batch-size. - - Any sorting is not done in this class, - so no length information is required, - This class is convenient for decoding mode, - or not seq2seq learning e.g. classification. - - Args: - batch_size: - key_file: - """ - - def __init__( - self, - batch_size: int, - key_file: str, - drop_last: bool = False, - utt2category_file: str = None, - ): - assert batch_size > 0 - self.batch_size = batch_size - self.key_file = key_file - self.drop_last = drop_last - - # utt2shape: - # uttA - # uttB - utt2any = read_2column_text(key_file) - if len(utt2any) == 0: - logging.warning(f"{key_file} is empty") - # In this case the, the first column in only used - keys = list(utt2any) - if len(keys) == 0: - raise RuntimeError(f"0 lines found: {key_file}") - - category2utt = {} - if utt2category_file is not None: - utt2category = read_2column_text(utt2category_file) - if set(utt2category) != set(keys): - raise RuntimeError( - f"keys are mismatched between {utt2category_file} != {key_file}" - ) - for k, v in utt2category.items(): - category2utt.setdefault(v, []).append(k) - else: - category2utt["default_category"] = keys - - self.batch_list = [] - for d, v in category2utt.items(): - category_keys = v - # Apply max(, 1) to avoid 0-batches - N = max(len(category_keys) // batch_size, 1) - if not self.drop_last: - # Split keys evenly as possible as. Note that If N != 1, - # the these batches always have size of batch_size at minimum. - cur_batch_list = [ - category_keys[i * len(keys) // N : (i + 1) * len(keys) // N] - for i in range(N) - ] - else: - cur_batch_list = [ - tuple(category_keys[i * batch_size : (i + 1) * batch_size]) - for i in range(N) - ] - self.batch_list.extend(cur_batch_list) - - def __repr__(self): - return ( - f"{self.__class__.__name__}(" - f"N-batch={len(self)}, " - f"batch_size={self.batch_size}, " - f"key_file={self.key_file}, " - ) - - def __len__(self): - return len(self.batch_list) - - def __iter__(self) -> Iterator[Tuple[str, ...]]: - return iter(self.batch_list) diff --git a/funasr/tasks/abs_task.py b/funasr/tasks/abs_task.py deleted file mode 100644 index f7f13d289..000000000 --- a/funasr/tasks/abs_task.py +++ /dev/null @@ -1,1965 +0,0 @@ -# Copyright ESPnet (https://github.com/espnet/espnet). All Rights Reserved. -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -"""Abstract task module.""" -import argparse -import functools -import logging -import os -import sys -from abc import ABC -from abc import abstractmethod -from dataclasses import dataclass -from distutils.version import LooseVersion -from io import BytesIO -from pathlib import Path -from typing import Any -from typing import Callable -from typing import Dict -from typing import List -from typing import Optional -from typing import Sequence -from typing import Tuple -from typing import Union - -import humanfriendly -import numpy as np -import torch -import torch.distributed as dist -import torch.multiprocessing -import torch.nn -import torch.optim -import yaml -from funasr.models.base_model import FunASRModel -from torch.utils.data import DataLoader - -from funasr import __version__ -from funasr.datasets.dataset import AbsDataset -from funasr.datasets.dataset import DATA_TYPES -from funasr.datasets.dataset import ESPnetDataset -from funasr.datasets.iterable_dataset import IterableESPnetDataset -from funasr.iterators.abs_iter_factory import AbsIterFactory -from funasr.iterators.chunk_iter_factory import ChunkIterFactory -from funasr.iterators.multiple_iter_factory import MultipleIterFactory -from funasr.iterators.sequence_iter_factory import SequenceIterFactory -from funasr.main_funcs.collect_stats import collect_stats -from funasr.optimizers.fairseq_adam import FairseqAdam -from funasr.optimizers.sgd import SGD -from funasr.samplers.build_batch_sampler import BATCH_TYPES -from funasr.samplers.build_batch_sampler import build_batch_sampler -from funasr.samplers.unsorted_batch_sampler import UnsortedBatchSampler -from funasr.schedulers.noam_lr import NoamLR -from funasr.schedulers.tri_stage_scheduler import TriStageLR -from funasr.schedulers.warmup_lr import WarmupLR -from funasr.torch_utils.load_pretrained_model import load_pretrained_model -from funasr.torch_utils.model_summary import model_summary -from funasr.torch_utils.pytorch_version import pytorch_cudnn_version -from funasr.torch_utils.set_all_random_seed import set_all_random_seed -from funasr.train.class_choices import ClassChoices -from funasr.train.distributed_utils import DistributedOption -from funasr.train.trainer import Trainer -from funasr.utils import config_argparse -from funasr.utils.build_dataclass import build_dataclass -from funasr.utils.cli_utils import get_commandline_args -from funasr.utils.get_default_kwargs import get_default_kwargs -from funasr.utils.nested_dict_action import NestedDictAction -from funasr.utils.types import humanfriendly_parse_size_or_none -from funasr.utils.types import int_or_none -from funasr.utils.types import str2bool -from funasr.utils.types import str2triple_str -from funasr.utils.types import str_or_int -from funasr.utils.types import str_or_none -from funasr.utils.wav_utils import calc_shape, generate_data_list, filter_wav_text -from funasr.utils.yaml_no_alias_safe_dump import yaml_no_alias_safe_dump -from funasr.modules.lora.utils import mark_only_lora_as_trainable - -try: - import wandb -except Exception: - wandb = None - -if LooseVersion(torch.__version__) >= LooseVersion("1.5.0"): - pass -else: - pass - -optim_classes = dict( - adam=torch.optim.Adam, - fairseq_adam=FairseqAdam, - adamw=torch.optim.AdamW, - sgd=SGD, - adadelta=torch.optim.Adadelta, - adagrad=torch.optim.Adagrad, - adamax=torch.optim.Adamax, - asgd=torch.optim.ASGD, - lbfgs=torch.optim.LBFGS, - rmsprop=torch.optim.RMSprop, - rprop=torch.optim.Rprop, -) -if LooseVersion(torch.__version__) >= LooseVersion("1.10.0"): - # From 1.10.0, RAdam is officially supported - optim_classes.update( - radam=torch.optim.RAdam, - ) -try: - import torch_optimizer - - optim_classes.update( - accagd=torch_optimizer.AccSGD, - adabound=torch_optimizer.AdaBound, - adamod=torch_optimizer.AdaMod, - diffgrad=torch_optimizer.DiffGrad, - lamb=torch_optimizer.Lamb, - novograd=torch_optimizer.NovoGrad, - pid=torch_optimizer.PID, - # torch_optimizer<=0.0.1a10 doesn't support - # qhadam=torch_optimizer.QHAdam, - qhm=torch_optimizer.QHM, - sgdw=torch_optimizer.SGDW, - yogi=torch_optimizer.Yogi, - ) - if LooseVersion(torch_optimizer.__version__) < LooseVersion("0.2.0"): - # From 0.2.0, RAdam is dropped - optim_classes.update( - radam=torch_optimizer.RAdam, - ) - del torch_optimizer -except ImportError: - pass -try: - import apex - - optim_classes.update( - fusedadam=apex.optimizers.FusedAdam, - fusedlamb=apex.optimizers.FusedLAMB, - fusednovograd=apex.optimizers.FusedNovoGrad, - fusedsgd=apex.optimizers.FusedSGD, - ) - del apex -except ImportError: - pass -try: - import fairscale -except ImportError: - fairscale = None - -scheduler_classes = dict( - ReduceLROnPlateau=torch.optim.lr_scheduler.ReduceLROnPlateau, - lambdalr=torch.optim.lr_scheduler.LambdaLR, - steplr=torch.optim.lr_scheduler.StepLR, - multisteplr=torch.optim.lr_scheduler.MultiStepLR, - exponentiallr=torch.optim.lr_scheduler.ExponentialLR, - CosineAnnealingLR=torch.optim.lr_scheduler.CosineAnnealingLR, - noamlr=NoamLR, - warmuplr=WarmupLR, - tri_stage=TriStageLR, - cycliclr=torch.optim.lr_scheduler.CyclicLR, - onecyclelr=torch.optim.lr_scheduler.OneCycleLR, - CosineAnnealingWarmRestarts=torch.optim.lr_scheduler.CosineAnnealingWarmRestarts, -) -# To lower keys -optim_classes = {k.lower(): v for k, v in optim_classes.items()} -scheduler_classes = {k.lower(): v for k, v in scheduler_classes.items()} - - -@dataclass -class IteratorOptions: - preprocess_fn: callable - collate_fn: callable - data_path_and_name_and_type: list - shape_files: list - batch_size: int - batch_bins: int - batch_type: str - max_cache_size: float - max_cache_fd: int - distributed: bool - num_batches: Optional[int] - num_iters_per_epoch: Optional[int] - train: bool - - -class AbsTask(ABC): - # Use @staticmethod, or @classmethod, - # instead of instance method to avoid God classes - - # If you need more than one optimizers, change this value in inheritance - num_optimizers: int = 1 - trainer = Trainer - class_choices_list: List[ClassChoices] = [] - finetune_args: None - - def __init__(self): - raise RuntimeError("This class can't be instantiated.") - - @classmethod - @abstractmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - pass - - @classmethod - @abstractmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[[Sequence[Dict[str, np.ndarray]]], Dict[str, torch.Tensor]]: - """Return "collate_fn", which is a callable object and given to DataLoader. - - >>> from torch.utils.data import DataLoader - >>> loader = DataLoader(collate_fn=cls.build_collate_fn(args, train=True), ...) - - In many cases, you can use our common collate_fn. - """ - raise NotImplementedError - - @classmethod - @abstractmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - raise NotImplementedError - - @classmethod - @abstractmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - """Define the required names by Task - - This function is used by - >>> cls.check_task_requirements() - If your model is defined as following, - - >>> from funasr.models.base_model import FunASRModel - >>> class Model(FunASRModel): - ... def forward(self, input, output, opt=None): pass - - then "required_data_names" should be as - - >>> required_data_names = ('input', 'output') - """ - raise NotImplementedError - - @classmethod - @abstractmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - """Define the optional names by Task - - This function is used by - >>> cls.check_task_requirements() - If your model is defined as follows, - - >>> from funasr.models.base_model import FunASRModel - >>> class Model(FunASRModel): - ... def forward(self, input, output, opt=None): pass - - then "optional_data_names" should be as - - >>> optional_data_names = ('opt',) - """ - raise NotImplementedError - - @classmethod - @abstractmethod - def build_model(cls, args: argparse.Namespace) -> FunASRModel: - raise NotImplementedError - - - @classmethod - def get_parser(cls) -> config_argparse.ArgumentParser: - - class ArgumentDefaultsRawTextHelpFormatter( - argparse.RawTextHelpFormatter, - argparse.ArgumentDefaultsHelpFormatter, - ): - pass - - parser = config_argparse.ArgumentParser( - description="base parser", - formatter_class=ArgumentDefaultsRawTextHelpFormatter, - ) - - # NOTE(kamo): Use '_' instead of '-' to avoid confusion. - # I think '-' looks really confusing if it's written in yaml. - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - # parser.set_defaults(required=["output_dir"]) - - group = parser.add_argument_group("Common configuration") - - group.add_argument( - "--print_config", - action="store_true", - help="Print the config file and exit", - ) - group.add_argument( - "--log_level", - type=lambda x: x.upper(), - default="INFO", - choices=("ERROR", "WARNING", "INFO", "DEBUG", "NOTSET"), - help="The verbose level of logging", - ) - group.add_argument( - "--dry_run", - type=str2bool, - default=False, - help="Perform process without training", - ) - group.add_argument( - "--iterator_type", - type=str, - choices=["sequence", "chunk", "task", "none"], - default="sequence", - help="Specify iterator type", - ) - - group.add_argument("--output_dir", type=str_or_none, default=None) - group.add_argument( - "--ngpu", - type=int, - default=0, - help="The number of gpus. 0 indicates CPU mode", - ) - group.add_argument("--seed", type=int, default=0, help="Random seed") - group.add_argument( - "--num_workers", - type=int, - default=1, - help="The number of workers used for DataLoader", - ) - group.add_argument( - "--num_att_plot", - type=int, - default=3, - help="The number images to plot the outputs from attention. " - "This option makes sense only when attention-based model. " - "We can also disable the attention plot by setting it 0", - ) - - group = parser.add_argument_group("distributed training related") - group.add_argument( - "--dist_backend", - default="nccl", - type=str, - help="distributed backend", - ) - group.add_argument( - "--dist_init_method", - type=str, - default="env://", - help='if init_method="env://", env values of "MASTER_PORT", "MASTER_ADDR", ' - '"WORLD_SIZE", and "RANK" are referred.', - ) - group.add_argument( - "--dist_world_size", - default=None, - type=int_or_none, - help="number of nodes for distributed training", - ) - group.add_argument( - "--dist_rank", - type=int_or_none, - default=None, - help="node rank for distributed training", - ) - group.add_argument( - # Not starting with "dist_" for compatibility to launch.py - "--local_rank", - type=int_or_none, - default=None, - help="local rank for distributed training. This option is used if " - "--multiprocessing_distributed=false", - ) - group.add_argument( - "--dist_master_addr", - default=None, - type=str_or_none, - help="The master address for distributed training. " - "This value is used when dist_init_method == 'env://'", - ) - group.add_argument( - "--dist_master_port", - default=None, - type=int_or_none, - help="The master port for distributed training" - "This value is used when dist_init_method == 'env://'", - ) - group.add_argument( - "--dist_launcher", - default=None, - type=str_or_none, - choices=["slurm", "mpi", None], - help="The launcher type for distributed training", - ) - group.add_argument( - "--multiprocessing_distributed", - default=False, - type=str2bool, - help="Use multi-processing distributed training to launch " - "N processes per node, which has N GPUs. This is the " - "fastest way to use PyTorch for either single node or " - "multi node data parallel training", - ) - group.add_argument( - "--unused_parameters", - type=str2bool, - default=False, - help="Whether to use the find_unused_parameters in " - "torch.nn.parallel.DistributedDataParallel ", - ) - group.add_argument( - "--sharded_ddp", - default=False, - type=str2bool, - help="Enable sharded training provided by fairscale", - ) - - group = parser.add_argument_group("cudnn mode related") - group.add_argument( - "--cudnn_enabled", - type=str2bool, - default=torch.backends.cudnn.enabled, - help="Enable CUDNN", - ) - group.add_argument( - "--cudnn_benchmark", - type=str2bool, - default=torch.backends.cudnn.benchmark, - help="Enable cudnn-benchmark mode", - ) - group.add_argument( - "--cudnn_deterministic", - type=str2bool, - default=True, - help="Enable cudnn-deterministic mode", - ) - - group = parser.add_argument_group("collect stats mode related") - group.add_argument( - "--collect_stats", - type=str2bool, - default=False, - help='Perform on "collect stats" mode', - ) - group.add_argument( - "--mc", - type=bool, - default=False, - help="MultiChannel input", - ) - group.add_argument( - "--write_collected_feats", - type=str2bool, - default=False, - help='Write the output features from the model when "collect stats" mode', - ) - - group = parser.add_argument_group("Trainer related") - group.add_argument( - "--max_epoch", - type=int, - default=40, - help="The maximum number epoch to train", - ) - group.add_argument( - "--max_update", - type=int, - default=sys.maxsize, - help="The maximum number update step to train", - ) - parser.add_argument( - "--batch_interval", - type=int, - default=-1, - help="The batch interval for saving model.", - ) - group.add_argument( - "--patience", - type=int_or_none, - default=None, - help="Number of epochs to wait without improvement " - "before stopping the training", - ) - group.add_argument( - "--val_scheduler_criterion", - type=str, - nargs=2, - default=("valid", "loss"), - help="The criterion used for the value given to the lr scheduler. " - 'Give a pair referring the phase, "train" or "valid",' - 'and the criterion name. The mode specifying "min" or "max" can ' - "be changed by --scheduler_conf", - ) - group.add_argument( - "--early_stopping_criterion", - type=str, - nargs=3, - default=("valid", "loss", "min"), - help="The criterion used for judging of early stopping. " - 'Give a pair referring the phase, "train" or "valid",' - 'the criterion name and the mode, "min" or "max", e.g. "acc,max".', - ) - group.add_argument( - "--best_model_criterion", - type=str2triple_str, - nargs="+", - default=[ - ("train", "loss", "min"), - ("valid", "loss", "min"), - ("train", "acc", "max"), - ("valid", "acc", "max"), - ], - help="The criterion used for judging of the best model. " - 'Give a pair referring the phase, "train" or "valid",' - 'the criterion name, and the mode, "min" or "max", e.g. "acc,max".', - ) - group.add_argument( - "--keep_nbest_models", - type=int, - nargs="+", - default=[10], - help="Remove previous snapshots excluding the n-best scored epochs", - ) - group.add_argument( - "--nbest_averaging_interval", - type=int, - default=0, - help="The epoch interval to apply model averaging and save nbest models", - ) - group.add_argument( - "--grad_clip", - type=float, - default=5.0, - help="Gradient norm threshold to clip", - ) - group.add_argument( - "--grad_clip_type", - type=float, - default=2.0, - help="The type of the used p-norm for gradient clip. Can be inf", - ) - group.add_argument( - "--grad_noise", - type=str2bool, - default=False, - help="The flag to switch to use noise injection to " - "gradients during training", - ) - group.add_argument( - "--accum_grad", - type=int, - default=1, - help="The number of gradient accumulation", - ) - group.add_argument( - "--bias_grad_times", - type=float, - default=1.0, - help="To scale the gradient of contextual related params", - ) - group.add_argument( - "--no_forward_run", - type=str2bool, - default=False, - help="Just only iterating data loading without " - "model forwarding and training", - ) - group.add_argument( - "--resume", - type=str2bool, - default=False, - help="Enable resuming if checkpoint is existing", - ) - group.add_argument( - "--train_dtype", - default="float32", - choices=["float16", "float32", "float64"], - help="Data type for training.", - ) - group.add_argument( - "--use_amp", - type=str2bool, - default=False, - help="Enable Automatic Mixed Precision. This feature requires pytorch>=1.6", - ) - group.add_argument( - "--log_interval", - type=int_or_none, - default=None, - help="Show the logs every the number iterations in each epochs at the " - "training phase. If None is given, it is decided according the number " - "of training samples automatically .", - ) - group.add_argument( - "--use_tensorboard", - type=str2bool, - default=True, - help="Enable tensorboard logging", - ) - group.add_argument( - "--use_wandb", - type=str2bool, - default=False, - help="Enable wandb logging", - ) - group.add_argument( - "--wandb_project", - type=str, - default=None, - help="Specify wandb project", - ) - group.add_argument( - "--wandb_id", - type=str, - default=None, - help="Specify wandb id", - ) - group.add_argument( - "--wandb_entity", - type=str, - default=None, - help="Specify wandb entity", - ) - group.add_argument( - "--wandb_name", - type=str, - default=None, - help="Specify wandb run name", - ) - group.add_argument( - "--wandb_model_log_interval", - type=int, - default=-1, - help="Set the model log period", - ) - group.add_argument( - "--detect_anomaly", - type=str2bool, - default=False, - help="Set torch.autograd.set_detect_anomaly", - ) - - group = parser.add_argument_group("Pretraining model related") - group.add_argument("--pretrain_path", help="This option is obsoleted") - group.add_argument( - "--init_param", - type=str, - action="append", - default=[], - help="Specify the file path used for initialization of parameters. " - "The format is ':::', " - "where file_path is the model file path, " - "src_key specifies the key of model states to be used in the model file, " - "dst_key specifies the attribute of the model to be initialized, " - "and exclude_keys excludes keys of model states for the initialization." - "e.g.\n" - " # Load all parameters" - " --init_param some/where/model.pb\n" - " # Load only decoder parameters" - " --init_param some/where/model.pb:decoder:decoder\n" - " # Load only decoder parameters excluding decoder.embed" - " --init_param some/where/model.pb:decoder:decoder:decoder.embed\n" - " --init_param some/where/model.pb:decoder:decoder:decoder.embed\n", - ) - group.add_argument( - "--ignore_init_mismatch", - type=str2bool, - default=False, - help="Ignore size mismatch when loading pre-trained model", - ) - group.add_argument( - "--freeze_param", - type=str, - default=[], - action="append", - help="Freeze parameters", - ) - - group = parser.add_argument_group("BatchSampler related") - group.add_argument( - "--num_iters_per_epoch", - type=int_or_none, - default=None, - help="Restrict the number of iterations for training per epoch", - ) - group.add_argument( - "--batch_size", - type=int, - default=20, - help="The mini-batch size used for training. Used if batch_type='unsorted'," - " 'sorted', or 'folded'.", - ) - group.add_argument( - "--valid_batch_size", - type=int_or_none, - default=None, - help="If not given, the value of --batch_size is used", - ) - group.add_argument( - "--batch_bins", - type=int, - default=1000000, - help="The number of batch bins. Used if batch_type='length' or 'numel'", - ) - group.add_argument( - "--valid_batch_bins", - type=int_or_none, - default=None, - help="If not given, the value of --batch_bins is used", - ) - - group.add_argument("--train_shape_file", type=str, action="append", default=[]) - group.add_argument("--valid_shape_file", type=str, action="append", default=[]) - - group = parser.add_argument_group("Sequence iterator related") - _batch_type_help = "" - for key, value in BATCH_TYPES.items(): - _batch_type_help += f'"{key}":\n{value}\n' - group.add_argument( - "--batch_type", - type=str, - default="length", - choices=list(BATCH_TYPES), - help=_batch_type_help, - ) - group.add_argument( - "--valid_batch_type", - type=str_or_none, - default=None, - choices=list(BATCH_TYPES) + [None], - help="If not given, the value of --batch_type is used", - ) - group.add_argument( - "--speech_length_min", - type=int, - default=-1, - help="speech length min", - ) - group.add_argument( - "--speech_length_max", - type=int, - default=-1, - help="speech length max", - ) - group.add_argument("--fold_length", type=int, action="append", default=[]) - group.add_argument( - "--sort_in_batch", - type=str, - default="descending", - choices=["descending", "ascending"], - help="Sort the samples in each mini-batches by the sample " - 'lengths. To enable this, "shape_file" must have the length information.', - ) - group.add_argument( - "--sort_batch", - type=str, - default="descending", - choices=["descending", "ascending"], - help="Sort mini-batches by the sample lengths", - ) - group.add_argument( - "--multiple_iterator", - type=str2bool, - default=False, - help="Use multiple iterator mode", - ) - - group = parser.add_argument_group("Chunk iterator related") - group.add_argument( - "--chunk_length", - type=str_or_int, - default=500, - help="Specify chunk length. e.g. '300', '300,400,500', or '300-400'." - "If multiple numbers separated by command are given, " - "one of them is selected randomly for each samples. " - "If two numbers are given with '-', it indicates the range of the choices. " - "Note that if the sequence length is shorter than the all chunk_lengths, " - "the sample is discarded. ", - ) - group.add_argument( - "--chunk_shift_ratio", - type=float, - default=0.5, - help="Specify the shift width of chunks. If it's less than 1, " - "allows the overlapping and if bigger than 1, there are some gaps " - "between each chunk.", - ) - group.add_argument( - "--num_cache_chunks", - type=int, - default=1024, - help="Shuffle in the specified number of chunks and generate mini-batches " - "More larger this value, more randomness can be obtained.", - ) - - group = parser.add_argument_group("Dataset related") - _data_path_and_name_and_type_help = ( - "Give three words splitted by comma. It's used for the training data. " - "e.g. '--train_data_path_and_name_and_type some/path/a.scp,foo,sound'. " - "The first value, some/path/a.scp, indicates the file path, " - "and the second, foo, is the key name used for the mini-batch data, " - "and the last, sound, decides the file type. " - "This option is repeatable, so you can input any number of features " - "for your task. Supported file types are as follows:\n\n" - ) - for key, dic in DATA_TYPES.items(): - _data_path_and_name_and_type_help += f'"{key}":\n{dic["help"]}\n\n' - - # for large dataset - group.add_argument( - "--dataset_type", - type=str, - default="small", - help="whether to use dataloader for large dataset", - ) - parser.add_argument( - "--dataset_conf", - action=NestedDictAction, - default=dict(), - help=f"The keyword arguments for dataset", - ) - group.add_argument( - "--train_data_file", - type=str, - default=None, - help="train_list for large dataset", - ) - group.add_argument( - "--valid_data_file", - type=str, - default=None, - help="valid_list for large dataset", - ) - - group.add_argument( - "--train_data_path_and_name_and_type", - type=str2triple_str, - action="append", - default=[], - help=_data_path_and_name_and_type_help, - ) - group.add_argument( - "--valid_data_path_and_name_and_type", - type=str2triple_str, - action="append", - default=[], - ) - group.add_argument( - "--allow_variable_data_keys", - type=str2bool, - default=False, - help="Allow the arbitrary keys for mini-batch with ignoring " - "the task requirements", - ) - group.add_argument( - "--max_cache_size", - type=humanfriendly.parse_size, - default=0.0, - help="The maximum cache size for data loader. e.g. 10MB, 20GB.", - ) - group.add_argument( - "--max_cache_fd", - type=int, - default=32, - help="The maximum number of file descriptors to be kept " - "as opened for ark files. " - "This feature is only valid when data type is 'kaldi_ark'.", - ) - group.add_argument( - "--valid_max_cache_size", - type=humanfriendly_parse_size_or_none, - default=None, - help="The maximum cache size for validation data loader. e.g. 10MB, 20GB. " - "If None, the 5 percent size of --max_cache_size", - ) - - group = parser.add_argument_group("Optimizer related") - for i in range(1, cls.num_optimizers + 1): - suf = "" if i == 1 else str(i) - group.add_argument( - f"--optim{suf}", - type=lambda x: x.lower(), - default="adadelta", - choices=list(optim_classes), - help="The optimizer type", - ) - group.add_argument( - f"--optim{suf}_conf", - action=NestedDictAction, - default=dict(), - help="The keyword arguments for optimizer", - ) - group.add_argument( - f"--scheduler{suf}", - type=lambda x: str_or_none(x.lower()), - default=None, - choices=list(scheduler_classes) + [None], - help="The lr scheduler type", - ) - group.add_argument( - f"--scheduler{suf}_conf", - action=NestedDictAction, - default=dict(), - help="The keyword arguments for lr scheduler", - ) - - # for training on PAI - group = parser.add_argument_group("PAI training related") - group.add_argument( - "--use_pai", - type=str2bool, - default=False, - help="flag to indicate whether training on PAI", - ) - group.add_argument( - "--simple_ddp", - type=str2bool, - default=False, - ) - group.add_argument( - "--num_worker_count", - type=int, - default=1, - help="The number of machines on PAI.", - ) - group.add_argument( - "--access_key_id", - type=str, - default=None, - help="The username for oss.", - ) - group.add_argument( - "--access_key_secret", - type=str, - default=None, - help="The password for oss.", - ) - group.add_argument( - "--endpoint", - type=str, - default=None, - help="The endpoint for oss.", - ) - group.add_argument( - "--bucket_name", - type=str, - default=None, - help="The bucket name for oss.", - ) - group.add_argument( - "--oss_bucket", - default=None, - help="oss bucket.", - ) - group.add_argument( - "--enable_lora", - type=str2bool, - default=False, - help="Apply lora for finetuning.", - ) - group.add_argument( - "--lora_bias", - type=str, - default="none", - help="lora bias.", - ) - - cls.trainer.add_arguments(parser) - cls.add_task_arguments(parser) - - return parser - - @classmethod - def build_optimizers( - cls, - args: argparse.Namespace, - model: torch.nn.Module, - ) -> List[torch.optim.Optimizer]: - if cls.num_optimizers != 1: - raise RuntimeError( - "build_optimizers() must be overridden if num_optimizers != 1" - ) - - optim_class = optim_classes.get(args.optim) - if optim_class is None: - raise ValueError(f"must be one of {list(optim_classes)}: {args.optim}") - if args.sharded_ddp: - if fairscale is None: - raise RuntimeError("Requiring fairscale. Do 'pip install fairscale'") - optim = fairscale.optim.oss.OSS( - params=model.parameters(), optim=optim_class, **args.optim_conf - ) - else: - optim = optim_class(model.parameters(), **args.optim_conf) - - optimizers = [optim] - return optimizers - - @classmethod - def exclude_opts(cls) -> Tuple[str, ...]: - """The options not to be shown by --print_config""" - return "required", "print_config", "config", "ngpu" - - @classmethod - def get_default_config(cls) -> Dict[str, Any]: - """Return the configuration as dict. - - This method is used by print_config() - """ - - def get_class_type(name: str, classes: dict): - _cls = classes.get(name) - if _cls is None: - raise ValueError(f"must be one of {list(classes)}: {name}") - return _cls - - # This method is used only for --print_config - parser = cls.get_parser() - args, _ = parser.parse_known_args() - config = vars(args) - # Excludes the options not to be shown - for k in AbsTask.exclude_opts(): - config.pop(k) - - for i in range(1, cls.num_optimizers + 1): - suf = "" if i == 1 else str(i) - name = config[f"optim{suf}"] - optim_class = get_class_type(name, optim_classes) - conf = get_default_kwargs(optim_class) - # Overwrite the default by the arguments, - conf.update(config[f"optim{suf}_conf"]) - # and set it again - config[f"optim{suf}_conf"] = conf - - name = config[f"scheduler{suf}"] - if name is not None: - scheduler_class = get_class_type(name, scheduler_classes) - conf = get_default_kwargs(scheduler_class) - # Overwrite the default by the arguments, - conf.update(config[f"scheduler{suf}_conf"]) - # and set it again - config[f"scheduler{suf}_conf"] = conf - - for class_choices in cls.class_choices_list: - if getattr(args, class_choices.name) is not None: - class_obj = class_choices.get_class(getattr(args, class_choices.name)) - conf = get_default_kwargs(class_obj) - name = class_choices.name - # Overwrite the default by the arguments, - conf.update(config[f"{name}_conf"]) - # and set it again - config[f"{name}_conf"] = conf - return config - - @classmethod - def check_required_command_args(cls, args: argparse.Namespace): - if hasattr(args, "required"): - for k in vars(args): - if "-" in k: - raise RuntimeError(f'Use "_" instead of "-": parser.get_parser("{k}")') - - required = ", ".join( - f"--{a}" for a in args.required if getattr(args, a) is None - ) - - if len(required) != 0: - parser = cls.get_parser() - parser.print_help(file=sys.stderr) - p = Path(sys.argv[0]).name - print(file=sys.stderr) - print( - f"{p}: error: the following arguments are required: " f"{required}", - file=sys.stderr, - ) - sys.exit(2) - - @classmethod - def check_task_requirements( - cls, - dataset: Union[AbsDataset, IterableESPnetDataset], - allow_variable_data_keys: bool, - train: bool, - inference: bool = False, - ) -> None: - """Check if the dataset satisfy the requirement of current Task""" - mes = ( - f"If you intend to use an additional input, modify " - f'"{cls.__name__}.required_data_names()" or ' - f'"{cls.__name__}.optional_data_names()". ' - f"Otherwise you need to set --allow_variable_data_keys true " - ) - - for k in cls.required_data_names(train, inference): - if not dataset.has_name(k): - raise RuntimeError( - f'"{cls.required_data_names(train, inference)}" are required for' - f' {cls.__name__}. but "{dataset.names()}" are input.\n{mes}' - ) - if not allow_variable_data_keys: - task_keys = cls.required_data_names( - train, inference - ) + cls.optional_data_names(train, inference) - for k in dataset.names(): - if k not in task_keys: - raise RuntimeError( - f"The data-name must be one of {task_keys} " - f'for {cls.__name__}: "{k}" is not allowed.\n{mes}' - ) - - @classmethod - def print_config(cls, file=sys.stdout) -> None: - # Shows the config: e.g. python train.py asr --print_config - config = cls.get_default_config() - file.write(yaml_no_alias_safe_dump(config, indent=4, sort_keys=False)) - - @classmethod - def main(cls, args: argparse.Namespace = None, cmd: Sequence[str] = None): - print(get_commandline_args(), file=sys.stderr) - if args is None: - parser = cls.get_parser() - args = parser.parse_args(cmd) - args.version = __version__ - if args.pretrain_path is not None: - raise RuntimeError("--pretrain_path is deprecated. Use --init_param") - if args.print_config: - cls.print_config() - sys.exit(0) - cls.check_required_command_args(args) - - if not args.distributed or not args.multiprocessing_distributed: - cls.main_worker(args) - else: - assert args.ngpu > 1 - cls.main_worker(args) - - @classmethod - def run(cls): - assert hasattr(cls, "finetune_args") - args = cls.finetune_args - args.train_shape_file = None - if args.distributed: - args.simple_ddp = True - else: - args.simple_ddp = False - args.ngpu = 1 - args.use_pai = False - args.batch_type = "length" - args.oss_bucket = None - args.input_size = None - cls.main_worker(args) - - @classmethod - def main_worker(cls, args: argparse.Namespace): - - # 0. Init distributed process - distributed_option = build_dataclass(DistributedOption, args) - # Setting distributed_option.dist_rank, etc. - if args.use_pai: - distributed_option.init_options_pai() - elif not args.simple_ddp: - distributed_option.init_options() - - # Invoking torch.distributed.init_process_group - if args.use_pai: - distributed_option.init_torch_distributed_pai(args) - elif not args.simple_ddp: - distributed_option.init_torch_distributed(args) - elif args.distributed and args.simple_ddp: - distributed_option.init_torch_distributed_pai(args) - args.ngpu = dist.get_world_size() - if args.dataset_type == "small" and args.ngpu > 0: - if args.batch_size is not None: - args.batch_size = args.batch_size * args.ngpu - if args.batch_bins is not None and args.ngpu > 0: - args.batch_bins = args.batch_bins * args.ngpu - - # filter samples if wav.scp and text are mismatch - if ( - args.train_shape_file is None and args.dataset_type == "small") or args.train_data_file is None and args.dataset_type == "large": - if not args.simple_ddp or distributed_option.dist_rank == 0: - filter_wav_text(args.data_dir, args.train_set) - filter_wav_text(args.data_dir, args.dev_set) - if args.simple_ddp: - dist.barrier() - - if args.train_shape_file is None and args.dataset_type == "small": - if not args.simple_ddp or distributed_option.dist_rank == 0: - calc_shape(args.data_dir, args.train_set, args.frontend_conf, args.speech_length_min, - args.speech_length_max) - calc_shape(args.data_dir, args.dev_set, args.frontend_conf, args.speech_length_min, - args.speech_length_max) - if args.simple_ddp: - dist.barrier() - args.train_shape_file = [os.path.join(args.data_dir, args.train_set, "speech_shape")] - args.valid_shape_file = [os.path.join(args.data_dir, args.dev_set, "speech_shape")] - - if args.train_data_file is None and args.dataset_type == "large": - if not args.simple_ddp or distributed_option.dist_rank == 0: - generate_data_list(args.data_dir, args.train_set) - generate_data_list(args.data_dir, args.dev_set) - if args.simple_ddp: - dist.barrier() - args.train_data_file = os.path.join(args.data_dir, args.train_set, "data.list") - args.valid_data_file = os.path.join(args.data_dir, args.dev_set, "data.list") - - # NOTE(kamo): Don't use logging before invoking logging.basicConfig() - if not distributed_option.distributed or distributed_option.dist_rank == 0: - if not distributed_option.distributed: - _rank = "" - else: - _rank = ( - f":{distributed_option.dist_rank}/" - f"{distributed_option.dist_world_size}" - ) - - # NOTE(kamo): - # logging.basicConfig() is invoked in main_worker() instead of main() - # because it can be invoked only once in a process. - # FIXME(kamo): Should we use logging.getLogger()? - # BUGFIX: Remove previous handlers and reset log level - for handler in logging.root.handlers[:]: - logging.root.removeHandler(handler) - logging.basicConfig( - level=args.log_level, - format=f"[{os.uname()[1].split('.')[0]}]" - f" %(asctime)s (%(module)s:%(lineno)d) %(levelname)s: %(message)s", - ) - else: - # BUGFIX: Remove previous handlers and reset log level - for handler in logging.root.handlers[:]: - logging.root.removeHandler(handler) - # Suppress logging if RANK != 0 - logging.basicConfig( - level="ERROR", - format=f"[{os.uname()[1].split('.')[0]}]" - f" %(asctime)s (%(module)s:%(lineno)d) %(levelname)s: %(message)s", - ) - logging.info("world size: {}, rank: {}, local_rank: {}".format(distributed_option.dist_world_size, - distributed_option.dist_rank, - distributed_option.local_rank)) - - # 1. Set random-seed - set_all_random_seed(args.seed) - torch.backends.cudnn.enabled = args.cudnn_enabled - torch.backends.cudnn.benchmark = args.cudnn_benchmark - torch.backends.cudnn.deterministic = args.cudnn_deterministic - if args.detect_anomaly: - logging.info("Invoking torch.autograd.set_detect_anomaly(True)") - torch.autograd.set_detect_anomaly(args.detect_anomaly) - - # 2. Build model - model = cls.build_model(args=args) - if not isinstance(model, FunASRModel): - raise RuntimeError( - f"model must inherit {FunASRModel.__name__}, but got {type(model)}" - ) - model = model.to( - dtype=getattr(torch, args.train_dtype), - device="cuda" if args.ngpu > 0 else "cpu", - ) - if args.enable_lora: - mark_only_lora_as_trainable(model, args.lora_bias) - for t in args.freeze_param: - for k, p in model.named_parameters(): - if k.startswith(t + ".") or k == t: - logging.info(f"Setting {k}.requires_grad = False") - p.requires_grad = False - - # 3. Build optimizer - optimizers = cls.build_optimizers(args, model=model) - - # 4. Build schedulers - schedulers = [] - for i, optim in enumerate(optimizers, 1): - suf = "" if i == 1 else str(i) - name = getattr(args, f"scheduler{suf}") - conf = getattr(args, f"scheduler{suf}_conf") - if name is not None: - cls_ = scheduler_classes.get(name) - if cls_ is None: - raise ValueError( - f"must be one of {list(scheduler_classes)}: {name}" - ) - scheduler = cls_(optim, **conf) - else: - scheduler = None - - schedulers.append(scheduler) - - logging.info(pytorch_cudnn_version()) - logging.info(model_summary(model)) - for i, (o, s) in enumerate(zip(optimizers, schedulers), 1): - suf = "" if i == 1 else str(i) - logging.info(f"Optimizer{suf}:\n{o}") - logging.info(f"Scheduler{suf}: {s}") - - # 5. Dump "args" to config.yaml - # NOTE(kamo): "args" should be saved after object-buildings are done - # because they are allowed to modify "args". - output_dir = Path(args.output_dir) - if not distributed_option.distributed or distributed_option.dist_rank == 0: - output_dir.mkdir(parents=True, exist_ok=True) - with (output_dir / "config.yaml").open("w", encoding="utf-8") as f: - logging.info( - f'Saving the configuration in {output_dir / "config.yaml"}' - ) - if args.use_pai: - buffer = BytesIO() - torch.save({"config": vars(args)}, buffer) - args.oss_bucket.put_object(os.path.join(args.output_dir, "config.dict"), buffer.getvalue()) - else: - yaml_no_alias_safe_dump(vars(args), f, indent=4, sort_keys=False) - - if args.dry_run: - pass - elif args.collect_stats: - # Perform on collect_stats mode. This mode has two roles - # - Derive the length and dimension of all input data - # - Accumulate feats, square values, and the length for whitening - - if args.valid_batch_size is None: - args.valid_batch_size = args.batch_size - - if len(args.train_shape_file) != 0: - train_key_file = args.train_shape_file[0] - else: - train_key_file = None - if len(args.valid_shape_file) != 0: - valid_key_file = args.valid_shape_file[0] - else: - valid_key_file = None - - collect_stats( - model=model, - train_iter=cls.build_streaming_iterator( - data_path_and_name_and_type=args.train_data_path_and_name_and_type, - key_file=train_key_file, - batch_size=args.batch_size, - mc=args.mc, - dtype=args.train_dtype, - num_workers=args.num_workers, - allow_variable_data_keys=args.allow_variable_data_keys, - ngpu=args.ngpu, - preprocess_fn=cls.build_preprocess_fn(args, train=False), - collate_fn=cls.build_collate_fn(args, train=False), - ), - valid_iter=cls.build_streaming_iterator( - data_path_and_name_and_type=args.valid_data_path_and_name_and_type, - key_file=valid_key_file, - batch_size=args.valid_batch_size, - mc=args.mc, - dtype=args.train_dtype, - num_workers=args.num_workers, - allow_variable_data_keys=args.allow_variable_data_keys, - ngpu=args.ngpu, - preprocess_fn=cls.build_preprocess_fn(args, train=False), - collate_fn=cls.build_collate_fn(args, train=False), - ), - output_dir=output_dir, - ngpu=args.ngpu, - log_interval=args.log_interval, - write_collected_feats=args.write_collected_feats, - ) - else: - logging.info("Training args: {}".format(args)) - # 6. Loads pre-trained model - for p in args.init_param: - logging.info(f"Loading pretrained params from {p}") - load_pretrained_model( - model=model, - init_param=p, - ignore_init_mismatch=args.ignore_init_mismatch, - # NOTE(kamo): "cuda" for torch.load always indicates cuda:0 - # in PyTorch<=1.4 - map_location=f"cuda:{torch.cuda.current_device()}" - if args.ngpu > 0 - else "cpu", - oss_bucket=args.oss_bucket, - ) - - # 7. Build iterator factories - if args.dataset_type == "large": - from funasr.datasets.large_datasets.build_dataloader import LargeDataLoader - train_iter_factory = LargeDataLoader(args, mode="train") - valid_iter_factory = LargeDataLoader(args, mode="eval") - - elif args.dataset_type == "small": - train_iter_factory = cls.build_iter_factory( - args=args, - distributed_option=distributed_option, - mode="train", - ) - valid_iter_factory = cls.build_iter_factory( - args=args, - distributed_option=distributed_option, - mode="valid", - ) - else: - raise ValueError(f"Not supported dataset_type={args.dataset_type}") - - if args.scheduler == "tri_stage": - for scheduler in schedulers: - scheduler.init_tri_stage_scheudler(max_update=args.max_update) - - # 8. Start training - if args.use_wandb: - if wandb is None: - raise RuntimeError("Please install wandb") - - try: - wandb.login() - except wandb.errors.UsageError: - logging.info("wandb not configured! run `wandb login` to enable") - args.use_wandb = False - - if args.use_wandb: - if ( - not distributed_option.distributed - or distributed_option.dist_rank == 0 - ): - if args.wandb_project is None: - project = "FunASR_" + cls.__name__ - else: - project = args.wandb_project - - if args.wandb_name is None: - name = str(Path(".").resolve()).replace("/", "_") - else: - name = args.wandb_name - - wandb.init( - entity=args.wandb_entity, - project=project, - name=name, - dir=output_dir, - id=args.wandb_id, - resume="allow", - ) - wandb.config.update(args) - else: - # wandb also supports grouping for distributed training, - # but we only logs aggregated data, - # so it's enough to perform on rank0 node. - args.use_wandb = False - - # Don't give args to trainer.run() directly!!! - # Instead of it, define "Options" object and build here. - trainer_options = cls.trainer.build_options(args) - cls.trainer.run( - model=model, - optimizers=optimizers, - schedulers=schedulers, - train_iter_factory=train_iter_factory, - valid_iter_factory=valid_iter_factory, - trainer_options=trainer_options, - distributed_option=distributed_option, - ) - - if args.use_wandb and wandb.run: - wandb.finish() - - @classmethod - def build_iter_options( - cls, - args: argparse.Namespace, - distributed_option: DistributedOption, - mode: str, - ): - if mode == "train": - preprocess_fn = cls.build_preprocess_fn(args, train=True) - collate_fn = cls.build_collate_fn(args, train=True) - data_path_and_name_and_type = args.train_data_path_and_name_and_type - shape_files = args.train_shape_file - batch_size = args.batch_size - batch_bins = args.batch_bins - batch_type = args.batch_type - max_cache_size = args.max_cache_size - max_cache_fd = args.max_cache_fd - distributed = distributed_option.distributed - num_batches = None - num_iters_per_epoch = args.num_iters_per_epoch - train = True - - elif mode == "valid": - preprocess_fn = cls.build_preprocess_fn(args, train=False) - collate_fn = cls.build_collate_fn(args, train=False) - data_path_and_name_and_type = args.valid_data_path_and_name_and_type - shape_files = args.valid_shape_file - - if args.valid_batch_type is None: - batch_type = args.batch_type - else: - batch_type = args.valid_batch_type - if args.valid_batch_size is None: - batch_size = args.batch_size - else: - batch_size = args.valid_batch_size - if args.valid_batch_bins is None: - batch_bins = args.batch_bins - else: - batch_bins = args.valid_batch_bins - if args.valid_max_cache_size is None: - # Cache 5% of maximum size for validation loader - max_cache_size = 0.05 * args.max_cache_size - else: - max_cache_size = args.valid_max_cache_size - max_cache_fd = args.max_cache_fd - distributed = distributed_option.distributed - num_batches = None - num_iters_per_epoch = None - train = False - else: - raise NotImplementedError(f"mode={mode}") - - return IteratorOptions( - preprocess_fn=preprocess_fn, - collate_fn=collate_fn, - data_path_and_name_and_type=data_path_and_name_and_type, - shape_files=shape_files, - batch_type=batch_type, - batch_size=batch_size, - batch_bins=batch_bins, - num_batches=num_batches, - max_cache_size=max_cache_size, - max_cache_fd=max_cache_fd, - distributed=distributed, - num_iters_per_epoch=num_iters_per_epoch, - train=train, - ) - - @classmethod - def build_iter_factory( - cls, - args: argparse.Namespace, - distributed_option: DistributedOption, - mode: str, - kwargs: dict = None, - ) -> AbsIterFactory: - """Build a factory object of mini-batch iterator. - - This object is invoked at every epochs to build the iterator for each epoch - as following: - - >>> iter_factory = cls.build_iter_factory(...) - >>> for epoch in range(1, max_epoch): - ... for keys, batch in iter_fatory.build_iter(epoch): - ... model(**batch) - - The mini-batches for each epochs are fully controlled by this class. - Note that the random seed used for shuffling is decided as "seed + epoch" and - the generated mini-batches can be reproduces when resuming. - - Note that the definition of "epoch" doesn't always indicate - to run out of the whole training corpus. - "--num_iters_per_epoch" option restricts the number of iterations for each epoch - and the rest of samples for the originally epoch are left for the next epoch. - e.g. If The number of mini-batches equals to 4, the following two are same: - - - 1 epoch without "--num_iters_per_epoch" - - 4 epoch with "--num_iters_per_epoch" == 4 - - """ - iter_options = cls.build_iter_options(args, distributed_option, mode) - - # Overwrite iter_options if any kwargs is given - if kwargs is not None: - for k, v in kwargs.items(): - setattr(iter_options, k, v) - - if args.iterator_type == "sequence": - return cls.build_sequence_iter_factory( - args=args, - iter_options=iter_options, - mode=mode, - ) - elif args.iterator_type == "chunk": - return cls.build_chunk_iter_factory( - args=args, - iter_options=iter_options, - mode=mode, - ) - elif args.iterator_type == "task": - return cls.build_task_iter_factory( - args=args, - iter_options=iter_options, - mode=mode, - ) - else: - raise RuntimeError(f"Not supported: iterator_type={args.iterator_type}") - - @classmethod - def build_sequence_iter_factory( - cls, args: argparse.Namespace, iter_options: IteratorOptions, mode: str - ) -> AbsIterFactory: - - if hasattr(args, "frontend_conf"): - if args.frontend_conf is not None and "fs" in args.frontend_conf: - dest_sample_rate = args.frontend_conf["fs"] - else: - dest_sample_rate = 16000 - else: - dest_sample_rate = 16000 - - dataset = ESPnetDataset( - iter_options.data_path_and_name_and_type, - float_dtype=args.train_dtype, - preprocess=iter_options.preprocess_fn, - max_cache_size=iter_options.max_cache_size, - max_cache_fd=iter_options.max_cache_fd, - dest_sample_rate=dest_sample_rate, - ) - cls.check_task_requirements( - dataset, args.allow_variable_data_keys, train=iter_options.train - ) - - if Path( - Path(iter_options.data_path_and_name_and_type[0][0]).parent, "utt2category" - ).exists(): - utt2category_file = str( - Path( - Path(iter_options.data_path_and_name_and_type[0][0]).parent, - "utt2category", - ) - ) - else: - utt2category_file = None - batch_sampler = build_batch_sampler( - type=iter_options.batch_type, - shape_files=iter_options.shape_files, - fold_lengths=args.fold_length, - batch_size=iter_options.batch_size, - batch_bins=iter_options.batch_bins, - sort_in_batch=args.sort_in_batch, - sort_batch=args.sort_batch, - drop_last=False, - min_batch_size=torch.distributed.get_world_size() - if iter_options.distributed - else 1, - utt2category_file=utt2category_file, - ) - - batches = list(batch_sampler) - if iter_options.num_batches is not None: - batches = batches[: iter_options.num_batches] - - bs_list = [len(batch) for batch in batches] - - logging.info(f"[{mode}] dataset:\n{dataset}") - logging.info(f"[{mode}] Batch sampler: {batch_sampler}") - logging.info( - f"[{mode}] mini-batch sizes summary: N-batch={len(bs_list)}, " - f"mean={np.mean(bs_list):.1f}, min={np.min(bs_list)}, max={np.max(bs_list)}" - ) - - if args.scheduler == "tri_stage" and mode == "train": - args.max_update = len(bs_list) * args.max_epoch - logging.info("Max update: {}".format(args.max_update)) - - if iter_options.distributed: - world_size = torch.distributed.get_world_size() - rank = torch.distributed.get_rank() - for batch in batches: - if len(batch) < world_size: - raise RuntimeError( - f"The batch-size must be equal or more than world_size: " - f"{len(batch)} < {world_size}" - ) - batches = [batch[rank::world_size] for batch in batches] - - return SequenceIterFactory( - dataset=dataset, - batches=batches, - seed=args.seed, - num_iters_per_epoch=iter_options.num_iters_per_epoch, - shuffle=iter_options.train, - num_workers=args.num_workers, - collate_fn=iter_options.collate_fn, - pin_memory=args.ngpu > 0, - ) - - @classmethod - def build_chunk_iter_factory( - cls, - args: argparse.Namespace, - iter_options: IteratorOptions, - mode: str, - ) -> AbsIterFactory: - - dataset = ESPnetDataset( - iter_options.data_path_and_name_and_type, - float_dtype=args.train_dtype, - preprocess=iter_options.preprocess_fn, - max_cache_size=iter_options.max_cache_size, - max_cache_fd=iter_options.max_cache_fd, - ) - cls.check_task_requirements( - dataset, args.allow_variable_data_keys, train=iter_options.train - ) - - if len(iter_options.shape_files) == 0: - key_file = iter_options.data_path_and_name_and_type[0][0] - else: - key_file = iter_options.shape_files[0] - - batch_sampler = UnsortedBatchSampler(batch_size=1, key_file=key_file) - batches = list(batch_sampler) - if iter_options.num_batches is not None: - batches = batches[: iter_options.num_batches] - logging.info(f"[{mode}] dataset:\n{dataset}") - - if iter_options.distributed: - world_size = torch.distributed.get_world_size() - rank = torch.distributed.get_rank() - if len(batches) < world_size: - raise RuntimeError("Number of samples is smaller than world_size") - if iter_options.batch_size < world_size: - raise RuntimeError("batch_size must be equal or more than world_size") - - if rank < iter_options.batch_size % world_size: - batch_size = iter_options.batch_size // world_size + 1 - else: - batch_size = iter_options.batch_size // world_size - num_cache_chunks = args.num_cache_chunks // world_size - # NOTE(kamo): Split whole corpus by sample numbers without considering - # each of the lengths, therefore the number of iteration counts are not - # always equal to each other and the iterations are limitted - # by the fewest iterations. - # i.e. the samples over the counts are discarded. - batches = batches[rank::world_size] - else: - batch_size = iter_options.batch_size - num_cache_chunks = args.num_cache_chunks - - return ChunkIterFactory( - dataset=dataset, - batches=batches, - seed=args.seed, - batch_size=batch_size, - # For chunk iterator, - # --num_iters_per_epoch doesn't indicate the number of iterations, - # but indicates the number of samples. - num_samples_per_epoch=iter_options.num_iters_per_epoch, - shuffle=iter_options.train, - num_workers=args.num_workers, - collate_fn=iter_options.collate_fn, - pin_memory=args.ngpu > 0, - chunk_length=args.chunk_length, - chunk_shift_ratio=args.chunk_shift_ratio, - num_cache_chunks=num_cache_chunks, - ) - - # NOTE(kamo): Not abstract class - @classmethod - def build_task_iter_factory( - cls, - args: argparse.Namespace, - iter_options: IteratorOptions, - mode: str, - ) -> AbsIterFactory: - """Build task specific iterator factory - - Example: - - >>> class YourTask(AbsTask): - ... @classmethod - ... def add_task_arguments(cls, parser: argparse.ArgumentParser): - ... parser.set_defaults(iterator_type="task") - ... - ... @classmethod - ... def build_task_iter_factory( - ... cls, - ... args: argparse.Namespace, - ... iter_options: IteratorOptions, - ... mode: str, - ... ): - ... return FooIterFactory(...) - ... - ... @classmethod - ... def build_iter_options( - .... args: argparse.Namespace, - ... distributed_option: DistributedOption, - ... mode: str - ... ): - ... # if you need to customize options object - """ - raise NotImplementedError - - @classmethod - def build_multiple_iter_factory( - cls, args: argparse.Namespace, distributed_option: DistributedOption, mode: str - ): - iter_options = cls.build_iter_options(args, distributed_option, mode) - assert len(iter_options.data_path_and_name_and_type) > 0, len( - iter_options.data_path_and_name_and_type - ) - - # 1. Sanity check - num_splits = None - for path in [ - path for path, _, _ in iter_options.data_path_and_name_and_type - ] + list(iter_options.shape_files): - if not Path(path).is_dir(): - raise RuntimeError(f"{path} is not a directory") - p = Path(path) / "num_splits" - if not p.exists(): - raise FileNotFoundError(f"{p} is not found") - with p.open() as f: - _num_splits = int(f.read()) - if num_splits is not None and num_splits != _num_splits: - raise RuntimeError( - f"Number of splits are mismathed: " - f"{iter_options.data_path_and_name_and_type[0][0]} and {path}" - ) - num_splits = _num_splits - - for i in range(num_splits): - p = Path(path) / f"split.{i}" - if not p.exists(): - raise FileNotFoundError(f"{p} is not found") - - # 2. Create functions to build an iter factory for each splits - data_path_and_name_and_type_list = [ - [ - (str(Path(p) / f"split.{i}"), n, t) - for p, n, t in iter_options.data_path_and_name_and_type - ] - for i in range(num_splits) - ] - shape_files_list = [ - [str(Path(s) / f"split.{i}") for s in iter_options.shape_files] - for i in range(num_splits) - ] - num_iters_per_epoch_list = [ - (iter_options.num_iters_per_epoch + i) // num_splits - if iter_options.num_iters_per_epoch is not None - else None - for i in range(num_splits) - ] - max_cache_size = iter_options.max_cache_size / num_splits - - # Note that iter-factories are built for each epoch at runtime lazily. - build_funcs = [ - functools.partial( - cls.build_iter_factory, - args, - distributed_option, - mode, - kwargs=dict( - data_path_and_name_and_type=_data_path_and_name_and_type, - shape_files=_shape_files, - num_iters_per_epoch=_num_iters_per_epoch, - max_cache_size=max_cache_size, - ), - ) - for ( - _data_path_and_name_and_type, - _shape_files, - _num_iters_per_epoch, - ) in zip( - data_path_and_name_and_type_list, - shape_files_list, - num_iters_per_epoch_list, - ) - ] - - # 3. Build MultipleIterFactory - return MultipleIterFactory( - build_funcs=build_funcs, shuffle=iter_options.train, seed=args.seed - ) - - @classmethod - def build_streaming_iterator( - cls, - data_path_and_name_and_type, - preprocess_fn, - collate_fn, - key_file: str = None, - batch_size: int = 1, - fs: dict = None, - mc: bool = False, - dtype: str = np.float32, - num_workers: int = 1, - allow_variable_data_keys: bool = False, - ngpu: int = 0, - inference: bool = False, - ) -> DataLoader: - """Build DataLoader using iterable dataset""" - # For backward compatibility for pytorch DataLoader - if collate_fn is not None: - kwargs = dict(collate_fn=collate_fn) - else: - kwargs = {} - - dataset = IterableESPnetDataset( - data_path_and_name_and_type, - float_dtype=dtype, - fs=fs, - mc=mc, - preprocess=preprocess_fn, - key_file=key_file, - ) - if dataset.apply_utt2category: - kwargs.update(batch_size=1) - else: - kwargs.update(batch_size=batch_size) - - cls.check_task_requirements( - dataset, allow_variable_data_keys, train=False, inference=inference - ) - - return DataLoader( - dataset=dataset, - pin_memory=ngpu > 0, - num_workers=num_workers, - **kwargs, - ) - - # ~~~~~~~~~ The methods below are mainly used for inference ~~~~~~~~~ - @classmethod - def build_model_from_file( - cls, - config_file: Union[Path, str] = None, - model_file: Union[Path, str] = None, - cmvn_file: Union[Path, str] = None, - device: str = "cpu", - ) -> Tuple[FunASRModel, argparse.Namespace]: - """Build model from the files. - - This method is used for inference or fine-tuning. - - Args: - config_file: The yaml file saved when training. - model_file: The model file saved when training. - device: Device type, "cpu", "cuda", or "cuda:N". - - """ - if config_file is None: - assert model_file is not None, ( - "The argument 'model_file' must be provided " - "if the argument 'config_file' is not specified." - ) - config_file = Path(model_file).parent / "config.yaml" - else: - config_file = Path(config_file) - - with config_file.open("r", encoding="utf-8") as f: - args = yaml.safe_load(f) - if cmvn_file is not None: - args["cmvn_file"] = cmvn_file - args = argparse.Namespace(**args) - model = cls.build_model(args) - if not isinstance(model, FunASRModel): - raise RuntimeError( - f"model must inherit {FunASRModel.__name__}, but got {type(model)}" - ) - model.to(device) - if model_file is not None: - if device == "cuda": - # NOTE(kamo): "cuda" for torch.load always indicates cuda:0 - # in PyTorch<=1.4 - device = f"cuda:{torch.cuda.current_device()}" - model.load_state_dict(torch.load(model_file, map_location=device)) - model.to(device) - return model, args diff --git a/funasr/tasks/asr.py b/funasr/tasks/asr.py deleted file mode 100644 index ce316f7a7..000000000 --- a/funasr/tasks/asr.py +++ /dev/null @@ -1,1762 +0,0 @@ -import argparse -import logging -import os -from pathlib import Path -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union - -import numpy as np -import torch -import yaml - -from funasr.datasets.collate_fn import CommonCollateFn -from funasr.datasets.preprocessor import CommonPreprocessor -from funasr.layers.abs_normalize import AbsNormalize -from funasr.layers.global_mvn import GlobalMVN -from funasr.layers.utterance_mvn import UtteranceMVN -from funasr.models.ctc import CTC -from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.models.decoder.rnn_decoder import RNNDecoder -from funasr.models.decoder.sanm_decoder import ParaformerSANMDecoder, FsmnDecoderSCAMAOpt -from funasr.models.decoder.transformer_decoder import ( - DynamicConvolution2DTransformerDecoder, # noqa: H301 -) -from funasr.models.decoder.transformer_decoder import DynamicConvolutionTransformerDecoder -from funasr.models.decoder.transformer_decoder import ( - LightweightConvolution2DTransformerDecoder, # noqa: H301 -) -from funasr.models.decoder.transformer_decoder import ( - LightweightConvolutionTransformerDecoder, # noqa: H301 -) -from funasr.models.decoder.transformer_decoder import ParaformerDecoderSAN -from funasr.models.decoder.transformer_decoder import TransformerDecoder -from funasr.models.decoder.contextual_decoder import ContextualParaformerDecoder -from funasr.models.decoder.transformer_decoder import SAAsrTransformerDecoder -from funasr.models.e2e_asr import ASRModel -from funasr.models.decoder.rnnt_decoder import RNNTDecoder -from funasr.models.joint_net.joint_network import JointNetwork -from funasr.models.e2e_asr_paraformer import Paraformer, ParaformerOnline, ParaformerBert, BiCifParaformer, ContextualParaformer -from funasr.models.e2e_asr_contextual_paraformer import NeatContextualParaformer -from funasr.models.e2e_tp import TimestampPredictor -from funasr.models.e2e_asr_mfcca import MFCCA -from funasr.models.e2e_sa_asr import SAASRModel -from funasr.models.e2e_uni_asr import UniASR -from funasr.models.e2e_asr_transducer import TransducerModel, UnifiedTransducerModel -from funasr.models.e2e_asr_bat import BATModel -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.encoder.conformer_encoder import ConformerEncoder, ConformerChunkEncoder -from funasr.models.encoder.data2vec_encoder import Data2VecEncoder -from funasr.models.encoder.rnn_encoder import RNNEncoder -from funasr.models.encoder.sanm_encoder import SANMEncoder, SANMEncoderChunkOpt -from funasr.models.encoder.transformer_encoder import TransformerEncoder -from funasr.models.encoder.mfcca_encoder import MFCCAEncoder -from funasr.models.encoder.resnet34_encoder import ResNet34Diar -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.frontend.default import DefaultFrontend -from funasr.models.frontend.default import MultiChannelFrontend -from funasr.models.frontend.fused import FusedFrontends -from funasr.models.frontend.s3prl import S3prlFrontend -from funasr.models.frontend.wav_frontend import WavFrontend -from funasr.models.frontend.windowing import SlidingWindow -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.postencoder.hugging_face_transformers_postencoder import ( - HuggingFaceTransformersPostEncoder, # noqa: H301 -) -from funasr.models.predictor.cif import CifPredictor, CifPredictorV2, CifPredictorV3, BATPredictor -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.preencoder.linear import LinearProjection -from funasr.models.preencoder.sinc import LightweightSincConvs -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.models.specaug.specaug import SpecAug -from funasr.models.specaug.specaug import SpecAugLFR -from funasr.modules.subsampling import Conv1dSubsampling -from funasr.tasks.abs_task import AbsTask -from funasr.tokenizer.phoneme_tokenizer import g2p_choices -from funasr.torch_utils.initialize import initialize -from funasr.models.base_model import FunASRModel -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.get_default_kwargs import get_default_kwargs -from funasr.utils.nested_dict_action import NestedDictAction -from funasr.utils.types import float_or_none -from funasr.utils.types import int_or_none -from funasr.utils.types import str2bool -from funasr.utils.types import str_or_none - -frontend_choices = ClassChoices( - name="frontend", - classes=dict( - default=DefaultFrontend, - sliding_window=SlidingWindow, - s3prl=S3prlFrontend, - fused=FusedFrontends, - wav_frontend=WavFrontend, - multichannelfrontend=MultiChannelFrontend, - ), - type_check=AbsFrontend, - default="default", -) -specaug_choices = ClassChoices( - name="specaug", - classes=dict( - specaug=SpecAug, - specaug_lfr=SpecAugLFR, - ), - type_check=AbsSpecAug, - default=None, - optional=True, -) -normalize_choices = ClassChoices( - "normalize", - classes=dict( - global_mvn=GlobalMVN, - utterance_mvn=UtteranceMVN, - ), - type_check=AbsNormalize, - default=None, - optional=True, -) -model_choices = ClassChoices( - "model", - classes=dict( - asr=ASRModel, - uniasr=UniASR, - paraformer=Paraformer, - paraformer_online=ParaformerOnline, - paraformer_bert=ParaformerBert, - bicif_paraformer=BiCifParaformer, - contextual_paraformer=ContextualParaformer, - neatcontextual_paraformer=NeatContextualParaformer, - mfcca=MFCCA, - timestamp_prediction=TimestampPredictor, - rnnt=TransducerModel, - rnnt_unified=UnifiedTransducerModel, - bat=BATModel, - sa_asr=SAASRModel, - ), - type_check=FunASRModel, - default="asr", -) -preencoder_choices = ClassChoices( - name="preencoder", - classes=dict( - sinc=LightweightSincConvs, - linear=LinearProjection, - ), - type_check=AbsPreEncoder, - default=None, - optional=True, -) -encoder_choices = ClassChoices( - "encoder", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - data2vec_encoder=Data2VecEncoder, - mfcca_enc=MFCCAEncoder, - chunk_conformer=ConformerChunkEncoder, - ), - type_check=AbsEncoder, - default="rnn", -) -encoder_choices2 = ClassChoices( - "encoder2", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - ), - type_check=AbsEncoder, - default="rnn", -) -asr_encoder_choices = ClassChoices( - "asr_encoder", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - data2vec_encoder=Data2VecEncoder, - mfcca_enc=MFCCAEncoder, - ), - type_check=AbsEncoder, - default="rnn", -) -spk_encoder_choices = ClassChoices( - "spk_encoder", - classes=dict( - resnet34_diar=ResNet34Diar, - ), - default="resnet34_diar", -) -postencoder_choices = ClassChoices( - name="postencoder", - classes=dict( - hugging_face_transformers=HuggingFaceTransformersPostEncoder, - ), - type_check=AbsPostEncoder, - default=None, - optional=True, -) -decoder_choices = ClassChoices( - "decoder", - classes=dict( - transformer=TransformerDecoder, - lightweight_conv=LightweightConvolutionTransformerDecoder, - lightweight_conv2d=LightweightConvolution2DTransformerDecoder, - dynamic_conv=DynamicConvolutionTransformerDecoder, - dynamic_conv2d=DynamicConvolution2DTransformerDecoder, - rnn=RNNDecoder, - fsmn_scama_opt=FsmnDecoderSCAMAOpt, - paraformer_decoder_sanm=ParaformerSANMDecoder, - paraformer_decoder_san=ParaformerDecoderSAN, - contextual_paraformer_decoder=ContextualParaformerDecoder, - sa_decoder=SAAsrTransformerDecoder, - ), - type_check=AbsDecoder, - default="rnn", -) -decoder_choices2 = ClassChoices( - "decoder2", - classes=dict( - transformer=TransformerDecoder, - lightweight_conv=LightweightConvolutionTransformerDecoder, - lightweight_conv2d=LightweightConvolution2DTransformerDecoder, - dynamic_conv=DynamicConvolutionTransformerDecoder, - dynamic_conv2d=DynamicConvolution2DTransformerDecoder, - rnn=RNNDecoder, - fsmn_scama_opt=FsmnDecoderSCAMAOpt, - paraformer_decoder_sanm=ParaformerSANMDecoder, - ), - type_check=AbsDecoder, - default="rnn", -) - -rnnt_decoder_choices = ClassChoices( - "rnnt_decoder", - classes=dict( - rnnt=RNNTDecoder, - ), - type_check=RNNTDecoder, - default="rnnt", -) - -joint_network_choices = ClassChoices( - name="joint_network", - classes=dict( - joint_network=JointNetwork, - ), - default="joint_network", - optional=True, -) - -predictor_choices = ClassChoices( - name="predictor", - classes=dict( - cif_predictor=CifPredictor, - ctc_predictor=None, - cif_predictor_v2=CifPredictorV2, - cif_predictor_v3=CifPredictorV3, - bat_predictor=BATPredictor, - ), - type_check=None, - default="cif_predictor", - optional=True, -) -predictor_choices2 = ClassChoices( - name="predictor2", - classes=dict( - cif_predictor=CifPredictor, - ctc_predictor=None, - cif_predictor_v2=CifPredictorV2, - ), - type_check=None, - default="cif_predictor", - optional=True, -) -stride_conv_choices = ClassChoices( - name="stride_conv", - classes=dict( - stride_conv1d=Conv1dSubsampling - ), - type_check=None, - default="stride_conv1d", - optional=True, -) - - -class ASRTask(AbsTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --specaug and --specaug_conf - specaug_choices, - # --normalize and --normalize_conf - normalize_choices, - # --model and --model_conf - model_choices, - # --preencoder and --preencoder_conf - preencoder_choices, - # --encoder and --encoder_conf - encoder_choices, - # --postencoder and --postencoder_conf - postencoder_choices, - # --decoder and --decoder_conf - decoder_choices, - # --predictor and --predictor_conf - predictor_choices, - # --encoder2 and --encoder2_conf - encoder_choices2, - # --decoder2 and --decoder2_conf - decoder_choices2, - # --predictor2 and --predictor2_conf - predictor_choices2, - # --stride_conv and --stride_conv_conf - stride_conv_choices, - # --rnnt_decoder and --rnnt_decoder_conf - rnnt_decoder_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - group = parser.add_argument_group(description="Task related") - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - # required = parser.get_default("required") - # required += ["token_list"] - - group.add_argument( - "--token_list", - type=str_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--split_with_space", - type=str2bool, - default=True, - help="whether to split text using ", - ) - group.add_argument( - "--max_spk_num", - type=int_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--seg_dict_file", - type=str, - default=None, - help="seg_dict_file for text processing", - ) - group.add_argument( - "--init", - type=lambda x: str_or_none(x.lower()), - default=None, - help="The initialization method", - choices=[ - "chainer", - "xavier_uniform", - "xavier_normal", - "kaiming_uniform", - "kaiming_normal", - None, - ], - ) - - group.add_argument( - "--input_size", - type=int_or_none, - default=None, - help="The number of input dimension of the feature", - ) - - group.add_argument( - "--ctc_conf", - action=NestedDictAction, - default=get_default_kwargs(CTC), - help="The keyword arguments for CTC class.", - ) - - group = parser.add_argument_group(description="Preprocess related") - group.add_argument( - "--use_preprocessor", - type=str2bool, - default=True, - help="Apply preprocessing to data or not", - ) - group.add_argument( - "--token_type", - type=str, - default="bpe", - choices=["bpe", "char", "word", "phn"], - help="The text will be tokenized " "in the specified level token", - ) - group.add_argument( - "--bpemodel", - type=str_or_none, - default=None, - help="The model file of sentencepiece", - ) - parser.add_argument( - "--non_linguistic_symbols", - type=str_or_none, - default=None, - help="non_linguistic_symbols file path", - ) - parser.add_argument( - "--cleaner", - type=str_or_none, - choices=[None, "tacotron", "jaconv", "vietnamese"], - default=None, - help="Apply text cleaning", - ) - parser.add_argument( - "--g2p", - type=str_or_none, - choices=g2p_choices, - default=None, - help="Specify g2p method if --token_type=phn", - ) - parser.add_argument( - "--speech_volume_normalize", - type=float_or_none, - default=None, - help="Scale the maximum amplitude to the given value.", - ) - parser.add_argument( - "--rir_scp", - type=str_or_none, - default=None, - help="The file path of rir scp file.", - ) - parser.add_argument( - "--rir_apply_prob", - type=float, - default=1.0, - help="THe probability for applying RIR convolution.", - ) - parser.add_argument( - "--cmvn_file", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_scp", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_apply_prob", - type=float, - default=1.0, - help="The probability applying Noise adding.", - ) - parser.add_argument( - "--noise_db_range", - type=str, - default="13_15", - help="The range of noise decibel level.", - ) - - for class_choices in cls.class_choices_list: - # Append -- and --_conf. - # e.g. --encoder and --encoder_conf - class_choices.add_arguments(group) - - @classmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[ - [Collection[Tuple[str, Dict[str, np.ndarray]]]], - Tuple[List[str], Dict[str, torch.Tensor]], - ]: - # NOTE(kamo): int value = 0 is reserved by CTC-blank symbol - return CommonCollateFn(float_pad_value=0.0, int_pad_value=-1) - - @classmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - if args.use_preprocessor: - retval = CommonPreprocessor( - train=train, - token_type=args.token_type, - token_list=args.token_list, - bpemodel=args.bpemodel, - non_linguistic_symbols=args.non_linguistic_symbols if hasattr(args, "non_linguistic_symbols") else None, - text_cleaner=args.cleaner, - g2p_type=args.g2p, - split_with_space=args.split_with_space if hasattr(args, "split_with_space") else False, - seg_dict_file=args.seg_dict_file if hasattr(args, "seg_dict_file") else None, - # NOTE(kamo): Check attribute existence for backward compatibility - rir_scp=args.rir_scp if hasattr(args, "rir_scp") else None, - rir_apply_prob=args.rir_apply_prob - if hasattr(args, "rir_apply_prob") - else 1.0, - noise_scp=args.noise_scp if hasattr(args, "noise_scp") else None, - noise_apply_prob=args.noise_apply_prob - if hasattr(args, "noise_apply_prob") - else 1.0, - noise_db_range=args.noise_db_range - if hasattr(args, "noise_db_range") - else "13_15", - speech_volume_normalize=args.speech_volume_normalize - if hasattr(args, "rir_scp") - else None, - ) - else: - retval = None - return retval - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - if not inference: - retval = ("speech", "text") - else: - # Recognition mode - retval = ("speech",) - return retval - - @classmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = () - return retval - - @classmethod - def build_model(cls, args: argparse.Namespace): - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size}") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend': - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 4. Pre-encoder input block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - if getattr(args, "preencoder", None) is not None: - preencoder_class = preencoder_choices.get_class(args.preencoder) - preencoder = preencoder_class(**args.preencoder_conf) - input_size = preencoder.output_size() - else: - preencoder = None - - # 5. Encoder - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(input_size=input_size, **args.encoder_conf) - - # 6. Post-encoder block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - encoder_output_size = encoder.output_size() - if getattr(args, "postencoder", None) is not None: - postencoder_class = postencoder_choices.get_class(args.postencoder) - postencoder = postencoder_class( - input_size=encoder_output_size, **args.postencoder_conf - ) - encoder_output_size = postencoder.output_size() - else: - postencoder = None - - # 7. Decoder - decoder_class = decoder_choices.get_class(args.decoder) - decoder = decoder_class( - vocab_size=vocab_size, - encoder_output_size=encoder_output_size, - **args.decoder_conf, - ) - - # 8. CTC - ctc = CTC( - odim=vocab_size, encoder_output_size=encoder_output_size, **args.ctc_conf - ) - - # 9. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("asr") - model = model_class( - vocab_size=vocab_size, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - postencoder=postencoder, - decoder=decoder, - ctc=ctc, - token_list=token_list, - **args.model_conf, - ) - - # 10. Initialize - if args.init is not None: - initialize(model, args.init) - - return model - - -class ASRTaskUniASR(ASRTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --specaug and --specaug_conf - specaug_choices, - # --normalize and --normalize_conf - normalize_choices, - # --model and --model_conf - model_choices, - # --preencoder and --preencoder_conf - preencoder_choices, - # --encoder and --encoder_conf - encoder_choices, - # --postencoder and --postencoder_conf - postencoder_choices, - # --decoder and --decoder_conf - decoder_choices, - # --predictor and --predictor_conf - predictor_choices, - # --encoder2 and --encoder2_conf - encoder_choices2, - # --decoder2 and --decoder2_conf - decoder_choices2, - # --predictor2 and --predictor2_conf - predictor_choices2, - # --stride_conv and --stride_conv_conf - stride_conv_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def build_model(cls, args: argparse.Namespace): - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size}") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend': - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 4. Pre-encoder input block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - if getattr(args, "preencoder", None) is not None: - preencoder_class = preencoder_choices.get_class(args.preencoder) - preencoder = preencoder_class(**args.preencoder_conf) - input_size = preencoder.output_size() - else: - preencoder = None - - # 5. Encoder - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(input_size=input_size, **args.encoder_conf) - encoder_output_size = encoder.output_size() - - stride_conv_class = stride_conv_choices.get_class(args.stride_conv) - stride_conv = stride_conv_class(**args.stride_conv_conf, idim=input_size + encoder_output_size, - odim=input_size + encoder_output_size) - stride_conv_output_size = stride_conv.output_size() - - # 6. Encoder2 - encoder_class2 = encoder_choices2.get_class(args.encoder2) - encoder2 = encoder_class2(input_size=stride_conv_output_size, **args.encoder2_conf) - - # 7. Post-encoder block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - encoder_output_size2 = encoder2.output_size() - if getattr(args, "postencoder", None) is not None: - postencoder_class = postencoder_choices.get_class(args.postencoder) - postencoder = postencoder_class( - input_size=encoder_output_size, **args.postencoder_conf - ) - encoder_output_size = postencoder.output_size() - else: - postencoder = None - - # 8. Decoder & Decoder2 - decoder_class = decoder_choices.get_class(args.decoder) - decoder_class2 = decoder_choices2.get_class(args.decoder2) - decoder = decoder_class( - vocab_size=vocab_size, - encoder_output_size=encoder_output_size, - **args.decoder_conf, - ) - decoder2 = decoder_class2( - vocab_size=vocab_size, - encoder_output_size=encoder_output_size2, - **args.decoder2_conf, - ) - - # 9. CTC - ctc = CTC( - odim=vocab_size, encoder_output_size=encoder_output_size, **args.ctc_conf - ) - ctc2 = CTC( - odim=vocab_size, encoder_output_size=encoder_output_size2, **args.ctc_conf - ) - - # 10. Predictor - predictor_class = predictor_choices.get_class(args.predictor) - predictor = predictor_class(**args.predictor_conf) - - predictor_class = predictor_choices2.get_class(args.predictor2) - predictor2 = predictor_class(**args.predictor2_conf) - - # 11. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("asr") - model = model_class( - vocab_size=vocab_size, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - postencoder=postencoder, - decoder=decoder, - ctc=ctc, - token_list=token_list, - predictor=predictor, - ctc2=ctc2, - encoder2=encoder2, - decoder2=decoder2, - predictor2=predictor2, - stride_conv=stride_conv, - **args.model_conf, - ) - - # 12. Initialize - if args.init is not None: - initialize(model, args.init) - - return model - - # ~~~~~~~~~ The methods below are mainly used for inference ~~~~~~~~~ - @classmethod - def build_model_from_file( - cls, - config_file: Union[Path, str] = None, - model_file: Union[Path, str] = None, - cmvn_file: Union[Path, str] = None, - device: str = "cpu", - ): - """Build model from the files. - - This method is used for inference or fine-tuning. - - Args: - config_file: The yaml file saved when training. - model_file: The model file saved when training. - device: Device type, "cpu", "cuda", or "cuda:N". - - """ - if config_file is None: - assert model_file is not None, ( - "The argument 'model_file' must be provided " - "if the argument 'config_file' is not specified." - ) - config_file = Path(model_file).parent / "config.yaml" - else: - config_file = Path(config_file) - - with config_file.open("r", encoding="utf-8") as f: - args = yaml.safe_load(f) - if cmvn_file is not None: - args["cmvn_file"] = cmvn_file - args = argparse.Namespace(**args) - model = cls.build_model(args) - if not isinstance(model, FunASRModel): - raise RuntimeError( - f"model must inherit {FunASRModel.__name__}, but got {type(model)}" - ) - model.to(device) - model_dict = dict() - model_name_pth = None - if model_file is not None: - logging.info("model_file is {}".format(model_file)) - if device == "cuda": - device = f"cuda:{torch.cuda.current_device()}" - model_dir = os.path.dirname(model_file) - model_name = os.path.basename(model_file) - if "model.ckpt-" in model_name or ".bin" in model_name: - model_name_pth = os.path.join(model_dir, model_name.replace('.bin', - '.pb')) if ".bin" in model_name else os.path.join( - model_dir, "{}.pb".format(model_name)) - if os.path.exists(model_name_pth): - logging.info("model_file is load from pth: {}".format(model_name_pth)) - model_dict = torch.load(model_name_pth, map_location=device) - else: - model_dict = cls.convert_tf2torch(model, model_file) - model.load_state_dict(model_dict) - else: - model_dict = torch.load(model_file, map_location=device) - model.load_state_dict(model_dict) - if model_name_pth is not None and not os.path.exists(model_name_pth): - torch.save(model_dict, model_name_pth) - logging.info("model_file is saved to pth: {}".format(model_name_pth)) - - return model, args - - @classmethod - def convert_tf2torch( - cls, - model, - ckpt, - ): - logging.info("start convert tf model to torch model") - from funasr.modules.streaming_utils.load_fr_tf import load_tf_dict - var_dict_tf = load_tf_dict(ckpt) - var_dict_torch = model.state_dict() - var_dict_torch_update = dict() - # encoder - var_dict_torch_update_local = model.encoder.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # predictor - var_dict_torch_update_local = model.predictor.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # decoder - var_dict_torch_update_local = model.decoder.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # encoder2 - var_dict_torch_update_local = model.encoder2.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # predictor2 - var_dict_torch_update_local = model.predictor2.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # decoder2 - var_dict_torch_update_local = model.decoder2.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # stride_conv - var_dict_torch_update_local = model.stride_conv.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - - return var_dict_torch_update - - -class ASRTaskParaformer(ASRTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # # Add variable objects configurations - # class_choices_list = [ - # # --frontend and --frontend_conf - # frontend_choices, - # # --specaug and --specaug_conf - # specaug_choices, - # # --normalize and --normalize_conf - # normalize_choices, - # # --model and --model_conf - # model_choices, - # # --preencoder and --preencoder_conf - # preencoder_choices, - # # --encoder and --encoder_conf - # encoder_choices, - # # --postencoder and --postencoder_conf - # postencoder_choices, - # # --decoder and --decoder_conf - # decoder_choices, - # # --predictor and --predictor_conf - # predictor_choices, - # ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def build_model(cls, args: argparse.Namespace): - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size}") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend': - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 4. Pre-encoder input block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - if getattr(args, "preencoder", None) is not None: - preencoder_class = preencoder_choices.get_class(args.preencoder) - preencoder = preencoder_class(**args.preencoder_conf) - input_size = preencoder.output_size() - else: - preencoder = None - - # 5. Encoder - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(input_size=input_size, **args.encoder_conf) - - # 6. Post-encoder block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - encoder_output_size = encoder.output_size() - if getattr(args, "postencoder", None) is not None: - postencoder_class = postencoder_choices.get_class(args.postencoder) - postencoder = postencoder_class( - input_size=encoder_output_size, **args.postencoder_conf - ) - encoder_output_size = postencoder.output_size() - else: - postencoder = None - - # 7. Decoder - decoder_class = decoder_choices.get_class(args.decoder) - decoder = decoder_class( - vocab_size=vocab_size, - encoder_output_size=encoder_output_size, - **args.decoder_conf, - ) - - # 8. CTC - ctc = CTC( - odim=vocab_size, encoder_output_size=encoder_output_size, **args.ctc_conf - ) - - # 9. Predictor - predictor_class = predictor_choices.get_class(args.predictor) - predictor = predictor_class(**args.predictor_conf) - - # 10. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("asr") - model = model_class( - vocab_size=vocab_size, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - postencoder=postencoder, - decoder=decoder, - ctc=ctc, - token_list=token_list, - predictor=predictor, - **args.model_conf, - ) - - # 11. Initialize - if args.init is not None: - initialize(model, args.init) - - return model - - # ~~~~~~~~~ The methods below are mainly used for inference ~~~~~~~~~ - @classmethod - def build_model_from_file( - cls, - config_file: Union[Path, str] = None, - model_file: Union[Path, str] = None, - cmvn_file: Union[Path, str] = None, - device: str = "cpu", - ): - """Build model from the files. - - This method is used for inference or fine-tuning. - - Args: - config_file: The yaml file saved when training. - model_file: The model file saved when training. - device: Device type, "cpu", "cuda", or "cuda:N". - - """ - if config_file is None: - assert model_file is not None, ( - "The argument 'model_file' must be provided " - "if the argument 'config_file' is not specified." - ) - config_file = Path(model_file).parent / "config.yaml" - else: - config_file = Path(config_file) - - with config_file.open("r", encoding="utf-8") as f: - args = yaml.safe_load(f) - if cmvn_file is not None: - args["cmvn_file"] = cmvn_file - args = argparse.Namespace(**args) - model = cls.build_model(args) - if not isinstance(model, FunASRModel): - raise RuntimeError( - f"model must inherit {FunASRModel.__name__}, but got {type(model)}" - ) - model.to(device) - model_dict = dict() - model_name_pth = None - if model_file is not None: - logging.info("model_file is {}".format(model_file)) - if device == "cuda": - device = f"cuda:{torch.cuda.current_device()}" - model_dir = os.path.dirname(model_file) - model_name = os.path.basename(model_file) - if "model.ckpt-" in model_name or ".bin" in model_name: - model_name_pth = os.path.join(model_dir, model_name.replace('.bin', - '.pb')) if ".bin" in model_name else os.path.join( - model_dir, "{}.pb".format(model_name)) - if os.path.exists(model_name_pth): - logging.info("model_file is load from pth: {}".format(model_name_pth)) - model_dict = torch.load(model_name_pth, map_location=device) - else: - model_dict = cls.convert_tf2torch(model, model_file) - model.load_state_dict(model_dict) - else: - model_dict = torch.load(model_file, map_location=device) - model.load_state_dict(model_dict) - if model_name_pth is not None and not os.path.exists(model_name_pth): - torch.save(model_dict, model_name_pth) - logging.info("model_file is saved to pth: {}".format(model_name_pth)) - model.to(device) - return model, args - - @classmethod - def convert_tf2torch( - cls, - model, - ckpt, - ): - logging.info("start convert tf model to torch model") - from funasr.modules.streaming_utils.load_fr_tf import load_tf_dict - var_dict_tf = load_tf_dict(ckpt) - var_dict_torch = model.state_dict() - var_dict_torch_update = dict() - # encoder - var_dict_torch_update_local = model.encoder.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # predictor - var_dict_torch_update_local = model.predictor.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # decoder - var_dict_torch_update_local = model.decoder.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # bias_encoder - var_dict_torch_update_local = model.clas_convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - - return var_dict_torch_update - - - -class ASRTaskMFCCA(ASRTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --specaug and --specaug_conf - specaug_choices, - # --normalize and --normalize_conf - normalize_choices, - # --model and --model_conf - model_choices, - # --preencoder and --preencoder_conf - preencoder_choices, - # --encoder and --encoder_conf - encoder_choices, - # --decoder and --decoder_conf - decoder_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def build_model(cls, args: argparse.Namespace): - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size}") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend': - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(stats_file=args.cmvn_file,**args.normalize_conf) - else: - normalize = None - - # 4. Pre-encoder input block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - if getattr(args, "preencoder", None) is not None: - preencoder_class = preencoder_choices.get_class(args.preencoder) - preencoder = preencoder_class(**args.preencoder_conf) - input_size = preencoder.output_size() - else: - preencoder = None - - # 5. Encoder - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(input_size=input_size, **args.encoder_conf) - - # 7. Decoder - decoder_class = decoder_choices.get_class(args.decoder) - decoder = decoder_class( - vocab_size=vocab_size, - encoder_output_size=encoder.output_size(), - **args.decoder_conf, - ) - - # 8. CTC - ctc = CTC( - odim=vocab_size, encoder_output_size=encoder.output_size(), **args.ctc_conf - ) - - - # 10. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("asr") - - rnnt_decoder = None - - # 8. Build model - model = model_class( - vocab_size=vocab_size, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - decoder=decoder, - ctc=ctc, - rnnt_decoder=rnnt_decoder, - token_list=token_list, - **args.model_conf, - ) - - # 11. Initialize - if args.init is not None: - initialize(model, args.init) - - return model - - -class ASRTaskAligner(ASRTaskParaformer): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --model and --model_conf - model_choices, - # --encoder and --encoder_conf - encoder_choices, - # --decoder and --decoder_conf - decoder_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def build_model(cls, args: argparse.Namespace): - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend': - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Encoder - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(input_size=input_size, **args.encoder_conf) - - # 3. Predictor - predictor_class = predictor_choices.get_class(args.predictor) - predictor = predictor_class(**args.predictor_conf) - - # 10. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("asr") - - # 8. Build model - model = model_class( - frontend=frontend, - encoder=encoder, - predictor=predictor, - token_list=token_list, - **args.model_conf, - ) - - # 11. Initialize - if args.init is not None: - initialize(model, args.init) - - return model - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = ("speech", "text") - return retval - - -class ASRTransducerTask(ASRTask): - """ASR Transducer Task definition.""" - - num_optimizers: int = 1 - - class_choices_list = [ - model_choices, - frontend_choices, - specaug_choices, - normalize_choices, - encoder_choices, - rnnt_decoder_choices, - joint_network_choices, - ] - - trainer = Trainer - - @classmethod - def build_model(cls, args: argparse.Namespace) -> TransducerModel: - """Required data depending on task mode. - Args: - cls: ASRTransducerTask object. - args: Task arguments. - Return: - model: ASR Transducer model. - """ - - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size }") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 4. Encoder - if getattr(args, "encoder", None) is not None: - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(input_size, **args.encoder_conf) - else: - encoder = Encoder(input_size, **args.encoder_conf) - encoder_output_size = encoder.output_size() - - # 5. Decoder - rnnt_decoder_class = rnnt_decoder_choices.get_class(args.rnnt_decoder) - decoder = rnnt_decoder_class( - vocab_size, - **args.rnnt_decoder_conf, - ) - decoder_output_size = decoder.output_size - - if getattr(args, "decoder", None) is not None: - att_decoder_class = decoder_choices.get_class(args.decoder) - - att_decoder = att_decoder_class( - vocab_size=vocab_size, - encoder_output_size=encoder_output_size, - **args.decoder_conf, - ) - else: - att_decoder = None - # 6. Joint Network - joint_network = JointNetwork( - vocab_size, - encoder_output_size, - decoder_output_size, - **args.joint_network_conf, - ) - - # 7. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("rnnt_unified") - - model = model_class( - vocab_size=vocab_size, - token_list=token_list, - frontend=frontend, - specaug=specaug, - normalize=normalize, - encoder=encoder, - decoder=decoder, - att_decoder=att_decoder, - joint_network=joint_network, - **args.model_conf, - ) - # 8. Initialize model - if args.init is not None: - raise NotImplementedError( - "Currently not supported.", - "Initialization part will be reworked in a short future.", - ) - - - return model - -class ASRBATTask(ASRTask): - """ASR Boundary Aware Transducer Task definition.""" - - num_optimizers: int = 1 - - class_choices_list = [ - model_choices, - frontend_choices, - specaug_choices, - normalize_choices, - encoder_choices, - rnnt_decoder_choices, - joint_network_choices, - predictor_choices, - ] - - trainer = Trainer - - @classmethod - def build_model(cls, args: argparse.Namespace) -> BATModel: - """Required data depending on task mode. - Args: - cls: ASRBATTask object. - args: Task arguments. - Return: - model: ASR BAT model. - """ - - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size }") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 4. Encoder - if getattr(args, "encoder", None) is not None: - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(input_size, **args.encoder_conf) - else: - encoder = Encoder(input_size, **args.encoder_conf) - encoder_output_size = encoder.output_size() - - # 5. Decoder - rnnt_decoder_class = rnnt_decoder_choices.get_class(args.rnnt_decoder) - decoder = rnnt_decoder_class( - vocab_size, - **args.rnnt_decoder_conf, - ) - decoder_output_size = decoder.output_size - - if getattr(args, "decoder", None) is not None: - att_decoder_class = decoder_choices.get_class(args.decoder) - - att_decoder = att_decoder_class( - vocab_size=vocab_size, - encoder_output_size=encoder_output_size, - **args.decoder_conf, - ) - else: - att_decoder = None - # 6. Joint Network - joint_network = JointNetwork( - vocab_size, - encoder_output_size, - decoder_output_size, - **args.joint_network_conf, - ) - - predictor_class = predictor_choices.get_class(args.predictor) - predictor = predictor_class(**args.predictor_conf) - - # 7. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("rnnt_unified") - - model = model_class( - vocab_size=vocab_size, - token_list=token_list, - frontend=frontend, - specaug=specaug, - normalize=normalize, - encoder=encoder, - decoder=decoder, - att_decoder=att_decoder, - joint_network=joint_network, - predictor=predictor, - **args.model_conf, - ) - # 8. Initialize model - if args.init is not None: - raise NotImplementedError( - "Currently not supported.", - "Initialization part will be reworked in a short future.", - ) - - #assert check_return_type(model) - - return model - -class ASRTaskSAASR(ASRTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --specaug and --specaug_conf - specaug_choices, - # --normalize and --normalize_conf - normalize_choices, - # --model and --model_conf - model_choices, - # --preencoder and --preencoder_conf - preencoder_choices, - # --encoder and --encoder_conf - # --asr_encoder and --asr_encoder_conf - asr_encoder_choices, - # --spk_encoder and --spk_encoder_conf - spk_encoder_choices, - # --decoder and --decoder_conf - decoder_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def build_model(cls, args: argparse.Namespace): - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size}") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend' or args.frontend == "multichannelfrontend": - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 5. Encoder - asr_encoder_class = asr_encoder_choices.get_class(args.asr_encoder) - asr_encoder = asr_encoder_class(input_size=input_size, **args.asr_encoder_conf) - spk_encoder_class = spk_encoder_choices.get_class(args.spk_encoder) - spk_encoder = spk_encoder_class(input_size=input_size, **args.spk_encoder_conf) - - # 7. Decoder - decoder_class = decoder_choices.get_class(args.decoder) - decoder = decoder_class( - vocab_size=vocab_size, - encoder_output_size=asr_encoder.output_size(), - **args.decoder_conf, - ) - - # 8. CTC - ctc = CTC( - odim=vocab_size, encoder_output_size=asr_encoder.output_size(), **args.ctc_conf - ) - - # import ipdb;ipdb.set_trace() - # 9. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("asr") - model = model_class( - vocab_size=vocab_size, - frontend=frontend, - specaug=specaug, - normalize=normalize, - asr_encoder=asr_encoder, - spk_encoder=spk_encoder, - decoder=decoder, - ctc=ctc, - token_list=token_list, - **args.model_conf, - ) - - # 10. Initialize - if args.init is not None: - initialize(model, args.init) - - return model diff --git a/funasr/tasks/data2vec.py b/funasr/tasks/data2vec.py deleted file mode 100644 index 80368f15a..000000000 --- a/funasr/tasks/data2vec.py +++ /dev/null @@ -1,368 +0,0 @@ -import argparse -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple - -import numpy as np -import torch - -from funasr.datasets.collate_fn import CommonCollateFn -from funasr.datasets.preprocessor import CommonPreprocessor -from funasr.layers.abs_normalize import AbsNormalize -from funasr.layers.global_mvn import GlobalMVN -from funasr.layers.utterance_mvn import UtteranceMVN -from funasr.models.data2vec import Data2VecPretrainModel -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.encoder.data2vec_encoder import Data2VecEncoder -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.frontend.default import DefaultFrontend -from funasr.models.frontend.windowing import SlidingWindow -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.preencoder.sinc import LightweightSincConvs -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.models.specaug.specaug import SpecAug -from funasr.tasks.abs_task import AbsTask -from funasr.tokenizer.phoneme_tokenizer import g2p_choices -from funasr.torch_utils.initialize import initialize -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.types import float_or_none -from funasr.utils.types import int_or_none -from funasr.utils.types import str2bool -from funasr.utils.types import str_or_none - -frontend_choices = ClassChoices( - name="frontend", - classes=dict(default=DefaultFrontend, sliding_window=SlidingWindow), - type_check=AbsFrontend, - default="default", -) -specaug_choices = ClassChoices( - name="specaug", - classes=dict(specaug=SpecAug), - type_check=AbsSpecAug, - default=None, - optional=True, -) -normalize_choices = ClassChoices( - "normalize", - classes=dict( - global_mvn=GlobalMVN, - utterance_mvn=UtteranceMVN, - ), - type_check=AbsNormalize, - default=None, - optional=True, -) -preencoder_choices = ClassChoices( - name="preencoder", - classes=dict( - sinc=LightweightSincConvs, - ), - type_check=AbsPreEncoder, - default=None, - optional=True, -) -encoder_choices = ClassChoices( - "encoder", - classes=dict( - data2vec_encoder=Data2VecEncoder, - ), - type_check=AbsEncoder, - default="data2vec_encoder", -) -model_choices = ClassChoices( - "model", - classes=dict( - data2vec=Data2VecPretrainModel, - ), - default="data2vec", -) - - -class Data2VecTask(AbsTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --specaug and --specaug_conf - specaug_choices, - # --normalize and --normalize_conf - normalize_choices, - # --preencoder and --preencoder_conf - preencoder_choices, - # --encoder and --encoder_conf - encoder_choices, - # --model and --model_conf - model_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - group = parser.add_argument_group(description="Task related") - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - group.add_argument( - "--token_list", - type=str_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--init", - type=lambda x: str_or_none(x.lower()), - default=None, - help="The initialization method", - choices=[ - "chainer", - "xavier_uniform", - "xavier_normal", - "kaiming_uniform", - "kaiming_normal", - None, - ], - ) - - group.add_argument( - "--input_size", - type=int_or_none, - default=None, - help="The number of input dimension of the feature", - ) - - group = parser.add_argument_group(description="Preprocess related") - group.add_argument( - "--use_preprocessor", - type=str2bool, - default=True, - help="Apply preprocessing to data or not", - ) - group.add_argument( - "--token_type", - type=str, - default=None, - choices=["bpe", "char", "word", "phn"], - help="The text will be tokenized " "in the specified level token", - ) - - group.add_argument( - "--feats_type", - type=str, - default='fbank', - help="feats type, e.g. fbank, wav, ark_wav(needed to be scale normalization)", - ) - - group.add_argument( - "--bpemodel", - type=str_or_none, - default=None, - help="The model file of sentencepiece", - ) - parser.add_argument( - "--non_linguistic_symbols", - type=str_or_none, - help="non_linguistic_symbols file path", - ) - parser.add_argument( - "--cleaner", - type=str_or_none, - choices=[None, "tacotron", "jaconv", "vietnamese"], - default=None, - help="Apply text cleaning", - ) - parser.add_argument( - "--g2p", - type=str_or_none, - choices=g2p_choices, - default=None, - help="Specify g2p method if --token_type=phn", - ) - parser.add_argument( - "--speech_volume_normalize", - type=float_or_none, - default=None, - help="Scale the maximum amplitude to the given value.", - ) - parser.add_argument( - "--rir_scp", - type=str_or_none, - default=None, - help="The file path of rir scp file.", - ) - parser.add_argument( - "--rir_apply_prob", - type=float, - default=1.0, - help="THe probability for applying RIR convolution.", - ) - parser.add_argument( - "--noise_scp", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_apply_prob", - type=float, - default=1.0, - help="The probability applying Noise adding.", - ) - parser.add_argument( - "--noise_db_range", - type=str, - default="13_15", - help="The range of noise decibel level.", - ) - parser.add_argument( - "--pred_masked_weight", - type=float, - default=1.0, - help="weight for predictive loss for masked frames", - ) - parser.add_argument( - "--pred_nomask_weight", - type=float, - default=0.0, - help="weight for predictive loss for unmasked frames", - ) - parser.add_argument( - "--loss_weights", - type=float, - default=0.0, - help="weights for additional loss terms (not first one)", - ) - - for class_choices in cls.class_choices_list: - # Append -- and --_conf. - # e.g. --encoder and --encoder_conf - class_choices.add_arguments(group) - - @classmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[ - [Collection[Tuple[str, Dict[str, np.ndarray]]]], - Tuple[List[str], Dict[str, torch.Tensor]], - ]: - return CommonCollateFn(clipping=True) - - @classmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - if args.use_preprocessor: - retval = CommonPreprocessor( - train=train, - bpemodel=args.bpemodel, - non_linguistic_symbols=args.non_linguistic_symbols, - text_cleaner=args.cleaner, - g2p_type=args.g2p, - # NOTE(kamo): Check attribute existence for backward compatibility - rir_scp=args.rir_scp if hasattr(args, "rir_scp") else None, - rir_apply_prob=args.rir_apply_prob - if hasattr(args, "rir_apply_prob") - else 1.0, - noise_scp=args.noise_scp if hasattr(args, "noise_scp") else None, - noise_apply_prob=args.noise_apply_prob - if hasattr(args, "noise_apply_prob") - else 1.0, - noise_db_range=args.noise_db_range - if hasattr(args, "noise_db_range") - else "13_15", - speech_volume_normalize=args.speech_volume_normalize - if hasattr(args, "rir_scp") - else None, - ) - else: - retval = None - return retval - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - # for pre-training - retval = ("speech",) - return retval - - @classmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = () - return retval - - @classmethod - def build_model(cls, args: argparse.Namespace): - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 4. Pre-encoder input block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - if getattr(args, "preencoder", None) is not None: - preencoder_class = preencoder_choices.get_class(args.preencoder) - preencoder = preencoder_class(**args.preencoder_conf) - input_size = preencoder.output_size() - else: - preencoder = None - - # 5. Encoder - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class( - input_size=input_size, - **args.encoder_conf, - ) - - # 6. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("data2vec") - model = model_class( - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - ) - - # 7. Initialize - if args.init is not None: - initialize(model, args.init) - - return model diff --git a/funasr/tasks/diar.py b/funasr/tasks/diar.py deleted file mode 100644 index 084b97127..000000000 --- a/funasr/tasks/diar.py +++ /dev/null @@ -1,659 +0,0 @@ -import argparse -import logging -import os -from pathlib import Path -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union - -import numpy as np -import torch -import yaml - -from funasr.datasets.collate_fn import DiarCollateFn -from funasr.datasets.preprocessor import CommonPreprocessor -from funasr.layers.abs_normalize import AbsNormalize -from funasr.layers.global_mvn import GlobalMVN -from funasr.layers.utterance_mvn import UtteranceMVN -from funasr.layers.label_aggregation import LabelAggregate, LabelAggregateMaxPooling -from funasr.models.ctc import CTC -from funasr.models.encoder.resnet34_encoder import ResNet34Diar, ResNet34SpL2RegDiar -from funasr.models.encoder.ecapa_tdnn_encoder import ECAPA_TDNN -from funasr.models.encoder.opennmt_encoders.conv_encoder import ConvEncoder -from funasr.models.encoder.opennmt_encoders.fsmn_encoder import FsmnEncoder -from funasr.models.encoder.opennmt_encoders.self_attention_encoder import SelfAttentionEncoder -from funasr.models.encoder.opennmt_encoders.ci_scorers import DotScorer, CosScorer -from funasr.models.e2e_diar_sond import DiarSondModel -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.encoder.conformer_encoder import ConformerEncoder -from funasr.models.encoder.data2vec_encoder import Data2VecEncoder -from funasr.models.encoder.rnn_encoder import RNNEncoder -from funasr.models.encoder.sanm_encoder import SANMEncoder, SANMEncoderChunkOpt -from funasr.models.encoder.transformer_encoder import TransformerEncoder -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.frontend.default import DefaultFrontend -from funasr.models.frontend.fused import FusedFrontends -from funasr.models.frontend.s3prl import S3prlFrontend -from funasr.models.frontend.wav_frontend import WavFrontend -from funasr.models.frontend.windowing import SlidingWindow -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.postencoder.hugging_face_transformers_postencoder import ( - HuggingFaceTransformersPostEncoder, # noqa: H301 -) -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.preencoder.linear import LinearProjection -from funasr.models.preencoder.sinc import LightweightSincConvs -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.models.specaug.specaug import SpecAug -from funasr.models.specaug.specaug import SpecAugLFR -from funasr.models.specaug.abs_profileaug import AbsProfileAug -from funasr.models.specaug.profileaug import ProfileAug -from funasr.tasks.abs_task import AbsTask -from funasr.torch_utils.initialize import initialize -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.types import float_or_none -from funasr.utils.types import int_or_none -from funasr.utils.types import str2bool -from funasr.utils.types import str_or_none - -frontend_choices = ClassChoices( - name="frontend", - classes=dict( - default=DefaultFrontend, - sliding_window=SlidingWindow, - s3prl=S3prlFrontend, - fused=FusedFrontends, - wav_frontend=WavFrontend, - ), - type_check=AbsFrontend, - default="default", -) -specaug_choices = ClassChoices( - name="specaug", - classes=dict( - specaug=SpecAug, - specaug_lfr=SpecAugLFR, - ), - type_check=AbsSpecAug, - default=None, - optional=True, -) -profileaug_choices = ClassChoices( - name="profileaug", - classes=dict( - profileaug=ProfileAug, - ), - type_check=AbsProfileAug, - default=None, - optional=True, -) -normalize_choices = ClassChoices( - "normalize", - classes=dict( - global_mvn=GlobalMVN, - utterance_mvn=UtteranceMVN, - ), - type_check=AbsNormalize, - default=None, - optional=True, -) -label_aggregator_choices = ClassChoices( - "label_aggregator", - classes=dict( - label_aggregator=LabelAggregate, - label_aggregator_max_pool=LabelAggregateMaxPooling, - ), - type_check=torch.nn.Module, - default=None, - optional=True, -) -model_choices = ClassChoices( - "model", - classes=dict( - sond=DiarSondModel, - ), - type_check=torch.nn.Module, - default="sond", -) -encoder_choices = ClassChoices( - "encoder", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - san=SelfAttentionEncoder, - fsmn=FsmnEncoder, - conv=ConvEncoder, - resnet34=ResNet34Diar, - resnet34_sp_l2reg=ResNet34SpL2RegDiar, - sanm_chunk_opt=SANMEncoderChunkOpt, - data2vec_encoder=Data2VecEncoder, - ecapa_tdnn=ECAPA_TDNN, - ), - type_check=torch.nn.Module, - default="resnet34", -) -speaker_encoder_choices = ClassChoices( - "speaker_encoder", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - san=SelfAttentionEncoder, - fsmn=FsmnEncoder, - conv=ConvEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - data2vec_encoder=Data2VecEncoder, - ), - type_check=AbsEncoder, - default=None, - optional=True -) -cd_scorer_choices = ClassChoices( - "cd_scorer", - classes=dict( - san=SelfAttentionEncoder, - ), - type_check=AbsEncoder, - default=None, - optional=True, -) -ci_scorer_choices = ClassChoices( - "ci_scorer", - classes=dict( - dot=DotScorer, - cosine=CosScorer, - conv=ConvEncoder, - ), - type_check=torch.nn.Module, - default=None, - optional=True, -) -# decoder is used for output (e.g. post_net in SOND) -decoder_choices = ClassChoices( - "decoder", - classes=dict( - rnn=RNNEncoder, - fsmn=FsmnEncoder, - ), - type_check=torch.nn.Module, - default="fsmn", -) - - -class DiarTask(AbsTask): - # If you need more than 1 optimizer, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --specaug and --specaug_conf - specaug_choices, - # --profileaug and --profileaug_conf - profileaug_choices, - # --normalize and --normalize_conf - normalize_choices, - # --label_aggregator and --label_aggregator_conf - label_aggregator_choices, - # --model and --model_conf - model_choices, - # --encoder and --encoder_conf - encoder_choices, - # --speaker_encoder and --speaker_encoder_conf - speaker_encoder_choices, - # --cd_scorer and cd_scorer_conf - cd_scorer_choices, - # --ci_scorer and ci_scorer_conf - ci_scorer_choices, - # --decoder and --decoder_conf - decoder_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - group = parser.add_argument_group(description="Task related") - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - # required = parser.get_default("required") - # required += ["token_list"] - - group.add_argument( - "--token_list", - type=str_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--split_with_space", - type=str2bool, - default=True, - help="whether to split text using ", - ) - group.add_argument( - "--seg_dict_file", - type=str, - default=None, - help="seg_dict_file for text processing", - ) - group.add_argument( - "--init", - type=lambda x: str_or_none(x.lower()), - default=None, - help="The initialization method", - choices=[ - "chainer", - "xavier_uniform", - "xavier_normal", - "kaiming_uniform", - "kaiming_normal", - None, - ], - ) - - group.add_argument( - "--input_size", - type=int_or_none, - default=None, - help="The number of input dimension of the feature", - ) - - group = parser.add_argument_group(description="Preprocess related") - group.add_argument( - "--use_preprocessor", - type=str2bool, - default=True, - help="Apply preprocessing to data or not", - ) - group.add_argument( - "--token_type", - type=str, - default="char", - choices=["char"], - help="The text will be tokenized in the specified level token", - ) - parser.add_argument( - "--speech_volume_normalize", - type=float_or_none, - default=None, - help="Scale the maximum amplitude to the given value.", - ) - parser.add_argument( - "--rir_scp", - type=str_or_none, - default=None, - help="The file path of rir scp file.", - ) - parser.add_argument( - "--rir_apply_prob", - type=float, - default=1.0, - help="THe probability for applying RIR convolution.", - ) - parser.add_argument( - "--cmvn_file", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_scp", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_apply_prob", - type=float, - default=1.0, - help="The probability applying Noise adding.", - ) - parser.add_argument( - "--noise_db_range", - type=str, - default="13_15", - help="The range of noise decibel level.", - ) - - for class_choices in cls.class_choices_list: - # Append -- and --_conf. - # e.g. --encoder and --encoder_conf - class_choices.add_arguments(group) - - @classmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[ - [Collection[Tuple[str, Dict[str, np.ndarray]]]], - Tuple[List[str], Dict[str, torch.Tensor]], - ]: - # NOTE(kamo): int value = 0 is reserved by CTC-blank symbol - return DiarCollateFn(float_pad_value=0.0, int_pad_value=-1) - - @classmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - if args.use_preprocessor: - retval = CommonPreprocessor( - train=train, - token_type=args.token_type, - token_list=args.token_list, - bpemodel=None, - non_linguistic_symbols=None, - text_cleaner=None, - g2p_type=None, - split_with_space=args.split_with_space if hasattr(args, "split_with_space") else False, - seg_dict_file=args.seg_dict_file if hasattr(args, "seg_dict_file") else None, - # NOTE(kamo): Check attribute existence for backward compatibility - rir_scp=args.rir_scp if hasattr(args, "rir_scp") else None, - rir_apply_prob=args.rir_apply_prob - if hasattr(args, "rir_apply_prob") - else 1.0, - noise_scp=args.noise_scp if hasattr(args, "noise_scp") else None, - noise_apply_prob=args.noise_apply_prob - if hasattr(args, "noise_apply_prob") - else 1.0, - noise_db_range=args.noise_db_range - if hasattr(args, "noise_db_range") - else "13_15", - speech_volume_normalize=args.speech_volume_normalize - if hasattr(args, "rir_scp") - else None, - ) - else: - retval = None - return retval - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - if not inference: - retval = ("speech", "profile", "binary_labels") - else: - # Recognition mode - retval = ("speech", "profile") - return retval - - @classmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = () - return retval - - @classmethod - def build_optimizers( - cls, - args: argparse.Namespace, - model: torch.nn.Module, - ) -> List[torch.optim.Optimizer]: - if cls.num_optimizers != 1: - raise RuntimeError( - "build_optimizers() must be overridden if num_optimizers != 1" - ) - from funasr.tasks.abs_task import optim_classes - optim_class = optim_classes.get(args.optim) - if optim_class is None: - raise ValueError(f"must be one of {list(optim_classes)}: {args.optim}") - else: - if (hasattr(model, "model_regularizer_weight") and - model.model_regularizer_weight > 0.0 and - hasattr(model, "get_regularize_parameters") - ): - to_regularize_parameters, normal_parameters = model.get_regularize_parameters() - logging.info(f"Set weight decay {model.model_regularizer_weight} for parameters: " - f"{[name for name, value in to_regularize_parameters]}") - module_optim_config = [ - {"params": [value for name, value in to_regularize_parameters], - "weight_decay": model.model_regularizer_weight}, - {"params": [value for name, value in normal_parameters], - "weight_decay": 0.0} - ] - optim = optim_class(module_optim_config, **args.optim_conf) - else: - optim = optim_class(model.parameters(), **args.optim_conf) - - optimizers = [optim] - return optimizers - - @classmethod - def build_model(cls, args: argparse.Namespace): - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size}") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend': - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 2b. Data augmentation for Profiles - if hasattr(args, "profileaug") and args.profileaug is not None: - profileaug_class = profileaug_choices.get_class(args.profileaug) - profileaug = profileaug_class(**args.profileaug_conf) - else: - profileaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 4. Encoder - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(input_size=input_size, **args.encoder_conf) - - # 5. speaker encoder - if getattr(args, "speaker_encoder", None) is not None: - speaker_encoder_class = speaker_encoder_choices.get_class(args.speaker_encoder) - speaker_encoder = speaker_encoder_class(**args.speaker_encoder_conf) - else: - speaker_encoder = None - - # 6. CI & CD scorer - if getattr(args, "ci_scorer", None) is not None: - ci_scorer_class = ci_scorer_choices.get_class(args.ci_scorer) - ci_scorer = ci_scorer_class(**args.ci_scorer_conf) - else: - ci_scorer = None - - if getattr(args, "cd_scorer", None) is not None: - cd_scorer_class = cd_scorer_choices.get_class(args.cd_scorer) - cd_scorer = cd_scorer_class(**args.cd_scorer_conf) - else: - cd_scorer = None - - # 7. Decoder - decoder_class = decoder_choices.get_class(args.decoder) - decoder = decoder_class(**args.decoder_conf) - - if getattr(args, "label_aggregator", None) is not None: - label_aggregator_class = label_aggregator_choices.get_class(args.label_aggregator) - label_aggregator = label_aggregator_class(**args.label_aggregator_conf) - else: - label_aggregator = None - - # 9. Build model - model_class = model_choices.get_class(args.model) - model = model_class( - vocab_size=vocab_size, - frontend=frontend, - specaug=specaug, - profileaug=profileaug, - normalize=normalize, - label_aggregator=label_aggregator, - encoder=encoder, - speaker_encoder=speaker_encoder, - ci_scorer=ci_scorer, - cd_scorer=cd_scorer, - decoder=decoder, - token_list=token_list, - **args.model_conf, - ) - - # 10. Initialize - if args.init is not None: - initialize(model, args.init) - logging.info(f"Init model parameters with {args.init}.") - - return model - - # ~~~~~~~~~ The methods below are mainly used for inference ~~~~~~~~~ - @classmethod - def build_model_from_file( - cls, - config_file: Union[Path, str] = None, - model_file: Union[Path, str] = None, - cmvn_file: Union[Path, str] = None, - device: Union[str, torch.device] = "cpu", - ): - """Build model from the files. - - This method is used for inference or fine-tuning. - - Args: - config_file: The yaml file saved when training. - model_file: The model file saved when training. - cmvn_file: The cmvn file for front-end - device: Device type, "cpu", "cuda", or "cuda:N". - - """ - if config_file is None: - assert model_file is not None, ( - "The argument 'model_file' must be provided " - "if the argument 'config_file' is not specified." - ) - config_file = Path(model_file).parent / "config.yaml" - else: - config_file = Path(config_file) - - with config_file.open("r", encoding="utf-8") as f: - args = yaml.safe_load(f) - if cmvn_file is not None: - args["cmvn_file"] = cmvn_file - args = argparse.Namespace(**args) - model = cls.build_model(args) - if not isinstance(model, torch.nn.Module): - raise RuntimeError( - f"model must inherit {torch.nn.Module.__name__}, but got {type(model)}" - ) - model.to(device) - model_dict = dict() - model_name_pth = None - if model_file is not None: - logging.info("model_file is {}".format(model_file)) - if device == "cuda": - device = f"cuda:{torch.cuda.current_device()}" - model_dir = os.path.dirname(model_file) - model_name = os.path.basename(model_file) - if "model.ckpt-" in model_name or ".bin" in model_name: - if ".bin" in model_name: - model_name_pth = os.path.join(model_dir, model_name.replace('.bin', '.pb')) - else: - model_name_pth = os.path.join(model_dir, "{}.pth".format(model_name)) - if os.path.exists(model_name_pth): - logging.info("model_file is load from pth: {}".format(model_name_pth)) - model_dict = torch.load(model_name_pth, map_location=device) - else: - model_dict = cls.convert_tf2torch(model, model_file) - # model.load_state_dict(model_dict) - else: - model_dict = torch.load(model_file, map_location=device) - model_dict = cls.fileter_model_dict(model_dict, model.state_dict()) - model.load_state_dict(model_dict) - if model_name_pth is not None and not os.path.exists(model_name_pth): - torch.save(model_dict, model_name_pth) - logging.info("model_file is saved to pth: {}".format(model_name_pth)) - - return model, args - - @classmethod - def fileter_model_dict(cls, src_dict: dict, dest_dict: dict): - from collections import OrderedDict - new_dict = OrderedDict() - for key, value in src_dict.items(): - if key in dest_dict: - new_dict[key] = value - else: - logging.info("{} is no longer needed in this model.".format(key)) - for key, value in dest_dict.items(): - if key not in new_dict: - logging.warning("{} is missed in checkpoint.".format(key)) - return new_dict - - @classmethod - def convert_tf2torch( - cls, - model, - ckpt, - ): - logging.info("start convert tf model to torch model") - from funasr.modules.streaming_utils.load_fr_tf import load_tf_dict - var_dict_tf = load_tf_dict(ckpt) - var_dict_torch = model.state_dict() - var_dict_torch_update = dict() - # speech encoder - if model.encoder is not None: - var_dict_torch_update_local = model.encoder.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # speaker encoder - if model.speaker_encoder is not None: - var_dict_torch_update_local = model.speaker_encoder.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # cd scorer - if model.cd_scorer is not None: - var_dict_torch_update_local = model.cd_scorer.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # ci scorer - if model.ci_scorer is not None: - var_dict_torch_update_local = model.ci_scorer.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # decoder - if model.decoder is not None: - var_dict_torch_update_local = model.decoder.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - - return var_dict_torch_update diff --git a/funasr/tasks/lm.py b/funasr/tasks/lm.py deleted file mode 100644 index d5445b24b..000000000 --- a/funasr/tasks/lm.py +++ /dev/null @@ -1,201 +0,0 @@ -import argparse -import logging -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple - -import numpy as np -import torch - -from funasr.datasets.collate_fn import CommonCollateFn -from funasr.datasets.preprocessor import CommonPreprocessor -from funasr.train.abs_model import AbsLM -from funasr.train.abs_model import LanguageModel -from funasr.models.seq_rnn_lm import SequentialRNNLM -from funasr.models.transformer_lm import TransformerLM -from funasr.tasks.abs_task import AbsTask -from funasr.tokenizer.phoneme_tokenizer import g2p_choices -from funasr.torch_utils.initialize import initialize -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.get_default_kwargs import get_default_kwargs -from funasr.utils.nested_dict_action import NestedDictAction -from funasr.utils.types import str2bool -from funasr.utils.types import str_or_none - -lm_choices = ClassChoices( - "lm", - classes=dict( - seq_rnn=SequentialRNNLM, - transformer=TransformerLM, - ), - type_check=AbsLM, - default="seq_rnn", -) - - -class LMTask(AbsTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [lm_choices] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - # NOTE(kamo): Use '_' instead of '-' to avoid confusion - group = parser.add_argument_group(description="Task related") - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - required = parser.get_default("required") - # required += ["token_list"] - - group.add_argument( - "--token_list", - type=str_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--init", - type=lambda x: str_or_none(x.lower()), - default=None, - help="The initialization method", - choices=[ - "chainer", - "xavier_uniform", - "xavier_normal", - "kaiming_uniform", - "kaiming_normal", - None, - ], - ) - group.add_argument( - "--model_conf", - action=NestedDictAction, - default=get_default_kwargs(LanguageModel), - help="The keyword arguments for model class.", - ) - - group = parser.add_argument_group(description="Preprocess related") - group.add_argument( - "--use_preprocessor", - type=str2bool, - default=True, - help="Apply preprocessing to data or not", - ) - group.add_argument( - "--token_type", - type=str, - default="bpe", - choices=["bpe", "char", "word"], - help="", - ) - group.add_argument( - "--bpemodel", - type=str_or_none, - default=None, - help="The model file fo sentencepiece", - ) - parser.add_argument( - "--non_linguistic_symbols", - type=str_or_none, - help="non_linguistic_symbols file path", - ) - parser.add_argument( - "--cleaner", - type=str_or_none, - choices=[None, "tacotron", "jaconv", "vietnamese"], - default=None, - help="Apply text cleaning", - ) - parser.add_argument( - "--g2p", - type=str_or_none, - choices=g2p_choices, - default=None, - help="Specify g2p method if --token_type=phn", - ) - - for class_choices in cls.class_choices_list: - class_choices.add_arguments(group) - - return parser - - @classmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[ - [Collection[Tuple[str, Dict[str, np.ndarray]]]], - Tuple[List[str], Dict[str, torch.Tensor]], - ]: - return CommonCollateFn(int_pad_value=0) - - @classmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - if args.use_preprocessor: - retval = CommonPreprocessor( - train=train, - token_type=args.token_type, - token_list=args.token_list, - bpemodel=args.bpemodel, - text_cleaner=args.cleaner, - g2p_type=args.g2p, - non_linguistic_symbols=args.non_linguistic_symbols, - ) - else: - retval = None - return retval - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = ("text",) - return retval - - @classmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = () - return retval - - @classmethod - def build_model(cls, args: argparse.Namespace) -> LanguageModel: - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # "args" is saved as it is in a yaml file by BaseTask.main(). - # Overwriting token_list to keep it as "portable". - args.token_list = token_list.copy() - elif isinstance(args.token_list, (tuple, list)): - token_list = args.token_list.copy() - else: - raise RuntimeError("token_list must be str or dict") - - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size}") - - # 1. Build LM model - lm_class = lm_choices.get_class(args.lm) - lm = lm_class(vocab_size=vocab_size, **args.lm_conf) - - # 2. Build ESPnetModel - # Assume the last-id is sos_and_eos - model = LanguageModel(lm=lm, vocab_size=vocab_size, **args.model_conf) - - # 3. Initialize - if args.init is not None: - initialize(model, args.init) - return model diff --git a/funasr/tasks/punctuation.py b/funasr/tasks/punctuation.py deleted file mode 100644 index dd5fe5758..000000000 --- a/funasr/tasks/punctuation.py +++ /dev/null @@ -1,218 +0,0 @@ -import argparse -import logging -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple - -import numpy as np -import torch - -from funasr.datasets.collate_fn import CommonCollateFn -from funasr.datasets.preprocessor import PuncTrainTokenizerCommonPreprocessor -from funasr.train.abs_model import PunctuationModel -from funasr.models.target_delay_transformer import TargetDelayTransformer -from funasr.models.vad_realtime_transformer import VadRealtimeTransformer -from funasr.tasks.abs_task import AbsTask -from funasr.tokenizer.phoneme_tokenizer import g2p_choices -from funasr.torch_utils.initialize import initialize -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.get_default_kwargs import get_default_kwargs -from funasr.utils.nested_dict_action import NestedDictAction -from funasr.utils.types import str2bool -from funasr.utils.types import str_or_none - -punc_choices = ClassChoices( - "punctuation", - classes=dict(target_delay=TargetDelayTransformer, vad_realtime=VadRealtimeTransformer), - default="target_delay", -) - - -class PunctuationTask(AbsTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [punc_choices] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - # NOTE(kamo): Use '_' instead of '-' to avoid confusion - group = parser.add_argument_group(description="Task related") - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - required = parser.get_default("required") - - group.add_argument( - "--token_list", - type=str_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--init", - type=lambda x: str_or_none(x.lower()), - default=None, - help="The initialization method", - choices=[ - "chainer", - "xavier_uniform", - "xavier_normal", - "kaiming_uniform", - "kaiming_normal", - None, - ], - ) - group.add_argument( - "--model_conf", - action=NestedDictAction, - default=get_default_kwargs(PunctuationModel), - help="The keyword arguments for model class.", - ) - - group = parser.add_argument_group(description="Preprocess related") - group.add_argument( - "--use_preprocessor", - type=str2bool, - default=True, - help="Apply preprocessing to data or not", - ) - group.add_argument( - "--token_type", - type=str, - default="bpe", - choices=["bpe", "char", "word"], - help="", - ) - group.add_argument( - "--bpemodel", - type=str_or_none, - default=None, - help="The model file fo sentencepiece", - ) - parser.add_argument( - "--non_linguistic_symbols", - type=str_or_none, - help="non_linguistic_symbols file path", - ) - parser.add_argument( - "--cleaner", - type=str_or_none, - choices=[None, "tacotron", "jaconv", "vietnamese"], - default=None, - help="Apply text cleaning", - ) - parser.add_argument( - "--g2p", - type=str_or_none, - choices=g2p_choices, - default=None, - help="Specify g2p method if --token_type=phn", - ) - - for class_choices in cls.class_choices_list: - # Append -- and --_conf. - # e.g. --encoder and --encoder_conf - class_choices.add_arguments(group) - - return parser - - @classmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[ - [Collection[Tuple[str, Dict[str, np.ndarray]]]], - Tuple[List[str], Dict[str, torch.Tensor]], - ]: - return CommonCollateFn(int_pad_value=0) - - @classmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - token_types = [args.token_type, args.token_type] - token_lists = [args.token_list, args.punc_list] - bpemodels = [args.bpemodel, args.bpemodel] - text_names = ["text", "punc"] - if args.use_preprocessor: - retval = PuncTrainTokenizerCommonPreprocessor( - train=train, - token_type=token_types, - token_list=token_lists, - bpemodel=bpemodels, - text_cleaner=args.cleaner, - g2p_type=args.g2p, - text_name = text_names, - non_linguistic_symbols=args.non_linguistic_symbols, - ) - else: - retval = None - return retval - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = ("text", "punc") - if inference: - retval = ("text", ) - return retval - - @classmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = ("vad",) - return retval - - @classmethod - def build_model(cls, args: argparse.Namespace) -> PunctuationModel: - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # "args" is saved as it is in a yaml file by BaseTask.main(). - # Overwriting token_list to keep it as "portable". - args.token_list = token_list.copy() - if isinstance(args.punc_list, str): - with open(args.punc_list, encoding="utf-8") as f2: - pairs = [line.rstrip().split(":") for line in f2] - punc_list = [pair[0] for pair in pairs] - punc_weight_list = [float(pair[1]) for pair in pairs] - args.punc_list = punc_list.copy() - elif isinstance(args.punc_list, list): - punc_list = args.punc_list.copy() - punc_weight_list = [1] * len(punc_list) - if isinstance(args.token_list, (tuple, list)): - token_list = args.token_list.copy() - else: - raise RuntimeError("token_list must be str or dict") - - vocab_size = len(token_list) - punc_size = len(punc_list) - logging.info(f"Vocabulary size: {vocab_size}") - - # 1. Build PUNC model - punc_class = punc_choices.get_class(args.punctuation) - punc = punc_class(vocab_size=vocab_size, punc_size=punc_size, **args.punctuation_conf) - - # 2. Build ESPnetModel - # Assume the last-id is sos_and_eos - if "punc_weight" in args.model_conf: - args.model_conf.pop("punc_weight") - model = PunctuationModel(punc_model=punc, vocab_size=vocab_size, punc_weight=punc_weight_list, **args.model_conf) - - # FIXME(kamo): Should be done in model? - # 3. Initialize - if args.init is not None: - initialize(model, args.init) - - return model diff --git a/funasr/tasks/sa_asr.py b/funasr/tasks/sa_asr.py deleted file mode 100644 index 6bf918f3e..000000000 --- a/funasr/tasks/sa_asr.py +++ /dev/null @@ -1,615 +0,0 @@ -import argparse -import logging -import os -from pathlib import Path -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union - -import numpy as np -import torch -import yaml - -from funasr.datasets.collate_fn import CommonCollateFn -from funasr.datasets.preprocessor import CommonPreprocessor -from funasr.layers.abs_normalize import AbsNormalize -from funasr.layers.global_mvn import GlobalMVN -from funasr.layers.utterance_mvn import UtteranceMVN -from funasr.models.ctc import CTC -from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.models.decoder.rnn_decoder import RNNDecoder -from funasr.models.decoder.sanm_decoder import ParaformerSANMDecoder, FsmnDecoderSCAMAOpt -from funasr.models.decoder.transformer_decoder import ( - DynamicConvolution2DTransformerDecoder, # noqa: H301 -) -from funasr.models.decoder.transformer_decoder import SAAsrTransformerDecoder -from funasr.models.decoder.transformer_decoder import DynamicConvolutionTransformerDecoder -from funasr.models.decoder.transformer_decoder import ( - LightweightConvolution2DTransformerDecoder, # noqa: H301 -) -from funasr.models.decoder.transformer_decoder import ( - LightweightConvolutionTransformerDecoder, # noqa: H301 -) -from funasr.models.decoder.transformer_decoder import ParaformerDecoderSAN -from funasr.models.decoder.transformer_decoder import TransformerDecoder -from funasr.models.decoder.contextual_decoder import ContextualParaformerDecoder -from funasr.models.e2e_sa_asr import SAASRModel -from funasr.models.e2e_asr_paraformer import Paraformer, ParaformerBert, BiCifParaformer, ContextualParaformer -from funasr.models.e2e_tp import TimestampPredictor -from funasr.models.e2e_asr_mfcca import MFCCA -from funasr.models.e2e_uni_asr import UniASR -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.encoder.conformer_encoder import ConformerEncoder -from funasr.models.encoder.data2vec_encoder import Data2VecEncoder -from funasr.models.encoder.rnn_encoder import RNNEncoder -from funasr.models.encoder.sanm_encoder import SANMEncoder, SANMEncoderChunkOpt -from funasr.models.encoder.transformer_encoder import TransformerEncoder -from funasr.models.encoder.mfcca_encoder import MFCCAEncoder -from funasr.models.encoder.resnet34_encoder import ResNet34,ResNet34Diar -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.frontend.default import DefaultFrontend -from funasr.models.frontend.default import MultiChannelFrontend -from funasr.models.frontend.fused import FusedFrontends -from funasr.models.frontend.s3prl import S3prlFrontend -from funasr.models.frontend.wav_frontend import WavFrontend -from funasr.models.frontend.windowing import SlidingWindow -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.postencoder.hugging_face_transformers_postencoder import ( - HuggingFaceTransformersPostEncoder, # noqa: H301 -) -from funasr.models.predictor.cif import CifPredictor, CifPredictorV2, CifPredictorV3 -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.preencoder.linear import LinearProjection -from funasr.models.preencoder.sinc import LightweightSincConvs -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.models.specaug.specaug import SpecAug -from funasr.models.specaug.specaug import SpecAugLFR -from funasr.models.base_model import FunASRModel -from funasr.modules.subsampling import Conv1dSubsampling -from funasr.tasks.abs_task import AbsTask -from funasr.tokenizer.phoneme_tokenizer import g2p_choices -from funasr.torch_utils.initialize import initialize -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.get_default_kwargs import get_default_kwargs -from funasr.utils.nested_dict_action import NestedDictAction -from funasr.utils.types import float_or_none -from funasr.utils.types import int_or_none -from funasr.utils.types import str2bool -from funasr.utils.types import str_or_none - -frontend_choices = ClassChoices( - name="frontend", - classes=dict( - default=DefaultFrontend, - sliding_window=SlidingWindow, - s3prl=S3prlFrontend, - fused=FusedFrontends, - wav_frontend=WavFrontend, - multichannelfrontend=MultiChannelFrontend, - ), - type_check=AbsFrontend, - default="default", -) -specaug_choices = ClassChoices( - name="specaug", - classes=dict( - specaug=SpecAug, - specaug_lfr=SpecAugLFR, - ), - type_check=AbsSpecAug, - default=None, - optional=True, -) -normalize_choices = ClassChoices( - "normalize", - classes=dict( - global_mvn=GlobalMVN, - utterance_mvn=UtteranceMVN, - ), - type_check=AbsNormalize, - default=None, - optional=True, -) -model_choices = ClassChoices( - "model", - classes=dict( - asr=SAASRModel, - uniasr=UniASR, - paraformer=Paraformer, - paraformer_bert=ParaformerBert, - bicif_paraformer=BiCifParaformer, - contextual_paraformer=ContextualParaformer, - mfcca=MFCCA, - timestamp_prediction=TimestampPredictor, - ), - type_check=FunASRModel, - default="asr", -) -preencoder_choices = ClassChoices( - name="preencoder", - classes=dict( - sinc=LightweightSincConvs, - linear=LinearProjection, - ), - type_check=AbsPreEncoder, - default=None, - optional=True, -) -asr_encoder_choices = ClassChoices( - "asr_encoder", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - data2vec_encoder=Data2VecEncoder, - mfcca_enc=MFCCAEncoder, - ), - type_check=AbsEncoder, - default="rnn", -) - -spk_encoder_choices = ClassChoices( - "spk_encoder", - classes=dict( - resnet34_diar=ResNet34Diar, - ), - default="resnet34_diar", -) - -encoder_choices2 = ClassChoices( - "encoder2", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - ), - type_check=AbsEncoder, - default="rnn", -) -postencoder_choices = ClassChoices( - name="postencoder", - classes=dict( - hugging_face_transformers=HuggingFaceTransformersPostEncoder, - ), - type_check=AbsPostEncoder, - default=None, - optional=True, -) -decoder_choices = ClassChoices( - "decoder", - classes=dict( - transformer=TransformerDecoder, - lightweight_conv=LightweightConvolutionTransformerDecoder, - lightweight_conv2d=LightweightConvolution2DTransformerDecoder, - dynamic_conv=DynamicConvolutionTransformerDecoder, - dynamic_conv2d=DynamicConvolution2DTransformerDecoder, - rnn=RNNDecoder, - fsmn_scama_opt=FsmnDecoderSCAMAOpt, - paraformer_decoder_sanm=ParaformerSANMDecoder, - paraformer_decoder_san=ParaformerDecoderSAN, - contextual_paraformer_decoder=ContextualParaformerDecoder, - sa_decoder=SAAsrTransformerDecoder, - ), - type_check=AbsDecoder, - default="sa_decoder", -) -decoder_choices2 = ClassChoices( - "decoder2", - classes=dict( - transformer=TransformerDecoder, - lightweight_conv=LightweightConvolutionTransformerDecoder, - lightweight_conv2d=LightweightConvolution2DTransformerDecoder, - dynamic_conv=DynamicConvolutionTransformerDecoder, - dynamic_conv2d=DynamicConvolution2DTransformerDecoder, - rnn=RNNDecoder, - fsmn_scama_opt=FsmnDecoderSCAMAOpt, - paraformer_decoder_sanm=ParaformerSANMDecoder, - ), - type_check=AbsDecoder, - default="rnn", -) -predictor_choices = ClassChoices( - name="predictor", - classes=dict( - cif_predictor=CifPredictor, - ctc_predictor=None, - cif_predictor_v2=CifPredictorV2, - cif_predictor_v3=CifPredictorV3, - ), - type_check=None, - default="cif_predictor", - optional=True, -) -predictor_choices2 = ClassChoices( - name="predictor2", - classes=dict( - cif_predictor=CifPredictor, - ctc_predictor=None, - cif_predictor_v2=CifPredictorV2, - ), - type_check=None, - default="cif_predictor", - optional=True, -) -stride_conv_choices = ClassChoices( - name="stride_conv", - classes=dict( - stride_conv1d=Conv1dSubsampling - ), - type_check=None, - default="stride_conv1d", - optional=True, -) - - -class ASRTask(AbsTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --specaug and --specaug_conf - specaug_choices, - # --normalize and --normalize_conf - normalize_choices, - # --model and --model_conf - model_choices, - # --preencoder and --preencoder_conf - preencoder_choices, - # --asr_encoder and --asr_encoder_conf - asr_encoder_choices, - # --spk_encoder and --spk_encoder_conf - spk_encoder_choices, - # --postencoder and --postencoder_conf - postencoder_choices, - # --decoder and --decoder_conf - decoder_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - group = parser.add_argument_group(description="Task related") - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - # required = parser.get_default("required") - # required += ["token_list"] - - group.add_argument( - "--token_list", - type=str_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--split_with_space", - type=str2bool, - default=True, - help="whether to split text using ", - ) - group.add_argument( - "--max_spk_num", - type=int_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--seg_dict_file", - type=str, - default=None, - help="seg_dict_file for text processing", - ) - group.add_argument( - "--init", - type=lambda x: str_or_none(x.lower()), - default=None, - help="The initialization method", - choices=[ - "chainer", - "xavier_uniform", - "xavier_normal", - "kaiming_uniform", - "kaiming_normal", - None, - ], - ) - - group.add_argument( - "--input_size", - type=int_or_none, - default=None, - help="The number of input dimension of the feature", - ) - - group.add_argument( - "--ctc_conf", - action=NestedDictAction, - default=get_default_kwargs(CTC), - help="The keyword arguments for CTC class.", - ) - group.add_argument( - "--joint_net_conf", - action=NestedDictAction, - default=None, - help="The keyword arguments for joint network class.", - ) - - group = parser.add_argument_group(description="Preprocess related") - group.add_argument( - "--use_preprocessor", - type=str2bool, - default=True, - help="Apply preprocessing to data or not", - ) - group.add_argument( - "--token_type", - type=str, - default="bpe", - choices=["bpe", "char", "word", "phn"], - help="The text will be tokenized " "in the specified level token", - ) - group.add_argument( - "--bpemodel", - type=str_or_none, - default=None, - help="The model file of sentencepiece", - ) - parser.add_argument( - "--non_linguistic_symbols", - type=str_or_none, - default=None, - help="non_linguistic_symbols file path", - ) - parser.add_argument( - "--cleaner", - type=str_or_none, - choices=[None, "tacotron", "jaconv", "vietnamese"], - default=None, - help="Apply text cleaning", - ) - parser.add_argument( - "--g2p", - type=str_or_none, - choices=g2p_choices, - default=None, - help="Specify g2p method if --token_type=phn", - ) - parser.add_argument( - "--speech_volume_normalize", - type=float_or_none, - default=None, - help="Scale the maximum amplitude to the given value.", - ) - parser.add_argument( - "--rir_scp", - type=str_or_none, - default=None, - help="The file path of rir scp file.", - ) - parser.add_argument( - "--rir_apply_prob", - type=float, - default=1.0, - help="THe probability for applying RIR convolution.", - ) - parser.add_argument( - "--cmvn_file", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_scp", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_apply_prob", - type=float, - default=1.0, - help="The probability applying Noise adding.", - ) - parser.add_argument( - "--noise_db_range", - type=str, - default="13_15", - help="The range of noise decibel level.", - ) - - for class_choices in cls.class_choices_list: - # Append -- and --_conf. - # e.g. --encoder and --encoder_conf - class_choices.add_arguments(group) - - @classmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[ - [Collection[Tuple[str, Dict[str, np.ndarray]]]], - Tuple[List[str], Dict[str, torch.Tensor]], - ]: - # NOTE(kamo): int value = 0 is reserved by CTC-blank symbol - return CommonCollateFn(float_pad_value=0.0, int_pad_value=-1) - - @classmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - if args.use_preprocessor: - retval = CommonPreprocessor( - train=train, - token_type=args.token_type, - token_list=args.token_list, - bpemodel=args.bpemodel, - non_linguistic_symbols=args.non_linguistic_symbols, - text_cleaner=args.cleaner, - g2p_type=args.g2p, - split_with_space=args.split_with_space if hasattr(args, "split_with_space") else False, - seg_dict_file=args.seg_dict_file if hasattr(args, "seg_dict_file") else None, - # NOTE(kamo): Check attribute existence for backward compatibility - rir_scp=args.rir_scp if hasattr(args, "rir_scp") else None, - rir_apply_prob=args.rir_apply_prob - if hasattr(args, "rir_apply_prob") - else 1.0, - noise_scp=args.noise_scp if hasattr(args, "noise_scp") else None, - noise_apply_prob=args.noise_apply_prob - if hasattr(args, "noise_apply_prob") - else 1.0, - noise_db_range=args.noise_db_range - if hasattr(args, "noise_db_range") - else "13_15", - speech_volume_normalize=args.speech_volume_normalize - if hasattr(args, "rir_scp") - else None, - ) - else: - retval = None - return retval - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - if not inference: - retval = ("speech", "text") - else: - # Recognition mode - retval = ("speech",) - return retval - - @classmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = () - return retval - - @classmethod - def build_model(cls, args: argparse.Namespace): - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size}") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend': - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 4. Pre-encoder input block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - if getattr(args, "preencoder", None) is not None: - preencoder_class = preencoder_choices.get_class(args.preencoder) - preencoder = preencoder_class(**args.preencoder_conf) - input_size = preencoder.output_size() - else: - preencoder = None - - # 5. Encoder - asr_encoder_class = asr_encoder_choices.get_class(args.asr_encoder) - asr_encoder = asr_encoder_class(input_size=input_size, **args.asr_encoder_conf) - spk_encoder_class = spk_encoder_choices.get_class(args.spk_encoder) - spk_encoder = spk_encoder_class(input_size=input_size, **args.spk_encoder_conf) - - # 6. Post-encoder block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - asr_encoder_output_size = asr_encoder.output_size() - if getattr(args, "postencoder", None) is not None: - postencoder_class = postencoder_choices.get_class(args.postencoder) - postencoder = postencoder_class( - input_size=asr_encoder_output_size, **args.postencoder_conf - ) - asr_encoder_output_size = postencoder.output_size() - else: - postencoder = None - - # 7. Decoder - decoder_class = decoder_choices.get_class(args.decoder) - decoder = decoder_class( - vocab_size=vocab_size, - encoder_output_size=asr_encoder_output_size, - **args.decoder_conf, - ) - - # 8. CTC - ctc = CTC( - odim=vocab_size, encoder_output_size=asr_encoder_output_size, **args.ctc_conf - ) - - max_spk_num=int(args.max_spk_num) - - # import ipdb;ipdb.set_trace() - # 9. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("asr") - model = model_class( - vocab_size=vocab_size, - max_spk_num=max_spk_num, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - asr_encoder=asr_encoder, - spk_encoder=spk_encoder, - postencoder=postencoder, - decoder=decoder, - ctc=ctc, - token_list=token_list, - **args.model_conf, - ) - - # 10. Initialize - if args.init is not None: - initialize(model, args.init) - - return model \ No newline at end of file diff --git a/funasr/tasks/sv.py b/funasr/tasks/sv.py deleted file mode 100644 index e69852251..000000000 --- a/funasr/tasks/sv.py +++ /dev/null @@ -1,536 +0,0 @@ -""" -Author: Speech Lab, Alibaba Group, China -""" - -import argparse -import logging -import os -from pathlib import Path -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union - -import numpy as np -import torch -import yaml - -from funasr.datasets.collate_fn import CommonCollateFn -from funasr.datasets.preprocessor import CommonPreprocessor -from funasr.layers.abs_normalize import AbsNormalize -from funasr.layers.global_mvn import GlobalMVN -from funasr.layers.utterance_mvn import UtteranceMVN -from funasr.models.e2e_asr import ASRModel -from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.encoder.rnn_encoder import RNNEncoder -from funasr.models.encoder.resnet34_encoder import ResNet34, ResNet34_SP_L2Reg -from funasr.models.pooling.statistic_pooling import StatisticPooling -from funasr.models.decoder.sv_decoder import DenseDecoder -from funasr.models.e2e_sv import ESPnetSVModel -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.frontend.default import DefaultFrontend -from funasr.models.frontend.fused import FusedFrontends -from funasr.models.frontend.s3prl import S3prlFrontend -from funasr.models.frontend.windowing import SlidingWindow -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.postencoder.hugging_face_transformers_postencoder import ( - HuggingFaceTransformersPostEncoder, # noqa: H301 -) -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.preencoder.linear import LinearProjection -from funasr.models.preencoder.sinc import LightweightSincConvs -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.models.specaug.specaug import SpecAug -from funasr.tasks.abs_task import AbsTask -from funasr.torch_utils.initialize import initialize -from funasr.models.base_model import FunASRModel -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.types import float_or_none -from funasr.utils.types import int_or_none -from funasr.utils.types import str2bool -from funasr.utils.types import str_or_none -from funasr.models.frontend.wav_frontend import WavFrontend - -frontend_choices = ClassChoices( - name="frontend", - classes=dict( - default=DefaultFrontend, - sliding_window=SlidingWindow, - s3prl=S3prlFrontend, - fused=FusedFrontends, - wav_frontend=WavFrontend, - ), - type_check=AbsFrontend, - default="default", -) -specaug_choices = ClassChoices( - name="specaug", - classes=dict( - specaug=SpecAug, - ), - type_check=AbsSpecAug, - default=None, - optional=True, -) -normalize_choices = ClassChoices( - "normalize", - classes=dict( - global_mvn=GlobalMVN, - utterance_mvn=UtteranceMVN, - ), - type_check=AbsNormalize, - default=None, - optional=True, -) -model_choices = ClassChoices( - "model", - classes=dict( - espnet=ESPnetSVModel, - ), - type_check=FunASRModel, - default="espnet", -) -preencoder_choices = ClassChoices( - name="preencoder", - classes=dict( - sinc=LightweightSincConvs, - linear=LinearProjection, - ), - type_check=AbsPreEncoder, - default=None, - optional=True, -) -encoder_choices = ClassChoices( - "encoder", - classes=dict( - resnet34=ResNet34, - resnet34_sp_l2reg=ResNet34_SP_L2Reg, - rnn=RNNEncoder, - ), - type_check=AbsEncoder, - default="resnet34", -) -postencoder_choices = ClassChoices( - name="postencoder", - classes=dict( - hugging_face_transformers=HuggingFaceTransformersPostEncoder, - ), - type_check=AbsPostEncoder, - default=None, - optional=True, -) -pooling_choices = ClassChoices( - name="pooling_type", - classes=dict( - statistic=StatisticPooling, - ), - type_check=torch.nn.Module, - default="statistic", -) -decoder_choices = ClassChoices( - "decoder", - classes=dict( - dense=DenseDecoder, - ), - type_check=AbsDecoder, - default="dense", -) - - -class SVTask(AbsTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --specaug and --specaug_conf - specaug_choices, - # --normalize and --normalize_conf - normalize_choices, - # --model and --model_conf - model_choices, - # --preencoder and --preencoder_conf - preencoder_choices, - # --encoder and --encoder_conf - encoder_choices, - # --postencoder and --postencoder_conf - postencoder_choices, - # --pooling and --pooling_conf - pooling_choices, - # --decoder and --decoder_conf - decoder_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - group = parser.add_argument_group(description="Task related") - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - required = parser.get_default("required") - required += ["token_list"] - - group.add_argument( - "--token_list", - type=str_or_none, - default=None, - help="A text mapping int-id to speaker name", - ) - group.add_argument( - "--init", - type=lambda x: str_or_none(x.lower()), - default=None, - help="The initialization method", - choices=[ - "chainer", - "xavier_uniform", - "xavier_normal", - "kaiming_uniform", - "kaiming_normal", - None, - ], - ) - - group.add_argument( - "--input_size", - type=int_or_none, - default=None, - help="The number of input dimension of the feature", - ) - - group = parser.add_argument_group(description="Preprocess related") - group.add_argument( - "--use_preprocessor", - type=str2bool, - default=True, - help="Apply preprocessing to data or not", - ) - parser.add_argument( - "--cleaner", - type=str_or_none, - choices=[None, "tacotron", "jaconv", "vietnamese"], - default=None, - help="Apply text cleaning", - ) - parser.add_argument( - "--speech_volume_normalize", - type=float_or_none, - default=None, - help="Scale the maximum amplitude to the given value.", - ) - parser.add_argument( - "--rir_scp", - type=str_or_none, - default=None, - help="The file path of rir scp file.", - ) - parser.add_argument( - "--rir_apply_prob", - type=float, - default=1.0, - help="THe probability for applying RIR convolution.", - ) - parser.add_argument( - "--noise_scp", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_apply_prob", - type=float, - default=1.0, - help="The probability applying Noise adding.", - ) - parser.add_argument( - "--noise_db_range", - type=str, - default="13_15", - help="The range of noise decibel level.", - ) - - for class_choices in cls.class_choices_list: - # Append -- and --_conf. - # e.g. --encoder and --encoder_conf - class_choices.add_arguments(group) - - @classmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[ - [Collection[Tuple[str, Dict[str, np.ndarray]]]], - Tuple[List[str], Dict[str, torch.Tensor]], - ]: - # NOTE(kamo): int value = 0 is reserved by CTC-blank symbol - return CommonCollateFn(float_pad_value=0.0, int_pad_value=-1) - - @classmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - if args.use_preprocessor: - retval = CommonPreprocessor( - train=train, - token_type=None, - token_list=None, - bpemodel=None, - non_linguistic_symbols=None, - text_cleaner=args.cleaner, - g2p_type=None, - # NOTE(kamo): Check attribute existence for backward compatibility - rir_scp=args.rir_scp if hasattr(args, "rir_scp") else None, - rir_apply_prob=args.rir_apply_prob - if hasattr(args, "rir_apply_prob") - else 1.0, - noise_scp=args.noise_scp if hasattr(args, "noise_scp") else None, - noise_apply_prob=args.noise_apply_prob - if hasattr(args, "noise_apply_prob") - else 1.0, - noise_db_range=args.noise_db_range - if hasattr(args, "noise_db_range") - else "13_15", - speech_volume_normalize=args.speech_volume_normalize - if hasattr(args, "rir_scp") - else None, - ) - else: - retval = None - return retval - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - if not inference: - retval = ("speech", "text") - else: - # Recognition mode - retval = ("speech",) - return retval - - @classmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = () - if inference: - retval = ("ref_speech",) - return retval - - @classmethod - def build_model(cls, args: argparse.Namespace) -> ESPnetSVModel: - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Speaker number: {vocab_size}") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 4. Pre-encoder input block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - if getattr(args, "preencoder", None) is not None: - preencoder_class = preencoder_choices.get_class(args.preencoder) - preencoder = preencoder_class(**args.preencoder_conf) - input_size = preencoder.output_size() - else: - preencoder = None - - # 5. Encoder - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(input_size=input_size, **args.encoder_conf) - - # 6. Post-encoder block - # NOTE(kan-bayashi): Use getattr to keep the compatibility - encoder_output_size = encoder.output_size() - if getattr(args, "postencoder", None) is not None: - postencoder_class = postencoder_choices.get_class(args.postencoder) - postencoder = postencoder_class( - input_size=encoder_output_size, **args.postencoder_conf - ) - encoder_output_size = postencoder.output_size() - else: - postencoder = None - - # 7. Pooling layer - pooling_class = pooling_choices.get_class(args.pooling_type) - pooling_dim = (2, 3) - eps = 1e-12 - if hasattr(args, "pooling_type_conf"): - if "pooling_dim" in args.pooling_type_conf: - pooling_dim = args.pooling_type_conf["pooling_dim"] - if "eps" in args.pooling_type_conf: - eps = args.pooling_type_conf["eps"] - pooling_layer = pooling_class( - pooling_dim=pooling_dim, - eps=eps, - ) - if args.pooling_type == "statistic": - encoder_output_size *= 2 - - # 8. Decoder - decoder_class = decoder_choices.get_class(args.decoder) - decoder = decoder_class( - vocab_size=vocab_size, - encoder_output_size=encoder_output_size, - **args.decoder_conf, - ) - - # 7. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("espnet") - model = model_class( - vocab_size=vocab_size, - token_list=token_list, - frontend=frontend, - specaug=specaug, - normalize=normalize, - preencoder=preencoder, - encoder=encoder, - postencoder=postencoder, - pooling_layer=pooling_layer, - decoder=decoder, - **args.model_conf, - ) - - # FIXME(kamo): Should be done in model? - # 8. Initialize - if args.init is not None: - initialize(model, args.init) - - return model - - # ~~~~~~~~~ The methods below are mainly used for inference ~~~~~~~~~ - @classmethod - def build_model_from_file( - cls, - config_file: Union[Path, str] = None, - model_file: Union[Path, str] = None, - cmvn_file: Union[Path, str] = None, - device: str = "cpu", - ): - """Build model from the files. - - This method is used for inference or fine-tuning. - - Args: - config_file: The yaml file saved when training. - model_file: The model file saved when training. - cmvn_file: The cmvn file for front-end - device: Device type, "cpu", "cuda", or "cuda:N". - - """ - if config_file is None: - assert model_file is not None, ( - "The argument 'model_file' must be provided " - "if the argument 'config_file' is not specified." - ) - config_file = Path(model_file).parent / "config.yaml" - else: - config_file = Path(config_file) - - with config_file.open("r", encoding="utf-8") as f: - args = yaml.safe_load(f) - if cmvn_file is not None: - args["cmvn_file"] = cmvn_file - args = argparse.Namespace(**args) - model = cls.build_model(args) - if not isinstance(model, FunASRModel): - raise RuntimeError( - f"model must inherit {FunASRModel.__name__}, but got {type(model)}" - ) - model.to(device) - model_dict = dict() - model_name_pth = None - if model_file is not None: - logging.info("model_file is {}".format(model_file)) - if device == "cuda": - device = f"cuda:{torch.cuda.current_device()}" - model_dir = os.path.dirname(model_file) - model_name = os.path.basename(model_file) - if "model.ckpt-" in model_name or ".bin" in model_name: - if ".bin" in model_name: - model_name_pth = os.path.join(model_dir, model_name.replace('.bin', '.pb')) - else: - model_name_pth = os.path.join(model_dir, "{}.pb".format(model_name)) - if os.path.exists(model_name_pth): - logging.info("model_file is load from pth: {}".format(model_name_pth)) - model_dict = torch.load(model_name_pth, map_location=device) - else: - model_dict = cls.convert_tf2torch(model, model_file) - model.load_state_dict(model_dict) - else: - model_dict = torch.load(model_file, map_location=device) - model.load_state_dict(model_dict) - if model_name_pth is not None and not os.path.exists(model_name_pth): - torch.save(model_dict, model_name_pth) - logging.info("model_file is saved to pth: {}".format(model_name_pth)) - - return model, args - - @classmethod - def convert_tf2torch( - cls, - model, - ckpt, - ): - logging.info("start convert tf model to torch model") - from funasr.modules.streaming_utils.load_fr_tf import load_tf_dict - var_dict_tf = load_tf_dict(ckpt) - var_dict_torch = model.state_dict() - var_dict_torch_update = dict() - # speech encoder - var_dict_torch_update_local = model.encoder.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # pooling layer - var_dict_torch_update_local = model.pooling_layer.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - # decoder - var_dict_torch_update_local = model.decoder.convert_tf2torch(var_dict_tf, var_dict_torch) - var_dict_torch_update.update(var_dict_torch_update_local) - - return var_dict_torch_update diff --git a/funasr/tasks/vad.py b/funasr/tasks/vad.py deleted file mode 100644 index 822be22d6..000000000 --- a/funasr/tasks/vad.py +++ /dev/null @@ -1,320 +0,0 @@ -import argparse -import logging -import os -from pathlib import Path -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union - -import numpy as np -import torch -import yaml - -from funasr.datasets.collate_fn import CommonCollateFn -from funasr.layers.abs_normalize import AbsNormalize -from funasr.layers.global_mvn import GlobalMVN -from funasr.layers.utterance_mvn import UtteranceMVN -from funasr.models.e2e_vad import E2EVadModel -from funasr.models.encoder.fsmn_encoder import FSMN -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.frontend.default import DefaultFrontend -from funasr.models.frontend.fused import FusedFrontends -from funasr.models.frontend.s3prl import S3prlFrontend -from funasr.models.frontend.wav_frontend import WavFrontend, WavFrontendOnline -from funasr.models.frontend.windowing import SlidingWindow -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.models.specaug.specaug import SpecAug -from funasr.models.specaug.specaug import SpecAugLFR -from funasr.tasks.abs_task import AbsTask -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.types import float_or_none -from funasr.utils.types import int_or_none -from funasr.utils.types import str_or_none - -frontend_choices = ClassChoices( - name="frontend", - classes=dict( - default=DefaultFrontend, - sliding_window=SlidingWindow, - s3prl=S3prlFrontend, - fused=FusedFrontends, - wav_frontend=WavFrontend, - wav_frontend_online=WavFrontendOnline, - ), - type_check=AbsFrontend, - default="default", -) -specaug_choices = ClassChoices( - name="specaug", - classes=dict( - specaug=SpecAug, - specaug_lfr=SpecAugLFR, - ), - type_check=AbsSpecAug, - default=None, - optional=True, -) -normalize_choices = ClassChoices( - "normalize", - classes=dict( - global_mvn=GlobalMVN, - utterance_mvn=UtteranceMVN, - ), - type_check=AbsNormalize, - default=None, - optional=True, -) -model_choices = ClassChoices( - "model", - classes=dict( - e2evad=E2EVadModel, - ), - type_check=object, - default="e2evad", -) - -encoder_choices = ClassChoices( - "encoder", - classes=dict( - fsmn=FSMN, - ), - type_check=torch.nn.Module, - default="fsmn", -) - - -class VADTask(AbsTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --model and --model_conf - model_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - group = parser.add_argument_group(description="Task related") - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - # required = parser.get_default("required") - # required += ["token_list"] - - group.add_argument( - "--init", - type=lambda x: str_or_none(x.lower()), - default=None, - help="The initialization method", - choices=[ - "chainer", - "xavier_uniform", - "xavier_normal", - "kaiming_uniform", - "kaiming_normal", - None, - ], - ) - - group.add_argument( - "--input_size", - type=int_or_none, - default=None, - help="The number of input dimension of the feature", - ) - - group = parser.add_argument_group(description="Preprocess related") - parser.add_argument( - "--speech_volume_normalize", - type=float_or_none, - default=None, - help="Scale the maximum amplitude to the given value.", - ) - parser.add_argument( - "--rir_scp", - type=str_or_none, - default=None, - help="The file path of rir scp file.", - ) - parser.add_argument( - "--rir_apply_prob", - type=float, - default=1.0, - help="THe probability for applying RIR convolution.", - ) - parser.add_argument( - "--cmvn_file", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_scp", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_apply_prob", - type=float, - default=1.0, - help="The probability applying Noise adding.", - ) - parser.add_argument( - "--noise_db_range", - type=str, - default="13_15", - help="The range of noise decibel level.", - ) - - for class_choices in cls.class_choices_list: - # Append -- and --_conf. - # e.g. --encoder and --encoder_conf - class_choices.add_arguments(group) - - @classmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[ - [Collection[Tuple[str, Dict[str, np.ndarray]]]], - Tuple[List[str], Dict[str, torch.Tensor]], - ]: - # NOTE(kamo): int value = 0 is reserved by CTC-blank symbol - return CommonCollateFn(float_pad_value=0.0, int_pad_value=-1) - - @classmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - # if args.use_preprocessor: - # retval = CommonPreprocessor( - # train=train, - # # NOTE(kamo): Check attribute existence for backward compatibility - # rir_scp=args.rir_scp if hasattr(args, "rir_scp") else None, - # rir_apply_prob=args.rir_apply_prob - # if hasattr(args, "rir_apply_prob") - # else 1.0, - # noise_scp=args.noise_scp if hasattr(args, "noise_scp") else None, - # noise_apply_prob=args.noise_apply_prob - # if hasattr(args, "noise_apply_prob") - # else 1.0, - # noise_db_range=args.noise_db_range - # if hasattr(args, "noise_db_range") - # else "13_15", - # speech_volume_normalize=args.speech_volume_normalize - # if hasattr(args, "rir_scp") - # else None, - # ) - # else: - # retval = None - retval = None - return retval - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - if not inference: - retval = ("speech", "text") - else: - # Recognition mode - retval = ("speech",) - return retval - - @classmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = () - return retval - - @classmethod - def build_model(cls, args: argparse.Namespace): - # 4. Encoder - encoder_class = encoder_choices.get_class(args.encoder) - encoder = encoder_class(**args.encoder_conf) - - # 5. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("e2evad") - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend': - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - model = model_class(encoder=encoder, vad_post_args=args.vad_post_conf, frontend=frontend) - - return model - - # ~~~~~~~~~ The methods below are mainly used for inference ~~~~~~~~~ - @classmethod - def build_model_from_file( - cls, - config_file: Union[Path, str] = None, - model_file: Union[Path, str] = None, - device: str = "cpu", - cmvn_file: Union[Path, str] = None, - ): - """Build model from the files. - - This method is used for inference or fine-tuning. - - Args: - config_file: The yaml file saved when training. - model_file: The model file saved when training. - device: Device type, "cpu", "cuda", or "cuda:N". - - """ - if config_file is None: - assert model_file is not None, ( - "The argument 'model_file' must be provided " - "if the argument 'config_file' is not specified." - ) - config_file = Path(model_file).parent / "config.yaml" - else: - config_file = Path(config_file) - - with config_file.open("r", encoding="utf-8") as f: - args = yaml.safe_load(f) - # if cmvn_file is not None: - args["cmvn_file"] = cmvn_file - args = argparse.Namespace(**args) - model = cls.build_model(args) - model.to(device) - model_dict = dict() - model_name_pth = None - if model_file is not None: - logging.info("model_file is {}".format(model_file)) - if device == "cuda": - device = f"cuda:{torch.cuda.current_device()}" - model_dir = os.path.dirname(model_file) - model_name = os.path.basename(model_file) - model_dict = torch.load(model_file, map_location=device) - model.encoder.load_state_dict(model_dict) - - return model, args diff --git a/funasr/tasks/whisper.py b/funasr/tasks/whisper.py deleted file mode 100644 index e26227c73..000000000 --- a/funasr/tasks/whisper.py +++ /dev/null @@ -1,675 +0,0 @@ -import argparse -import logging -import os -from pathlib import Path -from typing import Callable -from typing import Collection -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple -from typing import Union - -import numpy as np -import torch -import yaml - -from funasr.datasets.collate_fn import CommonCollateFn -from funasr.datasets.preprocessor import CommonPreprocessor -from funasr.layers.abs_normalize import AbsNormalize -from funasr.layers.global_mvn import GlobalMVN -from funasr.layers.utterance_mvn import UtteranceMVN -from funasr.models.ctc import CTC -from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.models.decoder.rnn_decoder import RNNDecoder -from funasr.models.decoder.sanm_decoder import ParaformerSANMDecoder, FsmnDecoderSCAMAOpt -from funasr.models.decoder.transformer_decoder import ( - DynamicConvolution2DTransformerDecoder, # noqa: H301 -) -from funasr.models.decoder.transformer_decoder import DynamicConvolutionTransformerDecoder -from funasr.models.decoder.transformer_decoder import ( - LightweightConvolution2DTransformerDecoder, # noqa: H301 -) -from funasr.models.decoder.transformer_decoder import ( - LightweightConvolutionTransformerDecoder, # noqa: H301 -) -from funasr.models.decoder.transformer_decoder import ParaformerDecoderSAN -from funasr.models.decoder.transformer_decoder import TransformerDecoder -from funasr.models.decoder.contextual_decoder import ContextualParaformerDecoder -from funasr.models.decoder.transformer_decoder import SAAsrTransformerDecoder -from funasr.models.e2e_asr import ASRModel -from funasr.models.decoder.rnnt_decoder import RNNTDecoder -from funasr.models.joint_net.joint_network import JointNetwork -from funasr.models.e2e_asr_paraformer import Paraformer, ParaformerOnline, ParaformerBert, BiCifParaformer, ContextualParaformer -from funasr.models.e2e_asr_contextual_paraformer import NeatContextualParaformer -from funasr.models.e2e_tp import TimestampPredictor -from funasr.models.e2e_asr_mfcca import MFCCA -from funasr.models.e2e_sa_asr import SAASRModel -from funasr.models.e2e_uni_asr import UniASR -from funasr.models.e2e_asr_transducer import TransducerModel, UnifiedTransducerModel -from funasr.models.e2e_asr_bat import BATModel -from funasr.models.encoder.abs_encoder import AbsEncoder -from funasr.models.encoder.conformer_encoder import ConformerEncoder, ConformerChunkEncoder -from funasr.models.encoder.data2vec_encoder import Data2VecEncoder -from funasr.models.encoder.rnn_encoder import RNNEncoder -from funasr.models.encoder.sanm_encoder import SANMEncoder, SANMEncoderChunkOpt -from funasr.models.encoder.transformer_encoder import TransformerEncoder -from funasr.models.encoder.mfcca_encoder import MFCCAEncoder -from funasr.models.encoder.resnet34_encoder import ResNet34Diar -from funasr.models.frontend.abs_frontend import AbsFrontend -from funasr.models.frontend.default import DefaultFrontend -from funasr.models.frontend.default import MultiChannelFrontend -from funasr.models.frontend.fused import FusedFrontends -from funasr.models.frontend.s3prl import S3prlFrontend -from funasr.models.frontend.wav_frontend import WavFrontend -from funasr.models.frontend.windowing import SlidingWindow -from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.postencoder.hugging_face_transformers_postencoder import ( - HuggingFaceTransformersPostEncoder, # noqa: H301 -) -from funasr.models.predictor.cif import CifPredictor, CifPredictorV2, CifPredictorV3, BATPredictor -from funasr.models.preencoder.abs_preencoder import AbsPreEncoder -from funasr.models.preencoder.linear import LinearProjection -from funasr.models.preencoder.sinc import LightweightSincConvs -from funasr.models.specaug.abs_specaug import AbsSpecAug -from funasr.models.specaug.specaug import SpecAug -from funasr.models.specaug.specaug import SpecAugLFR -from funasr.modules.subsampling import Conv1dSubsampling -from funasr.tasks.abs_task import AbsTask -from funasr.tokenizer.phoneme_tokenizer import g2p_choices -from funasr.torch_utils.initialize import initialize -from funasr.models.base_model import FunASRModel -from funasr.train.class_choices import ClassChoices -from funasr.train.trainer import Trainer -from funasr.utils.get_default_kwargs import get_default_kwargs -from funasr.utils.nested_dict_action import NestedDictAction -from funasr.utils.types import float_or_none -from funasr.utils.types import int_or_none -from funasr.utils.types import str2bool -from funasr.utils.types import str_or_none - -from funasr.models.whisper_models.model import Whisper, AudioEncoder, TextDecoder - -frontend_choices = ClassChoices( - name="frontend", - classes=dict( - default=DefaultFrontend, - sliding_window=SlidingWindow, - s3prl=S3prlFrontend, - fused=FusedFrontends, - wav_frontend=WavFrontend, - multichannelfrontend=MultiChannelFrontend, - ), - type_check=AbsFrontend, - default="default", -) -specaug_choices = ClassChoices( - name="specaug", - classes=dict( - specaug=SpecAug, - specaug_lfr=SpecAugLFR, - ), - type_check=AbsSpecAug, - default=None, - optional=True, -) -normalize_choices = ClassChoices( - "normalize", - classes=dict( - global_mvn=GlobalMVN, - utterance_mvn=UtteranceMVN, - ), - type_check=AbsNormalize, - default=None, - optional=True, -) -model_choices = ClassChoices( - "model", - classes=dict( - asr=ASRModel, - uniasr=UniASR, - paraformer=Paraformer, - paraformer_online=ParaformerOnline, - paraformer_bert=ParaformerBert, - bicif_paraformer=BiCifParaformer, - contextual_paraformer=ContextualParaformer, - neatcontextual_paraformer=NeatContextualParaformer, - mfcca=MFCCA, - timestamp_prediction=TimestampPredictor, - rnnt=TransducerModel, - rnnt_unified=UnifiedTransducerModel, - bat=BATModel, - sa_asr=SAASRModel, - whisper=Whisper, - ), - type_check=FunASRModel, - default="asr", -) -preencoder_choices = ClassChoices( - name="preencoder", - classes=dict( - sinc=LightweightSincConvs, - linear=LinearProjection, - ), - type_check=AbsPreEncoder, - default=None, - optional=True, -) -encoder_choices = ClassChoices( - "encoder", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - data2vec_encoder=Data2VecEncoder, - mfcca_enc=MFCCAEncoder, - chunk_conformer=ConformerChunkEncoder, - ), - type_check=AbsEncoder, - default="rnn", -) -encoder_choices2 = ClassChoices( - "encoder2", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - ), - type_check=AbsEncoder, - default="rnn", -) -asr_encoder_choices = ClassChoices( - "asr_encoder", - classes=dict( - conformer=ConformerEncoder, - transformer=TransformerEncoder, - rnn=RNNEncoder, - sanm=SANMEncoder, - sanm_chunk_opt=SANMEncoderChunkOpt, - data2vec_encoder=Data2VecEncoder, - mfcca_enc=MFCCAEncoder, - ), - type_check=AbsEncoder, - default="rnn", -) -spk_encoder_choices = ClassChoices( - "spk_encoder", - classes=dict( - resnet34_diar=ResNet34Diar, - ), - default="resnet34_diar", -) -postencoder_choices = ClassChoices( - name="postencoder", - classes=dict( - hugging_face_transformers=HuggingFaceTransformersPostEncoder, - ), - type_check=AbsPostEncoder, - default=None, - optional=True, -) -decoder_choices = ClassChoices( - "decoder", - classes=dict( - transformer=TransformerDecoder, - lightweight_conv=LightweightConvolutionTransformerDecoder, - lightweight_conv2d=LightweightConvolution2DTransformerDecoder, - dynamic_conv=DynamicConvolutionTransformerDecoder, - dynamic_conv2d=DynamicConvolution2DTransformerDecoder, - rnn=RNNDecoder, - fsmn_scama_opt=FsmnDecoderSCAMAOpt, - paraformer_decoder_sanm=ParaformerSANMDecoder, - paraformer_decoder_san=ParaformerDecoderSAN, - contextual_paraformer_decoder=ContextualParaformerDecoder, - sa_decoder=SAAsrTransformerDecoder, - ), - type_check=AbsDecoder, - default="rnn", -) -decoder_choices2 = ClassChoices( - "decoder2", - classes=dict( - transformer=TransformerDecoder, - lightweight_conv=LightweightConvolutionTransformerDecoder, - lightweight_conv2d=LightweightConvolution2DTransformerDecoder, - dynamic_conv=DynamicConvolutionTransformerDecoder, - dynamic_conv2d=DynamicConvolution2DTransformerDecoder, - rnn=RNNDecoder, - fsmn_scama_opt=FsmnDecoderSCAMAOpt, - paraformer_decoder_sanm=ParaformerSANMDecoder, - ), - type_check=AbsDecoder, - default="rnn", -) - -rnnt_decoder_choices = ClassChoices( - "rnnt_decoder", - classes=dict( - rnnt=RNNTDecoder, - ), - type_check=RNNTDecoder, - default="rnnt", -) - -joint_network_choices = ClassChoices( - name="joint_network", - classes=dict( - joint_network=JointNetwork, - ), - default="joint_network", - optional=True, -) - -predictor_choices = ClassChoices( - name="predictor", - classes=dict( - cif_predictor=CifPredictor, - ctc_predictor=None, - cif_predictor_v2=CifPredictorV2, - cif_predictor_v3=CifPredictorV3, - bat_predictor=BATPredictor, - ), - type_check=None, - default="cif_predictor", - optional=True, -) -predictor_choices2 = ClassChoices( - name="predictor2", - classes=dict( - cif_predictor=CifPredictor, - ctc_predictor=None, - cif_predictor_v2=CifPredictorV2, - ), - type_check=None, - default="cif_predictor", - optional=True, -) -stride_conv_choices = ClassChoices( - name="stride_conv", - classes=dict( - stride_conv1d=Conv1dSubsampling - ), - type_check=None, - default="stride_conv1d", - optional=True, -) - - -class ASRTask(AbsTask): - # If you need more than one optimizers, change this value - num_optimizers: int = 1 - - # Add variable objects configurations - class_choices_list = [ - # --frontend and --frontend_conf - frontend_choices, - # --specaug and --specaug_conf - specaug_choices, - # --normalize and --normalize_conf - normalize_choices, - # --model and --model_conf - model_choices, - # --preencoder and --preencoder_conf - preencoder_choices, - # --encoder and --encoder_conf - encoder_choices, - # --postencoder and --postencoder_conf - postencoder_choices, - # --decoder and --decoder_conf - decoder_choices, - # --predictor and --predictor_conf - predictor_choices, - # --encoder2 and --encoder2_conf - encoder_choices2, - # --decoder2 and --decoder2_conf - decoder_choices2, - # --predictor2 and --predictor2_conf - predictor_choices2, - # --stride_conv and --stride_conv_conf - stride_conv_choices, - # --rnnt_decoder and --rnnt_decoder_conf - rnnt_decoder_choices, - ] - - # If you need to modify train() or eval() procedures, change Trainer class here - trainer = Trainer - - @classmethod - def add_task_arguments(cls, parser: argparse.ArgumentParser): - group = parser.add_argument_group(description="Task related") - - # NOTE(kamo): add_arguments(..., required=True) can't be used - # to provide --print_config mode. Instead of it, do as - # required = parser.get_default("required") - # required += ["token_list"] - - group.add_argument( - "--token_list", - type=str_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--split_with_space", - type=str2bool, - default=True, - help="whether to split text using ", - ) - group.add_argument( - "--max_spk_num", - type=int_or_none, - default=None, - help="A text mapping int-id to token", - ) - group.add_argument( - "--seg_dict_file", - type=str, - default=None, - help="seg_dict_file for text processing", - ) - group.add_argument( - "--init", - type=lambda x: str_or_none(x.lower()), - default=None, - help="The initialization method", - choices=[ - "chainer", - "xavier_uniform", - "xavier_normal", - "kaiming_uniform", - "kaiming_normal", - None, - ], - ) - - group.add_argument( - "--input_size", - type=int_or_none, - default=None, - help="The number of input dimension of the feature", - ) - - group.add_argument( - "--ctc_conf", - action=NestedDictAction, - default=get_default_kwargs(CTC), - help="The keyword arguments for CTC class.", - ) - - group = parser.add_argument_group(description="Preprocess related") - group.add_argument( - "--use_preprocessor", - type=str2bool, - default=True, - help="Apply preprocessing to data or not", - ) - group.add_argument( - "--token_type", - type=str, - default="bpe", - choices=["bpe", "char", "word", "phn"], - help="The text will be tokenized " "in the specified level token", - ) - group.add_argument( - "--bpemodel", - type=str_or_none, - default=None, - help="The model file of sentencepiece", - ) - parser.add_argument( - "--non_linguistic_symbols", - type=str_or_none, - default=None, - help="non_linguistic_symbols file path", - ) - parser.add_argument( - "--cleaner", - type=str_or_none, - choices=[None, "tacotron", "jaconv", "vietnamese"], - default=None, - help="Apply text cleaning", - ) - parser.add_argument( - "--g2p", - type=str_or_none, - choices=g2p_choices, - default=None, - help="Specify g2p method if --token_type=phn", - ) - parser.add_argument( - "--speech_volume_normalize", - type=float_or_none, - default=None, - help="Scale the maximum amplitude to the given value.", - ) - parser.add_argument( - "--rir_scp", - type=str_or_none, - default=None, - help="The file path of rir scp file.", - ) - parser.add_argument( - "--rir_apply_prob", - type=float, - default=1.0, - help="THe probability for applying RIR convolution.", - ) - parser.add_argument( - "--cmvn_file", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_scp", - type=str_or_none, - default=None, - help="The file path of noise scp file.", - ) - parser.add_argument( - "--noise_apply_prob", - type=float, - default=1.0, - help="The probability applying Noise adding.", - ) - parser.add_argument( - "--noise_db_range", - type=str, - default="13_15", - help="The range of noise decibel level.", - ) - - for class_choices in cls.class_choices_list: - # Append -- and --_conf. - # e.g. --encoder and --encoder_conf - class_choices.add_arguments(group) - - @classmethod - def build_collate_fn( - cls, args: argparse.Namespace, train: bool - ) -> Callable[ - [Collection[Tuple[str, Dict[str, np.ndarray]]]], - Tuple[List[str], Dict[str, torch.Tensor]], - ]: - # NOTE(kamo): int value = 0 is reserved by CTC-blank symbol - return CommonCollateFn(float_pad_value=0.0, int_pad_value=-1) - - @classmethod - def build_preprocess_fn( - cls, args: argparse.Namespace, train: bool - ) -> Optional[Callable[[str, Dict[str, np.array]], Dict[str, np.ndarray]]]: - if args.use_preprocessor: - retval = CommonPreprocessor( - train=train, - token_type=args.token_type, - token_list=args.token_list, - bpemodel=args.bpemodel, - non_linguistic_symbols=args.non_linguistic_symbols if hasattr(args, "non_linguistic_symbols") else None, - text_cleaner=args.cleaner, - g2p_type=args.g2p, - split_with_space=args.split_with_space if hasattr(args, "split_with_space") else False, - seg_dict_file=args.seg_dict_file if hasattr(args, "seg_dict_file") else None, - # NOTE(kamo): Check attribute existence for backward compatibility - rir_scp=args.rir_scp if hasattr(args, "rir_scp") else None, - rir_apply_prob=args.rir_apply_prob - if hasattr(args, "rir_apply_prob") - else 1.0, - noise_scp=args.noise_scp if hasattr(args, "noise_scp") else None, - noise_apply_prob=args.noise_apply_prob - if hasattr(args, "noise_apply_prob") - else 1.0, - noise_db_range=args.noise_db_range - if hasattr(args, "noise_db_range") - else "13_15", - speech_volume_normalize=args.speech_volume_normalize - if hasattr(args, "rir_scp") - else None, - ) - else: - retval = None - return retval - - @classmethod - def required_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - if not inference: - retval = ("speech", "text") - else: - # Recognition mode - retval = ("speech",) - return retval - - @classmethod - def optional_data_names( - cls, train: bool = True, inference: bool = False - ) -> Tuple[str, ...]: - retval = () - return retval - - @classmethod - def build_model(cls, args: argparse.Namespace): - if args.token_list is not None: - if isinstance(args.token_list, str): - with open(args.token_list, encoding="utf-8") as f: - token_list = [line.rstrip() for line in f] - - # Overwriting token_list to keep it as "portable". - args.token_list = list(token_list) - elif isinstance(args.token_list, (tuple, list)): - token_list = list(args.token_list) - else: - raise RuntimeError("token_list must be str or list") - vocab_size = len(token_list) - logging.info(f"Vocabulary size: {vocab_size}") - else: - vocab_size = args.vocab_size - - # 1. frontend - if args.input_size is None: - # Extract features in the model - frontend_class = frontend_choices.get_class(args.frontend) - if args.frontend == 'wav_frontend': - frontend = frontend_class(cmvn_file=args.cmvn_file, **args.frontend_conf) - else: - frontend = frontend_class(**args.frontend_conf) - input_size = frontend.output_size() - else: - # Give features from data-loader - args.frontend = None - args.frontend_conf = {} - frontend = None - input_size = args.input_size - - # 2. Data augmentation for spectrogram - if args.specaug is not None: - specaug_class = specaug_choices.get_class(args.specaug) - specaug = specaug_class(**args.specaug_conf) - else: - specaug = None - - # 3. Normalization layer - if args.normalize is not None: - normalize_class = normalize_choices.get_class(args.normalize) - normalize = normalize_class(**args.normalize_conf) - else: - normalize = None - - # 9. Build model - try: - model_class = model_choices.get_class(args.model) - except AttributeError: - model_class = model_choices.get_class("asr") - model = model_class( - args.whisper_dims, - ) - - # 10. Initialize - if args.init is not None: - initialize(model, args.init) - - return model - - - # ~~~~~~~~~ The methods below are mainly used for inference ~~~~~~~~~ - @classmethod - def build_model_from_file( - cls, - config_file: Union[Path, str] = None, - model_file: Union[Path, str] = None, - cmvn_file: Union[Path, str] = None, - device: str = "cpu", - ): - """Build model from the files. - - This method is used for inference or fine-tuning. - - Args: - config_file: The yaml file saved when training. - model_file: The model file saved when training. - device: Device type, "cpu", "cuda", or "cuda:N". - - """ - if config_file is None: - assert model_file is not None, ( - "The argument 'model_file' must be provided " - "if the argument 'config_file' is not specified." - ) - config_file = Path(model_file).parent / "config.yaml" - else: - config_file = Path(config_file) - - with config_file.open("r", encoding="utf-8") as f: - args = yaml.safe_load(f) - if cmvn_file is not None: - args["cmvn_file"] = cmvn_file - args = argparse.Namespace(**args) - - if model_file is not None: - model_dict = torch.load(model_file, map_location=device) - args.whisper_dims = model_dict["dims"] - model = cls.build_model(args) - if not isinstance(model, FunASRModel): - raise RuntimeError( - f"model must inherit {FunASRModel.__name__}, but got {type(model)}" - ) - model.to(device) - model_dict = dict() - model_name_pth = None - if model_file is not None: - logging.info("model_file is {}".format(model_file)) - if device == "cuda": - device = f"cuda:{torch.cuda.current_device()}" - model_dir = os.path.dirname(model_file) - model_name = os.path.basename(model_file) - model_dict = torch.load(model_file, map_location=device) - model.load_state_dict(model_dict["model_state_dict"]) - if model_name_pth is not None and not os.path.exists(model_name_pth): - torch.save(model_dict, model_name_pth) - logging.info("model_file is saved to pth: {}".format(model_name_pth)) - - return model, args diff --git a/funasr/torch_utils/initialize.py b/funasr/torch_utils/initialize.py deleted file mode 100644 index e4ec5343b..000000000 --- a/funasr/torch_utils/initialize.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python3 - -"""Initialize modules for espnet2 neural networks.""" - -import math -import torch - - -def initialize(model: torch.nn.Module, init: str): - """Initialize weights of a neural network module. - - Parameters are initialized using the given method or distribution. - - Custom initialization routines can be implemented into submodules - as function `espnet_initialization_fn` within the custom module. - - Args: - model: Target. - init: Method of initialization. - """ - - if init == "chainer": - # 1. lecun_normal_init_parameters - for p in model.parameters(): - data = p.data - if data.dim() == 1: - # bias - data.zero_() - elif data.dim() == 2: - # linear weight - n = data.size(1) - stdv = 1.0 / math.sqrt(n) - data.normal_(0, stdv) - elif data.dim() in (3, 4): - # conv weight - n = data.size(1) - for k in data.size()[2:]: - n *= k - stdv = 1.0 / math.sqrt(n) - data.normal_(0, stdv) - else: - raise NotImplementedError - - for mod in model.modules(): - # 2. embed weight ~ Normal(0, 1) - if isinstance(mod, torch.nn.Embedding): - mod.weight.data.normal_(0, 1) - # 3. forget-bias = 1.0 - elif isinstance(mod, torch.nn.RNNCellBase): - n = mod.bias_ih.size(0) - mod.bias_ih.data[n // 4 : n // 2].fill_(1.0) - elif isinstance(mod, torch.nn.RNNBase): - for name, param in mod.named_parameters(): - if "bias" in name: - n = param.size(0) - param.data[n // 4 : n // 2].fill_(1.0) - if hasattr(mod, "espnet_initialization_fn"): - mod.espnet_initialization_fn() - - else: - # weight init - for p in model.parameters(): - if p.dim() > 1: - if init == "xavier_uniform": - torch.nn.init.xavier_uniform_(p.data) - elif init == "xavier_normal": - torch.nn.init.xavier_normal_(p.data) - elif init == "kaiming_uniform": - torch.nn.init.kaiming_uniform_(p.data, nonlinearity="relu") - elif init == "kaiming_normal": - torch.nn.init.kaiming_normal_(p.data, nonlinearity="relu") - else: - raise ValueError("Unknown initialization: " + init) - # bias init - for p in model.parameters(): - if p.dim() == 1: - p.data.zero_() - - # reset some modules with default init - for m in model.modules(): - if isinstance( - m, (torch.nn.Embedding, torch.nn.LayerNorm, torch.nn.GroupNorm) - ): - m.reset_parameters() - if hasattr(m, "espnet_initialization_fn"): - m.espnet_initialization_fn() - - # TODO(xkc): Hacking s3prl_frontend and wav2vec2encoder initialization - if getattr(model, "encoder", None) and getattr( - model.encoder, "reload_pretrained_parameters", None - ): - model.encoder.reload_pretrained_parameters() - if getattr(model, "frontend", None) and getattr( - model.frontend, "reload_pretrained_parameters", None - ): - model.frontend.reload_pretrained_parameters() - if getattr(model, "postencoder", None) and getattr( - model.postencoder, "reload_pretrained_parameters", None - ): - model.postencoder.reload_pretrained_parameters() diff --git a/funasr/train/abs_model.py b/funasr/train/abs_model.py deleted file mode 100644 index 968737674..000000000 --- a/funasr/train/abs_model.py +++ /dev/null @@ -1,303 +0,0 @@ -from abc import ABC -from abc import abstractmethod - -from funasr.modules.scorers.scorer_interface import BatchScorerInterface -from typing import Dict -from typing import Optional -from typing import Tuple - -import torch -import torch.nn.functional as F - -from funasr.modules.nets_utils import make_pad_mask -from funasr.torch_utils.device_funcs import force_gatherable -from funasr.models.base_model import FunASRModel - -class AbsLM(torch.nn.Module, BatchScorerInterface, ABC): - """The abstract LM class - - To share the loss calculation way among different models, - We uses delegate pattern here: - The instance of this class should be passed to "LanguageModel" - - This "model" is one of mediator objects for "Task" class. - - """ - - @abstractmethod - def forward( - self, input: torch.Tensor, hidden: torch.Tensor - ) -> Tuple[torch.Tensor, torch.Tensor]: - raise NotImplementedError - - -class LanguageModel(FunASRModel): - def __init__(self, lm: AbsLM, vocab_size: int, ignore_id: int = 0): - super().__init__() - self.lm = lm - self.sos = 1 - self.eos = 2 - - # ignore_id may be assumed as 0, shared with CTC-blank symbol for ASR. - self.ignore_id = ignore_id - - def nll( - self, - text: torch.Tensor, - text_lengths: torch.Tensor, - max_length: Optional[int] = None, - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Compute negative log likelihood(nll) - - Normally, this function is called in batchify_nll. - Args: - text: (Batch, Length) - text_lengths: (Batch,) - max_lengths: int - """ - batch_size = text.size(0) - # For data parallel - if max_length is None: - text = text[:, : text_lengths.max()] - else: - text = text[:, :max_length] - - # 1. Create a sentence pair like ' w1 w2 w3' and 'w1 w2 w3 ' - # text: (Batch, Length) -> x, y: (Batch, Length + 1) - x = F.pad(text, [1, 0], "constant", self.sos) - t = F.pad(text, [0, 1], "constant", self.ignore_id) - for i, l in enumerate(text_lengths): - t[i, l] = self.eos - x_lengths = text_lengths + 1 - - # 2. Forward Language model - # x: (Batch, Length) -> y: (Batch, Length, NVocab) - y, _ = self.lm(x, None) - - # 3. Calc negative log likelihood - # nll: (BxL,) - nll = F.cross_entropy(y.view(-1, y.shape[-1]), t.view(-1), reduction="none") - # nll: (BxL,) -> (BxL,) - if max_length is None: - nll.masked_fill_(make_pad_mask(x_lengths).to(nll.device).view(-1), 0.0) - else: - nll.masked_fill_( - make_pad_mask(x_lengths, maxlen=max_length + 1).to(nll.device).view(-1), - 0.0, - ) - # nll: (BxL,) -> (B, L) - nll = nll.view(batch_size, -1) - return nll, x_lengths - - def batchify_nll( - self, text: torch.Tensor, text_lengths: torch.Tensor, batch_size: int = 100 - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Compute negative log likelihood(nll) from transformer language model - - To avoid OOM, this fuction seperate the input into batches. - Then call nll for each batch and combine and return results. - Args: - text: (Batch, Length) - text_lengths: (Batch,) - batch_size: int, samples each batch contain when computing nll, - you may change this to avoid OOM or increase - - """ - total_num = text.size(0) - if total_num <= batch_size: - nll, x_lengths = self.nll(text, text_lengths) - else: - nlls = [] - x_lengths = [] - max_length = text_lengths.max() - - start_idx = 0 - while True: - end_idx = min(start_idx + batch_size, total_num) - batch_text = text[start_idx:end_idx, :] - batch_text_lengths = text_lengths[start_idx:end_idx] - # batch_nll: [B * T] - batch_nll, batch_x_lengths = self.nll( - batch_text, batch_text_lengths, max_length=max_length - ) - nlls.append(batch_nll) - x_lengths.append(batch_x_lengths) - start_idx = end_idx - if start_idx == total_num: - break - nll = torch.cat(nlls) - x_lengths = torch.cat(x_lengths) - assert nll.size(0) == total_num - assert x_lengths.size(0) == total_num - return nll, x_lengths - - def forward( - self, text: torch.Tensor, text_lengths: torch.Tensor - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - nll, y_lengths = self.nll(text, text_lengths) - ntokens = y_lengths.sum() - loss = nll.sum() / ntokens - stats = dict(loss=loss.detach()) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - loss, stats, weight = force_gatherable((loss, stats, ntokens), loss.device) - return loss, stats, weight - - def collect_feats( - self, text: torch.Tensor, text_lengths: torch.Tensor - ) -> Dict[str, torch.Tensor]: - return {} - - -class PunctuationModel(FunASRModel): - - def __init__(self, punc_model: torch.nn.Module, vocab_size: int, ignore_id: int = 0, punc_weight: list = None): - super().__init__() - self.punc_model = punc_model - self.punc_weight = torch.Tensor(punc_weight) - self.sos = 1 - self.eos = 2 - - # ignore_id may be assumed as 0, shared with CTC-blank symbol for ASR. - self.ignore_id = ignore_id - # if self.punc_model.with_vad(): - # print("This is a vad puncuation model.") - - def nll( - self, - text: torch.Tensor, - punc: torch.Tensor, - text_lengths: torch.Tensor, - punc_lengths: torch.Tensor, - max_length: Optional[int] = None, - vad_indexes: Optional[torch.Tensor] = None, - vad_indexes_lengths: Optional[torch.Tensor] = None, - ) -> Tuple[torch.Tensor, torch.Tensor]: - """Compute negative log likelihood(nll) - - Normally, this function is called in batchify_nll. - Args: - text: (Batch, Length) - punc: (Batch, Length) - text_lengths: (Batch,) - max_lengths: int - """ - batch_size = text.size(0) - # For data parallel - if max_length is None: - text = text[:, :text_lengths.max()] - punc = punc[:, :text_lengths.max()] - else: - text = text[:, :max_length] - punc = punc[:, :max_length] - - if self.punc_model.with_vad(): - # Should be VadRealtimeTransformer - assert vad_indexes is not None - y, _ = self.punc_model(text, text_lengths, vad_indexes) - else: - # Should be TargetDelayTransformer, - y, _ = self.punc_model(text, text_lengths) - - # Calc negative log likelihood - # nll: (BxL,) - if self.training == False: - _, indices = y.view(-1, y.shape[-1]).topk(1, dim=1) - from sklearn.metrics import f1_score - f1_score = f1_score(punc.view(-1).detach().cpu().numpy(), - indices.squeeze(-1).detach().cpu().numpy(), - average='micro') - nll = torch.Tensor([f1_score]).repeat(text_lengths.sum()) - return nll, text_lengths - else: - self.punc_weight = self.punc_weight.to(punc.device) - nll = F.cross_entropy(y.view(-1, y.shape[-1]), punc.view(-1), self.punc_weight, reduction="none", - ignore_index=self.ignore_id) - # nll: (BxL,) -> (BxL,) - if max_length is None: - nll.masked_fill_(make_pad_mask(text_lengths).to(nll.device).view(-1), 0.0) - else: - nll.masked_fill_( - make_pad_mask(text_lengths, maxlen=max_length + 1).to(nll.device).view(-1), - 0.0, - ) - # nll: (BxL,) -> (B, L) - nll = nll.view(batch_size, -1) - return nll, text_lengths - - def batchify_nll(self, - text: torch.Tensor, - punc: torch.Tensor, - text_lengths: torch.Tensor, - punc_lengths: torch.Tensor, - batch_size: int = 100) -> Tuple[torch.Tensor, torch.Tensor]: - """Compute negative log likelihood(nll) from transformer language model - - To avoid OOM, this fuction seperate the input into batches. - Then call nll for each batch and combine and return results. - Args: - text: (Batch, Length) - punc: (Batch, Length) - text_lengths: (Batch,) - batch_size: int, samples each batch contain when computing nll, - you may change this to avoid OOM or increase - - """ - total_num = text.size(0) - if total_num <= batch_size: - nll, x_lengths = self.nll(text, punc, text_lengths) - else: - nlls = [] - x_lengths = [] - max_length = text_lengths.max() - - start_idx = 0 - while True: - end_idx = min(start_idx + batch_size, total_num) - batch_text = text[start_idx:end_idx, :] - batch_punc = punc[start_idx:end_idx, :] - batch_text_lengths = text_lengths[start_idx:end_idx] - # batch_nll: [B * T] - batch_nll, batch_x_lengths = self.nll(batch_text, batch_punc, batch_text_lengths, max_length=max_length) - nlls.append(batch_nll) - x_lengths.append(batch_x_lengths) - start_idx = end_idx - if start_idx == total_num: - break - nll = torch.cat(nlls) - x_lengths = torch.cat(x_lengths) - assert nll.size(0) == total_num - assert x_lengths.size(0) == total_num - return nll, x_lengths - - def forward( - self, - text: torch.Tensor, - punc: torch.Tensor, - text_lengths: torch.Tensor, - punc_lengths: torch.Tensor, - vad_indexes: Optional[torch.Tensor] = None, - vad_indexes_lengths: Optional[torch.Tensor] = None, - ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: - nll, y_lengths = self.nll(text, punc, text_lengths, punc_lengths, vad_indexes=vad_indexes) - ntokens = y_lengths.sum() - loss = nll.sum() / ntokens - stats = dict(loss=loss.detach()) - - # force_gatherable: to-device and to-tensor if scalar for DataParallel - loss, stats, weight = force_gatherable((loss, stats, ntokens), loss.device) - return loss, stats, weight - - def collect_feats(self, text: torch.Tensor, punc: torch.Tensor, - text_lengths: torch.Tensor) -> Dict[str, torch.Tensor]: - return {} - - def inference(self, - text: torch.Tensor, - text_lengths: torch.Tensor, - vad_indexes: Optional[torch.Tensor] = None) -> Tuple[torch.Tensor, None]: - if self.punc_model.with_vad(): - assert vad_indexes is not None - return self.punc_model(text, text_lengths, vad_indexes) - else: - return self.punc_model(text, text_lengths) diff --git a/funasr/train/distributed_utils.py b/funasr/train/distributed_utils.py deleted file mode 100644 index 13f57447c..000000000 --- a/funasr/train/distributed_utils.py +++ /dev/null @@ -1,380 +0,0 @@ -# Copyright ESPnet (https://github.com/espnet/espnet). All Rights Reserved. -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -import dataclasses -import logging -import os -import socket -from typing import Optional - -import torch -import torch.distributed - - -@dataclasses.dataclass -class DistributedOption: - # Enable distributed Training - distributed: bool = False - # torch.distributed.Backend: "nccl", "mpi", "gloo", or "tcp" - dist_backend: str = "nccl" - # if init_method="env://", - # env values of "MASTER_PORT", "MASTER_ADDR", "WORLD_SIZE", and "RANK" are referred. - dist_init_method: str = "env://" - dist_world_size: Optional[int] = None - dist_rank: Optional[int] = None - local_rank: Optional[int] = None - ngpu: int = 0 - dist_master_addr: Optional[str] = None - dist_master_port: Optional[int] = None - dist_launcher: Optional[str] = None - multiprocessing_distributed: bool = True - - def init_options(self): - if self.distributed: - if self.dist_init_method == "env://": - if get_master_addr(self.dist_master_addr, self.dist_launcher) is None: - raise RuntimeError( - "--dist_master_addr or MASTER_ADDR must be set " - "if --dist_init_method == 'env://'" - ) - if get_master_port(self.dist_master_port) is None: - raise RuntimeError( - "--dist_master_port or MASTER_PORT must be set " - "if --dist_init_port == 'env://'" - ) - - def init_torch_distributed(self, args): - if self.distributed: - # See: - # https://docs.nvidia.com/deeplearning/sdk/nccl-developer-guide/docs/env.html - os.environ.setdefault("NCCL_DEBUG", "INFO") - - # See: - # https://pytorch.org/docs/stable/distributed.html#torch.distributed.init_process_group - os.environ.setdefault("NCCL_BLOCKING_WAIT", "1") - - torch.distributed.init_process_group(backend=self.dist_backend, - init_method=self.dist_init_method, - world_size=args.dist_world_size, - rank=args.dist_rank) - self.dist_rank = torch.distributed.get_rank() - self.dist_world_size = torch.distributed.get_world_size() - self.local_rank = args.local_rank - - def init_options_pai(self): - if self.distributed: - if self.dist_init_method == "env://": - if get_master_addr(self.dist_master_addr, self.dist_launcher) is None: - raise RuntimeError( - "--dist_master_addr or MASTER_ADDR must be set " - "if --dist_init_method == 'env://'" - ) - if get_master_port(self.dist_master_port) is None: - raise RuntimeError( - "--dist_master_port or MASTER_PORT must be set " - "if --dist_init_port == 'env://'" - ) - - self.dist_rank = get_rank(self.dist_rank, self.dist_launcher) - self.dist_world_size = get_world_size( - self.dist_world_size, self.dist_launcher - ) - self.local_rank = get_local_rank(self.local_rank, self.dist_launcher) - - if ( - self.dist_rank is not None - and self.dist_world_size is not None - and self.dist_rank >= self.dist_world_size - ): - raise RuntimeError( - f"RANK >= WORLD_SIZE: {self.dist_rank} >= {self.dist_world_size}" - ) - - if self.dist_init_method == "env://": - self.dist_master_addr = get_master_addr( - self.dist_master_addr, self.dist_launcher - ) - self.dist_master_port = get_master_port(self.dist_master_port) - if ( - self.dist_master_addr is not None - and self.dist_master_port is not None - ): - self.dist_init_method = ( - f"tcp://{self.dist_master_addr}:{self.dist_master_port}" - ) - - def init_torch_distributed_pai(self, args): - if self.distributed: - # See: - # https://docs.nvidia.com/deeplearning/sdk/nccl-developer-guide/docs/env.html - os.environ.setdefault("NCCL_DEBUG", "INFO") - - # See: - # https://pytorch.org/docs/stable/distributed.html#torch.distributed.init_process_group - os.environ.setdefault("NCCL_BLOCKING_WAIT", "1") - - torch.distributed.init_process_group(backend=self.dist_backend, init_method='env://') - self.dist_rank = torch.distributed.get_rank() - self.dist_world_size = torch.distributed.get_world_size() - self.local_rank = args.local_rank - - -def resolve_distributed_mode(args): - # Note that args.distributed is set by only this function. - # and ArgumentParser doesn't have such option - - if args.multiprocessing_distributed: - num_nodes = get_num_nodes(args.dist_world_size, args.dist_launcher) - # a. multi-node - if num_nodes > 1: - args.distributed = True - # b. single-node and multi-gpu with multiprocessing_distributed mode - elif args.ngpu > 1: - args.distributed = True - # c. single-node and single-gpu - else: - args.distributed = False - - if args.ngpu <= 1: - # Disable multiprocessing_distributed mode if 1process per node or cpu mode - args.multiprocessing_distributed = False - if args.ngpu == 1: - # If the number of GPUs equals to 1 with multiprocessing_distributed mode, - # LOCAL_RANK is always 0 - args.local_rank = 0 - - if num_nodes > 1 and get_node_rank(args.dist_rank, args.dist_launcher) is None: - raise RuntimeError( - "--dist_rank or RANK must be set " - "if --multiprocessing_distributed == true" - ) - - # Note that RANK, LOCAL_RANK, and WORLD_SIZE is automatically set, - # so we don't need to check here - else: - # d. multiprocess and multi-gpu with external launcher - # e.g. torch.distributed.launch - if get_world_size(args.dist_world_size, args.dist_launcher) > 1: - args.distributed = True - # e. single-process - else: - args.distributed = False - - if args.distributed and args.ngpu > 0: - if get_local_rank(args.local_rank, args.dist_launcher) is None: - raise RuntimeError( - "--local_rank or LOCAL_RANK must be set " - "if --multiprocessing_distributed == false" - ) - if args.distributed: - if get_node_rank(args.dist_rank, args.dist_launcher) is None: - raise RuntimeError( - "--dist_rank or RANK must be set " - "if --multiprocessing_distributed == false" - ) - if args.distributed and args.dist_launcher == "slurm" and not is_in_slurm_step(): - raise RuntimeError("Launch by 'srun' command if --dist_launcher='slurm'") - - -def is_in_slurm_job() -> bool: - return "SLURM_PROCID" in os.environ and "SLURM_NTASKS" in os.environ - - -def is_in_slurm_step() -> bool: - return ( - is_in_slurm_job() - and "SLURM_STEP_NUM_NODES" in os.environ - and "SLURM_STEP_NODELIST" in os.environ - ) - - -def _int_or_none(x: Optional[str]) -> Optional[int]: - if x is None: - return x - return int(x) - - -def free_port(): - """Find free port using bind(). - - There are some interval between finding this port and using it - and the other process might catch the port by that time. - Thus it is not guaranteed that the port is really empty. - - """ - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - sock.bind(("", 0)) - return sock.getsockname()[1] - - -def get_rank(prior=None, launcher: str = None) -> Optional[int]: - if prior is None: - if launcher == "slurm": - if not is_in_slurm_step(): - raise RuntimeError("This process seems not to be launched by 'srun'") - prior = os.environ["SLURM_PROCID"] - elif launcher == "mpi": - raise RuntimeError( - "launcher=mpi is used for 'multiprocessing-distributed' mode" - ) - elif launcher is not None: - raise RuntimeError(f"launcher='{launcher}' is not supported") - - if prior is not None: - return int(prior) - else: - # prior is None and RANK is None -> RANK = None - return _int_or_none(os.environ.get("RANK")) - - -def get_world_size(prior=None, launcher: str = None) -> int: - if prior is None: - if launcher == "slurm": - if not is_in_slurm_step(): - raise RuntimeError("This process seems not to be launched by 'srun'") - prior = int(os.environ["SLURM_NTASKS"]) - elif launcher == "mpi": - raise RuntimeError( - "launcher=mpi is used for 'multiprocessing-distributed' mode" - ) - elif launcher is not None: - raise RuntimeError(f"launcher='{launcher}' is not supported") - - if prior is not None: - return int(prior) - else: - # prior is None and WORLD_SIZE is None -> WORLD_SIZE = 1 - return int(os.environ.get("WORLD_SIZE", "1")) - - -def get_local_rank(prior=None, launcher: str = None) -> Optional[int]: - # LOCAL_RANK is same as GPU device id - - if prior is None: - if launcher == "slurm": - if not is_in_slurm_step(): - raise RuntimeError("This process seems not to be launched by 'srun'") - - prior = int(os.environ["SLURM_LOCALID"]) - elif launcher == "mpi": - raise RuntimeError( - "launcher=mpi is used for 'multiprocessing-distributed' mode" - ) - elif launcher is not None: - raise RuntimeError(f"launcher='{launcher}' is not supported") - - if prior is not None: - return int(prior) - - elif "LOCAL_RANK" in os.environ: - return int(os.environ["LOCAL_RANK"]) - - elif "CUDA_VISIBLE_DEVICES" in os.environ: - # There are two possibility: - # - "CUDA_VISIBLE_DEVICES" is set to multiple GPU ids. e.g. "0.1,2" - # => This intends to specify multiple devices to to be used exactly - # and local_rank information is possibly insufficient. - # - "CUDA_VISIBLE_DEVICES" is set to an id. e.g. "1" - # => This could be used for LOCAL_RANK - cvd = os.environ["CUDA_VISIBLE_DEVICES"].split(",") - if len(cvd) == 1 and "LOCAL_RANK" not in os.environ: - # If CUDA_VISIBLE_DEVICES is set and LOCAL_RANK is not set, - # then use it as LOCAL_RANK. - - # Unset CUDA_VISIBLE_DEVICES - # because the other device must be visible to communicate - return int(os.environ.pop("CUDA_VISIBLE_DEVICES")) - else: - return None - else: - return None - - -def get_master_addr(prior=None, launcher: str = None) -> Optional[str]: - if prior is None: - if launcher == "slurm": - if not is_in_slurm_step(): - raise RuntimeError("This process seems not to be launched by 'srun'") - - # e.g nodelist = foo[1-10],bar[3-8] or foo4,bar[2-10] - nodelist = os.environ["SLURM_STEP_NODELIST"] - prior = nodelist.split(",")[0].split("-")[0].replace("[", "") - - if prior is not None: - return str(prior) - else: - return os.environ.get("MASTER_ADDR") - - -def get_master_port(prior=None) -> Optional[int]: - if prior is not None: - return prior - else: - return _int_or_none(os.environ.get("MASTER_PORT")) - - -def get_node_rank(prior=None, launcher: str = None) -> Optional[int]: - """Get Node Rank. - - Use for "multiprocessing distributed" mode. - The initial RANK equals to the Node id in this case and - the real Rank is set as (nGPU * NodeID) + LOCAL_RANK in torch.distributed. - - """ - if prior is not None: - return prior - elif launcher == "slurm": - if not is_in_slurm_step(): - raise RuntimeError("This process seems not to be launched by 'srun'") - - # Assume ntasks_per_node == 1 - if os.environ["SLURM_STEP_NUM_NODES"] != os.environ["SLURM_NTASKS"]: - raise RuntimeError( - "Run with --ntasks_per_node=1 if mutliprocessing_distributed=true" - ) - return int(os.environ["SLURM_NODEID"]) - elif launcher == "mpi": - # Use mpi4py only for initialization and not using for communication - from mpi4py import MPI - - comm = MPI.COMM_WORLD - # Assume ntasks_per_node == 1 (We can't check whether it is or not) - return comm.Get_rank() - elif launcher is not None: - raise RuntimeError(f"launcher='{launcher}' is not supported") - else: - return _int_or_none(os.environ.get("RANK")) - - -def get_num_nodes(prior=None, launcher: str = None) -> Optional[int]: - """Get the number of nodes. - - Use for "multiprocessing distributed" mode. - RANK equals to the Node id in this case and - the real Rank is set as (nGPU * NodeID) + LOCAL_RANK in torch.distributed. - - """ - if prior is not None: - return prior - elif launcher == "slurm": - if not is_in_slurm_step(): - raise RuntimeError("This process seems not to be launched by 'srun'") - - # Assume ntasks_per_node == 1 - if os.environ["SLURM_STEP_NUM_NODES"] != os.environ["SLURM_NTASKS"]: - raise RuntimeError( - "Run with --ntasks_per_node=1 if mutliprocessing_distributed=true" - ) - return int(os.environ["SLURM_STEP_NUM_NODES"]) - elif launcher == "mpi": - # Use mpi4py only for initialization and not using for communication - from mpi4py import MPI - - comm = MPI.COMM_WORLD - # Assume ntasks_per_node == 1 (We can't check whether it is or not) - return comm.Get_size() - elif launcher is not None: - raise RuntimeError(f"launcher='{launcher}' is not supported") - else: - # prior is None -> NUM_NODES = 1 - return int(os.environ.get("WORLD_SIZE", 1)) diff --git a/funasr/train/reporter.py b/funasr/train/reporter.py deleted file mode 100644 index cfe31f518..000000000 --- a/funasr/train/reporter.py +++ /dev/null @@ -1,531 +0,0 @@ -"""Reporter module.""" -import dataclasses -import datetime -import logging -import time -import warnings -from collections import defaultdict -from contextlib import contextmanager -from distutils.version import LooseVersion -from typing import ContextManager -from typing import Dict -from typing import List -from typing import Optional -from typing import Sequence -from typing import Tuple -from typing import Union - -import humanfriendly -import numpy as np -import torch - -Num = Union[float, int, complex, torch.Tensor, np.ndarray] - -_reserved = {"time", "total_count"} - - -def to_reported_value(v: Num, weight: Num = None) -> "ReportedValue": - if isinstance(v, (torch.Tensor, np.ndarray)): - if np.prod(v.shape) != 1: - raise ValueError(f"v must be 0 or 1 dimension: {len(v.shape)}") - v = v.item() - - if isinstance(weight, (torch.Tensor, np.ndarray)): - if np.prod(weight.shape) != 1: - raise ValueError(f"weight must be 0 or 1 dimension: {len(weight.shape)}") - weight = weight.item() - - if weight is not None: - retval = WeightedAverage(v, weight) - else: - retval = Average(v) - return retval - - -def aggregate(values: Sequence["ReportedValue"]) -> Num: - - for v in values: - if not isinstance(v, type(values[0])): - raise ValueError( - f"Can't use different Reported type together: " - f"{type(v)} != {type(values[0])}" - ) - - if len(values) == 0: - warnings.warn("No stats found") - retval = np.nan - - elif isinstance(values[0], Average): - retval = np.nanmean([v.value for v in values]) - - elif isinstance(values[0], WeightedAverage): - # Excludes non finite values - invalid_indices = set() - for i, v in enumerate(values): - if not np.isfinite(v.value) or not np.isfinite(v.weight): - invalid_indices.add(i) - values = [v for i, v in enumerate(values) if i not in invalid_indices] - - if len(values) != 0: - # Calc weighed average. Weights are changed to sum-to-1. - sum_weights = sum(v.weight for i, v in enumerate(values)) - sum_value = sum(v.value * v.weight for i, v in enumerate(values)) - if sum_weights == 0: - warnings.warn("weight is zero") - retval = np.nan - else: - retval = sum_value / sum_weights - else: - warnings.warn("No valid stats found") - retval = np.nan - - else: - raise NotImplementedError(f"type={type(values[0])}") - return retval - - -def wandb_get_prefix(key: str): - if key.startswith("valid"): - return "valid/" - if key.startswith("train"): - return "train/" - if key.startswith("attn"): - return "attn/" - return "metrics/" - - -class ReportedValue: - pass - - -@dataclasses.dataclass(frozen=True) -class Average(ReportedValue): - value: Num - - -@dataclasses.dataclass(frozen=True) -class WeightedAverage(ReportedValue): - value: Tuple[Num, Num] - weight: Num - - -class SubReporter: - """This class is used in Reporter. - - See the docstring of Reporter for the usage. - """ - - def __init__(self, key: str, epoch: int, total_count: int): - self.key = key - self.epoch = epoch - self.start_time = time.perf_counter() - self.stats = defaultdict(list) - self._finished = False - self.total_count = total_count - self.count = 0 - self._seen_keys_in_the_step = set() - - def get_total_count(self) -> int: - """Returns the number of iterations over all epochs.""" - return self.total_count - - def get_epoch(self) -> int: - return self.epoch - - def next(self): - """Close up this step and reset state for the next step""" - for key, stats_list in self.stats.items(): - if key not in self._seen_keys_in_the_step: - # Fill nan value if the key is not registered in this step - if isinstance(stats_list[0], WeightedAverage): - stats_list.append(to_reported_value(np.nan, 0)) - elif isinstance(stats_list[0], Average): - stats_list.append(to_reported_value(np.nan)) - else: - raise NotImplementedError(f"type={type(stats_list[0])}") - - assert len(stats_list) == self.count, (len(stats_list), self.count) - - self._seen_keys_in_the_step = set() - - def register( - self, - stats: Dict[str, Optional[Union[Num, Dict[str, Num]]]], - weight: Num = None, - ) -> None: - if self._finished: - raise RuntimeError("Already finished") - if len(self._seen_keys_in_the_step) == 0: - # Increment count as the first register in this step - self.total_count += 1 - self.count += 1 - - for key2, v in stats.items(): - if key2 in _reserved: - raise RuntimeError(f"{key2} is reserved.") - if key2 in self._seen_keys_in_the_step: - raise RuntimeError(f"{key2} is registered twice.") - if v is None: - v = np.nan - r = to_reported_value(v, weight) - - if key2 not in self.stats: - # If it's the first time to register the key, - # append nan values in front of the the value - # to make it same length to the other stats - # e.g. - # stat A: [0.4, 0.3, 0.5] - # stat B: [nan, nan, 0.2] - nan = to_reported_value(np.nan, None if weight is None else 0) - self.stats[key2].extend( - r if i == self.count - 1 else nan for i in range(self.count) - ) - else: - self.stats[key2].append(r) - self._seen_keys_in_the_step.add(key2) - - def log_message(self, start: int = None, end: int = None, num_updates: int = None) -> str: - if self._finished: - raise RuntimeError("Already finished") - if start is None: - start = 0 - if start < 0: - start = self.count + start - if end is None: - end = self.count - - if self.count == 0 or start == end: - return "" - - message = f"{self.epoch}epoch:{self.key}:" f"{start + 1}-{end}batch:" - if num_updates is not None: - message += f"{num_updates}num_updates: " - - for idx, (key2, stats_list) in enumerate(self.stats.items()): - assert len(stats_list) == self.count, (len(stats_list), self.count) - # values: List[ReportValue] - values = stats_list[start:end] - if idx != 0 and idx != len(stats_list): - message += ", " - - v = aggregate(values) - if abs(v) > 1.0e3: - message += f"{key2}={v:.3e}" - elif abs(v) > 1.0e-3: - message += f"{key2}={v:.3f}" - else: - message += f"{key2}={v:.3e}" - return message - - def tensorboard_add_scalar(self, summary_writer, start: int = None): - if start is None: - start = 0 - if start < 0: - start = self.count + start - - for key2, stats_list in self.stats.items(): - assert len(stats_list) == self.count, (len(stats_list), self.count) - # values: List[ReportValue] - values = stats_list[start:] - v = aggregate(values) - summary_writer.add_scalar(f"{key2}", v, self.total_count) - - def wandb_log(self, start: int = None): - import wandb - - if start is None: - start = 0 - if start < 0: - start = self.count + start - - d = {} - for key2, stats_list in self.stats.items(): - assert len(stats_list) == self.count, (len(stats_list), self.count) - # values: List[ReportValue] - values = stats_list[start:] - v = aggregate(values) - d[wandb_get_prefix(key2) + key2] = v - d["iteration"] = self.total_count - wandb.log(d) - - def finished(self) -> None: - self._finished = True - - @contextmanager - def measure_time(self, name: str): - start = time.perf_counter() - yield start - t = time.perf_counter() - start - self.register({name: t}) - - def measure_iter_time(self, iterable, name: str): - iterator = iter(iterable) - while True: - try: - start = time.perf_counter() - retval = next(iterator) - t = time.perf_counter() - start - self.register({name: t}) - yield retval - except StopIteration: - break - - -class Reporter: - """Reporter class. - - Examples: - - >>> reporter = Reporter() - >>> with reporter.observe('train') as sub_reporter: - ... for batch in iterator: - ... stats = dict(loss=0.2) - ... sub_reporter.register(stats) - - """ - - def __init__(self, epoch: int = 0): - if epoch < 0: - raise ValueError(f"epoch must be 0 or more: {epoch}") - self.epoch = epoch - # stats: Dict[int, Dict[str, Dict[str, float]]] - # e.g. self.stats[epoch]['train']['loss'] - self.stats = {} - - def get_epoch(self) -> int: - return self.epoch - - def set_epoch(self, epoch: int) -> None: - if epoch < 0: - raise ValueError(f"epoch must be 0 or more: {epoch}") - self.epoch = epoch - - @contextmanager - def observe(self, key: str, epoch: int = None) -> ContextManager[SubReporter]: - sub_reporter = self.start_epoch(key, epoch) - yield sub_reporter - # Receive the stats from sub_reporter - self.finish_epoch(sub_reporter) - - def start_epoch(self, key: str, epoch: int = None) -> SubReporter: - if epoch is not None: - if epoch < 0: - raise ValueError(f"epoch must be 0 or more: {epoch}") - self.epoch = epoch - - if self.epoch - 1 not in self.stats or key not in self.stats[self.epoch - 1]: - # If the previous epoch doesn't exist for some reason, - # maybe due to bug, this case also indicates 0-count. - if self.epoch - 1 != 0: - warnings.warn( - f"The stats of the previous epoch={self.epoch - 1}" - f"doesn't exist." - ) - total_count = 0 - else: - total_count = self.stats[self.epoch - 1][key]["total_count"] - - sub_reporter = SubReporter(key, self.epoch, total_count) - # Clear the stats for the next epoch if it exists - self.stats.pop(epoch, None) - return sub_reporter - - def finish_epoch(self, sub_reporter: SubReporter) -> None: - if self.epoch != sub_reporter.epoch: - raise RuntimeError( - f"Don't change epoch during observation: " - f"{self.epoch} != {sub_reporter.epoch}" - ) - - # Calc mean of current stats and set it as previous epochs stats - stats = {} - for key2, values in sub_reporter.stats.items(): - v = aggregate(values) - stats[key2] = v - - stats["time"] = datetime.timedelta( - seconds=time.perf_counter() - sub_reporter.start_time - ) - stats["total_count"] = sub_reporter.total_count - if LooseVersion(torch.__version__) >= LooseVersion("1.4.0"): - if torch.cuda.is_initialized(): - stats["gpu_max_cached_mem_GB"] = ( - torch.cuda.max_memory_reserved() / 2 ** 30 - ) - else: - if torch.cuda.is_available() and torch.cuda.max_memory_cached() > 0: - stats["gpu_cached_mem_GB"] = torch.cuda.max_memory_cached() / 2 ** 30 - - self.stats.setdefault(self.epoch, {})[sub_reporter.key] = stats - sub_reporter.finished() - - def sort_epochs_and_values( - self, key: str, key2: str, mode: str - ) -> List[Tuple[int, float]]: - """Return the epoch which resulted the best value. - - Example: - >>> val = reporter.sort_epochs_and_values('eval', 'loss', 'min') - >>> e_1best, v_1best = val[0] - >>> e_2best, v_2best = val[1] - """ - if mode not in ("min", "max"): - raise ValueError(f"mode must min or max: {mode}") - if not self.has(key, key2): - raise KeyError(f"{key}.{key2} is not found: {self.get_all_keys()}") - - # iterate from the last epoch - values = [(e, self.stats[e][key][key2]) for e in self.stats] - - if mode == "min": - values = sorted(values, key=lambda x: x[1]) - else: - values = sorted(values, key=lambda x: -x[1]) - return values - - def sort_epochs(self, key: str, key2: str, mode: str) -> List[int]: - return [e for e, v in self.sort_epochs_and_values(key, key2, mode)] - - def sort_values(self, key: str, key2: str, mode: str) -> List[float]: - return [v for e, v in self.sort_epochs_and_values(key, key2, mode)] - - def get_best_epoch(self, key: str, key2: str, mode: str, nbest: int = 0) -> int: - return self.sort_epochs(key, key2, mode)[nbest] - - def check_early_stopping( - self, - patience: int, - key1: str, - key2: str, - mode: str, - epoch: int = None, - logger=None, - ) -> bool: - if logger is None: - logger = logging - if epoch is None: - epoch = self.get_epoch() - - best_epoch = self.get_best_epoch(key1, key2, mode) - if epoch - best_epoch > patience: - logger.info( - f"[Early stopping] {key1}.{key2} has not been " - f"improved {epoch - best_epoch} epochs continuously. " - f"The training was stopped at {epoch}epoch" - ) - return True - else: - return False - - def has(self, key: str, key2: str, epoch: int = None) -> bool: - if epoch is None: - epoch = self.get_epoch() - return ( - epoch in self.stats - and key in self.stats[epoch] - and key2 in self.stats[epoch][key] - ) - - def log_message(self, epoch: int = None) -> str: - if epoch is None: - epoch = self.get_epoch() - - message = "" - for key, d in self.stats[epoch].items(): - _message = "" - for key2, v in d.items(): - if v is not None: - if len(_message) != 0: - _message += ", " - if isinstance(v, float): - if abs(v) > 1.0e3: - _message += f"{key2}={v:.3e}" - elif abs(v) > 1.0e-3: - _message += f"{key2}={v:.3f}" - else: - _message += f"{key2}={v:.3e}" - elif isinstance(v, datetime.timedelta): - _v = humanfriendly.format_timespan(v) - _message += f"{key2}={_v}" - else: - _message += f"{key2}={v}" - if len(_message) != 0: - if len(message) == 0: - message += f"{epoch}epoch results: " - else: - message += ", " - message += f"[{key}] {_message}" - return message - - def get_value(self, key: str, key2: str, epoch: int = None): - if not self.has(key, key2): - raise KeyError(f"{key}.{key2} is not found in stats: {self.get_all_keys()}") - if epoch is None: - epoch = self.get_epoch() - return self.stats[epoch][key][key2] - - def get_keys(self, epoch: int = None) -> Tuple[str, ...]: - """Returns keys1 e.g. train,eval.""" - if epoch is None: - epoch = self.get_epoch() - return tuple(self.stats[epoch]) - - def get_keys2(self, key: str, epoch: int = None) -> Tuple[str, ...]: - """Returns keys2 e.g. loss,acc.""" - if epoch is None: - epoch = self.get_epoch() - d = self.stats[epoch][key] - keys2 = tuple(k for k in d if k not in ("time", "total_count")) - return keys2 - - def get_all_keys(self, epoch: int = None) -> Tuple[Tuple[str, str], ...]: - if epoch is None: - epoch = self.get_epoch() - all_keys = [] - for key in self.stats[epoch]: - for key2 in self.stats[epoch][key]: - all_keys.append((key, key2)) - return tuple(all_keys) - - def tensorboard_add_scalar( - self, summary_writer, epoch: int = None, key1: str = None - ): - if epoch is None: - epoch = self.get_epoch() - total_count = self.stats[epoch]["train"]["total_count"] - if key1 == "train": - summary_writer.add_scalar("iter_epoch", epoch, total_count) - - if key1 is not None: - key1_iterator = tuple([key1]) - else: - key1_iterator = self.get_keys(epoch) - - for key1 in key1_iterator: - for key2 in self.get_keys2(key1): - summary_writer.add_scalar( - f"{key2}", self.stats[epoch][key1][key2], total_count - ) - - def wandb_log(self, epoch: int = None): - import wandb - - if epoch is None: - epoch = self.get_epoch() - - d = {} - for key1 in self.get_keys(epoch): - for key2 in self.stats[epoch][key1]: - if key2 in ("time", "total_count"): - continue - key = f"{key1}_{key2}_epoch" - d[wandb_get_prefix(key) + key] = self.stats[epoch][key1][key2] - d["epoch"] = epoch - wandb.log(d) - - def state_dict(self): - return {"stats": self.stats, "epoch": self.epoch} - - def load_state_dict(self, state_dict: dict): - self.epoch = state_dict["epoch"] - self.stats = state_dict["stats"] diff --git a/funasr/train/trainer.py b/funasr/train/trainer.py deleted file mode 100644 index a5069d04c..000000000 --- a/funasr/train/trainer.py +++ /dev/null @@ -1,878 +0,0 @@ -# Copyright ESPnet (https://github.com/espnet/espnet). All Rights Reserved. -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -"""Trainer module.""" -import argparse -from contextlib import contextmanager -import dataclasses -from dataclasses import is_dataclass -from distutils.version import LooseVersion -import logging -from pathlib import Path -import time -from typing import Dict -from typing import Iterable -from typing import List -from typing import Optional -from typing import Sequence -from typing import Tuple -from typing import Union - -import humanfriendly -import oss2 -from io import BytesIO -import os -import numpy as np -import torch -import torch.nn -import torch.optim - -from funasr.iterators.abs_iter_factory import AbsIterFactory -from funasr.main_funcs.average_nbest_models import average_nbest_models -from funasr.main_funcs.calculate_all_attentions import calculate_all_attentions -from funasr.schedulers.abs_scheduler import AbsBatchStepScheduler -from funasr.schedulers.abs_scheduler import AbsEpochStepScheduler -from funasr.schedulers.abs_scheduler import AbsScheduler -from funasr.schedulers.abs_scheduler import AbsValEpochStepScheduler -from funasr.torch_utils.add_gradient_noise import add_gradient_noise -from funasr.torch_utils.device_funcs import to_device -from funasr.torch_utils.recursive_op import recursive_average -from funasr.torch_utils.set_all_random_seed import set_all_random_seed -from funasr.models.base_model import FunASRModel -from funasr.train.distributed_utils import DistributedOption -from funasr.train.reporter import Reporter -from funasr.train.reporter import SubReporter -from funasr.utils.build_dataclass import build_dataclass -from funasr.utils.kwargs2args import kwargs2args - -if torch.distributed.is_available(): - from torch.distributed import ReduceOp - -if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): - from torch.cuda.amp import autocast - from torch.cuda.amp import GradScaler -else: - # Nothing to do if torch<1.6.0 - @contextmanager - def autocast(enabled=True): - yield - - GradScaler = None - -try: - import fairscale -except ImportError: - fairscale = None - - -@dataclasses.dataclass -class TrainerOptions: - ngpu: int - resume: bool - use_amp: bool - train_dtype: str - grad_noise: bool - accum_grad: int - grad_clip: float - grad_clip_type: float - log_interval: Optional[int] - no_forward_run: bool - use_tensorboard: bool - use_wandb: bool - output_dir: Union[Path, str] - max_epoch: int - max_update: int - seed: int - sharded_ddp: bool - patience: Optional[int] - keep_nbest_models: Union[int, List[int]] - nbest_averaging_interval: int - early_stopping_criterion: Sequence[str] - best_model_criterion: Sequence[Sequence[str]] - val_scheduler_criterion: Sequence[str] - unused_parameters: bool - wandb_model_log_interval: int - use_pai: bool - oss_bucket: Union[oss2.Bucket, None] - batch_interval: int - bias_grad_times: float - -class Trainer: - """Trainer having a optimizer. - - If you'd like to use multiple optimizers, then inherit this class - and override the methods if necessary - at least "train_one_epoch()" - - >>> class TwoOptimizerTrainer(Trainer): - ... @classmethod - ... def add_arguments(cls, parser): - ... ... - ... - ... @classmethod - ... def train_one_epoch(cls, model, optimizers, ...): - ... loss1 = model.model1(...) - ... loss1.backward() - ... optimizers[0].step() - ... - ... loss2 = model.model2(...) - ... loss2.backward() - ... optimizers[1].step() - - """ - - def __init__(self): - raise RuntimeError("This class can't be instantiated.") - - @classmethod - def build_options(cls, args: argparse.Namespace) -> TrainerOptions: - """Build options consumed by train(), eval()""" - return build_dataclass(TrainerOptions, args) - - @classmethod - def add_arguments(cls, parser: argparse.ArgumentParser): - """Reserved for future development of another Trainer""" - pass - - @staticmethod - def resume( - checkpoint: Union[str, Path], - model: torch.nn.Module, - reporter: Reporter, - optimizers: Sequence[torch.optim.Optimizer], - schedulers: Sequence[Optional[AbsScheduler]], - scaler: Optional[GradScaler], - ngpu: int = 0, - oss_bucket=None, - ): - if oss_bucket is None: - if os.path.exists(checkpoint): - states = torch.load( - checkpoint, - map_location=f"cuda:{torch.cuda.current_device()}" if ngpu > 0 else "cpu", - ) - - else: - return 0 - else: - if oss_bucket.object_exists(checkpoint): - buffer = BytesIO(oss_bucket.get_object(checkpoint).read()) - states = torch.load(buffer, map_location=f"cuda:{torch.cuda.current_device()}" if ngpu > 0 else "cpu",) - else: - return 0 - model.load_state_dict(states["model"]) - reporter.load_state_dict(states["reporter"]) - for optimizer, state in zip(optimizers, states["optimizers"]): - optimizer.load_state_dict(state) - for scheduler, state in zip(schedulers, states["schedulers"]): - if scheduler is not None: - scheduler.load_state_dict(state) - if scaler is not None: - if states["scaler"] is None: - logging.warning("scaler state is not found") - else: - scaler.load_state_dict(states["scaler"]) - - logging.info(f"The training was resumed using {checkpoint}") - - @classmethod - def run( - cls, - model: FunASRModel, - optimizers: Sequence[torch.optim.Optimizer], - schedulers: Sequence[Optional[AbsScheduler]], - train_iter_factory: AbsIterFactory, - valid_iter_factory: AbsIterFactory, - trainer_options, - distributed_option: DistributedOption, - ) -> None: - """Perform training. This method performs the main process of training.""" - # NOTE(kamo): Don't check the type more strictly as far trainer_options - assert is_dataclass(trainer_options), type(trainer_options) - assert len(optimizers) == len(schedulers), (len(optimizers), len(schedulers)) - - if isinstance(trainer_options.keep_nbest_models, int): - keep_nbest_models = [trainer_options.keep_nbest_models] - else: - if len(trainer_options.keep_nbest_models) == 0: - logging.warning("No keep_nbest_models is given. Change to [1]") - trainer_options.keep_nbest_models = [1] - keep_nbest_models = trainer_options.keep_nbest_models - - output_dir = Path(trainer_options.output_dir) - reporter = Reporter() - if trainer_options.use_amp: - if LooseVersion(torch.__version__) < LooseVersion("1.6.0"): - raise RuntimeError( - "Require torch>=1.6.0 for Automatic Mixed Precision" - ) - if trainer_options.sharded_ddp: - if fairscale is None: - raise RuntimeError( - "Requiring fairscale. Do 'pip install fairscale'" - ) - scaler = fairscale.optim.grad_scaler.ShardedGradScaler() - else: - scaler = GradScaler() - else: - scaler = None - - if trainer_options.resume: - cls.resume( - checkpoint=os.path.join(trainer_options.output_dir, "checkpoint.pb") if trainer_options.use_pai else output_dir / "checkpoint.pb", - model=model, - optimizers=optimizers, - schedulers=schedulers, - reporter=reporter, - scaler=scaler, - ngpu=trainer_options.ngpu, - oss_bucket=trainer_options.oss_bucket if trainer_options.use_pai else None, - ) - - start_epoch = reporter.get_epoch() + 1 - if start_epoch == trainer_options.max_epoch + 1: - logging.warning( - f"The training has already reached at max_epoch: {start_epoch}" - ) - - if distributed_option.distributed: - if trainer_options.sharded_ddp: - dp_model = fairscale.nn.data_parallel.ShardedDataParallel( - module=model, - sharded_optimizer=optimizers, - ) - else: - dp_model = torch.nn.parallel.DistributedDataParallel( - model, find_unused_parameters=trainer_options.unused_parameters) - elif distributed_option.ngpu > 1: - dp_model = torch.nn.parallel.DataParallel( - model, - device_ids=list(range(distributed_option.ngpu)), - ) - else: - # NOTE(kamo): DataParallel also should work with ngpu=1, - # but for debuggability it's better to keep this block. - dp_model = model - - if trainer_options.use_tensorboard and ( - not distributed_option.distributed or distributed_option.dist_rank == 0 - ): - from torch.utils.tensorboard import SummaryWriter - if trainer_options.use_pai: - train_summary_writer = SummaryWriter( - os.path.join(trainer_options.output_dir, "tensorboard/train") - ) - valid_summary_writer = SummaryWriter( - os.path.join(trainer_options.output_dir, "tensorboard/valid") - ) - else: - train_summary_writer = SummaryWriter( - str(output_dir / "tensorboard" / "train") - ) - valid_summary_writer = SummaryWriter( - str(output_dir / "tensorboard" / "valid") - ) - else: - train_summary_writer = None - - start_time = time.perf_counter() - for iepoch in range(start_epoch, trainer_options.max_epoch + 1): - if iepoch != start_epoch: - logging.info( - "{}/{}epoch started. Estimated time to finish: {} hours".format( - iepoch, - trainer_options.max_epoch, - (time.perf_counter() - start_time) / 3600.0 / (iepoch - start_epoch) * ( - trainer_options.max_epoch - iepoch + 1), - ) - ) - else: - logging.info(f"{iepoch}/{trainer_options.max_epoch}epoch started") - set_all_random_seed(trainer_options.seed + iepoch) - - reporter.set_epoch(iepoch) - # 1. Train and validation for one-epoch - with reporter.observe("train") as sub_reporter: - all_steps_are_invalid, max_update_stop = cls.train_one_epoch( - model=dp_model, - optimizers=optimizers, - schedulers=schedulers, - iterator=train_iter_factory.build_iter(iepoch), - reporter=sub_reporter, - scaler=scaler, - summary_writer=train_summary_writer, - options=trainer_options, - distributed_option=distributed_option, - ) - - with reporter.observe("valid") as sub_reporter: - cls.validate_one_epoch( - model=dp_model, - iterator=valid_iter_factory.build_iter(iepoch), - reporter=sub_reporter, - options=trainer_options, - distributed_option=distributed_option, - ) - - # 2. LR Scheduler step - for scheduler in schedulers: - if isinstance(scheduler, AbsValEpochStepScheduler): - scheduler.step( - reporter.get_value(*trainer_options.val_scheduler_criterion) - ) - elif isinstance(scheduler, AbsEpochStepScheduler): - scheduler.step() - if trainer_options.sharded_ddp: - for optimizer in optimizers: - if isinstance(optimizer, fairscale.optim.oss.OSS): - optimizer.consolidate_state_dict() - - if not distributed_option.distributed or distributed_option.dist_rank == 0: - # 3. Report the results - logging.info(reporter.log_message()) - if train_summary_writer is not None: - reporter.tensorboard_add_scalar(train_summary_writer, key1="train") - reporter.tensorboard_add_scalar(valid_summary_writer, key1="valid") - if trainer_options.use_wandb: - reporter.wandb_log() - - # save tensorboard on oss - if trainer_options.use_pai and train_summary_writer is not None: - def write_tensorboard_summary(summary_writer_path, oss_bucket): - file_list = [] - for root, dirs, files in os.walk(summary_writer_path, topdown=False): - for name in files: - file_full_path = os.path.join(root, name) - file_list.append(file_full_path) - - for file_full_path in file_list: - with open(file_full_path, "rb") as f: - oss_bucket.put_object(file_full_path, f) - - write_tensorboard_summary(os.path.join(trainer_options.output_dir, "tensorboard/train"), trainer_options.oss_bucket) - write_tensorboard_summary(os.path.join(trainer_options.output_dir, "tensorboard/valid"), trainer_options.oss_bucket) - - - # 4. Save/Update the checkpoint - if trainer_options.use_pai: - buffer = BytesIO() - torch.save( - { - "model": model.state_dict(), - "reporter": reporter.state_dict(), - "optimizers": [o.state_dict() for o in optimizers], - "schedulers": [ - s.state_dict() if s is not None else None - for s in schedulers - ], - "scaler": scaler.state_dict() if scaler is not None else None, - "ema_model": model.encoder.ema.model.state_dict() - if hasattr(model, "encoder") and hasattr(model.encoder, "ema") and model.encoder.ema is not None else None, - }, - buffer, - ) - trainer_options.oss_bucket.put_object(os.path.join(trainer_options.output_dir, "checkpoint.pb"), buffer.getvalue()) - else: - torch.save( - { - "model": model.state_dict(), - "reporter": reporter.state_dict(), - "optimizers": [o.state_dict() for o in optimizers], - "schedulers": [ - s.state_dict() if s is not None else None - for s in schedulers - ], - "scaler": scaler.state_dict() if scaler is not None else None, - }, - output_dir / "checkpoint.pb", - ) - - # 5. Save and log the model and update the link to the best model - if trainer_options.use_pai: - buffer = BytesIO() - torch.save(model.state_dict(), buffer) - trainer_options.oss_bucket.put_object(os.path.join(trainer_options.output_dir, - f"{iepoch}epoch.pb"),buffer.getvalue()) - else: - torch.save(model.state_dict(), output_dir / f"{iepoch}epoch.pb") - - # Creates a sym link latest.pb -> {iepoch}epoch.pb - if trainer_options.use_pai: - p = os.path.join(trainer_options.output_dir, "latest.pb") - if trainer_options.oss_bucket.object_exists(p): - trainer_options.oss_bucket.delete_object(p) - trainer_options.oss_bucket.copy_object(trainer_options.oss_bucket.bucket_name, - os.path.join(trainer_options.output_dir, f"{iepoch}epoch.pb"), p) - else: - p = output_dir / "latest.pb" - if p.is_symlink() or p.exists(): - p.unlink() - p.symlink_to(f"{iepoch}epoch.pb") - - _improved = [] - for _phase, k, _mode in trainer_options.best_model_criterion: - # e.g. _phase, k, _mode = "train", "loss", "min" - if reporter.has(_phase, k): - best_epoch = reporter.get_best_epoch(_phase, k, _mode) - # Creates sym links if it's the best result - if best_epoch == iepoch: - if trainer_options.use_pai: - p = os.path.join(trainer_options.output_dir, f"{_phase}.{k}.best.pb") - if trainer_options.oss_bucket.object_exists(p): - trainer_options.oss_bucket.delete_object(p) - trainer_options.oss_bucket.copy_object(trainer_options.oss_bucket.bucket_name, - os.path.join(trainer_options.output_dir, f"{iepoch}epoch.pb"),p) - else: - p = output_dir / f"{_phase}.{k}.best.pb" - if p.is_symlink() or p.exists(): - p.unlink() - p.symlink_to(f"{iepoch}epoch.pb") - _improved.append(f"{_phase}.{k}") - if len(_improved) == 0: - logging.info("There are no improvements in this epoch") - else: - logging.info( - "The best model has been updated: " + ", ".join(_improved) - ) - - log_model = ( - trainer_options.wandb_model_log_interval > 0 - and iepoch % trainer_options.wandb_model_log_interval == 0 - ) - if log_model and trainer_options.use_wandb: - import wandb - - logging.info("Logging Model on this epoch :::::") - artifact = wandb.Artifact( - name=f"model_{wandb.run.id}", - type="model", - metadata={"improved": _improved}, - ) - artifact.add_file(str(output_dir / f"{iepoch}epoch.pb")) - aliases = [ - f"epoch-{iepoch}", - "best" if best_epoch == iepoch else "", - ] - wandb.log_artifact(artifact, aliases=aliases) - - # 6. Remove the model files excluding n-best epoch and latest epoch - _removed = [] - # Get the union set of the n-best among multiple criterion - nbests = set().union( - *[ - set(reporter.sort_epochs(ph, k, m)[: max(keep_nbest_models)]) - for ph, k, m in trainer_options.best_model_criterion - if reporter.has(ph, k) - ] - ) - - # Generated n-best averaged model - if ( - trainer_options.nbest_averaging_interval > 0 - and iepoch % trainer_options.nbest_averaging_interval == 0 - ): - average_nbest_models( - reporter=reporter, - output_dir=output_dir, - best_model_criterion=trainer_options.best_model_criterion, - nbest=keep_nbest_models, - suffix=f"till{iepoch}epoch", - oss_bucket=trainer_options.oss_bucket, - pai_output_dir=trainer_options.output_dir, - ) - - for e in range(1, iepoch): - if trainer_options.use_pai: - p = os.path.join(trainer_options.output_dir, f"{e}epoch.pb") - if trainer_options.oss_bucket.object_exists(p) and e not in nbests: - trainer_options.oss_bucket.delete_object(p) - _removed.append(str(p)) - else: - p = output_dir / f"{e}epoch.pb" - if p.exists() and e not in nbests: - p.unlink() - _removed.append(str(p)) - if len(_removed) != 0: - logging.info("The model files were removed: " + ", ".join(_removed)) - - # 7. If any updating haven't happened, stops the training - if all_steps_are_invalid: - logging.warning( - f"The gradients at all steps are invalid in this epoch. " - f"Something seems wrong. This training was stopped at {iepoch}epoch" - ) - break - - if max_update_stop: - logging.info( - f"Stopping training due to " - f"num_updates: {trainer_options.num_updates} >= max_update: {trainer_options.max_update}" - ) - break - - # 8. Check early stopping - if trainer_options.patience is not None: - if reporter.check_early_stopping( - trainer_options.patience, *trainer_options.early_stopping_criterion - ): - break - - else: - logging.info( - f"The training was finished at {trainer_options.max_epoch} epochs " - ) - - # Generated n-best averaged model - if not distributed_option.distributed or distributed_option.dist_rank == 0: - average_nbest_models( - reporter=reporter, - output_dir=output_dir, - best_model_criterion=trainer_options.best_model_criterion, - nbest=keep_nbest_models, - oss_bucket=trainer_options.oss_bucket, - pai_output_dir=trainer_options.output_dir, - ) - - @classmethod - def train_one_epoch( - cls, - model: torch.nn.Module, - iterator: Iterable[Tuple[List[str], Dict[str, torch.Tensor]]], - optimizers: Sequence[torch.optim.Optimizer], - schedulers: Sequence[Optional[AbsScheduler]], - scaler: Optional[GradScaler], - reporter: SubReporter, - summary_writer, - options: TrainerOptions, - distributed_option: DistributedOption, - ) -> Tuple[bool, bool]: - - grad_noise = options.grad_noise - accum_grad = options.accum_grad - grad_clip = options.grad_clip - grad_clip_type = options.grad_clip_type - log_interval = options.log_interval - no_forward_run = options.no_forward_run - ngpu = options.ngpu - use_wandb = options.use_wandb - bias_grad_times = options.bias_grad_times - distributed = distributed_option.distributed - - if bias_grad_times != 1.0: - logging.warning("Using bias_grad_times: {} for gradient scaling".format(bias_grad_times)) - if log_interval is None: - try: - log_interval = max(len(iterator) // 20, 10) - except TypeError: - log_interval = 100 - - model.train() - all_steps_are_invalid = True - max_update_stop = False - # [For distributed] Because iteration counts are not always equals between - # processes, send stop-flag to the other processes if iterator is finished - iterator_stop = torch.tensor(0).to("cuda" if ngpu > 0 else "cpu") - - #get the rank - rank = distributed_option.dist_rank - #get the num batch updates - num_batch_updates = 0 - #ouput dir - output_dir = Path(options.output_dir) - #batch interval - batch_interval = options.batch_interval - - start_time = time.perf_counter() - for iiter, (_, batch) in enumerate( - reporter.measure_iter_time(iterator, "iter_time"), 1 - ): - assert isinstance(batch, dict), type(batch) - - if batch_interval > 0 and (not distributed_option.distributed or rank == 0): - if hasattr(model, "num_updates") or (hasattr(model, "module") and hasattr(model.module, "num_updates")): - num_batch_updates = model.get_num_updates() if hasattr(model,"num_updates") else model.module.get_num_updates() - if num_batch_updates % batch_interval == 0: - if options.use_pai and options.oss_bucket is not None: - buffer = BytesIO() - if hasattr(model, "module"): - torch.save(model.module.state_dict(), buffer) - else: - torch.save(model.state_dict(), buffer) - options.oss_bucket.put_object(os.path.join(output_dir, f"{num_batch_updates}step.pb"), buffer.getvalue()) - else: - if hasattr(model, "module"): - torch.save(model.module.state_dict(), os.path.join(output_dir, f"{num_batch_updates}step.pb")) - else: - torch.save(model.state_dict(), os.path.join(output_dir, f"{num_batch_updates}step.pb")) - - if distributed: - torch.distributed.all_reduce(iterator_stop, ReduceOp.SUM) - if iterator_stop > 0: - break - - batch = to_device(batch, "cuda" if ngpu > 0 else "cpu") - if no_forward_run: - all_steps_are_invalid = False - continue - - if iiter == 1 and summary_writer is not None: - try: - args = kwargs2args(model.forward, batch) - except (ValueError, TypeError): - logging.warning( - "inpect.signature() is failed for the model. " - "The graph can't be added for tensorboard." - ) - else: - try: - summary_writer.add_graph(model, args, use_strict_trace=False) - except Exception: - logging.warning( - "summary_writer.add_graph() is failed for the model. " - "The graph can't be added for tensorboard." - ) - del args - - with autocast(scaler is not None): - with reporter.measure_time("forward_time"): - retval = model(**batch) - - # Note(kamo): - # Supporting two patterns for the returned value from the model - # a. dict type - if isinstance(retval, dict): - loss = retval["loss"] - stats = retval["stats"] - weight = retval["weight"] - optim_idx = retval.get("optim_idx") - if optim_idx is not None and not isinstance(optim_idx, int): - if not isinstance(optim_idx, torch.Tensor): - raise RuntimeError( - "optim_idx must be int or 1dim torch.Tensor, " - f"but got {type(optim_idx)}" - ) - if optim_idx.dim() >= 2: - raise RuntimeError( - "optim_idx must be int or 1dim torch.Tensor, " - f"but got {optim_idx.dim()}dim tensor" - ) - if optim_idx.dim() == 1: - for v in optim_idx: - if v != optim_idx[0]: - raise RuntimeError( - "optim_idx must be 1dim tensor " - "having same values for all entries" - ) - optim_idx = optim_idx[0].item() - else: - optim_idx = optim_idx.item() - - # b. tuple or list type - else: - loss, stats, weight = retval - optim_idx = None - - stats = {k: v for k, v in stats.items() if v is not None} - if ngpu > 1 or distributed: - # Apply weighted averaging for loss and stats - loss = (loss * weight.type(loss.dtype)).sum() - - # if distributed, this method can also apply all_reduce() - stats, weight = recursive_average(stats, weight, distributed) - - # Now weight is summation over all workers - loss /= weight - if distributed: - # NOTE(kamo): Multiply world_size because DistributedDataParallel - # automatically normalizes the gradient by world_size. - loss *= torch.distributed.get_world_size() - - loss /= accum_grad - - reporter.register(stats, weight) - - with reporter.measure_time("backward_time"): - if scaler is not None: - # Scales loss. Calls backward() on scaled loss - # to create scaled gradients. - # Backward passes under autocast are not recommended. - # Backward ops run in the same dtype autocast chose - # for corresponding forward ops. - scaler.scale(loss).backward() - else: - loss.backward() - - if iiter % accum_grad == 0: - if scaler is not None: - # Unscales the gradients of optimizer's assigned params in-place - for iopt, optimizer in enumerate(optimizers): - if optim_idx is not None and iopt != optim_idx: - continue - scaler.unscale_(optimizer) - - # gradient noise injection - if grad_noise: - add_gradient_noise( - model, - reporter.get_total_count(), - duration=100, - eta=1.0, - scale_factor=0.55, - ) - - # for contextual training - if bias_grad_times != 1.0: - # contextual related parameter names - cr_pnames = ["bias_encoder", "bias_embed", "decoder.bias_decoder", "decoder.bias_output"] - for name, param in model.named_parameters(): - for cr_pname in cr_pnames: - if cr_pname in name: - param.grad *= bias_grad_times - continue - - # compute the gradient norm to check if it is normal or not - grad_norm = torch.nn.utils.clip_grad_norm_( - model.parameters(), - max_norm=grad_clip, - norm_type=grad_clip_type, - ) - # PyTorch<=1.4, clip_grad_norm_ returns float value - if not isinstance(grad_norm, torch.Tensor): - grad_norm = torch.tensor(grad_norm) - - if not torch.isfinite(grad_norm): - logging.warning( - f"The grad norm is {grad_norm}. Skipping updating the model." - ) - - # Must invoke scaler.update() if unscale_() is used in the iteration - # to avoid the following error: - # RuntimeError: unscale_() has already been called - # on this optimizer since the last update(). - # Note that if the gradient has inf/nan values, - # scaler.step skips optimizer.step(). - if scaler is not None: - for iopt, optimizer in enumerate(optimizers): - if optim_idx is not None and iopt != optim_idx: - continue - scaler.step(optimizer) - scaler.update() - - else: - all_steps_are_invalid = False - with reporter.measure_time("optim_step_time"): - for iopt, (optimizer, scheduler) in enumerate( - zip(optimizers, schedulers) - ): - if optim_idx is not None and iopt != optim_idx: - continue - if scaler is not None: - # scaler.step() first unscales the gradients of - # the optimizer's assigned params. - scaler.step(optimizer) - # Updates the scale for next iteration. - scaler.update() - else: - optimizer.step() - if isinstance(scheduler, AbsBatchStepScheduler): - scheduler.step() - for iopt, optimizer in enumerate(optimizers): - if optim_idx is not None and iopt != optim_idx: - continue - optimizer.zero_grad() - - # Register lr and train/load time[sec/step], - # where step refers to accum_grad * mini-batch - reporter.register( - dict( - { - f"optim{i}_lr{j}": pg["lr"] - for i, optimizer in enumerate(optimizers) - for j, pg in enumerate(optimizer.param_groups) - if "lr" in pg - }, - train_time=time.perf_counter() - start_time, - ), - ) - start_time = time.perf_counter() - - # update num_updates - if distributed: - if hasattr(model.module, "num_updates"): - model.module.set_num_updates(model.module.get_num_updates() + 1) - options.num_updates = model.module.get_num_updates() - if model.module.get_num_updates() >= options.max_update: - max_update_stop = True - else: - if hasattr(model, "num_updates"): - model.set_num_updates(model.get_num_updates() + 1) - options.num_updates = model.get_num_updates() - if model.get_num_updates() >= options.max_update: - max_update_stop = True - - # NOTE(kamo): Call log_message() after next() - reporter.next() - if iiter % log_interval == 0: - num_updates = options.num_updates if hasattr(options, "num_updates") else None - logging.info(reporter.log_message(-log_interval, num_updates=num_updates)) - if summary_writer is not None: - reporter.tensorboard_add_scalar(summary_writer, -log_interval) - if use_wandb: - reporter.wandb_log() - - if max_update_stop: - break - - else: - if distributed: - iterator_stop.fill_(1) - torch.distributed.all_reduce(iterator_stop, ReduceOp.SUM) - return all_steps_are_invalid, max_update_stop - - @classmethod - @torch.no_grad() - def validate_one_epoch( - cls, - model: torch.nn.Module, - iterator: Iterable[Dict[str, torch.Tensor]], - reporter: SubReporter, - options: TrainerOptions, - distributed_option: DistributedOption, - ) -> None: - ngpu = options.ngpu - no_forward_run = options.no_forward_run - distributed = distributed_option.distributed - - model.eval() - - # [For distributed] Because iteration counts are not always equals between - # processes, send stop-flag to the other processes if iterator is finished - iterator_stop = torch.tensor(0).to("cuda" if ngpu > 0 else "cpu") - for (_, batch) in iterator: - assert isinstance(batch, dict), type(batch) - if distributed: - torch.distributed.all_reduce(iterator_stop, ReduceOp.SUM) - if iterator_stop > 0: - break - - batch = to_device(batch, "cuda" if ngpu > 0 else "cpu") - if no_forward_run: - continue - - retval = model(**batch) - if isinstance(retval, dict): - stats = retval["stats"] - weight = retval["weight"] - else: - _, stats, weight = retval - if ngpu > 1 or distributed: - # Apply weighted averaging for stats. - # if distributed, this method can also apply all_reduce() - stats, weight = recursive_average(stats, weight, distributed) - - reporter.register(stats, weight) - reporter.next() - - else: - if distributed: - iterator_stop.fill_(1) - torch.distributed.all_reduce(iterator_stop, ReduceOp.SUM) diff --git a/funasr/train_utils/__init__.py b/funasr/train_utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/funasr/torch_utils/add_gradient_noise.py b/funasr/train_utils/add_gradient_noise.py similarity index 100% rename from funasr/torch_utils/add_gradient_noise.py rename to funasr/train_utils/add_gradient_noise.py diff --git a/funasr/main_funcs/average_nbest_models.py b/funasr/train_utils/average_nbest_models.py similarity index 100% rename from funasr/main_funcs/average_nbest_models.py rename to funasr/train_utils/average_nbest_models.py diff --git a/funasr/main_funcs/collect_stats.py b/funasr/train_utils/collect_stats.py similarity index 96% rename from funasr/main_funcs/collect_stats.py rename to funasr/train_utils/collect_stats.py index ee2182c1f..7454ccf90 100644 --- a/funasr/main_funcs/collect_stats.py +++ b/funasr/train_utils/collect_stats.py @@ -12,10 +12,10 @@ import torch from torch.nn.parallel import data_parallel from torch.utils.data import DataLoader -from funasr.fileio.datadir_writer import DatadirWriter +from funasr.utils.datadir_writer import DatadirWriter from funasr.fileio.npy_scp import NpyScpWriter -from funasr.torch_utils.device_funcs import to_device -from funasr.torch_utils.forward_adaptor import ForwardAdaptor +from funasr.train_utils.device_funcs import to_device +from funasr.train_utils.forward_adaptor import ForwardAdaptor from funasr.models.base_model import FunASRModel diff --git a/funasr/torch_utils/device_funcs.py b/funasr/train_utils/device_funcs.py similarity index 100% rename from funasr/torch_utils/device_funcs.py rename to funasr/train_utils/device_funcs.py diff --git a/funasr/torch_utils/forward_adaptor.py b/funasr/train_utils/forward_adaptor.py similarity index 100% rename from funasr/torch_utils/forward_adaptor.py rename to funasr/train_utils/forward_adaptor.py diff --git a/funasr/train_utils/initialize.py b/funasr/train_utils/initialize.py new file mode 100644 index 000000000..ee9485048 --- /dev/null +++ b/funasr/train_utils/initialize.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +"""Initialize modules for espnet2 neural networks.""" + +import math +import torch + + +def initialize(model: torch.nn.Module, init: str): + """Initialize weights of a neural network module. + + Parameters are initialized using the given method or distribution. + + Custom initialization routines can be implemented into submodules + as function `espnet_initialization_fn` within the custom module. + + Args: + model: Target. + init: Method of initialization. + """ + + + # weight init + for p in model.parameters(): + if p.dim() > 1: + if init == "xavier_uniform": + torch.nn.init.xavier_uniform_(p.data) + elif init == "xavier_normal": + torch.nn.init.xavier_normal_(p.data) + elif init == "kaiming_uniform": + torch.nn.init.kaiming_uniform_(p.data, nonlinearity="relu") + elif init == "kaiming_normal": + torch.nn.init.kaiming_normal_(p.data, nonlinearity="relu") + else: + raise ValueError("Unknown initialization: " + init) + # bias init + for p in model.parameters(): + if p.dim() == 1: + p.data.zero_() + + # reset some modules with default init + for m in model.modules(): + if isinstance( + m, (torch.nn.Embedding, torch.nn.LayerNorm, torch.nn.GroupNorm) + ): + m.reset_parameters() + if hasattr(m, "espnet_initialization_fn"): + m.espnet_initialization_fn() + + # TODO(xkc): Hacking s3prl_frontend and wav2vec2encoder initialization + if getattr(model, "encoder", None) and getattr( + model.encoder, "reload_pretrained_parameters", None + ): + model.encoder.reload_pretrained_parameters() + if getattr(model, "frontend", None) and getattr( + model.frontend, "reload_pretrained_parameters", None + ): + model.frontend.reload_pretrained_parameters() + diff --git a/funasr/torch_utils/load_pretrained_model.py b/funasr/train_utils/load_pretrained_model.py similarity index 100% rename from funasr/torch_utils/load_pretrained_model.py rename to funasr/train_utils/load_pretrained_model.py diff --git a/funasr/torch_utils/model_summary.py b/funasr/train_utils/model_summary.py similarity index 100% rename from funasr/torch_utils/model_summary.py rename to funasr/train_utils/model_summary.py diff --git a/funasr/main_funcs/pack_funcs.py b/funasr/train_utils/pack_funcs.py similarity index 100% rename from funasr/main_funcs/pack_funcs.py rename to funasr/train_utils/pack_funcs.py diff --git a/funasr/torch_utils/pytorch_version.py b/funasr/train_utils/pytorch_version.py similarity index 100% rename from funasr/torch_utils/pytorch_version.py rename to funasr/train_utils/pytorch_version.py diff --git a/funasr/torch_utils/recursive_op.py b/funasr/train_utils/recursive_op.py similarity index 100% rename from funasr/torch_utils/recursive_op.py rename to funasr/train_utils/recursive_op.py diff --git a/funasr/torch_utils/set_all_random_seed.py b/funasr/train_utils/set_all_random_seed.py similarity index 100% rename from funasr/torch_utils/set_all_random_seed.py rename to funasr/train_utils/set_all_random_seed.py diff --git a/funasr/utils/trainer.py b/funasr/train_utils/trainer.py similarity index 98% rename from funasr/utils/trainer.py rename to funasr/train_utils/trainer.py index 01787673a..425b79f98 100644 --- a/funasr/utils/trainer.py +++ b/funasr/train_utils/trainer.py @@ -1,12 +1,12 @@ import torch import os -from funasr.torch_utils.device_funcs import to_device +from funasr.train_utils.device_funcs import to_device import logging import time from tqdm import tqdm from contextlib import nullcontext import torch.distributed as dist -from funasr.torch_utils.recursive_op import recursive_average +from funasr.train_utils.recursive_op import recursive_average class Trainer: """ diff --git a/funasr/utils/asr_env_checking.py b/funasr/utils/asr_env_checking.py deleted file mode 100644 index c393ee529..000000000 --- a/funasr/utils/asr_env_checking.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) Alibaba, Inc. and its affiliates. - -import os -import shutil -import ssl - -import nltk - -# mkdir nltk_data dir if not exist -try: - nltk.data.find('.') -except LookupError: - dir_list = nltk.data.path - for dir_item in dir_list: - if not os.path.exists(dir_item): - os.mkdir(dir_item) - if os.path.exists(dir_item): - break - -# download one package if nltk_data not exist -try: - nltk.data.find('.') -except: # noqa: * - try: - _create_unverified_https_context = ssl._create_unverified_context - except AttributeError: - pass - else: - ssl._create_default_https_context = _create_unverified_https_context - - nltk.download('cmudict', halt_on_error=False, raise_on_error=True) - -# deploy taggers/averaged_perceptron_tagger -try: - nltk.data.find('taggers/averaged_perceptron_tagger') -except: # noqa: * - data_dir = nltk.data.find('.') - target_dir = os.path.join(data_dir, 'taggers') - if not os.path.exists(target_dir): - os.mkdir(target_dir) - src_file = os.path.join(os.path.dirname(__file__), '..', 'nltk_packages', - 'averaged_perceptron_tagger.zip') - shutil.copyfile(src_file, - os.path.join(target_dir, 'averaged_perceptron_tagger.zip')) - shutil._unpack_zipfile( - os.path.join(target_dir, 'averaged_perceptron_tagger.zip'), target_dir) - -# deploy corpora/cmudict -try: - nltk.data.find('corpora/cmudict') -except: # noqa: * - data_dir = nltk.data.find('.') - target_dir = os.path.join(data_dir, 'corpora') - if not os.path.exists(target_dir): - os.mkdir(target_dir) - src_file = os.path.join(os.path.dirname(__file__), '..', 'nltk_packages', - 'cmudict.zip') - shutil.copyfile(src_file, os.path.join(target_dir, 'cmudict.zip')) - shutil._unpack_zipfile(os.path.join(target_dir, 'cmudict.zip'), target_dir) - -try: - nltk.data.find('taggers/averaged_perceptron_tagger') -except: # noqa: * - try: - _create_unverified_https_context = ssl._create_unverified_context - except AttributeError: - pass - else: - ssl._create_default_https_context = _create_unverified_https_context - - nltk.download('averaged_perceptron_tagger', - halt_on_error=False, - raise_on_error=True) - -try: - nltk.data.find('corpora/cmudict') -except: # noqa: * - try: - _create_unverified_https_context = ssl._create_unverified_context - except AttributeError: - pass - else: - ssl._create_default_https_context = _create_unverified_https_context - - nltk.download('cmudict', halt_on_error=False, raise_on_error=True) diff --git a/funasr/utils/build_dataclass.py b/funasr/utils/build_dataclass.py deleted file mode 100644 index 0d59ad958..000000000 --- a/funasr/utils/build_dataclass.py +++ /dev/null @@ -1,15 +0,0 @@ -import argparse -import dataclasses - - - -def build_dataclass(dataclass, args: argparse.Namespace): - """Helper function to build dataclass from 'args'.""" - kwargs = {} - for field in dataclasses.fields(dataclass): - if not hasattr(args, field.name): - raise ValueError( - f"args doesn't have {field.name}. You need to set it to ArgumentsParser" - ) - kwargs[field.name] = getattr(args, field.name) - return dataclass(**kwargs) diff --git a/funasr/train/class_choices.py b/funasr/utils/class_choices.py similarity index 100% rename from funasr/train/class_choices.py rename to funasr/utils/class_choices.py diff --git a/funasr/utils/cluster_backend.py b/funasr/utils/cluster_backend.py deleted file mode 100644 index 47b45d2af..000000000 --- a/funasr/utils/cluster_backend.py +++ /dev/null @@ -1,191 +0,0 @@ -# Copyright (c) Alibaba, Inc. and its affiliates. - -from typing import Any, Dict, Union - -import hdbscan -import numpy as np -import scipy -import sklearn -import umap -from sklearn.cluster._kmeans import k_means -from torch import nn - - -class SpectralCluster: - r"""A spectral clustering mehtod using unnormalized Laplacian of affinity matrix. - This implementation is adapted from https://github.com/speechbrain/speechbrain. - """ - - def __init__(self, min_num_spks=1, max_num_spks=15, pval=0.022): - self.min_num_spks = min_num_spks - self.max_num_spks = max_num_spks - self.pval = pval - - def __call__(self, X, oracle_num=None): - # Similarity matrix computation - sim_mat = self.get_sim_mat(X) - - # Refining similarity matrix with pval - prunned_sim_mat = self.p_pruning(sim_mat) - - # Symmetrization - sym_prund_sim_mat = 0.5 * (prunned_sim_mat + prunned_sim_mat.T) - - # Laplacian calculation - laplacian = self.get_laplacian(sym_prund_sim_mat) - - # Get Spectral Embeddings - emb, num_of_spk = self.get_spec_embs(laplacian, oracle_num) - - # Perform clustering - labels = self.cluster_embs(emb, num_of_spk) - - return labels - - def get_sim_mat(self, X): - # Cosine similarities - M = sklearn.metrics.pairwise.cosine_similarity(X, X) - return M - - def p_pruning(self, A): - if A.shape[0] * self.pval < 6: - pval = 6. / A.shape[0] - else: - pval = self.pval - - n_elems = int((1 - pval) * A.shape[0]) - - # For each row in a affinity matrix - for i in range(A.shape[0]): - low_indexes = np.argsort(A[i, :]) - low_indexes = low_indexes[0:n_elems] - - # Replace smaller similarity values by 0s - A[i, low_indexes] = 0 - return A - - def get_laplacian(self, M): - M[np.diag_indices(M.shape[0])] = 0 - D = np.sum(np.abs(M), axis=1) - D = np.diag(D) - L = D - M - return L - - def get_spec_embs(self, L, k_oracle=None): - lambdas, eig_vecs = scipy.linalg.eigh(L) - - if k_oracle is not None: - num_of_spk = k_oracle - else: - lambda_gap_list = self.getEigenGaps( - lambdas[self.min_num_spks - 1:self.max_num_spks + 1]) - num_of_spk = np.argmax(lambda_gap_list) + self.min_num_spks - - emb = eig_vecs[:, :num_of_spk] - return emb, num_of_spk - - def cluster_embs(self, emb, k): - _, labels, _ = k_means(emb, k) - return labels - - def getEigenGaps(self, eig_vals): - eig_vals_gap_list = [] - for i in range(len(eig_vals) - 1): - gap = float(eig_vals[i + 1]) - float(eig_vals[i]) - eig_vals_gap_list.append(gap) - return eig_vals_gap_list - - -class UmapHdbscan: - r""" - Reference: - - Siqi Zheng, Hongbin Suo. Reformulating Speaker Diarization as Community Detection With - Emphasis On Topological Structure. ICASSP2022 - """ - - def __init__(self, - n_neighbors=20, - n_components=60, - min_samples=10, - min_cluster_size=10, - metric='cosine'): - self.n_neighbors = n_neighbors - self.n_components = n_components - self.min_samples = min_samples - self.min_cluster_size = min_cluster_size - self.metric = metric - - def __call__(self, X): - umap_X = umap.UMAP( - n_neighbors=self.n_neighbors, - min_dist=0.0, - n_components=min(self.n_components, X.shape[0] - 2), - metric=self.metric, - ).fit_transform(X) - labels = hdbscan.HDBSCAN( - min_samples=self.min_samples, - min_cluster_size=self.min_cluster_size, - allow_single_cluster=True).fit_predict(umap_X) - return labels - - -class ClusterBackend(nn.Module): - r"""Perfom clustering for input embeddings and output the labels. - Args: - model_dir: A model dir. - model_config: The model config. - """ - - def __init__(self): - super().__init__() - self.model_config = {'merge_thr':0.78} - # self.other_config = kwargs - - self.spectral_cluster = SpectralCluster() - self.umap_hdbscan_cluster = UmapHdbscan() - - def forward(self, X, **params): - # clustering and return the labels - k = params['oracle_num'] if 'oracle_num' in params else None - assert len( - X.shape - ) == 2, 'modelscope error: the shape of input should be [N, C]' - if X.shape[0] < 20: - return np.zeros(X.shape[0], dtype='int') - if X.shape[0] < 2048 or k is not None: - labels = self.spectral_cluster(X, k) - else: - labels = self.umap_hdbscan_cluster(X) - - if k is None and 'merge_thr' in self.model_config: - labels = self.merge_by_cos(labels, X, - self.model_config['merge_thr']) - - return labels - - def merge_by_cos(self, labels, embs, cos_thr): - # merge the similar speakers by cosine similarity - assert cos_thr > 0 and cos_thr <= 1 - while True: - spk_num = labels.max() + 1 - if spk_num == 1: - break - spk_center = [] - for i in range(spk_num): - spk_emb = embs[labels == i].mean(0) - spk_center.append(spk_emb) - assert len(spk_center) > 0 - spk_center = np.stack(spk_center, axis=0) - norm_spk_center = spk_center / np.linalg.norm( - spk_center, axis=1, keepdims=True) - affinity = np.matmul(norm_spk_center, norm_spk_center.T) - affinity = np.triu(affinity, 1) - spks = np.unravel_index(np.argmax(affinity), affinity.shape) - if affinity[spks] < cos_thr: - break - for i in range(len(labels)): - if labels[i] == spks[1]: - labels[i] = spks[0] - elif labels[i] > spks[1]: - labels[i] -= 1 - return labels diff --git a/funasr/utils/compute_wer.py b/funasr/utils/compute_wer.py deleted file mode 100755 index 26a9f491f..000000000 --- a/funasr/utils/compute_wer.py +++ /dev/null @@ -1,157 +0,0 @@ -import os -import numpy as np -import sys - -def compute_wer(ref_file, - hyp_file, - cer_detail_file): - rst = { - 'Wrd': 0, - 'Corr': 0, - 'Ins': 0, - 'Del': 0, - 'Sub': 0, - 'Snt': 0, - 'Err': 0.0, - 'S.Err': 0.0, - 'wrong_words': 0, - 'wrong_sentences': 0 - } - - hyp_dict = {} - ref_dict = {} - with open(hyp_file, 'r') as hyp_reader: - for line in hyp_reader: - key = line.strip().split()[0] - value = line.strip().split()[1:] - hyp_dict[key] = value - with open(ref_file, 'r') as ref_reader: - for line in ref_reader: - key = line.strip().split()[0] - value = line.strip().split()[1:] - ref_dict[key] = value - - cer_detail_writer = open(cer_detail_file, 'w') - for hyp_key in hyp_dict: - if hyp_key in ref_dict: - out_item = compute_wer_by_line(hyp_dict[hyp_key], ref_dict[hyp_key]) - rst['Wrd'] += out_item['nwords'] - rst['Corr'] += out_item['cor'] - rst['wrong_words'] += out_item['wrong'] - rst['Ins'] += out_item['ins'] - rst['Del'] += out_item['del'] - rst['Sub'] += out_item['sub'] - rst['Snt'] += 1 - if out_item['wrong'] > 0: - rst['wrong_sentences'] += 1 - cer_detail_writer.write(hyp_key + print_cer_detail(out_item) + '\n') - cer_detail_writer.write("ref:" + '\t' + " ".join(list(map(lambda x: x.lower(), ref_dict[hyp_key]))) + '\n') - cer_detail_writer.write("hyp:" + '\t' + " ".join(list(map(lambda x: x.lower(), hyp_dict[hyp_key]))) + '\n') - - if rst['Wrd'] > 0: - rst['Err'] = round(rst['wrong_words'] * 100 / rst['Wrd'], 2) - if rst['Snt'] > 0: - rst['S.Err'] = round(rst['wrong_sentences'] * 100 / rst['Snt'], 2) - - cer_detail_writer.write('\n') - cer_detail_writer.write("%WER " + str(rst['Err']) + " [ " + str(rst['wrong_words'])+ " / " + str(rst['Wrd']) + - ", " + str(rst['Ins']) + " ins, " + str(rst['Del']) + " del, " + str(rst['Sub']) + " sub ]" + '\n') - cer_detail_writer.write("%SER " + str(rst['S.Err']) + " [ " + str(rst['wrong_sentences']) + " / " + str(rst['Snt']) + " ]" + '\n') - cer_detail_writer.write("Scored " + str(len(hyp_dict)) + " sentences, " + str(len(hyp_dict) - rst['Snt']) + " not present in hyp." + '\n') - - -def compute_wer_by_line(hyp, - ref): - hyp = list(map(lambda x: x.lower(), hyp)) - ref = list(map(lambda x: x.lower(), ref)) - - len_hyp = len(hyp) - len_ref = len(ref) - - cost_matrix = np.zeros((len_hyp + 1, len_ref + 1), dtype=np.int16) - - ops_matrix = np.zeros((len_hyp + 1, len_ref + 1), dtype=np.int8) - - for i in range(len_hyp + 1): - cost_matrix[i][0] = i - for j in range(len_ref + 1): - cost_matrix[0][j] = j - - for i in range(1, len_hyp + 1): - for j in range(1, len_ref + 1): - if hyp[i - 1] == ref[j - 1]: - cost_matrix[i][j] = cost_matrix[i - 1][j - 1] - else: - substitution = cost_matrix[i - 1][j - 1] + 1 - insertion = cost_matrix[i - 1][j] + 1 - deletion = cost_matrix[i][j - 1] + 1 - - compare_val = [substitution, insertion, deletion] - - min_val = min(compare_val) - operation_idx = compare_val.index(min_val) + 1 - cost_matrix[i][j] = min_val - ops_matrix[i][j] = operation_idx - - match_idx = [] - i = len_hyp - j = len_ref - rst = { - 'nwords': len_ref, - 'cor': 0, - 'wrong': 0, - 'ins': 0, - 'del': 0, - 'sub': 0 - } - while i >= 0 or j >= 0: - i_idx = max(0, i) - j_idx = max(0, j) - - if ops_matrix[i_idx][j_idx] == 0: # correct - if i - 1 >= 0 and j - 1 >= 0: - match_idx.append((j - 1, i - 1)) - rst['cor'] += 1 - - i -= 1 - j -= 1 - - elif ops_matrix[i_idx][j_idx] == 2: # insert - i -= 1 - rst['ins'] += 1 - - elif ops_matrix[i_idx][j_idx] == 3: # delete - j -= 1 - rst['del'] += 1 - - elif ops_matrix[i_idx][j_idx] == 1: # substitute - i -= 1 - j -= 1 - rst['sub'] += 1 - - if i < 0 and j >= 0: - rst['del'] += 1 - elif j < 0 and i >= 0: - rst['ins'] += 1 - - match_idx.reverse() - wrong_cnt = cost_matrix[len_hyp][len_ref] - rst['wrong'] = wrong_cnt - - return rst - -def print_cer_detail(rst): - return ("(" + "nwords=" + str(rst['nwords']) + ",cor=" + str(rst['cor']) - + ",ins=" + str(rst['ins']) + ",del=" + str(rst['del']) + ",sub=" - + str(rst['sub']) + ") corr:" + '{:.2%}'.format(rst['cor']/rst['nwords']) - + ",cer:" + '{:.2%}'.format(rst['wrong']/rst['nwords'])) - -if __name__ == '__main__': - if len(sys.argv) != 4: - print("usage : python compute-wer.py test.ref test.hyp test.wer") - sys.exit(0) - - ref_file = sys.argv[1] - hyp_file = sys.argv[2] - cer_detail_file = sys.argv[3] - compute_wer(ref_file, hyp_file, cer_detail_file) diff --git a/funasr/utils/config_argparse.py b/funasr/utils/config_argparse.py deleted file mode 100644 index c9d7197a7..000000000 --- a/funasr/utils/config_argparse.py +++ /dev/null @@ -1,47 +0,0 @@ -import argparse -from pathlib import Path - -import yaml - - -class ArgumentParser(argparse.ArgumentParser): - """Simple implementation of ArgumentParser supporting config file - - This class is originated from https://github.com/bw2/ConfigArgParse, - but this class is lack of some features that it has. - - - Not supporting multiple config files - - Automatically adding "--config" as an option. - - Not supporting any formats other than yaml - - Not checking argument type - - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.add_argument("--config", help="Give config file in yaml format") - - def parse_known_args(self, args=None, namespace=None): - # Once parsing for setting from "--config" - _args, _ = super().parse_known_args(args, namespace) - if _args.config is not None: - if not Path(_args.config).exists(): - self.error(f"No such file: {_args.config}") - - with open(_args.config, "r", encoding="utf-8") as f: - d = yaml.safe_load(f) - if not isinstance(d, dict): - self.error("Config file has non dict value: {_args.config}") - - for key in d: - for action in self._actions: - if key == action.dest: - break - else: - self.error(f"unrecognized arguments: {key} (from {_args.config})") - - # NOTE(kamo): Ignore "--config" from a config file - # NOTE(kamo): Unlike "configargparse", this module doesn't check type. - # i.e. We can set any type value regardless of argument type. - self.set_defaults(**d) - return super().parse_known_args(args, namespace) diff --git a/funasr/fileio/datadir_writer.py b/funasr/utils/datadir_writer.py similarity index 100% rename from funasr/fileio/datadir_writer.py rename to funasr/utils/datadir_writer.py diff --git a/funasr/utils/download_and_prepare_model.py b/funasr/utils/download_and_prepare_model.py deleted file mode 100644 index af8a3f3dc..000000000 --- a/funasr/utils/download_and_prepare_model.py +++ /dev/null @@ -1,93 +0,0 @@ - -import os -from pathlib import Path -import logging - -name_maps_ms = { - "paraformer-zh": "damo/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch", - "paraformer-zh-spk": "damo/speech_paraformer-large-vad-punc-spk_asr_nat-zh-cn", - "paraformer-en": "damo/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020", - "paraformer-en-spk": "damo/speech_paraformer-large-vad-punc_asr_nat-en-16k-common-vocab10020", - "paraformer-zh-streaming": "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", - "fsmn-vad": "damo/speech_fsmn_vad_zh-cn-16k-common-pytorch", - "ct-punc": "damo/punc_ct-transformer_cn-en-common-vocab471067-large", - "fa-zh": "damo/speech_timestamp_prediction-v1-16k-offline", -} - -def prepare_model( - model: str = None, - # mode: str = None, - vad_model: str = None, - punc_model: str = None, - model_hub: str = "ms", - cache_dir: str = None, - **kwargs, -): - if not Path(model).exists(): - if model_hub == "ms" or model_hub == "modelscope": - from modelscope.utils.logger import get_logger - - logger = get_logger(log_level=logging.CRITICAL) - logger.setLevel(logging.CRITICAL) - try: - from modelscope.hub.snapshot_download import snapshot_download as download_tool - model = name_maps_ms[model] if model is not None else None - vad_model = name_maps_ms[vad_model] if vad_model is not None else None - punc_model = name_maps_ms[punc_model] if punc_model is not None else None - except: - raise "You are exporting model from modelscope, please install modelscope and try it again. To install modelscope, you could:\n" \ - "\npip3 install -U modelscope\n" \ - "For the users in China, you could install with the command:\n" \ - "\npip3 install -U modelscope -i https://mirror.sjtu.edu.cn/pypi/web/simple" - - try: - model = download_tool(model, cache_dir=cache_dir, revision=kwargs.get("revision", None)) - print("asr model have been downloaded to: {}".format(model)) - except: - raise "model_dir must be model_name in modelscope or local path downloaded from modelscope, but is {}".format( - model) - - elif model_hub == "hf" or model_hub == "huggingface": - download_tool = 0 - else: - raise "model_hub must be on of ms or hf, but get {}".format(model_hub) - - - if vad_model is not None and not Path(vad_model).exists(): - vad_model = download_tool(vad_model, cache_dir=cache_dir) - print("vad_model have been downloaded to: {}".format(vad_model)) - if punc_model is not None and not Path(punc_model).exists(): - punc_model = download_tool(punc_model, cache_dir=cache_dir) - print("punc_model have been downloaded to: {}".format(punc_model)) - - # asr - kwargs.update({"cmvn_file": None if model is None else os.path.join(model, "am.mvn"), - "asr_model_file": None if model is None else os.path.join(model, "model.pb"), - "asr_train_config": None if model is None else os.path.join(model, "config.yaml"), - }) - mode = kwargs.get("mode", None) - if mode is None: - import json - json_file = os.path.join(model, 'configuration.json') - with open(json_file, 'r') as f: - config_data = json.load(f) - if config_data['task'] == "punctuation": - mode = config_data['model']['punc_model_config']['mode'] - else: - mode = config_data['model']['model_config']['mode'] - if vad_model is not None and "vad" not in mode: - mode = "paraformer_vad" - kwargs["mode"] = mode - # vad - kwargs.update({"vad_cmvn_file": None if vad_model is None else os.path.join(vad_model, "vad.mvn"), - "vad_model_file": None if vad_model is None else os.path.join(vad_model, "vad.pb"), - "vad_infer_config": None if vad_model is None else os.path.join(vad_model, "vad.yaml"), - }) - # punc - kwargs.update({ - "punc_model_file": None if punc_model is None else os.path.join(punc_model, "punc.pb"), - "punc_infer_config": None if punc_model is None else os.path.join(punc_model, "punc.yaml"), - }) - - - return model, vad_model, punc_model, kwargs diff --git a/funasr/utils/get_default_kwargs.py b/funasr/utils/get_default_kwargs.py deleted file mode 100644 index 0f11e8af4..000000000 --- a/funasr/utils/get_default_kwargs.py +++ /dev/null @@ -1,57 +0,0 @@ -import inspect - - -class Invalid: - """Marker object for not serializable-object""" - - -def get_default_kwargs(func): - """Get the default values of the input function. - - Examples: - >>> def func(a, b=3): pass - >>> get_default_kwargs(func) - {'b': 3} - - """ - - def yaml_serializable(value): - # isinstance(x, tuple) includes namedtuple, so type is used here - if type(value) is tuple: - return yaml_serializable(list(value)) - elif isinstance(value, set): - return yaml_serializable(list(value)) - elif isinstance(value, dict): - if not all(isinstance(k, str) for k in value): - return Invalid - retval = {} - for k, v in value.items(): - v2 = yaml_serializable(v) - # Register only valid object - if v2 not in (Invalid, inspect.Parameter.empty): - retval[k] = v2 - return retval - elif isinstance(value, list): - retval = [] - for v in value: - v2 = yaml_serializable(v) - # If any elements in the list are invalid, - # the list also becomes invalid - if v2 is Invalid: - return Invalid - else: - retval.append(v2) - return retval - elif value in (inspect.Parameter.empty, None): - return value - elif isinstance(value, (float, int, complex, bool, str, bytes)): - return value - else: - return Invalid - - # params: An ordered mapping of inspect.Parameter - params = inspect.signature(func).parameters - data = {p.name: p.default for p in params.values()} - # Remove not yaml-serializable object - data = yaml_serializable(data) - return data diff --git a/funasr/utils/griffin_lim.py b/funasr/utils/griffin_lim.py deleted file mode 100644 index 9e98ab824..000000000 --- a/funasr/utils/griffin_lim.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env python3 - -"""Griffin-Lim related modules.""" - -# Copyright 2019 Tomoki Hayashi -# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -import logging - -from distutils.version import LooseVersion -from functools import partial -from typing import Optional - -import librosa -import numpy as np -import torch - -EPS = 1e-10 - - -def logmel2linear( - lmspc: np.ndarray, - fs: int, - n_fft: int, - n_mels: int, - fmin: int = None, - fmax: int = None, -) -> np.ndarray: - """Convert log Mel filterbank to linear spectrogram. - - Args: - lmspc: Log Mel filterbank (T, n_mels). - fs: Sampling frequency. - n_fft: The number of FFT points. - n_mels: The number of mel basis. - f_min: Minimum frequency to analyze. - f_max: Maximum frequency to analyze. - - Returns: - Linear spectrogram (T, n_fft // 2 + 1). - - """ - assert lmspc.shape[1] == n_mels - fmin = 0 if fmin is None else fmin - fmax = fs / 2 if fmax is None else fmax - mspc = np.power(10.0, lmspc) - mel_basis = librosa.filters.mel( - sr=fs, n_fft=n_fft, n_mels=n_mels, fmin=fmin, fmax=fmax - ) - inv_mel_basis = np.linalg.pinv(mel_basis) - return np.maximum(EPS, np.dot(inv_mel_basis, mspc.T).T) - - -def griffin_lim( - spc: np.ndarray, - n_fft: int, - n_shift: int, - win_length: int = None, - window: Optional[str] = "hann", - n_iter: Optional[int] = 32, -) -> np.ndarray: - """Convert linear spectrogram into waveform using Griffin-Lim. - - Args: - spc: Linear spectrogram (T, n_fft // 2 + 1). - n_fft: The number of FFT points. - n_shift: Shift size in points. - win_length: Window length in points. - window: Window function type. - n_iter: The number of iterations. - - Returns: - Reconstructed waveform (N,). - - """ - # assert the size of input linear spectrogram - assert spc.shape[1] == n_fft // 2 + 1 - - if LooseVersion(librosa.__version__) >= LooseVersion("0.7.0"): - # use librosa's fast Grriffin-Lim algorithm - spc = np.abs(spc.T) - y = librosa.griffinlim( - S=spc, - n_iter=n_iter, - hop_length=n_shift, - win_length=win_length, - window=window, - center=True if spc.shape[1] > 1 else False, - ) - else: - # use slower version of Grriffin-Lim algorithm - logging.warning( - "librosa version is old. use slow version of Grriffin-Lim algorithm." - "if you want to use fast Griffin-Lim, please update librosa via " - "`source ./path.sh && pip install librosa==0.7.0`." - ) - cspc = np.abs(spc).astype(np.complex).T - angles = np.exp(2j * np.pi * np.random.rand(*cspc.shape)) - y = librosa.istft(cspc * angles, n_shift, win_length, window=window) - for i in range(n_iter): - angles = np.exp( - 1j - * np.angle(librosa.stft(y, n_fft, n_shift, win_length, window=window)) - ) - y = librosa.istft(cspc * angles, n_shift, win_length, window=window) - - return y - - -# TODO(kan-bayashi): write as torch.nn.Module -class Spectrogram2Waveform(object): - """Spectrogram to waveform conversion module.""" - - def __init__( - self, - n_fft: int, - n_shift: int, - fs: int = None, - n_mels: int = None, - win_length: int = None, - window: Optional[str] = "hann", - fmin: int = None, - fmax: int = None, - griffin_lim_iters: Optional[int] = 8, - ): - """Initialize module. - - Args: - fs: Sampling frequency. - n_fft: The number of FFT points. - n_shift: Shift size in points. - n_mels: The number of mel basis. - win_length: Window length in points. - window: Window function type. - f_min: Minimum frequency to analyze. - f_max: Maximum frequency to analyze. - griffin_lim_iters: The number of iterations. - - """ - self.fs = fs - self.logmel2linear = ( - partial( - logmel2linear, fs=fs, n_fft=n_fft, n_mels=n_mels, fmin=fmin, fmax=fmax - ) - if n_mels is not None - else None - ) - self.griffin_lim = partial( - griffin_lim, - n_fft=n_fft, - n_shift=n_shift, - win_length=win_length, - window=window, - n_iter=griffin_lim_iters, - ) - self.params = dict( - n_fft=n_fft, - n_shift=n_shift, - win_length=win_length, - window=window, - n_iter=griffin_lim_iters, - ) - if n_mels is not None: - self.params.update(fs=fs, n_mels=n_mels, fmin=fmin, fmax=fmax) - - def __repr__(self): - retval = f"{self.__class__.__name__}(" - for k, v in self.params.items(): - retval += f"{k}={v}, " - retval += ")" - return retval - - def __call__(self, spc: torch.Tensor) -> torch.Tensor: - """Convert spectrogram to waveform. - - Args: - spc: Log Mel filterbank (T_feats, n_mels) - or linear spectrogram (T_feats, n_fft // 2 + 1). - - Returns: - Tensor: Reconstructed waveform (T_wav,). - - """ - device = spc.device - dtype = spc.dtype - spc = spc.cpu().numpy() - if self.logmel2linear is not None: - spc = self.logmel2linear(spc) - wav = self.griffin_lim(spc) - return torch.tensor(wav).to(device=device, dtype=dtype) diff --git a/funasr/utils/hinter.py b/funasr/utils/hinter.py deleted file mode 100644 index 8c99809f1..000000000 --- a/funasr/utils/hinter.py +++ /dev/null @@ -1,13 +0,0 @@ -import sys -import torch.distributed -import logging - -HINTED = set() - - -def hint_once(content, uid, rank=None): - if (rank is None) or (not torch.distributed.is_initialized()) or torch.distributed.get_rank() == rank: - if uid not in HINTED: - logging.info(content) - HINTED.add(uid) - diff --git a/funasr/utils/job_runner.py b/funasr/utils/job_runner.py deleted file mode 100644 index a35d49c4c..000000000 --- a/funasr/utils/job_runner.py +++ /dev/null @@ -1,103 +0,0 @@ -from __future__ import print_function -from multiprocessing import Pool -import argparse -from tqdm import tqdm -import math - - -class MultiProcessRunner: - def __init__(self, fn): - self.args = None - self.process = fn - - def run(self): - parser = argparse.ArgumentParser("") - # Task-independent options - parser.add_argument("--nj", type=int, default=16) - parser.add_argument("--debug", action="store_true", default=False) - parser.add_argument("--no_pbar", action="store_true", default=False) - parser.add_argument("--verbose", action="store_ture", default=False) - - task_list, args = self.prepare(parser) - result_list = self.pool_run(task_list, args) - self.post(result_list, args) - - def prepare(self, parser): - raise NotImplementedError("Please implement the prepare function.") - - def post(self, result_list, args): - raise NotImplementedError("Please implement the post function.") - - def pool_run(self, tasks, args): - results = [] - if args.debug: - one_result = self.process(tasks[0]) - results.append(one_result) - else: - pool = Pool(args.nj) - for one_result in tqdm(pool.imap(self.process, tasks), total=len(tasks), ascii=True, disable=args.no_pbar): - results.append(one_result) - pool.close() - - return results - - -class MultiProcessRunnerV2: - def __init__(self, fn): - self.args = None - self.process = fn - - def run(self): - parser = argparse.ArgumentParser("") - # Task-independent options - parser.add_argument("--nj", type=int, default=16) - parser.add_argument("--debug", action="store_true", default=False) - parser.add_argument("--no_pbar", action="store_true", default=False) - parser.add_argument("--verbose", action="store_true", default=False) - - task_list, args = self.prepare(parser) - chunk_size = int(math.ceil(float(len(task_list)) / args.nj)) - if args.verbose: - print("Split {} tasks into {} sub-tasks with chunk_size {}".format(len(task_list), args.nj, chunk_size)) - subtask_list = [task_list[i*chunk_size: (i+1)*chunk_size] for i in range(args.nj)] - result_list = self.pool_run(subtask_list, args) - self.post(result_list, args) - - def prepare(self, parser): - raise NotImplementedError("Please implement the prepare function.") - - def post(self, result_list, args): - raise NotImplementedError("Please implement the post function.") - - def pool_run(self, tasks, args): - results = [] - if args.debug: - one_result = self.process(tasks[0]) - results.append(one_result) - else: - pool = Pool(args.nj) - for one_result in tqdm(pool.imap(self.process, tasks), total=len(tasks), ascii=True, disable=args.no_pbar): - results.append(one_result) - pool.close() - - return results - - -class MultiProcessRunnerV3(MultiProcessRunnerV2): - def run(self): - parser = argparse.ArgumentParser("") - # Task-independent options - parser.add_argument("--nj", type=int, default=16) - parser.add_argument("--debug", action="store_true", default=False) - parser.add_argument("--no_pbar", action="store_true", default=False) - parser.add_argument("--verbose", action="store_true", default=False) - parser.add_argument("--sr", type=int, default=16000) - - task_list, shared_param, args = self.prepare(parser) - chunk_size = int(math.ceil(float(len(task_list)) / args.nj)) - if args.verbose: - print("Split {} tasks into {} sub-tasks with chunk_size {}".format(len(task_list), args.nj, chunk_size)) - subtask_list = [(i, task_list[i * chunk_size: (i + 1) * chunk_size], shared_param, args) - for i in range(args.nj)] - result_list = self.pool_run(subtask_list, args) - self.post(result_list, args) diff --git a/funasr/utils/kwargs2args.py b/funasr/utils/kwargs2args.py deleted file mode 100644 index 4e0cdba87..000000000 --- a/funasr/utils/kwargs2args.py +++ /dev/null @@ -1,19 +0,0 @@ -import inspect - - -def func(a: int, b, *, c, **kwargs): - pass - -def kwargs2args(func, kwargs): - parameters = inspect.signature(func).parameters - d = {k: i for i, k in enumerate(parameters)} - args = [None for i in range(len(parameters))] - for k, v in kwargs.items(): - if k in d: - args[d[k]] = v - - for i, v in enumerate(args): - if v is None: - break - - return tuple(args[:i]) diff --git a/funasr/utils/load_fr_py.py b/funasr/utils/load_fr_py.py deleted file mode 100644 index 6697e04da..000000000 --- a/funasr/utils/load_fr_py.py +++ /dev/null @@ -1,13 +0,0 @@ -import importlib.util -import sys - -def load_class_from_path(model_path): - path, class_name = model_path - # import pdb; - # pdb.set_trace() - spec = importlib.util.spec_from_file_location("module.name", path) - module = importlib.util.module_from_spec(spec) - sys.modules[spec.name] = module - spec.loader.exec_module(module) - return getattr(module, class_name) - diff --git a/funasr/modules/streaming_utils/load_fr_tf.py b/funasr/utils/load_fr_tf.py similarity index 100% rename from funasr/modules/streaming_utils/load_fr_tf.py rename to funasr/utils/load_fr_tf.py diff --git a/funasr/utils/modelscope_param.py b/funasr/utils/modelscope_param.py deleted file mode 100644 index 9ff196a75..000000000 --- a/funasr/utils/modelscope_param.py +++ /dev/null @@ -1,35 +0,0 @@ -class modelscope_args(): - def __init__(self, - task: str = "", - model: str = "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch", - data_path: str = None, - output_dir: str = None, - model_revision: str = None, - dataset_type: str = "small", - batch_bins: int = 2000, - max_epoch: int = None, - accum_grad: int = None, - keep_nbest_models: int = None, - optim: str = None, - lr: float = None, - scheduler: str = None, - scheduler_conf: dict = None, - specaug: str = None, - specaug_conf: dict = None, - ): - self.task = task - self.model = model - self.data_path = data_path - self.output_dir = output_dir - self.model_revision = model_revision - self.dataset_type = dataset_type - self.batch_bins = batch_bins - self.max_epoch = max_epoch - self.accum_grad = accum_grad - self.keep_nbest_models = keep_nbest_models - self.optim = optim - self.lr = lr - self.scheduler = scheduler - self.scheduler_conf = scheduler_conf - self.specaug = specaug - self.specaug_conf = specaug_conf diff --git a/funasr/utils/modelscope_utils.py b/funasr/utils/modelscope_utils.py deleted file mode 100644 index 417988525..000000000 --- a/funasr/utils/modelscope_utils.py +++ /dev/null @@ -1,40 +0,0 @@ -import os -from modelscope.hub.snapshot_download import snapshot_download -from pathlib import Path - - -def check_model_dir(model_dir, model_name: str = "damo/speech_fsmn_vad_zh-cn-16k-common-pytorch"): - model_dir = "/Users/zhifu/test_modelscope_pipeline/FSMN-VAD" - - cache_root = os.path.dirname(model_dir) - dst_dir_root = os.path.join(cache_root, ".cache") - dst = os.path.join(dst_dir_root, model_name) - dst_dir = os.path.dirname(dst) - os.makedirs(dst_dir, exist_ok=True) - if not os.path.exists(dst): - os.symlink(model_dir, dst) - - model_dir = snapshot_download(model_name, cache_dir=dst_dir_root) - -def get_default_cache_dir(): - """ - default base dir: '~/.cache/modelscope' - """ - default_cache_dir = Path.home().joinpath('.cache', 'modelscope') - return default_cache_dir - -def get_cache_dir(model_id): - """cache dir precedence: - function parameter > environment > ~/.cache/modelscope/hub - - Args: - model_id (str, optional): The model id. - - Returns: - str: the model_id dir if model_id not None, otherwise cache root dir. - """ - default_cache_dir = get_default_cache_dir() - base_path = os.getenv('MODELSCOPE_CACHE', - os.path.join(default_cache_dir, 'hub')) - return base_path if model_id is None else os.path.join( - base_path, model_id + '/') \ No newline at end of file diff --git a/funasr/utils/nested_dict_action.py b/funasr/utils/nested_dict_action.py deleted file mode 100644 index 38ec57b31..000000000 --- a/funasr/utils/nested_dict_action.py +++ /dev/null @@ -1,106 +0,0 @@ -import argparse -import copy - -import yaml - - -class NestedDictAction(argparse.Action): - """Action class to append items to dict object. - - Examples: - >>> parser = argparse.ArgumentParser() - >>> _ = parser.add_argument('--conf', action=NestedDictAction, - ... default={'a': 4}) - >>> parser.parse_args(['--conf', 'a=3', '--conf', 'c=4']) - Namespace(conf={'a': 3, 'c': 4}) - >>> parser.parse_args(['--conf', 'c.d=4']) - Namespace(conf={'a': 4, 'c': {'d': 4}}) - >>> parser.parse_args(['--conf', 'c.d=4', '--conf', 'c=2']) - Namespace(conf={'a': 4, 'c': 2}) - >>> parser.parse_args(['--conf', '{d: 5, e: 9}']) - Namespace(conf={'d': 5, 'e': 9}) - - """ - - _syntax = """Syntax: - {op} = - {op} .= - {op} - {op} -e.g. - {op} a=4 - {op} a.b={{c: true}} - {op} {{"c": True}} - {op} {{a: 34.5}} -""" - - def __init__( - self, - option_strings, - dest, - nargs=None, - default=None, - choices=None, - required=False, - help=None, - metavar=None, - ): - super().__init__( - option_strings=option_strings, - dest=dest, - nargs=nargs, - default=copy.deepcopy(default), - type=None, - choices=choices, - required=required, - help=help, - metavar=metavar, - ) - - def __call__(self, parser, namespace, values, option_strings=None): - # --{option} a.b=3 -> {'a': {'b': 3}} - if "=" in values: - indict = copy.deepcopy(getattr(namespace, self.dest, {})) - key, value = values.split("=", maxsplit=1) - if not value.strip() == "": - value = yaml.load(value, Loader=yaml.Loader) - if not isinstance(indict, dict): - indict = {} - - keys = key.split(".") - d = indict - for idx, k in enumerate(keys): - if idx == len(keys) - 1: - d[k] = value - else: - if not isinstance(d.setdefault(k, {}), dict): - # Remove the existing value and recreates as empty dict - d[k] = {} - d = d[k] - - # Update the value - setattr(namespace, self.dest, indict) - else: - try: - # At the first, try eval(), i.e. Python syntax dict. - # e.g. --{option} "{'a': 3}" -> {'a': 3} - # This is workaround for internal behaviour of configargparse. - value = eval(values, {}, {}) - if not isinstance(value, dict): - syntax = self._syntax.format(op=option_strings) - mes = f"must be interpreted as dict: but got {values}\n{syntax}" - raise argparse.ArgumentTypeError(self, mes) - except Exception: - # and the second, try yaml.load - value = yaml.load(values, Loader=yaml.Loader) - if not isinstance(value, dict): - syntax = self._syntax.format(op=option_strings) - mes = f"must be interpreted as dict: but got {values}\n{syntax}" - raise argparse.ArgumentError(self, mes) - - d = getattr(namespace, self.dest, None) - if isinstance(d, dict): - d.update(value) - else: - # Remove existing params, and overwrite - setattr(namespace, self.dest, value) diff --git a/funasr/utils/sized_dict.py b/funasr/utils/sized_dict.py deleted file mode 100644 index 105d8c398..000000000 --- a/funasr/utils/sized_dict.py +++ /dev/null @@ -1,75 +0,0 @@ -import collections -import sys - -from torch import multiprocessing - - -def get_size(obj, seen=None): - """Recursively finds size of objects - - Taken from https://github.com/bosswissam/pysize - - """ - - size = sys.getsizeof(obj) - if seen is None: - seen = set() - - obj_id = id(obj) - if obj_id in seen: - return 0 - - # Important mark as seen *before* entering recursion to gracefully handle - # self-referential objects - seen.add(obj_id) - - if isinstance(obj, dict): - size += sum([get_size(v, seen) for v in obj.values()]) - size += sum([get_size(k, seen) for k in obj.keys()]) - elif hasattr(obj, "__dict__"): - size += get_size(obj.__dict__, seen) - elif isinstance(obj, (list, set, tuple)): - size += sum([get_size(i, seen) for i in obj]) - - return size - - -class SizedDict(collections.abc.MutableMapping): - def __init__(self, shared: bool = False, data: dict = None): - if data is None: - data = {} - - if shared: - # NOTE(kamo): Don't set manager as a field because Manager, which includes - # weakref object, causes following error with method="spawn", - # "TypeError: can't pickle weakref objects" - self.cache = multiprocessing.Manager().dict(**data) - else: - self.manager = None - self.cache = dict(**data) - self.size = 0 - - def __setitem__(self, key, value): - if key in self.cache: - self.size -= get_size(self.cache[key]) - else: - self.size += sys.getsizeof(key) - self.size += get_size(value) - self.cache[key] = value - - def __getitem__(self, key): - return self.cache[key] - - def __delitem__(self, key): - self.size -= get_size(self.cache[key]) - self.size -= sys.getsizeof(key) - del self.cache[key] - - def __iter__(self): - return iter(self.cache) - - def __contains__(self, key): - return key in self.cache - - def __len__(self): - return len(self.cache) diff --git a/funasr/utils/wav_utils.py b/funasr/utils/wav_utils.py deleted file mode 100644 index 8c2dc6884..000000000 --- a/funasr/utils/wav_utils.py +++ /dev/null @@ -1,332 +0,0 @@ -# Copyright (c) Alibaba, Inc. and its affiliates. - -import math -import os -import shutil -from multiprocessing import Pool -from typing import Any, Dict, Union - -import kaldiio -import librosa -import numpy as np -import torch -import torchaudio -import librosa -import torchaudio.compliance.kaldi as kaldi - - -def ndarray_resample(audio_in: np.ndarray, - fs_in: int = 16000, - fs_out: int = 16000) -> np.ndarray: - audio_out = audio_in - if fs_in != fs_out: - audio_out = librosa.resample(audio_in, orig_sr=fs_in, target_sr=fs_out) - return audio_out - - -def torch_resample(audio_in: torch.Tensor, - fs_in: int = 16000, - fs_out: int = 16000) -> torch.Tensor: - audio_out = audio_in - if fs_in != fs_out: - audio_out = torchaudio.transforms.Resample(orig_freq=fs_in, - new_freq=fs_out)(audio_in) - return audio_out - - -def extract_CMVN_featrures(mvn_file): - """ - extract CMVN from cmvn.ark - """ - - if not os.path.exists(mvn_file): - return None - try: - cmvn = kaldiio.load_mat(mvn_file) - means = [] - variance = [] - - for i in range(cmvn.shape[1] - 1): - means.append(float(cmvn[0][i])) - - count = float(cmvn[0][-1]) - - for i in range(cmvn.shape[1] - 1): - variance.append(float(cmvn[1][i])) - - for i in range(len(means)): - means[i] /= count - variance[i] = variance[i] / count - means[i] * means[i] - if variance[i] < 1.0e-20: - variance[i] = 1.0e-20 - variance[i] = 1.0 / math.sqrt(variance[i]) - - cmvn = np.array([means, variance]) - return cmvn - except Exception: - cmvn = extract_CMVN_features_txt(mvn_file) - return cmvn - - -def extract_CMVN_features_txt(mvn_file): # noqa - with open(mvn_file, 'r', encoding='utf-8') as f: - lines = f.readlines() - - add_shift_list = [] - rescale_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)] - add_shift_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)] - rescale_list = list(rescale_line) - continue - add_shift_list_f = [float(s) for s in add_shift_list] - rescale_list_f = [float(s) for s in rescale_list] - cmvn = np.array([add_shift_list_f, rescale_list_f]) - return cmvn - - -def build_LFR_features(inputs, m=7, n=6): # noqa - """ - Actually, this implements stacking frames and skipping frames. - if m = 1 and n = 1, just return the origin features. - if m = 1 and n > 1, it works like skipping. - if m > 1 and n = 1, it works like stacking but only support right frames. - if m > 1 and n > 1, it works like LFR. - - Args: - inputs_batch: inputs is T x D np.ndarray - m: number of frames to stack - n: number of frames to skip - """ - # LFR_inputs_batch = [] - # for inputs in inputs_batch: - LFR_inputs = [] - T = inputs.shape[0] - T_lfr = int(np.ceil(T / n)) - left_padding = np.tile(inputs[0], ((m - 1) // 2, 1)) - inputs = np.vstack((left_padding, inputs)) - T = T + (m - 1) // 2 - for i in range(T_lfr): - if m <= T - i * n: - LFR_inputs.append(np.hstack(inputs[i * n:i * n + m])) - else: # process last LFR frame - num_padding = m - (T - i * n) - frame = np.hstack(inputs[i * n:]) - for _ in range(num_padding): - frame = np.hstack((frame, inputs[-1])) - LFR_inputs.append(frame) - return np.vstack(LFR_inputs) - - -def compute_fbank(wav_file, - num_mel_bins=80, - frame_length=25, - frame_shift=10, - dither=0.0, - is_pcm=False, - fs: Union[int, Dict[Any, int]] = 16000): - audio_sr: int = 16000 - model_sr: int = 16000 - if isinstance(fs, int): - model_sr = fs - audio_sr = fs - else: - model_sr = fs['model_fs'] - audio_sr = fs['audio_fs'] - - if is_pcm is True: - # byte(PCM16) to float32, and resample - value = wav_file - middle_data = np.frombuffer(value, 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 - waveform = np.frombuffer( - (middle_data.astype(dtype) - offset) / abs_max, dtype=np.float32) - waveform = ndarray_resample(waveform, audio_sr, model_sr) - waveform = torch.from_numpy(waveform.reshape(1, -1)) - else: - # load pcm from wav, and resample - try: - waveform, audio_sr = torchaudio.load(wav_file) - except: - waveform, audio_sr = librosa.load(wav_file, dtype='float32') - if waveform.ndim == 2: - waveform = waveform[:, 0] - waveform = torch.tensor(np.expand_dims(waveform, axis=0)) - waveform = waveform * (1 << 15) - waveform = torch_resample(waveform, audio_sr, model_sr) - - mat = kaldi.fbank(waveform, - num_mel_bins=num_mel_bins, - frame_length=frame_length, - frame_shift=frame_shift, - dither=dither, - energy_floor=0.0, - window_type='hamming', - sample_frequency=model_sr) - - input_feats = mat - - return input_feats - - -def wav2num_frame(wav_path, frontend_conf): - try: - waveform, sampling_rate = torchaudio.load(wav_path) - except: - waveform, sampling_rate = librosa.load(wav_path) - waveform = torch.tensor(np.expand_dims(waveform, axis=0)) - speech_length = (waveform.shape[1] / sampling_rate) * 1000. - n_frames = (waveform.shape[1] * 1000.0) / (sampling_rate * frontend_conf["frame_shift"] * frontend_conf["lfr_n"]) - feature_dim = frontend_conf["n_mels"] * frontend_conf["lfr_m"] - return n_frames, feature_dim, speech_length - - -def calc_shape_core(root_path, frontend_conf, speech_length_min, speech_length_max, idx): - wav_scp_file = os.path.join(root_path, "wav.scp.{}".format(idx)) - shape_file = os.path.join(root_path, "speech_shape.{}".format(idx)) - with open(wav_scp_file) as f: - lines = f.readlines() - with open(shape_file, "w") as f: - for line in lines: - sample_name, wav_path = line.strip().split() - n_frames, feature_dim, speech_length = wav2num_frame(wav_path, frontend_conf) - write_flag = True - if speech_length_min > 0 and speech_length < speech_length_min: - write_flag = False - if speech_length_max > 0 and speech_length > speech_length_max: - write_flag = False - if write_flag: - f.write("{} {},{}\n".format(sample_name, str(int(np.ceil(n_frames))), str(int(feature_dim)))) - f.flush() - - -def calc_shape(data_dir, dataset, frontend_conf, speech_length_min=-1, speech_length_max=-1, nj=32): - shape_path = os.path.join(data_dir, dataset, "shape_files") - if os.path.exists(shape_path): - assert os.path.exists(os.path.join(data_dir, dataset, "speech_shape")) - print('Shape file for small dataset already exists.') - return - os.makedirs(shape_path, exist_ok=True) - - # split - wav_scp_file = os.path.join(data_dir, dataset, "wav.scp") - with open(wav_scp_file) as f: - lines = f.readlines() - num_lines = len(lines) - num_job_lines = num_lines // nj - start = 0 - for i in range(nj): - end = start + num_job_lines - file = os.path.join(shape_path, "wav.scp.{}".format(str(i + 1))) - with open(file, "w") as f: - if i == nj - 1: - f.writelines(lines[start:]) - else: - f.writelines(lines[start:end]) - start = end - - p = Pool(nj) - for i in range(nj): - p.apply_async(calc_shape_core, - args=(shape_path, frontend_conf, speech_length_min, speech_length_max, str(i + 1))) - print('Generating shape files, please wait a few minutes...') - p.close() - p.join() - - # combine - file = os.path.join(data_dir, dataset, "speech_shape") - with open(file, "w") as f: - for i in range(nj): - job_file = os.path.join(shape_path, "speech_shape.{}".format(str(i + 1))) - with open(job_file) as job_f: - lines = job_f.readlines() - f.writelines(lines) - print('Generating shape files done.') - - -def generate_data_list(data_dir, dataset, nj=100): - split_dir = os.path.join(data_dir, dataset, "split") - if os.path.exists(split_dir): - assert os.path.exists(os.path.join(data_dir, dataset, "data.list")) - print('Data list for large dataset already exists.') - return - os.makedirs(split_dir, exist_ok=True) - - with open(os.path.join(data_dir, dataset, "wav.scp")) as f_wav: - wav_lines = f_wav.readlines() - with open(os.path.join(data_dir, dataset, "text")) as f_text: - text_lines = f_text.readlines() - total_num_lines = len(wav_lines) - num_lines = total_num_lines // nj - start_num = 0 - for i in range(nj): - end_num = start_num + num_lines - split_dir_nj = os.path.join(split_dir, str(i + 1)) - os.mkdir(split_dir_nj) - wav_file = os.path.join(split_dir_nj, 'wav.scp') - text_file = os.path.join(split_dir_nj, "text") - with open(wav_file, "w") as fw, open(text_file, "w") as ft: - if i == nj - 1: - fw.writelines(wav_lines[start_num:]) - ft.writelines(text_lines[start_num:]) - else: - fw.writelines(wav_lines[start_num:end_num]) - ft.writelines(text_lines[start_num:end_num]) - start_num = end_num - - data_list_file = os.path.join(data_dir, dataset, "data.list") - with open(data_list_file, "w") as f_data: - for i in range(nj): - wav_path = os.path.join(split_dir, str(i + 1), "wav.scp") - text_path = os.path.join(split_dir, str(i + 1), "text") - f_data.write(wav_path + " " + text_path + "\n") - -def filter_wav_text(data_dir, dataset): - wav_file = os.path.join(data_dir,dataset,"wav.scp") - text_file = os.path.join(data_dir, dataset, "text") - with open(wav_file) as f_wav, open(text_file) as f_text: - wav_lines = f_wav.readlines() - text_lines = f_text.readlines() - os.rename(wav_file, "{}.bak".format(wav_file)) - os.rename(text_file, "{}.bak".format(text_file)) - wav_dict = {} - for line in wav_lines: - parts = line.strip().split() - if len(parts) != 2: - continue - sample_name, wav_path = parts - wav_dict[sample_name] = wav_path - text_dict = {} - for line in text_lines: - parts = line.strip().split() - if len(parts) < 2: - continue - sample_name = parts[0] - text_dict[sample_name] = " ".join(parts[1:]).lower() - filter_count = 0 - with open(wav_file, "w") as f_wav, open(text_file, "w") as f_text: - for sample_name, wav_path in wav_dict.items(): - if sample_name in text_dict.keys(): - f_wav.write(sample_name + " " + wav_path + "\n") - f_text.write(sample_name + " " + text_dict[sample_name] + "\n") - else: - filter_count += 1 - print("{}/{} samples in {} are filtered because of the mismatch between wav.scp and text".format(len(wav_lines), filter_count, dataset)) diff --git a/docs/model_zoo/huggingface_models.md b/model_zoo/huggingface_models.md similarity index 100% rename from docs/model_zoo/huggingface_models.md rename to model_zoo/huggingface_models.md diff --git a/docs/model_zoo/modelscope_models.md b/model_zoo/modelscope_models.md similarity index 100% rename from docs/model_zoo/modelscope_models.md rename to model_zoo/modelscope_models.md diff --git a/docs/model_zoo/modelscope_models_zh.md b/model_zoo/modelscope_models_zh.md similarity index 100% rename from docs/model_zoo/modelscope_models_zh.md rename to model_zoo/modelscope_models_zh.md