As you know I am running machine learning for all to experiment with automated machine learning with all the people that want to try it for free.
This time I want to share with you some of code running behind the scenes , in particular the scala code that , once a file with data and one with target column has been uploaded for analysis to a temporary folder of my azure blob account, trigger the execution of the entire automated machine learning workflows that , as I explained here runs on top of TransmogrifAI .
Of course there is a LOT that can be improved (how many times am I rewriting the same blob configuration paths ?????, proper error management, etc…) but it’s a starting point :-):
import com.salesforce.op.features.FeatureBuilder import org.apache.spark.SparkConf import org.apache.spark.sql.SparkSession import org.apache.log4j.{Level, LogManager} import org.apache.spark.sql.types._ import com.salesforce.op._ import com.salesforce.op.features.types._ import com.salesforce.op.stages.impl.regression.RegressionModelSelector import com.salesforce.op.stages.impl.classification._ import org.apache.hadoop.fs.{FileSystem, FileUtil, Path} object AzureBlobAnalysisv2 { def main(args: Array[String]) { LogManager.getLogger("com.salesforce.op").setLevel(Level.ERROR) val conf = new SparkConf() conf.setAppName("AutoMLForAll") var uniqueId=args(0) /* WASB */ conf.set("spark.hadoop.fs.wasb.impl", "org.apache.hadoop.fs.azure.NativeAzureFileSystem") conf.set("fs.azure.account.key.REPLACETHIS.blob.core.windows.net", "REPLACETHISKEY") implicit val spark = SparkSession.builder.config(conf).getOrCreate() spark.sparkContext.hadoopConfiguration.set("spark.hadoop.fs.wasb.impl", "org.apache.hadoop.fs.azure.NativeAzureFileSystem") spark.sparkContext.hadoopConfiguration.set("fs.azure.account.key.REPLACETHIS.blob.core.windows.net", "REPLACETHISKEY") val confh=new org.apache.hadoop.conf.Configuration() confh.set("spark.hadoop.fs.wasb.impl", "org.apache.hadoop.fs.azure.NativeAzureFileSystem") confh.set("fs.azure.account.key.REPLACETHIS.blob.core.windows.net", "REPLACETHISKEY") confh.set("fs.defaultFS","wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net") val fs=FileSystem.get(confh) //Copy Files from tmp to proc FileUtil.copy(fs,new Path("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/tmp/"+uniqueId+".csv"),fs,new Path("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/proc/"+uniqueId+".csv"),true,confh) FileUtil.copy(fs,new Path("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/tmp/"+uniqueId+".txt"),fs,new Path("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/proc/"+uniqueId+".txt"),true,confh) // Read data as a DataFrame var passengersData = spark.sqlContext.read.format("csv") .option("header", "true") .option("inferSchema", "true") .load("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/proc/" + uniqueId + ".csv") val targetColumn = spark.sparkContext.wholeTextFiles("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/proc/" + uniqueId + ".txt").take(1)(0)._2 //Convert Int and Long to Double to avoid Feature Builder exception with Integer / Long Types val toBechanged = passengersData.schema.fields.filter(x => x.dataType == IntegerType || x.dataType == LongType) toBechanged.foreach({ row => passengersData = passengersData.withColumn(row.name.concat("tmp"), passengersData.col(row.name).cast(DoubleType)) .drop(row.name) .withColumnRenamed(row.name.concat("tmp"), row.name) }) //Let's try to understand from the target variable which ML problem we want to solve val view = passengersData.createOrReplaceTempView("myview") val countTarget = spark.sql("SELECT COUNT(DISTINCT " + targetColumn + ") FROM myview").take(1)(0).get(0).toString().toInt val targetType = passengersData.schema.fields.filter(x => x.name == targetColumn).take(1)(0).dataType //Max Distinct Values for Binary Classification is 2 and for multi class is 30 val binaryL: Int = 2 val multiL: Int = 30 //If the target variable has 2 distinct values and it is numeric can be a binary classification if (countTarget == binaryL && targetType == DoubleType) { val (saleprice, features) = FeatureBuilder.fromDataFrame[RealNN](passengersData, response = targetColumn) val featureVector = features.toSeq.autoTransform() val checkedFeatures = saleprice.sanityCheck(featureVector, checkSample = 1.0, removeBadFeatures = true) val pred = BinaryClassificationModelSelector().setInput(saleprice, checkedFeatures).getOutput() val wf = new OpWorkflow() val model = wf.setInputDataset(passengersData).setResultFeatures(pred).train() val results = "Model summary:\n" + model.summaryPretty() model.save("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/models/" + uniqueId + "/binmodel") val dfWrite = spark.sparkContext.parallelize(Seq(results)) dfWrite.coalesce(1).saveAsTextFile("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/results/" + uniqueId + ".txt") } //If the target variable has more that 2 distinct values , less than 30 and it is string type can be a multi-classification else if (countTarget > binaryL && countTarget < multiL && targetType == StringType) { val (saleprice, features) = FeatureBuilder.fromDataFrame[Text](passengersData, response = targetColumn) val featureVector = features.toSeq.autoTransform() val pred = MultiClassificationModelSelector().setInput(saleprice.indexed(), featureVector).getOutput() val wf = new OpWorkflow() val model = wf.setInputDataset(passengersData).setResultFeatures(pred).train() val results = "Model summary:\n" + model.summaryPretty() model.save("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/models/" + uniqueId + "/multicmodel") val dfWrite = spark.sparkContext.parallelize(Seq(results)) dfWrite.coalesce(1).saveAsTextFile("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/results/" + uniqueId + ".txt") } // If it's not a classification then we can try a regression else { val (saleprice, features) = FeatureBuilder.fromDataFrame[RealNN](passengersData, response = targetColumn) val featureVector = features.toSeq.autoTransform() val checkedFeatures = saleprice.sanityCheck(featureVector, checkSample = 1.0, removeBadFeatures = true) val pred = RegressionModelSelector().setInput(saleprice, checkedFeatures).getOutput() val wf = new OpWorkflow() val model = wf.setInputDataset(passengersData).setResultFeatures(pred).train() val results = "Model summary:\n" + model.summaryPretty() model.save("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/models/" + uniqueId + "/regmodel") val dfWrite = spark.sparkContext.parallelize(Seq(results)) dfWrite.coalesce(1).saveAsTextFile("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/results/" + uniqueId + ".txt") } //if everything went smooth let's move files to the done folder FileUtil.copy(fs,new Path("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/proc/"+uniqueId+".csv"),fs,new Path("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/done/"+uniqueId+".csv"),true,confh) FileUtil.copy(fs,new Path("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/proc/"+uniqueId+".txt"),fs,new Path("wasbs://REPLACETHIS@REPLACETHIS.blob.core.windows.net/done/"+uniqueId+".txt"),true,confh) spark.close() } }
So essentially the code performs the following tasks:
- Receives the unique id that has been assigned for each automl request (this happens externally)
- Searches for the csv files containing data and metadata (target column) moving them to a process folder
- Looking at the data decides which ML workflow has to be executed
- Collects the results of the analysis (results and trained models) and the files moving them to their final folders.
Let me know your feedback !






















































