1

我正在阅读感知器并试图在haskell中实现一个。该算法似乎在我可以测试的范围内工作。我将在某个时候完全重写代码,但在这样做之前,我想问一些在编码时出现的问题。

当返回完整的神经元时,可以训练神经元。let neuron = train set [1,1]有效,但是如果我更改 train 函数以返回没有输入的不完整神经元,或者尝试进行模式匹配并仅创建不完整的神经元,则代码将陷入无休止的循环。

tl; dr 当返回完整的神经元时一切正常,但是当返回可咖喱神经元时,代码陷入循环。

module Main where
import System.Random
type Inputs = [Float]
type Weights = [Float]
type Threshold = Float
type Output = Float
type Trainingset = [(Inputs, Output)]

data Neuron = Neuron Threshold Weights Inputs deriving Show

output :: Neuron -> Output
output (Neuron threshold weights inputs) = 
          if total >= threshold then 1 else 0
          where total = sum $ zipWith (*) weights inputs

rate :: Float -> Float -> Float
rate t o = 0.1 * (t - o)

newweight :: Float -> Float -> Weights -> Inputs -> Weights
newweight t o weight input = zipWith nw weight input
  where nw w x = w + (rate t o) * x

learn :: Neuron -> Float -> Neuron
learn on@(Neuron tr w i) t = 
  let o = output on
  in Neuron tr (newweight t o w i) i

converged :: (Inputs -> Neuron) -> Trainingset -> Bool
converged n set = not $ any (\(i,o) -> output (n i) /= o) set

train :: Weights -> Trainingset -> Neuron
train w s = train' s (Neuron 1 w)

train' :: Trainingset -> (Inputs -> Neuron) -> Neuron
train' s n | not $ converged n set 
              = let (Neuron t w i) = train'' s n
                in train' s (Neuron t w)
          | otherwise = n $ fst $ head s

train'' :: Trainingset -> (Inputs -> Neuron) -> Neuron
train'' ((a,b):[]) n = learn (n a) b
train'' ((a,b):xs) n = let 
                        (Neuron t w i) = learn (n a) b
                      in
                        train'' xs (Neuron t w)

set :: Trainingset
set = [
        ([1,0], 0),
        ([1,1], 1),
        ([0,1], 0),
        ([0,0], 0)
      ]

randomWeights :: Int -> IO [Float]
randomWeights n = 
  do
    g <- newStdGen
    return $ take n $ randomRs (-1, 1) g

main = do
  w <- randomWeights 2
  let (Neuron t w i) = train w set
  print $ output $ (Neuron t w [1,1])
  return ()

编辑:根据评论,指定更多。

使用上面的代码运行,我得到: perceptron: <<loop>>

但是通过编辑 main 方法来:

main = do
  w <- randomWeights 2
  let neuron = train w set
  print $ neuron
  return ()

(注意let neuron, 和 print 行),一切正常,输出为:

Neuron 1.0 [0.71345896,0.33792675] [1.0,0.0]

4

2 回答 2

4

也许我遗漏了一些东西,但我将您的测试用例归结为这个程序:

module Main where
data Foo a = Foo a

main = do
  x ← getLine
  let (Foo x) = Foo x
  putStrLn x

这进一步简化为:

main = do
  x ← getLine
  let x = x
  putStrLn x

问题是绑定(Foo x)到依赖于 x 的东西是一个循环依赖。要评估 x,我们需要知道 x 的值。好的,所以我们只需要计算 x。要计算 x,我们需要知道 x 的值。没关系,我们只计算 x。等等。

这不是 C,请记住:它是绑定,而不是赋值,并且绑定是懒惰地评估的。

使用更好的变量名,这一切都有效:

module Main where
data Foo a = Foo a

main = do
  line ← getLine
  let (Foo x) = Foo line
  putStrLn x

(在您的情况下,有问题的变量是w。)

于 2010-07-23T05:44:57.603 回答
3

这是 Haskell 中的常见错误。你不能说这样的话:

let x = 0
let x = x + 1

它是否意味着它在具有分配甚至非递归绑定的语言中的含义。第一行无关紧要,它被第二行遮住了,第二行定义xx+1,也就是说,它递归地定义x = ((((...)+1)+1)+1)+1,它将在评估时循环。

于 2010-07-23T06:11:00.137 回答