rc (empty) → 0.1.0.0
raw patch · 9 files changed
+414/−0 lines, 9 filesdep +Learningdep +basedep +ddesetup-changed
Dependencies added: Learning, base, dde, hmatrix, random, rc, vector
Files
- ChangeLog.md +3/−0
- LICENSE +30/−0
- README.md +28/−0
- Setup.hs +2/−0
- examples/NTC/Main.hs +59/−0
- rc.cabal +79/−0
- rc/RC/Helpers.hs +65/−0
- rc/RC/NTC.hs +146/−0
- test/Spec.hs +2/−0
+ ChangeLog.md view
@@ -0,0 +1,3 @@+# Changelog for rc++## Unreleased changes
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Bogdan Penkovsky (c) 2018++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Bogdan Penkovsky nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,28 @@+# Reservoir Computing++Facilitating RC research++## Features++* [Nonlinear transient computing (NTC)](https://github.com/masterdezign/rc/tree/master/examples/NTC)+++## Getting Started++Use [Stack](http://haskellstack.org).++ $ git clone https://github.com/masterdezign/rc.git && cd rc+ $ stack build --install-ghc++### [Example 1](https://github.com/masterdezign/rc/tree/master/examples/NTC). NTC+++ $ stack exec ntc++ Error: 3.1103181863915367e-3++[Here](https://raw.githubusercontent.com/masterdezign/rc/master/examples/NTC/mg-prediction.png) is visualized prediction result.++++Great!
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ examples/NTC/Main.hs view
@@ -0,0 +1,59 @@+import Numeric.LinearAlgebra+import System.Random ( mkStdGen )+import Learning ( nrmse )++import RC.NTC as RC++-- Get training data+takePast :: Int -> Matrix Double -> Matrix Double+takePast horizon xs = xs ?? (All, Take (len - horizon))+ where+ len = cols xs++-- Get teacher data+takeFuture :: Int -> Matrix Double -> Matrix Double+takeFuture horizon = (?? (All, Drop horizon))++main = do+ -- Load and transpose time series to predict+ dta <- tr <$> loadMatrix "examples/data/mg.txt"++ let splitRatio = 0.50 -- Train on 50% of data+ total = cols dta+ spl = round $ splitRatio * fromIntegral total+ -- Split the data+ train = dta ?? (All, Take spl)+ validate = dta ?? (All, Drop spl)++ -- Configure new NTC network+ let p = RC.par0 { RC._inputWeightsRange = (0.1, 0.3) }+ g = mkStdGen 1111+ ntc = RC.new g p (1, 1000, 1)++ -- 20 steps ahead prediction horizon+ let horizon = 20++ let train' = takePast horizon train -- Past series+ trainTeacher = takeFuture horizon train -- Predicted series++ let forgetPts = 300 -- Washout++ -- Train+ case RC.learn ntc forgetPts train' trainTeacher of+ Left s -> error s+ Right ntc' -> do+ let target = (takeFuture horizon validate) ?? (All, Drop forgetPts)++ -- Predict+ case RC.predict ntc' forgetPts (takePast horizon validate) of+ Left s -> error s+ Right prediction -> do+ let tgt' = flatten target+ predic' = flatten prediction+ err = nrmse tgt' predic'++ putStrLn $ "Error: " ++ show err++ let result = (tr target) ||| (tr prediction)++ saveMatrix "examples/NTC/result.txt" "%g" result
+ rc.cabal view
@@ -0,0 +1,79 @@+-- This file has been generated from package.yaml by hpack version 0.20.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 32b8af1a3f4db71e5262f476ae36f22cd703e7dfd8e047f0c0d7b61b9ee1f3e8++name: rc+version: 0.1.0.0+synopsis: Reservoir Computing, fast RNNs+description: Please see the README on Github at <https://github.com/masterdezign/rc#readme>+category: Machine Learning+homepage: https://github.com/masterdezign/rc#readme+bug-reports: https://github.com/masterdezign/rc/issues+author: Bogdan Penkovsky+maintainer: dev () penkovsky dot com+copyright: Bogdan Penkovsky+license: BSD3+license-file: LICENSE+build-type: Simple+cabal-version: >= 1.10++extra-source-files:+ ChangeLog.md+ README.md++source-repository head+ type: git+ location: https://github.com/masterdezign/rc++library+ hs-source-dirs:+ rc+ build-depends:+ Learning+ , base >=4.7 && <5+ , dde ==0.0.0+ , hmatrix >=0.18.0.0+ , random+ , vector+ exposed-modules:+ RC.Helpers+ RC.NTC+ other-modules:+ Paths_rc+ default-language: Haskell2010++executable ntc+ main-is: Main.hs+ hs-source-dirs:+ examples/NTC+ build-depends:+ Learning+ , base >=4.7 && <5+ , dde ==0.0.0+ , hmatrix >=0.18.0.0+ , random+ , rc+ , vector+ other-modules:+ Paths_rc+ default-language: Haskell2010++test-suite rc-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ hs-source-dirs:+ test+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ Learning+ , base >=4.7 && <5+ , dde ==0.0.0+ , hmatrix >=0.18.0.0+ , random+ , rc+ , vector+ other-modules:+ Paths_rc+ default-language: Haskell2010
+ rc/RC/Helpers.hs view
@@ -0,0 +1,65 @@+module RC.Helpers+ ( addBiases+ , randList+ , randMatrix+ , randSparse+ , hsigmoid+ ) where++import System.Random+import Data.List ( unfoldr )+import qualified Numeric.LinearAlgebra as LA++-- | Hard sigmoid+hsigmoid :: (Fractional a, Ord a)+ => (a, a, a)+ -- ^ Vertical scaling, width, offset+ -> a+ -> a+hsigmoid (β, width, offset) x = f+ where+ f | x < offset = 0.0+ | x < width = β * (x - offset)+ | otherwise = β * (width - offset)++-- | Prepend a row of ones+-- >>> addBiases $ (2><3) [20..26]+-- (3><3)+-- [ 1.0, 1.0, 1.0+-- , 20.0, 21.0, 22.0+-- , 23.0, 24.0, 25.0 ]+addBiases :: LA.Matrix Double -> LA.Matrix Double+addBiases m = let no = LA.cols m+ m' = LA.konst 1.0 (1, no)+ in m' LA.=== m++-- | Random matrix with elements in the range of [minVal; maxVal]+randMatrix+ :: StdGen+ -> (Int, Int)+ -- ^ Number of rows and columns+ -> (Double, Double)+ -- ^ Minimal and maximal values+ -> LA.Matrix Double+randMatrix seed (rows', cols') (minVal, maxVal) = (LA.reshape cols'. LA.vector) xs+ where+ xs = f <$> randList (rows' * cols') seed+ f x = (maxVal - minVal) * x + minVal++-- | Random sparse matrix+--+-- NB: at the moment, the matrix is stored in memory as+-- an ordinary (dense) matrix.+randSparse g (rows', cols') (minVal, maxVal) connectivity =+ LA.reshape cols' $ LA.vector xs+ where+ (g1, g2) = split g+ rlist = randList (rows' * cols')+ xs = zipWith f (rlist g1) (rlist g2)+ f lv rv | lv < connectivity = (maxVal - minVal) * rv + minVal+ | otherwise = 0.0++randList :: (Random a, Floating a) => Int -> StdGen -> [a]+randList n = take n. unfoldr (Just. random)+{-# SPECIALISE randList :: Int -> StdGen -> [Float] #-}+{-# SPECIALISE randList :: Int -> StdGen -> [Double] #-}
+ rc/RC/NTC.hs view
@@ -0,0 +1,146 @@+-- = Nonlinear transient computing+--+-- This module was developed as a part of author's PhD project:+-- https://www.researchgate.net/project/Theory-and-Modeling-of-Complex-Nonlinear-Delay-Dynamics-Applied-to-Neuromorphic-Computing+--++{-# LANGUAGE BangPatterns #-}++module RC.NTC+ ( new+ , learn+ , predict+ , par0+ , NTCParameters (..)+ , DDEModel.Par (..)+ , DDEModel.BandpassFiltering (..)+ ) where++import Numeric.LinearAlgebra+import System.Random ( StdGen+ , split+ )+import qualified Data.Vector.Storable as V+import qualified Learning+import qualified Numeric.DDE as DDE+import qualified Numeric.DDE.Model as DDEModel++import qualified RC.Helpers as H++-- | DDE reservoir abstraction+newtype Reservoir = Reservoir { _transform :: Matrix Double -> Matrix Double }++data NTCParameters = Par+ { _preprocess :: Matrix Double -> Matrix Double+ -- ^ Modify data before masking (e.g. compression)+ , _inputWeightsRange :: (Double, Double) -- ^ Input weights (mask) range+ , _inputWeightsGenerator :: StdGen -> (Int, Int) -> (Double, Double) -> Matrix Double+ , _postprocess :: Matrix Double -> Matrix Double+ -- ^ Modify data before training or prediction (e.g. add biases)+ , _reservoirModel :: DDEModel.Par+ }++data NTC = NTC+ { _inputWeights :: Matrix Double+ , _reservoir :: Reservoir+ , _outputWeights :: Maybe (Matrix Double)+ -- ^ Trainable part of NTC+ , _par :: NTCParameters+ }++new+ :: StdGen+ -> NTCParameters+ -> (Int, Int, Int)+ -- ^ Input dimension, network nodes, and output dimension+ -> NTC+new g par (ind, nodes, out) =+ let iwgen = _inputWeightsGenerator par+ iw = iwgen g (nodes, ind) (_inputWeightsRange par)+ ntc = NTC { _inputWeights = iw+ , _reservoir = genReservoir (_reservoirModel par)+ , _outputWeights = Nothing+ , _par = par+ }+ in ntc++-- | Default NTC parameters+par0 :: NTCParameters+par0 = Par+ { _preprocess = id+ , _inputWeightsGenerator = H.randMatrix+ , _postprocess = H.addBiases -- Usually `id` will work+ , _inputWeightsRange = undefined -- To be manually set, e.g. (-1, 1)+ , _reservoirModel = DDEModel.RC { DDEModel._filt = filt'+ , DDEModel._rho = 3.25+ , DDEModel._fnl = H.hsigmoid (1.09375, 1.5, 0.0)+ }+ }+ where+ filt' = DDEModel.BandpassFiltering {+ DDEModel._tau = 7.8125e-3+ , DDEModel._theta = recip 0.34375+ }++genReservoir :: DDEModel.Par -> Reservoir+genReservoir par = Reservoir _r+ where+ _r sample = unflatten response+ where+ flatten' = flatten. tr+ unflatten = tr. reshape nodes++ oversampling = 1 :: Int -- No oversampling+ detuning = 1.0 :: Double -- Delay detuning factor, 1 = no detuning+ nodes = rows sample+ delaySamples = round $ detuning * fromIntegral (oversampling * nodes)++ -- Matrix to timetrace+ trace1 = flatten' sample++ -- Duplicate the last element (DDE.integHeun2_2D consumes one extra input)+ trace = trace1 V.++ V.singleton (V.last trace1)++ tau = DDEModel._tau $ DDEModel._filt par+ hStep = tau / 2++ !(_, !response) = DDE.integHeun2_2D delaySamples hStep (DDEModel.rhs par) (DDE.Input trace)++forwardPass :: NTC -> Matrix Double -> Matrix Double+forwardPass NTC { _par = Par { _preprocess = prep, _postprocess = post }+ , _inputWeights = iw+ , _reservoir = Reservoir res+ } sample =+ let pipeline = post. res. (iw <>). prep+ in pipeline sample++-- | Offline NTC training+learn+ :: NTC+ -> Int+ -- ^ Discard the first N points+ -> Matrix Double+ -- ^ Input matrix of features rows and observations columns+ -> Matrix Double+ -- ^ Desired output matrix of observations columns+ -> Either String NTC+learn ntc forgetPts inp out = ntc'+ where+ state' = (forwardPass ntc inp) ?? (All, Drop forgetPts)+ teacher' = out ?? (All, Drop forgetPts)+ ntc' = case Learning.learn' state' teacher' of+ Nothing -> Left "Cannot create a readout matrix"+ w -> Right $ ntc { _outputWeights = w }++predict :: NTC+ -> Int+ -> Matrix Double+ -> Either String (Matrix Double)+predict ntc@NTC { _outputWeights = ow+ } forgetPts inp =+ case ow of+ Nothing -> Left "Please train the NTC first"+ Just w -> let y = forwardPass ntc inp+ y2 = y ?? (All, Drop forgetPts)+ prediction = w <> y2+ in Right prediction
+ test/Spec.hs view
@@ -0,0 +1,2 @@+main :: IO ()+main = putStrLn "Test suite not yet implemented"