sum产品流:一个易于扩展的sum产品网络库
spflow的Python项目详细描述
spflow:一个简单且可扩展的sum产品网络库
spflow,一个开源的python库,提供了一个简单的推理接口, 深度可处理概率模型的学习和操作程序,称为和积网络(SPN)。 该库允许用户从数据和通过领域特定语言(DSL)快速创建SPN。 它有效地实现了一些概率推理程序,如计算边缘、条件和(近似的)最可能解释(mpes) 以及用于序列化、绘图和结构化SPN统计信息的采样和实用程序。
此外,spflow具有极强的可扩展性和可定制性,允许用户迅速创建新的推理和学习例程。 通过将自定义代码注入轻量级面向功能的api框架。
开始
这些说明将为您提供一份项目的副本,并在本地计算机上运行,以便进行开发和测试。
安装
使用pip安装最新版本的spflow
pip3 install spflow
示例
我们首先创建一个spn。使用领域特定语言(DSL),我们可以快速创建 像这样保留节点:
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))
我们可以使用对象层次结构创建相同的spn:
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn
p参数表示概率,scope表示我们正在建模的变量。
我们现在可以使用:
fromspn.io.Graphicsimportplot_spnplot_spn(spn,'basicspn.png')
边缘化spn意味着将所有其他不相关的变量相加。 所以,如果我们想把上面的spn边缘化,并求出所有其他变量的和,只剩下变量1和2,我们可以做到:
fromspn.algorithms.Marginalizationimportmarginalizespn_marg=marginalize(spn,[1,2])
在这里,我们将所有不在[1,2]中的变量边缘化,并创建一个对前一个变量一无所知的新结构 也不是关于变量0。
我们可以使用这个新的spn来做所有我们感兴趣的操作。这意味着,我们也可以策划它!
plot_spn(spn_marg,'marginalspn.png')
我们还可以将SPN转储为文本:
fromspn.io.Textimportspn_to_str_equationtxt=spn_to_str_equation(spn_marg)print(txt)
输出为:
(0.6*((Categorical(V1|p=[0.3,0.7])*Categorical(V2|p=[0.4,0.6])))+0.12000000000000002*((Categorical(V1|p=[0.3,0.7])*Categorical(V2|p=[0.4,0.6])))+0.27999999999999997*((Categorical(V1|p=[0.5,0.5])*Categorical(V2|p=[0.6,0.4]))))
然而,spns最有趣的方面是可处理的推断。下面是一个如何从上面评估SPN的示例。 由于我们有3个变量,我们希望创建一个包含3列和1行的2d numpy数组。
importnumpyasnptest_data=np.array([1.0,0.0,1.0]).reshape(-1,3)
然后我们计算对数似然:
pip3 install spflow0
输出为:
pip3 install spflow1
我们还可以计算边际spn的对数似然:
pip3 install spflow2
注意,我们使用了相同的test_数据输入,因为spn仍然需要一个包含数据的numpy数组在列1和列2处,忽略列0。 输出为:
pip3 install spflow3
另一种选择是对原始spn进行边缘推理。这是通过设置为np.nan来完成的,我们希望在运行中边缘化这个特性。 它不会改变结构。
pip3 install spflow4
输出与边际SPN的评估完全相同:
pip3 install spflow3
我们可以使用tensorflow在gpu中进行评估:
pip3 install spflow6
输出与预期一样,等于python中的输出:
pip3 install spflow1
我们还可以使用tensorflow在gpu中进行参数优化:
pip3 install spflow8
当然,输出的可能性更高:
pip3 install spflow9
我们可以根据SPN捕获的联合分布生成新样本!
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))0
在这里,我们创建了5个新实例,它们遵循分布
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))1
np.nan值表示要采样的列。
我们也可以做条件抽样,也就是说,如果我们有一些变量的证据,我们可以传递这些信息 其他变量的SPN和样本:
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))2
在这里,我们创建了5个新实例,它们的证据是v1=0和v2=0
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))3
通过从数据中学习SPN,然后比较给定类的概率,我们可以进行分类: 假设我们有以下数据集:
由两个均值为(5,5)和(10,10)的高斯函数生成,我们将(5,5)处的簇标记为0类,将(10,10)处的簇标记为1类。
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))4
我们可以从以下数据中学习SPN:
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))5
在这里,我们将问题建模为包含3个特征,两个高斯坐标和一个分类标签。 我们指定标签在第2列中,并创建相应的SPN。
现在,假设我们要对两个实例进行分类,一个位于(3,4),另一个位于(12,8)。 为此,我们首先创建一个包含两行和三列的数组。我们将最后一列设置为np.nan,表示我们不知道标签。 并相应地设置2d数组中的其余值。
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))6
第一行是第一个实例,第二行是第二个实例。
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))7
我们可以通过近似最可能解释(mpe)进行分类。 在这里,我们希望第一个实例标记为0,第二个实例标记为1。
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))8
如我们所见,两个实例都被正确分类,因为在最后一列中设置了正确的标签
fromspn.structure.leaves.parametric.ParametricimportCategoricalspn=0.4*(Categorical(p=[0.2,0.8],scope=0)*(0.3*(Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))+0.7*(Categorical(p=[0.5,0.5],scope=1)*Categorical(p=[0.6,0.4],scope=2))))+0.6*(Categorical(p=[0.2,0.8],scope=0)*Categorical(p=[0.3,0.7],scope=1)*Categorical(p=[0.4,0.6],scope=2))9
我们可以从数据中学习mspn和参数spn:
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn0
在这里,我们有一个包含四个特征的数据集,两个离散和两个实值。
我们可以使用以下命令学习mspn:
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn1
我们可以使用:
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn2
多变量叶
我们可以学习多变量叶的spn。例如,以周柳树(clts)为多变量叶的spn可以通过以下方法学习:
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn3
割集网络(CNET)
利用spflow,我们可以学习cnets的结构和参数,这是一种以clts为叶子的特殊的spns,它提供了精确的mpe推断,用:
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn4
期望和时刻
spns允许您通过直接计算树结构来计算所表示概率函数的一阶和高阶矩。它有三个主要功能。
expectations函数允许您直接计算给定SPN的第一阶矩,以及(可选)需要期望的特征列表和一系列证据。
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn5
如果您通过了功能范围,则只返回对这些功能的期望:
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn6
最后,您还可以将证据传递给计算条件期望的网络:
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn7
实用程序
最后,我们有一些基本实用程序可用于处理SPN:
我们可以确保我们使用的SPN是有效的,也就是说,它是一致和完整的。
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn8
输出表明SPN有效,并且没有调试错误消息:
fromspn.structure.leaves.parametric.ParametricimportCategoricalfromspn.structure.BaseimportSum,Productfromspn.structure.Baseimportassign_ids,rebuild_scopes_bottom_upp0=Product(children=[Categorical(p=[0.3,0.7],scope=1),Categorical(p=[0.4,0.6],scope=2)])p1=Product(children=[Categorical(p=[0.5,0.5],scope=1),Categorical(p=[0.6,0.4],scope=2)])s1=Sum(weights=[0.3,0.7],children=[p0,p1])p2=Product(children=[Categorical(p=[0.2,0.8],scope=0),s1])p3=Product(children=[Categorical(p=[0.2,0.8],scope=0),Categorical(p=[0.3,0.7],scope=1)])p4=Product(children=[p3,Categorical(p=[0.4,0.6],scope=2)])spn=Sum(weights=[0.4,0.6],children=[p2,p4])assign_ids(spn)rebuild_scopes_bottom_up(spn)returnspn9
计算SPN结构的基本统计信息:
fromspn.io.Graphicsimportplot_spnplot_spn(spn,'basicspn.png')0
扩展库
如我们所见,使用SPN相对容易。但是,如果我们想使用新的发行版,我们可能需要扩展它。
想象一下,我们想要创建一个新的叶子类型来模拟pareto分布。 我们首先创建一个新类:
fromspn.io.Graphicsimportplot_spnplot_spn(spn,'basicspn.png')1
现在,如果我们想用这种新的节点类型进行推理,我们只需实现相应的似然函数:
fromspn.io.Graphicsimportplot_spnplot_spn(spn,'basicspn.png')2
此函数接收节点、计算概率的数据以及结果的numpy数据类型。
现在,我们只需注册此功能,它就可以无缝地供基础结构的其他部分使用:
fromspn.io.Graphicsimportplot_spnplot_spn(spn,'basicspn.png')3
现在,我们可以创建使用新发行版的SPN,并对其进行评估。
fromspn.io.Graphicsimportplot_spnplot_spn(spn,'basicspn.png')4
这将产生输出:
fromspn.io.Graphicsimportplot_spnplot_spn(spn,'basicspn.png')5
SPN库的所有其他方面都可以以类似的方式进行扩展。
spflow可以复制纸张
- 尼古拉·迪莫罗、安东尼奥·维加里、特雷莎·M.A·巴兹勒、弗洛里安娜·埃斯波西托。"具有极随机割集网络的快速准确密度估计。输入:ECML/PKDD,2017。
- 尼古拉·迪莫罗、安东尼奥·维加里和特蕾莎·M.A.巴兹勒。"学习贝叶斯随机割集森林"。在ISMIS 2015,LNAI 9384,第1-11页,斯普林格,2015。
- 尼古拉·迪莫罗、安东尼奥·维加里和弗洛里安娜·埃斯波西托。"利用可分解性学习精确割集网络。在AI*IA。2015年,LNAI 9336,1-12,斯普林格,2015年。
- 安东尼奥·维加里、尼古拉·迪莫罗和弗洛里安娜·埃斯波西托。"简化、规范和加强和积网络结构学习"。在ECML/PKDD,LNCS,343-358,斯普林格。2015、
在spflow中实现的论文
莫利纳、亚历杭德罗、斯利拉姆·纳塔拉扬和克里斯蒂安·克尔斯汀。"泊松和积网络:可处理多元泊松分布的深层结构〉,载于AAAI,2357-2363页。2017、
莫利纳、亚历杭德罗、安东尼奥·维加里、尼古拉·迪毛罗、斯利拉姆·纳塔拉扬、弗洛里安娜·埃斯波西托和克里斯蒂安·克尔斯汀。"混合和产品网络:混合领域的深层架构〉,《人工智能会议论文集》。2018、
引文
如果您觉得spflow有用,请在您的工作中引用我们:
fromspn.io.Graphicsimportplot_spnplot_spn(spn,'basicspn.png')6
作者
- 亚历杭德罗·莫利纳-杜达姆施塔特
- Antonio Vergari-马克斯普朗克学院
- Karl Stelzner-Tu Darmstadt
- 罗伯特·佩哈兹-剑桥大学
- 尼科拉·迪·毛罗-巴里大学奥尔多·莫罗分校
- 克里斯汀-杜达姆施塔特
另请参见参与此项目的贡献者列表。
贡献者
- 莫里茨·库莱萨-杜达姆施塔特
- 克拉斯·沃克尔
- 西蒙·罗斯勒-卡尔斯鲁厄理工学院
- 史蒂文·朗
许可证
此项目是在2.0版apache许可下授权的-有关详细信息,请参见license.md文件
致谢
- 部分SPEFULL及其激励研究得到了德国科学基金会(DFG)——AIPHES、GRK 1994和CAML、KE 1686/3-1作为SPP 1999的一部分的支持和联邦教育和研究部(BBF)——InDaS,01IS17063B。