我在这里彻底糊涂了。我正在使用循环递归形式,我正在使用doall,但对于大型循环,我仍然会出现堆栈溢出。我的 Clojure 版本是 1.5.1。
背景:我正在训练一个神经网络来模拟 XOR。该函数xor
为前馈函数,取权重输入并返回结果;该函数b-xor
是反向传播函数,它在给定最后一次调用的结果的情况下返回更新的权重xor
。
下面的循环运行得很好,运行得非常快,并返回一个结果,并且根据它返回的结果,它完美地训练了权重:
(loop [res 1 ; <- initial value doesn't matter
weights xorw ; <- initial pseudo-random weights
k 0] ; <- count
(if (= k 1000000)
res
(let [n (rand-int 4)
r (doall (xor weights (first (nth xorset n))))]
(recur (doall r)
(doall (b-xor weights r (second (nth xorset n))))
(inc k)))))
但是,当然,这只给了我最后一次运行的结果。显然我想知道为了得到这个结果而训练了哪些权重!以下循环,除了返回值改变外,没有任何内容,溢出:
(loop [res 1
weights xorw
k 0]
(if (= k 1000000)
weights ; <- new return value
(let [n (rand-int 4)
r (doall (xor weights (first (nth xorset n))))]
(recur (doall r)
(doall (b-xor weights r (second (nth xorset n))))
(inc k)))))
这对我来说没有意义。每次weights
调用都使用xor
. 那么为什么我可以weights
在内部使用但不能将其打印到 REPL 中呢?
正如你所看到的,我被困doall
在了各种各样的地方,比我认为我应该需要的要多。XOR 是一个玩具示例,因此weights
和xorset
都非常小。我相信溢出不是由于 and 的执行而发生的xor
,b-xor
而是当 REPL 尝试打印时发生的weights
,原因有以下两个:
(1) 这个循环可以达到 1500 而不会溢出堆栈。
(2)循环运行的时间与循环的长度一致;也就是说,如果我循环到 5000,它会运行半秒,然后打印堆栈溢出;如果我循环到 1000000,它会运行 10 秒,然后打印堆栈溢出 - 再次,只有当我打印weights
而不是res
最后。
(3) 编辑:另外,如果我只是将循环包装在 中(def w ... )
,那么就没有堆栈溢出。但是,尝试查看结果变量确实如此。
user=> (clojure.stacktrace/e)
java.lang.StackOverflowError: null
at clojure.core$seq.invoke (core.clj:133)
clojure.core$map$fn__4211.invoke (core.clj:2490)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:60)
clojure.lang.RT.seq (RT.java:484)
clojure.core$seq.invoke (core.clj:133)
clojure.core$map$fn__4211.invoke (core.clj:2490)
clojure.lang.LazySeq.sval (LazySeq.java:42)
nil
惰性序列在哪里?
如果您对更好的方法有建议(这只是我的即时 REPL 代码),那就太好了,但我真的在寻找关于这种情况下发生的事情的解释。
编辑2:绝对(?)REPL有问题。
这很奇怪。weights
是一个包含六个列表的列表,其中四个是空的。到现在为止还挺好。但是尝试将这些空列表中的一个打印到屏幕上会导致堆栈溢出,但这只是第一次。第二次打印没有抛出任何错误。打印非空列表不会产生堆栈溢出。现在我可以继续我的项目了,但是……这里到底发生了什么?有任何想法吗?(请原谅下面的丑陋,但我认为它可能会有所帮助)
user=> (def ww (loop etc. etc. ))
#'user/ww
user=> (def x (first ww))
#'user/x
user=> x
StackOverflowError clojure.lang.RT.seq (RT.java:484)
user=> x
()
user=> (def x (nth ww 3))
#'user/x
user=> x
(8.47089879874061 -8.742792338501289 -4.661609290853221)
user=> (def ww (loop etc. etc. ))
#'user/ww
user=> ww
StackOverflowError clojure.core/seq (core.clj:133)
user=> ww
StackOverflowError clojure.core/seq (core.clj:133)
user=> ww
StackOverflowError clojure.core/seq (core.clj:133)
user=> ww
StackOverflowError clojure.core/seq (core.clj:133)
user=> ww
(() () () (8.471553034351501 -8.741870954507117 -4.661171802683782) () (-8.861958958234174 8.828933147027938 18.43649480263751 -4.532462509591159))