#fst #transducer #acceptor #graph #finite-state-machine #ffi #search

rustfst-ffi

用于构建、组合、优化和搜索加权有限状态转换器(FST)的库。Rustfst-ffi提供了Rust库的C接口

16个版本 (5个稳定版)

新增 1.1.2 2024年8月16日
1.0.1 2024年5月2日
0.13.6 2024年2月19日
0.13.5 2023年9月18日
0.11.5 2022年6月21日

#226 in 算法

Download history 191/week @ 2024-04-28 7/week @ 2024-05-05 3/week @ 2024-05-19 1/week @ 2024-05-26 1/week @ 2024-06-02 3/week @ 2024-07-07 27/week @ 2024-07-28 211/week @ 2024-08-04 116/week @ 2024-08-11

每月354次下载

MIT/Apache

1.5MB
32K SLoC

Rustfst

License: MIT/Apache-2.0 Maintenance Github tag

Rust

rustc >= 1.51.0 Native Linux test status Documentation

Python

PyPI version PyPI download month PyPI pyversions

Rust实现的加权有限状态转换器。

Rustfst是一个用于构建、组合、优化和搜索加权有限状态转换器(FST)的库。加权有限状态转换器是每个转换都有一个输入标签、一个输出标签和一个权重的自动机。更熟悉的有限状态接受器可以表示为每个转换的输入和输出标签相同的转换器。有限状态接受器用于表示字符串集合(特别是正则或有理集合);有限状态转换器用于表示字符串对之间的二元关系(特别是有理转换)。权重可以用来表示采取特定转换的成本。

FST在语音识别和合成、机器翻译、光学字符识别、模式匹配、字符串处理、机器学习、信息提取和检索等领域有关键应用。通常使用加权转换器来表示概率模型(例如,n-gram模型、发音模型)。FST可以通过确定化和最小化进行优化,模型可以应用于假设集(也用自动机表示)或通过有限状态组合级联,并通过最短路径算法选择最佳结果。

fst

概述

有关基本示例,请参阅下文部分。

可以使用宏[fst]或函数acceptortransducer轻松创建一些简单且常见的FST类型。

对于更复杂的案例,你可能会从 VectorFst 类型开始,这个类型将与大多数你需要的其他内容一起在 prelude 中导入。 VectorFst<TropicalWeight> 直接对应于 OpenFST 的 StdVectorFst,并且可以使用 readread_text 来加载其文件。

由于“迭代”一个 FST 可以表示很多不同的事情,因此存在多种不同的迭代器。为了迭代状态 ID,你可以使用 states_iter,而为了迭代从状态中出来的转移,你可以使用 get_trs。由于通常同时迭代两者,这可以通过 fst_iterfst_into_iter 来完成。迭代 FST 所接受的路径也非常常见,可以使用 paths_iter 来完成,而对于生成文本的便利性,可以使用 string_paths_iter。对于线性 FST,您还可以使用 decode_linear_fst 获取唯一的路径。

请注意,迭代路径与找到 最短 路径或路径不同,这可以通过 shortest_path(对于单个路径)或 shortest_path_with_config(对于 N 条最短路径)来完成。

有关算法的完整列表,请参阅 algorithms 模块。

你可能现在想知道,特别是如果你以前使用过像 pyfoma 这样的语言学家友好的工具,那么“如果我只是想 变换一些文本 呢???” 不友好的回答是 rustfst 是一个相对低层的库,设计用于实现诸如语音识别器之类的功能。稍微有用一点的回答是,你会通过构建一个 acceptor 用于你的输入,然后将其与 transducer compose,然后 project 结果到其输出,最后在结果 FST 中 迭代路径

参考文献

实现大量受到 Mehryar Mohri、Cyril Allauzen 和 Michael Riley 的工作的启发

该API与OpenFST非常相似,但进行了简化并改为更符合Rust语法的修改,尤其是使用Tr代替Arc。有关更多信息,请参阅与OpenFST的差异

示例

use anyhow::Result;
use rustfst::prelude::*;
use rustfst::algorithms::determinize::{DeterminizeType, determinize};
use rustfst::algorithms::rm_epsilon::rm_epsilon;

