| --- |
| license: cc-by-4.0 |
| library_name: gguf |
| tags: |
| - guitar |
| - tablature |
| - music-information-retrieval |
| - audio-to-tab |
| - crispasr |
| - gguf |
| pipeline_tag: audio-classification |
| --- |
| |
| # TabCNN β guitar tablature emission scorer (GGUF) |
|
|
| GGUF conversion of **TabCNN** for [CrispASR](https://github.com/CrispStrobe/CrispASR)'s |
| `--tab` surface. 833,982 parameters. |
|
|
| Per frame, the model emits **six independent distributions over 21 fret classes** |
| β one per guitar string. It contains no decoder: no inter-string coupling, no |
| temporal model, no search. |
|
|
| > β οΈ **These are emission SCORES, not a decided tablature.** Turning them into a |
| > playable fingering needs a constrained decoder (one note per string, fret |
| > range, capo, hand span). Taking the argmax of this grid ignores every |
| > playability constraint. CrispASR ships the scorer and leaves the decoder to |
| > the caller. |
|
|
| ## Provenance and licence β verifiable, not asserted |
|
|
| **Source artifact** (fetch it and check the hashes yourself): |
|
|
| | | | |
| |---|---| |
| | file | `best_TabCNN_tablature_trancription_model` (sic β typo is upstream's) | |
| | direct URL | <https://zenodo.org/records/11406378/files/best_TabCNN_tablature_trancription_model?download=1> | |
| | record | <https://zenodo.org/records/11406378> | |
| | size | 3,345,122 bytes | |
| | md5 (upstream, from the Zenodo API) | `ce168b2cd426f81a2a78499214e40605` | |
| | sha256 (computed on the bytes converted) | `1470a308896629352a811082843eb708cbc2f1aa3092757340055ef76a53ed0c` | |
|
|
| Every GGUF here carries these as metadata (`general.source.url`, |
| `general.source.record_url`, `general.source.md5_upstream`, |
| `general.source.sha256`), so provenance travels with the artifact. |
|
|
| β οΈ **There is no Zenodo DOI for this record.** `10.5281/zenodo.11406378` looks |
| plausible and **404s** β it does not exist. The record's actual DOI is the arXiv |
| one, `10.48550/arXiv.2405.14679` (resolves). Cite what resolves. |
|
|
| **Licence evidence.** The Zenodo API reports, for record 11406378: |
|
|
| ```json |
| "metadata": { "license": {"id": "cc-by-4.0"}, "access_right": "open" } |
| ``` |
|
|
| Zenodo has no per-file licensing (a file object exposes only `checksum`, `id`, |
| `key`, `links`, `size`), so the record licence governs every deposited file. And |
| the record description states explicitly that the weights are part of the |
| deposit: |
|
|
| > "The weights for the best performing model (TabCNN trained with |
| > \"GuitarProFX\") in the paper are also provided." |
|
|
| That sentence is also what confirms this is the **GuitarProFX-augmented** |
| variant rather than the baseline β the distinction that matters, since the |
| baseline collapses from tablature F1 0.748 to 0.447 on real electric guitar |
| while the augmented one recovers to 0.585 (DAFx-24). |
|
|
| **Required citation** (the record asks for this explicitly): |
|
|
| > Pedroza HE, Abreu W, Corey R, Roman IR. "Leveraging real electric guitar tones |
| > and effects to improve robustness in guitar tablature transcription modeling." |
| > In *27th International Conference on Digital Audio Effects (DAFx)*, 2024. |
|
|
| **Upstream chain:** |
|
|
| | | | |
| |---|---| |
| | **Model** | TabCNN β Wiggins & Kim, *Guitar Tablature Estimation with a Convolutional Neural Network*, ISMIR 2019 | |
| | **Reference implementation** | [`amt-tools`](https://github.com/cwitkowitz/amt-tools) (Cwitkowitz) β MIT | |
| | **Training corpus** | [GuitarSet](https://zenodo.org/records/3371780) β CC BY 4.0 | |
|
|
| ## Files |
|
|
| | file | size | tablature F1 | vs f32 | notes | |
| |---|---|---|---|---| |
| | `tabcnn-f16.gguf` | 1.78 MB | 0.7732 | **0.0000** | **default** β lossless, 100 % argmax agreement | |
| | `tabcnn-q8_0.gguf` | 1.10 MB | 0.7749 | +0.0017 | `dense0` q8_0, `head` f32 | |
| | `tabcnn-q4_k.gguf` | 0.72 MB | 0.7749 | +0.0017 | `dense0` Q4_0, `head` f32 β smallest, no measurable loss | |
| | `tabcnn-f32.gguf` | 3.34 MB | 0.7732 | β | full precision, for parity work | |
|
|
| (F1 on EGSet12 track 01 against its JAMS ground truth; the +0.0017 is noise on a |
| single 10 s clip β read it as "no loss", not "better".) |
|
|
| ### The output layer must stay at full precision |
|
|
| Only **two** tensors are quantizable at all: the conv stack is 3Γ3, so `ne0=3`, |
| far below any block size, and the biases are 32β126 wide. `dense0.weight` |
| (761 k of 834 k params) is effectively the whole model. |
|
|
| Quantizing `dense0` costs nothing β but quantizing `head.weight` alongside it is |
| catastrophic: |
|
|
| | | head quantized | head preserved | |
| |---|---|---| |
| | q8_0 | 0.7676 (β0.0057) | 0.7749 | |
| | Q4_0 | **0.7153 (β0.0579)** | 0.7749 | |
|
|
| `head.weight` is 16 k params, 1.6 % of the file, and directly determines the |
| 21-way per-string softmax. Preserving it makes Q4_0 as accurate as q8_0. |
| `crispasr-quantize` encodes this as an arch rule; anyone converting these |
| weights by another route should do the same. |
|
|
| β οΈ **`q4_k` here is really Q4_0.** No tensor has `ne0 % 256 == 0` |
| (`dense0.weight` is 5952; 5952 % 256 = 64), so k-quants cannot apply and the |
| quantizer falls back to Q4_0. The filename keeps the requested name; the content |
| is Q4_0. |
|
|
| ## Front end β read it from the file, do not assume it |
|
|
| ``` |
| CQT: sr 22050, hop 512, 192 bins, 24 per octave, fmin C1 (32.70 Hz) |
| -> amplitude_to_db(ref = max of the WHOLE clip) -> [-80, 0] |
| -> /80 + 1 -> [0, 1] |
| -> 9-frame centred context window |
| ``` |
|
|
| β οΈ **`fmin` is C1, not the guitar's low E.** Assuming E2 is the obvious guess and |
| it is wrong β and every wrong value still *runs*, producing plausible tensors |
| that pass shape and cosine checks while the model emits garbage. Measured on |
| EGSet12 track 01: fmin C1 β tablature **F1 0.771**, E1 β 0.040, E2 at 44.1 kHz β |
| **0.001**. All of these constants are stored as GGUF metadata |
| (`tabcnn.sample_rate`, `tabcnn.fmin_hz`, β¦) precisely so a consumer never has to |
| guess. |
|
|
| β οΈ `ref = max of the whole clip` is a **per-clip normalisation**, so features |
| cannot be computed streaming or chunked without changing them. This model is |
| two-pass by construction. |
|
|
| ## Usage |
|
|
| ```bash |
| crispasr --tab -m tabcnn-f16.gguf -f guitar.wav |
| crispasr --tab -m tabcnn-f16.gguf -f guitar.wav --tab-format json |
| ``` |
|
|
| For real use, take the log-probabilities through the C ABI |
| (`crispasr_session_tab` β `crispasr_session_tab_emissions`) and run your own |
| constrained decoder. `crispasr_session_tab_silent_class()` tells you which class |
| means "not played" β read it rather than assuming it is the highest index. |
|
|
| ## Validation |
|
|
| `crispasr-diff tabcnn` against a reference dump from the `amt-tools` model, run |
| from the **waveform** (not replayed features, so the CQT is covered): |
|
|
| | stage | cos | |
| |---|---| |
| | `cqt_db` | 0.998925 | |
| | `conv0_relu` | 0.991401 | |
| | `conv1_relu` | 0.987366 | |
| | `conv2_relu` | 0.972109 | |
| | `pool` | 0.975496 | |
| | `dense0_relu` | 0.991824 | |
| | `logits` | 0.999661 | |
|
|
| End to end on EGSet12 track 01 against its JAMS ground truth: |
|
|
| | | P | R | F1 | |
| |---|---|---|---| |
| | torch reference | 0.7183 | 0.8315 | 0.7708 | |
| | CrispASR (this GGUF) | 0.7179 | 0.8378 | **0.7732** | |
|
|
| ΞF1 **+0.0024**, argmax agreement **98.57 %**. The residual difference is the |
| front end β CrispASR uses direct Brown-kernel CQT against librosa's recursive |
| downsampling β and it costs nothing on the task metric. |
|
|
| ## Limitations |
|
|
| - Trained on solo guitar. Mixed music is out of domain. |
| - GuitarSet numbers overstate real-world performance; EGSet12 is the honest |
| reference point. |
| - The scorer is per-frame and per-string independent, so it can emit physically |
| impossible combinations. That is expected β the decoder is where playability |
| is enforced. |
|
|