写在前面
本博客是我对这篇论文的翻译和笔记理解,论文原文链接:ICCV 2023 Open Access Repository,代码开源。GitHub – zhoubenjia/GFSLT-VLP · GitHub
目录
写在前面
论文“故事”概述
论文要解决的问题
论文的核心想法
预训练和对比学习相关概念补充
0.摘要
1.Introduction
2.相关工作
2.1.手语识别
2.2.基于 Gloss 的手语翻译
2.3.无 Gloss 手语翻译
3.方法
3.1.视觉—语言预训练
视觉编码器
文本编码器
文本解码器
3.2.无 Gloss 手语翻译
4.实验
4.1.数据集和评估方法
4.2.实施细节
视觉编码器
文本解码器
预训练阶段
4.3.和SOTA的对比
4.4.消融实验
视觉—语言预训练
训练时间研究
模型参数规模的影响
冻结 Text Encoder 的影响
4.5.定性结果
5.结论和未来工作
论文“故事”概述
这篇论文想证明:手语翻译不一定需要昂贵的 gloss 标注;只要先通过视觉—语言预训练,让视频编码器学会提取“接近语言语义”的视觉特征,再进行端到端翻译,就可以显著提高无 gloss 手语翻译的效果。它比一般机器翻译困难,因为输入是连续的视频动作,输出却是离散的语言文本,二者之间存在很大的跨模态语义鸿沟。
论文要解决的问题
- 传统“先识别gloss再翻译”的方法虽然有效,但Gloss 标注非常昂贵、且Gloss 会形成信息瓶颈,即手语中的表情、动作幅度、空间位置以及连续动作关系,可能无法被简单的 gloss 序列完整表达。一旦信息在 gloss 阶段丢失,后续翻译模型无法恢复。
- 现有的gloss-free方法可能学到了动作或外观信息,却未必知道哪些视觉变化对应句子的核心语义,即不够“语言化”,缺少了明确的中间监督信号。
论文的核心想法
训练视觉编码器时,不只是要求它识别视频内容,而是要求它提取出的整体视频表示,在语义空间中接近对应的自然语言句子,该过程分为两阶段:
并且作者通过实验发现“无 gloss 手语翻译的主要瓶颈是视觉表示,而不是单纯的语言生成能力”以及“第二阶段的训练epoch数提升和数据规模的提升也能带来稳定收益”。
VLP 的作用不仅是让句子更流畅,更重要的是:提高视频语义与具体语言词汇之间的对应准确性。
预训练和对比学习相关概念补充
预训练的作用:
- 视觉编码器:通过视频—文本对比学习,学会把手语视频编码成带有语言语义的视觉表示。
- 文本编码器:作为预训练阶段的辅助桥梁,用来编码文本、指导视觉对齐以及支持掩码恢复;它不会进入第二阶段(后续微调),它的作用就是编码文本,让视觉编码器知道哪些视频信息与句子的语言语义相关(同时对于本文,它还与训练了文本解码器的句法恢复能力)。
- 文本解码器:通过掩码句子恢复,提前学习句法、语义和文本生成能力。
微调阶段:把预训练的 Visual Encoder 和 Text Decoder 接起来,两者之间的跨注意力和输出层也一起适配。因为第一阶段的文本编码来自文本编码器,但第二阶段不用文本编码器,所以需要有第二阶段的训练,即微调。
大规模外部相关数据预训练→目标训练集上的继续预训练→目标任务微调,即如本文的,ImageNet 上预训练的 ResNet18 和 CC25 文本语料上预训练的 mBART → VLP 阶段在各自的训练集进行任务相关预训练→第二阶段仍在同一训练集上进行端到端 SLT 微调。因为两个阶段学习的任务不同,所以使用相同的(视频,文本)对没有关系,只要不在预训练阶段使用测试集的视频或对应文本即可。
简单实现双向对比学习:
import torch
import torch.nn as nn
import torch.nn.functional as F
class SimpleVLP(nn.Module):
def __init__(
self,
video_input_dim: int,
text_input_dim: int,
projection_dim: int = 256,
):
super().__init__()
# 简化的视觉编码器 + 投影头
self.video_encoder = nn.Sequential(
nn.Linear(video_input_dim, 512),
nn.ReLU(),
nn.Linear(512, projection_dim),
)
# 简化的文本编码器 + 投影头
# 论文中这里对应 mBART Text Encoder
self.text_encoder = nn.Sequential(
nn.Linear(text_input_dim, 512),
nn.ReLU(),
nn.Linear(512, projection_dim),
)
# 温度系数,控制相似度分布的尖锐程度
self.logit_scale = nn.Parameter(
torch.tensor(1.0 / 0.07).log()
)
def forward(
self,
video_features: torch.Tensor,
text_features: torch.Tensor,
):
# video_embedding: [batch_size, projection_dim]
video_embedding = self.video_encoder(video_features)
# text_embedding: [batch_size, projection_dim]
text_embedding = self.text_encoder(text_features)
# L2 归一化,使点积等价于余弦相似度
video_embedding = F.normalize(video_embedding, dim=-1)
text_embedding = F.normalize(text_embedding, dim=-1)
# 计算一个批次内所有视频和文本之间的相似度
# logits[i, j] 表示第 i 个视频与第 j 个句子的相似度
logits = self.logit_scale.exp() * (
video_embedding @ text_embedding.T
) # 构造对角线label正样本最核心的一步
batch_size = logits.size(0)
# 正确配对位于相似度矩阵的对角线上:
# 第 i 个视频应该对应第 i 个文本
labels = torch.arange(batch_size, device=logits.device)
# 视频找文本(单向InfoNCE,就是一次基于正负样本相似度的交叉熵)
loss_video_to_text = F.cross_entropy(logits, labels)
# 文本找视频(单向InfoNCE)
loss_text_to_video = F.cross_entropy(logits.T, labels)
# 对称对比损失
loss = (loss_video_to_text + loss_text_to_video) / 2
return loss, logits
# —————- 使用示例 —————-
batch_size = 8
# 假设已经获得视频特征和文本特征
video_features = torch.randn(batch_size, 1024)
text_features = torch.randn(batch_size, 768)
model = SimpleVLP(
video_input_dim=1024,
text_input_dim=768,
projection_dim=256,
)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
loss, similarity_matrix = model(video_features, text_features)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("对比学习损失:", loss.item())
print("相似度矩阵形状:", similarity_matrix.shape)
简单实现预训练掩码恢复:
"""
掩码句子恢复的整体流程
========================================
原始句子:
<bos> 今天 天气 很 好 <eos>
步骤 1:随机掩码部分内容
<bos> 今天 <mask> 很 好 <eos>
步骤 2:Text Encoder 编码掩码后的句子
masked_sentence_ids
-> Token Embedding + Position Embedding
-> Transformer Encoder
-> 带有上下文信息的编码表示 memory
步骤 3:Text Decoder 根据两个信息恢复原句
① Text Encoder 输出的 memory
② 已经生成或已知的前文
训练时使用教师强制:
Decoder 输入:
<bos> 今天 天气 很 好
监督标签:
今天 天气 很 好 <eos>
步骤 4:使用交叉熵损失训练
Decoder 在每个位置预测原始句子的下一个词
注意:
这里演示的是完整句子重建,而不仅仅预测被掩码的位置。
这更接近编码器—解码器式的去噪预训练。
"""
import torch
import torch.nn as nn
import torch.nn.functional as F
class MaskedSentenceRecovery(nn.Module):
"""
简化版掩码句子恢复模型。
输入:
1. 被掩码的句子
2. 右移后的原始句子
输出:
原始句子中每个位置的词表概率
"""
def __init__(
self,
vocab_size: int,
hidden_dim: int = 128,
num_heads: int = 4,
num_layers: int = 2,
max_length: int = 32,
):
super().__init__()
# 将词编号转换为连续向量
self.token_embedding = nn.Embedding(
num_embeddings=vocab_size,
embedding_dim=hidden_dim,
)
# 为每个词加入位置信息
self.position_embedding = nn.Embedding(
num_embeddings=max_length,
embedding_dim=hidden_dim,
)
# 包含 Text Encoder 和 Text Decoder 的完整 Transformer
self.transformer = nn.Transformer(
d_model=hidden_dim,
nhead=num_heads,
num_encoder_layers=num_layers,
num_decoder_layers=num_layers,
dim_feedforward=hidden_dim * 4,
dropout=0.1,
batch_first=True,
)
# 将 Decoder 的隐藏向量映射到词表大小
self.output_layer = nn.Linear(
hidden_dim,
vocab_size,
)
def embed_tokens(
self,
token_ids: torch.Tensor,
) -> torch.Tensor:
"""
给词编号加入 Token Embedding 和 Position Embedding。
参数:
token_ids:
[batch_size, sequence_length]
返回:
embeddings:
[batch_size, sequence_length, hidden_dim]
"""
batch_size, sequence_length = token_ids.shape
# 为每个位置生成编号:0, 1, 2, …
position_ids = torch.arange(
sequence_length,
device=token_ids.device,
)
# 扩展到整个 batch
position_ids = position_ids.unsqueeze(0).expand(
batch_size,
sequence_length,
)
token_embeddings = self.token_embedding(token_ids)
position_embeddings = self.position_embedding(position_ids)
return token_embeddings + position_embeddings
def forward(
self,
masked_sentence_ids: torch.Tensor,
decoder_input_ids: torch.Tensor,
) -> torch.Tensor:
"""
masked_sentence_ids:
被掩码后的句子。
这是 Text Encoder 的输入。
decoder_input_ids:
右移后的原始句子。
这是 Text Decoder 的输入。
"""
# ====================================================
# 第一步:准备 Text Encoder 的输入
# ====================================================
# 注意:这里编码的是“掩码后的句子”
encoder_embeddings = self.embed_tokens(
masked_sentence_ids
)
# ====================================================
# 第二步:准备 Text Decoder 的输入
# ====================================================
decoder_embeddings = self.embed_tokens(
decoder_input_ids
)
target_length = decoder_input_ids.size(1)
# Decoder 使用因果掩码:
# 当前位置只能看到自己以及之前的词,
# 不能偷看未来的目标词。
causal_mask = nn.Transformer.generate_square_subsequent_mask(
target_length,
device=decoder_input_ids.device,
)
# ====================================================
# 第三步:执行编码和解码
# ====================================================
# 内部计算过程可以理解为:
#
# memory = TextEncoder(encoder_embeddings)
# hidden = TextDecoder(
# decoder_embeddings,
# memory
# )
#
# 这里 nn.Transformer 将两步封装在一起。
decoder_hidden_states = self.transformer(
src=encoder_embeddings,
tgt=decoder_embeddings,
tgt_mask=causal_mask,
)
# ====================================================
# 第四步:预测每个位置的词
# ====================================================
# 输出形状:
# [batch_size, target_length, vocab_size]
logits = self.output_layer(
decoder_hidden_states
)
return logits
# ============================================================
# 一、构建一个用于演示的小词表
# ============================================================
vocab = [
"<pad>",
"<bos>",
"<eos>",
"<mask>",
"今天",
"天气",
"很",
"好",
"明天",
"可能",
"会",
"下雨",
]
word_to_id = {
word: index
for index, word in enumerate(vocab)
}
id_to_word = {
index: word
for word, index in word_to_id.items()
}
PAD_ID = word_to_id["<pad>"]
BOS_ID = word_to_id["<bos>"]
EOS_ID = word_to_id["<eos>"]
MASK_ID = word_to_id["<mask>"]
# ============================================================
# 二、构造 Text Encoder 的输入
# ============================================================
# 原始句子 1:
# <bos> 今天 天气 很 好 <eos>
#
# 掩码句子 1:
# <bos> 今天 <mask> 很 好 <eos>
#
# 原始句子 2:
# <bos> 明天 可能 会 下雨 <eos>
#
# 掩码句子 2:
# <bos> 明天 可能 <mask> 下雨 <eos>
# 这个张量就是 Text Encoder 的输入。
# 因此,Text Encoder 编码的是掩码后的句子。
masked_sentence_ids = torch.tensor([
[
BOS_ID,
word_to_id["今天"],
MASK_ID,
word_to_id["很"],
word_to_id["好"],
EOS_ID,
],
[
BOS_ID,
word_to_id["明天"],
word_to_id["可能"],
MASK_ID,
word_to_id["下雨"],
EOS_ID,
],
])
# ============================================================
# 三、构造 Text Decoder 的输入
# ============================================================
# 训练阶段采用教师强制。
#
# 原目标:
# <bos> 今天 天气 很 好 <eos>
#
# Decoder 输入去掉最后一个词:
# <bos> 今天 天气 很 好
#
# 监督标签去掉第一个词:
# 今天 天气 很 好 <eos>
#
# 因而 Decoder 学习:
# 看到 <bos> -> 预测 今天
# 看到 <bos> 今天 -> 预测 天气
# 看到 <bos> 今天 天气 -> 预测 很
# …
decoder_input_ids = torch.tensor([
[
BOS_ID,
word_to_id["今天"],
word_to_id["天气"],
word_to_id["很"],
word_to_id["好"],
],
[
BOS_ID,
word_to_id["明天"],
word_to_id["可能"],
word_to_id["会"],
word_to_id["下雨"],
],
])
# ============================================================
# 四、构造监督标签
# ============================================================
target_ids = torch.tensor([
[
word_to_id["今天"],
word_to_id["天气"],
word_to_id["很"],
word_to_id["好"],
EOS_ID,
],
[
word_to_id["明天"],
word_to_id["可能"],
word_to_id["会"],
word_to_id["下雨"],
EOS_ID,
],
])
# ============================================================
# 五、创建模型和优化器
# ============================================================
model = MaskedSentenceRecovery(
vocab_size=len(vocab),
hidden_dim=128,
num_heads=4,
num_layers=2,
)
optimizer = torch.optim.Adam(
model.parameters(),
lr=1e-3,
)
# ============================================================
# 六、训练模型
# ============================================================
model.train()
for step in range(200):
# 前向传播:
# 掩码句子进入 Encoder,
# 右移原句进入 Decoder。
logits = model(
masked_sentence_ids=masked_sentence_ids,
decoder_input_ids=decoder_input_ids,
)
# logits 原始形状:
# [batch_size, target_length, vocab_size]
#
# cross_entropy 需要:
# 输入:[样本总数, vocab_size]
# 标签:[样本总数]
loss = F.cross_entropy(
logits.reshape(-1, len(vocab)),
target_ids.reshape(-1),
ignore_index=PAD_ID,
)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (step + 1) % 50 == 0:
print(
f"Step {step + 1:3d}, "
f"loss = {loss.item():.4f}"
)
# ============================================================
# 七、查看预测结果
# ============================================================
model.eval()
with torch.no_grad():
logits = model(
masked_sentence_ids=masked_sentence_ids,
decoder_input_ids=decoder_input_ids,
)
# 在词表维度上选择概率最大的词
predicted_ids = logits.argmax(dim=-1)
for sentence_index, sentence_ids in enumerate(predicted_ids):
predicted_words = [
id_to_word[token_id.item()]
for token_id in sentence_ids
]
print(
f"第 {sentence_index + 1} 个预测句子:",
" ".join(predicted_words),
)
0.摘要
手语翻译(Sign Language Translation,SLT)是一项具有挑战性的任务,因为它具有跨模态、跨领域的性质,需要将视觉—手势语言翻译为文本。许多以往的方法采用一种中间表示,即手语词汇标注序列(gloss sequence),来辅助完成手语翻译,从而将该任务转化为一个两阶段过程:首先进行手语识别(Sign Language Recognition,SLR),然后进行手语翻译(SLT)。然而,带有 gloss 标注的手语数据十分稀缺,同时,中间层的 gloss 表示还会造成信息瓶颈,这些问题阻碍了手语翻译任务的进一步发展。
为了解决这一挑战,本文提出了一种基于视觉—语言预训练的新型无 gloss 手语翻译方法,称为 GFSLT-VLP(Gloss-Free Sign Language Translation based on Visual-Language Pretraining)。该方法完全不借助任何 gloss 标注,而是通过继承预训练模型中面向语言的先验知识来提升手语翻译性能。本文的方法包含两个阶段:
第一阶段,将对比式语言—图像预训练(Contrastive Language-Image Pretraining,CLIP)与掩码自监督学习相结合,构建相应的预训练任务。这些任务一方面用于缩小视觉表示与文本表示之间的语义差距,另一方面用于恢复被掍码的句子内容。
第二阶段,构建一个端到端的编码器—解码器式网络架构,并继承第一阶段中预训练得到的视觉编码器和文本解码器参数。
这些新设计的有机结合,使模型能够学习到更加鲁棒的手语表示,并显著提升无 gloss 手语翻译的性能。
具体而言,与当前最先进的无 gloss 手语翻译方法相比,本文方法在 PHOENIX14T 数据集上的 BLEU-4 分数取得了至少 5分以上的提升,在 CSL-Daily 数据集上取得了至少 3分以上的提升,达到了此前未有过的改进幅度。此外,在 PHOENIX14T 数据集上,与大多数依赖 gloss 标注的方法相比,本文方法也取得了具有竞争力的结果。
1.Introduction
手语是聋人群体之间主要的交流媒介。为了促进聋人与听障程度较轻者之间的有效沟通,发展手语翻译(Sign Language Translation,SLT)技术是一个很有前景的方向。手语翻译是指将手语翻译成流畅的口语语言句子。由于手语翻译具有跨模态翻译的性质,并且可用的标注数据十分稀缺,因此它比传统的神经机器翻译(Neural Machine Translation,NMT)更具挑战性。
近年来,越来越多的研究工作通过直接或间接地使用一种中间表示——手语 gloss,来提升手语翻译性能。如 Figure 1(a) 所示,gloss 是对连续视频中各个手语单元的一种简化表示。尽管与端到端的无 gloss 方法相比(如 Figure 1(b) 所示),基于 gloss 的方法已经显著提升了手语翻译性能,但前者仍然存在以下问题:第一,gloss 标注是一项劳动密集型工作,需要进行细粒度对齐,并由专业人员完成标注,这极大地限制了基于 gloss 的手语翻译方法的可扩展性;第二,基于 gloss 的方法在中间层 gloss 表示处引入了信息瓶颈,这限制了网络理解手语的能力,因为翻译模型的性能上限受制于训练时使用的手语 gloss 标注质量。

