Author(s): The team at TD Bank | Dave Voyles, MSFT | @DaveVoyles
URL: www.DaveVoyles.com
Imagine that you have built a machine learning model and want others to be able to use it. You'd have to host it somewhere, and as more users hit the endpoint with the model, you'll need to scale dynamically to assure they have a fast and consistent experience. This project includes a number of simple, yet helpful tools.
Docker
Docker is a platform that allows users to easily pack, distribute, and manage applications within containers. It's an open-source project that automates the deployment of applications inside software containers. Gone are the days of an IT professional saying "Well, it worked on my machine." Not it works on all of our machines.
Flask
Flask is great for developers working on small projects that need a quick way to make a simple, Python-powered web site. It powers loads of small one-off tools, or simple web interfaces built over existing APIs.
Scikit-Learn
Scikit-Learn is a simple and efficient tools for data mining and data analysis, which is built on NumPy, SciPy, and matplotlib. It does a lot of the dirty work involved with machine learning, and allows you to quickly build models, make predicitons, and manage your data.
Once your docker container is deployed, you simply make an HTTP Post request to <YourWebsite>:5000/classify
with the URL of an image in the body, and the model will return a label for what it think best describes is in the image. At the moment it is trained to detect:
- axes
- boots
- carabiners
- crampons
- gloves
- hardshell jackets
- harnesses
- helmets
- insulated jackets
- pulleys
- rope
- tents
Yes!
You could easily train it to classify other objects, too. All of the code for this project is contained in the app.py file, and the trained model is contained in the pickle_model.pkl file.
Simply replace the pickle_model.pkl file with a trained model of your own.
App.py contains the code which does several things:
- Resizes the image
- Normalizes the image
- Parses the JSON POST request you made to its endpoint
- Calls the trained model
- Returns the classification result
The trained model, contained in pickle_model.pkl expects all images to be resized (128x128) and normalized, so if you're creating a new model of your own, you may want to keep this bit of code.
In a terminal, navigate to the folder containing the .dockerfile. This will create a new docker image and tag it with the name of your repository, name of the image, and the version It will take a few minutes to download & install all of the required files
docker build -t davevoyles/docker-flask-image-recognition-sklearn:latest .
Run the image locally in debug mode and expose ports 5000
docker run -d --name docker-flask-image-recognition-sklearn -p 5000:5000 davevoyles/docker-flask-image-recognition-sklearn
docker ps
docker logs docker-flask-image-recognition-sklearn
docker rm -f docker logs docker-flask-image-recognition-sklearnn
Push to docker hub account name/repository. This may take a few minutes
docker push davevoyles/docker-flask-image-recognition-sklearn
az login
az group create -l eastus -n dv-containers-rg
Create a container in azure w/ a public IP so that we can make HTTP post requests and expose port 5000. Pull image from dockerhub account/repository/tag
az container create --resource-group dv-containers-rg --name dv-flask-container --image davevoyles/docker-flask-image-recognition-sklearn:latest --ip-address public --location eastus --ports 5000
Check status of container by querying the ip address. You may have to wait a few minutes for it to complete.
az container show --resource-group dv-containers-rg --name dv-flask-container --query ipAddress
It should return with something like this:
{
"additionalProperties": {},
"dnsNameLabel": null,
"fqdn": null,
"ip": "40.114.107.193",
"ports": [
{
"additionalProperties": {},
"port": 5000,
"protocol": "TCP"
}
]
}
az container logs --resource-group dv-containers-rg --name dv-flask-container
You can also log into the Azure portal in your browser to see if your container service is running.
Swap the IP address listed below with your own. These will return the label of the image you passed in. For example:
{"classification": "insulated_jackets"}
curl -X POST \
http://40.117.156.248:5000/classify \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{
"url":"https://images.thenorthface.com/is/image/TheNorthFace/NF0A2VD5_KX7_hero?$638x745$"
}'
curl -X POST \
http://40.121.22.230:5000/classify \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{
"url":"https://images.thenorthface.com/is/image/TheNorthFace/NF0A2VD5_KX7_hero?$638x745$"
}'
curl -X POST \
http://40.121.22.230:5000/classify \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{
"url":"https://m.fortnine.ca/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/catalogimages/gmax/gm45-half-helmet-matte-black-xs.jpg"
}'
curl -X POST \
http://40.121.22.230:5000/classify \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{
"url":"https://images.sportsdirect.com/images/products/90800440_l.jpg"
}'
curl -X POST \
http://40.121.22.230:5000/classify \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{
"url":"https://mec.imgix.net/medias/sys_master/high-res/high-res/8860680618014/5052314-SIL00.jpg?w=600&h=600&auto=format&q=60&fit=fill&bg=FFF"
}'
az container delete --name dv-flask-container --resource-group dv-containers-rgt