One of the most challenging parts while building Data Science projects is how to ship into production your freshly developed Machine Learning model and keep track of it and ensure a full control of the model life cycle of the model.
Productionizing Machine Learning models and turn it into a real product requires mastering an expertise other than AI, ML & mathematics.
Now we have to deal with IT, infrastructure, security & monitoring.
Build a Machine Learning model
Before starting developing your Machine Learning models, make sure to use end-to-end frameworks rather than a standalone package.
Because this prevents your build spaghetti code to perform testing, validation & others operations.
We inspire from the example given by tidymodels authors by using hotel booking data, in order to build a a binary classification machine learning model that predicts if the customers will have children with them or not.
library(dplyr) # used for data manipulationlibrary(tidymodels) # end to end machine learning development# import data using readr package hotels <- readr::read_csv('https://tidymodels.org/start/case-study/hotels.csv') %>% dplyr::mutate(dplyr::across(dplyr::where(is.character), as.factor))# visualize the first rows of hotel datahotels%>%head(20)%>% knitr::kable()
hotel
lead_time
stays_in_weekend_nights
stays_in_week_nights
adults
children
meal
country
market_segment
distribution_channel
is_repeated_guest
previous_cancellations
previous_bookings_not_canceled
reserved_room_type
assigned_room_type
booking_changes
deposit_type
days_in_waiting_list
customer_type
average_daily_rate
required_car_parking_spaces
total_of_special_requests
arrival_date
City_Hotel
217
1
3
2
none
BB
DEU
Offline_TA/TO
TA/TO
0
0
0
A
A
0
No_Deposit
0
Transient-Party
80.75
none
1
2016-09-01
City_Hotel
2
0
1
2
none
BB
PRT
Direct
Direct
0
0
0
D
K
0
No_Deposit
0
Transient
170.00
none
3
2017-08-25
Resort_Hotel
95
2
5
2
none
BB
GBR
Online_TA
TA/TO
0
0
0
A
A
2
No_Deposit
0
Transient
8.00
none
2
2016-11-19
Resort_Hotel
143
2
6
2
none
HB
ROU
Online_TA
TA/TO
0
0
0
A
A
0
No_Deposit
0
Transient
81.00
none
1
2016-04-26
Resort_Hotel
136
1
4
2
none
HB
PRT
Direct
Direct
0
0
0
F
F
0
No_Deposit
0
Transient
157.60
none
4
2016-12-28
City_Hotel
67
2
2
2
none
SC
GBR
Online_TA
TA/TO
0
0
0
A
A
0
No_Deposit
0
Transient
49.09
none
1
2016-03-13
Resort_Hotel
47
0
2
2
children
BB
ESP
Direct
Direct
0
0
0
C
C
0
No_Deposit
0
Transient
289.00
none
1
2017-08-23
City_Hotel
56
0
3
0
children
BB
ESP
Online_TA
TA/TO
0
0
0
B
A
0
No_Deposit
0
Transient
82.44
none
1
2016-12-08
City_Hotel
80
0
4
2
none
BB
FRA
Online_TA
TA/TO
0
0
0
D
D
0
No_Deposit
0
Transient
135.00
none
1
2017-05-02
City_Hotel
6
2
2
2
children
BB
FRA
Online_TA
TA/TO
0
0
0
A
A
0
No_Deposit
0
Transient
180.00
none
1
2016-08-07
City_Hotel
130
1
2
2
none
BB
FRA
Offline_TA/TO
TA/TO
0
0
0
A
D
0
No_Deposit
0
Transient
71.00
none
0
2016-04-15
City_Hotel
27
0
1
1
none
BB
NLD
Online_TA
TA/TO
0
0
0
D
D
0
No_Deposit
0
Transient
120.12
none
1
2016-05-18
Resort_Hotel
16
1
2
2
none
BB
GBR
Corporate
Corporate
0
0
0
A
A
0
No_Deposit
0
Transient-Party
40.00
none
0
2017-02-17
Resort_Hotel
46
0
2
2
none
BB
PRT
Offline_TA/TO
TA/TO
0
0
0
D
D
0
No_Deposit
0
Transient
162.00
none
0
2016-12-30
City_Hotel
297
1
1
2
none
BB
FRA
Groups
TA/TO
0
0
0
A
A
0
No_Deposit
236
Transient-Party
65.00
none
0
2016-05-14
City_Hotel
423
1
1
2
none
HB
DEU
Offline_TA/TO
TA/TO
0
0
0
A
A
0
No_Deposit
0
Transient-Party
122.40
none
1
2017-07-22
City_Hotel
22
1
2
2
none
BB
FRA
Online_TA
TA/TO
0
0
0
D
D
0
No_Deposit
0
Transient
121.33
none
0
2017-03-13
Resort_Hotel
96
4
7
2
none
HB
GBR
Groups
TA/TO
0
0
0
A
A
4
No_Deposit
0
Transient-Party
74.18
none
0
2017-03-12
City_Hotel
0
1
0
1
none
BB
PRT
Corporate
Corporate
0
0
0
E
E
0
No_Deposit
0
Transient
139.00
parking
0
2016-07-18
Resort_Hotel
7
1
2
2
none
HB
NULL
Online_TA
TA/TO
0
0
1
E
I
1
No_Deposit
0
Transient
78.42
parking
1
2016-10-31
As a part of ML model developement, we split the intial data into 3 differents distincts subsets :
Training: used to train the model, allowing it to learn patterns and relationships in the data
Validation: helps in making decisions such as choosing the best model architecture or selecting regularization parameters
Testing: provides an unbiased evaluation of the model’s final performance to ensure generalizability to unseen data
set.seed(123)hotel_split <- rsample::initial_validation_split(hotels, strata = children)hotel_train <- rsample::training(hotel_split)hotel_test <- rsample::testing(hotel_split)## to use for monitoring example:hotel_validation <- rsample::validation(hotel_split)# build ml workflow using tidymodels componentsset.seed(234) # to make sure that generated random numbers are similar hotels_ml_wf <-workflow( children ~ average_daily_rate + reserved_room_type + lead_time + country + adults,boost_tree(mode ="classification", trees =10)%>%set_engine("xgboost", eval_metric ="auc") # use xgboost with Area Under the Curve as a evaluation metric )# fit the model hotels_ml <- hotels_ml_wf %>%fit(data = hotel_train)
Prepare for deployment: ML inference
One of the common ways of serving your ML model, is ML inference by exposing the prediction module as a RESTful API.
By doing so, end users will be able to perform predictions using third party applications or via different scripts/programming language.
Make your model available
Before serving the model as an API, first we need to make sure that our model, can be accessed by the server. For that, a complementary package called pins is available to store the ML object in one of the following storage systems:
To make sure that all works fine, we create a local board, and later we’ll use another storage system for final deployent:
# create a board based on a folder ml_board <- pins::board_folder(path ="./ml_models",versioned =TRUE)
Now that we have our board ready, next steps is to use another package called vetiver that enables a fluid tool that guarantees a standardized ML model deployment, versioning and monitoring framework.
Below is an example how we create a vetiverized ;) ML object and how to save into our previously created board.
ml_model_name <-"hotels_ml"# create vetiver ML modelml_model_v <- vetiver::vetiver_model(model = hotels_ml,model_name = ml_model_name,description ="ML model for predicting whther a customer will bring children with him or not") # save it into pin boardml_board%>% vetiver::vetiver_pin_write(board = .,vetiver_model = ml_model_v)
turn your ML model into an API
The next steps is to prepare the API server that connects to the ml object stored in the board and expose it as a POST request.
For R users, plumber package is the one to go with.
On other side (python), fastApi is the well know framework for building RESTFul APIs
Vetiver offers a complementary function that does this for your, what you is to provide both board & the model name.
vetiver::vetiver_write_plumber(board = ml_board, name = ml_model_name)
A new file (plumber.R) will be generated, ready to serve your model prediction inference as an API, below is the script contained in the file.
# Generated by the vetiver package; edit with carelibrary(pins)library(plumber)library(rapidoc)library(vetiver)b <-board_folder(path ="ml_models")v <-vetiver_pin_read(b, "hotels_ml", version ="20241001T113033Z-4a8d0")#* @plumberfunction(pr) { pr %>%vetiver_api(v)}
By serving the API via plumber.R file (run API), a swagger UI will be displayed in your browser as illustrated int the image below:
As a best practice step, it is required to set a static the port & the host where to serve you API.
We add a new line at the beginning of the plumber.R file:
Now we have set them, serve the API in the active session and open a new session R or python (or any other language)), and invoke the ML API locally in order to generate predictions.
Request using R
Use httr2 package to send API requests, as illustrated the script below:
# load librarylibrary(httr2)# define the body that contains input values to be used for predictioninput_data <-data.frame(average_daily_rate =180, reserved_room_type ="",lead_time =45,country ="DE" ,adults =2)req_body <-list(input_data = input_data)# specify target end point for predictionmain_url <-"http://127.0.0.1:8080/"target_endpoint <-"predict"# initialize the requestreq_url <- httr2::request(main_url)# add request specificationsml_api_req <- req_url %>%# initialize requestreq_url_path_append(target_endpoint) %>%# add endpoint# req_headers(token = token,user = user_mail) %>% # add headerreq_method(method ="POST")%>%# add request methodreq_body_json(data = input_data)%>%# add body contentreq_error(is_error =function(res) FALSE) # perform an API request and get the resultml_api_resp <- ml_api_req%>%# whether to handle errorsreq_perform() %>%# send a requestresp_body_json()%>%# convert json response object print() # print response result
Request using python
We use the both requests & json for requesting and preparing the reponse:
# import libariesimport requests import jsonimport pandas as pdimport numpy as np# prepare input data Columns = ['average_daily_rate', 'reserved_room_type', 'lead_time', 'country', 'adults']values = [[180, 'A', 45 , 'DE', 2]]df = pd.DataFrame( data = values , columns = Columns ) df = df.to_dict('records')# add input data for which we want to get predicitonbody = {'input_data': df}# df# specify target end point for predictiontarget_endpoint ="MAIN_URL"#"thaink2_sales_pred"main_url <-"http://127.0.0.1:8080/"+ target_endpoint# send requestresponse = requests.post(main_url, data = json.dumps(body), headers = headers)# printing request contentprint(response.content)
Summary
What we have described the sections above, is a part of a full process to deploy end-to-end machine learning/deep learning models on a large scale.
In the upcoming sessions we’ll tackle complementary components such as docker, CI/CD & kubernetes and more additional tools and best practices to build a successful complete project.