十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

dGSLM 生成式口语对话语言建模实战:基于 fairseq SpeechDLM 的双通道口语对话生成、训练与语音合成全流程

dGSLM 生成式口语对话语言建模实战:基于 fairseq SpeechDLM 的双通道口语对话生成、训练与语音合成全流程 dGSLM 生成式口语对话语言建模实战基于 fairseq SpeechDLM 的双通道口语对话生成、训练与语音合成全流程【免费下载链接】fairseqFacebook AI Research Sequence-to-Sequence Toolkit written in Python.项目地址: https://gitcode.com/gh_mirrors/fa/fairseqdGSLMGenerative Spoken Dialogue Language Modeling是 fairseq 中以examples/textless_nlp/dgslm/为核心代码的文本无关textless口语对话生成方案它由 Speech-to-Unit 编码器Fisher HuBERT k-means、双通道口语对话语言模型 SpeechDLM、Unit-to-Speech 解码器HiFi-GAN vocoder三段式流水线构成可在完全没有文本与标注的条件下从原始双通道对话音频中学习并生成包含语音、笑声等副语言信号的两人对话。本文将以 examples/textless_nlp/dgslm/README.md 为主线结合仓库源码深入讲解整个流水线的原理、预训练模型的使用、SpeechDLM 的采样、训练与验证以及最终的双通道语音合成读完即可在本地完整跑通从音频到离散单元、从离散单元到对话续写、再从对话单元回放为语音的全链路。一、dGSLM 总体架构三段式的 textless 口语对话流水线dGSLM 对应论文Generative Spoken Dialogue Language ModelingarXiv:2203.16502是首个能够在原始音频层面生成自然主义口语对话样本的 textless 模型。其核心思路是Speech-to-Unit 编码器利用无监督口语单元发现unsupervised spoken unit discovery技术把双通道对话音频转成离散单元序列代码位于 examples/textless_nlp/dgslm/hubert_fisher/SpeechDLM 对话语言模型采用带跨通道注意力cross-attention的双塔dual-towerTransformer 架构在 2000 小时的双通道原始对话音频Fisher 数据集上训练不使用任何文本或标签代码位于 fairseq/models/speech_dlm/Unit-to-Speech 解码器基于离散单元的 HiFi-GAN vocoder 把生成的单元序列合成回波形代码位于 examples/textless_nlp/dgslm/vocoder_hifigan/。据论文摘要该模型能够在两个通道中同时生成语音、笑声及其他副语言信号相比基于文本的级联cascaded模型能够生成更自然、更流畅的对话轮转turn taking。从仓库源码看SpeechDLM 在 fairseq 中的注册名为speech_dlm其对应的任务为speech_dlm_task见 fairseq/tasks/speech_dlm_task.py损失函数为speech_dlm_criterion见 fairseq/criterions/speech_dlm_criterion.py三者共同构成完整的训练与推理闭环。二、Speech-to-Unit 编码器Fisher HuBERT k-means2.1 模型原理与检查点Speech-to-Unit 编码器在 Fisher 数据集上训练了3 轮迭代的 HuBERT 模型并在该 HuBERT 模型的第 12 层layer 12特征上训练了一个500 单元units的 k-means 量化模型。两个预训练检查点均可从 examples/textless_nlp/dgslm/hubert_fisher/README.md 的 Model checkpoints 小节下载Fisher HuBERT 模型k-means 模型hubert_fisher.pthubert_fisher_km_500.bin2.2 用命令行把立体声数据集编码为离散单元使用quantize_with_kmeans.py脚本可对立体声stereo数据集逐通道编码命令示例如下注意对通道 1 和通道 2 各执行一次for CHANNEL_ID in 1 2; do python examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py \ --feature_type hubert \ --kmeans_model_path path/to/hubert_fisher_km_500.bin \ --acoustic_model_path path/to/hubert_fisher.pt \ --layer 12 \ --manifest_path $MANIFEST_FILE \ --out_quantized_file_path ${OUTPUT_FILE}-channel${CHANNEL_ID} \ --extension $EXTENSION \ --channel_id $CHANNEL_ID done其中$MANIFEST_FILE是 examples/wav2vec/wav2vec_manifest.py 的输出可通过如下命令生成python examples/wav2vec/wav2vec_manifest.py --valid-percent0.0 $AUDIO_DIR --dest$OUTPUT_DIR --ext$EXTENSION2.3 用 HubertTokenizer 交互式编码单条音频除了命令行也可以使用 examples/textless_nlp/dgslm/dgslm_utils.py 中封装的HubertTokenizer类在 Python 中交互式编码音频。从源码看dgslm_utils.py该类内部组合了HubertFeatureReader提取指定层特征与ApplyKmeansk-means 量化wav2codes会分别以channel_id1和channel_id2编码立体声的两个通道并返回两个单元串# Load the Hubert tokenizer from examples.textless_nlp.dgslm.dgslm_utils import HubertTokenizer encoder HubertTokenizer( hubert_path /path/to/hubert_ckpt.pt, hubert_layer 12, km_path path/to/km.bin ) # Encode the audio to units path /path/to/stereo/audio.wav codes encoder.wav2codes(path) # [7 376 376 133 178 486 486 486 486 486 486 486 486 2 486, # 7 499 415 177 7 7 7 7 7 7 136 136 289 289 408]返回的每个单元串由空格分隔的整数单元 ID 组成范围对应 k-means 的 500 个单元。这两个单元串即分别对应通道 AunitA与通道 BunitB是后续 SpeechDLM 的输入形式。三、Spoken Dialogue Transformer Language ModelSpeechDLM3.1 模型定位与预训练检查点SpeechDLM 是 dGSLM 流水线的对话大脑。官方共享了论文中最佳配置DLM-5 模型采用Edge Unit Prediction与Delayed Duration Prediction两个目标在 Fisher 2000 小时数据上训练得到的检查点可直接用于采样续写对话。预训练检查点与两个字典文件分别对应两个通道内容相同可从 examples/textless_nlp/dgslm/README.md 的 Pre-trained model 小节获取下载地址speech_dlm_base.ptSpeechDLM 模型检查点dict.unitA.txt与dict.unitB.txt两个通道各自的字典文件内容一致。从 fairseq/models/speech_dlm/speech_dlm.py 的源码可以看到模型注册名为speech_dlm继承自FairseqLanguageModelbuild_model会为所有通道构建共享的单元 Embedding并用CrossChannelTransformerDecoder作为解码器no_encoder_attnTrue即纯自回归语言模型无编码器注意力。3.2 双塔跨通道解码器架构SpeechDLM 的核心是 fairseq/models/speech_dlm/modules/speech_dlm_decoder.py 中的CrossChannelTransformerDecoder。从源码可以看出其结构特点共decoder_layers层其中前decoder_layers - decoder_cross_layers层是标准 Transformer 解码器层StandardTransformerDecoderLayer最后decoder_cross_layers层是跨通道注意力层CrossChannelTransformerDecoderLayer用于让两个通道互相感知对方的信息见 speech_dlm_decoder.py输入prev_output_tokens是一个通道名 → 张量的字典每个通道独立做 token embedding 与位置 embedding然后堆叠送入各层见 speech_dlm_decoder.py输出层output_layer按通道输出词表上的预测分布并在开启 duration prediction 时同时输出pred_token与pred_duration见 speech_dlm_decoder.py。默认配置SpeechDLMConfig见 speech_dlm.py中decoder_embed_dim512、decoder_ffn_embed_dim2048、decoder_layers6、decoder_cross_layers-1取 -1 时自动等于decoder_layers即全部为跨通道层、decoder_attention_heads8、dropout0.1。仓库还注册了更大的speech_dlm_big架构12 层、embed dim 1024、16 头见 speech_dlm.py。此外base_lm_architecture强制decoder_normalize_beforeTrue源码注释明确指出没有它模型训练不稳定见 speech_dlm.py。3.3 三种预测目标next / edge / durationSpeechDLM 支持三种预测目标supported_targets见 speech_dlm.py由任务配置开关控制见 fairseq/tasks/speech_dlm_task.py目标任务配置项默认值说明next--next-unit-predictionFalse常规的下一单元预测general/next unit predictionedge--edge-unit-predictionTrue边缘单元预测edge unit predictionduration--duration-predictionTrue单元时长预测duration prediction—--delayed-duration-targetTrue延迟时长目标delayed duration prediction注意这些配置项在源码中定义为字符串类型str必须传True/False这样的字符串见 speech_dlm_task.py。预训练模型对应的是--next-unit-prediction False --edge-unit-prediction True --duration-prediction True --delayed-duration-target True即Edge Unit Prediction Delayed Duration Prediction组合。此外任务还支持--max-target-durations 256对时长值做截断、--channel-weights为不同通道的损失加权见 speech_dlm_task.py。损失侧由 fairseq/criterions/speech_dlm_criterion.py 的SpeechDLMCriterion实现包含三部分general_unit_loss对应 next 目标、edge_unit_loss对应 edge 目标、duration_loss对应 duration 目标并支持以下权重配置--main-and-cross-weights 1,0默认主通道预测损失与跨通道预测损失的权重第二个值非 0 时解码器会为每个预测通道生成独立的输出投影见 speech_dlm_decoder.py--general-unit-loss-weight 0默认、--edge-unit-loss-weight 1、--duration-loss-weight 1各目标的损失权重。四、从预训练 SpeechDLM 模型采样生成对话4.1 Python API一行加载、交互式采样仓库提供了 Hub 风格的加载接口SpeechDLM.from_pretrained返回MultichannelGeneratorHubInterface见 fairseq/models/speech_dlm/hub_interface.py交互式采样代码如下来自原 READMEfrom fairseq.models.speech_dlm import SpeechDLM # Load SpeechDLM model speech_dlm SpeechDLM.from_pretrained( model_name_or_path/path/to/model/dir, checkpoint_filespeech_dlm_base.pt, data_name_or_path/path/to/data/dir ) # Disable dropout speech_dlm.eval() # Move model to GPU speech_dlm.cuda() # Define the input sequences input_sequences [{ unitA: 7 376 376 133 178 486 486 486 486 486 486 486 486 2 486, unitB: 7 499 415 177 7 7 7 7 7 7 136 136 289 289 408 }] # Sample from the SpeechDLM model generated_units speech_dlm.sample( input_sequences, max_len_a 0, max_len_b 500, samplingTrue, beam5, ) # {unitA: 7 376 376 133 178 486 486 486 486 486 486 486 486 2 486 486 178 486 486 2 2 376 376 486 486 486 376 376 387 387 ..., # unitB: 7 499 415 177 7 7 7 7 7 7 136 136 289 289 408 32 428 95 356 141 331 439 350 350 192 331 445 202 104 104 ...}其内部工作流程见 hub_interface.py为sample()→encode()把字符串单元序列编码为各通道的 token 张量 →generate()通过task.build_generator()构建多通道序列生成器 → 解码后把生成结果转回通道 → 单元串字典。其中max_len_b500表示生成序列的最大长度约为 500 个单元约 10 秒音频见 sample_speech_dlm.py 的注释。4.2 命令行脚本 sample_speech_dlm.py仓库还提供了批处理脚本 examples/textless_nlp/dgslm/sample_speech_dlm.pypython sample_speech_dlm.py \ --in-file $INPUT_CODE_FILE --out-file $OUTPUT_FILE \ --ckpt $CHECKPOINT_PATH --data $DATA_DIR其中$INPUT_CODE_FILE每行是一个包含audio, unitA, unitB三个键的字典格式如下{audio: file_1, unitA: 8 8 ... 352 352, unitB: 217 8 ... 8 8} {audio: file_2, unitA: 5 5 ... 65 65, unitB: 6 35 ... 8 9} ...该输入文件可由 examples/textless_nlp/dgslm/create_code_file.py 生成输入为quantize_with_kmeans.py的输出详见 hubert_fisher/README.md 的 Encode audio to discrete units 小节python examples/textless_nlp/dgslm/create_code_file.py \ $CHANNEL1_UNITS $CHANNEL2_UNITS $OUTPUT_CODE_FILEcreate_code_file.py要求两个通道文件每一行的文件名与单元数完全对齐文件名格式为$filename-channel1/$filename-channel2并据此构造{audio: ..., unitA: ..., unitB: ...}字典见 create_code_file.py。sample_speech_dlm.py支持的完整生成参数默认值见 sample_speech_dlm.py参数默认值说明--channelsunitA,unitB逗号分隔的通道名列表--prefix-sizeNone限制输入前缀的长度截断单元数--batch-max-tokens9216一个 batch 的最大 token 数--batch-max-positions6144一条样本允许的最大位置数--batch-max-sentencesNone一个 batch 的最大句数--skip-invalid-size-batchFalse跳过超过--batch-max-positions的样本--beam-searchFalse开启 beam search否则为随机采样 sampling--beam-size5beam 宽度采样与 beam search 均适用--sampling-topk-1仅从 top-k 候选中采样-1 表示不启用--sampling-topp-1.0累积概率超过 p 的最小候选集内采样-1.0 表示不启用--max-len-a0生成最大长度为 ax bx 为源长度--max-len-b500同上500 约对应 10 秒音频--min-len1生成序列的最小长度--temperature1.0生成单元 token 时的温度--dur-temperature1.0生成时长 token 时的温度--verboseFalse打印模型对生成序列的打分--seed123生成随机种子需要注意的是当--beam-search未开启时脚本默认采用随机采样sampling(not args.beam_search)这符合对话生成任务对多样性的需求。从任务侧源码看build_generator会依据--sampling选择ContiguousMultichannelSampling或ContiguousMultichannelBeamSearch搜索策略见 fairseq/tasks/speech_dlm_task.py。五、训练自己的 SpeechDLM 模型5.1 数据准备双通道单元文件首先准备原始数据。对每个 splittrain / valid需要两个分别对应两个通道例如unitA和unitB的单元文件且两个文件行数必须相同、每一行对应行的单元数也必须相同。unitA文件示例7 376 376 133 178 486 486 486 486 376对应的unitB文件7 499 415 177 7 7 7 136 331 445这两个文件可以用 hubert_fisher 的 编码命令 生成只需额外加上--hide-fname选项即只保留单元序列、去掉文件名前缀。最终原始数据目录应包含train.unitA valid.unitA train.unitB valid.unitB5.2 用 fairseq-preprocess 双通道分别二值化接着用fairseq-preprocess预处理数据关键要求是每个通道要单独预处理并把产物重命名为${split}.${channel}.{bin,idx}格式每个通道还需要独立的字典文件dict.${channel}.txt。官方示例命令# Preprocess the first channel (unitA) fairseq-preprocess --source-lang unitA \ --only-source \ --trainpref $RAW_DATA_DIR/train \ --validpref $RAW_DATA_DIR/valid \ --destdir $BIN_DATA_DIR \ --workers 20 # Preprocess the second channel (unitB) and reuse the dictionary from the first channel fairseq-preprocess --source-lang unitB \ --srcdict $BIN_DATA_DIR/dict.unitA.txt \ --only-source \ --trainpref $RAW_DATA_DIR/train \ --validpref $RAW_DATA_DIR/valid \ --destdir $BIN_DATA_DIR \ --workers 20 # Rename the bin index files for channel in unitA unitB; do for split in train valid; do mv $BIN_DATA_DIR/${split}.${channel}-None.${channel}.bin $BIN_DATA_DIR/${split}.${channel}.bin mv $BIN_DATA_DIR/${split}.${channel}-None.${channel}.idx $BIN_DATA_DIR/${split}.${channel}.idx done done最终二值化数据目录应包含dict.unitA.txt train.unitA.idx train.unitA.bin valid.unitA.idx valid.unitA.bin dict.unitB.txt train.unitB.idx train.unitB.bin valid.unitB.idx valid.unitB.bin从任务源码看SpeechDLMTask.setup_dictionary会扫描数据目录下所有dict.*.txt文件或在指定--channels时只加载指定通道并要求各通道字典的 pad/bos/eos/unk 索引一致见 fairseq/tasks/speech_dlm_task.pyload_dataset则按split.channel路径加载每个通道的索引数据集并经TokenBlockDatasetMonolingualDataset组装成SpeechDLMDataset见 speech_dlm_task.py。5.3 训练命令与关键超参以预训练模型相同的配置在 2 张 GPU 上训练的命令如下fairseq-train $BIN_DATA_DIR \ --save-dir $CHECKPOINT_DIR \ --tensorboard-logdir $CHECKPOINT_DIR \ --task speech_dlm_task --channels unitA,unitB \ --next-unit-prediction False --edge-unit-prediction True \ --duration-prediction True --delayed-duration-target True \ --criterion speech_dlm_criterion \ --arch speech_dlm --decoder-cross-layers 4 \ --share-decoder-input-output-embed \ --dropout 0.1 --attention-dropout 0.1 \ --optimizer adam --adam-betas (0.9, 0.98) --clip-norm 1.0 \ --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-07 \ --max-tokens 18432 --tokens-per-sample 6144 --sample-break-mode none \ --update-freq 16 --num-workers 4 --skip-invalid-size-inputs-valid-test \ --max-update 250000 --warmup-updates 20000 \ --save-interval-updates 10000 --keep-last-epochs 1 --no-epoch-checkpoints \ --log-interval 50 --seed 100501 \ --fp16 --checkpoint-activations对各关键参数的理解--task speech_dlm_task --channels unitA,unitB指定多通道对话任务与通道名对应 fairseq/tasks/speech_dlm_task.py--next-unit-prediction False --edge-unit-prediction True --duration-prediction True --delayed-duration-target True复现论文 DLM-5 的Edge Unit Prediction Delayed Duration Prediction目标组合与预训练检查点一致--arch speech_dlm --decoder-cross-layers 4指定双塔解码器其中最后 4 层使用跨通道注意力层decoder_layers6时前 2 层为普通自注意力层见 speech_dlm_decoder.py--share-decoder-input-output-embed共享输入输出 Embedding主通道投影直接复用 token embedding 权重见 speech_dlm_decoder.py--tokens-per-sample 6144 --sample-break-mode none每个样本截取 6144 个 token、按固定长度切块对应任务配置tokens_per_sample与sample_break_mode见 speech_dlm_task.py--max-tokens 18432 --update-freq 16单步前向 token 上限 18432累积 16 步更新一次梯度等效 batch 较大--lr 0.0005 --lr-scheduler inverse_sqrt --warmup-updates 20000 --warmup-init-lr 1e-07inverse_sqrt 学习率调度与 20000 步 warmup--fp16 --checkpoint-activations混合精度训练 激活检查点以显存换训练稳定性checkpoint_activations会包装每个解码器层见 speech_dlm_decoder.py。5.4 验证模型训练完成后可用fairseq-validate在验证集上评估困惑度等指标fairseq-validate $BIN_DATA_DIR \ --task speech_dlm_task \ --path $CHECKPOINT_PATH \ --max-tokens 6144任务源码的 docstring 中明确提示speech_dlm_task仅与fairseq-train和fairseq-validate兼容生成新样本请使用 examples/textless_nlp/dgslm/ 下的示例代码见 fairseq/tasks/speech_dlm_task.py。六、Unit-to-Speech 解码器用 HiFi-GAN vocoder 回放语音6.1 命令行合成双通道波形SpeechDLM 生成的单元序列仍是离散码需要经过基于离散单元的 HiFi-GAN vocoder 合成为波形。vocoder 在 Fisher 数据集上训练检查点与配置可从 examples/textless_nlp/dgslm/vocoder_hifigan/README.md 下载vocoder 模型 config.json。使用 examples/textless_nlp/dgslm/vocoder_hifigan/generate_stereo_waveform.py 合成python examples/textless_nlp/dgslm/vocoder_hifigan/generate_stereo_waveform.py \ --in-file $INPUT_CODE_FILE \ --vocoder $VOCODER_PATH \ --vocoder-cfg $VOCODER_CONFIG \ --results-path $OUTPUT_DIR输入文件格式与采样脚本一致每行一个含audio, unitA, unitB的字典{audio: file_1, unitA: 8 8 ... 352 352, unitB: 217 8 ... 8 8} {audio: file_2, unitA: 5 5 ... 65 65, unitB: 6 35 ... 8 9} ...该脚本其余可选参数见 generate_stereo_waveform.py--channels unitA,unitB、--sample-rate 16000、--channel1-spk 0通道 1 说话人 ID、--channel2-spk 4通道 2 说话人 ID默认与通道 1 不同、--mix把两通道混合成单声道输出、--cpu强制 CPU 推理。6.2 用 HifiganVocoder 交互式解码同样可以使用 dgslm_utils.py 中的HifiganVocoder类交互式合成。从源码看其内部基于CodeHiFiGANVocoder来自 fairseq/models/text_to_speech/vocoder.pycodes2wav会把两个通道的单元串分别经code2wav解码后再堆叠为(2, n_samples)的立体声数组# Load the Hifigan vocoder from examples.textless_nlp.dgslm.dgslm_utils import HifiganVocoder decoder HifiganVocoder( vocoder_path /path/to/hifigan_vocoder, vocoder_cfg_path /path/to/config.json, ) # Decode the units to waveform codes [ 7 376 376 133 178 486 486 486 486 486 486 486 486 2 486, 7 499 415 177 7 7 7 7 7 7 136 136 289 289 408, ] wav decoder.codes2wav(codes) # array of shape (2, 4800) # Play the waveform import IPython.display as ipd ipd.Audio(wav, rate16_000)注意codes2wav的默认说话人 ID 为[0, 4]见 dgslm_utils.py与命令行脚本的--channel1-spk/--channel2-spk默认值一致用于区分两个对话者若 vocoder 模型是multispkr多说话人版本还会额外传入 speaker ID见 dgslm_utils.py。七、端到端流程小结将以上三个组件串联即构成完整的 dGSLM 文本无关口语对话生成流水线编码用 Fisher HuBERT第 12 层特征 500 单元 k-means把双通道音频编码为unitA/unitB单元序列quantize_with_kmeans.py 或HubertTokenizer对话续写把单元序列作为前缀喂给 SpeechDLMspeech_dlm_base.pt采样生成两个通道后续的单元序列sample_speech_dlm.py 或SpeechDLM.sample()解码回放用基于离散单元的 HiFi-GAN vocoder 把生成的单元序列合成双通道波形generate_stereo_waveform.py 或HifiganVocoder。如需从头训练则按数据准备 → fairseq-preprocess 双通道二值化 → fairseq-train 训练 SpeechDLM → fairseq-validate 验证的顺序执行且注意任务只支持fairseq-train/fairseq-validate推理采样必须走 examples/textless_nlp/dgslm/ 下的脚本与 Hub 接口。八、引用与进一步阅读如果在研究中使用了 dGSLM官方建议引用论文bibtex 详见 examples/textless_nlp/dgslm/README.md 的 Reference 小节article{nguyen2022dgslm, title {Generative Spoken Dialogue Language Modeling}, author {Nguyen, Tu Anh and Kharitonov, Eugene and Copet, Jade and Adi, Yossi and Hsu, Wei-Ning and Elkahky, Ali and Tomasello, Paden and Algayres, Robin and Sagot, Benoit and Mohamed, Abdelrahman and Dupoux, Emmanuel}, eprint{2203.16502}, archivePrefix{arXiv}, primaryClass{cs.CL}, year{2022} }仓库内值得进一步阅读的资料还包括编码器与解码器的完整使用说明examples/textless_nlp/dgslm/hubert_fisher/README.md、examples/textless_nlp/dgslm/vocoder_hifigan/README.md、模型与任务核心实现fairseq/models/speech_dlm/、fairseq/tasks/speech_dlm_task.py、损失实现fairseq/criterions/speech_dlm_criterion.py以及工具脚本examples/textless_nlp/dgslm/dgslm_utils.py、examples/textless_nlp/dgslm/create_code_file.py。【免费下载链接】fairseqFacebook AI Research Sequence-to-Sequence Toolkit written in Python.项目地址: https://gitcode.com/gh_mirrors/fa/fairseq创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表