# Reverse Engineering a Neural Community’s Intelligent Resolution to Binary Addition

*by*Phil Tadros

There is a ton of consideration recently on large neural networks with billions of parameters, and rightly so. By combining large parameter counts with highly effective architectures like transformers and diffusion, neural networks are able to conducting astounding feats.

Nonetheless, even small networks might be surprisingly efficient – particularly after they’re particularly designed for a specialised use-case. As a part of some previous work I did, I used to be coaching small (<1000 parameter) networks to generate sequence-to-sequence mappings and carry out different easy logic duties. I needed the fashions to be as small and easy as doable with the aim of constructing little interactive visualizations of their inner states.

After discovering good success on quite simple issues, I attempted coaching neural networks to carry out binary addition. The networks would obtain the bits for 2 8-bit unsigned integers as enter (transformed the bits to floats as -1 for binary 0 and +1 for binary 1) and could be anticipated to supply properly-added output, together with dealing with wrapping of overflows.

```
Coaching instance in binary:
01001011 + 11010110 -> 00100001
As enter/output vectors for NN coaching:
enter: [-1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1]
output: [-1, -1, 1, -1, -1, -1, -1, 1]
```

What I hoped/imagined the community would be taught internally is one thing akin to a binary adder circuit:

I anticipated that it might determine the relationships between completely different bits within the enter and output, route them round as wanted, and use the neurons as logic gates – which I might seen occur up to now for different issues I examined.

## Coaching the Community

To begin out, I created a community with a fairly beneficiant structure that had 5 layers and a number of other thousand parameters. Nonetheless, I wasn’t positive even that was sufficient. The logic circuit diagram above for the binary adder solely handles a single bit; including 8 bits to eight bits would require a a lot bigger variety of gates, and the community must mannequin all of them.

Moreover, I wasn’t positive how the community would deal with lengthy chains of carries. When including `11111111 + 00000001`

, for instance, it wraps and produces an output of `00000000`

. To ensure that that to occur, the carry from the least-significant bit must propagate throughout the adder to the most-significant bit. I assumed that there was probability the community would want a minimum of 8 layers as a way to facilitate this type of habits.

Regardless that I wasn’t positive if it was going to have the ability to be taught something in any respect, I began off coaching the mannequin.

I created coaching knowledge by producing random 8-bit unsigned integers and including them along with wrapping. Along with the loss computed throughout coaching of the community, I additionally added code to validate the community’s accuracy on all 32,385 doable enter combos periodically throughout coaching to get a really feel for the way effectively it was doing total.

After some tuning of hyperparameters like studying charge and batch measurement, I used to be shocked to see that the mannequin was studying extraordinarily effectively! I used to be in a position to get it to the purpose the place it was converging to excellent or practically excellent options virtually each coaching run.

I needed to know what the community was doing internally to generate its options. The networks I used to be coaching had been fairly severely overparameterized for the duty at hand; it was very troublesome to get a grasp of what they had been doing by means of the tens of 1000’s of weights and biases. So, I began trimming the community down – eradicating layers and decreasing the variety of neurons in every layer.

To my continued shock, it stored working! In some unspecified time in the future excellent options grew to become much less widespread as networks change into depending on the luck of their beginning parameters, however I used to be in a position to get it to be taught excellent options with as few as 3 layers with neuron counts of 12, 10, and eight respectively:

```
Layer (sort) Enter Form Output form Param #
===========================================================
input1 (InputLayer) [[null,16]] [null,16] 0
___________________________________________________________
dense_Dense1 (Dense) [[null,16]] [null,12] 204
___________________________________________________________
dense_Dense2 (Dense) [[null,12]] [null,10] 130
___________________________________________________________
dense_Dense3 (Dense) [[null,10]] [null,8] 88
===========================================================
```

That is simply 422 whole parameters! I did not anticipate that the community would be capable to be taught an advanced operate like binary addition with that few.

It appeared too good to be true, to be sincere, and I needed to ensure I wasn’t making some mistake with the way in which I used to be coaching the community or validating its outputs. A overview of my instance era code and coaching pipeline did not reveal something that regarded off, so the subsequent step was to really check out the parameters after a profitable coaching run.

## Distinctive Activation Capabilities

One necessary factor to notice at this level is the activation capabilities used for the completely different layers within the mannequin. A part of my earlier work on this space consisted of designing and implementing a brand new activation operate to be used in neural networks with the aim of doing binary logic as effectively as doable. Amongst different issues, it’s able to modeling any 2-input boolean operate in a single neuron – that means that it solves the XOR drawback.

You possibly can examine it in additional element in my other post, however this is what it seems to be like:

