packages feed

hmatrix-backprop 0.1.0.0 → 0.1.1.0

raw patch · 3 files changed

+132/−103 lines, 3 filesdep ~backpropdep ~hmatrix-vector-sizedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: backprop, hmatrix-vector-sized

API changes (from Hackage documentation)

- Numeric.LinearAlgebra.Static.Backprop: dmmap' :: (Reifies s W, KnownNat n, KnownNat m, Domain field vec mat, Num (mat n m), Num field) => (forall s'. Reifies s' W => BVar s' field -> BVar s' field) -> BVar s (mat n m) -> BVar s (mat n m)
- Numeric.LinearAlgebra.Static.Backprop: dvmap' :: (Reifies s W, KnownNat n, Domain field vec mat, Num (vec n), Num field) => (forall s'. Reifies s' W => BVar s' field -> BVar s' field) -> BVar s (vec n) -> BVar s (vec n)
+ Numeric.LinearAlgebra.Static.Backprop: class Reifies k (s :: k) a | s -> a
+ Numeric.LinearAlgebra.Static.Backprop: data BVar s a :: Type -> * -> *
+ Numeric.LinearAlgebra.Static.Backprop: data W :: *
+ Numeric.LinearAlgebra.Static.Backprop: mmap :: (Reifies s W, KnownNat n, KnownNat m) => (BVar s Double -> BVar s Double) -> BVar s (L n m) -> BVar s (L n m)
+ Numeric.LinearAlgebra.Static.Backprop: mmap' :: forall n m mat field s. (Reifies s W, KnownNat m, Num (mat n m), Sized field (mat n m) Matrix, Element field) => (forall s'. Reifies s' W => BVar s' field -> BVar s' field) -> BVar s (mat n m) -> BVar s (mat n m)
+ Numeric.LinearAlgebra.Static.Backprop: vmap :: (Reifies s W, KnownNat n) => (BVar s Double -> BVar s Double) -> BVar s (R n) -> BVar s (R n)
+ Numeric.LinearAlgebra.Static.Backprop: vmap' :: (Reifies s W, Num (vec n), Storable field, Sized field (vec n) Vector) => (forall s'. Reifies s' W => BVar s' field -> BVar s' field) -> BVar s (vec n) -> BVar s (vec n)
- Numeric.LinearAlgebra.Static.Backprop: dmmap :: forall n m mat field s. (Reifies s W, KnownNat m, Num (mat n m), Storable (field, field), Sized field (mat n m) Matrix, Element field) => (forall s'. Reifies s' W => BVar s' field -> BVar s' field) -> BVar s (mat n m) -> BVar s (mat n m)
+ Numeric.LinearAlgebra.Static.Backprop: dmmap :: (Reifies s W, KnownNat n, KnownNat m, Domain field vec mat, Num (mat n m), Num field) => (forall s'. Reifies s' W => BVar s' field -> BVar s' field) -> BVar s (mat n m) -> BVar s (mat n m)
- Numeric.LinearAlgebra.Static.Backprop: dvmap :: (Reifies s W, Num (vec n), Storable field, Storable (field, field), Sized field (vec n) Vector) => (forall s'. Reifies s' W => BVar s' field -> BVar s' field) -> BVar s (vec n) -> BVar s (vec n)
+ Numeric.LinearAlgebra.Static.Backprop: dvmap :: (Reifies s W, KnownNat n, Domain field vec mat, Num (vec n), Num field) => (forall s'. Reifies s' W => BVar s' field -> BVar s' field) -> BVar s (vec n) -> BVar s (vec n)

Files

