packages feed

sgd 0.8.0.0 → 0.8.0.1

raw patch · 3 files changed

+3/−298 lines, 3 files

Files

sgd.cabal view
@@ -4,12 +4,12 @@ -- -- see: https://github.com/sol/hpack ----- hash: c76dc64057b0ad62fdd40b4496b01d9bdbf827e48db5996639347df6c4209224+-- hash: 2f29d911949ea62e385d514bbbce417c880285e7f8cd576492e8444fb45ae1c8  name:           sgd-version:        0.8.0.0+version:        0.8.0.1 synopsis:       Stochastic gradient descent library-description:    Please see the README on GitHub at <https://github.com/kawu/sgd#readme>+description:    Stochastic gradient descent library. . Import "Numeric.SGD" to use the library. category:       Math homepage:       https://github.com/kawu/sgd#readme bug-reports:    https://github.com/kawu/sgd/issues@@ -35,9 +35,7 @@       Numeric.SGD.DataSet       Numeric.SGD.Momentum       Numeric.SGD.ParamSet-      Numeric.SGD.Pipe       Numeric.SGD.Sparse-      Numeric.SGD.Sparse.Dataset       Numeric.SGD.Sparse.Grad       Numeric.SGD.Sparse.LogSigned       Numeric.SGD.Sparse.Momentum
− src/Numeric/SGD/Pipe.hs
@@ -1,169 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE DeriveGeneric #-}----- | Pipe-based interface---module Numeric.SGD.Pipe where---   ( Config(..)---   , Method(..)---   , sgd---   , result---   , every---   , pipeSeq---   , pipeRan---   ) where----- import           GHC.Generics (Generic)--- import           Numeric.Natural (Natural)--- --- import           Control.Monad (when, forM_)--- --- import qualified System.Random as R--- --- import qualified Data.IORef as IO--- --- import qualified Pipes as P--- import qualified Pipes.Prelude as P--- import           Pipes ((>->))--- --- import           Numeric.SGD.DataSet--- import           Numeric.SGD.ParamSet--- import qualified Numeric.SGD.AdaDelta as Ada--- import qualified Numeric.SGD.Momentum as Mom--- --- --- ------------------------------- --- -- Data--- ---------------------------------- --- --- -- | Top-level SGD configuration--- data Config = Config---   { iterNum :: Natural---     -- ^ Number of iteration over the entire training dataset---   , batchRandom :: Bool---     -- ^ Should the mini-batch be selected at random?  If not, the subsequent---     -- training elements will be picked sequentially.  Random selection gives---     -- no guarantee of seeing each training sample in every epoch.  Use `False`---     -- if unsure.---   , method :: Method---     -- ^ Selected SGD method---   , reportPeriod :: Double---     -- ^ How often the quality should be reported (with `1` meaning once per---     -- pass over the training data)---   } deriving (Show, Eq, Ord, Generic)--- --- --- -- | Different SGD methods, together with the corresponding configurations--- data Method---   = AdaDelta {adaDeltaCfg :: Ada.Config}---   | Momentum {momentumCfg :: Mom.Config}---   deriving (Show, Eq, Ord, Generic)--- --- --- ------------------------------- --- -- SGD--- ---------------------------------- --- --- -- | Pipe-based SGD.--- sgd---   :: (ParamSet p)---   => Config---   -> DataSet e---   -> (e -> p -> p)---     -- ^ Network gradient on a sample element---   -> (e -> p -> Double)---     -- ^ Value of the objective function on a sample element---   -> p---     -- ^ Initial parameter values---   -> IO p--- sgd Config{..} dataSet grad0 quality0 net0 = do---   let sgdPipe =---         case method of---           Momentum cfg -> Mom.momentum cfg---             -- (cfg {Mom.tau = iterScale (Mom.tau cfg)})---             grad0 net0---           AdaDelta cfg -> Ada.adaDelta cfg grad0 net0---   report net0---   result net0 $ pipeSeq dataSet---     >-> sgdPipe---     >-> P.take realIterNum---     >-> every realReportPeriod report---   where---     -- Iteration scaling---     iterScale x = fromIntegral (size dataSet) * x---     -- Number of iterations and reporting period---     realIterNum = ceiling $ iterScale (fromIntegral iterNum :: Double)---     realReportPeriod = ceiling $ iterScale reportPeriod---     -- Network quality over the entire training dataset---     report net = do---       putStr . show =<< quality net---       putStrLn $ " (norm_2 = " ++ show (norm_2 net) ++ ")"---     quality net = do---       res <- IO.newIORef 0.0---       forM_ [0 .. size dataSet - 1] $ \ix -> do---         x <- elemAt dataSet ix---         IO.modifyIORef' res (+ quality0 x net)---       IO.readIORef res--- --- --- ------------------------------- --- -- Dataset producers--- ---------------------------------- --- --- -- | Pipe the dataset sequentially in a loop.--- pipeSeq :: DataSet e -> P.Producer e IO ()--- pipeSeq dataSet = do---   go (0 :: Int)---   where---     go k---       | k >= size dataSet = go 0---       | otherwise = do---           x <- P.lift $ elemAt dataSet k---           P.yield x---           go (k+1)--- --- --- -- | Pipe the dataset randomly in a loop.--- pipeRan :: DataSet e -> P.Producer e IO ()--- pipeRan dataSet = do---   x <- P.lift $ do---     ix <- R.randomRIO (0, size dataSet - 1)---     elemAt dataSet ix---   P.yield x---   pipeRan dataSet--- --- --- ------------------------------- --- -- Utils--- ---------------------------------- --- --- -- | Extract the result of the SGD calculation (the last parameter--- -- set flowing downstream).--- result---   :: (Monad m)---   => p     ---     -- ^ Default value (in case the stream is empty)---   -> P.Producer p m ()---     -- ^ Stream of parameter sets---   -> m p--- result pDef = fmap (maybe pDef id) . P.last--- --- --- -- | Report every `k`-th parameter set flowing downstream.--- every :: (Monad m) => Int -> (p -> m ()) -> P.Pipe p p m x--- every k report = do---   go (1 `mod` k)---   where---     go i = do---       paramSet <- P.await---       when (i == 0) $ do---         P.lift $ report paramSet---       P.yield paramSet---       go $ (i+1) `mod` k
− src/Numeric/SGD/Sparse/Dataset.hs
@@ -1,124 +0,0 @@-{-# LANGUAGE RecordWildCards #-}----- | Dataset abstraction.---module Numeric.SGD.Sparse.Dataset-( --- * Dataset-  Dataset (..)--- * Reading-, loadData-, sample--- * Construction-, withVect-, withDisk-, withData-) where---import           Control.Monad (forM_)-import           Data.Binary (Binary, encodeFile, decode)-import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as BL-import           System.IO.Temp (withTempDirectory)-import           System.IO.Unsafe (unsafeInterleaveIO)-import           System.FilePath ((</>))-import qualified System.Random as R-import qualified Data.Vector as V-import qualified Control.Monad.State.Strict as S----- | A dataset with elements of type @a@.-data Dataset a = Dataset {-    -- | A size of the dataset.-      size      :: Int-    -- | Get dataset element with a given index.  The set of indices-    -- is of a {0, 1, .., size - 1} form.-    , elemAt    :: Int -> IO a -    }------------------------------------------------- Reading------------------------------------------------- | Lazily load dataset from a disk.-loadData :: Dataset a -> IO [a]-loadData Dataset{..} = lazyMapM elemAt [0 .. size - 1]----- | A dataset sample of the given size.-sample :: R.RandomGen g => g -> Int -> Dataset a -> IO ([a], g)-sample g 0 _       = return ([], g)-sample g n dataset = do-    (xs, g') <- sample g (n-1) dataset-    let (i, g'') = R.next g'-    x <- dataset `elemAt` (i `mod` size dataset)-    return (x:xs, g'')------------------------------------------------- Construction------------------------------------------------- | Construct dataset from a vector of elements and run the--- given handler.-withVect :: [a] -> (Dataset a -> IO b) -> IO b-withVect xs handler =-    handler dataset-  where-    v = V.fromList xs-    dataset = Dataset-        { size      = V.length v-        , elemAt    = \k -> return (v V.! k) }----- | Construct dataset from a list of elements, store it on a disk--- and run the given handler.-withDisk :: Binary a => [a] -> (Dataset a -> IO b) -> IO b-withDisk xs handler = withTempDirectory "." ".sgd" $ \tmpDir -> do-    -- We use state monad to compute the number of dataset elements. -    n <- flip S.execStateT 0 $ forM_ (zip xs [0 :: Int ..]) $ \(x, ix) -> do-        S.lift $ encodeFile (tmpDir </> show ix) x-        S.modify (+1)--    -- We need to avoid decodeFile laziness when using some older-    -- versions of the binary library.-    let at ix = do-          cs <- B.readFile (tmpDir </> show ix)-          return . decode $ BL.fromChunks [cs]--    handler $ Dataset {size = n, elemAt = at}----- | Use disk or vector dataset representation depending on--- the first argument: when `True`, use `withDisk`, otherwise--- use `withVect`.-withData :: Binary a => Bool -> [a] -> (Dataset a -> IO b) -> IO b-withData x = case x of-    True    -> withDisk-    False   -> withVect------------------------------------------------- Lazy IO Utils------------------------------------------------- | Lazily evaluate each action in the sequence from left to right,--- and collect the results.-lazySequence :: [IO a] -> IO [a]-lazySequence (mx:mxs) = do-    x   <- mx-    xs  <- unsafeInterleaveIO (lazySequence mxs)-    return (x : xs)-lazySequence [] = return []----- | `lazyMapM` f is equivalent to `lazySequence` . `map` f.-lazyMapM :: (a -> IO b) -> [a] -> IO [b]-lazyMapM f = lazySequence . map f