Share via


Tutorial: Usar o Personalizador no Bloco de Anotações do Azure

Importante

A partir de 20 de setembro de 2023, você não poderá criar novos recursos do Personalizador. O serviço de Personalizador será aposentado no dia 1º de outubro de 2026.

Este tutorial executa um loop do Personalizador em um Bloco de Anotações do Azure, demonstrando o ciclo de vida de ponta a ponta de um loop do Personalizador.

O loop sugere que tipo de café um cliente deve pedir. Os usuários e suas preferências são armazenados em um conjunto de dados do usuário. As informações sobre o café são armazenadas em um conjunto de dados de café.

Utilizadores e café

O notebook, simulando a interação do usuário com um site, seleciona um usuário aleatório, hora do dia e tipo de clima do conjunto de dados. Um resumo das informações do usuário é:

Clientes - recursos de contexto Horários do dia Tipos de clima
Estrela
Fernando
Cathy
Diogo
Manhã
Tarde
Início da noite
Ensolarado
Chuvoso
Nevado

Para ajudar o Personalizador a aprender, ao longo do tempo, o sistema também sabe detalhes sobre a seleção de café para cada pessoa.

Café - recursos de ação Tipos de temperatura Locais de origem Tipos de assado Orgânico
Cappacino Muito Interessado Quénia Escuro Orgânico
Cerveja gelada Sem Interesse Brasil Leve Orgânico
Mocha gelado Sem Interesse Etiópia Leve Não orgânico
Latte Muito Interessado Brasil Escuro Não orgânico

O objetivo do ciclo do Personalizador é encontrar a melhor combinação entre os usuários e o café o máximo de tempo possível.

O código para este tutorial está disponível no repositório GitHub de amostras do personalizador.

Como funciona a simulação

No início do sistema em execução, as sugestões do Personalizer só são bem-sucedidas entre 20% a 30%. Este sucesso é indicado pela recompensa enviada de volta para a API de Recompensa do Personalizador, com uma pontuação de 1. Depois de algumas chamadas de Rank e Reward, o sistema melhora.

Após as solicitações iniciais, execute uma avaliação offline. Isso permite que o Personalizer analise os dados e sugira uma política de aprendizagem melhor. Aplique a nova política de aprendizagem e execute o bloco de anotações novamente com 20% da contagem de solicitações anteriores. O ciclo terá um melhor desempenho com a nova política de aprendizagem.

Classificação e recompensa chamadas

Para cada uma das milhares de chamadas para o serviço Personalizador, o Bloco de Anotações do Azure envia a solicitação de Classificação para a API REST:

  • Um ID exclusivo para o evento Rank/Request
  • Recursos de contexto - Uma escolha aleatória do usuário, clima e hora do dia - simulando um usuário em um site ou dispositivo móvel
  • Ações com Recursos - Todos os dados do café - a partir dos quais o Personalizador faz uma sugestão

O sistema recebe a solicitação e, em seguida, compara essa previsão com a escolha conhecida do usuário para a mesma hora do dia e clima. Se a escolha conhecida for a mesma que a escolha prevista, a Recompensa de 1 é enviada de volta para o Personalizador. Caso contrário, a recompensa enviada de volta é 0.

Nota

Esta é uma simulação para que o algoritmo para a recompensa seja simples. Em um cenário do mundo real, o algoritmo deve usar a lógica de negócios, possivelmente com pesos para vários aspetos da experiência do cliente, para determinar a pontuação de recompensa.

Pré-requisitos

  • Uma conta do Bloco de Anotações do Azure.
  • Um recurso do Azure AI Personalizer.
    • Se você já tiver usado o recurso Personalizador, certifique-se de limpar os dados no portal do Azure para o recurso.
  • Carregue todos os arquivos deste exemplo em um projeto do Bloco de Anotações do Azure.

Descrições dos ficheiros:

Configurar recurso do Personalizer

No portal do Azure, configure seu recurso do Personalizador com a frequência do modelo de atualização definida como 15 segundos e um tempo de espera de recompensa de 10 minutos. Esses valores são encontrados na página Configuração.

Definição Valor
atualizar a frequência do modelo 15 segundos
tempo de espera de recompensa 10 minutos