fn main() -> Result<()> {
    // Creates a empty wFST
    let mut fst = VectorFst::<TropicalWeight>::new();

    // Add some states
    let s0 = fst.add_state();
    let s1 = fst.add_state();
    let s2 = fst.add_state();

    // Set s0 as the start state
    fst.set_start(s0)?;

    // Add a transition from s0 to s1
    fst.add_tr(s0, Tr::new(3, 5, 10.0, s1))?;

    // Add a transition from s0 to s2
    fst.add_tr(s0, Tr::new(5, 7, 18.0, s2))?;

    // Set s1 and s2 as final states
    fst.set_final(s1, 31.0)?;
    fst.set_final(s2, 45.0)?;

    // Iter over all the paths in the wFST
    for p in fst.paths_iter() {
         println!("{:?}", p);
    }

    // A lot of operations are available to modify/optimize the FST.
    // Here are a few examples :

    // - Remove useless states.
    connect(&mut fst)?;

    // - Optimize the FST by merging states with the same behaviour.
    minimize(&mut fst)?;

    // - Copy all the input labels in the output.
    project(&mut fst, ProjectType::ProjectInput);

    // - Remove epsilon transitions.
    rm_epsilon(&mut fst)?;

    // - Compute an equivalent FST but deterministic.
    fst = determinize(&fst)?;

    Ok(())
}

与OpenFST的差异

以下是非详尽的列表,说明Rustfst的API与OpenFST的不同之处

  • 默认的epsilon符号为<eps>,而不是<epsilon>
  • 函数和方法遵循Rust的命名约定,例如使用add_state而不是AddState,但其他方面基本上是等效的,除了
  • 转换被命名为Tr而不是Arc,因为Arc在Rust中有不同且已确立的含义,并且rustfst使用它(即std::sync::Arc)来引用计数符号表。所有相关函数也使用tr
  • 最终状态不是通过zero的最终权重来指示的。您可以使用is_final来测试最终状态,而final_weight返回一个Option。这要求在转换OpenFST代码时小心。
  • 可以直接作为切片访问转换,而不是需要迭代器。
  • 半群运算以普通方法的形式表达,而不是奇怪的C++事物。因此,例如,编写w1.plus(w2)而不是Plus(w1, w2)
  • 权重具有原地操作⊕(plus_assign)和⊗(times_assign)。
  • 大多数类型别名(在Rust中将是trait别名)如StdArcStdFst等,都缺失了,但类型推断使我们能够避免在大多数情况下显式类型参数,例如在调用Tr::new时,例如。
  • 状态ID是无符号的,默认为32位(可能,40亿状态对大多数应用程序来说足够了)。这意味着在使用它们作为索引时必须小心地将它们转换为usize,反之亦然,最好是检查溢出。
  • 符号ID也是无符号的,为32位,使用NO_LABEL表示缺失值。
  • 浮点权重不是泛型的,因此总是单精度。

与OpenFST的基准测试

我之前对几乎所有线性fst算法进行了基准测试,并与OpenFst进行了比较。您可以在以下位置找到结果

剧透警告:在所有这些算法上,Rustfst 都更快 😅

文档

最后发布版本的文档在此处可用:[https://docs.rs/rustfst](https://docs.rs/rustfst)

发布流程

  1. 使用脚本 update_version.sh 更新每个包的版本。
  2. 推送
  3. 推送一个以 rustfst-v 为前缀的新标签。

示例

./update_version.sh 0.9.1-alpha.6
git commit -am "Release 0.9.1-alpha.6"
git push
git tag -a rustfst-v0.9.1-alpha.6 -m "Release rustfst 0.9.1-alpha.6"  
git push --tags

可选的,如果这是一个主要版本,可以在 UI 中创建 GitHub 发布。

包含在本存储库中的项目

此存储库包含两个主要项目

  • rustfst 是 Rust 的重新实现。
    • Crate 在 crates.io 上可用的链接:[here](https://crates.org.cn/crates/rustfst)
    • 文档在 docs.rs 上可用的链接:[here](https://docs.rs/rustfst/latest/rustfst/)
  • rustfst-pythonrustfst 的 Python 绑定。
    • 软件包在 Pypi 上可用的链接:[here](https://pypi.ac.cn/project/rustfst-python/)
    • 文档在 Github Pages 上可用的链接:[here](https://garvys-org.github.io/rustfst/)

许可证

许可方式如下

  • Apache 许可证 2.0 版(LICENSE-APACHE 或 [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0))
  • MIT 许可证(LICENSE-MIT)或 [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT)

任选其一。

贡献

除非您明确声明,否则根据 Apache-2.0 许可证定义,您有意提交的任何贡献,都应如上所述双重许可,不附加任何额外的条款或条件。

依赖项

~4–5.5MB
~100K SLoC