def testReadWrite(self): categories = ["ES", "GB", "US"] # forced: is not recommended, but is used here for readability. see # scalar.py original = CategoryEncoder(w=3, categoryList=categories, forced=True) output = original.encode("US") target = numpy.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], dtype=defaultDtype) self.assertTrue(numpy.array_equal(output, target)) decoded = original.decode(output) proto1 = CategoryEncoderProto.new_message() original.write(proto1) # Write the proto to a temp file and read it back into a new proto with tempfile.TemporaryFile() as f: proto1.write(f) f.seek(0) proto2 = CategoryEncoderProto.read(f) encoder = CategoryEncoder.read(proto2) self.assertIsInstance(encoder, CategoryEncoder) self.assertEqual(encoder.verbosity, original.verbosity) self.assertEqual(encoder.width, original.width) self.assertEqual(encoder.description, original.description) self.assertEqual(encoder.name, original.name) self.assertDictEqual(encoder.categoryToIndex, original.categoryToIndex) self.assertDictEqual(encoder.indexToCategory, original.indexToCategory) self.assertTrue(numpy.array_equal(encoder.encode("US"), output)) self.assertEqual(original.decode(encoder.encode("US")), encoder.decode(original.encode("US"))) self.assertEqual(decoded, encoder.decode(output))
def testReadWrite(self): categories = ["ES", "GB", "US"] # forced: is not recommended, but is used here for readability. see # scalar.py original = CategoryEncoder(w=3, categoryList=categories, forced=True) output = original.encode("US") target = numpy.array([0,0,0,0,0,0,0,0,0,1,1,1], dtype=defaultDtype) self.assertTrue(numpy.array_equal(output, target)) decoded = original.decode(output) proto1 = CategoryEncoderProto.new_message() original.write(proto1) # Write the proto to a temp file and read it back into a new proto with tempfile.TemporaryFile() as f: proto1.write(f) f.seek(0) proto2 = CategoryEncoderProto.read(f) encoder = CategoryEncoder.read(proto2) self.assertIsInstance(encoder, CategoryEncoder) self.assertEqual(encoder.verbosity, original.verbosity) self.assertEqual(encoder.width, original.width) self.assertEqual(encoder.description, original.description) self.assertEqual(encoder.name, original.name) self.assertDictEqual(encoder.categoryToIndex, original.categoryToIndex) self.assertDictEqual(encoder.indexToCategory, original.indexToCategory) self.assertTrue(numpy.array_equal(encoder.encode("US"), output)) self.assertEqual(original.decode(encoder.encode("US")), encoder.decode(original.encode("US"))) self.assertEqual(decoded, encoder.decode(output))
categories = ("cat", "dog", "monkey", "mai") encoder = CategoryEncoder(w=5, categoryList=categories) cat = encoder.encode("cat") dog = encoder.encode("dog") monkey = encoder.encode("monkey") mai = encoder.encode("mai") print "cat =", cat print "dog =", dog print "monkey =", monkey print "mai =", mai print print "None =", encoder.encode(None) print "Unknown =", encoder.encode("unknown") print print "Decode cat", encoder.decode(cat) print "Decode dog", encoder.decode(dog) print "Decode monkey", encoder.decode(monkey) print "Decode mai", encoder.decode(mai) catnoise = numpy.zeros(25, 'int') catnoise[5:10] = 1 catnoise[[13, 18, 23]] = 1 print "Decode catnoise", encoder.decode(catnoise) # This representation has all activations of the cat cells turns on, and has one # cell turn on for each of other classes. It should safely generate 'cat', instead # it generates 'cat', 'dog', 'monkey', 'mai', making it very susceptible to noise. # catdog = numpy.array([0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0]) # print encoder.decode(catdog)
from nupic.encoders.category import CategoryEncoder categories = ("cat", "dog", "monkey", "slow loris") encoder = CategoryEncoder(w=3, categoryList=categories, forced=True) cat = encoder.encode("cat") dog = encoder.encode("dog") monkey = encoder.encode("monkey") loris = encoder.encode("slow loris") print "cat = ", cat print "dog = ", dog print "monkey = ", monkey print "slow loris =", loris print encoder.decode(cat) ss=cat+monkey+dog print encoder.decode(ss) ss from nupic.bindings.algorithms import SpatialPooler sp = SpatialPooler(inputDimensions=(15,), columnDimensions=(4,), potentialRadius=15, numActiveColumnsPerInhArea=1, globalInhibition=True, synPermActiveInc=0.03, potentialPct=1.0) for column in xrange(4): connected = np.zeros((15,), dtype="int")
def testCategoryEncoder(self): categories = ["ES", "GB", "US"] # forced: is not recommended, but is used here for readability. # see scalar.py e = CategoryEncoder(w=3, categoryList=categories, forced=True) output = e.encode("US") expected = numpy.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], dtype=defaultDtype) self.assertTrue(numpy.array_equal(output, expected)) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldNames), 1) self.assertEqual(len(fieldsDict), 1) self.assertEqual(fieldNames[0], fieldsDict.keys()[0]) (ranges, desc) = fieldsDict.values()[0] self.assertEqual(desc, "US") self.assertEqual(len(ranges), 1) self.assertTrue(numpy.array_equal(ranges[0], [3, 3])) # Test topdown compute for v in categories: output = e.encode(v) topDown = e.topDownCompute(output) self.assertEqual(topDown.value, v) self.assertEqual(topDown.scalar, e.getScalars(v)[0]) bucketIndices = e.getBucketIndices(v) topDown = e.getBucketInfo(bucketIndices)[0] self.assertEqual(topDown.value, v) self.assertEqual(topDown.scalar, e.getScalars(v)[0]) self.assertTrue(numpy.array_equal(topDown.encoding, output)) self.assertEqual(topDown.value, e.getBucketValues()[bucketIndices[0]]) # --------------------- # unknown category output = e.encode("NA") expected = numpy.array([1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=defaultDtype) self.assertTrue(numpy.array_equal(output, expected)) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldNames), 1) self.assertEqual(len(fieldsDict), 1) self.assertEqual(fieldNames[0], fieldsDict.keys()[0]) (ranges, desc) = fieldsDict.values()[0] self.assertEqual(len(ranges), 1) self.assertTrue(numpy.array_equal(ranges[0], [0, 0])) # Test topdown compute topDown = e.topDownCompute(output) self.assertEqual(topDown.value, UNKNOWN) self.assertEqual(topDown.scalar, 0) # -------------------------------- # ES output = e.encode("ES") expected = numpy.array([0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0], dtype=defaultDtype) self.assertTrue(numpy.array_equal(output, expected)) # MISSING VALUE outputForMissing = e.encode(SENTINEL_VALUE_FOR_MISSING_DATA) self.assertEqual(sum(outputForMissing), 0) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldNames), 1) self.assertEqual(len(fieldsDict), 1) self.assertEqual(fieldNames[0], fieldsDict.keys()[0]) (ranges, desc) = fieldsDict.values()[0] self.assertEqual(len(ranges), 1) self.assertTrue(numpy.array_equal(ranges[0], [1, 1])) # Test topdown compute topDown = e.topDownCompute(output) self.assertEqual(topDown.value, "ES") self.assertEqual(topDown.scalar, e.getScalars("ES")[0]) # -------------------------------- # Multiple categories output.fill(1) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldNames), 1) self.assertEqual(len(fieldsDict), 1) self.assertEqual(fieldNames[0], fieldsDict.keys()[0]) (ranges, desc) = fieldsDict.values()[0] self.assertEqual(len(ranges), 1) self.assertTrue(numpy.array_equal(ranges[0], [0, 3])) # ------------------------------------------------------------- # Test with width = 1 categories = ["cat1", "cat2", "cat3", "cat4", "cat5"] # forced: is not recommended, but is used here for readability. # see scalar.py e = CategoryEncoder(w=1, categoryList=categories, forced=True) for cat in categories: output = e.encode(cat) topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # ------------------------------------------------------------- # Test with width = 9, removing some bits end the encoded output categories = ["cat%d" % (x) for x in range(1, 10)] # forced: is not recommended, but is used here for readability. # see scalar.py e = CategoryEncoder(w=9, categoryList=categories, forced=True) for cat in categories: output = e.encode(cat) topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 1 bit on the left outputNZs = output.nonzero()[0] output[outputNZs[0]] = 0 topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 1 bit on the right output[outputNZs[0]] = 1 output[outputNZs[-1]] = 0 topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 4 bits on the left output.fill(0) output[outputNZs[-5:]] = 1 topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 4 bits on the right output.fill(0) output[outputNZs[0:5]] = 1 topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # OR together the output of 2 different categories, we should not get # back the mean, but rather one or the other output1 = e.encode("cat1") output2 = e.encode("cat9") output = output1 + output2 topDown = e.topDownCompute(output) self.assertTrue(topDown.scalar == e.getScalars("cat1")[0] \ or topDown.scalar == e.getScalars("cat9")[0])
def testCategoryEncoder(self): verbosity = 0 print "Testing CategoryEncoder...", categories = ["ES", "GB", "US"] e = CategoryEncoder(w=3, categoryList=categories) output = e.encode("US") self.assertTrue( (output == numpy.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], dtype=defaultDtype)).all()) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldsDict), 1) (ranges, desc) = fieldsDict.values()[0] self.assertTrue( len(ranges) == 1 and numpy.array_equal(ranges[0], [3, 3])) print "decodedToStr of", ranges, "=>", e.decodedToStr(decoded) # Test topdown compute for v in categories: output = e.encode(v) topDown = e.topDownCompute(output) self.assertEqual(topDown.value, v) self.assertEqual(topDown.scalar, e.getScalars(v)[0]) bucketIndices = e.getBucketIndices(v) print "bucket index =>", bucketIndices[0] topDown = e.getBucketInfo(bucketIndices)[0] self.assertEqual(topDown.value, v) self.assertEqual(topDown.scalar, e.getScalars(v)[0]) self.assertTrue((topDown.encoding == output).all()) self.assertEqual(topDown.value, e.getBucketValues()[bucketIndices[0]]) # --------------------- # unknown category output = e.encode("NA") self.assertTrue( (output == numpy.array([1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=defaultDtype)).all()) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldsDict), 1) (ranges, desc) = fieldsDict.values()[0] self.assertTrue( len(ranges) == 1 and numpy.array_equal(ranges[0], [0, 0])) print "decodedToStr of", ranges, "=>", e.decodedToStr(decoded) # Test topdown compute topDown = e.topDownCompute(output) self.assertEqual(topDown.value, "<UNKNOWN>") self.assertEqual(topDown.scalar, 0) # -------------------------------- # ES output = e.encode("ES") self.assertTrue( (output == numpy.array([0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0], dtype=defaultDtype)).all()) # MISSING VALUE outputForMissing = e.encode(SENTINEL_VALUE_FOR_MISSING_DATA) self.assertEqual(sum(outputForMissing), 0) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldsDict), 1) (ranges, desc) = fieldsDict.values()[0] self.assertTrue( len(ranges) == 1 and numpy.array_equal(ranges[0], [1, 1])) print "decodedToStr of", ranges, "=>", e.decodedToStr(decoded) # Test topdown compute topDown = e.topDownCompute(output) self.assertEqual(topDown.value, "ES") self.assertEqual(topDown.scalar, e.getScalars("ES")[0]) # -------------------------------- # Multiple categories output.fill(1) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldsDict), 1) (ranges, desc) = fieldsDict.values()[0] self.assertTrue( len(ranges) == 1 and numpy.array_equal(ranges[0], [0, 3])) print "decodedToStr of", ranges, "=>", e.decodedToStr(decoded) # ------------------------------------------------------------- # Test with width = 1 categories = ["cat1", "cat2", "cat3", "cat4", "cat5"] e = CategoryEncoder(w=1, categoryList=categories) for cat in categories: output = e.encode(cat) topDown = e.topDownCompute(output) if verbosity >= 1: print cat, "->", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # ------------------------------------------------------------- # Test with width = 9, removing some bits end the encoded output categories = ["cat%d" % (x) for x in range(1, 10)] e = CategoryEncoder(w=9, categoryList=categories) for cat in categories: output = e.encode(cat) topDown = e.topDownCompute(output) if verbosity >= 1: print cat, "->", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 1 bit on the left outputNZs = output.nonzero()[0] output[outputNZs[0]] = 0 topDown = e.topDownCompute(output) if verbosity >= 1: print "missing 1 bit on left:", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 1 bit on the right output[outputNZs[0]] = 1 output[outputNZs[-1]] = 0 topDown = e.topDownCompute(output) if verbosity >= 1: print "missing 1 bit on right:", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 4 bits on the left output.fill(0) output[outputNZs[-5:]] = 1 topDown = e.topDownCompute(output) if verbosity >= 1: print "missing 4 bits on left:", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 4 bits on the right output.fill(0) output[outputNZs[0:5]] = 1 topDown = e.topDownCompute(output) if verbosity >= 1: print "missing 4 bits on right:", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # OR together the output of 2 different categories, we should not get # back the mean, but rather one or the other output1 = e.encode("cat1") output2 = e.encode("cat9") output = output1 + output2 topDown = e.topDownCompute(output) if verbosity >= 1: print "cat1 + cat9 ->", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown self.assertTrue(topDown.scalar == e.getScalars("cat1")[0] \ or topDown.scalar == e.getScalars("cat9")[0]) print "passed"
class SMSequences(object): """ Class generates sensorimotor sequences """ def __init__( self, sensoryInputElements, spatialConfig, sensoryInputElementsPool=list("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz0123456789"), minDisplacement=1, maxDisplacement=1, numActiveBitsSensoryInput=9, numActiveBitsMotorInput=9, seed=42, verbosity=False, useRandomEncoder=False, ): """ @param sensoryInputElements (list) Strings or numbers representing the sensory elements that exist in your world. Elements can be repeated if multiple of the same exist. @param spatialConfig (numpy.array) Array of size: (1, len(sensoryInputElements), dimension). It has a coordinate for every element in sensoryInputElements. @param sensoryInputElementsPool (list) List of strings representing a readable version of all possible sensory elements in this world. Elements don't need to be in any order and there should be no duplicates. By default this contains the set of alphanumeric characters. @param maxDisplacement (int) Maximum `distance` for a motor command. Distance is defined by the largest difference along any coordinate dimension. @param minDisplacement (int) Minimum `distance` for a motor command. Distance is defined by the largest difference along any coordinate dimension. @param numActiveBitsSensoryInput (int) Number of active bits for each sensory input. @param numActiveBitsMotorInput (int) Number of active bits for each dimension of the motor input. @param seed (int) Random seed for nupic.bindings.Random. @param verbosity (int) Verbosity @param useRandomEncoder (boolean) if True, use the random encoder SDRCategoryEncoder. If False, use CategoryEncoder. CategoryEncoder encodes categories using contiguous non-overlapping bits for each category, which makes it easier to debug. """ # --------------------------------------------------------------------------------- # Store creation parameters self.sensoryInputElements = sensoryInputElements self.sensoryInputElementsPool = sensoryInputElementsPool self.spatialConfig = spatialConfig.astype(int) self.spatialLength = len(spatialConfig) self.maxDisplacement = maxDisplacement self.minDisplacement = minDisplacement self.numActiveBitsSensoryInput = numActiveBitsSensoryInput self.numActiveBitsMotorInput = numActiveBitsMotorInput self.verbosity = verbosity self.seed = seed self.initialize(useRandomEncoder) def initialize(self, useRandomEncoder): """ Initialize the various data structures. """ self.setRandomSeed(self.seed) self.dim = numpy.shape(self.spatialConfig)[-1] self.spatialMap = dict(zip(map(tuple, list(self.spatialConfig)), self.sensoryInputElements)) self.lengthMotorInput1D = (2 * self.maxDisplacement + 1) * self.numActiveBitsMotorInput uniqueSensoryElements = list(set(self.sensoryInputElementsPool)) if useRandomEncoder: self.sensoryEncoder = SDRCategoryEncoder( n=1024, w=self.numActiveBitsSensoryInput, categoryList=uniqueSensoryElements, forced=True ) self.lengthSensoryInput = self.sensoryEncoder.getWidth() else: self.lengthSensoryInput = (len(self.sensoryInputElementsPool) + 1) * self.numActiveBitsSensoryInput self.sensoryEncoder = CategoryEncoder( w=self.numActiveBitsSensoryInput, categoryList=uniqueSensoryElements, forced=True ) motorEncoder1D = ScalarEncoder( n=self.lengthMotorInput1D, w=self.numActiveBitsMotorInput, minval=-self.maxDisplacement, maxval=self.maxDisplacement, clipInput=True, forced=True, ) self.motorEncoder = VectorEncoder(length=self.dim, encoder=motorEncoder1D) def generateSensorimotorSequence(self, sequenceLength): """ Generate sensorimotor sequences of length sequenceLength. @param sequenceLength (int) Length of the sensorimotor sequence. @return (tuple) Contains: sensorySequence (list) Encoded sensory input for whole sequence. motorSequence (list) Encoded motor input for whole sequence. sensorimotorSequence (list) Encoder sensorimotor input for whole sequence. This is useful when you want to give external input to temporal memory. """ motorSequence = [] sensorySequence = [] sensorimotorSequence = [] currentEyeLoc = self.nupicRandomChoice(self.spatialConfig) for i in xrange(sequenceLength): currentSensoryInput = self.spatialMap[tuple(currentEyeLoc)] nextEyeLoc, currentEyeV = self.getNextEyeLocation(currentEyeLoc) if self.verbosity: print "sensory input = ", currentSensoryInput, "eye location = ", currentEyeLoc, " motor command = ", currentEyeV sensoryInput = self.encodeSensoryInput(currentSensoryInput) motorInput = self.encodeMotorInput(list(currentEyeV)) sensorimotorInput = numpy.concatenate((sensoryInput, motorInput)) sensorySequence.append(sensoryInput) motorSequence.append(motorInput) sensorimotorSequence.append(sensorimotorInput) currentEyeLoc = nextEyeLoc return (sensorySequence, motorSequence, sensorimotorSequence) def encodeSensorimotorSequence(self, eyeLocs): """ Encode sensorimotor sequence given the eye movements. Sequence will have length len(eyeLocs) - 1 because only the differences of eye locations can be used to encoder motor commands. @param eyeLocs (list) Numpy coordinates describing where the eye is looking. @return (tuple) Contains: sensorySequence (list) Encoded sensory input for whole sequence. motorSequence (list) Encoded motor input for whole sequence. sensorimotorSequence (list) Encoder sensorimotor input for whole sequence. This is useful when you want to give external input to temporal memory. """ sequenceLength = len(eyeLocs) - 1 motorSequence = [] sensorySequence = [] sensorimotorSequence = [] for i in xrange(sequenceLength): currentEyeLoc = eyeLocs[i] nextEyeLoc = eyeLocs[i + 1] currentSensoryInput = self.spatialMap[currentEyeLoc] currentEyeV = nextEyeLoc - currentEyeLoc if self.verbosity: print "sensory input = ", currentSensoryInput, "eye location = ", currentEyeLoc, " motor command = ", currentEyeV sensoryInput = self.encodeSensoryInput(currentSensoryInput) motorInput = self.encodeMotorInput(list(currentEyeV)) sensorimotorInput = numpy.concatenate((sensoryInput, motorInput)) sensorySequence.append(sensoryInput) motorSequence.append(motorInput) sensorimotorSequence.append(sensorimotorInput) return (sensorySequence, motorSequence, sensorimotorSequence) def getNextEyeLocation(self, currentEyeLoc): """ Generate next eye location based on current eye location. @param currentEyeLoc (numpy.array) Current coordinate describing the eye location in the world. @return (tuple) Contains: nextEyeLoc (numpy.array) Coordinate of the next eye location. eyeDiff (numpy.array) Vector describing change from currentEyeLoc to nextEyeLoc. """ possibleEyeLocs = [] for loc in self.spatialConfig: shift = abs(max(loc - currentEyeLoc)) if self.minDisplacement <= shift <= self.maxDisplacement: possibleEyeLocs.append(loc) nextEyeLoc = self.nupicRandomChoice(possibleEyeLocs) eyeDiff = nextEyeLoc - currentEyeLoc return nextEyeLoc, eyeDiff def setRandomSeed(self, seed): """ Reset the nupic random generator. This is necessary to reset random seed to generate new sequences. @param seed (int) Seed for nupic.bindings.Random. """ self.seed = seed self._random = Random() self._random.setSeed(seed) def nupicRandomChoice(self, array): """ Chooses a random element from an array using the nupic random number generator. @param array (list or numpy.array) Array to choose random element from. @return (element) Element chosen at random. """ return array[self._random.getUInt32(len(array))] def encodeMotorInput(self, motorInput): """ Encode motor command to bit vector. @param motorInput (1D numpy.array) Motor command to be encoded. @return (1D numpy.array) Encoded motor command. """ if not hasattr(motorInput, "__iter__"): motorInput = list([motorInput]) return self.motorEncoder.encode(motorInput) def decodeMotorInput(self, motorInputPattern): """ Decode motor command from bit vector. @param motorInputPattern (1D numpy.array) Encoded motor command. @return (1D numpy.array) Decoded motor command. """ key = self.motorEncoder.decode(motorInputPattern)[0].keys()[0] motorCommand = self.motorEncoder.decode(motorInputPattern)[0][key][1][0] return motorCommand def encodeSensoryInput(self, sensoryInputElement): """ Encode sensory input to bit vector @param sensoryElement (1D numpy.array) Sensory element to be encoded. @return (1D numpy.array) Encoded sensory element. """ return self.sensoryEncoder.encode(sensoryInputElement) def decodeSensoryInput(self, sensoryInputPattern): """ Decode sensory input from bit vector. @param sensoryInputPattern (1D numpy.array) Encoded sensory element. @return (1D numpy.array) Decoded sensory element. """ return self.sensoryEncoder.decode(sensoryInputPattern)[0]["category"][1] def printSensoryCodingScheme(self): """ Print sensory inputs along with their encoded versions. """ print "\nsensory coding scheme: " for loc in self.spatialConfig: sensoryElement = self.spatialMap[tuple(loc)] print sensoryElement, "%s : " % loc, printSequence(self.encodeSensoryInput(sensoryElement)) def printMotorCodingScheme(self): """ Print motor commands (displacement vector) along with their encoded versions. """ print "\nmotor coding scheme: " self.build(self.dim, []) def build(self, n, vec): """ Recursive function to help print motor coding scheme. """ for i in range(-self.maxDisplacement, self.maxDisplacement + 1): next = vec + [i] if n == 1: print "{:>5}\t".format(next), " = ", printSequence(self.encodeMotorInput(next)) else: self.build(n - 1, next)
def testCategoryEncoder(self): categories = ["ES", "GB", "US"] # forced: is not recommended, but is used here for readability. # see scalar.py e = CategoryEncoder(w=3, categoryList=categories, forced=True) output = e.encode("US") expected = numpy.array([0,0,0,0,0,0,0,0,0,1,1,1], dtype=defaultDtype) self.assertTrue(numpy.array_equal(output, expected)) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldNames), 1) self.assertEqual(len(fieldsDict), 1) self.assertEqual(fieldNames[0], fieldsDict.keys()[0]) (ranges, desc) = fieldsDict.values()[0] self.assertEqual(desc, "US") self.assertEqual(len(ranges), 1) self.assertTrue(numpy.array_equal(ranges[0], [3, 3])) # Test topdown compute for v in categories: output = e.encode(v) topDown = e.topDownCompute(output) self.assertEqual(topDown.value, v) self.assertEqual(topDown.scalar, e.getScalars(v)[0]) bucketIndices = e.getBucketIndices(v) topDown = e.getBucketInfo(bucketIndices)[0] self.assertEqual(topDown.value, v) self.assertEqual(topDown.scalar, e.getScalars(v)[0]) self.assertTrue(numpy.array_equal(topDown.encoding, output)) self.assertEqual(topDown.value, e.getBucketValues()[bucketIndices[0]]) # --------------------- # unknown category output = e.encode("NA") expected = numpy.array([1,1,1,0,0,0,0,0,0,0,0,0], dtype=defaultDtype) self.assertTrue(numpy.array_equal(output, expected)) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldNames), 1) self.assertEqual(len(fieldsDict), 1) self.assertEqual(fieldNames[0], fieldsDict.keys()[0]) (ranges, desc) = fieldsDict.values()[0] self.assertEqual(len(ranges), 1) self.assertTrue(numpy.array_equal(ranges[0], [0, 0])) # Test topdown compute topDown = e.topDownCompute(output) self.assertEqual(topDown.value, UNKNOWN) self.assertEqual(topDown.scalar, 0) # -------------------------------- # ES output = e.encode("ES") expected = numpy.array([0,0,0,1,1,1,0,0,0,0,0,0], dtype=defaultDtype) self.assertTrue(numpy.array_equal(output, expected)) # MISSING VALUE outputForMissing = e.encode(SENTINEL_VALUE_FOR_MISSING_DATA) self.assertEqual(sum(outputForMissing), 0) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldNames), 1) self.assertEqual(len(fieldsDict), 1) self.assertEqual(fieldNames[0], fieldsDict.keys()[0]) (ranges, desc) = fieldsDict.values()[0] self.assertEqual(len(ranges), 1) self.assertTrue(numpy.array_equal(ranges[0], [1, 1])) # Test topdown compute topDown = e.topDownCompute(output) self.assertEqual(topDown.value, "ES") self.assertEqual(topDown.scalar, e.getScalars("ES")[0]) # -------------------------------- # Multiple categories output.fill(1) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded self.assertEqual(len(fieldNames), 1) self.assertEqual(len(fieldsDict), 1) self.assertEqual(fieldNames[0], fieldsDict.keys()[0]) (ranges, desc) = fieldsDict.values()[0] self.assertEqual(len(ranges), 1) self.assertTrue(numpy.array_equal(ranges[0], [0, 3])) # ------------------------------------------------------------- # Test with width = 1 categories = ["cat1", "cat2", "cat3", "cat4", "cat5"] # forced: is not recommended, but is used here for readability. # see scalar.py e = CategoryEncoder(w=1, categoryList=categories, forced=True) for cat in categories: output = e.encode(cat) topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # ------------------------------------------------------------- # Test with width = 9, removing some bits end the encoded output categories = ["cat%d" % (x) for x in range(1, 10)] # forced: is not recommended, but is used here for readability. # see scalar.py e = CategoryEncoder(w=9, categoryList=categories, forced=True) for cat in categories: output = e.encode(cat) topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 1 bit on the left outputNZs = output.nonzero()[0] output[outputNZs[0]] = 0 topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 1 bit on the right output[outputNZs[0]] = 1 output[outputNZs[-1]] = 0 topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 4 bits on the left output.fill(0) output[outputNZs[-5:]] = 1 topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # Get rid of 4 bits on the right output.fill(0) output[outputNZs[0:5]] = 1 topDown = e.topDownCompute(output) self.assertEqual(topDown.value, cat) self.assertEqual(topDown.scalar, e.getScalars(cat)[0]) # OR together the output of 2 different categories, we should not get # back the mean, but rather one or the other output1 = e.encode("cat1") output2 = e.encode("cat9") output = output1 + output2 topDown = e.topDownCompute(output) self.assertTrue(topDown.scalar == e.getScalars("cat1")[0] \ or topDown.scalar == e.getScalars("cat9")[0])
def testCategoryEncoder(self): verbosity = 0 print "Testing CategoryEncoder...", categories = ["ES", "GB", "US"] e = CategoryEncoder(w=3, categoryList=categories) output = e.encode("US") assert (output == numpy.array([0,0,0,0,0,0,0,0,0,1,1,1], dtype=defaultDtype)).all() # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded assert len(fieldsDict) == 1 (ranges, desc) = fieldsDict.values()[0] assert len(ranges) == 1 and numpy.array_equal(ranges[0], [3,3]) print "decodedToStr of", ranges, "=>", e.decodedToStr(decoded) # Test topdown compute for v in categories: output = e.encode(v) topDown = e.topDownCompute(output) assert topDown.value == v assert topDown.scalar == e.getScalars(v)[0] bucketIndices = e.getBucketIndices(v) print "bucket index =>", bucketIndices[0] topDown = e.getBucketInfo(bucketIndices)[0] assert topDown.value == v assert topDown.scalar == e.getScalars(v)[0] assert (topDown.encoding == output).all() assert topDown.value == e.getBucketValues()[bucketIndices[0]] # --------------------- # unknown category output = e.encode("NA") assert (output == numpy.array([1,1,1,0,0,0,0,0,0,0,0,0], dtype=defaultDtype)).all() # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded assert len(fieldsDict) == 1 (ranges, desc) = fieldsDict.values()[0] assert len(ranges) == 1 and numpy.array_equal(ranges[0], [0,0]) print "decodedToStr of", ranges, "=>", e.decodedToStr(decoded) # Test topdown compute topDown = e.topDownCompute(output) assert topDown.value == "<UNKNOWN>" assert topDown.scalar == 0 # -------------------------------- # ES output = e.encode("ES") assert (output == numpy.array([0,0,0,1,1,1,0,0,0,0,0,0], dtype=defaultDtype)).all() # MISSING VALUE outputForMissing = e.encode(SENTINEL_VALUE_FOR_MISSING_DATA) assert sum(outputForMissing) == 0 # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded assert len(fieldsDict) == 1 (ranges, desc) = fieldsDict.values()[0] assert len(ranges) == 1 and numpy.array_equal(ranges[0], [1,1]) print "decodedToStr of", ranges, "=>", e.decodedToStr(decoded) # Test topdown compute topDown = e.topDownCompute(output) assert topDown.value == "ES" assert topDown.scalar == e.getScalars("ES")[0] # -------------------------------- # Multiple categories output.fill(1) # Test reverse lookup decoded = e.decode(output) (fieldsDict, fieldNames) = decoded assert len(fieldsDict) == 1 (ranges, desc) = fieldsDict.values()[0] assert len(ranges) == 1 and numpy.array_equal(ranges[0], [0,3]) print "decodedToStr of", ranges, "=>", e.decodedToStr(decoded) # ------------------------------------------------------------- # Test with width = 1 categories = ["cat1", "cat2", "cat3", "cat4", "cat5"] e = CategoryEncoder(w=1, categoryList=categories) for cat in categories: output = e.encode(cat) topDown = e.topDownCompute(output) if verbosity >= 1: print cat, "->", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown assert topDown.value == cat assert topDown.scalar == e.getScalars(cat)[0] # ------------------------------------------------------------- # Test with width = 9, removing some bits end the encoded output categories = ["cat%d" % (x) for x in range(1, 10)] e = CategoryEncoder(w=9, categoryList=categories) for cat in categories: output = e.encode(cat) topDown = e.topDownCompute(output) if verbosity >= 1: print cat, "->", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown assert topDown.value == cat assert topDown.scalar == e.getScalars(cat)[0] # Get rid of 1 bit on the left outputNZs = output.nonzero()[0] output[outputNZs[0]] = 0 topDown = e.topDownCompute(output) if verbosity >= 1: print "missing 1 bit on left:", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown assert topDown.value == cat assert topDown.scalar == e.getScalars(cat)[0] # Get rid of 1 bit on the right output[outputNZs[0]] = 1 output[outputNZs[-1]] = 0 topDown = e.topDownCompute(output) if verbosity >= 1: print "missing 1 bit on right:", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown assert topDown.value == cat assert topDown.scalar == e.getScalars(cat)[0] # Get rid of 4 bits on the left output.fill(0) output[outputNZs[-5:]] = 1 topDown = e.topDownCompute(output) if verbosity >= 1: print "missing 4 bits on left:", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown assert topDown.value == cat assert topDown.scalar == e.getScalars(cat)[0] # Get rid of 4 bits on the right output.fill(0) output[outputNZs[0:5]] = 1 topDown = e.topDownCompute(output) if verbosity >= 1: print "missing 4 bits on right:", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown assert topDown.value == cat assert topDown.scalar == e.getScalars(cat)[0] # OR together the output of 2 different categories, we should not get # back the mean, but rather one or the other output1 = e.encode("cat1") output2 = e.encode("cat9") output = output1 + output2 topDown = e.topDownCompute(output) if verbosity >= 1: print "cat1 + cat9 ->", output, output.nonzero()[0] print " scalarTopDown:", e.encoder.topDownCompute(output) print " topdown:", topDown assert topDown.scalar == e.getScalars("cat1")[0] \ or topDown.scalar == e.getScalars("cat9")[0] print "passed"
# print "now =", de.encode(now) # nextMonth = datetime.datetime.strptime("2014-06-02 13:08:58", "%Y-%m-%d %H:%M:%S") # print "next month =", de.encode(nextMonth) # xmas = datetime.datetime.strptime("2014-12-25 13:08:58", "%Y-%m-%d %H:%M:%S") # print "xmas =", de.encode(xmas) # Cateogry Encoding from nupic.encoders.category import CategoryEncoder categories = ("cat", "dog", "monkey", "mai") encoder = CategoryEncoder(w=3, categoryList=categories) cat = encoder.encode("cat") dog = encoder.encode("dog") monkey = encoder.encode("monkey") mai = encoder.encode("mai") print "cat =", cat print "dog =", dog print "monkey =", monkey print "mai =", mai print print "None =", encoder.encode(None) print "Unknown =", encoder.encode("unknown") print print "Decode cat", encoder.decode(cat) print "Decode dog", encoder.decode(dog) print "Decode monkey", encoder.decode(monkey) print "Decode mai", encoder.decode(mai) catdog = numpy.array([0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0]) print encoder.decode(catdog)
class SMSequences(object): """ Class generates sensorimotor sequences """ def __init__(self, sensoryInputElements, spatialConfig, sensoryInputElementsPool=list( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz0123456789"), minDisplacement=1, maxDisplacement=1, numActiveBitsSensoryInput=9, numActiveBitsMotorInput=9, seed=42, verbosity=False, useRandomEncoder=False): """ @param sensoryInputElements (list) Strings or numbers representing the sensory elements that exist in your world. Elements can be repeated if multiple of the same exist. @param spatialConfig (numpy.array) Array of size: (1, len(sensoryInputElements), dimension). It has a coordinate for every element in sensoryInputElements. @param sensoryInputElementsPool (list) List of strings representing a readable version of all possible sensory elements in this world. Elements don't need to be in any order and there should be no duplicates. By default this contains the set of alphanumeric characters. @param maxDisplacement (int) Maximum `distance` for a motor command. Distance is defined by the largest difference along any coordinate dimension. @param minDisplacement (int) Minimum `distance` for a motor command. Distance is defined by the largest difference along any coordinate dimension. @param numActiveBitsSensoryInput (int) Number of active bits for each sensory input. @param numActiveBitsMotorInput (int) Number of active bits for each dimension of the motor input. @param seed (int) Random seed for nupic.bindings.Random. @param verbosity (int) Verbosity @param useRandomEncoder (boolean) if True, use the random encoder SDRCategoryEncoder. If False, use CategoryEncoder. CategoryEncoder encodes categories using contiguous non-overlapping bits for each category, which makes it easier to debug. """ #--------------------------------------------------------------------------------- # Store creation parameters self.sensoryInputElements = sensoryInputElements self.sensoryInputElementsPool = sensoryInputElementsPool self.spatialConfig = spatialConfig.astype(int) self.spatialLength = len(spatialConfig) self.maxDisplacement = maxDisplacement self.minDisplacement = minDisplacement self.numActiveBitsSensoryInput = numActiveBitsSensoryInput self.numActiveBitsMotorInput = numActiveBitsMotorInput self.verbosity = verbosity self.seed = seed self.initialize(useRandomEncoder) def initialize(self, useRandomEncoder): """ Initialize the various data structures. """ self.setRandomSeed(self.seed) self.dim = numpy.shape(self.spatialConfig)[-1] self.spatialMap = dict( zip(map(tuple, list(self.spatialConfig)), self.sensoryInputElements)) self.lengthMotorInput1D = (2*self.maxDisplacement + 1) * \ self.numActiveBitsMotorInput uniqueSensoryElements = list(set(self.sensoryInputElementsPool)) if useRandomEncoder: self.sensoryEncoder = SDRCategoryEncoder( n=1024, w=self.numActiveBitsSensoryInput, categoryList=uniqueSensoryElements, forced=True) self.lengthSensoryInput = self.sensoryEncoder.getWidth() else: self.lengthSensoryInput = (len(self.sensoryInputElementsPool)+1) * \ self.numActiveBitsSensoryInput self.sensoryEncoder = CategoryEncoder( w=self.numActiveBitsSensoryInput, categoryList=uniqueSensoryElements, forced=True) motorEncoder1D = ScalarEncoder(n=self.lengthMotorInput1D, w=self.numActiveBitsMotorInput, minval=-self.maxDisplacement, maxval=self.maxDisplacement, clipInput=True, forced=True) self.motorEncoder = VectorEncoder(length=self.dim, encoder=motorEncoder1D) def generateSensorimotorSequence(self, sequenceLength): """ Generate sensorimotor sequences of length sequenceLength. @param sequenceLength (int) Length of the sensorimotor sequence. @return (tuple) Contains: sensorySequence (list) Encoded sensory input for whole sequence. motorSequence (list) Encoded motor input for whole sequence. sensorimotorSequence (list) Encoder sensorimotor input for whole sequence. This is useful when you want to give external input to temporal memory. """ motorSequence = [] sensorySequence = [] sensorimotorSequence = [] currentEyeLoc = self.nupicRandomChoice(self.spatialConfig) for i in xrange(sequenceLength): currentSensoryInput = self.spatialMap[tuple(currentEyeLoc)] nextEyeLoc, currentEyeV = self.getNextEyeLocation(currentEyeLoc) if self.verbosity: print "sensory input = ", currentSensoryInput, \ "eye location = ", currentEyeLoc, \ " motor command = ", currentEyeV sensoryInput = self.encodeSensoryInput(currentSensoryInput) motorInput = self.encodeMotorInput(list(currentEyeV)) sensorimotorInput = numpy.concatenate((sensoryInput, motorInput)) sensorySequence.append(sensoryInput) motorSequence.append(motorInput) sensorimotorSequence.append(sensorimotorInput) currentEyeLoc = nextEyeLoc return (sensorySequence, motorSequence, sensorimotorSequence) def encodeSensorimotorSequence(self, eyeLocs): """ Encode sensorimotor sequence given the eye movements. Sequence will have length len(eyeLocs) - 1 because only the differences of eye locations can be used to encoder motor commands. @param eyeLocs (list) Numpy coordinates describing where the eye is looking. @return (tuple) Contains: sensorySequence (list) Encoded sensory input for whole sequence. motorSequence (list) Encoded motor input for whole sequence. sensorimotorSequence (list) Encoder sensorimotor input for whole sequence. This is useful when you want to give external input to temporal memory. """ sequenceLength = len(eyeLocs) - 1 motorSequence = [] sensorySequence = [] sensorimotorSequence = [] for i in xrange(sequenceLength): currentEyeLoc = eyeLocs[i] nextEyeLoc = eyeLocs[i + 1] currentSensoryInput = self.spatialMap[currentEyeLoc] currentEyeV = nextEyeLoc - currentEyeLoc if self.verbosity: print "sensory input = ", currentSensoryInput, \ "eye location = ", currentEyeLoc, \ " motor command = ", currentEyeV sensoryInput = self.encodeSensoryInput(currentSensoryInput) motorInput = self.encodeMotorInput(list(currentEyeV)) sensorimotorInput = numpy.concatenate((sensoryInput, motorInput)) sensorySequence.append(sensoryInput) motorSequence.append(motorInput) sensorimotorSequence.append(sensorimotorInput) return (sensorySequence, motorSequence, sensorimotorSequence) def getNextEyeLocation(self, currentEyeLoc): """ Generate next eye location based on current eye location. @param currentEyeLoc (numpy.array) Current coordinate describing the eye location in the world. @return (tuple) Contains: nextEyeLoc (numpy.array) Coordinate of the next eye location. eyeDiff (numpy.array) Vector describing change from currentEyeLoc to nextEyeLoc. """ possibleEyeLocs = [] for loc in self.spatialConfig: shift = abs(max(loc - currentEyeLoc)) if self.minDisplacement <= shift <= self.maxDisplacement: possibleEyeLocs.append(loc) nextEyeLoc = self.nupicRandomChoice(possibleEyeLocs) eyeDiff = nextEyeLoc - currentEyeLoc return nextEyeLoc, eyeDiff def setRandomSeed(self, seed): """ Reset the nupic random generator. This is necessary to reset random seed to generate new sequences. @param seed (int) Seed for nupic.bindings.Random. """ self.seed = seed self._random = Random() self._random.setSeed(seed) def nupicRandomChoice(self, array): """ Chooses a random element from an array using the nupic random number generator. @param array (list or numpy.array) Array to choose random element from. @return (element) Element chosen at random. """ return array[self._random.getUInt32(len(array))] def encodeMotorInput(self, motorInput): """ Encode motor command to bit vector. @param motorInput (1D numpy.array) Motor command to be encoded. @return (1D numpy.array) Encoded motor command. """ if not hasattr(motorInput, "__iter__"): motorInput = list([motorInput]) return self.motorEncoder.encode(motorInput) def decodeMotorInput(self, motorInputPattern): """ Decode motor command from bit vector. @param motorInputPattern (1D numpy.array) Encoded motor command. @return (1D numpy.array) Decoded motor command. """ key = self.motorEncoder.decode(motorInputPattern)[0].keys()[0] motorCommand = self.motorEncoder.decode( motorInputPattern)[0][key][1][0] return motorCommand def encodeSensoryInput(self, sensoryInputElement): """ Encode sensory input to bit vector @param sensoryElement (1D numpy.array) Sensory element to be encoded. @return (1D numpy.array) Encoded sensory element. """ return self.sensoryEncoder.encode(sensoryInputElement) def decodeSensoryInput(self, sensoryInputPattern): """ Decode sensory input from bit vector. @param sensoryInputPattern (1D numpy.array) Encoded sensory element. @return (1D numpy.array) Decoded sensory element. """ return self.sensoryEncoder.decode( sensoryInputPattern)[0]['category'][1] def printSensoryCodingScheme(self): """ Print sensory inputs along with their encoded versions. """ print "\nsensory coding scheme: " for loc in self.spatialConfig: sensoryElement = self.spatialMap[tuple(loc)] print sensoryElement, "%s : " % loc, printSequence(self.encodeSensoryInput(sensoryElement)) def printMotorCodingScheme(self): """ Print motor commands (displacement vector) along with their encoded versions. """ print "\nmotor coding scheme: " self.build(self.dim, []) def build(self, n, vec): """ Recursive function to help print motor coding scheme. """ for i in range(-self.maxDisplacement, self.maxDisplacement + 1): next = vec + [i] if n == 1: print '{:>5}\t'.format(next), " = ", printSequence(self.encodeMotorInput(next)) else: self.build(n - 1, next)