TinyML Sınıflandırma: Wine Veri Kümesi

Bu gönderi, sınıflandırma görevi için Arduino uyumlu bir mikrodenetleyici üzerinde bir Tensorflow Sinir Ağının nasıl eğitileceği, dışa aktarılacağı ve çalıştırılacağı hakkında adım adım bir eğitimdir: özellikle, Wine veri setini sınıflandıracağız.

tinyml

TinyML ve Mikrodenetleyiciler için Tensorflow’a yeni gelen birçok kişi, sınıflandırma görevleri için sinir ağlarına başlamak için hala mücadele ediyor, bu yüzden bu yazıyı, bu boşluğu doldurmak için adım adım bir kılavuz olarak yazmaya karar verdik.

Bu içerik şunları kapsayacaktır:

  1. Iris veri kümesini sınıflandırmak için Python’da bir Tensorflow Sinir ağı eğitimi.
  2. Sinir Ağını Arduino uyumlu C++’a aktarmak
  3. Sinir Ağını bir mikro denetleyicide çalıştırmak

Tüm adımları ele alacağız, böylece bu gönderiyi, sahip olabileceğiniz herhangi bir veri kümesini sınıflandırması gereken diğer projeler için referans olarak kullanabilirsiniz: çoğu (tümü değilse) adımlar aynı olacaktır.

Python’da Sinir Ağı Eğitmek

Her şeyden önce, Tensorflow çerçevesini kullanarak Python’da bir sinir ağı oluşturmamız ve eğitmemiz gerekiyor. Keras API’yi kullanacağız çünkü kullanılması oldukça kolay ve yaygın.

import numpy as np
from tensorflow.keras import Sequential, layers
from tensorflow.keras.utils import to_categorical
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split