It seems to be a bit like a single interval of a flattened sine wave, and it has a pair controllable parameters to configure how flat it’s and the way it handles out-of-range inputs.

For the fashions I used to be coaching for binary addition, all of them used this activation operate (which I named Ameo) within the first layer and used `tanh`

for all the opposite layers.

## Dissecting the Mannequin

Though the variety of parameters was now fairly manageable, I could not discern what was happening simply by taking a look at them. Nonetheless, I did discover that there have been a number of parameters that had been very near “spherical” values like 0, 1, 0.5, -0.25, and so on.

Since a number of the logic gates I might modeled beforehand had been produced with parameters akin to these, I figured that could be factor to concentrate on to search out the sign within the noise.

I added some rounding and clamping that was utilized to all community parameters nearer than some threshold to these spherical values. I utilized it periodically all through coaching, giving the optimizer a while to regulate to the adjustments in between. After repeating a number of instances and ready for the community to converge to an ideal resolution once more, some clear patterns began to emerge:

```
layer 0 weights:
[[0 , 0 , 0.1942478 , 0.3666477, -0.0273195, 1 , 0.4076445 , 0.25 , 0.125 , -0.0775111, 0 , 0.0610434],
[0 , 0 , 0.3904364 , 0.7304437, -0.0552268, -0.0209046, 0.8210054 , 0.5 , 0.25 , -0.1582894, -0.0270081, 0.125 ],
[0 , 0 , 0.7264696 , 1.4563066, -0.1063093, -0.2293 , 1.6488117 , 1 , 0.4655252, -0.3091895, -0.051915 , 0.25 ],
[0.0195805 , -0.1917275, 0.0501585 , 0.0484147, -0.25 , 0.1403822 , -0.0459261, 1.0557909, -1 , -0.5 , -0.125 , 0.5 ],
[-0.1013674, -0.125 , 0 , 0 , -0.4704586, 0 , 0 , 0 , 0 , -1 , -0.25 , -1 ],
[-0.25 , -0.25 , 0 , 0 , -1 , 0 , 0 , 0 , 0 , 0.2798074 , -0.5 , 0 ],
[-0.5 , -0.5226266, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0.5 , -1 , 0 ],
[1 , -0.9827325, 0 , 0 , 0 , 0 , 0 , 0 , 0 , -1 , 0 , 0 ],
[0 , 0 , 0.1848682 , 0.3591821, -0.026541 , -1.0401837, 0.4050815 , 0.25 , 0.125 , -0.0777296, 0 , 0.0616584],
[0 , 0 , 0.3899804 , 0.7313382, -0.0548765, -0.021433 , 0.8209481 , 0.5 , 0.25 , -0.156925 , -0.0267142, 0.125 ],
[0 , 0 , 0.7257989 , 1.4584024, -0.1054092, -0.2270812, 1.6465081 , 1 , 0.4654536, -0.3099159, -0.0511372, 0.25 ],
[-0.125 , 0.069297 , -0.0477796, 0.0764982, -0.2324274, -0.1522287, -0.0539475, -1 , 1 , -0.5 , -0.125 , 0.5 ],
[-0.1006763, -0.125 , 0 , 0 , -0.4704363, 0 , 0 , 0 , 0 , -1 , -0.25 , 1 ],
[-0.25 , -0.25 , 0 , 0 , -1 , 0 , 0 , 0 , 0 , 0.2754751 , -0.5 , 0 ],
[-0.5 , -0.520548 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0.5 , 1 , 0 ],
[-1 , -1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , -1 , 0 , 0 ]]
layer 0 biases:
[0 , 0 , -0.1824367,-0.3596431, 0.0269886 , 1.0454538 , -0.4033574, -0.25 , -0.125 , 0.0803178 , 0 , -0.0613749]
```

Above are the ultimate weights generated for the primary layer of the community after the clamping and rounding. Every column represents the parameters for a single neuron, that means that the primary 8 weights from high to backside are utilized to bits from the primary enter quantity and the subsequent 8 are utilized to bits from the second.

All of those neurons have ended up in a really related state. There’s a sample of doubling the weights as they transfer down the road and matching up weights between corresponding bits of each inputs. The bias was chosen to match the bottom weight in magnitude. Totally different neurons had completely different bases for the multipliers and completely different offsets for beginning digit.

## The Community’s Intelligent Resolution

After puzzling over that for some time, I finally began to grasp how its resolution labored.

Digital to analog converters (DACs) are digital circuits that take digital indicators cut up into a number of enter bits and convert them right into a single analog output sign.

