2010-07-22 9 views
1

Je lisais sur les perceptrons et essayais d'en implémenter un en haskell. L'algorithme semble fonctionner aussi loin que je peux tester. Je vais réécrire entièrement le code à un moment donné, mais avant de le faire, j'ai pensé à poser quelques questions qui ont été soulevées lors du codage.Comportement incohérent avec Haskell

Le neurone peut être entraîné lors du retour du neurone complet. let neuron = train set [1,1] fonctionne, mais si je change la fonction de train pour renvoyer un neurone incomplet sans les entrées, ou essayer de modéliser correspondre et créer seulement un neurone incomplet, le code tombe en boucle sans fin. Lors du retour du neurone complet, tout fonctionne, mais lors du retour du neurone curryable, le code tombe dans une boucle.

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() 

Modifier: Comme pour les commentaires, en précisant un peu plus.

Courir avec le code ci-dessus, je reçois: perceptron: <<loop>>

Mais en éditant la principale méthode pour:

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

(Notez les let neuron et les lignes d'impression), tout fonctionne et la sortie est :

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

+6

1) De quelle manière la "boucle infinie lorsque je fais un changement" est-elle un "comportement incohérent"? 2) Pourriez-vous réduire (ou au moins commenter) votre exemple pour isoler une petite partie qui vous rend confus, si vous le faites, les gens sont plus susceptibles de répondre et de corriger correctement votre confusion dans la réponse. –

+1

Il serait utile de montrer le code qui fait ce que vous attendez, ainsi que le changement qui fait ce à quoi vous ne vous attendez pas. – intoverflow

+0

Le problème n'est-il pas lié à w? "let a = a; print a" va toujours être une boucle infinie. – jrockway

Répondre

4

peut-être que je manque quelque chose, mais je bouillis y notre cas de test jusqu'à ce programme:

module Main where 
data Foo a = Foo a 

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

Cette autre Simplifie à:

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

Le problème est que la liaison (Foo x) à quelque chose qui dépend de x est une dépendance cyclique. Pour évaluer x, nous devons connaître la valeur de x. OK, nous avons juste besoin de calculer x. Pour calculer x, nous devons connaître la valeur de x. C'est bien, nous allons juste calculer x. Etc. Souvenez-vous: ce n'est pas C, rappelez-vous: c'est une liaison, pas une affectation, et la liaison est évaluée paresseusement.

Utiliser des noms plus variables, et tout cela fonctionne:

module Main where 
data Foo a = Foo a 

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

(La variable en question, dans votre cas, est w.)

3

Ceci est une erreur commune dans Haskell. Vous ne pouvez pas dire des choses comme:

let x = 0 
let x = x + 1 

Et avez-il dire ce qu'il serait dans une langue avec affectation, ou même nonrecursive liaison. La première ligne n'est pas pertinente, elle est ombrée par la deuxième ligne, qui définit x comme x+1, c'est-à-dire qu'elle définit de manière récursive x = ((((...)+1)+1)+1)+1, qui sera bouclée lors de l'évaluation.

Questions connexes