Using Cognitive Services Containers with Azure IoT Edge
Tags: vscode, csharp, docker, azure
Published: 2019-04-30 22:17:06

---
title: Using Cognitive Services Containers with Azure IoT Edge
published: true 
description: Supercharge IoT Solutions with local processing of common AI tasks including Computer Vision, Facial Analysis, Language Understanding, and more!
tags: vscode, csharp, docker, azure
---

![Logo](https://thepracticaldev.s3.amazonaws.com/i/thbskhbtf81cxan4hg4x.png)

In this post we will cover how to enable use of Cognitive Services Containers within an Azure IoT Edge Deployment.

#Introduction

IoT Solutions often involve a number of challenges related to the environment where devices are ultimately deployed. These can include intermittent access to the internet, challenges related to remote updates of the device code, and security of the device itself.  On the software side, [Azure IoT Edge](https://docs.microsoft.com/en-us/azure/iot-edge/about-iot-edge?WT.mc_id=devto-blog-pdecarlo) addresses these challenges through a variety of features that were designed specifically for IoT scenarios.  

Here are some brief explanations of how IoT Edge addresses these challenges:
* Intermittent access to the internet is addressed by [buffering outbound device telemetry locally](https://docs.microsoft.com/en-us/azure/iot-edge/offline-capabilities?WT.mc_id=devto-blog-pdecarlo) on the device until internet access is restored, where it is then sent along with the original timestamps of the data at the time it was generated locally.
*  Remote updates are able to be configured using [targeted deployment configurations](https://docs.microsoft.com/en-us/azure/iot-edge/module-deployment-monitoring?WT.mc_id=devto-blog-pdecarlo) which specify a list of modules (containerized applications) which are to run on a given device
* Security is employed by only allowing devices which have been registered to an Azure IoT Hub instance to be able to submit telemetry data to it's respective Azure hosted endpoint in addition to a local [Hardware Security Manager](https://docs.microsoft.com/en-us/azure/iot-edge/iot-edge-security-manager?WT.mc_id=devto-blog-pdecarlo) which runs on the device itself to enable transitioning trust from underlying hardware root of trust hardware (if available) to securely bootstrap the IoT Edge runtime and monitor the integrity of its operations.

It is important to note that IoT Edge accomplishes safe deployment of code through the use of containerized modules.  Containers allow for easy distribution via familiar `docker pull` commands and enable runtime-recovery of modules via container restarts in mission critical IoT deployments.  This makes containers an ideal candidate for IoT Solutions where an OS environment is available. The IoT Edge runtime can run on [Linux X64](https://docs.microsoft.com/en-us/azure/iot-edge/how-to-install-iot-edge-linux?WT.mc_id=devto-blog-pdecarlo), [Linux ARM32](https://docs.microsoft.com/en-us/azure/iot-edge/how-to-install-iot-edge-linux-arm?WT.mc_id=devto-blog-pdecarlo), and [Windows X64](https://docs.microsoft.com/en-us/azure/iot-edge/how-to-install-iot-edge-windows
?WT.mc_id=devto-blog-pdecarlo) environments.  Once enabled, you can take advantage of all the benefits mentioned above in addition to some handy features in the [Device SDKs](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-sdks) which power custom IoT Edge modules.

[Azure Cognitive Services](https://docs.microsoft.com/en-us/azure/cognitive-services/?WT.mc_id=devto-blog-pdecarlo) allow developers to leverage intelligent algorithms into apps, websites, and bots so that they see, hear, speak, and understand by enabling common AI functionality through a Software as a Service offering.  Microsoft recently [announced support for a subset of it's line of Cognitive Services to run locally in the form of containers](https://docs.microsoft.com/en-us/azure/cognitive-services/cognitive-services-container-support?WT.mc_id=devto-blog-pdecarlo). These include services for Computer Vision, Face, LUIS, and various forms of Text Analytics. It is important to note that the Computer Vision and Face containers are currently in preview but may you may request access if you are interested in trying them out by filling out the [Cognitive Services Vision Containers Request form](https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR0XnG25zkIBLkA6GR39U7fRUQVE2MUVDVVJBVlU2Qk5TQTI1MVRSRExUMS4u).  Please be aware the Cognitive Services Containers currently only support Linux X64 and require that internet connectivity is re-established every ten minutes, otherwise the container will stop producing results when it's API endpoint is queried.


Leveraging Azure IoT Edge and Cognitive Services Containers together, we can build out IoT Solutions which allow for local AI processing in environments where internet connectivity may be intermittent.  We no longer need to rely on an external services to produce insights from our data, everything can be processed locally and deployed / configured from the cloud to enable rollout of updates in a securely designed fashion at scale.

#Steps

To begin development, you will want to ensure that you have a recent installation of [VSCode](https://code.visualstudio.com/Download?WT.mc_id=devto-blog-pdecarl) on your dev machine, you will also need to install the [IoT Edge Extension for VSCode](https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-edge&WT.mc_id=devto-blog-pdecarlo).


First create a new IoT Edge Solution with `F1` => "Azure IoT Edge: New IoT Edge Solution"

![Create New Solution](https://thepracticaldev.s3.amazonaws.com/i/zejh1ml46o51rzhoj3ej.PNG)

When asked to create a module, leave the default values and select "C# module" for the module template.

Next, open the deployment.template.json file included in the solution directory.  If you are using container images that are in preview, you will have been supplied a username and password to connect to a private container repository.  If this is the case, update the registryCredentials section as shown below, to enable pulling images from the private repository.

`            "registryCredentials": {
              "containerpreview": {
                "username": "{YourUsername}",
                "password": "{YourPassword}",
                "address": "containerpreview.azurecr.io"
              }`

Next we need to create a Cognitive Services resource in Azure:
![Create Cognitive Services Resource](https://thepracticaldev.s3.amazonaws.com/i/0iqrewwn26gu19bm7uim.PNG)

After you have created the Cognitive Services resource, obtain the API Key for the service, this will become the value used later for {YourCogServicesApiKey}:

![Get Cognitive Services API Key](https://thepracticaldev.s3.amazonaws.com/i/e05eigxc9sgm1os0ih29.png)


Now we can begin adding a module configuration to specify deployment of a Cognitive Services Container.  We will start using the "cognitive-services-recognize-text" container.  Keep in mind that the process will be similar for other Cognitive Services Containers.  You will want to look at the "modules" section of deployment.template.json and update it with the following additional entry (be sure to replace {YourCogServicesLocale} and {YourCogServicesApiKey} with appropriate values):


            "cognitive-services-recognize-text": {
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "containerpreview.azurecr.io/microsoft/cognitive-services-recognize-text:latest",
              "createOptions": 
              {                       
                "Cmd": [
                    "Eula=accept",
                  "Billing=https://{YourCogServicesLocale}.api.cognitive.microsoft.com/vision/v2.0",
                    "ApiKey={YourCogServicesApiKey}"
                ],
                "HostConfig": {
                  "PortBindings": {
                  "5000/tcp": [
                  {
                    "HostPort": "5000"
                  }
                  ] 
                  }
                  }
                }
            }
          },


The createOptions are inferred by looking at the [documentation to run the container locally](https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/computer-vision-how-to-install-containers#run-the-container-with-docker-run?WT.mc_id=devto-blog-pdecarlo), outside of IoT Edge, i.e.:

`docker run --rm -it -p 5000:5000 --memory 4g --cpus 1 \
containerpreview.azurecr.io/microsoft/cognitive-services-recognize-text \
Eula=accept \
Billing={BILLING_ENDPOINT_URI} \
ApiKey={BILLING_KEY}`

This specifies a container which maps port 5000 on the host to port 5000 running inside of the container along with Cmd's for setting Eula, Billing, and ApiKey values.

If you are curious how the appropriate syntax was obtained for the deployement.template.json module entry, I executed the command above and ran `docker inspect` on the container which will provide clues on how to formulate the appropriate structure for the "Cmd" section.  For a full list of available container create options, see the [Docker Engine API documentation](https://docs.docker.com/engine/api/v1.30/#operation/ContainerCreate).

Now to call the API from our C# module, add the following Global variables to SampleModule.cs:


`       // ApiKey is not needed on client side talking to a container
        private const string ApiKey = "000000000000000000000000000000";
        //Note: Endpoint value matches the module name used in deployment.template.json to allow internal resolution from custom modules
        private const string Endpoint = "http://cognitive-services-recognize-text:5000";
        private static HttpClient client = new HttpClient { BaseAddress = new Uri(Endpoint) };`

Next, add the following method:

				private static async Task ExtractText(Stream image)
				{

					String responseString = string.Empty;
					using (var imageContent = new StreamContent(image))
					{
						imageContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

						var requestAddress = "/vision/v2.0/recognizetextDirect";

						using (var response = await client.PostAsync(requestAddress, imageContent))
						{
							var resultAsString = await response.Content.ReadAsStringAsync();
							var resultAsJson = JsonConvert.DeserializeObject<JObject>(resultAsString);

							if (resultAsJson["lines"] == null)
							{
								responseString = resultAsString;
							}
							else
							{
								foreach (var line in resultAsJson["lines"])
								{
									responseString += line["text"] + "\n";
								}
							}

							Console.WriteLine(responseString);
						}
					}
				}


The process for calling the appropriate container endpoint was determined by perusing the source code of the [cognitive-services-containers-samples/Recognize-Text Sample](https://github.com/Azure-Samples/cognitive-services-containers-samples/tree/master/dotnet/Recognize-Text)

To trigger the ExtractText method, produce an appropriate mechanism to supply a Stream for a suitable image file to the method and monitor the result using `docker logs -f <container_id>`

Here is an example image and response supplied from using a screengrab of the NES Classic "The Addams Family"

![Example](https://thepracticaldev.s3.amazonaws.com/i/9wdkxcaaxlplyxegkrku.png)

If you think this kind of thing is cool (translating retro video games), I have a full open-source project which makes use of IoT Edge and Cognitive Services to do exactly that @ https://github.com/toolboc/RetroArch-AI-with-IoTEdge.

When your code is ready to deploy to a device, follow the instructions for [how to deploy modules from VSCode](https://docs.microsoft.com/en-us/azure/iot-edge/how-to-deploy-modules-vscode?WT.mc_id=devto-blog-pdecarlo).

# Summary

While I have only explicitly demonstrated the process for working with the cognitive-services-recognize-text container, the overall process can be applied to  other [Cognitive Services Containers](https://docs.microsoft.com/en-us/azure/cognitive-services/cognitive-services-container-support).  

Here is the general flow you will want to follow:

1. Create a proper module entry for the Cognitive Services container in deployment.template.json (Also provide docker registry credentials if using a preview image or images stored in a private docker registry).  If using multiple Cognitive Services Containers as modules, be sure to map the external host port from a unique external port number to the internal port 5000 for all entries.
2. Peruse the [cognitive-services-containers-samples repo](https://github.com/Azure-Samples/cognitive-services-containers-samples) for examples on how to interact with the service in question.
3. Implement a method which calls the appropriate API endpoint in your Custom Module code using information obtained in step 2 and employ logging to stdout to  track module output and status at runtime
4. Deploy and test the code by watching the `docker logs` of the module in question

# Conclusion

With the announcement of Cognitive Services Containers, we can now employ AI services into IoT Edge deployment configuration to allow for AI scenarios in IoT Edge Solutions without a need for reliance on external cloud services.  This provides extremely powerful AI capabilities without the need for the latency and overhead of external services.  The possibilities are endless: imagine using localized face recognition for access systems, live-translating video game text from one language to another, or processing license plate text on vehicles using an attached camera. These are exactly the types of scenarios that will be at the crest of the next wave of IoT solutions, i.e. scenarios which employ localized AI functionality in disconnected environments to produce intelligent decisions on-site.  It will interesting and exciting to see what kinds of systems will be created using AI processing paired with IoT solutions in the next five years.  Do you have any cool ideas you would like to see built on these concepts?  Drop a line in the comments and let us know what kinds of things you think will be part of the next wave of AI-enhanced IoT solutions!

Until next time,

Happy Hacking!