You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@systemml.apache.org by mb...@apache.org on 2018/02/10 06:23:55 UTC
[1/2] systemml git commit: [SYSTEMML-2041]
Performance/memory-efficiency ultra-sparse conv2d
Repository: systemml
Updated Branches:
refs/heads/master 5c1ac17cc -> 401b79657
[SYSTEMML-2041] Performance/memory-efficiency ultra-sparse conv2d
This patch improves the performance and memory-efficiency of
ultra-sparse conv2d operations by allocating the output in sparse
format, forcing ultra-sparse matrix multiplications (with sparse output)
and generalizing all related operations to handle sparse intermediates.
Furthermore, this also includes a fix for ultra-sparse matrix
multiplications where the rhs is much larger than the lhs which triggers
parallelization over rows in the rhs instead of the lhs, which is not
supported by ultra-sparse matrix multiplications.
Project: http://git-wip-us.apache.org/repos/asf/systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/08c7f00d
Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/08c7f00d
Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/08c7f00d
Branch: refs/heads/master
Commit: 08c7f00d5b3d7383ca0cf0e893736026c8ee7151
Parents: 5c1ac17
Author: Matthias Boehm <mb...@gmail.com>
Authored: Fri Feb 9 21:40:22 2018 -0800
Committer: Matthias Boehm <mb...@gmail.com>
Committed: Fri Feb 9 21:40:22 2018 -0800
----------------------------------------------------------------------
.../cp/ConvolutionCPInstruction.java | 4 +-
.../runtime/matrix/data/LibMatrixDNNConv2d.java | 58 ++++++++++++-------
.../runtime/matrix/data/LibMatrixDNNHelper.java | 2 +-
.../runtime/matrix/data/LibMatrixDNNIm2Col.java | 16 +++--
.../runtime/matrix/data/LibMatrixMult.java | 61 +++++++++-----------
.../runtime/matrix/data/LibMatrixNative.java | 2 +-
6 files changed, 76 insertions(+), 67 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/systemml/blob/08c7f00d/src/main/java/org/apache/sysml/runtime/instructions/cp/ConvolutionCPInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/instructions/cp/ConvolutionCPInstruction.java b/src/main/java/org/apache/sysml/runtime/instructions/cp/ConvolutionCPInstruction.java
index e32c3cf..34daf33 100644
--- a/src/main/java/org/apache/sysml/runtime/instructions/cp/ConvolutionCPInstruction.java
+++ b/src/main/java/org/apache/sysml/runtime/instructions/cp/ConvolutionCPInstruction.java
@@ -440,7 +440,9 @@ public class ConvolutionCPInstruction extends UnaryCPInstruction {
outputBlock = new MatrixBlock(N, K*P*Q, true);
}
else {
- outputBlock = new MatrixBlock(N, K*P*Q, false).allocateBlock();
+ boolean sparse = matBlock.isUltraSparse(false) && params.bias == null
+ && matBlock.getInMemorySize() < MatrixBlock.estimateSizeDenseInMemory(N, K*P*Q);
+ outputBlock = new MatrixBlock(N, K*P*Q, sparse).allocateBlock();
if(params.enableNative && !isFilterSparse(filter) && !matBlock.isInSparseFormat())
LibMatrixNative.conv2d(matBlock, filter, outputBlock, params);
else
http://git-wip-us.apache.org/repos/asf/systemml/blob/08c7f00d/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNConv2d.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNConv2d.java b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNConv2d.java
index e30de2c..22a5e1a 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNConv2d.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNConv2d.java
@@ -52,7 +52,7 @@ public class LibMatrixDNNConv2d
MatrixBlock in1 = params.input1;
boolean isEmptyDenseInput = !in1.isInSparseFormat() && in1.denseBlock == null;
- boolean isTransPref = in1.sparse && !params.input2.sparse &&
+ boolean isTransPref = in1.sparse && !params.input2.sparse && !params.output.sparse &&
MatrixBlock.evalSparseFormatInMemory(in1.clen, in1.rlen, in1.nonZeros);
boolean applyNative = isEligibleForConv2dSparse(params)
&& !(!isEmptyDenseInput && isTransPref);
@@ -171,8 +171,8 @@ public class LibMatrixDNNConv2d
@Override
public Long call() throws Exception {
final int PQ = _params.P*_params.Q, K = _params.K, CRS = _params.C*_params.R*_params.S;
- MatrixBlock outIm2col = new MatrixBlock(CRS, PQ, false);
- MatrixBlock outMM = new MatrixBlock(K, PQ, false);
+ MatrixBlock outIm2col = new MatrixBlock(CRS, PQ, _params.input1.sparse);
+ MatrixBlock outMM = new MatrixBlock(K, PQ, _params.output.sparse);
Im2colWorker im2ColWorker = Im2colWorker.getWorker( _params.input1, outIm2col, _params, false);
long time1 = 0; long time2 = 0;
for(int n = _rl; n < _ru; n++) {
@@ -182,7 +182,7 @@ public class LibMatrixDNNConv2d
long t2 = DMLScript.FINEGRAINED_STATISTICS ? System.nanoTime() : 0;
// filter %*% _im2ColOutBlock => matMultOutBlock
- outMM.reset(outMM.rlen, outMM.clen, false);
+ outMM.reset(outMM.rlen, outMM.clen, _params.output.sparse);
LibMatrixDNNHelper.singleThreadedMatMult(_params.input2, outIm2col, outMM, false, true, _params);
long t3 = DMLScript.FINEGRAINED_STATISTICS ? System.nanoTime() : 0;
@@ -191,8 +191,8 @@ public class LibMatrixDNNConv2d
time2 += t3 - t2;
}
- // Copy the matrix matMultOutBlock of shape [K X PQ] to params.output.denseBlock + destPos
- partialCopy1(outMM, _params.output.getDenseBlockValues(), n*K*PQ, K, PQ);
+ // Copy the outMM of shape [K x PQ] to a row in params.output
+ partialCopy1(outMM, _params.output, n, K, PQ);
// Add bias to current row if necessary, always dense
if(_params.bias != null)
@@ -209,27 +209,43 @@ public class LibMatrixDNNConv2d
return _params.output.recomputeNonZeros(_rl, _ru-1);
}
- // Copy the matrix src of shape [K X PQ] to params.output.denseBlock + destPos
- private static void partialCopy1(MatrixBlock src, double [] dest, int destPos, int K, int PQ) {
+ // Copy the matrix src of shape [K X PQ] to the r-th row in params.output
+ private static void partialCopy1(MatrixBlock src, MatrixBlock dest, int r, int K, int PQ) {
// Copying is required as LibMatrixMult.matrixMult (and/or Java) is not pointer aware.
- // This is not required in Native implementation
if( src.isEmptyBlock() )
return;
- if(src.isInSparseFormat()) {
- SparseBlock sblock = src.sparseBlock;
+ if( src.sparse ) { //* <- SPARSE
+ SparseBlock srcBlock = src.sparseBlock;
+ SparseBlock sdestBlock = dest.sparseBlock;
+ double[] ddestBlock = dest.getDenseBlockValues();
+
for(int k = 0; k < src.getNumRows(); k++) {
- if( sblock.isEmpty(k) ) continue;
- int apos = sblock.pos(k);
- int alen = sblock.size(k);
- int[] aix = sblock.indexes(k);
- double[] avals = sblock.values(k);
- int desPosK = destPos + k*PQ;
- for(int j = apos; j < apos+alen; j++)
- dest[desPosK+aix[j]] = avals[j];
+ if( srcBlock.isEmpty(k) ) continue;
+ int apos = srcBlock.pos(k);
+ int alen = srcBlock.size(k);
+ int[] aix = srcBlock.indexes(k);
+ double[] avals = srcBlock.values(k);
+ if( dest.sparse ) {
+ sdestBlock.setIndexRange(r,
+ 0, K*PQ, avals, aix, apos, alen);
+ }
+ else {
+ int desPosK = r + k*PQ;
+ for(int j = apos; j < apos+alen; j++)
+ ddestBlock[desPosK+aix[j]] = avals[j];
+ }
+ }
+ }
+ else { //* <- DENSE
+ if( dest.sparse ) {
+ dest.getSparseBlock().setIndexRange(r, 0, K*PQ,
+ src.getDenseBlockValues(), 0, K*PQ);
+ }
+ else {
+ System.arraycopy(src.getDenseBlockValues(), 0,
+ dest.getDenseBlockValues(), r*K*PQ, K*PQ);
}
}
- else
- System.arraycopy(src.getDenseBlockValues(), 0, dest, destPos, K * PQ);
}
}
http://git-wip-us.apache.org/repos/asf/systemml/blob/08c7f00d/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNHelper.java b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNHelper.java
index 32a0eaa..b985c42 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNHelper.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNHelper.java
@@ -62,7 +62,7 @@ public class LibMatrixDNNHelper
if( !params.enableNative || m1.sparse || m2.sparse ) {
prepNonZerosForMatrixMult(m1, recomputeNNZM1);
prepNonZerosForMatrixMult(m2, recomputeNNZM2);
- LibMatrixMult.matrixMult(m1, m2, ret, false);
+ LibMatrixMult.matrixMult(m1, m2, ret, true);
}
else {
ret.sparse = false;
http://git-wip-us.apache.org/repos/asf/systemml/blob/08c7f00d/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java
index ac7a6a8..4af4933 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java
@@ -54,7 +54,7 @@ public class LibMatrixDNNIm2Col {
//preallocate sparse-rows (larger than average sparsity to account for skew)
int estnnz = (int)Math.ceil(4*input.getSparsity()*out.clen);
for(int r = 0; r < out.rlen; r++)
- out.getSparseBlock().allocate(r, Math.min(estnnz, out.clen));
+ out.getSparseBlock().allocate(r, Math.max(Math.min(estnnz, out.clen),16));
return new SparseSparseIm2colWorkerAllChan(input, out, params, trans);
}
}
@@ -145,16 +145,15 @@ public class LibMatrixDNNIm2Col {
*/
private static class SparseSparseIm2colWorkerAllChan implements Im2colWorker {
private final MatrixBlock input, output;
- private final int S, R, P, Q, W, HW, RS;
+ private final int S, R, P, Q, H, W, RS;
private final int stride_h, stride_w, pad_h, pad_w;
private final boolean trans;
private final boolean simple;
public SparseSparseIm2colWorkerAllChan(MatrixBlock input, MatrixBlock im2ColOutBlock, ConvolutionParameters params, boolean trans) {
this.input = input;
this.output = im2ColOutBlock;
- this.HW = params.H * params.W;
this.RS = params.R * params.S;
- this.W = params.W; this.R = params.R; this.S = params.S; this.P = params.P; this.Q = params.Q;
+ this.H = params.H; this.W = params.W; this.R = params.R; this.S = params.S; this.P = params.P; this.Q = params.Q;
this.stride_h = params.stride_h; this.stride_w = params.stride_w;
this.pad_h = params.pad_h; this.pad_w = params.pad_w;
this.trans = trans;
@@ -175,20 +174,19 @@ public class LibMatrixDNNIm2Col {
double[] avals = sblock.values(n);
// Iterate over the sparse block
+ CellIndex3 ix = new CellIndex3();
for(int j=apos; j<apos+alen; j++) {
// Note: the input is of shape [N, CHW]
int chw = aix[j];
// Get individual zero-based c,h,w indexes from zero-based 'chw'
- int cInput = chw / HW;
- int hInput = (chw - cInput*HW)/W;
- int wInput = chw % W;
+ ix = LibMatrixDNNHelper.computeTensorIndexes(chw, H, W, ix);
if( simple )
- appendInputValueToIm2colOutputSimple(output, cInput, hInput, wInput,
+ appendInputValueToIm2colOutputSimple(output, ix.ix1, ix.ix2, ix.ix3,
avals[j], R, S, RS, P, trans);
else
- appendInputValueToIm2colOutput(output, cInput, hInput, wInput, avals[j],
+ appendInputValueToIm2colOutput(output, ix.ix1, ix.ix2, ix.ix3, avals[j],
R, S, P, Q, stride_h, stride_w, pad_h, pad_w, trans);
}
http://git-wip-us.apache.org/repos/asf/systemml/blob/08c7f00d/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixMult.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixMult.java b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixMult.java
index 6119e95..d5ed8b2 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixMult.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixMult.java
@@ -95,22 +95,18 @@ public class LibMatrixMult
* @param m1 first matrix
* @param m2 second matrix
* @param ret result matrix
- * @param maintainNnz if false, nnzs are not recomputed and evaluated
+ * @param fixedRet if true, output representation is fixed and nnzs not recomputed
* @throws DMLRuntimeException if DMLRuntimeException occurs
*/
- public static void matrixMult(MatrixBlock m1, MatrixBlock m2, MatrixBlock ret, boolean maintainNnz)
- throws DMLRuntimeException
- {
- matrixMult(m1, m2, ret, 0, m1.rlen, maintainNnz);
+ public static void matrixMult(MatrixBlock m1, MatrixBlock m2, MatrixBlock ret, boolean fixedRet) throws DMLRuntimeException {
+ matrixMult(m1, m2, ret, 0, m1.rlen, fixedRet);
}
- public static void matrixMult(MatrixBlock m1, MatrixBlock m2, MatrixBlock ret, int rl, int ru)
- throws DMLRuntimeException
- {
- matrixMult(m1, m2, ret, rl, ru, true);
+ public static void matrixMult(MatrixBlock m1, MatrixBlock m2, MatrixBlock ret, int rl, int ru) throws DMLRuntimeException {
+ matrixMult(m1, m2, ret, rl, ru, false);
}
- public static void matrixMult(MatrixBlock m1, MatrixBlock m2, MatrixBlock ret, int rl, int ru, boolean maintainNnz)
+ public static void matrixMult(MatrixBlock m1, MatrixBlock m2, MatrixBlock ret, int rl, int ru, boolean fixedRet)
throws DMLRuntimeException
{
//check inputs / outputs
@@ -122,14 +118,16 @@ public class LibMatrixMult
//Timing time = new Timing(true);
//pre-processing: output allocation
- boolean ultraSparse = isUltraSparseMatrixMult(m1, m2);
+ boolean ultraSparse = (fixedRet && ret.sparse)
+ || (!fixedRet && isUltraSparseMatrixMult(m1, m2));
boolean tm2 = checkPrepMatrixMultRightInput(m1,m2);
m2 = prepMatrixMultRightInput(m1, m2);
ret.sparse = ultraSparse;
ret.allocateBlock();
//prepare row-upper for special cases of vector-matrix
- boolean pm2 = checkParMatrixMultRightInputRows(m1, m2, Integer.MAX_VALUE);
+ boolean pm2 = !ultraSparse &&
+ checkParMatrixMultRightInputRows(m1, m2, Integer.MAX_VALUE);
int ru2 = (pm2 && ru==m1.rlen) ? m2.rlen : ru;
int cu = m2.clen;
@@ -146,7 +144,7 @@ public class LibMatrixMult
matrixMultDenseSparse(m1, m2, ret, pm2, 0, ru2);
//post-processing: nnz/representation
- if( maintainNnz ) {
+ if( !fixedRet ) {
if( !ret.sparse )
ret.recomputeNonZeros();
ret.examSparsity();
@@ -200,8 +198,8 @@ public class LibMatrixMult
}
//prepare row-upper for special cases of vector-matrix / matrix-matrix
- boolean pm2r = checkParMatrixMultRightInputRows(m1, m2, k);
- boolean pm2c = checkParMatrixMultRightInputCols(m1, m2, k, pm2r);
+ boolean pm2r = !ultraSparse && checkParMatrixMultRightInputRows(m1, m2, k);
+ boolean pm2c = !ultraSparse && checkParMatrixMultRightInputCols(m1, m2, k, pm2r);
int num = pm2r ? m2.rlen : pm2c ? m2.clen : m1.rlen;
//core multi-threaded matrix mult computation
@@ -1642,25 +1640,20 @@ public class LibMatrixMult
{
SparseBlock b = m2.sparseBlock;
- for(int k = 0; k < cd; k++ )
- {
- if( !b.isEmpty(k) )
- {
- int bpos = b.pos(k);
- int blen = b.size(k);
- int[] bixs = b.indexes(k);
- double[] bvals = b.values(k);
- for( int j=bpos; j<bpos+blen; j++ )
- {
- double bval = bvals[j];
- int bix = bixs[j];
- for( int i=rl; i<ru; i++ )
- {
- double cvald = bval*m1.quickGetValue(i, k);
- if( cvald != 0 ){
- double cval = ret.quickGetValue(i, bix);
- ret.quickSetValue(i, bix, cval+cvald);
- }
+ for(int k = 0; k < cd; k++ ) {
+ if( b.isEmpty(k) ) continue;
+ int bpos = b.pos(k);
+ int blen = b.size(k);
+ int[] bixs = b.indexes(k);
+ double[] bvals = b.values(k);
+ for( int j=bpos; j<bpos+blen; j++ ) {
+ double bval = bvals[j];
+ int bix = bixs[j];
+ for( int i=rl; i<ru; i++ ) {
+ double cvald = bval*m1.quickGetValue(i, k);
+ if( cvald != 0 ){
+ double cval = ret.quickGetValue(i, bix);
+ ret.quickSetValue(i, bix, cval+cvald);
}
}
}
http://git-wip-us.apache.org/repos/asf/systemml/blob/08c7f00d/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixNative.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixNative.java b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixNative.java
index 9e3a6ee..7e0a6d7 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixNative.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixNative.java
@@ -109,7 +109,7 @@ public class LibMatrixNative
Statistics.incrementNativeFailuresCounter();
}
if (k == 1)
- LibMatrixMult.matrixMult(m1, m2, ret, examSparsity);
+ LibMatrixMult.matrixMult(m1, m2, ret, !examSparsity);
else
LibMatrixMult.matrixMult(m1, m2, ret, k);
}
[2/2] systemml git commit: [SYSTEMML-2142] Performance sparse im2col
(constraint handling)
Posted by mb...@apache.org.
[SYSTEMML-2142] Performance sparse im2col (constraint handling)
This patch improves the performance of sparse im2col operations (general
case for arbitrary pad and stride) because it dominates the runtime of
ultra-sparse conv2d operations by more than an order-of-magnitude. On a
scenario of conv2d operations over ultra sparse inputs with sparsity
1e-5, this patch improves performance by more than 2.5x.
Project: http://git-wip-us.apache.org/repos/asf/systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/401b7965
Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/401b7965
Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/401b7965
Branch: refs/heads/master
Commit: 401b796578fb9dbdc2b835ce84263ea61910c9e3
Parents: 08c7f00
Author: Matthias Boehm <mb...@gmail.com>
Authored: Fri Feb 9 22:23:42 2018 -0800
Committer: Matthias Boehm <mb...@gmail.com>
Committed: Fri Feb 9 22:23:42 2018 -0800
----------------------------------------------------------------------
.../runtime/matrix/data/LibMatrixDNNIm2Col.java | 46 +++++++++-----------
1 file changed, 21 insertions(+), 25 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/systemml/blob/401b7965/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java
index 4af4933..d1f4b30 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixDNNIm2Col.java
@@ -187,7 +187,7 @@ public class LibMatrixDNNIm2Col {
avals[j], R, S, RS, P, trans);
else
appendInputValueToIm2colOutput(output, ix.ix1, ix.ix2, ix.ix3, avals[j],
- R, S, P, Q, stride_h, stride_w, pad_h, pad_w, trans);
+ R, S, RS, P, Q, stride_h, stride_w, pad_h, pad_w, trans);
}
output.sortSparseRows();
@@ -198,51 +198,47 @@ public class LibMatrixDNNIm2Col {
* Appends the value corresponding to the given [, cInput, hInput, wInput] to the appropriate im2col location of the output
*
* @param output output matrix block
- * @param cInput input channel index (zero-based)
- * @param hInput input height index (zero-based)
- * @param wInput input width index (zero-based)
+ * @param c input channel index (zero-based)
+ * @param h input height index (zero-based)
+ * @param w input width index (zero-based)
* @param value input value
* @param R filter height
* @param S filter width
+ * @param RS R*S
* @param P output height
* @param Q output width
* @param stride_h stride height
* @param stride_w stride width
* @param pad_h pad height
* @param pad_w pad width
+ * @param trans transposed output
*/
- private static void appendInputValueToIm2colOutput(MatrixBlock output, int cInput, int hInput, int wInput, double value,
- int R, int S, int P, int Q, int stride_h, int stride_w, int pad_h, int pad_w, boolean trans) {
- int RS = R*S;
+ private static void appendInputValueToIm2colOutput(MatrixBlock output, int c, int h, int w, double value,
+ int R, int S, int RS, int P, int Q, int stride_h, int stride_w, int pad_h, int pad_w, boolean trans)
+ {
// For the given h,w index, insert avals[j] into respective r,s,p,q locations
-
// Constraints: for(int r = 0; r < R; r++) { if(0 <= p && p < P && (hInput - r + pad_h) % stride_h == 0) { ... } }
// Constraint 1: p >= 0 and p = (hInput - r + pad_h) / stride_h
// Therefore, r <= hInput + pad_h
// Constraint 2: p < P and p = (hInput - r + pad_h) / stride_h
// Therefore, hInput + pad_h - P*stride_h < r
// Math.max(0, hInput + pad_h - P*stride_h + 1) <= r <= Math.min(R-1, hInput + pad_h)
- int rMin = Math.max(0, hInput + pad_h - P*stride_h + 1);
- int rMax = Math.min(R-1, hInput + pad_h);
- int sMin = Math.max(0, wInput + pad_w - Q*stride_w + 1);
- int sMax = Math.min(S-1, wInput + pad_w);
+ int rMin = Math.max(0, h + pad_h - P*stride_h + 1);
+ int rMax = Math.min(R-1, h + pad_h);
+ int sMin = Math.max(0, w + pad_w - Q*stride_w + 1);
+ int sMax = Math.min(S-1, w + pad_w);
// Constraint 3: (hInput - r + pad_h) % stride_h == 0
- while((hInput - rMin + pad_h) % stride_h != 0 && rMin <= rMax) rMin++;
- while((wInput - sMin + pad_w) % stride_w != 0 && sMin <= sMax) sMin++;
+ rMin += Math.min((h-rMin+pad_h) % stride_h, rMax-rMin+1);
+ sMin += Math.min((w-sMin+pad_w) % stride_w, sMax-sMin+1);
- for(int r = rMin; r <= rMax; r += stride_h) {
+ for( int r=rMin, ix=c*RS+rMin*S; r<=rMax; r+=stride_h, ix+=stride_h*S ) {
// Only append value if h == hInput, where h = (r - pad_h) + p*stride_h and 0 <= p < P
// Therefore, p = (hInput - r + pad_h) / stride_h. Use the same logic for q.
- final int p = (hInput - r + pad_h) / stride_h;
- final int pQ = p*Q;
- final int outRowIndex = cInput*RS + r*S;
- for(int s = sMin; s <= sMax; s += stride_w) {
- int q = (wInput - s + pad_w) / stride_w;
- // chw -> [crs, pq]
- if( trans )
- output.appendValue(pQ + q, outRowIndex + s, value);
- else
- output.appendValue(outRowIndex + s, pQ + q, value);
+ final int pQ = (h - r + pad_h) / stride_h * Q;
+ for(int s=sMin, ws=w-sMin+pad_w; s<=sMax; s+=stride_w, ws-=stride_w) {
+ int q = ws / stride_w; // chw -> [crs, pq]
+ output.appendValue(trans ? pQ+q : ix+s,
+ trans ? ix+s : pQ+q, value);
}
}
}