@@ -8,6 +8,9 @@ import Control.Monad
8import Control.Monad.Random
8import Control.Monad.Random
9import Data.List ( foldl' )
9import Data.List ( foldl' )
11+import qualified Data.ByteString as B
11import GHC.TypeLits
14import GHC.TypeLits
13import qualified Numeric.LinearAlgebra.Static as SA
16import qualified Numeric.LinearAlgebra.Static as SA
@@ -16,13 +19,12 @@ import Options.Applicative
17import Grenade
20import Grenade
19−-- The defininition for our simple feed forward network.
20−-- The type level list represents the shapes passed through the layers. One can see that for this demonstration
21−-- we are using relu, tanh and logit non-linear units, which can be easily subsituted for each other in and out.
23−-- It's important to keep the type signatures, as there's many layers which can "squeeze" into the gaps
24−-- between the shapes, so inference can't do it all for us.
23+-- The defininition for our simple feed forward network.
24+-- The type level lists represents the layers and the shapes passed through the layers.
25+-- One can see that for this demonstration we are using relu, tanh and logit non-linear
26+-- units, which can be easily subsituted for each other in and out.
26-- With around 100000 examples, this should show two clear circles which have been learned by the network.
28-- With around 100000 examples, this should show two clear circles which have been learned by the network.
27type FFNet = Network '[ FullyConnected 2 40, Tanh, FullyConnected 40 10, Relu, FullyConnected 10 1, Logit ]
29type FFNet = Network '[ FullyConnected 2 40, Tanh, FullyConnected 40 10, Relu, FullyConnected 10 1, Logit ]
28 '[ 'D1 2, 'D1 40, 'D1 40, 'D1 10, 'D1 10, 'D1 1, 'D1 1]
30 '[ 'D1 2, 'D1 40, 'D1 40, 'D1 10, 'D1 10, 'D1 1, 'D1 1]
@@ -30,8 +32,8 @@ type FFNet = Network '[ FullyConnected 2 40, Tanh, FullyConnected 40 10, Relu, F
30randomNet :: MonadRandom m => m FFNet
32randomNet :: MonadRandom m => m FFNet
31randomNet = randomNetwork
33randomNet = randomNetwork
33−netTest :: MonadRandom m => LearningParameters -> Int -> m String
35+netTrain :: FFNet -> LearningParameters -> Int -> IO FFNet
34−netTest rate n = do
36+netTrain net0 rate n = do
35 inps <- replicateM n $ do
37 inps <- replicateM n $ do
36 s <- getRandom
38 s <- getRandom
37 return $ S1D $ SA.randomVector s SA.Uniform * 2 - 1
39 return $ S1D $ SA.randomVector s SA.Uniform * 2 - 1
@@ -39,20 +41,28 @@ netTest rate n = do
39 if v `inCircle` (fromRational 0.33, 0.33) || v `inCircle` (fromRational (-0.33), 0.33)
41 if v `inCircle` (fromRational 0.33, 0.33) || v `inCircle` (fromRational (-0.33), 0.33)
40 then S1D $ fromRational 1
42 then S1D $ fromRational 1
41 else S1D $ fromRational 0
43 else S1D $ fromRational 0
44 let trained = foldl' trainEach net0 (zip inps outs)
45 let trained = foldl' trainEach net0 (zip inps outs)
45− let testIns = [ [ (x,y) | x <- [0..50] ]
46+ return trained
48− let outMat = fmap (fmap (\(x,y) -> (render . normx) $ runNet trained (S1D $ SA.vector [x / 25 - 1,y / 10 - 1]))) testIns
49− return $ unlines outMat
52 inCircle :: KnownNat n => SA.R n -> (SA.R n, Double) -> Bool
49 inCircle :: KnownNat n => SA.R n -> (SA.R n, Double) -> Bool
53 v `inCircle` (o, r) = SA.norm_2 (v - o) <= r
50 v `inCircle` (o, r) = SA.norm_2 (v - o) <= r
54 trainEach !network (i,o) = train rate network i o
51 trainEach !network (i,o) = train rate network i o
53+netLoad :: FilePath -> IO FFNet
54+netLoad modelPath = do
55+ modelData <- B.readFile modelPath
56+ either fail return $ runGet (get :: Get FFNet) modelData
58+netScore :: FFNet -> IO ()
60+ let testIns = [ [ (x,y) | x <- [0..50] ]
62+ outMat = fmap (fmap (\(x,y) -> (render . normx) $ runNet network (S1D $ SA.vector [x / 25 - 1,y / 10 - 1]))) testIns
63+ putStrLn $ unlines outMat
56 render n' | n' <= 0.2 = ' '
66 render n' | n' <= 0.2 = ' '
57 | n' <= 0.4 = '.'
67 | n' <= 0.4 = '.'
58 | n' <= 0.6 = '-'
68 | n' <= 0.6 = '-'
@@ -62,7 +72,7 @@ netTest rate n = do
62 normx :: S ('D1 1) -> Double
72 normx :: S ('D1 1) -> Double
63 normx (S1D r) = SA.mean r
73 normx (S1D r) = SA.mean r
65−data FeedForwardOpts = FeedForwardOpts Int LearningParameters
75+data FeedForwardOpts = FeedForwardOpts Int LearningParameters (Maybe FilePath) (Maybe FilePath)
67feedForward' :: Parser FeedForwardOpts
77feedForward' :: Parser FeedForwardOpts
68feedForward' =
78feedForward' =
@@ -72,9 +82,19 @@ feedForward' =
72 <*> option auto (long "momentum" <> value 0.9)
82 <*> option auto (long "momentum" <> value 0.9)
73 <*> option auto (long "l2" <> value 0.0005)
83 <*> option auto (long "l2" <> value 0.0005)
85+ <*> optional (strOption (long "load"))
86+ <*> optional (strOption (long "save"))
76main :: IO ()
88main :: IO ()
78− FeedForwardOpts examples rate <- execParser (info (feedForward' <**> helper) idm)
90+ FeedForwardOpts examples rate load save <- execParser (info (feedForward' <**> helper) idm)
79− putStrLn "Training network..."
91+ net0 <- case load of
80− putStrLn =<< evalRandIO (netTest rate examples)
92+ Just loadFile -> netLoad loadFile
95+ net <- netTrain net0 rate examples
99+ Just saveFile -> B.writeFile saveFile $ runPut (put net)
100+ Nothing -> return ()