mlboydaisuke commited on
Commit
a224538
·
verified ·
1 Parent(s): 5ea4789

Add PANNs CNN14 AudioSet tagging (fp16 CNN body + host log-mel assets)

Browse files
Files changed (5) hide show
  1. README.md +60 -0
  2. audioset_labels.txt +527 -0
  3. build_panns.py +139 -0
  4. cnn14_audioset_fp16.tflite +3 -0
  5. mel_basis.bin +3 -0
README.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: cc-by-4.0
3
+ library_name: LiteRT
4
+ pipeline_tag: audio-classification
5
+ tags: [litert, tflite, on-device, android, gpu, audio-tagging, audioset, sound-event-detection, panns, cnn14, fully-gpu]
6
+ ---
7
+
8
+ # PANNs CNN14 — LiteRT (on-device AudioSet tagging, GPU CNN + host log-mel)
9
+
10
+ [PANNs](https://github.com/qiuqiangkong/audioset_tagging_cnn) **CNN14** (`Cnn14_mAP=0.431`) general sound-event tagging, converted to **LiteRT** with the CNN body running **fully on the `CompiledModel` GPU** (ML Drift) on Android. Given ~10 s of audio it predicts probabilities over the **527 [AudioSet](https://research.google.com/audioset/) classes** — speech, music, instruments, animals, vehicles, alarms, household sounds, and so on. AudioSet tagging is **multi-label**: several tags can be high at once.
11
+
12
+ ```
13
+ waveform[320000] (32 kHz) →[host: log-mel]→ logmel[1,1,1001,64] →[GPU: CNN14]→ probs[1,527] (sigmoid)
14
+ ```
15
+
16
+ ## On-device (Pixel 8a, Tensor G3 — verified)
17
+
18
+ | | |
19
+ |---|---|
20
+ | nodes on GPU | **45 / 45** LITERT_CL (full residency, single graph, 1 partition) |
21
+ | inference | **~124 ms** GPU + ~99 ms host log-mel ≈ **0.22 s** per 10 s clip |
22
+ | size | 162 MB (fp16) |
23
+ | accuracy | fp16 tflite-vs-PyTorch corr **1.000000**; self-test top tag "Speech" |
24
+
25
+ ## How it converts (litert-torch) — and why the log-mel is host-side
26
+
27
+ PANNs builds its spectrogram with **torchlibrosa**, whose STFT is a *DFT-as-Conv1d* — so there is **no FFT op** and the whole raw-audio→tags graph is almost GPU-clean; the only blocker is the STFT centering **reflect-pad** (one `GATHER_ND`, removable via `pad_mode='constant'`, corr 1.0). **But** the converted spectral front-end is unusable: litert-torch lowers the giant 1024-tap DFT-conv incorrectly (fp32 tflite corr ≈ 0.19), and the power spectrum `|STFT|²` (~1e6) **overflows fp16 on Mali → NaN**.
28
+
29
+ So the spectral front-end is computed on the **CPU** (the Whisper/Kokoro pattern), matched to torchlibrosa exactly, and only the CNN body rides the GPU:
30
+
31
+ - **log-mel (host)** — reflect-pad center, periodic Hann, 1024-pt FFT, power, mel matmul (`librosa.filters.mel`, slaney), `10·log10(max(mel,1e-10))`. Validated host-vs-torch corr **1.000000** (max|d| 0.0017). The mel basis is shipped here as `mel_basis.bin` [64, 513].
32
+ - **CNN14 body (GPU)** — `bn0` + 6 conv blocks + mean/max time-pool + 2 FC + sigmoid. Pure CNN, converts at corr **1.000000** in fp32 **and** fp16, op-check banned NONE / >4D 0, one delegatable graph.
33
+
34
+ ## Files
35
+
36
+ | File | What |
37
+ | ---- | ---- |
38
+ | `cnn14_audioset_fp16.tflite` | the CNN body, fp16, input logmel [1,1,1001,64] → probs [1,527] |
39
+ | `mel_basis.bin` | mel filterbank [64, 513] float32 for the host log-mel |
40
+ | `audioset_labels.txt` | the 527 AudioSet class display names (row index = class id) |
41
+ | `build_panns.py` | conversion + host-mel validation script |
42
+
43
+ ## Preprocessing
44
+
45
+ Mono **32 kHz**, padded/truncated to 10 s (320000 samples), values in [-1, 1]. Compute the log-mel as above → [1,1,1001,64]. The output 527 sigmoid probabilities are per-class (multi-label); take the top-K as tags.
46
+
47
+ ## License
48
+
49
+ Code [Apache-2.0](https://github.com/qiuqiangkong/audioset_tagging_cnn/blob/master/LICENSE); weights `Cnn14_mAP=0.431.pth` [CC-BY-4.0](https://zenodo.org/record/3987831) (Zenodo). AudioSet ontology © Google, [CC-BY-4.0](https://research.google.com/audioset/). Upstream: [qiuqiangkong/audioset_tagging_cnn](https://github.com/qiuqiangkong/audioset_tagging_cnn).
50
+
51
+ ## Citation
52
+
53
+ ```bibtex
54
+ @article{kong2020panns,
55
+ title={PANNs: Large-Scale Pretrained Audio Neural Networks for Audio Pattern Recognition},
56
+ author={Kong, Qiuqiang and Cao, Yin and Iqbal, Turab and Wang, Yuxuan and Wang, Wenwu and Plumbley, Mark D},
57
+ journal={IEEE/ACM Transactions on Audio, Speech, and Language Processing},
58
+ year={2020}
59
+ }
60
+ ```
audioset_labels.txt ADDED
@@ -0,0 +1,527 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Speech
2
+ Male speech, man speaking
3
+ Female speech, woman speaking
4
+ Child speech, kid speaking
5
+ Conversation
6
+ Narration, monologue
7
+ Babbling
8
+ Speech synthesizer
9
+ Shout
10
+ Bellow
11
+ Whoop
12
+ Yell
13
+ Battle cry
14
+ Children shouting
15
+ Screaming
16
+ Whispering
17
+ Laughter
18
+ Baby laughter
19
+ Giggle
20
+ Snicker
21
+ Belly laugh
22
+ Chuckle, chortle
23
+ Crying, sobbing
24
+ Baby cry, infant cry
25
+ Whimper
26
+ Wail, moan
27
+ Sigh
28
+ Singing
29
+ Choir
30
+ Yodeling
31
+ Chant
32
+ Mantra
33
+ Male singing
34
+ Female singing
35
+ Child singing
36
+ Synthetic singing
37
+ Rapping
38
+ Humming
39
+ Groan
40
+ Grunt
41
+ Whistling
42
+ Breathing
43
+ Wheeze
44
+ Snoring
45
+ Gasp
46
+ Pant
47
+ Snort
48
+ Cough
49
+ Throat clearing
50
+ Sneeze
51
+ Sniff
52
+ Run
53
+ Shuffle
54
+ Walk, footsteps
55
+ Chewing, mastication
56
+ Biting
57
+ Gargling
58
+ Stomach rumble
59
+ Burping, eructation
60
+ Hiccup
61
+ Fart
62
+ Hands
63
+ Finger snapping
64
+ Clapping
65
+ Heart sounds, heartbeat
66
+ Heart murmur
67
+ Cheering
68
+ Applause
69
+ Chatter
70
+ Crowd
71
+ Hubbub, speech noise, speech babble
72
+ Children playing
73
+ Animal
74
+ Domestic animals, pets
75
+ Dog
76
+ Bark
77
+ Yip
78
+ Howl
79
+ Bow-wow
80
+ Growling
81
+ Whimper (dog)
82
+ Cat
83
+ Purr
84
+ Meow
85
+ Hiss
86
+ Caterwaul
87
+ Livestock, farm animals, working animals
88
+ Horse
89
+ Clip-clop
90
+ Neigh, whinny
91
+ Cattle, bovinae
92
+ Moo
93
+ Cowbell
94
+ Pig
95
+ Oink
96
+ Goat
97
+ Bleat
98
+ Sheep
99
+ Fowl
100
+ Chicken, rooster
101
+ Cluck
102
+ Crowing, cock-a-doodle-doo
103
+ Turkey
104
+ Gobble
105
+ Duck
106
+ Quack
107
+ Goose
108
+ Honk
109
+ Wild animals
110
+ Roaring cats (lions, tigers)
111
+ Roar
112
+ Bird
113
+ Bird vocalization, bird call, bird song
114
+ Chirp, tweet
115
+ Squawk
116
+ Pigeon, dove
117
+ Coo
118
+ Crow
119
+ Caw
120
+ Owl
121
+ Hoot
122
+ Bird flight, flapping wings
123
+ Canidae, dogs, wolves
124
+ Rodents, rats, mice
125
+ Mouse
126
+ Patter
127
+ Insect
128
+ Cricket
129
+ Mosquito
130
+ Fly, housefly
131
+ Buzz
132
+ Bee, wasp, etc.
133
+ Frog
134
+ Croak
135
+ Snake
136
+ Rattle
137
+ Whale vocalization
138
+ Music
139
+ Musical instrument
140
+ Plucked string instrument
141
+ Guitar
142
+ Electric guitar
143
+ Bass guitar
144
+ Acoustic guitar
145
+ Steel guitar, slide guitar
146
+ Tapping (guitar technique)
147
+ Strum
148
+ Banjo
149
+ Sitar
150
+ Mandolin
151
+ Zither
152
+ Ukulele
153
+ Keyboard (musical)
154
+ Piano
155
+ Electric piano
156
+ Organ
157
+ Electronic organ
158
+ Hammond organ
159
+ Synthesizer
160
+ Sampler
161
+ Harpsichord
162
+ Percussion
163
+ Drum kit
164
+ Drum machine
165
+ Drum
166
+ Snare drum
167
+ Rimshot
168
+ Drum roll
169
+ Bass drum
170
+ Timpani
171
+ Tabla
172
+ Cymbal
173
+ Hi-hat
174
+ Wood block
175
+ Tambourine
176
+ Rattle (instrument)
177
+ Maraca
178
+ Gong
179
+ Tubular bells
180
+ Mallet percussion
181
+ Marimba, xylophone
182
+ Glockenspiel
183
+ Vibraphone
184
+ Steelpan
185
+ Orchestra
186
+ Brass instrument
187
+ French horn
188
+ Trumpet
189
+ Trombone
190
+ Bowed string instrument
191
+ String section
192
+ Violin, fiddle
193
+ Pizzicato
194
+ Cello
195
+ Double bass
196
+ Wind instrument, woodwind instrument
197
+ Flute
198
+ Saxophone
199
+ Clarinet
200
+ Harp
201
+ Bell
202
+ Church bell
203
+ Jingle bell
204
+ Bicycle bell
205
+ Tuning fork
206
+ Chime
207
+ Wind chime
208
+ Change ringing (campanology)
209
+ Harmonica
210
+ Accordion
211
+ Bagpipes
212
+ Didgeridoo
213
+ Shofar
214
+ Theremin
215
+ Singing bowl
216
+ Scratching (performance technique)
217
+ Pop music
218
+ Hip hop music
219
+ Beatboxing
220
+ Rock music
221
+ Heavy metal
222
+ Punk rock
223
+ Grunge
224
+ Progressive rock
225
+ Rock and roll
226
+ Psychedelic rock
227
+ Rhythm and blues
228
+ Soul music
229
+ Reggae
230
+ Country
231
+ Swing music
232
+ Bluegrass
233
+ Funk
234
+ Folk music
235
+ Middle Eastern music
236
+ Jazz
237
+ Disco
238
+ Classical music
239
+ Opera
240
+ Electronic music
241
+ House music
242
+ Techno
243
+ Dubstep
244
+ Drum and bass
245
+ Electronica
246
+ Electronic dance music
247
+ Ambient music
248
+ Trance music
249
+ Music of Latin America
250
+ Salsa music
251
+ Flamenco
252
+ Blues
253
+ Music for children
254
+ New-age music
255
+ Vocal music
256
+ A capella
257
+ Music of Africa
258
+ Afrobeat
259
+ Christian music
260
+ Gospel music
261
+ Music of Asia
262
+ Carnatic music
263
+ Music of Bollywood
264
+ Ska
265
+ Traditional music
266
+ Independent music
267
+ Song
268
+ Background music
269
+ Theme music
270
+ Jingle (music)
271
+ Soundtrack music
272
+ Lullaby
273
+ Video game music
274
+ Christmas music
275
+ Dance music
276
+ Wedding music
277
+ Happy music
278
+ Funny music
279
+ Sad music
280
+ Tender music
281
+ Exciting music
282
+ Angry music
283
+ Scary music
284
+ Wind
285
+ Rustling leaves
286
+ Wind noise (microphone)
287
+ Thunderstorm
288
+ Thunder
289
+ Water
290
+ Rain
291
+ Raindrop
292
+ Rain on surface
293
+ Stream
294
+ Waterfall
295
+ Ocean
296
+ Waves, surf
297
+ Steam
298
+ Gurgling
299
+ Fire
300
+ Crackle
301
+ Vehicle
302
+ Boat, Water vehicle
303
+ Sailboat, sailing ship
304
+ Rowboat, canoe, kayak
305
+ Motorboat, speedboat
306
+ Ship
307
+ Motor vehicle (road)
308
+ Car
309
+ Vehicle horn, car horn, honking
310
+ Toot
311
+ Car alarm
312
+ Power windows, electric windows
313
+ Skidding
314
+ Tire squeal
315
+ Car passing by
316
+ Race car, auto racing
317
+ Truck
318
+ Air brake
319
+ Air horn, truck horn
320
+ Reversing beeps
321
+ Ice cream truck, ice cream van
322
+ Bus
323
+ Emergency vehicle
324
+ Police car (siren)
325
+ Ambulance (siren)
326
+ Fire engine, fire truck (siren)
327
+ Motorcycle
328
+ Traffic noise, roadway noise
329
+ Rail transport
330
+ Train
331
+ Train whistle
332
+ Train horn
333
+ Railroad car, train wagon
334
+ Train wheels squealing
335
+ Subway, metro, underground
336
+ Aircraft
337
+ Aircraft engine
338
+ Jet engine
339
+ Propeller, airscrew
340
+ Helicopter
341
+ Fixed-wing aircraft, airplane
342
+ Bicycle
343
+ Skateboard
344
+ Engine
345
+ Light engine (high frequency)
346
+ Dental drill, dentist's drill
347
+ Lawn mower
348
+ Chainsaw
349
+ Medium engine (mid frequency)
350
+ Heavy engine (low frequency)
351
+ Engine knocking
352
+ Engine starting
353
+ Idling
354
+ Accelerating, revving, vroom
355
+ Door
356
+ Doorbell
357
+ Ding-dong
358
+ Sliding door
359
+ Slam
360
+ Knock
361
+ Tap
362
+ Squeak
363
+ Cupboard open or close
364
+ Drawer open or close
365
+ Dishes, pots, and pans
366
+ Cutlery, silverware
367
+ Chopping (food)
368
+ Frying (food)
369
+ Microwave oven
370
+ Blender
371
+ Water tap, faucet
372
+ Sink (filling or washing)
373
+ Bathtub (filling or washing)
374
+ Hair dryer
375
+ Toilet flush
376
+ Toothbrush
377
+ Electric toothbrush
378
+ Vacuum cleaner
379
+ Zipper (clothing)
380
+ Keys jangling
381
+ Coin (dropping)
382
+ Scissors
383
+ Electric shaver, electric razor
384
+ Shuffling cards
385
+ Typing
386
+ Typewriter
387
+ Computer keyboard
388
+ Writing
389
+ Alarm
390
+ Telephone
391
+ Telephone bell ringing
392
+ Ringtone
393
+ Telephone dialing, DTMF
394
+ Dial tone
395
+ Busy signal
396
+ Alarm clock
397
+ Siren
398
+ Civil defense siren
399
+ Buzzer
400
+ Smoke detector, smoke alarm
401
+ Fire alarm
402
+ Foghorn
403
+ Whistle
404
+ Steam whistle
405
+ Mechanisms
406
+ Ratchet, pawl
407
+ Clock
408
+ Tick
409
+ Tick-tock
410
+ Gears
411
+ Pulleys
412
+ Sewing machine
413
+ Mechanical fan
414
+ Air conditioning
415
+ Cash register
416
+ Printer
417
+ Camera
418
+ Single-lens reflex camera
419
+ Tools
420
+ Hammer
421
+ Jackhammer
422
+ Sawing
423
+ Filing (rasp)
424
+ Sanding
425
+ Power tool
426
+ Drill
427
+ Explosion
428
+ Gunshot, gunfire
429
+ Machine gun
430
+ Fusillade
431
+ Artillery fire
432
+ Cap gun
433
+ Fireworks
434
+ Firecracker
435
+ Burst, pop
436
+ Eruption
437
+ Boom
438
+ Wood
439
+ Chop
440
+ Splinter
441
+ Crack
442
+ Glass
443
+ Chink, clink
444
+ Shatter
445
+ Liquid
446
+ Splash, splatter
447
+ Slosh
448
+ Squish
449
+ Drip
450
+ Pour
451
+ Trickle, dribble
452
+ Gush
453
+ Fill (with liquid)
454
+ Spray
455
+ Pump (liquid)
456
+ Stir
457
+ Boiling
458
+ Sonar
459
+ Arrow
460
+ Whoosh, swoosh, swish
461
+ Thump, thud
462
+ Thunk
463
+ Electronic tuner
464
+ Effects unit
465
+ Chorus effect
466
+ Basketball bounce
467
+ Bang
468
+ Slap, smack
469
+ Whack, thwack
470
+ Smash, crash
471
+ Breaking
472
+ Bouncing
473
+ Whip
474
+ Flap
475
+ Scratch
476
+ Scrape
477
+ Rub
478
+ Roll
479
+ Crushing
480
+ Crumpling, crinkling
481
+ Tearing
482
+ Beep, bleep
483
+ Ping
484
+ Ding
485
+ Clang
486
+ Squeal
487
+ Creak
488
+ Rustle
489
+ Whir
490
+ Clatter
491
+ Sizzle
492
+ Clicking
493
+ Clickety-clack
494
+ Rumble
495
+ Plop
496
+ Jingle, tinkle
497
+ Hum
498
+ Zing
499
+ Boing
500
+ Crunch
501
+ Silence
502
+ Sine wave
503
+ Harmonic
504
+ Chirp tone
505
+ Sound effect
506
+ Pulse
507
+ Inside, small room
508
+ Inside, large room or hall
509
+ Inside, public space
510
+ Outside, urban or manmade
511
+ Outside, rural or natural
512
+ Reverberation
513
+ Echo
514
+ Noise
515
+ Environmental noise
516
+ Static
517
+ Mains hum
518
+ Distortion
519
+ Sidetone
520
+ Cacophony
521
+ White noise
522
+ Pink noise
523
+ Throbbing
524
+ Vibration
525
+ Television
526
+ Radio
527
+ Field recording
build_panns.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """PANNs CNN14 (AudioSet 527-tag) -> LiteRT CompiledModel GPU.
3
+
4
+ Deployment = host-side log-mel + a single GPU graph for the CNN body:
5
+
6
+ waveform[320000] --[Kotlin log-mel]--> logmel[1,1,1001,64] --[GPU CNN14]--> probs[527]
7
+
8
+ Why the log-mel is host-side and not in the graph: PANNs builds the spectrogram with torchlibrosa's
9
+ STFT (a DFT-as-Conv1d, so there is NO FFT op and the full raw-audio graph IS op-clean — only the
10
+ center reflect-pad emits a single GATHER_ND, removable with pad_mode='constant'). BUT the converted
11
+ spectral front-end is numerically wrong (fp32 corr 0.19) and the power spectrum |STFT|^2 (~1e6)
12
+ overflows fp16 on Mali -> NaN. The CNN body alone (logmel -> tags) converts at corr 1.000000 in both
13
+ fp32 and fp16, so we keep it on the GPU and compute the log-mel on the CPU (Whisper/Kokoro pattern),
14
+ matched to torchlibrosa exactly (validated here in numpy at corr 1.0).
15
+
16
+ Deps: the qiuqiangkong model defs (`models.py` as panns_models.py + `pytorch_utils.py`) from
17
+ github.com/qiuqiangkong/audioset_tagging_cnn, and Cnn14_mAP=0.431.pth (Zenodo, CC-BY-4.0):
18
+ https://zenodo.org/record/3987831/files/Cnn14_mAP%3D0.431.pth
19
+ Run: ~/clipconv/bin/python build_panns.py
20
+ """
21
+ import _stub_propack # noqa: F401 (narrow scipy _propack shim; keeps librosa real)
22
+ import sys, os, csv, collections, numpy as np, torch, torch.nn as nn, torch.nn.functional as F
23
+ sys.path.insert(0, ".")
24
+ from panns_models import Cnn14
25
+
26
+ HERE = os.path.dirname(os.path.abspath(__file__))
27
+ SR, NFFT, HOP, NMEL = 32000, 1024, 320, 64
28
+ PAD = NFFT // 2
29
+ CLIP_SAMPLES = 320000 # 10 s @ 32 kHz (PANNs canonical eval window)
30
+ CFG = dict(sample_rate=SR, window_size=NFFT, hop_size=HOP, mel_bins=NMEL, fmin=50, fmax=14000, classes_num=527)
31
+ CKPT = os.path.join(HERE, "Cnn14_mAP=0.431.pth")
32
+ SAMPLE_WAV = os.path.expanduser("~/Downloads/meeting/wav2vec2-work/sample_speech.wav")
33
+ LABELS_CSV = os.path.join(HERE, "class_labels_indices.csv")
34
+ BANNED = {"GATHER", "GATHER_ND", "TOPK_V2", "GELU", "ERF", "WHERE", "SELECT", "SELECT_V2",
35
+ "BROADCAST_TO", "POW", "TRANSPOSE_CONV", "CAST", "EMBEDDING_LOOKUP",
36
+ "RFFT2D", "FFT", "STFT", "COMPLEX", "RFFT", "IRFFT", "CUMSUM"}
37
+
38
+
39
+ class LogmelCNN(nn.Module):
40
+ """The GPU graph: logmel[B,1,T,64] -> clipwise_output[B,527]. Mirrors Cnn14.forward after logmel."""
41
+ def __init__(s, m): super().__init__(); s.m = m
42
+ def forward(s, x):
43
+ m = s.m
44
+ x = x.transpose(1, 3); x = m.bn0(x); x = x.transpose(1, 3)
45
+ x = m.conv_block1(x, pool_size=(2, 2), pool_type='avg')
46
+ x = m.conv_block2(x, pool_size=(2, 2), pool_type='avg')
47
+ x = m.conv_block3(x, pool_size=(2, 2), pool_type='avg')
48
+ x = m.conv_block4(x, pool_size=(2, 2), pool_type='avg')
49
+ x = m.conv_block5(x, pool_size=(2, 2), pool_type='avg')
50
+ x = m.conv_block6(x, pool_size=(1, 1), pool_type='avg')
51
+ x = torch.mean(x, dim=3)
52
+ (x1, _) = torch.max(x, dim=2); x2 = torch.mean(x, dim=2)
53
+ x = x1 + x2
54
+ x = F.relu_(m.fc1(x))
55
+ return torch.sigmoid(m.fc_audioset(x))
56
+
57
+
58
+ def numpy_logmel(wav, melW):
59
+ """What the Kotlin front-end computes: reflect-pad center, periodic Hann, FFT, power, melW, 10log10."""
60
+ padded = np.pad(wav, (PAD, PAD), mode="reflect")
61
+ n = 1 + (len(padded) - NFFT) // HOP
62
+ win = 0.5 - 0.5 * np.cos(2 * np.pi * np.arange(NFFT) / NFFT)
63
+ power = np.empty((n, NFFT // 2 + 1), np.float64)
64
+ for t in range(n):
65
+ s = np.fft.rfft(padded[t * HOP: t * HOP + NFFT] * win, n=NFFT)
66
+ power[t] = s.real ** 2 + s.imag ** 2
67
+ return (10.0 * np.log10(np.maximum(power @ melW, 1e-10))).astype(np.float32)
68
+
69
+
70
+ def opcheck(path, label):
71
+ from ai_edge_litert.interpreter import Interpreter
72
+ it = Interpreter(model_path=path); it.allocate_tensors()
73
+ ops = collections.Counter(d.get("op_name", "?") for d in it._get_ops_details())
74
+ bad = {k: v for k, v in ops.items() if k.upper() in BANNED}
75
+ over = sum(1 for d in it.get_tensor_details() if len(d.get("shape", [])) > 4)
76
+ print(f"[{label}] banned:{bad or 'NONE'} >4D:{over} size {os.path.getsize(path)/1e6:.1f}MB "
77
+ f"VERDICT {'GPU-CLEAN' if not bad and not over else bad}")
78
+ return it
79
+
80
+
81
+ def tfl(it, x):
82
+ d = it.get_input_details()[0]; it.set_tensor(d["index"], x.astype(d["dtype"])); it.invoke()
83
+ return it.get_tensor(it.get_output_details()[0]["index"])
84
+
85
+
86
+ def to_fp16(fp32, fp16):
87
+ from ai_edge_quantizer import quantizer, recipe_manager
88
+ from ai_edge_quantizer.recipe import AlgorithmName, qtyping
89
+ rm = recipe_manager.RecipeManager()
90
+ rm.add_quantization_config(regex=".*", operation_name=qtyping.TFLOperationName.ALL_SUPPORTED,
91
+ op_config=qtyping.OpQuantizationConfig(
92
+ weight_tensor_config=qtyping.TensorQuantizationConfig(num_bits=16, dtype=qtyping.TensorDataType.FLOAT),
93
+ compute_precision=qtyping.ComputePrecision.FLOAT), algorithm_key=AlgorithmName.FLOAT_CASTING)
94
+ if os.path.exists(fp16): os.remove(fp16)
95
+ qt = quantizer.Quantizer(float_model=fp32); qt.load_quantization_recipe(rm.get_quantization_recipe())
96
+ qt.quantize().export_model(fp16); return fp16
97
+
98
+
99
+ def main():
100
+ labels = [r[2] for r in list(csv.reader(open(LABELS_CSV)))[1:]]
101
+ m = Cnn14(**CFG).eval()
102
+ m.load_state_dict(torch.load(CKPT, map_location="cpu")["model"])
103
+ melW = m.logmel_extractor.melW.detach().numpy() # [513,64]
104
+
105
+ import librosa
106
+ wav, _ = librosa.load(SAMPLE_WAV, sr=SR, mono=True)
107
+ wav = np.pad(wav, (0, max(0, CLIP_SAMPLES - len(wav))))[:CLIP_SAMPLES].astype(np.float32)
108
+
109
+ with torch.no_grad():
110
+ logmel = m.logmel_extractor(m.spectrogram_extractor(torch.from_numpy(wav)[None])) # [1,1,T,64]
111
+ y = LogmelCNN(m).eval()(logmel).numpy().ravel()
112
+
113
+ # validate the host-side (Kotlin) log-mel against torch
114
+ lm_np = numpy_logmel(wav, melW)
115
+ lm_t = logmel.numpy().reshape(-1, NMEL)
116
+ print(f"host log-mel vs torch: corr {np.corrcoef(lm_t.ravel(), lm_np.ravel())[0,1]:.6f} "
117
+ f"max|d| {np.abs(lm_t-lm_np).max():.4f}")
118
+
119
+ # convert the CNN body
120
+ import litert_torch
121
+ fp32 = os.path.join(HERE, "cnn14_audioset.tflite")
122
+ litert_torch.convert(LogmelCNN(m).eval(), (logmel,)).export(fp32)
123
+ it32 = opcheck(fp32, "fp32"); o32 = tfl(it32, logmel.numpy()).ravel()
124
+ print(f"[fp32] tflite-vs-torch corr {np.corrcoef(o32, y)[0,1]:.6f}")
125
+ fp16 = to_fp16(fp32, os.path.join(HERE, "cnn14_audioset_fp16.tflite"))
126
+ it16 = opcheck(fp16, "fp16"); o16 = tfl(it16, logmel.numpy()).ravel()
127
+ print(f"[fp16] tflite-vs-torch corr {np.corrcoef(o16, y)[0,1]:.6f}")
128
+
129
+ # assets + fixtures
130
+ melW.T.astype(np.float32).tofile(os.path.join(HERE, "mel_basis.bin")) # [64,513] mel-major
131
+ wav.tofile(os.path.join(HERE, "panns_input.bin"))
132
+ np.save(os.path.join(HERE, "panns_ref.npy"), o16)
133
+ top = np.argsort(o16)[::-1][:8]
134
+ print("top tags:", [(labels[i], round(float(o16[i]), 3)) for i in top])
135
+ print("wrote cnn14_audioset_fp16.tflite + mel_basis.bin + fixtures")
136
+
137
+
138
+ if __name__ == "__main__":
139
+ main()
cnn14_audioset_fp16.tflite ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:26e52a285ff324778c7b90642e9733b47a46071622ecba93d42ca14ec19a467f
3
+ size 161533712
mel_basis.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:50edbf75f0ffdb5bf295a54cb3b9c4ad27b841be1119255f0f785552b99f13bd
3
+ size 131328