on master help sign in
Add stupidly fast col2im
1ec65a4Huw Campbell
bench/bench.hs+7−3
@@ -11,14 +11,18 @@ main = defaultMain [
11 , bench "im2col 28x28" $ whnf (im2colUnsafe 5 5 1 1) ((28><28) [1..])
11 , bench "im2col 28x28" $ whnf (im2colUnsafe 5 5 1 1) ((28><28) [1..])
12 , bench "im2col 100x100" $ whnf (im2colUnsafe 10 10 1 1) ((100><100) [1..])
12 , bench "im2col 100x100" $ whnf (im2colUnsafe 10 10 1 1) ((100><100) [1..])
13 ]
13 ]
14− , bgroup "im2col_c" [ bench "im2col_c 3x4" $ whnf (im2col_c 2 2 1 1) ((3><4) [1..])
14+ , bgroup "im2col_c" [ bench "im2col_c 3x4" $ whnf (im2col 2 2 1 1) ((3><4) [1..])
15− , bench "im2col_c 28x28" $ whnf (im2col_c 5 5 1 1) ((28><28) [1..])
15+ , bench "im2col_c 28x28" $ whnf (im2col 5 5 1 1) ((28><28) [1..])
16− , bench "im2col_c 100x100" $ whnf (im2col_c 10 10 1 1) ((100><100) [1..])
16+ , bench "im2col_c 100x100" $ whnf (im2col 10 10 1 1) ((100><100) [1..])
17 ]
17 ]
18 , bgroup "col2im" [ bench "col2im 3x4" $ whnf (col2imUnsafe 2 2 1 1 3 4) ((6><4) [1..])
18 , bgroup "col2im" [ bench "col2im 3x4" $ whnf (col2imUnsafe 2 2 1 1 3 4) ((6><4) [1..])
19 , bench "col2im 28x28" $ whnf (col2imUnsafe 5 5 1 1 28 28) ((576><25) [1..])
19 , bench "col2im 28x28" $ whnf (col2imUnsafe 5 5 1 1 28 28) ((576><25) [1..])
20 , bench "col2im 100x100" $ whnf (col2imUnsafe 10 10 1 1 100 100) ((8281><100) [1..])
20 , bench "col2im 100x100" $ whnf (col2imUnsafe 10 10 1 1 100 100) ((8281><100) [1..])
21 ]
21 ]
22+ , bgroup "col2im_c" [ bench "col2im_c 3x4" $ whnf (col2im 2 2 1 1 3 4) ((6><4) [1..])
23+ , bench "col2im_c 28x28" $ whnf (col2im 5 5 1 1 28 28) ((576><25) [1..])
24+ , bench "col2im_c 100x100" $ whnf (col2im 10 10 1 1 100 100) ((8281><100) [1..])
25+ ]
22 , bgroup "poolfw" [ bench "poolforwards 3x4" $ whnf (poolForward 2 2 1 1 2 3) ((3><4) [1..])
26 , bgroup "poolfw" [ bench "poolforwards 3x4" $ whnf (poolForward 2 2 1 1 2 3) ((3><4) [1..])
23 , bench "poolforwards 28x28" $ whnf (poolForward 5 5 1 1 4 24) ((28><28) [1..])
27 , bench "poolforwards 28x28" $ whnf (poolForward 5 5 1 1 4 24) ((28><28) [1..])
24 , bench "poolforwards 100x100" $ whnf (poolForward 10 10 1 1 91 91) ((100><100) [1..])
28 , bench "poolforwards 100x100" $ whnf (poolForward 10 10 1 1 91 91) ((100><100) [1..])
cbits/im2col.c+33−4
@@ -12,16 +12,45 @@ void im2col_cpu(const double* data_im, int dataOffset, const int channels,
12 data_im += dataOffset;
12 data_im += dataOffset;
13 const int output_h = (height - kernel_h) / stride_h + 1;
13 const int output_h = (height - kernel_h) / stride_h + 1;
14 const int output_w = (width - kernel_w) / stride_w + 1;
14 const int output_w = (width - kernel_w) / stride_w + 1;
15+ const int channel_size = height * width;
15
16
17+ for (int fitting_height = 0; fitting_height <= (height - kernel_h); fitting_height += stride_h) {
18+ for (int fitting_width = 0; fitting_width <= (width - kernel_w); fitting_width += stride_w) {
19+ for (int channel = 0; channel < channels; channel++) {
20+ for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
21+ for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
22+ int input_row = fitting_height + kernel_row;
23+ int input_col = fitting_width + kernel_col;
24+ *(data_col++) = data_im[input_row * width + input_col + channel_size * channel];
25+ }
26+ }
27+ }
28+ }
29+ }
30+}
31+
32+void col2im_cpu(const double* data_col, int dataOffset, const int channels,
33+ const int height, const int width, const int kernel_h, const int kernel_w,
34+ const int stride_h, const int stride_w,
35+ double* data_im) {
36+
37+ memset(data_im, 0, height * width * channels * sizeof(double));
38+ data_col += dataOffset;
39+ const int output_h = (height - kernel_h) / stride_h + 1;
40+ const int output_w = (width - kernel_w) / stride_w + 1;
16 const int channel_size = height * width;
41 const int channel_size = height * width;
17− for (int channel = channels; channel--; data_im += channel_size) {
42+
18− for (int fitting_height = 0; fitting_height <= (height - kernel_h); fitting_height += stride_h) {
43+ int offsetRow = 0;
19− for (int fitting_width = 0; fitting_width <= (width - kernel_w); fitting_width += stride_w) {
44+ int offsetColumn = 0;
45+
46+ for (int fitting_height = 0; fitting_height <= (height - kernel_h); fitting_height += stride_h) {
47+ for (int fitting_width = 0; fitting_width <= (width - kernel_w); fitting_width += stride_w) {
48+ for (int channel = 0; channel < channels; channel++) {
20 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
49 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
21 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
50 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
22 int input_row = fitting_height + kernel_row;
51 int input_row = fitting_height + kernel_row;
23 int input_col = fitting_width + kernel_col;
52 int input_col = fitting_width + kernel_col;
24− *(data_col++) = data_im[input_row * width + input_col];
53+ data_im[input_row * width + input_col + channel_size * channel] += *(data_col++);
25 }
54 }
26 }
55 }
27 }
56 }
cbits/im2col.h+6
@@ -1,7 +1,13 @@
1#include <stdio.h>
1#include <stdio.h>
2#include <stdint.h>
2#include <stdint.h>
3+#include <string.h>
3
4
4void im2col_cpu(const double* data_im, int dataOffset, const int channels,
5void im2col_cpu(const double* data_im, int dataOffset, const int channels,
5 const int height, const int width, const int kernel_h, const int kernel_w,
6 const int height, const int width, const int kernel_h, const int kernel_w,
6 const int stride_h, const int stride_w,
7 const int stride_h, const int stride_w,
7 double* data_col);
8 double* data_col);
9+
10+void col2im_cpu(const double* data_col, int dataOffset, const int channels,
11+ const int height, const int width, const int kernel_h, const int kernel_w,
12+ const int stride_h, const int stride_w,
13+ double* data_im);
src/Grenade/Layers/Convolution.hs+10−10
@@ -155,9 +155,9 @@ instance ( KnownNat kernelRows
155 sy = fromIntegral $ natVal (Proxy :: Proxy strideCols)
155 sy = fromIntegral $ natVal (Proxy :: Proxy strideCols)
156 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
156 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
157 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
157 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
158− c = im2col_c kx ky sx sy ex
158+ c = im2col kx ky sx sy ex
159 mt = c LA.<> ek
159 mt = c LA.<> ek
160− r = col2vidUnsafe 1 1 1 1 ox oy mt
160+ r = col2vid 1 1 1 1 ox oy mt
161 rs = fmap (fromJust . create) r
161 rs = fmap (fromJust . create) r
162 in S3D' $ mkVector rs
162 in S3D' $ mkVector rs
163
163
@@ -172,17 +172,17 @@ instance ( KnownNat kernelRows
172 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
172 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
173 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
173 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
174
174
175− c = im2col_c kx ky sx sy ex
175+ c = im2col kx ky sx sy ex
176
176
177 eo = vecToList $ fmap extract dEdy
177 eo = vecToList $ fmap extract dEdy
178 ek = extract kernel
178 ek = extract kernel
179
179
180− vs = vid2colUnsafe 1 1 1 1 ox oy eo
180+ vs = vid2col 1 1 1 1 ox oy eo
181
181
182 kN = fromJust . create $ tr c LA.<> vs
182 kN = fromJust . create $ tr c LA.<> vs
183 dW = vs LA.<> tr ek
183 dW = vs LA.<> tr ek
184
184
185− xW = col2imUnsafe kx ky sx sy ix iy dW
185+ xW = col2im kx ky sx sy ix iy dW
186 in (Convolution' kN, S2D' . fromJust . create $ xW)
186 in (Convolution' kN, S2D' . fromJust . create $ xW)
187
187
188
188
@@ -214,9 +214,9 @@ instance ( KnownNat kernelRows
214 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
214 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
215 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
215 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
216
216
217− c = vid2colUnsafe kx ky sx sy ix iy ex
217+ c = vid2col kx ky sx sy ix iy ex
218 mt = c LA.<> ek
218 mt = c LA.<> ek
219− r = col2vidUnsafe 1 1 1 1 ox oy mt
219+ r = col2vid 1 1 1 1 ox oy mt
220 rs = fmap (fromJust . create) r
220 rs = fmap (fromJust . create) r
221 in S3D' $ mkVector rs
221 in S3D' $ mkVector rs
222 runBackwards (Convolution kernel _) (S3D' input) (S3D' dEdy) =
222 runBackwards (Convolution kernel _) (S3D' input) (S3D' dEdy) =
@@ -230,16 +230,16 @@ instance ( KnownNat kernelRows
230 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
230 ox = fromIntegral $ natVal (Proxy :: Proxy outputRows)
231 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
231 oy = fromIntegral $ natVal (Proxy :: Proxy outputCols)
232
232
233− c = vid2colUnsafe kx ky sx sy ix iy ex
233+ c = vid2col kx ky sx sy ix iy ex
234
234
235 eo = vecToList $ fmap extract dEdy
235 eo = vecToList $ fmap extract dEdy
236 ek = extract kernel
236 ek = extract kernel
237
237
238− vs = vid2colUnsafe 1 1 1 1 ox oy eo
238+ vs = vid2col 1 1 1 1 ox oy eo
239
239
240 kN = fromJust . create $ tr c LA.<> vs
240 kN = fromJust . create $ tr c LA.<> vs
241
241
242 dW = vs LA.<> tr ek
242 dW = vs LA.<> tr ek
243
243
244− xW = col2vidUnsafe kx ky sx sy ix iy dW
244+ xW = col2vid kx ky sx sy ix iy dW
245 in (Convolution' kN, S3D' . mkVector . fmap (fromJust . create) $ xW)
245 in (Convolution' kN, S3D' . mkVector . fmap (fromJust . create) $ xW)
src/Grenade/Layers/Internal/Convolution.hs+55−10
@@ -1,11 +1,13 @@
1−{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE ForeignFunctionInterface #-}
1{-# LANGUAGE ForeignFunctionInterface #-}
3module Grenade.Layers.Internal.Convolution (
2module Grenade.Layers.Internal.Convolution (
4 col2vidUnsafe
3 col2vidUnsafe
5 , col2imUnsafe
4 , col2imUnsafe
6 , vid2colUnsafe
5 , vid2colUnsafe
7 , im2colUnsafe
6 , im2colUnsafe
8− , im2col_c
7+ , im2col
8+ , col2im
9+ , col2vid
10+ , vid2col
9 , fittingStarts
11 , fittingStarts
10 , unsafeModifyMatrix
12 , unsafeModifyMatrix
11 ) where
13 ) where
@@ -67,6 +69,36 @@ import System.IO.Unsafe ( unsafePerformIO )
67-- @
69-- @
68--
70--
69
71
72+col2vid :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> [Matrix Double]
73+col2vid kernelRows kernelColumns strideRows strideColumns height width dataCol =
74+ let channels = cols dataCol `div` (kernelRows * kernelColumns)
75+ retMat = col2im_c channels height width kernelRows kernelColumns strideRows strideColumns dataCol
76+ in (\f -> subMatrix (f * height, 0) (height, width) retMat) <$> [0..channels -1]
77+
78+col2im :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
79+col2im kernelRows kernelColumns strideRows strideColumns height width dataCol =
80+ let channels = 1
81+ in col2im_c channels height width kernelRows kernelColumns strideRows strideColumns dataCol
82+
83+col2im_c :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
84+col2im_c channels height width kernelRows kernelColumns strideRows strideColumns dataCol =
85+ let vec = flatten dataCol
86+ in unsafePerformIO $ do
87+ outPtr <- mallocForeignPtrArray0 (height * width * channels)
88+ let (inPtr, inOffset, _) = U.unsafeToForeignPtr vec
89+
90+ withForeignPtr inPtr $ \inPtr' ->
91+ withForeignPtr outPtr $ \outPtr' ->
92+ col2im_cpu inPtr' inOffset channels height width kernelRows kernelColumns strideRows strideColumns outPtr'
93+
94+ let matVec = U.unsafeFromForeignPtr outPtr 0 (height * width * channels)
95+ return $ U.matrixFromVector U.RowMajor (height * channels) width matVec
96+
97+foreign import ccall safe
98+ col2im_cpu
99+ :: Ptr Double -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Ptr Double -> IO ()
100+
101+
70-- | col2im function.
102-- | col2im function.
71--
103--
72-- Takes a column patch, and reconstitutes it into a normal image.
104-- Takes a column patch, and reconstitutes it into a normal image.
@@ -127,26 +159,36 @@ col2vidUnsafe kernelRows kernelColumns strideRows strideColumns destinationRows
127
159
128 U.unsafeFreezeMatrix dataIm
160 U.unsafeFreezeMatrix dataIm
129
161
162+vid2col :: Int -> Int -> Int -> Int -> Int -> Int -> [Matrix Double] -> Matrix Double
163+vid2col kernelRows kernelColumns strideRows strideColumns height width dataVid =
164+ let channels = length dataVid
165+ in im2col_c channels height width kernelRows kernelColumns strideRows strideColumns (foldl1 (===) dataVid)
130
166
131−im2col_c :: Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
167+
132−im2col_c kernelRows kernelColumns strideRows strideColumns dataIm =
168+im2col :: Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
133− let height = rows dataIm
169+im2col kernelRows kernelColumns strideRows strideColumns dataIm =
170+ let channels = 1
171+ height = rows dataIm
134 width = cols dataIm
172 width = cols dataIm
135− vec = flatten dataIm
173+ in im2col_c channels height width kernelRows kernelColumns strideRows strideColumns dataIm
174+
175+im2col_c :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
176+im2col_c channels height width kernelRows kernelColumns strideRows strideColumns dataIm =
177+ let vec = flatten dataIm
136 rowOut = (height - kernelRows) `div` strideRows + 1
178 rowOut = (height - kernelRows) `div` strideRows + 1
137 colOut = (width - kernelColumns) `div` strideColumns + 1
179 colOut = (width - kernelColumns) `div` strideColumns + 1
138 kernelSize = kernelRows * kernelColumns
180 kernelSize = kernelRows * kernelColumns
139 numberOfPatches = rowOut * colOut
181 numberOfPatches = rowOut * colOut
140 in unsafePerformIO $ do
182 in unsafePerformIO $ do
141− outPtr <- mallocForeignPtrArray0 (numberOfPatches * kernelSize)
183+ outPtr <- mallocForeignPtrArray0 (numberOfPatches * kernelSize * channels)
142 let (inPtr, inOffset, _) = U.unsafeToForeignPtr vec
184 let (inPtr, inOffset, _) = U.unsafeToForeignPtr vec
143
185
144 withForeignPtr inPtr $ \inPtr' ->
186 withForeignPtr inPtr $ \inPtr' ->
145 withForeignPtr outPtr $ \outPtr' ->
187 withForeignPtr outPtr $ \outPtr' ->
146− im2col_cpu inPtr' inOffset 1 height width kernelRows kernelColumns strideRows strideColumns outPtr'
188+ im2col_cpu inPtr' inOffset channels height width kernelRows kernelColumns strideRows strideColumns outPtr'
147
189
148− let matVec = U.unsafeFromForeignPtr outPtr 0 (numberOfPatches * kernelSize)
190+ let matVec = U.unsafeFromForeignPtr outPtr 0 (numberOfPatches * kernelSize * channels)
149− return $ U.matrixFromVector U.RowMajor numberOfPatches kernelSize matVec
191+ return $ U.matrixFromVector U.RowMajor numberOfPatches (kernelSize * channels) matVec
150
192
151foreign import ccall safe
193foreign import ccall safe
152 im2col_cpu
194 im2col_cpu
@@ -231,3 +273,6 @@ im2colUnsafe kernelRows kernelColumns striderows stridecols dataIm = U.runSTMatr
231 modifySTRef' inputRowRef (+1)
273 modifySTRef' inputRowRef (+1)
232
274
233 return dataCol
275 return dataCol
276+
277+
278+{-# ANN module "HLint: ignore Reduce duplication" #-}
test/Test/Grenade/Layers/Convolution.hs+13−11
@@ -42,7 +42,7 @@ prop_im2col_c = once $
42 , 5.0, 6.0, 9.0, 10.0
42 , 5.0, 6.0, 9.0, 10.0
43 , 6.0, 7.0, 10.0, 11.0
43 , 6.0, 7.0, 10.0, 11.0
44 , 7.0, 8.0, 11.0, 12.0 ]
44 , 7.0, 8.0, 11.0, 12.0 ]
45− out = im2col_c 2 2 1 1 input
45+ out = im2col 2 2 1 1 input
46 in expected === out
46 in expected === out
47
47
48prop_im2col_stride = once $
48prop_im2col_stride = once $
@@ -68,7 +68,7 @@ prop_im2col_c_stride = once $
68 , 3.0, 4.0, 7.0, 8.0
68 , 3.0, 4.0, 7.0, 8.0
69 , 5.0, 6.0, 9.0, 10.0
69 , 5.0, 6.0, 9.0, 10.0
70 , 7.0, 8.0, 11.0, 12.0 ]
70 , 7.0, 8.0, 11.0, 12.0 ]
71− out = im2col_c 2 2 1 2 input
71+ out = im2col 2 2 1 2 input
72 in expected === out
72 in expected === out
73
73
74prop_im2col_other = once $
74prop_im2col_other = once $
@@ -90,12 +90,12 @@ prop_im2col_c_other = once $
90 expected = (2><6)
90 expected = (2><6)
91 [ 1.0, 2.0, 5.0, 6.0 , 9.0, 10.0
91 [ 1.0, 2.0, 5.0, 6.0 , 9.0, 10.0
92 , 3.0, 4.0, 7.0, 8.0 , 11.0 ,12.0 ]
92 , 3.0, 4.0, 7.0, 8.0 , 11.0 ,12.0 ]
93− out = im2col_c 3 2 1 2 input
93+ out = im2col 3 2 1 2 input
94 in expected === out
94 in expected === out
95
95
96prop_im2col_bigger = once $
96prop_im2col_bigger = once $
97 let input = (7><7) [ 1.0 .. ]
97 let input = (7><7) [ 1.0 .. ]
98− in im2colUnsafe 5 5 2 2 input === im2col_c 5 5 2 2 input
98+ in im2colUnsafe 5 5 2 2 input === im2col 5 5 2 2 input
99
99
100-- If there's no overlap (stride is the same size as the kernel)
100-- If there's no overlap (stride is the same size as the kernel)
101-- then col2im . im2col should be symmetric.
101-- then col2im . im2col should be symmetric.
@@ -104,7 +104,7 @@ prop_im2col_sym_on_same_stride = once $
104 [ 1.0, 2.0, 3.0, 4.0
104 [ 1.0, 2.0, 3.0, 4.0
105 , 5.0, 6.0, 7.0, 8.0
105 , 5.0, 6.0, 7.0, 8.0
106 , 9.0, 10.0, 11.0, 12.0 ]
106 , 9.0, 10.0, 11.0, 12.0 ]
107− out = col2imUnsafe 3 2 3 2 3 4 . im2colUnsafe 3 2 3 2 $ input
107+ out = col2im 3 2 3 2 3 4 . im2colUnsafe 3 2 3 2 $ input
108 in input === out
108 in input === out
109
109
110-- If there's no overlap (stride is the same size as the kernel)
110-- If there's no overlap (stride is the same size as the kernel)
@@ -114,7 +114,7 @@ prop_im2colunsafe_sym_on_same_stride = once $
114 [ 1.0, 2.0, 3.0, 4.0
114 [ 1.0, 2.0, 3.0, 4.0
115 , 5.0, 6.0, 7.0, 8.0
115 , 5.0, 6.0, 7.0, 8.0
116 , 9.0, 10.0, 11.0, 12.0 ]
116 , 9.0, 10.0, 11.0, 12.0 ]
117− out = col2imUnsafe 3 2 3 2 3 4 . im2colUnsafe 3 2 3 2 $ input
117+ out = col2im 3 2 3 2 3 4 . im2colUnsafe 3 2 3 2 $ input
118 in input === out
118 in input === out
119
119
120
120
@@ -129,7 +129,7 @@ prop_im2col_col2im_additive = once $
129 [ 1.0, 2.0, 2.0, 1.0
129 [ 1.0, 2.0, 2.0, 1.0
130 , 2.0, 4.0, 4.0, 2.0
130 , 2.0, 4.0, 4.0, 2.0
131 , 1.0, 2.0, 2.0, 1.0 ]
131 , 1.0, 2.0, 2.0, 1.0 ]
132− out = col2imUnsafe 2 2 1 1 3 4 . im2colUnsafe 2 2 1 1 $ input
132+ out = col2im 2 2 1 1 3 4 . im2colUnsafe 2 2 1 1 $ input
133 in expected === out
133 in expected === out
134
134
135prop_simple_conv_forwards = once $
135prop_simple_conv_forwards = once $
@@ -207,7 +207,8 @@ prop_vid2col_no_stride = once $
207 , 6.0, 7.0, 10.0, 11.0 , 26.0, 27.0, 30.0, 31.0
207 , 6.0, 7.0, 10.0, 11.0 , 26.0, 27.0, 30.0, 31.0
208 , 7.0, 8.0, 11.0, 12.0 , 27.0, 28.0, 31.0, 32.0 ]
208 , 7.0, 8.0, 11.0, 12.0 , 27.0, 28.0, 31.0, 32.0 ]
209 out = vid2colUnsafe 2 2 1 1 3 4 input
209 out = vid2colUnsafe 2 2 1 1 3 4 input
210− in expected === out
210+ out_c = vid2col 2 2 1 1 3 4 input
211+ in expected === out .&&. expected === out_c
211
212
212prop_vid2col_stride = once $
213prop_vid2col_stride = once $
213 let input = [(3><4)
214 let input = [(3><4)
@@ -223,8 +224,9 @@ prop_vid2col_stride = once $
223 , 3.0, 4.0, 7.0, 8.0 , 23.0, 24.0, 27.0, 28.0
224 , 3.0, 4.0, 7.0, 8.0 , 23.0, 24.0, 27.0, 28.0
224 , 5.0, 6.0, 9.0, 10.0 , 25.0, 26.0, 29.0, 30.0
225 , 5.0, 6.0, 9.0, 10.0 , 25.0, 26.0, 29.0, 30.0
225 , 7.0, 8.0, 11.0, 12.0 , 27.0, 28.0, 31.0, 32.0 ]
226 , 7.0, 8.0, 11.0, 12.0 , 27.0, 28.0, 31.0, 32.0 ]
226− out = vid2colUnsafe 2 2 1 2 3 4 input
227+ out = vid2colUnsafe 2 2 1 2 3 4 input
227− in expected === out
228+ out_c = vid2col 2 2 1 2 3 4 input
229+ in expected === out .&&. expected === out_c
228
230
229prop_vid2col_invert = once $
231prop_vid2col_invert = once $
230 let input = [(3><4)
232 let input = [(3><4)
@@ -235,7 +237,7 @@ prop_vid2col_invert = once $
235 [ 21.0, 22.0, 23.0, 24.0
237 [ 21.0, 22.0, 23.0, 24.0
236 , 25.0, 26.0, 27.0, 28.0
238 , 25.0, 26.0, 27.0, 28.0
237 , 29.0, 30.0, 31.0, 32.0 ] ]
239 , 29.0, 30.0, 31.0, 32.0 ] ]
238− out = col2vidUnsafe 3 2 3 2 3 4 . vid2colUnsafe 3 2 3 2 3 4 $ input
240+ out = col2vid 3 2 3 2 3 4 . vid2colUnsafe 3 2 3 2 3 4 $ input
239 in input === out
241 in input === out
240
242
241
243