当前位置: 首页 > news >正文

Qwen-Audio:一种新的大规模音频-语言模型

1. 方案简介

现有的多任务语言模型主要关注特定类型的音频(如人类语音)或特定任务(如语音识别和字幕生成),限制了模型的通用性和交互能力。于是提出了一个新颖的音频-语言模型,该模型拥有通用音频理解模型的能力,结构图如下。

从上图可以看出Qwen-Audio结合了一个音频编码器和一个基于Qwen-7B的大型语言模型。Qwen-Audio在超过30个任务和多种音频类型上进行预训练,包括人类语音、自然声音、音乐和歌曲,以促进通用音频理解能力,从论文(参考文献-1)及官方Demo体验来看效果还是非常不错的。

2. 对比LTU

从架构图上来看,Qwen-Audio和LTU-AS非常像,音频编码都是基于Whisper,然后接一个LLM。这里简单总结一下两者区别:

  • 推理方式
    • Qwen-Audio并没有输出识别结果,而是将Encode后的序列直接送入LLM
    • LTU-AS分为两步分,并将两个部分的结果和指令一同编码送入LLM
      1. 输出识别结果
      2. 对Whisper Encode输出送入轻量级的音频标记模型(at-model),生成音频标记序列
  • 训练方式
    • Qwen-Audio是采用的联合训练的方式,所有参数都需要训练,训练成本比较高
    • LTU-AS模型维持Whisper和LLaMA不变,只训练LoRA、TLTR部分及投影层,训练成本比较低
  • 开放度
    • Qwen-Audio模型是开源的,开放的仓库只提供了eval部分,不过Qwen提供了finetune脚本
    • LTU-AS模型都是开源的,提供了完整的环境,train、finetune、eval等过程可以快速验证
  • 效果上
    • Qwen-Audio基于Qwen-7B,词表151936,中文效果明显好于LTU-AS
    • LTU-AS是LLM是基于LLaMA,词表只有32000,主要针对英文场景,中文基本不可用

3. 推理运行环境

  • 官方体验Demo: https://modelscope.cn/studios/qwen/Qwen-Audio-Chat-Demo/summary/?st=1fuJ0kGSXvsR3TeNt2YKXhg
  • 部署Qwen-Audio
    • https://github.com/QwenLM/Qwen-Audio
    • 运行平台:Linux
    • 库依赖:按照requirements.txt/requirements_web_demo.txt进行安装,最好在一个独立的docker或conda虚拟环境中安装
    • 只提供了eval脚本,没有提供finetune和train脚本,应该和Qwen-7B比较接近:https://github.com/QwenLM/Qwen
    • 模型下载地址
      • https://huggingface.co/Qwen/Qwen-Audio-Chat
      • https://huggingface.co/Qwen/Qwen-Audio
      • 通过HF下载比较慢:https://modelscope.cn/models/qwen/Qwen-Audio-Chat/files
wget 'https://modelscope.cn/api/v1/models/qwen/Qwen-Audio-Chat/repo?Revision=master&FilePath=model-00001-of-00009.safetensors'
wget 'https://modelscope.cn/api/v1/models/qwen/Qwen-Audio-Chat/repo?Revision=master&FilePath=model-00002-of-00009.safetensors'
wget 'https://modelscope.cn/api/v1/models/qwen/Qwen-Audio-Chat/repo?Revision=master&FilePath=model-00003-of-00009.safetensors'
wget 'https://modelscope.cn/api/v1/models/qwen/Qwen-Audio-Chat/repo?Revision=master&FilePath=model-00004-of-00009.safetensors'
wget 'https://modelscope.cn/api/v1/models/qwen/Qwen-Audio-Chat/repo?Revision=master&FilePath=model-00005-of-00009.safetensors'
wget 'https://modelscope.cn/api/v1/models/qwen/Qwen-Audio-Chat/repo?Revision=master&FilePath=model-00006-of-00009.safetensors'
wget 'https://modelscope.cn/api/v1/models/qwen/Qwen-Audio-Chat/repo?Revision=master&FilePath=model-00007-of-00009.safetensors'
wget 'https://modelscope.cn/api/v1/models/qwen/Qwen-Audio-Chat/repo?Revision=master&FilePath=model-00008-of-00009.safetensors'
wget 'https://modelscope.cn/api/v1/models/qwen/Qwen-Audio-Chat/repo?Revision=master&FilePath=model-00009-of-00009.safetensors'
    • 运行示例: python web_demo_audio.py
      • 为方便调试并没有采用gradio的方式进行部署,直接运行一个简单示例,故作如下修改

    • 示例
      • 📎1.wav
      • 指令“请问这个音频想表达什么?”
    • 部署遇到问题
      • TypeError: Audio.__init__() got an unexpected keyword argument 'source'
      • 修复方案
        • pip install numpy==1.24.4
        • pip install gradio==3.41.2

