语音合成技术在过去几年里已经能生成非常接近真人的音频,但在虚拟主播、数字人、游戏NPC等场景中,用户看到的并不只有声音。如果虚拟角色的嘴型与声音不同步,或者表情和语气完全不搭,整体真实感会迅速下降。TTS多模态合成要解决的就是这类问题:让语音、口型和表情在同一个生成框架中协同工作。

传统TTS流水线通常只负责把文本转成声学特征,再由声码器还原波形。多模态合成在这个基础上增加了一条视觉分支,输出面部关键点位移或blendshape权重,并与音频帧保持相同的时间分辨率。这样设计后,韵律变化可以同时驱动声音和面部动作,比如重读音节对应更大幅度的下颌开合和眉毛抬起。要让这一点真正落地,数据表示必须同时覆盖声学和视觉两个域,并且能够在时间轴上严格对齐。
一、多模态合成的数据表示与整体架构
多模态TTS的输入虽然仍然是一段文本,但它的内部表示比传统TTS复杂得多。文本前端除了生成音素序列和韵律标记外,还要额外提供情绪标签、重音位置以及可能的说话风格编码。输出侧不再只有梅尔频谱或波形点,而是并行地产生视觉帧序列。视觉帧通常用两种方式表达:一种是基于面部动作编码系统FACS的动作单元AU,例如AU12对应嘴角上扬,AU25对应嘴唇分开;另一种是三维模型中的blendshape权重,每个权重控制局部区域的形变程度。两种表达可以互相转换,但在实时渲染中,blendshape更容易被引擎直接消费。
为了让声学和视觉分支共享同样的时间步,模型通常会在帧级别进行预测。声学帧的帧移一般是10到12毫秒,视觉帧可以保持相同帧率,也可以在渲染端做插值。输入文本经过编码后得到音素序列及其时长,时长预测器负责把音素展开到声学帧。视觉分支并不是独立工作,它会读取声学编码器的中间特征,或者读取与声学帧对应的注意力上下文,从而保证口型变化和声音波形在时间上不发生漂移。
一个完整的训练样本可以表示成下面的JSON结构。这个结构同时记录了音素、情绪和每一帧的视觉参数,训练时按时间索引读取对应数据。
{
"text": "你好,欢迎使用多模态合成",
"phonemes": ["n i3", "h ao3", "h uan1", "y ing2", "sh i3", "y ong4", "d uo1", "m o2", "t ai4", "h e2", "ch eng2"],
"emotion": "happy",
"frames": [
{
"time": 0.12,
"jaw_open": 0.18,
"lip_round": 0.05,
"au12": 0.42,
"au25": 0.31
},
{
"time": 0.24,
"jaw_open": 0.46,
"lip_round": 0.02,
"au12": 0.55,
"au25": 0.67
}
]
}
这种数据表示的好处是边界清晰,音频特征和视觉特征可以分别交给不同的解码器,但共享同一个编码器和时长模型。训练时,声学解码器和视觉解码器会联合优化,损失函数对两边都有约束,从而避免出现语音很自然但口型完全对不上的情况。
二、表情驱动与口型同步的关键技术
口型同步的核心任务是根据音素序列预测对应的视素序列。视素可以理解为视觉上的音素,一个视素可能对应多个发音相近的音素。例如双唇音p、b、m在视觉上都表现为双唇闭合,因此可以归为同一个视素。下面这段Python代码演示了一个简化版的音素到视素映射。
phoneme_to_viseme = {
"p": 0, "b": 0, "m": 0,
"f": 1, "v": 1,
"t": 3, "d": 3, "s": 3, "z": 3,
"k": 5, "g": 5, "n": 5, "l": 5,
"aa": 6, "ae": 6, "ah": 6,
"ao": 7, "ow": 7, "oy": 7,
"iy": 8, "y": 8,
"uw": 9, "w": 9, "uh": 9,
"sil": 10
}
def text_to_viseme_sequence(phonemes):
return [phoneme_to_viseme.get(p, 10) for p in phonemes]
规则映射可以解决一部分口型问题,但真实说话时的口型受到协同发音影响很大。一个音素前后的邻居会改变嘴唇动作,所以仅靠查表很容易出现机械感。更可靠的方案是用序列到序列模型直接学习音素上下文到视素参数的映射,再用时间对齐损失约束输出节奏。有些实现会用循环神经网络或Transformer解码器逐帧生成blendshape权重,输入包含当前音素、相邻音素以及已生成的声学帧特征。
表情驱动比口型同步更复杂,因为表情不仅与文本内容相关,还和情绪状态、说话风格、语境强相关。一种做法是显式控制,在输入文本前指定情绪标签,比如开心、悲伤、愤怒,然后通过条件编码让表情强度在生成过程中保持稳定。另一种做法是从语音韵律中隐式推断表情,例如基频较高、能量波动较大时倾向于生成更明显的眉毛抬起和嘴角上扬。两种方法可以组合,显式标签决定情绪基调,韵律特征控制表情的细微变化。
面部动作单元AU是表情驱动中常用的中间表示。AU12代表嘴角上扬,AU04代表眉毛下压,AU25代表嘴唇分开。模型可以输出AU强度值,渲染端再把这些AU转换成具体的面部形变。这样做比直接预测顶点位移更容易训练,因为AU空间维度低,而且语义明确。不过AU到blendshape的转换需要一套稳定的映射逻辑,否则可能出现表情不自然或左右脸不对称。
三、训练策略与损失函数设计
多模态TTS的训练目标比单一语音合成更复杂,需要同时照顾音频质量、口型准确度和表情自然度。常用的做法是多任务学习,把声学损失、视觉损失和同步损失加权求和。声学损失可以用L1或MSE约束梅尔频谱,视觉损失同样可以用L1约束blendshape或AU参数。除此之外,同步损失非常重要,它通常计算预测口型序列与真实口型序列在时间变化率上的差异,防止口型整体滞后或超前。
import torch
import torch.nn as nn
class MultimodalLoss(nn.Module):
def __init__(self):
super().__init__()
self.l1 = nn.L1Loss()
self.mse = nn.MSELoss()
def forward(self, pred_mel, gt_mel, pred_viseme, gt_viseme, pred_au, gt_au):
mel_loss = self.l1(pred_mel, gt_mel)
viseme_loss = self.mse(pred_viseme, gt_viseme)
au_loss = self.l1(pred_au, gt_au)
sync_loss = self.mse(pred_viseme[:, 1:] - pred_viseme[:, :-1],
gt_viseme[:, 1:] - gt_viseme[:, :-1])
total = mel_loss + 0.8 * viseme_loss + 0.5 * au_loss + 0.3 * sync_loss
return total
损失权重不是固定不变的。在训练早期,视觉分支可能还没有学会稳定输出,此时可以适当降低视觉损失权重,让声学分支先收敛到较好的韵律状态。训练后期再逐步提高视觉和同步损失的比重,让模型集中优化口型对齐。这种方式类似于课程学习,先用较简单的目标引导模型进入合理参数空间,再加入更难的多模态约束。
对抗训练也常被用于提升生成质量。可以在视觉输出端加一个判别器,判断生成的口型序列是否来自真实录制数据。判别器会强迫生成器输出更自然的下颌运动和嘴唇形变,避免只满足帧级回归却忽略整体动态。声学端同样可以用GAN来改善频谱细节,但需要谨慎平衡,因为多个判别器同时训练会让优化过程不稳定。实际工程中往往先用回归损失训练到基本可用的程度,再引入对抗损失做微调。
四、工程实现与性能优化
在工程落地时,多模态TTS通常需要满足实时或近实时的推理要求。文本到语音本来就有一定延迟,如果还要等待视觉分支逐帧生成,总延迟可能明显增加。优化手段包括模型轻量化、层融合和推理缓存。对于口型序列,很多情况下视觉帧变化比音频帧慢,可以在生成完整口型序列后由渲染端按时间轴播放,不需要逐帧等待模型输出。音频则可以用流式声码器分块合成,减少首包延迟。
下面是一个简化的实时推理流程。文本前端先得到音素和时长,然后模型在循环中同时输出声学帧和视觉帧,分别进入音频队列和面部队列,下游设备按时间戳消费。
def run_realtime_tts(text):
phonemes, durations = text_encoder(text)
audio_queue = []
face_queue = []
for frame_idx in range(len(phonemes)):
mel_frame, viseme_frame, au_frame = model.step(phonemes, frame_idx)
audio_queue.append(vocoder(mel_frame))
face_queue.append(blendshape_solver(viseme_frame, au_frame))
return audio_queue, face_queue
另一个容易忽略的工程问题是数据同步。训练数据如果来自不同设备录制,音频和视频帧之间可能存在固定偏移。这个偏移如果不校正,模型学到的口型就会天然滞后或提前。通常会用音视频对齐工具先估算偏移量,再统一重采样到相同帧率,并保证每个训练样本的起始和结束位置一致。数据清洗阶段还需要过滤掉说话人转头、遮挡嘴部或光照变化过大的片段,否则视觉分支可能会学到与口型无关的图像噪声。
实时渲染端也有优化空间。blendshape权重往往只控制嘴部和眉眼区域,如果模型输出了全脸关键点,渲染系统需要做平滑处理。简单的指数平滑或滑动平均可以消除帧间抖动,但平滑窗口过大会让口型开合看起来迟钝。更合理的方案是只在关键帧之间做插值,并保留快速的闭合动作,比如双唇音p、b的闭合需要在一帧内完成,不能因为平滑而丢失。
多模态TTS并不是语音合成和口型动画的简单叠加,它需要在数据、模型和工程三个层面同步设计。把表情和口型纳入统一的生成框架后,虚拟角色的表达会明显更自然,语音的重音、节奏和情绪也能通过视觉通道传递出来。随着端侧算力提升和高质量音视频数据的积累,这类技术会越来越多地进入实时交互场景。

