Självstudie: Använda Personanpassare i Azure Notebook
Den här självstudien kör en loop för personanpassare i en Azure Notebook, som visar livscykeln för en loop för personanpassare från slut till slut.
Loopen föreslår vilken typ av kaffe en kund ska beställa. Användarna och deras inställningar lagras i en användardatamängd. Information om kaffet lagras i en kaffemängd.
Användare och kaffe
Anteckningsboken, 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 | Typer av väder |
|---|---|---|
| Alice Bob Cathy Dave |
Morgon Eftermiddag Kväll |
Soliga Regniga Snöiga |
För att personanpassare ska kunna lära sig mer vet systemet även om kaffeval för varje person.
| Kaffe – åtgärdsfunktioner | Typer av temperatur | Ursprungsplatser | Typer av 100-000 | Organisk |
|---|---|---|---|---|
| Capacap | Frekvent | Kenya | Mörk | Organisk |
| Kall brew | Kall | Brasilien | Ljus | Organisk |
| Iced-mocha | Kall | Etiopien | Ljus | Inte organisk |
| Latte | Frekvent | Brasilien | Mörk | Inte organisk |
Syftet med loopen Personanpassare ä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 finns på lagringsplatsen för personanpassade exempel GitHub.
Så här fungerar simuleringen
I början av det system som körs lyckas förslagen från Personanpassaren endast mellan 20 % och 30 %. Den här framgången indikeras av att belöningen skickas tillbaka till API:et för personanpassarebelöning med ett resultat på 1. Efter några rangordnings- och belöningssamtal förbättras systemet.
Efter de första begärandena kör du en offlineutvärdering. På så sätt kan personanpassaren granska data och föreslå en bättre inlärningsprincip. Tillämpa den nya utbildningsprincipen och kör notebook-anteckningsboken igen med 20 % av det tidigare antalet förfrågningar. Loopen fungerar bättre med den nya inlärningsprincipen.
Rangordnings- och belöningssamtal
För vart och ett av de få tusen anropen till tjänsten Personanpassare skickar Azure Notebook Rank-begäran till REST API:
- Ett unikt ID för rankning/begäran-händelsen
- 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 Personanpassaren gör ett förslag
Systemet tar emot begäran och jämför sedan förutsägelsen med användarens kända val under samma tid på dagen och vädret. Om det kända valet är detsamma som det förutsagda valet skickas belöningen 1 tillbaka till Personanpassaren. Annars är belöningen som skickas tillbaka 0.
Anteckning
Det här är en simulering så algoritmen för belöningen är enkel. I ett verkligt scenario bör algoritmen använda affärslogik, möjligen med vikter för olika aspekter av kundens upplevelse, för att fastställa belöningspoängen.
Förutsättningar
- Ett Azure Notebook-konto.
- En personanpassarresurs i Azure.
- Om du redan har använt personanpassarresursen ska du rensa data i Azure Portal för resursen.
- Upload alla filer för det här exemplet i ett Azure Notebook-projekt.
Filbeskrivningar:
- Personalizer.ipynb är Jupyter Notebook för den här självstudien.
- Användardatauppsättningen lagras i ett JSON-objekt.
- Kaffemängden lagras i ett JSON-objekt.
- Exempelbegäran för JSON är det förväntade formatet för en POST-begäran till Rank-API:et.
Konfigurera resurs för personanpassare
I Azure Portal konfigurerar du din personanpassarresurs med uppdateringsmodellens frekvens inställd på 15 sekunder och en väntetid för belöning på 15 sekunder. Dessa värden finns på sidan Konfiguration.
| Inställning | Värde |
|---|---|
| uppdateringsmodellfrekvens | 15 sekunder |
| väntetid för belöning | 15 sekunder |
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 Loop för personanpassare.
Konfigurera Azure Notebook
- Ändra Kernel till
Python 3.6. - Öppna filen
Personalizer.ipynb.
Köra notebook-celler
Kör varje körbar cell och vänta tills den returneras. Du vet att det är klart när hakparenteserna bredvid cellen visar ett tal i stället för ett * . 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 de Python-moduler som krävs. Cellen har inga utdata.
import json
import matplotlib.pyplot as plt
import random
import requests
import time
import uuid
Ange resursnyckel och namn för Personanpassare
Från Azure Portal du nyckeln och slutpunkten på sidan Snabbstart för din resurs för personanpassare. Ändra värdet för <your-resource-name> till namnet på din Personanpassare-resurs. Ändra värdet för <your-resource-key> till din personanpassarnyckel.
# 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>"
Skriva ut aktuellt datum och tid
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 , anropas, skriver funktionen ut datum och tid då modellen senast get_last_updated ändrades.
Dessa celler har inga utdata. Funktionen matar ut det senaste modellträningsdatumet när den anropas.
Funktionen använder en GET-REST API för att hämta modellegenskaperna.
# 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äsa JSON-datafiler
Den här cellen
- skapar url:erna som används i REST-anrop
- anger säkerhetsrubriken med hjälp av din resursnyckel för Personanpassare
- anger det slumpmässiga start seed för rankningshändelse-ID:t
- läser i JSON-datafilerna
get_last_updatedanropsmetod – inlärningsprincipen har tagits bort i exempelutdataget_service_settingsanropsmetod
Cellen har utdata från anropet till get_last_updated get_service_settings funktionerna och .
# 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 och rewardWaitTime båda är inställda på modelExportFrequency 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:00:15', '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 Personanpassare. Kontrollera att REST-statuskoden i utdata är <Response [200]> . Om du får ett felmeddelande, till exempel 404, men du är säker på att din resursnyckel och ditt namn är korrekta läser du in anteckningsboken igen.
Kontrollera att antalet kaffe och användare är båda 4. Om du får ett felmeddelande kontrollerar du att du har laddat upp alla tre JSON-filerna.
Konfigurera måttdiagram i Azure Portal
Senare i den här självstudien visas den långvariga processen med 10 000 begäranden från webbläsaren med en textruta för uppdatering. Det kan vara lättare att se i ett diagram eller som en total summa när den långvariga processen avslutas. Om du vill visa den här informationen använder du de mått som medföljer 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 långvariga processen pågår.
I Azure Portal väljer du din resurs för Personanpassare.
I resursnavigeringen väljer du Mått under Övervakning.
I diagrammet väljer du Lägg till mått.
Resurs- och måttnamnrymden har redan angetts. Du behöver bara välja måttet för lyckade anrop och aggregeringen av summa.
Ändra tidsfiltret till de senaste 4 timmarna.

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 ranganrop. ID:t används för att identifiera information om rangordning och belöningssamtal. Det här värdet kan komma från en affärsprocess, till exempel ett webbvisnings-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 för att skicka till Rank-begäran.
Cellen har inga utdata. När funktionen anropas returneras den slumpmässiga användarens namn, slumpmässigt väder och slumpmässig tid på dagen.
Listan med 4 användare och deras preferenser – endast vissa inställningar visas av utrymmesklistlighet:
{
"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ägg till alla kaffedata
Den här funktionen lägger till hela listan med kaffe i JSON-objektet som ska skickas till Rank-begäran.
Cellen har inga utdata. Funktionen ändrar när den rankjsonobj anropas.
Här är ett exempel på en enda kaffebryggare:
{
"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ändarpreferenser
Den här funktionen anropas efter att RANK-API:et har anropats för varje iteration.
Den här funktionen jämför användarens önskemål om kaffe, baserat på väder och tid på dagen, med personanpassarens förslag till användaren för dessa filter. Om förslaget matchar returneras ett resultat på 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 genom anrop till rankning och belöning
Nästa cell är det viktigaste arbetet i notebook-programmet, att hämta en slumpmässig användare, hämta kaffelistan och skicka båda till Rank-API:et. Jämföra förutsägelsen med användarens kända inställningar och skicka sedan tillbaka belöningen till tjänsten Personanpassare.
Loopen körs under num_requests tider. Personanpassaren behöver några tusen anrop för att rangordna och belöning för att skapa en modell.
Ett exempel på JSON som skickas till Rank-API:et följer. Listan över kaffe är inte fullständig, av utrymmesklistrast. Du kan se hela JSON för kaffe i coffee.json .
JSON skickas till Rank-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 Rank-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 en bestämd belöning. Belöningen 1 anger att resursen Personanpassare 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:
- Rankning: en POST REST API för att få rangordningen.
- Belöning: en POST REST API att rapportera belöning.
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 loopen Personanpassare för 10 000 iterationer. Det här är en långvarig händelse. Stäng inte webbläsaren som kör anteckningsboken. Uppdatera måttdiagrammet i Azure Portal regelbundet för att se det totala antalet anrop till tjänsten. När du har cirka 20 000 anrop, ett rangordnings- och belöningsanrop för varje iteration av loopen, är iterationerna klara.
# 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 rangordningsbegäranden
Kör createChart funktionen .
createChart(count,rewards)
Läsa diagrammet
Det här diagrammet visar framgången för modellen för den aktuella standardinlärningsprincipen.

Det perfekta målet är att loopen i slutet av testet medelvärdet av en lyckad hastighet 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 Portal för personanpassarresursen 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 Personanpassar-loop.
Köra en offlineutvärdering
I Azure Portal öppnar du sidan Utvärderingar för personanpassarresursen.
Välj Skapa utvärdering.
Ange nödvändiga data för utvärderingsnamnet och datumintervallet för looputvärderingen. Datumintervallet bör endast innehålla de dagar som du fokuserar på för utvärderingen.

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. Se till att Optimeringsidentifiering är aktiverat för att hitta en bättre inlärningsprincip.
Välj OK för att påbörja utvärderingen.
På 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 gå tillbaka till den här sidan efter några minuter för att se resultatet.
När utvärderingen är klar väljer du utvärderingen och sedan Jämförelse av olika utbildningsprinciper. Detta visar tillgängliga utbildningsprinciper och hur de beter sig med data.
Välj den översta utbildningspolicyn i tabellen och välj Tillämpa. Detta tillämpar den bästa inlärningsprincipen på din modell och omträningar.
Ändra uppdateringsmodellens frekvens till 5 minuter
- I Azure Portal väljer du sidan Konfiguration på sidan Personanpassare.
- Ändra modellens uppdateringsfrekvens och belöningsväntetid till 5 minuter och välj Spara.
Läs mer om väntetiden för belöning och modelluppdateringsfrekvensen.
#Verify new learning policy and times
get_service_settings()
Kontrollera att utdata och rewardWaitTime båda är inställda på modelExportFrequency 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
Verifiera ny utbildningsprincip
Gå tillbaka till Azure Notebooks och fortsätt genom att köra samma loop, men endast för 2 000 iterationer. Uppdatera måttdiagrammet i listan Azure Portal regelbundet för att se det totala antalet anrop till tjänsten. När du har cirka 4 000 anrop, ett rangordnings- och belöningsanrop för varje iteration av loopen, är iterationerna klara.
# 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 rangordningsbegäranden
Kör createChart funktionen .
createChart(count2,rewards2)
Granska det andra diagrammet
Det andra diagrammet bör visa en synlig ökning i Rangordningsförutsägelser som överensstämmer med användarinställningarna.

Rensa resurser
Om du inte planerar att fortsätta självstudieserien rensar du följande resurser:
- Ta bort ditt Azure Notebook-projekt.
- Ta bort din personanpassarresurs.
Nästa steg
Jupyter Notebook och datafilerna som används i det här exemplet finns på lagringsplatsen GitHub för Personanpassare.