From fa15115163a2a3e3fbe323c039acf26323ec29d3 Mon Sep 17 00:00:00 2001 From: Quentin Fuxa Date: Sat, 14 Mar 2026 00:12:50 +0100 Subject: [PATCH] qwen3 alignment heads --- scripts/alignment_heads_qwen3_asr_1.7B.json | 3445 +++++++++++++++++++ scripts/alignment_heads_qwen3_asr_1.7B.png | Bin 0 -> 85188 bytes scripts/detect_alignment_heads_qwen3.py | 703 ++++ scripts/generate_architecture.py | 213 ++ 4 files changed, 4361 insertions(+) create mode 100644 scripts/alignment_heads_qwen3_asr_1.7B.json create mode 100644 scripts/alignment_heads_qwen3_asr_1.7B.png create mode 100644 scripts/detect_alignment_heads_qwen3.py create mode 100644 scripts/generate_architecture.py diff --git a/scripts/alignment_heads_qwen3_asr_1.7B.json b/scripts/alignment_heads_qwen3_asr_1.7B.json new file mode 100644 index 0000000..52c7e09 --- /dev/null +++ b/scripts/alignment_heads_qwen3_asr_1.7B.json @@ -0,0 +1,3445 @@ +{ + "model": "Qwen/Qwen3-ASR-1.7B", + "language": "English", + "num_layers": 28, + "num_heads": 16, + "num_kv_heads": 8, + "num_samples": 100, + "total_alignable_tokens": 1125, + "ts_threshold": 0.1, + "ts_matrix": [ + [ + 0.10222222222222223, + 0.09333333333333334, + 0.10133333333333333, + 0.10755555555555556, + 0.056, + 0.06933333333333333, + 0.07644444444444444, + 0.07466666666666667, + 0.08533333333333333, + 0.09422222222222222, + 0.13155555555555556, + 0.1431111111111111, + 0.05333333333333334, + 0.041777777777777775, + 0.05422222222222222, + 0.07466666666666667 + ], + [ + 0.15733333333333333, + 0.15555555555555556, + 0.096, + 0.14044444444444446, + 0.064, + 0.056, + 0.06933333333333333, + 0.07377777777777778, + 0.3502222222222222, + 0.06311111111111112, + 0.08533333333333333, + 0.04711111111111111, + 0.03111111111111111, + 0.17155555555555554, + 0.13155555555555556, + 0.5191111111111111 + ], + [ + 0.06488888888888888, + 0.056, + 0.2577777777777778, + 0.6417777777777778, + 0.08177777777777778, + 0.06844444444444445, + 0.192, + 0.07288888888888889, + 0.3457777777777778, + 0.08711111111111111, + 0.6604444444444444, + 0.6666666666666666, + 0.08266666666666667, + 0.1111111111111111, + 0.36977777777777776, + 0.12355555555555556 + ], + [ + 0.11822222222222223, + 0.12622222222222224, + 0.16444444444444445, + 0.18488888888888888, + 0.256, + 0.088, + 0.09155555555555556, + 0.07555555555555556, + 0.11377777777777778, + 0.11733333333333333, + 0.6853333333333333, + 0.616, + 0.12533333333333332, + 0.26755555555555555, + 0.20266666666666666, + 0.20355555555555555 + ], + [ + 0.030222222222222223, + 0.034666666666666665, + 0.11644444444444445, + 0.10577777777777778, + 0.11911111111111111, + 0.06933333333333333, + 0.029333333333333333, + 0.09333333333333334, + 0.12266666666666666, + 0.09244444444444444, + 0.3831111111111111, + 0.20533333333333334, + 0.43555555555555553, + 0.6542222222222223, + 0.08266666666666667, + 0.25955555555555554 + ], + [ + 0.10755555555555556, + 0.10133333333333333, + 0.08533333333333333, + 0.07022222222222223, + 0.13866666666666666, + 0.22133333333333333, + 0.11911111111111111, + 0.12622222222222224, + 0.1288888888888889, + 0.12977777777777777, + 0.44355555555555554, + 0.12266666666666666, + 0.05422222222222222, + 0.04888888888888889, + 0.152, + 0.32266666666666666 + ], + [ + 0.25244444444444447, + 0.21422222222222223, + 0.08088888888888889, + 0.12444444444444444, + 0.17155555555555554, + 0.13955555555555554, + 0.7288888888888889, + 0.7315555555555555, + 0.03288888888888889, + 0.24888888888888888, + 0.7146666666666667, + 0.7031111111111111, + 0.6417777777777778, + 0.6888888888888889, + 0.18666666666666668, + 0.1511111111111111 + ], + [ + 0.13422222222222221, + 0.03822222222222222, + 0.07022222222222223, + 0.08177777777777778, + 0.29155555555555557, + 0.1368888888888889, + 0.16444444444444445, + 0.07733333333333334, + 0.09244444444444444, + 0.030222222222222223, + 0.13155555555555556, + 0.14844444444444443, + 0.12444444444444444, + 0.22755555555555557, + 0.12622222222222224, + 0.17244444444444446 + ], + [ + 0.12266666666666666, + 0.6008888888888889, + 0.14844444444444443, + 0.06577777777777778, + 0.6488888888888888, + 0.3546666666666667, + 0.23644444444444446, + 0.296, + 0.10311111111111111, + 0.13155555555555556, + 0.17422222222222222, + 0.14666666666666667, + 0.136, + 0.1991111111111111, + 0.3111111111111111, + 0.09333333333333334 + ], + [ + 0.1902222222222222, + 0.03822222222222222, + 0.1608888888888889, + 0.09155555555555556, + 0.18844444444444444, + 0.19466666666666665, + 0.04533333333333334, + 0.1671111111111111, + 0.22844444444444445, + 0.23644444444444446, + 0.17333333333333334, + 0.11555555555555555, + 0.49422222222222223, + 0.41244444444444445, + 0.12977777777777777, + 0.018666666666666668 + ], + [ + 0.028444444444444446, + 0.04622222222222222, + 0.18222222222222223, + 0.25066666666666665, + 0.17866666666666667, + 0.32266666666666666, + 0.051555555555555556, + 0.07822222222222222, + 0.1448888888888889, + 0.152, + 0.0791111111111111, + 0.15733333333333333, + 0.1111111111111111, + 0.14844444444444443, + 0.04711111111111111, + 0.10044444444444445 + ], + [ + 0.18577777777777776, + 0.22044444444444444, + 0.7573333333333333, + 0.7182222222222222, + 0.11288888888888889, + 0.168, + 0.18044444444444444, + 0.2577777777777778, + 0.18933333333333333, + 0.11377777777777778, + 0.2871111111111111, + 0.6168888888888889, + 0.7093333333333334, + 0.7484444444444445, + 0.050666666666666665, + 0.11288888888888889 + ], + [ + 0.344, + 0.37155555555555553, + 0.16977777777777778, + 0.2551111111111111, + 0.0791111111111111, + 0.12, + 0.5511111111111111, + 0.07555555555555556, + 0.31733333333333336, + 0.09688888888888889, + 0.23733333333333334, + 0.06666666666666667, + 0.17155555555555554, + 0.10844444444444444, + 0.21244444444444444, + 0.20355555555555555 + ], + [ + 0.6124444444444445, + 0.192, + 0.18044444444444444, + 0.1288888888888889, + 0.3848888888888889, + 0.136, + 0.48533333333333334, + 0.5022222222222222, + 0.034666666666666665, + 0.04888888888888889, + 0.088, + 0.6702222222222223, + 0.025777777777777778, + 0.03822222222222222, + 0.5964444444444444, + 0.4231111111111111 + ], + [ + 0.19377777777777777, + 0.09066666666666667, + 0.16355555555555557, + 0.07466666666666667, + 0.051555555555555556, + 0.2222222222222222, + 0.18666666666666668, + 0.14666666666666667, + 0.064, + 0.07822222222222222, + 0.18755555555555556, + 0.23644444444444446, + 0.42133333333333334, + 0.21066666666666667, + 0.7351111111111112, + 0.7164444444444444 + ], + [ + 0.12622222222222224, + 0.168, + 0.1751111111111111, + 0.152, + 0.18488888888888888, + 0.1751111111111111, + 0.21866666666666668, + 0.10933333333333334, + 0.07555555555555556, + 0.16533333333333333, + 0.3111111111111111, + 0.16177777777777777, + 0.04088888888888889, + 0.037333333333333336, + 0.18488888888888888, + 0.11466666666666667 + ], + [ + 0.05333333333333334, + 0.041777777777777775, + 0.11377777777777778, + 0.15911111111111112, + 0.11555555555555555, + 0.13333333333333333, + 0.16444444444444445, + 0.4817777777777778, + 0.25422222222222224, + 0.264, + 0.648, + 0.5493333333333333, + 0.2995555555555556, + 0.4017777777777778, + 0.7573333333333333, + 0.6977777777777778 + ], + [ + 0.25866666666666666, + 0.25955555555555554, + 0.2328888888888889, + 0.18133333333333335, + 0.08444444444444445, + 0.058666666666666666, + 0.042666666666666665, + 0.22933333333333333, + 0.34044444444444444, + 0.24533333333333332, + 0.23822222222222222, + 0.18577777777777776, + 0.248, + 0.4017777777777778, + 0.11644444444444445, + 0.112 + ], + [ + 0.07377777777777778, + 0.07733333333333334, + 0.37244444444444447, + 0.6417777777777778, + 0.27466666666666667, + 0.6515555555555556, + 0.18222222222222223, + 0.16177777777777777, + 0.11377777777777778, + 0.07466666666666667, + 0.37777777777777777, + 0.1991111111111111, + 0.042666666666666665, + 0.19733333333333333, + 0.08711111111111111, + 0.2 + ], + [ + 0.16977777777777778, + 0.17066666666666666, + 0.31022222222222223, + 0.544, + 0.4391111111111111, + 0.6391111111111111, + 0.17066666666666666, + 0.712, + 0.4311111111111111, + 0.5022222222222222, + 0.07466666666666667, + 0.08711111111111111, + 0.3662222222222222, + 0.4017777777777778, + 0.04888888888888889, + 0.08266666666666667 + ], + [ + 0.10044444444444445, + 0.10844444444444444, + 0.15911111111111112, + 0.7644444444444445, + 0.3448888888888889, + 0.16177777777777777, + 0.3635555555555556, + 0.5031111111111111, + 0.31733333333333336, + 0.06933333333333333, + 0.5022222222222222, + 0.5742222222222222, + 0.3297777777777778, + 0.23644444444444446, + 0.6551111111111111, + 0.5831111111111111 + ], + [ + 0.5146666666666667, + 0.5031111111111111, + 0.112, + 0.07111111111111111, + 0.2391111111111111, + 0.15555555555555556, + 0.24266666666666667, + 0.18844444444444444, + 0.7386666666666667, + 0.7617777777777778, + 0.25066666666666665, + 0.352, + 0.5457777777777778, + 0.4088888888888889, + 0.3128888888888889, + 0.36177777777777775 + ], + [ + 0.21155555555555555, + 0.26666666666666666, + 0.10488888888888889, + 0.06222222222222222, + 0.288, + 0.25066666666666665, + 0.2995555555555556, + 0.6515555555555556, + 0.5955555555555555, + 0.6302222222222222, + 0.24977777777777777, + 0.2568888888888889, + 0.6195555555555555, + 0.5431111111111111, + 0.23466666666666666, + 0.08622222222222223 + ], + [ + 0.48977777777777776, + 0.5102222222222222, + 0.05688888888888889, + 0.06311111111111112, + 0.6222222222222222, + 0.4142222222222222, + 0.24888888888888888, + 0.6462222222222223, + 0.06488888888888888, + 0.1608888888888889, + 0.3537777777777778, + 0.31822222222222224, + 0.20177777777777778, + 0.1448888888888889, + 0.6275555555555555, + 0.6044444444444445 + ], + [ + 0.036444444444444446, + 0.048, + 0.06222222222222222, + 0.07377777777777778, + 0.42933333333333334, + 0.6257777777777778, + 0.5306666666666666, + 0.6008888888888889, + 0.09066666666666667, + 0.072, + 0.5493333333333333, + 0.5804444444444444, + 0.5866666666666667, + 0.5937777777777777, + 0.6257777777777778, + 0.6204444444444445 + ], + [ + 0.09066666666666667, + 0.11733333333333333, + 0.059555555555555556, + 0.07022222222222223, + 0.5982222222222222, + 0.648, + 0.5875555555555556, + 0.5964444444444444, + 0.352, + 0.4888888888888889, + 0.5715555555555556, + 0.6035555555555555, + 0.5875555555555556, + 0.5804444444444444, + 0.5688888888888889, + 0.3546666666666667 + ], + [ + 0.376, + 0.3217777777777778, + 0.5786666666666667, + 0.5466666666666666, + 0.5475555555555556, + 0.5155555555555555, + 0.1688888888888889, + 0.5528888888888889, + 0.6142222222222222, + 0.21511111111111111, + 0.08622222222222223, + 0.20533333333333334, + 0.13066666666666665, + 0.10222222222222223, + 0.5511111111111111, + 0.4951111111111111 + ], + [ + 0.08177777777777778, + 0.10044444444444445, + 0.08711111111111111, + 0.08888888888888889, + 0.08533333333333333, + 0.056, + 0.15466666666666667, + 0.07377777777777778, + 0.04888888888888889, + 0.07022222222222223, + 0.10222222222222223, + 0.0951111111111111, + 0.08088888888888889, + 0.06311111111111112, + 0.09688888888888889, + 0.07111111111111111 + ] + ], + "alignment_heads": [ + { + "layer": 20, + "head": 3, + "ts": 0.7644 + }, + { + "layer": 21, + "head": 9, + "ts": 0.7618 + }, + { + "layer": 11, + "head": 2, + "ts": 0.7573 + }, + { + "layer": 16, + "head": 14, + "ts": 0.7573 + }, + { + "layer": 11, + "head": 13, + "ts": 0.7484 + }, + { + "layer": 21, + "head": 8, + "ts": 0.7387 + }, + { + "layer": 14, + "head": 14, + "ts": 0.7351 + }, + { + "layer": 6, + "head": 7, + "ts": 0.7316 + }, + { + "layer": 6, + "head": 6, + "ts": 0.7289 + }, + { + "layer": 11, + "head": 3, + "ts": 0.7182 + }, + { + "layer": 14, + "head": 15, + "ts": 0.7164 + }, + { + "layer": 6, + "head": 10, + "ts": 0.7147 + }, + { + "layer": 19, + "head": 7, + "ts": 0.712 + }, + { + "layer": 11, + "head": 12, + "ts": 0.7093 + }, + { + "layer": 6, + "head": 11, + "ts": 0.7031 + }, + { + "layer": 16, + "head": 15, + "ts": 0.6978 + }, + { + "layer": 6, + "head": 13, + "ts": 0.6889 + }, + { + "layer": 3, + "head": 10, + "ts": 0.6853 + }, + { + "layer": 13, + "head": 11, + "ts": 0.6702 + }, + { + "layer": 2, + "head": 11, + "ts": 0.6667 + }, + { + "layer": 2, + "head": 10, + "ts": 0.6604 + }, + { + "layer": 20, + "head": 14, + "ts": 0.6551 + }, + { + "layer": 4, + "head": 13, + "ts": 0.6542 + }, + { + "layer": 18, + "head": 5, + "ts": 0.6516 + }, + { + "layer": 22, + "head": 7, + "ts": 0.6516 + }, + { + "layer": 8, + "head": 4, + "ts": 0.6489 + }, + { + "layer": 16, + "head": 10, + "ts": 0.648 + }, + { + "layer": 25, + "head": 5, + "ts": 0.648 + }, + { + "layer": 23, + "head": 7, + "ts": 0.6462 + }, + { + "layer": 2, + "head": 3, + "ts": 0.6418 + }, + { + "layer": 6, + "head": 12, + "ts": 0.6418 + }, + { + "layer": 18, + "head": 3, + "ts": 0.6418 + }, + { + "layer": 19, + "head": 5, + "ts": 0.6391 + }, + { + "layer": 22, + "head": 9, + "ts": 0.6302 + }, + { + "layer": 23, + "head": 14, + "ts": 0.6276 + }, + { + "layer": 24, + "head": 5, + "ts": 0.6258 + }, + { + "layer": 24, + "head": 14, + "ts": 0.6258 + }, + { + "layer": 23, + "head": 4, + "ts": 0.6222 + }, + { + "layer": 24, + "head": 15, + "ts": 0.6204 + }, + { + "layer": 22, + "head": 12, + "ts": 0.6196 + }, + { + "layer": 11, + "head": 11, + "ts": 0.6169 + }, + { + "layer": 3, + "head": 11, + "ts": 0.616 + }, + { + "layer": 26, + "head": 8, + "ts": 0.6142 + }, + { + "layer": 13, + "head": 0, + "ts": 0.6124 + }, + { + "layer": 23, + "head": 15, + "ts": 0.6044 + }, + { + "layer": 25, + "head": 11, + "ts": 0.6036 + }, + { + "layer": 8, + "head": 1, + "ts": 0.6009 + }, + { + "layer": 24, + "head": 7, + "ts": 0.6009 + }, + { + "layer": 25, + "head": 4, + "ts": 0.5982 + }, + { + "layer": 13, + "head": 14, + "ts": 0.5964 + }, + { + "layer": 25, + "head": 7, + "ts": 0.5964 + }, + { + "layer": 22, + "head": 8, + "ts": 0.5956 + }, + { + "layer": 24, + "head": 13, + "ts": 0.5938 + }, + { + "layer": 25, + "head": 6, + "ts": 0.5876 + }, + { + "layer": 25, + "head": 12, + "ts": 0.5876 + }, + { + "layer": 24, + "head": 12, + "ts": 0.5867 + }, + { + "layer": 20, + "head": 15, + "ts": 0.5831 + }, + { + "layer": 24, + "head": 11, + "ts": 0.5804 + }, + { + "layer": 25, + "head": 13, + "ts": 0.5804 + }, + { + "layer": 26, + "head": 2, + "ts": 0.5787 + }, + { + "layer": 20, + "head": 11, + "ts": 0.5742 + }, + { + "layer": 25, + "head": 10, + "ts": 0.5716 + }, + { + "layer": 25, + "head": 14, + "ts": 0.5689 + }, + { + "layer": 26, + "head": 7, + "ts": 0.5529 + }, + { + "layer": 12, + "head": 6, + "ts": 0.5511 + }, + { + "layer": 26, + "head": 14, + "ts": 0.5511 + }, + { + "layer": 16, + "head": 11, + "ts": 0.5493 + }, + { + "layer": 24, + "head": 10, + "ts": 0.5493 + }, + { + "layer": 26, + "head": 4, + "ts": 0.5476 + }, + { + "layer": 26, + "head": 3, + "ts": 0.5467 + }, + { + "layer": 21, + "head": 12, + "ts": 0.5458 + }, + { + "layer": 19, + "head": 3, + "ts": 0.544 + }, + { + "layer": 22, + "head": 13, + "ts": 0.5431 + }, + { + "layer": 24, + "head": 6, + "ts": 0.5307 + }, + { + "layer": 1, + "head": 15, + "ts": 0.5191 + }, + { + "layer": 26, + "head": 5, + "ts": 0.5156 + }, + { + "layer": 21, + "head": 0, + "ts": 0.5147 + }, + { + "layer": 23, + "head": 1, + "ts": 0.5102 + }, + { + "layer": 20, + "head": 7, + "ts": 0.5031 + }, + { + "layer": 21, + "head": 1, + "ts": 0.5031 + }, + { + "layer": 13, + "head": 7, + "ts": 0.5022 + }, + { + "layer": 19, + "head": 9, + "ts": 0.5022 + }, + { + "layer": 20, + "head": 10, + "ts": 0.5022 + }, + { + "layer": 26, + "head": 15, + "ts": 0.4951 + }, + { + "layer": 9, + "head": 12, + "ts": 0.4942 + }, + { + "layer": 23, + "head": 0, + "ts": 0.4898 + }, + { + "layer": 25, + "head": 9, + "ts": 0.4889 + }, + { + "layer": 13, + "head": 6, + "ts": 0.4853 + }, + { + "layer": 16, + "head": 7, + "ts": 0.4818 + }, + { + "layer": 5, + "head": 10, + "ts": 0.4436 + }, + { + "layer": 19, + "head": 4, + "ts": 0.4391 + }, + { + "layer": 4, + "head": 12, + "ts": 0.4356 + }, + { + "layer": 19, + "head": 8, + "ts": 0.4311 + }, + { + "layer": 24, + "head": 4, + "ts": 0.4293 + }, + { + "layer": 13, + "head": 15, + "ts": 0.4231 + }, + { + "layer": 14, + "head": 12, + "ts": 0.4213 + }, + { + "layer": 23, + "head": 5, + "ts": 0.4142 + }, + { + "layer": 9, + "head": 13, + "ts": 0.4124 + }, + { + "layer": 21, + "head": 13, + "ts": 0.4089 + }, + { + "layer": 16, + "head": 13, + "ts": 0.4018 + }, + { + "layer": 17, + "head": 13, + "ts": 0.4018 + }, + { + "layer": 19, + "head": 13, + "ts": 0.4018 + }, + { + "layer": 13, + "head": 4, + "ts": 0.3849 + }, + { + "layer": 4, + "head": 10, + "ts": 0.3831 + }, + { + "layer": 18, + "head": 10, + "ts": 0.3778 + }, + { + "layer": 26, + "head": 0, + "ts": 0.376 + }, + { + "layer": 18, + "head": 2, + "ts": 0.3724 + }, + { + "layer": 12, + "head": 1, + "ts": 0.3716 + }, + { + "layer": 2, + "head": 14, + "ts": 0.3698 + }, + { + "layer": 19, + "head": 12, + "ts": 0.3662 + }, + { + "layer": 20, + "head": 6, + "ts": 0.3636 + }, + { + "layer": 21, + "head": 15, + "ts": 0.3618 + }, + { + "layer": 8, + "head": 5, + "ts": 0.3547 + }, + { + "layer": 25, + "head": 15, + "ts": 0.3547 + }, + { + "layer": 23, + "head": 10, + "ts": 0.3538 + }, + { + "layer": 21, + "head": 11, + "ts": 0.352 + }, + { + "layer": 25, + "head": 8, + "ts": 0.352 + }, + { + "layer": 1, + "head": 8, + "ts": 0.3502 + }, + { + "layer": 2, + "head": 8, + "ts": 0.3458 + }, + { + "layer": 20, + "head": 4, + "ts": 0.3449 + }, + { + "layer": 12, + "head": 0, + "ts": 0.344 + }, + { + "layer": 17, + "head": 8, + "ts": 0.3404 + }, + { + "layer": 20, + "head": 12, + "ts": 0.3298 + }, + { + "layer": 5, + "head": 15, + "ts": 0.3227 + }, + { + "layer": 10, + "head": 5, + "ts": 0.3227 + }, + { + "layer": 26, + "head": 1, + "ts": 0.3218 + }, + { + "layer": 23, + "head": 11, + "ts": 0.3182 + }, + { + "layer": 12, + "head": 8, + "ts": 0.3173 + }, + { + "layer": 20, + "head": 8, + "ts": 0.3173 + }, + { + "layer": 21, + "head": 14, + "ts": 0.3129 + }, + { + "layer": 8, + "head": 14, + "ts": 0.3111 + }, + { + "layer": 15, + "head": 10, + "ts": 0.3111 + }, + { + "layer": 19, + "head": 2, + "ts": 0.3102 + }, + { + "layer": 16, + "head": 12, + "ts": 0.2996 + }, + { + "layer": 22, + "head": 6, + "ts": 0.2996 + }, + { + "layer": 8, + "head": 7, + "ts": 0.296 + }, + { + "layer": 7, + "head": 4, + "ts": 0.2916 + }, + { + "layer": 22, + "head": 4, + "ts": 0.288 + }, + { + "layer": 11, + "head": 10, + "ts": 0.2871 + }, + { + "layer": 18, + "head": 4, + "ts": 0.2747 + }, + { + "layer": 3, + "head": 13, + "ts": 0.2676 + }, + { + "layer": 22, + "head": 1, + "ts": 0.2667 + }, + { + "layer": 16, + "head": 9, + "ts": 0.264 + }, + { + "layer": 4, + "head": 15, + "ts": 0.2596 + }, + { + "layer": 17, + "head": 1, + "ts": 0.2596 + }, + { + "layer": 17, + "head": 0, + "ts": 0.2587 + }, + { + "layer": 2, + "head": 2, + "ts": 0.2578 + }, + { + "layer": 11, + "head": 7, + "ts": 0.2578 + }, + { + "layer": 22, + "head": 11, + "ts": 0.2569 + }, + { + "layer": 3, + "head": 4, + "ts": 0.256 + }, + { + "layer": 12, + "head": 3, + "ts": 0.2551 + }, + { + "layer": 16, + "head": 8, + "ts": 0.2542 + }, + { + "layer": 6, + "head": 0, + "ts": 0.2524 + }, + { + "layer": 10, + "head": 3, + "ts": 0.2507 + }, + { + "layer": 21, + "head": 10, + "ts": 0.2507 + }, + { + "layer": 22, + "head": 5, + "ts": 0.2507 + }, + { + "layer": 22, + "head": 10, + "ts": 0.2498 + }, + { + "layer": 6, + "head": 9, + "ts": 0.2489 + }, + { + "layer": 23, + "head": 6, + "ts": 0.2489 + }, + { + "layer": 17, + "head": 12, + "ts": 0.248 + }, + { + "layer": 17, + "head": 9, + "ts": 0.2453 + }, + { + "layer": 21, + "head": 6, + "ts": 0.2427 + }, + { + "layer": 21, + "head": 4, + "ts": 0.2391 + }, + { + "layer": 17, + "head": 10, + "ts": 0.2382 + }, + { + "layer": 12, + "head": 10, + "ts": 0.2373 + }, + { + "layer": 8, + "head": 6, + "ts": 0.2364 + }, + { + "layer": 9, + "head": 9, + "ts": 0.2364 + }, + { + "layer": 14, + "head": 11, + "ts": 0.2364 + }, + { + "layer": 20, + "head": 13, + "ts": 0.2364 + }, + { + "layer": 22, + "head": 14, + "ts": 0.2347 + }, + { + "layer": 17, + "head": 2, + "ts": 0.2329 + }, + { + "layer": 17, + "head": 7, + "ts": 0.2293 + }, + { + "layer": 9, + "head": 8, + "ts": 0.2284 + }, + { + "layer": 7, + "head": 13, + "ts": 0.2276 + }, + { + "layer": 14, + "head": 5, + "ts": 0.2222 + }, + { + "layer": 5, + "head": 5, + "ts": 0.2213 + }, + { + "layer": 11, + "head": 1, + "ts": 0.2204 + }, + { + "layer": 15, + "head": 6, + "ts": 0.2187 + }, + { + "layer": 26, + "head": 9, + "ts": 0.2151 + }, + { + "layer": 6, + "head": 1, + "ts": 0.2142 + }, + { + "layer": 12, + "head": 14, + "ts": 0.2124 + }, + { + "layer": 22, + "head": 0, + "ts": 0.2116 + }, + { + "layer": 14, + "head": 13, + "ts": 0.2107 + }, + { + "layer": 4, + "head": 11, + "ts": 0.2053 + }, + { + "layer": 26, + "head": 11, + "ts": 0.2053 + }, + { + "layer": 3, + "head": 15, + "ts": 0.2036 + }, + { + "layer": 12, + "head": 15, + "ts": 0.2036 + }, + { + "layer": 3, + "head": 14, + "ts": 0.2027 + }, + { + "layer": 23, + "head": 12, + "ts": 0.2018 + }, + { + "layer": 18, + "head": 15, + "ts": 0.2 + }, + { + "layer": 8, + "head": 13, + "ts": 0.1991 + }, + { + "layer": 18, + "head": 11, + "ts": 0.1991 + }, + { + "layer": 18, + "head": 13, + "ts": 0.1973 + }, + { + "layer": 9, + "head": 5, + "ts": 0.1947 + }, + { + "layer": 14, + "head": 0, + "ts": 0.1938 + }, + { + "layer": 2, + "head": 6, + "ts": 0.192 + }, + { + "layer": 13, + "head": 1, + "ts": 0.192 + }, + { + "layer": 9, + "head": 0, + "ts": 0.1902 + }, + { + "layer": 11, + "head": 8, + "ts": 0.1893 + }, + { + "layer": 9, + "head": 4, + "ts": 0.1884 + }, + { + "layer": 21, + "head": 7, + "ts": 0.1884 + }, + { + "layer": 14, + "head": 10, + "ts": 0.1876 + }, + { + "layer": 6, + "head": 14, + "ts": 0.1867 + }, + { + "layer": 14, + "head": 6, + "ts": 0.1867 + }, + { + "layer": 11, + "head": 0, + "ts": 0.1858 + }, + { + "layer": 17, + "head": 11, + "ts": 0.1858 + }, + { + "layer": 3, + "head": 3, + "ts": 0.1849 + }, + { + "layer": 15, + "head": 4, + "ts": 0.1849 + }, + { + "layer": 15, + "head": 14, + "ts": 0.1849 + }, + { + "layer": 10, + "head": 2, + "ts": 0.1822 + }, + { + "layer": 18, + "head": 6, + "ts": 0.1822 + }, + { + "layer": 17, + "head": 3, + "ts": 0.1813 + }, + { + "layer": 11, + "head": 6, + "ts": 0.1804 + }, + { + "layer": 13, + "head": 2, + "ts": 0.1804 + }, + { + "layer": 10, + "head": 4, + "ts": 0.1787 + }, + { + "layer": 15, + "head": 2, + "ts": 0.1751 + }, + { + "layer": 15, + "head": 5, + "ts": 0.1751 + }, + { + "layer": 8, + "head": 10, + "ts": 0.1742 + }, + { + "layer": 9, + "head": 10, + "ts": 0.1733 + }, + { + "layer": 7, + "head": 15, + "ts": 0.1724 + }, + { + "layer": 1, + "head": 13, + "ts": 0.1716 + }, + { + "layer": 6, + "head": 4, + "ts": 0.1716 + }, + { + "layer": 12, + "head": 12, + "ts": 0.1716 + }, + { + "layer": 19, + "head": 1, + "ts": 0.1707 + }, + { + "layer": 19, + "head": 6, + "ts": 0.1707 + }, + { + "layer": 12, + "head": 2, + "ts": 0.1698 + }, + { + "layer": 19, + "head": 0, + "ts": 0.1698 + }, + { + "layer": 26, + "head": 6, + "ts": 0.1689 + }, + { + "layer": 11, + "head": 5, + "ts": 0.168 + }, + { + "layer": 15, + "head": 1, + "ts": 0.168 + }, + { + "layer": 9, + "head": 7, + "ts": 0.1671 + }, + { + "layer": 15, + "head": 9, + "ts": 0.1653 + }, + { + "layer": 3, + "head": 2, + "ts": 0.1644 + }, + { + "layer": 7, + "head": 6, + "ts": 0.1644 + }, + { + "layer": 16, + "head": 6, + "ts": 0.1644 + }, + { + "layer": 14, + "head": 2, + "ts": 0.1636 + }, + { + "layer": 15, + "head": 11, + "ts": 0.1618 + }, + { + "layer": 18, + "head": 7, + "ts": 0.1618 + }, + { + "layer": 20, + "head": 5, + "ts": 0.1618 + }, + { + "layer": 9, + "head": 2, + "ts": 0.1609 + }, + { + "layer": 23, + "head": 9, + "ts": 0.1609 + }, + { + "layer": 16, + "head": 3, + "ts": 0.1591 + }, + { + "layer": 20, + "head": 2, + "ts": 0.1591 + }, + { + "layer": 1, + "head": 0, + "ts": 0.1573 + }, + { + "layer": 10, + "head": 11, + "ts": 0.1573 + }, + { + "layer": 1, + "head": 1, + "ts": 0.1556 + }, + { + "layer": 21, + "head": 5, + "ts": 0.1556 + }, + { + "layer": 27, + "head": 6, + "ts": 0.1547 + }, + { + "layer": 5, + "head": 14, + "ts": 0.152 + }, + { + "layer": 10, + "head": 9, + "ts": 0.152 + }, + { + "layer": 15, + "head": 3, + "ts": 0.152 + }, + { + "layer": 6, + "head": 15, + "ts": 0.1511 + }, + { + "layer": 7, + "head": 11, + "ts": 0.1484 + }, + { + "layer": 8, + "head": 2, + "ts": 0.1484 + }, + { + "layer": 10, + "head": 13, + "ts": 0.1484 + }, + { + "layer": 8, + "head": 11, + "ts": 0.1467 + }, + { + "layer": 14, + "head": 7, + "ts": 0.1467 + }, + { + "layer": 10, + "head": 8, + "ts": 0.1449 + }, + { + "layer": 23, + "head": 13, + "ts": 0.1449 + }, + { + "layer": 0, + "head": 11, + "ts": 0.1431 + }, + { + "layer": 1, + "head": 3, + "ts": 0.1404 + }, + { + "layer": 6, + "head": 5, + "ts": 0.1396 + }, + { + "layer": 5, + "head": 4, + "ts": 0.1387 + }, + { + "layer": 7, + "head": 5, + "ts": 0.1369 + }, + { + "layer": 8, + "head": 12, + "ts": 0.136 + }, + { + "layer": 13, + "head": 5, + "ts": 0.136 + }, + { + "layer": 7, + "head": 0, + "ts": 0.1342 + }, + { + "layer": 16, + "head": 5, + "ts": 0.1333 + }, + { + "layer": 0, + "head": 10, + "ts": 0.1316 + }, + { + "layer": 1, + "head": 14, + "ts": 0.1316 + }, + { + "layer": 7, + "head": 10, + "ts": 0.1316 + }, + { + "layer": 8, + "head": 9, + "ts": 0.1316 + }, + { + "layer": 26, + "head": 12, + "ts": 0.1307 + }, + { + "layer": 5, + "head": 9, + "ts": 0.1298 + }, + { + "layer": 9, + "head": 14, + "ts": 0.1298 + }, + { + "layer": 5, + "head": 8, + "ts": 0.1289 + }, + { + "layer": 13, + "head": 3, + "ts": 0.1289 + }, + { + "layer": 3, + "head": 1, + "ts": 0.1262 + }, + { + "layer": 5, + "head": 7, + "ts": 0.1262 + }, + { + "layer": 7, + "head": 14, + "ts": 0.1262 + }, + { + "layer": 15, + "head": 0, + "ts": 0.1262 + }, + { + "layer": 3, + "head": 12, + "ts": 0.1253 + }, + { + "layer": 6, + "head": 3, + "ts": 0.1244 + }, + { + "layer": 7, + "head": 12, + "ts": 0.1244 + }, + { + "layer": 2, + "head": 15, + "ts": 0.1236 + }, + { + "layer": 4, + "head": 8, + "ts": 0.1227 + }, + { + "layer": 5, + "head": 11, + "ts": 0.1227 + }, + { + "layer": 8, + "head": 0, + "ts": 0.1227 + }, + { + "layer": 12, + "head": 5, + "ts": 0.12 + }, + { + "layer": 4, + "head": 4, + "ts": 0.1191 + }, + { + "layer": 5, + "head": 6, + "ts": 0.1191 + }, + { + "layer": 3, + "head": 0, + "ts": 0.1182 + }, + { + "layer": 3, + "head": 9, + "ts": 0.1173 + }, + { + "layer": 25, + "head": 1, + "ts": 0.1173 + }, + { + "layer": 4, + "head": 2, + "ts": 0.1164 + }, + { + "layer": 17, + "head": 14, + "ts": 0.1164 + }, + { + "layer": 9, + "head": 11, + "ts": 0.1156 + }, + { + "layer": 16, + "head": 4, + "ts": 0.1156 + }, + { + "layer": 15, + "head": 15, + "ts": 0.1147 + }, + { + "layer": 3, + "head": 8, + "ts": 0.1138 + }, + { + "layer": 11, + "head": 9, + "ts": 0.1138 + }, + { + "layer": 16, + "head": 2, + "ts": 0.1138 + }, + { + "layer": 18, + "head": 8, + "ts": 0.1138 + }, + { + "layer": 11, + "head": 4, + "ts": 0.1129 + }, + { + "layer": 11, + "head": 15, + "ts": 0.1129 + }, + { + "layer": 17, + "head": 15, + "ts": 0.112 + }, + { + "layer": 21, + "head": 2, + "ts": 0.112 + }, + { + "layer": 2, + "head": 13, + "ts": 0.1111 + }, + { + "layer": 10, + "head": 12, + "ts": 0.1111 + }, + { + "layer": 15, + "head": 7, + "ts": 0.1093 + }, + { + "layer": 12, + "head": 13, + "ts": 0.1084 + }, + { + "layer": 20, + "head": 1, + "ts": 0.1084 + }, + { + "layer": 0, + "head": 3, + "ts": 0.1076 + }, + { + "layer": 5, + "head": 0, + "ts": 0.1076 + }, + { + "layer": 4, + "head": 3, + "ts": 0.1058 + }, + { + "layer": 22, + "head": 2, + "ts": 0.1049 + }, + { + "layer": 8, + "head": 8, + "ts": 0.1031 + }, + { + "layer": 0, + "head": 0, + "ts": 0.1022 + }, + { + "layer": 26, + "head": 13, + "ts": 0.1022 + }, + { + "layer": 27, + "head": 10, + "ts": 0.1022 + }, + { + "layer": 0, + "head": 2, + "ts": 0.1013 + }, + { + "layer": 5, + "head": 1, + "ts": 0.1013 + }, + { + "layer": 10, + "head": 15, + "ts": 0.1004 + }, + { + "layer": 20, + "head": 0, + "ts": 0.1004 + }, + { + "layer": 27, + "head": 1, + "ts": 0.1004 + } + ], + "alignment_heads_compact": [ + [ + 20, + 3 + ], + [ + 21, + 9 + ], + [ + 11, + 2 + ], + [ + 16, + 14 + ], + [ + 11, + 13 + ], + [ + 21, + 8 + ], + [ + 14, + 14 + ], + [ + 6, + 7 + ], + [ + 6, + 6 + ], + [ + 11, + 3 + ], + [ + 14, + 15 + ], + [ + 6, + 10 + ], + [ + 19, + 7 + ], + [ + 11, + 12 + ], + [ + 6, + 11 + ], + [ + 16, + 15 + ], + [ + 6, + 13 + ], + [ + 3, + 10 + ], + [ + 13, + 11 + ], + [ + 2, + 11 + ], + [ + 2, + 10 + ], + [ + 20, + 14 + ], + [ + 4, + 13 + ], + [ + 18, + 5 + ], + [ + 22, + 7 + ], + [ + 8, + 4 + ], + [ + 16, + 10 + ], + [ + 25, + 5 + ], + [ + 23, + 7 + ], + [ + 2, + 3 + ], + [ + 6, + 12 + ], + [ + 18, + 3 + ], + [ + 19, + 5 + ], + [ + 22, + 9 + ], + [ + 23, + 14 + ], + [ + 24, + 5 + ], + [ + 24, + 14 + ], + [ + 23, + 4 + ], + [ + 24, + 15 + ], + [ + 22, + 12 + ], + [ + 11, + 11 + ], + [ + 3, + 11 + ], + [ + 26, + 8 + ], + [ + 13, + 0 + ], + [ + 23, + 15 + ], + [ + 25, + 11 + ], + [ + 8, + 1 + ], + [ + 24, + 7 + ], + [ + 25, + 4 + ], + [ + 13, + 14 + ], + [ + 25, + 7 + ], + [ + 22, + 8 + ], + [ + 24, + 13 + ], + [ + 25, + 6 + ], + [ + 25, + 12 + ], + [ + 24, + 12 + ], + [ + 20, + 15 + ], + [ + 24, + 11 + ], + [ + 25, + 13 + ], + [ + 26, + 2 + ], + [ + 20, + 11 + ], + [ + 25, + 10 + ], + [ + 25, + 14 + ], + [ + 26, + 7 + ], + [ + 12, + 6 + ], + [ + 26, + 14 + ], + [ + 16, + 11 + ], + [ + 24, + 10 + ], + [ + 26, + 4 + ], + [ + 26, + 3 + ], + [ + 21, + 12 + ], + [ + 19, + 3 + ], + [ + 22, + 13 + ], + [ + 24, + 6 + ], + [ + 1, + 15 + ], + [ + 26, + 5 + ], + [ + 21, + 0 + ], + [ + 23, + 1 + ], + [ + 20, + 7 + ], + [ + 21, + 1 + ], + [ + 13, + 7 + ], + [ + 19, + 9 + ], + [ + 20, + 10 + ], + [ + 26, + 15 + ], + [ + 9, + 12 + ], + [ + 23, + 0 + ], + [ + 25, + 9 + ], + [ + 13, + 6 + ], + [ + 16, + 7 + ], + [ + 5, + 10 + ], + [ + 19, + 4 + ], + [ + 4, + 12 + ], + [ + 19, + 8 + ], + [ + 24, + 4 + ], + [ + 13, + 15 + ], + [ + 14, + 12 + ], + [ + 23, + 5 + ], + [ + 9, + 13 + ], + [ + 21, + 13 + ], + [ + 16, + 13 + ], + [ + 17, + 13 + ], + [ + 19, + 13 + ], + [ + 13, + 4 + ], + [ + 4, + 10 + ], + [ + 18, + 10 + ], + [ + 26, + 0 + ], + [ + 18, + 2 + ], + [ + 12, + 1 + ], + [ + 2, + 14 + ], + [ + 19, + 12 + ], + [ + 20, + 6 + ], + [ + 21, + 15 + ], + [ + 8, + 5 + ], + [ + 25, + 15 + ], + [ + 23, + 10 + ], + [ + 21, + 11 + ], + [ + 25, + 8 + ], + [ + 1, + 8 + ], + [ + 2, + 8 + ], + [ + 20, + 4 + ], + [ + 12, + 0 + ], + [ + 17, + 8 + ], + [ + 20, + 12 + ], + [ + 5, + 15 + ], + [ + 10, + 5 + ], + [ + 26, + 1 + ], + [ + 23, + 11 + ], + [ + 12, + 8 + ], + [ + 20, + 8 + ], + [ + 21, + 14 + ], + [ + 8, + 14 + ], + [ + 15, + 10 + ], + [ + 19, + 2 + ], + [ + 16, + 12 + ], + [ + 22, + 6 + ], + [ + 8, + 7 + ], + [ + 7, + 4 + ], + [ + 22, + 4 + ], + [ + 11, + 10 + ], + [ + 18, + 4 + ], + [ + 3, + 13 + ], + [ + 22, + 1 + ], + [ + 16, + 9 + ], + [ + 4, + 15 + ], + [ + 17, + 1 + ], + [ + 17, + 0 + ], + [ + 2, + 2 + ], + [ + 11, + 7 + ], + [ + 22, + 11 + ], + [ + 3, + 4 + ], + [ + 12, + 3 + ], + [ + 16, + 8 + ], + [ + 6, + 0 + ], + [ + 10, + 3 + ], + [ + 21, + 10 + ], + [ + 22, + 5 + ], + [ + 22, + 10 + ], + [ + 6, + 9 + ], + [ + 23, + 6 + ], + [ + 17, + 12 + ], + [ + 17, + 9 + ], + [ + 21, + 6 + ], + [ + 21, + 4 + ], + [ + 17, + 10 + ], + [ + 12, + 10 + ], + [ + 8, + 6 + ], + [ + 9, + 9 + ], + [ + 14, + 11 + ], + [ + 20, + 13 + ], + [ + 22, + 14 + ], + [ + 17, + 2 + ], + [ + 17, + 7 + ], + [ + 9, + 8 + ], + [ + 7, + 13 + ], + [ + 14, + 5 + ], + [ + 5, + 5 + ], + [ + 11, + 1 + ], + [ + 15, + 6 + ], + [ + 26, + 9 + ], + [ + 6, + 1 + ], + [ + 12, + 14 + ], + [ + 22, + 0 + ], + [ + 14, + 13 + ], + [ + 4, + 11 + ], + [ + 26, + 11 + ], + [ + 3, + 15 + ], + [ + 12, + 15 + ], + [ + 3, + 14 + ], + [ + 23, + 12 + ], + [ + 18, + 15 + ], + [ + 8, + 13 + ], + [ + 18, + 11 + ], + [ + 18, + 13 + ], + [ + 9, + 5 + ], + [ + 14, + 0 + ], + [ + 2, + 6 + ], + [ + 13, + 1 + ], + [ + 9, + 0 + ], + [ + 11, + 8 + ], + [ + 9, + 4 + ], + [ + 21, + 7 + ], + [ + 14, + 10 + ], + [ + 6, + 14 + ], + [ + 14, + 6 + ], + [ + 11, + 0 + ], + [ + 17, + 11 + ], + [ + 3, + 3 + ], + [ + 15, + 4 + ], + [ + 15, + 14 + ], + [ + 10, + 2 + ], + [ + 18, + 6 + ], + [ + 17, + 3 + ], + [ + 11, + 6 + ], + [ + 13, + 2 + ], + [ + 10, + 4 + ], + [ + 15, + 2 + ], + [ + 15, + 5 + ], + [ + 8, + 10 + ], + [ + 9, + 10 + ], + [ + 7, + 15 + ], + [ + 1, + 13 + ], + [ + 6, + 4 + ], + [ + 12, + 12 + ], + [ + 19, + 1 + ], + [ + 19, + 6 + ], + [ + 12, + 2 + ], + [ + 19, + 0 + ], + [ + 26, + 6 + ], + [ + 11, + 5 + ], + [ + 15, + 1 + ], + [ + 9, + 7 + ], + [ + 15, + 9 + ], + [ + 3, + 2 + ], + [ + 7, + 6 + ], + [ + 16, + 6 + ], + [ + 14, + 2 + ], + [ + 15, + 11 + ], + [ + 18, + 7 + ], + [ + 20, + 5 + ], + [ + 9, + 2 + ], + [ + 23, + 9 + ], + [ + 16, + 3 + ], + [ + 20, + 2 + ], + [ + 1, + 0 + ], + [ + 10, + 11 + ], + [ + 1, + 1 + ], + [ + 21, + 5 + ], + [ + 27, + 6 + ], + [ + 5, + 14 + ], + [ + 10, + 9 + ], + [ + 15, + 3 + ], + [ + 6, + 15 + ], + [ + 7, + 11 + ], + [ + 8, + 2 + ], + [ + 10, + 13 + ], + [ + 8, + 11 + ], + [ + 14, + 7 + ], + [ + 10, + 8 + ], + [ + 23, + 13 + ], + [ + 0, + 11 + ], + [ + 1, + 3 + ], + [ + 6, + 5 + ], + [ + 5, + 4 + ], + [ + 7, + 5 + ], + [ + 8, + 12 + ], + [ + 13, + 5 + ], + [ + 7, + 0 + ], + [ + 16, + 5 + ], + [ + 0, + 10 + ], + [ + 1, + 14 + ], + [ + 7, + 10 + ], + [ + 8, + 9 + ], + [ + 26, + 12 + ], + [ + 5, + 9 + ], + [ + 9, + 14 + ], + [ + 5, + 8 + ], + [ + 13, + 3 + ], + [ + 3, + 1 + ], + [ + 5, + 7 + ], + [ + 7, + 14 + ], + [ + 15, + 0 + ], + [ + 3, + 12 + ], + [ + 6, + 3 + ], + [ + 7, + 12 + ], + [ + 2, + 15 + ], + [ + 4, + 8 + ], + [ + 5, + 11 + ], + [ + 8, + 0 + ], + [ + 12, + 5 + ], + [ + 4, + 4 + ], + [ + 5, + 6 + ], + [ + 3, + 0 + ], + [ + 3, + 9 + ], + [ + 25, + 1 + ], + [ + 4, + 2 + ], + [ + 17, + 14 + ], + [ + 9, + 11 + ], + [ + 16, + 4 + ], + [ + 15, + 15 + ], + [ + 3, + 8 + ], + [ + 11, + 9 + ], + [ + 16, + 2 + ], + [ + 18, + 8 + ], + [ + 11, + 4 + ], + [ + 11, + 15 + ], + [ + 17, + 15 + ], + [ + 21, + 2 + ], + [ + 2, + 13 + ], + [ + 10, + 12 + ], + [ + 15, + 7 + ], + [ + 12, + 13 + ], + [ + 20, + 1 + ], + [ + 0, + 3 + ], + [ + 5, + 0 + ], + [ + 4, + 3 + ], + [ + 22, + 2 + ], + [ + 8, + 8 + ], + [ + 0, + 0 + ], + [ + 26, + 13 + ], + [ + 27, + 10 + ], + [ + 0, + 2 + ], + [ + 5, + 1 + ], + [ + 10, + 15 + ], + [ + 20, + 0 + ], + [ + 27, + 1 + ] + ] +} \ No newline at end of file diff --git a/scripts/alignment_heads_qwen3_asr_1.7B.png b/scripts/alignment_heads_qwen3_asr_1.7B.png new file mode 100644 index 0000000000000000000000000000000000000000..d5641322d17957435c1b26a85d453731c0c782b2 GIT binary patch literal 85188 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 n{O9!k|M(RD|K)8a$u#5u;g5rAz1 literal 0 HcmV?d00001 diff --git a/scripts/detect_alignment_heads_qwen3.py b/scripts/detect_alignment_heads_qwen3.py new file mode 100644 index 0000000..6cb268e --- /dev/null +++ b/scripts/detect_alignment_heads_qwen3.py @@ -0,0 +1,703 @@ +#!/usr/bin/env python3 +""" +Detect alignment heads in Qwen3-ASR for SimulStreaming-style inference. + +Qwen3-ASR is a decoder-only multimodal model: audio is encoded by an audio +encoder and the resulting embeddings are injected into the text sequence +(replacing <|audio_pad|> placeholder tokens). The text decoder then attends +over the full sequence -- both audio-derived tokens and text tokens -- via +causal self-attention. There is **no** cross-attention. + +For AlignAtt-style streaming, we need to find which (layer, head) pairs in +the text decoder's self-attention best track the monotonic alignment between +generated text tokens and their corresponding audio positions. + +Algorithm +--------- +For each audio sample with a known transcript: + 1. Run Qwen3-ASR with output_attentions=True + 2. Use the ForcedAligner to get ground-truth word->timestamp alignments + 3. Convert timestamps to audio token positions in the input sequence + 4. For each generated text token, check whether the argmax of each + attention head (over the audio-token region) points to the correct + audio position (as determined by the forced aligner) + 5. Accumulate scores per (layer, head) + +The heads whose attention argmax matches the ground-truth alignment most +often are the "alignment heads" usable for SimulStreaming. + +Reference: Adapted from scripts/determine_alignment_heads.py (Whisper) and + iwslt26-sst/SimulMT_tests/heads/detect_translation_heads_qwen3.py +""" + +import argparse +import io +import json +import logging +import re +import time +from difflib import SequenceMatcher +from typing import List, Optional, Tuple + +import numpy as np +import soundfile as sf +import torch + +logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") +logger = logging.getLogger(__name__) + +# ── Compatibility patches for qwen_asr 0.0.6 + transformers >= 5.3 ──── +def _apply_transformers_compat_patches(): + """Apply all necessary patches to make qwen_asr work with transformers >= 5.3.""" + # 1. check_model_inputs was removed + try: + import transformers.utils.generic as _g + if not hasattr(_g, "check_model_inputs"): + def check_model_inputs(*args, **kwargs): + def decorator(fn): + return fn + return decorator + _g.check_model_inputs = check_model_inputs + except ImportError: + pass + + # 2. 'default' rope type was removed from ROPE_INIT_FUNCTIONS + try: + from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS + if "default" not in ROPE_INIT_FUNCTIONS: + def _compute_default_rope_parameters(config=None, device=None, seq_len=None, **kwargs): + if hasattr(config, "head_dim"): + head_dim = config.head_dim + else: + head_dim = config.hidden_size // config.num_attention_heads + partial = getattr(config, "partial_rotary_factor", 1.0) + dim = int(head_dim * partial) + base = config.rope_theta + inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.int64).float().to(device) / dim)) + return inv_freq, 1.0 + ROPE_INIT_FUNCTIONS["default"] = _compute_default_rope_parameters + except ImportError: + pass + + # 3. pad_token_id missing on thinker config + try: + from qwen_asr.core.transformers_backend.configuration_qwen3_asr import ( + Qwen3ASRThinkerConfig, + ) + if not hasattr(Qwen3ASRThinkerConfig, "pad_token_id"): + Qwen3ASRThinkerConfig.pad_token_id = None + except ImportError: + pass + + # 4. fix_mistral_regex is now handled internally by transformers 5.3; + # qwen_asr passes it explicitly, causing a duplicate-kwarg error. + try: + from transformers.models.auto import processing_auto + _orig_ap_from_pretrained = processing_auto.AutoProcessor.from_pretrained.__func__ + + @classmethod + def _patched_ap_from_pretrained(cls, *args, **kwargs): + kwargs.pop("fix_mistral_regex", None) + return _orig_ap_from_pretrained(cls, *args, **kwargs) + + processing_auto.AutoProcessor.from_pretrained = _patched_ap_from_pretrained + except Exception: + pass + + # 5. _finalize_model_loading calls initialize_weights which expects + # compute_default_rope_parameters on RotaryEmbedding modules. + try: + from qwen_asr.core.transformers_backend.modeling_qwen3_asr import ( + Qwen3ASRThinkerTextRotaryEmbedding, + ) + if not hasattr(Qwen3ASRThinkerTextRotaryEmbedding, "compute_default_rope_parameters"): + @staticmethod + def _compute_default_rope_parameters(config=None, device=None, seq_len=None, **kwargs): + if hasattr(config, "head_dim"): + head_dim = config.head_dim + else: + head_dim = config.hidden_size // config.num_attention_heads + partial = getattr(config, "partial_rotary_factor", 1.0) + dim = int(head_dim * partial) + base = config.rope_theta + inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.int64).float().to(device) / dim)) + return inv_freq, 1.0 + Qwen3ASRThinkerTextRotaryEmbedding.compute_default_rope_parameters = _compute_default_rope_parameters + except ImportError: + pass + +_apply_transformers_compat_patches() + +# ── Constants ──────────────────────────────────────────────────────── +SAMPLE_RATE = 16000 +TS_THRESHOLD = 0.1 # Minimum Translation Score to qualify as alignment head +MIN_TEXT_SIMILARITY = 0.3 # Skip clips where generated text is too different from ground truth + + +def text_similarity(generated: str, reference: str) -> float: + """Compute text similarity between generated and reference transcriptions. + + Normalizes both strings (lowercase, remove punctuation, collapse whitespace) + then returns SequenceMatcher ratio. + """ + def normalize(s): + s = s.lower() + s = re.sub(r'[^\w\s]', '', s) + return re.sub(r'\s+', ' ', s).strip() + + gen_norm = normalize(generated) + ref_norm = normalize(reference) + if not gen_norm or not ref_norm: + return 0.0 + return SequenceMatcher(None, gen_norm, ref_norm).ratio() + + +def load_dataset_clips(name, config, split, limit): + """Load audio clips from a HuggingFace dataset.""" + from datasets import Audio as DatasetAudio + from datasets import load_dataset + + ds = load_dataset(name, config, split=split) + ds = ds.cast_column("audio", DatasetAudio(decode=False)) + clips = [] + for idx, row in enumerate(ds): + if limit is not None and idx >= limit: + break + audio_field = row["audio"] + transcript = row["text"] + + waveform_np, _ = sf.read(io.BytesIO(audio_field["bytes"]), dtype="float32") + if waveform_np.ndim > 1: + waveform_np = waveform_np.mean(axis=1) + + clips.append((waveform_np, str(transcript))) + return clips + + +def get_device(): + """Select the best available device.""" + if torch.backends.mps.is_available(): + logger.info("Using MPS (Apple Silicon GPU)") + return torch.device("mps") + elif torch.cuda.is_available(): + logger.info("Using CUDA (%s)", torch.cuda.get_device_name()) + return torch.device("cuda") + else: + logger.info("Using CPU (will be slow)") + return torch.device("cpu") + + +def load_qwen3_asr(model_id: str, device: torch.device, dtype: torch.dtype): + """Load Qwen3-ASR model, processor, and forced aligner.""" + from qwen_asr.core.transformers_backend import ( + Qwen3ASRConfig, + Qwen3ASRForConditionalGeneration, + Qwen3ASRProcessor, + ) + from qwen_asr.inference.qwen3_forced_aligner import Qwen3ForcedAligner + from transformers import AutoConfig, AutoModel, AutoProcessor + + AutoConfig.register("qwen3_asr", Qwen3ASRConfig) + AutoModel.register(Qwen3ASRConfig, Qwen3ASRForConditionalGeneration) + AutoProcessor.register(Qwen3ASRConfig, Qwen3ASRProcessor) + + logger.info("Loading model: %s (dtype=%s, device=%s)", model_id, dtype, device) + model = AutoModel.from_pretrained( + model_id, + torch_dtype=dtype, + attn_implementation="eager", + device_map=str(device), + ) + model.eval() + + # Force eager attention on all sub-modules (attn_implementation="eager" doesn't + # propagate through nested model configs in qwen_asr's custom architecture) + for name, module in model.named_modules(): + if hasattr(module, "config") and hasattr(module.config, "_attn_implementation"): + module.config._attn_implementation = "eager" + module.config._attn_implementation_internal = "eager" + + try: + processor = AutoProcessor.from_pretrained(model_id, fix_mistral_regex=True) + except TypeError: + processor = AutoProcessor.from_pretrained(model_id) + + logger.info("Loading forced aligner: Qwen/Qwen3-ForcedAligner-0.6B") + forced_aligner = Qwen3ForcedAligner.from_pretrained( + "Qwen/Qwen3-ForcedAligner-0.6B", + dtype=dtype, + device_map=str(device), + ) + + return model, processor, forced_aligner + + +def find_audio_token_range(input_ids: torch.Tensor, audio_token_id: int) -> Tuple[int, int]: + """Find the start and end positions of audio tokens in the input sequence.""" + mask = (input_ids == audio_token_id) + positions = mask.nonzero(as_tuple=True)[0] + if len(positions) == 0: + return 0, 0 + return positions[0].item(), positions[-1].item() + 1 + + +def timestamp_to_audio_token_position( + timestamp_sec: float, + audio_duration_sec: float, + audio_token_start: int, + audio_token_end: int, +) -> int: + """Convert a timestamp in seconds to the corresponding audio token position. + + Audio tokens span [audio_token_start, audio_token_end) in the input sequence. + We linearly interpolate within that range based on the timestamp fraction. + """ + n_audio_tokens = audio_token_end - audio_token_start + if n_audio_tokens <= 0 or audio_duration_sec <= 0: + return audio_token_start + + fraction = min(timestamp_sec / audio_duration_sec, 1.0) + pos = audio_token_start + int(fraction * (n_audio_tokens - 1)) + return max(audio_token_start, min(pos, audio_token_end - 1)) + + +def run_detection( + model, + processor, + forced_aligner, + clips: List[Tuple[np.ndarray, str]], + language: Optional[str], + device: torch.device, +) -> Tuple[np.ndarray, int]: + """Run alignment head detection on a set of audio clips. + + Uses PyTorch forward hooks on each self_attn module to capture attention + weights that the decoder layer discards (``hidden_states, _ = self.self_attn(...)``). + With eager attention, ``self_attn`` always returns ``(attn_output, attn_weights)`` + so the hook can read the weights from the return value. + + Returns: + g: array of shape (total_heads,) with alignment hit counts + m: total number of alignment checks performed + """ + thinker = model.thinker + text_config = thinker.config.text_config + num_layers = text_config.num_hidden_layers + num_heads = text_config.num_attention_heads + total_heads = num_layers * num_heads + + audio_token_id = thinker.config.audio_token_id + + logger.info( + "Text decoder: %d layers x %d heads = %d total heads", + num_layers, num_heads, total_heads, + ) + logger.info( + "KV heads: %d (GQA ratio: %d)", + text_config.num_key_value_heads, + num_heads // text_config.num_key_value_heads, + ) + + # Build prompt helper (same as Qwen3ASRModel._build_text_prompt) + from qwen_asr.inference.utils import normalize_language_name + + def build_messages(audio_payload): + return [ + {"role": "system", "content": ""}, + {"role": "user", "content": [{"type": "audio", "audio": audio_payload}]}, + ] + + def build_text_prompt(force_language=None): + msgs = build_messages("") + base = processor.apply_chat_template(msgs, add_generation_prompt=True, tokenize=False) + if force_language: + base = base + f"language {force_language}" + return base + + force_lang = None + if language: + force_lang = normalize_language_name(language) + + # Stop token IDs + eos_ids = {151645, 151643} # <|im_end|>, <|endoftext|> + if processor.tokenizer.eos_token_id is not None: + eos_ids.add(processor.tokenizer.eos_token_id) + + # Decoder layers: model.thinker.model.layers[i].self_attn + decoder_layers = thinker.model.layers + + g = np.zeros(total_heads, dtype=np.int64) + m = 0 + t0 = time.time() + + for clip_idx, (waveform, transcript) in enumerate(clips): + if not transcript.strip(): + continue + + audio_duration = len(waveform) / SAMPLE_RATE + + # 1. Get forced alignment timestamps + try: + align_results = forced_aligner.align( + audio=[(waveform, SAMPLE_RATE)], + text=[transcript], + language=[force_lang or "English"], + ) + align_result = align_results[0] + except Exception as e: + logger.warning("Forced alignment failed for clip %d: %s", clip_idx, e) + continue + + if not align_result.items: + continue + + # Build word -> (start_time, end_time) mapping + word_timestamps = [] + for item in align_result.items: + word_timestamps.append((item.text, item.start_time, item.end_time)) + + # 2. Prepare inputs + text_prompt = build_text_prompt(force_language=force_lang) + inputs = processor( + text=[text_prompt], + audio=[waveform], + return_tensors="pt", + padding=True, + ) + inputs = inputs.to(model.device).to(model.dtype) + prompt_len = inputs.input_ids.shape[1] + + # Find audio token range + audio_start, audio_end = find_audio_token_range( + inputs.input_ids[0], audio_token_id, + ) + n_audio_tokens = audio_end - audio_start + + if n_audio_tokens == 0: + logger.warning("No audio tokens found in clip %d", clip_idx) + continue + + # 3. Register forward hooks on self_attn to capture attention weights. + # The decoder layer discards them: hidden_states, _ = self.self_attn(...) + # but eager_attention_forward always computes and returns attn_weights. + # We capture just the argmax over the audio region (memory-efficient). + # captured_argmax[layer_idx] = list of (num_heads,) tensors, one per decode step. + captured_argmax = {i: [] for i in range(num_layers)} + + def _make_hook(store, a_start, a_end): + def hook_fn(module, args, output): + # output = (attn_output, attn_weights) + attn_weights = output[1] + if attn_weights is None: + return + # attn_weights shape: (batch, num_heads, q_len, kv_len) + # Only capture decode steps (q_len == 1), skip prefill + if attn_weights.shape[2] != 1: + return + kv_len = attn_weights.shape[-1] + if a_end > kv_len: + return + # Attention from the new token over audio region + audio_attn = attn_weights[0, :, 0, a_start:a_end] # (num_heads, n_audio) + store.append(audio_attn.argmax(dim=-1).cpu()) # (num_heads,) + return hook_fn + + hooks = [] + for layer_idx in range(num_layers): + h = decoder_layers[layer_idx].self_attn.register_forward_hook( + _make_hook(captured_argmax[layer_idx], audio_start, audio_end) + ) + hooks.append(h) + + # 4. Run generation + try: + with torch.inference_mode(): + outputs = thinker.generate( + **inputs, + max_new_tokens=256, + do_sample=False, + ) + except Exception as e: + for h in hooks: + h.remove() + logger.warning("Generation failed for clip %d: %s", clip_idx, e) + continue + finally: + for h in hooks: + h.remove() + + # outputs is (batch, seq_len) tensor + all_generated = outputs[0, prompt_len:] + num_gen = len(all_generated) + for i, tid in enumerate(all_generated): + if tid.item() in eos_ids: + num_gen = i + break + generated_ids = all_generated[:num_gen] + + if num_gen == 0: + del outputs, captured_argmax + continue + + generated_text = processor.tokenizer.decode(generated_ids, skip_special_tokens=True) + + # Filter out hallucinated clips (e.g. "!!!" patterns) + sim = text_similarity(generated_text, transcript) + if sim < MIN_TEXT_SIMILARITY: + logger.info( + "[%d/%d] SKIP (sim=%.2f) | %s...", + clip_idx + 1, len(clips), sim, generated_text[:60], + ) + del outputs, captured_argmax + continue + + # Verify hooks captured data + n_captured = len(captured_argmax[0]) + if n_captured == 0: + logger.warning( + "No attention weights captured for clip %d (hooks may not have fired)", clip_idx + ) + del outputs, captured_argmax + continue + + # 5. Map generated tokens to word timestamps + gen_token_strings = [ + processor.tokenizer.decode([tid.item()]) for tid in generated_ids + ] + + # Map each generated token index -> forced-aligner word index + accumulated_text = "" + word_idx = 0 + token_to_word = {} + for tok_idx, tok_str in enumerate(gen_token_strings): + accumulated_text += tok_str + # Advance word index when accumulated text covers the current word + while ( + word_idx < len(word_timestamps) + and len(accumulated_text.strip()) >= sum( + len(w[0]) + 1 for w in word_timestamps[:word_idx + 1] + ) + ): + word_idx += 1 + actual_word_idx = min(word_idx, len(word_timestamps) - 1) + token_to_word[tok_idx] = actual_word_idx + + # 6. Score each head using captured argmax data + for gen_step in range(num_gen): + word_idx = token_to_word.get(gen_step, None) + if word_idx is None or word_idx >= len(word_timestamps): + continue + + _, word_start, word_end = word_timestamps[word_idx] + word_mid = (word_start + word_end) / 2.0 + + # Expected audio token position for this word + expected_pos = timestamp_to_audio_token_position( + word_mid, audio_duration, audio_start, audio_end, + ) + + # Tolerance: +/- a few audio tokens (proportional to word duration) + word_dur_tokens = max(1, int( + (word_end - word_start) / audio_duration * n_audio_tokens / 2 + )) + tolerance = max(3, word_dur_tokens) + + m += 1 + + for layer_idx in range(num_layers): + if gen_step >= len(captured_argmax[layer_idx]): + continue + argmaxes = captured_argmax[layer_idx][gen_step].numpy() # (num_heads,) + + for head_idx in range(num_heads): + attended_pos = argmaxes[head_idx] # relative to audio_start + attended_abs = audio_start + attended_pos + if abs(attended_abs - expected_pos) <= tolerance: + g[layer_idx * num_heads + head_idx] += 1 + + del outputs, captured_argmax + if device.type == "mps": + torch.mps.empty_cache() + elif device.type == "cuda": + torch.cuda.empty_cache() + + elapsed = time.time() - t0 + avg = elapsed / (clip_idx + 1) + eta = avg * (len(clips) - clip_idx - 1) + logger.info( + "[%d/%d] m=%d | %s... | %.1fs/clip | ETA: %.0fs", + clip_idx + 1, len(clips), m, + generated_text[:60], avg, eta, + ) + + return g, m + + +def main(): + parser = argparse.ArgumentParser( + description="Detect alignment heads in Qwen3-ASR for SimulStreaming" + ) + parser.add_argument( + "--model", type=str, default="Qwen/Qwen3-ASR-1.7B", + help="Qwen3-ASR model name or path", + ) + parser.add_argument( + "--dataset", type=str, default="librispeech_asr", + help="HuggingFace dataset name", + ) + parser.add_argument( + "--dataset-config", type=str, default="clean", + help="Dataset config/subset", + ) + parser.add_argument( + "--dataset-split", type=str, default="validation", + help="Dataset split", + ) + parser.add_argument( + "-n", "--num-samples", type=int, default=50, + help="Number of audio samples to process", + ) + parser.add_argument( + "--language", type=str, default="English", + help="Language for forced alignment", + ) + parser.add_argument( + "--dtype", type=str, default="bf16", + choices=["float32", "bf16", "float16"], + help="Model dtype", + ) + parser.add_argument( + "-o", "--output", type=str, default="alignment_heads_qwen3_asr.json", + help="Output JSON file", + ) + parser.add_argument( + "--heatmap", type=str, default="alignment_heads_qwen3_asr.png", + help="Output heatmap image", + ) + parser.add_argument( + "--threshold", type=float, default=TS_THRESHOLD, + help="Minimum alignment score threshold", + ) + args = parser.parse_args() + + device = get_device() + + dtype_map = { + "float32": torch.float32, + "bf16": torch.bfloat16, + "float16": torch.float16, + } + dtype = dtype_map[args.dtype] + + # Load model + model, processor, forced_aligner = load_qwen3_asr(args.model, device, dtype) + + # Load data + logger.info("Loading dataset: %s/%s [%s]", args.dataset, args.dataset_config, args.dataset_split) + clips = load_dataset_clips( + args.dataset, args.dataset_config, args.dataset_split, args.num_samples, + ) + logger.info("Loaded %d clips", len(clips)) + + # Run detection + g, m = run_detection(model, processor, forced_aligner, clips, args.language, device) + + # Compute alignment scores + thinker = model.thinker + text_config = thinker.config.text_config + num_layers = text_config.num_hidden_layers + num_heads = text_config.num_attention_heads + + ts = g / max(m, 1) + ts_matrix = ts.reshape(num_layers, num_heads) + + # Identify alignment heads + tah = [] + for l in range(num_layers): + for h in range(num_heads): + score = ts_matrix[l, h] + if score > args.threshold: + tah.append({"layer": l, "head": h, "ts": round(float(score), 4)}) + + tah.sort(key=lambda x: x["ts"], reverse=True) + + # Print results + print(f"\n{'=' * 60}") + print(f"ALIGNMENT HEADS (TS > {args.threshold}): {len(tah)} / {num_layers * num_heads}") + print(f"{'=' * 60}") + for entry in tah: + bar = "#" * int(entry["ts"] * 50) + print(f" L{entry['layer']:2d} H{entry['head']:2d} : TS={entry['ts']:.4f} {bar}") + + n_active = sum(1 for s in ts if s > args.threshold) + n_low = sum(1 for s in ts if 0 < s <= args.threshold) + n_zero = sum(1 for s in ts if s == 0) + total_heads = num_layers * num_heads + print(f"\nDistribution:") + print(f" TS > {args.threshold} (alignment heads): {n_active} ({100 * n_active / total_heads:.1f}%)") + print(f" 0 < TS <= {args.threshold} (low activity): {n_low} ({100 * n_low / total_heads:.1f}%)") + print(f" TS = 0 (inactive): {n_zero} ({100 * n_zero / total_heads:.1f}%)") + print(f"\nTotal alignable tokens checked: m={m}") + + # Save JSON + output = { + "model": args.model, + "language": args.language, + "num_layers": num_layers, + "num_heads": num_heads, + "num_kv_heads": text_config.num_key_value_heads, + "num_samples": len(clips), + "total_alignable_tokens": int(m), + "ts_threshold": args.threshold, + "ts_matrix": ts_matrix.tolist(), + "alignment_heads": tah, + # WhisperLiveKit-compatible format: list of [layer, head] pairs + "alignment_heads_compact": [[e["layer"], e["head"]] for e in tah], + } + with open(args.output, "w") as f: + json.dump(output, f, indent=2) + logger.info("Results saved to %s", args.output) + + # Generate heatmap + try: + import matplotlib + matplotlib.use("Agg") + import matplotlib.pyplot as plt + + fig, ax = plt.subplots( + figsize=(max(10, num_heads * 0.6), max(8, num_layers * 0.35)), + ) + im = ax.imshow( + ts_matrix, + aspect="auto", + cmap="RdYlBu_r", + vmin=0, + vmax=max(0.4, ts_matrix.max()), + interpolation="nearest", + ) + ax.set_xlabel("Head ID", fontsize=12) + ax.set_ylabel("Layer", fontsize=12) + ax.set_title( + f"Alignment Scores - {args.model}\n" + f"{len(tah)} alignment heads (TS > {args.threshold}), n={len(clips)}", + fontsize=13, + ) + ax.set_xticks(range(num_heads)) + ax.set_yticks(range(num_layers)) + plt.colorbar(im, ax=ax, label="Alignment Score", shrink=0.8) + + for entry in tah: + ax.add_patch(plt.Rectangle( + (entry["head"] - 0.5, entry["layer"] - 0.5), + 1, 1, fill=False, edgecolor="red", linewidth=1.5, + )) + + plt.tight_layout() + plt.savefig(args.heatmap, dpi=150) + logger.info("Heatmap saved to %s", args.heatmap) + except Exception as e: + logger.warning("Could not generate heatmap: %s", e) + + +if __name__ == "__main__": + main() diff --git a/scripts/generate_architecture.py b/scripts/generate_architecture.py new file mode 100644 index 0000000..7f42d45 --- /dev/null +++ b/scripts/generate_architecture.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python3 +"""Generate the architecture.png diagram for WhisperLiveKit README.""" + +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt +import matplotlib.patches as mpatches +from matplotlib.patches import FancyBboxPatch, FancyArrowPatch + +# ── Colours ── +C_BG = "#1a1a2e" +C_PANEL = "#16213e" +C_PANEL2 = "#0f3460" +C_ACCENT = "#e94560" +C_GREEN = "#4ecca3" +C_ORANGE = "#f5a623" +C_BLUE = "#4a9eff" +C_PURPLE = "#b06af2" +C_PINK = "#ff6b9d" +C_YELLOW = "#f0e68c" +C_TEXT = "#e8e8e8" +C_TEXTDIM = "#a0a0b0" +C_BOX_BG = "#1e2d4a" +C_BOX_BG2 = "#2a1a3a" +C_BOX_BG3 = "#1a3a2a" +C_BORDER = "#3a4a6a" + +fig, ax = plt.subplots(1, 1, figsize=(20, 12), facecolor=C_BG) +ax.set_xlim(0, 20) +ax.set_ylim(0, 12) +ax.set_aspect("equal") +ax.axis("off") +fig.subplots_adjust(left=0.01, right=0.99, top=0.97, bottom=0.01) + + +def box(x, y, w, h, label, color=C_BORDER, bg=C_BOX_BG, fontsize=8, bold=False, + text_color=C_TEXT, radius=0.15): + rect = FancyBboxPatch( + (x, y), w, h, + boxstyle=f"round,pad=0.05,rounding_size={radius}", + facecolor=bg, edgecolor=color, linewidth=1.2, + ) + ax.add_patch(rect) + weight = "bold" if bold else "normal" + ax.text(x + w/2, y + h/2, label, ha="center", va="center", + fontsize=fontsize, color=text_color, fontweight=weight, family="monospace") + return rect + + +def arrow(x1, y1, x2, y2, color=C_TEXTDIM, style="->", lw=1.2): + ax.annotate("", xy=(x2, y2), xytext=(x1, y1), + arrowprops=dict(arrowstyle=style, color=color, lw=lw)) + + +def section_box(x, y, w, h, title, bg=C_PANEL, border=C_BORDER, title_color=C_ACCENT): + rect = FancyBboxPatch( + (x, y), w, h, + boxstyle="round,pad=0.05,rounding_size=0.2", + facecolor=bg, edgecolor=border, linewidth=1.5, + ) + ax.add_patch(rect) + ax.text(x + 0.15, y + h - 0.25, title, ha="left", va="top", + fontsize=9, color=title_color, fontweight="bold", family="monospace") + + +# ═══════════════════════════════════════════════════════════════════ +# Title +# ═══════════════════════════════════════════════════════════════════ +ax.text(10, 11.7, "WhisperLiveKit Architecture", ha="center", va="center", + fontsize=16, color=C_TEXT, fontweight="bold", family="monospace") +ax.text(10, 11.35, "CLI commands: serve | listen | run | transcribe | bench | diagnose | models | pull | rm | check", + ha="center", va="center", fontsize=7, color=C_TEXTDIM, family="monospace") + +# ═══════════════════════════════════════════════════════════════════ +# Left: Client / Server +# ═══════════════════════════════════════════════════════════════════ +section_box(0.1, 7.0, 3.5, 4.0, "FastAPI Server", border=C_GREEN) + +box(0.3, 10.0, 1.5, 0.5, "Web UI\nHTML + JS", color=C_GREEN, fontsize=7) +box(2.0, 10.0, 1.4, 0.5, "Frontend\n(optional)", color=C_GREEN, fontsize=7) + +box(0.3, 9.1, 3.1, 0.6, "WebSocket /asr • /v1/listen", color=C_GREEN, fontsize=7, bold=True) +box(0.3, 8.3, 3.1, 0.5, "REST /v1/audio/transcriptions", color=C_GREEN, fontsize=7) +box(0.3, 7.4, 3.1, 0.5, "Health • /v1/models", color=C_GREEN, fontsize=7) + +# Clients +ax.text(0.2, 6.5, "Clients:", fontsize=7, color=C_TEXTDIM, family="monospace") +for i, client in enumerate(["Browser", "OpenAI SDK", "Deepgram SDK", "TestHarness"]): + box(0.3 + i * 0.9, 5.8, 0.8, 0.5, client, fontsize=5.5, bg="#1a2a1a", color="#3a6a3a") + +# ═══════════════════════════════════════════════════════════════════ +# Centre: Audio Processor (per-session pipeline) +# ═══════════════════════════════════════════════════════════════════ +section_box(4.0, 5.5, 5.5, 5.5, "Audio Processor (per session)", border=C_BLUE) + +box(4.3, 10.0, 2.0, 0.6, "FFmpeg\nDecoding", color=C_BLUE, bg="#1a2a4a", bold=True) +arrow(3.6, 9.4, 4.3, 10.2, color=C_GREEN) + +box(6.6, 10.0, 2.6, 0.6, "Silero VAD\nspeech / silence", color=C_BLUE, bg="#1a2a4a") +arrow(6.3, 10.3, 6.6, 10.3, color=C_BLUE) + +box(4.3, 8.8, 4.9, 0.8, "SessionASRProxy\nthread-safe per-session language override", color=C_BLUE, fontsize=7) +arrow(6.0, 10.0, 6.0, 9.6, color=C_BLUE) + +box(4.3, 7.6, 2.3, 0.8, "DiffTracker\n(opt-in ?mode=diff)", color="#5a5a7a", fontsize=7) +box(6.9, 7.6, 2.3, 0.8, "Result Formatter\n→ FrontData.to_dict()", color=C_BLUE, fontsize=7) + +# Streaming policies +ax.text(4.3, 7.1, "Streaming policies:", fontsize=7, color=C_ORANGE, fontweight="bold", family="monospace") +box(4.3, 6.2, 2.3, 0.7, "LocalAgreement\nHypothesisBuffer", color=C_ORANGE, bg="#2a2a1a", fontsize=7) +box(6.9, 6.2, 2.3, 0.7, "SimulStreaming\nAlignAtt (Whisper)", color=C_ORANGE, bg="#2a2a1a", fontsize=7) + +# ═══════════════════════════════════════════════════════════════════ +# Right: TranscriptionEngine (singleton) +# ═══════════════════════════════════════════════════════════════════ +section_box(10.0, 0.3, 9.8, 10.7, "TranscriptionEngine (singleton — shared across sessions)", + border=C_ACCENT, bg="#1e1520") + +ax.text(10.2, 10.5, "6 ASR Backends", fontsize=9, color=C_ACCENT, fontweight="bold", family="monospace") + +# ── Whisper backends ── +section_box(10.2, 7.3, 4.5, 3.0, "Whisper Family (chunk-based)", border=C_PURPLE, bg=C_BOX_BG2) + +box(10.4, 9.2, 1.3, 0.6, "Faster\nWhisper", color=C_PURPLE, bg="#2a1a3a", fontsize=7, bold=True) +box(11.9, 9.2, 1.3, 0.6, "MLX\nWhisper", color=C_PURPLE, bg="#2a1a3a", fontsize=7, bold=True) +box(13.4, 9.2, 1.1, 0.6, "OpenAI\nWhisper", color=C_PURPLE, bg="#2a1a3a", fontsize=7) + +ax.text(10.4, 8.7, "PCM → Encoder → Decoder → Tokens", fontsize=6.5, color=C_TEXTDIM, family="monospace") +ax.text(10.4, 8.3, "Uses LocalAgreement or SimulStreaming (AlignAtt)", fontsize=6, color=C_PURPLE, family="monospace") +ax.text(10.4, 7.9, "Language detection • Buffer trimming", fontsize=6, color=C_TEXTDIM, family="monospace") +ax.text(10.4, 7.5, "CPU / CUDA / MLX", fontsize=6, color=C_TEXTDIM, family="monospace") + +# ── Voxtral backends ── +section_box(10.2, 3.8, 4.5, 3.2, "Voxtral (native streaming)", border=C_PINK, bg="#2a1520") + +box(10.4, 5.9, 1.8, 0.6, "Voxtral MLX\n(Apple Silicon)", color=C_PINK, bg="#2a1520", fontsize=7, bold=True) +box(12.5, 5.9, 2.0, 0.6, "Voxtral HF\n(CUDA/MPS/CPU)", color=C_PINK, bg="#2a1520", fontsize=7, bold=True) + +ax.text(10.4, 5.4, "Incremental encoder → Autoregressive decoder", fontsize=6.5, color=C_TEXTDIM, family="monospace") +ax.text(10.4, 5.0, "Sliding KV cache • Token-by-token output", fontsize=6, color=C_PINK, family="monospace") +ax.text(10.4, 4.6, "No chunking needed — truly streams audio", fontsize=6, color=C_TEXTDIM, family="monospace") +ax.text(10.4, 4.2, "4B params • 15 languages • 6-bit quant (MLX)", fontsize=6, color=C_TEXTDIM, family="monospace") + +# ── Qwen3 backend ── +section_box(15.0, 3.8, 4.6, 3.2, "Qwen3 ASR (batch + aligner)", border=C_GREEN, bg=C_BOX_BG3) + +box(15.2, 5.9, 2.0, 0.6, "Qwen3 ASR\n1.7B / 0.6B", color=C_GREEN, bg="#1a3a2a", fontsize=7, bold=True) +box(17.4, 5.9, 2.0, 0.6, "Forced\nAligner", color=C_GREEN, bg="#1a3a2a", fontsize=7) + +ax.text(15.2, 5.4, "Full-audio batch inference", fontsize=6.5, color=C_TEXTDIM, family="monospace") +ax.text(15.2, 5.0, "ForcedAligner provides word timestamps", fontsize=6, color=C_GREEN, family="monospace") +ax.text(15.2, 4.6, "Uses LocalAgreement for streaming output", fontsize=6, color=C_TEXTDIM, family="monospace") +ax.text(15.2, 4.2, "12 languages • CUDA/MPS/CPU", fontsize=6, color=C_TEXTDIM, family="monospace") + +# ── OpenAI API ── +box(15.2, 7.7, 4.2, 0.6, "OpenAI API (cloud)", color="#5a6a7a", fontsize=7) +ax.text(15.2, 7.4, "Remote transcription • API key required", fontsize=6, color=C_TEXTDIM, family="monospace") + +# ── Shared components ── +section_box(10.2, 0.5, 9.4, 3.0, "Shared Components", border="#5a6a7a", bg="#151520") + +box(10.4, 2.2, 2.5, 0.8, "Mel Spectrogram\ncached DFT + filterbank", + color="#5a6a7a", fontsize=7) +box(13.2, 2.2, 2.5, 0.8, "Diarization\nSortformer / pyannote", + color="#5a6a7a", fontsize=7) +box(16.0, 2.2, 3.4, 0.8, "Translation\nNLLB • CTranslate2", + color="#5a6a7a", fontsize=7) + +box(10.4, 0.8, 4.0, 0.8, "WhisperLiveKitConfig\n(single source of truth)", + color=C_ACCENT, fontsize=7, bold=True) +box(14.8, 0.8, 4.6, 0.8, "TestHarness\nfull pipeline testing without server", + color="#5a6a7a", fontsize=7) + +# ═══════════════════════════════════════════════════════════════════ +# Arrows: main data flow +# ═══════════════════════════════════════════════════════════════════ + +# Audio processor → TranscriptionEngine +arrow(9.5, 8.5, 10.2, 8.5, color=C_ACCENT, lw=2) +ax.text(9.6, 8.8, "PCM audio", fontsize=6, color=C_ACCENT, family="monospace") + +# TranscriptionEngine → Audio processor (results) +arrow(10.2, 7.0, 9.5, 7.0, color=C_GREEN, lw=2) +ax.text(9.6, 7.3, "ASRTokens", fontsize=6, color=C_GREEN, family="monospace") + +# Streaming policy connections +arrow(5.5, 6.2, 5.5, 5.5, color=C_ORANGE, style="->") +arrow(8.1, 6.2, 8.1, 5.5, color=C_ORANGE, style="->") +ax.text(4.3, 5.6, "Whisper + Qwen3", fontsize=5.5, color=C_ORANGE, family="monospace") +ax.text(6.9, 5.6, "Whisper + Qwen3-simul", fontsize=5.5, color=C_ORANGE, family="monospace") + +# Voxtral note (no policy needed) +ax.text(10.2, 3.5, "Voxtral: own streaming processor (no external policy)", fontsize=6, + color=C_PINK, family="monospace", style="italic") + + +# ═══════════════════════════════════════════════════════════════════ +# Legend +# ═══════════════════════════════════════════════════════════════════ +legend_y = 5.0 +ax.text(0.3, legend_y, "Streaming modes:", fontsize=7, color=C_TEXT, fontweight="bold", family="monospace") +for i, (label, color) in enumerate([ + ("Native streaming (Voxtral)", C_PINK), + ("Chunk-based (Whisper)", C_PURPLE), + ("Batch + aligner (Qwen3)", C_GREEN), +]): + ax.plot([0.3], [legend_y - 0.4 - i * 0.35], "s", color=color, markersize=6) + ax.text(0.6, legend_y - 0.4 - i * 0.35, label, fontsize=6.5, color=color, + va="center", family="monospace") + + +plt.savefig("architecture.png", dpi=200, facecolor=C_BG, bbox_inches="tight", pad_inches=0.1) +print("Saved architecture.png")