CHANGELOG.md view
@@ -1,6 +1,24 @@ Changelog ========= +Version 0.1.1.0+---------------++*Mar 25, 2018*++<https://github.com/mstksg/hmatrix-backprop/releases/tag/v0.1.1.0>++*   `dvmap`/`dmmap` family rewritten, which is a breaking API change.  Previous+    version of `dvmap`/`dmmap` would not even compile at all if used, though,+    because of nonsensical constraints, so it is likely that no code that+    previously worked is now breaking.+*   *backprop* types re-exported for convenience++*Internal*++*   Rewrote much code to use `isoVar` instead of `opIso`, for increased clarity+    and cleanliness.  Requires *backprop-0.1.4.0*.+ Version 0.1.0.0 --------------- 
hmatrix-backprop.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 0d60d828b601d4eb24c4978c049e961589bc85fcabfd9c4c71ee0103caf1477e+-- hash: 7bd7d72297fd6caf75a31bbc3856f764f21999255f99a4f6bcad71e4739acf2a  name:           hmatrix-backprop-version:        0.1.0.0+version:        0.1.1.0 synopsis:       hmatrix operations lifted for backprop description:    hmatrix operations lifted for backprop.                 .@@ -39,12 +39,13 @@   ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints   build-depends:       ANum >=0.2-    , backprop >=0.1.2+    , backprop >=0.1.4     , base >=4.7 && <5+    , finite-typelits     , ghc-typelits-knownnat     , ghc-typelits-natnormalise     , hmatrix >=0.18-    , hmatrix-vector-sized >=0.1+    , hmatrix-vector-sized >=0.1.1     , microlens     , vector     , vector-sized >=0.6@@ -61,13 +62,13 @@       test   ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N   build-depends:-      backprop >=0.1.2+      backprop >=0.1.4     , base >=4.7 && <5     , finite-typelits     , hedgehog     , hmatrix >=0.18     , hmatrix-backprop-    , hmatrix-vector-sized >=0.1+    , hmatrix-vector-sized >=0.1.1     , microlens     , microlens-platform     , vector-sized >=0.6
src/Numeric/LinearAlgebra/Static/Backprop.hs view
@@ -43,6 +43,8 @@ -- functions are automatically backpropagatable.  Useful types are all -- re-exported. --+-- Also contains 'sumElements' 'BVar' operation.+-- -- Formulas for gradients come from the following papers: -- --     * https://people.maths.ox.ac.uk/gilesm/files/NA-08-01.pdf@@ -77,10 +79,6 @@ --     to handle these are at the moment. --     * 'H.withRows' and 'H.withColumns' made "type-safe", without --     existential types, with 'fromRows' and 'fromColumns'.------ Some other notes:------     * Added 'sumElements', as well, for convenience.  module Numeric.LinearAlgebra.Static.Backprop (   -- * Vector@@ -150,10 +148,12 @@   , dot   , cross   , diagR+  , vmap+  , vmap'   , dvmap-  , dvmap'+  , mmap+  , mmap'   , dmmap-  , dmmap'   , outer   , zipWithVector   , zipWithVector'@@ -179,26 +179,34 @@   , mTm   , unSym   , (<·>)+  -- * Backprop types re-exported+  -- | Re-exported for convenience.+  --+  -- @since 0.1.1.0+  , BVar+  , Reifies+  , 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.Op import           Numeric.Backprop.Tuple 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.LinearAlgebra               as HU-import qualified Numeric.LinearAlgebra.Devel         as HU import qualified Numeric.LinearAlgebra.Static        as H import qualified Numeric.LinearAlgebra.Static.Vector as H+import qualified Prelude.Backprop                    as B  #if MIN_VERSION_base(4,11,0) import           Prelude hiding               ((<>))@@ -209,9 +217,7 @@     => BVar s H.ℝ     -> BVar s H.ℝ     -> BVar s (H.R 2)-vec2 = liftOp2 $ opIsoN-    (\(x ::< y ::< Ø)                -> H.vec2 x y     )-    (\(HU.toList.H.extract->[dx,dy]) -> dx ::< dy ::< Ø)+vec2 = isoVar2 H.vec2 (\(H.rVec->v) -> (SVS.index v 0, SVS.index v 1)) {-# INLINE vec2 #-}  vec3@@ -220,9 +226,7 @@     -> BVar s H.ℝ     -> BVar s H.ℝ     -> BVar s (H.R 3)-vec3 = liftOp3 $ opIsoN-    (\(x ::< y ::< z ::< Ø)             -> H.vec3 x y z          )-    (\(HU.toList.H.extract->[dx,dy,dz]) -> dx ::< dy ::< dz ::< Ø)+vec3 = isoVar3 H.vec3 (\(H.rVec->v) -> (SVS.index v 0, SVS.index v 1, SVS.index v 2)) {-# INLINE vec3 #-}  vec4@@ -232,22 +236,17 @@     -> BVar s H.ℝ     -> BVar s H.ℝ     -> BVar s (H.R 4)-vec4 vX vY vZ vW = liftOp o (vX :< vY :< vZ :< vW :< Ø)-  where-    o :: Op '[H.ℝ, H.ℝ, H.ℝ, H.ℝ] (H.R 4)-    o = opIsoN-      (\(x ::< y ::< z ::< w ::< Ø)          -> H.vec4 x y z w               )-      (\(HU.toList.H.extract->[dx,dy,dz,dw]) -> dx ::< dy ::< dz ::< dw ::< Ø)-    {-# INLINE o #-}+vec4 vX vY vZ vW = isoVarN+    (\(x ::< y ::< z ::< w ::< Ø) -> H.vec4 x y z w)+    (\(H.rVec->v) -> SVS.index v 0 ::< SVS.index v 1 ::< SVS.index v 2 ::< SVS.index v 3 ::< Ø)+    (vX :< vY :< vZ :< vW :< Ø) {-# INLINE vec4 #-}  (&) :: (Reifies s W, KnownNat n, 1 <= n, KnownNat (n + 1))     => BVar s (H.R n)     -> BVar s H.ℝ     -> BVar s (H.R (n + 1))-(&) = liftOp2 $ opIsoN-    (\(xs ::< y ::< Ø)    -> xs H.& y                         )-    (\(H.split->(dxs,dy)) -> dxs ::< fst (H.headTail dy) ::< Ø)+(&) = isoVar2 (H.&) (\(H.split->(dxs,dy)) -> (dxs, fst (H.headTail dy))) infixl 4 & {-# INLINE (&) #-} @@ -255,9 +254,7 @@     => BVar s (H.R n)     -> BVar s (H.R m)     -> BVar s (H.R (n + m))-(#) = liftOp2 $ opIsoN-    (\(x ::< y ::< Ø)    -> x H.# y        )-    (\(H.split->(dX,dY)) -> dX ::< dY ::< Ø)+(#) = isoVar2 (H.#) H.split infixl 4 # {-# INLINE (#) #-} @@ -267,9 +264,7 @@     -> (BVar s (H.R p), BVar s (H.R (n - p))) split v = (t ^^. _1, t ^^. _2)      -- should we just return the T2 ?   where-    t = liftOp1 (opIso (tupT2 . H.split)-                       (uncurryT2 (H.#))-                ) v+    t = isoVar (tupT2 . H.split) (uncurryT2 (H.#)) v     {-# NOINLINE t #-} {-# INLINE split #-} @@ -279,9 +274,9 @@     -> (BVar s H.ℝ, BVar s (H.R (n - 1))) headTail v = (t ^^. _1, t ^^. _2)   where-    t = liftOp1 (opIso (tupT2 . H.headTail)-                       (\(T2 d dx) -> (H.konst d :: H.R 1) H.# dx)-                ) v+    t = isoVar (tupT2 . H.headTail)+               (\(T2 d dx) -> (H.konst d :: H.R 1) H.# dx)+               v     {-# NOINLINE t #-} {-# INLINE headTail #-} @@ -290,9 +285,8 @@     :: forall n s. (Reifies s W, KnownNat n)     => SV.Vector n (BVar s H.ℝ)     -> BVar s (H.R n)-vector vs =-    liftOp1 (opIso (H.vecR . SVG.convert) (SVG.convert . H.rVec))-            (collectVar vs)+vector = isoVar (H.vecR . SVG.convert) (SVG.convert . H.rVec)+       . collectVar {-# INLINE vector #-}  linspace@@ -312,22 +306,20 @@ row :: (Reifies s W, KnownNat n)     => BVar s (H.R n)     -> BVar s (H.L 1 n)-row = liftOp1 $ opIso H.row H.unrow+row = isoVar H.row H.unrow {-# INLINE row #-}  col :: (Reifies s W, KnownNat n)     => BVar s (H.R n)     -> BVar s (H.L n 1)-col = liftOp1 $ opIso H.col H.uncol+col = isoVar H.col H.uncol {-# INLINE col #-}  (|||) :: (Reifies s W, KnownNat c, KnownNat r1, KnownNat (r1 + r2))       => BVar s (H.L c r1)       -> BVar s (H.L c r2)       -> BVar s (H.L c (r1 + r2))-(|||) = liftOp2 $ opIsoN-    (\(x ::< y ::< Ø)        -> x H.||| y        )-    (\(H.splitCols->(dX,dY)) -> dX ::< dY ::< Ø)+(|||) = isoVar2 (H.|||) H.splitCols infixl 3 ||| {-# INLINE (|||) #-} @@ -335,9 +327,7 @@       => BVar s (H.L r1        c)       -> BVar s (H.L r2        c)       -> BVar s (H.L (r1 + r2) c)-(===) = liftOp2 $ opIsoN-    (\(x ::< y ::< Ø)        -> x H.=== y        )-    (\(H.splitRows->(dX,dY)) -> dX ::< dY ::< Ø)+(===) = isoVar2 (H.===) H.splitRows infixl 2 === {-# INLINE (===) #-} @@ -347,9 +337,7 @@     -> (BVar s (H.L p n), BVar s (H.L (m - p) n)) splitRows v = (t ^^. _1, t ^^. _2)   where-    t = liftOp1 (opIso (tupT2 . H.splitRows)-                       (\(T2 dx dy) -> dx H.=== dy)-                ) v+    t = isoVar (tupT2 . H.splitRows) (uncurryT2 (H.===)) v     {-# NOINLINE t #-} {-# INLINE splitRows #-} @@ -359,9 +347,7 @@     -> (BVar s (H.L m p), BVar s (H.L m (n - p))) splitCols v = (t ^^. _1, t ^^. _2)   where-    t = liftOp1 (opIso (tupT2 . H.splitCols)-                       (uncurryT2 (H.|||))-                ) v+    t = isoVar (tupT2 . H.splitCols) (uncurryT2 (H.|||)) v     {-# NOINLINE t #-} {-# INLINE splitCols #-} @@ -369,20 +355,20 @@     :: (Reifies s W, KnownNat n)     => BVar s (H.L 1 n)     -> BVar s (H.R n)-unrow = liftOp1 $ opIso H.unrow H.row+unrow = isoVar H.unrow H.row {-# INLINE unrow #-}  uncol     :: (Reifies s W, KnownNat n)     => BVar s (H.L n 1)     -> BVar s (H.R n)-uncol = liftOp1 $ opIso H.uncol H.col+uncol = isoVar H.uncol H.col {-# INLINE uncol #-}  tr  :: (Reifies s W, HU.Transposable m mt, HU.Transposable mt m, Num m, Num mt)     => BVar s m     -> BVar s mt-tr = liftOp1 $ opIso H.tr H.tr+tr = isoVar H.tr H.tr {-# INLINE tr #-}  diag@@ -397,15 +383,9 @@     :: forall m n s. (Reifies s W, KnownNat m, KnownNat n)     => [BVar s H.ℝ]     -> BVar s (H.L m n)-matrix vs = case SV.fromList @(m * n) vs of-    Nothing  -> error "matrix: invalid number of elements"-    Just vs' ->-        liftOp1 (opIso (fromJust . H.create . HU.reshape n . VG.convert . SV.fromSized)-                       (SV.concatMap (SVG.convert . H.rVec) . H.lRows)-                )-                (collectVar vs')-  where-    n = fromInteger $ natVal (Proxy @n)+matrix = maybe (error "matrix: invalid number of elements")+               (isoVar (H.vecL . SVG.convert) (SVG.convert . H.lVec) . collectVar)+       . SV.fromList @(m * n) {-# INLINE matrix #-}  -- | Matrix product@@ -808,29 +788,43 @@     ) {-# INLINE diagR #-} -dvmap+-- | Note: if possible, use the potentially much more performant 'vmap''.+vmap     :: ( Reifies s W+       , KnownNat n+       )+    => (BVar s Double -> BVar s Double)+    -> BVar s (H.R n)+    -> BVar s (H.R n)+vmap f = isoVar (H.vecR . SVG.convert @V.Vector) (SVG.convert . H.rVec)+       . B.fmap f+       . isoVar (SVG.convert . H.rVec) (H.vecR . SVG.convert)+{-# INLINE vmap #-}++-- | 'vmap', but potentially more performant.  Only usable if the mapped+-- function does not depend on any external 'BVar's.+vmap'+    :: ( Reifies s W        , Num (vec n)        , Storable field-       , Storable (field, field)        , H.Sized field (vec n) HU.Vector        )     => (forall s'. Reifies s' W => BVar s' field -> BVar s' field)     -> BVar s (vec n)     -> BVar s (vec n)-dvmap f = liftOp1 . op1 $ \x ->-    let (y, dx) = HU.unzipVector $ VG.map (backprop f) (H.extract x)-    in  ( fromJust (H.create y)-        , \d -> d * fromJust (H.create dx)-        )-{-# INLINE dvmap #-}+vmap' f = liftOp1 . op1 $ bimap (fromJust . H.create . VG.convert)+                                ((*) . fromJust . H.create . VG.convert)+                        . V.unzip+                        . V.map (backprop f)+                        . VG.convert+                        . H.extract+{-# INLINE vmap' #-}  -- TODO: Can be made more efficient if backprop exports -- a custom-total-derivative version --- | A version of 'dvmap' that is less performant but is based on--- 'H.zipWithVector' from 'H.Domain'.-dvmap'+-- | Note: Potentially less performant than 'vmap''.+dvmap     :: ( Reifies s W        , KnownNat n        , H.Domain field vec mat@@ -840,38 +834,53 @@     => (forall s'. Reifies s' W => BVar s' field -> BVar s' field)     -> BVar s (vec n)     -> BVar s (vec n)-dvmap' f = liftOp1 . op1 $ \x ->+dvmap f = liftOp1 . op1 $ \x ->     ( H.dvmap (evalBP f) x     , (H.dvmap (gradBP f) x *)     )-{-# INLINE dvmap' #-}+{-# INLINE dvmap #-} -dmmap+-- | Note: if possible, use the potentially much more performant 'mmap''.+mmap+    :: ( Reifies s W+       , KnownNat n+       , KnownNat m+       )+    => (BVar s Double -> BVar s Double)+    -> BVar s (H.L n m)+    -> BVar s (H.L n m)+mmap f = isoVar (H.vecL . SVG.convert @V.Vector) (SVG.convert . H.lVec)+       . B.fmap f+       . isoVar (SVG.convert . H.lVec) (H.vecL . SVG.convert)+{-# INLINE mmap #-}++-- | 'mmap', but potentially more performant.  Only usable if the mapped+-- function does not depend on any external 'BVar's.+mmap'     :: forall n m mat field s.        ( Reifies s W        , KnownNat m        , Num (mat n m)-       , Storable (field, field)        , H.Sized field (mat n m) HU.Matrix        , HU.Element field        )     => (forall s'. Reifies s' W => BVar s' field -> BVar s' field)     -> BVar s (mat n m)     -> BVar s (mat n m)-dmmap f = liftOp1 . op1 $ \x ->-    let (y', dx') = HU.unzipVector-                  . VG.map (backprop f)-                  . HU.flatten-                  $ H.extract x-    in  ( fromJust . H.create . HU.reshape m $ y'-        , \d -> (* d) . fromJust . H.create . HU.reshape m $ dx'-        )+mmap' f = liftOp1 . op1 $ bimap (fromJust . H.create . HU.reshape m . VG.convert)+                                ((*) . fromJust . H.create . HU.reshape m . VG.convert)+                        . V.unzip+                        . V.map (backprop f)+                        . VG.convert+                        . HU.flatten+                        . H.extract   where     m :: Int     m = fromInteger $ natVal (Proxy @m)-{-# INLINE dmmap #-}+{-# INLINE mmap' #-} -dmmap'+-- | Note: Potentially less performant than 'mmap''.+dmmap     :: ( Reifies s W        , KnownNat n        , KnownNat m@@ -882,11 +891,11 @@     => (forall s'. Reifies s' W => BVar s' field -> BVar s' field)     -> BVar s (mat n m)     -> BVar s (mat n m)-dmmap' f = liftOp1 . op1 $ \x ->+dmmap f = liftOp1 . op1 $ \x ->     ( H.dmmap (evalBP f) x     , (H.dmmap (gradBP f) x *)     )-{-# INLINE dmmap' #-}+{-# INLINE dmmap #-}  outer     :: ( Reifies s W@@ -1031,28 +1040,28 @@     :: forall m n s. (Reifies s W, KnownNat m, KnownNat n)     => BVar s (H.L m n)     -> SV.Vector m (BVar s (H.R n))-toRows = sequenceVar . liftOp1 (opIso H.lRows H.rowsL)+toRows = sequenceVar . isoVar H.lRows H.rowsL {-# INLINE toRows #-}  toColumns     :: forall m n s. (Reifies s W, KnownNat m, KnownNat n)     => BVar s (H.L m n)     -> SV.Vector n (BVar s (H.R m))-toColumns = sequenceVar . liftOp1 (opIso H.lCols H.colsL)+toColumns = sequenceVar . isoVar H.lCols H.colsL {-# INLINE toColumns #-}  fromRows     :: forall m n s. (Reifies s W, KnownNat m, KnownNat n)     => SV.Vector m (BVar s (H.R n))     -> BVar s (H.L m n)-fromRows = liftOp1 (opIso H.rowsL H.lRows) . collectVar+fromRows = isoVar H.rowsL H.lRows . collectVar {-# INLINE fromRows #-}  fromColumns     :: forall m n s. (Reifies s W, KnownNat m, KnownNat n)     => SV.Vector n (BVar s (H.R m))     -> BVar s (H.L m n)-fromColumns = liftOp1 (opIso H.colsL H.lCols) . collectVar+fromColumns = isoVar H.colsL H.lCols . collectVar {-# INLINE fromColumns #-}  konst@@ -1142,9 +1151,10 @@     :: forall t s d q. (Reifies q W, H.Sized t s d, Num s, Num (d t))     => BVar q (d t)     -> Maybe (BVar q s)-create = fmap (unANum . sequenceVar) . liftOp1 $-    opIso (ANum              . H.create)-          (maybe 0 H.extract . unANum  )+create = unANum+       . sequenceVar+       . isoVar (ANum              . H.create)+                (maybe 0 H.extract . unANum  ) {-# INLINE create #-}  @@ -1198,7 +1208,7 @@     :: (Reifies s W, KnownNat n)     => BVar s (H.Sym n)     -> BVar s (H.Sq n)-unSym = liftOp1 (opIso H.unSym unsafeCoerce)+unSym = isoVar H.unSym unsafeCoerce {-# INLINE unSym #-}  -- | Unicode synonym for '<.>>'