Logo Idiwork

Experiment #102 How to construct and train a Deep Neural Network using Keras and deploy the model as an Azure Web Service 🧠☁️

1.     Install Libraries and Import Files

Keras is a Python library that allows us to construct Deep Learning models. First, we must import all needed modules and download the text analytics files from our GitHub repository. The cells of the “.ipynb” script look like this:

 

import re
import nltk
import uuid
import os
import numpy as np
import pandas as pd
import tensorflow as tf
import keras
from keras import models, layers, optimizers, regularizers
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.utils import to_categorical

import urllib.request
data_location = './data'
base_data_url = 'https://raw.githubusercontent.com/idiWork/Experiment_102/master/resources/'
filesToDownload = ['reviews_labels.txt', 'reviews_texts.txt', 'contractions.py', 'textanalytics.py']

os.makedirs(data_location, exist_ok=True)

for file in filesToDownload:
    data_url = os.path.join(base_data_url, file)
    local_file_path = os.path.join(data_location, file)
    urllib.request.urlretrieve(data_url, local_file_path)

nltk.download('stopwords') 
nltk.download('punkt')

import sys
sys.path.append(data_location)
import textanalytics as ta

 

2.     Prepare and Normalize the Training Data

We have prepared a list of sentences to train the reviews classification model. Each phrase corresponds to one of three different locations of a hotel: room (labeled with number 0), diner (labeled with number 1) or pool (labeled with number 2). At this step the script prepares and normalizes all the sentences and converts them to valid training data.

 

reviews_corpus = [review for review in open(os.path.join(data_location, 'reviews_texts.txt'))]
reviews_corpus

labels = [int(re.sub("\n", "", label)) for label in open(os.path.join(data_location, 'reviews_labels.txt'))]

labels = to_categorical(labels, 3)

norm_corpus = ta.normalize_corpus(reviews_corpus)
norm_corpus

vectorizer, tfidf_matrix = ta.build_feature_matrix(norm_corpus) 
data = tfidf_matrix.toarray()
print(data.shape)
data

 

3.     Build and Train the Neural Network Model

With our prepared data and labels we can now build and train the Neural Network model by running these lines of code:

 

np.random.seed(125)
model = Sequential()
model.add(Dense(60, input_dim=data.shape[1], kernel_regularizer=regularizers.l2(0.02)))
model.add(Activation('relu'))
model.add(Dense(3))
model.add(Activation('sigmoid'))
model.summary()

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=0)

opt = keras.optimizers.Adam(lr=0.001)
model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])

epochs = 100
batch_size = 16
model.fit(X_train, y_train, epochs=epochs, batch_size=batch_size, validation_data=(X_test, y_test))

 

4.     Test and Export the Neural Network Model

Then, we can test the model with a set of test reviews and verify that the classifier works fine and, finally, we can export the model to a file in our project folder for easy access in the future.

 

test_reviews = ['The room was very nice and the beds were especially comfortable.', 'The kids loved going to the Kids Club at the swimming pool.', 'The food was great and the buffet was priced very reasonably.']
test_reviews = ta.normalize_corpus(test_reviews)
test_reviews = vectorizer.transform(test_reviews)
test_reviews = test_reviews.toarray()
print(test_reviews.shape)

pred = model.predict(test_reviews)
pred_label = pred.argmax(axis=1)
pred_df = pd.DataFrame(np.column_stack((pred,pred_label)), columns=['class_0_room', 'class_1_diner', 'class_2_pool', 'label'])
pred_df.label = pred_df.label.astype(int)
pred_df

from sklearn.externals import joblib
output_folder = './output'
model_filename = 'final_model.hdf5'
os.makedirs(output_folder, exist_ok=True)
model.save(os.path.join(output_folder, model_filename))
vectorizer_name = 'vectorizer'
joblib.dump(vectorizer, os.path.join(output_folder, vectorizer_name))

from keras.models import load_model
loaded_model = load_model(os.path.join(output_folder, model_filename))
loaded_model.summary()

pred = loaded_model.predict(test_reviews)
pred_label = pred.argmax(axis=1)
pred_df = pd.DataFrame(np.column_stack((pred,pred_label)), columns=['class_0_room', 'class_1_diner', 'class_2_pool', 'label'])
pred_df.label = pred_df.label.astype(int)
pred_df

 

In the following animation you will see the processes and outputs of running these first steps in Azure Notebooks with Jupyter:

 

 

5.     Converting the Keras Model to ONNX Format

Now we will load the trained Keras model from file, and then convert the model to ONNX. ONNX is a format that will enable us to use this classifier model in different environments including Web Services. Furthermore, ONNX runtimes and libraries are also designed to maximize performance.

 

import os
import numpy as np
import pandas as pd
np.random.seed(125)
from keras.models import load_model
from sklearn.externals import joblib
output_folder = './output'
model_filename = 'final_model.hdf5'
keras_model = load_model(os.path.join(output_folder, model_filename))
print(keras_model.summary())
vectorizer_name = 'vectorizer'
vectorizer = joblib.load(os.path.join(output_folder, vectorizer_name))

import onnxmltools

deployment_folder = 'deploy'
onnx_export_folder = 'onnx'

onnx_model_name = 'reviews_classifier.onnx'
converted_model = onnxmltools.convert_keras(keras_model, onnx_model_name, target_opset=7)

onnx_model_path = os.path.join(deployment_folder, onnx_export_folder)
os.makedirs(onnx_model_path, exist_ok=True)
onnxmltools.utils.save_model(converted_model, os.path.join(onnx_model_path,onnx_model_name))

