#graph #data-science #onnx #mlops #data

jyafn

为数据科学编译为机器码的计算图

3个不稳定版本

0.3.1 2024年8月13日
0.3.0 2024年8月10日
0.2.0 2024年7月30日

127 in 数学

Download history 133/week @ 2024-07-27 8/week @ 2024-08-03 224/week @ 2024-08-10

每月365次下载

MIT/Apache

1MB
22K SLoC

C 13K SLoC // 0.0% comments Rust 7K SLoC // 0.0% comments Happy 843 SLoC OCaml 466 SLoC // 0.0% comments Shell 312 SLoC // 0.0% comments Python 192 SLoC // 0.2% comments

包含 (Mach-o exe, 330KB) vendored/qbe/qbe, (Mach-o exe, 84KB) vendored/qbe/parse.o, (Mach-o exe, 41KB) vendored/qbe/amd64/emit.o, (Mach-o exe, 40KB) vendored/qbe/amd64/isel.o, (Mach-o exe, 41KB) vendored/qbe/amd64/sysv.o, (Mach-o exe, 46KB) vendored/qbe/arm64/abi.o 等23个更多.

普通的函数

PyPI - Version Crates.io Version docs.rs GitHub go.mod Go version GitHub Actions Workflow Status

jyafn是一个项目,通过使用编译为机器码的计算图,使用方便且熟悉的Python界面来启用MLOps。

💡 不要忘记查看文档以获取更深入的信息。

There is something going on!

看看这个小巧可爱的代码片段

import jyafn as fn
import numpy as np

@fn.func
def reduce_sum(mat: fn.tensor[2, 2]) -> fn.scalar:
    return np.sum(mat)

我知道:它看起来有点奇怪,但如果我告诉你

  1. 它可以编译成机器码。
  2. 你仍然可以像调用普通Python函数一样调用它。
  3. 你可以将其导出、加载并在Go(或Rust、或Python、或C!)中调用它

很酷,对吧?这基本上是tf.function + onnx在一个包中!

一个快速示例

让我们在jyafn中编写一个愚蠢的函数

@fn.func
def a_fun(a: fn.scalar, b: fn.scalar) -> fn.scalar:
    return 2.0 * a + b + 1.0

它如此愚蠢,以至于如果你像通常那样调用它,a_fun(2, 3),你会得到你预期的,8。但这不是有趣的。有趣的在于你可以将此函数导出到一个文件

with open("a_fun.jyafn", "wb") as f:
    f.write(a_fun.dump())

现在你可以在任何地方传递这个文件,它都会正常工作。例如,让我们从Go调用它

// Read exported data:
code, err := os.ReadFile("a_fun.jyafn")
if err != nil {
    log.Fatal(err)
}

// Load the function:
fn, err := jyafn.LoadFunction(code)
if err != nil {
    log.Fatal(err)
}

// Call the function:
result, err := jyafn.Call[float64](
    fn,
    struct {
        a float64
        b float64
    }{a: 2.0, b: 3.0},
)
if err != nil {
    log.Fatal(err)
}

fmt.Println(result, "==", 8.0)

如何使用它

在所有情况下,很遗憾,您需要安装GNU的binutils(或等效版本),因为我们需要汇编器和链接器来完成QBE的任务(这不是构建依赖项!)。在大多数计算机上,它很可能已经安装(作为gcc或Python的一部分)。然而,当您例如构建Docker镜像时,这是一个需要了解的细节。此外,jyafn在Windows上保证无法工作。有关您的特定编程环境,请参阅下文

Python

从PyPI获取软件包

这是获取jyafn的最便捷方式

pip install jyafn

从源代码构建

克隆仓库,然后

make install

这应该可以解决问题。您可以像这样设置特定的Python版本

make install py=3.12

目前默认版本是3.11。

目前,Python版本取决于Rust编译器才能工作。它将从源代码编译jyafn。因此,您需要Rust的包管理器cargo,以及用于从Rust代码构建Python包的工具maturin。Maturin可以用pip轻松安装

pip install maturin

Go

您可以用它作为Go模块

import "github.com/viodotcom/jyafn/jyafn-go/pkg/jyafn"

您还需要在您的系统中安装libjyafn共享对象,该对象可在GitHub的最新发布中找到。

Rust

您可以直接从crates.io获取jyafncrate的最新版本,这是本项目的基础

cargo add jyafn

C

Jyafn可通过GitHub最新发布中提供的libjyafn共享对象直接从C使用。请查看Rust接口以获取有关如何使用可用函数的详细信息。

常见问题解答

出了一些问题!

是的,肯定有问题。您看到的是基本上是一个小型的JIT(即时编译器)。您的Python指令(添加这个!乘以那个!)被记录在一个计算图中,然后通过QBE编译成机器代码,QBE做所有的重活,“编译”事情。这段代码作为运行程序中的函数指针暴露出来。

加载任意代码不是安全问题吗?

是的,但jyafn产生的代码绝对不是任意的。首先,它是纯的:它不会导致任何外部突变。其次,由于它基于有向无环图(acyclic computational graph),因此可以保证完成(代码的大小限制了运行时间)。第三,没有交换机器代码:该代码仅在所在进程的持续时间内有效。交换的是计算图,而不是代码。

所以,我可以在里面写任何东西,它都会工作?

绝对不是

  1. 您的Python函数只能有常量大小的循环。
  2. 您使用的库必须能够处理泛型Python对象(即支持魔术方法,如__add____sub__等...)。幸运的是,numpy正是这样对其ndarray做。
  3. if-else仍然有点问题(您可以用choose方法代替)。如果有需求,将来可以解决这个问题。
  4. 到目前为止,支持主要集中在DS使用上。因此,浮点数和布尔值是支持的,但其他原始类型则不支持。
  5. 偶尔,在众多功能中可能会出现一个不支持的新功能。然而,实现它非常简单。

它比纯Python快吗?

当然!在 ./jyafn-python/tests/simple_graph.py 中有一个基准测试,您可以查看。有一个示例显示比普通的CPython快10倍。

支持哪些编程语言?

到目前为止,支持Go、Rust、Python和C。您可以使用 cjyafn 库将 jyafn 移植到您的语言。该仓库的GitHub发布版中提供了编译后的共享对象。

项目的当前状态如何?

它已经足够成熟可以进行测试。需要实验小白鼠!

依赖项

~17-28MB
~486K SLoC