Release prep: Phase 3 LM (checkpoints/phase3/p3_lm_full), versions/voices/settings, auto-tagger, Gradio app, CC-BY-SA-4.0 weights + Apache-2.0 code, model card
Browse files- .gitattributes +11 -0
- LICENSE +427 -201
- LICENSE-CODE +202 -0
- README.md +205 -105
- app.py +140 -0
- assets/dynamic_accent_banner.jpg +3 -0
- checkpoints/phase2/p2_lm_B/spk2id.json +1 -0
- checkpoints/phase3/p3_lm_full/args.json +1 -0
- checkpoints/phase3/p3_lm_full/best.pt +3 -0
- checkpoints/phase3/p3_lm_full/config.json +7 -0
- checkpoints/phase3/p3_lm_full/log.jsonl +211 -0
- checkpoints/phase3/p3_lm_full/spk2id.json +0 -0
- infer.py +276 -63
- prompts/voice_waxal_ibo_5.wav +3 -0
- prompts/voice_waxal_yor_5.wav +3 -0
- prompts/voices.json +41 -0
- requirements.txt +3 -1
- samples/phase3/phase2/custom_dynacc.mp3 +0 -0
- samples/phase3/phase2/ibo_000.mp3 +0 -0
- samples/phase3/phase2/omo_announce.mp3 +0 -0
- samples/phase3/phase2/para_hau_eng_pcm.mp3 +3 -0
- samples/phase3/phase2/para_ibo_pcm_eng.mp3 +3 -0
- samples/phase3/phase2/para_yor_eng.mp3 +3 -0
- samples/phase3/phase3/custom_dynacc.mp3 +0 -0
- samples/phase3/phase3/ibo_000.mp3 +0 -0
- samples/phase3/phase3/omo_announce.mp3 +0 -0
- samples/phase3/phase3/para_hau_eng_pcm.mp3 +3 -0
- samples/phase3/phase3/para_ibo_pcm_eng.mp3 +3 -0
- samples/phase3/phase3/para_yor_eng.mp3 +3 -0
- samples/phase3/phase3_female/custom_dynacc__waxal_yor_5.mp3 +0 -0
- samples/phase3/phase3_female/ibo_000__waxal_ibo_5.mp3 +0 -0
- samples/phase3/phase3_female/omo_announce__waxal_ibo_5.mp3 +0 -0
- samples/phase3/phase3_female/omo_announce__waxal_yor_5.mp3 +0 -0
- samples/phase3/phase3_female/para_ibo_pcm_eng__waxal_ibo_5.mp3 +3 -0
- samples/phase3/phase3_female/para_yor_eng__waxal_yor_5.mp3 +3 -0
- settings.json +47 -0
- tagger.py +348 -0
.gitattributes
CHANGED
|
@@ -40,3 +40,14 @@ prompts/clip3_waxal_yor_yor_1218.wav filter=lfs diff=lfs merge=lfs -text
|
|
| 40 |
samples/prosody_v2/para_hau_eng_pcm.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 41 |
samples/prosody_v2/para_ibo_pcm_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 42 |
samples/prosody_v2/para_yor_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
samples/prosody_v2/para_hau_eng_pcm.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 41 |
samples/prosody_v2/para_ibo_pcm_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 42 |
samples/prosody_v2/para_yor_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
assets/dynamic_accent_banner.jpg filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
prompts/voice_waxal_ibo_5.wav filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
prompts/voice_waxal_yor_5.wav filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
samples/phase3/phase2/para_hau_eng_pcm.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
samples/phase3/phase2/para_ibo_pcm_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
samples/phase3/phase2/para_yor_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
samples/phase3/phase3/para_hau_eng_pcm.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
samples/phase3/phase3/para_ibo_pcm_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
samples/phase3/phase3/para_yor_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 52 |
+
samples/phase3/phase3_female/para_ibo_pcm_eng__waxal_ibo_5.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
samples/phase3/phase3_female/para_yor_eng__waxal_yor_5.mp3 filter=lfs diff=lfs merge=lfs -text
|
LICENSE
CHANGED
|
@@ -1,202 +1,428 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
|
| 2 |
-
Apache License
|
| 3 |
-
Version 2.0, January 2004
|
| 4 |
-
http://www.apache.org/licenses/
|
| 5 |
-
|
| 6 |
-
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
-
|
| 8 |
-
1. Definitions.
|
| 9 |
-
|
| 10 |
-
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
-
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
-
|
| 13 |
-
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
-
the copyright owner that is granting the License.
|
| 15 |
-
|
| 16 |
-
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
-
other entities that control, are controlled by, or are under common
|
| 18 |
-
control with that entity. For the purposes of this definition,
|
| 19 |
-
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
-
direction or management of such entity, whether by contract or
|
| 21 |
-
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
-
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
-
|
| 24 |
-
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
-
exercising permissions granted by this License.
|
| 26 |
-
|
| 27 |
-
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
-
including but not limited to software source code, documentation
|
| 29 |
-
source, and configuration files.
|
| 30 |
-
|
| 31 |
-
"Object" form shall mean any form resulting from mechanical
|
| 32 |
-
transformation or translation of a Source form, including but
|
| 33 |
-
not limited to compiled object code, generated documentation,
|
| 34 |
-
and conversions to other media types.
|
| 35 |
-
|
| 36 |
-
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
-
Object form, made available under the License, as indicated by a
|
| 38 |
-
copyright notice that is included in or attached to the work
|
| 39 |
-
(an example is provided in the Appendix below).
|
| 40 |
-
|
| 41 |
-
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
-
form, that is based on (or derived from) the Work and for which the
|
| 43 |
-
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
-
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
-
of this License, Derivative Works shall not include works that remain
|
| 46 |
-
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
-
the Work and Derivative Works thereof.
|
| 48 |
-
|
| 49 |
-
"Contribution" shall mean any work of authorship, including
|
| 50 |
-
the original version of the Work and any modifications or additions
|
| 51 |
-
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
-
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
-
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
-
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
-
means any form of electronic, verbal, or written communication sent
|
| 56 |
-
to the Licensor or its representatives, including but not limited to
|
| 57 |
-
communication on electronic mailing lists, source code control systems,
|
| 58 |
-
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
-
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
-
excluding communication that is conspicuously marked or otherwise
|
| 61 |
-
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
-
|
| 63 |
-
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
-
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
-
subsequently incorporated within the Work.
|
| 66 |
-
|
| 67 |
-
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
-
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
-
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
-
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
-
Work and such Derivative Works in Source or Object form.
|
| 73 |
-
|
| 74 |
-
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
-
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
-
(except as stated in this section) patent license to make, have made,
|
| 78 |
-
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
-
where such license applies only to those patent claims licensable
|
| 80 |
-
by such Contributor that are necessarily infringed by their
|
| 81 |
-
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
-
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
-
institute patent litigation against any entity (including a
|
| 84 |
-
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
-
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
-
or contributory patent infringement, then any patent licenses
|
| 87 |
-
granted to You under this License for that Work shall terminate
|
| 88 |
-
as of the date such litigation is filed.
|
| 89 |
-
|
| 90 |
-
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
-
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
-
modifications, and in Source or Object form, provided that You
|
| 93 |
-
meet the following conditions:
|
| 94 |
-
|
| 95 |
-
(a) You must give any other recipients of the Work or
|
| 96 |
-
Derivative Works a copy of this License; and
|
| 97 |
-
|
| 98 |
-
(b) You must cause any modified files to carry prominent notices
|
| 99 |
-
stating that You changed the files; and
|
| 100 |
-
|
| 101 |
-
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
-
that You distribute, all copyright, patent, trademark, and
|
| 103 |
-
attribution notices from the Source form of the Work,
|
| 104 |
-
excluding those notices that do not pertain to any part of
|
| 105 |
-
the Derivative Works; and
|
| 106 |
-
|
| 107 |
-
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
-
distribution, then any Derivative Works that You distribute must
|
| 109 |
-
include a readable copy of the attribution notices contained
|
| 110 |
-
within such NOTICE file, excluding those notices that do not
|
| 111 |
-
pertain to any part of the Derivative Works, in at least one
|
| 112 |
-
of the following places: within a NOTICE text file distributed
|
| 113 |
-
as part of the Derivative Works; within the Source form or
|
| 114 |
-
documentation, if provided along with the Derivative Works; or,
|
| 115 |
-
within a display generated by the Derivative Works, if and
|
| 116 |
-
wherever such third-party notices normally appear. The contents
|
| 117 |
-
of the NOTICE file are for informational purposes only and
|
| 118 |
-
do not modify the License. You may add Your own attribution
|
| 119 |
-
notices within Derivative Works that You distribute, alongside
|
| 120 |
-
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
-
that such additional attribution notices cannot be construed
|
| 122 |
-
as modifying the License.
|
| 123 |
-
|
| 124 |
-
You may add Your own copyright statement to Your modifications and
|
| 125 |
-
may provide additional or different license terms and conditions
|
| 126 |
-
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
-
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
-
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
-
the conditions stated in this License.
|
| 130 |
-
|
| 131 |
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
-
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
-
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
-
this License, without any additional terms or conditions.
|
| 135 |
-
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
-
the terms of any separate license agreement you may have executed
|
| 137 |
-
with Licensor regarding such Contributions.
|
| 138 |
-
|
| 139 |
-
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
-
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
-
except as required for reasonable and customary use in describing the
|
| 142 |
-
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
-
|
| 144 |
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
-
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
-
implied, including, without limitation, any warranties or conditions
|
| 149 |
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
-
appropriateness of using or redistributing the Work and assume any
|
| 152 |
-
risks associated with Your exercise of permissions under this License.
|
| 153 |
-
|
| 154 |
-
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
-
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
-
unless required by applicable law (such as deliberate and grossly
|
| 157 |
-
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
-
liable to You for damages, including any direct, indirect, special,
|
| 159 |
-
incidental, or consequential damages of any character arising as a
|
| 160 |
-
result of this License or out of the use or inability to use the
|
| 161 |
-
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
-
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
-
other commercial damages or losses), even if such Contributor
|
| 164 |
-
has been advised of the possibility of such damages.
|
| 165 |
-
|
| 166 |
-
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
-
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
-
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
-
or other liability obligations and/or rights consistent with this
|
| 170 |
-
License. However, in accepting such obligations, You may act only
|
| 171 |
-
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
-
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
-
defend, and hold each Contributor harmless for any liability
|
| 174 |
-
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
-
of your accepting any such warranty or additional liability.
|
| 176 |
-
|
| 177 |
-
END OF TERMS AND CONDITIONS
|
| 178 |
-
|
| 179 |
-
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
-
|
| 181 |
-
To apply the Apache License to your work, attach the following
|
| 182 |
-
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
-
replaced with your own identifying information. (Don't include
|
| 184 |
-
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
-
comment syntax for the file format. We also recommend that a
|
| 186 |
-
file or class name and description of purpose be included on the
|
| 187 |
-
same "printed page" as the copyright notice for easier
|
| 188 |
-
identification within third-party archives.
|
| 189 |
-
|
| 190 |
-
Copyright [yyyy] [name of copyright owner]
|
| 191 |
-
|
| 192 |
-
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
-
you may not use this file except in compliance with the License.
|
| 194 |
-
You may obtain a copy of the License at
|
| 195 |
-
|
| 196 |
-
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
-
|
| 198 |
-
Unless required by applicable law or agreed to in writing, software
|
| 199 |
-
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
-
See the License for the specific language governing permissions and
|
| 202 |
-
limitations under the License.
|
|
|
|
| 1 |
+
Attribution-ShareAlike 4.0 International
|
| 2 |
+
|
| 3 |
+
=======================================================================
|
| 4 |
+
|
| 5 |
+
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
| 6 |
+
does not provide legal services or legal advice. Distribution of
|
| 7 |
+
Creative Commons public licenses does not create a lawyer-client or
|
| 8 |
+
other relationship. Creative Commons makes its licenses and related
|
| 9 |
+
information available on an "as-is" basis. Creative Commons gives no
|
| 10 |
+
warranties regarding its licenses, any material licensed under their
|
| 11 |
+
terms and conditions, or any related information. Creative Commons
|
| 12 |
+
disclaims all liability for damages resulting from their use to the
|
| 13 |
+
fullest extent possible.
|
| 14 |
+
|
| 15 |
+
Using Creative Commons Public Licenses
|
| 16 |
+
|
| 17 |
+
Creative Commons public licenses provide a standard set of terms and
|
| 18 |
+
conditions that creators and other rights holders may use to share
|
| 19 |
+
original works of authorship and other material subject to copyright
|
| 20 |
+
and certain other rights specified in the public license below. The
|
| 21 |
+
following considerations are for informational purposes only, are not
|
| 22 |
+
exhaustive, and do not form part of our licenses.
|
| 23 |
+
|
| 24 |
+
Considerations for licensors: Our public licenses are
|
| 25 |
+
intended for use by those authorized to give the public
|
| 26 |
+
permission to use material in ways otherwise restricted by
|
| 27 |
+
copyright and certain other rights. Our licenses are
|
| 28 |
+
irrevocable. Licensors should read and understand the terms
|
| 29 |
+
and conditions of the license they choose before applying it.
|
| 30 |
+
Licensors should also secure all rights necessary before
|
| 31 |
+
applying our licenses so that the public can reuse the
|
| 32 |
+
material as expected. Licensors should clearly mark any
|
| 33 |
+
material not subject to the license. This includes other CC-
|
| 34 |
+
licensed material, or material used under an exception or
|
| 35 |
+
limitation to copyright. More considerations for licensors:
|
| 36 |
+
wiki.creativecommons.org/Considerations_for_licensors
|
| 37 |
+
|
| 38 |
+
Considerations for the public: By using one of our public
|
| 39 |
+
licenses, a licensor grants the public permission to use the
|
| 40 |
+
licensed material under specified terms and conditions. If
|
| 41 |
+
the licensor's permission is not necessary for any reason--for
|
| 42 |
+
example, because of any applicable exception or limitation to
|
| 43 |
+
copyright--then that use is not regulated by the license. Our
|
| 44 |
+
licenses grant only permissions under copyright and certain
|
| 45 |
+
other rights that a licensor has authority to grant. Use of
|
| 46 |
+
the licensed material may still be restricted for other
|
| 47 |
+
reasons, including because others have copyright or other
|
| 48 |
+
rights in the material. A licensor may make special requests,
|
| 49 |
+
such as asking that all changes be marked or described.
|
| 50 |
+
Although not required by our licenses, you are encouraged to
|
| 51 |
+
respect those requests where reasonable. More considerations
|
| 52 |
+
for the public:
|
| 53 |
+
wiki.creativecommons.org/Considerations_for_licensees
|
| 54 |
+
|
| 55 |
+
=======================================================================
|
| 56 |
+
|
| 57 |
+
Creative Commons Attribution-ShareAlike 4.0 International Public
|
| 58 |
+
License
|
| 59 |
+
|
| 60 |
+
By exercising the Licensed Rights (defined below), You accept and agree
|
| 61 |
+
to be bound by the terms and conditions of this Creative Commons
|
| 62 |
+
Attribution-ShareAlike 4.0 International Public License ("Public
|
| 63 |
+
License"). To the extent this Public License may be interpreted as a
|
| 64 |
+
contract, You are granted the Licensed Rights in consideration of Your
|
| 65 |
+
acceptance of these terms and conditions, and the Licensor grants You
|
| 66 |
+
such rights in consideration of benefits the Licensor receives from
|
| 67 |
+
making the Licensed Material available under these terms and
|
| 68 |
+
conditions.
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
Section 1 -- Definitions.
|
| 72 |
+
|
| 73 |
+
a. Adapted Material means material subject to Copyright and Similar
|
| 74 |
+
Rights that is derived from or based upon the Licensed Material
|
| 75 |
+
and in which the Licensed Material is translated, altered,
|
| 76 |
+
arranged, transformed, or otherwise modified in a manner requiring
|
| 77 |
+
permission under the Copyright and Similar Rights held by the
|
| 78 |
+
Licensor. For purposes of this Public License, where the Licensed
|
| 79 |
+
Material is a musical work, performance, or sound recording,
|
| 80 |
+
Adapted Material is always produced where the Licensed Material is
|
| 81 |
+
synched in timed relation with a moving image.
|
| 82 |
+
|
| 83 |
+
b. Adapter's License means the license You apply to Your Copyright
|
| 84 |
+
and Similar Rights in Your contributions to Adapted Material in
|
| 85 |
+
accordance with the terms and conditions of this Public License.
|
| 86 |
+
|
| 87 |
+
c. BY-SA Compatible License means a license listed at
|
| 88 |
+
creativecommons.org/compatiblelicenses, approved by Creative
|
| 89 |
+
Commons as essentially the equivalent of this Public License.
|
| 90 |
+
|
| 91 |
+
d. Copyright and Similar Rights means copyright and/or similar rights
|
| 92 |
+
closely related to copyright including, without limitation,
|
| 93 |
+
performance, broadcast, sound recording, and Sui Generis Database
|
| 94 |
+
Rights, without regard to how the rights are labeled or
|
| 95 |
+
categorized. For purposes of this Public License, the rights
|
| 96 |
+
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
| 97 |
+
Rights.
|
| 98 |
+
|
| 99 |
+
e. Effective Technological Measures means those measures that, in the
|
| 100 |
+
absence of proper authority, may not be circumvented under laws
|
| 101 |
+
fulfilling obligations under Article 11 of the WIPO Copyright
|
| 102 |
+
Treaty adopted on December 20, 1996, and/or similar international
|
| 103 |
+
agreements.
|
| 104 |
+
|
| 105 |
+
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
| 106 |
+
any other exception or limitation to Copyright and Similar Rights
|
| 107 |
+
that applies to Your use of the Licensed Material.
|
| 108 |
+
|
| 109 |
+
g. License Elements means the license attributes listed in the name
|
| 110 |
+
of a Creative Commons Public License. The License Elements of this
|
| 111 |
+
Public License are Attribution and ShareAlike.
|
| 112 |
+
|
| 113 |
+
h. Licensed Material means the artistic or literary work, database,
|
| 114 |
+
or other material to which the Licensor applied this Public
|
| 115 |
+
License.
|
| 116 |
+
|
| 117 |
+
i. Licensed Rights means the rights granted to You subject to the
|
| 118 |
+
terms and conditions of this Public License, which are limited to
|
| 119 |
+
all Copyright and Similar Rights that apply to Your use of the
|
| 120 |
+
Licensed Material and that the Licensor has authority to license.
|
| 121 |
+
|
| 122 |
+
j. Licensor means the individual(s) or entity(ies) granting rights
|
| 123 |
+
under this Public License.
|
| 124 |
+
|
| 125 |
+
k. Share means to provide material to the public by any means or
|
| 126 |
+
process that requires permission under the Licensed Rights, such
|
| 127 |
+
as reproduction, public display, public performance, distribution,
|
| 128 |
+
dissemination, communication, or importation, and to make material
|
| 129 |
+
available to the public including in ways that members of the
|
| 130 |
+
public may access the material from a place and at a time
|
| 131 |
+
individually chosen by them.
|
| 132 |
+
|
| 133 |
+
l. Sui Generis Database Rights means rights other than copyright
|
| 134 |
+
resulting from Directive 96/9/EC of the European Parliament and of
|
| 135 |
+
the Council of 11 March 1996 on the legal protection of databases,
|
| 136 |
+
as amended and/or succeeded, as well as other essentially
|
| 137 |
+
equivalent rights anywhere in the world.
|
| 138 |
+
|
| 139 |
+
m. You means the individual or entity exercising the Licensed Rights
|
| 140 |
+
under this Public License. Your has a corresponding meaning.
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
Section 2 -- Scope.
|
| 144 |
+
|
| 145 |
+
a. License grant.
|
| 146 |
+
|
| 147 |
+
1. Subject to the terms and conditions of this Public License,
|
| 148 |
+
the Licensor hereby grants You a worldwide, royalty-free,
|
| 149 |
+
non-sublicensable, non-exclusive, irrevocable license to
|
| 150 |
+
exercise the Licensed Rights in the Licensed Material to:
|
| 151 |
+
|
| 152 |
+
a. reproduce and Share the Licensed Material, in whole or
|
| 153 |
+
in part; and
|
| 154 |
+
|
| 155 |
+
b. produce, reproduce, and Share Adapted Material.
|
| 156 |
+
|
| 157 |
+
2. Exceptions and Limitations. For the avoidance of doubt, where
|
| 158 |
+
Exceptions and Limitations apply to Your use, this Public
|
| 159 |
+
License does not apply, and You do not need to comply with
|
| 160 |
+
its terms and conditions.
|
| 161 |
+
|
| 162 |
+
3. Term. The term of this Public License is specified in Section
|
| 163 |
+
6(a).
|
| 164 |
+
|
| 165 |
+
4. Media and formats; technical modifications allowed. The
|
| 166 |
+
Licensor authorizes You to exercise the Licensed Rights in
|
| 167 |
+
all media and formats whether now known or hereafter created,
|
| 168 |
+
and to make technical modifications necessary to do so. The
|
| 169 |
+
Licensor waives and/or agrees not to assert any right or
|
| 170 |
+
authority to forbid You from making technical modifications
|
| 171 |
+
necessary to exercise the Licensed Rights, including
|
| 172 |
+
technical modifications necessary to circumvent Effective
|
| 173 |
+
Technological Measures. For purposes of this Public License,
|
| 174 |
+
simply making modifications authorized by this Section 2(a)
|
| 175 |
+
(4) never produces Adapted Material.
|
| 176 |
+
|
| 177 |
+
5. Downstream recipients.
|
| 178 |
+
|
| 179 |
+
a. Offer from the Licensor -- Licensed Material. Every
|
| 180 |
+
recipient of the Licensed Material automatically
|
| 181 |
+
receives an offer from the Licensor to exercise the
|
| 182 |
+
Licensed Rights under the terms and conditions of this
|
| 183 |
+
Public License.
|
| 184 |
+
|
| 185 |
+
b. Additional offer from the Licensor -- Adapted Material.
|
| 186 |
+
Every recipient of Adapted Material from You
|
| 187 |
+
automatically receives an offer from the Licensor to
|
| 188 |
+
exercise the Licensed Rights in the Adapted Material
|
| 189 |
+
under the conditions of the Adapter's License You apply.
|
| 190 |
+
|
| 191 |
+
c. No downstream restrictions. You may not offer or impose
|
| 192 |
+
any additional or different terms or conditions on, or
|
| 193 |
+
apply any Effective Technological Measures to, the
|
| 194 |
+
Licensed Material if doing so restricts exercise of the
|
| 195 |
+
Licensed Rights by any recipient of the Licensed
|
| 196 |
+
Material.
|
| 197 |
+
|
| 198 |
+
6. No endorsement. Nothing in this Public License constitutes or
|
| 199 |
+
may be construed as permission to assert or imply that You
|
| 200 |
+
are, or that Your use of the Licensed Material is, connected
|
| 201 |
+
with, or sponsored, endorsed, or granted official status by,
|
| 202 |
+
the Licensor or others designated to receive attribution as
|
| 203 |
+
provided in Section 3(a)(1)(A)(i).
|
| 204 |
+
|
| 205 |
+
b. Other rights.
|
| 206 |
+
|
| 207 |
+
1. Moral rights, such as the right of integrity, are not
|
| 208 |
+
licensed under this Public License, nor are publicity,
|
| 209 |
+
privacy, and/or other similar personality rights; however, to
|
| 210 |
+
the extent possible, the Licensor waives and/or agrees not to
|
| 211 |
+
assert any such rights held by the Licensor to the limited
|
| 212 |
+
extent necessary to allow You to exercise the Licensed
|
| 213 |
+
Rights, but not otherwise.
|
| 214 |
+
|
| 215 |
+
2. Patent and trademark rights are not licensed under this
|
| 216 |
+
Public License.
|
| 217 |
+
|
| 218 |
+
3. To the extent possible, the Licensor waives any right to
|
| 219 |
+
collect royalties from You for the exercise of the Licensed
|
| 220 |
+
Rights, whether directly or through a collecting society
|
| 221 |
+
under any voluntary or waivable statutory or compulsory
|
| 222 |
+
licensing scheme. In all other cases the Licensor expressly
|
| 223 |
+
reserves any right to collect such royalties.
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
Section 3 -- License Conditions.
|
| 227 |
+
|
| 228 |
+
Your exercise of the Licensed Rights is expressly made subject to the
|
| 229 |
+
following conditions.
|
| 230 |
+
|
| 231 |
+
a. Attribution.
|
| 232 |
+
|
| 233 |
+
1. If You Share the Licensed Material (including in modified
|
| 234 |
+
form), You must:
|
| 235 |
+
|
| 236 |
+
a. retain the following if it is supplied by the Licensor
|
| 237 |
+
with the Licensed Material:
|
| 238 |
+
|
| 239 |
+
i. identification of the creator(s) of the Licensed
|
| 240 |
+
Material and any others designated to receive
|
| 241 |
+
attribution, in any reasonable manner requested by
|
| 242 |
+
the Licensor (including by pseudonym if
|
| 243 |
+
designated);
|
| 244 |
+
|
| 245 |
+
ii. a copyright notice;
|
| 246 |
+
|
| 247 |
+
iii. a notice that refers to this Public License;
|
| 248 |
+
|
| 249 |
+
iv. a notice that refers to the disclaimer of
|
| 250 |
+
warranties;
|
| 251 |
+
|
| 252 |
+
v. a URI or hyperlink to the Licensed Material to the
|
| 253 |
+
extent reasonably practicable;
|
| 254 |
+
|
| 255 |
+
b. indicate if You modified the Licensed Material and
|
| 256 |
+
retain an indication of any previous modifications; and
|
| 257 |
+
|
| 258 |
+
c. indicate the Licensed Material is licensed under this
|
| 259 |
+
Public License, and include the text of, or the URI or
|
| 260 |
+
hyperlink to, this Public License.
|
| 261 |
+
|
| 262 |
+
2. You may satisfy the conditions in Section 3(a)(1) in any
|
| 263 |
+
reasonable manner based on the medium, means, and context in
|
| 264 |
+
which You Share the Licensed Material. For example, it may be
|
| 265 |
+
reasonable to satisfy the conditions by providing a URI or
|
| 266 |
+
hyperlink to a resource that includes the required
|
| 267 |
+
information.
|
| 268 |
+
|
| 269 |
+
3. If requested by the Licensor, You must remove any of the
|
| 270 |
+
information required by Section 3(a)(1)(A) to the extent
|
| 271 |
+
reasonably practicable.
|
| 272 |
+
|
| 273 |
+
b. ShareAlike.
|
| 274 |
+
|
| 275 |
+
In addition to the conditions in Section 3(a), if You Share
|
| 276 |
+
Adapted Material You produce, the following conditions also apply.
|
| 277 |
+
|
| 278 |
+
1. The Adapter's License You apply must be a Creative Commons
|
| 279 |
+
license with the same License Elements, this version or
|
| 280 |
+
later, or a BY-SA Compatible License.
|
| 281 |
+
|
| 282 |
+
2. You must include the text of, or the URI or hyperlink to, the
|
| 283 |
+
Adapter's License You apply. You may satisfy this condition
|
| 284 |
+
in any reasonable manner based on the medium, means, and
|
| 285 |
+
context in which You Share Adapted Material.
|
| 286 |
+
|
| 287 |
+
3. You may not offer or impose any additional or different terms
|
| 288 |
+
or conditions on, or apply any Effective Technological
|
| 289 |
+
Measures to, Adapted Material that restrict exercise of the
|
| 290 |
+
rights granted under the Adapter's License You apply.
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
Section 4 -- Sui Generis Database Rights.
|
| 294 |
+
|
| 295 |
+
Where the Licensed Rights include Sui Generis Database Rights that
|
| 296 |
+
apply to Your use of the Licensed Material:
|
| 297 |
+
|
| 298 |
+
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
| 299 |
+
to extract, reuse, reproduce, and Share all or a substantial
|
| 300 |
+
portion of the contents of the database;
|
| 301 |
+
|
| 302 |
+
b. if You include all or a substantial portion of the database
|
| 303 |
+
contents in a database in which You have Sui Generis Database
|
| 304 |
+
Rights, then the database in which You have Sui Generis Database
|
| 305 |
+
Rights (but not its individual contents) is Adapted Material,
|
| 306 |
+
including for purposes of Section 3(b); and
|
| 307 |
+
|
| 308 |
+
c. You must comply with the conditions in Section 3(a) if You Share
|
| 309 |
+
all or a substantial portion of the contents of the database.
|
| 310 |
+
|
| 311 |
+
For the avoidance of doubt, this Section 4 supplements and does not
|
| 312 |
+
replace Your obligations under this Public License where the Licensed
|
| 313 |
+
Rights include other Copyright and Similar Rights.
|
| 314 |
+
|
| 315 |
+
|
| 316 |
+
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
| 317 |
+
|
| 318 |
+
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
| 319 |
+
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
| 320 |
+
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
| 321 |
+
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
| 322 |
+
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
| 323 |
+
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
| 324 |
+
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
| 325 |
+
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
| 326 |
+
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
| 327 |
+
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
| 328 |
+
|
| 329 |
+
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
| 330 |
+
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
| 331 |
+
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
| 332 |
+
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
| 333 |
+
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
| 334 |
+
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
| 335 |
+
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
| 336 |
+
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
| 337 |
+
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
| 338 |
+
|
| 339 |
+
c. The disclaimer of warranties and limitation of liability provided
|
| 340 |
+
above shall be interpreted in a manner that, to the extent
|
| 341 |
+
possible, most closely approximates an absolute disclaimer and
|
| 342 |
+
waiver of all liability.
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
Section 6 -- Term and Termination.
|
| 346 |
+
|
| 347 |
+
a. This Public License applies for the term of the Copyright and
|
| 348 |
+
Similar Rights licensed here. However, if You fail to comply with
|
| 349 |
+
this Public License, then Your rights under this Public License
|
| 350 |
+
terminate automatically.
|
| 351 |
+
|
| 352 |
+
b. Where Your right to use the Licensed Material has terminated under
|
| 353 |
+
Section 6(a), it reinstates:
|
| 354 |
+
|
| 355 |
+
1. automatically as of the date the violation is cured, provided
|
| 356 |
+
it is cured within 30 days of Your discovery of the
|
| 357 |
+
violation; or
|
| 358 |
+
|
| 359 |
+
2. upon express reinstatement by the Licensor.
|
| 360 |
+
|
| 361 |
+
For the avoidance of doubt, this Section 6(b) does not affect any
|
| 362 |
+
right the Licensor may have to seek remedies for Your violations
|
| 363 |
+
of this Public License.
|
| 364 |
+
|
| 365 |
+
c. For the avoidance of doubt, the Licensor may also offer the
|
| 366 |
+
Licensed Material under separate terms or conditions or stop
|
| 367 |
+
distributing the Licensed Material at any time; however, doing so
|
| 368 |
+
will not terminate this Public License.
|
| 369 |
+
|
| 370 |
+
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
| 371 |
+
License.
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
Section 7 -- Other Terms and Conditions.
|
| 375 |
+
|
| 376 |
+
a. The Licensor shall not be bound by any additional or different
|
| 377 |
+
terms or conditions communicated by You unless expressly agreed.
|
| 378 |
+
|
| 379 |
+
b. Any arrangements, understandings, or agreements regarding the
|
| 380 |
+
Licensed Material not stated herein are separate from and
|
| 381 |
+
independent of the terms and conditions of this Public License.
|
| 382 |
+
|
| 383 |
+
|
| 384 |
+
Section 8 -- Interpretation.
|
| 385 |
+
|
| 386 |
+
a. For the avoidance of doubt, this Public License does not, and
|
| 387 |
+
shall not be interpreted to, reduce, limit, restrict, or impose
|
| 388 |
+
conditions on any use of the Licensed Material that could lawfully
|
| 389 |
+
be made without permission under this Public License.
|
| 390 |
+
|
| 391 |
+
b. To the extent possible, if any provision of this Public License is
|
| 392 |
+
deemed unenforceable, it shall be automatically reformed to the
|
| 393 |
+
minimum extent necessary to make it enforceable. If the provision
|
| 394 |
+
cannot be reformed, it shall be severed from this Public License
|
| 395 |
+
without affecting the enforceability of the remaining terms and
|
| 396 |
+
conditions.
|
| 397 |
+
|
| 398 |
+
c. No term or condition of this Public License will be waived and no
|
| 399 |
+
failure to comply consented to unless expressly agreed to by the
|
| 400 |
+
Licensor.
|
| 401 |
+
|
| 402 |
+
d. Nothing in this Public License constitutes or may be interpreted
|
| 403 |
+
as a limitation upon, or waiver of, any privileges and immunities
|
| 404 |
+
that apply to the Licensor or You, including from the legal
|
| 405 |
+
processes of any jurisdiction or authority.
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
=======================================================================
|
| 409 |
+
|
| 410 |
+
Creative Commons is not a party to its public
|
| 411 |
+
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
| 412 |
+
its public licenses to material it publishes and in those instances
|
| 413 |
+
will be considered the “Licensor.” The text of the Creative Commons
|
| 414 |
+
public licenses is dedicated to the public domain under the CC0 Public
|
| 415 |
+
Domain Dedication. Except for the limited purpose of indicating that
|
| 416 |
+
material is shared under a Creative Commons public license or as
|
| 417 |
+
otherwise permitted by the Creative Commons policies published at
|
| 418 |
+
creativecommons.org/policies, Creative Commons does not authorize the
|
| 419 |
+
use of the trademark "Creative Commons" or any other trademark or logo
|
| 420 |
+
of Creative Commons without its prior written consent including,
|
| 421 |
+
without limitation, in connection with any unauthorized modifications
|
| 422 |
+
to any of its public licenses or any other arrangements,
|
| 423 |
+
understandings, or agreements concerning use of licensed material. For
|
| 424 |
+
the avoidance of doubt, this paragraph does not form part of the
|
| 425 |
+
public licenses.
|
| 426 |
+
|
| 427 |
+
Creative Commons may be contacted at creativecommons.org.
|
| 428 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LICENSE-CODE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright [yyyy] [name of copyright owner]
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
license:
|
| 3 |
language:
|
| 4 |
- en
|
| 5 |
- pcm
|
|
@@ -8,177 +8,277 @@ language:
|
|
| 8 |
- ha
|
| 9 |
base_model: FunAudioLLM/CosyVoice2-0.5B
|
| 10 |
pipeline_tag: text-to-speech
|
|
|
|
| 11 |
tags:
|
| 12 |
- text-to-speech
|
| 13 |
- code-switching
|
| 14 |
- nigerian-languages
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
- cosyvoice2
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
---
|
| 18 |
|
| 19 |
-
|
| 20 |
|
| 21 |
-
|
| 22 |
|
| 23 |
-
|
| 24 |
-
- per-token **language embeddings**, a **speaker token** and an adversarial (GRL) speaker classifier on the LM, fine-tuned on about 120 h of Nigerian-language and code-switched speech with pause-normalised data (pause profile B);
|
| 25 |
-
- in-context **anchor prompts** at the LM and the flow, so prosody and pause style follow the anchor voice (WAXAL Yoruba speaker 4);
|
| 26 |
-
- a **flow-matching decoder fine-tuned on the anchor voice** (anchor SFT) for tone and pitch detail.
|
| 27 |
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
-
|
| 31 |
|
| 32 |
-
##
|
| 33 |
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
| 37 |
-
|
|
| 38 |
-
| `checkpoints/
|
| 39 |
-
| `
|
| 40 |
-
|
| 41 |
-
|
|
| 42 |
-
|
|
| 43 |
-
| `
|
|
|
|
|
|
|
| 44 |
|
| 45 |
-
|
| 46 |
|
| 47 |
-
## Setup (single GPU
|
| 48 |
|
| 49 |
```bash
|
| 50 |
# 1. CosyVoice code (the commit the model was built and tested on)
|
| 51 |
git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git
|
| 52 |
cd CosyVoice && git checkout 074ca6dc9e80a2f424f1f74b48bdd7d3fea531cc && git submodule update --init --recursive && cd ..
|
| 53 |
|
| 54 |
-
# 2. This repo
|
| 55 |
-
huggingface-cli login
|
| 56 |
huggingface-cli download Modularcomputing/dynamic-accent-preview --local-dir dynamic-accent-preview
|
| 57 |
|
| 58 |
# 3. Python deps (Python 3.10; on Colab keep the preinstalled torch/torchaudio)
|
| 59 |
pip install -r dynamic-accent-preview/requirements.txt
|
| 60 |
```
|
| 61 |
|
| 62 |
-
The base model downloads to `
|
| 63 |
-
|
| 64 |
-
The 0.5B model should fit comfortably on a 16 GB T4. This build was tested on an H100 only, not yet on Colab.
|
| 65 |
|
| 66 |
## Usage
|
| 67 |
|
| 68 |
```bash
|
| 69 |
cd dynamic-accent-preview
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
--seed 0 --out out.wav # defaults: --pause_mode model --speed 1.0
|
| 73 |
-
# experimental prosody v2: add --pause_mode clause --speed 1.05
|
| 74 |
-
```
|
| 75 |
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
-
|
| 79 |
-
- **`--speed`** (default 1.0): a pitch-preserving tempo factor (WSOLA via `audiotsm`) applied to the speech only, so the gaps stay as set. The allowed range is 1.0–1.2.
|
| 80 |
-
- **`--pause_mode model --speed 1.0`** reproduces the Phase 2 final system: model-generated pauses, sentence-by-sentence generation, internal silences capped at 0.6 s, and 0.6 s between sentences. Both modes use anchor prompt clip 0 at the LM and flow (`--prompt_clip 0`).
|
| 81 |
-
- **`--dtype`:** the LM ran under bf16 autocast. T4 has no bf16, so `auto` uses fp16 there. fp16 has not been tested yet; if a T4 run sounds wrong, compare against an A100 (bf16) run.
|
| 82 |
-
- **Determinism:** generation is not bit-reproducible across runs on GPU. Sampling under bf16 can pick a different token on near-ties, so the same seed can give a slightly different take.
|
| 83 |
|
| 84 |
-
|
|
|
|
| 85 |
|
| 86 |
-
|
| 87 |
-
from infer import DynamicAccent
|
| 88 |
-
tts = DynamicAccent("pretrained/CosyVoice2-0.5B", "../CosyVoice",
|
| 89 |
-
"checkpoints/p2_lm_B/best.pt", "checkpoints/p2_flow_sft/best.pt", "prompts/prompts.json")
|
| 90 |
-
wav = tts.say("<hau>Ina kwana, yaya aiki?</hau> <eng>The meeting has been moved to Friday morning.</eng>",
|
| 91 |
-
seed=0, pause_mode="model", speed=1.0)
|
| 92 |
-
import soundfile as sf; sf.write("hau_eng.wav", wav, tts.sr)
|
| 93 |
```
|
| 94 |
|
| 95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
|
| 97 |
```text
|
| 98 |
<eng>this is dynamic accent,</eng> <pcm>e dey sound nice abi?</pcm>
|
|
|
|
| 99 |
<yor>Ẹ káàárọ̀ o, ṣé dáadáa ni?</yor> <eng>I will send you the report this afternoon.</eng>
|
| 100 |
-
<ibo>Kedu ka ị mere?</ibo> <pcm>Abeg no vex, I go call you for evening.</pcm>
|
| 101 |
<hau>Ina kwana, yaya aiki?</hau> <eng>The meeting has been moved to Friday morning.</eng>
|
| 102 |
<ibo>Ndewo nụ, ụmụnna m.</ibo> <pcm>Una well done o, I know say the road no easy.</pcm> <eng>We have three things to discuss this evening.</eng>
|
| 103 |
-
<
|
| 104 |
```
|
| 105 |
|
| 106 |
-
|
| 107 |
|
| 108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
|
| 110 |
-
|
| 111 |
-
- `samples/prosody_v2/*.mp3`: the same custom sentence plus `para_ibo_pcm_eng`, `para_yor_eng`, `para_hau_eng_pcm`, `ibo_000` and `yor_000`, rendered with experimental prosody v2 (`--pause_mode clause --speed 1.05`, seed 0). The user preferred the original.
|
| 112 |
|
| 113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
|
| 115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
|
| 117 |
-
|
| 118 |
-
|---|---|---|---|---|---|---|
|
| 119 |
-
| reference speech (syl/s) | 4.45 | 4.78 (WAXAL, other speakers) | 4.73 | 5.71 | 3.87 | 4.53 (FLEURS) |
|
| 120 |
-
| Phase 2 final system (syl/s) | 4.20 (yor) | 4.20 | 4.50 | 3.98 | 3.63 | 4.77 |
|
| 121 |
-
| reference ÷ system | 1.06 | 1.14 | 1.05 | 1.43 | 1.06 | 0.95 |
|
| 122 |
|
| 123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
|
| 125 |
-
|
| 126 |
|
| 127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
|---|---|---|---|---|---|---|---|---|
|
| 129 |
-
|
|
| 130 |
-
|
|
| 131 |
-
|
|
| 132 |
-
| after: clause, speed 1.05 (experimental) | 0.275 (≈0.37 *) | 0.550 | 0.086 | 4.18 | 0.193 | 0.143 | 0.207 | 0.750 |
|
| 133 |
-
| clause, speed 1.10 | 0.315 | 0.550 | 0.067 | 4.37 | 0.244 | 0.194 | 0.224 | 0.748 |
|
| 134 |
-
| model pauses, speed 1.05 | 0.235 | 0.441 | 0.029 | 4.35 | 0.189 | 0.149 | 0.188 | 0.788 |
|
| 135 |
|
| 136 |
-
|
| 137 |
|
| 138 |
-
|
| 139 |
-
-
|
| 140 |
-
|
|
|
|
|
|
|
| 141 |
|
| 142 |
-
|
| 143 |
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
|
| 146 |
-
|
| 147 |
-
|---|---|---|---|---|---|---|---|---|---|---|
|
| 148 |
-
| Phase 1 Arm B (smoke) | 0.212 | 0.244 | 0.407 (0.294) | 0.412 | 0.035 | 0.201 | 0.195 | 0.804 | 0.030 | 0.649 |
|
| 149 |
-
| p2_lm (profile A) + SFT flow | 0.199 | 0.183 | 0.223 (0.140) | 0.190 | 0.038 | 0.184 | 0.176 | 0.769 | 0.069 | 0.634 |
|
| 150 |
-
| **p2_lm_B (profile B) + SFT flow (this release)** | 0.188 | 0.188 | 0.224 (0.137) | 0.174 | 0.034 | 0.167 | 0.173 | 0.782 | 0.039 | 0.642 |
|
| 151 |
|
| 152 |
-
|
| 153 |
|
| 154 |
-
|
| 155 |
-
|---|---|---|---|---|---|---|---|---|---|---|
|
| 156 |
-
| **real anchor recordings** (WAXAL val+test, raw) | 1.071 | 0.624 | 0.137 | 0.417 | 0 | 0.543 | – | 3.152 | 10.173 | 0.750 (2990) |
|
| 157 |
-
| Phase 1 Arm B (smoke) | 1.334 | 0.584 | 0.044 | 0.245 | 0.147 | 0.315 | 1.035 | 3.058 | 9.999 | 0.777 (251) |
|
| 158 |
-
| p2_lm (profile A) + SFT flow | 0.414 | 0.328 | 0.008 | 0.263 | 0.330 | 0.509 | 0.547 | 3.038 | 10.069 | 0.752 (254) |
|
| 159 |
-
| **p2_lm_B (profile B) + SFT flow (this release)** | 0.460 | 0.288 | 0.087 | 0.251 | 0.262 | 0.488 | 0.531 | 3.057 | 10.134 | 0.749 (255) |
|
| 160 |
|
| 161 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
|
| 163 |
-
|
| 164 |
|
| 165 |
-
|
| 166 |
-
|
|
|
|
|
|
|
|
|
|
| 167 |
- English after a Nigerian-language span keeps a strong local accent.
|
| 168 |
-
-
|
| 169 |
-
-
|
| 170 |
-
-
|
|
|
|
| 171 |
|
| 172 |
-
##
|
| 173 |
|
| 174 |
-
|
| 175 |
-
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
-
|
| 179 |
-
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
|
| 182 |
## Licence
|
| 183 |
|
| 184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
license: cc-by-sa-4.0
|
| 3 |
language:
|
| 4 |
- en
|
| 5 |
- pcm
|
|
|
|
| 8 |
- ha
|
| 9 |
base_model: FunAudioLLM/CosyVoice2-0.5B
|
| 10 |
pipeline_tag: text-to-speech
|
| 11 |
+
library_name: pytorch
|
| 12 |
tags:
|
| 13 |
- text-to-speech
|
| 14 |
- code-switching
|
| 15 |
- nigerian-languages
|
| 16 |
+
- igbo
|
| 17 |
+
- yoruba
|
| 18 |
+
- hausa
|
| 19 |
+
- nigerian-pidgin
|
| 20 |
- cosyvoice2
|
| 21 |
+
datasets:
|
| 22 |
+
- google/WaxalNLP
|
| 23 |
+
- McGill-NLP/NaijaS2ST
|
| 24 |
+
- AfriSpeech/open-bible-speech-african
|
| 25 |
+
- nkowaokwu/ibo-dict
|
| 26 |
+
- google/fleurs
|
| 27 |
---
|
| 28 |
|
| 29 |
+
<p align="center"><img src="assets/dynamic_accent_banner.jpg" width="600"/></p>
|
| 30 |
|
| 31 |
+
# Dynamic Accent: Code-switching TTS
|
| 32 |
|
| 33 |
+
**Code-switching TTS for Nigerian languages.** English, Nigerian Pidgin, Igbo, Yoruba and Hausa, mixed freely inside one sentence and spoken by one consistent voice, with no model swapping between languages.
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
+
Dynamic Accent is a fine-tune of [FunAudioLLM/CosyVoice2-0.5B](https://huggingface.co/FunAudioLLM/CosyVoice2-0.5B) by Modular. It adds:
|
| 36 |
+
- per-token **language embeddings**, a **speaker token** and an adversarial (gradient-reversal) speaker classifier on the LM, so the voice stays the same across a language switch (after Zhang et al., Google, 2019, *Learning to Speak Fluently in a Foreign Language*);
|
| 37 |
+
- training on about 178 h of Nigerian-language and code-switched speech, including about 102 h of Igbo;
|
| 38 |
+
- learned `[pause]`/`[breath]` events and a speaking-rate instruction (Phase 3);
|
| 39 |
+
- a **flow-matching decoder fine-tuned on the anchor voice** for tone and pitch detail.
|
| 40 |
|
| 41 |
+
It is a research release, not a production system. Read **Limitations** before you use it.
|
| 42 |
|
| 43 |
+
## Versions and voices
|
| 44 |
|
| 45 |
+
Two model versions ship side by side. Pick one with `--version`, or render both with `--compare` and A/B before use.
|
| 46 |
+
|
| 47 |
+
| version | LM | flow | decoding | what changed |
|
| 48 |
+
|---|---|---|---|---|
|
| 49 |
+
| `phase3` (**default**) | `checkpoints/phase3/p3_lm_full` (Phase 2 LM + 5,000 steps on a 178 h re-cut with ~102 h Igbo, `[pause]`/`[breath]` tags and a speed instruction, rate `normal`) | shared `checkpoints/phase2/p2_flow_sft` | one pass per paragraph, silence-aware repetition check, no audio post-processing | lower CER in Igbo/Hausa/Yoruba/code-switch/paragraphs, comma pauses at the anchor's length, clipped endings 63% → 11% |
|
| 50 |
+
| `phase2` | `checkpoints/phase2/p2_lm_B` (~120 h, pause profile B) | `checkpoints/phase2/p2_flow_sft` | sentence by sentence, internal silences capped at 0.6 s | the Phase 2 final system |
|
| 51 |
+
|
| 52 |
+
| voice (`--voice`) | who | notes |
|
| 53 |
+
|---|---|---|
|
| 54 |
+
| `anchor_male` (default) | WAXAL Yoruba speaker 4, male | the voice both versions were trained around |
|
| 55 |
+
| `waxal_ibo_5_female` | WAXAL Igbo speaker 5, female, native Igbo | zero-shot (prompt clip, no fine-tune); best CER of the three on the female test subset |
|
| 56 |
+
| `waxal_yor_5_female` | WAXAL Yoruba speaker 5, female, native Yoruba | zero-shot; strongest identity match, but its 3.8 s prompt has no pauses, so pauses are short and endings often clipped |
|
| 57 |
|
| 58 |
+
**Recommended pairing** (author's listening verdict): **Phase 3 sounds best with the female voices; Phase 2 is fine for the male anchor.** `infer.py` prints a note when you pick another pairing. The female voices were evaluated with `phase3` only; they run with `phase2` but are untested there. Settings live in `settings.json`.
|
| 59 |
|
| 60 |
+
## Setup (single GPU)
|
| 61 |
|
| 62 |
```bash
|
| 63 |
# 1. CosyVoice code (the commit the model was built and tested on)
|
| 64 |
git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git
|
| 65 |
cd CosyVoice && git checkout 074ca6dc9e80a2f424f1f74b48bdd7d3fea531cc && git submodule update --init --recursive && cd ..
|
| 66 |
|
| 67 |
+
# 2. This repo
|
|
|
|
| 68 |
huggingface-cli download Modularcomputing/dynamic-accent-preview --local-dir dynamic-accent-preview
|
| 69 |
|
| 70 |
# 3. Python deps (Python 3.10; on Colab keep the preinstalled torch/torchaudio)
|
| 71 |
pip install -r dynamic-accent-preview/requirements.txt
|
| 72 |
```
|
| 73 |
|
| 74 |
+
The stock base model `FunAudioLLM/CosyVoice2-0.5B` (tokenizer, vocoder, speech tokenizer, speaker encoder) downloads to `pretrained/CosyVoice2-0.5B` on first run; nothing in it needs changing. Point `--model_dir` (or `COSYVOICE2_DIR`) at an existing copy, and `--cosyvoice_dir` (or `COSYVOICE_REPO`) at your CosyVoice clone. A 16 GB GPU is enough for the CLI; the Gradio app keeps both versions loaded. Tested on an H100 (bf16). `infer.py` also runs on CPU in fp32, which is slow. T4-class GPUs fall back to fp16, which has not been tested.
|
|
|
|
|
|
|
| 75 |
|
| 76 |
## Usage
|
| 77 |
|
| 78 |
```bash
|
| 79 |
cd dynamic-accent-preview
|
| 80 |
+
# default: --version phase3 --voice anchor_male
|
| 81 |
+
python infer.py --cosyvoice_dir ../CosyVoice --text "<eng>this is dynamic accent,</eng> <pcm>e dey sound nice abi?</pcm>" --out out.wav
|
|
|
|
|
|
|
|
|
|
| 82 |
|
| 83 |
+
# recommended pairing
|
| 84 |
+
python infer.py --cosyvoice_dir ../CosyVoice --version phase3 --voice waxal_ibo_5_female \
|
| 85 |
+
--text "<ibo>Kedu ka ị mere?</ibo> <pcm>Abeg no vex, I go call you for evening.</pcm>" --out ibo_f.wav
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
+
# A/B: the same text, seed and voice through both versions -> cmp_phase2.wav, cmp_phase3.wav
|
| 88 |
+
python infer.py --cosyvoice_dir ../CosyVoice --compare --voice anchor_male --text "..." --out cmp.wav
|
| 89 |
|
| 90 |
+
python infer.py --list_voices # voices, versions, recommended pairing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
```
|
| 92 |
|
| 93 |
+
| flag | what it does |
|
| 94 |
+
|---|---|
|
| 95 |
+
| `--text` | the text: tagged (below) or plain with `--auto_tag` |
|
| 96 |
+
| `--version phase2\|phase3` | model version (default `phase3`) |
|
| 97 |
+
| `--voice anchor_male\|waxal_ibo_5_female\|waxal_yor_5_female` | voice (default `anchor_male`); old ids `anchor`, `waxal_ibo_5`, `waxal_yor_5` still work |
|
| 98 |
+
| `--list_voices` | list voices, versions and the recommended pairing |
|
| 99 |
+
| `--compare` | render with both versions → `<out>_phase2.wav`, `<out>_phase3.wav` |
|
| 100 |
+
| `--rate default\|none\|very slow\|slow\|normal\|fast\|very fast` | Phase 3 speaking-rate instruction to the LM (default: the version's setting, `normal`). It is a learned instruction, not time-stretching. `phase2` ignores it |
|
| 101 |
+
| `--auto_tag` | tag untagged mixed text automatically (see below), print the tagged text, then synthesise |
|
| 102 |
+
| `--tag_only` | with `--auto_tag`: print the tagged text and stop, so you can edit it and pass it back as `--text` |
|
| 103 |
+
| `--force_lang eng\|pcm\|ibo\|yor\|hau` | read the whole text in one language (tags are ignored) |
|
| 104 |
+
| `--lang_map "omo=pcm,sha=pcm"` | per-word language overrides for the tagger |
|
| 105 |
+
| `--lid none\|glotlid` | with `--auto_tag`: add [GlotLID v3](https://huggingface.co/cis-lmu/glotlid) clause scores (Apache-2.0 plus notices, 1.7 GB, `pip install fasttext`) |
|
| 106 |
+
| `--seed N` | sampling seed (default 0). Try 2–3 seeds and keep the take you like |
|
| 107 |
+
| `--out file.wav` | output path (24 kHz WAV) |
|
| 108 |
+
| `--dtype auto\|bf16\|fp16\|fp32` | LM autocast dtype on GPU (samples: bf16). CPU always runs fp32 |
|
| 109 |
+
| `--stitch` | `phase3`: sentence by sentence instead of one pass (not recommended) |
|
| 110 |
+
| `--prompt_clip 0-3` | which anchor prompt clip (released systems: 0) |
|
| 111 |
+
| `--model_dir`, `--cosyvoice_dir`, `--lm`, `--flow`, `--prompts`, `--voices` | paths and checkpoint overrides |
|
| 112 |
+
| `--pause_mode clause`, `--speed` | `phase2` only: the experimental "prosody v2" (fixed gaps plus WSOLA speed-up). A listening test rejected it; the defaults (`model`, `1.0`) are the real Phase 2 system |
|
| 113 |
+
|
| 114 |
+
Generation on GPU is not bit-reproducible: bf16 sampling can pick a different token on near-ties, so the same seed can give a slightly different take.
|
| 115 |
+
|
| 116 |
+
### Controlling code-switching
|
| 117 |
+
|
| 118 |
+
**1. Explicit tags (most control).** Wrap each span in `<eng>`, `<pcm>`, `<ibo>`, `<yor>` or `<hau>`. Keep punctuation inside the span it belongs to and put a space between spans. Untagged text is read as English.
|
| 119 |
|
| 120 |
```text
|
| 121 |
<eng>this is dynamic accent,</eng> <pcm>e dey sound nice abi?</pcm>
|
| 122 |
+
<pcm>omo,</pcm> <eng>I'm very excited to announce this new model,</eng> <ibo>ọ na-eme m obi ụtọ,</ibo> <pcm>I no go lie give you</pcm>
|
| 123 |
<yor>Ẹ káàárọ̀ o, ṣé dáadáa ni?</yor> <eng>I will send you the report this afternoon.</eng>
|
|
|
|
| 124 |
<hau>Ina kwana, yaya aiki?</hau> <eng>The meeting has been moved to Friday morning.</eng>
|
| 125 |
<ibo>Ndewo nụ, ụmụnna m.</ibo> <pcm>Una well done o, I know say the road no easy.</pcm> <eng>We have three things to discuss this evening.</eng>
|
| 126 |
+
<eng>Please tell everyone that</eng> <yor>a ó pàdé ní ọ̀la.</yor>
|
| 127 |
```
|
| 128 |
|
| 129 |
+
A switch can fall mid-sentence (`<eng>Please tell everyone that</eng> <yor>a ó pàdé ní ọ̀la.</yor>`). The tag sets the pronunciation and accent of the words inside it; the voice stays the same.
|
| 130 |
|
| 131 |
+
**2. `--auto_tag` for untagged text.** `tagger.py` does word- and span-level language ID: Yoruba/Igbo/Hausa letters (ẹ ṣ / ị ụ ṅ / ɓ ɗ ƙ ƴ), small lexicons of frequent words, Pidgin markers ("dey", "abi", "omo", "wetin", "abeg", "una", "no go", "e don", "know say", pronoun + "go" + verb …) and clause context for ambiguous words ("na", "o", "ka", "ya"). It prints the tagged text so you can check and edit it:
|
| 132 |
+
|
| 133 |
+
```bash
|
| 134 |
+
python infer.py --auto_tag --tag_only --text "omo, I'm very excited to announce this new model, ọ na-eme m obi ụtọ, I no go lie give you"
|
| 135 |
+
# [tagged] <pcm>omo,</pcm> <eng>I'm very excited to announce this new model,</eng> <ibo>ọ na-eme m obi ụtọ,</ibo> <pcm>I no go lie give you</pcm>
|
| 136 |
+
python infer.py --auto_tag --text "..." --out out.wav # tag, print, synthesise
|
| 137 |
+
python tagger.py "Kedu ka ị mere? Abeg no vex, I go call you for evening." # tagger on its own
|
| 138 |
+
```
|
| 139 |
+
|
| 140 |
+
Write Yoruba and Igbo with their diacritics where you can; text without diacritics is much harder to identify. See the tagger accuracy below.
|
| 141 |
+
|
| 142 |
+
**3. `--force_lang`** reads everything in one language, e.g. `--force_lang ibo`.
|
| 143 |
+
|
| 144 |
+
**4. `--lang_map`** fixes words the tagger gets wrong, e.g. `--lang_map "omo=pcm,sha=pcm,oga=pcm"`.
|
| 145 |
|
| 146 |
+
### Gradio app (local)
|
|
|
|
| 147 |
|
| 148 |
+
```bash
|
| 149 |
+
python app.py --cosyvoice_dir ../CosyVoice # http://127.0.0.1:7860 (--share for a public link)
|
| 150 |
+
```
|
| 151 |
+
|
| 152 |
+
It has a text box, an auto-tag toggle with an editable tagged-text preview, word overrides, a force-language option, version, voice and rate dropdowns, a seed, and a **Compare** button that plays Phase 2 and Phase 3 side by side.
|
| 153 |
+
|
| 154 |
+
### From Python
|
| 155 |
|
| 156 |
+
```python
|
| 157 |
+
import types, soundfile as sf, infer
|
| 158 |
+
a = types.SimpleNamespace(model_dir="pretrained/CosyVoice2-0.5B", cosyvoice_dir="../CosyVoice", lm="", flow="",
|
| 159 |
+
prompts="prompts/prompts.json", voices="prompts/voices.json", dtype="auto", stitch=False,
|
| 160 |
+
rate="default", voice="waxal_ibo_5_female")
|
| 161 |
+
tts = infer.build("phase3", a)
|
| 162 |
+
wav = tts.say("<ibo>Kedu ka ị mere?</ibo> <eng>The meeting has been moved to Friday morning.</eng>", seed=0)
|
| 163 |
+
sf.write("out.wav", wav, tts.sr)
|
| 164 |
+
```
|
| 165 |
+
|
| 166 |
+
## Samples
|
| 167 |
|
| 168 |
+
Seed 0, rendered with `infer.py`. Inputs: `para_ibo_pcm_eng`, `para_yor_eng`, `para_hau_eng_pcm` (code-switched paragraphs), `ibo_000` (Igbo), `custom_dynacc` ("this is dynamic accent, e dey sound nice abi?") and `omo_announce` ("omo, I'm very excited to announce this new model, ọ na-eme m obi ụtọ, I no go lie give you").
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
|
| 170 |
+
| input | Phase 2, anchor_male | Phase 3, anchor_male | Phase 3, female |
|
| 171 |
+
|---|---|---|---|
|
| 172 |
+
| para_ibo_pcm_eng | [mp3](samples/phase3/phase2/para_ibo_pcm_eng.mp3) | [mp3](samples/phase3/phase3/para_ibo_pcm_eng.mp3) | [waxal_ibo_5_female](samples/phase3/phase3_female/para_ibo_pcm_eng__waxal_ibo_5.mp3) |
|
| 173 |
+
| para_yor_eng | [mp3](samples/phase3/phase2/para_yor_eng.mp3) | [mp3](samples/phase3/phase3/para_yor_eng.mp3) | [waxal_yor_5_female](samples/phase3/phase3_female/para_yor_eng__waxal_yor_5.mp3) |
|
| 174 |
+
| para_hau_eng_pcm | [mp3](samples/phase3/phase2/para_hau_eng_pcm.mp3) | [mp3](samples/phase3/phase3/para_hau_eng_pcm.mp3) | – |
|
| 175 |
+
| ibo_000 | [mp3](samples/phase3/phase2/ibo_000.mp3) | [mp3](samples/phase3/phase3/ibo_000.mp3) | [waxal_ibo_5_female](samples/phase3/phase3_female/ibo_000__waxal_ibo_5.mp3) |
|
| 176 |
+
| custom_dynacc | [mp3](samples/phase3/phase2/custom_dynacc.mp3) | [mp3](samples/phase3/phase3/custom_dynacc.mp3) | [waxal_yor_5_female](samples/phase3/phase3_female/custom_dynacc__waxal_yor_5.mp3) |
|
| 177 |
+
| omo_announce | [mp3](samples/phase3/phase2/omo_announce.mp3) | [mp3](samples/phase3/phase3/omo_announce.mp3) | [waxal_ibo_5_female](samples/phase3/phase3_female/omo_announce__waxal_ibo_5.mp3), [waxal_yor_5_female](samples/phase3/phase3_female/omo_announce__waxal_yor_5.mp3) |
|
| 178 |
|
| 179 |
+
Older renders: `samples/pcm_eng_dynamic_accent_seed{0,1,2}.mp3` (Phase 2, three seeds) and `samples/prosody_v2/` (the rejected prosody-v2 post-processing, kept for reference).
|
| 180 |
|
| 181 |
+
## Evaluation: Phase 2 vs Phase 3
|
| 182 |
+
|
| 183 |
+
183-item eval set (30 per language, 10 code-switched, 3 hand-written + 20 native long-form paragraphs), anchor voice, seed 0. CER is ASR round-trip: MMS-1b-all for Igbo/Hausa/Yoruba, Whisper-large-v3-turbo for English and Pidgin, the lower of the two for code-switched items and paragraphs. "No tones" (in brackets) strips diacritics. SIM is ECAPA cosine to the anchor (ceiling about 0.84 on real held-out anchor clips). The Pidgin judge is weak: real Pidgin recordings score about 0.43.
|
| 184 |
+
|
| 185 |
+
| system | ibo | hau | yor | pcm | eng | CS | para (hand / native) | SIM |
|
| 186 |
|---|---|---|---|---|---|---|---|---|
|
| 187 |
+
| `phase2` as shipped (sentence stitching) | 0.215 (0.171) | 0.194 | 0.234 (0.149) | 0.196 | 0.035 | 0.163 | 0.192 / 0.154 | 0.785 |
|
| 188 |
+
| Phase 2 LM, Phase 3 decoding | 0.243 (0.189) | 0.169 | 0.275 (0.175) | 0.195 | 0.046 | 0.185 | 0.195 / 0.158 | 0.787 |
|
| 189 |
+
| **`phase3`** | **0.219 (0.173)** | **0.151** | **0.233 (0.145)** | 0.202 | 0.043 | **0.151** | **0.170** / 0.155 | **0.788** |
|
|
|
|
|
|
|
|
|
|
| 190 |
|
| 191 |
+
Same decoding, Phase 3 LM vs Phase 2 LM: lower CER in every language except Pidgin, same speaker similarity.
|
| 192 |
|
| 193 |
+
| system | comma pause s | sentence pause s | pauses / s | pause-length W1 vs anchor | trailing silence s | clipped endings (< 0.1 s) | articulation syl/s |
|
| 194 |
+
|---|---|---|---|---|---|---|---|
|
| 195 |
+
| real anchor recordings | 0.417 | 0.543 | 0.624 | 0 | 0.16 | 15% | 4.43 |
|
| 196 |
+
| Phase 2 LM, Phase 3 decoding | 0.403 | 0.389 | 0.329 | 0.194 | 0.08 | 63% | 4.36 |
|
| 197 |
+
| **`phase3`** | **0.422** | **0.453** | 0.319 | **0.161** | **0.17** | **11%** | 4.44 |
|
| 198 |
|
| 199 |
+
Female voices (29-item subset, `phase3`):
|
| 200 |
|
| 201 |
+
| voice | CER | no-tone CER | SIM to the speaker's own real clips | clipped endings |
|
| 202 |
+
|---|---|---|---|---|
|
| 203 |
+
| `anchor_male` (same items) | 0.182 | 0.141 | 0.12–0.13 (it is a different speaker) | 17% |
|
| 204 |
+
| `waxal_ibo_5_female` | **0.149** | **0.101** | 0.64 | 21% |
|
| 205 |
+
| `waxal_yor_5_female` | 0.171 | 0.134 | **0.76** | 62% |
|
| 206 |
|
| 207 |
+
Naturalness has not been rated by native speakers (no MOS or blind A/B yet). The numbers above are automatic proxies.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
|
| 209 |
+
### Auto-tagger accuracy
|
| 210 |
|
| 211 |
+
Word-level accuracy of `tagger.py` against hand-tagged text (no GlotLID / with `--lid glotlid`):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
|
| 213 |
+
| test set | words | rule-based | + GlotLID | exact sentences (rule-based) |
|
| 214 |
+
|---|---|---|---|---|
|
| 215 |
+
| the 6 sample inputs above | 145 | 1.000 | 1.000 | 6/6 |
|
| 216 |
+
| 10 new mixed sentences, written before the lexicons | 113 | 0.991 | 0.991 | 9/10 |
|
| 217 |
+
| 12 code-switched eval items (overlaps the samples) | 206 | 0.995 | 1.000 | 11/12 |
|
| 218 |
+
| 150 single-language eval sentences (real WAXAL/FLEURS text, never looked at while building the lexicons) | 1,697 | **0.898** | **0.915** | 115/150 |
|
| 219 |
|
| 220 |
+
On the held-out single-language set, per language (rule-based / + GlotLID): English 0.99 / 1.00, Igbo 1.00 / 1.00, Yoruba 1.00 / 1.00, Hausa 0.89 / 0.94, **Pidgin 0.63 / 0.65**. Pidgin written without markers looks like English and gets tagged `eng`. The mixed test sentences were written and gold-tagged by the tagger's author, not native speakers, so their scores are optimistic. Check the printed tags, and use explicit tags or `--lang_map` when it matters.
|
| 221 |
|
| 222 |
+
## Limitations
|
| 223 |
+
|
| 224 |
+
- **Pace**: speech is still 13–28% slower than native speakers (Igbo 4.60 vs 5.30 syl/s, Hausa 3.77 vs 5.26 syl/s), and there are about half as many pauses per second as in real speech. It can sound careful rather than fully native.
|
| 225 |
+
- **Pidgin is the weakest language**: only about 5 h of training data, no reliable ASR judge, and the auto-tagger's Pidgin/English split is its weakest point (~0.63 word accuracy on plain Pidgin).
|
| 226 |
+
- **No laughter or other expressive events**: the training data has effectively no laughter, so tags like `[laughter]` do nothing useful. `[pause]`/`[breath]` were learned from data, but there is no reliable user control over them yet.
|
| 227 |
- English after a Nigerian-language span keeps a strong local accent.
|
| 228 |
+
- Yoruba tone quality needs native listening; the automatic tone metric is saturated.
|
| 229 |
+
- Female voices are zero-shot; `waxal_yor_5_female` copies its short prompt (short pauses, clipped endings).
|
| 230 |
+
- Not evaluated for numbers, abbreviations or URLs; write numbers as words.
|
| 231 |
+
- Do not use it to impersonate real people. The voices are WAXAL Media Trust speakers, released under CC-BY-SA-4.0 for speech technology.
|
| 232 |
|
| 233 |
+
## What is in the repo
|
| 234 |
|
| 235 |
+
| path | what it is | licence |
|
| 236 |
+
|---|---|---|
|
| 237 |
+
| `checkpoints/phase3/p3_lm_full/` | Phase 3 LM (`best.pt`, val step 4,500), `config.json` (rate, sampler, one-pass, points at the shared Phase 2 flow), `spk2id.json`, `args.json`, `log.jsonl` | CC-BY-SA-4.0 |
|
| 238 |
+
| `checkpoints/phase2/p2_lm_B/` | Phase 2 LM (`best.pt`) and `spk2id.json` | CC-BY-SA-4.0 |
|
| 239 |
+
| `checkpoints/phase2/p2_flow_sft/best.pt` | anchor-SFT flow-matching decoder, used by both versions | CC-BY-SA-4.0 |
|
| 240 |
+
| `prompts/` | anchor prompt clips (`clip0..3`, `prompts.json` with transcripts and S3 tokens) and female voice prompts (`voice_*.wav`, `voices.json`), all from WAXAL | CC-BY-SA-4.0 |
|
| 241 |
+
| `samples/` | example renders | CC-BY-SA-4.0 |
|
| 242 |
+
| `settings.json` | versions, voices, recommended pairing | Apache-2.0 |
|
| 243 |
+
| `infer.py`, `tagger.py`, `app.py` | inference CLI, auto-tagger, Gradio app | Apache-2.0 |
|
| 244 |
+
| `code/` | the original training and synthesis code, for reference | Apache-2.0 |
|
| 245 |
+
| `requirements.txt`, `cosyvoice_requirements.txt` | dependencies (`cosyvoice_requirements.txt` is CosyVoice's own file at the commit used) | – |
|
| 246 |
+
| `assets/` | banner | – |
|
| 247 |
+
|
| 248 |
+
## Training data and attribution
|
| 249 |
+
|
| 250 |
+
The model weights are trained on, and the voice prompts are taken from, the datasets below. Several are CC-BY-SA-4.0, so the weights, voice prompts and samples are released under **CC-BY-SA-4.0** (share-alike).
|
| 251 |
+
|
| 252 |
+
| dataset | used for | licence | attribution |
|
| 253 |
+
|---|---|---|---|
|
| 254 |
+
| [WAXAL](https://huggingface.co/datasets/google/WaxalNLP), Media Trust TTS subsets (Igbo, Yoruba, Hausa, Nigerian Pidgin) | main training data; the **anchor voice** (Yoruba speaker 4) and the **female prompt voices** (Igbo speaker 5, Yoruba speaker 5) | CC-BY-SA-4.0 (as listed on the dataset card for the Media Trust subsets) | Google and Media Trust, WAXAL (arXiv:2602.02734) |
|
| 255 |
+
| [Open.Bible Igbo](https://huggingface.co/datasets/AfriSpeech/open-bible-speech-african) (Biblica® Open Igbo Contemporary Bible™, Audio Edition) | Igbo (Phase 3) | CC-BY-SA-4.0 | Biblica, Inc. via open.bible; Biblica® and Open Igbo Contemporary Bible™ are trademarks of Biblica, Inc. |
|
| 256 |
+
| [NaijaS2ST](https://huggingface.co/datasets/McGill-NLP/NaijaS2ST) (Igbo) | Igbo, many native speakers (Phase 3) | CC-BY-4.0 | McGill-NLP, NaijaS2ST (arXiv:2604.16287) |
|
| 257 |
+
| [IgboAPI](https://huggingface.co/datasets/nkowaokwu/ibo-dict) (ibo-dict, ibo-dict-expansion) | Igbo sentences (Phase 3) | CC-BY-4.0 | Nkọwa okwu / IgboAPI contributors |
|
| 258 |
+
| [IgboSynCorp](https://doi.org/10.7910/dvn/yb9fwk) | natural Igbo speech (Phase 3) | CC0-1.0 | University of Ibadan and Afe Babalola University (Lacuna Fund) |
|
| 259 |
+
| [FLEURS](https://huggingface.co/datasets/google/fleurs) (English, Hausa, Igbo, Yoruba) | multi-speaker data | CC-BY-4.0 | Google, FLEURS (Conneau et al., 2022) |
|
| 260 |
+
| [BibleTTS](https://masakhane-io.github.io/bibleTTS/) (Yoruba, Hausa) | Yoruba and Hausa | CC-BY-SA-4.0 | Meyer et al., BibleTTS (2022); Biblica / open.bible audio |
|
| 261 |
+
| [OpenSLR SLR70](https://openslr.org/70/) (Nigerian English) | English | CC-BY-SA-4.0 | Google, crowdsourced Nigerian English |
|
| 262 |
+
| [OpenSLR SLR86](https://openslr.org/86/) (Yoruba) | Yoruba | CC-BY-SA-4.0 | Google, crowdsourced Yoruba |
|
| 263 |
+
| code-switched pairs | about 9 h of synthetic code-switch training pairs | follows the source clips (CC-BY-SA-4.0 / CC-BY-4.0) | built by concatenating clips from the sets above, following the Google 2019 code-switching recipe (Zhang et al., 2019); no separate Google dataset |
|
| 264 |
+
| base model [FunAudioLLM/CosyVoice2-0.5B](https://huggingface.co/FunAudioLLM/CosyVoice2-0.5B) | LM initialisation, flow, vocoder, tokenizers | Apache-2.0 | FunAudioLLM / Alibaba Tongyi Lab, CosyVoice 2 (Du et al., 2024) |
|
| 265 |
+
| optional [GlotLID](https://huggingface.co/cis-lmu/glotlid) (not bundled) | `--lid glotlid` in the tagger | Apache-2.0 plus notices | Kargaran et al., GlotLID (EMNLP 2023) |
|
| 266 |
+
|
| 267 |
+
Excluded on licence grounds: WaZoBiaSpeech (bans TTS use), NaijaVoices (non-commercial), and non-commercial TTS weights.
|
| 268 |
|
| 269 |
## Licence
|
| 270 |
|
| 271 |
+
- **Model weights, voice prompts and samples** (`checkpoints/`, `prompts/`, `samples/`): **[CC-BY-SA-4.0](LICENSE)**. You may use them commercially. You must credit Modular and the datasets listed above, and anything you derive from the weights (fine-tunes, merges) must be shared under CC-BY-SA-4.0 too.
|
| 272 |
+
- **Code** (`infer.py`, `tagger.py`, `app.py`, `code/`, `settings.json`): **[Apache-2.0](LICENSE-CODE)**.
|
| 273 |
+
- The base model, CosyVoice2-0.5B, is Apache-2.0; its notices still apply to the parts it contributes.
|
| 274 |
+
|
| 275 |
+
## Citation
|
| 276 |
+
|
| 277 |
+
```bibtex
|
| 278 |
+
@misc{dynamicaccent2026,
|
| 279 |
+
title = {Dynamic Accent: Code-switching TTS for Nigerian languages},
|
| 280 |
+
author = {Modular},
|
| 281 |
+
year = {2026},
|
| 282 |
+
url = {https://huggingface.co/Modularcomputing/dynamic-accent-preview}
|
| 283 |
+
}
|
| 284 |
+
```
|
app.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""Dynamic Accent: local Gradio demo (single GPU).
|
| 3 |
+
|
| 4 |
+
pip install -r requirements.txt # includes gradio
|
| 5 |
+
python app.py --cosyvoice_dir ../CosyVoice # then open http://127.0.0.1:7860
|
| 6 |
+
|
| 7 |
+
Text box -> optional auto-tag (editable preview of the tagged text) -> version + voice + rate -> Synthesize, or
|
| 8 |
+
Compare to hear Phase 2 and Phase 3 on the same text, seed and voice. Both versions stay loaded (one shared CosyVoice2
|
| 9 |
+
base; each version has its own LM copy), so a GPU with >= 16 GB is recommended. CPU works but is slow.
|
| 10 |
+
"""
|
| 11 |
+
import argparse, json, os, sys, types
|
| 12 |
+
|
| 13 |
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 14 |
+
sys.path.insert(0, HERE)
|
| 15 |
+
import infer # noqa: E402
|
| 16 |
+
from tagger import Tagger, parse_map, strip_tags, TAGGED, LANGS # noqa: E402
|
| 17 |
+
|
| 18 |
+
EXAMPLES = [
|
| 19 |
+
"Omo, I'm very excited to announce this new model, ọ na-eme m obi ụtọ, I no go lie give you",
|
| 20 |
+
"Ẹ káàbọ̀ sí ìpàdé wa òní. Today we will talk about the new school calendar.",
|
| 21 |
+
"Barka da yamma, yaya kuke? The weather report says it will rain tomorrow morning.",
|
| 22 |
+
"Kedu ka ị mere? Abeg no vex, I go call you for evening.",
|
| 23 |
+
]
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class Engine:
|
| 27 |
+
def __init__(self, a):
|
| 28 |
+
self.a = a
|
| 29 |
+
self.models = {}
|
| 30 |
+
self.cosy = self.tok = None
|
| 31 |
+
self.taggers = {}
|
| 32 |
+
|
| 33 |
+
def get(self, version, voice):
|
| 34 |
+
if version not in self.models:
|
| 35 |
+
ns = types.SimpleNamespace(**vars(self.a))
|
| 36 |
+
ns.voice = voice
|
| 37 |
+
S = infer.build(version, ns, self.cosy, self.tok, copy_llm=self.cosy is not None)
|
| 38 |
+
self.cosy, self.tok = S.cosy, S.tok
|
| 39 |
+
S._rate0 = S.rate
|
| 40 |
+
self.models[version] = S
|
| 41 |
+
S = self.models[version]
|
| 42 |
+
if getattr(S, "_voice_name", None) != voice:
|
| 43 |
+
S.set_voice(voice, self.a.voices); S._voice_name = voice
|
| 44 |
+
return S
|
| 45 |
+
|
| 46 |
+
def tag(self, text, lang_map, use_lid):
|
| 47 |
+
key = (lang_map, use_lid)
|
| 48 |
+
if key not in self.taggers:
|
| 49 |
+
self.taggers[key] = Tagger("glotlid" if use_lid else None, parse_map(lang_map))
|
| 50 |
+
return self.taggers[key].tag(strip_tags(text))
|
| 51 |
+
|
| 52 |
+
def say(self, text, version, voice, rate, seed):
|
| 53 |
+
S = self.get(version, voice)
|
| 54 |
+
S.rate = S._rate0 if rate == "default" else (infer.RATES.index(rate) if rate in infer.RATES else 0)
|
| 55 |
+
w = S.say(text, seed=int(seed))
|
| 56 |
+
return S.sr, w
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def main():
|
| 60 |
+
ap = argparse.ArgumentParser()
|
| 61 |
+
ap.add_argument("--cosyvoice_dir", default=os.environ.get("COSYVOICE_REPO", os.path.join(HERE, "CosyVoice")))
|
| 62 |
+
ap.add_argument("--model_dir", default=os.environ.get("COSYVOICE2_DIR", os.path.join(HERE, "pretrained", "CosyVoice2-0.5B")))
|
| 63 |
+
ap.add_argument("--host", default="127.0.0.1")
|
| 64 |
+
ap.add_argument("--port", type=int, default=7860)
|
| 65 |
+
ap.add_argument("--share", action="store_true")
|
| 66 |
+
a = ap.parse_args()
|
| 67 |
+
for k, v in dict(lm="", flow="", prompts=os.path.join(HERE, "prompts", "prompts.json"),
|
| 68 |
+
voices=os.path.join(HERE, "prompts", "voices.json"), dtype="auto", stitch=False, rate="default").items():
|
| 69 |
+
setattr(a, k, v)
|
| 70 |
+
if not os.path.isdir(a.model_dir):
|
| 71 |
+
from huggingface_hub import snapshot_download
|
| 72 |
+
snapshot_download("FunAudioLLM/CosyVoice2-0.5B", local_dir=a.model_dir)
|
| 73 |
+
|
| 74 |
+
import gradio as gr
|
| 75 |
+
E = Engine(a)
|
| 76 |
+
S = infer.SETTINGS
|
| 77 |
+
voices = S.get("voices", ["anchor_male", "waxal_ibo_5_female", "waxal_yor_5_female"])
|
| 78 |
+
rec = S.get("recommended", {})
|
| 79 |
+
rates = ["default"] + S.get("rates", ["none", "very slow", "slow", "normal", "fast", "very fast"])
|
| 80 |
+
|
| 81 |
+
def prepare(text, auto, lang_map, use_lid, force):
|
| 82 |
+
if not text.strip():
|
| 83 |
+
return ""
|
| 84 |
+
if force and force != "off":
|
| 85 |
+
return f"<{force}>{strip_tags(text)}</{force}>"
|
| 86 |
+
if auto and not TAGGED.search(text):
|
| 87 |
+
return E.tag(text, lang_map or "", bool(use_lid))
|
| 88 |
+
return text
|
| 89 |
+
|
| 90 |
+
def hint(version, voice):
|
| 91 |
+
r = rec.get(version, [])
|
| 92 |
+
return "" if voice in r else f"Tip: {version} is recommended with {', '.join(r)}. {rec.get('note', '')}"
|
| 93 |
+
|
| 94 |
+
def synth(text, tagged, auto, lang_map, use_lid, force, version, voice, rate, seed):
|
| 95 |
+
t = tagged.strip() if tagged.strip() else prepare(text, auto, lang_map, use_lid, force)
|
| 96 |
+
sr, w = E.say(t, version, voice, rate, seed)
|
| 97 |
+
return t, (sr, w), hint(version, voice)
|
| 98 |
+
|
| 99 |
+
def compare(text, tagged, auto, lang_map, use_lid, force, voice, rate, seed):
|
| 100 |
+
t = tagged.strip() if tagged.strip() else prepare(text, auto, lang_map, use_lid, force)
|
| 101 |
+
a2 = E.say(t, "phase2", voice, rate, seed)
|
| 102 |
+
a3 = E.say(t, "phase3", voice, rate, seed)
|
| 103 |
+
return t, a2, a3
|
| 104 |
+
|
| 105 |
+
with gr.Blocks(title="Dynamic Accent: code-switching TTS") as demo:
|
| 106 |
+
gr.Markdown("## Dynamic Accent: code-switching TTS\nEnglish, Nigerian Pidgin, Igbo, Yoruba and Hausa, mixed in one "
|
| 107 |
+
"sentence. Tag spans with `<eng> <pcm> <ibo> <yor> <hau>`, or turn on auto-tag and edit its preview.")
|
| 108 |
+
text = gr.Textbox(label="Text", lines=3, value=EXAMPLES[0])
|
| 109 |
+
with gr.Row():
|
| 110 |
+
auto = gr.Checkbox(label="Auto-tag languages", value=True)
|
| 111 |
+
use_lid = gr.Checkbox(label="Use GlotLID (1.7 GB download, needs fasttext)", value=False)
|
| 112 |
+
force = gr.Dropdown(["off"] + LANGS, value="off", label="Force one language")
|
| 113 |
+
lang_map = gr.Textbox(label="Word overrides (e.g. omo=pcm,sha=pcm)", value="")
|
| 114 |
+
tag_btn = gr.Button("Preview tags")
|
| 115 |
+
tagged = gr.Textbox(label="Tagged text (edit before synthesis; leave empty to tag automatically)", lines=3)
|
| 116 |
+
with gr.Row():
|
| 117 |
+
version = gr.Dropdown(sorted(infer.VERSIONS), value=S.get("default_version", "phase3"), label="Version")
|
| 118 |
+
voice = gr.Dropdown(voices, value=S.get("default_voice", "anchor_male"), label="Voice")
|
| 119 |
+
rate = gr.Dropdown(rates, value="default", label="Rate (phase3)")
|
| 120 |
+
seed = gr.Number(value=0, precision=0, label="Seed")
|
| 121 |
+
tip = gr.Markdown()
|
| 122 |
+
with gr.Row():
|
| 123 |
+
go = gr.Button("Synthesize", variant="primary")
|
| 124 |
+
cmp_btn = gr.Button("Compare Phase 2 vs Phase 3")
|
| 125 |
+
out = gr.Audio(label="Output", type="numpy")
|
| 126 |
+
with gr.Row():
|
| 127 |
+
out2 = gr.Audio(label="Phase 2", type="numpy")
|
| 128 |
+
out3 = gr.Audio(label="Phase 3", type="numpy")
|
| 129 |
+
gr.Examples(EXAMPLES, inputs=text)
|
| 130 |
+
|
| 131 |
+
tag_btn.click(prepare, [text, auto, lang_map, use_lid, force], tagged)
|
| 132 |
+
version.change(hint, [version, voice], tip)
|
| 133 |
+
voice.change(hint, [version, voice], tip)
|
| 134 |
+
go.click(synth, [text, tagged, auto, lang_map, use_lid, force, version, voice, rate, seed], [tagged, out, tip])
|
| 135 |
+
cmp_btn.click(compare, [text, tagged, auto, lang_map, use_lid, force, voice, rate, seed], [tagged, out2, out3])
|
| 136 |
+
demo.queue(max_size=8).launch(server_name=a.host, server_port=a.port, share=a.share)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
if __name__ == "__main__":
|
| 140 |
+
main()
|
assets/dynamic_accent_banner.jpg
ADDED
|
Git LFS Details
|
checkpoints/phase2/p2_lm_B/spk2id.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"bible_hau": 0, "bible_yor": 1, "fleurs_eng_FEMALE_c000": 2, "fleurs_eng_FEMALE_c001": 3, "fleurs_eng_FEMALE_c002": 4, "fleurs_eng_FEMALE_c003": 5, "fleurs_eng_FEMALE_c004": 6, "fleurs_eng_FEMALE_c005": 7, "fleurs_eng_FEMALE_c006": 8, "fleurs_eng_FEMALE_c007": 9, "fleurs_eng_FEMALE_c008": 10, "fleurs_eng_FEMALE_c009": 11, "fleurs_eng_FEMALE_c010": 12, "fleurs_eng_FEMALE_c012": 13, "fleurs_eng_MALE_c000": 14, "fleurs_eng_MALE_c001": 15, "fleurs_eng_MALE_c002": 16, "fleurs_eng_MALE_c003": 17, "fleurs_eng_MALE_c004": 18, "fleurs_eng_MALE_c005": 19, "fleurs_eng_MALE_c006": 20, "fleurs_eng_MALE_c007": 21, "fleurs_hau_FEMALE_c000": 22, "fleurs_hau_FEMALE_c001": 23, "fleurs_hau_FEMALE_c003": 24, "fleurs_hau_FEMALE_misc": 25, "fleurs_hau_MALE_c000": 26, "fleurs_hau_MALE_c002": 27, "fleurs_hau_MALE_c003": 28, "fleurs_hau_MALE_c004": 29, "fleurs_hau_MALE_misc": 30, "fleurs_ibo_FEMALE_c000": 31, "fleurs_ibo_FEMALE_c001": 32, "fleurs_ibo_FEMALE_c002": 33, "fleurs_ibo_FEMALE_c003": 34, "fleurs_ibo_FEMALE_c004": 35, "fleurs_ibo_FEMALE_misc": 36, "fleurs_ibo_MALE_c000": 37, "fleurs_ibo_MALE_c001": 38, "fleurs_ibo_MALE_c002": 39, "fleurs_ibo_MALE_c004": 40, "fleurs_ibo_MALE_c005": 41, "fleurs_ibo_MALE_misc": 42, "fleurs_yor_FEMALE_c000": 43, "fleurs_yor_FEMALE_c001": 44, "fleurs_yor_FEMALE_c002": 45, "fleurs_yor_MALE_c000": 46, "fleurs_yor_MALE_c001": 47, "fleurs_yor_MALE_misc": 48, "slr70_ngf_00295": 49, "slr70_ngf_00610": 50, "slr70_ngf_01208": 51, "slr70_ngf_01523": 52, "slr70_ngf_02121": 53, "slr70_ngf_02436": 54, "slr70_ngf_02484": 55, "slr70_ngf_03349": 56, "slr70_ngf_03397": 57, "slr70_ngf_04310": 58, "slr70_ngf_05223": 59, "slr70_ngf_06136": 60, "slr70_ngf_07049": 61, "slr70_ngf_07508": 62, "slr70_ngf_08421": 63, "slr70_ngf_09334": 64, "slr70_ngf_12484": 65, "slr70_ngf_13397": 66, "slr70_ngf_15223": 67, "slr70_ngm_01523": 68, "slr70_ngm_02436": 69, "slr70_ngm_02484": 70, "slr70_ngm_03349": 71, "slr70_ngm_03397": 72, "slr70_ngm_07049": 73, "slr70_ngm_07508": 74, "slr70_ngm_08784": 75, "slr70_ngm_09334": 76, "slr70_ngm_09697": 77, "slr70_ngm_12484": 78, "slr70_ngm_14310": 79, "slr86_yof_00295": 80, "slr86_yof_00610": 81, "slr86_yof_01208": 82, "slr86_yof_02121": 83, "slr86_yof_02436": 84, "slr86_yof_02484": 85, "slr86_yof_03034": 86, "slr86_yof_03349": 87, "slr86_yof_03397": 88, "slr86_yof_04310": 89, "slr86_yof_05223": 90, "slr86_yof_06136": 91, "slr86_yof_07049": 92, "slr86_yof_07505": 93, "slr86_yof_07508": 94, "slr86_yof_08421": 95, "slr86_yof_08784": 96, "slr86_yof_09334": 97, "slr86_yof_09697": 98, "slr86_yom_00295": 99, "slr86_yom_00610": 100, "slr86_yom_01208": 101, "slr86_yom_01523": 102, "slr86_yom_02121": 103, "slr86_yom_02436": 104, "slr86_yom_02484": 105, "slr86_yom_03034": 106, "slr86_yom_03397": 107, "slr86_yom_04310": 108, "slr86_yom_06136": 109, "slr86_yom_07049": 110, "slr86_yom_07505": 111, "slr86_yom_07508": 112, "slr86_yom_08421": 113, "slr86_yom_08784": 114, "slr86_yom_09334": 115, "waxal_hau_1": 116, "waxal_hau_2": 117, "waxal_hau_3": 118, "waxal_hau_4": 119, "waxal_hau_5": 120, "waxal_hau_6": 121, "waxal_hau_7": 122, "waxal_hau_8": 123, "waxal_ibo_1": 124, "waxal_ibo_2": 125, "waxal_ibo_3": 126, "waxal_ibo_4": 127, "waxal_ibo_5": 128, "waxal_ibo_6": 129, "waxal_ibo_7": 130, "waxal_ibo_8": 131, "waxal_pcm_F1": 132, "waxal_pcm_F2": 133, "waxal_pcm_F3": 134, "waxal_pcm_F4": 135, "waxal_pcm_M1": 136, "waxal_pcm_M2": 137, "waxal_pcm_M3": 138, "waxal_pcm_M4": 139, "waxal_yor_1": 140, "waxal_yor_2": 141, "waxal_yor_3": 142, "waxal_yor_4": 143, "waxal_yor_5": 144, "waxal_yor_6": 145, "waxal_yor_7": 146, "waxal_yor_8": 147}
|
checkpoints/phase3/p3_lm_full/args.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"cmd": "lm", "arm": "b", "out": "/home/dev/runs/p3_lm_full", "init": "/home/dev/runs/p2_lm_B/best.pt", "flow_init": "/home/dev/runs/p2_flow_sft/best.pt", "minutes": 60.0, "max_steps": 5000, "lr": 1e-05, "lr_new": 0.0005, "warmup": 200, "tokens": 14000, "max_tok": 750, "adv_w": 0.02, "p_prompt": 0.5, "tag_drop": 0.5, "rate_drop": 0.5, "anchor_w": 1.0, "val_every": 500, "patience": 4, "hours_cap": 0, "quad": 600.0}
|
checkpoints/phase3/p3_lm_full/best.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1fa9986713767e80b3d6a6b72cbb3d4e182e37179554d34bdb4dc7a86cd52b2c
|
| 3 |
+
size 2046917388
|
checkpoints/phase3/p3_lm_full/config.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"rate": "normal",
|
| 3 |
+
"flow": "checkpoints/phase2/p2_flow_sft/best.pt",
|
| 4 |
+
"sampler": "silexcap",
|
| 5 |
+
"one_pass": true,
|
| 6 |
+
"note": "Phase 3 LM (p3_lm_full, best val step 4500). Uses the shared Phase 2 anchor-SFT flow; a Phase 3 flow SFT gave no measurable gain and is not shipped."
|
| 7 |
+
}
|
checkpoints/phase3/p3_lm_full/log.jsonl
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"step": 0, "val": {"np": 3.563712294792896, "p": 3.571646510972262, "anchor_p": 3.2171030044555664, "mean": 3.567679402882579}}
|
| 2 |
+
{"step": 25, "ce": 3.7304, "acc": 0.187, "adv": 8.175, "adv_acc": 0.129, "gn": 2.12, "B": 18, "lr": 1.25e-06, "skips": 0, "oom": 0, "min": 0.24}
|
| 3 |
+
{"step": 50, "ce": 4.0527, "acc": 0.1759, "adv": 7.922, "adv_acc": 0.0, "gn": 3.5, "B": 10, "lr": 2.499e-06, "skips": 0, "oom": 0, "min": 0.36}
|
| 4 |
+
{"step": 75, "ce": 4.1871, "acc": 0.1463, "adv": 8.59, "adv_acc": 0.009, "gn": 2.74, "B": 53, "lr": 3.748e-06, "skips": 0, "oom": 0, "min": 0.49}
|
| 5 |
+
{"step": 100, "ce": 3.4694, "acc": 0.2184, "adv": 4.838, "adv_acc": 0.0, "gn": 2.66, "B": 6, "lr": 4.996e-06, "skips": 1, "oom": 0, "min": 0.61}
|
| 6 |
+
{"step": 125, "ce": 3.7797, "acc": 0.1892, "adv": 5.106, "adv_acc": 0.029, "gn": 2.78, "B": 29, "lr": 6.241e-06, "skips": 1, "oom": 0, "min": 0.73}
|
| 7 |
+
{"step": 150, "ce": 3.6674, "acc": 0.2085, "adv": 4.72, "adv_acc": 0.001, "gn": 2.17, "B": 14, "lr": 7.485e-06, "skips": 2, "oom": 0, "min": 0.85}
|
| 8 |
+
{"step": 175, "ce": 3.8224, "acc": 0.178, "adv": 6.07, "adv_acc": 0.007, "gn": 2.08, "B": 34, "lr": 8.726e-06, "skips": 2, "oom": 0, "min": 0.97}
|
| 9 |
+
{"step": 200, "ce": 3.4966, "acc": 0.231, "adv": 5.114, "adv_acc": 0.18, "gn": 2.23, "B": 13, "lr": 9.965e-06, "skips": 2, "oom": 0, "min": 1.09}
|
| 10 |
+
{"step": 225, "ce": 3.6002, "acc": 0.2083, "adv": 4.485, "adv_acc": 0.172, "gn": 2.06, "B": 28, "lr": 9.956e-06, "skips": 2, "oom": 0, "min": 1.22}
|
| 11 |
+
{"step": 250, "ce": 3.831, "acc": 0.175, "adv": 5.128, "adv_acc": 0.004, "gn": 2.1, "B": 13, "lr": 9.945e-06, "skips": 2, "oom": 0, "min": 1.35}
|
| 12 |
+
{"step": 275, "ce": 3.5115, "acc": 0.2121, "adv": 5.416, "adv_acc": 0.0, "gn": 2.1, "B": 17, "lr": 9.933e-06, "skips": 2, "oom": 0, "min": 1.49}
|
| 13 |
+
{"step": 300, "ce": 3.6931, "acc": 0.1905, "adv": 5.637, "adv_acc": 0.011, "gn": 1.87, "B": 14, "lr": 9.921e-06, "skips": 2, "oom": 0, "min": 1.61}
|
| 14 |
+
{"step": 325, "ce": 3.933, "acc": 0.1594, "adv": 6.282, "adv_acc": 0.022, "gn": 2.38, "B": 41, "lr": 9.907e-06, "skips": 2, "oom": 0, "min": 1.73}
|
| 15 |
+
{"step": 350, "ce": 3.3591, "acc": 0.2514, "adv": 4.969, "adv_acc": 0.001, "gn": 2.06, "B": 10, "lr": 9.892e-06, "skips": 2, "oom": 0, "min": 1.85}
|
| 16 |
+
{"step": 375, "ce": 3.6679, "acc": 0.1897, "adv": 5.176, "adv_acc": 0.12, "gn": 1.9, "B": 15, "lr": 9.876e-06, "skips": 2, "oom": 0, "min": 1.97}
|
| 17 |
+
{"step": 400, "ce": 3.8537, "acc": 0.1769, "adv": 5.109, "adv_acc": 0.024, "gn": 1.81, "B": 23, "lr": 9.859e-06, "skips": 2, "oom": 0, "min": 2.07}
|
| 18 |
+
{"step": 425, "ce": 3.6942, "acc": 0.1925, "adv": 4.691, "adv_acc": 0.125, "gn": 2.17, "B": 26, "lr": 9.841e-06, "skips": 2, "oom": 0, "min": 2.2}
|
| 19 |
+
{"step": 450, "ce": 3.9306, "acc": 0.1615, "adv": 6.244, "adv_acc": 0.022, "gn": 2.23, "B": 44, "lr": 9.822e-06, "skips": 2, "oom": 0, "min": 2.33}
|
| 20 |
+
{"step": 475, "ce": 3.343, "acc": 0.2304, "adv": 4.348, "adv_acc": 0.115, "gn": 2.17, "B": 16, "lr": 9.802e-06, "skips": 2, "oom": 0, "min": 2.45}
|
| 21 |
+
{"step": 500, "ce": 3.6741, "acc": 0.1936, "adv": 4.489, "adv_acc": 0.025, "gn": 1.83, "B": 21, "lr": 9.781e-06, "skips": 3, "oom": 0, "min": 2.57}
|
| 22 |
+
{"step": 500, "val": {"np": 3.507689257786406, "p": 3.512645748616818, "anchor_p": 3.1165452003479004, "mean": 3.510167503201612}, "best": true}
|
| 23 |
+
{"step": 525, "ce": 3.7693, "acc": 0.1915, "adv": 8.908, "adv_acc": 0.0, "gn": 2.37, "B": 59, "lr": 9.758e-06, "skips": 3, "oom": 0, "min": 2.77}
|
| 24 |
+
{"step": 550, "ce": 3.5181, "acc": 0.2223, "adv": 4.695, "adv_acc": 0.103, "gn": 2.16, "B": 14, "lr": 9.735e-06, "skips": 4, "oom": 0, "min": 2.89}
|
| 25 |
+
{"step": 575, "ce": 3.5077, "acc": 0.2158, "adv": 4.792, "adv_acc": 0.0, "gn": 3.13, "B": 7, "lr": 9.71e-06, "skips": 4, "oom": 0, "min": 3.01}
|
| 26 |
+
{"step": 600, "ce": 3.4617, "acc": 0.2337, "adv": 4.699, "adv_acc": 0.032, "gn": 2.14, "B": 10, "lr": 9.685e-06, "skips": 4, "oom": 0, "min": 3.14}
|
| 27 |
+
{"step": 625, "ce": 3.5601, "acc": 0.1991, "adv": 4.77, "adv_acc": 0.021, "gn": 2.13, "B": 24, "lr": 9.659e-06, "skips": 5, "oom": 0, "min": 3.25}
|
| 28 |
+
{"step": 650, "ce": 3.3011, "acc": 0.2631, "adv": 4.122, "adv_acc": 0.011, "gn": 1.85, "B": 14, "lr": 9.631e-06, "skips": 5, "oom": 0, "min": 3.38}
|
| 29 |
+
{"step": 675, "ce": 3.5935, "acc": 0.2031, "adv": 4.653, "adv_acc": 0.033, "gn": 1.88, "B": 19, "lr": 9.602e-06, "skips": 5, "oom": 0, "min": 3.5}
|
| 30 |
+
{"step": 700, "ce": 3.2415, "acc": 0.2494, "adv": 4.693, "adv_acc": 0.003, "gn": 2.14, "B": 7, "lr": 9.573e-06, "skips": 5, "oom": 0, "min": 3.63}
|
| 31 |
+
{"step": 725, "ce": 3.2985, "acc": 0.2415, "adv": 4.372, "adv_acc": 0.129, "gn": 1.99, "B": 11, "lr": 9.542e-06, "skips": 5, "oom": 0, "min": 3.76}
|
| 32 |
+
{"step": 750, "ce": 3.5693, "acc": 0.1964, "adv": 4.211, "adv_acc": 0.047, "gn": 2.05, "B": 27, "lr": 9.511e-06, "skips": 5, "oom": 0, "min": 3.88}
|
| 33 |
+
{"step": 775, "ce": 3.26, "acc": 0.2431, "adv": 4.574, "adv_acc": 0.007, "gn": 2.29, "B": 8, "lr": 9.478e-06, "skips": 5, "oom": 0, "min": 4.01}
|
| 34 |
+
{"step": 800, "ce": 3.3265, "acc": 0.2363, "adv": 4.495, "adv_acc": 0.047, "gn": 2.32, "B": 9, "lr": 9.445e-06, "skips": 5, "oom": 0, "min": 4.13}
|
| 35 |
+
{"step": 825, "ce": 3.7204, "acc": 0.1812, "adv": 7.24, "adv_acc": 0.002, "gn": 2.3, "B": 29, "lr": 9.41e-06, "skips": 5, "oom": 0, "min": 4.27}
|
| 36 |
+
{"step": 850, "ce": 3.5532, "acc": 0.2079, "adv": 15.118, "adv_acc": 0.006, "gn": 3.38, "B": 11, "lr": 9.375e-06, "skips": 5, "oom": 0, "min": 4.38}
|
| 37 |
+
{"step": 875, "ce": 3.9259, "acc": 0.1713, "adv": 40.286, "adv_acc": 0.017, "gn": 4.35, "B": 41, "lr": 9.338e-06, "skips": 5, "oom": 0, "min": 4.51}
|
| 38 |
+
{"step": 900, "ce": 3.9721, "acc": 0.1658, "adv": 43.79, "adv_acc": 0.02, "gn": 6.45, "B": 51, "lr": 9.301e-06, "skips": 5, "oom": 0, "min": 4.62}
|
| 39 |
+
{"step": 925, "ce": 3.4603, "acc": 0.2349, "adv": 10.369, "adv_acc": 0.0, "gn": 2.68, "B": 14, "lr": 9.263e-06, "skips": 5, "oom": 0, "min": 4.74}
|
| 40 |
+
{"step": 950, "ce": 3.5721, "acc": 0.2092, "adv": 9.951, "adv_acc": 0.032, "gn": 2.45, "B": 20, "lr": 9.223e-06, "skips": 5, "oom": 0, "min": 4.85}
|
| 41 |
+
{"step": 975, "ce": 3.7512, "acc": 0.1921, "adv": 38.525, "adv_acc": 0.0, "gn": 5.27, "B": 65, "lr": 9.183e-06, "skips": 5, "oom": 0, "min": 4.97}
|
| 42 |
+
{"step": 1000, "ce": 3.4875, "acc": 0.2139, "adv": 9.408, "adv_acc": 0.104, "gn": 2.57, "B": 19, "lr": 9.142e-06, "skips": 5, "oom": 0, "min": 5.1}
|
| 43 |
+
{"step": 1000, "val": {"np": 3.4977280627632763, "p": 3.5005001353906886, "anchor_p": 3.1229519844055176, "mean": 3.4991140990769827}, "best": true}
|
| 44 |
+
{"step": 1025, "ce": 3.4877, "acc": 0.2195, "adv": 15.951, "adv_acc": 0.0, "gn": 3.29, "B": 16, "lr": 9.1e-06, "skips": 6, "oom": 0, "min": 5.31}
|
| 45 |
+
{"step": 1050, "ce": 3.4113, "acc": 0.2332, "adv": 19.778, "adv_acc": 0.08, "gn": 3.95, "B": 9, "lr": 9.057e-06, "skips": 6, "oom": 0, "min": 5.43}
|
| 46 |
+
{"step": 1075, "ce": 3.1604, "acc": 0.2612, "adv": 10.481, "adv_acc": 0.001, "gn": 3.24, "B": 7, "lr": 9.014e-06, "skips": 6, "oom": 0, "min": 5.54}
|
| 47 |
+
{"step": 1100, "ce": 3.9686, "acc": 0.1677, "adv": 33.668, "adv_acc": 0.0, "gn": 4.65, "B": 58, "lr": 8.969e-06, "skips": 6, "oom": 0, "min": 5.66}
|
| 48 |
+
{"step": 1125, "ce": 3.8179, "acc": 0.1783, "adv": 16.777, "adv_acc": 0.002, "gn": 3.08, "B": 36, "lr": 8.924e-06, "skips": 6, "oom": 0, "min": 5.78}
|
| 49 |
+
{"step": 1150, "ce": 3.6925, "acc": 0.1956, "adv": 10.705, "adv_acc": 0.012, "gn": 2.96, "B": 14, "lr": 8.877e-06, "skips": 6, "oom": 0, "min": 5.89}
|
| 50 |
+
{"step": 1175, "ce": 3.746, "acc": 0.1831, "adv": 11.042, "adv_acc": 0.001, "gn": 2.63, "B": 18, "lr": 8.83e-06, "skips": 6, "oom": 0, "min": 6.01}
|
| 51 |
+
{"step": 1200, "ce": 3.6621, "acc": 0.195, "adv": 8.882, "adv_acc": 0.0, "gn": 2.38, "B": 10, "lr": 8.782e-06, "skips": 6, "oom": 0, "min": 6.14}
|
| 52 |
+
{"step": 1225, "ce": 3.4611, "acc": 0.2234, "adv": 12.372, "adv_acc": 0.047, "gn": 2.56, "B": 18, "lr": 8.734e-06, "skips": 6, "oom": 0, "min": 6.26}
|
| 53 |
+
{"step": 1250, "ce": 3.7915, "acc": 0.1761, "adv": 9.404, "adv_acc": 0.045, "gn": 2.54, "B": 13, "lr": 8.684e-06, "skips": 6, "oom": 0, "min": 6.37}
|
| 54 |
+
{"step": 1275, "ce": 3.766, "acc": 0.1962, "adv": 22.222, "adv_acc": 0.0, "gn": 3.98, "B": 57, "lr": 8.634e-06, "skips": 6, "oom": 0, "min": 6.49}
|
| 55 |
+
{"step": 1300, "ce": 3.772, "acc": 0.1855, "adv": 9.375, "adv_acc": 0.001, "gn": 2.33, "B": 22, "lr": 8.583e-06, "skips": 6, "oom": 0, "min": 6.61}
|
| 56 |
+
{"step": 1325, "ce": 3.2919, "acc": 0.2332, "adv": 4.917, "adv_acc": 0.053, "gn": 2.88, "B": 7, "lr": 8.531e-06, "skips": 6, "oom": 0, "min": 6.73}
|
| 57 |
+
{"step": 1350, "ce": 3.3606, "acc": 0.2269, "adv": 8.513, "adv_acc": 0.001, "gn": 2.57, "B": 13, "lr": 8.478e-06, "skips": 6, "oom": 0, "min": 6.85}
|
| 58 |
+
{"step": 1375, "ce": 3.4161, "acc": 0.2352, "adv": 6.922, "adv_acc": 0.013, "gn": 2.26, "B": 14, "lr": 8.425e-06, "skips": 6, "oom": 0, "min": 6.96}
|
| 59 |
+
{"step": 1400, "ce": 3.325, "acc": 0.2363, "adv": 8.211, "adv_acc": 0.007, "gn": 2.91, "B": 9, "lr": 8.371e-06, "skips": 6, "oom": 0, "min": 7.08}
|
| 60 |
+
{"step": 1425, "ce": 3.7772, "acc": 0.1893, "adv": 22.674, "adv_acc": 0.0, "gn": 4.1, "B": 61, "lr": 8.316e-06, "skips": 6, "oom": 0, "min": 7.2}
|
| 61 |
+
{"step": 1450, "ce": 3.5065, "acc": 0.2128, "adv": 7.335, "adv_acc": 0.032, "gn": 2.11, "B": 29, "lr": 8.26e-06, "skips": 6, "oom": 0, "min": 7.33}
|
| 62 |
+
{"step": 1475, "ce": 3.5474, "acc": 0.2084, "adv": 6.431, "adv_acc": 0.009, "gn": 2.18, "B": 26, "lr": 8.204e-06, "skips": 6, "oom": 0, "min": 7.44}
|
| 63 |
+
{"step": 1500, "ce": 3.7764, "acc": 0.1759, "adv": 11.695, "adv_acc": 0.041, "gn": 2.27, "B": 43, "lr": 8.147e-06, "skips": 7, "oom": 0, "min": 7.56}
|
| 64 |
+
{"step": 1500, "val": {"np": 3.483489041219705, "p": 3.4874038346815577, "anchor_p": 3.090611457824707, "mean": 3.4854464379506314}, "best": true}
|
| 65 |
+
{"step": 1525, "ce": 3.5611, "acc": 0.2128, "adv": 6.366, "adv_acc": 0.017, "gn": 2.16, "B": 12, "lr": 8.09e-06, "skips": 7, "oom": 0, "min": 7.76}
|
| 66 |
+
{"step": 1550, "ce": 3.571, "acc": 0.2182, "adv": 11.321, "adv_acc": 0.004, "gn": 3.66, "B": 76, "lr": 8.032e-06, "skips": 7, "oom": 0, "min": 7.89}
|
| 67 |
+
{"step": 1575, "ce": 3.4323, "acc": 0.2329, "adv": 6.34, "adv_acc": 0.015, "gn": 2.26, "B": 10, "lr": 7.973e-06, "skips": 7, "oom": 0, "min": 7.99}
|
| 68 |
+
{"step": 1600, "ce": 3.7183, "acc": 0.1903, "adv": 11.932, "adv_acc": 0.005, "gn": 3.07, "B": 51, "lr": 7.914e-06, "skips": 7, "oom": 0, "min": 8.1}
|
| 69 |
+
{"step": 1625, "ce": 3.4348, "acc": 0.2274, "adv": 6.191, "adv_acc": 0.005, "gn": 2.24, "B": 12, "lr": 7.854e-06, "skips": 7, "oom": 0, "min": 8.23}
|
| 70 |
+
{"step": 1650, "ce": 3.5439, "acc": 0.1908, "adv": 7.033, "adv_acc": 0.0, "gn": 2.77, "B": 6, "lr": 7.793e-06, "skips": 7, "oom": 0, "min": 8.35}
|
| 71 |
+
{"step": 1675, "ce": 3.7204, "acc": 0.1895, "adv": 6.672, "adv_acc": 0.041, "gn": 1.98, "B": 27, "lr": 7.732e-06, "skips": 7, "oom": 0, "min": 8.47}
|
| 72 |
+
{"step": 1700, "ce": 3.6902, "acc": 0.1898, "adv": 6.503, "adv_acc": 0.031, "gn": 2.17, "B": 29, "lr": 7.67e-06, "skips": 8, "oom": 0, "min": 8.6}
|
| 73 |
+
{"step": 1725, "ce": 3.5412, "acc": 0.2078, "adv": 6.138, "adv_acc": 0.022, "gn": 2.09, "B": 21, "lr": 7.608e-06, "skips": 8, "oom": 0, "min": 8.73}
|
| 74 |
+
{"step": 1750, "ce": 3.5848, "acc": 0.208, "adv": 6.601, "adv_acc": 0.056, "gn": 2.2, "B": 10, "lr": 7.545e-06, "skips": 8, "oom": 0, "min": 8.84}
|
| 75 |
+
{"step": 1775, "ce": 3.4334, "acc": 0.2558, "adv": 18.173, "adv_acc": 0.0, "gn": 3.74, "B": 69, "lr": 7.482e-06, "skips": 8, "oom": 0, "min": 8.95}
|
| 76 |
+
{"step": 1800, "ce": 3.3952, "acc": 0.2212, "adv": 4.707, "adv_acc": 0.064, "gn": 2.3, "B": 9, "lr": 7.419e-06, "skips": 8, "oom": 0, "min": 9.07}
|
| 77 |
+
{"step": 1825, "ce": 3.6546, "acc": 0.2024, "adv": 6.154, "adv_acc": 0.044, "gn": 2.32, "B": 33, "lr": 7.354e-06, "skips": 8, "oom": 0, "min": 9.19}
|
| 78 |
+
{"step": 1850, "ce": 3.5126, "acc": 0.2026, "adv": 6.185, "adv_acc": 0.01, "gn": 2.16, "B": 26, "lr": 7.29e-06, "skips": 8, "oom": 0, "min": 9.3}
|
| 79 |
+
{"step": 1875, "ce": 3.0871, "acc": 0.2778, "adv": 4.731, "adv_acc": 0.098, "gn": 2.17, "B": 10, "lr": 7.225e-06, "skips": 8, "oom": 0, "min": 9.41}
|
| 80 |
+
{"step": 1900, "ce": 3.1692, "acc": 0.2457, "adv": 5.498, "adv_acc": 0.015, "gn": 2.32, "B": 6, "lr": 7.159e-06, "skips": 9, "oom": 0, "min": 9.53}
|
| 81 |
+
{"step": 1925, "ce": 3.6654, "acc": 0.1816, "adv": 11.98, "adv_acc": 0.001, "gn": 2.36, "B": 41, "lr": 7.093e-06, "skips": 9, "oom": 0, "min": 9.65}
|
| 82 |
+
{"step": 1950, "ce": 3.691, "acc": 0.1926, "adv": 15.862, "adv_acc": 0.0, "gn": 3.8, "B": 67, "lr": 7.027e-06, "skips": 9, "oom": 0, "min": 9.76}
|
| 83 |
+
{"step": 1975, "ce": 3.569, "acc": 0.2165, "adv": 5.811, "adv_acc": 0.034, "gn": 2.0, "B": 16, "lr": 6.96e-06, "skips": 9, "oom": 0, "min": 9.89}
|
| 84 |
+
{"step": 2000, "ce": 3.6569, "acc": 0.2025, "adv": 5.672, "adv_acc": 0.011, "gn": 2.62, "B": 24, "lr": 6.893e-06, "skips": 9, "oom": 0, "min": 10.01}
|
| 85 |
+
{"step": 2000, "val": {"np": 3.4673069890236623, "p": 3.473822727265498, "anchor_p": 3.0952401161193848, "mean": 3.47056485814458}, "best": true}
|
| 86 |
+
{"step": 2025, "ce": 3.5417, "acc": 0.2055, "adv": 6.049, "adv_acc": 0.031, "gn": 2.45, "B": 10, "lr": 6.826e-06, "skips": 9, "oom": 0, "min": 10.2}
|
| 87 |
+
{"step": 2050, "ce": 3.3296, "acc": 0.2364, "adv": 5.457, "adv_acc": 0.018, "gn": 2.29, "B": 8, "lr": 6.758e-06, "skips": 9, "oom": 0, "min": 10.32}
|
| 88 |
+
{"step": 2075, "ce": 3.39, "acc": 0.2286, "adv": 5.628, "adv_acc": 0.001, "gn": 2.08, "B": 13, "lr": 6.69e-06, "skips": 9, "oom": 0, "min": 10.43}
|
| 89 |
+
{"step": 2100, "ce": 3.7423, "acc": 0.1898, "adv": 10.36, "adv_acc": 0.003, "gn": 2.33, "B": 43, "lr": 6.622e-06, "skips": 9, "oom": 0, "min": 10.56}
|
| 90 |
+
{"step": 2125, "ce": 3.6225, "acc": 0.2003, "adv": 6.223, "adv_acc": 0.005, "gn": 1.99, "B": 13, "lr": 6.553e-06, "skips": 9, "oom": 0, "min": 10.68}
|
| 91 |
+
{"step": 2150, "ce": 3.4632, "acc": 0.2213, "adv": 5.662, "adv_acc": 0.0, "gn": 1.88, "B": 16, "lr": 6.484e-06, "skips": 9, "oom": 0, "min": 10.8}
|
| 92 |
+
{"step": 2175, "ce": 3.2873, "acc": 0.2562, "adv": 5.891, "adv_acc": 0.004, "gn": 2.14, "B": 10, "lr": 6.415e-06, "skips": 9, "oom": 0, "min": 10.92}
|
| 93 |
+
{"step": 2200, "ce": 3.9016, "acc": 0.1671, "adv": 8.882, "adv_acc": 0.005, "gn": 2.36, "B": 41, "lr": 6.346e-06, "skips": 9, "oom": 0, "min": 11.03}
|
| 94 |
+
{"step": 2225, "ce": 2.9077, "acc": 0.3194, "adv": 5.976, "adv_acc": 0.013, "gn": 2.83, "B": 7, "lr": 6.276e-06, "skips": 9, "oom": 0, "min": 11.15}
|
| 95 |
+
{"step": 2250, "ce": 3.6433, "acc": 0.2093, "adv": 13.079, "adv_acc": 0.001, "gn": 3.92, "B": 54, "lr": 6.207e-06, "skips": 9, "oom": 0, "min": 11.26}
|
| 96 |
+
{"step": 2275, "ce": 3.4893, "acc": 0.2168, "adv": 5.574, "adv_acc": 0.06, "gn": 1.87, "B": 14, "lr": 6.137e-06, "skips": 10, "oom": 0, "min": 11.38}
|
| 97 |
+
{"step": 2300, "ce": 3.704, "acc": 0.1807, "adv": 10.287, "adv_acc": 0.0, "gn": 2.77, "B": 50, "lr": 6.067e-06, "skips": 10, "oom": 0, "min": 11.5}
|
| 98 |
+
{"step": 2325, "ce": 3.8156, "acc": 0.1893, "adv": 13.466, "adv_acc": 0.0, "gn": 3.07, "B": 55, "lr": 5.997e-06, "skips": 10, "oom": 0, "min": 11.61}
|
| 99 |
+
{"step": 2350, "ce": 3.5805, "acc": 0.2117, "adv": 14.332, "adv_acc": 0.005, "gn": 3.27, "B": 68, "lr": 5.926e-06, "skips": 10, "oom": 0, "min": 11.74}
|
| 100 |
+
{"step": 2375, "ce": 3.3738, "acc": 0.2044, "adv": 6.482, "adv_acc": 0.0, "gn": 2.93, "B": 6, "lr": 5.856e-06, "skips": 10, "oom": 0, "min": 11.87}
|
| 101 |
+
{"step": 2400, "ce": 3.6756, "acc": 0.1828, "adv": 6.471, "adv_acc": 0.005, "gn": 1.93, "B": 12, "lr": 5.785e-06, "skips": 10, "oom": 0, "min": 11.99}
|
| 102 |
+
{"step": 2425, "ce": 3.3128, "acc": 0.2365, "adv": 6.476, "adv_acc": 0.013, "gn": 1.89, "B": 10, "lr": 5.715e-06, "skips": 10, "oom": 0, "min": 12.1}
|
| 103 |
+
{"step": 2450, "ce": 3.4673, "acc": 0.2181, "adv": 6.946, "adv_acc": 0.015, "gn": 2.02, "B": 33, "lr": 5.644e-06, "skips": 10, "oom": 0, "min": 12.22}
|
| 104 |
+
{"step": 2475, "ce": 3.5298, "acc": 0.2094, "adv": 6.09, "adv_acc": 0.039, "gn": 1.71, "B": 19, "lr": 5.574e-06, "skips": 10, "oom": 0, "min": 12.32}
|
| 105 |
+
{"step": 2500, "ce": 3.2715, "acc": 0.2515, "adv": 6.632, "adv_acc": 0.121, "gn": 1.87, "B": 17, "lr": 5.503e-06, "skips": 10, "oom": 0, "min": 12.43}
|
| 106 |
+
{"step": 2500, "val": {"np": 3.455619011329129, "p": 3.4601697774197455, "anchor_p": 3.0822691917419434, "mean": 3.4578943943744376}, "best": true}
|
| 107 |
+
{"step": 2525, "ce": 3.7506, "acc": 0.183, "adv": 15.727, "adv_acc": 0.002, "gn": 2.97, "B": 55, "lr": 5.432e-06, "skips": 10, "oom": 0, "min": 12.63}
|
| 108 |
+
{"step": 2550, "ce": 3.2503, "acc": 0.2422, "adv": 6.394, "adv_acc": 0.012, "gn": 2.1, "B": 10, "lr": 5.361e-06, "skips": 11, "oom": 0, "min": 12.75}
|
| 109 |
+
{"step": 2575, "ce": 3.3457, "acc": 0.2401, "adv": 6.05, "adv_acc": 0.119, "gn": 1.93, "B": 17, "lr": 5.291e-06, "skips": 11, "oom": 0, "min": 12.86}
|
| 110 |
+
{"step": 2600, "ce": 3.6437, "acc": 0.1846, "adv": 6.671, "adv_acc": 0.061, "gn": 1.87, "B": 29, "lr": 5.22e-06, "skips": 11, "oom": 0, "min": 12.97}
|
| 111 |
+
{"step": 2625, "ce": 3.5463, "acc": 0.2367, "adv": 14.848, "adv_acc": 0.003, "gn": 3.72, "B": 74, "lr": 5.15e-06, "skips": 11, "oom": 0, "min": 13.09}
|
| 112 |
+
{"step": 2650, "ce": 3.3847, "acc": 0.2314, "adv": 6.816, "adv_acc": 0.016, "gn": 2.39, "B": 9, "lr": 5.079e-06, "skips": 11, "oom": 0, "min": 13.2}
|
| 113 |
+
{"step": 2675, "ce": 3.5453, "acc": 0.2041, "adv": 6.815, "adv_acc": 0.003, "gn": 2.07, "B": 23, "lr": 5.009e-06, "skips": 11, "oom": 0, "min": 13.31}
|
| 114 |
+
{"step": 2700, "ce": 3.3028, "acc": 0.2437, "adv": 7.003, "adv_acc": 0.128, "gn": 1.87, "B": 15, "lr": 4.939e-06, "skips": 11, "oom": 0, "min": 13.43}
|
| 115 |
+
{"step": 2725, "ce": 3.8053, "acc": 0.1819, "adv": 9.202, "adv_acc": 0.03, "gn": 2.73, "B": 42, "lr": 4.869e-06, "skips": 11, "oom": 0, "min": 13.54}
|
| 116 |
+
{"step": 2750, "ce": 3.586, "acc": 0.2259, "adv": 10.705, "adv_acc": 0.038, "gn": 3.32, "B": 76, "lr": 4.799e-06, "skips": 12, "oom": 0, "min": 13.66}
|
| 117 |
+
{"step": 2775, "ce": 3.242, "acc": 0.2543, "adv": 7.569, "adv_acc": 0.147, "gn": 1.83, "B": 14, "lr": 4.729e-06, "skips": 12, "oom": 0, "min": 13.77}
|
| 118 |
+
{"step": 2800, "ce": 3.5247, "acc": 0.2002, "adv": 7.495, "adv_acc": 0.0, "gn": 1.98, "B": 12, "lr": 4.66e-06, "skips": 12, "oom": 0, "min": 13.88}
|
| 119 |
+
{"step": 2825, "ce": 3.5414, "acc": 0.2004, "adv": 7.73, "adv_acc": 0.06, "gn": 2.6, "B": 40, "lr": 4.59e-06, "skips": 12, "oom": 0, "min": 13.99}
|
| 120 |
+
{"step": 2850, "ce": 3.2731, "acc": 0.2393, "adv": 7.595, "adv_acc": 0.051, "gn": 1.9, "B": 21, "lr": 4.521e-06, "skips": 12, "oom": 0, "min": 14.1}
|
| 121 |
+
{"step": 2875, "ce": 3.427, "acc": 0.2152, "adv": 7.72, "adv_acc": 0.0, "gn": 1.96, "B": 10, "lr": 4.452e-06, "skips": 13, "oom": 0, "min": 14.23}
|
| 122 |
+
{"step": 2900, "ce": 3.4472, "acc": 0.2124, "adv": 7.726, "adv_acc": 0.0, "gn": 1.9, "B": 14, "lr": 4.384e-06, "skips": 13, "oom": 0, "min": 14.34}
|
| 123 |
+
{"step": 2925, "ce": 3.3561, "acc": 0.228, "adv": 7.77, "adv_acc": 0.139, "gn": 1.95, "B": 17, "lr": 4.315e-06, "skips": 13, "oom": 0, "min": 14.45}
|
| 124 |
+
{"step": 2950, "ce": 3.6581, "acc": 0.2103, "adv": 8.242, "adv_acc": 0.001, "gn": 2.15, "B": 53, "lr": 4.247e-06, "skips": 13, "oom": 0, "min": 14.58}
|
| 125 |
+
{"step": 2975, "ce": 3.5687, "acc": 0.2064, "adv": 7.748, "adv_acc": 0.0, "gn": 2.09, "B": 11, "lr": 4.18e-06, "skips": 13, "oom": 0, "min": 14.69}
|
| 126 |
+
{"step": 3000, "ce": 3.8188, "acc": 0.1662, "adv": 8.003, "adv_acc": 0.01, "gn": 11.11, "B": 52, "lr": 4.112e-06, "skips": 13, "oom": 0, "min": 14.81}
|
| 127 |
+
{"step": 3000, "val": {"np": 3.458494051271619, "p": 3.4631192987050605, "anchor_p": 3.0834555625915527, "mean": 3.4608066749883397}, "best": false}
|
| 128 |
+
{"step": 3025, "ce": 3.8608, "acc": 0.1688, "adv": 7.726, "adv_acc": 0.001, "gn": 2.45, "B": 47, "lr": 4.045e-06, "skips": 14, "oom": 0, "min": 14.96}
|
| 129 |
+
{"step": 3050, "ce": 3.5531, "acc": 0.2074, "adv": 7.65, "adv_acc": 0.193, "gn": 2.03, "B": 13, "lr": 3.978e-06, "skips": 14, "oom": 0, "min": 15.07}
|
| 130 |
+
{"step": 3075, "ce": 3.6485, "acc": 0.2358, "adv": 8.172, "adv_acc": 0.0, "gn": 2.18, "B": 54, "lr": 3.912e-06, "skips": 14, "oom": 0, "min": 15.19}
|
| 131 |
+
{"step": 3100, "ce": 3.6049, "acc": 0.1975, "adv": 7.879, "adv_acc": 0.015, "gn": 1.97, "B": 43, "lr": 3.846e-06, "skips": 14, "oom": 0, "min": 15.3}
|
| 132 |
+
{"step": 3125, "ce": 3.4728, "acc": 0.2281, "adv": 7.707, "adv_acc": 0.002, "gn": 1.97, "B": 15, "lr": 3.781e-06, "skips": 14, "oom": 0, "min": 15.4}
|
| 133 |
+
{"step": 3150, "ce": 3.1627, "acc": 0.248, "adv": 7.661, "adv_acc": 0.001, "gn": 2.15, "B": 7, "lr": 3.715e-06, "skips": 14, "oom": 0, "min": 15.51}
|
| 134 |
+
{"step": 3175, "ce": 3.632, "acc": 0.1925, "adv": 8.086, "adv_acc": 0.0, "gn": 2.32, "B": 61, "lr": 3.651e-06, "skips": 15, "oom": 0, "min": 15.64}
|
| 135 |
+
{"step": 3200, "ce": 3.1466, "acc": 0.2697, "adv": 7.568, "adv_acc": 0.001, "gn": 2.21, "B": 8, "lr": 3.587e-06, "skips": 15, "oom": 0, "min": 15.76}
|
| 136 |
+
{"step": 3225, "ce": 3.4873, "acc": 0.2071, "adv": 7.532, "adv_acc": 0.0, "gn": 2.03, "B": 15, "lr": 3.523e-06, "skips": 15, "oom": 0, "min": 15.87}
|
| 137 |
+
{"step": 3250, "ce": 3.4786, "acc": 0.2021, "adv": 7.501, "adv_acc": 0.078, "gn": 1.92, "B": 24, "lr": 3.46e-06, "skips": 15, "oom": 0, "min": 15.97}
|
| 138 |
+
{"step": 3275, "ce": 3.8398, "acc": 0.1564, "adv": 7.779, "adv_acc": 0.0, "gn": 2.0, "B": 45, "lr": 3.397e-06, "skips": 15, "oom": 0, "min": 16.09}
|
| 139 |
+
{"step": 3300, "ce": 3.4721, "acc": 0.1948, "adv": 7.401, "adv_acc": 0.0, "gn": 2.6, "B": 6, "lr": 3.335e-06, "skips": 15, "oom": 0, "min": 16.2}
|
| 140 |
+
{"step": 3325, "ce": 3.4505, "acc": 0.2151, "adv": 7.363, "adv_acc": 0.037, "gn": 2.08, "B": 19, "lr": 3.273e-06, "skips": 17, "oom": 0, "min": 16.32}
|
| 141 |
+
{"step": 3350, "ce": 3.6933, "acc": 0.1805, "adv": 8.033, "adv_acc": 0.0, "gn": 2.17, "B": 54, "lr": 3.212e-06, "skips": 17, "oom": 0, "min": 16.43}
|
| 142 |
+
{"step": 3375, "ce": 3.6515, "acc": 0.1935, "adv": 7.364, "adv_acc": 0.001, "gn": 1.94, "B": 26, "lr": 3.151e-06, "skips": 17, "oom": 0, "min": 16.54}
|
| 143 |
+
{"step": 3400, "ce": 3.3099, "acc": 0.2384, "adv": 7.2, "adv_acc": 0.241, "gn": 1.99, "B": 18, "lr": 3.091e-06, "skips": 18, "oom": 0, "min": 16.66}
|
| 144 |
+
{"step": 3425, "ce": 3.4313, "acc": 0.2122, "adv": 7.262, "adv_acc": 0.0, "gn": 2.29, "B": 11, "lr": 3.032e-06, "skips": 18, "oom": 0, "min": 16.77}
|
| 145 |
+
{"step": 3450, "ce": 3.1878, "acc": 0.2464, "adv": 7.173, "adv_acc": 0.109, "gn": 1.89, "B": 18, "lr": 2.973e-06, "skips": 18, "oom": 0, "min": 16.88}
|
| 146 |
+
{"step": 3475, "ce": 3.1116, "acc": 0.2702, "adv": 7.052, "adv_acc": 0.115, "gn": 2.0, "B": 12, "lr": 2.915e-06, "skips": 18, "oom": 0, "min": 16.98}
|
| 147 |
+
{"step": 3500, "ce": 3.69, "acc": 0.183, "adv": 7.387, "adv_acc": 0.001, "gn": 2.04, "B": 44, "lr": 2.857e-06, "skips": 18, "oom": 0, "min": 17.1}
|
| 148 |
+
{"step": 3500, "val": {"np": 3.450007374201225, "p": 3.453779433371578, "anchor_p": 3.084826946258545, "mean": 3.4518934037864017}, "best": true}
|
| 149 |
+
{"step": 3525, "ce": 3.8386, "acc": 0.1708, "adv": 7.872, "adv_acc": 0.0, "gn": 2.22, "B": 59, "lr": 2.8e-06, "skips": 18, "oom": 0, "min": 17.29}
|
| 150 |
+
{"step": 3550, "ce": 3.3008, "acc": 0.2418, "adv": 6.87, "adv_acc": 0.256, "gn": 2.36, "B": 18, "lr": 2.744e-06, "skips": 18, "oom": 0, "min": 17.39}
|
| 151 |
+
{"step": 3575, "ce": 3.2114, "acc": 0.2499, "adv": 6.952, "adv_acc": 0.143, "gn": 2.01, "B": 25, "lr": 2.689e-06, "skips": 18, "oom": 0, "min": 17.49}
|
| 152 |
+
{"step": 3600, "ce": 3.631, "acc": 0.2007, "adv": 7.465, "adv_acc": 0.0, "gn": 2.28, "B": 48, "lr": 2.634e-06, "skips": 18, "oom": 0, "min": 17.59}
|
| 153 |
+
{"step": 3625, "ce": 3.0395, "acc": 0.2746, "adv": 6.853, "adv_acc": 0.365, "gn": 2.04, "B": 14, "lr": 2.58e-06, "skips": 19, "oom": 0, "min": 17.71}
|
| 154 |
+
{"step": 3650, "ce": 3.2907, "acc": 0.2407, "adv": 6.957, "adv_acc": 0.059, "gn": 2.04, "B": 19, "lr": 2.526e-06, "skips": 19, "oom": 0, "min": 17.82}
|
| 155 |
+
{"step": 3675, "ce": 3.4421, "acc": 0.219, "adv": 6.903, "adv_acc": 0.078, "gn": 2.07, "B": 18, "lr": 2.474e-06, "skips": 20, "oom": 0, "min": 17.94}
|
| 156 |
+
{"step": 3700, "ce": 3.3729, "acc": 0.2236, "adv": 6.87, "adv_acc": 0.087, "gn": 2.08, "B": 11, "lr": 2.422e-06, "skips": 21, "oom": 0, "min": 18.05}
|
| 157 |
+
{"step": 3725, "ce": 3.8656, "acc": 0.1712, "adv": 7.638, "adv_acc": 0.001, "gn": 2.12, "B": 48, "lr": 2.37e-06, "skips": 21, "oom": 0, "min": 18.16}
|
| 158 |
+
{"step": 3750, "ce": 3.1599, "acc": 0.251, "adv": 6.81, "adv_acc": 0.002, "gn": 2.31, "B": 9, "lr": 2.32e-06, "skips": 21, "oom": 0, "min": 18.26}
|
| 159 |
+
{"step": 3775, "ce": 3.597, "acc": 0.2018, "adv": 7.29, "adv_acc": 0.0, "gn": 2.19, "B": 45, "lr": 2.27e-06, "skips": 21, "oom": 0, "min": 18.35}
|
| 160 |
+
{"step": 3800, "ce": 3.4677, "acc": 0.2096, "adv": 7.013, "adv_acc": 0.021, "gn": 2.12, "B": 38, "lr": 2.222e-06, "skips": 21, "oom": 0, "min": 18.46}
|
| 161 |
+
{"step": 3825, "ce": 3.8072, "acc": 0.162, "adv": 7.709, "adv_acc": 0.0, "gn": 2.54, "B": 56, "lr": 2.174e-06, "skips": 21, "oom": 0, "min": 18.57}
|
| 162 |
+
{"step": 3850, "ce": 3.3768, "acc": 0.2393, "adv": 6.691, "adv_acc": 0.07, "gn": 2.16, "B": 15, "lr": 2.126e-06, "skips": 22, "oom": 0, "min": 18.68}
|
| 163 |
+
{"step": 3875, "ce": 3.4887, "acc": 0.2255, "adv": 8.748, "adv_acc": 0.001, "gn": 2.49, "B": 57, "lr": 2.08e-06, "skips": 22, "oom": 0, "min": 18.78}
|
| 164 |
+
{"step": 3900, "ce": 3.3054, "acc": 0.2282, "adv": 6.594, "adv_acc": 0.169, "gn": 1.96, "B": 19, "lr": 2.034e-06, "skips": 23, "oom": 0, "min": 18.89}
|
| 165 |
+
{"step": 3925, "ce": 3.366, "acc": 0.2343, "adv": 6.587, "adv_acc": 0.001, "gn": 1.94, "B": 25, "lr": 1.99e-06, "skips": 24, "oom": 0, "min": 19.01}
|
| 166 |
+
{"step": 3950, "ce": 3.3814, "acc": 0.2161, "adv": 6.627, "adv_acc": 0.0, "gn": 2.39, "B": 8, "lr": 1.946e-06, "skips": 24, "oom": 0, "min": 19.13}
|
| 167 |
+
{"step": 3975, "ce": 3.8303, "acc": 0.1731, "adv": 7.142, "adv_acc": 0.001, "gn": 2.05, "B": 40, "lr": 1.903e-06, "skips": 24, "oom": 0, "min": 19.25}
|
| 168 |
+
{"step": 4000, "ce": 3.3377, "acc": 0.2298, "adv": 6.495, "adv_acc": 0.094, "gn": 2.11, "B": 14, "lr": 1.861e-06, "skips": 24, "oom": 0, "min": 19.34}
|
| 169 |
+
{"step": 4000, "val": {"np": 3.4431558952269414, "p": 3.446689893057758, "anchor_p": 3.0781209468841553, "mean": 3.4449228941423495}, "best": true}
|
| 170 |
+
{"step": 4025, "ce": 3.6726, "acc": 0.2001, "adv": 7.533, "adv_acc": 0.0, "gn": 2.45, "B": 48, "lr": 1.82e-06, "skips": 25, "oom": 0, "min": 19.52}
|
| 171 |
+
{"step": 4050, "ce": 3.3085, "acc": 0.241, "adv": 6.482, "adv_acc": 0.087, "gn": 1.9, "B": 19, "lr": 1.78e-06, "skips": 26, "oom": 0, "min": 19.63}
|
| 172 |
+
{"step": 4075, "ce": 3.3112, "acc": 0.2284, "adv": 6.608, "adv_acc": 0.0, "gn": 2.34, "B": 7, "lr": 1.74e-06, "skips": 26, "oom": 0, "min": 19.73}
|
| 173 |
+
{"step": 4100, "ce": 3.2196, "acc": 0.2551, "adv": 6.462, "adv_acc": 0.062, "gn": 2.0, "B": 18, "lr": 1.702e-06, "skips": 27, "oom": 0, "min": 19.83}
|
| 174 |
+
{"step": 4125, "ce": 3.3942, "acc": 0.2193, "adv": 6.398, "adv_acc": 0.072, "gn": 2.13, "B": 24, "lr": 1.665e-06, "skips": 27, "oom": 0, "min": 19.93}
|
| 175 |
+
{"step": 4150, "ce": 3.5767, "acc": 0.1964, "adv": 6.64, "adv_acc": 0.015, "gn": 2.21, "B": 37, "lr": 1.628e-06, "skips": 27, "oom": 0, "min": 20.05}
|
| 176 |
+
{"step": 4175, "ce": 3.1631, "acc": 0.2804, "adv": 8.278, "adv_acc": 0.0, "gn": 2.84, "B": 70, "lr": 1.593e-06, "skips": 27, "oom": 0, "min": 20.15}
|
| 177 |
+
{"step": 4200, "ce": 3.5769, "acc": 0.2021, "adv": 6.396, "adv_acc": 0.045, "gn": 3.32, "B": 29, "lr": 1.558e-06, "skips": 27, "oom": 0, "min": 20.25}
|
| 178 |
+
{"step": 4225, "ce": 3.4182, "acc": 0.228, "adv": 6.34, "adv_acc": 0.026, "gn": 1.91, "B": 23, "lr": 1.524e-06, "skips": 27, "oom": 0, "min": 20.34}
|
| 179 |
+
{"step": 4250, "ce": 3.4323, "acc": 0.1862, "adv": 6.416, "adv_acc": 0.0, "gn": 4.24, "B": 4, "lr": 1.492e-06, "skips": 27, "oom": 0, "min": 20.46}
|
| 180 |
+
{"step": 4275, "ce": 3.2959, "acc": 0.2454, "adv": 6.336, "adv_acc": 0.074, "gn": 2.14, "B": 10, "lr": 1.46e-06, "skips": 27, "oom": 0, "min": 20.56}
|
| 181 |
+
{"step": 4300, "ce": 3.3964, "acc": 0.2241, "adv": 6.433, "adv_acc": 0.0, "gn": 2.44, "B": 9, "lr": 1.429e-06, "skips": 27, "oom": 0, "min": 20.67}
|
| 182 |
+
{"step": 4325, "ce": 3.1359, "acc": 0.2704, "adv": 6.4, "adv_acc": 0.0, "gn": 2.44, "B": 8, "lr": 1.4e-06, "skips": 27, "oom": 0, "min": 20.78}
|
| 183 |
+
{"step": 4350, "ce": 3.3125, "acc": 0.2263, "adv": 6.296, "adv_acc": 0.024, "gn": 2.0, "B": 21, "lr": 1.371e-06, "skips": 27, "oom": 0, "min": 20.87}
|
| 184 |
+
{"step": 4375, "ce": 3.7765, "acc": 0.1722, "adv": 6.958, "adv_acc": 0.003, "gn": 2.27, "B": 44, "lr": 1.344e-06, "skips": 28, "oom": 0, "min": 20.98}
|
| 185 |
+
{"step": 4400, "ce": 3.802, "acc": 0.1807, "adv": 6.978, "adv_acc": 0.048, "gn": 2.29, "B": 44, "lr": 1.317e-06, "skips": 28, "oom": 0, "min": 21.1}
|
| 186 |
+
{"step": 4425, "ce": 3.9622, "acc": 0.1576, "adv": 7.175, "adv_acc": 0.001, "gn": 2.23, "B": 53, "lr": 1.292e-06, "skips": 28, "oom": 0, "min": 21.22}
|
| 187 |
+
{"step": 4450, "ce": 3.5589, "acc": 0.1894, "adv": 6.487, "adv_acc": 0.121, "gn": 2.24, "B": 38, "lr": 1.267e-06, "skips": 28, "oom": 0, "min": 21.33}
|
| 188 |
+
{"step": 4475, "ce": 3.5869, "acc": 0.1958, "adv": 6.216, "adv_acc": 0.091, "gn": 2.13, "B": 21, "lr": 1.244e-06, "skips": 28, "oom": 0, "min": 21.44}
|
| 189 |
+
{"step": 4500, "ce": 3.5748, "acc": 0.2104, "adv": 8.296, "adv_acc": 0.001, "gn": 2.57, "B": 62, "lr": 1.221e-06, "skips": 28, "oom": 0, "min": 21.54}
|
| 190 |
+
{"step": 4500, "val": {"np": 3.4411249983970817, "p": 3.4445827232509947, "anchor_p": 3.079256296157837, "mean": 3.442853860824038}, "best": true}
|
| 191 |
+
{"step": 4525, "ce": 3.6671, "acc": 0.1935, "adv": 7.579, "adv_acc": 0.0, "gn": 2.41, "B": 61, "lr": 1.2e-06, "skips": 28, "oom": 0, "min": 21.73}
|
| 192 |
+
{"step": 4550, "ce": 3.5396, "acc": 0.2035, "adv": 6.112, "adv_acc": 0.033, "gn": 2.28, "B": 28, "lr": 1.179e-06, "skips": 28, "oom": 0, "min": 21.84}
|
| 193 |
+
{"step": 4575, "ce": 3.0832, "acc": 0.2803, "adv": 6.234, "adv_acc": 0.0, "gn": 2.13, "B": 8, "lr": 1.16e-06, "skips": 29, "oom": 0, "min": 21.94}
|
| 194 |
+
{"step": 4600, "ce": 3.5924, "acc": 0.1956, "adv": 6.252, "adv_acc": 0.001, "gn": 2.17, "B": 29, "lr": 1.142e-06, "skips": 29, "oom": 0, "min": 22.05}
|
| 195 |
+
{"step": 4625, "ce": 3.4295, "acc": 0.2224, "adv": 6.193, "adv_acc": 0.043, "gn": 2.09, "B": 20, "lr": 1.125e-06, "skips": 30, "oom": 0, "min": 22.17}
|
| 196 |
+
{"step": 4650, "ce": 3.3532, "acc": 0.2302, "adv": 6.142, "adv_acc": 0.181, "gn": 2.09, "B": 22, "lr": 1.109e-06, "skips": 30, "oom": 0, "min": 22.29}
|
| 197 |
+
{"step": 4675, "ce": 3.6147, "acc": 0.2032, "adv": 6.351, "adv_acc": 0.031, "gn": 2.01, "B": 35, "lr": 1.094e-06, "skips": 30, "oom": 0, "min": 22.39}
|
| 198 |
+
{"step": 4700, "ce": 3.5387, "acc": 0.2016, "adv": 6.802, "adv_acc": 0.0, "gn": 2.13, "B": 43, "lr": 1.08e-06, "skips": 30, "oom": 0, "min": 22.51}
|
| 199 |
+
{"step": 4725, "ce": 3.5325, "acc": 0.2115, "adv": 6.492, "adv_acc": 0.001, "gn": 2.37, "B": 41, "lr": 1.067e-06, "skips": 30, "oom": 0, "min": 22.62}
|
| 200 |
+
{"step": 4750, "ce": 3.3788, "acc": 0.2414, "adv": 6.013, "adv_acc": 0.256, "gn": 1.93, "B": 16, "lr": 1.056e-06, "skips": 30, "oom": 0, "min": 22.73}
|
| 201 |
+
{"step": 4775, "ce": 3.4268, "acc": 0.228, "adv": 6.181, "adv_acc": 0.0, "gn": 2.18, "B": 13, "lr": 1.045e-06, "skips": 30, "oom": 0, "min": 22.83}
|
| 202 |
+
{"step": 4800, "ce": 3.4523, "acc": 0.2268, "adv": 6.0, "adv_acc": 0.077, "gn": 2.02, "B": 17, "lr": 1.036e-06, "skips": 30, "oom": 0, "min": 22.94}
|
| 203 |
+
{"step": 4825, "ce": 3.5242, "acc": 0.2296, "adv": 7.628, "adv_acc": 0.044, "gn": 2.09, "B": 51, "lr": 1.027e-06, "skips": 30, "oom": 0, "min": 23.05}
|
| 204 |
+
{"step": 4850, "ce": 3.1302, "acc": 0.2662, "adv": 5.944, "adv_acc": 0.324, "gn": 2.04, "B": 12, "lr": 1.02e-06, "skips": 30, "oom": 0, "min": 23.14}
|
| 205 |
+
{"step": 4875, "ce": 3.4428, "acc": 0.2185, "adv": 6.03, "adv_acc": 0.165, "gn": 2.1, "B": 15, "lr": 1.014e-06, "skips": 30, "oom": 0, "min": 23.25}
|
| 206 |
+
{"step": 4900, "ce": 3.1318, "acc": 0.2708, "adv": 6.019, "adv_acc": 0.0, "gn": 2.6, "B": 6, "lr": 1.009e-06, "skips": 30, "oom": 0, "min": 23.35}
|
| 207 |
+
{"step": 4925, "ce": 3.5066, "acc": 0.2196, "adv": 6.043, "adv_acc": 0.039, "gn": 1.91, "B": 24, "lr": 1.005e-06, "skips": 30, "oom": 0, "min": 23.44}
|
| 208 |
+
{"step": 4950, "ce": 3.4736, "acc": 0.2202, "adv": 7.73, "adv_acc": 0.0, "gn": 3.54, "B": 69, "lr": 1.002e-06, "skips": 30, "oom": 0, "min": 23.54}
|
| 209 |
+
{"step": 4975, "ce": 3.0291, "acc": 0.2834, "adv": 5.771, "adv_acc": 0.001, "gn": 2.29, "B": 9, "lr": 1.001e-06, "skips": 30, "oom": 0, "min": 23.64}
|
| 210 |
+
{"step": 5000, "ce": 3.4741, "acc": 0.2143, "adv": 5.99, "adv_acc": 0.0, "gn": 1.92, "B": 15, "lr": 1e-06, "skips": 30, "oom": 0, "min": 23.74}
|
| 211 |
+
{"step": 5000, "val": {"np": 3.4417521021653465, "p": 3.445160358658831, "anchor_p": 3.078298807144165, "mean": 3.443456230412089}, "best": false}
|
checkpoints/phase3/p3_lm_full/spk2id.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
infer.py
CHANGED
|
@@ -1,35 +1,58 @@
|
|
| 1 |
#!/usr/bin/env python
|
| 2 |
-
"""Dynamic Accent
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
"""
|
| 18 |
-
|
|
|
|
| 19 |
|
| 20 |
import numpy as np
|
| 21 |
import soundfile as sf
|
| 22 |
import librosa
|
| 23 |
import torch
|
| 24 |
import torch.nn as nn
|
|
|
|
| 25 |
|
| 26 |
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 27 |
LANGS = ["eng", "ibo", "hau", "yor", "pcm"]
|
| 28 |
L2I = {l: i for i, l in enumerate(LANGS)}
|
| 29 |
ANCHOR = "waxal_yor_4"
|
|
|
|
| 30 |
DEFAULT_SPEED = 1.0 # user listening test 2026-10-21: original model pauses preferred; clause/1.05 kept as experimental
|
| 31 |
|
| 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
# ------------------------------------------------------------------ text front-end (tags -> spans)
|
| 34 |
_TAG = re.compile(r"<(eng|ibo|hau|yor|pcm)>(.*?)</\1>", re.S)
|
| 35 |
_SENT = re.compile(r"(?<=[.?!])\s+")
|
|
@@ -214,6 +237,11 @@ def _sf_load_wav(wav, target_sr, min_sr=16000):
|
|
| 214 |
|
| 215 |
def load_cosy(model_dir, cosyvoice_dir):
|
| 216 |
sys.path[:0] = [cosyvoice_dir, os.path.join(cosyvoice_dir, "third_party", "Matcha-TTS")]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 217 |
import cosyvoice.utils.file_utils as fu
|
| 218 |
fu.load_wav = _sf_load_wav
|
| 219 |
import cosyvoice.cli.frontend as cf
|
|
@@ -231,16 +259,16 @@ def prompt_feats(cosy, wav_path):
|
|
| 231 |
n = min(feat.shape[1] // 2, tokn.shape[1])
|
| 232 |
feat, tokn = feat[:, :2 * n], tokn[:, :n]
|
| 233 |
emb = fe._extract_spk_embedding(wav_path)
|
| 234 |
-
return tokn.
|
| 235 |
|
| 236 |
|
| 237 |
@torch.no_grad()
|
| 238 |
def token2wav(cosy, tokens, ptok, pfeat, emb):
|
| 239 |
flow = cosy.model.flow
|
| 240 |
-
t = torch.tensor([tokens], dtype=torch.int32).
|
| 241 |
-
kw = dict(token=t, token_len=torch.tensor([t.shape[1]], dtype=torch.int32).
|
| 242 |
-
prompt_token=ptok, prompt_token_len=torch.tensor([ptok.shape[1]], dtype=torch.int32).
|
| 243 |
-
prompt_feat=pfeat, prompt_feat_len=torch.tensor([pfeat.shape[1]], dtype=torch.int32).
|
| 244 |
embedding=emb)
|
| 245 |
sig = inspect.signature(flow.inference).parameters
|
| 246 |
if "streaming" in sig:
|
|
@@ -248,43 +276,55 @@ def token2wav(cosy, tokens, ptok, pfeat, emb):
|
|
| 248 |
if "finalize" in sig:
|
| 249 |
kw["finalize"] = True
|
| 250 |
if "flow_cache" in sig:
|
| 251 |
-
kw["flow_cache"] = torch.zeros(1, 80, 0, 2).
|
| 252 |
mel = flow.inference(**kw)
|
| 253 |
mel = mel[0] if isinstance(mel, tuple) else mel
|
| 254 |
hs = inspect.signature(cosy.model.hift.inference).parameters
|
| 255 |
-
w = cosy.model.hift.inference(speech_feat=mel, **({"cache_source": torch.zeros(1, 1, 0).
|
| 256 |
w = w[0] if isinstance(w, tuple) else w
|
| 257 |
return w.squeeze().float().cpu().numpy()
|
| 258 |
|
| 259 |
|
| 260 |
# ------------------------------------------------------------------ Dynamic Accent LM (Qwen2LM + language + speaker embeddings)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
class DALM2(nn.Module):
|
| 262 |
def __init__(self, qlm, n_spk, d=896):
|
| 263 |
super().__init__()
|
| 264 |
self.q = qlm
|
| 265 |
self.lang_emb = nn.Embedding(len(LANGS), d)
|
| 266 |
self.spk_emb = nn.Embedding(n_spk, d)
|
|
|
|
|
|
|
| 267 |
self.adv = nn.Sequential(nn.Linear(d, 256), nn.ReLU(), nn.Linear(256, n_spk)) # training-only head
|
| 268 |
self.V = qlm.speech_token_size
|
| 269 |
|
| 270 |
def embed_text(self, ids, langs):
|
| 271 |
return self.q.llm.model.model.embed_tokens(ids) + self.lang_emb(langs)
|
| 272 |
|
| 273 |
-
def build2(self, ids, langs, spk, pids=None, plangs=None, psp=None):
|
| 274 |
sos = self.q.llm_embedding.weight[self.q.sos][None]
|
| 275 |
task = self.q.llm_embedding.weight[self.q.task_id][None]
|
| 276 |
if pids is not None:
|
| 277 |
ids = torch.cat([pids, ids]); langs = torch.cat([plangs, langs])
|
| 278 |
-
|
|
|
|
|
|
|
|
|
|
| 279 |
if psp is not None:
|
| 280 |
parts.append(self.q.speech_embedding(psp))
|
| 281 |
return torch.cat(parts, 0)
|
| 282 |
|
| 283 |
@torch.no_grad()
|
| 284 |
def generate2(self, ids, langs, spk, prompt=None, top_p=0.8, top_k=25, win=10, tau_r=0.1, seed=0,
|
| 285 |
-
min_ratio=2.0, max_ratio=20.0):
|
|
|
|
|
|
|
| 286 |
g = torch.Generator(device=ids.device).manual_seed(seed)
|
| 287 |
-
x = self.build2(ids, langs, spk, *(prompt if prompt else (None, None, None)))[None]
|
| 288 |
n = len(ids)
|
| 289 |
min_len, max_len = int(n * min_ratio), int(n * max_ratio)
|
| 290 |
past, out, inp = None, [], x
|
|
@@ -301,7 +341,15 @@ class DALM2(nn.Module):
|
|
| 301 |
keep[top_k:] = False
|
| 302 |
cp, ci = sp[keep], si[keep]
|
| 303 |
tokid = int(ci[torch.multinomial(cp / cp.sum(), 1, generator=g)])
|
| 304 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 305 |
tokid = int(torch.multinomial(p, 1, generator=g))
|
| 306 |
if tokid >= self.V:
|
| 307 |
break
|
|
@@ -310,40 +358,128 @@ class DALM2(nn.Module):
|
|
| 310 |
return out
|
| 311 |
|
| 312 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
class DynamicAccent:
|
| 314 |
-
def __init__(self, model_dir, cosyvoice_dir, lm_ckpt, flow_ckpt, prompts_json, dtype="auto", sent_pause=0.6, cap=0.6
|
|
|
|
| 315 |
from transformers import AutoTokenizer
|
| 316 |
-
self.tok = AutoTokenizer.from_pretrained(os.path.join(model_dir, "CosyVoice-BlankEN"))
|
| 317 |
-
self.cosy = load_cosy(model_dir, cosyvoice_dir)
|
| 318 |
self.sr = self.cosy.sample_rate
|
| 319 |
-
self.
|
| 320 |
-
|
|
|
|
| 321 |
self.spk2id = json.load(open(os.path.join(os.path.dirname(lm_ckpt), "spk2id.json")))
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 325 |
dtype = "bf16" if torch.cuda.is_bf16_supported() else "fp16"
|
| 326 |
-
self.dtype = torch.bfloat16
|
| 327 |
self.sent_pause, self.cap = sent_pause, cap
|
|
|
|
|
|
|
| 328 |
meta = json.load(open(prompts_json, encoding="utf-8"))
|
| 329 |
root = os.path.dirname(os.path.dirname(os.path.abspath(prompts_json)))
|
| 330 |
self.prompts = []
|
| 331 |
for p in meta["prompts"]:
|
| 332 |
ids, langs = text_tokens(self.tok, p["tagged"])
|
| 333 |
-
lmp = (torch.tensor(ids).
|
| 334 |
-
self.prompts.append(dict(id=p["id"], lm=lmp, flow=prompt_feats(self.cosy, os.path.join(root, p["wav"]))))
|
| 335 |
-
|
| 336 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
ids, langs = text_tokens(self.tok, tagged_text)
|
| 338 |
-
P = self.
|
| 339 |
-
with
|
| 340 |
-
sp = self.m.generate2(torch.tensor(ids).
|
| 341 |
-
|
|
|
|
| 342 |
if len(sp) < 3:
|
| 343 |
sp = sp + [0] * 3
|
|
|
|
| 344 |
return token2wav(self.cosy, sp, *P["flow"])
|
| 345 |
|
| 346 |
def say(self, tagged_text, seed=0, prompt_k=0, stitch=True, pause_mode="model", speed=1.0, return_info=False):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 347 |
if pause_mode == "clause":
|
| 348 |
return self.say_clause(tagged_text, seed, prompt_k, speed, return_info)
|
| 349 |
w = self.say_model(tagged_text, seed, prompt_k, stitch)
|
|
@@ -359,11 +495,11 @@ class DynamicAccent:
|
|
| 359 |
w = cap_internal(trim_tight(w, self.sr), self.sr, self.cap)
|
| 360 |
w = fade(time_stretch(w, self.sr, speed), self.sr)
|
| 361 |
if i == 0:
|
| 362 |
-
out.append(np.zeros(int(0.12 * self.sr), np.float32))
|
| 363 |
out.append(w)
|
| 364 |
if b is not None:
|
| 365 |
g = GAPS[b] + rng.uniform(-JITTER[b], JITTER[b])
|
| 366 |
-
out.append(np.zeros(max(0, int((g - 2 * lead) * self.sr)), np.float32))
|
| 367 |
else:
|
| 368 |
out.append(np.zeros(int(0.15 * self.sr), np.float32))
|
| 369 |
info.append(dict(lang=l, text=t, boundary=b))
|
|
@@ -384,34 +520,111 @@ class DynamicAccent:
|
|
| 384 |
return np.concatenate(out)
|
| 385 |
|
| 386 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 387 |
def main():
|
| 388 |
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
| 389 |
-
ap.add_argument("--text",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 390 |
ap.add_argument("--seed", type=int, default=0)
|
| 391 |
ap.add_argument("--out", default="out.wav")
|
| 392 |
-
ap.add_argument("--prompt_clip", type=int, default=0, help="anchor prompt clip 0-3 (final
|
| 393 |
ap.add_argument("--model_dir", default=os.environ.get("COSYVOICE2_DIR", os.path.join(HERE, "pretrained", "CosyVoice2-0.5B")),
|
| 394 |
-
help="stock FunAudioLLM/CosyVoice2-0.5B snapshot")
|
| 395 |
ap.add_argument("--cosyvoice_dir", default=os.environ.get("COSYVOICE_REPO", os.path.join(HERE, "CosyVoice")),
|
| 396 |
help="clone of github.com/FunAudioLLM/CosyVoice (with submodules)")
|
| 397 |
-
ap.add_argument("--lm", default=
|
| 398 |
-
ap.add_argument("--flow", default=
|
| 399 |
ap.add_argument("--prompts", default=os.path.join(HERE, "prompts", "prompts.json"))
|
| 400 |
-
ap.add_argument("--
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
ap.add_argument("--
|
| 404 |
-
|
| 405 |
-
ap.add_argument("--
|
| 406 |
-
|
| 407 |
a = ap.parse_args()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
if not os.path.isdir(a.model_dir):
|
| 409 |
from huggingface_hub import snapshot_download
|
| 410 |
snapshot_download("FunAudioLLM/CosyVoice2-0.5B", local_dir=a.model_dir)
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 415 |
|
| 416 |
|
| 417 |
if __name__ == "__main__":
|
|
|
|
| 1 |
#!/usr/bin/env python
|
| 2 |
+
"""Dynamic Accent: Nigerian multilingual, code-switching TTS on CosyVoice2-0.5B, with selectable model versions.
|
| 3 |
+
|
| 4 |
+
Versions (`--version`):
|
| 5 |
+
phase2 LM `p2_lm_B` + anchor-SFT flow `p2_flow_sft`. Phase 2 sampler, sentence stitching, edge trim, internal
|
| 6 |
+
silences capped at 0.6 s, 0.6 s between sentences (exactly the Phase 2 final samples).
|
| 7 |
+
phase3 LM `p3_lm_full` (re-cut long-form data with natural pauses, ~102 h of Igbo) + the shared Phase 2 flow (see
|
| 8 |
+
settings.json and checkpoints/phase3/p3_lm_full/config.json). Silence-aware sampler (silence tokens exempt from the repetition check up
|
| 9 |
+
to a 1 s run), the whole paragraph in ONE pass (up to ~60 words per pass), no audio post-processing: every
|
| 10 |
+
pause and the pace come from the model.
|
| 11 |
+
|
| 12 |
+
Voices (`--voice`): `anchor_male` (default; WAXAL Yoruba speaker 4), `waxal_ibo_5_female`, `waxal_yor_5_female`
|
| 13 |
+
(see --list_voices; recommended: phase3 with a female voice, phase2 with anchor_male). A non-anchor voice is zero-shot: its clip is the flow prompt and the LM prompt, and its
|
| 14 |
+
speaker token is used when the LM was trained on that speaker.
|
| 15 |
+
|
| 16 |
+
python infer.py --text "<eng>this is dynamic accent,</eng> <pcm>e dey sound nice abi?</pcm>" --version phase3 --out out.wav
|
| 17 |
+
python infer.py --text "..." --compare --out cmp.wav # -> cmp_phase2.wav and cmp_phase3.wav, same text, seed, voice
|
| 18 |
+
python infer.py --list_voices
|
| 19 |
+
python infer.py --auto_tag --tag_only --text "Omo, this traffic no be here o. Ẹ ṣé púpọ̀." # inspect / edit the tags
|
| 20 |
+
|
| 21 |
+
Text: wrap each language span in <eng>, <pcm>, <yor>, <ibo> or <hau> tags. Untagged text is treated as English, unless
|
| 22 |
+
--auto_tag (automatic word/span language ID, see tagger.py), --force_lang or --lang_map is given.
|
| 23 |
+
`--pause_mode clause` / `--speed` (prosody v2: fixed gaps + WSOLA) are kept for phase2 only as an experiment; a
|
| 24 |
+
listening test preferred the model's own pauses.
|
| 25 |
"""
|
| 26 |
+
|
| 27 |
+
import argparse, copy, inspect, json, os, re, sys, unicodedata
|
| 28 |
|
| 29 |
import numpy as np
|
| 30 |
import soundfile as sf
|
| 31 |
import librosa
|
| 32 |
import torch
|
| 33 |
import torch.nn as nn
|
| 34 |
+
import contextlib
|
| 35 |
|
| 36 |
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 37 |
LANGS = ["eng", "ibo", "hau", "yor", "pcm"]
|
| 38 |
L2I = {l: i for i, l in enumerate(LANGS)}
|
| 39 |
ANCHOR = "waxal_yor_4"
|
| 40 |
+
DEV = torch.device("cuda" if torch.cuda.is_available() else "cpu") # set_device() / --device to override
|
| 41 |
DEFAULT_SPEED = 1.0 # user listening test 2026-10-21: original model pauses preferred; clause/1.05 kept as experimental
|
| 42 |
|
| 43 |
|
| 44 |
+
def set_device(d):
|
| 45 |
+
global DEV
|
| 46 |
+
DEV = torch.device(d if d != "auto" else ("cuda" if torch.cuda.is_available() else "cpu"))
|
| 47 |
+
return DEV
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def autocast(dtype):
|
| 51 |
+
if DEV.type == "cuda" and dtype is not None:
|
| 52 |
+
return torch.autocast("cuda", dtype=dtype)
|
| 53 |
+
return contextlib.nullcontext() # CPU: plain fp32
|
| 54 |
+
|
| 55 |
+
|
| 56 |
# ------------------------------------------------------------------ text front-end (tags -> spans)
|
| 57 |
_TAG = re.compile(r"<(eng|ibo|hau|yor|pcm)>(.*?)</\1>", re.S)
|
| 58 |
_SENT = re.compile(r"(?<=[.?!])\s+")
|
|
|
|
| 237 |
|
| 238 |
def load_cosy(model_dir, cosyvoice_dir):
|
| 239 |
sys.path[:0] = [cosyvoice_dir, os.path.join(cosyvoice_dir, "third_party", "Matcha-TTS")]
|
| 240 |
+
try: # pyworld is only needed for CosyVoice training (F0 features); it often fails
|
| 241 |
+
import pyworld # noqa: F401 # to build, so inference runs without it
|
| 242 |
+
except ImportError:
|
| 243 |
+
import types
|
| 244 |
+
sys.modules["pyworld"] = types.ModuleType("pyworld")
|
| 245 |
import cosyvoice.utils.file_utils as fu
|
| 246 |
fu.load_wav = _sf_load_wav
|
| 247 |
import cosyvoice.cli.frontend as cf
|
|
|
|
| 259 |
n = min(feat.shape[1] // 2, tokn.shape[1])
|
| 260 |
feat, tokn = feat[:, :2 * n], tokn[:, :n]
|
| 261 |
emb = fe._extract_spk_embedding(wav_path)
|
| 262 |
+
return tokn.to(DEV), feat.to(DEV), emb.to(DEV)
|
| 263 |
|
| 264 |
|
| 265 |
@torch.no_grad()
|
| 266 |
def token2wav(cosy, tokens, ptok, pfeat, emb):
|
| 267 |
flow = cosy.model.flow
|
| 268 |
+
t = torch.tensor([tokens], dtype=torch.int32).to(DEV)
|
| 269 |
+
kw = dict(token=t, token_len=torch.tensor([t.shape[1]], dtype=torch.int32).to(DEV),
|
| 270 |
+
prompt_token=ptok, prompt_token_len=torch.tensor([ptok.shape[1]], dtype=torch.int32).to(DEV),
|
| 271 |
+
prompt_feat=pfeat, prompt_feat_len=torch.tensor([pfeat.shape[1]], dtype=torch.int32).to(DEV),
|
| 272 |
embedding=emb)
|
| 273 |
sig = inspect.signature(flow.inference).parameters
|
| 274 |
if "streaming" in sig:
|
|
|
|
| 276 |
if "finalize" in sig:
|
| 277 |
kw["finalize"] = True
|
| 278 |
if "flow_cache" in sig:
|
| 279 |
+
kw["flow_cache"] = torch.zeros(1, 80, 0, 2).to(DEV)
|
| 280 |
mel = flow.inference(**kw)
|
| 281 |
mel = mel[0] if isinstance(mel, tuple) else mel
|
| 282 |
hs = inspect.signature(cosy.model.hift.inference).parameters
|
| 283 |
+
w = cosy.model.hift.inference(speech_feat=mel, **({"cache_source": torch.zeros(1, 1, 0).to(DEV)} if "cache_source" in hs else {}))
|
| 284 |
w = w[0] if isinstance(w, tuple) else w
|
| 285 |
return w.squeeze().float().cpu().numpy()
|
| 286 |
|
| 287 |
|
| 288 |
# ------------------------------------------------------------------ Dynamic Accent LM (Qwen2LM + language + speaker embeddings)
|
| 289 |
+
# S3 tokens that fill silent frames in the anchor's recordings (Phase 3 Stage 0); used by the silence-aware sampler
|
| 290 |
+
SIL_TOKENS = {4137, 4218, 1950, 2031, 3894, 6324, 1707, 3677, 1701, 6405, 1947, 3645, 1944, 1704, 3891, 4134, 3680, 5838, 3651}
|
| 291 |
+
RATES = [None, "very slow", "slow", "normal", "fast", "very fast"]
|
| 292 |
+
|
| 293 |
+
|
| 294 |
class DALM2(nn.Module):
|
| 295 |
def __init__(self, qlm, n_spk, d=896):
|
| 296 |
super().__init__()
|
| 297 |
self.q = qlm
|
| 298 |
self.lang_emb = nn.Embedding(len(LANGS), d)
|
| 299 |
self.spk_emb = nn.Embedding(n_spk, d)
|
| 300 |
+
self.rate_emb = nn.Embedding(len(RATES), d, padding_idx=0) # phase3 speed instruct; zero = none (phase2)
|
| 301 |
+
nn.init.zeros_(self.rate_emb.weight)
|
| 302 |
self.adv = nn.Sequential(nn.Linear(d, 256), nn.ReLU(), nn.Linear(256, n_spk)) # training-only head
|
| 303 |
self.V = qlm.speech_token_size
|
| 304 |
|
| 305 |
def embed_text(self, ids, langs):
|
| 306 |
return self.q.llm.model.model.embed_tokens(ids) + self.lang_emb(langs)
|
| 307 |
|
| 308 |
+
def build2(self, ids, langs, spk, rate=0, pids=None, plangs=None, psp=None):
|
| 309 |
sos = self.q.llm_embedding.weight[self.q.sos][None]
|
| 310 |
task = self.q.llm_embedding.weight[self.q.task_id][None]
|
| 311 |
if pids is not None:
|
| 312 |
ids = torch.cat([pids, ids]); langs = torch.cat([plangs, langs])
|
| 313 |
+
sv = self.spk_emb(spk)
|
| 314 |
+
if rate:
|
| 315 |
+
sv = sv + self.rate_emb(torch.tensor(rate, device=sv.device))
|
| 316 |
+
parts = [sos, self.embed_text(ids, langs), sv[None], task]
|
| 317 |
if psp is not None:
|
| 318 |
parts.append(self.q.speech_embedding(psp))
|
| 319 |
return torch.cat(parts, 0)
|
| 320 |
|
| 321 |
@torch.no_grad()
|
| 322 |
def generate2(self, ids, langs, spk, prompt=None, top_p=0.8, top_k=25, win=10, tau_r=0.1, seed=0,
|
| 323 |
+
min_ratio=2.0, max_ratio=20.0, sampler="ras", rate=0, sil_cap=25):
|
| 324 |
+
"""sampler 'ras' = Phase 2 repetition-aware sampling; 'silexcap' = silence tokens exempt from the repetition
|
| 325 |
+
check while the current silence run is shorter than sil_cap frames (25 = 1.0 s), then the normal check."""
|
| 326 |
g = torch.Generator(device=ids.device).manual_seed(seed)
|
| 327 |
+
x = self.build2(ids, langs, spk, rate, *(prompt if prompt else (None, None, None)))[None]
|
| 328 |
n = len(ids)
|
| 329 |
min_len, max_len = int(n * min_ratio), int(n * max_ratio)
|
| 330 |
past, out, inp = None, [], x
|
|
|
|
| 341 |
keep[top_k:] = False
|
| 342 |
cp, ci = sp[keep], si[keep]
|
| 343 |
tokid = int(ci[torch.multinomial(cp / cp.sum(), 1, generator=g)])
|
| 344 |
+
exempt = False
|
| 345 |
+
if sampler == "silexcap" and tokid in SIL_TOKENS:
|
| 346 |
+
run = 0
|
| 347 |
+
for t in reversed(out):
|
| 348 |
+
if t not in SIL_TOKENS:
|
| 349 |
+
break
|
| 350 |
+
run += 1
|
| 351 |
+
exempt = run < sil_cap
|
| 352 |
+
if not exempt and out and sum(1 for t in out[-win:] if t == tokid) >= win * tau_r and tokid != self.V: # RAS
|
| 353 |
tokid = int(torch.multinomial(p, 1, generator=g))
|
| 354 |
if tokid >= self.V:
|
| 355 |
break
|
|
|
|
| 358 |
return out
|
| 359 |
|
| 360 |
|
| 361 |
+
SETTINGS_PATH = os.path.join(HERE, "settings.json")
|
| 362 |
+
SETTINGS = json.load(open(SETTINGS_PATH)) if os.path.exists(SETTINGS_PATH) else {}
|
| 363 |
+
VERSIONS = {k: {kk: vv for kk, vv in v.items() if kk != "desc"} for k, v in SETTINGS.get("versions", {}).items()} or {
|
| 364 |
+
"phase2": dict(lm="checkpoints/phase2/p2_lm_B/best.pt", flow="checkpoints/phase2/p2_flow_sft/best.pt", sampler="ras",
|
| 365 |
+
one_pass=False, postprocess=True, rate=None),
|
| 366 |
+
"phase3": dict(lm="checkpoints/phase3/p3_lm_full/best.pt", flow="checkpoints/phase2/p2_flow_sft/best.pt",
|
| 367 |
+
sampler="silexcap", one_pass=True, postprocess=False, rate="normal"),
|
| 368 |
+
}
|
| 369 |
+
RECOMMENDED = SETTINGS.get("recommended", {})
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
def recommendation(version, voice):
|
| 373 |
+
"""one-line hint when a version/voice pairing is not the recommended one (None when it is)."""
|
| 374 |
+
rec = RECOMMENDED.get(version)
|
| 375 |
+
if rec and voice not in rec:
|
| 376 |
+
return f"note: {version} is recommended with {' or '.join(rec)} ({RECOMMENDED.get('note', '')})"
|
| 377 |
+
return None
|
| 378 |
+
|
| 379 |
+
|
| 380 |
+
def version_cfg(name):
|
| 381 |
+
cfg = dict(VERSIONS[name])
|
| 382 |
+
cj = os.path.join(HERE, os.path.dirname(cfg["lm"]), "config.json")
|
| 383 |
+
if os.path.exists(cj): # a checkpoint may override flow / rate / sampler
|
| 384 |
+
cfg.update({k: v for k, v in json.load(open(cj)).items() if k in cfg})
|
| 385 |
+
cfg["lm"] = os.path.join(HERE, cfg["lm"]); cfg["flow"] = os.path.join(HERE, cfg["flow"])
|
| 386 |
+
return cfg
|
| 387 |
+
|
| 388 |
+
|
| 389 |
+
def word_chunks(text, max_words=60):
|
| 390 |
+
"""one pass per <= max_words, split only at sentence ends (a whole paragraph usually fits in one pass)."""
|
| 391 |
+
sents = split_sentences(text)
|
| 392 |
+
out, cur, n = [], [], 0
|
| 393 |
+
for s in sents:
|
| 394 |
+
w = len(re.sub(r"<[^>]+>", " ", s).split())
|
| 395 |
+
if cur and n + w > max_words:
|
| 396 |
+
out.append(" ".join(cur)); cur, n = [], 0
|
| 397 |
+
cur.append(s); n += w
|
| 398 |
+
if cur:
|
| 399 |
+
out.append(" ".join(cur))
|
| 400 |
+
return out or [text]
|
| 401 |
+
|
| 402 |
+
|
| 403 |
class DynamicAccent:
|
| 404 |
+
def __init__(self, model_dir, cosyvoice_dir, lm_ckpt, flow_ckpt, prompts_json, dtype="auto", sent_pause=0.6, cap=0.6,
|
| 405 |
+
sampler="ras", one_pass=False, postprocess=True, rate=None, cosy=None, tok=None, copy_llm=False):
|
| 406 |
from transformers import AutoTokenizer
|
| 407 |
+
self.tok = tok or AutoTokenizer.from_pretrained(os.path.join(model_dir, "CosyVoice-BlankEN"))
|
| 408 |
+
self.cosy = cosy or load_cosy(model_dir, cosyvoice_dir)
|
| 409 |
self.sr = self.cosy.sample_rate
|
| 410 |
+
self.flow_sd = torch.load(flow_ckpt, map_location=DEV, weights_only=False)["flow"]
|
| 411 |
+
self.cosy.model.flow.load_state_dict(self.flow_sd)
|
| 412 |
+
ck = torch.load(lm_ckpt, map_location=DEV, weights_only=False)
|
| 413 |
self.spk2id = json.load(open(os.path.join(os.path.dirname(lm_ckpt), "spk2id.json")))
|
| 414 |
+
# two versions resident at once (app.py) must not share LM weights: copy_llm=True gives each its own copy.
|
| 415 |
+
# The CLI runs versions one after the other and reloads the full LM state in place (saves ~2 GB RAM).
|
| 416 |
+
qlm = copy.deepcopy(self.cosy.model.llm) if copy_llm else self.cosy.model.llm
|
| 417 |
+
self.m = DALM2(qlm, ck["n_spk"]).to(DEV).eval()
|
| 418 |
+
miss = self.m.load_state_dict(ck["model"], strict=False)
|
| 419 |
+
assert not [k for k in miss.missing_keys if not k.startswith("rate_emb")], miss
|
| 420 |
+
del ck
|
| 421 |
+
if DEV.type != "cuda":
|
| 422 |
+
dtype = "fp32"
|
| 423 |
+
elif dtype == "auto":
|
| 424 |
dtype = "bf16" if torch.cuda.is_bf16_supported() else "fp16"
|
| 425 |
+
self.dtype = {"bf16": torch.bfloat16, "fp16": torch.float16, "fp32": None}[dtype]
|
| 426 |
self.sent_pause, self.cap = sent_pause, cap
|
| 427 |
+
self.sampler, self.one_pass, self.postprocess = sampler, one_pass, postprocess
|
| 428 |
+
self.rate = RATES.index(rate) if rate in RATES else 0
|
| 429 |
meta = json.load(open(prompts_json, encoding="utf-8"))
|
| 430 |
root = os.path.dirname(os.path.dirname(os.path.abspath(prompts_json)))
|
| 431 |
self.prompts = []
|
| 432 |
for p in meta["prompts"]:
|
| 433 |
ids, langs = text_tokens(self.tok, p["tagged"])
|
| 434 |
+
lmp = (torch.tensor(ids).to(DEV), torch.tensor(langs).to(DEV), torch.tensor(p["s3_tokens"], dtype=torch.int64).to(DEV))
|
| 435 |
+
self.prompts.append(dict(id=p["id"], lm=lmp, flow=prompt_feats(self.cosy, os.path.join(root, p["wav"])), spk=ANCHOR))
|
| 436 |
+
self.voice = None
|
| 437 |
+
|
| 438 |
+
def use_flow(self):
|
| 439 |
+
self.cosy.model.flow.load_state_dict(self.flow_sd) # two versions may share one CosyVoice2 instance
|
| 440 |
+
|
| 441 |
+
def set_voice(self, voice, voices_json=None):
|
| 442 |
+
"""'anchor' or an id from voices.json: its clip is the flow + LM prompt (zero-shot)."""
|
| 443 |
+
meta = json.load(open(voices_json, encoding="utf-8")) if voices_json else {"voices": {}}
|
| 444 |
+
voice = meta.get("aliases", {}).get(voice, voice)
|
| 445 |
+
if voice in (None, "anchor", "anchor_male"):
|
| 446 |
+
self.voice = None; return
|
| 447 |
+
if voice not in meta["voices"]:
|
| 448 |
+
raise SystemExit(f"unknown voice '{voice}'; available: {', '.join(meta['voices'])}")
|
| 449 |
+
V = meta["voices"][voice]
|
| 450 |
+
root = os.path.dirname(os.path.dirname(os.path.abspath(voices_json)))
|
| 451 |
+
ptok, pfeat, pemb = prompt_feats(self.cosy, os.path.join(root, V["wav"]))
|
| 452 |
+
ids, langs = text_tokens(self.tok, V["tagged"])
|
| 453 |
+
lmp = (torch.tensor(ids).to(DEV), torch.tensor(langs).to(DEV), ptok[0].long())
|
| 454 |
+
self.voice = dict(id=voice, lm=lmp, flow=(ptok, pfeat, pemb), spk=V["spk"] if V["spk"] in self.spk2id else ANCHOR)
|
| 455 |
+
|
| 456 |
+
def _prompt(self, prompt_k):
|
| 457 |
+
return self.voice or self.prompts[prompt_k % len(self.prompts)]
|
| 458 |
+
|
| 459 |
+
def one(self, tagged_text, seed, prompt_k, use_lm_prompt=True, lm_prompt=None):
|
| 460 |
ids, langs = text_tokens(self.tok, tagged_text)
|
| 461 |
+
P = self._prompt(prompt_k)
|
| 462 |
+
with autocast(self.dtype):
|
| 463 |
+
sp = self.m.generate2(torch.tensor(ids).to(DEV), torch.tensor(langs).to(DEV), torch.tensor(self.spk2id[P["spk"]]).to(DEV),
|
| 464 |
+
prompt=(lm_prompt or P["lm"]) if use_lm_prompt else None, seed=seed, sampler=self.sampler,
|
| 465 |
+
rate=self.rate, max_ratio=30.0 if self.one_pass else 20.0)
|
| 466 |
if len(sp) < 3:
|
| 467 |
sp = sp + [0] * 3
|
| 468 |
+
self.last_tokens = sp
|
| 469 |
return token2wav(self.cosy, sp, *P["flow"])
|
| 470 |
|
| 471 |
def say(self, tagged_text, seed=0, prompt_k=0, stitch=True, pause_mode="model", speed=1.0, return_info=False):
|
| 472 |
+
self.use_flow()
|
| 473 |
+
if self.one_pass: # phase3: the model makes every pause; nothing is trimmed or inserted
|
| 474 |
+
ws, prev = [], None
|
| 475 |
+
for i, ch in enumerate(word_chunks(tagged_text)):
|
| 476 |
+
w = self.one(ch, seed + 1000 * i, prompt_k, lm_prompt=prev)
|
| 477 |
+
ws.append(w)
|
| 478 |
+
ids, langs = text_tokens(self.tok, ch) # next chunk continues from this one (model sets the gap)
|
| 479 |
+
if len(self.last_tokens) <= 400:
|
| 480 |
+
prev = (torch.tensor(ids).to(DEV), torch.tensor(langs).to(DEV), torch.tensor(self.last_tokens).to(DEV))
|
| 481 |
+
w = np.concatenate(ws)
|
| 482 |
+
return (w, None) if return_info else w
|
| 483 |
if pause_mode == "clause":
|
| 484 |
return self.say_clause(tagged_text, seed, prompt_k, speed, return_info)
|
| 485 |
w = self.say_model(tagged_text, seed, prompt_k, stitch)
|
|
|
|
| 495 |
w = cap_internal(trim_tight(w, self.sr), self.sr, self.cap)
|
| 496 |
w = fade(time_stretch(w, self.sr, speed), self.sr)
|
| 497 |
if i == 0:
|
| 498 |
+
out.append(np.zeros(int(0.12 * self.sr), np.float32))
|
| 499 |
out.append(w)
|
| 500 |
if b is not None:
|
| 501 |
g = GAPS[b] + rng.uniform(-JITTER[b], JITTER[b])
|
| 502 |
+
out.append(np.zeros(max(0, int((g - 2 * lead) * self.sr)), np.float32))
|
| 503 |
else:
|
| 504 |
out.append(np.zeros(int(0.15 * self.sr), np.float32))
|
| 505 |
info.append(dict(lang=l, text=t, boundary=b))
|
|
|
|
| 520 |
return np.concatenate(out)
|
| 521 |
|
| 522 |
|
| 523 |
+
def build(version, a, cosy=None, tok=None, copy_llm=False):
|
| 524 |
+
cfg = version_cfg(version)
|
| 525 |
+
lm = a.lm or cfg["lm"]; flow = a.flow or cfg["flow"]
|
| 526 |
+
S = DynamicAccent(a.model_dir, a.cosyvoice_dir, lm, flow, a.prompts, a.dtype, sampler=cfg["sampler"],
|
| 527 |
+
one_pass=cfg["one_pass"] and not a.stitch, postprocess=cfg["postprocess"],
|
| 528 |
+
rate=a.rate if a.rate != "default" else cfg["rate"], cosy=cosy, tok=tok, copy_llm=copy_llm)
|
| 529 |
+
S.set_voice(a.voice, a.voices)
|
| 530 |
+
return S
|
| 531 |
+
|
| 532 |
+
|
| 533 |
+
def list_voices(voices_json):
|
| 534 |
+
V = json.load(open(voices_json, encoding="utf-8"))["voices"] if os.path.exists(voices_json) else {}
|
| 535 |
+
print("voices (--voice):")
|
| 536 |
+
for k, v in V.items():
|
| 537 |
+
print(f" {k:20s} {v.get('desc', '')}")
|
| 538 |
+
print("\nversions (--version):")
|
| 539 |
+
for k, v in SETTINGS.get("versions", {}).items():
|
| 540 |
+
print(f" {k:20s} {v.get('desc', '')}")
|
| 541 |
+
if RECOMMENDED:
|
| 542 |
+
print("\nrecommended pairing: phase3 -> " + ", ".join(RECOMMENDED.get("phase3", [])) +
|
| 543 |
+
"; phase2 -> " + ", ".join(RECOMMENDED.get("phase2", [])))
|
| 544 |
+
print(" " + RECOMMENDED.get("note", ""))
|
| 545 |
+
|
| 546 |
+
|
| 547 |
+
def prepare_text(a):
|
| 548 |
+
"""apply --auto_tag / --force_lang / --lang_map; returns the tagged text that will be synthesised."""
|
| 549 |
+
from tagger import Tagger, parse_map, TAGGED
|
| 550 |
+
text = a.text
|
| 551 |
+
if a.force_lang:
|
| 552 |
+
from tagger import strip_tags
|
| 553 |
+
return f"<{a.force_lang}>{strip_tags(text)}</{a.force_lang}>"
|
| 554 |
+
if a.auto_tag or a.lang_map:
|
| 555 |
+
if TAGGED.search(text) and not a.auto_tag:
|
| 556 |
+
return text
|
| 557 |
+
from tagger import strip_tags
|
| 558 |
+
T = Tagger(None if a.lid == "none" else a.lid, parse_map(a.lang_map))
|
| 559 |
+
return T.tag(strip_tags(text))
|
| 560 |
+
return text
|
| 561 |
+
|
| 562 |
+
|
| 563 |
def main():
|
| 564 |
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
| 565 |
+
ap.add_argument("--text", help="text; tagged ('<eng>Good morning,</eng> <pcm>how body?</pcm>') or plain with --auto_tag")
|
| 566 |
+
ap.add_argument("--version", default=SETTINGS.get("default_version", "phase3"), choices=sorted(VERSIONS),
|
| 567 |
+
help="model version (default phase3)")
|
| 568 |
+
ap.add_argument("--compare", action="store_true",
|
| 569 |
+
help="render the same text, seed and voice with phase2 AND phase3 -> <out>_phase2.wav, <out>_phase3.wav")
|
| 570 |
+
ap.add_argument("--voice", default=SETTINGS.get("default_voice", "anchor_male"),
|
| 571 |
+
help="anchor_male | waxal_ibo_5_female | waxal_yor_5_female (see --list_voices)")
|
| 572 |
+
ap.add_argument("--list_voices", action="store_true", help="list voices, versions and the recommended pairing")
|
| 573 |
+
ap.add_argument("--rate", default="default", choices=["default", "none", "very slow", "slow", "normal", "fast", "very fast"],
|
| 574 |
+
help="phase3 speed instruction to the LM (default: the version's setting, 'normal'; 'none' = no instruction)")
|
| 575 |
+
# code-switching control
|
| 576 |
+
ap.add_argument("--auto_tag", action="store_true",
|
| 577 |
+
help="tag untagged mixed text automatically (word/span language ID), print it, then synthesise")
|
| 578 |
+
ap.add_argument("--tag_only", action="store_true", help="with --auto_tag: print the tagged text and exit (edit it, then pass it back as --text)")
|
| 579 |
+
ap.add_argument("--force_lang", choices=LANGS, help="read the whole text in one language (tags are ignored)")
|
| 580 |
+
ap.add_argument("--lang_map", default="", help='per-word language overrides for the tagger, e.g. "omo=pcm,sha=pcm"')
|
| 581 |
+
ap.add_argument("--lid", default="none", choices=["none", "glotlid"],
|
| 582 |
+
help="optional LID model for --auto_tag (glotlid: cis-lmu/glotlid, Apache-2.0, 1.7 GB, pip install fasttext)")
|
| 583 |
ap.add_argument("--seed", type=int, default=0)
|
| 584 |
ap.add_argument("--out", default="out.wav")
|
| 585 |
+
ap.add_argument("--prompt_clip", type=int, default=0, help="anchor prompt clip 0-3 (final systems: 0)")
|
| 586 |
ap.add_argument("--model_dir", default=os.environ.get("COSYVOICE2_DIR", os.path.join(HERE, "pretrained", "CosyVoice2-0.5B")),
|
| 587 |
+
help="stock FunAudioLLM/CosyVoice2-0.5B snapshot (downloaded on first run)")
|
| 588 |
ap.add_argument("--cosyvoice_dir", default=os.environ.get("COSYVOICE_REPO", os.path.join(HERE, "CosyVoice")),
|
| 589 |
help="clone of github.com/FunAudioLLM/CosyVoice (with submodules)")
|
| 590 |
+
ap.add_argument("--lm", default="", help="override the version's LM checkpoint")
|
| 591 |
+
ap.add_argument("--flow", default="", help="override the version's flow checkpoint")
|
| 592 |
ap.add_argument("--prompts", default=os.path.join(HERE, "prompts", "prompts.json"))
|
| 593 |
+
ap.add_argument("--voices", default=os.path.join(HERE, "prompts", "voices.json"))
|
| 594 |
+
ap.add_argument("--dtype", default="auto", choices=["auto", "bf16", "fp16", "fp32"],
|
| 595 |
+
help="LM autocast dtype on GPU (samples: bf16; auto picks fp16 on GPUs without bf16). CPU always runs fp32")
|
| 596 |
+
ap.add_argument("--stitch", action="store_true", help="phase3: generate sentence by sentence instead of one pass")
|
| 597 |
+
ap.add_argument("--no_stitch", action="store_true", help="phase2: generate multi-sentence text in one pass")
|
| 598 |
+
ap.add_argument("--pause_mode", default="model", choices=["clause", "model"], help="phase2 only; clause = experimental prosody v2 (not recommended)")
|
| 599 |
+
ap.add_argument("--speed", type=float, default=DEFAULT_SPEED, help="phase2 only; pitch-preserving tempo factor (1.0 = as trained; not recommended)")
|
| 600 |
a = ap.parse_args()
|
| 601 |
+
if a.list_voices:
|
| 602 |
+
list_voices(a.voices); return
|
| 603 |
+
if not a.text:
|
| 604 |
+
ap.error("--text is required")
|
| 605 |
+
text = prepare_text(a)
|
| 606 |
+
if text != a.text or a.auto_tag:
|
| 607 |
+
print(f"[tagged] {text}")
|
| 608 |
+
if a.tag_only:
|
| 609 |
+
return
|
| 610 |
if not os.path.isdir(a.model_dir):
|
| 611 |
from huggingface_hub import snapshot_download
|
| 612 |
snapshot_download("FunAudioLLM/CosyVoice2-0.5B", local_dir=a.model_dir)
|
| 613 |
+
versions = ["phase2", "phase3"] if a.compare else [a.version]
|
| 614 |
+
cosy = tok = None
|
| 615 |
+
base, ext = os.path.splitext(a.out)
|
| 616 |
+
for v in versions:
|
| 617 |
+
hint = recommendation(v, json.load(open(a.voices)).get("aliases", {}).get(a.voice, a.voice) if os.path.exists(a.voices) else a.voice)
|
| 618 |
+
if hint:
|
| 619 |
+
print(hint)
|
| 620 |
+
S = build(v, a, cosy, tok)
|
| 621 |
+
cosy, tok = S.cosy, S.tok
|
| 622 |
+
w = S.say(text, seed=a.seed, prompt_k=a.prompt_clip, stitch=not a.no_stitch, pause_mode=a.pause_mode,
|
| 623 |
+
speed=a.speed if v == "phase2" else 1.0)
|
| 624 |
+
out = f"{base}_{v}{ext or '.wav'}" if a.compare else a.out
|
| 625 |
+
sf.write(out, w, S.sr)
|
| 626 |
+
print(f"[{v}] wrote {out} ({len(w) / S.sr:.2f} s, {S.sr} Hz, voice={a.voice}, device={DEV.type})")
|
| 627 |
+
del S.m; torch.cuda.empty_cache()
|
| 628 |
|
| 629 |
|
| 630 |
if __name__ == "__main__":
|
prompts/voice_waxal_ibo_5.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d537c83dbe167ccf0b43f03304e456fb05e59dfda6b4e359d941900ef629924f
|
| 3 |
+
size 318044
|
prompts/voice_waxal_yor_5.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ce75b93cf5166d0dc2f53cc943330b4d304f2e060f831d38deb2e664fff49ca5
|
| 3 |
+
size 182924
|
prompts/voices.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"note": "zero-shot voices: the clip is the flow + LM prompt; the speaker token is used when the LM saw that speaker",
|
| 3 |
+
"voices": {
|
| 4 |
+
"anchor_male": {
|
| 5 |
+
"wav": null,
|
| 6 |
+
"lang": "yor",
|
| 7 |
+
"spk": "waxal_yor_4",
|
| 8 |
+
"gender": "male",
|
| 9 |
+
"source": "WAXAL Media Trust TTS, Yoruba speaker 4 (prompts/clip0..3)",
|
| 10 |
+
"licence": "CC-BY-SA-4.0 (Media Trust TTS subset)",
|
| 11 |
+
"desc": "male, WAXAL Yoruba speaker 4: the anchor voice both versions were trained around (uses prompts/prompts.json clip 0)"
|
| 12 |
+
},
|
| 13 |
+
"waxal_ibo_5_female": {
|
| 14 |
+
"wav": "prompts/voice_waxal_ibo_5.wav",
|
| 15 |
+
"tagged": "<ibo>I nwere ike itinye mmemme ọbụla n'izu a ma gị atụla ụjọ maka oké mmiri ozuzo.</ibo>",
|
| 16 |
+
"text": "I nwere ike itinye mmemme ọbụla n'izu a ma gị atụla ụjọ maka oké mmiri ozuzo.",
|
| 17 |
+
"lang": "ibo",
|
| 18 |
+
"spk": "waxal_ibo_5",
|
| 19 |
+
"gender": "female",
|
| 20 |
+
"source_clip": "waxal_ibo_test_ibo_502_c003909",
|
| 21 |
+
"licence": "CC-BY-SA-4.0 (Media Trust TTS subset)",
|
| 22 |
+
"desc": "female native Igbo speaker (WAXAL ibo speaker 5); prompt clip waxal_ibo_test_ibo_502_c003909 (6.625 s)"
|
| 23 |
+
},
|
| 24 |
+
"waxal_yor_5_female": {
|
| 25 |
+
"wav": "prompts/voice_waxal_yor_5.wav",
|
| 26 |
+
"tagged": "<yor>Nínú oṣù Ọpẹ́ ni ó ra mọ́tò tí wọ́n jí gbé.</yor>",
|
| 27 |
+
"text": "Nínú oṣù Ọpẹ́ ni ó ra mọ́tò tí wọ́n jí gbé.",
|
| 28 |
+
"lang": "yor",
|
| 29 |
+
"spk": "waxal_yor_5",
|
| 30 |
+
"gender": "female",
|
| 31 |
+
"source_clip": "waxal_yor_test_yor_686",
|
| 32 |
+
"licence": "CC-BY-SA-4.0 (Media Trust TTS subset)",
|
| 33 |
+
"desc": "female native Yoruba speaker (WAXAL yor speaker 5); prompt clip waxal_yor_test_yor_686 (3.81 s)"
|
| 34 |
+
}
|
| 35 |
+
},
|
| 36 |
+
"aliases": {
|
| 37 |
+
"anchor": "anchor_male",
|
| 38 |
+
"waxal_ibo_5": "waxal_ibo_5_female",
|
| 39 |
+
"waxal_yor_5": "waxal_yor_5_female"
|
| 40 |
+
}
|
| 41 |
+
}
|
requirements.txt
CHANGED
|
@@ -21,7 +21,7 @@ inflect>=7.3
|
|
| 21 |
x-transformers>=2.11
|
| 22 |
openai-whisper>=20231117
|
| 23 |
einops>=0.8
|
| 24 |
-
pyworld>=0.3.4
|
| 25 |
pyarrow>=18
|
| 26 |
wget==3.2
|
| 27 |
gdown>=5.1
|
|
@@ -31,3 +31,5 @@ protobuf>=4.25
|
|
| 31 |
pydantic>=2.7
|
| 32 |
wetext==0.0.4
|
| 33 |
audiotsm==0.1.2 # WSOLA time-stretch for --speed (falls back to librosa if missing)
|
|
|
|
|
|
|
|
|
| 21 |
x-transformers>=2.11
|
| 22 |
openai-whisper>=20231117
|
| 23 |
einops>=0.8
|
| 24 |
+
# pyworld>=0.3.4 # CosyVoice training only; infer.py runs without it
|
| 25 |
pyarrow>=18
|
| 26 |
wget==3.2
|
| 27 |
gdown>=5.1
|
|
|
|
| 31 |
pydantic>=2.7
|
| 32 |
wetext==0.0.4
|
| 33 |
audiotsm==0.1.2 # WSOLA time-stretch for --speed (falls back to librosa if missing)
|
| 34 |
+
gradio>=4.44,<6 # app.py
|
| 35 |
+
# optional, for --lid glotlid / the GlotLID checkbox: fasttext (or fasttext-wheel)
|
samples/phase3/phase2/custom_dynacc.mp3
ADDED
|
Binary file (33.6 kB). View file
|
|
|
samples/phase3/phase2/ibo_000.mp3
ADDED
|
Binary file (42.4 kB). View file
|
|
|
samples/phase3/phase2/omo_announce.mp3
ADDED
|
Binary file (73.5 kB). View file
|
|
|
samples/phase3/phase2/para_hau_eng_pcm.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:cd687cc31eab7f893afd9e8ab1e64a3ce2093c7331ef6a70cd0a5f9a3f33bd72
|
| 3 |
+
size 143876
|
samples/phase3/phase2/para_ibo_pcm_eng.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:afae973f5a0fcbd50931b8dfc8f42d48c91b17f18a584a6558c8609af0e37f41
|
| 3 |
+
size 122636
|
samples/phase3/phase2/para_yor_eng.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:03d0f2bce66da138cbe6e0fe2d38392e638122b82be82dfcb1ba83b3f140d811
|
| 3 |
+
size 123380
|
samples/phase3/phase3/custom_dynacc.mp3
ADDED
|
Binary file (35.7 kB). View file
|
|
|
samples/phase3/phase3/ibo_000.mp3
ADDED
|
Binary file (36.1 kB). View file
|
|
|
samples/phase3/phase3/omo_announce.mp3
ADDED
|
Binary file (66.4 kB). View file
|
|
|
samples/phase3/phase3/para_hau_eng_pcm.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ee8e7b3b1011ef0e6fd6900acae4d7ddc62cbb830b0401492f6a5e40a84b19fa
|
| 3 |
+
size 132620
|
samples/phase3/phase3/para_ibo_pcm_eng.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:be778e8be5554b933e8fcaa5d9deac5150b2defd5fca9351bc3ae483697ed5b4
|
| 3 |
+
size 128036
|
samples/phase3/phase3/para_yor_eng.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2546d9ddde91b773447148cf767f19252bad7efc0914b494e04ee1cf8a23cd99
|
| 3 |
+
size 123884
|
samples/phase3/phase3_female/custom_dynacc__waxal_yor_5.mp3
ADDED
|
Binary file (42.7 kB). View file
|
|
|
samples/phase3/phase3_female/ibo_000__waxal_ibo_5.mp3
ADDED
|
Binary file (28.1 kB). View file
|
|
|
samples/phase3/phase3_female/omo_announce__waxal_ibo_5.mp3
ADDED
|
Binary file (55.5 kB). View file
|
|
|
samples/phase3/phase3_female/omo_announce__waxal_yor_5.mp3
ADDED
|
Binary file (61.3 kB). View file
|
|
|
samples/phase3/phase3_female/para_ibo_pcm_eng__waxal_ibo_5.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:eacca63c857ff58afcce75297eeb4c7e7f9deeb90ebc2dd212e57a026a53121a
|
| 3 |
+
size 119228
|
samples/phase3/phase3_female/para_yor_eng__waxal_yor_5.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0f6b90c343f255c8ffaab0ea92811928dee7b8b985fcd14973c2cbec40f80429
|
| 3 |
+
size 119060
|
settings.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"default_version": "phase3",
|
| 3 |
+
"default_voice": "anchor_male",
|
| 4 |
+
"versions": {
|
| 5 |
+
"phase2": {
|
| 6 |
+
"lm": "checkpoints/phase2/p2_lm_B/best.pt",
|
| 7 |
+
"flow": "checkpoints/phase2/p2_flow_sft/best.pt",
|
| 8 |
+
"sampler": "ras",
|
| 9 |
+
"one_pass": false,
|
| 10 |
+
"postprocess": true,
|
| 11 |
+
"rate": null,
|
| 12 |
+
"desc": "Phase 2 final system: LM p2_lm_B (~120 h, pause profile B) + anchor-SFT flow; sentence by sentence, internal silences capped at 0.6 s"
|
| 13 |
+
},
|
| 14 |
+
"phase3": {
|
| 15 |
+
"lm": "checkpoints/phase3/p3_lm_full/best.pt",
|
| 16 |
+
"flow": "checkpoints/phase2/p2_flow_sft/best.pt",
|
| 17 |
+
"sampler": "silexcap",
|
| 18 |
+
"one_pass": true,
|
| 19 |
+
"postprocess": false,
|
| 20 |
+
"rate": "normal",
|
| 21 |
+
"desc": "Phase 3: LM p3_lm_full (178 h re-cut, ~102 h Igbo, [pause]/[breath] + speed instruction) + the shared Phase 2 flow; one pass per paragraph, model-made pauses"
|
| 22 |
+
}
|
| 23 |
+
},
|
| 24 |
+
"voices": [
|
| 25 |
+
"anchor_male",
|
| 26 |
+
"waxal_ibo_5_female",
|
| 27 |
+
"waxal_yor_5_female"
|
| 28 |
+
],
|
| 29 |
+
"recommended": {
|
| 30 |
+
"phase3": [
|
| 31 |
+
"waxal_ibo_5_female",
|
| 32 |
+
"waxal_yor_5_female"
|
| 33 |
+
],
|
| 34 |
+
"phase2": [
|
| 35 |
+
"anchor_male"
|
| 36 |
+
],
|
| 37 |
+
"note": "Listening verdict (model author, 2026-10-21): Phase 3 sounds best with the female voices; Phase 2 is fine for the male anchor. Use --compare to A/B before use."
|
| 38 |
+
},
|
| 39 |
+
"rates": [
|
| 40 |
+
"none",
|
| 41 |
+
"very slow",
|
| 42 |
+
"slow",
|
| 43 |
+
"normal",
|
| 44 |
+
"fast",
|
| 45 |
+
"very fast"
|
| 46 |
+
]
|
| 47 |
+
}
|
tagger.py
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""Dynamic Accent auto-tagger: word/span-level language ID for untagged mixed Nigerian text.
|
| 3 |
+
|
| 4 |
+
Labels: eng (English), pcm (Nigerian Pidgin), ibo (Igbo), yor (Yoruba), hau (Hausa).
|
| 5 |
+
Output is the tagged text infer.py expects, e.g.
|
| 6 |
+
"omo, I'm very excited" -> "<pcm>omo,</pcm> <eng>I'm very excited</eng>"
|
| 7 |
+
|
| 8 |
+
How it decides (rule-based, no model needed):
|
| 9 |
+
1. letters: Yoruba-only (ẹ ṣ, tone-marked n/m), Igbo-only (ị ụ ṅ), Hausa-only (ɓ ɗ ƙ ƴ), shared ọ;
|
| 10 |
+
2. lexicons of frequent function words / greetings per language (diacritics folded for lookup);
|
| 11 |
+
3. Pidgin markers ("dey", "abi", "omo", "wetin", "abeg", "una", "no go", "e don", "know say", pronoun + "go" + verb ...):
|
| 12 |
+
a clause of plain-ASCII words that contains a Pidgin marker becomes Pidgin as a whole;
|
| 13 |
+
4. clause context: ambiguous words ("na", "o", "ka", "ya", "ma", "ni" ...) and unknown words take the language of the
|
| 14 |
+
clause they sit in, then of the neighbouring clause; plain ASCII with no evidence falls back to English.
|
| 15 |
+
5. optional: --lid glotlid adds clause-level scores from GlotLID v3 (cis-lmu/glotlid, fastText, Apache-2.0 + notices,
|
| 16 |
+
1.7 GB download, needs `pip install fasttext`), mainly to separate untagged Igbo/Yoruba/Hausa written without
|
| 17 |
+
diacritics from English.
|
| 18 |
+
|
| 19 |
+
Overrides: lang_map {"omo": "pcm"} forces a word; force_lang renders everything in one language.
|
| 20 |
+
Always print the tagged text and let the user fix it: the tagger is a convenience, not ground truth.
|
| 21 |
+
|
| 22 |
+
python tagger.py "Omo, this traffic no be here o. I go call you later."
|
| 23 |
+
python tagger.py --lang_map "omo=pcm,sha=pcm" "..."
|
| 24 |
+
"""
|
| 25 |
+
import argparse, json, re, sys, unicodedata
|
| 26 |
+
|
| 27 |
+
LANGS = ["eng", "pcm", "ibo", "yor", "hau"]
|
| 28 |
+
NG = ("ibo", "yor", "hau")
|
| 29 |
+
TAGGED = re.compile(r"<(eng|ibo|hau|yor|pcm)>")
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def fold(w):
|
| 33 |
+
"""lowercase, NFD, drop every combining mark (tones, dot below, dot above), map hooked letters."""
|
| 34 |
+
w = unicodedata.normalize("NFD", w.lower())
|
| 35 |
+
w = "".join(c for c in w if not unicodedata.combining(c))
|
| 36 |
+
return w.translate(str.maketrans({"ɓ": "b", "ɗ": "d", "ƙ": "k", "ƴ": "y", "’": "'", "ʼ": "'", "‘": "'"}))
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def _set(s):
|
| 40 |
+
return {fold(x) for x in s.split()}
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def _exact(s):
|
| 44 |
+
return {unicodedata.normalize("NFC", x.lower()) for x in s.split()}
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# --- lexicons (frequent, high-precision words; folded). Words shared across languages are listed in each.
|
| 48 |
+
_RAW = {
|
| 49 |
+
"ibo": """
|
| 50 |
+
bụ nke ndị ihe ụlọ mmiri kedu ndewo nụ ụmụ ụmụnna nna nne anyị unu gị ha ọ ya ka ma
|
| 51 |
+
nwere ga ji dị ọma biko daalụ dalu ụtọ obi ike nri ego akwụkwọ ọrụ maka ebe otu ọzọ ugbu
|
| 52 |
+
a m n' na mere meela kwa kwesịrị ịga ịbịa bịa gaa nyere aka mmadụ obodo nwanne nwa nwoke nwanyị
|
| 53 |
+
ụbọchị echi taa ụnyaahụ abalị ututu ehihie mgbede oge afọ ọnwa izu ukwuu nnukwu ntakịrị
|
| 54 |
+
mana ọbụna ọbụla ruo site gbasara ebee onye gịnị olee ole kpọmkwem eziokwu nso anọ abụọ atọ
|
| 55 |
+
ise isii asaa asatọ itoolu iri mbụ zuru ezu ahụ ahụla ịhụ hụ chere chọrọ chọ mara amaghị
|
| 56 |
+
nọ nọrọ bịara gara kwuru kwuo sị siri esi na-esi na-eme eme mee eji ogologo ọkụ ụzọ ahịa ụka
|
| 57 |
+
ọnụ ụtụtụ ka ọ dị mma mma nnọọ kpọọ zụta re ree rie riri ụmụaka ezinụlọ chi chukwu ndụ
|
| 58 |
+
""",
|
| 59 |
+
"yor": """
|
| 60 |
+
ni ti si sí àti àwọn mo o wa wọn kò ṣé jẹ́ ọjọ́ ẹ káàbọ̀ ilé ìlú ọmọ púpọ̀ dáadáa bẹ́ẹ̀ ni
|
| 61 |
+
náà yìí kan mi wa yín rẹ̀ rẹ tirẹ̀ fún láti pé ń máa yóò ó a jẹ ṣe lọ wá rí fẹ́ mọ̀ sọ gbọ́
|
| 62 |
+
ẹ̀kọ́ iṣẹ́ owó ọjà òní ọ̀la àná ìpàdé padà ilé-ìwé ọjọ́ ajé ìsinmi alẹ́ àárọ̀ káàárọ̀ káàsán
|
| 63 |
+
káalẹ́ ẹ kú ṣé gan an pàdé ìyá bàbá ẹ̀gbọ́n àbúrò ọ̀rẹ́ ènìyàn èèyàn àgbà ọba ìjọba
|
| 64 |
+
nítorí ṣùgbọ́n tàbí bí kí kì ìgbà ibi ibo kílódé báwo kíni ta tani mélòó ọ̀kan méjì mẹ́ta
|
| 65 |
+
mẹ́rin márùn-ún ẹ̀ẹ̀kan dúpẹ́ ẹ ṣeun ẹ̀ jọ̀ọ́ jọ̀ọ́ oúnjẹ omi ilẹ̀ ojú ọwọ́ ẹsẹ̀
|
| 66 |
+
""",
|
| 67 |
+
"hau": """
|
| 68 |
+
da ba ya ta ka ki su mu na ne ce ina yaya barka kuke don haka za idan mai wannan wancan yana
|
| 69 |
+
tana suna muna kuna sannu lafiya kwana aiki gobe yau jiya ruwa sai amma kuma shi ita nan
|
| 70 |
+
wani wata abin zan zai zata zamu mutane gida kudi gode sosai tafi fita zuwa laima yamma safe
|
| 71 |
+
rana dare mako shekara wata yanzu kai ke ku mun sun ban bai bata sani so iya yi yin
|
| 72 |
+
farashin tumatur tashi kasuwa abinci ruwan sha babu akwai kamar saboda domin tare har tun
|
| 73 |
+
daga cikin waje gaba baya sama kasa me wane wace ina yaushe nawa daya biyu uku hudu biyar
|
| 74 |
+
""",
|
| 75 |
+
"pcm": """
|
| 76 |
+
dey abi omo wetin abeg una wahala sabi oga sef sha oya jare ehn ehen shey kpele pikin
|
| 77 |
+
chop comot waka belle palava wan wey dem don am siddon gist gbam yawa kampe sharp sharp
|
| 78 |
+
nawa wahala kolo japa ginger vex dash ogbonge padi paddy shine eye
|
| 79 |
+
""",
|
| 80 |
+
"eng": """
|
| 81 |
+
the a an and or but if then so because of to in on at for with from by about as into over
|
| 82 |
+
after before between through during without under again further here there when where why how
|
| 83 |
+
all any both each few more most other some such no nor not only own same than too very can
|
| 84 |
+
will just should now i me my we our you your he him his she her it its they them their what
|
| 85 |
+
which who whom this that these those am is are was were be been being have has had having do
|
| 86 |
+
does did doing would could might must shall may please thank thanks yes hello hi good morning
|
| 87 |
+
evening afternoon night today tomorrow yesterday week year time day people man woman child
|
| 88 |
+
children team meeting report school market road weather rain safe everyone everybody
|
| 89 |
+
new old big small great right left back home work job money food water house car family
|
| 90 |
+
friend friends know think say said tell told make made take took get got give gave go went
|
| 91 |
+
come came see saw look want need like love help call send sent finish start stop keep let put
|
| 92 |
+
read write talk speak discuss three two one four five six seven eight nine ten first second
|
| 93 |
+
last next soon late early ready sure also still really very much many lot thing things way
|
| 94 |
+
out up down off well done going coming doing nothing something everything anything model
|
| 95 |
+
""",
|
| 96 |
+
}
|
| 97 |
+
LEX = {l: _set(v) for l, v in _RAW.items()} # folded (diacritics dropped) for lookup
|
| 98 |
+
LEX_EXACT = {l: _exact(v) for l, v in _RAW.items()} # as written
|
| 99 |
+
_N_LEX = {}
|
| 100 |
+
for _l, _v in LEX.items():
|
| 101 |
+
for _w in _v:
|
| 102 |
+
_N_LEX[_w] = _N_LEX.get(_w, 0) + 1 # >1 = word shared by several languages (na, o, ka, ya ...)
|
| 103 |
+
# words that are Pidgin markers on their own (strong evidence)
|
| 104 |
+
PCM_STRONG = _set("dey abi omo wetin abeg una wahala sabi sef oya jare shey pikin chop comot waka palava wan wey dem siddon vex japa ehn ehen")
|
| 105 |
+
PCM_BIGRAMS = {("no", "go"), ("no", "be"), ("no", "fit"), ("no", "dey"), ("e", "don"), ("e", "dey"), ("e", "no"),
|
| 106 |
+
("know", "say"), ("tell", "am"), ("well", "well"), ("how", "far"), ("how", "body"), ("na", "so"),
|
| 107 |
+
("make", "we"), ("make", "i"), ("make", "una"), ("make", "dem"), ("i", "no"), ("we", "no"),
|
| 108 |
+
("you", "no"), ("dem", "no"), ("no", "easy"), ("no", "forget"), ("no", "vex"), ("fit", "heavy"),
|
| 109 |
+
("don", "come"), ("don", "go"), ("for", "inside"), ("una", "well"), ("e", "go"), ("na", "you"),
|
| 110 |
+
("na", "me"), ("na", "im"), ("na", "dem"), ("na", "una"), ("give", "you"), ("lie", "give")}
|
| 111 |
+
PRON = _set("i we you dem una e im him she he they")
|
| 112 |
+
NOT_VERB_AFTER_GO = _set("to home there back out away on in up down off ahead")
|
| 113 |
+
PCM_AMBIG_END = _set("o") # clause-final particle "o" in an ASCII clause -> Pidgin evidence
|
| 114 |
+
|
| 115 |
+
YOR_CH = set("ẹṣ") # after NFC lowercase; also e/s + U+0323
|
| 116 |
+
IBO_CH = set("ịụṅ")
|
| 117 |
+
HAU_CH = set("ɓɗƙƴ")
|
| 118 |
+
WORD = re.compile(r"[^\W\d_](?:[^\W\d_]|['’ʼ\-\u0300-\u036f])*", re.U)
|
| 119 |
+
CLAUSE_END = re.compile(r"[,;:.?!]")
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def char_scores(w):
|
| 123 |
+
s = dict.fromkeys(LANGS, 0.0)
|
| 124 |
+
nfd = unicodedata.normalize("NFD", w.lower())
|
| 125 |
+
base = None
|
| 126 |
+
for c in nfd:
|
| 127 |
+
if unicodedata.combining(c):
|
| 128 |
+
if c == "\u0323": # dot below
|
| 129 |
+
if base in "es":
|
| 130 |
+
s["yor"] += 3
|
| 131 |
+
elif base in "iu":
|
| 132 |
+
s["ibo"] += 3
|
| 133 |
+
elif base == "o":
|
| 134 |
+
s["yor"] += 1; s["ibo"] += 1
|
| 135 |
+
elif c == "\u0307" and base == "n":
|
| 136 |
+
s["ibo"] += 3
|
| 137 |
+
elif c in "\u0300\u0301\u0304": # tones
|
| 138 |
+
if base in "nm":
|
| 139 |
+
s["yor"] += 2
|
| 140 |
+
else:
|
| 141 |
+
s["yor"] += 0.8; s["ibo"] += 0.3
|
| 142 |
+
continue
|
| 143 |
+
base = c
|
| 144 |
+
if c in HAU_CH:
|
| 145 |
+
s["hau"] += 4
|
| 146 |
+
if not any(s.values()) and re.fullmatch(r"[a-z'\-]+", fold(w)):
|
| 147 |
+
s["ascii"] = 1
|
| 148 |
+
return s
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def word_scores(w):
|
| 152 |
+
s = char_scores(w)
|
| 153 |
+
ascii_ = s.pop("ascii", 0)
|
| 154 |
+
f = fold(w)
|
| 155 |
+
parts = [f] + (f.split("-") if "-" in f else [])
|
| 156 |
+
if f.startswith("n'") or re.match(r"^na-[a-z]", f):
|
| 157 |
+
s["ibo"] += 3
|
| 158 |
+
ex = unicodedata.normalize("NFC", w.lower())
|
| 159 |
+
for p in parts:
|
| 160 |
+
amb = 0.5 if _N_LEX.get(p, 0) > 1 else 1.0 # shared words: let the clause decide
|
| 161 |
+
for l in LANGS:
|
| 162 |
+
if p in LEX[l]:
|
| 163 |
+
w_ = 1.5 if (p == f and ex in LEX_EXACT[l]) or ascii_ and p in LEX_EXACT[l] else 0.7
|
| 164 |
+
s[l] += amb * (w_ if l != "pcm" else 1.0)
|
| 165 |
+
if f in PCM_STRONG and ascii_: # Pidgin markers are plain ASCII ("ọmọ" is Yoruba)
|
| 166 |
+
s["pcm"] += 4
|
| 167 |
+
# orthography hints (weak)
|
| 168 |
+
if ascii_:
|
| 169 |
+
if re.search(r"(th|wh|ck|tion|ing$|ould$|ght)", f):
|
| 170 |
+
s["eng"] += 1
|
| 171 |
+
if re.match(r"^(nw|kw|gw|mm|nn|nk|ng[a-z])", f) and f not in LEX["eng"]:
|
| 172 |
+
s["ibo"] += 0.7
|
| 173 |
+
if re.search(r"(ts|^ky|^'y|aa|ii|uu)", f) and f not in LEX["eng"]:
|
| 174 |
+
s["hau"] += 0.5
|
| 175 |
+
return s, bool(ascii_)
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def tokenize(text):
|
| 179 |
+
"""-> list of (start, end, word) for words; everything else is glue."""
|
| 180 |
+
return [(m.start(), m.end(), m.group(0)) for m in WORD.finditer(text)]
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def clauses(text, toks):
|
| 184 |
+
"""clause index for each word: a new clause starts after , ; : . ? !"""
|
| 185 |
+
ends = [m.start() for m in CLAUSE_END.finditer(text)]
|
| 186 |
+
out, k = [], 0
|
| 187 |
+
for a, b, w in toks:
|
| 188 |
+
while k < len(ends) and ends[k] < a:
|
| 189 |
+
k += 1
|
| 190 |
+
out.append(k)
|
| 191 |
+
return out
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def _norm(d):
|
| 195 |
+
t = sum(max(0.0, v) for v in d.values())
|
| 196 |
+
return {k: (max(0.0, v) / t if t else 0.0) for k, v in d.items()}
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
class Tagger:
|
| 200 |
+
def __init__(self, lid=None, lang_map=None):
|
| 201 |
+
self.lang_map = {fold(k): v for k, v in (lang_map or {}).items()}
|
| 202 |
+
self.lid = None
|
| 203 |
+
if lid == "glotlid":
|
| 204 |
+
import fasttext
|
| 205 |
+
from huggingface_hub import hf_hub_download
|
| 206 |
+
self.lid = fasttext.load_model(hf_hub_download("cis-lmu/glotlid", "model.bin"))
|
| 207 |
+
|
| 208 |
+
def _lid_scores(self, text):
|
| 209 |
+
labs, ps = self.lid.predict(text.replace("\n", " "), k=20)
|
| 210 |
+
m = {"__label__eng_Latn": "eng", "__label__pcm_Latn": "pcm", "__label__ibo_Latn": "ibo",
|
| 211 |
+
"__label__yor_Latn": "yor", "__label__hau_Latn": "hau"}
|
| 212 |
+
s = dict.fromkeys(LANGS, 0.0)
|
| 213 |
+
for l, p in zip(labs, ps):
|
| 214 |
+
if l in m:
|
| 215 |
+
s[m[l]] += float(p)
|
| 216 |
+
return s
|
| 217 |
+
|
| 218 |
+
def word_langs(self, text):
|
| 219 |
+
toks = tokenize(text)
|
| 220 |
+
if not toks:
|
| 221 |
+
return toks, []
|
| 222 |
+
cl = clauses(text, toks)
|
| 223 |
+
n = len(toks)
|
| 224 |
+
sc, asc = zip(*[word_scores(w) for _, _, w in toks])
|
| 225 |
+
sc = [dict(s) for s in sc]
|
| 226 |
+
f = [fold(w) for _, _, w in toks]
|
| 227 |
+
# Pidgin bigrams and "pronoun go verb"
|
| 228 |
+
for i in range(n - 1):
|
| 229 |
+
if cl[i] != cl[i + 1]:
|
| 230 |
+
continue
|
| 231 |
+
if (f[i], f[i + 1]) in PCM_BIGRAMS:
|
| 232 |
+
sc[i]["pcm"] += 2.5; sc[i + 1]["pcm"] += 2.5
|
| 233 |
+
if i + 2 < n and f[i] in PRON and f[i + 1] == "go" and cl[i + 2] == cl[i] and f[i + 2] not in NOT_VERB_AFTER_GO \
|
| 234 |
+
and f[i + 2] in LEX["eng"] | LEX["pcm"]:
|
| 235 |
+
for j in (i, i + 1, i + 2):
|
| 236 |
+
sc[j]["pcm"] += 2.5
|
| 237 |
+
# clause-level evidence
|
| 238 |
+
C = sorted(set(cl))
|
| 239 |
+
cs = {c: dict.fromkeys(LANGS, 0.0) for c in C}
|
| 240 |
+
for i in range(n):
|
| 241 |
+
for l in LANGS:
|
| 242 |
+
cs[cl[i]][l] += sc[i][l]
|
| 243 |
+
# clause-final "o" in an ASCII clause = Pidgin particle (Yoruba "o" clauses carry other Yoruba evidence)
|
| 244 |
+
for i in range(n):
|
| 245 |
+
last = i == n - 1 or cl[i + 1] != cl[i]
|
| 246 |
+
if last and f[i] in PCM_AMBIG_END and asc[i]:
|
| 247 |
+
others = [j for j in range(n) if cl[j] == cl[i] and j != i]
|
| 248 |
+
if others and all(asc[j] for j in others) and cs[cl[i]]["yor"] < 2:
|
| 249 |
+
sc[i]["pcm"] += 3; cs[cl[i]]["pcm"] += 3
|
| 250 |
+
if self.lid is not None:
|
| 251 |
+
for c in C:
|
| 252 |
+
ws = [toks[i][2] for i in range(n) if cl[i] == c]
|
| 253 |
+
for l, v in self._lid_scores(" ".join(ws)).items():
|
| 254 |
+
cs[c][l] += 2.0 * v
|
| 255 |
+
out = []
|
| 256 |
+
for i in range(n):
|
| 257 |
+
c = cl[i]
|
| 258 |
+
ctx = _norm(cs[c])
|
| 259 |
+
nb = dict.fromkeys(LANGS, 0.0) # neighbouring clauses, weaker
|
| 260 |
+
for d in (-1, 1):
|
| 261 |
+
if c + d in cs:
|
| 262 |
+
for l, v in _norm(cs[c + d]).items():
|
| 263 |
+
nb[l] += 0.3 * v
|
| 264 |
+
tot = {l: sc[i][l] + 1.5 * ctx[l] + nb[l] for l in LANGS}
|
| 265 |
+
# plain-ASCII words in a clause without Nigerian-language evidence: English or Pidgin
|
| 266 |
+
if asc[i] and max(sc[i][l] for l in NG) < 1.0:
|
| 267 |
+
ng_ctx = max(cs[c][l] for l in NG)
|
| 268 |
+
if ng_ctx < 1.5 * max(cs[c]["eng"], cs[c]["pcm"], 0.1):
|
| 269 |
+
pc = cs[c]["pcm"] >= 2.5
|
| 270 |
+
out.append("pcm" if pc else ("eng" if sc[i]["pcm"] < 4 else "pcm"))
|
| 271 |
+
continue
|
| 272 |
+
best = max(tot, key=tot.get)
|
| 273 |
+
if tot[best] <= 0:
|
| 274 |
+
best = "eng"
|
| 275 |
+
out.append(best)
|
| 276 |
+
for i in range(n): # user overrides
|
| 277 |
+
if f[i] in self.lang_map:
|
| 278 |
+
out[i] = self.lang_map[f[i]]
|
| 279 |
+
return toks, out
|
| 280 |
+
|
| 281 |
+
def tag(self, text, force_lang=None):
|
| 282 |
+
text = unicodedata.normalize("NFC", text.strip())
|
| 283 |
+
if TAGGED.search(text):
|
| 284 |
+
return text # already tagged: leave alone
|
| 285 |
+
if force_lang:
|
| 286 |
+
return f"<{force_lang}>{text}</{force_lang}>"
|
| 287 |
+
toks, langs = self.word_langs(text)
|
| 288 |
+
if not toks:
|
| 289 |
+
return f"<eng>{text}</eng>"
|
| 290 |
+
# spans: consecutive same-language words; glue (spaces/punct) stays with the preceding word
|
| 291 |
+
spans, cur_l, a = [], langs[0], 0
|
| 292 |
+
for i in range(1, len(toks)):
|
| 293 |
+
if langs[i] != cur_l:
|
| 294 |
+
b = toks[i][0]
|
| 295 |
+
seg = text[a:b]
|
| 296 |
+
spans.append((cur_l, seg))
|
| 297 |
+
cur_l, a = langs[i], b
|
| 298 |
+
spans.append((cur_l, text[a:]))
|
| 299 |
+
lead = text[:toks[0][0]]
|
| 300 |
+
out = []
|
| 301 |
+
for k, (l, s) in enumerate(spans):
|
| 302 |
+
s2 = (lead + s) if k == 0 else s
|
| 303 |
+
core = s2.rstrip()
|
| 304 |
+
out.append(f"<{l}>{core}</{l}>")
|
| 305 |
+
return " ".join(out)
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
def parse_map(s):
|
| 309 |
+
m = {}
|
| 310 |
+
for kv in (s or "").split(","):
|
| 311 |
+
if "=" in kv:
|
| 312 |
+
k, v = kv.split("=", 1)
|
| 313 |
+
v = v.strip()
|
| 314 |
+
if v not in LANGS:
|
| 315 |
+
raise ValueError(f"--lang_map: unknown language '{v}' (use {LANGS})")
|
| 316 |
+
m[k.strip()] = v
|
| 317 |
+
return m
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
def spans_of(tagged):
|
| 321 |
+
return [(m.group(1), m.group(2)) for m in re.finditer(r"<(eng|ibo|hau|yor|pcm)>(.*?)</\1>", tagged, re.S)]
|
| 322 |
+
|
| 323 |
+
|
| 324 |
+
def word_labels(tagged):
|
| 325 |
+
"""gold/pred word-level labels from a tagged string."""
|
| 326 |
+
out = []
|
| 327 |
+
for l, s in spans_of(tagged):
|
| 328 |
+
out += [(fold(w), l) for _, _, w in tokenize(s)]
|
| 329 |
+
return out
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def strip_tags(tagged):
|
| 333 |
+
return re.sub(r"\s+", " ", re.sub(r"</?(eng|ibo|hau|yor|pcm)>", "", tagged)).strip()
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
def main():
|
| 337 |
+
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
| 338 |
+
ap.add_argument("text")
|
| 339 |
+
ap.add_argument("--lang_map", default="", help='per-word overrides, e.g. "omo=pcm,sha=pcm"')
|
| 340 |
+
ap.add_argument("--force_lang", choices=LANGS)
|
| 341 |
+
ap.add_argument("--lid", choices=["none", "glotlid"], default="none")
|
| 342 |
+
a = ap.parse_args()
|
| 343 |
+
t = Tagger(None if a.lid == "none" else a.lid, parse_map(a.lang_map))
|
| 344 |
+
print(t.tag(a.text, a.force_lang))
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
if __name__ == "__main__":
|
| 348 |
+
main()
|