Een leertempo
Een blinde muis vindt de kaas in de helft van de wandelingen. Nu gaat hij onthouden wat elke stap opleverde. Bij Nim kreeg een zet een hele punt erbij of eraf, en liep de score op tot 971: een getal dat vooral zegt hoe vaak een zet gespeeld is. Nieuw is een leertempo: de waarde van een stap schuift telkens een stukje op naar de beloning, en blijft zo tussen -1 en 1.
Voorspel
tempo = 0.5
schatting = 0
for keer in range(3):
schatting = schatting + tempo * (1 - schatting)
print(schatting)
Wat print dit programma? Komt schatting ooit boven 1?
Antwoord
0.5
0.75
0.875
Nee. Elke keer gaat de helft van wat er tot 1 over is erbij. Hij komt steeds dichter bij 1, maar er nooit boven.
Zo werkt het
De regel is:
nieuwe waarde = oude waarde + tempo * (beloning - oude waarde)
beloning - oude waarde is hoever de schatting ernaast zat. Het tempo zegt
welk deel daarvan de muis in één keer bijstelt. Bij 0.5 is dat de helft. Bij
CS50 heet het tempo alpha.
Onderzoek
- Draai de code. Wat doet de schatting na de beloning -1?
- Zet
tempoop 0.25. Gaat de schatting nu sneller of langzamer naar 1? - Zet
tempoop 1. Wat onthoudt de schatting dan nog van eerdere beloningen?
Wat zie je?
1 0.5
1 0.75
-1 -0.125
1 0.4375
Antwoorden
- Hij zakt van 0.75 naar -0.125: de helft van de afstand naar -1. Bij de volgende 1 stijgt hij weer.
- Langzamer: 0.25, dan 0.4375. Een klein tempo leert langzaam, maar laat zich ook minder van één keer pech afbrengen.
- Niets: de schatting is dan elke keer precies de laatste beloning.
Opdracht: de muis onthoudt
Geef de muis een methode bijwerken(vakje, actie, beloning) die de waarde
van een stap met het leertempo naar de beloning schuift. Laat hem leren van
1000 blinde wandelingen, en print zijn tabel:
1 -1.0 -0.25
2 -0.25 -0.25
3 -0.25 1.0
Per vakje staan er de waarde van links en die van rechts.
Begin klein, en breid de code stap voor stap uit:
- Draai de code:
bijwerkenzet nu de beloning van één wandeling in de tabel. - Laat
bijwerkende waarde metself.tempoeen stukje naar de beloning schuiven, zoals in Voorspel. De oude waarde krijg je metself.waarde(vakje, actie). - Leer van 1000 wandelingen in plaats van één.
- Print voor elk vakje van 1 tot en met 3 de waarde van links en van rechts.
Tip
Bij stap 3 hoort de muis buiten de loop van 1000. Maak je elke wandeling een
nieuwe Muis(), dan begint hij steeds met een lege tabel.
Antwoord
Dit vervangt alles in de editor. De gang blijft in de verborgen code.
import random
class Muis:
def __init__(self):
self.q = {}
self.tempo = 0.5
def waarde(self, vakje, actie):
if (vakje, actie) in self.q:
return self.q[(vakje, actie)]
return 0
def bijwerken(self, vakje, actie, beloning):
oud = self.waarde(vakje, actie)
self.q[(vakje, actie)] = oud + self.tempo * (beloning - oud)
random.seed(1)
piep = Muis()
for keer in range(1000):
for vakje, actie, nieuw, beloning in willekeurige_wandeling():
piep.bijwerken(vakje, actie, beloning)
for vakje in [1, 2, 3]:
print(vakje, piep.waarde(vakje, "links"), piep.waarde(vakje, "rechts"))
1 -1.0 -0.25
2 -0.25 -0.25
3 -0.25 1.0
In vakje 1 weet de muis nu dat links de val is, en in vakje 3 dat rechts de kaas is. Maar in vakje 2, waar hij begint, zijn links en rechts allebei -0.25. Hij leert alleen wat één stap direct oplevert, en vanuit vakje 2 is dat nooit de kaas.
Door naar de beste toekomst.