Pranavz nullHawk commited on
Commit
f927d3b
·
1 Parent(s): 539391b

refactor: rumik-oss (#1)

Browse files

- refactor: rename TinyAya to RumikOSS (c22516b73eac945db6b1752c2ba6be3185bd6ece)
- feat: add chat template for the trained prompt layout (52f8c0d50db25c2e3c8a0c9196f8f74f261579d2)
- add: LICENSE, and record modifications in NOTICE.md (408f06115787f3c25d49bad9717f6ab6c3fcbbe5)
- update: inference.py to use the config-driven audio API (dcced1a8047fab03966f06244daa4837c3254237)
- docs: rewrite the model card inference section (1b3425a17559b6f9bba2525ebfa157a90c123ce0)
- chore: relax the transformers pin (8b30ada9cd47121798ca881ed60b9b6c43c0e19a)
- revert: drop the chat template (96c18115faf0beac8e87cd5aa1277173d0391d6c)
- fix: recover from a broken round robin instead of truncating (d583cae6ae0c0bf9d3018b6885b327deacf8fd7b)
- fix: drop the huggingface_hub upper bound (7fba0e6a9924404af90ce00484f13570a71d1cbc)
- fix: install soundfile for inference examples (85848bff82548e4bdbb7e7c30faa67e05da396df)


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

LICENSE ADDED
@@ -0,0 +1,430 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ rumik-oss 1 base
2
+ Copyright 2026 Rumik AI
3
+
4
+ rumik-oss 1 base is a derivative of CohereLabs/tiny-aya-fire and is released under
5
+ the Creative Commons Attribution-NonCommercial 4.0 International license
6
+ (CC-BY-NC 4.0), together with the Cohere Labs acceptable-use addendum that
7
+ governs the upstream model.
8
+
9
+ License ......... https://cohere.com/cohere-labs-cc-by-nc-license
10
+ Acceptable use .. https://docs.cohere.com/docs/cohere-labs-acceptable-use-policy
11
+
12
+ Use of this model is permitted for research and other non-commercial purposes
13
+ only, and must comply with the Cohere Labs Acceptable Use Policy in addition
14
+ to the terms below. Redistribution must retain this notice, the license link,
15
+ upstream notices, and an indication of any modifications made (see NOTICE).
16
+
17
+ The Mimi codec in codec/ is licensed separately by Kyutai under CC-BY-4.0
18
+ (https://creativecommons.org/licenses/by/4.0/). That permission applies to the
19
+ codec only, not to the tiny-aya-derived TTS weights.
20
+
21
+ =======================================================================
22
+
23
+ Attribution-NonCommercial 4.0 International
24
+
25
+ =======================================================================
26
+
27
+ Creative Commons Corporation ("Creative Commons") is not a law firm and
28
+ does not provide legal services or legal advice. Distribution of
29
+ Creative Commons public licenses does not create a lawyer-client or
30
+ other relationship. Creative Commons makes its licenses and related
31
+ information available on an "as-is" basis. Creative Commons gives no
32
+ warranties regarding its licenses, any material licensed under their
33
+ terms and conditions, or any related information. Creative Commons
34
+ disclaims all liability for damages resulting from their use to the
35
+ fullest extent possible.
36
+
37
+ Using Creative Commons Public Licenses
38
+
39
+ Creative Commons public licenses provide a standard set of terms and
40
+ conditions that creators and other rights holders may use to share
41
+ original works of authorship and other material subject to copyright
42
+ and certain other rights specified in the public license below. The
43
+ following considerations are for informational purposes only, are not
44
+ exhaustive, and do not form part of our licenses.
45
+
46
+ Considerations for licensors: Our public licenses are
47
+ intended for use by those authorized to give the public
48
+ permission to use material in ways otherwise restricted by
49
+ copyright and certain other rights. Our licenses are
50
+ irrevocable. Licensors should read and understand the terms
51
+ and conditions of the license they choose before applying it.
52
+ Licensors should also secure all rights necessary before
53
+ applying our licenses so that the public can reuse the
54
+ material as expected. Licensors should clearly mark any
55
+ material not subject to the license. This includes other CC-
56
+ licensed material, or material used under an exception or
57
+ limitation to copyright. More considerations for licensors:
58
+ wiki.creativecommons.org/Considerations_for_licensors
59
+
60
+ Considerations for the public: By using one of our public
61
+ licenses, a licensor grants the public permission to use the
62
+ licensed material under specified terms and conditions. If
63
+ the licensor's permission is not necessary for any reason--for
64
+ example, because of any applicable exception or limitation to
65
+ copyright--then that use is not regulated by the license. Our
66
+ licenses grant only permissions under copyright and certain
67
+ other rights that a licensor has authority to grant. Use of
68
+ the licensed material may still be restricted for other
69
+ reasons, including because others have copyright or other
70
+ rights in the material. A licensor may make special requests,
71
+ such as asking that all changes be marked or described.
72
+ Although not required by our licenses, you are encouraged to
73
+ respect those requests where reasonable. More considerations
74
+ for the public:
75
+ wiki.creativecommons.org/Considerations_for_licensees
76
+
77
+ =======================================================================
78
+
79
+ Creative Commons Attribution-NonCommercial 4.0 International Public
80
+ License
81
+
82
+ By exercising the Licensed Rights (defined below), You accept and agree
83
+ to be bound by the terms and conditions of this Creative Commons
84
+ Attribution-NonCommercial 4.0 International Public License ("Public
85
+ License"). To the extent this Public License may be interpreted as a
86
+ contract, You are granted the Licensed Rights in consideration of Your
87
+ acceptance of these terms and conditions, and the Licensor grants You
88
+ such rights in consideration of benefits the Licensor receives from
89
+ making the Licensed Material available under these terms and
90
+ conditions.
91
+
92
+
93
+ Section 1 -- Definitions.
94
+
95
+ a. Adapted Material means material subject to Copyright and Similar
96
+ Rights that is derived from or based upon the Licensed Material
97
+ and in which the Licensed Material is translated, altered,
98
+ arranged, transformed, or otherwise modified in a manner requiring
99
+ permission under the Copyright and Similar Rights held by the
100
+ Licensor. For purposes of this Public License, where the Licensed
101
+ Material is a musical work, performance, or sound recording,
102
+ Adapted Material is always produced where the Licensed Material is
103
+ synched in timed relation with a moving image.
104
+
105
+ b. Adapter's License means the license You apply to Your Copyright
106
+ and Similar Rights in Your contributions to Adapted Material in
107
+ accordance with the terms and conditions of this Public License.
108
+
109
+ c. Copyright and Similar Rights means copyright and/or similar rights
110
+ closely related to copyright including, without limitation,
111
+ performance, broadcast, sound recording, and Sui Generis Database
112
+ Rights, without regard to how the rights are labeled or
113
+ categorized. For purposes of this Public License, the rights
114
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
115
+ Rights.
116
+ d. Effective Technological Measures means those measures that, in the
117
+ absence of proper authority, may not be circumvented under laws
118
+ fulfilling obligations under Article 11 of the WIPO Copyright
119
+ Treaty adopted on December 20, 1996, and/or similar international
120
+ agreements.
121
+
122
+ e. Exceptions and Limitations means fair use, fair dealing, and/or
123
+ any other exception or limitation to Copyright and Similar Rights
124
+ that applies to Your use of the Licensed Material.
125
+
126
+ f. Licensed Material means the artistic or literary work, database,
127
+ or other material to which the Licensor applied this Public
128
+ License.
129
+
130
+ g. Licensed Rights means the rights granted to You subject to the
131
+ terms and conditions of this Public License, which are limited to
132
+ all Copyright and Similar Rights that apply to Your use of the
133
+ Licensed Material and that the Licensor has authority to license.
134
+
135
+ h. Licensor means the individual(s) or entity(ies) granting rights
136
+ under this Public License.
137
+
138
+ i. NonCommercial means not primarily intended for or directed towards
139
+ commercial advantage or monetary compensation. For purposes of
140
+ this Public License, the exchange of the Licensed Material for
141
+ other material subject to Copyright and Similar Rights by digital
142
+ file-sharing or similar means is NonCommercial provided there is
143
+ no payment of monetary compensation in connection with the
144
+ exchange.
145
+
146
+ j. Share means to provide material to the public by any means or
147
+ process that requires permission under the Licensed Rights, such
148
+ as reproduction, public display, public performance, distribution,
149
+ dissemination, communication, or importation, and to make material
150
+ available to the public including in ways that members of the
151
+ public may access the material from a place and at a time
152
+ individually chosen by them.
153
+
154
+ k. Sui Generis Database Rights means rights other than copyright
155
+ resulting from Directive 96/9/EC of the European Parliament and of
156
+ the Council of 11 March 1996 on the legal protection of databases,
157
+ as amended and/or succeeded, as well as other essentially
158
+ equivalent rights anywhere in the world.
159
+
160
+ l. You means the individual or entity exercising the Licensed Rights
161
+ under this Public License. Your has a corresponding meaning.
162
+
163
+
164
+ Section 2 -- Scope.
165
+
166
+ a. License grant.
167
+
168
+ 1. Subject to the terms and conditions of this Public License,
169
+ the Licensor hereby grants You a worldwide, royalty-free,
170
+ non-sublicensable, non-exclusive, irrevocable license to
171
+ exercise the Licensed Rights in the Licensed Material to:
172
+
173
+ a. reproduce and Share the Licensed Material, in whole or
174
+ in part, for NonCommercial purposes only; and
175
+
176
+ b. produce, reproduce, and Share Adapted Material for
177
+ NonCommercial purposes only.
178
+
179
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
180
+ Exceptions and Limitations apply to Your use, this Public
181
+ License does not apply, and You do not need to comply with
182
+ its terms and conditions.
183
+
184
+ 3. Term. The term of this Public License is specified in Section
185
+ 6(a).
186
+
187
+ 4. Media and formats; technical modifications allowed. The
188
+ Licensor authorizes You to exercise the Licensed Rights in
189
+ all media and formats whether now known or hereafter created,
190
+ and to make technical modifications necessary to do so. The
191
+ Licensor waives and/or agrees not to assert any right or
192
+ authority to forbid You from making technical modifications
193
+ necessary to exercise the Licensed Rights, including
194
+ technical modifications necessary to circumvent Effective
195
+ Technological Measures. For purposes of this Public License,
196
+ simply making modifications authorized by this Section 2(a)
197
+ (4) never produces Adapted Material.
198
+
199
+ 5. Downstream recipients.
200
+
201
+ a. Offer from the Licensor -- Licensed Material. Every
202
+ recipient of the Licensed Material automatically
203
+ receives an offer from the Licensor to exercise the
204
+ Licensed Rights under the terms and conditions of this
205
+ Public License.
206
+
207
+ b. No downstream restrictions. You may not offer or impose
208
+ any additional or different terms or conditions on, or
209
+ apply any Effective Technological Measures to, the
210
+ Licensed Material if doing so restricts exercise of the
211
+ Licensed Rights by any recipient of the Licensed
212
+ Material.
213
+
214
+ 6. No endorsement. Nothing in this Public License constitutes or
215
+ may be construed as permission to assert or imply that You
216
+ are, or that Your use of the Licensed Material is, connected
217
+ with, or sponsored, endorsed, or granted official status by,
218
+ the Licensor or others designated to receive attribution as
219
+ provided in Section 3(a)(1)(A)(i).
220
+
221
+ b. Other rights.
222
+
223
+ 1. Moral rights, such as the right of integrity, are not
224
+ licensed under this Public License, nor are publicity,
225
+ privacy, and/or other similar personality rights; however, to
226
+ the extent possible, the Licensor waives and/or agrees not to
227
+ assert any such rights held by the Licensor to the limited
228
+ extent necessary to allow You to exercise the Licensed
229
+ Rights, but not otherwise.
230
+
231
+ 2. Patent and trademark rights are not licensed under this
232
+ Public License.
233
+
234
+ 3. To the extent possible, the Licensor waives any right to
235
+ collect royalties from You for the exercise of the Licensed
236
+ Rights, whether directly or through a collecting society
237
+ under any voluntary or waivable statutory or compulsory
238
+ licensing scheme. In all other cases the Licensor expressly
239
+ reserves any right to collect such royalties, including when
240
+ the Licensed Material is used other than for NonCommercial
241
+ purposes.
242
+
243
+
244
+ Section 3 -- License Conditions.
245
+
246
+ Your exercise of the Licensed Rights is expressly made subject to the
247
+ following conditions.
248
+
249
+ a. Attribution.
250
+
251
+ 1. If You Share the Licensed Material (including in modified
252
+ form), You must:
253
+
254
+ a. retain the following if it is supplied by the Licensor
255
+ with the Licensed Material:
256
+
257
+ i. identification of the creator(s) of the Licensed
258
+ Material and any others designated to receive
259
+ attribution, in any reasonable manner requested by
260
+ the Licensor (including by pseudonym if
261
+ designated);
262
+
263
+ ii. a copyright notice;
264
+
265
+ iii. a notice that refers to this Public License;
266
+
267
+ iv. a notice that refers to the disclaimer of
268
+ warranties;
269
+
270
+ v. a URI or hyperlink to the Licensed Material to the
271
+ extent reasonably practicable;
272
+
273
+ b. indicate if You modified the Licensed Material and
274
+ retain an indication of any previous modifications; and
275
+
276
+ c. indicate the Licensed Material is licensed under this
277
+ Public License, and include the text of, or the URI or
278
+ hyperlink to, this Public License.
279
+
280
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
281
+ reasonable manner based on the medium, means, and context in
282
+ which You Share the Licensed Material. For example, it may be
283
+ reasonable to satisfy the conditions by providing a URI or
284
+ hyperlink to a resource that includes the required
285
+ information.
286
+
287
+ 3. If requested by the Licensor, You must remove any of the
288
+ information required by Section 3(a)(1)(A) to the extent
289
+ reasonably practicable.
290
+
291
+ 4. If You Share Adapted Material You produce, the Adapter's
292
+ License You apply must not prevent recipients of the Adapted
293
+ Material from complying with this Public License.
294
+
295
+
296
+ Section 4 -- Sui Generis Database Rights.
297
+
298
+ Where the Licensed Rights include Sui Generis Database Rights that
299
+ apply to Your use of the Licensed Material:
300
+
301
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
302
+ to extract, reuse, reproduce, and Share all or a substantial
303
+ portion of the contents of the database for NonCommercial purposes
304
+ only;
305
+
306
+ b. if You include all or a substantial portion of the database
307
+ contents in a database in which You have Sui Generis Database
308
+ Rights, then the database in which You have Sui Generis Database
309
+ Rights (but not its individual contents) is Adapted Material; and
310
+
311
+ c. You must comply with the conditions in Section 3(a) if You Share
312
+ all or a substantial portion of the contents of the database.
313
+
314
+ For the avoidance of doubt, this Section 4 supplements and does not
315
+ replace Your obligations under this Public License where the Licensed
316
+ Rights include other Copyright and Similar Rights.
317
+
318
+
319
+ Section 5 -- Disclaimer of Warranties and Limitation of Liability.
320
+
321
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
322
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
323
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
324
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
325
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
326
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
327
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
328
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
329
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
330
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
331
+
332
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
333
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
334
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
335
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
336
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
337
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
338
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
339
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
340
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
341
+
342
+ c. The disclaimer of warranties and limitation of liability provided
343
+ above shall be interpreted in a manner that, to the extent
344
+ possible, most closely approximates an absolute disclaimer and
345
+ waiver of all liability.
346
+
347
+
348
+ Section 6 -- Term and Termination.
349
+
350
+ a. This Public License applies for the term of the Copyright and
351
+ Similar Rights licensed here. However, if You fail to comply with
352
+ this Public License, then Your rights under this Public License
353
+ terminate automatically.
354
+
355
+ b. Where Your right to use the Licensed Material has terminated under
356
+ Section 6(a), it reinstates:
357
+
358
+ 1. automatically as of the date the violation is cured, provided
359
+ it is cured within 30 days of Your discovery of the
360
+ violation; or
361
+
362
+ 2. upon express reinstatement by the Licensor.
363
+
364
+ For the avoidance of doubt, this Section 6(b) does not affect any
365
+ right the Licensor may have to seek remedies for Your violations
366
+ of this Public License.
367
+
368
+ c. For the avoidance of doubt, the Licensor may also offer the
369
+ Licensed Material under separate terms or conditions or stop
370
+ distributing the Licensed Material at any time; however, doing so
371
+ will not terminate this Public License.
372
+
373
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
374
+ License.
375
+
376
+
377
+ Section 7 -- Other Terms and Conditions.
378
+
379
+ a. The Licensor shall not be bound by any additional or different
380
+ terms or conditions communicated by You unless expressly agreed.
381
+
382
+ b. Any arrangements, understandings, or agreements regarding the
383
+ Licensed Material not stated herein are separate from and
384
+ independent of the terms and conditions of this Public License.
385
+
386
+
387
+ Section 8 -- Interpretation.
388
+
389
+ a. For the avoidance of doubt, this Public License does not, and
390
+ shall not be interpreted to, reduce, limit, restrict, or impose
391
+ conditions on any use of the Licensed Material that could lawfully
392
+ be made without permission under this Public License.
393
+
394
+ b. To the extent possible, if any provision of this Public License is
395
+ deemed unenforceable, it shall be automatically reformed to the
396
+ minimum extent necessary to make it enforceable. If the provision
397
+ cannot be reformed, it shall be severed from this Public License
398
+ without affecting the enforceability of the remaining terms and
399
+ conditions.
400
+
401
+ c. No term or condition of this Public License will be waived and no
402
+ failure to comply consented to unless expressly agreed to by the
403
+ Licensor.
404
+
405
+ d. Nothing in this Public License constitutes or may be interpreted
406
+ as a limitation upon, or waiver of, any privileges and immunities
407
+ that apply to the Licensor or You, including from the legal
408
+ processes of any jurisdiction or authority.
409
+
410
+ =======================================================================
411
+
412
+ Creative Commons is not a party to its public
413
+ licenses. Notwithstanding, Creative Commons may elect to apply one of
414
+ its public licenses to material it publishes and in those instances
415
+ will be considered the “Licensor.” The text of the Creative Commons
416
+ public licenses is dedicated to the public domain under the CC0 Public
417
+ Domain Dedication. Except for the limited purpose of indicating that
418
+ material is shared under a Creative Commons public license or as
419
+ otherwise permitted by the Creative Commons policies published at
420
+ creativecommons.org/policies, Creative Commons does not authorize the
421
+ use of the trademark "Creative Commons" or any other trademark or logo
422
+ of Creative Commons without its prior written consent including,
423
+ without limitation, in connection with any unauthorized modifications
424
+ to any of its public licenses or any other arrangements,
425
+ understandings, or agreements concerning use of licensed material. For
426
+ the avoidance of doubt, this paragraph does not form part of the
427
+ public licenses.
428
+
429
+ Creative Commons may be contacted at creativecommons.org.
430
+
NOTICE.md CHANGED
@@ -8,6 +8,33 @@ the model for multilingual, named-speaker speech synthesis.
8
  - License: https://cohere.com/cohere-labs-cc-by-nc-license
9
  - Acceptable-use policy: https://docs.cohere.com/docs/cohere-labs-acceptable-use-policy
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  The unmodified Mimi codec in `codec/` is by Kyutai, distributed under CC BY 4.0.
12
 
13
  - Mimi: https://huggingface.co/kyutai/mimi
 
8
  - License: https://cohere.com/cohere-labs-cc-by-nc-license
9
  - Acceptable-use policy: https://docs.cohere.com/docs/cohere-labs-acceptable-use-policy
10
 
11
+ CC-BY-NC 4.0 requires that redistribution indicate what was changed relative to
12
+ the upstream material. The modifications are:
13
+
14
+ 1. Vocabulary extended from 261,008 to 277,395 tokens:
15
+ - 16,384 Mimi codec unit tokens `<code>_<quantizer>`, ids 261008-277391
16
+ - 3 structure delimiters `<text>`, `<audio>`, `</audio>`, ids 277392-277394
17
+
18
+ Input and output embedding matrices were resized accordingly.
19
+
20
+ 2. A stop-prediction head (`stop_predictor`) was added on top of the final
21
+ hidden state to terminate audio generation.
22
+
23
+ 3. The model was trained for multilingual, named-speaker text-to-speech,
24
+ progressing from English through Indic-language continuation to
25
+ named-speaker adaptation.
26
+
27
+ 4. Model class and configuration are provided as `RumikOSSForCausalLM` /
28
+ `RumikOSSConfig` (model_type `rumik_oss`), subclassing the transformers
29
+ Cohere2 implementation. This is not a chat model and ships no chat
30
+ template; it uses the flat prompt layout documented in README.md.
31
+
32
+ The delivery-control fine-tuning and reinforcement learning that follow this
33
+ checkpoint are applied in
34
+ [rumik-oss 1](https://huggingface.co/rumik-ai/rumik-oss-1).
35
+
36
+ ## Bundled codec
37
+
38
  The unmodified Mimi codec in `codec/` is by Kyutai, distributed under CC BY 4.0.
39
 
40
  - Mimi: https://huggingface.co/kyutai/mimi
README.md CHANGED
@@ -1,13 +1,39 @@
1
  ---
2
  pipeline_tag: text-to-speech
 
3
  base_model: CohereLabs/tiny-aya-fire
4
- license: other
5
- license_name: cohere-cc-by-nc-4.0-with-acceptable-use-addendum
6
- license_link: https://cohere.com/cohere-labs-cc-by-nc-license
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  tags:
8
- - tts
9
- - indic
10
- - multilingual
 
 
 
11
  ---
12
 
13
  <p align="center">
@@ -38,17 +64,73 @@ this base release has not undergone description-conditioned delivery or inline v
38
 
39
  ## inference
40
 
 
 
 
 
 
 
41
  ```bash
42
- hf download rumik-ai/rumik-oss-1-base --local-dir rumik-oss-1-base
43
- cd rumik-oss-1-base
44
  pip install -r requirements.txt
45
- python inference.py --speaker Ira --text "Hello, how are you today?" --output speech.wav
46
  ```
47
 
48
- the `--speaker` argument accepts `Ira`, `Aisha`, `Siya`, or `Zoya`. pass the spoken text through `--text`; the inference script constructs the speaker-prefixed sequence:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
  ```text
51
- Ira: Hello, how are you today?<audio>
 
 
 
 
 
 
 
 
 
 
52
  ```
53
 
54
  ## further training
@@ -63,6 +145,9 @@ permitted non-commercial uses include speech-synthesis research, benchmarking, t
63
 
64
  the bundled [mimi codec](https://huggingface.co/kyutai/mimi) is separately licensed under [cc-by-4.0](https://creativecommons.org/licenses/by/4.0/). its commercial permissions do not extend to the tiny aya-derived tts weights.
65
 
 
 
 
66
  ## acknowledgments
67
 
68
  rumik-oss 1 base builds on [tiny aya fire](https://huggingface.co/CohereLabs/tiny-aya-fire), [mimi](https://huggingface.co/kyutai/mimi), [llama-mimi](https://arxiv.org/abs/2509.14882), and [torchtitan](https://github.com/pytorch/torchtitan). we thank their authors for making this work available.
 
1
  ---
2
  pipeline_tag: text-to-speech
3
+ library_name: transformers
4
  base_model: CohereLabs/tiny-aya-fire
5
+ base_model_relation: finetune
6
+ license: cc-by-nc-4.0
7
+ language:
8
+ - hi
9
+ - bn
10
+ - ta
11
+ - te
12
+ - mr
13
+ - gu
14
+ - kn
15
+ - ml
16
+ - pa
17
+ - or
18
+ - as
19
+ - ur
20
+ - ne
21
+ - sa
22
+ - mai
23
+ - mni
24
+ - brx
25
+ - doi
26
+ - kok
27
+ - sat
28
+ - ks
29
+ - en
30
  tags:
31
+ - tts
32
+ - text-to-speech
33
+ - indic
34
+ - multilingual
35
+ - mimi
36
+ - speech
37
  ---
38
 
39
  <p align="center">
 
64
 
65
  ## inference
66
 
67
+ rumik-oss 1 base generates **audio tokens**. decoding them to a waveform is a
68
+ separate step that uses the [mimi](https://huggingface.co/kyutai/mimi) codec,
69
+ bundled in this repository under `codec/`.
70
+
71
+ ### installation
72
+
73
  ```bash
 
 
74
  pip install -r requirements.txt
 
75
  ```
76
 
77
+ requires an nvidia gpu with cuda support. the one-shot example below also
78
+ needs `soundfile` to write a wav.
79
+
80
+ ### one-shot example
81
+
82
+ text in, `speech.wav` out:
83
+
84
+ ```python
85
+ """rumik-oss 1 base: text -> speech.wav"""
86
+ import soundfile as sf
87
+ import torch
88
+ from transformers import AutoModelForCausalLM, AutoTokenizer, MimiModel
89
+
90
+ REPO = "rumik-ai/rumik-oss-1-base"
91
+ SPEAKER = "Ira"
92
+ TEXT = "Hello, how are you today?"
93
+
94
+ tokenizer = AutoTokenizer.from_pretrained(REPO, trust_remote_code=True)
95
+ model = AutoModelForCausalLM.from_pretrained(
96
+ REPO, trust_remote_code=True, dtype=torch.bfloat16
97
+ ).eval().cuda()
98
+ mimi = MimiModel.from_pretrained(REPO, subfolder="codec").eval().cuda()
99
+
100
+ # [BOS] <text> Ira: text <audio>
101
+ # the tokenizer adds [BOS] itself, so it is not written here
102
+ prompt = f'<text>{SPEAKER}: {TEXT}<audio>'
103
+ inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
104
+
105
+ # 1. text -> audio tokens
106
+ ids = model.generate_audio(**inputs, max_new_tokens=2048,
107
+ temperature=0.8, top_k=30, do_sample=True)
108
+ audio_tokens = ids[0].tolist()[inputs.input_ids.shape[1]:]
109
+
110
+ # 2. audio tokens -> codec frames -> waveform
111
+ codes = model.audio_tokens_to_codes(audio_tokens)
112
+ with torch.inference_mode():
113
+ wav = mimi.decode(codes.to(mimi.device)).audio_values[0, 0]
114
+
115
+ sf.write("speech.wav", wav.float().cpu().numpy(), 24000)
116
+ print(f"{len(audio_tokens)} tokens -> {len(audio_tokens) / 100:.2f}s -> speech.wav")
117
+ ```
118
+
119
+ `SPEAKER` accepts `Ira`, `Aisha`, `Siya`, or `Zoya`. the model was trained on
120
+ a flat token layout, not a chat template:
121
 
122
  ```text
123
+ [BOS] <text> {speaker}: spoken text <audio> ... </audio>
124
+ ```
125
+
126
+ this checkpoint has no description-conditioned delivery or inline
127
+ vocalization controls; use the
128
+ [post-trained model](https://huggingface.co/rumik-ai/rumik-oss-1) for those.
129
+
130
+ ### command line
131
+
132
+ ```bash
133
+ python inference.py --speaker Ira --text "Hello, how are you today?" --output speech.wav
134
  ```
135
 
136
  ## further training
 
145
 
146
  the bundled [mimi codec](https://huggingface.co/kyutai/mimi) is separately licensed under [cc-by-4.0](https://creativecommons.org/licenses/by/4.0/). its commercial permissions do not extend to the tiny aya-derived tts weights.
147
 
148
+ the full license text is in [`LICENSE`](LICENSE), and [`NOTICE.md`](NOTICE.md)
149
+ records the modifications made to tiny aya fire, as cc-by-nc 4.0 requires.
150
+
151
  ## acknowledgments
152
 
153
  rumik-oss 1 base builds on [tiny aya fire](https://huggingface.co/CohereLabs/tiny-aya-fire), [mimi](https://huggingface.co/kyutai/mimi), [llama-mimi](https://arxiv.org/abs/2509.14882), and [torchtitan](https://github.com/pytorch/torchtitan). we thank their authors for making this work available.
config.json CHANGED
@@ -1,21 +1,54 @@
1
  {
2
- "vocab_size": 277395,
3
- "max_position_embeddings": 500000,
4
- "hidden_size": 2048,
5
- "logit_scale": 1.0,
6
- "intermediate_size": 11008,
7
- "num_hidden_layers": 36,
8
- "num_attention_heads": 16,
9
- "num_key_value_heads": 4,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  "hidden_act": "silu",
 
 
 
 
 
11
  "initializer_range": 0.02,
 
 
 
 
 
 
 
 
12
  "layer_norm_eps": 1e-05,
13
- "use_cache": true,
14
- "rope_theta": 50000,
15
- "rope_scaling": null,
16
- "attention_bias": false,
17
- "attention_dropout": 0.0,
18
- "sliding_window": 4096,
19
  "layer_types": [
20
  "sliding_attention",
21
  "sliding_attention",
@@ -54,94 +87,64 @@
54
  "sliding_attention",
55
  "full_attention"
56
  ],
57
- "head_dim": 128,
58
- "return_dict": true,
59
- "output_hidden_states": false,
60
- "torchscript": false,
61
- "dtype": "bfloat16",
62
- "pruned_heads": {},
63
- "tie_word_embeddings": true,
64
- "chunk_size_feed_forward": 0,
65
- "is_encoder_decoder": false,
66
- "is_decoder": false,
67
- "cross_attention_hidden_size": null,
68
- "add_cross_attention": false,
69
- "tie_encoder_decoder": false,
70
- "architectures": [
71
- "TinyAyaForCausalLM"
72
- ],
73
- "finetuning_task": null,
74
- "id2label": {
75
- "0": "LABEL_0",
76
- "1": "LABEL_1"
77
- },
78
- "label2id": {
79
- "LABEL_0": 0,
80
- "LABEL_1": 1
81
- },
82
- "task_specific_params": null,
83
- "problem_type": null,
84
- "tokenizer_class": null,
85
- "prefix": null,
86
- "bos_token_id": 2,
87
- "pad_token_id": 0,
88
- "eos_token_id": 3,
89
- "sep_token_id": null,
90
- "decoder_start_token_id": null,
91
  "max_length": 20,
 
92
  "min_length": 0,
93
- "do_sample": false,
94
- "early_stopping": false,
95
- "num_beams": 1,
96
- "temperature": 1.0,
97
- "top_k": 50,
98
- "top_p": 1.0,
99
- "typical_p": 1.0,
100
- "repetition_penalty": 1.0,
101
- "length_penalty": 1.0,
102
  "no_repeat_ngram_size": 0,
103
- "encoder_no_repeat_ngram_size": 0,
104
- "bad_words_ids": null,
105
- "num_return_sequences": 1,
106
- "output_scores": false,
107
- "return_dict_in_generate": false,
108
- "forced_bos_token_id": null,
109
- "forced_eos_token_id": null,
110
- "remove_invalid_values": false,
111
- "exponential_decay_length_penalty": null,
112
- "suppress_tokens": null,
113
- "begin_suppress_tokens": null,
114
  "num_beam_groups": 1,
115
- "diversity_penalty": 0.0,
116
- "_sliding_window_pattern": 4,
117
- "cache_implementation": "hybrid",
118
- "layer_switch": 4,
119
- "model_type": "tinyaya_mimi",
120
  "order_of_interleaved_layers": "local_attn_first",
 
 
 
 
121
  "position_embedding_type": "rope_gptj",
 
 
 
 
 
 
 
 
 
122
  "rotary_pct": 1.0,
 
 
123
  "sliding_window_pattern": 4,
124
- "use_embedding_sharing": true,
125
- "use_gated_activation": true,
126
- "use_parallel_block": true,
127
- "use_parallel_embedding": false,
128
- "use_qk_norm": false,
129
- "tf_legacy_loss": false,
130
- "use_bfloat16": false,
131
- "output_attentions": false,
132
- "num_quantizers": 8,
133
- "codebook_size": 2048,
134
- "audio_start_token_id": 277393,
135
- "audio_end_token_id": 277394,
136
  "speakers": [
137
  "Ira",
138
  "Aisha",
139
  "Siya",
140
  "Zoya"
141
  ],
142
- "auto_map": {
143
- "AutoConfig": "configuration_tinyaya.TinyAyaConfig",
144
- "AutoModelForCausalLM": "modeling_tinyaya.TinyAyaForCausalLM"
145
- },
146
- "torch_dtype": "bfloat16"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  }
 
1
  {
2
+ "_sliding_window_pattern": 4,
3
+ "add_cross_attention": false,
4
+ "architectures": [
5
+ "RumikOSSForCausalLM"
6
+ ],
7
+ "attention_bias": false,
8
+ "attention_dropout": 0.0,
9
+ "audio_end_token_id": 277394,
10
+ "audio_start_token_id": 277393,
11
+ "auto_map": {
12
+ "AutoConfig": "configuration_rumik_oss.RumikOSSConfig",
13
+ "AutoModelForCausalLM": "modeling_rumik_oss.RumikOSSForCausalLM"
14
+ },
15
+ "bad_words_ids": null,
16
+ "begin_suppress_tokens": null,
17
+ "bos_token_id": 2,
18
+ "chunk_size_feed_forward": 0,
19
+ "codebook_size": 2048,
20
+ "cross_attention_hidden_size": null,
21
+ "decoder_start_token_id": null,
22
+ "diversity_penalty": 0.0,
23
+ "do_sample": false,
24
+ "dtype": "bfloat16",
25
+ "early_stopping": false,
26
+ "encoder_no_repeat_ngram_size": 0,
27
+ "eos_token_id": 3,
28
+ "exponential_decay_length_penalty": null,
29
+ "finetuning_task": null,
30
+ "first_unit_id": 261008,
31
+ "forced_bos_token_id": null,
32
+ "forced_eos_token_id": null,
33
+ "frame_rate_hz": 12.5,
34
+ "head_dim": 128,
35
  "hidden_act": "silu",
36
+ "hidden_size": 2048,
37
+ "id2label": {
38
+ "0": "LABEL_0",
39
+ "1": "LABEL_1"
40
+ },
41
  "initializer_range": 0.02,
42
+ "intermediate_size": 11008,
43
+ "is_decoder": false,
44
+ "is_encoder_decoder": false,
45
+ "label2id": {
46
+ "LABEL_0": 0,
47
+ "LABEL_1": 1
48
+ },
49
+ "last_unit_id": 277391,
50
  "layer_norm_eps": 1e-05,
51
+ "layer_switch": 4,
 
 
 
 
 
52
  "layer_types": [
53
  "sliding_attention",
54
  "sliding_attention",
 
87
  "sliding_attention",
88
  "full_attention"
89
  ],
90
+ "length_penalty": 1.0,
91
+ "logit_scale": 1.0,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  "max_length": 20,
93
+ "max_position_embeddings": 500000,
94
  "min_length": 0,
95
+ "model_type": "rumik_oss",
 
 
 
 
 
 
 
 
96
  "no_repeat_ngram_size": 0,
97
+ "num_attention_heads": 16,
 
 
 
 
 
 
 
 
 
 
98
  "num_beam_groups": 1,
99
+ "num_beams": 1,
100
+ "num_hidden_layers": 36,
101
+ "num_key_value_heads": 4,
102
+ "num_quantizers": 8,
103
+ "num_return_sequences": 1,
104
  "order_of_interleaved_layers": "local_attn_first",
105
+ "output_attentions": false,
106
+ "output_hidden_states": false,
107
+ "output_scores": false,
108
+ "pad_token_id": 0,
109
  "position_embedding_type": "rope_gptj",
110
+ "prefix": null,
111
+ "problem_type": null,
112
+ "pruned_heads": {},
113
+ "remove_invalid_values": false,
114
+ "repetition_penalty": 1.0,
115
+ "return_dict": true,
116
+ "return_dict_in_generate": false,
117
+ "rope_scaling": null,
118
+ "rope_theta": 50000,
119
  "rotary_pct": 1.0,
120
+ "sep_token_id": null,
121
+ "sliding_window": 4096,
122
  "sliding_window_pattern": 4,
 
 
 
 
 
 
 
 
 
 
 
 
123
  "speakers": [
124
  "Ira",
125
  "Aisha",
126
  "Siya",
127
  "Zoya"
128
  ],
129
+ "suppress_tokens": null,
130
+ "task_specific_params": null,
131
+ "temperature": 1.0,
132
+ "text_start_token_id": 277392,
133
+ "tf_legacy_loss": false,
134
+ "tie_encoder_decoder": false,
135
+ "tie_word_embeddings": true,
136
+ "tokenizer_class": null,
137
+ "top_k": 50,
138
+ "top_p": 1.0,
139
+ "torch_dtype": "bfloat16",
140
+ "torchscript": false,
141
+ "typical_p": 1.0,
142
+ "use_bfloat16": false,
143
+ "use_cache": true,
144
+ "use_embedding_sharing": true,
145
+ "use_gated_activation": true,
146
+ "use_parallel_block": true,
147
+ "use_parallel_embedding": false,
148
+ "use_qk_norm": false,
149
+ "vocab_size": 277395
150
  }
configuration_rumik_oss.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Configuration for rumik-oss 1."""
2
+
3
+ from transformers import Cohere2Config
4
+
5
+
6
+ class RumikOSSConfig(Cohere2Config):
7
+ """rumik-oss 1: tiny aya fire extended with flattened Mimi codec tokens.
8
+
9
+ Beyond the base Cohere2 fields, this records where the audio vocabulary
10
+ lives so that callers can map token ids to codec (code, quantizer) pairs
11
+ arithmetically, without loading the tokenizer or scanning its vocabulary.
12
+
13
+ The unit tokens are laid out code-major, quantizer-minor::
14
+
15
+ <0_0> <0_1> ... <0_7> <1_0> ... <2047_7>
16
+
17
+ so for any id in ``[first_unit_id, last_unit_id]``::
18
+
19
+ code = (token_id - first_unit_id) // num_quantizers
20
+ quantizer = (token_id - first_unit_id) % num_quantizers
21
+ """
22
+
23
+ model_type = "rumik_oss"
24
+
25
+ def __init__(
26
+ self,
27
+ num_quantizers=8,
28
+ codebook_size=2048,
29
+ audio_start_token_id=None,
30
+ audio_end_token_id=None,
31
+ text_start_token_id=None,
32
+ first_unit_id=None,
33
+ last_unit_id=None,
34
+ frame_rate_hz=12.5,
35
+ speakers=None,
36
+ **kwargs,
37
+ ):
38
+ super().__init__(**kwargs)
39
+ self.num_quantizers = int(num_quantizers)
40
+ self.codebook_size = int(codebook_size)
41
+ self.audio_start_token_id = audio_start_token_id
42
+ self.audio_end_token_id = audio_end_token_id
43
+ self.text_start_token_id = text_start_token_id
44
+ self.first_unit_id = first_unit_id
45
+ # Derivable, but stored so a hand-edited config stays self-consistent.
46
+ if last_unit_id is None and first_unit_id is not None:
47
+ last_unit_id = int(first_unit_id) + self.codebook_size * self.num_quantizers - 1
48
+ self.last_unit_id = last_unit_id
49
+ self.frame_rate_hz = float(frame_rate_hz)
50
+ self.speakers = speakers or ["Ira", "Aisha", "Siya", "Zoya"]
51
+
52
+ @property
53
+ def audio_tokens_per_second(self) -> float:
54
+ """Tokens the model emits per second of audio (8 x 12.5 = 100)."""
55
+ return self.frame_rate_hz * self.num_quantizers
configuration_tinyaya.py DELETED
@@ -1,21 +0,0 @@
1
- from transformers import Cohere2Config
2
-
3
-
4
- class TinyAyaConfig(Cohere2Config):
5
- model_type = "tinyaya_mimi"
6
-
7
- def __init__(
8
- self,
9
- num_quantizers=8,
10
- codebook_size=2048,
11
- audio_start_token_id=None,
12
- audio_end_token_id=None,
13
- speakers=None,
14
- **kwargs,
15
- ):
16
- super().__init__(**kwargs)
17
- self.num_quantizers = int(num_quantizers)
18
- self.codebook_size = int(codebook_size)
19
- self.audio_start_token_id = audio_start_token_id
20
- self.audio_end_token_id = audio_end_token_id
21
- self.speakers = speakers or ["Ira", "Aisha", "Siya", "Zoya"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inference.py CHANGED
@@ -1,7 +1,6 @@
1
  """Speaker-conditioned inference for rumik-oss 1 base."""
2
 
3
  import argparse
4
- import re
5
  import wave
6
  from pathlib import Path
7
 
@@ -14,34 +13,10 @@ from transformers import (
14
  MimiModel,
15
  )
16
 
17
- SPEAKERS = ("Ira", "Aisha", "Siya", "Zoya")
18
- AUDIO_TOKEN = re.compile(r"^<(\d+)_(\d+)>$")
19
-
20
-
21
- def decode_frames(tokens, mapping, quantizers=8):
22
- frames, frame = [], []
23
- for token in tokens:
24
- item = mapping.get(token)
25
- if item is None:
26
- frame = []
27
- continue
28
- code, quantizer = item
29
- if quantizer == len(frame):
30
- frame.append(code)
31
- if len(frame) == quantizers:
32
- frames.append(frame)
33
- frame = []
34
- else:
35
- frame = [code] if quantizer == 0 else []
36
- if not frames:
37
- raise RuntimeError("No complete audio frames were generated.")
38
- return frames
39
-
40
-
41
  def main():
42
  parser = argparse.ArgumentParser(description=__doc__)
43
  parser.add_argument("--model", default=str(Path(__file__).resolve().parent))
44
- parser.add_argument("--speaker", choices=SPEAKERS, default="Ira")
45
  parser.add_argument("--text", required=True)
46
  parser.add_argument("--output", default="speech.wav")
47
  parser.add_argument("--device", default="cuda")
@@ -61,37 +36,30 @@ def main():
61
  root = Path(snapshot_download(args.model))
62
  torch.manual_seed(args.seed)
63
  dtype = torch.bfloat16 if args.device.startswith("cuda") else torch.float32
64
- tokenizer = AutoTokenizer.from_pretrained(root)
65
  model = (
66
  AutoModelForCausalLM.from_pretrained(
67
- root, trust_remote_code=True, torch_dtype=dtype, attn_implementation="sdpa"
68
  )
69
  .eval()
70
  .to(args.device)
71
  )
72
  codec = MimiModel.from_pretrained(root / "codec").eval().to(args.device)
73
  sample_rate = AutoFeatureExtractor.from_pretrained(root / "codec").sampling_rate
74
- mapping = {
75
- token_id: (int(match[1]), int(match[2]))
76
- for token, token_id in tokenizer.get_vocab().items()
77
- if (match := AUDIO_TOKEN.fullmatch(token))
78
- }
79
- eos = tokenizer.convert_tokens_to_ids("</audio>")
80
  inputs = tokenizer(
81
  f"<text>{args.speaker}: {args.text}<audio>", return_tensors="pt"
82
  ).to(args.device)
83
  with torch.inference_mode():
84
  output = model.generate_audio(
85
  **inputs,
86
- allowed_ids=torch.tensor(sorted([*mapping, eos]), device=args.device),
87
  max_new_tokens=args.max_new_tokens,
88
  temperature=args.temperature,
89
  top_k=args.top_k,
90
  )[0, inputs.input_ids.shape[1] :].tolist()
91
- if eos in output:
92
- output = output[: output.index(eos)]
93
- frames = decode_frames(output, mapping)
94
- codes = torch.tensor(frames, device=args.device).T.unsqueeze(0)
95
  audio = codec.decode(codes).audio_values[0, 0].float().cpu().clamp(-1, 1)
96
  with wave.open(args.output, "wb") as stream:
97
  stream.setnchannels(1)
 
1
  """Speaker-conditioned inference for rumik-oss 1 base."""
2
 
3
  import argparse
 
4
  import wave
5
  from pathlib import Path
6
 
 
13
  MimiModel,
14
  )
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  def main():
17
  parser = argparse.ArgumentParser(description=__doc__)
18
  parser.add_argument("--model", default=str(Path(__file__).resolve().parent))
19
+ parser.add_argument("--speaker", default="Ira")
20
  parser.add_argument("--text", required=True)
21
  parser.add_argument("--output", default="speech.wav")
22
  parser.add_argument("--device", default="cuda")
 
36
  root = Path(snapshot_download(args.model))
37
  torch.manual_seed(args.seed)
38
  dtype = torch.bfloat16 if args.device.startswith("cuda") else torch.float32
39
+ tokenizer = AutoTokenizer.from_pretrained(root, trust_remote_code=True)
40
  model = (
41
  AutoModelForCausalLM.from_pretrained(
42
+ root, trust_remote_code=True, dtype=dtype, attn_implementation="sdpa"
43
  )
44
  .eval()
45
  .to(args.device)
46
  )
47
  codec = MimiModel.from_pretrained(root / "codec").eval().to(args.device)
48
  sample_rate = AutoFeatureExtractor.from_pretrained(root / "codec").sampling_rate
49
+ speakers = tuple(model.config.speakers)
50
+ if args.speaker not in speakers:
51
+ parser.error(f"--speaker must be one of: {', '.join(speakers)}")
 
 
 
52
  inputs = tokenizer(
53
  f"<text>{args.speaker}: {args.text}<audio>", return_tensors="pt"
54
  ).to(args.device)
55
  with torch.inference_mode():
56
  output = model.generate_audio(
57
  **inputs,
 
58
  max_new_tokens=args.max_new_tokens,
59
  temperature=args.temperature,
60
  top_k=args.top_k,
61
  )[0, inputs.input_ids.shape[1] :].tolist()
62
+ codes = model.audio_tokens_to_codes(output).to(args.device)
 
 
 
63
  audio = codec.decode(codes).audio_values[0, 0].float().cpu().clamp(-1, 1)
64
  with wave.open(args.output, "wb") as stream:
65
  stream.setnchannels(1)
modeling_tinyaya.py → modeling_rumik_oss.py RENAMED
@@ -1,14 +1,24 @@
 
 
 
 
 
 
 
 
 
 
1
  from __future__ import annotations
2
 
3
  import torch
4
  from torch import nn
5
  from transformers.models.cohere2.modeling_cohere2 import Cohere2ForCausalLM
6
 
7
- from .configuration_tinyaya import TinyAyaConfig
8
 
9
 
10
- class TinyAyaForCausalLM(Cohere2ForCausalLM):
11
- config_class = TinyAyaConfig
12
 
13
  def __init__(self, config):
14
  super().__init__(config)
@@ -20,8 +30,67 @@ class TinyAyaForCausalLM(Cohere2ForCausalLM):
20
  nn.Linear(max(64, hidden // 4), 1),
21
  )
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  @staticmethod
24
- def _sample(scores, do_sample, temperature, top_k):
 
 
 
25
  if not do_sample:
26
  return scores.argmax(dim=-1, keepdim=True)
27
  scores = scores / max(float(temperature), 1e-5)
@@ -36,13 +105,19 @@ class TinyAyaForCausalLM(Cohere2ForCausalLM):
36
  self,
37
  input_ids,
38
  attention_mask,
39
- allowed_ids,
40
  max_new_tokens=2048,
41
  min_new_tokens=8,
42
  temperature=0.8,
43
  top_k=30,
44
  do_sample=True,
45
  ):
 
 
 
 
 
 
46
  out = self(
47
  input_ids=input_ids,
48
  attention_mask=attention_mask,
@@ -67,7 +142,7 @@ class TinyAyaForCausalLM(Cohere2ForCausalLM):
67
  restricted.index_copy_(1, allowed_ids, scores.index_select(1, allowed_ids))
68
  if step < int(min_new_tokens):
69
  restricted[:, audio_end_id] = torch.finfo(scores.dtype).min
70
- token = self._sample(restricted, do_sample, temperature, top_k)
71
  emitted = torch.cat((emitted, token), dim=1)
72
  if bool((token == audio_end_id).all()):
73
  break
 
1
+ """rumik-oss 1: text -> flattened Mimi codec tokens.
2
+
3
+ This model produces *audio tokens*, not waveforms. Decoding them to audio is
4
+ the caller's job and needs the Mimi codec (shipped in ``codec/``)::
5
+
6
+ ids = model.generate_audio(**inputs) # prompt + audio
7
+ tokens = ids[0].tolist()[inputs.input_ids.shape[1]:] # drop the prompt
8
+ codes = model.audio_tokens_to_codes(tokens) # [1, 8, T] for Mimi
9
+ wav = mimi.decode(codes).audio_values # your call
10
+ """
11
  from __future__ import annotations
12
 
13
  import torch
14
  from torch import nn
15
  from transformers.models.cohere2.modeling_cohere2 import Cohere2ForCausalLM
16
 
17
+ from .configuration_rumik_oss import RumikOSSConfig
18
 
19
 
20
+ class RumikOSSForCausalLM(Cohere2ForCausalLM):
21
+ config_class = RumikOSSConfig
22
 
23
  def __init__(self, config):
24
  super().__init__(config)
 
30
  nn.Linear(max(64, hidden // 4), 1),
31
  )
32
 
33
+ # ---- audio vocabulary -------------------------------------------------
34
+ def audio_token_ids(self, device=None) -> torch.Tensor:
35
+ """Every id the model may legally emit inside an <audio> span.
36
+
37
+ Derived from the config, so callers no longer have to scan the
38
+ tokenizer vocabulary for ``<code>_<quantizer>`` tokens.
39
+ """
40
+ c = self.config
41
+ if c.first_unit_id is None:
42
+ raise ValueError(
43
+ "config.first_unit_id is unset; pass allowed_ids explicitly or "
44
+ "add first_unit_id/last_unit_id to config.json.")
45
+ ids = torch.arange(int(c.first_unit_id), int(c.last_unit_id) + 1, dtype=torch.long)
46
+ end = torch.tensor([int(c.audio_end_token_id)], dtype=torch.long)
47
+ return torch.cat((ids, end)).to(device if device is not None else self.device)
48
+
49
+ def audio_tokens_to_codes(self, token_ids) -> torch.Tensor:
50
+ """Generated ids -> ``[1, num_quantizers, num_frames]`` codec codes.
51
+
52
+ Shaped for ``MimiModel.decode``. Purely arithmetic -- no tokenizer, no
53
+ codec, no audio. Pass only the generated tail, not the prompt.
54
+
55
+ A token that breaks the round robin does not end the audio: the
56
+ partial frame is dropped and the next complete frame is picked up
57
+ again, so one bad token costs one frame rather than the rest of the
58
+ clip. ``</audio>`` ends it.
59
+ """
60
+ c = self.config
61
+ first, last, Q = int(c.first_unit_id), int(c.last_unit_id), int(c.num_quantizers)
62
+ end_id = int(c.audio_end_token_id)
63
+ if torch.is_tensor(token_ids):
64
+ token_ids = token_ids.flatten().tolist()
65
+
66
+ frames: list[list[int]] = []
67
+ frame: list[int] = []
68
+ for tid in (int(t) for t in token_ids):
69
+ if tid == end_id:
70
+ break
71
+ if not first <= tid <= last:
72
+ frame = [] # stray token: resync
73
+ continue
74
+ code, q = divmod(tid - first, Q)
75
+ if q == len(frame):
76
+ frame.append(code)
77
+ if len(frame) == Q:
78
+ frames.append(frame)
79
+ frame = []
80
+ else: # off the round robin
81
+ frame = [code] if q == 0 else []
82
+ if not frames:
83
+ raise ValueError(
84
+ f"no complete codec frame in {len(token_ids)} tokens "
85
+ f"(need at least {Q})")
86
+ return torch.tensor(frames, dtype=torch.long).T.unsqueeze(0)
87
+
88
+ # ---- generation -------------------------------------------------------
89
  @staticmethod
90
+ def _constrained_sample(scores, do_sample, temperature, top_k):
91
+ # NB: deliberately not named `_sample`. `GenerationMixin._sample` is the
92
+ # method `generate()` dispatches to, and shadowing it makes every call
93
+ # to `generate()` fail with a TypeError on `logits_processor`.
94
  if not do_sample:
95
  return scores.argmax(dim=-1, keepdim=True)
96
  scores = scores / max(float(temperature), 1e-5)
 
105
  self,
106
  input_ids,
107
  attention_mask,
108
+ allowed_ids=None,
109
  max_new_tokens=2048,
110
  min_new_tokens=8,
111
  temperature=0.8,
112
  top_k=30,
113
  do_sample=True,
114
  ):
115
+ """Autoregressively emit audio tokens, ending at ``</audio>``.
116
+
117
+ ``allowed_ids`` defaults to the audio vocabulary from the config.
118
+ """
119
+ if allowed_ids is None:
120
+ allowed_ids = self.audio_token_ids(device=input_ids.device)
121
  out = self(
122
  input_ids=input_ids,
123
  attention_mask=attention_mask,
 
142
  restricted.index_copy_(1, allowed_ids, scores.index_select(1, allowed_ids))
143
  if step < int(min_new_tokens):
144
  restricted[:, audio_end_id] = torch.finfo(scores.dtype).min
145
+ token = self._constrained_sample(restricted, do_sample, temperature, top_k)
146
  emitted = torch.cat((emitted, token), dim=1)
147
  if bool((token == audio_end_id).all()):
148
  break
requirements.txt CHANGED
@@ -1,5 +1,6 @@
1
  torch>=2.9,<3
2
- transformers==4.57.6
3
- huggingface_hub>=0.36,<1
4
  accelerate>=1.12,<2
5
  safetensors>=0.6,<1
 
 
1
  torch>=2.9,<3
2
+ transformers>=4.57,<6
3
+ huggingface_hub>=0.36
4
  accelerate>=1.12,<2
5
  safetensors>=0.6,<1
6
+ soundfile>=0.12