diff --git a/auto_diff/auto_diff.py b/auto_diff/auto_diff.py index 4484b94..ed069bb 100644 --- a/auto_diff/auto_diff.py +++ b/auto_diff/auto_diff.py @@ -133,6 +133,9 @@ def backward(loss: Node): for node in reversed(topo): node._backward() +def update_weights(weight: Node, lr: float): + return Node(float(weight) - lr * weight.grad) + if __name__ == "__main__": x = Node(2, label="x") diff --git a/classes.py b/classes.py index 2ab3995..5b0c38b 100644 --- a/classes.py +++ b/classes.py @@ -1,4 +1,6 @@ +import copy import random +from auto_diff import auto_diff class DataSet: def __init__(self, func, N=1000) -> None: @@ -7,12 +9,97 @@ class DataSet: self.test = [] self.test_answs = [] - for i in range(N//5*4): - x = random.uniform(1, 9) - self.train.append(x) - self.train_answs.append(func(x)) + def gen_data(): + x1 = random.uniform(-1, 1) + x2 = random.uniform(-1, 1) + y = func(x1, x2) + return (x1, x2), y + + for i in range(N): + (x1, x2), y = gen_data() + self.train.append((x1, x2)) + self.train_answs.append(y) for i in range(N//5): - x = random.uniform(1, 9) - self.test.append(x) - self.test_answs.append(func(x)) \ No newline at end of file + (x1, x2), y = gen_data() + self.test.append((x1, x2)) + self.test_answs.append(y) + + + def __repr__(self): + return f"test: {self.test}\nansws: {self.test_answs}" + + +class Neuron: + def __init__(self, weights_num: int) -> None: + self.weights = [auto_diff.Node(random.uniform(-1, 1)) for _ in range(weights_num)] + self.b = auto_diff.Node(random.uniform(-1, 1)) + + def __repr__(self, debug: bool = False) -> str: + if not debug: + return f"" + else: + return f"" + + def update_weights(self, lr): + for i in range(len(self.weights)): + self.weights[i] = auto_diff.update_weights(self.weights[i], lr) + + self.b = auto_diff.update_weights(self.b, lr) + +def my_sum(array: list) -> int: + result = 0 + for i in array: + result += i + return result + +class NeuronNetwork: + def __init__(self, neurons_num: int, layers_num: int, inputs_num: int, outputs_num: int = 1) -> None: + ''' + neurons_num: количество нейронов на каждом слое\n + layers_num: количество слоёв\n + inputs_num: количество входных нейронов\n + outputs_num: количество выходных нейронов (по умолчанию 1)\n + ''' + neurons = [] + for layer in range(layers_num+1): + neurons.append([]) + + if layer == layers_num: + for neuron in range(outputs_num): + neurons[layer].append(Neuron(neurons_num)) + continue + + for neuron in range(neurons_num): + if layer == 0: + neurons[layer].append(Neuron(inputs_num)) + else: + neurons[layer].append(Neuron(neurons_num)) + + self.neurons = neurons + + def forward(self, func, *args, func_out=None): + if func_out is None: + func_out = func + + + prev_out = [*args] + out = [] + for layer in self.neurons[:-1]: + for neuron in layer: + out.append(func(my_sum([prev_out[i]*neuron.weights[i] for i in range(len(prev_out))]) + neuron.b)) + prev_out = copy.deepcopy(out) + out = [] + + for neuron in self.neurons[-1]: + out.append(func_out(my_sum([prev_out[i]*neuron.weights[i] for i in range(len(prev_out))]) + neuron.b)) + + return out[0] + + def update_weights(self, lr=0.1): + for i in range(len(self.neurons)): + for j in range(len(self.neurons[i])): + self.neurons[i][j].update_weights(lr) + +if __name__ == "__main__": + print(NeuronNetwork(4, 4, 2).neurons) \ No newline at end of file diff --git a/generate.py b/generate.py index 9640de2..f4b6507 100644 --- a/generate.py +++ b/generate.py @@ -1,7 +1,7 @@ import classes -def generate_dataset(N=1000): - return classes.DataSet(lambda x: 1*x-12, N) +def generate_dataset(N=100): + return classes.DataSet(lambda x, y: float(((x**2 + y**2)**0.5)>=0.5), N) if __name__ == "__main__": - print([[i.train, i.train_answs] for i in [generate_dataset(10)]]) \ No newline at end of file + print(generate_dataset(10)) \ No newline at end of file diff --git a/main.py b/main.py index 0cfce63..546c399 100644 --- a/main.py +++ b/main.py @@ -9,12 +9,16 @@ dataset = generate.generate_dataset(100) # Создаём и обучаем сеть nn = neuro_defs.SimpleNN() -nn.train(dataset.train, dataset.train_answs, epochs=100) +epoch = 100 +for i in range(epoch): + nn.train(dataset.train, dataset.train_answs, epochs=1) + + if epoch % 10 == 0: + print("*"*(i//10) + "-"*((epoch-i)//10)) # Проверяем на новой точке for dot in range(len(dataset.test)): - print(nn.forward(dataset.test[dot]).val, dataset.test_answs[dot]) + print(nn.forward(*dataset.test[dot]).val, dataset.test_answs[dot]) print() -print(nn.w_out.val, nn.b_out.val) # visual.plot_dataset(dataset) # visual.plt_show() \ No newline at end of file diff --git a/neuro_defs.py b/neuro_defs.py index 5473c0f..f82edb2 100644 --- a/neuro_defs.py +++ b/neuro_defs.py @@ -1,32 +1,86 @@ -import math -import random -from auto_diff import auto_diff -def func_active(x): - return +from auto_diff import auto_diff +import classes + +def sigmoid(x: auto_diff.Node): + return 1 / (1 + (-x).exp()) + +def tanh(x: auto_diff.Node): + return (x.exp() - (-x).exp()) / (x.exp() + (-x).exp()) class SimpleNN: def __init__(self): - self.w_out = auto_diff.Node(random.uniform(-1, 1), label="w_out") - self.b_out = auto_diff.Node(random.uniform(-1, 1), label="b_out") - self.lr = 0.02 # скорость обучения + #111 - 1 слой, 1 нейрон, 1 вес + # self.w111 = auto_diff.Node(random.uniform(-1, 1)) + # self.w112 = auto_diff.Node(random.uniform(-1, 1)) + # self.b11 = auto_diff.Node(random.uniform(-1, 1)) - def forward(self, x): + # self.w121 = auto_diff.Node(random.uniform(-1, 1)) + # self.w122 = auto_diff.Node(random.uniform(-1, 1)) + # self.b12 = auto_diff.Node(random.uniform(-1, 1)) + + # self.w131 = auto_diff.Node(random.uniform(-1, 1)) + # self.w132 = auto_diff.Node(random.uniform(-1, 1)) + # self.b13 = auto_diff.Node(random.uniform(-1, 1)) + + # self.w141 = auto_diff.Node(random.uniform(-1, 1)) + # self.w142 = auto_diff.Node(random.uniform(-1, 1)) + # self.b14 = auto_diff.Node(random.uniform(-1, 1)) + + + + # self.w211 = auto_diff.Node(random.uniform(-1, 1)) + # self.w212 = auto_diff.Node(random.uniform(-1, 1)) + # self.w213 = auto_diff.Node(random.uniform(-1, 1)) + # self.w214 = auto_diff.Node(random.uniform(-1, 1)) + # self.b21 = auto_diff.Node(random.uniform(-1, 1)) + + # self.w221 = auto_diff.Node(random.uniform(-1, 1)) + # self.w222 = auto_diff.Node(random.uniform(-1, 1)) + # self.w223 = auto_diff.Node(random.uniform(-1, 1)) + # self.w224 = auto_diff.Node(random.uniform(-1, 1)) + # self.b22 = auto_diff.Node(random.uniform(-1, 1)) + + + + # self.w1_out = auto_diff.Node(random.uniform(-1, 1)) + # self.w2_out = auto_diff.Node(random.uniform(-1, 1)) + # self.b_out = auto_diff.Node(random.uniform(-1, 1)) + + self.network = classes.NeuronNetwork(4, 2, 2) + + self.lr = 0.1 # скорость обучения + + def forward(self, x1, x2): # прямой проход - self.z1 = self.w_out * x + self.b_out - return self.z1 - def backward(self, x, y): + # #скрытые слои + # self.h11 = tanh(self.w111*x1 + self.w112*x2 + self.b11) + # self.h12 = tanh(self.w121*x1 + self.w122*x2 + self.b12) + # self.h13 = tanh(self.w131*x1 + self.w132*x2 + self.b13) + # self.h14 = tanh(self.w141*x1 + self.w142*x2 + self.b14) + + # self.h21 = tanh(self.w211*self.h11 + self.w212*self.h12 + self.w213*self.h13 + self.w214*self.h14 + self.b21) + # self.h22 = tanh(self.w221*self.h11 + self.w222*self.h12 + self.w223*self.h13 + self.w224*self.h14 + self.b22) + + # #выходной слой + # self.a1 = sigmoid(self.w1_out*self.h21 + self.w2_out*self.h22 + self.b_out) + + self.a1 = self.network.forward(sigmoid, x1, x2) + + return self.a1 + + def backward(self, y): # вычисляем ошибку - error = (self.z1 - y)**2 # dL/da2 + error = (self.a1 - y)**2 # dL/da2 auto_diff.backward(error) - self.w_out = auto_diff.Node(float(self.w_out) - self.lr * self.w_out.grad, label="w_out") - self.b_out = auto_diff.Node(float(self.b_out) - self.lr * self.b_out.grad, label="b_out") + + self.network.update_weights(self.lr) def train(self, dataset, answs, epochs=1000): for _ in range(epochs): for i in range(len(dataset)): - self.forward(dataset[i]) - self.backward(dataset[i], answs[i]) + self.forward(*dataset[i]) + self.backward(answs[i])