Firefox 翻译 是一款网站翻译插件,可以自动翻译网页内容。与基于云的替代方案不同,翻译是在用户计算机上的客户端本地完成的,因此要翻译的文本不会离开您的机器,使其完全私密。该插件可用于安装在 Firefox Nightly、Beta 和通用版中。
该插件利用了 Bergamot 项目的成果,该项目是 Mozilla、爱丁堡大学、布拉格查理大学、谢菲尔德大学和塔尔图大学之间的合作项目,由欧盟地平线 2020 研究与创新计划提供资金。
该插件在内部由 Bergamot Translator 提供支持,这是一种神经机器翻译引擎,执行实际的翻译任务。此引擎也可以在不同的上下文中使用,例如在这个演示网站中,它允许用户在不使用云的情况下进行自由形式的翻译。
在本文中,我们将讨论围绕翻译引擎开发的技术挑战,以及我们如何解决这些挑战来构建一个可用的 Firefox 翻译插件。
挑战
翻译引擎构建在 marian 框架 之上,这是一种用纯 C++ 编写的免费神经机器翻译框架。该框架有一个独立的原生应用程序,可以提供简单的翻译功能。但是,需要在插件中引入两个新功能,而现有原生应用程序中没有这些功能。
第一个是表单的翻译,允许用户以自己的语言输入文本,并动态地将其实时翻译成页面的语言。第二个是估计翻译的质量,以便可以自动突出显示低置信度翻译,以通知用户潜在的错误。这导致了翻译引擎的开发,该引擎是 marian 之上的高级 C++ API 层。
生成的翻译引擎直接编译为原生代码。有三种 潜在的架构解决方案 可以将其集成到插件中
- 与 Firefox 的原生集成:将整个翻译引擎原生代码捆绑到 Firefox 中。
- 原生消息传递:将翻译引擎部署为用户计算机上的原生应用程序,并允许插件与其交换消息。
- Wasm:将翻译引擎移植到 Wasm 并使用开发的 JS 绑定将其集成到插件中。
我们根据以下因素评估了这些解决方案,我们认为这些因素对于开发一个可用于生产环境的翻译插件至关重要
- 安全性:在 Mozilla 对引擎代码库进行了内部安全审查之后,放弃了在 Firefox Web 浏览器内进行原生集成的方案,该审查突出了 marian 框架的第三方依赖项数量所带来的问题。
- 可扩展性和可维护性:原生消息传递会在分发项目的代码方面带来挑战,因为需要提供与 Firefox 支持的所有平台兼容的构建版本。这在规模上将是不可行且难以维护的。
- 平台支持:翻译引擎的基础 marian 框架仅支持基于 x86/x86_64 架构处理器的翻译。鉴于基于 ARM 的消费设备的普及率不断提高,原生消息传递方法将限制私有和本地翻译技术到达更广泛受众的范围。
- 性能:与原生代码相比,Wasm 运行速度较慢。但是,它有可能通过利用各种平台上广泛提供的通用硬件功能来实现接近原生速度的执行。
Wasm 作为编程语言的可移植编译目标的设计,意味着可以开发和分发一个在所有平台上运行的单个二进制文件。此外,Wasm 是内存安全的,并在沙箱执行环境中运行,使其在解析和处理 Web 内容时是安全的。所有这些优点,再加上其能够以接近原生速度执行的潜力,激发了我们对这种架构解决方案进行原型设计并评估它是否满足翻译插件的性能要求。
原型设计:移植到 Wasm
我们选择 Emscripten 工具链来将翻译引擎编译为 Wasm。该引擎不能直接编译为 Wasm,我们进行了一些 更改 才能成功编译并使用生成的 Wasm 二进制文件进行翻译,其中一些更改如下
- 禁用了 marian 框架的特定于训练的原生代码,因为翻译引擎只需要特定于翻译的代码即可工作。
- 禁用了多线程代码,因为任何编译为 Wasm 的 pthread 代码都需要浏览器中的 SharedArrayBuffer 支持,在开发时,该功能正在从 禁用状态过渡到重新启用状态。
- 该引擎依赖于训练好的模型、词汇表以及可选的缩减列表文件,才能执行翻译,并期望用户从外部提供这些文件。由于 原生代码和普通 JavaScript 使用不同的文件访问范式,我们在 Emscripten 的虚拟文件系统中 打包了所有必需的文件,以加快原型设计速度。
- 用一个开源库 (onnxjs) 替换了 专有库 (Intel MKL),用于在 marian 框架的注意力层中执行 SGEMM 操作。
- 修复了与 marian 框架中不当使用原生数据类型 size_t 相关的问题,该问题会导致翻译过程中出现错误。
从原型设计到集成
问题
在获得可工作的翻译 Wasm 二进制文件后,我们发现了一些需要解决的关键问题,才能将原型转换为可用的产品。
可扩展性
将每个支持的语言对的所有文件打包到 Wasm 二进制文件中,意味着对新的语言对进行扩展是不可行的。每个语言对的所有文件(从一种语言翻译到另一种语言,反之亦然)在压缩形式下约占 40 MB 的磁盘空间。例如,支持 6 种语言对的翻译会使二进制文件的大小达到约 250 MB。
按需语言支持
将每个支持的语言对的文件打包到 Wasm 二进制文件中,意味着用户将被迫下载所有支持的语言对,即使他们只想使用其中的一部分。与根据用户的需求下载语言对的文件相比,这效率低下。
性能
我们在三个主要指标上对翻译引擎进行了基准测试,我们认为这三个指标对于可用性至关重要。
- 启动时间:引擎准备好进行翻译所花费的时间。引擎在此步骤中加载模型、词汇表以及可选的缩减列表文件内容。
- 翻译速度:引擎在成功启动后翻译给定文本所花费的时间,以每秒翻译的单词数(即 wps)来衡量。
- Wasm 二进制文件大小:生成的 Wasm 二进制文件的磁盘空间。
由于打包,生成的 Wasm 二进制文件的大小取决于支持的语言对的数量。翻译引擎启动时间过长(约 8 秒),翻译速度极慢,使其无法使用。
例如,使用 相应的训练模型 从英语翻译成德语,在 MacBook Pro(15 英寸,2017),macOS 版本 11.6.2,3.1 GHz 四核 Intel Core i7 处理器,16 GB 2133 MHz 内存上,每秒仅翻译 95 个单词。
解决方案
可扩展性、按需语言支持和二进制文件大小
由于文件的打包在多个方面影响了翻译引擎的可用性,因此我们决定首先解决这个问题。我们在翻译引擎中引入了新的 API,可以 将必需的文件作为字节缓冲区从外部传递,而不是在编译时将其打包到 Emscripten 的虚拟文件系统中。
这使得翻译引擎能够针对新语言进行扩展,而不会增加 Wasm 二进制文件的大小,并使插件能够动态下载用户感兴趣的语言对的文件。最终的 Wasm 二进制文件大小(约 6.5 MB)远远低于相应指标的限制。
启动时间优化
我们开发的用于解决打包问题的新的 API,加上 marian 框架中的 一些其他优化,解决了启动时间过长的问题。引擎的启动时间大幅缩短(约 1 秒),远远低于此性能指标的可接受范围。
翻译速度优化
对浏览器中的翻译步骤进行分析表明,针对 8 位整数操作数的一般矩阵乘法 (GEMM) 指令是最消耗计算量的操作,而 异常处理代码 对翻译速度造成了很大影响。我们将优化工作重点放在了这两个方面。
- 优化异常处理代码:我们用 基于 if/else 的实现 替换了 try/catch,该函数在翻译步骤中频繁调用,这导致翻译速度提高了约 20%。
- 优化 GEMM 操作:对分析结果进行深入调查后发现,Wasm 标准中没有 GEMM 指令 是其在 Wasm 上执行速度如此慢的原因。
- 实验性 GEMM 指令: 为了纯粹地评估 GEMM 指令的性能,而没有将其标准化到 Wasm 中,我们在 Firefox Nightly 和 Release 中为 x86/x86_64 架构添加了两个实验性指令。这些指令将 翻译速度提高了约 310%,网页翻译速度也足够快,可以在这些架构上使用该功能。由于此功能的实验性,它被隐藏在一个标志后面,并且仅在 Firefox Release 中向特权扩展公开。在将其发布为生产软件之前,我们仍然希望找到一种基于标准的解决方案,但这使我们能够在与 Firefox WASM 团队合作寻找更好的长期解决方案的同时继续开发扩展。
- 非标准长期解决方案: 由于 Wasm 标准中 GEMM 指令实现的时间表尚不确定,我们用 Firefox 特定的非标准长期解决方案替换了实验性 GEMM 指令,该解决方案提供了 与实验性 GEMM 指令相同或更高的翻译速度。除了特权扩展之外,该解决方案还为非特权扩展以及常规内容启用了翻译功能,翻译速度相同,并在基于 ARM64 的平台上启用了翻译,尽管速度较慢。实验性 GEMM 指令无法实现这些功能。
- 原生 GEMM 内在函数: 为了进一步提高翻译速度,我们在 Firefox Nightly 中添加了原生 GEMM 实现,该实现被隐藏在一个标志后面,并作为内在函数公开。每当翻译引擎在基于 x86/x86_64 架构的系统上的 Firefox Nightly 中运行时,它会在翻译步骤中直接调用这些内在函数。与我们之前添加的实验性指令相比,这项工作将 SSSE3 和 AVX2 SIMD 扩展的翻译速度分别 提高了 25% 和 43%。
- Emscripten 工具链升级: 最近一次将 Emscripten 工具链更新到最新版本的努力,使所有平台的翻译速度在 Firefox 上提高了约 15%,并进一步将 Wasm 二进制文件的大小减少了约 25%(最终大小约 4.94 MB)。
最终,我们实现了 使用 相应的训练模型,在 MacBook Pro(15 英寸,2017 年),MacOS 版本 11.6.2,3.1 GHz 四核 Intel Core i7 处理器,16 GB 2133 MHz 内存的 Firefox Release 上,从英语到德语的翻译速度约为 870 wps。
未来
翻译引擎被优化为仅在 x86/x86_64 处理器上以高速运行,我们有想法在 ARM 上改进这种情况。标准化的 Wasm GEMM 指令可以在 ARM 上实现类似的速度,为新兴的消费者笔记本电脑和移动设备类别带来益处。我们还知道,原生 Marian 引擎在多线程情况下表现得更好,但我们不得不在此版本的翻译引擎中禁用多线程代码。一旦 SharedArrayBuffer 支持得到广泛启用,我们相信我们可以重新启用多线程,甚至可以实现更快的翻译速度。
致谢
我要感谢 Bergamot 联盟合作伙伴、Mozilla 的 Wasm 团队以及我的队友 Andre Natal、Evgeny Pavlov,他们在开发成熟的翻译引擎方面做出了贡献。感谢 Lonnen 以及 Mozilla 的附加组件团队、本地化团队、问答团队和 Mozilla 社区,他们支持我们并为 Firefox Translations 附加组件的开发做出了贡献。
本项目已获得欧盟地平线 2020 研究与创新计划的资助,资助协议号为 825303。