The code that accompanies this article can be downloaded here.


In the previous articles, we explored how we can use Microsoft’s new framework for machine learning – ML.NET. We used different datasets for different purposes and explored how to solve real-world problems. First, we used the Iris dataset to explore machine learning concepts and get up to speed with this field in general. This dataset is sort of Hello World example, but we wanted to learn how to deal with more complex datasets too. Because of that, we used the Bike Sharing Demand dataset to break down one real-world regression problem.

Finally, in the previous article, we used the Wine Quality dataset for solving real-world classification problem. We didn’t run through specific algorithms, but we have made certain mechanisms that helped us find the best algorithm very quickly. However, we didn’t really explore how to utilize this model that we created. We just created it and evaluated it. Now, let’s see how we can save the model, and then use it in a standard web application.

It is not an unusual process to create and train machine learning model in one application, export it an use it another application. Training and evaluation of this model can be time-consuming and requires a lot of resources. That is what we are going to do here. Since we had pretty cool results with Bike Sharing Demand regression solution, we will make an ASP.NET application that will use this model. So, let’s start with exporting the model.

Exporting the Model

As you can remember we used different algorithms to solve the regression problem and come to the conclusion that the best results are achieved with the FastTreeTweedieRegressor model. So, now we are going to extend the Main method in that example with the additional call. Essentially, we just want to store that model somewhere and use it in another application that we are going to develop with ASP.NET. Here is the new implementation of the Main method:


static void Main(string[] args)
{
var trainingDataLocation = @"Data/hour_train.csv";
var testDataLocation = @"Data/hour_test.csv";
var modelEvaluator = new ModelEvaluator();
var fastTreeModel = new ModelBuilder(trainingDataLocation, new FastTreeRegressor()).BuildAndTrain();
var fastTreeMetrics = modelEvaluator.Evaluate(fastTreeModel, testDataLocation);
PrintMetrics("Fast Tree", fastTreeMetrics);
var fastForestModel = new ModelBuilder(trainingDataLocation, new FastForestRegressor()).BuildAndTrain();
var fastForestMetrics = modelEvaluator.Evaluate(fastForestModel, testDataLocation);
PrintMetrics("Fast Forest", fastForestMetrics);
var poissonModel = new ModelBuilder(trainingDataLocation, new PoissonRegressor()).BuildAndTrain();
var poissonMetrics = modelEvaluator.Evaluate(poissonModel, testDataLocation);
PrintMetrics("Poisson", poissonMetrics);
var gradientDescentModel = new ModelBuilder(trainingDataLocation, new OnlineGradientDescentRegressor()).BuildAndTrain();
var gradientDescentMetrics = modelEvaluator.Evaluate(gradientDescentModel, testDataLocation);
PrintMetrics("Online Gradient Descent", gradientDescentMetrics);
var fastTreeTweedieModel = new ModelBuilder(trainingDataLocation, new FastTreeTweedieRegressor()).BuildAndTrain();
var fastTreeTweedieMetrics = modelEvaluator.Evaluate(fastTreeTweedieModel, testDataLocation);
PrintMetrics("Fast Tree Tweedie", fastTreeTweedieMetrics);
var additiveModel = new ModelBuilder(trainingDataLocation, new GeneralizedAdditiveModelRegressor()).BuildAndTrain();
var additiveMetrics = modelEvaluator.Evaluate(additiveModel, testDataLocation);
PrintMetrics("Generalized Additive Model", additiveMetrics);
var stohasticDualCorordinateAscentModel = new ModelBuilder(trainingDataLocation, new StochasticDualCoordinateAscentRegressor()).BuildAndTrain();
var stohasticDualCorordinateAscentMetrics = modelEvaluator.Evaluate(stohasticDualCorordinateAscentModel, testDataLocation);
PrintMetrics("Stochastic Dual Coordinate Ascent", stohasticDualCorordinateAscentMetrics);
VisualizeTenPredictionsForTheModel(fastTreeTweedieModel, testDataLocation);
fastTreeTweedieModel.WriteAsync(@".\Model.zip");
Console.ReadLine();
}

The only difference is that at the end of the method, where we called WriteAsync method on FastTreeTweedieRegressor model. Using this method on any PredictionModel object you can save the model into either Stream or into the file. In this example, we are saving the machine learning model into the Model.zip file. This way we can copy this file over into our new web application, or to any other application in a nutshell, and then use it from there.

