Självstudie: Använda Personanpassning i Azure Notebook

Viktigt!

Från och med den 20 september 2023 kommer du inte att kunna skapa nya personaliseringsresurser. Personanpassningstjänsten dras tillbaka den 1 oktober 2026.

Den här självstudien kör en Personanpassningsloop i en Azure Notebook-fil som visar livscykeln för slutpunkt till slutpunkt för en Personanpassningsloop.

Loopen föreslår vilken typ av kaffe en kund ska beställa. Användarna och deras inställningar lagras i en användardatauppsättning. Information om kaffet lagras i en kaffedatauppsättning.

Användare och kaffe

Notebook-filen, som simulerar användarinteraktion med en webbplats, väljer en slumpmässig användare, tid på dagen och typ av väder från datauppsättningen. En sammanfattning av användarinformationen är:

Kunder – kontextfunktioner Tider på dagen Vädertyper
Alice
Johan
Cathy
Dave
Morgon
Eftermiddag
Kväll
Soliga
Regniga
Snöiga

För att hjälpa personanpassningen att lära sig, med tiden, känner systemet också till information om kaffevalet för varje person.

Kaffe – åtgärdsfunktioner Temperaturtyper Ursprungsplatser Typer av stek Ekologiska
Cappacino Het Kenya Mörkt Ekologiska
Kallbryggning Kall Brasilien Ljust Ekologiska
Iskall mocha Kall Etiopien Ljust Inte organiskt
Latte Het Brasilien Mörkt Inte organiskt

Syftet med personanpassningsloopen är att hitta den bästa matchningen mellan användarna och kaffet så mycket som möjligt.

Koden för den här självstudien är tillgänglig på GitHub-lagringsplatsen För personanpassningsexempel.

Så här fungerar simuleringen

I början av det system som körs lyckas bara förslag från Personanpassning mellan 20 % och 30 %. Denna framgång indikeras av belöningen som skickas tillbaka till Personanpassningsbelönings-API:et med poängen 1. Efter några Rank- och Reward-anrop förbättras systemet.

Efter de första begärandena kör du en offlineutvärdering. Detta gör att Personalizer kan granska data och föreslå en bättre inlärningsprincip. Tillämpa den nya inlärningsprincipen och kör notebook-filen igen med 20 % av det tidigare antalet förfrågningar. Loopen presterar bättre med den nya inlärningsprincipen.

Ranknings- och belöningssamtal

För vart och ett av de få tusen anropen till personanpassningstjänsten skickar Azure Notebook rankningsbegäran till REST-API:et:

  • Ett unikt ID för händelsen Rank/Request
  • Kontextfunktioner – Ett slumpmässigt val av användare, väder och tid på dagen – simulera en användare på en webbplats eller mobil enhet
  • Åtgärder med funktioner – Alla kaffedata – från vilka Personanpassning ger ett förslag

Systemet tar emot begäran och jämför sedan förutsägelsen med användarens kända val för samma tid på dagen och vädret. Om det kända valet är samma som det förutsagda valet skickas belöningen för 1 tillbaka till Personanpassning. Annars är belöningen som skickas tillbaka 0.

Kommentar

Det här är en simulering så att algoritmen för belöningen är enkel. I ett verkligt scenario bör algoritmen använda affärslogik, eventuellt med vikter för olika aspekter av kundens upplevelse, för att fastställa belöningspoängen.

Förutsättningar

Filbeskrivningar:

Konfigurera Personalizer-resurs

I Azure-portalen konfigurerar du personaliserarresursen med uppdateringsmodellens frekvens inställd på 15 sekunder och en väntetid på 10 minuter. Dessa värden finns på sidan Konfiguration .

Inställning Värde
uppdatera modellfrekvens 15 sekunder
belöningsväntetid 10 minuter

Dessa värden har en mycket kort varaktighet för att visa ändringar i den här självstudien. Dessa värden bör inte användas i ett produktionsscenario utan att verifiera att de uppnår ditt mål med din Personalizer-loop.

Konfigurera Azure Notebook

  1. Ändra kerneln till Python 3.6.
  2. Öppna Personalizer.ipynb-filen.

Kör notebook-celler

Kör varje körbar cell och vänta tills den returneras. Du vet att det görs när hakparenteserna bredvid cellen visar ett tal i stället för en *. I följande avsnitt förklaras vad varje cell gör programmatiskt och vad du kan förvänta dig för utdata.

Inkludera Python-modulerna

Inkludera nödvändiga Python-moduler. Cellen har inga utdata.

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

Ange personaliserarens resursnyckel och namn

Från Azure-portalen hittar du din nyckel och slutpunkt på sidan Snabbstart för personaliserarresursen. Ändra värdet <your-resource-name> för till personanpassningsresursens namn. Ändra värdet <your-resource-key> för till din personanpassningsnyckel.

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