Esses valores têm uma duração muito curta para mostrar as alterações neste tutorial. Esses valores não devem ser usados em um cenário de produção sem validar que eles atingem seu objetivo com seu loop do Personalizador.

Configurar o Bloco de Anotações do Azure

  1. Altere o kernel para Python 3.6.
  2. Abra o ficheiro Personalizer.ipynb.

Executar células do Bloco de Anotações

Execute cada célula executável e aguarde até que ela retorne. Você sabe que isso é feito quando os colchetes ao lado da célula exibem um número em vez de um *arquivo . As seções a seguir explicam o que cada célula faz programaticamente e o que esperar para a saída.

Incluir os módulos Python

Inclua os módulos Python necessários. A célula não tem saída.

import json
import matplotlib.pyplot as plt
import random
import requests
import time
import uuid

Definir a chave de recurso e o nome do Personalizador

No portal do Azure, localize sua chave e ponto de extremidade na página Início rápido do seu recurso Personalizador. Altere o valor de para o nome do recurso do <your-resource-name> Personalizador. Altere o valor de para a sua chave Personalizador <your-resource-key> .

# Replace 'personalization_base_url' and 'resource_key' with your valid endpoint values.
personalization_base_url = "https://<your-resource-name>.cognitiveservices.azure.com/"
resource_key = "<your-resource-key>"

Use esta função para anotar as horas de início e término da função iterativa, iterações.

Estas células não têm saída. A função produz a data e hora atuais quando chamada.

# Print out current datetime
def currentDateTime():
    currentDT = datetime.datetime.now()
    print (str(currentDT))

Obter a hora da última atualização do modelo

Quando a função, , é chamada, get_last_updateda função imprime a data e a hora da última modificação em que o modelo foi atualizado.

Estas células não têm saída. A função produz a última data de treinamento do modelo quando chamada.

A função usa uma API GET REST para obter propriedades do modelo.

# 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}')

Obter configuração de política e serviço

Valide o estado do serviço com essas duas chamadas REST.

Estas células não têm saída. A função produz os valores de serviço quando chamada.

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())

Construa URLs e leia arquivos de dados JSON

Esta célula

  • cria as URLs usadas em chamadas REST
  • define o cabeçalho de segurança usando sua chave de recurso do Personalizer
  • define a semente aleatória para o ID do evento Rank
  • leituras nos arquivos de dados JSON
  • Método de chamadas - A política de aprendizagem foi removida no exemplo de get_last_updated saída
  • Método de chamadas get_service_settings

A célula tem saída da chamada para get_last_updated e get_service_settings funções.

# 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)}')

Verifique se a saída rewardWaitTime está definida como 10 minutos e modelExportFrequency se está definida como 15 segundos.

-----checking model
<Response [200]>
{'creationTime': '0001-01-01T00:00:00+00:00', 'lastModifiedTime': '0001-01-01T00:00:00+00:00'}
-----model updated: "0001-01-01T00:00:00+00:00"
-----checking service settings
<Response [200]>
{...learning policy...}
<Response [200]>
{'rewardWaitTime': '00:10:00', 'defaultReward': 0.0, 'rewardAggregation': 'earliest', 'explorationPercentage': 0.2, 'modelExportFrequency': '00:00:15', 'logRetentionDays': -1}
User count 4
Coffee count 4

Solução de problemas da primeira chamada REST

Esta célula anterior é a primeira célula que chama o Personalizador. Verifique se o código de status REST na saída é <Response [200]>. Se você receber um erro, como 404, mas tiver certeza de que a chave de recurso e o nome estão corretos, recarregue o bloco de anotações.

Certifique-se de que a contagem de café e usuários é ambos 4. Se você receber um erro, verifique se você carregou todos os 3 arquivos JSON.

Configurar gráfico de métricas no portal do Azure

