3

我正在尝试实现一个神经网络,每个神经元都需要对其他神经元的引用。我一直在尝试通过原子来实现这个引用。

考虑代码

(def neuron1 {:connections [(atom 0)])
(def neuron2 {:connections [(atom neuron1)]})

(update-in neuron1 [:connections 0] #(reset! % neuron2))

最后一个会炸毁堆栈。

因此,原子似乎包含其内容,而不仅仅是引用它们。

如果我想传递一个指针的等价物,我该怎么办?我是否必须使用函数,如

(def neuron1 {:connections [(fn [] neuron2)]})

并调用它,而不是使用原子并取消引用它?

4

3 回答 3

5

你的代码很好。破坏堆栈的原因是您在 REPL 上运行 update-in 命令,这会导致它打印结果。由于每个神经元都嵌套在另一个神经元中,因此 print 语句会遇到堆栈溢出。尝试将 update-in 命令包含在另一个语句中,例如 (type),或者在另一个函数中运行它。

于 2013-03-01T04:07:10.643 回答
3

WolfeFan 已经回答了“为什么使用stackoverflow”的部分问题。就指针/引用类型的功能而言,您可以将 var(绑定到神经元)存储在原子中,而不是神经元对象本身。另外,我建议将连接作为向量的原子,而不是将单个连接作为原子,因为您很可能会从多个线程修改连接对象。

例子:

(def neuron1 {:connections (atom [])})
(def neuron2 {:connections (atom [#'neuron1])})

(update-in neuron1 [:connections] #(swap! % conj #'neuron2))

当您需要获取连接的神经元时,您需要使用var-get

(-> neuron1 :connections deref (get 0) var-get)

Vars 本身是线程安全的,要更改您需要使用的 var 的根绑定,alter-var-root这是一个原子操作。

于 2013-03-01T04:33:57.527 回答
3

如果您想使用简单的 Clojure 数据结构,最好忘记细粒度地使用原子。相反,制作一张巨大的地图来代表整个网络,可能像:

(def ann {1 {:connections [1 2 3] :weights [0.1 -0.3 0.5] :state 0.3} 2 {:connections [1 2 3] :weights [0.1 -0.3 0.5] :state 0.13} 3 {:connections [2 3] :weights [0.5 0.2] :state 0.31}})

然后减少它,使用 update-in 等来更新节点。使您的所有更新函数采用不可变的数据结构,因为这将使测试更容易。

现在肯定有比这更好的方法。您可能最好看看@mikera 对矩阵所做的事情。

或者,如果您想要异步,您可以使用 Lamina 或新的 Plumbing/Graph 库。

于 2013-03-01T04:39:25.837 回答