Script for estimating Lhotse dynamic duration buckets
jenkins jenkins jenkins jenkins
# What does this PR do ?

The script provides the user with the optimal, data-driven value of `model.train_ds.bucket_duration_bins` to avoid computing it at the start of the training.

It requires tiny changes to enable dataset mixing with non-tarred manifests (as we don't want to actually load any data here) and triggered an opportunity for a small refactor of the `CutSet` initialization code. Another issue was that NeMo manifests do not have `sampling_rate` info but Lhotse must have it to create a Recording object -- I introduced a `dummy_mode` for use-cases like this where we only need to iterate the metadata.

**Collection**: All speech collections

# Changelog 
- Script for estimating Lhotse dynamic duration buckets

# Usage

## Help message
```
$ python scripts/speech_recognition/estimate_duration_bins.py --help
usage: estimate_duration_bins.py [-h] [-b BUCKETS] [-n NUM_EXAMPLES]
                                 [-l MIN_DURATION] [-u MAX_DURATION] [-q QUIET]
                                 input

Estimate duration bins for Lhotse dynamic bucketing using a sample of the input
dataset. The dataset is read either from one or more manifest files and supports
data weighting.

positional arguments:
  input                 Same input format as in model configs under
                        model.train_ds.manifest_filepath. Options: 1)
                        "path.json"; 2) "[path1.json,path2.json,...]"; 3)
                        "[[path1.json,weight1],[path2.json,weight2],...]"

options:
  -h, --help            show this help message and exit
  -b BUCKETS, --buckets BUCKETS
                        The desired number of buckets.
  -n NUM_EXAMPLES, --num_examples NUM_EXAMPLES
                        The number of examples (utterances) to estimate the
                        bins. -1 means use all data.
  -l MIN_DURATION, --min_duration MIN_DURATION
                        If specified, we'll filter out utterances shorter than
                        this.
  -u MAX_DURATION, --max_duration MAX_DURATION
                        If specified, we'll filter out utterances longer than
                        this.
  -q QUIET, --quiet QUIET
                        When specified, only print the estimated duration bins.
```

## Example manifest and options
```
$ python scripts/speech_recognition/estimate_duration_bins.py -b 30 -l 2 -u 2.5 -n 10000 manifest.json
Note: we discarded 50168/60168 (83.38%) utterances due to min/max duration filtering.
Use the following options in your config:
        num_buckets=30
        bucket_duration_bins=[2.03,2.05419,2.08,2.11,2.13452,2.16,2.18,2.2,2.22,2.24,2.2531,2.27,2.285,2.3,2.3175,2.33,2.342,2.36,2.37,2.3896,2.4,2.41369,2.4295,2.44,2.45,2.46,2.47,2.48,2.491]
Computing utterance duration distribution...
Cut statistics:
╒═══════════════════════════╤══════════╕
│ Cuts count:               │ 10000    │
├───────────────────────────┼──────────┤
│ Total duration (hh:mm:ss) │ 06:21:17 │
├───────────────────────────┼──────────┤
│ mean                      │ 2.3      │
├───────────────────────────┼──────────┤
│ std                       │ 0.1      │
├───────────────────────────┼──────────┤
│ min                       │ 2.0      │
├───────────────────────────┼──────────┤
│ 25%                       │ 2.2      │
├───────────────────────────┼──────────┤
│ 50%                       │ 2.3      │
├───────────────────────────┼──────────┤
│ 75%                       │ 2.4      │
├───────────────────────────┼──────────┤
│ 99%                       │ 2.5      │
├───────────────────────────┼──────────┤
│ 99.5%                     │ 2.5      │
├───────────────────────────┼──────────┤
│ 99.9%                     │ 2.5      │
├───────────────────────────┼──────────┤
│ max                       │ 2.5      │
├───────────────────────────┼──────────┤
│ Recordings available:     │ 10000    │
├───────────────────────────┼──────────┤
│ Features available:       │ 0        │
├───────────────────────────┼──────────┤
│ Supervisions available:   │ 10000    │
╘═══════════════════════════╧══════════╛
CUT custom fields:
- shard_id (in 10000 cuts)
- text (in 10000 cuts)
- pcstrip_text (in 10000 cuts)
- source_lang (in 10000 cuts)
- target_lang (in 10000 cuts)
- taskname (in 10000 cuts)
- pnc (in 10000 cuts)
- answer (in 10000 cuts)
Speech duration statistics:
╒══════════════════════════════╤══════════╤══════════════════════╕
│ Total speech duration        │ 06:21:17 │ 100.00% of recording │
├──────────────────────────────┼──────────┼──────────────────────┤
│ Total speaking time duration │ 06:21:17 │ 100.00% of recording │
├──────────────────────────────┼──────────┼──────────────────────┤
│ Total silence duration       │ 00:00:01 │ 0.00% of recording   │
╘══════════════════════════════╧══════════╧══════════════════════╛

```

# Jenkins CI
To run Jenkins, a NeMo User with write access must comment `jenkins` on the PR.

# Before your PR is "Ready for review"
**Pre checks**:
- [x] Make sure you read and followed [Contributor guidelines](https://github.com/NVIDIA/NeMo/blob/main/CONTRIBUTING.md)
- [x] Did you write any new necessary tests?
- [x] Did you add or update any necessary documentation?
- [ ] Does the PR affect components that are optional to install? (Ex: Numba, Pynini, Apex etc)
  - [ ] Reviewer: Does the PR have correct import guards for all optional libraries?
  
**PR Type**:
- [x] New Feature
- [ ] Bugfix
- [ ] Documentation

If you haven't finished some of the above items you can still open "Draft" PR.


## Who can review?

Anyone in the community is free to review the PR once the checks have passed. 
[Contributor guidelines](https://github.com/NVIDIA/NeMo/blob/main/CONTRIBUTING.md) contains specific people who can review PRs to various areas.

# Additional Information
* Related to # (issue)
