fei-modelzoo-1.0.0: src/MXNet/NN/ModelZoo/VGG.hs
{-# LANGUAGE ViewPatterns #-}
module MXNet.NN.ModelZoo.VGG where
import RIO
import RIO.List (scanl, zip3)
import MXNet.Base
import MXNet.NN.Layer
{-
VGG(
(features): HybridSequential(
(0): Conv2D(3 -> 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): Activation(relu)
(2): Conv2D(64 -> 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): Activation(relu)
(4): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False, global_pool=False, pool_type=max, layout=NCHW)
(5): Conv2D(64 -> 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(6): Activation(relu)
(7): Conv2D(128 -> 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(8): Activation(relu)
(9): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False, global_pool=False, pool_type=max, layout=NCHW)
(10): Conv2D(128 -> 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): Activation(relu)
(12): Conv2D(256 -> 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(13): Activation(relu)
(14): Conv2D(256 -> 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(15): Activation(relu)
(16): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False, global_pool=False, pool_type=max, layout=NCHW)
(17): Conv2D(256 -> 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(18): Activation(relu)
(19): Conv2D(512 -> 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(20): Activation(relu)
(21): Conv2D(512 -> 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(22): Activation(relu)
(23): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False, global_pool=False, pool_type=max, layout=NCHW)
(24): Conv2D(512 -> 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(25): Activation(relu)
(26): Conv2D(512 -> 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(27): Activation(relu)
(28): Conv2D(512 -> 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(29): Activation(relu)
** (30): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False, global_pool=False, pool_type=max, layout=NCHW)
(31): Dense(25088 -> 4096, Activation(relu))
(32): Dropout(p = 0.5, axes=())
(33): Dense(4096 -> 4096, Activation(relu))
(34): Dropout(p = 0.5, axes=())
)
(output): Dense(4096 -> 1000, linear)
)
** It appears only if `with_last_pooling` is True.
-}
getFeature :: SymbolHandle -> [Int] -> [Int] -> Bool -> Bool -> Layer SymbolHandle
getFeature dat layers filters with_batch_norm with_last_pooling = do
sym <- foldM build1 dat 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 sym $ zip [idx..] $ replicate num filter
if not with_last_pooling
then return sym
else pooling (#data := sym
.& #pool_type := #max
.& #kernel := [2,2]
.& #stride := [2,2] .& Nil)
where
idxes = scanl (+) 0 layers
last_group:groups = reverse $ zip3 idxes layers filters
specs = reverse groups
build1 sym (idx, num, filter) = do
sym <- foldM build2 sym $ zip [idx..] $ replicate num filter
pooling (#data := sym
.& #pool_type := #max
.& #kernel := [2,2]
.& #stride := [2,2] .& Nil)
build2 sym (idx, filter) = do
sym <- convolution (#data := sym
.& #kernel := [3,3]
.& #pad := [1,1]
.& #num_filter := filter
.& #workspace := 2048 .& Nil)
sym <- if with_batch_norm
then batchnorm (#data := sym .& Nil)
else return sym
activation (#data := sym .& #act_type := #relu .& Nil)
getTopFeature :: SymbolHandle -> Layer SymbolHandle
getTopFeature input = do
sym <- unique' $ flatten input
sym <- fullyConnected (#data := sym .& #num_hidden := 4096 .& Nil)
-- sym <- activation (#data := sym .& #act_type := #relu .& Nil)
sym <- dropout sym 0.5
sym <- fullyConnected (#data := sym .& #num_hidden := 4096 .& Nil)
-- sym <- activation (#data := sym .& #act_type := #relu .& Nil)
dropout sym 0.5
symbol :: SymbolHandle -> Int -> Bool -> Layer SymbolHandle
symbol dat num_layers with_batch_norm =
getFeature dat layers filters with_batch_norm True >>= getTopFeature
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])
vgg16 dat num_classes = do
sym <- sequential "features" $ symbol dat 16 False
named "output" $ fullyConnected (#data := sym .& #num_hidden := num_classes .& Nil)