4. 推理源码解读

从架构图上可以看出,可以将推理过程分为3个步骤:音频编码、指令编码、LLM推理,其中音频编码和指令编码并无依赖关系,不过在Qwen-Audio代码实现过程中,需要获取音频编码后的长度,所以将音频编码放在步骤一。

步骤1:音频编码

编码模块基于Whisper encode部分(参考文献-2),“特征提取+CNN降低维度+Encode”部分一致,这里不再赘述,差异点是Qwen-Audio在Encode后增加降维模块“avg_pooler+proj”, 如下所示:

    (audio): AudioEncoder((conv1): Conv1d(80, 1280, kernel_size=(3,), stride=(1,), padding=(1,))(conv2): Conv1d(1280, 1280, kernel_size=(3,), stride=(2,), padding=(1,))(blocks): ModuleList((0-31): 32 x ResidualAttentionBlock((attn): MultiHeadAttention((query): Linear(in_features=1280, out_features=1280, bias=True)(key): Linear(in_features=1280, out_features=1280, bias=False)(value): Linear(in_features=1280, out_features=1280, bias=True)(out): Linear(in_features=1280, out_features=1280, bias=True))(attn_ln): LayerNorm((1280,), eps=1e-05, elementwise_affine=True)(mlp): Sequential((0): Linear(in_features=1280, out_features=5120, bias=True)(1): GELU(approximate='none')(2): Linear(in_features=5120, out_features=1280, bias=True))(mlp_ln): LayerNorm((1280,), eps=1e-05, elementwise_affine=True)))(ln_post): LayerNorm((1280,), eps=1e-05, elementwise_affine=True)(avg_pooler): AvgPool1d(kernel_size=(2,), stride=(2,), padding=(0,))(proj): Linear(in_features=1280, out_features=4096, bias=True)(audio_bos_eos_token): Embedding(2, 4096))

以1.wav为例,采样率为16000,共包含51236个样本点,帧移是10ms(也就是对应160个点),所以有效帧数L_in=51236/160=320,那么经过“CNN降低维度+avg_pooler”降低维度后帧数应该为320/4=80,增加开始和结束标志后变为82。所以Qwen-Audio AudioEncocerm模块将长度320帧的音频,转成长度82帧维度为4096的序列。

  • /root/.cache/huggingface/modules/transformers_modules/Qwen-Audio-Chat/tokenization_qwen.py:550
  • /root/.cache/huggingface/modules/transformers_modules/Qwen-Audio-Chat/modeling_qwen.py:764

步骤2:构建Prompt

该步骤可分为两步:prompt生成、prompt序列化

  1. prompt生成

prompt由“音频信息和指令”构成,如本例中音频是"./1.wav",指令是“请问这个音频想表达什么?”,那么添加对应的tag后,如下:

  • 音频信息:'Audio {1}: <audio>{"./1.wav"}</audio>'
  • 指令:'请问这个音频想表达什么?'

拼接后构成的prompt为 'Audio {1}: <audio>{"./1.wav"}</audio>\n请问这个音频想表达什么?' 。

  1. prompt序列化

