Last active
December 16, 2015 20:29
-
-
Save iandanforth/5493031 to your computer and use it in GitHub Desktop.
Learning Loop - A simple bit of python code that illustrates biological style learning.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import time | |
from random import randint | |
""" | |
############################# | |
Learning Loop | |
Our scenario is that of a simple creature in a very simple world. | |
The creature can look left, or it can look right. That's all it can do. | |
When it looks left, it sees blackness. When it looks right, it sees light. | |
Our creature likes light. | |
It learns, quite quickly, that looking right is better than looking left. Soon | |
it will look right all the time. | |
This script illustrates some of the basic components that go into biological | |
learning. In one configuration or another, all animal learning takes place | |
between *at least* this set of components. Even creatures that don't have brains | |
use neurons with specific rolls to fulfil these functions. | |
############################## | |
Important Concepts to Consider | |
What controls how quickly the creature learns? | |
What controls what the creature prefers? Do you think this is realistic? | |
What would happen if the judgement of internal and external state were at odds? | |
For example, if it hurt to turn your head right, but you really wanted to | |
see what was in that direction? | |
Does the program always take the same number of loops to eliminate one of the | |
behaviors? Do you think this is realistic? | |
############################## | |
Code Caveats | |
Biology is intrinsicly parallel and event driven. This code is written in an | |
imperative style to be easy to follow and introspect. | |
The 'bias' would be better implemented as a skew on a normal distribution. | |
""" | |
def main(): | |
# Create the world | |
world = World() | |
# Build up a body | |
senses = Senses() | |
senseCenter = SenseCenter() | |
motorCenter = MotorCenter() | |
critic = Critic() | |
brain = Brain(motorCenter, senseCenter, critic) | |
body = Body(senses, brain) | |
# Start time | |
counter = 0 | |
while True: | |
# The body changes based on a command from the motor center | |
body.setState(motorCenter.getAction()) | |
print "Action: ", motorCenter.action | |
# The senses register this change in internal state | |
senses.setInternalState(body.getState()) | |
# The world (from the body's perspective) is also changed | |
world.setState(body.getState()) | |
# The senses register this change in external state | |
senses.setExternalState(world.getState()) | |
print "Perception: ", world.state | |
# The brain perceives the senses | |
senseCenter.setStates(*senses.getStates()) | |
# The critic (judgement center) perceives the sense representation | |
critic.setJudgement(*senseCenter.getStates()) | |
print "Judgement: ", critic.judgement | |
# The motor center learns if what it did was good or bad | |
motorCenter.setBias(critic.getJudgement()) | |
###################################################################### | |
# This simulation runs quickly to completion. | |
time.sleep(.01) | |
counter += 1 | |
if counter >= 100: | |
print "Done" | |
quit() | |
class World(object): | |
''' | |
The whole world | |
''' | |
def __init__(self): | |
self.state = "White" | |
def setState(self, bodyState): | |
if bodyState == "Left": | |
self.state = "Black" | |
elif bodyState == "Right": | |
self.state = "White" | |
else: | |
raise Exception("Invalid body state") | |
def getState(self): | |
return self.state | |
class Body(object): | |
''' | |
A very simple creatures body. It can look left, and look right. | |
''' | |
def __init__(self, senses, brain): | |
self.senses = senses | |
self.brain = brain | |
self.state = None | |
def setState(self, action): | |
if action == "LookLeft": | |
self.state = "Left" | |
elif action == "LookRight": | |
self.state = "Right" | |
else: | |
raise Exception("Invalid action %s" % action) | |
def getState(self): | |
return self.state | |
class Senses(object): | |
''' | |
The internal and external senses of a body | |
''' | |
def __init__(self): | |
self.internalState = None | |
self.externalState = None | |
def setInternalState(self, bodyState): | |
self.internalState = bodyState | |
def setExternalState(self, worldState): | |
self.externalState = worldState | |
def getStates(self): | |
return self.internalState, self.externalState | |
class Brain(object): | |
''' | |
A very simple brain made up of three centers | |
''' | |
def __init__(self, motorCenter, senseCenter, critic): | |
self.motorCenter = motorCenter | |
self.senseCenter = senseCenter | |
self.critic = critic | |
class BrainCenter(object): | |
''' | |
The parent class for all our brain centers. Exists only to illustrate the | |
connection between classes. | |
''' | |
def __init__(self): | |
pass | |
class SenseCenter(BrainCenter): | |
''' | |
The brain center that percieves the output of the body's senses | |
''' | |
def __init__(self): | |
self.internalState = None | |
self.externalState = None | |
def setStates(self, internalState, externalState): | |
self.internalState = internalState | |
self.externalState = externalState | |
def getStates(self): | |
return self.internalState, self.externalState | |
class MotorCenter(BrainCenter): | |
''' | |
The brain center that generates actions and learns | |
''' | |
def __init__(self): | |
self.bias = 0 | |
self.min = 0 | |
self.max = 100 | |
self.action = None | |
def getAction(self): | |
rangeMin = self.min | |
rangeMax = self.max + self.bias | |
try: | |
choice = randint(rangeMin, rangeMax) | |
except ValueError: | |
print "Foo" | |
choice = 0 | |
if choice >= 50: | |
self.action = "LookLeft" | |
else: | |
self.action = "LookRight" | |
return self.action | |
def setBias(self, judgement): | |
if self.action == "LookLeft": | |
# More likely to go left | |
if judgement == "Good": | |
self.bias += 1 | |
# Less likely to go left | |
elif judgement == "Bad": | |
self.bias -= 1 | |
elif self.action == "LookRight": | |
# More likely to go right | |
if judgement == "Good": | |
self.bias -= 1 # Note the swapped sign here. | |
# Less likely to go right | |
elif judgement == "Bad": | |
self.bias += 1 | |
class Critic(BrainCenter): | |
''' | |
The innate judgement of good and bad. | |
''' | |
def __init__(self): | |
self.judgement = "Good" | |
def setJudgement(self, internalState, externalState): | |
if externalState == "Black": | |
self.judgement = "Bad" | |
elif externalState == "White": | |
self.judgement = "Good" | |
else: | |
raise Exception("Invalid external state: %s" % externalState) | |
def getJudgement(self): | |
return self.judgement | |
if __name__ == '__main__': | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment