Justme0 的博客

撷英采华,以备不需

Asr

大模型ASR推理过程分析


Qwen3 在2026年初开源了ASR语音识别模型,引起Redis作者antirez的注意,他用C语言重写了推理部分的代码 [1],依赖很少,方便理解整个过程,下方是流程图。

16kHz PCM → FBank 频谱 → Conv2D ×3 (8× downsample) → Transformer Encoder → Projector → Qwen3 Decoder → Tokens

1. Tokenizer load 1%

模型加载

2. 音频预处理(PCM变换为频谱) 1%

过程:预加重、分帧、加窗;短时FFT;Mel滤波。

分帧:每帧20或25ms,为防止割裂保持平滑性,取帧时与前后帧边界重叠, 窗口每次移动10ms,所以 100 frames/s。

短时FFT:重点, 将窗口内时域转为频域

Mel刻度:音高与频率是对数关系,符合人耳听觉。来自心理学中的Weber-Fechner定律(也称对数定律),除了听觉音高,还适用于听觉响度、味觉、触觉等。

\[mel(f) = 2595 \space log_{10}{(1 + f/700)}\]

1000以下近似线性,以上对数关系。

mel mel刻度

spectrom_zh.png 语谱图

FBank

取能量谱,经mel滤波器组滤波,将频率范围按对数方式划分为n段,人耳感觉到每段的音高差异相同,得到FBank。

\(E_k=\sum_{f}|X(f)|^2 \cdot H_k(f)\) 其中 $X(f)$是频率点的幅度,$ H_k(f) $是三角滤波器权重,k是mel bin序号,从0到n-1。

Bin 0:    20 -   45 Hz   (low bass)
Bin 1:    45 -   71 Hz
Bin 2:    71 -   98 Hz
...
Bin 60:  1000 - 1100 Hz  (mid, speech fundamentals)
...
Bin 127: 7200 - 8000 Hz  (high, sibilants like "s", "t")

3. Encode 43%

3.1 Conv2D 22%

将FBank下采样(压缩),减少数据量。

使用卷积kernel(也称channel/filter/mask)提取特征,一种kernel负责提取一种特征。

Why Compress:

The transformer’s attention is $O(n^2)$. Processing all 1,276 mel frames directly:

mel frame: 1,276 × 1,276 = 1,628,176 attention pairs ← expensive! token: 166 × 166 = 27,556 attention pairs ← 59× cheaper!

The Conv2D stem compresses 8× (1,276 → 166) while preserving the important speech information. The 3 Conv2D layers learn what to keep and what to discard — they keep phoneme boundaries, formant transitions, and pitch changes, while discarding redundant information between adjacent frames.

  Edge detector:          Blur:                  Sharpen:
  ┌────┬────┬────┐        ┌─────┬─────┬─────┐   ┌────┬────┬────┐
  │ -1 │ -1 │ -1 │        │ 1/9 │ 1/9 │ 1/9 │   │  0 │ -1 │  0 │
  ├────┼────┼────┤        ├─────┼─────┼─────┤   ├────┼────┼────┤
  │ -1 │  8 │ -1 │        │ 1/9 │ 1/9 │ 1/9 │   │ -1 │  5 │ -1 │
  ├────┼────┼────┤        ├─────┼─────┼─────┤   ├────┼────┼────┤
  │ -1 │ -1 │ -1 │        │ 1/9 │ 1/9 │ 1/9 │   │  0 │ -1 │  0 │
  └────┴────┴────┘        └─────┴─────┴─────┘   └────┴────┴────┘

考察1s音频:

考察单个token的变换如下(注意代码和论文中的向量是横向量,线性代数教科书中的向量通常是列向量) \(\alpha_{1 \times 7680} \cdot A_{7680\times 896} = \beta_{ 1 \times 896}\)

参数汇总:

以上是音频相关的内容,token化得到 input embedding,接下来是LLM通用的步骤,也适用于图片、视频、文本token化之后的处理。

3.2 Transformer 21%

transformer transformer架构

Positional Encoding

transformer如何利用输入序列中token的前后位置信息?

/* Add per-chunk sinusoidal position embeddings (starting from pos 0) */
float *pe = (float *)malloc(w3 * d_model * sizeof(float));
qwen_sinusoidal_pe(pe, w3, d_model);
qwen_add_inplace(projected, pe, w3 * d_model);

void qwen_sinusoidal_pe(float *pe, int n_pos, int d_model) {
    int half = d_model / 2;
    float log_timescale = logf(10000.0f) / (float)(half - 1);

    for (int p = 0; p < n_pos; p++) {
        float *row = pe + p * d_model;
        for (int d = 0; d < half; d++) {
            float inv_timescale = expf(-(float)d * log_timescale);
            float angle = (float)p * inv_timescale;
            row[d] = sinf(angle);          /* first half: sin */
            row[half + d] = cosf(angle);   /* second half: cos */
        }
    }
}

考察1s音频:

\[PE_{(p, d)} = sin(p*0.0001^{d/(d_{model}/2-1)}) \approx sin(p * 0.9796^d)\] \[PE_{(p, d_{model}/2+d)} = cos(p*0.0001^{d/(d_{model}/2-1)}) \approx cos(p * 0.9796^d)\]

