Upload folder using huggingface_hub
Browse files- README.md +75 -75
- config.json +9 -9
- create_safetensors.py +75 -75
- model.py +22 -22
README.md
CHANGED
|
@@ -1,75 +1,75 @@
|
|
| 1 |
-
---
|
| 2 |
-
license: mit
|
| 3 |
-
tags:
|
| 4 |
-
- pytorch
|
| 5 |
-
- safetensors
|
| 6 |
-
- threshold-logic
|
| 7 |
-
- neuromorphic
|
| 8 |
-
---
|
| 9 |
-
|
| 10 |
-
# threshold-mux16
|
| 11 |
-
|
| 12 |
-
16:1 multiplexer. Selects one of 16 data inputs based on 4-bit select signal.
|
| 13 |
-
|
| 14 |
-
## Function
|
| 15 |
-
|
| 16 |
-
MUX16(d0..d15, s3,s2,s1,s0) = d[s] where s = 8*s3 + 4*s2 + 2*s1 + s0
|
| 17 |
-
|
| 18 |
-
## Architecture
|
| 19 |
-
|
| 20 |
-
```
|
| 21 |
-
d0..d15 (16 data) s3 s2 s1 s0 (4 select)
|
| 22 |
-
| |
|
| 23 |
-
+--------------------+
|
| 24 |
-
|
|
| 25 |
-
v
|
| 26 |
-
[N0] d0 AND (s=0000) ----+
|
| 27 |
-
[N1] d1 AND (s=0001) ----|
|
| 28 |
-
[N2] d2 AND (s=0010) ----|
|
| 29 |
-
... +---> [OR] ---> output
|
| 30 |
-
[N14] d14 AND (s=1110) ----|
|
| 31 |
-
[N15] d15 AND (s=1111) ----+
|
| 32 |
-
```
|
| 33 |
-
|
| 34 |
-
## Layer 1 Weights
|
| 35 |
-
|
| 36 |
-
Each neuron Ni fires when di=1 AND s=i:
|
| 37 |
-
- Weight on di: +1
|
| 38 |
-
- Weight on each select bit: +1 if that bit is 1 in i, else -1
|
| 39 |
-
- Bias: -(1 + popcount(i))
|
| 40 |
-
|
| 41 |
-
## Parameters
|
| 42 |
-
|
| 43 |
-
| | |
|
| 44 |
-
|---|---|
|
| 45 |
-
| Inputs | 20 (16 data + 4 select) |
|
| 46 |
-
| Outputs | 1 |
|
| 47 |
-
| Neurons | 17 |
|
| 48 |
-
| Layers | 2 |
|
| 49 |
-
| Parameters | 373 |
|
| 50 |
-
| Magnitude | 145 |
|
| 51 |
-
|
| 52 |
-
## Usage
|
| 53 |
-
|
| 54 |
-
```python
|
| 55 |
-
from safetensors.torch import load_file
|
| 56 |
-
import torch
|
| 57 |
-
|
| 58 |
-
w = load_file('model.safetensors')
|
| 59 |
-
|
| 60 |
-
def mux16(data, s3, s2, s1, s0):
|
| 61 |
-
inp = torch.tensor([float(d) for d in data] +
|
| 62 |
-
[float(s3), float(s2), float(s1), float(s0)])
|
| 63 |
-
l1 = (inp @ w['layer1.weight'].T + w['layer1.bias'] >= 0).float()
|
| 64 |
-
out = (l1 @ w['layer2.weight'].T + w['layer2.bias'] >= 0).float()
|
| 65 |
-
return int(out.item())
|
| 66 |
-
|
| 67 |
-
# Select d10 (s=1010)
|
| 68 |
-
data = [0]*16
|
| 69 |
-
data[10] = 1
|
| 70 |
-
print(mux16(data, 1, 0, 1, 0)) # 1
|
| 71 |
-
```
|
| 72 |
-
|
| 73 |
-
## License
|
| 74 |
-
|
| 75 |
-
MIT
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
tags:
|
| 4 |
+
- pytorch
|
| 5 |
+
- safetensors
|
| 6 |
+
- threshold-logic
|
| 7 |
+
- neuromorphic
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# threshold-mux16
|
| 11 |
+
|
| 12 |
+
16:1 multiplexer. Selects one of 16 data inputs based on 4-bit select signal.
|
| 13 |
+
|
| 14 |
+
## Function
|
| 15 |
+
|
| 16 |
+
MUX16(d0..d15, s3,s2,s1,s0) = d[s] where s = 8*s3 + 4*s2 + 2*s1 + s0
|
| 17 |
+
|
| 18 |
+
## Architecture
|
| 19 |
+
|
| 20 |
+
```
|
| 21 |
+
d0..d15 (16 data) s3 s2 s1 s0 (4 select)
|
| 22 |
+
| |
|
| 23 |
+
+--------------------+
|
| 24 |
+
|
|
| 25 |
+
v
|
| 26 |
+
[N0] d0 AND (s=0000) ----+
|
| 27 |
+
[N1] d1 AND (s=0001) ----|
|
| 28 |
+
[N2] d2 AND (s=0010) ----|
|
| 29 |
+
... +---> [OR] ---> output
|
| 30 |
+
[N14] d14 AND (s=1110) ----|
|
| 31 |
+
[N15] d15 AND (s=1111) ----+
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
## Layer 1 Weights
|
| 35 |
+
|
| 36 |
+
Each neuron Ni fires when di=1 AND s=i:
|
| 37 |
+
- Weight on di: +1
|
| 38 |
+
- Weight on each select bit: +1 if that bit is 1 in i, else -1
|
| 39 |
+
- Bias: -(1 + popcount(i))
|
| 40 |
+
|
| 41 |
+
## Parameters
|
| 42 |
+
|
| 43 |
+
| | |
|
| 44 |
+
|---|---|
|
| 45 |
+
| Inputs | 20 (16 data + 4 select) |
|
| 46 |
+
| Outputs | 1 |
|
| 47 |
+
| Neurons | 17 |
|
| 48 |
+
| Layers | 2 |
|
| 49 |
+
| Parameters | 373 |
|
| 50 |
+
| Magnitude | 145 |
|
| 51 |
+
|
| 52 |
+
## Usage
|
| 53 |
+
|
| 54 |
+
```python
|
| 55 |
+
from safetensors.torch import load_file
|
| 56 |
+
import torch
|
| 57 |
+
|
| 58 |
+
w = load_file('model.safetensors')
|
| 59 |
+
|
| 60 |
+
def mux16(data, s3, s2, s1, s0):
|
| 61 |
+
inp = torch.tensor([float(d) for d in data] +
|
| 62 |
+
[float(s3), float(s2), float(s1), float(s0)])
|
| 63 |
+
l1 = (inp @ w['layer1.weight'].T + w['layer1.bias'] >= 0).float()
|
| 64 |
+
out = (l1 @ w['layer2.weight'].T + w['layer2.bias'] >= 0).float()
|
| 65 |
+
return int(out.item())
|
| 66 |
+
|
| 67 |
+
# Select d10 (s=1010)
|
| 68 |
+
data = [0]*16
|
| 69 |
+
data[10] = 1
|
| 70 |
+
print(mux16(data, 1, 0, 1, 0)) # 1
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
## License
|
| 74 |
+
|
| 75 |
+
MIT
|
config.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
| 1 |
-
{
|
| 2 |
-
"name": "threshold-mux16",
|
| 3 |
-
"description": "16:1 multiplexer as threshold circuit",
|
| 4 |
-
"inputs": 20,
|
| 5 |
-
"outputs": 1,
|
| 6 |
-
"neurons": 17,
|
| 7 |
-
"layers": 2,
|
| 8 |
-
"parameters": 373
|
| 9 |
-
}
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "threshold-mux16",
|
| 3 |
+
"description": "16:1 multiplexer as threshold circuit",
|
| 4 |
+
"inputs": 20,
|
| 5 |
+
"outputs": 1,
|
| 6 |
+
"neurons": 17,
|
| 7 |
+
"layers": 2,
|
| 8 |
+
"parameters": 373
|
| 9 |
+
}
|
create_safetensors.py
CHANGED
|
@@ -1,75 +1,75 @@
|
|
| 1 |
-
import torch
|
| 2 |
-
from safetensors.torch import save_file
|
| 3 |
-
|
| 4 |
-
weights = {}
|
| 5 |
-
|
| 6 |
-
# Input order: d0..d15, s3, s2, s1, s0 (20 inputs)
|
| 7 |
-
# Layer 1: 16 neurons, each selects di when s = i
|
| 8 |
-
# Layer 2: OR gate
|
| 9 |
-
|
| 10 |
-
layer1_weights = []
|
| 11 |
-
layer1_biases = []
|
| 12 |
-
|
| 13 |
-
for i in range(16):
|
| 14 |
-
w = [0.0] * 20
|
| 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 |
-
s3_bit = (i >> 3) & 1
|
| 19 |
-
s2_bit = (i >> 2) & 1
|
| 20 |
-
s1_bit = (i >> 1) & 1
|
| 21 |
-
s0_bit = i & 1
|
| 22 |
-
w[16] = 1.0 if s3_bit else -1.0 # s3
|
| 23 |
-
w[17] = 1.0 if s2_bit else -1.0 # s2
|
| 24 |
-
w[18] = 1.0 if s1_bit else -1.0 # s1
|
| 25 |
-
w[19] = 1.0 if s0_bit else -1.0 # s0
|
| 26 |
-
# Bias: -(1 + popcount(i))
|
| 27 |
-
bias = -(1 + bin(i).count('1'))
|
| 28 |
-
layer1_weights.append(w)
|
| 29 |
-
layer1_biases.append(bias)
|
| 30 |
-
|
| 31 |
-
weights['layer1.weight'] = torch.tensor(layer1_weights, dtype=torch.float32)
|
| 32 |
-
weights['layer1.bias'] = torch.tensor(layer1_biases, dtype=torch.float32)
|
| 33 |
-
|
| 34 |
-
# Layer 2: OR gate
|
| 35 |
-
weights['layer2.weight'] = torch.tensor([[1.0] * 16], dtype=torch.float32)
|
| 36 |
-
weights['layer2.bias'] = torch.tensor([-1.0], dtype=torch.float32)
|
| 37 |
-
|
| 38 |
-
save_file(weights, 'model.safetensors')
|
| 39 |
-
|
| 40 |
-
# Verify
|
| 41 |
-
def mux16(data, s3, s2, s1, s0):
|
| 42 |
-
inp = torch.tensor([float(d) for d in data] + [float(s3), 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 MUX16...")
|
| 48 |
-
errors = 0
|
| 49 |
-
test_count = 0
|
| 50 |
-
for s in range(16):
|
| 51 |
-
s3, s2, s1, s0 = (s >> 3) & 1, (s >> 2) & 1, (s >> 1) & 1, s & 1
|
| 52 |
-
# Test with selected data = 1, others = 0
|
| 53 |
-
data = [0] * 16
|
| 54 |
-
data[s] = 1
|
| 55 |
-
result = mux16(data, s3, s2, s1, s0)
|
| 56 |
-
if result != 1:
|
| 57 |
-
errors += 1
|
| 58 |
-
print(f"ERROR: s={s}, d[{s}]=1 -> {result}, expected 1")
|
| 59 |
-
test_count += 1
|
| 60 |
-
|
| 61 |
-
# Test with selected data = 0
|
| 62 |
-
data[s] = 0
|
| 63 |
-
result = mux16(data, s3, s2, s1, s0)
|
| 64 |
-
if result != 0:
|
| 65 |
-
errors += 1
|
| 66 |
-
print(f"ERROR: s={s}, d[{s}]=0 -> {result}, expected 0")
|
| 67 |
-
test_count += 1
|
| 68 |
-
|
| 69 |
-
if errors == 0:
|
| 70 |
-
print(f"All {test_count} test cases passed!")
|
| 71 |
-
else:
|
| 72 |
-
print(f"FAILED: {errors} errors")
|
| 73 |
-
|
| 74 |
-
mag = sum(t.abs().sum().item() for t in weights.values())
|
| 75 |
-
print(f"Magnitude: {mag:.0f}")
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from safetensors.torch import save_file
|
| 3 |
+
|
| 4 |
+
weights = {}
|
| 5 |
+
|
| 6 |
+
# Input order: d0..d15, s3, s2, s1, s0 (20 inputs)
|
| 7 |
+
# Layer 1: 16 neurons, each selects di when s = i
|
| 8 |
+
# Layer 2: OR gate
|
| 9 |
+
|
| 10 |
+
layer1_weights = []
|
| 11 |
+
layer1_biases = []
|
| 12 |
+
|
| 13 |
+
for i in range(16):
|
| 14 |
+
w = [0.0] * 20
|
| 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 |
+
s3_bit = (i >> 3) & 1
|
| 19 |
+
s2_bit = (i >> 2) & 1
|
| 20 |
+
s1_bit = (i >> 1) & 1
|
| 21 |
+
s0_bit = i & 1
|
| 22 |
+
w[16] = 1.0 if s3_bit else -1.0 # s3
|
| 23 |
+
w[17] = 1.0 if s2_bit else -1.0 # s2
|
| 24 |
+
w[18] = 1.0 if s1_bit else -1.0 # s1
|
| 25 |
+
w[19] = 1.0 if s0_bit else -1.0 # s0
|
| 26 |
+
# Bias: -(1 + popcount(i))
|
| 27 |
+
bias = -(1 + bin(i).count('1'))
|
| 28 |
+
layer1_weights.append(w)
|
| 29 |
+
layer1_biases.append(bias)
|
| 30 |
+
|
| 31 |
+
weights['layer1.weight'] = torch.tensor(layer1_weights, dtype=torch.float32)
|
| 32 |
+
weights['layer1.bias'] = torch.tensor(layer1_biases, dtype=torch.float32)
|
| 33 |
+
|
| 34 |
+
# Layer 2: OR gate
|
| 35 |
+
weights['layer2.weight'] = torch.tensor([[1.0] * 16], dtype=torch.float32)
|
| 36 |
+
weights['layer2.bias'] = torch.tensor([-1.0], dtype=torch.float32)
|
| 37 |
+
|
| 38 |
+
save_file(weights, 'model.safetensors')
|
| 39 |
+
|
| 40 |
+
# Verify
|
| 41 |
+
def mux16(data, s3, s2, s1, s0):
|
| 42 |
+
inp = torch.tensor([float(d) for d in data] + [float(s3), 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 MUX16...")
|
| 48 |
+
errors = 0
|
| 49 |
+
test_count = 0
|
| 50 |
+
for s in range(16):
|
| 51 |
+
s3, s2, s1, s0 = (s >> 3) & 1, (s >> 2) & 1, (s >> 1) & 1, s & 1
|
| 52 |
+
# Test with selected data = 1, others = 0
|
| 53 |
+
data = [0] * 16
|
| 54 |
+
data[s] = 1
|
| 55 |
+
result = mux16(data, s3, s2, s1, s0)
|
| 56 |
+
if result != 1:
|
| 57 |
+
errors += 1
|
| 58 |
+
print(f"ERROR: s={s}, d[{s}]=1 -> {result}, expected 1")
|
| 59 |
+
test_count += 1
|
| 60 |
+
|
| 61 |
+
# Test with selected data = 0
|
| 62 |
+
data[s] = 0
|
| 63 |
+
result = mux16(data, s3, s2, s1, s0)
|
| 64 |
+
if result != 0:
|
| 65 |
+
errors += 1
|
| 66 |
+
print(f"ERROR: s={s}, d[{s}]=0 -> {result}, expected 0")
|
| 67 |
+
test_count += 1
|
| 68 |
+
|
| 69 |
+
if errors == 0:
|
| 70 |
+
print(f"All {test_count} test cases passed!")
|
| 71 |
+
else:
|
| 72 |
+
print(f"FAILED: {errors} errors")
|
| 73 |
+
|
| 74 |
+
mag = sum(t.abs().sum().item() for t in weights.values())
|
| 75 |
+
print(f"Magnitude: {mag:.0f}")
|
model.py
CHANGED
|
@@ -1,22 +1,22 @@
|
|
| 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 mux16(data, s3, s2, s1, s0, weights):
|
| 8 |
-
"""16:1 Multiplexer: returns data[s] where s = 8*s3 + 4*s2 + 2*s1 + s0"""
|
| 9 |
-
inp = torch.tensor([float(d) for d in data] + [float(s3), float(s2), float(s1), float(s0)])
|
| 10 |
-
l1 = (inp @ weights['layer1.weight'].T + weights['layer1.bias'] >= 0).float()
|
| 11 |
-
out = (l1 @ weights['layer2.weight'].T + weights['layer2.bias'] >= 0).float()
|
| 12 |
-
return int(out.item())
|
| 13 |
-
|
| 14 |
-
if __name__ == '__main__':
|
| 15 |
-
w = load_model()
|
| 16 |
-
print('MUX16 verification:')
|
| 17 |
-
for s in range(16):
|
| 18 |
-
s3, s2, s1, s0 = (s >> 3) & 1, (s >> 2) & 1, (s >> 1) & 1, s & 1
|
| 19 |
-
data = [0] * 16
|
| 20 |
-
data[s] = 1
|
| 21 |
-
result = mux16(data, s3, s2, s1, s0, w)
|
| 22 |
-
print(f' s={s:2d} ({s3}{s2}{s1}{s0}), d[{s}]=1 -> {result}')
|
|
|
|
| 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 mux16(data, s3, s2, s1, s0, weights):
|
| 8 |
+
"""16:1 Multiplexer: returns data[s] where s = 8*s3 + 4*s2 + 2*s1 + s0"""
|
| 9 |
+
inp = torch.tensor([float(d) for d in data] + [float(s3), float(s2), float(s1), float(s0)])
|
| 10 |
+
l1 = (inp @ weights['layer1.weight'].T + weights['layer1.bias'] >= 0).float()
|
| 11 |
+
out = (l1 @ weights['layer2.weight'].T + weights['layer2.bias'] >= 0).float()
|
| 12 |
+
return int(out.item())
|
| 13 |
+
|
| 14 |
+
if __name__ == '__main__':
|
| 15 |
+
w = load_model()
|
| 16 |
+
print('MUX16 verification:')
|
| 17 |
+
for s in range(16):
|
| 18 |
+
s3, s2, s1, s0 = (s >> 3) & 1, (s >> 2) & 1, (s >> 1) & 1, s & 1
|
| 19 |
+
data = [0] * 16
|
| 20 |
+
data[s] = 1
|
| 21 |
+
result = mux16(data, s3, s2, s1, s0, w)
|
| 22 |
+
print(f' s={s:2d} ({s3}{s2}{s1}{s0}), d[{s}]=1 -> {result}')
|