受到 CLIP 的启发,CLIP 利用自然语言监督来学习图像表示;作者发现,从手语视频中学习语言指示的视觉表示,可以成为一种有效的手语翻译预训练任务,因为它能够在视觉手语动作与语言上下文之间建立潜在联系。然而,将 CLIP 直接应用于手语翻译仍然面临两个挑战:第一,它不具备为手语翻译联合预训练 Visual Encoder 和 Text Decoder 的能力;第二,这种预训练任务需要足够多的手语翻译数据。为解决这些障碍,作者需要回答两个关键问题:第一,如何利用有限的手语翻译数据集,高效地完成联合预训练?第二,如何保证预训练模型能够为下游手语翻译任务提供最有效的帮助?
为了克服第一个挑战,作者分别从算法层面和数据层面提出了解决方案。在算法层面,作者提出了一种新的预训练方法,称为视觉—语言预训练(Visual-Language Pretraining,VLP),如 Figure 2(a) 所示。该方法将掩码自监督学习与 CLIP 结合起来。具体来说,作者设计了一个预文本任务,将视觉表示和文本表示对齐到一个共享的多模态语义空间中,从而引导 Visual Encoder 学习语言指示的视觉表示。与此同时,作者在预训练过程中引入掩码自监督学习,帮助 Text Decoder 捕捉手语目标句子的句法和语义属性。在数据层面,作者研究了一组用于手语视频的强数据增强技术,以增加视觉数据的多样性;这一方面在以往的手语翻译方法中经常被忽视。
为了应对第二个问题,如 Figure 2(b) 所示,作者设计了一个端到端的无 gloss 手语翻译架构,称为 GFSLT。该架构采用编码器—解码器形式,并继承第一阶段预训练得到的 Visual Encoder 和 Text Decoder 参数。GFSLT 能够在不需要任何中间步骤或中间指导的情况下,直接将视觉表示转换成自然语言句子。此外,与其他只微调 Visual Encoder 中空间特征提取器,即视觉嵌入模块的方法不同,作者将空间特征提取器与时间关系建模网络,即 Transformer Encoder,作为一个统一整体进行微调。

