orthotope-hmatrix-0.1.2.0: Data/Array/Shaped/Convolve.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE NoStarIsType #-}
module Data.Array.Shaped.Convolve(convolve) where
import Data.Array.Shaped
import Data.Array.Shaped.MatMul
import Data.Array.Internal.Shape
import GHC.TypeLits
import qualified Numeric.LinearAlgebra as N
-- | Convolve the /n/ outer dimensions with the given kernel.
-- There is no padding nor striding.
-- The input has shape /spatialSh/ ++ /channelSh/,
-- the kernel has shape /spatialKernelSh/ ++ /channelSh/ ++ /featureSh/,
-- and the result has shape /spatialOutSh/ ++ /featureSh/.
-- The /n/ gives the rank of the /spatialSh/.
--
-- Example:
-- @
-- i :: Array [20,30,3] T -- 20x30 image with 3 channels
-- k :: Array [5,5,3,8] T -- 5x5 kernel with 8 output features
-- convolve @2 i k :: Array [16,26,8] T
-- @
convolve :: forall (n :: Nat) ish ksh osh wsh a ksc ksf i ws isp iwc .
( i ~ Rank ish -- input rank
, ws ~ Take n ksh -- window size
, Window ws ish wsh, KnownNat (Rank ws)
, ksc ~ Size (Take i ksh) -- spatial + channels
, ksf ~ Size (Drop i ksh) -- features
, isp ~ Size (Take n wsh) -- spatial
, iwc ~ Size (Drop n wsh) -- kernel + channels
, iwc ~ ksc
, osh ~ (Take n wsh ++ Drop i ksh)
, Size wsh ~ (isp * iwc)
, Size ksh ~ (ksc * ksf)
, Size osh ~ (isp * ksf)
, Shape wsh, Shape ksh, Shape osh
, KnownNat ksc, KnownNat isp, KnownNat ksf
, N.Numeric a
) =>
Array ish a -> Array ksh a -> Array osh a
convolve i k =
let iw :: Array wsh a
iw = window @ws i
ir :: Array [isp, iwc] a
ir = reshape iw
kr :: Array [ksc, ksf] a
kr = reshape k
m :: Array [isp, ksf] a
m = matMul ir kr
r :: Array osh a
r = reshape m
in r
_example :: Array [20,30,3] Float -> Array [5,5,3,8] Float -> Array [16,26,8] Float
_example = convolve @2