DACs are utilized in purposes like audio playback the place a sound information are represented by numbers saved in reminiscence. DACs take these binary values and convert them to an analog sign which is used to energy the audio system, figuring out their place and vibrating the air to supply sound. For instance, the Nintendo Recreation Boy had a 4-bit DAC for every of its two output audio channels.

Here is an instance circuit diagram for a DAC:

If you happen to take a look at the resistances of the resistors connected to every of the bits of the binary enter, you possibly can see that they double from one enter to a different from the least vital bit to probably the most vital. That is extraordinarily much like what the community realized to do with the weights of the enter layer. The principle distinction is that the weights are duplicated between every of the 2 8-bit inputs.

This enables the community to each sum the inputs in addition to convert the sum to analog all inside a single layer/neuron and do all of it earlier than any activation capabilities even come into play.

This was solely a part of the puzzle, although. As soon as the digital inputs had been transformed to analog and summed collectively, they had been instantly handed by means of the neuron’s activation operate. To assist monitor down what occurred subsequent, I plotted the post-activation outputs of some of the neurons within the first layer because the inputs elevated:

The neurons appeared to be producing sine wave-like outputs that modified easily because the sum of the binary inputs elevated. Totally different neurons had completely different durations; those pictured above have durations of 8, 4, and 32 respectively. Different neurons had completely different durations or had been offset by sure distances.

There’s one thing very exceptional about this sample: they map on to the durations at which completely different binary digits swap between 0 and 1 when counting in binary. The least vital digit switches between 0 and 1 with a interval of 1, the second with a interval of two, and so forth to 4, 8, 16, 32, and so on. Which means for a minimum of a few of the output bits, the community had realized to compute all the pieces it wanted in a single neuron.

Trying on the weights of neurons within the two later layers confirms this to be the case. The later layers are principally involved with routing across the outputs from the primary layer and mixing them. One further profit that these layers present is “saturating” the indicators and making them extra sq. wave-like – pushing them nearer to the goal values of -1 and 1 for all values. That is the very same property which is utilized in digital sign processing for audio synthesis the place `tanh`

is used so as to add distortion to sound for issues like guitar pedals.

Whereas taking part in round with this setup, I attempted re-training the community with the activation operate for the primary layer changed with `sin(x)`

and it finally ends up working just about the identical approach. Apparently, the weights realized in that case are fractions of π moderately than 1.

For different output digits, the community realized to do some over intelligent issues to generate the output indicators it wanted. For instance, it mixed outputs from the primary layer in such a approach that it was in a position to produce a shifted model of the sign not current in any of the first-layer neurons by including indicators from different neurons with completely different durations collectively. It labored out fairly effectively, greater than correct sufficient for the aim of the community.

The sine-based model of the operate realized by the community (blue) finally ends up being roughly equal to the operate `sin(1/2x + pi)`

(orange):

I don’t know if that is simply one other random mathematical coincidence or a part of some infinite collection or one thing, but it surely’s very neat regardless.

### Abstract

**So, in all, the community was conducting binary addition by**:

- Changing the binary inputs into “analog” utilizing a model of a digital to audio converter carried out utilizing the weights of the enter layer
- Mapping that inner analog sign into periodic sine wave-like indicators utilizing the Ameo activation operate (regardless that that activation operate is not periodic)
- Saturating the sine wave-like sign to make it extra like a sq. wave so outputs are as shut as doable to the anticipated values of -1 and 1 for all outputs

As I discussed, earlier than, I had imagined the community studying some fancy mixture of logic gates to carry out the entire addition course of digitally, equally to how a binary adder operates. This trick is yet one more instance of neural networks discovering surprising methods to resolve issues.

## Epilogue

One thought that occurred to me after this investigation was the premise that the immense bleeding-edge fashions of immediately with billions of parameters may be capable to be constructed utilizing orders of magnitude fewer community sources through the use of extra environment friendly or custom-designed architectures.

It is an thrilling prospect to make sure, however my pleasure is considerably dulled as a result of I used to be instantly reminded of The Bitter Lesson. If you happen to’ve not learn it, you must learn it now (it’s extremely brief); it actually impacted the way in which I take a look at computing and programming.

Even when this specific resolution was only a fluke of my community structure or the system being modeled, it made me much more impressed by the ability and flexibility of gradient descent and related optimization algorithms. The truth that these very specific patterns might be introduced into existence so persistently from pure randomness is admittedly superb to me.

I plan to proceed my work with small neural networks and ultimately create these visualizations I used to be speaking about. If you happen to’re , you possibly can subscribe to my weblog through RSS on the high of the web page, comply with me on Twitter @ameobea10, or Mastodon @ameo@mastodon.ameo.dev.