CharlesCNorton
commited on
Commit
·
aaa3ac0
0
Parent(s):
8:1 multiplexer threshold circuit, magnitude 61
Browse files- README.md +88 -0
- config.json +9 -0
- create_safetensors.py +67 -0
- model.py +24 -0
- model.safetensors +0 -0
README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
tags:
|
| 4 |
+
- pytorch
|
| 5 |
+
- safetensors
|
| 6 |
+
- threshold-logic
|
| 7 |
+
- neuromorphic
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# threshold-mux8
|
| 11 |
+
|
| 12 |
+
8:1 multiplexer. Selects one of 8 data inputs based on 3-bit select signal.
|
| 13 |
+
|
| 14 |
+
## Function
|
| 15 |
+
|
| 16 |
+
MUX8(d0-d7, s2,s1,s0) = d[s] where s = 4*s2 + 2*s1 + s0
|
| 17 |
+
|
| 18 |
+
## Architecture
|
| 19 |
+
|
| 20 |
+
```
|
| 21 |
+
d0 d1 d2 d3 d4 d5 d6 d7 s2 s1 s0
|
| 22 |
+
| | | | | | | | | | |
|
| 23 |
+
+--+--+--+--+--+--+--+----+--+--+
|
| 24 |
+
| |
|
| 25 |
+
v v
|
| 26 |
+
[N0] d0 AND (s=000) ----+
|
| 27 |
+
[N1] d1 AND (s=001) ----|
|
| 28 |
+
[N2] d2 AND (s=010) ----|
|
| 29 |
+
[N3] d3 AND (s=011) ----+---> [OR] ---> output
|
| 30 |
+
[N4] d4 AND (s=100) ----|
|
| 31 |
+
[N5] d5 AND (s=101) ----|
|
| 32 |
+
[N6] d6 AND (s=110) ----|
|
| 33 |
+
[N7] d7 AND (s=111) ----+
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
## Parameters
|
| 37 |
+
|
| 38 |
+
| | |
|
| 39 |
+
|---|---|
|
| 40 |
+
| Inputs | 11 (8 data + 3 select) |
|
| 41 |
+
| Outputs | 1 |
|
| 42 |
+
| Neurons | 9 |
|
| 43 |
+
| Layers | 2 |
|
| 44 |
+
| Parameters | 105 |
|
| 45 |
+
| Magnitude | 61 |
|
| 46 |
+
|
| 47 |
+
## Layer 1 Weights
|
| 48 |
+
|
| 49 |
+
Each neuron Ni fires when di=1 AND s=i:
|
| 50 |
+
|
| 51 |
+
| Neuron | Data weights | Select weights (s2,s1,s0) | Bias |
|
| 52 |
+
|--------|--------------|---------------------------|------|
|
| 53 |
+
| N0 | d0=1 | [-1,-1,-1] | -1 |
|
| 54 |
+
| N1 | d1=1 | [-1,-1,+1] | -2 |
|
| 55 |
+
| N2 | d2=1 | [-1,+1,-1] | -2 |
|
| 56 |
+
| N3 | d3=1 | [-1,+1,+1] | -3 |
|
| 57 |
+
| N4 | d4=1 | [+1,-1,-1] | -2 |
|
| 58 |
+
| N5 | d5=1 | [+1,-1,+1] | -3 |
|
| 59 |
+
| N6 | d6=1 | [+1,+1,-1] | -3 |
|
| 60 |
+
| N7 | d7=1 | [+1,+1,+1] | -4 |
|
| 61 |
+
|
| 62 |
+
## Layer 2
|
| 63 |
+
|
| 64 |
+
OR gate: weights [1,1,1,1,1,1,1,1], bias -1
|
| 65 |
+
|
| 66 |
+
## Usage
|
| 67 |
+
|
| 68 |
+
```python
|
| 69 |
+
from safetensors.torch import load_file
|
| 70 |
+
import torch
|
| 71 |
+
|
| 72 |
+
w = load_file('model.safetensors')
|
| 73 |
+
|
| 74 |
+
def mux8(d0, d1, d2, d3, d4, d5, d6, d7, s2, s1, s0):
|
| 75 |
+
inp = torch.tensor([float(d0), float(d1), float(d2), float(d3),
|
| 76 |
+
float(d4), float(d5), float(d6), float(d7),
|
| 77 |
+
float(s2), float(s1), float(s0)])
|
| 78 |
+
l1 = (inp @ w['layer1.weight'].T + w['layer1.bias'] >= 0).float()
|
| 79 |
+
out = (l1 @ w['layer2.weight'].T + w['layer2.bias'] >= 0).float()
|
| 80 |
+
return int(out.item())
|
| 81 |
+
|
| 82 |
+
# Select d5 (s=101)
|
| 83 |
+
print(mux8(0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1)) # 1
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
## License
|
| 87 |
+
|
| 88 |
+
MIT
|
config.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "threshold-mux8",
|
| 3 |
+
"description": "8:1 multiplexer as threshold circuit",
|
| 4 |
+
"inputs": 11,
|
| 5 |
+
"outputs": 1,
|
| 6 |
+
"neurons": 9,
|
| 7 |
+
"layers": 2,
|
| 8 |
+
"parameters": 105
|
| 9 |
+
}
|
create_safetensors.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from safetensors.torch import save_file
|
| 3 |
+
|
| 4 |
+
weights = {}
|
| 5 |
+
|
| 6 |
+
# Input order: d0, d1, d2, d3, d4, d5, d6, d7, s2, s1, s0 (11 inputs)
|
| 7 |
+
# Layer 1: 8 neurons, each selects di when s = i
|
| 8 |
+
# Layer 2: OR gate combining all 8
|
| 9 |
+
|
| 10 |
+
layer1_weights = []
|
| 11 |
+
layer1_biases = []
|
| 12 |
+
|
| 13 |
+
for i in range(8):
|
| 14 |
+
w = [0.0] * 11
|
| 15 |
+
# Data input weight
|
| 16 |
+
w[i] = 1.0
|
| 17 |
+
# Select weights: +1 if bit should be 1, -1 if bit should be 0
|
| 18 |
+
s2_bit = (i >> 2) & 1
|
| 19 |
+
s1_bit = (i >> 1) & 1
|
| 20 |
+
s0_bit = i & 1
|
| 21 |
+
w[8] = 1.0 if s2_bit else -1.0 # s2
|
| 22 |
+
w[9] = 1.0 if s1_bit else -1.0 # s1
|
| 23 |
+
w[10] = 1.0 if s0_bit else -1.0 # s0
|
| 24 |
+
# Bias: -(1 + popcount(i))
|
| 25 |
+
bias = -(1 + bin(i).count('1'))
|
| 26 |
+
layer1_weights.append(w)
|
| 27 |
+
layer1_biases.append(bias)
|
| 28 |
+
|
| 29 |
+
weights['layer1.weight'] = torch.tensor(layer1_weights, dtype=torch.float32)
|
| 30 |
+
weights['layer1.bias'] = torch.tensor(layer1_biases, dtype=torch.float32)
|
| 31 |
+
|
| 32 |
+
# Layer 2: OR gate
|
| 33 |
+
weights['layer2.weight'] = torch.tensor([[1.0] * 8], dtype=torch.float32)
|
| 34 |
+
weights['layer2.bias'] = torch.tensor([-1.0], dtype=torch.float32)
|
| 35 |
+
|
| 36 |
+
save_file(weights, 'model.safetensors')
|
| 37 |
+
|
| 38 |
+
# Verify
|
| 39 |
+
def mux8(d0, d1, d2, d3, d4, d5, d6, d7, s2, s1, s0):
|
| 40 |
+
inp = torch.tensor([float(d0), float(d1), float(d2), float(d3),
|
| 41 |
+
float(d4), float(d5), float(d6), float(d7),
|
| 42 |
+
float(s2), float(s1), float(s0)])
|
| 43 |
+
l1 = (inp @ weights['layer1.weight'].T + weights['layer1.bias'] >= 0).float()
|
| 44 |
+
out = (l1 @ weights['layer2.weight'].T + weights['layer2.bias'] >= 0).float()
|
| 45 |
+
return int(out.item())
|
| 46 |
+
|
| 47 |
+
print("Verifying MUX8...")
|
| 48 |
+
errors = 0
|
| 49 |
+
for s in range(8):
|
| 50 |
+
s2, s1, s0 = (s >> 2) & 1, (s >> 1) & 1, s & 1
|
| 51 |
+
for d_vals in range(256):
|
| 52 |
+
d = [(d_vals >> i) & 1 for i in range(8)]
|
| 53 |
+
result = mux8(*d, s2, s1, s0)
|
| 54 |
+
expected = d[s]
|
| 55 |
+
if result != expected:
|
| 56 |
+
errors += 1
|
| 57 |
+
if errors <= 5:
|
| 58 |
+
print(f"ERROR: s={s}, d={d}, got {result}, expected {expected}")
|
| 59 |
+
|
| 60 |
+
if errors == 0:
|
| 61 |
+
print("All 2048 test cases passed!")
|
| 62 |
+
else:
|
| 63 |
+
print(f"FAILED: {errors} errors")
|
| 64 |
+
|
| 65 |
+
# Print magnitude
|
| 66 |
+
mag = sum(t.abs().sum().item() for t in weights.values())
|
| 67 |
+
print(f"Magnitude: {mag:.0f}")
|
model.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from safetensors.torch import load_file
|
| 3 |
+
|
| 4 |
+
def load_model(path='model.safetensors'):
|
| 5 |
+
return load_file(path)
|
| 6 |
+
|
| 7 |
+
def mux8(d0, d1, d2, d3, d4, d5, d6, d7, s2, s1, s0, weights):
|
| 8 |
+
"""8:1 Multiplexer: returns d[s] where s = 4*s2 + 2*s1 + s0"""
|
| 9 |
+
inp = torch.tensor([float(d0), float(d1), float(d2), float(d3),
|
| 10 |
+
float(d4), float(d5), float(d6), float(d7),
|
| 11 |
+
float(s2), float(s1), float(s0)])
|
| 12 |
+
l1 = (inp @ weights['layer1.weight'].T + weights['layer1.bias'] >= 0).float()
|
| 13 |
+
out = (l1 @ weights['layer2.weight'].T + weights['layer2.bias'] >= 0).float()
|
| 14 |
+
return int(out.item())
|
| 15 |
+
|
| 16 |
+
if __name__ == '__main__':
|
| 17 |
+
w = load_model()
|
| 18 |
+
print('MUX8 verification:')
|
| 19 |
+
for s in range(8):
|
| 20 |
+
s2, s1, s0 = (s >> 2) & 1, (s >> 1) & 1, s & 1
|
| 21 |
+
d = [0] * 8
|
| 22 |
+
d[s] = 1
|
| 23 |
+
result = mux8(*d, s2, s1, s0, w)
|
| 24 |
+
print(f' s={s} ({s2}{s1}{s0}), d[{s}]=1 -> {result}')
|
model.safetensors
ADDED
|
Binary file (708 Bytes). View file
|
|
|