prakharkhatri prakhar khatri commited on
Commit
241501a
·
0 Parent(s):

IndiCodec v1.0

Browse files

Co-authored-by: prakhar khatri <prakhar khatri@users.noreply.huggingface.co>

.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ assets/architecture.png filter=lfs diff=lfs merge=lfs -text
LICENSE 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 ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ language:
4
+ - en
5
+ - hi
6
+ - bn
7
+ - gu
8
+ - kn
9
+ - ml
10
+ - mr
11
+ - or
12
+ - pa
13
+ - ta
14
+ - te
15
+ tags:
16
+ - audio
17
+ - speech
18
+ - audio-codec
19
+ - speech-tokenizer
20
+ - speech-language-models
21
+ pipeline_tag: audio-to-audio
22
+ datasets:
23
+ - amphion/Emilia-Dataset
24
+ - mythicinfinity/libritts
25
+ - mythicinfinity/libritts_r
26
+ - CSTR-Edinburgh/vctk
27
+ - ai4bharat/Rasa
28
+ - ai4bharat/indicvoices_r
29
+ - ai4bharat/IndicVoices
30
+ ---
31
+
32
+ # IndiCodec
33
+
34
+ [Audio samples](https://codeprakhar25.github.io/IndiCodec/) · [Code on GitHub](https://github.com/codeprakhar25/IndiCodec)
35
+
36
+ A 1.09 kbps neural speech codec for building speech language models and TTS. It turns speech into two streams of
37
+ integer tokens and decodes them back to 24 kHz audio.
38
+
39
+ It was trained mostly on English and 10 Indian languages, and it is strongest on Indian languages: among codecs at
40
+ about 1 kbps, it keeps the most words in every one of the 10 we tested.
41
+
42
+ ## Key features
43
+
44
+ - **Low bitrate:** 1.09 kbps, 75 tokens per second.
45
+ - **Two token streams:** a content stream (25 Hz) that carries the words, and an acoustic stream (50 Hz) that carries
46
+ the voice and detail.
47
+ - **Split FSQ, not RVQ:** each stream is a single FSQ grid. Content is coded first, and one acoustic grid codes what
48
+ remains, instead of a stack of residual codebooks. Each frame is one id per stream, with no learned codebook.
49
+ - **16 kHz in, 24 kHz out:** any input sample rate is resampled to 16 kHz.
50
+ - **One file:** all weights are in `model.safetensors`. Nothing else is downloaded.
51
+ - **Commercial use allowed:** Apache 2.0. All training data is under open licences, none of them non-commercial.
52
+
53
+ ## Model details
54
+
55
+ | | |
56
+ |---|---|
57
+ | Content stream | 25 Hz, FSQ 8 × 3 levels = 6,561 ids, 317 bps |
58
+ | Acoustic stream | 50 Hz, FSQ 6 × 6 levels = 46,656 ids, 775 bps |
59
+ | Bitrate | 1.09 kbps |
60
+ | Parameters | 624 M in the file, 387 M of them w2v-BERT 2.0; decoding alone uses 186 M |
61
+ | Licence | Apache 2.0 |
62
+
63
+ The content stream quantises w2v-BERT 2.0 features (layer 16). The acoustic stream quantises what a CNN encoder hears
64
+ beyond the content stream. A transformer decoder with an iSTFT head turns the sum back into audio.
65
+
66
+ IndiCodec is built on [NeuCodec](https://huggingface.co/neuphonic/neucodec) by Neuphonic: it uses NeuCodec's
67
+ architecture, and training started from its released weights. The two-stream quantiser, the encoder training and the
68
+ training recipe are new.
69
+
70
+ ## Quality
71
+
72
+ Speech codecs at about 1 kbps, on speakers not seen in training. Every codec is scored on the same clips.
73
+
74
+ PESQ-WB (higher is better):
75
+
76
+ | Test set | IndiCodec<br>1.09 kbps | Mimi, 8 codebooks<br>1.10 kbps | SNAC 24 kHz<br>0.98 kbps | NeuCodec<br>0.80 kbps |
77
+ |---|---|---|---|---|
78
+ | LibriTTS-R test (English) | **2.41** | 2.32 | 2.29 | 2.19 |
79
+ | CMU-Arctic (English) | **2.30** | 2.28 | 2.17 | 2.06 |
80
+ | Seed-TTS eval (English) | 1.99 | **2.07** | 1.82 | 1.81 |
81
+ | FLEURS, 10 Indian languages | **1.90** | 1.84 | 1.69 | 1.69 |
82
+
83
+ Words after a round trip (lower is better):
84
+
85
+ | | IndiCodec | Mimi | SNAC | NeuCodec |
86
+ |---|---|---|---|---|
87
+ | English WER, Seed-TTS eval | **2.5 %** | 3.6 % | 4.9 % | 3.5 % |
88
+ | English WER, CMU-Arctic | **2.3 %** | 3.2 % | 3.8 % | 2.8 % |
89
+ | Indian-language CER, FLEURS, 10 languages | **6.3 %** | 14.3 % | 13.3 % | 8.9 % |
90
+ | Tokens per second | 75 | 100 | 82 | 50 |
91
+
92
+ English WER uses Whisper large-v3. Indian-language CER uses the IndicConformer 600M ASR; the original recordings score
93
+ 5.2 %, so IndiCodec adds 1.0 point. The 10 languages are Hindi, Bengali, Gujarati, Kannada, Malayalam, Marathi, Odia,
94
+ Punjabi, Tamil and Telugu.
95
+
96
+ ## Use
97
+
98
+ ```bash
99
+ hf download prakharkhatri/IndiCodec --local-dir IndiCodec && cd IndiCodec
100
+ pip install torch==2.6.0 torchaudio==2.6.0 safetensors soundfile transformers==4.51.* vector-quantize-pytorch==1.17.8 torchtune==0.5.0 torchao==0.9.0 local-attention einops librosa
101
+ pip install --no-deps "git+https://github.com/neuphonic/neucodec@ed3e6cd"
102
+ ```
103
+
104
+ ```python
105
+ import soundfile as sf
106
+ from indicodec import IndiCodec
107
+
108
+ codec = IndiCodec.load("model.safetensors")
109
+ wav, sr = sf.read("speech.wav")
110
+
111
+ content, acoustic = codec.encode(wav, sr) # token arrays
112
+ audio = codec.decode(content, acoustic) # 24 kHz
113
+ ```
114
+
115
+ ## Training data
116
+
117
+ English: Emilia-YODAS (English part only), LibriTTS, LibriTTS-R and VCTK. Indian languages: Rasa, IndicVoices-R and
118
+ IndicVoices from AI4Bharat. Plus about 15 h of laughs, sighs and coughs from VocalSound. All CC BY 4.0, except
119
+ VocalSound (CC BY-SA 4.0). No audio is included in this release.
120
+
121
+ ## Limits
122
+
123
+ - Speech only; not for music.
124
+ - Not streaming: the encoder and the decoder both attend over the whole clip.
125
+
126
+ ## Licence
127
+
128
+ Apache 2.0. Built on [NeuCodec](https://huggingface.co/neuphonic/neucodec) (Apache 2.0). The bundled w2v-BERT 2.0
129
+ layers are Meta's, under MIT; its licence text is in `indicodec/w2v_bert/LICENSE`.
config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "indicodec",
3
+ "version": "1.0",
4
+ "weights": "model.safetensors",
5
+ "sample_rate_in": 16000,
6
+ "sample_rate_out": 24000,
7
+ "bitrate_bps": 1092,
8
+ "tokens_per_second": 75,
9
+ "content": {"hz": 25, "fsq_levels": [3, 3, 3, 3, 3, 3, 3, 3], "n_ids": 6561},
10
+ "acoustic": {"hz": 50, "fsq_levels": [6, 6, 6, 6, 6, 6], "n_ids": 46656},
11
+ "w2v_bert": {"source": "facebook/w2v-bert-2.0", "layers": 16, "bundled": true}
12
+ }
indicodec/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .infer import IndiCodec
2
+
3
+ __all__ = ["IndiCodec"]
indicodec/codec_spec.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "IndiCodec v1.0",
3
+ "ckpt": "model.safetensors",
4
+ "md5_safetensors": "7d9f2d7d04893de3706fcefcd33450ce",
5
+ "md5": "986a7c393c2168a00c56dfb96751a0d4",
6
+ "w2v_bert": {"source": "facebook/w2v-bert-2.0", "revision": "da985ba0987f70aaeb84a80f2851cfac8c697a7b", "layers": 16, "in_file": true},
7
+ "sample_rate_encoders": 16000,
8
+ "sample_rate_out": 24000,
9
+ "bitrate_bps": 1092,
10
+ "content": {
11
+ "levels": [3, 3, 3, 3, 3, 3, 3, 3],
12
+ "hz": 25,
13
+ "n_ids": 6561,
14
+ "bps": 317
15
+ },
16
+ "acoustic": {
17
+ "levels": [6, 6, 6, 6, 6, 6],
18
+ "hz": 50,
19
+ "n_ids": 46656,
20
+ "bps": 775
21
+ },
22
+ "hop_16": 320,
23
+ "hop_24": 480,
24
+ "n_fft": 1920,
25
+ "tail_frames": 2,
26
+ "level_db": null,
27
+ "decoder": "vocos_istft_12",
28
+ "amp_cuda": "bf16"
29
+ }
indicodec/infer.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """IndiCodec inference. Self-contained; the release file needs no weight download.
2
+
3
+ from indicodec import IndiCodec
4
+ c = IndiCodec.load("model.safetensors") # release file; the internal .pt still loads
5
+ idx_s, idx_a = c.encode(wav, sr)
6
+ wav24 = c.decode(idx_s, idx_a, n_samples=n24)
7
+ wav24 = c.reconstruct(wav, sr)
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import hashlib
12
+ import json
13
+ import os
14
+ from pathlib import Path
15
+
16
+ import numpy as np
17
+ import torch
18
+
19
+ _HERE = Path(__file__).resolve().parent
20
+ _SPEC = json.loads((_HERE / "codec_spec.json").read_text())
21
+
22
+
23
+ def md5_file(p: Path) -> str:
24
+ h = hashlib.md5()
25
+ with open(p, "rb") as f:
26
+ for b in iter(lambda: f.read(1 << 24), b""):
27
+ h.update(b)
28
+ return h.hexdigest()
29
+
30
+
31
+ def n24_of(wav, sr: int) -> int:
32
+ return int(round(len(wav) * _SPEC["sample_rate_out"] / sr))
33
+
34
+
35
+ def _refuse_train_flags(st: dict) -> None:
36
+ bad = []
37
+ if st.get("acoustic_continuous"):
38
+ bad.append("acoustic_continuous")
39
+ if int(st.get("acoustic_frames") or 1) != 1:
40
+ bad.append(f"acoustic_frames={st.get('acoustic_frames')}")
41
+ if st.get("rope_fix"):
42
+ bad.append("rope_fix")
43
+ if int(st.get("phase2d") or 0):
44
+ bad.append(f"phase2d={st.get('phase2d')}")
45
+ if bad:
46
+ raise SystemExit(f"IndiCodec infer refuses {bad}: not an IndiCodec release checkpoint")
47
+
48
+
49
+ def read_ckpt(p: Path) -> tuple[dict, str]:
50
+ """md5-check a weight file against the spec and return ({"gen", "tail_frames", "levels_a", ...}, md5)."""
51
+ got = md5_file(p)
52
+ if p.suffix == ".safetensors": # release format (2026-10-25): tensors only, no pickle
53
+ want = _SPEC["md5_safetensors"]
54
+ if got != want:
55
+ raise SystemExit(f"{p} md5 {got} != spec {want}")
56
+ from safetensors import safe_open
57
+ with safe_open(str(p), framework="pt", device="cpu") as f:
58
+ meta = f.metadata() or {}
59
+ gen = {k: f.get_tensor(k) for k in f.keys()}
60
+ st = {"gen": gen, "meta": meta, "tail_frames": int(meta.get("tail_frames", 0)),
61
+ "levels_a": [int(x) for x in meta.get("levels_a", "").split(",") if x]}
62
+ else: # internal training checkpoint (pickle)
63
+ want = _SPEC["md5"]
64
+ if got != want:
65
+ raise SystemExit(f"{p} md5 {got} != spec {want}")
66
+ st = torch.load(p, map_location="cpu", weights_only=False)
67
+ return st, got
68
+
69
+
70
+ class IndiCodec:
71
+ def __init__(self, model, device: str, amp: bool, ckpt_md5: str):
72
+ self.model = model
73
+ self.device = device
74
+ self.amp = amp
75
+ self.ckpt_md5 = ckpt_md5
76
+ self.spec = _SPEC
77
+
78
+ @classmethod
79
+ def load(cls, ckpt: str | Path, device: str | None = None, amp: bool | None = None) -> "IndiCodec":
80
+ try:
81
+ from .model import IndiNet
82
+ except ImportError:
83
+ from model import IndiNet # folder-alone: infer.py + model.py side by side
84
+
85
+ p = Path(ckpt)
86
+ st, got = read_ckpt(p)
87
+ if int(st.get("tail_frames", 0)) != int(_SPEC["tail_frames"]):
88
+ raise SystemExit(f"ckpt tail_frames {st.get('tail_frames')} != spec {_SPEC['tail_frames']}")
89
+ if list(st.get("levels_a") or []) != list(_SPEC["acoustic"]["levels"]):
90
+ raise SystemExit(f"ckpt levels_a {st.get('levels_a')} != spec {_SPEC['acoustic']['levels']}")
91
+ _refuse_train_flags(st)
92
+ bundled = any(k.startswith("semantic_model.") for k in st["gen"]) # release file; the .pt has no w2v-BERT
93
+ m = IndiNet(levels_a=st.get("levels_a"), w2v_bundled=bundled)
94
+ m.load_gen(st["gen"])
95
+ m.tail_frames = int(st.get("tail_frames", 0))
96
+ if device is None:
97
+ device = "cuda" if torch.cuda.is_available() else "cpu"
98
+ m.to(device).eval()
99
+ if amp is None:
100
+ amp = device != "cpu"
101
+ return cls(m, device, amp, got)
102
+
103
+ def encode(self, wav, sr: int) -> tuple[np.ndarray, np.ndarray]:
104
+ try:
105
+ from .model import encode_wav
106
+ except ImportError:
107
+ from model import encode_wav
108
+ idx_s, idx_a, _ = encode_wav(self.model, wav, sr, self.device, amp=self.amp)
109
+ return idx_s.detach().cpu().numpy(), idx_a.detach().cpu().numpy()
110
+
111
+ @torch.no_grad()
112
+ def decode(self, idx_s, idx_a, n_samples: int | None = None) -> np.ndarray:
113
+ s = torch.as_tensor(idx_s, device=self.device)
114
+ a = torch.as_tensor(idx_a, device=self.device)
115
+ with torch.autocast("cuda", dtype=torch.bfloat16, enabled=self.amp and self.device != "cpu"):
116
+ y = self.model.decode_codes(s, a, mode="full").float().cpu().numpy().reshape(-1)
117
+ if n_samples is None:
118
+ return y
119
+ return y[:n_samples] if len(y) >= n_samples else np.pad(y, (0, n_samples - len(y)))
120
+
121
+ def reconstruct(self, wav, sr: int) -> np.ndarray:
122
+ return self.decode(*self.encode(wav, sr), n_samples=n24_of(wav, sr))
123
+
124
+ def deterministic(self, on: bool = True) -> None:
125
+ if on:
126
+ os.environ.setdefault("CUBLAS_WORKSPACE_CONFIG", ":4096:8")
127
+ torch.backends.cudnn.deterministic = on
128
+ torch.backends.cudnn.benchmark = not on
129
+ torch.use_deterministic_algorithms(on, warn_only=True)
indicodec/model.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """IndiCodec inference graph. No weight download.
2
+
3
+ Architecture classes still come from installed `neucodec` (Apache 2.0, commit ed3e6cd).
4
+ The release model.safetensors holds every tensor, including the 16 w2v-BERT 2.0 (MIT) layers we use, built from the
5
+ shipped w2v_bert/config.json. The internal .pt has no w2v-BERT, so that path still fetches it (pinned revision).
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import math
10
+ from pathlib import Path
11
+
12
+ import numpy as np
13
+ import torch
14
+ import torch.nn as nn
15
+ import torch.nn.functional as F
16
+
17
+ SEM_LAYER = 16
18
+ HOP16, HOP24 = 320, 480
19
+ LEVELS_S = [3] * 8
20
+ W2V = "facebook/w2v-bert-2.0"
21
+ W2V_REV = "da985ba0987f70aaeb84a80f2851cfac8c697a7b"
22
+ W2V_DIR = Path(__file__).resolve().parent / "w2v_bert" # config (16 layers) + preprocessor config, from W2V_REV
23
+ NEED_GEN = (
24
+ "fsq_s.", "fsq_a.", "backbone.", "head.",
25
+ "CodecEnc.", "SemanticEncoder_module.",
26
+ )
27
+ # training-only head (a semantic reconstruction loss); never runs at inference, dropped from the release file
28
+ TRAIN_ONLY = ("SemanticDecoder_module.",)
29
+
30
+
31
+ class IndiNet(nn.Module):
32
+ """IndiCodec encode / decode only. Refuses phase2d, rope_fix, continuous, joint FSQ."""
33
+
34
+ def __init__(self, levels_a: list[int], w2v_bundled: bool = True):
35
+ super().__init__()
36
+ from transformers import Wav2Vec2BertConfig, Wav2Vec2BertModel
37
+ from vector_quantize_pytorch import FSQ
38
+ from neucodec.codec_encoder import CodecEncoder
39
+ from neucodec.codec_decoder_vocos import ISTFTHead, VocosBackbone
40
+ from neucodec.module import SemanticEncoder
41
+
42
+ self.w2v_bundled = bool(w2v_bundled)
43
+ if self.w2v_bundled: # weights come from the release file in load_gen
44
+ sm = Wav2Vec2BertModel(Wav2Vec2BertConfig.from_json_file(str(W2V_DIR / "config.json")))
45
+ else:
46
+ sm = Wav2Vec2BertModel.from_pretrained(W2V, revision=W2V_REV, output_hidden_states=True)
47
+ sm.encoder.layers = sm.encoder.layers[:SEM_LAYER]
48
+ if len(sm.encoder.layers) != SEM_LAYER:
49
+ raise SystemExit(f"w2v-BERT has {len(sm.encoder.layers)} layers, IndiCodec needs {SEM_LAYER}")
50
+ self.semantic_model = sm.eval().requires_grad_(False)
51
+ self.SemanticEncoder_module = SemanticEncoder(1024, 1024, 1024)
52
+ self.CodecEnc = CodecEncoder()
53
+ self.backbone = VocosBackbone(hidden_dim=1024, depth=12, heads=16, pos_meb_dim=64)
54
+ self.head = ISTFTHead(dim=1024, n_fft=HOP24 * 4, hop_length=HOP24, padding="same")
55
+ self.fsq_s = FSQ(levels=LEVELS_S, dim=1024)
56
+ self.levels_a = list(levels_a)
57
+ self.fsq_a = FSQ(levels=self.levels_a, dim=1024)
58
+ self.tail_frames = 0
59
+
60
+ def load_gen(self, gen: dict) -> None:
61
+ gen = {k: v for k, v in gen.items() if not k.startswith(TRAIN_ONLY)}
62
+ missing_pref = [p for p in NEED_GEN if not any(k.startswith(p) for k in gen)]
63
+ if missing_pref:
64
+ raise SystemExit(f"ckpt gen missing {missing_pref}; this infer needs the IndiCodec trained towers")
65
+ r = self.load_state_dict(gen, strict=False)
66
+ bad_u = [k for k in r.unexpected_keys if k.startswith("head.refine.")]
67
+ if bad_u:
68
+ raise RuntimeError(f"checkpoint has PhaseRefiner2D ({bad_u[0]}); IndiCodec infer refuses it")
69
+ bad_m = [m for m in r.missing_keys if self.w2v_bundled or not m.startswith("semantic_model.")]
70
+ if bad_m:
71
+ raise SystemExit(f"ckpt missing {len(bad_m)} keys, e.g. {bad_m[:5]}")
72
+
73
+ @torch.no_grad()
74
+ def semantic_target(self, feats: torch.Tensor) -> torch.Tensor:
75
+ return self.semantic_model(feats).hidden_states[SEM_LAYER].transpose(1, 2)
76
+
77
+ def towers(self, wav16: torch.Tensor, feats: torch.Tensor):
78
+ return self.semantic_target(feats), self.CodecEnc(wav16).transpose(1, 2)
79
+
80
+ def encode(self, wav16: torch.Tensor, feats: torch.Tensor):
81
+ sem, ac = self.towers(wav16, feats)
82
+ s_enc = self.SemanticEncoder_module(sem)
83
+ t = min(sem.shape[-1], ac.shape[-1], s_enc.shape[-1])
84
+ t -= t % 2
85
+ sem, ac, s_enc = sem[..., :t], ac[..., :t], s_enc[..., :t]
86
+ s25 = F.avg_pool1d(s_enc, 2, 2)
87
+ zq_s, idx_s = self.fsq_s(s25.transpose(1, 2))
88
+ c50 = zq_s.repeat_interleave(2, dim=1)
89
+ res = ac.transpose(1, 2) - c50.detach()
90
+ zq_a, idx_a = self.fsq_a(res)
91
+ return {"idx_s": idx_s, "idx_a": idx_a, "t": t}
92
+
93
+ def codes_to_latent(self, idx_s: torch.Tensor, idx_a: torch.Tensor | None) -> torch.Tensor:
94
+ c50 = self.fsq_s.indices_to_codes(idx_s).repeat_interleave(2, dim=1)
95
+ if idx_a is None:
96
+ return c50
97
+ za = self.fsq_a.indices_to_codes(idx_a)
98
+ t = min(c50.shape[1], za.shape[1])
99
+ return c50[:, :t] + za[:, :t]
100
+
101
+ def decode_latent(self, h: torch.Tensor) -> torch.Tensor:
102
+ return self.head(self.backbone(h))[0]
103
+
104
+ @torch.no_grad()
105
+ def decode_codes(self, idx_s, idx_a, mode: str = "full") -> torch.Tensor:
106
+ if mode == "zero_c":
107
+ return self.decode_latent(self.fsq_a.indices_to_codes(idx_a))
108
+ if mode == "zero_ac":
109
+ return self.decode_latent(self.codes_to_latent(idx_s, None))
110
+ return self.decode_latent(self.codes_to_latent(idx_s, idx_a))
111
+
112
+
113
+ _FE = None
114
+
115
+
116
+ def features(wav16_np_list):
117
+ global _FE
118
+ if _FE is None:
119
+ from transformers import AutoFeatureExtractor
120
+ _FE = AutoFeatureExtractor.from_pretrained(str(W2V_DIR)) # same file as W2V at W2V_REV
121
+ return _FE(wav16_np_list, sampling_rate=16_000, return_tensors="pt").input_features
122
+
123
+
124
+ def to_rate(w, src_sr, tgt):
125
+ from scipy.signal import resample_poly
126
+ if int(src_sr) == int(tgt):
127
+ return np.ascontiguousarray(w, dtype=np.float32)
128
+ g = math.gcd(int(src_sr), int(tgt))
129
+ return np.ascontiguousarray(resample_poly(np.asarray(w, np.float64), tgt // g, src_sr // g), dtype=np.float32)
130
+
131
+
132
+ def pad_w16(w16: np.ndarray, tail_frames: int) -> np.ndarray:
133
+ return np.pad(w16, (0, (-len(w16)) % HOP16 + int(tail_frames) * HOP16))
134
+
135
+
136
+ @torch.no_grad()
137
+ def encode_wav(model: IndiNet, wav, sr, device, amp: bool = True):
138
+ w16 = pad_w16(to_rate(wav, sr, 16000), getattr(model, "tail_frames", 0))
139
+ feats = features([w16]).to(device)
140
+ x = torch.from_numpy(w16)[None, None].to(device)
141
+ with torch.autocast("cuda", dtype=torch.bfloat16, enabled=amp and device != "cpu"):
142
+ e = model.encode(x, feats)
143
+ return e["idx_s"], e["idx_a"], e["t"]
indicodec/w2v_bert/LICENSE ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ w2v-BERT 2.0 (facebook/w2v-bert-2.0, revision da985ba0987f70aaeb84a80f2851cfac8c697a7b). Its first 16 layers are
2
+ included unchanged in IndiCodec's model.safetensors (tensors semantic_model.*). Licence: MIT, from MIT_LICENSE in
3
+ facebookresearch/seamless_communication.
4
+
5
+ MIT License
6
+
7
+ Copyright (c) Meta Platforms, Inc. and affiliates.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
indicodec/w2v_bert/config.json ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "activation_dropout": 0.0,
3
+ "adapter_act": "relu",
4
+ "adapter_kernel_size": 3,
5
+ "adapter_stride": 2,
6
+ "add_adapter": false,
7
+ "apply_spec_augment": false,
8
+ "architectures": [
9
+ "Wav2Vec2BertModel"
10
+ ],
11
+ "attention_dropout": 0.0,
12
+ "bos_token_id": 1,
13
+ "classifier_proj_size": 768,
14
+ "codevector_dim": 768,
15
+ "conformer_conv_dropout": 0.1,
16
+ "contrastive_logits_temperature": 0.1,
17
+ "conv_depthwise_kernel_size": 31,
18
+ "ctc_loss_reduction": "sum",
19
+ "ctc_zero_infinity": false,
20
+ "diversity_loss_weight": 0.1,
21
+ "eos_token_id": 2,
22
+ "feat_proj_dropout": 0.0,
23
+ "feat_quantizer_dropout": 0.0,
24
+ "feature_projection_input_dim": 160,
25
+ "final_dropout": 0.1,
26
+ "hidden_act": "swish",
27
+ "hidden_dropout": 0.0,
28
+ "hidden_size": 1024,
29
+ "initializer_range": 0.02,
30
+ "intermediate_size": 4096,
31
+ "layer_norm_eps": 1e-05,
32
+ "layerdrop": 0.1,
33
+ "left_max_position_embeddings": 64,
34
+ "mask_feature_length": 10,
35
+ "mask_feature_min_masks": 0,
36
+ "mask_feature_prob": 0.0,
37
+ "mask_time_length": 10,
38
+ "mask_time_min_masks": 2,
39
+ "mask_time_prob": 0.05,
40
+ "max_source_positions": 5000,
41
+ "model_type": "wav2vec2-bert",
42
+ "num_adapter_layers": 1,
43
+ "num_attention_heads": 16,
44
+ "num_codevector_groups": 2,
45
+ "num_codevectors_per_group": 320,
46
+ "num_hidden_layers": 16,
47
+ "num_negatives": 100,
48
+ "output_hidden_size": 1024,
49
+ "pad_token_id": 0,
50
+ "position_embeddings_type": "relative_key",
51
+ "proj_codevector_dim": 768,
52
+ "right_max_position_embeddings": 8,
53
+ "rotary_embedding_base": 10000,
54
+ "tdnn_dilation": [
55
+ 1,
56
+ 2,
57
+ 3,
58
+ 1,
59
+ 1
60
+ ],
61
+ "tdnn_dim": [
62
+ 512,
63
+ 512,
64
+ 512,
65
+ 512,
66
+ 1500
67
+ ],
68
+ "tdnn_kernel": [
69
+ 5,
70
+ 3,
71
+ 3,
72
+ 1,
73
+ 1
74
+ ],
75
+ "torch_dtype": "float32",
76
+ "transformers_version": "4.37.0.dev0",
77
+ "use_intermediate_ffn_before_adapter": false,
78
+ "use_weighted_layer_sum": false,
79
+ "vocab_size": null,
80
+ "xvector_output_dim": 512,
81
+ "output_hidden_states": true
82
+ }
indicodec/w2v_bert/preprocessor_config.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "feature_extractor_type": "SeamlessM4TFeatureExtractor",
3
+ "feature_size": 80,
4
+ "num_mel_bins": 80,
5
+ "padding_side": "right",
6
+ "padding_value": 1,
7
+ "processor_class": "Wav2Vec2BertProcessor",
8
+ "return_attention_mask": true,
9
+ "sampling_rate": 16000,
10
+ "stride": 2
11
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b8d9c02a70497db4953df94667cc5391b27ccfb671058b30b9d29e9b0c0922c2
3
+ size 2494732056