Copyright | (c) Justin Le 2023 |
---|---|
License | BSD3 |
Maintainer | justin@jle.im |
Stability | experimental |
Portability | non-portable |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
Automatic differentation and backpropagation.
Main idea: Write a function computing what you want, and the library automatically provies the gradient of that function as well, for usage with gradient descent and other training methods.
See the homepage for an introduction and walkthrough.
In more detail: instead of working directly with values to produce your
result, you work with BVar
s containing those values. Working with
these BVar
s is made smooth with the usage of lenses and other
combinators, and libraries can offer operatons on BVar
s instead of
those on normal types directly.
Then, you can use:
evalBP
:: (forall s.Reifies
sW
=>BVar
s a -> BVar s b) -> (a -> b)
to turn a BVar
function into the function on actual values a -> b
.
This has virtually zero overhead over writing the actual function
directly.
Then, there's:
gradBP
:: (forall s.Reifies
sW
=>BVar
s a -> BVar s b) -> (a -> a)
to automatically get the gradient, as well, for a given input.
Refer to the homepage for more information and
links to demonstrations and tutorials, or dive striaght in by reading
the docs for BVar
.
If you are writing a library, see https://backprop.jle.im/08-equipping-your-library.html for a guide for equipping your library with backpropatable operations.
In the original version 0.1, this module required Num
instances for
methods instead of Backprop
instances. This interface is still
available in Numeric.Backprop.Num, which has the same API as this
module, except with Num
constraints on all values instead of
Backprop
constraints.
See Prelude.Backprop.Explicit for a version allowing you to provide
zero
, add
, and one
explicitly, which can be useful when attempting
to avoid orphan instances or when mixing both Backprop
and Num
styles.
Synopsis
- data BVar s a
- data W
- class Backprop a where
- newtype ABP f a = ABP {
- runABP :: f a
- newtype NumBP a = NumBP {
- runNumBP :: a
- backprop :: (Backprop a, Backprop b) => (forall s. Reifies s W => BVar s a -> BVar s b) -> a -> (b, a)
- evalBP :: (forall s. Reifies s W => BVar s a -> BVar s b) -> a -> b
- gradBP :: (Backprop a, Backprop b) => (forall s. Reifies s W => BVar s a -> BVar s b) -> a -> a
- backpropWith :: Backprop a => (forall s. Reifies s W => BVar s a -> BVar s b) -> a -> (b, b -> a)
- backprop2 :: (Backprop a, Backprop b, Backprop c) => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) -> a -> b -> (c, (a, b))
- evalBP2 :: (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) -> a -> b -> c
- gradBP2 :: (Backprop a, Backprop b, Backprop c) => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) -> a -> b -> (a, b)
- backpropWith2 :: (Backprop a, Backprop b) => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) -> a -> b -> (c, c -> (a, b))
- backpropN :: (RPureConstrained Backprop as, Backprop b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, Rec Identity as)
- evalBPN :: forall as b. (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> b
- gradBPN :: (RPureConstrained Backprop as, Backprop b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> Rec Identity as
- backpropWithN :: RPureConstrained Backprop as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, b -> Rec Identity as)
- evalBP0 :: (forall s. Reifies s W => BVar s a) -> a
- constVar :: a -> BVar s a
- auto :: a -> BVar s a
- coerceVar :: Coercible a b => BVar s a -> BVar s b
- (^^.) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Lens' b a -> BVar s a
- (.~~) :: (Backprop a, Backprop b, Reifies s W) => Lens' b a -> BVar s a -> BVar s b -> BVar s b
- (%~~) :: (Backprop a, Backprop b, Reifies s W) => Lens' b a -> (BVar s a -> BVar s a) -> BVar s b -> BVar s b
- (^^?) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> Maybe (BVar s a)
- (^^..) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> [BVar s a]
- (^^?!) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> BVar s a
- viewVar :: forall b a s. (Backprop a, Backprop b, Reifies s W) => Lens' b a -> BVar s b -> BVar s a
- setVar :: (Backprop a, Backprop b, Reifies s W) => Lens' b a -> BVar s a -> BVar s b -> BVar s b
- overVar :: (Backprop a, Backprop b, Reifies s W) => Lens' b a -> (BVar s a -> BVar s a) -> BVar s b -> BVar s b
- sequenceVar :: (Traversable t, Backprop a, Reifies s W) => BVar s (t a) -> t (BVar s a)
- collectVar :: (Foldable t, Functor t, Backprop a, Reifies s W) => t (BVar s a) -> BVar s (t a)
- previewVar :: forall b a s. (Backprop b, Backprop a, Reifies s W) => Traversal' b a -> BVar s b -> Maybe (BVar s a)
- toListOfVar :: forall b a s. (Backprop b, Backprop a, Reifies s W) => Traversal' b a -> BVar s b -> [BVar s a]
- pattern T2 :: (Backprop a, Backprop b, Reifies s W) => BVar s a -> BVar s b -> BVar s (a, b)
- pattern T3 :: (Backprop a, Backprop b, Backprop c, Reifies s W) => BVar s a -> BVar s b -> BVar s c -> BVar s (a, b, c)
- isoVar :: (Backprop a, Reifies s W) => (a -> b) -> (b -> a) -> BVar s a -> BVar s b
- isoVar2 :: (Backprop a, Backprop b, Reifies s W) => (a -> b -> c) -> (c -> (a, b)) -> BVar s a -> BVar s b -> BVar s c
- isoVar3 :: (Backprop a, Backprop b, Backprop c, Reifies s W) => (a -> b -> c -> d) -> (d -> (a, b, c)) -> BVar s a -> BVar s b -> BVar s c -> BVar s d
- isoVarN :: (RPureConstrained Backprop as, Reifies s W) => (Rec Identity as -> b) -> (b -> Rec Identity as) -> Rec (BVar s) as -> BVar s b
- liftOp :: (RPureConstrained Backprop as, Reifies s W) => Op as b -> Rec (BVar s) as -> BVar s b
- liftOp1 :: (Backprop a, Reifies s W) => Op '[a] b -> BVar s a -> BVar s b
- liftOp2 :: (Backprop a, Backprop b, Reifies s W) => Op '[a, b] c -> BVar s a -> BVar s b -> BVar s c
- liftOp3 :: (Backprop a, Backprop b, Backprop c, Reifies s W) => Op '[a, b, c] d -> BVar s a -> BVar s b -> BVar s c -> BVar s d
- splitBV :: (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (z f), Backprop (Rep (z f) ()), RPureConstrained Backprop as, Reifies s W) => BVar s (z f) -> z (BVar s)
- joinBV :: (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (z f), Backprop (Rep (z f) ()), RPureConstrained Backprop as, Reifies s W) => z (BVar s) -> BVar s (z f)
- pattern BV :: (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (Rep (z f) ()), Backprop (z f), RPureConstrained Backprop as, RecApplicative as, Reifies s W) => z (BVar s) -> BVar s (z f)
- class BVGroup s as i o | o -> i, i -> as
- newtype Op as a = Op {}
- op0 :: a -> Op '[] a
- opConst :: forall as a. RPureConstrained Num as => a -> Op as a
- idOp :: Op '[a] a
- bpOp :: RPureConstrained Backprop as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Op as b
- op1 :: (a -> (b, b -> a)) -> Op '[a] b
- op2 :: (a -> b -> (c, c -> (a, b))) -> Op '[a, b] c
- op3 :: (a -> b -> c -> (d, d -> (a, b, c))) -> Op '[a, b, c] d
- opCoerce :: Coercible a b => Op '[a] b
- opTup :: Op as (Rec Identity as)
- opIso :: (a -> b) -> (b -> a) -> Op '[a] b
- opIsoN :: (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b
- opLens :: Num a => Lens' a b -> Op '[a] b
- noGrad1 :: (a -> b) -> Op '[a] b
- noGrad :: (Rec Identity as -> b) -> Op as b
- class Reifies (s :: k) a | s -> a
Types
A
is a value of type BVar
s aa
that can be "backpropagated".
Functions referring to BVar
s are tracked by the library and can be
automatically differentiated to get their gradients and results.
For simple numeric values, you can use its Num
, Fractional
, and
Floating
instances to manipulate them as if they were the numbers they
represent.
If a
contains items, the items can be accessed and extracted using
lenses. A
can be used to access an Lens'
b aa
inside a b
, using
^^.
(viewVar
):
(^.
) :: a ->Lens'
a b -> b (^^.
) ::BVar
s a ->Lens'
a b ->BVar
s b
There is also ^^?
(previewVar
), to use a Prism'
or Traversal'
to extract a target that may or may not be present
(which can implement pattern matching), ^^..
(toListOfVar
) to use a Traversal'
to extract all
targets inside a BVar
, and .~~
(setVar
) to set and update values
inside a BVar
.
If you have control over your data type definitions, you can also use
splitBV
and joinBV
to manipulate
data types by easily extracting fields out of a BVar
of data types and
creating BVar
s of data types out of BVar
s of their fields. See
Numeric.Backprop for a tutorial on this use pattern.
For more complex operations, libraries can provide functions on BVar
s
using liftOp
and related functions. This is how you
can create primitive functions that users can use to manipulate your
library's values. See
https://backprop.jle.im/08-equipping-your-library.html for a detailed
guide.
For example, the hmatrix library has a matrix-vector multiplication
function, #> :: L m n -> R n -> L m
.
A library could instead provide a function #> ::
, which the user can then use to manipulate their
BVar
(L m n) -> BVar
(R n) -> BVar (R m)BVar
s of L m n
s and R n
s, etc.
See Numeric.Backprop and documentation for
liftOp
for more information.
Instances
IsoHKD (BVar s :: Type -> Type) (a :: Type) Source # | Since: 0.2.6.3 |
BVGroup s ('[] :: [Type]) (K1 i a :: Type -> Type) (K1 i (BVar s a) :: Type -> Type) Source # | |
(Backprop a, Reifies s W) => Backprop (BVar s a) Source # | Since: 0.2.2.0 |
(Floating a, Reifies s W) => Floating (BVar s a) Source # | |
Defined in Numeric.Backprop.Internal sqrt :: BVar s a -> BVar s a # (**) :: BVar s a -> BVar s a -> BVar s a # logBase :: BVar s a -> BVar s a -> BVar s a # asin :: BVar s a -> BVar s a # acos :: BVar s a -> BVar s a # atan :: BVar s a -> BVar s a # sinh :: BVar s a -> BVar s a # cosh :: BVar s a -> BVar s a # tanh :: BVar s a -> BVar s a # asinh :: BVar s a -> BVar s a # acosh :: BVar s a -> BVar s a # atanh :: BVar s a -> BVar s a # log1p :: BVar s a -> BVar s a # expm1 :: BVar s a -> BVar s a # | |
(Num a, Reifies s W) => Num (BVar s a) Source # | |
(Fractional a, Reifies s W) => Fractional (BVar s a) Source # | |
NFData a => NFData (BVar s a) Source # | This will force the value inside, as well. |
Defined in Numeric.Backprop.Internal | |
Eq a => Eq (BVar s a) Source # | Compares the values inside the Since: 0.1.5.0 |
Ord a => Ord (BVar s a) Source # | Compares the values inside the Since: 0.1.5.0 |
Defined in Numeric.Backprop.Internal | |
type HKD (BVar s :: Type -> Type) (a :: Type) Source # | |
class Backprop a where Source #
Class of values that can be backpropagated in general.
For instances of Num
, these methods can be given by zeroNum
,
addNum
, and oneNum
. There are also generic options given in
Numeric.Backprop.Class for functors, IsList
instances, and Generic
instances.
instanceBackprop
Double
wherezero
=zeroNum
add
=addNum
one
=oneNum
If you leave the body of an instance declaration blank, GHC Generics
will be used to derive instances if the type has a single constructor
and each field is an instance of Backprop
.
To ensure that backpropagation works in a sound way, should obey the laws:
- identity
Also implies preservation of information, making
an
illegal implementation for lists and vectors.zipWith
(+
)
This is only expected to be true up to potential "extra zeroes" in x
and y
in the result.
- commutativity
- associativity
- idempotence
- unital
Note that not all values in the backpropagation process needs all of
these methods: Only the "final result" needs one
, for example. These
are all grouped under one typeclass for convenience in defining
instances, and also to talk about sensible laws. For fine-grained
control, use the "explicit" versions of library functions (for example,
in Numeric.Backprop.Explicit) instead of Backprop
based ones.
This typeclass replaces the reliance on Num
of the previous API
(v0.1). Num
is strictly more powerful than Backprop
, and is
a stronger constraint on types than is necessary for proper
backpropagating. In particular, fromInteger
is a problem for many
types, preventing useful backpropagation for lists, variable-length
vectors (like Data.Vector) and variable-size matrices from linear
algebra libraries like hmatrix and accelerate.
Since: 0.2.0.0
Nothing
"Zero out" all components of a value. For scalar values, this
should just be
. For vectors and matrices, this should
set all components to zero, the additive identity.const
0
Should be idempotent:
Should be as lazy as possible. This behavior is observed for all instances provided by this library.
See zeroNum
for a pre-built definition for instances of Num
and
zeroFunctor
for a definition for instances of Functor
. If left
blank, will automatically be genericZero
, a pre-built definition
for instances of Generic
whose fields are all themselves
instances of Backprop
.
Add together two values of a type. To combine contributions of gradients, so should be information-preserving:
Should be as strict as possible. This behavior is observed for all instances provided by this library.
See addNum
for a pre-built definition for instances of Num
and
addIsList
for a definition for instances of IsList
. If left
blank, will automatically be genericAdd
, a pre-built definition
for instances of Generic
with one constructor whose fields are
all themselves instances of Backprop
.
One all components of a value. For scalar values, this should
just be
. For vectors and matrices, this should set all
components to one, the multiplicative identity.const
1
As the library uses it, the most important law is:
That is,
is the gradient of the identity function with
respect to its input.one
x
Ideally should be idempotent:
Should be as lazy as possible. This behavior is observed for all instances provided by this library.
See oneNum
for a pre-built definition for instances of Num
and
oneFunctor
for a definition for instances of Functor
. If left
blank, will automatically be genericOne
, a pre-built definition
for instances of Generic
whose fields are all themselves
instances of Backprop
.
Instances
Backprop Void Source # | |
Backprop Word16 Source # | Since: 0.2.2.0 |
Backprop Word32 Source # | Since: 0.2.2.0 |
Backprop Word64 Source # | Since: 0.2.2.0 |
Backprop Word8 Source # | Since: 0.2.2.0 |
Backprop Integer Source # | |
Backprop Natural Source # | Since: 0.2.1.0 |
Backprop () Source # |
|
Backprop Double Source # | |
Backprop Float Source # | |
Backprop Int Source # | |
Backprop Word Source # | Since: 0.2.2.0 |
Num a => Backprop (NumBP a) Source # | |
RealFloat a => Backprop (Complex a) Source # | |
Backprop a => Backprop (Identity a) Source # | |
Backprop a => Backprop (First a) Source # | Since: 0.2.2.0 |
Backprop a => Backprop (Last a) Source # | Since: 0.2.2.0 |
Backprop a => Backprop (First a) Source # | Since: 0.2.2.0 |
Backprop a => Backprop (Last a) Source # | Since: 0.2.2.0 |
Backprop a => Backprop (Dual a) Source # | Since: 0.2.2.0 |
Backprop a => Backprop (Product a) Source # | Since: 0.2.2.0 |
Backprop a => Backprop (Sum a) Source # | Since: 0.2.2.0 |
Integral a => Backprop (Ratio a) Source # | |
Backprop a => Backprop (IntMap a) Source # |
|
Backprop a => Backprop (Seq a) Source # |
|
Backprop a => Backprop (Vector a) Source # | |
(Prim a, Backprop a) => Backprop (Vector a) Source # | |
(Storable a, Backprop a) => Backprop (Vector a) Source # | |
(Unbox a, Backprop a) => Backprop (Vector a) Source # | |
Backprop (Label field) Source # | Since: 0.2.6.3 |
Backprop t => Backprop (ElField '(s, t)) Source # | Since: 0.2.6.3 |
Backprop a => Backprop (Identity a) Source # | Since: 0.2.6.3 |
Backprop a => Backprop (Thunk a) Source # | Since: 0.2.6.3 |
Backprop a => Backprop (NonEmpty a) Source # |
|
Backprop a => Backprop (Maybe a) Source # |
|
Backprop a => Backprop [a] Source # |
|
(Applicative f, Backprop a) => Backprop (ABP f a) Source # | |
(Vector v a, Num a) => Backprop (NumVec v a) Source # | |
(Backprop a, Reifies s W) => Backprop (BVar s a) Source # | Since: 0.2.2.0 |
Backprop (Proxy a) Source # | |
(Backprop a, Backprop b) => Backprop (Arg a b) Source # | Since: 0.2.2.0 |
Backprop (U1 p) Source # | Since: 0.2.2.0 |
Backprop (V1 p) Source # | Since: 0.2.2.0 |
(Backprop a, Ord k) => Backprop (Map k a) Source # |
|
Backprop (SField field) Source # | Since: 0.2.6.3 |
Backprop a => Backprop (r -> a) Source # |
Since: 0.2.2.0 |
(Backprop a, Backprop b) => Backprop (a, b) Source # |
|
(Backprop a, Applicative m) => Backprop (Kleisli m r a) Source # | Since: 0.2.2.0 |
Backprop w => Backprop (Const w a) Source # | Since: 0.2.2.0 |
(ReifyConstraint Backprop f rs, RMap rs, RApply rs, RecApplicative rs, NatToInt (RLength rs), RPureConstrained (IndexableField rs) rs, ToARec rs) => Backprop (ARec f rs) Source # | Since: 0.2.6.3 |
(ReifyConstraint Backprop f rs, RMap rs, RApply rs) => Backprop (Rec f rs) Source # | Since: 0.2.6.3 |
Backprop w => Backprop (Const w a) Source # | Since: 0.2.6.3 |
(ReifyConstraint Backprop f rs, RMap rs, RApply rs, Storable (Rec f rs)) => Backprop (SRec f rs) Source # | Since: 0.2.6.3 |
Backprop (HKD t a) => Backprop (XData t a) Source # | Since: 0.2.6.3 |
(ReifyConstraint Backprop f rs, RMap rs, RApply rs, IsoXRec f rs) => Backprop (XRec f rs) Source # | Since: 0.2.6.3 |
(Backprop a, Backprop b, Backprop c) => Backprop (a, b, c) Source # |
|
(Backprop (f a), Backprop (g a)) => Backprop (Product f g a) Source # | Since: 0.2.2.0 |
(Backprop (f p), Backprop (g p)) => Backprop ((f :*: g) p) Source # | Since: 0.2.2.0 |
Backprop a => Backprop (K1 i a p) Source # | Since: 0.2.2.0 |
(Backprop a, Backprop b, Backprop c, Backprop d) => Backprop (a, b, c, d) Source # |
|
Backprop (f (g a)) => Backprop (Compose f g a) Source # | Since: 0.2.2.0 |
Backprop (f (g a)) => Backprop ((f :.: g) a) Source # | Since: 0.2.6.3 |
Backprop (f p) => Backprop (M1 i c f p) Source # | Since: 0.2.2.0 |
Backprop (f (g a)) => Backprop (Compose f g a) Source # | Since: 0.2.6.3 |
(Backprop a, Backprop b, Backprop c, Backprop d, Backprop e) => Backprop (a, b, c, d, e) Source # |
|
Backprop (op (f a) (g a)) => Backprop (Lift op f g a) Source # | Since: 0.2.6.3 |
A newtype wrapper over an f a
for
that gives
a free Applicative
fBackprop
instance (as well as Num
etc. instances).
Useful for performing backpropagation over functions that require some
monadic context (like IO
) to perform.
Since: 0.2.1.0
Instances
Foldable f => Foldable (ABP f) Source # | |
Defined in Numeric.Backprop.Class fold :: Monoid m => ABP f m -> m # foldMap :: Monoid m => (a -> m) -> ABP f a -> m # foldMap' :: Monoid m => (a -> m) -> ABP f a -> m # foldr :: (a -> b -> b) -> b -> ABP f a -> b # foldr' :: (a -> b -> b) -> b -> ABP f a -> b # foldl :: (b -> a -> b) -> b -> ABP f a -> b # foldl' :: (b -> a -> b) -> b -> ABP f a -> b # foldr1 :: (a -> a -> a) -> ABP f a -> a # foldl1 :: (a -> a -> a) -> ABP f a -> a # elem :: Eq a => a -> ABP f a -> Bool # maximum :: Ord a => ABP f a -> a # minimum :: Ord a => ABP f a -> a # | |
Traversable f => Traversable (ABP f) Source # | |
Alternative f => Alternative (ABP f) Source # | |
Applicative f => Applicative (ABP f) Source # | |
Functor f => Functor (ABP f) Source # | |
Monad f => Monad (ABP f) Source # | |
MonadPlus f => MonadPlus (ABP f) Source # | |
(Applicative f, Backprop a) => Backprop (ABP f a) Source # | |
(Typeable f, Typeable a, Data (f a)) => Data (ABP f a) Source # | |
Defined in Numeric.Backprop.Class gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> ABP f a -> c (ABP f a) # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (ABP f a) # toConstr :: ABP f a -> Constr # dataTypeOf :: ABP f a -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (ABP f a)) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (ABP f a)) # gmapT :: (forall b. Data b => b -> b) -> ABP f a -> ABP f a # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> ABP f a -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> ABP f a -> r # gmapQ :: (forall d. Data d => d -> u) -> ABP f a -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> ABP f a -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> ABP f a -> m (ABP f a) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> ABP f a -> m (ABP f a) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> ABP f a -> m (ABP f a) # | |
(Applicative f, Floating a) => Floating (ABP f a) Source # | |
Generic (ABP f a) Source # | |
(Applicative f, Num a) => Num (ABP f a) Source # | |
Read (f a) => Read (ABP f a) Source # | |
(Applicative f, Fractional a) => Fractional (ABP f a) Source # | |
Show (f a) => Show (ABP f a) Source # | |
NFData (f a) => NFData (ABP f a) Source # | |
Defined in Numeric.Backprop.Class | |
Eq (f a) => Eq (ABP f a) Source # | |
Ord (f a) => Ord (ABP f a) Source # | |
type Rep (ABP f a) Source # | |
Defined in Numeric.Backprop.Class |
A newtype wrapper over an instance of Num
that gives a free
Backprop
instance.
Useful for things like DerivingVia, or for avoiding orphan instances.
Since: 0.2.1.0
Instances
Foldable NumBP Source # | |
Defined in Numeric.Backprop.Class fold :: Monoid m => NumBP m -> m # foldMap :: Monoid m => (a -> m) -> NumBP a -> m # foldMap' :: Monoid m => (a -> m) -> NumBP a -> m # foldr :: (a -> b -> b) -> b -> NumBP a -> b # foldr' :: (a -> b -> b) -> b -> NumBP a -> b # foldl :: (b -> a -> b) -> b -> NumBP a -> b # foldl' :: (b -> a -> b) -> b -> NumBP a -> b # foldr1 :: (a -> a -> a) -> NumBP a -> a # foldl1 :: (a -> a -> a) -> NumBP a -> a # elem :: Eq a => a -> NumBP a -> Bool # maximum :: Ord a => NumBP a -> a # minimum :: Ord a => NumBP a -> a # | |
Traversable NumBP Source # | |
Applicative NumBP Source # | |
Functor NumBP Source # | |
Monad NumBP Source # | |
Num a => Backprop (NumBP a) Source # | |
Data a => Data (NumBP a) Source # | |
Defined in Numeric.Backprop.Class gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> NumBP a -> c (NumBP a) # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (NumBP a) # toConstr :: NumBP a -> Constr # dataTypeOf :: NumBP a -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (NumBP a)) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (NumBP a)) # gmapT :: (forall b. Data b => b -> b) -> NumBP a -> NumBP a # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> NumBP a -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> NumBP a -> r # gmapQ :: (forall d. Data d => d -> u) -> NumBP a -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> NumBP a -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> NumBP a -> m (NumBP a) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> NumBP a -> m (NumBP a) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> NumBP a -> m (NumBP a) # | |
Floating a => Floating (NumBP a) Source # | |
Generic (NumBP a) Source # | |
Num a => Num (NumBP a) Source # | |
Read a => Read (NumBP a) Source # | |
Fractional a => Fractional (NumBP a) Source # | |
Show a => Show (NumBP a) Source # | |
NFData a => NFData (NumBP a) Source # | |
Defined in Numeric.Backprop.Class | |
Eq a => Eq (NumBP a) Source # | |
Ord a => Ord (NumBP a) Source # | |
type Rep (NumBP a) Source # | |
Defined in Numeric.Backprop.Class |
Running
backprop :: (Backprop a, Backprop b) => (forall s. Reifies s W => BVar s a -> BVar s b) -> a -> (b, a) Source #
Turn a function
into the function BVar
s a -> BVar
s ba -> b
that it represents, also computing its gradient a
as well.
The Rank-N type forall s.
is used to ensure
that Reifies
s W
=> ...BVar
s do not leak out of the context (similar to how it is used
in Control.Monad.ST), and also as a reference to an ephemeral Wengert
tape used to track the graph of references.
gradBP :: (Backprop a, Backprop b) => (forall s. Reifies s W => BVar s a -> BVar s b) -> a -> a Source #
Take a function
, interpreted as a function
BVar
s a -> BVar
s ba -> b
, and compute its gradient with respect to its input.
The resulting a -> a
tells how the input (and its components) affects
the output. Positive numbers indicate that the result will vary in the
same direction as any adjustment in the input. Negative numbers
indicate that the result will vary in the opposite direction as any
adjustment in the input. Larger numbers indicate a greater sensitivity
of change, and small numbers indicate lower sensitivity.
See documentation of backprop
for more information.
If you want to provide an explicit "final gradient" for the end, see
backpropWith
.
backpropWith :: Backprop a => (forall s. Reifies s W => BVar s a -> BVar s b) -> a -> (b, b -> a) Source #
A version of backprop
that allows you to specify the gradent of your
"final result" in with respect to the output of your function.
Typically, this is just the scalar 1, or a value of components that are all 1.
Instead of taking the b
gradient, the you may provide a b -> b
,
which backpropWith
calls with the result of your function as the
argument. This allows you to return something with the correct "shape",
if not a scalar.
backprop
is essentially backpropWith
with
for scalars
and const
1Num
instances.
Note that argument order changed in v0.2.4
Since: 0.2.0.0
Multiple inputs
backprop2 :: (Backprop a, Backprop b, Backprop c) => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) -> a -> b -> (c, (a, b)) Source #
gradBP2 :: (Backprop a, Backprop b, Backprop c) => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) -> a -> b -> (a, b) Source #
backpropWith2 :: (Backprop a, Backprop b) => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) -> a -> b -> (c, c -> (a, b)) Source #
backprop2
, but allows you to provide the gradient of the "final
result" with respect to the output of your function. See backpropWith
for more details.
Note that argument order changed in v0.2.4
Since: 0.2.0.0
backpropN :: (RPureConstrained Backprop as, Backprop b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, Rec Identity as) Source #
backprop
generalized to multiple inputs of different types. See the
Numeric.Backprop.Op for a mini-tutorial on heterogeneous lists.
Not strictly necessary, because you can always uncurry a function by passing in all of the inputs in a data type containing all of the arguments or a giant tuple. However, this could potentially also be more performant.
A
, for instance, is a tuple
of Rec
(BVar
s) '[Double, Float, Double]
, BVar
s Double
, and BVar
s Float
, and
can be pattern matched on using BVar
s Double
:<
(cons) and Ø
(nil).
The
in the constraint says that every
value in the type-level list RPureConstrained
Backprop
asas
must have a Backprop
instance. This
means you can use, say, '[Double, Float, Int]
, but not '[Double,
Bool, String]
.
If you stick to concerete, monomorphic usage of this (with specific
types, typed into source code, known at compile-time), then
should be fulfilled automatically.RPureConstrained
Backprop
as
evalBPN :: forall as b. (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> b Source #
evalBP
generalized to multiple inputs of different types. See
documentation for backpropN
for more details.
gradBPN :: (RPureConstrained Backprop as, Backprop b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> Rec Identity as Source #
backpropWithN :: RPureConstrained Backprop as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, b -> Rec Identity as) Source #
backpropN
, but allows you to provide the gradient of the "final
result" with respect to the output of your function. See backpropWith
for more details.
Note that argument order changed in v0.2.4.
Since: 0.2.0.0
Manipulating BVar
constVar :: a -> BVar s a Source #
Lift a value into a BVar
representing a constant value.
This value will not be considered an input, and its gradients will not be backpropagated.
coerceVar :: Coercible a b => BVar s a -> BVar s b Source #
Coerce a BVar
contents. Useful for things like newtype wrappers.
Since: 0.1.5.2
(^^.) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Lens' b a -> BVar s a infixl 8 Source #
An infix version of viewVar
, meant to evoke parallels to ^.
from
lens.
With normal values, you can extract something from that value with a lens:
x ^.
myLens
would extract a piece of x :: b
, specified by myLens ::
.
The result has type Lens'
b aa
.
xVar ^^.
myLens
would extract a piece out of xVar ::
(a BVar
s bBVar
holding a
b
), specified by myLens :: Lens' b a
. The result has type
(a BVar
s aBVar
holding a a
)
This is the main way to pull out values from BVar
of container types.
If you have control of your data type definitions, consider using
splitBV
, which lets you break out BVar
s of values into BVar
s of
their individual fields automatically without requiring lenses.
NOTE: Usage of ^^.
on many fields from the same item is usually
the main source of overhead in backprop code, if you are looking to
optimize your code. See <https://backprop.jle.im/07-performance.html
this performance guide> for more information, and details on mitigating
this overhead.
WARNING: Do not use with any lenses that operate "numerically" on
the contents (like multiplying
).
(.~~) :: (Backprop a, Backprop b, Reifies s W) => Lens' b a -> BVar s a -> BVar s b -> BVar s b infixl 8 Source #
An infix version of setVar
, meant to evoke parallels to .~
from
lens.
With normal values, you can set something in a value with a lens:
x&
myLens.~
y
would "set" a part of x :: b
, specified by myLens ::
, to
a new value Lens'
a by :: a
.
xVar&
myLens.~~
yVar
would "set" a part of xVar ::
(a BVar
s bBVar
holding a b
),
specified by myLens ::
, to a new value given by Lens'
a byVar ::
. The result is a new (updated) value of type BVar
s a
.BVar
s b
This is the main way to set values inside BVar
s of container types.
Note that this does not incurr the performance overhead issues of
viewVar
and ^^.
, and is fairly cheap.
(%~~) :: (Backprop a, Backprop b, Reifies s W) => Lens' b a -> (BVar s a -> BVar s a) -> BVar s b -> BVar s b infixr 4 Source #
An infix version of overVar
, meant to evoke parallels to %~
from
lens.
With normal values, you can set modify in a value with a lens:
x&
myLens%~
negate
would "modify" a part of x :: b
, specified by myLens ::
,
using the function Lens'
a bnegate :: a -> a
.
xVar&
myLens%~~
negate
would "modify" a part of xVar ::
(a BVar
s bBVar
holding a b
),
specified by myLens ::
, using the function Lens'
a bnegate :: BVar
s a -> BVar s
. The result is a new (updated) value of type
.BVar
s b
Is essentially a convenient wrapper over a viewVar
followed by
a setVar
.
Since: 0.2.4.0
(^^?) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> Maybe (BVar s a) infixl 8 Source #
An infix version of previewVar
, meant to evoke parallels to ^?
from lens.
With normal values, you can (potentially) extract something from that value with a lens:
x ^?
myPrism
would (potentially) extract a piece of x :: b
, specified by
myPrism ::
. The result has type Traversal'
b a
.Maybe
a
xVar ^^?
myPrism
would (potentially) extract a piece out of xVar ::
(a
BVar
s bBVar
holding a b
), specified by myPrism :: Prism' b a
.
The result has type
(Maybe
(BVar
s a)Maybe
a BVar
holding
a a
).
This is intended to be used with Prism'
s (which hits at most one
target), but will actually work with any Traversal'
. If the
traversal hits more than one target, the first one found will be
extracted.
This can be used to "pattern match" on BVar
s, by using prisms on
constructors.
NOTE: Has the same potential of performance overhead issues as
^^.
; see documentation of ^^.
for more details.
(^^..) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> [BVar s a] Source #
An infix version of toListOfVar
, meant to evoke parallels to ^..
from lens.
With normal values, you can extract all targets of a Traversal
from
that value with a:
x ^..
myTraversal
would extract all targets inside of x :: b
, specified by myTraversal
::
. The result has type Traversal'
b a[a]
.
xVar ^^..
myTraversal
would extract all targets inside of xVar ::
(a BVar
s bBVar
holding a b
), specified by myTraversal :: Traversal' b a
. The result
has type [
(A list of BVar
s a]BVar
s holding a
s).
NOTE: Has all of the performance overhead issues of sequenceVar
;
see documentation for sequenceVar
for more information.
(^^?!) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> BVar s a infixl 8 Source #
viewVar :: forall b a s. (Backprop a, Backprop b, Reifies s W) => Lens' b a -> BVar s b -> BVar s a Source #
setVar :: (Backprop a, Backprop b, Reifies s W) => Lens' b a -> BVar s a -> BVar s b -> BVar s b Source #
overVar :: (Backprop a, Backprop b, Reifies s W) => Lens' b a -> (BVar s a -> BVar s a) -> BVar s b -> BVar s b Source #
sequenceVar :: (Traversable t, Backprop a, Reifies s W) => BVar s (t a) -> t (BVar s a) Source #
Extract all of the BVar
s out of a Traversable
container of
BVar
s.
Note that this associates gradients in order of occurrence in the
original data structure; the second item in the gradient is assumed to
correspond with the second item in the input, etc.; this can cause
unexpected behavior in Foldable
instances that don't have a fixed
number of items.
NOTE: A potential source of performance overhead. If there are
\(n\) total elements, and you use \(m\) of them, then there is an
overhead cost on the order of \(\mathcal{O}(m n)\), with a constant
factor dependent on the cost of add
. Should be negligible for types
with cheap add
(like Double
), but may be costly for things like
large matrices. See <https://backprop.jle.im/07-performance.html the
performance guide> for for details.
collectVar :: (Foldable t, Functor t, Backprop a, Reifies s W) => t (BVar s a) -> BVar s (t a) Source #
Collect all of the BVar
s in a container into a BVar
of that
container's contents.
Note that this associates gradients in order of occurrence in the
original data structure; the second item in the total derivative and
gradient is assumed to correspond with the second item in the input,
etc.; this can cause unexpected behavior in Foldable
instances that
don't have a fixed number of items.
Note that this does not suffer from the same performance overhead
issues as sequenceVar
. collectVar
is \(\mathcal{O}(n)\), with
a very small constant factor that consistent for all types. This
reveals a general property of reverse-mode automatic differentiation;
"many to one" is cheap, but "one to many" is expensive.
previewVar :: forall b a s. (Backprop b, Backprop a, Reifies s W) => Traversal' b a -> BVar s b -> Maybe (BVar s a) Source #
Using a Traversal'
, extract a single value inside a BVar
, if it
exists. If more than one traversal target exists, returns te first.
Meant to evoke parallels to preview
from lens. Really only intended
to be used wth Prism'
s, or up-to-one target traversals.
See documentation for ^^?
for more information, warnings, and caveats.
toListOfVar :: forall b a s. (Backprop b, Backprop a, Reifies s W) => Traversal' b a -> BVar s b -> [BVar s a] Source #
Using a Traversal'
, extract all targeted values inside a BVar
.
Meant to evoke parallels to toListOf
from lens.
See documentation for ^^..
for more information, warnings, and
caveats.
pattern T2 :: (Backprop a, Backprop b, Reifies s W) => BVar s a -> BVar s b -> BVar s (a, b) Source #
Useful pattern for constructing and deconstructing BVar
s of
two-tuples.
Since: 0.2.1.0
pattern T3 :: (Backprop a, Backprop b, Backprop c, Reifies s W) => BVar s a -> BVar s b -> BVar s c -> BVar s (a, b, c) Source #
Useful pattern for constructing and deconstructing BVar
s
three-tuples.
Since: 0.2.1.0
With Isomorphisms
isoVar :: (Backprop a, Reifies s W) => (a -> b) -> (b -> a) -> BVar s a -> BVar s b Source #
Convert the value inside a BVar
using a given isomorphism. Useful
for things like constructors.
If you have control of your data type definitions, consider using
joinBV
, which lets you use your data type constructors themselves to
join together BVar
s as their fields.
Warning: This is unsafe! It assumes that the isomorphisms themselves
have derivative 1, so will break for things like exp
& log
.
Basically, don't use this for any "numeric" isomorphisms.
Since: 0.1.4.0
isoVar2 :: (Backprop a, Backprop b, Reifies s W) => (a -> b -> c) -> (c -> (a, b)) -> BVar s a -> BVar s b -> BVar s c Source #
Convert the values inside two BVar
s using a given isomorphism.
Useful for things like constructors. See isoVar
for caveats.
If you have control of your data type definitions, consider using
joinBV
, which lets you use your data type constructors themselves to
join together BVar
s as their fields.
Since: 0.1.4.0
isoVar3 :: (Backprop a, Backprop b, Backprop c, Reifies s W) => (a -> b -> c -> d) -> (d -> (a, b, c)) -> BVar s a -> BVar s b -> BVar s c -> BVar s d Source #
isoVarN :: (RPureConstrained Backprop as, Reifies s W) => (Rec Identity as -> b) -> (b -> Rec Identity as) -> Rec (BVar s) as -> BVar s b Source #
Convert the values inside a tuple of BVar
s using a given
isomorphism. Useful for things like constructors. See isoVar
for
caveats.
If you have control of your data type definitions, consider using
joinBV
, which lets you use your data type constructors themselves to
join together BVar
s as their fields.
Since: 0.1.4.0
With Op
s
This library provides a few primitive actions for manipulating BVar
s
and the values inside them, including its Num
, Fractional
, and
Floating
instances, and lens-based operations like ^^.
, .~~
^^?
,
and ^^..
.
However, the power of this library comes from manipulating many
different types from libraries, like matrices and vectors. Libraries
can provide their own
functions, alongside
(or in lieu of) BVar
s a -> BVar
s ba -> b
functions for their types.
The easiest way to create a BVar
function is to use liftOp
with an
Op
constructor. For example, imagine a vector library providing a dot
product function. We can write this using liftOp2
and op2
:
dot ::BVar
s Vec -> BVar s Vec -> BVar s Double dot =liftOp2
. op2 $ \xs ys -> ( sum (zipWith (*) xs ys) , \g -> (map (*g) ys, map (*g) xs) )
We provide a function that, given the two inputs, returns:
- The result of the function on those two inputs
- A function taking the "total derivative", and returning the gradient with respect to each of the inputs.
See documentation in Numeric.Backprop.Op for more information on the second part (the gradient).
Nice Op
s are how backprop links together BVar
s and tracks them to
determine their gradient. Ideally, users would never have to deal with
these when backpropagating their own functions, and library authors
providing their matrix and vector operations, etc. would provide BVar
variants of their normal operations.
In fact, BVar
operations could even be defined instead of normal
operations, since it is easy to go from
to BVar
s a -> BVar
s ba
-> b
, using evalBP
, and this carries virtually zero overhead, so some
libraries might even provide BVar
versions by default.
liftOp :: (RPureConstrained Backprop as, Reifies s W) => Op as b -> Rec (BVar s) as -> BVar s b Source #
Lift an Op
with an arbitrary number of inputs to a function on the
appropriate number of BVar
s.
Should preferably be used only by libraries to provide primitive BVar
functions for their types for users.
See Numeric.Backprop and documentation for liftOp
for more
information, and Numeric.Backprop.Op for a mini-tutorial on using
Rec
.
liftOp1 :: (Backprop a, Reifies s W) => Op '[a] b -> BVar s a -> BVar s b Source #
Lift an Op
with a single input to be a function on a single BVar
.
Should preferably be used only by libraries to provide primitive BVar
functions for their types for users.
See Numeric.Backprop and documentation for liftOp
for more
information.
liftOp2 :: (Backprop a, Backprop b, Reifies s W) => Op '[a, b] c -> BVar s a -> BVar s b -> BVar s c Source #
Lift an Op
with two inputs to be a function on a two BVar
s.
Should preferably be used only by libraries to provide primitive BVar
functions for their types for users.
See Numeric.Backprop and documentation for liftOp
for more
information.
liftOp3 :: (Backprop a, Backprop b, Backprop c, Reifies s W) => Op '[a, b, c] d -> BVar s a -> BVar s b -> BVar s c -> BVar s d Source #
Lift an Op
with three inputs to be a function on a three BVar
s.
Should preferably be used only by libraries to provide primitive BVar
functions for their types for users.
See Numeric.Backprop and documentation for liftOp
for more
information.
Generics
splitBV
and joinBV
let you split out a BVar
of a data type and
join together a data type of BVar
s using the "higher-kinded data type"
technique, a la
http://reasonablypolymorphic.com/blog/higher-kinded-data/.
It will let you take a data type like
data MyType = MT { mtX :: Double
, mtY :: [Double] }
-- | Automatic instance
instance Backprop MyType
And automatically let you turn a
into a BVar
s MyType
and BVar
s Double
BVar s [Double]
, without munging around with lenses
and viewVar
. It'll also let you take a BVar s Double
and a BVar
s [Double]
and turn it into a BVar s MyType
without messing around
with manually lifting ops or isoVar
.
To do this, rewrite MyType
to take a Functor
argument:
-- | Can be re-used for every data type you use this trick with type family HKD f a where HKDIdentity
a = a HKD f a = f a data MyType' f = MT { mtX :: HKD f Double, mtY :: HKD f [Double] } deriving Generic -- | This is the original data type, which can be used the same way as -- before type MyType = MyType'Identity
-- | Automatic instance instanceBackprop
MyType
Now, splitBV
can be used, with type:
splitBV
:: BVar s MyType -> MyType' (BVar s)
So you can use it lke:
myFunction ::BVar
s MyType -> BVar s Double myFunction (splitBV
-> MT x y) = x +sum
y
Or also, using the BV
pattern synonym:
myFunction ::BVar
s MyType -> BVar s Double myFunction (BV
(MT x y)) = x +sum
y
If you use splitBV
, the contents will be a BVar s Double
and a BVar
s [Double]
. It lets you "extract" the fields, because your MyType'
constructor now holds a
and a BVar
s DoubleBVar s [Double]
,
instead of just a normal Double
and [Double]
.
Note that access using splitBV
and pattern matching is slightly slower
than access using lenses (by about 10-20%).
With this trick, joinBV
can also be used, with the type:
joinBV
:: MyType' (BVar s) -> BVar s MyType
So you can take a bunch of BVar
s and turn them into a BVar
of
a MyType
:
myOtherFunction ::BVar
s Double -> BVar s [Double] -> BVar s MyType myOtherFunction x y =joinBV
$ MT x y
The BV
pattern synonym abstracts over manual application of splitBV
and joinBV
as a pattern.
This will work with all data types made with a single constructor, whose
fields are all instances of Backprop
, where the type itself has an
instance of Backprop
.
:: (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (z f), Backprop (Rep (z f) ()), RPureConstrained Backprop as, Reifies s W) | |
=> BVar s (z f) |
|
-> z (BVar s) |
|
Split out a BVar
of "higher-kinded data type", a la
http://reasonablypolymorphic.com/blog/higher-kinded-data/
Lets you take BVar
of a value into a separate BVar
of every field of
that value.
See Numeric.Backprop for a tutorial on usage.
This will work with all data types made with a single constructor, whose
fields are all instances of Backprop
, where the type itself has an
instance of Backprop
. The type also must derive Generic
.
Note that access using splitBV
and pattern matching is slightly slower
than access using lenses (by about 10-20%).
See also BV
, pattern synonym version where the deconstructor is
exactly a view into splitBV
.
NOTE: Like ^^.
and viewVar
, splitBV
usage could potentially be
the main source of performance overhead in your program. If your data
type has \(n\) fields, and you use splitBV
to later use \(m\) of those
fields, there is an overhead cost on the order of \(\mathcal{O}(m n)\),
with a constant factor dependent on the cost of add
for your original
data type. Should be negligible for types with cheap add
(like
Double
), but may be costly for things like large matrices. See
the performance guide for
for details.
However, there is some potential opportunities to re-write some core
library functionality that would allow splitBV
to avoid all of the
significant performance overhead issues of ^^.
. Contact me if you are
interested in helping out!
Since: 0.2.2.0
:: (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (z f), Backprop (Rep (z f) ()), RPureConstrained Backprop as, Reifies s W) | |
=> z (BVar s) |
|
-> BVar s (z f) |
|
Assemble a BVar
of "higher-kinded data type", a la
http://reasonablypolymorphic.com/blog/higher-kinded-data/
It lets you take a BVar
of every field of a value, and join them into
a BVar
of that value.
See Numeric.Backprop for a tutorial on usage.
This will work with all data types made with a single constructor, whose
fields are all instances of Backprop
, where the type itself has an
instance of Backprop
.
See also BV
, a pattern synonym version where the constructor is
exactly joinBV
.
Note that joinBV
does not suffer the major performance overhead issues
of splitBV
. This is a general property of reverse-mode automatic
differentiation: "many to one" is cheap, but "one to many" is expensive.
Since: 0.2.2.0
class BVGroup s as i o | o -> i, i -> as Source #
Helper class for generically "splitting" and "joining" BVar
s into
constructors. See splitBV
and
joinBV
.
See Numeric.Backprop for a tutorial on how to use this.
Instances should be available for types made with one constructor whose
fields are all instances of Backprop
, with a Generic
instance.
Since: 0.2.2.0
gsplitBV, gjoinBV
Instances
BVGroup s as i o => BVGroup s as (M1 p c i) (M1 p c o) Source # | |
BVGroup s ('[] :: [Type]) (U1 :: Type -> Type) (U1 :: Type -> Type) Source # | |
BVGroup s ('[] :: [Type]) (V1 :: Type -> Type) (V1 :: Type -> Type) Source # | |
BVGroup s ('[] :: [Type]) (K1 i a :: Type -> Type) (K1 i (BVar s a) :: Type -> Type) Source # | |
(Reifies s W, BVGroup s as i1 o1, BVGroup s bs i2 o2, cs ~ (as ++ bs), RecApplicative as) => BVGroup s (i1 () ': (i2 () ': cs)) (i1 :*: i2) (o1 :*: o2) Source # | |
Defined in Numeric.Backprop.Explicit | |
(Reifies s W, BVGroup s as i1 o1, BVGroup s bs i2 o2, cs ~ (as ++ bs), RecApplicative as) => BVGroup s (i1 () ': (i2 () ': cs)) (i1 :+: i2) (o1 :+: o2) Source # | This instance is possible but it is not clear when it would be useful |
Defined in Numeric.Backprop.Explicit |
Op
An
describes a differentiable function from Op
as aas
to a
.
For example, a value of type
Op
'[Int, Bool] Double
is a function from an Int
and a Bool
, returning a Double
. It can
be differentiated to give a gradient of an Int
and a Bool
if given
a total derivative for the Double
. If we call Bool
\(2\), then,
mathematically, it is akin to a:
\[ f : \mathbb{Z} \times 2 \rightarrow \mathbb{R} \]
See runOp
, gradOp
, and gradOpWith
for examples on how to run it,
and Op
for instructions on creating it.
It is simpler to not use this type constructor directly, and instead use
the op2
, op1
, op2
, and op3
helper smart constructors.
See Numeric.Backprop.Op for a mini-tutorial on using Rec
and
'Rec Identity'.
To use an Op
with the backprop library, see liftOp
, liftOp1
,
liftOp2
, and liftOp3
.
Op | Construct an See the module documentation for Numeric.Backprop.Op for more
details on the function that this constructor and |
Instances
(RPureConstrained Num as, Floating a) => Floating (Op as a) Source # | |
(RPureConstrained Num as, Num a) => Num (Op as a) Source # | |
(RPureConstrained Num as, Fractional a) => Fractional (Op as a) Source # | |
Creation
Create an Op
that takes no inputs and always returns the given
value.
There is no gradient, of course (using gradOp
will give you an empty
tuple), because there is no input to have a gradient of.
>>>
runOp (op0 10) RNil
(10, RNil)
For a constant Op
that takes input and ignores it, see opConst
and
opConst'
.
opConst :: forall as a. RPureConstrained Num as => a -> Op as a Source #
An Op
that ignores all of its inputs and returns a given constant
value.
>>>
gradOp' (opConst 10) (1 :& 2 :& 3 :& RNil)
(10, 0 :& 0 :& 0 :& RNil)
bpOp :: RPureConstrained Backprop as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Op as b Source #
Giving gradients directly
op1 :: (a -> (b, b -> a)) -> Op '[a] b Source #
Create an Op
of a function taking one input, by giving its explicit
derivative. The function should return a tuple containing the result of
the function, and also a function taking the derivative of the result
and return the derivative of the input.
If we have
\[ \eqalign{ f &: \mathbb{R} \rightarrow \mathbb{R}\cr y &= f(x)\cr z &= g(y) } \]
Then the derivative \( \frac{dz}{dx} \), it would be:
\[ \frac{dz}{dx} = \frac{dz}{dy} \frac{dy}{dx} \]
If our Op
represents \(f\), then the second item in the resulting
tuple should be a function that takes \(\frac{dz}{dy}\) and returns
\(\frac{dz}{dx}\).
As an example, here is an Op
that squares its input:
square :: Num a =>Op
'[a] a square =op1
$ \x -> (x*x, \d -> 2 * d * x )
Remember that, generally, end users shouldn't directly construct Op
s;
they should be provided by libraries or generated automatically.
op2 :: (a -> b -> (c, c -> (a, b))) -> Op '[a, b] c Source #
Create an Op
of a function taking two inputs, by giving its explicit
gradient. The function should return a tuple containing the result of
the function, and also a function taking the derivative of the result
and return the derivative of the input.
If we have
\[ \eqalign{ f &: \mathbb{R}^2 \rightarrow \mathbb{R}\cr z &= f(x, y)\cr k &= g(z) } \]
Then the gradient \( \left< \frac{\partial k}{\partial x}, \frac{\partial k}{\partial y} \right> \) would be:
\[ \left< \frac{\partial k}{\partial x}, \frac{\partial k}{\partial y} \right> = \left< \frac{dk}{dz} \frac{\partial z}{dx}, \frac{dk}{dz} \frac{\partial z}{dy} \right> \]
If our Op
represents \(f\), then the second item in the resulting
tuple should be a function that takes \(\frac{dk}{dz}\) and returns
\( \left< \frac{\partial k}{dx}, \frac{\partial k}{dx} \right> \).
As an example, here is an Op
that multiplies its inputs:
mul :: Num a =>Op
'[a, a] a mul =op2'
$ \x y -> (x*y, \d -> (d*y, x*d) )
Remember that, generally, end users shouldn't directly construct Op
s;
they should be provided by libraries or generated automatically.
From Isomorphisms
opTup :: Op as (Rec Identity as) Source #
An Op
that takes as
and returns exactly the input tuple.
>>>
gradOp' opTup (1 :& 2 :& 3 :& RNil)
(1 :& 2 :& 3 :& RNil, 1 :& 1 :& 1 :& RNil)
opIsoN :: (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b Source #
An Op
that runs the input value through an isomorphism between
a tuple of values and a value. See opIso
for caveats.
In Numeric.Backprop.Op since version 0.1.2.0, but only exported from Numeric.Backprop since version 0.1.3.0.
Since: 0.1.2.0
No gradients
noGrad1 :: (a -> b) -> Op '[a] b Source #
Create an Op
with no gradient. Can be evaluated with evalOp
, but
will throw a runtime exception when asked for the gradient.
Can be used with BVar
with liftOp1
, and evalBP
will work fine.
gradBP
and backprop
will also work fine if the result is never used
in the final answer, but will throw a runtime exception if the final
answer depends on the result of this operation.
Useful if your only API is exposed through backprop. Just be sure to tell your users that this will explode when finding the gradient if the result is used in the final result.
Since: 0.1.3.0
noGrad :: (Rec Identity as -> b) -> Op as b Source #
Create an Op
with no gradient. Can be evaluated with evalOp
, but
will throw a runtime exception when asked for the gradient.
Can be used with BVar
with liftOp
, and evalBP
will work fine.
gradBP
and backprop
will also work fine if the result is never used
in the final answer, but will throw a runtime exception if the final
answer depends on the result of this operation.
Useful if your only API is exposed through backprop. Just be sure to tell your users that this will explode when finding the gradient if the result is used in the final result.
Since: 0.1.3.0
Utility
class Reifies (s :: k) a | s -> a #
Instances
KnownNat n => Reifies (n :: Nat) Integer | |
Defined in Data.Reflection | |
KnownSymbol n => Reifies (n :: Symbol) String | |
Defined in Data.Reflection | |
Reifies Z Int | |
Defined in Data.Reflection | |
Reifies n Int => Reifies (D n :: Type) Int | |
Defined in Data.Reflection | |
Reifies n Int => Reifies (PD n :: Type) Int | |
Defined in Data.Reflection | |
Reifies n Int => Reifies (SD n :: Type) Int | |
Defined in Data.Reflection | |
(B b0, B b1, B b2, B b3, B b4, B b5, B b6, B b7, w0 ~ W b0 b1 b2 b3, w1 ~ W b4 b5 b6 b7) => Reifies (Stable w0 w1 a :: Type) a | |
Defined in Data.Reflection |