前一半维度用sin,后一半用cos,使两个向量两两不同。为什么不能只用sin? 注:Attention论文中是偶数维用sin,奇数维用cos,类似于PCM的两种排列方式 interleaved 和 planar。

函数图像:

sin.png

sin PE

cos.png

cos PE

最后将PE向量与token向量相加,得到最终的embedding。

Attention

LayerNorm 数据处理技巧,将一个token向量标准化为均值0、方差1,避免数值间相差太大。

注:规范名称应是 Standardization(标准化) 或者 z-score ,不是 Normalization (归一化,有 L1, L2, min-max 等) [2]

token预处理成Query/Key/Value向量

为降低理解门槛,考察单个token向量 x ,通过三个训练时得到的weight矩阵 $W_q$, $W_k$, $W_v$和三个bias向量(有的模型没有),分别得到 q, k, v 三个向量。

\[q = x \cdot W_q + b_q \\ k = x \cdot W_k + b_k\\ v = x \cdot W_v + b_v\]

以句子 “猫在睡觉,它很可爱” 为例: x=“它”,$W_q$ → q:我要查【前文被指代的名词】 x=“猫“,$W_k$ → k:我是【可被指代的实体名词】→ 匹配成功,高分(后面将介绍计算方法),v:携带【猫的所有实际语义:动物、在睡觉】

Without these projections, attention would just compare raw embeddings directly. The learned projections allow the model to learn what aspects of the input to compare (keys vs. queries) and what information to pass forward (values).

双向注意力 所有token预处理后写成矩阵形式 Q, K, V.

\[Attention(Q, K, V) = softmax( \frac{ Q K^T } {\sqrt{d}}) V\]

$QK^T$的含义是两两token(包括自己和自己)的q向量与k向量求内积$\langle q, k \rangle=qk^T$,表示相似度。比如有3个token:

\[QK^T =\begin{pmatrix} q_1 \\ q_2 \\ q_3 \end{pmatrix} \begin{pmatrix} k_1 \\ k_2 \\ k_3 \end{pmatrix}^T =\begin{pmatrix} q_1 \\ q_2 \\ q_3 \end{pmatrix} \begin{pmatrix} k_1^T & k_2^T &k_3^T \end{pmatrix} = \begin{pmatrix} \langle q_1, k_1 \rangle & \langle q_1, k_2 \rangle & \langle q_1, k_3 \rangle \\ \langle q_2, k_1 \rangle & \langle q_2, k_2 \rangle & \langle q_2, k_3 \rangle \\ \langle q_3, k_1 \rangle & \langle q_3, k_2 \rangle & \langle q_3, k_3 \rangle \end{pmatrix}\]

除以$\sqrt{d}$ 和 softmax 可认为是一种数据处理技巧,避免数值间相差太大。由前面的LayerNorm得知$\langle q, k \rangle$标准差是$\sqrt{d}$,除以它使标准化;softmax对矩阵的每一行单独处理,处理后得到权重,用这些权重对Value加权求和。

\[\begin{pmatrix} w_{11} & w_{12} & w_{13} \\ w_{21} & w_{22} & w_{23} \\ w_{31} & w_{32} & w_{33} \end{pmatrix} \begin{pmatrix} v_1 \\ v_2 \\ v_3 \end{pmatrix} =\begin{pmatrix} \sum_{k=1}^{3} w_{1k}v_k \\ \sum_{k=1}^{3} w_{2k}v_k \\ \sum_{k=1}^{3} w_{3k}v_k \end{pmatrix}\]

output proj

Feed-Forward Network (FFN)

Processing Gathered Information

After attention gathers context, FFN processes it through a wider hidden layer:

  x [166, 896]  →  fc1 [896, 3584]  →  GELU  →  fc2 [3584, 896]  →  x [166, 896]
                       ↑ expand 4×              ↑ compress back

896 → 3584: “expand and look at the data from 3584 different angles” GELU: “keep useful signals, suppress noise” 3584 → 896: “compress back to original size with new understanding”

How 18 Layers Build Understanding

Each layer adds more abstraction:

Example for “今天天气不错” (nice weather today):

After layer 3: tokens know: [jin] [tian] [tian] [qi] [bu] [cuo] After layer 10: tokens know: [jintian] [tianqi] [bucuo] After layer 18: tokens know: [今天] [天气] [不错] with full context

3.3 projection

4. Prefill 42%

5. Decode 13%

6. Overhead

后记

看了antirez的其他仓库,还有AI生成图片的项目。

[1] qwen-asr C语言版 https://github.com/antirez/qwen-asr [2] Normalization v.s. Standardization https://stats.stackexchange.com/a/10298

机器学习模型评价指标整理

如何量化机器学习的模型性能?本文整理了机器学习模型性能度量指标,主要是我对这些指标的一些思考。这里说的“性能”指模型泛化(即预测)能力 performance,不是指在机器上运行消耗资源的多少。

1. recall & precision

