From 53396adb210d1db07f4400bb29e8aa8c0ae88af5 Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 20 May 2023 13:02:46 +0200 Subject: [PATCH 01/30] add device_index --- whisperx/asr.py | 4 ++-- whisperx/transcribe.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/whisperx/asr.py b/whisperx/asr.py index 88d5bf6..470e701 100644 --- a/whisperx/asr.py +++ b/whisperx/asr.py @@ -13,7 +13,7 @@ from .audio import N_SAMPLES, SAMPLE_RATE, load_audio, log_mel_spectrogram from .vad import load_vad_model, merge_chunks from .types import TranscriptionResult, SingleSegment -def load_model(whisper_arch, device, compute_type="float16", asr_options=None, language=None, +def load_model(whisper_arch, device, device_index=0, compute_type="float16", asr_options=None, language=None, vad_options=None, model=None, task="transcribe"): '''Load a Whisper model for inference. Args: @@ -29,7 +29,7 @@ def load_model(whisper_arch, device, compute_type="float16", asr_options=None, l if whisper_arch.endswith(".en"): language = "en" - model = WhisperModel(whisper_arch, device=device, compute_type=compute_type) + model = WhisperModel(whisper_arch, device=device, device_index=device_index, compute_type=compute_type) if language is not None: tokenizer = faster_whisper.tokenizer.Tokenizer(model.hf_tokenizer, model.model.is_multilingual, task=task, language=language) else: diff --git a/whisperx/transcribe.py b/whisperx/transcribe.py index 3edc746..4432abe 100644 --- a/whisperx/transcribe.py +++ b/whisperx/transcribe.py @@ -21,6 +21,7 @@ def cli(): parser.add_argument("--model", default="small", help="name of the Whisper model to use") parser.add_argument("--model_dir", type=str, default=None, help="the path to save model files; uses ~/.cache/whisper by default") parser.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu", help="device to use for PyTorch inference") + parser.add_argument("--device_index", default=None, type=int, help="device index to use for FasterWhisper inference") parser.add_argument("--batch_size", default=8, type=int, help="device to use for PyTorch inference") parser.add_argument("--compute_type", default="float16", type=str, choices=["float16", "float32", "int8"], help="compute type for computation") @@ -78,6 +79,7 @@ def cli(): output_dir: str = args.pop("output_dir") output_format: str = args.pop("output_format") device: str = args.pop("device") + device_index: int = args.pop("device_index") compute_type: str = args.pop("compute_type") # model_flush: bool = args.pop("model_flush") @@ -144,7 +146,7 @@ def cli(): results = [] tmp_results = [] # model = load_model(model_name, device=device, download_root=model_dir) - model = load_model(model_name, device=device, compute_type=compute_type, language=args['language'], asr_options=asr_options, vad_options={"vad_onset": vad_onset, "vad_offset": vad_offset}, task=task) + model = load_model(model_name, device=device, device_index=device_index, compute_type=compute_type, language=args['language'], asr_options=asr_options, vad_options={"vad_onset": vad_onset, "vad_offset": vad_offset}, task=task) for audio_path in args.pop("audio"): audio = load_audio(audio_path) From 74b98ebfaab771f4078c7ffe973117257667dda2 Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 20 May 2023 13:11:30 +0200 Subject: [PATCH 02/30] ensure device_index not None --- whisperx/transcribe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/whisperx/transcribe.py b/whisperx/transcribe.py index 4432abe..691e3f9 100644 --- a/whisperx/transcribe.py +++ b/whisperx/transcribe.py @@ -21,7 +21,7 @@ def cli(): parser.add_argument("--model", default="small", help="name of the Whisper model to use") parser.add_argument("--model_dir", type=str, default=None, help="the path to save model files; uses ~/.cache/whisper by default") parser.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu", help="device to use for PyTorch inference") - parser.add_argument("--device_index", default=None, type=int, help="device index to use for FasterWhisper inference") + parser.add_argument("--device_index", default=0, type=int, help="device index to use for FasterWhisper inference") parser.add_argument("--batch_size", default=8, type=int, help="device to use for PyTorch inference") parser.add_argument("--compute_type", default="float16", type=str, choices=["float16", "float32", "int8"], help="compute type for computation") From 1fc965bc1a78b5ae9a9bb155ab02a426dce6ea58 Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 20 May 2023 15:30:25 +0200 Subject: [PATCH 03/30] add task, language keyword to transcribe --- whisperx/asr.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/whisperx/asr.py b/whisperx/asr.py index 88d5bf6..2fab8bc 100644 --- a/whisperx/asr.py +++ b/whisperx/asr.py @@ -214,7 +214,7 @@ class FasterWhisperPipeline(Pipeline): return final_iterator def transcribe( - self, audio: Union[str, np.ndarray], batch_size=None, num_workers=0 + self, audio: Union[str, np.ndarray], batch_size=None, num_workers=0, language=None, task=None ) -> TranscriptionResult: if isinstance(audio, str): audio = load_audio(audio) @@ -229,13 +229,12 @@ class FasterWhisperPipeline(Pipeline): vad_segments = self.vad_model({"waveform": torch.from_numpy(audio).unsqueeze(0), "sample_rate": SAMPLE_RATE}) vad_segments = merge_chunks(vad_segments, 30) - del_tokenizer = False - if self.tokenizer is None: - language = self.detect_language(audio) - self.tokenizer = faster_whisper.tokenizer.Tokenizer(self.model.hf_tokenizer, self.model.model.is_multilingual, task="transcribe", language=language) - del_tokenizer = True - else: - language = self.tokenizer.language_code + language = language or self.tokenizer.language_code + task = task or self.tokenizer.task + if task != self.tokenizer.task or language != self.tokenizer.language_code: + self.tokenizer = faster_whisper.tokenizer.Tokenizer(self.model.hf_tokenizer, + self.model.model.is_multilingual, task=task, + language=language) segments: List[SingleSegment] = [] batch_size = batch_size or self._batch_size @@ -250,9 +249,6 @@ class FasterWhisperPipeline(Pipeline): "end": round(vad_segments[idx]['end'], 3) } ) - - if del_tokenizer: - self.tokenizer = None return {"segments": segments, "language": language} From 715435db4284c1e73caf284662c131542a938bb9 Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 20 May 2023 15:42:21 +0200 Subject: [PATCH 04/30] add tokenizer is None case --- whisperx/asr.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/whisperx/asr.py b/whisperx/asr.py index 2fab8bc..b4035e5 100644 --- a/whisperx/asr.py +++ b/whisperx/asr.py @@ -228,9 +228,12 @@ class FasterWhisperPipeline(Pipeline): vad_segments = self.vad_model({"waveform": torch.from_numpy(audio).unsqueeze(0), "sample_rate": SAMPLE_RATE}) vad_segments = merge_chunks(vad_segments, 30) - - language = language or self.tokenizer.language_code - task = task or self.tokenizer.task + if self.tokenizer is None: + language = language or self.detect_language(audio) + task = task or "transcribe" + else: + language = language or self.tokenizer.language_code + task = task or self.tokenizer.task if task != self.tokenizer.task or language != self.tokenizer.language_code: self.tokenizer = faster_whisper.tokenizer.Tokenizer(self.model.hf_tokenizer, self.model.model.is_multilingual, task=task, From a1c705b3a75a0582733109136b6013e652e14464 Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 20 May 2023 15:52:45 +0200 Subject: [PATCH 05/30] fix tokenizer is None --- whisperx/asr.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/whisperx/asr.py b/whisperx/asr.py index b4035e5..9b1e450 100644 --- a/whisperx/asr.py +++ b/whisperx/asr.py @@ -231,13 +231,16 @@ class FasterWhisperPipeline(Pipeline): if self.tokenizer is None: language = language or self.detect_language(audio) task = task or "transcribe" - else: - language = language or self.tokenizer.language_code - task = task or self.tokenizer.task - if task != self.tokenizer.task or language != self.tokenizer.language_code: self.tokenizer = faster_whisper.tokenizer.Tokenizer(self.model.hf_tokenizer, self.model.model.is_multilingual, task=task, language=language) + else: + language = language or self.tokenizer.language_code + task = task or self.tokenizer.task + if task != self.tokenizer.task or language != self.tokenizer.language_code: + self.tokenizer = faster_whisper.tokenizer.Tokenizer(self.model.hf_tokenizer, + self.model.model.is_multilingual, task=task, + language=language) segments: List[SingleSegment] = [] batch_size = batch_size or self._batch_size From 9c042c2d28eab5e048b047790e0d6c5c2f547c86 Mon Sep 17 00:00:00 2001 From: iambestfeeddddd Date: Fri, 26 May 2023 16:46:55 +0700 Subject: [PATCH 06/30] Add war2vec model for Vietnamese --- whisperx/alignment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/whisperx/alignment.py b/whisperx/alignment.py index 13dfddc..efd75de 100644 --- a/whisperx/alignment.py +++ b/whisperx/alignment.py @@ -42,6 +42,7 @@ DEFAULT_ALIGN_MODELS_HF = { "tr": "mpoyraz/wav2vec2-xls-r-300m-cv7-turkish", "da": "saattrupdan/wav2vec2-xls-r-300m-ftspeech", "he": "imvladikon/wav2vec2-xls-r-300m-hebrew", + "vi": 'nguyenvulebinh/wav2vec2-base-vi' } From 1d9d630fb9c4db809c29449066310dc5d1c282e0 Mon Sep 17 00:00:00 2001 From: Youssef Boulaoaune <43298428+Boulaouaney@users.noreply.github.com> Date: Fri, 26 May 2023 20:33:16 +0900 Subject: [PATCH 07/30] added Korean wav2vec2 model --- whisperx/alignment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/whisperx/alignment.py b/whisperx/alignment.py index 13dfddc..8f84ee5 100644 --- a/whisperx/alignment.py +++ b/whisperx/alignment.py @@ -42,6 +42,7 @@ DEFAULT_ALIGN_MODELS_HF = { "tr": "mpoyraz/wav2vec2-xls-r-300m-cv7-turkish", "da": "saattrupdan/wav2vec2-xls-r-300m-ftspeech", "he": "imvladikon/wav2vec2-xls-r-300m-hebrew", + "ko": "kresnik/wav2vec2-large-xlsr-korean", } From bb15d6b68edd9493d0c221d87ca7c72570b890e7 Mon Sep 17 00:00:00 2001 From: Thebys Date: Fri, 26 May 2023 21:17:01 +0200 Subject: [PATCH 08/30] Add Czech alignment model This PR adds the following Czech alignment model: https://huggingface.co/comodoro/wav2vec2-xls-r-300m-cs-250. I have successfully tested this with several Czech audio recordings with length of up to 3 hours, and the results are satisfactory. However, I have received the following warnings and I am not sure how relevant it is: ``` Lightning automatically upgraded your loaded checkpoint from v1.5.4 to v2.0.2. To apply the upgrade to your files permanently, run `python -m pytorch_lightning.utilities.upgrade_checkpoint --file C:\Users\Thebys\.cache\torch\whisperx-vad-segmentation.bin` Model was trained with pyannote.audio 0.0.1, yours is 2.1.1. Bad things might happen unless you revert pyannote.audio to 0.x. Model was trained with torch 1.10.0+cu102, yours is 2.0.0. Bad things might happen unless you revert torch to 1.x. ``` --- whisperx/alignment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/whisperx/alignment.py b/whisperx/alignment.py index 8f84ee5..34153ec 100644 --- a/whisperx/alignment.py +++ b/whisperx/alignment.py @@ -33,6 +33,7 @@ DEFAULT_ALIGN_MODELS_HF = { "uk": "Yehor/wav2vec2-xls-r-300m-uk-with-small-lm", "pt": "jonatasgrosman/wav2vec2-large-xlsr-53-portuguese", "ar": "jonatasgrosman/wav2vec2-large-xlsr-53-arabic", + "cs": "comodoro/wav2vec2-xls-r-300m-cs-250", "ru": "jonatasgrosman/wav2vec2-large-xlsr-53-russian", "pl": "jonatasgrosman/wav2vec2-large-xlsr-53-polish", "hu": "jonatasgrosman/wav2vec2-large-xlsr-53-hungarian", From 42b4909bc07ccad388acf86818d8c0da8482bc71 Mon Sep 17 00:00:00 2001 From: Max Bain Date: Fri, 26 May 2023 20:36:03 +0100 Subject: [PATCH 09/30] fix Unequal Stack Size VAD error --- whisperx/alignment.py | 2 ++ whisperx/vad.py | 10 ++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/whisperx/alignment.py b/whisperx/alignment.py index 1e22a7b..aade4b4 100644 --- a/whisperx/alignment.py +++ b/whisperx/alignment.py @@ -298,6 +298,8 @@ def align( aligned_subsegments["end"] = interpolate_nans(aligned_subsegments["end"], method=interpolate_method) # concatenate sentences with same timestamps agg_dict = {"text": " ".join, "words": "sum"} + if model_lang in LANGUAGES_WITHOUT_SPACES: + agg_dict["text"] = "".join if return_char_alignments: agg_dict["chars"] = "sum" aligned_subsegments= aligned_subsegments.groupby(["start", "end"], as_index=False).agg(agg_dict) diff --git a/whisperx/vad.py b/whisperx/vad.py index 42b0bfb..a7a2451 100644 --- a/whisperx/vad.py +++ b/whisperx/vad.py @@ -147,8 +147,6 @@ class Binarize: if is_active: curr_duration = t - start if curr_duration > self.max_duration: - # if curr_duration > 15: - # import pdb; pdb.set_trace() search_after = len(curr_scores) // 2 # divide segment min_score_div_idx = search_after + np.argmin(curr_scores[search_after:]) @@ -159,21 +157,21 @@ class Binarize: curr_scores = curr_scores[min_score_div_idx+1:] curr_timestamps = curr_timestamps[min_score_div_idx+1:] # switching from active to inactive - elif y < self.offset: + elif y <= self.offset: region = Segment(start - self.pad_onset, t + self.pad_offset) active[region, k] = label start = t is_active = False curr_scores = [] curr_timestamps = [] + curr_scores.append(y) + curr_timestamps.append(t) # currently inactive else: # switching from inactive to active - if y > self.onset: + if y >= self.onset: start = t is_active = True - curr_scores.append(y) - curr_timestamps.append(t) # if active at the end, add final region if is_active: From f1032bb40a4d39fa7a92cc6c2a1b071b282d8aa4 Mon Sep 17 00:00:00 2001 From: Max Bain <36994049+m-bain@users.noreply.github.com> Date: Fri, 26 May 2023 20:39:19 +0100 Subject: [PATCH 10/30] VAD unequal stack size, remove debug change --- whisperx/vad.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/whisperx/vad.py b/whisperx/vad.py index a7a2451..15a9e5e 100644 --- a/whisperx/vad.py +++ b/whisperx/vad.py @@ -157,7 +157,7 @@ class Binarize: curr_scores = curr_scores[min_score_div_idx+1:] curr_timestamps = curr_timestamps[min_score_div_idx+1:] # switching from active to inactive - elif y <= self.offset: + elif y < self.offset: region = Segment(start - self.pad_onset, t + self.pad_offset) active[region, k] = label start = t @@ -169,7 +169,7 @@ class Binarize: # currently inactive else: # switching from inactive to active - if y >= self.onset: + if y > self.onset: start = t is_active = True From 5a47f458ac56f1a0d8549d850371ec380a7ec5dd Mon Sep 17 00:00:00 2001 From: prameshbajra Date: Sat, 27 May 2023 11:38:54 +0200 Subject: [PATCH 11/30] Added download path parameter. --- whisperx/asr.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/whisperx/asr.py b/whisperx/asr.py index 713531c..d0e6962 100644 --- a/whisperx/asr.py +++ b/whisperx/asr.py @@ -13,8 +13,16 @@ from .audio import N_SAMPLES, SAMPLE_RATE, load_audio, log_mel_spectrogram from .vad import load_vad_model, merge_chunks from .types import TranscriptionResult, SingleSegment -def load_model(whisper_arch, device, device_index=0, compute_type="float16", asr_options=None, language=None, - vad_options=None, model=None, task="transcribe"): +def load_model(whisper_arch, + device, + device_index=0, + compute_type="float16", + asr_options=None, + language=None, + vad_options=None, + model=None, + task="transcribe", + download_root=None): '''Load a Whisper model for inference. Args: whisper_arch: str - The name of the Whisper model to load. @@ -22,14 +30,19 @@ def load_model(whisper_arch, device, device_index=0, compute_type="float16", asr compute_type: str - The compute type to use for the model. options: dict - A dictionary of options to use for the model. language: str - The language of the model. (use English for now) + download_root: Optional[str] - The root directory to download the model to. Returns: A Whisper pipeline. - ''' + ''' if whisper_arch.endswith(".en"): language = "en" - model = WhisperModel(whisper_arch, device=device, device_index=device_index, compute_type=compute_type) + model = WhisperModel(whisper_arch, + device=device, + device_index=device_index, + compute_type=compute_type, + download_root=download_root) if language is not None: tokenizer = faster_whisper.tokenizer.Tokenizer(model.hf_tokenizer, model.model.is_multilingual, task=task, language=language) else: @@ -114,7 +127,7 @@ class WhisperModel(faster_whisper.WhisperModel): # suppress_tokens=options.suppress_tokens, # max_initial_timestamp_index=max_initial_timestamp_index, ) - + tokens_batch = [x.sequences_ids[0] for x in result] def decode_batch(tokens: List[List[int]]) -> str: @@ -127,7 +140,7 @@ class WhisperModel(faster_whisper.WhisperModel): text = decode_batch(tokens_batch) return text - + def encode(self, features: np.ndarray) -> ctranslate2.StorageView: # When the model is running on multiple GPUs, the encoder output should be moved # to the CPU since we don't know which GPU will handle the next job. @@ -136,9 +149,9 @@ class WhisperModel(faster_whisper.WhisperModel): if len(features.shape) == 2: features = np.expand_dims(features, 0) features = faster_whisper.transcribe.get_ctranslate2_storage(features) - + return self.model.encode(features, to_cpu=to_cpu) - + class FasterWhisperPipeline(Pipeline): """ Huggingface Pipeline wrapper for FasterWhisperModel. @@ -176,7 +189,7 @@ class FasterWhisperPipeline(Pipeline): self.device = torch.device(f"cuda:{device}") else: self.device = device - + super(Pipeline, self).__init__() self.vad_model = vad @@ -194,7 +207,7 @@ class FasterWhisperPipeline(Pipeline): def _forward(self, model_inputs): outputs = self.model.generate_segment_batched(model_inputs['inputs'], self.tokenizer, self.options) return {'text': outputs} - + def postprocess(self, model_outputs): return model_outputs @@ -218,7 +231,7 @@ class FasterWhisperPipeline(Pipeline): ) -> TranscriptionResult: if isinstance(audio, str): audio = load_audio(audio) - + def data(audio, segments): for seg in segments: f1 = int(seg['start'] * SAMPLE_RATE) From 4cbd3030cc0011fa8e20b93d03078dc353ef6fa7 Mon Sep 17 00:00:00 2001 From: Max Bain <36994049+m-bain@users.noreply.github.com> Date: Mon, 29 May 2023 12:48:14 +0100 Subject: [PATCH 12/30] no sentence split on mr. mrs. dr... --- whisperx/alignment.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/whisperx/alignment.py b/whisperx/alignment.py index 7ac3a04..17e96f4 100644 --- a/whisperx/alignment.py +++ b/whisperx/alignment.py @@ -15,6 +15,9 @@ from .audio import SAMPLE_RATE, load_audio from .utils import interpolate_nans from .types import AlignedTranscriptionResult, SingleSegment, SingleAlignedSegment, SingleWordSegment import nltk +from nltk.tokenize.punkt import PunktSentenceTokenizer, PunktParameters + +PUNKT_ABBREVIATIONS = ['dr', 'vs', 'mr', 'mrs', 'prof'] LANGUAGES_WITHOUT_SPACES = ["ja", "zh"] @@ -143,7 +146,11 @@ def align( if any([c in model_dictionary.keys() for c in wrd]): clean_wdx.append(wdx) - sentence_spans = list(nltk.tokenize.punkt.PunktSentenceTokenizer().span_tokenize(text)) + + punkt_param = PunktParameters() + punkt_param.abbrev_types = set(PUNKT_ABBREVIATIONS) + sentence_splitter = PunktSentenceTokenizer(punkt_param) + sentence_spans = list(sentence_splitter.span_tokenize(text)) segment["clean_char"] = clean_char segment["clean_cdx"] = clean_cdx From 5a4382ae4d42f64c156acc48bfd18c4a08e737a9 Mon Sep 17 00:00:00 2001 From: Master X Date: Tue, 30 May 2023 15:11:07 +0500 Subject: [PATCH 13/30] fix: Bug in type hinting --- whisperx/types.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/whisperx/types.py b/whisperx/types.py index 75d4485..68f2d78 100644 --- a/whisperx/types.py +++ b/whisperx/types.py @@ -1,4 +1,4 @@ -from typing import TypedDict, Optional +from typing import TypedDict, Optional, List class SingleWordSegment(TypedDict): @@ -38,15 +38,15 @@ class SingleAlignedSegment(TypedDict): start: float end: float text: str - words: list[SingleWordSegment] - chars: Optional[list[SingleCharSegment]] + words: List[SingleWordSegment] + chars: Optional[List[SingleCharSegment]] class TranscriptionResult(TypedDict): """ A list of segments and word segments of a speech. """ - segments: list[SingleSegment] + segments: List[SingleSegment] language: str @@ -54,5 +54,5 @@ class AlignedTranscriptionResult(TypedDict): """ A list of segments and word segments of a speech. """ - segments: list[SingleAlignedSegment] - word_segments: list[SingleWordSegment] + segments: List[SingleAlignedSegment] + word_segments: List[SingleWordSegment] From 93ed6cfa93ffdce04ae0d125aa4d645cc6b9ea77 Mon Sep 17 00:00:00 2001 From: Max Bain <36994049+m-bain@users.noreply.github.com> Date: Thu, 1 Jun 2023 16:54:16 +0100 Subject: [PATCH 14/30] interspeech --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a660d2d..d6c2e3d 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ This repository provides fast automatic speech recognition (70x realtime with la

New🚨

+- _WhisperX_ accepted at INTERSPEECH 2023 - v3 transcript segment-per-sentence: using nltk sent_tokenize for better subtitlting & better diarization - v3 released, 70x speed-up open-sourced. Using batched whisper with [faster-whisper](https://github.com/guillaumekln/faster-whisper) backend! - v2 released, code cleanup, imports whisper library VAD filtering is now turned on by default, as in the paper. @@ -276,7 +277,7 @@ If you use this in your research, please cite the paper: @article{bain2022whisperx, title={WhisperX: Time-Accurate Speech Transcription of Long-Form Audio}, author={Bain, Max and Huh, Jaesung and Han, Tengda and Zisserman, Andrew}, - journal={arXiv preprint, arXiv:2303.00747}, + journal={INTERSPEECH 2023}, year={2023} } ``` From a323cff654cf39e190043a8642c35205d1af02e8 Mon Sep 17 00:00:00 2001 From: Max Bain Date: Mon, 5 Jun 2023 15:27:42 +0100 Subject: [PATCH 15/30] --suppress_numerals option, ensures non-numerical words, for wav2vec2 alignment --- whisperx/asr.py | 35 +++++++++++++++++++++++++++-------- whisperx/transcribe.py | 6 +++++- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/whisperx/asr.py b/whisperx/asr.py index 66b58ad..fbb5331 100644 --- a/whisperx/asr.py +++ b/whisperx/asr.py @@ -12,6 +12,14 @@ from transformers.pipelines.pt_utils import PipelineIterator from .audio import N_SAMPLES, SAMPLE_RATE, load_audio, log_mel_spectrogram from .vad import load_vad_model, merge_chunks +def find_numeral_symbol_tokens(tokenizer): + numeral_symbol_tokens = [] + for i in range(tokenizer.eot): + token = tokenizer.decode([i]).removeprefix(" ") + if all(c in "0123456789@#%&*+=_$:-.,?!" for c in token): + numeral_symbol_tokens.append(i) + return numeral_symbol_tokens + def load_model(whisper_arch, device, compute_type="float16", asr_options=None, language=None, vad_options=None, model=None, task="transcribe"): @@ -54,13 +62,27 @@ def load_model(whisper_arch, device, compute_type="float16", asr_options=None, l "max_initial_timestamp": 0.0, "word_timestamps": False, "prepend_punctuations": "\"'“¿([{-", - "append_punctuations": "\"'.。,,!!??::”)]}、" + "append_punctuations": "\"'.。,,!!??::”)]}、", + "suppress_numerals": False, } if asr_options is not None: default_asr_options.update(asr_options) + + if default_asr_options["suppress_numerals"]: + if tokenizer is None: + tokenizer = faster_whisper.tokenizer.Tokenizer(model.hf_tokenizer, model.model.is_multilingual, task=task, language="en") + numeral_symbol_tokens = find_numeral_symbol_tokens(tokenizer) + print(f"Suppressing numeral and symbol tokens: {numeral_symbol_tokens}") + default_asr_options["suppress_tokens"] += numeral_symbol_tokens + default_asr_options["suppress_tokens"] = list(set(default_asr_options["suppress_tokens"])) + del default_asr_options["suppress_numerals"] + default_asr_options = faster_whisper.transcribe.TranscriptionOptions(**default_asr_options) + + + default_vad_options = { "vad_onset": 0.500, "vad_offset": 0.363 @@ -106,13 +128,10 @@ class WhisperModel(faster_whisper.WhisperModel): result = self.model.generate( encoder_output, [prompt] * batch_size, - # length_penalty=options.length_penalty, - # max_length=self.max_length, - # return_scores=True, - # return_no_speech_prob=True, - # suppress_blank=options.suppress_blank, - # suppress_tokens=options.suppress_tokens, - # max_initial_timestamp_index=max_initial_timestamp_index, + length_penalty=options.length_penalty, + max_length=self.max_length, + suppress_blank=options.suppress_blank, + suppress_tokens=options.suppress_tokens, ) tokens_batch = [x.sequences_ids[0] for x in result] diff --git a/whisperx/transcribe.py b/whisperx/transcribe.py index 3edc746..e9b6fc6 100644 --- a/whisperx/transcribe.py +++ b/whisperx/transcribe.py @@ -50,9 +50,11 @@ def cli(): parser.add_argument("--best_of", type=optional_int, default=5, help="number of candidates when sampling with non-zero temperature") parser.add_argument("--beam_size", type=optional_int, default=5, help="number of beams in beam search, only applicable when temperature is zero") parser.add_argument("--patience", type=float, default=None, help="optional patience value to use in beam decoding, as in https://arxiv.org/abs/2204.05424, the default (1.0) is equivalent to conventional beam search") - parser.add_argument("--length_penalty", type=float, default=None, help="optional token length penalty coefficient (alpha) as in https://arxiv.org/abs/1609.08144, uses simple length normalization by default") + parser.add_argument("--length_penalty", type=float, default=1.0, help="optional token length penalty coefficient (alpha) as in https://arxiv.org/abs/1609.08144, uses simple length normalization by default") parser.add_argument("--suppress_tokens", type=str, default="-1", help="comma-separated list of token ids to suppress during sampling; '-1' will suppress most special characters except common punctuations") + parser.add_argument("--suppress_numerals", action="store_true", help="whether to suppress numeric symbols and currency symbols during sampling, since wav2vec2 cannot align them correctly") + parser.add_argument("--initial_prompt", type=str, default=None, help="optional text to provide as a prompt for the first window.") parser.add_argument("--condition_on_previous_text", type=str2bool, default=False, help="if True, provide the previous output of the model as a prompt for the next window; disabling may make the text inconsistent across windows, but the model becomes less prone to getting stuck in a failure loop") parser.add_argument("--fp16", type=str2bool, default=True, help="whether to perform inference in fp16; True by default") @@ -128,6 +130,8 @@ def cli(): "no_speech_threshold": args.pop("no_speech_threshold"), "condition_on_previous_text": False, "initial_prompt": args.pop("initial_prompt"), + "suppress_tokens": [int(x) for x in args.pop("suppress_tokens").split(",")], + "suppress_numerals": args.pop("suppress_numerals"), } writer = get_writer(output_format, output_dir) From 74a00eecd7e0f90766f9fcd709f3e287ad6d97b3 Mon Sep 17 00:00:00 2001 From: Max Bain Date: Mon, 5 Jun 2023 15:33:04 +0100 Subject: [PATCH 16/30] suppress numerals fix --- whisperx/asr.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/whisperx/asr.py b/whisperx/asr.py index f2a7203..501b21d 100644 --- a/whisperx/asr.py +++ b/whisperx/asr.py @@ -11,7 +11,7 @@ from transformers.pipelines.pt_utils import PipelineIterator from .audio import N_SAMPLES, SAMPLE_RATE, load_audio, log_mel_spectrogram from .vad import load_vad_model, merge_chunks -<<<<<<< HEAD +from .types import TranscriptionResult, SingleSegment def find_numeral_symbol_tokens(tokenizer): numeral_symbol_tokens = [] @@ -21,12 +21,6 @@ def find_numeral_symbol_tokens(tokenizer): numeral_symbol_tokens.append(i) return numeral_symbol_tokens - -def load_model(whisper_arch, device, compute_type="float16", asr_options=None, language=None, - vad_options=None, model=None, task="transcribe"): -======= -from .types import TranscriptionResult, SingleSegment - def load_model(whisper_arch, device, device_index=0, @@ -37,7 +31,6 @@ def load_model(whisper_arch, model=None, task="transcribe", download_root=None): ->>>>>>> ec6a110cdf2616919cfd0a616f9ae2fbdd44903f '''Load a Whisper model for inference. Args: whisper_arch: str - The name of the Whisper model to load. @@ -100,9 +93,6 @@ def load_model(whisper_arch, default_asr_options = faster_whisper.transcribe.TranscriptionOptions(**default_asr_options) - - - default_vad_options = { "vad_onset": 0.500, "vad_offset": 0.363 From d7f1d16f1927bfaf6b2b62de1d68daae470f2721 Mon Sep 17 00:00:00 2001 From: Max Bain Date: Mon, 5 Jun 2023 15:44:17 +0100 Subject: [PATCH 17/30] suppress numerals change logic --- whisperx/asr.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/whisperx/asr.py b/whisperx/asr.py index 501b21d..09454c9 100644 --- a/whisperx/asr.py +++ b/whisperx/asr.py @@ -17,7 +17,8 @@ def find_numeral_symbol_tokens(tokenizer): numeral_symbol_tokens = [] for i in range(tokenizer.eot): token = tokenizer.decode([i]).removeprefix(" ") - if all(c in "0123456789@#%&*+=_$:-.,?!" for c in token): + has_numeral_symbol = any(c in "0123456789%$£" for c in token) + if has_numeral_symbol: numeral_symbol_tokens.append(i) return numeral_symbol_tokens From 076ff96eb20f560f95a22eca7e5f4bcd01747070 Mon Sep 17 00:00:00 2001 From: CaraDuf <91517923+Ca-ressemble-a-du-fake@users.noreply.github.com> Date: Wed, 7 Jun 2023 05:49:49 +0200 Subject: [PATCH 18/30] Add Audacity export This exports the transcript to a text file that can be directly imported in Audacity as label file. This is useful to quickly check the transcript-audio alignment. --- whisperx/utils.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/whisperx/utils.py b/whisperx/utils.py index d042bb7..ff17cce 100644 --- a/whisperx/utils.py +++ b/whisperx/utils.py @@ -365,6 +365,28 @@ class WriteTSV(ResultWriter): print(round(1000 * segment["end"]), file=file, end="\t") print(segment["text"].strip().replace("\t", " "), file=file, flush=True) +class WriteAudacity(ResultWriter): + """ + Write a transcript to a text file that audacity can import as labels. + The extension used is "aud" to distinguish it from the txt file produced by WriteTXT. + Yet this is not an audacity project but only a label file! + + Please note : Audacity uses seconds in timestamps not ms! + Also there is no header expected. + + If speaker is provided it is prepended to the text between double square brackets [[]]. + """ + + extension: str = "aud" + + def write_result(self, result: dict, file: TextIO, options: dict): + ARROW = " " + for segment in result["segments"]: + print(segment["start"], file=file, end=ARROW) + print(segment["end"], file=file, end=ARROW) + print( ( ("[[" + segment["speaker"] + "]]") if "speaker" in segment else "") + segment["text"].strip().replace("\t", " "), file=file, flush=True) + + class WriteJSON(ResultWriter): extension: str = "json" @@ -377,6 +399,7 @@ def get_writer( output_format: str, output_dir: str ) -> Callable[[dict, TextIO, dict], None]: writers = { + "aud": WriteAudacity, "txt": WriteTXT, "vtt": WriteVTT, "srt": WriteSRT, @@ -399,4 +422,4 @@ def interpolate_nans(x, method='nearest'): if x.notnull().sum() > 1: return x.interpolate(method=method).ffill().bfill() else: - return x.ffill().bfill() \ No newline at end of file + return x.ffill().bfill() From b13778fefd71c955eb93bd9c4d3bb9c850acd5db Mon Sep 17 00:00:00 2001 From: Max Bain <36994049+m-bain@users.noreply.github.com> Date: Wed, 7 Jun 2023 11:47:49 +0100 Subject: [PATCH 19/30] make aud optional --- whisperx/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/whisperx/utils.py b/whisperx/utils.py index ff17cce..36c7543 100644 --- a/whisperx/utils.py +++ b/whisperx/utils.py @@ -399,13 +399,15 @@ def get_writer( output_format: str, output_dir: str ) -> Callable[[dict, TextIO, dict], None]: writers = { - "aud": WriteAudacity, "txt": WriteTXT, "vtt": WriteVTT, "srt": WriteSRT, "tsv": WriteTSV, "json": WriteJSON, } + optional_writers = { + "aud": WriteAudacity, + } if output_format == "all": all_writers = [writer(output_dir) for writer in writers.values()] @@ -416,6 +418,8 @@ def get_writer( return write_all + if output_format in optional_writers: + return optional_writers[output_format](output_dir) return writers[output_format](output_dir) def interpolate_nans(x, method='nearest'): From d39c1b2319a8140911be7f37b8176f300a89e3da Mon Sep 17 00:00:00 2001 From: Max Bain <36994049+m-bain@users.noreply.github.com> Date: Wed, 7 Jun 2023 11:48:49 +0100 Subject: [PATCH 20/30] add "aud" to output_format --- whisperx/transcribe.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/whisperx/transcribe.py b/whisperx/transcribe.py index 3bb1a36..1855178 100644 --- a/whisperx/transcribe.py +++ b/whisperx/transcribe.py @@ -26,7 +26,7 @@ def cli(): parser.add_argument("--compute_type", default="float16", type=str, choices=["float16", "float32", "int8"], help="compute type for computation") parser.add_argument("--output_dir", "-o", type=str, default=".", help="directory to save the outputs") - parser.add_argument("--output_format", "-f", type=str, default="all", choices=["all", "srt", "vtt", "txt", "tsv", "json"], help="format of the output file; if not specified, all available formats will be produced") + parser.add_argument("--output_format", "-f", type=str, default="all", choices=["all", "srt", "vtt", "txt", "tsv", "json", "aud"], help="format of the output file; if not specified, all available formats will be produced") parser.add_argument("--verbose", type=str2bool, default=True, help="whether to print out the progress and debug messages") parser.add_argument("--task", type=str, default="transcribe", choices=["transcribe", "translate"], help="whether to perform X->X speech recognition ('transcribe') or X->English translation ('translate')") @@ -210,4 +210,4 @@ def cli(): writer(result, audio_path, writer_args) if __name__ == "__main__": - cli() \ No newline at end of file + cli() From befe2b242eb59dcd7a8a122d127614d5c63d36e9 Mon Sep 17 00:00:00 2001 From: Max Bain <36994049+m-bain@users.noreply.github.com> Date: Wed, 7 Jun 2023 22:43:29 +0100 Subject: [PATCH 21/30] torch 2+ --- requirements.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index ec90a07..ddfa28a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -torch==2.0.0 -torchaudio==2.0.1 +torch>=2 +torchaudio>=2 faster-whisper transformers -ffmpeg-python==0.2.0 +ffmpeg-python>=0.2 pandas -setuptools==65.6.3 -nltk \ No newline at end of file +setuptools>=65 +nltk From 512ab1acf982053c3077c4ba179424c161815745 Mon Sep 17 00:00:00 2001 From: dan nelson Date: Fri, 30 Jun 2023 18:11:33 -0700 Subject: [PATCH 22/30] adding Replicate demo --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d6c2e3d..95dffba 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,11 @@ print(diarize_segments) print(result["segments"]) # segments are now assigned speaker IDs ``` +## Demos 🚀 + +[![Replicate](https://replicate.com/daanelson/whisperx/badge)](https://replicate.com/daanelson/whisperx) + +If you don't have access to your own GPUs, use the link above to try out WhisperX.

Technical Details 👷‍♂️

From 734ecc284456ab54497995572f819e4769fbb60d Mon Sep 17 00:00:00 2001 From: Ahmad Bilal Date: Mon, 17 Jul 2023 19:29:41 +0500 Subject: [PATCH 23/30] Add Urdu model support for alignment --- whisperx/alignment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/whisperx/alignment.py b/whisperx/alignment.py index 8d088be..3ffc3f7 100644 --- a/whisperx/alignment.py +++ b/whisperx/alignment.py @@ -48,6 +48,7 @@ DEFAULT_ALIGN_MODELS_HF = { "he": "imvladikon/wav2vec2-xls-r-300m-hebrew", "vi": 'nguyenvulebinh/wav2vec2-base-vi', "ko": "kresnik/wav2vec2-large-xlsr-korean", + "ur": "kingabzpro/wav2vec2-large-xls-r-300m-Urdu" } From 30eff5a01ff4dc5a883eff84a7e7c82327498137 Mon Sep 17 00:00:00 2001 From: Ahmad Bilal Date: Thu, 20 Jul 2023 02:32:37 +0500 Subject: [PATCH 24/30] Replace double quotes to single for JSON parsing --- whisperx/diarize.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/whisperx/diarize.py b/whisperx/diarize.py index 320d2a4..cf1e5cb 100644 --- a/whisperx/diarize.py +++ b/whisperx/diarize.py @@ -27,6 +27,9 @@ class DiarizationPipeline: def assign_word_speakers(diarize_df, transcript_result, fill_nearest=False): transcript_segments = transcript_result["segments"] for seg in transcript_segments: + if 'text' in seg: + seg["text"] = seg["text"].replace('"', "'") + # assign speaker to segment (if any) diarize_df['intersection'] = np.minimum(diarize_df['end'], seg['end']) - np.maximum(diarize_df['start'], seg['start']) diarize_df['union'] = np.maximum(diarize_df['end'], seg['end']) - np.minimum(diarize_df['start'], seg['start']) @@ -43,6 +46,7 @@ def assign_word_speakers(diarize_df, transcript_result, fill_nearest=False): # assign speaker to words if 'words' in seg: for word in seg['words']: + word = word.replace('"', "'") if 'start' in word: diarize_df['intersection'] = np.minimum(diarize_df['end'], word['end']) - np.maximum(diarize_df['start'], word['start']) diarize_df['union'] = np.maximum(diarize_df['end'], word['end']) - np.minimum(diarize_df['start'], word['start']) From eb712f3999c0d37d4306063c71a473b214f13d18 Mon Sep 17 00:00:00 2001 From: Ahmad Bilal Date: Thu, 20 Jul 2023 02:54:06 +0500 Subject: [PATCH 25/30] Rectify refernce to the word --- whisperx/diarize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/whisperx/diarize.py b/whisperx/diarize.py index cf1e5cb..59ca9e2 100644 --- a/whisperx/diarize.py +++ b/whisperx/diarize.py @@ -46,7 +46,7 @@ def assign_word_speakers(diarize_df, transcript_result, fill_nearest=False): # assign speaker to words if 'words' in seg: for word in seg['words']: - word = word.replace('"', "'") + word["word"] = word["word"].replace('"', "'") if 'start' in word: diarize_df['intersection'] = np.minimum(diarize_df['end'], word['end']) - np.maximum(diarize_df['start'], word['start']) diarize_df['union'] = np.maximum(diarize_df['end'], word['end']) - np.minimum(diarize_df['start'], word['start']) From e92325b7eb03583f53f8c6d19d2ce7f7122aa344 Mon Sep 17 00:00:00 2001 From: Ahmad Bilal Date: Thu, 20 Jul 2023 03:19:37 +0500 Subject: [PATCH 26/30] Remove the fix --- whisperx/diarize.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/whisperx/diarize.py b/whisperx/diarize.py index 59ca9e2..b14addf 100644 --- a/whisperx/diarize.py +++ b/whisperx/diarize.py @@ -27,8 +27,6 @@ class DiarizationPipeline: def assign_word_speakers(diarize_df, transcript_result, fill_nearest=False): transcript_segments = transcript_result["segments"] for seg in transcript_segments: - if 'text' in seg: - seg["text"] = seg["text"].replace('"', "'") # assign speaker to segment (if any) diarize_df['intersection'] = np.minimum(diarize_df['end'], seg['end']) - np.maximum(diarize_df['start'], seg['start']) @@ -46,7 +44,7 @@ def assign_word_speakers(diarize_df, transcript_result, fill_nearest=False): # assign speaker to words if 'words' in seg: for word in seg['words']: - word["word"] = word["word"].replace('"', "'") + if 'start' in word: diarize_df['intersection'] = np.minimum(diarize_df['end'], word['end']) - np.maximum(diarize_df['start'], word['start']) diarize_df['union'] = np.maximum(diarize_df['end'], word['end']) - np.minimum(diarize_df['start'], word['start']) From e6ecbaa68fcbb5a5010d42fc77d000eb362a6964 Mon Sep 17 00:00:00 2001 From: Ahmad Bilal Date: Thu, 20 Jul 2023 03:20:47 +0500 Subject: [PATCH 27/30] Remove spacing --- whisperx/diarize.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/whisperx/diarize.py b/whisperx/diarize.py index b14addf..320d2a4 100644 --- a/whisperx/diarize.py +++ b/whisperx/diarize.py @@ -27,7 +27,6 @@ class DiarizationPipeline: def assign_word_speakers(diarize_df, transcript_result, fill_nearest=False): transcript_segments = transcript_result["segments"] for seg in transcript_segments: - # assign speaker to segment (if any) diarize_df['intersection'] = np.minimum(diarize_df['end'], seg['end']) - np.maximum(diarize_df['start'], seg['start']) diarize_df['union'] = np.maximum(diarize_df['end'], seg['end']) - np.minimum(diarize_df['start'], seg['start']) @@ -44,7 +43,6 @@ def assign_word_speakers(diarize_df, transcript_result, fill_nearest=False): # assign speaker to words if 'words' in seg: for word in seg['words']: - if 'start' in word: diarize_df['intersection'] = np.minimum(diarize_df['end'], word['end']) - np.maximum(diarize_df['start'], word['start']) diarize_df['union'] = np.maximum(diarize_df['end'], word['end']) - np.minimum(diarize_df['start'], word['start']) From 86730646580259e4f7dbcefdabf86d98addf2a30 Mon Sep 17 00:00:00 2001 From: Eric Baer Date: Thu, 20 Jul 2023 17:02:34 -0700 Subject: [PATCH 28/30] Remove torchvision from README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6c2e3d..1694aba 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ GPU execution requires the NVIDIA libraries cuBLAS 11.x and cuDNN 8.x to be inst ### 2. Install PyTorch2.0, e.g. for Linux and Windows CUDA11.7: -`conda install pytorch==2.0.0 torchvision==0.15.0 torchaudio==2.0.0 pytorch-cuda=11.7 -c pytorch -c nvidia` +`conda install pytorch==2.0.0 torchaudio==2.0.0 pytorch-cuda=11.7 -c pytorch -c nvidia` See other methods [here.](https://pytorch.org/get-started/previous-versions/#v200) From 48e7caad77a731c9de84beb4346357466e62bc7e Mon Sep 17 00:00:00 2001 From: Mark Berger Date: Mon, 24 Jul 2023 11:45:38 +0200 Subject: [PATCH 29/30] Update transcribe.py -> small change in `batch_size` description Changed the description of the `batch_size` parameter. --- whisperx/transcribe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/whisperx/transcribe.py b/whisperx/transcribe.py index 1855178..1cc144e 100644 --- a/whisperx/transcribe.py +++ b/whisperx/transcribe.py @@ -22,7 +22,7 @@ def cli(): parser.add_argument("--model_dir", type=str, default=None, help="the path to save model files; uses ~/.cache/whisper by default") parser.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu", help="device to use for PyTorch inference") parser.add_argument("--device_index", default=0, type=int, help="device index to use for FasterWhisper inference") - parser.add_argument("--batch_size", default=8, type=int, help="device to use for PyTorch inference") + parser.add_argument("--batch_size", default=8, type=int, help="the preferred batch size for inference") parser.add_argument("--compute_type", default="float16", type=str, choices=["float16", "float32", "int8"], help="compute type for computation") parser.add_argument("--output_dir", "-o", type=str, default=".", help="directory to save the outputs") From 8c0fee90d39004adb72acc48b378f3e2d8704a70 Mon Sep 17 00:00:00 2001 From: Max Bain <36994049+m-bain@users.noreply.github.com> Date: Mon, 24 Jul 2023 10:47:41 +0100 Subject: [PATCH 30/30] Update alignment.py --- whisperx/alignment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/whisperx/alignment.py b/whisperx/alignment.py index 3ffc3f7..2717bc4 100644 --- a/whisperx/alignment.py +++ b/whisperx/alignment.py @@ -48,7 +48,7 @@ DEFAULT_ALIGN_MODELS_HF = { "he": "imvladikon/wav2vec2-xls-r-300m-hebrew", "vi": 'nguyenvulebinh/wav2vec2-base-vi', "ko": "kresnik/wav2vec2-large-xlsr-korean", - "ur": "kingabzpro/wav2vec2-large-xls-r-300m-Urdu" + "ur": "kingabzpro/wav2vec2-large-xls-r-300m-Urdu", }