如何在Haskell中有效地实现通用神经网络?

时间:2014-09-29 03:22:23

标签: haskell optimization neural-network

神经网络实际上只是一个包含许多参数的庞大函数,因此您可能会认为用函数式语言编写这样的函数会很漂亮,但是对于其他语言编写了一些NN库,我有一定的疑虑关于如何在这个范例中有效地实现它们。

传递信息:如果您绘制每个神经元或图层的依赖关系图,就会得到类似的结果

enter image description here

其中 x 是输入, f 是输出。虽然它在图表中看起来很直接,但如果您真的将网络视为一个函数,那么 f 必须将输入(加上权重参数的子集)传递给 g1 g2 ,每个人都必须将这些传递给最终发送结果的 h1 h2 h3 到上面的层。考虑到输入集加上权重集可能是一千个或更多变量,这看起来非常低效。在其他语言中,您不必这样做,因为每个神经元都可以保留它的参数,输入可以直接传递到输入层。

状态:如果您查看图表, g1 g2 将分别调用 h2 ,但由于 h2 必须为两者产生相同的值,因此计算其输出两次没有意义。由于你没有状态或副作用,这变得棘手,如果你有一个非常庞大的网络,那么即使进行一些并行计算,这也会浪费很多时间。

最后,当我说网络泛型时,我的意思是只要其结构不包含循环,它就可以具有任意形状。我见过的大多数库都使用了一叠层,所以你只需要定义每层中层的数量和神经元的数量,但它的形状是一个线性图形;这对于简单的应用程序来说很好,但真正的核心内容需要具有更复杂架构的网络

我喜欢一些关于如何解决这些问题的建议,因为我想根据自己的需要实现一个库。

注意:

我对语言并不是全新的。我已经使用了相当数量的Functors和Monads(大多数在我的FP库中用于基于haskells API的C#),但我之前从未将haskell用于实际应用程序。

更新

State monad似乎非常有前途!

1 个答案:

答案 0 :(得分:1)

我的意思是,既然Haskell具有相互递归可能是编写你构造的图的最简单方法,那就是一个大的相互递归的where子句:

run_graph x = run_f g1 g2 where
    g1 = run_g1 h1 h2
    g2 = run_g2 h2 h3
    h1 = run_h1 x
    h2 = run_h2 x
    h3 = run_h3 x

通过为这些数字提供比Double更丰富的类型,您可以构建一种与图形对应的抽象数据结构,然后您可以使用反向传播。

您可能不必担心过早地优化图形以进行评估:Haskell会自动在其输入上缓存函数的答案;这是可能的,因为在Haskell函数中不应该有副作用。当run_*函数在数据结构中创建抽象节点时,eval_g1 h2 h3很可能会使用eval_h2 x中的缓存值,当您跳回{h2时1}}。如果这变得太繁琐,那么你可能仍然可以切换到带有IntMap状态的节点的广度优先步行,然后你必须明确地开始指定图层并通过图层传播Data.Array.Unboxed图表。