Qwen2.5Omni解析
本文以Qwen2.5-Omni-7B
为例解析该模型。
Audio部分
1. 音频前处理
第一步:读取音频数据
第一步:比如20s的视频,原始采样率为44.100kHz。audio会用16kHz采样率重采样,得到335459个浮点数值,范围是[-1.0, 1.0]。为什么不是320000个浮点数值?这是因为原始采样率与16000存在四舍五入补帧情况,导致多采样部分。
第二步:特征提取
用WhisperFeatureExtractor进行特征处理,主要是采用fbank (Filter Bank)特征提取,将音频数据转换成机器学习的特征向量,过程包括预加重、分帧、加窗、短时傅里叶变化(STFT)、梅尔滤波。函数参见_torch_extract_fbank_features
输入值:[335459] float
过程:
reshape => [335459, 1] float
padding => [1, 4800000, 1] float + [1, 4800000] int32 仅前335459为有效值
transpose => [1, 1, 4800000] float
extract_fbank_features => [1, 128, 30000] float
返回值:
input_features: [1, 128, 30000] float
attention_mask: [1, 30000] int32 # 前2097为1,后全0
第三步:进一步预处理
audio_feature_lengths = sum(attention_mask) = 2097
input_features = permute(0,2,1) => [128, 2097] float
audio_feat_lengths = 1049
#进一步根据chunk = 200 进行分组
input_features = [11, 128, 200]
padded_mask = [11, 200] # 前10组全1,最后一组97个1
2. Qwen2_5OmniAudioEncoder
它是一个典型的transformers结构。
输入:[11, 128, 200]
conv1d (d_model, 128, 3) => [11, d_model, 200]
conv1d (d_model, d_model, 3), stride = 2 => [11, d_model, 100]
position_embedding + => [11, d_model, 100]
permute => [11, 100, d_model]
32x(attention+mlp) => [11, 100, d_model]
# merge
dim 1 average => [11, 50, d_model]
mm (d_model, hidden_size) => [11, 50, hidden_size]
reshape => [550, hidden_size]
由于有mask存在,最后一组只有前97有效,最终输出为[524, hidden_size]
3. 音频Tokens数计算
这里忽略音频重采样补帧情况,做粗略计算。
2秒音频取32000个浮点数值,经过预处理得到[1, 128, 200]
,经过模型推理得到[50, hidden_size]
;
所以可以粗略计算为:每秒音频约占25 token。
Vision部分
这部分与Qwen2.5VL相同vision部分
LLM 部分
Token如何摆放
以20s视频为例,音频占500 token;视频采用280x504分辨率,占1800 token;假定文本token占52;总token数为2352。通过pdb跟踪得到token摆放顺序如下:
内容 | token数 |
---|---|
文本 | 45 |
图像 | 180 |
音频 | 50 |
…… | …… |
图像 | 180 |
音频 | 50 |
文本 | 7 |
为何是如此摆放?这涉及到对replace_multimodal_special_tokens
的解读。输入text如下:
['<|im_start|>system\nYou are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generat
ing text and speech.<|im_end|>\n<|im_start|>user\n<|vision_bos|><|VIDEO|><|vision_eos|><|im_end|>\n<|im_start|>assistant\n']
文本部分直接转成相应token,重点是VIDEO部分的处理。
- 音频每秒25 token,视频每2秒180 token
seconds_per_chunk
为2.0,表示每个chunk为2s。所以20s视频分成了10个chunk,180个token视频+50个token音频为一个chunk。
Position ID是如何排列
position id为3维,position_id_per_seconds
为25,代表每秒间隔id为25。
id配置如下:
- 时序id方面:文本id累增,音频id以25为单位增加;视频id以50为单位增加,与fps有关
- hw维度:文本和音频与时序id一致;视频按照hw的顺利排布
具体ID排列如下:
内容 | token数 | id |
---|---|---|
文本 | 45 | T: 0,1,2,3, … 43,43; H和W与T完全一致 |
图像 | 180 | T: 44,44,44,…,44,44; H: 44(18个),45(18个),…,53(18个); W: [44, 61]共10个 |
音频 | 50 | T: 44,45,46,…,92,93; H和W与T完全一致 |
…… | …… | |
图像 | 180 | T: 494,494,494,…,494,494; H: 44(18个),45(18个),…,53(18个); W: [44, 61]共10个 |
音频 | 50 | T: 494,495,496,…,542,543; H和W与T完全一致 |
文本 | 7 | T: 544,544,545,546,547,548,549;H和W与T完全一致 |
推理过程
标准的embeding + num_layers x Block + lm_head结构
Talker部分
(待补充)