Mais adiante neste tutorial, o longo processo de execução de 10.000 solicitações é visível a partir do navegador com uma caixa de texto de atualização. Pode ser mais fácil de ver em um gráfico ou como uma soma total, quando o processo de longa duração termina. Para exibir essas informações, use as métricas fornecidas com o recurso. Você pode criar o gráfico agora que concluiu uma solicitação para o serviço e, em seguida, atualizá-lo periodicamente enquanto o processo de longa duração está em andamento.

  1. No portal do Azure, selecione seu recurso Personalizador.

  2. Na navegação de recursos, selecione Métricas abaixo de Monitoramento.

  3. No gráfico, selecione Adicionar métrica.

  4. O namespace de recurso e métrica já está definido. Você só precisa selecionar a métrica de chamadas bem-sucedidas e a agregação de soma.

  5. Altere o filtro de tempo para as últimas 4 horas.

    Set up metric chart in Azure portal, adding metric for successful calls for the last 4 hours.

    Você verá três chamadas bem-sucedidas no gráfico.

Gerar um ID de evento exclusivo

Esta função gera um ID exclusivo para cada chamada de classificação. O ID é usado para identificar as informações de classificação e chamada de recompensa. Esse valor pode vir de um processo comercial, como um ID de visualização da Web ou um ID de transação.

A célula não tem saída. A função produz o ID exclusivo quando chamada.

def add_event_id(rankjsonobj):
    eventid = uuid.uuid4().hex
    rankjsonobj["eventId"] = eventid
    return eventid

Obter usuário aleatório, clima e hora do dia

Essa função seleciona um usuário exclusivo, clima e hora do dia e, em seguida, adiciona esses itens ao objeto JSON para enviar à solicitação Rank.

A célula não tem saída. Quando a função é chamada, ela retorna o nome do usuário aleatório, clima aleatório e hora aleatória do dia.

A lista de 4 usuários e suas preferências - apenas algumas preferências são mostradas para brevidade:

{
  "Alice": {
    "Sunny": {
      "Morning": "Cold brew",
      "Afternoon": "Iced mocha",
      "Evening": "Cold brew"
    }...
  },
  "Bob": {
    "Sunny": {
      "Morning": "Cappucino",
      "Afternoon": "Iced mocha",
      "Evening": "Cold brew"
    }...
  },
  "Cathy": {
    "Sunny": {
      "Morning": "Latte",
      "Afternoon": "Cold brew",
      "Evening": "Cappucino"
    }...
  },
  "Dave": {
    "Sunny": {
      "Morning": "Iced mocha",
      "Afternoon": "Iced mocha",
      "Evening": "Iced mocha"
    }...
  }
}
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]

Adicionar todos os dados do café

Esta função adiciona toda a lista de café ao objeto JSON para enviar à solicitação Rank.

A célula não tem saída. A função muda o rankjsonobj quando chamado.

O exemplo das características de um único café é:

