Repository: incubator-systemml
Updated Branches:
  refs/heads/master b9814ccf0 -> 44d7a8857


[MINOR] Added SGDNesterovUpdate UDF support to Caffe2DML

This will allow us to extrapolate the performance gains using codegen.
The UDF is disabled by default and is enabled only after setting `export
USE_NESTEROV_UDF="true"`. We will remove this flag and also the class
org.apache.sysml.udf.lib.SGDNesterovUpdate after codegen is stable.


Project: http://git-wip-us.apache.org/repos/asf/incubator-systemml/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-systemml/commit/44d7a885
Tree: http://git-wip-us.apache.org/repos/asf/incubator-systemml/tree/44d7a885
Diff: http://git-wip-us.apache.org/repos/asf/incubator-systemml/diff/44d7a885

Branch: refs/heads/master
Commit: 44d7a88576dccce0bc2262588eb25cb521ca739d
Parents: b9814cc
Author: Niketan Pansare <npan...@us.ibm.com>
Authored: Fri May 5 15:32:12 2017 -0800
Committer: Niketan Pansare <npan...@us.ibm.com>
Committed: Fri May 5 16:32:12 2017 -0700

----------------------------------------------------------------------
 .../apache/sysml/udf/lib/SGDNesterovUpdate.java | 52 +++++++++++++++++---
 .../org/apache/sysml/api/dl/Caffe2DML.scala     | 11 +++++
 .../org/apache/sysml/api/dl/CaffeSolver.scala   |  5 +-
 3 files changed, 59 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/44d7a885/src/main/java/org/apache/sysml/udf/lib/SGDNesterovUpdate.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/udf/lib/SGDNesterovUpdate.java 