- (a)包含两条同时进行的训练分支
- 视频—文本对比学习分支,两种特征经过各自的投影头后进入共享多模态空间,计算视频和文本的相似度,使正确的视频—句子对更加接近(图中实线)。
- 掩码句子恢复分支,负责预训练 Text Decoder 的语言理解与生成能力(图中虚线)。
- (b)Visual Encoder 和 Text Decoder 继承第一阶段参数,然后使用视频—句子翻译目标进行端到端微调。
总而言之,本文的主要贡献如下:
- 在不使用 gloss 标注的情况下,本文在手语翻译的 BLEU-4 指标上取得了前所未有的提升。具体来说,与当时最先进的无 gloss 手语翻译方法相比,本文方法在 PHOENIX14T 数据集和 CSL-Daily 数据集上分别取得了至少 5 分和至少 3 分的提升。作者认为,这些提升代表了无 gloss 手语翻译任务上的一次重要突破。
- 据作者所知,这是首次在无 gloss 手语翻译任务中引入 VLP 策略,将视觉表示与文本表示对齐到一个共享的语义空间中。
- 作者提出了一种新的预训练范式,将掩码自监督学习与对比式语言—图像预训练结合起来,以促进无 gloss 手语翻译。与以往方法相比,该方法取得了显著改进,并有潜力大幅提升手语翻译系统的准确性和效率。
2.相关工作
总体而言,手语翻译(Sign Language Translation,SLT)方法可以分为两类:基于 gloss 的方法和无 gloss 的方法。在简要回顾这两个方向的研究工作之前,我们首先介绍手语识别(Sign Language Recognition,SLR)任务,因为它是基于 gloss 的手语翻译方法中的一个关键步骤。
2.1.手语识别
手语识别(SLR)包含两种不同的任务:孤立手语识别(Isolated Sign Language Recognition,ISLR)和连续手语识别(Continuous Sign Language Recognition,CSLR)。ISLR 的目标是将一个孤立的手语动作转换为对应的单个手语词汇,这一任务与孤立手势识别任务有些相似。CSLR 则是一项更具挑战性的任务,它致力于将一段连续的手语视频识别为按顺序排列的手语词汇,这些词汇序列被称为 gloss 序列。以往的手语翻译研究通常将 CSLR 作为一个预备任务,用于预测 gloss,或者用于获得更好的视觉表示。这类方法通常对 CSLR 的准确率有很高的要求。然而,在本文中,作者完全舍弃了 gloss 序列,并探索一种新的无 gloss 手语翻译方法。
2.2.基于 Gloss 的手语翻译
为了提升手语翻译性能,一些研究采用手语 gloss 作为中间层表示。SLRT 首次引入了一种基于 Transformer 的编码器—解码器框架,以执行端到端手语翻译。该方法利用连接时序分类(Connectionist Temporal Classification,CTC)损失,在手语视觉表示与 gloss 序列之间进行软匹配,从而提升模型性能。STMC-T 采用多线索学习的方式理解手语,并通过引入线索内部和线索之间的 CTC 损失来建模序列信息。SignBack 尝试将回译(back-translation) 等先进的机器翻译技术引入手语翻译。此外,得益于迁移学习在神经机器翻译中的成功应用,Chen 等人首次尝试将大型语言模型引入手语翻译。上述所有方法在手语翻译模型的训练过程中,都直接或间接地使用了 gloss 标注。然而,在本文的方法中,作者完全舍弃了 gloss 标注,因为 gloss 的存在限制了手语数据集规模的扩大。作为替代,本文引入了一种更加通用的手语预训练设计。
- Transformer 编码器—解码器如何执行端到端手语翻译?基本流程:手语视频→视觉特征(2DCNN)→Transformer Encoder(每一帧的特征先加入位置编码,然后理解整段动作包括其前后文)→Transformer Decoder(逐词生成)→自然语言句子;在 Encoder 后还有另一个使用 CTC 作为损失函数的识别分支,它们共同优化 Encoder。
- 多线索学习?不让一个网络只关注最明显的手部动作,而是分别提取多种视觉信息,再学习它们怎样共同表达手语含义。“线索内部”:对于每一种线索,如手部、面部等,单独学习它们自身独特的时序规律,避免有可能弱小但重要的面部信息被手部特征淹没,每条线索使用 CTC 是为了避免某条分支什么都学不到,这是辅助目标;“线索之间”:融合不同线索并学习它们之间的配合关系,不同线索不仅可能在同一时间发生,也可能存在时间上的先后配合。STMC 的线索内部路径分别保留各线索特征,线索之间路径则在不同时间尺度上融合这些特征,这是主要目标,依赖它完成最终识别。它是一个端到端网络,内部包含共享模块(骨干视觉网络)、多个单线索分支和一个融合分支。
2.3.无 Gloss 手语翻译
“无 gloss 手语翻译”是指在整个训练和测试过程中都不存在 gloss 监督,其中包括预训练阶段和微调阶段。NSLT 使用 CNN 与 RNN 的组合执行端到端手语翻译,其中 CNN 用于学习手语的视觉特征,而带有注意力机制的 RNN 则负责序列建模和文本建模。TSPNet 使用尺度间注意力和尺度内注意力,通过捕捉手语视频中的局部上下文与全局上下文来增强视觉特征学习。GASLT 揭示了 gloss 标注对手语翻译的重要作用,并引入了 gloss-attention,以利用 gloss 所带来的相关优势。与之不同,CSGCR 提出了三个模块——词语存在性验证、条件句子生成以及跨模态重排序——以学习更好的语法特征,从而提升手语翻译的准确性和流畅性。然而,由于手语视频中的动作顺序与口语句子的词语顺序存在显著差异,在没有 gloss 指导的情况下进行模态对齐十分困难。因此,无 gloss 手语翻译方法的性能通常低于基于 gloss 的方法。本文采用一种基于 VLP 的方法来获得更好的跨模态表示,从而有效缩小无 gloss 方法与基于 gloss 方法之间的性能差距。
3.方法
本文认为,语言指示的视觉表征同时具备语言信息的低冗余性与高度抽象性,因此能够改善手语翻译。为此,本文为手语翻译引入了一种新的预训练范式,将掩码自监督学习与 CLIP 相结合,从而为下游 GFSLT 模型联合预训练 Visual Encoder $\\psi_{VE}(\\cdot)$ 和 Text Decoder $\\psi_{TD}(\\cdot)$,具体见第 3.1 节。随后,本文将预训练后的 Visual Encoder $\\psi_{VE}^{*}(\\cdot)$ 和 Text Decoder $\\psi_{TD}^{*}(\\cdot)$ 的参数迁移到 GFSLT 模型 $\\psi_{GFSLT}(\\cdot)$ 中,以增强其翻译能力,具体见第 3.2 节。Algorithm 1 详细描述了整个算法流程。
-
这里的“语言指示”可以理解为:Visual Encoder 学到的不是普通动作识别特征,而是在文本语义监督下形成的视觉特征。