{
    "id": "Cappucino",
    "features": [
    {
        "type": "hot",
        "origin": "kenya",
        "organic": "yes",
        "roast": "dark"

    }
}
def add_action_features(rankjsonobj):
    rankjsonobj["actions"] = actionfeaturesobj

Compare a previsão com a preferência conhecida do usuário

Esta função é chamada depois que a API Rank é chamada, para cada iteração.

Esta função compara a preferência do utilizador pelo café, com base no tempo e na hora do dia, com a sugestão do Personalizador para o utilizador para esses filtros. Se a sugestão corresponder, uma pontuação de 1 é retornada, caso contrário, a pontuação é 0. A célula não tem saída. A função produz a pontuação quando chamada.

def get_reward_from_simulated_data(name, weather, timeofday, prediction):
    if(userpref[name][weather][timeofday] == str(prediction)):
        return 1
    return 0

Loop através de chamadas para Rank and Reward

A próxima célula é o trabalho principal do Caderno, obtendo um usuário aleatório, obtendo a lista de café, enviando ambos para a API Rank. Comparando a previsão com as preferências conhecidas do usuário e, em seguida, enviando a recompensa de volta para o serviço Personalizador.

O loop é executado por num_requests vezes. O Personalizer precisa de alguns milhares de chamadas para Rank and Reward para criar um modelo.

Segue-se um exemplo do JSON enviado para a API Rank. A lista de café não está completa, por uma questão de brevidade. Você pode ver todo o JSON para café em coffee.json.

JSON enviado para a API de classificação:

{
   'contextFeatures':[
      {
         'timeofday':'Evening',
         'weather':'Snowy',
         'name':'Alice'
      }
   ],
   'actions':[
      {
         'id':'Cappucino',
         'features':[
            {
               'type':'hot',
               'origin':'kenya',
               'organic':'yes',
               'roast':'dark'
            }
         ]
      }
        ...rest of coffee list
   ],
   'excludedActions':[

   ],
   'eventId':'b5c4ef3e8c434f358382b04be8963f62',
   'deferActivation':False
}

Resposta JSON da API de classificação:

{
    'ranking': [
        {'id': 'Latte', 'probability': 0.85 },
        {'id': 'Iced mocha', 'probability': 0.05 },
        {'id': 'Cappucino', 'probability': 0.05 },
        {'id': 'Cold brew', 'probability': 0.05 }
    ],
    'eventId': '5001bcfe3bb542a1a238e6d18d57f2d2',
    'rewardActionId': 'Latte'
}

Finalmente, cada loop mostra a seleção aleatória do usuário, clima, hora do dia e recompensa determinada. A recompensa de 1 indica que o recurso Personalizador selecionou o tipo de café correto para determinado usuário, clima e hora do dia.

1 Alice Rainy Morning Latte 1

A função usa:

def iterations(n, modelCheck, jsonFormat):

    i = 1

    # default reward value - assumes failed prediction
    reward = 0

    # Print out dateTime
    currentDateTime()

    # collect results to aggregate in graph
    total = 0
    rewards = []
    count = []

    # default list of user, weather, time of day
    namesopt = ['Alice', 'Bob', 'Cathy', 'Dave']
    weatheropt = ['Sunny', 'Rainy', 'Snowy']
    timeofdayopt = ['Morning', 'Afternoon', 'Evening']


    while(i <= n):

        # create unique id to associate with an event
        eventid = add_event_id(jsonFormat)

        # generate a random sample
        [name, weather, timeofday] = add_random_user_and_contextfeatures(namesopt, weatheropt, timeofdayopt, jsonFormat)

        # add action features to rank
        add_action_features(jsonFormat)

        # show JSON to send to Rank
        print('To: ', jsonFormat)

        # choose an action - get prediction from Personalizer
        response = requests.post(personalization_rank_url, headers = headers, params = None, json = jsonFormat)

        # show Rank prediction
        print ('From: ',response.json())

        # compare personalization service recommendation with the simulated data to generate a reward value
        prediction = json.dumps(response.json()["rewardActionId"]).replace('"','')
        reward = get_reward_from_simulated_data(name, weather, timeofday, prediction)

        # show result for iteration
        print(f'   {i} {currentDateTime()} {name} {weather} {timeofday} {prediction} {reward}')

        # send the reward to the service
        response = requests.post(personalization_reward_url + eventid + "/reward", headers = headers, params= None, json = { "value" : reward })

        # for every N rank requests, compute total correct  total
         total =  total + reward

        # every N iteration, get last updated model date and time
        if(i % modelCheck == 0):

            print("**** 10% of loop found")

            get_last_updated(modelLastModified)

        # aggregate so chart is easier to read
        if(i % 10 == 0):
            rewards.append( total)
            count.append(i)
             total = 0

        i = i + 1

    # Print out dateTime
    currentDateTime()

    return [count, rewards]

Executar para 10.000 iterações

Execute o loop do Personalizer para 10.000 iterações. Este é um evento de longa duração. Não feche o navegador que executa o bloco de notas. Atualize o gráfico de métricas no portal do Azure periodicamente para ver o total de chamadas para o serviço. Quando você tem cerca de 20.000 chamadas, uma chamada de classificação e recompensa para cada iteração do loop, as iterações são feitas.

# max iterations
num_requests = 200

# 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)

Resultados do gráfico para ver melhorias

Crie um gráfico a count partir do e rewards.

def createChart(x, y):
    plt.plot(x, y)
    plt.xlabel("Batch of rank events")
    plt.ylabel("Correct recommendations per batch")
    plt.show()

Executar gráfico para 10.000 solicitações de classificação

Execute a createChart função.

createChart(count,rewards)

Ler o gráfico

Este gráfico mostra o sucesso do modelo para a política de aprendizagem padrão atual.

This chart shows the success of the current learning policy for the duration of the test.

O alvo ideal é que, no final do teste, o loop esteja com uma média de taxa de sucesso próxima de 100% menos a exploração. O valor padrão de exploração é 20%.

100-20=80

Esse valor de exploração é encontrado no portal do Azure, para o recurso Personalizador, na página Configuração .

Para encontrar uma melhor política de aprendizagem, com base nos seus dados para a API de classificação, execute uma avaliação offline no portal para o seu loop do Personalizador.

Executar uma avaliação offline

  1. No portal do Azure, abra a página Avaliações do recurso Personalizador .

  2. Selecione Criar avaliação.

  3. Insira os dados necessários de nome da avaliação e intervalo de datas para a avaliação do loop. O intervalo de datas deve incluir apenas os dias em que você está se concentrando para sua avaliação. In the Azure portal, open the Personalizer resource's Evaluations page. Select Create Evaluation. Enter the evaluation name and date range.

    O objetivo de executar essa avaliação offline é determinar se há uma melhor política de aprendizagem para os recursos e ações usados nesse loop. Para encontrar essa melhor política de aprendizagem, certifique-se de que a Descoberta de otimização esteja ativada.

  4. Selecione OK para iniciar a avaliação.

  5. Esta página Avaliações lista a nova avaliação e o seu estado atual. Dependendo da quantidade de dados que você tem, essa avaliação pode levar algum tempo. Você pode voltar a esta página depois de alguns minutos para ver os resultados.

  6. Quando a avaliação estiver concluída, selecione a avaliação e, em seguida, selecione Comparação de diferentes políticas de aprendizagem. Isso mostra as políticas de aprendizagem disponíveis e como elas se comportariam com os dados.

  7. Selecione a política de aprendizagem mais importante na tabela e selecione Aplicar. Isso aplica a melhor política de aprendizagem ao seu modelo e reciclagem.

Altere a frequência do modelo de atualização para 5 minutos

  1. No portal do Azure, ainda no recurso Personalizador, selecione a página Configuração .
  2. Altere a frequência de atualização do modelo e o tempo de espera de recompensa para 5 minutos e selecione Salvar.

Saiba mais sobre o tempo de espera de recompensa e a frequência de atualização do modelo.

#Verify new learning policy and times
get_service_settings()

Verifique se a saída está rewardWaitTime definida modelExportFrequency como 5 minutos.

-----checking model
<Response [200]>
{'creationTime': '0001-01-01T00:00:00+00:00', 'lastModifiedTime': '0001-01-01T00:00:00+00:00'}
-----model updated: "0001-01-01T00:00:00+00:00"
-----checking service settings
<Response [200]>
{...learning policy...}
<Response [200]>
{'rewardWaitTime': '00:05:00', 'defaultReward': 0.0, 'rewardAggregation': 'earliest', 'explorationPercentage': 0.2, 'modelExportFrequency': '00:05:00', 'logRetentionDays': -1}
User count 4
Coffee count 4

Validar nova política de aprendizagem

Retorne ao arquivo do Azure Notebooks e continue executando o mesmo loop, mas por apenas 2.000 iterações. Atualize o gráfico de métricas no portal do Azure periodicamente para ver o total de chamadas para o serviço. Quando você tem cerca de 4.000 chamadas, uma chamada de classificação e recompensa para cada iteração do loop, as iterações são feitas.

# max iterations
num_requests = 2000

# check last mod date N% of time - currently 10%
lastModCheck2 = int(num_requests * .10)

jsonTemplate2 = rankactionsjsonobj

# main iterations
[count2, rewards2] = iterations(num_requests, lastModCheck2, jsonTemplate)

Executar gráfico para 2.000 solicitações de classificação

Execute a createChart função.

createChart(count2,rewards2)

Rever o segundo gráfico

O segundo gráfico deve mostrar um aumento visível nas previsões de classificação alinhadas com as preferências do usuário.

The second chart should show a visible increase in Rank predictions aligning with user preferences.

Clean up resources (Limpar recursos)

Se você não pretende continuar a série de tutoriais, limpe os seguintes recursos:

  • Exclua seu projeto do Bloco de Anotações do Azure.
  • Exclua seu recurso do Personalizador.

Próximos passos

O bloco de anotações Jupyter e os arquivos de dados usados neste exemplo estão disponíveis no repositório GitHub para Personalizer.