Application Overview

Now, we are not making some sort of sophisticated web application here. Basically, what we want to achieve is to give a user options to enter the values for the features and then feed this data to the machine learning model. After that, we want to present this prediction to the user. So, nothing too complex, the emphasis is on properly importing the model and using it out of the box. For this purpose, we created two views. Here is the first one which is used to gather information from the user:

And here is the second view that is used to display prediction results:

To sum it up, nothing complicated: getting information from the user, using machine learning model to get the prediction and displaying those predictions back to the user. But, let’s start at the beginning. During the creation the new project we used the .NET Core option in the left pane of the window and then used the ASP.NET Core Web Application. After filling the name and the location information about our app, we pressed the Next button.

In the next creation window, we used Model-Controler-View (MVC) option, because we want to create this kind of ASP.NET application.

As you probably know, this creates default views and controllers. So, in order to achieve the examples from above, we modified _Layout to remove unnecessary links from the header. Also, we rewrote the Index view from the Home folder completely. Here is what we added there:


@{
ViewData["Title"] = "Bike Sharing Demands";
}
<div class="row">
<div class="col-md-12">
<h3>Enter values: </h3>
<form method="post" action="Home/Predict">
<fieldset>
<div class="row">
<label class="col-md-2" for="Season">Season:</label>
<select class="col-md-4" name="season">
<option value="1">Spring</option>
<option value="2">Summer</option>
<option value="3">Autmn</option>
<option value="4">Winter</option>
</select>
</div>
<div class=" row">
<label class="col-md-2" for="Year">Year:</label>
<select class="col-md-4" name="year">
<option value="0">2011</option>
<option value="1">2012</option>
</select>
</div>
<div class=" row">
<label class="col-md-2" for="Month">Month:</label>
<select class="col-md-4" name="month">
<option value="1">Jan</option>
<option value="2">Feb</option>
<option value="3">Mar</option>
<option value="4">Apr</option>
<option value="5">May</option>
<option value="6">June</option>
<option value="7">July</option>
<option value="8">Aug</option>
<option value="9">Sept</option>
<option value="10">Oct</option>
<option value="11">Nov</option>
<option value="12">Dec</option>
</select>
</div>
<div class=" row">
<label class="col-md-2" for="Hour">Hour:</label>
<input class="col-md-4" type="time" name="hour" value="" />
</div>
<div class=" row">
<label class="col-md-2" for="Holiday">Holiday:</label>
<input class="col-md-4" type="checkbox" name="holiday" value="" />
</div>
<div class=" row">
<label class="col-md-2" for="Weekday">Weekday:</label>
<select class="col-md-4" name="weekday">
<option value="1">Monday</option>
<option value="2">Tuesday</option>
<option value="3">Wendesday</option>
<option value="4">Thursday</option>
<option value="5">Friday</option>
<option value="6">Saturday</option>
<option value="7">Sunday</option>
</select>
</div>
<div class=" row">
<label class="col-md-2" for="Weather">Weather:</label>
<select class="col-md-4" name="weather">
<option value="1">Clear, Few clouds, Partly cloudy, Partly cloudy</option>
<option value="2">Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist</option>
<option value="3">Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds</option>
<option value="4">Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog</option>
</select>
</div>
<div class=" row">
<label class="col-md-2" for="Temperature">Temperature:</label>
<input class="col-md-4" type="text" name="temperature" value="" />
</div>
<div class=" row">
<label class="col-md-2" for="NormalizedTemperature">NormalizedTemperature:</label>
<input class="col-md-4" type="text" name="normalizedTemperature" value="" />
</div>
<div class=" row">
<label class="col-md-2" for="Humidity">Humidity:</label>
<input class="col-md-4" type="text" name="humidity" value="" />
</div>
<div class=" row">
<label class="col-md-2" for="Windspeed">Windspeed:</label>
<input class="col-md-4" type="text" name="windspeed" value="" />
</div>
<p>
<input type="submit" value="Predict" class="submit" />
</p>
</fieldset>
</form>
</div>
</div>

view raw

Index.cshtml

hosted with ❤ by GitHub

Nothing too fancy, just a bunch of input fields. We expect these to be filled with by the user and passed to the controller. Apart from that, we implemented the second, very simple vier – Predict view:


