Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backpropagating through "stateful" operations. #16

Open
jh14778 opened this issue Aug 28, 2020 · 4 comments
Open

Backpropagating through "stateful" operations. #16

jh14778 opened this issue Aug 28, 2020 · 4 comments

Comments

@jh14778
Copy link

jh14778 commented Aug 28, 2020

I am trying to use this library with a third party C library, but I need to carry some additional context to perform the computations.

My issue boils down to how do I integrate library calls like:

-- Haskell wrapper function signature 
zero :: (Int, Int) -> StateT IO Context Matrix
one :: (Int, Int) -> StateT IO Context Matrix
add :: Matrix -> Matrix -> StateT IO Context Matrix
matMul :: Matrix -> Matrix -> StateT IO Context Matrix

-- FFI signature 
zero :: Ptr Context -> CInt -> CInt -> IO (Ptr Matrix)
one :: Ptr Context -> CInt -> CInt -> IO (Ptr Matrix)
add :: Ptr Context -> Ptr Matrix -> Ptr Matrix -> IO (Ptr Matrix)
matmul :: Ptr Context -> Ptr Matrix -> Ptr Matrix -> IO (Ptr Matrix)

There are no standalone functions to zero, one, or add a Matrix without carrying the Context.

@ocramz
Copy link

ocramz commented Sep 9, 2020

I've only recently started using backprop, but pretty much like ad it assumes that the computation to be differentiated is pure. I can't quite follow the internals of the library well enough to be able to tell why that is the case, though.

@jh14778
Copy link
Author

jh14778 commented Sep 9, 2020

I suspected that was the case.

My library calls are "pure" as far as the computed values are concerned.
Unfortunately, there are observable side-effects on the context (unsafePerformIO might not be acceptable here either).

Perhaps this is more of a feature request. I'm happy for this to be closed, if there's no plan for this to be supported.

@ivanovs-4
Copy link

Maybe the MVar trick will do:

import Control.Concurrent
import Control.Monad.State
import Data.Tuple
import System.IO.Unsafe

type Context = Int
type Matrix = [[Double]]
newtype Ctx = Ctx { unCtx :: MVar Context }

newCtx :: IO Context -> IO Ctx
newCtx ioc = fmap Ctx $ newMVar =<< ioc

zero :: (Int, Int) -> StateT Context IO Matrix
zero xy@(x,y) = do
    modify' succ
    s <- get
    lift $ print $ (s, xy)
    pure $ replicate y $ replicate x $ 0

zero' :: Ctx -> (Int, Int) -> Matrix
zero' ctx xy = wrap ctx $ zero xy

wrap :: Ctx -> StateT Context IO a -> a
wrap ctx ma = unsafePerformIO $
    modifyMVar (unCtx ctx) $ fmap swap . runStateT ma

main :: IO ()
main = do
  ctx <- newCtx $ pure 0
  print $ zero' ctx (2,3)
  print $ zero' ctx (1,1)

@ocramz
Copy link

ocramz commented Dec 20, 2020

@jh14778 @ivanovs-4 I just recalled : you could also wrap your effects inside ABP , which will provide the Backprop instance for you : https://hackage.haskell.org/package/backprop-0.2.6.4/docs/Numeric-Backprop.html#t:ABP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants