Sensor-to-Output Mapping with a Bit-Net

The bit-net is a neural-like net using single-bit weights and is essentially a wire-or map between the inputs and outputs. This arrangement can store specific patterns only if one input bit is on at a time, which for simple robotics applications is nearly the case. Relaxing the rules to just "anything that works" takes care of the rest and allows the network to settle into a solution. The result is a tiny array of connection bits that function as a self-organizing brain that learns to map sensors to outputs in whatever way results in unobstructed operation and appropriate behavior.

Traditional neural nets are... well too darn complicated and require too much memory for connection strengths to ever hope to implement on a PIC16C56 processor with only about 24 bytes of RAM available - yikes. My past approach, for both traditional and walker robots, was to use an 8 pin EEPROM chip to hold the memories and rather than neural nets just take a guess and if it works remember it otherwise guess again. It only accesses the memory about every four seconds or so and only writes if the previous memory failed so chip burnout wasn't too much of a concern, would last months to years. A typical neural net would burn the chip out in a week and be seriously slowed down by the snail's pace writes. OK when just writing one byte but a NN might have to write dozens to do the same thing. Have to get it entirely inside the processor to use. What to do...

What I ended up with can't really be called a neural net, it more closely resembles a diode-board that rewires itself spontaniously to produce workable output in a given situation. Much simpler and hopefully able to exibit more learning from the environment than from internal software "features".

To test these ideas I coded this QBasic simulation for MSDOS systems and a slightly modified version that converges much faster even with more output exclusions (discussion to follow). This is the version which learns to produce good output the hard way...

The simulated target application is the control of a nervous network walker with a four-neuron "microcore" with two motors and a reversing circuit (see also the BEAM Faq and my implementations Robot2 and Robot3). The rules are in effect only when the Train option is used, if manually trained by applying the Bad signal, the inputs and outputs could represent anything.

The input box shows signals on the Photo L>R and Dark R inputs, with the outputs activating nodes 2, 3 and 4. The outputs are a combination of stored bit patterns for the two inputs, L>R activates nodes 3 and 4, and Dark R activates node 2. If for some reason this is not desirable output (like ran into the wall on the next turn) then the "bad" training signal will cause it to produce different output the next time. All I've attempted to model in this simulation are the rules governing desirable output combinations, you can act as the "world" and deliver manual training signals using the Bad option. The Input option allows entering of specific input patterns as a string of 1s and 0s, for example enter 11000000 for Feeler L, Dark L. The Train option trains the network on random input data, evaluating and adjusting the output to satisfy the pre-programmed walker-robot rules. Note - the labeling of the inputs and outputs only applies when training via the Train option, otherwise the bits could mean anything. Reset scrambles all of the bits for starting over, Quit exits the program. When training, the input status, move evaluation and percent correct are updated in real time. If the rules aren't too restrictive, the network will quickly converge to 100% correct output. Press any key to exit training mode and display the menu.

After converging on a solution, individual memories can be altered without affecting others so long as the new memories don't conflict with the rules. It cannot solve AND-type problems, but that can be taken care of by preprocessing the input. The Front Feeler input in my particular walking robot is actually applied to both feeler inputs through diodes to save on input pins. Internally this is broken back into separate bits for left, right and forward with no more than one on at a time (but not in the demo, it treats forward as a separate switch but does simulate the one-at-a-time aspect of the differential photo inputs). I could decouple the forward switch and directly connect it, since I have a couple of free inputs thanks to ditching the eeprom, but this matters little - I don't care if both feelers touching is equivalent to the forward switch, actually makes it better since I can angle the feelers forward and let the actual forward switch take over only when it gets really close.

This type of neural network is perfect for simple robotic control applications, it's the first adapting network I've seen that comes close to being doable entirely on a PIC. The big question is whether something so simple can remember enough to handle it's primary mission - not get stuck and respond to its environment - but I suspect it will. The reason I suspect it will is most walker sensors are just hardwired to the microcore nodes and that works - pre-processing the sensors to mean individual things and a self-adapting wiring matrix should work that much better, yet any particular solution can be hardwired with a bunch of diodes and resistors. Would have to do the photo-processing in analog and it would take up far more space than the PIC, but it's conceptually simple and more BEAM-like than my previous robot-brains.


Was fooling around and thought why should the random bit flipper set bits that it can know would violate the rules? By adding one line of code, the modified simulation converges much faster, even when simulating a larger input/output space with tougher constraints. And more importantly, changes to the network induced by the environment do not trigger large-scale re-convergence, since it picks actions that will already pass the output constraint rules. Might be cheating just a bit, but who cares if it allows the robot to concentrate on learning the environment rather than how to satisfy a move evaluator.

In a burst of coding activity, I finally got a prototype bit-net onto a PIC chip, ended up being less than 512 instructions even with sleep code. The current PIC version will be updated as it changes (code is rarely final with me). The initial version exibited learning ability on the very first run, despite its bugs. Psuedo-code for the implementation is listed in the source.