Streaming ASR interfaces - #2377
Conversation
More WIP Bunch of filter properties impl More WIP interfaces stuff Fix type annotation in filter_analysis more wip interfaces wip Fix wrong context var set wip thoughts Implement file transcription
asumagic
left a comment
There was a problem hiding this comment.
Not yet done with replying/fixing according to all the review
There was a problem hiding this comment.
Thanks @asumagic! I left some comments.
I'd like to better understand about the usability of this new streaming ASR interface. For instance, If I'd like to use a CTC based model. How can I run streaming inference with it ? What needs to be changed in order to make everything works ?
I also think that we will really need a google colab on that (or a dedicated page on our documentation) to explain how to use it and define your own streaming interface.
TParcollet
left a comment
There was a problem hiding this comment.
@asumagic can you run a WER validation as well to verify that this does not alter the expected WER?
|
|
||
| HPARAMS_NEEDED = [ | ||
| "fea_streaming_extractor", | ||
| "Greedysearcher", |
There was a problem hiding this comment.
btw, in a future we will have to refactor this. For instance, if we want to use a CTC-based model, which could be the case since we will have a competitive CTC Branch/Conformer recipe on LibriSpeech, then one could use a beam search or greedy searcher in an online fashion. Maybe changing the naming to decoding_function or smth like that would be better.
There was a problem hiding this comment.
Added a decoding_function hparams and wrote some code for it, see the latest commit. Does that implementation seem reasonable?
|
I tested WER on test-clean with custom code using the StreamingASR Jank test script for referencedevice = "cuda"
model_path = "./librispeech-conformer"
test_csv = "/users/sdelangen/sb/recipes/LibriSpeech/ASR/transducer/results/conformer_transducer_large/3407/test-clean.csv"
import pandas as pd
test = pd.read_csv(test_csv)
import torch
torch.set_num_threads(1)
from concurrent.futures import ThreadPoolExecutor
from speechbrain.inference.ASR import StreamingASR
from speechbrain.utils.dynamic_chunk_training import DynChunkTrainConfig
from speechbrain.utils.metric_stats import ErrorRateStats
from speechbrain.utils.parallel import parallel_map
asr = StreamingASR.from_hparams(model_path, run_opts={"device": device})
config = DynChunkTrainConfig(24, 8)
wer_compute = ErrorRateStats()
def process_line(row):
i, line = row
path = line["wav"]
truth = line["wrd"]
pred = asr.transcribe_file(path, config, use_torchaudio_streaming=True)
return pred, truth
for i, (pred, truth) in enumerate(parallel_map(process_line, test.iterrows(), executor=ThreadPoolExecutor(20), chunk_size=1)):
wer_compute.append([i], [pred.split(" ")], [truth.split(" ")])
print(wer_compute.summarize()["WER"])
# for text_chunk in asr.transcribe_file_streaming(args.audio_path, config):
# print(text_chunk, flush=True, end="")Still fixing some stuff as suggested then I will re-request a review once done. |
Adel-Moumen
left a comment
There was a problem hiding this comment.
I would say that I have nothing much to say now. You answered all of my concerns. Could you please add the HF interface in private on the speechbrain HF hub ?
My only remark will be on the documentation part, I think we really need in the future (incoming weeks) to write good and high quality tutorials/etc to explain exactly what is needed to be changed if one wants to reuse the streamingASR interface.
Other than that, let's wait from @TParcollet POV on that :) (bug congrats this is a big thing for SB, a lot of people (industrials/researchers) were asking for this feature!).
I just moved the model to |
|
As for the docs, I've started writing some stuff but it will take some time. I already had some model details explained from the original PR that I will reuse. I am also starting to write a simple |
|
Thank you @asumagic, this is a great contribution. I ran recipe tests and everything seems fine. Thank you @Adel-Moumen and @TParcollet for the review. |
What does this PR do?
The goal of this PR is to provide high-level interfaces for streaming inference using the model introduced by #2140, and to provide some shared infrastructure for future streaming models.
I have hosted a LibriSpeech streaming ASR model at https://huggingface.co/sdelangen/speechbrain-asr-conformer-test/tree/main. There is currently no model card, but it will be possible to migrate this model under the speechbrain org once this is merged.
Introduced interfaces
The
StreamingASRinference interface was introduced.Features:
transcribe_chunk/decode_chunkAPI)Feature extraction
In the current conformer-transducer model, we have some feature extraction logic that stacks filter banks and 2 layers of down-sampling convolutions.
Ignoring normalization, we can consider feature extraction as a "filter" with a specific window size and stride.
Dynamic chunk training does not change how feature extraction is performed: it is applied over the entire batch at once, and is unaware of chunking.
This is mostly for simplicity, flexibility and training performance reasons.
Thus, when streaming, we have to be careful about how we chunk up our signal: for any given chunk, we must provide some past and future frames so that the transition across chunks remains as close to training as possible.
Streaming feature extraction abstraction
This logic is abstracted by
speechbrain.lobes.features.StreamingFeatureWrapperas introduced by this PR. When provided the "filter properties" of our feature extractor (window size and stride), it is able to process a stream of audio chunk by chunk while abstracting padding and left context saving details¹.Automatically determining filter properties
Those filter properties remain to be provided by the model developer. For this, we introduce
speechbrain.utils.filter_analysis. It allows modelling simple filter properties, and provides utilities to "stack" them, i.e. model what the properties offilter2(filter1(x))are.In our case, we are essentially trying to model
conv_layer_2(conv_layer_1(fbanks(waveform)))².This allows us to determine the filter properties of our feature extraction easily and requires little to no adjustment when changing feature extraction hyperparameters.
This PR introduces a
get_filter_propretiesmethod for some modules, so all that remains is providingStreamingFeatureWrapperour feature extractor module list.¹ This comes with a latency cost which depends on the window size and stride. However, that overhead is generally insignificant in practice as long as the window size and stride are kept reasonable.
² ignoring normalization. Not considering normalization specifically in our chunking process does not appear to have a significant effect on WER.
Example programs
Commandline tool to transcribe a file or a live stream
Decoding from a live stream using ffmpeg (BBC Radio 4):
python3 asr.py http://as-hls-ww-live.akamaized.net/pool_904/live/ww/bbc_radio_fourfm/bbc_radio_fourfm.isml/bbc_radio_fourfm-audio%3d96000.norewind.m3u8 --model-source=sdelangen/speechbrain-asr-conformer-test --device=cpu -vDecoding from a file:
python3 asr.py some-english-speech.wav --model-source=sdelangen/speechbrain-asr-conformer-test --device=cpu -vTODOsCompleted
I probably should be made part of the SB team on HF?done)StreamingASRinterface for flexibility as we might want to have several architectures be able to use it. -- I tried to make it so, but it's probably still biased towards the architecture I made it for. For what it's worth, it can be modified down the line and extended by any external users.should be made to support more than just sentencepiece-- the code was moved but it still only supports sentencepiece; but adding support for other tokenizers should otherwise not be too painful.-- might wait for Load audio with PyAV #2354probably will use torchaudio ffmpeg streaming stuff?Not sure how to handle things like rescoring that could change entire sentences, but let's consider it out-of-scope for
StreamingASR.Before submitting
PR review
Reviewer checklist