Repository: incubator-systemml Updated Branches: refs/heads/master 998b0b1a5 -> a23396df6
[SYSTEMML-1187] Updated the documentation for removeEmpty with select and bugfix for relu_backward Also, added a multi-input cbind external function. Project: http://git-wip-us.apache.org/repos/asf/incubator-systemml/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-systemml/commit/a23396df Tree: http://git-wip-us.apache.org/repos/asf/incubator-systemml/tree/a23396df Diff: http://git-wip-us.apache.org/repos/asf/incubator-systemml/diff/a23396df Branch: refs/heads/master Commit: a23396df60f485c8a6627afbf4e322145922707b Parents: 998b0b1 Author: Niketan Pansare <[email protected]> Authored: Sun Jan 22 19:12:13 2017 -0800 Committer: Niketan Pansare <[email protected]> Committed: Sun Jan 22 19:12:13 2017 -0800 ---------------------------------------------------------------------- docs/dml-language-reference.md | 2 +- .../java/org/apache/sysml/hops/BinaryOp.java | 3 +- .../apache/sysml/udf/lib/MultiInputCbind.java | 177 +++++++++++++++++++ 3 files changed, 180 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/a23396df/docs/dml-language-reference.md ---------------------------------------------------------------------- diff --git a/docs/dml-language-reference.md b/docs/dml-language-reference.md index 80fc8ca..c828e70 100644 --- a/docs/dml-language-reference.md +++ b/docs/dml-language-reference.md @@ -628,7 +628,7 @@ nrow(), <br/> ncol(), <br/> length() | Return the number of rows, number of colu prod() | Return the product of all cells in matrix | Input: matrix <br/> Output: scalarj | prod(X) rand() | Generates a random matrix | Input: (rows=<value>, cols=<value>, min=<value>, max=<value>, sparsity=<value>, pdf=<string>, seed=<value>) <br/> rows/cols: Number of rows/cols (expression) <br/> min/max: Min/max value for cells (either constant value, or variable that evaluates to constant value) <br/> sparsity: fraction of non-zero cells (constant value) <br/> pdf: "uniform" (min, max) distribution, or "normal" (0,1) distribution; or "poisson" (lambda=1) distribution. string; default value is "uniform". Note that, for the Poisson distribution, users can provide the mean/lambda parameter as follows: <br/> rand(rows=1000,cols=1000, pdf="poisson", lambda=2.5). <br/> The default value for lambda is 1. <br/> seed: Every invocation of rand() internally generates a random seed with which the cell values are generated. One can optionally provide a seed when repeatability is desired. <br/> Output: matrix | XÂ = rand(rows=10, cols=20, min=0, m ax=1, pdf="uniform", sparsity=0.2) <br/> The example generates a 10 x 20 matrix, with cell values uniformly chosen at random between 0 and 1, and approximately 20% of cells will have non-zero values. rbind() | Row-wise matrix concatenation. Concatenates the second matrix as additional rows to the first matrix | Input: (X <matrix>, Y <matrix>) <br/>Output: <matrix> <br/> X and Y are matrices, where the number of columns in X and the number of columns in Y are the same. | A = matrix(1, rows=2,cols=3) <br/> B = matrix(2, rows=2,cols=3) <br/> C = rbind(A,B) <br/> print("Dimensions of C: " + nrow(C) + " X " + ncol(C)) <br/> Output: <br/> Dimensions of C: 4 X 3 -removeEmpty() | Removes all empty rows or columns from the input matrix target X according to the specified margin. | Input : (target= X <matrix>, margin="...") <br/> Output : <matrix> <br/> Valid values for margin are "rows" or "cols". | A = removeEmpty(target=X, margin="rows") +removeEmpty() | Removes all empty rows or columns from the input matrix target X according to the specified margin. Also, allows to apply a filter F before removing the empty rows/cols. | Input : (target= X <matrix>, margin="...", select=F) <br/> Output : <matrix> <br/> Valid values for margin are "rows" or "cols". | A = removeEmpty(target=X, margin="rows", select=F) replace() | Creates a copy of input matrix X, where all values that are equal to the scalar pattern s1 are replaced with the scalar replacement s2. | Input : (target= X <matrix>, pattern=<scalar>, replacement=<scalar>) <br/> Output : <matrix> <br/> If s1 is NaN, then all NaN values of X are treated as equal and hence replaced with s2. Positive and negative infinity are treated as different values. | A = replace(target=X, pattern=s1, replacement=s2) rev() | Reverses the rows in a matrix | Input : (<matrix>) <br/> Output : <matrix> | <span style="white-space: nowrap;">A = matrix("1 2 3 4", rows=2, cols=2)</span> <br/> <span style="white-space: nowrap;">B = matrix("1 2 3 4", rows=4, cols=1)</span> <br/> <span style="white-space: nowrap;">C = matrix("1 2 3 4", rows=1, cols=4)</span> <br/> revA = rev(A) <br/> revB = rev(B) <br/> revC = rev(C) <br/> Matrix revA: [[3, 4], [1, 2]]<br/> Matrix revB: [[4], [3], [2], [1]]<br/> Matrix revC: [[1, 2, 3, 4]]<br/> seq() | Creates a single column vector with values starting from <from>, to <to>, in increments of <increment> | Input: (<from>, <to>, <increment>) <br/> Output: <matrix> | S = seq (10, 200, 10) http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/a23396df/src/main/java/org/apache/sysml/hops/BinaryOp.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/hops/BinaryOp.java b/src/main/java/org/apache/sysml/hops/BinaryOp.java index 7321d68..6269919 100644 --- a/src/main/java/org/apache/sysml/hops/BinaryOp.java +++ b/src/main/java/org/apache/sysml/hops/BinaryOp.java @@ -603,7 +603,8 @@ public class BinaryOp extends Hop && potentialZero instanceof LiteralOp && ((LiteralOp) potentialZero).getDoubleValue() == 0; if(op == OpOp2.MULT && isLeftXGt0 && - !getInput().get(0).isVector() && !getInput().get(1).isVector()) { + !getInput().get(0).isVector() && !getInput().get(1).isVector() + && getInput().get(0).dimsKnown() && getInput().get(1).dimsKnown()) { binary = new ConvolutionTransform(getInput().get(0).getInput().get(0).constructLops(), getInput().get(1).constructLops(), ConvolutionTransform.OperationTypes.RELU_BACKWARD, getDataType(), getValueType(), et, -1); http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/a23396df/src/main/java/org/apache/sysml/udf/lib/MultiInputCbind.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/udf/lib/MultiInputCbind.java b/src/main/java/org/apache/sysml/udf/lib/MultiInputCbind.java new file mode 100644 index 0000000..30d3571 --- /dev/null +++ b/src/main/java/org/apache/sysml/udf/lib/MultiInputCbind.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sysml.udf.lib; + +import java.io.IOException; +import java.util.Iterator; + +import org.apache.sysml.runtime.DMLRuntimeException; +import org.apache.sysml.runtime.controlprogram.caching.CacheException; +import org.apache.sysml.runtime.matrix.data.IJV; +import org.apache.sysml.runtime.matrix.data.InputInfo; +import org.apache.sysml.runtime.matrix.data.MatrixBlock; +import org.apache.sysml.runtime.matrix.data.OutputInfo; +import org.apache.sysml.udf.FunctionParameter; +import org.apache.sysml.udf.Matrix; +import org.apache.sysml.udf.PackageFunction; +import org.apache.sysml.udf.Scalar; +import org.apache.sysml.udf.Matrix.ValueType; + +/** + * This external built-in function addresses following two common scenarios: + * 1. cbind (cbind (cbind ( X1, X2 ), X3 ), X4) + * 2. With spagetization: cbind (cbind (cbind ( matrix(X1, rows=length(X1), cols=1), matrix(X2, rows=length(X2), cols=1) ), matrix(X3, rows=length(X3), cols=1) ), matrix(X4, rows=length(X4), cols=1)) + * + * The API of this external built-in function is as follows: + * + * func = externalFunction(int numInputs, boolean spagetize, matrix[double] X1, matrix[double] X2, matrix[double] X3, matrix[double] X4) return (matrix[double] out) + * implemented in (classname="org.apache.sysml.udf.lib.MultiInputCbind",exectype="mem"); + * + */ +public class MultiInputCbind extends PackageFunction { + private static final long serialVersionUID = -4266180315672563097L; + + private Matrix ret; + private MatrixBlock retMB; + long numRetRows; long numRetCols; + boolean spagetize; + + @Override + public int getNumFunctionOutputs() { + return 1; + } + + @Override + public FunctionParameter getFunctionOutput(int pos) { + if(pos == 0) + return ret; + else + throw new RuntimeException("MultiInputCbind produces only one output"); + } + + @Override + public void execute() { + int numInputs = Integer.parseInt(((Scalar)getFunctionInput(0)).getValue()); + spagetize = Boolean.parseBoolean(((Scalar)getFunctionInput(1)).getValue()); + + // Compute output dimensions + try { + numRetCols = 0; + if(spagetize) { + // Assumption the inputs are of same shape + MatrixBlock in = ((Matrix) getFunctionInput(2)).getMatrixObject().acquireRead(); + numRetRows = in.getNumRows()*in.getNumColumns(); + numRetCols = numInputs; + ((Matrix) getFunctionInput(2)).getMatrixObject().release(); + } + else { + for(int inputID = 2; inputID < numInputs + 2; inputID++) { + MatrixBlock in = ((Matrix) getFunctionInput(inputID)).getMatrixObject().acquireRead(); + numRetRows = in.getNumRows(); + numRetCols += in.getNumColumns(); + ((Matrix) getFunctionInput(inputID)).getMatrixObject().release(); + } + } + } catch (CacheException e) { + throw new RuntimeException("Error while executing MultiInputCbind", e); + } + + allocateOutput(); + + // Performs cbind (cbind (cbind ( X1, X2 ), X3 ), X4) + double [] retData = retMB.getDenseBlock(); + try { + int startColumn = 0; + for(int inputID = 2; inputID < numInputs + 2; inputID++) { + MatrixBlock in = ((Matrix) getFunctionInput(inputID)).getMatrixObject().acquireRead(); + if(spagetize && in.getNumRows()*in.getNumColumns() != numRetRows) { + throw new RuntimeException("Expected the inputs to be of same size when spagetization is turned on."); + } + int inputNumCols = in.getNumColumns(); + if(in.isInSparseFormat()) { + Iterator<IJV> iter = in.getSparseBlockIterator(); + while(iter.hasNext()) { + IJV ijv = iter.next(); + if(spagetize) { + // Perform matrix(X1, rows=length(X1), cols=1) operation before cbind + // Output Column ID = inputID-2 for all elements of inputs + int outputRowIndex = ijv.getI()*inputNumCols + ijv.getJ(); + int outputColIndex = inputID-2; + retData[(int) (outputRowIndex*retMB.getNumColumns() + outputColIndex)] = ijv.getV(); + } + else { + // Traditional cbind + // Row ID remains the same as that of input + int outputRowIndex = ijv.getI(); + int outputColIndex = ijv.getJ() + startColumn; + retData[(int) (outputRowIndex*retMB.getNumColumns() + outputColIndex)] = ijv.getV(); + } + } + } + else { + double [] denseBlock = in.getDenseBlock(); + if(denseBlock != null) { + if(spagetize) { + // Perform matrix(X1, rows=length(X1), cols=1) operation before cbind + // Output Column ID = inputID-2 for all elements of inputs + int j = inputID-2; + for(int i = 0; i < numRetRows; i++) { + retData[(int) (i*numRetCols + j)] = denseBlock[i]; + } + } + else { + // Traditional cbind + // Row ID remains the same as that of input + for(int i = 0; i < retMB.getNumRows(); i++) { + for(int j = 0; j < inputNumCols; j++) { + int outputColIndex = j + startColumn; + retData[(int) (i*numRetCols + outputColIndex)] = denseBlock[i*inputNumCols + j]; + } + } + } + } + } + ((Matrix) getFunctionInput(inputID)).getMatrixObject().release(); + startColumn += inputNumCols; + } + } catch (CacheException e) { + throw new RuntimeException("Error while executing MultiInputCbind", e); + } + + retMB.recomputeNonZeros(); + try { + retMB.examSparsity(); + ret.setMatrixDoubleArray(retMB, OutputInfo.BinaryBlockOutputInfo, InputInfo.BinaryBlockInputInfo); + } catch (DMLRuntimeException e) { + throw new RuntimeException("Error while executing MultiInputCbind", e); + } catch (IOException e) { + throw new RuntimeException("Error while executing MultiInputCbind", e); + } + } + + private void allocateOutput() { + String dir = createOutputFilePathAndName( "TMP" ); + ret = new Matrix( dir, numRetRows, numRetCols, ValueType.Double ); + retMB = new MatrixBlock((int) numRetRows, (int) numRetCols, false); + retMB.allocateDenseBlock(); + } + + +}
