SimpleNN / nn.py
ricardo-lsantos's picture
Fixed minor bugs. Fixed the Ui parameters to be more easy to train.
b7f5a9c
import random
import json
from typing import Any
from utils import sigmoid, sigmoid_prime
EPOCHS = 1000000
ALPHAS = 20
WEPOCHS = EPOCHS // 100
VARIANCE_W = 0.5
VARIANCE_B = 1
class NeuralNetwork:
def __init__(self):
self._w11 = random.uniform(-VARIANCE_W,VARIANCE_W)
self._w21 = random.uniform(-VARIANCE_W,VARIANCE_W)
self._b1 = VARIANCE_B
self._w12 = random.uniform(-VARIANCE_W,VARIANCE_W)
self._w22 = random.uniform(-VARIANCE_W,VARIANCE_W)
self._b2 = VARIANCE_B
self._w13 = random.uniform(-VARIANCE_W,VARIANCE_W)
self._w23 = random.uniform(-VARIANCE_W,VARIANCE_W)
self._b3 = VARIANCE_B
self._o1 = random.uniform(-VARIANCE_W,VARIANCE_W)
self._o2 = random.uniform(-VARIANCE_W,VARIANCE_W)
self._o3 = random.uniform(-VARIANCE_W,VARIANCE_W)
self._ob = VARIANCE_B
def predict(self, i1, i2, activation=sigmoid):
s1 = self._w11 * i1 + self._w21 * i2 + self._b1
s1 = activation(s1)
s2 = self._w12 * i1 + self._w22 * i2 + self._b2
s2 = activation(s2)
s3 = self._w13 * i1 + self._w23 * i2 + self._b3
s3 = activation(s3)
output = s1 * self._o1 + s2 * self._o2 + s3 * self._o3 + self._ob
output = activation(output)
return output
def learn(self, i1, i2, target, activation=sigmoid, activation_prime=sigmoid_prime, alpha=0.2):
s1 = self._w11 * i1 + self._w21 * i2 + self._b1
s1 = activation(s1)
s2 = self._w12 * i1 + self._w22 * i2 + self._b2
s2 = activation(s2)
s3 = self._w13 * i1 + self._w23 * i2 + self._b3
s3 = activation(s3)
output = s1 * self._o1 + s2 * self._o2 + s3 * self._o3 + self._ob
output = activation(output)
error = target - output
derror = error * activation_prime(output)
ds1 = derror * self._o1 * activation_prime(s1)
ds2 = derror * self._o2 * activation_prime(s2)
ds3 = derror * self._o3 * activation_prime(s3)
self._o1 += alpha * s1 * derror
self._o2 += alpha * s2 * derror
self._o3 += alpha * s3 * derror
self._ob += alpha * derror
self._w11 += alpha * i1 * ds1
self._w21 += alpha * i2 * ds1
self._b1 += alpha * ds1
self._w12 += alpha * i1 * ds2
self._w22 += alpha * i2 * ds2
self._b2 += alpha * ds2
self._w13 += alpha * i1 * ds3
self._w23 += alpha * i2 * ds3
self._b3 += alpha * ds3
def train(self, inputs=[], outputs=[], epochs=EPOCHS, alpha=ALPHAS):
if len(inputs) > 0 and len(outputs) > 0:
for epoch in range(1,epochs+1):
indexes = [0,1,2,3]
random.shuffle(indexes)
for j in indexes:
self.learn(inputs[j][0],inputs[j][1],outputs[j][0], activation=sigmoid, activation_prime=sigmoid_prime, alpha=alpha)
# Print cost every 100 epochs for debug
if epoch%WEPOCHS == 0:
cost = 0
for j in range(4):
o = self.predict(inputs[j][0],inputs[j][1], activation=sigmoid)
cost += (outputs[j][0] - o) ** 2
cost /= 4
print("epoch", epoch, "mean squared error:", cost)
def save_model(self, filename):
model = self.getModelJson()
with open(filename, 'w') as json_file:
json.dump(model, json_file)
def getModelJson(self):
return {
"w11": self._w11,
"w21": self._w21,
"b1": self._b1,
"w12": self._w12,
"w22": self._w22,
"b2": self._b2,
"w13": self._w13,
"w23": self._w23,
"b3": self._b3,
"o1": self._o1,
"o2": self._o2,
"o3": self._o3,
"ob": self._ob
}
def __str__(self):
return self.getModelJson()
## Main
def main():
INPUTS = [[0,0],[0,1],[1,0],[1,1]]
OUTPUTS = [[0],[1],[1],[0]]
# Train model
nn = NeuralNetwork()
print("Neural Network created")
nn.train(inputs=INPUTS, outputs=OUTPUTS, epochs=EPOCHS, alpha=ALPHAS)
print("Model trained")
print("Printing Model:")
print(nn._getModelJson())
# Save model to files
nn.save_model("model.json")
print("Model saved to model.json")
for i in range(4):
result = nn.predict(INPUTS[i][0],INPUTS[i][1], activation=sigmoid)
print("for input", INPUTS[i], "expected", OUTPUTS[i][0], "predicted", f"{result:4.4}", "which is", "correct" if round(result)==OUTPUTS[i][0] else "incorrect")
if __name__ == "__main__":
main()