From db839003bbba8881de17e4b8b4a706cd2064b4eb Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Thu, 25 May 2017 15:51:29 -0700 Subject: [PATCH 01/12] Add BundleService.R and README.md --- utils/BundleService.R | 57 +++++++++++++++++++++++++++++++++++++++++++ utils/README.md | 17 +++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 utils/BundleService.R create mode 100644 utils/README.md diff --git a/utils/BundleService.R b/utils/BundleService.R new file mode 100644 index 0000000..d31c276 --- /dev/null +++ b/utils/BundleService.R @@ -0,0 +1,57 @@ +library(jsonlite) + +bundleService <- function(init, run, objects, inputs, outputs, folder) +{ + saveToFile <- function(name, obj) { + binFile <- file(paste(folder, '/', name, sep = ''), 'wb') + binObj <- serialize(obj, NULL) + writeBin(con = binFile, object = binObj) + close(binFile) + } + + saveToFile('init', init) + saveToFile('run', run) + + preloadedObjects <- list(unbox('init'), unbox('run')) + + mapply(function(value, name) { + assign(name,value) + saveToFile(name, value) + }, objects, names(objects)) + + for(objName in names(objects)) { + preloadedObjects[[length(preloadedObjects)+1]] <- unbox(objName) + } + + argumentList = '' + + for(arg in names(inputs)) { + if(argumentList != '') { + argumentList = paste(argumentList, ', ', sep = '') + } + + argumentList = paste(argumentList, arg, sep = '') + } + + convertToParameterDefinition <- function(parameters) { + result <- list() + + for(key in names(parameters)) { + result[[length(result)+1]] <- structure(list(name=unbox(key), type=unbox(parameters[[key]]))) + } + + result + } + + svcmetadata <- structure(list( + runtimeType = unbox("R"), + initCode = unbox("init()"), + code = unbox(paste("run(", argumentList, ")", sep = '')), + inputParameterDefinitions = convertToParameterDefinition(inputs), + outputParameterDefinitions = convertToParameterDefinition(outputs), + preloadedObjects = preloadedObjects + )) + + json <- toJSON(svcmetadata, pretty=TRUE) + write(json, paste(folder, '/service.json', sep = '')) +} \ No newline at end of file diff --git a/utils/README.md b/utils/README.md new file mode 100644 index 0000000..9f54f8c --- /dev/null +++ b/utils/README.md @@ -0,0 +1,17 @@ +# Operationalizing R Models in AzureML + +## Bundle + +init <- function() { + d <<- 3 +} + +add <- function(x, y) { + result <<- (x + y) * myModel + d +} + +bundleService(init, add, list(myModel = 2), inputs = list(x = "numeric", y = "numeric"), outputs = list(result = "numeric"), "/tmp") + +## Deploy + +az ml service create realtime -n myservice1 -r mrs -f service.json -d init -d run -d myModel \ No newline at end of file From cc5f3ec4bf7d18a7d6e885707b6bf3aaf121345e Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Thu, 25 May 2017 15:53:18 -0700 Subject: [PATCH 02/12] Fix markup --- utils/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utils/README.md b/utils/README.md index 9f54f8c..804c283 100644 --- a/utils/README.md +++ b/utils/README.md @@ -1,7 +1,8 @@ # Operationalizing R Models in AzureML -## Bundle +## Create Bundle +```R init <- function() { d <<- 3 } @@ -11,7 +12,10 @@ add <- function(x, y) { } bundleService(init, add, list(myModel = 2), inputs = list(x = "numeric", y = "numeric"), outputs = list(result = "numeric"), "/tmp") +``` ## Deploy -az ml service create realtime -n myservice1 -r mrs -f service.json -d init -d run -d myModel \ No newline at end of file +``` +az ml service create realtime -n myservice1 -r mrs -f service.json -d init -d run -d myModel +``` \ No newline at end of file From fb71d4db14440a6d9e3d66b08f5b0fc245642a58 Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Thu, 25 May 2017 15:55:15 -0700 Subject: [PATCH 03/12] Add source instruction --- utils/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/README.md b/utils/README.md index 804c283..a81a503 100644 --- a/utils/README.md +++ b/utils/README.md @@ -3,6 +3,8 @@ ## Create Bundle ```R +source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') + init <- function() { d <<- 3 } From af89366736d6c9ebb62cac90e53f73dd92ca8331 Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Thu, 25 May 2017 15:58:45 -0700 Subject: [PATCH 04/12] Update README.md --- utils/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utils/README.md b/utils/README.md index a81a503..844b64e 100644 --- a/utils/README.md +++ b/utils/README.md @@ -20,4 +20,10 @@ bundleService(init, add, list(myModel = 2), inputs = list(x = "numeric", y = "nu ``` az ml service create realtime -n myservice1 -r mrs -f service.json -d init -d run -d myModel +``` + +## Test + +``` +az ml service run realtime -n myservice1 -d '{"x" : 2, "y": 3} ``` \ No newline at end of file From 174f5e902d60db80ae15d51dc60bed96006f9a55 Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Thu, 25 May 2017 16:02:47 -0700 Subject: [PATCH 05/12] Update sample --- utils/BundleService.R | 4 ++-- utils/README.md | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/utils/BundleService.R b/utils/BundleService.R index d31c276..5caf379 100644 --- a/utils/BundleService.R +++ b/utils/BundleService.R @@ -1,9 +1,9 @@ library(jsonlite) -bundleService <- function(init, run, objects, inputs, outputs, folder) +bundleService <- function(init, run, objects, inputs, outputs, outputFolder) { saveToFile <- function(name, obj) { - binFile <- file(paste(folder, '/', name, sep = ''), 'wb') + binFile <- file(paste(outputFolder, '/', name, sep = ''), 'wb') binObj <- serialize(obj, NULL) writeBin(con = binFile, object = binObj) close(binFile) diff --git a/utils/README.md b/utils/README.md index 844b64e..6c1b632 100644 --- a/utils/README.md +++ b/utils/README.md @@ -1,8 +1,17 @@ # Operationalizing R Models in AzureML +## Setup + +Create AzureML cluster + +``` +az ml env setup -k +``` + ## Create Bundle ```R +# One time load function source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') init <- function() { @@ -13,7 +22,14 @@ add <- function(x, y) { result <<- (x + y) * myModel + d } -bundleService(init, add, list(myModel = 2), inputs = list(x = "numeric", y = "numeric"), outputs = list(result = "numeric"), "/tmp") +bundleService( + init, + add, + list(myModel = 2), + inputs = list(x = "numeric", y = "numeric"), + outputs = list(result = "numeric"), + outputFolder = "/tmp") + ``` ## Deploy From 0c36fd6d38322e596ad013d90775b61ed26f0786 Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Thu, 25 May 2017 16:03:56 -0700 Subject: [PATCH 06/12] Fix bug --- utils/BundleService.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/BundleService.R b/utils/BundleService.R index 5caf379..d2c0357 100644 --- a/utils/BundleService.R +++ b/utils/BundleService.R @@ -53,5 +53,5 @@ bundleService <- function(init, run, objects, inputs, outputs, outputFolder) )) json <- toJSON(svcmetadata, pretty=TRUE) - write(json, paste(folder, '/service.json', sep = '')) + write(json, paste(outputFolder, '/service.json', sep = '')) } \ No newline at end of file From 93bee5db2694db5a275418453a54554e06ac5da5 Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Fri, 16 Jun 2017 08:50:05 -0700 Subject: [PATCH 07/12] Add R sample --- samples/R/iris-caret/SampleRequest.txt | 1 + samples/R/iris-caret/sample.R | 30 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 samples/R/iris-caret/SampleRequest.txt create mode 100644 samples/R/iris-caret/sample.R diff --git a/samples/R/iris-caret/SampleRequest.txt b/samples/R/iris-caret/SampleRequest.txt new file mode 100644 index 0000000..ddb7d05 --- /dev/null +++ b/samples/R/iris-caret/SampleRequest.txt @@ -0,0 +1 @@ +{ "SepalLength": 1, "SepalWidth": 2, "PetalLength": 3, "PetalWidth": 4 } \ No newline at end of file diff --git a/samples/R/iris-caret/sample.R b/samples/R/iris-caret/sample.R new file mode 100644 index 0000000..7718813 --- /dev/null +++ b/samples/R/iris-caret/sample.R @@ -0,0 +1,30 @@ +# import bundleService +source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') + + + +library(caret) +data(iris) +set.seed(12345) +inTrain<-createDataPartition(iris$Species,p=0.7,list=FALSE) +training<-iris[inTrain,] +testing<-iris[-inTrain,] + +irisModel<-train(Species~.,method="rpart",data=iris) + +init <- function() { + library(caret) +} + +predictIris <- function(SepalLength, SepalWidth, PetalLength, PetalWidth) { + input <- data.frame(Sepal.Length = c(SepalLength), Sepal.Width = c(SepalWidth), Petal.Length = c(PetalLength), Petal.Width = c(PetalWidth)) + result <<- as.character(predict(model, input)) +} + +bundleService( + init, + predictIris, + list(model = irisModel), + inputs = list(SepalLength = "numeric", SepalWidth = "numeric", PetalLength = "numeric", PetalWidth = "numeric"), + outputs = list(result = "character"), + outputFolder = "d:\\temp\\service3") From 395405a751b2bca127b802fd03b98308df192844 Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Fri, 16 Jun 2017 13:34:00 -0700 Subject: [PATCH 08/12] Incorporate files in README.md --- samples/R/iris-caret/{sample.R => README.md} | 35 ++++++++++++++++++-- samples/R/iris-caret/SampleRequest.txt | 1 - 2 files changed, 32 insertions(+), 4 deletions(-) rename samples/R/iris-caret/{sample.R => README.md} (65%) delete mode 100644 samples/R/iris-caret/SampleRequest.txt diff --git a/samples/R/iris-caret/sample.R b/samples/R/iris-caret/README.md similarity index 65% rename from samples/R/iris-caret/sample.R rename to samples/R/iris-caret/README.md index 7718813..938077b 100644 --- a/samples/R/iris-caret/sample.R +++ b/samples/R/iris-caret/README.md @@ -1,7 +1,18 @@ -# import bundleService -source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') +# Operationalizing R Models in AzureML + +## Setup + +Create AzureML cluster +``` +az ml env setup -k +``` +## Create Bundle + +```R +# import bundleService +source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') library(caret) data(iris) @@ -10,8 +21,12 @@ inTrain<-createDataPartition(iris$Species,p=0.7,list=FALSE) training<-iris[inTrain,] testing<-iris[-inTrain,] +# train model + irisModel<-train(Species~.,method="rpart",data=iris) +# define operationalization functions + init <- function() { library(caret) } @@ -27,4 +42,18 @@ bundleService( list(model = irisModel), inputs = list(SepalLength = "numeric", SepalWidth = "numeric", PetalLength = "numeric", PetalWidth = "numeric"), outputs = list(result = "character"), - outputFolder = "d:\\temp\\service3") + outputFolder = "/tmp") + +``` + +## Deploy + +``` +az ml service create realtime -n myservice1 -r mrs -f service.json -d init -d run -d model +``` + +## Test + +``` +az ml service run realtime -n myservice1 -d '{ "SepalLength": 1.1, "SepalWidth": 2.2, "PetalLength": 3.3, "PetalWidth": 4.4 }' +``` \ No newline at end of file diff --git a/samples/R/iris-caret/SampleRequest.txt b/samples/R/iris-caret/SampleRequest.txt deleted file mode 100644 index ddb7d05..0000000 --- a/samples/R/iris-caret/SampleRequest.txt +++ /dev/null @@ -1 +0,0 @@ -{ "SepalLength": 1, "SepalWidth": 2, "PetalLength": 3, "PetalWidth": 4 } \ No newline at end of file From c4c9c5bf481a8be3f295cdba3544c47cb8854c39 Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Fri, 16 Jun 2017 14:08:42 -0700 Subject: [PATCH 09/12] Update swagger section --- samples/R/iris-caret/README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/samples/R/iris-caret/README.md b/samples/R/iris-caret/README.md index 938077b..bb174a0 100644 --- a/samples/R/iris-caret/README.md +++ b/samples/R/iris-caret/README.md @@ -55,5 +55,30 @@ az ml service create realtime -n myservice1 -r mrs -f service.json -d init -d ru ## Test ``` -az ml service run realtime -n myservice1 -d '{ "SepalLength": 1.1, "SepalWidth": 2.2, "PetalLength": 3.3, "PetalWidth": 4.4 }' +az ml service run realtime -n myservice1 -d '{ "SepalLength": 4.7, "SepalWidth": 3.2, "PetalLength": 1.3, "PetalWidth": 0.2 }' +``` + +## Generate client code + +You can download the swagger.json metadata from /swagger.json + +Store it in a file and you can use [autorest](https://www.nuget.org/packages/AutoRest) to generate the client code: + +``` +.\AutoRest.exe -input 'swagger.json' -ClientName Service -CodeGenerator CSharp -Namespace 'AzureML' -OutputDirectory '/tmp' +``` + +With this you can create a sample C# application + +``` +internal class Program +{ + private static void Main(string[] args) + { + var service = new Service(new Uri("")); + + var webServiceResult = service.RunMLService(new InputParameters(4.7, 3.2, 1.3, 0.2)); + Console.WriteLine(webServiceResult.OutputParameters.Result); + } +} ``` \ No newline at end of file From bef3909e5ea295f026fe9cc2fa7a4ba6532449ac Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Fri, 16 Jun 2017 14:09:42 -0700 Subject: [PATCH 10/12] Update code highlighting --- samples/R/iris-caret/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/R/iris-caret/README.md b/samples/R/iris-caret/README.md index bb174a0..ba8c20c 100644 --- a/samples/R/iris-caret/README.md +++ b/samples/R/iris-caret/README.md @@ -70,7 +70,7 @@ Store it in a file and you can use [autorest](https://www.nuget.org/packages/Aut With this you can create a sample C# application -``` +```csharp internal class Program { private static void Main(string[] args) From d330e607758f5b8033e0cd5a86fcc6887dd3b113 Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Thu, 22 Jun 2017 08:55:24 -0700 Subject: [PATCH 11/12] Add microsoft-r/README.md --- .../R/{iris-caret => iris/caret}/README.md | 0 samples/R/iris/microsoft-r/README.md | 85 +++++++++++++++++++ utils/README.md | 45 ---------- 3 files changed, 85 insertions(+), 45 deletions(-) rename samples/R/{iris-caret => iris/caret}/README.md (100%) create mode 100644 samples/R/iris/microsoft-r/README.md delete mode 100644 utils/README.md diff --git a/samples/R/iris-caret/README.md b/samples/R/iris/caret/README.md similarity index 100% rename from samples/R/iris-caret/README.md rename to samples/R/iris/caret/README.md diff --git a/samples/R/iris/microsoft-r/README.md b/samples/R/iris/microsoft-r/README.md new file mode 100644 index 0000000..30ee67e --- /dev/null +++ b/samples/R/iris/microsoft-r/README.md @@ -0,0 +1,85 @@ +# Operationalizing R Models in AzureML + +## Setup + +Create AzureML cluster + +``` +az ml env setup -k +``` + +## Create Bundle + +```R +# import bundleService +source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') + +# import bundleService +source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') + +library(RevoScaleR); + +# train model + +trainData <- iris; formula <- Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width; +irisModel <- rxBTrees(formula, data = trainData, lossFunction = 'multinomial', nTree = 3,learningRate = 0.1, sampRate = 0.5, maxdepth = 1, minBucket = 1,seed = 1234, replace = FALSE, mTry = 0, maxNumBins = 200); + +# define operationalization functions + +init <- function() { + library(RevoScaleR) +} + +predictIris <- function(SepalLength, SepalWidth, PetalLength, PetalWidth) { + input <- data.frame(Sepal.Length = c(SepalLength), Sepal.Width = c(SepalWidth), Petal.Length = c(PetalLength), Petal.Width = c(PetalWidth)) + + prediction <- rxPredict(model, data = input) + result <<- as.character(prediction$Species_Pred) +} + +bundleService( + init, + predictIris, + list(model = irisModel), + inputs = list(SepalLength = "numeric", SepalWidth = "numeric", PetalLength = "numeric", PetalWidth = "numeric"), + outputs = list(result = "character"), + outputFolder = "/tmp") + +``` + +## Deploy + +``` +az ml service create realtime -n myservice1 -r mrs -f service.json -d init -d run -d model +``` + +## Test + +``` +az ml service run realtime -n myservice1 -d '{ "SepalLength": 4.7, "SepalWidth": 3.2, "PetalLength": 1.3, "PetalWidth": 0.2 }' +``` + +## Generate client code + +You can download the swagger.json metadata from /swagger.json + +Store it in a file and you can use [autorest](https://www.nuget.org/packages/AutoRest) to generate the client code: + +``` +.\AutoRest.exe -input 'swagger.json' -ClientName Service -CodeGenerator CSharp -Namespace 'AzureML' -OutputDirectory '/tmp' +``` + +With this you can create a sample C# application + +```csharp +internal class Program +{ + private static void Main(string[] args) + { + var service = new Service(new Uri("")); + + var webServiceResult = service.RunMLService(new InputParameters(4.7, 3.2, 1.3, 0.2)); + Console.WriteLine(webServiceResult.OutputParameters.Result); + } +} +``` \ No newline at end of file diff --git a/utils/README.md b/utils/README.md deleted file mode 100644 index 6c1b632..0000000 --- a/utils/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Operationalizing R Models in AzureML - -## Setup - -Create AzureML cluster - -``` -az ml env setup -k -``` - -## Create Bundle - -```R -# One time load function -source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') - -init <- function() { - d <<- 3 -} - -add <- function(x, y) { - result <<- (x + y) * myModel + d -} - -bundleService( - init, - add, - list(myModel = 2), - inputs = list(x = "numeric", y = "numeric"), - outputs = list(result = "numeric"), - outputFolder = "/tmp") - -``` - -## Deploy - -``` -az ml service create realtime -n myservice1 -r mrs -f service.json -d init -d run -d myModel -``` - -## Test - -``` -az ml service run realtime -n myservice1 -d '{"x" : 2, "y": 3} -``` \ No newline at end of file From 3ad4ca393b546109776b5bd3430cc0d5d9b28ba9 Mon Sep 17 00:00:00 2001 From: Daniel Hartl Date: Thu, 22 Jun 2017 09:00:31 -0700 Subject: [PATCH 12/12] Remove double used file --- samples/R/iris/microsoft-r/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/samples/R/iris/microsoft-r/README.md b/samples/R/iris/microsoft-r/README.md index 30ee67e..370320b 100644 --- a/samples/R/iris/microsoft-r/README.md +++ b/samples/R/iris/microsoft-r/README.md @@ -14,9 +14,6 @@ az ml env setup -k # import bundleService source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') -# import bundleService -source('https://raw.githubusercontent.com/danhartl/Machine-Learning-Operationalization/master/utils/BundleService.R') - library(RevoScaleR); # train model