packages feed

fei-examples-0.3.0: src/Model/VGG.hs

module Model.VGG where

import Text.Printf (printf)
import Control.Monad (foldM)
import Data.Maybe (fromMaybe)

import MXNet.Base
import MXNet.NN.Layer

getFeature :: SymbolHandle -> [Int] -> [Int] -> Bool -> Bool -> IO SymbolHandle
getFeature internalLayer layers filters with_batch_norm with_last_pooling= do
    sym <- foldM build1 internalLayer specs
    -- inlining the build1 below, and omit pooling depending on the with_last_pooling
    case last_group of
        (idx, num, filter) -> do
            sym <- foldM (build2 idx) sym $ zip [1::Int ..] (replicate num filter)
            if not with_last_pooling
                then return sym
                else pooling (printf "pool%d" idx) (#data := sym .& #pool_type := #max .& #kernel := [2,2] .& #stride := [2,2] .& Nil)

  where
    last_group:groups = reverse $ zip3 [1::Int ..] layers filters
    specs = reverse groups

    build1 sym (idx, num, filter) = do 
        sym <- foldM (build2 idx) sym $ zip [1::Int ..] (replicate num filter)
        pooling (printf "pool%d" idx) (#data := sym .& #pool_type := #max .& #kernel := [2,2] .& #stride := [2,2] .& Nil)

    build2 idx1 sym (idx2, filter) = do
        let ident = printf "%d_%d" idx1 idx2
        sym <- convolution ("conv" ++ ident) (#data := sym .& #kernel := [3,3] .& #pad := [1,1] .& #num_filter := filter .& #workspace := 2048 .& Nil)
        sym <- if with_batch_norm then batchnorm ("bn" ++ ident) (#data := sym .& Nil) else return sym
        activation ("relu" ++ ident) (#data := sym .& #act_type := #relu .& Nil)

getTopFeature :: Maybe String -> SymbolHandle -> IO SymbolHandle
getTopFeature prefix input_data = do
    let addPrefix = (fromMaybe "" prefix ++)
    sym <- flatten (addPrefix "flatten") (#data := input_data .& Nil)
    sym <- fullyConnected (addPrefix "fc6") (#data := sym .& #num_hidden := 4096 .& Nil)
    sym <- activation (addPrefix "relu6") (#data := sym .& #act_type := #relu .& Nil)
    sym <- dropout (addPrefix "drop6") (#data := sym .& #p := 0.5 .& Nil)
    sym <- fullyConnected (addPrefix "fc7") (#data := sym .& #num_hidden := 4096 .& Nil)
    sym <- activation (addPrefix "relu7") (#data := sym .& #act_type := #relu .& Nil)
    dropout (addPrefix "drop7") (#data := sym .& #p := 0.5 .& Nil)

getClassifier :: Maybe String -> SymbolHandle -> Int -> IO SymbolHandle
getClassifier prefix input_data num_classes = do
    let addPrefix = (fromMaybe "" prefix ++)
    sym <- getTopFeature prefix input_data
    fullyConnected (addPrefix "fc8") (#data := sym .& #num_hidden := num_classes .& Nil)

symbol :: Int -> Int -> Bool -> IO (Symbol Float)
symbol num_classes num_layers with_batch_norm = do
    sym <- variable "data"
    sym <- getFeature sym layers filters with_batch_norm True
    sym <- getClassifier Nothing sym num_classes
    sym <- softmaxoutput "softmax" (#data := sym .& Nil)
    return (Symbol sym)

  where  
    (layers, filters) = case num_layers of
                            11 -> ([1, 1, 2, 2, 2], [64, 128, 256, 512, 512])
                            13 -> ([2, 2, 2, 2, 2], [64, 128, 256, 512, 512])
                            16 -> ([2, 2, 3, 3, 3], [64, 128, 256, 512, 512])
                            19 -> ([2, 2, 4, 4, 4], [64, 128, 256, 512, 512])