Transformers 中的 X-Codec2:面向 LLM 语音合成的单码本神经音频编解码器
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
X-Codec2 是用于 LLaMA 系 LLM 语音合成管线的神经音频编解码器,它通过"语义编码器 + 声学编码器融合"与单层 Finite Scalar Quantization(FSQ)设计,把音频压缩为一维离散 token 序列。本文基于 🤗 Transformers 官方文档与仓库源码,系统讲解 X-Codec2 的架构原理、特征提取管线、配置参数,并给出可直接运行的编码/解码、批量处理与torch.compile加速完整示例。
X-Codec2 由 Eric Bezzam 与 Steven Zheng 贡献,模型检查点托管于 Hugging Face(模型仓库 ID:HKUSTAudio/xcodec2-hf)。本文的 API 说明可对照 docs/source/en/model_doc/xcodec2.md,源码实现位于 src/transformers/models/xcodec2/ 目录下。
背景与设计动机
X-Codec2 在论文Llasa: Scaling Train-Time and Inference-Time Compute for Llama-based Speech Synthesis中提出,目标是解决"以音频 token 为接口的 LLM 语音合成"这一场景下的核心矛盾:音频 token 既要保留足够语义信息(文本内容、情感),又要具备足够低的码率、稳定且适合自回归建模。
与常见神经编解码器相比,X-Codec2 的三个核心设计要点如下:
- 统一语义—声学 token 化(Unified Semantic-Acoustic Tokenization):X-Codec2 将语义编码器(如 Wav2Vec2-BERT)与声学编码器的输出融合进同一个 embedding。语义编码器负责捕获高层含义(文字内容、情感),声学编码器负责捕获底层音频细节(如音色),融合后的单一表示同时覆盖两者。
- 单层特征标量量化(Single-Stage FSQ):不同于 DAC、EnCodec、X-Codec、Mimi 等模型常用的多层残差矢量量化(residual VQ),X-Codec2 采用单层 Feature Scalar Quantization(FSQ),训练更稳定,也更兼容因果、自回归的 LLM。
- Transformer 友好的一维 token 结构:X-Codec2 输出的一维离散 token 序列天然对齐 LLaMA 等模型的自回归建模方式,从而提升训练效率与下游兼容性。
从源码注释中也可以印证这一点:量化器模块 Xcodec2FiniteScalarQuantization 说明中写道"X-Codec2 的主要特性就是只用单一 codebook"(原实现使用含单一 quantizer 的ResidualFSQ,此处直接以 FSQ 等价实现)。
架构总览:编码器、量化器与解码器
在 Xcodec2Model 中,整个模型由五大子模块组装而成,可以清晰地划分为三条处理链路:
- 语义链路(语义编码器 + 语义适配器):
Xcodec2Model通过AutoModel.from_config(config.semantic_model_config)实例化语义编码器(默认是 Wav2Vec2-BERT 结构),随后经过 Xcodec2SemanticAdapter(一组 1D 卷积 + ReLU 的适配层)得到语义隐状态。值得注意的实现细节是,语义编码器的前向推理在torch.no_grad()上下文中完成,即冻结、不参与梯度回传。 - 声学链路(声学编码器):Xcodec2Encoder 以波形为输入:先是 kernel size 为 7 的首个 1D 卷积,随后按
downsampling_ratios依次堆叠Xcodec2EncoderBlock(每个 block 将通道数翻倍并按 stride 下采样),最后经抗混叠激活与 1D 卷积输出声学隐状态。 - 融合与量化:语义与声学隐状态在通道维拼接后,经过
fc_encoder线性层,再由 Xcodec2Quantizer 完成量化——内部为project_in(映射到与quantization_levels等宽的维度)、Xcodec2FiniteScalarQuantization 与project_out的串联,输出量化后的连续 latent 与离散的audio_codes。 - 解码链路(声学解码器):Xcodec2Decoder 是基于 Vocos 思路的声码器风格解码器,包含输入线性层、embedding 卷积、两层
Xcodec2ResNetBlock、12 层带旋转位置编码(RoPE)的 Transformer、两层后处理 ResNet,最后经 Xcodec2ISTFTHead(STFT 预测 + Hann 窗 ISTFT 重建)还原出波形。代码中还用F.fold手工实现了torch.istft缺失的 "same" padding 语义。
模型的encode、decode、forward三个公开方法对应完整的单段处理、两段处理和端到端重建三种用法,细节见下文。编码器与解码器均可独立用于流水线的不同阶段(例如先用encode产出 token 供 LLM 自回归生成,再把生成结果交给decode重建波形)。
环境准备与快速开始
X-Codec2 在 Transformers 中以AutoModel(Xcodec2Model)与AutoFeatureExtractor(Xcodec2FeatureExtractor)的形式接入,因此加载方式与一般模型一致:
from transformers import AutoFeatureExtractor, AutoModel model_id = "HKUSTAudio/xcodec2-hf" model = AutoModel.from_pretrained(model_id, device_map="auto") feature_extractor = AutoFeatureExtractor.from_pretrained(model_id)一个典型的编码—解码工作流如下(可直接复制运行):
from datasets import Audio, load_dataset from transformers import AutoFeatureExtractor, AutoModel model_id = "HKUSTAudio/xcodec2-hf" model = AutoModel.from_pretrained(model_id, device_map="auto") feature_extractor = AutoFeatureExtractor.from_pretrained(model_id) dataset = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation") dataset = dataset.cast_column("audio", Audio(sampling_rate=feature_extractor.sampling_rate)) audio = dataset[0]["audio"]["array"] inputs = feature_extractor(audio=audio, sampling_rate=feature_extractor.sampling_rate, return_tensors="pt").to( model.device, model.dtype ) print("Input waveform shape:", inputs["input_values"].shape) # Input waveform shape: torch.Size([1, 1, 93760]) # encoder and decoder audio_codes = model.encode(**inputs).audio_codes print("Audio codes shape:", audio_codes.shape) # Audio codes shape: torch.Size([1, 1, 293]) audio_values = model.decode(audio_codes).audio_values print("Audio values shape:", audio_values.shape) # Audio values shape: torch.Size([1, 1, 93760]) # Equivalently, you can do encoding and decoding in one step model_output = model(**inputs) audio_codes = model_output.audio_codes audio_values = model_output.audio_values注意上述打印的 shape 反映了一条重要的换算关系:hop_length = 320个采样点对应一个 code。9 万多个采样点的输入被压缩成 293 个离散 token(93760 / 320 = 293),这正是后续 LLM 自回归生成所需的粒度。
关于输出结构
model.encode(...)返回 Xcodec2EncoderOutput,model(...)返回 Xcodec2Output,它们共享以下字段:
audio_codes(torch.LongTensor,形状(batch_size, 1, codes_length)):量化得到的离散 token,用于存储、传输或交给 LLM 生成;latents(torch.Tensor,形状(batch_size, dimension, time_steps)):量化的连续表示(forward 默认不返回,需设output_latents=True);audio_codes_mask(torch.int32,形状(batch_size, 1, codes_length)):对padding_mask按hop_length下采样得到的有效 code 掩码,便于判断哪些 token 是真实音频;仅当 encode 传入padding_mask时生成;audio_values(torch.FloatTensor,形状(batch_size, 1, sequence_length)):解码重建的时域波形(仅 decoder / forward 输出)。
端到端 forward 的截断逻辑
使用model(**inputs)一步完成编码解码时,forward内部先调用encode(强制output_latents=True),再把 latent 传给decode,最后将重建波形截断回原始输入长度:
audio_values = self.decode(latents=encoder_outputs.latents, return_dict=True, **kwargs)[0][..., :length]这段逻辑位于 Xcodec2Model.forward 中,length = input_values.shape[-1]保证输出与输入等长,便于直接计算重建误差或与参考波形对齐。
批量处理:官方实现未支持的增强能力
与原始 X-Codec2 发布版)指出,原始的torchaudio.compliance.kaldi.fbank不支持批量输入,原版实现只能逐条循环;而这里的实现虽然也逐条计算 mel 特征,但整体的 padding、mask 与波形前处理均已支持 batch,且保留了与原实现一致的数值行为。
批量处理示例:
from datasets import Audio, load_dataset from transformers import AutoFeatureExtractor, AutoModel batch_size = 2 model_id = "HKUSTAudio/xcodec2-hf" model = AutoModel.from_pretrained(model_id, device_map="auto") feature_extractor = AutoFeatureExtractor.from_pretrained(model_id) dataset = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation") dataset = dataset.cast_column("audio", Audio(sampling_rate=feature_extractor.sampling_rate)) audios = [dataset[i]["audio"]["array"] for i in range(batch_size)] inputs = feature_extractor(audio=audios, sampling_rate=feature_extractor.sampling_rate, return_tensors="pt").to( model.device, model.dtype ) print("Input waveform shape:", inputs["input_values"].shape) # Input waveform shape: torch.Size([2, 1, 93760]) # encoder and decoder encoder_output = model.encode(**inputs) audio_codes = encoder_output.audio_codes print("Audio codes shape:", audio_codes.shape) # Audio codes shape: torch.Size([2, 1, 293]) audio_values = model.decode(audio_codes).audio_values print("Audio values shape:", audio_values.shape) # Audio values shape: torch.Size([2, 1, 93760]) # Equivalently, you can do encoding and decoding in one step model_output = model(**inputs) audio_codes = model_output.audio_codes audio_values = model_output.audio_values在把音频列表交给特征提取器时,建议显式传入padding=True(或'longest'),使同一 batch 内的样本按最长长度对齐(特征提取器padding参数默认即为True)。
特征提取:波形到双路输入的前处理
Xcodec2FeatureExtractor 是理解 X-Codec2 输入格式的关键,它把一段波形同时加工成模型所需的两路输入:
input_values:给声学编码器使用的 padded 波形,形状(batch_size, 1, sequence_length);padding_mask:与input_values对应的掩码;input_features:给语义编码器使用的 mel 滤波器组特征(其帧按 stride 压缩合并),形状(batch_size, 特征帧数, 特征维度);input_features_mask:语义编码器侧的注意力掩码,1表示有效帧、0表示 padding。
处理流程分为两步(见其__call__):
- 声学编码器侧 padding:内部定义了一个专门的
SequenceFeatureExtractor(acoustic_encoder_padder),对波形按pad_to_multiple_of=self.hop_length(320)做对齐填充,确保每个样本长度是 hop 长度的整数倍,这是保证 code 数与 frame 数对齐的前提。 - 语义编码器侧 mel 特征:逐样本调用
torchaudio.compliance.kaldi.fbank计算 mel 滤波器组特征,窗口函数为 povey、预加重系数 0.97、mel 通道数 80、帧长 400 个采样点(25 ms)、帧移 160 个采样点(10 ms),随后做逐样本的均值/方差归一化,再按 stride=2 合并相邻帧并下采样掩码。
该类同时做了输入校验:若传入的sampling_rate与特征提取器内置的 16000 Hz 不一致会直接抛错;若未传sampling_rate则输出告警日志,提示可能引发难以排查的静默错误。因此请务必在调用时显式传入sampling_rate。
Xcodec2Config 配置详解
Xcodec2Config 负责描述完整模型结构。下表的默认值可直接从源码字段确认,其中大部分配置项影响的是模型规模、采样率与量化行为:
| 参数 | 默认值 | 含义 |
|---|---|---|
hidden_size | 1024 | Transformer 解码器(以及声学编码器输出映射目标)的隐层维度 |
intermediate_size | 4096 | MLP 中间层维度 |
num_hidden_layers | 12 | 解码端 Transformer 层数(也是 FSQ 之后的解码器层数) |
num_attention_heads/num_key_value_heads | 16/16 | 注意力头数与 KV 头数(GQA 场景下可小于前者) |
head_dim | 64 | 每个注意力头的维度 |
hidden_act | "silu" | 激活函数 |
max_position_embeddings | 4096 | 最大位置编码长度 |
rms_norm_eps | 1e-6 | LayerNorm / RMSNorm 的 epsilon |
attention_bias | False | 注意力投影是否使用偏置 |
attention_dropout | 0.0 | 注意力 dropout 率 |
encoder_hidden_size | 48 | 声学编码器首层通道数 |
downsampling_ratios | [2, 2, 4, 4, 5] | 声学编码器逐级下采样倍率 |
sampling_rate | 16000 | 模型期望的音频采样率(Hz) |
activation_dropout | 0.1 | ResNet block 中激活后的 dropout |
quantization_dim | 2048 | 量化器输入/输出投影维度 |
quantization_levels | [4, 4, 4, 4, 4, 4, 4, 4] | FSQ 每个维度上的量化级数 |
semantic_model_config | Wav2Vec2-BERT(16 层) | 语义编码器的子配置 |
几个值得展开的关键点:
downsampling_ratios与 hop 长度:该配置项决定了声学编码器的下采样路径,并间接派生出两个只读属性。hop_length定义为downsampling_ratios的乘积(2 × 2 × 4 × 4 × 5 = 320),即每个 token 覆盖的采样点数;n_fft定义为hop_length × 4 = 1280,用于解码端 ISTFT 头。这两个属性在 Xcodec2Config 中以@property实现。quantization_levels与 codebook 规模:8 个维度的级数全为 4,意味着隐含 codebook 大小为4^8 = 65536。这解释了 FSQ 的"单一 codebook"语义——它不显式存储码本向量,而是通过各维度级数穷举组合出索引,再在Xcodec2FiniteScalarQuantization内用basis(torch.cumprod前缀积)完成索引 ↔ 码字的双向换算,并通过_indices_to_codes/codebook缓冲实现查表。semantic_model_config子配置:sub_configs = {"semantic_model_config": AutoConfig}声明了嵌套子配置。若传入 dict,__post_init__会默认补上model_type = "wav2vec2-bert"并交给对应配置类实例化;若为None则自动创建一个 16 层的 Wav2Vec2-BERT 配置。- 架构校验:配置类上的
validate_architecture(由@strict装饰器驱动)会检查hidden_size是否可被num_attention_heads整除,不满足即抛错。
实例化与随机初始化模型的方式与其他 Transformers 模型一致:
from transformers import Xcodec2Config, Xcodec2Model # Initializing configuration configuration = Xcodec2Config() # Initializing a model (with random weights) from the configuration model = Xcodec2Model(configuration) # Accessing the model configuration configuration = model.configAPI 速览:encode / decode / forward
- Xcodec2Model.encode:输入
input_values、input_features以及可选的padding_mask、input_features_mask,内部完成"语义编码(冻结)→ 声学编码 → 拼接融合 → 量化"的完整流程,返回audio_codes(可选latents与audio_codes_mask)。output_latents=True时同时返回量化后的连续表示。 - Xcodec2Model.decode:接受
audio_codes(此时内部经quantizer.from_codes按索引查 codebook)或直接给定latents,二者必须提供其一,否则抛ValueError;输出重建的audio_values。 - Xcodec2Model.forward:等价于 encode + decode 一步完成,输出截断到原始输入长度。
Xcodec2Model的父类 Xcodec2PreTrainedModel 声明了一系列能力标记:支持 Flash Attention(_supports_flash_attn = True)、SDPA(_supports_sdpa = True)、Flex Attention、Cache类缓存、梯度检查点(supports_gradient_checkpointing = True)以及fullgraph编译(_can_compile_fullgraph = True),主输入名为input_values。也就是说,除了默认的 eager 注意力路径,你可以通过 Transformers 统一的注意力后端机制启用 Flash Attention 2 / SDPA 等加速实现。
使用 torch.compile 加速推理
得益于_can_compile_fullgraph = True与针对torch.compile友好的实现细节(例如 ISTFT 头中特意将频率轴保持在最后一维以兼容torch.polar编译),该模型可直接用torch.compile做整图编译加速。据仓库文档记载,在 A100 上、batch size 为 4 时实测约 1.35 倍加速。首次调用包含编译开销会偏慢,后续调用明显更快。示例:
import torch from datasets import Audio, load_dataset from transformers import AutoFeatureExtractor, AutoModel batch_size = 4 model_id = "HKUSTAudio/xcodec2-hf" model = AutoModel.from_pretrained(model_id, device_map="auto") feature_extractor = AutoFeatureExtractor.from_pretrained(model_id) dataset = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation") dataset = dataset.cast_column("audio", Audio(sampling_rate=feature_extractor.sampling_rate)) audios = [dataset[i]["audio"]["array"] for i in range(batch_size)] inputs = feature_extractor( audio=audios, sampling_rate=feature_extractor.sampling_rate, padding=True, return_tensors="pt" ).to(model.device, model.dtype) compiled_model = torch.compile(model, fullgraph=True) # Warmup (includes compilation on first call) for _ in range(10): with torch.inference_mode(): _ = compiled_model(**inputs) with torch.inference_mode(): output = compiled_model(**inputs) print("Audio values shape:", output.audio_values.shape)注意批量输入时特征提取需设padding=True,且编译/推理过程应包裹在torch.inference_mode()中。
项目资源导航
如果想深入研读实现或进行二次开发,以下仓库路径可作为起点:
- 模型组装与前向/编解码主流程:src/transformers/models/xcodec2/modeling_xcodec2.py
- 配置文件类:src/transformers/models/xcodec2/configuration_xcodec2.py
- 特征提取器(波形 → 双路输入):src/transformers/models/xcodec2/feature_extraction_xcodec2.py
- 模型的手工维护源(modeling_xcodec2.py 由 modular_xcodec2.py 自动生成,改动应落到 modular 文件)
- 官方检查点权重转换脚本:src/transformers/models/xcodec2/convert_xcodec2_checkpoint.py(包含 RoPE 置换、key 映射、weight norm 处理等逻辑)
- 相关编解码器对照阅读:DAC、EnCodec、X-Codec、Mimi
需要留意的是,X-Codec2 面向 16 kHz 音频,其 token 粒度(每 320 个采样点一个 code)与"语义 + 声学融合、单码本 FSQ"的组合是针对 LLaMA 系语音合成定制设计的。若需更高采样率或不同码率的编解码能力,建议先横向对比上述同类模型再选型。
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考