Release frozen StreamPA seed 1337 with validated standalone inference
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- LICENSE +29 -0
- README.md +172 -120
- README_zh.md +109 -0
- SHA256SUMS +41 -0
- THIRD_PARTY_NOTICES.md +43 -0
- assets/phn_dict.json +41 -0
- assets/prepared_resource_hashes.json +102 -0
- assets/pronunciation_lexicon.json +0 -0
- assets/runtime_sources.json +74 -0
- bundle_manifest.json +0 -107
- charsiu_en_w2v2_tiny_fc_10ms/config.json +0 -75
- charsiu_en_w2v2_tiny_fc_10ms/preprocessor_config.json +0 -1
- charsiu_en_w2v2_tiny_fc_10ms/pytorch_model.bin +0 -3
- examples/eval_streaming_gopt_test.py +0 -119
- examples/infer_one_audio.py +0 -395
- examples/sa1_infer_output.json +0 -30
- examples/session.py +21 -0
- licenses/Apache-2.0.txt +203 -0
- licenses/Charsiu-MIT.txt +21 -0
- licenses/G2P-Apache-2.0.txt +201 -0
- licenses/Whisper-MIT.txt +21 -0
- model_manifest.json +46 -0
- pyproject.toml +13 -0
- requirements-lock.txt +58 -0
- scorer/config.json +180 -0
- scorer/inference_assets.json +50 -0
- streaming_gopt_best/best_audio_model.pth → scorer/model.safetensors +2 -2
- scripts/setup_assets.py +74 -0
- scripts/verify_bundle.py +21 -0
- streaming_gopt_best/config.json +0 -42
- streaming_gopt_best/inference_assets.json +0 -48
- streaming_gopt_best/result.csv +0 -101
- streaming_gopt_best/test_metrics.json +0 -37
- streampa/__init__.py +4 -0
- streampa/charsiu_model.py +55 -0
- streampa/frontend.py +1556 -0
- streampa/infer.py +19 -0
- streampa/pipeline.py +318 -0
- streampa/stream.py +28 -0
- streampa/streaming_gopt.py +238 -0
- streampa/streaming_pcn_gopt.py +422 -0
- tests/test_runtime.py +88 -0
- validation_summary.json +139 -0
- {whisper_best_model → whisper}/added_tokens.json +0 -0
- {whisper_best_model → whisper}/config.json +0 -1
- {whisper_best_model → whisper}/generation_config.json +0 -0
- {whisper_best_model → whisper}/merges.txt +0 -0
- {whisper_best_model → whisper}/model.safetensors +0 -0
- {whisper_best_model → whisper}/normalizer.json +0 -0
- {whisper_best_model → whisper}/preprocessor_config.json +0 -0
LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
BSD 3-Clause License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2022, Yuan Gong
|
| 4 |
+
All rights reserved.
|
| 5 |
+
|
| 6 |
+
Redistribution and use in source and binary forms, with or without
|
| 7 |
+
modification, are permitted provided that the following conditions are met:
|
| 8 |
+
|
| 9 |
+
1. Redistributions of source code must retain the above copyright notice, this
|
| 10 |
+
list of conditions and the following disclaimer.
|
| 11 |
+
|
| 12 |
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
| 13 |
+
this list of conditions and the following disclaimer in the documentation
|
| 14 |
+
and/or other materials provided with the distribution.
|
| 15 |
+
|
| 16 |
+
3. Neither the name of the copyright holder nor the names of its
|
| 17 |
+
contributors may be used to endorse or promote products derived from
|
| 18 |
+
this software without specific prior written permission.
|
| 19 |
+
|
| 20 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 21 |
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 22 |
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 23 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 24 |
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 25 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 26 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 27 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 28 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 29 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
README.md
CHANGED
|
@@ -1,144 +1,196 @@
|
|
| 1 |
---
|
| 2 |
tags:
|
| 3 |
- speech
|
| 4 |
-
- whisper
|
| 5 |
-
- forced-alignment
|
| 6 |
- pronunciation-assessment
|
| 7 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
license: other
|
| 9 |
---
|
| 10 |
|
| 11 |
-
#
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
-
|
| 22 |
-
|
| 23 |
-
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
- `examples/infer_one_audio.py`: one-audio inference example.
|
| 29 |
-
|
| 30 |
-
## Download
|
| 31 |
|
| 32 |
-
|
| 33 |
-
from
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
-
|
| 36 |
-
repo_id="faeea/custom-gopt-252-eval",
|
| 37 |
-
repo_type="model",
|
| 38 |
-
local_dir="./hf_models/custom-gopt-252-eval",
|
| 39 |
-
)
|
| 40 |
-
```
|
| 41 |
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
```bash
|
| 45 |
-
|
|
|
|
| 46 |
```
|
| 47 |
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
-
|
| 53 |
-
git clone https://github.com/hf49w/custom-gopt.git
|
| 54 |
-
git clone https://github.com/lingjzhu/charsiu third_party/charsiu_repo
|
| 55 |
-
git -C third_party/charsiu_repo checkout 13a69f2a22ca0c0962b75cc693399b0ae23a12c9
|
| 56 |
-
```
|
| 57 |
-
|
| 58 |
-
Install the project dependencies in the `custom-gopt` repository, then install the small extra NLTK assets used by Charsiu/G2P:
|
| 59 |
|
| 60 |
-
```
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
```
|
| 65 |
|
| 66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
|
| 68 |
```bash
|
| 69 |
-
python
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
--repo-root /path/to/custom-gopt \
|
| 73 |
-
--charsiu-src-dir /path/to/third_party/charsiu_repo \
|
| 74 |
-
--device cuda \
|
| 75 |
-
--output-json ./one_audio_score.json
|
| 76 |
-
```
|
| 77 |
-
|
| 78 |
-
Use `--device cpu` when CUDA is unavailable.
|
| 79 |
-
|
| 80 |
-
The example accepts an English short utterance audio file. A mono 16 kHz WAV is preferred; other sample rates are resampled inside the script.
|
| 81 |
-
|
| 82 |
-
## Output Meaning
|
| 83 |
-
|
| 84 |
-
The Streaming GOPT model forward pass returns:
|
| 85 |
-
|
| 86 |
-
- `u1`: utterance-level accuracy.
|
| 87 |
-
- `u2`: utterance-level completeness.
|
| 88 |
-
- `u3`: utterance-level fluency.
|
| 89 |
-
- `u4`: utterance-level prosodic score.
|
| 90 |
-
- `u5`: utterance-level total score.
|
| 91 |
-
- `p`: phone-level pronunciation score for each visible phone token.
|
| 92 |
-
- `w1`: word-level accuracy.
|
| 93 |
-
- `w2`: word-level stress.
|
| 94 |
-
- `w3`: word-level total score.
|
| 95 |
-
- `w4`: word-level ASR accuracy.
|
| 96 |
-
|
| 97 |
-
The example script reports the user-facing utterance scores as:
|
| 98 |
-
|
| 99 |
-
```json
|
| 100 |
-
{
|
| 101 |
-
"utterance_scores": {
|
| 102 |
-
"accuracy": 8.4,
|
| 103 |
-
"completeness": 10.0,
|
| 104 |
-
"fluency": 8.3,
|
| 105 |
-
"prosodic": 7.9,
|
| 106 |
-
"total": 8.0
|
| 107 |
-
},
|
| 108 |
-
"overall_score": 8.0
|
| 109 |
-
}
|
| 110 |
```
|
| 111 |
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
-
|
| 133 |
-
-
|
| 134 |
-
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
tags:
|
| 3 |
- speech
|
|
|
|
|
|
|
| 4 |
- pronunciation-assessment
|
| 5 |
+
- streaming
|
| 6 |
+
- whisper
|
| 7 |
+
- charsiu
|
| 8 |
+
language:
|
| 9 |
+
- en
|
| 10 |
license: other
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# StreamPA
|
| 14 |
+
|
| 15 |
+
Frozen StreamPA pronunciation-assessment inference: fine-tuned Whisper Base
|
| 16 |
+
N-best -> G2P / prefix-local Charsiu / PCN / prosody -> slot and utterance scores.
|
| 17 |
+
This is a downloadable, multi-component Python system, not a hosted endpoint
|
| 18 |
+
or a standard Transformers `AutoModel`/`pipeline` implementation.
|
| 19 |
+
|
| 20 |
+
## Published identity
|
| 21 |
+
|
| 22 |
+
* Experiment: `M_stress_scalar_gate_capacity64` (Ours-M), primary seed **1337**.
|
| 23 |
+
* Original checkpoint SHA256:
|
| 24 |
+
`870df8dbe3c787487f094e0c4d4ade6bed8fcc5d86b578c4edc57581e81023b4`.
|
| 25 |
+
* All original tensors are retained losslessly in `scorer/model.safetensors`.
|
| 26 |
+
Strict loading retains the historical inactive `utt_head`; the active
|
| 27 |
+
utterance path is the frozen `gru_visible` head.
|
| 28 |
+
* 64 hidden dimensions, three local-attention blocks, four heads, scalar
|
| 29 |
+
reliability gate, detached stress branch, 64-dimensional recurrent state.
|
| 30 |
+
Inputs: 40 phone columns including epsilon, 14 global prosody features,
|
| 31 |
+
17 slot prosody features, and at most **72 PCN slots**.
|
| 32 |
+
* The included Whisper weights are the actual fine-tuned Base checkpoint,
|
| 33 |
+
SHA256 `8917c9612b44f73bb5ef2ffec48cf44a4ee0dfa5a94af25e9e6710b9fd66a17f`.
|
| 34 |
+
They must not be replaced with generic Whisper Base. Beam size 8, N-best 5,
|
| 35 |
+
maximum 128 decoded tokens; original hypothesis-score computation retained.
|
| 36 |
+
* The paper's four-seed aggregate (1337, 202601, 202602, 202603) is not the
|
| 37 |
+
performance of this single checkpoint. No unverified paper metric is copied
|
| 38 |
+
into this card. Interface tests do not establish assessment PCC.
|
| 39 |
+
|
| 40 |
+
## Download and install
|
| 41 |
+
|
| 42 |
+
Verified platform: **Python 3.10 on Ubuntu in local Windows WSL2, CPU FP32**.
|
| 43 |
+
Native Windows and GPU inference are not part of the verified platform.
|
| 44 |
+
Use a new Python 3.10 environment. The fixed release tag below is created only
|
| 45 |
+
after fresh Hub-download inference verification succeeds.
|
| 46 |
|
| 47 |
+
```bash
|
| 48 |
+
python3.10 -m venv .venv-streampa
|
| 49 |
+
source .venv-streampa/bin/activate
|
| 50 |
+
python -m pip install huggingface_hub==0.36.0
|
| 51 |
+
python -c "from huggingface_hub import snapshot_download; snapshot_download('faeea/StreamPA', revision='streampa-v1.0.0', local_dir='./StreamPA')"
|
| 52 |
+
cd StreamPA
|
| 53 |
+
python -m pip install --extra-index-url https://download.pytorch.org/whl/cpu -r requirements-lock.txt
|
| 54 |
+
python -m pip install --no-deps --no-build-isolation .
|
| 55 |
+
python scripts/setup_assets.py
|
| 56 |
+
python scripts/verify_bundle.py
|
| 57 |
+
```
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
+
The public bundle contains the scorer and fine-tuned Whisper weights. Setup
|
| 60 |
+
downloads Charsiu and G2P resources from official, **fixed revisions**, checks
|
| 61 |
+
their SHA256s, and installs them inside this bundle. There is no runtime
|
| 62 |
+
reference to a training checkout or private server. See `THIRD_PARTY_NOTICES.md`
|
| 63 |
+
for licenses and third-party weight terms. Internet is needed for initial
|
| 64 |
+
installation/setup, not for subsequent inference. No author token is required
|
| 65 |
+
for the public release or its official runtime resources.
|
| 66 |
|
| 67 |
+
## One WAV and streaming CLI
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
+
Input: your own English **mono 16,000-Hz WAV**, no transcript or labels.
|
| 70 |
+
The frontend supports at most 30 seconds per recording and 72 current PCN
|
| 71 |
+
slots; longer inputs return an explicit error/status, never hidden truncation.
|
| 72 |
+
Output files must not already exist.
|
| 73 |
|
| 74 |
```bash
|
| 75 |
+
python -m streampa.infer --audio /path/to/demo.wav --bundle-dir . --device cpu --output scores.json
|
| 76 |
+
python -m streampa.stream --audio /path/to/demo.wav --bundle-dir . --device cpu --output prefixes.jsonl
|
| 77 |
```
|
| 78 |
|
| 79 |
+
The single-file CLI returns all prefixes plus the EOF result. The streaming
|
| 80 |
+
CLI actually reads and appends waveform blocks, then signals EOF. Both run
|
| 81 |
+
the same causal implementation. CLI block size does not change the fixed
|
| 82 |
+
0.64-second schedule and 0.16-second lookahead.
|
| 83 |
|
| 84 |
+
For an appropriate CUDA installation, select one device externally and use
|
| 85 |
+
`--device cuda`. Do not use a broken/busy device. The inherited frontend uses
|
| 86 |
+
FP16 Whisper on CUDA, FP32 Charsiu/scorer; CPU is FP32 throughout. CUDA is
|
| 87 |
+
**untested in this release validation**, and changing precision can change ASR
|
| 88 |
+
decoding. The CPU lockfile deliberately selects CPU PyTorch.
|
| 89 |
|
| 90 |
+
## Python sessions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
+
```python
|
| 93 |
+
import soundfile as sf
|
| 94 |
+
from streampa import StreamPAPipeline
|
| 95 |
+
|
| 96 |
+
pipeline = StreamPAPipeline('./StreamPA', device='cpu', threads=2)
|
| 97 |
+
session = pipeline.create_session()
|
| 98 |
+
with sf.SoundFile('demo.wav') as f:
|
| 99 |
+
assert f.samplerate == 16000 and f.channels == 1
|
| 100 |
+
while True:
|
| 101 |
+
block = f.read(1600, dtype='float32') # 100 ms received audio
|
| 102 |
+
if len(block) == 0:
|
| 103 |
+
break
|
| 104 |
+
for result in session.append(block):
|
| 105 |
+
print(result['audio_end'], result['status'], result['scores'])
|
| 106 |
+
print(session.finish()) # process the exact EOF, including a short final block
|
| 107 |
+
session.reset() # required before a new recording in this session
|
| 108 |
+
assert session.current() is None
|
| 109 |
```
|
| 110 |
|
| 111 |
+
The pipeline owns frozen models; sessions have separate audio and recurrent
|
| 112 |
+
state. Use sessions sequentially (concurrent GPU service scheduling is not
|
| 113 |
+
provided). `StreamPAPipeline.from_pretrained(repo_id, revision=...)` is also
|
| 114 |
+
implemented, but its downloaded directory must have `setup_assets.py` run
|
| 115 |
+
before loading; use the explicit local-bundle example for first setup.
|
| 116 |
+
|
| 117 |
+
## JSON and state semantics
|
| 118 |
+
|
| 119 |
+
* `commit_time`: scheduling boundary; `audio_end`: exact prefix waveform end
|
| 120 |
+
supplied to **every** frontend; `received_audio_end`: audio received by the
|
| 121 |
+
caller so far, which may be later when a block spans multiple boundaries.
|
| 122 |
+
A normal prefix is processed only after `commit_time + 0.16` is received.
|
| 123 |
+
EOF alone defines the final endpoint. No reference boundary is consulted.
|
| 124 |
+
* `slots`: raw independent phone-head and word-head predictions per current
|
| 125 |
+
PCN slot, ASR word assignment, slot time, validity and commitment masks.
|
| 126 |
+
Epsilon/gap slots are retained; `valid_phone=false` means their phone score
|
| 127 |
+
is not a localized phone assessment. `asr_word_id=-1` has no word assignment.
|
| 128 |
+
* `words`: mean **word-head** predictions over visible slots assigned to each
|
| 129 |
+
current ASR word. This is a presentation aggregation, not mean phone accuracy.
|
| 130 |
+
It is not the paper's offline reference-word-identity evaluation. ASR words
|
| 131 |
+
and scores may be revised at later prefixes, including committed words.
|
| 132 |
+
* `new_commit_mask`: the frozen legacy boundary-aware state-update rule.
|
| 133 |
+
Only newly committed word representations are consumed by the GRU. With
|
| 134 |
+
no new words the persistent state remains unchanged, but visible features
|
| 135 |
+
still enter the sentence head and may change current utterance scores.
|
| 136 |
+
This heuristic has **no formal exactly-once guarantee** for every possible
|
| 137 |
+
mixed predecessor merge. It is not silently replaced with a corrected rule.
|
| 138 |
+
* `scores.utterance_network_raw` retains native model outputs, including the
|
| 139 |
+
untrained completeness dimension for audit only. Displayed utterance scores
|
| 140 |
+
omit completeness. ASR confidence is not a probability of correct pronunciation.
|
| 141 |
+
* Historical target normalization divides all source scores by 5: native
|
| 142 |
+
word/utterance source scores span 0--10; phone source scores span 0--2.
|
| 143 |
+
Thus displayed 0--5 word/utterance = network output x 2.5, and phone = network
|
| 144 |
+
output x 12.5. Outputs are **not clipped**; out-of-range estimates remain
|
| 145 |
+
visible. Stress has a trained head but is not a calibrated correctness probability.
|
| 146 |
+
* `status != 'ok'` returns `scores=null`, never a false zero grade. Statuses
|
| 147 |
+
include empty/too-short/silent audio, no usable hypothesis, G2P/alignment/
|
| 148 |
+
acoustic failures, nonfinite values and unsupported slot length. Failed
|
| 149 |
+
prefixes remain in the output; previously successful state is preserved.
|
| 150 |
+
* `stages` and `wall_time_sec` measure actual local computation, not capture
|
| 151 |
+
waiting or a universal real-time guarantee. Model loading is separate.
|
| 152 |
+
|
| 153 |
+
## Offline operation and checks
|
| 154 |
|
| 155 |
```bash
|
| 156 |
+
python scripts/setup_assets.py --offline
|
| 157 |
+
HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 python -m streampa.infer --audio /path/to/demo.wav --bundle-dir . --device cpu --output offline_scores.json
|
| 158 |
+
python -m pytest tests -q
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
```
|
| 160 |
|
| 161 |
+
Keep the entire prepared bundle, including `charsiu/` and `assets/nltk_data/`.
|
| 162 |
+
Do not delete those setup-generated directories when preparing an offline copy.
|
| 163 |
+
For hash mismatch, stop and re-download the specified revision rather than
|
| 164 |
+
replacing a resource with another model. Missing G2P/tagger resources require
|
| 165 |
+
`setup_assets.py`; inference does not intentionally download them. Proxy
|
| 166 |
+
configuration may be needed during setup in restricted networks. Use a fresh
|
| 167 |
+
output filename for each command. Convert sample rate/channels before opening
|
| 168 |
+
a session; the inference entry point does not resample a hidden full recording.
|
| 169 |
+
|
| 170 |
+
## Scope and limitations
|
| 171 |
+
|
| 172 |
+
Inference accepts audio only. Training used human annotations and teacher
|
| 173 |
+
supervision. Historical evaluation data were selected by preprocessing filters
|
| 174 |
+
and predominantly contain read speech. Deployment removes the historical
|
| 175 |
+
reference-phone-count ratio filter and uses received-audio/EOF scheduling;
|
| 176 |
+
it does not claim to reproduce historical test membership or PCC on arbitrary
|
| 177 |
+
WAVs. The frozen dictionary is a corpus-derived pronunciation vocabulary, not
|
| 178 |
+
an utterance-specific reference transcript. Original PCN gap semantics,
|
| 179 |
+
alignment, normalization, repetition filtering and legacy commitment are retained.
|
| 180 |
+
|
| 181 |
+
No claim of validated spontaneous/open-ended speech generalization, formal
|
| 182 |
+
exactly-once commitment, GRU-induced stability improvement, or end-to-end
|
| 183 |
+
real-time performance is made. Synthetic validation clips test computation
|
| 184 |
+
and interfaces, not pronunciation-assessment accuracy. See
|
| 185 |
+
`validation_summary.json` for actually completed and untested checks.
|
| 186 |
+
|
| 187 |
+
Observed interface-test limitation: several short prefixes produce repeated
|
| 188 |
+
Whisper hypotheses and are explicitly unscorable. A synthetic "Good morning"
|
| 189 |
+
clip was unscorable at all three prefixes; three separately selected licensed
|
| 190 |
+
read-speech clips all produced valid EOF scores, with 9 valid prefixes out of
|
| 191 |
+
15 attempted. These failures were not hidden or repaired by changing decoding.
|
| 192 |
+
CPU frontend computation was much slower than the audio duration in these tests.
|
| 193 |
+
|
| 194 |
+
The old v6 47-feature system remains historical only at
|
| 195 |
+
`faeea/StreamPA`, revision `legacy-v6-before-streampa`. It is not this checkpoint
|
| 196 |
+
and must not be mixed with these configurations or entry points.
|
README_zh.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# StreamPA 使用说明
|
| 2 |
+
|
| 3 |
+
这是冻结的 Ours-M / `M_stress_scalar_gate_capacity64`,默认 seed 1337。
|
| 4 |
+
它不是旧版 v6 的 47 维 Streaming GOPT。发布的是可下载运行的多组件系统,
|
| 5 |
+
不是 HF 网页在线推理服务,也不提供虚构的 Transformers `AutoModel` 接口。
|
| 6 |
+
|
| 7 |
+
原 checkpoint SHA256:
|
| 8 |
+
`870df8dbe3c787487f094e0c4d4ade6bed8fcc5d86b578c4edc57581e81023b4`。
|
| 9 |
+
`model_manifest.json` 记录发布 tensor、配置、源文件和各组件身份。
|
| 10 |
+
scorer 的全部原 tensor 保留为 safetensors,没有训练、微调、量化或修改值。
|
| 11 |
+
|
| 12 |
+
## 安装
|
| 13 |
+
|
| 14 |
+
实际验证环境是本机 Windows 的 Ubuntu WSL2,Python 3.10,CPU FP32。
|
| 15 |
+
没有将服务器 Linux 测试写成 Windows 原生测试。Windows 原生和 CUDA 尚未验证。
|
| 16 |
+
首次需要联网安装依赖和下载官方固定版本的 Charsiu、词典与 NLTK 资源。
|
| 17 |
+
|
| 18 |
+
```bash
|
| 19 |
+
python3.10 -m venv .venv-streampa
|
| 20 |
+
source .venv-streampa/bin/activate
|
| 21 |
+
python -m pip install huggingface_hub==0.36.0
|
| 22 |
+
python -c "from huggingface_hub import snapshot_download; snapshot_download('faeea/StreamPA', revision='streampa-v1.0.0', local_dir='./StreamPA')"
|
| 23 |
+
cd StreamPA
|
| 24 |
+
python -m pip install --extra-index-url https://download.pytorch.org/whl/cpu -r requirements-lock.txt
|
| 25 |
+
python -m pip install --no-deps --no-build-isolation .
|
| 26 |
+
python scripts/setup_assets.py
|
| 27 |
+
python scripts/verify_bundle.py
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
Charsiu 权重未在本仓库重新分发,由 setup 从官方固定 revision 下载并验 hash。
|
| 31 |
+
微调 Whisper Base 则已在包内,不能替换为通用预训练 Whisper。各组件并非同一
|
| 32 |
+
许可证,详见 `THIRD_PARTY_NOTICES.md`。初始安装若需要网络代理,由用户环境设置,
|
| 33 |
+
包内不包含作者 token、代理密码或服务器路径。
|
| 34 |
+
|
| 35 |
+
## 最短完整推理
|
| 36 |
+
|
| 37 |
+
输入自己的英文、单声道、16 kHz WAV,不输入参考文本、音素数、GT 边界、分数或 teacher。
|
| 38 |
+
输出文件必须不存在,以免覆盖旧结果。
|
| 39 |
+
|
| 40 |
+
```bash
|
| 41 |
+
python -m streampa.infer --audio /path/to/demo.wav --bundle-dir . --device cpu --output scores.json
|
| 42 |
+
python -m streampa.stream --audio /path/to/demo.wav --bundle-dir . --device cpu --output prefixes.jsonl
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
单音频命令返回全部 prefix 和 EOF 分数;流式命令逐块读取音频,经过相同的调度和计算。
|
| 46 |
+
最大原始音频长度为 30 秒,最大当前 PCN 槽位数为 72。超限明确拒绝,不静默截断。
|
| 47 |
+
实际运行路径:收到的 prefix 音频 -> 微调 Whisper N-best -> G2P、Charsiu、PCN、prosody
|
| 48 |
+
-> StreamPA。没有用预计算预测代替模型运行。
|
| 49 |
+
|
| 50 |
+
## 会话 API
|
| 51 |
+
|
| 52 |
+
```python
|
| 53 |
+
from streampa import StreamPAPipeline
|
| 54 |
+
pipeline = StreamPAPipeline('./StreamPA', device='cpu', threads=2)
|
| 55 |
+
session = pipeline.create_session()
|
| 56 |
+
# block 是实际已收到的、16 kHz 单声道 float32 波形数组
|
| 57 |
+
for result in session.append(block):
|
| 58 |
+
print(result)
|
| 59 |
+
print(session.current())
|
| 60 |
+
print(session.finish()) # 调用方 EOF,处理最后不足一个 chunk 的音频
|
| 61 |
+
session.reset() # 新录音前必须重置,清空音频、提交历史和 GRU state
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
完整可执行逐块示例:`python examples/session.py --bundle-dir . --audio demo.wav`。
|
| 65 |
+
不同 session 的 state 独立;当前包不提供多线程服务调度,建议顺序调用。
|
| 66 |
+
|
| 67 |
+
## 如何读输出
|
| 68 |
+
|
| 69 |
+
- `commit_time` 每 0.64 秒推进,普通 prefix 等收到额外 0.16 秒 lookahead 才处理。
|
| 70 |
+
`audio_end` 是每个前端实际得到的波形末端;`received_audio_end` 可能因整块到达而更晚,
|
| 71 |
+
但前端不能读取更晚部分。EOF 由调用方决定,不从参考标注推导。
|
| 72 |
+
- `slots` 保留原始独立 phone head 与 word head 输出、当前 ASR 词归属、时间、mask。
|
| 73 |
+
epsilon/gap 槽位保留;`valid_phone=false` 时不能作为有效局部音素评分。
|
| 74 |
+
- `words` 按当前 ASR word ID,平均该词可见槽位的 **word head** 输出用于显示。
|
| 75 |
+
不是平均 phone accuracy,不等同论文按 reference word ID 的共同单元评价。
|
| 76 |
+
- GRU 只消费 `new_commit_mask` 对应的新词。没有任何新词时 persistent state 不变,
|
| 77 |
+
但 visible 表示仍进入句级 head,所以句级分数仍可能变化。已提交词不代表其评分永远不变。
|
| 78 |
+
- 保留冻结的 legacy commitment,包括复杂 mixed merge 下的已知限制。
|
| 79 |
+
不声称“每一个完成词均有形式化 exactly-once 保证”,没有偷偷换成 corrected 规则。
|
| 80 |
+
- 原训练把源标签除以 5;词和句源尺度为 0--10、音素源尺度为 0--2。
|
| 81 |
+
显示成 0--5 时,词/句网络输出乘 2.5,音素网络输出乘 12.5。不裁剪超界估计。
|
| 82 |
+
原始网络输出同时保留。completeness 未参与训练,只在 raw 审计字段保留,不显示为可靠评分。
|
| 83 |
+
- 非 `ok` 状态给 `scores=null`,包括空音频、静音、无可用假设、对齐失败、超限等。
|
| 84 |
+
不用零分代替失败,不静默删掉失败 prefix。ASR confidence 也不等于“读对的概率”。
|
| 85 |
+
|
| 86 |
+
## 离线和性能
|
| 87 |
+
|
| 88 |
+
```bash
|
| 89 |
+
python scripts/setup_assets.py --offline
|
| 90 |
+
HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 python -m streampa.infer --audio demo.wav --bundle-dir . --device cpu --output offline_scores.json
|
| 91 |
+
python -m pytest tests -q
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
离线复制时保留整个已准备好的 bundle,包括 setup 产生的 `charsiu/` 与
|
| 95 |
+
`assets/nltk_data/`。依赖缺失先补 setup,不要用别的权重替换。
|
| 96 |
+
`stages` 分开记录前端与 scorer 的计算时间;不把文件读取测试声称为包含真实采集等待的
|
| 97 |
+
端到端实时实验。CUDA 分支保留原 Whisper FP16 行为,Charsiu/scorer FP32,但尚未验证。
|
| 98 |
+
|
| 99 |
+
## 论文与部署边界
|
| 100 |
+
|
| 101 |
+
发布 seed 1337 不等于论文四 seed 均值。接口测试音频不证明论文 PCC。
|
| 102 |
+
训练使用人工监督和 teacher;历史评测样本经过预处理筛选,主要来自朗读数据。
|
| 103 |
+
部署移除了历史参考音素长度比例筛选,并使用 audio/EOF 调度;这一差异已明确记录,
|
| 104 |
+
不声称任意 WAV 会复现历史样本集合和指标。词典只是通用词到音素的静态资源,
|
| 105 |
+
不按当前录音读取其标准文本。未验证自发开放回答泛化,不宣称 GRU/稳定性 loss 的
|
| 106 |
+
直接稳定性机制已获得证明。
|
| 107 |
+
|
| 108 |
+
旧 v6 历史版本保留在 `faeea/StreamPA` 的 `legacy-v6-before-streampa` revision;
|
| 109 |
+
其权重、结构和调用方法不能与本包混用。实际已通过和未测试项目见 `validation_summary.json`。
|
SHA256SUMS
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
d501f3b58c954ae35e9dac25422a1a4e1dc8a24be3de27c8feedfe383726e52c LICENSE
|
| 2 |
+
52d8113ecf4424695f4a967fcd8174693642659c3110cb044ab8458bc5d41ddc README.md
|
| 3 |
+
939a3e3859cc8edf2e4472b73b1068771cbfb8682e75631cdc0c0de95bb3ec4b README_zh.md
|
| 4 |
+
b10037f3f89563db6e3cea1d0872a7d8c6bf648798d13e643682bc95d40ac585 THIRD_PARTY_NOTICES.md
|
| 5 |
+
34d6a3fd820daf67d0f46d71c71bab83e2f4fe0a714e580098ce1b8981d19932 assets/phn_dict.json
|
| 6 |
+
3eae62ec67d23c40bd672a3e933ff68f20a5466286956c46cf5933d302a465a6 assets/prepared_resource_hashes.json
|
| 7 |
+
5d6f12bce4a61905d8fe2b78474bb9a6741f6165f40f390f6041d975a5dd06a2 assets/pronunciation_lexicon.json
|
| 8 |
+
5162cca670853595e2883504e55e74465f0921f643a43246b16b4ba3818389c7 assets/runtime_sources.json
|
| 9 |
+
3b74d2f27f7723852677f5acaa5a5fd1271129fc426e6f3cf29a0be41fdf9cb3 examples/session.py
|
| 10 |
+
77fd4710def9ec3c0f6225800e0235f15a425abd4a8b03559127fcd782612049 licenses/Apache-2.0.txt
|
| 11 |
+
a622a386b2acb06e150e16c26fb93ff6c09b3096eb1d84aa5b6436ac6c52f6bc licenses/Charsiu-MIT.txt
|
| 12 |
+
b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1 licenses/G2P-Apache-2.0.txt
|
| 13 |
+
b5d65a59060e68c4ff940e1eddfa6f94b2d68fdf58ed7f4dd57721c997e35e9d licenses/Whisper-MIT.txt
|
| 14 |
+
daa6056f84581c2311acbeaf4d5aff7df5c4aacb4fa23a7f788876257ce43efe model_manifest.json
|
| 15 |
+
f4350f936a2483da11f024c60b36915c21852431904a72908a544884a7afcfa1 pyproject.toml
|
| 16 |
+
dafdbd306609bf108a4b7b44b3c29fa263fdf3ba157824d31a9bde9ba19659d9 requirements-lock.txt
|
| 17 |
+
d508e880fff94cfc882109a1acc5122ea4c442bdc055114780d5c17b8ae1d026 scorer/config.json
|
| 18 |
+
49c772a0428649c7f676913847d978d4139e4bcaea39acbe83ac834c819dd0a9 scorer/inference_assets.json
|
| 19 |
+
26b2f4a90b90e997ceb2eae9df2f09166a9173c1297c53ef26b4b843eb778583 scorer/model.safetensors
|
| 20 |
+
b0d43d81486bd7c5216a032a21b9b9521838dd4460cb10cd627e466f3b80d284 scripts/setup_assets.py
|
| 21 |
+
e7b8437efd1496d8717720a5c58776f3b30c0550ea11a4642a1e600ee9961a88 scripts/verify_bundle.py
|
| 22 |
+
375cbd9410f7bff742e7e49c0aaf8b9a6ba04e3a7e9a8869e115a5bfa8074282 streampa/__init__.py
|
| 23 |
+
742be32f8decb995a9deb75a2a9d841f69f4eebb0c8dedcc2d1f204b1244ddc3 streampa/charsiu_model.py
|
| 24 |
+
be2e7dd491614553fee0beba238cf6bf66a0f59f2c1ace6b9972151ac22daf74 streampa/frontend.py
|
| 25 |
+
70e3b07c3f8ec862c56b8c1e3c8df3ebc5afaba412a404bb7238484793b83ccf streampa/infer.py
|
| 26 |
+
40838175655baa4996aef7c20066b71c77406b1b811282f793c0c97b948b3058 streampa/pipeline.py
|
| 27 |
+
efdeb871324aa0bdacd0f6cf43e926ddbcec3103c77a7256bf617b656b9d0500 streampa/stream.py
|
| 28 |
+
3643ef2e07ff94dc7dc6e829b825680f73c9846d95a21f88189cb5ce6b0dab68 streampa/streaming_gopt.py
|
| 29 |
+
1794fa024a698babbdfca90dfc9091d0a7ec051215461870c9f0b597ccee16fd streampa/streaming_pcn_gopt.py
|
| 30 |
+
000ae55e222f6b246dd337a8b7eecda520e34308bd7bac4f7e6e90c47c6c6153 tests/test_runtime.py
|
| 31 |
+
0c3b548f54cbb8e54aea347bce2fc75f56368bf30b90bd2b42252eb4b5e1bd15 validation_summary.json
|
| 32 |
+
9715fd2243b6f06a5858b5e32950d2853f73dd5bc201aafcf76f5082a2d8acd1 whisper/added_tokens.json
|
| 33 |
+
8dfbe1b3c46fa95ddde6cff3c53ece3b09a050182b152c64da5d90fe7eb68ea1 whisper/config.json
|
| 34 |
+
7b226ee4c0ea765809d5adb7959e76ca53da1202ca5a67c956bf3221979d2d53 whisper/generation_config.json
|
| 35 |
+
2df2990a395e35e8dfbc7511e08c12d56018d8d04691e0133e5d63b21e154dc6 whisper/merges.txt
|
| 36 |
+
8917c9612b44f73bb5ef2ffec48cf44a4ee0dfa5a94af25e9e6710b9fd66a17f whisper/model.safetensors
|
| 37 |
+
bf1c507dc8724ca9cf9903640dacfb69dae2f00edee4f21ceba106a7392f26dd whisper/normalizer.json
|
| 38 |
+
994838f1fa6462c8b9b3c90edada831f11f3dd8b4664634e18f4694d005c9dbf whisper/preprocessor_config.json
|
| 39 |
+
e67ae3a0aaa99abcd9f187138e12db1f65c16a14761c50ef10eef2c174a7a691 whisper/special_tokens_map.json
|
| 40 |
+
21a4fc0483c14b87f4e0bbc177a9a357479bfa7c95aaf21ad53d71e9c5afafb9 whisper/tokenizer_config.json
|
| 41 |
+
50d6a919f0a0601d56a04eb583c780d18553aa388254ba3158eb6a00f13e2c1a whisper/vocab.json
|
THIRD_PARTY_NOTICES.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Third-party notices and redistribution scope
|
| 2 |
+
|
| 3 |
+
This is a multi-component release, not a claim that every component shares one
|
| 4 |
+
license. The Hub card retains `license: other`; consult the component sources.
|
| 5 |
+
|
| 6 |
+
* GOPT-derived scorer and preprocessing source retain the original project's
|
| 7 |
+
BSD-3-Clause notice (`LICENSE`, copyright Yuan Gong, 2022). The published
|
| 8 |
+
scorer is the publisher's frozen StreamPA checkpoint, not the original GOPT
|
| 9 |
+
model and not the legacy v6 release. No training data or optimizer is bundled.
|
| 10 |
+
* The publisher's fine-tuned Whisper Base weights and their actual tokenizer
|
| 11 |
+
and processor are included. OpenAI's Whisper project publishes code and
|
| 12 |
+
model weights under MIT (`licenses/Whisper-MIT.txt`); the Transformers Hub
|
| 13 |
+
[Whisper Base card](https://huggingface.co/openai/whisper-base) labels its
|
| 14 |
+
converted distribution Apache-2.0. Both upstream notices are retained.
|
| 15 |
+
The included fine-tune is not interchangeable with generic Whisper Base.
|
| 16 |
+
* Charsiu frame-classifier code is from `lingjzhu/charsiu` commit
|
| 17 |
+
`13a69f2a22ca0c0962b75cc693399b0ae23a12c9`, under its MIT notice
|
| 18 |
+
(`licenses/Charsiu-MIT.txt`). The Charsiu weight repository does not expose
|
| 19 |
+
sufficiently explicit weight-redistribution terms for this release to
|
| 20 |
+
assign it a license. Its weights/tokenizer are **not redistributed here**.
|
| 21 |
+
`scripts/setup_assets.py` retrieves their official fixed revisions listed
|
| 22 |
+
in `assets/runtime_sources.json`; users must check the upstream terms.
|
| 23 |
+
* The pronunciation lexicon contains only isolated normalized word-to-phone
|
| 24 |
+
entries required by the frozen frontend. It is derived from
|
| 25 |
+
[speechocean762](https://www.openslr.org/101/), released by Beijing
|
| 26 |
+
Speechocean and Microsoft under CC BY 4.0. It omits utterance IDs, ordered
|
| 27 |
+
transcripts, recordings, boundaries and human scores. The normalization
|
| 28 |
+
and deduplication are adaptations. Attribution: Zhang et al.,
|
| 29 |
+
*speechocean762: An Open-Source Non-native English Speech Corpus For
|
| 30 |
+
Pronunciation Assessment* (2021), https://arxiv.org/abs/2104.01378 .
|
| 31 |
+
CC BY 4.0: https://creativecommons.org/licenses/by/4.0/ .
|
| 32 |
+
* g2p-en 2.1.0 is installed from its official package (Apache-2.0 notice in
|
| 33 |
+
`licenses/G2P-Apache-2.0.txt`). Its runtime uses NLTK CMUdict and English
|
| 34 |
+
POS tagger resources. They are fetched from a fixed `nltk/nltk_data`
|
| 35 |
+
revision, with individual SHA256s, rather than redistributed as corpus
|
| 36 |
+
archives here. Refer to their bundled notices and
|
| 37 |
+
https://github.com/nltk/nltk_data/blob/gh-pages/DATASET-LICENSES.md .
|
| 38 |
+
* PyTorch, Transformers, NumPy, librosa, SoundFile, NLTK and safetensors are
|
| 39 |
+
separately installed packages, each subject to its own upstream license.
|
| 40 |
+
|
| 41 |
+
Synthetic verification audio stays outside the public bundle. This release
|
| 42 |
+
does not distribute private recordings, human assessment labels, experiment
|
| 43 |
+
predictions, proprietary corpus archives or third-party optimizer states.
|
assets/phn_dict.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"W": 0,
|
| 3 |
+
"IY": 1,
|
| 4 |
+
"K": 2,
|
| 5 |
+
"AO": 3,
|
| 6 |
+
"L": 4,
|
| 7 |
+
"IH": 5,
|
| 8 |
+
"T": 6,
|
| 9 |
+
"B": 7,
|
| 10 |
+
"EH": 8,
|
| 11 |
+
"R": 9,
|
| 12 |
+
"Z": 10,
|
| 13 |
+
"OW": 11,
|
| 14 |
+
"TH": 12,
|
| 15 |
+
"F": 13,
|
| 16 |
+
"AY": 14,
|
| 17 |
+
"V": 15,
|
| 18 |
+
"AH": 16,
|
| 19 |
+
"N": 17,
|
| 20 |
+
"UW": 18,
|
| 21 |
+
"S": 19,
|
| 22 |
+
"G": 20,
|
| 23 |
+
"AA": 21,
|
| 24 |
+
"M": 22,
|
| 25 |
+
"P": 23,
|
| 26 |
+
"NG": 24,
|
| 27 |
+
"HH": 25,
|
| 28 |
+
"EY": 26,
|
| 29 |
+
"SH": 27,
|
| 30 |
+
"AE": 28,
|
| 31 |
+
"D": 29,
|
| 32 |
+
"UH": 30,
|
| 33 |
+
"AW": 31,
|
| 34 |
+
"DH": 32,
|
| 35 |
+
"ER": 33,
|
| 36 |
+
"Y": 34,
|
| 37 |
+
"JH": 35,
|
| 38 |
+
"CH": 36,
|
| 39 |
+
"OY": 37,
|
| 40 |
+
"ZH": 38
|
| 41 |
+
}
|
assets/prepared_resource_hashes.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"g2p_en_version": "2.1.0",
|
| 3 |
+
"g2p_files": [
|
| 4 |
+
{
|
| 5 |
+
"package_relative": "g2p_en/__init__.py",
|
| 6 |
+
"bytes": 21,
|
| 7 |
+
"sha256": "36ffae3e8f2cad9d285131c78963f690327f5046b5273dfecc52707659be949d"
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"package_relative": "g2p_en/checkpoint20.npz",
|
| 11 |
+
"bytes": 3342298,
|
| 12 |
+
"sha256": "b8af35e4596d8dd5836dfd3fe9b2ba4f97b9c311efe8879544cbcfcbd566d8c6"
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"package_relative": "g2p_en/expand.py",
|
| 16 |
+
"bytes": 2492,
|
| 17 |
+
"sha256": "b31f9f2173280f4479de1272d57540382d64496662ef127cf4d05af5a49d70db"
|
| 18 |
+
},
|
| 19 |
+
{
|
| 20 |
+
"package_relative": "g2p_en/g2p.py",
|
| 21 |
+
"bytes": 7637,
|
| 22 |
+
"sha256": "fc2548b855e102f774506a6afe4f4bc88424229b69701ab6040aa16710ddff3a"
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"package_relative": "g2p_en/homographs.en",
|
| 26 |
+
"bytes": 18711,
|
| 27 |
+
"sha256": "0403edcc6aefe8945f8987be398279fd98bf6b767e54b741331d3bc99a307071"
|
| 28 |
+
}
|
| 29 |
+
],
|
| 30 |
+
"prepared_resources": [
|
| 31 |
+
{
|
| 32 |
+
"path": "charsiu/model/config.json",
|
| 33 |
+
"bytes": 1522,
|
| 34 |
+
"sha256": "49b4e164f0375c7b0eaab8cf4d9727a20f1060e73bf0d899e2442ae95f70cae4"
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"path": "charsiu/model/pytorch_model.bin",
|
| 38 |
+
"bytes": 93368972,
|
| 39 |
+
"sha256": "a5b59d8cc3c548382dbc38c48d537b0bb520b9a67d2fafef2afee7740f9ce0c7"
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
"path": "charsiu/tokenizer/special_tokens_map.json",
|
| 43 |
+
"bytes": 85,
|
| 44 |
+
"sha256": "50eb73d51191696209d30d42d6ede50e57e7a542ca1db12df714b2c0aa3da8e2"
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"path": "charsiu/tokenizer/tokenizer_config.json",
|
| 48 |
+
"bytes": 180,
|
| 49 |
+
"sha256": "56e02b54de01a0ec4cc0c705ad3c303d7b73c83d61063a94b84cbf3a55da76a1"
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
"path": "charsiu/tokenizer/vocab.json",
|
| 53 |
+
"bytes": 403,
|
| 54 |
+
"sha256": "781514e251e9615ea4a05bbf3760ffcf8ec2ebe67355f411177ea64b0602d897"
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
"path": "assets/nltk_data/corpora/cmudict/README",
|
| 58 |
+
"bytes": 3808,
|
| 59 |
+
"sha256": "b0556be7a2b12bea6a667277b75864f802dd4854480657ce298c62e6897e766b"
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"path": "assets/nltk_data/corpora/cmudict/cmudict",
|
| 63 |
+
"bytes": 3820830,
|
| 64 |
+
"sha256": "cad209c39eb87677d64e93d97f8eed10b7e6f9bdd42de8e7ca8efc8e17d62e8a"
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"path": "assets/nltk_data/corpora/cmudict.zip",
|
| 68 |
+
"bytes": 896069,
|
| 69 |
+
"sha256": "d07cca47fd72ad32ea9d8ad1219f85301eeaf4568f8b6b73747506a71fb5afd6"
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"path": "assets/nltk_data/taggers/averaged_perceptron_tagger/averaged_perceptron_tagger.pickle",
|
| 73 |
+
"bytes": 6138625,
|
| 74 |
+
"sha256": "25a5a19c7ced7b2bac3831da5bc0afcc2c34e5dd01cd4f361bb799949a696238"
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"path": "assets/nltk_data/taggers/averaged_perceptron_tagger.zip",
|
| 78 |
+
"bytes": 2526731,
|
| 79 |
+
"sha256": "e1f13cf2532daadfd6f3bc481a49859f0b8ea6432ccdcd83e6a49a5f19008de9"
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"path": "assets/nltk_data/taggers/averaged_perceptron_tagger_eng/averaged_perceptron_tagger_eng.classes.json",
|
| 83 |
+
"bytes": 285,
|
| 84 |
+
"sha256": "d152ffa69d45b8357276341a3d592c6c025911d52ec0d9068d4f382560dd48b6"
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"path": "assets/nltk_data/taggers/averaged_perceptron_tagger_eng/averaged_perceptron_tagger_eng.tagdict.json",
|
| 88 |
+
"bytes": 25788,
|
| 89 |
+
"sha256": "4c713731cb06727736962bc8cd94ad919217a040e76691059af99bc0c2c9c246"
|
| 90 |
+
},
|
| 91 |
+
{
|
| 92 |
+
"path": "assets/nltk_data/taggers/averaged_perceptron_tagger_eng/averaged_perceptron_tagger_eng.weights.json",
|
| 93 |
+
"bytes": 5677744,
|
| 94 |
+
"sha256": "789e8e35f6fac656d9b7eccea29ba4e8a137cbb5b525dd31f39e4291a9e80832"
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
"path": "assets/nltk_data/taggers/averaged_perceptron_tagger_eng.zip",
|
| 98 |
+
"bytes": 1539115,
|
| 99 |
+
"sha256": "6025f530624335c67d6547d44757b357b4e79bae030a0383e9887a92c1718f0b"
|
| 100 |
+
}
|
| 101 |
+
]
|
| 102 |
+
}
|
assets/pronunciation_lexicon.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
assets/runtime_sources.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema": 1,
|
| 3 |
+
"sources": [
|
| 4 |
+
{
|
| 5 |
+
"kind": "hub",
|
| 6 |
+
"repo_id": "charsiu/en_w2v2_tiny_fc_10ms",
|
| 7 |
+
"revision": "8272e6ec07582696d212c2b15bdd271c92ae64ee",
|
| 8 |
+
"filename": "config.json",
|
| 9 |
+
"destination": "charsiu/model/config.json",
|
| 10 |
+
"sha256": "49b4e164f0375c7b0eaab8cf4d9727a20f1060e73bf0d899e2442ae95f70cae4",
|
| 11 |
+
"bytes": 1522
|
| 12 |
+
},
|
| 13 |
+
{
|
| 14 |
+
"kind": "hub",
|
| 15 |
+
"repo_id": "charsiu/en_w2v2_tiny_fc_10ms",
|
| 16 |
+
"revision": "8272e6ec07582696d212c2b15bdd271c92ae64ee",
|
| 17 |
+
"filename": "pytorch_model.bin",
|
| 18 |
+
"destination": "charsiu/model/pytorch_model.bin",
|
| 19 |
+
"sha256": "a5b59d8cc3c548382dbc38c48d537b0bb520b9a67d2fafef2afee7740f9ce0c7",
|
| 20 |
+
"bytes": 93368972
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"kind": "hub",
|
| 24 |
+
"repo_id": "charsiu/tokenizer_en_cmu",
|
| 25 |
+
"revision": "10507401aedf5e0aba164128535b49225ff95260",
|
| 26 |
+
"filename": "vocab.json",
|
| 27 |
+
"destination": "charsiu/tokenizer/vocab.json",
|
| 28 |
+
"sha256": "781514e251e9615ea4a05bbf3760ffcf8ec2ebe67355f411177ea64b0602d897",
|
| 29 |
+
"bytes": 403
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
"kind": "hub",
|
| 33 |
+
"repo_id": "charsiu/tokenizer_en_cmu",
|
| 34 |
+
"revision": "10507401aedf5e0aba164128535b49225ff95260",
|
| 35 |
+
"filename": "tokenizer_config.json",
|
| 36 |
+
"destination": "charsiu/tokenizer/tokenizer_config.json",
|
| 37 |
+
"sha256": "56e02b54de01a0ec4cc0c705ad3c303d7b73c83d61063a94b84cbf3a55da76a1",
|
| 38 |
+
"bytes": 180
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"kind": "hub",
|
| 42 |
+
"repo_id": "charsiu/tokenizer_en_cmu",
|
| 43 |
+
"revision": "10507401aedf5e0aba164128535b49225ff95260",
|
| 44 |
+
"filename": "special_tokens_map.json",
|
| 45 |
+
"destination": "charsiu/tokenizer/special_tokens_map.json",
|
| 46 |
+
"sha256": "50eb73d51191696209d30d42d6ede50e57e7a542ca1db12df714b2c0aa3da8e2",
|
| 47 |
+
"bytes": 85
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
"kind": "zip",
|
| 51 |
+
"url": "https://raw.githubusercontent.com/nltk/nltk_data/550b6625bcef1f2abff2ff770a5a0d272c9c6b2a/packages/corpora/cmudict.zip",
|
| 52 |
+
"destination": "assets/nltk_data/corpora/cmudict.zip",
|
| 53 |
+
"extract_to": "assets/nltk_data/corpora",
|
| 54 |
+
"sha256": "d07cca47fd72ad32ea9d8ad1219f85301eeaf4568f8b6b73747506a71fb5afd6",
|
| 55 |
+
"bytes": 896069
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"kind": "zip",
|
| 59 |
+
"url": "https://raw.githubusercontent.com/nltk/nltk_data/550b6625bcef1f2abff2ff770a5a0d272c9c6b2a/packages/taggers/averaged_perceptron_tagger.zip",
|
| 60 |
+
"destination": "assets/nltk_data/taggers/averaged_perceptron_tagger.zip",
|
| 61 |
+
"extract_to": "assets/nltk_data/taggers",
|
| 62 |
+
"sha256": "e1f13cf2532daadfd6f3bc481a49859f0b8ea6432ccdcd83e6a49a5f19008de9",
|
| 63 |
+
"bytes": 2526731
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"kind": "zip",
|
| 67 |
+
"url": "https://raw.githubusercontent.com/nltk/nltk_data/550b6625bcef1f2abff2ff770a5a0d272c9c6b2a/packages/taggers/averaged_perceptron_tagger_eng.zip",
|
| 68 |
+
"destination": "assets/nltk_data/taggers/averaged_perceptron_tagger_eng.zip",
|
| 69 |
+
"extract_to": "assets/nltk_data/taggers",
|
| 70 |
+
"sha256": "6025f530624335c67d6547d44757b357b4e79bae030a0383e9887a92c1718f0b",
|
| 71 |
+
"bytes": 1539115
|
| 72 |
+
}
|
| 73 |
+
]
|
| 74 |
+
}
|
bundle_manifest.json
DELETED
|
@@ -1,107 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"repo_id": "faeea/custom-gopt-252-eval",
|
| 3 |
-
"description": "Bundle of the v6 ASR-confidence Streaming GOPT checkpoint plus the Whisper and Charsiu models required by the local evaluation pipeline.",
|
| 4 |
-
"artifacts": [
|
| 5 |
-
{
|
| 6 |
-
"path": "streaming_gopt_best/best_audio_model.pth",
|
| 7 |
-
"type": "streaming_gopt_weights",
|
| 8 |
-
"purpose": "Pronunciation scoring model selected by validation phone MSE."
|
| 9 |
-
},
|
| 10 |
-
{
|
| 11 |
-
"path": "streaming_gopt_best/config.json",
|
| 12 |
-
"type": "streaming_gopt_config",
|
| 13 |
-
"purpose": "Network shape and training arguments used to restore the v6 ASR-confidence model."
|
| 14 |
-
},
|
| 15 |
-
{
|
| 16 |
-
"path": "streaming_gopt_best/result.csv",
|
| 17 |
-
"type": "training_metrics",
|
| 18 |
-
"purpose": "Per-epoch train/validation metrics."
|
| 19 |
-
},
|
| 20 |
-
{
|
| 21 |
-
"path": "streaming_gopt_best/test_metrics.json",
|
| 22 |
-
"type": "test_metrics",
|
| 23 |
-
"purpose": "Held-out test metrics for the best validation checkpoint."
|
| 24 |
-
},
|
| 25 |
-
{
|
| 26 |
-
"path": "streaming_gopt_best/inference_assets.json",
|
| 27 |
-
"type": "inference_metadata",
|
| 28 |
-
"purpose": "Normalization stats, feature dimension, and phone-id mapping required for one-audio local inference."
|
| 29 |
-
},
|
| 30 |
-
{
|
| 31 |
-
"path": "whisper_best_model",
|
| 32 |
-
"type": "transformers_whisper_model",
|
| 33 |
-
"purpose": "ASR model used to build ASR-driven GOPT chunks."
|
| 34 |
-
},
|
| 35 |
-
{
|
| 36 |
-
"path": "charsiu_en_w2v2_tiny_fc_10ms",
|
| 37 |
-
"type": "charsiu_aligner_model",
|
| 38 |
-
"purpose": "Frame-level phone alignment model used by preprocessing and inference."
|
| 39 |
-
},
|
| 40 |
-
{
|
| 41 |
-
"path": "examples/infer_one_audio.py",
|
| 42 |
-
"type": "example_script",
|
| 43 |
-
"purpose": "Minimal one-audio local inference script that prints utterance-level scores."
|
| 44 |
-
},
|
| 45 |
-
{
|
| 46 |
-
"path": "examples/eval_streaming_gopt_test.py",
|
| 47 |
-
"type": "example_script",
|
| 48 |
-
"purpose": "Minimal evaluation script for val/test split using the bundled best GOPT checkpoint."
|
| 49 |
-
}
|
| 50 |
-
],
|
| 51 |
-
"model_outputs": {
|
| 52 |
-
"utterance": [
|
| 53 |
-
"accuracy",
|
| 54 |
-
"completeness",
|
| 55 |
-
"fluency",
|
| 56 |
-
"prosodic",
|
| 57 |
-
"total"
|
| 58 |
-
],
|
| 59 |
-
"phone": [
|
| 60 |
-
"phone pronunciation score"
|
| 61 |
-
],
|
| 62 |
-
"word": [
|
| 63 |
-
"accuracy",
|
| 64 |
-
"stress",
|
| 65 |
-
"total",
|
| 66 |
-
"asr_accuracy"
|
| 67 |
-
],
|
| 68 |
-
"word_asr_accuracy_note": "The word-level ASR accuracy score can be used as an auxiliary indicator of whether the word was read correctly."
|
| 69 |
-
},
|
| 70 |
-
"best_validation_summary": {
|
| 71 |
-
"selection_metric": "phone_val_mse",
|
| 72 |
-
"best_epoch": 11,
|
| 73 |
-
"phone_val_mse": 0.04760764539241791,
|
| 74 |
-
"phone_val_pcc": 0.34831968338670993,
|
| 75 |
-
"utt_val_pcc_total": 0.661865583803676,
|
| 76 |
-
"word_val_pcc_total": 0.3418123225833971,
|
| 77 |
-
"word_val_pcc_asr_accuracy": 0.3633849619530143
|
| 78 |
-
},
|
| 79 |
-
"test_summary": {
|
| 80 |
-
"phone_test_mse": 0.04919730871915817,
|
| 81 |
-
"phone_test_pcc": 0.3975705055993251,
|
| 82 |
-
"utt_test_pcc": [
|
| 83 |
-
0.651909193610124,
|
| 84 |
-
0.012690043750859805,
|
| 85 |
-
0.7249977587357453,
|
| 86 |
-
0.7332794084754206,
|
| 87 |
-
0.681940037784353
|
| 88 |
-
],
|
| 89 |
-
"word_test_pcc": [
|
| 90 |
-
0.4047142491023989,
|
| 91 |
-
-0.0039119825110344765,
|
| 92 |
-
0.4122583381095728,
|
| 93 |
-
0.41746734262039764
|
| 94 |
-
],
|
| 95 |
-
"word_score_names": [
|
| 96 |
-
"accuracy",
|
| 97 |
-
"stress",
|
| 98 |
-
"total",
|
| 99 |
-
"asr_accuracy"
|
| 100 |
-
]
|
| 101 |
-
},
|
| 102 |
-
"code_dependencies": {
|
| 103 |
-
"custom_gopt_repo": "https://github.com/hf49w/custom-gopt.git",
|
| 104 |
-
"charsiu_repo": "https://github.com/lingjzhu/charsiu",
|
| 105 |
-
"charsiu_repo_commit": "13a69f2a22ca0c0962b75cc693399b0ae23a12c9"
|
| 106 |
-
}
|
| 107 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
charsiu_en_w2v2_tiny_fc_10ms/config.json
DELETED
|
@@ -1,75 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"activation_dropout": 0.1,
|
| 3 |
-
"apply_spec_augment": true,
|
| 4 |
-
"architectures": [
|
| 5 |
-
"Wav2Vec2ForFrameClassification"
|
| 6 |
-
],
|
| 7 |
-
"attention_dropout": 0.1,
|
| 8 |
-
"bos_token_id": 1,
|
| 9 |
-
"codevector_dim": 256,
|
| 10 |
-
"contrastive_logits_temperature": 0.1,
|
| 11 |
-
"conv_bias": false,
|
| 12 |
-
"conv_dim": [
|
| 13 |
-
512,
|
| 14 |
-
512,
|
| 15 |
-
512,
|
| 16 |
-
512,
|
| 17 |
-
512,
|
| 18 |
-
512,
|
| 19 |
-
512
|
| 20 |
-
],
|
| 21 |
-
"conv_kernel": [
|
| 22 |
-
10,
|
| 23 |
-
3,
|
| 24 |
-
3,
|
| 25 |
-
3,
|
| 26 |
-
3,
|
| 27 |
-
2,
|
| 28 |
-
2
|
| 29 |
-
],
|
| 30 |
-
"conv_stride": [
|
| 31 |
-
5,
|
| 32 |
-
2,
|
| 33 |
-
2,
|
| 34 |
-
2,
|
| 35 |
-
2,
|
| 36 |
-
2,
|
| 37 |
-
1
|
| 38 |
-
],
|
| 39 |
-
"ctc_loss_reduction": "sum",
|
| 40 |
-
"ctc_zero_infinity": false,
|
| 41 |
-
"diversity_loss_weight": 0.1,
|
| 42 |
-
"do_stable_layer_norm": false,
|
| 43 |
-
"eos_token_id": 2,
|
| 44 |
-
"feat_extract_activation": "gelu",
|
| 45 |
-
"feat_extract_norm": "group",
|
| 46 |
-
"feat_proj_dropout": 0.1,
|
| 47 |
-
"feat_quantizer_dropout": 0.0,
|
| 48 |
-
"final_dropout": 0.1,
|
| 49 |
-
"gradient_checkpointing": false,
|
| 50 |
-
"hidden_act": "gelu",
|
| 51 |
-
"hidden_dropout": 0.1,
|
| 52 |
-
"hidden_size": 384,
|
| 53 |
-
"initializer_range": 0.02,
|
| 54 |
-
"intermediate_size": 3072,
|
| 55 |
-
"layer_norm_eps": 1e-05,
|
| 56 |
-
"layerdrop": 0.1,
|
| 57 |
-
"mask_feature_length": 10,
|
| 58 |
-
"mask_feature_prob": 0.0,
|
| 59 |
-
"mask_time_length": 10,
|
| 60 |
-
"mask_time_prob": 0.05,
|
| 61 |
-
"model_type": "wav2vec2",
|
| 62 |
-
"num_attention_heads": 6,
|
| 63 |
-
"num_codevector_groups": 2,
|
| 64 |
-
"num_codevectors_per_group": 320,
|
| 65 |
-
"num_conv_pos_embedding_groups": 16,
|
| 66 |
-
"num_conv_pos_embeddings": 128,
|
| 67 |
-
"num_feat_extract_layers": 7,
|
| 68 |
-
"num_hidden_layers": 6,
|
| 69 |
-
"num_negatives": 100,
|
| 70 |
-
"pad_token_id": 0,
|
| 71 |
-
"proj_codevector_dim": 256,
|
| 72 |
-
"torch_dtype": "float32",
|
| 73 |
-
"transformers_version": "4.9.0",
|
| 74 |
-
"vocab_size": 42
|
| 75 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
charsiu_en_w2v2_tiny_fc_10ms/preprocessor_config.json
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
Entry not found
|
|
|
|
|
|
charsiu_en_w2v2_tiny_fc_10ms/pytorch_model.bin
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:a5b59d8cc3c548382dbc38c48d537b0bb520b9a67d2fafef2afee7740f9ce0c7
|
| 3 |
-
size 93368972
|
|
|
|
|
|
|
|
|
|
|
|
examples/eval_streaming_gopt_test.py
DELETED
|
@@ -1,119 +0,0 @@
|
|
| 1 |
-
import argparse
|
| 2 |
-
import json
|
| 3 |
-
import sys
|
| 4 |
-
from pathlib import Path
|
| 5 |
-
|
| 6 |
-
import torch
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
def get_args():
|
| 10 |
-
parser = argparse.ArgumentParser(
|
| 11 |
-
description="Evaluate the bundled Streaming GOPT checkpoint on a prepared val/test split."
|
| 12 |
-
)
|
| 13 |
-
parser.add_argument("--data-dir", type=Path, required=True, help="Directory containing *_chunks.npz and metadata.json.")
|
| 14 |
-
parser.add_argument("--model-dir", type=Path, required=True, help="Directory containing best_audio_model.pth and config.json.")
|
| 15 |
-
parser.add_argument("--repo-src", type=Path, required=True, help="Path to custom-gopt/src.")
|
| 16 |
-
parser.add_argument("--split", type=str, default="test", choices=["val", "test", "train"])
|
| 17 |
-
parser.add_argument("--device", type=str, default=None, help="cuda / cuda:0 / cpu. Defaults to cuda if available.")
|
| 18 |
-
parser.add_argument("--output-json", type=Path, default=None)
|
| 19 |
-
parser.add_argument("--main-context-tokens", type=int, default=None, help="Override evaluation main context tokens.")
|
| 20 |
-
parser.add_argument("--right-context-tokens", type=int, default=None, help="Override evaluation right context tokens.")
|
| 21 |
-
return parser.parse_args()
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
def load_summary(data_dir, model_dir, repo_src, split, device_name, main_context_tokens=None, right_context_tokens=None):
|
| 25 |
-
sys.path.insert(0, str(repo_src))
|
| 26 |
-
|
| 27 |
-
from models import StreamingGOPT, StreamingGOPTNoPhn
|
| 28 |
-
from train_streaming_charsiu import StreamingChunkDataset, load_model_state, make_loader, validate
|
| 29 |
-
|
| 30 |
-
metadata = json.loads((data_dir / "metadata.json").read_text(encoding="utf-8"))
|
| 31 |
-
cfg = json.loads((model_dir / "config.json").read_text(encoding="utf-8"))
|
| 32 |
-
args_dict = cfg["args"]
|
| 33 |
-
|
| 34 |
-
class Args:
|
| 35 |
-
pass
|
| 36 |
-
|
| 37 |
-
args = Args()
|
| 38 |
-
for key, value in args_dict.items():
|
| 39 |
-
setattr(args, key, value)
|
| 40 |
-
|
| 41 |
-
args.main_context_token_choices = args_dict.get("main_context_token_choices") or [
|
| 42 |
-
int(item.strip()) for item in str(args_dict["main_context_tokens"]).split(",") if item.strip()
|
| 43 |
-
]
|
| 44 |
-
args.right_context_token_choices = args_dict.get("right_context_token_choices") or [
|
| 45 |
-
int(item.strip()) for item in str(args_dict["right_context_tokens"]).split(",") if item.strip()
|
| 46 |
-
]
|
| 47 |
-
|
| 48 |
-
device = torch.device(device_name or ("cuda" if torch.cuda.is_available() else "cpu"))
|
| 49 |
-
if getattr(args, "tf32", False) and device.type == "cuda":
|
| 50 |
-
if hasattr(torch, "set_float32_matmul_precision"):
|
| 51 |
-
torch.set_float32_matmul_precision("high")
|
| 52 |
-
torch.backends.cuda.matmul.allow_tf32 = True
|
| 53 |
-
torch.backends.cudnn.allow_tf32 = True
|
| 54 |
-
|
| 55 |
-
dataset = StreamingChunkDataset(split, data_dir, metadata, final_only=(split != "train"))
|
| 56 |
-
loader = make_loader(dataset, len(dataset), False, int(getattr(args, "num_workers", 0)))
|
| 57 |
-
|
| 58 |
-
model_cls = StreamingGOPT if args_dict["model"] == "streaming_gopt" else StreamingGOPTNoPhn
|
| 59 |
-
model = model_cls(
|
| 60 |
-
embed_dim=int(args_dict["embed_dim"]),
|
| 61 |
-
num_heads=int(args_dict["heads"]),
|
| 62 |
-
depth=int(args_dict["depth"]),
|
| 63 |
-
input_dim=int(cfg["input_dim"]),
|
| 64 |
-
seq_len=int(cfg["seq_len"]),
|
| 65 |
-
phn_num=int(cfg["phn_num"]),
|
| 66 |
-
)
|
| 67 |
-
|
| 68 |
-
state = torch.load(model_dir / "best_audio_model.pth", map_location=device)
|
| 69 |
-
load_model_state(model, state)
|
| 70 |
-
model = model.to(device)
|
| 71 |
-
model.eval()
|
| 72 |
-
|
| 73 |
-
eval_main_context = int(main_context_tokens if main_context_tokens is not None else max(args.main_context_token_choices))
|
| 74 |
-
eval_right_context = int(right_context_tokens if right_context_tokens is not None else max(args.right_context_token_choices))
|
| 75 |
-
|
| 76 |
-
mse, corr, utt_mse, utt_corr, word_mse, word_corr = validate(
|
| 77 |
-
model,
|
| 78 |
-
loader,
|
| 79 |
-
args,
|
| 80 |
-
-1,
|
| 81 |
-
device,
|
| 82 |
-
eval_main_context,
|
| 83 |
-
eval_right_context,
|
| 84 |
-
)
|
| 85 |
-
|
| 86 |
-
return {
|
| 87 |
-
"split": split,
|
| 88 |
-
"device": str(device),
|
| 89 |
-
"main_context_tokens": eval_main_context,
|
| 90 |
-
"right_context_tokens": eval_right_context,
|
| 91 |
-
"phone_mse": float(mse),
|
| 92 |
-
"phone_pcc": float(corr),
|
| 93 |
-
"utt_mse": [float(x) for x in utt_mse],
|
| 94 |
-
"utt_pcc": [float(x) for x in utt_corr],
|
| 95 |
-
"word_mse": [float(x) for x in word_mse],
|
| 96 |
-
"word_pcc": [float(x) for x in word_corr],
|
| 97 |
-
}
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
def main():
|
| 101 |
-
args = get_args()
|
| 102 |
-
summary = load_summary(
|
| 103 |
-
data_dir=args.data_dir,
|
| 104 |
-
model_dir=args.model_dir,
|
| 105 |
-
repo_src=args.repo_src,
|
| 106 |
-
split=args.split,
|
| 107 |
-
device_name=args.device,
|
| 108 |
-
main_context_tokens=args.main_context_tokens,
|
| 109 |
-
right_context_tokens=args.right_context_tokens,
|
| 110 |
-
)
|
| 111 |
-
payload = json.dumps(summary, ensure_ascii=False, indent=2)
|
| 112 |
-
print(payload)
|
| 113 |
-
if args.output_json is not None:
|
| 114 |
-
args.output_json.parent.mkdir(parents=True, exist_ok=True)
|
| 115 |
-
args.output_json.write_text(payload, encoding="utf-8")
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
if __name__ == "__main__":
|
| 119 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/infer_one_audio.py
DELETED
|
@@ -1,395 +0,0 @@
|
|
| 1 |
-
import argparse
|
| 2 |
-
import json
|
| 3 |
-
import sys
|
| 4 |
-
import warnings
|
| 5 |
-
from pathlib import Path
|
| 6 |
-
|
| 7 |
-
import numpy as np
|
| 8 |
-
import torch
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
SCORE_NAMES = ["accuracy", "completeness", "fluency", "prosodic", "total"]
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
def get_args():
|
| 15 |
-
parser = argparse.ArgumentParser(
|
| 16 |
-
description="Run one-audio inference with the bundled Whisper + Charsiu + Streaming GOPT pipeline."
|
| 17 |
-
)
|
| 18 |
-
parser.add_argument("--audio", type=Path, required=True, help="Path to one wav audio file.")
|
| 19 |
-
parser.add_argument("--bundle-dir", type=Path, default=Path(__file__).resolve().parents[1])
|
| 20 |
-
parser.add_argument("--repo-root", type=Path, required=True, help="Path to the cloned custom-gopt repository root.")
|
| 21 |
-
parser.add_argument("--charsiu-src-dir", type=Path, required=True, help="Path to the official Charsiu repo root or its src directory.")
|
| 22 |
-
parser.add_argument("--device", type=str, default=None, help="cuda / cuda:0 / cpu. Defaults to cuda if available.")
|
| 23 |
-
parser.add_argument("--output-json", type=Path, default=None)
|
| 24 |
-
parser.add_argument("--main-context-tokens", type=int, default=None)
|
| 25 |
-
parser.add_argument("--right-context-tokens", type=int, default=None)
|
| 26 |
-
return parser.parse_args()
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
def add_repo_paths(repo_root):
|
| 30 |
-
repo_src = repo_root / "src"
|
| 31 |
-
prep_src = repo_src / "prep_data"
|
| 32 |
-
for path in [repo_src, prep_src]:
|
| 33 |
-
path_str = str(path)
|
| 34 |
-
if path_str not in sys.path:
|
| 35 |
-
sys.path.insert(0, path_str)
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
def load_asr_pipeline(whisper_model_dir, device):
|
| 39 |
-
from transformers import pipeline
|
| 40 |
-
from transformers.utils import logging as hf_logging
|
| 41 |
-
|
| 42 |
-
hf_logging.set_verbosity_error()
|
| 43 |
-
|
| 44 |
-
if str(device).startswith("cuda"):
|
| 45 |
-
pipe_device = int(str(device).split(":", 1)[1]) if ":" in str(device) else 0
|
| 46 |
-
torch_dtype = torch.float16
|
| 47 |
-
else:
|
| 48 |
-
pipe_device = -1
|
| 49 |
-
torch_dtype = torch.float32
|
| 50 |
-
|
| 51 |
-
pipe = pipeline(
|
| 52 |
-
"automatic-speech-recognition",
|
| 53 |
-
model=str(whisper_model_dir),
|
| 54 |
-
tokenizer=str(whisper_model_dir),
|
| 55 |
-
feature_extractor=str(whisper_model_dir),
|
| 56 |
-
framework="pt",
|
| 57 |
-
device=pipe_device,
|
| 58 |
-
dtype=torch_dtype,
|
| 59 |
-
)
|
| 60 |
-
if hasattr(pipe.model, "generation_config"):
|
| 61 |
-
pipe.model.generation_config.use_cache = False
|
| 62 |
-
kwargs = {
|
| 63 |
-
"return_timestamps": "word",
|
| 64 |
-
"generate_kwargs": {
|
| 65 |
-
"language": "english",
|
| 66 |
-
"task": "transcribe",
|
| 67 |
-
"max_new_tokens": 128,
|
| 68 |
-
"use_cache": False,
|
| 69 |
-
},
|
| 70 |
-
}
|
| 71 |
-
return pipe, kwargs
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
def load_audio_for_asr(audio_path, sample_rate):
|
| 75 |
-
import librosa
|
| 76 |
-
import soundfile as sf
|
| 77 |
-
|
| 78 |
-
audio, sr = sf.read(str(audio_path))
|
| 79 |
-
if audio.ndim > 1:
|
| 80 |
-
audio = audio.mean(axis=1)
|
| 81 |
-
audio = np.asarray(audio, dtype=np.float32)
|
| 82 |
-
if sr != sample_rate:
|
| 83 |
-
audio = librosa.resample(audio, orig_sr=sr, target_sr=sample_rate)
|
| 84 |
-
sr = sample_rate
|
| 85 |
-
return audio, sr
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
def transcribe_audio(asr_pipe, pipe_kwargs, audio_path, sample_rate, normalize_word):
|
| 89 |
-
audio, sr = load_audio_for_asr(audio_path, sample_rate)
|
| 90 |
-
result = asr_pipe({"raw": audio, "sampling_rate": sr}, **pipe_kwargs)
|
| 91 |
-
transcript = (result.get("text") or "").strip()
|
| 92 |
-
words = []
|
| 93 |
-
for chunk in result.get("chunks", []):
|
| 94 |
-
text = normalize_word(chunk.get("text", ""))
|
| 95 |
-
timestamp = chunk.get("timestamp") or (None, None)
|
| 96 |
-
if not text or timestamp[0] is None or timestamp[1] is None:
|
| 97 |
-
continue
|
| 98 |
-
words.append(
|
| 99 |
-
{
|
| 100 |
-
"text": text,
|
| 101 |
-
"start": float(timestamp[0]),
|
| 102 |
-
"end": float(timestamp[1]),
|
| 103 |
-
}
|
| 104 |
-
)
|
| 105 |
-
return transcript, words
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
def load_model(model_dir, repo_root, device):
|
| 109 |
-
add_repo_paths(repo_root)
|
| 110 |
-
from models import StreamingGOPT, StreamingGOPTNoPhn
|
| 111 |
-
|
| 112 |
-
cfg = json.loads((model_dir / "config.json").read_text(encoding="utf-8"))
|
| 113 |
-
model_args = cfg["args"]
|
| 114 |
-
model_cls = StreamingGOPT if model_args["model"] == "streaming_gopt" else StreamingGOPTNoPhn
|
| 115 |
-
model = model_cls(
|
| 116 |
-
embed_dim=int(model_args["embed_dim"]),
|
| 117 |
-
num_heads=int(model_args["heads"]),
|
| 118 |
-
depth=int(model_args["depth"]),
|
| 119 |
-
input_dim=int(cfg["input_dim"]),
|
| 120 |
-
seq_len=int(cfg["seq_len"]),
|
| 121 |
-
phn_num=int(cfg["phn_num"]),
|
| 122 |
-
)
|
| 123 |
-
state = torch.load(model_dir / "best_audio_model.pth", map_location=device)
|
| 124 |
-
incompatible = model.load_state_dict(state, strict=False)
|
| 125 |
-
allowed_missing = {
|
| 126 |
-
"mlp_head_word4.0.weight",
|
| 127 |
-
"mlp_head_word4.0.bias",
|
| 128 |
-
"mlp_head_word4.1.weight",
|
| 129 |
-
"mlp_head_word4.1.bias",
|
| 130 |
-
}
|
| 131 |
-
unexpected = set(incompatible.unexpected_keys)
|
| 132 |
-
missing = set(incompatible.missing_keys)
|
| 133 |
-
if unexpected:
|
| 134 |
-
raise RuntimeError(f"Unexpected checkpoint keys: {sorted(unexpected)}")
|
| 135 |
-
disallowed_missing = missing - allowed_missing
|
| 136 |
-
if disallowed_missing:
|
| 137 |
-
raise RuntimeError(f"Missing required checkpoint keys: {sorted(disallowed_missing)}")
|
| 138 |
-
model = model.to(device)
|
| 139 |
-
model.eval()
|
| 140 |
-
return model, cfg
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
def build_phone_segments(
|
| 144 |
-
audio_path,
|
| 145 |
-
transcript,
|
| 146 |
-
repo_root,
|
| 147 |
-
charsiu_src_dir,
|
| 148 |
-
charsiu_model_dir,
|
| 149 |
-
sample_rate,
|
| 150 |
-
device,
|
| 151 |
-
phn_dict,
|
| 152 |
-
expected_feat_dim,
|
| 153 |
-
):
|
| 154 |
-
add_repo_paths(repo_root)
|
| 155 |
-
for module_name in ["Charsiu", "models", "utils", "processors"]:
|
| 156 |
-
sys.modules.pop(module_name, None)
|
| 157 |
-
from build_charsiu_seq_data import (
|
| 158 |
-
audio_logits,
|
| 159 |
-
build_model_phone_map,
|
| 160 |
-
build_silence_keep_mask,
|
| 161 |
-
import_official_charsiu_forced_align,
|
| 162 |
-
load_official_charsiu_aligner,
|
| 163 |
-
normalize_phone,
|
| 164 |
-
segment_feature,
|
| 165 |
-
)
|
| 166 |
-
|
| 167 |
-
charsiu = load_official_charsiu_aligner(
|
| 168 |
-
model_name=str(charsiu_model_dir),
|
| 169 |
-
device=str(device),
|
| 170 |
-
sample_rate=sample_rate,
|
| 171 |
-
sil_threshold=4,
|
| 172 |
-
lang="en",
|
| 173 |
-
charsiu_src_dir=str(charsiu_src_dir),
|
| 174 |
-
)
|
| 175 |
-
phone_to_frame_id, _, _ = build_model_phone_map(charsiu)
|
| 176 |
-
phone_groups, words = charsiu.charsiu_processor.get_phones_and_words(transcript)
|
| 177 |
-
if not phone_groups:
|
| 178 |
-
raise ValueError("ASR transcript cannot be converted into phones.")
|
| 179 |
-
|
| 180 |
-
flat_records = []
|
| 181 |
-
for word_id, phones in enumerate(phone_groups):
|
| 182 |
-
word_text = str(words[word_id]).lower() if word_id < len(words) else f"word_{word_id}"
|
| 183 |
-
for phone in phones:
|
| 184 |
-
norm_phone = normalize_phone(phone)
|
| 185 |
-
if not norm_phone or norm_phone == "SIL":
|
| 186 |
-
continue
|
| 187 |
-
if norm_phone not in phone_to_frame_id:
|
| 188 |
-
raise ValueError(f"Phone not found in Charsiu frame-classifier vocab: {norm_phone}")
|
| 189 |
-
if norm_phone not in phn_dict:
|
| 190 |
-
raise ValueError(f"Phone not found in GOPT phone vocab: {norm_phone}")
|
| 191 |
-
flat_records.append(
|
| 192 |
-
{
|
| 193 |
-
"phone": norm_phone,
|
| 194 |
-
"word_id": int(word_id),
|
| 195 |
-
"word_text": word_text,
|
| 196 |
-
}
|
| 197 |
-
)
|
| 198 |
-
|
| 199 |
-
if not flat_records:
|
| 200 |
-
raise ValueError("No valid phones remained after transcript normalization.")
|
| 201 |
-
|
| 202 |
-
phone_ids = charsiu.charsiu_processor.get_phone_ids(phone_groups)
|
| 203 |
-
target_phone_ids = list(phone_ids[1:-1])
|
| 204 |
-
if len(target_phone_ids) != len(flat_records):
|
| 205 |
-
raise ValueError(
|
| 206 |
-
f"Phone count mismatch after G2P: target_phone_ids={len(target_phone_ids)} flat_records={len(flat_records)}"
|
| 207 |
-
)
|
| 208 |
-
|
| 209 |
-
probs, audio_duration = audio_logits(
|
| 210 |
-
audio_path=str(audio_path),
|
| 211 |
-
processor=charsiu.charsiu_processor,
|
| 212 |
-
model=charsiu.aligner,
|
| 213 |
-
sample_rate=sample_rate,
|
| 214 |
-
device=device,
|
| 215 |
-
)
|
| 216 |
-
keep_mask = build_silence_keep_mask(charsiu, probs)
|
| 217 |
-
kept_indices = np.flatnonzero(keep_mask)
|
| 218 |
-
kept_probs = probs[keep_mask]
|
| 219 |
-
if kept_probs.shape[0] < len(target_phone_ids):
|
| 220 |
-
raise ValueError(
|
| 221 |
-
f"Not enough non-silence frames for the recognized phones: frames={kept_probs.shape[0]} phones={len(target_phone_ids)}"
|
| 222 |
-
)
|
| 223 |
-
|
| 224 |
-
forced_align = import_official_charsiu_forced_align(str(charsiu_src_dir))
|
| 225 |
-
aligned_phone_ids = np.asarray(forced_align(kept_probs, target_phone_ids), dtype=np.int32)
|
| 226 |
-
frame_step = float(audio_duration) / max(len(probs), 1)
|
| 227 |
-
|
| 228 |
-
segments = []
|
| 229 |
-
for phone_idx, record in enumerate(flat_records):
|
| 230 |
-
token_frames = np.flatnonzero(aligned_phone_ids == phone_idx)
|
| 231 |
-
if token_frames.size == 0:
|
| 232 |
-
raise ValueError(f"Empty aligned segment for phone index {phone_idx} ({record['phone']}).")
|
| 233 |
-
|
| 234 |
-
segment_probs = kept_probs[token_frames]
|
| 235 |
-
target_id = int(phone_to_frame_id[record["phone"]])
|
| 236 |
-
base_feature = segment_feature(segment_probs, target_id, frame_step).astype(np.float32)
|
| 237 |
-
expected_base_dim = int(expected_feat_dim) - 1
|
| 238 |
-
expected_phone_prob_dim = expected_base_dim - 4
|
| 239 |
-
current_phone_prob_dim = int(base_feature.shape[0]) - 4
|
| 240 |
-
if current_phone_prob_dim == expected_phone_prob_dim + 1:
|
| 241 |
-
# Current local Charsiu exports an extra [PAD] probability channel at the end.
|
| 242 |
-
# The released GOPT checkpoint was trained without that channel.
|
| 243 |
-
base_feature = np.concatenate([base_feature[:expected_phone_prob_dim], base_feature[-4:]], axis=0)
|
| 244 |
-
elif current_phone_prob_dim != expected_phone_prob_dim:
|
| 245 |
-
raise ValueError(
|
| 246 |
-
f"Unexpected phone probability dimension: current={current_phone_prob_dim} expected={expected_phone_prob_dim}"
|
| 247 |
-
)
|
| 248 |
-
feature = np.concatenate([base_feature, np.array([0.0], dtype=np.float32)], axis=0)
|
| 249 |
-
|
| 250 |
-
start_frame = int(kept_indices[token_frames[0]])
|
| 251 |
-
end_frame = int(kept_indices[token_frames[-1]]) + 1
|
| 252 |
-
start_time = float(start_frame * frame_step)
|
| 253 |
-
end_time = float(min(audio_duration, end_frame * frame_step))
|
| 254 |
-
|
| 255 |
-
segments.append(
|
| 256 |
-
{
|
| 257 |
-
"phone": record["phone"],
|
| 258 |
-
"phone_id": int(phn_dict[record["phone"]]),
|
| 259 |
-
"word_id": int(record["word_id"]),
|
| 260 |
-
"word_text": record["word_text"],
|
| 261 |
-
"start_time": start_time,
|
| 262 |
-
"end_time": end_time,
|
| 263 |
-
"feature": feature,
|
| 264 |
-
}
|
| 265 |
-
)
|
| 266 |
-
return segments
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
def prepare_model_inputs(segments, seq_len, feat_dim, norm_mean, norm_std, device):
|
| 270 |
-
if len(segments) > seq_len:
|
| 271 |
-
raise ValueError(f"Phone sequence too long for this model: {len(segments)} > seq_len({seq_len})")
|
| 272 |
-
|
| 273 |
-
feat = np.zeros((seq_len, feat_dim), dtype=np.float32)
|
| 274 |
-
phn = np.full((seq_len,), -1, dtype=np.int64)
|
| 275 |
-
for idx, segment in enumerate(segments):
|
| 276 |
-
if int(segment["feature"].shape[-1]) != feat_dim:
|
| 277 |
-
raise ValueError(
|
| 278 |
-
f"Feature dimension mismatch at segment {idx}: got {segment['feature'].shape[-1]}, expected {feat_dim}"
|
| 279 |
-
)
|
| 280 |
-
feat[idx] = segment["feature"]
|
| 281 |
-
phn[idx] = int(segment["phone_id"])
|
| 282 |
-
|
| 283 |
-
valid = phn >= 0
|
| 284 |
-
feat[valid] = (feat[valid] - float(norm_mean)) / float(norm_std)
|
| 285 |
-
x = torch.from_numpy(feat).unsqueeze(0).to(device)
|
| 286 |
-
p = torch.from_numpy(phn).unsqueeze(0).to(device)
|
| 287 |
-
return x, p
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
def predict_scores(model, x, p, main_context_tokens, right_context_tokens):
|
| 291 |
-
with torch.no_grad():
|
| 292 |
-
u1, u2, u3, u4, u5, _, _, _, _, _ = model(
|
| 293 |
-
x,
|
| 294 |
-
p,
|
| 295 |
-
main_context_tokens=int(main_context_tokens),
|
| 296 |
-
right_context_tokens=int(right_context_tokens),
|
| 297 |
-
)
|
| 298 |
-
values = torch.cat([u1, u2, u3, u4, u5], dim=1).squeeze(0).cpu().numpy() * 5.0
|
| 299 |
-
values = np.clip(values, 0.0, 10.0)
|
| 300 |
-
return {name: float(value) for name, value in zip(SCORE_NAMES, values.tolist())}
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
def build_output(audio_path, transcript, asr_words, scores, segments, device, bundle_dir):
|
| 304 |
-
return {
|
| 305 |
-
"status": "ok",
|
| 306 |
-
"audio_path": str(audio_path.resolve()).replace("\\", "/"),
|
| 307 |
-
"bundle_dir": str(bundle_dir.resolve()).replace("\\", "/"),
|
| 308 |
-
"device": str(device),
|
| 309 |
-
"transcript": transcript,
|
| 310 |
-
"utterance_scores": scores,
|
| 311 |
-
"overall_score": float(scores["total"]),
|
| 312 |
-
"num_phone_segments": int(len(segments)),
|
| 313 |
-
"num_asr_words": int(len(asr_words)),
|
| 314 |
-
"recognized_words": [str(word["text"]).lower() for word in asr_words],
|
| 315 |
-
}
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
def main():
|
| 319 |
-
warnings.filterwarnings("ignore", message=".*return_token_timestamps.*")
|
| 320 |
-
args = get_args()
|
| 321 |
-
bundle_dir = args.bundle_dir.resolve()
|
| 322 |
-
repo_root = args.repo_root.resolve()
|
| 323 |
-
charsiu_src_dir = args.charsiu_src_dir.resolve()
|
| 324 |
-
device = torch.device(args.device or ("cuda" if torch.cuda.is_available() else "cpu"))
|
| 325 |
-
|
| 326 |
-
if not args.audio.exists():
|
| 327 |
-
raise FileNotFoundError(f"Audio file not found: {args.audio}")
|
| 328 |
-
|
| 329 |
-
model_dir = bundle_dir / "streaming_gopt_best"
|
| 330 |
-
whisper_model_dir = bundle_dir / "whisper_best_model"
|
| 331 |
-
charsiu_model_dir = bundle_dir / "charsiu_en_w2v2_tiny_fc_10ms"
|
| 332 |
-
inference_assets_path = model_dir / "inference_assets.json"
|
| 333 |
-
|
| 334 |
-
inference_assets = json.loads(inference_assets_path.read_text(encoding="utf-8"))
|
| 335 |
-
sample_rate = int(inference_assets["sample_rate"])
|
| 336 |
-
norm_mean = float(inference_assets["train_norm_mean"])
|
| 337 |
-
norm_std = float(inference_assets["train_norm_std"])
|
| 338 |
-
phn_dict = {str(key): int(value) for key, value in inference_assets["phn_dict"].items()}
|
| 339 |
-
|
| 340 |
-
model, cfg = load_model(model_dir, repo_root, device)
|
| 341 |
-
add_repo_paths(repo_root)
|
| 342 |
-
from build_charsiu_seq_data import normalize_word
|
| 343 |
-
|
| 344 |
-
asr_pipe, asr_kwargs = load_asr_pipeline(whisper_model_dir, device)
|
| 345 |
-
transcript, asr_words = transcribe_audio(asr_pipe, asr_kwargs, args.audio, sample_rate, normalize_word)
|
| 346 |
-
if not transcript:
|
| 347 |
-
raise ValueError("Whisper produced an empty transcript.")
|
| 348 |
-
|
| 349 |
-
segments = build_phone_segments(
|
| 350 |
-
audio_path=args.audio,
|
| 351 |
-
transcript=transcript,
|
| 352 |
-
repo_root=repo_root,
|
| 353 |
-
charsiu_src_dir=charsiu_src_dir,
|
| 354 |
-
charsiu_model_dir=charsiu_model_dir,
|
| 355 |
-
sample_rate=sample_rate,
|
| 356 |
-
device=device,
|
| 357 |
-
phn_dict=phn_dict,
|
| 358 |
-
expected_feat_dim=int(cfg["input_dim"]),
|
| 359 |
-
)
|
| 360 |
-
|
| 361 |
-
seq_len = int(cfg["seq_len"])
|
| 362 |
-
feat_dim = int(cfg["input_dim"])
|
| 363 |
-
x, p = prepare_model_inputs(
|
| 364 |
-
segments=segments,
|
| 365 |
-
seq_len=seq_len,
|
| 366 |
-
feat_dim=feat_dim,
|
| 367 |
-
norm_mean=norm_mean,
|
| 368 |
-
norm_std=norm_std,
|
| 369 |
-
device=device,
|
| 370 |
-
)
|
| 371 |
-
|
| 372 |
-
model_args = cfg["args"]
|
| 373 |
-
main_context_choices = model_args.get("main_context_token_choices") or [
|
| 374 |
-
int(item.strip()) for item in str(model_args["main_context_tokens"]).split(",") if item.strip()
|
| 375 |
-
]
|
| 376 |
-
right_context_choices = model_args.get("right_context_token_choices") or [
|
| 377 |
-
int(item.strip()) for item in str(model_args["right_context_tokens"]).split(",") if item.strip()
|
| 378 |
-
]
|
| 379 |
-
|
| 380 |
-
main_context_tokens = int(args.main_context_tokens if args.main_context_tokens is not None else max(main_context_choices))
|
| 381 |
-
right_context_tokens = int(
|
| 382 |
-
args.right_context_tokens if args.right_context_tokens is not None else max(right_context_choices)
|
| 383 |
-
)
|
| 384 |
-
scores = predict_scores(model, x, p, main_context_tokens, right_context_tokens)
|
| 385 |
-
payload = build_output(args.audio, transcript, asr_words, scores, segments, device, bundle_dir)
|
| 386 |
-
|
| 387 |
-
result_json = json.dumps(payload, ensure_ascii=False, indent=2)
|
| 388 |
-
print(result_json)
|
| 389 |
-
if args.output_json is not None:
|
| 390 |
-
args.output_json.parent.mkdir(parents=True, exist_ok=True)
|
| 391 |
-
args.output_json.write_text(result_json, encoding="utf-8")
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
if __name__ == "__main__":
|
| 395 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/sa1_infer_output.json
DELETED
|
@@ -1,30 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"status": "ok",
|
| 3 |
-
"audio_path": "D:/研究生/模型/charsiu/charsiu_repo/local/SA1.WAV",
|
| 4 |
-
"bundle_dir": "D:/研究生/智能体/gopt_charsiu/hf_bundle/custom-gopt-252-eval",
|
| 5 |
-
"device": "cpu",
|
| 6 |
-
"transcript": "She had your dark suit in greasy wash water all year.",
|
| 7 |
-
"utterance_scores": {
|
| 8 |
-
"accuracy": 5.0,
|
| 9 |
-
"completeness": 5.0,
|
| 10 |
-
"fluency": 5.0,
|
| 11 |
-
"prosodic": 5.0,
|
| 12 |
-
"total": 5.0
|
| 13 |
-
},
|
| 14 |
-
"overall_score": 5.0,
|
| 15 |
-
"num_phone_segments": 34,
|
| 16 |
-
"num_asr_words": 11,
|
| 17 |
-
"recognized_words": [
|
| 18 |
-
"she",
|
| 19 |
-
"had",
|
| 20 |
-
"your",
|
| 21 |
-
"dark",
|
| 22 |
-
"suit",
|
| 23 |
-
"in",
|
| 24 |
-
"greasy",
|
| 25 |
-
"wash",
|
| 26 |
-
"water",
|
| 27 |
-
"all",
|
| 28 |
-
"year"
|
| 29 |
-
]
|
| 30 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/session.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Live-style local example. Input: your own mono 16 kHz English WAV."""
|
| 2 |
+
import argparse
|
| 3 |
+
import json
|
| 4 |
+
import soundfile as sf
|
| 5 |
+
from streampa import StreamPAPipeline
|
| 6 |
+
|
| 7 |
+
p=argparse.ArgumentParser()
|
| 8 |
+
p.add_argument('--bundle-dir',required=True); p.add_argument('--audio',required=True)
|
| 9 |
+
p.add_argument('--device',default='cpu')
|
| 10 |
+
a=p.parse_args()
|
| 11 |
+
pipeline=StreamPAPipeline(a.bundle_dir,device=a.device)
|
| 12 |
+
session=pipeline.create_session()
|
| 13 |
+
with sf.SoundFile(a.audio) as audio:
|
| 14 |
+
if audio.samplerate!=16000 or audio.channels!=1: raise ValueError('Expected mono 16-kHz WAV')
|
| 15 |
+
while True:
|
| 16 |
+
block=audio.read(1600,dtype='float32')
|
| 17 |
+
if not len(block): break
|
| 18 |
+
for result in session.append(block): print(json.dumps(result))
|
| 19 |
+
print(json.dumps(session.finish()))
|
| 20 |
+
session.reset()
|
| 21 |
+
assert session.current() is None and session.state is None
|
licenses/Apache-2.0.txt
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright 2018- The Hugging Face team. All rights reserved.
|
| 2 |
+
|
| 3 |
+
Apache License
|
| 4 |
+
Version 2.0, January 2004
|
| 5 |
+
http://www.apache.org/licenses/
|
| 6 |
+
|
| 7 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 8 |
+
|
| 9 |
+
1. Definitions.
|
| 10 |
+
|
| 11 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 12 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 13 |
+
|
| 14 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 15 |
+
the copyright owner that is granting the License.
|
| 16 |
+
|
| 17 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 18 |
+
other entities that control, are controlled by, or are under common
|
| 19 |
+
control with that entity. For the purposes of this definition,
|
| 20 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 21 |
+
direction or management of such entity, whether by contract or
|
| 22 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 23 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 24 |
+
|
| 25 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 26 |
+
exercising permissions granted by this License.
|
| 27 |
+
|
| 28 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 29 |
+
including but not limited to software source code, documentation
|
| 30 |
+
source, and configuration files.
|
| 31 |
+
|
| 32 |
+
"Object" form shall mean any form resulting from mechanical
|
| 33 |
+
transformation or translation of a Source form, including but
|
| 34 |
+
not limited to compiled object code, generated documentation,
|
| 35 |
+
and conversions to other media types.
|
| 36 |
+
|
| 37 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 38 |
+
Object form, made available under the License, as indicated by a
|
| 39 |
+
copyright notice that is included in or attached to the work
|
| 40 |
+
(an example is provided in the Appendix below).
|
| 41 |
+
|
| 42 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 43 |
+
form, that is based on (or derived from) the Work and for which the
|
| 44 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 45 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 46 |
+
of this License, Derivative Works shall not include works that remain
|
| 47 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 48 |
+
the Work and Derivative Works thereof.
|
| 49 |
+
|
| 50 |
+
"Contribution" shall mean any work of authorship, including
|
| 51 |
+
the original version of the Work and any modifications or additions
|
| 52 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 53 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 54 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 55 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 56 |
+
means any form of electronic, verbal, or written communication sent
|
| 57 |
+
to the Licensor or its representatives, including but not limited to
|
| 58 |
+
communication on electronic mailing lists, source code control systems,
|
| 59 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 60 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 61 |
+
excluding communication that is conspicuously marked or otherwise
|
| 62 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 63 |
+
|
| 64 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 65 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 66 |
+
subsequently incorporated within the Work.
|
| 67 |
+
|
| 68 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 69 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 70 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 71 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 72 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 73 |
+
Work and such Derivative Works in Source or Object form.
|
| 74 |
+
|
| 75 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 76 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 77 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 78 |
+
(except as stated in this section) patent license to make, have made,
|
| 79 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 80 |
+
where such license applies only to those patent claims licensable
|
| 81 |
+
by such Contributor that are necessarily infringed by their
|
| 82 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 83 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 84 |
+
institute patent litigation against any entity (including a
|
| 85 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 86 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 87 |
+
or contributory patent infringement, then any patent licenses
|
| 88 |
+
granted to You under this License for that Work shall terminate
|
| 89 |
+
as of the date such litigation is filed.
|
| 90 |
+
|
| 91 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 92 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 93 |
+
modifications, and in Source or Object form, provided that You
|
| 94 |
+
meet the following conditions:
|
| 95 |
+
|
| 96 |
+
(a) You must give any other recipients of the Work or
|
| 97 |
+
Derivative Works a copy of this License; and
|
| 98 |
+
|
| 99 |
+
(b) You must cause any modified files to carry prominent notices
|
| 100 |
+
stating that You changed the files; and
|
| 101 |
+
|
| 102 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 103 |
+
that You distribute, all copyright, patent, trademark, and
|
| 104 |
+
attribution notices from the Source form of the Work,
|
| 105 |
+
excluding those notices that do not pertain to any part of
|
| 106 |
+
the Derivative Works; and
|
| 107 |
+
|
| 108 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 109 |
+
distribution, then any Derivative Works that You distribute must
|
| 110 |
+
include a readable copy of the attribution notices contained
|
| 111 |
+
within such NOTICE file, excluding those notices that do not
|
| 112 |
+
pertain to any part of the Derivative Works, in at least one
|
| 113 |
+
of the following places: within a NOTICE text file distributed
|
| 114 |
+
as part of the Derivative Works; within the Source form or
|
| 115 |
+
documentation, if provided along with the Derivative Works; or,
|
| 116 |
+
within a display generated by the Derivative Works, if and
|
| 117 |
+
wherever such third-party notices normally appear. The contents
|
| 118 |
+
of the NOTICE file are for informational purposes only and
|
| 119 |
+
do not modify the License. You may add Your own attribution
|
| 120 |
+
notices within Derivative Works that You distribute, alongside
|
| 121 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 122 |
+
that such additional attribution notices cannot be construed
|
| 123 |
+
as modifying the License.
|
| 124 |
+
|
| 125 |
+
You may add Your own copyright statement to Your modifications and
|
| 126 |
+
may provide additional or different license terms and conditions
|
| 127 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 128 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 129 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 130 |
+
the conditions stated in this License.
|
| 131 |
+
|
| 132 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 133 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 134 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 135 |
+
this License, without any additional terms or conditions.
|
| 136 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 137 |
+
the terms of any separate license agreement you may have executed
|
| 138 |
+
with Licensor regarding such Contributions.
|
| 139 |
+
|
| 140 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 141 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 142 |
+
except as required for reasonable and customary use in describing the
|
| 143 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 144 |
+
|
| 145 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 146 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 147 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 148 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 149 |
+
implied, including, without limitation, any warranties or conditions
|
| 150 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 151 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 152 |
+
appropriateness of using or redistributing the Work and assume any
|
| 153 |
+
risks associated with Your exercise of permissions under this License.
|
| 154 |
+
|
| 155 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 156 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 157 |
+
unless required by applicable law (such as deliberate and grossly
|
| 158 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 159 |
+
liable to You for damages, including any direct, indirect, special,
|
| 160 |
+
incidental, or consequential damages of any character arising as a
|
| 161 |
+
result of this License or out of the use or inability to use the
|
| 162 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 163 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 164 |
+
other commercial damages or losses), even if such Contributor
|
| 165 |
+
has been advised of the possibility of such damages.
|
| 166 |
+
|
| 167 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 168 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 169 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 170 |
+
or other liability obligations and/or rights consistent with this
|
| 171 |
+
License. However, in accepting such obligations, You may act only
|
| 172 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 173 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 174 |
+
defend, and hold each Contributor harmless for any liability
|
| 175 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 176 |
+
of your accepting any such warranty or additional liability.
|
| 177 |
+
|
| 178 |
+
END OF TERMS AND CONDITIONS
|
| 179 |
+
|
| 180 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 181 |
+
|
| 182 |
+
To apply the Apache License to your work, attach the following
|
| 183 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 184 |
+
replaced with your own identifying information. (Don't include
|
| 185 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 186 |
+
comment syntax for the file format. We also recommend that a
|
| 187 |
+
file or class name and description of purpose be included on the
|
| 188 |
+
same "printed page" as the copyright notice for easier
|
| 189 |
+
identification within third-party archives.
|
| 190 |
+
|
| 191 |
+
Copyright [yyyy] [name of copyright owner]
|
| 192 |
+
|
| 193 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 194 |
+
you may not use this file except in compliance with the License.
|
| 195 |
+
You may obtain a copy of the License at
|
| 196 |
+
|
| 197 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 198 |
+
|
| 199 |
+
Unless required by applicable law or agreed to in writing, software
|
| 200 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 201 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 202 |
+
See the License for the specific language governing permissions and
|
| 203 |
+
limitations under the License.
|
licenses/Charsiu-MIT.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2021 jzhu
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
licenses/G2P-Apache-2.0.txt
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "{}"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright {yyyy} {name of copyright owner}
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
licenses/Whisper-MIT.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2022 OpenAI
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
model_manifest.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_name": "StreamPA",
|
| 3 |
+
"experiment_id": "M_stress_scalar_gate_capacity64",
|
| 4 |
+
"primary_seed": 1337,
|
| 5 |
+
"original_checkpoint_sha256": "870df8dbe3c787487f094e0c4d4ade6bed8fcc5d86b578c4edc57581e81023b4",
|
| 6 |
+
"scorer_sha256": "26b2f4a90b90e997ceb2eae9df2f09166a9173c1297c53ef26b4b843eb778583",
|
| 7 |
+
"config_sha256": "d508e880fff94cfc882109a1acc5122ea4c442bdc055114780d5c17b8ae1d026",
|
| 8 |
+
"parameter_count": 142258,
|
| 9 |
+
"official_paper_seeds": [
|
| 10 |
+
1337,
|
| 11 |
+
202601,
|
| 12 |
+
202602,
|
| 13 |
+
202603
|
| 14 |
+
],
|
| 15 |
+
"source_model_class": "PCNStreamingScorer",
|
| 16 |
+
"charsiu_mode": "prefix_recompute",
|
| 17 |
+
"commit_rule": "legacy",
|
| 18 |
+
"source_config_sha256": "0aca7850b95ad2d522992493b6eabfb5810be9b7802c5557c355047a090602ab",
|
| 19 |
+
"data_manifest_sha256": "ce3c021836de4e8241bfc61f196dbda502b06da160080e70e0de76accbc6214c",
|
| 20 |
+
"source_files": {
|
| 21 |
+
"augment_slot_prosody_pcn.py": "e6ace1b6f909fd911f7a163b12363e9d33ef60fd46f25af4e2499e4c4097db2f",
|
| 22 |
+
"benchmark_ours_m_efficiency.py": "d7263131d9c84b398669b50e609d14fa3925c31d6f1d89d134cbca3e5dffb9e3",
|
| 23 |
+
"build_charsiu_seq_data.py": "2535957cce06f1816b7520ea1ffc1a35dd3815bda11a0e335cbcbb3c8f92ff2e",
|
| 24 |
+
"build_streaming_asr_gopt_data.py": "3bab451431f3386f293bd49760252d558e93ae92e706971a05394fe898a7fe39",
|
| 25 |
+
"build_streaming_charsiu_data.py": "3d6963e702d792b1967a24af8add08eaf812f30f02798589d60c50708f30822c",
|
| 26 |
+
"build_streaming_pcn_gopt_data.py": "4444775df9e88586247ed6233ff8fadb9a099dae36dd98271e8dd2dc7c6da43f",
|
| 27 |
+
"infer_streaming_pcn.py": "e005fd5612f0286f026641958f2259ed2774811ac0a7f00f05b329758de3c1d1",
|
| 28 |
+
"streaming_gopt.py": "3643ef2e07ff94dc7dc6e829b825680f73c9846d95a21f88189cb5ce6b0dab68",
|
| 29 |
+
"streaming_pcn_gopt.py": "1794fa024a698babbdfca90dfc9091d0a7ec051215461870c9f0b597ccee16fd",
|
| 30 |
+
"train_streaming_pcn.py": "8779d624c563e84acaa42e4b812835e672b385e7b3b03b20a5aa3a0afce22df6"
|
| 31 |
+
},
|
| 32 |
+
"deployment_changes": [
|
| 33 |
+
"caller EOF determines final time",
|
| 34 |
+
"reference phone-ratio filter removed",
|
| 35 |
+
"explicit overlength and invalid-prefix statuses",
|
| 36 |
+
"ASR-word presentation aggregation; raw slot outputs preserved"
|
| 37 |
+
],
|
| 38 |
+
"score_scaling": {
|
| 39 |
+
"word_network_to_0_10": 5,
|
| 40 |
+
"utterance_network_to_0_10": 5,
|
| 41 |
+
"phone_network_to_0_2": 5,
|
| 42 |
+
"word_network_to_0_5": 2.5,
|
| 43 |
+
"utterance_network_to_0_5": 2.5,
|
| 44 |
+
"phone_network_to_0_5": 12.5
|
| 45 |
+
}
|
| 46 |
+
}
|
pyproject.toml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[build-system]
|
| 2 |
+
requires = ["setuptools>=68", "wheel"]
|
| 3 |
+
build-backend = "setuptools.build_meta"
|
| 4 |
+
|
| 5 |
+
[project]
|
| 6 |
+
name = "streampa"
|
| 7 |
+
version = "1.0.0"
|
| 8 |
+
description = "Frozen StreamPA streaming pronunciation-assessment inference"
|
| 9 |
+
requires-python = ">=3.10,<3.11"
|
| 10 |
+
dependencies = ["torch==2.5.1", "transformers==4.46.3", "huggingface-hub==0.36.0", "safetensors==0.6.2", "numpy==1.26.4", "librosa==0.11.0", "soundfile==0.13.1", "g2p-en==2.1.0", "nltk==3.9.1"]
|
| 11 |
+
|
| 12 |
+
[tool.setuptools.packages.find]
|
| 13 |
+
include = ["streampa*"]
|
requirements-lock.txt
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Verified Python 3.10 / Linux CPU environment.
|
| 2 |
+
# Install with --extra-index-url https://download.pytorch.org/whl/cpu
|
| 3 |
+
audioread==3.1.0
|
| 4 |
+
certifi==2026.7.22
|
| 5 |
+
cffi==2.1.1
|
| 6 |
+
charset-normalizer==3.5.1
|
| 7 |
+
click==8.5.0
|
| 8 |
+
cloudpickle==3.1.2
|
| 9 |
+
decorator==5.3.1
|
| 10 |
+
Distance==0.1.3
|
| 11 |
+
exceptiongroup==1.3.1
|
| 12 |
+
filelock==3.32.6
|
| 13 |
+
fsspec==2026.7.0
|
| 14 |
+
g2p-en==2.1.0
|
| 15 |
+
hf-xet==1.6.0
|
| 16 |
+
huggingface-hub==0.36.0
|
| 17 |
+
idna==3.19
|
| 18 |
+
inflect==7.5.0
|
| 19 |
+
iniconfig==2.3.0
|
| 20 |
+
Jinja2==3.1.6
|
| 21 |
+
joblib==1.6.0
|
| 22 |
+
lazy-loader==0.5
|
| 23 |
+
librosa==0.11.0
|
| 24 |
+
llvmlite==0.49.0
|
| 25 |
+
MarkupSafe==3.0.3
|
| 26 |
+
more-itertools==11.1.0
|
| 27 |
+
mpmath==1.3.0
|
| 28 |
+
msgpack==1.2.2
|
| 29 |
+
networkx==3.4.2
|
| 30 |
+
nltk==3.9.1
|
| 31 |
+
numba==0.67.0
|
| 32 |
+
numpy==1.26.4
|
| 33 |
+
packaging==26.3
|
| 34 |
+
platformdirs==4.11.8
|
| 35 |
+
pluggy==1.6.0
|
| 36 |
+
pooch==1.9.0
|
| 37 |
+
pycparser==3.0
|
| 38 |
+
Pygments==2.21.0
|
| 39 |
+
pytest==8.4.2
|
| 40 |
+
PyYAML==6.0.3
|
| 41 |
+
regex==2026.9.10
|
| 42 |
+
requests==2.34.2
|
| 43 |
+
safetensors==0.6.2
|
| 44 |
+
scikit-learn==1.7.2
|
| 45 |
+
scipy==1.15.3
|
| 46 |
+
setuptools==79.0.1
|
| 47 |
+
soundfile==0.13.1
|
| 48 |
+
soxr==1.1.0
|
| 49 |
+
sympy==1.13.1
|
| 50 |
+
threadpoolctl==3.6.0
|
| 51 |
+
tokenizers==0.20.3
|
| 52 |
+
tomli==2.4.1
|
| 53 |
+
torch==2.5.1+cpu
|
| 54 |
+
tqdm==4.70.0
|
| 55 |
+
transformers==4.46.3
|
| 56 |
+
typeguard==4.6.0
|
| 57 |
+
typing_extensions==4.16.0
|
| 58 |
+
urllib3==2.7.0
|
scorer/config.json
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"metadata_schema": "streaming_pcn_gopt_v2_stateful",
|
| 3 |
+
"pcn_type": "nbest_derived_phone_confusion_network",
|
| 4 |
+
"phone_dim": 40,
|
| 5 |
+
"seq_len": 72,
|
| 6 |
+
"prosody_dim": 14,
|
| 7 |
+
"prosody_norm_mean": [
|
| 8 |
+
3.9681200981140137,
|
| 9 |
+
204.3585205078125,
|
| 10 |
+
24.05475616455078,
|
| 11 |
+
-0.20867417752742767,
|
| 12 |
+
0.12271453440189362,
|
| 13 |
+
-4.253726005554199,
|
| 14 |
+
1.724206805229187,
|
| 15 |
+
0.004727904684841633,
|
| 16 |
+
0.20122256875038147,
|
| 17 |
+
10.172670364379883,
|
| 18 |
+
0.3134472370147705,
|
| 19 |
+
1.937715768814087,
|
| 20 |
+
5.8537139892578125,
|
| 21 |
+
17295600.0
|
| 22 |
+
],
|
| 23 |
+
"prosody_norm_std": [
|
| 24 |
+
2.0985183715820312,
|
| 25 |
+
55.536617279052734,
|
| 26 |
+
13.517866134643555,
|
| 27 |
+
0.4277317225933075,
|
| 28 |
+
0.06661950051784515,
|
| 29 |
+
0.6672922372817993,
|
| 30 |
+
0.378594309091568,
|
| 31 |
+
0.009153330698609352,
|
| 32 |
+
0.0010623399866744876,
|
| 33 |
+
11.080301284790039,
|
| 34 |
+
0.1449834257364273,
|
| 35 |
+
0.9631871581077576,
|
| 36 |
+
2.870692014694214,
|
| 37 |
+
205320480.0
|
| 38 |
+
],
|
| 39 |
+
"slot_prosody_dim": 17,
|
| 40 |
+
"slot_prosody": [
|
| 41 |
+
"slot_duration",
|
| 42 |
+
"slot_log_energy_mean",
|
| 43 |
+
"slot_log_energy_std",
|
| 44 |
+
"slot_log_energy_max",
|
| 45 |
+
"slot_f0_mean",
|
| 46 |
+
"slot_f0_std",
|
| 47 |
+
"slot_f0_max",
|
| 48 |
+
"slot_voiced_ratio",
|
| 49 |
+
"slot_position_in_word",
|
| 50 |
+
"word_phone_count",
|
| 51 |
+
"energy_relative_to_word_mean",
|
| 52 |
+
"duration_relative_to_word_mean",
|
| 53 |
+
"f0_relative_to_word_mean",
|
| 54 |
+
"is_vowel",
|
| 55 |
+
"lexical_stress_0",
|
| 56 |
+
"lexical_stress_1",
|
| 57 |
+
"lexical_stress_2"
|
| 58 |
+
],
|
| 59 |
+
"slot_prosody_norm_mean": [
|
| 60 |
+
0.039656512439250946,
|
| 61 |
+
-0.9386982917785645,
|
| 62 |
+
0.12416643649339676,
|
| 63 |
+
-0.7695538997650146,
|
| 64 |
+
49.076961517333984,
|
| 65 |
+
1.3523738384246826,
|
| 66 |
+
51.32339096069336,
|
| 67 |
+
0.18721239268779755,
|
| 68 |
+
0.13828140497207642,
|
| 69 |
+
1.0300568342208862,
|
| 70 |
+
4.231509587171445e-10,
|
| 71 |
+
0.28040772676467896,
|
| 72 |
+
-2.2446879910376083e-08,
|
| 73 |
+
0.11200845241546631,
|
| 74 |
+
0.0,
|
| 75 |
+
0.0,
|
| 76 |
+
0.0
|
| 77 |
+
],
|
| 78 |
+
"slot_prosody_norm_std": [
|
| 79 |
+
0.11444349586963654,
|
| 80 |
+
1.6153852939605713,
|
| 81 |
+
0.31157857179641724,
|
| 82 |
+
1.3436129093170166,
|
| 83 |
+
92.65617370605469,
|
| 84 |
+
4.188445568084717,
|
| 85 |
+
97.01981353759766,
|
| 86 |
+
0.3661966025829315,
|
| 87 |
+
0.31229057908058167,
|
| 88 |
+
1.9228776693344116,
|
| 89 |
+
0.3923450708389282,
|
| 90 |
+
0.5529012084007263,
|
| 91 |
+
27.52008056640625,
|
| 92 |
+
0.31510770320892334,
|
| 93 |
+
0.0,
|
| 94 |
+
0.0,
|
| 95 |
+
0.0
|
| 96 |
+
],
|
| 97 |
+
"utt_pooling_head": "gru_visible",
|
| 98 |
+
"fusion_mode": "scalar_gate",
|
| 99 |
+
"stress_branch": "detached",
|
| 100 |
+
"stress_grad_scale": 0.2,
|
| 101 |
+
"uses_state_projection": false,
|
| 102 |
+
"args": {
|
| 103 |
+
"lr": 0.001,
|
| 104 |
+
"n_epochs": 80,
|
| 105 |
+
"batch_size": 12,
|
| 106 |
+
"num_workers": 4,
|
| 107 |
+
"embed_dim": 64,
|
| 108 |
+
"depth": 3,
|
| 109 |
+
"heads": 4,
|
| 110 |
+
"gru_dim": 64,
|
| 111 |
+
"main_context_tokens": 16,
|
| 112 |
+
"tbptt_steps": 0,
|
| 113 |
+
"loss_w_phone": 1.0,
|
| 114 |
+
"loss_w_word": 1.0,
|
| 115 |
+
"loss_w_utt": 1.0,
|
| 116 |
+
"loss_w_asr": 0.5,
|
| 117 |
+
"loss_w_uncertainty": 0.2,
|
| 118 |
+
"loss_w_confidence": 0.2,
|
| 119 |
+
"loss_w_abstention": 0.2,
|
| 120 |
+
"loss_w_calibration": 0.1,
|
| 121 |
+
"loss_w_teacher_score": 0.8,
|
| 122 |
+
"loss_w_prefix_kd": 1.0,
|
| 123 |
+
"loss_w_rank": 0.2,
|
| 124 |
+
"loss_w_oracle_phone": 0.3,
|
| 125 |
+
"loss_w_oracle_word": 1.0,
|
| 126 |
+
"loss_w_oracle_utt_prefix": 0.2,
|
| 127 |
+
"loss_w_oracle_utt_final": 0.3,
|
| 128 |
+
"loss_w_stress_pearson": 0.2,
|
| 129 |
+
"loss_w_oracle_stress_pearson": 0.3,
|
| 130 |
+
"loss_w_teacher_stress_pearson": 0.1,
|
| 131 |
+
"loss_w_stress_rank": 0.1,
|
| 132 |
+
"loss_w_oracle_stress_rank": 0.1,
|
| 133 |
+
"loss_w_phone_stability": 0.01,
|
| 134 |
+
"loss_w_word_stability": 0.01,
|
| 135 |
+
"loss_w_utt_stability": 0.01,
|
| 136 |
+
"loss_w_commit_consistency": 0.0,
|
| 137 |
+
"loss_w_state_projection": 0.0,
|
| 138 |
+
"utt_dim_weights": [
|
| 139 |
+
1.0,
|
| 140 |
+
0.0,
|
| 141 |
+
1.0,
|
| 142 |
+
1.0,
|
| 143 |
+
1.0
|
| 144 |
+
],
|
| 145 |
+
"word_dim_weights": [
|
| 146 |
+
1.0,
|
| 147 |
+
3.0,
|
| 148 |
+
1.0
|
| 149 |
+
],
|
| 150 |
+
"teacher_word_dim_weights": [
|
| 151 |
+
1.0,
|
| 152 |
+
2.0,
|
| 153 |
+
1.0
|
| 154 |
+
],
|
| 155 |
+
"oracle_word_dim_weights": [
|
| 156 |
+
1.0,
|
| 157 |
+
5.0,
|
| 158 |
+
1.0
|
| 159 |
+
],
|
| 160 |
+
"soft_label_policy": "original",
|
| 161 |
+
"relaxed_min_gt_posterior": 0.05,
|
| 162 |
+
"relaxed_acoustic_scale": 0.3,
|
| 163 |
+
"relaxed_min_weight": 0.05,
|
| 164 |
+
"relaxed_max_weight": 0.5,
|
| 165 |
+
"utt_pooling_head": "gru_visible",
|
| 166 |
+
"fusion_mode": "scalar_gate",
|
| 167 |
+
"rank_margin": 0.02,
|
| 168 |
+
"stress_rank_margin": 0.02,
|
| 169 |
+
"stress_rank_max_items": 512,
|
| 170 |
+
"stress_loss_mask": "vowel",
|
| 171 |
+
"stress_voiced_threshold": 0.3,
|
| 172 |
+
"stress_branch": "detached",
|
| 173 |
+
"stress_grad_scale": 0.2,
|
| 174 |
+
"grad_clip_norm": 1.0,
|
| 175 |
+
"compile": false,
|
| 176 |
+
"tf32": true,
|
| 177 |
+
"seed": 1337
|
| 178 |
+
},
|
| 179 |
+
"preserve_unused_legacy_utt_head": true
|
| 180 |
+
}
|
scorer/inference_assets.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"sample_rate": 16000,
|
| 3 |
+
"chunk_sec": 0.64,
|
| 4 |
+
"right_context_sec": 0.16,
|
| 5 |
+
"nbest": 5,
|
| 6 |
+
"beam_size": 8,
|
| 7 |
+
"max_new_tokens": 128,
|
| 8 |
+
"no_repeat_ngram_size": 0,
|
| 9 |
+
"language": "english",
|
| 10 |
+
"min_sil_frames": 4,
|
| 11 |
+
"commit_rule": "legacy",
|
| 12 |
+
"max_audio_sec": 30,
|
| 13 |
+
"filter": {
|
| 14 |
+
"max_new_tokens": 128,
|
| 15 |
+
"no_repeat_ngram_size": 0,
|
| 16 |
+
"strict_repeat_word_trigger": 64,
|
| 17 |
+
"strict_repeat_phone_trigger": 100,
|
| 18 |
+
"repeat_ngram_min_repeats": 4,
|
| 19 |
+
"repeat_max_ngram_size": 12,
|
| 20 |
+
"repeat_ngram_coverage": 0.6,
|
| 21 |
+
"repeat_token_ratio": 0.5,
|
| 22 |
+
"length_policy": "word_count and absolute phone_count only enable strict repetition checks; non-repetitive long hypotheses are retained",
|
| 23 |
+
"hard_rejection_policy": "reference-independent repeated hypotheses only; G2P or alignment failures return explicit invalid status"
|
| 24 |
+
},
|
| 25 |
+
"historical_reference_ratio_filter_disabled": true,
|
| 26 |
+
"lexical_stress_features": "zero as frozen builder",
|
| 27 |
+
"native_target_divisor": 5,
|
| 28 |
+
"score_scaling": {
|
| 29 |
+
"word_network_to_0_10": 5,
|
| 30 |
+
"utterance_network_to_0_10": 5,
|
| 31 |
+
"phone_network_to_0_2": 5,
|
| 32 |
+
"word_network_to_0_5": 2.5,
|
| 33 |
+
"utterance_network_to_0_5": 2.5,
|
| 34 |
+
"phone_network_to_0_5": 12.5
|
| 35 |
+
},
|
| 36 |
+
"clip_scores": false,
|
| 37 |
+
"historical_filter_metadata": {
|
| 38 |
+
"max_new_tokens": 128,
|
| 39 |
+
"no_repeat_ngram_size": 0,
|
| 40 |
+
"strict_repeat_word_trigger": 64,
|
| 41 |
+
"strict_repeat_phone_trigger": 100,
|
| 42 |
+
"max_phone_ratio": 3.0,
|
| 43 |
+
"repeat_ngram_min_repeats": 4,
|
| 44 |
+
"repeat_max_ngram_size": 12,
|
| 45 |
+
"repeat_ngram_coverage": 0.6,
|
| 46 |
+
"repeat_token_ratio": 0.5,
|
| 47 |
+
"length_policy": "word_count and absolute phone_count only enable strict repetition checks; non-repetitive long hypotheses are retained",
|
| 48 |
+
"hard_rejection_policy": "drop individual N-best hypotheses with detected repetition or ASR/reference phone ratio above max_phone_ratio; drop chunk only if all hypotheses are filtered"
|
| 49 |
+
}
|
| 50 |
+
}
|
streaming_gopt_best/best_audio_model.pth → scorer/model.safetensors
RENAMED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:26b2f4a90b90e997ceb2eae9df2f09166a9173c1297c53ef26b4b843eb778583
|
| 3 |
+
size 578264
|
scripts/setup_assets.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Fetch fixed official third-party assets; validate hashes; no model execution."""
|
| 2 |
+
import argparse
|
| 3 |
+
import hashlib
|
| 4 |
+
import importlib.metadata
|
| 5 |
+
import json
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
import urllib.request
|
| 8 |
+
import zipfile
|
| 9 |
+
from huggingface_hub import hf_hub_download
|
| 10 |
+
|
| 11 |
+
def sha(path):
|
| 12 |
+
h=hashlib.sha256()
|
| 13 |
+
with Path(path).open('rb') as f:
|
| 14 |
+
for chunk in iter(lambda:f.read(1048576),b''): h.update(chunk)
|
| 15 |
+
return h.hexdigest()
|
| 16 |
+
|
| 17 |
+
def setup(bundle, offline=False):
|
| 18 |
+
bundle=Path(bundle).resolve()
|
| 19 |
+
spec=json.loads((bundle/'assets/runtime_sources.json').read_text())
|
| 20 |
+
checks=[]
|
| 21 |
+
for row in spec['sources']:
|
| 22 |
+
dest=bundle/row['destination']
|
| 23 |
+
dest.parent.mkdir(parents=True,exist_ok=True)
|
| 24 |
+
if not dest.exists():
|
| 25 |
+
if offline: raise FileNotFoundError(f'Offline asset missing: {row["destination"]}')
|
| 26 |
+
if row['kind']=='hub':
|
| 27 |
+
source=Path(hf_hub_download(row['repo_id'],row['filename'],revision=row['revision'],token=False))
|
| 28 |
+
assert sha(source)==row['sha256'], row['destination']
|
| 29 |
+
dest.write_bytes(source.read_bytes())
|
| 30 |
+
else:
|
| 31 |
+
with urllib.request.urlopen(row['url'],timeout=120) as response:
|
| 32 |
+
content=response.read()
|
| 33 |
+
if hashlib.sha256(content).hexdigest()!=row['sha256']:
|
| 34 |
+
raise RuntimeError(f'Asset checksum failed: {row["destination"]}')
|
| 35 |
+
dest.write_bytes(content)
|
| 36 |
+
if sha(dest)!=row['sha256']:
|
| 37 |
+
raise RuntimeError(f'Asset checksum failed, not overwriting: {row["destination"]}')
|
| 38 |
+
if row['kind']=='zip':
|
| 39 |
+
target=(bundle/row['extract_to']).resolve()
|
| 40 |
+
with zipfile.ZipFile(dest) as archive:
|
| 41 |
+
for member in archive.infolist():
|
| 42 |
+
path=(target/member.filename).resolve()
|
| 43 |
+
if target!=path and target not in path.parents:
|
| 44 |
+
raise RuntimeError('Unsafe resource archive path')
|
| 45 |
+
if not member.is_dir():
|
| 46 |
+
content=archive.read(member)
|
| 47 |
+
if path.exists():
|
| 48 |
+
if path.read_bytes()!=content:
|
| 49 |
+
raise RuntimeError(f'Installed resource differs: {path.name}')
|
| 50 |
+
else:
|
| 51 |
+
path.parent.mkdir(parents=True,exist_ok=True)
|
| 52 |
+
path.write_bytes(content)
|
| 53 |
+
checks.append(dict(path=row['destination'],sha256=row['sha256'],status='PASS'))
|
| 54 |
+
inventory=json.loads((bundle/'assets/prepared_resource_hashes.json').read_text())
|
| 55 |
+
dist=importlib.metadata.distribution('g2p-en')
|
| 56 |
+
if dist.version!=inventory['g2p_en_version']: raise RuntimeError('G2P package version differs')
|
| 57 |
+
for row in inventory['g2p_files']:
|
| 58 |
+
path=Path(dist.locate_file(row['package_relative']))
|
| 59 |
+
if not path.is_file() or sha(path)!=row['sha256']:
|
| 60 |
+
raise RuntimeError(f'G2P resource differs: {row["package_relative"]}')
|
| 61 |
+
checks.append(dict(path=row['package_relative'],sha256=row['sha256'],status='PASS'))
|
| 62 |
+
for row in inventory['prepared_resources']:
|
| 63 |
+
path=bundle/row['path']
|
| 64 |
+
if not path.is_file() or sha(path)!=row['sha256']:
|
| 65 |
+
raise RuntimeError(f'Prepared resource differs: {row["path"]}')
|
| 66 |
+
print(json.dumps(dict(offline=offline,checks=checks),indent=2))
|
| 67 |
+
return checks
|
| 68 |
+
|
| 69 |
+
if __name__=='__main__':
|
| 70 |
+
p=argparse.ArgumentParser()
|
| 71 |
+
p.add_argument('--bundle-dir',type=Path,default=Path(__file__).resolve().parents[1])
|
| 72 |
+
p.add_argument('--offline',action='store_true')
|
| 73 |
+
a=p.parse_args()
|
| 74 |
+
setup(a.bundle_dir,a.offline)
|
scripts/verify_bundle.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Verify every published entity against the release SHA256SUMS."""
|
| 2 |
+
import argparse
|
| 3 |
+
import hashlib
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
def verify(root):
|
| 7 |
+
root=Path(root).resolve(); count=0
|
| 8 |
+
for row in (root/'SHA256SUMS').read_text().splitlines():
|
| 9 |
+
digest,name=row.split(' ',1); path=(root/name).resolve()
|
| 10 |
+
if root not in path.parents: raise ValueError('Invalid manifest path')
|
| 11 |
+
h=hashlib.sha256()
|
| 12 |
+
with path.open('rb') as f:
|
| 13 |
+
for block in iter(lambda:f.read(1048576),b''): h.update(block)
|
| 14 |
+
if h.hexdigest()!=digest: raise RuntimeError(f'Checksum mismatch: {name}')
|
| 15 |
+
count+=1
|
| 16 |
+
print(f'PASS: {count} published files verified')
|
| 17 |
+
return count
|
| 18 |
+
|
| 19 |
+
if __name__=='__main__':
|
| 20 |
+
p=argparse.ArgumentParser(); p.add_argument('--bundle-dir',default=Path(__file__).resolve().parents[1])
|
| 21 |
+
verify(p.parse_args().bundle_dir)
|
streaming_gopt_best/config.json
DELETED
|
@@ -1,42 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"data_dir": "/DATA_2/guest/custom-gopt/data/streaming_asr_gopt_v6_asrconf",
|
| 3 |
-
"input_dim": 47,
|
| 4 |
-
"phn_num": 40,
|
| 5 |
-
"seq_len": 692,
|
| 6 |
-
"args": {
|
| 7 |
-
"data_dir": "/DATA_2/guest/custom-gopt/data/streaming_asr_gopt_v6_asrconf",
|
| 8 |
-
"exp_dir": "/DATA_2/guest/custom-gopt/exp/streaming-asr-gopt-v6-asrconf",
|
| 9 |
-
"lr": 0.001,
|
| 10 |
-
"n_epochs": 100,
|
| 11 |
-
"depth": 3,
|
| 12 |
-
"heads": 1,
|
| 13 |
-
"batch_size": 64,
|
| 14 |
-
"embed_dim": 24,
|
| 15 |
-
"loss_w_phn": 1.0,
|
| 16 |
-
"loss_w_word": 1.0,
|
| 17 |
-
"loss_w_word_asr": 1.0,
|
| 18 |
-
"loss_w_utt": 1.0,
|
| 19 |
-
"model": "streaming_gopt",
|
| 20 |
-
"noise": 0.0,
|
| 21 |
-
"num_workers": 4,
|
| 22 |
-
"device": "cuda",
|
| 23 |
-
"main_context_tokens": "4,8,12,16",
|
| 24 |
-
"right_context_tokens": "0,1,2,4",
|
| 25 |
-
"compile": false,
|
| 26 |
-
"tf32": false,
|
| 27 |
-
"seed": 1337,
|
| 28 |
-
"resume": false,
|
| 29 |
-
"main_context_token_choices": [
|
| 30 |
-
4,
|
| 31 |
-
8,
|
| 32 |
-
12,
|
| 33 |
-
16
|
| 34 |
-
],
|
| 35 |
-
"right_context_token_choices": [
|
| 36 |
-
0,
|
| 37 |
-
1,
|
| 38 |
-
2,
|
| 39 |
-
4
|
| 40 |
-
]
|
| 41 |
-
}
|
| 42 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
streaming_gopt_best/inference_assets.json
DELETED
|
@@ -1,48 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"sample_rate": 16000,
|
| 3 |
-
"train_norm_mean": 0.0722440779209137,
|
| 4 |
-
"train_norm_std": 0.25949764251708984,
|
| 5 |
-
"feat_dim": 47,
|
| 6 |
-
"phn_num": 40,
|
| 7 |
-
"phn_dict": {
|
| 8 |
-
"W": 0,
|
| 9 |
-
"IY": 1,
|
| 10 |
-
"K": 2,
|
| 11 |
-
"AO": 3,
|
| 12 |
-
"L": 4,
|
| 13 |
-
"IH": 5,
|
| 14 |
-
"T": 6,
|
| 15 |
-
"B": 7,
|
| 16 |
-
"EH": 8,
|
| 17 |
-
"R": 9,
|
| 18 |
-
"Z": 10,
|
| 19 |
-
"OW": 11,
|
| 20 |
-
"TH": 12,
|
| 21 |
-
"F": 13,
|
| 22 |
-
"AY": 14,
|
| 23 |
-
"V": 15,
|
| 24 |
-
"AH": 16,
|
| 25 |
-
"N": 17,
|
| 26 |
-
"UW": 18,
|
| 27 |
-
"S": 19,
|
| 28 |
-
"G": 20,
|
| 29 |
-
"AA": 21,
|
| 30 |
-
"M": 22,
|
| 31 |
-
"P": 23,
|
| 32 |
-
"NG": 24,
|
| 33 |
-
"HH": 25,
|
| 34 |
-
"EY": 26,
|
| 35 |
-
"SH": 27,
|
| 36 |
-
"AE": 28,
|
| 37 |
-
"D": 29,
|
| 38 |
-
"UH": 30,
|
| 39 |
-
"AW": 31,
|
| 40 |
-
"DH": 32,
|
| 41 |
-
"ER": 33,
|
| 42 |
-
"Y": 34,
|
| 43 |
-
"JH": 35,
|
| 44 |
-
"CH": 36,
|
| 45 |
-
"OY": 37,
|
| 46 |
-
"ZH": 38
|
| 47 |
-
}
|
| 48 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
streaming_gopt_best/result.csv
DELETED
|
@@ -1,101 +0,0 @@
|
|
| 1 |
-
epoch,phone_train_mse,phone_train_pcc,phone_val_mse,phone_val_pcc,learning rate,utt_train_mse_accuracy,utt_train_mse_completeness,utt_train_mse_fluency,utt_train_mse_prosodic,utt_train_mse_total,utt_train_pcc_accuracy,utt_train_pcc_completeness,utt_train_pcc_fluency,utt_train_pcc_prosodic,utt_train_pcc_total,utt_val_mse_accuracy,utt_val_mse_completeness,utt_val_mse_fluency,utt_val_mse_prosodic,utt_val_mse_total,utt_val_pcc_accuracy,utt_val_pcc_completeness,utt_val_pcc_fluency,utt_val_pcc_prosodic,utt_val_pcc_total,word_train_pcc_accuracy,word_train_pcc_stress,word_train_pcc_total,word_train_pcc_asr_accuracy,word_val_pcc_accuracy,word_val_pcc_stress,word_val_pcc_total,word_val_pcc_asr_accuracy
|
| 2 |
-
0.000000000000000000e+00,1.079137027263641357e-01,2.776732289780305396e-01,5.458179116249084473e-02,2.056475016002890233e-01,1.000000000000000021e-03,1.017732769250869751e-01,1.537960255518555641e-03,8.632741868495941162e-02,7.209369540214538574e-02,9.389597922563552856e-02,5.060659645574577814e-01,1.744086679858893388e-02,5.009421071735626896e-01,4.932015166782500182e-01,5.813221164796392726e-01,8.561448007822036743e-02,1.139749772846698761e-03,6.641924381256103516e-02,7.153119891881942749e-02,7.674410939216613770e-02,4.032423467488363000e-01,-1.592214327453594924e-02,3.815769695007495410e-01,3.394003035876998475e-01,5.042478848682950821e-01,2.077918562638139122e-01,-8.336524674171885696e-02,2.191634810191739335e-01,1.596240049224992019e-01,1.359882526136001468e-01,-4.588009800221485440e-02,1.449690180410702356e-01,1.804069662785112715e-01
|
| 3 |
-
1.000000000000000000e+00,1.041820421814918518e-01,3.706449166264469408e-01,6.219116970896720886e-02,2.582953758852352122e-01,1.000000000000000021e-03,7.506916671991348267e-02,3.650750964879989624e-03,6.011062115430831909e-02,5.140639096498489380e-02,6.998758018016815186e-02,6.370056414927510735e-01,1.298882550120022128e-01,6.780273015672545478e-01,6.862977747573038023e-01,6.796541662922360727e-01,8.756997436285018921e-02,3.653137944638729095e-03,7.288870215415954590e-02,6.140800565481185913e-02,8.417460322380065918e-02,5.261388264911209811e-01,2.443657795377397399e-02,5.871761168081823801e-01,5.965706019434455776e-01,5.679167708900907385e-01,3.640398602379311677e-01,-4.233877629281119354e-02,3.880548763609277252e-01,2.728305487899807535e-01,2.182483660645393453e-01,-3.853244682653233361e-02,2.504640631625094094e-01,3.203802817658301660e-01
|
| 4 |
-
2.000000000000000000e+00,9.281047433614730835e-02,4.388932832189844646e-01,5.085919052362442017e-02,2.917910224071572634e-01,1.000000000000000021e-03,6.204526871442794800e-02,3.228217363357543945e-03,4.249990358948707581e-02,4.041586443781852722e-02,5.738137662410736084e-02,7.214929956115374576e-01,8.182538551806139981e-02,7.771532765174712365e-01,7.594808830575937586e-01,7.377560843879427122e-01,6.918659806251525879e-02,3.128336509689688683e-03,4.416642710566520691e-02,4.611694440245628357e-02,6.303169578313827515e-02,5.695003532178497530e-01,-5.067768569970219732e-03,6.471075033146025390e-01,6.484407925864426048e-01,5.987705131988432239e-01,4.295590856406035218e-01,4.127377961734719075e-02,4.581967800386524403e-01,3.538432132168152222e-01,2.500769892836061659e-01,-1.171821163103803007e-02,2.867814875505260153e-01,3.951812826603934847e-01
|
| 5 |
-
3.000000000000000000e+00,8.795424550771713257e-02,4.852790553580234034e-01,5.026153847575187683e-02,3.126730051242129216e-01,1.000000000000000021e-03,5.290393158793449402e-02,1.651985454373061657e-03,3.355559706687927246e-02,3.485541418194770813e-02,4.882648214697837830e-02,7.594843870921196283e-01,6.719378746568728522e-02,8.178115626685859008e-01,8.000001848572846352e-01,7.757036692980765480e-01,6.167699769139289856e-02,1.421156455762684345e-03,4.079946875572204590e-02,4.082865267992019653e-02,5.512074753642082214e-02,6.063115601065953708e-01,-1.548446743561882055e-02,7.083793729119221005e-01,6.996366675591403350e-01,6.376530729514864326e-01,4.858310069896916716e-01,6.929232988970045193e-02,5.100691439367808222e-01,3.846799513993024444e-01,2.785472851702357477e-01,-3.475561394853065884e-03,3.115620678538462696e-01,4.184954436680822232e-01
|
| 6 |
-
4.000000000000000000e+00,8.721461892127990723e-02,5.109648368379621219e-01,6.383151561021804810e-02,3.174473789177553185e-01,1.000000000000000021e-03,4.725972935557365417e-02,1.288253813982009888e-03,3.230554983019828796e-02,3.321465849876403809e-02,4.065737873315811157e-02,7.754567118380922830e-01,6.929346740417351158e-02,8.312628993336449446e-01,8.169172738551149227e-01,7.957848608365545306e-01,6.013352796435356140e-02,9.462164598517119884e-04,3.752611950039863586e-02,3.895737975835800171e-02,5.430128425359725952e-02,6.190762454692686489e-01,1.694164467552703758e-03,7.283609325777327115e-01,7.194678905436201477e-01,6.520788335982493633e-01,5.206589800308554228e-01,1.233108496997321890e-01,5.402275814379471353e-01,3.854360042662868802e-01,2.983254935808805075e-01,2.548658286062590109e-02,3.280349747585073472e-01,4.151764133724160089e-01
|
| 7 |
-
5.000000000000000000e+00,8.810387551784515381e-02,5.233755684010888976e-01,6.833378225564956665e-02,3.205610361957397236e-01,1.000000000000000021e-03,4.402649030089378357e-02,1.182442763820290565e-03,3.257671743631362915e-02,2.821853384375572205e-02,3.860916569828987122e-02,7.844561945868420150e-01,8.341824281097018345e-02,8.422572964788933580e-01,8.295394734322586450e-01,8.070802518044921658e-01,6.067190691828727722e-02,7.594404160045087337e-04,4.596406221389770508e-02,3.856667503714561462e-02,5.295049399137496948e-02,6.282226133800322687e-01,1.692926155089146192e-02,7.419398580744197558e-01,7.319690681809026822e-01,6.642837027774701752e-01,5.339778616486737794e-01,1.488257401530594937e-01,5.520129563203034495e-01,3.729090532051128615e-01,3.039651271249513842e-01,4.959261266514947142e-02,3.319566011496995483e-01,4.006294076261598947e-01
|
| 8 |
-
6.000000000000000000e+00,8.414012193679809570e-02,5.381291814772770632e-01,6.494909524917602539e-02,3.196504956671062936e-01,1.000000000000000021e-03,4.297406971454620361e-02,1.028442755341529846e-03,2.753048017621040344e-02,2.733003720641136169e-02,3.911860659718513489e-02,7.904577456767357679e-01,8.890016920034679582e-02,8.449343388914654085e-01,8.328881381871791056e-01,8.106734163016174888e-01,6.023196130990982056e-02,6.536911241710186005e-04,3.779817745089530945e-02,3.825043886899948120e-02,5.370716378092765808e-02,6.276532593165649043e-01,3.025794644290185492e-02,7.427249721192606957e-01,7.321564399718462068e-01,6.630480505758957754e-01,5.454458282743140929e-01,1.487224212418345459e-01,5.636291401743753759e-01,3.761236095987761652e-01,3.047638127886744819e-01,4.767652687284456431e-02,3.318484113513537892e-01,3.933327346715422279e-01
|
| 9 |
-
7.000000000000000000e+00,8.397044241428375244e-02,5.454177449248397425e-01,6.567811965942382812e-02,3.296529190938821685e-01,1.000000000000000021e-03,4.575878381729125977e-02,8.211127133108675480e-04,2.928980439901351929e-02,3.056729398667812347e-02,4.057361558079719543e-02,7.909265393099840225e-01,7.771252355228436270e-02,8.451621372874504878e-01,8.331802795242353454e-01,8.122646093462853045e-01,6.321127712726593018e-02,4.775344568770378828e-04,3.779856115579605103e-02,4.165362194180488586e-02,5.752434208989143372e-02,6.332849796716126800e-01,3.639127957694833493e-02,7.445063607304056585e-01,7.304949047675072249e-01,6.655040270535693692e-01,5.536482511279675611e-01,1.309219956720971967e-01,5.684799286193154000e-01,3.703783991526826136e-01,3.100192455908276079e-01,3.533682433665723266e-02,3.363407503874519255e-01,3.893300762394926728e-01
|
| 10 |
-
8.000000000000000000e+00,7.932690531015396118e-02,5.582815030417074276e-01,5.237221717834472656e-02,3.340726441925265799e-01,1.000000000000000021e-03,4.299703985452651978e-02,8.145723841153085232e-04,2.827190607786178589e-02,2.760162949562072754e-02,3.740537166595458984e-02,7.971513246111363582e-01,4.942613349235330106e-02,8.506182705909921538e-01,8.374494236667009428e-01,8.179940128038997171e-01,5.951761454343795776e-02,4.477837937884032726e-04,3.352825716137886047e-02,3.847572952508926392e-02,5.108420550823211670e-02,6.266715202161995402e-01,5.474103983132304341e-02,7.435485424447159097e-01,7.338903823378927216e-01,6.652732645359187291e-01,5.742735421688209829e-01,1.349266156713314069e-01,5.865511050648093416e-01,3.641521699647172206e-01,3.124377730571293310e-01,4.111003383586240428e-02,3.384491038277656072e-01,3.718153188329691994e-01
|
| 11 |
-
9.000000000000000000e+00,7.904511690139770508e-02,5.650366056915427926e-01,4.784649610519409180e-02,3.360747481594478225e-01,1.000000000000000021e-03,4.097953066229820251e-02,7.262713043019175529e-04,2.636589109897613525e-02,2.707981504499912262e-02,3.672679513692855835e-02,8.011406049594625989e-01,8.184587861598646708e-02,8.525136531793285899e-01,8.391137622169869692e-01,8.216666105301617673e-01,6.167176365852355957e-02,3.881674201693385839e-04,3.504731878638267517e-02,3.860588744282722473e-02,5.474837496876716614e-02,6.288495700353141649e-01,6.697507963883096715e-02,7.402487613039686609e-01,7.330606577567296833e-01,6.682398542183080048e-01,5.746754602825498992e-01,7.563367138892368446e-02,5.882577255826275664e-01,3.789453452980684478e-01,3.127768395502930621e-01,1.541690944289706745e-02,3.394110095896446522e-01,3.878069671015842435e-01
|
| 12 |
-
1.000000000000000000e+01,7.689129561185836792e-02,5.776432205722596969e-01,5.536097660660743713e-02,3.413896982038953642e-01,1.000000000000000021e-03,4.202426597476005554e-02,6.829157355241477489e-04,3.145125880837440491e-02,3.008835576474666595e-02,3.676103428006172180e-02,8.051306298644963499e-01,1.043719686279931530e-01,8.540243584935583998e-01,8.405825732097117475e-01,8.262232117460068803e-01,6.519529968500137329e-02,3.890781954396516085e-04,4.766941443085670471e-02,4.384284839034080505e-02,5.613239854574203491e-02,6.316056430066069316e-01,3.294144611561136693e-02,7.459347545625676368e-01,7.356252546667766401e-01,6.703888185909948616e-01,5.841334619136506756e-01,1.479103288774953062e-01,5.959824190433531399e-01,3.707404388453034993e-01,3.155141152755229772e-01,5.384112108945592057e-02,3.406913478994477162e-01,3.788207564887718370e-01
|
| 13 |
-
1.100000000000000000e+01,7.516384124755859375e-02,5.914801923276814533e-01,4.760764539241790771e-02,3.483196833867099329e-01,1.000000000000000021e-03,4.065796732902526855e-02,7.364017073996365070e-04,2.592927962541580200e-02,2.613618224859237671e-02,3.549587726593017578e-02,8.087561591048159082e-01,7.958508800689907681e-02,8.556992770720274200e-01,8.415271552833636370e-01,8.285827151333120533e-01,5.945572257041931152e-02,3.861584118567407131e-04,3.543989360332489014e-02,3.745276108384132385e-02,5.191485211253166199e-02,6.229969702595520298e-01,6.281145466019341650e-02,7.397628520376408057e-01,7.312510635331408437e-01,6.618655838036759942e-01,6.043028196305714195e-01,1.060545625305443773e-01,6.171694270678337313e-01,3.595423438258240623e-01,3.149798370223247934e-01,2.745311107611971002e-02,3.418123225833971102e-01,3.633849619530142849e-01
|
| 14 |
-
1.200000000000000000e+01,7.663895934820175171e-02,5.997901646405072729e-01,6.157444044947624207e-02,3.468672964819129456e-01,1.000000000000000021e-03,3.920639306306838989e-02,7.200848194770514965e-04,2.613169886171817780e-02,2.673601917922496796e-02,3.415981680154800415e-02,8.116596138560332463e-01,7.243813638614614303e-02,8.570480618383445881e-01,8.442193388473763216e-01,8.330602093696122257e-01,6.306268274784088135e-02,3.563576610758900642e-04,3.395630046725273132e-02,3.661862760782241821e-02,5.546560510993003845e-02,6.304151407170361932e-01,9.210440100728198298e-02,7.433763895498277652e-01,7.354283789871293164e-01,6.671798055380051551e-01,5.979152664819351592e-01,1.571473732632979736e-01,6.082983081070993947e-01,3.693969070139038191e-01,3.118508839069054628e-01,5.883939534569676555e-02,3.370823225553667979e-01,3.799641527374392203e-01
|
| 15 |
-
1.300000000000000000e+01,7.256346195936203003e-02,6.098782952290799919e-01,5.524610355496406555e-02,3.542463643554487618e-01,1.000000000000000021e-03,3.843601420521736145e-02,8.357077604159712791e-04,2.614173851907253265e-02,2.665366418659687042e-02,3.454660996794700623e-02,8.144846763541699897e-01,7.492669135169920114e-02,8.570755867672109618e-01,8.449939293996406864e-01,8.335468067718763141e-01,6.179256364703178406e-02,4.695496463682502508e-04,3.769916668534278870e-02,3.874914720654487610e-02,5.201447010040283203e-02,6.225628455283348517e-01,9.648262583582849217e-02,7.424723665114357773e-01,7.330119067794130805e-01,6.598358610773447097e-01,6.110371157194449676e-01,1.552750881937589311e-01,6.246053003526816916e-01,3.665856355335136985e-01,3.189198594517477781e-01,5.958419476997803971e-02,3.459633092613857985e-01,3.805706792897113333e-01
|
| 16 |
-
1.400000000000000000e+01,7.195486128330230713e-02,6.169794118565439245e-01,4.993401467800140381e-02,3.392562008434108489e-01,1.000000000000000021e-03,4.383291304111480713e-02,7.470826385542750359e-04,2.761650644242763519e-02,2.762824855744838715e-02,4.176798462867736816e-02,8.168654544164080100e-01,8.989541314315742382e-02,8.568601612763651065e-01,8.443383740427758966e-01,8.353573513014010965e-01,6.755137443542480469e-02,4.235668457113206387e-04,3.518375381827354431e-02,3.951911628246307373e-02,6.108940392732620239e-02,6.087498558206331234e-01,7.872335351492198985e-02,7.336116943863905115e-01,7.258784055892653075e-01,6.511477998726845628e-01,6.364816304845191119e-01,1.601424668561550746e-01,6.481992154516424964e-01,3.693914464094895655e-01,3.083383534991637753e-01,5.489005947919788769e-02,3.322964769383936479e-01,3.704947441740806813e-01
|
| 17 |
-
1.500000000000000000e+01,7.075122743844985962e-02,6.323892591565722920e-01,5.910111218690872192e-02,3.447981679203572791e-01,1.000000000000000021e-03,3.858285024762153625e-02,7.073186570778489113e-04,2.751739509403705597e-02,2.719741687178611755e-02,3.248418867588043213e-02,8.215097414902410300e-01,8.740473396015147056e-02,8.617868267862002218e-01,8.467433481412670604e-01,8.414161078562124585e-01,6.167950481176376343e-02,3.493003605399280787e-04,3.442856296896934509e-02,3.846492990851402283e-02,5.255946889519691467e-02,6.165435109975533345e-01,1.490365179083074643e-01,7.385942566868495263e-01,7.251184387416174104e-01,6.612034657340111199e-01,6.239650975157681190e-01,1.682825843195471516e-01,6.347013315289149471e-01,3.780849372705800682e-01,3.048308048922340752e-01,6.156359888784206091e-02,3.311269076812738410e-01,3.888617018279006410e-01
|
| 18 |
-
1.600000000000000000e+01,6.941830366849899292e-02,6.367579718055026428e-01,5.368442833423614502e-02,3.582530429930391169e-01,1.000000000000000021e-03,3.857583552598953247e-02,7.032497669570147991e-04,2.830678969621658325e-02,3.184502571821212769e-02,3.400620073080062866e-02,8.241257037848728206e-01,3.477050389087385507e-02,8.658223416019931173e-01,8.504439691558483005e-01,8.453646623834510931e-01,5.808711051940917969e-02,3.656651824712753296e-04,3.896261751651763916e-02,4.351807758212089539e-02,5.077878013253211975e-02,6.306182923610124114e-01,1.320119897689596977e-01,7.469628697170999088e-01,7.343568750931779299e-01,6.737555269781565492e-01,6.605669086693081171e-01,1.107345599251453594e-01,6.701111607763260425e-01,3.850484142984801350e-01,3.240116505199102659e-01,2.097613555844252825e-02,3.468377814469588705e-01,3.931040748811758245e-01
|
| 19 |
-
1.700000000000000000e+01,6.827208399772644043e-02,6.481063655746305274e-01,5.909809842705726624e-02,3.475036295651883766e-01,1.000000000000000021e-03,3.632614016532897949e-02,7.615093491040170193e-04,2.656896598637104034e-02,2.723619155585765839e-02,3.201103582978248596e-02,8.297603619793432195e-01,9.376895544185308295e-02,8.629920386293501444e-01,8.485437188797493313e-01,8.490615288659018045e-01,6.571350246667861938e-02,4.412145353853702545e-04,3.586862981319427490e-02,3.940239176154136658e-02,5.732339620590209961e-02,6.227764555590322715e-01,1.378991925938969076e-01,7.401593588933328416e-01,7.280205074888045358e-01,6.610552541057019837e-01,6.447963468612175619e-01,1.666588143018238877e-01,6.560366075213918124e-01,3.752414580503733443e-01,3.106617599148195907e-01,6.066518750136679072e-02,3.327274566071386497e-01,3.845188215080038718e-01
|
| 20 |
-
1.800000000000000000e+01,6.528741866350173950e-02,6.577194496671199264e-01,5.303359031677246094e-02,3.426573666809243357e-01,1.000000000000000021e-03,3.519031032919883728e-02,8.660148014314472675e-04,2.426595240831375122e-02,2.568129636347293854e-02,3.062949888408184052e-02,8.334083089643693487e-01,9.549110851307869574e-02,8.655011270354117103e-01,8.519881670885902647e-01,8.522890235698877825e-01,6.542401015758514404e-02,5.303072975948452950e-04,3.759600967168807983e-02,3.885564953088760376e-02,5.690687149763107300e-02,6.160673859807292985e-01,1.228819312296807881e-01,7.393793767864327293e-01,7.311372807855845979e-01,6.573841244302103259e-01,6.635511890365026755e-01,1.782893507093815666e-01,6.744458129873126540e-01,3.759633985952385293e-01,2.978070946697530252e-01,5.052960950363397097e-02,3.214569181446781387e-01,3.780565556255954252e-01
|
| 21 |
-
1.900000000000000000e+01,6.402742117643356323e-02,6.663314603670023040e-01,5.399615690112113953e-02,3.502948722834527406e-01,1.000000000000000021e-03,3.565825149416923523e-02,7.032151916064321995e-04,2.377996407449245453e-02,2.467401139438152313e-02,3.069304488599300385e-02,8.364699034314022619e-01,4.329379913005938080e-02,8.699819300887646767e-01,8.539097249667736422e-01,8.561120357656288871e-01,5.949262902140617371e-02,3.949175297748297453e-04,3.383481875061988831e-02,3.783671557903289795e-02,5.248850211501121521e-02,6.211871966230475550e-01,9.049038679806505059e-02,7.436686035531492323e-01,7.310939059559175002e-01,6.640955940383881373e-01,6.752341535107614368e-01,1.555600875127526039e-01,6.839357817704022624e-01,3.592474331377061292e-01,3.135504575542004679e-01,3.731551735251175533e-02,3.361986741430235126e-01,3.632362839247926800e-01
|
| 22 |
-
2.000000000000000000e+01,6.391590833663940430e-02,6.702765494447086025e-01,5.623666942119598389e-02,3.398963422630594255e-01,5.000000000000000104e-04,3.360487893223762512e-02,7.457135943695902824e-04,2.449966594576835632e-02,2.608380652964115143e-02,2.952133491635322571e-02,8.410428875245757885e-01,7.426608414107375988e-02,8.710016255252929218e-01,8.555186001865857648e-01,8.590339066366601273e-01,6.533356010913848877e-02,4.211958730593323708e-04,3.688760101795196533e-02,3.923613578081130981e-02,5.684324353933334351e-02,6.204506197661368017e-01,1.465976489839573849e-01,7.432043748793344395e-01,7.304846104798988771e-01,6.633517185264909966e-01,6.816812835194285825e-01,1.847466358996510127e-01,6.925770051728732390e-01,3.633060944337104248e-01,3.069802425104836696e-01,5.826202973205892727e-02,3.283637256519282288e-01,3.659883887738401564e-01
|
| 23 |
-
2.100000000000000000e+01,6.346534937620162964e-02,6.756393246410333786e-01,5.631577968597412109e-02,3.463531266388009677e-01,5.000000000000000104e-04,3.620840236544609070e-02,6.411169306375086308e-04,2.427953667938709259e-02,2.642281912267208099e-02,2.981889992952346802e-02,8.435377919936687396e-01,6.254226783423402769e-02,8.728355680857047272e-01,8.578676027967189199e-01,8.610370873207828790e-01,6.033084169030189514e-02,3.083940246142446995e-04,3.329208493232727051e-02,3.785052523016929626e-02,5.135870352387428284e-02,6.260232389540949516e-01,1.727440049436962666e-01,7.438323497894350211e-01,7.325367970944491880e-01,6.640035333519742622e-01,6.862486985766825809e-01,1.899596652027064903e-01,6.942660647571701205e-01,3.646062845673220254e-01,3.127599055248252991e-01,5.709049394248971038e-02,3.329020664847050504e-01,3.689723508809851227e-01
|
| 24 |
-
2.200000000000000000e+01,6.295169889926910400e-02,6.780346181846128584e-01,5.676514282822608948e-02,3.432412128917491922e-01,5.000000000000000104e-04,3.258477523922920227e-02,6.418189150281250477e-04,2.285112440586090088e-02,2.355079539120197296e-02,2.924986369907855988e-02,8.461488834607181486e-01,7.821668715462797017e-02,8.737032069582920668e-01,8.588698701288256521e-01,8.648705321234475552e-01,6.416442990303039551e-02,3.368620236869901419e-04,3.700662776827812195e-02,3.842322528362274170e-02,5.764890834689140320e-02,6.239184557144704657e-01,1.329812942224762040e-01,7.445485726717759878e-01,7.299535929335742024e-01,6.655939715414124214e-01,6.738925058911863220e-01,1.866534561351652355e-01,6.809724404980760371e-01,3.550303821584157027e-01,3.087244545220975134e-01,6.268585859060217536e-02,3.303643966729859494e-01,3.610599724255625920e-01
|
| 25 |
-
2.300000000000000000e+01,6.340137869119644165e-02,6.819126628302820681e-01,5.921486020088195801e-02,3.443549204251065698e-01,5.000000000000000104e-04,3.249366953969001770e-02,7.036869646981358528e-04,2.305609732866287231e-02,2.333074621856212616e-02,2.801304310560226440e-02,8.481754688227125527e-01,7.420298712759899884e-02,8.748908580912736488e-01,8.602331467124194608e-01,8.657512753154646967e-01,6.462273001670837402e-02,3.948313533328473568e-04,3.498147428035736084e-02,3.754160553216934204e-02,5.454888567328453064e-02,6.222505577742677429e-01,1.112495009168680687e-01,7.422312879239346683e-01,7.316176496065041057e-01,6.625461393696500112e-01,6.879837139298451421e-01,1.884064663216354629e-01,6.975923975110001063e-01,3.598806180781239372e-01,3.131195083225753462e-01,5.908461815423164676e-02,3.338137094565032936e-01,3.638793502767964649e-01
|
| 26 |
-
2.400000000000000000e+01,6.068088486790657043e-02,6.878450946415769485e-01,4.875090345740318298e-02,3.495979572437574734e-01,5.000000000000000104e-04,3.169814869761466980e-02,6.767227896489202976e-04,2.255837433040142059e-02,2.353114634752273560e-02,2.739009819924831390e-02,8.510547445059198912e-01,5.374846872144546650e-02,8.749255968808360429e-01,8.601015198365780101e-01,8.678228506331330250e-01,6.364411115646362305e-02,3.961643087677657604e-04,3.456138074398040771e-02,3.772752359509468079e-02,5.551146715879440308e-02,6.160173881401913576e-01,8.228247847731386122e-02,7.416109201567839815e-01,7.295856202774859689e-01,6.587965295021460665e-01,7.094098410444467095e-01,1.810738551774272731e-01,7.160526811785619117e-01,3.710549099030631126e-01,3.097857026537553793e-01,5.953687827699413737e-02,3.321428938740144665e-01,3.750779033508894189e-01
|
| 27 |
-
2.500000000000000000e+01,6.031619012355804443e-02,6.903506270255110877e-01,5.405574291944503784e-02,3.447442788855238360e-01,2.500000000000000052e-04,3.316438943147659302e-02,6.500548915937542915e-04,2.216979861259460449e-02,2.290121093392372131e-02,2.793949656188488007e-02,8.542046975071778681e-01,6.361110056719258832e-02,8.765686321023247185e-01,8.621832627270408222e-01,8.711761400314569359e-01,6.540291756391525269e-02,3.573002177290618420e-04,3.609022498130798340e-02,3.782694414258003235e-02,5.669248849153518677e-02,6.204851417326243679e-01,7.425108800889966554e-02,7.429793642403799137e-01,7.313579265650005379e-01,6.604005397865415627e-01,7.091463938627056152e-01,1.755177398158697111e-01,7.160381087432259317e-01,3.739973357197518555e-01,3.136034318675789967e-01,4.697654178146810910e-02,3.331712712970533730e-01,3.770217931719293536e-01
|
| 28 |
-
2.600000000000000000e+01,5.995142832398414612e-02,6.925230946428559964e-01,5.355495586991310120e-02,3.480550134195181666e-01,2.500000000000000052e-04,3.069485351443290710e-02,6.226680707186460495e-04,2.242030017077922821e-02,2.348239347338676453e-02,2.665530703961849213e-02,8.558991322783168210e-01,6.722210060324336489e-02,8.778781881413928456e-01,8.635594894731659643e-01,8.724823635795103671e-01,6.362553685903549194e-02,3.200087521690875292e-04,3.666429966688156128e-02,3.818965703248977661e-02,5.505591258406639099e-02,6.189094838140793975e-01,8.073578155585253713e-02,7.420012235392176025e-01,7.307268868382146287e-01,6.581269510944628420e-01,7.080442795821242363e-01,1.849471162040889072e-01,7.149346957329287822e-01,3.646297491359525855e-01,3.114020355996068301e-01,6.005806856794900644e-02,3.318427496268828158e-01,3.685824861506054595e-01
|
| 29 |
-
2.700000000000000000e+01,6.004891544580459595e-02,6.944908849671526108e-01,5.587754026055335999e-02,3.438676260494581416e-01,2.500000000000000052e-04,3.003809042274951935e-02,6.549322861246764660e-04,2.234407328069210052e-02,2.300366759300231934e-02,2.640154585242271423e-02,8.583373243555245669e-01,7.155713566229512934e-02,8.784953218374323969e-01,8.636326825438849220e-01,8.734295978982050679e-01,6.402294337749481201e-02,3.640253853518515825e-04,3.432694450020790100e-02,3.740804642438888550e-02,5.422083288431167603e-02,6.161971631897648072e-01,8.228573713468846640e-02,7.423702622157385411e-01,7.297789570118994318e-01,6.577781285912499554e-01,7.158898295450024651e-01,1.826371018872875174e-01,7.228272105761712751e-01,3.651851656905684140e-01,3.116621158277260717e-01,5.258706168642443557e-02,3.320296904305072849e-01,3.672945495827650841e-01
|
| 30 |
-
2.800000000000000000e+01,5.985029786825180054e-02,6.933653109572712747e-01,5.290323868393898010e-02,3.477972857564285425e-01,2.500000000000000052e-04,3.010958060622215271e-02,6.784298457205295563e-04,2.205792628228664398e-02,2.261771820485591888e-02,2.600004151463508606e-02,8.590121304461194596e-01,7.584280348114019743e-02,8.782511458347288524e-01,8.643014307332648194e-01,8.752394966512057062e-01,6.669440120458602905e-02,3.805161977652460337e-04,3.770961984992027283e-02,3.835452720522880554e-02,5.673299357295036316e-02,6.193146975274594901e-01,6.284355805472434386e-02,7.423264996160044982e-01,7.310498206422872958e-01,6.590836649000640923e-01,7.148949942827074189e-01,1.761373511014341364e-01,7.235392770178671329e-01,3.689076861609350000e-01,3.142230032554600427e-01,4.580595596497590016e-02,3.336598231082767985e-01,3.704537116271839348e-01
|
| 31 |
-
2.900000000000000000e+01,6.027451157569885254e-02,6.952877317139389834e-01,5.719231069087982178e-02,3.498466440879555717e-01,2.500000000000000052e-04,2.996739745140075684e-02,6.906153284944593906e-04,2.196395210921764374e-02,2.332052588462829590e-02,2.610654383897781372e-02,8.599966075740608229e-01,6.384125756763842086e-02,8.788804356193581357e-01,8.649910539251590702e-01,8.754611535242440290e-01,6.195820868015289307e-02,3.826686297543346882e-04,3.450454771518707275e-02,3.754130378365516663e-02,5.339368060231208801e-02,6.210951529452348741e-01,7.290467448662243943e-02,7.438691092082123646e-01,7.319431625813266340e-01,6.602139442371556255e-01,7.062189224953392408e-01,1.978882261501348216e-01,7.141785287545380223e-01,3.597772425307489974e-01,3.119770970686542300e-01,6.165929141645252326e-02,3.336554498264133195e-01,3.609263518099656842e-01
|
| 32 |
-
3.000000000000000000e+01,5.975107476115226746e-02,6.979072263829914080e-01,5.740753188729286194e-02,3.478860044026280685e-01,1.250000000000000026e-04,2.965832501649856567e-02,6.463322788476943970e-04,2.169117704033851624e-02,2.342507243156433105e-02,2.658935450017452240e-02,8.616706941163232436e-01,8.684818374757541370e-02,8.792070951012203039e-01,8.654324593950811773e-01,8.772109937120813328e-01,6.756551563739776611e-02,3.524999774526804686e-04,3.672973066568374634e-02,4.049425944685935974e-02,5.925842374563217163e-02,6.156634660885346166e-01,7.274489335521647226e-02,7.397050040545084526e-01,7.273484004209838094e-01,6.546979110931987478e-01,7.174872316051424948e-01,2.001236838568846432e-01,7.250422641568589066e-01,3.675869928830769462e-01,3.167808567355248628e-01,5.998355715627732426e-02,3.365922374717836840e-01,3.681417042652462279e-01
|
| 33 |
-
3.100000000000000000e+01,5.989413708448410034e-02,6.996315708299917224e-01,5.842041969299316406e-02,3.440624748909637542e-01,1.250000000000000026e-04,2.961734123528003693e-02,6.601685890927910805e-04,2.166771516203880310e-02,2.242912910878658295e-02,2.569067478179931641e-02,8.634551951189386454e-01,7.373518933681830201e-02,8.794441878022366543e-01,8.659882946775833146e-01,8.779229845445655211e-01,6.907349079847335815e-02,3.751260228455066681e-04,3.653013333678245544e-02,3.888595849275588989e-02,5.839163437485694885e-02,6.150854278556651122e-01,5.802537093317107486e-02,7.416038716429277367e-01,7.289021462955227459e-01,6.544694563937497600e-01,7.150284744404634685e-01,1.958093039968815674e-01,7.224319784724553273e-01,3.575101864052698808e-01,3.111619973530036498e-01,5.537481546693692747e-02,3.316298114154574428e-01,3.588923688312974369e-01
|
| 34 |
-
3.200000000000000000e+01,5.988566949963569641e-02,6.992238174807317019e-01,5.906623601913452148e-02,3.437693362988800683e-01,1.250000000000000026e-04,2.921968512237071991e-02,6.518669542856514454e-04,2.243194915354251862e-02,2.250174246728420258e-02,2.535537071526050568e-02,8.634937917269943641e-01,7.241407914803683898e-02,8.800457878841222437e-01,8.668112739215135809e-01,8.787675865989853508e-01,6.810630857944488525e-02,3.643998352345079184e-04,3.903735056519508362e-02,3.912184387445449829e-02,5.827815830707550049e-02,6.137886526556087796e-01,5.542250585126605456e-02,7.402951479130426282e-01,7.279087452110757361e-01,6.535956841824600572e-01,7.211685484736051199e-01,2.004402482862068791e-01,7.284616385881582667e-01,3.627351777170784164e-01,3.146118776179099852e-01,5.612319413387305278e-02,3.336771553828679071e-01,3.634197948389671917e-01
|
| 35 |
-
3.300000000000000000e+01,5.856835097074508667e-02,7.027648290299935985e-01,5.547048524022102356e-02,3.456412281611375703e-01,1.250000000000000026e-04,2.878449857234954834e-02,6.364382570609450340e-04,2.215472981333732605e-02,2.266022749245166779e-02,2.541560120880603790e-02,8.653584049018316904e-01,7.378762485576129126e-02,8.803915105983948219e-01,8.672222542835896775e-01,8.795875652758127217e-01,6.736468523740768433e-02,3.489613591227680445e-04,3.795114904642105103e-02,3.924616053700447083e-02,5.776481330394744873e-02,6.131427290828318499e-01,6.886720737441570650e-02,7.408723291529872856e-01,7.279738433197148195e-01,6.535120331035212393e-01,7.287091148572059085e-01,1.953318361844819939e-01,7.354631804938983608e-01,3.657085513064761151e-01,3.124106198230188203e-01,5.519759918668131621e-02,3.316457071033748760e-01,3.667481801553459930e-01
|
| 36 |
-
3.400000000000000000e+01,5.956137180328369141e-02,7.015111903412459826e-01,5.840645357966423035e-02,3.472559838709036728e-01,1.250000000000000026e-04,2.853194996714591980e-02,6.652665906585752964e-04,2.143907174468040466e-02,2.226617559790611267e-02,2.497347444295883179e-02,8.664504678222918477e-01,7.810052549555511481e-02,8.808924968244327136e-01,8.675718060196130343e-01,8.806561384852223950e-01,6.732786446809768677e-02,3.809542104136198759e-04,3.673619404435157776e-02,3.906324505805969238e-02,5.760419741272926331e-02,6.123279002002739446e-01,5.472623831975714087e-02,7.406030033460383466e-01,7.286484246560003264e-01,6.535712251404711681e-01,7.182941983251204254e-01,1.935832419876346022e-01,7.257508294253484094e-01,3.560281604373304876e-01,3.137823674085809533e-01,5.510003893718258550e-02,3.338001031978982125e-01,3.562527470882380642e-01
|
| 37 |
-
3.500000000000000000e+01,5.860019847750663757e-02,7.042685941720621123e-01,5.681401118636131287e-02,3.426948570678647887e-01,6.250000000000000130e-05,2.852385118603706360e-02,6.606067763641476631e-04,2.189970575273036957e-02,2.214490994811058044e-02,2.511783875524997711e-02,8.671265816255088188e-01,6.056621990584185045e-02,8.810910783324238382e-01,8.679369290638075940e-01,8.806758001445005313e-01,6.550332158803939819e-02,3.746953443624079227e-04,3.482795879244804382e-02,3.776421770453453064e-02,5.584855005145072937e-02,6.110341124228617637e-01,6.315143251565817628e-02,7.419664169244968299e-01,7.294856629996301356e-01,6.534160308873315781e-01,7.239311916665248647e-01,1.959648329695103386e-01,7.307705664689683189e-01,3.615640951859294683e-01,3.089042672495866393e-01,5.472984329952629984e-02,3.291205437424626901e-01,3.613079785138656463e-01
|
| 38 |
-
3.600000000000000000e+01,5.800328776240348816e-02,7.058639554149160888e-01,5.480755493044853210e-02,3.457778184903980145e-01,6.250000000000000130e-05,2.823890186846256256e-02,6.616351893171668053e-04,2.135722525417804718e-02,2.201527170836925507e-02,2.483780682086944580e-02,8.680317355375335442e-01,7.052221606300879131e-02,8.811202254223819974e-01,8.680425841307216617e-01,8.813524163465211725e-01,6.680154800415039062e-02,3.719100786838680506e-04,3.627144917845726013e-02,3.855656832456588745e-02,5.701784789562225342e-02,6.110060303671205340e-01,6.047594143758559804e-02,7.416879238707400068e-01,7.291988567987940373e-01,6.538546130955125157e-01,7.258998137388515959e-01,1.937728568144377050e-01,7.325817537818388736e-01,3.635695842678671186e-01,3.106436235208112073e-01,5.457905856713080039e-02,3.309423285163805017e-01,3.634895597850825166e-01
|
| 39 |
-
3.700000000000000000e+01,5.821143090724945068e-02,7.060490856412066085e-01,5.624023824930191040e-02,3.451095352632748137e-01,6.250000000000000130e-05,2.808584831655025482e-02,6.540680187754333019e-04,2.130166999995708466e-02,2.194941602647304535e-02,2.463362924754619598e-02,8.682341968461753101e-01,6.500924821837479606e-02,8.817616510640799987e-01,8.685528059703553350e-01,8.816875118489447827e-01,6.636561453342437744e-02,3.663054085336625576e-04,3.565122187137603760e-02,3.786234930157661438e-02,5.651423335075378418e-02,6.104779852515527239e-01,6.361121036485652136e-02,7.411132242911566692e-01,7.284491089149587317e-01,6.527329296195616415e-01,7.267961672123041117e-01,2.003436210825304820e-01,7.334647103090474740e-01,3.609690281656690036e-01,3.109696475770241664e-01,5.698784088164550454e-02,3.308524113313969228e-01,3.598523409197552092e-01
|
| 40 |
-
3.800000000000000000e+01,5.858330428600311279e-02,7.056686596762939967e-01,5.770558491349220276e-02,3.433030890213782382e-01,6.250000000000000130e-05,2.818251028656959534e-02,6.572849233634769917e-04,2.158987522125244141e-02,2.188542298972606659e-02,2.477445080876350403e-02,8.683318048718714488e-01,6.912307268689021900e-02,8.816780630369920324e-01,8.686194430565205016e-01,8.819711959246643307e-01,6.794276088476181030e-02,3.768432652577757835e-04,3.758767247200012207e-02,3.849954158067703247e-02,5.828216671943664551e-02,6.102192081982115157e-01,5.582113165320360532e-02,7.409289530500461352e-01,7.279011496602600939e-01,6.528841149421040768e-01,7.225824821515871577e-01,2.009601693270930967e-01,7.290785916522167787e-01,3.584961730876087826e-01,3.099739849808434977e-01,5.843306431368194137e-02,3.301805421857078593e-01,3.573073511771043265e-01
|
| 41 |
-
3.900000000000000000e+01,5.797545984387397766e-02,7.068249875867739229e-01,5.639252811670303345e-02,3.423814455008474811e-01,6.250000000000000130e-05,2.825962379574775696e-02,6.672614836134016514e-04,2.137997560203075409e-02,2.201181091368198395e-02,2.472093515098094940e-02,8.688877439572811889e-01,7.045663515915893960e-02,8.818967518319136278e-01,8.687278933009655590e-01,8.821898320856362830e-01,6.889443099498748779e-02,3.906847268808633089e-04,3.601168841123580933e-02,3.854733332991600037e-02,5.851984769105911255e-02,6.075133286488839657e-01,4.874245942327867093e-02,7.411498427443522496e-01,7.275979376853332070e-01,6.509654718424938702e-01,7.300784090103903390e-01,2.012783311615001791e-01,7.370016376253487600e-01,3.628737269023813994e-01,3.108207783531933277e-01,5.479218483292316866e-02,3.306985008802184600e-01,3.614559856482376654e-01
|
| 42 |
-
4.000000000000000000e+01,5.780132487416267395e-02,7.076845682885440914e-01,5.582342669367790222e-02,3.447100529096328581e-01,3.125000000000000065e-05,2.790156006813049316e-02,6.595281884074211121e-04,2.118394710123538971e-02,2.181223779916763306e-02,2.448670379817485809e-02,8.693170685028146494e-01,6.852327820707168615e-02,8.821605652506244732e-01,8.689914506207102596e-01,8.825441761734389434e-01,6.704224646091461182e-02,3.740004613064229488e-04,3.573477268218994141e-02,3.825870901346206665e-02,5.731629207730293274e-02,6.093766484870757338e-01,4.931480233138274549e-02,7.411405513262409039e-01,7.274726165098253094e-01,6.522141273082791013e-01,7.315319166110029192e-01,2.013658223387820856e-01,7.382315810834915171e-01,3.636219105701390397e-01,3.116874921760072192e-01,5.699874742054832771e-02,3.315820495724637329e-01,3.624326583095542897e-01
|
| 43 |
-
4.100000000000000000e+01,5.828995257616043091e-02,7.066286048497344430e-01,5.706362426280975342e-02,3.459699185008684452e-01,3.125000000000000065e-05,2.797951176762580872e-02,6.603868096135556698e-04,2.129152789711952209e-02,2.179086208343505859e-02,2.451370097696781158e-02,8.692540251607590029e-01,7.082228896083442304e-02,8.820935766079378570e-01,8.691655499903775395e-01,8.825804557586213184e-01,6.761421263217926025e-02,3.823030274361371994e-04,3.566716611385345459e-02,3.842425718903541565e-02,5.755558609962463379e-02,6.106474249991158398e-01,5.239089712007670430e-02,7.410667829313017929e-01,7.282225875622945210e-01,6.529481295853148959e-01,7.287269169212345910e-01,2.018144693099795106e-01,7.355872323539961455e-01,3.601301513283056144e-01,3.128390640007575607e-01,5.681476265570255257e-02,3.325660584907124684e-01,3.581642467692969234e-01
|
| 44 |
-
4.200000000000000000e+01,5.767818540334701538e-02,7.083593697349319651e-01,5.567393824458122253e-02,3.450525812276888926e-01,3.125000000000000065e-05,2.789531648159027100e-02,6.614017183892428875e-04,2.144028805196285248e-02,2.214754559099674225e-02,2.443265542387962341e-02,8.698934244766330925e-01,6.995147792279096666e-02,8.823073802449288294e-01,8.692241960798464673e-01,8.828946757919553523e-01,6.766057014465332031e-02,3.737104416359215975e-04,3.752689063549041748e-02,3.932658955454826355e-02,5.757582560181617737e-02,6.091655170830136967e-01,5.521279379669469939e-02,7.410967425174687095e-01,7.276310310991033203e-01,6.519055576492363002e-01,7.321361008107423185e-01,2.008564024727396979e-01,7.385725644515125365e-01,3.631703024360398713e-01,3.104354000475741393e-01,5.580264291672666632e-02,3.302157017348057444e-01,3.622790181555390343e-01
|
| 45 |
-
4.300000000000000000e+01,5.759618058800697327e-02,7.085554611848238205e-01,5.555627495050430298e-02,3.450387041283258238e-01,3.125000000000000065e-05,2.773241326212882996e-02,6.654032622464001179e-04,2.112060785293579102e-02,2.173044160008430481e-02,2.436096593737602234e-02,8.700636425271700558e-01,6.696098733771610467e-02,8.824468771804726552e-01,8.695095127901067977e-01,8.830525099645826215e-01,6.669093668460845947e-02,3.802514693234115839e-04,3.605126589536666870e-02,3.825873881578445435e-02,5.703527480363845825e-02,6.093725491128805238e-01,5.349416532629409221e-02,7.415783275786098638e-01,7.283704175611198650e-01,6.525071638422642595e-01,7.303498572629313346e-01,2.002654578875795177e-01,7.371714364026081823e-01,3.619188686608916794e-01,3.099812941028922131e-01,5.565063753053853951e-02,3.299581036331036277e-01,3.605957982918240323e-01
|
| 46 |
-
4.400000000000000000e+01,5.822703987360000610e-02,7.075455458741118919e-01,5.765088647603988647e-02,3.462342105836703765e-01,3.125000000000000065e-05,2.777497842907905579e-02,6.628511473536491394e-04,2.117313444614410400e-02,2.174271829426288605e-02,2.438138052821159363e-02,8.700455257953249033e-01,6.796645807946677387e-02,8.824540086649047543e-01,8.695612044219637182e-01,8.831718854438014299e-01,6.752336025238037109e-02,3.799579862970858812e-04,3.667435050010681152e-02,3.855218365788459778e-02,5.765973031520843506e-02,6.095982785396706349e-01,5.466589094564063694e-02,7.405244689229176780e-01,7.274844330826566452e-01,6.515848106624280156e-01,7.295350220072881475e-01,2.059644071069134108e-01,7.364478398577973817e-01,3.621229527844233020e-01,3.128254244499993897e-01,5.804053561308113868e-02,3.322142502772474915e-01,3.604570526307017686e-01
|
| 47 |
-
4.500000000000000000e+01,5.769359692931175232e-02,7.088952219240789443e-01,5.611725896596908569e-02,3.457854467122016828e-01,1.562500000000000033e-05,2.767258509993553162e-02,6.651677540503442287e-04,2.108610421419143677e-02,2.170417644083499908e-02,2.434734068810939789e-02,8.704508903408876286e-01,6.714432446217231953e-02,8.826457559752397541e-01,8.697000307649652706e-01,8.833458586902458443e-01,6.731349974870681763e-02,3.842133446596562862e-04,3.603804111480712891e-02,3.825381025671958923e-02,5.746502429246902466e-02,6.087264313957002626e-01,5.315064640925604850e-02,7.408080425410550340e-01,7.277592053589144738e-01,6.514728543804696459e-01,7.327779654086312711e-01,2.024004856589385615e-01,7.395825228860876122e-01,3.616162917402771515e-01,3.116594983302576893e-01,5.662300786174526840e-02,3.312077718562869699e-01,3.598959023096113818e-01
|
| 48 |
-
4.600000000000000000e+01,5.745465308427810669e-02,7.093090052191836081e-01,5.534964427351951599e-02,3.458918012321102187e-01,1.562500000000000033e-05,2.762340381741523743e-02,6.656824261881411076e-04,2.107143960893154144e-02,2.172498032450675964e-02,2.431985363364219666e-02,8.705947439892899320e-01,6.757555349179884818e-02,8.827781726566783504e-01,8.697761021354575295e-01,8.835025464756910418e-01,6.718486547470092773e-02,3.804236184805631638e-04,3.601611778140068054e-02,3.843561187386512756e-02,5.741376802325248718e-02,6.077893411843272586e-01,5.001972933418522699e-02,7.405460099978279365e-01,7.271469445069219661e-01,6.504525764632010931e-01,7.360548475941092184e-01,2.017586109909301761e-01,7.427582127472494022e-01,3.626873048749004180e-01,3.125231373892896625e-01,5.544993939067584948e-02,3.317397689311892273e-01,3.605279768709976351e-01
|
| 49 |
-
4.700000000000000000e+01,5.755202844738960266e-02,7.094526245926545682e-01,5.603271350264549255e-02,3.436986831991284408e-01,1.562500000000000033e-05,2.761166542768478394e-02,6.623791414313018322e-04,2.107540890574455261e-02,2.169752866029739380e-02,2.426778897643089294e-02,8.706998947355369944e-01,6.624190698800845600e-02,8.827928573609269414e-01,8.697687837970961011e-01,8.835294958386371578e-01,6.708716601133346558e-02,3.838978882413357496e-04,3.574781119823455811e-02,3.820417821407318115e-02,5.716274306178092957e-02,6.069471741938499143e-01,5.111831078369336728e-02,7.407809113987623428e-01,7.273025784631999002e-01,6.501304704598123152e-01,7.336412752850877128e-01,2.038583258365815054e-01,7.401499917193310463e-01,3.608014601519458076e-01,3.102317670183311615e-01,5.707784324779167223e-02,3.296459424914170988e-01,3.588569573464798212e-01
|
| 50 |
-
4.800000000000000000e+01,5.773221328854560852e-02,7.091742106206258001e-01,5.671997740864753723e-02,3.434390243436385992e-01,1.562500000000000033e-05,2.763002924621105194e-02,6.727011641487479210e-04,2.109275013208389282e-02,2.168871462345123291e-02,2.432486228644847870e-02,8.707913166638922009e-01,6.690043756836742961e-02,8.827819345601858325e-01,8.698173358497038876e-01,8.835564698481661594e-01,6.732903420925140381e-02,3.897958667948842049e-04,3.587563335895538330e-02,3.841435164213180542e-02,5.726577341556549072e-02,6.071362488653184730e-01,5.433829709532146668e-02,7.409303220453330452e-01,7.277695362485639974e-01,6.503840816440107364e-01,7.320757418118554183e-01,2.053662484820551470e-01,7.386397963519978349e-01,3.624746603871766282e-01,3.096988676000239082e-01,5.772596753198275948e-02,3.292777611974421204e-01,3.606933941165191837e-01
|
| 51 |
-
4.900000000000000000e+01,5.744978040456771851e-02,7.093154408998256777e-01,5.561470240354537964e-02,3.444123957010851722e-01,1.562500000000000033e-05,2.764600142836570740e-02,6.590643315576016903e-04,2.105278149247169495e-02,2.165265567600727081e-02,2.437323331832885742e-02,8.708487731923589825e-01,6.608317857522315319e-02,8.829438927414984262e-01,8.700246898896746295e-01,8.837622376542761948e-01,6.782389432191848755e-02,3.755304787773638964e-04,3.631832078099250793e-02,3.838998079299926758e-02,5.780165642499923706e-02,6.078100862332325161e-01,5.935557787600220098e-02,7.407617383560607394e-01,7.274707542544325278e-01,6.510144586348578510e-01,7.331774862231902334e-01,2.021975615192862230e-01,7.396517237089234031e-01,3.613093074463315513e-01,3.106812137270248964e-01,5.521973921801121704e-02,3.298824469686564287e-01,3.589976688376887992e-01
|
| 52 |
-
5.000000000000000000e+01,5.744143947958946228e-02,7.096113973815068032e-01,5.578177794814109802e-02,3.440315274742876128e-01,7.812500000000000163e-06,2.758510597050189972e-02,6.609005504287779331e-04,2.105022780597209930e-02,2.167608402669429779e-02,2.424302324652671814e-02,8.709811809435680230e-01,6.677995588459902099e-02,8.829151597688368325e-01,8.699930227440740849e-01,8.838281586068192919e-01,6.783218681812286377e-02,3.785888548009097576e-04,3.638352081179618835e-02,3.856224194169044495e-02,5.775172635912895203e-02,6.077613343840500004e-01,5.516893543981719189e-02,7.409062808528776856e-01,7.277482362042895225e-01,6.509364047043794121e-01,7.337173362346266492e-01,2.039715474619706592e-01,7.402187135041840005e-01,3.617603782530501300e-01,3.102615198805290797e-01,5.667052811720077465e-02,3.296842553492516092e-01,3.594805250401529872e-01
|
| 53 |
-
5.100000000000000000e+01,5.746058002114295959e-02,7.096573657180469397e-01,5.589713528752326965e-02,3.443466027509430316e-01,7.812500000000000163e-06,2.756033092737197876e-02,6.627957336604595184e-04,2.108188718557357788e-02,2.164329215884208679e-02,2.425745688378810883e-02,8.710167152754775266e-01,6.569096697135820562e-02,8.829446448338443831e-01,8.700608138395168334e-01,8.837941146224719269e-01,6.732848286628723145e-02,3.802987630479037762e-04,3.573525324463844299e-02,3.827473148703575134e-02,5.732126533985137939e-02,6.076442981306482416e-01,5.461907718325954147e-02,7.409988985411296580e-01,7.278288417045507552e-01,6.508177928270638679e-01,7.343908303498809520e-01,2.035377593945188468e-01,7.409945037241421062e-01,3.624381373643129622e-01,3.106487420758040074e-01,5.555166539029344347e-02,3.299577067962531918e-01,3.602340987901400671e-01
|
| 54 |
-
5.200000000000000000e+01,5.738569423556327820e-02,7.099512803252361337e-01,5.574252083897590637e-02,3.441396789367732190e-01,7.812500000000000163e-06,2.754599787294864655e-02,6.607761024497449398e-04,2.102622576057910919e-02,2.166540734469890594e-02,2.420506067574024200e-02,8.711537022378423867e-01,6.543294074551236905e-02,8.830061080640903004e-01,8.700840736724950730e-01,8.839310295663087569e-01,6.759815663099288940e-02,3.784334985539317131e-04,3.612096607685089111e-02,3.848814219236373901e-02,5.745160952210426331e-02,6.075964732096398313e-01,5.593347406072308320e-02,7.409179484254615478e-01,7.276072011916628890e-01,6.509216219801829961e-01,7.347097594234488493e-01,2.026618912124049376e-01,7.412273077491132733e-01,3.618820826802758295e-01,3.101322328973821763e-01,5.558650150301541748e-02,3.295844654713537825e-01,3.596749711973725172e-01
|
| 55 |
-
5.300000000000000000e+01,5.726695433259010315e-02,7.099092009597289810e-01,5.506875365972518921e-02,3.448645051657324156e-01,7.812500000000000163e-06,2.753267809748649597e-02,6.609478732571005821e-04,2.107972465455532074e-02,2.165041863918304443e-02,2.422757446765899658e-02,8.711347038217133187e-01,6.577574063057256559e-02,8.830393593638441452e-01,8.701435287650705064e-01,8.838324106851745965e-01,6.722164154052734375e-02,3.794580115936696529e-04,3.561870753765106201e-02,3.819055855274200439e-02,5.719408392906188965e-02,6.070218216437966996e-01,5.198784401657766813e-02,7.408011083228955851e-01,7.275787722839508476e-01,6.501541018088694557e-01,7.370305291565372174e-01,2.022317206845467563e-01,7.435495241228671226e-01,3.627283076848499266e-01,3.114589174387702997e-01,5.477136767835608794e-02,3.306253956319393228e-01,3.602222168156140047e-01
|
| 56 |
-
5.400000000000000000e+01,5.749739706516265869e-02,7.099768000574888660e-01,5.629877001047134399e-02,3.435642449469926141e-01,7.812500000000000163e-06,2.749819681048393250e-02,6.618950865231454372e-04,2.104782499372959137e-02,2.163715288043022156e-02,2.419226616621017456e-02,8.712632372035862272e-01,6.457463255110587608e-02,8.830277765559811920e-01,8.700969804745376512e-01,8.839593674779178123e-01,6.745953857898712158e-02,3.796762612182646990e-04,3.572872281074523926e-02,3.828851878643035889e-02,5.735072493553161621e-02,6.070244758575673583e-01,5.501328047543069949e-02,7.407822708789688626e-01,7.273625368430606253e-01,6.504314565645372692e-01,7.338703054532845771e-01,2.037055377244740284e-01,7.404006892535789364e-01,3.608267107595114487e-01,3.097512729440159429e-01,5.595773492613229094e-02,3.293947202124622997e-01,3.586948945963912561e-01
|
| 57 |
-
5.500000000000000000e+01,5.744592472910881042e-02,7.099502447958720985e-01,5.605857446789741516e-02,3.440822106348935816e-01,3.906250000000000081e-06,2.750833705067634583e-02,6.614544545300304890e-04,2.101761102676391602e-02,2.164744585752487183e-02,2.418000809848308563e-02,8.712630698303130972e-01,6.575795292532818359e-02,8.830568487743437611e-01,8.701431496428014833e-01,8.840183839907495011e-01,6.754182279109954834e-02,3.790056507568806410e-04,3.599338233470916748e-02,3.844262659549713135e-02,5.744356289505958557e-02,6.071553680617974846e-01,5.538666302768226191e-02,7.405784465696630958e-01,7.272834916682324735e-01,6.502788928308976812e-01,7.344872764498233675e-01,2.039611062079114967e-01,7.410120574928570347e-01,3.622459033902148406e-01,3.102944620565963318e-01,5.621457463940952859e-02,3.297463352021089977e-01,3.599476293087465750e-01
|
| 58 |
-
5.600000000000000000e+01,5.746303126215934753e-02,7.099635005156946788e-01,5.614554136991500854e-02,3.439336098482917992e-01,3.906250000000000081e-06,2.751494385302066803e-02,6.622456712648272514e-04,2.102038636803627014e-02,2.164217457175254822e-02,2.418814785778522491e-02,8.712946808144153010e-01,6.554859784255236133e-02,8.830379431413794000e-01,8.701335894882702426e-01,8.840337577906892674e-01,6.765138357877731323e-02,3.801561833824962378e-04,3.606564179062843323e-02,3.847213834524154663e-02,5.756577849388122559e-02,6.070577713647951068e-01,5.566291200979119752e-02,7.405575932262146166e-01,7.272849178545600646e-01,6.502626324498993471e-01,7.340726998346212007e-01,2.033669902555134135e-01,7.406457469733201959e-01,3.616563648407477016e-01,3.100256766548040166e-01,5.593236919252329853e-02,3.295938089942700433e-01,3.593854559770280344e-01
|
| 59 |
-
5.700000000000000000e+01,5.748935043811798096e-02,7.099813197060538261e-01,5.631250515580177307e-02,3.437170825525101003e-01,3.906250000000000081e-06,2.751132473349571228e-02,6.638185004703700542e-04,2.102210000157356262e-02,2.163031511008739471e-02,2.418697997927665710e-02,8.713340250157509681e-01,6.594080996969724218e-02,8.830353768040084539e-01,8.701472339562361658e-01,8.840857498130265668e-01,6.779824197292327881e-02,3.823727893177419901e-04,3.607602044939994812e-02,3.841697052121162415e-02,5.771909281611442566e-02,6.070268507093916632e-01,5.523025315558896531e-02,7.405728137837412905e-01,7.272655890373751486e-01,6.502818643337041626e-01,7.338888727480074037e-01,2.034808955781119699e-01,7.404993973829826492e-01,3.612731567732452298e-01,3.100130420248641827e-01,5.618285865226124026e-02,3.295905327230008175e-01,3.589679277044617312e-01
|
| 60 |
-
5.800000000000000000e+01,5.745500326156616211e-02,7.100520055173937806e-01,5.618080496788024902e-02,3.439299963749520295e-01,3.906250000000000081e-06,2.748979255557060242e-02,6.636264733970165253e-04,2.101479843258857727e-02,2.162936888635158539e-02,2.416725456714630127e-02,8.714037647121626318e-01,6.638927770915006854e-02,8.830848436809125568e-01,8.701791992659164698e-01,8.841333273198243026e-01,6.774181127548217773e-02,3.816561074927449226e-04,3.600073605775833130e-02,3.844484314322471619e-02,5.765548348426818848e-02,6.069957855584394713e-01,5.484584515529485060e-02,7.405033353968931698e-01,7.272297042634101594e-01,6.501928909772668463e-01,7.344980635267722713e-01,2.035563248389018476e-01,7.410796593347169781e-01,3.620049125807568990e-01,3.102097996031332738e-01,5.611079887527249677e-02,3.297294828354042084e-01,3.595955216620245198e-01
|
| 61 |
-
5.900000000000000000e+01,5.758251622319221497e-02,7.099037073395471076e-01,5.662655457854270935e-02,3.439635165985814869e-01,3.906250000000000081e-06,2.749112620949745178e-02,6.636538892053067684e-04,2.101693116128444672e-02,2.163022197782993317e-02,2.416982501745223999e-02,8.714278858185701138e-01,6.632164256115566370e-02,8.830627070952667967e-01,8.701511792836306158e-01,8.841536428611110887e-01,6.779840588569641113e-02,3.819456615019589663e-04,3.601596131920814514e-02,3.840891271829605103e-02,5.769450217485427856e-02,6.071504341831778229e-01,5.515850220565964718e-02,7.403165391151330654e-01,7.270850253579197453e-01,6.502341220190568372e-01,7.335112982184727182e-01,2.046558771622793427e-01,7.401405102076468179e-01,3.614544687204442885e-01,3.105029894514958477e-01,5.667124680036145917e-02,3.300118707392660222e-01,3.589813260740831735e-01
|
| 62 |
-
6.000000000000000000e+01,5.750261992216110229e-02,7.100298328197944819e-01,5.636451765894889832e-02,3.438838045476164673e-01,1.953125000000000041e-06,2.748706191778182983e-02,6.626528920605778694e-04,2.101116254925727844e-02,2.163318917155265808e-02,2.416505478322505951e-02,8.714440609389956238e-01,6.643742194557779313e-02,8.830893986407003515e-01,8.701764642334249844e-01,8.841600853386872849e-01,6.775550544261932373e-02,3.810750204138457775e-04,3.611311316490173340e-02,3.846086561679840088e-02,5.765195190906524658e-02,6.070095771636930815e-01,5.501938157445027816e-02,7.403823023680670135e-01,7.271268339545726711e-01,6.501884122178752667e-01,7.338650128192699684e-01,2.041193825277973217e-01,7.404693941472164642e-01,3.614324956331061989e-01,3.102934198398368260e-01,5.633098881812795278e-02,3.297916667773376220e-01,3.590016348394912127e-01
|
| 63 |
-
6.100000000000000000e+01,5.747239291667938232e-02,7.100768114204669690e-01,5.626931041479110718e-02,3.439365447182763935e-01,1.953125000000000041e-06,2.747968956828117371e-02,6.619442719966173172e-04,2.100781723856925964e-02,2.162843756377696991e-02,2.416320890188217163e-02,8.714569874907842628e-01,6.659394519421914238e-02,8.831089530212642424e-01,8.701930727936474375e-01,8.841699136549296956e-01,6.778241693973541260e-02,3.806125023402273655e-04,3.609474375844001770e-02,3.844692185521125793e-02,5.768891796469688416e-02,6.069438787520539114e-01,5.535387902445150499e-02,7.403574306710092312e-01,7.270986131176008227e-01,6.501294715026701976e-01,7.342165450768297630e-01,2.039093186302871619e-01,7.408261259316137881e-01,3.616949636917873856e-01,3.103177510311216358e-01,5.614140965732253297e-02,3.297947445288641477e-01,3.592100906461591636e-01
|
| 64 |
-
6.200000000000000000e+01,5.746459960937500000e-02,7.100954651034809828e-01,5.624506995081901550e-02,3.439711506156754584e-01,1.953125000000000041e-06,2.747949771583080292e-02,6.624918896704912186e-04,2.100725285708904266e-02,2.163183130323886871e-02,2.416116371750831604e-02,8.714739594260987321e-01,6.672604597846470975e-02,8.831149008602924289e-01,8.702029745773181002e-01,8.841927019913112806e-01,6.782055646181106567e-02,3.808027831837534904e-04,3.615681082010269165e-02,3.848693892359733582e-02,5.771644786000251770e-02,6.069152541184574812e-01,5.572132985734255806e-02,7.403267779546696126e-01,7.270852823131191967e-01,6.500916139521180082e-01,7.342327062846002450e-01,2.042021921463162415e-01,7.408494357672560371e-01,3.614715809750129738e-01,3.102934626020606435e-01,5.644253990570220758e-02,3.297711858555714692e-01,3.590089602660738732e-01
|
| 65 |
-
6.300000000000000000e+01,5.744896084070205688e-02,7.101646034684171438e-01,5.623002350330352783e-02,3.438030499367885628e-01,1.953125000000000041e-06,2.747701667249202728e-02,6.622786750085651875e-04,2.100756950676441193e-02,2.162049338221549988e-02,2.416110970079898834e-02,8.714915366816392561e-01,6.672908403116362130e-02,8.831199580932652671e-01,8.702139938330905045e-01,8.841768239195370027e-01,6.778392195701599121e-02,3.816551761701703072e-04,3.604271262884140015e-02,3.843371570110321045e-02,5.768740922212600708e-02,6.067463913864807878e-01,5.468604846667494968e-02,7.403845391950052424e-01,7.271417171701070048e-01,6.500002166688594318e-01,7.346104551545374894e-01,2.041861597972399467e-01,7.412228067091590766e-01,3.616012191394945008e-01,3.102571322292139167e-01,5.626679479673205725e-02,3.297149303789014274e-01,3.591025463489887493e-01
|
| 66 |
-
6.400000000000000000e+01,5.737597122788429260e-02,7.102790380416147409e-01,5.594910308718681335e-02,3.440291630858124949e-01,1.953125000000000041e-06,2.745947800576686859e-02,6.628466653637588024e-04,2.100154012441635132e-02,2.161486633121967316e-02,2.414684183895587921e-02,8.715167208854792680e-01,6.663791033460179924e-02,8.831506117808006762e-01,8.702436333903951216e-01,8.842038666303311256e-01,6.763724237680435181e-02,3.813193761743605137e-04,3.602033108472824097e-02,3.839222714304924011e-02,5.756296962499618530e-02,6.066215904891890665e-01,5.462397042410631343e-02,7.403788276418387104e-01,7.271107596709052157e-01,6.499326042803451609e-01,7.350360101939639179e-01,2.037992325926081538e-01,7.416203556735097013e-01,3.614885406456637695e-01,3.104073318576248686e-01,5.628447374123765612e-02,3.298390288829440853e-01,3.589506423431298443e-01
|
| 67 |
-
6.500000000000000000e+01,5.742330849170684814e-02,7.102498495237604681e-01,5.615479126572608948e-02,3.438248638467049645e-01,9.765625000000000203e-07,2.746735513210296631e-02,6.624046945944428444e-04,2.100297436118125916e-02,2.161747589707374573e-02,2.415156923234462738e-02,8.715226440095005245e-01,6.662532191158315742e-02,8.831408454158657939e-01,8.702381230362054021e-01,8.842093549178463574e-01,6.771884113550186157e-02,3.814140218310058117e-04,3.604901954531669617e-02,3.842851519584655762e-02,5.762577056884765625e-02,6.066099091433172497e-01,5.480663671696575645e-02,7.403786493495110310e-01,7.271063989182965370e-01,6.499111084779034542e-01,7.347419887624648815e-01,2.040652269559434795e-01,7.413429098350969859e-01,3.615473024798027124e-01,3.101995896802399177e-01,5.639015446311485685e-02,3.296759007834815236e-01,3.590577368393563784e-01
|
| 68 |
-
6.600000000000000000e+01,5.743084847927093506e-02,7.102458390551315004e-01,5.619189888238906860e-02,3.437223281006636655e-01,9.765625000000000203e-07,2.746964804828166962e-02,6.623897934332489967e-04,2.100237645208835602e-02,2.161710336804389954e-02,2.415246516466140747e-02,8.715239695041208101e-01,6.680110964960517261e-02,8.831428916515681182e-01,8.702413473815729938e-01,8.842140637364832578e-01,6.778001040220260620e-02,3.814703086391091347e-04,3.608370944857597351e-02,3.843955323100090027e-02,5.767344683408737183e-02,6.065907863892668894e-01,5.480893479841097982e-02,7.403868191174977076e-01,7.271154265714514509e-01,6.499082967719681525e-01,7.345655244079198898e-01,2.041366339695062093e-01,7.411724055749353557e-01,3.615937466484192009e-01,3.100744881473868619e-01,5.643906446673701421e-02,3.295617429962663381e-01,3.591223140172120076e-01
|
| 69 |
-
6.700000000000000000e+01,5.742966383695602417e-02,7.102276910859203207e-01,5.616797134280204773e-02,3.438750019743646580e-01,9.765625000000000203e-07,2.746456302702426910e-02,6.620165659114718437e-04,2.100214920938014984e-02,2.161811105906963348e-02,2.414805628359317780e-02,8.715300259666258764e-01,6.661088202982859419e-02,8.831511863294048137e-01,8.702485664725656545e-01,8.842212554124229129e-01,6.773312389850616455e-02,3.811963542830199003e-04,3.603926673531532288e-02,3.844437748193740845e-02,5.762740597128868103e-02,6.066108230143272273e-01,5.494236575551991741e-02,7.403686133376564671e-01,7.271292363145139825e-01,6.499158466610417406e-01,7.345826176530317886e-01,2.041374430034333942e-01,7.411916060699529352e-01,3.615420531365333146e-01,3.101976754017236049e-01,5.635779141127397751e-02,3.296675423609912170e-01,3.590533129951267166e-01
|
| 70 |
-
6.800000000000000000e+01,5.744453147053718567e-02,7.101912353749495477e-01,5.621329694986343384e-02,3.439541669591849593e-01,9.765625000000000203e-07,2.746905013918876648e-02,6.624023662880063057e-04,2.100083045661449432e-02,2.161679789423942566e-02,2.414926886558532715e-02,8.715216710079438656e-01,6.686462762640484059e-02,8.831522530561179973e-01,8.702580736671434725e-01,8.842256963318463336e-01,6.779894232749938965e-02,3.813615185208618641e-04,3.608727455139160156e-02,3.845654800534248352e-02,5.767928063869476318e-02,6.066489740043111700e-01,5.514803987322123430e-02,7.403531417310654783e-01,7.271265485903766201e-01,6.499131376244264846e-01,7.345535053173876117e-01,2.041591845041441367e-01,7.411710204180917971e-01,3.615164223696791246e-01,3.102713116455638187e-01,5.637762968686108045e-02,3.297313494457086436e-01,3.590069624682669658e-01
|
| 71 |
-
6.900000000000000000e+01,5.741333588957786560e-02,7.102344719011565166e-01,5.610705539584159851e-02,3.438906163069733735e-01,9.765625000000000203e-07,2.746745012700557709e-02,6.620911299251019955e-04,2.099974639713764191e-02,2.161715179681777954e-02,2.414671331644058228e-02,8.715295877193216523e-01,6.683181535985072141e-02,8.831582617509405875e-01,8.702657265821421850e-01,8.842268641732424772e-01,6.775505840778350830e-02,3.812537470366805792e-04,3.609113395214080811e-02,3.846439346671104431e-02,5.765100196003913879e-02,6.065827827516634407e-01,5.499353293042178598e-02,7.403678755139304624e-01,7.271498666099009967e-01,6.498810361927637169e-01,7.346256213232769117e-01,2.040405239921606606e-01,7.412257716723893441e-01,3.614186606072066765e-01,3.101862189384682611e-01,5.631335244027101811e-02,3.296347005457743173e-01,3.589207643789073532e-01
|
| 72 |
-
7.000000000000000000e+01,5.741957575082778931e-02,7.102338759210974350e-01,5.613540112972259521e-02,3.438565519280359362e-01,4.882812500000000102e-07,2.746713533997535706e-02,6.622620276175439358e-04,2.100080437958240509e-02,2.161522209644317627e-02,2.414687536656856537e-02,8.715329194263845558e-01,6.680114083732613395e-02,8.831555895355329699e-01,8.702661176641476315e-01,8.842277415884156611e-01,6.776099652051925659e-02,3.813746734522283077e-04,3.607115894556045532e-02,3.845753893256187439e-02,5.765837803483009338e-02,6.065597806446760831e-01,5.491732931327965306e-02,7.403657343645365652e-01,7.271482386203614867e-01,6.498592251183369362e-01,7.346088142577709146e-01,2.040645957742745487e-01,7.412128134982870487e-01,3.613981219948474433e-01,3.101717848451308046e-01,5.628795248480193691e-02,3.296199044585383930e-01,3.588923755329502807e-01
|
| 73 |
-
7.100000000000000000e+01,5.743572488427162170e-02,7.102025293807017192e-01,5.619068816304206848e-02,3.438917688213767865e-01,4.882812500000000102e-07,2.746425755321979523e-02,6.623473600484430790e-04,2.099950797855854034e-02,2.161705493927001953e-02,2.414534427225589752e-02,8.715370933640044226e-01,6.680158793679501217e-02,8.831599715635095604e-01,8.702678064043369854e-01,8.842362622394025484e-01,6.778512895107269287e-02,3.813570365309715271e-04,3.609488159418106079e-02,3.846958279609680176e-02,5.767019465565681458e-02,6.066114257530637044e-01,5.517179878912516905e-02,7.403524103149407010e-01,7.271451906747401495e-01,6.498958894936933683e-01,7.344465778515022469e-01,2.040861550498316579e-01,7.410578372863244612e-01,3.613194215880365379e-01,3.102081560806959071e-01,5.626919462228825025e-02,3.296579241971322460e-01,3.588155066651922964e-01
|
| 74 |
-
7.200000000000000000e+01,5.742456763982772827e-02,7.102330874794131610e-01,5.615560337901115417e-02,3.438496383175498883e-01,4.882812500000000102e-07,2.746473066508769989e-02,6.623619119636714458e-04,2.099896781146526337e-02,2.161580696702003479e-02,2.414513006806373596e-02,8.715425118069819455e-01,6.680827397049549088e-02,8.831623669097378171e-01,8.702705559340625507e-01,8.842386380628706188e-01,6.778574734926223755e-02,3.813081129919737577e-04,3.610007464885711670e-02,3.846602514386177063e-02,5.767326802015304565e-02,6.065865652272027786e-01,5.515785854182109205e-02,7.403676238964812528e-01,7.271459364112643486e-01,6.498823077501467704e-01,7.345185652658234865e-01,2.040652932886340698e-01,7.411264224684612767e-01,3.614207807064758193e-01,3.101370057278158288e-01,5.628216519104396742e-02,3.295882582440780029e-01,3.589288847564161000e-01
|
| 75 |
-
7.300000000000000000e+01,5.744622275233268738e-02,7.102085440379439785e-01,5.624263361096382141e-02,3.438078231277241215e-01,4.882812500000000102e-07,2.746675536036491394e-02,6.622779183089733124e-04,2.099933102726936340e-02,2.161627635359764099e-02,2.414718270301818848e-02,8.715486005796245772e-01,6.681960083939397776e-02,8.831601373665650678e-01,8.702650369683572196e-01,8.842437072602662429e-01,6.783352047204971313e-02,3.813345101661980152e-04,3.611586242914199829e-02,3.846872225403785706e-02,5.771346017718315125e-02,6.066047430300115506e-01,5.530605698219152183e-02,7.403510049412492799e-01,7.271327409855227186e-01,6.498895821470151990e-01,7.343251359196801831e-01,2.042279057627584826e-01,7.409417212156231836e-01,3.613473336454958718e-01,3.101037521015050369e-01,5.636500249825535103e-02,3.295673234357141546e-01,3.588698875484411244e-01
|
| 76 |
-
7.400000000000000000e+01,5.745136737823486328e-02,7.101988652753689069e-01,5.626487359404563904e-02,3.437961959620443042e-01,4.882812500000000102e-07,2.746806852519512177e-02,6.624182569794356823e-04,2.100029215216636658e-02,2.161525748670101166e-02,2.414771541953086853e-02,8.715464962571461971e-01,6.673250778543272921e-02,8.831571289386703771e-01,8.702652558859645948e-01,8.842419306220477004e-01,6.784765422344207764e-02,3.814064257312566042e-04,3.609406203031539917e-02,3.846426680684089661e-02,5.771929025650024414e-02,6.065959654872017381e-01,5.517422321250689543e-02,7.403405030580366697e-01,7.271262946793806137e-01,6.498627731350653525e-01,7.343356287452170728e-01,2.042494631860750920e-01,7.409576015036694052e-01,3.613675009667304261e-01,3.101217650133613057e-01,5.629325226478007482e-02,3.295818792319797352e-01,3.588877992376497961e-01
|
| 77 |
-
7.500000000000000000e+01,5.744588002562522888e-02,7.102078285940360836e-01,5.624829977750778198e-02,3.437983046230574380e-01,2.441406250000000051e-07,2.746831253170967102e-02,6.624551606364548206e-04,2.099987678229808807e-02,2.161517180502414703e-02,2.414772287011146545e-02,8.715481559739700623e-01,6.672828455264281922e-02,8.831588453122196647e-01,8.702672689314630006e-01,8.842446283828105935e-01,6.786394119262695312e-02,3.813432704191654921e-04,3.610038384795188904e-02,3.846692293882369995e-02,5.772996321320533752e-02,6.065904907838698401e-01,5.520335012537037206e-02,7.403407249192688333e-01,7.271236230294804148e-01,6.498558244496220881e-01,7.343600900759987837e-01,2.042524123136491288e-01,7.409805332907912767e-01,3.614077350502166719e-01,3.101093339909245516e-01,5.630572561695176836e-02,3.295716581338060669e-01,3.589284385806786326e-01
|
| 78 |
-
7.600000000000000000e+01,5.743892490863800049e-02,7.102216325694971077e-01,5.622515082359313965e-02,3.437954216054376344e-01,2.441406250000000051e-07,2.746747434139251709e-02,6.626070244237780571e-04,2.100008539855480194e-02,2.161485888063907623e-02,2.414709888398647308e-02,8.715492001269232736e-01,6.670314663601538407e-02,8.831602269790401749e-01,8.702697340896236033e-01,8.842413607944816789e-01,6.783617287874221802e-02,3.813692019321024418e-04,3.608340770006179810e-02,3.846577182412147522e-02,5.770989507436752319e-02,6.065669487708768015e-01,5.507845098411880136e-02,7.403505736808677629e-01,7.271360778216400256e-01,6.498418034119605169e-01,7.344514811222639938e-01,2.042009962502181475e-01,7.410714216144047572e-01,3.614115257143830640e-01,3.101078123435152545e-01,5.626472263132843016e-02,3.295700648258561016e-01,3.589282743186844038e-01
|
| 79 |
-
7.700000000000000000e+01,5.743740871548652649e-02,7.102277645436181341e-01,5.621990188956260681e-02,3.437912222676542395e-01,2.441406250000000051e-07,2.746638841927051544e-02,6.626519025303423405e-04,2.099964395165443420e-02,2.161437086760997772e-02,2.414614520967006683e-02,8.715510605716333403e-01,6.668044542525251861e-02,8.831618085627179759e-01,8.702718690627626597e-01,8.842433024221280080e-01,6.783072650432586670e-02,3.813685907516628504e-04,3.608386218547821045e-02,3.846294432878494263e-02,5.770359560847282410e-02,6.065518996553731501e-01,5.512295738221845848e-02,7.403490945075877905e-01,7.271339920355295305e-01,6.498351631318796118e-01,7.344367821116366546e-01,2.042106800712302217e-01,7.410545454497475815e-01,3.613939652687481185e-01,3.100906819358428823e-01,5.629561459838820781e-02,3.295534443168421923e-01,3.589142486480900729e-01
|
| 80 |
-
7.800000000000000000e+01,5.742450430989265442e-02,7.102489533366833641e-01,5.617469176650047302e-02,3.437790764511438057e-01,2.441406250000000051e-07,2.746506966650485992e-02,6.624925299547612667e-04,2.100067958235740662e-02,2.161271870136260986e-02,2.414591051638126373e-02,8.715520732867861886e-01,6.664341673793017229e-02,8.831628856262063731e-01,8.702750003923352962e-01,8.842404304654249980e-01,6.780597567558288574e-02,3.813672810792922974e-04,3.604932129383087158e-02,3.845183923840522766e-02,5.768522620201110840e-02,6.065137423796700400e-01,5.495576474417412927e-02,7.403605034412954478e-01,7.271430670287354348e-01,6.498163814275317307e-01,7.345507906434630696e-01,2.041300058224560510e-01,7.411677319636353900e-01,3.614287691137362257e-01,3.100878057155768697e-01,5.622565621818903514e-02,3.295461832279625303e-01,3.589406211929877522e-01
|
| 81 |
-
7.900000000000000000e+01,5.741957202553749084e-02,7.102535173267034985e-01,5.615540221333503723e-02,3.438023976347557298e-01,2.441406250000000051e-07,2.746395580470561981e-02,6.624498637393116951e-04,2.100028656423091888e-02,2.161260321736335754e-02,2.414489351212978363e-02,8.715540603538532993e-01,6.665346977670373596e-02,8.831650306271450201e-01,8.702775371404991578e-01,8.842427695310736135e-01,6.780055165290832520e-02,3.813297662418335676e-04,3.604963421821594238e-02,3.845350816845893860e-02,5.768076702952384949e-02,6.065057029300869873e-01,5.494590809392143477e-02,7.403565822759506920e-01,7.271388317076141750e-01,6.498053591684698205e-01,7.345912936291569828e-01,2.041239682220660767e-01,7.412080624280539265e-01,3.614513459967580999e-01,3.101168658392585153e-01,5.621218204044639566e-02,3.295692281711170568e-01,3.589595529608528568e-01
|
| 82 |
-
8.000000000000000000e+01,5.742327868938446045e-02,7.102504219218946924e-01,5.617029592394828796e-02,3.437985082666789594e-01,1.220703125000000025e-07,2.746420912444591522e-02,6.624478264711797237e-04,2.100002393126487732e-02,2.161327749490737915e-02,2.414488419890403748e-02,8.715553793996473342e-01,6.668622610354618674e-02,8.831649061447780502e-01,8.702772064294299614e-01,8.842449672757642931e-01,6.780930608510971069e-02,3.813274670392274857e-04,3.605801984667778015e-02,3.845958784222602844e-02,5.768844112753868103e-02,6.065086159650444619e-01,5.495675849027614052e-02,7.403526602871517426e-01,7.271364830789397438e-01,6.498056284249777992e-01,7.345706335879287341e-01,2.041451938521659237e-01,7.411880511018625883e-01,3.614587231489704289e-01,3.101153737674690603e-01,5.622062298497036009e-02,3.295674922735567502e-01,3.589650043976567728e-01
|
| 83 |
-
8.100000000000000000e+01,5.742004513740539551e-02,7.102552233824797057e-01,5.615895241498947144e-02,3.438009832114546360e-01,1.220703125000000025e-07,2.746364288032054901e-02,6.624411325901746750e-04,2.099973335862159729e-02,2.161274664103984833e-02,2.414433844387531281e-02,8.715567418555276724e-01,6.667365819663925719e-02,8.831662958821379084e-01,8.702785747588579479e-01,8.842461137663830684e-01,6.780733168125152588e-02,3.813440271187573671e-04,3.605687990784645081e-02,3.845658153295516968e-02,5.768571048974990845e-02,6.065045349047678558e-01,5.493589447177506246e-02,7.403531421841038629e-01,7.271358950685630207e-01,6.498024614359654283e-01,7.345784323300510454e-01,2.041305808100165875e-01,7.411949400847568370e-01,3.614325347432615354e-01,3.101178326569315469e-01,5.622187147412986696e-02,3.295680858940626123e-01,3.589360490815998728e-01
|
| 84 |
-
8.200000000000000000e+01,5.742454528808593750e-02,7.102536211330112703e-01,5.617781728506088257e-02,3.437949748221078572e-01,1.220703125000000025e-07,2.746343612670898438e-02,6.624619127251207829e-04,2.099967002868652344e-02,2.161291614174842834e-02,2.414404414594173431e-02,8.715582469488831752e-01,6.667628739681512318e-02,8.831660680878352654e-01,8.702780360038786522e-01,8.842482640540055838e-01,6.781229376792907715e-02,3.813602670561522245e-04,3.605883195996284485e-02,3.845781832933425903e-02,5.768891796469688416e-02,6.065076667294944102e-01,5.495254475954052670e-02,7.403493774394225291e-01,7.271307410576480779e-01,6.498010496227788479e-01,7.345430041073197636e-01,2.041551692820713915e-01,7.411600160967464213e-01,3.614112487133256946e-01,3.101169881487820246e-01,5.624037693540302751e-02,3.295691186051292743e-01,3.589150673760931887e-01
|
| 85 |
-
8.300000000000000000e+01,5.741937085986137390e-02,7.102646833694312711e-01,5.616059526801109314e-02,3.437875116461047154e-01,1.220703125000000025e-07,2.746262215077877045e-02,6.624469533562660217e-04,2.099954150617122650e-02,2.161208540201187134e-02,2.414362318813800812e-02,8.715596380042260893e-01,6.665438315321364771e-02,8.831675816643849153e-01,8.702796044123495278e-01,8.842474870367829087e-01,6.780055910348892212e-02,3.813409712165594101e-04,3.605354949831962585e-02,3.845212981104850769e-02,5.768060684204101562e-02,6.064956414959886688e-01,5.493389466612151606e-02,7.403580775376392697e-01,7.271369333260118140e-01,6.497981526826565046e-01,7.345749001675088152e-01,2.041367756464162186e-01,7.411899318080075183e-01,3.614002741940437469e-01,3.101005109603698906e-01,5.623601058817087606e-02,3.295541032431022477e-01,3.589059645250776143e-01
|
| 86 |
-
8.400000000000000000e+01,5.742282792925834656e-02,7.102602077522777169e-01,5.617344006896018982e-02,3.437879448014057870e-01,1.220703125000000025e-07,2.746327593922615051e-02,6.624107481911778450e-04,2.099902927875518799e-02,2.161283418536186218e-02,2.414352260529994965e-02,8.715599722999042287e-01,6.668134927302638015e-02,8.831673466751756019e-01,8.702795956575404279e-01,8.842507511258999031e-01,6.781244277954101562e-02,3.813021467067301273e-04,3.606931120157241821e-02,3.845940902829170227e-02,5.769089236855506897e-02,6.065012723608875778e-01,5.499186535075765991e-02,7.403508380939906042e-01,7.271287527484887603e-01,6.497969210242429128e-01,7.345521057569089907e-01,2.041456915753170898e-01,7.411681356864782133e-01,3.614087352742270109e-01,3.101010336203619544e-01,5.624676560807435888e-02,3.295551977613382921e-01,3.589165827975167034e-01
|
| 87 |
-
8.500000000000000000e+01,5.742383003234863281e-02,7.102593869730534637e-01,5.617755278944969177e-02,3.437851166294035865e-01,6.103515625000000127e-08,2.746325172483921051e-02,6.624160450883209705e-04,2.099900133907794952e-02,2.161286771297454834e-02,2.414354868233203888e-02,8.715608062245510101e-01,6.668276563026212522e-02,8.831674927718244916e-01,8.702796529290203198e-01,8.842511316899783758e-01,6.781384348869323730e-02,3.813048533629626036e-04,3.606985881924629211e-02,3.845983371138572693e-02,5.769224092364311218e-02,6.065017000850139173e-01,5.500202172672521289e-02,7.403500074081836857e-01,7.271286242946808365e-01,6.497979597943042140e-01,7.345461560816259894e-01,2.041580107852390413e-01,7.411625852311527485e-01,3.614117454931655149e-01,3.100988984322044506e-01,5.625210006108104926e-02,3.295532419031205196e-01,3.589201405935464884e-01
|
| 88 |
-
8.600000000000000000e+01,5.742476135492324829e-02,7.102577166814763032e-01,5.618143454194068909e-02,3.437860673037613224e-01,6.103515625000000127e-08,2.746317721903324127e-02,6.624088273383677006e-04,2.099902741611003876e-02,2.161268331110477448e-02,2.414346486330032349e-02,8.715609745634425032e-01,6.668429221677837915e-02,8.831675716440425816e-01,8.702801914155418039e-01,8.842517808547284419e-01,6.781657040119171143e-02,3.813170769717544317e-04,3.606923297047615051e-02,3.845962882041931152e-02,5.769429728388786316e-02,6.065015667970146129e-01,5.501792494191445199e-02,7.403491660686467579e-01,7.271283221611252179e-01,6.497967066819320126e-01,7.345436121881204761e-01,2.041618529719605168e-01,7.411608221796346374e-01,3.614174993926673740e-01,3.100996006103592384e-01,5.625190901768166440e-02,3.295539167726508345e-01,3.589251923969645763e-01
|
| 89 |
-
8.700000000000000000e+01,5.742425099015235901e-02,7.102597402265301563e-01,5.618052184581756592e-02,3.437816513065331536e-01,6.103515625000000127e-08,2.746314555406570435e-02,6.624137749895453453e-04,2.099907957017421722e-02,2.161258272826671600e-02,2.414346486330032349e-02,8.715616197665645437e-01,6.668009172373261240e-02,8.831678667479145872e-01,8.702805211557190779e-01,8.842518682405621222e-01,6.781435012817382812e-02,3.813206567429006100e-04,3.606607764959335327e-02,3.845885768532752991e-02,5.769266933202743530e-02,6.065005489542699690e-01,5.500491741334506690e-02,7.403505796290379415e-01,7.271300146719492652e-01,6.497975534486524207e-01,7.345501588966292239e-01,2.041616479228390568e-01,7.411670201525287771e-01,3.614134888071269258e-01,3.100970349862665065e-01,5.625026578452416159e-02,3.295516220044625300e-01,3.589199517714117271e-01
|
| 90 |
-
8.800000000000000000e+01,5.742482095956802368e-02,7.102610341983937037e-01,5.618404969573020935e-02,3.437716071276898377e-01,6.103515625000000127e-08,2.746328897774219513e-02,6.624396773986518383e-04,2.099916152656078339e-02,2.161259576678276062e-02,2.414366602897644043e-02,8.715621148233181348e-01,6.668368526771051297e-02,8.831676130337948738e-01,8.702803624611001876e-01,8.842520066339106810e-01,6.781849265098571777e-02,3.813256043940782547e-04,3.606628254055976868e-02,3.845921531319618225e-02,5.769608914852142334e-02,6.064983040540150583e-01,5.501151616932171279e-02,7.403516565604084665e-01,7.271295040258479725e-01,6.497967397218882279e-01,7.345460186766975541e-01,2.041725718048502392e-01,7.411631172426720315e-01,3.614178419427707678e-01,3.100866926065189433e-01,5.625602693862640641e-02,3.295421033584158832e-01,3.589255757506658595e-01
|
| 91 |
-
8.900000000000000000e+01,5.742535740137100220e-02,7.102602700873654751e-01,5.618613958358764648e-02,3.437749806570415956e-01,6.103515625000000127e-08,2.746353484690189362e-02,6.624433444812893867e-04,2.099914476275444031e-02,2.161250449717044830e-02,2.414372749626636505e-02,8.715623620935524229e-01,6.667737659294606378e-02,8.831675821657406500e-01,8.702805849956876116e-01,8.842521383030135240e-01,6.781842559576034546e-02,3.813384973909705877e-04,3.606744483113288879e-02,3.845893591642379761e-02,5.769626796245574951e-02,6.065021882422694244e-01,5.501647321737686974e-02,7.403518650629383746e-01,7.271322890442554199e-01,6.497994543215112051e-01,7.345403284212455031e-01,2.041695695030512625e-01,7.411579896989215488e-01,3.614340780278993415e-01,3.100864449011108692e-01,5.625480940280294662e-02,3.295422640160611261e-01,3.589414591791941778e-01
|
| 92 |
-
9.000000000000000000e+01,5.742720514535903931e-02,7.102574562376572365e-01,5.619290471076965332e-02,3.437764460693469859e-01,3.051757812500000064e-08,2.746373228728771210e-02,6.624161615036427975e-04,2.099910192191600800e-02,2.161275967955589294e-02,2.414384670555591583e-02,8.715623132075172030e-01,6.668807637986462478e-02,8.831674153196664712e-01,8.702805237292446927e-01,8.842525469967530416e-01,6.782269477844238281e-02,3.813300572801381350e-04,3.607061877846717834e-02,3.846121206879615784e-02,5.769957974553108215e-02,6.065060219820423981e-01,5.503423987277752255e-02,7.403500209198955462e-01,7.271312575679095280e-01,6.498009542043783338e-01,7.345292694679929069e-01,2.041793018001358817e-01,7.411475698598882778e-01,3.614327498634438141e-01,3.100892356773357061e-01,5.625932627504737216e-02,3.295452059159525438e-01,3.589403043226604417e-01
|
| 93 |
-
9.100000000000000000e+01,5.742630735039710999e-02,7.102588910144457257e-01,5.618974566459655762e-02,3.437782352952818976e-01,3.051757812500000064e-08,2.746357209980487823e-02,6.623930530622601509e-04,2.099904604256153107e-02,2.161267399787902832e-02,2.414374239742755890e-02,8.715624175541218932e-01,6.668484338112633247e-02,8.831677245896590867e-01,8.702808713766587712e-01,8.842525653260127072e-01,6.782145798206329346e-02,3.813205112237483263e-04,3.607034683227539062e-02,3.846084699034690857e-02,5.769851058721542358e-02,6.065037941992372783e-01,5.502904275149276409e-02,7.403492967169220673e-01,7.271310026517361358e-01,6.497990451241880683e-01,7.345395487245528487e-01,2.041752937338662255e-01,7.411575976380556652e-01,3.614393885949500618e-01,3.100922308855101894e-01,5.625429539251478039e-02,3.295469858190657741e-01,3.589457473718164482e-01
|
| 94 |
-
9.200000000000000000e+01,5.742597207427024841e-02,7.102592754383779683e-01,5.618848279118537903e-02,3.437810267037063605e-01,3.051757812500000064e-08,2.746345847845077515e-02,6.623783847317099571e-04,2.099903672933578491e-02,2.161254547536373138e-02,2.414366416633129120e-02,8.715624646103242723e-01,6.668456966930118301e-02,8.831679259620964784e-01,8.702811981563622901e-01,8.842526408152533435e-01,6.782101094722747803e-02,3.813080256804823875e-04,3.606924414634704590e-02,3.846025466918945312e-02,5.769795551896095276e-02,6.065019717847847103e-01,5.502628692895356749e-02,7.403497489148200827e-01,7.271307707089539329e-01,6.497979019243056431e-01,7.345463889467864771e-01,2.041730743630215394e-01,7.411644707540356869e-01,3.614368745602211663e-01,3.100943990664665750e-01,5.625078781013140988e-02,3.295488505874840657e-01,3.589439006174725555e-01
|
| 95 |
-
9.300000000000000000e+01,5.742697045207023621e-02,7.102574923029804088e-01,5.619199946522712708e-02,3.437837338260280595e-01,3.051757812500000064e-08,2.746360935270786285e-02,6.624151137657463551e-04,2.099906280636787415e-02,2.161253057420253754e-02,2.414369955658912659e-02,8.715624958332319761e-01,6.668857907904449100e-02,8.831677699435963591e-01,8.702811425971618275e-01,8.842530038548164217e-01,6.782369315624237061e-02,3.813255170825868845e-04,3.607001155614852905e-02,3.846047818660736084e-02,5.770011991262435913e-02,6.065051917421470096e-01,5.502141280420194680e-02,7.403477283781759732e-01,7.271301766202132866e-01,6.497982940777305982e-01,7.345412190348534764e-01,2.041792869080393258e-01,7.411600235732921371e-01,3.614369759222857970e-01,3.100994729535130334e-01,5.625291258045726772e-02,3.295536287179154922e-01,3.589429192136726621e-01
|
| 96 |
-
9.400000000000000000e+01,5.742746219038963318e-02,7.102563154624900177e-01,5.619365721940994263e-02,3.437862046159803620e-01,3.051757812500000064e-08,2.746367827057838440e-02,6.624052766710519791e-04,2.099899388849735260e-02,2.161255665123462677e-02,2.414371073246002197e-02,8.715623925121640525e-01,6.669259301730738609e-02,8.831678098162296653e-01,8.702813134274873796e-01,8.842534607436839389e-01,6.782675534486770630e-02,3.813199873548001051e-04,3.607209771871566772e-02,3.846112638711929321e-02,5.770229920744895935e-02,6.065070089296641376e-01,5.503022576882060646e-02,7.403466347282283699e-01,7.271294141216424478e-01,6.497990071087068609e-01,7.345372821665852037e-01,2.041820663731753194e-01,7.411561034109079849e-01,3.614360982622374374e-01,3.101021480963429555e-01,5.625362064777472693e-02,3.295559569789580645e-01,3.589423428538700556e-01
|
| 97 |
-
9.500000000000000000e+01,5.742703750729560852e-02,7.102569368484444867e-01,5.619209259748458862e-02,3.437863875497129129e-01,1.525878906250000032e-08,2.746364288032054901e-02,6.623973604291677475e-04,2.099897712469100952e-02,2.161252126097679138e-02,2.414368651807308197e-02,8.715624576018268233e-01,6.669376552850886375e-02,8.831679109726302546e-01,8.702814666682135991e-01,8.842534967828880044e-01,6.782664358615875244e-02,3.813143412116914988e-04,3.607213124632835388e-02,3.846103325486183167e-02,5.770227313041687012e-02,6.065063963792194368e-01,5.502879930785751356e-02,7.403467771952495502e-01,7.271294226491348267e-01,6.497986774818259592e-01,7.345407597214546058e-01,2.041818029266593004e-01,7.411594022836662798e-01,3.614371247467591530e-01,3.101022643236751031e-01,5.625301273860582735e-02,3.295556554624058387e-01,3.589432466792510934e-01
|
| 98 |
-
9.600000000000000000e+01,5.742678791284561157e-02,7.102575520972506107e-01,5.619135499000549316e-02,3.437856280610490645e-01,1.525878906250000032e-08,2.746361866593360901e-02,6.624010857194662094e-04,2.099897339940071106e-02,2.161247096955776215e-02,2.414365112781524658e-02,8.715625138140986605e-01,6.669376107974200885e-02,8.831680326898636579e-01,8.702816169756135700e-01,8.842534472271667001e-01,6.782566010951995850e-02,3.813155053649097681e-04,3.607146814465522766e-02,3.846075013279914856e-02,5.770148709416389465e-02,6.065047930719577041e-01,5.502466650980317869e-02,7.403471140747229784e-01,7.271298053896527724e-01,6.497974098810830323e-01,7.345431741808966519e-01,2.041813274201347839e-01,7.411617321492262045e-01,3.614393388577165078e-01,3.101010506631156072e-01,5.625284969015263009e-02,3.295544392626322816e-01,3.589454730277931160e-01
|
| 99 |
-
9.700000000000000000e+01,5.742698535323143005e-02,7.102573362458866058e-01,5.619213730096817017e-02,3.437870707514761870e-01,1.525878906250000032e-08,2.746362797915935516e-02,6.623939843848347664e-04,2.099893055856227875e-02,2.161259949207305908e-02,2.414362877607345581e-02,8.715625979873579121e-01,6.669771919788446135e-02,8.831680724676759242e-01,8.702816760955561781e-01,8.842538026328752299e-01,6.782711297273635864e-02,3.813042712863534689e-04,3.607279434800148010e-02,3.846183791756629944e-02,5.770270153880119324e-02,6.065066086491071040e-01,5.503128305077718829e-02,7.403467665509644302e-01,7.271292686309098752e-01,6.497982853711653517e-01,7.345432199076017410e-01,2.041833803809668946e-01,7.411617869837417993e-01,3.614402063993495395e-01,3.101021552493902211e-01,5.625366139488278960e-02,3.295553474636763736e-01,3.589460570228465430e-01
|
| 100 |
-
9.800000000000000000e+01,5.742775276303291321e-02,7.102563257942547947e-01,5.619505420327186584e-02,3.437868536375007777e-01,1.525878906250000032e-08,2.746368013322353363e-02,6.624005036428570747e-04,2.099893055856227875e-02,2.161265723407268524e-02,2.414363436400890350e-02,8.715626216531162651e-01,6.669872117073184781e-02,8.831679648722633447e-01,8.702815725062246210e-01,8.842540431483839614e-01,6.782810389995574951e-02,3.813096263911575079e-04,3.607365116477012634e-02,3.846231102943420410e-02,5.770342797040939331e-02,6.065077478649176790e-01,5.503514446043885483e-02,7.403463647436743233e-01,7.271291605538280356e-01,6.497988977719499903e-01,7.345372687393231237e-01,2.041856672287047370e-01,7.411561993314802477e-01,3.614395982609147628e-01,3.101020264633129742e-01,5.625488237129971925e-02,3.295555820748442000e-01,3.589459024230869932e-01
|
| 101 |
-
9.900000000000000000e+01,5.742808803915977478e-02,7.102558540605663495e-01,5.619632825255393982e-02,3.437867991928307276e-01,1.525878906250000032e-08,2.746366523206233978e-02,6.624017842113971710e-04,2.099892869591712952e-02,2.161265537142753601e-02,2.414361946284770966e-02,8.715626273732197671e-01,6.669814984436445160e-02,8.831679477860365779e-01,8.702816305084354331e-01,8.842541294929460172e-01,6.782823801040649414e-02,3.813100629486143589e-04,3.607377037405967712e-02,3.846235945820808411e-02,5.770352855324745178e-02,6.065081304513683103e-01,5.503931070687841792e-02,7.403462395819607744e-01,7.271290619693382418e-01,6.497991553380486618e-01,7.345340126649899659e-01,2.041871967844338664e-01,7.411530658095542012e-01,3.614379600582254271e-01,3.101018571036791571e-01,5.625574519011593277e-02,3.295554763053956671e-01,3.589443249033947292e-01
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
streaming_gopt_best/test_metrics.json
DELETED
|
@@ -1,37 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"phone_test_mse": 0.04919730871915817,
|
| 3 |
-
"phone_test_pcc": 0.3975705055993251,
|
| 4 |
-
"utt_test_mse": [
|
| 5 |
-
0.051985688507556915,
|
| 6 |
-
0.0016903950599953532,
|
| 7 |
-
0.03446277603507042,
|
| 8 |
-
0.03239584341645241,
|
| 9 |
-
0.04794545844197273
|
| 10 |
-
],
|
| 11 |
-
"utt_test_pcc": [
|
| 12 |
-
0.651909193610124,
|
| 13 |
-
0.012690043750859805,
|
| 14 |
-
0.7249977587357453,
|
| 15 |
-
0.7332794084754206,
|
| 16 |
-
0.681940037784353
|
| 17 |
-
],
|
| 18 |
-
"word_test_mse": [
|
| 19 |
-
0.06279397755861282,
|
| 20 |
-
0.0037991644348949194,
|
| 21 |
-
0.04641091078519821,
|
| 22 |
-
0.14399507641792297
|
| 23 |
-
],
|
| 24 |
-
"word_test_pcc": [
|
| 25 |
-
0.4047142491023989,
|
| 26 |
-
-0.0039119825110344765,
|
| 27 |
-
0.4122583381095728,
|
| 28 |
-
0.41746734262039764
|
| 29 |
-
],
|
| 30 |
-
"word_score_names": [
|
| 31 |
-
"accuracy",
|
| 32 |
-
"stress",
|
| 33 |
-
"total",
|
| 34 |
-
"asr_accuracy"
|
| 35 |
-
],
|
| 36 |
-
"best_epoch": 11
|
| 37 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
streampa/__init__.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .pipeline import StreamPAPipeline, StreamPASession
|
| 2 |
+
|
| 3 |
+
__all__ = ['StreamPAPipeline', 'StreamPASession']
|
| 4 |
+
__version__ = '1.0.0'
|
streampa/charsiu_model.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# MIT-licensed Charsiu frame classifier, extracted without numerical changes.
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn as nn
|
| 4 |
+
from transformers import Wav2Vec2ForCTC
|
| 5 |
+
from transformers.modeling_outputs import CausalLMOutput
|
| 6 |
+
class Wav2Vec2ForFrameClassification(Wav2Vec2ForCTC):
|
| 7 |
+
|
| 8 |
+
def forward(
|
| 9 |
+
self,
|
| 10 |
+
input_values,
|
| 11 |
+
attention_mask=None,
|
| 12 |
+
output_attentions=None,
|
| 13 |
+
output_hidden_states=None,
|
| 14 |
+
return_dict=None,
|
| 15 |
+
labels=None,
|
| 16 |
+
):
|
| 17 |
+
|
| 18 |
+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 19 |
+
|
| 20 |
+
outputs = self.wav2vec2(
|
| 21 |
+
input_values,
|
| 22 |
+
attention_mask=attention_mask,
|
| 23 |
+
output_attentions=output_attentions,
|
| 24 |
+
output_hidden_states=output_hidden_states,
|
| 25 |
+
return_dict=return_dict,
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
hidden_states = outputs[0]
|
| 29 |
+
hidden_states = self.dropout(hidden_states)
|
| 30 |
+
|
| 31 |
+
logits = self.lm_head(hidden_states)
|
| 32 |
+
|
| 33 |
+
loss = None
|
| 34 |
+
if labels is not None:
|
| 35 |
+
|
| 36 |
+
if labels.max() >= self.config.vocab_size:
|
| 37 |
+
raise ValueError(f"Label values must be <= vocab_size: {self.config.vocab_size}")
|
| 38 |
+
|
| 39 |
+
# retrieve loss input_lengths from attention_mask
|
| 40 |
+
attention_mask = (
|
| 41 |
+
attention_mask if attention_mask is not None else torch.ones_like(input_values, dtype=torch.long)
|
| 42 |
+
)
|
| 43 |
+
# input_lengths = self._get_feat_extract_output_lengths(attention_mask.sum(-1)).to(torch.long)
|
| 44 |
+
|
| 45 |
+
loss = nn.functional.cross_entropy(logits.view(-1,logits.size(2)), labels.flatten(), reduction="mean")
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
if not return_dict:
|
| 50 |
+
output = (logits,) + outputs[2:]
|
| 51 |
+
return ((loss,) + output) if loss is not None else output
|
| 52 |
+
|
| 53 |
+
return CausalLMOutput(
|
| 54 |
+
loss=loss, logits=logits, hidden_states=outputs.hidden_states, attentions=outputs.attentions
|
| 55 |
+
)
|
streampa/frontend.py
ADDED
|
@@ -0,0 +1,1556 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Frozen inference function extraction. See source provenance and licenses.
|
| 2 |
+
import gc
|
| 3 |
+
import math
|
| 4 |
+
import re
|
| 5 |
+
from collections import Counter
|
| 6 |
+
from itertools import groupby
|
| 7 |
+
import numpy as np
|
| 8 |
+
import librosa
|
| 9 |
+
import torch
|
| 10 |
+
from transformers import AutoProcessor, AutoModelForSpeechSeq2Seq
|
| 11 |
+
EPS = 1e-8
|
| 12 |
+
EPS_TOKEN = '<eps>'
|
| 13 |
+
|
| 14 |
+
def normalize_phone(phone):
|
| 15 |
+
phone = phone.upper().strip()
|
| 16 |
+
phone = phone.replace('[', '').replace(']', '')
|
| 17 |
+
phone = re.sub(r'[_\d].*', '', phone)
|
| 18 |
+
return phone
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def normalize_word(word):
|
| 22 |
+
word = word.upper().strip()
|
| 23 |
+
word = word.replace('[', '').replace(']', '')
|
| 24 |
+
word = re.sub(r"[^A-Z']", '', word)
|
| 25 |
+
return word
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def monotonic_align(neg_log_probs, phone_ids):
|
| 29 |
+
frame_num = neg_log_probs.shape[0]
|
| 30 |
+
token_num = len(phone_ids)
|
| 31 |
+
if frame_num < token_num:
|
| 32 |
+
raise ValueError(f'Not enough frames ({frame_num}) to align {token_num} phones.')
|
| 33 |
+
|
| 34 |
+
dp = np.full((frame_num, token_num), np.inf, dtype=np.float32)
|
| 35 |
+
back = np.zeros((frame_num, token_num), dtype=np.int8)
|
| 36 |
+
dp[0, 0] = neg_log_probs[0, phone_ids[0]]
|
| 37 |
+
|
| 38 |
+
for t in range(1, frame_num):
|
| 39 |
+
max_token = min(t, token_num - 1)
|
| 40 |
+
for tok in range(max_token + 1):
|
| 41 |
+
stay_cost = dp[t - 1, tok]
|
| 42 |
+
move_cost = dp[t - 1, tok - 1] if tok > 0 else np.inf
|
| 43 |
+
if move_cost < stay_cost:
|
| 44 |
+
dp[t, tok] = move_cost + neg_log_probs[t, phone_ids[tok]]
|
| 45 |
+
back[t, tok] = 1
|
| 46 |
+
else:
|
| 47 |
+
dp[t, tok] = stay_cost + neg_log_probs[t, phone_ids[tok]]
|
| 48 |
+
|
| 49 |
+
path = np.zeros(frame_num, dtype=np.int32)
|
| 50 |
+
tok = token_num - 1
|
| 51 |
+
for t in range(frame_num - 1, -1, -1):
|
| 52 |
+
path[t] = tok
|
| 53 |
+
if t > 0 and back[t, tok] == 1:
|
| 54 |
+
tok -= 1
|
| 55 |
+
return path
|
| 56 |
+
|
| 57 |
+
def select_visible_frames(probs, keep_mask, audio_end, frame_step):
|
| 58 |
+
frame_limit = max(int(math.ceil(audio_end / max(frame_step, EPS))), 1)
|
| 59 |
+
frame_mask = np.zeros(len(probs), dtype=bool)
|
| 60 |
+
frame_mask[: min(frame_limit, len(probs))] = True
|
| 61 |
+
visible_mask = keep_mask & frame_mask
|
| 62 |
+
return np.flatnonzero(visible_mask), probs[visible_mask]
|
| 63 |
+
|
| 64 |
+
def softmax_1d(values):
|
| 65 |
+
arr = np.asarray(values, dtype=np.float64)
|
| 66 |
+
if arr.size == 0:
|
| 67 |
+
return arr.astype(np.float32)
|
| 68 |
+
pos_inf = np.isposinf(arr)
|
| 69 |
+
if np.any(pos_inf):
|
| 70 |
+
out = np.zeros_like(arr, dtype=np.float64)
|
| 71 |
+
out[pos_inf] = 1.0 / float(np.sum(pos_inf))
|
| 72 |
+
return out.astype(np.float32)
|
| 73 |
+
finite = np.isfinite(arr)
|
| 74 |
+
if not np.any(finite):
|
| 75 |
+
return np.full(arr.shape, 1.0 / float(arr.size), dtype=np.float32)
|
| 76 |
+
min_finite = np.min(arr[finite])
|
| 77 |
+
arr = np.where(finite, arr, min_finite - 50.0)
|
| 78 |
+
arr = arr - np.max(arr)
|
| 79 |
+
exp_arr = np.exp(arr)
|
| 80 |
+
return (exp_arr / np.clip(exp_arr.sum(), EPS, None)).astype(np.float32)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def entropy_np(probs):
|
| 84 |
+
probs = np.asarray(probs, dtype=np.float64)
|
| 85 |
+
probs = probs[probs > 0]
|
| 86 |
+
if probs.size == 0:
|
| 87 |
+
return 0.0
|
| 88 |
+
return float(-np.sum(probs * np.log(np.clip(probs, EPS, None))))
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def top_margin(probs):
|
| 92 |
+
probs = np.asarray(probs, dtype=np.float32)
|
| 93 |
+
if probs.size == 0:
|
| 94 |
+
return 0.0, 0.0
|
| 95 |
+
top = np.sort(probs)[::-1]
|
| 96 |
+
top1 = float(top[0])
|
| 97 |
+
top2 = float(top[1]) if top.size > 1 else 0.0
|
| 98 |
+
return top1, float(top1 - top2)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def js_divergence(p, q):
|
| 102 |
+
p = np.asarray(p, dtype=np.float64)
|
| 103 |
+
q = np.asarray(q, dtype=np.float64)
|
| 104 |
+
p = p / np.clip(p.sum(), EPS, None)
|
| 105 |
+
q = q / np.clip(q.sum(), EPS, None)
|
| 106 |
+
m = 0.5 * (p + q)
|
| 107 |
+
kl_pm = np.sum(p * (np.log(np.clip(p, EPS, None)) - np.log(np.clip(m, EPS, None))))
|
| 108 |
+
kl_qm = np.sum(q * (np.log(np.clip(q, EPS, None)) - np.log(np.clip(m, EPS, None))))
|
| 109 |
+
return float(0.5 * (kl_pm + kl_qm))
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def safe_json(value):
|
| 113 |
+
if isinstance(value, dict):
|
| 114 |
+
return {str(key): safe_json(val) for key, val in value.items()}
|
| 115 |
+
if isinstance(value, (list, tuple)):
|
| 116 |
+
return [safe_json(item) for item in value]
|
| 117 |
+
if isinstance(value, np.ndarray):
|
| 118 |
+
return safe_json(value.tolist())
|
| 119 |
+
if isinstance(value, (np.floating, np.integer)):
|
| 120 |
+
return value.item()
|
| 121 |
+
return value
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def softmax_np_matrix(values):
|
| 125 |
+
arr = np.asarray(values, dtype=np.float64)
|
| 126 |
+
if arr.size == 0:
|
| 127 |
+
return arr.astype(np.float32)
|
| 128 |
+
arr = arr - np.max(arr, axis=-1, keepdims=True)
|
| 129 |
+
exp_arr = np.exp(arr)
|
| 130 |
+
return (exp_arr / np.clip(np.sum(exp_arr, axis=-1, keepdims=True), EPS, None)).astype(np.float32)
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def audio_array_logits(audio, processor, model, sample_rate, device):
|
| 134 |
+
audio = np.asarray(audio, dtype=np.float32)
|
| 135 |
+
if hasattr(processor, 'audio_preprocess'):
|
| 136 |
+
inputs = processor.audio_preprocess(audio, sr=sample_rate)
|
| 137 |
+
inputs = torch.tensor(inputs, dtype=torch.float32).unsqueeze(0).to(device)
|
| 138 |
+
model_inputs = {'input_values': inputs}
|
| 139 |
+
else:
|
| 140 |
+
model_inputs = processor(audio, sampling_rate=sample_rate, return_tensors='pt')
|
| 141 |
+
model_inputs = {key: value.to(device) for key, value in model_inputs.items()}
|
| 142 |
+
with torch.no_grad():
|
| 143 |
+
logits = model(**model_inputs).logits[0].detach().cpu().numpy()
|
| 144 |
+
return softmax_np_matrix(logits), float(len(audio) / sample_rate)
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def non_overlapping_occurrences(tokens, pattern):
|
| 148 |
+
positions = []
|
| 149 |
+
pattern_size = len(pattern)
|
| 150 |
+
cursor = 0
|
| 151 |
+
while cursor <= len(tokens) - pattern_size:
|
| 152 |
+
if tokens[cursor : cursor + pattern_size] == pattern:
|
| 153 |
+
positions.append(cursor)
|
| 154 |
+
cursor += pattern_size
|
| 155 |
+
else:
|
| 156 |
+
cursor += 1
|
| 157 |
+
return positions
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def find_repeated_ngram(
|
| 161 |
+
words,
|
| 162 |
+
min_repeats,
|
| 163 |
+
max_ngram_size=12,
|
| 164 |
+
strict=False,
|
| 165 |
+
min_coverage=0.6,
|
| 166 |
+
dominant_token_ratio=0.5,
|
| 167 |
+
):
|
| 168 |
+
if min_repeats <= 0:
|
| 169 |
+
return None
|
| 170 |
+
tokens = [str(word['text']) for word in words]
|
| 171 |
+
if not tokens:
|
| 172 |
+
return None
|
| 173 |
+
|
| 174 |
+
for ngram_size in range(1, min(max_ngram_size, len(tokens)) + 1):
|
| 175 |
+
span = ngram_size * min_repeats
|
| 176 |
+
for start in range(0, len(tokens) - span + 1):
|
| 177 |
+
pattern = tokens[start : start + ngram_size]
|
| 178 |
+
repeats = 1
|
| 179 |
+
cursor = start + ngram_size
|
| 180 |
+
while tokens[cursor : cursor + ngram_size] == pattern:
|
| 181 |
+
repeats += 1
|
| 182 |
+
cursor += ngram_size
|
| 183 |
+
if repeats >= min_repeats:
|
| 184 |
+
return {
|
| 185 |
+
'start': int(start),
|
| 186 |
+
'ngram_size': int(ngram_size),
|
| 187 |
+
'repeats': int(repeats),
|
| 188 |
+
'pattern': pattern,
|
| 189 |
+
'detection': 'contiguous_cycle',
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
if not strict:
|
| 193 |
+
return None
|
| 194 |
+
|
| 195 |
+
token_counts = Counter(tokens)
|
| 196 |
+
dominant_token, dominant_count = token_counts.most_common(1)[0]
|
| 197 |
+
token_ratio = float(dominant_count) / float(len(tokens))
|
| 198 |
+
if dominant_count >= max(min_repeats * 2, 8) and token_ratio >= dominant_token_ratio:
|
| 199 |
+
return {
|
| 200 |
+
'start': None,
|
| 201 |
+
'ngram_size': 1,
|
| 202 |
+
'repeats': int(dominant_count),
|
| 203 |
+
'pattern': [dominant_token],
|
| 204 |
+
'coverage': token_ratio,
|
| 205 |
+
'detection': 'dominant_token',
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
max_size = min(max_ngram_size, len(tokens) // max(min_repeats, 1))
|
| 209 |
+
for ngram_size in range(max_size, 1, -1):
|
| 210 |
+
candidates = Counter(
|
| 211 |
+
tuple(tokens[start : start + ngram_size])
|
| 212 |
+
for start in range(0, len(tokens) - ngram_size + 1)
|
| 213 |
+
)
|
| 214 |
+
for pattern, raw_count in candidates.most_common():
|
| 215 |
+
if raw_count < min_repeats:
|
| 216 |
+
break
|
| 217 |
+
positions = non_overlapping_occurrences(tokens, list(pattern))
|
| 218 |
+
if len(positions) < min_repeats:
|
| 219 |
+
continue
|
| 220 |
+
coverage = float(len(positions) * ngram_size) / float(len(tokens))
|
| 221 |
+
if coverage >= min_coverage:
|
| 222 |
+
return {
|
| 223 |
+
'start': int(positions[0]),
|
| 224 |
+
'ngram_size': int(ngram_size),
|
| 225 |
+
'repeats': int(len(positions)),
|
| 226 |
+
'pattern': list(pattern),
|
| 227 |
+
'coverage': coverage,
|
| 228 |
+
'detection': 'high_coverage_periodicity',
|
| 229 |
+
}
|
| 230 |
+
return None
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
class PhoneMapper:
|
| 234 |
+
def __init__(self, lexicon, phn_dict):
|
| 235 |
+
self.lexicon = lexicon
|
| 236 |
+
self.phn_dict = phn_dict
|
| 237 |
+
self.cache = {}
|
| 238 |
+
self.fallback_phone = 'AH' if 'AH' in phn_dict else (next(iter(phn_dict)) if phn_dict else None)
|
| 239 |
+
self.g2p = None
|
| 240 |
+
try:
|
| 241 |
+
from g2p_en import G2p
|
| 242 |
+
|
| 243 |
+
self.g2p = G2p()
|
| 244 |
+
except Exception:
|
| 245 |
+
pass
|
| 246 |
+
|
| 247 |
+
def word_to_phones(self, word):
|
| 248 |
+
word = normalize_word(word)
|
| 249 |
+
if word in self.lexicon:
|
| 250 |
+
return list(self.lexicon[word]), 'lexicon'
|
| 251 |
+
if word in self.cache:
|
| 252 |
+
return self.cache[word]
|
| 253 |
+
if self.g2p is not None:
|
| 254 |
+
try:
|
| 255 |
+
phones = []
|
| 256 |
+
for raw_phone in self.g2p(word.lower()):
|
| 257 |
+
phone = normalize_phone(raw_phone)
|
| 258 |
+
if phone and phone in self.phn_dict:
|
| 259 |
+
phones.append(phone)
|
| 260 |
+
if phones:
|
| 261 |
+
result = (phones, 'g2p_en')
|
| 262 |
+
self.cache[word] = result
|
| 263 |
+
return result
|
| 264 |
+
except Exception:
|
| 265 |
+
self.g2p = None
|
| 266 |
+
if self.fallback_phone is None:
|
| 267 |
+
result = ([], 'unmapped')
|
| 268 |
+
else:
|
| 269 |
+
approx_len = max(1, int(math.ceil(len(re.sub(r'[^A-Z]', '', word)) / 3.0)))
|
| 270 |
+
result = ([self.fallback_phone] * approx_len, 'fallback_phone')
|
| 271 |
+
self.cache[word] = result
|
| 272 |
+
return result
|
| 273 |
+
|
| 274 |
+
def words_to_phone_sequence(self, words):
|
| 275 |
+
phones = []
|
| 276 |
+
phone_to_word = []
|
| 277 |
+
source_counts = Counter()
|
| 278 |
+
for word_idx, word in enumerate(words):
|
| 279 |
+
cur_phones, source = self.word_to_phones(word)
|
| 280 |
+
source_counts[source] += 1
|
| 281 |
+
for phone in cur_phones:
|
| 282 |
+
phones.append(phone)
|
| 283 |
+
phone_to_word.append(word_idx)
|
| 284 |
+
return phones, phone_to_word, dict(source_counts)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
class WhisperNBestGenerator:
|
| 288 |
+
def __init__(self, model_name, language, device, nbest, beam_size, max_new_tokens, no_repeat_ngram_size):
|
| 289 |
+
self.processor = AutoProcessor.from_pretrained(model_name)
|
| 290 |
+
torch_dtype = torch.float16 if str(device).startswith('cuda') else torch.float32
|
| 291 |
+
self.model = AutoModelForSpeechSeq2Seq.from_pretrained(model_name, torch_dtype=torch_dtype)
|
| 292 |
+
self.model.to(device)
|
| 293 |
+
self.model.eval()
|
| 294 |
+
self.model_dtype = next(self.model.parameters()).dtype
|
| 295 |
+
self.language = language
|
| 296 |
+
self.device = device
|
| 297 |
+
self.nbest = int(nbest)
|
| 298 |
+
self.beam_size = max(int(beam_size), int(nbest))
|
| 299 |
+
self.max_new_tokens = int(max_new_tokens)
|
| 300 |
+
self.no_repeat_ngram_size = int(no_repeat_ngram_size)
|
| 301 |
+
self.forced_decoder_ids = None
|
| 302 |
+
if hasattr(self.processor, 'get_decoder_prompt_ids'):
|
| 303 |
+
try:
|
| 304 |
+
self.forced_decoder_ids = self.processor.get_decoder_prompt_ids(
|
| 305 |
+
language=language,
|
| 306 |
+
task='transcribe',
|
| 307 |
+
)
|
| 308 |
+
except Exception:
|
| 309 |
+
self.forced_decoder_ids = None
|
| 310 |
+
|
| 311 |
+
@torch.inference_mode()
|
| 312 |
+
def generate(self, audio, sample_rate, audio_end):
|
| 313 |
+
inputs = self.processor(
|
| 314 |
+
np.asarray(audio, dtype=np.float32),
|
| 315 |
+
sampling_rate=sample_rate,
|
| 316 |
+
return_tensors='pt',
|
| 317 |
+
return_attention_mask=True,
|
| 318 |
+
)
|
| 319 |
+
inputs = {key: value.to(self.device) for key, value in inputs.items()}
|
| 320 |
+
for key in ('input_features', 'input_values'):
|
| 321 |
+
if key in inputs and torch.is_floating_point(inputs[key]):
|
| 322 |
+
inputs[key] = inputs[key].to(dtype=self.model_dtype)
|
| 323 |
+
generate_kwargs = {
|
| 324 |
+
'num_beams': self.beam_size,
|
| 325 |
+
'num_return_sequences': self.nbest,
|
| 326 |
+
'max_new_tokens': self.max_new_tokens,
|
| 327 |
+
'return_dict_in_generate': True,
|
| 328 |
+
'output_scores': True,
|
| 329 |
+
'do_sample': False,
|
| 330 |
+
}
|
| 331 |
+
if self.no_repeat_ngram_size > 0:
|
| 332 |
+
generate_kwargs['no_repeat_ngram_size'] = self.no_repeat_ngram_size
|
| 333 |
+
if self.forced_decoder_ids is not None:
|
| 334 |
+
generate_kwargs['forced_decoder_ids'] = self.forced_decoder_ids
|
| 335 |
+
output = self.model.generate(**inputs, **generate_kwargs)
|
| 336 |
+
if torch.is_tensor(output):
|
| 337 |
+
sequences = output
|
| 338 |
+
sequence_scores = [0.0 for _ in range(int(sequences.shape[0]))]
|
| 339 |
+
transition_scores = []
|
| 340 |
+
else:
|
| 341 |
+
sequences = output.sequences
|
| 342 |
+
if getattr(output, 'sequences_scores', None) is not None:
|
| 343 |
+
sequence_scores = output.sequences_scores.detach().float().cpu().numpy().tolist()
|
| 344 |
+
else:
|
| 345 |
+
sequence_scores = [0.0 for _ in range(int(sequences.shape[0]))]
|
| 346 |
+
transition_scores = self._transition_scores(output)
|
| 347 |
+
texts = self.processor.batch_decode(sequences, skip_special_tokens=True)
|
| 348 |
+
|
| 349 |
+
rows = []
|
| 350 |
+
for rank, (text, sequence_score) in enumerate(zip(texts, sequence_scores)):
|
| 351 |
+
token_ids = sequences[rank].detach().cpu().tolist()
|
| 352 |
+
token_logprobs = (
|
| 353 |
+
transition_scores[rank]
|
| 354 |
+
if rank < len(transition_scores)
|
| 355 |
+
else [float(sequence_score) for _ in token_ids]
|
| 356 |
+
)
|
| 357 |
+
token_rows, word_rows = self._token_word_scores(token_ids, token_logprobs)
|
| 358 |
+
words = [row['word'] for row in word_rows]
|
| 359 |
+
length_norm = (
|
| 360 |
+
float(np.mean([row['logprob'] for row in token_rows]))
|
| 361 |
+
if token_rows
|
| 362 |
+
else float(sequence_score)
|
| 363 |
+
)
|
| 364 |
+
rows.append({
|
| 365 |
+
'rank': int(rank),
|
| 366 |
+
'text': ' '.join(words).lower(),
|
| 367 |
+
'words': words,
|
| 368 |
+
'logprob': float(length_norm),
|
| 369 |
+
'sequence_score': float(sequence_score),
|
| 370 |
+
'length_normalized_sequence_score': float(length_norm),
|
| 371 |
+
'token_ids': [int(row['token_id']) for row in token_rows],
|
| 372 |
+
'token_logprobs': [float(row['logprob']) for row in token_rows],
|
| 373 |
+
'token_confidences': [float(row['confidence']) for row in token_rows],
|
| 374 |
+
'word_token_ranges': [[int(row['token_start']), int(row['token_end'])] for row in word_rows],
|
| 375 |
+
'word_logprobs': [float(row['logprob']) for row in word_rows],
|
| 376 |
+
'word_confidences': [float(row['confidence']) for row in word_rows],
|
| 377 |
+
'word_timestamps': estimate_word_timestamps(words, audio_end),
|
| 378 |
+
})
|
| 379 |
+
if str(self.device).startswith('cuda'):
|
| 380 |
+
torch.cuda.empty_cache()
|
| 381 |
+
gc.collect()
|
| 382 |
+
return rows
|
| 383 |
+
|
| 384 |
+
def _transition_scores(self, output):
|
| 385 |
+
if getattr(output, 'scores', None) is None:
|
| 386 |
+
return []
|
| 387 |
+
try:
|
| 388 |
+
sequences = output.sequences.detach().cpu()
|
| 389 |
+
step_scores = [score.detach().float().cpu() for score in output.scores]
|
| 390 |
+
if not step_scores:
|
| 391 |
+
return []
|
| 392 |
+
beam_indices = getattr(output, 'beam_indices', None)
|
| 393 |
+
if beam_indices is not None:
|
| 394 |
+
beam_indices = beam_indices.detach().cpu()
|
| 395 |
+
generated_steps = len(step_scores)
|
| 396 |
+
start = max(0, int(sequences.shape[1]) - generated_steps)
|
| 397 |
+
rows = []
|
| 398 |
+
for seq_idx in range(int(sequences.shape[0])):
|
| 399 |
+
cur = []
|
| 400 |
+
for step, logits in enumerate(step_scores):
|
| 401 |
+
token_pos = start + step
|
| 402 |
+
if token_pos >= int(sequences.shape[1]):
|
| 403 |
+
break
|
| 404 |
+
token_id = int(sequences[seq_idx, token_pos])
|
| 405 |
+
if token_id < 0 or token_id >= int(logits.shape[-1]):
|
| 406 |
+
cur.append(0.0)
|
| 407 |
+
continue
|
| 408 |
+
score_row = min(seq_idx, int(logits.shape[0]) - 1)
|
| 409 |
+
if beam_indices is not None and seq_idx < int(beam_indices.shape[0]) and token_pos < int(beam_indices.shape[1]):
|
| 410 |
+
candidate = int(beam_indices[seq_idx, token_pos])
|
| 411 |
+
if 0 <= candidate < int(logits.shape[0]):
|
| 412 |
+
score_row = candidate
|
| 413 |
+
log_probs = torch.log_softmax(logits[score_row], dim=-1)
|
| 414 |
+
cur.append(float(log_probs[token_id].item()))
|
| 415 |
+
rows.append(cur)
|
| 416 |
+
return rows
|
| 417 |
+
except Exception:
|
| 418 |
+
return []
|
| 419 |
+
|
| 420 |
+
def _token_word_scores(self, token_ids, token_logprobs):
|
| 421 |
+
tokenizer = self.processor.tokenizer
|
| 422 |
+
special_ids = set(getattr(tokenizer, 'all_special_ids', []) or [])
|
| 423 |
+
if len(token_logprobs) != len(token_ids):
|
| 424 |
+
aligned = [0.0 for _ in token_ids]
|
| 425 |
+
offset = max(0, len(token_ids) - len(token_logprobs))
|
| 426 |
+
for idx, value in enumerate(token_logprobs[-len(token_ids) :]):
|
| 427 |
+
pos = offset + idx
|
| 428 |
+
if pos < len(aligned):
|
| 429 |
+
aligned[pos] = float(value)
|
| 430 |
+
token_logprobs = aligned
|
| 431 |
+
token_rows = []
|
| 432 |
+
words = []
|
| 433 |
+
current = []
|
| 434 |
+
current_token_ids = []
|
| 435 |
+
current_logprobs = []
|
| 436 |
+
current_start = None
|
| 437 |
+
|
| 438 |
+
def flush():
|
| 439 |
+
nonlocal current, current_token_ids, current_logprobs, current_start
|
| 440 |
+
word = normalize_word(''.join(current))
|
| 441 |
+
if word:
|
| 442 |
+
avg_logprob = float(np.mean(current_logprobs)) if current_logprobs else 0.0
|
| 443 |
+
words.append({
|
| 444 |
+
'word': word,
|
| 445 |
+
'token_start': int(current_start if current_start is not None else 0),
|
| 446 |
+
'token_end': int((current_token_ids[-1] + 1) if current_token_ids else 0),
|
| 447 |
+
'logprob': avg_logprob,
|
| 448 |
+
'confidence': float(np.clip(np.exp(avg_logprob), 0.0, 1.0)),
|
| 449 |
+
})
|
| 450 |
+
current = []
|
| 451 |
+
current_token_ids = []
|
| 452 |
+
current_logprobs = []
|
| 453 |
+
current_start = None
|
| 454 |
+
|
| 455 |
+
for pos, token_id in enumerate(token_ids):
|
| 456 |
+
if int(token_id) in special_ids:
|
| 457 |
+
continue
|
| 458 |
+
logprob = float(token_logprobs[pos]) if pos < len(token_logprobs) else 0.0
|
| 459 |
+
try:
|
| 460 |
+
text = tokenizer.decode([int(token_id)], skip_special_tokens=True, clean_up_tokenization_spaces=False)
|
| 461 |
+
except TypeError:
|
| 462 |
+
text = tokenizer.decode([int(token_id)], skip_special_tokens=True)
|
| 463 |
+
if not text:
|
| 464 |
+
continue
|
| 465 |
+
token_rows.append({
|
| 466 |
+
'token_id': int(token_id),
|
| 467 |
+
'logprob': logprob,
|
| 468 |
+
'confidence': float(np.clip(np.exp(logprob), 0.0, 1.0)),
|
| 469 |
+
})
|
| 470 |
+
for char in text:
|
| 471 |
+
if char.isalpha() or char == "'":
|
| 472 |
+
if current_start is None:
|
| 473 |
+
current_start = pos
|
| 474 |
+
current.append(char)
|
| 475 |
+
current_token_ids.append(pos)
|
| 476 |
+
current_logprobs.append(logprob)
|
| 477 |
+
else:
|
| 478 |
+
flush()
|
| 479 |
+
flush()
|
| 480 |
+
return token_rows, words
|
| 481 |
+
|
| 482 |
+
|
| 483 |
+
def normalize_text_to_words(text):
|
| 484 |
+
tokens = []
|
| 485 |
+
for token in re.findall(r"[A-Za-z']+", text):
|
| 486 |
+
norm = normalize_word(token)
|
| 487 |
+
if norm:
|
| 488 |
+
tokens.append(norm)
|
| 489 |
+
return tokens
|
| 490 |
+
|
| 491 |
+
|
| 492 |
+
def estimate_word_timestamps(words, audio_end):
|
| 493 |
+
if not words:
|
| 494 |
+
return []
|
| 495 |
+
step = float(audio_end) / max(len(words), 1)
|
| 496 |
+
rows = []
|
| 497 |
+
for idx, word in enumerate(words):
|
| 498 |
+
rows.append({
|
| 499 |
+
'word': word.lower(),
|
| 500 |
+
'start': float(idx * step),
|
| 501 |
+
'end': float(min(audio_end, (idx + 1) * step)),
|
| 502 |
+
'source': 'duration_proportional_estimate',
|
| 503 |
+
})
|
| 504 |
+
return rows
|
| 505 |
+
|
| 506 |
+
|
| 507 |
+
def hypothesis_phone_rows(row, phone_mapper, phn_dict):
|
| 508 |
+
phones = []
|
| 509 |
+
phone_ids = []
|
| 510 |
+
phone_to_word = []
|
| 511 |
+
phone_confidences = []
|
| 512 |
+
source_counts = Counter()
|
| 513 |
+
word_confidences = row.get('word_confidences') or [1.0 for _ in row.get('words', [])]
|
| 514 |
+
for word_idx, word in enumerate(row.get('words', [])):
|
| 515 |
+
cur_phones, source = phone_mapper.word_to_phones(word)
|
| 516 |
+
source_counts[source] += 1
|
| 517 |
+
word_conf = float(word_confidences[word_idx]) if word_idx < len(word_confidences) else 1.0
|
| 518 |
+
word_conf = float(np.clip(word_conf, 0.0, 1.0))
|
| 519 |
+
for phone in cur_phones:
|
| 520 |
+
if phone not in phn_dict:
|
| 521 |
+
continue
|
| 522 |
+
phones.append(phone)
|
| 523 |
+
phone_ids.append(int(phn_dict[phone]))
|
| 524 |
+
phone_to_word.append(int(word_idx))
|
| 525 |
+
phone_confidences.append(word_conf)
|
| 526 |
+
return {
|
| 527 |
+
'phones': phones,
|
| 528 |
+
'phone_ids': phone_ids,
|
| 529 |
+
'phone_to_word': phone_to_word,
|
| 530 |
+
'phone_confidences': phone_confidences,
|
| 531 |
+
'source_counts': dict(source_counts),
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
+
|
| 535 |
+
def align_hypothesis_with_charsiu(item, row, phone_mapper, phn_dict, phone_to_frame_id, audio_end):
|
| 536 |
+
hyp = hypothesis_phone_rows(row, phone_mapper, phn_dict)
|
| 537 |
+
words = row.get('words', [])
|
| 538 |
+
if not words or not hyp['phone_ids']:
|
| 539 |
+
row['word_timestamps'] = []
|
| 540 |
+
row['timestamp_source'] = 'empty_hypothesis'
|
| 541 |
+
row['phone_times'] = []
|
| 542 |
+
row['phone_acoustic_supports'] = []
|
| 543 |
+
return row
|
| 544 |
+
|
| 545 |
+
kept_indices, kept_probs = select_visible_frames(item['probs'], item['keep_mask'], audio_end, item['frame_step'])
|
| 546 |
+
frame_phone_ids = []
|
| 547 |
+
id_to_phone = {idx: phone for phone, idx in phn_dict.items()}
|
| 548 |
+
try:
|
| 549 |
+
for phone_idx in hyp['phone_ids']:
|
| 550 |
+
phone = id_to_phone[int(phone_idx)]
|
| 551 |
+
frame_phone_ids.append(phone_to_frame_id[phone])
|
| 552 |
+
if kept_probs.shape[0] < len(frame_phone_ids):
|
| 553 |
+
raise ValueError('not_enough_visible_frames_for_hypothesis')
|
| 554 |
+
path = monotonic_align(-np.log(np.clip(kept_probs, EPS, None)), frame_phone_ids)
|
| 555 |
+
phone_times = []
|
| 556 |
+
phone_acoustic_supports = []
|
| 557 |
+
for phone_pos, frame_phone_id in enumerate(frame_phone_ids):
|
| 558 |
+
local_frames = kept_indices[path == phone_pos]
|
| 559 |
+
if local_frames.size == 0:
|
| 560 |
+
raise ValueError('empty_aligned_phone_span')
|
| 561 |
+
start_time = float(local_frames.min() * item['frame_step'])
|
| 562 |
+
end_time = float((local_frames.max() + 1) * item['frame_step'])
|
| 563 |
+
support = float(np.mean(item['probs'][local_frames, frame_phone_id]))
|
| 564 |
+
phone_times.append((start_time, min(float(audio_end), end_time)))
|
| 565 |
+
phone_acoustic_supports.append(float(np.clip(support, 0.0, 1.0)))
|
| 566 |
+
word_rows = []
|
| 567 |
+
for word_idx, word in enumerate(words):
|
| 568 |
+
positions = [idx for idx, cur_word in enumerate(hyp['phone_to_word']) if cur_word == word_idx]
|
| 569 |
+
if not positions:
|
| 570 |
+
continue
|
| 571 |
+
start = min(phone_times[idx][0] for idx in positions)
|
| 572 |
+
end = max(phone_times[idx][1] for idx in positions)
|
| 573 |
+
word_rows.append({
|
| 574 |
+
'word': word,
|
| 575 |
+
'start': float(start),
|
| 576 |
+
'end': float(end),
|
| 577 |
+
'source': 'charsiu_hypothesis_alignment',
|
| 578 |
+
'word_logprob': float(row.get('word_logprobs', [0.0] * len(words))[word_idx])
|
| 579 |
+
if word_idx < len(row.get('word_logprobs', []))
|
| 580 |
+
else 0.0,
|
| 581 |
+
'word_confidence': float(row.get('word_confidences', [1.0] * len(words))[word_idx])
|
| 582 |
+
if word_idx < len(row.get('word_confidences', []))
|
| 583 |
+
else 1.0,
|
| 584 |
+
})
|
| 585 |
+
row['word_timestamps'] = word_rows
|
| 586 |
+
row['timestamp_source'] = 'charsiu_hypothesis_alignment'
|
| 587 |
+
row['phone_times'] = phone_times
|
| 588 |
+
row['phone_acoustic_supports'] = phone_acoustic_supports
|
| 589 |
+
except Exception as exc:
|
| 590 |
+
row['word_timestamps'] = estimate_word_timestamps(words, audio_end)
|
| 591 |
+
row['timestamp_source'] = 'duration_proportional_fallback'
|
| 592 |
+
row['timestamp_fallback_reason'] = repr(exc)
|
| 593 |
+
phone_times = []
|
| 594 |
+
phone_acoustic_supports = []
|
| 595 |
+
for phone_idx, word_idx in enumerate(hyp['phone_to_word']):
|
| 596 |
+
if word_idx < len(row['word_timestamps']):
|
| 597 |
+
word_time = row['word_timestamps'][word_idx]
|
| 598 |
+
phone_times.append((float(word_time['start']), float(word_time['end'])))
|
| 599 |
+
else:
|
| 600 |
+
phone_times.append((0.0, float(audio_end)))
|
| 601 |
+
phone_acoustic_supports.append(0.0)
|
| 602 |
+
row['phone_times'] = phone_times
|
| 603 |
+
row['phone_acoustic_supports'] = phone_acoustic_supports
|
| 604 |
+
row.update(hyp)
|
| 605 |
+
return row
|
| 606 |
+
|
| 607 |
+
|
| 608 |
+
def interval_overlap_ratio(a, b):
|
| 609 |
+
if a is None or b is None:
|
| 610 |
+
return 0.0
|
| 611 |
+
a0, a1 = a
|
| 612 |
+
b0, b1 = b
|
| 613 |
+
inter = max(0.0, min(float(a1), float(b1)) - max(float(a0), float(b0)))
|
| 614 |
+
union = max(float(a1), float(b1)) - min(float(a0), float(b0))
|
| 615 |
+
if union <= 0:
|
| 616 |
+
return 0.0
|
| 617 |
+
return inter / union
|
| 618 |
+
|
| 619 |
+
|
| 620 |
+
def align_token_sequences(
|
| 621 |
+
ref_tokens,
|
| 622 |
+
hyp_tokens,
|
| 623 |
+
mismatch_cost=1.0,
|
| 624 |
+
ref_times=None,
|
| 625 |
+
hyp_times=None,
|
| 626 |
+
hyp_confidences=None,
|
| 627 |
+
time_overlap_reward=0.0,
|
| 628 |
+
):
|
| 629 |
+
n = len(ref_tokens)
|
| 630 |
+
m = len(hyp_tokens)
|
| 631 |
+
dp = np.zeros((n + 1, m + 1), dtype=np.float32)
|
| 632 |
+
back = {}
|
| 633 |
+
for i in range(1, n + 1):
|
| 634 |
+
dp[i, 0] = dp[i - 1, 0] + 1.0
|
| 635 |
+
back[(i, 0)] = (i - 1, 0, 'delete')
|
| 636 |
+
for j in range(1, m + 1):
|
| 637 |
+
dp[0, j] = dp[0, j - 1] + 1.0
|
| 638 |
+
back[(0, j)] = (0, j - 1, 'insert')
|
| 639 |
+
for i in range(1, n + 1):
|
| 640 |
+
for j in range(1, m + 1):
|
| 641 |
+
sub_cost = 0.0 if ref_tokens[i - 1] == hyp_tokens[j - 1] else mismatch_cost
|
| 642 |
+
if ref_times is not None and hyp_times is not None:
|
| 643 |
+
sub_cost -= float(time_overlap_reward) * interval_overlap_ratio(ref_times[i - 1], hyp_times[j - 1])
|
| 644 |
+
if hyp_confidences is not None:
|
| 645 |
+
sub_cost -= 0.1 * float(np.clip(hyp_confidences[j - 1], 0.0, 1.0))
|
| 646 |
+
sub_cost = max(0.0, sub_cost)
|
| 647 |
+
candidates = [
|
| 648 |
+
(dp[i - 1, j - 1] + sub_cost, i - 1, j - 1, 'match'),
|
| 649 |
+
(dp[i - 1, j] + 1.0, i - 1, j, 'delete'),
|
| 650 |
+
(dp[i, j - 1] + 1.0, i, j - 1, 'insert'),
|
| 651 |
+
]
|
| 652 |
+
cost, prev_i, prev_j, op = min(candidates, key=lambda item: item[0])
|
| 653 |
+
dp[i, j] = cost
|
| 654 |
+
back[(i, j)] = (prev_i, prev_j, op)
|
| 655 |
+
|
| 656 |
+
pairs = []
|
| 657 |
+
i, j = n, m
|
| 658 |
+
while i > 0 or j > 0:
|
| 659 |
+
prev_i, prev_j, op = back[(i, j)]
|
| 660 |
+
if op == 'match':
|
| 661 |
+
pairs.append((i - 1, j - 1))
|
| 662 |
+
elif op == 'delete':
|
| 663 |
+
pairs.append((i - 1, None))
|
| 664 |
+
else:
|
| 665 |
+
pairs.append((None, j - 1))
|
| 666 |
+
i, j = prev_i, prev_j
|
| 667 |
+
pairs.reverse()
|
| 668 |
+
return pairs
|
| 669 |
+
|
| 670 |
+
|
| 671 |
+
def slot_top_phone(slot_counts, eps_index):
|
| 672 |
+
best_idx = None
|
| 673 |
+
best_mass = -1.0
|
| 674 |
+
for phone_idx, mass in slot_counts.items():
|
| 675 |
+
if phone_idx == eps_index:
|
| 676 |
+
continue
|
| 677 |
+
if mass > best_mass:
|
| 678 |
+
best_idx = phone_idx
|
| 679 |
+
best_mass = mass
|
| 680 |
+
return best_idx
|
| 681 |
+
|
| 682 |
+
|
| 683 |
+
def slot_time(slot):
|
| 684 |
+
mass = max(float(slot.get('time_mass', 0.0)), EPS)
|
| 685 |
+
if mass <= EPS:
|
| 686 |
+
return None
|
| 687 |
+
return float(slot.get('start_sum', 0.0) / mass), float(slot.get('end_sum', 0.0) / mass)
|
| 688 |
+
|
| 689 |
+
|
| 690 |
+
def add_slot_phone_mass(slot, phone_idx, phone_mass, eps_index, eps_mass=0.0, phone_time=None, confidence=1.0):
|
| 691 |
+
if phone_mass > 0:
|
| 692 |
+
slot['counts'][int(phone_idx)] += float(phone_mass)
|
| 693 |
+
if eps_mass > 0:
|
| 694 |
+
slot['counts'][eps_index] += float(eps_mass)
|
| 695 |
+
if phone_time is not None and phone_mass > 0:
|
| 696 |
+
slot['start_sum'] = slot.get('start_sum', 0.0) + float(phone_time[0]) * float(phone_mass)
|
| 697 |
+
slot['end_sum'] = slot.get('end_sum', 0.0) + float(phone_time[1]) * float(phone_mass)
|
| 698 |
+
slot['time_mass'] = slot.get('time_mass', 0.0) + float(phone_mass)
|
| 699 |
+
slot['confidence_sum'] = slot.get('confidence_sum', 0.0) + float(confidence) * max(float(phone_mass), 0.0)
|
| 700 |
+
slot['confidence_mass'] = slot.get('confidence_mass', 0.0) + max(float(phone_mass), 0.0)
|
| 701 |
+
|
| 702 |
+
|
| 703 |
+
def insert_slot(slots, insert_at, eps_index, prior_mass):
|
| 704 |
+
slot = {'counts': Counter(), 'start_sum': 0.0, 'end_sum': 0.0, 'time_mass': 0.0}
|
| 705 |
+
if prior_mass > 0:
|
| 706 |
+
slot['counts'][eps_index] += float(prior_mass)
|
| 707 |
+
slots.insert(insert_at, slot)
|
| 708 |
+
return slot
|
| 709 |
+
|
| 710 |
+
|
| 711 |
+
def build_pcn_from_hypotheses(hypotheses, phone_mapper, phn_dict):
|
| 712 |
+
eps_index = len(phn_dict)
|
| 713 |
+
phone_dim = len(phn_dict) + 1
|
| 714 |
+
hyp_logprobs = [float(row.get('length_normalized_sequence_score', row.get('logprob', 0.0))) for row in hypotheses]
|
| 715 |
+
hyp_weights = softmax_1d(hyp_logprobs)
|
| 716 |
+
id_to_phone = {idx: phone for phone, idx in phn_dict.items()}
|
| 717 |
+
|
| 718 |
+
hyp_phone_rows = []
|
| 719 |
+
for row, weight in zip(hypotheses, hyp_weights):
|
| 720 |
+
if 'phone_ids' not in row:
|
| 721 |
+
row = align_hypothesis_with_charsiu(
|
| 722 |
+
item={'probs': np.zeros((0, phone_dim), dtype=np.float32), 'keep_mask': np.zeros((0,), dtype=np.int32), 'frame_step': 0.02},
|
| 723 |
+
row=row,
|
| 724 |
+
phone_mapper=phone_mapper,
|
| 725 |
+
phn_dict=phn_dict,
|
| 726 |
+
phone_to_frame_id={},
|
| 727 |
+
audio_end=0.0,
|
| 728 |
+
)
|
| 729 |
+
phone_ids = [int(phone_idx) for phone_idx in row.get('phone_ids', [])]
|
| 730 |
+
phone_confidences = [float(x) for x in row.get('phone_confidences', [1.0] * len(phone_ids))]
|
| 731 |
+
phone_acoustic = [float(x) for x in row.get('phone_acoustic_supports', [0.0] * len(phone_ids))]
|
| 732 |
+
phone_times = row.get('phone_times', [None] * len(phone_ids))
|
| 733 |
+
hyp_phone_rows.append({
|
| 734 |
+
'phones': row.get('phones', []),
|
| 735 |
+
'phone_ids': phone_ids,
|
| 736 |
+
'phone_to_word': list(row.get('phone_to_word', [])),
|
| 737 |
+
'phone_confidences': phone_confidences,
|
| 738 |
+
'phone_acoustic_supports': phone_acoustic,
|
| 739 |
+
'phone_times': phone_times,
|
| 740 |
+
'weight': float(weight),
|
| 741 |
+
'source_counts': row.get('source_counts', {}),
|
| 742 |
+
})
|
| 743 |
+
|
| 744 |
+
slots = []
|
| 745 |
+
total_mass = 0.0
|
| 746 |
+
for hyp_idx, hyp in enumerate(hyp_phone_rows):
|
| 747 |
+
phone_ids = hyp['phone_ids']
|
| 748 |
+
weight = float(hyp['weight'])
|
| 749 |
+
if hyp_idx == 0:
|
| 750 |
+
for local_idx, phone_idx in enumerate(phone_ids):
|
| 751 |
+
slot = {'counts': Counter(), 'start_sum': 0.0, 'end_sum': 0.0, 'time_mass': 0.0}
|
| 752 |
+
quality = float(np.clip(
|
| 753 |
+
0.5 * hyp['phone_confidences'][local_idx] + 0.5 * hyp['phone_acoustic_supports'][local_idx],
|
| 754 |
+
0.0,
|
| 755 |
+
1.0,
|
| 756 |
+
))
|
| 757 |
+
add_slot_phone_mass(
|
| 758 |
+
slot,
|
| 759 |
+
phone_idx,
|
| 760 |
+
weight * quality,
|
| 761 |
+
eps_index,
|
| 762 |
+
eps_mass=weight * (1.0 - quality),
|
| 763 |
+
phone_time=hyp['phone_times'][local_idx] if local_idx < len(hyp['phone_times']) else None,
|
| 764 |
+
confidence=hyp['phone_confidences'][local_idx],
|
| 765 |
+
)
|
| 766 |
+
slots.append(slot)
|
| 767 |
+
total_mass += weight
|
| 768 |
+
continue
|
| 769 |
+
|
| 770 |
+
consensus_slot_ids = []
|
| 771 |
+
consensus_phone_ids = []
|
| 772 |
+
for slot_idx, slot in enumerate(slots):
|
| 773 |
+
top_idx = slot_top_phone(slot['counts'], eps_index)
|
| 774 |
+
if top_idx is not None:
|
| 775 |
+
consensus_slot_ids.append(slot_idx)
|
| 776 |
+
consensus_phone_ids.append(top_idx)
|
| 777 |
+
consensus_times = [slot_time(slots[slot_idx]) for slot_idx in consensus_slot_ids]
|
| 778 |
+
pairs = align_token_sequences(
|
| 779 |
+
consensus_phone_ids,
|
| 780 |
+
phone_ids,
|
| 781 |
+
ref_times=consensus_times,
|
| 782 |
+
hyp_times=hyp.get('phone_times'),
|
| 783 |
+
hyp_confidences=hyp.get('phone_confidences'),
|
| 784 |
+
time_overlap_reward=0.3,
|
| 785 |
+
)
|
| 786 |
+
cursor = 0
|
| 787 |
+
matched_slots = set()
|
| 788 |
+
for ref_pos, hyp_pos in pairs:
|
| 789 |
+
if ref_pos is None:
|
| 790 |
+
insert_at = consensus_slot_ids[cursor] if cursor < len(consensus_slot_ids) else len(slots)
|
| 791 |
+
slot = insert_slot(slots, insert_at, eps_index, total_mass)
|
| 792 |
+
quality = float(np.clip(
|
| 793 |
+
0.5 * hyp['phone_confidences'][hyp_pos] + 0.5 * hyp['phone_acoustic_supports'][hyp_pos],
|
| 794 |
+
0.0,
|
| 795 |
+
1.0,
|
| 796 |
+
))
|
| 797 |
+
add_slot_phone_mass(
|
| 798 |
+
slot,
|
| 799 |
+
phone_ids[hyp_pos],
|
| 800 |
+
weight * quality,
|
| 801 |
+
eps_index,
|
| 802 |
+
eps_mass=weight * (1.0 - quality),
|
| 803 |
+
phone_time=hyp['phone_times'][hyp_pos] if hyp_pos < len(hyp['phone_times']) else None,
|
| 804 |
+
confidence=hyp['phone_confidences'][hyp_pos],
|
| 805 |
+
)
|
| 806 |
+
cursor += 1
|
| 807 |
+
else:
|
| 808 |
+
slot_idx = consensus_slot_ids[ref_pos]
|
| 809 |
+
matched_slots.add(slot_idx)
|
| 810 |
+
cursor = ref_pos + 1
|
| 811 |
+
if hyp_pos is None:
|
| 812 |
+
slots[slot_idx]['counts'][eps_index] += weight
|
| 813 |
+
else:
|
| 814 |
+
quality = float(np.clip(
|
| 815 |
+
0.5 * hyp['phone_confidences'][hyp_pos] + 0.5 * hyp['phone_acoustic_supports'][hyp_pos],
|
| 816 |
+
0.0,
|
| 817 |
+
1.0,
|
| 818 |
+
))
|
| 819 |
+
add_slot_phone_mass(
|
| 820 |
+
slots[slot_idx],
|
| 821 |
+
phone_ids[hyp_pos],
|
| 822 |
+
weight * quality,
|
| 823 |
+
eps_index,
|
| 824 |
+
eps_mass=weight * (1.0 - quality),
|
| 825 |
+
phone_time=hyp['phone_times'][hyp_pos] if hyp_pos < len(hyp['phone_times']) else None,
|
| 826 |
+
confidence=hyp['phone_confidences'][hyp_pos],
|
| 827 |
+
)
|
| 828 |
+
for slot_idx, slot in enumerate(slots):
|
| 829 |
+
if slot_idx not in matched_slots and sum(slot['counts'].values()) < total_mass + weight - EPS:
|
| 830 |
+
if slot_top_phone(slot['counts'], eps_index) is not None:
|
| 831 |
+
slot['counts'][eps_index] += weight
|
| 832 |
+
total_mass += weight
|
| 833 |
+
|
| 834 |
+
if not slots:
|
| 835 |
+
slot = {'counts': Counter()}
|
| 836 |
+
slot['counts'][eps_index] = 1.0
|
| 837 |
+
slots = [slot]
|
| 838 |
+
total_mass = 1.0
|
| 839 |
+
|
| 840 |
+
cn_post = np.zeros((len(slots), phone_dim), dtype=np.float32)
|
| 841 |
+
top_phone_ids = []
|
| 842 |
+
slot_times = []
|
| 843 |
+
slot_confidences = []
|
| 844 |
+
for slot_idx, slot in enumerate(slots):
|
| 845 |
+
slot_mass = sum(slot['counts'].values())
|
| 846 |
+
if slot_mass < total_mass:
|
| 847 |
+
slot['counts'][eps_index] += total_mass - slot_mass
|
| 848 |
+
for phone_idx, mass in slot['counts'].items():
|
| 849 |
+
cn_post[slot_idx, int(phone_idx)] = float(mass) / max(float(total_mass), EPS)
|
| 850 |
+
cn_post[slot_idx] /= np.clip(cn_post[slot_idx].sum(), EPS, None)
|
| 851 |
+
top_phone_ids.append(slot_top_phone(slot['counts'], eps_index))
|
| 852 |
+
slot_times.append(slot_time(slot))
|
| 853 |
+
conf_mass = max(float(slot.get('confidence_mass', 0.0)), EPS)
|
| 854 |
+
slot_confidences.append(float(np.clip(slot.get('confidence_sum', 0.0) / conf_mass, 0.0, 1.0)))
|
| 855 |
+
|
| 856 |
+
return {
|
| 857 |
+
'cn_post': cn_post,
|
| 858 |
+
'top_phone_ids': top_phone_ids,
|
| 859 |
+
'slot_times': slot_times,
|
| 860 |
+
'slot_confidences': slot_confidences,
|
| 861 |
+
'hyp_phone_rows': hyp_phone_rows,
|
| 862 |
+
'hyp_weights': hyp_weights.tolist(),
|
| 863 |
+
'id_to_phone': id_to_phone,
|
| 864 |
+
'eps_index': eps_index,
|
| 865 |
+
}
|
| 866 |
+
|
| 867 |
+
|
| 868 |
+
def top_hyp_word_ids_for_slots(pcn):
|
| 869 |
+
slot_word_ids = np.zeros((len(pcn['top_phone_ids']),), dtype=np.int32) - 1
|
| 870 |
+
if not pcn['hyp_phone_rows']:
|
| 871 |
+
return slot_word_ids
|
| 872 |
+
top_hyp = pcn['hyp_phone_rows'][0]
|
| 873 |
+
hyp_phone_ids = list(top_hyp['phone_ids'])
|
| 874 |
+
hyp_phone_to_word = list(top_hyp['phone_to_word'])
|
| 875 |
+
consensus_slot_ids = []
|
| 876 |
+
consensus_phone_ids = []
|
| 877 |
+
for slot_idx, phone_idx in enumerate(pcn['top_phone_ids']):
|
| 878 |
+
if phone_idx is not None:
|
| 879 |
+
consensus_slot_ids.append(slot_idx)
|
| 880 |
+
consensus_phone_ids.append(phone_idx)
|
| 881 |
+
pairs = align_token_sequences(consensus_phone_ids, hyp_phone_ids)
|
| 882 |
+
for ref_pos, hyp_pos in pairs:
|
| 883 |
+
if ref_pos is None or hyp_pos is None:
|
| 884 |
+
continue
|
| 885 |
+
slot_idx = consensus_slot_ids[ref_pos]
|
| 886 |
+
if hyp_pos < len(hyp_phone_to_word):
|
| 887 |
+
slot_word_ids[slot_idx] = int(hyp_phone_to_word[hyp_pos])
|
| 888 |
+
return slot_word_ids
|
| 889 |
+
|
| 890 |
+
|
| 891 |
+
def pcn_stats(cn_post, top_phone_ids, prev_top_phone_ids, eps_index):
|
| 892 |
+
stats = np.zeros((cn_post.shape[0], 5), dtype=np.float32)
|
| 893 |
+
stable_prefix = 0
|
| 894 |
+
for idx, phone_idx in enumerate(top_phone_ids):
|
| 895 |
+
if idx < len(prev_top_phone_ids) and phone_idx == prev_top_phone_ids[idx]:
|
| 896 |
+
stable_prefix += 1
|
| 897 |
+
else:
|
| 898 |
+
break
|
| 899 |
+
prefix_stability = float(stable_prefix) / float(max(len(top_phone_ids), 1))
|
| 900 |
+
for idx, probs in enumerate(cn_post):
|
| 901 |
+
non_eps = np.delete(probs, eps_index)
|
| 902 |
+
top1, margin = top_margin(non_eps)
|
| 903 |
+
stats[idx] = np.array(
|
| 904 |
+
[
|
| 905 |
+
float(probs[eps_index]),
|
| 906 |
+
entropy_np(probs),
|
| 907 |
+
top1,
|
| 908 |
+
margin,
|
| 909 |
+
prefix_stability,
|
| 910 |
+
],
|
| 911 |
+
dtype=np.float32,
|
| 912 |
+
)
|
| 913 |
+
return stats, prefix_stability
|
| 914 |
+
|
| 915 |
+
|
| 916 |
+
def validate_pcn(pcn):
|
| 917 |
+
cn_post = np.asarray(pcn['cn_post'], dtype=np.float32)
|
| 918 |
+
if not np.isfinite(cn_post).all():
|
| 919 |
+
raise ValueError('pcn_contains_nan_or_inf')
|
| 920 |
+
sums = cn_post.sum(axis=-1)
|
| 921 |
+
if not np.allclose(sums, 1.0, atol=1e-3):
|
| 922 |
+
raise ValueError(f'pcn_posterior_not_normalized:max_abs_err={float(np.max(np.abs(sums - 1.0)))}')
|
| 923 |
+
eps_index = int(pcn['eps_index'])
|
| 924 |
+
if eps_index < 0 or eps_index >= cn_post.shape[-1]:
|
| 925 |
+
raise ValueError('invalid_epsilon_index')
|
| 926 |
+
eps_probs = cn_post[:, eps_index]
|
| 927 |
+
if np.any(eps_probs < -1e-6) or np.any(eps_probs > 1.0 + 1e-6):
|
| 928 |
+
raise ValueError('epsilon_probability_out_of_range')
|
| 929 |
+
for row in pcn.get('hyp_phone_rows', []):
|
| 930 |
+
for value in row.get('phone_confidences', []):
|
| 931 |
+
if not np.isfinite(value) or value < -1e-6 or value > 1.0 + 1e-6:
|
| 932 |
+
raise ValueError('phone_confidence_out_of_range')
|
| 933 |
+
for value in pcn.get('slot_confidences', []):
|
| 934 |
+
if not np.isfinite(value) or value < -1e-6 or value > 1.0 + 1e-6:
|
| 935 |
+
raise ValueError('slot_confidence_out_of_range')
|
| 936 |
+
|
| 937 |
+
|
| 938 |
+
def cumulative_candidate_mask_from_asr(pcn_word_id, word_timestamps, commit_time, audio_end, is_final):
|
| 939 |
+
mask = np.zeros((pcn_word_id.shape[0],), dtype=np.float32)
|
| 940 |
+
committed_words = set()
|
| 941 |
+
for word_idx, word_time in enumerate(word_timestamps or []):
|
| 942 |
+
end_time = float(word_time.get('end', 0.0))
|
| 943 |
+
if end_time <= commit_time + 1e-6 or (is_final and end_time <= audio_end + 1e-6):
|
| 944 |
+
committed_words.add(int(word_idx))
|
| 945 |
+
for slot_idx, word_idx in enumerate(pcn_word_id.tolist()):
|
| 946 |
+
if int(word_idx) in committed_words:
|
| 947 |
+
mask[slot_idx] = 1.0
|
| 948 |
+
return mask
|
| 949 |
+
|
| 950 |
+
|
| 951 |
+
def align_previous_commits(prev_state, current_top_phone_ids):
|
| 952 |
+
if prev_state is None:
|
| 953 |
+
return {}, [], []
|
| 954 |
+
prev_top_phone_ids = prev_state.get('top_phone_ids', [])
|
| 955 |
+
prev_committed = set(int(x) for x in prev_state.get('committed_slots', []))
|
| 956 |
+
pairs = align_token_sequences(prev_top_phone_ids, current_top_phone_ids, mismatch_cost=1.0)
|
| 957 |
+
prev_to_current = {}
|
| 958 |
+
for prev_idx, cur_idx in pairs:
|
| 959 |
+
if prev_idx is None or cur_idx is None:
|
| 960 |
+
continue
|
| 961 |
+
if prev_idx < len(prev_top_phone_ids) and cur_idx < len(current_top_phone_ids):
|
| 962 |
+
if prev_top_phone_ids[prev_idx] == current_top_phone_ids[cur_idx]:
|
| 963 |
+
prev_to_current[int(prev_idx)] = int(cur_idx)
|
| 964 |
+
mapped_old = sorted(prev_to_current[idx] for idx in prev_committed if idx in prev_to_current)
|
| 965 |
+
dropped = sorted(idx for idx in prev_committed if idx not in prev_to_current)
|
| 966 |
+
return prev_to_current, mapped_old, dropped
|
| 967 |
+
|
| 968 |
+
|
| 969 |
+
def _top_word_timestamps(word_timestamps):
|
| 970 |
+
rows = word_timestamps or []
|
| 971 |
+
if rows and isinstance(rows[0], list):
|
| 972 |
+
rows = rows[0]
|
| 973 |
+
return rows if isinstance(rows, list) else []
|
| 974 |
+
|
| 975 |
+
|
| 976 |
+
def _commit_word_metadata(word_timestamps, word_idx):
|
| 977 |
+
rows = _top_word_timestamps(word_timestamps)
|
| 978 |
+
row = rows[word_idx] if 0 <= int(word_idx) < len(rows) and isinstance(rows[word_idx], dict) else {}
|
| 979 |
+
text = normalize_word(str(row.get('word', ''))).casefold()
|
| 980 |
+
try:
|
| 981 |
+
start = float(row.get('start'))
|
| 982 |
+
end = float(row.get('end'))
|
| 983 |
+
except (TypeError, ValueError):
|
| 984 |
+
start = None
|
| 985 |
+
end = None
|
| 986 |
+
return {'text': text, 'start': start, 'end': end}
|
| 987 |
+
|
| 988 |
+
|
| 989 |
+
def _commit_time_iou(left, right):
|
| 990 |
+
if any(item.get(key) is None for item in (left, right) for key in ('start', 'end')):
|
| 991 |
+
return 0.0
|
| 992 |
+
overlap = max(0.0, min(left['end'], right['end']) - max(left['start'], right['start']))
|
| 993 |
+
union = max(left['end'], right['end']) - min(left['start'], right['start'])
|
| 994 |
+
return overlap / union if union > 0 else 0.0
|
| 995 |
+
|
| 996 |
+
|
| 997 |
+
def _word_level_lineage(prev_state, pcn_word_id, current_to_prev, word_timestamps):
|
| 998 |
+
"""Build deterministic one-to-one predecessor decisions without using supervision."""
|
| 999 |
+
current_positions = {
|
| 1000 |
+
word_idx: np.flatnonzero(pcn_word_id == word_idx)
|
| 1001 |
+
for word_idx in sorted(set(int(value) for value in pcn_word_id.tolist() if int(value) >= 0))
|
| 1002 |
+
}
|
| 1003 |
+
if prev_state is None:
|
| 1004 |
+
return current_positions, {
|
| 1005 |
+
word_idx: {
|
| 1006 |
+
'candidate_prev_word_id': None,
|
| 1007 |
+
'selected_prev_word_id': None,
|
| 1008 |
+
'predecessor_word_ids': [],
|
| 1009 |
+
'vote_counts': {},
|
| 1010 |
+
'mapping_status': 'first_seen',
|
| 1011 |
+
'split_competitor_count': 0,
|
| 1012 |
+
'reliable': True,
|
| 1013 |
+
'text_equal': False,
|
| 1014 |
+
'time_iou': 0.0,
|
| 1015 |
+
}
|
| 1016 |
+
for word_idx in current_positions
|
| 1017 |
+
}
|
| 1018 |
+
|
| 1019 |
+
prev_word_ids = np.asarray(prev_state.get('pcn_word_id', []), dtype=np.int32)
|
| 1020 |
+
prev_word_states = prev_state.get('word_states', {})
|
| 1021 |
+
decisions = {}
|
| 1022 |
+
competitors_by_prev = {}
|
| 1023 |
+
for word_idx, positions in current_positions.items():
|
| 1024 |
+
votes = Counter()
|
| 1025 |
+
for position in positions.tolist():
|
| 1026 |
+
old_slot = int(current_to_prev[position]) if position < len(current_to_prev) else -1
|
| 1027 |
+
if 0 <= old_slot < len(prev_word_ids):
|
| 1028 |
+
prev_word_idx = int(prev_word_ids[old_slot])
|
| 1029 |
+
if prev_word_idx >= 0:
|
| 1030 |
+
votes[prev_word_idx] += 1
|
| 1031 |
+
strict = [key for key, count in votes.items() if count > len(positions) / 2.0]
|
| 1032 |
+
decision = {
|
| 1033 |
+
'candidate_prev_word_id': None,
|
| 1034 |
+
'selected_prev_word_id': None,
|
| 1035 |
+
'predecessor_word_ids': sorted(int(key) for key in votes),
|
| 1036 |
+
'vote_counts': {str(key): int(value) for key, value in sorted(votes.items())},
|
| 1037 |
+
'mapping_status': 'unmatched_new' if not votes else 'ambiguous_no_majority',
|
| 1038 |
+
'split_competitor_count': 0,
|
| 1039 |
+
'reliable': not votes,
|
| 1040 |
+
'text_equal': False,
|
| 1041 |
+
'time_iou': 0.0,
|
| 1042 |
+
}
|
| 1043 |
+
if len(strict) == 1:
|
| 1044 |
+
prev_word_idx = int(strict[0])
|
| 1045 |
+
prev_meta = prev_word_states.get(prev_word_idx, {}).get('metadata', {})
|
| 1046 |
+
cur_meta = _commit_word_metadata(word_timestamps, word_idx)
|
| 1047 |
+
decision.update({
|
| 1048 |
+
'candidate_prev_word_id': prev_word_idx,
|
| 1049 |
+
'mapping_status': 'candidate',
|
| 1050 |
+
'text_equal': bool(prev_meta.get('text') and cur_meta['text'] and prev_meta['text'] == cur_meta['text']),
|
| 1051 |
+
'time_iou': float(_commit_time_iou(prev_meta, cur_meta)),
|
| 1052 |
+
})
|
| 1053 |
+
competitors_by_prev.setdefault(prev_word_idx, []).append((word_idx, decision))
|
| 1054 |
+
decisions[word_idx] = decision
|
| 1055 |
+
|
| 1056 |
+
# A strict-majority edge is unique for each current word. Selecting the
|
| 1057 |
+
# highest-weight edge for each predecessor is therefore the global maximum
|
| 1058 |
+
# weight one-to-one matching for this candidate graph.
|
| 1059 |
+
for prev_word_idx, competitors in sorted(competitors_by_prev.items()):
|
| 1060 |
+
for _, decision in competitors:
|
| 1061 |
+
decision['split_competitor_count'] = len(competitors)
|
| 1062 |
+
ranked = sorted(
|
| 1063 |
+
competitors,
|
| 1064 |
+
key=lambda item: (
|
| 1065 |
+
-int(item[1]['vote_counts'][str(prev_word_idx)]),
|
| 1066 |
+
-round(float(item[1]['time_iou']), 12),
|
| 1067 |
+
-int(item[1]['text_equal']),
|
| 1068 |
+
int(item[0]),
|
| 1069 |
+
),
|
| 1070 |
+
)
|
| 1071 |
+
winner_key = (
|
| 1072 |
+
int(ranked[0][1]['vote_counts'][str(prev_word_idx)]),
|
| 1073 |
+
round(float(ranked[0][1]['time_iou']), 12),
|
| 1074 |
+
int(ranked[0][1]['text_equal']),
|
| 1075 |
+
)
|
| 1076 |
+
tied = [
|
| 1077 |
+
item for item in ranked
|
| 1078 |
+
if (
|
| 1079 |
+
int(item[1]['vote_counts'][str(prev_word_idx)]),
|
| 1080 |
+
round(float(item[1]['time_iou']), 12),
|
| 1081 |
+
int(item[1]['text_equal']),
|
| 1082 |
+
) == winner_key
|
| 1083 |
+
]
|
| 1084 |
+
if len(tied) == 1:
|
| 1085 |
+
_, winner = ranked[0]
|
| 1086 |
+
winner['selected_prev_word_id'] = int(prev_word_idx)
|
| 1087 |
+
winner['mapping_status'] = 'accepted'
|
| 1088 |
+
winner['reliable'] = True
|
| 1089 |
+
else:
|
| 1090 |
+
for _, decision in tied:
|
| 1091 |
+
decision['mapping_status'] = 'ambiguous_competition_tie'
|
| 1092 |
+
decision['reliable'] = False
|
| 1093 |
+
for _, loser in ranked[1:]:
|
| 1094 |
+
if loser['mapping_status'] == 'candidate':
|
| 1095 |
+
loser['mapping_status'] = 'split_new_successor'
|
| 1096 |
+
loser['reliable'] = True
|
| 1097 |
+
return current_positions, decisions
|
| 1098 |
+
|
| 1099 |
+
|
| 1100 |
+
def build_stateful_commit_masks(
|
| 1101 |
+
prev_state,
|
| 1102 |
+
pcn,
|
| 1103 |
+
pcn_word_id,
|
| 1104 |
+
word_timestamps,
|
| 1105 |
+
commit_time,
|
| 1106 |
+
audio_end,
|
| 1107 |
+
is_final,
|
| 1108 |
+
current_to_prev_override=None,
|
| 1109 |
+
commit_rule='legacy',
|
| 1110 |
+
):
|
| 1111 |
+
if commit_rule not in {'legacy', 'merge_aware'}:
|
| 1112 |
+
raise ValueError(f"commit_rule must be 'legacy' or 'merge_aware', got {commit_rule!r}")
|
| 1113 |
+
word_timestamps = _top_word_timestamps(word_timestamps)
|
| 1114 |
+
candidate = cumulative_candidate_mask_from_asr(pcn_word_id, word_timestamps, commit_time, audio_end, is_final)
|
| 1115 |
+
if current_to_prev_override is None:
|
| 1116 |
+
prev_to_current, mapped_old_slots, dropped_or_revised = align_previous_commits(prev_state, pcn['top_phone_ids'])
|
| 1117 |
+
current_to_prev = np.zeros((len(pcn['top_phone_ids']),), dtype=np.int32) - 1
|
| 1118 |
+
for prev_idx, cur_idx in prev_to_current.items():
|
| 1119 |
+
if 0 <= cur_idx < current_to_prev.shape[0]:
|
| 1120 |
+
current_to_prev[cur_idx] = int(prev_idx)
|
| 1121 |
+
else:
|
| 1122 |
+
current_to_prev = np.asarray(current_to_prev_override, dtype=np.int32).copy()
|
| 1123 |
+
prev_to_current = {
|
| 1124 |
+
int(prev_idx): int(cur_idx)
|
| 1125 |
+
for cur_idx, prev_idx in enumerate(current_to_prev.tolist())
|
| 1126 |
+
if int(prev_idx) >= 0
|
| 1127 |
+
}
|
| 1128 |
+
prev_committed = set(int(value) for value in (prev_state or {}).get('committed_slots', []))
|
| 1129 |
+
mapped_old_slots = sorted(cur for prev, cur in prev_to_current.items() if prev in prev_committed)
|
| 1130 |
+
dropped_or_revised = sorted(prev for prev in prev_committed if prev not in prev_to_current)
|
| 1131 |
+
mapped_old_set = set(mapped_old_slots)
|
| 1132 |
+
cumulative = candidate.copy()
|
| 1133 |
+
for slot_idx in mapped_old_set:
|
| 1134 |
+
if 0 <= slot_idx < cumulative.shape[0]:
|
| 1135 |
+
cumulative[slot_idx] = 1.0
|
| 1136 |
+
|
| 1137 |
+
if commit_rule == 'legacy':
|
| 1138 |
+
new_mask = np.zeros_like(cumulative)
|
| 1139 |
+
for word_idx in sorted(set(int(value) for value in pcn_word_id.tolist() if int(value) >= 0)):
|
| 1140 |
+
positions = np.flatnonzero(pcn_word_id == word_idx)
|
| 1141 |
+
if positions.size == 0 or not bool(np.all(candidate[positions] > 0)):
|
| 1142 |
+
continue
|
| 1143 |
+
if any(int(position) in mapped_old_set for position in positions.tolist()):
|
| 1144 |
+
continue
|
| 1145 |
+
new_mask[positions] = 1.0
|
| 1146 |
+
committed_slots = sorted(np.flatnonzero(cumulative > 0).astype(int).tolist())
|
| 1147 |
+
new_slots = sorted(np.flatnonzero(new_mask > 0).astype(int).tolist())
|
| 1148 |
+
diagnostics = {
|
| 1149 |
+
'mapped_old_slots': mapped_old_slots,
|
| 1150 |
+
'new_slots': new_slots,
|
| 1151 |
+
'dropped_or_revised_slots': dropped_or_revised,
|
| 1152 |
+
'state_event_semantics': 'legacy_slot_any_v1',
|
| 1153 |
+
}
|
| 1154 |
+
next_state = {
|
| 1155 |
+
'top_phone_ids': list(pcn['top_phone_ids']),
|
| 1156 |
+
'committed_slots': committed_slots,
|
| 1157 |
+
}
|
| 1158 |
+
return cumulative.astype(np.float32), new_mask.astype(np.float32), current_to_prev, diagnostics, next_state
|
| 1159 |
+
|
| 1160 |
+
current_positions, lineage = _word_level_lineage(
|
| 1161 |
+
prev_state,
|
| 1162 |
+
np.asarray(pcn_word_id, dtype=np.int32),
|
| 1163 |
+
current_to_prev,
|
| 1164 |
+
word_timestamps,
|
| 1165 |
+
)
|
| 1166 |
+
prev_word_states = (prev_state or {}).get('word_states', {})
|
| 1167 |
+
next_logical_id = int((prev_state or {}).get('next_logical_word_id', 0))
|
| 1168 |
+
next_event_id = int((prev_state or {}).get('next_state_event_id', 0))
|
| 1169 |
+
next_word_states = {}
|
| 1170 |
+
word_event_rows = []
|
| 1171 |
+
new_mask = np.zeros_like(cumulative)
|
| 1172 |
+
|
| 1173 |
+
for word_idx, positions in sorted(current_positions.items()):
|
| 1174 |
+
decision = lineage[word_idx]
|
| 1175 |
+
selected_prev = decision['selected_prev_word_id']
|
| 1176 |
+
predecessor_ids = decision['predecessor_word_ids']
|
| 1177 |
+
predecessor_states = [prev_word_states.get(value, {}) for value in predecessor_ids]
|
| 1178 |
+
predecessor_committed = [bool(value.get('committed', False)) for value in predecessor_states]
|
| 1179 |
+
completed = bool(np.all(candidate[positions] > 0))
|
| 1180 |
+
split = int(decision['split_competitor_count']) > 1
|
| 1181 |
+
merge = len(predecessor_ids) > 1
|
| 1182 |
+
inherited_state = prev_word_states.get(selected_prev, {}) if selected_prev is not None else {}
|
| 1183 |
+
has_old_committed_slot = any(int(position) in mapped_old_set for position in positions.tolist())
|
| 1184 |
+
prev_word_ids_array = np.asarray((prev_state or {}).get('pcn_word_id', []), dtype=np.int32)
|
| 1185 |
+
prev_committed_slots = set(int(value) for value in (prev_state or {}).get('committed_slots', []))
|
| 1186 |
+
unassigned_committed_predecessors = 0
|
| 1187 |
+
for position in positions.tolist():
|
| 1188 |
+
old_slot = int(current_to_prev[position]) if position < len(current_to_prev) else -1
|
| 1189 |
+
if old_slot not in prev_committed_slots:
|
| 1190 |
+
continue
|
| 1191 |
+
if old_slot >= len(prev_word_ids_array) or int(prev_word_ids_array[old_slot]) < 0:
|
| 1192 |
+
unassigned_committed_predecessors += 1
|
| 1193 |
+
if unassigned_committed_predecessors:
|
| 1194 |
+
decision['mapping_reliable'] = False
|
| 1195 |
+
decision['reliable'] = False
|
| 1196 |
+
decision['mapping_status'] = 'lineage_broken_unassigned_committed_slot'
|
| 1197 |
+
legacy_emit = completed and not has_old_committed_slot
|
| 1198 |
+
mixed_merge = bool(
|
| 1199 |
+
merge
|
| 1200 |
+
and predecessor_committed
|
| 1201 |
+
and any(predecessor_committed)
|
| 1202 |
+
and not all(predecessor_committed)
|
| 1203 |
+
)
|
| 1204 |
+
partial_word_completed = bool(
|
| 1205 |
+
completed
|
| 1206 |
+
and selected_prev is not None
|
| 1207 |
+
and not inherited_state.get('committed', False)
|
| 1208 |
+
and not merge
|
| 1209 |
+
and bool(decision['reliable'])
|
| 1210 |
+
)
|
| 1211 |
+
# A3-Lite is intentionally minimal: reproduce the legacy mask exactly,
|
| 1212 |
+
# then add one event for a completed mixed committed/partial merge or
|
| 1213 |
+
# for a reliably inherited partial word that has now become complete.
|
| 1214 |
+
emit_event = bool(legacy_emit or (completed and mixed_merge) or partial_word_completed)
|
| 1215 |
+
committed = bool(completed or inherited_state.get('committed', False))
|
| 1216 |
+
|
| 1217 |
+
if selected_prev is not None and not (completed and mixed_merge):
|
| 1218 |
+
logical_id = int(inherited_state['logical_word_id'])
|
| 1219 |
+
else:
|
| 1220 |
+
logical_id = next_logical_id
|
| 1221 |
+
next_logical_id += 1
|
| 1222 |
+
|
| 1223 |
+
if completed and mixed_merge:
|
| 1224 |
+
event_reason = 'mixed_committed_partial_merge_completed'
|
| 1225 |
+
elif mixed_merge:
|
| 1226 |
+
event_reason = 'mixed_committed_partial_merge_partial'
|
| 1227 |
+
elif split:
|
| 1228 |
+
event_reason = 'split_completed' if completed else 'split_partial'
|
| 1229 |
+
elif merge:
|
| 1230 |
+
if completed:
|
| 1231 |
+
event_reason = 'merge_completed' if emit_event else 'merge_completed_legacy_suppressed'
|
| 1232 |
+
else:
|
| 1233 |
+
event_reason = 'merge_partial'
|
| 1234 |
+
elif unassigned_committed_predecessors and completed and not emit_event:
|
| 1235 |
+
event_reason = 'lineage_broken_completed_legacy_suppressed'
|
| 1236 |
+
elif selected_prev is not None and inherited_state.get('committed', False):
|
| 1237 |
+
event_reason = 'persistent_committed'
|
| 1238 |
+
elif selected_prev is not None:
|
| 1239 |
+
event_reason = 'partial_became_completed' if completed else 'partial_persistent'
|
| 1240 |
+
elif predecessor_ids:
|
| 1241 |
+
event_reason = 'ambiguous_completed' if completed else 'ambiguous_partial'
|
| 1242 |
+
else:
|
| 1243 |
+
event_reason = 'newly_completed' if completed else 'new_partial'
|
| 1244 |
+
|
| 1245 |
+
state_event_id = -1
|
| 1246 |
+
if emit_event:
|
| 1247 |
+
new_mask[positions] = 1.0
|
| 1248 |
+
state_event_id = next_event_id
|
| 1249 |
+
next_event_id += 1
|
| 1250 |
+
metadata = _commit_word_metadata(word_timestamps, word_idx)
|
| 1251 |
+
next_word_states[int(word_idx)] = {
|
| 1252 |
+
'logical_word_id': int(logical_id),
|
| 1253 |
+
'committed': bool(committed),
|
| 1254 |
+
'state_event_id': int(state_event_id if state_event_id >= 0 else inherited_state.get('state_event_id', -1)),
|
| 1255 |
+
'metadata': metadata,
|
| 1256 |
+
}
|
| 1257 |
+
word_event_rows.append({
|
| 1258 |
+
'current_word_id': int(word_idx),
|
| 1259 |
+
'logical_word_id': int(logical_id),
|
| 1260 |
+
'state_event_id': int(state_event_id),
|
| 1261 |
+
'completed': bool(completed),
|
| 1262 |
+
'emit_state_event': bool(emit_event),
|
| 1263 |
+
'event_reason': event_reason,
|
| 1264 |
+
'mapping_status': decision['mapping_status'],
|
| 1265 |
+
'mapping_reliable': bool(decision['reliable']),
|
| 1266 |
+
'selected_prev_word_id': selected_prev,
|
| 1267 |
+
'predecessor_word_ids': predecessor_ids,
|
| 1268 |
+
'predecessor_committed': predecessor_committed,
|
| 1269 |
+
'vote_counts': decision['vote_counts'],
|
| 1270 |
+
'split_competitor_count': int(decision['split_competitor_count']),
|
| 1271 |
+
'text': metadata['text'],
|
| 1272 |
+
'text_equal': bool(decision['text_equal']),
|
| 1273 |
+
'time_iou': float(decision['time_iou']),
|
| 1274 |
+
'unassigned_committed_predecessor_slots': int(unassigned_committed_predecessors),
|
| 1275 |
+
})
|
| 1276 |
+
|
| 1277 |
+
committed_slots = sorted(np.flatnonzero(cumulative > 0).astype(int).tolist())
|
| 1278 |
+
new_slots = sorted(np.flatnonzero(new_mask > 0).astype(int).tolist())
|
| 1279 |
+
diagnostics = {
|
| 1280 |
+
'mapped_old_slots': mapped_old_slots,
|
| 1281 |
+
'new_slots': new_slots,
|
| 1282 |
+
'dropped_or_revised_slots': dropped_or_revised,
|
| 1283 |
+
'word_level_state_events': word_event_rows,
|
| 1284 |
+
'state_event_semantics': 'word_predecessor_one_to_one_v1',
|
| 1285 |
+
}
|
| 1286 |
+
next_state = {
|
| 1287 |
+
'top_phone_ids': list(pcn['top_phone_ids']),
|
| 1288 |
+
'pcn_word_id': np.asarray(pcn_word_id, dtype=np.int32).tolist(),
|
| 1289 |
+
'committed_slots': committed_slots,
|
| 1290 |
+
'word_states': next_word_states,
|
| 1291 |
+
'next_logical_word_id': int(next_logical_id),
|
| 1292 |
+
'next_state_event_id': int(next_event_id),
|
| 1293 |
+
}
|
| 1294 |
+
return cumulative.astype(np.float32), new_mask.astype(np.float32), current_to_prev, diagnostics, next_state
|
| 1295 |
+
|
| 1296 |
+
|
| 1297 |
+
def acoustic_distribution_for_frames(frame_probs, phone_to_frame_id, phn_dict, phone_dim):
|
| 1298 |
+
out = np.zeros((phone_dim,), dtype=np.float32)
|
| 1299 |
+
if frame_probs.size == 0:
|
| 1300 |
+
return out
|
| 1301 |
+
mean_probs = frame_probs.mean(axis=0)
|
| 1302 |
+
for phone, phone_idx in phn_dict.items():
|
| 1303 |
+
frame_idx = phone_to_frame_id.get(phone)
|
| 1304 |
+
if frame_idx is not None and frame_idx < mean_probs.shape[0]:
|
| 1305 |
+
out[int(phone_idx)] = float(mean_probs[frame_idx])
|
| 1306 |
+
if out.sum() > 0:
|
| 1307 |
+
out /= out.sum()
|
| 1308 |
+
return out
|
| 1309 |
+
|
| 1310 |
+
|
| 1311 |
+
def build_acoustic_evidence(item, cn_post, top_phone_ids, phone_to_frame_id, phn_dict, audio_end):
|
| 1312 |
+
phone_dim = cn_post.shape[-1]
|
| 1313 |
+
acoustic_post = np.zeros_like(cn_post, dtype=np.float32)
|
| 1314 |
+
acoustic_stats = np.zeros((cn_post.shape[0], 4), dtype=np.float32)
|
| 1315 |
+
kept_indices, kept_probs = select_visible_frames(item['probs'], item['keep_mask'], audio_end, item['frame_step'])
|
| 1316 |
+
alignable = [
|
| 1317 |
+
(slot_idx, phone_idx)
|
| 1318 |
+
for slot_idx, phone_idx in enumerate(top_phone_ids)
|
| 1319 |
+
if phone_idx is not None
|
| 1320 |
+
]
|
| 1321 |
+
if kept_probs.shape[0] < len(alignable) or not alignable:
|
| 1322 |
+
for slot_idx in range(cn_post.shape[0]):
|
| 1323 |
+
acoustic_stats[slot_idx, 3] = js_divergence(cn_post[slot_idx], acoustic_post[slot_idx])
|
| 1324 |
+
return acoustic_post, acoustic_stats, 0
|
| 1325 |
+
|
| 1326 |
+
id_to_phone = {idx: phone for phone, idx in phn_dict.items()}
|
| 1327 |
+
frame_phone_ids = [phone_to_frame_id[id_to_phone[phone_idx]] for _, phone_idx in alignable]
|
| 1328 |
+
try:
|
| 1329 |
+
path = monotonic_align(-np.log(np.clip(kept_probs, EPS, None)), frame_phone_ids)
|
| 1330 |
+
except Exception:
|
| 1331 |
+
for slot_idx in range(cn_post.shape[0]):
|
| 1332 |
+
acoustic_stats[slot_idx, 3] = js_divergence(cn_post[slot_idx], acoustic_post[slot_idx])
|
| 1333 |
+
return acoustic_post, acoustic_stats, 0
|
| 1334 |
+
|
| 1335 |
+
for local_idx, (slot_idx, _) in enumerate(alignable):
|
| 1336 |
+
tok_frames = kept_indices[path == local_idx]
|
| 1337 |
+
if tok_frames.size == 0:
|
| 1338 |
+
acoustic_stats[slot_idx, 3] = js_divergence(cn_post[slot_idx], acoustic_post[slot_idx])
|
| 1339 |
+
continue
|
| 1340 |
+
dist = acoustic_distribution_for_frames(
|
| 1341 |
+
item['probs'][tok_frames],
|
| 1342 |
+
phone_to_frame_id,
|
| 1343 |
+
phn_dict,
|
| 1344 |
+
phone_dim,
|
| 1345 |
+
)
|
| 1346 |
+
acoustic_post[slot_idx] = dist
|
| 1347 |
+
non_eps = dist[:-1]
|
| 1348 |
+
_, margin = top_margin(non_eps)
|
| 1349 |
+
duration = float(tok_frames.size * item['frame_step'])
|
| 1350 |
+
acoustic_stats[slot_idx] = np.array(
|
| 1351 |
+
[
|
| 1352 |
+
entropy_np(dist),
|
| 1353 |
+
margin,
|
| 1354 |
+
duration,
|
| 1355 |
+
js_divergence(cn_post[slot_idx], dist),
|
| 1356 |
+
],
|
| 1357 |
+
dtype=np.float32,
|
| 1358 |
+
)
|
| 1359 |
+
return acoustic_post, acoustic_stats, int(kept_probs.shape[0])
|
| 1360 |
+
|
| 1361 |
+
|
| 1362 |
+
def compute_prosody(audio, sample_rate, audio_end, word_count, phone_count):
|
| 1363 |
+
audio = np.asarray(audio, dtype=np.float32)
|
| 1364 |
+
duration = float(max(audio_end, EPS))
|
| 1365 |
+
if audio.size == 0:
|
| 1366 |
+
return np.zeros((14,), dtype=np.float32)
|
| 1367 |
+
hop_length = max(int(0.01 * sample_rate), 1)
|
| 1368 |
+
frame_length = max(int(0.025 * sample_rate), hop_length)
|
| 1369 |
+
rms = librosa.feature.rms(y=audio, frame_length=frame_length, hop_length=hop_length)[0]
|
| 1370 |
+
log_energy = np.log(np.clip(rms, EPS, None))
|
| 1371 |
+
energy_threshold = np.percentile(rms, 20) if rms.size else 0.0
|
| 1372 |
+
silence = rms <= max(energy_threshold, EPS)
|
| 1373 |
+
silence_ratio = float(np.mean(silence)) if silence.size else 0.0
|
| 1374 |
+
pause_count, longest_pause = count_pauses(silence, hop_length / sample_rate)
|
| 1375 |
+
try:
|
| 1376 |
+
f0, voiced_flag, voiced_prob = librosa.pyin(
|
| 1377 |
+
audio,
|
| 1378 |
+
fmin=50,
|
| 1379 |
+
fmax=500,
|
| 1380 |
+
sr=sample_rate,
|
| 1381 |
+
frame_length=frame_length,
|
| 1382 |
+
hop_length=hop_length,
|
| 1383 |
+
)
|
| 1384 |
+
voiced = np.isfinite(f0)
|
| 1385 |
+
f0_values = f0[voiced]
|
| 1386 |
+
voiced_prob_mean = float(np.nanmean(voiced_prob)) if voiced_prob is not None else float(np.mean(voiced))
|
| 1387 |
+
except Exception:
|
| 1388 |
+
f0_values = np.array([], dtype=np.float32)
|
| 1389 |
+
voiced = np.zeros_like(rms, dtype=bool)
|
| 1390 |
+
voiced_prob_mean = 0.0
|
| 1391 |
+
f0_mean = float(np.mean(f0_values)) if f0_values.size else 0.0
|
| 1392 |
+
f0_std = float(np.std(f0_values)) if f0_values.size else 0.0
|
| 1393 |
+
f0_slope = slope(f0_values)
|
| 1394 |
+
energy_mean = float(np.mean(log_energy)) if log_energy.size else 0.0
|
| 1395 |
+
energy_std = float(np.std(log_energy)) if log_energy.size else 0.0
|
| 1396 |
+
energy_slope = slope(log_energy)
|
| 1397 |
+
voiced_duration = max(float(np.mean(voiced)) * duration, EPS) if voiced.size else EPS
|
| 1398 |
+
return np.array(
|
| 1399 |
+
[
|
| 1400 |
+
duration,
|
| 1401 |
+
f0_mean,
|
| 1402 |
+
f0_std,
|
| 1403 |
+
f0_slope,
|
| 1404 |
+
voiced_prob_mean,
|
| 1405 |
+
energy_mean,
|
| 1406 |
+
energy_std,
|
| 1407 |
+
energy_slope,
|
| 1408 |
+
silence_ratio,
|
| 1409 |
+
float(pause_count),
|
| 1410 |
+
float(longest_pause),
|
| 1411 |
+
float(word_count) / duration,
|
| 1412 |
+
float(phone_count) / duration,
|
| 1413 |
+
float(phone_count) / voiced_duration,
|
| 1414 |
+
],
|
| 1415 |
+
dtype=np.float32,
|
| 1416 |
+
)
|
| 1417 |
+
|
| 1418 |
+
|
| 1419 |
+
def slot_prosody_feature_names():
|
| 1420 |
+
return [
|
| 1421 |
+
'slot_duration',
|
| 1422 |
+
'slot_log_energy_mean',
|
| 1423 |
+
'slot_log_energy_std',
|
| 1424 |
+
'slot_log_energy_max',
|
| 1425 |
+
'slot_f0_mean',
|
| 1426 |
+
'slot_f0_std',
|
| 1427 |
+
'slot_f0_max',
|
| 1428 |
+
'slot_voiced_ratio',
|
| 1429 |
+
'slot_position_in_word',
|
| 1430 |
+
'word_phone_count',
|
| 1431 |
+
'energy_relative_to_word_mean',
|
| 1432 |
+
'duration_relative_to_word_mean',
|
| 1433 |
+
'f0_relative_to_word_mean',
|
| 1434 |
+
'is_vowel',
|
| 1435 |
+
'lexical_stress_0',
|
| 1436 |
+
'lexical_stress_1',
|
| 1437 |
+
'lexical_stress_2',
|
| 1438 |
+
]
|
| 1439 |
+
|
| 1440 |
+
|
| 1441 |
+
def compute_slot_prosody(audio, sample_rate, slot_times, pcn_word_id, top_phone_ids, phn_dict):
|
| 1442 |
+
feature_names = slot_prosody_feature_names()
|
| 1443 |
+
slot_count = len(top_phone_ids)
|
| 1444 |
+
out = np.zeros((slot_count, len(feature_names)), dtype=np.float32)
|
| 1445 |
+
if slot_count <= 0:
|
| 1446 |
+
return out
|
| 1447 |
+
audio = np.asarray(audio, dtype=np.float32)
|
| 1448 |
+
id_to_phone = {int(idx): phone for phone, idx in phn_dict.items()}
|
| 1449 |
+
hop_length = max(int(0.01 * sample_rate), 1)
|
| 1450 |
+
frame_length = max(int(0.025 * sample_rate), hop_length)
|
| 1451 |
+
if audio.size:
|
| 1452 |
+
rms = librosa.feature.rms(y=audio, frame_length=frame_length, hop_length=hop_length)[0]
|
| 1453 |
+
log_energy = np.log(np.clip(rms, EPS, None))
|
| 1454 |
+
frame_times = librosa.frames_to_time(np.arange(rms.shape[0]), sr=sample_rate, hop_length=hop_length)
|
| 1455 |
+
else:
|
| 1456 |
+
log_energy = np.zeros((0,), dtype=np.float32)
|
| 1457 |
+
frame_times = np.zeros((0,), dtype=np.float32)
|
| 1458 |
+
try:
|
| 1459 |
+
f0, _, _ = librosa.pyin(
|
| 1460 |
+
audio,
|
| 1461 |
+
fmin=50,
|
| 1462 |
+
fmax=500,
|
| 1463 |
+
sr=sample_rate,
|
| 1464 |
+
frame_length=frame_length,
|
| 1465 |
+
hop_length=hop_length,
|
| 1466 |
+
)
|
| 1467 |
+
except Exception:
|
| 1468 |
+
f0 = np.zeros_like(log_energy, dtype=np.float32) * np.nan
|
| 1469 |
+
if f0 is None:
|
| 1470 |
+
f0 = np.zeros_like(log_energy, dtype=np.float32) * np.nan
|
| 1471 |
+
f0 = np.asarray(f0, dtype=np.float32)
|
| 1472 |
+
common_frames = min(frame_times.shape[0], log_energy.shape[0], f0.shape[0])
|
| 1473 |
+
frame_times = frame_times[:common_frames]
|
| 1474 |
+
log_energy = log_energy[:common_frames]
|
| 1475 |
+
f0 = f0[:common_frames]
|
| 1476 |
+
|
| 1477 |
+
durations = np.zeros((slot_count,), dtype=np.float32)
|
| 1478 |
+
energy_means = np.zeros((slot_count,), dtype=np.float32)
|
| 1479 |
+
f0_means = np.zeros((slot_count,), dtype=np.float32)
|
| 1480 |
+
pcn_word_id = np.asarray(pcn_word_id, dtype=np.int32)
|
| 1481 |
+
for slot_idx in range(slot_count):
|
| 1482 |
+
if slot_idx < len(slot_times) and slot_times[slot_idx] is not None:
|
| 1483 |
+
start, end = slot_times[slot_idx]
|
| 1484 |
+
start = float(start)
|
| 1485 |
+
end = float(max(end, start))
|
| 1486 |
+
else:
|
| 1487 |
+
start = 0.0
|
| 1488 |
+
end = 0.0
|
| 1489 |
+
durations[slot_idx] = max(end - start, 0.0)
|
| 1490 |
+
frame_mask = (frame_times >= start) & (frame_times <= end) if frame_times.size else np.zeros((0,), dtype=bool)
|
| 1491 |
+
energy_values = log_energy[frame_mask]
|
| 1492 |
+
f0_values = f0[frame_mask]
|
| 1493 |
+
f0_values = f0_values[np.isfinite(f0_values)]
|
| 1494 |
+
if energy_values.size:
|
| 1495 |
+
out[slot_idx, 1] = float(np.mean(energy_values))
|
| 1496 |
+
out[slot_idx, 2] = float(np.std(energy_values))
|
| 1497 |
+
out[slot_idx, 3] = float(np.max(energy_values))
|
| 1498 |
+
energy_means[slot_idx] = out[slot_idx, 1]
|
| 1499 |
+
if f0_values.size:
|
| 1500 |
+
out[slot_idx, 4] = float(np.mean(f0_values))
|
| 1501 |
+
out[slot_idx, 5] = float(np.std(f0_values))
|
| 1502 |
+
out[slot_idx, 6] = float(np.max(f0_values))
|
| 1503 |
+
out[slot_idx, 7] = float(f0_values.size / max(frame_mask.sum(), 1))
|
| 1504 |
+
f0_means[slot_idx] = out[slot_idx, 4]
|
| 1505 |
+
out[slot_idx, 0] = durations[slot_idx]
|
| 1506 |
+
word_idx = int(pcn_word_id[slot_idx]) if slot_idx < pcn_word_id.shape[0] else -1
|
| 1507 |
+
same_word = np.flatnonzero(pcn_word_id == word_idx) if word_idx >= 0 else np.asarray([slot_idx], dtype=np.int64)
|
| 1508 |
+
if same_word.size:
|
| 1509 |
+
position = np.flatnonzero(same_word == slot_idx)
|
| 1510 |
+
out[slot_idx, 8] = float(position[0] / max(same_word.size - 1, 1)) if position.size else 0.0
|
| 1511 |
+
out[slot_idx, 9] = float(same_word.size)
|
| 1512 |
+
phone_idx = top_phone_ids[slot_idx] if slot_idx < len(top_phone_ids) else None
|
| 1513 |
+
phone = id_to_phone.get(int(phone_idx), '') if phone_idx is not None else ''
|
| 1514 |
+
out[slot_idx, 13] = 1.0 if phone[:1].upper() in {'A', 'E', 'I', 'O', 'U'} else 0.0
|
| 1515 |
+
|
| 1516 |
+
for slot_idx in range(slot_count):
|
| 1517 |
+
word_idx = int(pcn_word_id[slot_idx]) if slot_idx < pcn_word_id.shape[0] else -1
|
| 1518 |
+
same_word = np.flatnonzero(pcn_word_id == word_idx) if word_idx >= 0 else np.asarray([slot_idx], dtype=np.int64)
|
| 1519 |
+
if same_word.size:
|
| 1520 |
+
word_energy = float(np.mean(energy_means[same_word]))
|
| 1521 |
+
word_duration = float(np.mean(durations[same_word]))
|
| 1522 |
+
word_f0 = float(np.mean(f0_means[same_word]))
|
| 1523 |
+
out[slot_idx, 10] = out[slot_idx, 1] - word_energy
|
| 1524 |
+
out[slot_idx, 11] = durations[slot_idx] / max(word_duration, EPS)
|
| 1525 |
+
out[slot_idx, 12] = out[slot_idx, 4] - word_f0
|
| 1526 |
+
return out.astype(np.float32)
|
| 1527 |
+
|
| 1528 |
+
|
| 1529 |
+
def slope(values):
|
| 1530 |
+
values = np.asarray(values, dtype=np.float32)
|
| 1531 |
+
if values.size < 2:
|
| 1532 |
+
return 0.0
|
| 1533 |
+
x = np.arange(values.size, dtype=np.float32)
|
| 1534 |
+
x = x - x.mean()
|
| 1535 |
+
y = values - values.mean()
|
| 1536 |
+
denom = float(np.sum(x * x))
|
| 1537 |
+
if denom <= EPS:
|
| 1538 |
+
return 0.0
|
| 1539 |
+
return float(np.sum(x * y) / denom)
|
| 1540 |
+
|
| 1541 |
+
|
| 1542 |
+
def count_pauses(silence_mask, frame_step):
|
| 1543 |
+
pause_count = 0
|
| 1544 |
+
longest = 0.0
|
| 1545 |
+
cur = 0
|
| 1546 |
+
for value in silence_mask.tolist():
|
| 1547 |
+
if value:
|
| 1548 |
+
cur += 1
|
| 1549 |
+
elif cur > 0:
|
| 1550 |
+
pause_count += 1
|
| 1551 |
+
longest = max(longest, cur * frame_step)
|
| 1552 |
+
cur = 0
|
| 1553 |
+
if cur > 0:
|
| 1554 |
+
pause_count += 1
|
| 1555 |
+
longest = max(longest, cur * frame_step)
|
| 1556 |
+
return pause_count, longest
|
streampa/infer.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import json
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from .pipeline import StreamPAPipeline
|
| 5 |
+
|
| 6 |
+
def main():
|
| 7 |
+
p=argparse.ArgumentParser(description='Frozen StreamPA raw-WAV inference')
|
| 8 |
+
p.add_argument('--audio',required=True)
|
| 9 |
+
p.add_argument('--bundle-dir',required=True)
|
| 10 |
+
p.add_argument('--device',default='cpu')
|
| 11 |
+
p.add_argument('--threads',type=int,default=2)
|
| 12 |
+
p.add_argument('--output',required=True)
|
| 13 |
+
a=p.parse_args()
|
| 14 |
+
result=StreamPAPipeline(a.bundle_dir,a.device,a.threads).score_file(a.audio)
|
| 15 |
+
dest=Path(a.output); dest.parent.mkdir(parents=True,exist_ok=True)
|
| 16 |
+
with dest.open('x',encoding='utf-8') as f: json.dump(result,f,indent=2,allow_nan=False)
|
| 17 |
+
print(json.dumps(dict(output=str(dest),prefixes=len(result['prefixes']),final_status=result['final']['status'])))
|
| 18 |
+
|
| 19 |
+
if __name__=='__main__': main()
|
streampa/pipeline.py
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Reference-free deployment of the frozen StreamPA scorer and frontends."""
|
| 2 |
+
import hashlib
|
| 3 |
+
import json
|
| 4 |
+
import os
|
| 5 |
+
import time
|
| 6 |
+
from itertools import groupby
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
import soundfile as sf
|
| 11 |
+
import torch
|
| 12 |
+
from safetensors.torch import load_file
|
| 13 |
+
from transformers import Wav2Vec2CTCTokenizer, Wav2Vec2FeatureExtractor, Wav2Vec2Processor
|
| 14 |
+
|
| 15 |
+
from . import frontend as fe
|
| 16 |
+
from .charsiu_model import Wav2Vec2ForFrameClassification
|
| 17 |
+
from .streaming_pcn_gopt import PCNStreamingScorer
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def read_json(path):
|
| 21 |
+
return json.loads(Path(path).read_text(encoding='utf-8-sig'))
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def load_scorer(bundle, device='cpu'):
|
| 25 |
+
bundle = Path(bundle)
|
| 26 |
+
c = read_json(bundle / 'scorer/config.json')
|
| 27 |
+
a = c['args']
|
| 28 |
+
model = PCNStreamingScorer(phone_dim=c['phone_dim'], seq_len=c['seq_len'],
|
| 29 |
+
prosody_dim=c['prosody_dim'], embed_dim=a['embed_dim'], num_heads=a['heads'],
|
| 30 |
+
depth=a['depth'], gru_dim=a['gru_dim'], main_context_tokens=a['main_context_tokens'],
|
| 31 |
+
utt_pooling_head=c['utt_pooling_head'], fusion_mode=c['fusion_mode'],
|
| 32 |
+
slot_prosody_dim=c['slot_prosody_dim'], stress_branch=c['stress_branch'],
|
| 33 |
+
stress_grad_scale=c['stress_grad_scale'])
|
| 34 |
+
if c['preserve_unused_legacy_utt_head']:
|
| 35 |
+
model.utt_head = torch.nn.Sequential(torch.nn.LayerNorm(a['gru_dim']), torch.nn.Linear(a['gru_dim'], 5))
|
| 36 |
+
weights = load_file(str(bundle / 'scorer/model.safetensors'), device='cpu')
|
| 37 |
+
model.load_state_dict(weights, strict=True)
|
| 38 |
+
return model.to(device).eval(), c
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
class CharsiuFrontend:
|
| 42 |
+
def __init__(self, bundle, device, min_sil_frames):
|
| 43 |
+
self.device = device
|
| 44 |
+
self.min_sil_frames = min_sil_frames
|
| 45 |
+
tokenizer = Wav2Vec2CTCTokenizer.from_pretrained(str(bundle / 'charsiu/tokenizer'), local_files_only=True)
|
| 46 |
+
feature_extractor = Wav2Vec2FeatureExtractor(feature_size=1, sampling_rate=16000,
|
| 47 |
+
padding_value=0.0, do_normalize=True, return_attention_mask=False)
|
| 48 |
+
self.processor = Wav2Vec2Processor(feature_extractor=feature_extractor, tokenizer=tokenizer)
|
| 49 |
+
self.model = Wav2Vec2ForFrameClassification.from_pretrained(str(bundle / 'charsiu/model'),
|
| 50 |
+
local_files_only=True).to(device).eval()
|
| 51 |
+
self.phone_to_id = {}
|
| 52 |
+
for label, idx in tokenizer.get_vocab().items():
|
| 53 |
+
phone = fe.normalize_phone(label)
|
| 54 |
+
if phone and phone not in self.phone_to_id:
|
| 55 |
+
self.phone_to_id[phone] = int(idx)
|
| 56 |
+
self.sil_idx = tokenizer.convert_tokens_to_ids('[SIL]')
|
| 57 |
+
|
| 58 |
+
@torch.inference_mode()
|
| 59 |
+
def __call__(self, audio, audio_end):
|
| 60 |
+
if len(audio) > round(audio_end * 16000):
|
| 61 |
+
raise AssertionError('Charsiu received audio beyond the current boundary')
|
| 62 |
+
# Exact official audio_preprocess: Wav2Vec2Processor normalization, no text.
|
| 63 |
+
x = self.processor(audio, sampling_rate=16000, return_tensors='pt').input_values.to(self.device)
|
| 64 |
+
probs = fe.softmax_np_matrix(self.model(input_values=x).logits[0].cpu().numpy())
|
| 65 |
+
pred = probs.argmax(-1)
|
| 66 |
+
silence = []
|
| 67 |
+
for key, group in groupby(pred):
|
| 68 |
+
group = list(group)
|
| 69 |
+
silence.extend([-1] * len(group) if key == self.sil_idx and len(group) < self.min_sil_frames else group)
|
| 70 |
+
keep = np.asarray(silence) != self.sil_idx
|
| 71 |
+
if not keep.any(): keep[:] = True
|
| 72 |
+
return dict(probs=probs, keep_mask=keep, frame_step=len(audio)/16000/len(probs))
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def filter_hypotheses(rows, mapper, config):
|
| 76 |
+
"""Keep the historical repetition policy; no reference-length test."""
|
| 77 |
+
kept, rejected = [], []
|
| 78 |
+
for row in rows:
|
| 79 |
+
phones, _, sources = mapper.words_to_phone_sequence(row['words'])
|
| 80 |
+
strict = len(row['words']) > config['strict_repeat_word_trigger'] or len(phones) > config['strict_repeat_phone_trigger']
|
| 81 |
+
repeat = fe.find_repeated_ngram([{'text': w} for w in row['words']],
|
| 82 |
+
min_repeats=config['repeat_ngram_min_repeats'], max_ngram_size=config['repeat_max_ngram_size'],
|
| 83 |
+
strict=strict, min_coverage=config['repeat_ngram_coverage'], dominant_token_ratio=config['repeat_token_ratio'])
|
| 84 |
+
if repeat is not None:
|
| 85 |
+
rejected.append(dict(rank=row['rank'], reason='repetitive_asr_hypothesis', details=repeat))
|
| 86 |
+
elif sources.get('fallback_phone', 0) or sources.get('unmapped', 0):
|
| 87 |
+
rejected.append(dict(rank=row['rank'], reason='g2p_unavailable_for_word', sources=sources))
|
| 88 |
+
elif not row['words'] or not phones:
|
| 89 |
+
rejected.append(dict(rank=row['rank'], reason='empty_hypothesis'))
|
| 90 |
+
else:
|
| 91 |
+
kept.append(dict(row, asr_phone_count=len(phones), phone_source_counts=sources))
|
| 92 |
+
return kept, rejected
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
class StreamPAPipeline:
|
| 96 |
+
def __init__(self, bundle_dir, device='cpu', threads=2):
|
| 97 |
+
self.bundle_dir = Path(bundle_dir).resolve()
|
| 98 |
+
if device not in ('cpu', 'cuda', 'cuda:0'):
|
| 99 |
+
raise ValueError('Select cpu or one externally isolated CUDA device')
|
| 100 |
+
if device.startswith('cuda') and not torch.cuda.is_available():
|
| 101 |
+
raise RuntimeError('CUDA is not available')
|
| 102 |
+
self.device = device
|
| 103 |
+
torch.set_num_threads(threads)
|
| 104 |
+
torch.manual_seed(1337)
|
| 105 |
+
torch.backends.cuda.matmul.allow_tf32 = False
|
| 106 |
+
self.assets = read_json(self.bundle_dir / 'scorer/inference_assets.json')
|
| 107 |
+
if self.assets['sample_rate'] != 16000 or self.assets['commit_rule'] != 'legacy':
|
| 108 |
+
raise ValueError('Bundle is not the frozen 16-kHz legacy-commit configuration')
|
| 109 |
+
self.model, self.config = load_scorer(self.bundle_dir, device)
|
| 110 |
+
self.manifest = read_json(self.bundle_dir / 'model_manifest.json')
|
| 111 |
+
os.environ['NLTK_DATA'] = str(self.bundle_dir / 'assets/nltk_data')
|
| 112 |
+
import nltk
|
| 113 |
+
nltk.data.path[:] = [os.environ['NLTK_DATA']]
|
| 114 |
+
self.phn_dict = read_json(self.bundle_dir / 'assets/phn_dict.json')
|
| 115 |
+
self.mapper = fe.PhoneMapper(read_json(self.bundle_dir / 'assets/pronunciation_lexicon.json'), self.phn_dict)
|
| 116 |
+
if self.mapper.g2p is None:
|
| 117 |
+
raise RuntimeError('G2P runtime resources missing. Run scripts/setup_assets.py first.')
|
| 118 |
+
self.charsiu = CharsiuFrontend(self.bundle_dir, device, self.assets['min_sil_frames'])
|
| 119 |
+
missing = set(self.phn_dict) - set(self.charsiu.phone_to_id)
|
| 120 |
+
if missing:
|
| 121 |
+
raise RuntimeError(f'Charsiu label mapping missing: {sorted(missing)}')
|
| 122 |
+
self.asr = fe.WhisperNBestGenerator(str(self.bundle_dir / 'whisper'), self.assets['language'],
|
| 123 |
+
device, self.assets['nbest'], self.assets['beam_size'], self.assets['max_new_tokens'],
|
| 124 |
+
self.assets['no_repeat_ngram_size'])
|
| 125 |
+
|
| 126 |
+
@classmethod
|
| 127 |
+
def from_pretrained(cls, repo_id='faeea/StreamPA', revision=None, device='cpu', **kwargs):
|
| 128 |
+
if Path(repo_id).is_dir():
|
| 129 |
+
return cls(repo_id, device=device, **kwargs)
|
| 130 |
+
if revision is None:
|
| 131 |
+
raise ValueError('Specify a fixed Hub commit or release tag')
|
| 132 |
+
from huggingface_hub import snapshot_download
|
| 133 |
+
path = snapshot_download(repo_id, revision=revision)
|
| 134 |
+
# Optional assets are deliberately fetched only by the explicit setup script.
|
| 135 |
+
return cls(path, device=device, **kwargs)
|
| 136 |
+
|
| 137 |
+
def create_session(self):
|
| 138 |
+
return StreamPASession(self)
|
| 139 |
+
|
| 140 |
+
def score_file(self, audio_path, block_samples=4096):
|
| 141 |
+
session = self.create_session()
|
| 142 |
+
rows = []
|
| 143 |
+
with sf.SoundFile(audio_path) as f:
|
| 144 |
+
if f.samplerate != self.assets['sample_rate'] or f.channels != 1:
|
| 145 |
+
raise ValueError('Input must be mono 16000-Hz WAV; convert before starting a session')
|
| 146 |
+
while True:
|
| 147 |
+
block = f.read(block_samples, dtype='float32')
|
| 148 |
+
if len(block) == 0: break
|
| 149 |
+
rows.extend(session.append(block))
|
| 150 |
+
rows.append(session.finish())
|
| 151 |
+
return dict(model='StreamPA', seed=1337, prefixes=rows, final=rows[-1])
|
| 152 |
+
|
| 153 |
+
def make_batch(self, example):
|
| 154 |
+
n = len(example['cn_post']); limit = self.config['seq_len']
|
| 155 |
+
if n > limit: raise ValueError(f'{n} PCN slots exceeds supported {limit}')
|
| 156 |
+
batch = {}
|
| 157 |
+
for key in ['cn_post','cn_stats','acoustic_post','acoustic_stats','slot_prosody',
|
| 158 |
+
'pcn_word_id','cumulative_commit_mask','new_commit_mask']:
|
| 159 |
+
src = np.asarray(example[key])
|
| 160 |
+
arr = np.full((limit,)+src.shape[1:], -1 if key=='pcn_word_id' else 0, dtype=src.dtype)
|
| 161 |
+
arr[:n] = src
|
| 162 |
+
batch['word_ids' if key=='pcn_word_id' else key] = arr[None]
|
| 163 |
+
batch['prosody'] = example['prosody'][None]
|
| 164 |
+
for key in ['prosody','slot_prosody']:
|
| 165 |
+
mean = np.asarray(self.config[key+'_norm_mean'],np.float32)
|
| 166 |
+
std = np.asarray(self.config[key+'_norm_std'],np.float32)
|
| 167 |
+
batch[key] = (batch[key]-mean)/np.clip(std,1e-6,None)
|
| 168 |
+
batch['visible_len'] = np.asarray([n],np.int64)
|
| 169 |
+
return {k:torch.from_numpy(v).to(self.device) for k,v in batch.items()}
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
class StreamPASession:
|
| 173 |
+
def __init__(self, pipeline):
|
| 174 |
+
self.pipeline = pipeline
|
| 175 |
+
self.reset()
|
| 176 |
+
|
| 177 |
+
def reset(self):
|
| 178 |
+
self.audio = np.empty(0,np.float32)
|
| 179 |
+
self.state = None
|
| 180 |
+
self.commit_state = None
|
| 181 |
+
self.previous_phones = []
|
| 182 |
+
self.next_step = 1
|
| 183 |
+
self.prefix_index = 0
|
| 184 |
+
self.closed = False
|
| 185 |
+
self.last_result = None
|
| 186 |
+
|
| 187 |
+
def append(self, audio_block):
|
| 188 |
+
if self.closed: raise RuntimeError('Session ended; reset before appending another recording')
|
| 189 |
+
block = np.asarray(audio_block,dtype=np.float32)
|
| 190 |
+
if block.ndim != 1 or not np.isfinite(block).all():
|
| 191 |
+
raise ValueError('Audio block must be finite mono samples')
|
| 192 |
+
if (len(self.audio)+len(block))/16000 > self.pipeline.assets['max_audio_sec']:
|
| 193 |
+
raise ValueError('Recording exceeds supported 30-second frontend limit; no audio was appended')
|
| 194 |
+
self.audio = np.concatenate([self.audio,block])
|
| 195 |
+
rows = []
|
| 196 |
+
while True:
|
| 197 |
+
commit = self.next_step * self.pipeline.assets['chunk_sec']
|
| 198 |
+
end_samples = round((commit+self.pipeline.assets['right_context_sec'])*16000)
|
| 199 |
+
if len(self.audio) < end_samples: break
|
| 200 |
+
rows.append(self._step(round(commit*16000),end_samples,False))
|
| 201 |
+
self.next_step += 1
|
| 202 |
+
return rows
|
| 203 |
+
|
| 204 |
+
def finish(self):
|
| 205 |
+
if self.closed: raise RuntimeError('Session already ended')
|
| 206 |
+
self.closed = True
|
| 207 |
+
return self._step(len(self.audio),len(self.audio),True)
|
| 208 |
+
|
| 209 |
+
def current(self):
|
| 210 |
+
return self.last_result
|
| 211 |
+
|
| 212 |
+
@torch.inference_mode()
|
| 213 |
+
def _step(self, commit_samples, end_samples, is_final):
|
| 214 |
+
started = time.perf_counter(); p = self.pipeline
|
| 215 |
+
audio = self.audio[:end_samples].copy()
|
| 216 |
+
assert len(audio) == end_samples <= len(self.audio)
|
| 217 |
+
commit, end = commit_samples/16000, end_samples/16000
|
| 218 |
+
base = dict(prefix_index=self.prefix_index,commit_time=commit,audio_end=end,
|
| 219 |
+
received_audio_end=len(self.audio)/16000,is_final=is_final,
|
| 220 |
+
lookahead_sec=end-commit,model='StreamPA',seed=1337,
|
| 221 |
+
checkpoint_sha256=p.manifest['original_checkpoint_sha256'],
|
| 222 |
+
input_audio_sha256=hashlib.sha256(audio.tobytes()).hexdigest(),
|
| 223 |
+
frontend_received_samples=dict(whisper=0,charsiu=0,prosody=0,pcn=0),
|
| 224 |
+
state_updated=False,new_committed_word_count=0,scores=None)
|
| 225 |
+
self.prefix_index += 1
|
| 226 |
+
def finish(status, **kw):
|
| 227 |
+
self.last_result=dict(base,status=status,wall_time_sec=time.perf_counter()-started,**kw)
|
| 228 |
+
return self.last_result
|
| 229 |
+
if end_samples == 0: return finish('empty_audio')
|
| 230 |
+
if end_samples < 400: return finish('audio_too_short')
|
| 231 |
+
if float(np.max(np.abs(audio))) < 1e-7: return finish('silence')
|
| 232 |
+
stages={}
|
| 233 |
+
t=time.perf_counter()
|
| 234 |
+
base['frontend_received_samples']['whisper']=end_samples
|
| 235 |
+
try: raw = p.asr.generate(audio,16000,end)
|
| 236 |
+
except Exception as exc: return finish('asr_failed',error=str(exc))
|
| 237 |
+
stages['whisper_sec']=time.perf_counter()-t
|
| 238 |
+
hypotheses, rejected = filter_hypotheses(raw,p.mapper,p.assets['filter'])
|
| 239 |
+
if not hypotheses: return finish('no_usable_hypothesis',rejected_hypotheses=rejected,stages=stages)
|
| 240 |
+
t=time.perf_counter()
|
| 241 |
+
try:
|
| 242 |
+
base['frontend_received_samples']['charsiu']=end_samples
|
| 243 |
+
item=p.charsiu(audio,end)
|
| 244 |
+
hypotheses=[fe.align_hypothesis_with_charsiu(item,dict(row),p.mapper,p.phn_dict,p.charsiu.phone_to_id,end) for row in hypotheses]
|
| 245 |
+
failures=[r.get('timestamp_fallback_reason') for r in hypotheses if r.get('timestamp_source')!='charsiu_hypothesis_alignment']
|
| 246 |
+
if failures: return finish('alignment_failed',reasons=failures,stages=stages)
|
| 247 |
+
base['frontend_received_samples']['pcn']=end_samples
|
| 248 |
+
pcn=fe.build_pcn_from_hypotheses(hypotheses,p.mapper,p.phn_dict)
|
| 249 |
+
fe.validate_pcn(pcn)
|
| 250 |
+
except Exception as exc: return finish('pcn_or_alignment_failed',error=str(exc),stages=stages)
|
| 251 |
+
stages['charsiu_alignment_pcn_sec']=time.perf_counter()-t
|
| 252 |
+
n=len(pcn['top_phone_ids'])
|
| 253 |
+
if n>p.config['seq_len']: return finish('unsupported_slot_length',slot_count=n,limit=p.config['seq_len'],stages=stages)
|
| 254 |
+
if n==0: return finish('no_scorable_slots',stages=stages)
|
| 255 |
+
ids=fe.top_hyp_word_ids_for_slots(pcn)
|
| 256 |
+
stats,_=fe.pcn_stats(pcn['cn_post'],pcn['top_phone_ids'],self.previous_phones,pcn['eps_index'])
|
| 257 |
+
acoustic,astats,frames=fe.build_acoustic_evidence(item,pcn['cn_post'],pcn['top_phone_ids'],p.charsiu.phone_to_id,p.phn_dict,end)
|
| 258 |
+
if frames==0: return finish('acoustic_alignment_failed',stages=stages)
|
| 259 |
+
t=time.perf_counter()
|
| 260 |
+
base['frontend_received_samples']['prosody']=end_samples
|
| 261 |
+
prosody=fe.compute_prosody(audio,16000,end,len(hypotheses[0]['words']),sum(x is not None for x in pcn['top_phone_ids']))
|
| 262 |
+
slot_prosody=fe.compute_slot_prosody(audio,16000,pcn['slot_times'],ids,pcn['top_phone_ids'],p.phn_dict)
|
| 263 |
+
stages['prosody_sec']=time.perf_counter()-t
|
| 264 |
+
cumulative,new,mapping,diagnostics,next_commit=fe.build_stateful_commit_masks(self.commit_state,pcn,ids,
|
| 265 |
+
hypotheses[0]['word_timestamps'],commit,end,is_final,commit_rule='legacy')
|
| 266 |
+
example=dict(cn_post=pcn['cn_post'],cn_stats=stats,acoustic_post=acoustic,acoustic_stats=astats,
|
| 267 |
+
prosody=prosody,slot_prosody=slot_prosody,pcn_word_id=ids,cumulative_commit_mask=cumulative,new_commit_mask=new)
|
| 268 |
+
batch=p.make_batch(example)
|
| 269 |
+
if any(not torch.isfinite(v).all() for v in batch.values()): return finish('nonfinite_features',stages=stages)
|
| 270 |
+
t=time.perf_counter()
|
| 271 |
+
before=None if self.state is None else self.state.clone()
|
| 272 |
+
out=p.model(**batch,prev_state=self.state)
|
| 273 |
+
if p.device.startswith('cuda'): torch.cuda.synchronize()
|
| 274 |
+
stages['scorer_sec']=time.perf_counter()-t
|
| 275 |
+
if any(not torch.isfinite(v).all() for v in out.values() if torch.is_tensor(v)):
|
| 276 |
+
return finish('nonfinite_scores',stages=stages)
|
| 277 |
+
count=len(set(int(x) for x in ids[new>0] if x>=0))
|
| 278 |
+
scorer_count=int(out['new_word_mask'].sum().item())
|
| 279 |
+
if scorer_count!=count:
|
| 280 |
+
raise AssertionError('Scorer GRU input count differs from distinct newly committed ASR words')
|
| 281 |
+
if count==0 and before is not None:
|
| 282 |
+
assert torch.equal(before,out['next_state']), 'GRU state changed without a new committed word'
|
| 283 |
+
self.state=out['next_state']
|
| 284 |
+
self.commit_state=next_commit
|
| 285 |
+
self.previous_phones=list(pcn['top_phone_ids'])
|
| 286 |
+
phone=out['phone_score'][0,:n,0].cpu().numpy()
|
| 287 |
+
word=out['word_scores'][0,:n].cpu().numpy()
|
| 288 |
+
utt=out['utt_scores'][0].cpu().numpy()
|
| 289 |
+
word_names=['accuracy','stress','total']
|
| 290 |
+
utt_names=['accuracy','completeness','fluency','prosodic','total']
|
| 291 |
+
slots=[]
|
| 292 |
+
reverse={v:k for k,v in p.phn_dict.items()}
|
| 293 |
+
for i in range(n):
|
| 294 |
+
ph=pcn['top_phone_ids'][i]
|
| 295 |
+
slots.append(dict(slot_index=i,asr_word_id=int(ids[i]),phone=reverse.get(ph,'<eps>'),
|
| 296 |
+
time=pcn['slot_times'][i],phone_network_raw=float(phone[i]),phone_0_2=float(phone[i]*5),
|
| 297 |
+
phone_0_5=float(phone[i]*12.5),word_network_raw=word[i].tolist(),
|
| 298 |
+
word_0_5=(word[i]*2.5).tolist(),is_committed=bool(cumulative[i]),is_new_commit=bool(new[i]),
|
| 299 |
+
valid_phone=ph is not None))
|
| 300 |
+
words=[]
|
| 301 |
+
for wid in sorted(set(int(v) for v in ids if v>=0)):
|
| 302 |
+
pos=np.flatnonzero(ids==wid)
|
| 303 |
+
values=word[pos].mean(0)
|
| 304 |
+
words.append(dict(asr_word_id=wid,text=hypotheses[0]['words'][wid],slot_indices=pos.tolist(),
|
| 305 |
+
scores_0_5=dict(zip(word_names,(values*2.5).tolist())),scores_network_raw=dict(zip(word_names,values.tolist())),
|
| 306 |
+
committed=bool(np.all(cumulative[pos]>0)),new_commit=bool(np.all(new[pos]>0)),
|
| 307 |
+
revisable=True,aggregation='arithmetic mean of visible slots assigned to this current ASR word'))
|
| 308 |
+
base['state_updated']=count>0
|
| 309 |
+
base['new_committed_word_count']=count
|
| 310 |
+
base['scores']=dict(utterance_network_raw=dict(zip(utt_names,utt.tolist())),
|
| 311 |
+
utterance_0_5={k:float(utt[j]*2.5) for j,k in enumerate(utt_names) if k!='completeness'},
|
| 312 |
+
completeness_status='untrained_not_displayed',clipped=False)
|
| 313 |
+
return finish('ok',slots=slots,words=words,visible_len=n,
|
| 314 |
+
cumulative_commit_mask=cumulative.tolist(),new_commit_mask=new.tolist(),mapped_old_slot=mapping.tolist(),
|
| 315 |
+
commit_diagnostics=diagnostics,stages=stages,rejected_hypotheses=rejected,
|
| 316 |
+
scorer_new_word_count=scorer_count,
|
| 317 |
+
state_sha256=hashlib.sha256(self.state.cpu().numpy().tobytes()).hexdigest(),
|
| 318 |
+
hypothesis_count=len(hypotheses))
|
streampa/stream.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import json
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
import soundfile as sf
|
| 5 |
+
from .pipeline import StreamPAPipeline
|
| 6 |
+
|
| 7 |
+
def main():
|
| 8 |
+
p=argparse.ArgumentParser(description='Append raw audio blocks and emit each StreamPA prefix')
|
| 9 |
+
p.add_argument('--audio',required=True)
|
| 10 |
+
p.add_argument('--bundle-dir',required=True)
|
| 11 |
+
p.add_argument('--device',default='cpu')
|
| 12 |
+
p.add_argument('--threads',type=int,default=2)
|
| 13 |
+
p.add_argument('--block-samples',type=int,default=1600)
|
| 14 |
+
p.add_argument('--output',required=True)
|
| 15 |
+
a=p.parse_args()
|
| 16 |
+
session=StreamPAPipeline(a.bundle_dir,a.device,a.threads).create_session()
|
| 17 |
+
dest=Path(a.output); dest.parent.mkdir(parents=True,exist_ok=True)
|
| 18 |
+
with sf.SoundFile(a.audio) as audio, dest.open('x',encoding='utf-8') as f:
|
| 19 |
+
if audio.samplerate!=16000 or audio.channels!=1: raise ValueError('Input must be mono 16000-Hz WAV')
|
| 20 |
+
while True:
|
| 21 |
+
block=audio.read(a.block_samples,dtype='float32')
|
| 22 |
+
if not len(block): break
|
| 23 |
+
for row in session.append(block):
|
| 24 |
+
f.write(json.dumps(row,allow_nan=False)+'\n'); f.flush()
|
| 25 |
+
f.write(json.dumps(session.finish(),allow_nan=False)+'\n')
|
| 26 |
+
print(json.dumps(dict(output=str(dest),prefixes=session.prefix_index)))
|
| 27 |
+
|
| 28 |
+
if __name__=='__main__': main()
|
streampa/streaming_gopt.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
|
| 3 |
+
import math
|
| 4 |
+
import warnings
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
import torch
|
| 8 |
+
import torch.nn as nn
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def _no_grad_trunc_normal_(tensor, mean, std, a, b):
|
| 13 |
+
def norm_cdf(x):
|
| 14 |
+
return (1. + math.erf(x / math.sqrt(2.))) / 2.
|
| 15 |
+
|
| 16 |
+
if (mean < a - 2 * std) or (mean > b + 2 * std):
|
| 17 |
+
warnings.warn(
|
| 18 |
+
"mean is more than 2 std from [a, b] in nn.init.trunc_normal_. "
|
| 19 |
+
"The distribution of values may be incorrect.",
|
| 20 |
+
stacklevel=2,
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
with torch.no_grad():
|
| 24 |
+
l = norm_cdf((a - mean) / std)
|
| 25 |
+
u = norm_cdf((b - mean) / std)
|
| 26 |
+
tensor.uniform_(2 * l - 1, 2 * u - 1)
|
| 27 |
+
tensor.erfinv_()
|
| 28 |
+
tensor.mul_(std * math.sqrt(2.))
|
| 29 |
+
tensor.add_(mean)
|
| 30 |
+
tensor.clamp_(min=a, max=b)
|
| 31 |
+
return tensor
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def trunc_normal_(tensor, mean=0., std=1., a=-2., b=2.):
|
| 35 |
+
return _no_grad_trunc_normal_(tensor, mean, std, a, b)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
class MaskedAttention(nn.Module):
|
| 39 |
+
def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):
|
| 40 |
+
super().__init__()
|
| 41 |
+
self.num_heads = num_heads
|
| 42 |
+
head_dim = dim // num_heads
|
| 43 |
+
self.scale = qk_scale or head_dim ** -0.5
|
| 44 |
+
|
| 45 |
+
self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
|
| 46 |
+
self.attn_drop = nn.Dropout(attn_drop)
|
| 47 |
+
self.proj = nn.Linear(dim, dim)
|
| 48 |
+
self.proj_drop = nn.Dropout(proj_drop)
|
| 49 |
+
|
| 50 |
+
def forward(self, x, attn_mask):
|
| 51 |
+
bsz, seq_len, dim = x.shape
|
| 52 |
+
qkv = self.qkv(x).reshape(bsz, seq_len, 3, self.num_heads, dim // self.num_heads)
|
| 53 |
+
qkv = qkv.permute(2, 0, 3, 1, 4)
|
| 54 |
+
q, k, v = qkv[0], qkv[1], qkv[2]
|
| 55 |
+
|
| 56 |
+
attn = (q @ k.transpose(-2, -1)) * self.scale
|
| 57 |
+
attn = attn.masked_fill(~attn_mask.unsqueeze(1), torch.finfo(attn.dtype).min)
|
| 58 |
+
attn = attn.softmax(dim=-1)
|
| 59 |
+
attn = self.attn_drop(attn)
|
| 60 |
+
|
| 61 |
+
x = (attn @ v).transpose(1, 2).reshape(bsz, seq_len, dim)
|
| 62 |
+
x = self.proj(x)
|
| 63 |
+
x = self.proj_drop(x)
|
| 64 |
+
return x
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class Mlp(nn.Module):
|
| 68 |
+
def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
|
| 69 |
+
super().__init__()
|
| 70 |
+
out_features = out_features or in_features
|
| 71 |
+
hidden_features = hidden_features or in_features
|
| 72 |
+
self.fc1 = nn.Linear(in_features, hidden_features)
|
| 73 |
+
self.act = act_layer()
|
| 74 |
+
self.fc2 = nn.Linear(hidden_features, out_features)
|
| 75 |
+
self.drop = nn.Dropout(drop)
|
| 76 |
+
|
| 77 |
+
def forward(self, x):
|
| 78 |
+
x = self.fc1(x)
|
| 79 |
+
x = self.act(x)
|
| 80 |
+
x = self.drop(x)
|
| 81 |
+
x = self.fc2(x)
|
| 82 |
+
x = self.drop(x)
|
| 83 |
+
return x
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
class StreamingBlock(nn.Module):
|
| 87 |
+
def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
|
| 88 |
+
act_layer=nn.GELU, norm_layer=nn.LayerNorm):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.norm1 = norm_layer(dim)
|
| 91 |
+
self.attn = MaskedAttention(
|
| 92 |
+
dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop,
|
| 93 |
+
)
|
| 94 |
+
self.norm2 = norm_layer(dim)
|
| 95 |
+
mlp_hidden_dim = int(dim * mlp_ratio)
|
| 96 |
+
self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
|
| 97 |
+
|
| 98 |
+
def forward(self, x, attn_mask):
|
| 99 |
+
x = x + self.attn(self.norm1(x), attn_mask)
|
| 100 |
+
x = x + self.mlp(self.norm2(x))
|
| 101 |
+
return x
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
class StreamingGOPT(nn.Module):
|
| 105 |
+
def __init__(self, embed_dim, num_heads, depth, input_dim, seq_len, phn_num, use_phone_embedding=True):
|
| 106 |
+
super().__init__()
|
| 107 |
+
self.input_dim = input_dim
|
| 108 |
+
self.embed_dim = embed_dim
|
| 109 |
+
self.seq_len = seq_len
|
| 110 |
+
self.phn_num = phn_num
|
| 111 |
+
self.use_phone_embedding = use_phone_embedding
|
| 112 |
+
|
| 113 |
+
self.blocks = nn.ModuleList([StreamingBlock(dim=embed_dim, num_heads=num_heads) for _ in range(depth)])
|
| 114 |
+
self.pos_embed = nn.Parameter(torch.zeros(1, self.seq_len + 5, self.embed_dim))
|
| 115 |
+
trunc_normal_(self.pos_embed, std=.02)
|
| 116 |
+
|
| 117 |
+
self.in_proj = nn.Linear(self.input_dim, embed_dim)
|
| 118 |
+
self.phn_proj = nn.Linear(self.phn_num, embed_dim)
|
| 119 |
+
self.cls_tokens = nn.Parameter(torch.zeros(1, 5, embed_dim))
|
| 120 |
+
trunc_normal_(self.cls_tokens, std=.02)
|
| 121 |
+
|
| 122 |
+
self.mlp_head_phn = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 123 |
+
self.mlp_head_word1 = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 124 |
+
self.mlp_head_word2 = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 125 |
+
self.mlp_head_word3 = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 126 |
+
self.mlp_head_word4 = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 127 |
+
self.mlp_head_utt1 = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 128 |
+
self.mlp_head_utt2 = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 129 |
+
self.mlp_head_utt3 = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 130 |
+
self.mlp_head_utt4 = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 131 |
+
self.mlp_head_utt5 = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 132 |
+
|
| 133 |
+
def build_streaming_mask(self, visible_lens, max_phone_tokens, main_context_tokens, right_context_tokens, device):
|
| 134 |
+
total_len = max_phone_tokens + 5
|
| 135 |
+
mask = torch.zeros((visible_lens.shape[0], total_len, total_len), dtype=torch.bool, device=device)
|
| 136 |
+
for row, visible_len in enumerate(visible_lens.tolist()):
|
| 137 |
+
visible_len = int(visible_len)
|
| 138 |
+
cls_start = visible_len
|
| 139 |
+
valid_len = visible_len + 5
|
| 140 |
+
|
| 141 |
+
for tok_idx in range(visible_len):
|
| 142 |
+
block_end = ((tok_idx // main_context_tokens) + 1) * main_context_tokens - 1
|
| 143 |
+
max_key = min(visible_len - 1, block_end + right_context_tokens)
|
| 144 |
+
mask[row, tok_idx, :max_key + 1] = True
|
| 145 |
+
|
| 146 |
+
for cls_offset in range(5):
|
| 147 |
+
query_idx = cls_start + cls_offset
|
| 148 |
+
mask[row, query_idx, :query_idx + 1] = True
|
| 149 |
+
|
| 150 |
+
for pad_idx in range(valid_len, total_len):
|
| 151 |
+
mask[row, pad_idx, pad_idx] = True
|
| 152 |
+
|
| 153 |
+
return mask
|
| 154 |
+
|
| 155 |
+
def pack_sequence(self, token_embed, phn_ids):
|
| 156 |
+
batch_size, max_phone_tokens, embed_dim = token_embed.shape
|
| 157 |
+
visible_mask = phn_ids >= 0
|
| 158 |
+
visible_lens = visible_mask.sum(dim=1)
|
| 159 |
+
total_len = max_phone_tokens + 5
|
| 160 |
+
|
| 161 |
+
packed = token_embed.new_zeros(batch_size, total_len, embed_dim)
|
| 162 |
+
cls_positions = torch.zeros(batch_size, 5, dtype=torch.long, device=token_embed.device)
|
| 163 |
+
|
| 164 |
+
cls_tokens = self.cls_tokens.expand(batch_size, -1, -1)
|
| 165 |
+
for row, visible_len in enumerate(visible_lens.tolist()):
|
| 166 |
+
visible_len = int(visible_len)
|
| 167 |
+
if visible_len > 0:
|
| 168 |
+
packed[row, :visible_len] = token_embed[row, :visible_len]
|
| 169 |
+
cls_start = visible_len
|
| 170 |
+
packed[row, cls_start:cls_start + 5] = cls_tokens[row]
|
| 171 |
+
cls_positions[row] = torch.arange(cls_start, cls_start + 5, device=token_embed.device)
|
| 172 |
+
|
| 173 |
+
packed = packed + self.pos_embed[:, :total_len]
|
| 174 |
+
return packed, visible_lens, cls_positions
|
| 175 |
+
|
| 176 |
+
def unpack_phone_states(self, hidden, visible_lens, max_phone_tokens):
|
| 177 |
+
phone_hidden = hidden.new_zeros(hidden.shape[0], max_phone_tokens, hidden.shape[-1])
|
| 178 |
+
for row, visible_len in enumerate(visible_lens.tolist()):
|
| 179 |
+
visible_len = int(visible_len)
|
| 180 |
+
if visible_len > 0:
|
| 181 |
+
phone_hidden[row, :visible_len] = hidden[row, :visible_len]
|
| 182 |
+
return phone_hidden
|
| 183 |
+
|
| 184 |
+
def forward(self, x, phn, main_context_tokens=8, right_context_tokens=2):
|
| 185 |
+
main_context_tokens = max(int(main_context_tokens), 1)
|
| 186 |
+
right_context_tokens = max(int(right_context_tokens), 0)
|
| 187 |
+
|
| 188 |
+
batch_size, max_phone_tokens, _ = x.shape
|
| 189 |
+
visible_mask = phn >= 0
|
| 190 |
+
x = self.in_proj(x) if self.embed_dim != self.input_dim else x
|
| 191 |
+
|
| 192 |
+
phn_clamped = torch.clamp(phn.long() + 1, min=0, max=self.phn_num - 1)
|
| 193 |
+
phn_one_hot = F.one_hot(phn_clamped, num_classes=self.phn_num).float()
|
| 194 |
+
phn_embed = self.phn_proj(phn_one_hot) * visible_mask.unsqueeze(-1)
|
| 195 |
+
token_embed = x + phn_embed if self.use_phone_embedding else x
|
| 196 |
+
packed, visible_lens, cls_positions = self.pack_sequence(token_embed, phn)
|
| 197 |
+
|
| 198 |
+
attn_mask = self.build_streaming_mask(
|
| 199 |
+
visible_lens=visible_lens,
|
| 200 |
+
max_phone_tokens=max_phone_tokens,
|
| 201 |
+
main_context_tokens=main_context_tokens,
|
| 202 |
+
right_context_tokens=right_context_tokens,
|
| 203 |
+
device=x.device,
|
| 204 |
+
)
|
| 205 |
+
|
| 206 |
+
hidden = packed
|
| 207 |
+
for blk in self.blocks:
|
| 208 |
+
hidden = blk(hidden, attn_mask)
|
| 209 |
+
|
| 210 |
+
phone_hidden = self.unpack_phone_states(hidden, visible_lens, max_phone_tokens)
|
| 211 |
+
batch_index = torch.arange(batch_size, device=x.device).unsqueeze(1)
|
| 212 |
+
cls_hidden = hidden[batch_index, cls_positions]
|
| 213 |
+
|
| 214 |
+
u1 = self.mlp_head_utt1(cls_hidden[:, 0])
|
| 215 |
+
u2 = self.mlp_head_utt2(cls_hidden[:, 1])
|
| 216 |
+
u3 = self.mlp_head_utt3(cls_hidden[:, 2])
|
| 217 |
+
u4 = self.mlp_head_utt4(cls_hidden[:, 3])
|
| 218 |
+
u5 = self.mlp_head_utt5(cls_hidden[:, 4])
|
| 219 |
+
|
| 220 |
+
p = self.mlp_head_phn(phone_hidden)
|
| 221 |
+
w1 = self.mlp_head_word1(phone_hidden)
|
| 222 |
+
w2 = self.mlp_head_word2(phone_hidden)
|
| 223 |
+
w3 = self.mlp_head_word3(phone_hidden)
|
| 224 |
+
w4 = self.mlp_head_word4(phone_hidden)
|
| 225 |
+
return u1, u2, u3, u4, u5, p, w1, w2, w3, w4
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
class StreamingGOPTNoPhn(StreamingGOPT):
|
| 229 |
+
def __init__(self, embed_dim, num_heads, depth, input_dim, seq_len, phn_num):
|
| 230 |
+
super().__init__(
|
| 231 |
+
embed_dim=embed_dim,
|
| 232 |
+
num_heads=num_heads,
|
| 233 |
+
depth=depth,
|
| 234 |
+
input_dim=input_dim,
|
| 235 |
+
seq_len=seq_len,
|
| 236 |
+
phn_num=phn_num,
|
| 237 |
+
use_phone_embedding=False,
|
| 238 |
+
)
|
streampa/streaming_pcn_gopt.py
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
+
|
| 6 |
+
from .streaming_gopt import StreamingBlock, trunc_normal_
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def masked_mean(values, mask, dim, keepdim=False):
|
| 10 |
+
mask = mask.to(dtype=values.dtype)
|
| 11 |
+
while mask.dim() < values.dim():
|
| 12 |
+
mask = mask.unsqueeze(-1)
|
| 13 |
+
denom = mask.sum(dim=dim, keepdim=keepdim).clamp_min(1.0)
|
| 14 |
+
return (values * mask).sum(dim=dim, keepdim=keepdim) / denom
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class ReliabilityGate(nn.Module):
|
| 18 |
+
def __init__(self, hidden_dim=16, output_dim=1):
|
| 19 |
+
super().__init__()
|
| 20 |
+
self.net = nn.Sequential(
|
| 21 |
+
nn.Linear(4, hidden_dim),
|
| 22 |
+
nn.GELU(),
|
| 23 |
+
nn.Linear(hidden_dim, int(output_dim)),
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
def forward(self, cn_stats, acoustic_stats):
|
| 27 |
+
# cn_stats: eps, entropy, top1, margin, prefix_stability
|
| 28 |
+
# acoustic_stats: entropy, margin, duration, PCN-Charsiu JS divergence
|
| 29 |
+
gate_input = torch.stack(
|
| 30 |
+
[
|
| 31 |
+
cn_stats[..., 1],
|
| 32 |
+
acoustic_stats[..., 0],
|
| 33 |
+
acoustic_stats[..., 3],
|
| 34 |
+
cn_stats[..., 4],
|
| 35 |
+
],
|
| 36 |
+
dim=-1,
|
| 37 |
+
)
|
| 38 |
+
return torch.sigmoid(self.net(gate_input))
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
class PCNStreamingScorer(nn.Module):
|
| 42 |
+
"""
|
| 43 |
+
Stateful streaming scorer for streaming_pcn_gopt_v2_stateful.
|
| 44 |
+
|
| 45 |
+
Local phone/word heads read all visible PCN slots. The sentence GRU is
|
| 46 |
+
updated only from slots selected by new_commit_mask. cumulative_commit_mask
|
| 47 |
+
is retained for losses/diagnostics and must not be used for GRU updates.
|
| 48 |
+
"""
|
| 49 |
+
|
| 50 |
+
def __init__(
|
| 51 |
+
self,
|
| 52 |
+
phone_dim,
|
| 53 |
+
seq_len,
|
| 54 |
+
prosody_dim=14,
|
| 55 |
+
embed_dim=40,
|
| 56 |
+
num_heads=2,
|
| 57 |
+
depth=2,
|
| 58 |
+
pcn_embed_dim=16,
|
| 59 |
+
acoustic_embed_dim=16,
|
| 60 |
+
prosody_embed_dim=8,
|
| 61 |
+
gru_dim=32,
|
| 62 |
+
main_context_tokens=16,
|
| 63 |
+
dropout=0.0,
|
| 64 |
+
use_state_projection=False,
|
| 65 |
+
teacher_state_dim=128,
|
| 66 |
+
utt_pooling_head='gru',
|
| 67 |
+
fusion_mode='scalar_gate',
|
| 68 |
+
slot_prosody_dim=0,
|
| 69 |
+
slot_prosody_embed_dim=8,
|
| 70 |
+
stress_branch='none',
|
| 71 |
+
stress_grad_scale=0.2,
|
| 72 |
+
use_acoustic=True,
|
| 73 |
+
use_prosody=True,
|
| 74 |
+
use_uncertainty_stats=True,
|
| 75 |
+
):
|
| 76 |
+
super().__init__()
|
| 77 |
+
self.phone_dim = int(phone_dim)
|
| 78 |
+
self.seq_len = int(seq_len)
|
| 79 |
+
self.prosody_dim = int(prosody_dim)
|
| 80 |
+
self.embed_dim = int(embed_dim)
|
| 81 |
+
self.gru_dim = int(gru_dim)
|
| 82 |
+
self.main_context_tokens = max(int(main_context_tokens), 1)
|
| 83 |
+
self.use_state_projection = bool(use_state_projection)
|
| 84 |
+
self.utt_pooling_head = str(utt_pooling_head)
|
| 85 |
+
self.fusion_mode = str(fusion_mode)
|
| 86 |
+
self.slot_prosody_dim = int(slot_prosody_dim or 0)
|
| 87 |
+
self.stress_branch = str(stress_branch)
|
| 88 |
+
self.stress_grad_scale = float(stress_grad_scale)
|
| 89 |
+
self.use_acoustic = bool(use_acoustic)
|
| 90 |
+
self.use_prosody = bool(use_prosody)
|
| 91 |
+
self.use_uncertainty_stats = bool(use_uncertainty_stats)
|
| 92 |
+
|
| 93 |
+
if self.utt_pooling_head not in {'gru', 'gru_visible', 'visible_committed'}:
|
| 94 |
+
raise ValueError("utt_pooling_head must be 'gru', 'gru_visible', or 'visible_committed'.")
|
| 95 |
+
if self.fusion_mode not in {'scalar_gate', 'concat_vector_gate', 'fixed_average'}:
|
| 96 |
+
raise ValueError("fusion_mode must be 'scalar_gate', 'concat_vector_gate', or 'fixed_average'.")
|
| 97 |
+
if self.stress_branch not in {'none', 'detached', 'gradscale'}:
|
| 98 |
+
raise ValueError("stress_branch must be 'none', 'detached', or 'gradscale'.")
|
| 99 |
+
|
| 100 |
+
if pcn_embed_dim != acoustic_embed_dim:
|
| 101 |
+
raise ValueError('pcn_embed_dim and acoustic_embed_dim must match for gated interpolation.')
|
| 102 |
+
|
| 103 |
+
self.pcn_proj = nn.Sequential(
|
| 104 |
+
nn.Linear(self.phone_dim + 5, pcn_embed_dim),
|
| 105 |
+
nn.LayerNorm(pcn_embed_dim),
|
| 106 |
+
nn.GELU(),
|
| 107 |
+
)
|
| 108 |
+
self.acoustic_proj = None
|
| 109 |
+
if self.use_acoustic:
|
| 110 |
+
self.acoustic_proj = nn.Sequential(
|
| 111 |
+
nn.Linear(self.phone_dim + 4, acoustic_embed_dim),
|
| 112 |
+
nn.LayerNorm(acoustic_embed_dim),
|
| 113 |
+
nn.GELU(),
|
| 114 |
+
)
|
| 115 |
+
self.prosody_proj = None
|
| 116 |
+
prosody_fused_dim = 0
|
| 117 |
+
if self.use_prosody:
|
| 118 |
+
prosody_fused_dim = int(prosody_embed_dim)
|
| 119 |
+
self.prosody_proj = nn.Sequential(
|
| 120 |
+
nn.Linear(self.prosody_dim, max(16, prosody_embed_dim * 2)),
|
| 121 |
+
nn.GELU(),
|
| 122 |
+
nn.Linear(max(16, prosody_embed_dim * 2), prosody_embed_dim),
|
| 123 |
+
nn.LayerNorm(prosody_embed_dim),
|
| 124 |
+
)
|
| 125 |
+
if self.use_acoustic and self.fusion_mode != 'fixed_average':
|
| 126 |
+
gate_dim = pcn_embed_dim if self.fusion_mode == 'concat_vector_gate' else 1
|
| 127 |
+
self.reliability_gate = ReliabilityGate(output_dim=gate_dim)
|
| 128 |
+
else:
|
| 129 |
+
self.reliability_gate = None
|
| 130 |
+
self.slot_prosody_proj = None
|
| 131 |
+
slot_prosody_fused_dim = 0
|
| 132 |
+
if self.slot_prosody_dim > 0:
|
| 133 |
+
slot_prosody_fused_dim = int(slot_prosody_embed_dim)
|
| 134 |
+
self.slot_prosody_proj = nn.Sequential(
|
| 135 |
+
nn.Linear(self.slot_prosody_dim, max(16, slot_prosody_fused_dim * 2)),
|
| 136 |
+
nn.GELU(),
|
| 137 |
+
nn.Linear(max(16, slot_prosody_fused_dim * 2), slot_prosody_fused_dim),
|
| 138 |
+
nn.LayerNorm(slot_prosody_fused_dim),
|
| 139 |
+
)
|
| 140 |
+
if not self.use_acoustic:
|
| 141 |
+
evidence_dim = pcn_embed_dim
|
| 142 |
+
elif self.fusion_mode == 'concat_vector_gate':
|
| 143 |
+
evidence_dim = pcn_embed_dim * 4
|
| 144 |
+
else:
|
| 145 |
+
evidence_dim = pcn_embed_dim
|
| 146 |
+
self.fused_proj = nn.Sequential(
|
| 147 |
+
nn.Linear(evidence_dim + prosody_fused_dim + slot_prosody_fused_dim, embed_dim),
|
| 148 |
+
nn.LayerNorm(embed_dim),
|
| 149 |
+
nn.Dropout(dropout),
|
| 150 |
+
)
|
| 151 |
+
self.pos_embed = nn.Parameter(torch.zeros(1, self.seq_len, self.embed_dim))
|
| 152 |
+
trunc_normal_(self.pos_embed, std=.02)
|
| 153 |
+
self.blocks = nn.ModuleList(
|
| 154 |
+
[
|
| 155 |
+
StreamingBlock(
|
| 156 |
+
dim=embed_dim,
|
| 157 |
+
num_heads=num_heads,
|
| 158 |
+
mlp_ratio=2.0,
|
| 159 |
+
qkv_bias=True,
|
| 160 |
+
drop=dropout,
|
| 161 |
+
attn_drop=dropout,
|
| 162 |
+
)
|
| 163 |
+
for _ in range(depth)
|
| 164 |
+
]
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
self.word_pool_proj = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, embed_dim), nn.GELU())
|
| 168 |
+
self.sentence_gru = None
|
| 169 |
+
if self.utt_pooling_head != 'visible_committed':
|
| 170 |
+
self.sentence_gru = nn.GRU(input_size=embed_dim, hidden_size=gru_dim, batch_first=True)
|
| 171 |
+
|
| 172 |
+
self.phone_head = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 173 |
+
self.word_head = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 3))
|
| 174 |
+
self.stress_head = None
|
| 175 |
+
if self.stress_branch != 'none':
|
| 176 |
+
self.stress_head = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 177 |
+
self.asr_correct_head = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 178 |
+
self.uncertainty_head = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 179 |
+
self.confidence_head = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 180 |
+
self.abstention_head = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, 1))
|
| 181 |
+
self.utt_head = None
|
| 182 |
+
if self.utt_pooling_head == 'gru':
|
| 183 |
+
self.utt_head = nn.Sequential(nn.LayerNorm(gru_dim), nn.Linear(gru_dim, 5))
|
| 184 |
+
self.utt_visible_head = None
|
| 185 |
+
if self.utt_pooling_head == 'gru_visible':
|
| 186 |
+
visible_dim = gru_dim + embed_dim + embed_dim + 2
|
| 187 |
+
self.utt_visible_head = nn.Sequential(nn.LayerNorm(visible_dim), nn.Linear(visible_dim, 5))
|
| 188 |
+
elif self.utt_pooling_head == 'visible_committed':
|
| 189 |
+
visible_dim = embed_dim + embed_dim + 2
|
| 190 |
+
self.utt_visible_head = nn.Sequential(nn.LayerNorm(visible_dim), nn.Linear(visible_dim, 5))
|
| 191 |
+
self.state_projection = (
|
| 192 |
+
nn.Sequential(nn.LayerNorm(gru_dim), nn.Linear(gru_dim, int(teacher_state_dim)))
|
| 193 |
+
if self.use_state_projection
|
| 194 |
+
else None
|
| 195 |
+
)
|
| 196 |
+
|
| 197 |
+
def build_local_causal_mask(self, valid_mask):
|
| 198 |
+
batch_size, seq_len = valid_mask.shape
|
| 199 |
+
idx = torch.arange(seq_len, device=valid_mask.device)
|
| 200 |
+
causal = idx.view(1, -1) <= idx.view(-1, 1)
|
| 201 |
+
local = idx.view(1, -1) >= (idx.view(-1, 1) - self.main_context_tokens + 1)
|
| 202 |
+
base = causal & local
|
| 203 |
+
mask = base.unsqueeze(0).expand(batch_size, -1, -1).clone()
|
| 204 |
+
key_valid = valid_mask.unsqueeze(1).expand(-1, seq_len, -1)
|
| 205 |
+
query_valid = valid_mask.unsqueeze(2).expand(-1, -1, seq_len)
|
| 206 |
+
mask = mask & key_valid & query_valid
|
| 207 |
+
diag = torch.eye(seq_len, dtype=torch.bool, device=valid_mask.device).unsqueeze(0)
|
| 208 |
+
return mask | diag
|
| 209 |
+
|
| 210 |
+
def encode_slots(self, cn_post, cn_stats, acoustic_post, acoustic_stats, prosody, valid_mask, slot_prosody=None):
|
| 211 |
+
if not self.use_uncertainty_stats:
|
| 212 |
+
cn_stats = cn_stats.clone()
|
| 213 |
+
acoustic_stats = acoustic_stats.clone()
|
| 214 |
+
cn_stats[..., 1] = 0.0 # PCN entropy
|
| 215 |
+
cn_stats[..., 3] = 0.0 # PCN margin
|
| 216 |
+
cn_stats[..., 4] = 0.0 # prefix stability
|
| 217 |
+
acoustic_stats[..., 0] = 0.0 # acoustic entropy
|
| 218 |
+
acoustic_stats[..., 1] = 0.0 # acoustic margin
|
| 219 |
+
acoustic_stats[..., 3] = 0.0 # PCN/Charsiu JS divergence
|
| 220 |
+
z_pcn = self.pcn_proj(torch.cat([cn_post, cn_stats], dim=-1))
|
| 221 |
+
if self.use_acoustic:
|
| 222 |
+
z_acoustic = self.acoustic_proj(torch.cat([acoustic_post, acoustic_stats], dim=-1))
|
| 223 |
+
if self.fusion_mode == 'fixed_average':
|
| 224 |
+
gate = cn_post.new_full((*cn_post.shape[:2], 1), 0.5)
|
| 225 |
+
interpolation = 0.5 * z_acoustic + 0.5 * z_pcn
|
| 226 |
+
else:
|
| 227 |
+
gate = self.reliability_gate(cn_stats, acoustic_stats)
|
| 228 |
+
interpolation = gate * z_acoustic + (1.0 - gate) * z_pcn
|
| 229 |
+
if self.fusion_mode == 'concat_vector_gate':
|
| 230 |
+
evidence = torch.cat([z_pcn, z_acoustic, z_acoustic - z_pcn, interpolation], dim=-1)
|
| 231 |
+
else:
|
| 232 |
+
evidence = interpolation
|
| 233 |
+
else:
|
| 234 |
+
gate = cn_post.new_zeros((*cn_post.shape[:2], 1))
|
| 235 |
+
evidence = z_pcn
|
| 236 |
+
fused_parts = [evidence]
|
| 237 |
+
if self.prosody_proj is not None:
|
| 238 |
+
z_prosody = self.prosody_proj(prosody).unsqueeze(1).expand(-1, cn_post.shape[1], -1)
|
| 239 |
+
fused_parts.append(z_prosody)
|
| 240 |
+
if self.slot_prosody_proj is not None:
|
| 241 |
+
if slot_prosody is None:
|
| 242 |
+
slot_prosody = cn_post.new_zeros(cn_post.shape[0], cn_post.shape[1], self.slot_prosody_dim)
|
| 243 |
+
fused_parts.append(self.slot_prosody_proj(slot_prosody))
|
| 244 |
+
token = self.fused_proj(torch.cat(fused_parts, dim=-1))
|
| 245 |
+
token = token + self.pos_embed[:, : token.shape[1]]
|
| 246 |
+
token = token * valid_mask.unsqueeze(-1).to(token.dtype)
|
| 247 |
+
return token, gate
|
| 248 |
+
|
| 249 |
+
def local_causal_transformer(self, token, valid_mask):
|
| 250 |
+
attn_mask = self.build_local_causal_mask(valid_mask)
|
| 251 |
+
hidden = token
|
| 252 |
+
for block in self.blocks:
|
| 253 |
+
hidden = block(hidden, attn_mask)
|
| 254 |
+
return hidden * valid_mask.unsqueeze(-1).to(hidden.dtype)
|
| 255 |
+
|
| 256 |
+
def pool_new_committed_words(self, hidden, new_commit_mask, word_ids=None):
|
| 257 |
+
batch_size, _, dim = hidden.shape
|
| 258 |
+
row_groups = []
|
| 259 |
+
max_words = 0
|
| 260 |
+
for row in range(batch_size):
|
| 261 |
+
active = torch.nonzero(new_commit_mask[row] > 0, as_tuple=False).squeeze(1).tolist()
|
| 262 |
+
groups = []
|
| 263 |
+
if active:
|
| 264 |
+
if word_ids is None:
|
| 265 |
+
groups = [[idx] for idx in active]
|
| 266 |
+
else:
|
| 267 |
+
cur_group = [active[0]]
|
| 268 |
+
cur_word = int(word_ids[row, active[0]].item())
|
| 269 |
+
for idx in active[1:]:
|
| 270 |
+
next_word = int(word_ids[row, idx].item())
|
| 271 |
+
if next_word == cur_word and next_word >= 0:
|
| 272 |
+
cur_group.append(idx)
|
| 273 |
+
else:
|
| 274 |
+
groups.append(cur_group)
|
| 275 |
+
cur_group = [idx]
|
| 276 |
+
cur_word = next_word
|
| 277 |
+
groups.append(cur_group)
|
| 278 |
+
row_groups.append(groups)
|
| 279 |
+
max_words = max(max_words, len(groups))
|
| 280 |
+
|
| 281 |
+
max_words = max(max_words, 1)
|
| 282 |
+
pooled_rows = []
|
| 283 |
+
pooled_masks = []
|
| 284 |
+
for row, groups in enumerate(row_groups):
|
| 285 |
+
pooled = hidden.new_zeros(max_words, dim)
|
| 286 |
+
mask = hidden.new_zeros(max_words)
|
| 287 |
+
for group_idx, positions in enumerate(groups):
|
| 288 |
+
pos = torch.tensor(positions, dtype=torch.long, device=hidden.device)
|
| 289 |
+
pooled[group_idx] = self.word_pool_proj(hidden[row, pos].mean(dim=0))
|
| 290 |
+
mask[group_idx] = 1.0
|
| 291 |
+
pooled_rows.append(pooled)
|
| 292 |
+
pooled_masks.append(mask)
|
| 293 |
+
return torch.stack(pooled_rows, dim=0), torch.stack(pooled_masks, dim=0)
|
| 294 |
+
|
| 295 |
+
def update_sentence_state(self, new_words, word_mask, prev_state):
|
| 296 |
+
batch_size = new_words.shape[0]
|
| 297 |
+
if prev_state is not None and prev_state.dim() == 2:
|
| 298 |
+
prev_state = prev_state.unsqueeze(0)
|
| 299 |
+
states = []
|
| 300 |
+
for row in range(batch_size):
|
| 301 |
+
if prev_state is None:
|
| 302 |
+
h0 = new_words.new_zeros(1, 1, self.gru_dim)
|
| 303 |
+
else:
|
| 304 |
+
h0 = prev_state[:, row : row + 1, :]
|
| 305 |
+
word_count = int(word_mask[row].sum().item())
|
| 306 |
+
if word_count <= 0:
|
| 307 |
+
states.append(h0)
|
| 308 |
+
continue
|
| 309 |
+
_, h_row = self.sentence_gru(new_words[row : row + 1, :word_count], h0)
|
| 310 |
+
states.append(h_row)
|
| 311 |
+
return torch.cat(states, dim=1)
|
| 312 |
+
|
| 313 |
+
def forward(
|
| 314 |
+
self,
|
| 315 |
+
cn_post,
|
| 316 |
+
cn_stats,
|
| 317 |
+
acoustic_post,
|
| 318 |
+
acoustic_stats,
|
| 319 |
+
prosody,
|
| 320 |
+
visible_len,
|
| 321 |
+
cumulative_commit_mask=None,
|
| 322 |
+
new_commit_mask=None,
|
| 323 |
+
commit_mask=None,
|
| 324 |
+
word_ids=None,
|
| 325 |
+
slot_prosody=None,
|
| 326 |
+
prev_state=None,
|
| 327 |
+
detach_next_state=False,
|
| 328 |
+
):
|
| 329 |
+
batch_size, seq_len, _ = cn_post.shape
|
| 330 |
+
device = cn_post.device
|
| 331 |
+
token_idx = torch.arange(seq_len, device=device).unsqueeze(0)
|
| 332 |
+
valid_mask = token_idx < visible_len.to(device).unsqueeze(1)
|
| 333 |
+
|
| 334 |
+
if cumulative_commit_mask is None:
|
| 335 |
+
cumulative_commit_mask = commit_mask
|
| 336 |
+
if cumulative_commit_mask is None:
|
| 337 |
+
cumulative_commit_mask = torch.zeros((batch_size, seq_len), dtype=torch.bool, device=device)
|
| 338 |
+
if new_commit_mask is None:
|
| 339 |
+
# Legacy fallback: safe only for stateless/full-sentence use.
|
| 340 |
+
new_commit_mask = cumulative_commit_mask
|
| 341 |
+
cumulative_commit_mask = (cumulative_commit_mask > 0) & valid_mask
|
| 342 |
+
new_commit_mask = (new_commit_mask > 0) & valid_mask
|
| 343 |
+
|
| 344 |
+
token, gate = self.encode_slots(cn_post, cn_stats, acoustic_post, acoustic_stats, prosody, valid_mask, slot_prosody=slot_prosody)
|
| 345 |
+
slot_hidden = self.local_causal_transformer(token, valid_mask)
|
| 346 |
+
new_words, new_word_mask = self.pool_new_committed_words(slot_hidden, new_commit_mask, word_ids=word_ids)
|
| 347 |
+
if self.sentence_gru is None:
|
| 348 |
+
final_state = slot_hidden.new_zeros(1, batch_size, self.gru_dim)
|
| 349 |
+
else:
|
| 350 |
+
final_state = self.update_sentence_state(new_words, new_word_mask, prev_state)
|
| 351 |
+
next_state = final_state.detach() if detach_next_state else final_state
|
| 352 |
+
sentence_state = final_state[-1]
|
| 353 |
+
|
| 354 |
+
confidence_logit = self.confidence_head(slot_hidden)
|
| 355 |
+
abstention_logit = self.abstention_head(slot_hidden)
|
| 356 |
+
confidence = torch.sigmoid(confidence_logit)
|
| 357 |
+
abstention_probability = torch.sigmoid(abstention_logit)
|
| 358 |
+
if self.utt_pooling_head in {'gru_visible', 'visible_committed'}:
|
| 359 |
+
committed_pool = masked_mean(slot_hidden, cumulative_commit_mask, dim=1)
|
| 360 |
+
visible_pool = masked_mean(slot_hidden, valid_mask, dim=1)
|
| 361 |
+
mean_confidence = masked_mean(confidence, valid_mask, dim=1)
|
| 362 |
+
mean_abstention = masked_mean(abstention_probability, valid_mask, dim=1)
|
| 363 |
+
if self.utt_pooling_head == 'gru_visible':
|
| 364 |
+
utt_input = torch.cat([sentence_state, committed_pool, visible_pool, mean_confidence, mean_abstention], dim=-1)
|
| 365 |
+
else:
|
| 366 |
+
utt_input = torch.cat([committed_pool, visible_pool, mean_confidence, mean_abstention], dim=-1)
|
| 367 |
+
utt_scores = self.utt_visible_head(utt_input)
|
| 368 |
+
else:
|
| 369 |
+
utt_scores = self.utt_head(sentence_state)
|
| 370 |
+
base_word_scores = self.word_head(slot_hidden)
|
| 371 |
+
if self.stress_head is None:
|
| 372 |
+
word_scores = base_word_scores
|
| 373 |
+
else:
|
| 374 |
+
if self.stress_branch == 'detached':
|
| 375 |
+
stress_input = slot_hidden.detach()
|
| 376 |
+
else:
|
| 377 |
+
scale = float(self.stress_grad_scale)
|
| 378 |
+
stress_input = scale * slot_hidden + (1.0 - scale) * slot_hidden.detach()
|
| 379 |
+
stress_score = self.stress_head(stress_input)
|
| 380 |
+
word_scores = torch.cat([base_word_scores[..., 0:1], stress_score, base_word_scores[..., 2:3]], dim=-1)
|
| 381 |
+
|
| 382 |
+
output = {
|
| 383 |
+
'phone_score': self.phone_head(slot_hidden),
|
| 384 |
+
'word_scores': word_scores,
|
| 385 |
+
'utt_scores': utt_scores,
|
| 386 |
+
'asr_correct_logits': self.asr_correct_head(slot_hidden),
|
| 387 |
+
'uncertainty_logits': self.uncertainty_head(slot_hidden),
|
| 388 |
+
'confidence_logit': confidence_logit,
|
| 389 |
+
'confidence': confidence,
|
| 390 |
+
'abstention_logit': abstention_logit,
|
| 391 |
+
'abstention_probability': abstention_probability,
|
| 392 |
+
'reliability_gate': gate,
|
| 393 |
+
'slot_hidden': slot_hidden,
|
| 394 |
+
'new_word_states': new_words,
|
| 395 |
+
'new_word_mask': new_word_mask,
|
| 396 |
+
'word_states': new_words,
|
| 397 |
+
'word_mask': new_word_mask,
|
| 398 |
+
'sentence_state': sentence_state,
|
| 399 |
+
'next_state': next_state,
|
| 400 |
+
'cumulative_commit_mask': cumulative_commit_mask,
|
| 401 |
+
'new_commit_mask': new_commit_mask,
|
| 402 |
+
}
|
| 403 |
+
if self.state_projection is not None:
|
| 404 |
+
output['state_projection'] = self.state_projection(sentence_state)
|
| 405 |
+
return output
|
| 406 |
+
|
| 407 |
+
@torch.inference_mode()
|
| 408 |
+
def stream_step(self, batch, prev_state=None):
|
| 409 |
+
return self.forward(
|
| 410 |
+
cn_post=batch['cn_post'],
|
| 411 |
+
cn_stats=batch['cn_stats'],
|
| 412 |
+
acoustic_post=batch['acoustic_post'],
|
| 413 |
+
acoustic_stats=batch['acoustic_stats'],
|
| 414 |
+
prosody=batch['prosody'],
|
| 415 |
+
visible_len=batch['visible_len'],
|
| 416 |
+
cumulative_commit_mask=batch.get('cumulative_commit_mask', batch.get('commit_mask')),
|
| 417 |
+
new_commit_mask=batch.get('new_commit_mask'),
|
| 418 |
+
word_ids=batch.get('pcn_word_id'),
|
| 419 |
+
slot_prosody=batch.get('slot_prosody'),
|
| 420 |
+
prev_state=prev_state,
|
| 421 |
+
detach_next_state=True,
|
| 422 |
+
)
|
tests/test_runtime.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Deterministic contract tests; real audio validation is documented separately."""
|
| 2 |
+
from types import SimpleNamespace
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
import numpy as np
|
| 5 |
+
import pytest
|
| 6 |
+
import torch
|
| 7 |
+
from streampa.pipeline import StreamPASession, load_scorer
|
| 8 |
+
from streampa import frontend as fe
|
| 9 |
+
|
| 10 |
+
class ScheduleSession(StreamPASession):
|
| 11 |
+
def _step(self,commit_samples,end_samples,is_final):
|
| 12 |
+
row=dict(commit=commit_samples,end=end_samples,final=is_final,samples=self.audio[:end_samples].copy())
|
| 13 |
+
self.last_result=row
|
| 14 |
+
return row
|
| 15 |
+
|
| 16 |
+
def session():
|
| 17 |
+
return ScheduleSession(SimpleNamespace(assets={'max_audio_sec':30,'chunk_sec':.64,'right_context_sec':.16}))
|
| 18 |
+
|
| 19 |
+
def test_received_boundary_and_short_eof():
|
| 20 |
+
s=session()
|
| 21 |
+
assert s.append(np.zeros(12799,np.float32))==[]
|
| 22 |
+
r=s.append(np.ones(1,np.float32))[0]
|
| 23 |
+
assert r['commit']==10240 and r['end']==12800 and not r['final']
|
| 24 |
+
s.append(np.ones(100,np.float32))
|
| 25 |
+
r=s.finish()
|
| 26 |
+
assert r['end']==12900 and r['commit']==12900 and r['final']
|
| 27 |
+
|
| 28 |
+
def test_reset_and_new_session_do_not_share_state():
|
| 29 |
+
a=session(); b=session()
|
| 30 |
+
a.state=torch.ones(1,64); a.commit_state={'committed_slots':[0]}
|
| 31 |
+
a.append(np.ones(100)); a.reset()
|
| 32 |
+
assert a.state is None and a.commit_state is None and len(a.audio)==0
|
| 33 |
+
assert b.state is None and len(b.audio)==0
|
| 34 |
+
|
| 35 |
+
def test_suffix_is_not_in_current_input():
|
| 36 |
+
prefix=np.arange(12800,dtype=np.float32)
|
| 37 |
+
a=session(); b=session()
|
| 38 |
+
x=a.append(np.concatenate([prefix,np.ones(10000)]))[0]
|
| 39 |
+
y=b.append(np.concatenate([prefix,-np.ones(10000)]))[0]
|
| 40 |
+
assert np.array_equal(x['samples'],y['samples'])
|
| 41 |
+
|
| 42 |
+
def test_closed_empty_and_invalid_input():
|
| 43 |
+
s=session(); assert s.finish()['end']==0
|
| 44 |
+
with pytest.raises(RuntimeError): s.append(np.zeros(1))
|
| 45 |
+
s.reset()
|
| 46 |
+
with pytest.raises(ValueError): s.append(np.array([np.nan]))
|
| 47 |
+
with pytest.raises(ValueError): s.append(np.zeros((2,2)))
|
| 48 |
+
with pytest.raises(ValueError): s.append(np.zeros(480001))
|
| 49 |
+
assert len(s.audio)==0
|
| 50 |
+
|
| 51 |
+
def test_normalization_and_gap_mass():
|
| 52 |
+
assert fe.normalize_phone('AH0')=='AH'
|
| 53 |
+
assert fe.normalize_word('Hello!')=='HELLO'
|
| 54 |
+
post=np.array([[.6,.1,.3],[.2,.6,.2]],np.float32)
|
| 55 |
+
pcn={'cn_post':post,'eps_index':2}
|
| 56 |
+
fe.validate_pcn(pcn)
|
| 57 |
+
stats,_=fe.pcn_stats(post,[0,1],[],2)
|
| 58 |
+
assert np.allclose(stats[:,0],[.3,.2])
|
| 59 |
+
with pytest.raises(ValueError): fe.validate_pcn({'cn_post':post*0,'eps_index':2})
|
| 60 |
+
|
| 61 |
+
def test_partial_commit_and_legacy_persistence():
|
| 62 |
+
pcn={'top_phone_ids':[1,2],'slot_times':[(0,.3),(.3,.8)]}
|
| 63 |
+
ids=np.array([0,1],np.int32)
|
| 64 |
+
times=[{'word':'A','start':0,'end':.3},{'word':'B','start':.3,'end':.8}]
|
| 65 |
+
cum,new,_,_,state=fe.build_stateful_commit_masks(None,pcn,ids,times,.64,.8,False,commit_rule='legacy')
|
| 66 |
+
assert new.tolist()==[1.,0.] and cum.tolist()==[1.,0.]
|
| 67 |
+
cum,new,_,_,state=fe.build_stateful_commit_masks(state,pcn,ids,times,.8,.8,True,commit_rule='legacy')
|
| 68 |
+
assert new.tolist()==[0.,1.] and cum.tolist()==[1.,1.]
|
| 69 |
+
_,new,_,_,_=fe.build_stateful_commit_masks(state,pcn,ids,times,1,1,True,commit_rule='legacy')
|
| 70 |
+
assert new.sum()==0
|
| 71 |
+
|
| 72 |
+
def test_no_new_words_keeps_state_but_visible_path_remains_active():
|
| 73 |
+
torch.set_num_threads(2); torch.manual_seed(1337)
|
| 74 |
+
model,c=load_scorer(Path(__file__).resolve().parents[1])
|
| 75 |
+
n=c['seq_len']; d=c['phone_dim']
|
| 76 |
+
batch=dict(cn_post=torch.softmax(torch.randn(1,n,d),-1),cn_stats=torch.randn(1,n,5),
|
| 77 |
+
acoustic_post=torch.softmax(torch.randn(1,n,d),-1),acoustic_stats=torch.randn(1,n,4),
|
| 78 |
+
prosody=torch.randn(1,c['prosody_dim']),slot_prosody=torch.randn(1,n,c['slot_prosody_dim']),
|
| 79 |
+
visible_len=torch.tensor([4]),cumulative_commit_mask=torch.zeros(1,n),new_commit_mask=torch.zeros(1,n),
|
| 80 |
+
word_ids=torch.arange(n)[None])
|
| 81 |
+
state=torch.randn(1,1,64)
|
| 82 |
+
with torch.inference_mode():
|
| 83 |
+
first=model(**batch,prev_state=state)
|
| 84 |
+
batch['cn_stats'][:,:4]+=2
|
| 85 |
+
second=model(**batch,prev_state=state)
|
| 86 |
+
assert torch.equal(first['next_state'],state) and torch.equal(second['next_state'],state)
|
| 87 |
+
assert first['new_word_mask'].sum()==0
|
| 88 |
+
assert not torch.equal(first['utt_scores'],second['utt_scores'])
|
validation_summary.json
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"status": "LOCAL_VALIDATION_PASS_HUB_VERIFICATION_REQUIRED",
|
| 3 |
+
"created_at": "2026-09-10T10:50:20.386964+00:00",
|
| 4 |
+
"python": "3.10.19",
|
| 5 |
+
"torch": "2.5.1+cpu",
|
| 6 |
+
"platform": "Ubuntu WSL2 on local Windows computer",
|
| 7 |
+
"device": "cpu",
|
| 8 |
+
"dtype": "float32",
|
| 9 |
+
"no_training": true,
|
| 10 |
+
"no_finetuning": true,
|
| 11 |
+
"checkpoint_values_unchanged": true,
|
| 12 |
+
"scorer_equivalence": {
|
| 13 |
+
"status": "PASS",
|
| 14 |
+
"atol": 1e-05,
|
| 15 |
+
"rtol": 1e-05,
|
| 16 |
+
"dtype": "float32",
|
| 17 |
+
"device": "cpu",
|
| 18 |
+
"prefixes": 4,
|
| 19 |
+
"server_torch": "2.3.1+cu121",
|
| 20 |
+
"local_torch": "2.5.1+cpu",
|
| 21 |
+
"max_abs": 3.814697265625e-06,
|
| 22 |
+
"max_mse": 1.655095813488414e-13
|
| 23 |
+
},
|
| 24 |
+
"frontend_real_audio": {
|
| 25 |
+
"model_load_sec": 5.285994583999999,
|
| 26 |
+
"platform": "local Ubuntu WSL2",
|
| 27 |
+
"device": "cpu",
|
| 28 |
+
"dtype": "float32",
|
| 29 |
+
"audios": [
|
| 30 |
+
{
|
| 31 |
+
"name": "real_short",
|
| 32 |
+
"duration_sec": 1.951,
|
| 33 |
+
"sha256": "cfc3105c2ac4db72dbd23ad052261ed812a8d1c51a6c98700d89f45835348cc0",
|
| 34 |
+
"prefixes": 3,
|
| 35 |
+
"valid": 2,
|
| 36 |
+
"updates": 2,
|
| 37 |
+
"statuses": [
|
| 38 |
+
"no_usable_hypothesis",
|
| 39 |
+
"ok",
|
| 40 |
+
"ok"
|
| 41 |
+
],
|
| 42 |
+
"end_to_end_compute_sec": 162.954407101,
|
| 43 |
+
"scorer_compute_sec": 0.01154370499997981
|
| 44 |
+
},
|
| 45 |
+
{
|
| 46 |
+
"name": "real_medium",
|
| 47 |
+
"duration_sec": 2.889,
|
| 48 |
+
"sha256": "165bcc252817fac922eecba9447293fa04d79bb215e05c3eb7934061ed501a58",
|
| 49 |
+
"prefixes": 5,
|
| 50 |
+
"valid": 3,
|
| 51 |
+
"updates": 2,
|
| 52 |
+
"statuses": [
|
| 53 |
+
"no_usable_hypothesis",
|
| 54 |
+
"no_usable_hypothesis",
|
| 55 |
+
"ok",
|
| 56 |
+
"ok",
|
| 57 |
+
"ok"
|
| 58 |
+
],
|
| 59 |
+
"end_to_end_compute_sec": 250.548563628,
|
| 60 |
+
"scorer_compute_sec": 0.007423772000038298
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"name": "real_long",
|
| 64 |
+
"duration_sec": 4.387,
|
| 65 |
+
"sha256": "450eccef92e195845254f9915cb9b28ea6acffe0a2962526af435e29f330f397",
|
| 66 |
+
"prefixes": 7,
|
| 67 |
+
"valid": 4,
|
| 68 |
+
"updates": 2,
|
| 69 |
+
"statuses": [
|
| 70 |
+
"no_usable_hypothesis",
|
| 71 |
+
"no_usable_hypothesis",
|
| 72 |
+
"ok",
|
| 73 |
+
"no_usable_hypothesis",
|
| 74 |
+
"ok",
|
| 75 |
+
"ok",
|
| 76 |
+
"ok"
|
| 77 |
+
],
|
| 78 |
+
"end_to_end_compute_sec": 383.971490372,
|
| 79 |
+
"scorer_compute_sec": 0.008973775000185924
|
| 80 |
+
}
|
| 81 |
+
],
|
| 82 |
+
"status": "PASS",
|
| 83 |
+
"suffix_invariance": "PASS",
|
| 84 |
+
"reset": "PASS",
|
| 85 |
+
"empty_audio": "PASS",
|
| 86 |
+
"silence": "PASS",
|
| 87 |
+
"audio_source": "SpeechOcean762 CC BY 4.0 read speech; fixed availability/duration selection; interface tests only, no accuracy calculation"
|
| 88 |
+
},
|
| 89 |
+
"cli": {
|
| 90 |
+
"status": "PASS",
|
| 91 |
+
"stage": "cli",
|
| 92 |
+
"prefixes": 3,
|
| 93 |
+
"exact_single_stream_match": true,
|
| 94 |
+
"device": "cpu",
|
| 95 |
+
"dtype": "float32"
|
| 96 |
+
},
|
| 97 |
+
"offline": {
|
| 98 |
+
"status": "PASS",
|
| 99 |
+
"stage": "offline",
|
| 100 |
+
"prefixes": 3,
|
| 101 |
+
"exact_single_stream_match": true,
|
| 102 |
+
"device": "cpu",
|
| 103 |
+
"dtype": "float32"
|
| 104 |
+
},
|
| 105 |
+
"valid_prefix_causal_test": {
|
| 106 |
+
"status": "PASS",
|
| 107 |
+
"implementation": "actual fine-tuned Whisper, Charsiu, PCN/prosody and scorer",
|
| 108 |
+
"boundary_samples": 23040,
|
| 109 |
+
"received_samples": 24000,
|
| 110 |
+
"lookahead_seconds": 0.16,
|
| 111 |
+
"prefix_outputs_exact": true,
|
| 112 |
+
"state_hash_exact": true,
|
| 113 |
+
"actual_frontend_samples": {
|
| 114 |
+
"whisper": 23040,
|
| 115 |
+
"charsiu": 23040,
|
| 116 |
+
"prosody": 23040,
|
| 117 |
+
"pcn": 23040
|
| 118 |
+
},
|
| 119 |
+
"prior_history_reused": "one actually executed identical prefix, including original state; no saved prediction substituted for current inference",
|
| 120 |
+
"no_gpu": true
|
| 121 |
+
},
|
| 122 |
+
"failed_synthetic_test": {
|
| 123 |
+
"audio": "local SAPI Good morning",
|
| 124 |
+
"prefixes": 3,
|
| 125 |
+
"statuses": [
|
| 126 |
+
"no_usable_hypothesis",
|
| 127 |
+
"no_usable_hypothesis",
|
| 128 |
+
"no_usable_hypothesis"
|
| 129 |
+
],
|
| 130 |
+
"reason": "frozen Whisper repetition policy; no false zero score emitted"
|
| 131 |
+
},
|
| 132 |
+
"untested": [
|
| 133 |
+
"native Windows",
|
| 134 |
+
"CUDA",
|
| 135 |
+
"assessment accuracy on new recordings",
|
| 136 |
+
"concurrent sessions"
|
| 137 |
+
],
|
| 138 |
+
"hub_verification": "Only a release tag created after fresh-download validation marks a verified release."
|
| 139 |
+
}
|
{whisper_best_model → whisper}/added_tokens.json
RENAMED
|
File without changes
|
{whisper_best_model → whisper}/config.json
RENAMED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
{
|
| 2 |
-
"_name_or_path": "/DATA_2/guest/custom-gopt/server_assets/models/whisper-base",
|
| 3 |
"activation_dropout": 0.0,
|
| 4 |
"activation_function": "gelu",
|
| 5 |
"apply_spec_augment": false,
|
|
|
|
| 1 |
{
|
|
|
|
| 2 |
"activation_dropout": 0.0,
|
| 3 |
"activation_function": "gelu",
|
| 4 |
"apply_spec_augment": false,
|
{whisper_best_model → whisper}/generation_config.json
RENAMED
|
File without changes
|
{whisper_best_model → whisper}/merges.txt
RENAMED
|
File without changes
|
{whisper_best_model → whisper}/model.safetensors
RENAMED
|
File without changes
|
{whisper_best_model → whisper}/normalizer.json
RENAMED
|
File without changes
|
{whisper_best_model → whisper}/preprocessor_config.json
RENAMED
|
File without changes
|