@@ -11,7 +11,7 @@ import Control.Monad.Random
11import Control.Monad.Trans.Except
11import Control.Monad.Trans.Except
13import Data.Char ( isUpper, toUpper, toLower )
13import Data.Char ( isUpper, toUpper, toLower )
14−import Data.List ( unfoldr, foldl' )
14+import Data.List ( foldl' )
15import Data.Maybe ( fromMaybe )
15import Data.Maybe ( fromMaybe )
17import qualified Data.Vector as V
17import qualified Data.Vector as V
@@ -20,6 +20,8 @@ import Data.Vector ( Vector )
20import qualified Data.Map as M
20import qualified Data.Map as M
21import Data.Proxy ( Proxy (..) )
21import Data.Proxy ( Proxy (..) )
23+import qualified Data.ByteString as B
24import Data.Singletons.Prelude
26import Data.Singletons.Prelude
25import GHC.TypeLits
27import GHC.TypeLits
@@ -32,29 +34,31 @@ import Grenade
32import Grenade.Recurrent
34import Grenade.Recurrent
33import Grenade.Utils.OneHot
35import Grenade.Utils.OneHot
37+import System.IO.Unsafe ( unsafeInterleaveIO )
35-- The defininition for our natural language recurrent network.
39-- The defininition for our natural language recurrent network.
36-- This network is able to learn and generate simple words in
40-- This network is able to learn and generate simple words in
37-- about an hour.
41-- about an hour.
39−-- This is a first class recurrent net, although it's similar to
43+-- This is a first class recurrent net.
42-- The F and R types are tagging types to ensure that the runner and
45-- The F and R types are tagging types to ensure that the runner and
43-- creation function know how to treat the layers.
46-- creation function know how to treat the layers.
45-- As an example, here's a short sequence generated.
48-- As an example, here's a short sequence generated.
47−-- > the see and and the sir, and and the make and the make and go the make and go the make and the
50+-- > KING RICHARD III:
48−--
51+-- > And as the heaven her his words, we the son, I show sand stape but the lament to shall were the sons with a strend
49type F = FeedForward
53type F = FeedForward
50type R = Recurrent
54type R = Recurrent
52-- The definition of our network
56-- The definition of our network
53−type Shakespeare = RecurrentNetwork '[ R (LSTM 40 50), R (LSTM 50 40), F (FullyConnected 40 40), F Logit]
57+type Shakespeare = RecurrentNetwork '[ R (LSTM 40 80), R (LSTM 80 40), F (FullyConnected 40 40), F Logit]
54− '[ 'D1 40, 'D1 50, 'D1 40, 'D1 40, 'D1 40 ]
58+ '[ 'D1 40, 'D1 80, 'D1 40, 'D1 40, 'D1 40 ]
56-- The definition of the "sideways" input, which the network if fed recurrently.
60-- The definition of the "sideways" input, which the network if fed recurrently.
57−type Shakespearian = RecurrentInputs '[ R (LSTM 40 50), R (LSTM 50 40), F (FullyConnected 40 40), F Logit]
61+type Shakespearian = RecurrentInputs '[ R (LSTM 40 80), R (LSTM 80 40), F (FullyConnected 40 40), F Logit]
59randomNet :: MonadRandom m => m (Shakespeare, Shakespearian)
63randomNet :: MonadRandom m => m (Shakespeare, Shakespearian)
60randomNet = randomRecurrent
64randomNet = randomRecurrent
@@ -82,15 +86,23 @@ trainSlice !rate !net !recIns input offset size =
82runShakespeare :: ShakespeareOpts -> ExceptT String IO ()
86runShakespeare :: ShakespeareOpts -> ExceptT String IO ()
83runShakespeare ShakespeareOpts {..} = do
87runShakespeare ShakespeareOpts {..} = do
84 (shakespeare, oneHotMap, oneHotDictionary) <- loadShakespeare trainingFile
88 (shakespeare, oneHotMap, oneHotDictionary) <- loadShakespeare trainingFile
85− (net0, i0) <- lift randomNet
89+ (net0, i0) <- lift $
91+ Just loadFile -> netLoad loadFile
86− lift $ foldM_ (\(!net, !io) size -> do
94+ (trained, bestInput) <- lift $ foldM (\(!net, !io) size -> do
87 xs <- take (iterations `div` 15) <$> getRandomRs (0, length shakespeare - size - 1)
95 xs <- take (iterations `div` 15) <$> getRandomRs (0, length shakespeare - size - 1)
88 let (!trained, !bestInput) = foldl' (\(!n, !i) offset -> trainSlice rate n i shakespeare offset size) (net, io) xs
96 let (!trained, !bestInput) = foldl' (\(!n, !i) offset -> trainSlice rate n i shakespeare offset size) (net, io) xs
89− let results = take 100 $ generateParagraph trained bestInput oneHotMap oneHotDictionary ( S1D $ konst 0)
97+ results <- take 1000 <$> generateParagraph trained bestInput oneHotMap oneHotDictionary ( S1D $ konst 0)
90 putStrLn ("TRAINING STEP WITH SIZE: " ++ show size)
98 putStrLn ("TRAINING STEP WITH SIZE: " ++ show size)
91 putStrLn (unAnnotateCapitals results)
99 putStrLn (unAnnotateCapitals results)
92 return (trained, bestInput)
100 return (trained, bestInput)
93− ) (net0, i0) [10,10,15,15,20,20,25,25,30,30,35,35,40,40,50 :: Int]
101+ ) (net0, i0) [50,50,50,50,50,50,50,50,50,50,50,50,50,50,50 :: Int]
104+ Just saveFile -> lift . B.writeFile saveFile $ runPut (put (trained, bestInput))
105+ Nothing -> return ()
95generateParagraph :: forall layers shapes n a. (Last shapes ~ 'D1 n, Head shapes ~ 'D1 n, KnownNat n, Ord a)
107generateParagraph :: forall layers shapes n a. (Last shapes ~ 'D1 n, Head shapes ~ 'D1 n, KnownNat n, Ord a)
96 => RecurrentNetwork layers shapes
108 => RecurrentNetwork layers shapes
@@ -98,20 +110,23 @@ generateParagraph :: forall layers shapes n a. (Last shapes ~ 'D1 n, Head shapes
98 -> M.Map a Int
110 -> M.Map a Int
99 -> Vector a
111 -> Vector a
100 -> S ('D1 n)
112 -> S ('D1 n)
101− -> [a]
113+ -> IO [a]
102−generateParagraph n s hotmap hotdict i =
114+generateParagraph n s hotmap hotdict =
103− unfoldr go (s, i)
115+ go s
105− go (x, y) =
117+ go x y =
106 do let (ns, o) = runRecurrent n x y
118 do let (ns, o) = runRecurrent n x y
107− un <- unHot hotdict o
119+ un <- sample 0.4 hotdict o
108− re <- makeHot hotmap un
120+ Just re <- return $ makeHot hotmap un
109− Just (un, (ns, re))
121+ rest <- unsafeInterleaveIO $ go ns re
111data ShakespeareOpts = ShakespeareOpts {
124data ShakespeareOpts = ShakespeareOpts {
112 trainingFile :: FilePath
125 trainingFile :: FilePath
113 , iterations :: Int
126 , iterations :: Int
114 , rate :: LearningParameters
127 , rate :: LearningParameters
128+ , loadPath :: Maybe FilePath
129+ , savePath :: Maybe FilePath
117shakespeare' :: Parser ShakespeareOpts
132shakespeare' :: Parser ShakespeareOpts
@@ -122,6 +137,8 @@ shakespeare' = ShakespeareOpts <$> argument str (metavar "TRAIN")
122 <*> option auto (long "momentum" <> value 0.95)
137 <*> option auto (long "momentum" <> value 0.95)
123 <*> option auto (long "l2" <> value 0.000001)
138 <*> option auto (long "l2" <> value 0.000001)
140+ <*> optional (strOption (long "load"))
141+ <*> optional (strOption (long "save"))
126main :: IO ()
143main :: IO ()
@@ -132,6 +149,11 @@ main = do
132 Left err -> putStrLn err
149 Left err -> putStrLn err
152+netLoad :: FilePath -> IO (Shakespeare, Shakespearian)
153+netLoad modelPath = do
154+ modelData <- B.readFile modelPath
155+ either fail return $ runGet get modelData
135-- Replace capitals with an annotation and the lower case letter
157-- Replace capitals with an annotation and the lower case letter
136-- http://fastml.com/one-weird-trick-for-training-char-rnns/
158-- http://fastml.com/one-weird-trick-for-training-char-rnns/
137annotateCapitals :: String -> String
159annotateCapitals :: String -> String