import onnxruntime

onnx_session = onnxruntime.InferenceSession(
    os.path.join(os.path.join(deployment_folder, onnx_export_folder), onnx_model_name))
input_name = onnx_session.get_inputs()[0].name
output_name = onnx_session.get_outputs()[0].name
print('Expected input shape: ', onnx_session.get_inputs()[0].shape)

 

6.     Package and Deploy Model to Container

In this step we are going to create an Azure Web Service by packaging and deploying the ONNX model to an Azure Container Instance.

 

!cat .azureml/config.json
import azureml.core
from azureml.core.workspace import Workspace
ws = Workspace.from_config()
from azureml.core.model import Model

registered_model_name = 'reviews_classifier_onnx'
onnx_model_path = os.path.join(os.path.join(deployment_folder, onnx_export_folder), onnx_model_name)

registered_model = Model.register(model_path = onnx_model_path, model_name = registered_model_name, description = "Reviews classification model.", workspace = ws)

output_folder = './output'
vectorizer_name = 'vectorizer'
vectorizer_path = os.path.join(output_folder, vectorizer_name)

registered_vectorizer = Model.register(model_path = vectorizer_path, model_name = vectorizer_name, description = "Reviews classification model vectorizer.", workspace = ws)

cwd = os.getcwd()
if cwd.endswith(deployment_folder):
    os.chdir('../')
%%writefile $deployment_folder/scoring_service.py

import json
import numpy as np
import os
import sys
import urllib.request
import nltk
from sklearn.externals import joblib
from azureml.core.model import Model
import onnxruntime

onnx_model_name = 'reviews_classifier_onnx'
vectorizer_name = 'vectorizer'

def init():
    global onnx_session
    global vectorizer
    
    try:
        nltk.download("all")
        tempFolderName = './resources'
        os.makedirs(tempFolderName, exist_ok=True)
        base_data_url = 'https://raw.githubusercontent.com/idiWork/Experiment_102/master/resources/'
        filesToDownload = ['contractions.py', 'textanalytics.py']
        
        for file in filesToDownload:
            data_url = os.path.join(base_data_url, file)
            local_file_path = os.path.join(tempFolderName, file)
            urllib.request.urlretrieve(data_url, local_file_path)
        
        sys.path.append(tempFolderName)

        import textanalytics as ta
        onnx_model_path = Model.get_model_path(onnx_model_name)
        vectorizer_path = Model.get_model_path(vectorizer_name)
        onnx_session = onnxruntime.InferenceSession(onnx_model_path)
        vectorizer = joblib.load(vectorizer_path)
    except Exception as e:
        print(e)

def run(raw_data):
    try:
        import textanalytics as ta
        input_data = np.array(json.loads(raw_data))
        input_data = ta.normalize_corpus(input_data)
        input_data = vectorizer.transform(input_data)
        input_data = input_data.toarray().astype(np.float32)
        
        result = onnx_session.run(None, {onnx_session.get_inputs()[0].name: input_data})[0].argmax(axis=1).item()
        return result
    except Exception as e:
        print(e)
        error = str(e)
        return error

from azureml.core.conda_dependencies import CondaDependencies 
conda_packages = ['numpy', 'scikit-learn']
pip_packages = ['nltk', 'azureml-sdk', 'onnxruntime']
mycondaenv = CondaDependencies.create(conda_packages=conda_packages, pip_packages=pip_packages)

cwd = os.getcwd()
if not cwd.endswith(deployment_folder):
    os.chdir(deployment_folder)
    
conda_file = 'dependencies.yml'
with open(conda_file, 'w') as f:
    f.write(mycondaenv.serialize_to_string())

runtime = 'python'
execution_script = 'scoring_service.py'

from azureml.core.image import ContainerImage
image_config = ContainerImage.image_configuration(execution_script = execution_script, runtime = runtime, conda_file = conda_file)

image_name = 'review-classifier-image'

from azureml.core import Image
image = Image.create(name=image_name, models=[registered_model, registered_vectorizer], image_config=image_config, workspace=ws)

image.wait_for_creation(show_output=True)

os.chdir("..")
from azureml.core.webservice import AciWebservice, Webservice

aci_config = AciWebservice.deploy_configuration(cpu_cores = 1, memory_gb = 1, tags = {'name': 'Review Classification'}, description = "Classifies a review as room (0), diner (1) or pool (2).")

service_name = "reviewclassservice"

aci_service = Webservice.deploy_from_image(deployment_config=aci_config, image=image, name=service_name, workspace=ws)

aci_service.wait_for_deployment(show_output=True)

 

7.     Test Web Service with HTTP Requests

With the Web Service deployed and published we can make direct HTTP calls from a REST client.

 

import json

test_reviews = ['The room was very nice and the beds were especially comfortable.', 'The kids loved going to the Kids Club at the swimming pool.', 'The food was great and the buffet was priced very reasonably.']

for i in range(len(test_reviews)):
    result = aci_service.run(json.dumps([test_reviews[i]]))
    print('Predicted label for test review #{} is {}'.format(i+1, result))

import requests

url = aci_service.scoring_uri
print('ACI Service: Review Classification scoring URI is: {}'.format(url))
headers = {'Content-Type':'application/json'}

for i in range(len(test_reviews)):
    response = requests.post(url, json.dumps([test_reviews[i]]), headers=headers)
    print('Predicted label for test review #{} is {}'.format(i+1, response.text))

 

In the following animation you will see the processes and outputs of running these last steps in Azure Notebooks with Jupyter:

 

Stay up to date!



Leave a comment