on master help sign in
Add c 3d pad and crop functions
commit7af621cbb6b4208f4c111d7ae87de67cca9e748e authorHuw Campbell <huw.campbell@ambiata.com> dateThu 2 Feb 2017, 20:27 (10 years ago) parenta23103e
17 files changed+581−93
cbits/pad.c+44 cbits/pad.h+13 grenade.cabal+10−1 src/Grenade.hs+3−1 src/Grenade/Core/Layer.hs+2−24 src/Grenade/Core/Network.hs+10−5 src/Grenade/Core/Shape.hs+19−3 src/Grenade/Graph/Core/Network.hs−39 src/Grenade/Layers/Concat.hs+125 src/Grenade/Layers/Crop.hs+35 src/Grenade/Layers/Inception.hs+42 src/Grenade/Layers/Internal/Pad.hs+125 src/Grenade/Layers/Merge.hs+55 src/Grenade/Layers/Pad.hs+35 src/Grenade/Layers/Flatten.hs → src/Grenade/Layers/Reshape.hs+22−17 src/Grenade/Layers/Trivial.hs+29 src/Grenade/Recurrent/Core/Network.hs+12−3
cbits/pad.cnew file+44
@@ -0,0 +1,44 @@
1+#include "pad.h"
2+
3+void pad_cpu(const double* data, const int channels,
4+ const int height, const int width, const int pad_left, const int pad_top,
5+ const int pad_right, const int pad_bottom,
6+ double* data_padded) {
7+
8+ const int pad_width = width + pad_left + pad_right;
9+ const int pad_height = height + pad_top + pad_bottom;
10+ const int channel_size = height * width;
11+
12+ memset(data_padded, 0, pad_height * pad_width * channels * sizeof(double));
13+
14+ for (int channel = 0; channel < channels; channel++) {
15+ double* px = data_padded + (pad_width * pad_top + pad_left) + channel * (pad_width * pad_height);
16+ for (int y = 0; y < height; y++) {
17+ for (int x = 0; x < width; x++) {
18+ *(px++) = data[y * width + x + channel_size * channel];
19+ }
20+ px += pad_left + pad_right;
21+ }
22+ }
23+}
24+
25+void crop_cpu(double* data, const int channels,
26+ const int height, const int width, const int crop_left, const int crop_top,
27+ const int crop_right, const int crop_bottom,
28+ double* data_cropped) {
29+
30+ const int crop_width = width + crop_left + crop_right;
31+ const int crop_height = height + crop_top + crop_bottom;
32+
33+ const int channel_size = height * width;
34+
35+ for (int channel = 0; channel < channels; channel++) {
36+ double* px = data + (crop_width * crop_top + crop_left) + channel * (crop_width * crop_height);
37+ for (int y = 0; y < height; y++) {
38+ for (int x = 0; x < width; x++) {
39+ data_cropped[y * width + x + channel_size * channel] = *(px++);
40+ }
41+ px += crop_left + crop_right;
42+ }
43+ }
44+}
cbits/pad.hnew file+13
@@ -0,0 +1,13 @@
1+#include <stdio.h>
2+#include <stdint.h>
3+#include <string.h>
4+
5+void pad_cpu(const double* data_im, const int channels,
6+ const int height, const int width, const int pad_left, const int pad_top,
7+ const int pad_right, const int pad_bottom,
8+ double* data_col);
9+
10+void crop_cpu(double* data_im, const int channels,
11+ const int height, const int width, const int crop_left, const int crop_top,
12+ const int crop_right, const int crop_bottom,
13+ double* data_col);
grenade.cabal+10−1
@@ -13,6 +13,10 @@ description: grenade.
1313extra-source-files:
1414 cbits/im2col.h
1515 cbits/im2col.c
16+ cbits/gradient_decent.h
17+ cbits/gradient_decent.c
18+ cbits/pad.h
19+ cbits/pad.c
1620
1721library
1822 build-depends:
@@ -50,11 +54,13 @@ library
5054 Grenade.Core.Runner
5155 Grenade.Core.Shape
5256 Grenade.Layers.Crop
57+ Grenade.Layers.Concat
5358 Grenade.Layers.Convolution
5459 Grenade.Layers.Dropout
5560 Grenade.Layers.FullyConnected
56− Grenade.Layers.Flatten
61+ Grenade.Layers.Reshape
5762 Grenade.Layers.Logit
63+ Grenade.Layers.Merge
5864 Grenade.Layers.Relu
5965 Grenade.Layers.Elu
6066 Grenade.Layers.Tanh
@@ -62,6 +68,7 @@ library
6268 Grenade.Layers.Pooling
6369
6470 Grenade.Layers.Internal.Convolution
71+ Grenade.Layers.Internal.Pad
6572 Grenade.Layers.Internal.Pooling
6673 Grenade.Layers.Internal.Update
6774
@@ -77,8 +84,10 @@ library
7784
7885 includes: cbits/im2col.h
7986 cbits/gradient_decent.h
87+ cbits/pad.h
8088 c-sources: cbits/im2col.c
8189 cbits/gradient_decent.c
90+ cbits/pad.c
8291
8392 cc-options: -std=c99 -O3 -msse4.2 -Wall -Werror -DCABAL=1
8493
src/Grenade.hs+3−1
@@ -7,13 +7,15 @@ import Grenade.Core.Layer as X
77import Grenade.Core.Network as X
88import Grenade.Core.Runner as X
99import Grenade.Core.Shape as X
10+import Grenade.Layers.Concat as X
1011import Grenade.Layers.Crop as X
1112import Grenade.Layers.Dropout as X
1213import Grenade.Layers.Pad as X
1314import Grenade.Layers.Pooling as X
14−import Grenade.Layers.Flatten as X
15+import Grenade.Layers.Reshape as X
1516import Grenade.Layers.FullyConnected as X
1617import Grenade.Layers.Logit as X
18+import Grenade.Layers.Merge as X
1719import Grenade.Layers.Convolution as X
1820import Grenade.Layers.Relu as X
1921import Grenade.Layers.Elu as X
src/Grenade/Core/Layer.hs+2−24
@@ -21,7 +21,6 @@ module Grenade.Core.Layer (
2121import Control.Monad.Random (MonadRandom)
2222
2323import Data.List ( foldl' )
24−import Data.Singletons
2524
2625import Grenade.Core.Shape
2726import Grenade.Core.LearningParameters
@@ -29,7 +28,6 @@ import Grenade.Core.LearningParameters
2928-- | Class for updating a layer. All layers implement this, and it is
3029-- shape independent.
3130class UpdateLayer x where
32− {-# MINIMAL runUpdate, createRandom #-}
3331 -- | The type for the gradient for this layer.
3432 -- Unit if there isn't a gradient to pass back.
3533 type Gradient x :: *
@@ -43,6 +41,8 @@ class UpdateLayer x where
4341 runUpdates :: LearningParameters -> x -> [Gradient x] -> x
4442 runUpdates rate = foldl' (runUpdate rate)
4543
44+ {-# MINIMAL runUpdate, createRandom #-}
45+
4646-- | Class for a layer. All layers implement this, however, they don't
4747-- need to implement it for all shapes, only ones which are appropriate.
4848class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
@@ -58,25 +58,3 @@ class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
5858 -- the layer above.
5959 -- Returns the gradient layer and the derivatives to push back further.
6060 runBackwards :: x -> Tape x i o -> S o -> (Gradient x, S i)
61−
62−
63−-- | Run two layers in parallel, combining their outputs.
64−-- This just kind of "smooshes" the weights together.
65−instance (UpdateLayer x, UpdateLayer y) => UpdateLayer (x, y) where
66− type Gradient (x, y) = (Gradient x, Gradient y)
67− runUpdate lr (x, y) (x', y') = (runUpdate lr x x', runUpdate lr y y')
68− createRandom = (,) <$> createRandom <*> createRandom
69−
70−-- | Combine the outputs and the inputs, summing the output shape
71−instance (SingI i, SingI o, Layer x i o, Layer y i o) => Layer (x, y) i o where
72− type Tape (x, y) i o = (Tape x i o, Tape y i o)
73−
74− runForwards (x, y) input =
75− let (xT, xOut) = runForwards x input
76− (yT, yOut) = runForwards y input
77− in ((xT, yT), xOut + yOut)
78−
79− runBackwards (x, y) (xTape, yTape) o =
80− let (x', xB) = runBackwards x xTape o
81− (y', yB) = runBackwards y yTape o
82− in ((x', y'), xB + yB)
src/Grenade/Core/Network.hs+10−5
@@ -46,8 +46,13 @@ import Grenade.Core.Shape
4646-- Can be considered to be a heterogeneous list of layers which are able to
4747-- transform the data shapes of the network.
4848data Network :: [*] -> [Shape] -> * where
49− NNil :: SingI i => Network '[] '[i]
50− (:~>) :: (SingI i, SingI h, Layer x i h) => !x -> !(Network xs (h ': hs)) -> Network (x ': xs) (i ': h ': hs)
49+ NNil :: SingI i
50+ => Network '[] '[i]
51+
52+ (:~>) :: (SingI i, SingI h, Layer x i h)
53+ => !x
54+ -> !(Network xs (h ': hs))
55+ -> Network (x ': xs) (i ': h ': hs)
5156infixr 5 :~>
5257
5358instance Show (Network '[] '[i]) where
@@ -66,13 +71,13 @@ applyUpdate rate (layer :~> rest) (gradient :/> grest)
6671
6772
6873-- | Gradients of a network.
69−-- Parameterised on the layers of a Network.
74+-- Parameterised on the layers of the network.
7075data Gradients :: [*] -> * where
7176 GNil :: Gradients '[]
7277 (:/>) :: UpdateLayer x => Gradient x -> Gradients xs -> Gradients (x ': xs)
7378
74−-- | Gradients of a network.
75−-- Parameterised on the layers of a Network.
79+-- | Wegnert Tapes of a network.
80+-- Parameterised on the layers and shapes of the network.
7681data Tapes :: [*] -> [Shape] -> * where
7782 TNil :: SingI i => Tapes '[] '[i]
7883 (:\>) :: (SingI i, SingI h, Layer x i h) => !(Tape x i h) -> !(Tapes xs (h ': hs)) -> Tapes (x ': xs) (i ': h ': hs)
src/Grenade/Core/Shape.hs+19−3
@@ -48,21 +48,37 @@ import qualified Numeric.LinearAlgebra as NLA
4848-- | The current shapes we accept.
4949-- at the moment this is just one, two, and three dimensional
5050-- Vectors/Matricies.
51+--
52+-- These are only used with DataKinds, as Kind `Shape`, with Types 'D1, 'D2, 'D3.
5153data Shape
5254 = D1 Nat
55+ -- ^ One dimensional vector
5356 | D2 Nat Nat
57+ -- ^ Two dimensional matrix. Row, Column.
5458 | D3 Nat Nat Nat
59+ -- ^ Three dimensional matrix. Row, Column, Channels.
5560
5661-- | Given a Shape n, these are the possible data structures with that shape.
5762-- All shapes are held in contiguous memory.
5863-- 3D is held in a matrix (usually row oriented) which has height depth * rows.
5964data S (n :: Shape) where
60− S1D :: ( KnownNat o ) => R o -> S ('D1 o)
61− S2D :: ( KnownNat rows, KnownNat columns ) => L rows columns -> S ('D2 rows columns)
65+ -- | One dimensional data
66+ S1D :: ( KnownNat len )
67+ => R len
68+ -> S ('D1 len)
69+
70+ -- | Two dimensional data
71+ S2D :: ( KnownNat rows, KnownNat columns )
72+ => L rows columns
73+ -> S ('D2 rows columns)
74+
75+ -- | Three dimensional data
6276 S3D :: ( KnownNat rows
6377 , KnownNat columns
6478 , KnownNat depth
65− , KnownNat (rows * depth)) => L (rows * depth) columns -> S ('D3 rows columns depth)
79+ , KnownNat (rows * depth))
80+ => L (rows * depth) columns
81+ -> S ('D3 rows columns depth)
6682
6783deriving instance Show (S n)
6884
src/Grenade/Graph/Core/Network.hsdeleted−39
@@ -1,39 +0,0 @@
1−{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE GADTs #-}
3−{-# LANGUAGE TypeFamilies #-}
4−{-# LANGUAGE TypeOperators #-}
5−{-# LANGUAGE FlexibleContexts #-}
6−{-# LANGUAGE ScopedTypeVariables #-}
7−{-# LANGUAGE RankNTypes #-}
8−
9−{-|
10−Module : Grenade.Graph.Core.Network
11−Description : Core definition of the Shapes of data we understand
12−Copyright : (c) Huw Campbell, 2016-2017
13−License : BSD2
14−Stability : experimental
15−
16−This module defines the core data types for the shapes of data that
17−are understood by Grenade.
18−-}
19−module Grenade.Graph.Core.Network (
20− Fin (..)
21− ) where
22−
23−import Data.Constraint
24−import Data.Singletons
25−import Data.Proxy
26−
27−import Grenade
28−
29−import GHC.TypeLits
30−
31−data Edge :: * where
32− E :: Fin n -> Shape -> Edge
33−
34−data Fin n where
35− Fin0 :: Fin (n + 1)
36− FinS :: Fin n -> Fin (n + 1)
37−
38−data Network :: [*] -> [Edge] -> * where { }
39−
src/Grenade/Layers/Concat.hsnew file+125
@@ -0,0 +1,125 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE FlexibleContexts #-}
7+{-# LANGUAGE RankNTypes #-}
8+{-# LANGUAGE FlexibleInstances #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE StandaloneDeriving #-}
11+{-|
12+Module : Grenade.Core.Network
13+Description : Core definition a simple neural etwork
14+Copyright : (c) Huw Campbell, 2016-2017
15+License : BSD2
16+Stability : experimental
17+-}
18+module Grenade.Layers.Concat (
19+ Concat (..)
20+ ) where
21+
22+import Data.Singletons
23+import GHC.TypeLits
24+
25+import Grenade.Core
26+
27+import Numeric.LinearAlgebra.Static ( row, (===), splitRows, unrow, (#), split, R )
28+
29+-- | A Concatentating Layer.
30+--
31+-- This layer shares it's input state between two sublayers, and concatenates their output.
32+--
33+-- With Networks able to be Layers, this allows for very expressive composition of complex Networks.
34+--
35+-- The Concat layer has a few instances, which allow one to flexibly "bash" together the outputs.
36+--
37+-- Two 1D vectors, can go to a 2D shape with 2 rows if their lengths are identical.
38+-- Any 2 1D vectors can also become a longer 1D Vector.
39+--
40+-- 3D images become 3D images with more channels. The sizes must be the same, one can use Pad
41+-- and Crop layers to ensure this is the case.
42+data Concat :: Shape -> * -> Shape -> * -> * where
43+ Concat :: x -> y -> Concat m x n y
44+
45+instance (Show x, Show y) => Show (Concat m x n y) where
46+ show (Concat x y) = "Concat\n" ++ show x ++ "\n" ++ show y
47+
48+-- | Run two layers in parallel, combining their outputs.
49+instance (UpdateLayer x, UpdateLayer y) => UpdateLayer (Concat m x n y) where
50+ type Gradient (Concat m x n y) = (Gradient x, Gradient y)
51+ runUpdate lr (Concat x y) (x', y') = Concat (runUpdate lr x x') (runUpdate lr y y')
52+ createRandom = Concat <$> createRandom <*> createRandom
53+
54+instance ( SingI i
55+ , Layer x i ('D1 o)
56+ , Layer y i ('D1 o)
57+ ) => Layer (Concat ('D1 o) x ('D1 o) y) i ('D2 2 o) where
58+ type Tape (Concat ('D1 o) x ('D1 o) y) i ('D2 2 o) = (Tape x i ('D1 o), Tape y i ('D1 o))
59+
60+ runForwards (Concat x y) input =
61+ let (xT, xOut :: S ('D1 o)) = runForwards x input
62+ (yT, yOut :: S ('D1 o)) = runForwards y input
63+ in case (xOut, yOut) of
64+ (S1D xOut', S1D yOut') ->
65+ ((xT, yT), S2D (row xOut' === row yOut'))
66+
67+ runBackwards (Concat x y) (xTape, yTape) (S2D o) =
68+ let (ox, oy) = splitRows o
69+ (x', xB :: S i) = runBackwards x xTape (S1D $ unrow ox)
70+ (y', yB :: S i) = runBackwards y yTape (S1D $ unrow oy)
71+ in ((x', y'), xB + yB)
72+
73+instance ( SingI i
74+ , Layer x i ('D1 m)
75+ , Layer y i ('D1 n)
76+ , KnownNat o
77+ , KnownNat m
78+ , KnownNat n
79+ , o ~ (m + n)
80+ , n ~ (o - m)
81+ , (m <=? o) ~ 'True
82+ ) => Layer (Concat ('D1 m) x ('D1 n) y) i ('D1 o) where
83+ type Tape (Concat ('D1 m) x ('D1 n) y) i ('D1 o) = (Tape x i ('D1 m), Tape y i ('D1 n))
84+
85+ runForwards (Concat x y) input =
86+ let (xT, xOut :: S ('D1 m)) = runForwards x input
87+ (yT, yOut :: S ('D1 n)) = runForwards y input
88+ in case (xOut, yOut) of
89+ (S1D xOut', S1D yOut') ->
90+ ((xT, yT), S1D (xOut' # yOut'))
91+
92+ runBackwards (Concat x y) (xTape, yTape) (S1D o) =
93+ let (ox :: R m , oy :: R n) = split o
94+ (x', xB :: S i) = runBackwards x xTape (S1D ox)
95+ (y', yB :: S i) = runBackwards y yTape (S1D oy)
96+ in ((x', y'), xB + yB)
97+
98+-- | Concat 3D shapes, increasing the number of channels.
99+instance ( SingI i
100+ , Layer x i ('D3 rows cols m)
101+ , Layer y i ('D3 rows cols n)
102+ , KnownNat (rows * n)
103+ , KnownNat (rows * m)
104+ , KnownNat (rows * o)
105+ , KnownNat o
106+ , KnownNat m
107+ , KnownNat n
108+ , ((rows * m) + (rows * n)) ~ (rows * o)
109+ , ((rows * o) - (rows * m)) ~ (rows * n)
110+ , ((rows * m) <=? (rows * o)) ~ 'True
111+ ) => Layer (Concat ('D3 rows cols m) x ('D3 rows cols n) y) i ('D3 rows cols o) where
112+ type Tape (Concat ('D3 rows cols m) x ('D3 rows cols n) y) i ('D3 rows cols o) = (Tape x i ('D3 rows cols m), Tape y i ('D3 rows cols n))
113+
114+ runForwards (Concat x y) input =
115+ let (xT, xOut :: S ('D3 rows cols m)) = runForwards x input
116+ (yT, yOut :: S ('D3 rows cols n)) = runForwards y input
117+ in case (xOut, yOut) of
118+ (S3D xOut', S3D yOut') ->
119+ ((xT, yT), S3D (xOut' === yOut'))
120+
121+ runBackwards (Concat x y) (xTape, yTape) (S3D o) =
122+ let (ox, oy) = splitRows o
123+ (x', xB :: S i) = runBackwards x xTape (S3D ox :: S ('D3 rows cols m))
124+ (y', yB :: S i) = runBackwards y yTape (S3D oy :: S ('D3 rows cols n))
125+ in ((x', y'), xB + yB)
src/Grenade/Layers/Crop.hs+35
@@ -3,6 +3,7 @@
33{-# LANGUAGE GADTs #-}
44{-# LANGUAGE TypeOperators #-}
55{-# LANGUAGE TypeFamilies #-}
6+{-# LANGUAGE FlexibleContexts #-}
67{-# LANGUAGE MultiParamTypeClasses #-}
78module Grenade.Layers.Crop (
89 Crop (..)
@@ -14,6 +15,7 @@ import Data.Singletons.TypeLits
1415import GHC.TypeLits
1516
1617import Grenade.Core
18+import Grenade.Layers.Internal.Pad
1719
1820import Numeric.LinearAlgebra (konst, subMatrix, diagBlock)
1921import Numeric.LinearAlgebra.Static (extract, create)
@@ -62,3 +64,36 @@ instance ( KnownNat cropLeft
6264 eo = extract dEdy
6365 vs = diagBlock [konst 0 (cropt,cropl), eo, konst 0 (cropb,cropr)]
6466 in ((), S2D . fromJust . create $ vs)
67+
68+
69+-- | A two dimentional image can be cropped.
70+instance ( KnownNat cropLeft
71+ , KnownNat cropTop
72+ , KnownNat cropRight
73+ , KnownNat cropBottom
74+ , KnownNat inputRows
75+ , KnownNat inputColumns
76+ , KnownNat outputRows
77+ , KnownNat outputColumns
78+ , KnownNat channels
79+ , KnownNat (inputRows * channels)
80+ , KnownNat (outputRows * channels)
81+ , (outputRows + cropTop + cropBottom) ~ inputRows
82+ , (outputColumns + cropLeft + cropRight) ~ inputColumns
83+ ) => Layer (Crop cropLeft cropTop cropRight cropBottom) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) where
84+ type Tape (Crop cropLeft cropTop cropRight cropBottom) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) = ()
85+ runForwards Crop input =
86+ let cropl = Proxy :: Proxy cropLeft
87+ cropt = Proxy :: Proxy cropTop
88+ cropr = Proxy :: Proxy cropRight
89+ cropb = Proxy :: Proxy cropBottom
90+ cropped = crop cropl cropt cropr cropb input
91+ in ((), cropped)
92+
93+ runBackwards Crop () gradient =
94+ let cropl = Proxy :: Proxy cropLeft
95+ cropt = Proxy :: Proxy cropTop
96+ cropr = Proxy :: Proxy cropRight
97+ cropb = Proxy :: Proxy cropBottom
98+ padded = pad cropl cropt cropr cropb gradient
99+ in ((), padded)
src/Grenade/Layers/Inception.hsnew file+42
@@ -0,0 +1,42 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE FlexibleContexts #-}
7+{-# LANGUAGE RankNTypes #-}
8+{-# LANGUAGE FlexibleInstances #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-|
11+Module : Grenade.Core.Network
12+Description : Core definition a simple neural etwork
13+Copyright : (c) Huw Campbell, 2016-2017
14+License : BSD2
15+Stability : experimental
16+-}
17+module Grenade.Layers.Inception (
18+ Concat (..)
19+ ) where
20+
21+import Data.Singletons
22+import GHC.TypeLits
23+
24+import Grenade.Core
25+import Grenade.Layers.Convolution
26+import Grenade.Layers.Pad
27+import Grenade.Layers.Pooling
28+import Grenade.Layers.Relu
29+import Grenade.Layers.Concat
30+
31+type Inception rows cols channels chx chy
32+ = Network '[ Concat ('D3 (rows - 5) (rows - 5) chx) (Inception3x3 rows cols channels chx) ('D3 (rows - 5) (rows - 5) chy) (Inception5x5 rows cols channels chy) ]
33+ '[ 'D3 rows cols channels, 'D3 (rows -2) (cols -2) (chx + chy) ]
34+
35+type Inception3x3 rows cols channels chx
36+ = Network '[ Convolution channels chx 3 3 1 1 ]
37+ '[ 'D3 rows cols channels, 'D3 (rows -2) (cols -2) chx ]
38+
39+type Inception5x5 rows cols channels chx
40+ = Network '[ Convolution channels chx 5 5 1 1, Pad 1 1 1 1 ]
41+ '[ 'D3 rows cols channels, 'D3 (rows -4) (cols -4) chx, 'D3 (rows -2) (cols -2) chx ]
42+
src/Grenade/Layers/Internal/Pad.hsnew file+125
@@ -0,0 +1,125 @@
1+{-# LANGUAGE ForeignFunctionInterface #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+{-# LANGUAGE GADTs #-}
5+{-# LANGUAGE TypeOperators #-}
6+{-# LANGUAGE TypeFamilies #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE FlexibleInstances #-}
9+{-# LANGUAGE FlexibleContexts #-}
10+{-# LANGUAGE PolyKinds #-}
11+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
12+
13+module Grenade.Layers.Internal.Pad (
14+ pad
15+ , crop
16+ ) where
17+
18+import Data.Maybe ( fromJust )
19+import Data.Proxy
20+import qualified Data.Vector.Storable as U ( unsafeToForeignPtr0, unsafeFromForeignPtr0 )
21+
22+import GHC.TypeLits
23+
24+import Grenade.Core
25+
26+import Foreign ( mallocForeignPtrArray, withForeignPtr )
27+import Foreign.Ptr ( Ptr )
28+
29+import Numeric.LinearAlgebra ( flatten )
30+import Numeric.LinearAlgebra.Static ( extract )
31+
32+import System.IO.Unsafe ( unsafePerformIO )
33+
34+pad :: forall padLeft padTop padRight padBottom rows rows' cols cols' channels.
35+ ( KnownNat padLeft
36+ , KnownNat padTop
37+ , KnownNat padRight
38+ , KnownNat padBottom
39+ , KnownNat rows
40+ , KnownNat rows'
41+ , KnownNat cols
42+ , KnownNat cols'
43+ , KnownNat channels
44+ , rows' ~ (rows + padTop + padBottom)
45+ , cols' ~ (cols + padLeft + padRight)
46+ , KnownNat (rows' * channels)
47+ ) => Proxy padLeft
48+ -> Proxy padTop
49+ -> Proxy padRight
50+ -> Proxy padBottom
51+ -> S ('D3 rows cols channels)
52+ -> S ('D3 rows' cols' channels)
53+pad _ _ _ _ (S3D m) =
54+ let channels = fromIntegral $ natVal (Proxy :: Proxy channels)
55+ padLeft = fromIntegral $ natVal (Proxy :: Proxy padLeft)
56+ padTop = fromIntegral $ natVal (Proxy :: Proxy padTop)
57+ padRight = fromIntegral $ natVal (Proxy :: Proxy padRight)
58+ padBottom = fromIntegral $ natVal (Proxy :: Proxy padBottom)
59+ rows = fromIntegral $ natVal (Proxy :: Proxy rows)
60+ cols = fromIntegral $ natVal (Proxy :: Proxy cols)
61+ rows' = fromIntegral $ natVal (Proxy :: Proxy rows')
62+ cols' = fromIntegral $ natVal (Proxy :: Proxy cols')
63+ outMatSize = rows' * cols' * channels
64+
65+ vec = flatten (extract m)
66+ in unsafePerformIO $ do
67+ outPtr <- mallocForeignPtrArray outMatSize
68+ let (inPtr, _) = U.unsafeToForeignPtr0 vec
69+
70+ withForeignPtr inPtr $ \inPtr' ->
71+ withForeignPtr outPtr $ \outPtr' ->
72+ pad_cpu inPtr' channels rows cols padLeft padTop padRight padBottom outPtr'
73+
74+ let matVec = U.unsafeFromForeignPtr0 outPtr outMatSize
75+ return (fromJust $ fromStorable matVec)
76+
77+foreign import ccall unsafe
78+ pad_cpu
79+ :: Ptr Double -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Ptr Double -> IO ()
80+
81+
82+crop :: forall padLeft padTop padRight padBottom rows rows' cols cols' channels.
83+ ( KnownNat padLeft
84+ , KnownNat padTop
85+ , KnownNat padRight
86+ , KnownNat padBottom
87+ , KnownNat rows
88+ , KnownNat rows'
89+ , KnownNat cols
90+ , KnownNat cols'
91+ , KnownNat channels
92+ , rows' ~ (rows + padTop + padBottom)
93+ , cols' ~ (cols + padLeft + padRight)
94+ , KnownNat (rows * channels)
95+ ) => Proxy padLeft
96+ -> Proxy padTop
97+ -> Proxy padRight
98+ -> Proxy padBottom
99+ -> S ('D3 rows' cols' channels)
100+ -> S ('D3 rows cols channels)
101+crop _ _ _ _ (S3D m) =
102+ let channels = fromIntegral $ natVal (Proxy :: Proxy channels)
103+ padLeft = fromIntegral $ natVal (Proxy :: Proxy padLeft)
104+ padTop = fromIntegral $ natVal (Proxy :: Proxy padTop)
105+ padRight = fromIntegral $ natVal (Proxy :: Proxy padRight)
106+ padBottom = fromIntegral $ natVal (Proxy :: Proxy padBottom)
107+ rows = fromIntegral $ natVal (Proxy :: Proxy rows)
108+ cols = fromIntegral $ natVal (Proxy :: Proxy cols)
109+ outMatSize = rows * cols * channels
110+
111+ vec = flatten (extract m)
112+ in unsafePerformIO $ do
113+ outPtr <- mallocForeignPtrArray outMatSize
114+ let (inPtr, _) = U.unsafeToForeignPtr0 vec
115+
116+ withForeignPtr inPtr $ \inPtr' ->
117+ withForeignPtr outPtr $ \outPtr' ->
118+ crop_cpu inPtr' channels rows cols padLeft padTop padRight padBottom outPtr'
119+
120+ let matVec = U.unsafeFromForeignPtr0 outPtr outMatSize
121+ return (fromJust $ fromStorable matVec)
122+
123+foreign import ccall unsafe
124+ crop_cpu
125+ :: Ptr Double -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Ptr Double -> IO ()
src/Grenade/Layers/Merge.hsnew file+55
@@ -0,0 +1,55 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE FlexibleContexts #-}
7+{-# LANGUAGE RankNTypes #-}
8+{-# LANGUAGE FlexibleInstances #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE StandaloneDeriving #-}
11+{-|
12+Module : Grenade.Core.Network
13+Description : Core definition a simple neural etwork
14+Copyright : (c) Huw Campbell, 2016-2017
15+License : BSD2
16+Stability : experimental
17+-}
18+module Grenade.Layers.Merge (
19+ Merge (..)
20+ ) where
21+
22+import Data.Singletons
23+
24+import Grenade.Core
25+
26+-- | A Merging layer.
27+--
28+-- Similar to Concat layer, except sums the activations instead of creating a larger
29+-- shape.
30+data Merge :: * -> * -> * where
31+ Merge :: x -> y -> Merge x y
32+
33+instance (Show x, Show y) => Show (Merge x y) where
34+ show (Merge x y) = "Merge\n" ++ show x ++ "\n" ++ show y
35+
36+-- | Run two layers in parallel, combining their outputs.
37+-- This just kind of "smooshes" the weights together.
38+instance (UpdateLayer x, UpdateLayer y) => UpdateLayer (Merge x y) where
39+ type Gradient (Merge x y) = (Gradient x, Gradient y)
40+ runUpdate lr (Merge x y) (x', y') = Merge (runUpdate lr x x') (runUpdate lr y y')
41+ createRandom = Merge <$> createRandom <*> createRandom
42+
43+-- | Combine the outputs and the inputs, summing the output shape
44+instance (SingI i, SingI o, Layer x i o, Layer y i o) => Layer (Merge x y) i o where
45+ type Tape (Merge x y) i o = (Tape x i o, Tape y i o)
46+
47+ runForwards (Merge x y) input =
48+ let (xT, xOut) = runForwards x input
49+ (yT, yOut) = runForwards y input
50+ in ((xT, yT), xOut + yOut)
51+
52+ runBackwards (Merge x y) (xTape, yTape) o =
53+ let (x', xB) = runBackwards x xTape o
54+ (y', yB) = runBackwards y yTape o
55+ in ((x', y'), xB + yB)
src/Grenade/Layers/Pad.hs+35
@@ -4,6 +4,7 @@
44{-# LANGUAGE TypeOperators #-}
55{-# LANGUAGE TypeFamilies #-}
66{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE FlexibleContexts #-}
78module Grenade.Layers.Pad (
89 Pad (..)
910 ) where
@@ -15,6 +16,7 @@ import Data.Singletons.TypeLits
1516import GHC.TypeLits
1617
1718import Grenade.Core
19+import Grenade.Layers.Internal.Pad
1820
1921import Numeric.LinearAlgebra (konst, subMatrix, diagBlock)
2022import Numeric.LinearAlgebra.Static (extract, create)
@@ -67,3 +69,36 @@ instance ( KnownNat padLeft
6769 m = extract dEdy
6870 vs = subMatrix (padt, padl) (nrows, ncols) m
6971 in ((), S2D . fromJust . create $ vs)
72+
73+
74+-- | A two dimentional image can be padped.
75+instance ( KnownNat padLeft
76+ , KnownNat padTop
77+ , KnownNat padRight
78+ , KnownNat padBottom
79+ , KnownNat inputRows
80+ , KnownNat inputColumns
81+ , KnownNat outputRows
82+ , KnownNat outputColumns
83+ , KnownNat channels
84+ , KnownNat (inputRows * channels)
85+ , KnownNat (outputRows * channels)
86+ , (inputRows + padTop + padBottom) ~ outputRows
87+ , (inputColumns + padLeft + padRight) ~ outputColumns
88+ ) => Layer (Pad padLeft padTop padRight padBottom) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) where
89+ type Tape (Pad padLeft padTop padRight padBottom) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) = ()
90+ runForwards Pad input =
91+ let padl = Proxy :: Proxy padLeft
92+ padt = Proxy :: Proxy padTop
93+ padr = Proxy :: Proxy padRight
94+ padb = Proxy :: Proxy padBottom
95+ padded = pad padl padt padr padb input
96+ in ((), padded)
97+
98+ runBackwards Pad () gradient =
99+ let padl = Proxy :: Proxy padLeft
100+ padt = Proxy :: Proxy padTop
101+ padr = Proxy :: Proxy padRight
102+ padb = Proxy :: Proxy padBottom
103+ cropped = crop padl padt padr padb gradient
104+ in ((), cropped)
src/Grenade/Layers/Flatten.hs → src/Grenade/Layers/Reshape.hsrenamed+22−17
@@ -3,8 +3,8 @@
33{-# LANGUAGE TypeFamilies #-}
44{-# LANGUAGE MultiParamTypeClasses #-}
55{-# LANGUAGE FlexibleContexts #-}
6−module Grenade.Layers.Flatten (
7− FlattenLayer (..)
6+module Grenade.Layers.Reshape (
7+ Reshape (..)
88 ) where
99
1010import Data.Serialize
@@ -17,39 +17,44 @@ import Numeric.LinearAlgebra.Data as LA ( flatten )
1717
1818import Grenade.Core
1919
20−-- | Flatten Layer
20+-- | Reshape Layer
2121--
2222-- Flattens input down to D1 from either 2D or 3D data.
2323--
2424-- Can also be used to turn a 3D image with only one channel into a 2D image.
25−data FlattenLayer = FlattenLayer
25+data Reshape = Reshape
2626 deriving Show
2727
28−instance UpdateLayer FlattenLayer where
29− type Gradient FlattenLayer = ()
30− runUpdate _ _ _ = FlattenLayer
31− createRandom = return FlattenLayer
28+instance UpdateLayer Reshape where
29+ type Gradient Reshape = ()
30+ runUpdate _ _ _ = Reshape
31+ createRandom = return Reshape
3232
33−instance (KnownNat a, KnownNat x, KnownNat y, a ~ (x * y)) => Layer FlattenLayer ('D2 x y) ('D1 a) where
34− type Tape FlattenLayer ('D2 x y) ('D1 a) = ()
33+instance (KnownNat a, KnownNat x, KnownNat y, a ~ (x * y)) => Layer Reshape ('D2 x y) ('D1 a) where
34+ type Tape Reshape ('D2 x y) ('D1 a) = ()
3535 runForwards _ (S2D y) = ((), fromJust' . fromStorable . flatten . extract $ y)
3636 runBackwards _ _ (S1D y) = ((), fromJust' . fromStorable . extract $ y)
3737
38−instance (KnownNat a, KnownNat x, KnownNat y, KnownNat (x * z), KnownNat z, a ~ (x * y * z)) => Layer FlattenLayer ('D3 x y z) ('D1 a) where
39− type Tape FlattenLayer ('D3 x y z) ('D1 a) = ()
38+instance (KnownNat a, KnownNat x, KnownNat y, KnownNat (x * z), KnownNat z, a ~ (x * y * z)) => Layer Reshape ('D3 x y z) ('D1 a) where
39+ type Tape Reshape ('D3 x y z) ('D1 a) = ()
4040 runForwards _ (S3D y) = ((), fromJust' . fromStorable . flatten . extract $ y)
4141 runBackwards _ _ (S1D y) = ((), fromJust' . fromStorable . extract $ y)
4242
43−instance (KnownNat y, KnownNat x, KnownNat z, z ~ 1) => Layer FlattenLayer ('D3 x y z) ('D2 x y) where
44− type Tape FlattenLayer ('D3 x y z) ('D2 x y) = ()
43+instance (KnownNat y, KnownNat x, KnownNat z, z ~ 1) => Layer Reshape ('D3 x y z) ('D2 x y) where
44+ type Tape Reshape ('D3 x y z) ('D2 x y) = ()
4545 runForwards _ (S3D y) = ((), S2D y)
4646 runBackwards _ _ (S2D y) = ((), S3D y)
4747
48−instance Serialize FlattenLayer where
48+instance (KnownNat y, KnownNat x, KnownNat z, z ~ 1) => Layer Reshape ('D2 x y) ('D3 x y z) where
49+ type Tape Reshape ('D2 x y) ('D3 x y z) = ()
50+ runForwards _ (S2D y) = ((), S3D y)
51+ runBackwards _ _ (S3D y) = ((), S2D y)
52+
53+instance Serialize Reshape where
4954 put _ = return ()
50− get = return FlattenLayer
55+ get = return Reshape
5156
5257
5358fromJust' :: Maybe x -> x
5459fromJust' (Just x) = x
55−fromJust' Nothing = error $ "FlattenLayer error: data shape couldn't be converted."
60+fromJust' Nothing = error $ "Reshape error: data shape couldn't be converted."
src/Grenade/Layers/Trivial.hsnew file+29
@@ -0,0 +1,29 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+module Grenade.Layers.Trivial (
7+ Trivial (..)
8+ ) where
9+
10+import Data.Serialize
11+
12+import Grenade.Core.Network
13+
14+-- | A trivial layer.
15+data Trivial = Trivial
16+ deriving Show
17+
18+instance Serialize Trivial where
19+ put _ = return ()
20+ get = return Trivial
21+
22+instance UpdateLayer Trivial where
23+ type Gradient Trivial = ()
24+ runUpdate _ _ _ = Trivial
25+ createRandom = return Trivial
26+
27+instance (a ~ b) => Layer Trivial a b where
28+ runForwards _ = id
29+ runBackwards _ _ y = ((), y)
src/Grenade/Recurrent/Core/Network.hs+12−3
@@ -54,9 +54,18 @@ class (RecurrentUpdateLayer x, SingI (RecurrentShape x)) => RecurrentLayer x (i
5454 runRecurrentBackwards :: x -> RecTape x i o -> S (RecurrentShape x) -> S o -> (Gradient x, S (RecurrentShape x), S i)
5555
5656data RecurrentNetwork :: [*] -> [Shape] -> * where
57− RNil :: SingI i => RecurrentNetwork '[] '[i]
58− (:~~>) :: (SingI i, Layer x i h) => !x -> !(RecurrentNetwork xs (h ': hs)) -> RecurrentNetwork (FeedForward x ': xs) (i ': h ': hs)
59− (:~@>) :: (SingI i, RecurrentLayer x i h) => !x -> !(RecurrentNetwork xs (h ': hs)) -> RecurrentNetwork (Recurrent x ': xs) (i ': h ': hs)
57+ RNil :: SingI i
58+ => RecurrentNetwork '[] '[i]
59+
60+ (:~~>) :: (SingI i, Layer x i h)
61+ => !x
62+ -> !(RecurrentNetwork xs (h ': hs))
63+ -> RecurrentNetwork (FeedForward x ': xs) (i ': h ': hs)
64+
65+ (:~@>) :: (SingI i, RecurrentLayer x i h)
66+ => !x
67+ -> !(RecurrentNetwork xs (h ': hs))
68+ -> RecurrentNetwork (Recurrent x ': xs) (i ': h ': hs)
6069infixr 5 :~~>
6170infixr 5 :~@>
6271