File size: 7,504 Bytes
985a719
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ce88315
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
985a719
 
 
 
 
ce88315
985a719
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
---
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.