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)、すべてが機能し、出力は次のとおりです。

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の値を知る必要があります。OK、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

そしてそれは、割り当てのある言語、あるいは非再帰的なバインディングでさえもそれが何を意味するのかを意味します。最初の行は無関係であり、2番目の行によってシャドウされます。2番目の行は、xとして定義されますx+1。つまり、再帰的に定義され、x = ((((...)+1)+1)+1)+1評価時にループします。

于 2010-07-23T06:11:00.137 に答える