最常见的指标有recall(召回率,查全率),precision(查准率)。“召回”一词来自制造业,比如某款汽车售卖到市场上后发现有安全问题需要回收,关心有没有把所有有问题的汽车都找到回收了,以及有没有误回收[1]。

另外还有准确率、精确率的叫法,各个地方翻译得不一样,中文的“博大精深”,在这里增加了不必要的麻烦,比如accuracy网络上大多称准确率,周志华《机器学习》书中称为“精度”,而网络上是将precision称为精确率。精确率、准确率本身也不够见名知义,本文将用英文单词叙述。我读研时是做程序静态分析的,用工具查找程序缺陷,在这个领域用的指标是漏报率(false negative rate)和误报率(false discovery rate,注意不叫 false positive rate),漏报率就是1-recall,误报率是1-precision,这两个名称能够见名知义。

维基百科上这张图总结得很全[2],红框中是常用的指标。

image.png

WebRTC 浏览器端如何抓取和解密 SRTP

WebRTC 默认使用加密协议 SRTP 传输数据,抓包时看不到明文,不便于排查问题。

一种方法是下载开发版浏览器关闭加密选项,需要通讯的对端支持;

另一种方法是打开浏览器的 debug 选项,dump SRTP 解密后的 RTP 数据,下面先介绍这种方法。

1. dump RTP 明文

以 Windows 为例,关闭所有浏览器实例后,cmd下使用下面的选项打开浏览器,浏览器路径换成你的。

"C:\Program Files\Google\Chrome\Application\chrome.exe" --enable-logging --v=1 --force-fieldtrials=WebRTC-Debugging-RtpDump/Enabled/

字符编码小结

记得几年前有次需要写个简单的脚本,开始用的Python碰到中文编码问题,而且Python2和3规则不同,折腾了之后改用Ruby分分钟就搞定了,感觉Ruby的开发效率更高,几乎没有“令人惊讶”的设计;Python以缩进表示层级有时也带来不便,其他语言可以用clang-format自动格式化,也能保持风格的一致。

Python在AI的生态很好,最近写这块程序碰到bytesstr转换时字符编码的问题,平常也时常碰到乱码的困惑,比如打开文件或者浏览网页乱码,尝试换一下编码就ok了,但是没有深究原理。这次彻底把字符编码弄清楚了。

下面说下常见的编码,ASCII, latin-1, Unicode, UTF-8(UTF-16/32),这几种在Python中常见。

WebRTC TURN 协议源码分析

WebRTC 是2011年谷歌开源的媒体框架,可以在浏览器中进行实时音视频通信,它是为P2P通信设计的,开发者也可以自己搭建服务器作为通信的一端。在下面这些网络条件限制严格的场景下不能直接建立通信,需要借助中转服务器TURN(Traversal Using Relays around NAT)转发。

  1. 一端是对称型NAT,另一端是端口限制锥形NAT或者也是对称型NAT,无法建立P2P。这个工具可以检测自己网络的NAT类型 https://github.com/aarant/pynat
  2. 对网络出口限制严格的环境,比如银行、政府单位,要求访问的外网IP地址需要加到其网关白名单。可以独立部署TURN服务器,将TURN的公网IP地址加到白名单。
  3. 对安全要求极端严格的防火墙,不允许UDP通信,甚至只允许TLS over 443端口的流量。(来源 https://security.stackexchange.com/a/196330

TURN 流程分析

协议分为三部分

  1. 在TURN服务器上创建传输资源,称为 allocation
  2. indication 方式传输数据
  3. channel 方式传输数据

要注意的是,这两种传输数据的方式是并列关系。三部分的流程时序图如下(可右键打开,放大查看文本格式),client参考WebRTC代码,server参考pion/turn代码。

【转】RTMP 协议规范

由于RTMP规范不在RFC官网上,为方便查看,转自 https://github.com/melpon/rfc/blob/master/rtmp.md,同 Adobe 官方标准 https://www.adobe.com/content/dam/acom/en/devnet/rtmp/pdf/rtmp_specification_1.0.pdf

Copyright Adobe Systems Incorporated                    H. Parmar, Ed.
                                                    M. Thornburgh, Ed.
                                                                 Adobe
                                                     December 21, 2012

Adobe’s Real Time Messaging Protocol

Abstract

This memo describes Adobe’s Real Time Messaging Protocol (RTMP), an application-level protocol designed for multiplexing and packetizing multimedia transport streams (such as audio, video, and interactive content) over a suitable transport protocol (such as TCP).

水垢

电水壶用了大半年,某天早晨起床后倒杯水,看到水中有一些杂质,开始以为是水质有问题,后来看了水壶中飘着一层薄膜状的东西,是烧水之后才出现的,水壶底和内壁上有一些刮痕状的东西,应该是水垢。回顾起中学化学的知识,查了一些资料,对水垢的来龙去脉做下记录,以后可以更好地处理生活上的问题。

水垢形成的主要过程

1, 空气中的$\ce{CO2}$与水结合形成$\ce{H2CO3}$,落到地面。

\[\ce{CO_2 +H_2O -> H_{2}CO_3}\]