MicroFlow — библиотека Arduino, которая позволяет обучить TensorFlow-модель на компьютере, а потом запустить её даже на самых простых контроллерах Arduino.
В качестве примера приводится обучение нейронной сети решению классической задачи XOR:
# TensorFlow is an open source machine learning library import tensorflow as tf # Keras is TensorFlow's high-level API for deep learning from tensorflow import keras # Numpy is a math library import numpy as np #Create a model with a (2, 2, 2, 1) architecture MODEL = keras.Sequential() MODEL.add(keras.layers.Dense(2, activation='sigmoid', input_shape=(2,))) MODEL.add(keras.layers.Dense(2, activation='sigmoid')) # Final layer is a single neuron, since we want to output a single value MODEL.add(keras.layers.Dense(1)) # Compile the model using the standard 'adam' optimizer and the mean squared error or 'mse' loss function for regression. MODEL.compile(optimizer=keras.optimizers.Adam(learning_rate=1e-2), loss='mse') #Train the model training_data = np.array([[0, 0],[1, 0],[0, 1],[1, 1]], "float32") # the four expected results in the same order target_data = np.array([[0],[1],[1],[0]], "float32") MODEL.fit(training_data, target_data, epochs=1000)
Получив обученную модель TensorFlow, останется только экспортировать её веса в код для MicroFlow.
Для этого используется следующий простой код:
def weights_to_cpp(model, filename="weights_and_biases.txt"): model.summary() weights = [] biases = [] for l in range(len(model.layers)): W, B = model.layers[l].get_weights() weights.append(W.flatten()) biases.append(B.flatten()) z = [] b = [] for i in np.array(weights): for l in i: z.append(l) for i in np.array(biases): for l in i: b.append(l) with open(filename, "w") as f: f.write("weights: {") for i in range(len(z)): if (i < len(z)-1): f.write(str(z[i])+", ") else: f.write(str(z[i])) f.write("}\n\n") f.write("biases: {") for i in range(len(b)): if (i < len(b)-1): f.write(str(b[i])+", ") else: f.write(str(b[i])) f.write("}\n\n") arch = [] arch.append(model.layers[0].input_shape[1]) for i in range(1, len(model.layers)): arch.append(model.layers[i].input_shape[1]) arch.append(model.layers[len(model.layers)-1].output_shape[1]) f.write("Architecture: {") for i in range(len(arch)): if (i < len(arch)-1): f.write(str(arch[i])+", ") else: f.write(str(arch[i])) f.write("}") print("Architecture (alpha):", arch) print("Layers: ", len(arch)) print("Weights: ", z) print("Biases: ", b)
В результате получится файл со строчками данных вида:
weights: {...} biases: {...} Architecture: {...}
Результирующий скетч XorModel.ino
#include "MicroFlow.h" void setup(){ Serial.begin(9600); int topology[] = {2, 2, 2, 1}; double weights[] = {6.5388827, 2.3116155, 6.5393276, 2.311627, -2.8204367, -2.5849876, 3.4741454, -1.7074409, -2.5904362, -0.8814233}; double biases[] = {-1.4674287, -3.13011, 0.36903697, -0.27291444, 1.5541532}; double inputs[] = {0, 0}; double output[1] = {}; int layers = 4; MicroMLP mlp(layers, topology, weights, biases, SIGMOID); mlp.feedforward(inputs, output); Serial.print("Inputs: ");Serial.print(inputs[0]);Serial.print(", ");Serial.println(inputs[1]); Serial.print("Neural Network Output: ");Serial.println(output[0]); inputs[0] = 1; mlp.feedforward(inputs, output); Serial.print("Inputs: ");Serial.print(inputs[0]);Serial.print(", ");Serial.println(inputs[1]); Serial.print("Neural Network Output: ");Serial.println(output[0]); inputs[1] = 1; mlp.feedforward(inputs, output); Serial.print("Inputs: ");Serial.print(inputs[0]);Serial.print(", ");Serial.println(inputs[1]); Serial.print("Neural Network Output: ");Serial.println(output[0]); inputs[0] = 0; mlp.feedforward(inputs, output); Serial.print("Inputs: ");Serial.print(inputs[0]);Serial.print(", ");Serial.println(inputs[1]); Serial.print("Neural Network Output: ");Serial.println(output[0]); } void loop(){ }
Как видим — модель представлена в виде весов, которые и используются для вычисления результатов.
Из функций активаций пока доступны:
0 SIGMOID, 1 TANH, 2 RELU, 3, EXPONENTIAL (e^x), 4,SWISH (x * sigmoid(x)), -1 LINEAR (no activation)
На что стоит обратить внимание — библиотека использует для хранения и работы тип double, что явно не самый оптимальный тип данных для использования на 8-битных микроконтроллерах.
Ссылки
По теме
- AIfES — библиотека машинного обучения для Arduino
- Запуск TensorFlow Lite Micro на Arduino
- STM32Cube.AI — пакет расширения для STM32CubeMX для встраивания нейронных сетей в микроконтроллеры STM32
- CMSIS-NN — библиотека для работы с нейронными сетями для микроконтроллеров ARM Cortex-M
- uTensor — AI на микроконтроллерах
- Глубокие нейронные сети как следующий этап развития программного обеспечения
Нейронная сеть