packages feed

fei-nn-1.0.0: src/MXNet/NN/Callback.hs

module MXNet.NN.Callback where

import RIO
import RIO.Time
import RIO.FilePath
import Formatting
import Control.Lens (use)

import MXNet.NN.Types (mod_statistics, stat_last_lr)
import MXNet.NN.Session
import MXNet.NN.TaggedState (untag)
import MXNet.NN.Utils (saveState)

-- | Learning rate
data DumpLearningRate = DumpLearningRate

instance CallbackClass DumpLearningRate where
    endOfBatch _ _ _ = do
        lr <- use (untag . mod_statistics . stat_last_lr)
        lift . logInfo . display $ sformat ("<lr: " % fixed 6 % ">") lr

-- | Throughput
data DumpThroughputEpoch = DumpThroughputEpoch {
    _tp_begin_time :: IORef UTCTime,
    _tp_end_time :: IORef UTCTime,
    _tp_total_sample :: IORef Int
}

instance CallbackClass DumpThroughputEpoch where
    begOfBatch _ n (DumpThroughputEpoch _ _ totalRef) = do
        liftIO $ modifyIORef totalRef (+n)
    begOfEpoch _ _ (DumpThroughputEpoch tt1Ref _ _) =
        liftIO $ getCurrentTime >>= writeIORef tt1Ref
    endOfEpoch _ _ (DumpThroughputEpoch _ tt2Ref _) = do
        liftIO $ getCurrentTime >>= writeIORef tt2Ref
    endOfVal   _ _ (DumpThroughputEpoch tt1Ref tt2Ref totalRef) = do
        tbeg <- readIORef tt1Ref
        tend <- readIORef tt2Ref
        let diff = realToFrac $ diffUTCTime tend tbeg :: Float
        total <- readIORef totalRef
        writeIORef totalRef 0
        lift . logInfo . display $ sformat ("Throughput: " % int % " samples/sec") (floor $ fromIntegral total / diff :: Int)

dumpThroughputEpoch :: IO Callback
dumpThroughputEpoch = do
    t0 <- getCurrentTime
    r0 <- newIORef t0
    r1 <- newIORef t0
    r2 <- newIORef 0
    return $ Callback $ DumpThroughputEpoch r0 r1 r2

-- | Checkpoint
data Checkpoint = Checkpoint FilePath

instance CallbackClass Checkpoint where
    endOfVal i _ (Checkpoint path) = do
        let filename = path </> formatToString ("epoch_" % int) i
        saveState (i == 0) filename