将prompt按照特定格式打包,并序列化为token_id:

def make_context():# 以history=None为例#'system\nYou are a helpful assistant.'==》[151644, 8948, 198, 2610, 525, 264, 10950, 17847, 13, 151645]context_tokens = system_tokenscontext_tokens += (nl_tokens+ im_start_tokens+ _tokenize_str("user", query)[1]+ im_end_tokens+ nl_tokens+ im_start_tokens+ tokenizer.encode("assistant")+ nl_tokens)# /root/.cache/huggingface/modules/transformers_modules/Qwen-Audio-Chat/modeling_qwen.py:1191
# 位于函数:QWenLMHeadModel::chat
# 输入query形如:'Audio 1: <audio>./1.wav</audio>\n请问这个音频想表达什么?'
# 输出context_tokens形如:'[151644, 8948, 198, ...'
raw_text, context_tokens, audio_info = make_context(tokenizer,query,history=history,system=system,max_window_size=max_window_size,chat_format=generation_config.chat_format,
)

执行后make_context生成prompt序列为:

[151644, 8948, 198, 2610, 525, 264, 10950, 17847, 13, 151645, 198, 151644, 872, 198, 14755, 220, 16, 25, 220, 155163, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 151851, 155164, 198, 109194, 99487, 111268, 99172, 102124, 99245, 11319, 151645, 198, 151644, 77091, 198]

序列化后的token_id含义如下表,这里仅列出本次任务所涉及token,如果需要了获取更多可以通过函数tokenizer._convert_id_to_token(int)获取

token

token_id

含义

system

8948

系统

user

872

用户

assistant

77091

智能助手

<|im_start|>

151644

一般用于角色交替,角色开始说话

<|im_end|>

151645

一般用于角色交替,角色说话结束

<audio>

155163

标识音频的开始位置

</audio>

155164

标识音频结束的位置

[[[AUDIO:modality]]]

151851

音频占位符,后边用音频编码后的序列填充

Audio

14755

标识音频名字

\n

198

换行

220

空格

步骤3:LLM推理

该模块是将序列化后的Prompt输入LLM(基于Qwen-7B )进行预测。下边是QWenModel模型结构,可以看出推理过程主要是一个32层维度为4096的残差注意力块(QWenBlock)。

<bound method QWenLMHeadModel.generate of QWenLMHeadModel((transformer): QWenModel((wte): Embedding(155947, 4096)(drop): Dropout(p=0.0, inplace=False)(rotary_emb): RotaryEmbedding()(h): ModuleList((0-31): 32 x QWenBlock((ln_1): RMSNorm()(attn): QWenAttention((c_attn): Linear(in_features=4096, out_features=12288, bias=True)(c_proj): Linear(in_features=4096, out_features=4096, bias=False)(attn_dropout): Dropout(p=0.0, inplace=False))(ln_2): RMSNorm()(mlp): QWenMLP((w1): Linear(in_features=4096, out_features=11008, bias=False)(w2): Linear(in_features=4096, out_features=11008, bias=False)(c_proj): Linear(in_features=11008, out_features=4096, bias=False))))(ln_f): RMSNorm())(lm_head): Linear(in_features=4096, out_features=155947, bias=False)
)

推理后输出每个token的得分(QWen词表长度155947),并将得分送入decode_tokens得出文本(通常采用greedy-search),都是标准过程这里不再赘述。下边给出对应的代码位置。

