如何将羔羊化表达式保存到文件并将其加载到新会话中?

问题描述 投票:0回答:1

我的计划是首先以符号方式计算表达式的分配,保护它们,然后在几个广泛的大都会蒙特卡罗模拟中使用它们。虽然我最初尝试了 Sympy,然后又尝试了 Symbolics,但现在我打算使用 SymEngine,因为它在所有相关步骤中似乎都快得多。当使用 SymEngine 时,用于生成函数的大部分时间实际上不是符号计算,而是羔羊化。因此我希望保存由lambdaify生成的函数而不是符号表达式。但是我似乎无法找到一种方法将它们成功加载到新会话中。

我最初尝试使用此处建议的 BSON:https://discourse.julialang.org/t/is-there-a-way-to-write-a-function-into-jld-or-other-h5-file /77718/2。但遗憾的是,重新加载只能在同一个会话中起作用。例如,可以通过执行以下操作来重现:

using SymEngine
using BSON: @save, @load

function mwe()
    @vars X
    f = X
    return(lambdify(f,[X]))
end

f = mwe()

@save "test.bson" f

然后(在新会话中):

using SymEngine
using BSON: @save, @load

function mwe()
    @vars X
    f = X
    return(lambdify(f,[X]))
end

@load "test.bson" f
println(f(1))
f = "nofunction"
@load "test.bson" f
println(f(1))

如果我在同一个会话中执行这两项操作,则输出为

1       
1

正如预期的那样。

但是,如果我在新会话中运行第二部分,我会得到:

ERROR: UndefVarError: ###312 not defined

我还尝试了一种简单的(也许有更复杂的方法来应用这些方法?)使用序列化、FileIO 以及 JLD2 的方法。如果在同一会话中加载,所有这些都会导致类似的行为正常工作,但在不同的会话中加载时会出现错误或警告,然后出现意外行为。

有效的是使用符号

write("test.jl", string(f))
,如下所述: https://discourse.julialang.org/t/using-serialization-to-store-then-load-a-lambdified-function/85884/2。然而,由于 Symbolics 比 SymEnginge 慢得多,这对我来说似乎并不是理想的方式。

更新:我尝试通过使用 PackageCompiler 生成 sysimage 来找到解决方法。想法是创建一个模块,在其中完成所有符号计算,然后创建一个包含所有 lamdified 表达式列表的常量。然后创建该模块的 sysimage,并希望在开始使用 sysimage 时可以在新会话中使用羔羊化表达式。 如果我不生成常量,则创建 sysimage 工作正常。但是一旦我添加了应该创建函数列表的行

const Bookofterms = generate_terms(3,3)

我收到一条有点长的错误消息,其中包含:

ERROR: The following 1 direct dependency failed to precompile:
TimeInt [14fa5fd4-ce9e-41c9-8e49-66abaaa3fbcd]

(TimeInt是自定义包)

Failed to precompile TimeInt [14fa5fd4-ce9e-41c9-8e49-66abaaa3fbcd] to C:\Users\...
ERROR: LoadError: ArgumentError: Expression does not lambdify
caused by: Evaluation into the closed module `SymEngine` breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating `SymEngine` with `eval` during precompilation - don't do this.

老实说我对发生的事情感到很困惑。

更新:由于几天后没有得到任何回复,我决定尝试将这篇文章复制到:https://discourse.julialang.org/t/how-to-save-a-lambdifyed-by-symengine-expression -到文件并在新会话中加载它/111165?u=zaph

file julia lambdify packagecompiler.jl symengine
1个回答
0
投票

在进一步调查中我发现了一些事情: 首先:保存以类似方式定义的 Julia 函数

function f(x,y,z)
    do stuff
    return something
end

然后在另一个会话中加载它不适用于 BSON,并且我认为它不适用于我之前尝试过的任何方法。所以不需要使用lambdaify来产生这样的错误。

但是https://discourse.julialang.org/t/is-there-a-way-to-write-a-function-into-jld-or-other-h5-file/77718/给出的代码示例2仍然有效。因此,问题似乎出在函数名称中的某个地方,因为可以保存匿名函数。

我当时尝试的是使用以下内容:

 function perf_func(ex, vars = [])
    body = convert(Expr, ex)
    if isempty(vars)
        syms = Symbol.(free_symbols(ex))
    else
        syms = Symbol.(vars)
    end
    fn = eval(:($(Expr(:tuple,syms...)) -> $body));
    return(fn)
end

而不是羔羊化。

事实上,这使我能够保存生成的函数并使用 BSON 将它们加载到新会话中。

现在最后应该指出的是,我使用 BSON 加载的速度非常慢,实际上比重新计算函数还要慢。然而,这种方法还允许使用序列化,与在每个新会话中重新计算相比,这确实提供了显着的加速。

所以我的问题的答案是使用上面定义的函数而不是lambdaify,并且只是通过序列化保存和加载。

© www.soinside.com 2019 - 2024. All rights reserved.