2010-07-22 18 views
1

我在閱讀perceptrons並試圖在haskell中實現一個。算法似乎正在工作,只要我可以測試。我將在某個時候完全重寫代碼,但在此之前,我想提出一些在編寫代碼時出現的問題。與Haskell的行爲不一致

當返回完整的神經元時,可以訓練神經元。 let neuron = train set [1,1]的作品,但如果我改變火車功能返回一個不完整的神經元沒有輸入,或嘗試模式匹配,並只創建一個不完整的神經元,代碼將陷入無休止的循環。

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 [email protected](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 = do 
    w <- randomWeights 2 
    let neuron = train w set 
    print $ neuron 
    return() 

(注意let neuron和打印行),一切正常,輸出爲:

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

+6

1)「變更時無限循環」和「不一致行爲」是什麼? 2)你是否可以減少(或者至少評論)你的例子,以隔離令你困惑的小部分,如果你確實有人更有可能迴應並且正確地解決你在迴應中的困惑。 – 2010-07-22 20:43:32

+1

這會很方便地顯示你所期望的代碼,以及做你不期望的改變。 – intoverflow 2010-07-22 21:58:26

+0

這個問題不是用w來重新綁定w嗎? 「讓a = a;打印一個」總是會成爲一個無限循環。 – jrockway 2010-07-23 05:37:52

回答

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

3

這是在Haskell一個常見的錯誤。你不能說這樣的事情:

let x = 0 
let x = x + 1 

而且它意味着什麼它會在語言與任務,甚至非遞歸綁定。第一行是無關緊要的,它被第二行隱藏,它將x定義爲x+1,即它遞歸地定義了x = ((((...)+1)+1)+1)+1,它將在評估時循環。