NMCxyz commited on
Commit
6093ad1
·
verified ·
1 Parent(s): a26e1b6

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/prepare_audio.sh +78 -0
  2. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/prepare_audio_v2.sh +68 -0
  3. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/prepare_text.sh +83 -0
  4. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/prepare_timit.sh +79 -0
  5. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/remove_silence.py +63 -0
  6. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/vads.py +98 -0
  7. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py +128 -0
  8. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wav2vec_cluster_faiss.py +210 -0
  9. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py +119 -0
  10. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wer.py +82 -0
  11. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wrd_to_ltr.py +16 -0
  12. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/tasks/__init__.py +11 -0
  13. omni_speech/infer/fairseq/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py +452 -0
  14. omni_speech/infer/fairseq/examples/wav2vec/xlsr/README.md +95 -0
  15. omni_speech/infer/fairseq/examples/wav2vec/xlsr/config/finetune.yaml +66 -0
  16. omni_speech/infer/fairseq/examples/wav2vec/xlsr/scripts/eval_speaker_clf_task.py +173 -0
  17. omni_speech/infer/fairseq/examples/wav2vec/xlsr/scripts/gen_audio_embedding.py +222 -0
  18. omni_speech/infer/fairseq/examples/wmt19/README.md +85 -0
  19. omni_speech/infer/fairseq/examples/wmt20/README.md +72 -0
  20. omni_speech/infer/fairseq/examples/wmt21/README.md +25 -0
  21. omni_speech/infer/fairseq/examples/wmt21/eval.sh +49 -0
  22. omni_speech/infer/fairseq/examples/wmt21/scripts/normalize-punctuation.perl +90 -0
  23. omni_speech/infer/fairseq/examples/wmt21/scripts/replace-unicode-punctuation.perl +55 -0
  24. omni_speech/infer/fairseq/examples/womens_bios/README.md +81 -0
  25. omni_speech/infer/fairseq/examples/womens_bios/query_occupations_from_wikidata.py +34 -0
  26. omni_speech/infer/fairseq/examples/xformers/README.md +43 -0
  27. omni_speech/infer/fairseq/examples/xglm/README.md +195 -0
  28. omni_speech/infer/fairseq/examples/xglm/XStoryCloze.md +57 -0
  29. omni_speech/infer/fairseq/examples/xglm/model_card.md +152 -0
  30. omni_speech/infer/fairseq/examples/xlmr/README.md +144 -0
  31. omni_speech/infer/fairseq/examples/xmod/README.md +151 -0
  32. omni_speech/infer/fairseq/examples/xmod/preprocess_nli.py +168 -0
  33. omni_speech/infer/fairseq/fairseq/__init__.py +45 -0
  34. omni_speech/infer/fairseq/fairseq/benchmark/__init__.py +7 -0
  35. omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/__init__.cpython-312.pyc +0 -0
  36. omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_dataset.cpython-312.pyc +0 -0
  37. omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_lm.cpython-312.pyc +0 -0
  38. omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_masked_lm.cpython-312.pyc +0 -0
  39. omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_model.cpython-312.pyc +0 -0
  40. omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_mt.cpython-312.pyc +0 -0
  41. omni_speech/infer/fairseq/fairseq/benchmark/benchmark_multihead_attention.py +172 -0
  42. omni_speech/infer/fairseq/fairseq/benchmark/dummy_dataset.py +36 -0
  43. omni_speech/infer/fairseq/fairseq/benchmark/dummy_lm.py +83 -0
  44. omni_speech/infer/fairseq/fairseq/benchmark/dummy_masked_lm.py +94 -0
  45. omni_speech/infer/fairseq/fairseq/benchmark/dummy_model.py +96 -0
  46. omni_speech/infer/fairseq/fairseq/benchmark/dummy_mt.py +119 -0
  47. omni_speech/infer/fairseq/fairseq/binarizer.py +381 -0
  48. omni_speech/infer/fairseq/fairseq/checkpoint_utils.py +918 -0
  49. omni_speech/infer/fairseq/fairseq/clib/cuda/ngram_repeat_block_cuda.cpp +55 -0
  50. omni_speech/infer/fairseq/fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu +82 -0
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/prepare_audio.sh ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env zsh
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ source_dir=$1
8
+ tgt_dir=$2
9
+ model=$3
10
+
11
+ if [ -z "$4" ]
12
+ then
13
+ dim=512
14
+ else
15
+ dim=$4
16
+ fi
17
+
18
+ echo "using $dim dim for PCA"
19
+
20
+ if [ -z "$5" ]
21
+ then
22
+ layer=14
23
+ else
24
+ layer=$5
25
+ fi
26
+
27
+ echo "extracting from layer $layer"
28
+
29
+ train_split=train
30
+ valid_split=valid
31
+ test_split=test
32
+
33
+ all_splits=($train_split)
34
+
35
+ if [[ -f "$source_dir/valid.tsv" ]]; then
36
+ all_splits+=('valid')
37
+ fi
38
+
39
+ if [[ -f "$source_dir/test.tsv" ]]; then
40
+ all_splits+=('test')
41
+ fi
42
+
43
+ echo "processing splits: $all_splits"
44
+
45
+ mkdir -p $tgt_dir
46
+
47
+ cp $source_dir/*.tsv $tgt_dir
48
+ cp $source_dir/*.wrd $tgt_dir
49
+ cp $source_dir/*.ltr $tgt_dir
50
+ cp $source_dir/*.phn $tgt_dir
51
+ cp $source_dir/dict* $tgt_dir
52
+
53
+ setopt shwordsplit
54
+
55
+ for split in $all_splits; do
56
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py $source_dir --split $split \
57
+ --save-dir $tgt_dir --checkpoint $model --layer $layer
58
+ done
59
+
60
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/wav2vec_cluster_faiss.py $tgt_dir/${train_split}.tsv \
61
+ --checkpoint $model --save-dir $tgt_dir -f "CLUS128" --sample-pct 1.0
62
+
63
+ for split in $all_splits; do
64
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py $tgt_dir \
65
+ --checkpoint $model --path $tgt_dir/CLUS128 --split $split
66
+ done
67
+
68
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/pca.py $tgt_dir/${train_split}.npy --output $tgt_dir/pca --dim $dim
69
+
70
+ for split in $all_splits; do
71
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/apply_pca.py $tgt_dir --split $split --save-dir $tgt_dir/precompute_pca$dim --pca-path $tgt_dir/pca/${dim}_pca --batch-size 1048000
72
+
73
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/merge_clusters.py $tgt_dir/precompute_pca$dim --cluster-dir $tgt_dir/CLUS128 \
74
+ --split $split --save-dir $tgt_dir/precompute_pca${dim}_cls128_mean --pooling mean
75
+
76
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/mean_pool.py $tgt_dir/precompute_pca${dim}_cls128_mean \
77
+ --save-dir $tgt_dir/precompute_pca${dim}_cls128_mean_pooled --split $split
78
+ done
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/prepare_audio_v2.sh ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env zsh
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ source_dir=$1
8
+ tgt_dir=$2
9
+ model=$3
10
+
11
+ if [ -z "$4" ]
12
+ then
13
+ dim=64
14
+ else
15
+ dim=$4
16
+ fi
17
+
18
+ echo "using $dim clusters for auxilary target"
19
+
20
+ if [ -z "$5" ]
21
+ then
22
+ layer=14
23
+ else
24
+ layer=$5
25
+ fi
26
+
27
+ echo "extracting from layer $layer"
28
+
29
+ train_split=train
30
+ valid_split=valid
31
+ test_split=test
32
+
33
+ all_splits=($train_split)
34
+
35
+ if [[ -f "$source_dir/valid.tsv" ]]; then
36
+ all_splits+=('valid')
37
+ fi
38
+
39
+ if [[ -f "$source_dir/test.tsv" ]]; then
40
+ all_splits+=('test')
41
+ fi
42
+
43
+ echo "processing splits: $all_splits"
44
+
45
+ mkdir -p $tgt_dir
46
+
47
+ cp $source_dir/*.tsv $tgt_dir
48
+ cp $source_dir/*.wrd $tgt_dir
49
+ cp $source_dir/*.ltr $tgt_dir
50
+ cp $source_dir/*.phn $tgt_dir
51
+ cp $source_dir/dict* $tgt_dir
52
+
53
+ setopt shwordsplit
54
+
55
+ for split in $all_splits; do
56
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py $source_dir --split $split \
57
+ --save-dir $tgt_dir --checkpoint $model --layer $layer
58
+ done
59
+
60
+
61
+ mkdir -p $tgt_dir/mfcc
62
+
63
+ # Consider spliting corpus into chuncks for large corpus, see HuBERT preprocessing for more details
64
+ python $FAIRSEQ_ROOT/examples/hubert/simple_kmeans/dump_mfcc_feature.py \
65
+ $tgt_dir $train_split 1 0 $tgt_dir/mfcc
66
+ python $FAIRSEQ_ROOT/examples/hubert/simple_kmeans/dump_km_label.py \
67
+ $tgt_dir/mfcc $train_split $tgt_dir/mfcc/cls$dim 1 0 $tgt_dir/mfcc/cls${dim}_idx
68
+ cp $tgt_dir/mfcc/cls${dim}_idx/${train_split}_0_1.km $tgt_dir/$train_split.km
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/prepare_text.sh ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env zsh
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ lg=$1
8
+ text_path=$2
9
+ target_dir=$3
10
+ min_phones=$4
11
+ phonemizer=$5
12
+ lid_path=$6
13
+ sil_prob=$7
14
+
15
+ if [ -z "$lid_path" ]; then
16
+ lid_path="lid.187.bin"
17
+ fi
18
+
19
+ ph_lg=${lg:l}
20
+ if test "$lg" = 'fr'; then
21
+ ph_lg='fr-fr'
22
+ elif test "$lg" = 'en'; then
23
+ ph_lg='en-us'
24
+ elif test "$lg" = 'pt'; then
25
+ ph_lg='pt-br'
26
+ fi
27
+
28
+ ESPEAK_PATH=''
29
+ if test "$phonemizer" = 'espeak'; then
30
+ ESPEAK_PATH=$(which espeak)
31
+ elif test "$phonemizer" = 'espeak-ng'; then
32
+ ESPEAK_PATH=$(which espeak-ng)
33
+ elif test "$phonemizer" = 'G2P'; then
34
+ ESPEAK_PATH=''
35
+ else
36
+ echo "Unknown phonemizer $phonemizer. Valid options are espeak, espean-ng and G2P"
37
+ exit 1
38
+ fi
39
+
40
+ echo $lg
41
+ echo $ph_lg
42
+ echo $text_path
43
+ echo $target_dir
44
+ echo "min phone seen threshold is $min_phones"
45
+
46
+ mkdir -p $target_dir
47
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py --lang $lg --fasttext-model $lid_path < $text_path | grep -v '\-\-\-' >! $target_dir/lm.upper.lid.txt
48
+ python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/lm.upper.lid.txt --only-source --destdir $target_dir --thresholdsrc 2 --padding-factor 1 --dict-only
49
+ cut -f1 -d' ' $target_dir/dict.txt | grep -v -x '[[:punct:]]*' | grep -Pv '\d\d\d\d\d+' >! $target_dir/words.txt
50
+
51
+
52
+ if [ -z "$ESPEAK_PATH" ]; then
53
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py --compact < $target_dir/words.txt > $target_dir/phones.txt
54
+ else
55
+ # echoing 1 into corpus will prevent the mismatch lines between lexicon and phones in case the phonemizer fails
56
+ one=$(echo "1" | PHONEMIZER_ESPEAK_PATH=$ESPEAK_PATH phonemize -p ' ' -w '' -l $ph_lg --language-switch remove-flags)
57
+ sed 's/$/ 1/' $target_dir/words.txt | PHONEMIZER_ESPEAK_PATH=$ESPEAK_PATH phonemize -o $target_dir/phones.txt -p ' ' -w '' -l $ph_lg -j 70 --language-switch remove-flags
58
+ echo "one is ${one}"
59
+ sed -i "s/${one}$//" $target_dir/phones.txt
60
+ fi
61
+
62
+ paste $target_dir/words.txt $target_dir/phones.txt >! $target_dir/lexicon.lst
63
+
64
+ python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/phones.txt --only-source --destdir $target_dir/phones --thresholdsrc $min_phones --padding-factor 1 --dict-only
65
+
66
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/filter_lexicon.py -d $target_dir/phones/dict.txt < $target_dir/lexicon.lst >! $target_dir/lexicon_filtered.lst
67
+ python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/phonemize_with_sil.py -s $sil_prob --surround --lexicon $target_dir/lexicon_filtered.lst < $target_dir/lm.upper.lid.txt >! $target_dir/phones/lm.phones.filtered.txt
68
+ cp $target_dir/phones/dict.txt $target_dir/phones/dict.phn.txt
69
+ echo "<SIL> 0" >> $target_dir/phones/dict.phn.txt
70
+ python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/phones/lm.phones.filtered.txt --workers 70 --only-source --destdir $target_dir/phones --srcdict $target_dir/phones/dict.phn.txt
71
+
72
+ $KENLM_ROOT/lmplz -o 4 < $target_dir/lm.upper.lid.txt --discount_fallback --prune 0 0 0 3 >! $target_dir/kenlm.wrd.o40003.arpa
73
+ $KENLM_ROOT/build_binary $target_dir/kenlm.wrd.o40003.arpa $target_dir/kenlm.wrd.o40003.bin
74
+
75
+ lg=$lg python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py kaldi_root=$KALDI_ROOT fst_dir=$target_dir/fst/phn_to_words_sil lm_arpa=$target_dir/kenlm.wrd.o40003.arpa wav2letter_lexicon=$target_dir/lexicon_filtered.lst data_dir=$target_dir/phones in_labels=phn "blank_symbol='<SIL>'"
76
+ lg=$lg python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py kaldi_root=$KALDI_ROOT fst_dir=$target_dir/fst/phn_to_words lm_arpa=$target_dir/kenlm.wrd.o40003.arpa wav2letter_lexicon=$target_dir/lexicon_filtered.lst data_dir=$target_dir/phones in_labels=phn
77
+
78
+ $KENLM_ROOT/lmplz -o 4 < $target_dir/phones/lm.phones.filtered.txt --discount_fallback >! $target_dir/phones/lm.phones.filtered.04.arpa
79
+ $KENLM_ROOT/build_binary $target_dir/phones/lm.phones.filtered.04.arpa $target_dir/phones/lm.phones.filtered.04.bin
80
+ $KENLM_ROOT/lmplz -o 6 < $target_dir/phones/lm.phones.filtered.txt --discount_fallback >! $target_dir/phones/lm.phones.filtered.06.arpa
81
+ $KENLM_ROOT/build_binary $target_dir/phones/lm.phones.filtered.06.arpa $target_dir/phones/lm.phones.filtered.06.bin
82
+
83
+ lg=$lg python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py kaldi_root=$KALDI_ROOT fst_dir=$target_dir/fst/phn_to_phn_sil lm_arpa=$target_dir/phones/lm.phones.filtered.06.arpa data_dir=$target_dir/phones in_labels=phn "blank_symbol='<SIL>'"
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/prepare_timit.sh ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ timit_root=$1 # assume it is the upper-cased version
8
+ tgt_dir=$2
9
+ model=$3
10
+
11
+ set -eu
12
+
13
+ setups="matched unmatched"
14
+ splits="test valid train train_text"
15
+
16
+ tgt_dir=$(realpath $tgt_dir)
17
+ sph2wav=$KALDI_ROOT/tools/sph2pipe_v2.5/sph2pipe
18
+ wav_dir=$tgt_dir/wav
19
+
20
+
21
+ mkdir -p $tgt_dir $wav_dir
22
+ find $timit_root/{TRAIN,TEST} -iname "*.WAV" > $tgt_dir/all_sph.flist
23
+ cat $tgt_dir/all_sph.flist | sed -e 's#//*#/#g' -e 's#.*/\([^/]*\)/\([^/]*\).WAV#\1_\2#g' > $tgt_dir/all.uid
24
+ paste -d' ' $tgt_dir/{all_sph.flist,all.uid} | \
25
+ awk -v sph2wav=$sph2wav -v wav_dir=$wav_dir '{print sph2wav " -f wav " $1 " > " wav_dir "/" $2 ".wav"}' \
26
+ > $tgt_dir/sph2wav.sh
27
+ bash $tgt_dir/sph2wav.sh
28
+ cat $tgt_dir/all.uid | awk -v wav_dir=$(pwd)/$wav_dir '{print $1" "wav_dir"/"$1".wav"}' | sort > $tgt_dir/all_wav.scp
29
+ cut -d' ' -f2 $tgt_dir/all_wav.scp | xargs -I{} soxi -s {} > $tgt_dir/all.dur
30
+ paste -d' ' $tgt_dir/{all_wav.scp,all.dur} > $tgt_dir/all_wav_dur.scp
31
+ rm $tgt_dir/{all.uid,all_sph.flist,sph2wav.sh}
32
+
33
+ find $timit_root/{TRAIN,TEST} -iname "*.PHN" > $tgt_dir/all_phn60.flist
34
+ while read line; do
35
+ if [ ! -f $line ]; then
36
+ >&2 echo "Cannot find transcription file '$line'" && exit 1;
37
+ fi
38
+ cut -f3 -d' ' "$line" | tr '\n' ' ' | perl -ape 's: *$:\n:;'
39
+ done < $tgt_dir/all_phn60.flist > $tgt_dir/all.phn60
40
+ cat $tgt_dir/all_phn60.flist | sed -e 's#//*#/#g' -e 's#.*/\([^/]*\)/\([^/]*\).PHN#\1_\2#g' | \
41
+ paste -d' ' - $tgt_dir/all.phn60 | \
42
+ $KALDI_ROOT/egs/timit/s5/local/timit_norm_trans.pl -i - -m $KALDI_ROOT/egs/timit/s5/conf/phones.60-48-39.map -to 39 | \
43
+ sort > $tgt_dir/all.phn
44
+ echo "done preparing wav and 39-phone transcripts"
45
+
46
+
47
+ for s in $setups; do
48
+ mkdir -p $tgt_dir/$s
49
+ for x in $splits; do
50
+ uid_path=config/timit_${s}/${x}.uid
51
+ grep -w -f $uid_path $tgt_dir/all.phn | cut -d' ' -f2- > $tgt_dir/$s/$x.phn
52
+ ln -sf $(realpath $tgt_dir/$s/$x.phn) $tgt_dir/$s/$x.wrd
53
+
54
+ echo "/" > $tgt_dir/$s/$x.tsv && grep -w -f $uid_path $tgt_dir/all_wav_dur.scp | cut -d' ' -f2- | sed 's# #\t#' >> $tgt_dir/$s/$x.tsv
55
+ done
56
+
57
+ for x in $splits; do
58
+ cat $tgt_dir/$s/$x.phn
59
+ done | tr ' ' '\n' | sort -u | awk '{print $1" "1}' > $tgt_dir/$s/dict.phn.txt
60
+ ln -sf $(realpath $tgt_dir/$s/dict.phn.txt) $tgt_dir/$s/dict.wrd.txt
61
+ done
62
+ echo "done preparing unmatched and matched setups for TIMIT"
63
+
64
+
65
+ for s in $setups; do
66
+ zsh scripts/prepare_audio.sh $tgt_dir/$s $tgt_dir/$s/feat $model
67
+
68
+ lm_dir=$tgt_dir/$s/phones
69
+ fst_dir=$tgt_dir/$s/fst/phn_to_phn
70
+
71
+ python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $tgt_dir/$s/train_text.phn --workers 10 --only-source --destdir $lm_dir --srcdict $tgt_dir/$s/dict.phn.txt
72
+ $KENLM_ROOT/lmplz -o 3 < $tgt_dir/$s/train_text.phn --discount_fallback >$lm_dir/train_text_phn.03.arpa
73
+ $KENLM_ROOT/build_binary $lm_dir/train_text_phn.03.arpa $lm_dir/train_text_phn.03.bin
74
+ $KENLM_ROOT/lmplz -o 4 < $tgt_dir/$s/train_text.phn --discount_fallback >$lm_dir/train_text_phn.04.arpa
75
+ $KENLM_ROOT/build_binary $lm_dir/train_text_phn.04.arpa $lm_dir/train_text_phn.04.bin
76
+
77
+ python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py kaldi_root=$KALDI_ROOT fst_dir=$fst_dir lm_arpa=$lm_dir/train_text_phn.03.arpa data_dir=$tgt_dir/$s in_labels=phn
78
+ done
79
+ echo "done preprocessing audio and text for wav2vec-U"
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/remove_silence.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3 -u
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ """
8
+ get intervals from .vads file, specify output data, and this script removes silences and saves the audio data in out path folder
9
+ paths=shards/train.tsv
10
+ vads=shards/train.vads
11
+ python remove_silence.py --paths $paths --vads $vads
12
+ """
13
+
14
+ import os
15
+ import argparse
16
+ import torch
17
+ import torchaudio
18
+ import tqdm
19
+
20
+
21
+ parser = argparse.ArgumentParser()
22
+ parser.add_argument("--tsv", default="", type=str)
23
+ parser.add_argument("--vads", default="", type=str)
24
+ parser.add_argument("--out", type=str)
25
+ params = parser.parse_args()
26
+
27
+ # load paths
28
+ paths = []
29
+ with open(params.tsv) as f:
30
+ root = next(f).rstrip()
31
+ for line in f:
32
+ paths.append(os.path.join(root, line.rstrip().split("\t")[0]))
33
+
34
+ # load vads
35
+ list_intervals = []
36
+ with open(params.vads) as f:
37
+ for line in f:
38
+ interval = [
39
+ [int(w.split(":")[0]), int(w.split(":")[1])] for w in line.rstrip().split()
40
+ ]
41
+ list_intervals.append(interval)
42
+
43
+
44
+ # load audio and keep only intervals (i.e. remove silences)
45
+ for i in tqdm.trange(len(paths)):
46
+ data, _ = torchaudio.load(paths[i])
47
+ if len(list_intervals[i]) > 0:
48
+ data_filtered = torch.cat(
49
+ [data[0][int(it[0]) : int(it[1])] for it in list_intervals[i]]
50
+ ).unsqueeze(0)
51
+ else:
52
+ data_filtered = data
53
+
54
+ # YOU MAY NEED TO MODIFY THIS TO GET THE RIGHT SUBPATH
55
+ # outpath = params.out + '/'.join(paths[i].split('/')[-1])
56
+ outpath = params.out + "/" + "/".join(paths[i].split("/")[-2:])
57
+
58
+ if not os.path.isdir("/".join(outpath.split("/")[:-1])):
59
+ os.makedirs("/".join(outpath.split("/")[:-1]))
60
+ if not os.path.exists(outpath):
61
+ torchaudio.save(outpath, data_filtered, sample_rate=16000)
62
+ else:
63
+ print(outpath, "exists!")
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/vads.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3 -u
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ import argparse
8
+ import sys
9
+
10
+ from copy import deepcopy
11
+ from scipy.signal import lfilter
12
+
13
+ import numpy as np
14
+ from tqdm import tqdm
15
+ import soundfile as sf
16
+ import os.path as osp
17
+
18
+
19
+ def get_parser():
20
+ parser = argparse.ArgumentParser(description="compute vad segments")
21
+ parser.add_argument(
22
+ "--rvad-home",
23
+ "-r",
24
+ help="path to rvad home (see https://github.com/zhenghuatan/rVADfast)",
25
+ required=True,
26
+ )
27
+
28
+ return parser
29
+
30
+
31
+ def rvad(speechproc, path):
32
+ winlen, ovrlen, pre_coef, nfilter, nftt = 0.025, 0.01, 0.97, 20, 512
33
+ ftThres = 0.5
34
+ vadThres = 0.4
35
+ opts = 1
36
+
37
+ data, fs = sf.read(path)
38
+ assert fs == 16_000, "sample rate must be 16khz"
39
+ ft, flen, fsh10, nfr10 = speechproc.sflux(data, fs, winlen, ovrlen, nftt)
40
+
41
+ # --spectral flatness --
42
+ pv01 = np.zeros(ft.shape[0])
43
+ pv01[np.less_equal(ft, ftThres)] = 1
44
+ pitch = deepcopy(ft)
45
+
46
+ pvblk = speechproc.pitchblockdetect(pv01, pitch, nfr10, opts)
47
+
48
+ # --filtering--
49
+ ENERGYFLOOR = np.exp(-50)
50
+ b = np.array([0.9770, -0.9770])
51
+ a = np.array([1.0000, -0.9540])
52
+ fdata = lfilter(b, a, data, axis=0)
53
+
54
+ # --pass 1--
55
+ noise_samp, noise_seg, n_noise_samp = speechproc.snre_highenergy(
56
+ fdata, nfr10, flen, fsh10, ENERGYFLOOR, pv01, pvblk
57
+ )
58
+
59
+ # sets noisy segments to zero
60
+ for j in range(n_noise_samp):
61
+ fdata[range(int(noise_samp[j, 0]), int(noise_samp[j, 1]) + 1)] = 0
62
+
63
+ vad_seg = speechproc.snre_vad(
64
+ fdata, nfr10, flen, fsh10, ENERGYFLOOR, pv01, pvblk, vadThres
65
+ )
66
+ return vad_seg, data
67
+
68
+
69
+ def main():
70
+ parser = get_parser()
71
+ args = parser.parse_args()
72
+
73
+ sys.path.append(args.rvad_home)
74
+ import speechproc
75
+
76
+ stride = 160
77
+ lines = sys.stdin.readlines()
78
+ root = lines[0].rstrip()
79
+ for fpath in tqdm(lines[1:]):
80
+ path = osp.join(root, fpath.split()[0])
81
+ vads, wav = rvad(speechproc, path)
82
+
83
+ start = None
84
+ vad_segs = []
85
+ for i, v in enumerate(vads):
86
+ if start is None and v == 1:
87
+ start = i * stride
88
+ elif start is not None and v == 0:
89
+ vad_segs.append((start, i * stride))
90
+ start = None
91
+ if start is not None:
92
+ vad_segs.append((start, len(wav)))
93
+
94
+ print(" ".join(f"{v[0]}:{v[1]}" for v in vad_segs))
95
+
96
+
97
+ if __name__ == "__main__":
98
+ main()
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3 -u
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ import argparse
8
+ import os
9
+ import os.path as osp
10
+ import numpy as np
11
+ import tqdm
12
+ import torch
13
+ import sys
14
+
15
+ import faiss
16
+ import torch.nn.functional as F
17
+
18
+ from wav2vec_cluster_faiss import parse_faiss_specs, Wav2VecFeatureReader
19
+
20
+
21
+ def get_parser():
22
+ parser = argparse.ArgumentParser(description="apply clusters")
23
+ # fmt: off
24
+ parser.add_argument('data', help='location of tsv files')
25
+ parser.add_argument('--split', help='split to process', required=True)
26
+ parser.add_argument('--labels', help='split to process', default="phn")
27
+ parser.add_argument('--path', help='path to pca and centroids', required=True)
28
+ parser.add_argument('--checkpoint', type=str, help='checkpoint for wav2vec model (if using wav2vec features)', required=True)
29
+ parser.add_argument('--layer', '-l', type=int, help='which layer to read', default=14)
30
+ parser.add_argument('--max-tsz', type=int, help='batch kmeans up to this much', default=14)
31
+ # fmt: on
32
+
33
+ return parser
34
+
35
+
36
+ def get_iterator(args):
37
+ label_path = osp.join(args.data, f"{args.split}.{args.labels}")
38
+ if osp.exists(label_path):
39
+ lp = open(label_path, "r")
40
+ else:
41
+ lp = None
42
+
43
+ with open(osp.join(args.data, f"{args.split}.tsv"), "r") as fp:
44
+ lines = fp.read().split("\n")
45
+ root = lines.pop(0).strip()
46
+ files = [line.rstrip() for line in lines if len(line) > 0]
47
+
48
+ if lp is not None:
49
+ lbls = [line.rstrip() for line in lp]
50
+ else:
51
+ lbls = [None] * len(files)
52
+
53
+ num = len(files)
54
+ reader = Wav2VecFeatureReader(args.checkpoint, args.layer)
55
+
56
+ def iterate():
57
+ for fname, lbl in zip(files, lbls):
58
+ file = osp.join(root, fname.split("\t")[0])
59
+ feats = reader.get_feats(file)
60
+ yield feats.data, fname, lbl
61
+
62
+ return iterate, num, root
63
+
64
+
65
+ def main():
66
+ parser = get_parser()
67
+ args = parser.parse_args()
68
+
69
+ spec = osp.basename(args.path)
70
+
71
+ try:
72
+ faiss_spec = parse_faiss_specs(spec.rstrip("/"))[0]
73
+ except:
74
+ print(spec)
75
+ raise
76
+
77
+ print("Faiss Spec:", faiss_spec, file=sys.stderr)
78
+
79
+ if faiss_spec.pca:
80
+ A = torch.from_numpy(np.load(osp.join(args.path, "pca_A.npy"))).cuda()
81
+ b = torch.from_numpy(np.load(osp.join(args.path, "pca_b.npy"))).cuda()
82
+ print("Loaded PCA", file=sys.stderr)
83
+
84
+ centroids = np.load(osp.join(args.path, "centroids.npy"))
85
+ print("Loaded centroids", centroids.shape, file=sys.stderr)
86
+
87
+ res = faiss.StandardGpuResources()
88
+ index_flat = (
89
+ faiss.IndexFlatL2(centroids.shape[1])
90
+ if not faiss_spec.sphere
91
+ else faiss.IndexFlatIP(centroids.shape[1])
92
+ )
93
+ faiss_index = faiss.index_cpu_to_gpu(res, 0, index_flat)
94
+ faiss_index.add(centroids)
95
+
96
+ generator, num, root = get_iterator(args)
97
+ iterator = generator()
98
+
99
+ had_labels = False
100
+ label_path = osp.join(args.path, f"{args.split}.{args.labels}")
101
+
102
+ with torch.no_grad():
103
+ with open(osp.join(args.path, f"{args.split}.src"), "w") as fp, open(
104
+ osp.join(args.path, f"{args.split}.tsv"), "w"
105
+ ) as pp, open(label_path, "w") as lp:
106
+ print(root, file=pp)
107
+ for f, fname, lbl in tqdm.tqdm(iterator, total=num):
108
+ if faiss_spec.pca:
109
+ f = torch.mm(f, A) + b
110
+ if faiss_spec.norm:
111
+ f = F.normalize(f, p=2, dim=-1)
112
+
113
+ f = f.cpu().numpy()
114
+
115
+ _, z = faiss_index.search(f, 1)
116
+
117
+ print(" ".join(str(x.item()) for x in z), file=fp)
118
+ print(fname, file=pp)
119
+
120
+ if lbl is not None:
121
+ print(lbl, file=lp)
122
+ had_labels = True
123
+ if not had_labels:
124
+ os.remove(label_path)
125
+
126
+
127
+ if __name__ == "__main__":
128
+ main()
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wav2vec_cluster_faiss.py ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3 -u
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ import argparse
8
+ import gc
9
+ import os
10
+ import os.path as osp
11
+ import random
12
+ import numpy as np
13
+ import tqdm
14
+ import torch
15
+
16
+ from collections import namedtuple
17
+
18
+ import faiss
19
+
20
+ import fairseq
21
+ import soundfile as sf
22
+
23
+
24
+ def get_parser():
25
+ parser = argparse.ArgumentParser(
26
+ description="compute kmeans codebook from kaldi-computed feats"
27
+ )
28
+ # fmt: off
29
+ parser.add_argument('data', help='location of tsv files')
30
+ parser.add_argument('--save-dir', help='where to save the output', required=True)
31
+ parser.add_argument('--checkpoint', type=str, help='checkpoint for wav2vec model (if using wav2vec features)', required=True)
32
+ parser.add_argument('--sample-pct', '-r', type=float, help='percentage of timesteps to sample', default=0)
33
+ parser.add_argument('--layer', '-l', type=int, help='which layer to read', default=14)
34
+ parser.add_argument('--faiss-specs', '-f', type=str,
35
+ help='faiss index specs; separated by space '
36
+ 'format is: PCAx_NORM_CLUSx_SPHERICAL -> '
37
+ 'PCAx if exists first apply PCA '
38
+ 'NORM if exists, normalize the vector by L2 norm '
39
+ 'CLUSx must exist, cluster to x clusters '
40
+ 'SPEHRICAL if exists, apply spherical kmeans',
41
+ default='l2')
42
+ # fmt: on
43
+
44
+ return parser
45
+
46
+
47
+ faiss_spec = namedtuple("faiss_spec", ["pca", "norm", "n_clus", "sphere", "spec_str"])
48
+
49
+
50
+ def parse_faiss_specs(specs_str):
51
+ specs = []
52
+ for ss in specs_str.split():
53
+ comps = ss.split("_")
54
+ pca = 0
55
+ norm = False
56
+ n_clus = 0
57
+ sphere = False
58
+ for c in comps:
59
+ if c.startswith("PCA"):
60
+ pca = int(c[3:])
61
+ elif c == "NORM":
62
+ norm = True
63
+ elif c.startswith("CLUS"):
64
+ n_clus = int(c[4:])
65
+ elif c == "SPHERICAL":
66
+ sphere = True
67
+ assert n_clus > 0
68
+ specs.append(
69
+ faiss_spec(pca=pca, norm=norm, n_clus=n_clus, sphere=sphere, spec_str=ss)
70
+ )
71
+ return specs
72
+
73
+
74
+ class Wav2VecFeatureReader(object):
75
+ def __init__(self, cp_file, layer):
76
+ state = fairseq.checkpoint_utils.load_checkpoint_to_cpu(cp_file)
77
+
78
+ self.layer = layer
79
+
80
+ if "cfg" in state:
81
+ w2v_args = state["cfg"]
82
+ task = fairseq.tasks.setup_task(w2v_args.task)
83
+ model = task.build_model(w2v_args.model)
84
+ else:
85
+ w2v_args = state["args"]
86
+ task = fairseq.tasks.setup_task(w2v_args)
87
+ model = task.build_model(w2v_args)
88
+ model.load_state_dict(state["model"], strict=True)
89
+ model.eval()
90
+ model.cuda()
91
+ self.model = model
92
+
93
+ def read_audio(self, fname):
94
+ """Load an audio file and return PCM along with the sample rate"""
95
+ wav, sr = sf.read(fname)
96
+ assert sr == 16e3
97
+
98
+ return wav
99
+
100
+ def get_feats(self, loc):
101
+ x = self.read_audio(loc)
102
+ with torch.no_grad():
103
+ source = torch.from_numpy(x).view(1, -1).float().cuda()
104
+ res = self.model(
105
+ source=source, mask=False, features_only=True, layer=self.layer
106
+ )
107
+ return res["layer_results"][self.layer][0].squeeze(1)
108
+
109
+
110
+ def get_iterator(args):
111
+ with open(args.data, "r") as fp:
112
+ lines = fp.read().split("\n")
113
+ root = lines.pop(0).strip()
114
+ files = [osp.join(root, line.split("\t")[0]) for line in lines if len(line) > 0]
115
+
116
+ if getattr(args, "sample_pct", 0) > 0:
117
+ files = random.sample(files, int(args.sample_pct * len(files)))
118
+ num = len(files)
119
+ reader = Wav2VecFeatureReader(args.checkpoint, args.layer)
120
+
121
+ def iterate():
122
+ for fname in files:
123
+ feats = reader.get_feats(fname)
124
+ yield feats.cpu().numpy()
125
+
126
+ return iterate, num
127
+
128
+
129
+ def main():
130
+ parser = get_parser()
131
+ args = parser.parse_args()
132
+
133
+ faiss_specs = parse_faiss_specs(args.faiss_specs)
134
+ print("Faiss Specs:", faiss_specs)
135
+
136
+ feat_path = osp.join(args.save_dir, "features")
137
+ if osp.exists(feat_path + ".npy"):
138
+ feats = np.load(feat_path + ".npy")
139
+ else:
140
+ generator, num = get_iterator(args)
141
+ iterator = generator()
142
+
143
+ feats = []
144
+ for f in tqdm.tqdm(iterator, total=num):
145
+ feats.append(f)
146
+
147
+ del iterator
148
+ del generator
149
+
150
+ feats = np.concatenate(feats)
151
+
152
+ print(feats.shape)
153
+
154
+ os.makedirs(args.save_dir, exist_ok=True)
155
+ # np.save(feat_path, feats)
156
+
157
+ gc.collect()
158
+ torch.cuda.empty_cache()
159
+
160
+ reload = False
161
+ for spec in faiss_specs:
162
+ print("Processing spec", spec)
163
+
164
+ if reload:
165
+ print("Reloading...")
166
+ del feats
167
+ gc.collect()
168
+ feats = np.load(feat_path + ".npy")
169
+
170
+ save_path = osp.join(args.save_dir, spec.spec_str)
171
+ os.makedirs(save_path, exist_ok=True)
172
+ d = feats.shape[-1]
173
+ x = feats
174
+ if spec.pca > 0:
175
+ print("Computing PCA")
176
+ pca = faiss.PCAMatrix(d, spec.pca)
177
+ pca.train(x)
178
+ d = spec.pca
179
+ b = faiss.vector_to_array(pca.b)
180
+ A = faiss.vector_to_array(pca.A).reshape(pca.d_out, pca.d_in)
181
+ np.save(osp.join(save_path, "pca_A"), A.T)
182
+ np.save(osp.join(save_path, "pca_b"), b)
183
+ print("Applying PCA")
184
+ x = pca.apply_py(x)
185
+
186
+ if spec.norm:
187
+ reload = spec.pca <= 0
188
+ print("Normalizing")
189
+ faiss.normalize_L2(x)
190
+
191
+ print("Computing kmeans")
192
+ kmeans = faiss.Kmeans(
193
+ d,
194
+ spec.n_clus,
195
+ niter=50,
196
+ verbose=True,
197
+ spherical=spec.sphere,
198
+ max_points_per_centroid=feats.shape[0],
199
+ gpu=True,
200
+ nredo=3,
201
+ )
202
+ kmeans.train(x)
203
+ np.save(osp.join(save_path, "centroids"), kmeans.centroids)
204
+ del kmeans
205
+ del x
206
+ gc.collect()
207
+
208
+
209
+ if __name__ == "__main__":
210
+ main()
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3 -u
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ import argparse
8
+ import os
9
+ import os.path as osp
10
+ import tqdm
11
+ import torch
12
+ import torch.nn.functional as F
13
+ from shutil import copyfile
14
+
15
+ from npy_append_array import NpyAppendArray
16
+
17
+ import fairseq
18
+ import soundfile as sf
19
+
20
+
21
+ def get_parser():
22
+ parser = argparse.ArgumentParser(
23
+ description="compute kmeans codebook from kaldi-computed feats"
24
+ )
25
+ # fmt: off
26
+ parser.add_argument('data', help='location of tsv files')
27
+ parser.add_argument('--split', help='which split to read', required=True)
28
+ parser.add_argument('--save-dir', help='where to save the output', required=True)
29
+ parser.add_argument('--checkpoint', type=str, help='checkpoint for wav2vec ctc model', required=True)
30
+ parser.add_argument('--layer', type=int, default=14, help='which layer to use')
31
+ # fmt: on
32
+
33
+ return parser
34
+
35
+
36
+ class Wav2VecFeatureReader(object):
37
+ def __init__(self, cp_file, layer):
38
+ model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task(
39
+ [cp_file]
40
+ )
41
+ model = model[0]
42
+ model.eval()
43
+ model.cuda()
44
+ self.model = model
45
+ self.task = task
46
+ self.layer = layer
47
+
48
+ def read_audio(self, fname):
49
+ """Load an audio file and return PCM along with the sample rate"""
50
+ wav, sr = sf.read(fname)
51
+ assert sr == 16e3
52
+
53
+ return wav
54
+
55
+ def get_feats(self, loc):
56
+ x = self.read_audio(loc)
57
+ with torch.no_grad():
58
+ source = torch.from_numpy(x).float().cuda()
59
+ if self.task.cfg.normalize:
60
+ assert source.dim() == 1, source.dim()
61
+ with torch.no_grad():
62
+ source = F.layer_norm(source, source.shape)
63
+ source = source.view(1, -1)
64
+
65
+ m_res = self.model(source=source, mask=False, features_only=True, layer=self.layer)
66
+ return m_res["x"].squeeze(0).cpu()
67
+
68
+
69
+ def get_iterator(args):
70
+ with open(osp.join(args.data, args.split) + ".tsv", "r") as fp:
71
+ lines = fp.read().split("\n")
72
+ root = lines.pop(0).strip()
73
+ files = [osp.join(root, line.split("\t")[0]) for line in lines if len(line) > 0]
74
+
75
+ num = len(files)
76
+ reader = Wav2VecFeatureReader(args.checkpoint, args.layer)
77
+
78
+ def iterate():
79
+ for fname in files:
80
+ w2v_feats = reader.get_feats(fname)
81
+ yield w2v_feats
82
+
83
+ return iterate, num
84
+
85
+
86
+ def main():
87
+ parser = get_parser()
88
+ args = parser.parse_args()
89
+
90
+ os.makedirs(args.save_dir, exist_ok=True)
91
+
92
+ def create_files(dest):
93
+ copyfile(osp.join(args.data, args.split) + ".tsv", dest + ".tsv")
94
+ if osp.exists(osp.join(args.data, args.split) + ".wrd"):
95
+ copyfile(osp.join(args.data, args.split) + ".wrd", dest + ".wrd")
96
+ if osp.exists(osp.join(args.data, args.split) + ".phn"):
97
+ copyfile(osp.join(args.data, args.split) + ".phn", dest + ".phn")
98
+
99
+ if osp.exists(dest + ".npy"):
100
+ os.remove(dest + ".npy")
101
+ npaa = NpyAppendArray(dest + ".npy")
102
+ return npaa
103
+
104
+ save_path = osp.join(args.save_dir, args.split)
105
+ npaa = create_files(save_path)
106
+
107
+ generator, num = get_iterator(args)
108
+ iterator = generator()
109
+
110
+ with open(save_path + ".lengths", "w") as l_f:
111
+ for w2v_feats in tqdm.tqdm(iterator, total=num):
112
+ print(len(w2v_feats), file=l_f)
113
+
114
+ if len(w2v_feats) > 0:
115
+ npaa.append(w2v_feats.numpy())
116
+
117
+
118
+ if __name__ == "__main__":
119
+ main()
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wer.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3 -u
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ """
8
+ Implement unsupervised metric for decoding hyperparameter selection:
9
+ $$ alpha * LM_PPL + ViterbitUER(%) * 100 $$
10
+ """
11
+ import argparse
12
+ import logging
13
+ import sys
14
+
15
+ import editdistance
16
+
17
+ logging.root.setLevel(logging.INFO)
18
+ logging.basicConfig(stream=sys.stdout, level=logging.INFO)
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ def get_parser():
23
+ parser = argparse.ArgumentParser()
24
+ parser.add_argument("-s", "--hypo", help="hypo transcription", required=True)
25
+ parser.add_argument(
26
+ "-r", "--reference", help="reference transcription", required=True
27
+ )
28
+ return parser
29
+
30
+
31
+ def compute_wer(ref_uid_to_tra, hyp_uid_to_tra, g2p):
32
+ d_cnt = 0
33
+ w_cnt = 0
34
+ w_cnt_h = 0
35
+ for uid in hyp_uid_to_tra:
36
+ ref = ref_uid_to_tra[uid].split()
37
+ if g2p is not None:
38
+ hyp = g2p(hyp_uid_to_tra[uid])
39
+ hyp = [p for p in hyp if p != "'" and p != " "]
40
+ hyp = [p[:-1] if p[-1].isnumeric() else p for p in hyp]
41
+ else:
42
+ hyp = hyp_uid_to_tra[uid].split()
43
+ d_cnt += editdistance.eval(ref, hyp)
44
+ w_cnt += len(ref)
45
+ w_cnt_h += len(hyp)
46
+ wer = float(d_cnt) / w_cnt
47
+ logger.debug(
48
+ (
49
+ f"wer = {wer * 100:.2f}%; num. of ref words = {w_cnt}; "
50
+ f"num. of hyp words = {w_cnt_h}; num. of sentences = {len(ref_uid_to_tra)}"
51
+ )
52
+ )
53
+ return wer
54
+
55
+
56
+ def main():
57
+ args = get_parser().parse_args()
58
+
59
+ errs = 0
60
+ count = 0
61
+ with open(args.hypo, "r") as hf, open(args.reference, "r") as rf:
62
+ for h, r in zip(hf, rf):
63
+ h = h.rstrip().split()
64
+ r = r.rstrip().split()
65
+ errs += editdistance.eval(r, h)
66
+ count += len(r)
67
+
68
+ logger.info(f"UER: {errs / count * 100:.2f}%")
69
+
70
+
71
+ if __name__ == "__main__":
72
+ main()
73
+
74
+
75
+ def load_tra(tra_path):
76
+ with open(tra_path, "r") as f:
77
+ uid_to_tra = {}
78
+ for line in f:
79
+ uid, tra = line.split(None, 1)
80
+ uid_to_tra[uid] = tra
81
+ logger.debug(f"loaded {len(uid_to_tra)} utterances from {tra_path}")
82
+ return uid_to_tra
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/scripts/wrd_to_ltr.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3 -u
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ #
4
+ # This source code is licensed under the MIT license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ import sys
8
+
9
+
10
+ def main():
11
+ for line in sys.stdin:
12
+ print(" ".join(list(line.strip().replace(" ", "|"))) + " |")
13
+
14
+
15
+ if __name__ == "__main__":
16
+ main()
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/tasks/__init__.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from .unpaired_audio_text import UnpairedAudioText
7
+
8
+
9
+ __all__ = [
10
+ "UnpairedAudioText",
11
+ ]
omni_speech/infer/fairseq/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py ADDED
@@ -0,0 +1,452 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2017-present, Facebook, Inc.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the license found in the LICENSE file in
5
+ # the root directory of this source tree. An additional grant of patent rights
6
+ # can be found in the PATENTS file in the same directory.
7
+
8
+ from dataclasses import dataclass, field
9
+ import logging
10
+ import math
11
+ import os
12
+ from typing import Optional
13
+ import torch
14
+
15
+ from fairseq.logging import metrics
16
+ from fairseq.tasks import FairseqTask, register_task
17
+ from ..data import ExtractedFeaturesDataset, RandomInputDataset
18
+
19
+ from fairseq.data import (
20
+ Dictionary,
21
+ data_utils,
22
+ StripTokenDataset,
23
+ )
24
+ from fairseq.dataclass import FairseqDataclass
25
+ from fairseq.distributed.utils import get_data_parallel_world_size
26
+ from omegaconf import MISSING
27
+
28
+ from examples.speech_recognition.kaldi.kaldi_decoder import (
29
+ KaldiDecoder,
30
+ KaldiDecoderConfig,
31
+ )
32
+
33
+
34
+ logger = logging.getLogger(__name__)
35
+
36
+
37
+ @dataclass
38
+ class DecodingConfig(FairseqDataclass):
39
+ kenlm_path: Optional[str] = None
40
+ lm_weight: float = 0
41
+ blank_weight: float = 0
42
+
43
+
44
+ @dataclass
45
+ class UnpairedAudioTextConfig(FairseqDataclass):
46
+ data: str = field(
47
+ default=MISSING, metadata={"help": "path to data directory containing audio"}
48
+ )
49
+ text_data: str = field(
50
+ default=MISSING, metadata={"help": "path to data directory containing text"}
51
+ )
52
+ max_length: Optional[int] = None
53
+ labels: Optional[str] = field(
54
+ default=None,
55
+ metadata={"help": "extension of the label file to load, used for fine-tuning"},
56
+ )
57
+ aux_target_postfix: Optional[str] = field(
58
+ default=None,
59
+ metadata={"help": "auxaliry target filename extension"},
60
+ )
61
+ unfiltered: bool = field(
62
+ default=False, metadata={"help": "load data with _unfiltered suffix"}
63
+ )
64
+ ctc_eval: bool = field(
65
+ default=False, metadata={"help": "eval UER as if computed by CTC"}
66
+ )
67
+ sort_by_length: bool = field(
68
+ default=True, metadata={"help": "sort examples by length of audio timesteps"}
69
+ )
70
+ shuffle: bool = field(default=True, metadata={"help": "shuffle examples"})
71
+ append_eos: bool = field(default=False, metadata={"help": "append eos"})
72
+ uppercase: Optional[bool] = field(
73
+ default=False, metadata={"help": "uppercase for LM score computation"}
74
+ )
75
+ skipwords: Optional[str] = field(
76
+ default="",
77
+ metadata={
78
+ "help": "comma-separated words to be removed for LM score computation"
79
+ },
80
+ )
81
+ kenlm_path: Optional[str] = None
82
+ vocab_usage_power: float = 2
83
+
84
+ word_decoder_config: Optional[KaldiDecoderConfig] = None
85
+ word_kenlm_path: Optional[str] = None
86
+
87
+ decoding_config: DecodingConfig = DecodingConfig()
88
+
89
+
90
+ @register_task("unpaired_audio_text", dataclass=UnpairedAudioTextConfig)
91
+ class UnpairedAudioText(FairseqTask):
92
+ """ """
93
+
94
+ cfg: UnpairedAudioTextConfig
95
+
96
+ def __init__(
97
+ self,
98
+ cfg: UnpairedAudioTextConfig,
99
+ source_dictionary=None,
100
+ target_dictionary=None,
101
+ ):
102
+ super().__init__(cfg)
103
+
104
+ self._target_dictionary = target_dictionary
105
+ self._source_dictionary = source_dictionary
106
+ self.num_symbols = (
107
+ len([s for s in target_dictionary.symbols if not s.startswith("madeup")])
108
+ - target_dictionary.nspecial
109
+ )
110
+ self.sil_id = (
111
+ target_dictionary.index("<SIL>") if "<SIL>" in target_dictionary else -1
112
+ )
113
+ self.kenlm = None
114
+ if cfg.kenlm_path is not None:
115
+ import kenlm
116
+
117
+ self.kenlm = kenlm.Model(cfg.kenlm_path)
118
+
119
+ self.word_kenlm = None
120
+ if cfg.word_kenlm_path is not None:
121
+ import kenlm
122
+
123
+ self.word_kenlm = kenlm.Model(cfg.word_kenlm_path)
124
+
125
+ self.uppercase = cfg.uppercase
126
+ self.skipwords = set(cfg.skipwords.split(","))
127
+
128
+ def str_postprocess(s):
129
+ s = " ".join(w for w in s.split() if w not in self.skipwords)
130
+ s = s.upper() if self.uppercase else s
131
+ return s
132
+
133
+ self.str_postprocess = str_postprocess
134
+ self.compute_lm_score = lambda s: self.kenlm.score(self.str_postprocess(s))
135
+
136
+ self.compute_word_score = None
137
+ if cfg.word_decoder_config is not None:
138
+ self.kaldi_decoder = KaldiDecoder(cfg.word_decoder_config, beam=10)
139
+
140
+ def compute_word_score(logits, padding):
141
+ res = self.kaldi_decoder.decode(logits, padding)
142
+ for r in res:
143
+ r = r.result()
144
+ assert len(r) == 1
145
+ r = r[0]
146
+ yield r["score"], r["words"]
147
+
148
+ self.compute_word_score = compute_word_score
149
+
150
+ @classmethod
151
+ def setup_task(cls, cfg: UnpairedAudioTextConfig, **kwargs):
152
+ """Setup the task (e.g., load dictionaries).
153
+
154
+ Args:
155
+ cfg (AudioPretrainingConfig): configuration of this task
156
+ """
157
+
158
+ dict_path = os.path.join(cfg.text_data, "dict.txt")
159
+ if os.path.exists(dict_path):
160
+ target_dictionary = Dictionary.load(dict_path)
161
+ else:
162
+ dict_path = os.path.join(cfg.data, f"dict.{cfg.labels}.txt")
163
+ target_dictionary = Dictionary.load(dict_path)
164
+
165
+ return cls(cfg, target_dictionary=target_dictionary)
166
+
167
+ def optimizer_step(self, optimizer, model, update_num):
168
+ if hasattr(model, "get_groups_for_update"):
169
+ groups = model.get_groups_for_update(update_num)
170
+ optimizer.step(groups={groups})
171
+ else:
172
+ optimizer.step()
173
+
174
+ def valid_step(self, sample, model, criterion):
175
+ res = model(
176
+ **sample["net_input"],
177
+ dense_x_only=True,
178
+ )
179
+
180
+ dense_x = res["logits"]
181
+ padding_mask = res["padding_mask"]
182
+
183
+ word_scores = None
184
+ if self.compute_word_score is not None:
185
+ word_scores = self.compute_word_score(dense_x.cpu(), padding_mask.cpu())
186
+
187
+ z = dense_x.argmax(-1)
188
+ z[padding_mask] = self.target_dictionary.pad()
189
+
190
+ vocab_seen = torch.zeros(self.num_symbols, dtype=torch.bool)
191
+
192
+ import editdistance
193
+
194
+ c_err = 0
195
+ c_len = 0
196
+ pred_c_len = 0
197
+ lm_score_sum = 0
198
+ for i, (x, t, id) in enumerate(
199
+ zip(
200
+ z,
201
+ sample["target"] if "target" in sample else [None] * len(z),
202
+ sample["id"],
203
+ )
204
+ ):
205
+
206
+ if t is not None:
207
+ t = t[(t >= self.target_dictionary.nspecial)]
208
+ x = x[
209
+ (x >= self.target_dictionary.nspecial)
210
+ & (x < (self.num_symbols + self.target_dictionary.nspecial))
211
+ ]
212
+ if self.sil_id >= 0:
213
+ x = x[x != self.sil_id]
214
+
215
+ vocab_seen[x - self.target_dictionary.nspecial] = True
216
+
217
+ pred_units_arr = x
218
+ if self.cfg.ctc_eval:
219
+ pred_units_arr = pred_units_arr.unique_consecutive()
220
+ pred_units_arr = pred_units_arr[pred_units_arr != 0]
221
+
222
+ if id == 0:
223
+ if t is not None:
224
+ logger.info(f"REF: {self.target_dictionary.string(t)}")
225
+ logger.info(f"HYP: {self.target_dictionary.string(pred_units_arr)}")
226
+
227
+ if self.kenlm is not None:
228
+ if t is not None:
229
+ ref_lm_s = self.compute_lm_score(
230
+ self.target_dictionary.string(t)
231
+ )
232
+ logger.info(
233
+ f"LM [REF]: {ref_lm_s}, {math.pow(10, -ref_lm_s / (len(t) + 1))}"
234
+ )
235
+
236
+ hyp_lm_s = self.compute_lm_score(
237
+ self.target_dictionary.string(pred_units_arr)
238
+ )
239
+ logger.info(
240
+ f"LM [HYP]: {hyp_lm_s}, {math.pow(10, -hyp_lm_s / (len(pred_units_arr) + 1))}"
241
+ )
242
+
243
+ pred_units_arr = pred_units_arr.tolist()
244
+
245
+ pred_c_len += len(pred_units_arr)
246
+
247
+ if t is not None:
248
+ t = t.tolist()
249
+ c_err += editdistance.eval(pred_units_arr, t)
250
+ c_len += len(t)
251
+ else:
252
+ c_len = pred_c_len
253
+
254
+ if self.kenlm is not None:
255
+ pred_str = self.target_dictionary.string(pred_units_arr)
256
+ lm_score = self.compute_lm_score(pred_str)
257
+ lm_score_sum += lm_score
258
+
259
+ kaldi_score_sum = 0
260
+ word_lm_sum = 0
261
+ num_words = 0
262
+ if word_scores is not None:
263
+ for score, words in word_scores:
264
+ kaldi_score_sum += score
265
+ num_words += len(words)
266
+ if self.word_kenlm is not None:
267
+ word_lm_sum += self.kenlm.score(" ".join(words))
268
+
269
+ try:
270
+ world_size = get_data_parallel_world_size()
271
+ except:
272
+ world_size = 1
273
+
274
+ logging_output = {
275
+ "loss": c_err,
276
+ "_num_char_errors": c_err,
277
+ "_num_chars": c_len,
278
+ "_num_pred_chars": pred_c_len,
279
+ "ntokens": c_len,
280
+ "nsentences": z.size(0),
281
+ "sample_size": c_len,
282
+ "_world_size": world_size,
283
+ "_lm_score_sum": lm_score_sum,
284
+ "_kaldi_score_sum": kaldi_score_sum,
285
+ "_word_lm_sum": word_lm_sum,
286
+ "_num_words": num_words,
287
+ "_vocab_seen": vocab_seen,
288
+ }
289
+
290
+ return c_err, c_len, logging_output
291
+
292
+ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs):
293
+ data_path = self.cfg.data
294
+ task_cfg = task_cfg or self.cfg
295
+
296
+ has_unpaired_text = os.path.exists(
297
+ os.path.join(self.cfg.text_data, f"{split}.idx")
298
+ )
299
+
300
+ self.datasets[split] = ExtractedFeaturesDataset(
301
+ path=data_path,
302
+ split=split,
303
+ min_length=3,
304
+ max_length=task_cfg.max_length,
305
+ labels=None if has_unpaired_text else task_cfg.labels,
306
+ label_dict=self.target_dictionary,
307
+ shuffle=getattr(task_cfg, "shuffle", True),
308
+ sort_by_length=task_cfg.sort_by_length,
309
+ aux_target_postfix=task_cfg.aux_target_postfix,
310
+ )
311
+
312
+ logger.info(f"split {split} has unpaired text? {has_unpaired_text}")
313
+ if has_unpaired_text:
314
+ text_dataset = data_utils.load_indexed_dataset(
315
+ os.path.join(self.cfg.text_data, split), self.target_dictionary
316
+ )
317
+ text_dataset = StripTokenDataset(text_dataset, self.target_dictionary.eos())
318
+ self.datasets[split] = RandomInputDataset(
319
+ self.datasets[split],
320
+ text_dataset,
321
+ ["random_label"],
322
+ add_to_input=True,
323
+ pad_idx=self.target_dictionary.pad(),
324
+ )
325
+
326
+ @property
327
+ def source_dictionary(self):
328
+ return self._source_dictionary
329
+
330
+ @property
331
+ def target_dictionary(self):
332
+ """Return the :class:`~fairseq.data.Dictionary` for the language
333
+ model."""
334
+ return self._target_dictionary
335
+
336
+ def max_positions(self):
337
+ """Maximum input length supported by the encoder."""
338
+ return None
339
+
340
+ def reduce_metrics(self, logging_outputs, criterion):
341
+ super().reduce_metrics(logging_outputs, criterion)
342
+
343
+ zero = torch.scalar_tensor(0.0)
344
+ num_char_errors = sum(
345
+ log.get("_num_char_errors", zero) for log in logging_outputs
346
+ )
347
+ num_chars = sum(log.get("_num_chars", zero) for log in logging_outputs)
348
+ num_word_errors = sum(
349
+ log.get("_num_word_errors", zero) for log in logging_outputs
350
+ )
351
+ num_words = sum(log.get("_num_words", zero) for log in logging_outputs)
352
+ num_pred_chars = sum(
353
+ log.get("_num_pred_chars", zero) for log in logging_outputs
354
+ )
355
+
356
+ lm_score_sum = sum(log.get("_lm_score_sum", zero) for log in logging_outputs)
357
+ vocab_seen = (
358
+ sum(log.get("_vocab_seen", zero) for log in logging_outputs)
359
+ .bool()
360
+ .sum()
361
+ .item()
362
+ )
363
+ kaldi_score_sum = sum(
364
+ log.get("_kaldi_score_sum", zero) for log in logging_outputs
365
+ )
366
+ word_lm_sum = sum(log.get("_word_lm_sum", zero) for log in logging_outputs)
367
+
368
+ metrics.log_scalar_sum("_num_char_errors", num_char_errors)
369
+ metrics.log_scalar_sum("_num_chars", num_chars)
370
+ metrics.log_scalar_sum("_num_word_errors", num_word_errors)
371
+ metrics.log_scalar_sum("_num_words", num_words)
372
+
373
+ metrics.log_scalar_sum("lm_score_sum", lm_score_sum)
374
+ metrics.log_scalar_sum("num_pred_chars", num_pred_chars)
375
+
376
+ if self.cfg.word_kenlm_path is not None:
377
+ metrics.log_scalar_sum("kaldi_score_sum", kaldi_score_sum)
378
+ metrics.log_scalar_sum("word_lm_sum", word_lm_sum)
379
+
380
+ if num_chars > 0:
381
+ metrics.log_derived(
382
+ "uer",
383
+ lambda meters: meters["_num_char_errors"].sum
384
+ * 100.0
385
+ / meters["_num_chars"].sum
386
+ if meters["_num_chars"].sum > 0
387
+ else float("nan"),
388
+ )
389
+
390
+ if lm_score_sum < 0 and vocab_seen > 0:
391
+ metrics.log_scalar("vocab_seen_pct", vocab_seen / self.num_symbols)
392
+
393
+ metrics.log_derived(
394
+ "weighted_lm_ppl",
395
+ lambda meters: math.pow(
396
+ 10,
397
+ -meters["lm_score_sum"].sum
398
+ / (
399
+ meters["num_pred_chars"].sum + meters["nsentences"].sum
400
+ ), # account for </s>
401
+ )
402
+ / meters["vocab_seen_pct"].avg ** self.cfg.vocab_usage_power,
403
+ )
404
+
405
+ metrics.log_derived(
406
+ "lm_ppl",
407
+ lambda meters: math.pow(
408
+ 10,
409
+ -meters["lm_score_sum"].sum
410
+ / (
411
+ meters["num_pred_chars"].sum + meters["nsentences"].sum
412
+ ), # account for </s>
413
+ ),
414
+ )
415
+ else:
416
+ metrics.log_derived("weighted_lm_ppl", lambda meters: float("inf"))
417
+
418
+ if num_words > 0:
419
+ if word_lm_sum != 0:
420
+ metrics.log_derived(
421
+ "word_lm_ppl",
422
+ lambda meters: math.pow(
423
+ 10,
424
+ -meters["word_lm_sum"].sum
425
+ / (
426
+ meters["_num_words"].sum + meters["nsentences"].sum
427
+ ), # account for </s>
428
+ ),
429
+ )
430
+ metrics.log_derived(
431
+ "weighted_word_lm_ppl",
432
+ lambda meters: math.pow(
433
+ 10,
434
+ -meters["word_lm_sum"].sum
435
+ / (
436
+ meters["_num_words"].sum + meters["nsentences"].sum
437
+ ), # account for </s>
438
+ )
439
+ / meters["vocab_seen_pct"].avg ** self.cfg.vocab_usage_power,
440
+ )
441
+
442
+ if self.cfg.word_kenlm_path is not None:
443
+ metrics.log_derived(
444
+ "kaldi_score",
445
+ lambda meters: meters["kaldi_score_sum"].sum
446
+ / meters["nsentences"].sum,
447
+ )
448
+
449
+ def build_model(self, cfg: FairseqDataclass, from_checkpoint=False):
450
+ model = super().build_model(cfg)
451
+
452
+ return model
omni_speech/infer/fairseq/examples/wav2vec/xlsr/README.md ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # XLS-R
2
+
3
+ XLS-R is a set of large-scale models for self-supervised cross-lingual speech representation learning based on wav2vec 2.0. It was pretrained on 128 languages and approximately 436K hours of unlabeled speech data. With finetuning, these models achieve state of the art performance in speech translation, speech recognition and language identification. We evaluate the model across multiple benchmarks such as CoVoST-2 for speech translation, BABEL / MLS / CommonVoice / VoxPopuli for automatic speech recognition, and VoxLingua107 for language identification as we llas VoxCeleb1 for speaker identification. More details about this work can be found in our [paper](https://arxiv.org/pdf/2111.09296.pdf) and download links can be found below.
4
+
5
+ Model | Link
6
+ |------|------
7
+ XLS-R 300M | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr2_300m.pt)
8
+ XLS-R 1B | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr2_960m_1000k.pt)
9
+ XLS-R 2B | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr2_2B_1000k.pt)
10
+
11
+ You can also download these models [here](https://huggingface.co/models?other=xls_r) and read more about it in the [blogpost](https://huggingface.co/blog/fine-tune-xlsr-wav2vec2) from Hugging Face.
12
+
13
+ ## Speech Translation Finetuned Models
14
+
15
+ We multilingually finetune XLS-R models on [CoVoST 2](https://github.com/facebookresearch/covost), which has 21
16
+ into-English and 15 out-of-English directions.
17
+
18
+ Model | Directions | Link
19
+ |------|------|------
20
+ XLS-R 300M | 21 langs &#8594; En | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_300m_21_en.pt)
21
+ XLS-R 300M | En &#8594; 15 langs | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_300m_en_15.pt)
22
+ XLS-R 1B | 21 langs &#8594; En | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_1b_21_en.pt)
23
+ XLS-R 1B | En &#8594; 15 langs | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_1b_en_15.pt)
24
+ XLS-R 2B | 21 langs &#8594; En | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_2b_21_en.pt)
25
+ XLS-R 2B | En &#8594; 15 langs | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_2b_en_15.pt)
26
+ XLS-R 2B | 21 langs &#8594; En + En &#8594; 15 langs | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_2b_22_16.pt)
27
+
28
+ ## ASR Finetuning
29
+
30
+ You can refer the original wav2vec documentation on detailed instructions about how to finetune a pretrained model with CTC [here](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec#fine-tune-a-pre-trained-model-with-ctc). Below is an example command and you can find the values for different hyperparameters to reproduce the results in our paper.
31
+
32
+ ```shell script
33
+ $ fairseq-hydra-train \
34
+ distributed_training.distributed_port=$PORT \
35
+ task.data=/path/to/data \
36
+ model.w2v_path=/path/to/model.pt \
37
+ --config-dir /path/to/fairseq-py/examples/wav2vec/xlsr/config \
38
+ --config-name finetune
39
+ ```
40
+
41
+ For finetuning the 300M as well as 1B model, we use the same hyperparameter setting defined in `finetune.yaml`. We vary `optimization.max_update` as described in the below table and the `optimization.lr` is picked from the interval [2e-5, 3e-4] based on dev word error rate.
42
+
43
+ Benchmark | Total Number of Updates
44
+ |------|------
45
+ Babel | 26000
46
+ Common Voice | 13000
47
+ VoxPopuli | 50000
48
+ MLS 10h | 20000
49
+
50
+ For finetuning the 2B model, we make some additional changes for `finetune.yaml` . We use the fully_sharded `distributed_training.ddp_backend` provided by the [fairscale](https://github.com/facebookresearch/fairscale) library and and set `model.activation_checkpoint` to true. We also increase `dataset.max_tokens` to 2560000 and use a total effective batch size of 2560000*24. We sweep for the best `optimization.lr` within the interval [3e−6,3e−5] using dev error rate. For common voice dataset, we pick the `model.mask_prob` for different languages among {0.30, 0.40} based on best dev error rate.
51
+
52
+ ## LID Inference
53
+
54
+ Model | Link
55
+ |------|------
56
+ XLS-R 300M + ft Voxlingua107 | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr_300m_voxlingua107_ft.pt)
57
+
58
+ How to run inference & calculate accuracy (step-by-step):
59
+ 1. Download the Voxlingua107 checkpoint from the table above.
60
+ 1. Use this python script to extract logit/embedding from the XLSR model: https://github.com/fairinternal/fairseq-py/blob/xlsr2/examples/wav2vec/gen_audio_embedding.py
61
+ ```shell command
62
+ CUDA_VISIBLE_DEVICES=0 PYTHONPATH=. python3 examples/wav2vec/gen_audio_embedding.py \
63
+ /fsx/data/VoxLingua107/manifest --path "/path/to/checkpoint.pt" \
64
+ --task audio_classification --batch-size 90 --gen-subset test \
65
+ --infer-manifest /fsx/data/VoxLingua107/manifest/test.tsv \
66
+ --infer-xtimes 10 --infer-max-sample-size 160000 --output-path /tmp/tmp_voxling_infer.npz
67
+ ```
68
+
69
+ 2. Calculate the overall accuracy, 0-5 seconds and 5-20 seconds:
70
+ ```shell command
71
+ PYTHONPATH='.' python examples/wav2vec/eval_speaker_clf_task.py \
72
+ --task cls --merge mean_logit --data /tmp/tmp_voxling_infer.npz
73
+
74
+ Output:
75
+ | run classification evaluation
76
+ | acc = 94.34% -- err = 5.66% -- correct=1518 total=1609
77
+ | acc 0to5 = 90.91% -- err = 9.09% -- c_5=230.0 t_5=253
78
+ | acc 5to20 = 94.99% -- err = 5.01% -- c_20=1288.0 t_20=1356
79
+ ```
80
+
81
+ ## Citation
82
+
83
+ Please cite as:
84
+
85
+ ``` bibtex
86
+ @article{babu2021xlsr,
87
+ title={XLS-R: Self-supervised Cross-lingual Speech Representation Learning at Scale},
88
+ author={Arun Babu and Changhan Wang and Andros Tjandra and Kushal Lakhotia and Qiantong Xu and Naman Goyal and Kritika Singh and Patrick von Platen and Yatharth Saraf and Juan Pino and Alexei Baevski and Alexis Conneau and Michael Auli},
89
+ year={2021},
90
+ volume={abs/2111.09296},
91
+ journal={arXiv},
92
+ }
93
+ ```
94
+
95
+
omni_speech/infer/fairseq/examples/wav2vec/xlsr/config/finetune.yaml ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package _group_
2
+
3
+ common:
4
+ fp16: true
5
+ log_format: json
6
+ log_interval: 200
7
+ tensorboard_logdir: tb
8
+
9
+ checkpoint:
10
+ save_interval: 1000
11
+ save_interval_updates: 1000
12
+ keep_interval_updates: 1
13
+ no_epoch_checkpoints: true
14
+ best_checkpoint_metric: wer
15
+
16
+ task:
17
+ _name: audio_finetuning
18
+ data: ???
19
+ normalize: true
20
+ labels: ltr
21
+
22
+ dataset:
23
+ num_workers: 6
24
+ max_tokens: 1280000
25
+ skip_invalid_size_inputs_valid_test: true
26
+ validate_after_updates: 10000
27
+ validate_interval_updates: 1000
28
+ valid_subset: valid
29
+
30
+ distributed_training:
31
+ ddp_backend: legacy_ddp
32
+ distributed_world_size: 4
33
+
34
+ criterion:
35
+ _name: ctc
36
+ zero_infinity: true
37
+
38
+ optimization:
39
+ max_update: ???
40
+ lr: [0.0003]
41
+ sentence_avg: true
42
+ update_freq: [5]
43
+
44
+ optimizer:
45
+ _name: adam
46
+ adam_betas: (0.9,0.98)
47
+ adam_eps: 1e-08
48
+
49
+ lr_scheduler:
50
+ _name: tri_stage
51
+ phase_ratio: [0.1, 0.4, 0.5]
52
+ final_lr_scale: 0.05
53
+
54
+ model:
55
+ _name: wav2vec_ctc
56
+ w2v_path: ???
57
+ apply_mask: true
58
+ mask_prob: 0.75
59
+ mask_channel_prob: 0.25
60
+ mask_channel_length: 64
61
+ layerdrop: 0.1
62
+ activation_dropout: 0.1
63
+ feature_grad_mult: 0.0
64
+ freeze_finetune_updates: 10000
65
+
66
+ checkpoint_activations: false
omni_speech/infer/fairseq/examples/wav2vec/xlsr/scripts/eval_speaker_clf_task.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Usage:
3
+ This scripts it to evaluate the classification accuracy/error rate from the embedding extracted
4
+ by gen_audio_embedding.py
5
+ Example (LID classification)
6
+
7
+ PYTHONPATH='.' python examples/wav2vec/eval_speaker_clf_task.py \
8
+ --data /fsx/androstj/exps/lid_voxlingua/infer/atj_xlsr2_100pct_300M_mean_fast_upd_100k_new.npz \
9
+ --task cls --merge mean_logit
10
+ """
11
+ import numpy as np
12
+ import sklearn
13
+ from sklearn.metrics.pairwise import cosine_similarity
14
+ from sklearn.preprocessing import StandardScaler
15
+ from tqdm import tqdm
16
+ import ipdb
17
+ import logging
18
+ import argparse
19
+ from scipy.special import softmax
20
+
21
+ log=logging.getLogger(__name__)
22
+ log.setLevel(logging.INFO)
23
+
24
+ def calculate_eer(y_label, y_score):
25
+ # y denotes groundtruth scores,
26
+ # y_score denotes the prediction scores.
27
+ from scipy.optimize import brentq
28
+ from sklearn.metrics import roc_curve
29
+ from scipy.interpolate import interp1d
30
+
31
+ fpr, tpr, thresholds = roc_curve(y_label, y_score, pos_label=1)
32
+ eer = brentq(lambda x : 1. - x - interp1d(fpr, tpr)(x), 0., 1.)
33
+ optimal_threshold = interp1d(fpr, thresholds)(eer)
34
+ return eer, optimal_threshold
35
+
36
+ def calculate_minDCF(y_label, y_score, p_target=0.01, c_miss=1, c_fa=1):
37
+ # https://github.com/kaldi-asr/kaldi/blob/master/egs/sre08/v1/sid/compute_min_dcf.py
38
+ from sklearn.metrics import det_curve
39
+ fpr, fnr, thresholds = det_curve(y_label, y_score, pos_label=1)
40
+ min_c_det = float("inf")
41
+ min_c_det_threshold = thresholds[0]
42
+ for i in range(0, len(fpr)):
43
+ # See Equation (2). it is a weighted sum of false negative
44
+ # and false positive errors.
45
+ c_det = c_miss * fnr[i] * p_target + c_fa * fpr[i] * (1 - p_target)
46
+ if c_det < min_c_det:
47
+ min_c_det = c_det
48
+ min_c_det_threshold = thresholds[i]
49
+ # See Equations (3) and (4). Now we normalize the cost.
50
+ c_def = min(c_miss * p_target, c_fa * (1 - p_target))
51
+ min_dcf = min_c_det / c_def
52
+ return min_dcf, min_c_det_threshold
53
+
54
+
55
+ if __name__ == '__main__':
56
+ parser = argparse.ArgumentParser()
57
+ parser.add_argument('--data', help='npz contains name & latent file')
58
+ parser.add_argument('--task', choices=['cls', 'veri', 'cls_voxlingua'])
59
+ parser.add_argument('--merge', choices=['mean_logit', 'first_logit', 'mean_latent_sim', 'first_latent_sim', 'mean_logit_sim', 'first_logit_sim'])
60
+ parser.add_argument('--veri-pair', help='verification file contains 1/0 utt_x utt_y')
61
+ parser.add_argument('--scaler', type=str, choices=['mean_var'])
62
+ parser.add_argument('--compress-method', choices=['pca'])
63
+ parser.add_argument('--compress-dim', type=int)
64
+ args = parser.parse_args()
65
+
66
+ if args.task in ['cls', 'cls_voxlingua']:
67
+ print('| run classification evaluation')
68
+ data = np.load(args.data)
69
+ data_logit = data['logit']
70
+ data_target = data['target']
71
+ data_src_len = data['src_len']
72
+ assert data_logit.shape[0] == data_target.shape[0]
73
+ B = data_logit.shape[0]
74
+ correct = 0
75
+ total = 0
76
+ data_prob = softmax(data_logit, axis=2)
77
+ correct_vs_len = np.empty((B, 2))
78
+ for ii in range(B):
79
+ _target = data_target[ii]
80
+ if args.merge == 'mean_logit':
81
+ _prob = np.mean(data_prob[ii], axis=0)
82
+ top_1 = np.argmax(_prob)
83
+ elif args.merge == 'first_logit':
84
+ _prob = data_prob[ii][0]
85
+ top_1 = np.argmax(_prob)
86
+ else :
87
+ raise ValueError()
88
+ is_top_1 = (1 if top_1 == _target else 0)
89
+ correct += is_top_1
90
+ total += 1
91
+ _src_len = data_src_len[ii] / 16000
92
+ correct_vs_len[ii] = [is_top_1, _src_len]
93
+
94
+ acc = correct / total * 100
95
+ t_5 = correct_vs_len[:, 1] <= 5
96
+ t_20 = correct_vs_len[:, 1] > 5
97
+ c_5 = correct_vs_len[t_5, 0].sum()
98
+ c_20 = correct_vs_len[t_20, 0].sum()
99
+ t_5 = t_5.sum()
100
+ t_20 = t_20.sum()
101
+ acc_5 = c_5 / t_5 * 100
102
+ acc_20 = c_20 / t_20 * 100
103
+ print(f'| acc = {acc:.2f}% -- err = {100-acc:.2f}% -- {correct=} {total=}')
104
+ print(f'| acc 0to5 = {acc_5:.2f}% -- err = {100-acc_5:.2f}% -- {c_5=} {t_5=}')
105
+ print(f'| acc 5to20 = {acc_20:.2f}% -- err = {100-acc_20:.2f}% -- {c_20=} {t_20=}')
106
+
107
+
108
+
109
+ if args.task == 'veri':
110
+ print('| run verification evaluation')
111
+ veri_pairs = []
112
+ with open(args.veri_pair) as ff:
113
+ for fi in ff:
114
+ a,b,c = fi.split()
115
+ a = int(a)
116
+ veri_pairs.append([a,b,c])
117
+
118
+ data = np.load(args.data)
119
+ if 'logit' in args.merge:
120
+ data_latent = data['logit']
121
+ elif 'latent' in args.merge:
122
+ data_latent = data['latent']
123
+ else :
124
+ raise ValueError()
125
+
126
+ data_name = data['name']
127
+ assert len(data_name) == len(data_latent)
128
+ map_name_latent = {}
129
+
130
+ from sklearn.pipeline import make_pipeline
131
+ pipe = []
132
+ if args.scaler == 'mean_var':
133
+ print(f'| apply StandardScaler')
134
+ pipe.append(StandardScaler())
135
+
136
+ if args.compress_method == 'pca':
137
+ n_comp = args.compress_dim
138
+ print(f'| apply PCA with {n_comp=}')
139
+ from sklearn.decomposition import PCA
140
+ pipe.append(PCA(n_components=n_comp))
141
+ if len(pipe) > 0 :
142
+ pipe = make_pipeline(*pipe)
143
+ data_latent_2d = data_latent.reshape(-1, data_latent.shape[-1])
144
+ pipe.fit(data_latent_2d)
145
+ data_latent_2d = pipe.transform(data_latent_2d)
146
+ data_latent = data_latent_2d.reshape(data_latent.shape[0], data_latent.shape[1], -1)
147
+
148
+ for ii in range(len(data_name)):
149
+ map_name_latent[data_name[ii]] = data_latent[ii]
150
+ labels = []
151
+ scores = []
152
+ for lbl, pair_a, pair_b in tqdm(veri_pairs):
153
+ labels.append(lbl)
154
+ pair_a = map_name_latent[pair_a]
155
+ pair_b = map_name_latent[pair_b]
156
+ assert pair_a.ndim == pair_b.ndim == 2
157
+ score = cosine_similarity(pair_a, pair_b)
158
+ if args.merge.startswith('mean'):
159
+ score = np.mean(score)
160
+ elif args.merge.startswith('first'):
161
+ score = score[0, 0]
162
+ else :
163
+ raise ValueError()
164
+ scores.append(score)
165
+ labels = np.array(labels)
166
+ scores = np.array(scores)
167
+ eer, eer_threshold = calculate_eer(labels, scores)
168
+ minDCF, minDCF_threshold = calculate_minDCF(labels, scores)
169
+ print('='*40)
170
+ print(f'| EER = {eer*100:.2f}%\tthreshold = {eer_threshold:.2f}')
171
+ print(f'| minDCF = {minDCF:.2f}\tthreshold = {minDCF_threshold:.2f}')
172
+
173
+
omni_speech/infer/fairseq/examples/wav2vec/xlsr/scripts/gen_audio_embedding.py ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Usage:
3
+ This script is used to extract the embedding / logit for speech classification task.
4
+ 1. Set fdir into your model checkpoint directory
5
+ 2. Run the following command (preferrably on GPU machine to speed up the inference process)
6
+
7
+ CUDA_VISIBLE_DEVICES=0 python3 examples/wav2vec/gen_audio_embedding.py /fsx/data/VoxLingua107/manifest --path ${fdir} \
8
+ --task audio_classification --batch-size 90 --gen-subset test \
9
+ --infer-manifest /fsx/data/VoxLingua107/manifest/test.tsv \
10
+ --infer-xtimes 10 --infer-max-sample-size 160000 --output-path $odir
11
+
12
+ Example:
13
+ Case: LID logit extraction
14
+ fdir='/fsx/androstj/exps/voxlingua_lid_train_all/ckpt_100pct_300m_voxling-act_linear-pool_mean_fast-lr_1e-4-phase_0.1_0.4_0.5-maxupd_100000-ufreq_1-mprob_0.5-fz_0-cr_softmax/0/checkpoints/checkpoint_best.pt'
15
+ python3 examples/wav2vec/gen_audio_embedding.py /fsx/data/VoxLingua107/manifest --path ${fdir} \
16
+ --task audio_classification --batch-size 90 --gen-subset test \
17
+ --infer-manifest /fsx/data/VoxLingua107/manifest/test.tsv \
18
+ --infer-xtimes 10 --infer-max-sample-size 160000 --output-path $odir
19
+
20
+ """
21
+ import torch
22
+ from fairseq import checkpoint_utils, distributed_utils, options, utils
23
+ from fairseq.dataclass.utils import convert_namespace_to_omegaconf
24
+ from fairseq.logging import metrics, progress_bar
25
+ from fairseq import checkpoint_utils, data, options, tasks
26
+ from fairseq.data import FileAudioDataset, AddTargetDataset, Dictionary
27
+ from fairseq.tasks.audio_classification import LabelEncoder
28
+ import ipdb
29
+ import copy
30
+ import sys
31
+ from tqdm import tqdm
32
+ import tempfile
33
+ import numpy as np
34
+ import sklearn
35
+
36
+ def subset_manifest(infer_manifest, veri_pair):
37
+ with open(infer_manifest) as ff, open(veri_pair) as gg, \
38
+ tempfile.NamedTemporaryFile('w', delete=False) as ww:
39
+ fnames = ff.read().strip().split("\n")
40
+ basedir = fnames[0]
41
+ needed_fname = []
42
+ for gi in gg.read().strip().split('\n'):
43
+ _, x1, x2 = gi.split()
44
+ needed_fname.append(x1)
45
+ needed_fname.append(x2)
46
+ needed_fname = set(needed_fname)
47
+
48
+ ww.write(basedir+'\n')
49
+ for ii in range(1, len(fnames)):
50
+ x1,x2 = fnames[ii].split()
51
+ if x1 in needed_fname:
52
+ ww.write(fnames[ii]+'\n')
53
+ print(f'| subset manifest for verification: {ww.name}')
54
+ return ww.name
55
+
56
+ def wrap_target_dataset(infer_manifest, dataset, task):
57
+ label_path = infer_manifest.replace(".tsv", ".label")
58
+ with open(label_path, "r") as f:
59
+ labels = f.read().strip().split("\n")
60
+ assert len(labels) == len(dataset)
61
+ process_label = LabelEncoder(task.target_dictionary)
62
+ dataset = AddTargetDataset(dataset, labels,
63
+ pad=task.target_dictionary.pad(),
64
+ eos=task.target_dictionary.eos(),
65
+ batch_targets=True,
66
+ process_label=process_label,
67
+ add_to_input=False)
68
+ return dataset
69
+
70
+ def resample_data(source, padding_mask, n_sample, max_sample_len):
71
+ # source: BxT
72
+ # padding_mask: BxT
73
+ B = source.shape[0]
74
+ T = source.shape[1]
75
+ sources = []
76
+ padding_masks = []
77
+ seq_len = (~padding_mask).sum(1)
78
+ for jj in range(n_sample):
79
+ new_source = source.new_zeros(B, max_sample_len)
80
+ new_padding_mask = padding_mask.new_zeros(B, max_sample_len)
81
+ for ii in range(B):
82
+ if seq_len[ii] > max_sample_len:
83
+ start = np.random.randint(0, seq_len[ii]-max_sample_len+1)
84
+ end = start + max_sample_len
85
+ else :
86
+ start = 0
87
+ end = seq_len[ii]
88
+ new_source[ii, 0:end-start] = source[ii, start:end]
89
+ new_padding_mask[ii, end-start+1:] = True
90
+ sources.append(new_source)
91
+ padding_masks.append(new_padding_mask)
92
+ return sources, padding_masks
93
+
94
+ def resample_sample(sample, n_sample, max_sample_len):
95
+ new_sources, new_padding_masks = resample_data(sample['net_input']['source'], sample['net_input']['padding_mask'], n_sample, max_sample_len)
96
+ new_samples = []
97
+ for ii in range(n_sample):
98
+ new_sample = copy.deepcopy(sample)
99
+ new_sample['net_input']['source'] = new_sources[ii]
100
+ new_sample['net_input']['padding_mask'] = new_padding_masks[ii]
101
+ new_samples.append(new_sample)
102
+ return new_samples
103
+
104
+ if __name__ == '__main__':
105
+ np.random.seed(123)
106
+ # Parse command-line arguments for generation
107
+ parser = options.get_generation_parser(default_task='audio_classification')
108
+ # parser.add_argument('--infer-merge', type=str, default='mean')
109
+ parser.add_argument('--infer-xtimes', type=int, default=1)
110
+ parser.add_argument('--infer-max-sample-size', type=int, default=5*16000) # 5 secs
111
+ parser.add_argument('--infer-manifest', type=str)
112
+ parser.add_argument('--verification-pair', type=str, required=False,
113
+ help='''
114
+ a file that contains pairs of utts to evaluated if they are from same speaker or not
115
+ format: (following voxceleb)
116
+ 1/0 <wav_pair_a> <wav_pair_b>
117
+ ''')
118
+ parser.add_argument('--output-path', type=str)
119
+ # parser.add_argument('--infer-xtimes', type=int, default=1)
120
+
121
+ args = options.parse_args_and_arch(parser)
122
+ # Setup task
123
+ # task = tasks.setup_task(args)
124
+ use_cuda = not args.cpu
125
+
126
+ # Load model & task
127
+ print('| loading model from {}'.format(args.path))
128
+ arg_overrides = {
129
+ 'data': args.data,
130
+ # 'mask_prob': 0
131
+ #'max_sample_size': sys.maxsize,
132
+ #'min_sample_size': 0,
133
+ }
134
+ state = checkpoint_utils.load_checkpoint_to_cpu(args.path)
135
+ # move to AWS
136
+ state['cfg']['model']['w2v_path'] = state['cfg']['model']['w2v_path'].replace('/checkpoint/arbabu/XLSR2/model_versions/', '/fsx/data/model_versions/').replace('/checkpoint/kushall/final_model_checkpoints/wav2vec2/', '/fsx/data/wav2vec_ckpt/')
137
+ state['cfg']['task']['data'] = state['cfg']['task']['data'].replace('/checkpoint/kushall/data/', '/fsx/data/')
138
+
139
+ models, _model_args, task = checkpoint_utils.load_model_ensemble_and_task([args.path],
140
+ arg_overrides=arg_overrides,
141
+ task=None,
142
+ state=state)
143
+ model = models[0]
144
+ model.eval()
145
+ if use_cuda:
146
+ model.cuda()
147
+
148
+
149
+ # Load dataset
150
+ task.load_dataset(args.gen_subset)
151
+ dataset = task.dataset(args.gen_subset)
152
+ infer_manifest = args.infer_manifest
153
+ # only decode needed utts
154
+ # infer_manifest = subset_manifest(infer_manifest,
155
+ # args.verification_pair)
156
+ infer_dataset = FileAudioDataset(infer_manifest,
157
+ sample_rate=task.cfg.sample_rate,
158
+ max_sample_size=10**10, #task.cfg.max_sample_size,
159
+ min_sample_size=1, #task.cfg.min_sample_size,
160
+ pad=True,
161
+ normalize=task.cfg.normalize)
162
+ # add target (if needed)
163
+ infer_dataset = wrap_target_dataset(infer_manifest, infer_dataset, task)
164
+ itr = task.get_batch_iterator(
165
+ dataset=infer_dataset,
166
+ max_sentences=args.batch_size,
167
+ ).next_epoch_itr(shuffle=False)
168
+
169
+
170
+ # correct = 0
171
+ # total = 0
172
+ list_uttname = []
173
+ list_latent = []
174
+ list_logit = []
175
+ list_target = []
176
+ list_src_len = []
177
+ with torch.no_grad():
178
+ for _, sample in tqdm(enumerate(itr)):
179
+ # resample if needed
180
+ samples = resample_sample(sample, args.infer_xtimes, args.infer_max_sample_size)
181
+ list_uttname.extend(sample['name'])
182
+ list_target.extend(sample['target'][:, 0].cpu().numpy())
183
+ list_src_len.extend((~sample['net_input']['padding_mask']).sum(1).cpu().numpy())
184
+ latents = []
185
+ logits = []
186
+ for sample in samples:
187
+ sample = utils.move_to_cuda(sample) if use_cuda else sample
188
+ try:
189
+ latent = model.forward_latent(**sample['net_input'])
190
+ latents.append(latent.detach().cpu().numpy())
191
+ except:
192
+ latent = None
193
+ logit = model.forward(**sample['net_input'])
194
+ logits.append(logit.detach().cpu().numpy())
195
+
196
+ if len(latents) > 0:
197
+ latents = np.stack(latents, 1) # B,X,D
198
+ logits = np.stack(logits, 1) # B,X,Cls
199
+ list_latent.extend(latents)
200
+ list_logit.extend(logits)
201
+
202
+ # create big npz
203
+ list_uttname = np.array(list_uttname)
204
+ list_latent = np.array(list_latent)
205
+ list_target = np.array(list_target)
206
+ list_logit = np.array(list_logit)
207
+ list_src_len = np.array(list_src_len)
208
+ # save to npz
209
+ output_path = args.output_path
210
+ if (output_path is None):
211
+ output_path = tempfile.NamedTemporaryFile('wb', delete=False).name
212
+
213
+ with open(output_path, 'wb') as ww:
214
+ np.savez(ww, name=list_uttname,
215
+ latent=list_latent,
216
+ target=list_target,
217
+ logit=list_logit,
218
+ src_len=list_src_len)
219
+
220
+ print("="*10 + " REPORT " + "="*10)
221
+ print(f'| latent saved in {output_path}')
222
+ print(f'| {list_uttname.shape=}, {list_latent.shape=}, {list_target.shape=}, {list_logit.shape=}, {list_src_len.shape=}')
omni_speech/infer/fairseq/examples/wmt19/README.md ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # WMT 19
2
+
3
+ This page provides pointers to the models of Facebook-FAIR's WMT'19 news translation task submission [(Ng et al., 2019)](https://arxiv.org/abs/1907.06616).
4
+
5
+ ## Pre-trained models
6
+
7
+ Model | Description | Download
8
+ ---|---|---
9
+ `transformer.wmt19.en-de` | En->De Ensemble | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-de.joined-dict.ensemble.tar.gz)
10
+ `transformer.wmt19.de-en` | De->En Ensemble | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt19.de-en.joined-dict.ensemble.tar.gz)
11
+ `transformer.wmt19.en-ru` | En->Ru Ensemble | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-ru.ensemble.tar.gz)
12
+ `transformer.wmt19.ru-en` | Ru->En Ensemble | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt19.ru-en.ensemble.tar.gz)
13
+ `transformer_lm.wmt19.en` | En Language Model | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt19.en.tar.gz)
14
+ `transformer_lm.wmt19.de` | De Language Model | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt19.de.tar.gz)
15
+ `transformer_lm.wmt19.ru` | Ru Language Model | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt19.ru.tar.gz)
16
+
17
+ ## Pre-trained single models before finetuning
18
+
19
+ Model | Description | Download
20
+ ---|---|---
21
+ `transformer.wmt19.en-de` | En->De Single, no finetuning | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-de.ffn8192.tar.gz)
22
+ `transformer.wmt19.de-en` | De->En Single, no finetuning | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt19.de-en.ffn8192.tar.gz)
23
+ `transformer.wmt19.en-ru` | En->Ru Single, no finetuning | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-ru.ffn8192.tar.gz)
24
+ `transformer.wmt19.ru-en` | Ru->En Single, no finetuning | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt19.ru-en.ffn8192.tar.gz)
25
+
26
+ ## Example usage (torch.hub)
27
+
28
+ #### Requirements
29
+
30
+ We require a few additional Python dependencies for preprocessing:
31
+ ```bash
32
+ pip install fastBPE sacremoses
33
+ ```
34
+
35
+ #### Translation
36
+
37
+ ```python
38
+ import torch
39
+
40
+ # English to German translation
41
+ en2de = torch.hub.load('pytorch/fairseq', 'transformer.wmt19.en-de', checkpoint_file='model1.pt:model2.pt:model3.pt:model4.pt',
42
+ tokenizer='moses', bpe='fastbpe')
43
+ en2de.translate("Machine learning is great!") # 'Maschinelles Lernen ist großartig!'
44
+
45
+ # German to English translation
46
+ de2en = torch.hub.load('pytorch/fairseq', 'transformer.wmt19.de-en', checkpoint_file='model1.pt:model2.pt:model3.pt:model4.pt',
47
+ tokenizer='moses', bpe='fastbpe')
48
+ de2en.translate("Maschinelles Lernen ist großartig!") # 'Machine learning is great!'
49
+
50
+ # English to Russian translation
51
+ en2ru = torch.hub.load('pytorch/fairseq', 'transformer.wmt19.en-ru', checkpoint_file='model1.pt:model2.pt:model3.pt:model4.pt',
52
+ tokenizer='moses', bpe='fastbpe')
53
+ en2ru.translate("Machine learning is great!") # 'Машинное обучение - это здорово!'
54
+
55
+ # Russian to English translation
56
+ ru2en = torch.hub.load('pytorch/fairseq', 'transformer.wmt19.ru-en', checkpoint_file='model1.pt:model2.pt:model3.pt:model4.pt',
57
+ tokenizer='moses', bpe='fastbpe')
58
+ ru2en.translate("Машинное обучение - это здорово!") # 'Machine learning is great!'
59
+ ```
60
+
61
+ #### Language Modeling
62
+
63
+ ```python
64
+ # Sample from the English LM
65
+ en_lm = torch.hub.load('pytorch/fairseq', 'transformer_lm.wmt19.en', tokenizer='moses', bpe='fastbpe')
66
+ en_lm.sample("Machine learning is") # 'Machine learning is the future of computing, says Microsoft boss Satya Nadella ...'
67
+
68
+ # Sample from the German LM
69
+ de_lm = torch.hub.load('pytorch/fairseq', 'transformer_lm.wmt19.de', tokenizer='moses', bpe='fastbpe')
70
+ de_lm.sample("Maschinelles lernen ist") # 'Maschinelles lernen ist das A und O (neues-deutschland.de) Die Arbeitsbedingungen für Lehrerinnen und Lehrer sind seit Jahren verbesserungswürdig ...'
71
+
72
+ # Sample from the Russian LM
73
+ ru_lm = torch.hub.load('pytorch/fairseq', 'transformer_lm.wmt19.ru', tokenizer='moses', bpe='fastbpe')
74
+ ru_lm.sample("машинное обучение это") # 'машинное обучение это то, что мы называем "искусственным интеллектом".'
75
+ ```
76
+
77
+ ## Citation
78
+ ```bibtex
79
+ @inproceedings{ng2019facebook},
80
+ title = {Facebook FAIR's WMT19 News Translation Task Submission},
81
+ author = {Ng, Nathan and Yee, Kyra and Baevski, Alexei and Ott, Myle and Auli, Michael and Edunov, Sergey},
82
+ booktitle = {Proc. of WMT},
83
+ year = 2019,
84
+ }
85
+ ```
omni_speech/infer/fairseq/examples/wmt20/README.md ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # WMT 20
2
+
3
+ This page provides pointers to the models of Facebook-FAIR's WMT'20 news translation task submission [(Chen et al., 2020)](https://arxiv.org/abs/2011.08298).
4
+
5
+ ## Single best MT models (after finetuning on part of WMT20 news dev set)
6
+
7
+ Model | Description | Download
8
+ ---|---|---
9
+ `transformer.wmt20.ta-en` | Ta->En | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.ta-en.single.tar.gz)
10
+ `transformer.wmt20.en-ta` | En->Ta | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-ta.single.tar.gz)
11
+ `transformer.wmt20.iu-en.news` | Iu->En (News domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.news.single.tar.gz)
12
+ `transformer.wmt20.en-iu.news` | En->Iu (News domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.news.single.tar.gz)
13
+ `transformer.wmt20.iu-en.nh` | Iu->En (Nunavut Hansard domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.nh.single.tar.gz)
14
+ `transformer.wmt20.en-iu.nh` | En->Iu (Nunavut Hansard domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.nh.single.tar.gz)
15
+
16
+ ## Language models
17
+ Model | Description | Download
18
+ ---|---|---
19
+ `transformer_lm.wmt20.en` | En Language Model | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en.tar.gz)
20
+ `transformer_lm.wmt20.ta` | Ta Language Model | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.ta.tar.gz)
21
+ `transformer_lm.wmt20.iu.news` | Iu Language Model (News domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu.news.tar.gz)
22
+ `transformer_lm.wmt20.iu.nh` | Iu Language Model (Nunavut Hansard domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu.nh.tar.gz)
23
+
24
+ ## Example usage (torch.hub)
25
+
26
+ #### Translation
27
+
28
+ ```python
29
+ import torch
30
+
31
+ # English to Tamil translation
32
+ en2ta = torch.hub.load('pytorch/fairseq', 'transformer.wmt20.en-ta')
33
+ en2ta.translate("Machine learning is great!") # 'இயந்திரக் கற்றல் அருமை!'
34
+
35
+ # Tamil to English translation
36
+ ta2en = torch.hub.load('pytorch/fairseq', 'transformer.wmt20.ta-en')
37
+ ta2en.translate("இயந்திரக் கற்றல் அருமை!") # 'Machine learning is great!'
38
+
39
+ # English to Inuktitut translation
40
+ en2iu = torch.hub.load('pytorch/fairseq', 'transformer.wmt20.en-iu.news')
41
+ en2iu.translate("machine learning is great!") # 'ᖃᒧᑕᐅᔭᓄᑦ ᐃᓕᓐᓂᐊᕐᓂᖅ ᐱᐅᔪᒻᒪᕆᒃ!'
42
+
43
+ # Inuktitut to English translation
44
+ iu2en = torch.hub.load('pytorch/fairseq', 'transformer.wmt20.iu-en.news')
45
+ iu2en.translate("ᖃᒧᑕᐅᔭᓄᑦ ᐃᓕᓐᓂᐊᕐᓂᖅ ᐱᐅᔪᒻᒪᕆᒃ!") # 'Machine learning excellence!'
46
+ ```
47
+
48
+ #### Language Modeling
49
+
50
+ ```python
51
+ # Sample from the English LM
52
+ en_lm = torch.hub.load('pytorch/fairseq', 'transformer_lm.wmt20.en')
53
+ en_lm.sample("Machine learning is") # 'Machine learning is a type of artificial intelligence that uses machine learning to learn from data and make predictions.'
54
+
55
+ # Sample from the Tamil LM
56
+ ta_lm = torch.hub.load('pytorch/fairseq', 'transformer_lm.wmt20.ta')
57
+ ta_lm.sample("இயந்திரக் கற்றல் என்பது செயற்கை நுண்ணறிவின்") # 'இயந்திரக் கற்றல் என்பது செயற்கை நுண்ணறிவின் ஒரு பகுதியாகும்.'
58
+
59
+ # Sample from the Inuktitut LM
60
+ iu_lm = torch.hub.load('pytorch/fairseq', 'transformer_lm.wmt20.iu.news')
61
+ iu_lm.sample("ᖃᒧᑕᐅᔭᓄᑦ ᐃᓕᓐᓂᐊᕐᓂᖅ") # 'ᖃᒧᑕᐅᔭᓄᑦ ᐃᓕᓐᓂᐊᕐᓂᖅ, ᐊᒻᒪᓗ ᓯᓚᐅᑉ ᐊᓯᙳᖅᐸᓪᓕᐊᓂᖓᓄᑦ ᖃᓄᐃᓕᐅᕈᑎᒃᓴᑦ, ᐃᓚᖃᖅᖢᑎᒃ ᐅᑯᓂᖓ:'
62
+ ```
63
+
64
+ ## Citation
65
+ ```bibtex
66
+ @inproceedings{chen2020facebook
67
+ title={Facebook AI's WMT20 News Translation Task Submission},
68
+ author={Peng-Jen Chen and Ann Lee and Changhan Wang and Naman Goyal and Angela Fan and Mary Williamson and Jiatao Gu},
69
+ booktitle={Proc. of WMT},
70
+ year={2020},
71
+ }
72
+ ```
omni_speech/infer/fairseq/examples/wmt21/README.md ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # WMT 21
2
+
3
+ This page provides pointers to the models of Facebook AI's WMT'21 news translation task submission [(Tran et al., 2021)](https://arxiv.org/abs/2108.03265).
4
+
5
+ ## Single best dense models
6
+
7
+ Model | Description | Download
8
+ ---|---|---
9
+ `wmt21.dense-24-wide.X-En` | X-En | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt21.dense-24-wide.X-En.tar.gz)
10
+ `wmt21.dense-24-wide.En-X` | En-X | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt21.dense-24-wide.En-X.tar.gz)
11
+
12
+ ## Example usage
13
+
14
+ See eval.sh
15
+
16
+
17
+ ## Citation
18
+ ```bibtex
19
+ @inproceedings{tran2021facebook
20
+ title={Facebook AI’s WMT21 News Translation Task Submission},
21
+ author={Chau Tran and Shruti Bhosale and James Cross and Philipp Koehn and Sergey Edunov and Angela Fan},
22
+ booktitle={Proc. of WMT},
23
+ year={2021},
24
+ }
25
+ ```
omni_speech/infer/fairseq/examples/wmt21/eval.sh ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Copyright (c) Facebook, Inc. and its affiliates.
3
+ # All rights reserved.
4
+ #
5
+ # This source code is licensed under the license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+ SRC=en
8
+ TGT=is
9
+ MODEL_NAME=wmt21.dense-24-wide.En-X
10
+
11
+ PATH_TO_FAIRSEQ_PY=.
12
+ TMP_DIR=generation_tmp
13
+ mkdir -p $TMP_DIR
14
+
15
+ REPLACE_UNICODE_PUNCT=$PATH_TO_FAIRSEQ_PY/examples/wmt21/scripts/replace-unicode-punctuation.perl
16
+ NORM_PUNCT=$PATH_TO_FAIRSEQ_PY/examples/wmt21/scripts/normalize-punctuation.perl
17
+ if [ ! -d "${TMP_DIR}/${MODEL_NAME}" ]; then
18
+ wget https://dl.fbaipublicfiles.com/fairseq/models/${MODEL_NAME}.tar.gz -P $TMP_DIR/
19
+ tar -xvf $TMP_DIR/${MODEL_NAME}.tar.gz -C $TMP_DIR
20
+ fi
21
+ MODEL_DIR=$TMP_DIR/${MODEL_NAME}
22
+ if [ ! -d "${TMP_DIR}/wmt21-news-systems" ]; then
23
+ git clone https://github.com/wmt-conference/wmt21-news-systems $TMP_DIR/wmt21-news-systems
24
+ fi
25
+
26
+ DOMAIN_TAG="wmtdata newsdomain"
27
+ INPUT_FILE=$TMP_DIR/wmt21-news-systems/txt/sources/newstest2021.${SRC}-${TGT}.src.${SRC}
28
+ REF_FILE=$TMP_DIR/wmt21-news-systems/txt/references/newstest2021.${SRC}-${TGT}.ref.A.${TGT}
29
+
30
+ # Translate
31
+ cat ${INPUT_FILE} | sed "s/^/${DOMAIN_TAG} /" | $REPLACE_UNICODE_PUNCT | $NORM_PUNCT -l ${SRC} | python $PATH_TO_FAIRSEQ_PY/fairseq_cli/interactive.py $MODEL_DIR \
32
+ --path ${MODEL_DIR}/checkpoint.pt \
33
+ --task translation_multi_simple_epoch \
34
+ --langs "en,ha,is,ja,cs,ru,zh,de" \
35
+ --lang-pairs $SRC-$TGT \
36
+ --bpe "sentencepiece" \
37
+ --sentencepiece-model ${MODEL_DIR}/sentencepiece.model \
38
+ --buffer-size 1024 \
39
+ --batch-size 10 -s $SRC -t $TGT \
40
+ --decoder-langtok \
41
+ --encoder-langtok src \
42
+ --beam 5 \
43
+ --lenpen 1.0 \
44
+ --fp16 > $TMP_DIR/${SRC}-${TGT}.gen_log
45
+
46
+ cat $TMP_DIR/$SRC-$TGT.gen_log | grep -P "^D-" | cut -f3 > $TMP_DIR/$SRC-$TGT.hyp
47
+
48
+ # Calculate BLEU score
49
+ sacrebleu -l $SRC-$TGT $REF_FILE < $TMP_DIR/$SRC-$TGT.hyp
omni_speech/infer/fairseq/examples/wmt21/scripts/normalize-punctuation.perl ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env perl
2
+ #
3
+ # This file is part of moses. Its use is licensed under the GNU Lesser General
4
+ # Public License version 2.1 or, at your option, any later version.
5
+
6
+ use warnings;
7
+ use strict;
8
+
9
+ my $language = "en";
10
+ my $PENN = 0;
11
+
12
+ while (@ARGV) {
13
+ $_ = shift;
14
+ /^-b$/ && ($| = 1, next); # not buffered (flush each line)
15
+ /^-l$/ && ($language = shift, next);
16
+ /^[^\-]/ && ($language = $_, next);
17
+ /^-penn$/ && ($PENN = 1, next);
18
+ }
19
+
20
+ while(<STDIN>) {
21
+ s/\r//g;
22
+ # remove extra spaces
23
+ s/\(/ \(/g;
24
+ s/\)/\) /g; s/ +/ /g;
25
+ s/\) ([\.\!\:\?\;\,])/\)$1/g;
26
+ s/\( /\(/g;
27
+ s/ \)/\)/g;
28
+ s/(\d) \%/$1\%/g;
29
+ s/ :/:/g;
30
+ s/ ;/;/g;
31
+ # normalize unicode punctuation
32
+ if ($PENN == 0) {
33
+ s/\`/\'/g;
34
+ s/\'\'/ \" /g;
35
+ }
36
+
37
+ s/„/\"/g;
38
+ s/“/\"/g;
39
+ s/”/\"/g;
40
+ s/–/-/g;
41
+ s/—/ - /g; s/ +/ /g;
42
+ s/´/\'/g;
43
+ s/([a-z])‘([a-z])/$1\'$2/gi;
44
+ s/([a-z])’([a-z])/$1\'$2/gi;
45
+ s/‘/\'/g;
46
+ s/‚/\'/g;
47
+ s/’/\"/g;
48
+ s/''/\"/g;
49
+ s/´´/\"/g;
50
+ s/…/.../g;
51
+ # French quotes
52
+ s/ « / \"/g;
53
+ s/« /\"/g;
54
+ s/«/\"/g;
55
+ s/ » /\" /g;
56
+ s/ »/\"/g;
57
+ s/»/\"/g;
58
+ # handle pseudo-spaces
59
+ s/ \%/\%/g;
60
+ s/nº /nº /g;
61
+ s/ :/:/g;
62
+ s/ ºC/ ºC/g;
63
+ s/ cm/ cm/g;
64
+ s/ \?/\?/g;
65
+ s/ \!/\!/g;
66
+ s/ ;/;/g;
67
+ s/, /, /g; s/ +/ /g;
68
+
69
+ # English "quotation," followed by comma, style
70
+ if ($language eq "en") {
71
+ s/\"([,\.]+)/$1\"/g;
72
+ }
73
+ # Czech is confused
74
+ elsif ($language eq "cs" || $language eq "cz") {
75
+ }
76
+ # German/Spanish/French "quotation", followed by comma, style
77
+ else {
78
+ s/,\"/\",/g;
79
+ s/(\.+)\"(\s*[^<])/\"$1$2/g; # don't fix period at end of sentence
80
+ }
81
+
82
+
83
+ if ($language eq "de" || $language eq "es" || $language eq "cz" || $language eq "cs" || $language eq "fr") {
84
+ s/(\d) (\d)/$1,$2/g;
85
+ }
86
+ else {
87
+ s/(\d) (\d)/$1.$2/g;
88
+ }
89
+ print $_;
90
+ }
omni_speech/infer/fairseq/examples/wmt21/scripts/replace-unicode-punctuation.perl ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env perl
2
+ #
3
+ # This file is part of moses. Its use is licensed under the GNU Lesser General
4
+ # Public License version 2.1 or, at your option, any later version.
5
+
6
+ use warnings;
7
+ use strict;
8
+
9
+ while (@ARGV) {
10
+ $_ = shift;
11
+ /^-b$/ && ($| = 1, next); # not buffered (flush each line)
12
+ }
13
+
14
+ #binmode(STDIN, ":utf8");
15
+ #binmode(STDOUT, ":utf8");
16
+
17
+ while(<STDIN>) {
18
+ s/,/,/g;
19
+ s/。 */. /g;
20
+ s/、/,/g;
21
+ s/”/"/g;
22
+ s/“/"/g;
23
+ s/∶/:/g;
24
+ s/:/:/g;
25
+ s/?/\?/g;
26
+ s/《/"/g;
27
+ s/》/"/g;
28
+ s/)/\)/g;
29
+ s/!/\!/g;
30
+ s/(/\(/g;
31
+ s/;/;/g;
32
+ s/1/1/g;
33
+ s/」/"/g;
34
+ s/「/"/g;
35
+ s/0/0/g;
36
+ s/3/3/g;
37
+ s/2/2/g;
38
+ s/5/5/g;
39
+ s/6/6/g;
40
+ s/9/9/g;
41
+ s/7/7/g;
42
+ s/8/8/g;
43
+ s/4/4/g;
44
+ s/. */. /g;
45
+ s/~/\~/g;
46
+ s/’/\'/g;
47
+ s/…/\.\.\./g;
48
+ s/━/\-/g;
49
+ s/〈/\</g;
50
+ s/〉/\>/g;
51
+ s/【/\[/g;
52
+ s/】/\]/g;
53
+ s/%/\%/g;
54
+ print $_;
55
+ }
omni_speech/infer/fairseq/examples/womens_bios/README.md ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Wikipedia Biographies of Women
2
+
3
+
4
+ ## Training:
5
+
6
+ The training dataset is created based on WikiSum, a dataset created from the paper [Generating Wikipedia by Summarizing Long Sequences](https://arxiv.org/pdf/1801.10198.pdf). The dataset needs to be generated following the instructions in this [Github Repository](https://github.com/tensorflow/tensor2tensor/tree/master/tensor2tensor/data_generators/wikisum).
7
+
8
+ ### How is the WikiSum dataset structured?
9
+
10
+ Overall, the task in WikiSum was to generate the entire Wikipedia article based on the contents of the top 10 Google Search Results. The authors provide a way for people to recreate their work. In the WikiSum Github, there are two options for the dataset recreation --- the first is to use CommonCrawl (a static, open source crawl of the web) and the second to do Live Web Fetches. The second has higher coverage, but the content is subject to change and difficult to fetch. We used the static, Commoncrawl version. This can be downloaded following the Github repo instructions, though note it will require usage of Google Cloud.
11
+
12
+ Note: in our experience, it also requires requesting that the resource limit of the Google Cloud instance be raised, which requires emailing.
13
+
14
+ Note: Having higher coverage in the training dataset would be expected to improve the model quality. There are many instances in the dataset where the training input (web evidence) does not contain sufficient content for producing the desired Wikipedia article. This may harm the model's ability to learn to retrieve, look at the input evidence, and overall could contribute to increased challenges in generating verifiable Wikipedia biographies.
15
+
16
+ ### How do you go from WikiSum dataset to Biography dataset?
17
+
18
+ The WikiSum dataset is for Wikipedia in general, not just biographies. We do this by querying WikiData to see if the Wikipedia article has an occupation, with the thought that all articles with occupations are probably biographies.
19
+
20
+
21
+ ## Evaluation:
22
+
23
+ You can download the dataset and baseline model with the following command:
24
+
25
+ ```
26
+ wget -N 'https://dl.fbaipublicfiles.com/fairseq/womenbios_dataset.zip'
27
+ wget -N 'https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/encoder.json'
28
+ wget -N 'https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/vocab.bpe'
29
+ wget -N 'https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/dict.txt'
30
+ ```
31
+
32
+ We provide the full text Wikipedia articles split into four categories:
33
+ - Women in Africa
34
+ - Women in Asia
35
+ - Women in Science
36
+ - Women
37
+ We note that these are not exhaustive intersectional categories and mainly stem from personal interest.
38
+
39
+ We also provide the URL of the Wikipedia article. Note that Wikipedia articles are constantly being improved, edited, and changed. Thus, it's completely possible that the Wikipedia article on Wikipedia has been lovingly improved by other Wikipedia editors.
40
+
41
+ To get the occupations of each biographical subject, we use WikiData. We provide a sample script to do this. We also provide the raw output of this query.
42
+
43
+ The final part of the evaluation dataset is to query web evidence for each of the biographical subjects. This is the part of the evaluation dataset that requires the most improvement. As we discuss in our paper, one of the major reasons why it is difficult to write biographies for sometimes very well qualified women is that there is not information online about them. Further, the search engine may not find it. We encourage others to improve upon this part of the data, as even re-querying again on the internet may find new, updated sources of information as the web is constantly evolving.
44
+
45
+ We use the search engine from [Internet-Augmented Dialogue Generation](https://arxiv.org/abs/2107.07566), see [project URL](https://parl.ai/projects/sea/) to do the search queries. Note: we remove wikipedia site sources from our query (or we'd query the data itself). However, it's possible Wikipedia information can be copied around in multiple forms on the web, linked with edits, etc.
46
+
47
+
48
+ ## Section by Section Generation:
49
+
50
+ Wikipedia articles are split into sections, which are usually separated by headings. These headings can be separated in the article text by looking for these equal signs (==), where the number of equal signs usually signals if you are looking at a toplevel heading or a subheading, etc. An example regex that you can use is:
51
+
52
+ `
53
+ section_header_re = re.compile(r"(?<!=)==([^=]+)==(?!=)")
54
+ `
55
+
56
+
57
+ ## List of Notes:
58
+ - People can have multiple occupations, and we keep all occupations that we query from WikiData
59
+
60
+
61
+ ## List of Possible Improvement Areas:
62
+ Using a larger generative pre-trained model, larger-scale retrieval, a retrieval encoder specialized to Wikipedia (or biographies), tuning all of the training & generation parameters exhaustively --- and the like --- would most likely be very useful. Overall, we hope that this is a starting point for others who might be interested in focusing on how we can help address the gender gap on Wikipedia.
63
+
64
+
65
+ ## Interested in Wikipedia and Gender Gap?
66
+ You might want to check out:
67
+ - https://humaniki.wmcloud.org/
68
+ - https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Women_in_Red and https://wikimediafoundation.org/news/2018/10/18/women-in-red-wikiproject/
69
+ - https://meta.wikimedia.org/wiki/Whose_Knowledge%3F/VisibleWikiWomen
70
+ - https://www.ted.com/talks/jess_wade_a_voice_for_diversity_in_science
71
+
72
+ and thanks again to all of the Wikipedia editors and the entire community that is already working so hard to write amazing articles for diverse groups of people.
73
+
74
+
75
+ # LICENSE
76
+ This is licensed under CC-BY-NC, however portions of the dataset are available under separate license terms: text sourced from Wikipedia is licensed under CC-BY-SA.
77
+
78
+
79
+
80
+
81
+
omni_speech/infer/fairseq/examples/womens_bios/query_occupations_from_wikidata.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ from SPARQLWrapper import SPARQLWrapper, JSON
3
+
4
+ endpoint_url = "https://query.wikidata.org/sparql"
5
+
6
+ with open("/your/urls/here") as f:
7
+ data = f.readlines()
8
+ urls = [i.strip() for i in data]
9
+
10
+ def get_results(endpoint_url, URL):
11
+ query = f"""SELECT ?uriLabel ?occupation ?occupationLabel ?dob ?dobLabel WHERE {{
12
+ <{URL}> schema:about ?uri .
13
+ ?uri wdt:P106 ?occupation .
14
+ SERVICE wikibase:label {{ bd:serviceParam wikibase:language "en" }}
15
+ }}"""
16
+ user_agent = "WDQS-example Python/%s.%s" % (sys.version_info[0], sys.version_info[1])
17
+ sparql = SPARQLWrapper(endpoint_url, agent=user_agent)
18
+ sparql.setQuery(query)
19
+ sparql.setReturnFormat(JSON)
20
+ return sparql.query().convert()
21
+
22
+ all_occupations = []
23
+ for URL in urls:
24
+ results = get_results(endpoint_url, URL)
25
+ occupations = []
26
+ for result in results["results"]["bindings"]:
27
+ occupations.append(result['occupationLabel']['value'])
28
+ all_occupations.append(result['uriLabel']['value'] + ", " + ", ".join(occupations))
29
+
30
+ assert(len(all_occupations) == len(urls))
31
+
32
+ with open("/your/file/output/here", "w") as o:
33
+ for line in all_occupations:
34
+ o.write(line.strip() + "\n")
omni_speech/infer/fairseq/examples/xformers/README.md ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Using xFormers with FairSeq
2
+
3
+ [xFormers](https://github.com/facebookresearch/xformers) is a xFormers is a modular library for flexibly generating transformer architectures with interoperable and optimized building blocks.
4
+ The current integration allows for FairSeq users to use an attention variant available in the xFormers repository.
5
+
6
+ In order to enable xFormers, all that needs to be passed in is a string representing an [xFormers attention config](https://github.com/facebookresearch/xformers/blob/5f754129bfb1ea53747b1ab2077261ea762faa47/xformers/components/attention/base.py#L18).
7
+
8
+ The various attention variants can be found [here](https://github.com/facebookresearch/xformers/tree/main/xformers/components/attention).
9
+ These include sparse attention and blocksparse attention.
10
+
11
+ For example, you could pass in the following args:
12
+ ```python
13
+ decoder_xformers_att_config = '{"name": "scaled_dot_product"}'
14
+
15
+ encoder_xformers_att_config = '{"name": "linformer", "seq_len": "256"}'
16
+ ```
17
+
18
+ In order to use blocksparse attention you would have to additionally pass in a blocksparse layout and blocksize. For example:
19
+
20
+ ```python
21
+
22
+ xformers_att_config = '{"name": "scaled_dot_product"}'
23
+ xformers_blocksparse_blocksize = 16
24
+ xformers_blocksparse_layout = torch.ones(
25
+ seq_len // xformers_blocksparse_blocksize,
26
+ seq_len // xformers_blocksparse_blocksize,
27
+ )
28
+
29
+ xf_blocksparse_mha = (
30
+ MultiheadAttention(
31
+ embedding,
32
+ num_heads,
33
+ dropout=0.0,
34
+ add_zero_attn=add_zero_attn,
35
+ xformers_att_config=xformers_att_config,
36
+ xformers_blocksparse_layout=xformers_blocksparse_layout,
37
+ xformers_blocksparse_blocksize=xformers_blocksparse_blocksize,
38
+ )
39
+
40
+ ```
41
+
42
+ The xFormers repository currenlty has benchmarks on the [runtime](https://github.com/facebookresearch/xformers/blob/main/docs/plots/runtime_vs_attention.png)
43
+ and [memory usage](https://github.com/facebookresearch/xformers/blob/main/docs/plots/memory_vs_attention.png) of the various attentions.
omni_speech/infer/fairseq/examples/xglm/README.md ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Few-shot Learning with Multilingual Language Models
2
+
3
+ ## Introduction
4
+
5
+ In this work, we train a family of multilingual generative language models, dubbed XGLM, on a balanced corpus covering a diverse set of languages, and study their few- and zero-shot learning capabilities in a wide range of tasks. Our largest model with 7.5 billion parameters sets new state of the art in few-shot learning on more than 20 representative languages, outperforming GPT-3 of comparable size in multilingual commonsense reasoning (+7.4 accuracy points for 0-shot, +9.4 for 4-shot) and natural language inference (+5.4 for 0-shot, +5.4 for 4-shot). We have included a [model card](model_card.md) of XGLM for transparency and accountability.
6
+
7
+ ## Data and Languages
8
+ XGLM models are trained on a new multilingual corpus extracted from CommonCrawl (CC100-XL), a significantly larger multilingual dataset covering 68 Common Crawl (CC) snapshots (from [Summer 2013](http://commoncrawl.org/2013/11/new-crawl-data-available/) to [March/April 2020](https://commoncrawl.org/2020/04/march-april-2020-crawl-archive-now-available/) consisting of 134 languages. The detailed languages and data statistics are reported in the paper (Table A.1).
9
+
10
+ ## Pre-trained models
11
+
12
+ Model | Layers | Model Dim | FFN Dim | Languages | Download
13
+ ---|---|---|---|---|---
14
+ `XGLM 564M` | 24 | 1024 | 4096 | trained on 30 languages| [xglm.564M.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.564M.tar.gz)
15
+ `XGLM 1.7B` | 24 | 2048 | 8192 | trained on 30 languages| [xglm.1.7B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.1.7B.tar.gz)
16
+ `XGLM 2.9B` | 48 | 2048 | 8192 | trained on 30 languages| [xglm.2.9B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.2.9B.tar.gz)
17
+ `XGLM 7.5B` | 32 | 4096 | 16384 | trained on 30 languages| [xglm.7.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.7.5B.tar.gz)
18
+ `XGLM 4.5B` | 48 | 2048 | 16384 | trained on 134 languages| [xglm.4.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.4.5B.tar.gz)
19
+
20
+ ## Pre-training Data Format
21
+ Our models were pre-trained with data in the following format (i.e. paragraphs are separated with new lines and documents were separated with double new lines).
22
+ ```
23
+ <doc0,para0,tok0> ... <doc0,para0,tokX0> # X0: number of tokens in para0 of doc0
24
+ <doc0,para1,tok0> ... <doc0,para1,tokY0> # Y0: number of tokens in para1 of doc0
25
+
26
+ <doc1,para0,tok0> ... <doc1,para0,tokX1> # X1: number of tokens in para0 of doc1
27
+ <doc1,para1,tok0> ... <doc1,para1,tokY1> # Y1: number of tokens in para1 of doc1
28
+
29
+ ...
30
+ ```
31
+ Fairseq's preprocessing replaces newlines with the end-of-sentence symbol (`</s>`). As a result, the models never saw newline characters during pretraining and the same preprocessing should be run prior to few-shot inference to maximize performance. For example, our language model scoring function has `replace_newlines_with_eos` argument to trigger this preprocessing:
32
+ ```python
33
+ from fairseq.models.transformer_lm import TransformerLanguageModel
34
+
35
+ model_dir = 'path_to_decompressed_tar_gz_dir'
36
+ lm = TransformerLanguageModel.from_pretrained(model_dir, bpe='sentencepiece')
37
+
38
+ text = """First paragraph of the first document.
39
+ Second paragraph of the first document.
40
+
41
+ First paragraph of the second document.
42
+ """
43
+ tokens = lm.score(text, replace_newlines_with_eos=True)['tokens']
44
+ assert '\n' not in lm.decode(tokens) # no newlines were encoded
45
+ ```
46
+
47
+ ## Evaluation
48
+
49
+ ### Example (COPA)
50
+
51
+ The following snippet show how to evaluate our models on the Choice of Plausible Alternatives (COPA) task, using examples in English, Chinese and Hindi.
52
+
53
+ ```python
54
+ data_samples = {
55
+ 'en': [
56
+ {
57
+ "premise": "I wanted to conserve energy.",
58
+ "choice1": "I swept the floor in the unoccupied room.",
59
+ "choice2": "I shut off the light in the unoccupied room.",
60
+ "question": "effect",
61
+ "label": "1"
62
+ },
63
+ {
64
+ "premise": "The flame on the candle went out.",
65
+ "choice1": "I blew on the wick.",
66
+ "choice2": "I put a match to the wick.",
67
+ "question": "cause",
68
+ "label": "0"
69
+ }
70
+ ],
71
+ 'zh': [
72
+ {
73
+ "premise": "我想节约能源。",
74
+ "choice1": "我在空着的房间里扫了地板。",
75
+ "choice2": "我把空房间里的灯关了。",
76
+ "question": "effect",
77
+ "label": "1"
78
+ },
79
+ {
80
+ "premise": "蜡烛上的火焰熄灭了。",
81
+ "choice1": "我吹灭了灯芯。",
82
+ "choice2": "我把一根火柴放在灯芯上。",
83
+ "question": "cause",
84
+ "label": "0"
85
+ }
86
+ ],
87
+ 'hi': [
88
+ {
89
+ "premise": "M te vle konsève enèji.",
90
+ "choice1": "Mwen te fin baleye chanm lib la.",
91
+ "choice2": "Mwen te femen limyè nan chanm lib la.",
92
+ "question": "effect",
93
+ "label": "1"
94
+ },
95
+ {
96
+ "premise": "Flam bouji a te etenn.",
97
+ "choice1": "Mwen te soufle bouji a.",
98
+ "choice2": "Mwen te limen mèch bouji a.",
99
+ "question": "cause",
100
+ "label": "0"
101
+ }
102
+ ]
103
+ }
104
+ ```
105
+ In this example, we format the examples use the non-verbal prompts `{premise}\n{choice1}` and `{premise}\n{choice2}`, which are shared by all three languages.
106
+ ```python
107
+ from fairseq.models.transformer_lm import TransformerLanguageModel
108
+
109
+ model_dir = 'path_to_decompressed_tar_gz_dir'
110
+ lm = TransformerLanguageModel.from_pretrained(model_dir, bpe='sentencepiece')
111
+ lm = lm.eval()
112
+ lm = lm.half()
113
+ lm = lm.cuda()
114
+
115
+ def get_logprobs(prompt):
116
+ import re
117
+ prompt = re.sub('\n+' , '\n', prompt) # collapse repeated newlines, which indicate separate documents
118
+ return lm.score(prompt, replace_newlines_with_eos=True)['positional_scores']
119
+
120
+ # Zero-shot evaluation for the Choice of Plausible Alternatives (COPA) task.
121
+ # A return value of 0 indicates that the first alternative is more plausible,
122
+ # while 1 indicates that the second alternative is more plausible.
123
+ def COPA_eval(prompt, alternative1, alternative2):
124
+ lprob1 = get_logprobs(prompt + "\n" + alternative1).sum()
125
+ lprob2 = get_logprobs(prompt + "\n" + alternative2).sum()
126
+ return 0 if lprob1 > lprob2 else 1
127
+
128
+ for lang in ['en', 'zh', 'hi']:
129
+ for idx, example in enumerate(data_samples[lang]):
130
+ predict = COPA_eval(example["premise"], example["choice1"], example["choice2"])
131
+ print(f'{lang}-{idx}', predict, example['label'])
132
+
133
+ # en-0 1 1
134
+ # en-1 0 0
135
+ # zh-0 1 1
136
+ # zh-1 0 0
137
+ # hi-0 1 1
138
+ # hi-1 0 0
139
+ ```
140
+
141
+ ## XStoryCloze
142
+
143
+ We release XStoryCloze, a new multilingual dataset intended for few-shot evaluation, alongside this paper. XStoryCloze consists of professional translation of the validation split of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. It is opensourced under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/legalcode), the same license as the English StoryCloze.
144
+
145
+ You can download the dataset via [this link](https://dl.fbaipublicfiles.com/xstorycloze.zip).
146
+
147
+ Language | ar | es | eu | hi | id | my | ru | sw | te | zh
148
+ ---|---|---|---|---|---|---|---|---|---|---
149
+ Train size | 360 | 360 | 360 | 360 | 360 | 360 | 360 | 360 | 360 | 360
150
+ Eval size | 1511 | 1511 | 1511 | 1511 | 1511 | 1511 | 1511 | 1511 | 1511 | 1511
151
+
152
+ Please refer to [the dataset doc](XStoryCloze.md) for more information.
153
+
154
+
155
+ ## Publication
156
+ [Few-shot Learning with Multilingual Generative Language Models](https://arxiv.org/abs/2112.10668).
157
+ Xi Victoria Lin*, Todor Mihaylov, Mikel Artetxe, Tianlu Wang, Shuohui Chen, Daniel Simig, Myle Ott, Naman Goyal, Shruti Bhosale, Jingfei Du, Ramakanth Pasunuru, Sam Shleifer, Punit Singh Koura, Vishrav Chaudhary, Brian O'Horo, Jeff Wang, Luke Zettlemoyer, Zornitsa Kozareva, Mona Diab, Veselin Stoyanov, Xian Li* (* Equal Contribution).
158
+ EMNLP 2022.
159
+
160
+ ## Citation
161
+ ```
162
+ @article{DBLP:journals/corr/abs-2112-10668,
163
+ author = {Xi Victoria Lin and
164
+ Todor Mihaylov and
165
+ Mikel Artetxe and
166
+ Tianlu Wang and
167
+ Shuohui Chen and
168
+ Daniel Simig and
169
+ Myle Ott and
170
+ Naman Goyal and
171
+ Shruti Bhosale and
172
+ Jingfei Du and
173
+ Ramakanth Pasunuru and
174
+ Sam Shleifer and
175
+ Punit Singh Koura and
176
+ Vishrav Chaudhary and
177
+ Brian O'Horo and
178
+ Jeff Wang and
179
+ Luke Zettlemoyer and
180
+ Zornitsa Kozareva and
181
+ Mona T. Diab and
182
+ Veselin Stoyanov and
183
+ Xian Li},
184
+ title = {Few-shot Learning with Multilingual Language Models},
185
+ journal = {CoRR},
186
+ volume = {abs/2112.10668},
187
+ year = {2021},
188
+ url = {https://arxiv.org/abs/2112.10668},
189
+ eprinttype = {arXiv},
190
+ eprint = {2112.10668},
191
+ timestamp = {Tue, 04 Jan 2022 15:59:27 +0100},
192
+ biburl = {https://dblp.org/rec/journals/corr/abs-2112-10668.bib},
193
+ bibsource = {dblp computer science bibliography, https://dblp.org}
194
+ }
195
+ ```
omni_speech/infer/fairseq/examples/xglm/XStoryCloze.md ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ XStoryCloze consists of professional translation of the validation split of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. This dataset is released by Meta AI alongside the paper [Few-shot Learning with Multilingual Generative Language Models. EMNLP 2022](https://arxiv.org/abs/2112.10668).
2
+
3
+ # Languages
4
+ ru, zh (Simplified), es (Latin America), ar, hi, id, te, sw, eu, my.
5
+
6
+ # Data Splits
7
+ This dataset is intended to be used for evaluating the zero- and few-shot learning capabilities of multlingual language models. We split the data for each language into train and test (360 vs. 1510 examples, respectively). The released data files for different languages maintain a line-by-line alignment.
8
+
9
+ # Access English StoryCloze
10
+ Please request the original English StoryCloze dataset through the [official website](https://cs.rochester.edu/nlp/rocstories/). You can create a split of the en data following our data split scheme using the following commands:
11
+ ```
12
+ head -361 spring2016.val.tsv > spring2016.val.en.tsv.split_20_80_train.tsv
13
+
14
+ head -1 spring2016.val.tsv > spring2016.val.en.tsv.split_20_80_eval.tsv # TSV header
15
+ tail -1511 spring2016.val.tsv >> spring2016.val.en.tsv.split_20_80_eval.tsv
16
+ ```
17
+
18
+ # Licence
19
+ XStoryCloze is opensourced under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/legalcode), the same license as the original English StoryCloze.
20
+
21
+ # Citation
22
+ We hope this dataset is helpful for the research and wider NLP community. If you use XStoryCloze in your work, please cite
23
+ ```
24
+ @article{DBLP:journals/corr/abs-2112-10668,
25
+ author = {Xi Victoria Lin and
26
+ Todor Mihaylov and
27
+ Mikel Artetxe and
28
+ Tianlu Wang and
29
+ Shuohui Chen and
30
+ Daniel Simig and
31
+ Myle Ott and
32
+ Naman Goyal and
33
+ Shruti Bhosale and
34
+ Jingfei Du and
35
+ Ramakanth Pasunuru and
36
+ Sam Shleifer and
37
+ Punit Singh Koura and
38
+ Vishrav Chaudhary and
39
+ Brian O'Horo and
40
+ Jeff Wang and
41
+ Luke Zettlemoyer and
42
+ Zornitsa Kozareva and
43
+ Mona T. Diab and
44
+ Veselin Stoyanov and
45
+ Xian Li},
46
+ title = {Few-shot Learning with Multilingual Language Models},
47
+ journal = {CoRR},
48
+ volume = {abs/2112.10668},
49
+ year = {2021},
50
+ url = {https://arxiv.org/abs/2112.10668},
51
+ eprinttype = {arXiv},
52
+ eprint = {2112.10668},
53
+ timestamp = {Tue, 04 Jan 2022 15:59:27 +0100},
54
+ biburl = {https://dblp.org/rec/journals/corr/abs-2112-10668.bib},
55
+ bibsource = {dblp computer science bibliography, https://dblp.org}
56
+ }
57
+ ```
omni_speech/infer/fairseq/examples/xglm/model_card.md ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # XGLM multilingual model
2
+ ## Version 1.0.0
3
+
4
+ ### Model developer
5
+ Meta AI
6
+
7
+ ### Model type
8
+ A family of multilingual autoregressive language models (ranging from 564 million to 7.5 billion parameters) trained on a balanced corpus of a diverse set of languages. The language model can learn tasks from natural language descriptions and a few examples.
9
+
10
+ ### Model Feedback Channel
11
+ https://github.com/pytorch/fairseq
12
+
13
+ ## Intended use
14
+ ### Primary intended use
15
+ For research purposes only, e.g. reproducing model evaluation results. Generation is only used in a limited capacity for explanation/justification or for prompting/probing/priming for class labels.
16
+
17
+ ### Out of scope uses
18
+ The primary purpose of the model is not to generate language, although the model is capable of doing that.
19
+
20
+ ## Potential risks
21
+ This section lists the potential risks associated with using the model.
22
+
23
+ ### Relevant factors
24
+ Based on known problems with NLP technology, potential relevant factors include output correctness, robustness, bias (gender, profession, race and religion), etc.
25
+
26
+ ### Evaluation factors
27
+ The model was evaluated on hate speech detection and occupation identification.
28
+ * Hate speech detection (Huang et al. (2020)) - A safety task to test language models’ ability to identify hateful and offensive text.
29
+ * Occupation identification (De-Arteaga et al., 2019), (Zhao et al., 2020) - A bias task to study language models’ performance divergence between different gender groups on the task of occupation identification.
30
+
31
+ ## Metrics
32
+ ### Model performance measures
33
+ The XGLM model was primarily evaluated on
34
+ 1. Zero shot and few shot learning by looking at per-language performance on tasks spanning commonsense reasoning (XCOPA, XWinograd), natural language inference (XNLI) and paraphrasing (PAWS-X). The model is also evaluated on XStoryCloze, a new dataset created by Meta AI.
35
+ 2. Cross lingual transfer through templates and few-shot examples.
36
+ 3. Knowledge probing - Evaluate to what extent the XGLM model can effectively store factual knowledge in different languages using the mLAMA benchmark.
37
+ 4. Translation - We report machine translation results on WMT benchmarks and a subset of FLORES-101 in the main paper.
38
+
39
+ The model was also evaluated on hate speech datasets introduced by Huang et al. (2020) and an occupation identification dataset by De-Arteaga et al. 2019 to identify bias in the model.
40
+
41
+ ### Approaches to handle uncertainty
42
+ Report confidence intervals, variance metrics for the model performance metrics. Few-shot evaluation was conducted with different sampling with 5 seeds. We reported statistical significance.
43
+
44
+ ## Evaluation data
45
+ ## Zero Shot and Few Shot evaluation
46
+
47
+ ### XNLI (Conneau et al., 2018)
48
+ #### Description
49
+ The Cross-lingual Natural Language Inference (XNLI) corpus is the extension of the Multi-Genre NLI (MultiNLI) corpus to 15 languages. The dataset was created by manually translating the validation and test sets of MultiNLI into each of those 15 languages.
50
+
51
+ ### XStoryCloze
52
+ #### Description
53
+ A new dataset created by Meta AI along side this work by translating the validation split of the English StoryCloze dataset (Mostafazadeh et al., 2016) (Spring 2016 version) to 10 other typologically diverse languages (ru, zh Simplified, es Latin America, ar, hi, id, te, sw, eu, my).
54
+
55
+ ### XCOPA (Ponti et al., 2020)
56
+ #### Description
57
+ The Cross-lingual Choice of Plausible Alternatives (XCOPA) dataset is a benchmark to evaluate the ability of machine learning models to transfer commonsense reasoning across languages. The dataset is the translation and reannotation of the English COPA (Roemmele et al. 2011) and covers 11 languages from 11 families and several areas around the globe.
58
+
59
+ ### XWinograd (Tikhonov and Ryabinin, 2021)
60
+ #### Description
61
+ XWinograd is a multilingual collection of Winograd Schemas in six languages that can be used for evaluation of cross-lingual commonsense reasoning capabilities.
62
+
63
+ ### PAWS-X (Yang et al., 2019)
64
+ #### Description
65
+ PAWS-X contains 23,659 human translated PAWS evaluation pairs and 296,406 machine translated training pairs in six typologically distinct languages: French, Spanish, German, Chinese, Japanese, and Korean. All translated pairs are sourced from examples in PAWS-Wiki.
66
+
67
+ ## Responsible AI (RAI) evaluation
68
+ ### Hate speech (Huang et al. 2020)
69
+ This is a multilingual Twitter corpus for the task of hate speech detection with inferred four author demographic factors: age, country, gender and race/ethnicity. The corpus covers five languages: English, Italian, Polish, Portuguese and Spanish.
70
+
71
+ ### Bias dataset (De-Arteaga et al. 2019)
72
+ The aim of this dataset is to study the gender bias of models that identify a person’s occupation from their bios.
73
+
74
+ ----
75
+
76
+ ## Training data
77
+ ### CC100-XL
78
+ #### Description
79
+ Following the recent success of multilingual self-supervised pre-training (Devlin et al., 2019; Lample and Conneau, 2019; Con; Xue et al., 2020; Goyal et al., 2021a; Liu et al., 2020), we train our language models on a mixture of monolingual text of different languages. We extended the pipeline used for mining the CC100 corpus to generate CC100-XL, a significantly larger multilingual dataset covering 68 Common Crawl snapshots (from Summer 2013 to March/April 2020) and 134 languages.
80
+
81
+ More details on the CC100-XL dataset can be found in the Appendix section of the paper.
82
+
83
+ ## RAI Dimensions
84
+ ### Fairness (Bias and inclusion)
85
+ The XGLM model was evaluated on Hate speech and bias identification datasets. For hate speech, we observe that across the 5 languages in the dataset, in context learning results are only slightly better than random (50%). Another interesting observation is that most few shot results are worse than zero-shot, which indicates that the model is not able to utilize examples using the templates described in the paper. For bias identification, the XGLM (6.7B) English only model achieves the best performance on English and Spanish, while the GPT-3 model of comparable size (6.7B) model achieves the best in French. On certain occupations (e.g. model and teacher), XGLM 6.7B En only model and GPT-3 (6.7B) have very significant bias while XGLM 7.5B is much less biased.
86
+
87
+ ### Privacy and security
88
+ The XGLM model did not have any special Privacy and Security considerations. The training data and evaluation data were both public and went through standard Meta AI Privacy and licensing procedures.
89
+
90
+ ### Transparency and control
91
+ In the spirit of transparency and accountability we have created this model card and a data card for the CC100-XL which can be found in the Appendix section of the paper.
92
+
93
+ ### Efficiency (Green AI)
94
+ From an engineering perspective, XGLM pertains to a family of models that represent single unified models catering to many languages which have wide application across many applications. Such a unified single model saves on carbon footprint as well as energy consumption (comparing to the alternative: separate models for different languages) leading to more energy efficiency. A single model, despite having the risk of being a single point of failure, has the powerful incentive of being easier to maintain, access, distribute, and track.
95
+
96
+ ## References
97
+ Edoardo Maria Ponti, Goran Glavas, Olga Majewska, Qianchu Liu, Ivan Vulic, and Anna Korhonen. 2020. XCOPA: A multilingual dataset for causal commonsense reasoning. In Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing, EMNLP 2020, Online, November 16-20, 2020, pages 2362–2376. Association for Computational Linguistics.
98
+ XCOPA Dataset | Papers With Code
99
+
100
+ Alexey Tikhonov and Max Ryabinin. 2021. It’s all in the heads: Using attention heads as a baseline for cross-lingual transfer in commonsense reasoning. In Findings of the Association for Computational Linguistics: ACL/IJCNLP 2021, Online Event, August 1-6, 2021, volume ACL/IJCNLP 2021 of Findings of ACL, pages 3534–3546. Association for Computational Linguistics.
101
+ XWINO Dataset | Papers With Code (XWinograd)
102
+
103
+ Yinfei Yang, Yuan Zhang, Chris Tar, and Jason Baldridge. 2019. PAWS-X: A cross-lingual adversarial dataset for paraphrase identification. CoRR, abs/1908.11828.
104
+ PAWS-X Dataset | Papers With Code
105
+
106
+ Alexis Conneau, Guillaume Lample, Ruty Rinott, Adina Williams, Samuel R. Bowman, Holger Schwenk, and Veselin Stoyanov. 2018. XNLI: evaluating cross-lingual sentence representations. CoRR, abs/1809.05053.
107
+ XNLI Dataset | Papers With Code
108
+
109
+ Xiaolei Huang, Linzi Xing, Franck Dernoncourt, and Michael Paul. 2020. Multilingual twitter corpus and baselines for evaluating demographic bias in hate speech recognition. In Proceedings of the 12th Language Resources and Evaluation Conference, pages 1440–1448.
110
+
111
+ Maria De-Arteaga, Alexey Romanov, Hanna Wallach, Jennifer Chayes, Christian Borgs, Alexandra Chouldechova, Sahin Geyik, Krishnaram Kenthapadi, and Adam Tauman Kalai. 2019. Bias in bios: A case study of semantic representation bias in a high-stakes setting. In proceedings of the Conference on Fairness, Accountability, and Transparency, pages 120–128.
112
+
113
+ Nasrin Mostafazadeh, Nathanael Chambers, Xiaodong He, Devi Parikh, Dhruv Batra, Lucy Vanderwende, Pushmeet Kohli, James F. Allen. A Corpus and Evaluation Framework for Deeper Understanding of Commonsense Stories. CoRR abs/1604.01696.
114
+
115
+ Jieyu Zhao, Subhabrata Mukherjee, Saghar Hosseini, Kai-Wei Chang, and Ahmed Hassan Awadallah. 2020. Gender bias in multilingual embeddings and crosslingual transfer. In Proceedings of the 58th Annual Meeting of the Association for Computational Linguistics, pages 2896–2907.
116
+
117
+ ## Citation details
118
+ ```
119
+ @article{DBLP:journals/corr/abs-2112-10668,
120
+ author = {Xi Victoria Lin and
121
+ Todor Mihaylov and
122
+ Mikel Artetxe and
123
+ Tianlu Wang and
124
+ Shuohui Chen and
125
+ Daniel Simig and
126
+ Myle Ott and
127
+ Naman Goyal and
128
+ Shruti Bhosale and
129
+ Jingfei Du and
130
+ Ramakanth Pasunuru and
131
+ Sam Shleifer and
132
+ Punit Singh Koura and
133
+ Vishrav Chaudhary and
134
+ Brian O'Horo and
135
+ Jeff Wang and
136
+ Luke Zettlemoyer and
137
+ Zornitsa Kozareva and
138
+ Mona T. Diab and
139
+ Veselin Stoyanov and
140
+ Xian Li},
141
+ title = {Few-shot Learning with Multilingual Language Models},
142
+ journal = {CoRR},
143
+ volume = {abs/2112.10668},
144
+ year = {2021},
145
+ url = {https://arxiv.org/abs/2112.10668},
146
+ eprinttype = {arXiv},
147
+ eprint = {2112.10668},
148
+ timestamp = {Tue, 04 Jan 2022 15:59:27 +0100},
149
+ biburl = {https://dblp.org/rec/journals/corr/abs-2112-10668.bib},
150
+ bibsource = {dblp computer science bibliography, https://dblp.org}
151
+ }
152
+ ```
omni_speech/infer/fairseq/examples/xlmr/README.md ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Unsupervised Cross-lingual Representation Learning at Scale (XLM-RoBERTa)
2
+ https://arxiv.org/pdf/1911.02116.pdf
3
+
4
+ # Larger-Scale Transformers for Multilingual Masked Language Modeling
5
+ https://arxiv.org/pdf/2105.00572.pdf
6
+
7
+
8
+ ## What's New:
9
+ - June 2021: `XLMR-XL` AND `XLMR-XXL` models released.
10
+
11
+ ## Introduction
12
+
13
+ `XLM-R` (`XLM-RoBERTa`) is a generic cross lingual sentence encoder that obtains state-of-the-art results on many cross-lingual understanding (XLU) benchmarks. It is trained on `2.5T` of filtered CommonCrawl data in 100 languages (list below).
14
+
15
+ Language | Language|Language |Language | Language
16
+ ---|---|---|---|---
17
+ Afrikaans | Albanian | Amharic | Arabic | Armenian
18
+ Assamese | Azerbaijani | Basque | Belarusian | Bengali
19
+ Bengali Romanize | Bosnian | Breton | Bulgarian | Burmese
20
+ Burmese zawgyi font | Catalan | Chinese (Simplified) | Chinese (Traditional) | Croatian
21
+ Czech | Danish | Dutch | English | Esperanto
22
+ Estonian | Filipino | Finnish | French | Galician
23
+ Georgian | German | Greek | Gujarati | Hausa
24
+ Hebrew | Hindi | Hindi Romanize | Hungarian | Icelandic
25
+ Indonesian | Irish | Italian | Japanese | Javanese
26
+ Kannada | Kazakh | Khmer | Korean | Kurdish (Kurmanji)
27
+ Kyrgyz | Lao | Latin | Latvian | Lithuanian
28
+ Macedonian | Malagasy | Malay | Malayalam | Marathi
29
+ Mongolian | Nepali | Norwegian | Oriya | Oromo
30
+ Pashto | Persian | Polish | Portuguese | Punjabi
31
+ Romanian | Russian | Sanskrit | Scottish Gaelic | Serbian
32
+ Sindhi | Sinhala | Slovak | Slovenian | Somali
33
+ Spanish | Sundanese | Swahili | Swedish | Tamil
34
+ Tamil Romanize | Telugu | Telugu Romanize | Thai | Turkish
35
+ Ukrainian | Urdu | Urdu Romanize | Uyghur | Uzbek
36
+ Vietnamese | Welsh | Western Frisian | Xhosa | Yiddish
37
+
38
+ ## Pre-trained models
39
+
40
+ Model | Description | #params | vocab size | Download
41
+ ---|---|---|---|---
42
+ `xlmr.base` | XLM-R using the BERT-base architecture | 250M | 250k | [xlm.base.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xlmr.base.tar.gz)
43
+ `xlmr.large` | XLM-R using the BERT-large architecture | 560M | 250k | [xlm.large.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xlmr.large.tar.gz)
44
+ `xlmr.xl` | XLM-R (`layers=36, model_dim=2560`) | 3.5B | 250k | [xlm.xl.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xlmr/xlmr.xl.tar.gz)
45
+ `xlmr.xxl` | XLM-R (`layers=48, model_dim=4096`) | 10.7B | 250k | [xlm.xxl.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xlmr/xlmr.xxl.tar.gz)
46
+
47
+ ## Results
48
+
49
+ **[XNLI (Conneau et al., 2018)](https://arxiv.org/abs/1809.05053)**
50
+
51
+ Model | average | en | fr | es | de | el | bg | ru | tr | ar | vi | th | zh | hi | sw | ur
52
+ ---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
53
+ `roberta.large.mnli` _(TRANSLATE-TEST)_ | 77.8 | 91.3 | 82.9 | 84.3 | 81.2 | 81.7 | 83.1 | 78.3 | 76.8 | 76.6 | 74.2 | 74.1 | 77.5 | 70.9 | 66.7 | 66.8
54
+ `xlmr.large` _(TRANSLATE-TRAIN-ALL)_ | 83.6 | 89.1 | 85.1 | 86.6 | 85.7 | 85.3 | 85.9 | 83.5 | 83.2 | 83.1 | 83.7 | 81.5 | 83.7 | 81.6 | 78.0 | 78.1
55
+ `xlmr.xl` _(TRANSLATE-TRAIN-ALL)_ | 85.4 | 91.1 | 87.2 | 88.1 | 87.0 | 87.4 | 87.8 | 85.3 | 85.2 | 85.3 | 86.2 | 83.8 | 85.3 | 83.1 | 79.8 | 78.2 | 85.4
56
+ `xlmr.xxl` _(TRANSLATE-TRAIN-ALL)_ | 86.0 | 91.5 | 87.6 | 88.7 | 87.8 | 87.4 | 88.2 | 85.6 | 85.1 | 85.8 | 86.3 | 83.9 | 85.6 | 84.6 | 81.7 | 80.6
57
+
58
+ **[MLQA (Lewis et al., 2018)](https://arxiv.org/abs/1910.07475)**
59
+
60
+ Model | average | en | es | de | ar | hi | vi | zh
61
+ ---|---|---|---|---|---|---|---|---
62
+ `BERT-large` | - | 80.2/67.4 | - | - | - | - | - | -
63
+ `mBERT` | 57.7 / 41.6 | 77.7 / 65.2 | 64.3 / 46.6 | 57.9 / 44.3 | 45.7 / 29.8| 43.8 / 29.7 | 57.1 / 38.6 | 57.5 / 37.3
64
+ `xlmr.large` | 70.7 / 52.7 | 80.6 / 67.8 | 74.1 / 56.0 | 68.5 / 53.6 | 63.1 / 43.5 | 69.2 / 51.6 | 71.3 / 50.9 | 68.0 / 45.4
65
+ `xlmr.xl` | 73.4 / 55.3 | 85.1 / 72.6 | 66.7 / 46.2 | 70.5 / 55.5 | 74.3 / 56.9 | 72.2 / 54.7 | 74.4 / 52.9 | 70.9 / 48.5
66
+ `xlmr.xxl` | 74.8 / 56.6 | 85.5 / 72.4 | 68.6 / 48.4 | 72.7 / 57.8 | 75.4 / 57.6 | 73.7 / 55.8 | 76.0 / 55.0 | 71.7 / 48.9
67
+
68
+
69
+ ## Example usage
70
+
71
+ ##### Load XLM-R from torch.hub (PyTorch >= 1.1):
72
+ ```python
73
+ import torch
74
+ xlmr = torch.hub.load('pytorch/fairseq:main', 'xlmr.large')
75
+ xlmr.eval() # disable dropout (or leave in train mode to finetune)
76
+ ```
77
+
78
+ ##### Load XLM-R (for PyTorch 1.0 or custom models):
79
+ ```python
80
+ # Download xlmr.large model
81
+ wget https://dl.fbaipublicfiles.com/fairseq/models/xlmr.large.tar.gz
82
+ tar -xzvf xlmr.large.tar.gz
83
+
84
+ # Load the model in fairseq
85
+ from fairseq.models.roberta import XLMRModel
86
+ xlmr = XLMRModel.from_pretrained('/path/to/xlmr.large', checkpoint_file='model.pt')
87
+ xlmr.eval() # disable dropout (or leave in train mode to finetune)
88
+ ```
89
+
90
+ ##### Apply sentence-piece-model (SPM) encoding to input text:
91
+ ```python
92
+ en_tokens = xlmr.encode('Hello world!')
93
+ assert en_tokens.tolist() == [0, 35378, 8999, 38, 2]
94
+ xlmr.decode(en_tokens) # 'Hello world!'
95
+
96
+ zh_tokens = xlmr.encode('你好,世界')
97
+ assert zh_tokens.tolist() == [0, 6, 124084, 4, 3221, 2]
98
+ xlmr.decode(zh_tokens) # '你好,世界'
99
+
100
+ hi_tokens = xlmr.encode('नमस्ते दुनिया')
101
+ assert hi_tokens.tolist() == [0, 68700, 97883, 29405, 2]
102
+ xlmr.decode(hi_tokens) # 'नमस्ते दुनिया'
103
+
104
+ ar_tokens = xlmr.encode('مرحبا بالعالم')
105
+ assert ar_tokens.tolist() == [0, 665, 193478, 258, 1705, 77796, 2]
106
+ xlmr.decode(ar_tokens) # 'مرحبا بالعالم'
107
+
108
+ fr_tokens = xlmr.encode('Bonjour le monde')
109
+ assert fr_tokens.tolist() == [0, 84602, 95, 11146, 2]
110
+ xlmr.decode(fr_tokens) # 'Bonjour le monde'
111
+ ```
112
+
113
+ ##### Extract features from XLM-R:
114
+ ```python
115
+ # Extract the last layer's features
116
+ last_layer_features = xlmr.extract_features(zh_tokens)
117
+ assert last_layer_features.size() == torch.Size([1, 6, 1024])
118
+
119
+ # Extract all layer's features (layer 0 is the embedding layer)
120
+ all_layers = xlmr.extract_features(zh_tokens, return_all_hiddens=True)
121
+ assert len(all_layers) == 25
122
+ assert torch.all(all_layers[-1] == last_layer_features)
123
+ ```
124
+
125
+ ## Citation
126
+
127
+ ```bibtex
128
+ @article{conneau2019unsupervised,
129
+ title={Unsupervised Cross-lingual Representation Learning at Scale},
130
+ author={Conneau, Alexis and Khandelwal, Kartikay and Goyal, Naman and Chaudhary, Vishrav and Wenzek, Guillaume and Guzm{\'a}n, Francisco and Grave, Edouard and Ott, Myle and Zettlemoyer, Luke and Stoyanov, Veselin},
131
+ journal={arXiv preprint arXiv:1911.02116},
132
+ year={2019}
133
+ }
134
+ ```
135
+
136
+
137
+ ```bibtex
138
+ @article{goyal2021larger,
139
+ title={Larger-Scale Transformers for Multilingual Masked Language Modeling},
140
+ author={Goyal, Naman and Du, Jingfei and Ott, Myle and Anantharaman, Giri and Conneau, Alexis},
141
+ journal={arXiv preprint arXiv:2105.00572},
142
+ year={2021}
143
+ }
144
+ ```
omni_speech/infer/fairseq/examples/xmod/README.md ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # X-MOD: Lifting the Curse of Multilinguality by Pre-training Modular Transformers
2
+
3
+ https://arxiv.org/abs/2205.06266
4
+
5
+
6
+ ## Introduction
7
+
8
+ X-MOD extends multilingual masked language models like XLM-R to include language-specific modular components, introduced at each transformer layer. Each module is only used by one language. For fine-tuning, the modular components are frozen, and replaced with the target language in cross-lingual transfer settings.
9
+
10
+
11
+ ## Pre-trained models
12
+
13
+ Model | Size | # train steps | # langs | Download
14
+ ---|---|---|---|---
15
+ `xmod.base.13.125k` | BERT-base | 125k | 13 | [xmod.base.13.125k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.13.125k.tar.gz)
16
+ `xmod.base.30.125k` | BERT-base | 125k | 30 | [xmod.base.30.125k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.30.125k.tar.gz)
17
+ `xmod.base.30.195k` | BERT-base | 195k | 30 | [xmod.base.30.195k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.30.195k.tar.gz)
18
+ `xmod.base.60.125k` | BERT-base | 125k | 60 | [xmod.base.60.125k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.60.125k.tar.gz)
19
+ `xmod.base.60.265k` | BERT-base | 265k | 60 | [xmod.base.60.265k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.60.265k.tar.gz)
20
+ `xmod.base.75.125k` | BERT-base | 125k | 75 | [xmod.base.75.125k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.75.125k.tar.gz)
21
+ `xmod.base.75.269k` | BERT-base | 269k | 75 | [xmod.base.75.269k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.75.269k.tar.gz)
22
+ `xmod.base` | BERT-base | 1M | 81 | [xmod.base.81.1M.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.81.1M.tar.gz)
23
+ `xmod.large.prenorm` | BERT-large | 500k | 81 | [xmod.large.prenorm.81.500k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.large.prenorm.81.500k.tar.gz)
24
+
25
+
26
+ ## Fine-tuning on NLI
27
+
28
+ We next provide an example of how to fine-tune the pre-trained models above on Natural Language Inference (NLI). We use MNLI for training in English, and show how to run inference in other languages.
29
+
30
+ ### 1) Download a pre-trained model
31
+
32
+ ```bash
33
+ MODEL=xmod.base.81.1M
34
+ wget https://dl.fbaipublicfiles.com/fairseq/models/xmod/$MODEL.tar.gz
35
+ tar -xzf $MODEL.tar.gz
36
+ ```
37
+
38
+ ### 2) Download and preprocess [MNLI](https://cims.nyu.edu/~sbowman/multinli/)
39
+ ```bash
40
+ wget https://cims.nyu.edu/~sbowman/multinli/multinli_1.0.zip
41
+ unzip multinli_1.0.zip
42
+ python ./examples/xmod/preprocess_nli.py \
43
+ --sentencepiece-model $MODEL/sentencepiece.bpe.model \
44
+ --train multinli_1.0/multinli_1.0_train.jsonl \
45
+ --valid multinli_1.0/multinli_1.0_dev_matched.jsonl \
46
+ --destdir multinli_1.0/fairseq
47
+ ```
48
+
49
+ ### 3) Fine-tune on MNLI:
50
+
51
+ ```bash
52
+ MAX_EPOCH=5
53
+ LR=1e-05
54
+ BATCH_SIZE=32
55
+ DATA_DIR=multinli_1.0/fairseq/bin
56
+
57
+ CUDA_VISIBLE_DEVICES=0 fairseq-train $DATA_DIR \
58
+ --restore-file $MODEL/model.pt \
59
+ --save-dir $MODEL/nli \
60
+ --reset-optimizer \
61
+ --reset-dataloader \
62
+ --reset-meters \
63
+ --best-checkpoint-metric accuracy \
64
+ --maximize-best-checkpoint-metric \
65
+ --task sentence_prediction_adapters \
66
+ --num-classes 3 \
67
+ --init-token 0 \
68
+ --separator-token 2 \
69
+ --max-positions 512 \
70
+ --shorten-method "truncate" \
71
+ --arch xmod_base \
72
+ --dropout 0.1 \
73
+ --attention-dropout 0.1 \
74
+ --weight-decay 0.01 \
75
+ --criterion sentence_prediction_adapters \
76
+ --optimizer adam \
77
+ --adam-betas '(0.9, 0.98)' \
78
+ --adam-eps 1e-06 \
79
+ --clip-norm 0.0 \
80
+ --lr-scheduler fixed \
81
+ --lr $LR \
82
+ --fp16 \
83
+ --fp16-init-scale 4 \
84
+ --threshold-loss-scale 1 \
85
+ --fp16-scale-window 128 \
86
+ --batch-size $BATCH_SIZE \
87
+ --required-batch-size-multiple 1 \
88
+ --update-freq 1 \
89
+ --max-epoch $MAX_EPOCH
90
+ ```
91
+
92
+ ### 4) Run inference
93
+
94
+ After training the model, we can load it and run inference in our target language. The default language is set to English, which is why we were not required to pass a language ID to the model during fine-tuning. To run inference in a non-English language, we need to tell the model that the module of the target language should be used instead:
95
+
96
+ ```python
97
+ from fairseq.models.xmod import XMODModel
98
+
99
+ MODEL='xmod.base.81.1M/nli'
100
+ DATA='multinli_1.0/fairseq/bin'
101
+
102
+ # Load model
103
+ model = XMODModel.from_pretrained(
104
+ model_name_or_path=MODEL,
105
+ checkpoint_file='checkpoint_best.pt',
106
+ data_name_or_path=DATA,
107
+ suffix='',
108
+ criterion='cross_entropy',
109
+ bpe='sentencepiece',
110
+ sentencepiece_model=DATA+'/input0/sentencepiece.bpe.model')
111
+ model = model.eval(); # disable dropout
112
+ model = model.half(); # use FP16
113
+ model = model.cuda(); # move to GPU
114
+
115
+ def predict(premise, hypothesis, lang):
116
+ tokens = model.encode(premise, hypothesis)
117
+ idx = model.predict('sentence_classification_head', tokens, lang_id=[lang]).argmax().item()
118
+ dictionary = model.task.label_dictionary
119
+ return dictionary[idx + dictionary.nspecial]
120
+
121
+ predict(
122
+ premise='X-Mod hat spezifische Module die für jede Sprache existieren.',
123
+ hypothesis='X-Mod hat Module.',
124
+ lang='de_DE'
125
+ ) # entailment
126
+
127
+ predict(
128
+ premise='Londres es la capital del Reino Unido.',
129
+ hypothesis='Londres está en Francia.',
130
+ lang='es_XX',
131
+ ) # contradiction
132
+
133
+ predict(
134
+ premise='Patxik gogoko ditu babarrunak.',
135
+ hypothesis='Patxik babarrunak bazkaldu zituen.',
136
+ lang='eu_ES',
137
+ ) # neutral
138
+ ```
139
+
140
+
141
+ ## Citation
142
+
143
+ ```bibtex
144
+ @misc{pfeiffer2022xmod,
145
+ doi = {10.48550/ARXIV.2205.06266},
146
+ url = {https://arxiv.org/abs/2205.06266},
147
+ title = {Lifting the Curse of Multilinguality by Pre-training Modular Transformers},
148
+ publisher = {arXiv},
149
+ year = {2022},
150
+ }
151
+ ```
omni_speech/infer/fairseq/examples/xmod/preprocess_nli.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import os
7
+ import json
8
+ import collections
9
+ import argparse
10
+ import shutil
11
+ import subprocess
12
+ import sys
13
+ import tempfile
14
+ from multiprocessing import Pool
15
+ import sentencepiece as spm
16
+
17
+
18
+ def preprocess(spm_model_path, train_path, valid_path, test_path, dest_dir, remove_empty=False, output_format='piece', workers=20):
19
+ with tempfile.TemporaryDirectory() as tmp:
20
+ # Tokenize with SentencePiece
21
+ for split, path in ('train', train_path), ('valid', valid_path), ('test', test_path):
22
+ if path is None:
23
+ continue
24
+ if path == '-':
25
+ path = sys.stdin.fileno()
26
+ with open(path, encoding='utf-8', errors='surrogateescape') as fin:
27
+ with open(f'{tmp}/{split}', mode='w', encoding='utf-8', errors='surrogateescape') as fout:
28
+ encoder = MultiprocessingEncoder(model=spm_model_path, remove_empty=remove_empty, output_format=output_format)
29
+ pool = Pool(workers, initializer=encoder.initializer)
30
+ encoded_lines = pool.imap(encoder.encode, fin, 10000)
31
+ for i, line in enumerate(encoded_lines, start=1):
32
+ if line is not None:
33
+ print(line, file=fout)
34
+ if i % 10000 == 0:
35
+ print("tokenized {} lines".format(i), file=sys.stderr)
36
+
37
+ # Generate dictionary
38
+ sp = spm.SentencePieceProcessor(model_file=spm_model_path)
39
+ if output_format == 'piece':
40
+ vocab = [sp.id_to_piece(i) for i in range(3, sp.vocab_size())]
41
+ else:
42
+ vocab = map(str, range(sp.vocab_size()))
43
+ with open(f'{tmp}/dict.txt', mode='w', encoding='utf-8', errors='surrogateescape') as f:
44
+ for word in vocab:
45
+ print(word, 1, file=f)
46
+
47
+ # Binarize
48
+ command = [
49
+ 'python3', '-m', 'fairseq_cli.preprocess',
50
+ '--only-source',
51
+ '--thresholdsrc', '0',
52
+ '--destdir', dest_dir,
53
+ '--srcdict', f'{tmp}/dict.txt',
54
+ '--workers', '20',
55
+ ]
56
+ for split, path in ('train', train_path), ('valid', valid_path), ('test', test_path):
57
+ if path is not None:
58
+ command += [f'--{split}pref', f'{tmp}/{split}']
59
+ subprocess.run(command)
60
+
61
+ # Copy SentencePiece model
62
+ shutil.copyfile(spm_model_path, f'{dest_dir}/sentencepiece.bpe.model')
63
+
64
+
65
+ class MultiprocessingEncoder(object):
66
+ def __init__(self, model, remove_empty, output_format):
67
+ self.model = model
68
+ self.remove_empty = remove_empty
69
+ self.output_format = output_format
70
+
71
+ def initializer(self):
72
+ global sp
73
+ sp = spm.SentencePieceProcessor(model_file=self.model)
74
+
75
+ def encode(self, line):
76
+ global sp
77
+ line = line.strip()
78
+ if len(line) == 0 and self.remove_empty:
79
+ return None
80
+
81
+ if self.output_format == 'piece':
82
+ return ' '.join(sp.encode_as_pieces(line))
83
+ else:
84
+ return ' '.join(map(str, sp.encode(line)))
85
+
86
+
87
+ def write_lines(lines, path):
88
+ with open(path, mode='x', encoding='utf-8') as f:
89
+ for line in lines:
90
+ print(line, file=f)
91
+
92
+
93
+ def read_jsonl(path):
94
+ with open(path, encoding='utf-8') as f:
95
+ return [json.loads(line) for line in f.read().splitlines()]
96
+
97
+
98
+ def read_nli(path, langs=None):
99
+ data = read_jsonl(path)
100
+
101
+ if langs is not None:
102
+ data = [sample for sample in data if sample.get('language') in langs]
103
+
104
+ lang2count = collections.defaultdict(int)
105
+ for sample in data:
106
+ lang2count[sample.get('language')] += 1
107
+
108
+ if langs:
109
+ assert set(lang2count.keys()) == set(langs)
110
+
111
+ nlangs = len(lang2count)
112
+ assert nlangs > 0
113
+ lens = list(lang2count.values())
114
+ assert all([lens[0] == length for length in lens])
115
+
116
+ print(f'Loaded {lens[0]} samples in {nlangs} languages from {path}', file=sys.stderr)
117
+ return data
118
+
119
+
120
+ def main():
121
+ parser = argparse.ArgumentParser(description='Tokenize and binarize NLI data')
122
+ parser.add_argument('--sentencepiece-model', required=True)
123
+ parser.add_argument('--train', required=True, help='Training data in jsonl format')
124
+ parser.add_argument('--valid', required=True, help='Validation data in jsonl format')
125
+ parser.add_argument('--destdir', required=True)
126
+
127
+ args = parser.parse_args()
128
+
129
+ os.makedirs(args.destdir + '/raw',)
130
+ os.makedirs(args.destdir + '/bin', )
131
+
132
+ # Extract input/labels
133
+ for split, path in ('train', args.train), ('valid', args.valid):
134
+ data = read_nli(path, langs=None)
135
+ original_size = len(data)
136
+ data = [sample for sample in data if sample['gold_label'] != '-']
137
+ assert all(sample['gold_label'] in ('contradiction', 'entailment', 'neutral') for sample in data)
138
+ filtered_size = len(data)
139
+ if filtered_size != original_size:
140
+ print(f'Filtered {filtered_size}/{original_size} samples from {path}', file=sys.stderr)
141
+ for name, field in ('input0', 'sentence1'), ('input1', 'sentence2'), ('label', 'gold_label'):
142
+ write_lines([sample[field] for sample in data], f'{args.destdir}/raw/{split}.{name}.txt')
143
+
144
+ # Tokenize and binarize input
145
+ for field in 'input0', 'input1':
146
+ preprocess(
147
+ spm_model_path=args.sentencepiece_model,
148
+ train_path=f'{args.destdir}/raw/train.{field}.txt',
149
+ valid_path=f'{args.destdir}/raw/valid.{field}.txt',
150
+ test_path=None,
151
+ dest_dir=f'{args.destdir}/bin/{field}',
152
+ workers=20,
153
+ )
154
+
155
+ # Binarize labels
156
+ subprocess.run([
157
+ 'python3', '-m', 'fairseq_cli.preprocess',
158
+ '--trainpref', f'{args.destdir}/raw/train.label.txt',
159
+ '--validpref', f'{args.destdir}/raw/valid.label.txt',
160
+ '--only-source',
161
+ '--thresholdsrc', '0',
162
+ '--destdir', f'{args.destdir}/bin/label',
163
+ '--workers', '20',
164
+ ])
165
+
166
+
167
+ if __name__ == '__main__':
168
+ main()
omni_speech/infer/fairseq/fairseq/__init__.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+ """isort:skip_file"""
6
+
7
+ import os
8
+ import sys
9
+
10
+ try:
11
+ from .version import __version__ # noqa
12
+ except ImportError:
13
+ version_txt = os.path.join(os.path.dirname(__file__), "version.txt")
14
+ with open(version_txt) as f:
15
+ __version__ = f.read().strip()
16
+
17
+ __all__ = ["pdb"]
18
+
19
+ # backwards compatibility to support `from fairseq.X import Y`
20
+ from fairseq.distributed import utils as distributed_utils
21
+ from fairseq.logging import meters, metrics, progress_bar # noqa
22
+
23
+ sys.modules["fairseq.distributed_utils"] = distributed_utils
24
+ sys.modules["fairseq.meters"] = meters
25
+ sys.modules["fairseq.metrics"] = metrics
26
+ sys.modules["fairseq.progress_bar"] = progress_bar
27
+
28
+ # initialize hydra
29
+ from fairseq.dataclass.initialize import hydra_init
30
+
31
+ hydra_init()
32
+
33
+ import fairseq.criterions # noqa
34
+ import fairseq.distributed # noqa
35
+ import fairseq.models # noqa
36
+ import fairseq.modules # noqa
37
+ import fairseq.optim # noqa
38
+ import fairseq.optim.lr_scheduler # noqa
39
+ import fairseq.pdb # noqa
40
+ import fairseq.scoring # noqa
41
+ import fairseq.tasks # noqa
42
+ import fairseq.token_generation_constraints # noqa
43
+
44
+ import fairseq.benchmark # noqa
45
+ import fairseq.model_parallel # noqa
omni_speech/infer/fairseq/fairseq/benchmark/__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ # import models/tasks to register them
7
+ from . import dummy_dataset, dummy_lm, dummy_masked_lm, dummy_model, dummy_mt # noqa
omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (314 Bytes). View file
 
omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_dataset.cpython-312.pyc ADDED
Binary file (2.2 kB). View file
 
omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_lm.cpython-312.pyc ADDED
Binary file (4.72 kB). View file
 
omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_masked_lm.cpython-312.pyc ADDED
Binary file (5.1 kB). View file
 
omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_model.cpython-312.pyc ADDED
Binary file (5 kB). View file
 
omni_speech/infer/fairseq/fairseq/benchmark/__pycache__/dummy_mt.cpython-312.pyc ADDED
Binary file (6.88 kB). View file
 
omni_speech/infer/fairseq/fairseq/benchmark/benchmark_multihead_attention.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import itertools
7
+ import random
8
+
9
+ import torch
10
+ from torch.utils import benchmark
11
+
12
+ from fairseq.modules.multihead_attention import MultiheadAttention
13
+
14
+ BATCH = [20, 41, 97]
15
+ SEQ = 64
16
+ EMB = 48
17
+ HEADS = 4
18
+ DROP = 0.1
19
+ DEVICE = torch.device("cuda")
20
+ ATTN_MASK_DTYPE = [torch.uint8, torch.bool, torch.float]
21
+ KEY_PADDING_MASK_DTYPE = [torch.uint8, torch.bool]
22
+
23
+
24
+ def _reset_seeds():
25
+ torch.manual_seed(0)
26
+ random.seed(0)
27
+
28
+
29
+ def _get_mask(to_dtype: torch.dtype, dim0: int, dim1: int):
30
+ if to_dtype == torch.float:
31
+ mask = torch.randint(0, 2, (dim0, dim1)).to(dtype=torch.bool)
32
+ return mask.to(dtype=to_dtype).masked_fill(mask, -float("inf"))
33
+ return torch.randint(0, 2, (dim0, dim1)).to(dtype=to_dtype)
34
+
35
+
36
+ def benchmark_multihead_attention(
37
+ label="",
38
+ attn_dtype=torch.uint8,
39
+ key_padding_dtype=torch.uint8,
40
+ add_bias_kv=False,
41
+ add_zero_attn=False,
42
+ static_kv=False,
43
+ batch_size=20,
44
+ embedding=EMB,
45
+ seq_len=SEQ,
46
+ num_heads=HEADS,
47
+ ):
48
+
49
+ results = []
50
+ # device = torch.device("cuda")
51
+
52
+ xformers_att_config = '{"name": "scaled_dot_product"}'
53
+
54
+ attn_mask = _get_mask(to_dtype=attn_dtype, dim0=seq_len, dim1=seq_len)
55
+ key_padding_mask = _get_mask(
56
+ to_dtype=key_padding_dtype, dim0=batch_size, dim1=seq_len
57
+ )
58
+
59
+ q = torch.rand(seq_len, batch_size, embedding, requires_grad=True)
60
+ k = torch.rand(seq_len, batch_size, embedding, requires_grad=True)
61
+ v = torch.rand(seq_len, batch_size, embedding, requires_grad=True)
62
+
63
+ _reset_seeds()
64
+
65
+ original_mha = MultiheadAttention(
66
+ embedding,
67
+ num_heads,
68
+ dropout=0.0,
69
+ xformers_att_config=None,
70
+ add_bias_kv=add_bias_kv,
71
+ add_zero_attn=add_zero_attn,
72
+ )
73
+
74
+ xformers_mha = MultiheadAttention(
75
+ embedding,
76
+ num_heads,
77
+ dropout=0.0,
78
+ xformers_att_config=xformers_att_config,
79
+ add_bias_kv=add_bias_kv,
80
+ add_zero_attn=add_zero_attn,
81
+ )
82
+
83
+ def original_bench_fw(q, k, v, key_padding_mask, attn_mask, static_kv):
84
+ original_mha(
85
+ query=q,
86
+ key=k,
87
+ value=v,
88
+ key_padding_mask=key_padding_mask,
89
+ attn_mask=attn_mask,
90
+ static_kv=static_kv,
91
+ )
92
+
93
+ def xformers_bench_fw(q, k, v, key_padding_mask, attn_mask, static_kv):
94
+ xformers_mha(
95
+ query=q,
96
+ key=k,
97
+ value=v,
98
+ key_padding_mask=key_padding_mask,
99
+ attn_mask=attn_mask,
100
+ static_kv=static_kv,
101
+ )
102
+
103
+ def original_bench_fw_bw(q, k, v, key_padding_mask, attn_mask, static_kv):
104
+ output, _ = original_mha(
105
+ query=q,
106
+ key=k,
107
+ value=v,
108
+ key_padding_mask=key_padding_mask,
109
+ attn_mask=attn_mask,
110
+ static_kv=static_kv,
111
+ )
112
+ loss = torch.norm(output)
113
+ loss.backward()
114
+
115
+ def xformers_bench_fw_bw(q, k, v, key_padding_mask, attn_mask, static_kv):
116
+ output, _ = xformers_mha(
117
+ query=q,
118
+ key=k,
119
+ value=v,
120
+ key_padding_mask=key_padding_mask,
121
+ attn_mask=attn_mask,
122
+ static_kv=static_kv,
123
+ )
124
+ loss = torch.norm(output)
125
+ loss.backward()
126
+
127
+ fns = [
128
+ original_bench_fw,
129
+ xformers_bench_fw,
130
+ original_bench_fw_bw,
131
+ xformers_bench_fw_bw,
132
+ ]
133
+
134
+ for fn in fns:
135
+ results.append(
136
+ benchmark.Timer(
137
+ stmt="fn(q, k, v, key_padding_mask, attn_mask, static_kv)",
138
+ globals={
139
+ "q": q,
140
+ "k": k,
141
+ "v": v,
142
+ "key_padding_mask": key_padding_mask,
143
+ "attn_mask": attn_mask,
144
+ "static_kv": static_kv,
145
+ "fn": fn,
146
+ },
147
+ label="multihead fw + bw",
148
+ sub_label=f"{fn.__name__}",
149
+ description=label,
150
+ ).blocked_autorange(min_run_time=1)
151
+ )
152
+
153
+ compare = benchmark.Compare(results)
154
+ compare.print()
155
+
156
+
157
+ def run_benchmarks():
158
+ for attn_dtype, key_padding_dtype, add_bias_kv, add_zero_attn in itertools.product(
159
+ ATTN_MASK_DTYPE, KEY_PADDING_MASK_DTYPE, [True, False], [True, False]
160
+ ):
161
+ label = f"attn_dtype {attn_dtype}, key_padding_dtype {key_padding_dtype}, \
162
+ add_bias_kv {add_bias_kv}, add_zero_attn {add_zero_attn}"
163
+ benchmark_multihead_attention(
164
+ label=label,
165
+ attn_dtype=attn_dtype,
166
+ key_padding_dtype=key_padding_dtype,
167
+ add_bias_kv=add_bias_kv,
168
+ add_zero_attn=add_zero_attn,
169
+ )
170
+
171
+
172
+ run_benchmarks()
omni_speech/infer/fairseq/fairseq/benchmark/dummy_dataset.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from fairseq.data import FairseqDataset
3
+
4
+
5
+ class DummyDataset(FairseqDataset):
6
+ def __init__(self, batch, num_items, item_size):
7
+ super().__init__()
8
+ self.batch = batch
9
+ self.num_items = num_items
10
+ self.item_size = item_size
11
+
12
+ def __getitem__(self, index):
13
+ return index
14
+
15
+ def __len__(self):
16
+ return self.num_items
17
+
18
+ def collater(self, samples):
19
+ return self.batch
20
+
21
+ @property
22
+ def sizes(self):
23
+ return np.array([self.item_size] * self.num_items)
24
+
25
+ def num_tokens(self, index):
26
+ return self.item_size
27
+
28
+ def size(self, index):
29
+ return self.item_size
30
+
31
+ def ordered_indices(self):
32
+ return np.arange(self.num_items)
33
+
34
+ @property
35
+ def supports_prefetch(self):
36
+ return False
omni_speech/infer/fairseq/fairseq/benchmark/dummy_lm.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+ from dataclasses import dataclass, field
8
+ from typing import Optional
9
+
10
+ import torch
11
+ from .dummy_dataset import DummyDataset
12
+ from fairseq.data import Dictionary
13
+ from fairseq.dataclass import FairseqDataclass
14
+ from fairseq.tasks import FairseqTask, register_task
15
+ from omegaconf import II
16
+
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @dataclass
22
+ class DummyLMConfig(FairseqDataclass):
23
+ dict_size: int = 49996
24
+ dataset_size: int = 100000
25
+ tokens_per_sample: int = field(
26
+ default=512, metadata={"help": "max sequence length"}
27
+ )
28
+ add_bos_token: bool = False
29
+ batch_size: Optional[int] = II("dataset.batch_size")
30
+ max_tokens: Optional[int] = II("dataset.max_tokens")
31
+ max_target_positions: int = II("task.tokens_per_sample")
32
+
33
+
34
+ @register_task("dummy_lm", dataclass=DummyLMConfig)
35
+ class DummyLMTask(FairseqTask):
36
+ def __init__(self, cfg: DummyLMConfig):
37
+ super().__init__(cfg)
38
+
39
+ # load dictionary
40
+ self.dictionary = Dictionary()
41
+ for i in range(cfg.dict_size):
42
+ self.dictionary.add_symbol("word{}".format(i))
43
+ self.dictionary.pad_to_multiple_(8) # often faster if divisible by 8
44
+ logger.info("dictionary: {} types".format(len(self.dictionary)))
45
+
46
+ seq = torch.arange(cfg.tokens_per_sample + 1) + self.dictionary.pad() + 1
47
+
48
+ self.dummy_src = seq[:-1]
49
+ self.dummy_tgt = seq[1:]
50
+
51
+ def load_dataset(self, split, epoch=1, combine=False, **kwargs):
52
+ """Load a given dataset split.
53
+ Args:
54
+ split (str): name of the split (e.g., train, valid, test)
55
+ """
56
+ if self.cfg.batch_size is not None:
57
+ bsz = self.cfg.batch_size
58
+ else:
59
+ bsz = max(1, self.cfg.max_tokens // self.cfg.tokens_per_sample)
60
+ self.datasets[split] = DummyDataset(
61
+ {
62
+ "id": 1,
63
+ "net_input": {
64
+ "src_tokens": torch.stack([self.dummy_src for _ in range(bsz)]),
65
+ "src_lengths": torch.full(
66
+ (bsz,), self.cfg.tokens_per_sample, dtype=torch.long
67
+ ),
68
+ },
69
+ "target": torch.stack([self.dummy_tgt for _ in range(bsz)]),
70
+ "nsentences": bsz,
71
+ "ntokens": bsz * self.cfg.tokens_per_sample,
72
+ },
73
+ num_items=self.cfg.dataset_size,
74
+ item_size=self.cfg.tokens_per_sample,
75
+ )
76
+
77
+ @property
78
+ def source_dictionary(self):
79
+ return self.dictionary
80
+
81
+ @property
82
+ def target_dictionary(self):
83
+ return self.dictionary
omni_speech/infer/fairseq/fairseq/benchmark/dummy_masked_lm.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+ from dataclasses import dataclass, field
8
+ from typing import Optional
9
+
10
+ import torch
11
+ from omegaconf import II
12
+
13
+ from .dummy_dataset import DummyDataset
14
+ from fairseq.data import Dictionary
15
+ from fairseq.dataclass import FairseqDataclass
16
+ from fairseq.tasks import FairseqTask, register_task
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @dataclass
22
+ class DummyMaskedLMConfig(FairseqDataclass):
23
+ dict_size: int = 49996
24
+ dataset_size: int = 100000
25
+ tokens_per_sample: int = field(
26
+ default=512,
27
+ metadata={
28
+ "help": "max number of total tokens over all"
29
+ " segments per sample for BERT dataset"
30
+ },
31
+ )
32
+ batch_size: Optional[int] = II("dataset.batch_size")
33
+ max_tokens: Optional[int] = II("dataset.max_tokens")
34
+ max_target_positions: int = II("task.tokens_per_sample")
35
+
36
+
37
+ @register_task("dummy_masked_lm", dataclass=DummyMaskedLMConfig)
38
+ class DummyMaskedLMTask(FairseqTask):
39
+ def __init__(self, cfg: DummyMaskedLMConfig):
40
+ super().__init__(cfg)
41
+
42
+ self.dictionary = Dictionary()
43
+ for i in range(cfg.dict_size):
44
+ self.dictionary.add_symbol("word{}".format(i))
45
+ logger.info("dictionary: {} types".format(len(self.dictionary)))
46
+ # add mask token
47
+ self.mask_idx = self.dictionary.add_symbol("<mask>")
48
+ self.dictionary.pad_to_multiple_(8) # often faster if divisible by 8
49
+
50
+ mask_idx = 0
51
+ pad_idx = 1
52
+ seq = torch.arange(cfg.tokens_per_sample) + pad_idx + 1
53
+ mask = torch.arange(2, cfg.tokens_per_sample, 7) # ~15%
54
+ src = seq.clone()
55
+ src[mask] = mask_idx
56
+ tgt = torch.full_like(seq, pad_idx)
57
+ tgt[mask] = seq[mask]
58
+
59
+ self.dummy_src = src
60
+ self.dummy_tgt = tgt
61
+
62
+ def load_dataset(self, split, epoch=1, combine=False, **kwargs):
63
+ """Load a given dataset split.
64
+ Args:
65
+ split (str): name of the split (e.g., train, valid, test)
66
+ """
67
+ if self.cfg.batch_size is not None:
68
+ bsz = self.cfg.batch_size
69
+ else:
70
+ bsz = max(1, self.cfg.max_tokens // self.cfg.tokens_per_sample)
71
+ self.datasets[split] = DummyDataset(
72
+ {
73
+ "id": 1,
74
+ "net_input": {
75
+ "src_tokens": torch.stack([self.dummy_src for _ in range(bsz)]),
76
+ "src_lengths": torch.full(
77
+ (bsz,), self.cfg.tokens_per_sample, dtype=torch.long
78
+ ),
79
+ },
80
+ "target": torch.stack([self.dummy_tgt for _ in range(bsz)]),
81
+ "nsentences": bsz,
82
+ "ntokens": bsz * self.cfg.tokens_per_sample,
83
+ },
84
+ num_items=self.cfg.dataset_size,
85
+ item_size=self.cfg.tokens_per_sample,
86
+ )
87
+
88
+ @property
89
+ def source_dictionary(self):
90
+ return self.dictionary
91
+
92
+ @property
93
+ def target_dictionary(self):
94
+ return self.dictionary
omni_speech/infer/fairseq/fairseq/benchmark/dummy_model.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from fairseq.data import Dictionary
9
+ from fairseq.models import (
10
+ FairseqDecoder,
11
+ FairseqLanguageModel,
12
+ register_model,
13
+ register_model_architecture,
14
+ )
15
+
16
+
17
+ @register_model("dummy_model")
18
+ class DummyModel(FairseqLanguageModel):
19
+ def __init__(self, args, encoder):
20
+ super().__init__(encoder)
21
+ self.args = args
22
+
23
+ @staticmethod
24
+ def add_args(parser):
25
+ parser.add_argument("--num-layers", type=int, default=24)
26
+ parser.add_argument("--embed-dim", type=int, default=1024)
27
+
28
+ @classmethod
29
+ def build_model(cls, args, task):
30
+ encoder = DummyEncoder(
31
+ num_embed=len(task.target_dictionary),
32
+ embed_dim=args.embed_dim,
33
+ num_layers=args.num_layers,
34
+ )
35
+ return cls(args, encoder)
36
+
37
+ def forward(self, src_tokens, masked_tokens=None, **kwargs):
38
+ return self.decoder(src_tokens, masked_tokens=masked_tokens)
39
+
40
+
41
+ class DummyEncoder(FairseqDecoder):
42
+ def __init__(self, num_embed=50000, embed_dim=1024, num_layers=24):
43
+ super().__init__(Dictionary())
44
+ self.embed = nn.Embedding(
45
+ num_embeddings=num_embed, embedding_dim=embed_dim, padding_idx=0
46
+ )
47
+ self.layers_a = nn.ModuleList(
48
+ [
49
+ nn.Sequential(
50
+ nn.LayerNorm(embed_dim),
51
+ nn.Linear(embed_dim, 3 * embed_dim), # q, k, v input projection
52
+ nn.Linear(3 * embed_dim, embed_dim), # skip self-attention
53
+ nn.Linear(embed_dim, embed_dim), # output projection
54
+ nn.Dropout(),
55
+ )
56
+ for i in range(num_layers)
57
+ ]
58
+ )
59
+ self.layers_b = nn.ModuleList(
60
+ [
61
+ nn.Sequential(
62
+ nn.LayerNorm(embed_dim),
63
+ nn.Linear(embed_dim, 4 * embed_dim), # FFN
64
+ nn.ReLU(),
65
+ nn.Linear(4 * embed_dim, embed_dim), # FFN
66
+ nn.Dropout(0.1),
67
+ )
68
+ for i in range(num_layers)
69
+ ]
70
+ )
71
+ self.out_proj = nn.Linear(embed_dim, num_embed)
72
+
73
+ def forward(self, tokens, masked_tokens=None):
74
+ x = self.embed(tokens)
75
+ for layer_a, layer_b in zip(self.layers_a, self.layers_b):
76
+ x = x + layer_a(x)
77
+ x = x + layer_b(x)
78
+ x = self.out_proj(x)
79
+ if masked_tokens is not None:
80
+ x = x[masked_tokens]
81
+ return (x,)
82
+
83
+ def max_positions(self):
84
+ return 1024
85
+
86
+ def get_normalized_probs(self, net_output, log_probs, sample=None):
87
+ logits = net_output[0].float()
88
+ if log_probs:
89
+ return F.log_softmax(logits, dim=-1)
90
+ else:
91
+ return F.softmax(logits, dim=-1)
92
+
93
+
94
+ @register_model_architecture("dummy_model", "dummy_model")
95
+ def base_architecture(args):
96
+ pass
omni_speech/infer/fairseq/fairseq/benchmark/dummy_mt.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+
8
+ import numpy as np
9
+ import torch
10
+
11
+ from fairseq.data import Dictionary, FairseqDataset
12
+ from fairseq.tasks import LegacyFairseqTask, register_task
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @register_task("dummy_mt")
18
+ class DummyMTTask(LegacyFairseqTask):
19
+ @staticmethod
20
+ def add_args(parser):
21
+ """Add task-specific arguments to the parser."""
22
+ parser.add_argument("--dict-size", default=49996, type=int)
23
+ parser.add_argument("--dataset-size", default=100000, type=int)
24
+ parser.add_argument("--src-len", default=30, type=int)
25
+ parser.add_argument("--tgt-len", default=30, type=int)
26
+
27
+ def __init__(self, args, dictionary):
28
+ super().__init__(args)
29
+ self.dictionary = dictionary
30
+ self.seed = args.seed
31
+
32
+ dictionary.pad_to_multiple_(8) # often faster if divisible by 8
33
+
34
+ self.dummy_src = torch.arange(args.src_len + 1) + dictionary.pad() + 1
35
+ self.dummy_tgt = torch.arange(args.tgt_len + 1) + dictionary.pad() + 1
36
+
37
+ @classmethod
38
+ def setup_task(cls, args, **kwargs):
39
+ """Setup the task."""
40
+ dictionary = Dictionary()
41
+ for i in range(args.dict_size):
42
+ dictionary.add_symbol("word{}".format(i))
43
+ logger.info("dictionary: {} types".format(len(dictionary)))
44
+
45
+ args.max_source_positions = args.src_len + dictionary.pad() + 2
46
+ args.max_target_positions = args.tgt_len + dictionary.pad() + 2
47
+
48
+ return cls(args, dictionary)
49
+
50
+ def load_dataset(self, split, epoch=1, combine=False, **kwargs):
51
+ """Load a given dataset split.
52
+ Args:
53
+ split (str): name of the split (e.g., train, valid, test)
54
+ """
55
+ item_size = max(self.args.src_len, self.args.tgt_len)
56
+ if self.args.batch_size is not None:
57
+ bsz = self.args.batch_size
58
+ else:
59
+ bsz = max(1, self.args.max_tokens // item_size)
60
+ tgt = torch.stack([self.dummy_tgt for _ in range(bsz)])
61
+ self.datasets[split] = DummyDataset(
62
+ {
63
+ "id": 1,
64
+ "net_input": {
65
+ "src_tokens": torch.stack([self.dummy_src for _ in range(bsz)]),
66
+ "src_lengths": torch.full(
67
+ (bsz,), self.args.src_len, dtype=torch.long
68
+ ),
69
+ "prev_output_tokens": tgt.clone(),
70
+ },
71
+ "target": tgt,
72
+ "nsentences": bsz,
73
+ "ntokens": bsz * self.args.tgt_len,
74
+ },
75
+ num_items=self.args.dataset_size,
76
+ item_size=item_size,
77
+ )
78
+
79
+ @property
80
+ def source_dictionary(self):
81
+ return self.dictionary
82
+
83
+ @property
84
+ def target_dictionary(self):
85
+ return self.dictionary
86
+
87
+
88
+ class DummyDataset(FairseqDataset):
89
+ def __init__(self, batch, num_items, item_size):
90
+ super().__init__()
91
+ self.batch = batch
92
+ self.num_items = num_items
93
+ self.item_size = item_size
94
+
95
+ def __getitem__(self, index):
96
+ return index
97
+
98
+ def __len__(self):
99
+ return self.num_items
100
+
101
+ def collater(self, samples):
102
+ return self.batch
103
+
104
+ @property
105
+ def sizes(self):
106
+ return np.array([self.item_size] * self.num_items)
107
+
108
+ def num_tokens(self, index):
109
+ return self.item_size
110
+
111
+ def size(self, index):
112
+ return self.item_size
113
+
114
+ def ordered_indices(self):
115
+ return np.arange(self.num_items)
116
+
117
+ @property
118
+ def supports_prefetch(self):
119
+ return False
omni_speech/infer/fairseq/fairseq/binarizer.py ADDED
@@ -0,0 +1,381 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+ import os
8
+ import typing as tp
9
+ from abc import ABC, abstractmethod
10
+ from collections import Counter
11
+ from dataclasses import dataclass
12
+ from multiprocessing import Pool
13
+
14
+ import torch
15
+
16
+ from fairseq.data import Dictionary, indexed_dataset
17
+ from fairseq.file_chunker_utils import Chunker, find_offsets
18
+ from fairseq.file_io import PathManager
19
+ from fairseq.tokenizer import tokenize_line
20
+
21
+ logger = logging.getLogger("binarizer")
22
+
23
+
24
+ @dataclass
25
+ class BinarizeSummary:
26
+ """
27
+ Keep track of what's going on in the binarizer
28
+ """
29
+
30
+ num_seq: int = 0
31
+ replaced: tp.Optional[Counter] = None
32
+ num_tok: int = 0
33
+
34
+ @property
35
+ def num_replaced(self) -> int:
36
+ if self.replaced is None:
37
+ return 0
38
+ return sum(self.replaced.values())
39
+
40
+ @property
41
+ def replaced_percent(self) -> float:
42
+ return 100 * self.num_replaced / self.num_tok
43
+
44
+ def __str__(self) -> str:
45
+ base = f"{self.num_seq} sents, {self.num_tok} tokens"
46
+ if self.replaced is None:
47
+ return base
48
+
49
+ return f"{base}, {self.replaced_percent:.3}% replaced"
50
+
51
+ def merge(self, other: "BinarizeSummary"):
52
+ replaced = None
53
+ if self.replaced is not None:
54
+ replaced = self.replaced
55
+ if other.replaced is not None:
56
+ if replaced is None:
57
+ replaced = other.replaced
58
+ else:
59
+ replaced += other.replaced
60
+ self.replaced = replaced
61
+ self.num_seq += other.num_seq
62
+ self.num_tok += other.num_tok
63
+
64
+
65
+ class Binarizer(ABC):
66
+ """
67
+ a binarizer describes how to take a string and build a tensor out of it
68
+ """
69
+
70
+ @abstractmethod
71
+ def binarize_line(
72
+ self,
73
+ line: str,
74
+ summary: BinarizeSummary,
75
+ ) -> torch.IntTensor:
76
+ ...
77
+
78
+
79
+ def _worker_prefix(output_prefix: str, worker_id: int):
80
+ return f"{output_prefix}.pt{worker_id}"
81
+
82
+
83
+ class FileBinarizer:
84
+ """
85
+ An file binarizer can take a file, tokenize it, and binarize each line to a tensor
86
+ """
87
+
88
+ @classmethod
89
+ def multiprocess_dataset(
90
+ cls,
91
+ input_file: str,
92
+ dataset_impl: str,
93
+ binarizer: Binarizer,
94
+ output_prefix: str,
95
+ vocab_size=None,
96
+ num_workers=1,
97
+ ) -> BinarizeSummary:
98
+ final_summary = BinarizeSummary()
99
+
100
+ offsets = find_offsets(input_file, num_workers)
101
+ # find_offsets returns a list of position [pos1, pos2, pos3, pos4] but we would want pairs:
102
+ # [(pos1, pos2), (pos2, pos3), (pos3, pos4)] to process the chunks with start/end info
103
+ # we zip the list with itself shifted by one to get all the pairs.
104
+ (first_chunk, *more_chunks) = zip(offsets, offsets[1:])
105
+ pool = None
106
+ if num_workers > 1:
107
+ pool = Pool(processes=num_workers - 1)
108
+ worker_results = [
109
+ pool.apply_async(
110
+ cls._binarize_chunk_and_finalize,
111
+ args=(
112
+ binarizer,
113
+ input_file,
114
+ start_offset,
115
+ end_offset,
116
+ _worker_prefix(
117
+ output_prefix,
118
+ worker_id,
119
+ ),
120
+ dataset_impl,
121
+ ),
122
+ kwds={
123
+ "vocab_size": vocab_size,
124
+ }
125
+ if vocab_size is not None
126
+ else {},
127
+ )
128
+ for worker_id, (start_offset, end_offset) in enumerate(
129
+ more_chunks, start=1
130
+ )
131
+ ]
132
+
133
+ pool.close()
134
+ pool.join()
135
+ for r in worker_results:
136
+ summ = r.get()
137
+ final_summary.merge(summ)
138
+
139
+ # do not close the bin file as we need to merge the worker results in
140
+ final_ds, summ = cls._binarize_file_chunk(
141
+ binarizer,
142
+ input_file,
143
+ offset_start=first_chunk[0],
144
+ offset_end=first_chunk[1],
145
+ output_prefix=output_prefix,
146
+ dataset_impl=dataset_impl,
147
+ vocab_size=vocab_size if vocab_size is not None else None,
148
+ )
149
+ final_summary.merge(summ)
150
+
151
+ if num_workers > 1:
152
+ for worker_id in range(1, num_workers):
153
+ # merge the worker outputs
154
+ worker_output_prefix = _worker_prefix(
155
+ output_prefix,
156
+ worker_id,
157
+ )
158
+ final_ds.merge_file_(worker_output_prefix)
159
+ try:
160
+ os.remove(indexed_dataset.data_file_path(worker_output_prefix))
161
+ os.remove(indexed_dataset.index_file_path(worker_output_prefix))
162
+ except Exception as e:
163
+ logger.error(
164
+ f"couldn't remove {worker_output_prefix}.*", exc_info=e
165
+ )
166
+
167
+ # now we can close the file
168
+ idx_file = indexed_dataset.index_file_path(output_prefix)
169
+ final_ds.finalize(idx_file)
170
+ return final_summary
171
+
172
+ @staticmethod
173
+ def _binarize_file_chunk(
174
+ binarizer: Binarizer,
175
+ filename: str,
176
+ offset_start: int,
177
+ offset_end: int,
178
+ output_prefix: str,
179
+ dataset_impl: str,
180
+ vocab_size=None,
181
+ ) -> tp.Tuple[tp.Any, BinarizeSummary]: # (dataset builder, BinarizeSummary)
182
+ """
183
+ creates a dataset builder and append binarized items to it. This function does not
184
+ finalize the builder, this is useful if you want to do other things with your bin file
185
+ like appending/merging other files
186
+ """
187
+ bin_file = indexed_dataset.data_file_path(output_prefix)
188
+ ds = indexed_dataset.make_builder(
189
+ bin_file,
190
+ impl=dataset_impl,
191
+ vocab_size=vocab_size,
192
+ )
193
+ summary = BinarizeSummary()
194
+
195
+ with Chunker(
196
+ PathManager.get_local_path(filename), offset_start, offset_end
197
+ ) as line_iterator:
198
+ for line in line_iterator:
199
+ ds.add_item(binarizer.binarize_line(line, summary))
200
+
201
+ return ds, summary
202
+
203
+ @classmethod
204
+ def _binarize_chunk_and_finalize(
205
+ cls,
206
+ binarizer: Binarizer,
207
+ filename: str,
208
+ offset_start: int,
209
+ offset_end: int,
210
+ output_prefix: str,
211
+ dataset_impl: str,
212
+ vocab_size=None,
213
+ ):
214
+ """
215
+ same as above, but also finalizes the builder
216
+ """
217
+ ds, summ = cls._binarize_file_chunk(
218
+ binarizer,
219
+ filename,
220
+ offset_start,
221
+ offset_end,
222
+ output_prefix,
223
+ dataset_impl,
224
+ vocab_size=vocab_size,
225
+ )
226
+
227
+ idx_file = indexed_dataset.index_file_path(output_prefix)
228
+ ds.finalize(idx_file)
229
+
230
+ return summ
231
+
232
+
233
+ class VocabularyDatasetBinarizer(Binarizer):
234
+ """
235
+ Takes a Dictionary/Vocabulary, assign ids to each
236
+ token using the dictionary encode_line function.
237
+ """
238
+
239
+ def __init__(
240
+ self,
241
+ dict: Dictionary,
242
+ tokenize: tp.Callable[[str], tp.List[str]] = tokenize_line,
243
+ append_eos: bool = True,
244
+ reverse_order: bool = False,
245
+ already_numberized: bool = False,
246
+ ) -> None:
247
+ self.dict = dict
248
+ self.tokenize = tokenize
249
+ self.append_eos = append_eos
250
+ self.reverse_order = reverse_order
251
+ self.already_numberized = already_numberized
252
+ super().__init__()
253
+
254
+ def binarize_line(
255
+ self,
256
+ line: str,
257
+ summary: BinarizeSummary,
258
+ ):
259
+ if summary.replaced is None:
260
+ summary.replaced = Counter()
261
+
262
+ def replaced_consumer(word, idx):
263
+ if idx == self.dict.unk_index and word != self.dict.unk_word:
264
+ summary.replaced.update([word])
265
+
266
+ if self.already_numberized:
267
+ id_strings = line.strip().split()
268
+ id_list = [int(id_string) for id_string in id_strings]
269
+ if self.reverse_order:
270
+ id_list.reverse()
271
+ if self.append_eos:
272
+ id_list.append(self.dict.eos())
273
+ ids = torch.IntTensor(id_list)
274
+ else:
275
+ ids = self.dict.encode_line(
276
+ line=line,
277
+ line_tokenizer=self.tokenize,
278
+ add_if_not_exist=False,
279
+ consumer=replaced_consumer,
280
+ append_eos=self.append_eos,
281
+ reverse_order=self.reverse_order,
282
+ )
283
+
284
+ summary.num_seq += 1
285
+ summary.num_tok += len(ids)
286
+ return ids
287
+
288
+
289
+ class AlignmentDatasetBinarizer(Binarizer):
290
+ """
291
+ binarize by parsing a set of alignments and packing
292
+ them in a tensor (see utils.parse_alignment)
293
+ """
294
+
295
+ def __init__(
296
+ self,
297
+ alignment_parser: tp.Callable[[str], torch.IntTensor],
298
+ ) -> None:
299
+ super().__init__()
300
+ self.alignment_parser = alignment_parser
301
+
302
+ def binarize_line(
303
+ self,
304
+ line: str,
305
+ summary: BinarizeSummary,
306
+ ):
307
+ ids = self.alignment_parser(line)
308
+ summary.num_seq += 1
309
+ summary.num_tok += len(ids)
310
+ return ids
311
+
312
+
313
+ class LegacyBinarizer:
314
+ @classmethod
315
+ def binarize(
316
+ cls,
317
+ filename: str,
318
+ dico: Dictionary,
319
+ consumer: tp.Callable[[torch.IntTensor], None],
320
+ tokenize: tp.Callable[[str], tp.List[str]] = tokenize_line,
321
+ append_eos: bool = True,
322
+ reverse_order: bool = False,
323
+ offset: int = 0,
324
+ end: int = -1,
325
+ already_numberized: bool = False,
326
+ ) -> tp.Dict[str, int]:
327
+ binarizer = VocabularyDatasetBinarizer(
328
+ dict=dico,
329
+ tokenize=tokenize,
330
+ append_eos=append_eos,
331
+ reverse_order=reverse_order,
332
+ already_numberized=already_numberized,
333
+ )
334
+ return cls._consume_file(
335
+ filename,
336
+ binarizer,
337
+ consumer,
338
+ offset_start=offset,
339
+ offset_end=end,
340
+ )
341
+
342
+ @classmethod
343
+ def binarize_alignments(
344
+ cls,
345
+ filename: str,
346
+ alignment_parser: tp.Callable[[str], torch.IntTensor],
347
+ consumer: tp.Callable[[torch.IntTensor], None],
348
+ offset: int = 0,
349
+ end: int = -1,
350
+ ) -> tp.Dict[str, int]:
351
+ binarizer = AlignmentDatasetBinarizer(alignment_parser)
352
+ return cls._consume_file(
353
+ filename,
354
+ binarizer,
355
+ consumer,
356
+ offset_start=offset,
357
+ offset_end=end,
358
+ )
359
+
360
+ @staticmethod
361
+ def _consume_file(
362
+ filename: str,
363
+ binarizer: Binarizer,
364
+ consumer: tp.Callable[[torch.IntTensor], None],
365
+ offset_start: int,
366
+ offset_end: int,
367
+ ) -> tp.Dict[str, int]:
368
+ summary = BinarizeSummary()
369
+
370
+ with Chunker(
371
+ PathManager.get_local_path(filename), offset_start, offset_end
372
+ ) as line_iterator:
373
+ for line in line_iterator:
374
+ consumer(binarizer.binarize_line(line, summary))
375
+
376
+ return {
377
+ "nseq": summary.num_seq,
378
+ "nunk": summary.num_replaced,
379
+ "ntok": summary.num_tok,
380
+ "replaced": summary.replaced,
381
+ }
omni_speech/infer/fairseq/fairseq/checkpoint_utils.py ADDED
@@ -0,0 +1,918 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import ast
7
+ import collections
8
+ import contextlib
9
+ import inspect
10
+ import logging
11
+ import os
12
+ import re
13
+ import time
14
+ import traceback
15
+ from collections import OrderedDict
16
+ from pathlib import Path
17
+ from typing import Any, Dict, Optional, Union
18
+
19
+ import numpy as np
20
+ import torch
21
+ from fairseq.data import data_utils
22
+ from fairseq.dataclass.configs import CheckpointConfig
23
+ from fairseq.dataclass.utils import (
24
+ convert_namespace_to_omegaconf,
25
+ overwrite_args_by_name,
26
+ )
27
+ from fairseq.distributed.fully_sharded_data_parallel import FSDP, has_FSDP
28
+ from fairseq.file_io import PathManager
29
+ from fairseq.models import FairseqDecoder, FairseqEncoder
30
+ from omegaconf import DictConfig, OmegaConf, open_dict
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss):
36
+ from fairseq import meters
37
+
38
+ # only one worker should attempt to create the required dir
39
+ if trainer.data_parallel_rank == 0:
40
+ os.makedirs(cfg.save_dir, exist_ok=True)
41
+
42
+ prev_best = getattr(save_checkpoint, "best", val_loss)
43
+ if val_loss is not None:
44
+ best_function = max if cfg.maximize_best_checkpoint_metric else min
45
+ save_checkpoint.best = best_function(val_loss, prev_best)
46
+
47
+ if cfg.no_save:
48
+ return None
49
+
50
+ trainer.consolidate_optimizer() # TODO(SS): do we need this if no_save_optimizer_state
51
+
52
+ if not trainer.should_save_checkpoint_on_current_rank:
53
+ if trainer.always_call_state_dict_during_save_checkpoint:
54
+ trainer.state_dict()
55
+ return None
56
+
57
+ write_timer = meters.StopwatchMeter()
58
+ write_timer.start()
59
+
60
+ epoch = epoch_itr.epoch
61
+ end_of_epoch = epoch_itr.end_of_epoch()
62
+ updates = trainer.get_num_updates()
63
+
64
+ logger.info(f"Preparing to save checkpoint for epoch {epoch} @ {updates} updates")
65
+
66
+ def is_better(a, b):
67
+ return a >= b if cfg.maximize_best_checkpoint_metric else a <= b
68
+
69
+ suffix = trainer.checkpoint_suffix
70
+ checkpoint_conds = collections.OrderedDict()
71
+ checkpoint_conds["checkpoint{}{}.pt".format(epoch, suffix)] = (
72
+ end_of_epoch and not cfg.no_epoch_checkpoints and epoch % cfg.save_interval == 0
73
+ )
74
+ checkpoint_conds["checkpoint_{}_{}{}.pt".format(epoch, updates, suffix)] = (
75
+ not end_of_epoch
76
+ and cfg.save_interval_updates > 0
77
+ and updates % cfg.save_interval_updates == 0
78
+ )
79
+ checkpoint_conds["checkpoint_best{}.pt".format(suffix)] = val_loss is not None and (
80
+ not hasattr(save_checkpoint, "best")
81
+ or is_better(val_loss, save_checkpoint.best)
82
+ )
83
+ if val_loss is not None and cfg.keep_best_checkpoints > 0:
84
+ worst_best = getattr(save_checkpoint, "best", None)
85
+ chkpts = checkpoint_paths(
86
+ cfg.save_dir,
87
+ pattern=r"checkpoint\.best_{}_(\d+\.?\d*){}\.pt".format(
88
+ cfg.best_checkpoint_metric, suffix
89
+ ),
90
+ )
91
+ if len(chkpts) > 0:
92
+ p = chkpts[-1] if cfg.maximize_best_checkpoint_metric else chkpts[0]
93
+ worst_best = float(p.rsplit("_")[-1].replace("{}.pt".format(suffix), ""))
94
+ # add random digits to resolve ties
95
+ with data_utils.numpy_seed(epoch, updates, val_loss):
96
+ rand_sfx = np.random.randint(0, cfg.keep_best_checkpoints)
97
+
98
+ checkpoint_conds[
99
+ "checkpoint.best_{}_{:.3f}{}{}.pt".format(
100
+ cfg.best_checkpoint_metric, val_loss, rand_sfx, suffix
101
+ )
102
+ ] = worst_best is None or is_better(val_loss, worst_best)
103
+ checkpoint_conds[
104
+ "checkpoint_last{}.pt".format(suffix)
105
+ ] = not cfg.no_last_checkpoints
106
+
107
+ extra_state = {"train_iterator": epoch_itr.state_dict(), "val_loss": val_loss}
108
+ if hasattr(save_checkpoint, "best"):
109
+ extra_state.update({"best": save_checkpoint.best})
110
+
111
+ checkpoints = [
112
+ os.path.join(cfg.save_dir, fn) for fn, cond in checkpoint_conds.items() if cond
113
+ ]
114
+ saved_cp = None
115
+ if len(checkpoints) > 0 and trainer.should_save_checkpoint_on_current_rank:
116
+ saved_cp = trainer.save_checkpoint(checkpoints[0], extra_state)
117
+ for cp in checkpoints[1:]:
118
+ if cfg.write_checkpoints_asynchronously:
119
+ # TODO[ioPath]: Need to implement a delayed asynchronous
120
+ # file copying/moving feature.
121
+ logger.warning(
122
+ f"ioPath is not copying {checkpoints[0]} to {cp} "
123
+ "since async write mode is on."
124
+ )
125
+ else:
126
+ assert PathManager.copy(
127
+ checkpoints[0], cp, overwrite=True
128
+ ), f"Failed to copy {checkpoints[0]} to {cp}"
129
+
130
+ write_timer.stop()
131
+ logger.info(
132
+ "Saved checkpoint {} (epoch {} @ {} updates, score {}) (writing took {} seconds)".format(
133
+ checkpoints[0], epoch, updates, val_loss, write_timer.sum
134
+ )
135
+ )
136
+
137
+ if (
138
+ not end_of_epoch
139
+ and cfg.keep_interval_updates > 0
140
+ and trainer.should_save_checkpoint_on_current_rank
141
+ ):
142
+ # remove old checkpoints; checkpoints are sorted in descending order
143
+ if cfg.keep_interval_updates_pattern == -1:
144
+ checkpoints = checkpoint_paths(
145
+ cfg.save_dir, pattern=r"checkpoint_\d+_(\d+){}\.pt".format(suffix)
146
+ )
147
+ else:
148
+ checkpoints = checkpoint_paths(
149
+ cfg.save_dir,
150
+ pattern=r"checkpoint_\d+_(\d+){}\.pt".format(suffix),
151
+ keep_match=True,
152
+ )
153
+ checkpoints = [
154
+ x[0]
155
+ for x in checkpoints
156
+ if x[1] % cfg.keep_interval_updates_pattern != 0
157
+ ]
158
+
159
+ for old_chk in checkpoints[cfg.keep_interval_updates :]:
160
+ if os.path.lexists(old_chk):
161
+ os.remove(old_chk)
162
+ elif PathManager.exists(old_chk):
163
+ PathManager.rm(old_chk)
164
+
165
+ if cfg.keep_last_epochs > 0 and trainer.should_save_checkpoint_on_current_rank:
166
+ # remove old epoch checkpoints; checkpoints are sorted in descending order
167
+ checkpoints = checkpoint_paths(
168
+ cfg.save_dir, pattern=r"checkpoint(\d+){}\.pt".format(suffix)
169
+ )
170
+ for old_chk in checkpoints[cfg.keep_last_epochs :]:
171
+ if os.path.lexists(old_chk):
172
+ os.remove(old_chk)
173
+ elif PathManager.exists(old_chk):
174
+ PathManager.rm(old_chk)
175
+
176
+ if cfg.keep_best_checkpoints > 0 and trainer.should_save_checkpoint_on_current_rank:
177
+ # only keep the best N checkpoints according to validation metric
178
+ checkpoints = checkpoint_paths(
179
+ cfg.save_dir,
180
+ pattern=r"checkpoint\.best_{}_(\d+\.?\d*){}\.pt".format(
181
+ cfg.best_checkpoint_metric, suffix
182
+ ),
183
+ )
184
+ if not cfg.maximize_best_checkpoint_metric:
185
+ checkpoints = checkpoints[::-1]
186
+ for old_chk in checkpoints[cfg.keep_best_checkpoints :]:
187
+ if os.path.lexists(old_chk):
188
+ os.remove(old_chk)
189
+ elif PathManager.exists(old_chk):
190
+ PathManager.rm(old_chk)
191
+
192
+ return saved_cp
193
+
194
+
195
+ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args):
196
+ """
197
+ Load a checkpoint and restore the training iterator.
198
+
199
+ *passthrough_args* will be passed through to
200
+ ``trainer.get_train_iterator``.
201
+ """
202
+
203
+ reset_optimizer = cfg.reset_optimizer
204
+ reset_lr_scheduler = cfg.reset_lr_scheduler
205
+ optimizer_overrides = ast.literal_eval(cfg.optimizer_overrides)
206
+ reset_meters = cfg.reset_meters
207
+ reset_dataloader = cfg.reset_dataloader
208
+
209
+ if cfg.finetune_from_model is not None and (
210
+ reset_optimizer or reset_lr_scheduler or reset_meters or reset_dataloader
211
+ ):
212
+ raise ValueError(
213
+ "--finetune-from-model can not be set together with either --reset-optimizer"
214
+ " or reset_lr_scheduler or reset_meters or reset_dataloader"
215
+ )
216
+
217
+ suffix = trainer.checkpoint_suffix
218
+ if (
219
+ cfg.restore_file == "checkpoint_last.pt"
220
+ ): # default value of restore_file is 'checkpoint_last.pt'
221
+ checkpoint_path = os.path.join(
222
+ cfg.save_dir, "checkpoint_last{}.pt".format(suffix)
223
+ )
224
+ first_launch = not PathManager.exists(checkpoint_path)
225
+ if first_launch and getattr(cfg, "continue_once", None) is not None:
226
+ checkpoint_path = cfg.continue_once
227
+ elif cfg.finetune_from_model is not None and first_launch:
228
+ # if there is no last checkpoint to restore, start the finetune from pretrained model
229
+ # else just use usual logic to load checkpoint, e.g. restart from last checkpoint and etc.
230
+ if PathManager.exists(cfg.finetune_from_model):
231
+ checkpoint_path = cfg.finetune_from_model
232
+ reset_optimizer = True
233
+ reset_lr_scheduler = True
234
+ reset_meters = True
235
+ reset_dataloader = True
236
+ logger.info(
237
+ f"loading pretrained model from {checkpoint_path}: "
238
+ "optimizer, lr scheduler, meters, dataloader will be reset"
239
+ )
240
+ else:
241
+ raise ValueError(
242
+ f"--finetune-from-model {cfg.finetune_from_model} does not exist"
243
+ )
244
+ elif suffix is not None:
245
+ checkpoint_path = cfg.restore_file.replace(".pt", suffix + ".pt")
246
+ else:
247
+ checkpoint_path = cfg.restore_file
248
+
249
+ if cfg.restore_file != "checkpoint_last.pt" and cfg.finetune_from_model:
250
+ raise ValueError(
251
+ "--finetune-from-model and --restore-file (non-default value) "
252
+ "can not be specified together: " + str(cfg)
253
+ )
254
+
255
+ extra_state = trainer.load_checkpoint(
256
+ checkpoint_path,
257
+ reset_optimizer,
258
+ reset_lr_scheduler,
259
+ optimizer_overrides,
260
+ reset_meters=reset_meters,
261
+ )
262
+
263
+ if (
264
+ extra_state is not None
265
+ and "best" in extra_state
266
+ and not reset_optimizer
267
+ and not reset_meters
268
+ ):
269
+ save_checkpoint.best = extra_state["best"]
270
+
271
+ if extra_state is not None and not reset_dataloader:
272
+ # restore iterator from checkpoint
273
+ itr_state = extra_state["train_iterator"]
274
+ epoch_itr = trainer.get_train_iterator(
275
+ epoch=itr_state["epoch"], load_dataset=True, **passthrough_args
276
+ )
277
+ epoch_itr.load_state_dict(itr_state)
278
+ else:
279
+ epoch_itr = trainer.get_train_iterator(
280
+ epoch=1, load_dataset=True, **passthrough_args
281
+ )
282
+
283
+ trainer.lr_step(epoch_itr.epoch)
284
+
285
+ return extra_state, epoch_itr
286
+
287
+
288
+ def load_checkpoint_to_cpu(path, arg_overrides=None, load_on_all_ranks=False):
289
+ """Loads a checkpoint to CPU (with upgrading for backward compatibility).
290
+
291
+ If doing single-GPU training or if the checkpoint is only being loaded by at
292
+ most one process on each node (current default behavior is for only rank 0
293
+ to read the checkpoint from disk), load_on_all_ranks should be False to
294
+ avoid errors from torch.distributed not having been initialized or
295
+ torch.distributed.barrier() hanging.
296
+
297
+ If all processes on each node may be loading the checkpoint
298
+ simultaneously, load_on_all_ranks should be set to True to avoid I/O
299
+ conflicts.
300
+
301
+ There's currently no support for > 1 but < all processes loading the
302
+ checkpoint on each node.
303
+ """
304
+ local_path = PathManager.get_local_path(path)
305
+ # The locally cached file returned by get_local_path() may be stale for
306
+ # remote files that are periodically updated/overwritten (ex:
307
+ # checkpoint_last.pt) - so we remove the local copy, sync across processes
308
+ # (if needed), and then download a fresh copy.
309
+ if local_path != path and PathManager.path_requires_pathmanager(path):
310
+ try:
311
+ os.remove(local_path)
312
+ except FileNotFoundError:
313
+ # With potentially multiple processes removing the same file, the
314
+ # file being missing is benign (missing_ok isn't available until
315
+ # Python 3.8).
316
+ pass
317
+ if load_on_all_ranks:
318
+ torch.distributed.barrier()
319
+ local_path = PathManager.get_local_path(path)
320
+
321
+ with open(local_path, "rb") as f:
322
+ state = torch.load(f, map_location=torch.device("cpu"))
323
+
324
+ if "args" in state and state["args"] is not None and arg_overrides is not None:
325
+ args = state["args"]
326
+ for arg_name, arg_val in arg_overrides.items():
327
+ setattr(args, arg_name, arg_val)
328
+
329
+ if "cfg" in state and state["cfg"] is not None:
330
+
331
+ # hack to be able to set Namespace in dict config. this should be removed when we update to newer
332
+ # omegaconf version that supports object flags, or when we migrate all existing models
333
+ from omegaconf import __version__ as oc_version
334
+ from omegaconf import _utils
335
+
336
+ if oc_version < "2.2":
337
+ old_primitive = _utils.is_primitive_type
338
+ _utils.is_primitive_type = lambda _: True
339
+
340
+ state["cfg"] = OmegaConf.create(state["cfg"])
341
+
342
+ _utils.is_primitive_type = old_primitive
343
+ OmegaConf.set_struct(state["cfg"], True)
344
+ else:
345
+ state["cfg"] = OmegaConf.create(state["cfg"], flags={"allow_objects": True})
346
+
347
+ if arg_overrides is not None:
348
+ overwrite_args_by_name(state["cfg"], arg_overrides)
349
+
350
+ state = _upgrade_state_dict(state)
351
+ return state
352
+
353
+
354
+ def load_model_ensemble(
355
+ filenames,
356
+ arg_overrides: Optional[Dict[str, Any]] = None,
357
+ task=None,
358
+ strict=True,
359
+ suffix="",
360
+ num_shards=1,
361
+ state=None,
362
+ ):
363
+ """Loads an ensemble of models.
364
+
365
+ Args:
366
+ filenames (List[str]): checkpoint files to load
367
+ arg_overrides (Dict[str,Any], optional): override model args that
368
+ were used during model training
369
+ task (fairseq.tasks.FairseqTask, optional): task to use for loading
370
+ """
371
+ assert not (
372
+ strict and num_shards > 1
373
+ ), "Cannot load state dict with strict=True and checkpoint shards > 1"
374
+ ensemble, args, _task = load_model_ensemble_and_task(
375
+ filenames,
376
+ arg_overrides,
377
+ task,
378
+ strict,
379
+ suffix,
380
+ num_shards,
381
+ state,
382
+ )
383
+ return ensemble, args
384
+
385
+
386
+ def get_maybe_sharded_checkpoint_filename(
387
+ filename: str, suffix: str, shard_idx: int, num_shards: int
388
+ ) -> str:
389
+ orig_filename = filename
390
+ filename = filename.replace(".pt", suffix + ".pt")
391
+ fsdp_filename = filename[:-3] + f"-shard{shard_idx}.pt"
392
+ model_parallel_filename = orig_filename[:-3] + f"_part{shard_idx}.pt"
393
+ if PathManager.exists(fsdp_filename):
394
+ return fsdp_filename
395
+ elif num_shards > 1:
396
+ return model_parallel_filename
397
+ else:
398
+ return filename
399
+
400
+
401
+ def load_model_ensemble_and_task(
402
+ filenames,
403
+ arg_overrides: Optional[Dict[str, Any]] = None,
404
+ task=None,
405
+ strict=True,
406
+ suffix="",
407
+ num_shards=1,
408
+ state=None,
409
+ ):
410
+ assert state is None or len(filenames) == 1
411
+
412
+ from fairseq import tasks
413
+
414
+ assert not (
415
+ strict and num_shards > 1
416
+ ), "Cannot load state dict with strict=True and checkpoint shards > 1"
417
+ ensemble = []
418
+ cfg = None
419
+ for filename in filenames:
420
+ orig_filename = filename
421
+ model_shard_state = {"shard_weights": [], "shard_metadata": []}
422
+ assert num_shards > 0
423
+ st = time.time()
424
+ for shard_idx in range(num_shards):
425
+ filename = get_maybe_sharded_checkpoint_filename(
426
+ orig_filename, suffix, shard_idx, num_shards
427
+ )
428
+
429
+ if not PathManager.exists(filename):
430
+ raise IOError("Model file not found: {}".format(filename))
431
+ if state is None:
432
+ state = load_checkpoint_to_cpu(filename, arg_overrides)
433
+ if "args" in state and state["args"] is not None:
434
+ cfg = convert_namespace_to_omegaconf(state["args"])
435
+ elif "cfg" in state and state["cfg"] is not None:
436
+ cfg = state["cfg"]
437
+ else:
438
+ raise RuntimeError(
439
+ f"Neither args nor cfg exist in state keys = {state.keys()}"
440
+ )
441
+
442
+ if task is None:
443
+ task = tasks.setup_task(cfg.task, from_checkpoint=True)
444
+
445
+ if "task_state" in state:
446
+ task.load_state_dict(state["task_state"])
447
+
448
+ argspec = inspect.getfullargspec(task.build_model)
449
+
450
+ if "fsdp_metadata" in state and num_shards > 1:
451
+ model_shard_state["shard_weights"].append(state["model"])
452
+ model_shard_state["shard_metadata"].append(state["fsdp_metadata"])
453
+ # check FSDP import before the code goes too far
454
+ if not has_FSDP:
455
+ raise ImportError(
456
+ "Cannot find FullyShardedDataParallel. "
457
+ "Please install fairscale with: pip install fairscale"
458
+ )
459
+ if shard_idx == num_shards - 1:
460
+ consolidated_model_state = FSDP.consolidate_shard_weights(
461
+ shard_weights=model_shard_state["shard_weights"],
462
+ shard_metadata=model_shard_state["shard_metadata"],
463
+ )
464
+ if "from_checkpoint" in argspec.args:
465
+ model = task.build_model(cfg.model, from_checkpoint=True)
466
+ else:
467
+ model = task.build_model(cfg.model)
468
+ if (
469
+ "optimizer_history" in state
470
+ and len(state["optimizer_history"]) > 0
471
+ and "num_updates" in state["optimizer_history"][-1]
472
+ ):
473
+ model.set_num_updates(
474
+ state["optimizer_history"][-1]["num_updates"]
475
+ )
476
+ model.load_state_dict(
477
+ consolidated_model_state, strict=strict, model_cfg=cfg.model
478
+ )
479
+ else:
480
+ # model parallel checkpoint or unsharded checkpoint
481
+ # support old external tasks
482
+
483
+ if "from_checkpoint" in argspec.args:
484
+ model = task.build_model(cfg.model, from_checkpoint=True)
485
+ else:
486
+ model = task.build_model(cfg.model)
487
+ if (
488
+ "optimizer_history" in state
489
+ and len(state["optimizer_history"]) > 0
490
+ and "num_updates" in state["optimizer_history"][-1]
491
+ ):
492
+ model.set_num_updates(state["optimizer_history"][-1]["num_updates"])
493
+ model.load_state_dict(
494
+ state["model"], strict=strict, model_cfg=cfg.model
495
+ )
496
+
497
+ # reset state so it gets loaded for the next model in ensemble
498
+ state = None
499
+ if shard_idx % 10 == 0 and shard_idx > 0:
500
+ elapsed = time.time() - st
501
+ logger.info(
502
+ f"Loaded {shard_idx} shards in {elapsed:.2f}s, {elapsed / (shard_idx+1):.2f}s/shard"
503
+ )
504
+
505
+ # build model for ensemble
506
+ ensemble.append(model)
507
+ return ensemble, cfg, task
508
+
509
+
510
+ def load_model_ensemble_and_task_from_hf_hub(
511
+ model_id,
512
+ cache_dir: Optional[str] = None,
513
+ arg_overrides: Optional[Dict[str, Any]] = None,
514
+ **kwargs: Any,
515
+ ):
516
+ try:
517
+ from huggingface_hub import snapshot_download
518
+ except ImportError:
519
+ raise ImportError(
520
+ "You need to install huggingface_hub to use `load_from_hf_hub`. "
521
+ "See https://pypi.org/project/huggingface-hub/ for installation."
522
+ )
523
+
524
+ library_name = "fairseq"
525
+ cache_dir = cache_dir or (Path.home() / ".cache" / library_name).as_posix()
526
+ cache_dir = snapshot_download(
527
+ model_id, cache_dir=cache_dir, library_name=library_name, **kwargs
528
+ )
529
+
530
+ _arg_overrides = arg_overrides or {}
531
+ _arg_overrides["data"] = cache_dir
532
+ return load_model_ensemble_and_task(
533
+ [p.as_posix() for p in Path(cache_dir).glob("*.pt")],
534
+ arg_overrides=_arg_overrides,
535
+ )
536
+
537
+
538
+ def checkpoint_paths(path, pattern=r"checkpoint(\d+)\.pt", keep_match=False):
539
+ """Retrieves all checkpoints found in `path` directory.
540
+
541
+ Checkpoints are identified by matching filename to the specified pattern. If
542
+ the pattern contains groups, the result will be sorted by the first group in
543
+ descending order.
544
+ """
545
+ pt_regexp = re.compile(pattern)
546
+ files = PathManager.ls(path)
547
+
548
+ entries = []
549
+ for i, f in enumerate(files):
550
+ m = pt_regexp.fullmatch(f)
551
+ if m is not None:
552
+ idx = float(m.group(1)) if len(m.groups()) > 0 else i
553
+ entries.append((idx, m.group(0)))
554
+ if keep_match:
555
+ return [(os.path.join(path, x[1]), x[0]) for x in sorted(entries, reverse=True)]
556
+ else:
557
+ return [os.path.join(path, x[1]) for x in sorted(entries, reverse=True)]
558
+
559
+
560
+ def torch_persistent_save(obj, filename, async_write: bool = False):
561
+ if async_write:
562
+ with PathManager.opena(filename, "wb") as f:
563
+ _torch_persistent_save(obj, f)
564
+ else:
565
+ if PathManager.supports_rename(filename):
566
+ # do atomic save
567
+ with PathManager.open(filename + ".tmp", "wb") as f:
568
+ _torch_persistent_save(obj, f)
569
+ PathManager.rename(filename + ".tmp", filename)
570
+ else:
571
+ # fallback to non-atomic save
572
+ with PathManager.open(filename, "wb") as f:
573
+ _torch_persistent_save(obj, f)
574
+
575
+
576
+ def _torch_persistent_save(obj, f):
577
+ if isinstance(f, str):
578
+ with PathManager.open(f, "wb") as h:
579
+ torch_persistent_save(obj, h)
580
+ return
581
+ for i in range(3):
582
+ try:
583
+ return torch.save(obj, f)
584
+ except Exception:
585
+ if i == 2:
586
+ logger.error(traceback.format_exc())
587
+ raise
588
+ else:
589
+ time.sleep(2.5)
590
+
591
+
592
+ def _upgrade_state_dict(state):
593
+ """Helper for upgrading old model checkpoints."""
594
+
595
+ # add optimizer_history
596
+ if "optimizer_history" not in state:
597
+ state["optimizer_history"] = [
598
+ {"criterion_name": "CrossEntropyCriterion", "best_loss": state["best_loss"]}
599
+ ]
600
+ state["last_optimizer_state"] = state["optimizer"]
601
+ del state["optimizer"]
602
+ del state["best_loss"]
603
+ # move extra_state into sub-dictionary
604
+ if "epoch" in state and "extra_state" not in state:
605
+ state["extra_state"] = {
606
+ "epoch": state["epoch"],
607
+ "batch_offset": state["batch_offset"],
608
+ "val_loss": state["val_loss"],
609
+ }
610
+ del state["epoch"]
611
+ del state["batch_offset"]
612
+ del state["val_loss"]
613
+ # reduce optimizer history's memory usage (only keep the last state)
614
+ if "optimizer" in state["optimizer_history"][-1]:
615
+ state["last_optimizer_state"] = state["optimizer_history"][-1]["optimizer"]
616
+ for optim_hist in state["optimizer_history"]:
617
+ del optim_hist["optimizer"]
618
+ # record the optimizer class name
619
+ if "optimizer_name" not in state["optimizer_history"][-1]:
620
+ state["optimizer_history"][-1]["optimizer_name"] = "FairseqNAG"
621
+ # move best_loss into lr_scheduler_state
622
+ if "lr_scheduler_state" not in state["optimizer_history"][-1]:
623
+ state["optimizer_history"][-1]["lr_scheduler_state"] = {
624
+ "best": state["optimizer_history"][-1]["best_loss"]
625
+ }
626
+ del state["optimizer_history"][-1]["best_loss"]
627
+ # keep track of number of updates
628
+ if "num_updates" not in state["optimizer_history"][-1]:
629
+ state["optimizer_history"][-1]["num_updates"] = 0
630
+ # use stateful training data iterator
631
+ if "train_iterator" not in state["extra_state"]:
632
+ state["extra_state"]["train_iterator"] = {
633
+ "epoch": state["extra_state"].get("epoch", 0),
634
+ "iterations_in_epoch": state["extra_state"].get("batch_offset", 0),
635
+ }
636
+
637
+ # backward compatibility, cfg updates
638
+ if "args" in state and state["args"] is not None:
639
+ # old model checkpoints may not have separate source/target positions
640
+ if hasattr(state["args"], "max_positions") and not hasattr(
641
+ state["args"], "max_source_positions"
642
+ ):
643
+ state["args"].max_source_positions = state["args"].max_positions
644
+ state["args"].max_target_positions = state["args"].max_positions
645
+ # default to translation task
646
+ if not hasattr(state["args"], "task"):
647
+ state["args"].task = "translation"
648
+ # --raw-text and --lazy-load are deprecated
649
+ if getattr(state["args"], "raw_text", False):
650
+ state["args"].dataset_impl = "raw"
651
+ elif getattr(state["args"], "lazy_load", False):
652
+ state["args"].dataset_impl = "lazy"
653
+ # epochs start at 1
654
+ if state["extra_state"]["train_iterator"] is not None:
655
+ state["extra_state"]["train_iterator"]["epoch"] = max(
656
+ state["extra_state"]["train_iterator"].get("epoch", 1), 1
657
+ )
658
+ # --remove-bpe ==> --postprocess
659
+ if hasattr(state["args"], "remove_bpe"):
660
+ state["args"].post_process = state["args"].remove_bpe
661
+ # --min-lr ==> --stop-min-lr
662
+ if hasattr(state["args"], "min_lr"):
663
+ state["args"].stop_min_lr = state["args"].min_lr
664
+ del state["args"].min_lr
665
+ # binary_cross_entropy / kd_binary_cross_entropy => wav2vec criterion
666
+ if hasattr(state["args"], "criterion") and state["args"].criterion in [
667
+ "binary_cross_entropy",
668
+ "kd_binary_cross_entropy",
669
+ ]:
670
+ state["args"].criterion = "wav2vec"
671
+ # remove log_keys if it's None (criteria will supply a default value of [])
672
+ if hasattr(state["args"], "log_keys") and state["args"].log_keys is None:
673
+ delattr(state["args"], "log_keys")
674
+ # speech_pretraining => audio pretraining
675
+ if (
676
+ hasattr(state["args"], "task")
677
+ and state["args"].task == "speech_pretraining"
678
+ ):
679
+ state["args"].task = "audio_pretraining"
680
+ # audio_cpc => wav2vec
681
+ if hasattr(state["args"], "arch") and state["args"].arch == "audio_cpc":
682
+ state["args"].arch = "wav2vec"
683
+ # convert legacy float learning rate to List[float]
684
+ if hasattr(state["args"], "lr") and isinstance(state["args"].lr, float):
685
+ state["args"].lr = [state["args"].lr]
686
+ # convert task data arg to a string instead of List[string]
687
+ if (
688
+ hasattr(state["args"], "data")
689
+ and isinstance(state["args"].data, list)
690
+ and len(state["args"].data) > 0
691
+ ):
692
+ state["args"].data = state["args"].data[0]
693
+
694
+ state["cfg"] = convert_namespace_to_omegaconf(state["args"])
695
+
696
+ if "cfg" in state and state["cfg"] is not None:
697
+ cfg = state["cfg"]
698
+ with open_dict(cfg):
699
+ # any upgrades for Hydra-based configs
700
+ if (
701
+ "task" in cfg
702
+ and "eval_wer_config" in cfg.task
703
+ and isinstance(cfg.task.eval_wer_config.print_alignment, bool)
704
+ ):
705
+ cfg.task.eval_wer_config.print_alignment = "hard"
706
+ if "generation" in cfg and isinstance(cfg.generation.print_alignment, bool):
707
+ cfg.generation.print_alignment = (
708
+ "hard" if cfg.generation.print_alignment else None
709
+ )
710
+ if (
711
+ "model" in cfg
712
+ and "w2v_args" in cfg.model
713
+ and cfg.model.w2v_args is not None
714
+ and (
715
+ hasattr(cfg.model.w2v_args, "task") or "task" in cfg.model.w2v_args
716
+ )
717
+ and hasattr(cfg.model.w2v_args.task, "eval_wer_config")
718
+ and cfg.model.w2v_args.task.eval_wer_config is not None
719
+ and isinstance(
720
+ cfg.model.w2v_args.task.eval_wer_config.print_alignment, bool
721
+ )
722
+ ):
723
+ cfg.model.w2v_args.task.eval_wer_config.print_alignment = "hard"
724
+
725
+ return state
726
+
727
+
728
+ def prune_state_dict(state_dict, model_cfg: Optional[DictConfig]):
729
+ """Prune the given state_dict if desired for LayerDrop
730
+ (https://arxiv.org/abs/1909.11556).
731
+
732
+ Training with LayerDrop allows models to be robust to pruning at inference
733
+ time. This function prunes state_dict to allow smaller models to be loaded
734
+ from a larger model and re-maps the existing state_dict for this to occur.
735
+
736
+ It's called by functions that load models from checkpoints and does not
737
+ need to be called directly.
738
+ """
739
+ arch = None
740
+ if model_cfg is not None:
741
+ arch = (
742
+ model_cfg._name
743
+ if isinstance(model_cfg, DictConfig)
744
+ else getattr(model_cfg, "arch", None)
745
+ )
746
+
747
+ if not model_cfg or arch is None or arch == "ptt_transformer":
748
+ # args should not be none, but don't crash if it is.
749
+ return state_dict
750
+
751
+ encoder_layers_to_keep = getattr(model_cfg, "encoder_layers_to_keep", None)
752
+ decoder_layers_to_keep = getattr(model_cfg, "decoder_layers_to_keep", None)
753
+
754
+ if not encoder_layers_to_keep and not decoder_layers_to_keep:
755
+ return state_dict
756
+
757
+ # apply pruning
758
+ logger.info(
759
+ "Pruning model to specified layer configuration - this works best if the model was trained with LayerDrop"
760
+ )
761
+
762
+ def create_pruning_pass(layers_to_keep, layer_name):
763
+ keep_layers = sorted(
764
+ int(layer_string) for layer_string in layers_to_keep.split(",")
765
+ )
766
+ mapping_dict = {}
767
+ for i in range(len(keep_layers)):
768
+ mapping_dict[str(keep_layers[i])] = str(i)
769
+
770
+ regex = re.compile(r"^{layer}.*\.layers\.(\d+)".format(layer=layer_name))
771
+ return {"substitution_regex": regex, "mapping_dict": mapping_dict}
772
+
773
+ pruning_passes = []
774
+ if encoder_layers_to_keep:
775
+ pruning_passes.append(create_pruning_pass(encoder_layers_to_keep, "encoder"))
776
+ if decoder_layers_to_keep:
777
+ pruning_passes.append(create_pruning_pass(decoder_layers_to_keep, "decoder"))
778
+
779
+ new_state_dict = {}
780
+ for layer_name in state_dict.keys():
781
+ match = re.search(r"\.layers\.(\d+)\.", layer_name)
782
+ # if layer has no number in it, it is a supporting layer, such as an
783
+ # embedding
784
+ if not match:
785
+ new_state_dict[layer_name] = state_dict[layer_name]
786
+ continue
787
+
788
+ # otherwise, layer should be pruned.
789
+ original_layer_number = match.group(1)
790
+ # figure out which mapping dict to replace from
791
+ for pruning_pass in pruning_passes:
792
+ if original_layer_number in pruning_pass["mapping_dict"] and pruning_pass[
793
+ "substitution_regex"
794
+ ].search(layer_name):
795
+ new_layer_number = pruning_pass["mapping_dict"][original_layer_number]
796
+ substitution_match = pruning_pass["substitution_regex"].search(
797
+ layer_name
798
+ )
799
+ new_state_key = (
800
+ layer_name[: substitution_match.start(1)]
801
+ + new_layer_number
802
+ + layer_name[substitution_match.end(1) :]
803
+ )
804
+ new_state_dict[new_state_key] = state_dict[layer_name]
805
+
806
+ # Since layers are now pruned, *_layers_to_keep are no longer needed.
807
+ # This is more of "It would make it work fix" rather than a proper fix.
808
+ if isinstance(model_cfg, DictConfig):
809
+ context = open_dict(model_cfg)
810
+ else:
811
+ context = contextlib.ExitStack()
812
+ with context:
813
+ if hasattr(model_cfg, "encoder_layers_to_keep"):
814
+ model_cfg.encoder_layers_to_keep = None
815
+ if hasattr(model_cfg, "decoder_layers_to_keep"):
816
+ model_cfg.decoder_layers_to_keep = None
817
+
818
+ return new_state_dict
819
+
820
+
821
+ def load_pretrained_component_from_model(
822
+ component: Union[FairseqEncoder, FairseqDecoder],
823
+ checkpoint: str,
824
+ strict: bool = True,
825
+ ):
826
+ """
827
+ Load a pretrained FairseqEncoder or FairseqDecoder from checkpoint into the
828
+ provided `component` object. If state_dict fails to load, there may be a
829
+ mismatch in the architecture of the corresponding `component` found in the
830
+ `checkpoint` file.
831
+ """
832
+ if not PathManager.exists(checkpoint):
833
+ raise IOError("Model file not found: {}".format(checkpoint))
834
+ state = load_checkpoint_to_cpu(checkpoint)
835
+ if isinstance(component, FairseqEncoder):
836
+ component_type = "encoder"
837
+ elif isinstance(component, FairseqDecoder):
838
+ component_type = "decoder"
839
+ else:
840
+ raise ValueError(
841
+ "component to load must be either a FairseqEncoder or "
842
+ "FairseqDecoder. Loading other component types are not supported."
843
+ )
844
+ component_state_dict = OrderedDict()
845
+ for key in state["model"].keys():
846
+ if key.startswith(component_type):
847
+ # encoder.input_layers.0.0.weight --> input_layers.0.0.weight
848
+ component_subkey = key[len(component_type) + 1 :]
849
+ component_state_dict[component_subkey] = state["model"][key]
850
+ component.load_state_dict(component_state_dict, strict=strict)
851
+ return component
852
+
853
+
854
+ def verify_checkpoint_directory(save_dir: str) -> None:
855
+ if not os.path.exists(save_dir):
856
+ os.makedirs(save_dir, exist_ok=True)
857
+ temp_file_path = os.path.join(save_dir, "dummy")
858
+ try:
859
+ with open(temp_file_path, "w"):
860
+ pass
861
+ except OSError as e:
862
+ logger.warning(
863
+ "Unable to access checkpoint save directory: {}".format(save_dir)
864
+ )
865
+ raise e
866
+ else:
867
+ os.remove(temp_file_path)
868
+
869
+
870
+ def save_ema_as_checkpoint(src_path, dst_path):
871
+ state = load_ema_from_checkpoint(src_path)
872
+ torch_persistent_save(state, dst_path)
873
+
874
+
875
+ def load_ema_from_checkpoint(fpath):
876
+ """Loads exponential moving averaged (EMA) checkpoint from input and
877
+ returns a model with ema weights.
878
+
879
+ Args:
880
+ fpath: A string path of checkpoint to load from.
881
+
882
+ Returns:
883
+ A dict of string keys mapping to various values. The 'model' key
884
+ from the returned dict should correspond to an OrderedDict mapping
885
+ string parameter names to torch Tensors.
886
+ """
887
+ params_dict = collections.OrderedDict()
888
+ new_state = None
889
+
890
+ with PathManager.open(fpath, "rb") as f:
891
+ new_state = torch.load(
892
+ f,
893
+ map_location=(
894
+ lambda s, _: torch.serialization.default_restore_location(s, "cpu")
895
+ ),
896
+ )
897
+
898
+ # EMA model is stored in a separate "extra state"
899
+ model_params = new_state["extra_state"]["ema"]
900
+
901
+ for key in list(model_params.keys()):
902
+ p = model_params[key]
903
+ if isinstance(p, torch.HalfTensor):
904
+ p = p.float()
905
+ if key not in params_dict:
906
+ params_dict[key] = p.clone()
907
+ # NOTE: clone() is needed in case of p is a shared parameter
908
+ else:
909
+ raise ValueError("Key {} is repeated in EMA model params.".format(key))
910
+
911
+ if len(params_dict) == 0:
912
+ raise ValueError(
913
+ f"Input checkpoint path '{fpath}' does not contain "
914
+ "ema model weights, is this model trained with EMA?"
915
+ )
916
+
917
+ new_state["model"] = params_dict
918
+ return new_state
omni_speech/infer/fairseq/fairseq/clib/cuda/ngram_repeat_block_cuda.cpp ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Copyright (c) Microsoft Corporation.
3
+ Licensed under the MIT License.
4
+ */
5
+
6
+ #include <torch/extension.h>
7
+ #include <vector>
8
+
9
+ /*
10
+ CPP Binding for CUDA OP
11
+ */
12
+
13
+ // CUDA forward declarations
14
+ torch::Tensor ngram_repeat_block_cuda_forward(
15
+ torch::Tensor tokens,
16
+ torch::Tensor lprobs,
17
+ int bsz,
18
+ int step,
19
+ int beam_size,
20
+ int no_repeat_ngram_size);
21
+
22
+ #define CHECK_CUDA(x) \
23
+ TORCH_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor")
24
+ #define CHECK_CONTIGUOUS(x) \
25
+ TORCH_CHECK(x.is_contiguous(), #x " must be contiguous")
26
+ #define CHECK_INPUT(x) \
27
+ CHECK_CUDA(x); \
28
+ CHECK_CONTIGUOUS(x)
29
+
30
+ // Input check and call to CUDA OP
31
+ // Backward method not required
32
+ torch::Tensor ngram_repeat_block_forward(
33
+ torch::Tensor tokens,
34
+ torch::Tensor lprobs,
35
+ int bsz,
36
+ int step,
37
+ int beam_size,
38
+ int no_repeat_ngram_size) {
39
+ CHECK_INPUT(tokens);
40
+ CHECK_INPUT(lprobs);
41
+ assert(bsz > 0);
42
+ assert(step >= 0);
43
+ assert(beam_size > 0);
44
+ assert(no_repeat_ngram_size > 0);
45
+
46
+ return ngram_repeat_block_cuda_forward(
47
+ tokens, lprobs, bsz, step, beam_size, no_repeat_ngram_size);
48
+ }
49
+
50
+ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
51
+ m.def(
52
+ "forward",
53
+ &ngram_repeat_block_forward,
54
+ "No Repeat Ngram Block forward (CUDA)");
55
+ }
omni_speech/infer/fairseq/fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Copyright (c) Microsoft Corporation.
3
+ Licensed under the MIT License.
4
+ */
5
+
6
+ /*
7
+ Kernel implementation for blocking repeated n-grams.
8
+ */
9
+
10
+ #include <cuda.h>
11
+ #include <cuda_runtime.h>
12
+ #include <math.h>
13
+ #include <torch/extension.h>
14
+ #include <vector>
15
+
16
+ // Ban repeated ngrams of length = 'no_repeat_ngram_size'
17
+ __global__ void banRepeatedTokens(
18
+ long* __restrict__ tokens,
19
+ float* __restrict__ lprobs,
20
+ int max_predict_len,
21
+ int vocab_size,
22
+ int no_repeat_ngram_size) {
23
+ auto row = blockIdx.x;
24
+ auto col = threadIdx.x;
25
+ auto start = row * (max_predict_len) + col;
26
+ // Each thread compares ngram starting from
27
+ // thread index with final ngram starting from
28
+ // step - no_repeat_ngram_size +2
29
+ auto check_start_pos = blockDim.x;
30
+ auto lprob_start = row * vocab_size;
31
+ bool is_banned = true;
32
+ extern __shared__ long tokens_shm[];
33
+ tokens_shm[col] = tokens[start];
34
+ if (col == blockDim.x - 1) {
35
+ for (int i = 1; i < no_repeat_ngram_size; i++) {
36
+ if (col + i < max_predict_len) {
37
+ tokens_shm[col + i] = tokens[start + i];
38
+ }
39
+ }
40
+ }
41
+ __syncthreads();
42
+
43
+ for (int k = 0; k < no_repeat_ngram_size - 1; k++) {
44
+ if (tokens_shm[col + k] != tokens_shm[check_start_pos + k]) {
45
+ is_banned = false;
46
+ }
47
+ }
48
+ if (is_banned == true) {
49
+ auto token_to_be_banned = tokens_shm[col + no_repeat_ngram_size - 1];
50
+ lprobs[lprob_start + token_to_be_banned] = -INFINITY;
51
+ }
52
+ }
53
+
54
+ // Allocate blocks and threads based on
55
+ // batch size and sequence length and launch
56
+ // kernel
57
+ torch::Tensor ngram_repeat_block_cuda_forward(
58
+ const torch::Tensor tokens,
59
+ torch::Tensor lprobs,
60
+ int bsz,
61
+ int step,
62
+ int beam_size,
63
+ int no_repeat_ngram_size) {
64
+ int threads = step - no_repeat_ngram_size + 2;
65
+ if (threads <= 0)
66
+ return lprobs;
67
+ int max_predict_len = tokens.size(1);
68
+ int vocab_size = lprobs.size(1);
69
+ auto token_ptr = tokens.data_ptr<long>();
70
+ auto lprob_ptr = lprobs.data_ptr<float>();
71
+ int blocks = bsz * beam_size;
72
+ int shared_mem_size = (step + 1) * sizeof(long);
73
+
74
+ // Launching N blocks where N is number of samples in a batch (beams*bsz)
75
+ // Launching T threads where T is number of previous ngrams in a sample
76
+ // Allocating shared mem per block for fastser access of input tokens since
77
+ // each token will be accessed N times to compare with current Ngram where
78
+ // N is Ngram size.
79
+ banRepeatedTokens<<<blocks, threads, shared_mem_size>>>(
80
+ token_ptr, lprob_ptr, max_predict_len, vocab_size, no_repeat_ngram_size);
81
+ return lprobs;
82
+ }