----------------------------------------------------------- -- | -- copyright: (c) 2016-2017 Tao He -- license: MIT -- maintainer: sighingnow@gmail.com -- -- Test suite for mxnet package. -- {-# OPTIONS_GHC -Wno-name-shadowing #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE TypeApplications #-} import qualified Data.Vector.Storable as V import Test.Tasty import Test.Tasty.HUnit import MXNet.Core.Base main :: IO () main = mxListAllOpNames >> defaultMain mxnetTest mxnetTest :: TestTree mxnetTest = testGroup "MXNet Test Suite" [ hmapTest , ndarrayTest , symbolTest ] hmapTest :: TestTree hmapTest = testGroup "HMap" [ testCase "Get after add" $ do let expected = 1 got = get @"a" (add @"a" (1 :: Int) nil) assertEqual "get after add" expected got ] ndarrayTest :: TestTree ndarrayTest = testGroup "NDArray" [ testCaseSteps "NDArray basic operation" $ \step -> do step "preparing ndarray" let sh = [2, 3, 4, 5] p = product sh arr <- array sh [1 .. fromIntegral $ product sh] :: IO (NDArray Float) step "shape and size" (d, sh') <- ndshape arr assertEqual "dimension should coincide" 4 d assertEqual "shape should coincide" sh sh' s <- ndsize arr assertEqual "size should coincide" p s step "arithmetic operators" b <- (arr + arr) .* 3 >>= (./ 2) r <- V.sum <$> items b let expected = 3 * (p * (p+1) `div` 2) assertEqual "sum of elements should be as expected" expected (round r) step "comparison with scalar" b <- _Maximum' arr 1000 r <- V.sum <$> items b let expected = 1000 * p assertEqual "_Maximum' should set the whole ndarray" expected (round r) , testCaseSteps "NDArray linear algebra" $ \step -> do step "preparing ndarray" a <- array [2, 3] [1 .. 6] step "ndarray dot product" b <- (a `dot`) =<< transpose a expected1 <- array [2, 2] [14, 32, 32, 77] :: IO (NDArray Float) assertEqual "a `dot` transpose a" expected1 b c <- transpose a >>= (`dot` a) expected2 <- array [3, 3] [17, 22, 27, 22, 29, 36, 27, 36, 45] :: IO (NDArray Float) assertEqual "transpose a `dot` a" expected2 c , testCaseSteps "NDArray activation" $ \step -> do step "preparing ndarray" a <- array [4] [-0.5, -0.1, 0.1, 0.5] step "relu activation" r <- activation a "relu" expected <- array [4] [0.0, 0.0, 0.1, 0.5] :: IO (NDArray Float) assertEqual "relu activation" expected r step "sigmoid activation" r <- activation a "sigmoid" expected <- array [4] [0.37754068, 0.4750208, 0.52497917, 0.62245935] :: IO (NDArray Float) assertEqual "sigmoid activation" expected r step "softrelu activation" r <- activation a "softrelu" expected <- array [4] [0.47407699, 0.64439672, 0.74439669, 0.97407699] :: IO (NDArray Float) assertEqual "softrelu activation" expected r step "tanh activation" r <- activation a "tanh" expected <- array [4] [-0.46211717, -0.099667996, 0.099667996, 0.46211717] :: IO (NDArray Float) assertEqual "tanh activation" expected r step "softmax activation" r <- softmaxActivation a expected <- array [4] [0.1422025, 0.21214119, 0.25910985, 0.38654646] :: IO (NDArray Float) assertEqual "softmax activation" expected r step "leakyReLU activation" -- for leakyReLU, input must be a multiple dimensions ndarray. a' <- array [1, 4] [-0.5, -0.1, 0.1, 0.5] r <- leakyReLU a' "leaky" expected <- array [1, 4] [-0.125, -0.025, 0.1, 0.5] :: IO (NDArray Float) assertEqual "leakyReLU activation" expected r ] symbolTest :: TestTree symbolTest = testGroup "Symbol" [ testCaseSteps "Symbol basic operation" $ \step -> do step "preparing symbol" a <- variable "a" :: IO (Symbol Float) step "get name" a' <- getName a assertEqual "get symbol name" "a" a' , testCaseSteps "Symbol bind ndarray data" $ \step -> do step "preparing symbol and ndarray" a <- variable "a" :: IO (Symbol Float) b <- variable "b" :: IO (Symbol Float) arr1 <- array [2, 3] [1 .. 6] arr2 <- array [2, 3] [5 .. 10] step "bind and arithmetic operators" c <- a + b .+ 2 >>= (./ 2) expected <- array [2, 3] [4 .. 9] exec <- bind c contextCPU [ ("a", arr1) , ("b", arr2) ] forward exec False [r] <- getOutputs exec assertEqual "bind and arithmetics with scalar" expected r step "bind and linear algebra" c <- (a `dot`) =<< transpose b expected <- array [2, 2] [38, 56, 92, 137] exec <- bind c contextCPU [ ("a", arr1) , ("b", arr2) ] forward exec False [r] <- getOutputs exec assertEqual "bind and a `dot` transpose b" expected r c <- transpose a >>= (`dot` b) expected <- array [3, 3] [ 37, 42, 47 , 50, 57, 64 , 63, 72, 81 ] exec <- bind c contextCPU [ ("a", arr1) , ("b", arr2) ] forward exec False [r] <- getOutputs exec assertEqual "bind and transpose a `dot` b" expected r step "bind and activation" c <- softmaxActivation a expected <- array [2, 3] [ 0.09003057, 0.24472848, 0.66524094 , 0.09003057, 0.24472848, 0.66524094 ] exec <- bind c contextCPU [ ("a", arr1) ] forward exec False [r] <- getOutputs exec assertEqual "bind and softmax activation" expected r c <- leakyReLU a "leaky" expected <- array [2, 3] [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 ] exec <- bind c contextCPU [ ("a", arr1) ] forward exec False [r] <- getOutputs exec assertEqual "bind and leakyReLU activation" expected r ]