def forward():# 残差注意力模块:由于是递归输出1个维度为[1, 1, 4096]的序列# /root/.cache/huggingface/modules/transformers_modules/Qwen-Audio-Chat/modeling_qwen.py:892# 位于函数: QWenModel::forwardfor i, (block, layer_past) in enumerate(zip(self.h, past_key_values)):if output_hidden_states:all_hidden_states = all_hidden_states + (hidden_states,)......outputs = block(   # 32层残差注意力块hidden_states,layer_past=layer_past,rotary_pos_emb_list=rotary_pos_emb_list,attention_mask=attention_mask,head_mask=head_mask[i],encoder_hidden_states=encoder_hidden_states,encoder_attention_mask=encoder_attention_mask,use_cache=use_cache,output_attentions=output_attentions,)......# 将[1, 4096]序列映射成[1, 1, 155947]的序列,即获取每个token的得分# /root/.cache/huggingface/modules/transformers_modules/Qwen-Audio-Chat/modeling_qwen.py:1125# QWenLMHeadModel::forwardlm_logits = self.lm_head(hidden_states)# 如果是greedy-search,获取得分最高的token# /usr/local/lib/python3.10/site-packages/transformers/generation/logits_process.py:419# 自回归解码
# /usr/local/lib/python3.10/site-packages/transformers/generation/utils.py:2709
# 位于函数: QWenLMHeadModel::chat->QWenLMHeadModel::generate->GenerationMixin::generate->GenerationMixin::sample
while True:model_inputs = self.prepare_inputs_for_generation(input_ids, **model_kwargs)# forward pass to get next tokenoutputs = forward(    # 也就是代码里的self**model_inputs,return_dict=True,output_attentions=output_attentions,output_hidden_states=output_hidden_states)# token解码:将自回归解码获得的token序列转成文本
# /root/.cache/huggingface/modules/transformers_modules/Qwen-Audio-Chat/modeling_qwen.py:1213
# 位于函数: QWenLMHeadModel::chat
# outputs形如: [151644, 8948, 198, 2610, 525, 264, 10950, 17847, 13, ...]
# response形如: '这个音频想表达的是一个男人在说话,说的内容是"i have a dream that one day"。'
response = decode_tokens(outputs[0],tokenizer, ...)

5. 参考文献

  1. Qwen-Audio: https://arxiv.org/pdf/2311.07919.pdf
  2. 《Whisper推理源码解读
http://www.dtcms.com/a/452911.html

相关文章:

  • 做教育网站宣传策略湖北三丰建设集团股份网站
  • 《Vuejs设计与实现》第 18 章(同构渲染)(上)
  • 【前端基础】20、CSS属性——transform、translate、transition
  • ChartStudio: New Chart Types Added for Enhanced Data Visualization
  • 测试用例设计万能公式:功能到安全
  • 做招投标应该了解的网站广州产品网站设计
  • Apache StreamPark 快速上手从一键安装到跑起第一个 Flink SQL 任务
  • 珠海市手机网站建设公司广州头条新闻最新
  • 多模卫星导航定位与应用-原理与实践(RTKLib)5
  • 【数据结构】汉诺塔问题
  • AI - 自然语言处理(NLP) - part 2 - 词向量
  • 焦作做网站最专业的公司滨海新区做网站电话
  • 【JavaScript Proxy 与 Reflect 指南】
  • 【软件开发】管理类系统
  • 使用Unity引擎开发Rokid主机应用的全面配置交互操作
  • web服务器有哪些?服务器和web服务器有什么区别
  • 大数据Spark(六十七):Transformation转换算子distinct和mapValues
  • 【寰宇光锥舟】
  • 计算机视觉(opencv)——嘴部表情检测
  • 唤醒手腕2025年最新机器学习K近邻算法详细教程
  • 广州化妆品网站建设公司排名北京网站建设91086
  • 【纯AI观点】用于协作内容创建和知识管理的MediaWiki
  • 贵州省网站建设网站打开时的客户引导页
  • C++新标准——decltype 关键字
  • Java中通过.xml文件管理测试用例类
  • 清空全网题目系列 · 洛谷 · P1054 [NOIP 2005 提高组] 等价表达式
  • 偏振光阴影投影的三元光学逻辑处理器
  • GitLab 安装指南
  • 磁共振成像原理(理论)20:K空间采样 (Sampling of k-Space) - 采样定理
  • 安装wslgui