# veri kümesini eğitme, doğrulama, test'e yükleme ve bölme
X, y = load_wine(return_X_y=True)
y = to_categorical(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
X_train, X_valid, y_train, y_valid = train_test_split(X_train, y_train, test_size=0.3)

input_dim = X_train.shape[1:]
output_dim = y.shape[1]

print('input_dim', input_dim)
print('output_dim', output_dim)

# create and train network
# you can customize the layers as you prefer
nn = Sequential()
nn.add(layers.Dense(units=50, activation='relu', input_shape=input_dim))
nn.add(layers.Dense(units=50, activation='relu'))
nn.add(layers.Dense(output_dim, activation='softmax'))

# use categorical_crossentropy for multi-class classification
nn.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
nn.fit(X_train, y_train, validation_data=(X_valid, y_valid), epochs=100, verbose=0)

print('Doğruluk: %.1f' % nn.evaluate(X_test, y_test)[1])

Bu yapılandırmada% 89’luk en iyi doğruluğu elde ettik: veri kümenize ve katmanlarınıza bağlı olarak sonuçlar değişebilir.

C++’a Aktarım

Sinir ağını, C veri dizisine aktarmak için tinymlgen paketini kullanacağız.

from tinymlgen import port

print(port(nn, variable_name='wine_model', pretty_print=True, optimize=False))

Aşağıdaki gibi bir şey alacaksınız:

#ifdef __has_attribute
#define HAVE_ATTRIBUTE(x) __has_attribute(x)
#else
#define HAVE_ATTRIBUTE(x) 0
#endif
#if HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
#define DATA_ALIGN_ATTRIBUTE __attribute__((aligned(4)))
#else
#define DATA_ALIGN_ATTRIBUTE
#endif

const unsigned char wine_model[] DATA_ALIGN_ATTRIBUTE = {
    0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x00, 0x00, 0x12, 0x00, 
    0x1c, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00,
    .......
};
const int iris_model_len = 15228;

Bu metni kopyalayıpArduino projenizin içinde, wine_model.h adlı bir dosyaya yapıştırın.

Sinir Ağını Mikrodenetleyicide Çalıştırmak

Mikrodenetleyicimizdeki sinir ağını kolayca çalıştırmak için EloquentTinyML kütüphanesini kullanacağız. Arduino IDE kütüphane yöneticisi aracılığıyla kolayca yükleyebilirsiniz.

#include <EloquentTinyML.h>
#include "wine_model.h"

#define NUMBER_OF_INPUTS 13
#define NUMBER_OF_OUTPUTS 3
#define TENSOR_ARENA_SIZE 16*1024

Eloquent::TinyML::TfLite<NUMBER_OF_INPUTS, NUMBER_OF_OUTPUTS, TENSOR_ARENA_SIZE> nn;

float X_test[20][13] = {
    {1.340e+01, 4.600e+00, 2.860e+00, 2.500e+01, 1.120e+02, 1.980e+00,
    9.600e-01, 2.700e-01, 1.110e+00, 8.500e+00, 6.700e-01, 1.920e+00, 6.300e+02},
    {1.285e+01, 3.270e+00, 2.580e+00, 2.200e+01, 1.060e+02, 1.650e+00,
    6.000e-01, 6.000e-01, 9.600e-01, 5.580e+00, 8.700e-01, 2.110e+00, 5.700e+02},
    {1.334e+01, 9.400e-01, 2.360e+00, 1.700e+01, 1.100e+02, 2.530e+00,
    1.300e+00, 5.500e-01, 4.200e-01, 3.170e+00, 1.020e+00, 1.930e+00, 7.500e+02},
    {1.423e+01, 1.710e+00, 2.430e+00, 1.560e+01, 1.270e+02, 2.800e+00,
    3.060e+00, 2.800e-01, 2.290e+00, 5.640e+00, 1.040e+00, 3.920e+00, 1.065e+03},
    {1.483e+01, 1.640e+00, 2.170e+00, 1.400e+01, 9.700e+01, 2.800e+00,
    2.980e+00, 2.900e-01, 1.980e+00, 5.200e+00, 1.080e+00, 2.850e+00, 1.045e+03},
    {1.245e+01, 3.030e+00, 2.640e+00, 2.700e+01, 9.700e+01, 1.900e+00,
    5.800e-01, 6.300e-01, 1.140e+00, 7.500e+00, 6.700e-01, 1.730e+00, 8.800e+02},
    {1.430e+01, 1.920e+00, 2.720e+00, 2.000e+01, 1.200e+02, 2.800e+00,
    3.140e+00, 3.300e-01, 1.970e+00, 6.200e+00, 1.070e+00, 2.650e+00, 1.280e+03},
    {1.390e+01, 1.680e+00, 2.120e+00, 1.600e+01, 1.010e+02, 3.100e+00,
    3.390e+00, 2.100e-01, 2.140e+00, 6.100e+00, 9.100e-01, 3.330e+00, 9.850e+02},
    {1.165e+01, 1.670e+00, 2.620e+00, 2.600e+01, 8.800e+01, 1.920e+00,
    1.610e+00, 4.000e-01, 1.340e+00, 2.600e+00, 1.360e+00, 3.210e+00, 5.620e+02},
    {1.386e+01, 1.510e+00, 2.670e+00, 2.500e+01, 8.600e+01, 2.950e+00,
    2.860e+00, 2.100e-01, 1.870e+00, 3.380e+00, 1.360e+00, 3.160e+00, 4.100e+02},
    {1.377e+01, 1.900e+00, 2.680e+00, 1.710e+01, 1.150e+02, 3.000e+00,
    2.790e+00, 3.900e-01, 1.680e+00, 6.300e+00, 1.130e+00, 2.930e+00, 1.375e+03},
    {1.296e+01, 3.450e+00, 2.350e+00, 1.850e+01, 1.060e+02, 1.390e+00,
    7.000e-01, 4.000e-01, 9.400e-01, 5.280e+00, 6.800e-01, 1.750e+00, 6.750e+02},
    {1.305e+01, 5.800e+00, 2.130e+00, 2.150e+01, 8.600e+01, 2.620e+00,
    2.650e+00, 3.000e-01, 2.010e+00, 2.600e+00, 7.300e-01, 3.100e+00, 3.800e+02},
    {1.182e+01, 1.470e+00, 1.990e+00, 2.080e+01, 8.600e+01, 1.980e+00,
    1.600e+00, 3.000e-01, 1.530e+00, 1.950e+00, 9.500e-01, 3.330e+00, 4.950e+02},
    {1.164e+01, 2.060e+00, 2.460e+00, 2.160e+01, 8.400e+01, 1.950e+00,
    1.690e+00, 4.800e-01, 1.350e+00, 2.800e+00, 1.000e+00, 2.750e+00, 6.800e+02},
    {1.303e+01, 9.000e-01, 1.710e+00, 1.600e+01, 8.600e+01, 1.950e+00,
    2.030e+00, 2.400e-01, 1.460e+00, 4.600e+00, 1.190e+00, 2.480e+00, 3.920e+02},
    {1.176e+01, 2.680e+00, 2.920e+00, 2.000e+01, 1.030e+02, 1.750e+00,
    2.030e+00, 6.000e-01, 1.050e+00, 3.800e+00, 1.230e+00, 2.500e+00, 6.070e+02},
    {1.439e+01, 1.870e+00, 2.450e+00, 1.460e+01, 9.600e+01, 2.500e+00,
    2.520e+00, 3.000e-01, 1.980e+00, 5.250e+00, 1.020e+00, 3.580e+00, 1.290e+03},
    {1.420e+01, 1.760e+00, 2.450e+00, 1.520e+01, 1.120e+02, 3.270e+00,
    3.390e+00, 3.400e-01, 1.970e+00, 6.750e+00, 1.050e+00, 2.850e+00, 1.450e+03},
    {1.368e+01, 1.830e+00, 2.360e+00, 1.720e+01, 1.040e+02, 2.420e+00,
    2.690e+00, 4.200e-01, 1.970e+00, 3.840e+00, 1.230e+00, 2.870e+00, 9.900e+02}
};

uint8_t y_test[20] = {2, 2, 1, 0, 0, 2, 0, 0, 1, 1, 0, 2, 1, 1, 1, 1, 1, 0, 0, 0};

void setup() {
    Serial.begin(115200);
    nn.begin(wine_model);
}

void loop() {
    for (uint8_t i = 0; i < 10; i++) {
        Serial.print("Örnek #");
        Serial.print(i + 1);
        Serial.print(": ");
        Serial.print("tahmin ");
        Serial.print(nn.predictClass(X_test[i]));
        Serial.print(" vs ");
        Serial.print(y_test[i]);
        Serial.println(" gerçek değer");
    }

    delay(10000);
}

Derleyin, taslağı yükleyin ve seri monitörü açın: hedef sınıflarla eşleşen tahmini sınıfları görmelisiniz.