Arduino Düşük Kaynaklı Makine Öğrenimi Modeli

Şimdiye kadar, bir Makine öğrenimi modelini bir mikro denetleyiciye taşımak için ana sınıflandırıcımız olarak SVM’yi (Destek Vektör Makinesi) kullandık: ancak son zamanlarda, benzer bir doğruluğu sağlayan, çok daha küçük olabilecek ilginç bir alternatifini sizlerle tanıştırmak istedik!

Relevance Vector Machine

MicroML çerçevesi için ilgi odağımızı olarak svm’yi seçtik çünkü destek vektör kodlamasının düz C’ye taşındıktan sonra bellek kullanımı verimli olabileceğini biliyorduk.

Eski Arduino Nano (32 kb flaş, 2 kb RAM) gibi küçük mikrodenetleyicilere birçok gerçek dünya modelini (hareket tanımlama, uyandırma kelimesi algılama) uygulayabildik.

Uygulamamın uzlaşması, genellikle en sınırlayıcı faktör olan mümkün olduğunca fazla RAM tasarrufu sağlamak için flaş alanını (genellikle oldukça büyük olan) feda etmekti.

Bu uygulama nedeniyle, modeliniz boyut olarak büyürse (yüksek boyutlu veriler veya iyi ayrılamayan veriler), oluşturulan kod yine de RAM’e sığar, ancak kullanılabilir flaşı “taşar”.

Önceki yazımızın bir çiftinde, bir modeli bir MCU’ya yüklemeden önce model seçiminin gerekli bir adım olabileceği konusunda uyardık, çünkü önce uygun olup olmadığını kontrol etmelisiniz. Değilse, her biri kod boyutu artışına katkıda bulunduğundan, daha az destek vektörü almayı umarak başka bir modeli eğitmeniz gerekir.

Yeni bir algoritma: Uygunluk Vektörü Makineleri

Alaka Düzeyi Vektör Makinesi(Relevance Vector Machine) adı verilen yeni bir algoritma ile karşılaşmamız şans eseri oldu. Geçen yıla kadar Microsoft tarafından patentliydi, ancak şimdi kullanımı ücretsizdir.

Bayesan modeli uygulayarak aynı SVM formülasyonunu (ağırlaştırılmış bir çekirdek toplamı) kullanıyor.

Bu, ilk etapta SVM’de tamamen eksik olan sınıflandırma sonuçlarının olasılıklarını elde edebilmek için hizmet eder.

İkinci sırada, algoritma, aşağıdaki resimde görebileceğiniz gibi, destek vektörlerinin çok daha seyrek bir temsilini öğrenmeye çalışır.

Relevance Vector Machine

Yüksek doğruluk elde edebilen oldukça hafif bir model

Sınıflandırıcıyı Eğitmek

Öyle görünüyor ki, patentli olduğu için bir uygulaması yoktu. Neyse ki, sklearn paradigmasını izleyen bir uygulama var. Bunu yüklemeniz gerekir:

pip install Cython
pip install https://github.com/AmazaspShumik/sklearn_bayes/archive/master.zip

Arayüz her zamanki uyum tahmini olduğundan, bir sınıflandırıcıyı eğitmek çok kolaydır.

from sklearn.datasets import load_iris
from skbayes.rvm_ard_models import RVC
import warnings

# I get tons of boring warnings during training, so turn it off
warnings.filterwarnings("ignore")

iris = load_iris()
X = iris.data
y = iris.target
clf = RVC(kernel='rbf', gamma=0.001)
clf.fit(X, y)
y_predict = clf.predict(X)

SVCYapıcının parametreleri , sklearn’deki sınıflandırıcınınkilere benzer:

  • kernel: lineer, poly, rbf’den biri
  • degree: eğer kernel=poly
  • gamma: eğer kernel=polyveyakernel=rbf

Daha fazla bilgi edinmek için sklearn’deki belgeleri okuyabilirsiniz.

C’ye Taşıma

Artık eğitilmiş bir sınıflandırıcımız olduğuna göre, onu seçtiğimiz mikrodenetleyicide derlenen düz C’ye taşımamız gerekiyor.

 from micromlgen import port_rvm

 clf = get_rvm_classifier()
 c_code = port_rvm(clf)
 print(c_code)

Artık herhangi bir mikrodenetleyiciye yerleştirebileceğiniz düz C kodunuz var.

Performans Karşılaştırması

Bu yeni algoritmanın etkinliğini test etmek için, hem SVM’nin hem de RVM’nin boyutunu ve doğruluğunu yan yana karşılaştırarak önceki gönderilerimde oluşturduğumuz veri kümelerine uyguladık.

