Новости:

SMF форум только что установлен!

Main Menu

Небольшая нейронная сеть на Raspberry Pi Pico

Автор ak167, 11 Марта 2023, 22:54:11

« предыдущая тема - следующая тема »

ak167

В этом посте я вам покажу как создать достаточно эффективную нейронную сеть на Raspberry Pi Pico!



Для начала каким-либо образом копируем этот код в память pico:


from random import random
from math import exp

class NeyroNet:
def __init__(self, n_inputs, hiddens_layer, n_outputs):
self.network = list()

self.n_outputs = n_outputs

hidden_layer = [{`weights`:[random() for i in range(n_inputs + 1)]} for i in range(hiddens_layer[0])]
self.network.append(hidden_layer)

for layer in hiddens_layer[1:]:
hidden_layer = [{`weights`:[random() for i in range(len(self.network[-1])+1)]} for i in range(layer)]
self.network.append(hidden_layer)

output_layer = [{`weights`:[random() for i in range(hiddens_layer[-1] + 1)]} for i in range(n_outputs)]
self.network.append(output_layer)

def activate(self, weights, inputs):
activation = weights[-1]
for i in range(len(weights)-1):
activation += weights * inputs
return activation

def transfer(self, activation):
return 1.0 / (1.0 + exp(-activation))

def forward_propagate(self, row):
inputs = row
for layer in self.network:
new_inputs = []
for neuron in layer:
activation = self.activate(neuron[`weights`], inputs)
neuron[`output`] = self.transfer(activation)
new_inputs.append(neuron[`output`])
inputs = new_inputs
return inputs

def transfer_derivative(self, output):
return output * (1.0 - output)

def backward_propagate_error(self, expected):
for i in reversed(range(len(self.network))):
layer = self.network
errors = list()
if i != len(self.network)-1:
for j in range(len(layer)):
error = 0.0
for neuron in self.network[i + 1]:
error += (neuron[`weights`][j] * neuron[`delta`])
errors.append(error)
else:
for j in range(len(layer)):
neuron = layer[j]
errors.append(expected[j] - neuron[`output`])
for j in range(len(layer)):
neuron = layer[j]
neuron[`delta`] = errors[j] * self.transfer_derivative(neuron[`output`])

def update_weights(self, row, l_rate):
for i in range(len(self.network)):
inputs = row[:-1]
if i != 0:
inputs = [neuron[`output`] for neuron in self.network[i - 1]]
for neuron in self.network:
for j in range(len(inputs)):
neuron[`weights`][j] += l_rate * neuron[`delta`] * inputs[j]
neuron[`weights`][-1] += l_rate * neuron[`delta`]

def train_network(self, train, l_rate, n_epoch, err_val_threshold=0):
for epoch in range(n_epoch):
sum_error = 0
for row in train:
outputs = self.forward_propagate(row)
expected = [0 for i in range(self.n_outputs)]
expected[row[-1]] = 1
sum_error += sum([(expected-outputs)**2 for i in range(len(expected))])
self.backward_propagate_error(expected)
self.update_weights(row, l_rate)
pdat = `>epoch=%d, lrate=%.1f, error=%.10f` % (epoch, l_rate, sum_error)
print(pdat, end=`\r`)
if(sum_error < err_val_threshold):
print(` ` * len(pdat), end=`\r`)
print(`THRESHOLD WITH EPOCH > ` + str(epoch))
break

def predict(self, row):
outputs = self.forward_propagate(row)
return outputs.index(max(outputs))

def save(self, filename):
with open(filename, `w`) as sv:
sv.write(str(self.network))
sv.close()

def load(self, filename):
with open(filename, `r`) as sv:
data = sv.read()
sv.close()
self.network = eval(data)


Называем файл как угодно

Далее заходим в консоль pico через minicom или через thonny

Прописываем для инициализации нейронной сети

import <скопированный файл без приставки .py>
net = NeyroNet(3, [6], 2) # 3 - Сколько входов, [6] - Это список слоёв


Далее берём любой dataset

dataset = [[1, 0 ,0 ,1], [1, 1, 0, 1], [0, 1, 1, 0], [0, 0, 1, 0]]


Вы спросите: "Почему у тебя в каждом элементе по 4 значения а входов всего 4?"

Дело в том что самое последнее значение в элементе это и есть выходные данные, а все остальные - это входные!

После этого обучаем нейросеть

net.train_network(dataset, l_rate=0.5, n_epoch=10000, err_val_threshold=0.0009)


P.S. параметр err_val_threshold нужен для того чтобы не ждать пока нейросеть пройдёт все эпохи, этот параметр указывает пороговое значение ошибки т.e. если ошибка будет меньше этого значения обучение прекратится!

Ну вот мы и обучили нейросеть! Теперь давайте проверим что она выдаёт!

Как мы помним у нас всего выходных класса

net.predict([1, 0, 1]) # возвращает 1 т.е какой выход (начинается с 0)
net.forward_propagate([0, 0, 0]) # возвращает [0.99998464, 0.00006544]


И чтобы сохранить текущие веса нужно прописать:

net.save(`<имя файла>`)


А чтобы загрузить веса сети нужно воопервых при создании объекта сети нужно указать столько же выходов, сколько и было сохранено, а иначе будет ошибка!

net.load(`<имя файла>`)


Вот и всё!