ONNX release v1
Browse files- LICENSE +201 -0
- NOTICE +15 -0
- README.md +92 -0
- config.json +58 -0
- conversion/README.md +65 -0
- conversion/export.py +398 -0
- conversion/pyproject.toml +25 -0
- conversion/uv.lock +247 -0
- decoder.onnx +3 -0
- encoder.onnx +3 -0
LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
NOTICE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
g2p_en 2.1.0: English grapheme-to-phoneme conversion
|
| 2 |
+
Original work by Kyubyong Park and Jongseok Kim, licensed under the Apache
|
| 3 |
+
License, Version 2.0. https://github.com/Kyubyong/g2p
|
| 4 |
+
Source file: g2p_en/checkpoint20.npz (SHA-256
|
| 5 |
+
b8af35e4596d8dd5836dfd3fe9b2ba4f97b9c311efe8879544cbcfcbd566d8c6)
|
| 6 |
+
|
| 7 |
+
This repository contains an ONNX conversion made by Drew Bednar for
|
| 8 |
+
go-phonmatchnet, from the repackaging androiddrew/g2p-en-decoder-pytorch
|
| 9 |
+
(revision v1, commit fc55559c25a12fce6e0cf9062729e7f2a9fc1ddc). It is not
|
| 10 |
+
affiliated with or endorsed by the g2p_en authors.
|
| 11 |
+
|
| 12 |
+
Modifications to the original work: the NumPy arrays were renamed and stored
|
| 13 |
+
in safetensors format, then the network was split into a word-encoder graph
|
| 14 |
+
and a single-step decoder graph and exported to ONNX. Values are unchanged.
|
| 15 |
+
No training or fine-tuning was performed.
|
README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
library_name: onnx
|
| 4 |
+
language:
|
| 5 |
+
- en
|
| 6 |
+
pipeline_tag: feature-extraction
|
| 7 |
+
tags:
|
| 8 |
+
- grapheme-to-phoneme
|
| 9 |
+
- g2p
|
| 10 |
+
- keyword-spotting
|
| 11 |
+
- wake-word
|
| 12 |
+
- onnx
|
| 13 |
+
base_model: androiddrew/g2p-en-decoder-pytorch
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# g2p_en decoder: keyword text features, ONNX
|
| 17 |
+
|
| 18 |
+
The [g2p_en](https://github.com/Kyubyong/g2p) grapheme-to-phoneme model
|
| 19 |
+
(Kyubyong Park & Jongseok Kim, Apache-2.0, release 2.1.0) as two ONNX graphs,
|
| 20 |
+
converted from
|
| 21 |
+
[`androiddrew/g2p-en-decoder-pytorch`](https://huggingface.co/androiddrew/g2p-en-decoder-pytorch).
|
| 22 |
+
The values are unchanged.
|
| 23 |
+
|
| 24 |
+
It is **not** used to output phoneme strings. The keyword model
|
| 25 |
+
[`androiddrew/naptrap-phonmatchnet-en-onnx`](https://huggingface.co/androiddrew/naptrap-phonmatchnet-en-onnx)
|
| 26 |
+
was trained on the decoder's **hidden states**. It is embedded in
|
| 27 |
+
[go-phonmatchnet](https://github.com/androiddrew/go-phonmatchnet).
|
| 28 |
+
|
| 29 |
+
> Not affiliated with or endorsed by the g2p_en authors. See `LICENSE` and `NOTICE`.
|
| 30 |
+
|
| 31 |
+
## Files
|
| 32 |
+
|
| 33 |
+
| Graph | Inputs | Outputs |
|
| 34 |
+
|---|---|---|
|
| 35 |
+
| `encoder.onnx` | `graphemes` int64 `[L]`: a word's grapheme IDs, then `</s>` (2) | `hidden` `[1, 256]`; `separator` `[1, 256]`, the row placed between words |
|
| 36 |
+
| `decoder.onnx` | `token` int64 `[1]`, `hidden` `[1, 256]` | `next_hidden` `[1, 256]`; `logits` `[1, 74]` |
|
| 37 |
+
|
| 38 |
+
`config.json` lists the grapheme vocabulary, start/end phoneme IDs, the
|
| 39 |
+
20-step limit and the SHA-256 of both graphs. `conversion/` holds the export
|
| 40 |
+
script, its locked environment and README.
|
| 41 |
+
|
| 42 |
+
## Keyword features
|
| 43 |
+
|
| 44 |
+
1. Normalize the keyword: NFKD, drop combining marks, lowercase, and keep
|
| 45 |
+
words matching `[a-z]+(?:'[a-z]+)*`. Numbers must be spelled out.
|
| 46 |
+
2. Encode each word: grapheme IDs from `config.json` (`<unk>` for `'`), then `</s>`.
|
| 47 |
+
3. Decode greedily from token 2 (`<s>`) for up to 20 steps; each step's
|
| 48 |
+
`next_hidden` is one feature row, until the argmax token is 3 (`</s>`),
|
| 49 |
+
whose state is not kept.
|
| 50 |
+
4. Put the `separator` row between words.
|
| 51 |
+
|
| 52 |
+
```python
|
| 53 |
+
import numpy as np
|
| 54 |
+
import onnxruntime as ort
|
| 55 |
+
|
| 56 |
+
encoder = ort.InferenceSession("encoder.onnx")
|
| 57 |
+
decoder = ort.InferenceSession("decoder.onnx")
|
| 58 |
+
graphemes = {g: i for i, g in enumerate(config["graphemes"])}
|
| 59 |
+
|
| 60 |
+
def features(normalized):
|
| 61 |
+
rows = []
|
| 62 |
+
for i, word in enumerate(normalized.split()):
|
| 63 |
+
ids = np.array([graphemes.get(c, 1) for c in word] + [2], dtype=np.int64)
|
| 64 |
+
hidden, separator = encoder.run(None, {"graphemes": ids})
|
| 65 |
+
if i:
|
| 66 |
+
rows.append(separator)
|
| 67 |
+
token = 2
|
| 68 |
+
for _ in range(20):
|
| 69 |
+
hidden, logits = decoder.run(None, {"token": np.array([token]), "hidden": hidden})
|
| 70 |
+
token = int(logits.argmax())
|
| 71 |
+
if token == 3:
|
| 72 |
+
break
|
| 73 |
+
rows.append(hidden)
|
| 74 |
+
return np.concatenate(rows) # float32 [positions, 256]
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
## Conversion and accuracy
|
| 78 |
+
|
| 79 |
+
`conversion/export.py` loads the PyTorch release at commit
|
| 80 |
+
`fc55559c25a12fce6e0cf9062729e7f2a9fc1ddc` with naptrap 0.1.0. The grapheme
|
| 81 |
+
GRU has PyTorch's gate layout, so the encoder is an ONNX `GRU` operator; the
|
| 82 |
+
decoder is one GRU-cell step plus the output projection. Over eight keywords,
|
| 83 |
+
including apostrophes, accents, one letter, a 34-letter word and a nine-word
|
| 84 |
+
sentence, every feature length matched naptrap and the maximum difference was
|
| 85 |
+
5.5e-6. With the locked environment it reproduces both graphs byte for byte.
|
| 86 |
+
|
| 87 |
+
## Limitations
|
| 88 |
+
|
| 89 |
+
The model was trained on CMUdict pronunciations of American English words.
|
| 90 |
+
Unusual names, brand names and non-English words get its best-guess
|
| 91 |
+
pronunciation, which may not match how people say them. The dictionary-lookup,
|
| 92 |
+
homograph and number-expansion steps of the g2p_en package are not used.
|
config.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format": "naptrap-g2p-en-decoder-onnx-v1",
|
| 3 |
+
"source": {
|
| 4 |
+
"repo_id": "androiddrew/g2p-en-decoder-pytorch",
|
| 5 |
+
"commit": "fc55559c25a12fce6e0cf9062729e7f2a9fc1ddc",
|
| 6 |
+
"format": "naptrap-g2p-en-decoder-v1",
|
| 7 |
+
"sha256": "bba37553a3414f90c7ed0cd465925aa15def67f42cc59bf43b8c633e1eb7b445"
|
| 8 |
+
},
|
| 9 |
+
"opset": 17,
|
| 10 |
+
"hidden_size": 256,
|
| 11 |
+
"graphemes": [
|
| 12 |
+
"<pad>",
|
| 13 |
+
"<unk>",
|
| 14 |
+
"</s>",
|
| 15 |
+
"a",
|
| 16 |
+
"b",
|
| 17 |
+
"c",
|
| 18 |
+
"d",
|
| 19 |
+
"e",
|
| 20 |
+
"f",
|
| 21 |
+
"g",
|
| 22 |
+
"h",
|
| 23 |
+
"i",
|
| 24 |
+
"j",
|
| 25 |
+
"k",
|
| 26 |
+
"l",
|
| 27 |
+
"m",
|
| 28 |
+
"n",
|
| 29 |
+
"o",
|
| 30 |
+
"p",
|
| 31 |
+
"q",
|
| 32 |
+
"r",
|
| 33 |
+
"s",
|
| 34 |
+
"t",
|
| 35 |
+
"u",
|
| 36 |
+
"v",
|
| 37 |
+
"w",
|
| 38 |
+
"x",
|
| 39 |
+
"y",
|
| 40 |
+
"z"
|
| 41 |
+
],
|
| 42 |
+
"phonemes": 74,
|
| 43 |
+
"start_token": 2,
|
| 44 |
+
"end_token": 3,
|
| 45 |
+
"max_decoder_steps": 20,
|
| 46 |
+
"inputs": {
|
| 47 |
+
"encoder": "graphemes [L] int64: a word's grapheme IDs followed by </s> (2)",
|
| 48 |
+
"decoder": "token [1] int64 (start with 2), hidden [1,256] float32"
|
| 49 |
+
},
|
| 50 |
+
"outputs": {
|
| 51 |
+
"encoder": "hidden [1,256]; separator [1,256], the row placed between words",
|
| 52 |
+
"decoder": "next_hidden [1,256], one feature row; logits [1,74], argmax is the next token"
|
| 53 |
+
},
|
| 54 |
+
"sha256": {
|
| 55 |
+
"encoder.onnx": "c492a8907a8b62d7f1e311c0df469490a4e4670865a6a5d8b4b7749a38666091",
|
| 56 |
+
"decoder.onnx": "86953a2604f3494bf44c4d81df67c444455b4a9f0cf6f08d62fab08393bd29e1"
|
| 57 |
+
}
|
| 58 |
+
}
|
conversion/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Export tooling
|
| 2 |
+
|
| 3 |
+
`export.py` rebuilds every model go-phonmatchnet embeds (`models/`) from
|
| 4 |
+
naptrap's PyTorch releases on Hugging Face, pinned by commit and SHA-256:
|
| 5 |
+
|
| 6 |
+
| Source | Commit | Output |
|
| 7 |
+
|---|---|---|
|
| 8 |
+
| `androiddrew/naptrap-phonmatchnet-en` v1 | `e8f6c45bff04d7368cbe14979392b7d52dc88ba8` | `phonmatchnet/model.onnx`, `config.json` |
|
| 9 |
+
| `androiddrew/google-speech-embedding-pytorch` v1 | `ad7a3dd93b02f83797a040857425d6343d98680a` | `google/model.onnx`, `config.json` |
|
| 10 |
+
| `androiddrew/g2p-en-decoder-pytorch` v1 | `fc55559c25a12fce6e0cf9062729e7f2a9fc1ddc` | `g2p/encoder.onnx`, `decoder.onnx`, `config.json` |
|
| 11 |
+
|
| 12 |
+
The PyTorch modules come from naptrap 0.1.0, so the graphs are traced from the
|
| 13 |
+
same code that defines the reference outputs. The trained values are copied
|
| 14 |
+
unchanged. Two things are re-expressed for ONNX:
|
| 15 |
+
|
| 16 |
+
- **Spectrogram frontends.** `torch.stft` and `torch.fft.rfft` do not export
|
| 17 |
+
reliably, so each FFT is a strided `Conv` with a fixed cos/sin DFT basis
|
| 18 |
+
that has the original window folded in. Reflect and zero padding, power or
|
| 19 |
+
magnitude, the mel matrix and the log are ordinary graph operators. The
|
| 20 |
+
graphs take raw samples.
|
| 21 |
+
- **The g2p greedy decode.** The encoder is an ONNX `GRU`; the decoder is one
|
| 22 |
+
step, which the caller runs until the end token. Data-dependent loops stay
|
| 23 |
+
out of the graph.
|
| 24 |
+
|
| 25 |
+
After exporting, the script runs every graph with ONNX Runtime against
|
| 26 |
+
naptrap's PyTorch modules (17 clips of speech and noise from 8,000 to
|
| 27 |
+
32,000 samples long, eight keywords) and fails outside 1e-3 on embeddings and
|
| 28 |
+
logits or 1e-5 on text features. The measured maxima are about 4e-5, 1e-5 and 5.5e-6.
|
| 29 |
+
|
| 30 |
+
```bash
|
| 31 |
+
cd tools/export
|
| 32 |
+
uv run --frozen python export.py --output out --check
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
`--check` compares each output with the committed file and fails on any
|
| 36 |
+
difference. With the locked environment in `uv.lock` (Python 3.12, torch
|
| 37 |
+
2.6.0+cpu, onnx 1.17.0, onnxruntime 1.22.1, naptrap 0.1.0) on Linux/amd64,
|
| 38 |
+
all seven outputs reproduce byte for byte. Copy `out/` over `models/` only
|
| 39 |
+
when intentionally changing the embedded models.
|
| 40 |
+
|
| 41 |
+
## Hugging Face repositories
|
| 42 |
+
|
| 43 |
+
```bash
|
| 44 |
+
uv run --frozen python hf.py --output hf-out
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
assembles `hf-out/naptrap-phonmatchnet-en-onnx`, `google-speech-embedding-onnx`
|
| 48 |
+
and `g2p-en-decoder-onnx` from the committed `models/`, the cards and NOTICE
|
| 49 |
+
files in `hf/`, the Apache-2.0 LICENSE and this directory as `conversion/`.
|
| 50 |
+
|
| 51 |
+
## Test fixtures
|
| 52 |
+
|
| 53 |
+
`fixtures.py` builds `testdata/`:
|
| 54 |
+
|
| 55 |
+
```bash
|
| 56 |
+
uv run --frozen python fixtures.py synth --server http://host:8880 # Kokoro clips
|
| 57 |
+
uv run --frozen python fixtures.py reference # naptrap outputs
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
`synth` requests each phrase from an OpenAI-compatible Kokoro speech server
|
| 61 |
+
(`kokoro-v1.0`; voices `af_heart`, `am_michael`, `bf_emma`), converts it to
|
| 62 |
+
16 kHz 16-bit mono with ffmpeg and adds 0.2 s of silence on each side. TTS
|
| 63 |
+
output is not guaranteed to be bit-stable, so the clips are committed.
|
| 64 |
+
`reference` scores the committed clips with naptrap's PyTorch models and
|
| 65 |
+
writes `testdata/reference.json`.
|
conversion/export.py
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Convert naptrap's PyTorch PhonMatchNet models to the ONNX graphs go-phonmatchnet embeds.
|
| 2 |
+
|
| 3 |
+
Sources are naptrap's three Hugging Face repositories at their v1 commits,
|
| 4 |
+
pinned by commit and SHA-256. The PyTorch modules come from naptrap 0.1.0, so
|
| 5 |
+
every graph is traced from the same code that produced the reference outputs.
|
| 6 |
+
|
| 7 |
+
Outputs, in the repository's models/ layout:
|
| 8 |
+
|
| 9 |
+
phonmatchnet/model.onnx waveform [N], google [G,96], text [P,256] -> logit [1]
|
| 10 |
+
google/model.onnx waveform [N] -> embeddings [floor(N/1280), 96]
|
| 11 |
+
g2p/encoder.onnx graphemes [L] -> hidden [1,256], separator [1,256]
|
| 12 |
+
g2p/decoder.onnx token [1], hidden [1,256] -> next_hidden [1,256], logits [1,74]
|
| 13 |
+
*/config.json metadata the Go engine reads
|
| 14 |
+
|
| 15 |
+
The STFT frontends are inside the graphs. Each FFT is written as a strided
|
| 16 |
+
convolution with a fixed DFT basis (the window folded in), which ONNX exports
|
| 17 |
+
exactly; torch.stft and torch.fft do not export reliably. The g2p greedy
|
| 18 |
+
decode stays a loop in Go around the single-step decoder graph.
|
| 19 |
+
|
| 20 |
+
Usage: uv run --frozen python export.py --output out [--check]
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
import argparse
|
| 24 |
+
import hashlib
|
| 25 |
+
import json
|
| 26 |
+
import math
|
| 27 |
+
import shutil
|
| 28 |
+
import sys
|
| 29 |
+
import urllib.request
|
| 30 |
+
from pathlib import Path
|
| 31 |
+
|
| 32 |
+
import numpy as np
|
| 33 |
+
import onnx
|
| 34 |
+
import onnxruntime
|
| 35 |
+
import torch
|
| 36 |
+
from torch import nn
|
| 37 |
+
from torch.nn import functional as F
|
| 38 |
+
|
| 39 |
+
from naptrap.models.phonmatchnet import PhonMatchNet
|
| 40 |
+
from naptrap.text import GRAPHEMES
|
| 41 |
+
|
| 42 |
+
REPO = Path(__file__).resolve().parents[2]
|
| 43 |
+
OPSET = 17
|
| 44 |
+
HF = "https://huggingface.co/androiddrew/{repo}/resolve/{commit}/{file}"
|
| 45 |
+
SOURCES = {
|
| 46 |
+
"naptrap-phonmatchnet-en": ("e8f6c45bff04d7368cbe14979392b7d52dc88ba8", {
|
| 47 |
+
"config.json": "33b0a0decd5b563ebc67cd248008f8fcfcca8a2e71c03b79da9677470b7a619a",
|
| 48 |
+
"model.safetensors": "6cdb3f86b6ab57a00d47d3436b16c7ffd9c4b0d049cfcb98d49a478877213226",
|
| 49 |
+
"examples/said-mister.wav": "770afe00e123da53a8ef37be2b637083b2b84cdaeba59ab2d060878d349b2403",
|
| 50 |
+
}),
|
| 51 |
+
"google-speech-embedding-pytorch": ("ad7a3dd93b02f83797a040857425d6343d98680a", {
|
| 52 |
+
"config.json": "cd241bf118d3e16c74e3850ed6c75340216af00c8810835c95b8b620c6f22b6f",
|
| 53 |
+
"model.safetensors": "80a10015f4eb8ff9ba1aa10b56b1d6e27ef9f9f3419ebbae56fb43e9afce37be",
|
| 54 |
+
}),
|
| 55 |
+
"g2p-en-decoder-pytorch": ("fc55559c25a12fce6e0cf9062729e7f2a9fc1ddc", {
|
| 56 |
+
"config.json": "d1f02ff5209f688537731abdb849c5b793538abecdb5b9c19c1a0c0f25a03b11",
|
| 57 |
+
"model.safetensors": "bba37553a3414f90c7ed0cd465925aa15def67f42cc59bf43b8c633e1eb7b445",
|
| 58 |
+
}),
|
| 59 |
+
}
|
| 60 |
+
OUTPUTS = [
|
| 61 |
+
"phonmatchnet/model.onnx",
|
| 62 |
+
"phonmatchnet/config.json",
|
| 63 |
+
"google/model.onnx",
|
| 64 |
+
"google/config.json",
|
| 65 |
+
"g2p/encoder.onnx",
|
| 66 |
+
"g2p/decoder.onnx",
|
| 67 |
+
"g2p/config.json",
|
| 68 |
+
]
|
| 69 |
+
# Clip lengths cover the accepted range, both frame-length rules and every
|
| 70 |
+
# boundary where N % 160 or N % 1280 changes the frame count.
|
| 71 |
+
LENGTHS = [8000, 8001, 8159, 8160, 12800, 12801, 16000, 23999, 31840, 32000]
|
| 72 |
+
KEYWORDS = ["hey computer", "said mister", "okay naptrap", "don't stop", "Café au lait", "a",
|
| 73 |
+
"supercalifragilisticexpialidocious", "the quick brown fox jumps over the lazy dog"]
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def sha256(path):
|
| 77 |
+
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def fetch(cache):
|
| 81 |
+
"""Download each pinned source file once and verify it."""
|
| 82 |
+
roots = {}
|
| 83 |
+
for repo, (commit, files) in SOURCES.items():
|
| 84 |
+
root = cache / repo / commit
|
| 85 |
+
for name, digest in files.items():
|
| 86 |
+
path = root / name
|
| 87 |
+
if not path.exists() or sha256(path) != digest:
|
| 88 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 89 |
+
url = HF.format(repo=repo, commit=commit, file=name)
|
| 90 |
+
print("download", url, file=sys.stderr)
|
| 91 |
+
with urllib.request.urlopen(url) as response:
|
| 92 |
+
path.write_bytes(response.read())
|
| 93 |
+
if sha256(path) != digest:
|
| 94 |
+
raise SystemExit(f"{repo}/{name}: SHA-256 mismatch")
|
| 95 |
+
roots[repo] = root
|
| 96 |
+
return roots
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def dft_basis(window, n_fft, offset=0):
|
| 100 |
+
"""[2*(n_fft//2+1), 1, taps] cos/-sin DFT rows with the window applied.
|
| 101 |
+
|
| 102 |
+
The window sits at ``offset`` inside the n_fft-point frame; taps after it
|
| 103 |
+
multiply zeros, so they are dropped.
|
| 104 |
+
"""
|
| 105 |
+
bins = n_fft // 2 + 1
|
| 106 |
+
padded = torch.zeros(n_fft, dtype=torch.float64)
|
| 107 |
+
padded[offset:offset + window.numel()] = window.double()
|
| 108 |
+
n = torch.arange(n_fft, dtype=torch.float64)
|
| 109 |
+
angle = 2 * math.pi * torch.arange(bins, dtype=torch.float64)[:, None] * n[None, :] / n_fft
|
| 110 |
+
basis = torch.cat([torch.cos(angle), -torch.sin(angle)]) * padded
|
| 111 |
+
length = offset + window.numel()
|
| 112 |
+
return basis[:, :length].float().unsqueeze(1).contiguous()
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
class GoogleGraph(nn.Module):
|
| 116 |
+
"""naptrap GoogleSpeechEmbedding with its rfft frontend as a DFT convolution."""
|
| 117 |
+
|
| 118 |
+
def __init__(self, google):
|
| 119 |
+
super().__init__()
|
| 120 |
+
self.google = google
|
| 121 |
+
self.register_buffer("basis", dft_basis(google.window, 512))
|
| 122 |
+
|
| 123 |
+
def forward(self, waveform):
|
| 124 |
+
padded = F.pad(waveform, (11120, 0)).reshape(1, 1, -1)
|
| 125 |
+
spectrum = F.conv1d(padded, self.basis, stride=160)[0]
|
| 126 |
+
real, imag = spectrum[:257], spectrum[257:]
|
| 127 |
+
magnitude = torch.sqrt(real * real + imag * imag).transpose(0, 1)
|
| 128 |
+
log_mel = torch.log(magnitude @ self.google.mel_matrix + .001)
|
| 129 |
+
return self.google.encode_log_mel(log_mel)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
class PhonMatchNetGraph(nn.Module):
|
| 133 |
+
"""naptrap PhonMatchNetwork with its centered STFT frontend as a DFT convolution."""
|
| 134 |
+
|
| 135 |
+
def __init__(self, network):
|
| 136 |
+
super().__init__()
|
| 137 |
+
self.network = network
|
| 138 |
+
frontend = network.audio.frontend
|
| 139 |
+
# torch.stft centers a 400-sample window inside the 512-point frame.
|
| 140 |
+
self.register_buffer("basis", dft_basis(frontend.window, 512, offset=56))
|
| 141 |
+
self.register_buffer("mel_matrix", frontend.mel_matrix.clone())
|
| 142 |
+
|
| 143 |
+
def forward(self, waveform, google, text):
|
| 144 |
+
samples = waveform.shape[0]
|
| 145 |
+
padded = F.pad(waveform.reshape(1, 1, -1), (256, 256), mode="reflect")
|
| 146 |
+
spectrum = F.conv1d(padded, self.basis, stride=160)[0]
|
| 147 |
+
real, imag = spectrum[:257], spectrum[257:]
|
| 148 |
+
power = (real * real + imag * imag).transpose(0, 1)
|
| 149 |
+
keyword_mel = torch.log10(power @ self.mel_matrix + 1e-7)
|
| 150 |
+
keyword_mel = keyword_mel[:(samples + 159) // 160].unsqueeze(0)
|
| 151 |
+
return self.network(keyword_mel, google.unsqueeze(0), text.unsqueeze(0))
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
class G2PEncoderGraph(nn.Module):
|
| 155 |
+
"""Grapheme IDs of one word (ending in </s>) -> final encoder GRU state.
|
| 156 |
+
|
| 157 |
+
The g2p_en cell has PyTorch's GRU gate layout (r, z, n with the reset gate
|
| 158 |
+
applied after the hidden projection), so nn.GRU exports it as an ONNX GRU.
|
| 159 |
+
The decoder's <pad> phoneme embedding is returned as the word separator.
|
| 160 |
+
"""
|
| 161 |
+
|
| 162 |
+
def __init__(self, text):
|
| 163 |
+
super().__init__()
|
| 164 |
+
size = text.size
|
| 165 |
+
self.embedding = nn.Parameter(text.enc_emb.detach().clone())
|
| 166 |
+
self.gru = nn.GRU(size, size, batch_first=True)
|
| 167 |
+
cell = text.encoder
|
| 168 |
+
self.gru.weight_ih_l0.data.copy_(cell.w_ih)
|
| 169 |
+
self.gru.weight_hh_l0.data.copy_(cell.w_hh)
|
| 170 |
+
self.gru.bias_ih_l0.data.copy_(cell.b_ih)
|
| 171 |
+
self.gru.bias_hh_l0.data.copy_(cell.b_hh)
|
| 172 |
+
self.register_buffer("pad", text.dec_emb[0:1].detach().clone())
|
| 173 |
+
|
| 174 |
+
def forward(self, graphemes):
|
| 175 |
+
_, hidden = self.gru(self.embedding[graphemes].unsqueeze(0))
|
| 176 |
+
return hidden[0], self.pad
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
class G2PDecoderGraph(nn.Module):
|
| 180 |
+
"""One greedy decoder step: previous phoneme ID and state -> new state, logits."""
|
| 181 |
+
|
| 182 |
+
def __init__(self, text):
|
| 183 |
+
super().__init__()
|
| 184 |
+
self.text = text
|
| 185 |
+
|
| 186 |
+
def forward(self, token, hidden):
|
| 187 |
+
hidden = self.text.decoder(self.text.dec_emb[token], hidden)
|
| 188 |
+
return hidden, hidden @ self.text.fc_w.T + self.text.fc_b
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
def export(module, path, args, inputs, outputs, axes):
|
| 192 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 193 |
+
module.eval()
|
| 194 |
+
with torch.no_grad():
|
| 195 |
+
torch.onnx.export(module, args, str(path), input_names=inputs, output_names=outputs,
|
| 196 |
+
dynamic_axes=axes, opset_version=OPSET, do_constant_folding=True, dynamo=False)
|
| 197 |
+
model = onnx.load(str(path))
|
| 198 |
+
# A constant output (the g2p separator) is folded into an initializer and
|
| 199 |
+
# loses its requested name; restore it with an Identity node.
|
| 200 |
+
for output, name in zip(model.graph.output, outputs):
|
| 201 |
+
if output.name != name:
|
| 202 |
+
model.graph.node.append(onnx.helper.make_node("Identity", [output.name], [name]))
|
| 203 |
+
output.name = name
|
| 204 |
+
onnx.checker.check_model(model, full_check=True)
|
| 205 |
+
# Drop the exporter's version stamp so the bytes depend only on the graph.
|
| 206 |
+
model.producer_version = ""
|
| 207 |
+
onnx.save(model, str(path))
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def companion_config(source_config, repo, commit, fmt, files, extra):
|
| 211 |
+
config = {
|
| 212 |
+
"format": fmt,
|
| 213 |
+
"source": {
|
| 214 |
+
"repo_id": "androiddrew/" + repo,
|
| 215 |
+
"commit": commit,
|
| 216 |
+
"format": source_config["format"],
|
| 217 |
+
"sha256": source_config["sha256"]["model.safetensors"],
|
| 218 |
+
},
|
| 219 |
+
"opset": OPSET,
|
| 220 |
+
}
|
| 221 |
+
config.update(extra)
|
| 222 |
+
config["sha256"] = {name: sha256(path) for name, path in files}
|
| 223 |
+
return config
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
def write_json(path, value):
|
| 227 |
+
path.write_text(json.dumps(value, indent=2) + "\n")
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
def build(roots, output):
|
| 231 |
+
pm_root = roots["naptrap-phonmatchnet-en"]
|
| 232 |
+
google_root = roots["google-speech-embedding-pytorch"]
|
| 233 |
+
g2p_root = roots["g2p-en-decoder-pytorch"]
|
| 234 |
+
model = PhonMatchNet(pm_root, google_root, g2p_root)
|
| 235 |
+
google, text = model.google_encoder, model.text_encoder
|
| 236 |
+
configs = {key: json.loads((roots[repo] / "config.json").read_text()) for key, repo in [
|
| 237 |
+
("phonmatchnet", "naptrap-phonmatchnet-en"), ("google", "google-speech-embedding-pytorch"),
|
| 238 |
+
("g2p", "g2p-en-decoder-pytorch")]}
|
| 239 |
+
|
| 240 |
+
wave = torch.zeros(16000)
|
| 241 |
+
export(GoogleGraph(google), output / "google/model.onnx", (wave,), ["waveform"], ["embeddings"],
|
| 242 |
+
{"waveform": {0: "samples"}, "embeddings": {0: "frames"}})
|
| 243 |
+
export(PhonMatchNetGraph(model._model), output / "phonmatchnet/model.onnx",
|
| 244 |
+
(wave, torch.zeros(12, 96), torch.zeros(9, 256)), ["waveform", "google", "text"], ["logit"],
|
| 245 |
+
{"waveform": {0: "samples"}, "google": {0: "google_frames"}, "text": {0: "positions"}})
|
| 246 |
+
export(G2PEncoderGraph(text), output / "g2p/encoder.onnx", (torch.tensor([5, 6, 2]),),
|
| 247 |
+
["graphemes"], ["hidden", "separator"], {"graphemes": {0: "length"}})
|
| 248 |
+
export(G2PDecoderGraph(text), output / "g2p/decoder.onnx", (torch.tensor([2]), torch.zeros(1, 256)),
|
| 249 |
+
["token", "hidden"], ["next_hidden", "logits"], {})
|
| 250 |
+
|
| 251 |
+
source = configs["phonmatchnet"]
|
| 252 |
+
commit = SOURCES["naptrap-phonmatchnet-en"][0]
|
| 253 |
+
write_json(output / "phonmatchnet/config.json", companion_config(
|
| 254 |
+
source, "naptrap-phonmatchnet-en", commit, "naptrap-phonmatchnet-onnx-v1",
|
| 255 |
+
[("model.onnx", output / "phonmatchnet/model.onnx")], {
|
| 256 |
+
"architecture": source["architecture"],
|
| 257 |
+
"task": source["task"],
|
| 258 |
+
"language": source["language"],
|
| 259 |
+
"thresholds": source["thresholds"],
|
| 260 |
+
"threshold_note": source["threshold_note"],
|
| 261 |
+
"inputs": {
|
| 262 |
+
"waveform": "[N] mono 16 kHz float32 in [-1, 1], 8000 <= N <= 32000",
|
| 263 |
+
"google": "[floor(N / 1280), 96] output of google/model.onnx for the same waveform",
|
| 264 |
+
"text": "[P, 256] g2p decoder features, 1 <= P <= 128",
|
| 265 |
+
},
|
| 266 |
+
"outputs": {"logit": "[1] keyword logit; score = sigmoid(logit)"},
|
| 267 |
+
"frontend": source["frontend"],
|
| 268 |
+
# The companion graphs this model was trained with, pinned like the
|
| 269 |
+
# PyTorch release pins its encoders.
|
| 270 |
+
"requires": {
|
| 271 |
+
"google": {"repo_id": "androiddrew/google-speech-embedding-onnx", "revision": "v1",
|
| 272 |
+
"sha256": {"model.onnx": sha256(output / "google/model.onnx")}},
|
| 273 |
+
"g2p": {"repo_id": "androiddrew/g2p-en-decoder-onnx", "revision": "v1",
|
| 274 |
+
"sha256": {"encoder.onnx": sha256(output / "g2p/encoder.onnx"),
|
| 275 |
+
"decoder.onnx": sha256(output / "g2p/decoder.onnx")}},
|
| 276 |
+
},
|
| 277 |
+
}))
|
| 278 |
+
source = configs["google"]
|
| 279 |
+
write_json(output / "google/config.json", companion_config(
|
| 280 |
+
source, "google-speech-embedding-pytorch", SOURCES["google-speech-embedding-pytorch"][0],
|
| 281 |
+
"naptrap-google-speech-embedding-onnx-v1", [("model.onnx", output / "google/model.onnx")], {
|
| 282 |
+
"embedding_size": source["embedding_size"],
|
| 283 |
+
"inputs": {"waveform": "[N] mono 16 kHz float32, N >= 1280"},
|
| 284 |
+
"outputs": {"embeddings": "[floor(N / 1280), 96]"},
|
| 285 |
+
"preprocessing": source["preprocessing"],
|
| 286 |
+
}))
|
| 287 |
+
source = configs["g2p"]
|
| 288 |
+
write_json(output / "g2p/config.json", companion_config(
|
| 289 |
+
source, "g2p-en-decoder-pytorch", SOURCES["g2p-en-decoder-pytorch"][0],
|
| 290 |
+
"naptrap-g2p-en-decoder-onnx-v1", [("encoder.onnx", output / "g2p/encoder.onnx"),
|
| 291 |
+
("decoder.onnx", output / "g2p/decoder.onnx")], {
|
| 292 |
+
"hidden_size": source["hidden_size"],
|
| 293 |
+
"graphemes": GRAPHEMES,
|
| 294 |
+
"phonemes": source["phonemes"],
|
| 295 |
+
"start_token": 2,
|
| 296 |
+
"end_token": 3,
|
| 297 |
+
"max_decoder_steps": source["max_decoder_steps"],
|
| 298 |
+
"inputs": {
|
| 299 |
+
"encoder": "graphemes [L] int64: a word's grapheme IDs followed by </s> (2)",
|
| 300 |
+
"decoder": "token [1] int64 (start with 2), hidden [1,256] float32",
|
| 301 |
+
},
|
| 302 |
+
"outputs": {
|
| 303 |
+
"encoder": "hidden [1,256]; separator [1,256], the row placed between words",
|
| 304 |
+
"decoder": "next_hidden [1,256], one feature row; logits [1,74], argmax is the next token",
|
| 305 |
+
},
|
| 306 |
+
}))
|
| 307 |
+
return model
|
| 308 |
+
|
| 309 |
+
|
| 310 |
+
class OnnxText:
|
| 311 |
+
"""The Go engine's keyword algorithm, run with ONNX Runtime."""
|
| 312 |
+
|
| 313 |
+
def __init__(self, output):
|
| 314 |
+
self.encoder = onnxruntime.InferenceSession(str(output / "g2p/encoder.onnx"))
|
| 315 |
+
self.decoder = onnxruntime.InferenceSession(str(output / "g2p/decoder.onnx"))
|
| 316 |
+
self.index = {g: i for i, g in enumerate(GRAPHEMES)}
|
| 317 |
+
|
| 318 |
+
def __call__(self, normalized):
|
| 319 |
+
rows = []
|
| 320 |
+
for i, word in enumerate(normalized.split()):
|
| 321 |
+
ids = np.array([self.index.get(c, 1) for c in word] + [2], dtype=np.int64)
|
| 322 |
+
hidden, separator = self.encoder.run(None, {"graphemes": ids})
|
| 323 |
+
if i:
|
| 324 |
+
rows.append(separator)
|
| 325 |
+
token = 2
|
| 326 |
+
for _ in range(20):
|
| 327 |
+
hidden, logits = self.decoder.run(None, {"token": np.array([token], dtype=np.int64),
|
| 328 |
+
"hidden": hidden})
|
| 329 |
+
token = int(logits.argmax())
|
| 330 |
+
if token == 3:
|
| 331 |
+
break
|
| 332 |
+
rows.append(hidden)
|
| 333 |
+
return np.concatenate(rows)
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
def verify(model, output, wav):
|
| 337 |
+
"""Compare every graph with naptrap's PyTorch modules; fail outside tolerance."""
|
| 338 |
+
google_session = onnxruntime.InferenceSession(str(output / "google/model.onnx"))
|
| 339 |
+
pm_session = onnxruntime.InferenceSession(str(output / "phonmatchnet/model.onnx"))
|
| 340 |
+
text = OnnxText(output)
|
| 341 |
+
generator = torch.Generator().manual_seed(7)
|
| 342 |
+
clips = [("said-mister", wav)]
|
| 343 |
+
for n in LENGTHS:
|
| 344 |
+
noise = torch.randn(n, generator=generator) * 0.1
|
| 345 |
+
clips.append((f"noise-{n}", noise.clamp(-1, 1)))
|
| 346 |
+
if n >= wav.numel():
|
| 347 |
+
clips.append((f"said-mister-pad-{n}", F.pad(wav, (0, n - wav.numel()))))
|
| 348 |
+
worst = {"google": 0.0, "text": 0.0, "logit": 0.0}
|
| 349 |
+
keywords = {}
|
| 350 |
+
for keyword in KEYWORDS:
|
| 351 |
+
expected = model.keyword(keyword)
|
| 352 |
+
actual = text(expected.text)
|
| 353 |
+
if actual.shape != tuple(expected.features.shape):
|
| 354 |
+
raise SystemExit(f"text positions differ for {keyword!r}: {actual.shape} vs {tuple(expected.features.shape)}")
|
| 355 |
+
worst["text"] = max(worst["text"], float(np.abs(actual - expected.features.numpy()).max()))
|
| 356 |
+
keywords[keyword] = (expected, actual)
|
| 357 |
+
for name, clip in clips:
|
| 358 |
+
clip = clip.float().contiguous()
|
| 359 |
+
g_ref = model.google_encoder(clip)
|
| 360 |
+
(g_onnx,) = google_session.run(None, {"waveform": clip.numpy()})
|
| 361 |
+
worst["google"] = max(worst["google"], float(np.abs(g_onnx - g_ref.numpy()).max()))
|
| 362 |
+
mel_ref = model._frontend(clip)[0]
|
| 363 |
+
for keyword, (expected, features) in keywords.items():
|
| 364 |
+
ref = model.predict({"keyword_mel": mel_ref, "google": g_ref, "text": expected.features})
|
| 365 |
+
(logit,) = pm_session.run(None, {"waveform": clip.numpy(), "google": g_onnx, "text": features})
|
| 366 |
+
worst["logit"] = max(worst["logit"], abs(float(logit[0]) - ref.details["keyword_logit"]))
|
| 367 |
+
limits = {"google": 1e-3, "text": 1e-5, "logit": 1e-3}
|
| 368 |
+
for key, value in worst.items():
|
| 369 |
+
print(f"max |onnx - torch| {key}: {value:.3g} (limit {limits[key]:g})")
|
| 370 |
+
failed = [key for key, value in worst.items() if value > limits[key]]
|
| 371 |
+
if failed:
|
| 372 |
+
raise SystemExit("ONNX graphs differ from naptrap: " + ", ".join(failed))
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
def main():
|
| 376 |
+
parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
|
| 377 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 378 |
+
parser.add_argument("--cache", type=Path, default=Path(__file__).resolve().parent / ".cache")
|
| 379 |
+
parser.add_argument("--check", action="store_true", help="compare outputs with the committed models/")
|
| 380 |
+
args = parser.parse_args()
|
| 381 |
+
torch.manual_seed(0)
|
| 382 |
+
roots = fetch(args.cache)
|
| 383 |
+
if args.output.exists():
|
| 384 |
+
shutil.rmtree(args.output)
|
| 385 |
+
model = build(roots, args.output)
|
| 386 |
+
from naptrap import load_wav
|
| 387 |
+
verify(model, args.output, load_wav(roots["naptrap-phonmatchnet-en"] / "examples/said-mister.wav"))
|
| 388 |
+
if args.check:
|
| 389 |
+
changed = [name for name in OUTPUTS
|
| 390 |
+
if not (REPO / "models" / name).exists()
|
| 391 |
+
or sha256(args.output / name) != sha256(REPO / "models" / name)]
|
| 392 |
+
if changed:
|
| 393 |
+
raise SystemExit("differs from models/: " + ", ".join(changed))
|
| 394 |
+
print(f"all {len(OUTPUTS)} outputs match models/")
|
| 395 |
+
|
| 396 |
+
|
| 397 |
+
if __name__ == "__main__":
|
| 398 |
+
main()
|
conversion/pyproject.toml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[project]
|
| 2 |
+
name = "go-phonmatchnet-export"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
description = "Convert naptrap's PyTorch PhonMatchNet models to the ONNX graphs go-phonmatchnet embeds"
|
| 5 |
+
requires-python = "==3.12.*"
|
| 6 |
+
dependencies = [
|
| 7 |
+
"naptrap==0.1.0",
|
| 8 |
+
"numpy==2.2.6",
|
| 9 |
+
"onnx==1.17.0",
|
| 10 |
+
"onnxruntime==1.22.1",
|
| 11 |
+
"safetensors==0.5.3",
|
| 12 |
+
"torch==2.6.0+cpu",
|
| 13 |
+
]
|
| 14 |
+
|
| 15 |
+
[tool.uv]
|
| 16 |
+
package = false
|
| 17 |
+
environments = ["sys_platform == 'linux' and platform_machine == 'x86_64'"]
|
| 18 |
+
|
| 19 |
+
[tool.uv.sources]
|
| 20 |
+
torch = { index = "pytorch-cpu" }
|
| 21 |
+
|
| 22 |
+
[[tool.uv.index]]
|
| 23 |
+
name = "pytorch-cpu"
|
| 24 |
+
url = "https://download.pytorch.org/whl/cpu"
|
| 25 |
+
explicit = true
|
conversion/uv.lock
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version = 1
|
| 2 |
+
revision = 3
|
| 3 |
+
requires-python = "==3.12.*"
|
| 4 |
+
resolution-markers = [
|
| 5 |
+
"platform_machine == 'x86_64' and sys_platform == 'linux'",
|
| 6 |
+
]
|
| 7 |
+
supported-markers = [
|
| 8 |
+
"platform_machine == 'x86_64' and sys_platform == 'linux'",
|
| 9 |
+
]
|
| 10 |
+
|
| 11 |
+
[[package]]
|
| 12 |
+
name = "coloredlogs"
|
| 13 |
+
version = "15.0.1"
|
| 14 |
+
source = { registry = "https://pypi.org/simple" }
|
| 15 |
+
dependencies = [
|
| 16 |
+
{ name = "humanfriendly", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 17 |
+
]
|
| 18 |
+
sdist = { url = "https://files.pythonhosted.org/packages/cc/c7/eed8f27100517e8c0e6b923d5f0845d0cb99763da6fdee00478f91db7325/coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0", size = 278520, upload-time = "2021-06-11T10:22:45.202Z" }
|
| 19 |
+
wheels = [
|
| 20 |
+
{ url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018, upload-time = "2021-06-11T10:22:42.561Z" },
|
| 21 |
+
]
|
| 22 |
+
|
| 23 |
+
[[package]]
|
| 24 |
+
name = "filelock"
|
| 25 |
+
version = "4.1.1"
|
| 26 |
+
source = { registry = "https://pypi.org/simple" }
|
| 27 |
+
sdist = { url = "https://files.pythonhosted.org/packages/35/c8/1d457d9150ff948f2ce6ada7715e0eeebbe5d3b58a45271a1e222474bcd3/filelock-4.1.1.tar.gz", hash = "sha256:7ba0927482c5a814b0a7f391d029ccdb8010f576f0a74c0dcde1811e8bc4c1b6", size = 563430, upload-time = "2026-10-11T16:11:54.373Z" }
|
| 28 |
+
wheels = [
|
| 29 |
+
{ url = "https://files.pythonhosted.org/packages/d7/8b/f837f52905395ba4510fe61f753c24833fb0a9c76e21267bb9f828b664a9/filelock-4.1.1-py3-none-any.whl", hash = "sha256:3f4a557945a7b0f95efeb1f432267affe5d45ac8ddde2aed1b97ebb62382c089", size = 132460, upload-time = "2026-10-11T16:11:52.753Z" },
|
| 30 |
+
]
|
| 31 |
+
|
| 32 |
+
[[package]]
|
| 33 |
+
name = "flatbuffers"
|
| 34 |
+
version = "25.12.19"
|
| 35 |
+
source = { registry = "https://pypi.org/simple" }
|
| 36 |
+
wheels = [
|
| 37 |
+
{ url = "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4", size = 26661, upload-time = "2025-12-19T23:16:13.622Z" },
|
| 38 |
+
]
|
| 39 |
+
|
| 40 |
+
[[package]]
|
| 41 |
+
name = "fsspec"
|
| 42 |
+
version = "2026.9.0"
|
| 43 |
+
source = { registry = "https://pypi.org/simple" }
|
| 44 |
+
sdist = { url = "https://files.pythonhosted.org/packages/77/cd/9be253869fc42e764de7f3dedd6969af7d44ff9c3375214a3442a6f3fc08/fsspec-2026.9.0.tar.gz", hash = "sha256:0f08147951c8cb31d844c3547d631053b127863b60be04cf06e121333ee0e2fe", size = 333545, upload-time = "2026-09-18T17:50:42.825Z" }
|
| 45 |
+
wheels = [
|
| 46 |
+
{ url = "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl", hash = "sha256:8dd6e646e99ea382bd85f97a45e6b526a442d79423a7dc673f1e2756d05fcb5f", size = 221738, upload-time = "2026-09-18T17:50:41.341Z" },
|
| 47 |
+
]
|
| 48 |
+
|
| 49 |
+
[[package]]
|
| 50 |
+
name = "go-phonmatchnet-export"
|
| 51 |
+
version = "0.1.0"
|
| 52 |
+
source = { virtual = "." }
|
| 53 |
+
dependencies = [
|
| 54 |
+
{ name = "naptrap", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 55 |
+
{ name = "numpy", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 56 |
+
{ name = "onnx", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 57 |
+
{ name = "onnxruntime", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 58 |
+
{ name = "safetensors", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 59 |
+
{ name = "torch", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 60 |
+
]
|
| 61 |
+
|
| 62 |
+
[package.metadata]
|
| 63 |
+
requires-dist = [
|
| 64 |
+
{ name = "naptrap", specifier = "==0.1.0" },
|
| 65 |
+
{ name = "numpy", specifier = "==2.2.6" },
|
| 66 |
+
{ name = "onnx", specifier = "==1.17.0" },
|
| 67 |
+
{ name = "onnxruntime", specifier = "==1.22.1" },
|
| 68 |
+
{ name = "safetensors", specifier = "==0.5.3" },
|
| 69 |
+
{ name = "torch", specifier = "==2.6.0+cpu", index = "https://download.pytorch.org/whl/cpu" },
|
| 70 |
+
]
|
| 71 |
+
|
| 72 |
+
[[package]]
|
| 73 |
+
name = "humanfriendly"
|
| 74 |
+
version = "10.0"
|
| 75 |
+
source = { registry = "https://pypi.org/simple" }
|
| 76 |
+
sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702, upload-time = "2021-09-17T21:40:43.31Z" }
|
| 77 |
+
wheels = [
|
| 78 |
+
{ url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794, upload-time = "2021-09-17T21:40:39.897Z" },
|
| 79 |
+
]
|
| 80 |
+
|
| 81 |
+
[[package]]
|
| 82 |
+
name = "jinja2"
|
| 83 |
+
version = "3.1.6"
|
| 84 |
+
source = { registry = "https://pypi.org/simple" }
|
| 85 |
+
dependencies = [
|
| 86 |
+
{ name = "markupsafe", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 87 |
+
]
|
| 88 |
+
sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
|
| 89 |
+
wheels = [
|
| 90 |
+
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
|
| 91 |
+
]
|
| 92 |
+
|
| 93 |
+
[[package]]
|
| 94 |
+
name = "markupsafe"
|
| 95 |
+
version = "3.0.4"
|
| 96 |
+
source = { registry = "https://pypi.org/simple" }
|
| 97 |
+
sdist = { url = "https://files.pythonhosted.org/packages/38/9b/e422a865e1d5d57d0e509b4e0bf1c1a70a7f6382c29a5aa428df994c8bc8/markupsafe-3.0.4.tar.gz", hash = "sha256:2e9ad7dd851bf45fab9f75cbff4cb493fee9979e8d8c7c9c3ee119022518edd6", size = 153777, upload-time = "2026-10-02T23:07:22.29Z" }
|
| 98 |
+
wheels = [
|
| 99 |
+
{ url = "https://files.pythonhosted.org/packages/4f/a7/aeedb5140afa41fc74c225e9184ab96723a6e873b6ee1c9fede7283456d8/markupsafe-3.0.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e124f974786f831d6043728e38296969d3579db8896fe004682f5758e613581", size = 22985, upload-time = "2026-10-02T23:04:57.521Z" },
|
| 100 |
+
{ url = "https://files.pythonhosted.org/packages/0c/fe/fb1e79be0fea60aa32602ebefc9c35a82bb42b4df157285ab7dfec12341a/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9a7f43c0b202b334cc9184af09bb8f21d3a209e038efaf106936fb69e6b026e", size = 23048, upload-time = "2026-10-02T23:05:04.479Z" },
|
| 101 |
+
]
|
| 102 |
+
|
| 103 |
+
[[package]]
|
| 104 |
+
name = "mpmath"
|
| 105 |
+
version = "1.3.0"
|
| 106 |
+
source = { registry = "https://pypi.org/simple" }
|
| 107 |
+
sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" }
|
| 108 |
+
wheels = [
|
| 109 |
+
{ url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" },
|
| 110 |
+
]
|
| 111 |
+
|
| 112 |
+
[[package]]
|
| 113 |
+
name = "naptrap"
|
| 114 |
+
version = "0.1.0"
|
| 115 |
+
source = { registry = "https://pypi.org/simple" }
|
| 116 |
+
dependencies = [
|
| 117 |
+
{ name = "safetensors", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 118 |
+
{ name = "torch", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 119 |
+
]
|
| 120 |
+
sdist = { url = "https://files.pythonhosted.org/packages/73/02/f32e8515c47f30688f191f35e594b74d1a70e176de57addddff950f73f3b/naptrap-0.1.0.tar.gz", hash = "sha256:d458c0999441710ea3d67622f7ef3c782c75a07624d44ecaacedfb93685ccb6d", size = 28457, upload-time = "2026-10-12T13:40:05.714Z" }
|
| 121 |
+
wheels = [
|
| 122 |
+
{ url = "https://files.pythonhosted.org/packages/d3/70/7c0d678b0e60eaad6712685172a4b943a1d37ba50b2e6bcc39de870329aa/naptrap-0.1.0-py3-none-any.whl", hash = "sha256:8dc2a77ff212a40d7fe4b57bb79961870c16a3b123571a87c346ca96cfc63e52", size = 25185, upload-time = "2026-10-12T13:40:04.606Z" },
|
| 123 |
+
]
|
| 124 |
+
|
| 125 |
+
[[package]]
|
| 126 |
+
name = "networkx"
|
| 127 |
+
version = "3.7"
|
| 128 |
+
source = { registry = "https://pypi.org/simple" }
|
| 129 |
+
sdist = { url = "https://files.pythonhosted.org/packages/dc/76/3af777226b63a5e64a6b36b1ec5855c14e2b94a37096d4760e595fc43511/networkx-3.7.tar.gz", hash = "sha256:fd77a511bd90f39f3d016351345b52cf5319b813bdca01de3f755d3cca62e96a", size = 1866482, upload-time = "2026-09-21T16:45:16.974Z" }
|
| 130 |
+
wheels = [
|
| 131 |
+
{ url = "https://files.pythonhosted.org/packages/7e/cd/fe58041e9011f307c490e3e17dd48cc516448f7c698a3f2d9d9d65d7e6a8/networkx-3.7-py3-none-any.whl", hash = "sha256:e3fd2c13a7814cee3746340d8d7f8598a67f16a58bf47fb7f8793fab6efca1b0", size = 2142205, upload-time = "2026-09-21T16:45:14.609Z" },
|
| 132 |
+
]
|
| 133 |
+
|
| 134 |
+
[[package]]
|
| 135 |
+
name = "numpy"
|
| 136 |
+
version = "2.2.6"
|
| 137 |
+
source = { registry = "https://pypi.org/simple" }
|
| 138 |
+
sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" }
|
| 139 |
+
wheels = [
|
| 140 |
+
{ url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" },
|
| 141 |
+
{ url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" },
|
| 142 |
+
]
|
| 143 |
+
|
| 144 |
+
[[package]]
|
| 145 |
+
name = "onnx"
|
| 146 |
+
version = "1.17.0"
|
| 147 |
+
source = { registry = "https://pypi.org/simple" }
|
| 148 |
+
dependencies = [
|
| 149 |
+
{ name = "numpy", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 150 |
+
{ name = "protobuf", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 151 |
+
]
|
| 152 |
+
sdist = { url = "https://files.pythonhosted.org/packages/9a/54/0e385c26bf230d223810a9c7d06628d954008a5e5e4b73ee26ef02327282/onnx-1.17.0.tar.gz", hash = "sha256:48ca1a91ff73c1d5e3ea2eef20ae5d0e709bb8a2355ed798ffc2169753013fd3", size = 12165120, upload-time = "2024-10-01T21:48:40.63Z" }
|
| 153 |
+
wheels = [
|
| 154 |
+
{ url = "https://files.pythonhosted.org/packages/3d/7c/67f4952d1b56b3f74a154b97d0dd0630d525923b354db117d04823b8b49b/onnx-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f3fb5cc4e2898ac5312a7dc03a65133dd2abf9a5e520e69afb880a7251ec97a", size = 16046307, upload-time = "2024-10-01T21:46:21.186Z" },
|
| 155 |
+
]
|
| 156 |
+
|
| 157 |
+
[[package]]
|
| 158 |
+
name = "onnxruntime"
|
| 159 |
+
version = "1.22.1"
|
| 160 |
+
source = { registry = "https://pypi.org/simple" }
|
| 161 |
+
dependencies = [
|
| 162 |
+
{ name = "coloredlogs", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 163 |
+
{ name = "flatbuffers", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 164 |
+
{ name = "numpy", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 165 |
+
{ name = "packaging", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 166 |
+
{ name = "protobuf", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 167 |
+
{ name = "sympy", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 168 |
+
]
|
| 169 |
+
wheels = [
|
| 170 |
+
{ url = "https://files.pythonhosted.org/packages/0a/50/519828a5292a6ccd8d5cd6d2f72c6b36ea528a2ef68eca69647732539ffa/onnxruntime-1.22.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2d39a530aff1ec8d02e365f35e503193991417788641b184f5b1e8c9a6d5ce8d", size = 16475713, upload-time = "2025-07-10T19:15:45.452Z" },
|
| 171 |
+
]
|
| 172 |
+
|
| 173 |
+
[[package]]
|
| 174 |
+
name = "packaging"
|
| 175 |
+
version = "26.3"
|
| 176 |
+
source = { registry = "https://pypi.org/simple" }
|
| 177 |
+
sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" }
|
| 178 |
+
wheels = [
|
| 179 |
+
{ url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" },
|
| 180 |
+
]
|
| 181 |
+
|
| 182 |
+
[[package]]
|
| 183 |
+
name = "protobuf"
|
| 184 |
+
version = "7.36.2"
|
| 185 |
+
source = { registry = "https://pypi.org/simple" }
|
| 186 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d9/89/5b8517baa72f84a67b8a307ba953c91057af618bf40bf676f3c03551f8f0/protobuf-7.36.2.tar.gz", hash = "sha256:497d0463ff3316681da6c0b9e8d06cb465d61abce00b613ab42226175644d1bb", size = 512737, upload-time = "2026-09-17T20:07:59.326Z" }
|
| 187 |
+
wheels = [
|
| 188 |
+
{ url = "https://files.pythonhosted.org/packages/db/f3/3996583dd2906297a637af12114deddf7658af6e683fedb83be061983fb5/protobuf-7.36.2-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:89f23aa53c24553a2416fd4fd1ec06f74fa42b14b546d8883128813f775bbfd2", size = 343223, upload-time = "2026-09-17T20:07:54.931Z" },
|
| 189 |
+
{ url = "https://files.pythonhosted.org/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl", hash = "sha256:bdb3a345d48db958e6ce1f18e508beb0cc981d64f24088427549c866cd039f1e", size = 179806, upload-time = "2026-09-17T20:07:58.211Z" },
|
| 190 |
+
]
|
| 191 |
+
|
| 192 |
+
[[package]]
|
| 193 |
+
name = "safetensors"
|
| 194 |
+
version = "0.5.3"
|
| 195 |
+
source = { registry = "https://pypi.org/simple" }
|
| 196 |
+
sdist = { url = "https://files.pythonhosted.org/packages/71/7e/2d5d6ee7b40c0682315367ec7475693d110f512922d582fef1bd4a63adc3/safetensors-0.5.3.tar.gz", hash = "sha256:b6b0d6ecacec39a4fdd99cc19f4576f5219ce858e6fd8dbe7609df0b8dc56965", size = 67210, upload-time = "2025-02-26T09:15:13.155Z" }
|
| 197 |
+
wheels = [
|
| 198 |
+
{ url = "https://files.pythonhosted.org/packages/a6/f8/dae3421624fcc87a89d42e1898a798bc7ff72c61f38973a65d60df8f124c/safetensors-0.5.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cead1fa41fc54b1e61089fa57452e8834f798cb1dc7a09ba3524f1eb08e0317a", size = 471642, upload-time = "2025-02-26T09:15:00.544Z" },
|
| 199 |
+
{ url = "https://files.pythonhosted.org/packages/40/ad/2b113098e69c985a3d8fbda4b902778eae4a35b7d5188859b4a63d30c161/safetensors-0.5.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:37f1521be045e56fc2b54c606d4455573e717b2d887c579ee1dbba5f868ece04", size = 643147, upload-time = "2025-02-26T09:15:11.185Z" },
|
| 200 |
+
]
|
| 201 |
+
|
| 202 |
+
[[package]]
|
| 203 |
+
name = "setuptools"
|
| 204 |
+
version = "84.0.0"
|
| 205 |
+
source = { registry = "https://pypi.org/simple" }
|
| 206 |
+
sdist = { url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz", hash = "sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73", size = 1168449, upload-time = "2026-08-08T18:27:58.365Z" }
|
| 207 |
+
wheels = [
|
| 208 |
+
{ url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl", hash = "sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670", size = 818216, upload-time = "2026-08-08T18:27:56.719Z" },
|
| 209 |
+
]
|
| 210 |
+
|
| 211 |
+
[[package]]
|
| 212 |
+
name = "sympy"
|
| 213 |
+
version = "1.13.1"
|
| 214 |
+
source = { registry = "https://pypi.org/simple" }
|
| 215 |
+
dependencies = [
|
| 216 |
+
{ name = "mpmath", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 217 |
+
]
|
| 218 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ca/99/5a5b6f19ff9f083671ddf7b9632028436167cd3d33e11015754e41b249a4/sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f", size = 7533040, upload-time = "2024-07-19T09:26:51.238Z" }
|
| 219 |
+
wheels = [
|
| 220 |
+
{ url = "https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8", size = 6189177, upload-time = "2024-07-19T09:26:48.863Z" },
|
| 221 |
+
]
|
| 222 |
+
|
| 223 |
+
[[package]]
|
| 224 |
+
name = "torch"
|
| 225 |
+
version = "2.6.0+cpu"
|
| 226 |
+
source = { registry = "https://download.pytorch.org/whl/cpu" }
|
| 227 |
+
dependencies = [
|
| 228 |
+
{ name = "filelock", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 229 |
+
{ name = "fsspec", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 230 |
+
{ name = "jinja2", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 231 |
+
{ name = "networkx", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 232 |
+
{ name = "setuptools", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 233 |
+
{ name = "sympy", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 234 |
+
{ name = "typing-extensions", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 235 |
+
]
|
| 236 |
+
wheels = [
|
| 237 |
+
{ url = "https://download-r2.pytorch.org/whl/cpu/torch-2.6.0%2Bcpu-cp312-cp312-linux_x86_64.whl", hash = "sha256:59e78aa0c690f70734e42670036d6b541930b8eabbaa18d94e090abf14cc4d91", upload-time = "2025-01-30T00:38:31Z" },
|
| 238 |
+
]
|
| 239 |
+
|
| 240 |
+
[[package]]
|
| 241 |
+
name = "typing-extensions"
|
| 242 |
+
version = "4.16.0"
|
| 243 |
+
source = { registry = "https://pypi.org/simple" }
|
| 244 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" }
|
| 245 |
+
wheels = [
|
| 246 |
+
{ url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" },
|
| 247 |
+
]
|
decoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:86953a2604f3494bf44c4d81df67c444455b4a9f0cf6f08d62fab08393bd29e1
|
| 3 |
+
size 1736403
|
encoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c492a8907a8b62d7f1e311c0df469490a4e4670865a6a5d8b4b7749a38666091
|
| 3 |
+
size 1611543
|