[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
   }

Reply via email to