mirror of
https://github.com/guezoloic/neural-network.git
synced 2026-01-25 07:34:23 +00:00
feat: add learning program
This commit is contained in:
54
main.py
54
main.py
@@ -1 +1,53 @@
|
|||||||
import network
|
from network import *
|
||||||
|
|
||||||
|
def data(size:int, max_val: int):
|
||||||
|
def int_to_bits(n: int):
|
||||||
|
return [(n >> i) & 1
|
||||||
|
for i in reversed(range(size))
|
||||||
|
]
|
||||||
|
|
||||||
|
return [(int_to_bits(i),[i / max_val])
|
||||||
|
for i in range(max_val + 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
def train_network(network: NeuralNetwork, epochs=10000, learning_rate=0.1,
|
||||||
|
verbose: bool = False, size_data: int = 8, max_val: int = 255):
|
||||||
|
|
||||||
|
train_data = data(size_data, max_val)
|
||||||
|
|
||||||
|
for epoch in range(epochs):
|
||||||
|
for bits, target in train_data:
|
||||||
|
network.backward(bits, target, learning_rate)
|
||||||
|
|
||||||
|
if verbose and epoch % 100 == 0:
|
||||||
|
output = network.forward(bits)[0]
|
||||||
|
loss = (output - target[0]) ** 2
|
||||||
|
|
||||||
|
print(f"Epoch: {epoch}, Loss: {loss:.6f}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
size = 8
|
||||||
|
max_val = (1 << size) - 1
|
||||||
|
|
||||||
|
network = NeuralNetwork([8, 16, 1])
|
||||||
|
|
||||||
|
print("Start training...")
|
||||||
|
train_network(network, verbose=True, size_data=size, epochs=45_000)
|
||||||
|
print("End training...")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
string = input("Enter 8 bit number (ex: 01101001) or 'quit' to close: ") \
|
||||||
|
.strip().lower()
|
||||||
|
|
||||||
|
if (string == 'quit'): break
|
||||||
|
if (len(string) != 8 or any (char not in '01' for char in string)):
|
||||||
|
print("Error: please enter exactly 8 bits (only 0 or 1).")
|
||||||
|
continue
|
||||||
|
|
||||||
|
bits_input = [int(char) for char in string]
|
||||||
|
output = network.forward(bits_input)[0] * max_val
|
||||||
|
|
||||||
|
print(f"Estimated value: {output} (approx: {round(output)})\n")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|||||||
20
network.py
20
network.py
@@ -30,14 +30,16 @@ class Neuron:
|
|||||||
# last output sigmoid(z)
|
# last output sigmoid(z)
|
||||||
self.last_output = 0
|
self.last_output = 0
|
||||||
|
|
||||||
def forward(self, x):
|
def forward(self, x, activate=True):
|
||||||
"""
|
"""
|
||||||
x : list of input values to the neuron
|
x : list of input values to the neuron
|
||||||
"""
|
"""
|
||||||
# computes the weighted sum of inputs and add the bias
|
# computes the weighted sum of inputs and add the bias
|
||||||
self.z = sum(w * xi for w, xi in zip(self.weight, x)) + self.bias
|
self.z = sum(w * xi for w, xi in zip(self.weight, x)) + self.bias
|
||||||
# normalize the output between 0 and 1
|
# normalize the output between 0 and 1
|
||||||
self.last_output = sigmoid(self.z)
|
if activate: self.last_output = sigmoid(self.z)
|
||||||
|
else: self.last_output = self.z
|
||||||
|
|
||||||
return self.last_output
|
return self.last_output
|
||||||
|
|
||||||
# adjust weight and bias of neuron
|
# adjust weight and bias of neuron
|
||||||
@@ -54,6 +56,9 @@ class Neuron:
|
|||||||
dy_dz = sigmoid_deriv(self.z)
|
dy_dz = sigmoid_deriv(self.z)
|
||||||
# dz/dw = x
|
# dz/dw = x
|
||||||
dz_dw = x
|
dz_dw = x
|
||||||
|
|
||||||
|
assert len(dz_dw) >= self.isize, "too many value for input size"
|
||||||
|
|
||||||
# dz/db = 1
|
# dz/db = 1
|
||||||
dz_db = 1
|
dz_db = 1
|
||||||
|
|
||||||
@@ -78,10 +83,10 @@ class Layer:
|
|||||||
# list of neurons
|
# list of neurons
|
||||||
self.neurons = [Neuron(input_size) for _ in range(output_size)]
|
self.neurons = [Neuron(input_size) for _ in range(output_size)]
|
||||||
|
|
||||||
def forward(self, inputs):
|
def forward(self, inputs, activate=True):
|
||||||
self.inputs = inputs
|
self.inputs = inputs
|
||||||
# give the same inputs to each neuron in the layer
|
# give the same inputs to each neuron in the layer
|
||||||
return [neuron.forward(inputs) for neuron in self.neurons]
|
return [neuron.forward(inputs, activate) for neuron in self.neurons]
|
||||||
|
|
||||||
# adjust weight and bias of the layer (all neurons)
|
# adjust weight and bias of the layer (all neurons)
|
||||||
def backward(self, dcost_dy_list, learning_rate=0.1):
|
def backward(self, dcost_dy_list, learning_rate=0.1):
|
||||||
@@ -105,8 +110,9 @@ class NeuralNetwork:
|
|||||||
|
|
||||||
def forward(self, inputs):
|
def forward(self, inputs):
|
||||||
output = inputs
|
output = inputs
|
||||||
for layer in self.layers:
|
for i, layer in enumerate(self.layers):
|
||||||
output = layer.forward(output)
|
activate = (i != len(self.layers) - 1) # deactivate sigmoid latest neuron
|
||||||
|
output = layer.forward(output, activate=activate)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def backward(self, inputs, targets, learning_rate=0.1):
|
def backward(self, inputs, targets, learning_rate=0.1):
|
||||||
@@ -117,7 +123,7 @@ class NeuralNetwork:
|
|||||||
output = self.forward(inputs)
|
output = self.forward(inputs)
|
||||||
|
|
||||||
# computes the initial gradient of the cost function for each neuron
|
# computes the initial gradient of the cost function for each neuron
|
||||||
# by using Mean Squared Error: dC/dy = 2 * (output - target)
|
# by using Mean Squared Error's derivate: dC/dy = 2 * (output - target)
|
||||||
dcost_dy_list = [2 * (o - t) for o, t in zip(output, targets)]
|
dcost_dy_list = [2 * (o - t) for o, t in zip(output, targets)]
|
||||||
|
|
||||||
grad = dcost_dy_list
|
grad = dcost_dy_list
|
||||||
|
|||||||
Reference in New Issue
Block a user