[SYSTEMML-1432] Extend `util::pad_image` with a `pad_value` parameter Currently, our `util::pad_image` function performs zero-padding, which is correct for operations such as convolution. In some cases, such as max pooling, it is necessary to pad with a different value such as negative infinity. Therefore, this extends the `util::pad_image` function to accept a `pad_value` parameter with a noted typical value of 0.
Additionally, this fixes the max pooling layers by using negative-infinity padding, and updates a test case accordingly. Closes #434. Project: http://git-wip-us.apache.org/repos/asf/incubator-systemml/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-systemml/commit/169a2da5 Tree: http://git-wip-us.apache.org/repos/asf/incubator-systemml/tree/169a2da5 Diff: http://git-wip-us.apache.org/repos/asf/incubator-systemml/diff/169a2da5 Branch: refs/heads/master Commit: 169a2da5f5e2d1e0d6616866f98c3131999079e7 Parents: 15ccb7c Author: Mike Dusenberry <mwdus...@us.ibm.com> Authored: Wed Mar 22 16:45:23 2017 -0700 Committer: Mike Dusenberry <mwdus...@us.ibm.com> Committed: Wed Mar 22 16:45:23 2017 -0700 ---------------------------------------------------------------------- scripts/staging/SystemML-NN/nn/layers/conv.dml | 4 ++-- scripts/staging/SystemML-NN/nn/layers/max_pool.dml | 10 ++++++---- scripts/staging/SystemML-NN/nn/test/max_pool_simple.dml | 8 +++++--- scripts/staging/SystemML-NN/nn/test/test.dml | 6 +++--- scripts/staging/SystemML-NN/nn/util.dml | 6 ++++-- 5 files changed, 20 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/169a2da5/scripts/staging/SystemML-NN/nn/layers/conv.dml ---------------------------------------------------------------------- diff --git a/scripts/staging/SystemML-NN/nn/layers/conv.dml b/scripts/staging/SystemML-NN/nn/layers/conv.dml index 4036bbc..cc60a46 100644 --- a/scripts/staging/SystemML-NN/nn/layers/conv.dml +++ b/scripts/staging/SystemML-NN/nn/layers/conv.dml @@ -78,7 +78,7 @@ forward = function(matrix[double] X, matrix[double] W, matrix[double] b, Xn = matrix(X[n,], rows=C, cols=Hin*Win) # reshape # Pad image - Xn_padded = util::pad_image(Xn, Hin, Win, padh, padw) # shape (C, (Hin+2*padh)*(Win+2*padw)) + Xn_padded = util::pad_image(Xn, Hin, Win, padh, padw, 0) # shape (C, (Hin+2*padh)*(Win+2*padw)) # Extract local image patches into columns with im2col, of shape (C*Hf*Wf, Hout*Wout) Xn_padded_cols = util::im2col(Xn_padded, Hin+2*padh, Win+2*padw, Hf, Wf, strideh, stridew) @@ -140,7 +140,7 @@ backward = function(matrix[double] dout, int Hout, int Wout, # Compute dW Xn = matrix(X[n,], rows=C, cols=Hin*Win) # reshape - Xn_padded = util::pad_image(Xn, Hin, Win, padh, padw) # shape (C, (Hin+2*padh)*(Win+2*padw)) + Xn_padded = util::pad_image(Xn, Hin, Win, padh, padw, 0) # shape (C, (Hin+2*padh)*(Win+2*padw)) Xn_padded_cols = util::im2col(Xn_padded, Hin+2*padh, Win+2*padw, Hf, Wf, strideh, stridew) # dW = dW + doutn %*% t(Xn_padded_cols) dWN[n,] = matrix(doutn %*% t(Xn_padded_cols), rows=1, cols=F*C*Hf*Wf) http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/169a2da5/scripts/staging/SystemML-NN/nn/layers/max_pool.dml ---------------------------------------------------------------------- diff --git a/scripts/staging/SystemML-NN/nn/layers/max_pool.dml b/scripts/staging/SystemML-NN/nn/layers/max_pool.dml index ec7d431..22e1747 100644 --- a/scripts/staging/SystemML-NN/nn/layers/max_pool.dml +++ b/scripts/staging/SystemML-NN/nn/layers/max_pool.dml @@ -59,6 +59,7 @@ forward = function(matrix[double] X, int C, int Hin, int Win, int Hf, int Wf, N = nrow(X) Hout = as.integer((Hin + 2 * padh - Hf) / strideh + 1) Wout = as.integer((Win + 2 * padw - Wf) / stridew + 1) + pad_value = -1/0 # in max pooling we pad with -infinity # Create output volume out = matrix(0, rows=N, cols=C*Hout*Wout) @@ -68,8 +69,8 @@ forward = function(matrix[double] X, int C, int Hin, int Win, int Hf, int Wf, img = matrix(X[n,], rows=C, cols=Hin*Win) # reshape if (padh > 0 | padw > 0) { - # Pad image - img = util::pad_image(img, Hin, Win, padh, padw) # shape (C, (Hin+2*padh)*(Win+2*padw)) + # Pad image to shape (C, (Hin+2*padh)*(Win+2*padw)) + img = util::pad_image(img, Hin, Win, padh, padw, pad_value) } img_maxes = matrix(0, rows=C, cols=Hout*Wout) # zeros @@ -115,6 +116,7 @@ backward = function(matrix[double] dout, int Hout, int Wout, matrix[double] X, * - dX: Gradient wrt X, of shape (N, C*Hin*Win). */ N = nrow(X) + pad_value = -1/0 # in max pooling we pad with -infinity # Create gradient volume dX = matrix(0, rows=N, cols=C*Hin*Win) @@ -123,8 +125,8 @@ backward = function(matrix[double] dout, int Hout, int Wout, matrix[double] X, parfor (n in 1:N, check=0) { # all examples img = matrix(X[n,], rows=C, cols=Hin*Win) if (padh > 0 | padw > 0) { - # Pad image - img = util::pad_image(img, Hin, Win, padh, padw) # shape (C, (Hin+2*padh)*(Win+2*padw)) + # Pad image to shape (C, (Hin+2*padh)*(Win+2*padw)) + img = util::pad_image(img, Hin, Win, padh, padw, pad_value) } dimg = matrix(0, rows=C, cols=(Hin+2*padh)*(Win+2*padw)) http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/169a2da5/scripts/staging/SystemML-NN/nn/test/max_pool_simple.dml ---------------------------------------------------------------------- diff --git a/scripts/staging/SystemML-NN/nn/test/max_pool_simple.dml b/scripts/staging/SystemML-NN/nn/test/max_pool_simple.dml index 12db116..4394ffd 100644 --- a/scripts/staging/SystemML-NN/nn/test/max_pool_simple.dml +++ b/scripts/staging/SystemML-NN/nn/test/max_pool_simple.dml @@ -65,12 +65,13 @@ forward = function(matrix[double] X, int C, int Hin, int Win, int Hf, int Wf, Xn = matrix(X[n,], rows=C, cols=Hin*Win) # Pad image - Xn_padded = matrix(0, rows=C, cols=(Hin+2*padh)*(Win+2*padw)) # zeros + pad_value = -1/0 + Xn_padded = matrix(pad_value, rows=C, cols=(Hin+2*padh)*(Win+2*padw)) # zeros parfor (c in 1:C) { Xn_slice = matrix(Xn[c,], rows=Hin, cols=Win) # depth slice C reshaped Xn_padded_slice = matrix(Xn_padded[c,], rows=Hin+2*padh, cols=Win+2*padw) Xn_padded_slice[padh+1:padh+Hin, padw+1:padw+Win] = Xn_slice - Xn_padded[c, ] = matrix(Xn_padded_slice, rows=1, cols=(Hin+2*padh)*(Win+2*padw)) # reshape + Xn_padded[c,] = matrix(Xn_padded_slice, rows=1, cols=(Hin+2*padh)*(Win+2*padw)) # reshape } img = Xn_padded # shape (C, (Hin+2*padh)*(Win+2*padw)) @@ -127,7 +128,8 @@ backward = function(matrix[double] dout, int Hout, int Wout, matrix[double] X, Xn = matrix(X[n,], rows=C, cols=Hin*Win) # Pad image - Xn_padded = matrix(0, rows=C, cols=(Hin+2*padh)*(Win+2*padw)) # zeros + pad_value = -1/0 + Xn_padded = matrix(pad_value, rows=C, cols=(Hin+2*padh)*(Win+2*padw)) # zeros parfor (c in 1:C) { Xn_slice = matrix(Xn[c,], rows=Hin, cols=Win) # depth slice C reshaped Xn_padded_slice = matrix(Xn_padded[c,], rows=Hin+2*padh, cols=Win+2*padw) http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/169a2da5/scripts/staging/SystemML-NN/nn/test/test.dml ---------------------------------------------------------------------- diff --git a/scripts/staging/SystemML-NN/nn/test/test.dml b/scripts/staging/SystemML-NN/nn/test/test.dml index 5052fa6..dd24a55 100644 --- a/scripts/staging/SystemML-NN/nn/test/test.dml +++ b/scripts/staging/SystemML-NN/nn/test/test.dml @@ -116,7 +116,7 @@ im2col = function() { x = rand(rows=C, cols=Hin*Win) # pad - x_pad = util::pad_image(x, Hin, Win, pad, pad) + x_pad = util::pad_image(x, Hin, Win, pad, pad, 0) # im2col x_cols = util::im2col(x_pad, Hin+2*pad, Win+2*pad, Hf, Wf, stride, stride) @@ -145,7 +145,7 @@ padding = function() { x = rand(rows=C, cols=Hin*Win) # Pad image - x_pad = util::pad_image(x, Hin, Win, pad, pad) + x_pad = util::pad_image(x, Hin, Win, pad, pad, 0) # Check for padded rows & columns for (c in 1:C) { @@ -381,7 +381,7 @@ max_pool = function() { # 0 0 0 # 0 -6 0 # 0 0 0 - target = matrix("0 0 0 0 -6 0 0 0 0 0 0 0 0 -6 0 0 0 0", rows=1, cols=C*Hout*Wout) + target = matrix("-1 -2 -4 -5 -6 -8 -13 -14 -16 -1 -5 -13 -2 -6 -14 -4 -8 -16", rows=1, cols=C*Hout*Wout) target = rbind(target, target) # n=2 tmp = util::check_all_equal(out, target) tmp = util::check_all_equal(out_simple, target) http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/169a2da5/scripts/staging/SystemML-NN/nn/util.dml ---------------------------------------------------------------------- diff --git a/scripts/staging/SystemML-NN/nn/util.dml b/scripts/staging/SystemML-NN/nn/util.dml index 6870a5f..fdf0f76 100644 --- a/scripts/staging/SystemML-NN/nn/util.dml +++ b/scripts/staging/SystemML-NN/nn/util.dml @@ -214,7 +214,7 @@ col2im = function(matrix[double] img_cols, int C, int Hin, int Win, int Hf, int } } -pad_image = function(matrix[double] img, int Hin, int Win, int padh, int padw) +pad_image = function(matrix[double] img, int Hin, int Win, int padh, int padw, double pad_value) return (matrix[double] img_padded) { /* * Pads an image along the height and width dimensions with zeros. @@ -226,6 +226,8 @@ pad_image = function(matrix[double] img, int Hin, int Win, int padh, int padw) * - Win: Input width. * - padh: Padding for top and bottom sides. * - padw: Padding for left and right sides. + * - pad_value: Value to use for the padding. + * A typical value is 0. * * Outputs: * - img_padded: The input image padded along the height and width @@ -235,7 +237,7 @@ pad_image = function(matrix[double] img, int Hin, int Win, int padh, int padw) img_padded = matrix(0, rows=C, cols=(Hin+2*padh)*(Win+2*padw)) # zeros parfor (c in 1:C) { img_slice = matrix(img[c,], rows=Hin, cols=Win) # depth slice C reshaped - img_padded_slice = matrix(0, rows=Hin+2*padh, cols=Win+2*padw) + img_padded_slice = matrix(pad_value, rows=Hin+2*padh, cols=Win+2*padw) img_padded_slice[padh+1:padh+Hin, padw+1:padw+Win] = img_slice img_padded[c,] = matrix(img_padded_slice, rows=1, cols=(Hin+2*padh)*(Win+2*padw)) # reshape }