on master help sign in
Make things faster
commitb090b5f073174f52dd16f9b7beccd5b4a43e06d6 authorHuw Campbell <huw.campbell@ambiata.com> dateThu 8 Dec 2016, 01:16 (10 years ago) parentd360438
16 files changed+314−107
grenade.cabal+1 src/Grenade/Core/Network.hs+1−1 src/Grenade/Core/Runner.hs+2−2 src/Grenade/Layers/Convolution.hs+23−80 src/Grenade/Layers/Convolution/Internal.hs+238 src/Grenade/Layers/Crop.hs+1−1 src/Grenade/Layers/Dropout.hs+2−2 src/Grenade/Layers/Flatten.hs+2−2 src/Grenade/Layers/FullyConnected.hs+1−1 src/Grenade/Layers/Fuse.hs+3−3 src/Grenade/Layers/Logit.hs+3−3 src/Grenade/Layers/Pad.hs+1−1 src/Grenade/Layers/Pooling.hs+3−3 src/Grenade/Layers/Relu.hs+3−3 src/Grenade/Layers/Tanh.hs+3−3 test/Test/Grenade/Layers/Convolution.hs+27−2
grenade.cabal+1
@@ -40,6 +40,7 @@ library
4040 Grenade.Core.Shape
4141 Grenade.Layers.Crop
4242 Grenade.Layers.Convolution
43+ Grenade.Layers.Convolution.Internal
4344 Grenade.Layers.Dropout
4445 Grenade.Layers.FullyConnected
4546 Grenade.Layers.Flatten
src/Grenade/Core/Network.hs+1−1
@@ -51,7 +51,7 @@ class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
5151 -- layer gave from the input and the back propagated derivatives from
5252 -- the layer above.
5353 -- Returns the gradient layer and the derivatives to push back further.
54− runBackards :: x -> S' i -> S' o -> (Gradient x, S' i)
54+ runBackwards :: x -> S' i -> S' o -> (Gradient x, S' i)
5555
5656-- | Type of a network.
5757-- The [*] type specifies the types of the layers. This is needed for parallel
src/Grenade/Core/Runner.hs+2−2
@@ -32,7 +32,7 @@ backPropagate network input target =
3232 -- recursively run the rest of the network, and get the gradients from above.
3333 (n', dWs') = go y n
3434 -- calculate the gradient for this layer to pass down,
35− (layer', dWs) = runBackards layer x dWs'
35+ (layer', dWs) = runBackwards layer x dWs'
3636
3737 in (layer' :/> n', dWs)
3838
@@ -40,7 +40,7 @@ backPropagate network input target =
4040 go !x (O layer)
4141 = let y = runForwards layer x
4242 -- the gradient (how much y affects the error)
43− (layer', dWs) = runBackards layer x (y - target)
43+ (layer', dWs) = runBackwards layer x (y - target)
4444
4545 in (OG layer', dWs)
4646
src/Grenade/Layers/Convolution.hs+23−80
@@ -16,26 +16,22 @@ module Grenade.Layers.Convolution (
1616 Convolution (..)
1717 , Convolution' (..)
1818 , randomConvolution
19− , im2col
20− , vid2col
21− , col2im
22− , col2vid
23− , fittingStarts
2419 ) where
2520
26−import Control.Monad.Random hiding (fromList)
21+import Control.Monad.Random hiding ( fromList )
2722import Data.Maybe
2823import Data.Proxy
2924import Data.Singletons.TypeLits
3025import GHC.TypeLits
3126
32−import Numeric.LinearAlgebra hiding (uniformSample, konst)
27+import Numeric.LinearAlgebra hiding ( uniformSample, konst )
3328import qualified Numeric.LinearAlgebra as LA
3429import Numeric.LinearAlgebra.Static hiding ((|||), build, toRows)
3530
3631import Grenade.Core.Network
3732import Grenade.Core.Shape
3833import Grenade.Core.Vector
34+import Grenade.Layers.Convolution.Internal
3935
4036-- | A convolution layer for a neural network.
4137-- This uses the im2col convolution trick popularised by Caffe, which essentially turns the
@@ -153,18 +149,21 @@ instance ( KnownNat kernelRows
153149 runForwards (Convolution kernel _) (S2D' input) =
154150 let ex = extract input
155151 ek = extract kernel
152+ ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
153+ iy = fromIntegral $ natVal (Proxy :: Proxy inputCols)
156154 kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
157155 ky = fromIntegral $ natVal (Proxy :: Proxy kernelCols)
158156 sx = fromIntegral $ natVal (Proxy :: Proxy strideRows)
159157 sy = fromIntegral $ natVal (Proxy :: Proxy strideCols)
160158 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
161159 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
162− c = im2col kx ky sx sy ex
160+ c = im2colUnsafe kx ky sx sy ix iy ex
163161 mt = c LA.<> ek
164− r = col2vid 1 1 1 1 ox oy mt
162+ r = col2vidUnsafe 1 1 1 1 ox oy mt
165163 rs = fmap (fromJust . create) r
166164 in S3D' $ mkVector rs
167− runBackards (Convolution kernel _) (S2D' input) (S3D' dEdy) =
165+
166+ runBackwards (Convolution kernel _) (S2D' input) (S3D' dEdy) =
168167 let ex = extract input
169168 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
170169 iy = fromIntegral $ natVal (Proxy :: Proxy inputCols)
@@ -174,17 +173,19 @@ instance ( KnownNat kernelRows
174173 sy = fromIntegral $ natVal (Proxy :: Proxy strideCols)
175174 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
176175 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
177− c = im2col kx ky sx sy ex
176+ fl = fromIntegral $ natVal (Proxy :: Proxy filters)
177+
178+ c = im2colUnsafe kx ky sx sy ix iy ex
178179
179180 eo = vecToList $ fmap extract dEdy
180181 ek = extract kernel
181182
182− vs = vid2col 1 1 1 1 ox oy eo
183+ vs = vid2colUnsafe fl 1 1 1 1 ox oy eo
183184
184185 kN = fromJust . create $ tr c LA.<> vs
185186 dW = vs LA.<> tr ek
186187
187− xW = col2im kx ky sx sy ix iy dW
188+ xW = col2imUnsafe kx ky sx sy ix iy dW
188189 in (Convolution' kN, S2D' . fromJust . create $ xW)
189190
190191
@@ -215,12 +216,13 @@ instance ( KnownNat kernelRows
215216 sy = fromIntegral $ natVal (Proxy :: Proxy strideCols)
216217 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
217218 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
218− c = vid2col kx ky sx sy ix iy ex
219+ ch = fromIntegral $ natVal (Proxy :: Proxy channels)
220+ c = vid2colUnsafe ch kx ky sx sy ix iy ex
219221 mt = c LA.<> ek
220− r = col2vid 1 1 1 1 ox oy mt
222+ r = col2vidUnsafe 1 1 1 1 ox oy mt
221223 rs = fmap (fromJust . create) r
222224 in S3D' $ mkVector rs
223− runBackards (Convolution kernel _) (S3D' input) (S3D' dEdy) =
225+ runBackwards (Convolution kernel _) (S3D' input) (S3D' dEdy) =
224226 let ex = vecToList $ fmap extract input
225227 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
226228 iy = fromIntegral $ natVal (Proxy :: Proxy inputCols)
@@ -230,77 +232,18 @@ instance ( KnownNat kernelRows
230232 sy = fromIntegral $ natVal (Proxy :: Proxy strideCols)
231233 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
232234 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
233− c = vid2col kx ky sx sy ix iy ex
235+ ch = fromIntegral $ natVal (Proxy :: Proxy channels)
236+ fl = fromIntegral $ natVal (Proxy :: Proxy filters)
237+ c = vid2colUnsafe ch kx ky sx sy ix iy ex
234238
235239 eo = vecToList $ fmap extract dEdy
236240 ek = extract kernel
237241
238− vs = vid2col 1 1 1 1 ox oy eo
242+ vs = vid2colUnsafe fl 1 1 1 1 ox oy eo
239243
240244 kN = fromJust . create $ tr c LA.<> vs
241245
242246 dW = vs LA.<> tr ek
243247
244− xW = col2vid kx ky sx sy ix iy dW
248+ xW = col2vidUnsafe kx ky sx sy ix iy dW
245249 in (Convolution' kN, S3D' . mkVector . fmap (fromJust . create) $ xW)
246−
247−im2col :: Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
248−im2col nrows ncols srows scols m =
249− let starts = fittingStarts (rows m) nrows srows (cols m) ncols scols
250− in im2colFit starts nrows ncols m
251−
252−im2colFit :: [(Int,Int)] -> Int -> Int -> Matrix Double -> Matrix Double
253−im2colFit starts nrows ncols m =
254− let imRows = fmap (\start -> flatten $ subMatrix start (nrows, ncols) m) starts
255− in fromRows imRows
256−
257−vid2col :: Int -> Int -> Int -> Int -> Int -> Int -> [Matrix Double] -> Matrix Double
258−vid2col nrows ncols srows scols inputrows inputcols ms =
259− let starts = fittingStarts inputrows nrows srows inputcols ncols scols
260− subs = fmap (im2colFit starts nrows ncols) ms
261− in foldl1 (|||) subs
262−
263−col2vid :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> [Matrix Double]
264−col2vid nrows ncols srows scols drows dcols m =
265− let starts = fittingStart (cols m) (nrows * ncols) (nrows * ncols)
266− r = rows m
267− mats = fmap (\s -> subMatrix (0,s) (r, nrows * ncols) m) starts
268− colSts = fittingStarts drows nrows srows dcols ncols scols
269− in fmap (col2imfit colSts nrows ncols drows dcols) mats
270−
271−col2im :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
272−col2im krows kcols srows scols drows dcols m =
273− let starts = fittingStarts drows krows srows dcols kcols scols
274− in col2imfit starts krows kcols drows dcols m
275−
276−col2imfit :: [(Int,Int)] -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
277−col2imfit starts krows kcols drows dcols m =
278− let indicies = fmap (\[a,b] -> (a,b)) $ sequence [[0..(krows-1)], [0..(kcols-1)]]
279− convs = fmap (zip indicies . toList) . toRows $ m
280− pairs = zip convs starts
281− accums = concat $ fmap (\(conv',(stx',sty')) -> fmap (\((ix,iy), val) -> ((ix + stx', iy + sty'), val)) conv') pairs
282− in accum (LA.konst 0 (drows, dcols)) (+) accums
283−
284−
285−-- | These functions are not even remotely safe, but it's only called from the statically typed
286−-- commands, so we should be good ?!?!?
287−-- Returns the starting sub matrix locations which fit inside the larger matrix for the
288−-- convolution. Takes into account the stride and kernel size.
289−fittingStarts :: Int -> Int -> Int -> Int -> Int -> Int -> [(Int,Int)]
290−fittingStarts nrows kernelrows steprows ncols kernelcols stepcolsh =
291− let rs = fittingStart nrows kernelrows steprows
292− cs = fittingStart ncols kernelcols stepcolsh
293− ls = sequence [rs, cs]
294− in fmap (\[a,b] -> (a,b)) ls
295−
296−-- | Returns the starting sub vector which fit inside the larger vector for the
297−-- convolution. Takes into account the stride and kernel size.
298−fittingStart :: Int -> Int -> Int -> [Int]
299−fittingStart width kernel steps =
300− let go left | left + kernel < width
301− = left : go (left + steps)
302− | left + kernel == width
303− = left : []
304− | otherwise
305− = error "Kernel and step do not fit in matrix."
306− in go 0
src/Grenade/Layers/Convolution/Internal.hsnew file+238
@@ -0,0 +1,238 @@
1+module Grenade.Layers.Convolution.Internal (
2+ im2col
3+-- , im2colUnsafe
4+ , vid2col
5+ , col2im
6+ , col2imFit
7+ , col2vid
8+
9+ , col2vidUnsafe
10+ , col2imUnsafe
11+ , im2colUnsafe
12+ , vid2colUnsafe
13+ , fittingStarts
14+ ) where
15+
16+import Control.Monad.ST
17+import Control.Parallel.Strategies ( parMap, rseq )
18+
19+import Data.STRef
20+import Data.Foldable ( forM_ )
21+
22+import Numeric.LinearAlgebra hiding ( uniformSample, konst )
23+import qualified Numeric.LinearAlgebra as LA
24+import qualified Numeric.LinearAlgebra.Devel as U
25+
26+im2col :: Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
27+im2col nrows ncols srows scols m =
28+ let starts = fittingStarts (rows m) nrows srows (cols m) ncols scols
29+ in im2colFit starts nrows ncols m
30+
31+im2colFit :: [(Int,Int)] -> Int -> Int -> Matrix Double -> Matrix Double
32+im2colFit starts nrows ncols m =
33+ let imRows = fmap (\start -> flatten $ subMatrix start (nrows, ncols) m) starts
34+ in fromRows imRows
35+
36+vid2col :: Int -> Int -> Int -> Int -> Int -> Int -> [Matrix Double] -> Matrix Double
37+vid2col nrows ncols srows scols inputrows inputcols ms =
38+ let starts = fittingStarts inputrows nrows srows inputcols ncols scols
39+ subs = parMap rseq (im2colFit starts nrows ncols) ms
40+ in foldl1 (|||) subs
41+
42+col2vid :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> [Matrix Double]
43+col2vid krows kcols srows scols drows dcols m =
44+ let starts = fittingStart (cols m) (krows * kcols) (krows * kcols)
45+ r = rows m
46+ mats = fmap (\s -> subMatrix (0,s) (r, krows * kcols) m) starts
47+ colSts = fittingStarts drows krows srows dcols kcols scols
48+ in parMap rseq (col2imFit colSts krows kcols drows dcols) mats
49+
50+col2im :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
51+col2im krows kcols srows scols drows dcols m =
52+ let starts = fittingStarts drows krows srows dcols kcols scols
53+ in col2imFit starts krows kcols drows dcols m
54+
55+-- | These functions are not even remotely safe, but it's only called from the statically typed
56+-- commands, so we should be good ?!?!?
57+-- Returns the starting sub matrix locations which fit inside the larger matrix for the
58+-- convolution. Takes into account the stride and kernel size.
59+fittingStarts :: Int -> Int -> Int -> Int -> Int -> Int -> [(Int,Int)]
60+fittingStarts nrows kernelrows steprows ncols kernelcols stepcolsh =
61+ let rs = fittingStart nrows kernelrows steprows
62+ cs = fittingStart ncols kernelcols stepcolsh
63+ ls = sequence [rs, cs]
64+ in fmap (\[a,b] -> (a,b)) ls
65+
66+-- | Returns the starting sub vector which fit inside the larger vector for the
67+-- convolution. Takes into account the stride and kernel size.
68+fittingStart :: Int -> Int -> Int -> [Int]
69+fittingStart width kernel steps =
70+ let go left | left + kernel < width
71+ = left : go (left + steps)
72+ | left + kernel == width
73+ = [left]
74+ | otherwise
75+ = error "Kernel and step do not fit in matrix."
76+ in go 0
77+
78+col2imFit :: [(Int,Int)] -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
79+col2imFit starts krows kcols drows dcols m =
80+ let indicies = (\[a,b] -> (a,b)) <$> sequence [[0..(krows-1)], [0..(kcols-1)]]
81+ convs = fmap (zip indicies . toList) . toRows $ m
82+ pairs = zip convs starts
83+ accums = concatMap (\(conv',(stx',sty')) -> fmap (\((ix,iy), val) -> ((ix + stx', iy + sty'), val)) conv') pairs
84+ in accum (LA.konst 0 (drows, dcols)) (+) accums
85+
86+-- void col2im_cpu(const Dtype* data_col, const int channels,
87+-- const int height, const int width, const int kernel_h, const int kernel_w,
88+-- const int pad_h, const int pad_w,
89+-- const int stride_h, const int stride_w,
90+-- const int dilation_h, const int dilation_w,
91+-- Dtype* data_im) {
92+-- caffe_set(height * width * channels, Dtype(0), data_im);
93+-- const int output_h = (height + 2 * pad_h -
94+-- (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
95+-- const int output_w = (width + 2 * pad_w -
96+-- (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
97+-- const int channel_size = height * width;
98+-- for (int channel = channels; channel--; data_im += channel_size) {
99+-- for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
100+-- for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
101+-- int input_row = -pad_h + kernel_row * dilation_h;
102+-- for (int output_rows = output_h; output_rows; output_rows--) {
103+-- if (!is_a_ge_zero_and_a_lt_b(input_row, height)) {
104+-- data_col += output_w;
105+-- } else {
106+-- int input_col = -pad_w + kernel_col * dilation_w;
107+-- for (int output_col = output_w; output_col; output_col--) {
108+-- if (is_a_ge_zero_and_a_lt_b(input_col, width)) {
109+-- data_im[input_row * width + input_col] += *data_col;
110+-- }
111+-- data_col++;
112+-- input_col += stride_w;
113+-- }
114+-- }
115+-- input_row += stride_h;
116+-- }
117+-- }
118+-- }
119+-- }
120+-- }
121+
122+
123+-- let starts = fittingStart (cols m) (krows * kcols) (krows * kcols)
124+-- r = rows m
125+-- mats = fmap (\s -> subMatrix (0,s) (r, krows * kcols) m) starts
126+-- in parMap rseq (col2imUnsafe krows kcols srows scols drows dcols) mats
127+
128+col2imUnsafe :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
129+col2imUnsafe kernelRows kernelColumns strideRows strideColumns destinationRows destinationCols columnMatrix = U.runSTMatrix $ do
130+ let columnMatrixRows = rows columnMatrix
131+
132+ dataIm <- U.newMatrix 0 destinationRows destinationCols
133+
134+ offsetR <- newSTRef 0
135+ offsetC <- newSTRef 0
136+
137+ forM_ [0 .. columnMatrixRows - 1] $ \ir -> do
138+ inputColumn <- newSTRef 0
139+ forM_ [0 .. kernelRows -1] $ \kr ->
140+ forM_ [0 .. kernelColumns -1] $ \kc -> do
141+ ic <- readSTRef inputColumn
142+ offsetR' <- readSTRef offsetR
143+ offsetC' <- readSTRef offsetC
144+ U.modifyMatrix dataIm (kr + offsetR') (kc + offsetC') (+ atIndex columnMatrix (ir,ic))
145+ modifySTRef inputColumn (+1)
146+
147+ offsetC' <- readSTRef offsetC
148+ if offsetC' + kernelColumns < destinationCols
149+ then modifySTRef offsetC (+ strideColumns)
150+ else writeSTRef offsetC 0 >> modifySTRef offsetR (+ strideRows)
151+
152+ return dataIm
153+
154+col2vidUnsafe :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> [Matrix Double]
155+col2vidUnsafe kernelRows kernelColumns strideRows strideColumns destinationRows destinationCols columnMatrix = runST $ do
156+ let columnMatrixRows = rows columnMatrix
157+ let filters = cols columnMatrix `div` (kernelRows * kernelColumns)
158+
159+ dataIms <- traverse (\_ -> U.newMatrix 0 destinationRows destinationCols) [0 .. filters-1]
160+
161+ offsetR <- newSTRef 0
162+ offsetC <- newSTRef 0
163+ offsetM <- newSTRef 0
164+
165+ forM_ dataIms $ \dataIm -> do
166+ offsetM' <- readSTRef offsetM
167+ forM_ [0 .. columnMatrixRows - 1] $ \ir -> do
168+ inputColumn <- newSTRef 0
169+ forM_ [0 .. kernelRows -1] $ \kr ->
170+ forM_ [0 .. kernelColumns -1] $ \kc -> do
171+ ic <- readSTRef inputColumn
172+ offsetR' <- readSTRef offsetR
173+ offsetC' <- readSTRef offsetC
174+ U.modifyMatrix dataIm (kr + offsetR') (kc + offsetC') (+ atIndex columnMatrix (ir, ic + offsetM'))
175+ modifySTRef inputColumn (+1)
176+
177+ offsetC' <- readSTRef offsetC
178+ if offsetC' + kernelColumns < destinationCols
179+ then modifySTRef offsetC (+ strideColumns)
180+ else writeSTRef offsetC 0 >> modifySTRef offsetR (+ strideRows)
181+
182+ writeSTRef offsetR 0
183+ writeSTRef offsetC 0
184+ modifySTRef offsetM (+ (kernelRows * kernelColumns))
185+
186+ traverse U.freezeMatrix dataIms
187+
188+vid2colUnsafe :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> [Matrix Double] -> Matrix Double
189+vid2colUnsafe channels kernelRows kernelColumns striderows stridecols vidrows vidcols dataVid = U.runSTMatrix $ do
190+ let starts = fittingStarts vidrows kernelRows striderows vidcols kernelColumns stridecols
191+ matWidth = kernelRows * kernelColumns
192+ destinationRows = 1 + (vidrows - kernelRows) `div` striderows
193+ destinationCols = 1 + (vidcols - kernelColumns) `div` stridecols
194+ destinationSize = destinationRows * destinationCols
195+
196+ dataCol <- U.newMatrix 0 destinationSize (channels * matWidth)
197+
198+ offsetC <- newSTRef 0
199+
200+ forM_ dataVid $ \dataIm -> do
201+ inputRow <- newSTRef 0
202+ offsetC' <- readSTRef offsetC
203+ forM_ starts $ \(startRow, startCol) -> do
204+ inputColumn <- newSTRef 0
205+ inputRow' <- readSTRef inputRow
206+ forM_ [0 .. kernelRows -1] $ \kr ->
207+ forM_ [0 .. kernelColumns -1] $ \kc -> do
208+ inputColumn' <- readSTRef inputColumn
209+ U.modifyMatrix dataCol inputRow' (inputColumn' + offsetC') (+ atIndex dataIm (kr + startRow, kc + startCol))
210+ modifySTRef inputColumn (+1)
211+ modifySTRef inputRow (+1)
212+
213+ modifySTRef offsetC (+ matWidth)
214+
215+ return dataCol
216+
217+im2colUnsafe :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
218+im2colUnsafe kernelRows kernelColumns striderows stridecols vidrows vidcols dataIm = U.runSTMatrix $ do
219+ let starts = fittingStarts vidrows kernelRows striderows vidcols kernelColumns stridecols
220+ matWidth = kernelRows * kernelColumns
221+ destinationRows = 1 + (vidrows - kernelRows) `div` striderows
222+ destinationCols = 1 + (vidcols - kernelColumns) `div` stridecols
223+ destinationSize = destinationRows * destinationCols
224+
225+ dataCol <- U.newMatrix 0 destinationSize matWidth
226+
227+ inputRow <- newSTRef 0
228+ forM_ starts $ \(startRow, startCol) -> do
229+ inputColumn <- newSTRef 0
230+ inputRow' <- readSTRef inputRow
231+ forM_ [0 .. kernelRows -1] $ \kr ->
232+ forM_ [0 .. kernelColumns -1] $ \kc -> do
233+ inputColumn' <- readSTRef inputColumn
234+ U.modifyMatrix dataCol inputRow' inputColumn' (+ atIndex dataIm (kr + startRow, kc + startCol))
235+ modifySTRef inputColumn (+1)
236+ modifySTRef inputRow (+1)
237+
238+ return dataCol
src/Grenade/Layers/Crop.hs+1−1
@@ -58,7 +58,7 @@ instance ( KnownNat cropLeft
5858 m = extract input
5959 r = subMatrix (cropt, cropl) (nrows, ncols) m
6060 in S2D' . fromJust . create $ r
61− runBackards _ _ (S2D' dEdy) =
61+ runBackwards _ _ (S2D' dEdy) =
6262 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
6363 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
6464 cropr = fromIntegral $ natVal (Proxy :: Proxy cropRight)
src/Grenade/Layers/Dropout.hs+2−2
@@ -47,5 +47,5 @@ randomDropout rate = do
4747instance (KnownNat i) => Layer (Dropout i) ('D1 i) ('D1 i) where
4848 runForwards (Dropout drops) (S1D' x) = S1D' $ x * drops
4949 runForwards (Pass rate) (S1D' x)= S1D' $ dvmap (* (1 - rate)) x
50− runBackards (Dropout drops) _ (S1D' x) = ((), S1D' $ x * drops)
51− runBackards (Pass rate) _ (S1D' x) = ((), S1D' $ dvmap (* (1 - rate)) x)
50+ runBackwards (Dropout drops) _ (S1D' x) = ((), S1D' $ x * drops)
51+ runBackwards (Pass rate) _ (S1D' x) = ((), S1D' $ dvmap (* (1 - rate)) x)
src/Grenade/Layers/Flatten.hs+2−2
@@ -33,11 +33,11 @@ instance UpdateLayer FlattenLayer where
3333
3434instance (KnownNat a, KnownNat x, KnownNat y, a ~ (x * y)) => Layer FlattenLayer ('D2 x y) ('D1 a) where
3535 runForwards _ (S2D' y) = S1D' . fromList . toList . flatten . extract $ y
36− runBackards _ _ (S1D' y) = ((), S2D' . fromList . toList . unwrap $ y)
36+ runBackwards _ _ (S1D' y) = ((), S2D' . fromList . toList . unwrap $ y)
3737
3838instance (KnownNat a, KnownNat x, KnownNat y, KnownNat z, a ~ (x * y * z)) => Layer FlattenLayer ('D3 x y z) ('D1 a) where
3939 runForwards _ (S3D' y) = S1D' . raiseShapeError . create . vjoin . vecToList . fmap (flatten . extract) $ y
40− runBackards _ _ (S1D' o) =
40+ runBackwards _ _ (S1D' o) =
4141 let x' = fromIntegral $ natVal (Proxy :: Proxy x)
4242 y' = fromIntegral $ natVal (Proxy :: Proxy y)
4343 z' = fromIntegral $ natVal (Proxy :: Proxy z)
src/Grenade/Layers/FullyConnected.hs+1−1
@@ -52,7 +52,7 @@ instance (KnownNat i, KnownNat o) => Layer (FullyConnected i o) ('D1 i) ('D1 o)
5252 runForwards (FullyConnected wB _ wN _) (S1D' v) = S1D' (wB + wN #> v)
5353
5454 -- Run a backpropogation step for a full connected layer.
55− runBackards (FullyConnected _ _ wN _) (S1D' x) (S1D' dEdy) =
55+ runBackwards (FullyConnected _ _ wN _) (S1D' x) (S1D' dEdy) =
5656 let wB' = dEdy
5757 mm' = dEdy `outer` x
5858 -- calcluate derivatives for next step
src/Grenade/Layers/Fuse.hs+3−3
@@ -45,8 +45,8 @@ instance (Layer x i h, Layer y h o) => Layer (Fuse x y i h o) i o where
4545 let yInput :: S' h = runForwards x input
4646 in runForwards y yInput
4747
48− runBackards (x :$$ y) input backGradient =
48+ runBackwards (x :$$ y) input backGradient =
4949 let yInput :: S' h = runForwards x input
50− (y', yGrad) = runBackards y yInput backGradient
51− (x', xGrad) = runBackards x input yGrad
50+ (y', yGrad) = runBackwards y yInput backGradient
51+ (x', xGrad) = runBackwards x input yGrad
5252 in ((x', y'), xGrad)
src/Grenade/Layers/Logit.hs+3−3
@@ -29,15 +29,15 @@ instance UpdateLayer Logit where
2929
3030instance (KnownNat i) => Layer Logit ('D1 i) ('D1 i) where
3131 runForwards _ (S1D' y) = S1D' (logistic y)
32− runBackards _ (S1D' y) (S1D' dEdy) = ((), S1D' (logistic' y * dEdy))
32+ runBackwards _ (S1D' y) (S1D' dEdy) = ((), S1D' (logistic' y * dEdy))
3333
3434instance (KnownNat i, KnownNat j) => Layer Logit ('D2 i j) ('D2 i j) where
3535 runForwards _ (S2D' y) = S2D' (logistic y)
36− runBackards _ (S2D' y) (S2D' dEdy) = ((), S2D' (logistic' y * dEdy))
36+ runBackwards _ (S2D' y) (S2D' dEdy) = ((), S2D' (logistic' y * dEdy))
3737
3838instance (KnownNat i, KnownNat j, KnownNat k) => Layer Logit ('D3 i j k) ('D3 i j k) where
3939 runForwards _ (S3D' y) = S3D' (fmap logistic y)
40− runBackards _ (S3D' y) (S3D' dEdy) = ((), S3D' (vectorZip (\y' dEdy' -> logistic' y' * dEdy') y dEdy))
40+ runBackwards _ (S3D' y) (S3D' dEdy) = ((), S3D' (vectorZip (\y' dEdy' -> logistic' y' * dEdy') y dEdy))
4141
4242
4343logistic :: Floating a => a -> a
src/Grenade/Layers/Pad.hs+1−1
@@ -58,7 +58,7 @@ instance ( KnownNat padLeft
5858 m = extract input
5959 r = diagBlock [konst 0 (padt,padl), m, konst 0 (padb,padr)]
6060 in S2D' . fromJust . create $ r
61− runBackards Pad _ (S2D' dEdy) =
61+ runBackwards Pad _ (S2D' dEdy) =
6262 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
6363 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
6464 nrows = fromIntegral $ natVal (Proxy :: Proxy inputRows)
src/Grenade/Layers/Pooling.hs+3−3
@@ -24,7 +24,7 @@ import GHC.TypeLits
2424import Grenade.Core.Network
2525import Grenade.Core.Shape
2626import Grenade.Core.Vector
27−import Grenade.Layers.Convolution
27+import Grenade.Layers.Convolution.Internal
2828
2929import Numeric.LinearAlgebra hiding (uniformSample)
3030import qualified Numeric.LinearAlgebra as LA
@@ -75,7 +75,7 @@ instance ( KnownNat kernelRows
7575 r = poolForward kx ky sx sy ox oy $ ex
7676 rs = fromJust . create $ r
7777 in S2D' $ rs
78− runBackards Pooling (S2D' input) (S2D' dEdy) =
78+ runBackwards Pooling (S2D' input) (S2D' dEdy) =
7979 let kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
8080 ky = fromIntegral $ natVal (Proxy :: Proxy kernelColumns)
8181 sx = fromIntegral $ natVal (Proxy :: Proxy strideRows)
@@ -111,7 +111,7 @@ instance ( KnownNat kernelRows
111111 r = poolForwardList kx ky sx sy ix iy ox oy ex
112112 rs = fmap (fromJust . create) r
113113 in S3D' rs
114− runBackards Pooling (S3D' input) (S3D' dEdy) =
114+ runBackwards Pooling (S3D' input) (S3D' dEdy) =
115115 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
116116 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
117117 kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
src/Grenade/Layers/Relu.hs+3−3
@@ -31,7 +31,7 @@ instance ( KnownNat i) => Layer Relu ('D1 i) ('D1 i) where
3131 runForwards _ (S1D' y) = S1D' (relu y)
3232 where
3333 relu = LAS.dvmap (\a -> if a <= 0 then 0 else a)
34− runBackards _ (S1D' y) (S1D' dEdy) = ((), S1D' (relu' y * dEdy))
34+ runBackwards _ (S1D' y) (S1D' dEdy) = ((), S1D' (relu' y * dEdy))
3535 where
3636 relu' = LAS.dvmap (\a -> if a <= 0 then 0 else 1)
3737
@@ -39,7 +39,7 @@ instance (KnownNat i, KnownNat j) => Layer Relu ('D2 i j) ('D2 i j) where
3939 runForwards _ (S2D' y) = S2D' (relu y)
4040 where
4141 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
42− runBackards _ (S2D' y) (S2D' dEdy) = ((), S2D' (relu' y * dEdy))
42+ runBackwards _ (S2D' y) (S2D' dEdy) = ((), S2D' (relu' y * dEdy))
4343 where
4444 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
4545
@@ -47,6 +47,6 @@ instance (KnownNat i, KnownNat j, KnownNat k) => Layer Relu ('D3 i j k) ('D3 i j
4747 runForwards _ (S3D' y) = S3D' (fmap relu y)
4848 where
4949 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
50− runBackards _ (S3D' y) (S3D' dEdy) = ((), S3D' (vectorZip (\y' dEdy' -> relu' y' * dEdy') y dEdy))
50+ runBackwards _ (S3D' y) (S3D' dEdy) = ((), S3D' (vectorZip (\y' dEdy' -> relu' y' * dEdy') y dEdy))
5151 where
5252 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
src/Grenade/Layers/Tanh.hs+3−3
@@ -26,15 +26,15 @@ instance UpdateLayer Tanh where
2626
2727instance KnownNat i => Layer Tanh ('D1 i) ('D1 i) where
2828 runForwards _ (S1D' y) = S1D' (tanh y)
29− runBackards _ (S1D' y) (S1D' dEdy) = ((), S1D' (tanh' y * dEdy))
29+ runBackwards _ (S1D' y) (S1D' dEdy) = ((), S1D' (tanh' y * dEdy))
3030
3131instance (KnownNat i, KnownNat j) => Layer Tanh ('D2 i j) ('D2 i j) where
3232 runForwards _ (S2D' y) = S2D' (tanh y)
33− runBackards _ (S2D' y) (S2D' dEdy) = ((), S2D' (tanh' y * dEdy))
33+ runBackwards _ (S2D' y) (S2D' dEdy) = ((), S2D' (tanh' y * dEdy))
3434
3535instance (KnownNat i, KnownNat j, KnownNat k) => Layer Tanh ('D3 i j k) ('D3 i j k) where
3636 runForwards _ (S3D' y) = S3D' (fmap tanh y)
37− runBackards _ (S3D' y) (S3D' dEdy) = ((), S3D' (vectorZip (\y' dEdy' -> tanh' y' * dEdy') y dEdy))
37+ runBackwards _ (S3D' y) (S3D' dEdy) = ((), S3D' (vectorZip (\y' dEdy' -> tanh' y' * dEdy') y dEdy))
3838
3939tanh' :: (Floating a) => a -> a
4040tanh' t = 1 - s ^ (2 :: Int) where s = tanh t
test/Test/Grenade/Layers/Convolution.hs+27−2
@@ -8,6 +8,7 @@ import Grenade.Core.Shape
88import Grenade.Core.Vector as Grenade
99import Grenade.Core.Network
1010import Grenade.Layers.Convolution
11+import Grenade.Layers.Convolution.Internal
1112
1213import Numeric.LinearAlgebra hiding (uniformSample, konst, (===))
1314import qualified Numeric.LinearAlgebra.Static as HStatic
@@ -63,6 +64,17 @@ prop_im2col_sym_on_same_stride = once $
6364 out = col2im 3 2 3 2 3 4 . im2col 3 2 3 2 $ input
6465 in input === out
6566
67+-- If there's no overlap (stride is the same size as the kernel)
68+-- then col2im . im2col should be symmetric.
69+prop_im2colunsafe_sym_on_same_stride = once $
70+ let input = (3><4)
71+ [ 1.0, 2.0, 3.0, 4.0
72+ , 5.0, 6.0, 7.0, 8.0
73+ , 9.0, 10.0, 11.0, 12.0 ]
74+ out = col2imUnsafe 3 2 3 2 3 4 . im2colUnsafe 3 2 3 2 3 4 $ input
75+ in input === out
76+
77+
6678-- If there is an overlap, then the gradient passed back should be
6779-- the sum of the gradients across the filters.
6880prop_im2col_col2im_additive = once $
@@ -127,7 +139,7 @@ prop_simple_conv_forwards = once $
127139 expectBack = (HStatic.matrix
128140 [ 1.0, 0.0, 0.0
129141 , 0.0, -2.0,-1.0] :: HStatic.L 2 3)
130− (nc, inX) = runBackards convLayer input grad
142+ (nc, inX) = runBackwards convLayer input grad
131143
132144 in case (out, inX, nc) of
133145 (S3D' out' , S2D' inX', Convolution' backGrad)
@@ -187,6 +199,19 @@ prop_vid2col_invert = once $
187199 out = col2vid 3 2 3 2 3 4 . vid2col 3 2 3 2 3 4 $ input
188200 in input === out
189201
202+prop_vid2col_invert_unsafe = once $
203+ let input = [(3><4)
204+ [ 1.0, 2.0, 3.0, 4.0
205+ , 5.0, 6.0, 7.0, 8.0
206+ , 9.0, 10.0, 11.0, 12.0 ]
207+ , (3><4)
208+ [ 21.0, 22.0, 23.0, 24.0
209+ , 25.0, 26.0, 27.0, 28.0
210+ , 29.0, 30.0, 31.0, 32.0 ] ]
211+ out = col2vidUnsafe 3 2 3 2 3 4 . vid2colUnsafe 2 3 2 3 2 3 4 $ input
212+ in input === out
213+
214+
190215-- This test show that 2D convs act the same
191216-- 3D convs with one layer
192217prop_single_conv_forwards = once $
@@ -239,7 +264,7 @@ prop_single_conv_forwards = once $
239264 expectBack = (HStatic.matrix
240265 [ 1.0, 0.0, 0.0
241266 , 0.0, -2.0,-1.0] :: HStatic.L 2 3)
242− (nc, inX) = runBackards convLayer input grad
267+ (nc, inX) = runBackwards convLayer input grad
243268
244269 in case (out, inX, nc) of
245270 (S3D' out' , S3D' inX', Convolution' backGrad)