veri kümesiDVMRVMDelta
Flaş(bayt)Doğruluk(%)Flaş(bayt)Doğruluk(%)FlaşDoğruluk
RGB renkleri45841003580100-%22-0%
İvmeölçer hareketleri(doğrusal çekirdek)3688892705685-%80-7%
İvmeölçer hareketleri(gauss çekirdeği)4534895776695-82%-0%
Wifi konumlandırma46411003534100-24%-0%
Kelime ile uyandırma(doğrusal çekirdek)1809886360253-%80-%33
Kelim ile uyandırma(gauss çekirdeği)2178890482662-78-%28

Gördüğünüz gibi, sonuçlar oldukça şaşırtıcı:

  • Doğrulukta herhangi bir kayıp olmadan (gauss çekirdeği ile ivmeölçer hareketleri) yüksek boyutlu veri setinde %82’ye kadar alan azaltma elde edebilirsiniz.
  • Bazen iyi bir doğruluk elde edemeyebilirsiniz (uyandırma kelimesi veri setinde en fazla %62).

Her durumda olduğu gibi, kullanım durumunuz için iki algoritmadan hangisinin en iyi sonucu verdiğini test etmelisiniz, ancak izleyebileceğiniz birkaç yönerge var:

  • En yüksek doğruluğa ihtiyacınız varsa, yeterli alanınız varsa muhtemelen SVM daha az daha iyi performans elde edebilir.
  • Küçük alana veya en yüksek hıza ihtiyacınız varsa, RVM’nin tatmin edici bir doğruluk elde edip etmediğini test edin.
  • Hem SVM hem de RVM karşılaştırılabilir performans elde ederse, RVM ile devam edin: çoğu durumda SVM’den çok daha hafiftir ve daha hızlı çalışır.

Boyut Karşılaştırması

Referans olarak, IRIS veri setini sınıflandırmak için bir SVM sınıflandırıcısı ve bir RVM sınıflandırıcısı için oluşturulan kodlar buradadır.

uint8_t predict_rvm(double *x) {
    double decision[3] = { 0 };
    decision[0] = -0.6190847299428206;
    decision[1] = (compute_kernel(x,  6.3, 3.3, 6.0, 2.5) - 72.33233 ) * 0.228214 + -2.3609625;
    decision[2] = (compute_kernel(x,  7.7, 2.8, 6.7, 2.0) - 81.0089166 ) * -0.29006 + -3.360963;
    uint8_t idx = 0;
    double val = decision[0];
    for (uint8_t i = 1; i < 3; i++) {
        if (decision[i] > val) {
            idx = i;
            val = decision[i];
        }
    }
    return idx;
}

int predict_svm(double *x) {
    double kernels[10] = { 0 };
    double decisions[3] = { 0 };
    int votes[3] = { 0 };
        kernels[0] = compute_kernel(x,   6.7  , 3.0  , 5.0  , 1.7 );
        kernels[1] = compute_kernel(x,   6.0  , 2.7  , 5.1  , 1.6 );
        kernels[2] = compute_kernel(x,   5.1  , 2.5  , 3.0  , 1.1 );
        kernels[3] = compute_kernel(x,   6.0  , 3.0  , 4.8  , 1.8 );
        kernels[4] = compute_kernel(x,   7.2  , 3.0  , 5.8  , 1.6 );
        kernels[5] = compute_kernel(x,   4.9  , 2.5  , 4.5  , 1.7 );
        kernels[6] = compute_kernel(x,   6.2  , 2.8  , 4.8  , 1.8 );
        kernels[7] = compute_kernel(x,   6.0  , 2.2  , 5.0  , 1.5 );
        kernels[8] = compute_kernel(x,   4.8  , 3.4  , 1.9  , 0.2 );
        kernels[9] = compute_kernel(x,   5.1  , 3.3  , 1.7  , 0.5 );
        decisions[0] = 20.276395502
                    + kernels[0] * 100.0
                    + kernels[1] * 100.0
                    + kernels[3] * -79.351629954
                    + kernels[4] * -49.298850195
                    + kernels[6] * -40.585178082
                    + kernels[7] * -30.764341769
        ;
        decisions[1] = -0.903345464
                    + kernels[2] * 0.743494115
                    + kernels[9] * -0.743494115
        ;
        decisions[2] = -1.507856504
                    + kernels[5] * 0.203695177
                    + kernels[8] * -0.160020702
                    + kernels[9] * -0.043674475
        ;
        votes[decisions[0] > 0 ? 0 : 1] += 1;
        votes[decisions[1] > 0 ? 0 : 2] += 1;
        votes[decisions[2] > 0 ? 1 : 2] += 1;
                int classVal = -1;
        int classIdx = -1;
        for (int i = 0; i < 3; i++) {
            if (votes[i] > classVal) {
                classVal = votes[i];
                classIdx = i;
            }
        }
        return classIdx;
}

Gördüğünüz gibi, RVM aslında sadece 2 çekirdeği hesaplar ve 2 çarpma yapar. SVM ise 10 çekirdek hesaplar ve 13 çarpma işlemi yapar.

Bu yinelenen bir modeldir, dolayısıyla RVM çıkarım sürecinde çok daha hızlıdır.