How to construct and train a Deep Neural Network using Keras and deploy the model as an Azure Web Service
Experiment #102 – Discover 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: