From 651a6f95de5377060e884a82e2f9a87e388e99d2 Mon Sep 17 00:00:00 2001 From: Eagan Farlin <55567338+EaganFarlin@users.noreply.github.com> Date: Sun, 26 Nov 2023 20:38:29 -0500 Subject: [PATCH 1/4] Fixed cd'ing to wrong directory for python devs (#11) --- Instructions/Exercises/02-ai-services-security.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Instructions/Exercises/02-ai-services-security.md b/Instructions/Exercises/02-ai-services-security.md index be444d38..1125365b 100644 --- a/Instructions/Exercises/02-ai-services-security.md +++ b/Instructions/Exercises/02-ai-services-security.md @@ -160,7 +160,7 @@ Now you're ready to use the service principal identity in an application, so it > **Note**: In this exercise, we'll store the service principal credentials in the application configuration and use them to authenticate a **ClientSecretCredential** identity in your application code. This is fine for development and testing, but in a real production application, an administrator would assign a *managed identity* to the application so that it uses the service principal identity to access resources, without caching or storing the password. -1. In your terminal, switch to the **C-Sharp** or **Python** folder depending on your language preference. By running `cd C-Sharp` or `cd Python`. Then run `cd keyvault_client`. +1. In your terminal, switch to the **C-Sharp** or **Python** folder depending on your language preference. By running `cd C-Sharp` or `cd Python`. Then run `cd keyvault_client` for **C-Sharp** or `cd keyvault-client` for **Python**. 2. Install the packages you will need to use for Azure Key Vault and the Text Analytics API in your Azure AI services resource by running the appropriate command for your language preference: **C#** From 2bcb280e1f348ddcc8aa957b688597409499e01b Mon Sep 17 00:00:00 2001 From: 6cpsmidnight Date: Mon, 27 Nov 2023 23:52:11 -0500 Subject: [PATCH 2/4] Fixed cd'ing to wrong directory for python devs (#11) --- Instructions/Labs/02-ai-services-security.md | 227 ++++++++++--------- 1 file changed, 116 insertions(+), 111 deletions(-) diff --git a/Instructions/Labs/02-ai-services-security.md b/Instructions/Labs/02-ai-services-security.md index 9b25711b..b5e4a615 100644 --- a/Instructions/Labs/02-ai-services-security.md +++ b/Instructions/Labs/02-ai-services-security.md @@ -1,7 +1,7 @@ --- lab: - title: 'Manage Azure AI Services Security' - module: 'Module 2 - Developing AI Apps with Azure AI Services' + title: "Manage Azure AI Services Security" + module: "Module 2 - Developing AI Apps with Azure AI Services" --- # Manage Azure AI Services Security @@ -14,27 +14,27 @@ Access to Azure AI services is typically controlled through authentication keys, Open up a new browser tab to work with Cloud Shell. If you haven't cloned this repository to Cloud Shell recently, follow the steps below to make sure you have the most recent version. Otherwise, open Cloud Shell and navigate to your clone. -1. In the [Azure portal](https://portal.azure.com?azure-portal=true), select the **[>_]** (*Cloud Shell*) button at the top of the page to the right of the search box. A Cloud Shell pane will open at the bottom of the portal. +1. In the [Azure portal](https://portal.azure.com?azure-portal=true), select the **[>_]** (_Cloud Shell_) button at the top of the page to the right of the search box. A Cloud Shell pane will open at the bottom of the portal. - ![Screenshot of starting Cloud Shell by clicking on the icon to the right of the top search box.](../media/cloudshell-launch-portal.png#lightbox) + ![Screenshot of starting Cloud Shell by clicking on the icon to the right of the top search box.](../media/cloudshell-launch-portal.png#lightbox) -2. The first time you open the Cloud Shell, you may be prompted to choose the type of shell you want to use (*Bash* or *PowerShell*). Select **Bash**. If you don't see this option, skip the step. +2. The first time you open the Cloud Shell, you may be prompted to choose the type of shell you want to use (_Bash_ or _PowerShell_). Select **Bash**. If you don't see this option, skip the step. 3. If you're prompted to create storage for your Cloud Shell, ensure your subscription is specified and select **Create storage**. Then wait a minute or so for the storage to be created. -4. Make sure the type of shell indicated on the top left of the Cloud Shell pane is switched to *Bash*. If it's *PowerShell*, switch to *Bash* by using the drop-down menu. +4. Make sure the type of shell indicated on the top left of the Cloud Shell pane is switched to _Bash_. If it's _PowerShell_, switch to _Bash_ by using the drop-down menu. 5. Once the terminal starts, enter the following command to download the sample application and save it to a folder called `labs`. - ```bash + ```bash git clone https://github.com/MicrosoftLearning/mslearn-ai-services labs - ``` - + ``` + 6. The files are downloaded to a folder named **labs**. Navigate to the lab files for this exercise using the following command. - ```bash + ```bash cd labs/Labfiles/02-ai-services-security - ``` + ``` Use the following command to open the lab files in the built-in code editor. @@ -49,12 +49,12 @@ Code for both C# and Python has been provided. If you don't already have one in your subscription, you'll need to provision an **Azure AI Services** resource. 1. Open the Azure portal at `https://portal.azure.com`, and sign in using the Microsoft account associated with your Azure subscription. -2. In the top search bar, search for *Azure AI services*, select **Azure AI Services**, and create an Azure AI services multi-service account resource with the following settings: - - **Subscription**: *Your Azure subscription* - - **Resource group**: *Choose or create a resource group (if you are using a restricted subscription, you may not have permission to create a new resource group - use the one provided)* - - **Region**: *Choose any available region* - - **Name**: *Enter a unique name* - - **Pricing tier**: Standard S0 +2. In the top search bar, search for _Azure AI services_, select **Azure AI Services**, and create an Azure AI services multi-service account resource with the following settings: + - **Subscription**: _Your Azure subscription_ + - **Resource group**: _Choose or create a resource group (if you are using a restricted subscription, you may not have permission to create a new resource group - use the one provided)_ + - **Region**: _Choose any available region_ + - **Name**: _Enter a unique name_ + - **Pricing tier**: Standard S0 3. Select the required checkboxes and create the resource. 4. Wait for deployment to complete, and then view the deployment details. @@ -63,85 +63,86 @@ If you don't already have one in your subscription, you'll need to provision an When you created your Azure AI services resource, two authentication keys were generated. You can manage these in the Azure portal or by using the Azure command line interface (CLI). 1. In the Azure portal, go to your Azure AI services resource and view its **Keys and Endpoint** page. This page contains the information that you will need to connect to your resource and use it from applications you develop. Specifically: - - An HTTP *endpoint* to which client applications can send requests. - - Two *keys* that can be used for authentication (client applications can use either of the keys. A common practice is to use one for development, and another for production. You can easily regenerate the development key after developers have finished their work to prevent continued access). - - The *location* where the resource is hosted. This is required for requests to some (but not all) APIs. -2. Now you can use the following command to get the list of Azure AI services keys, replacing *<resourceName>* with the name of your Azure AI services resource, and *<resourceGroup>* with the name of the resource group in which you created it. + - An HTTP _endpoint_ to which client applications can send requests. + - Two _keys_ that can be used for authentication (client applications can use either of the keys. A common practice is to use one for development, and another for production. You can easily regenerate the development key after developers have finished their work to prevent continued access). + - The _location_ where the resource is hosted. This is required for requests to some (but not all) APIs. +2. Now you can use the following command to get the list of Azure AI services keys, replacing _<resourceName>_ with the name of your Azure AI services resource, and _<resourceGroup>_ with the name of the resource group in which you created it. - ``` - az cognitiveservices account keys list --name --resource-group - ``` + ``` + az cognitiveservices account keys list --name --resource-group + ``` - The command returns a list of the keys for your Azure AI services resource - there are two keys, named **key1** and **key2**. + The command returns a list of the keys for your Azure AI services resource - there are two keys, named **key1** and **key2**. -3. To test your Azure AI service, you can use **curl** - a command line tool for HTTP requests. In the **02-ai-services-security** folder, open **rest-test.sh** and edit the **curl** command it contains (shown below), replacing *<yourEndpoint>* and *<yourKey>* with your endpoint URI and **Key1** key to use the Text Analytics API in your Azure AI services resource. +3. To test your Azure AI service, you can use **curl** - a command line tool for HTTP requests. In the **02-ai-services-security** folder, open **rest-test.sh** and edit the **curl** command it contains (shown below), replacing _<yourEndpoint>_ and _<yourKey>_ with your endpoint URI and **Key1** key to use the Text Analytics API in your Azure AI services resource. - ```bash - curl -X POST "/text/analytics/v3.1/languages?" -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: " --data-ascii "{'documents':[{'id':1,'text':'hello'}]}" - ``` + ```bash + curl -X POST "/text/analytics/v3.1/languages?" -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: " --data-ascii "{'documents':[{'id':1,'text':'hello'}]}" + ``` 4. Save your changes, and then run the following command: - ``` - sh rest-test.sh - ``` + ``` + sh rest-test.sh + ``` The command returns a JSON document containing information about the language detected in the input data (which should be English). -5. If a key becomes compromised, or the developers who have it no longer require access, you can regenerate it in the portal or by using the Azure CLI. Run the following command to regenerate your **key1** key (replacing *<resourceName>* and *<resourceGroup>* for your resource). +5. If a key becomes compromised, or the developers who have it no longer require access, you can regenerate it in the portal or by using the Azure CLI. Run the following command to regenerate your **key1** key (replacing _<resourceName>_ and _<resourceGroup>_ for your resource). - ``` - az cognitiveservices account keys regenerate --name --resource-group --key-name key1 - ``` + ``` + az cognitiveservices account keys regenerate --name --resource-group --key-name key1 + ``` The list of keys for your Azure AI services resource is returned - note that **key1** has changed since you last retrieved them. 6. Re-run the **rest-test** command with the old key (you can use the **^** arrow on your keyboard to cycle through previous commands), and verify that it now fails. -7. Edit the *curl* command in **rest-test.sh** replacing the key with the new **key1** value, and save the changes. Then rerun the **rest-test** command and verify that it succeeds. +7. Edit the _curl_ command in **rest-test.sh** replacing the key with the new **key1** value, and save the changes. Then rerun the **rest-test** command and verify that it succeeds. -> **Tip**: In this exercise, you used the full names of Azure CLI parameters, such as **--resource-group**. You can also use shorter alternatives, such as **-g**, to make your commands less verbose (but a little harder to understand). The [Azure AI Services CLI command reference](https://docs.microsoft.com/cli/azure/cognitiveservices?view=azure-cli-latest) lists the parameter options for each Azure AI services CLI command. +> **Tip**: In this exercise, you used the full names of Azure CLI parameters, such as **--resource-group**. You can also use shorter alternatives, such as **-g**, to make your commands less verbose (but a little harder to understand). The [Azure AI Services CLI command reference](https://docs.microsoft.com/cli/azure/cognitiveservices?view=azure-cli-latest) lists the parameter options for each Azure AI services CLI command. ## Secure key access with Azure Key Vault -You can develop applications that consume Azure AI services by using a key for authentication. However, this means that the application code must be able to obtain the key. One option is to store the key in an environment variable or a configuration file where the application is deployed, but this approach leaves the key vulnerable to unauthorized access. A better approach when developing applications on Azure is to store the key securely in Azure Key Vault, and provide access to the key through a *managed identity* (in other words, a user account used by the application itself). +You can develop applications that consume Azure AI services by using a key for authentication. However, this means that the application code must be able to obtain the key. One option is to store the key in an environment variable or a configuration file where the application is deployed, but this approach leaves the key vulnerable to unauthorized access. A better approach when developing applications on Azure is to store the key securely in Azure Key Vault, and provide access to the key through a _managed identity_ (in other words, a user account used by the application itself). ### Create a key vault and add a secret -First, you need to create a key vault and add a *secret* for the Azure AI services key. +First, you need to create a key vault and add a _secret_ for the Azure AI services key. 1. Make a note of the **key1** value for your Azure AI services resource (or copy it to the clipboard). -2. In the Azure portal, on the **Home** page, select the **+Create a resource** button, search for *Key Vault*, and create a **Key Vault** resource with the following settings: - - - **Basics** tab - - **Subscription**: *Your Azure subscription* - - **Resource group**: *The same resource group as your Azure AI service resource* - - **Key vault name**: *Enter a unique name* - - **Region**: *The same region as your Azure AI service resource* - - **Pricing tier**: Standard - - - **Access configuration** tab - - **Permission model**: Vault access policy - - Scroll down to the **Access policies** section and select your user using the checkbox on the left. Then select **Review + create**, and select **Create** to create your resource. - +2. In the Azure portal, on the **Home** page, select the **+Create a resource** button, search for _Key Vault_, and create a **Key Vault** resource with the following settings: + + - **Basics** tab + + - **Subscription**: _Your Azure subscription_ + - **Resource group**: _The same resource group as your Azure AI service resource_ + - **Key vault name**: _Enter a unique name_ + - **Region**: _The same region as your Azure AI service resource_ + - **Pricing tier**: Standard + + - **Access configuration** tab + - **Permission model**: Vault access policy + - Scroll down to the **Access policies** section and select your user using the checkbox on the left. Then select **Review + create**, and select **Create** to create your resource. + 3. Wait for deployment to complete and then go to your key vault resource. 4. In the left navigation pane, select **Secrets** (in the Objects section). 5. Select **+ Generate/Import** and add a new secret with the following settings : - - **Upload options**: Manual - - **Name**: AI-Services-Key *(it's important to match this exactly, because later you'll run code that retrieves the secret based on this name)* - - **Value**: *Your **key1** Azure AI services key* + - **Upload options**: Manual + - **Name**: AI-Services-Key _(it's important to match this exactly, because later you'll run code that retrieves the secret based on this name)_ + - **Value**: _Your **key1** Azure AI services key_ 6. Select **Create**. ### Create a service principal To access the secret in the key vault, your application must use a service principal that has access to the secret. You'll use the Azure command line interface (CLI) to create the service principal, find its object ID, and grant access to the secret in Azure Vault. -1. Run the following Azure CLI command, replacing *<spName>* with a unique suitable name for an application identity (for example, *ai-app* with your initials appended on the end; the name must be unique within your tenant). Also replace *<subscriptionId>* and *<resourceGroup>* with the correct values for your subscription ID and the resource group containing your Azure AI services and key vault resources: +1. Run the following Azure CLI command, replacing _<spName>_ with a unique suitable name for an application identity (for example, _ai-app_ with your initials appended on the end; the name must be unique within your tenant). Also replace _<subscriptionId>_ and _<resourceGroup>_ with the correct values for your subscription ID and the resource group containing your Azure AI services and key vault resources: - > **Tip**: If you are unsure of your subscription ID, use the **az account show** command to retrieve your subscription information - the subscription ID is the **id** attribute in the output. If you see an error about the object already existing, please choose a different unique name. + > **Tip**: If you are unsure of your subscription ID, use the **az account show** command to retrieve your subscription information - the subscription ID is the **id** attribute in the output. If you see an error about the object already existing, please choose a different unique name. - ``` - az ad sp create-for-rbac -n "api://" --role owner --scopes subscriptions//resourceGroups/ - ``` + ``` + az ad sp create-for-rbac -n "api://" --role owner --scopes subscriptions//resourceGroups/ + ``` The output of this command includes information about your new service principal. It should look similar to this: @@ -157,83 +158,87 @@ The output of this command includes information about your new service principal Make a note of the **appId**, **password**, and **tenant** values - you will need them later (if you close this terminal, you won't be able to retrieve the password; so it's important to note the values now - you can paste the output into a new text file on your local machine to ensure you can find the values you need later!) -2. To get the **object ID** of your service principal, run the following Azure CLI command, replacing *<appId>* with the value of your service principal's app ID. +2. To get the **object ID** of your service principal, run the following Azure CLI command, replacing _<appId>_ with the value of your service principal's app ID. - ``` - az ad sp show --id - ``` + ``` + az ad sp show --id + ``` -3. Copy the `id` value in the json returned in response. -3. To assign permission for your new service principal to access secrets in your Key Vault, run the following Azure CLI command, replacing *<keyVaultName>* with the name of your Azure Key Vault resource and *<objectId>* with the value of your service principal's ID value you've just copied. +3. Copy the `id` value in the json returned in response. +4. To assign permission for your new service principal to access secrets in your Key Vault, run the following Azure CLI command, replacing _<keyVaultName>_ with the name of your Azure Key Vault resource and _<objectId>_ with the value of your service principal's ID value you've just copied. - ``` - az keyvault set-policy -n --object-id --secret-permissions get list - ``` + ``` + az keyvault set-policy -n --object-id --secret-permissions get list + ``` ### Use the service principal in an application Now you're ready to use the service principal identity in an application, so it can access the secret Azure AI services key in your key vault and use it to connect to your Azure AI services resource. -> **Note**: In this exercise, we'll store the service principal credentials in the application configuration and use them to authenticate a **ClientSecretCredential** identity in your application code. This is fine for development and testing, but in a real production application, an administrator would assign a *managed identity* to the application so that it uses the service principal identity to access resources, without caching or storing the password. +> **Note**: In this exercise, we'll store the service principal credentials in the application configuration and use them to authenticate a **ClientSecretCredential** identity in your application code. This is fine for development and testing, but in a real production application, an administrator would assign a _managed identity_ to the application so that it uses the service principal identity to access resources, without caching or storing the password. -1. In your terminal, switch to the **C-Sharp** or **Python** folder depending on your language preference. By running `cd C-Sharp` or `cd Python`. Then run `cd keyvault_client`. +1. In your terminal, switch to the **C-Sharp** or **Python** folder depending on your language preference. By running `cd C-Sharp` or `cd Python`. Then run `cd keyvault_client` for **C-Sharp** or `cd keyvault-client` for **Python**. 2. Install the packages you will need to use for Azure Key Vault and the Text Analytics API in your Azure AI services resource by running the appropriate command for your language preference: - **C#** + **C#** - ``` - dotnet add package Azure.AI.TextAnalytics --version 5.3.0 - dotnet add package Azure.Identity --version 1.5.0 - dotnet add package Azure.Security.KeyVault.Secrets --version 4.2.0-beta.3 - ``` + ``` + dotnet add package Azure.AI.TextAnalytics --version 5.3.0 + dotnet add package Azure.Identity --version 1.5.0 + dotnet add package Azure.Security.KeyVault.Secrets --version 4.2.0-beta.3 + ``` - **Python** + **Python** - ``` - pip install azure-ai-textanalytics==5.3.0 - pip install azure-identity==1.5.0 - pip install azure-keyvault-secrets==4.2.0 - ``` + ``` + pip install azure-ai-textanalytics==5.3.0 + pip install azure-identity==1.5.0 + pip install azure-keyvault-secrets==4.2.0 + ``` 3. View the contents of the **keyvault-client** folder, and note that it contains a file for configuration settings: - - **C#**: appsettings.json - - **Python**: .env - - Open the configuration file and update the configuration values it contains to reflect the following settings: - - - The **endpoint** for your Azure AI Services resource - - The name of your **Azure Key Vault** resource - - The **tenant** for your service principal - - The **appId** for your service principal - - The **password** for your service principal - - Save your changes by pressing **CTRL+S**. + + - **C#**: appsettings.json + - **Python**: .env + + Open the configuration file and update the configuration values it contains to reflect the following settings: + + - The **endpoint** for your Azure AI Services resource + - The name of your **Azure Key Vault** resource + - The **tenant** for your service principal + - The **appId** for your service principal + - The **password** for your service principal + + Save your changes by pressing **CTRL+S**. + 4. Note that the **keyvault-client** folder contains a code file for the client application: - - **C#**: Program.cs - - **Python**: keyvault-client.py + - **C#**: Program.cs + - **Python**: keyvault-client.py + + Open the code file and review the code it contains, noting the following details: + + - The namespace for the SDK you installed is imported + - Code in the **Main** function retrieves the application configuration settings, and then it uses the service principal credentials to get the Azure AI services key from the key vault. + - The **GetLanguage** function uses the SDK to create a client for the service, and then uses the client to detect the language of the text that was entered. - Open the code file and review the code it contains, noting the following details: - - The namespace for the SDK you installed is imported - - Code in the **Main** function retrieves the application configuration settings, and then it uses the service principal credentials to get the Azure AI services key from the key vault. - - The **GetLanguage** function uses the SDK to create a client for the service, and then uses the client to detect the language of the text that was entered. 5. Enter the following command to run the program: - **C#** + **C#** - ``` - dotnet run - ``` + ``` + dotnet run + ``` - **Python** + **Python** - ``` - python keyvault-client.py - ``` + ``` + python keyvault-client.py + ``` 6. When prompted, enter some text and review the language that is detected by the service. For example, try entering "Hello", "Bonjour", and "Gracias". 7. When you have finished testing the application, enter "quit" to stop the program. ## More information -For more information about securing Azure AI services, see the [Azure AI Services security documentation](https://docs.microsoft.com/azure/ai-services/security-features). \ No newline at end of file +For more information about securing Azure AI services, see the [Azure AI Services security documentation](https://docs.microsoft.com/azure/ai-services/security-features). From a273108381da208f13a34c500951452cc95e6f3a Mon Sep 17 00:00:00 2001 From: 6cpsmidnight Date: Mon, 27 Nov 2023 23:59:11 -0500 Subject: [PATCH 3/4] Resolved Command Typo For 05 (#15) --- .../Exercises/05-personalizer-exercise.md | 614 ++++++++--------- Instructions/Labs/05-personalizer-exercise.md | 616 +++++++++--------- 2 files changed, 615 insertions(+), 615 deletions(-) diff --git a/Instructions/Exercises/05-personalizer-exercise.md b/Instructions/Exercises/05-personalizer-exercise.md index fbb09ab8..0d82b9a2 100644 --- a/Instructions/Exercises/05-personalizer-exercise.md +++ b/Instructions/Exercises/05-personalizer-exercise.md @@ -1,6 +1,6 @@ --- lab: - title: 'Use AI Personalizer with Visual Studio Code Notebooks to simulate a loop' + title: "Use AI Personalizer with Visual Studio Code Notebooks to simulate a loop" --- > **Note** @@ -12,13 +12,13 @@ In this exercise, you'll use Azure AI Personalizer with notebooks in Visual Stud 1. In the Azure portal, search for **Azure AI services**. Then select **Create** under **Personalizer** in the results list. - ![A screenshot of the Azure portal showing how to create an Azure AI Personalizer resource](../media/ai-personalizer/create-personalizer-portal.png) + ![A screenshot of the Azure portal showing how to create an Azure AI Personalizer resource](../media/ai-personalizer/create-personalizer-portal.png) 1. Select your subscription, enter a resource group name, and name for your resource. For pricing tier, choose **Free F0**. 1. Select **Review + create** to review your choices, then select **Create** create your resource. 1. Go to your newly created Azure AI Personalizer resource, then in the Keys and Endpoint pane, copy and paste the **Key** and **Endpoint** somewhere safe for use later: - ![A screenshot showing the Key and Endpoint pane.](../media/ai-personalizer/copy-key-endpoint.png) + ![A screenshot showing the Key and Endpoint pane.](../media/ai-personalizer/copy-key-endpoint.png) 1. Select Setup in the navigation pane, and then set the **Reward wait time** to **10 minutes** (if not already set), and set the **Model update frequency** to **15 seconds**. 1. Select **Save**. @@ -26,13 +26,15 @@ In this exercise, you'll use Azure AI Personalizer with notebooks in Visual Stud ## Set up notebook 1. In your Visual Studio Code editor, press **Ctrl+Shift+P** and select **Create new Jupyter notebook**. +1. In your Visual Studio Code editor, press **Ctrl+Shift+P** and select **Create: New Jupyter Notebook**. 1. Save the file and name it **my-notebook** on your device. 1. Now you need to install the required extensions. Select **Select Kernel** in the top right of the notebook. Then select **Install/Enable suggested extensions**. - ![A screenshot showing how to install the extensions.](../media/ai-personalizer/8-install-enable-extensions-code.png) + ![A screenshot showing how to install the extensions.](../media/ai-personalizer/8-install-enable-extensions-code.png) + + > [!NOTE] + > If you've already done this before, you won't see this option and can skip this step. - > [!NOTE] - > If you've already done this before, you won't see this option and can skip this step. 1. Wait for the extensions to be installed, then select **Python environments...** in the dropdown that appears. 1. Then select the top recommended environment. @@ -42,173 +44,170 @@ For the purpose of this exercise, we'll create a list of users and a list coffee 1. Copy the following JSON code into an empty file and save that file as `users.json` in the same folder as your notebook file. - ```json - { - "Alice": { - "Sunny": { - "Morning": "Cold brew", - "Afternoon": "Iced mocha", - "Evening": "Cold brew" - }, - "Rainy": { - "Morning": "Latte", - "Afternoon": "Cappucino", - "Evening": "Latte" - }, - "Snowy": { - "Morning": "Cappucino", - "Afternoon": "Cappucino", - "Evening": "Cappucino" - } - }, - "Bob": { - "Sunny": { - "Morning": "Cappucino", - "Afternoon": "Iced mocha", - "Evening": "Cold brew" - }, - "Rainy": { - "Morning": "Latte", - "Afternoon": "Latte", - "Evening": "Latte" - }, - "Snowy": { - "Morning": "Iced mocha", - "Afternoon": "Iced mocha", - "Evening": "Iced mocha" - } - }, - "Cathy": { - "Sunny": { - "Morning": "Latte", - "Afternoon": "Cold brew", - "Evening": "Cappucino" - }, - "Rainy": { - "Morning": "Cappucino", - "Afternoon": "Latte", - "Evening": "Iced mocha" - }, - "Snowy": { - "Morning": "Cold brew", - "Afternoon": "Iced mocha", - "Evening": "Cappucino" - } - }, - "Dave": { - "Sunny": { - "Morning": "Iced mocha", - "Afternoon": "Iced mocha", - "Evening": "Iced mocha" - }, - "Rainy": { - "Morning": "Latte", - "Afternoon": "Latte", - "Evening": "Latte" - }, - "Snowy": { - "Morning": "Cappucino", - "Afternoon": "Cappucino", - "Evening": "Cappucino" - } - } - } - ``` + ```json + { + "Alice": { + "Sunny": { + "Morning": "Cold brew", + "Afternoon": "Iced mocha", + "Evening": "Cold brew" + }, + "Rainy": { + "Morning": "Latte", + "Afternoon": "Cappucino", + "Evening": "Latte" + }, + "Snowy": { + "Morning": "Cappucino", + "Afternoon": "Cappucino", + "Evening": "Cappucino" + } + }, + "Bob": { + "Sunny": { + "Morning": "Cappucino", + "Afternoon": "Iced mocha", + "Evening": "Cold brew" + }, + "Rainy": { + "Morning": "Latte", + "Afternoon": "Latte", + "Evening": "Latte" + }, + "Snowy": { + "Morning": "Iced mocha", + "Afternoon": "Iced mocha", + "Evening": "Iced mocha" + } + }, + "Cathy": { + "Sunny": { + "Morning": "Latte", + "Afternoon": "Cold brew", + "Evening": "Cappucino" + }, + "Rainy": { + "Morning": "Cappucino", + "Afternoon": "Latte", + "Evening": "Iced mocha" + }, + "Snowy": { + "Morning": "Cold brew", + "Afternoon": "Iced mocha", + "Evening": "Cappucino" + } + }, + "Dave": { + "Sunny": { + "Morning": "Iced mocha", + "Afternoon": "Iced mocha", + "Evening": "Iced mocha" + }, + "Rainy": { + "Morning": "Latte", + "Afternoon": "Latte", + "Evening": "Latte" + }, + "Snowy": { + "Morning": "Cappucino", + "Afternoon": "Cappucino", + "Evening": "Cappucino" + } + } + } + ``` 1. Next, copy the following code and save it to a file called `coffee.json`: - ```json - [ - { - "id": "Cappucino", - "features": [ - { - "type": "hot", - "origin": "kenya", - "organic": "yes", - "roast": "dark" - - } - ] - }, - { - "id": "Cold brew", - "features": [ - { - "type": "cold", - "origin": "brazil", - "organic": "yes", - "roast": "light" - } - ] - }, - { - "id": "Iced mocha", - "features": [ - { - "type": "cold", - "origin": "ethiopia", - "organic": "no", - "roast": "light" - } - ] - }, - { - "id": "Latte", - "features": [ - { - "type": "hot", - "origin": "brazil", - "organic": "no", - "roast": "dark" - } - ] - } - ] - ``` + ```json + [ + { + "id": "Cappucino", + "features": [ + { + "type": "hot", + "origin": "kenya", + "organic": "yes", + "roast": "dark" + } + ] + }, + { + "id": "Cold brew", + "features": [ + { + "type": "cold", + "origin": "brazil", + "organic": "yes", + "roast": "light" + } + ] + }, + { + "id": "Iced mocha", + "features": [ + { + "type": "cold", + "origin": "ethiopia", + "organic": "no", + "roast": "light" + } + ] + }, + { + "id": "Latte", + "features": [ + { + "type": "hot", + "origin": "brazil", + "organic": "no", + "roast": "dark" + } + ] + } + ] + ``` 1. Copy and paste the following code into a file and save it as `example-rankrequest.json`: - - ```json - { - "contextFeatures": [ - ], - "actions": [ - ], - "excludedActions": [ - ], - "eventId": "", - "deferActivation": false - } - ``` + + ```json + { + "contextFeatures": [], + "actions": [], + "excludedActions": [], + "eventId": "", + "deferActivation": false + } + ``` ## Set your endpoint and key 1. At the top of your notebook, add the following code to include the required modules: - ```python - import json - import matplotlib.pyplot as plt - import random - import requests - import time - import uuid - import datetime - ``` + ```python + import json + import matplotlib.pyplot as plt + import random + import requests + import time + import uuid + import datetime + ``` 1. Select the cell, then select the run button to the left of the cell: - ![A screenshot showing the run button.](../media/ai-personalizer/8-press-run.png) - > [!NOTE] - > Make to you select the run button each time you populate a new cell. If you're prompted to install the ipykernel package, select **Install**. + ![A screenshot showing the run button.](../media/ai-personalizer/8-press-run.png) + + > [!NOTE] + > Make to you select the run button each time you populate a new cell. If you're prompted to install the ipykernel package, select **Install**. 1. Select **+ Code** at the top of your notebook to create a new code cell. Then add the following code: - ```python - # Replace 'personalization_base_url' and 'resource_key' with your valid endpoint values. - personalization_base_url = "" - resource_key = "" - ``` + ```python + # Replace 'personalization_base_url' and 'resource_key' with your valid endpoint values. + personalization_base_url = "" + resource_key = "" + ``` 1. Replace **personalization_base_url** value with your copied endpoint, and **resource_key** value with your key. @@ -216,32 +215,32 @@ For the purpose of this exercise, we'll create a list of users and a list coffee 1. Next, you create the code helps to take note of start and end times of iterative functions you will use later. Add the following code to a new cell: - ```python - # Print out current datetime - def currentDateTime(): - currentDT = datetime.datetime.now() - print (str(currentDT)) - - # ititialize variable for model's last modified date - modelLastModified = "" - - def get_last_updated(currentModifiedDate): - - print('-----checking model') - - # get model properties - response = requests.get(personalization_model_properties_url, headers = headers, params = None) - - print(response) - print(response.json()) - - # get lastModifiedTime - lastModifiedTime = json.dumps(response.json()["lastModifiedTime"]) - - if (currentModifiedDate != lastModifiedTime): - currentModifiedDate = lastModifiedTime - print(f'-----model updated: {lastModifiedTime}') - ``` + ```python + # Print out current datetime + def currentDateTime(): + currentDT = datetime.datetime.now() + print (str(currentDT)) + + # ititialize variable for model's last modified date + modelLastModified = "" + + def get_last_updated(currentModifiedDate): + + print('-----checking model') + + # get model properties + response = requests.get(personalization_model_properties_url, headers = headers, params = None) + + print(response) + print(response.json()) + + # get lastModifiedTime + lastModifiedTime = json.dumps(response.json()["lastModifiedTime"]) + + if (currentModifiedDate != lastModifiedTime): + currentModifiedDate = lastModifiedTime + print(f'-----model updated: {lastModifiedTime}') + ``` 1. Don't forget to run your new cell once you've added your new code. @@ -249,23 +248,23 @@ For the purpose of this exercise, we'll create a list of users and a list coffee 1. Next, you'll need to validate the service state by getting the policy and service configuration. To do this, add the following code to a new cell: - ```python - def get_service_settings(): - - print('-----checking service settings') - - # get learning policy - response = requests.get(personalization_model_policy_url, headers = headers, params = None) - - print(response) - print(response.json()) - - # get service settings - response = requests.get(personalization_service_configuration_url, headers = headers, params = None) - - print(response) - print(response.json()) - ``` + ```python + def get_service_settings(): + + print('-----checking service settings') + + # get learning policy + response = requests.get(personalization_model_policy_url, headers = headers, params = None) + + print(response) + print(response.json()) + + # get service settings + response = requests.get(personalization_service_configuration_url, headers = headers, params = None) + + print(response) + print(response.json()) + ``` 1. Make sure to run your new code cell. @@ -284,63 +283,63 @@ Now you'll add code to: 1. To do this, add the following code to a new cell and run it: - ```python - # build URLs - personalization_rank_url = personalization_base_url + "personalizer/v1.0/rank" - personalization_reward_url = personalization_base_url + "personalizer/v1.0/events/" #add "{eventId}/reward" - personalization_model_properties_url = personalization_base_url + "personalizer/v1.0/model/properties" - personalization_model_policy_url = personalization_base_url + "personalizer/v1.0/configurations/policy" - personalization_service_configuration_url = personalization_base_url + "personalizer/v1.0/configurations/service" - - headers = {'Ocp-Apim-Subscription-Key' : resource_key, 'Content-Type': 'application/json'} - - # context - users = "users.json" - - # action features - coffee = "coffee.json" - - # empty JSON for Rank request - requestpath = "example-rankrequest.json" - - # initialize random - random.seed(time.time()) - - userpref = None - rankactionsjsonobj = None - actionfeaturesobj = None - - with open(users) as handle: - userpref = json.loads(handle.read()) - - with open(coffee) as handle: - actionfeaturesobj = json.loads(handle.read()) - - with open(requestpath) as handle: - rankactionsjsonobj = json.loads(handle.read()) - - get_last_updated(modelLastModified) - get_service_settings() - - print(f'User count {len(userpref)}') - print(f'Coffee count {len(actionfeaturesobj)}') - ``` + ```python + # build URLs + personalization_rank_url = personalization_base_url + "personalizer/v1.0/rank" + personalization_reward_url = personalization_base_url + "personalizer/v1.0/events/" #add "{eventId}/reward" + personalization_model_properties_url = personalization_base_url + "personalizer/v1.0/model/properties" + personalization_model_policy_url = personalization_base_url + "personalizer/v1.0/configurations/policy" + personalization_service_configuration_url = personalization_base_url + "personalizer/v1.0/configurations/service" + + headers = {'Ocp-Apim-Subscription-Key' : resource_key, 'Content-Type': 'application/json'} + + # context + users = "users.json" + + # action features + coffee = "coffee.json" + + # empty JSON for Rank request + requestpath = "example-rankrequest.json" + + # initialize random + random.seed(time.time()) + + userpref = None + rankactionsjsonobj = None + actionfeaturesobj = None + + with open(users) as handle: + userpref = json.loads(handle.read()) + + with open(coffee) as handle: + actionfeaturesobj = json.loads(handle.read()) + + with open(requestpath) as handle: + rankactionsjsonobj = json.loads(handle.read()) + + get_last_updated(modelLastModified) + get_service_settings() + + print(f'User count {len(userpref)}') + print(f'Coffee count {len(actionfeaturesobj)}') + ``` 1. The call should return a response similar to the following: - ```bash - -----checking model - - {'creationTime': '2023-09-22T14:58:45+00:00', 'lastModifiedTime': '2023-09-22T14:58:45+00:00'} - -----model updated: "2023-09-22T14:58:45+00:00" - -----checking service settings - - {'name': '917554355a3347a1af3d2935d521426a', 'arguments': '--cb_explore_adf --epsilon 0.20000000298023224 --power_t 0 -l 0.001 --cb_type mtr -q ::'} - - {'rewardWaitTime': 'PT10M', 'defaultReward': 0.0, 'rewardAggregation': 'earliest', 'explorationPercentage': 0.2, 'modelExportFrequency': 'PT15S', 'logRetentionDays': 90, 'lastConfigurationEditDate': '2021-01-01T00:00:00', 'learningMode': 'Online'} - User count 4 - Coffee count 4 - ``` + ```bash + -----checking model + + {'creationTime': '2023-09-22T14:58:45+00:00', 'lastModifiedTime': '2023-09-22T14:58:45+00:00'} + -----model updated: "2023-09-22T14:58:45+00:00" + -----checking service settings + + {'name': '917554355a3347a1af3d2935d521426a', 'arguments': '--cb_explore_adf --epsilon 0.20000000298023224 --power_t 0 -l 0.001 --cb_type mtr -q ::'} + + {'rewardWaitTime': 'PT10M', 'defaultReward': 0.0, 'rewardAggregation': 'earliest', 'explorationPercentage': 0.2, 'modelExportFrequency': 'PT15S', 'logRetentionDays': 90, 'lastConfigurationEditDate': '2021-01-01T00:00:00', 'learningMode': 'Online'} + User count 4 + Coffee count 4 + ``` 1. The response code should be `` to indicate a successful call. The **rewardWaitTime** should show as 10 minutes and **modelExportFrequency** should be 15 seconds. @@ -352,7 +351,7 @@ Your code makes requests to the API. To get a good metric your requests, you can 1. Select **Metrics** under Monitoring in the navigation pane. - ![A screenshot of the metric chart.](../media/ai-personalizer/8-create-metric-chart.png) + ![A screenshot of the metric chart.](../media/ai-personalizer/8-create-metric-chart.png) 1. The **Scope** and **Metric** namespace are already set for you. You only need to select the **Metric** of **Successful calls** and the **Aggregation** of **Sum**. @@ -364,12 +363,12 @@ Next, you add code to generate a unique ID for each rank API call. You use this 1. To do this, create a new code cell in your notebook and add the following: - ```python - def add_event_id(rankjsonobj): - eventid = uuid.uuid4().hex - rankjsonobj["eventId"] = eventid - return eventid - ``` + ```python + def add_event_id(rankjsonobj): + eventid = uuid.uuid4().hex + rankjsonobj["eventId"] = eventid + return eventid + ``` 1. Remember to run your new code cell. @@ -385,14 +384,14 @@ Now can you add a function to: To do this, add the following code to a new cell and run it: - ```python - def add_random_user_and_contextfeatures(namesoption, weatheropt, timeofdayopt, rankjsonobj): - name = namesoption[random.randint(0,3)] - weather = weatheropt[random.randint(0,2)] - timeofday = timeofdayopt[random.randint(0,2)] - rankjsonobj['contextFeatures'] = [{'timeofday': timeofday, 'weather': weather, 'name': name}] - return [name, weather, timeofday] - ``` +```python +def add_random_user_and_contextfeatures(namesoption, weatheropt, timeofdayopt, rankjsonobj): + name = namesoption[random.randint(0,3)] + weather = weatheropt[random.randint(0,2)] + timeofday = timeofdayopt[random.randint(0,2)] + rankjsonobj['contextFeatures'] = [{'timeofday': timeofday, 'weather': weather, 'name': name}] + return [name, weather, timeofday] +``` ## Add coffee data @@ -411,18 +410,18 @@ You can then create a function to compare a user's preference for a particular c 1. To do this, create a new cell, add the following code, and run it: - ```python - def get_reward_from_simulated_data(name, weather, timeofday, prediction): - if(userpref[name][weather][timeofday] == str(prediction)): - return 1 - return 0 - ``` + ```python + def get_reward_from_simulated_data(name, weather, timeofday, prediction): + if(userpref[name][weather][timeofday] == str(prediction)): + return 1 + return 0 + ``` -1. This function is intended to run after every time the Rank API is called. If the suggestion matches, a score of `1` is returned in the response. If doesn't match, then `0` will be returned. +1. This function is intended to run after every time the Rank API is called. If the suggestion matches, a score of `1` is returned in the response. If doesn't match, then `0` will be returned. ## Create a loop with calls to the Rank and Reward APIs -The previous cells are used to set up your notebook for the loop. You'll now configure your loop. The loop covers the main body of work in your notebook. It gets a random user, gets the coffee list, and send them both to the Rank API. It compares the prediction from Azure AI Personalizer with that user's known perferences, and then sends the reward back again to Azure AI Personalizer. +The previous cells are used to set up your notebook for the loop. You'll now configure your loop. The loop covers the main body of work in your notebook. It gets a random user, gets the coffee list, and send them both to the Rank API. It compares the prediction from Azure AI Personalizer with that user's known perferences, and then sends the reward back again to Azure AI Personalizer. To create your loop, add the following code to a new cell and run it: @@ -556,7 +555,7 @@ Each loop iteration will display the randomly selected user, weather, and time o 1 Alice Rainy Morning Latte 1 ``` -A reward of `1` means your Azure AI Personalizer resource has selected the correct coffee type for this particular combination of user, weather, and time of day. +A reward of `1` means your Azure AI Personalizer resource has selected the correct coffee type for this particular combination of user, weather, and time of day. ## Run the loop and view chart results @@ -564,41 +563,41 @@ Azure AI Personalizer needs a few thousand calls to the Rank API and the Reward 1. To do this, create a new code cell, add the following code and run it: - ```python - # max iterations - num_requests = 150 - - # check last mod date N% of time - currently 10% - lastModCheck = int(num_requests * .10) - - jsonTemplate = rankactionsjsonobj - - # main iterations - [count, rewards] = iterations(num_requests, lastModCheck, jsonTemplate) - ``` + ```python + # max iterations + num_requests = 150 + + # check last mod date N% of time - currently 10% + lastModCheck = int(num_requests * .10) + + jsonTemplate = rankactionsjsonobj + + # main iterations + [count, rewards] = iterations(num_requests, lastModCheck, jsonTemplate) + ``` 1. Refresh your metrics chart in the Azure portal every so often to see the total calls to the service. 1. This event can run for a while. Don't close your notebook until it has finished. When the loop as made around 20,000 calls - a rank and reward call for each iteration of the loop - the loop will finish. 1. Next, you create a chart in your notebook to plot the batches of rank events, and how many correct recommendations were made for each batch. To do this, add the following code in a new cell and run it: - ```python - def createChart(x, y): - plt.plot(x, y) - plt.xlabel("Batch of rank events") - plt.ylabel("Correct recommendations per batch") - plt.show() + ```python + def createChart(x, y): + plt.plot(x, y) + plt.xlabel("Batch of rank events") + plt.ylabel("Correct recommendations per batch") + plt.show() - createChart(count,rewards) - ``` + createChart(count,rewards) + ``` 1. Your notebook will create a chart: - ![A screenshot of the chart.](../media/ai-personalizer/7-chart2.png) + ![A screenshot of the chart.](../media/ai-personalizer/7-chart2.png) > **Tip:** Ideally, once testing has finished, your loop should on average make correct recommendations at a rate of 100 percent minus the exploration value (which is 20% by default), so 80% is your target rate here. A way to get to this is to increase the iterations to at least 10,000. -The chart displays how successful your model is based on the default learning policy. This chart shows that the learning policy can be improved. You can do this by changing the policy after running evaluations. +The chart displays how successful your model is based on the default learning policy. This chart shows that the learning policy can be improved. You can do this by changing the policy after running evaluations. ## Run an offline evaluation @@ -610,18 +609,20 @@ You can run an offline evaluation to find a better learning policy for an Azure 1. In the Azure portal, go to your Azure AI Personalizer resource's Optimize pane and select **Create evaluation**. 1. Provide an evaluation name, and select a start and end date range for your loop evaluation. Your date range should include only the days you are focusing on for your evaluation: - ![A screenshot showing the evaluation form.](../media/ai-personalizer/7-evaluation-form.png) + ![A screenshot showing the evaluation form.](../media/ai-personalizer/7-evaluation-form.png) + 1. Select **Start evaluation** to begin your evaluation. 1. When your evaluation has completed, select it from the list of evaluations on the Optimize pane. Then review the performance of your learning policies based on details like their average reward, confidence intervals, and more: - ![A screenshot showing evaluation results.](../media/ai-personalizer/7-offline-eval-result.png) + ![A screenshot showing evaluation results.](../media/ai-personalizer/7-offline-eval-result.png) + 1. You'll see a few policies including: - - **Online** - Your Azure AI Personalizer's current policy. - - **Baseline1** - Your app's baseline policy - - **BaselineRand** - A policy of taking actions at random. - - **Inter-len#** or **Hyper#** - Policies created by Optimization discovery. + - **Online** - Your Azure AI Personalizer's current policy. + - **Baseline1** - Your app's baseline policy + - **BaselineRand** - A policy of taking actions at random. + - **Inter-len#** or **Hyper#** - Policies created by Optimization discovery. 1. Select **Apply** on the policy that improves the model best. @@ -632,4 +633,3 @@ If you're not using the Azure resources created in this lab for other training m 1. Open the Azure portal at `https://portal.azure.com`, and in the top search bar, search for the resources you created in this lab. 2. On the resource page, select **Delete** and follow the instructions to delete the resource. Alternatively, you can delete the entire resource group to clean up all resources at the same time. - diff --git a/Instructions/Labs/05-personalizer-exercise.md b/Instructions/Labs/05-personalizer-exercise.md index caaf66d3..e58bcd57 100644 --- a/Instructions/Labs/05-personalizer-exercise.md +++ b/Instructions/Labs/05-personalizer-exercise.md @@ -1,6 +1,6 @@ --- lab: - title: 'Use AI Personalizer with Visual Studio Code Notebooks to simulate a loop' + title: "Use AI Personalizer with Visual Studio Code Notebooks to simulate a loop" --- > **Note** @@ -12,27 +12,28 @@ In this exercise, you'll use Azure AI Personalizer with notebooks in Visual Stud 1. In the Azure portal, search for **Azure AI services**. Then select **Create** under **Personalizer** in the results list. - ![A screenshot of the Azure portal showing how to create an Azure AI Personalizer resource](../media/ai-personalizer/create-personalizer-portal.png) + ![A screenshot of the Azure portal showing how to create an Azure AI Personalizer resource](../media/ai-personalizer/create-personalizer-portal.png) 1. Select your subscription, enter a resource group name, and name for your resource. For pricing tier, choose **Free F0**. 1. Select **Review + create** to review your choices, then select **Create** create your resource. 1. Go to your newly created Azure AI Personalizer resource, then in the Keys and Endpoint pane, copy and paste the **Key** and **Endpoint** somewhere safe for use later: - ![A screenshot showing the Key and Endpoint pane.](../media/ai-personalizer/copy-key-endpoint.png) + ![A screenshot showing the Key and Endpoint pane.](../media/ai-personalizer/copy-key-endpoint.png) 1. Select Setup in the navigation pane, and then set the **Reward wait time** to **10 minutes** (if not already set), and set the **Model update frequency** to **15 seconds**. 1. Select **Save**. ## Set up notebook -1. In your Visual Studio Code editor, press **Ctrl+Shift+P** and select **Create new Jupyter notebook**. +1. In your Visual Studio Code editor, press **Ctrl+Shift+P** and select **Create: New Jupyter Notebook**. 1. Save the file and name it **my-notebook** on your device. 1. Now you need to install the required extensions. Select **Select Kernel** in the top right of the notebook. Then select **Install/Enable suggested extensions**. - ![A screenshot showing how to install the extensions.](../media/ai-personalizer/8-install-enable-extensions-code.png) + ![A screenshot showing how to install the extensions.](../media/ai-personalizer/8-install-enable-extensions-code.png) + + > [!NOTE] + > If you've already done this before, you won't see this option and can skip this step. - > [!NOTE] - > If you've already done this before, you won't see this option and can skip this step. 1. Wait for the extensions to be installed, then select **Python environments...** in the dropdown that appears. 1. Then select the top recommended environment. @@ -42,173 +43,170 @@ For the purpose of this exercise, we'll create a list of users and a list coffee 1. Copy the following JSON code into an empty file and save that file as `users.json` in the same folder as your notebook file. - ```json - { - "Alice": { - "Sunny": { - "Morning": "Cold brew", - "Afternoon": "Iced mocha", - "Evening": "Cold brew" - }, - "Rainy": { - "Morning": "Latte", - "Afternoon": "Cappucino", - "Evening": "Latte" - }, - "Snowy": { - "Morning": "Cappucino", - "Afternoon": "Cappucino", - "Evening": "Cappucino" - } - }, - "Bob": { - "Sunny": { - "Morning": "Cappucino", - "Afternoon": "Iced mocha", - "Evening": "Cold brew" - }, - "Rainy": { - "Morning": "Latte", - "Afternoon": "Latte", - "Evening": "Latte" - }, - "Snowy": { - "Morning": "Iced mocha", - "Afternoon": "Iced mocha", - "Evening": "Iced mocha" - } - }, - "Cathy": { - "Sunny": { - "Morning": "Latte", - "Afternoon": "Cold brew", - "Evening": "Cappucino" - }, - "Rainy": { - "Morning": "Cappucino", - "Afternoon": "Latte", - "Evening": "Iced mocha" - }, - "Snowy": { - "Morning": "Cold brew", - "Afternoon": "Iced mocha", - "Evening": "Cappucino" - } - }, - "Dave": { - "Sunny": { - "Morning": "Iced mocha", - "Afternoon": "Iced mocha", - "Evening": "Iced mocha" - }, - "Rainy": { - "Morning": "Latte", - "Afternoon": "Latte", - "Evening": "Latte" - }, - "Snowy": { - "Morning": "Cappucino", - "Afternoon": "Cappucino", - "Evening": "Cappucino" - } - } - } - ``` + ```json + { + "Alice": { + "Sunny": { + "Morning": "Cold brew", + "Afternoon": "Iced mocha", + "Evening": "Cold brew" + }, + "Rainy": { + "Morning": "Latte", + "Afternoon": "Cappucino", + "Evening": "Latte" + }, + "Snowy": { + "Morning": "Cappucino", + "Afternoon": "Cappucino", + "Evening": "Cappucino" + } + }, + "Bob": { + "Sunny": { + "Morning": "Cappucino", + "Afternoon": "Iced mocha", + "Evening": "Cold brew" + }, + "Rainy": { + "Morning": "Latte", + "Afternoon": "Latte", + "Evening": "Latte" + }, + "Snowy": { + "Morning": "Iced mocha", + "Afternoon": "Iced mocha", + "Evening": "Iced mocha" + } + }, + "Cathy": { + "Sunny": { + "Morning": "Latte", + "Afternoon": "Cold brew", + "Evening": "Cappucino" + }, + "Rainy": { + "Morning": "Cappucino", + "Afternoon": "Latte", + "Evening": "Iced mocha" + }, + "Snowy": { + "Morning": "Cold brew", + "Afternoon": "Iced mocha", + "Evening": "Cappucino" + } + }, + "Dave": { + "Sunny": { + "Morning": "Iced mocha", + "Afternoon": "Iced mocha", + "Evening": "Iced mocha" + }, + "Rainy": { + "Morning": "Latte", + "Afternoon": "Latte", + "Evening": "Latte" + }, + "Snowy": { + "Morning": "Cappucino", + "Afternoon": "Cappucino", + "Evening": "Cappucino" + } + } + } + ``` 1. Next, copy the following code and save it to a file called `coffee.json`: - ```json - [ - { - "id": "Cappucino", - "features": [ - { - "type": "hot", - "origin": "kenya", - "organic": "yes", - "roast": "dark" - - } - ] - }, - { - "id": "Cold brew", - "features": [ - { - "type": "cold", - "origin": "brazil", - "organic": "yes", - "roast": "light" - } - ] - }, - { - "id": "Iced mocha", - "features": [ - { - "type": "cold", - "origin": "ethiopia", - "organic": "no", - "roast": "light" - } - ] - }, - { - "id": "Latte", - "features": [ - { - "type": "hot", - "origin": "brazil", - "organic": "no", - "roast": "dark" - } - ] - } - ] - ``` + ```json + [ + { + "id": "Cappucino", + "features": [ + { + "type": "hot", + "origin": "kenya", + "organic": "yes", + "roast": "dark" + } + ] + }, + { + "id": "Cold brew", + "features": [ + { + "type": "cold", + "origin": "brazil", + "organic": "yes", + "roast": "light" + } + ] + }, + { + "id": "Iced mocha", + "features": [ + { + "type": "cold", + "origin": "ethiopia", + "organic": "no", + "roast": "light" + } + ] + }, + { + "id": "Latte", + "features": [ + { + "type": "hot", + "origin": "brazil", + "organic": "no", + "roast": "dark" + } + ] + } + ] + ``` 1. Copy and paste the following code into a file and save it as `example-rankrequest.json`: - - ```json - { - "contextFeatures": [ - ], - "actions": [ - ], - "excludedActions": [ - ], - "eventId": "", - "deferActivation": false - } - ``` + + ```json + { + "contextFeatures": [], + "actions": [], + "excludedActions": [], + "eventId": "", + "deferActivation": false + } + ``` ## Set your endpoint and key 1. At the top of your notebook, add the following code to include the required modules: - ```python - import json - import matplotlib.pyplot as plt - import random - import requests - import time - import uuid - import datetime - ``` + ```python + import json + import matplotlib.pyplot as plt + import random + import requests + import time + import uuid + import datetime + ``` 1. Select the cell, then select the run button to the left of the cell: - ![A screenshot showing the run button.](../media/ai-personalizer/8-press-run.png) - > [!NOTE] - > Make to you select the run button each time you populate a new cell. If you're prompted to install the ipykernel package, select **Install**. + ![A screenshot showing the run button.](../media/ai-personalizer/8-press-run.png) + + > [!NOTE] + > Make to you select the run button each time you populate a new cell. If you're prompted to install the ipykernel package, select **Install**. 1. Select **+ Code** at the top of your notebook to create a new code cell. Then add the following code: - ```python - # Replace 'personalization_base_url' and 'resource_key' with your valid endpoint values. - personalization_base_url = "" - resource_key = "" - ``` + ```python + # Replace 'personalization_base_url' and 'resource_key' with your valid endpoint values. + personalization_base_url = "" + resource_key = "" + ``` 1. Replace **personalization_base_url** value with your copied endpoint, and **resource_key** value with your key. @@ -216,32 +214,32 @@ For the purpose of this exercise, we'll create a list of users and a list coffee 1. Next, you create the code helps to take note of start and end times of iterative functions you will use later. Add the following code to a new cell: - ```python - # Print out current datetime - def currentDateTime(): - currentDT = datetime.datetime.now() - print (str(currentDT)) - - # ititialize variable for model's last modified date - modelLastModified = "" - - def get_last_updated(currentModifiedDate): - - print('-----checking model') - - # get model properties - response = requests.get(personalization_model_properties_url, headers = headers, params = None) - - print(response) - print(response.json()) - - # get lastModifiedTime - lastModifiedTime = json.dumps(response.json()["lastModifiedTime"]) - - if (currentModifiedDate != lastModifiedTime): - currentModifiedDate = lastModifiedTime - print(f'-----model updated: {lastModifiedTime}') - ``` + ```python + # Print out current datetime + def currentDateTime(): + currentDT = datetime.datetime.now() + print (str(currentDT)) + + # ititialize variable for model's last modified date + modelLastModified = "" + + def get_last_updated(currentModifiedDate): + + print('-----checking model') + + # get model properties + response = requests.get(personalization_model_properties_url, headers = headers, params = None) + + print(response) + print(response.json()) + + # get lastModifiedTime + lastModifiedTime = json.dumps(response.json()["lastModifiedTime"]) + + if (currentModifiedDate != lastModifiedTime): + currentModifiedDate = lastModifiedTime + print(f'-----model updated: {lastModifiedTime}') + ``` 1. Don't forget to run your new cell once you've added your new code. @@ -249,23 +247,23 @@ For the purpose of this exercise, we'll create a list of users and a list coffee 1. Next, you'll need to validate the service state by getting the policy and service configuration. To do this, add the following code to a new cell: - ```python - def get_service_settings(): - - print('-----checking service settings') - - # get learning policy - response = requests.get(personalization_model_policy_url, headers = headers, params = None) - - print(response) - print(response.json()) - - # get service settings - response = requests.get(personalization_service_configuration_url, headers = headers, params = None) - - print(response) - print(response.json()) - ``` + ```python + def get_service_settings(): + + print('-----checking service settings') + + # get learning policy + response = requests.get(personalization_model_policy_url, headers = headers, params = None) + + print(response) + print(response.json()) + + # get service settings + response = requests.get(personalization_service_configuration_url, headers = headers, params = None) + + print(response) + print(response.json()) + ``` 1. Make sure to run your new code cell. @@ -284,63 +282,63 @@ Now you'll add code to: 1. To do this, add the following code to a new cell and run it: - ```python - # build URLs - personalization_rank_url = personalization_base_url + "personalizer/v1.0/rank" - personalization_reward_url = personalization_base_url + "personalizer/v1.0/events/" #add "{eventId}/reward" - personalization_model_properties_url = personalization_base_url + "personalizer/v1.0/model/properties" - personalization_model_policy_url = personalization_base_url + "personalizer/v1.0/configurations/policy" - personalization_service_configuration_url = personalization_base_url + "personalizer/v1.0/configurations/service" - - headers = {'Ocp-Apim-Subscription-Key' : resource_key, 'Content-Type': 'application/json'} - - # context - users = "users.json" - - # action features - coffee = "coffee.json" - - # empty JSON for Rank request - requestpath = "example-rankrequest.json" - - # initialize random - random.seed(time.time()) - - userpref = None - rankactionsjsonobj = None - actionfeaturesobj = None - - with open(users) as handle: - userpref = json.loads(handle.read()) - - with open(coffee) as handle: - actionfeaturesobj = json.loads(handle.read()) - - with open(requestpath) as handle: - rankactionsjsonobj = json.loads(handle.read()) - - get_last_updated(modelLastModified) - get_service_settings() - - print(f'User count {len(userpref)}') - print(f'Coffee count {len(actionfeaturesobj)}') - ``` + ```python + # build URLs + personalization_rank_url = personalization_base_url + "personalizer/v1.0/rank" + personalization_reward_url = personalization_base_url + "personalizer/v1.0/events/" #add "{eventId}/reward" + personalization_model_properties_url = personalization_base_url + "personalizer/v1.0/model/properties" + personalization_model_policy_url = personalization_base_url + "personalizer/v1.0/configurations/policy" + personalization_service_configuration_url = personalization_base_url + "personalizer/v1.0/configurations/service" + + headers = {'Ocp-Apim-Subscription-Key' : resource_key, 'Content-Type': 'application/json'} + + # context + users = "users.json" + + # action features + coffee = "coffee.json" + + # empty JSON for Rank request + requestpath = "example-rankrequest.json" + + # initialize random + random.seed(time.time()) + + userpref = None + rankactionsjsonobj = None + actionfeaturesobj = None + + with open(users) as handle: + userpref = json.loads(handle.read()) + + with open(coffee) as handle: + actionfeaturesobj = json.loads(handle.read()) + + with open(requestpath) as handle: + rankactionsjsonobj = json.loads(handle.read()) + + get_last_updated(modelLastModified) + get_service_settings() + + print(f'User count {len(userpref)}') + print(f'Coffee count {len(actionfeaturesobj)}') + ``` 1. The call should return a response similar to the following: - ```bash - -----checking model - - {'creationTime': '2023-09-22T14:58:45+00:00', 'lastModifiedTime': '2023-09-22T14:58:45+00:00'} - -----model updated: "2023-09-22T14:58:45+00:00" - -----checking service settings - - {'name': '917554355a3347a1af3d2935d521426a', 'arguments': '--cb_explore_adf --epsilon 0.20000000298023224 --power_t 0 -l 0.001 --cb_type mtr -q ::'} - - {'rewardWaitTime': 'PT10M', 'defaultReward': 0.0, 'rewardAggregation': 'earliest', 'explorationPercentage': 0.2, 'modelExportFrequency': 'PT15S', 'logRetentionDays': 90, 'lastConfigurationEditDate': '2021-01-01T00:00:00', 'learningMode': 'Online'} - User count 4 - Coffee count 4 - ``` + ```bash + -----checking model + + {'creationTime': '2023-09-22T14:58:45+00:00', 'lastModifiedTime': '2023-09-22T14:58:45+00:00'} + -----model updated: "2023-09-22T14:58:45+00:00" + -----checking service settings + + {'name': '917554355a3347a1af3d2935d521426a', 'arguments': '--cb_explore_adf --epsilon 0.20000000298023224 --power_t 0 -l 0.001 --cb_type mtr -q ::'} + + {'rewardWaitTime': 'PT10M', 'defaultReward': 0.0, 'rewardAggregation': 'earliest', 'explorationPercentage': 0.2, 'modelExportFrequency': 'PT15S', 'logRetentionDays': 90, 'lastConfigurationEditDate': '2021-01-01T00:00:00', 'learningMode': 'Online'} + User count 4 + Coffee count 4 + ``` 1. The response code should be `` to indicate a successful call. The **rewardWaitTime** should show as 10 minutes and **modelExportFrequency** should be 15 seconds. @@ -352,7 +350,7 @@ Your code makes requests to the API. To get a good metric your requests, you can 1. Select **Metrics** under Monitoring in the navigation pane. - ![A screenshot of the metric chart.](../media/ai-personalizer/8-create-metric-chart.png) + ![A screenshot of the metric chart.](../media/ai-personalizer/8-create-metric-chart.png) 1. The **Scope** and **Metric** namespace are already set for you. You only need to select the **Metric** of **Successful calls** and the **Aggregation** of **Sum**. @@ -364,12 +362,12 @@ Next, you add code to generate a unique ID for each rank API call. You use this 1. To do this, create a new code cell in your notebook and add the following: - ```python - def add_event_id(rankjsonobj): - eventid = uuid.uuid4().hex - rankjsonobj["eventId"] = eventid - return eventid - ``` + ```python + def add_event_id(rankjsonobj): + eventid = uuid.uuid4().hex + rankjsonobj["eventId"] = eventid + return eventid + ``` 1. Remember to run your new code cell. @@ -385,14 +383,14 @@ Now can you add a function to: To do this, add the following code to a new cell and run it: - ```python - def add_random_user_and_contextfeatures(namesoption, weatheropt, timeofdayopt, rankjsonobj): - name = namesoption[random.randint(0,3)] - weather = weatheropt[random.randint(0,2)] - timeofday = timeofdayopt[random.randint(0,2)] - rankjsonobj['contextFeatures'] = [{'timeofday': timeofday, 'weather': weather, 'name': name}] - return [name, weather, timeofday] - ``` +```python +def add_random_user_and_contextfeatures(namesoption, weatheropt, timeofdayopt, rankjsonobj): + name = namesoption[random.randint(0,3)] + weather = weatheropt[random.randint(0,2)] + timeofday = timeofdayopt[random.randint(0,2)] + rankjsonobj['contextFeatures'] = [{'timeofday': timeofday, 'weather': weather, 'name': name}] + return [name, weather, timeofday] +``` ## Add coffee data @@ -411,18 +409,18 @@ You can then create a function to compare a user's preference for a particular c 1. To do this, create a new cell, add the following code, and run it: - ```python - def get_reward_from_simulated_data(name, weather, timeofday, prediction): - if(userpref[name][weather][timeofday] == str(prediction)): - return 1 - return 0 - ``` + ```python + def get_reward_from_simulated_data(name, weather, timeofday, prediction): + if(userpref[name][weather][timeofday] == str(prediction)): + return 1 + return 0 + ``` -1. This function is intended to run after every time the Rank API is called. If the suggestion matches, a score of `1` is returned in the response. If doesn't match, then `0` will be returned. +1. This function is intended to run after every time the Rank API is called. If the suggestion matches, a score of `1` is returned in the response. If doesn't match, then `0` will be returned. ## Create a loop with calls to the Rank and Reward APIs -The previous cells are used to set up your notebook for the loop. You'll now configure your loop. The loop covers the main body of work in your notebook. It gets a random user, gets the coffee list, and send them both to the Rank API. It compares the prediction from Azure AI Personalizer with that user's known perferences, and then sends the reward back again to Azure AI Personalizer. +The previous cells are used to set up your notebook for the loop. You'll now configure your loop. The loop covers the main body of work in your notebook. It gets a random user, gets the coffee list, and send them both to the Rank API. It compares the prediction from Azure AI Personalizer with that user's known perferences, and then sends the reward back again to Azure AI Personalizer. To create your loop, add the following code to a new cell and run it: @@ -556,7 +554,7 @@ Each loop iteration will display the randomly selected user, weather, and time o 1 Alice Rainy Morning Latte 1 ``` -A reward of `1` means your Azure AI Personalizer resource has selected the correct coffee type for this particular combination of user, weather, and time of day. +A reward of `1` means your Azure AI Personalizer resource has selected the correct coffee type for this particular combination of user, weather, and time of day. ## Run the loop and view chart results @@ -564,42 +562,42 @@ Azure AI Personalizer needs a few thousand calls to the Rank API and the Reward 1. To do this, create a new code cell, add the following code and run it: - ```python - # max iterations - num_requests = 150 - - # check last mod date N% of time - currently 10% - lastModCheck = int(num_requests * .10) - - jsonTemplate = rankactionsjsonobj - - # main iterations - [count, rewards] = iterations(num_requests, lastModCheck, jsonTemplate) - ``` + ```python + # max iterations + num_requests = 150 + + # check last mod date N% of time - currently 10% + lastModCheck = int(num_requests * .10) + + jsonTemplate = rankactionsjsonobj + + # main iterations + [count, rewards] = iterations(num_requests, lastModCheck, jsonTemplate) + ``` 1. Refresh your metrics chart in the Azure portal every so often to see the total calls to the service. 1. This event can run for a while. Don't close your notebook until it has finished. When the loop as made around 20,000 calls - a rank and reward call for each iteration of the loop - the loop will finish. 1. Next, you create a chart in your notebook to plot the batches of rank events, and how many correct recommendations were made for each batch. To do this, add the following code in a new cell and run it: - ```python - def createChart(x, y): - plt.plot(x, y) - plt.xlabel("Batch of rank events") - plt.ylabel("Correct recommendations per batch") - plt.show() + ```python + def createChart(x, y): + plt.plot(x, y) + plt.xlabel("Batch of rank events") + plt.ylabel("Correct recommendations per batch") + plt.show() - createChart(count,rewards) - ``` + createChart(count,rewards) + ``` 1. Your notebook will create a chart: - ![A screenshot of the chart.](../media/ai-personalizer/7-chart2.png) + ![A screenshot of the chart.](../media/ai-personalizer/7-chart2.png) > [!TIP] > Ideally, once testing has finished, your loop should on average make correct recommendations at a rate of 100 percent minus the exploration value (which is 20% by default), so 80% is your target rate here. A way to get to this is to increase the iterations to at least 10,000. -The chart displays how successful your model is based on the default learning policy. This chart shows that the learning policy can be improved. You can do this by changing the policy after running evaluations. +The chart displays how successful your model is based on the default learning policy. This chart shows that the learning policy can be improved. You can do this by changing the policy after running evaluations. ## Run an offline evaluation @@ -611,17 +609,19 @@ You can run an offline evaluation to find a better learning policy for an Azure 1. In the Azure portal, go to your Azure AI Personalizer resource's Optimize pane and select **Create evaluation**. 1. Provide an evaluation name, and select a start and end date range for your loop evaluation. Your date range should include only the days you are focusing on for your evaluation: - ![A screenshot showing the evaluation form.](../media/ai-personalizer/7-evaluation-form.png) + ![A screenshot showing the evaluation form.](../media/ai-personalizer/7-evaluation-form.png) + 1. Select **Start evaluation** to begin your evaluation. 1. When your evaluation has completed, select it from the list of evaluations on the Optimize pane. Then review the performance of your learning policies based on details like their average reward, confidence intervals, and more: - ![A screenshot showing evaluation results.](../media/ai-personalizer/7-offline-eval-result.png) + ![A screenshot showing evaluation results.](../media/ai-personalizer/7-offline-eval-result.png) + 1. You'll see a few policies including: - - **Online** - Your Azure AI Personalizer's current policy. - - **Baseline1** - Your app's baseline policy - - **BaselineRand** - A policy of taking actions at random. - - **Inter-len#** or **Hyper#** - Policies created by Optimization discovery. + - **Online** - Your Azure AI Personalizer's current policy. + - **Baseline1** - Your app's baseline policy + - **BaselineRand** - A policy of taking actions at random. + - **Inter-len#** or **Hyper#** - Policies created by Optimization discovery. -1. Select **Apply** on the policy that improves the model best. \ No newline at end of file +1. Select **Apply** on the policy that improves the model best. From 377203a0f0bd1cbec4e0e9477cbc8a05c8a149f0 Mon Sep 17 00:00:00 2001 From: 6cpsmidnight Date: Tue, 28 Nov 2023 00:05:33 -0500 Subject: [PATCH 4/4] Resolved Command Typo For 05 (#15) --- Instructions/Exercises/05-personalizer-exercise.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Instructions/Exercises/05-personalizer-exercise.md b/Instructions/Exercises/05-personalizer-exercise.md index 0d82b9a2..e7638e8e 100644 --- a/Instructions/Exercises/05-personalizer-exercise.md +++ b/Instructions/Exercises/05-personalizer-exercise.md @@ -25,7 +25,6 @@ In this exercise, you'll use Azure AI Personalizer with notebooks in Visual Stud ## Set up notebook -1. In your Visual Studio Code editor, press **Ctrl+Shift+P** and select **Create new Jupyter notebook**. 1. In your Visual Studio Code editor, press **Ctrl+Shift+P** and select **Create: New Jupyter Notebook**. 1. Save the file and name it **my-notebook** on your device. 1. Now you need to install the required extensions. Select **Select Kernel** in the top right of the notebook. Then select **Install/Enable suggested extensions**.