hmatrix-backprop 0.1.2.0 → 0.1.2.1
raw patch · 6 files changed
+119/−72 lines, 6 filesdep −ANumdep ~backpropPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies removed: ANum
Dependency ranges changed: backprop
API changes (from Hackage documentation)
+ Numeric.LinearAlgebra.Static.Backprop: instance (GHC.TypeNats.KnownNat n, GHC.TypeNats.KnownNat m) => Numeric.Backprop.Class.Backprop (Internal.Static.L n m)
+ Numeric.LinearAlgebra.Static.Backprop: instance (GHC.TypeNats.KnownNat n, GHC.TypeNats.KnownNat m) => Numeric.Backprop.Class.Backprop (Internal.Static.M n m)
+ Numeric.LinearAlgebra.Static.Backprop: instance GHC.TypeNats.KnownNat n => Numeric.Backprop.Class.Backprop (Numeric.LinearAlgebra.Static.Sym n)
+ Numeric.LinearAlgebra.Static.Backprop: instance Numeric.Backprop.Class.Backprop (Internal.Static.C n)
+ Numeric.LinearAlgebra.Static.Backprop: instance Numeric.Backprop.Class.Backprop (Internal.Static.R n)
- Numeric.LinearAlgebra.Static.Backprop: create :: forall t s d q. (Reifies q W, Sized t s d, Num s, Num (d t)) => BVar q (d t) -> Maybe (BVar q s)
+ Numeric.LinearAlgebra.Static.Backprop: create :: forall t s d q. (Reifies q W, Sized t s d, Backprop s, Num (d t), Backprop (d t)) => BVar q (d t) -> Maybe (BVar q s)
- Numeric.LinearAlgebra.Static.Backprop: extractM :: forall t s q. (Reifies q W, Sized t s Matrix, Num s, Konst t (Int, Int) Matrix, Container Matrix t, Num (Matrix t)) => BVar q s -> BVar q (Matrix t)
+ Numeric.LinearAlgebra.Static.Backprop: extractM :: forall t s q. (Sized t s Matrix, Backprop s, Konst t (Int, Int) Matrix, Container Matrix t, Num (Matrix t), Reifies q W) => BVar q s -> BVar q (Matrix t)
- Numeric.LinearAlgebra.Static.Backprop: extractV :: forall t s q. (Reifies q W, Sized t s Vector, Num s, Konst t Int Vector, Container Vector t, Num (Vector t)) => BVar q s -> BVar q (Vector t)
+ Numeric.LinearAlgebra.Static.Backprop: extractV :: forall t s q. (Sized t s Vector, Konst t Int Vector, Container Vector t, Backprop t, Backprop s, Reifies q W) => BVar q s -> BVar q (Vector t)
- Numeric.LinearAlgebra.Static.Backprop: invlndet :: forall n mat field vec d s. (Reifies s W, KnownNat n, Num (mat n n), Domain field vec mat, Sized field (mat n n) d, Transposable (mat n n) (mat n n)) => BVar s (mat n n) -> (BVar s (mat n n), (BVar s field, BVar s field))
+ Numeric.LinearAlgebra.Static.Backprop: invlndet :: forall n mat field vec d s. (Reifies s W, KnownNat n, Num (mat n n), Domain field vec mat, Sized field (mat n n) d, Transposable (mat n n) (mat n n), Backprop field, Backprop (mat n n)) => BVar s (mat n n) -> (BVar s (mat n n), (BVar s field, BVar s field))
Files
- CHANGELOG.md +10/−0
- README.md +4/−3
- hmatrix-backprop.cabal +5/−6
- src/Numeric/LinearAlgebra/Static/Backprop.hs +71/−43
- test/Nudge.hs +27/−17
- test/Spec.hs +2/−3
CHANGELOG.md view
@@ -1,6 +1,16 @@ Changelog ========= +Version 0.1.2.1+---------------++*May 1, 2018*++<https://github.com/mstksg/hmatrix-backprop/releases/tag/v0.1.2.1>++* Updated for compatibility with *backprop-0.2.0.0*+* Orphan instances added for types in *Numeric.LinearAlgebra.Static*.+ Version 0.1.2.0 ---------------
README.md view
@@ -4,7 +4,8 @@ [](https://hackage.haskell.org/package/hmatrix-backprop) [](https://travis-ci.org/mstksg/hmatrix-backprop) -*[hmatrix][]* operations lifted for *[backprop][]*.+*[hmatrix][]* operations lifted for *[backprop][]*, along with orphan instances+of `Backprop`. [hmatrix]: http://hackage.haskell.org/package/hmatrix [backprop]: http://hackage.haskell.org/package/backprop@@ -41,8 +42,8 @@ TODO ---- -Apart from the exact API of hmatrix, it'd be nice to have:-+1. Now that new backprop no longer requires `Num`, we can lift normal hmatrix+ operations as well. 1. Statically sized convolutions. Should probably add this to hmatrix instead first, though.
hmatrix-backprop.cabal view
@@ -2,12 +2,12 @@ -- -- see: https://github.com/sol/hpack ----- hash: 11c33ad908b833f31f1c4bbe92635523c13c44f590d50114a5e0a4992e1c47a1+-- hash: 33301e0e44babbb514f51cf80addcfb5da2a0a2764c096e657abc8fa87db7879 name: hmatrix-backprop-version: 0.1.2.0+version: 0.1.2.1 synopsis: hmatrix operations lifted for backprop-description: hmatrix operations lifted for backprop.+description: hmatrix operations lifted for backprop, along with orphan instances. . Meant to act as a drop-in replacement to the API of Numeric.LinearAlgebra.Static. Just change your imports, and your@@ -38,8 +38,7 @@ src ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints build-depends:- ANum >=0.2- , backprop >=0.1.4+ backprop >=0.2 , base >=4.7 && <5 , finite-typelits , ghc-typelits-knownnat@@ -62,7 +61,7 @@ test ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N build-depends:- backprop >=0.1.4+ backprop >=0.2 , base >=4.7 && <5 , finite-typelits , hedgehog
src/Numeric/LinearAlgebra/Static/Backprop.hs view
@@ -8,6 +8,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-} {-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-} @@ -22,7 +23,9 @@ -- -- A wrapper over "Numeric.LinearAlgebra.Static" (type-safe vector and -- matrix operations based on blas/lapack) that allows its operations to--- work with <https://hackage.haskell.org/package/backprop backprop>.+-- work with <https://hackage.haskell.org/package/backprop backprop>. Also+-- provides orphan instances of 'Backprop' for types in+-- "Numeric.LinearAlgebra.Static". -- -- In short, these functions are "lifted" to work with 'BVar's. --@@ -189,30 +192,56 @@ , W ) where -import Data.ANum import Data.Bifunctor import Data.Maybe import Data.Proxy import Foreign.Storable import GHC.TypeLits import Lens.Micro hiding ((&))-import Numeric.Backprop-import Numeric.Backprop.Tuple+import Numeric.Backprop.Class+import Numeric.Backprop.Num import Unsafe.Coerce import qualified Data.Vector as V import qualified Data.Vector.Generic as VG import qualified Data.Vector.Generic.Sized as SVG import qualified Data.Vector.Sized as SV import qualified Data.Vector.Storable.Sized as SVS+import qualified Numeric.Backprop as BBP+import qualified Numeric.Backprop.Explicit as BE import qualified Numeric.LinearAlgebra as HU import qualified Numeric.LinearAlgebra.Static as H import qualified Numeric.LinearAlgebra.Static.Vector as H-import qualified Prelude.Backprop as B+import qualified Prelude.Backprop.Num as B #if MIN_VERSION_base(4,11,0) import Prelude hiding ((<>)) #endif +instance Backprop (H.R n) where+ zero = zeroNum+ add = addNum+ one = oneNum++instance Backprop (H.C n) where+ zero = zeroNum+ add = addNum+ one = oneNum++instance (KnownNat n, KnownNat m) => Backprop (H.L n m) where+ zero = zeroNum+ add = addNum+ one = oneNum++instance (KnownNat n, KnownNat m) => Backprop (H.M n m) where+ zero = zeroNum+ add = addNum+ one = oneNum++instance KnownNat n => Backprop (H.Sym n) where+ zero = zeroNum+ add = addNum+ one = oneNum+ vec2 :: Reifies s W => BVar s H.ℝ@@ -263,9 +292,9 @@ :: forall p n s. (Reifies s W, KnownNat p, KnownNat n, p <= n) => BVar s (H.R n) -> (BVar s (H.R p), BVar s (H.R (n - p)))-split v = (t ^^. _1, t ^^. _2) -- should we just return the T2 ?+split v = (t ^^. _1, t ^^. _2) where- t = isoVar (tupT2 . H.split) (uncurryT2 (H.#)) v+ t = BBP.isoVar H.split (uncurry (H.#)) v {-# NOINLINE t #-} {-# INLINE split #-} @@ -275,9 +304,9 @@ -> (BVar s H.ℝ, BVar s (H.R (n - 1))) headTail v = (t ^^. _1, t ^^. _2) where- t = isoVar (tupT2 . H.headTail)- (\(T2 d dx) -> (H.konst d :: H.R 1) H.# dx)- v+ t = BBP.isoVar H.headTail+ (\(d, dx) -> (H.konst d :: H.R 1) H.# dx)+ v {-# NOINLINE t #-} {-# INLINE headTail #-} @@ -338,7 +367,7 @@ -> (BVar s (H.L p n), BVar s (H.L (m - p) n)) splitRows v = (t ^^. _1, t ^^. _2) where- t = isoVar (tupT2 . H.splitRows) (uncurryT2 (H.===)) v+ t = BBP.isoVar H.splitRows (uncurry (H.===)) v {-# NOINLINE t #-} {-# INLINE splitRows #-} @@ -348,7 +377,7 @@ -> (BVar s (H.L m p), BVar s (H.L m (n - p))) splitCols v = (t ^^. _1, t ^^. _2) where- t = isoVar (tupT2 . H.splitCols) (uncurryT2 (H.|||)) v+ t = BBP.isoVar H.splitCols (uncurry (H.|||)) v {-# NOINLINE t #-} {-# INLINE splitCols #-} @@ -443,17 +472,17 @@ -> (BVar s (H.L m m), BVar s (H.R n), BVar s (H.L n n)) svd_ r = (t ^^. _1, t ^^. _2, t ^^. _3) where- o :: Op '[H.L m n] (T3 (H.L m m) (H.R n) (H.L n n))+ o :: Op '[H.L m n] (H.L m m, H.R n, H.L n n) o = op1 $ \x ->- let (u, σ, v) = H.svd x- in ( T3 u σ v- , \(T3 dU dΣ dV) ->+ let msv@(u, _, v) = H.svd x+ in ( msv+ , \(dU, dΣ, dV) -> if H.norm_0 dU == 0 && H.norm_0 dV == 0 then (u H.<> H.diagR 0 dΣ) H.<> H.tr v else error "svd_: Cannot backprop if U and V are used." ) {-# INLINE o #-}- t = liftOp1 o r+ t = BBP.liftOp1 o r {-# NOINLINE t #-} {-# INLINE svd_ #-} @@ -473,19 +502,19 @@ -> (BVar s (H.R n), BVar s (H.L n n)) eigensystem u = (t ^^. _1, t ^^. _2) where- o :: Op '[H.Sym n] (T2 (H.R n) (H.L n n))+ o :: Op '[H.Sym n] (H.R n, H.L n n) o = op1 $ \x -> let (l, v, vInv, vTr) = helpEigen x lRep = H.rowsL . SV.replicate $ l fMat = (1 - H.eye) * (lRep - H.tr lRep)- in ( T2 l v- , \(T2 dL dV) -> unsafeCoerce $+ in ( (l, v)+ , \(dL, dV) -> unsafeCoerce $ H.tr vInv H.<> (H.diag dL + fMat * (vTr H.<> dV)) H.<> vTr ) {-# INLINE o #-}- t = liftOp1 o u+ t = BBP.liftOp1 o u {-# NOINLINE t #-} {-# INLINE eigensystem #-} @@ -661,10 +690,10 @@ meanCov v = (t ^^. _1, t ^^. _2) where m = fromInteger $ natVal (Proxy @m)- t = ($ v) . liftOp1 . op1 $ \x ->- let (μ, σ) = H.meanCov x- in ( T2 μ σ- , \(T2 dμ dσ) ->+ t = ($ v) . BBP.liftOp1 . op1 $ \x ->+ let ms@(μ, _) = H.meanCov x+ in ( ms+ , \(dμ, dσ) -> let gradMean = H.rowsL . SV.replicate $ (dμ / H.konst m)@@ -999,23 +1028,25 @@ , H.Domain field vec mat , H.Sized field (mat n n) d , HU.Transposable (mat n n) (mat n n)+ , Backprop field+ , Backprop (mat n n) ) => BVar s (mat n n) -> (BVar s (mat n n), (BVar s field, BVar s field)) invlndet v = (t ^^. _1, (t ^^. _2, t ^^. _3)) where- o :: Op '[mat n n] (T3 (mat n n) field field)+ o :: Op '[mat n n] (mat n n, field, field) o = op1 $ \x -> let (i,(ldet, s)) = H.invlndet x iTr = H.tr i- in ( T3 i ldet s- , \(T3 dI dLDet _) ->+ in ( (i, ldet, s)+ , \(dI, dLDet, _) -> let gradI = - iTr `H.mul` dI `H.mul` iTr gradLDet = H.konst dLDet * H.tr i in gradI + gradLDet ) {-# INLINE o #-}- t = liftOp1 o v+ t = BBP.liftOp1 o v {-# NOINLINE t #-} {-# INLINE invlndet #-} @@ -1102,16 +1133,16 @@ -- If there are missing items, they are treated as zero. extractV :: forall t s q.- ( Reifies q W- , H.Sized t s HU.Vector- , Num s+ ( H.Sized t s HU.Vector , HU.Konst t Int HU.Vector , HU.Container HU.Vector t- , Num (HU.Vector t)+ , Backprop t+ , Backprop s+ , Reifies q W ) => BVar q s -> BVar q (HU.Vector t)-extractV = liftOp1 . op1 $ \x ->+extractV = BBP.liftOp1 . op1 $ \x -> let n = H.size x in ( H.extract x , \d -> let m = HU.size d@@ -1127,16 +1158,16 @@ -- If there are missing items, they are treated as zero. extractM :: forall t s q.- ( Reifies q W- , H.Sized t s HU.Matrix- , Num s+ ( H.Sized t s HU.Matrix+ , Backprop s , HU.Konst t (Int, Int) HU.Matrix , HU.Container HU.Matrix t , Num (HU.Matrix t)+ , Reifies q W ) => BVar q s -> BVar q (HU.Matrix t)-extractM = liftOp1 . op1 $ \x ->+extractM = BE.liftOp1 BE.addFunc (BE.ZF (HU.cmap (const 0))) . op1 $ \x -> -- TODO: can be BBP once instances are in Numeric.LinearAlgebra.Backprop let (xI,xJ) = H.size x in ( H.extract x , \d -> let (dI,dJ) = HU.size d@@ -1162,13 +1193,10 @@ {-# INLINE extractM #-} create- :: forall t s d q. (Reifies q W, H.Sized t s d, Num s, Num (d t))+ :: forall t s d q. (Reifies q W, H.Sized t s d, Backprop s, Num (d t), Backprop (d t)) => BVar q (d t) -> Maybe (BVar q s)-create = unANum- . sequenceVar- . isoVar (ANum . H.create)- (maybe 0 H.extract . unANum )+create = BBP.sequenceVar . BBP.isoVar H.create (maybe 0 H.extract) {-# INLINE create #-}
test/Nudge.hs view
@@ -7,6 +7,8 @@ {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} module Nudge where @@ -21,7 +23,6 @@ import Lens.Micro import Lens.Micro.Platform () import Numeric.Backprop-import Numeric.Backprop.Tuple import qualified Data.Ix as Ix import qualified Data.Vector.Sized as SV import qualified Hedgehog.Gen as Gen@@ -36,7 +37,7 @@ eps :: Double eps = 1e-11 -class (Num c, Show c, Show (TIx c)) => Testing c where+class (Backprop c, Show c, Show (TIx c)) => Testing c where type TIx c :: Type allIx :: c -> [TIx c] ixLens :: TIx c -> Lens' c Double@@ -95,7 +96,7 @@ scalarize = liftOp1 . op1 $ \xs -> (HU.sumElements xs, (`HU.konst` HU.size xs)) genTest = HU.fromLists <$> (replicateM 3 . replicateM 2) genTest -instance (KnownNat n, Testing a) => Testing (SV.Vector n a) where+instance (KnownNat n, Testing a, Num a) => Testing (SV.Vector n a) where type TIx (SV.Vector n a) = (Finite n, TIx a) allIx = fst . SV.imapM (\i x -> ((fromIntegral i,) <$> allIx x , x)) ixLens (i,j) = SV.ix i . ixLens j@@ -105,22 +106,22 @@ o = op1 $ \xs -> (SV.sum xs, SV.replicate) genTest = SV.replicateM genTest -instance (Testing a, Testing b) => Testing (T2 a b) where- type TIx (T2 a b) = Either (TIx a) (TIx b)- allIx (T2 x y) = (Left <$> allIx x)- ++ (Right <$> allIx y)+instance (Testing a, Testing b) => Testing (a, b) where+ type TIx (a, b) = Either (TIx a) (TIx b)+ allIx (x, y) = (Left <$> allIx x)+ ++ (Right <$> allIx y) ixLens (Left i) = _1 . ixLens i ixLens (Right j) = _2 . ixLens j scalarize t = B.norm_2V (B.vec2 (scalarize (t ^^. _1)) (scalarize (t ^^. _2)) )- genTest = T2 <$> genTest <*> genTest+ genTest = (,) <$> genTest <*> genTest -instance (Testing a, Testing b, Testing c, Num a, Num b, Num c) => Testing (T3 a b c) where- type TIx (T3 a b c) = Either (TIx a) (Either (TIx b) (TIx c))- allIx (T3 x y z) = (Left <$> allIx x)- ++ (Right . Left <$> allIx y)- ++ (Right . Right <$> allIx z)+instance (Testing a, Testing b, Testing c) => Testing (a, b, c) where+ type TIx (a, b, c) = Either (TIx a) (Either (TIx b) (TIx c))+ allIx (x, y, z) = (Left <$> allIx x)+ ++ (Right . Left <$> allIx y)+ ++ (Right . Right <$> allIx z) ixLens (Left i ) = _1 . ixLens i ixLens (Right (Left j)) = _2 . ixLens j ixLens (Right (Right k)) = _3 . ixLens k@@ -128,7 +129,7 @@ (scalarize (t ^^. _2)) (scalarize (t ^^. _3)) )- genTest = T3 <$> genTest <*> genTest <*> genTest+ genTest = (,,) <$> genTest <*> genTest <*> genTest validGrad :: Monad m@@ -166,12 +167,21 @@ (inpC, inpD, i) <- forAll $ do inpC <- genTest inpD <- genTest- i <- Gen.element (allIx (T2 inpC inpD))+ i <- Gen.element (allIx (inpC, inpD)) return (inpC, inpD, i)- let (r, gr) = second tupT2 $ backprop2 (\x -> scalarize . f x) inpC inpD+ let (r, gr) = backprop2 (\x -> scalarize . f x) inpC inpD when (r**2 < eps) discard- (old, new) <- validGrad (ixLens i) (T2 inpC inpD) gr+ (old, new) <- validGrad (ixLens i) (inpC, inpD) gr (evalBP (\t -> scalarize $ f (t ^^. _1) (t ^^. _2))) footnoteShow (r, gr, old, new, (old - new)**2, ((old - new)/old)**2) assert $ ((old - new)/old)**2 < eps +instance (HU.Container HU.Vector a, Num a) => Backprop (HU.Matrix a) where+ zero = HU.cmap (const 0)+ add = HU.add+ one = HU.cmap (const 1)++instance (KnownNat n, Num a) => Backprop (SV.Vector n a) where+ zero = (0 <$)+ add = (+)+ one = (1 <$)
test/Spec.hs view
@@ -11,7 +11,6 @@ import Lens.Micro import Nudge import Numeric.Backprop-import Numeric.Backprop.Tuple import Numeric.LinearAlgebra.Static (L, R) import System.Exit import System.IO@@ -21,11 +20,11 @@ prop_vec2 = nudgeProp2 B.vec2 prop_vec3 :: Property-prop_vec3 = nudgeProp @(T3 Double Double Double)+prop_vec3 = nudgeProp @(Double, Double, Double) (\t -> B.vec3 (t ^^. _1) (t ^^. _2) (t ^^. _3)) prop_vec4 :: Property-prop_vec4 = nudgeProp2 @(T2 Double Double) @(T2 Double Double)+prop_vec4 = nudgeProp2 @(Double, Double) @(Double, Double) (\x y -> B.vec4 (x ^^. _1) (x ^^. _2) (y ^^. _1) (y ^^. _2)) prop_snoc :: Property