<h2>Prediction</h2>
<p>Predicted value: @ViewData["Prediction"]</p>

view raw

Predict.cshtml

hosted with ❤ by GitHub

As you can see, we will expect from our controller to fill the ViewData with the Prediction property when this view is returned. Of course for generating this value we will have to use the machine learning model. All of this is handled in the controller, so let’s examine its implementation.

Importing the Model into Controller

You remember how we saved the machine learning model from the previous application into Model.zip file? We have to include that file in our web application. That is why we created new folder MachineLeartningModel and copied over that file there:

Don’t forget to set configure this file in the way that it is always copied over to the bin output folder. Now, what we want to do is import this model into our controller and use it on the input data provided by a user. We can achieve that by using the ReadAsync function of the PredictionModel class. This is done in the constructor of the controller like this:


public PredictionModel<BikeSharingDemandSample, BikeSharingDemandPrediction> _machineLearningModel;
public HomeController()
{
_machineLearningModel = PredictionModel.ReadAsync<BikeSharingDemandSample, BikeSharingDemandPrediction>(@"./MachineLearningModel/Model.zip").Result;
}

From this moment on, we can use _machineLearningModel as we have used it in previous applications. HomeController has yet two methods implemented: Index and Predict. The first one is used on application start to display the Index view and to initiate gathering of the information from the user.


public IActionResult Index()
{
return View();
}

Again, nothing too fancy, we are just returning the view in this method. However, once the Submit button from the form on the Index view has been clicked, the HTTP POST request will be issued. That request is processed inside of Predict method on HomeController. Here is how it is implemented:


[HttpPost]
public IActionResult Predict(
float season,
float year,
float month,
DateTime hour,
bool holiday,
float weekday,
float weather,
float temperature,
float normalizedTemperature,
float humidity,
float windspeed)
{
var justHour = hour.Hour;
var input = new BikeSharingDemandSample()
{
Season = season,
Year = year,
Month = month,
Hour = justHour,
Holiday = holiday,
Weekday = weekday,
Weather = weather,
Temperature = temperature,
NormalizedTemperature = normalizedTemperature,
Humidity = humidity,
Windspeed = windspeed,
Count = 0
};
var prediction = _machineLearningModel.Predict(input);
ViewData.Add("prediction", prediction.PredictedCount);
return View();
}

Input data is gathered and it is used to create a new object of BikeSharingDemandSample class. This class is the same as in the previous application, just like the BikeSharingDemandPrediction class. We had to move these classes over from the machine learning model training application as well. Just as a reminder, here is their implementation:


public class BikeSharingDemandSample
{
[Column("2")] public float Season;
[Column("3")] public float Year;
[Column("4")] public float Month;
[Column("5")] public float Hour;
[Column("6")] public bool Holiday;
[Column("7")] public float Weekday;
[Column("8")] public float Weather;
[Column("9")] public float Temperature;
[Column("10")] public float NormalizedTemperature;
[Column("11")] public float Humidity;
[Column("12")] public float Windspeed;
[Column("16")] public float Count;
}
public class BikeSharingDemandPrediction
{
[ColumnName("Score")]
public float PredictedCount;
}

It is crucial to install the Microsoft.ML NuGet package in this web application as well, so don’t forget on that step when you are building your own app. We already mentioned that we can use the object of the PredictionModel class (_machineLearningModel) just like in the machine learning model training application. That is why we call the Predict method that returns us an object of the BikeSharingDemandPrediction class and we are using this information to fill in the ViewData and return the view. This way we used the model and gave back the information that the user required.

Conclusion

In this post, we examined how to export machine learning model that we created and use it in another application. Of course, for this, we used Microsoft technologies ML.NET and ASP.NET. Training and evaluation of the model can take a lot of time and resources, and that is why these processes are actually separated from the moment that the model is used. In this scenario, we used it in another web ASP.NET application.

However, we could have used it anywhere else not just in simple web applications. Using the same principles of storing and loading the machine learning model form the file we are able to incorporate it into any other workflow we want to. This gives us enormous possibilities of using the machine learning, from big enterprise systems to simpler web apps.

Thank you for reading!


Read more posts from the author at Rubik’s Code.


 

Discover more from Rubix Code

Subscribe now to keep reading and get access to the full archive.

Continue reading