获得符号矩阵区分的计算图/表达式

时间:2017-10-26 12:02:25

标签: python symbolic-math

我想为神经网络编写一些自定义CUDA内核以加速计算,但是如果有可以自动执行此操作的软件包,我不想花时间手动区分张量表达式。

是否有一个python包可以显示符号矩阵区分的表达式?

我知道sympy可以为非矩阵表达式执行此操作:

def func(x):
    return 1 / x

arg_symbols = sp.symbols(inspect.getfullargspec(func).args)
sym_func = func(*arg_symbols)
s = ''
for arg in arg_symbols:
    s += '{}\n'.format(arg, sp.Lambda(arg_symbols, sym_func.diff(arg)))
# this is what I need:
print(s)
>>> Lambda(x, -1/x**2)

我知道autograd包可以计算矩阵表达式的导数

  

评估函数后,autograd会列出所有操作   已执行的以及它们依赖的节点。这是   功能评估的计算图。计算   衍生物,我们只是将差异规则应用于每个节点   在图中。

但是有没有办法从它或类似的包中获得这种差异计算图?

1 个答案:

答案 0 :(得分:1)

您引用的软件包之间存在一些严重差异。差异是您无法直接从自动差异库中获取(AFAIK)计算图形的原因,但您可以从基于符号的图形中获取它。

简而言之:

  • 数值差异化:shmget就足够了
  • 象征性差异化:numpy
  • 自动区分:sympy就是一个例子

有三种差异化方法:

  • 数值微分:这会评估autograd,其中Delta(f(x)) / Delta(x)是一个小差异,代表Delta(x)的变体,同时保留在x的域中。这不是你需要的。你不需要一个包。
  • 符号区分:基于构成表示函数符号应用的图形(我有一篇关于Ruby here中符号引擎实现的文章)。在这种情况下,区分是通过链推导规则的递归应用来执行的:

    f

    当此规则应用于整个符号图时,结果是具有导数的较新符号图。优点在于导数是精确的,但对于非常复杂的图,最终的导数图可能是不可处理的(超过内存限制或过深递归的堆栈限制)。 在python中f(g(x))' = f'(g(x)) * g'(x) 实现了这种派生。另一方面,如果您有衍生图表,您可以对其进行操作,例如简化或替换。

    sympy

    正如您可以看到它与from sympy import * import numpy as np x = symbol('x') f = 1 / x df = diff(f, x) print(df) # -1/x**2 ldf = lambdify((x), df) # Now ldf is a lambda x_ary = np.array([ [[1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3]] ]) y_ary = ldf(x_ary) print(xn.shape) # (2, 2, 3) print(y_ary) # array([[[-1. , -0.25 , -0.11111111], # [-1. , -0.25 , -0.11111111]], # [[-1. , -0.25 , -0.11111111], # [-1. , -0.25 , -0.11111111]]]) 一起使用,但它涵盖了一些基本示例而不是所有内容,实际上numpysympy.matrix一起应该用于特定图表(对于例如:我认为它不能直接处理sympy.symbol

    export the graph as C code也可以,但它有一些有限的功能,对于你的应用程序,你必须修改结果:

    diff(x.T A x, x) = x.T A + A x)

    打印出来:

  
from scipy.utilities.codegen import codegen

[(cf, cc), (hf, hc)] = codegen(("df", df), "C", "df")

print(hc, cc)
  • 自动区分是通过/***************************************************** * Code generated with sympy 1.1.1 * * See http://www.sympy.org/ for more information. * * This file is part of 'project' * *****************************************************/ #ifndef PROJECT__DIFF__H #define PROJECT__DIFF__H double df(double x); #endif /***************************************************** * Code generated with sympy 1.1.1 * * See http://www.sympy.org/ for more information. * * This file is part of 'project' * *****************************************************/ #include "diff.h" #include <math.h> double df(double x) { double df_result; df_result = -1/pow(x, 2); return df_result; } 完成的工作。在这种情况下,两个世界的最好是团结一致。从一方面来说,没有必要明确地评估图形,另一方面,您不能对派生函数执行进一步操作,同时保持导数精确。这通常是通过使用附加字段(类似autograd或更多字段)扩充float定义来完成的,其中附加字段包含派生。例如,在自动差异化环境中,float[2]函数可能会超载:

    sin

    但正如您可以通过这种方式理解的那样,没有可用的计算图,但您可以直接得到def sin(x): return [sin(x[0]), x[1] * cos(x[0])] 的精确导数的值(所有函数都必须重载)。我有一个更完整的例子(在C语言中,只使用宏)here请注意,内部Tensorflow使用自动区分而不是符号,但建议用户直接提供&#34;显式版本&#34;处理数值不稳定的问题!。自动微分通常不会处理数值不稳定。