Använd den här funktionen för att notera start- och sluttiderna för den iterativa funktionen iterationer.

Dessa celler har inga utdata. Funktionen matar ut aktuellt datum och tid när den anropas.

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

Hämta den senaste uppdateringstiden för modellen

När funktionen, get_last_updated, anropas, skriver funktionen ut det senast ändrade datum och den tid då modellen uppdaterades.

Dessa celler har inga utdata. Funktionen matar ut det senaste modellträningsdatumet när det anropas.

Funktionen använder ett GET REST API för att hämta modellegenskaper.

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

Hämta princip- och tjänstkonfiguration

Verifiera tjänstens tillstånd med dessa två REST-anrop.

Dessa celler har inga utdata. Funktionen matar ut tjänstvärdena när den anropas.

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

Skapa URL:er och läs JSON-datafiler

Den här cellen

  • skapar url:er som används i REST-anrop
  • anger säkerhetsrubriken med hjälp av personaliserarens resursnyckel
  • anger det slumpmässiga fröet för händelse-ID för rankning
  • läser i JSON-datafilerna
  • anropsmetod get_last_updated – inlärningsprincipen har tagits bort i exempelutdata
  • anropsmetod get_service_settings

Cellen har utdata från anropet till get_last_updated och get_service_settings funktionerna.

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

Kontrollera att utdata rewardWaitTime är inställda på 10 minuter och modelExportFrequency är inställt på 15 sekunder.

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

Felsöka det första REST-anropet

Den här föregående cellen är den första cellen som anropar Personanpassning. Kontrollera att REST-statuskoden i utdata är <Response [200]>. Om du får ett fel, till exempel 404, men du är säker på att resursnyckeln och namnet är korrekta läser du in anteckningsboken igen.

Kontrollera att antalet kaffe och användare är båda 4. Om du får ett fel kontrollerar du att du har laddat upp alla 3 JSON-filer.

Konfigurera måttdiagram i Azure-portalen

Senare i den här självstudien visas den tidskrävande processen med 10 000 begäranden från webbläsaren med en uppdateringstextruta. Det kan vara lättare att se i ett diagram eller som en total summa när den tidskrävande processen slutar. Om du vill visa den här informationen använder du måtten som tillhandahålls med resursen. Du kan skapa diagrammet nu när du har slutfört en begäran till tjänsten och sedan uppdatera diagrammet regelbundet medan den tidskrävande processen pågår.

  1. I Azure-portalen väljer du din Personalizer-resurs.

  2. I resursnavigering väljer du Mått under Övervakning.

  3. I diagrammet väljer du Lägg till mått.

  4. Resurs- och måttnamnområdet har redan angetts. Du behöver bara välja måttet för lyckade anrop och summans sammansättning.

  5. Ändra tidsfiltret till de senaste 4 timmarna.

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

    Du bör se tre lyckade anrop i diagrammet.

Generera ett unikt händelse-ID

Den här funktionen genererar ett unikt ID för varje rankningsanrop. ID:t används för att identifiera ranknings- och belöningssamtalsinformationen. Det här värdet kan komma från en affärsprocess, till exempel ett webbvy-ID eller transaktions-ID.

Cellen har inga utdata. Funktionen matar ut det unika ID:t när det anropas.

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

Hämta slumpmässig användare, väder och tid på dagen

Den här funktionen väljer en unik användare, väder och tid på dagen och lägger sedan till objekten i JSON-objektet som ska skickas till Rank-begäran.

Cellen har inga utdata. När funktionen anropas returneras den slumpmässiga användarens namn, slumpmässiga väder och slumpmässig tid på dagen.

Listan med 4 användare och deras inställningar – endast vissa inställningar visas för korthet:

{
  "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]

Lägga till alla kaffedata

Den här funktionen lägger till hela listan med kaffe till JSON-objektet som ska skickas till Rank-begäran.

Cellen har inga utdata. Funktionen ändrar när den anropas rankjsonobj .

Exemplet på en enda kaffefunktion är:

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

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

Jämför förutsägelse med kända användarinställningar

Den här funktionen anropas efter att ranknings-API:et anropats för varje iteration.

Den här funktionen jämför användarens inställningar för kaffe, baserat på väder och tid på dagen, med personanpassningens förslag för användaren för dessa filter. Om förslaget matchar returneras poängen 1, annars är poängen 0. Cellen har inga utdata. Funktionen matar ut poängen när den anropas.

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

Loopa igenom anrop till Rank and Reward

Nästa cell är huvudarbetet i notebook-filen, hämtar en slumpmässig användare, hämtar kaffelistan och skickar båda till ranknings-API:et. Jämföra förutsägelsen med användarens kända inställningar och skicka sedan belöningen tillbaka till personanpassningstjänsten.

Loopen körs för num_requests tider. Personanpassning behöver några tusen anrop till Rank and Reward för att skapa en modell.

Ett exempel på JSON som skickas till ranknings-API:et följer. Listan över kaffe är inte fullständig, för korthet. Du kan se hela JSON för kaffe i coffee.json.

JSON skickas till ranknings-API:et:

{
   '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
}

JSON-svar från ranknings-API:et:

{
    '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'
}

Slutligen visar varje loop det slumpmässiga valet av användare, väder, tid på dagen och fast belöning. Belöningen på 1 anger att personaliserarresursen har valt rätt kaffetyp för den angivna användaren, vädret och tiden på dagen.

1 Alice Rainy Morning Latte 1

Funktionen använder:

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]