b/src/main/java/org/apache/sysml/udf/lib/SGDNesterovUpdate.java
index fa3bd0e..9c027d3 100644
--- a/src/main/java/org/apache/sysml/udf/lib/SGDNesterovUpdate.java
+++ b/src/main/java/org/apache/sysml/udf/lib/SGDNesterovUpdate.java
@@ -67,6 +67,10 @@ public class SGDNesterovUpdate extends PackageFunction {
                
                throw new RuntimeException("Invalid function output being 
requested");
        }
+       
+       boolean isDense(MatrixBlock X) {
+               return !X.isInSparseFormat() && X.getDenseBlock() != null;
+       }
 
        @Override
        public void execute() {
@@ -81,19 +85,53 @@ public class SGDNesterovUpdate extends PackageFunction {
                        updatedV = new Matrix( "tmp_" + rand.nextLong(), 
v.getNumRows(), v.getNumColumns(), ValueType.Double );
                        MatrixBlock updatedVMB = 
allocateDenseMatrixBlock(updatedV);
                        double [] updatedVData = updatedVMB.getDenseBlock();
-                       multiplyByConstant(v, mu, updatedVData);
-                       multiplyByConstant(dX, -lr, updatedVData);
-                       updatedVMB.setNonZeros(-1); // rather than 
updatedVMB.recomputeNonZeros();
+                       if(isDense(v) && isDense(dX)) {
+                               double [] vArr = v.getDenseBlock();
+                               double [] dXArr = dX.getDenseBlock();
+                               int nnz = 0;
+                               for(int i = 0; i < updatedVData.length; i++) {
+                                       updatedVData[i] = mu*vArr[i] - 
lr*dXArr[i];
+                                       nnz += (updatedVData[i]!=0) ? 1 : 0;
+                               }
+                               updatedVMB.setNonZeros(nnz); 
+                       }
+                       else {
+                               multiplyByConstant(v, mu, updatedVData);
+                               multiplyByConstant(dX, -lr, updatedVData);
+                               updatedVMB.recomputeNonZeros();
+                       }
                        updatedV.setMatrixDoubleArray(updatedVMB, 
OutputInfo.BinaryBlockOutputInfo, InputInfo.BinaryBlockInputInfo);
                        
                        // X = X - mu * v_prev + (1 + mu) * v
                        updatedX = new Matrix( "tmp_" + rand.nextLong(), 
X.getNumRows(), X.getNumColumns(), ValueType.Double );
                        MatrixBlock updatedXMB = 
allocateDenseMatrixBlock(updatedX);
                        double [] updatedXData = updatedXMB.getDenseBlock();
-                       copy(X, updatedXData);
-                       multiplyByConstant(v, -mu, updatedXData);
-                       multiplyByConstant(updatedVData, 1+mu, updatedXData);
-                       updatedXMB.setNonZeros(-1); // rather than 
updatedXMB.recomputeNonZeros();
+                       if(isDense(X) && isDense(v)) {
+                               double [] XArr = X.getDenseBlock();
+                               double [] vPrevArr = v.getDenseBlock();
+                               int nnz = 0; double muPlus1 = mu+1;
+                               for(int i = 0; i < updatedXData.length; i++) {
+                                       updatedXData[i] = XArr[i] - 
mu*vPrevArr[i] + muPlus1*updatedVData[i];
+                                       nnz += (updatedXData[i]!=0) ? 1 : 0;
+                               }
+                               updatedXMB.setNonZeros(nnz); 
+                       }
+                       else if(isDense(v)) {
+                               copy(X, updatedXData);
+                               double [] vPrevArr = v.getDenseBlock();
+                               int nnz = 0; double muPlus1 = mu+1;
+                               for(int i = 0; i < updatedXData.length; i++) {
+                                       updatedXData[i] += - mu*vPrevArr[i] + 
muPlus1*updatedVData[i];
+                                       nnz += (updatedXData[i]!=0) ? 1 : 0;
+                               }
+                               updatedXMB.setNonZeros(nnz);
+                       }
+                       else {
+                               copy(X, updatedXData);
+                               multiplyByConstant(v, -mu, updatedXData);
+                               multiplyByConstant(updatedVData, 1+mu, 
updatedXData);
+                               updatedXMB.recomputeNonZeros();
+                       }
                        updatedX.setMatrixDoubleArray(updatedXMB, 
OutputInfo.BinaryBlockOutputInfo, InputInfo.BinaryBlockInputInfo);
                        
                        ((Matrix) 
getFunctionInput(0)).getMatrixObject().release();

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/44d7a885/src/main/scala/org/apache/sysml/api/dl/Caffe2DML.scala
----------------------------------------------------------------------
diff --git a/src/main/scala/org/apache/sysml/api/dl/Caffe2DML.scala 
b/src/main/scala/org/apache/sysml/api/dl/Caffe2DML.scala
index 22de112..377ebf3 100644
--- a/src/main/scala/org/apache/sysml/api/dl/Caffe2DML.scala
+++ b/src/main/scala/org/apache/sysml/api/dl/Caffe2DML.scala
@@ -61,6 +61,13 @@ object Caffe2DML  {
   // Naming conventions:
   val X = "X"; val y = "y"; val batchSize = "BATCH_SIZE"; val numImages = 
"num_images"; val numValidationImages = "num_validation"
   val XVal = "X_val"; val yVal = "y_val"
+  
+  var USE_NESTEROV_UDF = {
+    // Developer environment variable flag 'USE_NESTEROV_UDF' until codegen 
starts working.
+    // Then, we will remove this flag and also the class 
org.apache.sysml.udf.lib.SGDNesterovUpdate
+    val envFlagNesterovUDF = System.getenv("USE_NESTEROV_UDF")
+    envFlagNesterovUDF != null && envFlagNesterovUDF.toBoolean
+  }
 }
 
 class Caffe2DML(val sc: SparkContext, val solverParam:Caffe.SolverParameter, 
@@ -283,6 +290,10 @@ class Caffe2DML(val sc: SparkContext, val 
solverParam:Caffe.SolverParameter,
          source(net, solver, Array[String]("l2_reg"))
          appendVisualizationHeaders(dmlScript, numTabs)
          
+         if(Caffe2DML.USE_NESTEROV_UDF) {
+           tabDMLScript(dmlScript, numTabs).append("update_nesterov = 
externalFunction(matrix[double] X, matrix[double] dX, double lr, double mu, 
matrix[double] v) return (matrix[double] X, matrix[double] v) implemented in 
(classname=\"org.apache.sysml.udf.lib.SGDNesterovUpdate\",exectype=\"mem\");  
\n")
+         }
+         
          // Read and convert to one-hote encoding
          assign(tabDMLScript, "X_full", "read(\" \", format=\"csv\")")
          assign(tabDMLScript, "y_full", "read(\" \", format=\"csv\")")

http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/44d7a885/src/main/scala/org/apache/sysml/api/dl/CaffeSolver.scala
----------------------------------------------------------------------
diff --git a/src/main/scala/org/apache/sysml/api/dl/CaffeSolver.scala 
b/src/main/scala/org/apache/sysml/api/dl/CaffeSolver.scala
index 755949d..ae3d21d 100644
--- a/src/main/scala/org/apache/sysml/api/dl/CaffeSolver.scala
+++ b/src/main/scala/org/apache/sysml/api/dl/CaffeSolver.scala
@@ -145,10 +145,11 @@ class AdaGrad(lambda:Double=5e-04, epsilon:Double=1e-6) 
extends CaffeSolver {
 class Nesterov(lambda:Double=5e-04, momentum:Double=0.9) extends CaffeSolver {
   def update(dmlScript:StringBuilder, layer:CaffeLayer):Unit = {
     l2reg_update(lambda, dmlScript, layer)
+    val fn = if(Caffe2DML.USE_NESTEROV_UDF) "update_nesterov" else 
"sgd_nesterov::update"
     if(layer.shouldUpdateWeight) dmlScript.append("\t").append("["+ 
commaSep(layer.weight, layer.weight+"_v") + "] " + 
-        "= sgd_nesterov::update(" + commaSep(layer.weight, layer.dWeight, 
getWeightLr(layer), momentum.toString, layer.weight+"_v") + ")\n")
+        "= " + fn + "(" + commaSep(layer.weight, layer.dWeight, 
getWeightLr(layer), momentum.toString, layer.weight+"_v") + ")\n")
     if(layer.shouldUpdateBias) dmlScript.append("\t").append("["+ 
commaSep(layer.bias, layer.bias+"_v") + "] " + 
-        "= sgd_nesterov::update(" + commaSep(layer.bias, layer.dBias, 
getBiasLr(layer), momentum.toString, layer.bias+"_v") + ")\n")
+        "= " + fn + "(" + commaSep(layer.bias, layer.dBias, getBiasLr(layer), 
momentum.toString, layer.bias+"_v") + ")\n")
   }
   def init(dmlScript:StringBuilder, layer:CaffeLayer):Unit = {
     if(layer.shouldUpdateWeight) dmlScript.append(layer.weight+"_v = 
sgd_nesterov::init(" + layer.weight + ")\n")

Reply via email to