Я пытаюсь сконструировать блок персептрона в Хаскеле, чтобы выучить булевы функции И и Или, как в книге Митчелла.
Я почти уверен, что мой градиентный спуск правильный, но я изо всех сил пытаюсь проверить, действительно ли он изучает алгоритм. У меня есть три вопроса, размещенных между кодом ниже.
(i) Правильна ли моя реализация градиентного спуска?
(ii) Если да, то учитывает ли он «лучшие» веса?
(iii) Как проверить, правильно ли изучены веса? oor и aand - это значения, когда вы подключаете логические пары к весам, приведенным в книге, но я думал, что порог sgn будет применяться к этим значениям? Если это была правильная гипотеза оценки, то решение Митчелла угадывает ту же функцию и / или. Являются ли мои обученные функции и и или (вычисленные в ans1, ans2) неверными?
import System.Random
-- for generating random initial weights
randomList :: Int -> [Double]
randomList seed = randoms (mkStdGen seed) :: [Double]
dotProd x y = foldr (+) 0 $ zipWith (*) x y
gdHelper [] _ del_w _ _ = del_w
gdHelper (x:xs) (t:ts) y@(weight:weights) w nu = gdHelper xs ts del_w w nu
where del_w = zipWith (+) y (map (*asdf) x)
asdf = nu * (t - o)
o = dotProd w x
gd _ _ _ w _ 0 = w
gd xs ts ws w nu n = gd xs ts [0,0,0] w2 nu (n-1)
where w2 = zipWith (+) w delW
delW = gdHelper xs ts ws w nu
-- initial weights
w = map (/20) $ take 3 $ randomList 30
trainingData = [([1,1],1),([1,-1],-1),([-1,1],-1),([-1,-1],-1)]
andData = map (1:) (map fst trainingData)
andOuts = map snd trainingData
orOuts = [1,1,1,-1]
gdand = gd andData andOuts [0,0,0] w 0.02 10000
gdor = gd andData orOuts [0,0,0] w 0.01 10000
ans1 = map (dotProd gdand) andData
ans2 = map (dotProd gdor) andData
-- trying to verify this from the book
aand = map (dotProd [-0.8,0.5,0.5]) andData
oor = map (dotProd [-0.3,0.5,0.5]) andData
От Митчелла:
Edit:
В заключение предположим, что я хочу реплицировать новые логические значения и и или для данных о логических значениях. Замените следующий код, и геометрическая картина останется прежней. (w1 = w2 = 1/2, а точка пересечения равна 1/2 от первоначального значения). Однако, поскольку данные были масштабированы (на 1/2) и переведены (на (1 / 2,1 / 2)), и мой алгоритм теперь узнает неправильную функцию. `andData = map (1 :) [[x, y] | x <- [0,1], y <- [0,1]] </p>
andData = map (1:) [[x,y] | x <- [0,1], y <- [0,1]]
andOuts = [0,0,0,1]
orOuts = [0,1,1,1]
oor = map (dotProd [-0.5,1,1]) andData
aand = map (dotProd [-1.5,1,1]) andData