Kör för 10 000 iterationer

Kör personanpassningsloopen för 10 000 iterationer. Det här är en tidskrävande händelse. Stäng inte webbläsaren som kör notebook-filen. Uppdatera måttdiagrammet i Azure-portalen med jämna mellanrum för att se totalt antal anrop till tjänsten. När du har cirka 20 000 anrop, ett ranknings- och belöningsanrop för varje iteration av loopen, görs iterationerna.

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

Diagramresultat för att se förbättringar

Skapa ett diagram från count och rewards.

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

Kör diagram för 10 000 rankningsbegäranden

createChart Kör funktionen.

createChart(count,rewards)

Läsa diagrammet

Det här diagrammet visar modellens framgång för den aktuella standardinlärningsprincipen.

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

Det idealiska målet att loopen i slutet av testet i genomsnitt är en lyckad frekvens som är nära 100 procent minus utforskningen. Standardvärdet för utforskning är 20 %.

100-20=80

Det här utforskningsvärdet finns i Azure-portalen för personanpassningsresursen på sidan Konfiguration .

För att hitta en bättre inlärningsprincip, baserat på dina data till Rank-API:et, kör du en offlineutvärdering i portalen för din Personanpassningsloop.

Kör en offlineutvärdering

  1. Öppna sidan Utvärderingar för personanpassningsresursen i Azure-portalen.

  2. Välj Skapa utvärdering.

  3. Ange nödvändiga data för utvärderingsnamnet och datumintervallet för looputvärderingen. Datumintervallet bör bara innehålla de dagar som du fokuserar på för utvärderingen. In the Azure portal, open the Personalizer resource's Evaluations page. Select Create Evaluation. Enter the evaluation name and date range.

    Syftet med att köra den här offlineutvärderingen är att avgöra om det finns en bättre inlärningsprincip för de funktioner och åtgärder som används i den här loopen. Kontrollera att optimeringsidentifiering är aktiverat för att hitta den bättre inlärningsprincipen.

  4. Välj OK för att påbörja utvärderingen.

  5. sidan Utvärderingar visas den nya utvärderingen och dess aktuella status. Beroende på hur mycket data du har kan den här utvärderingen ta lite tid. Du kan komma tillbaka till den här sidan efter några minuter för att se resultatet.

  6. När utvärderingen är klar väljer du utvärderingen och sedan Jämförelse av olika inlärningsprinciper. Detta visar tillgängliga inlärningsprinciper och hur de skulle bete sig med data.

  7. Välj den mest populära utbildningsprincipen i tabellen och välj Använd. Detta tillämpar den bästa inlärningsprincipen för din modell och omträningar.

Ändra uppdateringsmodellfrekvens till 5 minuter

  1. I Azure-portalen går du fortfarande till personanpassningsresursen och väljer sidan Konfiguration .
  2. Ändra modellens uppdateringsfrekvens och belöningsväntetid till 5 minuter och välj Spara.

Läs mer om väntetiden för belöningen och uppdateringsfrekvensen för modellen.

#Verify new learning policy and times
get_service_settings()

Kontrollera att utdata och rewardWaitTimemodelExportFrequency båda är inställda på 5 minuter.

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

Validera ny inlärningsprincip

Gå tillbaka till Azure Notebooks-filen och fortsätt genom att köra samma loop, men endast för 2 000 iterationer. Uppdatera måttdiagrammet i Azure-portalen med jämna mellanrum för att se totalt antal anrop till tjänsten. När du har cirka 4 000 samtal, ett ranknings- och belöningsanrop för varje iteration av loopen, görs iterationerna.

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

Körningsdiagram för 2 000 rankningsbegäranden

createChart Kör funktionen.

createChart(count2,rewards2)

Granska det andra diagrammet

Det andra diagrammet bör visa en synlig ökning av rankningsförutsägelser som överensstämmer med användarinställningar.

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

Rensa resurser

Om du inte tänker fortsätta självstudieserien rensar du upp följande resurser:

  • Ta bort ditt Azure Notebook-projekt.
  • Ta bort personaliserarresursen.

Nästa steg

Jupyter-anteckningsboken och datafilerna som används i det här exemplet är tillgängliga på GitHub-lagringsplatsen för Personalizer.