语言翻译是自然语言处理中最重要的任务之一。在本教程中,您将学习如何使用 T5(Text-to-Text Transfer Transformer)模型和 Hugging Face Transformers 库实现一个强大的多语言翻译系统。学完本教程后,您将能够构建一个可以处理多种语言对的生产级翻译系统。具体来说,您将学习:
- 什么是 T5 模型及其工作原理
- 如何为翻译生成多种备选方案
- 如何评估翻译质量
通过我的书籍《Hugging Face Transformers中的NLP》,快速启动您的项目。它提供了带有工作代码的自学教程。
让我们开始吧!

使用 T5 和 Transformers 实现多语言翻译
Hermes Rivera。保留部分权利。
概述
这篇博文分为三部分;它们是:
- 设置翻译管道
- 带备选方案的翻译
- 质量评估
设置翻译管道
文本翻译是自然语言处理中的一项基本任务,它启发了原始 Transformer 模型的发明。T5,即 *Text-to-Text Transfer Transformer*,由 Google 于 2020 年发布,由于其文本到文本的方法和在海量多语言数据集上的预训练,它是一个强大的翻译模型。
transformers
库中的文本翻译被实现为“条件生成”,这意味着模型在输入文本的条件下生成文本,就像条件概率分布一样。与 transformers
库中的所有其他模型一样,您只需几行代码即可实例化一个 T5 模型。在开始之前,请确保已安装以下依赖项:
1 |
pip install torch transformers sentencepiece protobuf sacrebleu |
让我们看看如何使用 T5 创建一个翻译引擎:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import torch from transformers import T5ForConditionalGeneration, T5Tokenizer class MultilingualTranslator: def __init__(self, model_name="t5-base"): self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"Using device: {self.device}") self.tokenizer = T5Tokenizer.from_pretrained(model_name, legacy=False) self.model = T5ForConditionalGeneration.from_pretrained(model_name).to(self.device) def translate(self, text, source_lang, target_lang): """将文本从源语言翻译成目标语言""" # 确保支持源语言和目标语言 supported_lang = ["English", "French", "German", "Spanish"] if source_lang not in supported_lang: raise ValueError(f"不支持的源语言: {source_lang}") if target_lang not in supported_lang: raise ValueError(f"不支持的目标语言: {target_lang}") # 准备输入文本 task_prefix = f"translate {source_lang} to {target_lang}" input_text = f"{task_prefix}: {text}" # 分词并生成翻译 inputs = self.tokenizer(input_text, return_tensors="pt", max_length=512, truncation=True) inputs = inputs.to(self.device) outputs = self.model.generate(**inputs, max_length=512, num_beams=4, length_penalty=0.6, early_stopping=True) # 解码并返回翻译 translation = self.tokenizer.decode(outputs[0], skip_special_tokens=True) return translation en_text = "Hello, how are you today?" es_text = "¿Cómo estás hoy?" translator = MultilingualTranslator("t5-base") translation = translator.translate(en_text, "English", "French") print(f"英语: {en_text}") print(f"法语: {translation}") print() translation = translator.translate(en_text, "English", "German") print(f"英语: {en_text}") print(f"德语: {translation}") print() translation = translator.translate(es_text, "Spanish", "English") print(f"西班牙语: {es_text}") print(f"英语: {translation}") |
MultilingualTranslator
类像往常一样实例化一个 T5 模型和一个分词器。translate()
方法是实际翻译发生的地方。您可以看到它只是一个带提示的文本生成,提示只是说“将 X 翻译成 Y”。因为这是一个文本生成任务,所以您可以看到用于控制束搜索的参数,例如 num_beams
、length_penalty
和 early_stopping
。
分词器将 return_tensors="pt"
设置为返回 PyTorch 张量,否则它将返回一个 token ID 的 Python 列表。您需要这样做,因为模型需要 PyTorch 张量。输出的默认格式取决于分词器的实现,因此您需要查阅文档以正确使用它。
在生成之后,分词器再次用于将生成的 token 解码回文本。
以上代码的输出是:
1 2 3 4 5 6 7 8 9 |
使用设备: cuda 英语: Hello, how are you today? 法语: Bonjour, comment vous êtes-vous aujourd'hui? 英语: Hello, how are you today? 德语: Hallo, wie sind Sie heute? 西班牙语: ¿Cómo estás hoy? 英语: Cómo estás hoy? |
您可以看到模型可以将英语翻译成法语或德语,但未能将西班牙语翻译成英语。这是模型的问题(可能与模型的训练方式有关)。您可能需要尝试其他模型,看看它是否表现更好。
带备选方案的翻译
将一个句子翻译成另一种语言并不是一一对应的关系。由于语法、词语用法和句法结构的变化,翻译一个句子有多种方法。
由于上述模型的文本生成使用束搜索,您可以原生生成翻译的多个备选方案。您可以修改 translate()
方法以返回多个翻译:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
def translate(self, text, source_lang, target_lang): """翻译文本并报告束搜索得分""" supported_lang = ["English", "French", "German", "Spanish"] if source_lang not in supported_lang: raise ValueError(f"不支持的源语言: {source_lang}") if target_lang not in supported_lang: raise ValueError(f"不支持的目标语言: {target_lang}") # 准备输入文本 task_prefix = f"translate {source_lang} to {target_lang}" input_text = f"{task_prefix}: {text}" # 分词并生成翻译 inputs = self.tokenizer(input_text, return_tensors="pt", max_length=512, truncation=True) inputs = inputs.to(self.device) with torch.no_grad(): outputs = self.model.generate(**inputs, max_length=512, num_beams=4*4, num_beam_groups=4, num_return_sequences=4, diversity_penalty=0.8, length_penalty=0.6, early_stopping=True, output_scores=True, return_dict_in_generate=True) # 解码并返回翻译 translation = [self.tokenizer.decode(output, skip_special_tokens=True) for output in outputs.sequences] return { "translation": translation, "score": [float(score) for score in outputs.sequences_scores], } |
这个修改后的方法返回一个包含翻译列表和分数的字典,而不是单个字符串。模型的输出仍然是 logits 张量,您需要使用分词器将其解码回文本,一次一个翻译。
这些分数用于束搜索。因此,它们总是按降序排列,并且最高的分数会被挑选出来作为输出。
让我们看看如何使用它:
1 2 3 4 5 6 7 8 9 |
... original_text = "这是一条需要准确翻译的重要信息。" translator = MultilingualTranslator("t5-base") output = translator.translate(original_text, "English", "French") print(f"英语: {original_text}") print("法语:") for text, score in zip(output["translation"], output["score"]): print(f"- (得分: {score:.2f}) {text}") |
输出如下:
1 2 3 4 5 6 |
英语: This is an important message that needs accurate translation. 法语 - (得分: -0.65) Il s'agit d'un message important qui a besoin d'une traduction précise。 - (得分: -0.70) Il s'agit d'un message important qui doit être traduit avec précision。 - (得分: -0.76) C'est un message important qui a besoin d'une traduction précise。 - (得分: -0.81) Il s'agit là d'un message important qui doit être traduit avec précision。 |
分数是负数,因为它们是对数概率。您应该使用更复杂的句子来查看翻译中的变化。
质量评估
上面代码中打印的分数是束搜索中使用的分数。它有助于自回归生成在保持多样性的同时完成一个句子。想象一下,模型一次生成一个 token,并且每个步骤都会发出多个候选。完成句子有多种路径,并且路径的数量随着探索的自回归步骤的数量呈指数增长。束搜索通过对每条路径进行评分并仅保留前 k 条路径来限制要跟踪的路径数量。
确实,您可以检查束搜索过程中使用的概率。在模型中,有一个 compute_transition_scores()
方法,它返回生成的 token 的转移分数。您可以尝试如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
... outputs = model.generate(**inputs, max_length=512, num_beams=4*4, num_beam_groups=4, num_return_sequences=4, diversity_penalty=0.8, length_penalty=0.6, early_stopping=True, output_scores=True, return_dict_in_generate=True) transition_scores = model.compute_transition_scores( outputs.sequences, outputs.scores, outputs.beam_indices, normalize_logits=True ) for idx, (out_tok, out_score) in enumerate(zip(outputs.sequences, transition_scores)): translation = tokenizer.decode(out_tok, skip_special_tokens=True) print(f"翻译: {translation}") print("token | token 字符串 | logit | 概率") for tok, score in zip(out_tok[1:], out_score): print(f"| {tok:5d} | {tokenizer.decode(tok):14s} | {score.numpy():.4f} | {np.exp(score.numpy()):.2%}") |
对于与上一个示例相同的输入文本,上述代码片段的输出是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
翻译: Il s'agit d'un message important qui a besoin d'une traduction précise。 token | token 字符串 | logit | 概率 802 | Il | -0.7576 | 46.88% 3 | | -0.0129 | 98.72% 7 | s | -0.0068 | 99.32% 31 | ' | -0.3295 | 71.93% 5356 | agit | -0.0033 | 99.67% 3 | | -0.3863 | 67.96% 26 | d | -0.0108 | 98.93% 31 | ' | -0.0005 | 99.95% 202 | un | -0.0152 | 98.49% 1569 | message | -0.0296 | 97.09% 359 | important | -0.0228 | 97.75% 285 | qui | -0.4194 | 65.74% 3 | | -0.9925 | 37.07% 9 | a | -0.1236 | 88.37% 6350 | besoin | -0.0114 | 98.87% 3 | | -0.1201 | 88.68% 26 | d | -0.0006 | 99.94% 31 | ' | -0.0007 | 99.93% 444 | une | -0.4557 | 63.40% 16486 | traduc | -0.0027 | 99.73% 1575 | tion | -0.0001 | 99.99% 17767 | précise | -0.6423 | 52.61% 5 | . | -0.0033 | 99.67% 1 | </s> | -0.0006 | 99.94% 翻译: Il s'agit d'un message important qui doit être traduit avec précision。 token | token 字符串 | logit | 概率 802 | Il | -0.7576 | 46.88% 3 | | -0.0129 | 98.72% ... |
在 for 循环中,您并排打印 token 和分数。第一个 token 始终是填充 token;因此我们将 out_tok[1:]
与 out_score
匹配。概率对应于该步骤的 token。它取决于之前的 token 序列,因此相同的 token 在不同的步骤或不同的输出句子中可能具有不同的概率。具有高概率的 token 很可能是由于语法规则。具有低概率的 token 意味着在该位置存在一些可能的替代方案。请注意,在束搜索中,输出是从概率加权分布中采样的。因此,您从上面看到的 token 不一定是生成的概率最高的 token。
outputs.sequence_scores
是 outputs
对象中上述概率的归一化总和,其中包含每个序列的分数。您可以使用它来估计翻译的质量。
然而,这对您来说没什么用,因为您并没有自己实现束搜索。这些概率无法告诉您翻译的质量。您无法在不同的输入句子之间进行比较,也无法与不同的模型进行比较。
一种评估翻译质量的流行方法是使用 BLEU (Bilingual Evaluation Understudy) 分数。您可以使用 sacrebleu
库来计算翻译的 BLEU 分数,但您需要一个参考翻译才能获得分数。下面是一个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
... import sacrebleu sample_document = """ 机器翻译多年来取得了显著发展。早期系统使用 基于规则的方法,定义了语言的语法规则。统计 机器翻译后来出现,利用大量翻译文本语料库自动学习 翻译模式。 """ reference_translation = """ 机器翻译多年来取得了显著发展。早期系统使用 基于规则的方法,定义了语言的语法规则。 统计机器翻译后来出现,利用大量翻译文本语料库自动学习 翻译模式。 des modèles de traduction。 """ translator = MultilingualTranslator("t5-base") output = translator.translate(sample_document, "English", "French") print(f"英语: {sample_document}") print("法语:") for text, score in zip(output["translation"], output["score"]): bleu = sacrebleu.corpus_bleu([text], [[reference_translation]]) print(f"- (得分: {score:.2f}, bleu: {bleu.score:.2f}) {text}") |
输出可能为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
英语 机器翻译多年来取得了显著发展。早期系统使用 基于规则的方法,定义了语言的语法规则。统计 机器翻译后来出现,利用大量翻译文本语料库自动学习 翻译模式。 法语 - (得分: -0.94, bleu: 26.49) 机器翻译多年来取得了显著发展。 早期系统使用基于规则的方法,定义了 语言的语法规则。 - (得分: -1.26, bleu: 56.78) 机器翻译多年来取得了显著发展。 早期系统使用基于规则的方法,定义了 语言的语法规则。统计机器翻译后来 出现,利用大量翻译文本语料库自动学习 翻译模式。 - (得分: -1.26, bleu: 56.41) 机器翻译多年来取得了显著发展。 早期系统使用基于规则的方法,定义了 语言的语法规则。统计机器翻译后来 出现,利用大量翻译文本语料库自动学习 翻译模式。 - (得分: -1.32, bleu: 53.79) 机器翻译多年来取得了显著发展。 早期系统使用基于规则的方法,定义了 语言的语法规则。统计机器翻译后来 后来出现,利用大量翻译文本语料库自动学习 翻译模式。 |
BLEU 分数显示翻译与参考文本的匹配程度。它的范围从 0 到 100;分数越高越好。您可以看到模型对翻译的评分与 BLEU 分数不匹配。一方面,这突出表明分数并非用于评估翻译质量。另一方面,这取决于您提供的参考翻译。
进一步阅读
以下是一些您可能会觉得有用的资源:
- Hugging Face Transformers 文档中的翻译任务指南
- Hugging Face Transformers 文档中的文本生成
- Hugging Face Transformers 文档中的 T5
- T5: 文本到文本转换器
- SacreBLEU
总结
在本教程中,您已经使用 T5 和 Transformers 库构建了一个全面的多语言翻译系统。具体来说,您学习了:
- 如何使用 T5 模型和提示实现基本翻译系统
- 如何调整束搜索以生成翻译的多种替代方案
- 如何使用 BLEU 分数估计翻译质量
代码不起作用,请检查
你好 kobubu。请复制并粘贴错误消息,以便我们进行调查。