我正在尝试在Haskell中实现神经网络架构,并在MNIST上使用它.
我正在使用hmatrix线性代数包.我的培训框架是使用pipes包构建的.
问题是,我的代码编译不会崩溃.
但是对于一个,层NaN,小批量大小和学习速率的某些组合产生1e-100计算中的值.经过一些检查,我发现if激活中最终会出现非常小的值(顺序).但是,即使没有发生这种情况,培训仍然无效.它的损失或准确性没有任何改善.
我检查并重新检查了我的代码,我不知道问题的根源是什么.
这是反向传播训练,它计算每一层的增量:
backward lf n (out,tar) das = do
let ?out = tr (derivate lf (tar, out)) -- dE/dy
deltas = scanr (\(l, a') ? -> let w = weights l in (tr a') * (w <> ?)) ?out (zip (tail $ toList n) das)
return (deltas)
Run Code Online (Sandbox Code Playgroud)
n为损耗函数,weight是网络(bias矩阵和out向量的每个层),tar并且target是网络和所述的实际输出das(期望的)输出,并且out各自层的激活衍生物.在批处理模式中tar,das …
我正在努力优化一个依赖于ads conjugateGradientDescent函数的程序来完成大部分工作.
基本上我的代码是用Matlab和C编写的旧论文代码的翻译.我没有测量它,但是代码每秒运行几次迭代.我的每次迭代大约为几分钟......
代码在此存储库中可用:
可以通过以下命令运行相关代码:
$ cd aer-utils
$ cabal sandbox init
$ cabal sandbox add-source ../aer
$ cabal run learngabors
Run Code Online (Sandbox Code Playgroud)
使用GHC分析设施我已经确认下降实际上是大部分时间都在使用的部分:

(此处为交互式版本:https://dl.dropboxusercontent.com/u/2359191/learngabors.svg)
-s 告诉我生产力很低:
Productivity 33.6% of total user, 33.6% of total elapsed
Run Code Online (Sandbox Code Playgroud)
根据我收集的内容,有两件事可能会带来更高的性能:
拆箱:目前我使用自定义矩阵实现(in src/Data/SimpleMat.hs).这是我可以ad使用矩阵的唯一方法(参见:如何在hmatrix上自动区分?).我的猜测是,通过使用矩阵类型,newtype Mat w h a = Mat (Unboxed.Vector a)由于拆箱和融合将获得更好的性能.我找到了一些代码,其中包含未ad装箱的矢量实例,但到目前为止我还没有能够使用这些代码conjugateGradientFunction.
矩阵导数:在目前我无法找到的电子邮件中,爱德华提到最好使用Forward矩阵类型的实例而不是填充Forward实例的矩阵.我对如何实现这一点有一个微弱的想法,但还没有弄清楚我是如何根据ads类类实现它的.
这可能是一个太宽泛而无法回答的问题,所以如果你愿意帮助我,请随时与我联系Github.
Sooooo ......因为事实证明从伪矩阵到hmatrix数据类型变得非常重要:)
序言部分供参考:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ParallelListComp #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
import Numeric.LinearAlgebra.HMatrix
import Numeric.AD
reconstruct :: (Container Vector a, Num (Vector a))
=> [a] -> [Matrix a] -> Matrix a
reconstruct as ?s = sum [ a `scale` ? | a <- as | ? <- ?s ]
preserveInfo :: (Container Vector a, Num (Vector a))
=> Matrix a -> [a] -> [Matrix …Run Code Online (Sandbox Code Playgroud) HaskellHMatrix可以让你方便地获取切片:
m ?? (All, Take 3)
Run Code Online (Sandbox Code Playgroud)
但是如何设置切片,尤其是非矩形切片呢?例如,在 Python 的 Numpy 中我会这样做:
>>> x = np.arange(12).reshape(3, 4)
>>> x
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> x[[0,0], [1,3]] += x[[2,2], [1,3]] # to ix (0, 1) add (2, 1) and to ix (0, 3) add (2, 3)
>>> x
array([[ 0, 10, 2, 14],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
Run Code Online (Sandbox Code Playgroud)
我可以自己编写这个辅助函数,但是,它确实丑陋且不完整,并且需要我添加zipWith3M_ …
是否有一个标准的Haskell等同于NumPy的argsort功能?
我正在使用HMatrix,因此,希望兼容的功能Vector R是别名Data.Vector.Storable.Vector Double.argSort下面的函数是我目前使用的实现:
{-# LANGUAGE NoImplicitPrelude #-}
module Main where
import qualified Data.List as L
import qualified Data.Vector as V
import qualified Data.Vector.Storable as VS
import Prelude (($), Double, IO, Int, compare, print, snd)
a :: VS.Vector Double
a = VS.fromList [40.0, 20.0, 10.0, 11.0]
argSort :: VS.Vector Double -> V.Vector Int
argSort xs = V.fromList (L.map snd $ L.sortBy (\(x0, _) (x1, _) -> compare x0 x1) (L.zip …Run Code Online (Sandbox Code Playgroud) 由于hmatrix为Matrix类型提供了Num的实例,我可以表达元素减法,如:
m = (2><2)[1..] :: Double Matrix
m' = m - 3
Run Code Online (Sandbox Code Playgroud)
这很好,就像3a一样Num,并且通过从每个元素中减去3来创建矩阵m.
为什么这不起作用:
m' = m - (3::Double)
Run Code Online (Sandbox Code Playgroud)
我得到的错误是:
Couldn't match expected type ‘Matrix Double’
with actual type ‘Double’
In the second argument of ‘(-)’, namely ‘(3 :: Double)’
In the expression: m - (3 :: Double)
Run Code Online (Sandbox Code Playgroud)
我希望编译器能够理解a Double也是一个Num.为什么看似不是这样?
我需要以有效的方式在Haskell中对向量的元素应用函数,这意味着我不是在寻找这样的东西:
sigmoid :: [Float] -> [Float]
sigmoid [] = []
sigmoid (z:zs) = ( 1/(1+exp (-z)) ):(sigmoid zs)
Run Code Online (Sandbox Code Playgroud)
更具体地说,是否exp, log, ... etc使用Haskell在hmatrix中进行元素方向向量操作,类似于使用Python的numpy中的对应方式?如果我不使用矢量处理功能,我的代码运行速度非常慢.