Skip to content

Commit 3e771a2

Browse files
authored
Notebook for deploying a fine-tuned ResNet18 CNN model using AzureML for Image Similarity (#560)
* Added notebook for deploying a fine-tuned resnet18 CNN model using AzureML that builds on the html_demo notebooks with a custom scoring script that saves the features in the intermediate layers and returns them in JSON format. Also added fix to script.js to support image similarity scenarios. * Updated readme * Fixed typo in readme * Addressed PR comment - removed link in notebook. * Addressing PR comments: Added descriptions for the notebook and updated its name. * Addressed PR comment: Made DATA_PATH point to the returned value from unzip_url using our fridge_objects dataset so that the user can just run the notebook.
1 parent eabe7e4 commit 3e771a2

File tree

3 files changed

+787
-13
lines changed

3 files changed

+787
-13
lines changed

contrib/html_demo/JupyterCode/4_train_and_deploy_custom_image_similarity_webapp.ipynb

Lines changed: 773 additions & 0 deletions
Large diffs are not rendered by default.

contrib/html_demo/JupyterCode/readme.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This directory contains a few helper notebooks that upload files and deploy mode
1010
| [1_image_similarity_export.ipynb](1_image_similarity_export.ipynb)| Exports computed reference image features for use in visualizng results (see details in "Image Similarity" section below) |
1111
| [2_upload_ui.ipynb](2_upload_ui.ipynb)| Uploads web page files to Azure Blob storage |
1212
| [3_deployment_to_azure_app_service.ipynb](3_deployment_to_azure_app_service.ipynb)| Deploys image classification model as an Azure app service |
13+
| [4_train_and_deploy_custom_image_similarity_webapp.ipynb](4_train_and_deploy_custom_image_similarity_webapp.ipynb) | Fine-tunes a ResNet18 CNN model and deploys a custom image similarity webapp using AzureML
1314

1415
### Requirements
1516

@@ -28,14 +29,15 @@ To run the code in the [2_upload_ui.ipynb](2_upload_ui.ipynb) notebook, you must
2829
* If you want to use an image similarity model, you can run [1_image_similarity_export.ipynb](1_image_similarity_export.ipynb) to export your image features for the web page to use.
2930
* To upload the web page for sharing, notebook [2_upload_ui.ipynb](2_upload_ui.ipynb) outlines the process of uploading to your Azure Blob storage.
3031
* As the web page needs the API to allow CORS, we recommend uploading models as an Azure app service. Notebook [3_deployment_to_azure_app_service.ipynb](3_deployment_to_azure_app_service.ipynb) gives a tutorial on how to do so with an image classification model.
32+
* [4_train_and_deploy_custom_image_similarity_webapp.ipynb](4_train_and_deploy_custom_image_similarity_webapp.ipynb) guides through the process of deploying a custom image similarity web application - from finetuning a RESNET50 model using a sample dataset in ImageNet directory structure format to updating required files for the web application and deploying them along with the model.
3133

3234
### Image Similarity
3335

3436
Image similarity relies on comparing DNN features of a query image, to the respective DNN features of potentially tens of thousands of references images. The notebooks in this directory compute these reference image DNN features and package them for use in the HTML UI. The DNN features are exported into a text file and compressed to be uploaded with the HTML UI files. To compare a query image to these exported reference image features, you will need a DNN model deployed to Azure App services that is able to compute the features of the query image and return them via API call.
3537

3638
Steps:
37-
1. Execute "1_image_similarity_export.ipynb" notebook to generate your reference image features and export them to compressed ZIP files
38-
2. Execute "2_upload_ui.ipynb" notebook to upload the HTML UI and all supporting files to your Azure Blob storage account
39-
3. Execute "3_deployment_to_azure_app_service.ipynb" notebook to upload your model for generating DNN features for your query image and create an API endpoint in Azure App service
39+
1. Execute [1_image_similarity_export.ipynb](1_image_similarity_export.ipynb) notebook to generate your reference image features and export them to compressed ZIP files
40+
2. Execute [2_upload_ui.ipynb](2_upload_ui.ipynb) notebook to upload the HTML UI and all supporting files to your Azure Blob storage account
41+
3. Execute [3_deployment_to_azure_app_service.ipynb](3_deployment_to_azure_app_service.ipynb) notebook to upload your model for generating DNN features for your query image and create an API endpoint in Azure App service
4042
4. Open the index.html file from your Blob storage account in a browser, enter your API endpoint URL, upload a query image and see what you get back
41-
43+
5. *(Optional)* Execute [4_train_and_deploy_custom_image_similarity_webapp.ipynb](4_train_and_deploy_custom_image_similarity_webapp.ipynb) notebook to finetune a RESNET50 model and deploy a custom image similarity web application

contrib/html_demo/UICode/script.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ function populateTable(i, tableData) {
4848
item.classList.add("item");
4949
var img = document.createElement('img');
5050
img.src = 'https://cvbp.blob.core.windows.net/public/html_demo/small-150/' + rowData[0];
51-
//img.src = 'small-150/' + rowData[0];
5251
var txt = document.createElement('p');
5352
txt.innerHTML = rowData[0] + "<br/><i>Dist.: " + rowData[1] + "</i>";
5453
item.appendChild(img);
@@ -78,7 +77,6 @@ function calcSimilar(top, queryFeatures, simType) {
7877
var queryRow = Math.floor(Math.random() * (rows - 0 + 1) + 0);
7978
var queryimg = ref_array[queryRow];
8079
retImg = 'https://cvbp.blob.core.windows.net/public/html_demo/small-150/' + fn_array[queryRow];
81-
//retImg = 'small-150/' + fn_array[queryRow];
8280
} else {
8381
var queryimg = queryFeatures;
8482
}
@@ -104,7 +102,6 @@ async function parseSimFileNames(fileType) {
104102
zipFile_fn = 'data/ref_filenames.zip';
105103
if (fileType == "example")
106104
zipFile_fn = 'https://cvbp.blob.core.windows.net/public/html_demo/data/ref_filenames.zip';
107-
//JSZipUtils.getBinaryContent('data/ref_filenames.zip', function(err, data) {
108105
JSZipUtils.getBinaryContent(zipFile_fn, function(err, data) {
109106
if (err) {
110107
reject(err);
@@ -138,7 +135,6 @@ async function parseSimFileFeatures(fileType) {
138135
zipFile_ref = 'data/ref_features.zip';
139136
if (fileType == "example")
140137
zipFile_ref = 'https://cvbp.blob.core.windows.net/public/html_demo/data/ref_features.zip';
141-
// JSZipUtils.getBinaryContent('data/ref_features.zip', function(err, data) {
142138
JSZipUtils.getBinaryContent(zipFile_ref, function(err, data) {
143139
if (err) {
144140
reject(err);
@@ -319,7 +315,7 @@ $('#multiCollapseWebcam').on('shown.bs.collapse', function () {
319315

320316
$('#multiCollapseSample').on('hidden.bs.collapse', function () {
321317
document.getElementById("btnSample").classList.remove("active");
322-
document.getElementById("btnSample").innerText = "Samples";
318+
document.getElementById("btnSample").innerText = "Choose From Samples";
323319
})
324320

325321
$('#multiCollapseSample').on('shown.bs.collapse', function () {
@@ -556,7 +552,7 @@ async function jsonParser(jString, ovr) {
556552
if (Array.isArray(resp[0])) {
557553
if (resp[0][0].hasOwnProperty("top")) {
558554
// "[[top: #, ]]"
559-
//will need to target a different feature if another scenario ends up doing rectangle boxes
555+
// will need to target a different feature if another scenario ends up doing rectangle boxes
560556
for (let i in resp) {
561557
let j = i
562558
if (ovr) {
@@ -600,7 +596,11 @@ async function jsonParser(jString, ovr) {
600596
}
601597
await renderImage(j);
602598
let features = resp[i].features;
603-
imgsimilarity(j, 5, features);
599+
600+
// parse the json into an array
601+
let featuresArray = JSON.parse(features)
602+
603+
imgsimilarity(j, 5, featuresArray);
604604
}
605605
return "similarity"
606606
}
@@ -618,8 +618,7 @@ function APIRequest() {
618618
uplBtn.disabled = "true";
619619
uplStatus.classList.remove("hide");
620620
uplStatus.innerHTML = 'Loading... <div class="spinner-border ml-auto spinner-border-sm" role="status" aria-hidden="true"></div>';
621-
//console.log(url);
622-
//console.log(JSON.stringify({data: b64o}));
621+
623622
let xhr = new XMLHttpRequest();
624623

625624
xhr.onload = function() {

0 commit comments

Comments
 (0)