-
Stage1 中重复执行的内容是:对数据集 $\\mathcal D$ 中的每一对 $V^{(i)},S^{(i)}$:使用视频与文本之间的对比损失执行梯度下降从而更新对比分支中的 Visual Encoder 和 Text Encoder。获得掩码后的句子并用它恢复损失执行梯度下降从而更新 Text Decoder。
-
Stage2 中重复执行的内容是:对数据集 $\\mathcal D$ 中的每一对 $V^{(i)},S^{(i)}$:使用翻译损失执行梯度下降从而更新整个 $\\psi_{GFSLT}(\\cdot)$。
3.1.视觉—语言预训练
为了从手语视频中学习语言指示的视觉表征,需要考虑两个关键问题:第一,如何设计一种能够有效缩小视觉表征和文本表征之间语义差距的预文本任务?第二,如何在有限的手语翻译数据集上实现联合预训练?
为了解决第一个问题,我们从零样本迁移学习领域的 CLIP 中获得启发。CLIP 将“图像到文本”发展为一种标准化的输入—输出接口,使视觉模型能够通过自然语言监督获得迁移能力。CLIP 展示了从自然语言中学习相对于其他任务无关预训练方式的优势,因此特别适合手语翻译任务。换句话说,由于手语翻译数据天然具有图像—文本配对结构,利用语言监督学习视觉表征,是一种直接而有效的手语翻译预文本任务。基于这一认识,我们提出了一种新的视觉—语言预训练方案,称为 VLP,如 Figure 2(a) 所示。该方案联合训练 Visual Encoder $\\psi_{VE}(\\cdot)$ 和 Text Encoder $\\psi_{TE}(\\cdot)$,使模型能够从一个批次的“手语视频—自然语言句子”训练样本中预测正确的配对关系。形式化地,首先将视频—文本对分别输入 $\\psi_{VE}(\\cdot)$ 和 $\\psi_{TE}(\\cdot)$,得到相应的高维语义特征:
$$I_f=\\psi_{VE}(V),
\\qquad
V=(v_1,\\ldots,v_T);$$
$$I_y=\\psi_{TE}(S),
\\qquad
S=(s_1,\\ldots,s_U).$$
其中,$V$ 是一段包含 $T$ 帧的手语视频,$v_t$ 是视频中的第 $t$ 帧,$S$ 是一句包含 $U$ 个词的口语语言句子,$s_u$是句子中的第 $u$ 个词或子词 Token,$I_f$是Visual Encoder 输出的视觉特征序列。

视觉编码器
Visual Encoder 由一个 Vision Embedding 层以及随后堆叠的多层 Transformer Encoder 构成,其 Vision Embedding 结构如 Figure 3(b) 所示。视频中的每一帧首先经过共享权重的二维 CNN 编码;得到的视觉编码随后通过两个时间模块,这两个模块采用 Conv1D-BN-ReLU-MaxPooling 的组合来捕捉短期依赖关系。最后,特征被送入 Transformer Encoder,以捕捉视频中的长期依赖关系。
文本编码器
为了有效地编码文本数据,一个强大的 Text Encoder 至关重要。因此,作者选择使用 mBART 中的 12 层编码器进行参数初始化。mBART 是一个已经在 CC25 上完成预训练的神经机器翻译模型;CC25 是一个覆盖 25 种语言的多语言语料库。
随后,将提取到的视觉特征 $I_f$ 和文本特征 $I_y$ 分别输入对应的映射头,通过线性投影进入共享的多模态语义空间,以计算相似度。这里,两个映射头都只由一个简单的 Linear 层组成。形式化地,该过程表示为:
$$\\widetilde I_{f,c}
=
\\operatorname{Linear}(I_{f,c}),
\\qquad
\\widetilde I_{y,k}
=
\\operatorname{Linear}(I_{y,k}).$$
其中,$I_{f,c}$ 表示 Visual Encoder 最后一层在 [CLS] Token 位置的激活值;$I_{y,k}$ 表示 Text Encoder 最后一层在 <EOS> Token 位置的激活值。随后,与 CLIP 类似,对 $\\widetilde I_{f,c}$ 和 $\\widetilde I_{y,k}$ 进行层归一化和成对缩放,并利用对称交叉熵损失计算损失值:
$$\\mathcal L_s
=
-\\frac{1}{2}
\\left(
\\sum V\\log\\left(\\widetilde I_{f,c}\\right)
+
\\sum S\\log\\left(\\widetilde I_{y,k}\\right)
\\right).$$
-
[CLS] 是为了形成整个视频序列的全局表示而添加的特殊 Token。文本序列则由 <BOS> 和 <EOS> 包围,作者取 <EOS> 位置的激活作为整句话的全局表示。
为了解决第二个问题,作者在算法层面和数据层面同时采取措施。在算法层面,如 Figure 2(a) 所示,我们额外引入了一条辅助监督流——掩码自监督学习,即图中的虚线分支,从而实现联合预训练。在该分支中,Text Decoder $\\psi_{TD}(\\cdot)$ 接收由共享权重的 Text Encoder从掩码句子中提取的语言特征,并预测掩码区域中的词。
- 这里的“共享权重”意味着:
- 对比学习分支中的正常句子进入 $\\psi_{TE}$;
- 掩码恢复分支中的掩码句子也进入同一个 $\\psi_{TE}$;
- 两条分支不是各自使用一套独立的 Text Encoder。
文本解码器
Text Decoder 实际上是一个带有因果掩码的标准 Transformer Decoder。其优化目标可以表示为:
$$\\min_{\\Theta}
\\frac{1}{N}
\\sum_{i=1}^{N}
\\mathcal L_c
\\left(
\\psi_{TD}
\\left(
\\psi_{TE}^{*}
\\left(
\\widetilde S^{(i)}
\\right)
\\right),
S^{(i)}
\\right).$$
其中,$\\widetilde S$ 表示掩码后的句子,$N$ 表示训练样本数,$\\mathcal L_c$ 表示损失函数。可以拆解为:
$$\\widetilde S^{(i)}
\\rightarrow
\\psi_{TE}^{*}
\\left(
\\widetilde S^{(i)}
\\right)
\\rightarrow
\\psi_{TD}
\\left(
\\psi_{TE}^{*}
\\left(
\\widetilde S^{(i)}
\\right)
\\right)
\\rightarrow
S^{(i)}.$$
各符号含义如下:
- $S^{(i)}$:第 $i$ 个完整原始句子。
- $\\widetilde S^{(i)}$:对 $S^{(i)}$ 进行掩码后得到的句子。
- $\\psi_{TE}^{*}$:为 Decoder 提供上下文特征的 Text Encoder。
- $\\psi_{TD}$:根据编码特征和目标前文恢复句子的 Text Decoder。
- $\\Theta$:该目标下被优化的参数集合,主要对应 Text Decoder 参数。
- $\\mathcal L_c$:掩码句子恢复损失。
因果掩码保证 Decoder 在预测第 $u$ 个词时,只能看到:
$$s_1,\\ldots,s_{u-1}$$
而不能看到第 $u$ 个词之后的内容。
采用联合预训练的原因在于,不同的预训练范式能够捕捉数据的不同方面,而将它们结合起来可以获得更全面的数据表征。
在数据层面,作者为手语翻译的输入视频引入了强数据增强,该增强由 VIDAUG 库实现,包括几何变换、颜色空间变换和时间变换。在训练期间,我们随机组合这三类增强方法,以扩大数据空间。
事实上,这种预训练范式使 Visual Encoder 能够获得与 Text Encoder 相似的、强大的语言表征能力,从而生成更加鲁棒、更具代表性的视觉特征。这就是为什么为手语翻译学习语言指示的视觉特征是可行的。因此,当 Visual Encoder 和 Text Decoder 建立起这样的建模能力之后,我们便在第二阶段使用它们执行手语翻译任务。
3.2.无 Gloss 手语翻译
在本节中,作者提出无 Gloss 手语翻译网络 GFSLT。该网络能够在不借助任何 Gloss 标注的情况下,根据给定的手语视频 $V$ 生成对应句子 $S$。为了实现这一目标,如 Figure 3(a) 所示,我们采用 Transformer 作为模型的主要框架,因为它已经在神经机器翻译任务中表现出优异性能。首先,将手语视频输入在 VLP 阶段预训练得到的 Visual Encoder $\\psi_{VE}^{*}$,从而得到隐藏语义向量:
$$h_{1:M}
=
\\psi_{VE}^{*}
\\left(
v_{1:T}
\\right).$$
其中:
$$M=\\frac{T}{4}.$$
与此同时,在 VLP 阶段预训练得到的 Text Decoder $\\psi_{TD}^{*}$,将对应句子:
$$S=(s_1,\\ldots,s_U)$$
和 Encoder 的最后一层隐藏状态作为输入,每次生成一个词:
$$z_u
=
\\psi_{TD}^{*}
\\left(
s_{1:u-1},
h_{1:M}
\\right).$$
句子的第一个词被人为设置为特殊标记 <BOS>,Transformer Decoder 会一直生成,直到输出特殊标记 <EOS>。最后,经过 Linear 层和 Softmax 层后,计算条件概率 $p(S\\mid V)$,并通过最小化视频到句子的交叉熵损失,优化整个网络:
$$p(S\\mid V)
=
\\prod_{u=1}^{U}
p(s_u\\mid o_u),
\\qquad
o_u
=
\\operatorname{softmax}
\\left(
Wz_u+b
\\right),$$
$$\\mathcal L_g
=
-\\log p(S\\mid V).$$
4.实验
4.1.数据集和评估方法
数据集。我们在两个被广泛使用的手语翻译数据集上评估所提出的方法:RWTH-PHOENIX-Weather 2014T,简称 PHOENIX-2014T,以及 CSL-Daily。PHOENIX-2014T 包含来自天气预报节目的 8257 个德国手语(DGS)视频及其对应的德语翻译。该数据集被划分为训练集、验证集和测试集,样本数量分别为 7096、519 和 642。其德语翻译文本的词表大小为 2887。CSL-Daily 主要关注中国手语中的日常生活主题,共包含 20654 个中国手语视频及其对应的中文翻译。该数据集被划分为训练集、验证集和测试集,样本数量分别为 18401、1077 和 1176,中文翻译文本的词表大小为 2343。
评估指标。遵循以往工作,我们采用 BLEU 和 ROUGE 评估手语翻译性能。BLEU 和 ROUGE-L 的数值越高,表示翻译性能越好。
- BLEU-$n$ 主要考察模型译文与参考译文之间 $n$-gram 的匹配情况。例如:
- BLEU-1 更侧重单词是否正确;
- BLEU-2 考察连续两个词是否匹配;
- BLEU-4 考察连续四个词的匹配,更能反映短语结构和翻译流畅性。因此,BLEU-4 通常比 BLEU-1 更严格,也是本文后续消融实验主要关注的指标。
- ROUGE-L 基于模型译文与参考译文之间的最长公共子序列,更重视词语顺序以及句子中有多少参考内容被覆盖。
4.2.实施细节
GFSLT 模型。作者使用在 ImageNet 上预训练的 ResNet18 作为二维 CNN。对于时间模块,我们沿用现有工作的配置:Conv1D 层的步长和卷积核大小分别设置为 1 和 5,MaxPooling 层的步长和池化核大小分别设置为 2 和 2。Transformer Encoder 和 Transformer Decoder 均包含 3 层,隐藏层维度为 1024,前馈网络维度为 4096。每一层都包含 8 个注意力头,并将 Dropout 设置为 0.1,以避免过拟合。
视觉—语言预训练。作者分别在两个手语数据集各自的训练集上执行预训练任务。Mini-batch 大小设置为 16;使用 AMP 技术扩大批次大小。输入序列首先被缩放至 $256\\times256$,随后在训练和推理阶段分别进行随机裁剪和中心裁剪,得到 $224\\times224$ 的输入。采用动量为 0.9 的 SGD 作为优化器,并使用余弦学习率调度策略,使学习率从最大值 0.01 衰减至最小值 $1\\times10^{-5}$。预训练总共进行 80 个 Epoch。
-
AMP 是 Automatic Mixed Precision,自动混合精度训练。它通常结合半精度和单精度计算,以减少显存占用、提高训练速度,因此作者能够采用更大的有效批次。
手语翻译训练与推理。GFSLT 网络采用带有 0.2 标签平滑的交叉熵损失进行端到端训练,Mini-batch 大小设置为 8。使用动量为 0.9 的 SGD 优化器,将初始学习率设置为 0.01,并采用余弦退火学习率调度器。整个网络训练 200 个 Epoch。在推理阶段,模型使用束搜索策略进行解码,长度惩罚设置为 1,Beam Size 设置为 5。
- 标签平滑:普通交叉熵通常把正确词的目标概率设置为 1,其他词设置为 0。标签平滑为 0.2 时,会把一部分概率分配给词表中的其他词,避免模型对训练标签过度自信。
- 束搜索:保留概率最高的候选序列。
- 长度惩罚设置为 1,用于在句子概率和句子长度之间进行平衡,避免模型仅仅因为短句需要相乘的词概率较少,就过度偏向生成较短句子。
视觉编码器
手语视频帧
↓
ResNet18
↓
Conv1D(kernel=5, stride=1)
↓
BN → ReLU
↓
MaxPool1D(kernel=2, stride=2)
↓
Conv1D(kernel=5, stride=1)
↓
BN → ReLU
↓
MaxPool1D(kernel=2, stride=2)
↓
Linear
↓
位置编码 PE
↓
Transformer Encoder
文本解码器
之前的目标词
↓
Word Embedding + 位置编码
↓
Transformer Decoder ⬅ 视觉编码器中 Transformer Encoder 的输出
↓
Linear
↓
Softmax
↓
下一个词
预训练阶段
预训练时还使用了 mBART 的 12 层 Text Encoder。
完整句子或掩码句子
↓
mBART 12 层 Text Encoder
其中:
- mBART 的 12 层 Text Encoder 使用外部预训练参数;
- 视觉编码器中的 Transformer Encoder 是标准 Transformer Encoder;
- 文本解码器中的 Transformer Decoder 是标准 Transformer Decoder;
- mBART Text Encoder 仅在预训练阶段使用,不进入第二阶段的最终翻译模型。
4.3.和SOTA的对比
Table 1 (凤凰数据集)展示了本文方法与当前最先进的基于 Gloss 方法和无 Gloss 方法在手语翻译任务上的比较结果。与 CSGCR 等其他无 Gloss 方法相比,本文方法取得了显著的性能提升。具体而言,本文方法在验证集和测试集上的 BLEU-4 分数分别提升了约 7.0 分和 5.7 分,ROUGE 分数分别提升了约 4.8 分和 2.6 分。此外,与大多数基于 Gloss 的方法相比,本文方法也具有很强的竞争力。值得注意的是,本文方法取得了与 SLRT 和 STMC-T 接近的性能:在验证集 BLEU-4 上,SLRT、STMC-T 和本文方法的结果分别为 22.38、24.09 和 22.12。这一结果显示了无 Gloss 方法的潜力。
-
单独使用本文设计的 GFSLT 架构,即不进行 VLP,已经得到测试集 19.66 BLEU-4,明显超过此前无 Gloss 方法 GASLT 的 15.74。
Table 2 (CSL-Daily数据集)将本文方法与 CSL-Daily 数据集上的最先进方法进行了比较。CSL-Daily 是于 2021 年发布的大规模中国手语数据集,因此,当时在该数据集上进行测试的方法数量较少,特别是无 Gloss 方法更少。从结果中可以看出,本文方法在所有指标上都超过了无 Gloss 方法 NSLT + Luong。此外,在与基于 Gloss 的方法比较时,本文方法已经接近 SLRT 和 BN-TIN-Transf.。这两种方法没有采用更复杂的辅助训练策略。
4.4.消融实验
消融实验主要在 PHOENIX14T 数据集上进行,并重点考察 BLEU-4 的提升,因为 BLEU-4 是衡量手语翻译准确性最可靠的指标。除非另有说明,网络均采用第 4.2 节所述的配置作为基线设置。
视觉—语言预训练
在对 VLP 的研究中,作者深入分析了影响其有效性的关键因素,并观察到以下现象。
首先,从 Table 3 可以看出,对手语视频进行数据增强,对 VLP 的成功起着重要作用。具体而言,当仅使用随机裁剪等轻量级数据增强时,VLP 对手语翻译的提升比较有限:验证集 BLEU-4 仅提高约 0.3 分,测试集仅提高约 0.1 分。然而,当 VLP 与强数据增强结合时,它能够显著改善手语翻译性能,使验证集 BLEU-4 从 19.84 提升至 22.05,提高了约 2.2 分。这一结果体现了 VLP 对数据量和数据多样性的较高需求。
其次,作者发现,在没有 VLP 的情况下,仅在第二阶段使用强数据增强并不能为手语翻译带来明显收益,甚至可能略微损害模型性能。但当强数据增强与 VLP 结合时,手语翻译性能可以得到进一步提升。这是因为,激进的数据增强方法可能会在训练数据中引入过多变化或失真,使手语翻译模型难以适应增强数据的分布。相比之下,VLP 阶段利用大语言模型提供的语言监督,促使 Visual Encoder 适应增强数据所带来的分布差异,从而帮助下游手语翻译模型获得对增强数据的泛化能力。
此外,从 Table 4 可以发现,将 Visual Embedding 模块和 Transformer Encoder 作为一个统一整体进行预训练参数迁移与微调,与只迁移其中一个模块相比,可以带来显著的性能提升。
最后,作者观察到,使用预训练的 Text Decoder 也能够带来一定提升,但增益相对有限,不超过 1 分。
这些结果证实,高质量的视觉特征对于无 Gloss 手语翻译至关重要。VLP 策略促使 Visual Encoder 学习语言表示所具有的低冗余、高抽象特征,因此 Visual Encoder 是整个系统中的关键组成部分。
训练时间研究
基于 Gloss 的手语翻译模型,训练时间通常不会超过 100 个 Epoch。然而,如 Table 5 所示,在固定预训练时间的情况下,无 Gloss 手语翻译模型需要更长的训练周期,即超过 100 个 Epoch,才能获得令人满意的性能。
这是因为,在没有中间表示辅助的情况下,网络的收敛速度会降低,因此需要更长的训练时间,才能使模型达到预期拟合效果。
此外,作者还研究了预训练时长对模型性能的影响。实验结果表明,似乎没有必要进行过长时间的预训练。综合两个手语数据集的情况,80 个 Epoch 是一个较为合理的折中选择。并固定第二阶段为 200 Epoch。
模型参数规模的影响
人们普遍认为,网络参数规模会显著影响模型的最终性能;一种比较直观的观点是,网络越深,性能越好。
然而,对于 GFSLT 网络,作者发现,增加网络层数会导致更加严重的过拟合,如 Figure 4 中的绿色曲线所示。作者认为,这是由于手语翻译数据集规模有限。拥有足够大的手语翻译数据集,可能能够缓解这一问题。
冻结 Text Encoder 的影响
考虑到 Text Encoder 来源于预训练的 mBART,作者在这一实验中尝试冻结其参数,将其作为教师模型,监督 Visual Encoder 的学习。
与预期相反,这种预训练策略并没有产生令人满意的结果,如 Table 6 所示。作者推测,原因可能在于文本特征和视觉特征在底层表示上存在根本差异。为了进行有意义的比较和分析,两种模态需要被共同优化到一个共享表示空间中。因此,直接冻结 Text Encoder 的参数,可能无法为 Visual Encoder 学习鲁棒表示提供充分指导。
4.5.定性结果
作者在 Table 7 中,直观展示了模型在 PHOENIX14T 测试集若干手语视频上的表现。虽然两个模型都能够理解手语视频的整体含义,并生成完整的句子,但基线模型在某些关键词上更容易出错,从而产生含义差异很大的翻译结果,如表中的第一行和第二行所示。此外,VLP 模型在识别命名实体方面优于基线模型,能够更加准确地翻译地点名称和月份,如第三行和第四行所示。
5.结论和未来工作
在本研究中,作者从缩小视觉表示与文本表示之间语义差距的角度,为无 Gloss 手语翻译任务提出了一种新的思路,使模型能够从手语视频中学习语言指示的视觉表示。为实现这一目标,我们提出了一种新的预训练范式,将掩码自监督学习与视觉—语言监督学习相结合。
实验结果表明,数据规模和模型参数规模都会对该方法的性能产生显著影响。尽管本文提出的预训练范式是迈向无 Gloss 手语翻译的重要一步,但我们也认识到仍需开展进一步研究,尤其是在大规模、无 Gloss 标注的手语翻译数据集上进行预训练。我们希望本文的工作能够启发该领域未来的研究。
网硕互联帮助中心





评论前必须登录!
注册